In my previous article I talked about the general process of developing from the outside-in. This way we ensure that our API is correct and more mature before we invest time and effort in implementation. This process also makes writing a Fluent Interface much more intuitive than when building from the inside-out.
Just to recap: First we write a sketch of how we want our (not-yet-implemented) functionality to be consumed. Next we stub out the surface area, building an object required to support our sketch one at a time. Once we stub out a method or class we define how it should behave using a unit test. Finally, after all the classes and methods are in place we start implementation to make our tests pass.
Last time we covered using the Method Chaining pattern to provide a Fluent Interface. Sometimes simple method chaining using one class is not enough to get our API to "flow" in a way that makes sense. Depending on a particular method call we might need to branch and provide different types of linguistic elements or functionality. Also, building a Fluent Interface does not consist of using Method Chaining alone and can be achieved with many different techniques. The point is to make the API readable and for it to flow.
For this demonstration I have added some elements to our code sketch from the last article.
Egg humptyDumpty = new Egg("Humpty Dumpty"); Wall wall = new Wall("Great wall of China");
humptyDumpty .Does .SitOn(wall) .HasFall(Severity.Great);
King henry = new King { Name = "Henry", Horses = 100, Men = 500 };
Boolean isFixed = henry .GetFromKingdom() .AllHorses() .Plus .AllMen() .AttemptToPutTogether(humptyDumpty);
Console.Write("All the kings horses and all the kings men could " + ((isFixed) ? String.Empty : "not") + " put Humpty together again"); |
As I mentioned, building a Fluid interface is not solely method chaining and the goal is to have readable code that flows. One way is with new instantiation syntax available in .NET 3.5 using automatically implemented property setters. So instantiating a King class (above) is a way to write readable code that flows.
public class King { public Int32 Men { get; set; } public Int32 Horses { get; set; } public String Name { get; set; } } |
Personally I'm torn as to whether or not I like this style of declaring properties with the hidden backing store. It does take a lot less code and makes the class a bit more readable. It bothers me in that I feel like I'm "faking" encapsulation if only because I can't see the class member variable even though I know it is there. I will use this style if the object holds a relatively simple state like with simple data transport objects and I can keep the same style within the class. Often objects are a little more complex and require some more guts and I prefer consistency over brevity in how member variables are coded in a class. I also like to declare my own class member variables as backing stores and set them to "readonly" whenever possible because it simplifies the object in that anyone reading it knows the only time the variable could have been set is in the constructor and it will not change during the life time of the object. You can't do this with auto-implemented properties and I have found that the inconsistency of using a mix of both styles in a single object causes a great deal of confusion. However, because I can be consistent within the King class we will go ahead with this style. I feel that doing this in our example is ok because it provides readable code and is in the spirit of building a fluent interface.
In the last article we stubbed out the first part of our sketch and now we'll start with the Henry's kingdom. First we'll stub out the GetFromKingdom() method.
Here's where things get complicated and we have to put on our thinking caps to be sure we don't end up going down a rabbit hole. It is very easy to overdo it using this style of coding and we need to remember to try balancing keeping the code and the API as simple as possible. We need to consider complexity that will exist not only in our library but any consumers of our library. We also have to constantly check ourselves and make sure we are coding at a proper and consistent level of abstraction. If we model too granularly, we get object/code bloat. If we model too coarsely, we get an unusable object model. If we mix the two and don't have consistency in our abstractions our library will not be intuitive to consume.
We have to decide how to handle building this method chain and there are many domain driven factors that would influence our decision. What object should we return from GetFromKingdom() and what should it do? Well, we know it will be used to define a set of things that all work together to try and put together Humpty-Dumpty in the end. The questions to ask our self are: How flexible do we want the API? How will it grow in the future?
Let's say we would eventually like to be able to say things like the following:
Boolean isFixed = henry .GetFromKingdom() .Horses(30) .Plus.AllMen() .Subtract.Men(20) .AttemptToPutTogether(humptyDumpty); |
In this case, we'll build an object model that will have the elbow room to go in this direction in the future. Often when I get to this point in defining the classes it is a place where I realize that I can drastically simplify my API by specifying a different syntax in the sketch. Using this style of coding we should constantly be on the lookout for these opportunities to make thing simpler and take advantage of them so we end up with a nice concise API in the end. The whole idea of this style of development is to be able to make the changes before we are committed having already lost our investment in time coding the implementation which will probably have to change. Once the implementation cycle starts and we have even just a few methods finished, the flexibility of our code decreases significantly and change comes at a much higher cost because of cascading breaks. Also, if we have identified some major blocking points (by falling into them when building the API) starting over from scratch with a different sketch is not a bad idea. This way we can compare the two different APIs we have built and take the best from both.
The approach we'll take here is to create a class representing a verb-like linguistic element used to add things from the king's kingdom to a subset of stuff that belongs to that kingdom. We'll also need a class to hold our entire kingdom subset of "stuff".
public class King { public Int32 Men { get; set; } public Int32 Horses { get; set; } public String Name { get; set; } public KingdomStuffAdderPart GetFromKingdom() { KingdomStuff allStuff = new KingdomStuff(); return new KingdomStuffAdderPart() } } |
The KingdomStuff class is used to hold things that belong to a kingdom. The KingdomStuffAdderPart is used to represent a linguistic element used as a piece of a fluent interface that has the express purpose of adding things to the KingdomStuff class (like a verb). I like suffixing classes that represent fluent interface linguistic elements with "Part". For example: KingdomStuffAdderPart. I have also seen other developers suffix the class name with "Fluent". Either way, consistency is key so that we can (hopefully) make this part of our source code more readable once someone understands what is going on. Something to keep in mind is that these types of objects are very hard to decipher when looked at out of context in their own *.cs file and we need a way to remind ourselves and others reading our code what they are.
Now we'll generate the KingdomStuff class and it will contain a count for Men and Horses. This could have just as easily been two collections (one for a Horse object, one for a Man object), but we'll err on the side of simplicity. We can always go back and make things more complex if the domain demands it but to do the reverse is sometimes painful.
public class KingdomStuff { public Int32 Men { get; set; } public Int32 Horses { get; set; } } public class King { public Int32 Men { get; set; } public Int32 Horses { get; set; } public String Name { get; set; } public KingdomStuffAdderPart GetFromKingdom() { KingdomStuff allStuff = new KingdomStuff { Horses = this.Horses, Men = this.Men }; return new KingdomStuffAdderPart() } } |
Next we'll define the KingdomStuffAdderPart. This class will need to keep track of what the source stuff is and where the destination stuff is so we'll make two member variables to do this.
public class KingdomStuffAdderPart { public KingdomStuffAdderPart(KingdomStuff source, KingdomStuff destination) { m_Source = source; m_Destination = destination; } private readonly KingdomStuff m_Source, m_Destination; } public class King { public Int32 Men { get; set; } public Int32 Horses { get; set; } public String Name { get; set; } public KingdomStuffAdderPart GetFromKingdom() { KingdomStuff allStuff = new KingdomStuff { Horses = this.Horses, Men = this.Men }; KingdomStuff emptyStuff = new KingdomStuff(); return new KingdomStuffAdderPart(allStuff, emptyStuff); } } |
Now that we've chosen a path (for better or worse), we'll continue to the next item in our sketch and see how the rest of our API development plays out. Hopefully we have chosen wisely so our object model doesn't spiral out of control and we avoid having a "Raiders of the Lost Ark" moment… but there's only one way to find out. Hold your breath and we'll stub out the "AllHorses()" method which will end up on the KingdomStuffAdderPart class.
So far so good. We now have to figure out what to return from the "AllHorses()" method. We know from our sketch that we'll need to have a ".Plus" property off of the returned class. We also may want to have a ".Minus" property in the future. If we think of "AllHorses()" as a "verb" element, we now need a "noun" element. We'll build a KingdomStuffBuilderPart "noun" class just to retain some state during the transition to the "AllMen()" "verb" class.
public class KingdomStuffAdderPart { public KingdomStuffAdderPart(KingdomStuff source, KingdomStuff destination) { m_Source = source; m_Destination = destination; } private readonly KingdomStuff m_Source, m_Destination; public KingdomStuffBuilderPart AllHorses() { throw new NotImplementedException(); } } |
The KingdomStuffBuilderPart class will be very similar to the KingdomStuffAdderPart class except for that it is not active, but rather just a stagnant placeholder object.
public class KingdomStuffBuilderPart { public KingdomStuffBuilderPart(KingdomStuff source, KingdomStuff destination) { m_Source = source; m_Destination = destination; } private readonly KingdomStuff m_Source, m_Destination; } |
Now we can stub out the ".Plus" property which should return our already existing KingdomStuffAdderPart class from the KingdomStuffBuilderPart class that we just defined.
public class KingdomStuffBuilderPart { public KingdomStuffBuilderPart(KingdomStuff source, KingdomStuff destination) { m_Source = source; m_Destination = destination; } private readonly KingdomStuff m_Source, m_Destination; public KingdomStuffAdderPart Plus { get { return new KingdomStuffAdderPart(m_Source, m_Destination); } } } |
Now we can follow the same steps we used for building the "AllHorses()" method and stub out the "AllMen()" method on our KingdomStuffAdderPart class which should also return a KingdomStuffBuilderPart object.
And so our implementation will look something like this:
public class KingdomStuffAdderPart { public KingdomStuffAdderPart(KingdomStuff source, KingdomStuff destination) { m_Source = source; m_Destination = destination; } private readonly KingdomStuff m_Source, m_Destination; public KingdomStuffBuilderPart AllHorses() { m_Destination.Horses = m_Source.Horses; return new KingdomStuffBuilderPart(m_Source, m_Destination); } public KingdomStuffBuilderPart AllMen() { m_Destination.Men = m_Source.Men; return new KingdomStuffBuilderPart(m_Source, m_Destination); } } |
This would be the point at which we would start stubbing out the unit tests to ensure our functionality is correct and then to keep it pinned down as things may change. Even though it rubs me the wrong way, for the sake of brevity we'll skip this step.
Last (but not least) we'll stub out the "AttemptToPutTogether()" method which will return a Boolean and ends up on our KingdomStuffBuilderPart class.
Again, we should pin down the expected output with some unit tests at this point. Out implementation of the "AttemptToPutTogether()" class might end up looking something like the following:
public class KingdomStuffBuilderPart { public KingdomStuffBuilderPart(KingdomStuff source, KingdomStuff destination) { m_Source = source; m_Destination = destination; } private readonly KingdomStuff m_Source, m_Destination; public KingdomStuffAdderPart Plus { get { return new KingdomStuffAdderPart(m_Source, m_Destination); } } public Boolean AttemptToPutTogether(Egg humptyDumpty) { throw new NotImplementedException(); // put logic here to determine if an attempt would be possible return m_Destination.Horses > 0 && m_Destination.Men > 0; } } |
So now we have reached the point where all code necessary for our original syntax sketch is done. Next we could expand our functionality by adding a KingdomStuffBuilder.Minus property that would return a KingdomStuffSutractorPart "verb" class to allow us to remove things from a destination KingdomStuff object. Or maybe we could overload the KingdomStuffAdderPart to have a Horses(Int32 count) method in order to move a specified amount of horses from the source KingdomStuff to the destination. The primary purpose of what we have walked through is to demonstrate some of the possibilities of what can be done and should not be mistaken for what "should" be done. Building a API using this approach may give you good results in some situations but will not work for every situation.
The Pluses: By using this approach we end up with an easy to consume API which should minimize the coding time required for consumers of our library. Code resulting from consumption of our library should be very language-like and will flow and be easy to read and somewhat self-documenting (if we did our job well),
The Minuses: On the down-side we can end up with a cluttered library (too many objects) where some of our objects don't make sense outside their context (mainly the fluent interface linguistic elements). This will make the code inside our library harder to maintain with the caveat that the code consuming our library should be easier to maintain. We need to decide where maintainability is more important, in the fluent interface library or the consumer of our library. Another downside is that we have extra object instantiations and even though the object will generally be pretty light we do run the risk of putting a heavier load on the garbage collector so be careful in high performance applications.
If you were a professional boxer who knows only how to jab your career would probably be short lived. More moves are required in order to do well. Think of being able to build a Fluent Interface as adding an uppercut to your development skills. It can sometimes be a knockout if applied in just the right situations and sometimes it will get you in a tangled mess. We have to know the right move to make at the right time and this only comes with practice, critical thought and experience. Like many other decisions, the choice to build a fluent interface will always be a tradeoff and needs to be thought out carefully.
Coding from the outside-in is more like the basic footwork you would need to know to survive in the ring. Give this approach some practice and it will definately pay dividends for you.
In my next article we'll look at an example of how we can build a Fluent API that could be used in real-world applications.
Until next time,
Happy coding