Programowanie oddolne
1993
(Ten esej pochodzi z wprowadzenia doOn Lisp .)
Istnieje od dawna zasada stylu programowania, według której elementy funkcyjne programu nie powinny być zbyt duże. Jeśli jakiś komponent programu przekroczy etap, w którym jest łatwo zrozumiały, staje się masą złożoności, która ukrywa błędy równie łatwo, jak wielkie miasto ukrywa zbiegów. Takie oprogramowanie będzie trudne do czytania, trudne do testowania i trudne do debugowania.
Zgodnie z tą zasadą, duży program musi być podzielony na części, a im większy program, tym bardziej musi być podzielony. Jak podzielić program? Tradycyjne podejście nazywa się projektowaniem odgórnym (top-down design): mówisz „celem programu jest wykonanie tych siedmiu rzeczy, więc dzielę go na siedem głównych podprogramów. Pierwszy podprogram musi wykonać te cztery rzeczy, więc z kolei będzie miał cztery własne podprogramy”, i tak dalej. Proces ten trwa, aż cały program osiągnie odpowiedni poziom granularności – każda część jest wystarczająco duża, aby zrobić coś znaczącego, ale wystarczająco mała, aby można ją było zrozumieć jako pojedynczą jednostkę.
Doświadczeni programiści Lisp dzielą swoje programy inaczej. Oprócz projektowania odgórnego, stosują zasadę, którą można nazwać projektowaniem oddolnym (bottom-up design) – dostosowywania języka do problemu. W Lisp nie tylko piszesz swój program w dół do języka, ale także budujesz język w górę do swojego programu. Podczas pisania programu możesz pomyśleć „szkoda, że Lisp nie ma takiego i takiego operatora”. Więc idziesz i go piszesz. Później zdajesz sobie sprawę, że użycie nowego operatora uprościłoby projektowanie innej części programu i tak dalej. Język i program ewoluują razem. Podobnie jak granica między dwoma walczącymi państwami, granica między językiem a programem jest rysowana i przerysowywana, aż w końcu spocznie wzdłuż gór i rzek, naturalnych granic twojego problemu. Ostatecznie twój program będzie wyglądał tak, jakby język został zaprojektowany dla niego. A kiedy język i program dobrze do siebie pasują, otrzymujesz kod, który jest jasny, mały i wydajny.
Warto podkreślić, że projektowanie oddolne nie oznacza po prostu pisania tego samego programu w innej kolejności. Kiedy pracujesz oddolnie, zazwyczaj kończysz z innym programem. Zamiast jednego, monolitycznego programu, otrzymasz większy język z bardziej abstrakcyjnymi operatorami i mniejszy program napisany w nim. Zamiast nadproża, otrzymasz łuk.
W typowym kodzie, po wyodrębnieniu części będących jedynie księgowością, to, co pozostaje, jest znacznie krótsze; im wyżej budujesz język, tym mniejszą odległość będziesz musiał pokonać od góry do niego. Przynosi to kilka korzyści:
-
Dzięki temu, że język wykonuje więcej pracy, projektowanie oddolne daje programy mniejsze i bardziej zwinne. Krótszy program nie musi być dzielony na tak wiele komponentów, a mniej komponentów oznacza programy łatwiejsze do czytania lub modyfikacji. Mniej komponentów oznacza również mniej połączeń między komponentami, a tym samym mniejszą szansę na błędy. Tak jak projektanci przemysłowi dążą do zmniejszenia liczby ruchomych części w maszynie, tak doświadczeni programiści Lisp używają projektowania oddolnego, aby zmniejszyć rozmiar i złożoność swoich programów.
-
Projektowanie oddolne promuje ponowne wykorzystanie kodu. Kiedy piszesz dwa lub więcej programów, wiele narzędzi, które napisałeś dla pierwszego programu, będzie również przydatnych w kolejnych. Po zdobyciu dużego podłoża narzędzi, pisanie nowego programu może zająć tylko ułamek wysiłku, jaki wymagałoby rozpoczęcie od surowego Lisp.
-
Projektowanie oddolne sprawia, że programy są łatwiejsze do czytania. Przykład tego typu abstrakcji prosi czytelnika o zrozumienie operatora ogólnego przeznaczenia; przykład abstrakcji funkcjonalnej prosi czytelnika o zrozumienie podprogramu specjalnego przeznaczenia. [1]
-
Ponieważ zawsze skłania cię do szukania wzorców w kodzie, praca oddolna pomaga doprecyzować twoje pomysły dotyczące projektu programu. Jeśli dwa odległe komponenty programu są podobne w formie, zauważysz podobieństwo i być może przeprojektujesz program w prostszy sposób.
Projektowanie oddolne jest możliwe w pewnym stopniu w językach innych niż Lisp. Gdziekolwiek widzisz funkcje biblioteczne, tam zachodzi projektowanie oddolne. Jednak Lisp daje ci znacznie szersze możliwości w tym zakresie, a rozszerzanie języka odgrywa proporcjonalnie większą rolę w stylu Lisp – tak bardzo, że Lisp jest nie tylko innym językiem, ale zupełnie innym sposobem programowania.
Prawdą jest, że ten styl rozwoju lepiej nadaje się do programów, które mogą być pisane przez małe grupy. Jednocześnie rozszerza granice tego, co może zrobić mała grupa. W The Mythical Man-Month Frederick Brooks zaproponował, że produktywność grupy programistów nie rośnie liniowo wraz z jej rozmiarem. Wraz ze wzrostem wielkości grupy, produktywność poszczególnych programistów spada. Doświadczenie programowania w Lisp sugeruje bardziej optymistyczny sposób sformułowania tej zasady: wraz ze zmniejszaniem się wielkości grupy, produktywność poszczególnych programistów rośnie. Mała grupa wygrywa, względnie rzecz biorąc, po prostu dlatego, że jest mniejsza. Kiedy mała grupa wykorzystuje również techniki, które umożliwia Lisp, może wygrać bezapelacyjnie.
Nowość: Pobierz On Lisp za darmo.
[1] „Ale nikt nie może przeczytać programu bez zrozumienia wszystkich twoich nowych narzędzi”. Aby zobaczyć, dlaczego takie stwierdzenia są zazwyczaj błędne, zobacz sekcję 4.8.