Each project has its own rules for development. Most often, these rules describe development practices and work with a version control system (VCS) that outlines how to test and deploy the product, the structure, the architecture of the project, and the code style, but the rules can also include the basics of secure development and more.
These rules can be unwritten but are usually defined and recorded in a shared space where everyone has access to them. Yet more important is how these rules are applied and enforced in practice.
Wise men know it best
Some people believe that pair programming or code review is an appropriate platform for rules revision. Participants can agree on the application of the rules or change them based on context. When developers approach this conscientiously, the result can be a project that may not be consistent, but its individual parts will be in the best possible shape.
This approach may lead to better results for a short period of time at the start of a project, but its shortcomings will start to become apparent over time. Even experienced developers and technical leads are just people. They can occasionally get tired or simply overlook something. Thus, minor deviations from the agreed-upon rules pile up and begin to form so-called technical debt.
The next aspect that reflects in time is the expansion of the project, and this is on two levels.
The first is the expansion of the product itself. As the product becomes successful, it receives new and more sophisticated features that begin to connect previously simpler and independent features. This is where the small deviations and inconsistencies that at first seemed good for the functionality start to show up. The problem is that now more of these functions need to be compatible with each other, but they are not ready for it.
This is not just a problem of incompatibility of features. Often, well-intentioned developers try to reuse existing components as much as possible to avoid code duplication. They forget the rule that we can reuse a component when we expect the same behavior but also have the same reasons to change. If this condition is not met, the Single Responsibility Principle is violated and the project has low flexibility for future development.
The second level of project expansion is the development team itself. Once the product becomes successful, sooner or later it leads to the expansion of the development team. The new team members do not know the whole genesis of the project and thus do not have the same understanding of the rules as the older members who set the rules themselves. This leads to misunderstandings and yet another minor deviation from the agreed rules, which again increases the technical debt. A side effect is an increased need for communication during pair programming and code review, which reduces the overall productivity of the team.
These problems in project expansion are not limited to large development teams, but also happen to smaller ones. For example, when a two-person team introduces two new developers, the productivity of the team may hardly change. And all this is due to the circumstances described above. Without knowing the cause of the problem, it can lead to further blind "strengthening" of the team and make it even worse.
Tripping comes before a fall
When a development team repeatedly fails to finish agreed features or is unable to release a new version of a product for technical reasons, one of the critical scenarios occurs. At this point, people outside the standard development team get involved in discovering the cause and solving the problem. Together, they all work under stress and with a lot of human effort to get the development back under control. It is only at this point that a retrospective analysis takes place to uncover the true causes of the problems.
Yet the accompanying symptoms and spring of these problems have been manifesting themselves for a long time in advance. A few subtle situations as examples:
- A developer repeatedly receives feedback on misnaming during code review.
- A ticket in the project issue tracker does not contain a reference to the implementation due to a typo in the project source code.
- A feature that is still under development is enabled in the test version of the application.
Often they just look like minor ambiguities, individual mistakes, or accidents that sometimes happen during development. When these situations recur, their negative impact on team productivity and the project's error rate quickly increases. But if we look closely at them, we can see blank spaces in the way we work that are actually easy to fill and solve the problem once and for all.
To avoid the problems mentioned above, we need to have clearly specified development rules. Their content should reflect the individual needs of each project. For some projects, it will be critical to clearly define collaboration with the QA team and describe the release management of the product, while other teams will focus more on collaboration between developers within the development itself.
The more detailed and specific the rules are, the better their effect on the team's work will be. Therefore, it is not possible to start from a general template, but each team must define these rules themselves.
Sometimes we see cases where a team defines a few basic rules of a more general nature at the start of a project but does not develop them over time. Thus, the rules never accurately represent how the team works, and even the little they contain becomes meaningless over time.
Nothing is set in stone, and even an established team changes the tools it uses or discovers new ways of working over time. All these natural changes have an impact on the team rules. They remain alive and valid.
In the introduction, we briefly discussed the form the rules can take and the possible ways of applying them. To be most effective, rules must be applied automatically without the need for manual control. Likewise, we must think about the productivity of the team, which can be reduced by the influence of a large number of repressive rules. Therefore, tools that help team members automate certain steps are an integral part of this process. These tools save time and their output is naturally in line with the defined rules.
In practice, it is so common that Code Style or Project Architecture is enforced by automated rules, but at the same time, there are code templates and formatting tools that do most of the work for the developers without them being aware of it.
Most issue tracking tools provide a programmatic interface so that it is easy to automate the creation of a new development branch in VCS so that the new code is linked to a specific issue. Similarly, it is possible to create a VCS hook that checks that a corresponding issue exists for a given branch or commit for cases when the developer has created the new development branch manually.
Release management is a completely separate chapter. When releasing a new version of a product, there are generally routine and clearly defined steps that need to be performed. Here, automation not only gives us the assurance that the release of a new version will be done in an orderly and error-free manner but it also speeds up the process and allows for easy knowledge sharing between team members. A bonus is an easy automation of generating release notes, even if only for internal testers.
Testers will also appreciate the ability to configure the product for internal testing. They can toggle a feature flag, configure the environment the application runs against, or have the ability to simulate scenarios that are difficult to do manually. Besides the undeniable benefit of these test tools for testers, it has benefits for the developers themselves. They don't have to maintain more versions of the product than strictly necessary, which saves them time by fundamentally simplifying the build logic.
This is just a small sample of the rules we commonly encounter on projects. However, it is far from exhaustive of the options, whether they are related to quantity, depth, or sophistication.
How far to go?
Some rules may seem strict enough to restrict your freedom to work. Others may seem so vague that they will not have the desired effect. That's all right. Every team and every member has different needs and different perceptions of risk. All of this has a bearing on the form of the rules.
In our projects, we try to define the rules strictly by default. Over time, when we find that they limit us too much, it's easy to make the rule more generalized or turn it into a recommendation or warning. The opposite approach is considerably more complicated, because the team and its operation have already become accustomed to the more general rule, so it may not be possible to make a change overnight.
When developing a product, in addition to the short-term goals of making the necessary features, we always consider the idea of long-term sustainability and viability of the project. Especially in mobile development, it is not an exception to the opinion that a project should be discarded once every 2-3 years and developed completely from scratch. This is a real disaster in terms of productivity.
In our portfolio, we have apps that are more than 7 years old and have gone through several major changes during their lifetime. On a business level, there has been a change in targeting a different sector of users and aligned with changes in branding and design. On a technical level I would mention the switch from Java programming language to Kotlin, or the transition of asynchronous work from a custom imperative solution to a reactive approach via RxJava and later Kotlin Coroutines. Even so, the development team is still only two people (while they are altering throughout) and at the same pace, it delivers new functionalities according to the business needs.
Clearly defined development rules and the consistency enforced by them have a major impact on the quality of the final product in every way.
Next time we will take a closer look at how some rules can be implemented and what tools we have for this.