How can I convince my team to adopt TDD? How do I convince my manager that we should do pair programming? How do I convince the business that we should invest in continuous integration?
Those are questions we normally get everywhere we go to talk about software craftsmanship. One of the biggest mistakes we make as developers is to think that adopting certain practices is a goal that all teams and organizations should have. Technical practices and methodologies are a means to an end, not a goal on their own. They are the “how,” not the “why.”
Before pushing a practice or methodology to a team or organization, we should make sure that everyone understands the problem we are trying to solve- the “why.” Let’s assume that as a goal, we would like to provide business agility through deploying our software to production multiple times a day, for an extended period of time. This is valuable to the business as they can react very quickly to the market and try many different business ideas. However, in order to achieve that, we need to be disciplined in the way we code. We cannot have bugs in production- at least, nothing critical. We need to remove all the manual steps. We need to ensure we have good collaboration and also a good understanding of what is going to production. We need to make sure that developers understand the code, regardless of their seniority. We need to make sure that a good degree of quality is constantly maintained so that different developers can work on their features and send them to production. We need to make sure the whole code is quickly tested every time developers change the code. We need to make sure we have a repeatable process that can integrate code, test it, and deploy it automatically if all tests pass. These are the second level goals that were defined to support the first level goal that is to provide business agility through continuous deployment to production.
Now we can discuss practices. What are the practices that would allow us to have a fast and short feedback loop when it comes to the correctness of our code? And how do we make it repeatable? Hmm... Maybe a set of automated tests could be very helpful. In minutes, if not seconds, we can know if our code works. Yes, that would be cool because today it takes us at least 2 weeks for our QA team to test the system. We also need to have “code freezes” while they do their testing. Yeah, that’s quite wasteful when we compare the size of the feedback loop and how repeatable the process is.
OK, I’m convinced. Now, how do we build this test suite? How do we make sure we don’t over-engineer and only build enough to satisfy business requirements? How do we get feedback in our design? Hmm... Maybe Test-Driven Development could be a very good practice. True. This way we can move along being confident that we haven’t missed anything and everything we’ve done is tested. Hey, we don’t ever need to bother with code coverage, as we would always be very close to, if not at, 100%.
Yes, but it would be nice to share knowledge about different parts of the code base with all members of the team, and also make sure we are all happy with the quality of code we are producing. Hmm... Maybe we should start pair programming and rotating pairs often. Yes, and we could have another pair reviewing our code once we are done. OK. So we can develop our code, use different branches, and merge the code once it is reviewed, assuming that no issues were found. Yes, and to make reviews faster and easier (we don’t want to waste anyone’s time), we could work on very short-lived branches and make sure each branch focuses on a very specific single behavior. Cool, sounds like a good idea. And how can we know that the work being done in parallel by different people is not breaking anything else? Hmm... Maybe we could make it easy to continuously integrate our code and run all of our tests every time it happens. Yes, that would give us an immediate feedback on our change. Even better if we had this check when we raise a pull request, at branch level and not after the code is merged. If the build fails, we know we can’t merge our code; this way we can always keep the main branch clean and ready to be deployed. Yes, that makes sense. I love that.
Right, so if all production code has been written to satisfy an existing test, it has been written and reviewed by different pairs, it was successfully integrated and tested, then we could potentially go live, right? Sure, why not? OK, maybe we could automate our deployment pipeline, removing the need for manual steps and making the process repeatable. This way we could trigger it as many times as we want. Even if we ever need to make an emergency fix in production, it would be easy and safe to do it as everything is automated. From our experience, when we need to quickly fix a bug, we may create other bugs. With all our practices in places, this would be a very unlikely scenario. Sounds like a plan.
Don’t discuss practices. Discuss the value you would like to provide and walk backwards.
I don’t have an issue with developers who don’t use TDD or any other XP practice. But whenever that is the case, my default question is: What do you do instead that can provide a shorter feedback loop and more value? At Codurance, we advocate XP practices because they are among the best practices we know. They are aligned to the fast feedback loop we want to have while writing code and are also aligned to the value they bring to our clients and us as developers. However, we are constantly looking to improve and we are happy to ditch or supplement some of the XP practices when we find better ones. We believe that a good practice is only good until we find better ones to replace them.
In summary, before you try to convince someone to adopt a practice, first make sure you have an agreement on the problem you are trying to solve. Then, discuss practices using the size of their feedback loop and value they bring as the criteria. If someone rejects the practices you are proposing, ask them what they suggest instead that could give a shorter feedback and more value when compared to the practices you are proposing.