Indiana Jones and The Legend of the Lost Codebase

August 18th, 2010

Detective.jpg

Well... I'm donning the old fedora again, and off in search of the Lost Codebase. It's really quite amazing the skill that some people have to hide code. I'm sure they don't think of it that way - they probably consider it to be exactly where they want it to be - the right spot. But if I can't find it after working in the repository for nearly two months, then it's time to call it "hidden". Yup... hidden. And that means I need to get out the fedora and get exploring.

The first thing I check is of course, the most obvious - the name of the directory. Clearly, this is a trap, for who in their right mind would put the code in a clearly labeled directory. No, that's the location for some of the code. Maybe. Hard to tell as the class files are nearly completely empty, and one would wonder if the code even compiles. I'm not fool enough to fall for that trick - typing 'make' could end of wiping out my entire machine's drive. I'm no fool.

Next, I check the similarly named directories. No luck there, but not nearly as complex, and some of the traps aren't even well constructed. In one there's no Makefile - a dead giveaway, if ever there was one. In another, they foolishly only include a handful of files. This is too easily scanned and I can see what I'm looking for isn't there. In all, a minor detour, but I have no idea where to go next.

Next I have to go with the big guns - I grep for a keyword in the entire source tree. As expected, this yields far too many hits, and I need to filter it down. Doggedly, I wrestle the filter on the grep to give me something I can work with. I struggle weeding out the false hits. I finally think I may be onto something only to have my hopes dashed when it's a simple comment and not the real code I'm looking for.

It's frustrating, and in the end, I realize I've met my match. I have to back off, regroup, and hope that when the author(s) decide to come in for the day, they have some answers to where the hid the secret directory to the code.

Oh yeah... I even checked for the hidden directories... no luck.

Google Chrome dev 6.0.495.0 is Out

August 18th, 2010

It looks like they have fired up the 'dev' channel again as Google Chrome dev 6.0.495.0 was released this morning. I went back to the dev channel after moving to the beta when it was released a few days ago. I have to say, this has become an incredibly stable platform. It's fast, looks like a Mac app, and it just plain works. Nice.

The release notes indicate that, for the Mac at least, we're getting a fix for the download shelf, and a few fixes for CSS and plug-in handling. Looks good to me.

Swatting Flies is an Annoying Thing to Do

August 17th, 2010

cubeLifeView.gif

I've been working (still) on getting more exchange feed codecs into the system, and while it's not really hard work, it takes a little thought, and a lot of attention to detail. So when I get some kibitzing from those that would love to see me fail, but are too afraid to really stand up to this project, it's like swatting flies - not hard, they aren't going to do me any harm, but it's annoying nonetheless.

When it gets bad, I just get up, take a little walk, get a pop, and clear my head. That usually does it. Oh... and getting another feeder done in less than a day makes me feel good. It shows the "flies" that they really might want to take notice of the different way I've put this together. But that's really hoping for too much, I suppose.

Time to get some bug spray.

Google Chrome beta 6.0.472.36 is Out

August 17th, 2010

This morning I noticed that Google Chrome beta 6.0.472.36 was out - still no word on a new 'dev' release, so it appears that for now, they are simply sticking with the 6.0.x branch and not starting anything new for the time being. It seems reasonable that if they aren't making major changes, they can keep the 6.0.x branch moving along from dev to beta to stable. It's only if they have great new ideas that it makes sense to open up the dev branch again.

So it's out there - a few little UI fixes - nothing major.

Once Again – Amazing Progress with a Good Design

August 16th, 2010

MarketData.jpg

Today I spent all day working on getting two exchange feeders written and tested. This kind of speed is not because I can copy/paste very fast, it's because I've got a solid design that allows me to leverage the work I've already done and customize it very quickly and easily. Given that the last developers of these feeds took months to achieve what I've done in a day, there's a lot to be said about the power of the design. The previous one was particularly ill-suited to this task.

So it was a hard day, but I'm getting a lot closer to the point that I'm caught up with all the exchange feeds we have. At that point, I can look to data enrichment, and really start to add value to the data feeds.

Fantastic Point About the Consequences of Who You Hire

August 13th, 2010

I was reading this article by Paul Graham about why Yahoo didn't last, and came across this point: (which, by the way, wasn't John Gruber's highlighted section)

In technology, once you have bad programmers, you're doomed. I can't think of an instance where a company has sunk into technical mediocrity and recovered. Good programmers want to work with other good programmers. So once the quality of programmers at your company starts to drop, you enter a death spiral from which there is no recovery.

Paul goes on to talk about the difference in the culture of Google at 500 people and Yahoo at the same point. It's interesting, but not necessarily surprising for someone that's been in this business as long as Paul, and I, have. It's classic: There's no Free Lunch.

There's no way around hiring the best talent you can get. No one thinks getting the cheapest artist is a good idea. Nor the cheapest surgeon. Everyone seems to understand that when you're dealing with an artistic, or especially challenging area of study, and there's one and only one person at the task, that it's a good idea - no, the right idea, to get the best you can. What they think is that coding, like building automobiles, or making frozen pizzas, is something that you can get better at by throwing more people at it.

There are tons of books on this. Even more Harvard Business Studies. It's a deceptively simple lie - programmers are like ants - you just need more. Yup... you keep thinking that. It's a lie, plain and simple.

Everything we humans do has some sense of skill and quality. If you want to be good at something, you have to practice. And not a little. You have to want it. These are the qualities of a good worker - not just that he knows a language, and takes orders. That's a given. You need more.

Sadly, I have a feeling this is never going to be really understood by most people.

Hulu Desktop 0.9.9 is Out

August 13th, 2010

HuluDesktop.jpg

While I've heard a lot of grumblings from the net about the fact that Hulu is going "for pay", the Mac Desktop app is still just commercial supported TV. I can deal with that. I know it's based on the Flash player, but with the latest player being hardware-accelerated, that's not too bad. This morning I noticed that they had released the Hulu Desktop 0.9.9, so I needed to upgrade.

It's nice to be able to watch some of my favorites on the desktop. Really nice.

Google Chrome beta 6.0.472.33 is Out

August 13th, 2010

GoogleChrome.jpg

Well... I'm a little surprised (again) at the Google Chrome guys... this time, the update to 6.0.472.33 didn't work from the application, and I had to get the update directly from the web site. In addition, the permissions on the existing app package made it impossible for a new user to replace the old with the new. Very odd. But in the end, I got what I needed, and I hope they have these updating issues fixed. It's amazing that they don't just use Sparkle, it's almost a defacto standard for the Mac.

UPDATE: I see the point... they promoted this to beta from dev, and that's the reason it wasn't updating. I'm going to have to go back to the dev channel when it's on the next major release. Makes sense now.

The Amazing Power of Really Good Design – And Hard Work

August 12th, 2010

Today I was very pleased to see that I could add a second exchange feed to the codebase. Yeah... just one day. Pretty amazing. I know it's primarily due to a good design because the number of lines of code I had to write was very few - on the order of 600 lines, but there's still a little bit of good old hard work to attribute to it as well.

But really, it was the design. What a great design. This is something I'm going to enjoy over and over again as I keep working with this codebase. I need to add in at least six more feeds, but if they are only a day or two per feed, I'm still done long before I had expected to be. Amazing.

So after I had it all done, I looked at the code and realized that when I was "unpacking" the time data from the exchange into milliseconds since epoch, I was making a few system calls, and that was going to come back to bite me later as the loads got higher and higher. The original code looked like:

  /*
   * This method takes the exchange-specific time format and converts it
   * into a timestamp - msec since epoch. This is necessary to parse the
   * timestamp out of the exchange messages as the formats are different.
   */
  uint64_t unpackTime( const char *aCode, uint32_t aSize )
  {
    /*
     * The GIDS format of time is w.r.t. midnight, and a simple, 9-byte
     * field: HHMMSSCCC - so we can parse out this time, but need to add
     * in the offset of the date if we want it w.r.t. epoch.
     */
    uint64_t      timestamp = 0;
 
    // check that we have everything we need
    if ((aCode == NULL) || (aSize < 9)) {
      cLog.warn("[unpackTime] the passed in data was NULL or insufficient "
                "length to do the job. Check on it.");
    } else {
      // first, get the current date/time...
      time_t    when_t = time(NULL);
      struct tm when;
      localtime_r(&when_t, &when);
      // now let's overwrite the hour, min, and sec from the data
      when.tm_hour = (aCode[0] - '0')*10 + (aCode[1] - '0');
      when.tm_min = (aCode[2] - '0')*10 + (aCode[3] - '0');
      when.tm_sec = (aCode[4] - '0')*10 + (aCode[5] - '0');
      // ...and yank the msec while we're at it...
      time_t  msec = ((aCode[6] - '0')*10 + (aCode[7] - '0'))*10 + (aCode[8] - '0');
 
      // now make the msec since epoch from the broken out time
      timestamp = mktime(&when) + msec;
      if (timestamp < 0) {
        // keep it to epoch - that's bad enough
        timestamp = 0;
        // ...and the log the error
        cLog.warn("[unpackTime] unable to create the time based on the "
                  "provided data");
      }
    }
 
    return timestamp;
  }

The problem is that there are two rather costly calls - localtime_r and mktime. They are very necessary, as the ability to calculate milliseconds since epoch is a non-trivial problem, but still... it'd be nice to not have to do that.

So I created two methods: the first was just a rename of this guy:

  /*
   * This method takes the exchange-specific time format and converts it
   * into a timestamp - msec since epoch. This is necessary to parse the
   * timestamp out of the exchange messages as the formats are different.
   */
  uint64_t unpackTimeFromEpoch( const char *aCode, uint32_t aSize )
  {
    // ...
  }

and the second was a much more efficient calculation of the milliseconds since midnight:

  /*
   * This method takes the exchange-specific time format and converts it
   * into a timestamp - msec since midnight. This is necessary to parse
   * the timestamp out of the exchange messages as the formats are
   * different.
   */
  uint64_t unpackTimeFromMidnight( const char *aCode, uint32_t aSize )
  {
    /*
     * The GIDS format of time is w.r.t. midnight, and a simple, 9-byte
     * field: HHMMSSCCC - so we can parse out this time.
     */
    uint64_t      timestamp = 0;
 
    // check that we have everything we need
    if ((aCode == NULL) || (aSize < 9)) {
      cLog.warn("[unpackTimeFromMidnight] the passed in data was NULL "
                "or insufficient length to do the job. Check on it.");
    } else {
      // now let's overwrite the hour, min, and sec from the data
      time_t  hour = (aCode[0] - '0')*10 + (aCode[1] - '0');
      time_t  min = (aCode[2] - '0')*10 + (aCode[3] - '0');
      time_t  sec = (aCode[4] - '0')*10 + (aCode[5] - '0');
      time_t  msec = ((aCode[6] - '0')*10 + (aCode[7] - '0'))*10 + (aCode[8] - '0');
      timestamp = ((hour*60 + min)*60 + sec)*1000 + msec;
      if (timestamp < 0) {
        // keep it to midnight - that's bad enough
        timestamp = 0;
        // ...and the log the error
        cLog.warn("[unpackTimeFromMidnight] unable to create the time "
                  "based on the provided data");
      }
    }
 
    return timestamp;
  }

At this point, I have something that has no system calls in it, and since I'm parsing all these exchange messages, that's going to really pay off in the end. I'm not going to have to do any nasty context switching for these calls - just simple multiplications and additions. I like being able to take the time to go back and clean this kind of stuff up. Makes me feel a lot better about the potential performance issues.

Oh... I forgot... in the rest of my code, I handled the difference in these two by looking at the magnitude of the value. Anything less than "a day" had to be "since midnight" - the rest are "since epoch". Pretty simple.

It works wonderfully!

Over the First Big Hurdle – Really Nice Feeling

August 11th, 2010

MarketData.jpg

This afternoon I can sit back for a minute and look at what I've been doing for the past several weeks as it's gotten to the point that it's tested against data from the exchange, and it's passed those tests. It's only one of about a dozen feeds that I need to handle, but it's the first, and that means that all the infrastructure work I've done - the boost asio sockets... the serialization... the unpacking of exchange data stream... all that is done. Now it's time to put the second codec in the system and see how well it maps to the system I created for one. I'm not really convinced that the design I have now will withstand all the other sources, unmodified, but it's a really good start, and I think it's close.

So I've run this sprint to get the first data feed done, and it's done, and now I find myself exceptionally tired. No surprise there... just a matter of when not if. I've been running on this for a long time without even the slightest break, but it's done now, and I can rest for a minute and then hit it again.

Well... there's my minute's rest... time to get back at it.