Przykłady przeinżynierowanego kodu

0

Jakie przykłady przeinżynierowanego kodu znacie z komercyjnych systemów? Dlaczego są przeinżynierowane? Dlaczego ktoś napisał taki kod a nie napisał czegoś prostszego? W nawiązaniu do: Dlaczego programy "enterprise" muszą być tak kosmicznie przekombinowane?

5

Sam doświadczyłem:

  • Zamiast użyć dostępnego na rynku mapera (dto <-> encja), architekt wyrzeźbił własny, closed source oczywiście i zmusza resztę firmy żeby korzystała z tego przybytku.
  • Własny silnik do workflowów, oparty na transformatach XSLT wraz z graficznym toolem do edycji.

Oba przypadki Not Invented Here Syndrome.

7

Używanie maperów w ogóle.

W aplikacji jest iles tam pseudowarstw przepisujących obiekty 1-1 - jest Entity, DTO, ETO, CTO, UseCaseObject i nie wiadomo nawet co. Wszystkie te klasy są bliźniacze i kopiuje się je 1 do 1 przez jakiegoś mapera.
Co za g**no.

Uzasadnienia na taką kupę są, bo jak się używa JPA to trzeba uważać co się robi z obiektami Entity, a prostsze rozwiązanie to po prostu nie używać JPA (ew. używać nieco bezpieczniej niż standardowo - da się).

Co więcej DTO mają jakiś sens jak różnią się istotnie od encji, co oczywiście w typowym korpo projekcie nie występuje, architekci potrafią nawet pisać toole do eclipsa, które generują cały ten powtarzalny kod.

Za względu na zaszłości historyczne i popularność JPA, które nie tak łatwo wyrzucić, jeden poziom zrypania czyli DTO i Entity jestem w stanie zrozumieć. Nawet jak są mapery. Niestety najczęściej jest tych "pseudo warstw" (pseudo bo nic nie wnoszą) zwykle dużo więcej.

Rekord to chyba 18 - nie żartuje. Jak się dodawało pole do formularza do w 18tu miejscach trzeba było to pole dodać... (i oczywiście czasem dokonfigurować mappery). Aplikacja była rozbita na wiele warstw fizycznie - server backend-backend, server pośredni, server frontend (chociaż każda z tych warstw to po prosty kolejny jvm backend - http).
Każda z tych aplikacji miała wiele logicznych warstw i własną bazę danych. Przy czym uważam, że podział na osobne warstwy fizyczne był w miarę sensowny (specyfika firmy i systemów -security szczególnie), ale to żeby w każdej z tych fizycznych aplikacji bawić się w x warstw to już był nonsens.

3

@nobody01: Apache camel i ogólnie tworzenie flow programu za pomocą fluent api, gdzie nie polegamy na programowaniu funkcyjnym (czyli input/output lub reactive), tylko na trzymaniu stanu w jakimś gównianym kontekście (widziałem np. taki in-house framework do testowania w pythonie, który wyglądał bliźniaczo podobnie, obserwacje i problemy były takie same). Na początku idea jest fajna, bo wymuszasz pewien ustalony styl programowania dla częstych idiomów. Póżniej wraz z czasem dodajesz kolejne ficzery i zauważasz, że zalety są praktycznie minimalne natomiast sam pomysł jest nierealny, bo nie przewidzisz wszystkiego i nagle zaczynasz robić cuda na kiju, żeby dana operacja była wykonalna, gdzie w normalnym programowaniu nie musisz nawet myśleć o takim problemie

4

Jeden wielki "serwis", a konkretnie klasa z suffixem Service która ma wiele zagnieżdżonych serwisów. Ten root serwisu miał nazwę całego produktu (jako przykład użyje Fabrikam) i był wstrzykiwany wszędzie gdzie jakikolwiek "podserwis" był potrzebny. Coś takiego:

interface IFabrikamService
{
  ISomeService Some;
  ISomeOtherService SomeOther;
}

interface ISomeService
{
  IEvenOtherService EvenOther;
}

// ...
// Używanie tego wyglądało tak
var result = _fabrikam.Some.SomeOther.Finally.DoSomething();

Oraz jeszcze inny przykład dosyć nagminnie spotykany w .Net czyli nadmierne abstrahowanie wszystkiego do interfejsów, tam gdzie mamy tylko jedną implementację i nawet nie ma potrzeby mocowania tego do testów. Innymi słowy abstrakcja dla samego abstrahowania. W zasadzie to miałem w planach kiedyś założyć na ten temat nowy wątek bo całkiem niedawno miałem burzliwą dyskusje w zespole dla czego tego nie robimy, bo jeden programista definitywnie twierdził że brak takiego abstrahowania łamie SOLID, I to "antypattern" bo mamy tight coupling. I nie przegadasz takiemu argumentami, bo jako odpowiedź słyszysz tylko takie puste slogany bez żadnej refleksji... Niektórych chyba traktują własne przyzwyczajenie jako prawdę objawioną, a jeśli widzą w konstruktorze wstrzyknięte coś co nie jest interfejsem to od razu traktują to jako antypattern.

2

Dla mnie typowy przykład przekombinowania, to generalnie aplikacje w Androidzie. Jak wygląda typowa aplikacja, każdy wie - parę ekranów na krzyż, pobrać dane z backendu, wyświetlić, pozwolić zmienić, odesłać na serwer, aplikację pomalować na zielono. W to wszystko były wrzucane kontenery IoC (chociaż w Androidzie nie działają), rozbicie tego na komponenty samego frameworku (wizualne, nie wizualne, usługi itd. Event bus'y, JavaRx. Fakt, że jak się już to opanowało, to już nie bolało tak bardzo. Do tego jakieś optymalizacje typu "nie używaj enumów, bo one alokują pamięć", wieczne dyskusje o wyższości MVVM nad MVC (lub odwrotnie). Efekt dość łatwo dostrzec - kiedyś aplikacja zajmowała powiedzmy kilka MB i były to głównie zasoby, aktualnie 100MB i większość zajmują biblioteki. Parę lat temu "problemem" było to, że aplikacja dla Android nie mogła mieć więcej niz 65k metod, bo kompilator je sobie numerował i ktoś użył jedynie 16b https://schibsted.com/blog/dealing-65k-methods-limit-android/ I generalnie naprawdę mówimy o aplikacjach w których nikomu nic by się nie stało, gdyby ktoś cały ten kod wrzucił na widok.

Dla kontrastu - byłem w projekcie, który był prowadzony przez pewnego "doświadczonego" programistę, w dodatku do tej pory nie mam zielonego pojęcia, po co ktoś wydał na niego kasę, bo projekt nie robił absolutnie nic użytecznego - brał dane z serwisu X, magazynował je sobie i pozwalał serwisowi Y je pobrać w niezmienionej formie (o ile wszystko poszło ok). Warstwy, mikroserwisy, mappery, dtosy, kolejki, blobsotrage, redis, cała architektura chmurowa z DR, regionem zapasowym, blue-green deployment, własna usługa do autoryzacji i uwierzytelniania itd. Oczywiście wszystko robione na kolanie i "na termin". Żeby było śmieszniej, serwis Y wspomniany wyżej, robiony przez inny zespół pobierał sobie te dane i trzymał samodzielnie, bo nie dowierzał (i słusznie), że to co robimy będzie działać. Z drugiej strony, jak padło hasło "Sonarqube" od korpo architektów, to devlead najpierw popuścił, później znalazł sposób i w metodach raportowanych jako "cognitive complexity 18341 allowed 5" (nie żartuję z liczbami) zaczął dopisywać //NOSONAR jak podzielimy tę metodę, to będzie nieczytelna. Jak widać overengineering nie wyklucza burdelu.

Co do wyciągania niepotrzebnych interface'ów - zdarza mi się, głównie z powodu, że często najpierw je definiuję, dopiero później implementuję, więc faktycznie dość często zdarza się interface z pojedynczą implementacją.

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