Service-Oriented Thinking

TL;DR Contrary to the common belief, proper conceptual decomposition of large software solutions doesn't require any particular architecture patterns in place. Being service-oriented doesn't necessarily enforce any constraints on...

6 months ago

Latest Post Mixing warsaw.ex by Sebastian Gebski

TL;DR Contrary to the common belief, proper conceptual decomposition of large software solutions doesn't require any particular architecture patterns in place. Being service-oriented doesn't necessarily enforce any constraints on build or deployment - it's a matter of proper, highly aware design which can't be conducted in a correct way without proper understanding of concepts like: capability, boundary, identity & role exclusiveness.

Disclaimer 1: this is not a post about microservices, this one is about importance of design & proper decomposition of problems you're facing.

Sometimes these're the most "obvious" topics that cause the most confusion. The concept of service belongs exactly to this category - the word "service" is very frequently used in many work-related situations, but it seems that we (IT people) vary in terms of our perception & understanding of what service is (should be?):


I'm certainly not going to claim that I know the best definition, in fact I'm not even going to convince you to anything. The only goal here is to share the version of the concept of service that I personally find most beneficial in everyday's work. I encourage you to read through, confront it with your own beliefs/opinions & use your own judgement whether you can take anything beneficial out of it.

Disclaimer 2: I'll focus on concept of service in on-line systems/applications. For the sake of simplicity.

Service Commandments

Why don't we try to define "service" with a list of striking one-liners that hopefully do not leave much to interpretation?

C1. Service is a design construct, not a code pattern.

Yes, we (should) start defining services even before making a decision of what kind of technology will be used for the sake of implementation.

Example: in this system some users will be booking the cinema tickets, some will update what are the forthcoming premieres, etc. As different concerns, these are candidates for separate services.

C2. Service is an abstract in model that represents the capability.

Probably the most crucial statement to understand the concept of service. In IT solutions actors (automated, human) have their capabilitites - sets of abilities they can perform. On the higher level these capabilities may together form roles, positions, etc. but basic capabilities are still there, under the hood. Capability ain't just a single action that can be performed - it's a set of actions (mutating or not) that are coherently oriented around some distinguished concept (& data that are depicting this concept only).

Example: cashiers have capability of issueing the ticket, clients have capability of creating a new order, offer managers have capability of adding new movies to the catalogue.

C3. Service'es capability has to be exclusive within (bounded) context.

Within a given bounded context (part of model that serves particular sub-domain) each capability should be laser-sharp: there can't be two parallel capabilities that manipulate the same information in a different manner - this would cause a risk on incoherence & watering down the responsibility of a service. If needed, slice your services more finely, but keeps each service's clear identity (so everyone knows that XYZService is a one-stop-shop to do stuff with XYZ).

Example: Imagine 2 services used to sell & issue cinema tickets - one is for on-line sale & the other one for Point-of-Sale one, if these 2 are designed & implemented separately, how do you make sure that the concept of ticket (in the end there's just a ticket in customer's "hand") maintains the same inherent qualities in both cases? Maybe the details of different sale process should belong to dedicated sales services (OnlineTicketSale & PosTicketSale) & issuing of tickets to another one (TicketIssuing)?

C4. The only part of Service visible outside it its contract (API - with the outside work), everything else is an implementation detail.

Everything else: implementation (algorithms, processing logic), data structures (data model, database content incl. business parameterisation), etc. The word "contract" is absolutely crucial here - service contract is both your agreement & commitment in the same time:

Example: It does NOT matter that ticket DB table does have a column "valid until" as this one is NOT exposed in services contract -> it means that no-one but service implementation is allowed to manipulate it in any way. Service contract can expose this information in a another way (e.g. as "is still valid" property) - no-one (of the service consumers) should care about how it's implemented - it's the part of aggrement+commitment deal that you take what contract exposes for granted, as a single source of truth (for this capability).

C5. Services are building blocks of higher level capabilities (which are also Services)

Conceptually: atomic interactions, when orchestrated properly, build up more complex interactions like workflows & processes. This doesn't conflict with capabilities of these atomic interactions as they are not overwritten, neglected or even "enhanced" - higher level service just utilises them as they are.

Example: You can do various stuff with a single note (money one) - spend it, tear it down, roll into a ball, ... These are capabilities of a note (every note as it's a standardised object). Think about a wallet (a physical one) - it collects several notes - you can shuffle them around, sort them, etc. but to do such operations you still need to "call" atomic operations on individual notes (pull out 5 bucks note, align it so the dead president face is at the top, insert it in the beginning of the note stack).

C6. Capability exclusiveness doesn't equal to information exclusiveness

Data redundancy to the rescue! The same information can be represented (across whole system/platform) by several, separate physical representations - if you've heard about CQS/CQRS you probably already know what I mean: primary (transactional) service that performs writes can trigger system-wide events which will populate mutated data to many, specialized read-only data stores that power read-only services responsible for non-transactional capabilities (reporting, exports, analysis, etc.). This can also be covered by batch or native replication, etc.

Example: You've designed a system built around the concept of customer - customer has a lot of specific information oriented around different capabilities: his interest, connections, customisations, physical locations, market segments is qualifies to, etc. You want to create a heavy-duty dashboard with the most important 1-2 data quanta from all these capabilities - does it mean you have to refer to all these services separately?

Original services are still responsible for the original capabilities (& they remain origins of truth within their areas), but what they additionally do is publishing the event that particular piece of data has been updated, so some specialized read-only service (e.g. one responsible for dashboard only), that subscribe for such events can keep their information (separate, duplicated one) up-to-date. Such service's capability is ONLY to serve aggregated information for dashboard.

What's in it for me?

OK, these principles are just like any other principles - they look good on paper, they don't seem to contradict (hopefully), but what's the point, what's the gain?

The gain gets visible once you use service as a mean to tackle domain complexity: slicing domain into capabilities (hierarchically, until you get down to atomic, low-level ones) is a very flexible top-down decomposition method:

Words of warning

The concept of service is deceptively simple, but the devil is certainly in the details. Building a good service is NOT an implementation challenge, it's definitely a design one (I can't emphasize it much enough!):

Final word(s)

I work on building software products for nearly 20 years & if I had to name Top 5 challenges I've encountered during all my professional endeavors, scaling out the complexity & functionality (in terms of how many capabilities platform serves - on other words: how feature reach it becomes over the time) would clearly be on this list. In my personal opinion (I can underline that with full conviction), there's no better way to deal with this problem than hierarchical service/capability decomposition.

Sebastian Gebski

Published 6 months ago


Leave us your opinion.

Subscribe our newsletter

Recieve news directly to your email.

No Kill Switch © 2018.