Реальная Цена Абстракций в .NET. Продолжение
Начало
Обёртки Сервисов: контекст имеет значение
✅ Хороший пример
При интеграции с внешними API обёртка действительно полезна, поскольку централизует задачи:
public interface IGitHubClient
{
Task<UserDto?> GetUserAsync(string username);
Task<IReadOnlyList<RepoDto>>
GetRepositoriesAsync(string username);
}
public class GitHubClient(HttpClient httpClient)
: IGitHubClient
{
public Task<UserDto?> GetUserAsync(string username) =>
httpClient
.GetFromJsonAsync<UserDto>($"/users/{username}");
public Task<IReadOnlyList<RepoDto>>
GetRepositoriesAsync(string username) =>
httpClient
.GetFromJsonAsync<IReadOnlyList<RepoDto>>(
$"/users/{username}/repos");
}
Эта обёртка изолирует детали API GitHub. При изменении аутентификации или развитии конечных точек вы обновляете одно место. Вашей бизнес-логике не нужно разбираться с HTTP-заголовками, базовыми URL или JSON-сериализацией.
❌ Плохой пример
Проблемы начинаются, когда мы обёртываем наши собственные стабильные сервисы, не добавляя им ценности:
public class UserService(IUserRepository userRepository)
{
// Просто перенаправляем вызовы
public Task<User?> GetByIdAsync(Guid id)
=> userRepository.GetByIdAsync(id);
public Task<IEnumerable<User>> GetAllAsync()
=> userRepository.GetAllAsync();
public Task SaveAsync(User user)
=> userRepository.SaveAsync(user);
}
Этот UserService только добавляет косвенности. Всё, что он делает, — перенаправляет вызовы в IUserRepository. Он не обеспечивает соблюдение бизнес-правил, не добавляет валидацию, не реализует кэширование и не предоставляет никакой реальной функциональности. Это слой, существующий только потому, что «сервисы — это хорошая архитектура».
По мере того, как эти атрофированные обёртки множатся, ваша кодовая база превращается в лабиринт. Разработчики тратят время на перемещение по слоям вместо того, чтобы сосредоточиться на том, где на самом деле находится бизнес-логика.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/the-real-cost-of-abstractions-in-dotnet