Jakiś czas temu zacząłem pracować dla klienta, który realizuje swój projekt w oparciu o koncepcję mikroserwisów Martina Fowlera. Nowe serwisy pisane są w Pythonie ale utrzymanie i dalszy rozwój starszych częściej architektury wymaga znajomości języka PHP. Mam ponad pięcioletnie, ciągłe doświadczenie w programowaniu w PHP, ale sięga ono czasów kiedy użycie JavaScriptu na serwerze wydawało się być pomysłem absurdalnym, kiedy konto na Naszej Klasie było tak powszechne jak dziś profil na Facebooku, a na współdzielonych hostingach królowało PHP w wersji 5.3, która zasłynęła m.in z wprowadzenia instrukcji goto.
Odkąd porzuciłem PHP na rzecz Pythona nie tylko zacząłem tworzyć bardziej pythoniczny kod, ale wzbogaciłem też swój warsztat deweloperski o nowe narzędzia, praktyki i metodologie. Po tych kilku latach patrzę już na PHP przez pryzmat doświadczeń zdobytych w trakcie programowania w innych językach. Nie dawno miała miejsce premiera PHP w wersji 7, która zbiera dobre recenzje i ma rewelacyjne wyniki w benchmarkach. Postanowiłem zapoznać się z tą nową odsłoną – dla mnie zapomnianego już lekko – języka. Pierwsza krok jaki musiałem wykonać to instalacja najnowszej wersji PHP na komputerze.
PHPbrew
Dwie wersje Pythona 2 i 3 zainstalowane równolegle w systemie to standard jednak chcąc mieć możliwość skorzystania z mniej popularnych wersji warto posłużyć się dodatkowym oprogramowaniem takim jak pythonz będącego forkiem nie wspieranego już projektu pythonbrew, który oficjalnie odsyła do pyenv (nie mylić z pyvenv, o którym za chwilę).
PHP ma swój odpowiednik pythonbrew – PHPbrew. Instalacja tego narzędzia jest bezproblemowa i szczegółowo opisana na stronie projektu http://phpbrew.github.io/phpbrew/ więc nie będę jej powielał. Po instalacji PHPbrew możemy przystąpić do instalacji samego PHP w różnych wersjach. Podobnie jak analogiczne narzędzia Pythona – PHPbrew do zainstalowania PHP oraz jego rozszerzeń wymaga także zadbania o zależności. Ja np. spotkałem się z komunikatem configure: error: Please reinstall readline – I cannot find readline.h, który w uprzejmy sposób poinformował mnie o konieczności doinstalowania pakietu deweloperskiego redline
sudo aptitude install libreadline-dev phpbrew install php-5.5.9 |
albo instalacji PHP bez obsługi tego rozszerzenia np w wersji 7.
phpbrew install php-7.0.6 -readline
Przełączenie się na wybraną wersję PHP wymaga wydania prostej komendy w konsoli:
phpbrew use php-7.0.6 |
Od tej chwili możemy rozpocząć pracę z wybraną wersją PHP w konsoli lub też odpalić wbudowany w PHP od wersji 5.4 serwer, a po zakończeniu pracy wrócić do domyślnie zainstalowanej w systemie wersji.
phpbrew off |
virtPHP
Zarówno Python, jak i PHP stale się rozwijają. Wciąż dochodzą mniejsze lub większe usprawnienia, pojawiają się nowe rozszerzenia, biblioteki, moduły. Przełomowe zmiany, takie jak w przypadku wydania siódmej odsłony PHP następują stosunkowo rzadko, a co za tym idzie mechanizmy zarządzania wersjami danego języka w systemie przydają się sporadycznie. O wiele częściej deweloperzy spotykają się z potrzebą konfiguracji środowiska deweloperskiego dobraną specjalnie pod dany projekt.
Python ze swoim wirtualnym środowiskiem virtualenv trochę mnie rozpieścił jako dewelopera. Virtualenv lub też jego funkcjonalny następca – wbudowany w Pythona 3 moduł pyvenv pokazał mi że praca nad różnymi aplikacjami, wymagającymi często odmiennego zestawu bibliotek i konfiguracji może być łatwa i przyjemna.
Instalacja, utworzenie wirtualnego środowiska – w tym wypadku w katalogu projektu – i uruchomienie go poprzez wywołanie skryptu, który ustawia wszelkie zmienne środowiskowe.
sudo apt-get install python-virtualenv cd ~/my_project/ virtualenv .ve source .ve/bin/activate |
Do wersji 3.3 Pythona zalecane jest używanie virtualenv zamiast pyvenv bo dopiero w wersji 3.4 pyvenv ma wbudowanego menagera pakietów pip umożliwiającego łatwą instalację zależności.
pip install django |
Pip umożliwia zrzucenie listy zainstalowanych pakietów do pliku dzięki czemu możliwe jest np. zachowanie konfiguracji wirtualnego środowiska w repozytorium Git
pip freeze > requirements.txt |
i późniejsze jego odtworzenie na innej maszynie.
pip install -r requirements.txt |
Komfort pracy, jaki daje wirtualne środowisko jest nie do przecenienia. W katalogu projektu mamy tylko i wyłącznie pliki projektu. Wszystkie zależności – niezbędne moduły i biblioteki dostarczane przez zewnętrznych developerów trzymane są w odmiennej lokalizacji i jedyne czego potrzebujemy do odtworzenia środowiska niezbędnego do uruchomienia projektu jest plik requirements.txt. Python dał mi zupełnie odmienne doświadczenie w tej kwestii w stosunku do projektów realizowanych w PHP gdzie wszelkie zależności – nie licząc wbudowanych funkcji języka oraz wkompilowanych w niego rozszerzeń – były trzymane, najczęściej w podkatalogu „vendors” i razem z plikami projektu do repozytorium pchane były całe feameworki i inne rozbudowane biblioteki, ewentualnie zaciągane zewnętrzne repozytoria.
Jak wspomniałem przez ostatnie lata nie obcowałem z PHP zbyt intensywnie więc szukałem funkcjonalnego odpowiednika virtualenv. Znalazłem virtPHP. Twórcy virtPHP nie ukrywają, że wzorowali się na swym pythonowym odpowiedniku starając się stworzyć narzędzie równie łatwe a nawet podobne w użyciu. Biblioteka ta nie została jeszcze ustabilizowana. Ostatnia póki co wersja virtPHP 0.5.2-alpha jest dedykowana jedynie na systemy unixopochodne. Trochę martwi brak aktywności developerów przez ostatni rok – nie mniej zachęcam do wypróbowania możliwości wirtualnych środowisk w PHP.
Kiedy już uporamy się z zainstalowaniem virtPHP, możemy przystąpić do utworzenia pierwszego wirtualnego środowiska dla projektu w PHP.
cd ~/my_php_project/ php virtphp.phar create .my-ve source .my-ve/bin/activate |
VirtPHP można łaczyć także z PHPbrew
php virtphp.phar create --php-bin-dir="/home/user/.phpbrew/php/php-5.5.9/bin" .my-ve |
Od tej chwili można instalować biblioteki z repozytoriów PECL i PEAR
pecl install mongo pear install pear.phpunit.de/PHPUnit |
Potencjał tego narzędzia oceniałbym jako wysoki gdyby nie problem z repozytoriami PHP. PECL to repozytorium rozszerzeń PHP napisanymi w języku C. Trudno mi ocenić jego aktualność – zwłaszcza w związku z wydaniem wersji PHP 7. PEAR to biblioteki napisane w PHP tyle, że to staroć nieuaktualniany o nowe wydania bibliotek (np. Symfony Framework). Ponieważ trzymanie zależności w podkatalogu „vendor” stało się powszechnie stosowaną praktyką w świecie PHP popularność zdobył sobie menadżer zależności, który niejako podtrzymał tradycję.
Composer
Menadżer zależności Composer może być uruchomiony w kontekście wirtualnego środowiska virtPHP co niesie ze sobą dodatkowe korzyści, ale równie dobrze może być używany niezależnie. Koncepcyjnie Composerowi najbliżej do npm znanego z Node.js.
Instalacja Composera sprowadza się do ściągnięcia pliku composer.phar do katalogu głównego projektu.
cd ~/my_php_project/ php -r "readfile('https://getcomposer.org/installer');" | php
Zależności są instalowane w podkatalogu vendors.
php composer.phar require monolog/monolog php composer.phar require twig/twig |
natomiast w katalogu głównym tworzone są trzy pliki:
./vendors/autoload.php ./composer.json ./composer.lock |
Plik composer.json, zawiera bieżącą konfigurację zależności.
{ "require": { "monolog/monolog": "^1.19", "twig/twig": "^1.24" } } |
Z kolei w pliku composer.lock – również w formacie json – zapisane są szczegóły na temat zainstalowanych paczek i ich wersji. Tan plik jest bardzo rozbudowany. W repozytorium kodu zalecane jest przechowywanie obu plików, gdyż w przypadku próby odwzorowania konfiguracji na innej maszynie,
php composer.phar install |
polecenie composer install korzysta właśnie z pliku composer.lock i dopiero w przypadku jego braku, z konfiguracji zapisanej w composer.json, ale wtedy nie ma pewności, że dostaniemy dokładnie taki sam wynik.
Deweloperzy PHP są leniwi jak przystało na każdego szanującego się programistę i unikają pisania zbędnego kodu związanego z dołączaniem wymaganych klas i funkcji. Mają do dyspozycji autoloader. Sam byłem zakochany w koncepcie autoloadera dopóki nie zacząłem na full etat kodować w Pythonie. Okazało się, że importy są całkowicie wystarczające a do tego stanowią jeden z aspektów samodokumentującego się kodu. Jeśli unikasz tzw. importowania z gwiazdką, nie potrzebujesz zaawansowanego IDE aby wiedzieć, gdzie co jest i czego możesz się spodziewać w danym module. Pythonowcy nie wiedzą co to autoloader. PHP-owcy nie potrafią bez niego żyć tak więc Composer wspiera również ten mechanizm. Po zainstalowaniu zależności w katalogu vendors generowany jest plik autoload.php, który wystarczy tylko zaimportować.
require __DIR__ . '/vendor/autoload.php'; |
PHP przez wiele lat królowało na współdzielonych hostingach dając PHP dużą przewagę nad innymi językami skryptowymi używanymi w web developmencie. Wystarczyło połączenie FTP do przesłania plików na serwer i początkujący webmaster mógł się cieszyć z działającej strony www. Composer wymaga dostępu do shella tak więc z pełni jego zalet będą cieszyć się osoby pracujące nad serwisami publikowanymi na kontach z dostępem przez ssh np. na VPN-ach albo serwerach dedykowanych.
Docker
Przez ostatnie parę lat mocno rozwinęła się wirtualizacja. Deweloperzy bardzo chętnie sięgają dziś po narzędzia typu Vagrant lub Docker, które umożliwiają utworzenie niemal całkowicie odseparowanego środowiska deweloperskiego, niezależnego od konfiguracji komputera programisty, dającego się przenieść na inną maszynę. W kontenerze można dziś zamknąć zarówno aplikacje pisane w PHP, Pythonie jak i w wielu innych językach programowania więc to nie czyni różnicy między nimi. Docker ma ogromne możliwości, których nie zamierzam tutaj opisywać. Jest to temat na grubą książkę. Chcę jedynie zaprezentować przykład podstawowego użycia kontenera, w którym zamknięte jest PHP w wersji 7 do sprawdzenia możliwości nowej odsłony tego języka.
PHP ma swoje oficjalne obrazy w repozytorium Dockera i w domyślnej konfiguracji, wraz z pełni funkcjonalnym Apachem daje się uruchomić po wydaniu zaledwie dwóch komend .
docker pull php:7.0.6-apache docker run -p 8080:80 -v "~/my_php_project":/var/www/html --name my-php7-container php:7.0.6-apache |
Po wrzuceniu pliku do katalogu my_php_project
echo '<?php phpinfo();' > ~/my_php_project/info.php |
I wybranie w przeglądarce adresu
localhost:8080/info.php |
możemy obejrzeć sobie konfigurację PHP 7.
Naturalnie trzeba mieś już zainstalowanego i skonfigurowanego Dockera. Warto ten wysiłek podjąć i rozpocząć przygodę z kontenerami. Już najprostsze przypadki użycia są przydatne i wcale nie trzeba pracować nad wielkim projektem o rozbudowanej architekturze aby docenić zalety konteneryzacji. Choć rozwiązanie to nie jest bez wad – obrazy Dockera sporo ważą, a uruchomione instancje zabierają sporo zasobów będąc bądź co bądź pełnoprawnymi systemami – w zamian dostajemy odseparowane pudełko, w którym możemy zamknąć np. wersję 2.4 blendera, która jako ostatnia obsługuje skrypty pisane w Pythonie 2.
Każdy człowiek ucząc się nowej rzeczy czerpie ze swoich dotychczasowych doświadczeń. Programiści rozpoczynający pisanie oprogramowania w nowym dla nich języku starają się zorganizować swój warsztat pracy w sposób, który jest im znany. Udaje się to mniej lub bardziej bo każdy język programowania ma swoją specyfikę uwarunkowaną przyjętymi założeniami, filozofią, techniczną implementacją i wypracowaną praktyką. To co jest przyjęte za standard w jednej technologii w innej może być uważane za niemile widziane. Sztuką jest dostosować się i nauczyć poprawnie każystać z dedykowanych narzędzi. Zarówno PHP, jak i Python umożliwiają organizację pracy dewelopera w sposób umożliwiający łatwe przełączanie się pomiędzy różnymi projektami posiadającymi swoją konfigurację i zależności. Choć robią to w nieco odmienny sposób w mojej ocenie wygoda rozwiązań stoi na porównywalnym poziomie.