Modularyzacja w dobie mikroserwisów

0

Cześć,

chciałbym się podpytać, jak u was w projektach wygląda sprawa modularyzacji. Ja za każdym razem mam tak, że otwieram kod mikroserwisu, widzę pakiet typu "controllers" posiadający 40 plików, katalog "model" posiadający ponad 200 plików, wszystko publiczne, wszystko gada ze wszystkim. Naszło mnie takie przemyślenie, że odkąd zaczęło być jakieś parcie na mikroserwisy to ludzie przestali się przejmować jego podziałem na moduły, bo przecież mikroserwis sam w sobie ma reprezentować jeden bounded context. Są event stormingi, które mają odkrywać bounded contexty w aplikacji, ale w praktyce nie widziałem, żeby ktoś to stosował. Bo jakby to miało działać? Pewnego dnia miałby przyjść do nas architekt i powiedzieć: "no słuchajcie, za duży ten serwis, to sobie zrobimy event storming i go podzielimy"? W projektach, w których pracowałem to zazwyczaj serwisy osiągały takie rozmiary, że nie dało się już tego podzielić i sensownie z tym pracować, więc przepisywano na kilka mniejszych serwisów. Stąd też moje pytanie czy to ja mam takiego pecha i trafiam do takich projektów, gdzie nigdy nie ma sensownego podziału czy to po prostu standard w naszej branży i nikt się tym nie przejmuje?

3

To nie jest kwestia mikroserwisów, bo gdyby nie były one popularne to pewnie Twój wątek dotyczyłby kwestii z OOP :-)

To raczej kompetencje ludzi, a przede wszystkim skutek złego zarządzania.

Skoro jest źle w projekcie, to projekt będzie się sypał. Na Twoim miejscu nie próbowałbym tego stanu zmieniać, lecz wyczekiwałbym pożarów, gdzie można zabłysnąć.

Patrz na to jak na biznes. Firmę jak na klienta. Im więcej widzisz problemów tym lepsze masz pole do sprzedaży.

0

@con:

@znowutosamo2:

Każda religia masowa tak robi z adeptów
Spełniamy wymogi kultu (jesteśmy mikroserwisowi), jesteśmy ok, ci dobrzy, to nieważne stają się pytania szczegółowe, "moralne", naszego wewnętrznego poziomu.

ps. a że us - co podniosła niedawna publikacja o odwrocie - potrzebuje kodu, dużo kodu "służebnego", infrastrukturalnego ... gdy wszyscy to wiedzą, to panuje powszechne wybaczenie (dla "swoich"), że "tak musi być"

1

To niestety chyba standard. Moje doświadczenia są takie, że mikroserwisy są implementowane na przekór logice i przez ludzi, którzy się tym nie powinni zajmować.
W projekcie gdzie teraz pracuję mamy system napisany w mikroserwisach. Są one powydzielane w tak paskudny sposób, że nie widać tam ani trochę logiki. Narzut skomplikowania związany z podziałem straszliwie przedłuża pracę. A co ciekawe, bywa że mamy trudny orzech do zgryzienia jeśli trzeba dodać coś nowego - bo nie wiadomo w którym miejscu to zaimplementować. Oprócz tego serwisy duplikują duże ilości danych, są one zbyt mocno ze sobą powiązane.
Zaproponowałem zmianę tego podziału, projekt toczy się na razie bokiem i może uda się w tym roku jeszcze wystartować. Na razie omawiamy konteksty i zakresy odpowiedzialności.

Oczywiście, w zespole nie ma już nikogo kto pracował z tymi serwisami od początku. Patrząc na stan zastany, jestem przekonany że jedynym powodem napisania systemu w taki sposób była chęć napisania mikroserwisów bez przemyślenia czy naprawdę jest potrzebne lub przynajmniej w jaki sposób je zaprojektować.
I uciec do innej firmy, tak aby nie musieć utrzymywać potworka którego się stworzyło.

znowutosamo2 napisał(a):

Skoro jest źle w projekcie, to projekt będzie się sypał. Na Twoim miejscu nie próbowałbym tego stanu zmieniać, lecz wyczekiwałbym pożarów, gdzie można zabłysnąć.

Patrz na to jak na biznes. Firmę jak na klienta. Im więcej widzisz problemów tym lepsze masz pole do sprzedaży.

Tak to niestety wygląda. Żaden manager nie pozwoli na znaczną inwestycję mającą na celu naprawienie problemów architektury dopóki wszystko działa. Można robić mniejsze refaktory ale one nie rozwiążą problemu u podstaw. Konkretne posunięcia stają się możliwe dopiero wtedy kiedy klienci zgłaszają coraz to więcej problemów, których nie da się rozwiązać inaczej niż przepisując system.

1

Mało ludzi potrafi pisać modularny kod, dodatkowo standardowo uczy się tego głupiego podejścia package by layer. Mikroserwisy trochę zamiatają problem pod stołem, bo im mniejszy kod tym łatwiejsze jest ogarnięcie się w takim burdelu, przy dużym monolicie ktoś w koncu kiedyś powie "dość"

4

@con:

Stąd też moje pytanie czy to ja mam takiego pecha i trafiam do takich projektów, gdzie nigdy nie ma sensownego podziału czy to po prostu standard w naszej branży i nikt się tym nie przejmuje?

Moje przemyślenia na ten temat są dwa:

  1. Cargo cult i RDD (resume driven development)
  2. Słabe wykształcenie programistów w zakresie architektury systemów

Powyższe tyczy się nie tylko architektur rozproszonych ale też zwykłych aplikacji monolitycznych.

4

Ludzie nigdy się nie przejmowali podziałem na moduły - jest to dosyć trudne (moim zdaniem opłacalne), ale dużo prościej się robi spaghetti.

Oczywiście możemy potem robić kawałki apek które się komunikują po http i nazywać je "mikrkserwisami", ale jeśli ktoś nie umie dobrze zrobić modułów w jednym projekcie, to tym bardziej nie podzieli jednej apki na mikroserwisy. Jeśli ktoś, kto nigdy nie zrobił dobrze modularyzacji w jednym projekcie, weźmie się za pisanie mikroserwisów to wyjdzie mu jedna monolityczna spaghetti aplikacja, tylko że dodatkowo zamiast interfejsu zwykłego będzie interfejs http. Zysk z tego żaden, właściwie to jest gorzej.

1

Branżowy standard. Czasami jak masz szczęście to trafią ci się ludzie którym jakoś zależy, ale to raczej mniejszość.
Niestety narzędzia nie pomagają. Języki słabo wspierają modularyzację. Np. javowy package scope i moduły z jdk9 to jakiś żart. Kotlin, który wszystko robi lepiej, zrobił modularyzację znośnie, ale nadal kiepsko.

1
Riddle napisał(a):

Ludzie nigdy się nie przejmowali podziałem na moduły

Odważne stwierdzenie. Przecież jest multum książek, prezentacji czy całych społeczności, które skupiają się w dużej mierze między innymi na architekturze, a co z tym idzie - podziałem systemu na moduły. Nawet na tym forum widać niemałe zainteresowanie tym tematem.

Riddle napisał(a):

Jeśli ktoś, kto nigdy nie zrobił dobrze modularyzacji w jednym projekcie, weźmie się za pisanie mikroserwisów to wyjdzie mu jedna monolityczna spaghetti aplikacja, tylko że dodatkowo zamiast interfejsu zwykłego będzie interfejs http.

Czym się różni podział aplikacji na moduły od podziału jej na mikroserwisy? W zasadzie tylko sposobem komunikacji. Jak sposób komunikacji wpływa na to, czy ktoś umie, czy nie umie, dobrze podzielić aplikacji?

Riddle napisał(a):

Zysk z tego żaden, właściwie to jest gorzej.

Nie trzeba mieć mikroserwisów, żeby czerpać korzyści z architektury rozproszonej. Banalny przykład - wydzielam sobie ciężkie zadanie, np. import, do osobnego serwisu (nie mikro). "Główny" serwis informuje ten wydzielony, że w jakiejś lokalizacji jest nowy plik, który ma zostać zaimportowany. Wydzielony serwis robi swoje, a aplikacja działa jak wcześniej - nie blokując wątku na przetwarzanie gigabajtowego pliku csv.

1
con napisał(a):

Cześć,

chciałbym się podpytać, jak u was w projektach wygląda sprawa modularyzacji. Ja za każdym razem mam tak, że otwieram kod mikroserwisu, widzę pakiet typu "controllers" posiadający 40 plików, katalog "model" posiadający ponad 200 plików,

Na tym etapie należałoby porzucić przedrostek mikro- do tego czegoś i zamienić na makro- xD

wszystko publiczne, wszystko gada ze wszystkim.

Ale w ramach jednego serwisu? To na tym chyba miało polegać, żeby komunikacja między różnymi serwisami była ładna, ale w środku konkretnego serwisu może być burdel, bo się najwyżej przepisze cały serwis.

0

Sporo wynika z złego podejścia mniej doświadczonych w programowaniu. Zbyt dużą wagę przykłada się do narzędzi i technologii (jak właśnie mikroserwisy, docker, kibernetes, terraform), a zbyt małą do metodyk które istotnie zwiększają jakość: loose coupling, odpowiednie abstrakcje i enkaosulacja enkapsulacja (i mówiąc "enkapsulacja" nie mam na myśli setterow i getterow, tylko odpowiednie schowanie implementacji)

1

Problem ludzi z świata IT nie polega na samych zasadach, czy praktykach the best of the best. Problemem jest fakt, że IT przysysa się do jakiegoś obszaru, aby go wspomóc, ale Ci sami ludzie od IT nie ogarniają tak dobrze domeny i aby coś usunąć, nie są w stanie przeskanować projektu, a następnie wyjść z inicjatywą, aby usunąć coś z systemu / zredukować złożoność, zaproponować inny korzystniejszy flow, bo wiedza na temat projektu albo nie leży po ich stronie, albo również nie mają wystarczającej decyzyjności, by móc coś tutaj zmienić.

3
Riddle napisał(a):

Sporo wynika z złego podejścia mniej doświadczonych w programowaniu.

Bo wbrew temu, co mówią bootcampy, nie każdy może i powinien być programistą.

Jednak rynek przez lata przyjmował osoby nieogarnięte, bo było ssanie na programistów. Lepszy dla biznesu programista, który zrobi burdel, ale dostarczy wartość biznesową niż żeby w ogóle nie mieć programisty i nie móc dostarczyć wartości biznesowej. Dlatego spaghetti kod jest dobry dla biznesu, bo alternatywą nie jest ładny kod, tylko brak kodu w ogóle (większość programistów nie umie programować, więc jak znaleźć tych, co umieją).

Tylko, że przez lata mało kto chciał być programistą - teraz wreszcie coś się zaczyna dziać i podaż programistów się zwiększa i może łatwiej będzie odfiltrować tych, co umieją coś, bo wymagania bardzo wzrosły.

2

to nie chodzi o programistów doświadczony albo nawet nie, tylko menagoidy próbują udawać ze są techniczni i dlatego takie hasełka wrzucają programistom

0

Dziękuję za ogrom odpowiedzi, nie spodziewałem się takiej aktywności.

znowutosamo2 napisał(a):

To nie jest kwestia mikroserwisów, bo gdyby nie były one popularne to pewnie Twój wątek dotyczyłby kwestii z OOP :-)

Być może tak. Gdy jeszcze mikroserwisy nie były tak popularne to pracowałem w projektach, które były jako-tako modularne. Ok, nie były idealnie podzielone na moduły, ale zawsze coś. Ktoś miał jakąś koncepcję, ktoś próbował cokolwiek zrobić. Teraz gdy rozpoczynam rozmowę o tym, czy nie warto podzielić naszego serwisu na mniejsze moduły to słyszę coś w stylu: "ale po co, przecież to już jest mikroserwis". No ok, jest, tylko co z tego. Jest jakaś zasada, że skoro mamy architekturę mikroserwisową w firmie to już nie można go podzielić na moduły? Ja wychodzę z takiego założenia, że być może mikroserwis urósł na tyle, że być może trzeba wydzielić z niego dodatkowy mikroserwis. Tylko skąd mam wiedzieć, czy mogę to zrobić, skoro mikroserwis nie jest podzielony i jest jeden wielki moduł?

var napisał(a):

A co ciekawe, bywa że mamy trudny orzech do zgryzienia jeśli trzeba dodać coś nowego - bo nie wiadomo w którym miejscu to zaimplementować. Oprócz tego serwisy duplikują duże ilości danych, są one zbyt mocno ze sobą powiązane.

Znam ten ból, mamy dokładnie to samo w firmie. I najgorsze jest to, że odpowiedzialność jest rozmyta i zgodnie z zasadą "mniej kodu do utrzymania to mniej problemów", żaden z zespołów nie chce tego wziąć i kończy się na tym, że komuś po prostu na chama wrzucamy kod.

Riddle napisał(a):

Jeśli ktoś, kto nigdy nie zrobił dobrze modularyzacji w jednym projekcie, weźmie się za pisanie mikroserwisów to wyjdzie mu jedna monolityczna spaghetti aplikacja, tylko że dodatkowo zamiast interfejsu zwykłego będzie interfejs http. Zysk z tego żaden, właściwie to jest gorzej.

To jest bardzo duży problem, bo jak znaleźć takich ludzi, którzy potrafią dobrze zrobić taką modularyzację w obrębie serwisu? Jak tu ktoś już słusznie zauważył, to nie daje żadnej wartości biznesowej, więc raczej w godzinach pracy się tego nie nauczymy. Obejrzenie kilku konferencji/przerobienie tutoriali też moim zdaniem nic nie da, dopóki nie będziemy pracować na większym projekcie dla prawdziwego klienta.

Grzyboo napisał(a):

Niestety narzędzia nie pomagają. Języki słabo wspierają modularyzację. Np. javowy package scope i moduły z jdk9 to jakiś żart. Kotlin, który wszystko robi lepiej, zrobił modularyzację znośnie, ale nadal kiepsko.

Mi osobiście podoba się package scope z Javy i brakuje mi tego w Kotlinie. Internale w kotlinie wręcz zmuszają do tworzenia modułów (co jest super), ale brakuje mi jednak tego package scope w Kotlinie. Znasz może języki, które lepiej to wspierają? Ja niestety mam doświadczenie tylko z językami na JVM, więc mam bardzo słabe porównanie.

iksde napisał(a):
Riddle napisał(a):

Ludzie nigdy się nie przejmowali podziałem na moduły

Odważne stwierdzenie. Przecież jest multum książek, prezentacji czy całych społeczności, które skupiają się w dużej mierze między innymi na architekturze, a co z tym idzie - podziałem systemu na moduły. Nawet na tym forum widać niemałe zainteresowanie tym tematem.

Zainteresowanie jest, ale chyba tylko teoretyczne. Jest multum konferencji o tym, sale są przepełnione, wątki na forum aktywne. Mnie tylko boli to, że potem w praktyce i tak mało kto (u mnie nikt) tego nie stosuje i jak przychodzi co do czego, to nie ma żadnego podziału.

1

Wady Controller -> Service -> Repo już kilka osób opisało, i trafnie nazwali to Spaghetti. Jedną z zalet jest to, że patrząc na nowy projekt tak napisany, mniej więcej wiesz gdzie spojrzeć, zacząć itd.

Jeżeli chodzi o modularyzację z perspektywy nietechnicznej, to ją staram się wciągnąć w to ludzi z biznesu. Jeżeli akurat jestem w projekcie który jest DDD, to jest to łatwiejsze. Nawet patrząc na Confluence jak biznes strukturyzuje swoją dokumentację, strony, hierarchię itd. można wiele zrozumieć.

Jeżeli chodzi o stronę techniczną, to dla mnie jednym z najważniejszych rzeczy jest enkapsulacja. Kiedy proszę IDE o metody które mogę wywołać, chcę ich dostać jak najmniej, i nawet IDE szybciej chodzi :) . Konkretny moduł powinięć mieć jeden 'abstract' punkt wejścia i wyjścia, wszystko inne jest wewnętrzne i prywatne. Testy przechodzą przez punkty wejścia i wyjścia z test containers, nie chcę żadnych 'mockitow' wewnątrz serwisu, bo to się może zmienić i zazwyczaj się zmienia kiedy zdam sobie sprawę, że implementacja może być lepsza np. pół roku później.

0

Pomijając dyskusję czy 40 plików z logiką to "mikro", burdel jest takim smutnym branżowym standardem. Podział na moduły nie jest trudny jeżeli zaczyna się od poznania problemu, zaprojektowania rozwiązania i dopiero się to rozwiązanie implementuje. Tylko w rzeczywistości ten naturalny wydawałoby się porządek rzadko kiedy jest stosowany. Implementacja zaczyna się od razu, projektowanie w najlepszym razie jest robione w trakcie implementacji, a jak już jest zrobione, to rozpoznawana jest domena. Wtedy, już w warunkach zbliżających się terminów dostosowuje się implementację, żeby robiła coś innego, niż wydawało się że ma robić i powstaje burdel.
Mikroserwisy niby miały temu w jakimś zakresie przeciwdziałać, ale najczęściej tego nie robią, bo skoro nie myśli się co ma robić kawałek systemu, to naiwnością jest oczekiwać, że ktoś pomyśli co ma robić system jako całość.

4

Jeszcze dziesięć lat temu, gdyby ktoś sobie stwierdził "aa, mam ochotę napisać sobie nową aplikację, i niech główna aplikacja strzela do niej po HTTP" to dostałby klawiaturą przez łeb, bo wtedy wszyscy wiedzieli żeby szanować KISS.

Teraz, jak słowo "mikroserwis" stało się popularne; to nawet najbardziej hardcore'owe i szalone pomysły żeby stworzyć nową apkę po nic, z jakiegoś powodu są "okej", pod warunkiem że nazwie się repozytorium "mikroserwis" - nawet jeśli powstały twór w ten sposób nawet nie stał obok MS.

Według mojej skromnej analizy, powody czemu ludzie tworzą mikroserwisy to:

  • Wkurza ich słaba jakość kodu w projekcie który piszą
  • Mają ochotę sobie stworzyć nową aplikację, bo fajnie się robi greenfield project
  • Mają ochotę popróbować nowe technologie
  • Słyszeli że Microserwisy to jest "new kid on the block" i chcą spróbować w swoich sił
  • To się wydaje ciekawsze niż klepanie CRUD'ów w swoich projektach

Wszystko to argumenty niemerytoryczne, ale kierując się takimi powodami devowie tworzą mikroserwisy tam gdzie nie mają miejscu posiłkując się argumentami że: skalowalność, bo amazon, bo netflix, bo szybkoć, bo lepiej, bo modularyzacja; tylko że nie biorą pod uwagę tego że to że ich główny projekt jest takiej niskiej jakości jest właśnie przez nieumiejętność modularyzacji, i bez takiej stworzenie dobrego mikroserwisu jest niemożliwe- powstanie również śmietnik, który teraz będzie miał dodatkowy narzuć complexity przez dodatkowy deploy i dodatkowy niepotrzebny interfejs HTTP między nimi. Co więcej, będą próbować bronić pomysłu argumentami: "że skalowalność", "że niezależność", "że loose-coupling"; ale to jasno widać że jest kłamstwo, bo jak zaproponujemy wtedy "ej, a może dodalibyśmy wzorzec X" albo "może wydzielilibyśmy moduł Y"; to stwierdzimy, aaaaaa po co, trzeba dowozić feature'y - i wtedy argumenty o skalowalnośc i loose coupling już ich nie obchodzą.

Praktycznie wszystkie miejsca gdzie widziałem mikroserwisy to miejsca gdzie one nie były potrzebne.

Ludzie będą się bronić rękami i nogami krzycząc "bo skalowalność", "bo design", "bo architektura"; podczas gdy ich prawdziwy powód to chęć napisania czegokolwiek poza ich monolitem (i mikroserwisy to jedyna "nowa" rzecz na jaką management się zgadza).

0
Riddle napisał(a):

Jeszcze dziesięć lat temu, gdyby ktoś sobie stwierdził "aa, mam ochotę napisać sobie nową aplikację, i niech główna aplikacja strzela do niej po HTTP" to dostałby klawiaturą przez łeb, bo wtedy wszyscy wiedzieli żeby szanować KISS.

Tak dla jasności to było w czasach przed czy po Unixowych? Ew. przed czy po systemd jeśli poruszamy się bliżej Linuksopodobnych.

1

Hype Driven Development jest niewątpliwie silniejszy niż lat temu 10-15-20
Popularne serwisy multimedialne itd... globalna wioska posunięta do którejś potęgi, a na wsi nie można być innym.

https://pl.wikipedia.org/wiki/Globalna_wioska (jestem zaskoczony, że 1962 rok, strzelał bym dekadę pózniej)

3

Dzisiaj jak nie ma 'BlockChain' i 'Microservices' to znaczy, że firma jest zacofana technologicznie.

W jednej z firm dla których pracowałem, właściciel mówił na zewnętrznych prezentacjach itd., że 'jesteśmy pierwszym produktem tego typu działającym na BlockChain' a tam większość nawet nie wiedziała co to jest BlockChain.

3
Riddle napisał(a):

Jeszcze dziesięć lat temu, gdyby ktoś sobie stwierdził "aa, mam ochotę napisać sobie nową aplikację, i niech główna aplikacja strzela do niej po HTTP" to dostałby klawiaturą przez łeb, bo wtedy wszyscy wiedzieli żeby szanować KISS.

Trochę masz rację, ale nie do końca. Narzędzia jakie wspierają rozwój systemu opartego o mikroserwisy "trochę" się zmieniły. Główny problem w tym, że architektura mikro usług nie rozwiązuje sama z siebie żadnego problemu, jest jedynie narzędziem, które prawidłowo użyte, może takie problemy pomóc rozwiązać. Z tego co ja widziałem, to podstawowe problemu, to:

  • Wdrażanie na rympał bez przeczytania czym ta architektura jest i w efekcie wdrożenie czegoś, co może i czymś jest, ale na pewno nie mikroserwisami
  • Wejście w technologię bez pojęcia jakie są związane z nią koszty.
  • Wdrażanie bez odpowiednich umiejętności i narzędzi
  • Radosne przekonanie, że skoro nie poradziliśmy sobie ze splątaniem na poziomie monolitu, to jak rozrzucimy przypadkowe odpowiedzialności na przypadkowe usługi zrobi się lepiej.
  • Pominięcie faktu, że nawet po zredukowaniu splątań statycznych (na poziomie kodu), nasilają się problemy ze splątaniami dynamicznymi (np. eventual consistency).

Dla mnie zalety to:

  • Modularyzacja kodu o której trzeba pomyśleć na etapie projektowania systemu. Wtedy nawet, jeżeli ktoś odstawi jakąś ostrą kaszankę wewnątrz dowolnej z usług, to jest to nie rozlewa się po całym systemie.
  • Legacy w istniejących kontenerach nie wpływa na nowe kontenery. Mogę zrobić nową usługę w czym tylko chcę.
  • Testowanie - mam kontener, wiem co ma robić, mogę sprawdzić, czy to robi
  • Wdrażanie - przy każdym deploy'u zmieniam zamkniętą, wyizolowaną część systemu. Dokładnie wiem, patrząc na 1 plik z kodem, która część systemu się zmieni.
4
con napisał(a):

chciałbym się podpytać, jak u was w projektach wygląda sprawa modularyzacji. Ja za każdym razem mam tak, że otwieram kod mikroserwisu, widzę pakiet typu "controllers" posiadający 40 plików, katalog "model" posiadający ponad 200 plików, wszystko publiczne, wszystko gada ze wszystkim.

Staramy się podążać za clean architecture:
screenshot-20230530015749.png
Na poziomie organizacji kodu wygląda to tak, że każdy nasz mikroserwis posiada "moduły" (foldery/jednostki kompilacji/przestrzenie nazw, de facto warstwy aplikacji):

  • Domain (encje);
  • Application (implementacje UseCasów, czyli klasy obsługujące commandy z naszego command dispatchera oraz interfejsy repozytoriów, klientów zewnętrznych API, itp.);
  • Infrastructure (implementacje powyższych, klasy pomocnicze);
  • Web (kontrolery);
  • Consumer (konsument kafki)
  • Producer (producent kafki)

W każdym module oczywiście są stosowane modyfikatory dostępu, i publiczne jest to, czego pozostałe moduły używają, a nie wszystko. Problem z widocznością w testach rozwiązujemy przez InternalsVisibleTo.

Przepływ jest taki: request HTTP/event kafki -> UseCase -> a ten już robi, co trzeba, np. z repozytorium wczytuje encje, potem wywołuje jakieś zewnętrzne API, potem zapisuje zaktualizowaną encję (co może wyprodukować jakiś wyjściowy event kafki).

Taka struktura aplikacji jest narzucona w szablonie, więc jak ktoś kliknie tworzenie nowej aplikacji w backstage, to dostanie to wszystko za darmo - musi tylko pobrać nowe repozytorium na kompa.

Oczywiście zdarzają się tacy, którzy z tym walczą, bo im "taki podział jest niepotrzebny", bo "mają tylko jeden endpoint", i łączą sobie wszystkie warstwy w jedną, tyle że potem ani wsparcia od nas nie maja, Security się czepia, no i jak dostaną słabą ocenę na backstage, to i ich osobisty Engineering Manager zacznie zadawać pytania.
Tak więc rebeliantów coraz mniej.

Naszło mnie takie przemyślenie, że odkąd zaczęło być jakieś parcie na mikroserwisy to ludzie przestali się przejmować jego podziałem na moduły, bo przecież mikroserwis sam w sobie ma reprezentować jeden bounded context.

Bynajmniej, spaghetti było zawsze. Dopiero w firmach, w których są mikroserwisy zauważam dbanie o utrzymywalność kodu i ogólnie o dobre praktyki.

Są event stormingi, które mają odkrywać bounded contexty w aplikacji, ale w praktyce nie widziałem, żeby ktoś to stosował. Bo jakby to miało działać? Pewnego dnia miałby przyjść do nas architekt i powiedzieć: "no słuchajcie, za duży ten serwis, to sobie zrobimy event storming i go podzielimy"?

Być może tak, ale metoda wrzucania wszystkiego do jednego worka, a potem ewentualnego wydzielania wydaje mi się szalenie nieefektywna. Prawdopodobnie lepiej byłoby, gdyby przed implementacją jakiegoś ficzera zastanowić się, do którego mikroserwisu on pasuje, a jeśli do żadnego, to utworzyć nowy.

W projektach, w których pracowałem to zazwyczaj serwisy osiągały takie rozmiary, że nie dało się już tego podzielić i sensownie z tym pracować, więc przepisywano na kilka mniejszych serwisów. Stąd też moje pytanie czy to ja mam takiego pecha i trafiam do takich projektów, gdzie nigdy nie ma sensownego podziału czy to po prostu standard w naszej branży i nikt się tym nie przejmuje?

Może niekoniecznie masz pecha, co zawsze wybierasz złe branże albo złe typy firm.

piotrpo napisał(a):

Pomijając dyskusję czy 40 plików z logiką to "mikro", burdel jest takim smutnym branżowym standardem. Podział na moduły nie jest trudny jeżeli zaczyna się od poznania problemu, zaprojektowania rozwiązania i dopiero się to rozwiązanie implementuje. Tylko w rzeczywistości ten naturalny wydawałoby się porządek rzadko kiedy jest stosowany. Implementacja zaczyna się od razu, projektowanie w najlepszym razie jest robione w trakcie implementacji, a jak już jest zrobione, to rozpoznawana jest domena. Wtedy, już w warunkach zbliżających się terminów dostosowuje się implementację, żeby robiła coś innego, niż wydawało się że ma robić i powstaje burdel.

Standardy są jak idole - każdy ma takich, na jakich zasługuje. :-)

2

Ehhh ale narzekacie. Akurat z mojego punktu widzenia sytuacja wygląda odrobinę inaczej. Większość programistów, z którymi pracowałam jednoznacznie uważa, że struktura aplikacji powinna odzwierciedlać domenę. Pakiet controllers z wszystkimi controllerami i tego typu podział na warstwy, to pamiętam z dawnych czasów i raczej jak rozmawiam z ludźmi to nikt nie uważa tego za dobra strukturę pakietów w projekcie.
Jak wiadomo w praktyce różnie to wychodzi, aczkolwiek wydaje mi się powszechnym podejsciem jest pakiet o nazwie jak feature i wewnątrz Rest controller, i cała logika tylko model, który jest wykorzystywany w kontekście wielu featurów we wspólnym pakiecie, podobnie jak są jakieś pomocnicze klasy w sensie jakies mechanizmy ogólne.
Ogólnie jak przeczytałam, że to jest microserwis więc jest micro i możemy wrzucać jak do worka 40 controlerów to miałam wtf

1

@szarotka:

Podział architektury aplikacji na ficzery i pchanie wszystkiego do jednego pakietu to trochę przesada, zwłaszcza w przypadku naprawdę złożonych domen biznesowych, ale podział na zasadzie poddziedzin już ma sens i jest podstawą dobrze zaprojektowanego modularnego monolitu. Wysokopoziomowo zwykle wygląda to tak:

Orders

  • API
  • Application
  • Domain
  • Infrastructure

Payments

  • API
  • Application
  • Domain
  • Infrastructure

Invoicing
...

Mamy coś tak jakby moduł który reprezentuje poddziedzinę biznesową (główna, wspierająca, generyczna) i każda z poddziedzin ma swój podział na warstwy.

Jeśli zrobimy do dobrze to późniejsza migracja w kierunku architektury mikroserwisowej to bajka, ponieważ możemy wydzielić moduł (poddziedzinę) bezpośrednio do osobnej usługi. Wiem bo to robiłem, więc to nie jest tylko teoretyczne gadanie.

1

Nie wiem czy się zrozumieliśmy. Chodziło mi o coś w tym stylu (myślnik to pakiet, schodek bez myślnika to klasa):

  • product
    • db
      Encja produkt
    • registerProduct
      Rest controller
      • service
        BlablaCreator
        Mapper
        • validators
          Few validators
      • model
        Reqest
        Response
    • findProduct
      Rest controller
      • model
        Request
        Response
      • service
5

@szarotka: Spoko, ale co w Twoim przypadku oznacza Product? W zależności od kontekstu produkt będzie znaczył co innego. Produkt w kontekście modułu katalogu produktów będzie znaczył co innego niż w przypadku produktu w kontekście zamówienia, dostawy czy płatności. W zależności od kontekstu (czasem poddziedziny) będziemy modelować produkt inaczej. Przykładowo dla modułu/kontekstu katalogu produktów znaczenie będą miały takie atrybuty jak rodzina produktu, kategoria, SKU, tagi, zdjęcia/galeria, opis, itd. I teraz czy moduł Zamówień aby zrealizować proces zamówienia musi wiedzieć jaki opis ma dany produkt albo zdjęcie? No więc nie musi. Dlatego w takim modularnym monolicie podzielonym według kontekstów (czasem poddziedzin) będziemy mieć kilka reprezentacji (klas) produktu. Uproszczony przykład:

  • ProductCatalog
    • Application
      • FindProduct.cs
      • FindProductHandler.cs
    • Domain
      • Product.cs (+id, +name, +sku, +price, +pictures, +description, +family, +tags, +attributes)
    • Infrastructure
      • ProductRepository.cs
  • Inventory
    • Application
      • IsProductAvailable.cs
      • IsProductAvailableHandler.cs
    • Domain
      • Product (+id, +sku, +amount)
    • Infrastructure
      • ProductRepository.cs
  • Orders
    • Application
      • PlaceOrder.cs
      • PlaceOrderHandler.cs
      • ConfirmOrder.cs
      • ConfirmOrderHandler.cs
      • CancelOrder.cs
      • CancelOrderHandler.cs
    • Domain
      • Product.cs (+name, +sku, +price, +vat)
      • Order.cs
      • OrderItem.cs
    • Infrastructure
      • OrderRepository.cs
  • Shipment
    • Application
      • ScheduleShipment.cs
      • ScheduleShimpmentHandler.cs
    • Domain
      • Product.cs (+id, +sku, +name, +height, +width, +weight, +depth)
    • Infrastructure
      • ProductRepository.cs

Teraz jeżeli według Twojej propozycji zamodelujemy Product jako jeden ficzer/pakiet to taki model będzie miał wszystkie atrybuty j/w + logikę i będzie takim uber modelem. Dużo lepszym rozwiązaniem w tej sytuacji jest podzielić aplikację na konteksty ograniczone/poddziedziny i w zależności od kontekstu/poddziedziny modelować produkt inaczej. Innymi słowy każda poddziedzina ma swoje warstwy i swój model domenowy takiego produktu skrojony na miarę bo po co modułowi zamówień wiedza o tym jakie wymiary i wagę ma produkt. Te atrybuty będą miały znaczenie na przykład w module odpowiedzialnym za obsługę dostawy bo na tej podstawie moduł będzie w stanie zamówić przestrzeń w paczkomacie według rozmiaru produktu.

To samo tyczy się modułu płatności. Czy bramka/operator typu PayU, Przelewy24 musi znać dokładnie jaki produkt ktoś zamówił, jakie ma zdjęcie, opis, itd? A no nie musi. I tak dalej i tak dalej :)

0

Już nie chcę wchodzić w temat modelowania poddziedzin, czyli jak zamodelować poddziedzinę główną (Core Subdomain), jak wspierającą (Supporting Subdomain) czy generyczną (Generic Subdomain). W skrócie chodzi o to, że może się okazać, że każda z poddziedzin będzie miała inną architekturę/liczbę warstw. Co ciekawe generyczne poddziedziny zwykle nie mają żadnych warstw bo ich się nie tworzy tylko kupuje gotowca i integruje z resztą systemu. Przykład? Wystawianie faktur. Mało która firma będzie się bawić w pisanie swojego softu do wystawiania faktur. Zwykle kończy się tym, że kupuję się jakieś SaaS (Software as a Service) i integruje z resztą systemu. W tej sytuacji wystawienie faktury polega na wysłaniu odpowiedniego requestu HTTP do programu fakturującego i gotowe, faktura wystawiona. Teraz pozostaje tylko wysłać klientowi pdf na mejla i koniec tematu.

3

@markone_dev:

... Już nie chcę wchodzić w temat modelowania poddziedzin, czyli jak zamodelować poddziedzinę główną (Core Subdomain), jak wspierającą (Supporting Subdomain) czy generyczną (Generic Subdomain).

Dokladnie tak samo, tzn w takiej samej strukturze warstw kodu, "nie biorac do bani" faktu iz wzajemne odpowiedniki klas w warstwie roznia sie iloscia linijek kodu. Jesli zdecydujesz na poczatku iz trzymasz sie okreslonej architektury, to sie tego trzymasz, a "genialne" pomysly kazdego nowego czlonka zespolu, ktory wpada do projektu nie wiadomo skad, nie wiadomo na jak dlugo "topisz w kiblu" i spuszczasz podwojnie wode. W przeciwnym przypadku robi sie z tego kolejny patchwork. Czas na zajebiste pomysly jest na poczatku. Architekt/lead zbiera zespol przedstawia swoja wizje a reszta przedstawia swoje uwagi/propozycje/sugestie. Bezdyskusyjnie ma to swoje wady, ale ma za to jedna zdecydowana zalete, jednolita logike aplikacji jest w stanie utrzymac kazdy nowo przyjety, nawet srednio ogarniety czlonek zespolu. Aplikacja jest latwa w utrzymaniu przez dlugi okres czasu, a jej przepisywanie w przyszlosci daje satysfakcje bo developer nie traci 90% swojego czasu na rozkminianie o czym tym razem kolejny kawalek kodu do mnie "rozmawia".

@markone_dev:

... J> ... że może się okazać, że każda z poddziedzin będzie miała inną architekturę/liczbę warstw.

Nie moze, a dzieje sie to najczesciej w sytuacjach kiedy ktos, logike jednej warstwy przenosi do innej z powodu "bulu d...py" wynikajacego z faktu iz jednym przypadku jest to 100 llinijek a w biezacym tylko jedna. W web-dev masz zawsze do czynienia z banalnym flow'em: zaczyna sie od request'u, konczy sie na response'ie. Mozna w rozny sposob budowac to co jest pomiedzy, ale trzeba sie tego trzymac do konca. Ktos to musi trzymac "za pysk" ale do tego trzeba miec przyslowiowe "jaja" i kompetencje.

@markone_dev:

Co ciekawe generyczne poddziedziny zwykle nie mają żadnych warstw bo ich się nie tworzy tylko kupuje gotowca i integruje z resztą systemu.

To po co o nich wspominasz, jesli nie stanowia problemu bo "przychodza" z zewnatrz, a tymbardziej nie masz wplywu na to ani kto i ani jak to zrobil.

Reasumujac. Kod aplikacji ma byc jednolity i czytelny bo w rezultacie generuje to wiecej pros niz cons. Kropka. Trzymanie sie zasad przyjetych na poczatku jest kluczem. To jaka jest jakosc tych zasad to juz loteria i odpowiedzialnosc spada na tego ktory je ustalil i innego ktory zatwierdzil te ustalenia. Produkt jest dla tego kto za niego placi, a nie dla dania mozliwosci rozwoju kazdemu "geniuszowi" ktory pojawia sie w miedzyczsie w projekcie. Chcesz sie wyszalec w sensie kodu/technologii, zaloz startap i utrzymaj sie z tego, zobaczysz jak dokladnie zaczniesz liczyc pieniadze w takiej sytuacji. W przeciwnym przypadku "morda w kubel" i nie bulgocz. Wystawiasz klientowi faktury wiec dostarcz mu taki kod jaki od Ciebie wymaga. Czytelny, jednolity, rozszerzalny, latwy w utrzymaniu i do ewentualnego przepisania. Naduzywania coraz bardziej zawilej terminologii (ktora i tak za 5-10 lat nikt sie nie bedzie przejmowal) i robienie z tego dev'o woo-doo to jest najwiekszy kant w branzy IT. Niestety wiekszosc klientow to debile/gadget'ciaze ktorym latwo wmowic ze zbudujesz mu lepszego iphone'a w tym roku niz apple wypusci na rynek za 20 lat.

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