plik


ÿþIDZ DO IDZ DO PRZYK£ADOWY ROZDZIA£ PRZYK£ADOWY ROZDZIA£ Perl. Najlepsze SPIS TRERCI SPIS TRERCI rozwi¹zania KATALOG KSI¥¯EK KATALOG KSI¥¯EK Autor: Damian Conway T³umaczenie: Grzegorz Werner KATALOG ONLINE KATALOG ONLINE ISBN: 83-246-0127-9 Tytu³ orygina³u: Perl Best Practices ZAMÓW DRUKOWANY KATALOG ZAMÓW DRUKOWANY KATALOG Format: B5, stron: 488 TWÓJ KOSZYK TWÓJ KOSZYK Zastosuj w pracy sprawdzone style i standardy kodowania DODAJ DO KOSZYKA DODAJ DO KOSZYKA " Wypracuj czytelne konwencje nazewnicze " Stwórz odpowiedni¹ dokumentacjê kodu " Przetestuj kod i usuñ b³êdy CENNIK I INFORMACJE CENNIK I INFORMACJE Indywidualne style kodowania, obejmuj¹ce m.in. nazywanie zmiennych, wpisywanie komentarzy i stosowanie okreSlonych konstrukcji jêzykowych, pomagaj¹ ZAMÓW INFORMACJE ZAMÓW INFORMACJE O NOWORCIACH w rozbudowywaniu programów i usuwaniu z nich b³êdów. Jednak taka metoda pracy, O NOWORCIACH charakterystyczna dla doSwiadczonych programistów, nie zawsze jest najlepsza. Dodatkowo w³asny styl staje siê ogromn¹ przeszkod¹ w przypadku pracy zespo³owej  ZAMÓW CENNIK ZAMÓW CENNIK tu powinno siê raczej stosowaæ spójne standardy, dziêki którym kod bêdzie klarowny, niezawodny, wydajny, ³atwy w konserwacji i zwiêz³y. CZYTELNIA CZYTELNIA W ksi¹¿ce  Perl. Najlepsze rozwi¹zania znajdziesz ponad 250 porad programisty z 22-letni¹ praktyk¹, dotycz¹cych pisania kodu xród³owego w Perlu. Wskazówki te FRAGMENTY KSI¥¯EK ONLINE FRAGMENTY KSI¥¯EK ONLINE obejmuj¹ uk³ad kodu, konwencje nazewnicze, dobór struktur danych i konstrukcji steruj¹cych, dekompozycjê programu, projekt i implementacjê interfejsu, modularnoSæ, obiektowoSæ, obs³ugê b³êdów, testowanie i debugowanie. Autor ksi¹¿ki nie stara siê udowodniæ, ¿e preferowane przez niego rozwi¹zania s¹ jedyne i najlepsze  przedstawia jedynie sprawdzone techniki, u¿ywane przez programistów z ca³ego Swiata. " Formatowanie kodu xród³owego " Metody okreSlania nazw zmiennych i obiektów " Korzystanie ze struktur steruj¹cych " Przygotowywanie dokumentacji " Implementacja operacji wejScia i wyjScia " Stosowanie wyra¿eñ regularnych " Obs³uga wyj¹tków Wydawnictwo Helion ul. Chopina 6 " Podzia³ kodu na modu³y 44-100 Gliwice " Wykrywanie i usuwanie b³êdów z kodu tel. (32)230-98-63 Wykorzystaj znajduj¹ce siê w tej ksi¹¿ce wskazówki  stwórz najlepszy kod e-mail: helion@helion.pl Spis tre[ci Przedmowa ...................................................................................................................13 1. Zalecane praktyki .........................................................................................................21 Trzy cele 22 Niniejsza ksi|ka 24 Zmiana nawyków 26 2. UkBad kodu ................................................................................................................... 27 Stosowanie nawiasów 28 SBowa kluczowe 30 Procedury i zmienne 31 Funkcje wbudowane 31 Klucze i indeksy 32 Operatory 33 Zredniki 34 Przecinki 35 DBugo[ wierszy 36 Wcicia 37 Znaki tabulacji 38 Bloki 39 Akapity 40 Instrukcje else 41 Wyrównanie pionowe 42 Dzielenie dBugich wierszy 44 Wyra|enia nieterminalne 45 Dzielenie wyra|eD wedBug priorytetu 46 Przypisania 46 Operator trójkowy 47 Listy 48 Zautomatyzowane formatowanie 49 5 3. Konwencje nazewnicze ...............................................................................................51 Identyfikatory 52 Warto[ci logiczne 55 Zmienne referencyjne 56 Tablice zwykBe i asocjacyjne 57 Znaki podkre[lenia 58 Wielko[ liter 58 Skróty 60 Niejednoznaczne skróty 61 Niejednoznaczne nazwy 61 Procedury narzdziowe 62 4. Warto[ci i wyra|enia .................................................................................................. 65 Ograniczniki BaDcuchów 65 AaDcuchy puste 67 AaDcuchy jednoznakowe 67 Znaki specjalne 68 StaBe 69 Pocztkowe zera 72 DBugie liczby 73 AaDcuchy wielowierszowe 73 Dokumenty here 74 Wcicia w dokumentach here 74 Terminatory dokumentów here 75 Przytaczanie terminatorów 77 Nagie sBowa 77 Grube przecinki 78 Cienkie przecinki 80 Operatory o niskim priorytecie 81 Listy 82 Przynale|no[ do listy 83 5. Zmienne ....................................................................................................................... 85 Zmienne leksykalne 85 Zmienne pakietowe 87 Lokalizowanie 89 Inicjalizacja 89 Zmienne interpunkcyjne 90 Lokalizowanie zmiennych interpunkcyjnych 92 Zmienne dopasowania 93 Dolar-znak podkre[lenia 96 6 | Spis tre[ci Indeksy tablic 98 Wycinki 99 UkBad wycinków 100 Wyodrbnianie list z wycinków 101 6. Struktury sterujce .....................................................................................................103 Bloki if 103 Selektory przyrostkowe 104 Inne modyfikatory przyrostkowe 105 Negatywne instrukcje sterujce 106 Ptle w stylu C 109 Niepotrzebne indeksowanie 110 Potrzebne indeksowanie 112 Zmienne iteracyjne 114 Nieleksykalne iteratory ptli 116 Generowanie list 118 Wybieranie elementów z listy 119 Transformacja listy 120 ZBo|one odwzorowania 121 Efekty uboczne przetwarzania list 122 Wielokrotny wybór 124 Wyszukiwanie warto[ci 125 Operatory trójkowe w ukBadzie tabelarycznym 128 Ptle do...while 129 Kodowanie liniowe 131 Rozproszone sterowanie 132 Powtarzanie przebiegu ptli 134 Etykiety ptli 135 7. Dokumentacja ............................................................................................................139 Typy dokumentacji 139 Szablony 140 Rozszerzone szablony 144 Miejsce 145 CigBo[ 145 PoBo|enie 146 Dokumentacja techniczna 146 Komentarze 147 Dokumentacja algorytmiczna 148 Dokumentacja wyja[niajca 149 Dokumentacja defensywna 149 Spis tre[ci | 7 Dokumentacja sygnalizujca 150 Dokumentacja dygresyjna 150 Korekta 152 8. Funkcje wbudowane ..................................................................................................153 Sortowanie 153 Odwracanie list 156 Odwracanie skalarów 157 Dane z polami o staBej szeroko[ci 157 Dane rozdzielone separatorami 160 Dane z polami o zmiennej szeroko[ci 161 Ewaluacje BaDcuchów 163 Automatyzacja sortowania 166 PodBaDcuchy 167 Warto[ci tablic asocjacyjnych 168 Rozwijanie nazw plików 168 Wstrzymywanie programu 169 Funkcje map i grep 170 Funkcje narzdziowe 171 9. Procedury ....................................................................................................................177 SkBadnia wywoBaD 177 Homonimy 179 Listy argumentów 180 Nazwane argumenty 183 Brakujce argumenty 184 Domy[lnie warto[ci argumentów 185 Skalarne warto[ci zwrotne 187 Kontekstowe warto[ci zwrotne 188 Wielokontekstowe warto[ci zwrotne 191 Prototypy 194 Jawne powroty 196 Zwracanie bBdów 198 10. Wej[cie-wyj[cie ..........................................................................................................201 Uchwyty plików 201 Po[rednie uchwyty plików 203 Lokalizowanie uchwytów plików 204 Eleganckie otwieranie 205 Sprawdzanie bBdów 207 Porzdkowanie 207 Ptle wej[ciowe 209 8 | Spis tre[ci Wczytywanie danych wiersz po wierszu 210 Proste  zasysanie 211 Zaawansowane  zasysanie 212 Standardowe wej[cie 213 Pisanie w uchwytach plików 214 Proste monitowanie 214 Interaktywno[ 215 Zaawansowane monitowanie 217 Wskazniki postpu 218 Automatyczne wskazniki postpu 220 Automatyczne opró|nianie bufora 221 11. Referencje .................................................................................................................. 223 WyBuskiwanie 223 Referencje w nawiasach klamrowych 224 Referencje symboliczne 226 Referencje cykliczne 227 12. Wyra|enia regularne .................................................................................................231 Rozszerzone formatowanie 232 Granice wierszy 233 Granice BaDcuchów 234 Koniec BaDcucha 235 Dopasowywanie dowolnych znaków 236 Opcje dla leniwych 237 Nawiasy klamrowe jako ograniczniki w wyra|eniach regularnych 237 Inne ograniczniki 240 Metaznaki 241 Nazwy znaków 242 WBa[ciwo[ci 242 Odstpy 243 Nieograniczone powtórzenia 244 Nawiasy przechwytujce 246 Przechwycone warto[ci 246 Zmienne przechwytujce 247 Dopasowywanie po kawaBku 250 Tabelaryczne wyra|enia regularne 252 Konstruowanie wyra|eD regularnych 254 Wyra|enia regularne z puszki 255 Alternacje 257 Wyodrbnianie wspólnej cz[ci alternacji 258 Wycofywanie 260 Porównywanie BaDcuchów 262 Spis tre[ci | 9 13. ObsBuga bBdów ........................................................................................................ 265 Wyjtki 266 BBdy funkcji wbudowanych 269 BBdy kontekstowe 270 BBdy systemowe 271 BBdy naprawialne 272 ZgBaszanie bBdów 273 Komunikaty o bBdach 275 Dokumentowanie bBdów 276 Obiekty wyjtków 277 Ulotne komunikaty o bBdach 280 Hierarchie wyjtków 280 Przetwarzanie wyjtków 281 Klasy wyjtków 282 Odpakowywanie wyjtków 285 14. Wiersz poleceD .......................................................................................................... 287 Struktura wiersza polecenia 288 Konwencje skBadni wiersza polecenia 289 Metaopcje 291 Argumenty in situ 292 Przetwarzanie wiersza polecenia 293 Spójno[ interfejsu 298 Spójno[ aplikacji 301 15. Obiekty ...................................................................................................................... 305 U|ywanie technik obiektowych 306 Kryteria 306 Pseudotablice 308 Ograniczone tablice asocjacyjne 308 Hermetyzacja 309 Konstruktory 317 Klonowanie 317 Destruktory 320 Metody 321 Akcesory 323 Akcesory l-warto[ciowe 328 Po[redni dostp do obiektów 330 Interfejsy klas 333 Przeci|anie operatorów 335 PrzeksztaBcenia typów 337 10 | Spis tre[ci 16. Hierarchie klas ........................................................................................................... 339 Dziedziczenie 340 Obiekty 340  BBogosBawienie obiektów 344 Argumenty konstruktora 346 Inicjalizacja klasy bazowej 349 Konstrukcja i destrukcja 353 Automatyzowanie hierarchii klas 360 Niszczenie atrybutów 360 Budowanie atrybutów 363 Konwersje typów 364 Metody kumulacyjne 365 Automatyczne wczytywanie 368 17. ModuBy ....................................................................................................................... 373 Interfejsy 373 Refaktoryzacja 376 Numery wersji 379 Wymagania dotyczce wersji 380 Eksportowanie 382 Eksportowanie deklaratywne 383 Zmienne interfejsu 385 Tworzenie moduBów 389 Biblioteka standardowa 390 CPAN 391 18. Testowanie i debugowanie ...................................................................................... 393 Przypadki testowe 393 Testowanie modularne 394 Pakiety testów 397 BBdy 398 Co testowa? 398 Debugowanie i testowanie 399 Ograniczenia 401 Ostrze|enia 403 Poprawno[ 404 Omijanie ograniczeD 405 Debuger 407 Debugowanie rczne 408 Debugowanie póBautomatyczne 410 Spis tre[ci | 11 19. Zagadnienia ró|ne .................................................................................................... 413 Kontrola wersji 413 Inne jzyki 414 Pliki konfiguracyjne 416 Formaty 419 Wizy 422 Spryt 423 Ukryty spryt 424 Mierzenie wydajno[ci 426 Pami 429 Buforowanie 429 Memoizacja 431 Optymalizacja przez buforowanie 432 Profilowanie 433 Zapluskwianie 435 A Perl: kluczowe praktyki ............................................................................................. 437 B Perl: zalecane praktyki .............................................................................................. 441 C Konfiguracje edytorów .............................................................................................453 D Zalecane moduBy i narzdzia.....................................................................................459 E Bibliografia.................................................................................................................465 Skorowidz .................................................................................................................. 467 12 | Spis tre[ci ROZDZIAA 2. UkBad kodu Wikszo[ programów nale|aBoby wci o sze[ stóp w dóB... i przysypa ziemi.  Blair P. Houghton Formatowanie. Wcicia. Styl. UkBad kodu. Bez wzgldu na nazw, jest to jedna z najbardziej kontrowersyjnych dziedzin dyscypliny programistycznej. O ukBad kodu stoczono wicej (i bar- dziej krwawych) wojen ni| o jakikolwiek inny aspekt kodowania. Jaka jest zatem zalecana praktyka? Czy nale|y posBugiwa si klasycznym stylem Kernighana i Ritchie ego (K&R)? A mo|e zdecydowa si na formatowanie BSD? Wybra ukBad zalecany przez projekt GNU? A mo|e wytyczne kodowania Slashcode? Oczywi[cie, |e nie! Ka|dy wie, |e [tutaj wstawi swój osobisty styl kodowania] jest Jedynym SBusz- nym Stylem, jedynym rozsdnym wyborem, u[wiconym przez [tutaj wstawi nazw ulubionego Bóstwa Programistycznego] od Niepamitnych Czasów! Ka|de inne rozwizanie jest absurdalne i heretyckie, a zatem ewidentnie jest DzieBem Ciemno[ci!!! I wBa[nie na tym polega problem. Kiedy przychodzi wybra ukBad kodu, trudno zdecydowa, gdzie koDcz si racjonalne uzasadnienia, a zaczynaj zracjonalizowane nawyki. Przyjcie spójnych metod formatowania kodu i stosowanie ich we wszystkich programach ma fundamentalne znaczenie dla realizacji zalecanych praktyk programistycznych. Dobry ukBad zwiksza czytelno[ kodu, pomaga wykrywa bBdy i sprawia, |e struktura programu jest bar- dziej zrozumiaBa. UkBad kodu jest wa|ny. Korzy[ci te zapewnia jednak wikszo[ stylów kodowania  w tym cztery wspomniane wcze- [niej. Cho wic ukBad kodu jest bardzo wa|ny, to konkretny ukBad... jest zupeBnie nieistotny! Trzeba tylko przyj pojedynczy, spójny styl, który odpowiada caBemu zespoBowi, a nastpnie stosowa go konsekwentnie we wszystkich programach. Zamieszczone ni|ej wskazówki dotyczce ukBadu kodu zostaBy starannie i [wiadomie wybrane spo[ród wielu mo|liwo[ci, aby skonstruowa styl, który jest spójny i zwizBy, zwiksza czy- telno[ kodu, uBatwia wykrywanie pomyBek oraz mo|e by z powodzeniem stosowany przez ró|nych programistów pracujcych w wielu odmiennych [rodowiskach. 27 Nie wtpi, |e niektóre z tych wskazówek wywoBaj sprzeciw. Prawdopodobnie gwaBtowny. Ka|dy czytelnik musi zastanowi si, czy argumenty za odrzuceniem danej wskazówki prze- wa|aj nad argumentami za jej przyjciem. Je[li tak, nieprzestrzeganie tej reguBy nie bdzie miaBo znaczenia. Stosowanie nawiasów Stosuj nawiasy klamrowe i okrgBe w stylu K&R. Podczas tworzenia bloków kodu nale|y stosowa nawiasy w stylu K&R1, tzn. umieszcza otwie- rajcy nawias klamrowy na koDcu konstrukcji, która steruje blokiem. Zawarto[ bloku nale|y rozpocz od nastpnego wiersza, wcinajc j o jeden poziom. Wreszcie zamykajcy nawias klamrowy nale|y umie[ci w oddzielnym wierszu, na tym samym poziomie wcicia, co kon- strukcja sterujca. Podobnie podczas pisania w nawiasie listy, która rozciga si na wiele wierszy, nale|y umie- [ci otwierajcy nawias okrgBy na koDcu wyra|enia sterujcego; elementy listy umie[ci w ko- lejnych wierszach, wcite o jeden poziom; zamykajcy nawias okrgBy umie[ci w oddzielnym wierszu, zmniejszajc wcicie do poziomu instrukcji wyra|enia sterujcego, na przykBad: my @names = ( 'Damian', # Klucz podstawowy 'Matthew', # Ujednoznacznienie 'Conway', # Ogólna klasa lub kategoria ); for my $name (@names) { for my $word ( anagrams_of(lc $name) ) { print "$word\n"; } } Nie nale|y umieszcza otwierajcego nawiasu klamrowego lub okrgBego w oddzielnym wier- szu, jak w stylach BSD lub GNU: # Nie u|ywa stylu BSD... my @names = ( 'Damian', # Klucz podstawowy 'Matthew', # Ujednoznacznienie 'Conway', # Ogólna klasa lub kategoria ); for my $name (@names) { for my $word (anagrams_of(lc $name)) { print "$word\n"; } } # ani stylu GNU... 1  K&R to Brian Kernighan i Dennis Ritchie, autorzy ksi|ki Jzyk C (wyd. WNT, 1988). 28 | RozdziaB 2. UkBad kodu for my $name (@names) { for my $word (anagrams_of(lc $name)) { print "$word\n"; } } Styl K&R ma jedn oczywist przewag nad pozostaBymi dwoma: zajmuje jeden wiersz mniej na ka|dy blok, co oznacza, |e na ekranie wida wicej rzeczywistego kodu. Je[li wy[wietlana jest seria bloków, mo|e to oznacza trzy lub cztery dodatkowe wiersze na ka|dy ekran. GBównym kontrargumentem na korzy[ stylów BSD i GNU ma by to, |e nawias otwieraj- cy2 w oddzielnym wierszu uBatwia wizualne dopasowanie pocztku i koDca bloku lub listy. Twierdzenie to ignoruje jednak fakt, |e równie Batwo jest dopasowa je w stylu K&R. Wystar- czy przewija program do góry a| do napotkania konstrukcji sterujcej, a nastpnie przesko- czy na koniec wiersza. Jeszcze Batwiej nacisn klawisz edytora, który przenosi kursor midzy dopasowanymi nawia- sami. W edytorze vi jest to klawisz %. W edytorze Emacs nie ma takiego polecenia, ale Batwo je utworzy poprzez dopisanie do pliku .emacs nastpujcych wierszy3: ;; Klawisz % sBu|y do dopasowywania ró|nych rodzajów nawiasów... (global-set-key "%" 'match-paren) (defun match-paren (arg) "Przechodzi do dopasowanego nawiasu, gdy kursor jest na nawiasie, w przeciwnym razie wstawia znak %." (interactive "p") (cond ((string-match "[[{(<]" next-char) (forward-sexp 1)) ((string-match "[\]})>]" prev-char) (backward-sexp 1)) (t (self-insert-command (or arg 1))))) Co wa|niejsze, znajdowanie pasujcego nawiasu rzadko jest celem samym w sobie. Zwykle jeste[my zainteresowani nawiasem zamykajcym dlatego, |e chcemy ustali, gdzie koDczy si bie|ca konstrukcja (ptla for, instrukcja if lub procedura), albo dowiedzie si, jak konstruk- cj koDczy nawias zamykajcy. Oba te zadania s nieco Batwiejsze w przypadku stylu K&R. Aby znalez koniec konstrukcji, wystarczy spojrze prosto w dóB, poczwszy od sBowa kluczo- wego; |eby znalez konstrukcj zakoDczon nawiasem, wystarczy patrze w gór a| do napo- tkania sBowa kluczowego. Innymi sBowy, style BSD i GNU uBatwiaj dopasowanie skBadni nawiasów, a styl K&R  do- pasowanie ich semantyki. To powiedziawszy, spiesz zapewni, |e w stylach BSD i GNU nie ma niczego zBego. Je[li czytelnik i programi[ci z jego zespoBu uznaj, |e wyrównane pionowo nawiasy uBatwiaj im czytanie kodu, mog ich u|ywa. Liczy si tylko to, aby wszyscy czBon- kowie zespoBu uzgodnili wspólny styl i konsekwentnie go stosowali. 2 Dalej w tej ksi|ce sBowo  nawias bdzie u|ywane jako ogólny termin na oznaczenie czterech typów ogra- niczników wystpujcych w parach: nawiasów klamrowych ({...}), okrgBych ((...)), kwadratowych ([...]) i trójktnych (<...>). 3 Sugerowane konfiguracje edytorów zostaBy zebrane w dodatku C. Mo|na je równie| pobra pod adresem http://www.oreilly.com/catalog/perlbp. Stosowanie nawiasów | 29 SBowa kluczowe Oddzielaj sBowa kluczowe struktur sterujcych od nawiasu otwierajcego. Struktury sterujce reguluj dziaBanie programu, wic ich sBowa kluczowe zaliczaj si do naj- bardziej krytycznych komponentów kodu. Dlatego istotne jest, aby sBowa te dobrze wyró|niaBy si w kodzie zródBowym. W Perlu po wikszo[ci sBów kluczowych struktur sterujcych natychmiast nastpuje nawias otwierajcy, co sprawia, |e Batwo pomyli je z wywoBaniami procedur. Warto zatem jako[ je wyró|ni. W tym celu nale|y wstawia pojedyncz spacj midzy sBowem kluczowym a nast- pujcym po nim nawiasem klamrowym lub okrgBym: for my $result (@results) { print_sep(); print $result; } while ($min < $max) { my $try = ($max - $min) / 2; if ($value[$try] < $target) { $max = $try; } else { $min = $try; } } Bez tego odstpu trudniej zauwa|y sBowo kluczowe i Batwiej pomyli je z wywoBaniem pro- cedury: for(@results) { print_sep(); print; } while($min < $max) { my $try = ($max - $min) / 2; if($value[$try] < $target) { $max = $try; } else{ $min = $try; } } 30 | RozdziaB 2. UkBad kodu Procedury i zmienne Nie oddzielaj nazw procedur i zmiennych od nastpujcego po nich nawiasu otwierajcego. Aby poprzednia reguBa si sprawdziBa, nie nale|y umieszcza spacji midzy nazwami proce- dur i zmiennych a nastpujcymi po nich nawiasami. W przeciwnym razie Batwo bdzie po- myli wywoBanie procedury ze struktur sterujc albo uzna pocztkow cz[ elementu ta- blicy za niezale|n zmienn skalarn. Nale|y zatem dosuwa nazwy procedur i zmiennych do nastpujcych po nich nawiasów okrgBych lub klamrowych: my @candidates = get_candidates($marker); CANDIDATE: for my $i (0..$#candidates) { next CANDIDATE if open_region($i); $candidates[$i] = $incumbent{ $candidates[$i]{region} }; } U|ycie spacji niepotrzebnie utrudnia ich rozpoznanie: my @candidates = get_candidates ($marker); CANDIDATE: for my $i (0..$#candidates) { next CANDIDATE if open_region ($i); $candidates [$i] = $incumbent {$candidates [$i] {region}}; } Funkcje wbudowane Nie u|ywaj niepotrzebnych nawiasów podczas wywoBania funkcji wbudowanych i  honorowo wbudowanych. Wbudowane funkcje Perla s faktycznie sBowami kluczowymi jzyka, wic mo|na je wywo- Bywa bez nawiasów okrgBych, chyba |e konieczne jest wymuszenie priorytetu. WywoBywanie funkcji wbudowanych bez nawiasów zmniejsza zagszczenie kodu i zwiksza jego czytelno[. Brak nawiasów pomaga te| odró|ni wywoBania procedur od wywoBaD funkcji wbudowanych: while (my $record = <$results_file>) { chomp $record; my ($name, $votes) = split "\t", $record; print 'GBosy na ', substr($name, 0, 10), # Nawiasy niezbdne ze wzgldu na priorytet ": $votes (verified)\n"; } Funkcje wbudowane | 31 Niektóre importowane procedury, zwykle zawarte w moduBach podstawowej dystrybucji, zali- czaj si do  honorowych funkcji wbudowanych i równie| mog by wywoBywane bez na- wiasów. Zazwyczaj dotyczy to procedur oferujcych funkcje, które powinny by w samym jzyku, ale nie s. PrzykBadem mog by procedury carp i croak (ze standardowego moduBu Carp  rozdziaB 13.), first i max (ze standardowego moduBu List::Util  rozdziaB 8.) oraz prompt (z moduBu CPAN IO::Prompt  rozdziaB 10.). Jednak|e w przypadkach, gdy konieczne jest u|ycie funkcji wbudowanych z nawiasami, na- le|y zastosowa reguB dotyczc procedur, a nie sBów kluczowych, tzn. nie umieszcza spacji midzy nazw funkcji wbudowanej a otwierajcym nawiasem okrgBym: while (my $record = <$results_file>) { chomp( $record ); my ($name, $votes) = split("\t", $record); print( 'GBosy na ', substr($name, 0, 10), ": $votes (verified)\n" ); } Nie nale|y traktowa funkcji wbudowanych jak sBów kluczowych (poprzez dopisanie spacji): while (my $record = <$results_file>) { chomp ($record); my ($name, $votes) = split ("\t", $record); print ( 'GBosy na ', substr ($name, 0, 10), ": $votes (verified)\n" ); } Klucze i indeksy Oddzielaj skomplikowane klucze lub indeksy od otaczajcych je nawiasów. Podczas uzyskiwania dostpu do elementów zagnie|d|onych struktur danych (tablic asocja- cyjnych, które przechowuj tablice asocjacyjne, które przechowuj tablice, które przechowuj jakie[ elementy) Batwo o dBugie, skomplikowane i zagszczone wyra|enia w rodzaju: $candidates[$i] = $incumbent{$candidates[$i]{get_region()}}; Dotyczy to szczególnie sytuacji, w której indeksy same s zmiennymi indeksowanymi. StBo- czenie wszystkich elementów bez u|ycia odstpów nie poprawia czytelno[ci takich wyra|eD. Szczególnie trudno czasem domy[li si, czy dana para nawiasów jest cz[ci indeksu wewntrz- nego, czy zewntrznego. Je[li indeks nie jest prost staB albo zmienn skalarn, lepiej umie[ci spacje midzy wyra|e- niem indeksujcym a otaczajcymi je nawiasami: $candidates[$i] = $incumbent{ $candidates[$i]{ get_region() } }; 32 | RozdziaB 2. UkBad kodu Decydujcymi czynnikami s tu zBo|ono[ i ogólna dBugo[ indeksu. Od czasu do czasu  roz- rzedzenie indeksu ma sens nawet wtedy, gdy jest on pojedyncz staB lub skalarem. Je[li na przykBad indeks jest bardzo dBugi, lepiej zapisa go w taki sposób: print $incumbent{ $largest_gerrymandered_constituency }; ni| tak: print $incumbent{$largest_gerrymandered_constituency}; Operatory U|ywaj odstpów midzy operatorami binarnymi a ich argumentami. DBugie wyra|enia czsto bywaj niezrozumiaBe, wic nie nale|y jeszcze bardziej utrudnia ich interpretacji poprzez stBaczanie komponentów: my $displacement=$initial_velocity*$time+0.5*$acceleration*$time**2; my $price=$coupon_paid*$exp_rate+(($face_val+$coupon_val)*$exp_rate**2); Warto da operatorom binarnym nieco  oddechu , nawet je[li bdzie to wymaga przeniesie- nia kodu do nastpnego wiersza: my $displacement = $initial_velocity * $time + 0.5 * $acceleration * $time**2; my $price = $coupon_paid * $exp_rate + ($face_val + $coupon_val) * $exp_rate**2; Ilo[ odstpów nale|y dobra zgodnie z priorytetem operatorów, aby osoba czytajca wyra|e- nie mogBa Batwo wyró|ni naturalne grupy elementów. Mo|na na przykBad dopisa dodatkowe spacje po obu stronach operatora + (o ni|szym priorytecie), aby wizualnie podkre[li wy|szy priorytet dwóch wyra|eD multiplikatywnych. Z drugiej strony, mo|na [miaBo [cisn operator ** i jego dwa argumenty, poniewa| ma on bardzo wysoki priorytet i dBu|szy, Batwo za- uwa|alny symbol. Jedna spacja zawsze wystarcza, kiedy do podkre[lenia (albo zmiany) priorytetu u|ywane s nawiasy: my $velocity = $initial_velocity + ($acceleration * ($time + $delta_time)); my $future_price = $current_price * exp($rate - $dividend_rate_on_index) * ($delivery - $now); Symboliczne operatory unarne powinny by zawsze dosunite do argumentów: my $spring_force = !$hyperextended ? -$spring_constant * $extension : 0; my $payoff = max(0, -$asset_price_at_maturity + $strike_price); Nazwane operatory binarne nale|y traktowa tak jak funkcje wbudowane i odpowiednio od- dziela od argumentów: my $tan_theta = sin $theta / cos $theta; my $forward_differential_1_year = $delivery_price * exp -$interest_rate; Operatory | 33 Zredniki Umieszczaj [rednik za ka|d instrukcj. W Perlu [redniki s separatorami, a nie terminatorami instrukcji, wic nie trzeba umieszcza [rednika po ostatniej instrukcji w bloku. Pomimo to nale|y je dopisywa, nawet je[li blok za- wiera tylko jedn instrukcj: while (my $line = <>) { chomp $line; if ( $line =~ s{\A (\s*) -- (.*)}{$1#$2}xms ) { push @comments, $2; } print $line; } Nie wymaga to wielkiego wysiBku, a koDcowy [rednik zapewnia dwie wa|ne korzy[ci: sy- gnalizuje osobie czytajcej kod, |e poprzednia instrukcja jest zakoDczona, a ponadto sygnali- zuje to kompilatorowi. Jest to znacznie wa|niejsze, poniewa| czBowiek czsto mo|e domy[li si, co programista miaB na my[li, a kompilator odczytuje tylko to, co zostaBo rzeczywi[cie napisane. Pominicie koDcowego [rednika zwykle nie powoduje problemów podczas pisania kodu (tzn. wtedy, gdy programista przykBada uwag do caBego fragmentu kodu): while (my $line = <>) { chomp $line; if ( $line =~ s{\A (\s*) -- (.*)}{$1#$2}xms ) { push @comments, $2 } print $line } Poza [rednikiem nie ma jednak niczego, co zapobiegaBoby subtelnym problemom, kiedy pro- gramista pózniej dopisze kolejne instrukcje: while (my $line = <>) { chomp $line; if ( $line =~ s{\A (\s*) -- (.*)}{$1#$2}xms ) { push @comments, $2 /shift/mix } print $line $src_len += length; } Problem w tym, |e dopisany kod nie dodaje nowych instrukcji, lecz jest absorbowany przez poprzednie. Zatem powy|szy fragment kodu w istocie znaczy: while (my $line = <>) { chomp $line; if ( $line =~ s{\A (\s*) -- (.*)}{$1#$2}xms ) { 34 | RozdziaB 2. UkBad kodu push @comments, $2 / shift() / mix() } print $line ($src_len += length); } Jest to bardzo czsta i zrozumiaBa pomyBka. Podczas rozbudowywania kodu z natury rzeczy skupiamy si na nowych instrukcjach, zakBadajc, |e istniejce bd nadal dziaBaBy prawidBowo. Jednak|e brak koDcowego [rednika mo|e sprawi, |e istniejce instrukcje zostan wchBonite przez now. ReguBa nie dotyczy bloków map lub grep, które zawieraj tylko jedn instrukcj. W takim przy- padku lepiej pomin terminator: my @sqrt_results = map { sqrt $_ } @results; poniewa| [rednik w bloku utrudnia dostrze|enie koDca peBnej instrukcji: my @sqrt_results = map { sqrt $_; } @results; Wyjtek ten nie zwiksza podatno[ci programu na bBdy, poniewa| umieszczanie kilku instruk- cji w bloku map lub grep jest do[ nietypowe i czsto [wiadczy o tym, |e nale|aBoby zastosowa inn konstrukcj (podrozdziaB  ZBo|one odwzorowania w rozdziale 6.). Przecinki Umieszczaj przecinek po ka|dej warto[ci na wielowierszowej li[cie. Podobnie jak [redniki peBni funkcj separatora w blokach instrukcji, tak przecinki oddzielaj warto[ci na li[cie. Oznacza to, |e równie| je nale|y traktowa jak terminatory. Ponadto dopisanie koDcowego przecinka (co wolno zrobi na dowolnej li[cie Perla) bardzo uBa- twia zmian kolejno[ci elementów, na przykBad du|o Batwiej przeksztaBci poni|sz list: my @dwarves = ( 'Smutu[', 'Zpioch', 'FajtBapek', 'Apsik', 'Gderek', 'Nie[miaBek', 'Mdrek', ); na: my @dwarves = ( 'Nie[miaBek', 'Mdrek', 'FajtBapek', 'Gderek', 'Smutu[', 'Zpioch', 'Apsik', ); Przecinki | 35 Mo|na rcznie wycina i wkleja wiersze, a nawet przetworzy zawarto[ listy poleceniem sort. Bez koDcowego przecinka za elementem 'Mdrek' zmiana kolejno[ci listy spowodowaBaby bBd: my @dwarves = ( 'Nie[miaBek', 'Mdrek' 'FajtBapek', 'Gderek', 'Smutu[', 'Zpioch', 'Apsik', ); Oczywi[cie, tego rodzaju pomyBk Batwo znalez i poprawi, ale czemu nie kodowa w sposób, który uniemo|liwia wystpienie takiego problemu? DBugo[ wierszy U|ywaj wierszy liczcych 78 kolumn. W [wiecie 30-calowych ekranów o wysokiej rozdzielczo[ci, wygBadzanych czcionek i laserowej korekcji wzroku mo|na programowa w oknie terminala szerokim na 300 kolumn. Mo|na, ale nie nale|y. Zwa|ywszy na ograniczenia drukowanych dokumentów, tradycyjnych ekranów VGA i opro- gramowania prezentacyjnego, nierozsdnie jest formatowa kod na szeroko[ wiksz ni| 80 ko- lumn. Nawet 80-kolumnowe wiersze nie zawsze s bezpieczne ze wzgldu na mechanizmy zawijania tekstu w niektórych terminalach, edytorach i systemach pocztowych. Ustawienie prawego marginesu w 78. kolumnie maksymalizuje u|yteczn szeroko[ ka|dego wiersza kodu, a jednocze[nie gwarantuje, |e wiersze bd wy[wietlane w taki sam sposób na wikszo[ci ekranów. Aby ustawi prawy margines w edytorze vi, nale|y do pliku konfiguracyjnego doBczy poni|- szy wiersz: set textwidth=78 W przypadku Emacsa nale|y u|y poleceD: (setq fill-column 78) (setq auto-fill-mode t) Kolejn zalet takiej szeroko[ci wiersza jest to, |e ka|dy fragment kodu przesBany w wiadomo- [ci e-mail mo|na przytoczy przynajmniej raz bez zawijania wierszy: From: boss@headquarters To: you@saltmines Subject: Prosz o wyja[nienia WBa[nie znalazBem ten fragment kodu w Pana najnowszym module. Czy to ma by |art!? > $;=$/;seek+DATA,undef$/,!$s;$_=<DATA>;$s&&print||(*{q;::\; > ;}=sub{$d=$d-1?$d:$0;s;';\t#$d#;,$_})&&$g&&do{$y=($x||=20)*($y||8);sub 36 | RozdziaB 2. UkBad kodu > i{sleep&f}sub'p{print$;x$=,join$;,$b=~/.{$x}/g,$;}sub'f{pop||1}sub'n{substr($b > ,&f%$y,3)=~tr,0,0,}sub'g{@_[@_]=@_;--($f=&f);$m=substr($b,&f,1);($w,$w,$m,0) > [n($f-$x)+n($x+$f)-(${m}eq+0=>)+n$f]||$w}$w="\40";$b=join'',@ARGV?<>:$_,$w > x$y;$b=~s).)$&=~/\w/?0:$w)gse;substr($b,$y)=q++;$g='$i=0;$i?$b:$c=$b; > substr+$c,$i,1,g$i;$g=~s?\d+?($&+1)%$y?e;$i-$y+1?eval$g:do{$b=$c;p;i}'; > sub'e{eval$g;&e};e}||eval||die+No.$; Prosz natychmiast przyj[ do mojego gabinetu! Y.B. Wcicia U|ywaj czterokolumnowych poziomów wcicia. GBboko[ wci to sprawa du|o bardziej kontrowersyjna ni| szeroko[ wiersza. Je[li zapytamy czterech programistów, ile kolumn powinien liczy ka|dy poziom wcicia, otrzymamy cztery ró|ne odpowiedzi: dwie, trzy, cztery albo osiem. WywoBamy te| za|art kBótni. Staro|ytni mistrzowie kodowania, którzy zaczynali od teletekstów i terminali sprztowych ze staBymi przystankami tabulatora, bd nas zapewnia, |e do przyjcia s wyBcznie 8-kolumnowe wcicia, poniewa| wikszo[ drukarek i terminali programowych nadal domy[lnie wypi- suje 8 kolumn na ka|dy znak tabulacji. Gwarantuje to jednolity wygld kodu na ka|dym urzdzeniu: while (my $line = <>) { chomp $line; if ( $line =~ s{\A (\s*) -- ([^\n]*) }{$1#$2}xms ) { push @comments, $2; } print $line; } Tak (zgodzi si wielu mBodszych hakerów), 8-kolumnowe wcicia gwarantuj, |e kod bdzie wygldaB równie paskudnie i nieczytelnie na ka|dym urzdzeniu! Ka|dy poziom wcicia powinien zatem liczy nie wicej ni| 2 lub 3 kolumny. Mniejsze wcicia pozwalaj zmie[ci na ekranie wicej poziomów zagnie|d|enia: mniej wicej 12 poziomów przy wciciu 2- lub 3-kolumnowym, a zaledwie 4 lub 5 poziomów przy wciciu 8-kolumnowym. PBytsze wcicia zmniejszaj te| poziom odlegBo[, któr musi pokona oko. CaBa lewa krawdz kodu pozostaje w zasigu wzroku, dziki czemu Batwiej oceni kontekst ka|dego wiersza: while (my $line = <>) { chomp $line; if ( $line =~ s{\A (\s*) -- ([^\n]*) }{$1#$2}xms ) { push @comments, $2; } print $line; } Niestety (zapBacz starzy mistrzowie), taka metoda utrudnia dostrze|enie wci programi- stom po trzydziestce i ka|demu, kto nie ma sokolego wzroku. I w tym le|y sedno problemu. GBbokie wcicia podkre[laj czytelno[ strukturaln kosztem kontekstowej, a pBytkie  od- wrotnie. Nie ma idealnego rozwizania. Wcicia | 37 Rozsdnym kompromisem4 jest u|ycie czterech kolumn na ka|dy poziom wcicia. Dziki temu starzy mistrzowie bd mogli dostrzec wcicia, a mBodzi hakerzy zagnie|d|a kod na osiem lub dziewi poziomów5 bez zawijania wierszy: while (my $line = <>) { chomp $line; if ( $line =~ s{\A (\s*) -- (.*)}{$1#$2}xms ) { push @comments, $2; } print $line; } Znaki tabulacji Wcinaj kod z wykorzystaniem spacji, a nie znaków tabulacji. Znaki tabulacji nie nadaj si do wcinania kodu, nawet je[li przystanki tabulatora w edytorze s ustawione na cztery kolumny. Znaki tabulacji wygldaj inaczej, kiedy s drukowane na ró|nych urzdzeniach wyj[ciowych, wklejane do procesora tekstu albo wy[wietlane w edytorze z innymi przystankami tabulacji. Nie nale|y wic u|ywa znaków tabulacji albo (co gorsza) miesza ich ze spacjami: sub addarray_internal { » my ($var_name, $need_quotemeta) = @_; » $raw .= $var_name; » my $quotemeta = $need_quotemeta ? q{ map {quotemeta $_} } » » » » » : $EMPTY_STR » ··············; ····my $perl5pat ····» = qq{(??{join q{|}, $quotemeta \@{$var_name}})}; » push @perl5pats, $perl5pat; » return; } Jedynym niezawodnym, powtarzalnym i przeno[nym sposobem wcinania kodu w taki spo- sób, aby wygldaB jednakowo w ka|dym [rodowisku, jest u|ycie spacji. Zgodnie z poprzedni reguB dotyczc gBboko[ci wcinania oznacza to cztery znaki spacji na ka|dy poziom wcicia: sub addarray_internal { ····my ($var_name, $need_quotemeta) = @_; ····$raw .= $var_name; ····my $quotemeta = $need_quotemeta ? q{ map {quotemeta $_} } ··················:···················$EMPTY_STR ··················; 4 WedBug wyników badaD opublikowanych w artykule  Programming Indentation and Comprehensibility (Communications of ACM, Vol. 26. No. 11, s. 861  867). 5 Nie nale|y jednak tego robi! Je[li potrzeba wicej ni| czterech lub piciu poziomów zagnie|d|enia, kod niemal na pewno powinien zosta przeniesiony do procedury lub moduBu (rozdziaBy 9. i 17.). 38 | RozdziaB 2. UkBad kodu ····my $perl5pat ········= qq{(??{join q{|}, $quotemeta \@{$var_name}})}; ····push @perl5pats, $perl5pat; ····return; } Zauwa|my, |e powy|sza reguBa nie zabrania u|ywa klawisza Tab do wcinania kodu; wymaga tylko, aby wynikiem naci[nicia tego klawisza byBo co[ innego ni| znak tabulacji. Aatwo to osign w nowoczesnych edytorach, które mo|na skonfigurowa tak, aby przeksztaBcaBy znaki tabulacji w spacje, na przykBad u|ytkownicy edytora vim mog umie[ci poni|sze dyrektywy w swoim pliku .vimrc: set tabstop=4 "Poziom wcicia co cztery kolumny" set expandtab "PrzeksztaBcanie wszystkich wpisanych znaków tabulacji w spacje" set shiftwidth=4 "Wcinanie i usuwanie wci o cztery kolumny" set shiftround "Wcinanie i usuwanie wci do najbli|szego przystanku tabulatora" W pliku inicjalizacyjnym .emacs nale|y natomiast napisa (tryb  cperl ): (defalias 'perl-mode 'cperl-mode) ;; czterokolumnowe wcicia w trybie cperl '(cperl-close-paren-offset -4) '(cperl-continued-statement-offset 4) '(cperl-indent-level 4) '(cperl-indent-parens-as-block t) '(cperl-tab-always-indent t) ByBoby najlepiej, gdyby kod nie zawieraB ani jednego znaku tabulacji. W ukBadzie kodu nale- |y przeksztaBca je w spacje, natomiast w literalnych BaDcuchach trzeba posBugiwa si symbo- lem \t (rozdziaB 4.). Bloki Nigdy nie umieszczaj dwóch instrukcji w tym samym wierszu. Je[li w jednym wierszu znajduj si dwie lub wicej instrukcji, ka|da z nich staje si mniej zrozumiaBa: RECORD: while (my $record = <$inventory_file>) { chomp $record; next RECORD if $record eq $EMPTY_STR; my @fields = split $FIELD_SEPARATOR, $record; update_sales(\@fields);$count++; } Oszczdno[ miejsca na ekranie zapewniaj ju| nawiasy w stylu K&R; warto wykorzysta to miej- sce do zwikszenia czytelno[ci kodu przez umieszczenie ka|dej instrukcji w oddzielnym wierszu: RECORD: while (my $record = <$inventory_file>) { chomp $record; next RECORD if $record eq $EMPTY_STR; my @fields = split $FIELD_SEPARATOR, $record; update_sales(\@fields); $count++; } Bloki | 39 Wskazówka ta dotyczy nawet bloków map i grep, które zawieraj wicej ni| jedn instrukcj. Nale|y pisa: my @clean_words = map { my $word = $_; $word =~ s/$EXPLETIVE/[DELETED]/gxms; $word; } @raw_words; a nie: my @clean_words = map { my $word = $_; $word =~ s/$EXPLETIVE/[DELETED]/gxms; $word } @raw_words; Akapity Dziel kod na akapity. Akapit to zbiór instrukcji, które realizuj pojedyncze zadanie; w literaturze jest to seria zdaD przekazujcych jedn ide, a w programowaniu  seria instrukcji odpowiadajcych jednej fa- zie algorytmu. Kod trzeba dzieli na sekwencje, które realizuj pojedyncze zadanie. Midzy kolejnymi sekwen- cjami nale|y umieszcza puste wiersze. Aby jeszcze bardziej uBatwi konserwacj kodu, na pocztku ka|dego akapitu powinno si dopisywa jednowierszowy komentarz wyja[niajcy przeznaczenie danej sekwencji: # Przetwarzamy rozpoznan tablic... sub addarray_internal { my ($var_name, $needs_quotemeta) = @_; # Buforujemy oryginaB... $raw .= $var_name; # Na |danie konstruujemy kod przytaczajcy metaznaki... my $quotemeta = $needs_quotemeta ? q{map {quotemeta $_} } : $EMPTY_STR; # Rozwijamy elementy zmiennej, Bczymy je za pomoc operacji OR... my $perl5pat = qq{(??{join q{|}, $quotemeta \@{$var_name}})}; # Na |danie wstawiamy kod diagnostyczny... my $type = $quotemeta ? 'literaB' : 'wzorzec'; debug_now("Dodaj $var_name (jako $type)"); add_debug_mesg("Wypróbowuj $var_name (jako $type)"); return $perl5pat; } Akapity s przydatne, poniewa| ludzie potrafi skupi si tylko na kilku informacjach jedno- cze[nie6. Akapity grupuj powizane informacje, dziki czemu wynikowa  porcja mo|e zmie- [ci si w ograniczonej pamici krótkotrwaBej. Dziki akapitom fizyczna struktura tekstu od- 6 Ide t przedstawiB w 1956 roku George A. Miller w artykule  Magiczna liczba siedem, plus minus dwa (The Psychological Review, 1956, Vol. 63, s. 81  97). 40 | RozdziaB 2. UkBad kodu zwierciedla i podkre[la struktur logiczn. Komentarze na pocztku akapitów wzmacniaj ten podziaB, jawnie podsumowujc przeznaczenie ka|dego fragmentu7. Zauwa|my jednak, |e komentarze maj tu drugorzdne znaczenie. Kluczowe s pionowe od- stpy midzy akapitami. Bez nich czytelno[ kodu znacznie si zmniejsza, nawet w razie za- chowania komentarzy: sub addarray_internal { my ($var_name, $needs_quotemeta) = @_; # Buforujemy oryginaB... $raw .= $var_name; # Na |danie konstruujemy kod przytaczajcy metaznaki... my $quotemeta = $needs_quotemeta ? q{map {quotemeta $_} } : $EMPTY_STR; # Rozwijamy elementy zmiennej, Bczymy je za pomoc operacji OR... my $perl5pat = qq{(??{join q{|}, $quotemeta \@{$var_name}})}; # Na |danie wstawiamy kod diagnostyczny... my $type = $quotemeta ? 'literaB' : 'wzorzec'; debug_now("Dodaj $var_name (jako $type)"); add_debug_mesg("Wypróbowuj $var_name (jako $type)"); return $perl5pat; } Instrukcje else Nie stBaczaj instrukcji else.  StBoczona instrukcja else wyglda tak: } else { A  niestBoczona tak: } else { StBoczone instrukcje else pozwalaj oszczdzi jeden wiersz na ka|d alternatyw, ale osta- tecznie zmniejszaj czytelno[ kodu, zwBaszcza sformatowanego w stylu K&R. StBoczona in- strukcja else nie znajduje si w jednej linii ani z kontrolujc j instrukcj if, ani z wBasnym nawiasem zamykajcym. To przesunicie utrudnia wizualne dopasowanie poszczególnych kom- ponentów konstrukcji if-else. Co wa|niejsze, instrukcja else definiuje alternatywny tryb postpowania, kiedy za[ jest stBo- czona, rozró|nienie to staje si mniej wyrazne. Znika niemal pusty wiersz z nawiasem klamro- wym zamykajcym instrukcj if, co zmniejsza wizualny odstp pomidzy blokami if i else. Takie [ci[nicie bloków kBóci si z ich wewntrznym ukBadem, zwBaszcza je[li s one podzielo- ne na akapity w sposób opisany w poprzednim podrozdziale. StBaczanie sprawia te|, |e instrukcja else nie zajmuje nale|nego jej miejsca po lewej stronie wiersza, co utrudnia zlokalizowanie sBowa kluczowego podczas przegldania kodu. Natomiast niestBoczona instrukcja else poprawia pionowy podziaB kodu i uBatwia identyfikacj sBowa kluczowego: 7 Znaczenie, a nie dziaBanie. Komentarze przed akapitami maj wyja[nia, do czego sBu|y kod, a nie parafra- zowa realizowane przez niego operacje. Instrukcje else | 41 if ($sigil eq '$') { if ($subsigil eq '?') { $sym_table{ substr($var_name,2) } = delete $sym_table{$var_name}; $internal_count++; $has_internal{$var_name}++; } else { ${$var_ref} = q{$sym_table{$var_name}}; $external_count++; $has_external{$var_name}++; } } elsif ($sigil eq '@' && $subsigil eq '?') { @{ $sym_table{$var_name} } = grep {defined $_} @{$sym_table{$var_name}}; } elsif ($sigil eq '%' && $subsigil eq '?') { delete $sym_table{$var_name}{$EMPTY_STR}; } else { ${$var_ref} = q{$sym_table{$var_name}}; } Porównajmy to ze stBoczon instrukcj else lub elseif, która zaciemnia wewntrzny podziaB bloków na akapity i zmniejsza widoczno[ sBów kluczowych: if ($sigil eq '$') { if ($subsigil eq '?') { $sym_table{ substr($var_name,2) } = delete $sym_table{$var_name}; $internal_count++; $has_internal{$var_name}++; } else { ${$var_ref} = q{$sym_table{$var_name}}; $external_count++; $has_external{$var_name}++; } } elsif ($sigil eq '@' && $subsigil eq '?') { @{$sym_table{$var_name}} = grep {defined $_} @{$sym_table{$var_name}}; } elsif ($sigil eq '%' && $subsigil eq '?') { delete $sym_table{$var_name}{$EMPTY_STR}; } else { ${$var_ref} = q{$sym_table{$var_name}}; } Wyrównanie pionowe Wyrównuj pionowo powizane ze sob elementy. Innym, dobrze znanym sposobem grupowania pokrewnych informacji (i sygnalizowania re- lacji logicznych przez ukBad fizyczny) s tabele. Podczas formatowania kodu czsto warto roz- mie[ci dane w sposób przypominajcy tabel. Jednolite wcicia mog sugerowa równowa|n struktur, u|ycie lub przeznaczenie. 42 | RozdziaB 2. UkBad kodu PrzykBadowo inicjalizatory zmiennych nieskalarnych s znacznie czytelniejsze, kiedy uBo|y si je w kolumny z wykorzystaniem dodatkowych odstpów. Poni|sze inicjalizatory tablicy zwy- kBej i asocjacyjnej s bardzo czytelne wBa[nie dziki ukBadowi tabelarycznemu: my @months = qw( StyczeD Luty Marzec KwiecieD Maj Czerwiec Lipiec SierpieD WrzesieD Pa|dziernik Listopad GrudzieD ); my %expansion_of = ( q{it's} => q{it is}, q{we're} => q{we are}, q{didn't} => q{did not}, q{must've} => q{must have}, q{I'll} => q{I will}, ); PrzeksztaBcenie ich w listy pozwala zaoszczdzi kilka wierszy, ale znacznie zmniejsza ich czytelno[: my @months = qw( StyczeD Luty Marzec KwiecieD Maj Czerwiec Lipiec SierpieD WrzesieD Pa|dziernik Listopad GrudzieD ); my %expansion_of = ( q{it's} => q{it is}, q{we're} => q{we are}, q{didn't} => q{did not}, q{must've} => q{must have}, q{I'll} => q{I will}, ); Podobny ukBad warto stosowa w sekwencjach ustawiajcych warto[ci pokrewnych zmien- nych. Lepiej wyrówna operatory przypisania: $name = standardize_name($name); $age = time - $birth_date; $status = 'aktywny'; ni| pisa w taki sposób: $name = standardize_name($name); $age = time - $birth_date; $status = 'aktywny'; Wyrównanie jest jeszcze wa|niejsze podczas przypisywania warto[ci elementom tablicy aso- cjacyjnej lub zwykBej. W takich przypadkach klucze (lub indeksy) nale|y uBo|y w kolumnie, a otaczajce je nawiasy klamrowe (lub okrgBe) równie| powinny by wyrównane: $ident{ name } = standardize_name($name); $ident{ age } = time - $birth_date; $ident{ status } = 'aktywny'; UkBad tabelaryczny wyró|nia klucze elementów, a zatem podkre[la cel ka|dego przypisania. Bez tego uwag przyciga  kolumna przedrostków $ident, przez co du|o trudniej odró|ni nazwy kluczy: $ident{name} = standardize_name($name); $ident{age} = time - $birth_date; $ident{status} = 'aktywny'; Wyrównanie pionowe | 43 Wyrównanie samych operatorów przypisania jest lepsze ni| zupeBny brak wyrównania, ale nie a| tak czytelne jak wyrównanie zarówno kluczy, jak i operatorów: $ident{ name } = standardize_name($name); $ident{ age } = time - $birth_date; $ident{ status } = 'aktywny'; Dzielenie dBugich wierszy Dziel dBugie wyra|enia przed operatorem. Kiedy wyra|enie na koDcu instrukcji jest zbyt dBugie, czsto dzieli si je zaraz po operatorze i kontynuuje od nowego wiersza wcite o jeden poziom: push @steps, $steps[-1] + $radial_velocity * $elapsed_time + $orbital_velocity * ($phase + $phase_shift) - $DRAG_COEFF * $altitude; Operator na koDcu wiersza ma peBni funkcj znacznika kontynuacji  sygnalizowa, |e in- strukcja cignie si dalej w nastpnym wierszu. U|ywanie operatora jako znacznika kontynuacji wydaje si doskonaBym pomysBem, ale jest z tym pewien problem: ludzie rzadko patrz na praw stron kodu. Wikszo[ wskazówek se- mantycznych  takich jak sBowa kluczowe  pojawia si po lewej stronie. Co wa|niejsze, wska- zówki strukturalne, na przykBad wcicia, równie| znajduj si z lewej strony (wicej informacji na ten temat mo|na znalez w ramce  Na lewo patrz ). Oznacza to, |e wcinanie kolejnych wierszy wyra|enia w rzeczywisto[ci wywoBuje faBszywe wra|enie podstawowej struktury, któ- re trzeba skorygowa poprzez prze[ledzenie caBego wiersza a| do prawego marginesu. Na lewo patrz Lewa krawdz kodu jest najbardziej wyró|niajcym si miejscem, poniewa|  podobnie jak jzyk polski  Perl jest zasadniczo jzykiem typu  od lewej do prawej , a w takich jzykach lewa cz[ wyra|enia jest szczególnie istotna. Na pocztku wyra|enia czytelnik jest  [wie|y ; nie musi pamita niczego, co nastpiBo wcze- [niej. Natomiast na koDcu wyra|enia pami krótkotrwaBa jest wypeBniona, a czytelnik skupia uwag na interpretacji caBego wiersza albo w ogóle traci koncentracj. Lingwi[ci nazywaj ten efekt  problemem wagi koDcowej i odradzaj zachowywanie wa|- nych informacji na sam koniec: Poniewa| po dBugiej nocy spdzonej na programowaniu w przera|ajcym [nie przyszBy do mnie potpione dusze odpowiedzialne za ANSI C++, uciekBem z krzykiem. Je[li informacja ta zostanie umieszczona na pocztku, Batwiej bdzie zwróci na ni uwag, mimo |e reszta zdania nieco si rozmyje: UciekBem z krzykiem, poniewa| potpione dusze odpowiedzialne za ANSI C++ przyszBy do mnie w przera|ajcym [nie po dBugiej nocy spdzonej na programowaniu. Oczywi[cie, mo|na zaprojektowa jzyk programowania, w którym wa|ne informacje s umieszczone na szarym koDcu  przykBadami mog by Forth i PostScript  ale, na szcz- [cie, Perl nie jest takim jzykiem. 44 | RozdziaB 2. UkBad kodu Lepszym rozwizaniem jest dzielenie dBugich wierszy przed operatorem. Dziki temu ka|dy wiersz kontynuowanego wyra|enia bdzie zaczynaB si od operatora, co w kodzie Perla jest niezwykBe. Kiedy osoba czytajca kod bdzie przesuwa wzrok wzdBu| lewej krawdzi, natych- miast zauwa|y, |e wcity wiersz jest dalszym cigiem poprzedniego. Bardzo istotne jest równie| wcicie drugiego i nastpnych wierszy. Kontynuowanych wier- szy nie nale|y przesuwa do nastpnego poziomu wcicia, ale do pocztkowej kolumny wyra- |enia, do którego nale|, tzn. |e nie nale|y pisa tak: push @steps, $steps[-1] + $radial_velocity * $elapsed_time + $orbital_velocity * ($phase + $phase_shift) - $DRAG_COEFF * $altitude ; lecz tak: push @steps, $steps[-1] + $radial_velocity * $elapsed_time + $orbital_velocity * ($phase + $phase_shift) - $DRAG_COEFF * $altitude ; UkBad ten ma dodatkow zalet  dwa argumenty instrukcji push s wizualnie oddzielone, dziki czemu Batwiej je odró|ni. Je[li wyra|enie rozciga si na wiele wierszy, warto umie[ci koDcowy [rednik w oddzielnym wierszu i w tej samej kolumnie, od której rozpoczyna si kontynuowany tekst. Kiedy czytel- nik bdzie przesuwaB wzrok wzdBu| operatorów rozpoczynajcych kolejne wiersze, napotkanie samotnego [rednika wyraznie zasygnalizuje mu, |e wyra|enie dobiegBo koDca. Wyra|enia nieterminalne Wyodrbniaj dBugie wyra|enia ze [rodka instrukcji. Poprzednia wskazówka dotyczy tylko sytuacji, w której dBugie wyra|enie jest ostatnim ele- mentem instrukcji. Je[li wystpuje ono w [rodku instrukcji, lepiej wyodrbni je w oddzielne przypisanie zmiennej, na przykBad: my $next_step = $steps[-1] + $radial_velocity * $elapsed_time + $orbital_velocity * ($phase + $phase_shift) - $DRAG_COEFF * $altitude ; add_step( \@steps, $next_step, $elapsed_time); zamiast: add_step( \@steps, $steps[-1] + $radial_velocity * $elapsed_time + $orbital_velocity * ($phase + $phase_shift) - $DRAG_COEFF * $altitude , $elapsed_time); Wyra|enia nieterminalne | 45 Dzielenie wyra|eD wedBug priorytetu Zawsze dziel dBugie wyra|enie na operatorze o najni|szym priorytecie. Jak pokazuj przykBady w poprzednich dwóch podrozdziaBach, podczas dzielenia wyra|enia na wiele wierszy ka|dy wiersz powinien rozpoczyna si od operatora o niskim priorytecie. Dzielenie wierszy na operatorach o wy|szym priorytecie mo|e sprawi, |e nieuwa|ny czytelnik bBdnie zinterpretuje obliczenia. Poni|szy ukBad na przykBad mo|e zasugerowa, |e dodawania i odejmowania zachodz przed mno|eniami: push @steps, $steps[-1] + $radial_velocity * $elapsed_time + $orbital_velocity * ($phase + $phase_shift) - $DRAG_COEFF * $altitude ; Je[li konieczne jest podzielenie wiersza na operatorze o wysokim priorytecie, nale|y wci dal- szy cig wiersza o jeden poziom wzgldem pocztku wyra|enia: push @steps, $steps[-1] + $radial_velocity * $elapsed_time + $orbital_velocity * ($phase + $phase_shift) - $DRAG_COEFF * $altitude ; Dziki tej strategii podwyra|enia o wy|szym priorytecie pozostaj wizualnie  blisko siebie . Przypisania Dziel dBugie instrukcje przed operatorem przypisania. Czsto dBug instrukcj, która wymaga podzielenia, jest przypisanie. W takich przypadkach mo|na zastosowa poprzedni reguB, ale prowadzi ona do kodu nieestetycznego i nieczy- telnego: $predicted_val = $average + $predicted_change * $fudge_factor ; Tego rodzaju instrukcje lepiej dzieli przed operatorem przypisania, pozostawiajc w pierw- szym wierszu tylko nazw zmiennej. Nastpny wiersz nale|y wci o jeden poziom i umie[ci w nim operator przypisania, który bdzie peBniB funkcj znacznika kontynuacji: $predicted_val = $average + $predicted_change * $fudge_factor; Metoda ta czsto pozwala zmie[ci praw stron przypisania w jednym wierszu, tak jak w po- wy|szym przykBadzie. Je[li jednak wyra|enie po prawej stronie nadal jest za dBugie, nale|y podzieli je ponownie na operatorze o niskim priorytecie, w sposób zasugerowany w poprzed- niej wskazówce: 46 | RozdziaB 2. UkBad kodu $predicted_val = ($minimum + $maximum) / 2 + $predicted_change * max($fudge_factor, $local_epsilon); Inn strategi jest dzielenie dBugich instrukcji za operatorem przypisania: $predicted_val = $average + $predicted_change * $fudge_factor; Metoda ta ma jednak opisany wcze[niej problem: uniemo|liwia wykrycie kontynuacji wiersza bez prze[ledzenia go a| do prawego marginesu kodu, a  nienacechowane wcicie drugiego wiersza mo|e wprowadzi w bBd nieuwa|nego czytelnika. Problem czytelno[ci staje si szcze- gólnie dotkliwy, kiedy zmienna, której przypisywana jest warto[, sama jest dBuga: $predicted_val{$current_data_set}[$next_iteration] = $average + $predicted_change * $fudge_factor; a wBa[nie w takich sytuacjach przypisanie zwykle wymaga podziaBu. Dzielenie wiersza przed operatorem przypisania uBatwia identyfikacj dBugich przypisaD, poniewa| operator pozostaje blisko wyra|enia: $predicted_val{$current_data_set}[$next_iteration] = $average + $predicted_change * $fudge_factor; Operator trójkowy Formatuj w kolumny wyra|enia z kaskadowymi operatorami trójkowymi. Operator trójkowy zachca do tworzenia szczególnie dBugich wyra|eD. Poniewa| elementy ? oraz : tego operatora maj bardzo niski priorytet, prosta interpretacja reguBy dzielenia dBugich wyra|eD nie sprawdza si w tym przypadku, bowiem prowadzi do instrukcji w rodzaju: my $salute = $name eq $EMPTY_STR ? 'Customer' : $name =~ m/\A((?:Sir|Dame) \s+ \S+)/xms ? $1 : $name =~ m/(.*), \s+ Ph[.]?D \z/xms ? "Dr $1" : $name; które s bardzo nieczytelne. Seri operatorów trójkowych najlepiej uBo|y w dwóch kolumnach: # Kiedy klient ma na nazwisko.. TytuBujemy go... my $salute = $name eq $EMPTY_STR ? 'Customer' : $name =~ m/\A((?:Sir|Dame) \s+ \S+) /xms ? $1 : $name =~ m/(.*), \s+ Ph[.]?D \z /xms ? "Dr $1" : $name ; Innymi sBowy, nale|y dzieli seri operatorów trójkowych przed ka|dym dwukropkiem, wy- równujc dwukropki z operatorem poprzedzajcym pierwszy warunek. Dziki temu testy utwo- rz kolumn. Nastpnie trzeba wyrówna znaki zapytania w taki sposób, aby mo|liwe wyniki operatora trójkowego równie| tworzyBy kolumn. Na koniec nale|y wci ostatni wynik (nie- poprzedzony znakiem zapytania) tak, |eby równie| znalazB si w kolumnie wyników. Ten specjalny ukBad zmienia nieczyteln sekwencj operatorów trójkowych w prost tabel wyszukiwania  dla danego warunku w pierwszej kolumnie u|y odpowiedniego wyniku z drugiej. Operator trójkowy | 47 UkBadu tabelarycznego mo|na u|y nawet wtedy, gdy instrukcja zawiera tylko jeden operator trójkowy: my $name = defined $customer{name} ? $customer{name} : 'Sir or Madam' ; Dziki temu kolejni programi[ci bd mogli Batwiej dodawa do tabeli kolejne mo|liwo[ci. Ide t zbadamy dokBadniej w podrozdziale  Operatory trójkowe w ukBadzie tabelarycznym w rozdziale 6. Listy Umieszczaj dBugie listy w nawiasach okrgBych. Przecinek jest operatorem tylko w kontek[cie skalarnym; na listach jest separatorem elemen- tów. Dlatego przecinki na listach wielowierszowych lepiej traktowa jak terminatory. Co wi- cej, Batwo pomyli wielowierszow list z sekwencj instrukcji, poniewa| wizualna ró|nica midzy przecinkiem a [rednikiem jest niewielka. Ze wzgldu na mo|liwo[ nieporozumieD warto jasno oznaczy list wielowierszow jako list. Je[li wic konieczne jest podzielenie listy na wiele wierszy, nale|y umie[ci j w nawiasie okr- gBym. Nawias otwierajcy podkre[la fakt, |e nastpujce po nim wyra|enie jest list, a nawias zamykajcy jednoznacznie wskazuje, |e lista dobiegBa koDca. Podczas formatowania instrukcji zawierajcej wielowierszow list nale|y umie[ci nawias otwierajcy w tym samym wierszu, w którym znajduje si poprzednia cz[ instrukcji. Na- stpnie trzeba podzieli list po ka|dym przecinku, umieszczajc jednakow liczb elementów w ka|dym wierszu i wcinajc te wiersze o jeden poziom w stosunku do instrukcji. Nawias za- mykajcy nale|y umie[ci na tym samym poziomie wcicia, na jakim jest instrukcja, na przykBad: my @months = qw( StyczeD Luty Marzec KwiecieD Maj Czerwiec Lipiec SierpieD WrzesieD Pa|dziernik Listopad GrudzieD ); for my $item (@requested_items) { push @items, ( "ZupeBnie nowy $item", "W peBni odnowiony $item", "Sfatygowany stary $item", ); } print ( 'Przetwarzam ', scalar(@items), ' elementów o ', time, "\n", ); 48 | RozdziaB 2. UkBad kodu Warto pamita, |e ostatni element na li[cie równie| powinien by opatrzony przecinkiem, cho nie jest to wymagane syntaktycznie. Podczas pisania wielowierszowych list zawsze nale|y u|ywa nawiasów okrgBych (w stylu K&R), umieszcza tyle samo elementów w ka|dym wierszu i pamita, |e w kontek[cie listy przecinek nie jest operatorem, wic reguBa dzielenia przed operatorem w tym przypadku nie obowizuje. Innymi sBowy, nie nale|y pisa tak: my @months = qw( StyczeD Luty Marzec KwiecieD Maj Czerwiec Lipiec SierpieD WrzesieD Pa|dziernik Listopad GrudzieD ); for my $item (@requested_items) { push @items, "ZupeBnie nowy $item" , "W peBni odnowiony $item" , "Sfatygowany stary $item" ; } print 'Przetwarzam ' , scalar(@items) ,' elementów o ' , time , "\n" ; W podrozdziale  Cienkie przecinki , w rozdziale 4. podano inne przesBanki do umieszczania list w nawiasie okrgBym. Zautomatyzowane formatowanie Wymuszaj stosowanie wybranego stylu kodowania. Na dBu|sz met najlepiej wywiczy siebie i innych czBonków zespoBu w konsekwentnym, ra- cjonalnym i czytelnym stylu kodowania, takim jak zasugerowany wcze[niej. Czasem brakuje jednak na to czasu lub siB. Wtedy mo|na pój[ na kompromis i wybra narzdzie do formato- wania kodu, które trzeba bdzie stosowa przed przekazaniem programu do przejrzenia albo publicznej prezentacji. DoskonaBe narzdzie do formatowania kodu Perla, to perltidy. Jest ono dostpne bezpBatnie w witrynie SourceForge pod adresem http://perltidy.sourceforge.net i oferuje szerok gam opcji konfiguracyjnych, które pozwalaj okre[li wcicia, ukBad ograniczników bloków, wyrówny- wanie kolumn oraz pozycjonowanie komentarzy. Za pomoc programu perltidy mo|na przeksztaBci poni|szy kod: if($sigil eq '$'){ if($subsigil eq '?'){ $sym_table{substr($var_name,2)}=delete $sym_table{locate_orig_var($var_name)}; $internal_count++;$has_internal{$var_name}++ } else { ${$var_ref} = q{$sym_table{$var_name}}; $external_count++; $has_external{$var_name}++; Zautomatyzowane formatowanie | 49 }} elsif ($sigil eq '@'&&$subsigil eq '?') { @{$sym_table{$var_name}} = grep {defined $_} @{$sym_table{$var_name}}; } elsif ($sigil eq '%' && $subsigil eq '?') { delete $sym_table{$var_name}{$EMPTY_STR}; } else { ${$var_ref} = q{$sym_table{$var_name}} } w co[ bardziej czytelnego: if ( $sigil eq '$' ) { if ( $subsigil eq '?' ) { $sym_table{ substr( $var_name, 2 ) } = delete $sym_table{ locate_orig_var($var_name) }; $internal_count++; $has_internal{$var_name}++; } else { ${$var_ref} = q{$sym_table{$var_name}}; $external_count++; $has_external{$var_name}++; } } elsif ( $sigil eq '@' && $subsigil eq '?' ) { @{ $sym_table{$var_name} } = grep {defined $_} @{ $sym_table{$var_name} }; } elsif ( $sigil eq '%' && $subsigil eq '?' ) { delete $sym_table{$var_name}{$EMPTY_STR}; } else { ${$var_ref} = q{$sym_table{$var_name}}; } Zauwa|my, |e zmodyfikowana wersja speBnia reguBy formatowania podane w niniejszym roz- dziale. Aby osign taki rezultat, nale|y skonfigurowa plik .perltidyrc w nastpujcy sposób: -l=78 # Maksymalna szeroko[ wiersza: 78 kolumn -i=4 # Poziom wcicia: 4 kolumny -ci=4 # Wcicie kontynuowanego wiersza: 4 kolumny -st # Wyniki na STDOUT -se # BBdy na STDERR -vt=2 # Maksymalne [cie[nienie w pionie -cti=0 # Bez dodatkowego wcinania nawiasów zamykajcych -pt=1 # Zrednie [cie[nienie nawiasów okrgBych -bt=1 # Zrednie [cie[nienie nawiasów kwadratowych -sbt=1 # Zrednie [cie[nienie nawiasów klamrowych -bbt=1 # Bez spacji przed przecinkami -nsfs # Bez zmniejszania wcicia dBugich BaDcuchów w cudzysBowie -nolq -wbb="% + - * / x != == >= <= =~ !~ < > | & >= < = **= += *= &= <<= &&= -= /= |= >>= ||= .= %= ^= x=" # PodziaB przed wszystkimi operatorami Nakaz formatowania kodu z wykorzystaniem okre[lonego narzdzia pozwala te| unikn obiekcji, kBótni i wygBaszania dogmatów nieodBcznie zwizanych z ka|d dyskusj na temat ukBadu kodu. Je[li caB prac wykonuje program perltidy, programi[ci mog przyj nowe zale- cenia praktycznie bez wysiBku. Wystarczy, |e ustawi w edytorze makro, które na |danie  uporzdkuje kod. 50 | RozdziaB 2. UkBad kodu

Wyszukiwarka

Podobne podstrony:
Java Aplikacje?zodanowe Najlepsze rozwiazania jabnar
Ajax dla zaawansowanych Architektura i najlepsze rozwiazania
Kraj SEJM NIE ROZWIÄ„ZANY
ZARZÄ„DZANIE FINANSAMI cwiczenia zadania rozwiazaneE
RozwiÄ…zanie umowy o pracÄ™ za wypowiedzeniem
06 Zadania z rozwiÄ…zaniamiidd47
Zarzadzanie jakoscia rozwiazanie testu

więcej podobnych podstron