![]() |
Articles Feed |
Categories
Archives
- March 2010 (1)
- February 2010 (2)
- January 2010 (1)
- December 2009 (1)
- October 2009 (4)
- September 2009 (2)
- August 2009 (2)
- July 2009 (5)
- June 2009 (2)
- May 2009 (2)
- April 2009 (8)
- March 2009 (7)
- January 2009 (2)
- December 2008 (3)
- November 2008 (5)
- October 2008 (4)
- September 2008 (6)
- August 2008 (4)
- July 2008 (5)
- June 2008 (5)
- May 2008 (4)
- April 2008 (2)
- February 2008 (4)
- January 2008 (2)
- December 2007 (2)
- November 2007 (2)
- October 2007 (2)
- September 2007 (1)
- August 2007 (3)
- July 2007 (1)
- June 2007 (4)
- May 2007 (7)
- April 2007 (2)
- February 2007 (3)
- January 2007 (3)
- November 2006 (3)
- October 2006 (3)
- September 2006 (17)
- November 2004 (1)
Stubbing :new Considered Harmful
by: eric | February 8th, 2010 | 1 comments »
Hi my name is Eric, and I have made a mess.
There I said it. I’m not proud of it, but I believe a couple very loosely related things:
- You only learn from your mistakes
- Everybody makes mistakes, a craftsman cleans them up.
It is in the process of cleaning up the mess that I’ve been trying to evaluate the messy code in the first place. How is the code messy? Was it Test-Driven? It was - or at least it attempted to be (we’ll get back to that). Was I lazy? Certainly not. Am I stupid? Crap I hope not. So how did we end up in this mess?
What’s the mess nimrod?
Recently Justin, our latest apprentice, wrote about attending a code review here. The feature he is referring to is part of one of our best client’s systems, where we integrated with several webservices, making them look seamless in our application. This was an extremely difficult problem, and our code bent in a dozen painful ways for a solution, and has since become rigid. Changes have stopped being done in the nice Test-Code-Refactor mode, and instead are being done by trying a change, trying the product, then backing out the change and making the test pass. While we identified several ways to improve the code, such as better naming and adding a facade between some of our interfaces, one stated goal was to “make the tests readable.” See the problem isn’t that it’s not tested - it’s that you can’t follow the tests at all. Let’s look at an example, modified to protect the guilty:
- it "should call a webservice when its complete" do
- @caller.should_receive(:call_webservice)
- typedObj = mock("Obj", :no_follow_ups? => false, :null_object => true)
- ProprietaryObject.stub!(:create_typed_obj).and_return(typedObj)
- @page.stub!(:widget_id).and_return(@widget.id)
- @page.stub!(:previous_page_id).and_return(nil)
- @product.page_cache = [@page]
- @widget.follow_ups({}, {:application_id => "123", :group => "group"})
- end
-
This probably isn’t the worst example - if you look closely you can see that we’re testing that call_webservice needs to get called when ‘its complete.’ But what complete? I don’t see a stubbed object that returns complete. Also I have no idea what @page, @widget, @product or :createtypedobj are doing here. When I want to write the next test I have to guess at intent, and start playing with variables. What this is trying to test is that a webservice caller object receives call_webservice when the widget (an object on the screen) is called with certain variables. I’d tell you what those variables are, but I truly don’t know.
It doesn’t get better. Let’s look at where some of those variables are coming from. These are excerpts from a setup method that is too long.*
- Context.stub!(:find_by_widget_and_application_form).and_return(@context)
- Page.stub!(:new).and_return(@page)
- ...
- @caller = mock('caller', :call_webservice => nil)
- WebserviceCaller.stub!(:new).and_return(@caller)
- ...
- @page_factory = mock_model(PageFactory, :acquire => @page)
- PageFactory.stub!(:new).and_return(@page_factory)
-
So by my count we’ve stubbed new three times, two finders, and an acquire all of which inject yet another dependency into the code. Thus the premise of the article stubbing new considered harmful.
Is it really harmful?
Dependencies in static languages are generally more onerous than what we’ve got here, sometimes extremely painful although usually it can be accomplished with simple setters and constructors. In Ruby this isn’t the case - you can just stub new and create the object the way the user intended, thereby continuing to test. This can be a VERY BAD THING because it’s a moment where you need to pause. Do you need this dependency? Should you be wrapping dependencies? Do you need a facade or wrapper object for a couple dependencies? The difficulty of DI in other languages enforces that pause, but Ruby does not. It lets you stub anything, only to one day wonder why you have such a mess on your hands.
It’s important to remember that Dependency Inversion existed before Unit Testing, and isn’t just a Unit Testing technique. Indeed we often sell TDD as a way to make you have better designs, and yet here it failed me because I can so simply call new and continue testing. This is a mistake. To paraphrase Jurassic Park, just because you can easily stub new doesn’t mean you should. Would you create a constructor that took five objects? Then why would you stub :new (or finders, or factory methods) five times. Would you pass in an object to the constructor that’s only used in one method? No - that’s not cohesive. By stubbing :new you can slowly, and easily, introduce dependency after dependency creating an indecipherable mess despite writing tests. Worse you can do this easily, without suffering the traditional pain of tightly coupled code. It’s only later that you’ll feel the awful, horrible, indescribable pain. Trust me it’s bad.
Am I really advocating stopping stubbing :new? No not really. It makes perfect since to just call :new when you can, and in many cases factories are a way to get around the limitations of a static language. What I am saying is that each time you do stub!(:new) THINK! You have a dependency to manage, so manage it. It’s your job you know.
*This is also a smell. Allow me to quote “The Art of Unit Testing”, an excellent book on Unit Testing by Roy Osherove
Don’t use [SetUp] and [TearDown] to initialize or destroy objects that aren’t shared throughout the test class in all the tests, because it makes the tests less understandable. Someone reading your code won’t know which tests use the logic inside the setup method and which don’t.
TDD and iPhone - NSTimer
by: eric | May 11th, 2009 | 3 comments »
TDD on the iPhone is a challenging experience, especially when you’ve been spoiled by Ruby like I have been, but it can be done. I have a tutorial in the works for getting started, but in the meantime I’ll be writing bits and pieces about my experience. The first was here and this is the second. Test cases are written using the Google Toolbox for Mac. This particular example is about the NSTimer.
It keeps going and going
The app to your right is a simple app for experimentation purposes that runs Conway’s Game of Life. It has two buttons: advance and start. Advance moves one generation ahead each time you press it, whereas Start keeps advancing generations until you touch Stop. To implement that we use an NSTimer object which is programmed to call advance on the game object. The design is simple, shown here:
The GameRunner creates an NSTimer, the NSTimer sends the message to Game. Great but how do we test it? The less I know about something the more I tend to test it, which means I tend to write smaller and smaller tests. Let’s look at my first few tests of the GameRunner object:
- -(void) testSetsAndGetsTimeInterval {
- runner.interval = 0.30;
- STAssertEquals(0.30, runner.interval, nil);
- }
- -(void) testCreatesNSTimerObject {
- [runner start];
- STAssertNotNil(runner.timer, @"The timer was not created");
- STAssertTrue([runner.timer isValid], nil);
- }
- -(void) testNSTimerFields {
- runner.interval = (NSTimeInterval) 0.26;
- [runner start];
- STAssertEquals([runner.timer timeInterval], 0.26, nil);
- }
We’ve got some basic tests of creation. At this point I was stumped. I couldn’t check the other parameters of the timer, because they weren’t public variables, so at this point the code that actually created the timer looked like this:
- -(void) start {
- timer = [[NSTimer timerWithTimeInterval: interval
- target:nil
- selector:nil
- userInfo:nil
- repeats:true] retain];
- }
That doesn’t really help me does it? I have a timer with an interval, but it won’t call anything when it’s triggered. This is about the time I got to pair with Jake Scruggs during the Craftsman Swap, which he’s written about here. It went badly, somewhat embarrassingly for me since I’m supposed to be the expert, however we learn from failure. Let’s look at some of the steps Jake and I took that didn’t quite get us there.
The first pass on the test was simple. We needed a mock game, and it needed to have its advanceGeneration method called (Ed. note: I realize they aren’t called methods in Obj-C, to which I say: bite me.) each turn. Let’s try the brute force approach:
- -(void) testTimerCallsGameAdvance {
- MockGame *mockGame = [[MockGame alloc] init];
- runner.game = mockGame;
- [runner start];
- sleep(.30);
- STAssertTrue([mockGame advanceGenerationCalled], nil);
- }
I’m writing the original tests from memory, so I make the occasional error here, but it doesn’t matter since we got this wrong. This test here seemed the most logical. We ran the test and it failed, yea! Then we updated the code:
- -(void) start {
- timer = [[NSTimer timerWithTimeInterval: interval
- target:game
- selector:@selector(advanceGeneration)
- userInfo:nil
- repeats:true] retain];
- }
Experienced Cocoa developer’s have already discovered our error, please don’t ruin it for the rest of the readers. So after changing the code we run the test and…we fail. So from here Jake and I figured it out. Sleep won’t work because it stops the entire application, including the run loop that calls our timer, so we’ll just have to get the info out of the timer another way. We’re interested in testing that we’ve setup the timer correctly, and can trust that the timer just works. After a loooong time browsing documentation we figured it out. We could call this:
- -(void) testTimerCallsGameAdvance {
- MockGame *mockGame = [[MockGame alloc] init];
- runner.game = mockGame;
- [runner start];
- [runner.timer fire];
- STAssertTrue([mockGame advanceGenerationCalled], nil);
- }
This will fire the timer and validate that it is setup correctly. So we did this, our test passed, we ran the app and it….failed. We knew the timer was executing because our test was passing, but when we ran the real app it just didn’t do it. Stumped and frustrated we stopped for the day. Then time passed…..
Yesterday I had a candidate in for an apprenticeship position, and we attempted to solve the same problem. We re-evaluated the test and decided calling fire directly was cheating. We looked into a half-dozen other ways to test this and learned about the NSRunLoop. Too much coding in Windows had rotted my brain, the run loop in Objective-C is not the same as the one in Windows. Specifically the current run loop is accessible as an object. We wrote a new test:
- -(void) testTimerCallsGameAdvance {
- MockGame *mockGame = [[MockGame alloc] init];
- runner.game = mockGame;
- [runner start];
- [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow: 0.30]];
- STAssertTrue([mockGame advanceGenerationCalled], nil);
- }
It’s not perfect - the 0.30 relies on the hard coded default interval of 0.25, and that is too long, but it failed! In the process of learning about NSRunLoop we also realized I used the wrong method. The working code is this:
- -(void) start {
- timer = [[NSTimer scheduledTimerWithTimeInterval: interval
- target:game
- selector:@selector(advanceGeneration)
- userInfo:nil
- repeats:true] retain];
- }
See the word “scheduled” in front of Timer? That actually adds the timer to the default run loop. Now we ran our spec, ran our actual code, and it works! The moral of the story? Well if you’re persistent enough you can get your code under test, and if your test is correct then your code will work.
Apprentice Architecture
by: paul | May 6th, 2009 | 1 comments »
Good design sense is a skill that comes only from many years of coding experience. Sometimes it can be very difficult to make those design decisions when you are an apprentice or otherwise don’t have much experience.
When I was an apprentice, oftentimes I would get a problem from Micah (my mentor) and would solve it the simplest way possible. Then I would walk up to him with my head held high and say I was done. He would almost always point out some way the architecture was not easy to extend or that he didn’t even know java had goto statements.
As an apprentice, the most important thing is to get everything to work correctly; only then should you concentrate on making sure it is good code. Writing great code with great designs is not a skill that will appear overnight. It took years of honing my design sense to be able to see designs right away, and I have only scratched the surface of my mentor’s abilities.
When I was an apprentice, I lacked the experience and skill to make difficult architectural choices. Let alone the ability to get it right on the first pass. I instead stayed close to the code and continued to move forward writing working code. This led to many design mistakes, and I had to throw out plenty of code or refactor to a better design. This is an exercise in taking a step backwards to move forwards. I learned the value of working code as well as the value of refactoring to better designs. Content before form is an important lesson I learned as an apprentice. It laid the foundation for the later lesson that good form is essential for high quality code.
As an apprentice, ask your mentor when you have completed a task if they think there is a better design. Then refactor that design and compare the two. Once again, repetition and practice will pay off as these exercises help you develop a matured design sense. You will learn from having to solve the problem without being told the design first, and then later having to re-implement a better design. This practice will internalize your design sense and eventually you will start to see the better designs the first time through.
The big problem with trying to get the design right the first time is it leads to coders block. Staring at the blank screen, trying to figure out the best way to do something. Even if you are writing the wrong code, it is important to be moving in some direction. When I see the code, oftentimes the design I get will form around the reading of the code rather than trying to think in the abstract about the whole problem at once. For me the problem and the design for the solution would be too big of a mental model to fit in my head all at once. Don’t worry, as you get more experience, your mental context will expand too. Your ability to sustain concentration will build as well as you practice and become more experienced. With experience, you won’t have to think about as many of the small problems anymore.
Architecture is like most craftsman practices in the sense that there are breakthroughs but there is always more to learn. I read a blog recently where Uncle Bob Martin talks about thinking through the architecture of a problem for hours or days before he will start. When I was an apprentice, I would not have had enough experience or a large enough mental model to think about the architectural impact of a solution. Even as a journeyman, I still only have a big enough mental model to think about an aspect of a problem, write the code, then reevaluate where the solution stands in the context of the system.
For an apprentice, bad design should not be seen as the end of the world. As long as you are learning and progressing in the techniques of creating working code, you are moving in the right direction. Design sense is a long-term skill and you will have to be patient with it. Remember that practice makes perfect.
Bug free or Free Bugs
by: paul | April 26th, 2009 | 1 comments »
I will not charge a client for a bug fix. Not a penny. If I make a mistake, it is my professional obligation to fix it.
If something doesn’t work with my car, there could be catastrophic consequences, I would be mad unless the company has a solution and offers to fix it for free. As a car owner, I expect nothing less. If a doctor makes a mistake, the patient has the right to sue the doctor for malpractice. Why is it if I make a mistake, I get off scot free? Or worse, I get paid to fix my own mistakes.
I know sometimes the devil is in the details. What is a bug? This is not an easy question to answer, but if there are customer written acceptance tests for the system, the items that fall through are fewer. These are general rules I go by when deciding if something is a bug or not.
One: I made a mistake. These are usually easy to notice, due to the redness in my face when the bug is reported. It is clear to me, I made a mistake, and it is clear I need to fix the bug. It should not cost the customer any money and the process should be transparent.
Two: There is a mistake that both development and the customer team should have caught. A scenario the customer should have specified and during development I should have noticed and brought to their attention. The fault goes on both parties and can be fixed at some version of half price (i.e. every other or a half price story).
Three: The application doesn’t behave correctly due to a missed specification. a scenario that the customer missed or a piece of the business logic that wasn’t fully correct. Almost everyone makes some mistakes. This is not a bug to me, but a feature enhancement. It can be written up as a story and completed.
I think it is important to build faith with the customer that there is a team of developers that are accountable. When you create the culture of accountability, it spreads. The customer team is willing to be accountable when they make a mistake. When no one is afraid to make or admit to a mistake, the projects quality is positively affected. Finally, by taking financial ownership of a bug, I build a trust with my stakeholders of the project.
Dependency Inversion Principle and iPhone
by: eric | April 16th, 2009 | 0 comments »
Vertical Dependency
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 (DIP) reads as follows:
A. High level modules should not depend upon low level modules. Both should depend upon abstractions.
B. 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.
- [NSString stringWithFormat:@"Object is: %@", object];
Do you see the DIP at work? It’s subtle here, but look at the method 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:
- return [NSString stringWithFormat:@"Object is %s", [object toString]];
That’s not bad at all is it? Well what if there are different objects.
- return [NSString stringWithFormat:@"Object is %s %s %s", [object1 toString],
- [object2 toS],
- [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:
- +(NSString *) createStringFrom: (id) cell at: (CGPoint) point
- sizeOf: (CGRect) rect
- {
- return [NSString stringWithFormat:@"%@ %f %f %f %f", cell,
- point.x,
- point.y,
- rect.size.width,
- rect.size.height];
- }
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?
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 programatically, 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:
- for (int row = 0; row < 15; row++)
- {
- for (int column = 0; column < 15; column++)
- {
- button = GetButtonViewAt(row, column)
- STAssertEquals(expectedSize, button.size)
- STAssertEquals(expectedLocation, button.location)
- STAssertAction(expectedAction, button.action)
- }
- }
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.
- -(void) setUp
- {
- controller = [[GameOfLifeViewController alloc] init];
- controller.board = [[MockBoard alloc] init];
- controller.buttonControllerFactory = [[MockButtonFactory alloc] init];
- }
- -(void) testCreationOfButtons
- {
- [controller viewDidLoad];
- bool called = [controller.board calledWith: params that: I want: true];
- STAssertTrue(called);
- }
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 just 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 implemenation 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:
- #import "ButtonController.h"
- @protocol ButtonControllerFactoryProtocol
- -(ButtonController*) createButtonControllerForCell: (id) cell
- at: (CGPoint) point
- sizeOf: (CGRect) rect;
- @end
As you can see the interface only defines one message, createButtonControllerForCell. 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.
- #import <uikit />
- #import "ButtonController.h"
- #import "ButtonControllerFactoryProtocol.h"
- @interface ConcreteButtonControllerFactory :
- NSObject<buttoncontrollerfactoryprotocol> {
- }
- @end
Not much here is there. The important part to look at is NSObject
- #import "ConcreteButtonControllerFactory.h"
- @implementation ConcreteButtonControllerFactory
- -(ButtonController*) createButtonControllerForCell: (id) cell
- at: (CGPoint) point
- sizeOf: (CGRect) rect;
- {
- ButtonController *controller =
- [[ButtonController alloc] initWithCell:cell];
- UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
- [button setFrame:rect];
- [button setCenter:point];
- [button setImage:[UIImage imageNamed:@"dead_cell.png"]
- forState:UIControlStateNormal];
- [button addTarget:controller
- action:@selector(bringToLife:)
- forControlEvents:UIControlEventTouchUpInside];
- controller.view = button;
- return controller;
- }
- @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:
As you can see I’ve got objects for the Game, ConcreteButtonControllerFactory, 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:
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):
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:
- #import "BoardProtocol.h"
- #import "ButtonControllerFactoryProtocol.h"
- #import "GameProtocol.h"
- @interface GameOfLifeViewController : UIViewController {
- IBOutlet NSObject<boardprotocol> *board;
- IBOutlet NSObject<buttoncontrollerfactoryprotocol> *buttonFactory;
- IBOutlet NSObject<gameprotocol> *game;
- }
- @property(nonatomic, retain) NSObject<boardprotocol> *board;
- @property(nonatomic, retain) NSObject<buttoncontrollerfactoryprotocol> *buttonFactory;
- @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?
FootNotes:
* Uh yeah we gave that talk already. These take a while!
** I’m 99% positive there’s a better way, and that I haven’t found it. Tell me if there is!
*** To be fair it’s the only one I’ve actually used.
Copyrights Conundrum
by: micah | March 12th, 2009 | 5 comments »
Here’s the situation. You’ve spent days working on an open source project. Your sweat, blood, and tears have been poured into thousands of lines of code spread through countless file in a sprawling tree of directories. The final step is to release your masterpiece into the wild. So you choose your open source license and then it hits you; you realize that need to add a copyright header to EACH and EVERY source code files. How tedious! You google for a tool that will automatically add the headers for you, and you find nothing satisfactory. In the end, you write your own script to add the headers for you.
I’ve been in this exact situation and written such a script too many times. My most recent experience and script implementation will be the last. I’ve dubbed this last imeplementation MM Copyrights and you’re welcome to use it.
MM Copyrights is a simple Ruby gem that will search a directory for source code files, inserting or updating a header comment in each file.
Installing
It’s just a matter of installing the gem hosted on Github.
- gem sources -a http://gems.github.com
- sudo gem install slagyr-mmcopyrights
Usage
Let’s say you want to add the following copyright header to all .rb files in the lib directory…
- require 'mmcopyrights'
- MM::Copyrights.process("lib", "rb", "#-", "©2009 Micah Martin\nAll rights reserved")
And all the ruby files will look like this:
- #- ©2009 Micah Martin
- #- All rights reserved
- ... ruby code ...
Typically I keep the copyright text in a separate file and write the following Rake task…
- task :copyrights do
- require 'mmcopyrights'
- MM::Copyrights.process('lib', "rb", "#-", IO.read('copyrights.txt'))
- end
or the following ant task if need be…
- <target name="copyrights">
- <exec command="ruby">
- <arg value="-rrubygems" />
- <arg value="-e" />
- <arg value="require 'mmcopyrights'; MM::Copyrights.process('src', 'java', '//-', IO.read('copyright.txt'))" />
- </exec>
- </target>
Details
If you haven’t guessed, MM::Copyrights::process takes 4 parameters.
- The path of the directory containing source code.
- The extension of source file to be processed.
- The comment prefix. Note that there’s an extra -. This is because we want the copyright comments to be unique from all other comments. The tool will search for this unique prefix to find existing copyright headers.
- The copyright text, without the comment prefix.
That’s about it. Feel free to run MM::Copyrights::process multiple times on the same code base. It’s harmless. And when the new year rolls around, just change the copyright text and rerun the tool. It will update existing headers.
When is a Mock not a Mock
by: eric | January 10th, 2009 | 0 comments »
A couple of weeks ago I had to add a feature to some code that was written almost two years ago. It was a pretty simple web service client that constructed some XML, using Ruby’s REXML library, and made the web service call via another library. A quick inventory shows two dependencies, the web service call and REXML, so that’s what I expected to see when I came across the tests. But what did I see? Paraphrasing:
- @client_under_test = Client.new
- @client_under_test.stub!(:send_message)
- @client_under_test.stub!(:parse_response)
Of course the send_message call contained the construction of the XML so that there was no test that the XML being constructed was correct. Heck that was all that was being done in the class, and a closer inspection of the tests revealed that all they were doing was testing the error handling by changing the return value of parse_response. This is a classic sign that the developer at the time couldn’t figure out how to stub out the actual dependency, and so they did the next best thing, they stubbed out the caller.
I knew this was wrong, but I had an iteration meeting the next day and still had to update the .NET web service that this code was calling. So I started to just go ahead and make the untested change, but then my Clean Code wristband started burning until I couldn’t take it any more. I had to get the REXML library under test. So what to do? Well the REXML construction looked like this:
- doc = REXML::Document.new(create_schema)
- doc.elements["name1"].text = "thing 1"
- doc.elements["name2"].text = "thing 2"
- ...
Okay I know how to do this normally. The first test was simple:
- REXML::Document.should_receive(:new).with(schema)
It passed! What was so hard about testing this anyway? Okay let’s test that the elements are set:
- ....
- elements = mock(REXML::Document, :[] => mock_element)
- doc = mock(REXML::Document, :elements => elements)
- REXML::Document.stub!(:new).with(schema).and_return(doc)
- ...
Oh that sucks! Since the API doesn’t run entirely through the doc object I have to stub elements, then stub each individual element, then should_receive on text, and if I want to be perfect I can stub out the array accessor too. I have to should_receive for each element name, the tests will be hard to follow and fragile. Now I get why the original developer punted on this. There’s got to be a better way. I can start expecting actual XML, but from past experience I know that leads to very hard to read tests that give errors that aren’t easy to diagnose. What I really care about is that the elements in this hash-like structure have their text element set to the right data. After trying out several approaches I had a moment of inspiration, I want a struct! Must be my inner C programmer. If elements was a hash of structs, I could just check their text values are set. This way I’m testing that I’m using the REXML library right rather than testing the library itself. If only Ruby had a struct concept…..
I suppose you’ve already figured out that it does, haven’t you?
- MockElement = Struct.new("MockElement", :text)
What that does is setup a class named MockElement, with the accessor text. When is a Mock not a Mock? When it’s really a Fake. Instead of stubbing out elements to return yet another mock, elements will return a hash of the element names I know I’m using that point to these fake elements. Then after making the call in the client, I’ll just check that the text is set properly. This is best demonstrated with an example:
- before(:each) do
- @elements = initial_elements_hash
- @doc = mock(REXML::Document, :elements => @elements)
- REXML::Document.stub!(:new).with(schema).and_return(@doc)
- end
- def initial_elements_hash
- return {"element1" => MockElement.new,
- "element2" => MockElement.new}
- end
- it "should set the data in the xml doc" do
- @client.send_message
- @doc.elements["element1"].text.should == "Eric"
- @doc.elements["element2"].text.should == "Smith"
- end
Aha! Now I’ve tested that the XML was properly constructed without relying on looking at the actual XML text itself and without stubbing out the class itself. The code is cleaner, the tests are easier to understand, and I can implement my new feature. More importantly, my wristband stopped burning.
Embedded Ruby Talks Morse
by: doug | January 8th, 2009 | 6 comments »
I've been working with Ruby on embedded systems for a couple of weeks now. The final pieces have fallen into place and I'd like to share them with you. From the beginning of the project, my goal have been to turn some LEDs on and off from a web page.
Getting down to the metal
Any embedded software application has to eventually control some interesting hardware. My ARM board had two LEDs wired up, so I thought I'd try to control them. The control for the ports that control those LEDs are in memory mapped registers. Ruby really never let's us see the memory that we are working with, and even if it did, we are working in a virtual memory environment, so we wouldn't be able to access the specific memory address where the register is located. So it was time to learn how to write Ruby extensions.
I was surprised how easy this ended up being. Ruby has a great little module 'mkmf' that makes Makefiles for you. The API for defining ruby modules was also pretty straight forward and explained well in Pickaxe. I put the module I wrote up on git hub, so take a look there if you are interested. The extension allows you to just read from or write to any physical address on the device. To set a bit in a register, you might do something like this.
- include MemoryMappedIO
- from_register = read(0x560000010, "w")
- write(0x560000010, "w", from_register | 0x00000001)
Ahh. . 0x, hex numbers, addresses. It's nice to be back.
To get the module into my Ruby environment, I created an 'mmio' directory in the 'ext' directory of the Ruby source and dropped in the source files. I didn't have to change any makefiles, I just created an extconf.rb and the ruby build system took care of the rest. It would certainly be possible to build the module separate from the rest of the Ruby source, but since I already had the source tree configure to cross-compile, the path of least resistance was to just include this extension in the source tree.
I posted my extension to the ruby-core mailing list to see if there was any wider interested in it. It turns out there is a memory mapper extension already written. I took a quick look and it isn't exactly the same thing that I did. My interface is much more basic (and simple), but I think the mmap extension could be made to do the same thing I am doing.
The Promised Land
With a way to control the hardware from Ruby, I had finally arrived where I had wanted to be. The entire thesis behind this little experiment was that Ruby could make embedded application development fast and fun. I found both to be true. This entire application came together in just a couple of hours. I was able to make use of a ruby gem that did a bunch of the work for me. I called the application weblink. You are free to interpret the name however you would like (We Blink, Web Blink, Web link). The source is on git hub.
When test-driving an embedded system, you'll save yourself a bundle of time by doing as much of the development as you can on your host computer. The download, restart, test cycle can really add up when you are working in quick TDD cycles. On my particular system, the files system is still being hosted remotely, and the language is interpreted (no compile) so this overhead is not that bad. Still I wanted my application to run on my development machine, and I didn't think it wise to overwrite some random address in my Mac's memory, so I needed an abstraction.
When developing these kinds of environments in a C++ system, I would traditionally build a pure-virtual interface and implement it twice, once for the target hardware and once for the simulated, or development environment. In C you can do a similar thing with the linker. You write two functions, one for each platform and just link in the correct one when building for that platform. With Ruby's ducktyping, there is no need for a defined interface, but the concept is very similar.
I wrote two Led classes both with 'on', 'off', and 'on?' methods. The MockLed class just saves the on/off state in a YAML file. The real Led class uses the mmio extension to read and write a bit in a memory mapped register. I did not want the real Led class to have the platform specific knowledge about which LEDs were in which register, so I used the Factory Pattern to create the Led objects. The factory method is called 'find.' The MockLed file implements this same method that returns MockLed objects in the development environment.
The tricky part of this is switching between the two Led classes. For this, I chose to use Sinatra's environment configuration scheme. The production environment is used when running the app on the target, and the development environment runs on my Mac.
- configure :production do
- require 'leds_S3C2440A'
- end
- configure :development do
- require 'mock_led'
- end
Dit, Dash
To celebrate the 170th anniversary of the first demonstration of the telegraph, I decided to turn the application into a visual telegraph, beeping out little messages. The ideas is that you enter a message in the web page, and the LED blinks out your morse code. Here is where I saw the great power of not only Ruby, but also the community who uses it. I discovered right away that there is a Morse Code Gem already written. You give it a string and It gives you back a series of dits, dashes, and spaces. Thanks Ben!
Eric Meyer sat down with me and we ping-ponged out the morse blinker in short order. I love how simple this class ended up. It just proves again to me what great code you can write in Ruby.
See it for yourself
Okay, so enough talking, let me show it to you. Enjoy.
A Screenshot of the app:
What's Next
So I know that the response that I will get from embedded developers is "Great, but it's slow and big, it can't be used in a real system." I'm going to do some profiling and optimization on this system to get some hard performance data. Initial results (just looking at 'top') shows that the ruby process with Sinatra, Webrick, the morse gem, and my code loaded up is taking up about 12% of the system memory. That mean about 6 or 7 MB. What nice is that you only pay for what you use. If you don't require it, it won't load into memory.
As far as clock cycles go, the ruby processes peaks out at about 20% of the 400 MHz processor when serving HTTP requests. While blinking the LEDs, only a fraction of a percent of the processor's cycles are being consumed. I'm not happy with the performance of Webrick (no one ever claimed it was fast anyway) and I am going to try to get Sinatra running with 'Thin' instead.
Synchronization: I fork a new ruby process to blink out the messages. If you got both LEDs blinking at the same time, they could step on each other's toes and cause incorrect values to be written to the LED. I need to stick a mutex in to protect that register.
I remember early in my career, Kevin Moore and I had started using Ruby to run our embedded builds. We used the Win32 API to drive the automation interface of Metrowerks and we wrote lots of little tools to do the annoying parts of building a flash image for us. I remember at the time, Kevin and I having a conversation that went something like "Wouldn't it be cool if we could write the entire app in Ruby?" Well Kevin, now we can.
Embedded Ruby Sings Sinatra
by: doug | December 30th, 2008 | 2 comments »
Last Time I got ruby up and running on my Arm based embedded development platform. Here is a quick summary of what Santa and I did over Christmas.Sockets
Getting support for sockets built into Ruby turned out to not be hard at all. All I had to do has uncomment the extensions I wanted in ext/Setup. Here is everything I decided to turn on.- etc
- fcntl
- iconv
- socket
- stringio
- strscan
- syck
- thread
- zlib
After a rebuild and reinstall, I could require and use 'socket.' Welcome, Ruby, to the outside world!
Relocating Ruby
I decided to move ruby to the 'standard' install directory (/usr/local/) instead of the root that I had done in the first iteration. This would avoid having to set the RUBYLIB environment variable and keep any mess I made out out of the main system /bin and /lib directories. First I removed the --prefix from the configure script I had written last time. This will cause Ruby to build assuming the default install location (/usr/local/).- #! /bin/sh
- export ARM_TOOLS=/usr/local/arm/gcc-4.2.3-glibc-2.3.3/arm-unknown-linux-gnu/bin
- export CC=$ARM_TOOLS/arm-unknown-linux-gnu-gcc
- export LD=$ARM_TOOLS/arm-unknown-linux-gnu-gcc
- export AR=$ARM_TOOLS/arm-unknown-linux-gnu-ar
- export RANLIB=$ARM_TOOLS/arm-unknown-linux-gnu-ranlib
- export ac_cv_func_getpgrp_void=yes
- export ac_cv_func_setpgrp_void=yes
- ./configure --host=arm-unknown-linux --enable-wide-getaddrinfo
After Ruby was built, but before installing it (make install), I hacked the DESTDIR in rbconfig.rb
- ...
- TOPDIR = File.dirname(__FILE__).chomp!("/lib/ruby/1.8/arm-linux")
- DESTDIR = "/~/ruby/install"
- CONFIG = {}
- ...
This created the /usr/local tree inside my install directory. I created a /usr/local/ on my file system and copied that tree over. The only problem with this process is that the sh-bang line on the top of all of the ruby scrips (irb, testrb, etc.) had the wrong path in them. They had the install path on the host machine (/~/ruby/install/usr/local/bin/ruby) instead of the actual path on the target (/usr/local/bin/ruby). I changed those by hand.
Sinatra
Ahh, now the good part. Using a gem on an embedded system is an interesting problem. I first had to get rubygems installed on the network files system. I downloaded the source code and temporarily placed in on the target files system. On the target I ran the install command.- ruby setup.rb --no-rdoc --no-ri
I found it more convenient to install the gems from the host system instead of the target. It would be faster and the 'gem' command had some ruby dependencies that I hadn't yet build. I downloaded Sinatra and Rack and then manually installed them into my target's file system on the host machine. Note that /arm/fs/ is the root of my networked file system. I switched off rdoc and ri to help keep the install small.
- sudo gem install sinatra-0.3.2.gem -i /arm/fs/usr/local/lib/ruby/gems/1.8 --no-rdoc --no-ri
- sudo gem install rack-0.4.0.gem -i /arm/fs/usr/local/lib/ruby/gems/1.8 --no-rdoc --no-ri
With Sinatra installed and ready to go, I wrote a quick Sinatra app. Sinatra runs on Mongrel by default, but I wanted to run on the lighter weight Webrick web server which was already in my ruby installation.
- require 'rubygems'
- require 'rack/handler/webrick'
- require 'sinatra'
- Sinatra::Application.default_options.merge!(
- :run => false,
- :env => :production,
- :port => 80
- )
- get '/' do
- "Hello Sinatra!"
- end
- Rack::Handler::WEBrick.run Sinatra.application
Drum roll please ...
Next Steps
I've been plugging away on the linux device and ruby extension side of the project. I'm still on the steep side of the learning curve, but making progress. I'm still after that elusive blinking LED!Embedded Ruby - First Steps
by: doug | December 19th, 2008 | 3 comments »
I spent the beginning of my career working on embedded systems for some audio company. These embedded systems were my first love in programming and to me, no flashy css on a web page can beat the thrill of writing some code that flashes an LED. I've been working lately with Ruby a lot. I love it. I love that the language nearly disappears and I am able to express pure intent. Ok, so there is still syntax and such, but I can create so much more with so much less code.I hate living a fragmented existence, so I've been working the last few days on bridging these two worlds of mine. I figured that it will also give me a chance to get more familiar with linux and the latest in the embedded world.
First up, pick a platform.
I chose this single board computer from Glomation. It has an ARM920T core and an LCD / touch screen interface which may be fun later.Next, Tools.
I was determined that I could get a toolchain up and running on my MAC, but eventually ended up running linux in a virtual machine. Glomation had a set of tools and a pre-patched kernel already to go on their support page and our apprentice had a virtualbox linux image that he let me copy, so I was up and running quickly.I do want to share with you a few of the resources I found in the processes.
- I began with the GNUARM project.
- Tom Walsh on the gnuarm mailing list was helpful and pointed me to his scripts. I came real close to a working toolchain on the Mac with his help.
- I also gave the Crosstools project a try but ended up in the same place I was before.
- Thanks to David Goodlad's RubyConf 2008 presentation I discovered Open Embedded. This seems to be where the momentum is right now. I imagine I will give this project a careful look soon. I wish I would have started here.
Cross-Compiling Ruby
A few folks have had some success cross compiling ruby and Goodlad's presentation claimed that ruby is a part of the open embedded project. I built ruby 1.8.6-p111 because that what was on my linux distribution and it seems to be a well distributed release. Here is the script I used to configure ruby for cross compilation. Thanks to The Zen Machine blog for the skeleton of this script.- #! /bin/sh
- export ARM_TOOLS=/usr/.../arm-unknown-linux-gnu/bin
- export CC=$ARM_TOOLS/arm-unknown-linux-gnu-gcc
- export LD=$ARM_TOOLS/arm-unknown-linux-gnu-gcc
- export AR=$ARM_TOOLS/arm-unknown-linux-gnu-ar
- export RANLIB=$ARM_TOOLS/arm-unknown-linux-gnu-ranlib
- export ac_cv_func_getpgrp_void=yes
- export ac_cv_func_setpgrp_void=yes
- ./configure --host=arm-unknown-linux --prefix=$HOME/ruby/install
ARM_TOOLS is where I installed the cross compiler. The prefix is just the place where 'make install' will drop the results of the build.
The configure script generates a file in the ruby root director called fake.rb that causes some problems when I went to 'make'
- /ruby-1.8.6-p111/fake.rb:12: unterminated string meets end of file (SyntaxError)
I opened it up and it has a very obvious syntax error in it. I added the missing backslash on line 12 and ruby built fine from there.
- 12 ALT_SEPARATOR = "\";
becomes . . .
- 12 ALT_SEPARATOR = "\\";
'make' then 'make install' and I had my cross compiled rubyGetting Ruby onto the Target
The last step to seeing little rubies flying on my ARM core was to get the build onto the target. The Glomation board came preloaded with a kernel and a root file system. The kernel source was provided on the support page but not the root file system. I asked their support guy and he kindly posted it for me. I was dreading having to rebuild a file system from scratch, so I was grateful for his help.I decided that the best option would be to just have the target load of the root file system over the network on boot. I followed these instructions for mounting the image on my linux VM and these instructions for setting up an NFS Server. Mounting the file system over the network is a great option because now I can edit the file system from my Mac or linux VM and have the target see the changes without even rebooting. Perfect! The 2440 board came loaded with UBoot and all I had to do to load the file system over the network was to set the nfsroot in the bootargs from the bootloader's command line.
- set bootargs 'nfsroot=10.0.1.151:/arm/fs rw console=ttySAC0,115200 ip=dhcp init=/linuxrc'
Once booted, I only needed to set the RUBYLIB environment variable so that ruby knows where to find the libraries. I added this to my init script.
- export RUBYLIB=/lib/ruby/1.8
And there you have it. Ruby running on my ARM board:
Next Steps
Here is where I want to go from here.- Sockets. I need to build openssl support for ruby so that I can talk to the world from Ruby. The Zen Machine ought to help me out here.
- Sinatra - I'd like to run Sinatra on the target and start serving up some web pages
- RTC - I want to get that on chip Real Time Clock working so that it's not always 1970
- Drivers and extensions - I want to be able to control some hardware from Ruby. I've got a lot to learn here but I'll have to find or write a linux driver and then build a Ruby extension on top of it. I'm imagining something like led.on and led.flash.
- Submit to ESC. I'm hoping to submit my work to the Embedded Systems Conference. I hope that Ruby can start picking up some momentum in the space and save embedded developers gobs of time like it has done in the web development world.
One Take on Configuring Rails Routes and asset_host
by: jim | December 2nd, 2008 | 1 comments »
We recently had an interesting requirement surface. In anticipation of the release of a number of demo environments, our customer requested that system configuration be able to be done at the server level. The goal was to avoid being forced to use source control to manage configuration files.
A little background is in order. The systems that we are working on are pretty large. There are two distinct, decoupled systems, each consisting of between 10 and 40 subsystems. Of these subsystems, a handful on each side are Rails applications. Most others are small Ruby application that talk a central Rinda server. We already have a configuration strategy in place for the two systems, which involves a central configuration file per system which populates a globally-accessible configuration hash.
The directory structure looks something like this:
/deployment /deployment/system_one /deployment/system_one/etc /deployment/system_one/etc/config.rb /deployment/system_one/rails_app_one /deployment/system_one/non_rails_subsystem_one
The systemone/etc/config.rb file creates the configuration hash and populates it with all of the appropriate configurations (in practice, config.rb actually loads the appropriate configuration file based on an environment variable, i.e. RAILSENV, but we will ignore that here for brevity and clarity):
- APPLICATION_CONFIGURATION ||= {}
- APPLICATION_CONFIGURATION[:foo] = "bar"
From the context of a Rails application, this central configuration file is loaded from railsappone/config/environment.rb:
- # Load the system configuration
- require File.expand_path("/deployment/system_one/etc/config")
- # Bootstrap the Rails environment, frameworks, and default configuration
- require File.join(File.dirname(__FILE__), 'boot')
With this configuration strategy in place already, the team was tasked with setting up multiple demo environments for the entire system, each deployed on a different server and accessed through a different external URL. We could have attempted to solve the configuration issues by just adding many separate Rails environments, say demo1 and demo2, but there were a couple problems with that. First, the configurations for the different environments would have been nearly identical. Second, we wanted to avoid the complexity of relying on source control to manage the configurations for each deployment. In most cases, relying on the Rails convention of setting up a new environment makes a lot of sense. However, in our case, the only differences between the environments would be setting the asset_host and routes. Storing this in source control means that in order to make a change to the external URL means that files under source control need to be modified, checked in and then redeployed to the affected system. It makes much more sense to have some reasonable defaults in source control and then provide a mechanism to override these configurations at the server level.
The solution to this problem ended up being quite simple. We first agreed on an acceptable location for the server configuration file:
deployment/config deployment/config/server_config.rb
In order to allow for overriding the system configuration, this code was added to /deployment/system_one/etc/config.rb:
- # Allow for configuration to be overridden by a config file that is not under source control
- server_config_file = File.expand_path("/deployment/config/server_config.rb")
- require server_config_file if File.exists?(server_config_file)
The server configuration in deployment/config/serverconfig.rb will be loaded (and executed), if it exists. If it doesn’t exist, the default configurations will be used, which is the desirable behavior. The first task was to configure the assethost. To start with, we add the desired assethost configuration to /deployment/config/serverconfig.rb
- APPLICATION_CONFIGURATION[:my_rails_app_asset_host] = "https://www.example.com/my_rails_app/demo"
For each Rails environment that we want the assethost to be configurable from the server configuration file, just add this line to the appropriate config file, e.g. deployment/systemone/railsappone/config/environments/demo.rb:
- config.action_controller.asset_host = APPLICATION_CONFIGURATION[:my_rails_app_asset_host]
You would want to add a separate assethost configuration for each Rails application, and each Rails application would set its own assethost to the appropriate configuration. For a simple configuration like asset_host, this works great. For routes, though, it gets a bit more complicated. We need a Mapper instance in order to build a route. For example, your routes configuration looks something like this:
- ActionController::Routing::Routes.draw do |map|
- map.connect ':controller/:action/:id'
- end
We initially saw two options. 1) Create a data structure representing the desired routes, store it in the configuration, then from the routes file iterate through the structure created in the configuration file, creating the appropriate routes; or 2) Store some Ruby code in the configuration so that the context (i.e. the Mapper instance) can be passed to the block at the run-time. This second option eliminates the need for a secondary data structure to represent the routes. How better to configure the routes than with the actual code used to configure them?
It turned out that this was nearly as simple as the assethost configuration. First, let’s define the routes in /deployment/config/serverconfig.rb:
- APPLICATION_CONFIGURATION[:my_rails_app_routes] = lambda do |map|
- map.connect 'my_rails_app/demo/:controller/:action/:id'
- map.connect 'my_rails_app/demo', :controller => "login", :action => "index"
- map.login 'my_rails_app/demo/login', :controller => "login", :action => "index"
- end
We have used the lambda method to convert a block into a Proc object. The Proc object is stored as a value in a hash which can be executed later. The rest should look familiar to anyone using Rails; it is exactly what we would have had in our routes file. Now, from /deployment/systemone/railsapp_one/config/routes.rb, we can do this:
- ActionController::Routing::Routes.draw do |map|
- APPLICATION_CONFIGURATION[:my_rails_app_routes].call(map) if APPLICATION_CONFIGURATION[:my_rails_app_routes]
- # Install the default route as the lowest priority.
- map.connect ':controller/:action/:id.:format'
- end
In order to invoke the Proc object stored in serverconfig.rb, we just send the call message to the Proc stored in the configuration hash, if it exists. In our implementation, we invoke the Proc configured in serverconfig.rb before all of the other (default) routes, with the assumption that the configured routes should have the highest priority. If we run into a case where this isn’t the case, we can address that problem then.
Kata: Langston's Ant in Ruby
by: micah | November 13th, 2008 | 3 comments »
I’ve recorded my Langston’s Ant kata for all to see.
This particular kata, with slight variations, has been in front of an audience twice before. Once at a Software Craftsmanship group SCG meeting and again at RubyConf2007.
On both occasions I asked the audience to evaluate my performance on a scale of 0-10, 0 being the worst kata you can imagine, and 10 being the best. At the SCG, my performance was longer than the screencast because I didn’t use the instance_eval trick and wrote multiple case/when statements. It resulted in much more code as well. Honestly, I felt the kata dragged on a bit too long which is why I shortened in subsequent performances. Despite this, the SCG audience gave me an average score of 8. At RubyConf, the kata was almost exactly like the screencast and it earned me an average score of 7.
Now coming from an audience of dedicated Ruby developers, I’m quite pleased with my score. Here’s some of the feedback I got…
- Use of
instance_eval: -1 - First test, going from compile error to passing tests: -1
- Refactoring on with red bar: -1 (not repeated in the screencast)
- Non-idiomatic
is_black?: -0.5 (fixed in screencast) - Steps are too big in between tests: -1
- …
I find this feedback immensely valuable and thank those who took the time to provide me with it.
In martial arts, the techniques performed in kata are not always by the book. There is an aspect of art, creativity, and entertainment. At several points in my Langston’s Ant kata I intentionally decided to bend the rules to enhance artistic and entertainment values. I leave it up to you whether I made the right compromise or not.
After watching the kata, leave a comment with your rating and any feedback you have for me. I thank you in advanced.
Simon
by: micah | November 10th, 2008 | 0 comments »
You remember the classic Simon game, right? The one where the electronic devise will blink a color and make a sound that you have to replicate by pushing the colored buttons.
At RubyConf 2008, I cornered Jim Weirich and asked his opinion on Limelight. He didn’t feel like he had seen enough of it to give a good opinion. So we found an hour where we could both sit down and build a simple Limelight production. We decided to build Simon.
The result is really quite simple. It’s a couple hundred lines of code, UI, game logic, and all. It’s also got a suite of unit tests.
If Limelight is installed, you can download the production file, and double click it, or enter the url in the Startup Limelight Production.
Limelight Production file: http://blog.8thlight.com/files/simon.llp
The Source Code can be found on github.
Ruby Battleship Sparring Tournament
by: micah | November 8th, 2008 | 0 comments »
Yesterday in my talk at RubyConf2008, I announced the commencement of the Ruby Battleship Sparring Tournament.
This is an open tournament. All are welcome to participate.
Agile in Buenos Aires
by: micah | October 29th, 2008 | 0 comments »
Last week I attended Agiles2008 in Buenos Aires, Argentina. It was a fun, high energy conference. The highlight was a heated panel discussion at the closing of the conference. On the Panel was Matt Gelbwaks, myself, Tom and Marry Poppdieck, Dave Nicolette, and Tobias Mayer. Tobias has already posted a blog about the event. So that my opinion is not misconstrued, I'll share it with you here.The future of Agile is Software Craftsmanship.
Software is a young industry and we're still discovering more about it every day. Yet, it has it's origins in electrical engineering. So it's seems that, at it's inception, people assumed software was a form of engineering. And to build software systems should be no different from engineering any other creation. Take a bridge for example. Before building a bridge, you have to analyze the bridge requirements. How long will it be? How much weight must it hold? etc... Once the requirements are understood, you design a solution. Build to-scale models that you can push and stress to make sure the design hold up. Then, once you have a solid design, can you begin construction of the bridge.
It's waterfall. Waterfall worked for engineering so waterfall was applied to software. We know now that waterfall doesn't work. Agile, is a realization that software is not a form of engineering. Agile is a realization that software is a craft.
I have been to every North American Agile conference since the very first, and I have noticed a trend. In the first conference in Charlotte NC, laptops were open on every table, around every corner, with someone or a pair of people writing code. In many of the sessions, people were writing code or talking about it. This is the conference where people were bragging about their Ward number (0 if you paired with Ward Cunningham. n + 1 if you pared with someone with a Ward number of n.) and desperately trying to improve it. It was truly a conference about software. Over the years, less and less coding could be found at the conferences. This last year, at the conference in Toronto, it was abysmal. Although there was some good content, I felt like the conference had been taken over by Scrum Masters. It was no longer a conference about software development. It had become a conference about project management, people management, and Scrum. This makes me sad.
The future of Agile is Software Craftsmanship. Developers out there need to realize that software is a craft. As such, developers should strive to become craftsmen; strive to learn more about software; strive to write better code; strive to build the best software possible. The software you get from a team of true craftsmen will be unrivaled. It is the goal and quality within that drives a team of craftsmen. They'll find a way to overcome any obstacles and adapt to any changes. #





