Lava Flow jest antywzorcem, który niestety często można spotkać w starych projektach, nierzadko przekazywanych od jednego zespołu do drugiego.
Zacznijmy od cytatu z Wikipedii:
“In computer programming jargon, lava flow is a problem in which computer code written under sub-optimal conditions is put into production and added to while still in a developmental state.”
Definicja prawdopodobnie nie jest do końca jasna, ale mówi o sytuacji, w której zmiany w kodzie dokonywane są bez pełnego zrozumienia projektu oraz w pośpiechu.
Antywzorzec Lava Layer powstaje, gdy próbujemy korzystać z wielu technologii lub rozwiązań mających podobne zastosowanie. Jako przykład rozważmy DAL…
W starych projektach, często można spotkać czyste zapytania SQL\ADO.NET. Jeśli projekt jest ogromny, trudno wszystko natychmiast naprawić. Często jednak programiści podejmują się takiego zadania i np. w przypadku zapytań SQL, mógłby ktoś zastosować wzorzec Gateway. Załóżmy, że po pewnym czasie ktoś inny, w tym samym projekcie, wprowadzana kolejną modyfikacje – jakiś framework ORM np. EntityFramework.
W przypadku braku komunikacji między poszczególnymi programistami, może okazać się, że mamy kilka technologii (SQL queries, EntityFramework, nHibernate, Dapper) w tym samym projekcie, mające te same zadanie. Kod oczywiście jest bardzo trudny wtedy w utrzymaniu i np. dodanie nowej encji do projektu wygląda inaczej w zależności od jej typu.
Innymi słowy, Lava to brak spójnej wizji, którą podążają wszyscy programiści. Każda osoba, próbując zmienić DAL, ma dobre intencje – chce skorzystać z nowej technologii. Dzisiaj EntityFrameowrk czy Dapper są dość stabilnymi bibliotekami, ale za parę lat może okazać się, że programiści będą chcieli pozbyć się tego z kodu jak szybko tylko to możliwe.
Problem wynika często z braku odpowiedzialności za kod. Jeśli projekt jest przesuwany pomiędzy różne osoby czy zespoły, wizja autora kodu jest po drodze po prostu gubiona.
Osoby przychodzące potem do zespołu, zwykle krytykują kod, który został przed nimi napisany. Bardzo często w legacy code jest wiele okropnych rzeczy, ale mimo to, kluczowe jest zrozumienie dlaczego pewne decyzje zostały podjęte w dany sposób. Narzekanie na istniejący kod i budowanie wszystkiego od nowa zwykle jest bardzo złym rozwiązaniem. Przed jakimikolwiek ulepszeniami, należy zrozumieć intencje poprzednich autorów oraz dokładne rozwiązania z których korzystali.
Następnie, bardzo ważne jest, aby być spójnym w refaktoryzacji. Jeśli zdecydujemy się na zastąpienie technologii A, technologią B, nie możemy w międzyczasie wprowadzić nowego rozwiązania C. Każda refaktoryzacja to proces iteracyjny i naturalne jest, że rozwiązania A i B będą przez pewien czas egzystować równolegle. Powinniśmy jednak dążyć do sytuacji kiedy stosowanie rozwiązania A będzie zmniejszać się, na rzecz B. Jeśli w trakcie tego procesu, okaże się, że jednak technologia C jest lepsza to powinniśmy najpierw dokończyć albo anulować poprzednie kroki (tzn. wprowadzenie B).
Bez tej dyscypliny, może okazać się, że skończymy z rozwiązaniami A,B,C,D,E i nikt nie będzie w stanie w zespole powiedzieć dlaczego tak stało się.
Problem pojawia się, gdy programiści odchodzą z firmy i nie zostawiają jasnej wizji w jakim kierunku projekt powinien pójść. Wtedy zwykle nowi programiści przychodzący do firmy, oczywiście nie znają tych intencji i próbują wprowadzać swoje ulepszenia, mając dobre intencje.
Mowa tutaj o pojedynczym projekcie. Poszczególne zespoły powinny mieć wybór między różnymi technologiami i wtedy nie ma w tym nic złego, że w jednym serwisie jest EntityFramework w a drugim Dapper.
Inna moja obserwacja jest taka, że im bardziej monolitowa architektura tym łatwiej o Lava w projekcie. W kolejnych postach będę pisał o mikroserwisach, które są może czymś oczywistym, ale rozwiązują naprawdę wiele problemów – nie tylko natury technicznej.