XpdWiki
Set your name in
UserPreferences Edit this page Referenced by
JSPWiki v2.0.52
![]() ![]() |
An approach designed to provide the benefits of TestFirstDesign without needing to write unit tests. You might need this if you plan to do AcceptanceTestOnlyDevelopment. A brief history of software designHere are some schools of thought on design, in rough chronological order.
Why does TestFirstDesign work so well?The empirical evidence for TestFirstDesign is overwhelming: most people seem to report a very good effect on their designs. Sadly, I haven't seen much in the way of theorising why this is. So I will have a try. My view is that it combines the strengths of two previous approaches: the first two I list above. Top-down functional decomposition, done properly, is very good at coding by intent. This makes code inherently readable locally and is good at preventing bloat by overdesign. Sadly, it's weaknesses are also well-known and few people want to return to it now. The lack of a conceptual element means that cohesion suffers sooner or later and the lack of information hiding means that large systems become hard to manage and understand. The object-oriented revolution took us onto a new plane in this way: but in solving the weaknesses of the previous approach it also abandoned its stengths to a large extent. The up-front design phase brought in big, unwieldy designs and designers out of touch with the reality of how the design is implemented. This produced bloated systems where the coding was less by today's intent and more strait-jacketed by last year's UML diagram. TestFirstDesign works, quite simply, because it is both object-oriented and usage-driven. But is the test part really necessary for a good design?Seen as a design process only (i.e. assuming we can get the other benefits of unit testing elsewhere), the TestFirstDesign process is simply writing artificial usage code while aiming at previously designed concepts. If I'm planning to design the Movie class, I first have a brief think about broadly what concept I'm aiming at (maybe with a brief whiteboard design session), then I make up a usage for a Movie (a unit test), and only when that's in place do I write the Movie, implementing as I do so only what's necessary to satisfy the usage I just made up. Then I implement the "real usage code" by writing the code in the system for which my new class is actually intended. An obvious shortcut version, if you get your tests elsewhere via AcceptanceTests, is to drive the design from the real usage instead of creating a made-up one first. While keeping the other steps, particularly the conceptual class design at the start. A year of doing this ("Usage First Design") has led me to be pretty happy with the results. It is impossible to know empirically what would have happened with TestFirstDesign, but I certainly observe high cohesion and loose coupling. In fact, it now becomes rather obvious when we work with parts of the system that were designed before we started doing this. One possible objection is that, because TestFirstDesign always provides two usages of the class concerned (the real one and the unit-test one), you automatically make every class reusable. In response I would say that that sounds very much against the spirit of XP: design effort invested up-front in the hope of a later pay-off. It also seems to me that there is a risk that the artificial usage which drives the design ends up not corresponding very well to the real usage, and this seems to be a hard problem to correct. Of course there is only anecdotal evidence for this, but AndrewSwan? seemed to think it was a real problem when I discussed with him at XP2003, and he seems to have done lots of unit testing. This is where I think UsageFirstDesign might actually improve on TestFirstDesign (apart from being simpler). -- GeoffBache (though credit for most of the ideas here must go to JohanAndersson?)
|