At the very beginning of designing a system there are a lot of assumptions and predictions about the traffic, load and performance needs. Sometimes you may even have more questions than answers. What if you know that you will need a microservice architecture, but you do not know how to divide your business requirements into small, independent services? Actually, starting building microservices architecture does not mean starting building microservices. There is an option that you may like.
There is an approach that leads to microservices architecture, but starts with a simple monolith application. The most important thing is to create monolith design that enables you to extract each piece of business logic to a microservice very smoothly. What is more Java is natively designed to be used that way.
Sounds good... then how?
It’s all about access modifiers and encapsulation. Those two ideas play together. There are 4 (not 3!) access modifiers in Java: default, public, protected and private. This language also provides three levels of encapsulation: class, package and module. This knowledge is enough to implement assumptions listed above.
Firstly, we have to divide the business logic into packages. Important thing here is to perform this division by business responsibilities and place all related logic (classes) in one package. Packages should not be large if we divide them smartly. This is how encapsulation plays its role. We encapsulate every part of business logic to a consistent package and all related and needed information in there. If you want to change something in shipping you go to the shipping package. When you need to change order logic you go to the order package. This idea is illustrated on image below.
Second aspect is to keep the business package independent as much as possible and this means to keep as restricted access to the classes and methods as possible. We can achieve this by using default (package) access. Almost all of classes in the package should be package-private. As well as the methods they expose. Of course, we need a public interface (facade), exceptions and data transfer classes, but this is all we need to be public. General access schema is provided below.
This very basic concept of Java applications design, usually is not used, but enables us, developers, to extract each package and create a new standalone microservice with a very little effort. Everything needed for new service is included in the package. All you need on client side is to implement the interface exposed by new remote service and call it via web instead of invoking method within the same application.
Spring Framework also supports this kind of application design. Spring works correctly with classes that have default access and registers them in the context as beans. What is more, not all of your classes have to be Spring beans. Only the ones that are used in other packages (facades / controllers) and the rest of needed classes may be instantiated in each package configuration class. This gives developers more control on application behaviour and its configuration, but also decreases number of beans in the context.
Described approach empowers the system’s architecture with the flexibility and scalability. Each part of application may be easily extracted and scaled up when the usage of them increases.