Small Batch Sizes
Introduction
Every piece of evidence we have says that working in smaller batch sizes reduces risk and allows us to build more quickly. Each batch is a learning opportunity, and the more opportunities we have to lear learn the better we can adapt to changing circumstances.
Efficient software development needs to be done in a way that allows for fast feedback and easy adaptation. Our process should be both incremental and iterative. This means that we should be working on small portions of the code and refining them until they are complete. Both of these approaches are required in order to break the development process into the smallest, most manageable pieces. Each piece is developed, tested, and released through a series of iterations, allowing for continuous improvement and learning.
The very first piece of advice I give every new developer is to work in smaller steps. If you have been working for hours before you check if your code runs, you are just setting yourself up for failure. If there is a problem, that issue could be anywhere in the code you have written. If you work in smaller steps, there is a much smaller area where the problem might be, making resolving it much easier.
Iterative vs Incremental
With iterative development, each step we take is refining our solution until it eventually reaches completion. Incremental development, on the other hand, is about building a small portions of the system to completion at a time. Both approaches are about breaking down the development process into smaller, more manageable pieces.
This difference is commonly used to compare waterfall methodologies with agile methodologies. Waterfall is often seen as a more iterative approach, while agile is seen as more incremental, but this only applies when we are building the entire project with this approach. In reality, we can use both iterative and incremental development in any project, and doing so can help us build more efficiently.
The best approach is to work on small portions of the code and refine them until they are complete. This gives us the best chance of building the right thing, and building it quickly.
Advantages of Small Batch Sizes
Forces Good Habits
Working in small batch sizes acts as a positive feedback loop to encourage good habits. In order to support small batch sizes, we need to have good testing practices, otherwise the testing overhead will become too high. We need the team to be able to work independently, otherwise the team will be slowed down by dependencies. The system needs to well designed, otherwise we won't be able to work on it in small pieces. Our delivery pipeline needs to be efficient, otherwise we won't be able to release our changes quickly. Every one of these changes will make the team more efficient.
In order to support small batch sizes, we need to have good practices in place. This is a good thing. The more we can encourage good practices, the more efficient we can be.
Reduces Risk
"Anyone who has never made a mistake has never tried anything new."
-- Albert Einstein
Working in small batch sizes is a more defensive approach to development when compared with a more long-term plan oriented approach. They allow us to learn and adapt more quickly. Each batch is a learning opportunity, and the more we can learn, the better we can adapt to changing circumstances.
If we are building the wrong thing, we want to know as soon as possible. The longer we wait to find out, the more time and money we lose. Small batches allow us to get feedback early and often, and correct course as needed.
Defects are also easier to find and fix when we work in smaller batch sizes. The longer we wait to find a defect, the more lines of code we have to search through to find it. Working in smaller batch sizes allows us address defects more quickly and with less effort.
Mistakes are simply less costly when we work in smaller batches.
Faster Feedback
Putting a product in front of users as soon as possible is the best way to get feedback. The longer we wait to get feedback, the more time and money we might be wasting. Delivering smaller units of code allow us to get more targeted feedback sooner. This gives us more opportunities to ensure that our system is aligned with the needs of our users.
Developers need to be thinking about how they can break down their work into smaller pieces, where each piece delivers some value to the users. This value can be pretty nebulously defined, but it is important to have some idea of what you are trying to achieve with each piece of work. We can then check our release against this planned value, and see if we have achieved it. This last step is skipped with shocking regularity, but it is the most important part of the process.
Iterative Development
Gradually refining our solution is a great way to build software. We can start with a rough idea of what we want to build, and then refine it as we go. Even if we have no idea where we are going, iterative development can allow us to make progress. All you need is a metric to identify success, and you can start building. Take a random step, and then measure the result. If it is successful, take another step in the same direction. If it is not, undo your change and take a step in a different direction.
"I think there is a world market for maybe five computers."
-- Thomas Watson, Chairman of IBM, 1943
Accurately predicting what people want is more a matter of luck than skill. Most industry data that I've seen says that, even for the best software companies in the world, two-thirds of all of their ideas produce zero or negative value. We are bad at predicting what people want, and the best way to find out is to build something and see if people use it.
Working Iteratively
There are several practical tools that can help you work iteratively. A good development process is a combination of these tools, and the best process for your team will depend on your team's strengths and weaknesses.
Agile Development
Agile teams naturally work in an iterative way. They break down their work into small pieces, and then refine them until they are complete. This is a good place to start, but we can take this further. Too many teams don't release their changes at the end of each iteration. This is a mistake. We should be releasing our changes as soon as possible, and getting feedback from users. Iteration without feedback is no better than waterfall.
Testing Throughout the Process
During your own development process, you should be testing your code as you go. This is the best way to ensure that your code is working as expected. Write small tests that ensure that your code is working as expected, and that it will keep working as expected whenever you make changes. Waiting until the end of the development process to test your code is a mistake. The longer you wait to test your code, the more likely you are to have defects and the harder they will be to find.
Continuous Integration
Combine your changes with the rest of the codebase more frequently. The longer you wait, the more likely you are to have conflicts with other developers. You also ensure that your changes work with any changes made by the rest of the team. If you and another developer have been working in isolation for a week, and then you try to combine your changes, you are likely to have conflicts. You may have spent time on duplicate work, or you may have made changes that are incompatible with the rest of the system. Work in a way that allows you to combine your changes with the rest of the team more frequently.
Incremental Development
Incremental development was a fundamental part of both Extreme Programming and Scrum. Both methodologies are about breaking down the development process into smaller, more manageable pieces. In many ways, incremental development is the heart of Agile.
We should be working on small units of work, developing them to completion, and then moving on to the next unit of work. The general idea was that measuring progress in software was hard, but we can measure finished features. So, we work to deliver completed features in order to better track our progress.
Working Incrementally
Modularity
Efficient incremental development requires good system design. We need to have clear boundaries between the different parts of our code, so that we can work on them independently. This allows us to develop them to completion, and then move on to the next part of the code. We cannot build a component to completion if that component is tightly coupled to the rest of the system.
One of the best tools for supporting modularity is the Ports and Adapters pattern. This pattern allows us to define clear boundaries between the different parts of our code, so that we can work on them independently.
Team Independence
Working incrementally requires teams to be able to work independently. Each team needs to be able to make meaningful progress without relying on outside help. This means that each team needs to have a clear understanding of what they are building, and how it fits into the rest of the system.
This is a good thing. The more independent teams are, the more quickly they can move. The more quickly they can move, the more quickly they can adapt to changing circumstances.
Incremental Design
Complex systems don't spring fully formed from the mind of some genius creator. Any initial design is going to be wrong, and the best way to find out what is wrong with it is to build it. Incremental development allows us to build a small part of the system, and then refine it as we go.
Complaining that they got the requirements wrong is a symptom of a waterfall mindset. In reality, we are all they. We are all trying to figure out what the users want, and the best way to do that is to build something and see if they use it.
No one ever knows all of the requirements up front. Assume that the requirements are going to change, and build your system in a way that allows you to adapt to changing circumstances.
Common Mistakes
Teams often struggle to work effectively in small batches, and even when they do, they often struggle to release their changes frequently. Most issues can be traced back to one of the following problems.
Not Releasing Changes
Working in small batch sizes is only useful if we are releasing our changes frequently. The longer we wait to release our changes, the more time and money we are wasting. We need real feedback from real users.
A common approach is for teams to work in small batches, but to group them together into a larger release. This is a mistake, and discards many of the benefits of working in small batches.
Not Going Small Enough
Another common mistake is to not go small enough. Many developers are used to working on a feature for weeks or months before they release it. When asked to work in smaller batches, they will often break their work into smaller pieces, but these pieces are still too large. Some task that takes a week to complete might feel like a small batch, but is still too large. We need to be working on tasks that take hours to complete, not days.
Doing this requires a different mindset. We should aim to decouple the merging of code from the completion of features.
Conclusion
Incremental and iterative development is a way to break down the development process into smaller, more manageable pieces. Each piece is developed, tested, and released in a series of iterations, allowing for continuous improvement and learning. Working in smaller batch sizes reduces risk and allows us to learn and adapt more quickly.
These approaches are critical for improving development processes, and are a necessary starting point for any team that wants to build better software faster.