Как да ядем [монолитен] слон?

Управлението на еволюцията на „наследена“ софтуерна система е труден за решаване проблем. Размерът на кодовата база, високата степен на свързване между компоненти и техническия дълг, натрупан през годините, могат да бъдат огромни. Често липсата на автоматизирани тестове прави всяка техническа промяна рискова и потенциално разрушаваща за бизнеса. Помислете за това, че клиентите не могат да правят поръчки поради актуализация на библиотеката.

Как екипите подхождат към тази неудобна ситуация? Когато им е възложено основно упражнение за рефакторинг или миграция, как да съставят план за безопасен преход? Как да започнат и да измерват напредъка?

В тази публикация представяме казус, който показва, че процес, базиран на данни, базиран на метода цел-въпрос-метрика, може да даде яснота и увереност на екипа. След въвеждането на подхода описваме някои от инструментите, използвани за събиране на данните по време на целия процес (преди и по време на миграцията).

Казус

Наскоро помогнахме на екип, който разработва B2B продукт с типична многостепенна архитектура. Няколко уеб приложения взаимодействат с REST API, свързани с бизнес и услуги за достъп до данни. Софтуерът е на около 7 години. Въпреки че работихме върху много по-големи, по-стари и сложни системи, това приложение вече има приличен размер, с десетки крайни точки.

След първоначален преглед на кода установихме проблеми, често срещани за наследени системи: неуправлявани и остарели зависимости, ерозирана структура на пакети и файлове, липса на автоматизирано тестване, липса на автоматизация на изграждане.

Бяхме помолени да предложим техническа стратегия за миграция и да работим с екипа за нейното изпълнение. Основните движещи фактори за миграцията бяха разходите за поддръжка и рисковете за сигурността, свързани с остарели библиотеки и рамки.

Нашата препоръка беше да не разделяме монолитно приложение на федерация от микро услуги. Разпространените микро услуги биха добавили сложност без реална полза. Вместо това посъветвахме да префабрикуваме наследения монолит в по-управляем и здрав монолит. За да приложим тази стратегия, ние проектирахме постепенно процес:

  • Създайте скелета на новия монолит.
  • Идентифицирайте ограничени контексти и ги извлечете един по един.
  • По време на миграцията потребителите взаимодействат със старите и „пресни“ услуги.
  • След миграцията остарелите крайни точки и мъртвият код са елиминирани.
  • За да внедрите безопасно този процес, напишете автоматизирани тестове (прилагайки BDD техники), за да опишете текущото поведение на всеки ограничен контекст. Тези тестове ни позволяват да потвърдим, че поведението на старата и новата системи е едно и също.

В горната диаграма виждаме:

  • Наследеният монолит (1). Някои от крайните точки и кодът вече не се използват (но не знаехме колко).
  • Различни клиенти (2), които взаимодействат с резервната система.
  • Новият монолит (3), изграден върху чиста структура, с управлявани зависимости. Първоначално този нов бекенд не съдържа крайна точка. С течение на времето крайните точки и поддържащите услуги се мигрират през тази свежа кодова база.
  • API Gateway (4), който въведохме, за да активираме процеса на постепенна миграция. Шлюзът маршрутизира HTTP заявки към съответния монолит. В началото на миграцията всички заявки се препращат към наследената система. В края всички заявки се изпращат до новата система.
  • BDD тестов ремък (5), който представлява набор от автоматизирани тестове, които описват предвиденото поведение на задните приложения. Тестовете са написани в началото на процеса, за да се опише поведението на наследения монолит. По време на миграцията, тъй като крайните точки и трафикът се преместват по новата система, тестовият сноп се използва за проверка дали поведението на системата не е променено.
  • Създаден е и набор от тестове от край до край (6) за валидиране на системата през слоя на потребителския интерфейс. Докато тестовете на слоя API трябва да бъдат изчерпателни, се прилагат по-малък брой тестове от край до край (обикновено фокусирани върху „щастливия път“).

Как да започнем?

Описването на процеса на миграция оставя редица открити въпроси. Колко време ще е необходимо на екипа да го приложи? И по време на процеса как екипът ще може да измери напредъка и да прегледа очакваното време за завършване?

Отговорът на тези въпроси е много важен за осигуряване на видимост на управлението и яснота на екипа. Без него всеки би се почувствал неудобно да започне упражнението. Това е нещо, което наблюдавахме много пъти: когато екипите не знаят размера на слона, им е много трудно да започнат да хапят.

Оформяне на проблема с метрика за цел-въпрос

За да помогнем на екипа, ние приложихме метода Цел-Въпрос-Метрик. В този конкретен случай имахме две цели:

  • Когато оценявахме ситуацията преди миграцията, нашата цел беше да оценим общите усилия. Измислихме 5 въпроса и за всеки въпрос посочихме списък с показатели.
Цел Преценете усилията за извършване на основен рефакторинг
  Въпрос Колко "голям" е продуктът?
    Метричен брой сценарии от край до край
    Брой на UI компоненти (приложения, страници, компоненти)
    Метричен брой крайни точки на REST
    Метричен брой постоянни единици
    Брой БД заявки
    Метричен брой изходни файлове
    Метричен брой броят на историите в git история
    Разпределение по метрични възрасти на изходните файлове
  Въпрос Кои са най-важните части на приложението?
    Метрично класиране на крайните точки на REST по употреба (от регистрационни файлове)
    Показател Оценка на въздействието на сценариите върху бизнеса
  Въпрос Колко "значим" е рефакторингът?
    Метричен Брой библиотеки / рамки за замяна
    Брой библиотеки за надстройка
    Метрична Delta между текущата и целевата версия на libs
    Метричен брой Изходни файлове, които трябва да бъдат модифицирани
  Въпрос Как "безопасно" можем да направим рефакторинга?
    Метричен% от крайните сценарии с автоматизирани тестове
    Метричен% от крайните точки на REST с автоматизирани тестове
    Покритие на метричния код
    Метрично време, необходимо за ръчно тестване на приложението
    Метрични настроения за програмисти
  Въпрос Колко от кода все още се използва?
    Метричен% от крайните точки на REST, все още използвани в сценарии за използване
    Метричен% от обхванатия код при преминаване през сценарии
    Оценка на метрични разработчици
  • По време на миграцията нашата цел беше да проследим напредъка и да актуализираме оставащите усилия. Създадохме 2 въпроса, отново свързани с конкретни показатели.
Цел проследяване на напредъка на рефакторинга
  Въпрос Колко подобрихме мрежата за безопасност?
    Метричен% от крайните сценарии с автоматизирани тестове + делта
    Метричен% от крайните точки на REST с автоматизирани тестове + делта
    Метричен код покритие + делта
    Метрични настроения за програмисти
  Въпрос Колко „услуги“ сме извлекли и мигрирали?
    Мигриран метричен% от крайните точки на REST (с агрегати)
    Метричен Брой изходни файлове, премахнати от версията
    Метрично Време, изразходвано за всяка тестова автоматизация
    Метрично време, изразходвано за всяко извличане

Извличане на показатели

Със структурата на GQM трябваше да намерим начин да събираме показателите по автоматизиран начин. Имаме инструменти за извличане на кодови показатели, но няма да ги обсъждаме в тази публикация. По-скоро ще се съсредоточим върху следните две показатели от по-високо ниво, които са по-трудни за събиране:

  • процентът на крайните точки REST, все още използвани в сценарии за използване
  • процентът на обхванатия код при преминаване през сценарии

За да съберем данните, създадохме система за запис на сценарии за използване. Системата генерира журнални файлове, които свързват всеки сценарий със списък на крайните точки и със списък на изпълнените методи. Например, можем да използваме системата за запис на сценария „Създаване на фактура“. Системата генерира метаданни, които свързват сценария с 3 крайни точки REST и 12 метода.

За да изградим системата, ние интегрирахме 3 основни компонента:

  • Използвахме разширение за Chrome с отворен код, предназначено да улесни проучвателните тестове. Той предоставя лесен начин за записване на „начало“ и „край“ на сценарий. Собственикът на продукта може да извърши цялостно разглеждане на приложението и да сигнализира за началото и края на всеки отделен сценарий. Може да им даде описателни имена. В края на сесията на запис разширението на Chrome ни дава първи дневник на събитията с времевото разграничаване между сценариите.
  • Използвахме обикновен шлюз на API пред монолита, за да уловим HTTP заявки, изпратени до REST API. Този прокси ни дава втори журнал на събитията, където имаме времева марка за всяко извикване на крайната точка.
  • И накрая, OpenClover се използва за инструментиране на кода на приложението и генериране на показатели за покритие на кода. Това създава трета продукция на метаданни, поставени във временни срокове.

Ето опростен изглед на трите генерирани лог файлове (OpenClover съхранява данни в база данни и процесът за записване на сесии е малко по-ангажиран):

* Регистър на събитията 1 (разширение за хром)
12:02:00 старт - клиент на фактура
12:03:12 край - клиент фактура
12:04:10 старт - отпечатване на месечен отчет
Края на 12:05:00 - отпечатване на месечен отчет
* Журнал на събитията 2 (API шлюз)
12:02:04 POST / api / авт
12:02:30 GET / api / клиенти / 93
12:02:49 POST / api / задачи / изпратете фактура
* Дневник на събитията 3 (OpenClover)
12:02:04 метод com.acme.controllers.AuthController.login
12:02:04 метод com.acme.services.AuthService.authenticate
...

След това е доста лесно да се обработват тези файлове. Първият се използва за идентифициране на времевите граници между сценариите. След това останалите се използват за извличане на крайните точки и извиквания на методи, които се появяват в тези граници. Един от начините да направите тези данни лесни за използване е да генерирате CSV файл и след това да използвате инструмент за визуализация на данни като Tableau.

заключение

Разбира се, създаването на подобна система и записването на всеки сценарий за използване (изграждане на инвентара на функциите) отнема доста време.

Но когато това е направено, екипът има нещо осезаемо и измеримо за работа. Екипът има конкретен и количествен начин за проследяване на напредъка на миграцията. Освен това, разработчиците бързо имат представа за количеството на остарелите крайни точки и мъртвия код.

Както казахме по-рано, това често е необходимо на екипите, за да започнат да работят върху предизвикателна и преобладаваща задача. Независимо дали става въпрос за сложен рефакторинг, инициатива за изплащане на технически дълг или кампания за въвеждане на автоматизирани практики за тестване, може да се приложи същия подход на високо ниво.