If you ask ten people what they think about Continuous Integration, you will get eleven different opinions. Between various tools, rules and values, every developer/organization has a different opinion about what Continuous Integration (CI) is, what it means to the company, and how to implement it. However, stripped to its core, CI is quite basic. Simply put, CI is the act of making sure that the entire development team integrates code with the core branch as often as possible. This definition of “often” is incredibly subjective, depending on the team, but on average, this means each developer should merge their code multiple times a day. CI becomes important as one transitions from working as individual to working as a part of team. A single developer only has to worry about the code changes they create themselves, whereas in a team, CI helps to mitigate the change that comes from dealing with multiple people working in the same space.
The purpose of CI is to make the process of integration as smooth as possible. Within a system of CI, a developer should never encounter the scenario where a feature takes a week to develop and a month to integrate with the rest of the codebase. Features will not be built upon stale assumptions of architecture that have long been refactored away. Integration bugs introduced by the meeting of disparate systems will no longer be hidden from view until it is too late to fix them. With the practice of merging to a common code base on a regular basis, developers also learn to write more modular and less complex code.
The very act of integrating regularly makes the act of integration easier. This is partly due to the simple fact that repetition of difficult tasks over time will make said tasks simpler, but it is also due to the nature of integration. The act of integration is simply to take changes made on a local developers’ branch, and put it on top of the foundational branch or production branch. The more rapidly the integrations occur, the less the reality of the foundation is able to shift away from the reality present in working code. Assumptions will have had less time to change, and as such, refactors that do change critical systems will be less damaging and less work to fix.
Even given a perfectly tested set of functionality, the potential for bugs is ever present. In particular, the fault lines at the intersection of functionality are fertile breeding grounds for bugs. These “integration bugs” are typically caused by the unintended, and unforeseen interactions around features that should, in theory, have no crossover. CI, like most good practices in software development, does not necessarily serve to prevent integration bugs from happening. It acknowledges that bugs and mistakes will happen. What CI does facilitate is to surface these bugs in a timely manner. Instead of building features for the majority of the development timeline, then adding in crunchtime/death marches at the end of the development cycle, CI ensures that integration bugs are just part of the regular planning, development and release status. By integrating early and often, integration bugs can be found, assessed and prioritized.
More modular code:
Ultimately the main benefit of continuous integration is the availability of all features and code across the entire software team. This helps to breed familiarity with the system as a whole, and prevent the siloing of knowledge. When a feature, or a branch, lives for weeks or months without being integrated, there can be a sense of ownership and protectiveness with said code. Developers tend to write more esoteric code when they feel like the code is theirs and theirs alone. With discipline of proper CI, all developers should feel empowered to understand and improve a much larger area of the code. This should foster a greater sense of code stewardship as a team rather than ownership as individuals. Developers can focus on the holistic health of the entire code base, rather than obsess over grooming their individual enclaves.
It is important to mention, Continuous Integration, just like many good software development practices, cannot exist within a vacuum. Without other good practices, such as TDD, pairing, planning and cross team communication, CI will not solve any problems in its own right. It is merely one of many tools employed to make the lives of your team more productive and less stressful.
The means to achieve CI will vary vastly between team to team, depending on size, location and preference of the individual developers. However, within all of these variables of “how?” one does not lose track of the question of “why?”. CI helps to improve the day to day operation of your developers and product teams by streamlining the act of integration, exposing the points of stress and contact between various systems, and facilitating the creation of clean code. Each team will have to find what practices work for their particular composition, as well as a cadence that makes sense. One must gauge the status of their codebase, and the willingness of their team before implementing some arbitrary metrics. Start with the very simple goal of once a day, see how much people riot, and then adjust as necessary.