Dependency Inversion Principle and iPhone

While working on the slides for our upcoming talk on TDD for iPhone I asked Eric Meyer why we need the Dependency Inversion Principle. He eagerly answered, “Testing!” which made me laugh because I wasn’t giving him a trivia quiz, and I love Eric’s enthusiasm.

He’s right, but the answer is circular. TDD is great because it gives us better designs that correspond to the DIP which enables TDD. Ha! I win, would you like to buy my consulting services? I have plenty of three letter acronyms where those came from.

Fortunately this isn’t the case, as the DIP existed well before TDD was popularized, but recently there was a bit of a dust-up over the SOLID principles. Many developers don’t understand why dependency inversion is important, so let’s demonstrate the usefulness in the Objective-C language on the iPhone.

The Dependency Inversion Principle reads as follows:

  1. High level modules should not depend upon low level modules. Both should depend upon abstractions.

  2. Abstractions should not depend upon details. Details should depend upon abstractions.

So your code should depend on interfaces not on concrete classes, but why? Let’s look at a useful example in the Objective-C built in classes.

1 [NSString stringWithFormat:@"Object is: %@", object];

Do you see the DIP at work? It’s subtle here, but look at the method < code>stringWithFormat, which takes a format string and then a list of parameters to fill in the format specifiers. The format specifier here is “%@” which takes any Objective-C object and calls descriptionWithLocale on it, or description otherwise.

The object that is passed in here could be anything because all the stringWithFormat method cares about is that the object provides at least one of the two methods above. It’s depending on the interface, and not the concrete class. Let’s imagine a world where this didn’t exist, and the NSString method could only be composed of other strings. Suddenly you’d have something like:

1 return [NSString stringWithFormat:@"Object is %s", [object toString]];

That’s not bad at all is it? Well what if there are different objects.

1 return [NSString stringWithFormat:@"Object is %s %s %s", [object1 toString],
2                                             [object2 toS],  
3                                             [object3 stringify]];

Are you starting to see the problem? Suddenly I can’t use this method without being cognizant of the specifics of the object I passed in. The minute one of these interfaces changes I have to change my code. I stole this method from some real code, so let’s look at it with some context.

Once upon a time I was writing a mock object for an iPhone application. Now iPhone doesn’t have a good mock object framework, at least that I’m aware of, so I was rolling my own mock. The mock logged calls to it which I then queried. To construct the string I used this method:

1 +(NSString *) createStringFrom: (id) cell at: (CGPoint) point 
2                             sizeOf: (CGRect) rect 
3 {   
4     return [NSString stringWithFormat:@"%@ %f %f %f %f", cell, 
5                                             point.x, 
6                                             point.y, 
7                                             rect.size.width, 
8                                             rect.size.height];
9 }

Don’t sweat the details right now, they’re not important. Instead look at how you can see the DIP succeeding and failing in the same code here. The first parameter to createStringFrom is a cell object, but it’s of type id, so it could really be anything.

That’s good because I wasn’t sure when I wrote this mock what type the cell would be and I’d generally prefer that my mock object not have to know the details. In fact the cell did change type several times which is why insulating yourself from change is so important.

There’s an assumption by many developers that you should only worry about the things you’ll be changing in the future, but the best gauge of future changes is present changes, and if you’re changing a module frequently during development as you get it right you’ve found a likely change point.

Even if you haven’t, you’ll make your life simpler in the present by insulating yourself from that change, speeding up your development cycles. I digress.

The rest of this method isn’t so lucky. You see CGPoint and CGRect are C structures, and I am left to write these as floats in the string (%f). If I was to change the parameter types frequently I would probably introduce some way to insulate myself from that change as well, possibly by wrapping them in objects.

Since those parameters have not changed I haven’t done that, although I’m thinking about it.

Our current apprentice Colin has given a first-hand account of refactoring to DIP here as well.

How do I do it?

skitched-20090403-102851.jpg

Eric and I are working on a program to run Conway’s Game of Life. On the iPhone screen you see Rounded Rect Buttons that change color based on whether a cell is alive or dead. The problem is that we don’t really want to drag and drop 300+ tiny buttons on the screen with interface builder.

Instead we want to create them programmatically, when the GameOfLifeViewController is loaded. Again I don’t want to overload you with extraneous details, so just take my word for it that there is a GameOfLifeViewController, and it needs to generate buttons. Here’s what my first pass at a test looked like in rough pseudocode:

 1 for (int row = 0; row < 15; row++) 
 2 {
 3     for (int column = 0; column < 15; column++)
 4     {
 5         button = GetButtonViewAt(row, column)
 6         STAssertEquals(expectedSize, button.size)
 7         STAssertEquals(expectedLocation, button.location)
 8         STAssertAction(expectedAction, button.action)
 9     }
10 }

There’s a lot wrong with this test. The most obvious is the hard coded 15. What happens when we want to change the number of rows and columns? Now we have to change code in multiple places.

Naturally we did in fact change this, so I would have paid for this decision quickly if I hadn’t already refactored it away.

The second is that there’s going to be more than one test for creation, each of which will have to perform the same 15x15 loop.

The annoyance of constantly changing this will reveal the root the problem, the GameOfLifeViewController should really only be in charge of GameOfLifeView and really doesn’t need to know the details of the creation of its subviews. It’s violating the Single Responsibility Principle.

We can fix that with a factory object, and will do so, but that will violate the Dependency Inversion Principle. So we’ve got one DIP violation, an SRP violation, and a potential second DIP violation, all demonstrated in 6 lines of test code.

Fortunately we’re going to introduce some interfaces to clean that up. The first is an interface to the board object. Why the board?

Well the board should know the number of rows and columns it has, and if we can inject a fake version of the board we can actually set those to be 1 and 1. That’s will make our test focus on what we are truly concerned about.

The second thing we’re going to do is introduce the Abstract Factory pattern to create our button views. It’s a bit of a heavyweight solution but its going to pay off by cleaning up our client code dramatically.

We’ll have a View Controller concerned with controlling the view, and a creation factory concerned with creation, as well as a board that keeps track of rows. Let’s take a look at the test now, again in rough pseudocode.

 1 -(void) setUp
 2 {
 3     controller = [[GameOfLifeViewController alloc] init];
 4     controller.board = [[MockBoard alloc] init];
 5     controller.buttonControllerFactory = [[MockButtonFactory alloc] init];
 6 }
 7 
 8 -(void) testCreationOfButtons
 9 {
10     [controller viewDidLoad];
11     bool called = [controller.board calledWith: params that: I want: true];
12 
13     STAssertTrue(called);
14 }

So what’s going on here? In the setup we load up the board with a fake board, one that returns 1 for its rows and columns, and we load up its buttonControllerFactory with a fake buttonController Factory.

In our test we call the viewDidLoad method, which is called on controllers after their view is loaded. Duh. That’s the method where we use the buttonControllerFactory.

Then we call a method on the mock factory calledWith: that takes the parameters I expected the creation factory to receive. Finally we check that it was called with the assertion. So far I’ve only been showing test code, because I wanted to demonstrate how much cleaner our tests have become.

Now there’s no loop, no hard coded constants, and no testing the internals of the creation factory in the view controller. That isn’t to say we don’t test the creation, we just do that in a different test case, the one that corresponds to the ConcreteButtonFactory class.

As a rule if our test code is cleaner, our implementation code is cleaner, and that’s the case here as well.

Let’s now look at the real class, and how to enable Dependency Inversion on it. We have to start with Objective-C protocols. Protocols are very similar to Java interfaces, and just as useful, but are strangely underrepresented in XCode.

As best I can tell just create an NSObject subclass and remove the .m file and any imports from the .h. Here’s the protocol from the unfortunately named ButtonControllerFactoryProtocol.h:

1 #import "ButtonController.h"
2 
3 @protocol ButtonControllerFactoryProtocol
4 
5 -(ButtonController*) createButtonControllerForCell: (id) cell 
6                                     at: (CGPoint) point 
7                                  sizeOf: (CGRect) rect;
8 
9 @end

As you can see the interface only defines one message, createButton ControllerForCell. It returns the ButtonController object, although it could return an object conforming to a protocol. Indeed one could argue it should, as that would streamline my mock object. Hmmm…I see a refactoring in my future.

Now let’s look at the class definition for the ConcreteButtonControllerFactory, which is the object that is actually used when the real app is running.

 1 #import <uikit />
 2 #import "ButtonController.h"
 3 #import "ButtonControllerFactoryProtocol.h"
 4 
 5 @interface ConcreteButtonControllerFactory : 
 6                                 NSObject<buttoncontrollerfactoryprotocol> {
 7 
 8 }
 9 
10 @end

Not much here is there. The important part to look at is NSObject. ConcreteButtonControllerFactory inherits from NSObject, as all Cocoa objects do, and conforms to the ButtonControllerFactoryProtocol.

Like a Java interface this is a contract to later implement createButtonControllerForCell in my implementation file and that’s exactly what I’ve done.

 1 #import "ConcreteButtonControllerFactory.h"
 2 
 3 @implementation ConcreteButtonControllerFactory
 4 
 5 -(ButtonController*) createButtonControllerForCell: (id) cell
 6                                      at: (CGPoint) point 
 7                                   sizeOf: (CGRect) rect;
 8 {
 9     ButtonController *controller = 
10                 [[ButtonController alloc] initWithCell:cell];
11 
12     UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
13     [button setFrame:rect]; 
14     [button setCenter:point];
15     [button setImage:[UIImage imageNamed:@"dead_cell.png"] 
16                               forState:UIControlStateNormal];
17 
18     [button addTarget:controller 
19               action:@selector(bringToLife:) 
20       forControlEvents:UIControlEventTouchUpInside];
21 
22     controller.view = button;
23     return controller;
24 }
25 
26 @end

This isn’t an article on UIKit so I’m not going to get into the details of creating the button. You can see again that I’ve ignored the DIP for creating the UIButton and the ButtonController.

Since this is a factory I’m okay with this violation. I could have created abstract factories for the UIButton and ButtonController and passed them in here but I don’t believe I’d gain any benefit from that implementation.

That’s verified by my testing, as writing tests for the creation of these objects was hard before I introduced this factory but isn’t any longer.

If it becomes difficult then I’ll consider making the change to two factories. Now we need to inject the concrete dependency. In a Java project you could do this in a main method or with a DI framework like Spring. We’re going to be using my favorite DI framework of all time: Interface Builder!

It’s a common misconception that IB is just a GUI builder. What’s great about it is that it doesn’t just generate a bunch of code, but instead “freeze dries” real objects to be instantiated when the program loads the NIB file.

Furthermore while the most common Outlets are UI elements there’s no reason other objects can’t be used. Let’s take a look at my NIB document window for the GameOfLifeViewController:

GameOfLifeViewController.xib-3

As you can see I’ve got objects for the Game, ConcreteButtonController Factory, and the Board. That’s because all three of the objects are injected at runtime, while the code depends on protocols. To add your own objects to a NIB file simply by selecting it from the Library:

Activity Monitor
Uploaded with plasq’s Skitch!

It’s inspector window will have a class drop down, so set this object’s object to your class. Finally you need to connect the outlets to actual outlets in your code. Let’s look at the Outlets tab in IB for my controller (the File’s Owner):

Game Of Life View Controller Identity
Uploaded with plasq’s Skitch!

Notice how the controller still thinks of them all as NSObject? So if I change the objects it doesn’t care, as long as I conform to the interface? Finally let’s take a peek at the controller interface file:

 1 #import "BoardProtocol.h"
 2 #import "ButtonControllerFactoryProtocol.h"
 3 #import "GameProtocol.h"
 4 
 5 @interface GameOfLifeViewController : UIViewController {
 6     IBOutlet NSObject<boardprotocol> *board;
 7     IBOutlet NSObject<buttoncontrollerfactoryprotocol>  *buttonFactory;
 8     IBOutlet NSObject<gameprotocol> *game;
 9 }
10 
11 @property(nonatomic, retain) NSObject<boardprotocol> *board;
12 @property(nonatomic, retain) NSObject<buttoncontrollerfactoryprotocol> *buttonFactory;
13 @property(nonatomic, retain) NSObject<gameprotocol> *game;

See any dependencies on the actual objects? Nope—just protocols. There are properties for the objects so that I can inject the dependencies through the tests, all of which pass in fake versions as various times depending on how it suits the test. It may be unhealthy—but I find this incredibly cool.

Summary

What I love about Interface Builder is setting this up is extremely simple. Writing tests for the controller that is based on these dependencies is also extremely simple, far simpler than just depending on the concrete objects.

It’s funny how developers often complain about the time wasted writing tests or “over-engineering” in this way, but once I broke these dependencies I got things done a lot faster. I’m writing working code without loading the actual simulator.

I write my tests first, making progress, and when I’m done for the session I run the app once or twice just to verify I haven’t done anything like forgotten to inject the dependency.

Compare that to running the simulator constantly, each time hoping your code is functional. Who’s wasting their time now?

Eric Smith, Software Craftsman

Eric Smith has been programming since he started a web design company in college.