Archive for the ‘Cube Life’ Category

Miracles Don’t Warrant Attention Any Longer

Monday, August 17th, 2009

cubeLifeView.gif

Well... maybe it's the Slump talking, but today I was asked to put in a feature quickly and in less than two hours I had a new view of the data available to my clients just like they'd asked for. Two hours. One would call that pretty nice - maybe even pretty wild. But today it didn't even warrant a "Nice job!" email.

I'm sure they expect this from me now, and that's a double-edge sword. One one hand, it's great because I can then expect impressive bonuses, but on the other hand, it's expected now, and if I just do a "good" job, it's seen as me 'slipping'.

Everyone likes to hear that what they are doing is appreciated. I'm no different. I don't require it, but there are times when I hammer out a new feature on a 'rush' schedule and it'd be nice to hear something. Oh well... I do it for myself. I do it because I'm who I am.

It's just a little tough to take this hit in the middle of a slump. But I'll get over it. I always do.

[8/18] UPDATE: I did get a 'good job' email today, so I guess it was noticed. It helps.

Fighting to Get Out of a Slump

Friday, August 14th, 2009

It's been a hard week, and I'm finding it more and more difficult to focus and get motivated to get work done. It's a slump, I know it. It happens every so often when I'm not really having a fun project to work on and the hours are getting long and there's no real outlet in the evenings and weekends. It's a slump.

I know that time will take care of this, it always has in the past. The only real question is How long? Clearly, I'm hoping for "not too bloody long", but there's no way to tell. It could be something as simple as an update to some program that's got something I really have needed for a while... or maybe it's Snow Leopard... or maybe it'll be a few days off at home.

Something will start the ball rolling and then it'll build on itself just like the slump did, and in the end, I'll be back on top where the sun is shining. Just wish it'd hurry up and get here.

It Seems Very Easy to Misuse Google Collections

Thursday, August 13th, 2009

I like reusable code as much as the next guy. I really do. For what I've seen of the Google Collections Java code, I like that too, though to be honest, I haven't seen all that much. But that's not to say that it's not possible - even easy, to create a mess with the Collections. In fact, it can make code very difficult to read. Take as an example, the code I ran into today:

  public Set<Trade> getTradesForReport(PositionService aPositionService) {
    // get all the trades from the service
    Set<Trade>  retval = aPositionService.getAllTrades();
    // now filter them on the trading parameter
    for (Iterator<Trade> iter = retval.iterator(); iter.hasNext(); ) {
      Trade   t = iter.next();
      if (!allowedUsers.contains(t.getUser())) {
        iter.remove();
      }
    }
    return retval;
  }

Java's definition of the initial Set<Trade> does not address the mutability of the Set. In fact, Java has no native immutability, and the way that Google achieved this is to make an Iterator that overrides the remove() method and throws an Exception.

That's dangerous. Not illegal for the language, but certainly dangerous.

If you look at NeXTSTEP/OPENSTEP/Cocoa on the Mac, the 'base class' is by definition immutable. You have to create a mutable version deliberately. This makes it clear what you are dealing with. The 'default' (base) behavior is to assume that you can't mess with it. Makes perfect sense.

But Java is the opposite. By default, all the objects, collections, etc. are mutable, and they handle immutability by removing the iterator() method, and using a different Enumerator. Look at the ConcurrentHashMap. No way to remove an item during a 'scan' of the data because the Enumerator doesn't have a remove() method. Period.

While I admire Google's work, it's not clear what they are doing. Say, in the example above, there were several position services, and some of them decided to return Google's ImmutableSet. Now I'm sunk. The compiler won't see that I can't do this, because as far as it's concerned, I can. I'd have to trap for the exception and reverse the logic - create a blank one and add those I wanted to it. But if I do that, I might as well use that logic for all cases:

  public Set<Trade> getTradesForReport(PositionService aPositionService) {
    // get all the trades from the service
    Set<Trade>  src = aPositionService.getAllTrades();
    // ...and make a place to put the good ones
    Set<Trade>  retval = new HashSet();
    // now filter them on the trading parameter
    for (Trade t : src) {
      if (allowedUsers.contains(t.getUser())) {
        retval.add(t);
      }
    }
    return retval;
  }

While this works in all cases, it doubles the references used, and that's not a good thing when you get into a tight memory application and garbage collection is already an issue.

What they should have done isn't clear. Face it, they wanted this to fit into the standard Collections in Java. But they are all mutable by default. No... the problem here lies with the coder that uses these. You need to be more explicit on the return types and explicitly say they are ImmutableSets. Then, the user/maintainer of the code can see what was intended.

Alas, such was not the case for me today. I had a production problem because some of the code returned a standard HashSet to the method signature and some returned a Google ImmutableSet. Unfortunately, this has been in production for several weeks, but it's just now getting hit. Lovely bug to catch and fix in a hurry.

A Hallmark of a Good System – Clean Mid-Day Restarts

Wednesday, August 12th, 2009

Well... when I left last evening, I left my system in a less-than-perfect state: if you restarted the web app in the middle of the day, it's possible that you might not get correct firm totals for P/L, etc. Why? Because it was based on a table trigger, and if you didn't get new rows, they weren't being counted. That's not going to work when some data sources send data only during fixed times of the day. Crud.

And while it's true that I don't restart production mid-day very often, it's still not the sign of a really good app to restart poorly in the middle of the day. The problem was, properly restarting mid-day was a real problem.

First, the firm totals needed to be stored on each alert - thankfully, they already were. Why? Because the alert could be an 11-point moving average filter or a 31-point moving average. In these cases, the firm totals will be different because of the different smoothing employed on the raw data. So it's got to be "local" to the alert.

Second, the firm totals needed to be updated for all incoming data. Initially, I had first checked to see if the portfolio was one of the ones I was interested in, but that was a mistake. I needed to update the firm totals and then filter on the appropriateness of the portfolio. That was a simple fix, so no big deal.

Finally, it's how the data needed to be fed into the alerts in order to get them primed for action on the restart. If there are n alerts, then we need to push n copies of each portfolio. Doing this at the alert level means there's a lot of hits to the database, and while that's logically reasonable, it's not a good plan as the number of alerts grows. So we need a different plan.

This morning I came up with a plan that seems to be working quite well.

In the alert controller code, just after creating all the alerts, I'm going to look at all the portfolios that have sent in data so far today. I'll then look at all the alerts and ask them how many data points they need, add one to that, and know that this is the number of "recent rows" in the data table I need for each portfolio.

I'll then run through all the portfolios, get the maximum number of rows I'll need from the table, and then feed those into each of the alerts, one at a time. Of course, I'll limit the data I feed any one alert to be that which is needs, but there will be at least one that will need all the data I've obtained, and that's not bad. Then, I'll be able to use this to calculate the firm totals for each alert.

What's interesting is that this process is really quite fast. One database connection, and to the H2 in-memory database at that. Most of the pulls there are less than 150 msec. in duration (yeah, I timed them in the code), and then pushing the data to the alerts is really fast as it's all just a bunch of data structures.

In the end, I have firm totals that survive a mid-day restart quite nicely. I'm more than a little pleased that all this work took no more than three hours. I was expecting quite a bit more. Nice surprise.

Finally Getting my Alerts Working Properly

Thursday, August 6th, 2009

cubeLifeView.gif

I'm finally pretty happy that the alerts in my web system are working as they should. The aggregated values are being calculated properly, the alerts are being triggered correctly, it's all working as it should. This is a "Big Deal" as it's one of the important things this guy was supposed to do - alert people via "push methods" (email and chat for now) of problems in the data. With these alerts in place, it's easier to let people not look at the data all day long, and have it alert them to problems. With a good set of alerts in place, it'll be easy to have the right people informed of the proper conditions.

Sure, it's geeky, but this is what it often comes down to - being able to finally bend this code into what I want it to be and seeing the results play out in front of me.

Goin’ Old School on Some Code

Monday, August 3rd, 2009

Professor.jpg

Today I was trying to figure out why an app I inherited was returning wild values and I came across code that I'd skimmed several times before, but hadn't really dug into. Since the running program wasn't generating any exceptions, I assumed that the problem had to be in the data we were receiving. I spent several hours digging into the data, logging it, checking for problems, all to come to the conclusion that it couldn't be the data, and had to be something in how it was being interpreted in the code.

So back to the processing code that was the first step in the program.

My goals were simple - put in logging and try/catch blocks to make sure that we caught the exceptions and group the processing into distinct groups: gathering data, converting it into values, and then organizing the data into objects. Seems simple. And then I looked, really looked at the code.

What I saw made me shake my head... and bring out the "Old School" in me. The original code looked something like this:

  public uploadData(StringTokenizer mainTokenizer) {
    // get the number of rows as a rough size for the maps
    int size = mainTokenizer.countTokens();
	// ...make some maps to store data
 
    while (mainTokenizer.hasMoreTokens()) {
      String row = mainTokenizer.nextToken();
      StringTokenizer columns = new StringTokenizer(row, "\t");
      while (columns.hasMoreTokens()) {
        String nameString = columns.nextToken().trim();
        String dateString = columns.nextToken().trim();
        String costString = columns.nextToken().trim();
        String qtyString = columns.nextToken().trim();
        // ...more of the same
 
        String name = nameString;
        Date transDate = dateFormat.parse(dateString);
        Double cost = Double.valueOf(costString);
        Double qty = Double.valueOf(qtyString);
        // ...more of the same
 
        Order ord = orderFactory.createOrder(name, transDate, cost, qty);
        orderMap.put(name, ord);
        // ...more of the same
      }
    }
  }

The goal was admirable - divide the processing into three sections: acquisition, conversion, and organization. It's an admirable goal. But doing it this way is not only a little redundant, it's downright dangerous.

Look at the most obvious things: reused variables. Get rid of them. Make it cleaner by using the variables where they are needed. No more, no less. it's an admirable goal, and a good design plan, but when you're processing 30 or more variables in a table of data, it gets to be a little much when you have to repeat these three times. Trim it a little and keep it readable.

But he subtle things really are the danger signs. Why is he using the StringTokenizer for the rows in the table and not checking the number of elements? There's the possibility for a major confusion here. What if you have a row of data that's malformed? There's nothing that's going to tell me what the problem was and where to look in the data stream to correct it. Also, if there's an exception thrown all the remaining data is lost. Not a good thing.

Let's try something a little different.

  public uploadData(StringTokenizer mainTokenizer) {
    // get the number of rows as a rough size for the maps
    int size = mainTokenizer.countTokens();
	// ...make some maps to store data
 
     // processing variables used in the loop
    String name = null;
    Date transDate = null;
    Double cost = null;
    Double qty = null;
 
    // keep track of what I've done for logging at the end
    int    uploadCount = 0;
    int    uploadErrors = 0;
    while (mainTokenizer.hasMoreTokens()) {
      String row = mainTokenizer.nextToken();
      String[] columns = row.split("\t");
      if ((columns == null) || (columns.length != SIZE)) {
        log.error("No columns or wrong number.");
        ++uploadCount;
        ++uploadErrors;
        continue;
      }
 
      String nameString = columns[0].trim();
      String dateString = columns[1].trim();
      String costString = columns[2].trim();
      String qtyString = columns[3].trim();
      // ...more of the same
 
      try {
        name = nameString;
        transDate = dateFormat.parse(dateString);
        cost = Double.valueOf(costString);
        qty = Double.valueOf(qtyString);
        // ...more of the same
      } catch (NumberFormatException nfe) {
        log.error("While parsing " + name + " got a "
            + nfe.getMessage());
        ++uploadCount;
        ++uploadErrors;
        continue;
      } catch (ParseException pe) {
        log.error("While parsing " + name + " got a "
            + nfe.getMessage());
        ++uploadCount;
        ++uploadErrors;
        continue;
      }
 
      try {
        Order ord = orderFactory.createOrder(name, transDate, cost, qty);
        orderMap.put(name, ord);
        // ...more of the same
      } catch (Exception e) {
        log.error("While organizing " + name + " got a "
            + e.getMessage());
        ++uploadCount;
        ++uploadErrors;
        continue;
      }
 
      // update the count of rows processed
      ++uploadCount;
    }
 
    // log what we've done
    log.info("Processed " + uploadCount + " with "
        + uploadErrors + " errors");
  }

Now the logging messages are far too simplistic here, but they're where you need to log what's happening. First, forget that StringTokenizer and it's loop. What if you're wrong about the count? Use a simple String[] and then check the count. To maintain the style, you can leave the intermediate values, but another scheme is to have static final int values for each column header and then use them as opposed to the temporary variables:

      String nameString = columns[0].trim();
      String dateString = columns[1].trim();
      String costString = columns[2].trim();
      String qtyString = columns[3].trim();
      // ...more of the same
 
      try {
        name = nameString;
        transDate = dateFormat.parse(dateString);
        cost = Double.valueOf(costString);
        qty = Double.valueOf(qtyString);
        // ...more of the same
      } catch (NumberFormatException nfe) {
        log.error("While parsing " + name + " got a "
            + nfe.getMessage());
        ++uploadCount;
        ++uploadErrors;
        continue;
      } catch (ParseException pe) {
        log.error("While parsing " + name + " got a "
            + nfe.getMessage());
        ++uploadCount;
        ++uploadErrors;
        continue;
      }

becomes:

      try {
        name = columns[NAME_COL].trim();
        transDate = dateFormat.parse(columns[DATE_COL].trim());
        cost = Double.valueOf(columns[COST_COL].trim());
        qty = Double.valueOf(columns[QTY_COL].trim());
        // ...more of the same
      } catch (NumberFormatException nfe) {
        log.error("While parsing " + name + " got a "
            + nfe.getMessage());
        ++uploadCount;
        ++uploadErrors;
        continue;
      } catch (ParseException pe) {
        log.error("While parsing " + name + " got a "
            + nfe.getMessage());
        ++uploadCount;
        ++uploadErrors;
        continue;
      }

and what's left is as readable as the original, but uses half the variables. This is important if we're in a tight loop and getting hit with a ton of data. Garbage Collection is a killer for Java apps, and the fewer variables you can use the better.

When I put this code into the system I had an immediate hit: the data coming from the other app was leaving a column field empty when it meant to send a zero. I saw this with the NumberFormatException and it clearly labeled the row in the table where the error occurred. I looked in the multi-thousand line upload and sure enough - a blank. Given that it was meant to be a zero, I just put that into the code on the uploader so I wouldn't have to worry about other such occurrences. Easy.

So what have we learned?

Well... I've learned that it's better to have less code that does the same thing so long as it's readable and well commented. Both of these attributes were missing in the original version. Secondly, check everything - there's no reason not to, it'll save your bacon more times than you can imagine. Third, care about the code you're writing. It's a craft, after all. Be proud of it.

Something to Really Like in Java – VarArgs and Arrays

Friday, July 31st, 2009

java-logo-thumb.png

I've been so jaded about Java that the last few years I really haven't worked to keep up with all the syntactical candy that has been added. The new for loops are a great example - as are templates: things that are in other languages that reduce typing a bit but don't really add to the power of the language.

So imagine my surprise when I started digging into varArgs in Java. First, I could see how they were used by a method:

  public void printAll(Object... things) {
    for (Object thing : things) {
      System.out.println(thing + ", ");
    }
  }

that's a pretty standard take on the C/C++ varArgs, and I'll admit, it's really nice to have. Makes the signatures of a lot of classes a lot simpler. But I needed to be able to call something with varArgs based on a stack.

For example, I have a parser that calls my code with all the arguments on a stack. I need to pop off the values - LIFO order, and then call the String.format() method with the fmt and then a bunch of Object values. But how to do that?

Thankfully, the Java guys really extended the language here. I'm really glad. They made the idea of Object... synonymous with the array: Object[]. This means that I can put all the values in an Object[] and then call the method, like this:

  /**
   * Get the format and all the args and then generate the string
   */
  public void run(Stack aStack) throws ParseException
  {
    // Check if stack is null
    if (aStack == null) {
      throw new ParseException("Stack argument null");
    }
    // see if we have a reasonable number of arguments
    if (curNumberOfParameters < 1) {
      throw new ParseException("You need at least a string format for "
            + "this call.");
    }
 
    // create an array of the proper size to hold all the args
    Object[]  varArgs = new Object[curNumberOfParameters - 1];
    if (varArgs == null) {
      throw new ParseException("I was unable to create an array to hold "
            + "the arguments. Check on it.");
    }
    // get the parameter from the stack
    for (int i = (curNumberOfParameters - 2); i >= 0; --i) {
      varArgs[i] = aStack.pop();
    }
    // finally, get the string format to use with these args
    String    fmt = (String) aStack.pop();
    // now we need to do the work... it will auto-convert the array
    aStack.push(String.format(fmt, varArgs));
  }

Needless to say, this is making the method within the parser very powerful. I now have the complete printf-like formatting available to my expressions, and while my original code worked (assuming a maximum size), this is far more flexible, and a far far better solution.

So I'm going to lighten up on Java for a while. Someone is still working on it in good ways that are just syntactic sugar.

CoRD – a Cocoa Remote Resktop Client

Thursday, July 30th, 2009

CoRD.jpg

I'm currently working in a tri-OS world. Lots of developers are using Mac laptops, linux workstations and Windows workstations. Things run on all these, and we need to be able to get to one from another. We have Cisco VPN, but I use Shimo for VPN control as it's so much nicer. But one of the things I've been concerned about is the ability to use RemoteDesktop into my Windows boxes (I need to monitor/control about 11 every day) from my Mac.

Enter CoRD 0.5.0.

It's an Open Source project on Sourceforge that places a Cocoa client to the Windows RemoteDesktop API and gives me the ability to show windows displays back on my Mac. That's something really nice. I can't wait to try it out.

Back in the Saddle (Again)

Thursday, July 30th, 2009

OK, things are looking a lot smoother this morning. I've been able to get everything I needed from TimeMachine, the laptop is running well, it's got another 180GB of storage (up to 500GB from 320GB) which is always helpful, and things are coming back into a comfortable swing.

In this experience, I have to say the surprising moments were these:

  • The Apple Store had no drives. Why on earth not?
  • The drive was only $129 at Fry's. Again, so inexpensive, why not have a few on hand, Apple?
  • The replacement of the drive was easy. Thanks, Apple. It could have been a lot worse.
  • The original drive was a lemon because it didn't even last a year. Sad, but it happens.

So things are kicking right along. I've got a lot of little things to watch today and it should be a nice, easy day.

It's good to be back in the saddle.

Adding Transactions to a Servlet-Based System

Wednesday, July 29th, 2009

WebDevel.jpg

Today I had the difficult task of trying to add in transactional integrity to a web system where the data is coming in as posts to the web server. If each post was a transaction, that wouldn't be so bad, but if I needed to have transactional integrity over multiple posts, then we get into a lot of trouble. Face it, web servers aren't noted for their state-maintenance - that's something you add on top of the web server in order to create the illusion of saved state for the user.

But in this case, we had one program feeding another. The sender wasn't passing in real markers for the beginning and end of a transaction, and that was the first thing that needed to change. We then needed to do something with this information, so I added that in. Now I had a place to handle the meat of starting and ending a transaction - but I needed to know what to put there.

The next problem I attacked was a little simpler, the market data service wasn't handling the blocks of data in a unit. Rather, as it was parsing data, it was sending it to it's cache. This would allow for inconsistent data as the instrument prices move but the greeks were in a buffer until the entire block was read. Also, the market data cache had no locking on it. So I added the locking and the buffering so that the market data was "clean" for each block.

But that still didn't solve the real problem - how to put multiple blocks in a transaction?

After thinking about all the alternatives, I came to realize that the only good way to do this is to have the sender "mark" each block of a transaction - including the BEGIN and END, so that the receiver can buffer the data by transactionID, and then release all that data and update the reports on the END. So I needed to figure out a way to get these transactionIDs.

From the UUID work I've done in the past, the IP address turned into a long was a good start. I didn't need to add in the time, as I wanted to have a transactionID per sequence, and not per transaction. So no need for the time. I did add in a simple three-digit sequence number on top of the IP address, and that should do it just fine.

Now the transactions needed to be tagged with this number. That meant modifying the payload format. Not something I was fond of doing, but it could not be helped. Did that, and decoded it on the receiver (web) side. Then I had to modify the buffering of the market data and the greeks to buffer by transactionID. I had to thread the transactionID into the code - passing it from the decoding through all the method calls all the way to the market data methods and greek cache methods. It wasn't more than three levels, but it required a ton of changes to the unit tests.

I then had the transactionID to the right places. I added that to the buffering in the market data and greeks cache, and then was ready to update the way the update events were sent. Previously, after each update of a block, the values would be recalculated. This almost guarantee problems with updates as the values would be recalculated within a "transaction". Bad. So I changed all that to only update if there was no transaction active - or at the end of a transaction.

The results are really impressive, but I want to do more testing tomorrow. It was really pretty simple once I had decided the best approach.