The week began as busy as ever. And then I learned that one more task — beyond everything else on my plate — must be accomplished. Which task? The one you are reading. Why?
On Being Confused: MicroservicesTo say the least, the word Microservices became a source of confusion even more quickly than its use became hype. Since then it has moved on to trend and possibly even defacto standard for service architectures. Funny thing, this. It seems many hype, follow, promote, and hype and promote more, but without a clear definition of intended use. Why? It has a lot to do with the software “thought leaders” that we listen to. Our point of view is shaped by our world view, but also by the leaders that take ownership of definitions. You will often find that different vision and thought leaders have different views and messaging, and that is very much the case with Microservices. So then, to which leaders should we listen? I suggest that you take in a number of definitions and guidelines. Additionally, I strongly suggest working by definitions that are less radical, dogmatic, and critical about arbitrary constraints, as if the constraints themselves prove correctness and value. I am of the strong opinion that Microservices are definitely a case where one size does not fit all. As I tweeted earlier today, I really have no problem with the word Microservice. My take is that it’s about purpose and cohesion. Microservices should not be defined by a predetermined size metric, but rather by necessity to achieve a purpose. Following a purpose leads to useful cohesion.
So What?Going back five years and more, I’ve had a few different overarching thoughts about the term Microservices. The first formative thought I had was something such as: “So what?” I have been working on smallish services for much of my career, a career that spans 36+ years and a lot of different business domains. Many of my experiences are around separating software by what it does, and it usually does one or a few things well. Whether it has been with modules, plugins, components, local or distributed, whenever I had a significant influence on architecture, every part of the software has had its place in the architecture. Herein I refer to all of these modules, plugins, and components as services for the sake of keeping the discussion on topic. Thus, “So what?” is not a rejection of the word Microservices. It’s a sentiment toward seeing a new name for things I have done for a long time.
Size?My second thought aligns with my first thought, but this thought is definitely critical: “Size?” What I never worried much about in developing software was the size of a given service. As I wrote in my book Implementing Domain-Driven Design, a given service is as big as it needs to be and no bigger. I also specially wrote about microservices in my book Domain-Driven Design Distilled. Here is a blog post, Reactive Microservices, from some years back, which is a close reflection of an e-zine article I wrote the year prior to it. That comes from my mindset that biases toward cohesion for a reason (hey, that rhymes). Sometimes I would survey the size of my code by line count, but that was just a matter of interest. I don’t remember ever having a reaction to lines of code to judge the value or worthiness of the service I had implemented.
The ProblemsOne problem with the contemporary implementation of services from the beginning was lines-of-code count being the end, rather than the means. That’s not only a problem. That’s a big problem. It means that if your service lines-of-code count is ±N, its correctness and value are questionable. A second problem isn’t explicitly questioning lines of code, but still asserts size as a critical measurement. It’s most easily described by a name: Entity as a Service. This is a service that implements a single software model concept and no more. The modeled concept may not actually be an Entity. It may be some sort of calculator or other kind of processor, but let’s say it’s anything that you would normally otherwise think of as one object doing something in behalf of another object within the same runtime process/instance. In such a case there is no network in between the two objects because it would actually be wasteful to place a network boundary there; that is, unless the network boundary is the end rather than a means. I think we should take a lesson from another use of the word micro as the prefix in a compound word: Microprocessor.
On Being Schooled: Microprocessors
I think it is notable that there has been little if any argument and dissent about the definition of Microprocessor. Here is one worthy definition found on Wikipedia. I’ve used the Simple English edition.
- 4-bit designs: This was the design of the original commercially available microprocessor, the 4004, produced by Intel in 1971. It’s cost was $60 and was used in calculators. At roughly the same time, Texas Instruments developed its first microprocessor used in a desktop terminal (very early PC).
- 8-bit designs: There is an interesting story around how Intel produced the 8008, the first 8-bit microprocessor. It was used by the Mark-8 microcomputer in 1974. This was followed by the 8080.
- 12-bit designs: This design had limited use.
- 16-bit designs: Includes the Intel 8086, the 8088 used in the first IBM PC, 80186, 80188, and the more popular 80286. The 80286 provided protected mode, which was necessary for running true multitasking and multiprocess operating systems. Protected mode prevents one process from overwriting memory (e.g. stray pointer outside the process’ address space, or a memory write with incorrect bounds) and stomping on other processes.
- 32-bit designs: Includes 80386, 80486, and the 80586, known as the Pentium. The 32-bit microprocessors continued through the Intel Core and early Xeon.
- 64-bit designs: Intel began its designs with Itanium and a new Pentium, and then several generations of Intel 64.
- large and small household appliances
- cars (and their accessory equipment units)
- car keys
- tools and test instruments
- light switches/dimmers and electrical circuit breakers
- smoke alarms
- battery packs
- hi-fi audio/visual components
- cellular telephones
- DVD video system
- HDTV broadcast systems
- IoT devices
Purpose-Built MicroservicesThe size of a microservice should not be a goal. Rather, it’s a result. Similar to a microprocessor, a microservice serves a purpose within a set of runtime constraints and SLAs. Depending on the purpose, constraints, and SLAs, the word microservice might mean different things. Just like with all things DDD, when you change the context, you change the meaning of any given word.
Start Off With Bounded Context as MicroserviceI’ve been giving this advice for quite a while. Using a Domain-Driven Design (DDD) Bounded Context as the initial “measurement” of a microservice is a great place to start. A Bounded Context is not arbitrary in size. Again, as I have pointed out for quite a number of years, a Bounded Context is the size of its Ubiquitous Language codified in a domain model, and with supporting components for UI and/or REST endpoints, database access, and possibly a messaging mechanism. The key here is Ubiquitous Language. A Ubiquitous Language is developed by a team of one or more business experts and developers. You constrain your Language to solve a specific problem that provides core business advantage. Sometimes you might use DDD, or at least some strategic tools of DDD and possibly Domain Events, in microservices that support the core. Thus, the core and any supporting and even generic subdomains would generally all be different microservices. I have written a lot about what constitutes a Ubiquitous Language, so I won’t go into that in detail here. Even so, I will say that a Ubiquitous Language is typically not tiny, but also not very large. It focuses on a single core business value. The concepts of a single Ubiquitous Language is what drives the natural cohesion of components found in single service. It is probably much like what Gergely Orosz of Uber considers “wells-sized services.” Yet, note again that I said that Bounded Context “is a great place to start.” This means that if you deliver your Bounded Context solution as a single deployment unit, this is a great position in which to begin. You won’t have a monolith, but you also won’t have thousands of tiny-tiny microservices on your back, that can feel more like thousands of crazy monkeys.
Even SmallerStill, there may be good reasons that can drive the need to divide a Bounded Context into separate deployment units. Note that this is not an arbitrary decision driven by radical and dogmatic opinions on lines-of-code count or single component. Let’s consider a few.
- Rate of change: Some areas of the Bounded Context change more frequently than other areas.
- Scale: A specific component in the Bounded Context is measurably attracting heavier load than other components.
- Performance: Similar to scale, but more focused on latency and throughput, a specific component in the Bounded Context is measurably bogging down other components, and/or being bogged down by others.