OO as a Prerequisite to Agile
A few comments (and tweets) have popped up, not in response to the main point from my last post (Scrum != Agile), but rather from my saying that many people thought that OO was dead (or as one writer pointed out, wished it were dead). So, let's talk about that.
There are two main camps when it comes to defining OO: structural (if it uses polymorphism and inheritance, it's object oriented) and architectural (OO systems are models of real or imaginary things and of the way that these things interact as they perform some useful activity). I fall firmly in the second camp; structure is an important implementation detail, but doesn't affect the object-oriented nature of the system one iota. I've even programmed what I think of as object-oriented systems in assembly language, with nary a class definition or virtual method in sight.
The objections to OO come largely from people so entrenched in the first camp that they don't know that the second camp exists. For example, they say that Java is too complicated and wordy which is certainly true therefore OO is bad which is not. They say that Java is too hard to deploy also true therefore OO is bad. They say that design patterns can add too much complexity to what should be a simple system again, true, but that's a good-versus-bad design argument, not a critique of OO. They say that it's sometimes best to program with functional-programming techniques instead of inheritance also true, but functional programming in no way renders the system less object oriented.
The real issue is the benefit of a model-driven approach, whether or not you call that approach OO. I've better things to do with my time than argue semantics.
The fact is that, if you don't take a model-driven OO approach to architecture and also leverage some of the natural consequences of that approach (such as hard-core data abstraction), you will fail at Agile (or at minimum, waste an awful lot of time). The constant change that all Agile processes mandate puts too much stress on the code to leave room for sloppiness; and a model-driven approach to design meshes nicely with Agile's focus on stories. The structure of the code just falls out of the stories, with little or no work.
There are two main issues:
First, the system should model your customer's thinking: The main classes, objects, and interactions in your system should be obvious (and readable) to anybody with domain knowledge. For example, a payment system should have classes like
You may send a
This domain-based organization is an essential element of agility, because it's the domain-level things that change with every story. When that happens, you need to quickly identify and modify the associated code. If the domain and the system architecture don't march in lock step, even trivial changes will be unnecessarily difficult; so difficult in fact, that you can't finish them on a truly Agile schedule. That point applies even when the code isn't changing. It's a lot easer to verify that a story is implemented correctly when there's a close connection between the words in the story itself and the implementation. That is, without a domain-based model, your T/BDD tests will be little more than simple unit tests.
There is a learning curve, here. It takes a week-long full-day hands-on class for me to teach the basics to a bunch of smart programmers, and at least a month or two for them to get any good at it, but this is something you can learn. This sort of design is also very collaborative. Customers, business people, and programmers really do have to work together to pull it off. If you're doing some sort of pseudo-Agile process where you don't have access to real customers or business people (and a Scrum Product Owner isn't either), you can't do it.
The second issue is the "natural consequences" of OO modeling: implementation hiding and hard-core data abstraction. The implementation of an "object" has to be opaque. My test for that is the eponymous "Holub Substitution Principle (HSP): It should be possible to completely change the implementation of an object without the clients of that object knowing that the change has happened. You should be able to add, remove, or modify any or all of the fields in an object, replace all the non-public methods of the object, and completely replace all the implementations of the public methods. As long as the public interface hasn't changed, the users of the object shouldn't know or care that a change has happened. This principle extends to any sort of modularized system, not just OO classes and objects.
In an Agile world, following HSP gives you the freedom of changing implementation without the effects of that change rippling out to the rest of the program, and this property is, again, essential when constant change is in the picture. I've written about one aspect of HSP accessor and mutator methods extensively. (See Saying No To Properties, for example.)
Interestingly, when you implement a model that reflects the domain, you end up with code that implements HSP. Unnecessary
get/set methods, for example, are not interactions that exist in most domains, so the associated methods don't end up in the code. If you work outwards from a badly designed vendor-supplied library (that requires
get/set methods, for example) instead of inwards from the model, you'll get it wrong.
Finally, none of this OO structure mandates that system be heavyweight, highly complex, or written in any particular language; but if you don't adhere to these principles, your code quickly collapses under the weight of the constant change that's part and parcel of working in an Agile way.