Kiedy zapytano Murraya Gell-Manna, jak Richard Feynman rozwiązał tak wiele trudnych problemów, Gell-Mann odpowiedział, że Feynman ma algorytm:
- Zapisz problem.
- Myśl naprawdę ciężko.
- Zapisz rozwiązanie.
Gell-Mann próbował wyjaśnić, że Feynman był innym rodzajem rozwiązywania problemów i nie można było uzyskać wglądu w studiowanie jego metod. Podobnie myślę o zarządzaniu złożonością w średnich / dużych projektach oprogramowania. Ludzie, którzy są dobrzy, są z natury dobrzy i jakoś potrafią nakładać warstwy i układać różne abstrakty, aby wszystko było możliwe do zarządzania bez wprowadzania jakichkolwiek obcych cruft.
Czy algorytm Feynmana jest jedynym sposobem zarządzania przypadkową złożonością, czy też istnieją rzeczywiste metody, które inżynierowie oprogramowania mogą konsekwentnie stosować w celu oswojenia przypadkowej złożoności?
źródło
Odpowiedzi:
Z mojego doświadczenia wynika, że największą przyczyną przypadkowej złożoności są programiści trzymający się pierwszego szkicu tylko dlatego, że tak się dzieje. Tego możemy się nauczyć z naszych angielskich lekcji kompozycji. Zebrali czas, aby przejrzeć kilka szkiców w swoich zadaniach, uwzględniając opinie nauczycieli. Klasy programowania z jakiegoś powodu nie.
Istnieją książki pełne konkretnych i obiektywnych sposobów rozpoznawania, artykułowania i poprawiania suboptymalnego kodu: Czysty kod , Efektywna praca ze starszym kodem i wiele innych. Wielu programistów zna te techniki, ale nie zawsze poświęca czas na ich zastosowanie. Są doskonale zdolne do zmniejszenia przypadkowej złożoności, po prostu nie przyzwyczaili się próbować .
Część problemu polega na tym, że często nie widzimy pośredniej złożoności kodu innych osób, chyba że został on poddany recenzji na wczesnym etapie. Czysty kod wygląda na łatwy do napisania, podczas gdy w rzeczywistości zwykle wymaga kilku szkiców. Najpierw piszesz w najlepszy sposób, który przychodzi ci do głowy, zauważasz niepotrzebne zawiłości, które wprowadza, a potem „szukaj lepszego ruchu” i refaktoryzuj, aby usunąć te zawiłości. Następnie kontynuujesz „szukanie lepszego ruchu”, dopóki nie będziesz w stanie go znaleźć.
Jednak nie wystawiasz kodu na sprawdzenie, dopóki nie zniknie, więc na zewnątrz wygląda na to, że równie dobrze mógłby to być proces Feynmana. Masz tendencję do myślenia, że nie możesz zrobić tego wszystkiego tak, więc nie zawracaj sobie głowy próbowaniem, ale prawda jest taka, że autor tego pięknie prostego kodu, który właśnie czytasz, zwykle nie jest w stanie napisać wszystkiego w jednym kawałku w ten sposób albo, jeśli mogą, to tylko dlatego, że wiele razy pisali podobny kod i mogą teraz zobaczyć wzorzec bez etapów pośrednich. Tak czy inaczej, nie można uniknąć przeciągów.
źródło
„Nie można nauczyć umiejętności architektury oprogramowania” jest powszechnym błędem.
Łatwo jest zrozumieć, dlaczego wielu ludzi w to wierzy (ci, którzy są w tym dobrzy, chcą wierzyć, że są mistycznie wyjątkowi, a ci, którzy nie chcą wierzyć, że to nie ich wina, że nie są.) jest jednak nie tak; umiejętność jest nieco bardziej wymagająca od innych umiejętności programistycznych (np. rozumienie pętli, radzenie sobie ze wskaźnikami itp.)
Mocno wierzę, że konstruowanie dużych systemów jest podatne na wielokrotne ćwiczenia i uczenie się na podstawie doświadczenia w taki sam sposób, jak bycie wielkim muzykiem lub mówcą: minimalna ilość talentu jest warunkiem koniecznym, ale nie jest to przygnębiająco duże minimum, które jest poza zasięg większości praktyków.
Radzenie sobie ze złożonością to umiejętność, którą zdobywasz, próbując kilka razy i ponosząc porażkę. Tyle tylko, że wiele ogólnych wskazówek odkrytych przez społeczność w zakresie programowania na dużą skalę (używaj warstw, walcz z duplikacją wszędzie tam, gdzie ma głowę, przestrzegaj religii do 0/1 / nieskończoności ...) nie jest tak oczywiście poprawne i konieczne początkujący, dopóki nie zaprogramują czegoś, co jest duże. Dopóki nie zostaniesz ugryziony przez powielanie, które spowodowało problemy dopiero kilka miesięcy później, po prostu nie możesz „zrozumieć” znaczenia takich zasad.
źródło
Pragmatyczne myślenie Andy'ego Hunta rozwiązuje ten problem. Odnosi się do modelu Dreyfusa, zgodnie z którym istnieje 5 stopni biegłości w różnych umiejętnościach. Nowicjusze (etap 1) potrzebują dokładnych instrukcji, aby móc zrobić coś poprawnie. Przeciwnie, eksperci (etap 5) mogą zastosować ogólne wzorce do danego problemu. Powołując się na książkę,
Ta ogólna zasada postrzegania (a przez to unikania) różnych problemów może być zastosowana w szczególności do kwestii przypadkowej złożoności. Posiadanie danego zestawu reguł nie wystarczy, aby uniknąć tego problemu. Zawsze będzie sytuacja, która nie będzie objęta tymi zasadami. Musimy zdobyć doświadczenie, aby móc przewidzieć problemy lub znaleźć rozwiązania. Doświadczenie jest czymś, czego nie można się nauczyć, można je zdobyć tylko poprzez ciągłe próby, porażki lub sukcesy i uczenie się na błędach.
To pytanie z miejsca pracy jest istotne i IMHO byłby ciekawy do przeczytania w tym kontekście.
źródło
Nie piszesz tego, ale „przypadkowa złożoność” jest definiowana jako złożoność, która nie jest nieodłączna od problemu, w porównaniu do „niezbędnej” złożoności. Techniki wymagane do „Oswajania” będą zależeć od tego, od czego zaczniesz. Poniższe odnosi się głównie do systemów, które już uzyskały niepotrzebną złożoność.
Mam doświadczenie w wielu dużych projektach wieloletnich, w których komponent „przypadkowy” znacznie przewyższał aspekt „zasadniczy”, a także tych, w których go nie miał.
W rzeczywistości algorytm Feynmana stosuje się do pewnego stopnia, ale to nie znaczy, że „myśleć naprawdę mocno” oznacza tylko magię, której nie można skodyfikować.
Uważam, że należy zastosować dwa podejścia. Weź je oba - nie są alternatywami. Jednym z nich jest rozwiązanie tego fragmentarycznie, a drugim dokonanie poważnej przeróbki. Z pewnością „zapisz problem”. Może to przybrać formę audytu systemu - modułów kodu, ich stanu (zapachu, poziomu zautomatyzowanych testów, ilu pracowników twierdzi, że to rozumie), ogólnej architektury (istnieje, nawet jeśli „ma problemy” ), stan wymagań itp. itp.
Charakter „przypadkowej” złożoności polega na tym, że nie ma jednego problemu, który należy rozwiązać. Musisz więc segregować. Gdzie to boli - pod względem zdolności do utrzymania systemu i postępu w jego rozwoju? Być może jakiś kod jest naprawdę śmierdzący, ale nie ma najwyższego priorytetu i można naprawić, aby poczekać. Z drugiej strony może istnieć kod, który szybko zwróci czas poświęcony na refaktoryzację.
Zdefiniuj plan, jaka będzie lepsza architektura i postaraj się, aby nowe prace były zgodne z tym planem - jest to podejście przyrostowe.
Wyszczególnij także koszty problemów i wykorzystaj je do zbudowania uzasadnienia biznesowego w celu uzasadnienia refaktoryzacji. Kluczową kwestią jest to, że dobrze zaprojektowany system może być znacznie bardziej niezawodny i testowalny, co skutkuje znacznie krótszym czasem (kosztem i harmonogramem) wdrożenia zmian - ma to realną wartość.
Poważna przeróbka pojawia się w kategorii „myśl naprawdę mocno” - musisz to zrobić dobrze. Właśnie w tym przypadku posiadanie „Feynmana” (cóż, niewielki ułamek byłby w porządku) bardzo się opłaca. Poważna przeróbka, która nie skutkuje lepszą architekturą, może być katastrofą. Znane są z tego pełne przepisywania systemu.
W każdym podejściu ukrywa się umiejętność odróżnienia „przypadkowego” od „niezbędnego” - co oznacza, że musisz mieć świetnego architekta (lub zespół architektów), który naprawdę rozumie system i jego cel.
Powiedziawszy to wszystko, najważniejsze dla mnie są testy automatyczne . Jeśli masz go dość, twój system jest pod kontrolą. Jeśli nie. . .
źródło
Pozwól mi naszkicować mój osobisty algorytm radzenia sobie z przypadkową złożonością.
Cała magia projektowania dotyczyłaby kroku 3: jak skonfigurować te klasy? To staje się tym samym pytaniem: jak wyobrażasz sobie, że masz rozwiązanie swojego problemu, zanim masz rozwiązanie swojego problemu?
Co ciekawe, po prostu wyobrażając masz rozwiązanie wydaje się być jednym z głównych zaleceń ludzi piszących na rozwiązywaniu problemów (zwane „myślenie życzeniowe” przez Abelson i Sussman w Struktura i interpretacja programów komputerowych i „działa wstecz” w Polya użytkownika Jak Rozwiąż to )
Z drugiej strony, nie wszyscy mają ten sam „ gust do wymyślonych rozwiązań ”: istnieją rozwiązania, które tylko Ty uważasz za eleganckie, a są inne, bardziej zrozumiałe dla szerszej publiczności. Dlatego musisz recenzować swój kod wspólnie z innymi programistami: nie tyle, aby dostroić wydajność, ale uzgodnić zrozumiałe rozwiązania. Zwykle prowadzi to do przeprojektowania, a po kilku iteracjach, do znacznie lepszego kodu.
Jeśli trzymasz się pisania minimalnych implementacji, aby przejść testy, i piszesz testy zrozumiałe dla wielu osób, powinieneś skończyć na bazie kodu, w której pozostaje tylko nieredukowalna złożoność .
źródło
Przypadkowa złożoność
Pierwotne pytanie (parafrazowane) brzmiało:
Przypadkowa złożoność pojawia się, gdy osoby kierujące projektem decydują się na dołączenie technologii, które są jedyne w swoim rodzaju, i że ogólna strategia pierwotnych architektów projektu nie miała zamiaru wnieść do projektu. Z tego powodu ważne jest, aby zapisać uzasadnienie wyboru w strategii.
Przypadkowa złożoność może zostać powstrzymana przez przywództwo, które trzyma się swojej pierwotnej strategii, dopóki celowe odejście od tej strategii nie będzie najwyraźniej konieczne.
Unikanie niepotrzebnej złożoności
Na podstawie treści pytania sformułuję to w następujący sposób:
To przeformułowanie jest bardziej zbliżone do treści pytania, w którym następnie wprowadzono algorytm Feynmana, zapewniając kontekst, który proponuje najlepszym architektom, w obliczu problemu, gestalt, z którego następnie umiejętnie konstruują rozwiązanie, i że reszta z nas nie może się tego nauczyć. Posiadanie gestu zrozumienia zależy od inteligencji przedmiotu i ich chęci poznania cech opcji architektonicznych, które mogą być w ich zakresie.
Proces planowania projektu wykorzystałby naukę organizacji do sporządzenia listy wymagań projektu, a następnie próby zbudowania listy wszystkich możliwych opcji, a następnie uzgodnienia opcji z wymaganiami. Gestalt eksperta pozwala mu to zrobić szybko i być może przy niewielkiej widocznej pracy, dzięki czemu wydaje się, że łatwo mu to przychodzi.
Poddaję się wam, że przychodzi do niego z powodu jego przygotowania. Aby gestalt eksperta wymagał znajomości wszystkich opcji, a także przewidywania w celu zapewnienia prostego rozwiązania, które pozwala przewidzieć przyszłe potrzeby, które zostaną określone w projekcie, a także elastyczność w dostosowaniu się do zmieniających się potrzeb projekt. Przygotowanie Feynmana polegało na głębokim zrozumieniu różnych podejść zarówno w matematyce teoretycznej, jak i stosowanej i fizyce. Był z natury ciekawy i wystarczająco bystry, aby zrozumieć rzeczy, które odkrył w otaczającym go świecie przyrody.
Ekspert-architekt technologii będzie miał podobną ciekawość, czerpiąc z głębokiego zrozumienia podstaw, a także szerokiej ekspozycji na wielką różnorodność technologii. On (lub ona) będzie miał mądrość, aby czerpać ze strategii, które odniosły sukces w różnych domenach (takich jak Zasady programowania w Uniksie ) i tych, które dotyczą określonych domen (takich jak wzorce projektowe i przewodniki po stylach ). Może nie jest dogłębnie zaznajomiony z każdym zasobem, ale będzie wiedział, gdzie go znaleźć.
Budowanie rozwiązania
Ten poziom wiedzy, zrozumienia i mądrości można czerpać z doświadczenia i edukacji, ale wymaga inteligencji i aktywności umysłowej, aby stworzyć strategiczne rozwiązanie gestalt, które działa razem w sposób pozwalający uniknąć przypadkowej i niepotrzebnej złożoności. Wymaga od eksperta zebrania tych podstaw; byli to pracownicy wiedzy, których Drucker przewidywał, gdy po raz pierwszy wymyślił ten termin.
Powrót do konkretnych pytań końcowych:
Konkretne metody oswajania przypadkowej złożoności można znaleźć w następujących źródłach.
Postępując zgodnie z zasadami programowania w Uniksie, będziesz tworzyć proste programy modułowe, które działają dobrze i są odporne na wspólne interfejsy. Następujące wzorce projektowe pomogą Ci zbudować złożone algorytmy, które nie są bardziej złożone niż to konieczne. Poniższe przewodniki po stylach zapewnią, że kod będzie czytelny, łatwy w utrzymaniu i optymalny dla języka, w którym został napisany. Eksperci zinternalizują wiele zasad zawartych w tych zasobach i będą mogli połączyć je w spójny, spójny sposób.
źródło
To może być trudne pytanie kilka lat temu, ale obecnie IMO nie jest już trudne do wyeliminowania przypadkowej złożoności.
Co w pewnym momencie powiedział o sobie Kent Becks: „Nie jestem świetnym programistą; jestem tylko dobrym programistą o wielkich nawykach”.
Warto podkreślić dwie rzeczy, IMO: uważa się za programistę , a nie architekta, a jego uwaga koncentruje się na nawykach, a nie wiedzy.
Jedynym sposobem na rozwiązanie trudnych problemów jest Feynman. Opis niekoniecznie jest bardzo łatwy do zrozumienia, więc opiszę go. Głowa Feynmana była nie tylko pełna wiedzy, ale także umiejętności jej stosowania. Gdy masz zarówno wiedzę, jak i umiejętności korzystania z niej, rozwiązanie trudnego problemu nie jest ani trudne, ani łatwe. To jedyny możliwy wynik.
Istnieje całkowicie niemagiczny sposób pisania czystego kodu, który nie zawiera przypadkowej złożoności, i jest w większości podobny do tego, co zrobił Feynman: zdobądź całą wymaganą wiedzę, przyzwyczaj się do jego uruchomienia, zamiast po prostu odkładać go na bok. w pewnym zakątku mózgu, a następnie napisz czysty kod.
Teraz wielu programistów nie jest nawet świadomych całej wiedzy wymaganej do napisania czystego kodu. Młodsi programiści mają tendencję do odrzucania wiedzy o algorytmach i strukturach danych, a większość starszych programistów ma tendencję do zapominania o niej. Lub duża notacja O i analiza złożoności. Starsi programiści mają tendencję do odrzucania wzorów lub zapachów kodu - lub nawet nie wiedzą, że istnieją. Większość programistów dowolnej generacji, nawet jeśli znają wzorce, nigdy nie pamiętają, kiedy dokładnie używać i sterować częściami. Niewielu programistów z dowolnego pokolenia stale ocenia swój kod pod kątem zasad SOLID. Wielu programistów miesza w każdym miejscu wszystkie możliwe poziomy abstrakcji. Na razie nie znam innego programisty, który stale ocenia swój kod pod kątem smród opisanych przez Fowlera w jego książce o refaktoryzacji. Chociaż niektóre projekty korzystają z niektórych narzędzi pomiarowych, najczęściej stosowanym miernikiem jest złożoność, czy innego rodzaju, podczas gdy dwa inne wskaźniki - łączenie i spójność - są w dużej mierze ignorowane, nawet jeśli są bardzo ważne dla czystego kodu. Kolejnym aspektem, który prawie wszyscy ignorują, jest ładunek poznawczy. Niewielu programistów traktuje testy jednostkowe jako dokumentację, a jeszcze mniej jest świadomych, że trudne do napisania lub nazwania testy jednostkowe są kolejnym smrodem kodu, który zwykle wskazuje na zły faktoring. Niewielka mniejszość zdaje sobie sprawę z mantry projektowania opartego na domenie, aby model kodu i model domeny biznesowej były jak najbardziej zbliżone do siebie, ponieważ rozbieżności z tym związane będą powodować problemy w przyszłości. Wszystkie te kwestie należy cały czas brać pod uwagę, jeśli chcesz oczyścić kod. I wiele innych, których teraz nie pamiętam. najczęściej używaną metryką jest złożoność, tego rodzaju lub innego, podczas gdy dwie inne metryki - sprzężenie i spójność - są w dużej mierze ignorowane, nawet jeśli są bardzo ważne dla czystego kodu. Kolejnym aspektem, który prawie wszyscy ignorują, jest ładunek poznawczy. Niewielu programistów traktuje testy jednostkowe jako dokumentację, a jeszcze mniej jest świadomych, że trudne do napisania lub nazwania testy jednostkowe są kolejnym smrodem kodu, który zwykle wskazuje na zły faktoring. Niewielka mniejszość zdaje sobie sprawę z mantry projektowania opartego na domenie, aby model kodu i model domeny biznesowej były jak najbardziej zbliżone do siebie, ponieważ rozbieżności z tym związane będą powodować problemy w przyszłości. Wszystkie te kwestie należy cały czas brać pod uwagę, jeśli chcesz oczyścić kod. I wiele innych, których teraz nie pamiętam. najczęściej używaną metryką jest złożoność, tego rodzaju lub innego, podczas gdy dwie inne metryki - sprzężenie i spójność - są w dużej mierze ignorowane, nawet jeśli są bardzo ważne dla czystego kodu. Kolejnym aspektem, który prawie wszyscy ignorują, jest ładunek poznawczy. Niewielu programistów traktuje testy jednostkowe jako dokumentację, a jeszcze mniej jest świadomych, że trudne do napisania lub nazwania testy jednostkowe są kolejnym smrodem kodu, który zwykle wskazuje na zły faktoring. Niewielka mniejszość zdaje sobie sprawę z mantry projektowania opartego na domenie, aby model kodu i model domeny biznesowej były jak najbardziej zbliżone do siebie, ponieważ rozbieżności z tym związane będą powodować problemy w przyszłości. Wszystkie te kwestie należy cały czas brać pod uwagę, jeśli chcesz oczyścić kod. I wiele innych, których teraz nie pamiętam. podczas gdy dwa inne wskaźniki - sprzężenie i spójność - są w dużej mierze ignorowane, nawet jeśli są bardzo ważne dla czystego kodu. Kolejnym aspektem, który prawie wszyscy ignorują, jest ładunek poznawczy. Niewielu programistów traktuje testy jednostkowe jako dokumentację, a jeszcze mniej jest świadomych, że trudne do napisania lub nazwania testy jednostkowe są kolejnym smrodem kodu, który zwykle wskazuje na zły faktoring. Niewielka mniejszość zdaje sobie sprawę z mantry projektowania opartego na domenie, aby model kodu i model domeny biznesowej były jak najbardziej zbliżone do siebie, ponieważ rozbieżności z tym związane będą powodować problemy w przyszłości. Wszystkie te kwestie należy cały czas brać pod uwagę, jeśli chcesz oczyścić kod. I wiele innych, których teraz nie pamiętam. podczas gdy dwa inne wskaźniki - sprzężenie i spójność - są w dużej mierze ignorowane, nawet jeśli są bardzo ważne dla czystego kodu. Kolejnym aspektem, który prawie wszyscy ignorują, jest ładunek poznawczy. Niewielu programistów traktuje testy jednostkowe jako dokumentację, a jeszcze mniej jest świadomych, że trudne do napisania lub nazwania testy jednostkowe są kolejnym smrodem kodu, który zwykle wskazuje na zły faktoring. Niewielka mniejszość zdaje sobie sprawę z mantry projektowania opartego na domenie, aby model kodu i model domeny biznesowej były jak najbardziej zbliżone do siebie, ponieważ rozbieżności z tym związane będą powodować problemy w przyszłości. Wszystkie te kwestie należy cały czas brać pod uwagę, jeśli chcesz oczyścić kod. I wiele innych, których teraz nie pamiętam. Kolejnym aspektem, który prawie wszyscy ignorują, jest ładunek poznawczy. Niewielu programistów traktuje testy jednostkowe jako dokumentację, a jeszcze mniej jest świadomych, że trudne do napisania lub nazwania testy jednostkowe są kolejnym smrodem kodu, który zwykle wskazuje na zły faktoring. Niewielka mniejszość zdaje sobie sprawę z mantry projektowania opartego na domenie, aby model kodu i model domeny biznesowej były jak najbardziej zbliżone do siebie, ponieważ rozbieżności z tym związane będą powodować problemy w przyszłości. Wszystkie te kwestie należy cały czas brać pod uwagę, jeśli chcesz oczyścić kod. I wiele innych, których teraz nie pamiętam. Kolejnym aspektem, który prawie wszyscy ignorują, jest ładunek poznawczy. Niewielu programistów traktuje testy jednostkowe jako dokumentację, a jeszcze mniej jest świadomych, że trudne do napisania lub nazwania testy jednostkowe są kolejnym smrodem kodu, który zwykle wskazuje na zły faktoring. Niewielka mniejszość zdaje sobie sprawę z mantry projektowania opartego na domenie, aby model kodu i model domeny biznesowej były jak najbardziej zbliżone do siebie, ponieważ rozbieżności z tym związane będą powodować problemy w przyszłości. Wszystkie te kwestie należy cały czas brać pod uwagę, jeśli chcesz oczyścić kod. I wiele innych, których teraz nie pamiętam. mantrą, aby model kodu i model domeny biznesowej były jak najbliżej siebie, ponieważ rozbieżności z pewnością będą powodować problemy w przyszłości. Wszystkie te kwestie należy cały czas brać pod uwagę, jeśli chcesz oczyścić kod. I wiele innych, których teraz nie pamiętam. mantrą, aby model kodu i model domeny biznesowej były jak najbliżej siebie, ponieważ rozbieżności z pewnością będą powodować problemy w przyszłości. Wszystkie te kwestie należy cały czas brać pod uwagę, jeśli chcesz oczyścić kod. I wiele innych, których teraz nie pamiętam.
Chcesz napisać czysty kod? Nie wymaga magii. Po prostu dowiedz się wszystkiego, co jest wymagane, a następnie użyj go do oceny czystości kodu i dokonaj refaktoryzacji, aż będziesz zadowolony. I ucz się dalej - oprogramowanie to wciąż młoda dziedzina, a nowe spostrzeżenia i wiedza są zdobywane w szybkim tempie.
źródło