This is an HTML rendering of a working paper draft that led to a publication. The publication should always be cited in preference to this draft using the following reference:
Robert C. Martin
Agile Software Development: Principles, Patterns, and Practices
Prentice Hall, Upper Saddle River, NJ. 2003
Agile software development can be described as an uprising against the tyranny of excessively structured software processes. According to its manifesto, it values individuals and interaction over processes and tools; working software over comprehensive documentation; customer collaboration over contract negotiation; and response to change over a strict adherence to a plan. The importance that agile software development principles place on fluid and fleeting parts of the development process, like human interactions, changing requirements, working software, and customer satisfaction make one wonder how these aspects can be documented and communicated in a concrete way to software professionals looking for hands-on advice. Robert C. Martin (Uncle Bob, as he is affectionately known in the object-oriented programmer community), succeeds brilliantly in this task, no doubt thanks to his more than 30 years of software development experience.The book can be roughly divided into three parts. The first, titled “Agile Development”, provides an overview of the Agile Alliance and the Extreme Programming (XP) practices. Separate chapters deal with the most important elements of agile development: planning, testing, and refactoring. The part ends with a case study of a bowling game score calculator, developed following the XP practices. Interestingly, the case study is presented in the form of a dialogue between the author and a colleague, working as a pair-programming team. We are thus able to witness programmer interactions, design, mistakes, testing, refactoring, and coding as the project evolves toward its final form. The book’s second part deals with agile design. Agile software development practices abhor grand and detailed designs before a single line of code is written, advocating instead always having the code comprising the system structured in the best possible way. Martin, taking the lead from an article by Jack Reeves provided in an appendix, argues convincingly that the only software documentation that actually satisfies the criteria of engineering design, as most disciplines understand it, is the system’s source code. To improve a software project’s design one has to recognize symptoms of poor design: rigidity, fragility, needless complexity and repetition, immobility, viscosity, and opacity. Martin illustrates five important principles of agile design using code examples and clear UML diagrams. Two principles guide a system’s composition into separate entities: the single responsibility principle states that classes should always have only one reason to change, while the open-closed principle has software entities, such as classes, packages, and functions, be open for extension, but closed for modification. The three other principles concern the composition of a system’s entities: the Liskov substitution principle declares that subtypes must be substitutable for their base types; the interface-segregation principle states that clients should not be forced to depend on methods they do not use. The dependency-inversion principle can be read in two different ways: high-level modules should not depend on lower-level modules, or abstractions should not depend on details. The book’s last part illustrates the coding practices of agile development by means of three case studies: a payroll system, a weather station, and excerpts from a real-life project, the automation of an educational testing service. Each of the three allows Martin to examine different aspects of software development using agile methods: data-driven systems, embedded systems, and lifecycle issues. More importantly, the case studies are used as a backdrop for illustrating important design patterns. The pattern names can be bewildering: command, active object, template method, strategy, facade, mediator, singleton, monostate, null object, factory, composite, observer, abstract server, adapter, bridge, proxy, stairway to heaven, visitor, state. However, any experienced developer working on object-oriented artifacts will, deliberately or by accident, have used or encountered at least one of them. Interweaving the pattern descriptions with the development of the actual code makes learning the patterns a pleasure. Traditionally organized design pattern catalogues are useful, but can be tiresome to read. I readily admit that I never succeeded in completing more than a couple of chapters in a single “pattern-catalogue” reading session; with Martin’s exposition I found myself having gone through more than five patterns before I could leave the book down. The book is choke-full of UML diagrams illustrating design principles and patterns. For those not yet well versed in the UML notation, two to-the-point appendices describing the most important diagram elements are there to bring them up to speed. On the other hand, all readers will benefit from seeing UML used in the context of concrete case studies together with code; some nitpickers may wonder why a generalization instead of a realization relationship is sometimes used to denote the implementation of an interface, or a navigable association relationship is used in places one would expect to see a dependency. None of these problems however obfuscates the presentation or distracts the reader. The only important shortcoming of the book is its presentation. A small text font laid as a single column on an unusually wide page makes following the lines a challenge. Then again, the wide pages allow the faithful presentation of the numerous C++ and Java code samples and UML diagrams. Agile software development favors working software over comprehensive documentation, so the decision to make space for the code appears to follow the book’s spirit.