Ответ
Слоистая архитектура (Layered Architecture) — это подход к проектированию ПО, при котором приложение разделяется на горизонтальные уровни (слои), каждый из которых имеет свою четко определенную зону ответственности.
Основное правило: вышележащий слой может обращаться только к нижележащему. Это создает однонаправленный поток зависимостей и уменьшает связанность компонентов.
Типичные слои в Go веб-сервисе:
Слой представления (Presentation/Transport Layer)
- Ответственность: Прием HTTP-запросов, парсинг данных (JSON, query-параметры), валидация и передача данных на следующий слой. В Go это обычно пакет
http
или фреймворки (Gin, Echo). - Пример:
handler
,controller
.
- Ответственность: Прием HTTP-запросов, парсинг данных (JSON, query-параметры), валидация и передача данных на следующий слой. В Go это обычно пакет
Слой бизнес-логики (Business Logic/Service Layer)
- Ответственность: Реализация основной логики приложения. Координирует работу с данными, выполняет вычисления, применяет бизнес-правила. Не зависит от способа доставки (HTTP, gRPC) и хранения данных (PostgreSQL, Redis).
- Пример:
service
,usecase
.
Слой доступа к данным (Data Access/Repository Layer)
- Ответственность: Взаимодействие с хранилищами данных (БД, кэш, внешние API). Абстрагирует детали работы с конкретной базой данных.
- Пример:
repository
,storage
,dao
.
Пример потока в Go:
// 1. Presentation Layer (handler)
func (h *UserHandler) GetUser(c *gin.Context) {
userID := c.Param("id")
// Вызов слоя бизнес-логики
user, err := h.userService.GetByID(c.Request.Context(), userID)
if err != nil {
// ... обработка ошибки
return
}
c.JSON(http.StatusOK, user)
}
// 2. Business Logic Layer (service)
func (s *UserService) GetByID(ctx context.Context, id string) (*User, error) {
// Вызов слоя доступа к данным
return s.userRepo.FindByID(ctx, id)
}
// 3. Data Access Layer (repository)
func (r *UserRepo) FindByID(ctx context.Context, id string) (*User, error) {
// Выполнение SQL-запроса к базе данных
// ... db.QueryRowContext(ctx, "SELECT ...")
return &User{}, nil
}
Преимущества:
- Низкая связанность (Low Coupling): Изменение в одном слое (например, замена PostgreSQL на MongoDB) минимально затрагивает другие слои.
- Тестируемость: Каждый слой можно тестировать изолированно, подменяя его зависимости моками (например, тестировать сервис с моком репозитория).
- Повторное использование: Логику из слоя сервисов можно использовать в разных обработчиках (HTTP, gRPC, CLI).
- Понятная структура: Проект легко читать и поддерживать, так как у каждого компонента есть свое место и роль.