Mikroserwisy - jak uniknąć duplikacji kodu?

Mikroserwisy - jak uniknąć duplikacji kodu?
YA
  • Rejestracja:prawie 4 lata
  • Ostatnio:6 dni
  • Postów:252
0

Pytanie bazuję na następujących założeniach:

  • Mikroserwisy są zazwyczaj wdrażane w ten sposób, że każdy serwis to osobne repo
    • Jednym z założeń mikroserwisów jest umożliwienie niezależnego od siebie wersjonowania i wdrażania komponentów aplikacji. Gdyby korzystać z "tradycyjnego" modelu, tj. jedno repo z wieloma projektami kompilowanymi jako biblioteki (np. .dllki), to każda zmiana w danej bibliotece pociąga za sobą konieczność podniesienia wersji i wdrożenia wszystkich bibliotek (oraz oczywiście samego exeka), które zależą od tej biblioteczki, która uległa zmianie. Nie dzieje się tak, jeśli zamiast bibliotek mamy osobne pliki wykonywalne, które są kompilowane niezależnie od siebie.
  • Mikroserwisy komunikują się ze sobą za pomocą serializacji i mechanizmów takich, jak REST API. Wymaga to, by komunikujące się ze sobą mikroserwisy korzystały z tego samego modelu danych

Przedstawiłem swój "mental model", bo wiele razy się orientowałem, że pytania, które chcę zadać są oparte na niepoprawnym rozumieniu zagadnienia - jeśli teraz też tak jest, to może dzięki temu uda się uniknąć konfuzji.

Teraz właściwe pytanie.

Załóżmy, że mamy mikroserwis A oraz mikroserwis B i A przesyła jakieś dane B.

Wobec tego w A będziemy mieć klasę jakąś taką:

Kopiuj
public class ModelDanych
{
    public string JakisNapis {get; set;}
    public int JakasLiczba {get; set;}

    public List<PodModel> JakasKolekcja {get; set;}
}

public class PodModel
{
    public double // ...
    /*
        ...
    */
}

(Javowców przepraszam za C#, niestety ten język na razie znam najlepiej, z pewnością jednak zagadnienie jest analogiczne w Javie)

Serwis A zserializuje tę klasę do np. JSONa, wyśle ją do serwisu B, który otrzyma JSONa i zdeserializuje go do klasy jakiejś takiej:

Kopiuj
public class ModelDanych
{
    public string JakisNapis {get; set;}
    public int JakasLiczba {get; set;}

    public List<PodModel> JakasKolekcja {get; set;}
}

public class PodModel
{
    public double // ...
    /*
        ...
    */
}

Tak, zrobiłem tu Ctrl+C Ctrl+V podczas pisania pytania. Analogiczny Ctrl+C Ctrl+V trzeba by zrobić podczas pisania tych mikroserwisów. A tymczasem Ctrl+C Ctrl+V jest operacją podobno zakazaną podczas programowania?

W przypadku monolitu zamiast serwisów A i B mielibyśmy biblioteki A i B i one zależałyby od klasy ModelDanych, która siedziałaby pewnie w jakiejś wspólnej bibliotece Modele.dll czy coś w tym stylu. Dlatego zawartość tej klasy nie byłaby przeklejona. A jak uniknąć duplikacji w przypadku mikroserwisów?

edytowany 1x, ostatnio: YetAnohterone
Aventus
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
2

To akurat proste- od tego stosuje się paczki, np. w .Net za pomocą NuGet. Wtedy serwis A wystawia paczkę ze swoimi DTOs, a serwis B może tę paczkę zainstalować i używać DTO typy wystawione przez A. Pozwala to również lepiej kontrolować wersje modeli. To oczywiście w przypadku bardziej "tradycyjnych" metod komunikacji (HTTP, eventy itp). Np. w takim gRPC nie ma koniecznie potrzeby dzielenia się typami, ale dzieli się plikami *protobuf *które są swoistymi definicjami wiadomości (typów).


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
edytowany 1x, ostatnio: Aventus
PA
W przypadku Resta, można użyć OpenAPI
Aventus
OpenAPI raczej nie odpowiada na pytanie OPa. Chociaż znając życie to są jakieś narzędzia które generują DTO na podstawie OpenAPI?
PA
Tak, da się generować DTO z OpenAPI.
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:3 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
7

Jednak dokonałeś tu założenia. Założeniem jest że wszystkie mikroserwisy są w C#. Wtedy można jak najbardziej wystawiać paczki z DTO. Tak samo jak się robiło dla starego dobrego SOAP.
Co jednak jeśli drugi mikroserwice będzie np w Javie? Wtedy wystawianie paczek z DTO nie wystarczy. O czywiście można użyć jakiejś metody opisu DTO niezależnej od języka programowania i na tej podstawie generować DTO. W starym dobrym SOAP był to XML a konkretnie WSDL. Teraz jest multum schematów do wybrania jak Protocol Buffet, Thrift, AVRO czy zwykły JSON Scheme (oprócz oczywiście open api)
Mimo to często kończy się na klepaniu w klientach DTO raz jeszcze. Co ciekawe nie muszą być to te same klasy jak w oryginale. Clienty mogą nie używać wszystkich pól lub ( o zgrozo :) ) posiadać dodatkowe metody


Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
edytowany 5x, ostatnio: KamilAdam
YA
Dotnet odchodzi od Soapów...
KamilAdam
Wszyscy odchodzą. Ale SOAP rozwiązywał cześć problemów których REST dalej nie umie rozwiązać dobrze. Może już jest lepiej niż na początku, ale dalej brak standardu i panuje chaos
Aventus
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
0

Słuszna uwaga, faktycznie dokonałem takiego założenia- głównie dla tego że OP wspomniał C#. W przypadku mikroserwisów pisanych w różnych językach to z pomocą mogą przyjść narzędzia dla OpenAPI o których wspomniał @Pazura.

Chociaż prawda jest taka że przypadki systemu opartego o mikroserwisy, gdzie używa się różnych języków, to raczej mniejszość- najczęściej chyba spotykana w korpo-molochach.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:dzień
  • Lokalizacja:Wrocław
4
YetAnohterone napisał(a):

A tymczasem Ctrl+C Ctrl+V jest operacją podobno zakazaną podczas programowania?

To tylko takie kłamstwo dla dzieci, jak to, że niebo jest niebieskie, albo nie ma pierwiastka z -1. ;)

A jak uniknąć duplikacji w przypadku mikroserwisów?

Generujesz klienta do Twojej zależności na podstawie OpenAPI: https://github.com/Azure/autorest

YA
"To tylko takie kłamstwo dla dzieci, jak to, że niebo jest niebieskie, albo nie ma pierwiastka z -1. ;)" - Nie raz i nie dwa pozwalałem sobie na Ctrl+C Ctrl+V...
SL
  • Rejestracja:około 7 lat
  • Ostatnio:40 minut
  • Postów:876
0

@YetAnohterone: przecież to główna zasada mikroserwisów: piszesz jakieś 10x więcej kodu, ale twój system jest dostosowany do wstecznie kompatybilnych zmian. Ctrl + C/V nie jest zakazane: po prostu zasady i podejścia wewnątrz jednego serwisu są diametralnie inne niż w ekosystemie mikroserwisów. Najlepiej to widać, gdy przyjrzysz się strukturom danych używanych w obu podejściach. W przypadku logiki wewnątrz serwisu chcesz używać mocnych typów, żeby twój kod był prosty i miał mało przypadków. Mocne typy sprawiają, że nie musisz robić wiele ifów np. czy wartość nie jest nullem. Zmiana czegokolwiek jest bardzo prosta, wystarczy użyć refactoru z IDE i poprawiać aż kompilator/testy przestaną krzyczeć. W przypadku komunikacji pomiędzy serwisami używamy "głupich" formatów danych takich jak JSON czy protobuf. W takim protobufie możesz zmienić nazwę pola albo listę na pojedyńczą wartość i nic się nie zepsuje, bo format wymusza na tobie dokładne sprawdzenie wszystkich możliwych przypadków.

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0
  1. Jak technologia ta sama (np. JVM), to możesz opublikować klienta do swojego serwisu i drugi serwis weźmie go jako zalezność
  2. Jak technologie są różne to cudów nie ma, klienta trzeba będzie zrobić kilka razy

"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 2 godziny
  • Postów:3277
1
Shalom napisał(a):
  1. Jak technologie są różne to cudów nie ma, klienta trzeba będzie zrobić kilka razy

Może się robić sam - wystawiasz po jednej stronie OpenAPI, po drugiej zaciągasz i swagger genem tego klienta tworzysz. Albo jak to teraz modne, przygotowujesz openAPI i generujesz zarówno serwer, jak i klienta.

Kod klienta oczywiście będzie nadmiarowy, ale jak sądzę można z tym żyć. DRY stosuje się po to, żeby po kodzie nie rozłaziły się pasty jakiegoś kawałka i w razie konieczności jakiejś zmiany nie trzeba było przez 2 dni szukać wszystkich możliwych miejsc gdzie trzeba coś zmienić, a przez kolejne pół roku dowiadywać się które nie zostały jednak znalezione. Jeżeli zautomatyzujemy taki proces, to swagger file jest naszą zależnością, a dynamicznie generowany service stub, czy http client kawałkami kodu na które nie zwracamy większej uwagi przy utrzymaniu.

edytowany 1x, ostatnio: piotrpo
somekind
To robi przecież narzędzie, które podlinkowałem wyżej. ;)
piotrpo
Podlinkowałeś narzędzie, którego nie znam (Azure mnie zmyliło) miałem na myśli dokładnie to: https://swagger.io/tools/swagger-codegen/
somekind
Tego z kolei ja nie znałem, dzięki!
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)