March 30, 2011

...Learn TDD with Codemanship

Visual Models Are Useful, Especially In Those Early Stages

I've been thrown back into the world of teaching UML today running a 2-day workshop in Agile Design for the nice folks at BBC News & Knowledge.

The first point I wanted to make to them was that, although we'd be using some UML notations in the workshop - and to some extent the point of the workshop was to learn these basic notations - we shouldn't fall into any of the bear traps that have been set for the unwary visual modeler.

Trap #1 is that "Design = UML". I've worked with people who claimed that "our developers don't do any design" because they didn't produce evidence in the shape of UML diagrams. This is nonsense. If the developers genuinely did "no design", then their code would just be random characters. The fact that their code compiles, has a shape, and isn't just random ASCII noise suggests that someone, somewhere made some design decisions. Yes, proponents of Intelligent Design will be delighted to learn that code that compiles, works and makes some kind of sense displays compelling evidence of the influence of an intelligent designer.

I'm not a great believer in using models to justify design decisions. In my experience, if a tree falls in the forest but there's no class diagram to document it, the tree does make a sound. Good design is good design, with or without the necessary paperwork.

Trap #2 is the perennial misconception of young and inexperienced Agilistas everywhere: "UML = Big Design Up-Front". This is as misguided as believing that "Ruby = BDD". It's true that the UML user community has earned a reputation for BDUF. But then, the C++ community earned a reputation for premature optimisation. C++ does not require us to optimise early, nor Ruby to write acceptance tests up-front. And UML is just a language, like Ruby and C++. You can be as agile as you like. Do as much or as little up-front design as you want. Go into as much or as little detail as you need. My advice has always been "if a diagram helps, use one".

Trap #3 is kind of related to the first 2 traps, and is potentially the most lethal: "UML is a design process". Meaning that folk learn on a course like this one to follow a certain thought process, and mistake a sequence of UML diagrams for that thought process. So, even if they know what code they're going to write, they draw the diagrams anyway. "Good design is a use case model followed by some sequence diagrams followed by some class diagrams". No, good design is good design. The evidence for good design is in your software. Use a UML diagram (or a Venn diagram, or a Mind map - whatever tells the story best) if and only if you think it'll help you understand something better or communicate something better to other people in your team.

The BBC N&K folk are a smart bunch, and I think they've steered their way through the bear traps quite impressively. I'll be surprised if they go back and say "so when you pick up a user story, draw one of these diagrams and then one of these diagrams and then one of these diagrams before you write any code".

The modus operandi in the workshop, my first using UML in anger for several years, is that everyone works as one team, but split into pairs/threes and each pair is working on one user story for a community video library application. So one pair is working on "As a video club member, I want to donate a DVD" while another is working on "As a video club member, I want to borrow a DVD". All this is happening in parallel. You know how clumsy and awrkward it can be when teams start work on a new application. We tend to trip over each other's feet as we work on the same core classes to implement our part of the functional puzzle. I watched a team of similar size working for a large and reputable Agile development shop end up with several architectures and different versions of the same objects on the code because they didn't collaborate and co-ordinate anywhere near enough over design in those early stages.

The N&K folks each did some modeling to figure out what objects were involved in their scenario (defined as an acceptance test in the popular "given... when.. then..." style), what each object was doing and how the objects were collaborating to complete the work - and therefore pass the acceptance test. They only modeled what they needed for that test. And then they automated their acceptance test and wrote the code based on - but not blindly following - their high-level designs.

Some of the pairs discovered as they coded that their models were not quite what they needed, and new features emerged from that feedback. At this point, their code was the definitive model, and that model was evolving. And I didn't make them update their diagrams. Shock, horror!

Refactoring also helped the model - in the code - to evolve. For example, I spotted a for.. loop in one acceptance test (which we wrote in JUnit because we were just working on the "back end" on day #1 - UI tomorrow) which displayed feature envy for one of the model classes. So they extracted that block of code into a method and moved it on to the model class.

4 pairs co-ordinating around a handful of classes to implement 4 different scenarios, and working code passing their acceptance tests by the end of the first day. I've seen it work well, and I've seen some train wrecks. And I've noticed that visual modeling - be it using UML diagrams or whatever - is a factor in deciding that outcome. Making your thinking visible, especially in those early stages of design when we know the least and the team hasn't established a shared language for the thing they're building, helps. It really does.

I'm looking forward to adding user interfaces to these back ends to see whether, when we join all the MVC dots, we end up with the software we wanted.

Posted 2 weeks, 5 days ago on March 30, 2011