This evening I finished up the work I needed to do on the optimization of the Pinning process to use the indexed demand data, and I have to say that I'm very happy with the results. When I really dug into it, I was happy to realize that as long as I kept the complete set of matching criteria in the key, I would not have to do anything other than make the appropriate keys, look up and collect the data, and then unique it so as not to have any duplicates.
Thankfully, it wasn't really that hard. The key generation was pretty simple, and the collection and uniquing was not bad. In the end, a lot of code got thrown away because we simply weren't doing anything nearly as complicated as we had been doing, and that was great news!
I had to write a few tests on the indexing of the demand data, but that was to be expected, and once it was indexed, that was all I needed to be sure of.
It took me a while, but not too bad, and Liza and the girls were at a movie I didn't want to see, so it all really worked out.
Nice!
Posted in Coding, Cube Life | Comments Off on Optimizing the Pinning Process (cont.)
Late today I was talking with Phil, a co-worker, and he had placed some New Relic instrumentation in the code and with the results we obtained from a few runs, it was clear that the way in which we were pinning the demand points to the merchants was a real problem. Like the singularly largest time spent in the code. And in a way, it makes sense - we're scanning all demand points for each of several thousand merchants, and that's going to take some time.
What's the better solution? Well… indexes, of course!
What we decided to do was something like what we'd done in a different part of the code, and I decided that I wanted to do it. The plan was to index all the demand data very much like a HashMap does - but the key for each 'bin' is the same values that we are trying to match in the scanning code.
For example, if we're matching the City, State, and Service, then we make the key:
key = [city, state, service]
and then use that as the key in a Hash to hold an array of all the demand points that have those three values. Of course, for a demand point with multiple services, we'll have multiple entries in the indexing data, but that's OK, as Ruby does all this with references and not deep copies.
I'm just getting started, and I'm planning on working on it this weekend, but it's looking very exciting, and I'm really happy the direction this is going.
UPDATE: I'm happy to say that I got a lot of good work done on the train. I still need to finish a lot of loose ends, but the bulk of the work should be ready to go. Lots of testing to do, but it's looking good.
Posted in Coding, Cube Life | Comments Off on Optimizing the Pinning Process
Today I finally decided to take an axe to three rather silly facade classes in the code. These guys were really less than 10 lines for the entire class, and it was very simple to move the one to two useful lines from the class into the calling method of another class and toss the entire class away.
It's been bothering me for a while, but I'm new to Ruby, and I didn't want to make waves in the group, but I got enough support from a few of the old guard Ruby guys that I decided to trash the silly classes.
It was really nice! I felt like the code I was getting rid of was just a red herring to someone trying to understand the code. The tests were unnecessary and burning up time, and there was really no reason for any of it.
Much better.
Posted in Coding, Cube Life | Comments Off on Simplifying Code – Finally Killed the Facade Classes
I was looking at the results of the overnight runs and realized that I really needed to work making the nightly runs far more robust by retrying the complete division run if there were errors in the processing. The trick was - How?
So I came up with the idea that the summary script that's gripping the log of the process, could, in fact, look at the log and determine if the run was a "success". Then, I could have it return a simple error code and the nightly run script could detect that and place the division into a retry queue if it failed.
Great idea, but getting the Bash scripts to do it was a little more work than I'd expected. Oh sure, the exit value from the summary script was easy, I just had to pick the right thing to test in that script, and after a few tries, I got what I needed. No… this was about the dealing with the string vs. integer nature of the bash variables.
For example, this is OK:
if[$pass-gt3]; thenbreakfi
unless$pass is a string, and then you get an error and die. So it's possible to say:
if[[$pass>3]]; thenbreakfi
but this seems to cause me grief:
if[[$pass>= 3]]; thenbreakfi
It's not easy to figure out all the edge cases until you've written more than a few bash scripts using a feature, but hey… that's the power and grief of using bash.
In the end, it was really much easier to force the type of variables and make sure they are OK, than it was to try and figure out why 'greater than' was OK, but 'greater than or equal to' wasn't. The goal was to have a couple of scripts tied together that allowed me to ensure that they nightly runs worked, and worked well, and I've got that now.
There are several problems related to the underlying sockets in JRuby that are fixed in 1.7.0, so The Team was interested in moving to it as soon as realistically possible, and today was that day. Everything seemed to be working just fine, but then when we tried to run the code in the CI environment we got all kinds of failures due to the code we were using. While CI was running JDK 1.7, and I think we're all on JDK 1.6 for our laptops, the glibc that exists with CentOS 5 is too old to run the JRuby 1.7.0 code.
I have used CentOS 5 for a long time. It's stable, but it's old. There's a lot to be said for stable, but when it's impossible to deploy things because the fundamental libraries are too old, or the packages are too old to run a recent package from someone else, then it's time to really consider a change.
Here, the solution seems to be to build a custom glibc and then just force the LD_LIBRARY_PATH for the particular application. But that's got all kinds of stability problems in it. Glibc isn't like just another library - it's a fundamental library in the OS. There's tie-ins to the compiler and a lot of other things that aren't as easy to assume will be "OK" with just a new version of glib.
But I've already asked, and it's just not going to be possible to update to a more recent OS. Politics and support make this just right out.
At The Shop we use Campfire for 'chat' as opposed to using IRC. I can see the advantage - it's very popular, it's already logging, and there's a reason to outsource those things that you don't offer a competitive advantage. There's a nice Mac OS X native app called Propane that allows you to have Campfire open in a nice app as opposed to a web browser. It's basically a simple WebKit view of the data stream from Campfire, but it's nice and slick, and there's several things it can do that are nice.
One of the nice things is that it can do is to offer call-backs to the image rendering so that we can modify the stream, and easily add additional CSS for the rendering. This was something I've been looking to work on as I don't really like the default font and size as well as seeing a few guys in The Shop having a nice call-back that adds the user's gravatar to the stream.
Here's how I did it.
First, you can get use copy this gist:
as the file: ~/Library/Application Support/Propane/unsupported/caveatPatchor.js
Restart.
That's most of it as it's got the gravatars now. Next, is to change the fonts of the main text and the fixed-width text in the chat window. In order to do that, you need to look in the directory: ~/Library/Application Support/Propane/styles/ and modify the file cf_chat.css to have:
I love King's Island's roller coasters, and The Beast is the best. If you ride it at night - right before the park closes it's chilling and thrilling, and no matter how many times I ride it, it's always a new thrill for me. Today was kinda like that - but at work.
So we had 'Launch Day' on Monday, and so as you might expect, there were a bunch of "little things" from the users that needed to be attended to. Certainly understandable, and I've done this enough to know that this is just the way things are… still, like riding The Beast, it's something that certainly gets your heart racing.
First and foremost - it's about time. You have a day to get as many of the "bad" problems fixed, tested and into production as possible. This is because the first impression you gave the users today is going to be supported by the changes you can give them tomorrow. Speed of fixes is crucial in the first days of a project.
Then it's about quality. You can't introduce problems with the fixes, so you have to be careful. This is most often where I have seen a lot of folks stumble. They fix one thing and then break another, and the result is that the users think the development staff is asleep at the wheel. Not good.
So today has been a lot of very fast, very careful work highlighted by the fact that we're really doing the vast majority of the work do deal with crummy sources and sinks of data. I was thinking about this a few days ago, and wondering why this seemingly simple project had so many developers on it and was taking so much time. True, we're ahead of schedule, but that just reinforces my concern.
In Finance, this would have been a few weeks of one or two people - tops. Here's it's much more than that. Why? Well… I came to the realization that about 90% of the code we've written is about dealing with bad sources and sinks of the data. I know the purported benefits of SOA… it's supposed to be great. But that's only true for little things. There's a reason that databases are useful and valuable.
We read a lot of merchant data from an unreliable source. If this were in a database in the data center, then this would be trivial. Likewise for reading the demand data. Updating data would be super easy as we'd have some stored procedure or something to update it.
Yet due to SOA, all this is taking tons of time, and then there's the SSL layer on top due to the fact that a database offers security, but a web service doesn't. It's a mess. But I understand why they are doing it - it's "the way". Still doesn't make it efficient.
I'd love to trade in the sources and sinks for a few databases. The code would be 100x faster, far more reliable, and far less complicated. When I write stuff, I'm not going to let the Kool-Aid get in the way of making a good system.
Posted in Coding, Cube Life | Comments Off on Nothing Like Riding the Beast at Night – At Work
Well, I didn't realize what today was, so I was a little surprised to see that today was Launch Day for the project I've been working on at The Shop. It's nothing that I'm worried about, but it's been a very busy day considering what's going on.
The day started out with problems in the production runs, but I was in early enough to make sure that things worked out, and then we're off to the races. There were a lot of things still to do, and today I started a few of them and passed off a few to some of the guys in the group.
First, we need to look at the performance. It's horrible. I mean really bad. It's taking an hour to run a division on the production "box" at EC2. Compare that to running it on my MacBook Pro at about 5 min. and the problem is evident. We need to fix the I/O issues. Maybe it's all in the resources of the EC2 machine, but maybe we have what we have and need to change the code around to make it more efficient.
Right now, we need to up the resources, which I did, and let the runs go again and see what the performance differences are. I'm hoping to see significant improvements, but I'm guessing we won't see real improvements until we get the dedicated hardware at the SNC1 datacenter when that arrives. Still… cutting down the hour to 30 mins or so would really be nice.
Second, we need to have a lot better handle on the performance metrics. We have NewRelic wired in, but not nearly enough. We need to make it a lot more interwoven. So we took the time today and added a lot more instrumentation in the code so that come tomorrow we will be able to see a lot more of the breakdown of where the time is being spent.
Third, we needed to fix a bit in the code regarding merchants with closed deals that haven't run yet. In the existing code, these were considered merchants that should be contacted again, but in reality they shouldn't. So I needed to modify the Salesforce endpoint, and then put that to Staging and write the code to pick it up and do the math that was needed. It's not hard, but considering that we're live, it's something that needs to be done today.
So I spent a bit of time this afternoon getting the Salesforce changes in, checked into git and tested and going in UAT. Then I felt with the Salesforce guys to get it pushed to production. I needed it there in order to make sure it was going to run well tonight at midnight. I'm glad to see that it all got done.
Finally, there were a ton of little issues from the initial user feedback. Nothing major, but lots of little things that needed to be cleaned up before tomorrow. It's been a heck of a day!
Hopefully, it's going to work well tonight. But I'll be sure to be in good and early (like usual) to make sure that things are ready for the day.
Today I've been trying very hard to get a new view done before I have to leave early to catch a bus, to catch a train to get home in time to go to the Car Dealership to pick up the car we got for Marie to drive. It's a 1989 Volvo 740GL with 198,000 miles on it. That's a lot of miles, but I know she could not be happier with the car.
In any case, I needed to get this visualization done, and it meant that I needed to add a new view to the CouchDB as well as making it another drop-down on the page to allow the user to pick the sales rep to view. The basics of this page is to show the user the Top 100 merchants assigned to each sales rep in the division, ordered by the merchant's sales value.
It's not really all that hard, but in keeping with the style I've change to with these pages, it's a lot of little calls, as opposed to a few big calls and then manipulating the data once it's on the client. It's a different style, that's to be sure, but it's workable and I just needed to get the queries done, and the calls set up so that things looked reasonable.
Thankfully, I was able to just get things done before I had to leave.
Whew!
Posted in Coding, Cube Life | Comments Off on Working Feverishly to Build a New View
This morning I got a note about a Sublime Text 2 plugin for working with Salesforce.com APEX code as well as Git integration - MavensMate-SublimeText. This is a pretty amazing project for working with Salesforce.com code. While I haven't installed it on my laptop, it looks to be the thing if you're doing any significant amount of Salesforce.com coding. There are pages for running tests as well as immediate mode execution, and then of course, the highlighting and 'Code Assist'.
Very interesting. If I get into some real Salesforce.com code, I'll have to look harder at this.