PHPCenter.pl - Twoje Centrum Informacji - PHP, Wydarzenia, Artykuły, Oferty pracy
Twoje Centrum Informacji
PHP, Artykuły, Meetupy, Oferty pracy

Jak rozpoznać aplikację legacy?

Przez wielu programistów określenie „legacy” jest odbierane bardzo negatywnie. Oznacza ono aplikację z dużym, albo nawet bardzo dużym długiem technicznym, który jest bardzo trudny a czasami niemożliwy do spłacenia. Praca z taką aplikacją jest bolesna, nierzadko powoduje frustrację i niechęć do dalszej pracy nad nią.

Po czym jednak poznać aplikację legacy? Nie ma sztywnych zasad, dzięki którym aplikację należy traktować jako taką – wszystko zależy od jej stanu i subiektywnego spojrzenia na nią. Możemy jednak wyłonić kilka wskazówek, które mogą zasugerować ocenę aplikacji jako legacy.

Nie każdy punkt z tej listy jest tak samo ważny jak pozostałe. Należy tą listę odczytywać jako wskazówki, a nie wymogi do oceny. Przy każdym punkcie zobaczysz komentarz opisujący dany problem, subiektywny czas spłacenia długu technicznego a także uwagi dotyczące jego spłacenia. No to lecimy.

Wywoływanie/użycie skryptów, które znajdują się bezpośrednio w katalogu root serwera/domeny.

Zaczynamy od tego punktu nie bez powodu – jest on najczęściej spotykany w przeróżnych programach OpenSource i nie tylko, a co za tym idzie, razem z nim w parze idzie wiele powiązanych błędów.

Problemem jest możliwość odpalenia praktycznie każdego skryptu PHP znajdującego się na serwerze, z poziomu przeglądarki. Dzieje się tak, ponieważ domena jest podłączona pod główny katalog aplikacji. WordPress, Joomla! i wiele innych skryptów PHP, posiada tego typu strukturę plików. Domena powinna być podpięta pod katalog dostępny publicznie, na przykład /var/www/web, a pozostałe pliki powinny być katalog wyżej, lub katalog obok, na przykład /va/www/src.

Koszt spłacenia długu: 4/5
Gdy aplikacja jest mała, albo mało złożona, spłacenie takiego długu nie powinno być uciążliwe. Jeśli jednak w aplikacji mamy zakodowane na sztywno ścieżki do plików/katalogów, zmiana tej struktury może być czasochłonna i ciężka do wdrożenia, bez popełnienia błędów.

Używanie plików index.html by uniknąć listowania plików/katalogów w przeglądarce.

Niektóre serwery posiadają funkcję listowania plików/katalogów po wejściu na stronę, w sytuacji gdy w katalogu nie istnieje główny plik uruchomieniowy (często jest to plik index.html lubindex.php). Funkcja ta umożliwiała stworzenie szybkiego podglądu listy plików i katalogów na danym serwerze – szybszy i tańszy sposób na FTP 🙂

Gdy na takim serwerze zamieszczona była aplikacja, gdzie pliki wykonywalne były dostępne z poziomu przeglądarki, można było wylistować te pliki i uruchomić każdy z nich w oczekiwaniu na reakcje aplikacji czy serwera i w efekcie zaatakowanie jej. Bywa, że aplikacja posiada dziesiątki pustych plików index.html, w każdym katalogu, które uniemożliwiają takie listowanie.

Koszt spłacenia długu: 1/5
Samo usunięcie plików nie będzie problemem. Punkt ten jest też połączony z punktem wyżej, czyli strukturą katalogów. Gdy spełniony zostanie punkt powyżej, ten będzie sprowadzał tylko do usunięcia plików z serwera.

Posiadanie specjalnego kodu na początku plików PHP, kończącego wykonywanie (die(), exit()), gdy jakiś warunek nie jest spełniony (na przykład istnienie specjalnej stałej).

Kolejny punkt powiązany z pierwszym. Publiczny dostęp do plików PHP zmuszał developerów do blokowania ich wykonywania, przez sprawdzanie jakiejś stałej zdefiniowanej we front-kontrolerze (w pliku index.php na który kieruje Apache lub nginx). Dzięki temu, przy odpaleniu strony „po bożemu”, stała była zdefiniowana w systemie i aplikacja działała bez przeszkód, a gdy jakiś plik wykonywalny był uruchamiany bezpośrednio z poziomu przeglądarki – kod kończył wykonywanie, ponieważ nie było tej specjalnej stałej. Dzięki temu, nie można było wykonać skryptu z plików (czyli bezpośrednio wywołując plik z poziomu przeglądarki) bez działającej aplikacji.

<?php if (!defined('SUPER_CONST')) die();

Jednak gdy tej linijki sprawdzającej brakowało w jakimś pliku, powodowało to dziurę w systemie, która mogła pociągnąć za sobą wielkie konsekwencje.

Koszt spłacenia długu: 1/5
Ponownie, samo usunięcie linijek z kodem sprawdzającym to chwila, jednak należy najpierw wykonać punkt pierwszy z listy.

Architektura aplikacji oparta jest w większości na funkcjach zamiast na klasach/obiektach.

W przypadku PHP, gdy posiadamy świetny system OOP, używanie funkcji w rozbudowanych aplikacjach to katorga dla programistów. Wystarczy zobaczyć jak wyglądają wtyczki do WordPressa. Rozbudowa i utrzymanie takiej aplikacji powoduje wiele wyrzeczeń.

Koszt spłacenia długu: 5/5
To chyba jeden z najbardziej kosztownych punktów tej listy. Wymaga tak na prawdę przepisania aplikacji od nowa, a jeśli nie całej, to jej lwiej części.

Aplikacja posiada bardzo mało klas (względem ilości kodu) lub posiada jest bardzo rozbudowane.

Miałem kiedyś okazje pracować na systemie, gdzie dostępna była klasa, która posiadała około 6000 linijek kodu – sześć tysięcy! Proszę, nie…

Koszt spłacenia długu: 5/5
Koszt jest również bardzo duży, jednak wydaje się relatywnie mniejszy niż poprzedni dotyczący funkcji, bo w pewnym stopniu jakakolwiek obiektowość już istnieje w tym systemie.

Struktura klas jest niezorganizowana; brakuje zasad YAGNI/DRY/SOLID.

Zdublowany kod, wymieszana odpowiedzialność, rozbudowane klasy/metody, brak spójności co do argumentów czy zwracanych wartości a także problemy z zależnościami są kulą u nogi takiej aplikacji. Przemyślana struktura klas oraz ich metod wymaga samozaparcia i doświadczenia, a z rozrostem aplikacji, poświęcony na to czas, zwraca się.

Koszt spłacenia długu: 4/5
Gdy aplikacja jest OOP, sama refaktoryzacja jest możliwa i nie powinna być trudna sama w sobie, jednak jest czasochłonna w zależności od ilości plików w projekcie.

Brak podziału na MVC (lub inny wzorzec), czyli mieszanie kodu HTML i PHP, czy nawet SQL, w wielu plikach/warstwach aplikacji.

Jedną z najstarszych naleciałości PHP jest mieszanie kodu HTML z PHP (a także SQL) w jednym pliku. Wymieszanie powoduje przenikanie się warstw prezentacji i logiki z dostępem do danych, co powoduje problemy w rozbudowie kodu. Powoduje to także powielanie tego samego kodu w wielu miejscach aplikacji – zamiast wydzielić zapytanie SQL do osobnej klasy, pisze się zapytanie bezpośrednio w kontrolerze.

Koszt spłacenia długu: 2/5
Refaktoryzacja jest relatywnie prosta – kod jest już napisany, należy go tylko przenieść w odpowiednie miejsca, rozdzielając warstwy aplikacji od siebie.

Brakuje testów automatycznych, unit/acceptance.

Testy pozwalają nam upewnić się, że napisany przez nas nowy kawałek kodu działa zgodnie z naszymi oczekiwaniami, a stary i zmodyfikowany kod, po naszych zmianach, nadal działa bezproblemowo. Dzięki testom mamy również pewność, że nowa funkcjonalność nie zepsuła czegoś, co już jest w aplikacji.

Brak testów to brak świadomości na temat błędów oraz brak możliwości weryfikacji wprowadzanych funkcjonalności pod względem ewentualnych bugów, wynikłych podczas ich wprowadzania.

Koszt spłacenia długu: 3/5
Dodanie testów wiąże się z decyzją dotyczącą ilości tych testów, tego ile procent aplikacji mają pokryć, a także z czasem jaki trzeba poświęcić na ich napisanie.

Brak Inversion of Control/Dependency Injection.

Zależności pomiędzy klasami można tworzyć na wiele sposobów, jednak chyba najgorszym jest tworzenie obiektów klas zależnych bezpośrednio w konstruktorze. Tworzą się silne powiązania pomiędzy częściami systemu, i poprzez brak abstrakcji uzależniamy nasz kod od konkretnych wdrożeń, zamiast od interfejsów.

Takie silne powiązania powodują, że kod jest ciężki w rozwoju, i jeszcze cięższy w testowaniu. Rezultatem jest kod z zależnościami, których nie możemy zmockować w testach jednostkowych. Również często używany jest Singleton Pattern, który zaśmieca aplikację, a kod stworzony z jego użyciem jest mocno uzależniony od danego singletona i praktycznie niemożliwy w testowaniu.

Koszt spłacenia długu: 3/5
W zależności od ilości klas, zmiana ta nie jest relatywnie pracochłonna, ale w połączeniu z dodaniem kontenera DI (jeśli go brakuje), może zająć ciut więcej czasu. Należy doliczyć dodatkowy czas na całkowite przepisanie klas Singletonowych – jeśli te istnieją w systemie.

Brak composera/autoloadera.

Ten punkt w dzisiejszych czasach może budzić myśli typu: „jakim cudem, przecież composer jest wszędzie”. Jednak istnieją aplikacje, które nie używają żadnego autoloadera, ani tym bardziej composera, a wszystkie klasy ładowane są za pomocą zwykłych dyrektyw include.

Koszt spłacenia długu: 3/5
Wszystko zależy od ilości plików, które należy zaktualizować, oraz struktury klas. Dodatkowo, autoloader najlepiej działa gdy w systemie występuje standard PSR-4 lub chociaż PSR-1. Composer działa również na katalogach wyszukując w nich klas.

Brak Request->Response flow, a zamiast tego echo i exit.

W dzisiejszych frameworkach (chociażby Symfony) żądanie i odpowiedź do przeglądarki są definiowane w formie obiektów Request i Response, a na tych obiektach opiera się lwia część aplikacji, by dostarczyć content do przeglądarki. Niestety, brak tego flow zastępuje zwykłe echo, niekiedy z dodatkowymi wywołaniami funkcji header(), które modyfikują typ odpowiedzi (na przykład JSON). Powoduje to brak kontroli nad flow przetwarzania danych, i późniejsze problemy w ich przetwarzaniu. Na przykład dodanie cache dla całej aplikacji wymaga zmiany odpowiedzi (dodanie nagłówków chociażby) w bardzo wielu miejscach aplikacji.

Koszt spłacenia długu: 2/5
W zależności od ilości miejsc występowania. Sama naprawa błędu to tylko zmiana echo $content na new Response($content), i dodanie paru nagłówków w razie potrzeby.

Podsumowanie

Aplikacje legacy można podzielić na dwie grupy. Te które nadają się do refaktoryzacji, i te które nadają się tylko do przepisania na nowo. Im więcej punktów potrafisz wskazać w swojej aplikacji, tym bardziej zalicza się ona do tej drugiej grupy.

Mam nadzieję, że dzięki temu artykułowi będziesz mógł wskazać słabe punkty aplikacji na której pracujesz, którą rozwijasz, i dzięki temu będziesz miał świadomość na co zwrócić uwagę przy rozwoju swojego kodu. A może nawet uda Ci się podjąć kroki w celu zmniejszenia tych problemów – czego serdecznie Ci życzę.

A jak jest u Ciebie? Może masz inny pogląd, może coś byś dodał do tej listy?

13150cookie-checkJak rozpoznać aplikację legacy?
A co tam, udostępnij:
avatar
  Subscribe  
Powiadom o
Podoba Ci się to co czytasz, chcesz więcej treści od phpcenter.pl?
×
Wyszukaj