Friday, May 27, 2011

Continous integration i Python?

Czy ktoś widział może kiedyś budowanie projektu pisanego w Pythonie?
Może nie jestem czegoś świadom, albo myślę zbyt szablonowo ale: continous-integration jest dobrze zdefiniowane dla projektów, które trzeba kompilować. Wiadomo. Developer nie kompiluje kodu sam. System CI sam sprawdza za niego czy kod pozytywnie przechodzi etap kompilacji i wysyła powiadomienia.

Ale jak odnieść się do tego w świetle Pythona. No dobra, wyciągamy kod źródłowy z repozytorium - i co? Przecież go nie skompiluję. Wszystko, na stać moją wyobraźnię na dzień dzisiejszy, to hmm... scan pylint, pychecker, pep8, odpalanie metody .compile() na każdym module? Jeżeli już zdecydujemy się na skany: to jak zachować się w przypadku jakiś komunikatów. Kod nie musi być źle napisany, zresztą zakładamy, że przeszedł review, ale wtedy co? Sfailować build tylko dlatego, że kod Pythona programisty nie odpowiada pylint. To niczego nie udowadnia.

Piszę ten post w związku z sytuacją jaka miała miejsce kilka dni temu. Rozumiem, żeby w trakcie budowania projektu Pythonowego odpalać testy w ramach. W moim przypadku nie mam nawet czasu aby je pisać więc nie ma co odpalać. Przyjmuję argument, że to co wychodzi na produkcję powinno być numerowane. To bardzo pomocne i użyteczne. Jednak w Python 2 wszystko co sobie wyobrażam to otagowywanie kolejnych wersji w repozytorium. Podmienianie egga, który wywala serwer Apache ponieważ przestają mu się zgadzać sumy kontrolne - to jakaś porażka. To nie wiem co innego mógłbym robić? Dodawać komentarz z numerem buildu w jakimś umówionym pliku? Dodam jeszcze, że to aplikacja internetowa pisana w Django.

Jeżeli ktoś jest w temacie to jestem bardzo zainteresowany wymianą doświadczeń w tym temacie.

Webdevelopment i unit testy

Kilka tygodni temu zacząłem developować webowy frontend dla projektu gitolite o nazwie glboard. Gitolite to warstwa abstrakcji pozwalająca na kontrolę dostępu do repozytoriów systemu git podczas dostępu do serwera przez ssh.

Glboard od samego początku pisany był z myślą o testach, dlatego wraz z kodem publikowane były unit testy do udowadniania poprawności metod, klasy, która stanowi trzon funkcjonalności.
Podczas oglądania prelekcji "State of Pylons/Turbo Gears2/repoze.bfg", moją uwagę przykuły zarzuty postawione unit testom w web-developmencie.

W tym okresie spędziłem sporo czasu, w glboard, na poprawianiu unit testów. Jeżeli padłem ofiarą zbyt wczesnego testowania - to jaki sens ma Test Driven Development?
Podczas zmieniania głównej klasy, obsługującej operacje na repozytorium gita, uzyskałem pewien ciekawy efekt - witryna działała i mogłem dzięki niej wykonać wszystkie operacje - natomiast testy failowały. Wszystkie. Powód był prosty: klasa przyjmowała teraz nowy argument w metodzie __init__.

Wspomniana prelekcja uświadomiła mi jedną rzecz. Jeżeli nie wystawiasz czegoś na zewnątrz, nie wystawiasz API lub biblioteki, nie będziesz zobligowany do zachowywania wstecznej kompatybilności z jakimś stworzonym przez siebie interfejsem, które kiedyś udostępniłeś, tylko dlatego, że używają go klienci - nie używaj unit testów. Pisanie unit testów do elementów, które zostają w twoim projekcie i nie wychodzą w żaden sposób na zewnątrz - to strzelanie sobie w stopę.

Moim zdaniem pisząc aplikację we frameworku webowym to co powinno się testować - to działanie przez przeglądarce. Testy funkcjonalne wydają się wystarczające. Może są troszkę bardziej kosztowne niż unit testy, ale w gruncie rzeczy, dobrze napisane, testują dokładnie to co powinny. Nie skupiają się na API konkretnej klasy, funkcji, metody, ale na tym czy witryna działa - nie ważne jest jak.

Odnosząc się do narzekań na Selenium i długiego czasu trwania testów w nim napisanych: myślę, że możemy spodziewać się rewolucji w świecie testów web-aplikacji dzięki PhantomJS. Nie znam jego wydajności, ale funkcjonalność jest w tej dziedzinie bardzo obiecująca i daje znacznie więcej możliwości niż zwykłe funkcyjne testy. Równocześnie nie używa całego niepotrzebne osprzętu jakie ładuje przeglądarka.

Wszystko co w tej chwili mi pozostaje to usunąć unit testy z glboard i napisać functional testy :)