Story Behind this Post
This post is further discussion of the post that can be found here where we discussed two most prominent features about micro-services and tried to explain how they are not exclusive to Micro-Services actually they are attributes that can be achieved with good architecture and following basic
Link to the first post of this series is here Blame it on Monoliths - Part 1
In this post(
Part 2) we will take an example of an application that looks like have a micro-service architecture and try to see how having a
micro-services alone will not help with
Maintainability of the software.
The example in this Post is inspired from the Book Clean Architecture by
Robert C Martin. It’s a great book and must read for any developer to understand the basic principles of Software Construction. So all the credit for this post goes to the book.
Flight Finder System (Flight Finder)
This system knows about many airline companies, and allows customers to search for flights. Let’s assume that the customers select flights based on a number of criteria, such as date/time, cost, luxury. We wanted our system to be
scalable, so we chose to build it out of lots of small
micro-services. We subdivided our development staff into many small teams, each of which is responsible for developing, maintaining, and operating a correspondingly small number of services.
Here are few Micro-Services we have in our
fictitious architecture and their purposes from the above diagram.
FlightFinderUIis front end application used by customers to search/book flights using our system.
FlightSearchService is used by Flight Finder UI to search the flights available for provided criteria and combination of User preferences.
FlightAggregatorService is responsible to scan through various supplier inventories and find all suitable flights for provided user criteria.
FlightSelectorservice takes user criteria of cost and time and then further filter down the available flights.
FlightBookingservice order the selected flight for the Customer and communicate the booking to
FlightFinderUI is front end used by the customers, who use mobile devices/web browser to search flights. The
FlightSearch takes the user selection criteria as input from
FlightFinderUI and call
FlightAggregator service which then examines the inventories of the various
Airlines and determines which flights are available for the user and then return results back to service
FlightSearch which keep it in some local cache.It then passes all the flights available from different airlines to the Service
FlightSelector service takes the user’s criteria of cost, date/time, luxury, and so forth, and then call the
UserPreference service to fetch additional user preferences and further filter down the list of available flights. Then it returns results back to
FlightFinderUI. Then customer select one of the available options and
FlightFinderUI invokes the
FlightBooking service, which book the appropriate flight.
Warning: I am no Architect and lot of people may not like the architecture but keep in mind this architecture is fictitious and used for example sake only.
One bright and cheerful day, the marketing department holds a meeting with the development team. In this meeting, they announce their plans to find flights for Kittens customers can look up flights that are Kitten friendly.
I am just making up this requirement for example sake. - You must have figured that out already :)
Only one of the Airline Company have agreed to provide this service but others will follow in future. Some airline companies may decline. Some of the passenger will have Cat allergies so a Flight that has been used to deliver kittens should not be selected for customers who declare such allergies and so on.
What needs to change
How many of those services will have to change to implement this feature? All of them. Clearly, the development and deployment of the Kitty feature will have to be very carefully coordinated.
In other words, the services are all coupled, and cannot be independently developed, deployed, and maintained.This feature request involved cross cutting concerns that run through the most the services. How we could have made such feature request
least painful or more
SOLID to the Rescue
Let’s assume for a moment we don’t have micro-services we have a monolith with component based(Plugin based) architecture instead of multiple services we have multiple components that make up the system.
Component is something equivalent to DLL in .net world, jar in java world or GEM in Ruby world.
Specially if we look at the
Open Closed Principle it would have suggested us to create a set of classes that could be polymorphically extended to handle new features.
We should create a abstract class to define the behavior of
FlightSearch class and then we implement classes for
Kittens that will be polymorphically used in place of the abstract
To add new feature for
Kittens we will add new component(DLL/jar) that override the Abstract
FlightSearch class. So The new feature for kittens has been placed into a Kittens component. These two components override the abstract base classes in the original components.
So we will end up having two components
Kittens both follows the dependency rule dictated by
SOLID principles. The
FlightFinderUI will have a factory which will decide which override of Base abstract should be created to handle a request depending upon if user is searching for
Passenger flight or
Kittens Flight. If we need to add another feature in the future we add another component that override the abstract base class for
This way in future if we add new feature we just update
FlightFinderUI to load another DLL dynamically so the factory can crate instances of it.But nothing else needs to be changed. Rather, a new jar file, or Gem, or DLL is added to the system and dynamically loaded at runtime.
So if we have to show the Component diagram for the
FlightSearch.Note: I omitted other classes from the digram for brevity. It will looks something like below. The
empty arrow head show inheritance(Abstract override). Red rectangle shows the component boundaries.
So the abstract base class for
FlightSearch is overridden polymorphically for
Passengers. If in future they want to find flights for
Parcels also they can add another polymorphic override for the
In this way we can add new functionality to the system by just adding new code instead of editing existing code. This is what exactly the Open Closed Principle if this this principle is followed new changes can be made with least pain.
It doesn’t even matter if you are using
Micro-Services or just using plain
component or plugin based
architecture The effort needed to add new feature will be similar.
What we learned
What we have learned is that architectural boundaries do not fall between services. Rather, those boundaries run through the services, dividing them into components. To deal with the cross-cutting concerns that all significant systems face, services must be designed with internal component architectures that follow the Dependency Rule,
Here is what our micro-services diagram will look something like if we stick to basic SOLID principles.
See you later
This post was part of the 2 post series. In the first post we discussed the Two Major benefits of the
Micro-Services in details and how they are not exclusive to the
micro-services and then we discussed the theory about the what core
SOLID concepts actually help with
Deployability of the code. Then in this post we looked at the example using an interesting application. It’s time for me to say goodbye will see you soon with some other post. Enjoy your life and Be humble. I will see you soon new post.