You are on page 1of 15

IDZ DO

PRZYKADOWY ROZDZIA
SPIS TRECI

KATALOG KSIEK
KATALOG ONLINE
ZAMW DRUKOWANY KATALOG

TWJ KOSZYK
DODAJ DO KOSZYKA

Zarzdzanie projektami
informatycznymi. Subiektywne
spojrzenie programisty
Autor: Joel Spolsky
Tumaczenie: Mikoaj Szczepaniak
ISBN: 83-7361-869-4
Tytu oryginau: Joel on Software: And on Diverse and
Occasionally Related Matters That Will Prove of Interest
to Software Developers, Designers, and Managers, and to Those
Who, Whether by Good Fortune or Ill Luck, Work with Them in Some Capacity
Format: B5, stron: 360
Poznaj skuteczne i techniki kierowania prac zespou programistw

CENNIK I INFORMACJE
ZAMW INFORMACJE
O NOWOCIACH
ZAMW CENNIK

CZYTELNIA
FRAGMENTY KSIEK ONLINE

Wydawnictwo Helion
ul. Chopina 6
44-100 Gliwice
tel. (32)230-98-63
e-mail: helion@helion.pl

Dowiedz si, jak przygotowa specyfikacj funkcjonaln produktu,


ktr wszyscy odpowiednio zrozumiej
Stwrz moliwy do zrealizowania harmonogram prac nad projektem
Zbuduj zesp projektowy, zatrudniajc odpowiednich ludzi
Pamitaj o prawach Murphyego
Projekty informatyczne s do specyficznym typem projektw. Zarzdzanie nimi te
rni si od tradycyjnego zarzdzania projektami. Informatycy to ludzie pracujcy
w sposb zdecydowanie odmienny od standardowo przyjtego, co z kolei sprawia,
e kierowanie zespoem informatykw wymaga odpowiedniego podejcia.
Metody zarzdzania projektami zaczerpnite z innych bran czsto nie sprawdzaj si
przy projektach IT. Na szczcie metody skutecznego zarzdzania projektami
informatycznymi naprawd istniej. Poznanie ich jest niezbdne do tego, aby kierowany
przez Ciebie projekt zakoczy si w terminie i zmieci w wyznaczonym budecie.
Zarzdzanie projektami informatycznymi. Subiektywne spojrzenie programisty to zbir
zasad zarzdzania projektami IT spisanych przez programist, ktrego niespodziewanie
mianowano kierownikiem projektu. Czytajc t ksik, dowiesz si, jak zbudowa
skutecznie dziaajcy zesp programistw, jak stworzy realny harmonogram prac
i pisa specyfikacje, ktre rzeczywicie oka si przydatne. Przekonasz si,
e stosowanie gotowych rozwiza dostpnych w internecie nie zawsze zdaje egzamin,
i nauczysz si, jak wane jest testowanie kodu na kadym etapie projektu.
Przeczytasz o strategii tworzenia oprogramowania i dowiesz si, dlaczego pozornie
skazane na sukces projekty IT upadaj.
12 zasad skutecznego zarzdzania projektami IT
Tworzenie uytecznych specyfikacji funkcjonalnych
Planowanie harmonogramu realizacji projektu
Testowanie i usuwanie bdw
Tajniki skutecznej rekrutacji
Korzystanie z rozwiza open source
Dobr odpowiedniej technologii
Naucz si skutecznie zarzdza projektami,
w ktrych dotychczas brae udzia jako programista

Spis treci
O Autorze ......................................................................................... 9
Wprowadzenie ................................................................................ 11

Cz I

Bity i bajty: praktyczne elementy programowania ...........15

Rozdzia 1. Wybr jzyka programowania .......................................................... 17


Rozdzia 2. Powrt do podstaw ......................................................................... 19
Rozdzia 3. Test Joela: 12 krokw ku lepszemu oprogramowaniu ....................... 29
Rozdzia 4. Absolutne minimum na temat formatu Unicode i innych
systemw kodowania znakw, ktre nie moe by obce
adnemu programicie (bez wyjtku!) .............................................. 43
Rozdzia 5. Niegrone specyfikacje funkcjonalne. Cz 1: Po co to wszystko? .... 55
Rozdzia 6. Niegrone specyfikacje funkcjonalne. Cz 2: Czym waciwie
jest specyfikacja? ........................................................................... 63
Rozdzia 7. Niegrone specyfikacje funkcjonalne. Cz 3: Ale jak? ................ 73
Rozdzia 8. Niegrone specyfikacje funkcjonalne. Cz 4: Wskazwki .............. 77
Rozdzia 9. Niegrone harmonogramy tworzenia oprogramowania ....................... 85
Rozdzia 10. Codzienne kompilacje s Twoimi sprzymierzecami ......................... 97
Rozdzia 11. Bezwzgldne usuwanie bdw ...................................................... 103
Rozdzia 12. Pi wiatw ............................................................................... 109
Rozdzia 13. Przygotowywanie papierowych prototypw .................................... 117
Rozdzia 14. Nie pozwl, aby astronauci architektur decydowali
o Twoich projektach ..................................................................... 119
Rozdzia 15. Ognia i naprzd ............................................................................ 123
Rozdzia 16. Rzemioso .................................................................................... 127

Zarzdzanie projektami informatycznymi. Subiektywne spojrzenie programisty

Rozdzia 17. Trzy bdne opinie w wiecie informatyki ....................................... 133


Rozdzia 18. Dwukulturowo ........................................................................... 139
Rozdzia 19. Zbieraj od uytkownikw raporty o bdach
rb to automatycznie! ............................................................... 147

Cz II

Zarzdzanie zespoem programistw ............................157

Rozdzia 20. Partyzancki poradnik rekrutacji ..................................................... 159


Rozdzia 21. Szkodliwy wpyw motywujcego systemu kar i nagrd ................ 173
Rozdzia 22. Pi wymwek, z powodu ktrych nie korzystamy
z pomocy testerw ....................................................................... 177
Rozdzia 23. Szkodliwe skutki przeczania zada rozdzielonych
pomidzy pracownikw ................................................................. 185
Rozdzia 24. Rzeczy, ktrych nigdy nie naley robi: cz pierwsza .................. 189
Rozdzia 25. Sekret gry lodowej: rozwizanie .................................................. 195
Rozdzia 26. Prawo Nieszczelnych Abstrakcji .................................................... 203
Rozdzia 27. Lord Palmerston o programowaniu ................................................ 209
Rozdzia 28. Mierniki ....................................................................................... 217

Cz III By jak Joel: Przypadkowo wybrane opinie


na nieprzypadkowe tematy ..........................................219
Rozdzia 29. Rick Chapman w poszukiwaniu gupoty ......................................... 221
Rozdzia 30. Czym zajmuj si psy w tym kraju? ............................................... 225
Rozdzia 31. Realizacja zada z perspektywy pocztkujcego programisty ........... 231
Rozdzia 32. Dwie historie ................................................................................ 237
Rozdzia 33. McDonalds kontra The Naked Chef .............................................. 243
Rozdzia 34. Nic nie jest tak proste, na jakie wyglda ....................................... 249
Rozdzia 35. W obronie syndromu NIH .............................................................. 253
Rozdzia 36. Pierwszy list w sprawie strategii: Ben & Jerry kontra Amazon ........ 257
Rozdzia 37. Drugi list w sprawie strategii: problem jajka i kury ........................ 267
Rozdzia 38. Trzeci list w sprawie strategii: wrmy do podstaw! ...................... 275
Rozdzia 39. Czwarty list w sprawie strategii: Bloatware i mit 80-20 ................. 281
Rozdzia 40. Pity list w sprawie strategii: ekonomia otwartego dostpu
do kodu rdowego ...................................................................... 285
Rozdzia 41. Tydzie szalestwa prawa Murphyego .......................................... 295
Rozdzia 42. Jak Microsoft przegra wojn na interfejsy API ............................... 299

Spis treci

Cz IV Przydugi komentarz na temat technologii .NET ............315


Rozdzia 43. Microsoft oszala .......................................................................... 317
Rozdzia 44. Nasza strategia .NET .................................................................... 323
Rozdzia 45. Przepraszam szanownego pana, mog prosi o program czcy? ..... 327

Dodatki .......................................................................................331
Dodatek A Najlepsze pytania do Joela ............................................................ 333
Skorowidz ..................................................................................... 347

Rozdzia 1.

Wybr jzyka
programowania
Niedziela, 5 maja 2002 roku.
Dlaczego programici wybieraj do realizowanych przez siebie zada pewne jzyki
programowania, rezygnujc z wszystkich pozostaych?
Kiedy potrzebuj przede wszystkim szybkoci, czsto wybieram surowy jzyk C.
Kiedy chc opracowa moliwie may program, ktry bdzie dziaa w systemie operacyjnym Windows, zazwyczaj decyduj si na jzyk C++ ze statycznie doczanymi
klasami biblioteki MFC.
Jeli jednak potrzebuj graficznego interfejsu uytkownika (GUI), ktry bdzie prawidowo funkcjonowa w systemach Mac, Windows i Linux, zazwyczaj wybieram Jav.
Chocia mechanizmy obsugi tego typu interfejsw dostpne w tym jzyku nie s doskonae, utworzone rozwizanie z pewnoci bdzie przenone.
Kiedy niezbdne jest zastosowanie techniki szybkiego tworzenia oprogramowania
z odpowiednim interfejsem GUI, zwykle uywam Visual Basica, chocia mam wiadomo zwizanych z tym ogranicze oraz cisych zwizkw z jedn platform (systemem operacyjnym Windows).
W przypadku narzdzi wykonywanych w wierszu polece, ktre bd uruchamiane
wycznie na komputerach z systemami UNIX i ktre nie musz by specjalnie szybkie,
moemy uy Perla.
Jeli tworzone oprogramowanie ma by wykonywane w przegldarce internetowej,
jedynym sensownym rozwizaniem jest zastosowanie jzyka JavaScript. Natomiast
w przypadku procedury skadowanej SQL-a przewanie musimy wybra odpowiedni
pochodn standardu jzyka SQL stosowan w danym serwerze bazy danych.

18

Cz I Bity i bajty: praktyczne elementy programowania

Co jest najwaniejsze?
Prawda jest taka, e najczciej wybieramy jzyk programowania, kierujc si wycznie
jego skadni. Zawsze wolaem jzyki z nawiasami klamrowymi wyznaczajcymi
poszczeglne bloki kodu (C/C++, C# i Jav). Syszaem ju mnstwo opinii na temat
czynnikw decydujcych o tym, czy skadnia jzyka programowania jest dobra czy za.
Nie dabym si jednak przekona do skadni, ktra wymusza zajmowanie 20 MB przez
same redniki.
Szczeglnie interesujcym elementem technologii .NET jest strategia programowania
dla wielu platform w rnych jzykach. Jej ide jest moliwo wybrania dowolnego,
odpowiadajcego nam jzyka programowania (ktrych jest mnstwo) i napisania oprogramowania, ktrego dziaanie nie bdzie si rni od funkcjonowania odpowiednich
programw napisanych w innych jzykach.
Jzyki VB.NET i C#.NET s niemal identyczne wszelkie niezgodnoci midzy nimi
wynikaj z drobnych rnic skadniowych. Wszystkie pozostae jzyki programowania,
ktre maj ambicje wkroczy do wiata technologii .NET, musz obsugiwa przynajmniej minimalny zestaw mechanizmw i typw, ktry bdzie wspdziaa z innymi
elementami tej technologii. Jednak w jaki sposb mona tworzy w technologii .NET
programy wiersza polece dla systemu UNIX? Czy ta technologia umoliwia tworzenie maych (mniejszych od 16 KB) programw dla systemu Windows?
Wydaje si zatem, e technologia .NET umoliwia wybr jzyka na podstawie jego
cechy, ktra interesuje nas najbardziej skadni.

Rozdzia 2.

Powrt do podstaw
Wtorek, 5 grudnia 2001 roku.
Znaczna cz dyskusji prowadzonych na mojej witrynie internetowej dotyczya oglnych kwestii, takich jak: analiza porwnawcza technologii .NET i jzyka Java, omwienie strategii XML, problem przechodzenia na nowe technologie, zestawianie konkurencyjnych strategii, projektowanie oprogramowania, architektur itp. Kade z tych
zagadnie w pewnym sensie przypomina przekadaniec (rodzaj ciasta). Na najwyszym
poziomie jest oglna strategia oprogramowania, bezporednio pod ni architektura
(np. .NET), pod ktr dziaaj poszczeglne produkty, np. narzdzia wytwarzania
oprogramowania (jak Java lub platformy, np. Windows).
Chcesz pozna kolejne warstwy? Prosz bardzo: biblioteki DLL, obiekty, funkcje.
Jeszcze niej? W kocu dotrzemy do pojedynczych wierszy kodu napisanych w wybranym jzyku programowania.
Poziom wyrae jzyka programowania jest dla Ciebie zbyt wysoki? Poniej chciabym
si zaj procesorami, czyli kawakiem krzemu przetwarzajcym bajty. Przypumy,
e jeste pocztkujcym programist. Zapomnij o wszystkim, czego dowiedziae si
o programowaniu, oprogramowaniu i zarzdzaniu, aby wrci na najniszy poziom
podstawowego modelu Von Neumanna. Wyrzu z pamici wszelkie dowiadczenia
zwizane z prac w rodowisku J2EE. Myl tylko o bajtach.
Dlaczego w ogle to robimy? Sdz, e najwikszym bdem popenianym przez programistw nawet na najwyszych poziomach architektur oprogramowania jest
niedostateczna lub obarczona bdami wiedza na temat procesw zachodzcych na
najniszych poziomach. Mona w ten sposb zbudowa wspaniay paac na grzskim
gruncie; zamiast betonowych fundamentw powstanie niestabilne rumowisko. Taki
paac co prawda adnie wyglda, ale od czasu do czasu popkaj kafelki w azience i nie
bdzie wiadomo, co jest rdem braku stabilnoci naszego dziea.
Sprbuj wic, przynajmniej teraz, si odpry zapraszam na krtki spacer z atrakcjami w postaci praktycznych wicze stosowania jzyka programowania C.

20

Cz I Bity i bajty: praktyczne elementy programowania

Pamitasz sposb obsugi acuchw w jzyku C? Kady z nich skada si z pewnej


liczby bajtw, z ktrych ostatni reprezentuje znak null rwny 01. Wybr takiego rozwizania wie si z dwoma do oczywistymi nastpstwami:
1. Brak moliwoci sprawdzenia, gdzie dany acuch si koczy (a wic wyznaczenia

jego dugoci) bez jego iteracyjnego przeszukania pod ktem miejsca


przechowywania koczcego znaku null.
2. acuch nie moe zawiera adnych zer, zatem nie mona umieszcza

w acuchach jzyka C dowolnych nieprzetworzonych danych binarnych,


takich jak obrazy w formacie JPEG.
Dlaczego acuchy jzyka programowania C dziaaj w taki sposb? Wynika to wprost
z tego, e mikroprocesor PDP-7, dla ktrego zaprojektowano system operacyjny UNIX
i wanie jzyk C, przetwarza acuchy typu ASCIZ. Skrt ASCIZ oznacza format
ASCII z Z (zerem) na kocu.
Czy to jedyny sposb skadowania acuchw w tym jzyku? Nie. W rzeczywistoci
jest to jedna z najgorszych istniejcych metod przechowywania acuchw. W przypadku bardziej rozbudowanych programw, interfejsw API, systemw operacyjnych
i bibliotek klas, naley jak ognia unika acuchw typu ASCIZ. Dlaczego?
Rozwaania zaczn od napisania wasnej wersji kodu funkcji strcat, ktra dodaje jeden
acuch na koniec drugiego:
void strcat(char* dest, char* src)
{
while(*dest) dest++;
while(*dest++ = *src++);
}

Wystarczy krtka analiza tej funkcji, aby przekona si, jakie jest jej faktyczne dziaanie. Po pierwsze, przegldnij pierwszy acuch w poszukiwaniu koczcego znaku
null. Kiedy uda si to zrobi, zobacz iteracyjnie znaki drugiego acucha i kolejno je
skopiuj do pierwszego.
Takie podejcie do problemu obsugi i konkatenacji acuchw byo moe dobre w czasie,
gdy swoje opracowanie przygotowywali Kernighan i Ritchie2, ale w rzeczywistoci
stwarza mnstwo problemw. Oto jeden z nich. Przypumy, e chcesz umieci zbir
imion w jednym, duym acuchu:
char bigString[1000]; /* Nigdy nie wiem, ile przydzieli pamici... */
bigString[0] = '\0';
strcat(bigString, "Jan, ");
strcat(bigString, "Pawe, ");
strcat(bigString, "Jerzy, ");
strcat(bigString, "Jzef ");

Wicej informacji na temat acuchw znakw w jzyku programowania C znajdziesz na stronie


internetowej www-ee.eng.hawaii.edu/Courses/EE150/Book/chap7/subsection2.1.1.2.html.

B. Kernighan, D. Ritchie, The C Programming Language, Second Edition, Prentice Hall 1988.

Rozdzia 2. Powrt do podstaw

21

Powyszy przykad powinien dziaa, prawda? Tak. Raczej nie bdzie z nim adnych
problemw.
Jaka jest efektywno zastosowanej techniki? Czy nasz program jest wystarczajco
szybki? Czy nie mona zrobi tego szybciej? Czy jest skalowalny? Czy majc milion
acuchw, powiniene uy analogicznego rozwizania?
Nie. Zaprezentowany kod wykorzystuje algorytm roztargnionego malarza. Czym malarz
zasuy sobie na ten przydomek? Powinien to wyjani poniszy dowcip:
Malarz dosta zlecenie pomalowania jezdni narysowania linii przerywanej na
rodku ulicy. Pierwszego dnia pooy na krawniku puszk farby i pomalowa
100 metrw. Niele! usysza od swojego szefa. Jeste naprawd szybki!.
Do kieszeni malarza trafia zotwka premii.
Nastpnego dnia udao mu si pomalowa tylko 50 metrw drogi. C, dzi nie
byo tak dobrze jak wczoraj, ale nadal jeste wydajnym pracownikiem. 50 metrw
to take sporo. Malarz znowu dosta zotwk premii.
Nastpnego dnia pomalowa tylko 10 metrw jedni. Co? 10 metrw? krzykn
rozzoszczony szef. To nie do przyjcia! Pierwszego dnia pomalowae 10 razy
duszy odcinek! Co si dzieje?.
Nic na to nie poradz odpar malarz. Codziennie mam dalej do mojej
puszki z farb!.

(Pytanie dodatkowe: jakie naprawd powinny by liczby wymienione w tym dowcipie?3).


Ten przecitny dowcip dosy dokadnie oddaje to, co dzieje si podczas wywoywania
przedstawionej przed momentem funkcji strcat. Poniewa pierwsza cz tej funkcji
za kadym razem przeglda cay acuch docelowy w poszukiwaniu koczcego znaku
null, funkcja jest zdecydowanie za wolna i nie zapewnia odpowiedniej skalowalnoci.
Okazuje si, e ten sam problem dotyczy znacznej czci wykorzystywanego na co
dzie kodu. Wiele systemw plikw jest implementowanych w taki sposb, e umieszczenie zbyt duej liczby plikw w pojedynczym katalogu ma bardzo negatywny wpyw
na wydajno ich przetwarzania, poniewa efektywno tego typu operacji dramatycznie
spada wraz ze wzrostem liczby obsugiwanych elementw (w tym przypadku tysicy
plikw). Aby si o tym przekona, sprbuj otworzy bardzo zapchany Kosz w systemie
Windows zanim zostan wywietlone umieszczone tam pliki, minie mnstwo czasu,
ktry z pewnoci nie jest liniowo zaleny od liczby tych plikw. Autorzy systemu
widocznie musieli gdzie zastosowa algorytm roztargnionego malarza. Za kadym
razem, gdy stwierdzisz, e mechanizm, ktrego wydajno powinna rosn liniowo
wraz z poszerzanym zbiorem danych wejciowych, funkcjonuje raczej jak mechanizm
kwadratowo zaleny od iloci tych danych, koniecznie powiniene poszuka w kodzie
ukrytych malarzy z puszkami farby na krawniku. Tego typu niedocignicia czsto
mona znale w naszych bibliotekach. Widok cigu wywoa funkcji strcat lub ptli
z takimi wywoaniami czsto nie jest wystarczajcym sygnaem, e ma si do czynienia
ze zoonoci kwadratow, a wanie tak jest w tym przypadku.
3

Matematyczn analiz tego zagadnienia znajdziesz na stronie discuss.fogcreek.com/techInterview/


default.asp?cmd=show&ixPost=153.

22

Cz I Bity i bajty: praktyczne elementy programowania

Jak mona to poprawi? Kilku sprytnych programistw jzyka C zaimplementowao


wasne metody mystrcat w nastpujcy sposb:
char* strcat(char* dest, char* src)
{
while(*dest) dest++;
while(*dest++ = *src++);
return --dest;
}

Co tak naprawd zrobiono? Minimalnym kosztem udao si wprowadzi mechanizm


zwracania wskanika na koniec nowego, duszego acucha. Dziki temu kod wywoujcy nasz funkcj moe wymusi dodawanie kolejnych acuchw bez koniecznoci
ponownego przeszukiwania acucha docelowego:
char bigString[1000]; /* Nigdy nie wiem, ile przydzieli pamici... */
char *p = bigString;
bigString[0] = '\0';
p = strcat(p, "Jan, ");
p = strcat(p, "Pawe, ");
p = strcat(p, "Jerzy, ");
p = strcat(p, "Jzef ");

Takie rozwizanie oczywicie gwarantuje liniow (zamiast kwadratowej) zoono


obliczeniow, zatem nie jest naraone na spadek wydajnoci w przypadku wielokrotnego wykonywania operacji czenia acuchw.
Projektanci jzyka programowania Pascal mieli wiadomo tego problemu i rozwizali go przez umieszczanie licznika bajtw w pierwszym bajcie acucha. acuchy
konstruowane na podstawie tego mechanizmu s w zwizku z tym nazywane acuchami
Pascala. Poniewa jednak najwiksza warto, ktr mona reprezentowa za pomoc
pojedynczego bajta, to 255, dugoci acuchw Pascala jest ograniczona do 255 znakw;
ale poniewa acuchy nie zawieraj koczcego znaku null, ostatecznie zajmuj tyle
samo pamici co acuchy ASCIZ. Ogromn zalet acuchw Pascala jest to, e nigdy
nie musisz stosowa kosztownych ptli tylko po to, by okreli ich dugo. Zamiast
tego, wyznaczenie dugoci acucha Pascala wymaga uycia pojedynczego polecenia.
Rnica w wydajnoci obu mechanizmw jest ogromna.
Stary system operacyjny Macintosh wykorzystywa acuchy Pascala wszdzie, gdzie
si dao. Wielu programistw jzyka C pracujcych na innych platformach wykorzystywao acuchy Pascala wanie ze wzgldu na ich szybko. S one wewntrznie
wykorzystywane np. w Excelu to wyjania, dlaczego w wielu miejscach ich dugo
jest ograniczana do 255 bajtw, ale te pozwala odpowiedzie na pytanie, z czego wynika
niesamowita szybko Excela.
Bardzo dugo byo tak, e kiedy chciae umieci acuch Pascala w naszym kodzie
jzyka C, musiae uywa podobnych operacji przypisania:
char* str = "\006Witaj!";

To prawda, musiae samodzielnie zlicza bajty i kodowa je na stae w pierwszym


bajcie tworzonego acucha. Bardziej leniwi programici stosowali nastpujcy zabieg,
ktry dodatkowo spowalnia ich programy:

Rozdzia 2. Powrt do podstaw

23

char* str = "*Witaj!";


str[0] = strlen(str) - 1;

Zwr uwag, e mamy w tym przypadku do czynienia zarwno z acuchem zakoczonym znakiem null (za wstawienie tego znaku odpowiada kompilator), jak i z acuchem Pascala. Zwykle nazywaem tego typu konstrukcje cholernymi acuchami,
poniewa uywanie sformuowania acuchy Pascala zakoczone znakiem null zajmowao zbyt wiele czasu. Poniewa jednak ta ksika moe trafi take w rce dzieci,
trzeba raczej uywa tego drugiego, do niezrcznego okrelenia.
Odszedem troch od zagadnienia, ktre interesuje nas najbardziej. Pamitasz ten
wiersz kodu?
char bigString[1000];

/* Nigdy nie wiem, ile przydzieli pamici... */

Poniewa mielimy si zaj bitami, z pewnoci nie zignoruj problemu przydziau


waciwej iloci pamici. Powinienem podej do tej kwestii bardziej profesjonalnie,
a wic okreli liczb potrzebnych bajtw i przydzieli odpowiedni obszar w pamici.
Mylisz, e nie powinienem?
Warto pamita, e jaki sprytny haker, gdy uzyska dostp do mojego kodu rdowego, zauway, e przydzielam tylko 1000 bajtw w nadziei, e to wystarczy. Wtedy
znajdzie sposb zmuszenia mojego programu do poczenia w moim acuchu danych
o cznej dugoci 1100 bajtw. W ten sposb nadpisze ramk stosu i tak zmieni adres
zwracania, aby moja funkcja, koczc prac, przekazywaa sterowanie do kodu napisanego przez tego hakera. Wanie tak w praktyce wyglda problem nazywany czsto
wraliwoci na atak przepenienia bufora. Taki bd by pierwszym wykrytym sabym
punktem programu Microsoft Outlook, ktry umoliwia wamania komputerowe nawet
pocztkujcym adeptom tej sztuki.
No dobrze, przyjmijmy, e wszyscy programici s rwnie leniwi. Tak czy owak, powinni
zawsze stara si w rozsdny sposb okrela, ile pamici bdzie potrzebne do skadowania definiowanej struktury danych.
Jzyk C z pewnoci tego nie uatwia. Wrc do przykadu z imionami:
char bigString[1000]; /* Nigdy nie wiem, ile przydzieli pamici... */
char *p = bigString;
bigString[0] = '\0';
p = strcat(p, "Jan, ");
p = strcat(p, "Pawe, ");
p = strcat(p, "Jerzy, ");
p = strcat(p, "Jzef ");

Ile pamici powinno si przydzieli? Sprbuj zrobi to zadanie w jedyny suszny sposb:
char bigString;
int i = 0;
i = strlen("Jan, ");
+ strlen("Pawe, ");
+ strlen("Jerzy, ");

24

Cz I Bity i bajty: praktyczne elementy programowania


+ strlen("Jzef ");
bigString = (char*)malloc(i+1);
/* Pamitaj o przestrzeni na koczcy znak null! */
...

Nie wierz wasnym oczom! Myl, e jednak nie powiniene pokazywa tej ksiki
swoim dzieciom. Nie chc zrzuca winy na Ciebie, wic trzymaj si blisko, bo mamy
do czynienia z czym naprawd interesujcym.
Musisz przeglda wszystkie acuchy wejciowe tylko po to, by okreli, jak dugi
powinien by acuch wyjciowy, dopiero potem przegldaj je ponownie w trakcie
waciwej operacji ich czenia. W przypadku acuchw Pascala przynajmniej operacja
strlen bya szybka. Moe powiniene sprbowa napisa tak wersj funkcji strcat,
ktra bdzie automatycznie przydzielaa odpowiedni obszar pamici?
Przedstawione rozwizanie wywouje kolejne problemy tym razem puapk jest
przydzielanie pamici (tzw. alokatorw pamici). Czy wiesz, jak dziaa funkcja malloc?
Jej dziaanie bazuje na utrzymywanej jednokierunkowej licie dostpnych blokw pamici
nazywanej wolnym acuchem. Kiedy wywoujesz funkcj malloc, lista ta jest przegldana w poszukiwaniu pierwszego bloku pamici, ktry bdzie odpowiednio duy,
by zrealizowa biece danie (pomieci wskazan struktur danych). Wybrany
blok jest nastpnie dzielony na dwa jeden o danym rozmiarze i drugi zawierajcy
bajty nadmiarowe. Pierwszy blok przechowuje nasz struktur danych, drugi (jeli istnieje) jest z powrotem umieszczany na licie wolnych blokw. Kiedy wywoasz funkcj
free, zwolniony blok zostanie ponownie doczony do listy wolnych blokw pamici.
Z czasem bloki pamici s wic dzielone na coraz mniejsze kawaki i kiedy zadasz
wikszego obszaru pamici, moe si okaza, e odpowiedni blok nie istnieje. Funkcja malloc poprosi wwczas o czas i zacznie naprawia wolny acuch, sortujc ca
list (wedug adresw) i czc ssiadujce ze sob mae bloki danych w coraz wiksze
obszary. Moe to zabra mnstwo czasu. Efekt jest taki, e funkcja malloc nigdy nie
gwarantuje naleytej szybkoci, poniewa za kadym razem musi przeszuka list wolnych blokw pamici, a niekiedy (w trudnych do przewidzenia momentach) dodatkowo
porzdkuje t list i wydajno caej funkcji jest bardzo maa (wydajno funkcji malloc
przypomina wwczas raczej mechanizmy czyszczenia pamici, zatem wszelkie teorie
na temat niepotrzebnych opnie powodowanych przez procedury czyszczenia pamici
s nie do koca prawdziwe, poniewa typowa implementacja funkcji malloc jest obarczona ryzykiem bardzo podobnych opnie, chocia by moe w mniejszym zakresie).
Sprytniejsi programici minimalizuj potencjalne opnienia generowane przez
funkcj malloc, stosujc operacje przydzielania blokw pamici, ktrych rozmiary s zawsze potgami liczby 2; wiadomo: 2 bajty, 4 bajty, 8 bajtw, 16 bajtw,
18446744073709551616 bajtw itd. Z oczywistych wzgldw (przynajmniej dla osb,
ktre kiedykolwiek bawiy si klockami lego) w ten sposb mona zminimalizowa
liczb niepodanych operacji fragmentowania blokw z wolnego acucha. Chocia
takie dziaania s z pozoru niepotrzebn strat przestrzeni pamiciowej, nietrudno
obliczy, e maksymalna nadwyka tej przestrzeni nigdy nie przekroczy 50 procent.
Nasz program nie zajmie wic wicej ni dwukrotno pamici, ktrej rzeczywicie
potrzebuje, co w wikszoci przypadkw nie stanowi wikszego problemu.

Rozdzia 2. Powrt do podstaw

25

Przypumy, e napisae udoskonalon wersj funkcji strcat, ktra w razie koniecznoci


automatycznie przydziela potrzebn pami dla bufora danych wyjciowych (acucha
docelowego). Czy ta funkcja zawsze powinna przydziela acuchowi obszar dokadnie
odpowiadajcy jego rozmiarowi? Mj nauczyciel i mentor, Stan Eisenstat4, zasugerowa
mi kiedy, e wywoujc funkcj realloc, zawsze powinienem podwaja obszar pamici,
ktry by wczeniej przydzielony. W takim przypadku nigdy nie musiabym wywoa
tej funkcji wicej ni lg(n) razy, co jest niezym wynikiem nawet dla ogromnych acuchw (co wicej, takie rozwizanie oznacza, e nigdy bezproduktywnie nie zajmuje
si wicej ni 50 procent pamici).
Tak czy inaczej tu, w wiecie bajtw, ycie stale si komplikuje. Czy nie bye zadowolony, kiedy odkrye, e nie musisz ju programowa w jzyku C? Mamy obecnie do dyspozycji tak znakomite jzyki programowania, jak: Perl, Java, Visual Basic
oraz XSLT, ktre cakowicie zwalniaj z obowizku analizowania opisanych przed
chwil problemw po prostu w jaki sposb same o wszystko dbaj. Niekiedy jednak
co przestaje dziaa w najmniej spodziewanym czasie i miejscu (np. instalacja wodna
pka na rodku pokoju gocinnego) i dopiero wwczas musisz si zastanowi, czy naley
uywa klasy String czy moe StringBuilder. Podobne problemy najczciej wynikaj z tego, i wspczesne kompilatory nadal nie potrafi same oceni, co prbujemy
osign za pomoc pewnych struktur i na si ratuj nas przed przypadkowym wprowadzeniem w kodzie algorytmu roztargnionego malarza.
Niniejsze rozwaania sprowokowaem, publikujc na swojej witrynie internetowej krtk
rozpraw, w ktrej stwierdziem, e nie jest moliwe zaimplementowanie szybkiej obsugi
typowego zapytania jzyka SQL (np. SELECT author FROM books), jeli przetwarzane
dane s skadowane w formacie XML5. Na wypadek, gdyby kto wwczas nie zrozumia,
co miaem na myli i niejako przy okazji omawiania efektywnego wykorzystywania
procesora, warto bliej przeanalizowa ten problem.
W jaki sposb relacyjne bazy danych implementuj zapytanie SELECT author FROM
books? W relacyjnej bazie danych kady wiersz tabeli (w tym przypadku tabeli books)
ma dokadnie tak sam dugo (wyraon w bajtach) jak wszystkie pozostae. Co
wicej, kade pole takiego wiersza jest przesunite o sta liczb bajtw wzgldem
pocztku wiersza. Przykadowo, jeli kady wiersz tabeli books ma 100 bajtw, a pole
author jest przesunite wzgldem pocztku wiersza o 23 bajty, to nazwiska autorw
s przechowywane w bajtach 23, 123, 223, 323 itd. Jak wobec tego powinien wyglda
kod przechodzcy do nastpnego rekordu w wyniku tego zapytania? Na przykad tak:
pointer += 100;

To tylko jeden rozkaz procesora, musi wic dziaa baaardzo szybko.


Zobacz teraz tabel books w wejciowym dokumencie XML:
<?xml bla bla bla>
<books>
<book>
<title>UI Design for Programmers</title>
4

Patrz strona internetowa www.cs.yale.edu/people/faculty/eisenstat.html.

Patrz strona internetowa www.joelonsoftware.com/articles/fog0000000296.html.

Cz I Bity i bajty: praktyczne elementy programowania

26

<author>Joel Spolsky</author>
</book>
<book>
<title>The Chop Suey Club</title>
<author>Bruce Weber</author>
</book>
</books>

Krtkie pytanie: jak powinien wyglda kod przechodzcy do nastpnego rekordu?


Hm
Dobry programista powiedziaby teraz, e naley przetworzy ten kod XML i zbudowa w pamici odpowiednie drzewo, ktre umoliwioby stosunkowo szybk prac
z tymi danymi. Ilo pracy, jak w takim przypadku musiaby wykona nasz procesor
(tylko po to, by wykona zapytanie SELECT author FROM BOOKS), niejednego czowieka
zanudziaby na mier. Kady, kto mia kiedy do czynienia z pisaniem kompilatorw,
doskonale zdaje sobie spraw z tego, e wanie analiza leksykalna i skadniowa stanowi
najwolniejsz cz caego procesu kompilacji. Wystarczy powiedzie, e takie przetwarzanie danych (analiza leksykalna, skadniowa i budowa drzewa) wymaga stosowania wielu operacji na acuchach, ktre jak wiemy s bardzo wolne. Co wicej,
rozwizanie bazujce na drzewie zakada, e dysponujemy odpowiedni iloci pamici,
aby umieci tam wszystkie dane wejciowe. W przypadku relacyjnych baz danych czas
potrzebny na przejcie do kolejnego rekordu jest stay i w praktyce wymaga uycia
pojedynczego rozkazu procesora. To bardzo dua rnica, a dziki plikom odwzorowania pamici dodatkowo istnieje moliwo wczytywania tylko tych stron pamici
dyskowej, ktre bd po chwili przetwarzane. W przypadku danych zapisanych w formacie XML, jeli przeprowadzi si operacj wstpnego przetworzenia i umieszczenia
potrzebnych informacji w pamici, czas przechodzenia pomidzy rekordami take bdzie
stay, ale bardzo wyduy si czas uruchamiania aplikacji. Jeli natomiast zrezygnuje
si z przetwarzania tych danych na pocztku, czas wykonywania operacji przejcia
z jednego rekordu do nastpnego bdzie si rni w zalenoci od dugoci biecego
rekordu, a operacja ta zawsze bdzie wymagaa wykonania setek rozkazw procesora.
Z przedstawionej analizy wynika, e nie mona stosowa formatu XML, jeli przy duej
iloci danych oczekuje si wysokiej wydajnoci systemu. Jeli jednak operujemy na
niewielkiej iloci danych lub jeli opracowywane oprogramowanie nie musi by szybkie,
format XML w zupenoci wystarczy. Gdy chcemy korzysta z zalet obu wiatw (relacyjnych baz danych i formatu XML), trzeba opracowa mechanizm skadowania takich
metadanych doczanych do tradycyjnych dokumentw XML (jak w przypadku licznika
bajtw w acuchach Pascala), ktre bd stanowiy czytelne wskazwki o lokalizacji
danych, aby nie musie ich dodatkowo przetwarza. Wwczas nie bdzie jednak mona
wykorzystywa edytorw tekstu do modyfikowania naszych plikw XML, poniewa
mogoby to zniszczy te metadane nie bd to wic prawdziwe dokumenty XML.
Zwracam si do kilku czytelnikw, ktrzy dotarli ze mn a tutaj mam nadziej, e
moje rozwaania czego was nauczyy i zmobilizoway do ponownego przemylenia
poruszonych kwestii. Myl, e przedstawiona analiza nudnych zagadnie, typowych
dla pierwszego roku studiw informatycznych (jak choby faktycznego dziaania funkcji
strcat i malloc) pokazuje, e warto czasem wrci do korzeni podczas podejmowania

Rozdzia 2. Powrt do podstaw

27

decyzji odnonie strategii i architektury nowoczesnych rozwiza na podstawie technologii XML. Jako zadanie domowe zastanw si, dlaczego ukady firmy Transmeta s
tak powolne. Sprbuj take stwierdzi, dlaczego oryginalna specyfikacja jzyka
HTML dla tabel zostaa tak skonstruowana, e uytkownicy modemw analogowych
trac mnstwo czasu, czekajc na otwarcie stron z wielkimi tabelami. Odpowiedz te
na pytanie, dlaczego komponenty modelu COM s bardzo szybkie tylko do momentu,
w ktrym zmusisz je do przetwarzania midzyprocesowego. I dlaczego programici,
ktrzy zaprojektowali system NT, umiecili sterowniki ekranu w przestrzeni jdra
zamiast w przestrzeni uytkownika?
Wszystkie te kwestie wymagaj przeprowadzenia odpowiedniej analizy na poziomie
bajtw, a uzyskane w ten sposb odpowiedzi maj zasadniczy wpyw na decyzje podejmowane na najwyszym poziomie podczas doboru architektury i strategii. Dlatego
wanie moja wizja nauczania studentw pierwszego roku informatyki przewiduje
konieczno wprowadzania technik programowania od podstaw, czyli najlepiej od
jzyka programowania C wraz z wyjanieniem rozkazw procesora kryjcych si za
poszczeglnymi funkcjami tego jzyka. Jestem szczerze zatroskany, kiedy sysz, e
wiele programw nauczania informatyki traktuje Jav jako dobry jzyk do nauki, tylko
dlatego e Java jest prosta nie wymaga analizy tych wszystkich kwestii zwizanych
z acuchami i przydzielaniem pamici, a pozwala szybko budowa programy obiektowe zoone z wielu moduw. Takie podejcie jest z pedagogicznego punktu widzenia
nie do przyjcia i w niedugim czasie doprowadzi do katastrofy. Cae pokolenia magistrw informatyki bd na kadym kroku wprowadzay do oprogramowania algorytmy roztargnionego malarza, nawet nie zdajc sobie z tego sprawy, poniewa bdzie im
brakowao elementarnej wiedzy na temat faktycznych technik reprezentowania acuchw, ktre nie s przecie widoczne w kodzie Perla. Jeli chcesz kogo nauczy czego
naprawd poytecznego, musisz rozpocz zajcia od wprowadzenia zagadnie zwizanych z najniszym poziomem funkcjonowania oprogramowania. Trzeba najpierw
przez trzy tygodnie przekazywa najprostsze i jednoczenie najistotniejsze informacje,
aby przygotowa waciwy grunt do skutecznego rozwizywania naprawd trudnych
problemw.

You might also like