Just some things that are percolating in my head this morning on the train ride to work that just won't make a real post. I write some posts for my readers, and some posts just to compose my thoughts. This is definitely the latter.
Create Knowledge Together
Yesterday I had a meeting where the client's lead and I started laying out some design ideas and approaches to other members of the team. The meeting ended up being almost a near rehash of the exact same conversations that the client lead and I had already had over the past week and I think that it flustered him a little bit. My thought was that we really should have had those conversations with a broader swathe of the team in the first place — and will from here on out. You create a lot of knowledge in a software project, especially in the early stages of the project. It's never enough just to create that knowledge, you also have to transfer that knowledge somehow to the rest of the team. Knowledge transfer is most effective when the "why" behind a decision is also communicated.
There's a bit of danger in having only the senior most guy(s) or gal(s) do the heavy thinking in isolation for too long. It may seem like it's more efficient to keep the other developers working on other things while your senior most person is working solo to prepare the field, but many times it's more productive in the end to have more developers involved in the knowledge creation early to cut down on the overhead of communication later. The hardest part of leading design efforts to me is the communication aspect, not the design itself. I distinctly remember being very frustrated on my first lead assignment because I had everything thought out in my head, but I just couldn't get that vision across to my team. The end result was that I wrote maybe 90% of the initial code on a 4-5 developer team. If the other developers had been involved earlier, and I had done much more collaborative design, I bet that 90% figure would have been much lower and we would have finished with much less overtime.
I'm largely an introvert, so one of the hardest things for me on software teams is trying to think out load and do design collaboratively with other team members (I have some serious problems trying to pair with extremely extroverted people. I'm always tempted to just scream "shut up and let me think in peace!"). The sweet siren call of going headphones down and cranking out code has to be defied. Besides, that's what side projects are for.
Reduce Communication Latency
Communication, and the overhead and "lossiness" of communication, is a massive cost in any nontrivial software project. You have more latency and "lossiness" in your communication with more relays in information between people, lower fidelity mechanisms for communication, and temporal displacement of the communication. Think about that last part. What's easier for you to explain to a team member, code you wrote yesterday versus code that you wrote three months ago?
It's definitely a factor that the business folks don't properly account for when they're weighing the cost savings from offshoring. Sequential lifecycles with lots of specialization in the team are the absolute worst. I've seen too many projects fumble handoffs between analysts, developers, and testers. A strictly sequential cycle can be a killer because the different people on a project are coming onto a project at completely different times. Every successive batch of people on the project have to learn about the project before they can begin. In my experience, waterfall testers are often slow to pick up the pace of testing at first because they're not familiar with the new functionality yet. Big teams of specialists that are working on multiple projects simultaneously have extra burdens from the sheer number of people who need to communicate and the context switching between different assignments.
I want my teams to cut down on communication latency by:
- Having everybody work on the project at the same time
- Analysts may be a little ahead, but have developers and testers start working on a feature at the exact same time with a common understanding. Both to cut down on fights over different interpretations of the requirements, and to make sure the tester knows exactly how to test a feature the second it's finished and the developer knows the tester's expectations.
- Involve fewer people in the project. Fewer people means less latency because there are fewer communication "hops." Shrink the team by eliminating specialization roles as much as possible. Whatever you do, strive for an organization where most of your people are focused on one project at a time. I've never seen a "multi-tasking" organization that didn't flat out suck.
- Face to face communication is a vastly better way to convey understanding and create a common vision than all the paperwork in the world ever will. To me, documentation is only valuable for it's durability. Documentation is largely for the people who come next and people outside your team. Don't depend on it for communication between your team.
What about Tomorrow?
As a consultant I hear plenty of very understandable concern for what happens after I leave the project. Mostly it's a cry for effective documentation so somebody else can understand the system after we're gone. I do want to leave a system and environment that is maintainable, but I'm not really a believer in much traditional documentation. It might come down to differing paranoia's. I'm always more worried about the overhead of creating documentation because I don't believe it's valuable for the creation of software. I'm especially concerned about creating documentation that quickly becomes out of date and needs to be either thrown out or updated. That's just waste. I definitely don't want any incentive to carry out a bad design just because it's too much work to change the formal documentation. Some of the folks at my client are more concerned about getting a system that they can't make heads or tails out of. I think we'll be about to easily meet in the middle. Without further ado, here's my recipe for what *I* want when I have to take over somebody else's code (and I've never, ever gotten):
- Just really good code. If I could have anything, and only one thing, it would be well written, well factored, clean, intention revealing code. Everything else is just trying to sprinkle on some heavy spices to disguise the fact that your code smells like rotten meat. I took over a system from some consultants that had fabulous documentation (it was definitely a cost reimbursable contract), but had terrible code. We had to toss out the system, and it was hard to support anyway because of the architecture. I'd also consider very high unit test coverage to be very valuable. I find systems with a great deal of unit test coverage to be much easier to deal with, both because of the unit tests themselves and also because the code tends to have better than average separation of concerns.
- A project Wiki that can act as a great starting point to everything else, and it's relatively easy to keep up to date compared to other medium. Now what's on that Wiki? I'll stick up a 2-3 page paper describing the key element of the system and a handful of UML diagrams just to act as a roadmap to the system. I want another page that details the configuration management practices for the project. Where is the code repository, how do I build the system, and how is it deployed?
- Comprehensive build automation. I want a brand new team member to be able to follow a couple steps in a Wiki page to set up his system, checkout the code, and use the build script to be up and running in under an hour. Give me a good story for build automation to setup the development environment, and that goes a long, long way towards being able to work with someone else's code. I don't want to have to scan a word document looking for the legacy COM component that has to be registered on some out of the way place. I want the build script to do it for me and get going.
- Use acceptance tests, and especially executable specifications, as the real detailed documentation. Don't create a document that a tester can then use to create a test plan. Go straight to an acceptance test, keep it human readable, and then see if you can automate that test and stick it in an automated test suite that's run at least every night. Make your acceptance tests a requirement that "bites back" when the system doesn't meet the requirement. <PROMOTION>Come to DevTeach and one of my talks is on this very subject.</PROMOTION>
- Try really hard to use common tools and common patterns. Frankly, try to make Addison Wessely and Manning do as much of your documentation work as possible. A major advantage of using off the shelf tools, and I'm counting OSS tools here too, is that documentation and knowledge exists for these tools already. Writing your own O/R Mapper is going to be harder to maintain. My current project is going to be using the Passive View variant of MVP. Granted, I don't think it's that common in .Net circles outside the blogosphere yet, but I can point the Wiki right to www.martinfowler.com and give quite a bit of background on our design choices and philosophy. I am thinking very seriously about building and using an alternative to Data Binding in WinForms, and if we do end up going down that path, I'll have to document that somewhat. A lot of people blow off design patterns as just "something I do without that silly jargon," but that silly jargon can be an effective way of communicating quite a bit of information about a solution in a little packet of information. <RANT>If you haven't already, go learn about using Design Patterns</RANT>
Something important that I wanted to call out was the desire for moving documentation closer to the code and even trying to create mechanisms to ensure that the documentation is synchronized with the code. The Don't Repeat Yourself principle should be applied to documentation as well. I actually count things like a NAnt script, unit tests, and FIT tests as a very effective form of documentation – that can't get out of synch with the code as long as they're being executed regularly.
Good Practices aren't just a Strategic Advantage
Good practices like unit testing and build automation shouldn't just be looked at as a strategic enabler of the long term goals. Good practices can be made a tactical advantage in getting your day to day work done. More importantly, find a way to apply good practices in a way that makes you more productive.