Code Unit Test First
Continuous Builds
Fluent Interface
A few months ago I attended a workshop with Eric Evans, and he talked about a certain style of interface which we decided to name a fluent interface. It's not a common style, but one we think should be better known. Probably the best way to describe it is by example.
The simplest example is probably from Eric's timeAndMoney library. To make a time interval in the usual way we might see something like this:
TimePoint fiveOClock, sixOClock;...TimeInterval meetingTime = new
TimeInterval(fiveOClock, sixOClock);
The timeAndMoney library user would do it this way:
TimeInterval meetingTime = fiveOClock.until(sixOClock);
I'll continue with the common example of making out an order for a customer. The order has line-items, with quantities and products. A line item can be skippable, meaning I'd prefer to deliver without this line item rather than delay the whole order. I can give the whole order a rush status.
The most common way I see this kind of thing built up is like this:
private void makeNormal(Customer customer)
{Order o1 = new Order();
customer.addOrder(o1
OrderLine line1 = new OrderLine(6, Product.find("TAL
o1.addLine(line1
OrderLine line2 = new OrderLine(5, Product.find("HPK
o1.addLine(line2
OrderLine line3 = new OrderLine(3, Product.find("LGV
o1.addLine(line3
line2.setSkippable(true
o1.setRush(true);
}
In essence we create the various objects and wire them up together. If we can't set up everything in the constructor, then we need to make temporary variables to help us complete the wiring - this is particularly the case where you're adding items into collections.
Here's the same assembly done in a fluent style:
private void makeFluent(Customer customer)
{customer.newOrder
.with(6, "TAL")
.with(5, "HPK").skippable()
.with(3, "LGV")
.priorityRush();}
Probably the most important thing to notice about this style is that the intent is to do something along the lines of an internal Domain Specific Language. Indeed this is why we chose the term 'fluent' to describe it, in many ways the two terms are synonyms. The API is primarily designed to be readable and to flow. The price of this fluency is more effort, both in thinking and in the API construction itself. The simple API of constructor, setter, and addition methods is much easier to write. Coming up with a nice fluent API requires a good bit of thought.
Indeed one of the problems of this little example is that I just knocked it up in a Calgary coffee shop over breakfast. Good fluent APIs take a while to build. If you want a much more thought out example of a fluent API take a look at JMock. JMock, like any mocking library, needs to create complex specifications of behavior. There have been many mocking libraries built over the last few years, JMock's contains a very nice fluent API which flows very nicely. Here's an example expectation:
mock.expects(once()).method("m").with(
or(stringContains("hello"),
stringContains("howdy")) );
I saw Steve Freeman and Nat Price give an excellent talk at JAOO2005 on the evolution of the JMock API, they since wrote it up in an OOPSLA paper.
So far we've mostly seen fluent APIs to create configurations of objects, often involving value objects. I'm not sure if this is a defining characteristic, although I suspect there is something about them appearing in a declarative context. The key test of fluency, for us, is the Domain Specific Language quality. The more the use of the API has that language like flow, the more fluent it is.
Building a fluent API like this leads to some unusual API habits. One of the most obvious ones are setters that return a value. (In the order example with adds an order line to the order and returns the order.) The common convention in the curly brace world is that modifier methods are void, which I like because it follows the principle of CommandQuerySeparation. This convention does get in the way of a fluent interface, so I'm inclined to suspend the convention for this case.
You should choose your return type based on what you need to continue fluent action. JMock makes a big point of moving its types depending on what's likely to be needed next. One of the nice benefits of this style is that method completion (intellisense) helps tell you what to type next - rather like a wizard in the IDE. In general I find dynamic languages work better for DSLs since they tend to have a less cluttered syntax. Using method completion, however, is a plus for static languages.
One of the problems of methods in a fluent interface is that they don't make much sense on their own. Looking at a method browser of method by method documentation doesn't show much sense to with. Indeed sitting there on its own I'd argue that it's a badly named method that doesn't communicate its intent at all well. It's only in the context of the fluent action that it shows its strengths. One way around this may be to use builder objects that are only used in this context.
One thing that Eric mentioned was that so far he's used, and seen, fluent interfaces mostly around configurations of value objects. Value objects don't have domain-meaningful identity so you can make them and throw them away easily. So the fluency rides on making new values out of old values.
I haven't seen a lot of fluent interfaces out there yet, so I conclude that we don't know much about their strengths and weaknesses. So any exhortations to use them can only be preliminary - however I do think they are ripe for more experimentation.
Extreme Programming Core Practices
The 12 “XP Xtudes” (Xtude is XP means ‘Attitude’) of Extreme Programming (XP) grouped into four categories
1. Fine Scale feedback
XP thrives on providing feedback at smaller intervals with higher frequency. This allows controlling deviation at the right time, since in software or any othe industry for that matter, once deviation starts happening it is dificult to control at the later stages.
- Test Driven Development via Programmer Tests (Unit Tests) and Customer Tests (Acceptance Tests/Automation Tests)
- Planning Game (Definition Iteration Objectives and playfield etc)
- Whole Team (Onsite Customer + Programmer + Quality Team + Customer Team + Scrum Master + Product Owner)
- Pair Programming ( two engineers participate in one development effort at one workstation)
2. Continuous Process rather than Batch
- Continuous Integration (Integrate Continuosly and keep the check using Nightly Builds)
- Design Improvement (Refactor Mercilessly)
- Small Releases (Release Often)
4. Programmer welfare
YAGNI
"You Arent Gonna Need It" (often abbreviated YAGNI) is an Extreme Programming (XP)practice which states:
"Always implement things when you actually need them, never when you just foresee that you need them."Even if you're totally, totally, totally sure that you'll need a feature later on, don't implement it now. Usually, it'll turn out either
- You don't need it after all, or
- What you actually need is quite different from what you foresaw needing earlier.
This doesn't mean you should avoid building flexibility into your code. It means you shouldn't overengineer something based on what you think you might need later on. There are two main reasons to practise YagNi:
- You save time, because you avoid writing code that you turn out not to need.
- Your code is better, because you avoid polluting it with 'guesses' that turn out to be more or less wrong but stick around anyway.
A scenario that explains the practices:
You're working on some class. You have just added some functionality that you need. You realize that you are going to need some other bit of functionality. If you don't need it now, don't add it now. Why not?
But unless your universe is very different from mine, you can't 'save' time by doing the work now, unless it will take more time to do it later than it will to do now. So you are saying:
"OK, Mohan, why do you want to add it now?"
"Well, Rahul, it will save time later."
But unless your project is very different from mine, you already have too much to do right now. Doing more now is a very bad thing when you already have too much to do.
"We will be able to do less work overall, at the cost of doing more work now."
And unless your mind is very different from mine, there is a high chance that you won't need it after all, or that you'll need to rewrite or fix it once you do need it. If either of these happens, not only will you waste time overall, you will prevent yourself from adding things that you do need right now.
Keep it simple. If you need it, you can put it in later. If you don't need it, you won't have to do the work at all. Take that day off.
"But Rahul, I know how to do it right now, and later I might not."
"So, Mohan, you're telling me that this class you're writing is so complex that even you won't be able to maintain it?"
YAGNI in the context of the other Extreme Programming practices
You have a Release Plan: each User Story has been assigned to an Iteration where it will be done. Under the current Iteration Plan, you are working on an Engineering Task that you signed up for, in support of one of the Iteration's User Stories. As always, you have signed up for as much Ideal Programming Time as your Load Factor indicates you can accomplish.
You are evolving the system to have the new functionality required by the User Story, defined in the Engineering Task. You add capability to any class we need to, directly growing from the requirement. If you find yourself writing duplicate code, you refactor to eliminate it, even (perhaps) adding an abstract class, or making a subclass, etc. You and your co-programmers always keep the code clean.
You're building a class, and suddenly you get an idea for a feature you could add to it. You don't need it right now, but "Someday we're gonna need ...", you say to yourself.
Keep in mind that you are employing other Extreme Programming practices that allow you to deal with the future when it happens. Collective Code Ownership allows you to change anybody else's code to give it the functionality you want. Refactor Mercilessly and Once And Only Once make it easier to understand the best way to add your functionality. Unit Tests help ensure that your added functionality won't break any past functionality. So if you do need to implement this feature in the future, it probably won't be much harder than it would be to implement now.
At this moment, you have a choice: continue working on what you signed up to do, or begin working on something you didn't sign up to do, and that isn't needed in this Iteration.
Therefore, tell yourself YAGNI. Set aside your thoughts and fears about tomorrow and get back to work on today. Without a clear use for the feature, you don't know enough about what is really needed. Spending time on it is speculative at best.