PRZEDMOWA DO WYDANIA POLSKIEGO
7
PRZEDMOWA
DO WYDANIA POLSKIEGO
Z błędami programistycznymi jest trochę tak, jak z potworem z jeziora Loch
Ness — nikt go tak naprawdę nie widział, co wcale nie upoważnia do kategoryczne-
go wnioskowania o jego nieistnieniu; gdyby jednak komuś udało się zaobserwować
go choć raz (i oczywiście fakt ten udokumentować), potwór przestałby być potwo-
rem, stając się kolejną pozycją w hierarchii Regnum Zoa i nie wzbudzając odtąd
żadnych sensacji. Na tej samej zasadzie żaden program nie jest bezbłędny, nawet
jeżeli wydaje się być takowym z bardzo dużym prawdopodobieństwem, bezspornie
udowodnić można bowiem jedynie istnienie błędów, nigdy zaś ich brak.
W przeciwieństwie do legendarnego potwora, błędy programistyczne nie mają
żadnego posmaku sensacji, za to niosą ze sobą całkiem realne — i poważne —
konsekwencje, w postaci straconego czasu, nadwerężonej reputacji twórców opro-
gramowania, zmarnowanych pieniędzy, a nawet nadszarpniętego zdrowia. Skoro
więc zdecydowaliśmy się powierzyć komputerom i informatyce najważniejsze z
aspektów naszego życia doczesnego, musimy jednocześnie wypracować rozwiąza-
nia chroniące nas przed owymi konsekwencjami. Niewystarczające okazują się tu
rozwiązania oczywiste, jak wytężona uwaga programistów, szczególna staranność
w wykonywaniu pracy itp.; wszystko to rzecz jasna jest jak najbardziej pożądane,
lecz musi być dodatkowo wsparte stosowną metodologią tworzenia oprogramo-
wania. Klasyczne ujęcie algorytmiczne, z rzeczywistym problemem na jednym bie-
gunie, a sformalizowanym opisem jego rozwiązania na drugim, musi być uzupełnione
trzecim elementem — owym demonem ludzkiej omylności, odciskającym swe pięt-
no na adekwatności wspomnianego opisu.
Pierwszym z założeń wspomnianej metodologii jest wybór takiego stylu pro-
gramowania, który a priori zmniejsza prawdopodobieństwo popełniania błędów.
Często zdarza się na przykład tak, iż wskutek zwykłej pomyłki przy wpisywaniu
kodu programu otrzymujemy inną poprawną konstrukcję, nie wzbudzającą żadnej
podejrzliwości ze strony kompilatora, lecz całkowicie sprzeczną z naszymi inten-
C:\WINDOWS\Pulpit\Szymon\Niezawodność oprogramowania\r00-1.doc
7
NIEZAWODNOŚĆ OPROGRAMOWANIA
cjami. Jeżeli świadomi tego faktu zastosujemy taki styl programowania, by błąd ty-
pograficzny równoważny był w większości przypadków błędowi syntaktyczne-
mu, znakomita większość takich „czeskich błędów” wykryta zostanie już na etapie
kompilacji.
Drugie założenie opiera się na praktycznym spostrzeżeniu, iż najgroźniejszymi
błędami są błędy głęboko ukryte, manifestujące się bardzo rzadko i niespodziewa-
nie. Błędy o wyraźnie widocznych i dających się reprodukować na żądanie konse-
kwencjach łatwiej mogą zostać rozpoznane i usunięte — należy więc dążyć do nada-
wania tworzonemu programowi jak największej „wrażliwości” w tym względzie.
I wreszcie — nawet najgorszy błąd w oprogramowaniu nie okaże się skrajnym
nieszczęściem, jeżeli nie spowoduje utraty cennych danych. Zdając sobie sprawę z
mniejszej lub większej zawodności tworzonego programu pamiętajmy o tym, iż
bezpieczeństwo przetwarzanych danych jest zadaniem najważniejszym.
Wymienione trzy założenia, akcentujące (kolejno) odporność, wrażliwość i
bezpieczeństwo tworzonego oprogramowania składają się na swoistą filozofię
zwaną programowaniem defensywnym — nazwa ta wydaje się wystarczają-
co dobitnie odzwierciedlać ów „obronny” aspekt programowania, jakim jest walka
programisty ze skutkami własnej niedoskonałości. Mimo dość ogólnego charakteru
przedstawionych zasad, filozofia ta nie jest jednak wyłącznie zbiorem pobożnych
życzeń, lecz z powodzeniem stosowana jest w praktyce — czego jednym z dowo-
dów jest właśnie niniejsza książka. Jej autor, doświadczony programista, kierujący
niegdyś zespołem programistycznym w firmie Microsoft, w przejrzysty sposób
prezentuje rozmaite detale programowania defensywnego na prostych przykładach
wyrażonych w języku C. Mimo pewnej tendencji do formułowania prezentowa-
nych stwierdzeń w postaci lakonicznych reguł, treść książki bardzo daleka jest od
zbędnego „teoretyzowania”. Jej wyjątkowo praktyczny charakter przejawia się
również w tym, iż obok zalecanych wzorców postępowania programistycznego au-
tor nie szczędzi przykładów zachowań niepożądanych, których był świadkiem pod-
czas wieloletniej współpracy z licznym gronem programistów o zróżnicowanych
cechach charakterologicznych. W szczególny sposób akcentuje pierwszorzędną
rolę programisty w dziele tworzenia niezawodnych programów i wyraźnie piętnuje
tendencję do spychania odpowiedzialności za błędy na zespoły testujące.
Skoro mowa o różnorodnych zabiegach mających na celu zwiększenie nieza-
wodności tworzonego oprogramowania, to nie mogę powstrzymać się od pewnej
refleksji osobistej. Rozpocznę od przypomnienia pewnego znanego w świecie pro-
gramistów błędu, którego konsekwencją było unicestwienie projektu kosztującego
miliony dolarów. Były wczesne lata sześćdziesiąte i jedynym dostępnym językiem
algorytmicznym był osławiony FORTRAN. Poniższy fragment
DO 10 I = 1,10
...
instrukcje
...
10 CONTINUE
powoduje dziesięciokrotne wykonanie ciągu instrukcji dla zmieniającej się od
1 do 10 zmiennej I. Jeżeli jednak pomyłkowo zamienić przecinek na kropkę,
pierwsza z cytowanych instrukcji zmienia się w instrukcję
8
C:\WINDOWS\Pulpit\Szymon\Niezawodność oprogramowania\r00-1.doc
PRZEDMOWA DO WYDANIA POLSKIEGO
9
DO 10 I = 1.10
dokonującą — uwaga — przypisania wartości 1.10 do zmiennej o nazwie
DO10I. Język FORTRAN zezwala bowiem zarówno na używanie zmiennych bez
ich deklarowania, jak i na dowolne wplatanie spacji do nazw zmiennych (spacje ta-
kie ignorowane są przez kompilator). Następujący dalej ciąg instrukcji wykonywany
jest jednokrotnie, dla przypadkowej (lub wynikającej z poprzednich obliczeń)
wartości zmiennej I. Tak błaha i jednocześnie kosztowna pomyłka nie mogłaby się
wydarzyć ani w C, ani w Pascalu, gdzie obowiązkowe jest zarówno deklarowanie
wszystkich używanych zmiennych, jak i wymóg „spójności” identyfikatorów. Przy-
kład ten udowadnia bardzo istotną tezę — tę mianowicie, iż jednym z elementów
programowania defensywnego może być wybór odpowiedniego języka
programowania. Autor książki pomija tę kwestię zupełnym milczeniem, ograni-
czając się wyłącznie do języka C — co jest poniekąd zrozumiałe wobec faktu, iż
język ten był bodaj jedynym powszechnie stosowanym w firmie Microsoft w cza-
sach, gdy powstawał oryginał niniejszej książki.
Tak się składa, iż moim ulubionym językiem programowania jest Pascal, z
którym związany jestem niemal od samych jego początków (dokładniej — od jego
pierwszej dostępnej w Polsce implementacji na CDC CYBER 70). Wielokrotnie
słyszałem i czytałem, jak programiści posługujący się językiem C++ odmawiają
Pascalowi miana „poważnego” języka, ograniczając jego rolę wyłącznie do celów
edukacyjnych. Jakby na przekór tym opiniom niedawno ukazała się szósta już wer-
sja (opartego na rozbudowanym Pascalu) Delphi, nie to jest jednak najważniejsze:
celem moich osobistych wywodów jest zwrócenie uwagi na fakt, iż Pascal jako ta-
ki charakteryzuje się znacznie większym stopniem defensywności niż C
czy C++ — kto nie wierzy, niech przeanalizuje prezentowane w niniejszej książce
przykłady rozmaitych błędów i zastanowi się, które z nich nie mogłyby wystąpić w
Pascalu (nie zezwalającym np. na używanie instrukcji przypisania w roli wyrażeń,
czy samodzielne definiowanie przeciążonych operatorów). Być może ów argument
w obronie zasłużonego Pascala okaże się komuś pomocny w wyborze pomiędzy
Delphi a C++Builderem jako potencjalnymi narzędziami do realizacji określonego
projektu.
I jeszcze jedno: zdecydowaliśmy się na wydanie niniejszej książki, mimo iż jej
oryginał powstał przed niemal ośmioma laty. W technologii informatycznej to
przecież cała epoka — tymczasem prawie całość prezentowanego materiału wciąż
zachowuje swą aktualność, co z jednej strony jest dowodem na istnienie pewnych
uniwersalnych idei tkwiących u samej istoty tworzenia oprogramowania, z drugiej
natomiast wymaga odrobiny dystansu czytelnika do pewnej szczególnej kwestii.
Otóż w sytuacji rozpowszechnienia się systemów operacyjnych wykorzystujących
chroniony ( protected) tryb pracy procesora (m.in. Windows 9x) wiele błędów pro-
gramistycznych prowadzi do wykonywania operacji nielegalnych z punktu widze-
nia samej architektury komputera, wskutek czego błędne programy często kończą
się błędem ochrony dostępu, zamiast działać w sposób losowy i (co ważniejsze)
destrukcyjny; można zaryzykować stwierdzenie, iż wzrost wspomnianej „defen-
sywności” nie ominął także sprzętu komputerowego. Szczególnie podatnymi na
awaryjne zakończenie są programy dokonujące odwoływania się do „nie swoich”
obszarów pamięci lub posługujące się wskaźnikami „wiszącymi”, zerowymi albo
niezainicjowanymi. Z treści książki można wywnioskować, iż autor obraca się ra-
C:\WINDOWS\Pulpit\Szymon\Niezawodność oprogramowania\r00-1.doc
9
NIEZAWODNOŚĆ OPROGRAMOWANIA
czej w kręgu trybu adresowania bezpośredniego ( real mode — chociaż nie brak
wzmianek o błędach ochrony dostępu) , w którym błędy tego rodzaju często prze-
chodzą niemal niezauważone. Nie zmienia to oczywiście w niczym faktu, iż pro-
gramy przejawiające wspomniane zachowanie są programami ewidentnie błędny-
mi, niezależnie od platformy systemowej, na której są uruchamiane.
Zagadnienie niezawodności oprogramowania, a tym bardziej — metodologii
programowania prowadzącej do owej niezawodności — wciąż jest zagadnieniem
znacznie mniej sformalizowanym niż wiele innych zagadnień algorytmicznych.
Niniejsza książka nie pretenduje więc do miana jakiegoś oficjalnego podręcznika
na ten temat (taki podręcznik trudno byłoby zrealizować w formie książki o tak
małej objętości), stanowi raczej rezultat osobistych (i notabene bardzo pouczają-
cych) doświadczeń autora. Jest więc rzeczą naturalną, iż wielu programistów-
praktyków mogłoby wzbogacić jej treść o własne uwagi, czy nawet zakwestiono-
wać zasadność niektórych poglądów autora. Ciekawi jesteśmy opinii naszych
Czytelników w tym względzie i oczekujemy na nie w naszej internetowej księdze go-
ści. Zaawansowanym Czytelnikom proponujemy ponadto pouczające doświadcze-
nie, polegające na przejrzeniu kodu źródłowego jakiegoś popularnego oprogramowania
— na przykład Delphi, czy rozmaitych odmian Linuksa — i zwrócenie uwagi na te
jego fragmenty, których określona postać podyktowana jest względami defensywno-
ści oprogramowania. Być może zaowocuje to większą niezawodnością własnego,
tworzonego teraz i w przyszłości, oprogramowania.
Mamy nadzieję, iż niniejsza książka przyczyni się do wielu sukcesów w walce
z plagą dokuczliwych błędów, krążących wciąż po oprogramowaniu i czyhających
na nic nie podejrzewających programistów. Jeżeli przyczyni się ona do uniknięcia
chociaż jednej nieprzespanej nocy albo zapobieże stracie wakacji, to będzie ozna-
czać, że było warto — z nadzieją na co pozostajemy.
W imieniu wydawnictwa
Andrzej Grażyński
w listopadzie 2001
10
C:\WINDOWS\Pulpit\Szymon\Niezawodność oprogramowania\r00-1.doc
PRZEDMOWA DO WYDANIA POLSKIEGO
11
C:\WINDOWS\Pulpit\Szymon\Niezawodność oprogramowania\r00-1.doc
11