Продвинутый

Когда какой подход применять

Урок 6 из 6 в курсе Архитектурные паттерны и подходы к проектированию

Содержание курса (6/6)

Когда какой подход применять

SOLID, паттерны, чистая архитектура, DDD, TDD — как выбрать правильный инструмент для конкретного проекта. Decision framework: от простого CRUD до сложного домена.

Почему это важно: Overengineering так же вреден, как и отсутствие архитектуры. DDD для простого блога — потеря времени. Голый ActiveRecord для банковской системы — катастрофа. Нужен фреймворк для принятия решений.

Главная идея

Сложность проекта определяет нужный уровень архитектуры. Простой CRUD → фреймворковые конвенции. Средняя сложность → SOLID + паттерны + Service Objects. Сложный домен → Clean Architecture + DDD. TDD применяется к любому уровню для критичной логики.

Как это выглядит на практике

  1. Новый проект: оценка — это CRUD-приложение или сложный домен?
  2. CRUD (блог, каталог): фреймворк (Rails, Django) + тесты на модели и контроллеры
  3. Средний (e-commerce, SaaS): Service Objects + SOLID + Repository для тяжёлых запросов
  4. Сложный (финтех, логистика, медицина): Clean Architecture + DDD + TDD для домена
  5. Ключевой вопрос: если убрать фреймворк, останется ли бизнес-логика отдельно?
  6. Если да — архитектура правильная. Если нет — логика вплетена в инфраструктуру

Примеры кода

Уровень 1: простой CRUD — фреймворк достаточен

# Для блога, каталога, лендинга — Rails Way
# Не нужно: Service Objects, Repository, DDD

class ArticlesController < ApplicationController
  def create
    @article = Article.new(article_params)
    if @article.save
      redirect_to @article, notice: 'Статья создана'
    else
      render :new, status: :unprocessable_entity
    end
  end

  private

  def article_params
    params.require(:article).permit(:title, :body, :published)
  end
end

# Модель с валидациями — достаточно
class Article < ApplicationRecord
  validates :title, presence: true, length: { maximum: 200 }
  validates :body, presence: true
  scope :published, -> { where(published: true) }
end

# Тест — простой и прямой
RSpec.describe Article do
  it 'validates title presence' do
    article = Article.new(title: nil)
    expect(article).not_to be_valid
  end
end

Уровень 2: средняя сложность — Service Objects

# E-commerce, SaaS — бизнес-логика сложнее CRUD
# Service Objects + SOLID, без полного DDD

# app/services/checkout_service.rb
class CheckoutService
  def initialize(
    payment: StripePayment.new,
    inventory: InventoryService.new,
    mailer: OrderMailer
  )
    @payment = payment
    @inventory = inventory
    @mailer = mailer
  end

  def call(cart:, user:)
    order = Order.create!(user: user, items: cart.items, total: cart.total)

    @payment.charge(order.total, user.payment_method)
    @inventory.reserve(order.items)
    @mailer.confirmation(order).deliver_later

    order
  rescue PaymentFailed => e
    order&.update!(status: :payment_failed)
    raise
  end
end

# Контроллер тонкий
class OrdersController < ApplicationController
  def create
    order = CheckoutService.new.call(
      cart: current_cart,
      user: current_user
    )
    render json: order, status: :created
  end
end

Decision framework: какой подход выбрать

# Задайте себе эти вопросы:

# 1. Сколько бизнес-правил?
#    0-5 правил   → Rails Way (CRUD)
#    5-20 правил  → Service Objects + SOLID
#    20+ правил   → Clean Architecture + DDD

# 2. Сколько разработчиков?
#    1-2 человека → проще = лучше
#    3-5 человек  → Service Objects + конвенции
#    5+ человек   → Bounded Contexts + чёткие интерфейсы

# 3. Как часто меняются требования?
#    Редко     → Rails Way достаточен
#    Регулярно → SOLID + паттерны для гибкости
#    Постоянно → DDD + TDD для безопасного рефакторинга

# 4. Есть ли доменные эксперты (бизнес-аналитики)?
#    Нет  → Service Objects + здравый смысл
#    Да   → DDD: Ubiquitous Language + Event Storming

# 5. Критичность ошибок?
#    Низкая (блог)   → тесты после, Rails Way
#    Средняя (магазин) → TDD для платежей и корзины
#    Высокая (финтех) → TDD для всего домена + integration tests

# Золотое правило: начните просто, усложняйте при боли.

Что происходит под капотом

  • Overengineering = архитектура сложнее проблемы. DDD для блога — overengineering
  • Underengineering = отсутствие архитектуры при сложном домене. 2000-строчный god-object = underengineering
  • Рефакторинг дешевле, чем преждевременная архитектура: начните просто, усложняйте при появлении боли
  • Признаки того, что пора усложнять: тесты ломаются при несвязанных изменениях, классы > 300 строк, новые фичи = правки в 10+ файлах
  • Стратегический DDD (Bounded Contexts) можно применять без тактического (Aggregates, Value Objects)

Типичные ошибки и заблуждения

  • «Хорошая архитектура нужна с первого дня» — нет, хороший код нужен с первого дня, архитектура эволюционирует с проектом
  • «Микросервисы = хорошая архитектура» — микросервисы без DDD Bounded Contexts = распределённый монолит, который ещё сложнее
  • «TDD замедляет стартап» — TDD для критичной логики (платежи, авторизация) ускоряет стартап, потому что предотвращает дорогие баги

Ключевые выводы

  • Сложность проекта определяет уровень архитектуры: CRUD → Service Objects → Clean + DDD
  • Начинайте просто, усложняйте при боли: тесты ломаются, классы разрастаются, фичи дорожают
  • TDD — не уровень архитектуры, а дисциплина: применяйте к критичной бизнес-логике на любом уровне

Термины урока

{:term=>"Overengineering", :definition=>"Архитектура, сложность которой превышает сложность решаемой проблемы"}
{:term=>"Evolutionary architecture", :definition=>"Подход, при котором архитектура развивается вместе с проектом, а не определяется заранее на 3 года"}
{:term=>"Decision framework", :definition=>"Набор вопросов/критериев для выбора архитектурного подхода в конкретной ситуации"}

Связь с работой backend-разработчика

Архитектура — инструмент, а не самоцель. Правильная архитектура — та, при которой стоимость изменений минимальна для текущего и ожидаемого уровня сложности. Начните просто, мониторьте боль, усложняйте точечно.

Мини-разбор реальной ситуации

Стартап начал с DDD и чистой архитектурой для MVP интернет-магазина. 3 месяца ушло на инфраструктуру вместо фич. Конкурент запустился на Rails Way за 3 недели и захватил рынок. Урок: для MVP достаточно Service Objects, DDD добавляется при масштабировании, когда домен действительно усложняется.

Что запомнить

  • Простой CRUD → Rails Way. Средний → Service Objects + SOLID. Сложный домен → DDD + Clean Architecture
  • Начните просто, усложняйте при боли. Рефакторинг дешевле преждевременной архитектуры
  • TDD для критичной бизнес-логики на любом уровне сложности

Итог

Нет универсально правильной архитектуры — есть подходящая для вашего проекта. Decision framework: оцените сложность домена, размер команды, частоту изменений и критичность ошибок. Начните просто, усложняйте при реальной боли.

Комментарии к уроку

Войдите, чтобы оставить комментарий.

Пока нет комментариев — будьте первым.