You should always endeavour to maintain a product that is ready to ship. This is typically the state the mainline (trunk) of your version control system should remain in throughout your development lifecycle, with new features developed in dedicated branches.
Each individual feature team should commit its work to their own feature branch each sprint. This can be created as a one-off or persistent branch, according to your tooling or process preferences.
By “feature”, we’re referring to a functional area (perhaps a physics engine, checkout, content search etc.), rather than individual minor changes (make the font blue etc.).
Merging back to the mainline
Towards the end of a sprint, when the team considers any changes or new features to be production ready (after testing and acceptance), the code should be merged back into the mainline (trunk).
You can decide whether you would merge small changes on an ad hoc basis or grouped together, as long as they are independent.
However, any team committing a change to the mainline which then breaks the build (or existing product functionality) is responsible for fixing it. With CI (or just regular releases), the team should be aware of the broken build before the start of the next sprint (importantly, before its planning session). The team will need to account for any time needed to rectify issues they have introduced from their sprint.
Updates from the mainline
There should be an update from the mainline at the start of each sprint, to ensure that each feature team is working from the same core code base.
Optionally, you can merge any changes introduced into the mainline during the course of your sprint. Whether you do this will depend on how fundamental (likely to change your current activity / work) the changes are to what you are doing, along with the level of impact if addressed earlier or later.
As you’d expect, the more teams you have working on a single product, the greater the chances are that there will be changes (or bugs) introduced by one team that will impact the other. With the best of intentions, this is just an unfortunate reality – but there are steps to mitigate the impact:
Unit and integration testing
Earlier, we touched upon a scenario where another team may have broken some existing functionality. The quickest (and most objective) way to determine if any functionality has been broken, is to have appropriate test coverage included in your build process.
As an advocate of TDD, one approach we endorse is the use of tests to qualify whether one team has introduced errors into another team’s functionality (i.e. they have broken the build). Very basically – if you haven’t written a test to “protect” the functionality, then any undesired change in behaviour will be the responsibility of the team prescribing that behaviour, not necessarily the originator of the change.
That is, if you are dependant on a contract, your unit and integration tests should enforce it. Then, if another team causes that test to fail, the responsibility for fixing it is theirs.
Avoid monolithic architectures
Many solutions are built around large central systems, instead of a distributed set of independent systems. Setchu does not mandate using micro-services architectures or similar to force a clear separation of responsibility, but we generally suggest your solutions attempt to avoid monolithic architectures. Instead, consider dividing solutions into distinct, individually releasable systems where appropriate.
For example, building a payment processor into your ecommerce site, when you have a similar requirement for a separate, in-store, point of sale system within the same estate isn’t very efficient. Instead, you could provide an independent payment application that will serve both (with dedicated interfaces, if required), without the duplication of effort or close coupling. An independent application is generally what we are referring to when we describe a product.
This separation of concerns gives you future flexibility (for example, if you upgrade or change your ecommerce suite) and allows each distinct system to evolve independently.
If other teams know that you are / will be working on a certain area, it gives them the opportunity to highlight any likely areas of contention / conflict in advance. Furthermore, it is often impossible to predict all the potential consequences, but if other teams have at least been made aware of what area your team is working on, they may be able to trace the root cause of any issues more quickly.
In any event, close collaboration between teams with any shared dependencies will promote the quickest way to reaching a mutually acceptable solution.