- 1. Legacy code – co to takiego?
- 2. Legacy code – co zrobić z takim kodem?
- 3. Refactoring kodu – narzędzia
- 4. Rector PHP – pogromca legacy code?
- 5. Refaktoryzacja – jakie mamy możliwości w takim przypadku?
- 6. Zmiana architektury kodu
- 7. Dlaczego Rector, a nie IDE?
- 8. Rector – konfiguracja
- 9. Rector a kod legacy – podsumowanie
Legacy code – co to takiego?
Zanim przejdę do opisania możliwości Rectora, chciałbym w kilku zdaniach nakreślić, czym jest legacy code i jakie są najczęściej wybierane sposoby radzenia sobie z tymże problemem. W sieci trafimy na wiele definicji legacy code. W dosłownym tłumaczeniu legacy code oznacza nic innego, jak „kod dziedziczony”, czyli kod, który de facto otrzymujemy w spadku po innych programistach, na przykład w momencie dołączenia do nowego projektu. Taki kod budzi lęki i obawy – kod działa, lecz nie znamy jego zawiłej logiki. Szczególny postrach sieje trudny do zrozumienia i okiełznania spaghetti code. Legacy code to również kod, który… piszemy w danej chwili, ale nie został jeszcze pokryty testami, zatem nie jest przygotowany na zmiany w przyszłości. Według mnie każda z powyższych definicji opisuje istotę problemu.
Legacy code – co zrobić z takim kodem?
W pracy z legacy code mamy do wyboru podejścia, które albo minimalizują jego wystąpienie, albo usuwają taki kod całkowicie. Możemy zatem zastosować takie rozwiązania jak refactoring kodu lub całkowicie go przepisać. Refactoring kodu dotyczy optymalizacji jego małych fragmentów, bez zmiany podstawowej funkcjonalności, drugie podejście wymaga przepisania całego kodu aplikacji na nowo, z uwzględnieniem aktualnych standardów.
Przeczytaj także:
Refactoring kodu – narzędzia
Jak już wspomniałem we wstępie, mamy obecnie wiele narzędzi umożliwiających walkę z długiem technologicznym w kodzie PHP. Wśród narzędzi do refaktoryzacji można wymienić takie jak:
- PHP_CodeSniffer,
- PHP CS Fixer,
- PHP-Parser,
- PHPStan,
- Psalm,
- Rector.
Które z narzędzi wybrać? Wszystko zależy od tego, czego zespół programistów potrzebuje w danym momencie oraz tego, czy narzędzie spełnia nasze oczekiwania. Jednym z decydujących czynników będzie też znajomość danego narzędzia przez członków zespołu developerskiego. Jedne z powyższych narzędzi przeprowadzają analizę statyczną kodu, drugie modyfikują go zgodnie z aktualnymi standardami, a jeszcze inne umożliwiają obie te rzeczy – tak jak właśnie Rector.
Rector PHP – pogromca legacy code?
Rector pojawił się w 2017 roku, a inicjatorem jego powstania był Tomasa Votruba. Rector to program CLI (Command Line Interface) na licencji open source, oparty na komponentach
Symfony. To narzędzie, które poza analizą statyczną kodu dokonuje też jego zmiany. Podstawowe zastosowania Rectora to sprawna i szybka aktualizacja i refaktoryzacja kodu, a także zmiana architektury aplikacji.
Refaktoryzacja – jakie mamy możliwości w takim przypadku?
W przypadku aktualizacji i refaktoryzacji możemy tutaj wymienić takie możliwości jak:
- migracja z PHP 5.3 do PHP 8.1,
- migracja z Symfony 2.8 do Symfony 4.4,
- usuwanie tzw. martwego kodu (ang. dead code, czyli kodu, który nigdy nie będzie wykorzystany),
- zmiana nazw klas, metod, parametrów.
Zmiana architektury kodu
Co do zmian architektury, zmiana fasady w Laravel na DI czy przeniesienie aplikacji z TYPO3 na Symfony. Oczywiście współczesne IDE umożliwiają refaktoryzację kodu, jednak mogą działać wolno i być skomplikowane w obsłudze. W przypadku wykorzystywania wyrażeń regularnych do wyszukiwania fragmentów kodu mogą znajdować nie wszystkie wystąpienia lub wręcz przeciwnie – wyszukiwać znacznie więcej. Kopiowanie i wklejanie przez programistę także może być obarczone pewnym błędem wynikającym ze zmęczenia czy rozkojarzenia.
Dlaczego Rector, a nie IDE?
Rector nie zrobi nic, na co nie pozwoli programista! Opiera się na regułach (to zdefiniowane, pojedyncze „przepisy”, które dokonują pojedynczej zmiany w kodzie), zgrupowanych w zestawy reguł wykonujących zmiany o zbliżonej charakterystyce.
Pojedyncze reguły:
- ArrayKeyFirstLastRector,
- IsCountableRector,
- JsonThrowOnErrorRector.
Zestawy reguł:
- PSR4,
- Php70,
- Php71, TypeDeclaration,
- DowngradePhp71.
W momencie pisania artykułu Rector udostępniał około 660 reguł, zebranych w ponad 48 zestawów.
Rector – konfiguracja
Zasada działania Rectora jest bardzo prosta – zaczynamy od zainstalowania narzędzia i jego konfiguracji. Rector w pierwszej kolejności wyszukuje wszystkie pliki wskazane przez programistę, następnie, analizując każdy z nich z osobna, buduje dla nich AST (Abstract Syntax Tree), tzw. drzewo abstrakcji składniowej. Do każdego takiego drzewa stosuje zdefiniowane przez programistę w pliku konfiguracyjnym reguły. Gdy cały proces zostanie przeprowadzony, w konsoli otrzymujemy raport dotyczący naniesionych zmian. Warto wspomnieć, że Rector nie opiera się wyłącznie na domyślnych regułach – narzędzie umożliwia tworzenie własnych, bardziej wyspecjalizowanych.
/** @var SplFileInfo[] $fileInfos */ foreach ($fileInfos as $fileInfo) { // 1 file => nodes /** @var Parser $phpParser */ $nodes = $phpParser->parse(file_get_contents($fileInfo->getRealPath())); // nodes => 1 node foreach ($nodes as $node) { // rather traverse all of them /** @var PhpRectorInterface[] $rectors */ foreach ($rectors as $rector) { foreach ($rector->getNodeTypes() as $nodeType) { if (is_a($node, $nodeType, true)) { $rector->refactor($node); } } } } }
return static function ( ContainerConfigurator $containerConfigurator ): void { // get parameters $parameters = $containerConfigurator->parameters(); $parameters->set(Option::PATHS, [ __DIR__ . '/src' ]); // Define what rule sets will be applied $containerConfigurator->import(SetList::CODE_QUALITY); }; ChangeArrayPushToArrayAssignRector class SomeClass { public function run() { $items = []; - array_push($items, $item); + $items[] = $item; } }
CombinedAssignRector -$value = $value + 5; +$value += 5; DateTimeToDateTimeInterfaceRector class SomeClass { - public function methodWithDateTime(DateTime $dateTime) + /** + * @param DateTime|DateTimeImmutable $dateTime + */ + public function methodWithDateTime( DateTimeInterface $dateTime ){ return true; } } SimplifyArraySearchRector -array_search("searching", $array) !== false; +in_array("searching", $array);
Kod legacy – podsumowanie
Pracy z legacy code nie sposób uniknąć, prędzej czy później każdy programista spotka się z nim w projekcie. Dobrze jest znać możliwości, jakie w zakresie refaktoryzacji kodu dają dostępne narzędzia, takie jak Rector. Mam nadzieję, że przekonałem was do poznania jego możliwości – a jeśli chcecie dowiedzieć się więcej, zachęcam do obejrzenia mojego wystąpienia na DrupalCamp Poland 2021:
- 1. Legacy code – co to takiego?
- 2. Legacy code – co zrobić z takim kodem?
- 3. Refactoring kodu – narzędzia
- 4. Rector PHP – pogromca legacy code?
- 5. Refaktoryzacja – jakie mamy możliwości w takim przypadku?
- 6. Zmiana architektury kodu
- 7. Dlaczego Rector, a nie IDE?
- 8. Rector – konfiguracja
- 9. Rector a kod legacy – podsumowanie