Managing services that don’t have clear code ownership
Services need clear ownership as somebody has to be accountable for managing changes in the code. This is easy enough for services whose responsibilities fit neatly into team or organisational boundaries.
The problem comes where you have a service that doesn’t fit in cleanly to any existing team. For example, it will be easy to identify a team to look after domain specific features such as order processing, but something like identity management or single sign-on is more difficult to assign as it is shared across every application.
There is also the problem of “orphaned” services, or those that don’t have any meaningful ownership. Many services are developed in a blaze of activity around a particular project. Once the project ends the teams get disbanded, everybody’s attention moves on and some of the services are left to operate on their own. This is fine until changes are required or bugs are found.
Shared service team
One solution is to create a separate team to manage services that don’t belong anywhere else. This may seem convenient but a shared services team can easily become a “bucket” for features that nobody else is able or willing to take on. The very act of establishing a shared services team tends to fuel the demand for this kind of shared service.
It can be difficult to assemble a team to work on shared services. Most teams are able to focus on a particular business domain and contribute to a shared code base. This promotes collective code ownership within a team and helps to reduce development bottlenecks.
A shared service team has to engage with much wider scope both in terms of technologies and business knowledge. It can be difficult to recruit developers with sufficient breadth of knowledge to work across the entire code base. This can give rise to a team of individuals working separately on individual services rather than a cohesive team contributing to a shared code base. The potential benefits of collective code ownership often get lost.
Internal open source
An alternative model is to adopt an open source model for shared service development. There are numerous ways of organising this but the basic approach opens up a service to modifications by anybody. If you couple this with a mature code production pipeline it can be easy to build, test and deploy new releases with confidence.
The main challenge here is one of accountability and governance. Who owns the roadmap and takes responsibility for the longer term direction for the service? How do you ensure consistency of the implementation? You need somebody to take ownership of the code or it will fall into disrepair under the weight of different developer contributions.
Another problem concerns coordination. When a lot of changes are being made to the code it can be easy for developers to trip each other up. If numerous different teams depend on the service some level of release coordination will be required. This can be difficult given the chaotic nature of open source changes. An extra layer of coordination will be required if production deployments are handled by a separate team.
The internal open source model can be made to work, but only for services that do not change very often. This implies either very small services or those that have reached a state of maturity so that change is predictable or infrequent.
An open source project doesn’t have to be a free-for-all. One approach is to appoint a “benevolent dictator” to determine the general direction of the service and make final decisions over which contributions can be included in a release. This role is one of arbitrator and coordinator and should not be particularly onerous for a service that rarely changes.
This can be particularly useful way of keeping some sense of ownership over services that have not been updated for some time. These services are at particular risk of becoming “orphaned” over time as the team who originally developed them is disbanded at the end of a project.
The open source approach can also be mitigated in the short term through temporary ownership of a service. If a major programme of changes need to be made to an otherwise static code base then a team can assume control of the service while the work is carried out. This will help to ensure that there is some consistency over the implementation and also some responsibility for coordination.
Teams are often reluctant to accept temporary ownership as they see it as adding to their workload. It can also be an unnecessary distraction from their permanent code base. Most teams can be placated by providing clear entry and exit points for ownership rather than an amorphous engagement with no clear ending.
Do we really need shared services?
One approach for managing shared services is not to have any. There is a strong case for using shared platform infrastructure, such as database servers or API Gateways. The overhead involved in this kind of “heavy equipment” is too great to consider replicating it across each team. The case for developing shared services providing generic features is less clear.
These services are often the result of an attempt to create a shared framework that other teams are obliged to use. They can become a development bottleneck as the team is overwhelmed with competing requests for features and fixes. This approach can yield services that are either too specific for general use or too generalised to add any value.
If you examine a domain with sufficient discipline the scope for shared services often turns out to be fairly limited. In most cases they become a case of sharing infrastructure dependencies rather than data and behaviour. A large number of shared or orphaned services may be symptomatic of a deeper problem with the way the domain has been analysed.