In the software engineering field we all have been using the factory pattern for many years. However, something changed with the introduction of the microservice architecture. How did this affect your factory pattern implementations and have you realized that you need to change your implementation to align it with the microservice architecture?
In the factory pattern, you basically have the following:
- Interface that contains your method signatures
- Base class
- Class A that inherits from Base and implements the interface
- Class B that inherits from Base and implements the interface
- Then you have the Factory class
- Then you have a client or some form of Manager class that creates an instance of the factory and invokes the methods defined in the interface
Let’s now use an example. Let’s say you have a website that accepts the customer’s address and then you need to verify if that address is valid. Let’s assume that behind the scenes you have two different external (3rd party) providers that you can use to do the address verification and you want to abstract that from your clients (Front End code). Then you would end up coding a service as following:
- IVerifyAddress interface with verifyAddress(…) method signature
- BaseAddressVerification class
- ProviderA class that inherits from BaseAddressVerification and implements IVerifyAddress interface
- ProviderB class that inherits from BaseAddressVerification and implements IVerifyAddress interface
- AddressVerificationProviderFactory class
- AddressVerificationManager that creates and instance of the factory and invokes the verifyAddress(…) method
In the n-tier architecture or a monolithic application, the verifyAddress(…) method would be fully implemented within the ProviderA and ProviderB classes within that existing application/service.
However, if you do this type of approach in your microservice architecture, your service really becomes a macro-service instead of a micro-service. You just need to go back to basics of the microservice architecture and go through that exercise of cleanly defining what micro means in the microservice (https://medium.com/@almirx101/micro-in-microservices-677e183baa5a). Once you go through this exercise, then you would realize that you need to do some refactoring in the above code.
Basically the full implementation of the verifyAddress(…) method is NOT going to be within the ProviderA and ProviderB classes of the existing service. The verifyAddress(…) method is those two classes would just be a shell or wrapper method and within that shell you would be making a call into TWO different microservices that you need to implement. One microservice would be AddressProviderA microservice and the other one would be AddressProviderB microservice. Those two microservices would contain the code that integrates behind the scenes to the EXTERNAL (3rd party) ProviderA and ProviderB.
With this approach, we truly decoupled things and each microservice has its single purpose:
- My Address Factory microservice has the sole purpose to orchestrate things using factory pattern.
- AddressProviderA microservice has my code on how to integrate with the external ProviderA and verifyAddress() method is fully implemented here.
- AddressProviderB microservice has my code on how to integrate with the external ProviderB microservice and verifyAddress() method is fully implemented here.
- and then you have the EXTERNAL (3rd party) APIs that you talk to and they are the actual external ProviderA APIs and ProviderB APIs.
The following exercise is what I like to go through to explain if you implemented the factory pattern properly within the microservice architecture. Let’s say you implemented your service as the macro-service described in the beginning. Then I tell you that I want to implement a batch process and verify a bunch of addresses through provider A leveraging what you have built so far. Would you be able to give me an API route that I can call to specifically verify addresses via provider A? I am sure you could expose an API route within your existing macro-service, but that API route would mostly likely NOT be RESTful. Now going back to the cleaned-up version of your microservices, I could just read the API documentation of your AddressProviderA microservice and I could invoke it directly (without talking to your Factory microservice) because in my batch process I want to run certain address only through provider A.
In conclusion, the factory pattern as the shell is your orchestration microservice and the actual full implementations of the interface are in separate microservices that you need to implement.
Thank you for reading this article.