Thursday, August 27, 2009

Builder Pattern in Clojure

We've been working steadily on our toy traffic simulator and doing TDD along the way. Of course a major concept in a traffic simulator is a car, so we of course have a car struct + cars have some behavior patterns so we also have a behavior struct. They look like:

(defstruct behavior :accel-dist :decel-dist)
(defstruct car :name :position :length :speed :behavior)

So to construct a valid car you need to do something like:

(struct car :a 1 1 1 (struct behavior 10 5)))

Yikes, we constantly wanted cars for our tests and constructing a car like that was often more code than the real stuff we wanted to test. So, we made a bunch of convenience methods (object mother type stuff), like:

(defn slow-car [name position]
 (struct car name position 1 1 (struct behavior 10 5)))

(defn car-with-speed-position [speed position]
 (struct car :a position 1 speed (struct behavior 10 5)))

Suddenly we started creating lots of car-with-* methods. We got annoyed and accidentally started implementing the builder pattern.

(defn default-car []
 (struct car :a 1 1 1 (struct behavior 10 5)))

(defn car-with 
 ([key value]
  (assoc (default-car) key value))
 ([key1 value1 key2 value2]
  (assoc (car-with key1 value1) key2 value2)))

Ignore the total ugliness of the car-with function for a moment, this let us do things like:

(def a-car (car-with :speed 1 :position 4))

as opposed to:

(def a-car (car-with-speed-position 1 4))

Our new version, was not only easier to read, and didn't make us create new methods for each different thing we wanted to do, but hey, that looks really similar to the builder pattern. Now I'm sure there are better ways to implement car-with, but it works for now.

Wednesday, August 26, 2009

Null once again

InfoQ has a nice talk by Tony Hoare, Null References: The Billion Dollar Mistake. I've been in a few arguments in that past that languages would be much better without null, so it's nice to hear someone much smarter than myself, who also happens to have invented the null reference regret their existence. But he doesn't feel as bad as he thinks the C language designers should feel, because he says, they allowed the for the buffer overflow by abusing the get routine. And that allowed for viruses, which have cost industry much more than his billion dollar mistake. He's tough on the language designers (and himself): "Language designers should be responsible for the mistakes programmers make". Thanks Tony, for giving me someone to blame when I muck things up :)

Saturday, August 1, 2009

Returing Null... again

so... thinking more about returning null. I'm thinkin' returning null is allowing you to return a second type from a method. And a null pointer exception is equivalent to a class cast exception. AND a null check if (foo == null) is the same as an instance of check.

nulls are syntactic sugar for a type! I refuse to think of them as values for references any longer. They are types, returning them from functions is returning multiple types from a function (not in a polymorphic way, but in a type system abusing way) and null checks are instance checks.

Returning Null

I've always had a problem with returning null from a method. And I was reminded of this when reading a post at Misko Hevery's blog about how to think about OO

I think returning null is a problematic, it's often abused as a way to have two different return types from one method. A quick googling of "returning null" has the suggestion of returning a null object implementation of your return type. Returning a Null Object is appropriate in some cases, but not when you need to signal to your client two different things. Misko's code refactoring show's an example of this. He refactors some login code (I really like the steps he took btw) down to something like:

  Cookie login(Ldap ldap) {
    if ( ldap.auth(user, password) )
      return new Cookie(user);
    return null;
  }

When I read this code I see two things (structurally that is)

  1. If authentication succeeds then notify the client of the successful authentication with a new Cookie
  2. If authentication fails notify the client by returning null

What could a client of this method look like?

  public void authenticateUser(User user) {
     Cookie userCookie = user.login(ldap);
     if (userCookie == null) {
           //notify someone that auth failed
     } eles {
           //register them as logged in
     }
  }

We're doing the same work twice in each place, but with slightly different syntax, each place we need to check if login failed or not. What if instead we used IoC / "Tell Don't Ask" / "Hollywood Principle"

  Cookie login(Ldap ldap, AuthenticationRegistry authenticationRegistry) {
    if ( ldap.auth(user, password) )
      authenticationRegistry.authSucceeded(new Cookie(user));
    authenticationRegistry.authFailed(user);
  }

and the client

  public void authenticateUser(User user) {
     user.login(ldap,this);
  }

  public void authSucceeded(Cookie cookie) {
     //register them as logged in
  }

  public void authFailed(User user) {
     //register them as auth failed
  }

This new code is a little more complicated, but I think it is clearer, and more straight forward to implement. Now we have two entities that are communicating with each-other and we've defined the way in which they are communicating. Again I liked Misko's refactorings, I'd just take it one step further. It's all definitely arguable, but I think if you're ever in a situation where you want to be returning two types of data from a method using IoC is the way to go.

 
Web Statistics