Overengineering jako wzorzec projektowy

7

Z mojego skromnego doświadczenia wychodzi, że dość często w projektach używa się ostro przegiętej architektury doprawionej miljonem zależności do rozwiązywania banalnych problemów. Typowe przykłady:
Aplikacje mobilne składające się z 5 ekranów na krzyż mają w sobie:

  • Biblioteke do IoC
  • ORM
  • Event Bus
  • Jakieś customowe biblioteki do MVVM

Proste aplikacje serwerowe z pojedynczym endpointem ładują Springa z wszystkimi dobrodziejstwami, 5 bibliotek do wrzucenia paru linijek logów i również ORM'a do realizacji banalnych zadań.

Zastanawiam się, czy ma to jakiś ukryty sens, czy chodzi o takie sprawy jak:

  • Na blogu przeczytałem, że RxJava to super rzecz i chcę tego użyć.
  • Wszyscy teraz chcą programistów Spring, więc użyjmy tego frameworka, bo chcę go mieć w CV.
  • A co jak nasza aplikacja za 5 lat będzie większa i wtedy to się przyda?

Do tego sprawa trochę poboczna, ale chyba wpisująca się w ten trend - fetysz clean code, polegający na niekończących się dyskusjach, jak nazwać zmienną, żeby zamiast 20 znaków miała 15 znaków i dalej mówiła co przechowuje. Czepianie się o if(obj==null) zamiast if(null==obj), bo w C++ można pomylić porównanie z przypisaniem, my co prawda piszemy w Javie, ale na wszelki wypadek...

6

Proste aplikacje z jednym endpontem?
Ktoś tak robi na produkcji?

Wszyscy teraz chcą programistów Spring, więc użyjmy tego frameworka, bo chcę go mieć w CV.

Powiem szczerze że to mnie dziwi. Większość firm szuka programistów Springa, Angulara itp więc wielu ludzi się boi wykluczenia z rekrutacji.
Poza tym produkcja to nie eksperyment na projekt w Githubie, i tam używa się czegoś czego się zna.
To czy jar wazy 100 czy 200 mb to żadna różnica w porównaniu do rozmiaru community, dobrej dokumentacji itp

2

To nie wiem gdzie pracujesz.. chociaż z clean coderem miałem do czynienia. Na końcu każdego pliku, między nawiasem kończącym klasę, a drugim kończącym ostatnią metodę musiał być enter xD

7

@IHaveHandedInMyResignation:
A to ja kiedyś miałem taki przypadek, gość robił logikę w kontrolerach, klasy z 10 polami itp ale jak były u mnie przez przypadek dwie linie odstępu to afera xD.
Ja się nauczyłem formatowania, typ dobrego kodu raczej nie...

1

OP: Mówisz o projektach komercyjnych czy amatorsko-edukacyjnych? Jeżeli to drugie, to nie widzę w tym nic dziwnego - ludzie chcą na jakimś prostym przykładzie ogarnąć, jak dane narzędzie działa.

5

A jeszcze lepiej kiedy:

  • design jest fancy,
  • zrobione ASAP,
  • project jest flexible,
  • itp itd.

Coraz częściej rzeczy jest możliwych do wyklikania. Potrzeba pisania czegoś samemu jest coraz rzadsza. Zarządy firm kumają IT w stopniu najwyżej miernym. Dla nich ważne, że jest zrobione. Ktoś rzucił buzzwordem typu Spring, który pozwala w krótkiej perspektywie zaoszczędzić parę tysięcy¿ "Me gusta¡" - krzyczą członkowie zarządu i godzą się na takie fajerwerki. Ale, że RAMu trzeba dołożyć albo potem poprawki robić, to nikt nie wie czemu tak się dzieje. Tzn. programiści wiedzą, ale ich mało kto słucha.

4

Mam takie doświadczenia ze sporej liczby komercyjnych projektów, które miały miejsce w sporej liczbie firm. Jak ktoś sobie chce coś prywatnie wyrzeźbić, to nic mi do tego - edukacyjnie wiadomo, że ma to sens. Ale jak chodzi o zrobienie prostej aplikacji do obsługi jakiejś tam promocji, serwisu, który ma szybko dostarczyć jakąś banalna funkcjonalność, czy innego przysłowiowego CRUD'a, to już zaczyna to przypominać trochę kult cargo, w efekcie czego mamy np. aplikacje mobilną z paroma guzikami na krzyż, gdzie zamiast zwyczajnie zareagować na kliknięcie jest rozgłaszany event o naciśnięciu guzika, jakis serwis go przechwytuje, pobiera dane, wysyła inny event, że dane pobrane, co znowu jest przechwytywane przez jakiś ekran i pokazane na ekranie. W efekcie czego po zajrzeniu w taki kod nie wiadomo kompletnie nic, stack trace z exceptionami pokazuje wszystko co możliwe, ale zero odwołań do własnego kodu. Jak przychodzi zrobić jakąś prostą zmianę, to po tygodniu odpowiedź brzmi, że się nie da, bo nie ma takiej adnotacji, ew. ta biblioteka, co jej uzywamy już od tygodnia jest niemodna i trzeba poświęcić miesiąc na jej podmianę do modniejszej. A po przeczytaniu paru rozdziałów z "Clean Code" (nie żebym miał cos przeciwko) 20% czasu w projekcie jest przepalane na dyskusje o wyższości spacji nad tabami.

5

Biblioteke do IoC
(...)
Proste aplikacje serwerowe z pojedynczym endpointem ładują Springa z wszystkimi dobrodziejstwami

NIe znam ekosystemu Javy ale czytając posty na forum coraz częściej odnoszę wrażenie że problemem tak naprawdę jest ten cały Spring, który rzutuje negatywnie na pewne inne, całkowicie normalne aspekty. I winą tutaj po części jesteście Wy szanowni programiści Java, bo wykazujecie się trochę arogancją i nie bierzecie pod uwagę że framework którego Wy używacie nie jest jedyną miarą. Później pojawiają się geniusze którzy wszem i wobec głoszą że te całe IoC to w ogóle zło i tyle, i po co to w ogóle używać.W przypadku IoC ja uważam że nawet w prostszych aplikacjach IoC można stosować i nie ma w tym nic złego, tym bardziej że jest tyle lekkich bibliotek do tego.Oczywiście wszystko ma swoje granice i zależy od wymagań, więc zdaję sobie sprawę że są przypadki gdzie faktycznie podejmuje się próby przeinżynierowania prostych problemów. W 99% przypadków nie zaliczał bym do tego IoC- zakładając że używa się do tego coś normalnego.

fetysz clean code, polegający na niekończących się dyskusjach, jak nazwać zmienną, żeby zamiast 20 znaków miała 15 znaków i dalej mówiła co przechowuje. Czepianie się o if(obj==null) zamiast if(null==obj), bo w C++ można pomylić porównanie z przypisaniem, my co prawda piszemy w Javie, ale na wszelki wypadek...

Ale co do ma wspólnego z czystym kodem? Brzmi to bardziej jakby ktoś sam nie wiedział co chce osiągnąć.

3

@piotrpo: jak pisałem, obawiam się że to w dużym stopniu wina firm. Szukają ludzi którzy mają doświadczenie z 20 technologiami więc ludzie wciskają reactjx itp do tego Androida.
Oczywiście ktoś napisze ze trzeba iść do cywilizowanej firmy która szuka programistów a nie klepaczy Springa, Angulara etc, zgoda - tylko mówię to co widzę.

5

Szefostwo jest niekompetentne i koderzy potrafią wmówić zalety takich rozwiązać, o których przeczytali bo doświadczenia przecież z tym nie maja,. Doświadczenie chcą właśnie móc se wpisać dzięki danemu projektowi. Oczywiście tego doświadczenia nadal nie mają bo jak się pojawiły problemy z daną technologią to sp* z firmy, potem jak masz naprawić ten bajzel to nawet nie ma kogo spytać dlaczego takie rozwiązanie. Zostajesz z transakcjami rozproszonymi w MySQL obejmującymi kod w javie :(

3
Aventus napisał(a):

Biblioteke do IoC
(...)
Proste aplikacje serwerowe z pojedynczym endpointem ładują Springa z wszystkimi dobrodziejstwami

NIe znam ekosystemu Javy ale czytając posty na forum coraz częściej odnoszę wrażenie że problemem tak naprawdę jest ten cały Spring, który rzutuje negatywnie na pewne inne, całkowicie normalne aspekty. I winą tutaj po części jesteście Wy szanowni programiści Java, bo wykazujecie się trochę arogancją i nie bierzecie pod uwagę że framework którego Wy używacie nie jest jedyną miarą. Później pojawiają się geniusze którzy wszem i wobec głoszą że te całe IoC to w ogóle zło i tyle, i po co to w ogóle używać.W przypadku IoC ja uważam że nawet w prostszych aplikacjach IoC można stosować i nie ma w tym nic złego, tym bardziej że jest tyle lekkich bibliotek do tego.Oczywiście wszystko ma swoje granice i zależy od wymagań, więc zdaję sobie sprawę że są przypadki gdzie faktycznie podejmuje się próby przeinżynierowania prostych problemów. W 99% przypadków nie zaliczał bym do tego IoC- zakładając że używa się do tego coś normalnego.

Problemem jest chyba to, że ludziom wydaje się, że magia adnotacji to nic złego. Wtedy Spring przecieka do głębszych warstw niż kontrolery w postaci sławnego @Transactional, różnych Before, After, Pre, Pro, całego Spring Expression Language i AOP. Dokładamy do tego przemycanie np. SecurityContextu i karuzela rusza :) A wystarczyłoby przestać polegać na magii i pisać normalny kod.

4

Jakbym czytał o mojej poprzedniej firmie zatrudniającej "programistów z wyższej półki". Ostatni projekt to zwykły CRUD który musiał mieć CQRS, 2 oddzielne bazy na read i write synchronizowane eventami. Niekończące się code review co do literki w zmiennych. Dodanie prostego endpointa szło w dni/tydzień a projekt wyceniony oczywiście jak zwykły CRUD. Wieczne pożary z powodu błędów bo ogarnięcie wszystkich zbędnych klas przy presji czasu przekracza ludzkie możliwości a projekty były małe kilkumiesięczne więc ludzie wrzucani często nie pracowali nigdy z połową technologii. Podejrzewam, że takim firmom chodzi o przyciągnięcie nowych pracowników których nie chcą przyciągnąć zarobkami tylko perspektywą rozwoju w nowoczesnych buzzwordach, albo przyciągnięcie klientów chwaleniem się czego to nie robią ich pracownicy.

3

@SkrzydlatyWąż a ja właśnie o tym piszę- wspominasz jakieś adnotacje o których ja nawet nie mam pojęcia, i nigdy na myśl by mi nie przyszło że to może mieć coś wspólnego z IoC. Czyli potwierdza się to co pisałem wcześniej- jest grupa programistów którzy używali/używają Springa, są na tyle rozsądni że widzą w nim problemy, ale nie na tyle rozsądni żeby przestać utożsamiać Springa z definicją IoC. Skutkiem tego stosują "Spring" i "IoC" zamiennie.

9

Ja widzę dwa niezależne zjawiska:

  • resume driven development - uprawiane i przez programistów i przez firmy
    Firmy technologiczne też lubią mieć pokemony w portfolio.
    RDD nie jest do końca złe - gdzieś trzeba sie uczyć, a najlepiej na produkcji. Tak serio - jeśli projekt jest niekrytyczny, wszyscy jasno wiedzą (łącznie z klientem), że robimy jakiś ekspertyment technologiczny - to sprawa jest dla mnie ok. To, że w projektach hobby uprawiamy RDD to oczywistość. Rozwój polega na robieniu eksperymentów i częstych niepowodzeniach. Jakkolwiek - jeśli robimy po raz 20ty Springa w CRUDzie na dwie tabelki - to pewnie to już nie jest żaden rozwój.
  • cargo cult - wrzucamy framework, pattern, bazę danych - bo dziadowie też tak robili i im działało - to jest coś co mnie wnerwia naprawdę. Cargo cult jest o tyle trudny do zwalczenia, że większość tak używanych "wzorców" co prawda nie pomaga, ale i nie szkodzi (coś jak modlitwa). Niestety, wytłumaczenie, że coś jest bez sensu, skoro produkcja nadal działa, jest całkiem trudne. Większość cargo cultowanych rozwiązań miała kiedyś sens, w pewnym kontekście, w pewnych projektach. Często sens polegał na tym, że mainstream akurat nie znał wtedy lepszego rozwiązania.
    Ten sens dawno zginął, a deweloperzy nie pytają - tylko walą w te klawisze jak Rambo.

sometimes it takes years to realize how suckish some practices are (Venkat)

0

@Aventus: a jak działa [Transaction] w .net?

0

@Aleksander32: nie wiem, nigdy nie używałem. Tym bardziej w kontekście IoC.

3

@piotrpo weź pod uwagę że celem jest rozwiazanie problemu biznesowego, a nie pokazanie że umiesz naklepać od zera webserwer albo driver do bazy danych ;)
Nawet jak masz jeden endpoint, to może wolisz wrzucić sobie zależność do jakiejs libki i mieć to z głowy i zająć się faktycznym celem aplikacji? Zresztą w 9 na 10 przypadków aplikacja będzie rozwijać się dalej i jak na początku zrobiłeś na szybko jakiegoś hacka (żeby uciec przez overengineeringiem) to jutro okaże sie że musisz to przepisać od zera.

Moim zdaniem problem istnieje, ale trochę innej natury. Np. zaczynamy nowy projekt, jeszcze nie wiadomo dokładnie jakie są wymagania i ograniczenia, a ktoś w zespole już konfiguruje ci bazę danych, a inna osoba już zrobiła repo i wrzuciła w zależności springa i hibernate ;) A może ta aplikacja w ogóle nie będzie potrzebować trwałego zapisywania danych? ;)

0

@Aventus: generalnie znaczącą część frameworków ma jakieś potencjalnie niebezpieczne konstrukcje, przeciekające abstrakcje itp.
Nie sądzę żeby Spring jakoś był dużo gorszy od tego, moje jedyne podejrzenie jest takie że średnio programiści .net mogą być bardziej ogarnięci od tych Javovych i stosują lepsze mechanizmy.
Spring też ma duży ekosystem, ale można po prostu wykorzystać core bez pobierania wszystkich innych jarów.

3

Ja byłem w projekcie team leaderem gdzie chłopaki na siłę wcisnęli Webfluxa. Po roku pisania w tym tylko więcej czasu im zajmowało debugowanie, pisanie kodu. A dla biznesu to było wsio ryba czy Webflux czy normalnie blokujący kod. Przeprowadzałem analizę tego później i starty przez to że ktoś zaczął robić Webfluxa były ogromne. Gdy wytłumaczyłem biznesowi co inicjatorzy projektu nawymyślał i technologii to aż wstyd. Niestety programiści coś mają na punkcie słów typu Hazelcast, Webflux, RxJava a potem płacz bo za bardzo zagmatwany projekt. Albo teksty po jakimś czasie "mogliśmy jednak użyć Oracle" czy "po co nam ten Webflux"

7

Nawet na tym forum widzę, że przychodzą ludzie absolutnie zieloni i jednocześnie rzucają się od razu na frejmłorki, o których sama nie mam pojęcia (i niezbyt mam ochotę mieć pojęcie). Ktoś tu niedawno pisał nawet o: skryptach jQuery w sposób, który sugerował, iż uważa je za coś natywnego.
Ludzie nie uczą się języków tylko frejmłorków i bez nich pewnie często niewiele nawet potrafią.

3

wiekszosc projektow ktore pisze przez ostatnie ~2 lata maja wlasnie po 10-20 klas i w sumie rzadko zmieniaja sie w cos duzo wiekszego.
pierwsze co robie to dorzucam w pom.xml pare rzeczy typu vavr, guice, loggera, config parser, 5 libek do testow, i event/queue lib. po co wymyslac kola na nowo?
fetyszystow od clean code zalatwia sie wspolnym code guidlines zaimportowanym do ide...

4
piotrpo napisał(a):

Zastanawiam się, czy ma to jakiś ukryty sens, czy chodzi o takie sprawy jak:

  • Na blogu przeczytałem, że RxJava to super rzecz i chcę tego użyć.
  • Wszyscy teraz chcą programistów Spring, więc użyjmy tego frameworka, bo chcę go mieć w CV.

Ludzie jarają się technologiami, nie designem, więc tak to wygląda. Nieważne, czy coś ma sens, ważne aby było nowe i modne.

  • A co jak nasza aplikacja za 5 lat będzie większa i wtedy to się przyda?

Kiedyś brałem udział w czymś, co miało 11 warstw na backendzie (3 fizyczne), 4 na frontendzie (projekt trwał tak długo, że był tam Angular, Knockout i jQuery jednocześnie), a logikę biznesową generalnie i tak w triggerach.
Nic nie miało sensu, ale nazywali to "skalowalną architekturą".
To był publicznie dostępny system. Przez 5 lat na produkcji zarejestrowały się dwie osoby. Po prostu nie dało się tego używać tak bardzo, że ludzie woleli przyjść do oddziału firmy i na miejscu skorzystać z usług zamiast załatwić sprawy przez internet.

Do tego sprawa trochę poboczna, ale chyba wpisująca się w ten trend - fetysz clean code, polegający na niekończących się dyskusjach, jak nazwać zmienną, żeby zamiast 20 znaków miała 15 znaków i dalej mówiła co przechowuje. Czepianie się o if(obj==null) zamiast if(null==obj), bo w C++ można pomylić porównanie z przypisaniem, my co prawda piszemy w Javie, ale na wszelki wypadek...

To nie jest clean code.

Aleksander32 napisał(a):

@Aventus: a jak działa [Transaction] w .net?

Najlepiej jak to możliwe - nawet się nie kompiluje, bo go nie ma. :)
Możesz sobie oczywiście taki zaimplementować. Na jakim poziomie chcesz: filtra w WebAPI, pipeline w mediatorze albo nawet jako interceptor jednego z wielu frameworków IoC. Tylko, żeby zaimplementować samodzielnie trzeba wiedzieć co się robi i po co. Jeśli w Javie jest taki mechanizm wbudowany, a do tego 3/4 programistów nie doczyta dokumentacji i będzie traktować go jako magię, która "sama działa", to nieszczęście chyba gotowe.

0

Ja będe na siłę wciskał do mojego projektu biliboteki/rozwiązania których się używa przy androidowych projektach. Nie widzę nic w tym złego, nie potrzebuję daggera w moim projekcie ale wypada go znać(lub jakieś inne DI) jak człowiek idzie się rekrutować.

0

Over engineering to dość powszechny problem. Wczoraj miałem live coding podczas rozmowy rekrutacyjnej. Jedno proste zadanie, które może być obsłużone jedną klasą z miejsca ma klasę i jakiś serwis. Dla przykładu została stworzona klasa Request to wykonywania zapytań http po stronie klienta i logika do wykonywania retry przez oddzielny serwis. Problem jest taki, że nie widzę potrzeby tworzyć dodatkowo niepotrzebnej abstrakcji, w dodatku klasa Request była prawie pusta.

3
somekind napisał(a):

Kiedyś brałem udział w czymś, co miało 11 warstw na backendzie (3 fizyczne), 4 na frontendzie (projekt trwał tak długo, że był tam Angular, Knockout i jQuery jednocześnie)

A to już wiem, skąd ostatnio moda na gadanie o mikrofrontendach - widocznie wiele firm ma takie nagromadzenie legacy kodu w różnych frameworkach, że szuka sposobu na jego odizolowanie, żeby nie popaść już w totalne spaghetti.
(bo ponoć podejście mikrofrontendowe pozwala na pisanie aplikacji w kilku różnych frameworkach i przez kilka oddzielnych teamów i to ma być jego zaleta czy coś takiego).

Myślałem, że mikrofrontendy to po prostu odkrycie zasady enkapsulacji przez frontendowców, ale może chodzi bardziej o to, żeby zamieść pod dywan legacy kod.

Bo jak brzmi lepiej
projekt trwał tak długo, że był tam Angular, Knockout i jQuery jednocześnie)
czy:
projekt ma taką skalę, że używa aż 3 różnych frameworków, które nawzajem się komunikują przez mikrofrontendy! Amazing

O ile faktycznie są to niezależne moduły, a nie że przeplatają się nawzajem.

0

@LukeJL: w mikrofrontendach głównie chodzi o to aby każdy mikroserwis miał swój odpowiadający frontend, z tym że najczęściej chodzi o to że taki frontend to bardziej biblioteka komponentów UI I ich zachowań (np. komunikacja z mikroserwisem do którego ten frontend "należy") niż aplikacja UI sama w sobie. Aplikacja UI jest zazwyczaj jedna, i spina ona te wszystkie biblioteki komponentów (mikrofrontendy) w jedną całość. Chodzi po prostu o ideę że skoro mamy zakresy odpowiedzialności wydzielone do mikroserwisów, to na tej samej zasadzie wydzielamy odpowiedzialność aplikacji klienckiej, tak że nie mamy jednego wielkiego frontendu (kodu) który wie wszystko o wszystkim.

3

Bardzo ciekawe rzeczy tutaj piszecie, ale moje doświadczenia wskazywały na dużo prostszą przyczynę tego stanu rzeczy. Jeśli dajecie nowy projekt do zrobienia programiście Springa, to pewnie zrobi go w Springu, bo tak jest dla niego szybciej i łatwiej. A że większość programistów Java w korpo to programiści Springa, to jest to co jest...

2

Myślałem, że mikrofrontendy to po prostu odkrycie zasady enkapsulacji przez frontendowców, ale może chodzi bardziej o to, żeby zamieść pod dywan legacy kod.
Mikrofrontendów też nie lubię, ale mikroserwisy po stronie backendu też są używane by zamieść pod dywan legacy code :D

Dlaczego legacy kod?
Po prostu praca zbyt dużej ilości osób nad wspólnym kodem w repozytorium jest cięzka, i stąd się biorą tego typu twory. Wyobrażasz sobie żeby amazon.com był jednym wielkim monolitem? Kilkaset albo i więcej osob pracujących na jednym repo gitowym, restart aplikacji trwający godzine odbywający się co 4 godziny bo coś nowego trzeba wrzuć na produkcje? To że część osób używa mikroserwisów żeby poczuć się cool i jazzy to już nie wina mikroserwisów.

@Kalrais ale przeciez o tym pisałem. Kod pisze się żeby przynosił hajs, a PO nie obchodzi czy to Spring czy Ktor czy jakaś Akka HTTP.

2

Aplikacje mobilne składające się z 5 ekranów na krzyż mają w sobie:

Biblioteke do IoC - dagger / koin / hilt jak najbardziej w projekcie. Teraz hilt na topie, znam apkę 1mln + pobrań która ją używa na produkcji, bardzo mało problemów. Ja mówię nie - jest w alphie a ja mam dość purystyczne podejście do libek w projekcie.

ORM - to zależy od biznesu. Jeśli aplikacja wymaga filtrowania po dużej liczbie danych to room może się przydać, jeśli nie to pewnie shared preferences i lecimy.

Event Bus - od razu usuwam z projektu. Libka która ukrywa problemy związane za architekturą, bardzo ciężko się debuguje, bardzo ciężko zrozumieć flow, liczna problemów z tą libką jest większa niż kod bez niej.

Jakieś customowe biblioteki do MVVM - customowe libki do mvvm? Od razu do kosza. Tak samo jak event bus - zło. Prosty kod od googla i lecimy.

rxjava to zło - rxjava to zło jak doda się ezoteryczne operatory które zna 10% programistów. Ja w projektach używam rxa w najprostszy sposób: map/flatmap, single, subscribe, zip/combine latest to już max jest skomplikowania. Dlaczego? Prostsze utrzymanie projektu, łatwiej zrozumieć kod. Jeśli jest potrzeba napisania własnego operatora to pewnie da radę napisać go składając powyższe operatory. Rx dla mnie to tak naprawdę fork and join + mapowanie. Dodatkowy plus takiego rozwiazania to to że każda libka do async będzie to wspierać - podmiana np na korutyny to bajka to to tam też jest dodane w przystępny sposób.

"aplikacje mobilną z paroma guzikami na krzyż, gdzie zamiast zwyczajnie zareagować na kliknięcie jest rozgłaszany event o naciśnięciu guzika, jakis serwis go przechwytuje, pobiera dane, wysyła inny event, że dane pobrane, co znowu jest przechwytywane przez jakiś ekran i pokazane na ekranie. W efekcie czego po zajrzeniu w taki kod nie wiadomo kompletnie nic, stack trace z exceptionami pokazuje wszystko co możliwe, ale zero odwołań do własnego kodu." Wypisz wymaluj problemy z roku 2014 z eventbusem bez sticky events albo rxjava ze złym logowanie błędów albo kosmiczny redux. Byłem widziałem.

0

Troche offtopic - ale czy jak mamy courutines to ta RxJava jest potrzebna?

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