4# My Journey From CRUD Developer to Building a Production-Oriented Go Backend
Application Layer: Orchestrating Multiple Domains
In the previous section, I began to understand that transactions should not be the responsibility of the repository. A business operation can involve multiple repositories, so the transaction boundary must exist outside of the repository. From there, I introduced the Unit of Work pattern. But after that, a new question arose:
If a single operation requires multiple domains, who should manage the order of the process?
The answer led me to the concept of the Application Layer.
A Single Business Operation Can Involve Multiple Domains
Previously, I was quite comfortable with the pattern:
Handler β Usecase β Repository
For simple operations, this still makes sense. For example:
Get Profile β Profile Usecase β Profile Repository
There is only one domain and one persistence flow. But consider the registration process. Registration is not just: INSERT user In a growing system, registration can involve: Register β βββ Credential βββ Profile βββ Verification βββ Session / Challenge
Each of these has distinct responsibilities. Credential handles credentials. Profile handles user profiles. Verification handles the verification process. They should not be merged into a single domain just because they happen to be used together in one operation. The problem now is: Who knows that registration requires all of them?
Do Not Make a Single Usecase Aware of All Domains
One seemingly easy solution is to create a monolithic usecase:
Then:
RegisterUsecase βββ Credential βββ Profile βββ Verification
At first, it seems practical. However, if every business operation is implemented this way, over time you end up with objects like:
AuthService βββ Register βββ Login βββ Logout βββ VerifyOTP βββ RefreshSession βββ CreateProfile βββ UpdateProfile βββ UploadAvatar βββ ...
Eventually, a single object knows far too much. I began to realize that the issue isn't simply how many functions an object has. The real issue is: Does the object hold multiple unrelated responsibilities?
Domain Usecases and Application Operations Are Two Different Things
This is where I started differentiating between two concepts. Usecase
A Usecase contains operations relevant to a specific domain. For example: Credential βββ Create βββ Validate βββ UpdatePassword
or: Profile βββ Create βββ Get βββ Update
A Usecase doesn't need to know about the entire system. It focuses solely on the domain or capability under its responsibility.
Application
The Application knows the larger business flow. For example: Register User The Application knows that this operation requires: Credential β Profile β Verification
However, the Application does not take over the logic of those domains. It merely orchestrates them.
The Application as an Orchestrator
I then started viewing the Application Layer as an orchestratorβnot the performer doing all the work, but the director that knows: what operation is being performed, which domains are needed, the sequence of operations, the transaction boundary, how multiple capabilities are combined into a cohesive flow.
Example: Registration For example, suppose I have:
And then the application operation:
The flow can be visualized as: Register βΌ Validate Registration βΌ Create Credential βΌ Create Profile βΌ Create Verification Challenge βΌ Commit
The key point is that each operation below it maintains its own boundaries. The Application doesn't need to know how a credential is created. It simply requests: Create Credential The Credential usecase determines how credential rules are applied. The same goes for Profile.
Orchestration Is Not a Business Rule
This is a crucial distinction. For instance, consider the rule: Password must be at least 8 characters long. That is a business/domain rule. It does not belong in the Application layer. Credential Usecase β Password Policy
On the other hand: After the credential is created successfully, create the profile within the same transaction. That is part of orchestration. Application β Credential β Profile
With this separation, the Application layer doesn't turn into a dumping ground for all business logic. Application Knows the Flow, Not the Details
Imagine the Application as a director and Usecases as actors. The Application guides the overall scene, while each Usecase executes its specific capability.