Jak rozumiem, projektowanie odgórne polega na dopracowaniu abstrakcyjnej koncepcji wysokiego poziomu na mniejsze betonowe i zrozumiałe części, aż do zdefiniowania najmniejszego elementu konstrukcyjnego. Z drugiej strony „od dołu” definiuje części niskiego poziomu, a następnie stopniowo buduje bloki wyższego poziomu, aż powstanie cały system.
W praktyce najlepiej powiedzieć, że łączą dwie metody: zaczynają się od specyfikacji wysokiego poziomu, aby w pełni określić wiedzę w dziedzinie, jej relacje i ograniczenia. Gdy problem zostanie dobrze zrozumiany, tworzone są najmniejsze bloki konstrukcyjne w celu zbudowania systemu.
Proces:
- Tworzenie specyfikacji wymagań
- Utwórz specyfikację projektu (z diagramami)
- Wprowadzić w życie
- Dostarczyć
- Powtórz (w iteracyjnym rozwoju, zamiast robić cały kawałek w każdej fazie, robimy po trochu każdego z nich wielokrotnie i codziennie spotykamy się, aby dostosować się do dynamicznych wymagań klienta)
wygląda mi zupełnie normalnie (ze specyfikacjami jako planami). Ma swoje wady, ale właśnie dlatego mamy iteracyjny rozwój: zamiast poświęcać czas na jedną fazę, mówi, analiza wymagań, aby badać każdą możliwą rzecz w wiedzy w dziedzinie, która podlega zmianom (być może codziennie), przeprowadzamy trochę analizy, trochę projektu, a następnie go wdrożyć.
Innym sposobem jest to, że każda iteracja odbywa się w stylu mini-wodospadu, gdzie analiza jest przeprowadzana w ciągu kilku dni (lub tygodnia). To samo dotyczy projektu. Resztę czasu poświęca się na wdrożenie. Czy jest coś z natury niewłaściwego w podejściu odgórnym w połączeniu z iteracyjnym rozwojem?
W swoim eseju Programowanie od dołu , Paul Graham wydaje się zachęcać do budowania od podstaw całkowicie lub programować od podstaw, ale nie fazę analizy / projektowania wymagań:
Doświadczeni programiści Lisp inaczej dzielą swoje programy. Oprócz projektowania odgórnego, działają zgodnie z zasadą, którą można nazwać projektowaniem oddolnym - zmieniając język w celu dopasowania do problemu.
O ile mi wiadomo, miał na myśli to, że Lisper nadal wykonuje odgórne projektowanie, ale program oddolny, czy to prawda? Kolejny punkt, który napisał:
Warto podkreślić, że projekt oddolny nie oznacza po prostu pisania tego samego programu w innej kolejności. Kiedy pracujesz oddolnie, zwykle kończy się to innym programem. Zamiast jednego monolitycznego programu otrzymasz większy język z bardziej abstrakcyjnymi operatorami i napisany w nim mniejszy program. Zamiast nadproża dostaniesz łuk.
Czy to oznacza, że w okresie pisania programu w Lisp otrzymujesz ogólne narzędzie?
Odpowiedzi:
Odgórny to świetny sposób na opisanie rzeczy, które znasz, lub na odbudowanie rzeczy, które już zbudowałeś.
Największym problemem odgórnym jest to, że dość często po prostu nie ma „góry”. Zmienisz zdanie na temat tego, co powinien zrobić system podczas opracowywania systemu i eksploracji domeny. Jak może być punktem wyjścia coś, czego nie wiesz (tj. Co chcesz, aby system zrobił)?
„Lokalny” z góry na dół jest dobrą rzeczą… pewne myślenie przed kodowaniem jest wyraźnie dobre. Ale zbyt dużo myślenia i planowania nie jest, ponieważ to, co sobie wyobrażasz, nie jest prawdziwym scenariuszem (chyba że już tam byłeś, tj. Jeśli nie budujesz, ale odbudowujesz). Globalne odgórne tworzenie nowych rzeczy to tylko nonsens.
Podejście oddolne powinno być (globalne) podejściem, chyba że znasz 100% problemu, potrzebujesz tylko znanego rozwiązania do zakodowania i nie przejmujesz się szukaniem możliwych alternatywnych rozwiązań.
Podejście Lisp to destylowane podejście oddolne. Nie tylko budujesz oddolnie, ale możesz również kształtować cegły tak, jak chcesz. Nic nie jest ustalone, wolność jest całkowita. Oczywiście wolność bierze odpowiedzialność i możesz robić okropne rzeczy, niewłaściwie wykorzystując tę moc.
Ale okropny kod można napisać w dowolnym języku. Nawet w językach, które są ukształtowane jako klatki dla umysłu, zaprojektowane z nadzieją, że dzięki tym językom nawet małpy mogłyby uruchomić dobre programy (pomysł tak błędny na tak wielu poziomach, że boli nawet samo myślenie o tym).
Twój przykład dotyczy serwera WWW. Teraz w 2012 r. Jest to dobrze zdefiniowany problem, musisz przestrzegać specyfikacji. Serwer WWW to tylko problem z implementacją. Zwłaszcza jeśli zamierzasz napisać serwer WWW zasadniczo identyczny z innymi gajillionami serwerów WWW, które tam są, nic nie jest tak naprawdę niejasne, z wyjątkiem kilku drobiazgów. Nawet twój komentarz na temat RSA wciąż mówi o jasno zdefiniowanym problemie, z formalnymi specyfikacjami.
Przy dobrze zdefiniowanym problemie, formalnych specyfikacjach i znanych już rozwiązaniach, kodowanie łączy się w kropki. Z góry na dół jest w porządku. To raj dla kierowników projektów.
W wielu przypadkach nie ma jednak sprawdzonego, dobrze znanego podejścia do łączenia kropek. W rzeczywistości bardzo często trudno powiedzieć nawet, jakie są kropki.
Załóżmy na przykład, że poprosiłeś automatyczną maszynę do cięcia, aby wyrównała cięte części do drukowanego materiału, który nie jest idealnie zgodny z teoretycznym powtarzalnym logo. Dostajesz części i zdjęcia materiału wykonane przez maszynę.
Co to jest reguła wyrównania? Ty decydujesz. Co to jest wzór, jak go przedstawić? Ty decydujesz. Jak wyrównać części? Ty decydujesz. Czy części można „wygiąć”? To zależy, niektóre nie, a niektóre tak, ale oczywiście nie za dużo. Co zrobić, jeśli materiał jest zbyt zniekształcony, aby część mogła go przeciąć w odpowiedni sposób? Ty decydujesz. Czy wszystkie rolki materiału są identyczne? Oczywiście, że nie, ale nie możesz zaszkodzić użytkownikowi w dostosowaniu reguł wyrównania dla każdego rzutu ... byłoby to niepraktyczne. Jakie zdjęcia widzą kamery? Materiał, cokolwiek to może znaczyć ... może być kolorowy, może być czarny na czarnym, gdzie tylko odruch światła sprawia, że wzór jest widoczny. Co to znaczy rozpoznać wzór? Ty decydujesz.
Teraz spróbuj zaprojektować ogólną strukturę rozwiązania tego problemu i podaj ofertę cenową i czasową. Założę się, że nawet architektura systemu ... (tak, architektura) będzie błędna. Szacunkowe koszty i czas będą liczbami losowymi.
Wdrożyliśmy go i teraz jest to działający system, ale wiele razy zmienialiśmy zdanie na temat samego kształtu systemu. Dodaliśmy całe podsystemy, do których teraz nie można nawet dotrzeć z menu. Wielokrotnie przełączaliśmy role master / slave w protokołach. Prawdopodobnie teraz mamy wystarczającą wiedzę, aby lepiej ją odbudować.
Inne firmy oczywiście rozwiązały ten sam problem ... ale chyba, że jesteś w jednej z tych firm, najprawdopodobniej twój szczegółowy projekt z góry na dół będzie żartem. Możemy zaprojektować go z góry na dół. Nie możesz, ponieważ nigdy wcześniej tego nie robiłeś.
Prawdopodobnie możesz rozwiązać ten sam problem. Działa jednak oddolnie. Zaczynając od tego, co wiesz, ucząc się tego, czego nie wiesz i sumując.
Nowe złożone systemy oprogramowania są rozwijane, a nie projektowane. Od czasu do czasu ktoś zaczyna projektować od nowa duży, złożony, źle określony system oprogramowania (zauważ, że przy dużym złożonym projekcie oprogramowania istnieją tylko trzy możliwości: a] specyfikacja jest rozmyta, b] specyfikacja jest błędna i sprzeczna lub c] zarówno… jak i najczęściej [c] ma miejsce).
Są to typowe projekty dużych firm, w których tysiące godzin wrzucono w same slajdy PowerPoint i same diagramy UML. Niezmiennie zawodzą całkowicie po spaleniu zawstydzających ilości zasobów ... lub w bardzo wyjątkowym przypadku w końcu dostarczają drogiego oprogramowania, które implementuje tylko niewielką część początkowej specyfikacji. I to oprogramowanie jest zawsze głęboko nienawidzone przez użytkowników ... nie tego rodzaju oprogramowania, które kupiłbyś, ale takiego oprogramowania, którego używasz, ponieważ jesteś do tego zmuszony.
Czy to oznacza, że uważam, że powinieneś myśleć tylko o kodowaniu? Oczywiście nie. Ale moim zdaniem konstrukcja powinna zaczynać się od dołu (cegły, konkretny kod) i powinna iść w górę ... a twoje skupienie i dbałość o szczegóły powinny w pewnym sensie „zanikać” w miarę zbliżania się do tego, co masz. Odgórne przedstawienie jest często przedstawiane tak, jakbyś chciał wprowadzić ten sam poziom szczegółowości do całego systemu naraz: po prostu dziel go na wszystkie węzły, aż wszystko stanie się oczywiste ... w rzeczywistości moduły podsystemu są „hodowane” z podprogramów. Jeśli nie masz wcześniejszego doświadczenia w konkretnym problemie, projektowanie odgórnego podsystemu, modułu lub biblioteki będzie straszne. Po zaprojektowaniu dobrej biblioteki możesz zaprojektować dobrą bibliotekę, a nie na odwrót.
Wiele pomysłów Lisp zyskuje na popularności (funkcje pierwszej klasy, zamykanie, dynamiczne pisanie jako domyślne, wyrzucanie elementów bezużytecznych, metaprogramowanie, interaktywne programowanie), ale Lisp jest nadal (wśród znanych mi języków) dość wyjątkowy pod względem łatwości kształtowania kodu za to, czego potrzebujesz.
Na przykład parametry słowa kluczowego są już obecne, ale jeśli nie byłyby obecne, można je dodać. Zrobiłem to (w tym weryfikację słów kluczowych w czasie kompilacji) dla zabawkowego kompilatora Lisp, z którym eksperymentuję i nie wymaga to dużo kodu.
Zamiast tego w C ++ najwięcej możesz uzyskać od ekspertów C ++, którzy mówią ci, że parametry słów kluczowych nie są tak przydatne, lub niesamowicie złożoną, zepsutą implementację szablonów w połowie wspieraną, która tak naprawdę nie jest tak przydatna. Czy klasy C ++ są pierwszorzędnymi obiektami? Nie i nic nie możesz na to poradzić. Czy możesz mieć introspekcję w czasie wykonywania lub w czasie kompilacji? Nie i nic nie możesz na to poradzić.
Ta elastyczność językowa Lisp sprawia, że świetnie nadaje się do budowania oddolnego. Możesz budować nie tylko podprogramy, ale także składnię i semantykę języka. I w pewnym sensie sama Lisp jest oddolna.
źródło
Nie jestem pewien, w jaki sposób ta odpowiedź miałaby zastosowanie do Lisp, ale właśnie skończyłem czytać zwinne zasady, wzorce i praktyki , a autor, wujek Bob , zdecydowanie zaleca odgórne podejście do C # (dotyczy również C ++), z którym w pełni Zgodzić się.
Jednak w przeciwieństwie do niektórych innych odpowiedzi, które wyciągnęły wniosek, że podejście odgórne oznacza, że w pierwszej interakcji dostarczasz tylko dokumenty i ogólny projekt, książka wskazuje na inną metodę: TDD w połączeniu z projektowaniem ewolucyjnym.
Chodzi o to, że zaczynasz od góry i określasz najwyższe poziomy abstrakcji (lub najwyższe lokalne), a gdy tylko zostaną zdefiniowane, sprawisz, że wykonają użyteczną pracę, dzięki czemu funkcja nr 1 natychmiast zacznie działać. Następnie, gdy dodajesz coraz więcej funkcji, przebudowujesz kod i ewoluujesz zgodnie z potrzebami, zawsze mając świadomość zasad SOLID. W ten sposób nie skończy się zbyt wiele warstw abstrakcji i nie skończy się projektowaniem niskiego poziomu, który nie pasuje do ogólnej architektury. Jeśli nie jesteś pewien, co to oznacza, książka, o której wspomniałem powyżej, zawiera cały rozdział z przykładem, w którym programiści biorą koncepcje i zaczynają od diagramów UML i klas niskiego poziomu, tylko po to, aby uświadomić sobie, że połowa tych klas nie jest potrzebna, gdy kodowanie faktycznie się rozpocznie. Zasadniczo dzięki takiemu podejściu kod niskiego poziomu jest naturalnie spychany, ponieważ w projekcie definiowanych jest więcej szczegółów wysokiego poziomu.
I na koniec, jeśli ćwiczysz SOLID, nie powinieneś wpadać w sytuację, w której masz zdefiniowane abstrakcje na wysokim poziomie, a następnie wchodzić w szczegóły i nagle odkryć, że nie ma OOD ani abstrakcji. To nie jest tak naprawdę wina odgórnego projektu, ale leniwa inżynieria.
Jeśli chcesz przeczytać więcej o XP i projektowaniu ewolucyjnym, zapoznaj się z dobrym tekstem Martina Fowlera, innego wielkiego autora: „Czy Design Dead?”
źródło
Dla mnie najważniejsze uwagi, które Paul Graham wygłasza w swoim artykule, to:
Lub, jak wiadomo w kręgach C ++: Projektowanie bibliotek to Projektowanie języków (Bjarne Stroustrup)
Główną ideą projektowania z góry na dół jest: najpierw planujesz, a potem kodujesz. Beanow ma rację, gdy pisze , że występują problemy, gdy kod wykonywalny spóźnia się w tym procesie. W projektowaniu oddolnym zawsze masz kod i kod, który można przetestować.
Ponadto twój kod nie jest płaski. Rozumiem przez to, że ma więcej poziomów mniejszych abstrakcji. W projektowaniu z góry na dół ludzie często kończą się dużymi abstracjami do pewnego arbitralnego poziomu, a poniżej tego nie ma żadnych abstrakcji. Kod zaprojektowany od podstaw OTOH często zawiera mniej kontroli niskiego poziomu i struktur danych, ponieważ prawdopodobnie zostaną one usunięte.
źródło
Idealnie, pisanie programu w dowolnym języku, nie tylko Lisp, pozwala napisać cały zestaw ogólnych narzędzi, które mogą przyspieszyć twój następny program lub ulepszenia prędkości do obecnego.
W praktyce śledzenie tych narzędzi może być trudne. Dokumentacja jest słaba i niezorganizowana, a ludzie, którzy o nich wiedzą, odchodzą. W praktyce ponowne użycie kodu jest często większym problemem niż jest warte. Ale jeśli kod jest odpowiednio udokumentowany i odpowiednio zorganizowany, a programiści trzymają się (lub zachowują własne zasoby użytecznego kodu), można zaoszczędzić wiele pracy, pobierając kod z magazynu zamiast go odbudowywać.
Cały projekt musi być z góry na dół, inaczej nie wiedziałbyś, co robisz. Budujesz szopę lub samochód? Nie możesz tego rozgryźć z projektem oddolnym. Ale jeśli zamierzasz zbudować lewe przednie koło, możesz pomyśleć, że możesz potrzebować więcej kół później, zarówno do tego projektu, jak i do innych. A jeśli zbudujesz koło wielokrotnego użytku, będziesz mieć cztery w cenie jednego. (I 18 za tę przyczepę-ciągnik, którą budujesz obok, wszystko za darmo.)
Zauważ, że w przeciwieństwie do prawdziwych samochodów i prawdziwych kół, jeśli zbudowałeś jedno „koło” oprogramowania, zbudowałeś ich nieskończoną liczbę.
Więcej na temat odgórnego projektu: chociaż musisz zacząć od tego, czuję się zobowiązany do wskazania, że jeśli nie możesz zbudować koła, musisz się tego dowiedzieć, zanim zaczniesz dużo pracować nad samochodem. Musisz więc pracować od dołu do góry prawie równolegle do pracy z góry na dół. Wiedza, że możesz zbudować koło, może sugerować wiele projektów, o których wcześniej nie pomyślałeś, na przykład ciągnik siodłowy. Myślę, że podejście odgórne musi dominować, ale z bardzo lekkim akcentem.
Tak więc, aby kontynuować parafrazowanie Paula Grahama, idealnie, gdy piszesz program, dostajesz wiele części wielokrotnego użytku, które mogą zaoszczędzić dużo czasu zarówno na oryginalnym programie, jak i na innych. Aby nieco się zdystansować od Paula Grahama, działa to w dowolnym języku (choć niektórzy zachęcają do tego bardziej niż inni).
Wrogiem tego niemal magicznego procesu są programiści o bardzo krótkoterminowych perspektywach. Może to wynikać z wad osobowości, ale częściej ze zbyt szybkiej zmiany pracy i obowiązków, zarówno wewnątrz firmy, jak i pomiędzy zatrudnionymi firmami.
źródło
Użycie podejścia odgórnego przy programowaniu iteracyjnym nie dostarcza żadnego działającego kodu w pierwszych iteracjach. Dostarcza dokumenty projektowe i takie, których klient będzie miał trudności z udzieleniem opinii. Odpowiedzi typu „tak, tak sądzę (to dla mnie zbyt abstrakcyjne)” nie pomogą ci w dalszym określaniu specyfiki pożądanego systemu przez klienta.
Zamiast tego tworzysz tylko ogólny przegląd tego, co jest wymagane. (Wymagania) do zastosowania jako ogólna wskazówka dotycząca tego, co definiuje gotowy produkt i co zasługuje na pierwszeństwo we wdrożeniu. Odtąd tworzysz działające produkty dla każdej iteracji, z którymi klient może się właściwie bawić, aby sprawdzić, czy właśnie o to chodzi. Jeśli nie, to nie będzie to problemem, ponieważ nie poświęcono setek godzin na zaprojektowanie systemu, który działa inaczej niż obecnie.
Nie będę mówić w imieniu innej osoby. Nie przeczytałem też jego eseju. Odpowiedź, którą ci daję, pochodzi z mojego wykształcenia i doświadczeń.
Zastosowanie tego podejścia oznacza, że skończysz z bardziej abstrakcyjnymi blokami konstrukcyjnymi. Po prostu dlatego, że będziesz musiał zbudować autonomiczne podsystemy, które można od razu zaprezentować, nie możesz stworzyć projektu odgórnego, który jest ściśle ze sobą powiązany i musi zostać wdrożony od razu. Poprawia możliwość ponownego użycia, łatwość konserwacji, ale przede wszystkim pozwala na bardziej elastyczną reakcję na zmiany.
źródło