Rozwój aplikacji bez rewolucji u klientów
W pracy związanej z rozwojem oprogramowania naturalne jest, że każda aplikacja, każdy system, który tworzymy prędzej czy później będzie musiał być zmodyfikowany. To normalne, świat się zmienia, wymagania biznesowe też, dlatego nasze systemy muszą dopasowywać się do tych zmian. Niektóre modyfikacje są małe i nie wpływają zbyt mocno na system. Jednak prędzej czy później nadchodzą potężne zmiany, które potrafią wywrócić nasze dotychczasowe myślenie do góry nogami. Jak więc wdrażać takie zmiany w systemach w bezpieczny sposób, upewniając się, że nasi klienci wciąż mogą pracować?

Rozwój oprogramowania można porównać do remontu drogi. Gdy chcemy przebudować jeden z odcinków drogi ekspresowej S8, to nie możemy sobie pozwolić na zamknięcie całej drogi. Jeżeli po prostu zamkniemy daną drogę, to zablokujemy wielu kierowców. W szczególności, gdy nie ogłaszaliśmy tego wcześniej i nie wyznaczyliśmy objazdu. Takie problemy warto starać się przewidzieć i spróbować jak najbardziej zmniejszyć niedogodności dla użytkowników (lub kierowców w tym przypadku). Można by więc pomyśleć o objeździe, najlepiej jak najkrótszym. W świecie aplikacji czasem twórcy zapominają o objazdach, a nawet próbują wytyczać całe drogi od nowa. Czy to jest dobry pomysł? Jak sobie w takiej sytuacji radzą użytkownicy? 

Historia

Wyobraźmy sobie sytuację, że zajmujemy się rozwojem aplikacji do wysyłki smsów. Posiada ona póki co dość proste funkcjonalności, ale jest już używana zarówno przez projekty wewnątrz naszej firmy jak i kilkanaście zewnętrznych firm, które wykupiły u nas usługi wysyłki SMS z użyciem API.

Wraz z rozwojem aplikacji postanowiliśmy dość mocno przebudować całość rozwiązania. Poprzednią wersję systemu coraz ciężej się już rozwijało i dość mocno nas ona ograniczała.

Przyszedł czas dużych porządków, jednak wraz z nimi wprowadziliśmy do aplikacji zmiany niekompatybilne wstecz. Dokładne wytłumaczenie tego pojęcia znajdziesz w artykule []. W skrócie zmiana niekompatybilna wstecz to zmiana, która powoduje popsucie integracji pomiędzy naszymi klientami a systemem, który rozwijamy (wracając na chwilę do świata dróg - taka zmiana to właśnie wytyczenie zupełnie nowej trasy). 
Jakie więc teraz mamy możliwości, żeby wprowadzić takie zmiany na produkcję. Rozważmy kilka scenariuszy:

Wdrożenie niekompatybilnej wstecz zmiany

To najprostsza opcja. Zrobiliśmy zmianę, więc ją po prostu wdrażamy. Jakie jednak niesie to ryzyko?
Popsute aplikacje klientów
Każda aplikacja, która obecnie używa naszej usługi przestaje działać. To poważny problem, zarówno reputacyjny jak i finansowy. Jeżeli dla przykładu używaliśmy tej usługi do wysyłki smsów z kodami potwierdzającymi logowanie (2 factor authentication) to żaden z użytkowników takiej aplikacji nie mógł z niej korzystać.  To ewidentny problem i w praktyce nieakceptowalne rozwiązanie.

Zostawienie klientom czasu na migrację

Kolejną możliwością jest podejście pośrednie. Jakiś czas przed wdrożeniem naszej niekompatybilnej wstecz zmiany kontaktujemy się ze wszystkimi klientami i ustalamy, że określonego dnia będziemy wprowadzać do systemu taką zmianę. W związku z tym ich systemy przestaną działać, ale już teraz możemy im dostarczyć nowe interfejsy API, które będą działały na nowej wersji oprogramowania. Maja więc czas na poprawę swojej aplikacji.

Tu rzeczywiście (o ile wszystko pójdzie po naszej myśli) nie popsujemy nikomu funkcjonalności. Jednak nadal to podejście ma kilka problemów.
Jak zapewnić odpowiedni poziom testów?
W takim przypadku musimy wystawić naszym klientom aplikację w nowej wersji do testów. To nam dodaje kolejne środowisko do utrzymania.

W jaki sposób można zsynchronizować wdrożenie wszystkich aplikacji klienckich?
To większy problem. Nie możemy oczekiwać, że wszystkie aplikacje klienckie zrobią wdrożenie swoich poprawek (zgodnie z naszymi zaleceniami) w godzinie 0 - gdy my będziemy wdrażać swoje nowe rozwiązanie. W związku z tym musimy zastosować tu podejście przejściowe. 
Mianowicie musimy wystawić im nową produkcyjną wersję serwisu do wysyłki SMS i pozwolić im się powoli migrować w okresie przejściowym. 
 
W jaki sposób możemy zmusić naszych klientów do zmiany?
Dopóki wszystkie aplikacje, które korzystają z naszego rozwiązania, są rozwijane w ramach naszej firmy i co ważniejsze są aktywnie rozwijane, to mamy ułatwione zadanie. Choć nadal próba skoordynowania takiej poprawki w kilkunastu zespołach jest bardzo skomplikowana.
Schody zaczynają się, gdy aplikacje korzystające z naszej usługi są poza nami (np. u naszych klientów). Co więcej, możemy w ogóle nie być świadomi w jak wielu aplikacjach nasze rozwiązanie jest używane. Przez to wymaganie zaktualizowania wszystkich klientów w określonym przedziale czasowym wydaje się nierealne.
 
To podejście jest więc akceptowalne, ale w praktyce niewykonalne, bo jak można zmusić płacących klientów do tego, żeby zainwestowali w poprawki swoje kolejne pieniądze?Przecież kupując rozwiązanie naszej firmy również oczekują, że będzie ono cały czas działało.
 

Utrzymanie kilku wersji

Rozwiniemy tutaj poprzedni punkt: jeżeli damy klientom czas na migrację na nasze nowe rozwiązanie, to musimy im udostępnić co najmniej dwa środowiska produkcyjne: w poprzedniej wersji i w nowej wersji. Tak więc już tutaj musieliśmy wprowadzić wersjonowanie naszych aplikacji. Oczekując, że w zadanym przedziale czasowym wszyscy klienci się zmigrują, będziemy mogli bezpiecznie wyłączyć poprzednią wersję.
Jednak życie często weryfikuje nasze plany i nie wszyscy klienci będą w stanie zmigrować się z zadanym terminie. W związku  tym płynnie przechodzimy do utrzymania wielu wersji aplikacji jednocześnie. Przy dwóch wersjach nie jest to jeszcze dużym problemem, ale… 
Jak utrzymywać wiele wersji aplikacji?
Jednak, idąc tym tropem, z każdą kolejną niekompatybilną zmianą dodajemy nową wersję do utrzymania. Co już przy dwóch lub więcej wersjach potrafi przysporzyć nam sporo pracy. W takiej sytuacji każdy wykryty błąd będzie musiał być najpierw zgłoszony z uwzględnieniem konkretnej wersji, następnie naprawiony, a poprawki spropagowane do pozostałych wersji. Jednak nie do wszystkich. Trzeba będzie jeszcze zweryfikować, czy błąd dotyczy każdej wersji, czy tylko niektórych.
Jak się możesz domyślić, każda kolejna wersja zwiększa tylko złożoność operacji na takim ekosystemie.

Utrzymanie kompatybilności wstecznej

Biorąc to wszystko pod uwagę, najlepszym rozwiązaniem zazwyczaj jest ciągła walka o kompatybilność wsteczną. Dzięki temu:
- nie będziemy musieli utrzymywać wielu wersji aplikacji, 
- będziemy mogli bez problemów wdrażać aplikację, nie informując o tym klientów, 
- zachowamy bezpieczeństwo wdrożeń.