Архитектура приложения
Инверсия зависимостей, слоистая и Clean/Onion архитектура, паттерн Repository поверх EF Core, отображение DTO и доменных сущностей.
5 вопросов
MiddleТеорияОчень частоКак внедрение через конструктор поддерживает принцип инверсии зависимостей (DIP)?
Как внедрение через конструктор поддерживает принцип инверсии зависимостей (DIP)?
Класс принимает нужное как параметр-интерфейс и не создаёт конкретный тип через new, поэтому зависит лишь от абстракции, которой владеет сам. Реализацию выбирает composition root, и зависимость инвертируется в сторону домена.
Типичные ошибки
- ✗Считать, что любое использование контейнера удовлетворяет
DIP, включая service locator внутри метода - ✗Позволять инфраструктуре объявлять интерфейс, из-за чего домен по-прежнему зависит от инфраструктуры
- ✗Считать
DIPтрюком ради тестируемости, а не правилом о направлении зависимостей
Уточняющие вопросы
- →Кто должен владеть интерфейсом — потребитель или реализация — и почему?
- →Что ломается, когда singleton-сервис принимает scoped-зависимость в конструкторе?
JuniorТеорияЧастоЧем объект передачи данных (DTO) отличается от доменной сущности?
Чем объект передачи данных (DTO) отличается от доменной сущности?
DTO — плоская структура без поведения, переносящая данные через границу: это контракт API. Доменная сущность имеет идентичность, инварианты и поведение. Маппинг между ними не даёт схеме хранения протечь в контракт.
Типичные ошибки
- ✗Возвращать сущности Entity Framework из контроллеров, пуская схему БД в контракт API
- ✗Класть бизнес-правила и инварианты в
DTOвместо доменной сущности - ✗Считать, что
DTOнужна идентичность и семантика равенства, как у сущности
Уточняющие вопросы
- →Когда отдельный
DTOна каждый endpoint лучше одного общегоDTO? - →Что ломается, когда один и тот же
DTOслужит и запросом, и ответом?
JuniorТеорияЧастоИз каких слоёв состоит типичное многослойное решение на ASP.NET Core?
Из каких слоёв состоит типичное многослойное решение на ASP.NET Core?
Presentation (контроллеры, DTO), application (сценарии), domain (сущности, бизнес-правила) и infrastructure (Entity Framework, HTTP-клиенты). Каждый слой обращается только к нижележащему, а домен свободен от типов фреймворка и базы.
Типичные ошибки
- ✗Позволять доменному слою ссылаться на
DbContextили типы ASP.NET Core - ✗Класть бизнес-правила в контроллеры, оставляя домен анемичным набором данных
- ✗Считать разделение на слои раскладкой по папкам, а не правилом зависимостей
Уточняющие вопросы
- →Куда должна быть направлена зависимость между domain и infrastructure и почему?
- →Чего стоит анемичная доменная модель по мере роста бизнес-правил?
SeniorТеорияЧастоКак архитектура Clean/Onion ложится на проекты решения ASP.NET Core?
Как архитектура Clean/Onion ложится на проекты решения ASP.NET Core?
Domain хранит сущности и свои интерфейсы и не ссылается ни на что; Application держит сценарии поверх него; Infrastructure реализует эти интерфейсы; Web — composition root. Зависимости направлены внутрь: Infrastructure ссылается на Domain, но не наоборот.
Типичные ошибки
- ✗Ссылаться на
DbContextили типы ASP.NET Core из доменного проекта - ✗Объявлять интерфейс репозитория в Infrastructure вместо Domain или Application
- ✗Считать деление на кольца вопросом названий проектов, а не проверяемым направлением зависимостей
Уточняющие вопросы
- →Какой проект должен владеть интерфейсом репозитория и почему это размещение важно?
- →Что делает composition root такого, чего не вправе делать ни один другой проект?
MiddleТеорияИногдаСтоит ли добавлять паттерн доступа к данным Repository поверх Entity Framework Core?
Стоит ли добавлять паттерн доступа к данным Repository поверх Entity Framework Core?
Обычно нет: DbSet<T> уже репозиторий, а DbContext — уже Unit of Work, поэтому обёртка-переходник лишь прячет IQueryable. Он оправдан, когда нужно скрыть технологию хранения или ограничить запросы вызывающего кода.
Типичные ошибки
- ✗Оборачивать
DbSet<T>в репозиторий-переходник, который не даёт ни ограничений, ни абстракции - ✗Возвращать
IQueryableиз репозитория, выпуская наружу ту самую технологию, которую он должен скрыть - ✗Считать, что у Entity Framework Core нет собственного Unit of Work
Уточняющие вопросы
- →Что именно выдаёт вызывающему коду
IQueryable, возвращённый из репозитория? - →Как тестировать сервис, который зависит напрямую от
DbContext?