Do you use unique DTOs per use case?

Updated by Brady Stroud [SSW] 3 months ago. See history

123
<introEmbed body={<> In Clean Architecture, it is normally better to have a unique Data Transfer Object (DTO) for each endpoint or use case. While sharing DTOs across multiple endpoints might seem like a way to save some code, it often leads to several problems: * **Unnecessary Data Transfer:** Endpoints sending more data than what is actually needed, this can lead to performance issues. * **Increased Coupling:** When multiple endpoints share the same DTO, a change required by one endpoint can inadvertently affect others. * **Developer Confusion:** Developers will find it hard to understand which properties are relevant for a specific endpoint, leading to potential misuse or misunderstanding of the data structure. </>} />

By creating unique DTOs tailored to each endpoint's specific requirements, you ensure that:

  • Endpoints only deal with the data they need.
  • Performance is optimized by avoiding the transfer of superfluous data.
  • Endpoints are decoupled, making them easier to develop, test, and maintain independently.
namespace Northwind.Trading.Application.Contracts.Models;
public class OrderItemModel
{
public int OrderId { get; set; }
public string CustomerId { get; set; }
public DateTime OrderDate { get; set; }
public decimal TotalAmount { get; set; }
public OrderStatus Status { get; set; }
/// <summary>
/// Used for GetOrderListEndpoint. Ignore when updating
/// </summary>
public string? ShipFromCountry { get; set; }
/// <summary>
/// Used only for GetOrdersEndpoint.
/// </summary>
public DateTimeOffset ModifiedDateUtc { get; set; }
/// <summary>
/// Detailed list of order items. Only for GetOrderDetails.
/// Not used for GetOrderList
/// </summary>
public List<OrderItemViewModel> OrderItems { get; set; } = [];
}

❌ Figure: Figure: Bad example - `OrderViewModel` is used for multiple purposes (e.g., `GetOrderList`, `GetOrderDetails`, `CreateOrder`) and has accumulated many properties, making it hard to read and maintain.

namespace Northwind.Trading.Application.Contracts.OrderQueries.Models;
public class GetOrderListItemDto
{
public int OrderId { get; set; }
public string CustomerId { get; set; }
public DateTime OrderDate { get; set; }
public decimal TotalAmount { get; set; }
public OrderStatus Status { get; set; }
}

✅ Figure: Figure: Good example - A simple `OrderSummaryDto` designed specifically for an endpoint that lists orders.

Acknowledgements

Brady Stroud
Daniel Mackay
Related rules

Need help?

SSW Consulting has over 30 years of experience developing awesome software solutions.

We open source.Loving SSW Rules? Star us on GitHub. Star