Skip to main content

Autonomous Computing and how it influenced the way I build software

There are a lot of concepts and papers that have influenced the way I design and build software. One concept that certainly should be on the list is 'Autonomous Computing' as introduced by Pat Helland more than 20 years ago.

If you have never heard about this concept, I would recommend to first read this paper before you continue reading my blog post.


Back? Let’s continue.

In the paper Pat introduces the concept of Fiefdoms and Emissaries and Collaborations.

Fiefdoms refer to independent, autonomous components within a computing system. Each fiefdom is responsible for a specific aspect or function of the overall system. They operate independently and have their own decision-making capabilities.

Emissaries are entities that facilitate communication and coordination between fiefdoms. They act as messengers, relaying information and requests between different components of the system. Emissaries enable fiefdoms to interact and collaborate without direct dependencies on each other.

A collaboration is an abstraction for a set of messages into and out of a fiefdom for a single long-running business operation.

Each of those concepts sound familiar to specific techniques I like to use when building software.

Technique 1 – The actor model

The actor model is a theoretical framework for concurrent computation that treats actors as fundamental units of computation. Actors are independent entities that communicate with each other by sending and receiving messages. Each actor has its own internal state and can perform actions in response to messages it receives.

In Helland's vision of autonomous computing, systems are composed of autonomous components that communicate asynchronously through message passing. This aligns with the principles of the actor model, where actors operate independently and communicate via message passing.

Both the actor model and Helland's concept emphasize decentralized, loosely-coupled systems where components can operate autonomously and reactively. By leveraging message passing and asynchronous communication, systems can be more scalable, resilient, and adaptable to changing conditions.

So an actor could be seen as a fiefdom.

Technique 2 – An anti-corruption layer

In Domain Driven Design, the anti-corruption layer is a design pattern used to isolate a bounded context from external systems or domains with different models or languages. It acts as a translation layer, ensuring that communication between different bounded contexts remains consistent and that the internal model of a context is protected from external influences.

Similarly, in Helland's concept of collaborations, the emissaries serve as intermediaries between autonomous components, facilitating communication and coordination. They ensure that interactions between fiefdoms are well-defined and consistent, helping to maintain the autonomy and integrity of each component.

Both the anti-corruption layer in DDD and collaborations in autonomous computing focus on managing interactions between different parts of a system to prevent conflicts, maintain autonomy, and enable interoperability. They provide mechanisms for managing complexity and ensuring that systems remain cohesive and adaptable as they evolve.

So an anti-corruption layer could be seen as an emissary.

Technique 3 – Sagas

In the context of distributed systems and event-driven architectures, a saga is a pattern used to manage long-lived transactions that span multiple (micro)services or components.

A saga represents a sequence of local transactions that are coordinated to achieve a global outcome. Each local transaction corresponds to a step in the saga and is responsible for making changes within its own bounded context. If a step fails, compensating actions are executed to undo the changes made by previous steps.

This aligns with the concept of a collaboration that is used to represent a single long-running business process.

So a saga could be seen as a collaboration.

Summary

Pat proposes a vision where computing systems are more autonomous, decentralized, and responsive. The techniques above can help you to realize that vision.

It certainly helped me to build better systems.

More information

Anti-corruption Layer pattern - Azure Architecture Center | Microsoft Learn

Saga pattern - Azure Design Patterns | Microsoft Learn

Popular posts from this blog

Podman– Command execution failed with exit code 125

After updating WSL on one of the developer machines, Podman failed to work. When we took a look through Podman Desktop, we noticed that Podman had stopped running and returned the following error message: Error: Command execution failed with exit code 125 Here are the steps we tried to fix the issue: We started by running podman info to get some extra details on what could be wrong: >podman info OS: windows/amd64 provider: wsl version: 5.3.1 Cannot connect to Podman. Please verify your connection to the Linux system using `podman system connection list`, or try `podman machine init` and `podman machine start` to manage a new Linux VM Error: unable to connect to Podman socket: failed to connect: dial tcp 127.0.0.1:2655: connectex: No connection could be made because the target machine actively refused it. That makes sense as the podman VM was not running. Let’s check the VM: >podman machine list NAME         ...

Cache stampede: when our cache turned against us

While investigating some performance issues, we ran into an ASP.NET Core API that cached a fairly expensive aggregation query for 60 seconds. Under normal load, that was fine: one request rebuilds the cache, everyone else reads from it. Under peak load, dozens of requests would arrive in that same expiry window, all see a cache miss, and all fire the same expensive query in parallel. The database didn't like that. That was the moment when our caching layer stopped helping and started hurting. A burst of requests comes in at the same time, all miss the cache, and all go hammer the database or the downstream API at once. That's a cache stampede . The cache was supposed to protect our backend, and for a few hundred milliseconds it did the opposite. Why this happens IMemoryCache.GetOrCreate (and its async sibling) looks like it protects you, but it doesn't add any locking on its own. Look at the naive version: public async Task<Report> GetReportAsync(string key) ...

A complex system designed from scratch never works

A few years ago, I worked as an architect on a big mainframe rewrite. I still count it as one of my failures. Not because the technology was wrong, but because I couldn't convince the management team to simplify the approach. Years later, the organization is still struggling to get the new system up and running. I left the project at the time, because I couldn't put my name behind an approach that would take very long and cost a lot of money without a working system to show for it along the way. Gall’s Law That memory keeps coming back to me, because it's a textbook case of Gall's Law playing out in real life. Gall's Law , from John Gall's Systemantics , states it plainly: A complex system that works is invariably found to have evolved from a simple system that worked. A complex system designed from scratch never works, and it cannot be patched to make it work. You have to start over with a simple system that works. What does that mean in practice,...