DEV Community

Cover image for Orchestration Isn't Just for AI Agents. What About Our Applications?
Pierrie Mostert
Pierrie Mostert

Posted on

Orchestration Isn't Just for AI Agents. What About Our Applications?

Explore the DataArc Orchestration Framework and architecture on GitHub

These days, orchestration seems to come up everywhere in conversations about AI agents. But what about the applications we've been building for years?

I recently started a discussion on Reddit asking whether Clean Architecture sometimes introduces more complexity than necessary. It sparked an interesting debate and got me thinking about some of the patterns we've come to accept as standard practice.

Don't get me wrong. I'm a firm believer in Clean Architecture, DDD and separation of concerns.

Clean Architecture, to me, is fundamentally about protecting business rules from implementation details. Domain rules should be able to evolve without unnecessarily forcing changes to persistence, presentation or infrastructure.

But sometimes, the way we implement these principles creates more moving parts than the business problem actually needs.

Here are five problems I wanted to address.

1. Do we really need all those CQRS handlers?

Consider a simple Employee entity.

A typical mediator-based implementation might introduce GetEmployeeByIdQuery, CreateEmployeeCommand, UpdateEmployeeCommand and their respective handlers.

Nothing inherently wrong with that.

But what happens when a business workflow needs to retrieve an employee, evaluate domain policies, update their salary and perform additional operations?

We start chaining handlers, introducing handlers to coordinate other handlers, or moving everything into application services.

CQRS doesn't require this structure. It's simply become a common implementation convention.

I wanted explicit input/output contracts and workflow execution without having to create a request/response handler for every operation.

2. Business workflows don't always fit inside one DbContext

Take employee onboarding as an example.

You might have separate modules for HR, Finance, IT and Operations, each maintaining its own EF Core DbContext.

The business sees one operation: onboard an employee.

The application sees several persistence boundaries that need to participate in the same workflow.

Now we're managing execution order, transaction participation, failures and consistency across those boundaries.

That's a lot of plumbing to repeat for every similar use case.

I wanted a way to make this coordination explicit and reusable, including the ability for compatible EF Core contexts to participate in a shared SQL Server transaction where appropriate.

This isn't distributed transaction orchestration across independent services. It's about coordinating multiple persistence contexts within a compatible relational transaction boundary.

3. Business rules should decide WHAT, not HOW

This is probably the most important one for me.

A domain policy should determine whether an operation is permitted.

It shouldn't need to know how a transaction is created, how many databases are involved or which persistence operation executes first.

For example, an onboarding policy might reject an employee who has already been onboarded.

That decision belongs to the domain.

The orchestrator coordinates the approved workflow, while infrastructure handles the persistence mechanics.

Business rules decide what is allowed. Orchestration coordinates execution.

That separation makes it easier to evolve domain rules without unnecessarily changing the underlying infrastructure.

4. Why keep rebuilding the same infrastructure?

Transaction coordination, execution policies, observability and failure handling tend to appear repeatedly as applications grow.

One application service handles transactions one way. Another does something slightly different. A third introduces another layer of handlers.

Before long, we have several implementations of essentially the same execution concerns.

I wanted these responsibilities to have an explicit, reusable home instead of scattering them throughout the application.

Not because every application needs another framework, but because repeatedly solving the same infrastructure problem has a maintenance cost of its own.

5. EF Core models aren't automatically domain models

It's quite common to see persistence models gradually becoming the place where business decisions live.

Sometimes that's perfectly reasonable for a straightforward application.

But with more complex domains, persistence-specific concerns can creep into business logic, making it harder to change one without affecting the other.

Orchestration doesn't magically fix poor domain modelling.

What it can do is provide a dedicated execution boundary that keeps transaction mechanics and persistence coordination away from domain policies.

So, what did I build?

These problems led me to develop the DataArc Orchestration Framework.

To demonstrate the approach, I built an employee onboarding application using .NET Aspire, domain policies, an observer pipeline and multiple EF Core contexts across Identity, HR, Finance, IT and Operations.

The idea is straightforward: keep business decisions in the domain, coordinate workflows explicitly, and let infrastructure handle persistence.

The demonstration is publicly available for anyone interested in exploring the implementation, questioning the design or trying it out.

Explore the DataArc Orchestration Framework and employee onboarding demo on GitHub

One final thought

I'm not suggesting that Clean Architecture, CQRS, repositories or application services are wrong.

And I'm certainly not suggesting every CRUD application needs an orchestrator.

Every abstraction has a cost, including orchestration.

But when business workflows span multiple modules, persistence contexts and domain policies, the cost of repeatedly implementing that coordination becomes a real engineering concern.

That's the problem I've been trying to solve.

So perhaps the question isn't whether we should use more or fewer architectural patterns.

It's whether the patterns we're introducing are actually reducing complexity, or simply moving it around.

I'd be interested to hear how others approach orchestration in their applications. Do you favour application services, mediator handlers, explicit orchestrators or something else?


This article grew out of a discussion I started on r/softwarearchitecture.

Top comments (0)