Projekt typy Greenfield. Takim sloganem często próbują nas skusić rekruterzy. Muszę przyznać, że działa to całkiem dobrze. Za każdym razem wyobrażam sobie puste repozytorium, do którego ląduje nieskalany długiem technicznym kod. Rozmyślam o tych wszystkich nowych framworkach. Wspominam ostatnio odwiedzone konferencje i wizualizuje sobie, jak implementuję nowo poznane wzorce. Też tak masz?
Niestety ten post będzie o czymś zupełnie innym.
W swojej karierze miałem okazję dwukrotnie przeprowadzać proces przejęcia produkcyjnie działającego systemu napisanego przez innego dostawcę.
W pierwszym przypadku zostałem rzucony na głęboką wodę. System działający od dziesięciu lat na produkcji. Osiem osobnych wdrożeń w ośmiu europejskich krajach. Napisany z użyciem tureckiego komercyjnego framework’a z poprzedniego wieku i rozwijany przez kolegów z Azji. Spaghetti jakich mało, a dług technologiczny jak odległość z Warszawy do Stambułu.
W drugim przypadku chodziło o bardziej nowożytną architekturę. Standardowy stos Java’ovy bazujący na Spring Boot. Jedna instalacja, ale używana przez użytkowników z kilku krajów. Niestety cała masa złych praktyk. Węgierscy koledzy po fachu, którzy oryginalnie zaimplementowali ten soft, najwyraźniej dopiero się uczyli.
W obydwu przypadkach zastosowaliśmy ten sam siedmiopunktowy plan działania.
W obydwu przypadkach najważniejszy driver był ten sam: zadowolenie użytkowników końcowych. Chodziło o to, żeby nie odczuli, że coś zmienia się na gorsze. W obu przypadkach klient był obiecujący i wykonując przejęcie systemu sprawnie, mogliśmy liczyć na współpracę również przy innych projektach.
1. Poznanie biznesu oraz funkcji systemu
Z punktu developera wydawać by się mogło, że powinniśmy oczywiście w pierwszej kolejności poprosić o kod i zacząć od jego analizy. Ja należę jednak do tego nurtu, który uważa, że poznanie domeny biznesowej jest najistotniejsze. Zwłaszcza że przejmowane systemy działały już od lat produkcyjnie, a support wymagał bezpośredniego kontaktu z użytkownikami końcowymi. A przecież kluczowe do sprawnego prowadzenia wsparcia technicznego jest między innymi posługiwanie się terminologią, do której przywykli użytkownicy.
W przypadku pierwszego systemu ten etap został zorganizowany w postaci dwutygodniowego warsztatu. Cały nasz zespół czyli: architekt, analitycy, programiści i testerzy uczyli się, jak działa system. Tak dokładnie przez dwa tygodnie nie dotknęliśmy w ogóle kodu.
W drugim przypadku etap ten był krótszy i zamknął się w postaci dwóch kilkugodzinnych prezentacji. Tak samo udział brał w nich cały zespół.
2. Analiza specyfikacji funkcjonalnej
Drugim etapem, w który zaangażowany był cały zespól, było zapoznanie się z dostarczoną specyfikacją funkcjonalną. Chodziło o zweryfikowanie jej pod kątem wiedzy zdobytej podczas warsztatu/szkolenia. Zweryfikowanie jej aktualności i czy odzwierciedla stan faktyczny systemu. Celem tego etapu było zadbanie o to, aby każdy członek zespołu mógł w szybki sposób odnajdywać właściwą funkcję systemy na podstawie opisu zgłoszenia.
W przypadku drugiego przejęcia okazało się, że specyfikacja funkcjonalna była tak tragiczna, że nasi analitycy postanowili napisać własną od podstaw.
Podczas realizacji tej fazy kluczowe było posiadanie wsparcia zespołu aktualnego dostawcy. Pewne było, że będą pojawiać się pytania.
3. Analiza architektury systemu i dokumentacji technicznej
W końcu nadszedł czas na trochę technicznego mięcha. Zespół programistów, na czele z architektem, analizuje dostarczoną dokumentację techniczną. Cel to zapoznanie się z architekturą, podziałem na moduły.
Nic nie stoi oczywiście na przeszkodzie, aby ten etap toczył się równolegle z punktem drugim. Jednak w obu przypadkach uznaliśmy, że developerzy nie powinni zaczynać od tego punktu.
4. Praca z kodem
W końcu to, co kochamy najbardziej. W etap ten byli zaangażowani oczywiście wyłącznie programiści i architekt. Wynikiem tego etapu było (co oczywiste) zapoznanie się z kodem, zweryfikowanie go pod kątem dokumentacji technicznej oraz co najważniejsze zestawienie środowisk developerskich do pracy.
Podczas tego etapu również kluczowe było posiadanie wsparcia aktualnego zespołu developerskiego na wypadek pojawiających się pytań.
W przypadku przejęcia systemu od kolegów z Turcji pytań było tyle, że organizowaliśmy codzienne spotkania architekt-architekt oraz team leader – team leader przez około tydzień.
Miały miejsce też warsztaty developerskie (5 dni), na których na zasadzie pair programming’u tureccy programiści wspólnie z naszymi pracowali nad prawdziwymi zgłoszeniami z Jira.
5. Przejęcie procesów CI/CD
Jednym z bardzo istotnych technicznych etapów była gotowość do samodzielnego wdrażania kolejnych release’ów systemu na wszystkie środowiska w tym najważniejsze, czyli dostarczanie na produkcję.
W przypadku systemu przejmowanym od kolegów z Turcji stanęliśmy przed dylematem. Środowiska developerskie, jakie otrzymaliśmy były bardzo silnie zintegrowane z Eclipse w archaicznej wersji (z racji autorskich wtyczek poprzedniego zespołu niedostosowywanych nigdy do nowszego Eclipse). Do lokalnego developmentu nie był używany ani Maven ani Ant, a kompilacja odbywała się w Eclipse. Z kolei paczka dostarczana na środowiska test, preprod i produkcję budowana była Ant’em. Na każde środowisko było trzeba wykonywać osobny release. Systemem kontroli wersji był SVN. Kompletnie nie wpasowywało się to w nasze standardy.
Naturalnie padła propozycja przerobienia tego po naszemu.
Musieliśmy jednak wziąć pod uwagę najważniejsze ograniczenie, którym był czas. Musieliśmy jak najszybciej zyskać pełną operacyjną sprawność i zapewnić wsparcie użytkownikom końcowych na takim samym poziomie jak poprzedni dostawca. W refaktoryzację w tak złożonym systemie i procesie moglibyśmy zagrzebać się na zbyt długo. Zapadła decyzja, że przejmujemy wszystko jak jest.
6. Okres przejściowy
Był to czas, kiedy oznajmiliśmy użytkownikom końcowym o naszym istnieniu. Oczywiście wiedzieli, że proces ma miejsce, ale dopiero w tym okresie zaczęliśmy udzielać się w JIRA. Pracowaliśmy nad zadaniami, jednak każde rozwiązanie było przeglądane przez członków poprzedniego zespołu i przez nich akceptowane. Co istotne, odpowiedzialność cały czas była po stronie starego team’u. Oznaczało to, że za nasze błędy odpowiadali oni :D.
7. Przejęcie odpowiedzialności
Był to moment, kiedy nastąpiło przekazanie odpowiedzialności na nasz zespół. Jednocześnie w tym momencie stary zespół przestał nas wspierać merytorycznie. W tym momencie uświadomiliśmy sobie, jak istotne były wszystkie poprzednie etapy. Znaliśmy system biznesowo, mieliśmy zbudowane już relacje z użytkownikami systemu, wiedzieliśmy czego się spodziewać w zgłoszeniach. Dostarczaliśmy nowe wersje bez najmniejszego problemu. Dopiero w tym momencie mogliśmy zacząć myśleć o usprawnieniach i refaktoringu.