(Nie)projektowanie i rozwój oprogramowania a YAGNI

0

Uprzedzając pytania i pouczenia - nie chodzi mi o funkcjonalność tworzonego systemu i rzeźbienie ficzerów na wyrost, lecz o sposób, w jaki (nie)powstaje jego design, architektura etc ;)

Pytam dlatego, że mam (nie pierwszy raz zresztą) déjà vu, gdy patrzę na rzeczy, które klepię lub inni klepią i już sam nie wiem, czy to objawy syndromu niemieckiego architekta lub innego strasznego choróbska, czy co.

Piszę o déjà vu dlatego, że przeważnie wygląda to w miarę podobnie i ma podobne etapy - z moim udziałem lub bez, lub tylko częściowym i w niektórych etapach, nieważne:

  • zaczyna się projekt
  • jak się go zaczyna robić, to realizacja przebiega w ogólnie akceptowanym przez zespół planie minimum, to może oznacza na przykład "encja na twarz i pchasz" lub klasyczna trójwarstwowa lazania z frameworkiem X z przodu i bazą Y z tyłu w backendzie, ale tak naprawdę w grę wchodzą dowolne drogi na skróty, które krótkoterminowo nie spowodują większych reperkusji
  • z początku z wybranym planem minimum da się jakoś żyć, w projekcie nie ma dużo skomplikowanych zależności więc jeszcze się to nie mści - nie ma bodźca by odejść od planu minimum, bo YAGNI, nie twórzmy architektury na wyrost, jest dobrze jak jest, jakoś się żyje, nie wiadomo co będzie potrzebne więc po co wymyślać, jesteśmy agile a nie waterfall
  • kula błota powoli rośnie, na tyle wolno że działa efekt gotowanej żaby
  • przy odrobinie szczęścia projekt umiera lub przechodzi w utrzymanie zanim kula błota przekroczy masę krytyczną
  • jak szczęścia zabraknie, to drogi na skróty zaczynają w końcu kopać w d**ę przy wprowadzaniu kolejnych zmian, strach to ruszać, no i tak się żyje z legacy czasu rzeczywistego

Co więcej, widzę to nawet wtedy, gdy nie gonią terminy i nie trzeba dowozić na wczoraj. Nie ukrywam, że sam też długo kierowałem się takim myśleniem, radośnie produkowałem legacy na bieżąco i dawałem złapać na gotowaną żabę :D Niemniej jednak coraz bardziej mi ten stan rzeczy - i jego (postrzegana przeze mnie) wszechobecność - przeszkadza. No, ale jako cienki bolek z mlekiem pod nosem to sobie mogę.. ;)

Jak wy do tego podchodzicie? Trzymacie się do końca tego planu minimum, umiecie powiedzieć "sprawdzam" i popchnąć projekt w kierunku, który uważacie za słuszny, zanim dotychczasowy będzie zbyt upierdliwy albo nawet później? A może od samego początku nie akceptujecie pewnych dróg na skróty - jeśli tak, to gdzie wyznaczacie granicę?

@Charles_Ray @Afish @Shalom @hauleth @kq @krwq @jarekr000000 jeśli macie czas i chęci, podzielcie się swoją perspektywą ;)

1

Ja często spotykam się z anemicznymi modelami całkowicie powiązanymi z ORMem, jednym DTOsem do wszyskiego.

No i każda próba przeforsowania czegoś nowego spala się na panewce, bo albo traci się czas na powtórną analizę zadania, bo osoba za to odpowiedzialna jak zwykle to skopała, albo deadline jest na wczoraj, albo robisz projekt z osobą, która nie ma pojęcia i koniec końców robicie po linii najmniejszego oporu, albo pseudoarchitekt/pm/manager/właściciel wymusza użycie istniejących bibliotek w innych projektach, co już samo w sobie powoduje, że ciężko z gówna wyrzeźbić.

Bywa i tak, że człowiek kombinuje jak koń pod górkę, chociażby z optymalizacją sql, bo firma januszex sa ma bazę danych na azure, bez żadnych indeksów, bo za większą przestrzeń dyskową trzeba więcej zapłacić, elasticsearch - nie, cache - nie, cokolwiek - nie.
No i co człowiek ma zrobić, jak z wyszukiwarki do bazy leci LIKE po 10 kolumnach.

No i kończy się to tak, że człowiek bierze dłuto i rzeźbi, traci chęci i nadzieje, szuka nowej pracy, łapie haczyk HRu, po czym otrzymuje jeszcze większe dłuto do ręki :)

8

Kuba Pilimon fajnie powiedział, że zaczęliśmy traktować podejście „no big design upfront” jako „no design at all”.

Dużo zależy od kontekstu - jak skomplikowana jest domena, czy robimy MVP, czy osadzamy się w istniejącej architekturze, jakich mamy ludzi, ile czasu, jakie normy musimy spełniać itd. (tzw. drivery architektoniczne).

Zwykle jednak występuje po prostu brak strategicznego myślenia, a jedynie prześciganie się na buzzwordy i wzorce taktyczne, które niewiele wnoszą. Łatwiej dodać do projektu takiego Vavra czy Reactora i wpisać go sobie do LinkedIna niż zastanowić się nad ograniczeniami, wyzwaniami domenowym i kierunkiem rozwoju softu.

Dobry soft wymaga planu + nie całą aplikację trzeba stawiać na jedną modłę - można podzielić na moduły i każdy znich zrobić w innej architekturze tak, żeby tez nie wszystko kodować w portach adapterach czy mikroserwisach - to patologia w drugą stronę.

Jeśli chodzi o drogę na skróty - jak najbardziej! Tylko trzeba wiedzieć, gdzie świadomie przyciąć, gdzie można skipnąć jakiś wzorzec czy warstwę. Ja to nazywam świadomym zarządzaniem jakością i długiem technicznym. Naprawdę czasem mogę ogarnąć cały moduł/MVP za pomocą Springa i JPA w tydzień, zamiast rzeźbić jakieś pure functional state-of-the-art cuda wianki. Jakaś cześć kodu wykonuje się 50ms, a mogłaby po optymalizacji 10ms? Może na danym etapie rozwoju można z tym żyć.

Jak do tego podejść? Doświadczenie + jest sporo wiedzy na ten temat. Planowanie rozwoju aplikacji to robota dla bardziej doświadczonych członków zespołu, którzy chcą się rozwijać w kierunku architektów. Do tego przydaje się otwartość na ludzi z biznesu, o czym pisałem na mikroblogu.

7

Gdy ludzie uczą się czegoś nowego, to rozumieją, że za pierwszym razem nie wyjdzie poprawnie, ale jak piszą aplikację, to jakoś zawsze się łudzą, że potrafią zrobić tak, żeby nie trzeba było poprawiać. No ale rzeczywistość świetnie pokazuje, że o ile nie piszesz tej samej aplikacji piąty raz, to zawsze się w coś wkopiesz. Trzeba zaakceptować fakt, że aplikacja nie jest wyryta w kamieniu i trzeba będzie część (w skrajnych przypadkach całość) pracy wyrzucić i zrobić od nowa, mając dodatkowe doświadczenie i wiedzę.

Jeżeli nie zgadzasz się, aby jutro wyrzucić kod napisany dzisiaj, to w końcu utkniesz w legacy. Dopiero gdy zaakceptujesz to ryzyko, wtedy będziesz mógł ze spokojem rozwijać aplikację, bo nie będzie tego strachu/smutku/rozczarowania, że tyle czasu spędziłeś nad elementem X, a teraz trzeba go wywalić i zacząć od nowa.

Większość ludzi i firm nie lubi tego podejścia i szukają jakichś sposobów, aby za pierwszym razem zrobić idealne rozwiązanie. A potem jednak okazuje się, że (według statystyk) wymagania zmieniają się o 30%, a budżet jest przekroczony dwukrotnie.

Jak już przyjmiemy podejście, w którym nie boimy się wyrzucenia kodu (modułu, komponentu, serwisu itp.), to trzeba zacząć pisać aplikacje tak, aby usuwanie było jak najprostsze. Przede wszystkim trzeba mieć sensowny model, bo błąd w tym obszarze jest praktycznie nieodwracalny. Potem wprowadzamy małe konteksty (jak z DDD) i pilnujemy ich niezależności. Potem dbamy o kontrakty między kontekstami, tu przydaje się bardzo doświadczony architekt, który już takie rzeczy klepał i wie, gdzie popełnił błędy. A potem już jest o wiele prościej, bo gdy jakiś moduł X będzie skopany, to się go przepisze i kluczowe jest, żeby przepisanie trwało miesiąc zamiast roku.

Jeżeli zaś nie chcemy takiego podejścia i ze wszystkich sił walczymy o trzymanie tego, co już zostało napisane, to potrzebny jest dobry architekt (który już popełnił błędy) i zamrożone wymagania. Jeżeli tego nie ma, to i tak skończymy z legacy, kwestia czasu.

Gwiazdka 1: Piszę to z perspektywy systemu rozproszonego, pisanego z ideą mikroserwisów i rozwijanego przez 5+ lat. W innych sytuacjach opisane wyżej podejście może nie być dobre.

Gwiazdka 2: Okej, a jak w takim razie zrobić dobry model i dobre kontrakty? Tu są 3 elementy: 1) doświadczenie domenowe - rzeczywistość zaskakuje, drzewa genealogiczne nie są drzewami, pesele nie są liczbami i mają kolizje, a adresy nie są postaci Ulica Numer. Takich rzeczy raczej się nie przewidzi, trzeba się odpowiednio naciąć 2) doświadczenie innych - dobrze jest pogadać z innymi architektami, dzielić się doświadczeniem, chodzić na konferencje itp., to naprawdę pomaga w zrozumieniu, co w praktyce się sypie. Dobrze jest mieć jakiegoś konsultanta, który niekoniecznie pisał 100 systemów, ale widział ich problemy. 3) jakieś typowe "best practices", czyli jak wersjonować, jak opakować identyfikatory w value objecty czy coś, jak zrobić przestrzenie nazw, jak zrobić haki na przyszłość (jakaś hashmapa na nieprzewidziane pola itp.), to jest opisane w książkach/konferencjach, trzeba się po prostu wyedukować.

2

kula błota powoli rośnie, na tyle wolno że działa efekt gotowanej żaby

Tutaj. Na tym etapie powinien być wcielany refaktoring i zasada skauta. Ale do tego trzeba teamu, który widzi potrzebę refaktoru (bo wiele osób nie ma poczucia stylu i uważa, że dobrze jest jak jest, byle działało) i który ma tyle dyscypliny, żeby go wprowadzać (tutaj zarządzanie jeszcze musi nie przeszkadzać, bo jak PM będzie naciskać na "wincyj ficzerów", a próby refaktoringu/pisania testów/czegokolwiek będą hejtowane - to raczej się nic nie zrobi).

Czyli pisanie byle jak, byle do przodu jest okej na krótką metę, ale trzeba to potem spłacać, ten dług techniczny.

YAGNI, nie twórzmy architektury na wyrost

Często nie da się od razu zaprojektować aplikacji, jeśli się wcześniej nie robiło podobnej (chyba, że apka jest trywialna), więc z tą architekturą to niby okej, że nie na samym początku. Pierwsze etapy pracy nad nowym projektem lepiej potraktować jako zwykłe prototypowanie i zbieranie wymagań. Bo tak to wygląda w końcu. Coś robisz, nie wiesz najpierw co, musisz czytać wymagania, myślisz jak zrobić, coś robisz, konsultujesz z innymi, w końcu ileś tasków później zbieracie projekt do kupy, bo już coś działa, już coś się pokazuje.

Tylko, że architektonicznie to zwykle kupa (w zależności od kultury teamu - albo spaghetti kod pisany na kolanie, albo coś na maksa przeinżynierowanego - i z dwojga złego wolę to pierwsze - łatwiej jest nadać kształt czemuś, co kształtu nie ma, niż rozmontowywać kawałek po kawałku jakieś chore przeinżynierowane abstrakcje). I na tym etapie można się pobawić w refaktoring, wydzielanie sensownych abstrakcji, przepisanie kawałka kodu od zera itp.

3

Wydaje mi się, że dużo pomaga modułowość i możliwość łatwego wywalenia całego modułu i napisania od 0, Łatwiej jest zmieniać takie pojedyncze małe rzeczy niż przepisywać pół systemu. Łatwiej też to potem testować

1

Ja wyznaczam granicę przy próbie zrobienia tego co jest w tytule - czyli rozpoczęcia pracy bez zrobienia projektu przynajmniej w bardzo ogólnym sensie. Ciekawe że jak trzeba przygotować wycenę dla zewnętrznego klienta to szefostwo nagle widzi sens takiego projektu.....

3

Ogólnie to akceptuje drogi na skróty, ale im większy i sensowniejszy projekt tym mniej.
Warstwy, projekty i inne cuda - olewam.
Za to testy, nawet w małych projektach, muszą być sensowne.

Co do reszty to zasada jest prosta - jak na coś narzekamy. to poprawiamy przy pierwszej okazji (jak tylko coś ruszamy w danym kodzie).
Jak ktoś w zespole narzeka ... no to znaczy, że trzeba go przekonać do naprawienia. Ogólnie narzekacze (nie wszyscy) to niezła moc zespołu - mogą projekt nieźle podciągnąć.

1 użytkowników online, w tym zalogowanych: 0, gości: 1