# Droga Shoprocket do mikroserwisów, część 1: w czym pomyliłem się, rozbijając monolit

> Wpis zespołu inżynierskiego z pierwszych lat Shoprocket o pierwszej próbie wydzielenia usługi z monolitu w PHP. Dlaczego wybrałem złą pierwszą usługę, czego nauczyło mnie silne sprzężenie i jaką radę Newmana powinienem był przyjąć wcześniej.

Winston Berty  - 17 marca 2016 - 5 min czytania

Kilka miesięcy po rozpoczęciu pracy w Shoprocket zacząłem odczuwać frustrację. Mieliśmy aplikację w PHP, nad którą pracował niewielki zespół błyskotliwych programistów rozsianych po całym świecie, a mnie się wydawało, że poprawki błędów rodzą kolejne błędy, wdrażanie nowych funkcji nie jest tak proste, jak powinno być, a wdrożenia zdarzają się rzadko i są stresujące. Przyczyna: mocno sprzężony kod.

Mieliśmy aplikację monolityczną, prawie w całości w jednym repozytorium na GitHubie. Aktualizacje lub poprawki jednej funkcji często wymagały zmian w kilku miejscach. Do testowania służył proces code review, w którym co najmniej dwóch innych programistów musiało zatwierdzić gałąź, zanim trafiła do mastera i została wdrożona. To wszystko oznaczało, że gdy wkradł się błąd, często trudno było znaleźć zmianę, która go wywołała. Kiedy już ją znaleźliśmy, poprawka przechodziła ten sam proces, a cała aplikacja musiała zostać wdrożona od nowa.

Jako zapalony młody programista, który zawsze szukał nowinek, uznałem, że gdy trafiłem na mikroserwisy, rozwiążą one wszystkie nasze problemy.

## Czym według mnie były mikroserwisy

Nie ma formalnej definicji mikroserwisów, ale z mojego researchu wyniosłem, że architektura mikroserwisowa to sposób projektowania aplikacji jako rozproszonych systemów niezależnych usług, z których każda jest wysoce wyspecjalizowana i ma własny cykl życia. Szczegółowe wprowadzenie to świetny [artykuł](https://martinfowler.com/articles/microservices.html) Martina Fowlera.

Zaczepiły mnie dwie rzeczy. Po pierwsze, pomysł podziału aplikacji na usługi o ścisłych granicach. Zmniejsza to ryzyko, że logika właściwa jednemu kontekstowi biznesowemu będzie przeciekać między komponentami, bo interfejsy między granicami trzeba starannie zaplanować. To nie jest tak proste jak lokalne wywołania funkcji. Po drugie, każdy komponent może mieć niezależny cykl życia. Zespoły mogą być właścicielami swojego kodu i używać stosu najlepiej dopasowanego do usługi, a zmiany można wdrażać po jednej usłudze naraz i wycofywać bez wpływu na resztę.

Byłem kupiony. Shoprocket miał rozbić monolit. To część 1 krótkiej serii opisującej tę drogę. Mam nadzieję, że czytelnicy planujący podobną zmianę lub właśnie ją przechodzący wyniosą coś z naszych sukcesów i porażek.

## Pierwsze wyzwanie było ludzkie, nie techniczne

Musiałem sprzedać ten pomysł reszcie zespołu. Byli ciekawi, ale nie podzielali entuzjazmu i niechętnie oddawali godziny programistów na tak wczesnym etapie życia produktu. Na szczęście CTO chciał, żebym przyjrzał się naszemu zarządzaniu sesjami, więc chwyciłem okazję: przekonałem go, że mogę wydzielić usługę sesji.

Z perspektywy czasu to był kiepski wybór pierwszej usługi. Nasz produkt zawiera widżet JavaScript, który [umożliwia sprzedaż na dowolnej stronie](https://v3.shoprocket.io/pl/funkcje/sprzedaz-na-kazdej-stronie.md). Sesje traktujemy jako zasób i zapisujemy ich dane w bazie, żeby analizować porzucone koszyki i inne wskaźniki. Ale ten zasób nie jest tak namacalny jak zamówienia czy pozycje zamówienia, a sesji używaliśmy przy prawie każdej zmianie stanu aplikacji. To oznaczało, że usługa będzie nieuchronnie bardzo rozmowna względem reszty aplikacji, czego nie przewidziałem, a co utrudniło mi zadanie.

## Czego nauczyłem się, budując ją naprawdę

Zwiększyłem tempo researchu. Obok Fowlera niezastąpionym źródłem okazała się książka Sama Newmana **Building Microservices**.

Rada Newmana, z perspektywy czasu, była tą, której powinienem był posłuchać: najpierw przebudować istniejącą aplikację na moduły odzwierciedlające ograniczone konteksty (bounded contexts) domeny. Gdy programiści są zadowoleni z granic, *dopiero wtedy* wydziela się moduły do osobnych usług. Powód jest taki, że o wiele łatwiej rozebrać i przepisać moduły o złych granicach niż całe usługi z ich dodatkowym kodem infrastrukturalnym i trwałymi zasobami.

Nie posłuchałem tej rady. Chcąc zbudować własny komponent, przystąpiłem do usługi sesji.

Wybrałem stos tylko nieznacznie różniący się od stosu monolitu i zacząłem budować. Sama usługa powstała szybko: kilka tygodni na samodzielną aplikację z REST API. Tam nie leżała trudność. Trudne było sprawienie, żeby usługa rozmawiała z monolitem.

Okazało się, że zarządzanie sesjami jest ściśle sprzężone z resztą kodu. Zastępowanie wywołań funkcji wywołaniami API szło mozolnie. Ponieważ usługa sesji i monolit miały osobne schematy baz danych, musiałem przepisać każdą logikę w monolicie korzystającą z zasobów sesji ze starej bazy i przestrukturyzować dane na granicy aplikacji, żeby zachować zgodność z klientami takimi jak nasz widżet JavaScript.

Integracja trwała dłużej niż budowa. I to wciąż bez większości narzutu, jaki zwykle niosą mikroserwisy: wykrywania usług, logowania, monitoringu, śledzenia rozproszonego. Co gorsza, silne sprzężenie sprawiało, że zmiany rozlewały się na wiele obszarów kodu. Ponieważ zespół w tym czasie pracował równolegle, scalenie i wprowadzenie usługi sesji na produkcję wymagałoby znacznie więcej koordynacji, niż szacowałem.

## Szczera ocena

Usługa może wkrótce trafić na produkcję. Ale czuję teraz, że powinienem był posłuchać Newmana i najpierw włożyć wysiłek w modularyzację istniejącej aplikacji. Korzyść z jednej usługi żyjącej samodzielnie jest marginalna. Prawdziwa korzyść pojawia się, gdy rozbijesz całość, przynajmniej na gruboziarniste usługi, które rozmawiają ze sobą jak najmniej. To wymaga dobrze przemyślanych granic komponentów, a my jeszcze tam nie byliśmy.

Nadal jestem przekonany do mikroserwisów jako idei. Moją próbę traktuję jako użyteczny eksperyment. Nauczyłem się bardzo wiele o architekturze aplikacji, modelowaniu domeny i zasadach REST, a te lekcje przełożyły się na inne części naszego kodu.

Dla każdego, kto myśli o podobnej zmianie, moje szczere rekomendacje:

- Przeczytaj jak najwięcej na ten temat, zanim się zobowiążesz
- Odłóż tę pracę, aż naprawdę pewnie poczujesz się w swoim kodzie i modelu domeny
- Pamiętaj, że są inne sposoby na stabilność i odporność monolitu. Automatyczne testy jednostkowe i funkcjonalne pomagają ogromnie. Programowanie sterowane testami ogranicza regresje. Skalowanie poziome czyni wdrożenia mniej bolesnymi
- Zacznij od modularyzacji monolitu, zanim zaczniesz wydzielać usługi

Shoprocket będzie kontynuować swoją drogę. W części 2 robi się ciekawiej.

---

*Pierwotnie opublikowane jako pierwszy z krótkiej serii wpisów dokumentujących wczesne odejście Shoprocket od monolitu w PHP. Pełna droga, łącznie z błędami poprawionymi w późniejszych iteracjach, trwała dalej przy każdym kolejnym dużym przepisaniu platformy.*

---

- HTML version: https://v3.shoprocket.io/pl/blog/droga-shoprocket-do-mikroserwisow-czesc-1-rozbijanie-monolitu
- Language: Polski (pl)
- Also in: [العربية](https://v3.shoprocket.io/ar/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [Deutsch](https://v3.shoprocket.io/de/blog/shoprocket-microservices-teil-1-monolith-zerlegen-fehler.md), [Ελληνικά](https://v3.shoprocket.io/el/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [English](https://v3.shoprocket.io/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [Español](https://v3.shoprocket.io/es/blog/shoprocket-microservicios-parte-1-lo-que-hice-mal-monolito.md), [Français](https://v3.shoprocket.io/fr/blog/shoprocket-vers-les-microservices-partie-1-decouper-le-monolithe.md), [עברית](https://v3.shoprocket.io/he/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [हिन्दी](https://v3.shoprocket.io/hi/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [Bahasa Indonesia](https://v3.shoprocket.io/id/blog/perjalanan-shoprocket-menuju-microservices-bagian-1-salah-memecah-monolit.md), [Italiano](https://v3.shoprocket.io/it/blog/viaggio-di-shoprocket-verso-i-microservizi-parte-1-cosa-ho-sbagliato-sul-monolite.md), [日本語](https://v3.shoprocket.io/ja/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [Lietuvių](https://v3.shoprocket.io/lt/tinklarastis/shoprocket-kelione-i-mikropaslaugas-1-dalis.md), [Norsk](https://v3.shoprocket.io/nb/blogg/shoprockets-vei-mot-mikrotjenester-del-1-hva-jeg-tok-feil-av.md), [Nederlands](https://v3.shoprocket.io/nl/blog/shoprocket-microservices-deel-1-monoliet-opknippen.md), [Português](https://v3.shoprocket.io/pt/blog/jornada-do-shoprocket-para-microsservicos-parte-1-o-que-errei-ao-quebrar-o-monolito.md), [Română](https://v3.shoprocket.io/ro/blog/drumul-shoprocket-spre-microservicii-partea-1-ce-am-gresit-cu-monolitul.md), [Русский](https://v3.shoprocket.io/ru/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [ไทย](https://v3.shoprocket.io/th/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [Türkçe](https://v3.shoprocket.io/tr/blog/shoprocket-mikroservis-yolculugu-1-monoliti-parcalarken-yanlis-yaptiklarim.md), [中文](https://v3.shoprocket.io/zh/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md)
