Many years ago I worked on code that integrated tightly with 3rd party software. The APIs were not always documented, and when they were, the documentation sometimes had omissions or was just plain wrong. In a situation like this, what to do?
Management’s idea was to involve experts, people who were already familiar with the 3rd party software, in fact some had worked for the company that made it had a hand in creating it. However, the software was vast and nobody could understand more than a fraction of it. Once again, QA could only test the basics during development, thorough testing would have to wait until just before release. And that’s when we’d discover that our current design wouldn’t work and would need significant revision.
Lesson learned: When there are lots of things you can’t know, iterative development is the key to validating designs and getting a predictable schedule as soon as possible. It’s more important to get something working and testable first, then refine it, than it is to build it “production quality” from the start.
At another job, the team would divide up each project into independent components, and have each person work on a different component. We’d intend to do design reviews, and sometimes even do them. Then, after a few weeks, when it was time for a code review, someone would often point out a simpler way to achieve the same goal, or where more defensive programming was needed throughout the work. Only now it was a lot more work to change it. In other words, each part is exposed to the entire genius and foibles of the individual programmer who worked on it.
So we kept saying we needed more reviews and tried various things to encourage that. The problem is, when developers had a choice of working on their own code or going over someone else’s, they usually chose their own. That’s the task that was on the backlog that everybody else was tracking. Interrupting a co-worker to say “can you show me what’s changed since the last time I stopped by?” felt unusual.
The one thing that worked — and worked well — was for people to trade off tasks that lasted around a day. That way, I need to understand the code you wrote yesterday since I’m modifying it today. Plus, your change probably touched code that I’ve worked on and have opinions on. And discussing those opinions is exactly what we needed.
Lesson learned: It’s important to have multiple developers thinking about the details, and it’s really hard to thoroughly consider the details of something you’re not working on. So explicitly resist developers urge to work on independent parts of a system. Instead, assign people interdependent tasks that each take around a day.
None of this replaces good coding practices such as always checking return values (even if with just an assert), automated tests, readable code, etc. In fact, it’s designed to encourage those, to encourage people to share such best practices early and often.