Defining How to Integrate Continuously

When a group of people work on related things, it is very important that they frequently combine their work to reconcile inconsistencies. This is true regardless of whether one is talking about documents, computer code, or hardware components.

When we say “combine their work” we mean that they put all their respective pieces together. Then they should check if it all is aligned, consistent; but more importantly, they should check that the combined work is effective as a whole: sometimes pieces might work, but when assembled, the combined system is not effective for its main purpose.

The process of combining work is usually referred to as integrating the various components.

A dilemma arises for digital artifacts such as software, digital designs for hardware, and digital documents: it is possible for people to independently work on copies of the same artifact. That is often referred to as concurrent development. So-called concurrent version control systems support the re-integration of digital artifacts when people concurrently but independently work on the same artifacts.

The dilemma is that when people work concurrently on separate copies of the same thing, they often make inconsistent changes. The process of reconciling those changes is usually referred to as merging the changes. To merge changes with high certainty of correctness, one must examine each change and mentally verify that it is consistent with other changes. However, many concurrent version control systems make an assumption that changes that are far apart in the artifact are not inconsistent, and so they merge those changes automatically. That actually presents a risk, but for software the risk can be mitigated by having high coverage automated tests: one can run the tests to verify that the artifacts are still correct.

Merging can be done in one of two directions: one can merge one’s changes into the shared global copy, or one can merge changes to the global copy into one’s local copy. Both cases achieve the goal of reconciling inconsistencies. The former is usually called an upward merge and the latter a downward merge.

An important point is that when one merges changes, one is always merging two different versions of an artifact or set of artifacts. One is never merging multiple versions. Thus, even if many people are working concurrently, one never has to worry about more than two different versions: one’s own version and the global shared version.

Generally speaking, it is a good idea to integrate frequently. In other words, do frequent merges, and verify that the combined system works and is an improvement over the prior version. This can be done with the global version of a local version. The point is to not let too much time pass before (1) changes between versions have been reconciled, and (2) all the pieces are combined and checked for operational compatibility.

If one merges frequently in the downward direction but only infrequently in the upward direction, there is not a problem per se. But if many people do that, then there is a risk that they each will diverge greatly in their local versions and the eventual reconciliation will be difficult. However, there are advantages to delaying an upward merge, the chief one being that one can complete a complex feature and make sure it works before merging it into the shared global version. Merging in a half-complete feature can be very disruptive for others, as their code will stop working.

That is why it is essential that someone pay attention to who is working on which features, and who is delaying their upward merges. If it is one person working on a complex feature, that is a good thing; if it is many people working on simple features but delaying merging upward out of laziness, that is a bad thing.