Cookin' Code
My wife and I have done our share of cooking, me as a short order chef and she as someone who just enjoys it. Both of us are a “clean as you go” type of chef (loosely speaking here). My friend has the attitude that if I cook it, you clean it. We can all create good food after our style, but the state of the kitchen and the ability to do more is very different by the time we are done. By the time my wife and I are done, the used dishes are either in the sink or the dishwasher and the surfaces are wiped clean. By the time my friend is done, it looks as if hurricane Katrina had her way with the kitchen. Either way, there is some finish work that needs to happen but the amount of work is drastically different.
There’s a subtle psychological difference and a big difference in the time to completion. If you clean up your code as you go, the effort is much smaller and the number of loose ends are far fewer. If you wait until you are done with a cycle, you’ll end up with several methods that accomplish the same goal with only slight differences. The effort to consolidate them can be pretty heinous. Particularly if you have to adjust the client code to be consistent.
In both cases the underlying philosophy is “make it work, then make it better”. I’ve found that making the cycle shorter between making it work and making it work better keeps the code cleaner. It also makes it done. If you hand a customer a working application, but there are a “few things to clean up” then the customer will only be so patient. A lot of the things you may want to clean up will just not get done because the client doesn’t want to pay for it. They need to be done, and those who need to maintain the app after you will curse under their breath if they aren’t done—but it’s a hard sell. What’s worse is that the time to clean up becomes longer than if you’ve been cleaning as you go. There’s no baked on grease, or staining things that have been left on the cooking surface too long.
Keep things simple, and keep them clean as you develop. Create your test proving you have work to do, make the test pass, then make the code cleaner. You’ll find that not only does it make it easier to move on to the next thing, but you end up working quicker overall. It takes me about the same time to clean as I go as it does to “make it work” and not clean as I go. The hacks you did along the way accumulate and dry and harden, and make it generally unpleasant to fix.
Pretty Code
What would happen if you could integrate a word processor and a compiler? That’s precisely what geoProgrammer from Commodore 64 fame did. The Graphical Environment Operating System (GEOS) team had several tools available out of the box. That included geoWrite and a few other cool apps. Because the GEOS team controlled the file formats for all the tools that were part of the system, they could integrate things a bit better than others. There was no plain text editor in the GEOS system, that wasn’t sexy. That wasn’t graphical. So why bother with it?
You wrote your applications in geoWrite and compiled them with geoAssembler which produced relocatable bytecode. Finally you linked it with geoLinker . The whole suite came with a comprehensive API manual which was quite nice considering that GEOS was all assembly language. The experience taught me that you can have very elegant code even when you are working at the assembly level. However, an interesting side effect of using geoWrite to write the code was that you had fonts and font sizes available. It was actually rewarding to write nice looking comments. In fact, the comments would be more noticeable than the code. It was an unexpected side-effect from using a word processor for writing code.
Another very nice side effect was that if you wanted to embed graphics for buttons and such, all you had to do was paste your graphic into the document with some marker so that you can reference the graphic in your code. Can you imagine if your code would make it that easy to reference a graphic instead of having a large byte field encoded in numbers or relying on the linker to get it right?
Something like this has never been done since, for a number of reasons. First, it used to be that graphical operating systems were simply too expensive. Next, it was that all word processors had their own proprietary formats. Finally, you have the geek chic of only using text editors because that’s what geeks do. You’d be surprised what a little style can do to make the code more readable. One example are the text editors and IDEs that color your code for you. Now that we have an Open Document that most word processors can be extended to use, why not leverage that standard?
It turns out that the answer is that it makes the compiler more complicated. Of course, it’s easy enough to write a bit of code that simply strips out all the style and feeds the compiler/interpreter the plain version of the code. Do I expect something like this in the future? I’m not sure. There has to be a cultural demand for it to happen, and right now we are still stuck in the mainframe and resource starved origins. I think that UTF support in the source code is going to be a sooner cultural demand than WYSIWYG prettifying of code. The future is still unwritten.
Example of Simplicity in Design
It’s all well and good to preach simplicity, but if you don’t provide practical examples then no-one can get it. I’m going to highlight one section of Java ActionPack to show simplicity in action. The first mistake that people make when talking about simplicity is confusing it with simplisticness.
Simplicity is the ultimate sophistication. Leonardo DaVinci
So what does it mean to use simplicity in code? First, simplicity has to do with keeping the responsibilities of your code small and focused . You should resist adding responsibilities to a bit of code unless there is no better place to put it. The org.dhaven.actionpack.Route class in Java ActionPack takes a URL pattern, and set of default values and populates request attributes with the substitution values. That’s it. Nothing else. It’s the controller code that reacts to the special attributes “controller” and “action” to find the controller and action to execute. The org.dhaven.actionpack.Routes class will allow you to register a series of Route objects to evaluate in order. It also provides a method to iterate through the Routes and return when the first match has been found. Pretty sweet, huh? Two classes that have a relationship, but their responsibilities are very small.
Nice overview, but can we look at things in more detail? Sure thing. I wanted to make sure it was easy to programatically set up the Routes you wanted your application to use. If you didn’t want a routes file hanging around, or you wanted to embed this framework someplace I hadn’t expected, it shouldn’t be hard to do. I.e., I shouldn’t have to try and set up an object tree like the Apache Digester based projects. When you try to start from the configuration file format, instead of how you should add new routes to the system it gets really ugly really fast. So I wanted to make it simple , or easy to do. My solution? Why not simply call Routes.connect() ? If you were to set up the routes manually, it would look like this:
public static void setUpMyRoutes() {
Routes.connect("/{controller}/{action}/{id}");
Routes.connect("/{controller}/{action}");
Map<String,String> initParams = new HashMap<String,String>();
initParams.put("controller", "home");
initParams.put("action", "index");
Routes.connect("/{controller}", initParams);
Routes.connect("", initParams);
}
Notice that I’m only passing strings into the Routes object? In turn, the Routes object doesn’t do anything with these strings other than creating Route objects with the parameters passed in to the constructor. It’s the Route object itself that knows what to do with the provided strings. The initParams map is also a simple map, which provides default values. The default values are overridden by the values interpreted by the URL. What I haven’t done, and I probably ought to do is to make it so that if defaults are present, the same Route can match partial URLs like the Ruby on Rails version of the functionality can. Perhaps that is a future enhancement. Remember, it is only the Route object I have to alter to make that possible. Setting up the Routes is as simple as it gets.
So what if I don’t want to worry about setting up the routing myself? Well, why not create a route parser? That’s exactly what we did. The org.dhaven.actionpack.RouteMapParser handles parsing a very simple route file format that isn’t XML. In fact, it’s similar to the Ruby format (with minor differences). I didn’t want a full on Ruby parser, just a convenient format. If you call org.dhaven.actionpack.RouteMapParser.parseFile() while passing in an InputStream or Reader, you can have it parse the file for you. The parser is very simple as well. First, all routes are completely defined on one line. Second, blank lines and lines that start with the ’#’ character are ignored. Why the ’#’ character? Because it is used as the comment marker in Properties files, shell scripts, and Ruby files. It should be reasonable to assume people know that is a comment. So what does a line look like? Well, let’s do the same thing with our file that we did in the method above.
"/{controller}/{action}/{id}"
"/{controller}/{action}"
"/{controller}", action => "index"
"", controller => "home", action => "index"
The first part of the line is the URL in quotes. This is the “route” that is being connected through the Routes class. All elements of a route are separated by a comma. That means the route and all default request attributes are separated by commas. The key/value of each map entry is separated by the ’=>’ combination. That separator is a convention used in Ruby and Javascript, but it looks right. No quotes for the key, and the element is surrounded by quotes. There really isn’t much of a reason for this convention other than I thought it looked easy on the eyes. With everything in quotes it got tough to keep straight what were the keys and what were the values. Now, all the key/value pairs are strings. It’s up to you to perform the conversions to other types in the controller if you want. The reason for that has to do with simplicity of design, and not getting the whole route map process too convoluted.
The RouteMapParser takes care of calling the Routes.connect() method which in turn takes care of creating the Route and putting it in our list of routes to match against. Each responsibility is clearly mapped to one class. If someone else wanted a different format for setting this up, there would be nothing to stop them from doing it. It also makes understanding each class much easier. The RouteMapParser only has the responsibility of converting a file to a set of routes. The Routes object only has the responsibility of managing the list of routes and testing a request against that list. The Route object has the responsibility of trying to match the URL, and then populating the attributes if there is a match. The Route object may be expanded in the future to take the parameters and generate a URL from them (as Ruby On Rails currently does), but that is a future enhancement.
The bottom line is that the responsibilities are finite and related to each other. More importantly, the concerns of configuring the system are kept separate from the code that does the work. The number of objects needed to do simple things is very small, and the interactions are well defined and easy to understand. The simplicity allows the objects to be used in ways I may have not foreseen, but that doesn’t really matter. What matters is that the sophisticated uses I haven’t foreseen are because of the simplicity of the classes governing that responsibility.
Using Java Enums for Finite State Machines 3
Finite state machines are useful design constructs for a number of situations, although they seem to be fewer and farther between these days. Currently, the only place I tend to use them is when I have to write a parser by hand. Sure there are BNF parser generators around, but not all parsing requirements fit those restrictions. I have to parse legacy message formats which predate BNF parser theory (i.e. from the 1950s), so this is a useful tool to ensure that the message is properly formatted and all the information is pulled out properly.
According to Design Patterns by the GoF, the way to do an object oriented finite state machine is to use objects to represent each state, each with a common interface. My first introduction was a C++ program that was written with the old C mindset. That meant that the states were represented by an enum and all actions were taken with large switch or if/else hierarchies. I can see how using objects can clean things up, because the conditional logic would be decided by the state object. Of course, the state pattern in the GoF book required keeping the state in an external object and neglected to dictate how to change the state properly.
The Problem We are Solving
For my purposes, I have to populate a message object with all the information from a text message. That includes things like security markings, addresses, tags, captions, etc. The message format is distinct enough so that each line means something. Of course, there is a proper order of processing, but I can parse one line at a time. That simplifies things a whole bunch. I can have the parser work with an interface that looks like this:
public interface Partial {
public State parse(Message message, String line)
throws ParseException;
}
In Java 7 we will likely be able to use partials for this approach, which will clean up a lot of the code clutter. In that case the interface would look like this:
{Message, String => State throws ParseException}
Either approach you take will allow you to write the enumeration delegating the actual processing to anonymous classes. I’m sure you’re thinking, “My God! This guy’s off his rocker! I thought he liked elegant code!” Trust me, you’ll see the elegance in a minute. You aren’t going to do this all the time, but when the situation calls for it, you’ll appreciate it. The real benefit comes from testing.
Enums and Finite State Machines
Java enums are objects which is really useful. I’ve used this fact to associate sort order SQL snippets with an enum for the different sorting algorithms supported in a system, along with other uses. I decided to do an experiment with rewriting a parser we have. The parser works for the most part, but it leaves out some important information we want to support, and more importantly it is difficult to change. It needs some major rework beyond the scope of a bunch of refactorings. That is why I chose to rewrite it.
We have to start writing the State instances, and it really helps to have a starting point. For this blog, I’ll only split a message into header and body sections. There’s a whole lot more going on, but I just want to show how things work. The marker that splits the message header from the body will be a line that has “BODY” on it with nothing else. First, let’s look at our State enum. The important thing here is that we are not
public enum State implements Partial {
HEADER(null),
BODY(null);
private final Partial partial;
private State(Partial parser) {
partial = parser;
}
public State parse(Message message, String line)
throws ParseException {
return partial.parse(message, line);
}
}
The implementations of HEADER and BODY are null right now because we will get into it a bit later. First, you’ll notice a couple things about the enum. We are passing something that does work into the constructor, which also means that our enums can do work. For consistency sake we used the same interface for the enum as we did for the interface we pass into the constructors. If we were to use the closures spec, we wouldn’t have an interface to implement, so the method we provided would be how we access the blocks passed into the constructor. The spirit of the design is the same, it’s just that there is less extra code to type. Just so you can see what it looks like (assuming I have a better understanding of the spec), here you go:
public enum State {
HEADER(null),
BODY(null);
private final {Message,String=>State throws ParseException}
partial;
private State(
{Message,String=>State throws ParseException} parser) {
partial = parser;
}
public State parse(Message message, String line)
throws ParseException {
return partial.invoke(message, line);
}
}
In either case, the base design is identical. The only way to have the functionality of enum values change based on the value is to use the delegate approach. In short, we are passing in an object that does the work that is specific to that state in the constructor and calling it later when we call the parse method. It’s also important to note that enums are singletons by definition. There is one and only one State.HEADER enum value in the system, as there is one and only one State.BODY enum value in the system. That means the implementation has to be re-entrant. As long as you don’t attempt to keep any state in the objects you should be fine.
For the rest of the article, I’ll be focusing on the anonymous class approach (i.e. the first version). I’m assuming you can do the translation into closures later. Besides, I’m not sure if it would be legal to use the control invocation syntax for the constructor or not. This is a question for Neal Grafter, would this be legal syntax for the constructor of an object (it would be better if that’s the case)?:
HEADER(Message message, String line:) {
HEADER
}
The State Implementations
The implementation of the state is very simple. We are providing an anonymous class (or closure declaration). The header is going to add the line of text to the header provided until we hit the “BODY” line. We aren’t going to copy that line at all. The important thing is that we can easily test these conditions in isolation from any other state. Let’s write some tests to make sure our implementation does what it is supposed to do (we are skipping the boiler plate JUnit code):
public void testCopiesLineToMessageHeader_and_ReturnsHEADERstate()
throws ParseException {
String line = "test line";
Message message = new Message();
State state = State.HEADER.parse(message, line);
assertEquals( State.HEADER, state );
assertEquals( line, message.getHeader() );
}
Currently our implementation compiles but only throws NullPointerExceptions because we haven’t given it anything to do yet. Let’s at least get this to pass. We have to rewrite the HEADER constructor in the enum:
HEADER(new Partial() {
public State parse(Message message, String line)
throws ParseException {
message.addLineToHeader( line );
return HEADER;
}
});
That’s all well and good, but we need to make sure that we switch to the BODY state eventually. So let’s add a new test:
public testBodyLineReturnsBodyState_and_DoesNotWriteToMessage()
throws ParseException {
String line = "BODY"
Message message = new Message();
State state = State.HEADER.parse(message, line);
assertEquals( State.BODY, state );
assertEmpty( message.getHeader() );
}
Now, all we have to do is make this pass in the HEADER enum:
HEADER(new Partial() {
public State parse(Message message, String line)
throws ParseException {
if ( line.equals("BODY") ) return BODY;
message.addLineToHeader( line );
return HEADER;
}
});
Now, if you are using Java closures, you simply cannot have multiple exit points. It’s easy enough to alter the logic. Some people don’t like what I did as a matter of principle. That’s OK. We know it works and its tested. We can refactor it later to our heart’s content. For the purpose of brevity, it’s up to you to do the same thing with the State.BODY implementation.
Using our Finite State Machine
Using the Finite State Machine we just created (granted it has only two states) is really easy. We know that we need a message object, and we need to iterate over the lines to a message. We’ll assume that you got it from some Reader. Here is a method that does the hard work for you:
public Message parseMessage(Reader in)
throws ParseException, IOException
{
Message message = new Message();
State state = State.HEADER;
BufferedReader reader = new BufferedReader(in);
String line = null;
while((line = reader.readLine()) != null) {
state = state.parse(message, line);
}
reader.close();
return message;
}
I left all the error handling code as an exercise for you, dear reader. If you want to provide accurate line numbers for your ParseException objects, you can surround the thing in a try/catch and use the following construct:
catch(ParseException pe) {
// Rewrite the line number where the problem occurred.
ParseException npe =
new ParseException(pe.getMessage(), lineNumber);
npe.setStackTrace(pe.getStackTrace());
throw npe;
}
You have to keep track of the line number yourself. The lineNumber variable was incremented in the while loop in my code. I also wrapped the IOException in a ParseException keeping track of the line number so the signature was simplified. Of course, you’ll want close the reader in a finally clause.
In Conclusion
You aren’t going to write a finite state machine every day, but when you do you’ll want to keep things as simple as possible. The approach I outlined is very handy in the sense that you can completely test each state in isolation from the others. Because it is its own object, you don’t have to worry about testing the whole of the application to ensure your states are doing what they were designed to do. I typically have each State instance tested in its own TestCase object. This makes it particularly clear what each state is supposed to do, and how/when transitions take place.
I find that FSM are much easier to understand when you think about one state at at time. Trying to keep the whole “if this, then that, or is it the other thing” reasoning can be avoided that way. Doing it the old procedural approach is really not very useful these days. Don’t query data and keep control. Ask your objects to do work for you. Delegate.
