Joel on Software

Joel on Software   Joel o programowaniu

 

Inne artykuły serwisu "Joel on Software" po polsku

Inne artykuły serwisu "Joel on Software" po angielsku

Napisz do autora (tylko po angielsku)

 

Pożytki z codziennego generowania wersji


Joel Spolsky
Przełożył Andrzej Kocoń
Korekta Andrzej Swędrzyński
27 stycznia 2001

Pierwszy komputer IBM-PC trafił do Izraela w 1982 roku. Chociaż miał być dostarczony do naszego domu, nie mogliśmy się doczekać i sami pojechaliśmy odebrać go z portowego magazynu. Do dziś nie wiem, w jaki sposób udało mi się namówić ojca na zamówienie tak w pełni wyposażonej wersji. W skład zestawu wchodziły dwa napędy dyskietek, 128 kilobajtów pamięci, dwie drukarki - igłowa do szybkiego drukowania szkiców i głowicowa firmy Brother, hałasująca głośniej niż karabin maszynowy.
Myślę, że mieliśmy prawie wszystkie dostępne akcesoria: PC-DOS 1.0, dokumentację techniczną wartą 75 dolarów z kompletnym kodem źródłowym BIOSu, Macro Assembler i niezwykły monitor monochromatyczny IBM, z 80-ma kolumnami i... małymi literami! Całość kosztowała około 10.000 dolarów, wliczając srogie opłaty importowe. Czysta ekstrawagancja!

„Wszyscy” wówczas wiedzieli, że BASIC to język dla dzieci, który wymuszał pisanie pogmatwanego kodu i przeobrażał umysł w ser camembert. Wydaliśmy więc dodatkowo 600 dolarów na Pascal IBM, zajmujący trzy dyskietki. Na pierwszej i drugiej znajdowały się dwa przebiegi kompilatora, a na trzeciej był linker. Napisałem prosty program typu „hello, world” i skompilowałem go. Łączny czas jaki upłynął: 8 minut.

Hmm. To dość długo. Napisałem skrypt żeby zautomatyzować ten proces. Zszedłem do 7,5 minuty. Lepiej. Kiedy jednak próbowałem pisać dłuższe programy, takie jak moja przebojowa wersja Otella, z którą zawsze przegrywam, większość czasu spędzałem w oczekiwaniu na wyniki kompilacji. „Tak, tak”, rzekł mi pewien profesjonalny programista, „zwykliśmy trzymać w biurze sprzęt gimnastyczny i ćwiczyć podczas kompilacji. Po kilku miesiącach programowania miałem mięśnie zabójcy”.

Pewnego dnia w Danii ukazał się cudowny program, Compas Pascal, nota bene kupiony później przez Philippa Kahna i przemianowany na  Borland Turbo Pascal. To był szok. Turbo Pascal potrafił wszystko to, co Pascal IBM, ale mieścił się w 33 kilobajtach pamięci, wliczając w  to edytor tekstowy. Jeszcze bardziej niezwykły był fakt, że mały program można było skompilować w niecałą sekundę. Nie byłbym bardziej zdumiony, gdyby nikomu nie znana firma stworzyła nagle podróbkę buicka LeSabre, zdolnego rozwinąć 1.000.000 mil na godzinę i objechać kulę ziemską zużywając przy tym tak niewiele paliwa, że jego wypicie nie zaszkodziłoby nawet mrówce.

Nagle stałem się o wiele bardziej wydajny.

To właśnie wtedy poznałem pojęcie cyklu Czytaj-Wartościuj-Drukuj (CWD), który opisuje cały sposób działania interpretera lispu: czyta on wyrażenie, oblicza jego wartość i drukuje wynik. Poniżej pokazano przykład pętli CWD: interpreter lispu czyta, wartościuje i drukuje wynik tego, co napisałem.

REP Loop 

Podczas tworzenia programu mamy do czynienia z wersją makro pętli CWD - pętlą Redaguj-Kompiluj-Testuj. Poprawiamy program, kompilujemy go i sprawdzamy, jak działa.

Istotne jest tutaj to, że aby stworzyć program, należy wykonać ten cykl wiele razy. Dlatego im krócej trwa pętla Redaguj-Kompiluj-Testuj, tym większa jest wydajność programisty, aż do naturalnej granicy kompilacji natychmiastowej. Oto formalny, naukowy wręcz powód, dla którego programiści chcą mieć jak najszybsze maszyny, a twórcy kompilatorów zrobią wszystko, co tylko możliwe, aby skrócić cykl Redaguj-Kompiluj-Testuj. W środowisku Visual Basic kompilacja jest bardzo szybka dzięki analizie składniowej każdego wiersza jeszcze w trakcie jego pisania. W Visual C++ efekt ten uzyskuje się poprzez zastosowanie przyrostowych kompilacji i linkowania oraz prekompilowanych plików nagłówkowych.

Ta sama pętla w zwielokrotnionej niczym fraktal postaci pojawia się, kiedy tylko zaczynamy pracę w większym zespole, składającym się z wielu programistów i testerów. Tester znajduje błąd w programie i sporządza zgłoszenie. Programista poprawia defekt. Ile czasu upływa, nim tester otrzyma poprawioną wersję programu? W niektórych firmach ten cykl Reklamuj-Popraw-Sprawdź zajmuje nawet kilka tygodni, a to z kolei oznacza, że całe przedsięwzięcie jest nieproduktywne. Aby proces wytwarzania oprogramowania przebiegał sprawnie, należy skupić się skupić na skróceniu pętli Reklamuj-Popraw-Sprawdź.

Jednym z dobrych sposobów jest codzienne generowanie wersji, czyli automatyczne, codzienne i kompletne generowanie produktu na podstawie całego drzewa kodu źródłowego.

Automatyczne - dzięki ustawieniu stałej pory kompilacji kodu każdego dnia przy użyciu usługi cron (UNIX) lub dyspozytora (Windows).

Codzienne - lub nawet bardziej częste. Kuszące byłoby generowanie ciągłe, ale może być ono niewykonalne ze względu na problemy z synchronizacją kodu źródłowego, o czym za chwilę.

Kompletne - możliwe, że twój kod ma wiele wersji. Wersje językowe, wersje zależne od systemu operacyjnego lub od odbiorcy. Proces generowania powinien obejmować je wszystkie. Powinien też kompilować każdy plik źródłowy, bez polegania na być może niedoskonałej możliwości kompilacji przyrostowej.
A oto niektóre spośród wielu korzyści, jakie daje codzienne generowanie wersji:

  1. Testerzy szybko otrzymują nową wersję po poprawieniu błędu. Dzięki temu mogą szybko sprawdzić, czy błąd został rzeczywiście usunięty.
  2. Programiści mogą być spokojni, że dokonane przez nich zmiany nie spowodują problemów przy generowaniu jakiejkolwiek spośród 1024 wersji produktu. I to bez potrzeby posiadania na biurku komputera z systemem OS/2 w celach testowych.
  3. Programiści wprowadzają swoje zmiany do repozytorium tuż przed codziennym generowaniem wersji. Dzięki temu wiedzą, że nie posłali innych w maliny przez załamanie całego procesu generowania. Nie zrobili czegoś, co uniemożliwia kompilację każdemu członkowi zespołu. Taki stan to odpowiednik błękitnego ekranu śmierci dla całego zespołu. Często zdarza się on, kiedy programista zapomniał wprowadzić do repozytorium nowo utworzony plik. Na jego maszynie generowanie przebiega poprawnie, lecz kiedy tylko ktoś zsynchronizuje swoją kopię z repozytorium, otrzyma błąd kompilacji i nie będzie w stanie dalej pracować.
  4. Zewnętrzne grupy, które korzystają z niedojrzałego produktu, takie jak marketing, odbiorcy wersji beta itp., mogą w każdej chwili otrzymać względnie stabilną wersję i używać ją przez pewien czas.
  5. Warto też przechowywać wyniki codziennego generowania programu. W przypadku wykrycia nowego, naprawdę dziwnego błędu, można przeszukać binarnie archiwum w celu wyśledzenia momentu, od którego błąd zaczął się pojawiać. W połączeniu z dobrym systemem kontroli wersji, łatwo można ustalić, która zmiana spowodowała problem. Podobnie kiedy tester zgłasza rzekomo poprawiony wcześniej błąd, wskazuje także wersję programu, której ten problem dotyczy. Dzięki temu programista może sprawdzić, kiedy wprowadził poprawkę i ustalić, czy problem rzeczywiście został usunięty.
Jak się zabrać do codziennego generowania wersji? Po pierwsze potrzebny jest serwer - prawdopodobnie najszybsza maszyna, na jaką można sobie pozwolić. Po drugie skrypt, który będzie pobierał kompletną kopię bieżącego kodu źródłowego z repozytorium (w projekcie jest używany przecież system zarządzania wersjami, prawda?), a następnie wygeneruje od zera wszystkie wersje końcowego produktu. Jeżeli przewidywany jest program instalacyjny, on także powinien być generowany. Słowem - wszystko, co w przyszłości otrzyma klient, musi być uwzględnione w procesie codziennego generowania. Wyniki kompilacji z każdego dnia należy umieścić w osobnym katalogu, zakodowanym według daty. Skrypt powinien być uruchamiany każdego dnia o ustalonej porze.
  • Wyjątkowo ważne jest, aby wszystko, co składa się na końcowy produkt, było generowane przez skrypt. Od pobrania źródeł, poprzez umieszczenie odpowiednich plików we właściwym miejscu serwisu internetowego, przeznaczonego do publicznego pobierania (mimo, że w fazie tworzenia produktu będzie to oczywiście serwer testowy). To jedyny sposób, aby zapewnić, że w procesie generowania nie ma nic, co byłoby „udokumentowane” tylko w czyjejś głowie. Nigdy nie znajdziemy się w sytuacji, w której nie można wypuścić produktu, bo tylko Shaniqua wie, jak utworzyć program instalacyjny, a właśnie potrącił ją autobus. W zespole Juno jedyne, co trzeba było wiedzieć, aby utworzyć od zera pełną wersję programu, to gdzie znajduje się serwer i jak kliknąć ikonę codziennego generowania. 
  • Aby zachować zdrowe zmysły, nie należy nic poprawiać na serwerze, służącym do generowania wersji. I to nawet jeśli we właśnie przygotowywanym do publikacji produkcie jest jeszcze tylko jeden mały błąd. Powinno być żelazną zasadą publikowanie tylko takiego produktu, który powstał w wyniku pełnego i przebiegającego bez żadnych błędów procesu codziennego generowania wersji na podstawie kompletnej kopii kodu.
  • Należy ustawić najwyższy poziom ostrzegania o błędach przez kompilatory (-W4 w świecie Microsoftu, -Wall na terytorium gcc) i wymusić zatrzymywanie się po napotkaniu nawet najbardziej błahego ostrzeżenia.
  • Jeśli proces codziennego generowania wersji zatnie się, może zostać zatrzymana praca całego zespołu. Należy wówczas zostawić wszystko inne i tak długo ponawiać proces, aż się powiedzie. Niekiedy powstaje w ten sposób kilka dziennych wersji produktu.
  • Skrypt codziennego generowania wersji powinien informować cały zespół o błędach za pośrednictwem poczty elektronicznej. Nie jest trudno przejrzeć logi systemowe programem grep w poszukiwaniu linii zawierających „error” czy „warning” i dołączyć te informacje do poczty. Skrypt powinien również dodać informację o wynikach każdego procesu do dostępnej dla wszystkich strony HTML, aby programiści i testerzy mogli sprawdzić, które próby zakończyły się powodzeniem.
  • W zespole Microsoft Excel stosowaliśmy z powodzeniem pewną zasadę. Polegała ona na tym, że programista, który spowodował błędy w procesie codziennego generowania wersji, stawał się od tego momentu odpowiedzialny za czuwanie nad tym procesem, przejmując tę rolę od poprzedniego pechowego kolegi. Reguła ta była nie tylko niezłym bodźcem do tego, aby dbać o poprawność procesu, ale dzięki niej każdy miał okazję pełnić rolę jego opiekuna i  poznać jego szczegóły.
  • W przypadku zespołów pracujących w jednej strefie czasowej, dobrą porą na generowanie wersji jest przerwa obiadowa. Wszyscy wprowadzają swoje poprawki do repozytorium tuż przed wyjściem, generowanie odbywa się w trakcie posiłku, a po powrocie wszyscy są na miejscu na wypadek, gdyby coś się nie powiodło. Gdy tylko proces zakończy się poprawnie, każdy może pobrać najświeższą wersję kodu bez obawy, że czyjś błąd uniemożliwi mu dalszą pracę.
  • Jeśli zespół pracuje w dwóch strefach czasowych, pora generowania wersji powinna zostać wybrana tak, aby grupa w jednej strefie nie blokowała grupy w drugiej. W zespole Juno programiści z Nowego Jorku wprowadzali poprawki o 19-tej czasu nowojorskiego i szli do domu. Gdyby stało się coś złego, zespół z Hyderabadu w Indiach, zbierający się około 20-tej czasu nowojorskiego, przez cały dzień nie byłby w stanie nic zrobić. Zaczęliśmy więc praktykować dwukrotne generowanie wersji w  ciągu dnia, na około godzinę przed końcem pracy każdego zespołu. To całkowicie rozwiązało problem.
Dalsza lektura:
  • Codzienne generowanie wersji jest na tyle istotne, że stanowi jeden z 12 kroków ku lepszym programom.
  • Wiele interesujących rzeczy na temat (cotygodniowego) generowania wersji przez zespół Windows NT można znaleźć w książce G. Pascala Zachary'ego pt. Showstopper
  • Tutaj można się dowiedzieć, co na temat codziennego generowania wersji pisze Steve McConnell.
  • Windows NT Build Lab.


Oryginał ukazał się w wersji angielskiej pod nazwą Daily Builds Are Your Friend  

Joel Spolsky jest założycielem Fog Creek Software, małej firmy programistycznej w Nowym Jorku. Ukończył Uniwersytet Yale i  pracował jako programista i menedżer w Microsofcie, Viacom i Juno.


Zawartość tych stron wyraża opinie jednej osoby.
Cała zawartość prawnie chroniona. Copyright ©1999-2005 by Joel Spolsky. Wszelkie prawa zastrzeżone.

FogBUGZ | CityDesk | Fog Creek Software | Joel Spolsky