Od diagramu architektury do mapy, która odpowiada na pytania.
Zbierz wymagania, dopytaj biznes, rozstrzygnij sprzeczności.
Potnij system, wybierz integracje, uzasadnij decyzje.
I jeszcze to wszystko dowieź na czas.
„You can do it! Just use AI! Become a Software Generalist”
I wyciąga z tego rozsądny wniosek: zanim cokolwiek podzieli, musi zobaczyć, co w ogóle ma. Zaczyna od zebrania ludzi przy ścianie.
Świetne na start. Tylko że po warsztacie zostaje ściana karteczek, a nie decyzja.
To nie jest wada diagramu. On po prostu opisuje technikę, a nie podział domeny.
@Joachim na Black Friday potrzebujemy nowych rabatów. Robimy to my czy Billing? Oba zespoły twierdzą, że to ich.
@Joachim Ania wraca z urlopu. Dajemy ją na powiadomienia czy na cennik? Obie rzeczy się palą.
@Joachim mała poprawka w zamówieniach, a w release notes znowu płatności, magazyn i raporty. Czemu?
otwiera diagram architektury i pisze
Obie są potrzebne. Kłopot zaczyna się, gdy od jednej oczekujemy odpowiedzi należących do drugiej.
Technical Lead w Jit Team · architekt i konsultant
To samo słowo po dwóch stronach granicy znaczy co innego. I bardzo dobrze.
Zamówienie
Zamówienie
Duże modele rozbija się na osobne konteksty, a potem jawnie opisuje, jak te konteksty się ze sobą mają. Rozbicie robi większość zespołów. Opisanie relacji już nie.
Domain-Driven Design, 2003
Najpierw narysuj teren taki, jaki jest, łącznie z tym, co Ci się nie podoba. Dopiero mając mapę, podejmujesz decyzje.
Większość tego, czego potrzebujesz, siedzi już w diagramie, który macie na ścianie. Trzeba tylko zadać mu inne pytania.
Ładnym i pożytecznym przy onboardingu. Tylko że nikt do niej nie zagląda, gdy w piątek trzeba zdecydować, gdzie wyląduje nowe wymaganie.
Sama mapa to wciąż obrazek. Dopiero te warstwy sprawiają, że zaczyna odpowiadać na pytania, które ktoś naprawdę zadaje.
Gdzie przebiega, kiedy każdy zespół uważa, że dana funkcjonalność należy do niego.
Gdzie warto wysłać dobry zespół, a co spokojnie można kupić.
Co ten kontekst komuś obiecał i czego nie wolno złamać po cichu.
Dlaczego jedna zmiana pociąga za sobą kolejne konteksty i kolejne wdrożenia.
Każdy refaktor jest lokalnie uzasadniony. Żaden nie wraca do mapy, żeby ją poprawić.
Jeden artefakt, który rośnie razem z tym, ile już wiecie o systemie. Każdy poziom dokładasz dopiero wtedy, gdy masz czym go wypełnić.
Konteksty, relacje, kierunek zależności. To wychodzi wprost z diagramu, który macie.
Klasyfikacja i pytania. Gdzie granica, gdzie inwestować.
Co kontekst komuś obiecał i co ktoś mu narzucił.
Metryki sprzężenia i connascence na krawędziach. Czemu zmiana wysypuje coś obok.
map "Classic context map · e-commerce" context ERP { at 150 110 } context Catalog { at 150 390 } context Orders { at 800 410 } Identity -> Orders { type open-host-service upstream OHS downstream CF } ERP -> Catalog { type customer-supplier downstream ACL integration "nightly sync" } Orders -> Notifications { type conformist }
7 kontekstów, 7 relacji
Tyle da się wyciągnąć z diagramu architektury w jedno popołudnie. I tyle zwykle ludzie nazywają mapą kontekstów.
Sales dodaje rabat na Black Friday: druga sztuka 50% taniej. Klient widzi w koszyku 150 zł.
Billing liczy ten sam rabat po swojemu: od ceny netto, z zaokrągleniem każdej pozycji.
Klient zapłacił 150 zł, a na fakturze ma 153,75 zł.
Reklamacja trafia do obu zespołów. Każdy pokazuje, że u niego wszystko się zgadza.
Spór nie jest o kod, tylko o to, czyje jest pojęcie. Rozstrzygają go trzy pytania:
Każdy kontekst istnieje po to, żeby odpowiadać na kilka pytań. Jeśli nie umiesz ich wypisać, granica jest w złym miejscu.
Każdy kontekst niesie swoje pytania. Dwa pudełka z tym samym pytaniem od razu rzucają się w oczy.
Joachim ma dwóch seniorów i trzech juniorów. Seniorów daje na powiadomienia i Kafkę, bo tam jest „najtrudniejsza technologia”.
Cennik i rabaty trafiają do juniorów. Przecież to tylko kilka ifów.
Powiadomienia mają własny silnik szablonów i trzy poziomy retry. Nikt o to nie prosił.
Biznes chce promocji na Black Friday. Rabaty to 40 zagnieżdżonych ifów, wdrożenie potrwa trzy tygodnie.
Joachim rozdzielił ludzi według trudności technicznej, a nie według tego, na czym firma zarabia.
W DDD to są trzy rodzaje subdomen. W mapie zapisujesz je przy kontekście jako jedną etykietę.
Tu jest przewaga konkurencyjna. Buduj sam, najlepszymi ludźmi, i pilnuj tego jak oka w głowie.
Potrzebne, ale nikt Was za to nie pokocha. Buduj prosto, bez ceremonii, świadomie taniej.
Rozwiązany problem. Kup, zintegruj, postaw warstwę tłumaczącą i zapomnij.
Mapa pokazuje wtedy nie tylko połączenia, ale i to, gdzie idą pieniądze i uwaga zespołu.
Model Cynefin opracował Dave Snowden pod koniec lat 90. w IBM. Nazwa pochodzi z walijskiego i oznacza mniej więcej siedlisko, czyli miejsce, które nas kształtuje.
context Orders { subdomain core cynefin complicated } context Warehouse { subdomain supporting cynefin complicated } context Payments { subdomain generic cynefin clear }
Dwie etykiety na kontekście i mapa zaczyna mówić, gdzie wysłać ludzi, a co kupić.
Klient płaci przelewem przez bramkę płatności. Pieniądze schodzą z konta.
Orders nie widzi potwierdzenia, więc anuluje zamówienie i zwalnia towar.
Bank rozlicza przelew. Payments publikuje PaymentConfirmed.
Klient ma pusty portfel, anulowane zamówienie i dzwoni na infolinię.
Orders zakładał, że potwierdzenie przychodzi w kilka minut. Payments nigdy tego nie obiecał, bo nie ma wpływu na to, kiedy bank rozliczy przelew.
Model współpracy autonomicznych agentów, opisany przez Marka Burgessa. Agenci nie wydają sobie poleceń, tylko składają dobrowolne obietnice.
Agent kontroluje wyłącznie własne zachowanie. Bounded Context jest dokładnie takim agentem.
Obietnica ma sens dopiero wtedy, gdy ktoś z zewnątrz jest w stanie sprawdzić, czy została dotrzymana. Stąd obserwator na rysunku.
„Będę publikował zdarzenie o przyznaniu licencji w ciągu minuty.”
Składa ją ten, kto ma nad tym kontrolę. Da się ją zweryfikować i da się jej zaufać.
„Macie publikować to zdarzenie w ciągu minuty.”
Narzucone z zewnątrz, bez kontroli nad wykonaniem. Wygląda jak ustalenie, a jest życzeniem.
Obietnica ma autora, odbiorcę, treść i warunki. Jeśli któregoś z tych czterech brakuje, to nie jest obietnica, tylko założenie.
context Orders { promise + "an accepted order is valid and paid" to Warehouse promise - "payment confirmation" from Payments if "order total is positive" } context Carrier { // to nie jest obietnica imposition "you must use our label format" on Warehouse }
Plus to obietnica złożona, minus to obietnica, na której polegasz. Narzucenie rysuje się inaczej, bo nim nie jest.
To co, wdrażamy dziś poprawkę w płatnościach?
Jak płatności, to magazyn też musi iść. Zmienił się format eventu.
A jak magazyn, to raportowanie też. Inaczej rano dashboardy pokażą zera.
Panowie, coś nam chyba nie wyszło to event driven.
Sprzężenie to klej, który trzyma system w całości.
Bez sprzężenia zegarek nie chodzi. Koła muszą się zazębiać, inaczej nic nie napędza niczego.
Ale im ciaśniej je dociśniesz, tym szybciej zetrą się zęby i tym trudniej wymienić jedno koło bez rozbierania całego mechanizmu.
Miara jakości mówiąca, kiedy dwa elementy muszą zmieniać się razem, żeby system pozostał poprawny.
Sprzężenie mówi, że coś jest połączone. Connascence mówi, jak bardzo boli, gdy to ruszysz.
Jak trudno to wykryć i bezpiecznie zmienić. Od nazwy, przez typ i pozycję, po wykonanie i czas.
Jak daleko od siebie leżą powiązane elementy. To samo powiązanie w jednej klasie jest nieszkodliwe, a między kontekstami bywa zabójcze.
Ile miejsc trzeba ruszyć naraz. Dwa wywołania to drobiazg, czterdzieści to projekt.
Reguła praktyczna: im dalej od siebie, tym słabsza connascence powinna je łączyć.
Metryki Roberta C. Martina, opisane w OO Design Quality Metrics z 1994 roku, a potem w Agile Software Development i Clean Architecture. Powstały dla pakietów w kodzie. Na mapie kontekstów działają tak samo.
Strzałka przestaje być jedna. Zaczynasz widzieć, co dokładnie przez nią przechodzi i co pęknie przy zmianie.
Legal -> Availability {
type customer-supplier
upstream OHS
downstream ACL
integration "DNS + PL"
coupling 2
connascence meaning distant 3
}
Joachim ma teraz mapę. Wraca na kanał, na którym od poniedziałku czekają trzy pytania. A Kasia właśnie dopisała czwarte.
@Kasia rabaty liczymy my. To język koszyka i to my płacimy za pomyłkę w cenie. Billing dostaje gotową kwotę.
@Robert Ania idzie na cennik. To core, tam firma zarabia. Powiadomienia wystarczy kupić.
@Marta Orders czeka na przelew tyle, ile obiecał Payments, a nie 15 minut. A magazyn dostaje od nas opublikowany format, więc płatności wdrażamy osobno.
@Joachim super. A program lojalnościowy dorzucimy do zamówień? Biznes chce na poniedziałek.
Nie tutaj. Loyalty to osobny kontekst. Orders nie będzie obiecywał punktów, nad którymi nie ma kontroli.
Dopóki tylko opisuje stan zastany, jest kosztem. Od momentu, w którym pomaga powiedzieć „nie tutaj”, jest narzędziem.
Trzy kroki na diagramie, który już macie. Godzina pracy i macie pierwszą mapę, która na coś odpowiada.
Przy każdym pudełku wypiszcie trzy pytania, na które odpowiada. Dwa pudełka z tym samym pytaniem to kandydaci na złą granicę.
Dopiszcie core, supporting albo generic. Porównajcie z tym, gdzie dziś siedzą Wasi najlepsi ludzie.
Przy każdej strzałce zapiszcie, co jedna strona obiecuje drugiej i na jakich warunkach. Strzałka bez obietnicy to założenie.
Connascence zostawcie na drugi tydzień. Najpierw niech mapa odpowie na te trzy rzeczy.
Kamil Kiełbasa
Slajdy i materiały
do mapowania kontekstów.