Что такое чистая архитектура?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое Чистая Архитектура (Clean Architecture)?
Чистая Архитектура — это концепция организации кода, предложенная Робертом Мартином (Uncle Bob), которая направлена на создание гибких, поддерживаемых и независимых от фреймворков, UI и баз данных программных систем. Её основная цель — разделение ответственности (Separation of Concerns) и соблюдение правила зависимости (Dependency Rule): зависимости в коде должны быть направлены внутрь, к ядру системы, а внешние детали (как база данных или веб-интерфейс) зависят от внутренних бизнес-правил, а не наоборот.
Ключевые принципы и слои
Чистая архитектура организует код в концентрические слои (или круги), где каждый внешний слой зависит от внутреннего, но не наоборот. Вот основные слои, от внутренних к внешним:
1. Сущности (Entities)
Это ядро системы, содержащее бизнес-правила и ключевые объекты предметной области (например, User, Order, Product). Они не зависят ни от чего внешнего — ни от баз данных, ни от фреймворков, ни даже от вариантов использования.
// Пример сущности в Go
package entity
type User struct {
ID string
Email string
FirstName string
LastName string
}
func (u *User) ValidateEmail() error {
// Бизнес-правило валидации email
if !strings.Contains(u.Email, "@") {
return errors.New("invalid email format")
}
return nil
}
2. Сценарии использования (Use Cases)
Содержат бизнес-логику приложения, реализующую конкретные сценарии (например, "создание заказа", "аутентификация пользователя"). Они зависят только от сущностей, но не от внешних деталей.
// Пример use case в Go
package usecase
import "project/entity"
type UserRepository interface {
Save(user *entity.User) error
FindByEmail(email string) (*entity.User, error)
}
type CreateUserUseCase struct {
repo UserRepository
}
func (uc *CreateUserUseCase) Execute(email, firstName, lastName string) error {
user := &entity.User{
Email: email,
FirstName: firstName,
LastName: lastName,
}
if err := user.ValidateEmail(); err != nil {
return err
}
return uc.repo.Save(user)
}
3. Интерфейсы адаптеров (Interface Adapters)
Преобразуют данные между форматами, удобными для use cases и внешними системами. Сюда входят:
- Контроллеры (обработчики HTTP-запросов)
- Гейтвеи/репозитории (интерфейсы для работы с данными)
- Презентеры (подготовка данных для отображения)
// Пример контроллера и репозитория в Go
package handler
import "project/usecase"
type UserHandler struct {
createUserUseCase *usecase.CreateUserUseCase
}
func (h *UserHandler) CreateUser(c *fiber.Ctx) error {
var request struct {
Email string `json:"email"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
}
if err := c.BodyParser(&request); err != nil {
return c.Status(400).JSON(map[string]string{"error": "invalid request"})
}
err := h.createUserUseCase.Execute(request.Email, request.FirstName, request.LastName)
if err != nil {
return c.Status(500).JSON(map[string]string{"error": err.Error()})
}
return c.Status(201).JSON(map[string]string{"status": "user created"})
}
4. Фреймворки и драйверы (Frameworks & Drivers)
Внешний слой, содержащий конкретные реализации: базы данных (PostgreSQL, MongoDB), веб-фреймворки (Fiber, Gin), внешние API и т.д.
// Пример реализации репозитория для PostgreSQL
package postgres
import (
"project/entity"
"gorm.io/gorm"
)
type UserRepository struct {
db *gorm.DB
}
func (r *UserRepository) Save(user *entity.User) error {
return r.db.Create(user).Error
}
func (r *UserRepository) FindByEmail(email string) (*entity.User, error) {
var user entity.User
err := r.db.Where("email = ?", email).First(&user).Error
return &user, err
}
Преимущества Чистой Архитектуры в Go
- Тестируемость: Бизнес-логику можно тестировать изолированно, без зависимости от внешних систем.
- Независимость от фреймворков: Миграция с одного фреймворка на другой затрагивает только внешний слой.
- Гибкость и поддерживаемость: Изменения в одном слое минимально затрагивают другие.
- Чёткая структура проекта: Каждый компонент имеет строго определённую ответственность.
- Отсроченные решения: Можно отложить выбор конкретных технологий (БД, фреймворков).
Практическое применение в Go-проектах
В экосистеме Go Чистая Архитектура часто реализуется через:
- Интерфейсы для определения контрактов между слоями
- Внедрение зависимостей (Dependency Injection) для связывания слоев
- Структуру папок, отражающую слои архитектуры:
project/
├── cmd/ # Точки входа
├── internal/ # Внутренние пакеты
│ ├── entity/ # Сущности
│ ├── usecase/ # Сценарии использования
│ ├── repository/ # Интерфейсы репозиториев
│ └── handler/ # HTTP-обработчики
├── pkg/ # Переиспользуемые пакеты
└── infrastructure/ # Конкретные реализации (PostgreSQL, Redis и т.д.)
Чистая архитектура особенно полезна в средних и крупных Go-проектах, где важны долгосрочная поддерживаемость и возможность эволюции системы без полного переписывания. Она требует большего количества кода и абстракций на начальном этапе, но окупается при долгосрочной разработке и поддержке проекта.