Arda Akgür
Most ideas in software architecture do not appear fully formed from nothing.
A principle an engineer learns takes a different shape when they meet another problem. Sometimes a small idea grows over years — applied, broken, redesigned — and eventually becomes its own architectural approach.
That is how the story of ARC-DDD began.
I started developing the first versions of this approach while working as an Associate Engineer in Australia.
But when I explain where the idea came from, I especially need to give credit to one person:
Victorian Software CEO Adrian Budiman.
Adrian was the first person who showed me the idea of splitting a system into horizontally separate domains, instead of thinking about domains only as classic architectural layers.
That idea became my starting point.
I later carried this approach much further in systems I built myself.
Today ARC-DDD, or as I sometimes call it Australian DDD, is the result of that process.
Classic Domain-Driven Design usually splits a system into vertical layers:
That approach is extremely valuable, and ARC-DDD does not try to eliminate it.
What I added is a second axis.
While the system is split into vertical layers, the domain model itself is also split into horizontal bounded contexts.
For example:
Core├── Users├── Events├── Transactions├── Vendors└── PaymentsThe fundamental rule here is this:
One domain should not know another domain's entire world.
This is where ARC-DDD's real character emerges.
One of the most common problems I see in large systems is enormous entity models.
For example, there is a single User class in the system.
Over time, everything gets added into it:
PasswordPhoneAddressBalanceIBANKYCPermissionsProfileSecurityTransactionsPreferences...Then the Events domain starts using the entire User model even when it only wants to show the user's name and photo.
The Transactions domain uses the same model for balance and IBAN.
The Vendor system uses the same model again.
In the end, a system that looks domain-separated in theory becomes, in practice, one giant structure tied together through the same entities.
ARC-DDD takes a different approach here.
For example:
Users.UserEvents.User2Transactions.User3These are different domain models.
But they can represent the same physical database table.
Users.User ──┐Events.User2 ──┼──> Users tableTransactions.User3 ──┘If the Events domain only needs:
UserIdFirstNameFamilyNamePhotoUser2 contains only those.
If the Transactions domain needs:
UserIdBalanceIBANVerifiedfields, then User3 is defined according to its own domain needs.
Each domain sees the world only as far as it needs to.
That is exactly the core approach of ARC-DDD: bounded contexts are separate, and instead of carrying another domain's full aggregate, you create a domain-local projection that contains the fields you need. When necessary, that projection is mapped to the same physical table.
One important characteristic of ARC-DDD is that it does not treat separate databases as mandatory for creating bounded contexts.
For example, with Entity Framework Core:
modelBuilder .Entity<User2>() .ToTable("Users") .HasKey(x => x.UserId);User2 in the Events domain can still bind to the physical Users table.
But because the model only contains the properties the Events domain needs, that domain does not drag unnecessary user fields into its own model.
In the public reference implementation (eski-dev), the Goldtag example shows User, User2, and User3 binding to the same Users table from different domain perspectives. User2 represents the data and behavior Events needs; User3 represents what Transactions needs.
This gives us an important balance:
The database can be physically shared, but domain models do not have to be shared.
That is one of ARC-DDD's core principles.
This separation does not stop at the folder level.
Each bounded context has its own DbContext structure.
For example:
UserDbContextEventsDbContextTransactionDbContextVendorsDbContextThe Events domain knows its own projection models.
The Transactions domain knows its own models.
The Users domain owns the canonical User model.
In the public reference implementation (eski-dev), for example, UserDbContext uses the canonical User model, EventsDbContext uses the User2 projection, and TransactionDbContext uses the User3 projection within its own context.
For that reason, one domain does not directly import another domain's Core models.
Inside Events:
using Gold.Core.Users;instead of pulling the entire User aggregate into the system, Events creates its own projection.
This is deliberate duplication.
Because in ARC-DDD, sometimes:
A small amount of duplication is cheaper than strong coupling.
One of the core rules at the Core level is that domain folders do not import each other directly. For example, instead of using Gold.Core.Users, Events creates its own local representation such as User2.
In real applications, bounded contexts cannot live in complete isolation.
A single operation may need multiple domains at once, such as:
ARC-DDD does not connect domain layers to each other here. Instead, it moves composition to the outer edge of the system.
For example:
API | +--> OrderingRepository | +--> PaymentsRepository | +--> UsersRepositoryIn other words, cross-domain orchestration happens at the API or application level.
Core domains do not import each other and create a dependency chain.
In eski-dev as well, cross-domain composition is done on the API side. A controller or application service can work with multiple repositories when needed, but Core domains are not wired to each other.
This separation becomes very valuable as the system grows.
If I were creating a new ARC-DDD system today, I would keep the basic structure quite simple:
Product.CoreProduct.DomainProduct.ApiDependency direction:
Product.Api ↓Product.Domain ↓Product.CoreCore contains pure domain models.
It has no Entity Framework or infrastructure dependency.
Domain contains the persistence layer, DbContexts, and repository structures.
Api acts as the composition root and orchestrates different bounded contexts within the same use case when needed.
The dependency direction in eski-dev's current reference structure is also Gold.Api → Gold.Domain → Gold.Core. Keeping the Core layer free of infrastructure packages is one of the fundamental rules.
If I had to describe this architecture in a single sentence today:
ARC-DDD is a software architecture approach that extends classic layered DDD with horizontal bounded contexts and domain-specific entity projections over shared tables.
I define it more technically as:
Classic layered DDD + horizontal bounded-context folders in Core + per-context entity projections over shared tables.
But for me, the more important idea behind this approach is this:
A domain should not see all the knowledge that exists in the system — only the world it needs to do its own work.
Because for me, the origin of the approach goes back to Australia.
The horizontal domain-separation idea I learned from Adrian Budiman while working as an Associate Engineer was the starting point.
I later expanded that idea by applying it in my own systems — with domain-local entity models, shared-table projections, per-domain DbContexts, and controlled cross-domain composition principles.
So when I talk about ARC-DDD, I do not think it is right to present it as "I invented everything from scratch."
Engineering usually does not progress that way anyway.
Someone gives you a strong idea.
You apply it to other problems.
You see what is missing.
You add new principles on top.
And years later, a system emerges that is quite different from the original idea.
For me, ARC-DDD developed exactly that way.
The horizontal domain thinking Adrian showed me was the spark.
My contribution was turning that spark into a practical architectural model that today I call ARC-DDD.
ARC-DDD is not only an architectural approach I describe in theory.
For anyone who wants to see how the approach is applied inside a real system, I have published one of my older development codebases publicly:
GitHub:
https://github.com/Arcnaboo/eski-dev
The repository is public, C#-based, and published under the MIT license.
This repository is the public Goldtag legacy backend reference implementation for ARC-DDD.
The repository explicitly defines the reference implementation as:
Gold.CoreGold.DomainGold.ApiInside the repository, I especially recommend looking at these models:
Gold.Core/Users/User.csGold.Core/Events/User2.csGold.Core/Transactions/User3.csThese show ARC-DDD's most important idea directly.
Canonical User belongs to the Users bounded context.
Events uses a narrowed User2 model shaped for its own needs for the same user.
Transactions uses a User3 model suited to its own operations.
You can see the same approach in models such as Event and Event2, Notification and Notification2. Look at these files in the repository especially when learning the reference implementation.
An important distinction needs to be made here.
This repository carries the traces of an old, real production codebase.
So I would not use every implementation detail in it one-to-one in a system I would write from scratch today.
For example, old connection-string approaches, some controller structures, incomplete dependency-injection usage, and legacy pieces that are no longer needed are not ARC-DDD itself.
I call out this difference especially:
Take the ideas, modernize the mechanics.
The lasting idea:
Horizontal bounded contexts + per-domain projections + per-domain DbContexts.
Not the historical implementation details of the old code.
I do not think it is enough to explain an architectural approach with diagrams alone.
People need to be able to:
That is why I want both the architectural documentation and a real public reference implementation for ARC-DDD to stay accessible.
Repository:
https://github.com/Arcnaboo/eski-dev
But I do not want you to copy every line in the repository in order to understand ARC-DDD.
Quite the opposite.
Separate the parts that come from the age of the code.
Look at the domain boundaries.
Look at how the same physical entity is modeled differently across different bounded contexts.
Look at how the contexts are separated.
Look at why Core does not import other domains' models.
Because the essence of ARC-DDD is not a framework or a specific technology.
Entity Framework can change.
.NET can change.
The database can change.
The repository pattern can change.
Years from now, most of the tools we use today may have changed as well.
But the fundamental principle does not change:
Make domain boundaries real boundaries in code.
And show each domain only the world it needs.