Sunday
Dec252011

utilities that make unit testing easier

Working with an application that requires many resources and services might take a while to initialize. Such is our Kontera Advertisers Center. When working in development mode it is nice to be able to run our Rspec tests. But although the test themselves run fast (about 300 tests in ~30 seconds), loading the environment takes 40 seconds. To ease the pain of waiting I use a spork!

 

Image taken from http://imgs.xkcd.com/comics/forks_and_spoons.png

 

Spork makes running unit tests faster by shortening the loading time. It requires some modifications to your spec_helper.rb file: (example from AC spec/spec_helper.rb)

require 'spork'

Spork.prefork do
  # Loading more in this block will cause your tests to run faster. However,
  # if you change any configuration or code from libraries loaded here, you'll
  # need to restart spork for it to take effect.
  ENV["RAILS_ENV"] = 'ci'
  $LOAD_PATH.push File.join(File.dirname(__FILE__),"..")
  require File.expand_path(File.join(File.dirname(__FILE__),'..','config','environment'))
  require 'spec/rails'
end
Spork.each_run do
  # This code will be run each time you run your specs.
  Dir[File.expand_path(File.join(File.dirname(__FILE__),'/spec_helpers','**','*.rb'))].each {|f| require f}
end

To use Spork: Install spork gem:

gem install spork

Bootstap spork: (then modify your spec_helper)

spork --bootstrap

Run spork in the background: (from application root)

spork &

Add --drb to the running test, for example:

spec spec/models/permissions.rb -c -fn --drb

 

Sunday
Dec182011

Porting from Ruby 1.8.7 to Ruby 1.9.3: An Oddyssey

Episode I

Late November afternoon, a yellow sun hangs over the glass buildings of Herzliya Pituach, and here at Kontera the Moon team has decided to finally face an ancient challenge and attempt to port one of our core services to Ruby 1.9.3.

Unlike Achilles at the gates of Troy, we had no heavenly assistence from the gods, except one - Google, the God of Knowledge.

Our journey started by installing Ruby 1.9.3 (preview), and creating a new gemset.

The first problem soon popped up, not much more intelligible than the riddle of the Sphynx.

It looked like this:

undefined method `path' for class `ActionController::UploadedStringIO

The problem it seems lay in the fact that we needed to use Ruby on Rails as a gem rather as a 3rd-party code.

We therefore deleted the Rails vendor folder:

rm -rf vendor/rails

Next we had to decide on a matching version of Ruby on Rails. Having first tried 2.3.8, we made up our minds to go with 2.3.14.

Removing unnecessary plugins was a high priority - we managed to delete all but four:

  • acts_as_addressable
  • acts_as_commentable
  • acts_as_permissable
  • auto_complete

The other plugins we replaced with gems.

Unfortunately, even these many offerings could not please the gods of Ruby, and not much later we encountered our next challenge.

Episode II

It soon came to our attention that 'CGI::Session::ActiveRecordStore' had been deprecated, giving us the following error

uninitialized constant CGI::Session:

The solution, it seemed, lay with simply changing "CGI::Session::ActiveRecordStore" to "ActiveRecord::SessionStore".

Just like a Harpy, right on the heels of this error arrived another one:

uninitialized constant ApplicationController

here the solution was as simple as before - renaming the file "application.rb" to "application_controller.rb"

So far so good, but the next issue proved to be quite a Chimera. A file called 'admin_access_helper.rb' is apparently needed by the app, and is nowhere to be found:

cannot load such file - admin_access_helper.rb

After searching all across the wide web and consulting every oracle we encountered, the mystery seemed to no closer to solution. Finally we decided to call it a day and go back to our tents to sleep.

The morning, however, brought a surprising turn of events - just like the Greek armies on the beaches of Troy, this problem dissappeared into thin air!

It completely vanished, leaving no trace behind except its tracks in our logfile.

Puzzled and even a bit concerned, we decided to continue on our way.

Episode III

Finally after many efforts we managed to set sail on the Rails and leave the sands behind us - the application was finally up and running on our localhost.

A long journey still lay ahead of us before reaching safety, however, and it was not long before dark clouds gathered overhead, in the form of an error message:

stylesheet_link_tag : wrong number of arguments (1 for 2)

The problem lay in a method called 'expand_stylesheet_sources', which now was hungry for two arguments instead of one (the second is a Boolean named 'recursive').

So a TRUE was added as a second argument, and we continued.

A third error now reared its ugly head:

sessions_controller.rb:86: syntax error, unexpected ':', expecting keyword_then or ',' or ';' or '\n'

But seasoned code warriors by now, solving it was easy - simply removing the offending colon.

The sun started to set, and we decided to stop for the night on a small island and attempt to rest, before continuing on our journey.

TO BE CONTINUED...

Sunday
Dec112011

First Steps on Amazon's CloudWatch

In this post we will go over some of the services offered by Amazon Web Services, focusing on CloudWatch in particular. I'm assuming that you either have some app running on AWS or at least you know the rudiments on how to launch one.

I don’t need no CloudWatch: my app is bullet-proof

Yes, you have thought out every contingency, every possible happenstance, and every little accident that the universe could throw at your app. You have plans named after most letters of the alphabet. Your app is so strong that it will outlive cockroaches in case of a nuclear attack. However, there's still that devil-spawn butterfly down there in Brazil, waiting for the TechCrunch feature about your app to go live so it can flap its multicolored wings and bring it to its sorry knees. Or better yet, that butterfly and its buddies are waiting for you to showcase the app to potential investors.

Back in the old days (1990's), the best practices to keep a server up and running included smearing garlic on the sides of the server rack, hanging clovers and horseshoes on the door and lighting a candle to Edward Murphy. This list is not exhaustive. Now, with the advent of cloud computing we don’t even know where the servers are, let alone have access to them without getting shot at or eaten by giant Dobermans.

OK, I need CloudWatch; how do I go about it?

Out of the box, the guys at AWS give you five metrics at a frequency of one sample every 5 minutes. For free. These metrics are CPU, Disk Reads, Disk Writes, Network In, and Network Out and are stored for two weeks. To have a look, log in to your AWS console and select the EC2 tab. Once you see the instance you're interested in, click on it: on the bottom half of the console, click the tab labeled "Monitoring". Do it, I'll wait here.

While we are on this screen, go to the "Description" tab and write down the instance id; we'll use it later. To get a collective impression of how things are running, select multiple instances on the top half of the console. The "Description" tab will show nothing useful, but the "Monitoring" section will render an aggregation of metrics, each instance with its own color.

There isn’t much you can do with these metrics but get a feeling on how your fleet is doing. Think of it as licking your finger to get a sense of where the wind is blowing.

In order to close the feedback loop, we need a way to take action based upon conditions we can measure. Enter CloudWatch. On the top of the console, go over the "CloudWatch" tab and select "All Metrics" on the Navigation panel. On the "Viewing" combo box, select "EC2: Instance Metrics". You'll see a list of metrics; we're after the one reading "CPUUtilization" for the MetricName field, and the instance id you wrote down earlier (told you we'll need it) for the InstanceId field. Clicking on it will bring forth a more detailed graph and some nifty buttons on the right side. You can play for a while and go reminiscing with your instance going back and forth in time, up to two weeks ago. The fun part begins with the "Create alert" button.

In the alarm creation wizard you can set up a threshold condition that will trigger the alarm. Once you set this threshold you can define what you want it to do. Alarms can be in one of three possible states: OK, ALARM and INSUFFICIENT DATA. When the threshold condition is reached for the period of time set, the alarm will go from OK to ALARM. This state transition could also initiate an action. Notice that the actions are performed only during state transitions. Let's have a look at this with an example: say you set an alarm whose threshold is 90% CPU for 30 consecutive minutes. During the first 29 minutes the instance is at 90% CPU the alarm is still in the OK state. Worse still, if the CPU is at 100% during those first 29 minutes, the alarm will remain in the OK state. Once the alarm transitioned to the ALARM state, if an action was defined for this transition it will be taken. The alarm will remain in this state until the condition does not hold, i.e. the CPU has been below 90% at least for one sample in the last 30 minutes.

Here's when CloudWatch' sampling frequency becomes relevant: you can have 1 sample every 5 minutes for free, or 1 sample per minute for a monthly fee per instance monitored (at the time of this writing, it was around $3.50/month/instance). If you are sampling once every 5 minutes, and you set the alarm condition for 10 minutes you are actually evaluating only two samples. Conversely, if you take many samples at that rate, things can get very bad till the moment you notice. In short: spend the three fifty and sleep better.

 

would you rather give 3.50 to the loch ness monster?

There's also the third state: INSUFFICIENT DATA. The alarm enters this state when, as is implied in the state's name, it does not get data from the instance. Setting an action for a transition to this state can be immensely valuable: it basically tells you that your instance is dead.

Regarding the actions that can be taken upon transitions: the most obvious is of course sending an email. To set this up you need to define a channel of sorts in the Simple Notification Service (SNS) tab. You set a topic ("database-machines") and assign to it subscriptions (email addresses of people on your team). More interesting alternatives to email are HTTP, SMS and SQS. With HTTP you can set up a web service somewhere that reacts to the alert. And with SQS you can dispatch messages through Amazon's Simple Queue Service; how cool is that?

All that is pretty cool… what else can CloudWatch do?

I'll write about custom metrics and auto scaling in the upcoming posts. Stay tuned!

 

 

Wednesday
Nov302011

Mock It All Up

We are supporters of Test Driven Development / Behavior Driven Development, and, consequently, we've picked Jasmine as our ultimate testing tool: it is quick, friendly and easy to learn, and our code is tested with every build.

There are many reasons to write/maintain code in a modular manner. When considering testing, the modular code allows each segment/class/flow to be tested separately. Before you object, let me demonstrate one tip that might come handy. Here is a (simplified) class to be tested:

    
function ModalOverlay() {
    var shown = false;

    this.show = function() {
        // roughly will open a dialogue only in half of the total requests
        if (Math.random() < 0.5) {
            shown = true;
        }
    }

    this.hide = function() {
        shown = false;
    }

    this.isShown = function() {
        return shown;
    }
}

That's right! The overlay code is by no means deterministic but still testable as is. How? Let's inspect the well-known Math.random() method:

    
describe("Modal Overlay Test", function() {
    var mocRandomObj;
    var modalOverlay;

    function MocRandomObj() {
        var predefinedRandomResult;

        this.set = function(result) {
            predefinedRandomResult = result;
        }
        
        this.get = function() {
            return predefinedRandomResult;
        }
    }

    beforeEach(function() {
        mocRandomObj = new MocRandomObj();

        // here goes the punch!
        spyOn(Math,'random').andCallFake(mocRandomObj.get);

        modalOverlay = new ModalOverlay();
    });

    describe("when probability is coined", function(){
        beforeEach(function() {
            mocRandomObj.set(0.4);
        });

		it("should show overlay", function() {
			modalOverlay.show();
			expect(modalOverlay.isShown()).toBeTruthy();
		});
	});
});

As demonstrated above, with a big help from spyOn() a fake code block is called and a known "probabilistic" value is returned. You couldn't ask for it to be any more simple! Generalizing the above approach, we can be extremely flexible and mock all kinds of behaviors in almost every granular level, leaving the tested code intact.

We will be more than happy to hear about your testing/mocking tricks and techniques. If you choose to share any tips or constructive criticism of your own, we are here to listen (and respond).

Sunday
Nov272011

Javascript Functions as a Mind Map

In Clean Code: A Handbook of Agile Software Craftsmanship, the author describes the optimal structure of an agile function:

The following advice has appeared in one form or another for 30 years or more.

  1. Functions should do one thing.
  2. They should do it well.
  3. They should only do that function.

In order to make sure our functions do one thing, we need to make sure that the statements within our function are all at the same level of abstraction.

Usually, the statements are themselves made of functions that also do one thing, leading to a recursive structure. If you think about it, the basic structure of functions is Mind Map. We will illustrate this at the end of the article.

Javascript is really one of the best languages to illustrate this Mind Map concepts because in javascript, functions are first class citizens and functions can be nested very naturally. So let's take a very common example in javascript: the testing of some new feature: the feature is only enabled in some predefined ratio of the page views and then we compare performance vs. the old feature. For example, imagine you want to compare the user experience of two designs of the same button. The cool name for this methodology is Ab testing.

As an example, let's dig into the code for the creation of a COOOOL Button: sometimes, we will use the new style and sometimes the old style:

function createCOOOOLButton(){
    if(shouldUseNewStyle()){
        createNewStyleButton();
    } else {  
        createOldStyleButton(); 
    }
}

In this post, we will focus on the implementation of the function shouldUseNewStyle(). This function is not the most complex function one has ever written, but it is neither so trivial. There are different constraints to deciding whether we want to use the new/old style:

  1. Ab test value (generated by the server or randomly)
  2. Url parameter (enforce new/old design - mostly used for dev/test phases)
  3. Enforce new design for fancy users

Let's try to express this complexity in a single line of code where all the parts belong to the same level of abstraction.

function shouldUseNewStyle(){
    function isEnforcedByUrlParam() {...}
    function isEnabledByAbTest() {...}
    function isEnforcedByUserCategory(){...}
    return isEnforcedByUserCategory() || isEnforcedByUrlParam() || isEnabledByAbTest();
} 

Hey!!! Wait a minute. How do you implement all those functions? The answer is very simple: NEVERMIND. Or more accurately, at the level of abstraction of shouldUseNewStyle, it is of no interest to dig into these details. Writing all those details into separate functions is the essence of the structure of an agile function. It ensures that:

  1. The code is structured into small blocks
  2. All parts of the blocks belong to the same level of abstraction
Exactly like a Mind Map!!! (Be patient, and wait until you see the illustrating image at the end of this post...) As a consequence, the code is readable and there is no need to comment it: the code comments itself!

Now, we can continue our recursive journey into the details of the implementation. Let's say, we want to read the code of isEnforcedByUrlParam(). No problem, just unfold the line (any descent IDE supports folding/unfolding: even vi!!!) and here is the result

function isEnforcedByUrlParam() {
    function getUrlParameter(variable) {...}
    return getUrlParameter('cool_button_new_style') === '1';
}

It's that simple! The enforcement by url occurs if, and only if, the cool_button_new_style url parameter is switched on. Again very readable. Again, we don't care about the implementation of getUrlParameter() - at this level of abstraction.

Let's end our recursive journey here. Just before you go back home, let me keep my promise and summarize in a single picture the whole structure of the agile function we have described. Let me introduce the Mind Map!!!