In the past time of monolith the development teams were forced to share some basis libraries to make their packages refer to same classes, class members and methods, so that they could be compiled together into one big deployment artifact.
The time changes. More and more software teams are practicing agile development process and choosing micro services for their software architectures. The communications among the services are normally based on REST(ful) API via HTTP(S). The JSON bodies are transferred from service to service. Once the resource URL, the parameters and the body formats have been defined, the contracts are established. It is mandatory that the service implementation conforms the contracts until new contracts, if needed, are agreed by all communication partners.
For each team, which has its own team structure, own technical skills, own culture, own development velocity and own personality of team members, the most important thing is just to deliver qualified services in time according to the contracts. The internal implementation details should be lying on the hands of the teams.
But in some contexts there could still be common implementations for re-usage by all teams. They could be very basic like the JSON serialization and de-serialization, the realization of messaging, the HTTP requests and responses etc. They could also be the comprehensive implementation of general business logic of the projects. Do we need to package them to a basis library shared by all teams?
The advantages for a basis library are obvious:
- The teams don’t have to invent the wheels newly to solve the common problems.
- Using the same code basis can reduce the possibility of unconventional I/O style against the contracts.
- A compatible change could be broadcast quickly to all services using the library, when the teams just update the referred version number to the library.
However, before we really take the basis library into account, we have to answer the following questions carefully:
- Scope: Can the basis library solve the common problems for all teams in all contexts? If not, how far shall the library be extended or are the teams allowed to use their own solutions?
- Responsibility: Who or which teams are responsible for the library and shall maintain it? Do they do this job in full time or part time? If part time, can they begin to revise the library quickly in need? Are code commits from other teams allowed to the library? If yes, are there any quality gates for the acceptance?
- Quality: Any code changes can impact all teams directly or indirectly. Are the impacts predicable? What should be done eliminate/limit the side effects? What components or systems using this library shall be tested in which scope? How is the release process?
- Compatible: Each team has its own task schedule. If it cannot react on the library change immediately, can it use the old version? How many old versions will be kept? When must the teams update to the new library? If there is no old version, does the library provide any backwards compatibility? What is the compatibility level: code level, binary level or function level?
- Continuous improvement: The solutions provided by the basis library are really the best choices? Are the developers encouraged to improve it continuously?
With my experience in projects, the most of the questions above were answered negatively or ambiguously. Such libraries had perhaps a good start or at least good initiative. But during the their growth they corrupted here or there. For instances:
- Missing decision maker: The libraries were designed but fell into endless review discussions.
- Missing obligation: They were implemented but was promoted badly due to missing technical acceptance or political acceptance. Few teams would use them. The other teams were still using their own solutions.
- Missing commitment: They were widely used, but in case of maintenance and extension no staff or no team had time, budget or competence to do the work. When a team needed a change urgently, it had to do the modification by itself. But the change could impact the other teams, so the team, which did the change, had to keep the change in its own code branch or project, because it had no interest/time/budget to test it for the other teams.
- Over-engineered: Some of the basis libraries were very complex because they had to cover all usage scenarios and so had to build plenty generic types, inheritances and polymorphism. After several months few people still knew what had been the ideas behind, even for the writers themselves or other gurus.
- Personnel factor: After the key library promoter/supporter left, many of the basis libraries have been become obsolete day after day.
Of course there were also successful practices, might be because they had the proper timing, use cases, contexts, frameworks, technologies, teams and developers as well as support from management with schedule and budget.
Actually the essential idea of micro services is to make independent, rapidly incrementally developed and self-deployed software components. The cooperation between components and teams should be based on the contracts. Hence, we should allow certain duplication codes because they are located in different business domains and would have different reasons to be changed later. Through this we could create margins for innovation during software development. The basis libraries are more meaningfully for me if they are just treated as sample codes instead of compiled libraries.
The basis libraries could be practicable and make sense in certain situations. If you are working in a company with good development organization and competent colleagues, the basis libraries could contribute to the success. If there is no such ideal environment, it would be better think about your action again before you start. If you still want to go on, please keep the rule of thumb in mind: your basis library had better be always stable, because there would not be time/budget to revise it later and no one would be willing to take the risks of impacts.