Глава 5. Навык #2: Архитектурное мышление
"AI может написать функцию за секунды. Но спроектировать всю систему — ваша задача."
5.1. AI пишет код, вы — архитектор
Новая роль программиста
Представьте стройку небоскрёба:
Рабочие — кладут кирпичи, варят сваи, красят стены. Архитектор — проектирует здание, решает, где что будет, как всё соединится.
С AI:
- AI — это рабочие (пишут код)
- Вы — архитектор (проектируете систему)
Что может AI
AI отлично справляется с:
- ✅ Написать функцию по описанию
- ✅ Создать CRUD API
- ✅ Настроить базу данных
- ✅ Написать тесты
- ✅ Исправить баг
Что НЕ может AI (пока)
AI плохо справляется с:
- ❌ Спроектировать архитектуру всей системы
- ❌ Понять бизнес-контекст и долгосрочные цели
- ❌ Предвидеть, как система будет масштабироваться
- ❌ Решить, какие компромиссы приемлемы
- ❌ Увидеть "большую картину"
Это ваша зона ответственности.
Пример
Плохо (без архитектурного мышления):
Вы: "AI, создай систему для онлайн-магазина"
AI: [генерирует монолитное приложение со всем в одном файле]
Через месяц:
- Код превратился в спагетти
- Невозможно добавить новую функцию без багов
- Тормозит при 100+ пользователях
- Невозможно разделить работу в команде
Хорошо (с архитектурным мышлением):
Вы: "AI, создай систему для онлайн-магазина.
Используй следующую архитектуру:
- Frontend: React
- Backend API: Node.js/Express
- База данных: PostgreSQL
- Разбей на модули: users, products, orders, payments
- Каждый модуль — отдельный сервис (микросервисы)
- Используй REST API для коммуникации"
AI: [генерирует структурированную систему]
Через месяц:
- Чистая архитектура
- Легко добавлять функции
- Каждый сервис масштабируется независимо
- Команда может работать параллельно над разными модулями
Разница: Вы спроектировали систему, AI реализовал.
5.2. Как разбить большую задачу на модули
Принцип: Divide and Conquer
Большую задачу невозможно решить за один раз.
Нужно разбить на части:
- Выделить модули (независимые части системы)
- Определить ответственность каждого модуля
- Определить интерфейсы между модулями
Пример: Система для блога
Большая задача: "Создать платформу для блогов, где пользователи могут писать статьи, комментировать, подписываться друг на друга"
Без разбиения (монолит):
blog_system.py (3000 строк кода — всё в одном файле)
С разбиением (модули):
users/ # Модуль пользователей
- models.py # User модель
- auth.py # Аутентификация
- profile.py # Профили
articles/ # Модуль статей
- models.py # Article модель
- crud.py # Создание, редактирование, удаление
- search.py # Поиск статей
comments/ # Модуль комментариев
- models.py # Comment модель
- moderation.py# Модерация
subscriptions/ # Модуль подписок
- models.py # Subscription модель
- feed.py # Лента подписок
Как определить модули
Задайте вопросы:
-
Какие основные сущности (entities) в системе?
- Пользователи (Users)
- Статьи (Articles)
- Комментарии (Comments)
- Подписки (Subscriptions)
-
Какие операции выполняются над каждой сущностью?
- Users: регистрация, логин, профиль
- Articles: создание, редактирование, удаление, поиск
- Comments: добавление, удаление, модерация
- Subscriptions: подписка, отписка, лента
-
Можно ли эти операции выделить в отдельный модуль?
- Да! Каждая сущность → отдельный модуль
С AI
Промпт:
Проанализируй требования к платформе блогов:
- Пользователи могут писать статьи
- Комментировать статьи
- Подписываться друг на друга
- Видеть ленту подписок
Предложи модульную архитектуру.
Опиши каждый модуль и его ответственность.
AI даст вам предложение.
Ваша задача: Проверить, осмыслить, скорректировать.
5.3. Separation of Concerns
Принцип: Каждый модуль — одна ответственность
Separation of Concerns (Разделение ответственности):
Каждая часть системы должна заниматься одной вещью и делать её хорошо.
Плохой пример
def create_article(title, content, user_id):
# Проверка пользователя
user = db.query("SELECT * FROM users WHERE id = ?", user_id)
if not user:
return "User not found"
# Проверка прав
if not user['is_active']:
return "User not active"
# Создание статьи
article_id = db.insert("INSERT INTO articles ...")
# Отправка email
send_email(user['email'], "Article created!")
# Логирование
log("Article created: " + article_id)
# Обновление статистики
update_stats(user_id)
return article_id
Проблемы:
- Функция делает слишком много (проверка пользователя, создание статьи, email, лог, статистика)
- Сложно тестировать
- Сложно изменить (изменение email затронет всю функцию)
Хороший пример
# users/auth.py
def get_active_user(user_id):
"""Получить активного пользователя"""
user = db.query("SELECT * FROM users WHERE id = ?", user_id)
if not user or not user['is_active']:
return None
return user
# articles/crud.py
def create_article(title, content, author_id):
"""Создать статью"""
article_id = db.insert(
"INSERT INTO articles (title, content, author_id) VALUES (?, ?, ?)",
title, content, author_id
)
return article_id
# notifications/email.py
def notify_article_created(user_email, article_id):
"""Уведомить о создании статьи"""
send_email(user_email, f"Article {article_id} created!")
# analytics/stats.py
def update_user_stats(user_id):
"""Обновить статистику пользователя"""
# ...
# Главная функция (orchestrator)
def publish_article(title, content, user_id):
# Проверка пользователя
user = get_active_user(user_id)
if not user:
return {"error": "User not found or inactive"}
# Создание статьи
article_id = create_article(title, content, user_id)
# Побочные эффекты (асинхронно)
notify_article_created(user['email'], article_id)
update_user_stats(user_id)
log_event("article_created", article_id)
return {"article_id": article_id}
Преимущества:
- Каждая функция делает одну вещь
- Легко тестировать каждую функцию отдельно
- Легко изменить (изменение email не затронет создание статьи)
- Можно переиспользовать функции
С AI
Плохо:
AI, создай функцию для публикации статьи
Хорошо:
AI, создай следующие функции:
1. get_active_user(user_id) - проверить пользователя
2. create_article(title, content, author_id) - создать статью в БД
3. notify_article_created(user_email, article_id) - отправить email
4. publish_article(title, content, user_id) - главная функция, которая оркестрирует всё
Каждая функция должна иметь одну ответственность.
AI сгенерирует чистую архитектуру.
5.4. Слоистая архитектура
Принцип: Разделить систему на слои
Слоистая архитектура (Layered Architecture):
Система разделена на горизонтальные слои, каждый слой общается только с соседними.
Типичные слои
┌─────────────────────────┐
│ Presentation Layer │ ← UI, API endpoints
├─────────────────────────┤
│ Business Logic Layer │ ← Бизнес-логика, правила
├─────────────────────────┤
│ Data Access Layer │ ← Работа с БД
├─────────────────────────┤
│ Database │ ← Хранилище данных
└─────────────────────────┘
Правило: Каждый слой общается только с непосредственно соседним.
Пример
Слой 1: Presentation (API)
# api/articles.py
@app.post("/articles")
def create_article_endpoint(request):
"""API endpoint для создания статьи"""
data = request.json
# Валидация входных данных
if not data.get('title') or not data.get('content'):
return {"error": "Missing fields"}, 400
# Вызов бизнес-логики
result = article_service.create_article(
title=data['title'],
content=data['content'],
user_id=request.user_id
)
return {"article_id": result}, 201
Слой 2: Business Logic (Сервис)
# services/article_service.py
def create_article(title, content, user_id):
"""Бизнес-логика создания статьи"""
# Проверка прав пользователя
user = user_repository.get_by_id(user_id)
if not user or not user.is_active:
raise PermissionError("User not active")
# Проверка лимитов
if user.article_count >= user.max_articles:
raise LimitError("Article limit reached")
# Создание статьи через Data Access Layer
article = article_repository.create(
title=title,
content=content,
author_id=user_id
)
# Обновление счётчика
user_repository.increment_article_count(user_id)
return article.id
Слой 3: Data Access (Repository)
# repositories/article_repository.py
def create(title, content, author_id):
"""Создать статью в БД"""
query = """
INSERT INTO articles (title, content, author_id, created_at)
VALUES (?, ?, ?, NOW())
RETURNING id
"""
result = db.execute(query, title, content, author_id)
return result
Преимущества слоистой архитектуры
✅ Разделение ответственности: Каждый слой делает своё ✅ Тестируемость: Можно тестировать каждый слой отдельно ✅ Замена компонентов: Можно заменить БД без изменения бизнес-логики ✅ Читаемость: Ясная структура
С AI
Промпт:
Создай слоистую архитектуру для модуля статей:
1. API layer (endpoints)
2. Service layer (бизнес-логика)
3. Repository layer (работа с БД)
Каждый слой в отдельном файле.
AI создаст чистую структуру.
5.5. API Design — как компоненты общаются
Принцип: Чёткие интерфейсы между модулями
API (Application Programming Interface) — это контракт, как один модуль общается с другим.
Типы API
1. Внутренний API (между модулями вашего приложения)
# users/service.py
def get_user(user_id: int) -> User:
"""Получить пользователя по ID"""
pass
# articles/service.py
from users.service import get_user
def create_article(title, content, author_id):
user = get_user(author_id) # Вызов API другого модуля
if not user:
raise ValueError("User not found")
# ...
2. Внешний API (HTTP/REST)
# API endpoints
GET /articles # Список статей
GET /articles/:id # Одна статья
POST /articles # Создать статью
PUT /articles/:id # Обновить статью
DELETE /articles/:id # Удалить статью
Принципы хорошего API
1. Предсказуемость
Плохо:
def create_article(data):
# Что в data? Неясно!
pass
Хорошо:
def create_article(title: str, content: str, author_id: int) -> int:
"""
Создать статью.
Args:
title: Заголовок статьи
content: Содержимое статьи
author_id: ID автора
Returns:
ID созданной статьи
Raises:
ValueError: Если автор не найден
"""
pass
2. Консистентность
Плохо:
# Одни функции возвращают объект, другие ID
create_article() # → возвращает ID
create_user() # → возвращает объект User
Хорошо:
# Все функции возвращают объект
create_article() # → Article
create_user() # → User
3. Минимализм
API должен быть простым:
# Плохо: слишком много параметров
def create_article(title, content, author_id, tags, category,
published, featured, allow_comments, notify_subscribers):
pass
# Хорошо: основные параметры, остальное опционально
def create_article(title: str, content: str, author_id: int, **options):
pass
REST API Design
Принципы REST:
-
Ресурсы — существительные, не глаголы
- ✅
GET /articles - ❌
GET /getArticles
- ✅
-
HTTP методы определяют действие
GET— получитьPOST— создатьPUT/PATCH— обновитьDELETE— удалить
-
Статус-коды информативны
200— OK201— Created400— Bad Request404— Not Found500— Server Error
С AI
Промпт:
Спроектируй REST API для модуля статей.
Включи endpoints для:
- Список статей (с пагинацией)
- Одна статья по ID
- Создание статьи
- Обновление статьи
- Удаление статьи
Используй RESTful принципы.
Опиши каждый endpoint: метод, путь, параметры, ответ.
AI даст вам спроектированный API.
Ваша задача: Проверить консистентность, логичность.
5.6. Масштабируемость
Принцип: Система должна расти с нагрузкой
Масштабируемость — способность системы справляться с ростом:
- Пользователей
- Данных
- Запросов
Два типа масштабирования
1. Вертикальное (Vertical Scaling)
Идея: Купить более мощный сервер.
1 сервер (4 CPU, 8 GB RAM)
↓
1 сервер (16 CPU, 64 GB RAM)
Плюсы:
- Просто
- Не нужно менять код
Минусы:
- Дорого
- Есть предел (нельзя бесконечно улучшать один сервер)
2. Горизонтальное (Horizontal Scaling)
Идея: Добавить больше серверов.
1 сервер
↓
10 серверов (за load balancer)
Плюсы:
- Дешевле (много маленьких серверов)
- Нет предела (можно добавлять бесконечно)
Минусы:
- Сложнее
- Нужна правильная архитектура
Архитектура для масштабирования
Проблема монолита:
[Веб-сервер + Бизнес-логика + БД] (всё в одном процессе)
Если растёт нагрузка на БД, нужно масштабировать всё.
Решение: разделить на сервисы
[Веб-сервер] ← → [API сервер] ← → [БД сервер]
Теперь можно масштабировать каждую часть независимо:
- 10 веб-серверов
- 5 API серверов
- 3 БД реплики
Пример: кэширование
Проблема: База данных тормозит при 1000 запросах/сек.
Решение: добавить кэш (Redis, Memcached)
# Без кэша (медленно)
def get_article(article_id):
return db.query("SELECT * FROM articles WHERE id = ?", article_id)
# С кэшем (быстро)
def get_article(article_id):
# Проверяем кэш
cached = cache.get(f"article:{article_id}")
if cached:
return cached # Возвращаем из кэша (быстро!)
# Запрос к БД
article = db.query("SELECT * FROM articles WHERE id = ?", article_id)
# Сохраняем в кэш на 10 минут
cache.set(f"article:{article_id}", article, ttl=600)
return article
Результат: 90%+ запросов обслуживаются из кэша (в миллисекунды вместо секунд).
С AI
Плохо:
AI, сделай систему быстрее
Хорошо:
AI, добавь кэширование для функции get_article.
Используй Redis.
Кэшируй результаты на 10 минут.
Инвалидируй кэш при обновлении статьи.
5.7. Практика: проектируем архитектуру с AI
Упражнение: TODO-приложение
Задача: Спроектировать архитектуру для TODO-приложения.
Требования:
- Пользователи могут регистрироваться и логиниться
- Создавать задачи (TODO items)
- Отмечать задачи как выполненные
- Фильтровать: все / активные / выполненные
- Каждый пользователь видит только свои задачи
Шаг 1: Определите модули
Подсказка
Модули:
- users — регистрация, аутентификация
- todos — CRUD операции с задачами
Шаг 2: Определите слои
Подсказка
Слои:
- API layer — HTTP endpoints
- Service layer — бизнес-логика
- Repository layer — работа с БД
Шаг 3: Спроектируйте API
Подсказка
POST /auth/register # Регистрация
POST /auth/login # Логин
GET /todos # Список задач (?filter=all|active|completed)
POST /todos # Создать задачу
PUT /todos/:id # Обновить задачу
DELETE /todos/:id # Удалить задачу
PATCH /todos/:id/complete # Отметить как выполненную
Шаг 4: Используйте AI для генерации
Промпт:
Создай архитектуру для TODO-приложения:
Модули:
- users (регистрация, аутентификация)
- todos (CRUD операции)
Слои:
- API layer (Flask/FastAPI)
- Service layer (бизнес-логика)
- Repository layer (SQLAlchemy)
API endpoints:
[вставьте спроектированные endpoints]
Создай структуру файлов и базовый код для каждого слоя.
Шаг 5: Проверьте результат
Проверьте:
- ✅ Каждый модуль имеет одну ответственность?
- ✅ Слои чётко разделены?
- ✅ API консистентен?
- ✅ Можно легко добавить новую функцию (например, теги для задач)?
5.8. Упражнения
Задание 1: Анализ архитектуры
Попросите AI сгенерировать простое приложение (например, блог).
Затем проанализируйте:
- Какие модули выделены?
- Есть ли разделение на слои?
- Как модули общаются друг с другом?
- Можно ли улучшить архитектуру?
Задание 2: Рефакторинг монолита
Попросите AI создать монолитное приложение (всё в одном файле).
Затем:
- Разбейте на модули
- Выделите слои
- Попросите AI помочь с рефакторингом
- Сравните до/после
Задание 3: Проектирование API
Спроектируйте REST API для:
- Системы бронирования отелей
- Магазина электронных книг
- Социальной сети для программистов
Используйте AI для генерации, но сначала спроектируйте сами, потом сравните.
Ключевые выводы главы
✅ Архитектор vs Исполнитель: AI пишет код, вы проектируете систему
✅ Модули: Разбивайте большую задачу на независимые части
✅ Separation of Concerns: Каждый модуль — одна ответственность
✅ Слоистая архитектура: API → Service → Repository → DB
✅ API Design: Чёткие интерфейсы, предсказуемость, консистентность
✅ Масштабируемость: Проектируйте с учётом роста
✅ С AI: Вы проектируете, AI реализует
✅ Проверяйте AI: Архитектура требует человеческого понимания контекста
Следующая глава: Алгоритмическое мышление — понимание сложности и оптимизации