The build system is the heart of the development process. Most programmers execute it many times during their workday. It processes resources, compiles, executes tests, packages application and possibly performs many more activities. Depending on the project, technology and requirements it might be pretty simple or very complicated. There are projects which contain hundreds of thousands of lines of build code and configuration. No matter the size and tooling, the build system matters a lot for developers productivity.
However, many projects treat it as a necessary evil. Build systems are often considered as an addition to the software – a very expensive addition in a matter of maintenance efforts. To lower it, they are handled superficially and briefly. Unfortunately, such behaviour results in even larger developer effort lost during their everyday work. Improper naming, badly structured configuration, duplications of build code and properties and counter intuitive solutions lead to hundreds of problems during different development phases. Such problems are then often discovered by almost each developer alone on their local workstations and a lot of time is wasted as everyone needs to solve the same problem to continue development of the project.
Taking care of the build code and configuration in the same way as for the application code, especially in complex projects, helps to avoid the above described scenario. Well structured and intuitive build systems without hidden twists greatly boosts developers to deliver new functionality. So, what are the especially important rules to follow during build system development?
Use meaningful names. It is quite the same as with your source code: names of your properties, application modules, build profiles and whatever involved is crucial. Think about every newly introduced name at least twice. There will probably be dozens of people using it from time to time. They shouldn’t need to check every time they want to execute a specific build as to what the goal or specific properties do. They should be able to derive it from the context and the naming itself. Sometimes it is very hard to provide a proper name shorter than a long sentence. However, it is worth the effort to deeply think about possibilities.
Avoid duplications. Do you remember why it is worth it to avoid duplication in your code? Exactly the same reason applies to your build system. Whenever you copy and paste a part of its definition to a different module, you are making it more likely that someone will not provide necessary changes (either a fix or new feature) to all of the places where it is required. As a result, it is easy to introduce hard to detect problems and inconsistencies within different modules. No matter whether you are using Maven, Gradle, sbt or other tooling, try very hard to avoid duplications.
Structure it well. While you are programming you are paying special attention to how you can divide your code between classes and methods. Do the same with your build system. Make sure that the configuration used for some specific purpose is not scattered across many different places. Constantly take care of your module structure. It should reflect specific components/parts of the system or its layers. Manage dependencies in a clean way – avoid structures resembling shoestrings.
Comment where appropriate. We try to avoid writing comments in our code as much as it is possible. We should also apply this rule to our build systems. However, always write one when you introduce some hidden twist or unclean solution so as to save other people many hours of unpleasant investigation. Just because it is a build system it does not mean it does not deserve a comment!
Care about formatting. People tend to ignore the styling of xml, json or whatever other format is used within the build system. As it makes it harder to read code without proper indentation, it is much more difficult to understand build system configuration. You know how frustrating it is when you need to just check one small thing by a web interface of a repository and meet a total mess? Moreover, cleaning styling issues after someone else obscures the history and makes the VCS blame command unusable.
Use meaningful error messages. Have you come across the situation where your build system has thrown an exception at you with a message saying absolutely nothing to you? That is the exact reason you need to handle error information with proper care. Each message should state what part of the build system went wrong and what was the root cause (or a reason as close to the root cause as possible). Hundreds of times I have seen very fancy misleading error messages. Whenever you need to deal with error handling think how you can help developers to understand best what the problem is.
A build system significantly affects developer productivity. Moreover, it plays a major role in the deployment pipeline. Taking care of its quality should at least have the same priority as taking care of the condition of your code. It will pay off for sure. Moreover, we can use the same techniques and good practices for both purposes. It is just a matter of paying enough attention and getting a little experience. Do not treat your build system as a necessary evil but as the heart of your development.