Nie ma chyba zawodu, którego przedstawiciele popełnialiby więcej błędów niż programiści. No, może oprócz futurologów i ekspertów politycznych, ale oni nie ponoszą konsekwencji swoich błędów – opinia publiczna zwykle zapomina o prognozach, zanim się zdążą okazać błędne, więc można się bezkarnie mylić notorycznie. Programiści tak dobrze nie mają – błędy muszą systematycznie poprawiać, a poprawki te kosztują przy przeciętnym projekcie około jednej trzeciej czasu pracy. Czemu jest tak źle, skoro programowaniem – w przeciwieństwie do polityki – nie zajmują się przecież byle kretyni?
Cóż, pokażmy na przykładzie, jak to tajemnicze programowanie wygląda.
Żeby rzecz była zrozumiała dla laików, pomińmy wszelkie możliwe szczegóły techniczne i wiedzę tajemną. Zamiast tego wyobraźmy sobie, że możemy zaprogramować komputer, po prostu opisując mu pożądane działania po ludzku – i spróbujmy w ten sposób przedstawić jakieś prościutkie zadanie. Na przykład działanie budzika w komórce. Powiedzmy, że chcemy mieć prostacki budzik, w którym ustawiamy godzinę i minutę, a on będzie nam codziennie dzwonić. Mniejsza o samo ustawianie czasu – załóżmy, że to już mamy zrobione razem z całym interfejsem i ładnym czerwonym przyciskiem do wyłączania budzika, musimy więc tylko zaimplementować dzwonienie.
Jeśli aktualny czas w zegarku jest równy czasowi ustawionemu w budziku, włącz dzwonek.
Jeśli został wciśnięty czerwony przycisk, wyłącz dzwonek.
Nic prostszego, prawda? No to ustawmy budzik i przetestujmy… Ups, nie działa. Czemu? Ano temu, że w budziku ustawiamy tylko godzinę i minutę, a w zegarku są jeszcze sekundy – a dla komputera 7:00:00 to nie to samo co 7:00, więc warunek nie jest spełniony. Poprawmy:
Jeśli aktualna godzina i minuta jest równa godzinie i minucie ustawionej w budziku, włącz dzwonek.
Jeśli został wciśnięty czerwony przycisk, wyłącz dzwonek.
Testujemy ponownie – i dzwonek się ładnie włączył, ale wyłączyć się nie chce. Dlaczego? Dlatego, że podane warunki są sprawdzane w kółko, więc natychmiast po wyłączeniu dzwonka komputer stwierdza, że godzina i minuta się zgadza, więc włącza go ponownie i nie ma sposobu, żeby temu zapobiec, dopóki nie minie pełna minuta, czas przestanie się zgadzać i czerwony przycisk w końcu zadziała. Robimy zatem kolejną poprawkę:
Jeśli aktualna godzina i minuta jest równa godzinie i minucie ustawionej w budziku i nie wciśnięto czerwonego przycisku, włącz dzwonek.
Jeśli został wciśnięty czerwony przycisk, wyłącz dzwonek i zapamiętaj, że wciśnięto czerwony przycisk.
Dobra, teraz dzwonek grzecznie się wyłącza – ale następnego dnia już nie włącza się w ogóle. Co tym razem? No cóż, komputer cały czas pamięta, że wciśnięto czerwony przycisk, więc warunek na odpalenie dzwonka nie jest spełniony – i już nigdy nie będzie. Jak to naprawić?
Jeśli aktualna godzina i minuta jest równa godzinie i minucie ustawionej w budziku i nie wciśnięto dzisiaj czerwonego przycisku, włącz dzwonek.
Jeśli został wciśnięty czerwony przycisk, wyłącz dzwonek i zapamiętaj, że wciśnięto czerwony przycisk.
Teraz budzik działa już codziennie – ale jeszcze nie ma happy endu. Co się bowiem stanie, jeśli po przebudzeniu przestawimy go na późniejszą godzinę? No właśnie – budzik nie zadzwoni, bo przycisk został już dzisiaj wciśnięty. Jeszcze jedna poprawka…
Jeśli aktualna godzina i minuta jest równa godzinie i minucie ustawionej w budziku i nie wciśnięto dzisiaj czerwonego przycisku, włącz dzwonek.
Jeśli został wciśnięty czerwony przycisk, wyłącz dzwonek i zapamiętaj, że wciśnięto czerwony przycisk.
Jeśli czas w budziku został zmieniony, zapomnij, że wciśnięto czerwony przycisk.
Uff, nareszcie wszystko działa jak należy.
I w tym momencie wchodzi klient, cały na biało, i oznajmia, że jednak musimy dorobić jeszcze przycisk drzemki. Klient nasz pan, więc dorabiamy – tu już litościwie oszczędzę Wam kolejnych kroków, ograniczając się do efektu końcowego:
Jeśli aktualna godzina i minuta jest równa godzinie i minucie ustawionej w budziku i nie wciśnięto dzisiaj żadnego przycisku, włącz dzwonek.
Jeśli rezerwowy budzik jest aktywny, aktualna godzina i minuta jest równa godzinie i minucie ustawionej w rezerwowym budziku i nie wciśnięto w ciągu ostatniej minuty przycisku drzemki, włącz dzwonek.
Jeśli został wciśnięty czerwony przycisk, wyłącz dzwonek i zapamiętaj, że wciśnięto czerwony przycisk.
Jeśli został wciśnięty przycisk drzemki, wyłącz dzwonek, zapamiętaj, że wciśnięto przycisk drzemki, aktywuj rezerwowy budzik i ustaw go na godzinę o pięć minut późniejszą od aktualnej.
Jeśli czas w budziku został zmieniony, deaktywuj rezerwowy budzik i zapomnij, że wciśnięto którykolwiek przycisk.
Czy na pewno końcowego? A może została tu jeszcze jakaś niedoróbka? Śmiało, spróbujcie przeanalizować ten niby-kod i odpowiedzieć w komentarzu (obecnych na sali programistów proszę o niepodpowiadanie).
Ten przykład daje chyba wystarczające wyobrażenie, jak łatwo jest zrobić błąd przy pisaniu kodu. A przecież cały czas mówimy tu o programiku zupełnie trywialnym, który nawet napisany w prawdziwym kodzie zmieściłby się z grubsza na ekranie – cóż więc powiedzieć o dużych profesjonalnych projektach, przy których budzik wygląda jak fajerwerk przy rakiecie kosmicznej, z całymi tonami drobnych niuansów i zależności…
Wierzę, że mając to wszystko na uwadze, spojrzycie na programistów i ich nieuniknione błędy nieco łaskawszym okiem.
Komentarze
„Nie ma chyba zawodu, którego przedstawiciele popełnialiby więcej błędów niż programiści”
Moim zdaniem jest wręcz przeciwnie. W mało którym zawodzie popełnia się tak mało błędów.
Weźmy pod uwagę mały program. Mały program oznacza dla mnie około 10 tysięcy linii kodu źródłowego. Zazwyczaj jest w nim kilka błędów, powiedzmy że 5.
Kto w innym zawodzie potrafiłby napisać tyle linii tekstu z co najwyżej pięcioma błędami? 10 tysięcy wierszy to 200 stron tekstu, licząc 50 linijek na stronę. Liczy się każdy błąd: nadmiarowy przecinek, brakujący przecinek, zamieniona kolejność, wszystko.
To jedna sprawa. A druga to ta, że współczesne programy wykorzystują wiele bibliotek czy frameworków, które też zawierają błędy, braki w dokumentacji, czy działają w sposób zaskakujący. Przykładem tego ostatniego jest Query by example w bibliotece Hibernate, które działa pod warunkiem że nie wyszukujemy po kluczu.
Trochę podobnie ma lekarz: niby wszystko poszło ze sztuką, ale u konkretnego pacjenta coś może zadziałać zupełnie inaczej niż jest to w podręcznikach opisane.
No i jest jeszcze koordynacja dużych grup ludzi: użytkownik, który nie do końca wie czego chce (będzie wiedział dopiero jak dostanie zrobiony program), analityk który wysłuchał użytkownika, ale niedokładnie spisał jego życzenia, kierownik zespołu który uznał że dany projekt nie jest priorytetowy i należy go skończyć jak najszybciej, jak najmniejszym kosztem, administratorzy którzy przygotowali środowisko testowe w niewłaściwy sposób, no i na końcu łańcucha pokarmowego programista który zbiera cięgi za wszystko.
Programiści robią mniej błędów niż zwykli ludzie, tyle tylko że każdy ich najmniejszy błąd jest od razu widoczny. W innych branżach widać tylko grube błędy, a w IT po prostu nie ma drobnych błędów.
Jeśli potrafisz napisać dziesięć tysięcy linii kodu, popełniając przy tym tylko pięć błędów, to wielki szacun – takiej perfekcji nawet programiści sond kosmicznych w NASA nie osiągają. Oczywiście mam na myśli wszystkie błędy, nie tylko te, które weszły na produkcję – choć nawet wtedy byłaby to całkiem niezła liczba.
Poza tym zasadniczo masz rację: poziom precyzji myślenia, jaki muszą utrzymywać programiści, jest z wielkim trudem lub w ogóle nieosiągalny dla przeciętnego śmiertelnika, a tolerancja komputerów na błędy zerowa – i to też próbowałem zademonstrować w notce. Pozostałe problemy to już rzecz wtórna: koordynacja, komunikacja i cudze błędy zdarzają się chyba w każdej branży.