Published on

COCOA: from Ports & Adapters to concepts, capabilities and providers

Authors

Time for a little (de)tour?

Imagine that we observe a discussion between a senior software engineer Dan, an architect Alex and a business stakeholder Pete.

Pete is working in local, guided tourism business and he tries to explain to Dan and Alex how a particular workflow is working, so that they can modernize the technical side of it (because technical people should bother only by technical matters, right dear Reader?).

He explains the moment when a tour was published and what happens next.

Discussion
Pete, a business stakeholder:Ok, the tour got published.
Alex, an architect:Why is it important?
Pete, a business stakeholder:Only published tours can be activated.
Dan, a software engineer:What does it mean that a published tour is activated?
Pete, a business stakeholder:Well, it becomes visible in the web page as a search result, if that's what counts as important. Customers can view the details of such a tour, then book it.
Alex, an architect:Anything else? Why actually is it named as "activated" and not "searchable"?
Pete, a business stakeholder:Hmm, good question. Some of the tours can be navigated by guides having specific skills or licenses. Whenever a tour has such a requirement, then we need to book this guide for this tour.
Dan, a software engineer:Ok, it makes sense. I wonder, can we draw it?
Pete, a business stakeholder:Yes, of course! Whatever helps you understand better.

So they pulled couple of stickies and following Event Storming notation, they created following visualization of the workflow:

A published tour becoming activated.

Technical folks continued asking.

Discussion
Alex, an architect:You said that customers can book it, what are consequences of that?
Pete, a business stakeholder:Well, for each declared participant we need to reserve a seat, isn't it obvious?
Alex, an architect:Why is it important?
Pete, a business stakeholder:Depending on the tour activities, sometimes we need to book buses to commute between locations. But let's not complicate, for now at least.
Dan, a software engineer:So reserving seats means that there needs to be a pool of seats available, while the tour is activated?
Pete, a business stakeholder:Yes, that's right. A tour must have a total number of available seats associated with it, otherwise we can't track if the tour is full!
Dan, a software engineer:Could I put it on the board and you confirm if it matches how you understand it?
Pete, a business stakeholder:Yup, let's try.
Two consequences of activating a published tour.

Pete visibly started thinking, while staring at the board, and then he continued explaining.

Discussion
Pete, a business stakeholder:"Tour becomes searchable", does it represent that a tour can appear in the search results?
Dan, a software engineer:Yes, exactly.
Pete, a business stakeholder:Ok, if that's what you mean, then fine.
Alex, an architect:In our previous collaborative session, when we looked through potential opportunities and risks, you highlighted something related to participants getting lost, could you say something about it?
Pete, a business stakeholder:Yes, what we explored during this "Big Picture" session, is really big deal. Our guides often report that some participants do not follow the guide and walk to the next activity location using different routes than the group. That's what I meant they "are getting lost" - so a consequence of that is a guide who needs to "chase" them.
Dan, a software engineer:How does a guide "chase" such participants?
Pete, a business stakeholder:Well, a guide prepares a list of all adult participants with phone numbers - whenever an adult participant is lost, a guide can call them. It's pretty easy job, but it drags attention from other participants, which make them irritated and so on.
Dan, a software engineer:While calling them using the mobile phone, what does a guide ask for?
Pete, a business stakeholder:The most important thing is to locate them - so a guide asks where they are, and after that a guide either goes to get them back or asks them to return to the group.
Dan, a software engineer:What if they did not return?
Pete, a business stakeholder:A guide calls again and checks where they are.
Alex, an architect:Ok, if I correctly follow you, a guide needs to be capable of locating participants, right? How this is achieved today is that guides prepare participant-to-phone-number lists, which then is used for calling?
Pete, a business stakeholder:Yes, you stated it very precisely. Can we go back to the board - I see we didn't put booking guides when a tour requires specific skills.
Dan, a software engineer:Sure, let me add it.
An additional consequence of activating a published tour.

Alex was not happy that suddenly they jumped out of the topic of losing the location of participants, his architectural spider senses told him that something important is hidden there.

Discussion
Alex, an architect:And regarding locating lost participants - in a way, a guide needs to track location of each participant, right?
Pete, a business stakeholder:Hmmmm, a guide needs to know where a participant is, yes - we can say so.
Dan, a software engineer:But is this knowledge required while the tour is activated?
Pete, a business stakeholder:No, definitely not. Such information is important while a guide navigates the tour.
Alex, an architect:So such guide needs to actively track location at that moment, otherwise such tracking is not necessary.
Pete, a business stakeholder:Yes, participants tracking is necessary during tour navigation.
Dan, a software engineer:I'll put something on the board right now.

Dan walked to the board and placed another orange sticky, representing another consequence of activating a published tour.

All four consequences of activating a published tour, including establishing inactive geotracking session.

Pete did not understand it in the first place, but both Dan and Alex explained the idea behind geotracking session and why it starts as inactive.

After couple of minutes of discussion, Pete nodded and confirmed that it matches his understanding.

They told him that as soon as the tour navigation starts, such geotracking session becomes activated, and guides will be able to track participants' locations.

Technical folks thanked the business stakeholder for his time and insights, and they went back to their office to started collaborating on the solution, using the insights and findings.

What is possible?

Alex looked at the board again, and he started thinking and mumbling to himself, at the same time.

Dan was typing something on the keyboard, and suddenly he stopped and looked at Alex.

Discussion
Dan, a software engineer:Hey Alex, what are you thinking about?
Alex, an architect:Well, I was thinking about business capabilities we need while the tour is activated.
Dan, a software engineer:Business capabilities? What do you mean?
Alex, an architect:Each orange sticky tells us that there was an important state change, right? And they are consequences of requesting jobs to be done, based on the needs of the consumer - in this context, something orchestrating published tour activation.
Dan, a software engineer:Yeah, orange stickies are events, so I think we need to publish an event - Published Tour Activated. Then four services need to listen on it, translate it to a respective command, and handle those.
Alex, an architect:Pardon me, commands?
Dan, a software engineer:You know, CQRS - Command Query Responsibility Segregation. Events represent something that happened, and commands represent an intention to do something.
Alex, an architect:Hmm, if we take an architectural element, a component providing Searching business capability, why do you want it to listen to a very specific event? It would creating coupling.
Dan, a software engineer:Are you nuts? Events decouple things. Come on, I know you are an architect, but please do follow recent trends. Everyone talks about that - events bring decoupling.
Alex, an architect:I've heard about CQRS, but I don't feel how can it help. I see that in order to provide published tour activation capability, we need four capabilities: one for establishing seats pool, one for creating search entry, one for booking guide and another one for creating inactive geotracking session.
Dan, a software engineer:I still don't get what do you mean about those capabilities, but in my world they will be simple ports.
Alex, an architect:Ports?
Dan, a software engineer:Oh come one, ports - Ports & Adapters - didn't you hear about that one too?!
Alex, an architect:There are two other capabilities that were not mentioned, but they are required too: one for loading a published tour for activation and another one for saving activated published tour.
Dan, a software engineer:Are you listening to me, Alex?! You know what, let's go to the code, I'll show you how I would implement that use case.

And Dan started typing, representing his understanding of how to implement the published tour activation workflow.

public class ActivatePublishedTourCommandHandler(
    IPublishedTourRepository publishedTourRepository,
    ISearchService searchService,
    ISeatsPoolService seatsPoolService,
    IGuideBookingService guideBookingService,
    IGeotrackingService geotrackingService,
    IEventsPublisher eventsPublisher
)
{
    public Task Handle(ActivatePublishedTourCommand command)
    {
        var publishedTour = await publishedTourRepository.Load(command.PublishedTourId);
        if (publishedTour is null)
        {
            throw new PublishedTourNotFoundException(command.PublishedTourId);
        }
        publishedTour.Activate();
        await publishedTourRepository.Save(publishedTour);
        await eventsPublisher.Publish(new PublishedTourActivatedEvent(publishedTour.Id));

        await searchService.CreateSearchEntry(@for: publishedTour.ToSearchEntry());
        await seatsPoolService.EstablishSeatsPool(publishedTour.Id, publishedTour.SeatsCount);
        if(publishedTour.RequiresGuideBooking)
        {
            await guideBookingService.BookGuide(publishedTour.Id, publishedTour.RequiredGuideSkills, publishedTour.NavigationDate);
        }
        await geotrackingService.CreateInactiveGeotrackingSession(publishedTour.Id);
    }
}

Even though Dan was very keen on going fully with Event-Driven Architecture, because he believed in its benefits, he decided to implement the entire workflow in a single command handler.

It reflected exactly what was visualized on the board, and it was easy to understand.

And because it was easy to understand, it was easy to debug, test, and maintain.

Alex looked at the code, and asked about what happens if one of the services fails - whether the entire operation is expected to be rolled back, or not.

But the discussion quickly stopped and both of them started doing circles between business capabilities and ports and adapters.

Clean, adaptive hexagonal ports, or something else?

Discussion
Alex, an architect:I see that you expressed exactly what I was saying aloud - six required capabilities.
Dan, a software engineer:You mean the ports? Yeah, that's exactly what I was thinking after looking at the board.
Alex, an architect:I think our board does not match the code right now, because it shows only important state changes. Should we add those capabilities?
Dan, a software engineer:When you say capabilities - you think of commands? If yes, then I agree - let's add them.
A complete workflow of published tour activation.

They included blue stickies for commands and green stickies representing state that is used in a particular step of a workflow.

Now the board reflected the code better, and both Dan and Alex were happy.

Alex was curious about the mismatch between the language that he used and what Dan used.

Discussion
Alex, an architect:Dan, I noticed that both me and you disagree on terms, but we mostly speak about the same thing.
Dan, a software engineer:Hmm, you might be right. I still don't get what did you mean by saying "business capabilities". There are various patterns people use - CQRS, Vertical Slices, Hexagonal Architecture, Clean Architecture, Ports & Adapters (that's my favorite, by the way), but never business capabilities.
Alex, an architect:"Business capabilities" is not a new concept, just so you know. As far as I recall, it originated in enterprise architecture reasoning.
Dan, a software engineer:Enterprise architecture - now you scared me.
Alex, an architect:Sorry for that. A business capability is pretty pragmatic, in its role. It expresses "WHAT, not HOW and not WHO". Can you show me ports that you used in the code?

Dan pointed to the command handler constructor parameters, and Alex nodded.

Then, he showed all the interfaces representing those ports:

public interface IPublishedTourRepository
{
    Task<PulishedTour?> Load(PublishedTourId id);
    Task Save(PublishedTour publishedTour);
}

public interface ISearchService
{
    Task CreateSearchEntry(SearchEntry entry);
}

public interface ISeatsPoolService
{
    Task EstablishSeatsPool(
        PublishedTourId publishedTourId,
        int seatsCount
    );
}

public interface IGuideBookingService
{
    Task BookGuide(
        PublishedTourId publishedTourId,
        IEnumerable<Skill> requiredSkills,
        DateTime navigationDate
    );
}

public interface IGeotrackingService
{
    Task CreateInactiveGeotrackingSession(PublishedTourId publishedTourId);
}

public interface IEventsPublisher
{
    Task Publish(DomainEvent domainEvent);
}
Discussion
Alex, an architect:By looking at the interfaces and how they are used, can you tell me who is providing those capabilities?
Dan, a software engineer:No, just by looking at the interfaces and the command, I can't.
Alex, an architect:Can you say how EstablishSeatsPool is implemented?
Dan, a software engineer:No, I can't say - I just use that method, trusting that a responsible object knows how to provide it.
Alex, an architect:Exactly - so they express what I call a business capability.
Dan, a software engineer:Ok, but how does loading and saving published tour relate to a business needs?
Alex, an architect:Well, storing and restoring information is pretty fundamental to many businesses, isn't it? When you get money from a client, wouldn't you like to keep that information?
Dan, a software engineer:Hmmm, I see you point now - because it's one of the fundamental capabilities that supports business operations.
Alex, an architect:Restoring information is also important - we do it either to make a decision or present it for others to make a decision. How can you decide to buy something if you know how much money do you have?
Dan, a software engineer:So each interface represents a business capability?
Alex, an architect:Sometimes there are capabilities that are not directly expressed by business people, and they can be regarded as pure fabrications, a technical necessity to support other capabilities.

Dan felt that something important just clicked in his mind.

Ports were not just technical abstractions, they could be expressions of business capabilities, that are required by a particular use case!

He was wondering about the implications of that realization, so he immediately asked about adapters.

Discussion
Dan, a software engineer:Alex, if those port interfaces play a role of business capabilities, expressing what, not how and not who - what about adapters? What is the role they play?
Alex, an architect:Good question - if we take a delivery company - what capabilities do they provide for consumers like you?
Dan, a software engineer:They provide package delivery - I can send packages to my friends. So you mean that they are a delivery capability providers?
Alex, an architect:Yup, they are providers. If you need to send a package, could you provide such capability for yourself? Probably yes, but you decide to use another providers, by exchanging various things for money.
Dan, a software engineer:So adapters are capability providers?
Alex, an architect:Yes, adapters are required capability providers.
Dan, a software engineer:"Required"? What do you mean?
Alex, an architect:If you look at command handler, it uses interfaces, because it requires them to satisfy its consumer needs. We could say that satisfying consumer needs can be regarded as a providing a capability to them.
Dan, a software engineer:A command handler requires capabilities to provide a capability?
Alex, an architect:Exactly, and the best part is that our command handler is a provider itself too.
Dan, a software engineer:Yyyyy?
Alex, an architect:Look from the perspective of a consumer, who invokes the command handler via HTTP API, does it matter how "published tour activation" capability is provided?
Dan, a software engineer:Mhm, no. From that perspective, it does not matter.
Alex, an architect:So instead of those nice interfaces, we could use transaction script, write everything in a database, and still capability will be provided?

Dan was enlightened.

This means that ports and adapters can express something more profound than just another way of structuring software.

Then can be used to express business capabilities and their providers.

And what truly matters is a perspective - a command handler can be either a capability provider or a consumer, requiring other capabilities.

But never both at the same time, as holding two perspectives is really difficult, if not impossible.

Alex asked Dan to show him a directory structure of the project, so that they can see how those concepts are expressed there.

src/
└── ActivatePublishedTour/
    ├── Adapters/
    ├── Api/
    ├── Domain/
    ├── Ports/
    └── ActivatePublishedTourCommandHandler.cs

Just to reinforce the idea of business capabilities, Alex asked if it matters, from a consumer, outside-in perspective, whether there is no folder structure inside ActivatePublishedTour/ folder, and Dan agreed that it does not matter.

"I think that's what is advocated through Vertical Slices", he thought to himself.

After expanding all the directories, they saw following structure:

src/
└── ActivatePublishedTour/
    ├── Adapters/
    │   ├── PostgresPublishedTourRepository.cs
    │   ├── RabbitMqGuideBookingService.cs
    │   ├── RabbitMqGeotrackingService.cs
    │   ├── RabbitMqSearchService.cs
    │   └── RabbitMqSeatsPoolService.cs
    ├── Api/
    │   └── Http/
    │       └── ActivatePublishedTourEndpoint.cs
    ├── Domain/
    │   ├── Events/
    │   │   └── PublishedTourActivated.cs
    │   └── Models/
    │       ├── PublishedTour.cs
    │       ├── SearchEntry.cs
    │       └── Skill.cs
    ├── Ports/
    │   ├── IEventsPublisher.cs
    │   ├── IGeotrackingService.cs
    │   ├── IGuideBookingService.cs
    │   ├── IPublishedTourRepository.cs
    │   ├── ISearchService.cs
    │   └── ISeatsPoolService.cs
    └── ActivatePublishedTourCommandHandler.cs

Alex smiled and asked, knowing what they both learned, if they could do a little renaming.

The idea was to rename Ports/ directory to RequiredCapabilities/, Adapters/ directory to Providers/.

Additionally, rename Domain/ to Concepts/, which made Dan a little bit confused, as they were not discussing that before, but Alex asked to firstly do so and then they could discuss it.

src/
└── ActivatePublishedTour/
    ├── Api/
    │   └── Http/
    │       └── ActivatePublishedTourEndpoint.cs
    ├── Concepts/
    │   ├── Events/
    │   │   └── PublishedTourActivated.cs
    │   └── Models/
    │       ├── PublishedTour.cs
    │       ├── SearchEntry.cs
    │       └── Skill.cs
    ├── Providers/
    │   ├── PostgresPublishedTourRepository.cs
    │   ├── RabbitMqGuideBookingService.cs
    │   ├── RabbitMqGeotrackingService.cs
    │   ├── RabbitMqSearchService.cs
    │   └── RabbitMqSeatsPoolService.cs
    ├── RequiredCapabilities/
    │   ├── IEventsPublisher.cs
    │   ├── IGeotrackingService.cs
    │   ├── IGuideBookingService.cs
    │   ├── IPublishedTourRepository.cs
    │   ├── ISearchService.cs
    │   └── ISeatsPoolService.cs
    └── ActivatePublishedTourCommandHandler.cs
Discussion
Alex, an architect:I use "concepts" very intentionally - they express abstract ideas that are important in a particular capability that we provide.
Dan, a software engineer:Abstract idea?
Alex, an architect:For me an abstraction is a very specific perspective one holds to think about something. People often tend to think in absolute terms, mixing many perspectives, and putting that knowledge in a single entity - a User, a Tour, a Product.
Dan, a software engineer:Hmmm, so "concept" means some kind of a decomposition?
Alex, an architect:You are really close - a context-based decomposition, contextual segregation. For example, we don't want to think about base price while activating a published tour, that's why we don't bring that information in.
Dan, a software engineer:Same with past reviews, they are not needed while activating a published tour.
Alex, an architect:Exactly. Concepts are about focusing on what matters in a specific context, in a way they outline a boundary...
Dan, a software engineer:...In which they have sense and mean something!

Dan was excited about the new terminology. It seemed to him that while talking to business stakeholders, it was easier to talk about "capabilities" rather than "ports" or "commands".

Also, "providers" sounded slighlty more humane than "adapters".

It almost felt as super powers - was that the secret technique used by enterprise architects to communicate with business stakeholders?

Finally, "concepts" made perfect sense - it expressed the idea of focusing on what matters in a specific context.

He was eager to try those new terms in his next conversations with business stakeholders.

Hexagonal? Clean? Onion? Hardware?

Ok, time to stop this lovely tale.

"You must be kidding me", some Readers could think right now.

"It's soo foolish to rename well-known terms like ports and adapters to capabilities and providers, and domain to concepts!", others might comment in their heads.

"You did so just to sound fancy and different!", one could accuse.

"Isn't it a SOA reincarnation?", yat another could blame.

How dare I propose a new terminology, in the world where so many architectural patterns already exist, describing similar ideas?

Whatever we mentally do, as human beings, we build mental models.

A model is like a metaphor - it's not created to be perfect, accurate, and complete.

It is brought to life to help us understand something, to reason about it, to communicate our understanding to others.

It might have its flaws, but if it emphasizes the essentials, it does its job.

Isn't abstractions just that - imperfect mental models that help us reason about complex things?

Nevermind, let's get back to the point.

We use a variety of models to describe application architecture: hexagonal architecture, onion architecture, clean architecture, ports and adapters architecture.

Some of them were named after the shape, some were named after "clean code" to sound similar, others were named after hardware and the idea separating ports from adapters.

Each of them convey profound ideas that shape the way we reason about our applications, and aim at bringing certain qualities.

The big idea behind each of them is to isolate the application logic from the outside, external concerns, to make everything testable and maintainable.

But nothing really stops us from using THE domain model, a single entity for everything.

It will attract more and more the knowledge, growing into enormous size, becoming unmaintanable, untestable, and inflexible.

To counteract that, CQRS-thinking comes into play, helping us with model segregation: some for writing (or making a decisions), others for reading (or presenting information to make a decision).

Commands typically need little information, just to make a decision with transactional integrity, whereas queries might require tons of information, aggregated from various sources, to present a complete picture.

And nothing really stops us from coupling decision models across various use cases, making them interdependent and inflexible.

To counteract that, Vertical Slices-thinking comes into play, helping us with reasoning about independent use cases, where isolation and possible duplication are acceptable for independent evolution.

Of course, we're touching only the surface of these topics.

All of those models are imperfect, but useful - they help us reasoning and communicating about complex things.

When one developer says "port", another one immediately understands what is meant.

In a way, those are the language patterns technical people use to communicate.

What about communicating across boundaries?

When we communicate with business stakeholders, would they understand what is meant by "port" or "adapter"?

"Of course not, you dummy" - one might easily answer.

No one uses such words in business conversations, right?

How naive one would be to use entity, aggregate, repository or even domain in conversations with business stakeholders - those terms are pretty tactical, "low-level", and technical.

Others can use "use cases", "features", "services" - but those terms are so overloaded that they hardly help in communication.

Somehow architects are able to reason about business, enterprises, without stepping too much into technical details (which many times is a problem on its own, but let's leave it for another blogpost).

Through our tiny tale, we saw how an architect and a software engineer struggled to find a common ground to effectively communicate.

How often do we see that happening in real life - two technical folks discussing a solution, but failing to understand each other?

The idea behind this tale is not to resolve all the misunderstandings, and conflicts that arise in such conversations - oh no.

It is yet again an attempt to show that naming is framing - how we name things shapes the way we think about the world.

WHAT, not WHO and not HOW

Living next to Ports&Adapters and other types of application architecture might make us blind to strategic aspects of the business area we might build software solutions for.

And please do not get me wrong, dear Reader - I am not saying that Ports&Adapters and others are bad, incorrect, or that we should abandon it.

"All models are wrong (=imperfect, an interpretation of mine), but some are useful", as George Box said.

Let's start - what is a business capability?

a business capability - short version

What a business does or needs to be able to do to achieve its objectives.

A longer version:

a business capability - long version

An ability of an organization to perform a particular business activity, supporting its business operations and goals. It's a stable, abstract description of business functions that doesn't change much over time, regardless of how the organization is structured or which technologies are used.

Both are inspired by enterprise architecture thinking.

The most important is that we focus on WHAT needs to be done, not HOW and not WHO.

So we frame our thinking around capabilities - what needs to be provided to satisfy consumer needs.

Needs are very important as they enable the way of reasoning, Outside-In one, that drives everything.

Ideally, there should be one technical authority for a business capability.

In other words, one (capability) provider.

One could say that as long as the capability is provided with success, it does not matter who provides it, or how.

But when we step into a details of a given provider, suddenly how matters a lot.

Such provider becomes a consumer, requiring other capabilities in order to provide the capability it was contracted with.

A (capability) provider uses concepts that depict important ideas that matter for that capability.

Those abstract terms mean something inside that boundary, as if there were invisible contours outlining the context in which those concepts make sense.

Additionally, conceptual outlining helps counteracting absolute, universal and reality-chasing models that suffer from the knowledge gravity problem.

Yes, dear Reader, if you are familiar with Domain-Driven Design, you might see some similarities with Bounded Contexts and Ubiquitous Language.

And I think it might be quite important to express it explicitly, when we discuss application architecture.

Here comes the idea of COCOA - Capabilities-Oriented, Concepts-Outlined Architecture.

COCOA: Capabilities-Oriented, Concepts-Outlined Architecture

In COCOA, we would like to reason about application architecture through the lens of business capabilities, their providers, and concepts that outline the context in which make sense.

One shouldn't forget the big picture, the high-level persperctive, thinking only about low-level tactical details.

Sometimes a required capability would be provided by team-owned service, whereas other times it would be provided by a third-party system.

The capability does not change, but the provider does.

While testing, one might mock a required capability by using a mock provider so that we are able to verify if a specific step happened.

But when we register dependencies in the composition root, we would use a real provider that communicates with another system over HTTP, or a database.

Summing it all up:

  • When we think about concepts, we think about WHAT abstract ideas and terms matter in a specific context.
  • When we think about capabilities, we think about WHAT needs to be provided, not HOW and not WHO, from the persperctive of a consumer.
  • When we think about providers, we think about WHO provides the capability, and HOW it is provided, but only from the perspective of that provider.

Capabilities are pretty important here, emphasizing the behavioral aspects of the system.

Reasoning behind that is similar to Sandi Metz's words about objects and messages:

Conclusion 🔍

You don't send messages because you have objects, you have objects because you send messages.

Which can be rephrased in the context of capabilities and providers as:

Conclusion 🔍

You don't have capabilities because you need providers, you have providers because you need capabilities.

And of course, now you might be thinking now, dear Reader, if we discussed "business capabilities", what about "business processes"?

Let's get a brief definition.

a business process - short version

A business process is how the business does something.

And a longer version:

a business process - long version

It's a specific sequence of activities, steps, and tasks that transform inputs into outputs. Processes are more concrete and can change frequently as the business optimizes operations or adopts new technologies.

Doesn't it sound similar to a workflow we saw our three amigos visualizing on the board?

It was a logical sequence of steps that needed to be performed to achieve a specific goal.

A description of HOW something is done.

In that context, the goal was activating a published tour.

Let's shift our focus to the problem of locating "lost participants", that Pete mentioned.

He described HOW a guide (WHO) tried to locate lost participants by calling them over the phone, asking repeatedly until they reached the group.

So the guide was a capability provider in that context.

The architect and the software engineer suggested an abstraction - "geotracking" capability.

They tried to depict WHAT needed to be provided.

Of course, when this "geotracking" capability is provided by a software system, there will be a sequence of logical steps to provide it.

But yet again, it is a matter of the perspective.

When we look from outside, as consumers, we care about WHAT.

When we look from inside, as capability providers, we care about HOW.

A consumer and a provider perspectives

For a consumer - it does not matter HOW geotracking is provided, as long as it is provided.

For a provider - it matters HOW geotracking is provided, as long as it satisfies consumer needs.

If we are outside the boundary, reasoning will be framed around capabilities.

If we are inside the boundary, reasoning will be framed around processes.

Why COCOA?

You might be wondering, dear Reader, why and how on earth I came up with COCOA.

It's because I love chocolate?

Am I a cocoa farmer on the side?

I needed a catchy phrase, that's all.

The big thing is not the name, not the symbol, not the abstraction.

The real deal is the mental model behind it.

I tried to reflect on my experiences and observations, and synthesize them into something useful.

A mental model that mainly helps me with reasoning and helps me with communication.

It enables me changing the levels (using Gregor Hohpe's The Software Architect Elevator metaphor), connecting higher-level, strategic thinking with tactical, technical implementations.

As mentioned before, I am not saying that Ports & Adapters (and others), CQRS and Vertical Slices are anyhow "bad" or "incorrect".

I learned from them, used them, drew from them, and they shaped the way I think about application architecture.

COCOA is another model one can use to think about application architecture.

It still uses isolation, separation of concerns, and other qualities, but it also tries to capture and emphasize strategic aspects of the business area we are building software solutions for.

Organizing code is very important topic to many, so how potentially COCOA would look like in practice?

src/
└── ActivatePublishedTour/
    ├── Api/
    ├── Concepts/
    ├── Providers/
    ├── RequiredCapabilities/
    └── ActivatePublishedTourCommandHandler.cs

And when expanding all the directories:

src/
└── ActivatePublishedTour/
    ├── Api/
    │   └── Http/
    │       └── ActivatePublishedTourEndpoint.cs
    ├── Concepts/
    │   ├── Events/
    │   │   └── PublishedTourActivated.cs
    │   └── Models/
    │       ├── PublishedTour.cs
    │       ├── SearchEntry.cs
    │       └── Skill.cs
    ├── Providers/
    │   ├── PostgresPublishedTourRepository.cs
    │   ├── RabbitMqGuideBookingService.cs
    │   ├── RabbitMqGeotrackingService.cs
    │   ├── RabbitMqSearchService.cs
    │   └── RabbitMqSeatsPoolService.cs
    ├── RequiredCapabilities/
    │   ├── IEventsPublisher.cs
    │   ├── IGeotrackingService.cs
    │   ├── IGuideBookingService.cs
    │   ├── IPublishedTourRepository.cs
    │   ├── ISearchService.cs
    │   └── ISeatsPoolService.cs
    └── ActivatePublishedTourCommandHandler.cs

So nothing really changed, one could comment.

"It's just a naming, fool", some might say.

But naming is framing, when we see "geotracking" required capability, might it be that another team requires it also?

Might it be that we can reuse that capability in other contexts?

If not, what can we do to make it reusable?

If yes, why aren't we doing it?

I am not saying about reusing that interface, but reusing the capability.

Aligning the language used, possible web services providing that capability, and so on.

"You say providers - how does it differ from services?", one might ask.

Well, as many concepts in our industry, "service" is an overloaded term.

Appearing on different levels of abstractions - an application level, an architecture level, a business level.

Many might hold an image of services having dozens of methods, exposing too big API surface, making them impossible to change.

I hope you know, dear Reader, I am more interested in roles things play.

And I am not the first one who tries to express an important role something plays by renaming it.

In COCOA, capabilities strive to emphasize the contextual behaviors.

Concepts aim at expressing contextual models.

Finally, providers embody "the doers", but they shall come last in the whole process.

I only give it a name so that I can refer to it later.

It is a useful abstraction, a mental model, still being imperfect.

I don't aim at building a school or a church around it - it's goal is to help different reasoning.

Should you use COCOA?

When you get back to work, refactor all codebases, align with COCOA.

And give me fifty.

Ok, jokes aside.

I don't know, dear Reader.

You might find it useful, or not.

COCOA doesn't throw away isolating application logic from outside concerns, used to achieve testability, which is advocated by Ports & Adapters and others.

COCOA doesn't throw away locality of behavior, used to achieve high cohesion and evolvability, which is advocated by Vertical Slices.

COCOA doesn't throw away segregation of models, used to achieve maintainability and flexibility, which is advocated by CQRS.

COCOA doesn't throw away domain modeling, used to achieve alignment with business areas, which is advocated by Domain-Driven Design.

All of those abstract ideas need to live in the designer's mind.

COCOA is a way of reasoning, nothing more, nothing less.

Expressing COCOA through code organization is just a way to express those ideas.

You can have a single file, having all of mentioned ideas, and COCOA will be there.

You can have a complex directory structure, and COCOA will appear again.

COCOA is in the eye of the beholder, same as a tree that falls in the forest, and no one is around to hear it.

Remember: systems are built by, with and for people.

Talk to your experts, collaborate with people - that's what truly matters.

Happy building!