Návrh mikroslužby orientované na DDD

Tip

Tento obsah je výňatek z eBooku, architektury mikroslužeb .NET pro kontejnerizované aplikace .NET, které jsou k dispozici na .NET Docs nebo jako zdarma ke stažení PDF, které lze číst offline.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

Návrh řízený doménou (DDD) podporuje modelování na základě reality firmy, jak je relevantní pro vaše případy použití. V kontextu vytváření aplikací DDD hovoří o problémech jako doménách. Popisuje nezávislé oblasti problémů jako ohraničené kontexty (každý ohraničený kontext koreluje s mikroslužbou) a zdůrazňuje společný jazyk, který o těchto problémech mluví. Navrhuje také mnoho technických konceptů a vzorů, jako jsou doménové entity s bohatými modely (bez modelu anemic-domain), hodnotové objekty, agregace a pravidla agregace kořenové (nebo kořenové entity), která podporují interní implementaci. Tato část představuje návrh a implementaci těchto interních vzorů.

Někdy se tato technická pravidla a vzory DDD považují za překážky, které mají strmou křivku učení pro implementaci přístupů DDD. Důležitou součástí ale nejsou samotné vzory, ale uspořádání kódu tak, aby byl v souladu s obchodními problémy a používáním stejných obchodních podmínek (všudypřítomný jazyk). Přístupy DDD by se navíc měly použít jenom v případě, že implementujete složité mikroslužby s významnými obchodními pravidly. Jednodušší odpovědnosti, jako je služba CRUD, je možné spravovat pomocí jednodušších přístupů.

Kde nakreslit hranice je klíčovou úlohou při návrhu a definování mikroslužby. Vzory DDD vám pomůžou pochopit složitost domény. Pro doménový model pro každý ohraničený kontext identifikujete a definujete entity, objekty hodnot a agregace, které modelují vaši doménu. Vytvoříte a zpřesníte doménový model, který je obsažen v rámci hranice, která definuje váš kontext. A to je explicitní ve formě mikroslužby. Komponenty v těchto hranicích končí jako mikroslužby, i když v některých případech se bc nebo obchodní mikroslužby můžou skládat z několika fyzických služeb. DDD se týká hranic, a proto jsou mikroslužby.

Zachování hranic kontextu mikroslužeb relativně malé

Určení umístění hranic mezi ohraničenými kontexty vyrovnává dva konkurenční cíle. Nejprve chcete nejprve vytvořit nejmenší možné mikroslužby, i když by to nemělo být hlavním faktorem; měli byste vytvořit hranici pro věci, které potřebují soudržnost. Zadruhé, chcete se vyhnout chatty komunikaci mezi mikroslužbami. Tyto cíle mohou být vzájemně v rozporu. Měli byste je vyvážit tak, že systém rozdělíte do tolik malých mikroslužeb, kolik jich můžete dosáhnout, dokud neuvidíte, že se hranice komunikace rychle rozrůstají s každým dalším pokusem o oddělení nového vázaného kontextu. Soudržnost je klíčem v rámci jednoho vázaného kontextu.

Při implementaci tříd se podobá zápachu nevhodného kódu intimacy. Pokud dvě mikroslužby potřebují spolupracovat hodně s ostatními, měly by být pravděpodobně stejné mikroslužby.

Dalším způsobem, jak se podívat na tento aspekt, je autonomie. Pokud mikroslužba musí k přímému poskytování žádosti spoléhat na jinou službu, není skutečně autonomní.

Vrstvy v mikroslužbách DDD

Většina podnikových aplikací s významnou obchodní a technickou složitostí je definována několika vrstvami. Vrstvy jsou logickým artefaktem a nesouvisejí s nasazením služby. Existují, aby vývojářům pomohli spravovat složitost kódu. Různé vrstvy (například vrstva doménového modelu a prezentační vrstva atd.) můžou mít různé typy, které mezi těmito typy vyžadují překlady.

Entita může být například načtena z databáze. Potom lze část těchto informací nebo agregaci informací včetně dalších dat z jiných entit odeslat do uživatelského rozhraní klienta prostřednictvím webového rozhraní REST API. Tady je bod, že entita domény je obsažena ve vrstvě doménového modelu a neměla by být šířena do dalších oblastí, do kterých nepatří, jako je prezentační vrstva.

Kromě toho musíte mít vždy platné entity (viz ověření návrhu v oddílu vrstvy doménového modelu) řízené agregovanými kořeny (kořenovými entitami). Entity by proto neměly být vázány na zobrazení klienta, protože na úrovni uživatelského rozhraní nemusí být některá data stále ověřena. Z tohoto důvodu je model ViewModel určený. Model ViewModel je datový model výhradně pro potřeby prezentační vrstvy. Entity domény nepatří přímo do modelu ViewModel. Místo toho je potřeba přeložit mezi modely ViewModels a entitami domény a naopak.

Při řešení složitosti je důležité mít doménový model řízený agregačními kořeny, které zajišťují, že všechny invarianty a pravidla související s danou skupinou entit (agregace) se provádějí prostřednictvím jediného vstupního bodu nebo brány, agregovaného kořene.

Obrázek 7-5 ukazuje, jak se v aplikaci eShopOnContainers implementuje vrstvený návrh.

Diagram showing the layers in a domain-driven design microservice.

Obrázek 7–5 Vrstvy DDD v objednávání mikroslužeb v eShopOnContainers

Tři vrstvy v mikroslužbě DDD, jako je Ordering. Každá vrstva je projekt VS: Aplikační vrstva je Ordering.API, Doménová vrstva je Ordering.Domain a vrstva infrastruktury je Ordering.Infrastructure. Chcete navrhnout systém tak, aby každá vrstva komunikuje pouze s některými dalšími vrstvami. Tento přístup může být jednodušší vynutit, pokud jsou vrstvy implementovány jako různé knihovny tříd, protože můžete jasně identifikovat, jaké závislosti jsou nastaveny mezi knihovnami. Například vrstva doménového modelu by neměla brát závislost na žádné jiné vrstvě (třídy doménového modelu by měly být prosté staré třídy nebo POCO, třídy). Jak je znázorněno na obrázku 7–6, knihovna vrstvy Ordering.Domain má závislosti pouze na knihovnách .NET nebo balíčcích NuGet, ale ne v žádné jiné vlastní knihovně, například knihovně dat nebo knihovně trvalosti.

Screenshot of Ordering.Domain dependencies.

Obrázek 7–6 Vrstvy implementované jako knihovny umožňují lepší kontrolu nad závislostmi mezi vrstvami.

Vrstva doménového modelu

Eric Evans je vynikající kniha Domain Driven Design říká následující informace o vrstvě doménového modelu a aplikační vrstvě.

Vrstva doménového modelu: Zodpovídá za reprezentaci konceptů firmy, informací o obchodní situaci a obchodních pravidlech. Stav, který odráží obchodní situaci, je zde řízen a používán, i když technické podrobnosti o uložení jsou delegovány do infrastruktury. Tato vrstva je jádrem obchodního softwaru.

Vrstva doménového modelu je místo, kde se firma vyjadřuje. Při implementaci vrstvy doménového modelu mikroslužby v .NET se tato vrstva zakóduje jako knihovna tříd s entitami domény, které zaznamenávají data plus chování (metody s logikou).

Tato vrstva musí zcela ignorovat podrobnosti trvalosti dat podle zásad trvalosti a infrastruktury. Tyto úlohy trvalosti by měly provádět vrstva infrastruktury. Proto by tato vrstva neměla přijímat přímé závislosti na infrastruktuře, což znamená, že důležitým pravidlem je, že třídy entit modelu domény by měly být objekty POCOs.

Entity domény by neměly mít žádnou přímou závislost (například odvozování ze základní třídy) v rámci infrastruktury přístupu k datům, jako je Entity Framework nebo NHibernate. V ideálním případě by se entity domény neměly odvozovat ani implementovat žádný typ definovaný v žádné infrastruktuře.

Většina moderních architektur ORM, jako je Entity Framework Core, umožňuje tento přístup, takže třídy doménového modelu nejsou propojené s infrastrukturou. Při používání určitých databází a architektur NoSQL, jako jsou Actors a Reliable Collections v Azure Service Fabric, ale entity POCO nemusí být vždy možné.

I v případě, že je důležité dodržovat zásadu trvalosti pro váš doménový model, byste neměli ignorovat obavy o trvalost. Stále je důležité porozumět fyzickému datovému modelu a způsobu, jakým se mapuje na model objektu entity. V opačném případě můžete vytvářet nemožné návrhy.

Tento aspekt také neznamená, že můžete použít model navržený pro relační databázi a přímo ho přesunout do noSQL nebo dokumentově orientované databáze. V některých modelech entit se model může vejít, ale obvykle ne. Stále existují omezení, která musí model entity dodržovat, a to jak na základě technologie úložiště, tak technologie ORM.

Aplikační vrstva

Přechod na aplikační vrstvu můžeme znovu citovat Eric Evansovu knihu Domain Driven Design:

Aplikační vrstva: Definuje úlohy, které má software provádět, a směruje objekty expresní domény, aby fungovaly problémy. Úlohy, za které tato vrstva odpovídá, jsou pro firmu smysluplné nebo nezbytné pro interakci s aplikačními vrstvami jiných systémů. Tato vrstva je štíhlá. Neobsahuje obchodní pravidla ani znalosti, ale koordinuje pouze úkoly a delegáty pracují na spolupráci s doménovými objekty v další vrstvě dolů. Nemá stav odrážející obchodní situaci, ale může mít stav, který odráží průběh úkolu pro uživatele nebo program.

Aplikační vrstva mikroslužeb v .NET se běžně kóduje jako projekt webového rozhraní API ASP.NET Core. Projekt implementuje interakci mikroslužby, vzdálený přístup k síti a externí webová rozhraní API používaná z uživatelského rozhraní nebo klientských aplikací. Zahrnuje dotazy, pokud používáte přístup CQRS, příkazy přijaté mikroslužbou a dokonce i komunikaci řízenou událostmi mezi mikroslužbami (události integrace). Rozhraní ASP.NET Core Web API, které představuje aplikační vrstvu, nesmí obsahovat obchodní pravidla ani znalosti domény (zejména pravidla domény pro transakce nebo aktualizace); ty by měly vlastnit knihovna tříd doménového modelu. Aplikační vrstva musí koordinovat pouze úlohy a nesmí obsahovat ani definovat žádný stav domény (doménový model). Deleguje provádění obchodních pravidel na samotné třídy doménového modelu (agregované kořeny a entity domény), které nakonec aktualizují data v rámci těchto entit domény.

Logika aplikace je v podstatě tam, kde implementujete všechny případy použití, které závisí na daném front-endu. Například implementace související se službou webového rozhraní API.

Cílem je, aby logika domény ve vrstvě doménového modelu, její invarianty, datový model a související obchodní pravidla byla zcela nezávislá na prezentační a aplikační vrstvě. Ve většině případů vrstva doménového modelu nesmí přímo záviset na žádné infrastruktuře.

Vrstva infrastruktury

Vrstva infrastruktury je způsob, jakým se data, která jsou původně uložená v entitách domény (v paměti), uchovávají v databázích nebo jiném trvalém úložišti. Příkladem je použití kódu Entity Framework Core k implementaci tříd vzoru úložiště, které používají DBContext k zachování dat v relační databázi.

V souladu s dříve zmíněnými principy persistence ainfrastruktury nesmí vrstva infrastruktury "kontaminovat" vrstvu doménového modelu. Třídy entit doménového modelu musíte ponechat nezávislé na infrastruktuře, kterou používáte k zachování dat (EF nebo jakékoli jiné architektury), a to tak, že nepřebírají pevné závislosti na architekturách. Knihovna tříd vrstvy doménového modelu by měla obsahovat pouze váš kód domény, pouze třídy entit POCO implementované srdce vašeho softwaru a zcela oddělené od technologií infrastruktury.

Vrstvy nebo knihovny tříd a projekty by tedy měly nakonec záviset na vrstvě vašeho doménového modelu (knihovně), ne naopak, jak je znázorněno na obrázku 7–7.

Diagram showing dependencies that exist between DDD service layers.

Obrázek 7–7 Závislosti mezi vrstvami v DDD

Závislosti ve službě DDD, aplikační vrstva závisí na doméně a infrastruktuře a infrastruktuře závisí na doméně, ale doména nezávisí na žádné vrstvě. Tento návrh vrstvy by měl být nezávislý pro každou mikroslužbu. Jak jsme si poznamenali dříve, můžete implementovat nejsložitější mikroslužby následující vzory DDD, zatímco jednodušší implementaci jednodušších mikroslužeb založených na datech (jednoduché CRUD v jedné vrstvě) jednodušším způsobem.

Další materiály