Ответ
Модель C4 (C4 Model) — это иерархический подход к визуализации архитектуры программного обеспечения, созданный Саймоном Брауном. Он позволяет описывать систему на разных уровнях детализации, делая архитектуру понятной для разной аудитории (от менеджеров до разработчиков).
Модель состоит из 4 уровней диаграмм:
-
Уровень 1: Контекст (System Context)
- Что показывает: Систему как «чёрный ящик», её пользователей (акторов) и внешние системы, с которыми она взаимодействует.
- Аудитория: Все (бизнес, менеджмент, разработчики).
-
Уровень 2: Контейнеры (Containers)
- Что показывает: Основные строительные блоки системы: веб-приложения, мобильные приложения, базы данных, файловые системы, микросервисы.
- Важно: «Контейнер» здесь — это не Docker-контейнер, а развертываемая единица (deployable unit).
- Аудитория: Разработчики, архитекторы, DevOps-инженеры.
-
Уровень 3: Компоненты (Components)
- Что показывает: Основные модули или компоненты, из которых состоит отдельный контейнер. Например, в Go-приложении это могут быть
UserController,AuthService,PaymentGatewayClient. - Аудитория: Разработчики, архитекторы.
- Что показывает: Основные модули или компоненты, из которых состоит отдельный контейнер. Например, в Go-приложении это могут быть
-
Уровень 4: Код (Code)
- Что показывает: Детали реализации конкретного компонента (диаграммы классов, схемы баз данных). Этот уровень часто не визуализируют, а ссылаются прямо на исходный код.
Пример для Go-бэкенда:
Представим, что мы детализируем архитектуру:
- Контейнер:
API Server(веб-сервис на Go). - Компонент:
UserService(отвечает за бизнес-логику пользователей). - Код: Реализация компонента
UserService.
// Уровень 4 (Код) — реализация компонента "UserService"
// UserRepository - это интерфейс, который является частью другого компонента (например, "PersistenceComponent")
type UserRepository interface {
FindByID(id string) (*User, error)
}
type UserService struct {
repo UserRepository
}
func (s *UserService) GetUser(id string) (*User, error) {
// Бизнес-логика и вызов другого компонента
return s.repo.FindByID(id)
}
Главное преимущество C4 — это создание общего языка для обсуждения архитектуры и возможность рассматривать систему с нужным уровнем абстракции.
Ответ 18+ 🔞
Давай разберём эту вашу C4 Model, а то как слышу «архитектура» — сразу представляю себе бородатого дядьку в свитере, который рисует квадратики и стрелочки, пока все остальные реально кодят. Но эта штука, блядь, оказалась не такой уж и бесполезной!
Представь, что ты объясняешь, как устроен твой дом. Ты же не начнёшь с того, из какого конкретно сплава сделана защёлка на двери в сортире? Нет, сука. Ты скажешь: «Вот дом, в нём живём мы, а вот почтальон приносит письма». Это и есть первый уровень — Контекст. Просто чёрный ящик и кто к нему лезет.
Потом, если собеседнику не похуй, ты уточнишь: «А внутри дома есть кухня, ванная и серверная стойка в чулане». Это второй уровень — Контейнеры. И да, «контейнер» — это не про докер, ёпта! Это про то, что можно воткнуть/выключить как отдельную штуку: веб-сервак, базу данных, тот же твой Go-бэкенд.
Дальше уже для своих: «На кухне стоит холодильник, плита и кофе-машина, которая без кофеина не работает». Это третий уровень — Компоненты. То есть из каких основных модулей состоит твой Go-сервис: UserController, AuthService и прочая пиздопроебибна.
Ну а четвёртый уровень — Код — это когда ты лезешь внутрь кофе-машины и смотришь, как там шестерёнки цепляются. То есть прям исходники. Часто его даже не рисуют, а просто тыкают пальцем в репозиторий.
Вот смотри, как это для нашего Go-приложения выглядит:
Мы на уровне контейнеров решили, что у нас есть API Server. Хорошо.
Залезаем в него — видим компонент UserService. Отлично.
А вот и его кишки, уровень кода:
// Это уже четвёртый уровень, детка. Смотри, как оно внутри.
// UserRepository — это интерфейс, он из другого компонента, "PersistenceComponent"
type UserRepository interface {
FindByID(id string) (*User, error)
}
type UserService struct {
repo UserRepository // держим за зависимость, как полагается
}
func (s *UserService) GetUser(id string) (*User, error) {
// Ну тут наша бизнес-логика, вся соль
// И вызов другого компонента через интерфейс — красота, блядь!
return s.repo.FindByID(id)
}
И вся фишка C4 в чём? В том, что ты можешь объяснить систему и менеджеру, который думает, что Go — это настольная игра, и сеньору, который уже готов спорить про внедрение зависимостей. Каждый получает ровно ту детализацию, которая ему нужна, без лишней хуйни. Никаких мартышлюшек с диаграммами на 100500 страниц, где всё связано со всем. Чистая иерархия, как у нормальных людей. В рот меня чих-пых, а ведь работает!