This is a mild rewrite of an old blog post of mine from 2005 that I think is still relevant today. While this was originally about pair programming, I’ve tried to rewrite this to be more about working collaboratively in general.
My shop is having some constructive internal discussions about our development process and practices. While I don’t think that Pair Programming is likely to be a big part of our daily routine, I think we could still use a bigger dose of collective ownership in our various code base’s and less silo-ing of developers. Since I’m a typical introverted developer who doesn’t handle hours of pair programming and I don’t think my attitude is uncommon at all, we need to look for ways to get the same type of shared understanding that you would get from 100% paired programming.
One of my suggestions is at a minimum to stop assigning coding stories to a single developer. Even if they aren’t pair programming all the time, they can still collaborate on the approach and split tasks so they can code in parallel. On one hand this should increase our team’s shared understanding of the codebase, and on the other hand it’ll definitely help us work discrete stories serially to completion instead of having so many half-done stories laying around at any one time.
“This is the Way We Do It”
My favorite metaphor for software design these days is a fishing tackle box. I want a place for everything and everything in its place. When I need a top water lure, I know exactly where to look. I put data access code here, business logic there, and hook the two things up like this. When I’m creating new code I want to organize it along a predictable structure that anyone else on the project will instantly recognize. When other coders are making changes I want them to follow the same basic organization so I can find and understand their code later.
Each application is a little bit different so the application’s design is always going to vary. In any agile project you should hit an inflection point in the team’s velocity that I think of as the “This is the Way We Do It” moment. Things become smoother. There are fewer surprises. Story estimates become more consistent and accurate. When any pair starts a new story, they understand the general pattern of the system structure and can make the mechanical implementation with minimal fuss.
You really want to get to this point as soon as you can. There are two separate issues to address before you can reach this inflection point:
- Determining the pattern and architecture for the system under development
- Socializing the design throughout the development team
To the first point, pairing allows you bring to bear the knowledge and experience of everybody on the team to the work at hand. It’s just not possible for any one developer to understand every technology and design pattern in the world. By having every developer active in the project design, you can often work out a workable approach faster than a solo architect ever could. On the one project I’ve done with theoretical 100% pairing, we had a couple of developers with a lot of heavy client experience and me with more backend and web development experience. By pairing together with our disparate knowledge we could rapidly create a workable general design strategy for the system as a whole by bringing a wider skill set to any coding task.
Right now I’m working some with a system that’s being built by two different teams that work in two very different ways with very different levels of understanding of some of the core architecture. That’s really not an ideal situation and it’s causing plenty of grumbling. There’s a couple specific subsystems that generate complaints about their usability. In one case it just needs to be a full redesign, but that really needs to take place with more than one or two people involved. In the other case, the problems might be from the team that didn’t build the subsystem not understanding how it works and why it was built that way — or it might be because the remaining developer who worked on it doesn’t completely understand the problems that the other team is having. Regardless of what the actual problem is, more active collaboration between the teams might help that subsystem be more usable.
If you’re a senior developer or the technical lead, one of your responsibilities is fostering an understanding of the technical direction to the other developers. Nothing else I’ve ever done as a lead (design sessions, documentation, presentations, “do this,” etc.) beats working shoulder to shoulder with other developers as a mechanism for creating a shared understanding of the project strategy. By making every developer be involved or at least exposed to the thinking behind the design, they’ll have much more contextual information about the design.
We have a great policy of doing internal brown bag presentations at our development office and it’s giving our guys a lot more experience in presentation skills and opportunities to learn about new tools and techniques along the way. While I’d like to see that continue and I like learning about programming languages we don’t yet use, I also think our teams should probably speak about their own work much more often to try to create better shared understanding of the architectures and code structures that they use every day.
Part of any explanation or knowledge sharing about your system’s architecture, structure, and build processes needs to include a discussion of why you’ve chosen or arrived at that architecture. One unpleasant fact I’ve discovered over and over again is that the more detailed instructions you give to another developer, the worse the code is that comes back to you. I simply can’t do the thinking for someone else, especially if I’m trying to do all the thinking upfront independently of the feedback you’d naturally get from working through the problem at hand. If the developer doing the work understands the “why” of your design or instructions, they’ll often do a better job and make improvements as they go — and that’s especially important if you gave out instructions that turn out to be the wrong approach and they should really do something different altogether.
For example, I’ve spent the last couple years learning where some of the more rarely used cooking utensils and gadgets in our kitchen go. Instead of trying to memorize where each thing I find unloading the dishwasher goes, my wife has explained her rationale for how the kitchen is organized and I’m somewhat able to get things put up in the right place now. Organizing code isn’t all that different.
Improving Our Code vs. Defensiveness about My Code
Don’t for one second discount the psychological advantages of pair programming or even just a more collaborative coding process. Formal or even just peer code reviews can be nasty affairs. They can often amount to a divide between the prosecution and the accused. In my admittedly limited experience, they’ve been largely blown off or devolve into meaningless compliance checks with coding style standards. Even worse is the fact that they are generally used as a gating process just prior to the next stage of the waterfall, eliminating the usefulness because it’s too late to make any kind of big change.
The collective ownership achieved with pair programming can turn this situation on its head. My peers and I can now start to talk about how to improve our code instead of being defensive or sensitive to criticism about my code. Since we’ve all got visibility now into the majority of the code, we can have informed conversations about the technical direction overall. The in depth code review happens in real time, so problems are caught sooner. Add in the shifting of different coders through different areas of the code and you end up with more eyes on any important piece of code. The ability to be self-critical about existing code, without feeling defensive, helps to continuously improve the system design and code. I think this is one of the primary ways in which agile development can lead to a better, more pleasant workplace.