Showing posts with label microservice. Show all posts
Showing posts with label microservice. Show all posts

Microservices Platforms: When Team Topologies Meets Microservices Patterns

Mike's Notes

Great presentation by Chris Richardson, who is very experienced.

"Chris Richardson explains how microservices platforms reduce team cognitive load, sharing six key platform patterns to streamline delivery and accelerate software development flow⁠." - InfoQ

The link has a video recording of the talk. Excellent as usual. 

Resources

References

  • Reference

Repository

  • Home > Ajabbi Research > Library > Subscriptions > InfoQ Weekly Digest
  • Home > Handbook > 

Last Updated

08/08/2026

Microservices Platforms: When Team Topologies Meets Microservices Patterns

By: Chris Richardson
InfoQ: 04/08/2026

Chris Richardson is a software architect and serial entrepreneur. He is a Java Champion, a JavaOne rock star and the author of POJOs in Action, which describes how to build enterprise Java applications with frameworks such as Spring and Hibernate. Chris was also the founder of the original CloudFoundry.com, an early Java PaaS for Amazon EC2.

Transcript

Chris Richardson: Welcome to my talk on microservices platforms. Really, what the talk's about is a simple idea, taking the concept of team topologies, platforms, and platform groups, which is another term for platform teams, and using those to accelerate the delivery of applications that use the microservice architecture. Basically, it's all about reducing the cognitive load of the service teams, enabling them to deliver better software faster. I've been building software for a million years now, at least that's what it feels like. It did mean that I was actually around when patterns became popular within the software community back in 1994, 1995. I was really good, and that shaped my thinking ever since.

My brain is full of 30 years of patterns now, as well as 30 years of Java. I've just done various things. I've worked on Lisp systems, created the original Cloud Foundry. Then I also, for the past 10-plus years, been pretty much focused on the microservice architecture, just helping organizations around the world improve how they deliver software. I'm excited, so my book, "Microservices Patterns," came out like 7 years ago now, which is still quite current, remarkably. I'm in the middle of working on a second edition of the book, so one day it will come out. I just think about microservices most of the time.

Microservices Platform: Why?

In this talk, I'm actually going to walk through six different patterns that I've identified that will help with the delivery of microservices. I'm sure there's actually many more. I want to start off just by talking about why platforms, why do they matter? What are the benefits in the context of developing microservices? I want to take a step back and talk about what software development is all about, and I like to think that at the heart of software development is a feedback loop. We in IT, we develop software, and then we put it into production, put it into the hands of the users, and we get feedback from that. It's really critical for businesses today to have short feedback loops so that they can thrive in today's volatile, crazy world, which is unpredictable from one moment to the next. Ages ago, I used to talk about brick-and-mortar businesses being disrupted by digital technology.

Since then, we've had pandemics, we've had wars, we haven't had tariffs, now we do, now we don't. It's just completely volatile. Businesses quickly need to be nimble. There's a lot of research that shows, and this is one of the findings from the keynote, that the better you are at delivering software, as defined by continuous stream of small changes, the more successful the business is likely to be. Fast flow is really important. To actually achieve fast flow, you need a combination of three things. You actually need a process, or specifically DevOps, which I'm actually not going to talk about today. That's how an organization should work. You need a properly structured organization, specifically one that follows the ideas of team topologies, which is actually a collection of patterns for structuring an organization for fast flow. Then you need an architecture that enables both of those things, which, at scale, is often the microservice architecture. I'm really focusing on the organization and the architecture piece of this in today's talk.

What is this team topologies thing? That is a collection of organizational patterns and principles for fast flow. It's basically, how do you structure your organization to deliver software rapidly, frequently, and reliably, using DevOps, actually? There are several different concepts involved. The first one is there's four different team types. Most of the work is done by what is known as a stream-aligned team. That is a team that is responsible for the end-to-end flow of work that is taking requirements and turning it into code running in production. These teams are generally small, five to nine people. Those are the teams that are doing the vast majority of the work. Then they're supported by three other team types. There's enabling teams that act as consulting teams that help teams acquire new skills. There's complicated subsystem teams that focus on domains that actually involve deep skills like math, for example.

I'm not talking about them so much in this talk. Then, lastly, there are what used to be called platform teams, and then they got renamed into platform groupings. I reject that, and I just call them platform groups in the second edition of "Team Topologies." Which is what I'm really going to talk about today. You've got these. I'll talk about what platform groups do. Then there are these three different interaction styles. Most of the interactions are via X as a Service, one team consuming the output of another in a self-service fashion. Occasionally, teams need to collaborate to discover new capabilities. Then, of course, enabling teams, which are acting as consultants, facilitate with the team that is learning. I'm going to talk about these interaction types quite a bit. Then there's a set of principles, and the most important principle is about managing a team's cognitive load.

The human brain can only deal with so much complexity. Collectively, a team, a set of brains can only deal with so much cognitive load as well. They only have a certain cognitive capacity, and you do not want to exceed that. Because if you cognitively overload a team, like just in order to get the work done, there's just so much mental effort, then that actually reduces team performance, and it ultimately impacts their mental health in terms of stress, and burnout, and so on. As Nicole mentioned in the keynote, a key part of having a great developer experience is minimizing the cognitive load of a team. As you're going to see, that is one of the key goals of having a platform or a collection of platforms. That's team topologies and cognitive load.

Then in terms of what is my definition of the microservice architecture. It's an architectural style that structures an application as a set of components or deployable units, which also go by the name of services. Then those services have two essential characteristics. They are independently deployable, meaning a service can be built, tested, and deployed in isolation from other services. They are loosely coupled, or specifically loosely design-time coupled, which means that a change to one service rarely requires other services to change in lockstep. Notice in this definition, I'm not talking about claiming that services should be small or numerous. That might be implied by the name, but that's not an important characteristic. The reason I'm talking about microservices here is because they actually enable fast flow. The way they do that is that they enable the teams that are developing in them, the stream-aligned teams, to be independent.

That comes from those two properties. Because the services are loosely design-time coupled, a team can change their service without having to coordinate that change with other teams. Then because the services are independently deployable, a team can deploy their service without any kind of collaboration with those other teams, at least the vast majority of the time, which means that teams are able to work separately most of the time, which is essential for fast flow. The challenge that you have is that the microservice architecture is quite complex. If you go look at the microservices patterns language, most of the patterns there are solutions to problems that you encounter when implementing microservices. There's a lot of different patterns that you have to implement. If you look at each pattern, it's a combination of three things. Application logic, which is what the team should be focusing on. There tends to be a lot of plumbing, so supporting infrastructure code, connecting to databases and message brokers, and logging and so on.

Then there's infrastructure services as well. Teams should be focused on application logic, and for them, having to deal with plumbing or infrastructure services would be an excessive burden. In some cases, it requires deep expertise, so it would impose a significant cognitive load. If each team was dealing with this, it would be duplicated effort. You'd end up with multiple bespoke implementations, which would be a maintenance nightmare. Then, on top of that, there are these cross-cutting application-wide concerns that don't really belong to any one team. Not only that, it's not just patterns. If you go look at the source code for a service, it's not just the application code. There's build logic, a definition of the service's dependencies, and task definitions that compile and test and package that service. There's also some deployment logic. There's also the definition of the service's deployment pipeline. Then there's probably Infrastructure as Code, like Kubernetes YAML, for example, that's there to deploy the service.

You don't want the team reinventing the wheel for all of that, because that would be an excessive burden. There's even more. Not only do you have the services, but then there's all these infrastructure services, including the infrastructure that runs the deployment pipeline, services that are global, like your message broker, for example, and then the deployment infrastructure. It would be a burden for all of the teams to actually have to take on that work themselves. That's the big motivation for platforms and platform groups. From a team topologies' perspective, a platform is an artifact that reduces the cognitive load of a stream-aligned team. It could be just a wiki page, but usually it's a tool or a library or some kind of self-service, SaaS-like solution providing a capability. It's developed by a platform group, and it's consumed as a service by the stream-aligned teams. That's the big idea here.

If you look at what a platform group is, it's actually a composite team type. It most certainly would have a stream-aligned team that develops the platform, but there might also be an enabling team that provides a consulting function that helps the stream-aligned teams be more successful with that platform. Then in terms of collaboration, this is primarily X as a Service. It's all about self-service platforms, but then the teams will collaborate to evolve the platform. Then, as I mentioned, the enabling team that's part of the platform will also consult with the service teams. The primary benefit is that it reduces the cognitive load of the teams, enabling them to work on their specific business functionality and actually deliver value. Then the platform is a single standardized implementation of some important capability. It's done right just once. Then the platform group itself can focus on developing skills in that area. Unlike the stream-aligned team, which is focused on delivering business functionality, the platform team can dive deep into whatever their particular more technical problem domain is. That's the big idea with these platforms.

The Service Foundation Platform

As I mentioned, I identified six different platforms, and there's most likely more, but I thought this was a good start. I'm going to talk about each one very briefly in turn. The first one I want to talk about is the service foundation platform that simplifies the creation and maintenance of services. As I mentioned a little while ago, if you look at a service, there's a lot of plumbing, there's build logic, there's Infrastructure as Code for deploying the service. There's a lot of stuff, and actually setting up a new service from scratch would be quite a burden on the teams, and maintaining all of that would be quite a burden as well. The solution is to have a service foundation platform that simplifies that part of service development. The service foundation platform is comprised of two parts. There's the service template, which, as the name suggests, is a template that can just be cloned to create a running service.

Then there's a service chassis that is a framework that the template is built upon. The idea of a service template, super simple. It's a complete running service that a team can just copy and drop in their business logic, and they've got this testable, deployable, observable service up and running relatively quickly. Big reduction in cognitive load there. The problem you have is that a template, and this is same as true with code generation as well, it is basically glorified copy and paste. Then what's more is the template is changing. When it's time to make an update to the plumbing for the services, you now have multiple copies of the code and it's likely to be slightly different because each service was cloned from a slightly different version of the template. There's potentially a massive maintenance task in updating all of these services. That's where the service chassis comes in.

The idea is you extract out most of the functionality that is in the template into this chassis, which is this framework. Then that framework is just referenced by the template. Hopefully, the template is really small, so the amount of copy and paste is significantly reduced. When it's time to make a change to the plumbing, you just update the framework, release a new version of it, update the service template to use that version, and then update each service to use the new version of the chassis. Fingers crossed, you've just rolled that change out and it's just a one-line version update. Of course, there are scenarios where it's a bit more complicated than that. A lot of the time, the upgrades are quite straightforward. If you have more complex upgrades that require code changes to each service, which includes updating stuff that is in the service template, one option is for the teams to do it themselves.

A much better option is for there to be some kind of update or migration script or some tool that you can apply to each service's repository to create a pull request. That might be a deterministic tool like OpenRewrite, which provides large-scale refactoring of your codebase. Or maybe, and this is my obligatory mention of GenAI, because that's the only thing that's real today, you might be able to use GenAI to actually do this update. You could actually give it the diffs of the service template, and maybe it would figure out how to apply those diffs to each and every service and create a pull request for it. Who knows, because every time you use GenAI, it's a roll of the dice as to whether you'll get something usable out of it. That's the service template, or to be more precise, the service foundation.

The Security Platform

The next platform I want to talk about is the security platform. Who here, first off, understands security and likes it. Because to me, it's like a prime example of my brain does not have the cognitive capacity to maintain knowledge of how OAuth authorization flows actually work. I learn it for a while, and then a month later, it's paged out. I don't know if that's because it's complex or because I'm getting old and my mental capacity is diminished. Security is really important, yet at the same time, it's really complicated. There's a lot of different areas to that, and I just want to talk about three areas that can impact developers. One part of security that's obviously important is authentication, verifying the user is who they claim to be, logging them in, in other words. There's a whole complex mechanism involving OAuth and OIDC and IAM services, and so on, that result in services being handed a token.

Then they have to do authorization based on that token, which might be hard-coded Java authorization rules, or perhaps they delegate to an authorization service like also cloud. There's also access control lists for things like Kafka topics and stuff. This is not what developers should be spending their time thinking about, because this stuff is hard, or at least for me, it's hard. Then, on top of that, there's also transport level security. You want to secure the communication between services as well, and that involves technologies like certifical authorities that are handing out certificates and so on. That's also quite complicated. The obvious solution is to have a security platform that takes care of that. This platform consists of two parts. There's a bunch of infrastructure services that provide the security mechanisms that I just described, like an IAM service, certificate management, which might actually be a service mesh, for example.

Maybe there's the authorization service as well. You've got that infrastructure. Then there are elements that provide security that are incorporated into the service chassis so that services are actually secure by default. You build them on top of the chassis. Then, let's just say automatically every REST endpoint will require a JWT. It knows how to get the JWT signing certificate from the IAM service. The idea is that this insulates the developer from the complexities of security, and the only security aspects they need to think about are writing the authorization rules that determine which operations can be invoked by whom. That's about it. That's the security side of things.

Infrastructure Services Platform

The next platform I want to talk about is the infrastructure services platform. Services are not these standalone things. They need a bunch of infrastructure services in order to run. Most obviously, the services need database servers, which need to be provisioned and managed. Typically, even if you're running on Kubernetes, you'll probably use AWS RDS or Aurora for the service databases. Then there's application-wide infrastructure like Apache Kafka. Maybe you use AWS MSK. On the one hand, it sounds simple, but on the other hand, setting up cloud resources on AWS and other public clouds is incredibly complicated and requires deep expertise, starting with getting an access key and taking it from there. It's like really complicated. You don't want teams dealing with this, because they should be focusing on their business logic. It makes sense to have a platform to do this. Once again, the platform consists of two parts.

One part provides the shared services like Apache Kafka and other pieces of infrastructure. Then there's what I call an infrastructure orchestrator. What that does, it enables the service team to say, my service needs a Postgres database with this capacity. Then the orchestrator is responsible for taking that service specification and creating the appropriate cloud resources, which are then managed. The teams can just go, I need this. They can express their intent and the orchestrator takes care of it. There are a few different solutions out there. One that I've used in the past in the Kubernetes world is Crossplane, which if you can get past the word soup of the documentation, it's actually really interesting. It basically extends the Kubernetes API. Let's say the platform team create a new resource type like service database. That's a CRD in Kubernetes terminology. Then they define how that maps to cloud resources.

Then, a service team can just write the manifest, the YAML that says, I need a service database and it needs to be this big and so on. Crossplane provisions and manages it for you. It's really cool because the service is defined at the Kubernetes level and now its infrastructure is defined at the Kubernetes level. Perhaps it's all packaged up into a Helm chart, so you install the Helm chart. You automatically get cloud resources in that environment. I think the technology is still maturing, but it's actually really interesting. Daniel Hertz company has one, Kratix, even better than Crossplane. Really interesting stuff, but it's deep technology.

The Observability Platform

Yet another platform I want to talk about is the observability platform. As you can imagine, a team that develops a service needs to understand how that service is behaving in production, and then they also need to understand what the users are doing, and how they're actually using that service. In the microservice architecture pattern language, there's actually six observability patterns. The gray ovals are the patterns. This includes the standard stuff like log aggregation, application metrics, and distributed tracing. It's like an observable service has to implement these patterns. As you can imagine, each of these observability patterns is some instrumentation which is comprised of application logic, plumbing, plus some dependencies, and that's emitting telemetry. Then there's infrastructure services like Prometheus, or something for storing logs and so on, that's gathering the telemetry, storing it, analyzing it, and presenting it to the teams. Yet again, on the one hand, the teams probably have to write some application-specific instrumentation, but everything else would be too much of a burden.

Setting things up, yet again, requires specific knowledge or in-depth expertise. Having an observability platform provide the infrastructure services like Prometheus, or ELK, or CloudWatch, or Datadog, so it could be a SaaS, or it could be on-prem, doesn't really matter, but it's stuff that needs to be provided, managed, and so on. Then, in the service template and chassis, there's elements that ensure that out of the box, the service is observable by default. You just build on top of the service chassis. You have an observable service. The team just needs to write the appropriate logging code, and collect the appropriate business-oriented metrics, and all of the low-level details are just insulated from them. Recurring theme. The team either ignores the low-level stuff completely, or focuses on the valuable parts, and everything else is provided via the chassis and these pre-managed infrastructure services.

The Build Platform

I now want to talk about the remaining two platforms, which are actually quite connected in a way, two sides of the same coin, the build platform, which is responsible for the deployment pipeline, and then the deployment platform that's responsible for the production environment. They're actually connected, because what comes out of the build platform actually has to be compatible with what the deployment platform is expected. Let's look at the build platform. Every service has a deployment pipeline that's going to compile the service, run the tests, package it up, perhaps as a deployable unit, like it could actually build a container, and a Helm chart, test that, and then either push it into the production environment or publish it to a registry where the production environment can pull it. Every service has one of these. It needs to be set up. It needs to be administered. That can be a significant burden for the team.

Then, also, the infrastructure that the deployment pipeline runs on also needs to be set up and administered as well. If we're using GitHub Actions, you've got to have a GitHub Actions workflow file for each service. Then the organization that contains the service's repository needs to be configured with GitHub Actions runners that actually execute the deployment pipeline, and also budgets need to be set and all of that administrative stuff. Not something you really want the teams to be doing, especially when you have a lot of services that are more or less built the same way, it's like, why reinvent the wheel? Good use case for having a build platform which provides the pipeline infrastructure, properly configured GitHub organizations. Then in the service template, there's actually a templated definition of the deployment pipeline, whether that's a GitHub Actions file or a CircleCI config.yml. Then, hopefully, the actual pipeline specification is built using these reusable package components like GitHub Custom Actions or CircleCI Orbs, to actually minimize the amount of copy and paste that's involved.

At least those two have a way of providing reusable deployment pipeline logic, and GitLab has something similar as well. Then the build platform can also provide some repository/registries for storing build artifacts, shared libraries, as well as publishing deployable units to a container registry for your container images and Helm charts. Because what comes out of the deployment pipeline obviously has to be stored somewhere. With this build platform, hopefully, most teams don't have to be concerned with all of this. It just happens for them. Maybe they need to tweak the deployment pipeline if they have specialized use cases, but hopefully not so much. I feel like this is pretty standard.

The Deployment Platform

Then that leads to the last part, which is the deployment platform. To actually run an application, you obviously need to have a production environment, and you might actually have some other environments, staging, dev, QA, though unclear exactly how many you really should have. Those are a centralized place where your service is run, and they actually have to provide a rich set of capabilities. They need to have a deployer mechanism that takes an updated service and rolls it out somehow. It's hard to talk about this in the abstract, but later on, I'll mention things like GitOps tooling like Flux CD or Argo. They also need to deploy your services in a fault-tolerant way. The big idea is like, here's my service, I need to run n instances of this. The infrastructure tries its hardest to make sure that's true. That could be an AWS autoscaling group, or it could be Kubernetes deployment, depending on what mechanism you're using.

Then there's also a networking capability as well. Requests that come in get routed and load balanced across your service instances. As you probably know, or maybe you're blissfully unaware, it's really complicated to set all of that up. Then the other part of this, every service needs some Infrastructure as Code configuration to define how it's deployed. It's either Kubernetes YAML, or maybe it's some Terraform Infrastructure as Code or something worse. There's a lot of stuff. It's really funny. I mostly live in the Spring world. When I step outside the Spring world and I go to the frontend, I'm horrified. I have been for many years. Then, over the past few years, I've been doing more of this DevOps-y stuff, and I'm equally as horrified. It is so complicated. I guess it's evolving. As a Spring developer, I don't want to have to deal with this. Actually, I find it cool and interesting, but there's another part of me that just wants to run away screaming.

You need a deployment platform to shield the developers from the complexity of the infrastructure. That will provide the various environments. Hopefully, in your service template, it'll provide IaC code for deploying the service, some kind of template. Then hopefully that is composed out of some reusable Infrastructure as Code components. Though the modularization technologies there leave a lot to be desired, specifically in the Kubernetes YAML world. Here's one example that I've worked with, which is where there's a GitOps tooling, here I've shown Flux, but there's also Argo CD. The state of the cluster is defined by one or more Git repositories. When those change, Flux will actually apply those changes to the cluster. It can also monitor the container registry. When a new Helm chart is published, it will edit the manifest and then deploy that new version. It's a pretty slick setup, but it is quite complicated. That's the deployment platform, and ideally it shields the developers from a lot of the complexity.

Microservices Platforms: How?

That's the six platforms. I just want to wrap up with a few comments about this platform development thing. While I was putting this talk together, I saw this article by The New Stack, which just pointed out that the success rate for platform engineering is not that great. Mostly fails. Based on what I've seen looking at organizations, is it's not surprising. I think one issue that's going on is for a lot of organizations, platforms are a way of ignoring the hard problems of people and solving actual customer problems. They do that by diving into what I call the infinity pool of technology. Because you can just get lost in the Kubernetes world and feel like you're doing useful things like creating custom Kubernetes operators. If you're not actually solving real problems, you're not going to succeed. A few thoughts. I've observed this antipattern forever. You really have to focus on the services, get those deployed in production, and worry about the technology later.

Specifically, what that means in terms of platforms, build some services, put them in production. Figure out what problems the teams are struggling with, then build the platforms, migrate the services to those platforms, and just iterate around that. Rather than go do a lot of platform development up front. Then team topologies has this great concept of a thinnest viable platform, or you could say it's like a minimum viable platform, where you build just enough platform to enable the teams to be successful. No more, no less. Maybe that involves Kubernetes operators, but maybe it doesn't. Then, teams need to adopt a customer-focused mindset, where customers in this case are the teams that are developing the services. The platform teams exist to help those teams, not actually dictate to them. They need to learn what their problems are, and provide platforms that help. Then they also need to actually help those teams use the platforms through facilitation. Build just enough platform to help, and do it in a customer-focused way.

Summary

In summary, microservices do require platforms to avoid the teams having to reinvent a lot of complex wheels. I identified six different platforms. There's probably more. Then I think it's really important to take a software engineering approach to these platforms, which are actually easier said than done with some aspects, and develop reusable components, rather than just copy-pasting everywhere, which creates a maintenance nightmare. Obviously, if you're a developer, you go, that's no big deal. Programming languages have libraries, frameworks, build tools like Maven, Gradle have plugins, even CI/CD platforms like GitHub Actions and CircleCI have reusable components. Then it gets a bit iffy when you're in the Kubernetes YAML world. There's Helm library charts, which are just weird. They work, but they're weird. Then there is a language called q, but that seems slightly weird to me as an application developer. I think there's work to be done in that area. You want to have these modular, reusable components everywhere. When you do have copy-paste, you then need tooling to actually automatically roll out updates to all of your services, generate pull requests for each one. Then, lastly, if you're building microservices, focus on the services, not on the technology. Build just minimal platforms that help.

Cell Boundaries: Defining the Scope of a Cell in Cell-based Architecture

Mike's Notes

Pipi uses several different novel cell-like structures in its architecture, unlike the one described in this article. However, there are some good ideas here.

I went with embracing chaos and complexity. The trick is making it work.

Resources

References


Repository

  • Home > 

Last Updated

30/03/2025

Cell Boundaries: Defining the Scope of a Cell in Cell-based Architecture

By: Benjamin Cane
Medium: 2/03/2025

Builder of payments systems & open-source contributor. Writing mostly micro-posts on Medium. https://github.com/madflojo

One of the hardest questions when adopting Cell-based Architecture is defining what should and shouldn’t be within a Cell.

Defining a Cell’s boundary is crucial to ensure you’ve encapsulated everything you need while balancing its size and complexity.

Today, I will share my thought process when defining a Cell’s boundary.

Recap on Cell-based Architecture

For those who may have missed my previous posts, the TL;DR on Cell-based Architecture is that instead of building one massive system, split it into isolated groups called Cells.

Doing so will improve the system’s resilience, performance, and scalability.

To catch up, check out my recent Cell-based Architecture post.

Avoiding a Massive Cell

Ideally, every service a single request may traverse or require as a dependency should be within a Cell.

However, in a complex enterprise, a single request may trigger multiple downstream events and rely on numerous systems.

Since every component within a Cell should be tested, deployed, and failed-over together, managing such a massive system is impractical. Breaking up this customer journey across multiple Cells is better but requires thought and strategy.

Defining some Terms

Before discussing how boundaries are defined, let’s define some terms that will help ensure we are all speaking the same language.

Platform:

For this post, a Platform is a collection of sub-platforms and/or monolith systems that provide a set of functionalities for a customer journey (i.e., payment processing).

Sub-platform:

For this post, a Sub-platform is a collection of microservices that provide a clearly defined capability (e.g., account or request validations).

Region and Availability Zones:

We will also use the public cloud definitions of Regions and Availability Zones, where a Region is a separate geographical area separated by a significant distance, and availability zones are multiple isolated hosting environments close to each other but not relying on a shared resource like power, physical location, or network.

Principles

When defining boundaries, I often apply a set of principles made of rules and guidelines. While these might sound similar, the difference between a rule and a guideline is how much I’m willing to break the guidance.

I do not break the rules; they guide my decisions. A guideline is a bias, something I’m willing to ignore if it makes sense and I have good reasons (which should be written down and captured).

Rules

  • A single Cell does not span regions.

The core concept of Cell-based Architecture is to build multiple isolated systems that are carbon copies of each other rather than a single system that gains its resiliency by spreading across numerous regions.

To ensure availability, we must deploy those carbon copies in multiple Regions, with each Cell acting independently and isolated at the Region level.

A Cell might span multiple Availability Zones within a Region but it is not required.

Keeping cells within a single availability zone may be prudent if you need low latency.

Of course, this deployment approach will add operational overhead, leading to more cells, as you still need to ensure you have carbon copies in other regions. But this decision is one of those infamous trade-off moments.

  • Sub-platforms do not span multiple Cells.

Aside from the performance and failover complexities incurred by a sub-platform spanning multiple cells, keeping a sub-platform within a single cell helps solidify its responsibilities and boundaries.

The idea of a sub-platform is that external systems don’t know the internal workings of the sub-platform, only the external facing interfaces.

Is the sub-platform a microservices design, a monolith, or macroservices? It does not matter.

A sub-platform has a contract, and its owners decide its internal workings.

Extending that internal flexibility across multiple Cells becomes very complex and will likely violate other rules.

  • Components within a Cell must be tested together.

Cells might be a collection of multiple sub-platforms (more on this later), but the idea of a Cell is that it’s a single isolated unit of processing.

Whenever you deploy new capabilities or establish a new Cell, you want to ensure everything works together as expected. The best way to accomplish this is to test the entire customer journey at the Cell level.

If a customer journey spans multiple cells, testing them together may be a good idea, but ideally, the boundaries should be clear enough that cells are independently testable.

  • Failover is at a whole cell level.

In a traditional architecture where a platform is a single entity across regions, you’ll see scenarios where a single microservice fails, and traffic to that microservice is routed to another region to service new requests.

While this approach sounds excellent from an availability perspective, it’s problematic.

When a single microservice fails, the latency of a single cross-region call may not break the system, but what happens when multiple services fail? Now, a single customer request may traverse regions numerous times.

Not only is this a performance killer, but every time you traverse regions, the chances of packet loss, network failures, etc., increase — a classic “death by 1000 microservices” example.

  • Cell-to-cell communications must use fixed contracts and protocols.

Interactions between sub-platforms must follow fixed contracts and protocols, whether a REST API, a Message Queue, gRPC, or a file.

Changes within a sub-platform are okay; typically (but not always), a single team can implement them across the sub-platform.

However, we should always assume that different teams manage different sub-platforms. Changes between sub-platforms require coordination and communication across multiple teams. The same applies to Cells.

Changes between Cells always require extra coordination and testing, so we should manage them like any other API change (with versioning!).

  • Cell to Cell communications can cross Regions, but never Cell internal communications.

When defining a Cell boundary, it’s best to assume that calls between Cells may traverse regions. Cell-based Architecture acknowledges that failures will happen. A Cell will need to failover; when this happens, a request might traverse regions.

While it might be optimal to ensure Cells talk locally within a region, this is an optimization and should not be relied on for performance or resiliency.

When you assume cell-to-cell calls traverse Regions, a new set of non-functional requirements must be considered, such as retries, circuit breakers, latency, etc.

Internal Cell calls should always be local because failover is at the Cell level, not the microservice level. The whole point of Cell-based architecture is to create isolation; if internal communications traverse regions, it breaks the entire design.

Guidelines

  • Avoid Dependencies between Cells.

Some customer journeys are expansive, so encapsulating everything into a single cell can be challenging.

Building dependencies between Cells is okay, but as described above, Cell-to-Cell calls will span regions and have more non-functional concerns such as increased latency and failures.

It’s easier to manage Cells that do not depend on others, but it’s not always practical.

  • A Cell should contain a single sub-platform.

Some may argue that this guideline should be a rule, but I don’t see it as that simple.

If you can draw cell boundaries around each sub-platform, that will simplify a lot of your design. However, the practicality of a cell per sub-platform depends on your system’s use case and requirements.

If your customer journey requires low latency, having each sub-platform act as a Cell can impact your performance.

Having too many Cells also creates operational complexity, which can cause just as many issues as you are trying to prevent with Cell-based Architecture.

It’s okay to have a cell contain multiple sub-platforms; you must design it accordingly.

  • Deploy all components within a Cell together.

I firmly believe that a sub-platform’s components should be deployed together, as this reduces the complexity of releases and testing. Still, I don’t prescribe forcing Cells with multiple sub-platforms to follow this approach.

Deploying the whole Cell as one is a great practice, but it is also okay to do this at a sub-platform level.

Use discretion; this one breaks down to operational overhead, and tooling & team maturity.

  • Use Natural Boundaries to define Cell Boundaries.

A natural boundary is when a customer journey transitions from one type of architecture pattern to another, like a real-time system (REST APIs) to a batch or event-based system (Message Broker).

A real-time system takes a different approach and requires different resilience and performance from an event-based system. These changes in requirements and flow are great places to define Cell boundaries.

This guideline is not a rule, though. Sometimes, you may want to bring multiple sub-platforms and workloads into a single cell, which may mean not defining a boundary at these transition points.

By Example

Let’s explore an example system to help understand the above approach to defining Cells.

In this Example, a simple backend API calls multiple microservices (using an orchestrated microservice pattern) and triggers events to a set of event-driven microservices.

Following our principle of natural borders, the most apparent boundary is where the customer journey goes from API calls to event messages.

The event-driven systems that perform post-processing can be one Cell, while the APIs can be another.

Benefits:

  • Microservice-to-microservice calls are local within each Cell, which improves latency and reduces failure points.
  • APIs and Event-based systems can have different failover mechanisms.
  • Establishing these as two sub-platforms makes testing and releasing easier as there is a clear contract, and we can test them independently.

Why it works:

  • APIs do not have a hard dependency on event-based systems to finalize processing.
  • The event-based system has different needs and SLAs.
  • The Cells do not share the same database (a rule in microservices that applies to Cells).

Final Thoughts

While I covered many principles for defining boundaries, remember that each situation and use case is different. Guidelines are not the same as rules; they can be broken when reasonable.

However, remember the core concepts behind cell-based architecture when ignoring any guidelines.

By creating independent Cells that operate without reliance on a central dependency, you can isolate and reduce the impact and frequency of failures.

Remember these core concepts while focusing on reducing the number of times a request crosses cells, keeping cells small and manageable, and using natural boundaries.

If you do, you’ll have a resilient and performant architecture.

Pipi 7 (2020)

Mike's Notes

A Brief History of Building Pipi 7.

Resources

  • Resource

References

  • Reference

Repository

  • Home > Ajabbi Research > Library >
  • Home > Handbook > 

Last Updated

30/05/2025

Pipi 7 (2020)

By: Mike Peters
On a Sandy Beach: 01/03/2021

Mike is the inventor and architect of Pipi and the founder of Ajabbi.

When Pipi 6 was finished, it was already overdue for replacement, given what I had learned from building it.

2020 Starting

The most significant change was the adoption of microservice architecture. Each microservice has a separate database, logic, workflow and web presentation layer. There were 300 microservices and lots of drawings inside 6-sided polygons.


I must have left a big trail of smoke from my Google searches, because Google started calling me every two months. Initially, I ignored them, but they wanted to host Pipi on Google Cloud Platform (GCP).

So, I optimised the internal architecture for cloud hosting on GCP using their platform tools.

A rules engine was built to handle logic. CQRS messaging that included persistent data storage.

The platform's self-documentation utilised ColdFusion.

Influences

2020 Finish

It looked good, and then it was ready for a complete rebuild (not even a refactor). However, the microservices architecture wouldn't scale because of the growing complexity caused by the Covert cell simulator-derived components. Docker wouldn't work, and it would now require a Virtual machine (VM).

Back to the drawing board.

Cliff Richardson - A Pattern Language for Microservices

Mike's Notes

Chris Richardson has a useful outline of options to choose from when considering using Microservices.
  • Good diagrams
  • Has written a book
  • Offers training
  • Has skin in the game

Resources

References

  • Reference

Repository

  • Home > Ajabbi Research > Library > Authors > Chris Richardson
  • Home > Handbook > 

Last Updated

11/05/2025

Cliff Richardson - A Pattern Language for Microservices

By: Mike Peters
On a Sandy Beach: 28/03/2019

Mike is the inventor and architect of Pipi and the founder of Ajabbi.

"Chris Richardson is a developer and architect with over 20 years of experience. He is a Java Champion and the author of POJOs in Action, which describes how to build enterprise Java applications with POJOs and frameworks such as Spring and Hibernate. Chris is the founder of the original CloudFoundry.com. He now spends his time providing microservices consulting and training and working on his third startup, Eventuate, Inc. Chris has a computer science degree from the University of Cambridge in England and lives in Oakland, CA."

Summary

From the home page ..."Microservices - also known as the microservice architecture - is an architectural style that structures an application as a collection of services that are

  • Highly maintainable and testable
  • Loosely coupled
  • Independently deployable
  • Organised around business capabilities.

The microservice architecture enables the continuous delivery/deployment of large, complex applications. It also enables an organization to evolve its technology stack."

Contents

Application architecture patterns

Decomposition

Deployment patterns

Cross-cutting concerns

Communication style

External API

Transactional messaging

Service discovery

Reliability

Data management

Security

Testing

Observability

UI patterns

Presentations

Chris Richardson - Documenting a service using the microservice canvas

Mike's Notes

This is a copy of an excellent blog article by Chris Richardson from his website. He also has more information about this on GitHub.
  • Use this template, which is available on GitHub.
  • Credit both Chris & Matt.
  • It closely matches what I use anyway, but it is much better laid out.
  • Most of these metadata fields are already completed.
  • The existing project documentation generator could quickly work with this template to batch output HTML and PDF files.
  • Pipi will not be using Saga's; however, it can work with workflow messaging.

Resources

References

  • Reference

Repository

  • Home > Ajabbi Research > Library >
  • Home > Handbook > 

Last Updated

11/05/2025

Documenting a service using the microservice canvas

By: Chris Richardson
Microservices.io: 27/02/2019

In What’s a service—part 1? I described the key aspects of a service, including its API and dependencies. A good way to document a service and its structure is to use a microservice canvas. A microservice canvas is a concise description of a service. It’s similar to a CRC card that’s sometimes used in object-oriented design.

I first read about the canvas in a 2017 DZone article by Matt McLarty and Irakli Nadareishvili. I’ve since adapted its structure so that it emphasises the interface (top of the canvas) and the dependencies (bottom of the canvas) and de-emphasises implementation (middle of the canvas).

Here is an example of a microservice canvas. It describes the Order Service, which is part of my book’s example FTGO application.


A service’s external view

The service’s external view is described by the following sections:

  • Name - name of the service
  • Description - a brief description of the service
  • Capabilities - the business capabilities implemented by the service
  • Service API - the operations implemented by the service and the domain events published by the service
  • Quality attributes - the service’s quality attributes, which are also known as non-functional attributes
  • Observability - includes health check endpoint, key metrics, etc.

A service’s dependencies

A service’s dependencies are described by the dependencies section, which consists of two parts.
  • Invokes - the operations which are implemented by other services that this service invokes
  • Subscribes - the messages, which include events, that this service subscribes to

A service’s implementation

The canvas can also describe the service’s implementation, such as its domain model.

Example canvas

To learn more