← Назад к вопросам

Почему не выбрал архитектуру?

1.0 Junior🔥 81 комментариев
#Архитектура и паттерны#Опыт и карьера

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Отличный вопрос, который затрагивает саму суть работы старшего разработчика. Мой подход заключается не в том, чтобы «не выбирать архитектуру» — архитектура есть всегда, даже в самом простом скрипте. Вопрос в том, какую именно архитектуру выбрать и когда это делать.

Я не выбираю сложную, многослойную архитектуру по умолчанию для каждого проекта по нескольким ключевым причинам, основанным на принципах YAGNI (You Ain’t Gonna Need It — вам это не понадобится) и KISS (Keep It Simple, Stupid — делай проще).

1. Соответствие архитектуры масштабу и требованиям проекта

Сложная архитектура (например, полноценный гексагональный порт/адаптер, CQRS с Event Sourcing) — это дорогостоящий актив. Она вводит накладные расходы на:

  • Понимание кода новыми членами команды.
  • Количество boilerplate-кода (интерфейсы, DTO, мапперы, обработчики).
  • Время на разработку даже простых изменений.

Пример: Если я делаю внутренний микросервис на Laravel для обработки одного типа запросов из очереди, его архитектура будет кардинально отличаться от публичного API ядра высоконагруженного SaaS-продукта.

Для небольшого сервиса достаточно чистой структуры App/Services, App/DTOs и явного разделения ответственности внутри контроллеров или консольных команд.

// Пример простой, но структурированной архитектуры для ограниченного контекста
namespace App\Services\Payment;

use App\DTOs\PaymentRequest;
use App\Models\Transaction;

class PaymentProcessor
{
    public function __construct(
        private PaymentGateway $gateway,
        private NotificationService $notifier
    ) {}

    public function process(PaymentRequest $request): Transaction
    {
        // Логика валидации, вызова шлюза, создания транзакции
        $result = $this->gateway->charge($request);
        $transaction = Transaction::create($result->toArray());
        $this->notifier->sendSuccess($request->user, $transaction);
        return $transaction;
    }
}
// Контроллер остается тонким
public function pay(PaymentRequest $httpRequest, PaymentProcessor $processor)
{
    $transaction = $processor->process($httpRequest->toDto());
    return new JsonResponse($transaction);
}

2. Эволюционный дизайн и рефакторинг

Я верю в эволюционную архитектуру. Вместо того чтобы пытаться предугадать все будущие требования на день первый (что почти невозможно), я начинаю с простой, но чистой и тестируемой структуры. По мере роста проекта и появления конкретных сложностей (например, необходимость сменить провайдера SMS, добавить кеширование запросов или разделить чтение и запись) я проводлю точечный рефакторинг, внедряя нужные архитектурные паттерны именно там, где они требуются.

  • Появилась сложная бизнес-логика? Выделяем ее в Domain Model или Service Layer.
  • Контроллеры раздулись? Внедряем Action или Form Request объекты.
  • Нужна независимость от фреймворка? Постепенно вводим Ports & Adapters вокруг критических модулей.

Это снижает первоначальные затраты и позволяет архитектуре «вырасти» органически, отвечая реальным, а не гипотетическим потребностям.

3. Производительность команды и стоимость владения

Сложная архитектура требует высокой квалификации всей команды. Если ее необоснованно применить в проекте с junior-разработчиками или высокой текучкой, это приведет к:

  • Ошибкам в реализации паттернов (получается «телега на квадратных колесах»).
  • Страху и непониманию при внесении изменений.
  • Замедлению разработки из-за необходимости постоянно «обслуживать» архитектуру.

Моя цель как старшего разработчика — выбрать такую степень архитектурной сложности, которая максимизирует производительность команды сейчас и дает возможность масштабироваться завтра. Иногда оптимальным решением будет стандартная, хорошо документированная структура фреймворка (MVC в Laravel), дополненная несколькими простыми соглашениями.

4. Конкретный пример: неоправданный CQRS

Одна из самых частых ошибок — это внедрение CQRS и разделения на Command и Query слои там, где нет проблемы с производительностью чтения или сложности предметной области. В 95% CRUD-приложений это избыточно и лишь удваивает количество классов.

// Часто это избыточно для простого чтения
class FindUserQuery {}
class FindUserQueryHandler {}
class UserQueryController {}

// Гораздо проще и понятнее для команды (если нет специфических требований)
class UserController
{
    public function show(int $id)
    {
        $user = User::with('profile')->findOrFail($id);
        return new UserResource($user);
    }
}

Заключение

Я не «не выбираю архитектуру». Я сознательно выбираю минимально достаточную и максимально прагматичную архитектуру для конкретного проекта, его стадии жизненного цикла, состава команды и бизнес-требований. Я стремлюсь к балансу между гибкостью, поддерживаемостью, скоростью разработки и стоимостью владения. Ключевой навык — не в умении реализовать все паттерны из книги, а в способности понять, какие из них принесут пользу именно этому проекту, а какие будут бесполезным усложнением. Архитектура — это средство для достижения бизнес-целей, а не самоцель.