I’ve been working on a project for a client that features a component to be shared with more than one application. The client has had a lot of problems with these kinds of components. They have tried implementations using micro-services, web services, project libraries, or sharing the project in multiple solutions. A frequent occurrence is that two different applications are making modifications to the shared library at the same time, on different release schedules. If both teams check their changes into version control, a release dependency between the two projects is created, resulting in a lot of coordination and testing issues.
They know they need to separate the dependencies of different release cycles. The required solution for my component is to simply create a file that may be copied, and share no code in actual implementation. This works great until you find you need to make a modification that impacts all instances of the source. If you have a different copy in different applications, then you have to be sure to make the necessary changes in all instances of the component code. While this solution provides the necessary separation, the redundancy of code results in extended risk as the number of instances of the same code increase.
This implementation causes me no small degree of concern. We are introducing risk when there are other solutions available.
One solution available are the principles found in the SOLID acronym. They all have something to say about the problem. The principle of Open/Closed for the O in SOLID stands out immediately. Open/Closed means that if you have an existing library that has been published, the interfaces are Open for extension, but Closed for modification. What that means is that you can’t change the inputs or return type for any public methods.
If two different projects need to make modifications to public methods, they must create their own new interface. The same library, and even object, should be able to simultaneously support multiple versions of code, through the use of an interface. In order to take advantage of this capability, your library must use and expose interfaces. Client applications declare variables of a specific interface, and then, using different methods of implementation, can implement an object implementation that supports the interface.
What this means is that the library can simultaneously support multiple implementations. What drives how it works is the client. If application 1 still supports interface one, even if a new library is deployed for application 2, it won’t matter. The deployed instance of application 1 still supports and uses the old version of the software. Application 2 is now deployed on a new schedule. It deploys the shared service. It doesn’t matter that it is implementing a new interface. Even if the interface implementation is shared against two different application. Why? Because the applications using the shared library are associated with an interface, not an implementation.
This solution results in the ability to not only share code, but to have backward support to a single application with a new library instance.
When designing your services, keep in mind the Open/Closed principle in the SOLID acronym.