Dzisiaj zajmiemy się pewną legendą i żartem w gronie programistów. Ale czy powinienem w sumie nazywać to legendą? Istotnie, w społeczeństwie osób pracujących nad rozwiązywaniem problemów IT pojawia się ta praktyka i mimo że jest często traktowana z przymrużeniem oka, to ma swoje uzasadnienie. I nie mówimy tutaj o konkretnym narzędziu instalowanym na komputerze, dostępnym online czy elektronicznym sprzęcie, ale o zwykłym przedmiocie, który można chwycić w rękę, a nawet się z nim wykąpać.
Tak, dzisiejszy artykuł będzie o gumowej kaczuszce w kontekście programowania lub - jak ktoś woli - metodzie gumowej kaczuszki. Nie zwariowałem - poważnie, to tekst o tym zagadnieniu. Na blogu poważnej firmy IT.
Jak w ogóle... Skąd?!
Najpierw może powiedzmy sobie, o co w ogóle chodzi w tym dość zabawnym zagadnieniu. Programiści - jak każda grupa specjalistów i w ogóle ludzi - trafiają na błędy i problemy, które spędzają im sen z powiek. Nie chodzi tutaj często o jakieś bardzo skomplikowane wyzwania, które wymagają ogromnej wiedzy i czasu poświęconego na planowanie. Mowa głównie o kłopotach, które nazwalibyśmy "drobnymi, aczkolwiek denerwującymi", a te tym bardziej irytują, gdy intuicyjnie czujemy, że są proste w pozbyciu się, ale nijak nie możemy trafić na właściwą ścieżkę. Czasem wynika to z braku informacji, niekiedy z zapomnienia o konkretnym aspekcie, ale bywa, że działa tutaj także kolokwialne "zaćmienie umysłu". Krótko mówiąc - może być tak, że wszystko idzie wspaniale, ale natrafiamy na pozornie prostą przeszkodę, której przez długi czas nie możemy ominąć lub nawet porządnie przeanalizować. Warto też zaznaczyć, że skupimy się tutaj na błędach programistycznych.
Najczęstszym sposobem na rozwiązywanie takich błędów jest tzw. debugowanie (po polsku zwane "odpluskwianiem", gdyż to słowo rzeczywiście pochodzi od owadów gnieżdżących się w starych komputerach wielkości szafy). To proces polegający na krokowym uruchamianiu programu (wręcz linijka po linijka) i obserwowaniu, co dzieje się pod spodem, czyli jakie wartości przyjmują zmienne oraz w które miejsca kodu wchodzimy. Ten proces umożliwiają specjalne narzędzia dostępne w zintegrowanych środowiskach programistych (ang. Integrated Development Environment, w skrócie IDE), choć w prostszych sytuacjach można również sięgnąć do klasycznego i oficjalnie niepolecanego "debugowania printfami", czyli wypisywania komunikatów w odpowiednich miejscach i obserwowania logów. Poza debugowaniem istnieje też możliwość analizy statycznej, kiedy po prostu czytamy kod i rewidujemy potencjalne czynniki ryzyka lub w ogóle pomysł na rozwiązanie danego zagadnienia. Tego tematu jednak nie będziemy poruszać w tym artykule.
Bywa jednak, że debugowanie nie daje rezultatów - mimo że widzimy wszystko i wydaje nam się, że mamy wszystkie dane, to nie rozumiemy, jak może dochodzić do błędu. Nie pomaga też ani Stack Overflow, ani ChatGPT, ani żadna inna techniczna pomoc. Zaczynamy wręcz podejrzewać, że nie rozumiemy istoty rzeczy (do tego zdania jeszcze wrócimy). Słowem - utknęliśmy. Co wówczas robi taki stereotypowy programista, gdy zawiodą wszystkie środki techniczne? Bierze gumową kaczuszkę i zaczyna jej opowiadać o sytuacji - omawia problem, dane wejściowe, oczekiwany wynik, uzyskiwany rezultat, przechodzi przez ideę stojącą za poszczególnymi fragmentami kodu i nagle... pojawia się metaforyczna żarówka nad głową, a rozwiązanie staje się proste. Programista wówczas dziękuje kaczuszce, odkłada ją, naprawia problem i idzie grać w CS-a.
Brzmi niedorzecznie, prawda? Ale... działa. Przy czym, oczywiście, nie trzeba się ograniczać do kaczuszki lub w ogóle jakiegokolwiek przedmiotu. Ważne, aby rozumieć istotę tej koncepcji, nawet jeśli nie chcemy wchodzić stricte w zagadnienia psychologiczne i neurologiczne. Czego zresztą nie będziemy tutaj w szczegółach robić, ale podamy po drodze parę interesujących linków.
Myślenie na głos
Jesteśmy przyzwyczajeni do tego, że gdy czytamy, robimy to po cichu - po pierwsze, tak jest szybciej, a po drugie, nie przeszkadzamy innym. Podobnie jest z myśleniem, gdzie zwykle nie werbalizujemy tego, co układamy sobie w mózgu. Jest to zwyczajna oszczędność naszego aparatu mowy oraz otoczenia, a ponadto zazwyczaj wystarczy do poradzenia sobie z tym, co spotykamy w życiu. Ale nie zawsze tak jest - czasem trzeba zaangażować inne obszary naszego zbioru szarych komórek.
Osoby, które przez lata robiły notatki w sposób odręczny, a później przeszły na formę cyfrową, pewnie powiedzą, że zrobiły to ze względu na szybkość (faktycznie, jest szybciej, a po latach pisania na komputerze, tradycyjne ręczne zapiski są często niechlujne), dostępność technologiczną i łatwość kopiowania. To zrozumiałe i w większości przypadków jak najbardziej pożądane i wystarczające. Jednak wykorzystanie tradycyjnego przyrządu do pisania i kawałka papieru (od biedy rysika i tabletu) w większym stopniu zaprzęga do pracy mózg, aktywując bardziej złożone połączenia nerwowe i pobudzając pamięć. Angażuje rękę (specyficzne ruchy, które możemy potem odtworzyć), kreatywność (za każdym razem piszemy literki troszkę inaczej, co niekiedy zapamiętujemy), a także wymaga koncentracji (co ponownie pomaga w zapamiętywaniu). I faktycznie, gdy przypomnę sobie momenty, kiedy uczyłem się do egzaminów na studiach, to bardzo dużo korzystałem z przypominania sobie okoliczności, w których dana odręczna notatka powstała, a podczas samego sprawdzenia wiedzy, poza zrozumieniem tematu, miałem przed oczami nawet całe kartki papieru z moimi charakterystycznymi gryzmołami. W wersji cyfrowej (czyli "cichej", bardziej mechanicznej) też można zauważyć tego typu procesy, ale mają one słabszą moc.
Dlaczego w ogóle wspominam o pisaniu? Gdyż wypowiadanie swoich myśli na głos opiera się na podobnej idei - angażujemy kolejne partie ciała, koncentrujemy się na tym, co mówimy (werbalizacja myśli, szczególnie w obecności kogoś, wymaga zrozumiałego mówienia), "czyścimy" nasze myśli, a to sprzyja analizie informacji i ich poskładaniu, gdyż zwyczajnie nie możemy skrócić naszego wywodu i pominąć "niewygodnych" fragmentów, których wcześniej nie wyobrażaliśmy sobie jako "niewygodne".
Wróćmy teraz do zdania, które pojawiło się kilka akapitów wcześniej - jak sprawdzić, czy faktycznie rozumiemy nasz problem? Starajmy się znaleźć lub wyobrazić sobie laika i wytłumaczyć mu/jej (na głos) to zagadnienie. W ten sposób przy okazji analizujemy temat i uświadamiamy sobie luki w naszej wiedzy. Na pewno znamy osoby, o których powiedzielibyśmy, że "znają się na danym temacie, ale nie potrafią go wyjaśnić" - może to świadczyć o niedostatecznych umiejętnościach interpersonalnych (od razu powiem - nie jest to nic karygodnego), ale także o niewystarczająco dogłębnym zrozumieniu obszaru. Cała idea polega bowiem na tym, że gdy staramy się coś przekazać nowicjuszowi i okaże się, że czegoś nie umiemy wyrazić słowami bądź znaleźć analogii, to warto się zastanowić, czy tak naprawdę nie musimy sami się czegoś dowiedzieć i później ponowić "wykład". Im bardziej złożone zagadnienie, tym lepiej to widać - jeśli będziemy umieli je wytłumaczyć tak, że każdy to zrozumie, to oznacza, że naprawdę glęboko sami je rozumiemy, gdyż po drodze wiele fragmentów musi rozłożyć na czynniki pierwsze. Nie jest to nowa koncepcja - to wszystko nazywa się techniką Feynmana, gdyż właśnie wybitny fizyk, noblista z 1965 roku był propagatorem tej metody.
A co, jeżeli faktycznie komuś coś tłumaczymy i ten ktoś zadaje nam jeszcze pytania? Albo sami sobie zadajemy pytania podczas wykładu, prowadząc wyimaginowany dialog? Tym lepiej - zaczynamy otwierać się na aspekty, o których wcześniej nie pomyśleliśmy i które też musimy jakoś wytłumaczyć lub wziąć pod uwagę w projektowaniu. Przy okazji, istnieje taka koncepcja jak aktywne słuchanie, które polega na pełnym skupieniu na rozmówcu oraz tym, co mówi - wówczas więcej zapamiętujemy, lepiej przyswajamy informacje, a nawet uwzględniamy mowę ciała, emocje i rozwijamy więź z rozmówcą, co pomaga w dalszej relacji. To w mniejszym stopniu dotyczy naszego przypadku, chyba że jesteśmy na tyle empatyczni, że potrafimy wcielić się w nieistniejącego rozmówcę i kierować wobec siebie wątpliwości, z których wcześniej sobie nie zdawaliśmy sprawy.
Podsumowując ten fragment, rozmawianie z gumową kaczuszką podczas rozwiązywania problemu to niekoniecznie objaw choroby psychicznej, ale wytoczenie kolejnych dział umysłowych w celu zrozumienia trudności i pozbycia się jej. Zestawiamy się z drugą stroną i tłumacząc jej sytuację, sami zaczynamy dochodzić do rozwiązania lub przynajmniej identyfikujemy kwestie do dalszego sprawdzenia. Brak solucji nie musi bowiem oznaczać, że sami nie wiemy, czego szukamy - być może podczas tego procesu uświadomimy sobie, które obszary są dla nas niejasne i musimy o nich dowiedzieć się czegoś wiecej.
Nawiasem mówiąc, po przeczytaniu ostatniego zdania niektórym może przypomnieć się znane powiedzenie przypisywanie Sokratesowi, czyli "wiem, że nic nie wiem", a także tzw. efekt Dunninga-Krugera, które mowią o tym, że im głębiej drążymy daną dziedzinę, tym bardziej uświadamiamy sobie, ile wiedzy jeszcze mamy do zdobycia. Nie jest to jednak związane z gumowymi kaczuszkami - wspominam o tym w ramach ciekawostki oraz aby artykuł wyglądał na nieco mądrzejszy niż jest w rzeczywistości.
Czy musi to być gumowa kaczuszka?
Oczywiście, nie - gumowa kaczuszka jest tylko pewnym konceptem, memiczną wręcz ilustracją drugiej strony naszego dialogu, która pomaga w rozwiązaniu problemu. Ten sympatyczny (albo i nie) ptak wykonany z materiału pochodzenia chemicznego utarł się w powszechnej świadomości z uwagi na publikację "The Pragmatic Programmer: From Journeyman to Master" autorstwa Andrew Hunta i Davida Thomasa, gdzie pojawiła się technika "rubber duck debugging".
Tak naprawdę, najlepszym partnerem do rozwiązywania problemu byłaby druga osoba, najlepiej programista, w dodatku świeży w danym temacie, który nie jest "skażony" naszym procesem myślowym i spojrzy na sprawę bez uprzedzeń, z zupełnie innej perspektywy. To jest zresztą jeden z argumentów za inną metodą, programowaniem w parach, o ile partnerzy nawzajem się uzupełniają. Wiemy jednak dobrze, że czasem nie da się poprosić o pomoc innego człowieka lub nawet istoty ludzkiej (psy mądrze patrzą, gdy tłumaczy się im, co znajduje się w pętli lub ifie). W takim układzie zostaje przedmiot, którego wartość wzrasta, gdy choć trochę przypomina żywy organizm realnie nami zainteresowany - pluszowy miś sprawdzi się równie dobrze, choć gumowa kaczuszka ma dodatkowy ładunek pełen żartu, a także po prostu sympatyczny wygląd.
Można też mówić w przestrzeń, wyobrażając sobie rozmówcę lub stawiając w tej roli samego siebie. Jeśli ktoś ma dużą wyobraźnię oraz empatię, to jest to możliwe, choć prawdopodobnie mniej skuteczne niż przelanie tej "energii" w konkretny obiekt, do którego możemy mówić, spojrzeć na niego i wyobrażać sobie, że nam odpowiada, podczas gdy tak naprawdę to my sami w swojej głowie rozkładamy problem na części pierwsze, próbując złożyć rozwiazanie.
Czy to realnie działa?
Tak - zdarzają się sytuacje, w których programista utknął i trudno mu ruszyć dalej "normalnymi" metodami, choć, na szczęście, należą one do rzadkości. Gdy jednak się pojawiają, warto pamiętać o metodzie gumowej kaczuszki, choć czasem trzeba się przełamać, aby skorzystać z tego triku psychologicznego. Warto to jednak zrobić, gdyż wówczas można też się dowiedzieć więcej o sobie samym i tym, jak realnie rozumujemy to, co piszemy w kodzie (i nie tylko).
Sama gumowa kaczuszka jako przedmiot przedstawiający pociesznego ptaka jest też znakomitym pomysłem na prezent dla programisty, wywołujący uśmiech na twarzy i stanowiący ozdobę biurka. A w razie potrzeby można go nawet wziać do wanny.
Pozdrawiam i dziękuję - Jakub Rojek.