Найбезпечніший підхід — strangler pattern: новий застосунок ставиться поруч, роутинг поступово перекидається на нього, спільною лишається база даних; переписувати все одразу означає роками тримати дві версії продукту.
Як питають
З якого модуля починати міграцію?
Як тримати дві системи в парі під час переходу?
Переписати з нуля чи мігрувати поступово?
Пояснення
Міграція з Yii2 — це не технічне питання про фреймворк, а питання ризику. Повне переписування рідко закінчується: стара система містить роки неявних правил, бізнес продовжує її змінювати, і розрив між системами росте швидше, ніж закривається. Тому робочий підхід — strangler pattern: новий застосунок ставиться поруч, і маршрути переносяться в нього по одному, поки стара система не залишиться порожньою.
Порядок має значення. Спершу характеризаційні тести на критичні сценарії поточної системи: оформлення замовлення, оплата, розрахунок звіту. Вони фіксують поведінку, яку треба зберегти, і закривають суперечки про те, чи баг був раніше. Потім інфраструктура переходу: маршрутизація на рівні nginx або фронт-контролера, спільна автентифікація через Redis-сесію або підписаний токен, спільна база з чіткими правилами володіння таблицями. І лише потім перший модуль: малий, ізольований, але реальний, щоб перевірити весь ланцюжок від деплою до моніторингу.
Далі модулі беруть за пріоритетом бізнесу й частотою змін: те, що змінюється часто, вигідніше мати в новій системі раніше. Логіку з ActiveRecord-моделей спершу виділяють у сервіси ще всередині Yii, а схему бази змінюють лише тоді, коли таблицею володіє одна система. Продукт при цьому не зупиняється: нові фічі пишуться в новій системі, а стара отримує лише виправлення.
КодPHP
// Фронт-контролер перехідного періоду: один вхід, два застосунки
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$migrated = [
'#^/api/v2/#',
'#^/reports/#',
'#^/account/invoices#',
];
foreach ($migrated as $pattern) {
if (preg_match($pattern, $path)) {
require __DIR__.'/../new/public/index.php'; // Symfony або Laravel
return;
}
}
(new yii\web\Application(require __DIR__.'/../config/web.php'))->run();
// Той самий підхід на рівні nginx: маршрути перекидаються без релізу PHP-коду
// location ~ ^/(api/v2|reports)/ { proxy_pass http://new-app; }
// location / { fastcgi_pass yii-fpm; }
// Спільна автентифікація: обидві системи перевіряють один підписаний cookie
final class SharedSessionGuard
{
public function userId(string $cookie): ?int
{
[$payload, $signature] = explode('.', $cookie, 2) + [null, null];
return hash_equals(hash_hmac('sha256', $payload, $this->secret), $signature)
? (int) json_decode(base64_decode($payload), true)['uid']
: null;
}
}
Що хоче почути інтервʼюер
Порядок: спершу характеризаційні тести на критичні сценарії, потім міграція, а не навпаки.
Що strangler pattern це маршрутизація на рівні проксі або фронт-контролера: нові й перенесені маршрути йдуть у новий застосунок, решта в Yii, і бізнес не помічає переходу.
Що спільна база даних на перехідний період є нормою, а спільні сесії, автентифікація й кеш вимагають окремого рішення від першого дня.
Критерії вибору першого модуля: ізольований, з невеликою кількістю залежностей, але з реальною цінністю, щоб перевірити весь ланцюжок від деплою до моніторингу.
Тверезу оцінку: повне переписування рідко закінчується, бо фічі в старій системі не зупиняються, а різниця між системами росте.
Типові помилки
Переписати все за одну ітерацію й переключити в один день.
Починати з найскладнішого модуля або з того, який усі ненавидять, замість малого ізольованого.
Мігрувати без тестів на поточну поведінку й потім сперечатись, чи баг був у старій системі.
Ігнорувати спільні сесії й авторизацію: користувач логіниться в Yii і виявляється анонімним у новій частині.
Зупиняти розвиток продукту до завершення міграції або, навпаки, дублювати кожну нову фічу в обидві системи.
ПОРАДА
Наголосіть на порядку: спершу тести на критичні сценарії, потім міграція, а не навпаки. І поясніть, як вирішили спільну сесію між Yii і новим застосунком.
Додаткові питанняЗ ВІДПОВІДЯМИ
З малого, ізольованого й реального: окремий API-ендпоінт, сторінка звіту, воркер розсилки. Він має мало залежностей від решти Yii-коду, але проходить увесь шлях: репозиторій, CI, деплой, роутинг, логи, моніторинг. Мета першого модуля не перенести цінність, а перевірити інфраструктуру переходу. Потім беруть модулі за пріоритетом бізнесу й за частотою змін: те, що змінюється часто, вигідніше мати в новій системі.
База спільна, кожна система пише лише у свої таблиці або через чіткі правила володіння. Сесії: спільне сховище в Redis з однаковим форматом, або окремий сервіс автентифікації з JWT чи підписаним cookie, який обидві системи перевіряють. Кеш і черги: спільні брокери з окремими неймспейсами. Спільні доменні події через таблицю outbox або брокер дозволяють новій системі реагувати на зміни у старій.
Стара система містить роки неявних правил, які ніхто не задокументував, і новий код мусить їх усі відтворити перед запуском. Тим часом бізнес продовжує змінювати стару систему, і розрив росте. Реліз відкладається, довіра падає, проєкт закривають. Поступова міграція дає результат щомісяця, дозволяє зупинитись у будь-якій точці й перевіряє припущення на реальному трафіку.
Спочатку виділити логіку з моделей у сервіси ще в Yii, покриваючи тестами: це рефакторинг без зміни поведінки. Потім переносити сервіси в новий застосунок як доменні класи, а доступ до тих самих таблиць реалізувати новим ORM або Query Builder. Схему бази на цьому етапі не чіпають: зміни схеми йдуть після того, як таблицею володіє лише одна система.