| Termin | Definicja |
|---|---|
| Funkcja deterministyczna | Funkcja deterministyczna zawsze zwraca ten sam wynik dla identycznych argumentów wejściowych. Funkcja deterministyczna jako przewidywalny model obliczeńFunkcja deterministyczna to sposób opisywania obliczeń, w którym rezultat wynika wyłącznie z przekazanych danych wejściowych oraz z reguł zapisanych w definicji funkcji. Jeżeli do funkcji trafi dokładnie ten sam zestaw argumentów, przy zachowaniu tych samych warunków obliczenia, otrzymany zostanie ten sam wynik. Dotyczy to zarówno prostych działań matematycznych, jak i procedur używanych w programach komputerowych, systemach operacyjnych oraz narzędziach diagnostycznych. Istotą deterministyczności jest powtarzalność. Funkcja nie podejmuje decyzji na podstawie przypadku, aktualnej godziny, położenia pliku, kolejności zdarzeń ani niejawnego stanu środowiska. Można ją traktować jak dobrze określoną instrukcję: dostarczenie danych uruchamia ustalony ciąg operacji, a zakończenie tego ciągu prowadzi do z góry określonego rezultatu. Gdy argumentem jest liczba, wynikiem może być inna liczba. Gdy argumentem jest tekst, funkcja może zwrócić jego długość, zmienioną postać albo informację o zgodności z wzorcem. Przykładowo funkcja obliczająca pole prostokąta na podstawie długości boków jest deterministyczna, ponieważ dla tych samych boków zawsze stosuje ten sam wzór. Podobnie działa funkcja zamieniająca wielkie litery na małe, pod warunkiem że zasady kodowania i reguły językowe pozostają niezmienione. Deterministyczność nie oznacza, że funkcja musi być prosta. Duży algorytm sortowania, sprawdzania poprawności danych lub wyliczania sumy kontrolnej także może mieć tę właściwość. Funkcja deterministyczna w programie i kontekst technicznyW praktycznym programowaniu deterministyczność odnosi się nie tylko do widocznych argumentów, lecz także do wszystkich danych, od których zależy obliczenie. Funkcja może wyglądać na deterministyczną, ale utraci tę cechę, jeśli podczas działania odczytuje bieżący czas, losową wartość, zmienną globalną, zawartość zewnętrznego pliku lub stan urządzenia. Z tego powodu przy ocenie funkcji trzeba sprawdzić cały kontekst wykonania, a nie tylko listę parametrów znajdującą się w nagłówku procedury. Za deterministyczne można uznać na przykład dodawanie dwóch liczb, obliczanie reszty z dzielenia, porównanie dwóch napisów według ustalonych zasad oraz przekształcenie obrazu, jeśli wszystkie ustawienia są przekazywane jawnie. Jeżeli jednak ta sama procedura pobiera konfigurację z nieokreślonego źródła albo korzysta ze zmiennego ustawienia regionalnego, wynik może się zmienić mimo identycznych argumentów. W takim przypadku funkcja jest deterministyczna tylko warunkowo, czyli przy założeniu niezmienności dodatkowych zależności. Warto odróżnić funkcję deterministyczną od funkcji bezstanowej. Funkcja bezstanowa nie przechowuje informacji pomiędzy wywołaniami, natomiast deterministyczność opisuje zgodność wyników dla tych samych danych i warunków. Funkcja może mieć stan wewnętrzny, lecz pozostawać przewidywalna, jeżeli stan jest częścią jawnego wejścia albo jego zmiany są ściśle określone. W praktyce najłatwiej testuje się jednak funkcje bezstanowe, ponieważ ograniczają liczbę czynników, które trzeba kontrolować. Przeciwieństwem funkcji deterministycznej jest funkcja zależna od przypadku lub od zmiennego otoczenia. Generator liczb pseudolosowych, odczyt aktualnej daty, pobranie danych z sieci oraz wybór wolnego zasobu systemowego mogą zwrócić różne rezultaty podczas kolejnych uruchomień. Nie oznacza to, że takie rozwiązania są błędne. Oznacza jedynie, że wymagają innego sposobu testowania, zapisu wyników i diagnozowania problemów. Funkcja deterministyczna a typowe problemy z powtarzalnościąJednym z częstych problemów jest niejawne korzystanie z danych znajdujących się poza argumentami. Program może wyświetlać różne wyniki, ponieważ funkcja odczytuje plik konfiguracyjny, zależny od użytkownika katalog roboczy albo ustawienia językowe systemu. Wtedy osoba analizująca kod może uznać procedurę za deterministyczną, choć w rzeczywistości na wynik wpływa wiele zmiennych. Utrudnia to odtwarzanie błędu, zwłaszcza gdy problem pojawia się tylko na wybranym komputerze. Inna przyczyna rozbieżności wiąże się z niedokładnością reprezentacji liczb. W obliczeniach zmiennoprzecinkowych te same działania mogą prowadzić do wartości bardzo zbliżonych, ale nie zawsze identycznych bit po bicie. Różnica może wynikać z kolejności operacji, zastosowanej biblioteki matematycznej albo rodzaju procesora. Sama reguła funkcji pozostaje określona, lecz sposób przechowywania danych może wymagać porównywania wyników z tolerancją zamiast sprawdzania pełnej równości. Problemy występują także wtedy, gdy funkcja modyfikuje przekazany obiekt. Kolejne wywołanie może otrzymać dane zmienione przez poprzednie wywołanie, mimo że kod przekazuje pozornie ten sam odnośnik. Takie zachowanie bywa mylone z losowością, chociaż przyczyną jest ukryta zmiana stanu. Pomocne jest rozdzielenie danych wejściowych od wynikowych, stosowanie kopii tam, gdzie jest to uzasadnione, oraz jasne dokumentowanie skutków ubocznych. W systemach wielozadaniowych dodatkowe znaczenie ma kolejność zdarzeń. Funkcja może otrzymywać te same wartości, lecz działać w otoczeniu, w którym inny proces zmienił plik, rejestr systemowy albo zasób urządzenia. W efekcie rezultat zależy od momentu wykonania. Aby przywrócić powtarzalność, należy przekazywać do funkcji wszystkie potrzebne dane, ograniczać dostęp do zmiennych globalnych i rozdzielać obliczenia od operacji wejścia-wyjścia. Funkcja deterministyczna w testach i praktycznych wskazówkachFunkcje deterministyczne dobrze nadają się do testów jednostkowych. Dla określonego zestawu argumentów można zapisać oczekiwany rezultat, a następnie wielokrotnie sprawdzać, czy implementacja zachowuje się zgodnie z założeniami. Warto uwzględniać zarówno zwykłe przypadki, jak i wartości graniczne: pusty tekst, zero, liczby ujemne, bardzo długie dane, powtarzające się elementy oraz wartości spoza przewidywanego zakresu. Przydatną metodą jest test powtarzalności. Te same dane przekazuje się funkcji wiele razy, a otrzymane wyniki porównuje. Jeżeli rezultaty różnią się, należy ustalić, czy przyczyną jest losowość, zmienny stan, wpływ środowiska, równoległe wykonanie, błąd w kodzie czy niedokładność numeryczna. Sam fakt wystąpienia różnicy nie wystarcza do rozpoznania źródła problemu, dlatego test powinien rejestrować także wersję programu, ustawienia środowiska, typ danych i kolejność operacji. W większych aplikacjach opłaca się oddzielać część obliczeniową od komunikacji z systemem. Odczyt pliku, pobranie informacji z urządzenia lub zapytanie do usługi zewnętrznej może zostać wykonane w jednej warstwie, a przetwarzanie uzyskanych danych w drugiej. Czysta część obliczeniowa otrzymuje wtedy jawne argumenty i może działać w sposób deterministyczny. Ułatwia to testy, analizę błędów oraz późniejszą wymianę źródła danych. Przy diagnozowaniu problemu technicznego należy sprawdzić, czy powtarzalność dotyczy samej funkcji, czy całego programu. Funkcja może zwracać prawidłowy wynik dla otrzymanego wejścia, podczas gdy błąd powstaje wcześniej, na etapie odczytu danych, konwersji formatu albo interpretacji ustawień. Pomocne jest zapisanie rzeczywistych argumentów i porównanie ich między poprawnym oraz wadliwym przebiegiem. Dzięki temu można odróżnić błąd logiki od problemu z urządzeniem, plikiem lub konfiguracją. Kiedy funkcja deterministyczna wymaga zgłoszenia do serwisuDo serwisu warto zgłosić się wtedy, gdy różne wyniki pojawiają się mimo potwierdzenia identycznych danych wejściowych, a przyczyna nie wynika z zamierzonej losowości ani z opisanej zależności od środowiska. Szczególną uwagę należy zwrócić na powtarzające się zawieszanie programu, uszkodzenia plików, błędy odczytu danych, nieoczekiwane restarty oraz rozbieżności występujące tylko na jednym komputerze. Objawy mogą wskazywać na problem z pamięcią, nośnikiem danych, chłodzeniem, zasilaniem lub konfiguracją systemu, choć sama funkcja deterministyczna jest pojęciem programistycznym i nie przesądza o źródle usterki. Przed przekazaniem sprzętu przydatne jest przygotowanie opisu: jakie dane zostały wprowadzone, jaki rezultat powinien wystąpić, jaki rezultat pojawia się faktycznie oraz czy błąd można odtworzyć. Warto również zanotować moment wystąpienia problemu i komunikat wyświetlany przez program. Takie informacje ułatwiają rozdzielenie błędu algorytmu od awarii środowiska pracy i pozwalają sprawniej zaplanować dalszą diagnostykę. W przypadku problemów z laptopem można skorzystać z pomocy Warszawskiego Pogotowia Komputerowego 24/7, gdzie diagnoza laptopa jest bezpłatna. Podczas analizy można sprawdzić, czy niestabilne działanie wynika z oprogramowania, danych wejściowych, ustawień systemowych albo fizycznego stanu urządzenia. Rozumienie funkcji deterministycznej pomaga dokładniej opisać objawy, ale nie zastępuje pełnej oceny sprzętu i środowiska, w którym wykonywany jest program. |