Błędy (bugi) są bardzo ciekawym zjawiskiem w programowaniu. Jakże często zdarza nam się mówić "to źle działa", "tu jest na pewno jakiś błąd" itp. Rodzi się pytanie, jak w deterministycznym środowisku może zaistnieć błąd? Programista pisze kod, a następnie komputer przetwarza go na kod maszynowy i wykonuje w kółko kilka operacji na liczbach binarnych. Gdzie jest tu miejsce na błąd? Mniej więcej od połowy lat 90., kiedy pewna seria procesorów Pentium miała faktyczną usterkę techniczną, komputery w zasadzie "nie mylą się". Skąd zatem błędy? Bugi?
Otóż, wg mnie, występują następujące zasadnicze źródła "błędów" (zachowań systemu niezgodnych z przeznaczeniem; pomijam błędy składniowe):
- niejasne lub sprzeczne wymagania
- niedbałość, ograniczenia techniczne
- niejawne założenia
O ile o pierwszych dwóch przyczynach napisano bardzo wiele i wszyscy zdają sobie z nich świetnie sprawę, o tyle niejawne założenia uważam za zaniedbane, dlatego chciałbym zanalizować ich szkodliwość.
Ileż razy zdarzyło się Wam siedzieć nad debuggerem kilka godzin zanim zorientowaliście się, że analizowana usterka wynika z tego, że inny programista założył coś o jakimś fragmencie kodu? Np. "A no tak, bo ta metoda spodziewa się czegoś tam..."? NullPointerException to chyba najczęściej lecący wyjątek w Javie, a z czego on wynika? Oczywiście z założenia, że w tym miejscu na pewno nie pojawi się wartość null. Trudno w takich przypadkach mówić o czyjejkolwiek winie bezpośrednio.
Problemy z niejawnymi założeniami występują wszędzie tam, gdzie
- nie ma żadnej dokumentacji (albo jest marna)
- brak komunikacji w zespole
- brak głębokiego zrozumienia działania systemu
- architektura systemu jest nadmiernie skomplikowana i niezrozumiała
Dobry kod to taki, który nie tylko "działa", ale też ma czysty prosty i przejrzysty design oraz jest dobrze przetestowany (wszyscy to wiedzą). Zazwyczaj w parze z tymi cechami idzie jawność założeń. Przeglądając dobry kod i dokumentację, zyskujemy jasność co do założeń: na czym ta klasa operuje (a na czym nie), jakich argumentów ta metoda się spodziewa (a jakich nie) itd. Postulat jawności założeń prowadzi nas wprost w ramiona Design By Contract, metodologii, w której zależności pomiędzy klasami formułuje się na zasadzie kontraktu między dostawcą usługi a klientem (analogicznie do prawdziwych kontraktów biznesowych).
Jaki płynie wniosek z tych rozważań? Według mnie, powinniśmy pójść w stronę pełnej jawności założeń. Wszystkie publiczne metody, nagłówki klas, powinny jasno i dobitnie stwierdzać: co przyjmują jako parametr, a co nie (np. czy może być null), co zwracają itd. Idea ta wywodzi się ze wspomnianego Design by Contract - jasno określić kontrakty klas (zasady, na jakich działają), żeby potem nie było "niejasności" (jak w życiu). Jestem także za tworzeniem "zewnętrznej" dokumentacji (poza kodem) - oczywiście nie jakichś opasłych tomów, ale kilka zwięzłych diagramów, rzeczowy opis działania jakiegoś mechanizmu z pełną specyfikacją założeń - wtedy nie będziemy musieli narażać się na wielogodzinne "odkrywanie" nieujawnionych domniemań.