Some years ago at a prior employer I had the luxury of working with a team delivering a large green-field Java & Oracle project. The requirements were complex and the interfaces, APIs and business logic all needed some pretty exotic thinking to make everything work.
Prior to that project we’d delivered plenty of relatively simple work and been through requirements, design, code, unit test, integration, system test, documentation etc many times. We were generally a “pretty good” team.
We hired a new member – a very experienced and hands-on architect. He brought a whole load of knowledge we were looking for to the team and more…
After being on board about 2 weeks he called a meeting with the entire team. Hauled us into a room and pointed out just how poor we were at proper design. Moreover he took control of the situation, developed a series of design spec templates, guidance and examples, got the team fully ramped up on UML, capturing design decisions, practices, patterns – the works.
Using our new design knowledge and tools, we moved onto the first critical phase of our green-field project in 2 groups.
Group 1 had to get a working proof of concept to the customer in a matter of weeks, group 2 needed to start designing the way more complex second round of features.
For group 1 (a small pilot team of 2), one of the team did about a week’s research, wrote up the basics and hit the ground running (no real design). Group 2 were not allowed to touch a line of code until the designs were complete!
From memory, start to finish; that first phase took about 3 months.
After the initial work was completed, both groups 1 & 2 progressed onto the next round of features based on the design efforts group 2 had completed.
After about 2 weeks we realized we were having to sacrifice one of the team (our feature lead!) almost full-time to maintain the designs. Coding was completed in a total of about 6 weeks. The fastest coding turnaround we’d ever had for something of this scale and the functionality was way harder than the first round of work.
After our crash-course in the pain of full-on software design, our architect reconvened the team to lead a design practices brainstorming session.
“OK, now you know how to do proper software design; of the tools, practices and documents you used, which do you want to keep and which do you want to ditch?”
Our management seemed to have had the foresight to allow our architect this social experiment knowing full-well that the net result would be a major overall team improvement (the same manager also helped us develop successful business cases for major refactoring efforts – a pretty forward thinking guy).
So what did we keep and what was our philosophy?
The greatest value in design after the fact is not in what was implemented but why we chose to do it that way (and why not another way).
The second greatest value in design after the fact is for team members (especially new joiners or maintainers) to get a foothold into the codebase and be able to navigate around safely.
With these cornerstones in mind we kept a few things…
1: High level architecture – a verbal or pictorial summary of the general concept and approach. Often just a photo of some legible whiteboard sketches. - our first foothold
2: Top level flow – a sequence diagram defining the overall flow of responsibility between actors. - our main ”ladder”into the codebase.
3: Design decisions and rejections. (in a wiki/threaded discussion) – why did we choose to do things and why did we chose not to do others. – since learning the “why & why not” approach we saved days of ramp-up and maintenance pain on projects.
4: Complex algorithm annotations – for the really gnarly bits. (Avoid this where possible) – draw pictures for these where you can.
5: Public interfaces – as peer and tech-author-reviewed Javadoc post-implementation. I like public interfaces - they’re a great long-term commitment to communicate in a given stable way. In this case they were also a commitment to our customer. Doing a decent job on these saved a world of support pain later.
6: Unit & functional tests - yes, these are design too!
That’s it! – we ditched a whole world of class diagram hell and parameter definitions. We could still sketch out basic class diagrams when needed but not the level of depth needed to generate code from a CASE tool. We ditched all the noise and blurb and we made it clear why the product was written and behaved the way it did.
So – give your teams an easy leg-up into your code and then explain why it does things rather than telling people what it should do.