Trying a New Twitter Client – Hibari

January 27th, 2012

Hibari

I've had quite a few troubles with Twitterrific and the official Twitter client with the GPU switching from integrated to discrete and back again. In both cases, the apps appear to be working on the GPU that they started on, but if you 'hide' them (both have this feature) and then switch the GPU - for example, go from battery to power adapter, and try to un-hide the apps, they won't function. This has been ongoing for a long time with both apps. I like both, but this one feature means that I have had to stick with one GPU - regardless of the battery/power adapter setting, and leave it there if I want to make sure things are going to work.

Not horrible, but I've been hoping with each update of each of these apps that the bug will get fixed. I've sent bug report after bug report to both teams, and they either can't reproduce something that's superlatively easy for me to reproduce, or they aren't working on it. Sad.

So when Daniel J. tweeted that he was trying Hibari as a new Twitter client, I gave it a look. The big difference here is that Hibari is being actively developed, and that's something that does not seem to be the case for either of the other two I really liked. First, I was glad to see the style. It's clean, nice, solid, and shows thumbnails of the inline images. Very nice so far.

Then I realized it can hide/unhide nicely. Even better. Then I did the GPU-switch test and it passed with flying colors. OK, time to pay my $10, it's passed everything I wanted in a Twitter client. And it's still being developed!

I then saw that Gus M. of JSTalk fame was using JSTalk to tweet in Hibari. Even better. Auto-updates, I'm hoping are with Sparkle, but we'll have to see, and I'm smiling. Not bad at all.

I'm going to give it a while. See how it goes. I'm glad I can now let my GPUs switch and take advantage of the better GPU when I'm plugged into the wall, but fall back to the internal GPU when it's on battery, and I don't have to worry about my Twitter client.

Oh… and it's got great Growl integration. Can't beat that!

Adding New Data to the Greek Engine

January 26th, 2012

High-Tech Greek Engine

Today, in addition to dealing with QA questions from a lot of the groups trying to test their apps against my new engine, I had to add in the last trade on each exchange to the system so that the clients could see that - in addition to the per exchange quotes and volume. I don't know why the guy who used to work on this didn't tell me this was needed - but he didn't, and that's just the way things go. Nothing to do today, but fit it in.

The problem is that the change really makes the serialized output format different, and that means that we need to have the Java and C# clients updated as well. I did the C++ client when I put in the change, and tested it out as a part of my codebase. But the other clients are in my codebase, and so I just have to send out the change, and hope they see the note and pick it up as soon as possible.

I'm sure there will be prodding on the part of the users, and it'll make them a little grumpy, but since I didn't know about it until today, I can't really have done anything about it until today. So it goes.

It was a bit of a hassle because of the way they wanted me to implement it - first in a different branch, then fold it into mine so I could really test it. Not horrible, but annoying. So it goes.

I'm saying a lot of that recently… Not a really great sign in my book...

Setting Up a Second Datacenter

January 26th, 2012

Building Great Code

Today I got word that I had new boxes at out second datacenter - call it disaster/recovery, but it runs 100% all the time, so it's really just a secondary site that is fully used. There's a lot to get going on these boxes - postgres, The Broker, the user accounts, the right SSH keys, a lot of little things before I even really get to worry about the software and making it run on the second site.

Thankfully, there is no rush. I'll get it done when the sys admins get their stuff done, and then I'll fire up postgres and The Broker, and make the changes to the code so it deploys and runs as it should.

Throw in a few crontab entries and we'll be good to go. But it'll probably be tomorrow before that's all done. Just takes time.

Apple’s $13+ billion Profit Quarter

January 25th, 2012

keynote_sm.png

I've been reading a bit about Apple's first quarter earnings call today, and I am just stunned. The numbers and the graphs are all impressive, but it's the real scale that's blowing me away. Here's this (supposedly) niche company that had profits in the first quarter greater than Google's revenue. Amazing. Really.

And in my book, it could not happen to a better company. iBooks Author. The iBooks Textbooks. The hardware, and the tools. Simply amazing. Catering to the creative person in all of us has certainly made them incredibly wealthy. And the stories of what they did for their people, and the citizens of Japan after the earthquake - that's a company that's not just about making a buck.

It's good to see good karma generating good outcomes.

More Details, and the Harm Legacy Systems Do

January 25th, 2012

bug.gif

This morning I again have been battling the latest in the list of "not quite there - yet" issues with my greek engine. This morning's list of issues are really only one - the exchanges, in this case via the CTS feed, are sending start of day Summary messages with a 'close' value that I'm taking as the close for the day.

Wrong.

What I'd really like to do is to put all these "not really used" Summary messages from the exchanges into a group via flags, so that I can still send them, still see them, but the pricing part of the system would not use them. As it is, the legacy system I'm replacing just ignores them, and that's a little too dangerous for my taste. What if someone wanted to really see them? Too bad. They just aren't there.

That's one of the many dangers of legacy systems - you end up crippling your new code just to get it to match the old. Yet if the old was all that fantastic, why replace it? Seems like you'd want to accept some of these changes as they are really making the product better.

But that's not what I did. I removed the decoding of the message. I'm going to go back in someday and use some flags and then filter in the pricing component. But for now, it's safer to just go along than to try and change people's minds. They're just too stuck in their ways.

Google Chrome dev 18.0.1017.2 is Out

January 25th, 2012

This morning, the Google Chrome team released 18.0.1017.2 and the release notes indicate it's got several nice things like the latest V8 javascript engine (3.8.7.1) as well as several nice-to-haves like popup window fixes and flashing window fixes on the Mac. Nice to see the improvement in the V8 engine, as that's where so much of the work is going these days - heavy javascript on the client for thin client deployments.

Hope they keep up the good work.

Firing Up C++ Functors – Beautiful Solution to the Problem

January 24th, 2012

cplusplus.jpg

This morning I've been battling a really nasty problem in my Greek Engine - at the start of the business day, I need to clear out the previous day's values for some daily summary values - like open/high/low. I do that fine in the instruments themselves, but there's an component in the engine that listens to all trades and creates this summary data. And it wasn't getting cleared out. So when I reloaded all the instruments at the beginning of the day, and flushed all the messages from the exchanges to them, these "lingering" values from the previous day were slipping in.

Ideally, we'd just clear out these values, and I could just clear out the cache in the component. But then I'd loose the last valid trade as well - and that I don't want to loose. So I really to operate on all the messages in the component. This seemed to scream "Iterator!" to me, and I spent several hours on it. The problem is not with the basic iterator concept, it's that we're trying to iterate over a trie, and that's not really all that easy when your trie is lockless, and it's possible for someone to change the data as soon as you're sure it's there.

Yeah, it's nice to think of an iterator on the trie, but it's not really all that practical.

Sure didn't stop me from wasting several hours trying to get it to work, though.

What I really wanted was to be able to pass in some function to operate on all the messages in the trie, and then let the trie itself, handle all the thread-safety issues. This seemed like a much better idea, so I started looking into something I haven't used up till now - functors.

The basic idea is just to have a simple class that has a few standard operators on it, and then use this base class to derive all the operations that you need. For example, in my case what I needed was to operate on Messages. Sure, I only needed to operate on one kind of Message - the Summary Message, but if I'm going to make this, I might as well make it capable of dealing with all the message functor usage I'm going to need.

So I create the following header:

  namespace msg
  {
  struct MessageFunction
  {
    // this is the overt method that can be called
    bool doIt( Message *aMsg );
    // …and this is the simple operator to make it look like a function
    bool operator()( Message *aMsg );
 
    // these are the methods to override for the different message types
    virtual bool doHello( message::Hello & aMsg );
    virtual bool doGoodBye( message::GoodBye & aMsg );
    virtual bool doQuote( message::Quote & aMsg );
    virtual bool doPrint( message::Print & aMsg );
  };
  }      // end of namespace msg

and I implemented all the specific message type methods so that if you don't need to implement it, you don't have to, and it'll just be a no-op on the message:

  namespace msg
  {
  // this is the overt method that can be called
  bool MessageFunction::doIt( Message *aMsg )
  {
    bool      error = false;
 
    if (aMsg != NULL) {
      switch (aMsg->getType()) {
        case eHello:
          error = !doHello((message::Hello &)(*aMsg));
          break;
        case eGoodBye:
          error = !doGoodBye((message::GoodBye &)(*aMsg));
          break;
        case eQuote:
          error = !doQuote((message::Quote &)(*aMsg));
          break;
        case ePrint:
          error = !doPrint((message::Print &)(*aMsg));
          break;
        default:
          error = true;
          break;
      }
    }
 
    return !error;
  }
 
  // …and this is the simple operator to make it look like a function
  bool MessageFunction::operator()( Message *aMsg )
  {
    return doIt(aMsg);
  }
 
  // these are the methods to override for the different message types
  bool MessageFunction::doHello( message::Hello & aMsg )
  {
    return true;
  }
 
  bool MessageFunction::doGoodBye( message::GoodBye & aMsg )
  {
    return true;
  }
 
  bool MessageFunction::doQuote( message::Quote & aMsg )
  {
    return true;
  }
 
  bool MessageFunction::doPrint( message::Print & aMsg )
  {
    return true;
  }
  }      // end of namespace msg

Now in my code, I only needed to implement a subclass that did the one thing I needed it to do - reset the values. In this case, I'll use the Quote as an example:

  struct QuoteClear :
    MessageFunction
  {
    virtual bool doQuote( message::Quote & aMsg );
  };

implemented as:

  bool QuoteClear::doQuote( message::Quote & aMsg )
  {
    aMsg.clear();
    return true;
  }

Then all I needed to do was to add in an apply() method to the trie, and have it run through all the values and on each one that is non-NULL, call the functor. The signature for the apply() method is simple, and it makes it clear how to use it:

  virtual bool apply( MessageFunction & aFunctor );

This was an excellent use of the idea, as it allowed me to pass in an arbitrarily complex function to be operated on a general Message, and the apply() method simply knows how to scan it's internal data structure, and call this application as needed. Very sweet.

While it's not as generally useful as an iterator on a trie, it's perfectly suited to what I needed. Love the idea.

Knowing What to Do is Harder than it Looks

January 23rd, 2012

cubeLifeView.gif

I'm sitting at my desk (to call it a desk is an overstatement - it's a 6 ft. section of a 24 ft. table) this morning and trying to come to terms with what I should be doing next. And 'next' is not always defined to be the very next thing I'm working on. No, this is a more long-term 'next', like What am I doing here? and Is this place the right place for me? kind of 'next' questions. The Shop is undergoing a lot of changes lately, and I'm feeling more isolated than I've felt in a while. It's not comfortable, and I'm just not sure why I'm subjecting myself to this - long-term. After all, in this market, in this day, the skills I have are in high demand, and there's no shortage of places to work.

So I'm sitting here, looking at my code - very happy with it, but fundamentally wondering if this is the right place for me. WHat should I really be doing? I'm not really advancing my career here. Not that it's that important to me. But still… I'm helping them out, I'm getting more years of experience in this industry, but I'm not really getting myself any closer to what I want to be doing.

Or maybe I am?

I just want to do fun, interesting things with fun, interesting people. I believed this was the place when I came here almost two years ago, and I've certainly built some amazing systems while I've been here. So I've done the fun and interesting code, but the fun and interesting people have been pulled away from me. The guy that I came here to work with became the Head of IT, and I don't get to work with him any more. The guy I worked with for a few good months, got pulled away to be the head of a large development group, and so I don't get to work with him either.

So it's like the fun and interesting people are here, and I did get to work with them, but as soon as I did, they seemed to get pulled away into management duties. I don't begrudge the organization pulling good devs out of the trenches, and making them management. It's what most organizations do - right or wrong. I support my friends that have moved away from development into these management roles because if they are happy, then I'm happy for them.

But with each move, I feel all that much more isolated. What's the point of staying here if there are a few guys I want to work with but will never again get the chance to work with?

That's my Big Next Question.

I have no idea. I sure wish I knew.

Sampling Intervals and the Dangers of Common Sense

January 20th, 2012

bug.gif

This afternoon I've spent quite a bit of time working on a few issues that popped up in today's testing of the greek engine. One was a bad copy constructor that was leading to bad calculated values, and another was the calculation of the high and low for a composite instrument. The guy doing QA looked at the formula for the composite:

  Value = (Comp1 * 0.700) + (Comp1 * 0.400) + 0.55

and thought that the high/low on the day should be the simple application of this formula to the individual high/low values for the components. But that is not the case. The computed value of this function is a time-based function and unless the components are perfectly correlated, the high of one will not coincide with the high of the other. This means that the computed high will be the largest value of the computed quantity, and will most likely be less than the "expected" high value.

But it gets more interesting…

Because of the speed of ticks, we accurately track all trades for the determination of the high and low. However, downstream, we conflate the messages, so that when the calculation is actually performed, it may only be once every 100 trades (depending on volume). This means that the formula is not accurately calculating every value of the function - only those that it needs, and that, too, will effect the high/low as shown.

All this is just too confusing for the traders to cope with. So I used the equation:

  Value(high) = (Comp1(high) * 0.700) + (Comp1(high) * 0.400) + 0.55

and decided it was better to have a clear, explainable value, than risk the confusion and effort of having to explain it to all the traders several times.

Pricing Systems are Details, Details, Details (cont.)

January 20th, 2012

bug.gif

OK, I just finished the latest fixes for today, for testing Monday. I know it's the way it goes, but it's still tough. I'd really like to know it's fixed, but the best I can do it run it through in my head and be sure that, at least there, it's right. I then have to hope that my mental picture of the system is accurate. Sometimes yes, sometimes no.

Today's issue was really pretty significant. It appeared as though the previous close and adjusted previous close weren't being loaded. But I'd tested that code, and I knew in my tests it was working. Something was amiss.

So I resorted to logging, and in that I realized that the problem was systemic. I was indeed loading them properly, but then the first message was clearing out the summary data, that contained these values. Therefore, it appeared that the values weren't set when they had been set. So what was the problem? I was resetting all parts of the summary data when all I wanted to clear were the open/close/high/low. Ah! Simple fix.

But what about the reloading of an instrument where we replayed the messages from the previous day and the last trade last night was then setting our new high/low/close? Hmmm… this is just as obvious, but it's a lot less clear how to fix it. We can't block the messages, they are needed. Also, we can't stop the resetting process, that's crucial.

What I came up with was a very surgical change: if the trade was yesterday (i.e. not today), then do not allow it up update the summary values of open/high/low/close. Simple and surgical. This is the complete context of the problem. I'm hoping that there are no unintended consequences on Monday, but we'll have to wait until then to see. I've run it through my head so many times I can't see a hole in the logic.

I have my fingers crossed.