Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як провести великий рефакторинг, не зупиняючи розробку: Branch by Abstraction?

Великі зміни (заміна ORM-шару, платіжного провайдера, пошукового рушія, переписування ключового модуля) в окремій гілці Git на тижні - класична пастка: гілка відстає від main, злиття стає болісним, а результат не перевірений у продакшені до самого кінця.

Branch by Abstraction - «гілкування» всередині коду замість гілки в Git:

  1. ввести абстракцію перед частиною, що змінюється, і перевести на неї всіх клієнтів - поки з єдиною реалізацією, старою:
interface SearchEngine
{
    public function search(SearchQuery $query): SearchResults;
}

final class DatabaseSearch implements SearchEngine { /* наявний код */ }
  1. поступово писати нову реалізацію поруч - у main, маленькими комітами, з тестами:
final class MeilisearchSearch implements SearchEngine { /* нова */ }
  1. перемикати клієнтів на нову реалізацію - через конфігурацію чи feature flag, частинами:
$this->app->bind(SearchEngine::class, fn () => Feature::active('new-search')
    ? app(MeilisearchSearch::class)
    : app(DatabaseSearch::class));
  1. видалити стару реалізацію, а за потреби - і саму абстракцію, якщо вона більше не потрібна.

Переваги:

  • код завжди в робочому стані і постійно інтегрується - немає великого злиття;
  • зміни потрапляють у продакшен поступово і можуть бути вимкнені миттєво;
  • паралельна робота: інша команда продовжує розробку, не чекаючи на завершення рефакторингу;
  • перевірка на реальних даних: нову реалізацію можна ввімкнути для частини користувачів чи запускати «в тіні» й порівнювати результати.

Інструменти:

  • feature flags - у Laravel - Pennant (Feature::active()), з поступовим ввімкненням для відсотка користувачів;
  • контейнер - перемикання реалізацій без змін у клієнтах;
  • тести на контракт абстракції - однаковий набір тестів для старої й нової реалізацій.

Що може піти не так:

  • абстракція, «зліплена» зі старої реалізації, - нова не вкладається в неї. Абстракцію варто проєктувати від потреб клієнтів, а не від методів старого класу;
  • прапорці, які ніхто не прибирає - після завершення переходу їх треба видалити разом зі старим кодом;
  • дані: якщо реалізації по-різному зберігають дані, потрібна міграція чи подвійний запис на перехідний період.

Пов'язане: Strangler Fig - та сама ідея на рівні систем і маршрутизації запитів, Branch by Abstraction - на рівні коду всередині застосунку.

Докладніше в документації: Мартін Фаулер: Branch By Abstraction

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання