From 3cdb6ea97aada3175fe4c1ea58e5d8245b482f05 Mon Sep 17 00:00:00 2001 From: Galip Tolga Erdem Date: Wed, 20 Mar 2024 12:58:07 -0400 Subject: [PATCH] Added best practice for domain service docs --- docs/en/Best-Practices/Domain-Services.md | 65 ++++++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/docs/en/Best-Practices/Domain-Services.md b/docs/en/Best-Practices/Domain-Services.md index bb43ee9025..89d3125857 100644 --- a/docs/en/Best-Practices/Domain-Services.md +++ b/docs/en/Best-Practices/Domain-Services.md @@ -1,7 +1,68 @@ ## Domain Services Best Practices & Conventions -> **This document is not ready yet. Please see the [Domain Services](../Domain-Services.md) document.** + + +### Domain Service + +- **Do** define domain services in the **domain layer**. +- **Do not** create interfaces for the domain services **unless** you have a good reason to (like mock and test different implementations). +- **Do** name your domain service with `Manager` suffix. + +For the example of a domain service: +```cs +public class IssueManager : DomainService +{ + //... +} +``` + +### Domain Service Methods + +- **Do not** define `GET` methods. `GET` methods do not change the state of an entity. Hence, use the repository directly in the Application Service instead of Domain Service method. + +- **Do** define methods that only mutates data; changes the state of an entity or an aggregate root. + +- **Do not** define methods with generic names (like `UpdateIssueAsync`). + +- **Do** define methods with self explanatory names (like `AssignToAsync`) that implements the specific domain logic. + + +- **Do** accept valid domain objects as parameters. + +```cs +public async Task AssignToAsync(Issue issue, IdentityUser user) +{ + //... +} +``` + +- **Do** throw `BusinessException` or custom business exception if a validation fails. + + - **Do** use domain error codes with unique code-namespace for exception localization. + +```cs +public async Task AssignToAsync(Issue issue, IdentityUser user) +{ + var openIssueCount = await _issueRepository.GetCountAsync( + i => i.AssignedUserId == user.Id && !i.IsClosed + ); + + if (openIssueCount >= 3) + { + throw new BusinessException("IssueTracking:ConcurrentOpenIssueLimit"); + } + + issue.AssignedUserId = user.Id; +} +``` + +- **Do not** return `DTO`. Return only domain objects when you need. +- **Do not** involve authenticated user logic. Instead, define extra parameter and send the related data of ` CurrentUser` from the Application Service layer. + + ## See Also -* [Video tutorial](https://abp.io/video-courses/essentials/domain-services) \ No newline at end of file +* [Video tutorial](https://abp.io/video-courses/essentials/domain-services) +* [Domain Services](../Domain-Services.md) +* [Exception Handling](../Exception-Handling.md) \ No newline at end of file