Движок сайта должен быть настолько простым, насколько это возможно

Sep 25, 2026

Движок сайта должен быть настолько простым, насколько это возможно

Много лет хороший движок сайта было принято оценивать по количеству возможностей. Чем больше он умеет из коробки, тем серьёзнее выглядит платформа: роли, права, шаблоны, поля, плагины, события, workflow, мультиязычность, поиск, кэширование, медиа, версии, API и ещё десятки подсистем.

В этом была вполне понятная логика. Добавить отсутствующую возможность потом могло быть дорого. Нужно было найти разработчика, разобраться в чужом проекте, выбрать библиотеку, интегрировать её, протестировать и сопровождать. Поэтому универсальная CMS заранее брала на себя как можно больше потенциальных задач.

Coding agents меняют экономику этого решения.

Не потому, что сложные сайты исчезли. Наоборот, реальный проект может использовать PostgreSQL, reverse proxy, отдельный tile server, очередь, поиск, внешние API и несколько микросервисов. Но теперь всё меньше причин заставлять каждый проект заранее платить сложностью за функции, которые ему, возможно, никогда не понадобятся.

Простое ядро — не простой конечный продукт

Это важное различие.

Максимально простой движок не означает, что сайт должен состоять из пяти файлов и никогда не выходить за их пределы. Речь о другом: сложность должна появляться тогда и там, где возникла задача, которая эту сложность оправдывает.

Нужна раздача картографических тайлов — добавляется специализированный tile server. Появилась нагрузка, при которой полезен HTTP-кэш, — добавляется Varnish. Понадобился полнотекстовый поиск — выбирается подходящий поисковый механизм. Нет этой задачи — нет и соответствующей подсистемы.

У каждого нового компонента должен быть простой ответ на два вопроса:

  1. Что именно мы получаем?
  2. Для чего это нужно этому проекту?

Если вместо ответа приходится объяснять целую платформу из десятков связанных возможностей, возникает подозрение, что вместе с нужной функцией проект получил слишком много чужой архитектуры.

Что показала миграция bizneshelper.ru

Хороший практический пример — недавняя переделка bizneshelper.ru.

5 сентября была заведена основная задача миграции старого Ruby-сайта на новую систему. Legacy-приложение удалось локально запустить и использовать как источник данных и эталон для сверки. Уже на этом этапе стало понятно, что воспроизводить старую архитектуру целиком бессмысленно.

В старом проекте накопилось много специализированных сущностей и таблиц. Похожие по сути виды контента имели разные модели хранения, отдельную логику представления и местами собственный CSS. Исторический WYSIWYG и HTML требовали нормализации. Структура данных была тесно связана со старыми шаблонами.

Вместо переноса этой архитектуры один к одному содержательные сущности начали сводить к универсальной модели Concept. Поля старых кейсов вроде customer, problem, solution, result, review и comment использовались как исходные данные, но не превращались автоматически в шесть обязательных полей новой схемы. Они собирались в содержимое Concept. Исторические URL, когда они действительно были нужны, обслуживались отдельно через redirect rules.

9 сентября этот подход был уже зафиксирован как основная архитектура миграции. 10 сентября в worklog появилась запись: сайт фактически полностью пересобран на новой системе.

Основная техническая переделка заняла примерно 3–4 дня.

И существенная часть этого времени ушла не на создание новой функциональности, а на обход особенностей старой реализации.

Это важный практический результат. Сложность legacy-системы не дала проекту дополнительной ценности во время миграции. Наоборот, её пришлось сначала понять, затем отделить полезные данные от исторических архитектурных решений и только после этого переносить действительно нужное.

Не переносить возможность только потому, что она существует

Во время той же миграции обнаружился показательный пример с авторизацией в форме обратной связи. Интерфейс предлагал вход через Google+, ВКонтакте, Twitter и Facebook. Ни один из этих сценариев уже не работал. Google+ к этому моменту вообще давно перестал существовать как потребительский сервис.

Формально это была «функциональность сайта». Если подходить к миграции как к восстановлению всех возможностей старого движка, её следовало бы воспроизвести.

Но правильный вопрос другой: нужна ли пользователю социальная авторизация для отправки обращения сегодня?

Если нет, переносить соответствующую архитектуру не нужно.

То же произошло со старым поиском на Sunspot/Solr. Вместо восстановления legacy-контура задача была сформулирована заново: нужен поиск по новой унифицированной базе Concepts. Как именно его реализовать — уже отдельное решение текущего проекта.

Это и есть минимализм основания: не отрицание функций, а отказ считать историческое наличие функции доказательством её необходимости.

Раньше расширяемость приходилось проектировать заранее

У традиционного движка была ещё одна проблема. Если авторы хотели дать разработчикам возможность расширять систему, им приходилось заранее строить инфраструктуру расширения:

  • plugin API;
  • hooks и events;
  • систему пакетов;
  • интеграцию расширений с правами доступа;
  • конфигурацию;
  • административный интерфейс;
  • правила совместимости версий.

То есть возможность когда-нибудь добавить неизвестную функцию сама становилась большой функцией ядра.

Coding agent способен работать иначе. Если проект представляет собой понятный исходный код, агент может исследовать существующую архитектуру и добавить функцию непосредственно туда, где она нужна. Для отзывов он создаст модель отзывов, операции API, права, компоненты интерфейса и тесты. Для новой интеграции — адаптер и необходимые точки вызова. Для кэша — соответствующий слой инфраструктуры.

Расширяемость всё меньше зависит от количества заранее предусмотренных extension points и всё больше — от того, насколько проект понятен, проверяем и изменяем.

AI снижает цену отсутствующей абстракции

Это, возможно, главное изменение.

У любой архитектуры есть две цены.

Первая — цена отсутствующей возможности. Если функция внезапно понадобилась, сколько стоит её добавить?

Вторая — цена уже встроенной сложности. Сколько стоит понимать, обновлять, тестировать и учитывать подсистему всё время, пока существует проект?

Раньше первая цена часто была высокой. Поэтому имело смысл заранее покупать архитектурный запас.

AI резко уменьшает первую цену. Написание glue-кода, изучение API, создание миграций, изменение нескольких слоёв приложения и большая часть механического тестирования стали значительно дешевле.

А вот вторая цена никуда не исчезла. Лишняя абстракция по-прежнему увеличивает пространство состояний системы. Её по-прежнему должен учитывать разработчик. Теперь её ещё должен понимать агент.

Поэтому баланс смещается.

Если возможность можно относительно дёшево сгенерировать и интегрировать в тот момент, когда она понадобится, становится менее рационально постоянно носить её в ядре «на всякий случай».

Сложность должна быть локализована около причины

Из этого получается полезный архитектурный принцип:

Сложность должна находиться рядом с задачей, которая её породила.

Tile server существует потому, что проекту нужны карты. Varnish существует потому, что есть конкретная задача HTTP-кэширования. База данных существует потому, что есть состояние, которое необходимо хранить. Сервис обработки изображений появляется, когда появляется соответствующая нагрузка.

У такой архитектуры есть ещё одно достоинство: её проще разбирать обратно.

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

Поэтому к двум вопросам «что это?» и «зачем это?» стоит добавить третий:

Что произойдёт, если этот компонент убрать?

Если ответ невозможно сформулировать без исследования половины системы, модульность, возможно, существует только на диаграмме.

Не проектировать неизвестное будущее

Классическая инженерная тревога звучит так: «А что, если через три года понадобится X?»

Отсюда вырастают универсальные модели данных, абстрактные extension layers и подсистемы для сценариев, которых пока нет.

Но через три года станет известно не только то, что понадобился X. Станет известно, какой именно X нужен.

Мультиязычность небольшого информационного сайта и мультиязычность международного маркетплейса — разные задачи. Поиск по двадцати статьям и поиск по миллиону товаров — разные задачи. Права доступа в корпоративном портале и авторизация администратора маленького сайта — разные задачи.

Заранее встроенная универсальная подсистема вынуждена решать абстрактное множество будущих сценариев. Решение, добавленное по факту, может решать конкретный.

AI делает второй путь существенно дешевле.

Новый вариант YAGNI

У программистов давно есть принцип YAGNI — You Aren't Gonna Need It: не реализуйте функцию, пока она не нужна.

В AI-разработке у него появляется дополнительное экономическое основание:

You Can Generate It When You Need It.

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

Но универсальность больше не обязана означать наличие всех функций.

Возможно, более ценная универсальность сегодня — это способность проекта принять новую функцию без необходимости заранее знать, какой она будет.

И тогда хороший движок оказывается не тем, в котором уже есть всё.

А тем, в котором очень хорошо понятно, что есть сейчас — и куда добавить следующее, когда оно действительно понадобится.