Fredrb's Blog

Microservices and Object Oriented Programming

Sam Newman defines in his book Building Microservices (2015) that there are two key traits that make a good service in a Microservice Design: (1) Loose Coupling and (2) High Cohesion. These two traits have been previously raised in the context of Object-Oriented Design by authors such as Robert C. Martin, Martin Fowler and Sandi Metz. But what makes Object-Oriented Design and Microservices converge into these two design principles? The simplest answer can be: Message Passing. Both Microservices and Object-Orientation have Message Passing as their core for communication between its atomic entities. Where atomic entities is the cellular like organism that lives in each paradigm, being Services for Microservices and Objects for Object-Oriented Programming.

Integrating Services

In this article, I intent to focus on the 4th Capther of Newman’s book named Integrating Services. In this book, Newman walks us through different integration patterns for Microservices and the best and not-so-best way to implement Service-to-Service communication. Here are some points Newman highlights in this chapter:

References to Object Oriented Design

Keeping in mind the comparison between Microservices and Object-Oriented Design, we can leverage years of wisdom on the OO Design front when creating Microservices. When it comes to design principles there quite a few things that we can corroborate with Newman’s points above. The idea of message passing is in the roots of Object Oriented design. It’s even mentioned by Alan Kay it should have been called Message-Oriented programming due to it’s focus on passing message between cell like structures.

Law of Demeter: It illustrates how our objects don’t need to be exposed to more information than they need. There is a good article by David Bock’s that explains the Law of Demeter very well. This law specifies that he must provide real world abstractions that makes sense in our code. These interfaces are easy to use and they don’t expose more of the internal behavior than it’s needed for the consumer to do it’s job - or better - to send it’s message.

Liskov Substitution Principle (LSP): In his Book Clean Architecture (2018) Robert C. Martin provides an example of LSP at the architecture level by two services that provide the same API for Taxi ordering (Acme and PurpleCab). Even though they respect the same URI format for locating resources (e.g. GET /driver/<id>) and for posting driver’s pickups (e.g. POST /driver/<id>/pickupRequest), they differ in property names, for example, PurpleCab expect destination and Acme dest as a property on the POST request. This could even be more subtle by having the same property name but different data structure. The problem is that now the consumer must identify who is the receiver in order to create the proper message. This is a smell when discussion Object-Oriented Inheritance. But as shown in the Martin’s book example, this can be applied 1:1 to REST APIs.

Dependency Inversion Principle (DIP): The idea behind this principle is to hide the concrete classed under abstractions. All references and message passing must be done through it’s abstraction (i.e. Interface or Abstract Class in Java) and not to the concrete class itself. This way you can provide Stable Abstractions and avoid major changes in consumer when making changes to the concrete implementations. In my opinion, the structure of a Service must follow a similar pattern. The interface to interact with a service must be its stable interface and the implementation details are hidden inside the Service. Taking this principle even further, consumers must depend on a stable interface of that service, and the Service that is implementing that interface should not matter to the consumer. This means that if we want to re-implement a service in another programming language or a different framework providing the same interface, we can easily change the receiver’s end without even informing the consumers. Making our Services loosly coupled, technology agnostic and independently deployable.

I think all of the SOLID Principles offer good insights to designing loosely coupled and highly cohesive services, but I’ve highlighted the two above because they seem to be closer to the points that Newman brings in his books.

Integration Patterns

In Newman’s book, he mentions a few integrations patterns found in Microservices-based architectures.

1. Shared Database: The simplest way to integrated services - by having the same data storage.

2. Service-to-Service Communication: It gets a bit messy with definitions here, but what I gather is that is comes down to two different characteristics, regardless of the technology used:

Synchronous vs Asynchronous

This point comes down to either services calling each other directly, or communicating through a message queue. Regardless if services communicate with each other view RPC or HTTP, request/response style communication is simpler but limited. Any service that receives a request and then send requests to a dozen other services is likely to be a bottle-neck to the original caller. Message Queues allow consumers to not tie themselves to the receivers (i.e. open socket or waiting for an HTTP response). It does, however, increase the levels of complexity significantly by having to place Queues for Service-to-Service communication. As the author puts, it comes down to changing how you approach messages sent. It goes from “these things need to be done” to “these things happened”. Asynchronous communication is event-driven communication.

Orchestration vs Choreography

These concepts are not coined by Newman either, in fact, it’s something inherited from SOA (Service Oriented Architecture). I’ve found a few articles from early 2000’s explaining these. The concept can still be applied to Microservices as is, as Newman states, they are styles of architecture. Orchestration is where you have a central decision maker, who delegates activities to mindless workers who are task driven. This is very similar to a Primary-Worker threads or Client-Server communication in Networking. Where Choreography is when you have mindful services who can act and decide on themselves and communicate with other services. These services are like actors in a play, each have its role and they rely on their fellow actors to play their part accordingly. Much like a P2P communication.


We notice that orchestration goes hand-in-hand with synchronous communication and choreography does the same to asynchronous. This shows the reader how not only there is some sort of a link between the two but they form sort of a maturity model of Service-to-Service communication. It’s reasonable to assume that the author is showing that Asynchronous-Choreography based systems are more complex but more mature from a Microservice perspective.

Event-based collaboration is also highly decoupled

I have found that systems that tend more toward the choreographed approach are more loosely coupled

Those two quotes from the book resonate to the mantra of Loose Coupling and High Cohesion, which defines a well designed services. I get it there are reasons why you’d create a synchronous service, specially for the sake of simplicity. But even though, in the long run, if you have a big application and it needs to be maintained, asynchronous and choreography should be what stands for a well designed architecture.

Object Oriented Affordences

The last point I want to talk about is something Sandi Metz have said on her talk Polly wants to send a message. In this great talk, she offers a few hihglights on OO design (like Churn vs Complexity by Michael Feathers), but one major point is when she mentions Affordences we have to make when developing with OO. They are also incredible close to how Newman expects Microservices to be. Here’s the list of Affordences:

Conclusion

There are design gems in the years of knowledge of building Object-Oriented Systems that can be adapted and re-applied to new challenges of Software Architecture. Given that the atomic entities of each paradigm (Services and Objects) are treated equally, these design principles can be used almost interchangedly in a Microservices based application. This doesn’t mean that services must be written using an Object-Oriented programming language, far from that. What it means is that how you structure the communication between Services via message passing is similar to how you structure the communication between Objects. The code that lives in Service itself is a whole different universe, which can be its own isolated box in any technology and design that is the best tool for the job it’s trying to solve. As much as the same principles can be applied to the Micro level if the service is using an Object-Oriented language, it’s irrelevant to how they are being consumed.

References

Sam Newman:

His books: Building Microservices (2015) and Monolith to Microservices (2019)

Bounded Context:
Object Oriented Design:
Orchestration and Choreography:

#ramble #oo #cloud #microservices

⇦ Back Home | ⇧ Top |

If you hated this post, and can't keep it to yourself, consider sending me an e-mail at fred.rbittencourt@gmail.com or complain with me at Twitter X @derfrb. I'm also occasionally responsive to positive comments.