In this article, I’ll describe the following technical practices that will greatly influence the agility of your project:
- Coding standards
- Collective code ownership
- Continuous integration / continuous deployment
- Test-driven development
- Clean architecture
But before we can understand how these practices impact your agility, we need to be clear about what we mean be “agile”.
What is agile?
Personally, I subscribe to the school of thought that says that “agile” is an adjective, not a noun. This means that you cannot “do agile”. Simply buying a certificate, or blindly implementing some popular process, does not mean that you “do agile”. You can only choose to do your work in such ways that it either increases or decreases your agility.
In software development projects, there are many methodologies, such as Scrum and Kanban, that are very good at providing structure and guidance for the work process. These methodologies help increase your agility.
However, in software development projects there are also certain technical aspects to the work that can greatly improve your agility if you get them right, or completely derail your project if you get them wrong. And if you get these wrong, you can impose WIP limits all you want, shuffle sticky notes around until your arms fall of, and hold retrospective meetings until you see blue in the face, but that will probably not make much of a difference.
In this article, we’ll look at some of these technical practices. If you are a software developer, mastering these topics will greatly improve your effectiveness and efficiency. If you are a Scrum Master, agile coach or involved in the work process in some other capacity, it helps to be aware of these technical practices. If not to coach your team directly, then at least to be aware of certain pitfalls that may be hiding in the technical side of things.
One final note, before we dive in: this is certainly not an exhaustive list. I’ve taken these practices from Extreme Programming (XP), a software development methodology that prescribes both technical practices and practices for planning and organizing your work. But Extreme Programming prescribes more than these practices, and there are other practices and methodologies that will be just as valuable. Having said that, I think these practices are common to a lot of methodologies, and they provide a good introduction or starting point.
Let’s start with a practice that is easy to implement, and quite commonplace in most software teams today, but no less relevant: adhering to coding standards. You should agree upon a certain coding standard within your team and format all your code according to that standard.
If all code looks and feels the same, it is much easier for new and veteran team members alike to find their way around the code base. Refactoring is much easier as well. And finally, a consistent code base greatly contributes to collective code ownership. See also the next sections on Collective code ownership and Refactoring. All these attributes make your code easy to reason about, easy to work with, and easy to change, so you can respond quickly to change. In other words: you are agile.
For some coding languages, coding style is largely a built-in part of the language (ELM comes to mind). For others, commonly used coding conventions can often be found online, so you don’t have to re-invent the wheel. When possible, use your code editor or some other linting or formatting tool to help you format your code according to the standards. That way, adhering to the standards can be automated for the most part.
Collective code ownership
This practice states that everybody on the team can contribute to any part of the code. There is no part of the code that is ‘owned’ by certain individuals and can only be changed by them. Of course, when the team and the codebase is sufficiently large, some people will have better knowledge of certain parts of the system than others. But that should never preclude anyone from contributing code to any part of the system. This encourages everyone to apply fixes or refactorings wherever they feel it is necessary, which improves the quality of the code base over time. It also helps to avoid knowledge silos, which can be a real problem when a knowledgeable developer suddenly leaves the team.
It helps to have a solid suite of automated unit tests and integration tests. You will be much more comfortable changing or refactoring a piece of code that you are not very familiar with if that code is covered by tests. That way, you can safely try out your changes and if they happen to break anything, the tests will tell you.
How does this practice improve agility? Since every member of the team can work on any new feature, work will not be held up because a particular team member is not available. And no individual developer will ever become a bottleneck in the work process because the work can be distributed to all team members.
Simple code is easy to understand. Code that is easy to understand, is easy to change. When all code is easy to change, you can build new functionality quickly and easily. So, you should always make sure that the code is as simple as it can be. However, this is not easy! You should continuously refactor your code so that is remains simple. You should remove duplication and apply design patterns and architectural patterns to keep the code manageable. You need to decide within your team what “simple” means. And keep in mind that a solution that makes one project simple might very well complicate things in another.
A good guideline to follow are Kent Beck’s four rules of simple design. These are simple rules, but they will help you work towards a design that is as simple as it can be.
Continuous integration / continuous deployment
This is a very broad topic, which has become a separate discipline in its own right (DevOps Engineer, anyone?). However, there are certain basic practices that everyone on the development team can follow. It all starts with checking in your code into a shared code repository, preferably multiple times per day. This is basic practice nowadays of course, but important, nonetheless. Next, you might want to run certain checks whenever the repository is updated. This can be as simple as checking that the code still compiles. But also as elaborate as spinning up an entire app ecosystem and running all kinds of automated integration tests. And everything in between. The goal of all this is to provide rapid feedback when something is wrong. The sooner you detect an issue in your code, the cheaper it is to fix. So having this kind of rapid feedback saves you time, money and potentially a lot of frustration.
Apart from continuous integration, you might want to set up continuous deployment as well. In most agile software projects, you’ll want to release early and release often. Maybe not to the final “production” environment, but then at least to some test or staging area. And doing anything over and over again means that you’ll want to automate it! So a basic strategy would be to have a deployment script that you can run against your code repository. One click to run the script, and it will automatically grab the code, build the software, and deploy it to the appropriate environment. More advanced strategies might involve running tests, deploying automatically whenever anything changes, or deploying to multiple environments based on certain criteria. Again, rapid feedback is key here: the sooner your stakeholders can evaluate new features, the better. The sooner customers can use it (and pay for it!), the better.
I love Test-driven development (TDD). In fact, I teach it, because I think it is one of the best practices you can adopt to improve your coding skills. There are two sides to this: making sure there are high-quality tests at all, and adopting the test-first method of writing these tests.
People sometimes think that the main benefit of an automated test suite is to prove that your software works. While that is a part of it, the main benefit is far more immediate and practical: it allows you to refactor safely (see the next section). The tests provide a safety net, so you are free to improve the code as much as you want, without risk of breaking anything. And as we saw earlier, doing so is crucial to keeping your software design simple and easy to work with.
The tests also contribute greatly to your ability to do continuous integration and continuous deployment. If you run your test suite as part of your integration cycle, you will detect any potential issues quickly (again, rapid feedback!) and can address them before they become a problem.
Adopting the test-first approach to writing tests brings its own benefits. It forces you to really think ahead about what you want your code to do. You have to, because you have to write a test for it first! This alone will often lead to clearer, shorter, simpler, concise code. Writing the test first also ensures that your code is well testable. It has to be, almost by definition. And testable code is usually modular in nature. You may have heard that well-written code exhibits loose coupling and high cohesion? These qualities come naturally when adopting a test-first style of coding.
Refactoring means to change the structure of your code, without changing the behavior of your code. This practice is crucial to maintain a codebase that is simple and easy to work with. A project always starts out small and simple, and in the beginning, it takes little effort to understand everything. If you keep on adding features without any regard for the quality of the code, it quickly becomes a hard to maintain mess. You should continuously refactor to remove duplication and improve the structure of the code, so that it remains as simple as it can be.
As we have seen before, this practice ties in closely with that of Test-Driven Development. Having a good test suite gives you the confidence to refactor safely, without risk of breaking existing functionality.
This practice also closely relates to the practice of Simplicity. If you refactor complex code to make it simple, you make the code easier to understand, easier to change, so you improve your agility.
Bonus tip: clean architecture
This practice is not from Extreme Programming, but I think it deserves mentioning. The success and ease of your software development project depends heavily on choosing the right architecture for your application. And one style of architecture that has proven to be very effective is the so-called Clean Architecture. This is the name Uncle Bob uses, but it is also known as Hexagonal Architecture, Ports and Adapters, or Onion Architecture. There may be slight variations between these architectures, depending on who you ask, but the main principles are the same. This style of architecture enforces a strong separation between the ‘core’ of your application, its essence, its business rules if you will, and the ‘infrastructural’ concerns such as storage, networking, the user interface or API, etc. By adopting such an architecture, your application will be highly testable and modular. Maintaining and evolving such a system will be relatively easy.
A small word of warning: there is no such thing as The Ultimate Architecture™. While architectures such as Clean Architecture can be very powerful, there will be many scenarios where alternative approaches will be a better fit. But that doesn’t take anything away from the main point of this bonus tip: make sure you choose an architecture that fits the purpose of your application, because this will make all the difference for the ease with which you can develop and maintain it.
If you are a software developer, I hope these practices resonate with you, and perhaps inspire you to study some of these topics more deeply. Are there any practices I have missed that you feel should definitely be on this list?
If you are a Scrum Master or agile coach without a technical background, I hope this article gives you a better grasp on the technical side of agile software development. I think it helps the entire team when techies have a good grasp of the basic of agile methods, just as much as it helps when Scrum Masters or agile coaches understand the basic practices of software development.