Write Code Once/Separate Multiple Application Dependencies

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.



  • Mark Tiede

    Ya lost me a little. Can you provide a code sample? Are you suggesting that the interface stays the same and the implementation changes? Or are you saying that a new version has to provide its own interface separate from the original? Or something entirely different?

  • John Shadows

    The part that has me stumped is the different release schedules. My only thought on this is to separate out the common parts into an inheritable class then let the application specific parts inherit and build on top of or if necessary override or shadow methods with their own unique flare.

    Admittedly this is an older tactic in “.Net-land” than interfaces and such. The thing that always annoyed me about interfaces (I’ll quickly concede, I may be doing this wrong) is that you get the method stubs but STILL have to put code in them. I liked inheritance because I got the methods just like inheritance however I only had one place where the shared code amongst classes resided and the method signatures were the same.