Сущности и сценарии не знают HTTP и SQL: зависимости направлены к центру. В Go интерфейс объявляет потребитель на границе, а не «у каждой структуры пакет с моком».
Проектирование сервисов architecture собеседование
Чистая архитектура, гексагональная, ports and adapters — один рисунок разными словами. В центре домен и сценарии. Снаружи адаптеры: HTTP, Postgres, Kafka, CLI.
Правило зависимостей: внутренние пакеты не импортируют фреймворки и драйверы. В Go это видно по графу import.
Зачем это бэкенду: сценарий «оформить заказ» тестируется без Docker и без gin. Хендлер остаётся тонким: разобрать запрос, вызвать use case, перевести ошибку в статус.
Пример. Смену БД или брокера не размазывают по двенадцати хендлерам. Меняете адаптер. Сценарий PlaceOrder остаётся тем же.
Правило зависимостей
Use case зависит от порта «сохранить заказ», не от *sql.DB. Реализация порта живёт в adapter и импортирует домен, а не наоборот.
HTTP-хендлер не содержит SQL и не знает про колонки. Миграции и драйвер — детали инфраструктуры.
Тест сценария подставляет фейковый порт в памяти. Тест адаптера бьёт в Postgres и не дублирует всю бизнес-логику. Путать эти два уровня — источник медленных «юнитов», которые поднимают Docker.
Как это выглядит в Go
Интерфейс объявляет потребитель. Пакет use case, рядом со структурой сценария. Пакет postgres реализует его неявно.
Не тащите большой интерфейс «весь склад» в домен, если сценарию нужны два метода. Один адаптер навсегда без теста — лишний слой.
package order
import "context"
type Repository interface {
Save(ctx context.Context, o Order) error
ByID(ctx context.Context, id ID) (Order, error)
}
type Place struct{ Repo Repository }
func (p Place) Do(ctx context.Context, o Order) error {
if err := o.Validate(); err != nil {
return err
}
return p.Repo.Save(ctx, o)
}
Порт объявлен у сценария. Адаптер реализует его снаружи и не протекает в домен.
Толстый хендлер
SQL внутри HTTP-хендлера смешивает транспорт с правилами домена. Протестировать «нельзя оформить пустой заказ» без сервера и без БД уже нельзя. gRPC-хендлер с той же болезнью не лучше: транспорт всё равно не место для инварианта.
Типичная ошибка
Объявить интерфейс в пакете postgres на 50 методов заранее и заставить домен импортировать инфраструктуру. Это инверсия правила зависимостей. Вторая крайность — абстракция ради абстракции: один адаптер, ноль тестов, три слоя DTO на каждый запрос.
На собеседовании
Зависимости к центру. Интерфейс живёт у потребителя. Хендлер тонкий. Сценарий тестируется фейковым портом. SQL остаётся в адаптере. Hexagonal и ports-and-adapters — тот же рисунок.