fbpx

Własna, customowa libka to same problemy

Własna, customowa libka to same problemy

Wiesz, że własna, customowa libka, zbudowana specjalnie dla Twojego mikroserwisowego systemu to tak naprawdę strzał prosto w kolano?

Pewnie pierwsza myśl jaka Ci się pojawi, to:

🗣️ “Ale dlaczego? Co w tym złego?”

Już tłumaczę.

Zazwyczaj chcemy dobrze. Wychodzimy z założenia DRY, czyli Don’t Repeat Yourself. Nie chcemy się powtarzać. No bo w końcu tak nas wszyscy uczą. Nie duplikuj kodu.

Zasadniczo jest to słuszne.

Jeżeli coś jest skomplikowane, to lepiej to zrobić raz, w jednym miejscu, w libce i jej użyć wszędzie. No i tu pojawia się problem. Nagle, dodajemy twardą zależność do wszystkich mikroserwisów. Zazwyczaj zależność, która mocno wymusza konkretny framework i jego wersje. Tracimy możliwość niezależnego rozwoju poszczególnych usług. Betonujemy swój system.

Osobiście spotkałem się z kilkoma rodzajami takich libek:

  • 🔒 Mechanizmy bezpieczeństwa – np. na potrzeby zabezpieczenia komunikacji REST
  • 💬 Mechanizmy komunikacji – sztandardowym przykładem będą tu wszelkie connectory, np do Kafki
  • 🛠️ Utilsy narzędziowe – np. do mechanizmu obsługi feature flag

No to kolejno.

🔒 Własne mechanizmy bezpieczeństwa

Podstawowe pytanie tutaj: Ale po co Ci własny mechanizm?

Istnieją szeroko wspierane standardy, które w 99% przypadków będą wystarczające. Naprawdę nie trzeba wymyślać nic nowego. OAuth2 i jego tokeny JWT powinny wystarczyć. Co więcej, Spring Security wspiera wiele protokołów wydawania takich tokenów, więc możesz wybrać taki flow jaki będzie dla Ciebie najlepszy.

Może się tutaj pojawić argument:

🗣️ “Ale nasz token musi zawierać dodatkowe informacje, dlatego będziemy go generować w każdym serwisie przy użyciu libki”

No i super. Ale to nadal nie usprawiedliwia tworzenia libki.

✅ Stwórz dodatkowy mikroserwis, który będzie wystawiał API zgodne z OAuth2 i wydawał tokeny według Twoich standardów.

🧨 Najgorsze co możesz zrobić, to stworzyć libkę która będzie w sobie miała pełną autokonfiguracje warstwy bezpieczeństwa (czyli np. Spring Security). To sprawi, że totalnie odbierzesz możliwość tuningowania serwisom z niej korzystającym, a co więcej, wymusisz bardzo konkretne rozwiązanie.

💬 Mechanizmy komunikacji

Kafka connector. Rabbit connector. REST XYZ client.

Jeżeli Twój mechanizm komunikacji jest tak skomplikowany, że wymaga napisania do niego specjalnej libki, to znaczy, że jest jakiś spory problem gdzieś indziej.

Aktualnie mamy wiele sposobów w jaki możemy się komunikować.

Wyliczę kilka dla samej Kafki:

  • Kafka Connect
  • Kafka Client
  • Kafka Streams
  • ksqlDB
  • Spring Cloud Stream Kafka i Kafka Streams

No i może jeszcze kilka dla REST:

  • Feign
  • Retrofit
  • WebClient
  • RestTemplate
  • Apache HttpClient

Sporo tego, prawda?

No i teraz, pisząc własny connector, musisz wybrać, którą technologię narzucisz? A może się okazać, że dla pewnego mikroserwisu lepsza byłaby inna technologia? I co teraz?

Także, zanim pójdziesz w tę stronę, dobrze się zastanów, dlaczego chcesz to zrobić.

  • Czy masz jakieś standardowe nagłówki które mają zostać dodane?
  • Czy klucz komunikatu ma mieć określony format?
  • Czy payload ma mieć jakąś standardową strukturę?

✅ Wszystkie te rzeczy możesz wymusić poprzez określenie standardów i kontraktów. Możesz użyć specyfikacji Avro lub OpenAPI. Możesz też wykorzystać testy oparte o konktrakty.

🧨 A co jeśli masz jakąś bardziej zagmatwaną logikę? Na przykład, doklejasz jakieś sufixy i prefixy do nazw topików, albo jakoś dziwnie budujesz URL zapytania, doklejając jakieś dziwne parametry query?

W takim przypadku, bym na Twoim miejscu dobrze się zastanowił, dlaczego coś takiego w ogóle robisz. Bo jak dla mnie, jest to totalnie zbędne utrudnianie sobie życia.

⚒️ Utilsy narzędziowe

Kolejny rodzaj libek, prawdę mówiąc najbardziej sensowny, to narzędzia.

✅ Jeżeli Twoja libka to czyste klasy narzędziowe, np. coś w stylu Apache Commons, Apache lang itp. No to super. To ma to szanse być użyteczne (chyba że duplikujesz coś, co już jest dostępne na rynku ot tak).

Natomiast, jeżeli Twoja libka adresuje jakiś szerszy problem, np. “Sposób wykorzystania mechanizmu Feature Flag”, no to już jest gorzej.

Bardzo często, chcąc stworzyć libkę do prostego problemu, zaczynamy budować uniwersalnego potworka do wszystkiego, wręcz framework. Chcemy przewidzieć wszystko. Co powoduje, że kod i samo użycie robi się mega skomplikowane.

A umówmy się, sprawdzenie Feature Flag to tak naprawdę sprawdzenie IFa. Prosta operacja, jedyna trudność to to, że źródło prawdy może znajdować się w innym serwisie.

🧨 Taki potworek puchnie i puchnie. Jest dla nas dodatkowym obciążeniem, dodatkowym kodem do utrzymania. Co więcej, im więcej usług z niego korzysta, tym bardziej prawdopodobne, że coś popsujemy przy wydaniu kolejnych wersji libki. Musimy położyć bardzo mocny nacisk na dokładne przetestowanie naszego potworka.

🍄 Ale ja jednak chce zrobić libkę!

No dobra, jeżeli jednak potrzebujesz tę libkę, to trzymaj się tych zasad:

✅ Sprawdź, czy nie ma już gotowego standardu adresującego Twój problem.
Jeżeli jest, wykorzystaj ogólnodostępne biblioteki wspierające ten standard.

✅ Najpierw zdefiniuj standard czy też specyfikację Twojego problemu.
Dzięki temu libka będzie opcjonalna. Każdy w razie czego będzie mógł zaimplementować mechanizm u siebie w swojej technologii.

✅ Stwórz narzędzia, nie rozwiązania.
Spraw, aby Twoja libka dostarczała klas narzędziowych, które możesz swobodnie wpinać w mechanizmy Twojego serwisu. Tak, aby nie wymuszała rozwiązania, a jedynie wspierała.

✅ Unikaj automatycznej konfiguracji.
Nigdy nie wymuszaj swoją libką automatycznej konfiguracji. To jest największe zagrożenie ze strony libek, które jeżeli jest nieumiejętnie zrobione, bardzo utrudnia rozwój aplikacji.

W niektórych przypadkach może w ogóle zablokować Twoją pracę i wymagać najpierw wprowadzenia poważnych zmian w samej libce.

👿 Pamiętaj, że jak stworzysz libkę, to musisz ją później utrzymywać, fixować i rozwijać. Nie ma lekko.

Awatar Łukasz Monkiewicz

3 odpowiedzi na „Własna, customowa libka to same problemy”

  1. Awatar Szymon
    Szymon

    Hej, co proponujesz jeśli odpowiedź dla tego pytania „Czy masz jakieś standardowe nagłówki które mają zostać dodane?” to tak? Każdym serwisie osobno robić propagacje takich nagłówków? W przypadku mieszania SpringMVC i Webflux/Webclienta nie jest to trywialne, łatwo o błędy. Czy w takim przypadku nie lepsza będzie jednak biblioteka którą inne usługi mogą wykorzystać?

    1. Awatar Łukasz Monkiewicz

      Podszedłbym do tego w ten sposób:
      1. Dokumentacja jasno mówiąca jakie nagłówki są potrzebne.
      2. Opcjonalna libka lub kilka libek (per technologia), które dostarczają implementacje Filtrów/Interceptorów itp., które dołączają odpowiednie nagłówki na podstawie wartości dostarczonych przez aplikację. Tutaj moim zdaniem jest istotne, aby nie zaszyć w libce logiki wyciągania tych informacji, bo wtedy zaczynamy lać beton 🙁

      Może zrobię wpis z konkretnym przykładem i omówieniem, bo rzeczywiście to jest scenariusz, który można spotkać.

  2. […] własnej libki na potrzeby architektury mikroserwisowej to nie jest najlepszy pomysł. Z wielu powodów. Tym razem spójrz jak to zrobić, w sytuacji, kiedy jednak taką libke bardzo chcesz […]

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *