Archive for October, 2012

Google Chrome dev 24.0.1284.2 is Out

Wednesday, October 3rd, 2012

Google Chrome

This morning I saw that the Google Chrome team has upped the major version number of Chrome to 24.0.1284.2 with a few nine updates, and several bug fixes - notably a few Flash issues, crashes, and a new version of WebKit and the V8 javascript engine. Nicely done. I'm curious why this qualifies as a major release number, but I think it has more to do with when the version gets stable enough to deploy out to the masses, then the dev version has to up it's number to be unique. Sure seems like it anyway.

Well… nicely done to the Chrome team!

Added Days to Close for Anticipating Demand

Tuesday, October 2nd, 2012

WebDevel.jpg

In the original code of the seasonality adjustment to the raw demand data we're getting, I had added in a fixed 6 weeks lead time for getting and closing deals. This was given to me by the project manager, and I used it because I didn't know any better number to use. What this allows us to do is to anticipate the demand rise (or fall), and adjust who to call today. Sounds like a good idea, but it could always be better.

This afternoon, it got a lot better. Ryan looked into Teradata at the time (in days) between the first call to a merchant, and the closing of the deal and came up with an average number of days for a deal cycle - bucketed by the category of the business. He sent these to me, and I was able to use this - along with a more general global average number of days for all deals, and use this in the code.

Now we have a solid default deal time, as well as better values for specific categories of businesses. This is great news. It took him less than a few hours, and I implemented it in about 15 mins. Fantastic work.

Ever better. Sweet.

Adding Seasonality Reasons – Against My Judgement

Tuesday, October 2nd, 2012

Bad Idea

After looking at what I had done for the seasonality adjustment of the demand data - something that should be handled upstream of us, but at this time it's not, the project manager decided that he wanted me to add in the reasons to the solution. Something like: Increased demand for Boat Tours in Oct (150%). And then to carry these through to the client so that they can see why the demand is, what it is.

I told him that I thought it was a bad idea because it's not going to last. Specifically, when the demand service is really finished, it's going to be broken out into at least four components:

  • Inventory Replenishment - any decent inventory control system can see what's being sold (rate), the inventory on hand (quantity), and then project the need to acquire more. This has nothing to do with seasonality, but will naturally take care of a lot of demand issues because the more that's bought, the more we'll acquire. Simple.
  • Manual Demand Insertion - there will always be the need for a system to accept manual commands from a wise and thoughtful operator, and in this case, there are folks that will anticipate demand for things that simply can't be put into code.
  • Demand Forecasting - this is where you want to look at the month-by-month sales, see what might be needed - see the lead time for it, see what we have, and then try to plan what's needed based on past experience. As well, it'd be nice to have this part of the system capable of detecting demand much in the same way the manual input is done.
  • Mixing Board - these previous three components need to be "mixed" together with an aggregator/balancer that allows the user to adjust the "signal strength" of each input independently, and then also adjust the output. Very much like a sound board, you need to be able to mix in all this demand carefully and then feed it into the main engine we've developed.

and he knows all these pieces, and knows they are on the way.

So I say: "The final demand system will have seasonality built-in… we won't be able to get at that data because it'll be baked into the operation and data."

"Yeah, but maybe we need introspection on that…" he replies.

"Think about it… it's not going to happen… what if there's a natural 3 month cycle to some service… we'll see it repeated, but we won't know the reason"

"Oh…"

So he presses - despite my objections, and I implement the feature. Then we talk about this afterwards, and he says "Listen, you tell me if you think it's a bad idea, or hard to implement". I about scream. But I keep my cool.

We talk for about 15 mins about this, and I point out to him that I have been saying the exact words he asked me to say to stop this process. He just wasn't listening. And this isn't the first time for him, either. Not by a long shot. It's one of his more annoying features - he just doesn't listen.

It's in there, and it'll be going away, and the users will wonder where it went, or we'll make a complete mess of the system and try to include it in the final demand values. But I think I'm going to say "No" to that. It's just not possible to really do a decent job of that.

Dealing with JRuby Jar Deployments – Reading Files

Tuesday, October 2nd, 2012

JRuby

One of the nice things about using JRuby is being able to use Warbler to package up all the files and scripts into a single jar for easy deployment. One of the problems with that is that some of the common coding statements don't work the way you expect them to - but they do work.

When I had an issue with reading a CSV file in a jar, my solution was to "go to the metal" and work it out in Java. This worked, and it was OK, but it wasn't something that was transportable to a non-JRuby environment, and I wanted to have that. So this morning I tackled just that.

The thing that's been bugging me was that Configulations works just fine in our code - jar or no-jar, so why was that working and the file reads of CSV files not? What I needed to do was to look seriously at how they were being used.

We were using Configulations in the following snippet:

  require 'configurations'
  require 'date'
 
  AppConfig = Configulations.new(File.dirname(__FILE__)+'/../config')

I know that JRuby 1.7.0 doesn't like the use of the '/../' in the path in a jar as it tries to "walk" the structure, so I changed this to a slightly less round-about way:

  require 'configurations'
  require 'date'
 
  AppConfig = Configulations.new(File.dirname(File.dirname(__FILE__))+'/config')

This allows JRuby to handle the parsing of the path as it sees fit and I don't have to worry about moving around within the jar file like I can in a filesystem.

And then it hit me… how we're using the filenames in the reading of the CSV files:

  require 'csv'
  require 'json'
 
  module FileUtility
    DATA_FILE = 'lib/sales/histData.csv'
 
    # ...
    if File.exists?(filename)
      File.open(filename) do |file|
        contents = file.read
      end
    else
      # ...
    end
 
    # ...
  end

and it stood out as clear as can be - the path was wrong. We were looking for these CSV files in a directory relative to the existing directory. How was JRuby to know that we wanted to look within the jar? Impossible.

The Configulations example worked because it used the dirname() method relative to the existing file - which is in the jar. That means that we were the ones telling JRuby to look in the jar (or on the filesystem), and it was all about the path we prepended to the beginning of the file we wanted to load.

There was no need to have the Java solution - we just needed to be more careful with the location of the CSV files. What we have now is far simpler:

  def self.read_file(filename)
    contents = ''
    File.open(project_root + '/' + filename) do |file|
      contents = file.read
    end
    contents
  end
 
  def self.read_csv(filename, key)
    res = {}
    CSV.parse(read_file(filename), :headers => true).each do |rec|
      k = key.map { |c| rec[c] }
      res[k] = rec
    end
    res
  end
 
  def self.read_json(filename)
    JSON.parse(read_file(filename))
  end
 
  def self.project_root
    @root ||= File.dirname(File.dirname(__FILE__))
  end

where once again, we use the "double dir" method chain to get the parent's directory, and use that to know that it's the root of the project - based on the location of this file in the project. This is far, far simpler than we had in the past, and it's removed all the silly Java code that wasn't really necessary in the first place.

It's important to realize you solved a problem, but not in the way it was intended. I'm glad I went back and fixed this. Very glad.

Added Seasonality to the Demand Data

Monday, October 1st, 2012

WebDevel.jpg

One of the things that's really quite limiting about the current demand forecast data from another system at The Shop is that it's not a month-by-month demand projection. They took the year's sales data and then extrapolated for the next month. But in doing so, they have removed any monthly/seasonal trends so that the demand for Boat Tours in Chicago is the same in July as January. Clearly, absurd. Unfortunately, there doesn't seem to be the will to push a change in and fix the Demand in a reasonable timeframe. So I had to add in some kind of demand adjustment based on the month and some sense of the time to close a deal.

What I came up with was a series of factors - one per month, that could be individually adjusted in a GUI - like an equalizer, and then we'd take each of these and multiply the given demand by this factor and divide by 100 (converting it into a percentage). In this way, we can ramp things up, and shut them down, a month at a time.

If they want to boost something up, they can pretend it's seasonal, and use move everything up to 200%… if they want to suppress something, then move all months to 25% - simple. It's a great plan, and we can "seed" the data with the sales data by service, by month.

What I need to do is to start with the code and then work back as I'm not about to do the GUI first - I'm no artist, and that's what this is going to take to make it look really nice.

More Salesforce Production Issues

Monday, October 1st, 2012

cubeLifeView.gif

This morning we once again had a series of production problems caused by Salesforce.com - this time, it was that a class had been deployed to the production instance and the permissions hadn't been set properly. How I figured this out - I don't know. I mean, I know how I figured it out - I looked, but to look was a stroke of luck.

I certainly believe in things we can't see and touch, so I'm not against divine intervention, but I just have no idea why He'd want me to figure this out so quickly. In any case, all the calls to updating the merchant data were failing, and the error was not the same one as I'd seen previously, so seeing no one in the Salesforce support group in at 7:00 am, I decided to start digging and see if I could find the problem.

Thankfully, I remember the support crew checking these in the last go-round, so I thought I'd give it a go. Turns out I was right. Still took me until 9:00 am to get everything re-run for the day. Nothing I could do about it, but without checking on their part, and them coming in later, there's not much else I could do.