Wątek przeniesiony 2021-10-09 12:07 z Flame przez Shalom.

Dlaczego programy "enterprise" muszą być tak kosmicznie przekombinowane?

17

Byłem już w iluś projektach, ale w większości były stosunkowo niewielkie. Staraliśmy się, żeby kod był czysty i czytelny - pisaliśmy "dla siebie".
Ostatnio trafiłem do takiego "korpo-projektu" zrobionego przez jakichś szaleńców, którzy naczytali się 10000 książek o wzorcach projektowych, i oczywiście nie po to, żeby teraz nie wciskać tych wszystkich wzorców wszędzie, niezależnie czy ma to jakikolwiek sens czy nie. Nie można zrobić

int sum = 2 + 3;

tylko trzeba

Integer a = IntegerBuilder
  .fromPrimitiveInt(2)
  .withSign('+')
  .build();
Integer b = IntegerBuilder
  .fromPrimitiveInt(3)
  .withSign('+')
  .build();
Integer sum = OperationResultFactory
  .createResult()
  .withOperationType(operationUtils.getOperation('addition'))
  .withNumbers(ArrayOfNumbersHandler.getNumbersFromNumberListWrapper(ArrayOfNumbersHandler.createArrayOfNumbersFromIntegers(a, b)
  .doWhateverOtherUnnecessaryBsICouldThinkOf();

??
To jest jakieś kompletne szaleństwo. Nawciskane warstw abstrakcji, które nie rozwiązują żadnych problemów, tylko tworzą nowe. Chcesz zobaczyć, co się dzieje, np. jak wstawisz nowy rekord typu User do bazy? Nie wystarczy, że zerkniesz do UserTriggerHandler. Musisz iść do jakiejś bzdurnej TriggerHandlerFactory, która wywołuje jakieś inne bzdurne klasy, które wywołują inne bzdurne klasy, które wywołują inne bzdurne klasy, i dopiero po przebiciu się przez 5 warstw bzdurnych, niepotrzebnych abstrakcji dochodzisz do czegoś, co w poprzednich projektach było zwyczajnie UserTriggerHandlerem. Każda z tych klas "rozwiązuje" problem, który na 99% nigdy nie powstanie, za to tworzy kilka nowych, już teraz, kiedy ja potrzebuję naprawić jakiegoś buga w tej istniejącej logice.
Szczerze mówiąc to ten kod z tymi całymi "enterprise patternami" jest równie nieczytelny, jak hinduso-kod pisany przez ludzi, którzy znali tylko i wyłącznie struktury "if" i "for", i zagnieżdżali je 25 razy, żeby osiągnąć pożądany rezultat, tyle że ten hinduso-kod można było śmiało przerabiać po kawałku na coś bardziej sensownego i było to mile widziane, a tutaj oczywiście jest system zaprojektowany przez doświadczonych architektów, znających wszystkie wzorce projektowe i w ogóle, i tego betonu już nikt nie ruszy, do końca świata.
Ja wiem, że "kto nigdy nie strzelił do komara z armaty, niech pierwszy rzuci kamieniem", ale dla niektórych programistów, a zwłaszcza architektów, to jest po prostu styl życia. Dlaczego oni muszą to robić?! I dlaczego ja potem muszę to nieczytelne spaghetti napisane zgodnie ze wszystkimi SOLIDami i innymi śmiesznymi skrótami z ewidentnym pominięciem tego najważniejszego (KISS) utrzymywać?!
Nienawidzę tej roboty.
Rant over.

2

Ostatnio czytałem artykuł o tym, że w większości wielkich firm, zbyt szybko wyciąga się uzdolnionych devów na wyższe stanowiska, przez co w pisaniu kodu jest ciągły niedosyt ludzi, którzy rozumieją co robią (pomijając w ogóle, że mało jest ludzi z odpowiednimi predyspozycjami i realnym wykształceniem). Natomiast ludzie, którzy nie rozumieją musza pisać na pałę, w jeden z dwóch sposobów, które wskazałeś. Z dwojga złego, to podejście „overengineered” trochę łatwiej zmodyfikować na zasadzie dodania jeszcze jednej warstwy lub przekierowania z jednego miejsca w drugie, trochę łatwiej usunąć obiekt i przemieścić go.

3

korporacje to czesto przechowalnie dla slabych programistow.

12

Jest dużo przyczyn. Raczej nie chodzi o złośliwość:

  • każdy kiedyś żałował, że nie zrobił gdzies dodatkowej warstwy abstrakcji, więc potem już wpiernicza w podobne miejsca, czy to ma sens czy nie (chyba sam najczęściej w tą pułapkę wpadam),
  • chęć ogarnięcia projektu w jeden spójny sposób, więc produkujemy ultra generyczny pattern, który pasuje na wszystkie funkcje w projekcie (mimo że w 90% kodu jest overkillem),
  • moda i kargo kult - widziałem, że kolega robił taki pattern więc też będę robił (nieważne, że to był inny projekt), ktoś na blogu pokazał fajny pattern... może się kiedyś przydać więc wrzucamy na zapas,
  • braki w języku programowowania łatamy warstwami - (specyficzne dla javy i podobnych języków), tu trudno coś nawet poradzić,
  • opór korpoarchitektów i korpomanagierów przed zmianami- nie można uprościć uprzednio wypracowanych patternów, bo poprzednie projekty tez były tak zasrane, ale się udały (w końcu z bólem weszły na produkcję) (to, że zwolniła się połowa programistów, a projekt przez 90% czasu był w fazie łatania błędów już umyka),
  • specyficzny sposób pokazywania kto ma większe cojones (przez narzucenie własnego patternu, lub pokazywanie innym, że są głupi bo nie ogarniają),
  • chyba na koniec najważniejsze: 95% korpoarchitektów wymyślających takie frameworki nie pisze w nich nic większego niż todo-list, nie widzi problemu
3

Skoro kasa jest proporcjonalna do ilości linii ...

Właśnie odnawiam kod w starszych projektach, i ogromne ilosci linii kasuję - chyba powinienem oddać kasę klientowi ?

3

Trzeba uwzględnić, że takie korpo-warstwy mogą rozwiązywać problemy w chwili T0, ale w chwili T0+2 lata, problemy z T0 są nieistotne. Kod został.

Nie słyszeliście nigdy "zróbmy jakieś założenia"? Moim zdaniem stopień abstrakcji/przekombinowania wynika ze stanu wiedzy dostępnej na moment projektowania systemu. Po tym jak projekt jest wdrożony często przychodzi refleksja "można to było zrobić inaczej, prościej... gdyby tylko na początku było wiadomo, że X, Y, Z". No ale bywa tak, że brakuje wiedzy o tych X,Y,Z. Jeśli chcemy czekać (przeważnie chcemy, ale z różnych względów nie możemy), to idziemy w kierunku waterfalla.

Jak sobie radzić z brakiem wiedzy o szczegółach X? Przykryć X dodatkową abstrakcją? Jak odwrócić zależność od nieznanego Y? Interfejs i dostawca usługi?

1

Czasem te skomplikowane patterny™ zwiększają poziom wejścia, ale gdy już zrozumiesz o co chodzi, jakie są konwencje itd. to faktycznie okazuje się że ma to ręce i nogi

Aczkolwiek konsultanci ewangelizujący też mają swoje za uszami :D

Kiedy gruboziarnisty kod jest lepszy?

Czy u was w pracy stosuje się Domain Driven Design?

9

@Crazy_Rockman powodów może być wiele i czasami faktycznie jest tak że trafia się "przeinżynierowanie", ale uważałbym z takimi rantami, szczególnie jeśli w projekcie jesteś "nowy" i nie rozumiesz jeszcze do końca wymagań biznesu ani gdzie ten projekt jest umieszczony w ekosystemie innych projektów. Jeśli masz jakieś HandlerTriggerFactory to sugeruje że takich handlerów może być wiele z czego ty możesz sobie nie zdawać sprawy.

Każda z tych klas "rozwiązuje" problem, który na 99% nigdy nie powstanie,

Bardzo śmiałe założenie, ale znów bardzo ryzykowne. Moze taki problem już faktycznie "powstał" i w odpowiedzi na niego 3 lata temu dodano obsługę? :)

Ten twój przykład z DSLem jest bardzo fajny, sam robiłem jakiś czas temu coś podobnego, więc się do niego odniosę. Nie będę sie tutaj rozwodził nad szczegółami, ale w wielkim skrócie potrzebowaliśmy kawałka kodu, który z jednej strony można "ewaluować", a z drugiej strony wygenerować na jego podstawie w innym systemie SQLa. Ktoś patrząc tylko na ten system który potrzebuje natychmiastowej ewaluacji wyrażenia też mógłby rantować że po co robimy jakiś cyrk z DSLem, skoro można było bezpośrednio napisać kawałek kodu...

Generalnie zalecam patrzeć na cudzy kod wychodząc z założenia, że autor wiedział co robi, a nie z założenia ze autor to debil. Widziałem wiele razy (i sam też się na tym łapałem) akcje w stylu "przepiszmy ten kawałek kodu, bo przecież da się to zrobić 100 razy prościej", co po kilku dniach/tygodniach kończyło się zaoraniem brancha, bo okazywało się, że jednak nie da się prościej, zeby obsłużyc wszystkie przypadki użycia i spełnić wymagania biznesowe.

5

Zgadzam się że czasami jest przekombinowane, taki "overengineering". Robi się go "przekombinujmy" po to żeby "przekombinować".

Ale z kolei innym razem, to co niektórzy odbierają jako "przekombinowanie", lub "utrudnianie prostych zadań", jest po prostu generalny/ogólnym podejściem do problemu - zbyt ogólnym dla tych którzy nie znają dziedziny. Dla kogoś kto nie zna dziedziny, i chce zrobić "jedną prostą rzecz", możę wydawać się dziwne że musi skorzystać z innych elementów - dla niego to jest przekombinowane. Ale to czego nie wie ta osoba, to to że jego potrzeba jest tylko jedną z wielu, i dodatkowo jest jedną z rodziny problemów - i tym "przekombinowanym" sposobem można rozwiązać całą taką rodzię problemów.

Innymi słowy, czasem przekombinowanie jest przekombinowaniem, faktycznie. Ale czasem przekombinowane jest coś tylko przez ignorancję, i tak na prawdę jest świetnym rozwiązaniem.

Przykładowo, dla kogoś kto jeździł na automacie całe życie ręczna skrzynia biegów może być przekombinowana. Albo dla programisty node'a C może być przekombinowane. Dla programisty Vue.js - Angular może być przekombinowany. Ale czy są takie w istocie? Czy po prostu są bardziej ogólnymi rozwiązaniami?

PS: PHP jest przekombinowany koniec kropka.

5
  1. Bo programowanie na większą skalę jest trudne i ludzie próbują sobie radzić za pomocą tego co znają (mnóstwo wzorców projektowych "na zapas"), bo boją się spaghetti, które jest mało utrzymywalne. Problem w tym, że to, co potem powstaje, też jest mało utrzymywalne, ale cóż, nie dało się lepiej.

  2. Bo języki są mało ekspresywne. Często mam wrażenie, że to, czego potrzeba, to języki, które by ogarniały abstrakcje za nas, zamiast klepania ręcznie tych abstrakcji w postaci "wzorców projektowych" czy wydziwionych wewnętrznych frameworków. Dodajmy do tego, że wiele programistów nie zna dobrze języków, w których pisze, więc nawet nie wykorzystuje w pełni możliwości języka i kod jest bardziej zagmatwany niż mógłby być.

  3. Bo komercyjne i zespołowe pisanie ma dużą bezwładność. Pisząc sobie własny projekt hobbystycznie możesz popróbować różnych wzorców, a później stwierdzić, że dupa, to był błąd i przepisujesz wszystko od nowa w myśl zasady KISS. A w firmach się tak nie da, bo produkt już jest na produkcji, więc jak ktoś się pojechał za daleko z abstrakcjami, to już musi tak być. Chyba, że jednak podejmujemy decyzję o przepisaniu czegoś, ale to raczej zabawa na wiele dłużej, bo projekty są zwykle o wiele większe. Więc to przeinżynierowane legacy się ciągnie latami czasem.

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