“It’s All About Software Development” is a series of posts exploring why organizations should care about optimizing for effective software development. What does effective software development look like? How can organizations move from their (mostly) pretty ineffective software development to effective software development without magic? Read on…
This is the fourth in a series of posts on effective software development. This series has discussed of what makes modern software development so much more effective than traditional software development: frequent releases and constant velocity forever. And then it continued with an explanation of how an organization should run its products and technology teams so that the amount of work delivered to the development team to build is small enough and iterative enough so that these frequent releases can actually be done.
But even if your organization is doing this product side right and down-scoping features and iterating designs against users and subject-matter experts for validation, if you are not following effective software development lifecycle practices, you will fail to execute this modern software development.
“Write code like the next programmer who has to work with your code is holding a gun to your head.” — Programmer adage
In effective modern software development, development teams have a knowable velocity with minimal regression. This means that the development team can turn out new features and bug fixes and other things that need to be implemented in code frequently enough so that it is possible to release software all the time and for those releases to have meaningful changes at each release.This means that the number of bugs that come up — regressions — has to be minimal. Otherwise, the team will spend all of its time fixing bugs.
Below, I describe the four key processes that software development teams have to practice if they are going to be able to execute in this way.
Here’s process number one: small story sizes. Developers get their work in tickets, often called “stories” today because each should be written as a “user story” so that the developer understands why the work is being done and has empathy for and understanding of the user.
Small stories are great for several reasons. First, if the story calls for no more than about a day and a half of work, then if a developer miscalculates the time estimate for the job by 25 percent, that is still less than a day of additional work. This means that it’s easily possible on a weekly basis to understand whether a project is on schedule or not. If stories are estimated to take weeks, then it’s incredibly difficult to know you’re behind until after the deadline has passed.
Second, large stories tend to not be very well-specified. If a developer is given a story that she thinks will take about two weeks to do, she almost certainly will need more information than what has been written down for her. If, instead, that two weeks of work is broken down into ten different stories, each one of those probably has a rigorous enough definition so that she doesn’t have to go hunting around for whoever wrote the story to understand the additional details she needs to write the code.
The second critical practice is branching on every piece of work that needs to be done. It is still quite common for development teams to all be working on the same copy of the code stored somewhere centrally. This is a terrible practice because developers introduce errors.
If you are a developer working on the same copy of the code in which another developer is breaking things, your work will be disrupted, and the day and a half that you estimated for the ticket may turn into three or four days because errors created by other developers.
In addition, if you are creating regressions in your code, you should identify those and fix those before you merged more new code in with the general population. Otherwise, whoever finds the problem that you have created now has to go track you down (which is usually difficult if everyone’s editing the same copy of the code) or has to go diagnose the problem herself, causing more delay.
The third critical practice is automated testing. When you are a developer and you are working in your branch, you need an easy way to know whether or not you broke something by adding your new code. This means that someone needs to write a bunch of automated tests to validate that people aren’t breaking things.
I find that most effective development organizations have developers write their own tests to protect the features that they have added, but the key here is to have them deliver automated testing instead of manual quality assurance (QA) process that takes days. Also, manual QA almost never works in an environment where you have a branch for each separate piece of work that is being done. That is simply too many different things to test for manual QA to make sense financially. So manual QA can only be run once the individual branches have been merged, which means that each bug requires the “find who broke this” process, which is an unnecessarily slow and painful process vs. having automated tests.
Manual QA is often still necessary for some parts of applications, where automated testing is very difficult or impractical. But it is essentially impossible to do multiple releases per week if you have a substantial amount of manual QA to do for each release.
Many people think that it is impossible to get automated testing in place on existing projects where there is no test coverage or mechanism in place for writing or running tests already. For all of you, please stay tuned for the next post, where I will discuss how to adopt these practices with existing applications, without having to stop all forward progress on feature development for weeks or months.
The fourth critical practice is code review. There is a traditional programmer adage which says “write code like the next programmer who has to work with your code is holding a gun to your head.” Code review is like getting that next programmer to look at your code and give you comments before you merge your code with the general population.
Code review does a number of great things. It means that there are several sets of eyes on code before it gets merged with the existing code base. Really effective teams usually have a fairly strict style guide, and so there is usually only one correct way to write a particular section of code. In addition, most great teams have every developer reviewing code, not just one or two senior developers. This enables really good cross-understanding of the code base, making it much easier for everyone to continue working with this code base into the future and delivering the kind of velocity and frequent releases that are necessary.
While there are other great processes that effective teams often follow, the above four elements are critical to effective modern software development. If you lack any one of the above four, you will not be able to deliver a constant velocity with minimal regressions with a scalable team for an extended period of time.