

Discover more from INUVEON
Microservices Journey — A Practical Guidance Part I
Microservices Journey — A Practical Guidance Part I

How to Create a Online Store using the Microservices Approach
In this series of articles I would like to report on my longtime experiences in the development of complex systems using the microservices approach, but also using cloud services and cool technologies like Spring Boot, Kafka, Kubernetes, and NextJs. I call it a journey because in this series of articles you can accompany me on my way to develop a new platform. I will use proven patterns and technologies, but also try out new things for me. The most parts of this project will be available on GitHub as OpenSource.
In the last few years I have spent a lot of time in projects to establish and apply microservices, if it was suitable. Of course, this has meant learning, trying, rejecting, rethinking and constantly improving. Now I use my knowledge in a new project and make my experiences publicly available and let you participate.
This first part of the article series focuses on identifying the requirements, discussing the basic approach and to create a first architectural sketch.
In some parts of my journey I describe things as I want to realize them. So it may well happen that I discuss and rethink them later.
About Microservices
Modularization is nothing new in the development of software. Most approaches in the past were concerned with cutting software into smaller modules and structuring code. If, for example, one thinks of layered architectures, the software is technically well structured, but technical concerns cannot be derived from it. Class libraries play an important role in the world of object-oriented design. These also make it possible, under certain circumstances, to separate technical things very well. If in this classical approach a domain-oriented module is updated in the form of a class library, a complete deployment of the application is necessary. Therefore, this approach is called deployment monolith.
In addition, it has been shown in practice that adhering to module boundaries is very difficult with monolithic applications, since due to time constraints, classes from other Java packages or .NET projects are often quickly used. Dependencies can thus unintentionally arise quite quickly.
Talking about Modularization in the context of microservices means that independently deployable modules are created. Microservices have their own source code projects. The interfaces between the microservices are implemented as REST interfaces. This prevents dependencies from creeping in so easily. Compliance with the module limits is therefore forced by the architecture without the need for additional tools.
Microservices lead to increased complexity in operation and testing. This additional complexity is offset by the advantages described in the following chapter, such as better modularization, stronger decoupling, and independent deployment.
In my point of view, when we talk about microservices, it is implicit to talk about automation, that means: container orchestration, automated application deployment, scaling, and management. Since more than three years I used Kubernetes as a proved platform to run and scale microservices in all stages in the software life-cycle: development, testing, and production.
The Idea
I would like to develop an online store that can be used as quickly as possible and can be expanded at any time without major risks. The inclusion of further developers should be possible at a later date without great effort.
Another point is that the store should not be developed specifically for a particular industry, but can still be expanded for specific requirements by choosing a microservices architecture.
Designing Roles and User Stories
We basically have two different views to the system, resulting in the following two roles:
Customer
The role Customer means user of the system who can order articles.
Retailer
The role of Retailer refers to users of the system who offer, sell and ship items.
Let’s write a few user stories to get started.
In a first step the following user stories should be covered (no claim to completeness):
As a Retailer I want to login/ logout to the system.
As a Retailer I want to create a new product.
As a Retailer I want to edit an existing product.
As a Retailer I want to list all products.
As a Retailer I want to mark products as featured.
As a Retailer I want to hide products.
As a Retailer I want to have an overview about all orders.
As a Retailer I want to see and change the status of an order.
As a Retailer I want to modify the stock of a product.
As a Customer I want to search for products.
As a Customer I want to see details to a product.
As a Customer I want to add/ remove products to the basket.
As a Customer I want to order one or more products.
As a Customer I want to create an user account.
As a Customer I want to login/ logout to the online store.
As a Customer I want see all my orders.
As a Customer I want to be able cancelling an order in case the order isn´t shipped yet.
As described before, I want to divide the business logic into several small services, which are as completely independent of each other as possible. The communication between the services should be asynchronous, if possible. A service should represent a small business unit. The goal is to get only a few of the user stories or features defined above into a service.
Service Design
Our entire application should be divided into loosely coupled, independent services, each modelled around a business domain. Each microservice is independent and has a clearly defined business boundary that can be independently developed, tested, deployed, monitored and scaled. Services can basically be developed in different programming languages and using different technologies. Each service has it´s own specific data model that reflects the business requirements. It´s important that the code and data structures of a microservice is NOT shared with other services.
If the microservices exist as autonomous instances and each of them provide REST interfaces, it naturally seems very fragmented and not very homogeneous for consumers such as an SPA. It does not feel like one system.
Service Routing
For this reason, we will use an API gateway to enable access to each service via an endpoint. Since I am planning to roll out the services on Kubernetes, we will use an NGINX to allow access to the container instances from outside.
What is an API Gateway? An API gateway is a reverse proxy that forwards requests to the endpoints of the internal microservices. This simplifies routing from the client’s point of view, as only one endpoint needs to be set up. Essential tasks of the API gateways are service discovery, routing and security.
Service Discovery is the process of automatically discovering which instances of services meet a particular query. This means that if docker containers are started and stopped, the routes on the API gateway must be updated.
Architecture Overview
I am a great friend of making things clear and comprehensible. For this reason, I would like to give an overview of the necessary components and technologies based on the user stories described above and the general conditions and requirements for a resilient architecture, using an example.

The picture above shows two microservices (based on our user stories) running on a Kubernetes cluster. This microservices are not public available directly. For all the incoming traffic from outside the Kubernetes cluster we use a Load Balancer. We use the NGINX as an ingress controller. That means, from a client perspective (i.e. a web frontend or a mobile app) our services appears as one application. We have to define ingress rules for the NGINX that the request from outside will be routed to the desired internal microservice.
In a later article I will go into more detail about Kubernetes concepts. At this point I will present the Kubernetes components in a simplified way. In another article of this series we will also take a closer look at routing, NGINX and Ingress.
Currently, we will take a closer look at the first two microservices, which we will create as examples.
These will initially cover three user stories that we defined above.
As a Retailer I want to create a new product.
As a Retailer I want to list all products.
As a Retailer I want to modify the stock of a product.
Since I would like to avoid that the services communicate directly with each other, the communication should be event-based and use a Kafka as message broker. Basically, this means that significant events that occur within a micro service create events and publish them on the Kafka. Interested parties (consumers) subscribe to events and process them within their context.
In concrete terms, this means that the Product Service creates and publishes an event when a new product has been successfully created. The Stock Service can react to this by subscribing to this event and writing a new entry with stock 0. The Stock Service itself provides a route for updating stocks. When the inventory of a product is updated, the stock service creates and publishes a StockUpdated Event. This in turn is subscribed to by the Product Service. The Product Service reacts to this event by marking the product as “available” or “not available”.
Next, we want to implement this features and try it out locally.

In the next part of my series we will start implementing the first two services as disccussed.
If you have any suggestions or questions, I am of course very happy about every feedback.
Microservices Journey — A Practical Guidance Part I was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.