Services, Microservices, and SOA... oh my!
Summary
A Little History
The earliest OSIDs were based on a simple architectural principle. Define an interface to abstract away the technical details of its implementation. By doing so, multiple implementations using different technologies can be used for the same functionality. This kind of service-oriented architecture (SOA) wasn't a new concept.
Then came web services. This included the premise that the interfaces are always used over HTTP. So popular was the movement that SOA became equated with the web.
With the number of failed SOA projects out there, the three-letter acronym eventually became a four letter word. Lately, there seems to be an attempt to rebrand SOA as microservices.
Everything Looks Great on a Whiteboard
SOA, like any other methodology, has been pitched with a simple philosophy and promise of great rewards. There are wikis, books, and workshops that walk us through unrealistically simple examples (customer buys a product) adorned with colorful rectangles and XML schemas so beautiful a non-technical person could follow.
With the most basic of training the new service architect is dumped into a project with a budget, deadline, and a development team that has already decided how they are building it. When the first models and service contracts are produced, they don't hold up to the product requirements and don't deliver performance expectations. Idealism and delays give way to hacking the interfaces. Eventually it is decided that service interface design should be put off until the code is written. The result is a mishmash that would have been better off never having attempted the service architecture in the first place.
It's Always Been About Decomposing the Problem
A service-based methodology requires breaking down a problem into its atomic parts. This is done through entity modeling. The problem of hotel reservations is decomposed into customers, rooms, events, and credit cards. The problem of managing these entities is decomposed into retrieving, updating, organizing, and notifications. The problem of the underlying system is decomposed into authorization, authentication, logging, messaging, commenting, tracking, and workflow. Just to name a few.
Instead of having a monolithic system, a service-based approach uses dozens of contained (or micro) services. The complexity of the monolith shifts to a complex orchestration of services. Nothing will make a complex problem simple. Think of it as conservation of complexity.
The reasons for making this shift are to:
- promote a one-service-at-a-time incremental development approach
- promote reusability of services
- promote parallel development
- simplify testing
- limit exposure and risk of thick infrastructure
The Fine Print
Adopting any methodology, whether it is a management methodology, a development methodology, or this methodology, requires a change of practice and mindset. Do you know of any teams that have daily stand ups and yet are not agile? Jumping into a methodology without understanding what's needed to make it successful can be worse than not doing it at all.
Using an architecture based on highly decomposed services creates new design problems that cannot be solved using monolithic approaches. It requires that development activities are focused on one service at at time.
Why Does SOA Have a Bad Rap?
Unstable Interfaces
The premise of a contract, like any standard, is that it is stable and doesn't change under your feet. Service contracts evolve slowly without having to spend most of your resources keeping up with the change of the day.
What causes service contracts to be unstable?
- Synchronizing the design of service contracts with development iterations. Development iterations are performed on features and technical debt management. Service contracts designed on this short timescale will need frequent refactoring. Being agile with service design should not be mixed up with agility in development. These are separate agile processes with different frequencies.
- Inexperience in the problem domain.
- Fear of not being agile enough. Services contracts are stable when the models capture enough detail and nuance that model refactorings are rare. This requires including those services & entities which are needed in the foreseeable future.
It's a New World
Where what worked in the monolithic world does not work here. It can be culture shock for newcomers.
- What do you mean I can't join these two tables?
- Why can't I do everything in one service call?
- I'll set a topic name and the other side will know what I mean.
- It will be more efficient to pass the object instead of just the Id.
- How do I tell the service what configuration to use?
For those programmers who enjoy encapsulation and boundaries, this isn't much of a transition. But it will be a struggle for programmers who are accustomed to make it work at any cost.
The Aura of Complexity
Complex things are complex. All we can do is move that complexity around. In a service-based architecture, the multitude of services and interfaces absorb a great deal of the complexity that is typically squirreled away in other parts of a system. Yes, services add a great deal of complexity that wasn't there before. It absorbed that complexity by simplifying application and system components.
Crossing The Streams
Working with services should be like working with black boxes. You see the outside of the box (interface) but should have no clue as to the inner workings. However, in many development projects, the same developer is working on a functional slice from the application on through the service stack to the backend. The service contract will always appear as the impediment between the developer's right and left hand. If the service contract is also in the purview of the developer, expect it to be optimized for what the developer needs to do at the cost of other uses.
Association With Web Services
Service contracts are meant to separate and standardize components of a system. A complex system may have hundreds of components. Not all of these components need to talk to each other via a remote protocol.
How Do OSIDs Fit Into This?