Что такое Onion архитектура?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое Onion (Луковая) архитектура?
Onion архитектура (или "луковая" архитектура) — это шаблон проектирования, основанный на принципах чистой архитектуры (Clean Architecture) и инверсии зависимостей (Dependency Inversion Principle, DIP). Основная идея заключается в организации кода в виде концентрических слоёв, подобных слоям лука, где зависимости направлены строго внутрь, к центру системы. Внешние слои зависят от внутренних, но не наоборот, что обеспечивает низкую связанность (low coupling) и высокую тестируемость.
Основные принципы и слои
1. Домен (Domain) — ядро системы
Это центральный слой, абсолютно независимый от внешних факторов. Он содержит:
- Сущности (Entities): базовые бизнес-объекты (например,
User,Order). - Интерфейсы репозиториев (Repository Interfaces): определяют контракты для работы с данными.
- Бизнес-правила и логику — то, ради чего существует система.
// Пример сущности в доменном слое
package domain
type User struct {
ID int
Name string
Email string
}
// Интерфейс репозитория в доменном слое
type UserRepository interface {
FindByID(id int) (*User, error)
Save(user *User) error
}
2. Слой приложения (Application)
Содержит сценарии использования (Use Cases), которые координируют поток данных между доменом и внешними слоями. Здесь реализуется конкретная бизнес-логика.
// Пример use case в слое приложения
package application
import "myapp/domain"
type UserService struct {
repo domain.UserRepository
}
func (s *UserService) GetUser(id int) (*domain.User, error) {
// Бизнес-логика (например, валидация) может быть здесь
return s.repo.FindByID(id)
}
3. Инфраструктурный слой (Infrastructure)
Внешний слой, который реализует интерфейсы, определённые во внутренних слоях. Включает:
- Реализации репозиториев (работа с БД, файлами, API).
- Внешние сервисы (например, отправка email, кеширование).
- Фреймворки и драйверы (HTTP-серверы, ORM).
// Реализация репозитория в инфраструктурном слое
package infrastructure
import "myapp/domain"
type PostgreSQLUserRepository struct {
// подключение к БД
}
func (r *PostgreSQLUserRepository) FindByID(id int) (*domain.User, error) {
// Реализация запроса к PostgreSQL
// ...
}
4. Слой представления (Presentation/API)
Обрабатывает ввод/вывод (например, HTTP-запросы, CLI-команды). Зависит от слоя приложения, но не напрямую от инфраструктуры.
// Пример HTTP-обработчика
package presentation
import "myapp/application"
type UserHandler struct {
userService *application.UserService
}
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
// Парсинг запроса, вызов use case, формирование ответа
// ...
}
Ключевые преимущества
- Независимость бизнес-логики: Домен и use cases не зависят от базы данных, фреймворков или UI.
- Тестируемость: Бизнес-логику можно тестировать изолированно с помощью моков.
- Гибкость: Замена внешних компонентов (например, СУБД или веб-фреймворка) не затрагивает ядро.
- Поддержка DIP: Зависимости направлены к абстракциям (интерфейсам в домене), а не к реализациям.
Пример зависимости в Go с использованием инъекции
// Сборка компонентов (обычно в main или wire)
func main() {
// 1. Создаём инфраструктурную зависимость
repo := &infrastructure.PostgreSQLUserRepository{}
// 2. Внедряем её в use case (удовлетворяя интерфейс домена)
userService := &application.UserService{Repo: repo}
// 3. Передаём use case в обработчик
handler := &presentation.UserHandler{UserService: userService}
// Запуск приложения
http.ListenAndServe(":8080", handler)
}
Отличие от других архитектур
- От MVC: В MVC нет чёткого разделения на слои с направленностью зависимостей — модель часто знает о базе данных.
- От Гексагональной (Hexagonal): Очень похожи, но Onion делает больший акцент на концентрических слоях и домене как абсолютном центре.
Когда использовать?
Onion архитектура особенно полезна для:
- Сложных бизнес-приложений с часто меняющимися требованиями.
- Долгосрочных проектов, где важна поддерживаемость.
- Систем, где бизнес-логика является ключевой ценностью.
Заключение
Onion архитектура в Go способствует созданию чистого, тестируемого и гибкого кода, отделяя "что делает система" (домен) от "как она это делает" (инфраструктура). Хотя она добавляет некоторую сложность (больше интерфейсов и слоёв), выгоды в долгосрочной поддержке и адаптивности к изменениям обычно перевешивают первоначальные затраты. В Go её особенно удобно реализовывать благодаря неявным интерфейсам, которые естественным образом поддерживают инверсию зависимостей.