Code Curiosity

Install Redis on Ubuntu

| Comments

Setting up Sidekiq recently forced me to install redis.Sidekiq requires a pretty recent version of redis. One more recent than the package manger on Ubuntu provides. You can use the following script to install a more recent version. It’s also useful for other packages you might need more up to date versions of (nginx, postgres, etc…)

Install redis
1
2
3
4
5
sudo apt-get -y update
sudo apt-get -y install python-software-properties
sudo add-apt-repository -y ppa:rwky/redis
sudo apt-get -y update
sudo apt-get -y install redis-server

python-software-properties adds the add-apt-repository command. add-apt-repository is a script which adds an external APT repository to either /etc/apt/sources.list or a file in /etc/apt/sources.list.d/ or removes an already existing repository. Basically, it allows us to reference and use the PPA (Personal Package Archives) and install a more recent version.

Check version
1
2
root@test:~# redis-server -v
Redis server v=2.6.16 sha=00000000:0 malloc=jemalloc-3.2.0 bits=64

Some other useful commands to test redis is running correctly.

Check port
1
netstat -nlpt | grep 6379
Check connection from another server
1
redis-cli -h xxx.xxx.xxx.xxx ping

You could also do this from your application

Check connection from another server
1
2
r = Redis.new(host: 'xxx.xxx.xxx.xxx', port: 6379)
r.ping

Learning Clojure

| Comments

If you are not aware of the ongoing shift from OO to functional programming, it might be worth watching this talk from Rich Hickey titled Are We There Yet. It contains many solid arguments in favor of pure functional languages, like clojure.

More and more languages are including functional aspects and it definitely feels like the way programming is going. Why not take some time with clojure?

Getting Started

The easiest way to play with clojure is with the web REPL. Let’s do a small experiment there now. Open the REPL in another window and copy the code below.

add function
1
2
(defn add [x y]
  (+ x y))

Now type

using add function
1
(add 2 3)

You should see the result 5. Congratulations, you just wrote your first clojure function. Let me explain. defn is a macro for defining a clojure function. add is the name of the function and [x y] signifies that the function takes two parameters. What about (+ x y)? Here we are defining a clojure list literal that will take two numbers and add them together. This feels wrong at first, but if you think of + as simply a function invocation, it really doesn’t seem that different from add(2, 3) which is very close to (add 2 3).

Now that you have had a little taste of clojure, let’s setup clojure and leiningen. If you are familiar with ruby, leiningen is a magical combo of rake, bundler and rails generators. This guide assumes OSX and homebrew.

install clojure and leiningen
1
2
brew install clojure
brew install leiningen

Now to start your first project, run the following.

create project
1
lein new adder

Here is what the project should look like.

project structure
1
2
3
4
5
6
7
8
9
10
11
12
13
14
cd adder
tree
.
├── README.md
├── doc
│   └── intro.md
├── project.clj
├── resources
├── src
│   └── adder
│       └── core.clj
└── test
    └── adder
        └── core_test.clj

Project layout

The project.cli is the starting point for your application. It should look something like the following.

project.cli
1
2
3
4
5
6
(defproject adder "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.5.1"]])

The only part here to note for now is the dependencies. This is where you can define other libraries you code will use. Assuming we had some defined, you can run the following to include them.

install dependencies
1
lein deps

Next, let’s look in the src folder. The core.clj file should look like the following.

core.cli
1
2
3
4
5
6
(ns adder.core)

(defn foo
  "I don't do a whole lot."
  [x]
  (println x "Hello, World!"))

Let’s replace that with the following. Notice our add function is back.

core.cli
1
2
3
4
5
6
7
(ns adder.core)

(defn add [x y]
  (+ x y))

(defn -main []
  (println "2 + 3 =" (add 2 3)))

A few things are going on here. ns signifies a clojure namespace. In this case, we are defining our namespace.

The other new part is a declaration for main. This won’t do anything just yet. We have to wire up the entry point first. Return to your project.cli file and change it to the following.

project.cli
1
2
3
4
5
6
7
(defproject adder "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :main adder.core
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.5.1"]])

Note the addition of a main symbol and our project namespace. This is what ties the projects starting point into our -main function.

Running code

We should now be ready to run the actual project.

run project
1
2
lein run
2 + 3 = 5

Hopefully that works. Once again, another small achievement. Your first clojure project is complete.

You can also play with your code in the REPL.

run REPL
1
2
3
lein repl
(add 4 9)
13

Notice how it loaded your add function. This is very helpful for debugging.

Testing

You may have noticed a test folder. Clojure has first class support for testing so let’s go ahead and add our first test. Open the file located at test/adder/core_test.clj and you should see the following.

core_test.cli
1
2
3
4
5
6
7
(ns adder.core-test
  (:require [clojure.test :refer :all]
            [adder.core :refer :all]))

(deftest a-test
  (testing "FIXME, I fail."
    (is (= 0 1))))

Let’s change that to the following.

core_test.cli
1
2
3
4
5
6
(ns adder.core-test
  (:require [clojure.test :refer :all]
            [adder.core :refer :all]))

(deftest addition-test
  (is (= 5 (add 3 2)) "3 added to 2 should be 5"))

Now when we start the tests. We should see our first passing test.

run tests
1
2
3
4
5
6
lein test

lein test adder.core-test

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.

Moving Forward

If you enjoyed your first taste of clojue checkout Clojure Contrib to find some sample projects. 4Clojure is another good site to find some clojure challenges.

Install PhantomJS on Ubuntu

| Comments

For those that know me, PhantomJS, is something that I have a soft spot for. It is fantastic for testing your JavaScript. Lately, I have been trying to use it to test my application features with Poltergeist, but have run into some version issues. For whatever reason, apt-get is installing a very old version (1.4). In order to install the current version you need to pull it down from the PhantomJS site. Below should help you out.

Setup instructions
1
2
3
4
5
cd /usr/local/share/
sudo wget http://phantomjs.googlecode.com/files/phantomjs-1.8.1-linux-x86_64.tar.bz2
sudo tar jxvf phantomjs-1.8.1-linux-x86_64.tar.bz2
sudo ln -s /usr/local/share/phantomjs-1.8.1-linux-x86_64/ /usr/local/share/phantomjs
sudo ln -s /usr/local/share/phantomjs/bin/phantomjs /usr/local/bin/phantomjs

The steps are straight forward, but let me explain them anyways. Hop into the share folder. Download the latest at the time of this post (1.8.1) into the share. Unzip the file. Symlink the unzipped directory to phatomjs. Symlink the phatomjs executable (though the previous symlink) into the /usr/local/bin. If everything worked, then you should see it when running the following.

1
which phantomjs

ORM Tradeoffs

| Comments

There has been much talk about ORM hate. I have had many discussions with colleagues at ThoughtWorks about their feelings on ORMs from their personal experience. Some think they are wonderful and couldn’t imagine life without them. Others think they are abused and included in projects too often. I have a theory where this latter argument is really coming from, but I will save that for the conclusion.

Make no mistake, ORMs are a compromise. Choosing to use an ORM library will not make all your SQL problems go away and will even introduce some new ones. Given that, let’s go through some of the main ORM attributes, starting with the negative ones.

Where ORM’s Hurt

Leaky Abstraction

Every ORM has some SQL concepts bleeding into it and you can never fully abstract away the implementation details. Configuration, mappings and relationships will require a deep understanding of how relational databases work and how to optimize them. There are no silver bullets.

SQL bleeding into code
1
2
3
4
5
var catNames = session.QueryOver<Cat>()
  .WhereRestrictionOn(c => c.Age).IsBetween(2).And(8)
  .Select(c => c.Name)
  .OrderBy(c => c.Name).Asc
  .List<string>();

Inefficient Abstraction

Depending on your needs, you may only use parts of the data stored in a table. For example, you only want a User’s name, but have to get the entire record out of the database because of your mappings, which may also include getting the User’s address from another table. This results in selecting more data than you need and includes an unnecessary join.

Performance Problems

Leaky as the abstraction may be, developers can still remain ignorant of the underlying SQL queries. This often results in poor application performance. SQL queries could be less than optimal, but you could also have other issues. For example, I have yet to see someone using an ORM and not be bitten by an N+1 problem.

Learn another tool

You should expect to spend time reading up on, experimenting with and debugging issues in the ORM of your choosing. This also provides a barrier to entry if a team member is not familiar with your particular ORM. This is true of any major library you would choose to use, but can easily be forgotten when including NHibernate for the 12th time on that new web project.

Batching and Reporting

Because these generally don’t fit into any domain model, your ORM will not be able to handle these concerns very well. Your ORM of choice will need to support writing SQL by hand for these queries. The more focus in this area you application has, the more your ORM will get in the way. Each ORM will have varying levels of support here.

Where ORM’s Help

Impedance Mismatch

This is primarily what ORMs were created for, so it shouldn’t be surprising they excell here. Impedance mismatches include figuring out the data types for fields, but can also cover handling relationships. For example, getting both the User and Address because the User mapping defines a has a relationship between the User and Address tables.

Developer Efficiency

An ORM easily generates most of your SQL queries from your data models and mappings. Some SQL queries will bleed the underlying query details into your application, but generally in a way that can be kept DRY and still ignore impedance mismatch details. For example, the code below has some knowledge of SQL, but manages to handle all CRUD operations in a highly reusable fashion.

CRUD Handling
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class Repository : IRepository {
    public ISession Session { get; private set; }

    public Repository(ISession session) {
        Session = session;
    }

    // Find by ID
    // Eg: var user = repo.Find<User>(1);
    public T Find<T>(int id) where T : DataModel {
        return Session.Get<T>(id);
    }

    // Find by predicate
    // Eg: var user = repo.Find<User>(x => x.name == "Tom");
    public T Find<T>(Expression<Func<T, bool>> criteria) where T : DataModel {
        return Session
            .Query<T>()
            .Where(criteria)
            .SingleOrDefault();
    }

    // Create or update
    // Eg: repo.Save(user);
    public T Save<T>(T item) where T : DataModel {
        using (var trans = Session.BeginTransaction()) {
            Session.SaveOrUpdate(item);
            trans.Commit();
        }

        return item;
    }

    // Delete
    // Eg: repo.Delete(user);
    public void Delete<T>(T entity) where T : DataModel {
        using (var trans = Session.BeginTransaction()) {
            Session.Delete(entity);
            trans.Commit();
        }
    }
}

Separation of Concerns

An ORM provides an excellent barrier between your application and your database. This makes adding cross cutting concerns, such as security and logging, much easier. For example, it is generally a trivial task to log all of your SQL queries with an ORM.

Caching is Much Easier

Related to the previous point, but there are two other things helping out here. First, many ORMs have great caching support. Most natively cache objects by their IDs and some will support third party caching through configuration. Second, the Inefficient Abstractions your domain models represent are often ideal caching candidates. The fewer ways you can get the same information, the fewer concerns your caching layer needs to get in front of.

Alternatives

When discussing the viability of using an ORM, Ad Hoc Queries and Stored Procedures often come up. DBAs usually favor stored procedures and procedural programmers usually favor Ad Hoq queries or some combination of the two.

Ad Hoc SQL Queries

SQL cannot be easily decomposed. There is basically no good way to share and reuse SQL inside your application. The effect of this is that your data access layer will become very procedural and it will end up consuming a disproportionate amount of your time solving the same problems repeatedly. You will also have the same leaky abstraction problems as an ORM, without a layer to protect you.

Stored Procedures

The same deficiencies as Ad Hoc SQL apply, but we have some additional problems. First, stored procedures are incredibly difficult to test in an automated fashion. Second, stored procedures tend to grow with time because they provide few techniques for restructuring and refactoring. The end result is something that is difficult to comprehend and impossible to test. This is why many developers will tell you that business logic in your database is almost never a good idea.

Conclusion

If you want to write object oriented code and persist those models into a relational database, you are going to be dealing with an ORM in some form. That doesn’t mean you have to use an ORM library, but beware of the cost involved in creating one before you get started on a “simpler” and likely less maintainable version.

At this point, it probably sounds like your options are to use an ORM or to store your data in a flat file. Before you go read up on file access, there is another option and this ties into what most of these discussions about the negative points of ORMs are really alluding to, the use of NoSQL. To avoid ORMs, while writing object oriented code, you could choose to go with a non-relational alternative (NoSQL). If you choose to go down this road, you should pick the alternative that best fits your domain model. For example, a blog or a CMS fits a document store like MongoDB really well, but not a graph database like Neo4j. Adding to that from personal experience, some of these alternatives can be a pleasure to work with. Most are many times easier to setup, develop on and to scale than a traditional relational database will be. For example, setting up a high availability MongoDB instance to test how it reacts to failure can be done on one machine in a couple of hours, most of that time spent reading. Have you ever done that with a traditional RDBS?

When choosing a NoSQL option, remember that you are giving up decades of research, tooling and support. You are also giving up an incredible powerful and prevalent querying language. Sometimes the tradeoffs (ease of developer use, scalability, cost, etc..) are worth it, but that is something you should carefully weigh, including things like the use of an ORM.

Testing Javascript in Rails

| Comments

This post is inspired by Derek Hammer’s testing coffeescript for rails with jasmine. His solution was great for getting my team started, but we both agreed it wasn’t ideal. I’m still not entirely happy with the final solution because you do need to start a rails server. However, I have made that as painless as possible.

The Setup

First, you will need to be using a version of Rails with the Asset Pipeline. This means Rails 3.1+

Second, we are going to be using PhantomJS to run the tests. Install PhantomJS with your favourite package manager (homebrew for me).

PhantomJS
1
brew install phantomjs

Now we are ready to begin. I am going to go through this with a new project, but there should be no difficulty in adding this to an existing rails project.

Create Project
1
rails new example_project

Next, update the gemfile. I use RSpec, but that is just a personal preference.

Gemfile
1
2
3
4
group :development, :test do
  gem "rspec-rails"
  gem 'jasminerice'
end

Install RSpec

Install
1
2
bundle install
rails generate rspec:install

Now we need to setup the testing folder. Create a folder under spec called ‘javascripts’ and then add the following spec helper file to it. Ignore the console reporter part for now.

spec/javascripts/spec.js.coffee
1
2
3
#= require application
#= require_tree ./
#= require jasmine.ConsoleReporter

Now you should be able to load up your tests in a browser by starting your rails server and navigating to localhost/jasmine

Let’s add a CoffeeScript class with a jasmine spec

app/assets/javascripts/example.js.coffee
1
2
3
class window.Example
  load: ->
    'Hello'
spec/javascripts/example_spec.js.coffee
1
2
3
4
5
describe 'Example', =>
  describe 'load', =>
    it 'should return hello', =>
      example = new window.Example()
      expect(example.load()).toBe('hello')

If everything worked correctly, localhost/jasmine should now show your failing spec. Before you fix it, let’s continue with getting jasmine working from the command line.

Remember that console reporter? We will we need to add that to report the jasmine test output to the terminal. Let’s place it in the vendor folder (vendor/assets/javascripts).

vendor/assets/javascripts/jasmine.ConsoleReporter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
(function(jasmine, console) {

  if (!jasmine) { throw "jasmine library isn't loaded!"; }
  if (!console || !console.log) { throw "console isn't present!"; }

  var colorMap = {
    "red" : 31,
    "green" : 32,
    "yellow" : 33,
    "purple" : 34,
    "pink" : 35,
    "turquoise" : 36
  };

  jasmine.ConsoleReporter= function() {
    window.jasmineErrorCount = undefined;
  };

  jasmine.ConsoleReporter.prototype = {

    reportRunnerStarting: function(runner) {
      this.startTime = new Date().getTime();
      this.executedSpecs = 0;
      this.passedSpecs = 0;
    },

    reportSpecStarting: function(spec) {
      this.executedSpecs++;
    },

    reportSpecResults: function(spec) {
      var results = spec.results();
      if (results.passed()) {
        this.passedSpecs++;
        return;
      }

      this.log("\n" + spec.getFullName(), "red");

      var resultItems = results.getItems();
      for (var i = 0; i < resultItems.length; i++) {
        var result = resultItems[i];
        if (result.type == 'log') {
          this.log(result, "yellow");
        } else if (result.type == 'expect' && result.passed && !result.passed()) {
          this.log(result.message, "red");
          if (result.trace.stack) {
            this.log(result.trace.stack, "yellow");
          }
        }
      }
    },

    reportRunnerResults: function(runner) {
      var failureCount = this.executedSpecs - this.passedSpecs;
      var specDetails = this.executedSpecs + (this.executedSpecs === 1 ? " spec, " : " specs, ");
      var failureDetails = failureCount + (failureCount === 1 ? " failure\n" : " failures\n");
      var color = failureCount > 0 ? "red" : "green";
      var duration = new Date().getTime() - this.startTime;

      this.log("\nFinished in " + (duration/1000) + " seconds\n");
      this.log(specDetails + failureDetails, color);

      window.jasmineErrorCount = failureCount;
    },

    colorizeText: function(text, color) {
      var colorCode = colorMap[color];
      return "\033[" + colorCode + "m" + text + "\033[0m";
    },

    log: function(output, color) {
      var text = (color != undefined) ? this.colorizeText(output, color) : output;
      console.log(text);
    }

  };

})(jasmine, console);

We are almost finished. Next we need to add a rake task to run the javascript tests. Add the following under lib/tasks

lib/tasks/jasmine.rake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
require 'rubygems'

namespace :jasmine do
  desc "Runs the jasmine tests"
  task :spec => [:start_server] do
    unless system("which phantomjs > /dev/null 2>&1")
      abort "PhantomJS is not installed. Download from http://phantomjs.org"
    end

    sh "phantomjs lib/tasks/phantomjs_runner.coffee http://localhost:5555/jasmine"
    specs_passed = $?.success?
    Rake::Task['jasmine:stop_server'].execute
    fail('Jasmine Specs Failed') unless specs_passed
  end

  desc "starts the jasmine server"
  task :start_server do
    # empty log file
    File.open('log/jasmine.log', 'w') {|file| file.truncate(0) }

    # start jasmine server
    sh "rails server --port=5555 >log/jasmine.log 2>&1 &"

    20.times do |i|
      log_contents = File.read('log/jasmine.log')
      if log_contents.length == 0
        puts "waiting for server to start..."
      else
        sleep 0.5
        break
      end
      sleep 0.5
    end
  end

  desc "stops the jasmine server"
  task :stop_server do
    `ps aux | grep port=5555 | awk '{print $2}' | tail -n 1 | xargs kill -9`
  end
end

task :spec do
  Rake::Task['jasmine:spec'].invoke
end

Finally add the phantomjs runner under lib/tasks as well.

lib/tasks/phantomjs_runner.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# Script Begin
if phantom.args.length == 0
  console.log "Need a url as the argument"
  phantom.exit 1

reportWatcher =
  run: (page, max_tries=10) ->
    tries = 0

    callback = =>
      tries = @incrementTries(tries, max_tries)
      @checkForReportCompletion(page)

    setTimeout callback, 100

  incrementTries: (tries, max_tries) ->
    phantom.exit 1 if tries == max_tries
    tries + 1

  getErrorCount: (page) ->
    page.evaluate ->
      window.jasmineErrorCount

  checkForReportCompletion: (page) ->
    errorCount = @getErrorCount(page)
    if errorCount == undefined then return
    if errorCount == 0 then phantom.exit 0 else phantom.exit 1

address = phantom.args[0]
page = new WebPage()

page.onConsoleMessage = (msg) ->
  console.log msg

page.onError = (msg, trace) ->
  console.log msg
  trace.forEach (item) ->
    console.log " #{item.file}:#{item.line}"

page.onInitialized = =>
  page.evaluate =>
    window.onload = =>
      jasmine.getEnv().addReporter(new jasmine.ConsoleReporter())

# open test page and wait for completion
page.open address, (status) ->
  if status != 'success'
    console.log 'Unable to access network'
    phantom.exit 1

  reportWatcher.run(page);

That’s it. Run the following:

Install
1
rake jasmine:spec

You should now see the same test failure from before. Fix the case in ‘Hello’ and you will have your first passing JavaScript test.

Note

WEBrick may cause you some issues with stopping/starting. I used thin (gem ‘thin’ in your Gemfile) and the issue went away.

I have a project on github which this is based off of. Check it out if you want to get something similar setup outside of rails.

Tell, Don’t Ask

| Comments

I have been asking quite a few of my colleagues to tell me what “Tell, Don’t Ask” means to them. Mostly we agreed on a definition similar to what is below, but there was enough discrepancy to warrant a blog post. My definition is as follows:

TELL things what you need, don’t ASK them for information

In more detail, this means is that you should not be interrogating the state of other objects to make decisions. It is better to tell a module what you need and let the module sort out the logic. This helps to keep the module encapsulated and reduce the amount of coupling your code will have to the module. A real example drives home the point much better than any description. Below is a violation of Tell, Don’t Ask.

Problem Example
1
2
3
4
5
6
7
class Car
  constructor: (@doors) ->

car = new Car(4)

if car.doors > 2
  alert('Higher insurance!');

The Problem

Most of us have written code like this and will continue to do so. In a small example, such as this, the problems introduced are relatively minimal. However, there are problems and primary among them is coupling. Simply put, coupling is the degree to which each part of the code relies on another part. High coupling becomes a problem when we want to change the structure of the code.

What does this look like when we remove the violation?

Fixed Example
1
2
3
4
5
6
7
8
class Car
  constructor: (@doors) ->
  isSporty: -> @doors > 2

car = new Car(4)

if car.isSporty()
  alert('Higher insurance!');

The Solution

Coupling has now been reduced. Make no mistake, our change does not remove the reliance entirely, as a change in the car would still impact our code. What we have done is manage that coupling through a better separation of concerns.

In the violated example, the code that is coupled is deciding on state it does not control. Because the class does not control the state, we should push the decision making into the class that does. This helps to separate the concern (state logic) from the class we are working in and prevents it from being duplicated in the future.

The Problem With Pingdom

| Comments

Time to be Awesome - awesome.rb
1
puts "Awesome!" unless lame

The problem with pingdom.

My money’s in that office, right? If she start giving me some bullshit about it ain’t there, and we got to go someplace else and get it, I’m gonna shoot you in the head then and there. Then I’m gonna shoot that bitch in the kneecaps, find out where my goddamn money is. She gonna tell me too. Hey, look at me when I’m talking to you, motherfucker. You listen: we go in there, and that nigga Winston or anybody else is in there, you the first motherfucker to get shot. You understand?

Blockquote is what goes inside this block here would you believe that bullshit?

Well, the way they make shows is, they make one show. That show’s called a pilot. Then they show that show to the people who make shows, and on the strength of that one show they decide if they’re going to make more shows. Some pilots get picked and become television programs. Some don’t, become nothing. She starred in one of the ones that became nothing.

The path of the righteous man is beset on all sides by the iniquities of the selfish and the tyranny of evil men. Blessed is he who, in the name of charity and good will, shepherds the weak through the valley of darkness, for he is truly his brother’s keeper and the finder of lost children. And I will strike down upon thee with great vengeance and furious anger those who would attempt to poison and destroy My brothers. And you will know My name is the Lord when I lay My vengeance upon thee.

Your bones don’t break, mine do. That’s clear. Your cells react to bacteria and viruses differently than mine. You don’t get sick, I do. That’s also clear. But for some reason, you and I react the exact same way to water. We swallow it too fast, we choke. We get some in our lungs, we drown. However unreal it may seem, we are connected, you and I. We’re on the same curve, just on opposite ends.

Do you see any Teletubbies in here? Do you see a slender plastic tag clipped to my shirt with my name printed on it? Do you see a little Asian child with a blank expression on his face sitting outside on a mechanical helicopter that shakes when you put quarters in it? No? Well, that’s what you see at a toy store. And you must think you’re in a toy store, because you’re here shopping for an infant named Jeb.

Intro

| Comments

Testing!

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sollicitudin, massa eu vestibulum laoreet, nibh ante vulputate lorem, ac lobortis ante tellus eu mi. Duis sem nisi, luctus at feugiat eget, fringilla ut tellus. Nam a molestie justo. Sed pulvinar est vitae tellus semper tincidunt. Fusce euismod luctus lacus nec placerat. Mauris rutrum scelerisque nulla ut tempor. Nunc porttitor posuere mi, aliquet vehicula lorem feugiat in. Ut ut fermentum risus. Aliquam tincidunt ultricies ante sit amet bibendum. Cras nec sapien odio. Duis posuere congue sem, at congue massa faucibus at.

Integer ut sapien eget nisl auctor faucibus ut fermentum arcu. Nunc rutrum urna non risus congue et tristique felis eleifend. Maecenas blandit est eu mauris aliquam aliquet. Quisque porttitor enim eget risus blandit in mollis orci eleifend. Nam malesuada nulla sed lacus elementum placerat accumsan arcu rhoncus. Phasellus feugiat cursus turpis nec facilisis. Duis eget metus arcu, eget commodo velit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer cursus vulputate enim, vel gravida velit faucibus et. Ut a urna vitae tellus cursus rhoncus. Maecenas at odio eget quam cursus elementum. Aliquam vitae eros quis tellus laoreet accumsan sed id lorem. Suspendisse et rutrum leo. Integer scelerisque vestibulum adipiscing. In posuere, libero ac accumsan suscipit, nulla ligula gravida erat, ut tempor odio erat nec sem. Quisque justo ipsum, adipiscing volutpat varius vitae, blandit eget nisi.

Nullam adipiscing neque ac lacus commodo vitae imperdiet dui sollicitudin. Ut ac nunc augue. Nam at sem ut quam commodo aliquet vitae vitae dui. Vivamus scelerisque felis eget dolor cursus feugiat. Phasellus at dui sed lectus scelerisque pretium. Etiam nec massa ut justo vestibulum fringilla ac vitae urna. Morbi tortor erat, tempus sed consectetur at, elementum nec eros. Vivamus mattis arcu a sapien semper non lacinia eros pretium.

Proin ut hendrerit arcu. Maecenas ullamcorper tristique magna vel mattis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam tincidunt euismod viverra. In sit amet neque turpis. Suspendisse ac sapien mi, id blandit purus. Ut tortor turpis, rutrum ac tempor at, accumsan sit amet erat. Etiam ultricies eleifend dolor, eget tempus justo tristique vitae. In hac habitasse platea dictumst. Aliquam eu enim neque.

Morbi massa lorem, viverra non dictum at, malesuada vel nibh. Nam fermentum lobortis varius. Sed a nulla lacus, quis posuere risus. Nunc id urna libero, quis rutrum mi. In gravida felis urna. Praesent nec dolor ac urna tempor fermentum. Curabitur rutrum arcu et lorem volutpat viverra.

Conditions and Dictionaries

Last week I was involved in some new employee code reviews and pairing interviews. Since most people that apply to ThoughtWorks do our Mars Rover problem, I decided that I should probably give the problem a try. The solution is pretty simple, which is probably why most people select this problem. I happened to be in a programming mood at the time, so I decided to make the problem a little more difficult.

Could I write a solution without an IF statement?

It turns out that I can and the results were very interesting. Here is the first cut of my spin left method before the change over.



Here is another deviation with if statements, because you know… switches are smelly.



Then here is what I came up with when trying to remove all my conditions.



Personally, I find it much more readable than the other two. This is something I would not have expected given an arbitrary challenge. Maybe those anti-if people are onto something.

Comments

Tyler
I ended up with 5 classes in the end and some constants (like Direction). Seemed to work pretty well and the total code was about 100 lines, with another 100 lines of tests. Pretty fun little problem.
Steve Moyer
Might also consider states

class East: IDirection{
public IDirection SpinLeft(){
return new North();

}
public IDirection SpinRight(){
return new South();

}
}

A directional vector could fit on there as well

Tackling Business Complexity

This week at a client site, one of our stories came back from the dead because some condition wasn’t handled. As we were implementing the story, our understanding increased and along with understanding came new questions. After asking these new questions, it became clear that there was a lack of holistic understanding for the both the developers and the business. The developers wanted a rationalized set of conditions, the business wanted things to be displayed in different ways when certain conditions were met. Basically, we wanted the same thing, but could not meet on a common language.

The thing we could agree on was what parts were important, so I came up with the idea of producing a truth table to hash out the different combinations. It looked a lot like the image below.




After creating the table, it was a matter of going through each combination and recording what expected result should be displayed. This produced five potential outcomes that turned out to be relatively simple to handle.



Looks almost too easy right? I’ll assure you that the vernacular of the story did not cover the problem in such logical terms. The distillation of these guard statements (each condition returned) was a direct result of the truth table. Had we gone with a more classical approach, it would have likely resulted in a fair bit of cyclomatic complexity or the introduction of more classes to tackle this problem through polymorphism.

As it turned out, we wrote some tests, wired everything up and it worked just like the BA wanted, but could not logically define.