Search code examples
c#domain-driven-designnaming-conventions

Struggle with names in DDD ; how to name my services and entities in external layers?


I'm trying to create a clean API project structure relaying on the DDD principles.

So far I have :

  • Project.Api : REST Endpoints, controllers, and Program.cs for the DI configuration.
  • Project.Domain : The pure business logic, following the rules provided by the business team.
  • Project.Dal : EntityFramework and all the database related stuff.
  • Project.Application : A higher layer aiming to link the Domain, the Dal and external layers such as Grpc/Api endpoints.
  • Project.Grpc : Using protobuf.net-grpc, this project implements the grpc services which interact with the Application layer.
  • Project.Contracts : Using an on-build action, this project automatically generates the .proto files according to the structure and naming of the Gprc layer.

Giving a concret example, let's say I have 2 business entities named User and Role. These entities are defined in the Domain project. I have also a Domain service called UserService. Let's forget about the Dal as this layer is irrelevant for the example.

In my Grpc layer, which will be identically reproduced as .proto files in my Contracts project, I want to use the exact same naming as the Domain (or as close as I can) because my clients will consume my API using these entities, and I don't want them to have entity names inside their code such as GrpcUser, or UserContract or else. I want them to have simple class names, without any informations that reflects the fact that these are Contracts classes. So in my Grpc project, I would have something like : User, Role, UserRequest, UserResponse, RoleRequest, RoleResponse, UserService, RoleService. Some of them have the same name than my Domain entities. But because my Grpc layer will never directly interact with my Domain layer, I'll never have a name conflict within these projects.

And now let's talk about the Application layer, where I'm struggling with the naming convention I want to use.

Basically, a service from my Application layer will sometimes have a name close to the Domain name. So if I want a logic built around my User entity, I will need a UserService also in my Application layer. But I'll have a name conflict with both the Domain version of the UserService, and the Grpc version of the UserService.

I will have to inject the Domain.UserService in my Application.UserService, and my Application.UserService will later be injected in my Grpc.UserService to open my Domain to the external Grpc layer. Furthermore, my Application services should have input and outputs. They usually return a Dto version of the Domain entity, so I don't have any problem to create a UserDto, or more precise classes such as CreateUserDto. But for the input, usually I would need Requests too. Exactly like my Grpc project.

To solve my naming issue, I was starting to add Application to all my classes in this project. For example, I would have an UserApplicationService, which will receive a CreateUserApplicationRequest and returns a UserDto.

But these names are very long and not convenient to use, and I've never seen anyone using this kind of naming convention (but maybe I'm wrong about this point.)

So my questions are : are my naming choices wrong ? If not, how could I name my entities and services inside my Application layer ?


Solution

  • Naming in a DDD-based project with multiple layers can definitely be challenging. Here's a breakdown of how you might approach naming for each layer:

    1. Domain Layer Entities: User, Role Services: UserService, RoleService
    2. Application Layer Since this layer serves as a bridge between the Domain and external layers (like Grpc or API), it often needs to orchestrate calls to Domain services and provide DTOs for communication.

    Naming Conventions:

    Services:

    Prefix with Application if necessary, but for clarity and conciseness, consider a simpler approach. Use a name that reflects its role in the Application layer. For example, UserManager or UserHandler instead of UserApplicationService. DTOs and Requests:

    Keep DTOs named based on their purpose rather than the layer they belong to. For example: CreateUserDto UpdateUserDto UserDto Requests:

    Use names that clearly describe their role in the Application layer, such as CreateUserRequest, UpdateUserRequest. Example:

    Services: UserManager (Application layer service) DTOs: UserDto, CreateUserDto, UpdateUserDto Requests: CreateUserRequest, UpdateUserRequest 3. Grpc Layer Service Names: Use straightforward names as you mentioned: UserService, RoleService Message Types: Use names that mirror the Domain where possible, e.g., User, Role Requests and Responses can be named according to their purpose, e.g., UserRequest, UserResponse General Tips: Avoid Prefixes/Suffixes: Try to avoid excessive prefixes or suffixes that might clutter names. Instead, rely on context and project structure to clarify roles.

    Consistency: Ensure naming conventions are consistent across your project to avoid confusion. Document your naming conventions so that all team members follow them.

    Descriptive Names: Focus on clarity and descriptiveness over brevity. Clear names help in understanding the role and purpose of each component, even if they are a bit longer.

    By using these conventions, you should be able to clearly differentiate between entities, services, and DTOs while maintaining a clean and understandable codebase.