WeiXiao
2019-09-18 17:45

Software Architecture is Overrated, Clear and Simple Design is Underrated

https://news.ycombinator.com/item?id=21001676

Next 4-8 years, I started getting cute with it and applied all kinds of design patterns, Factory, Abstractions, DI, Facade, Singleton you name it. It looked cute and felt good when it all worked but it was a juggling act. There was usually like 2-3 files to touch just to do one thing. UserFactory, UserService, UserModel, User, you get the idea. It got to a point coding now felt like a burden and I started getting allergic reaction to any projects that had more than 50 files.

xD

tdudzik

Ja ostatnio mam te same odczucia. Dlatego choćby nabrałem alergii na DDD. :D Gdzieś nawet tu wspominałem, czasem wielki plik na 1,8k linii, ale z prostym i logicznym designem jest znacznie lepszy niż jakieś wyszukane rozwiązania, których logikę zna tylko sam autor. :)

Shalom

@tdudzik: tak ci sie tylko wydaje :D Teraz po prostu masz wielki plik na 1.8k linii kodu którego logikę znasz tylko ty. I pracuje ci się dobrze bo jest twój :P

tdudzik

@Shalom: pudło. :) akurat był to projekt do którego wskoczylem na tydzień i zdążyłem się wdrożyć i dodać jakiś niewielki feature. Zresztą nie tylko ja. Swoje zdanie zmieniłem wlasnie po tym doświadczeniu. Niby duży plik to antypatern, ale prosty i logiczny design sprawia że łatwo Ci sie w tym odnaleźć. Mówiąc logiczny mam na myśli ze za wszystkim stoi jakiś sens, ktory kazdy moze zrozumieć. Po drugiej stronie barykady masz np. DDD, gdzie najlepiej zatrudnić stado konsultantów którzy godzinami będą dyskutowac co jest zgodne z filozofią.

No i co do tego projektu, są plany ofc zeby to rozbić, po prostu nikt nie miał jeszcze czasu, a chcą zrobić to dobrze.

danek

@tdudzik: jeden duży plik jest moze spoko jak chcesz zmienić jedną pierdołe. Gorzej jak chcesz zmienić coś co rusza więcej niż jedno miejsce

Shalom

Jeden duży plik zwykle niestety oznacza słabą separacje odpowiedzialności, bo "wszystko jest pod ręką to się używa" i jest ok dopóki nie ugryzie cię coś jak Fragile Base Class Problem albo tight coupling, czyli chciałbyś coś zmienić, ale nie możesz, bo jest to tak mocno uwikłane z innymi rzeczami, że po prostu się nie da bo wszystko wybuchnie. Podział na osobne klasy / obiekty / moduły, stawianie interfejsów/kontraktów itd. pozwalają tego uniknąć bo masz tzw loose coupling, który dużo lepiej sie skaluje i jest odporny na zmiany.

jarekr000000

Już od dawna miałem dość rozdmuchania. Większość pro architektur w javie to tylko kult kargo, potem mamy połowe kodu w mapperach, a jak trzeba znaleźć gdzieś logike biznesową to się okazuje, ze nie bardzo nawet wiadomo gdzie jest (tzw. logika rozmyta). Java jest przy tym mało winna,- po prostu taka społecznośc - pamiętam jak prezentowałem dlaczego zrobie pewien projekt w Scali, bo bliblioteka do obsługi command line miała taką funkcjonalmnosć val result = "moj.cmd.exe -bla bla" !!
To samo w javie to ileś tam wywołań, handlerów itd. - najlepsze, że dało by się zrobić taką prostą bibliotekę (nakładkę) jak w Scali - ale przez 20 lat javy nikt nie wpadł ....

Drugie to fakt, że w pewnych jezykach da się napisać sedno logiki totalnie bez kodu infrastruktury - czysto i jasno - Haskell to najlepszy przykład, Scala też daje radę. Ale tu oprócz cukru składniowego potrzebny jest niezły system typów.

tdudzik

@danek @Shalom może źle się wyraziłem. Nie uważam że jeden plik jest dobry. Uważam, że logiczny monolit jest lepszy niż nielogiczny podział. Przez logiczny mam na myśli, że w danej 'architekturze' istenieje idealnie (nieosiągalne, traktowałbym to raczej jako 'granice') jeden sposób na dodanie danej funkcji. Jeżeli dasz jedno zadanie 10 osobom, i zrobią je dokładnie tak samo, to znaczy że najprawdopodobniej architektura jest logiczna i zrozumiała dla wszystkich. Jeżeli dostaniesz 10 różnych rozwiązań, a na końcu wszyscy pobiją się które jest prawidłowe, to znaczy że najprawdopodobniej jest coś nie tak. Przykład z plikiem podałem, bo często jak ktoś zobaczy taki plik to zacznie krzyczeć, że antypatern i wszystko źle, kiedy prawdziwy problem jest wtedy kiedy dla jednej spójnej zmiany musisz zmodyfikować 10 plików, o ile uda się Ci w ogóle zrozumieć przepływ danych, wtedy mamy raczej distributed coupling (edit: widzę, że @jarekr000000 mnie trochę uprzedził z podobnym określeniem :D ).

WeiXiao

Jeżeli dasz jedno zadanie 10 osobom, i zrobią je dokładnie tak samo, to znaczy że najprawdopodobniej architektura jest logiczna i zrozumiała dla wszystkich. Jeżeli dostaniesz 10 różnych rozwiązań, a na końcu wszyscy pobiją się które jest prawidłowe, to znaczy że najprawdopodobniej jest coś nie tak wow, dałbym wincyj plusów gdybym mógł. Czyli Idealna architektura to taka w której team się swobodnie porusza?

tdudzik

Po pierwsze zależy co rozumieć przez team. Po 10 latach w projekcie jest szansa, że każdy będzie się w nim swobodnie poruszał, bez względu na to jak skopana jest architektura. Zatem założyłbym, że team to obecny zespół + każda nowa osoba po relatywnie szybkim wdrożeniu. Po 2. swobodnie porusza to też dość płynne pojęcie i raczej niewystarczające. Poruszanie się i zrozumienie kodu to jedno, a minimalizowanie decyzji które trzeba podjąć przy dodawaniu funkcji to drugie.

Szczerze mówiąc nie potrafie dać lepszego przykładu do tego czym dla mnie jest dobra architektura niż ten który zacytowałeś. :) Wydaje mi się, że do takiej architektura można dojść stosując właśnie podejście opisane w artykule zalinkowanym w poście. Im więcej osób zobaczy dany pomysł i podzieli się informacją zwrotną, tym większa szansa, że końcowy rezultat będzie zrozumiały dla wszystkich. Ważne jest też, żeby walidować pomysł jak najwcześniej (white boarding -> design doc -> code review). Łatwiej zmodyfikować pomysł na etapie pisania po tablicy, niż po tym jak jedna osoba poświęci 2 tygodnie na pisanie i dopieszczanie kodu realizującego rozwiązanie którego nikt nie rozumie. Nie wiem ile jest zespołów, które odważą się wyrzucić to wszystko do kosza i zacząć od nowa, ale podejrzewam, że niewiele. Wtedy już tylko wystarczy dać approve (często bez dogłębnego review, bo 5-20k linii zmian, na pewno jest dobrze) i jesteśmy na prostej drodze do projektu którego nikt nie rozumie i nikt nie chce w nim pracować. :)

viader

@tdudzik czyli mam używać Painta i nie Photoshopa, bo są ludzie co w Paincie lepiej rysują niż ludzie, którzy w Photoshopie nie umieja rysować?

tdudzik

@viader: nie wiem o co Ci chodzi, ale nie wydaje się żeby miało to jakikolwiek związek z tym co napisałem.

viader

No piszesz argument, że lepszy dobry monolit, niż słaba architektura.

tdudzik

No tak. Zarówno jeżeli chodzi o podział na klasy, funkcje, pliki, ale też serwisy. Analogicznie uważam, że lepiej mieć jeden serwis który robi trochę za dużo, niż 10 źle podzielonych mikroserwisów, gdzie dany bounded context czy invariants (jak zwał, tak zwał) rozproszony jest na kilka jednostek (mikroserwisów tym przypadku), co może spowodawać że wykonanie jednej prostej operacji wymaga calli do kilku serwisów, a to z kolei wymaga obsługi błędów, zapewnienia spójności, monitoringu i dodaje innych problemów których nie ma się stawiając na monolit.

viader

Ja uważam, że modularyzacja na poziomie kodu przynosi konkretne korzyści. W przypadku mojej działki czyli Androida: szybsze budowanie aplikacji, lepszy podział odpowiedzialności, lepsza przenośność i reużywalność kodu.

somekind

Tytuł pierwszego tekstu to jakaś bzdura. Architektura właśnie polega na tworzeniu rzeczy prostych i czytelnych. To, że ktoś mając zamówienie na altankę tworzy gotycką katedrę, to wynika z jego upośledzenia w tym względzie.