Stosuj zasady programowania funkcjonalnego
Oryginalny tytuł: Apply Functional Programming Principles
Autor: Edward Garson
Programowanie funkcjonalne cieszy się ostatnio wzmożonym zainteresowaniem wśród społeczności programistów piszących w językach głównego nurtu. Po części jest to spowodowane tym, że pewne cechy paradygmatu funkcjonalnego czynią go szczególnie przydatnym przy rozwiązywaniu problemów powstających przy okazji przestawiania się naszej branży na środowiska wielordzeniowe. Mimo iż z pewnością jest to ważny obszar zastosowań, nie jest to powód, dla którego w niniejszym artykule będę namawiał Cię do zaprzyjaźnienia się z programowaniem funkcjonalnym.
Opanowanie paradygmatu programowania funkcjonalnego może znacząco podnieść jakość kodu, który tworzysz w różnorakich sytuacjach. Głębokie zrozumienie i stosowanie podejścia funkcjonalnego sprawi, że to, co zaprojektujesz, będzie odznaczało się wysoką przezroczystościa referencyjną (ang. referential transparency).
Przezroczystość referencyjna to bardzo pożądana cecha: sprawia ona, że dla tych samych danych wejściowych, funkcja konsekwnetnie zwraca ten sam wynik, niezależnie od tego, w jakim kontekście i kiedy jest ona wywoływana. Innymi słowy, wartość funkcji w mniejszym stopniu zależy — a w idealnej sytuacji jest całkowicie niezależna &mdash od efektów ubocznych i modyfikowalnego stanu.
Uważa się, że jedną z głównych przyczyn błędów w kodzie imperatywnym są modyfikowalne zmienne. Podejrzewam, że większość czytelników tego tekstu natknęło się już kiedyś (bądź natknie się) na konieczność dociekania, dlaczego wartość pewnej zmiennej jest inna, niż można by się spodziewać w określonej sytuacji. Semantyka modyfikatorów widoczności jest w stanie zmniejszyć ryzyko wystąpienia tych zdradzieckich błędów albo przynajmniej znacząco ograniczyć obszar poszukiwań, jednakże w rzeczywistości może ona przyczyniać się do powstawania designów, które za bardzo polegają na modyfikowalności stanu.
Od naszej branży nie możemy oczekiwać pomocy w tym względzie. Wszelkie kursy wprowadzające do zorientowania obiektowego zachęcają, często nieświadomie, do takiego właśnie projektowania, prezentując przykłady grafów obiektów o stosunkowo długim czasie życia, które bez wahania wywołują na sobie metody modyfikujące ich stan, a to bywa niebezpieczne.
Można jednak pozbyć się nadmiernej modyfikowalności poprzez rozsądne stosowanie projektowania opartego na testach, a w szczególności upewnienie się, że mockujemy role, a nie obiekty.
Końcowym rezultatem takiego podejścia jest zazwyczaj design z lepszym rozłożeniem odpowiedzialności, z większą liczbą małych funkcji, które operują na przekazanych argumentach zamiast odwoływać się do pól klasy. Taki design skutkuje mniejszą liczbą błędów, które jeśli już wystąpią, będą łatwiejsze do debugowania, ponieważ ich zlokalizowanie będzie mniej problematyczne niż zastanawianie się, w jakim konkretnym kontekście nastąpiło błędne przypisanie. W rezultacie stopień przezroczystości referencyjnej wzrasta, a nic nie wpoi Ci tych zasad tak głęboko jak nauka jakiegoś języka funkcjonalnego, gdzie taki model obliczeń jest normą.
Oczywiście takie podejście nie we wszystkich sytuacjach będzie optymalne. Przykładowo, w systemach zorientowanych obiektowo, styl funkcjonalny lepiej sprawdzi się przy implementacji modelu dziedziny (to znaczy wtedy, gdy współpracujące ze soba klasy służą zredukowaniu złożoności reguł biznesowych) niż przy tworzeniu interfejsu użytkownika.
Opanuj w stopniu doskonałym paradygmat programowania funkcjonalnego, abyś mógł w sposób rozsądny zastosować tę wiedzę w różnych dziedzinach. Przykładowo, Twoje systemy obiektowe będą czerpać korzyści z wysokiej przezroczystości referencyjnej i będą upodabniać się do swoich funkcjonalnych odpowiedników bardziej, niż mogłoby się to wydawać. Tak naprawdę to wielu powiedziałoby nawet, że na podstawowym poziomie programowanie funkcjonalne i obiektowe są jedynie swoimi lustrzanymi odbiciami, czymś w rodzaju obliczeniowego yin i yang.
Artykuł został opublikowany na licencji Creative Commons Uznanie Autorstwa 3.0.