От легаси к своему фреймворку: как необходимость стала архит

Всё началось с типичной задачи: нужно было постепенно мигрировать большое процедурное PHP-приложение на современный стек. Классический сценарий — тысячи строк кода без архитектуры, без тестов, без DI, написанные в эпоху “просто работает”.

Почему не взять готовый фреймворк? Первая мысль очевидна: взять Laravel или Symfony и переписать. Но у задачи была специфика — миграция должна быть постепенной, без остановки продакшена. Новые функции пишутся на современном стеке, старые живут как есть. Это означало микросервисную архитектуру: каждый новый кусок функциональности выносится в отдельный сервис. И вот тут полный Laravel оказывался избыточным. Сервис, который занимается только обработкой платёжных уведомлений, не нуждается в очередях Horizon, Eloquent со всеми его связями, Blade-шаблонах и ещё двухстах пакетах. Он должен получить запрос, проверить подпись, записать в базу, отправить событие. Всё. Symfony в минимальной конфигурации был ближе, но требовал погружения в свою экосистему — Service Container, Kernel, бандлы — что для небольшой команды создавало ненужный порог входа.

Что на самом деле нужно микросервису? Когда выписываешь список реальных потребностей, он оказывается коротким: - DI-контейнер - Роутинг - ORM для работы с базой - HTTP-примитивы (запрос/ответ) - Консольные команды - Очереди для асинхронных задач - Миграции

Всё. Никаких шаблонов, никакой авторизации, никакого HTTP-клиента в ядре — это детали конкретного сервиса, не фреймворка.

Сборка из компонентов Оказалось, что весь этот список закрывается существующими компонентами без написания велосипедов: php-di для контейнера, bramus/router для роутинга, Eloquent через Capsule для ORM, Symfony Console для команд, Predis для Redis-очередей, Phinx для миграций. Каждый компонент делает одно и делает хорошо. Никто из них не тянет за собой чужую экосистему. Вместе они дают именно тот список, что выше — и ничего лишнего. Оставалось написать тонкий слой склейки: AbstractKernel который загружает конфиг и собирает контейнер, HttpKernel который запускает middleware pipeline и роутер, ConsoleKernel который регистрирует команды. Суммарно — несколько сотен строк кода.

Что получилось Фреймворк получил название Splinter — небольшой прочный кусок, отколотый от большого дерева. Философия сформулировалась сама собой: Start with the essential. Add only what you need. Ядро намеренно не содержит мнений об авторизации, рендеринге, HTTP-клиенте — всё это опциональные модули. Сервис, которому нужен Twig, подключает splinter/view. Сервис с правилами доступа подключает splinter/access. Сервис-воркер не подключает ничего сверх ядра. Каждый новый сервис разворачивается одной командой:

composer create-project splinter/skeleton my-service

И сразу получает единообразную структуру, те же точки входа, тот же CLI — независимо от того, что именно делает сервис.

Неожиданный результат Самым неожиданным оказалось то, что написание своего фреймворка стало не усложнением, а упрощением. Команда перестала спорить о том, “как правильно по Laravel” или “как это делается в Symfony”. Появилась одна конвенция, понятная всем, без магии и без необходимости читать чужую документацию. Легаси-миграция всё ещё идёт. Но каждый новый сервис — это уже не кусок старого кода, переписанный наспех, а осознанно спроектированный минимальный модуль, который делает одно и делает это хорошо.

https://github.com/splinter-php #microframework #legasy

От легаси к своему фреймворку: как необходимость стала архит | Сетка — социальная сеть от hh.ru