Unlocking the potential of Microservices

Yaroslav Chykhut
Newsoft Official
Published in
5 min readDec 1, 2023

The evolution of software development never misses a chance to surprise me. Developers all over the world, just like me, have witnessed how it shaped the way we design, build, and maintain complex applications. From monolithic systems to modern microservices, software architecture has transformed significantly.

Brief history

The rise of microservices takes us back to the late 1990s, when in 1997 the Enterprise JavaBeans (EJB) specification began and laid the foundation for the component-based software development. Later, the service-oriented architecture (SOA) provided a structured approach to building scalable and interoperable systems. Moving on to the early 2000s, the concept of Representational State Transfer (REST) changed the way web services interact by simplifying the communication between distributed systems. The era of Agile and DevOps practices established agility and collaboration in software development in the mid 2000s.

In 2011, at the Software Architecture Workshop, Gartner Conference, the discussions on microservices began and it led to the formal adoption of the term “microservice” in 2012. In the same year, the tech giant Netflix made microservices a key part of its infrastructure, highlighting the relevance of the approach in managing complex systems.

Escaping monolithic hell

Monolithic architecture put us, developers, into a “monolithic hell’ as there were multiple evident challenges, such as:

  • Complexity of the codebase
    The bigger the codebase, the more challenging and overwhelming it was to develop and maintain
  • Slowing down development cycles
    As monolithic application require all-or-nothing deployments, the development cycles were often slowed down
  • Time-consuming deployment process
    As there was a need for extensive testing and quality assurance, the deployment was time and efforts-consuming
  • Challenging scaling process
    Scaling a monolith often required scaling the whole application
  • Outdated tech stack
    The lack of opportunities to modernize and innovate due to the outdated technology stack
  • Complex process of delivering a reliable monolith

Facing a lot of issues, developers were eager to find an alternative solution that would suit their needs perfectly. That alternative was microservices, designed opposite to monolithic architecture, as they are:

  • Independently deployable
    The development, testing, and deployment of each service is performed separately reducing the risks
  • Loosely coupled
    Services interact with each other with the help of APIs minimizing dependencies and allowing flexibility
  • Organized around business capabilities
    The organization of microservices is based on specific business functions, simplifying the alignment of technologies and business goals
  • Owned by a small team

Advantages & Disadvantages of Microservices

Microservices were the answers to a lot of issues faced during the development process. They brought to projects such advantages as:

  • Continuous delivery and deployment
  • Small and easily maintained services
  • Independently deployable services
  • Independently scaling services
  • Autonomous teams
  • Easy experimentation and technology adoption
  • Better fault isolation

Even though the adoption of microservices brought a lot of improvements, yet there are a few disadvantages to mention:

  • Challenging service selection
  • Complexity in distributed systems
  • Coordination for feature deployment
  • Difficult decision on adoption

Decomposition Strategies

Another challenge that comes on developer’s way of successfully implementing microservices is deciding how to decompose a monolithic application into smaller, therefore more manageable services. There are several decomposition strategies:

  • Decompose by business capability
    Business capability is the thing that business does to generate value, for example order management, consumer management, or accounting
  • Decompose by subdomain
    Domain-driven design (DDD) is a methodology that involves dividing complex systems into subdomains and bounded text. Each subdomain may require a separate domain level. The same business capabilities should relate to the same domain
  • Single Responsibility Principle (SRP)
    When a business rule changes, developers only need to change code in a small number of packages
  • Common Closure Principle (CCP)
    A microservice should have only one reason to change

Selecting the decomposition strategy should depend on the specific needs of the project, organization’s structure, and the target level of service autonomy. When selecting, be aware of the possible challenges:

  • Network latency
    Can effect system’s performance because of the large number of round-trips between two services
  • Reduced availability due to synchronous communication
    Adopting asynchronous communication patterns helps decouple services and fault tolerance
  • Maintaining data consistency across services
    Implementing Saga pattern helps provide a mechanism for managing distributed transactions and ensuring eventual consistency
  • Obtaining a consistent view of data
    If you need a consistent view of some data, then it must reside in a single service which prevents decomposition
  • God classes preventing decomposition
    Breaking down God classes into smaller and focused components might help to solve the problem

Navigating the challenges while implementing decomposition strategies is crucial for microservices architecture. It is important to remember that while there are already known and established ways to handle them, there are challenges that might require tailor-made solutions.

Synchronous Remote Procedure Call (RPC)

Synchronous RPS is a commonly used method for establishing communication in microservices. One service makes a request to another device and waits for the response. While some consider this method straightforward, others believe that it can lead to some performance issues.

  • Representational State Transfer (REST)
    A style that uses standard HTTP methods for communication between services.
  • gRPC
    A framework developed by Google, it uses Protocol Buffers and offers features like bi-directional streaming and efficient binary communication.
  • API versioning
    Crucial for ensuring backward compatibility while introducing new features or changes.
  • Network timeouts
    Handling network timeouts helps prevent service degradation or failures.
  • Limited number of tries
    Combined with network timeouts, prevents service overload and failures.
  • Circuit breaker pattern
    Is a must-have for system stability and block further requests to a failing service to allow for recovery.
  • Service discovery
    Service discovery tools such as Consul and Eureka help locate and connect to available services.

Asynchronous messaging patterns

Asynchronous messaging patterns are vital in establishing decoupled, scalable, and fault-tolerant communication between services. There are two key approaches:

  • Broker-based messaging
  • Brokerless messaging

Broker-based messaging (ActiveMQ, RabbitMQ, Kafka)

Advantages:

  • Loose coupling
  • Message buffering
  • Flexible communication

Disadvantages:

  • Possible performance bottleneck
  • Risk of a single point of failure
  • Additional operational complexity

Brokerless messaging (ZeroMQ — TCP, UNIX-style domain sockets)

Advantages:

  • Allows lighter network traffic and better latency because of direct communication
  • Eliminates the possibility of the message broker being a performance bottleneck or a single point of failure
  • Features less operational complexity

Disadvantages:

  • Services need to know about each other’s locations
  • Implementing mechanisms, such as guaranteed delivery, is more challenging

Additionally, there are three concepts worth mentioning:

  • Message ordering
    Ensuring the correct order of message process
  • Handling duplicate messages
    Prevents issues caused by duplicate messages
  • Transactional messaging
    Provides all-or-nothing semantics for distributed operations in microservices

It goes without saying, microservices do benefit software development and will stay with us for sure, as they leave a space for flexibility, scalability, and resilience. Using the principles, patterns, and strategies will help developers and architects harness the full potential of microservices by building more reliable and adaptable software systems.

--

--