علاقمند به فناوری، استادیار دانشگاه شهید بهشتی و دانشآموخته دانشگاه تهران
طراحی مبتنی بر دامنه (DDD) راهکاری برای مقیاسپذیری در معماری مایکروسرویس
در دنیای امروز به دلیل گستردگی نیاز به سرویسهای مستقل و کارآمد، بسیاری از توسعهدهندگان نرمافزار بر روی توسعه مبتنی بر مایکروسرویس تمرکز میکنند. این توسعه، علاوه بر مستقلسازی و توسعه چابک سرویسها، قابلیت تنظیم میزان منابع و نمونههای مورد نیاز از آنها در زمان استقرار را نیز به مهندسین نرمافزار ارائه میدهد. اما سوال اساسی در توسعه مبتنی بر مایکروسرویس همواره این است که تا چه اندازه لازم است یک سرویس ریزدانه یا درشتدانه باشد. به بیان سادهتر، اندازه مایکروسرویسها چقدر باشند تا به قدرت توسعه و کارایی سرویس مناسب دست یابیم؟ یکی از راهکارهای حرفهای در جهت پاسخ به این نیاز، استفاده از مدل طراحی مبتنی بر دامنه (DDD) یا همان Domain-Driven Design است. DDD یک روش طراحی مشترک با افکار بیزنسی است که زبان مشترکی (Ubiquitous Language) بین لایههای مختلف کسبوکار و فنی ایجاد میکند. البته که DDD یک روش مهم در مهندسی نیازمندی و مدیریت فرآیندهای مهندسی نرمافزار به شمار میرود که در عین حال به طراحی هدفمند و منظم معماری مبتنی بر مایکروسرویسها نیز کمک میکند. در ادامه به تعریف و ساختار طراحی مبتنی بر دامنه میپردازیم. این مطلب در وبلاگ در روزهای آینده با موردهای مطالعاتی تطبیقی ادامه خواهد یافت.
دامنه چیست؟
در فرآیندهای مهندسی نرمافزار، دامنه به طور مستقیم و غیرمستقیم به بخشهای مختلف کسبوکار اشاره دارد. بخشهای منطقی کسبوکار در واقع دامنههایی هستند که منطق توسعه حول آن شکل میگیرد. طبق تعریف کلاسیک، دامنه مجموعهای از دانش، تاثیرهای مرتبط و فعالیتهاست که در راستای اهداف مشخصی در کنار یکدیگر قرار میگیرند. دامنههای اغلب در قالب سگمنتهای بیزنسی نمایش داده میشوند که قابلیت تفکر، توسعه و ارزیابی مستقل هر بخش به صورت جداگانه فراهم است هر چند ارتباطات بین دامنهها همچنان امکانپذیر باشد. به طور خلاصه، جامعه مهندسی نرمافزار با این تعریف بیشتر همراه هستند که دامنه آن بخش از بیزنس است که هدف برنامه تولیدی، ساختن آن است. اریک ایونز در کتاب معروف خود در خصوص طراحی مبتنی بر دامنه، دامنه را به شکل زیر تعریف میکند:
"A sphere of knowledge, influence, or activity. The subject area to which the user applies a program is the domain of the software."
همانطور که در شکل 1 نمایش داده شده، در ساختار چندلایه توسعه، دامنهها به عنوان قلب اصلی مهندسی نرمافزار در نظر گرفته میشوند. دامنه اصلی سیستم آن بخشی است که بیانگر هسته اصلی کسبوکار بوده و برنامه تولیدی، قرار است انعکاسدهنده آن باشد. بر اساس تصویر، برنامه کاربردی تولیدی روی دامنه شکل میگیرد و زیرساخت نیز متناسب با آن پیکربندی میشود. در نتیجه درک درست از دامنه بسیار مهم بوده و به همین جهت است که طراحی مبتنی بر دامنه در تعیین و تطبیق نیازهای کسبوکار و فنی موفق عمل خواهد کرد.
طراحی مبتنی بر دامنه
یک متدولوژی طراحی نرمافزار است که در آن مهندسین نرمافزار برای درک بهتر نیازمندیهای یک دامنه از کسبوکار، اقدام به مدلسازی آن دامنه میکنند. همانطور که در روشهای مرسوم مهندسی نرمافزار نیز دیدهایم، ابزارها و نمودارهای تحلیلی مبتنی بر UML نیز از روش مدلسازی تبعیت میکنند. همواره سعی بر آن است تا با مدلسازی از دنیای واقعی، به سطحی از انتزاع دست پیدا کنیم که قابلیت پیادهسازی بدون ابهام یا با حداقل ابهام ممکن را داشته باشد. DDD نیز از این قاعده مستثناء نیست و در تحلیل و توصیف دامنهها از یک مجموعه روشهای مدلسازی بهره میگیرد. در واقع وقتی که اطلاعات کافی از کسبوکار (دامنه) دریافت شد، نوبت به توسعه مدل DDD میرسد. در این بخش به اجزای اصلی این مدلسازی میپردازیم.
همانطور که در شکل 2 نمایش داده شده، هسته اصلی طراحی مبتنی بر دامنه، زبان مشترک است. زبان مشترک بر پایه اصطلاحات و دانش پایه کسبوکار (دامنه) تدوین میشود. بر این اساس که دامنه قابل توسعه مربوط به چه صنعت و کاربردی است، اصطلاحات و نیازمندیهای اولیه در قالب زبان مشترک گردآوری شده و توافقی اولیه بین تیمهای فنی و کسبوکار شکل میگیرد. افراد از جمله متخصص دامنه (Domain Expert)، تحلیلگر کسبوکار، مدیران محصول و توسعهدهندگان عضو تیم DDD خواهند بود. متخصص دامنه فردی است که بر ابعاد بیزنسی مورد مطالعه تسلط کافی دارد. برای مثال اگر دامنه مورد مطالعه یک دامنه فینتکی باشد، لازم است تا فرد انتخاب شده اطلاعات کافی در مورد صنعت فینتک را داشته باشد و بتواند در همه مسائل تخصصی کسبوکار اظهارنظر یا تحقیق نماید.
بخش مهمی از خروجیهای DDD، نیازمندیهای عملکردی و مشخصههای محصول نهایی است؛ آنچه که در شکل 2 با Functional Requirements نمایش داده شده است. دامنهها در جلسات تخصصی شناسایی شده و هر یک میتوانند دارای زیردامنه (Sub-Domain) باشند. در مدلسازی دامنهها/زیردامنهها لازم است تا عناصری مانند Bounded Context (BC) و Context Map مشخص شوند که در ادامه به جزئیات این عناصر و شیوه مدلسازی میپردازیم. علاوه بر آن، شیوه ارتباط بین این عناصر بیزنسی و نحوه نگاشت آنها به عناصر فنی باید مشخص شود. برنامهریزی توسعه محصول، تولید کد و مستندات فنی/تحلیلی مورد نیاز هم متناسب با خروجی DDD انجام میگیرد.
متون محدودشده (Bounded Context) و مدل نگاشت BCها
بسته به دامنه مورد استفاده، هر کدام از مفاهیم و کلمات میتوانند معنای خاص خود را داشته باشند. برای مثال یک سیستم فروشگاهی کتاب آنلاین را در نظر بگیرید که در آن یک عنصر به نام book وجود دارد. این مفهوم هم میتواند به معنای کتاب باشد و هم به معنای رزرو کردن. Bounded Context یا همان BC به مفاهیم و متون محدودشده اطلاق میگردد که به طور شفاف و بدون ابهام وظیفه تعریف مشخصی از مفاهیم کسبوکار را بر عهده دارند. در مثال فوق لازم است تا معنای دقیق book مشخص شده و به عنوان یک عنصر محدود شده از این پس در DDD مورد استفاده قرار گیرد. دلیل عمده استفاده از BCها در DDD این است که در مهندسی نرمافزار همه چیز باید دقیق باشد. علاوه بر رفع ابهام، در توسعه زبان مشترک بین توسعهدهندهها و متخصصین دامنه کمک میکند.
پس از تعیین BCها در یک دامنه، لازم است تا مسیر و نحوه ارتباطات بین آنها مشخص شود. نقشه ارتباط بین BCها که از آن به Context Map نیز یاد میشود، ارتباط بین BCها در داخل دامنه/زیردامنهها و بین دامنه/زیردامنهها را تعیین میکند. برای مثال اگر در دامنه کسبوکار تجارت الکترونیکی هستیم، فروشندهها لازم است تا پیش از فروش محصول، موجودی انبار خود را بررسی نمایند. به همین ترتیب، وقتی کالایی به فروش رسید، توسط واحد پستی باید به آدرس تعیینشده توسط مشتری، تحویل داده شود. همانطور که در شکل 3 نمایش داده شده، در DDD رابطه بین BCها در یک دامنه/زیردامنه با Context Map نمایش داده میشود.
الگوهای طراحی مبتنی بر دامنه: راهبردی و تاکتیکی
در DDD دو نوع الگوی طراحی وجود دارد که بسته به سطح بیزنسی و عمق فنی دامنه/زیردامنهها از آنها استفاده میشود. هدف الگوی راهبردی (Strategic) تعیین BCها و تولید Context Map است در حالی که الگوی طراحی تاکتیکی (Tactical) بر روی مدلسازی فنی هر یک از BCها بر اساس قواعد کسبوکار و زیردامنههای مرتبط تمرکز دارد. در ادامه علاوه بر بررسی هر یک از این دو فاز، به نقش تعیینکننده آنها در معماری سرویسهای مبتنی بر مایکروسرویس میپردازیم.
فاز راهبردی، با مشارکت افراد کسبوکار، فنی و محصول به صورت مشترک اجرا میشود. لازمه این همکاری، برگزاری جلسات طوفان رویداد (Event Storming) است. در این جلسات، مدلسازی بالا به پایین و راهبردی انجام میگیرد و نیازمندیهای کسبوکار بر اساس رویدادهای مهم دامنه به صورت دقیق تعیین میشود. انتظار میرود تا پس از برگزاری این جلسات، به لیست دقیقی از BCها برسیم. مراحل این فاز به این ترتیب است که ابتدا تحلیل دامنه کسبوکار به صورت کامل انجام میگیرد و همه اعضا از جزئیات کسبوکار مطلع میشوند. سپس BCها مشخص شده و از روی BCها و روابط بین آنها، نگاشتی به تعداد و کیفیت مایکروسرویسها مشخص میگردد. در واقع هر BC فرصتی برای پیادهسازی یک مایکروسرویس را منعکس میکند. پس از آن، نوبت به تعیین روابط بین BCها میرسد که بسته به نوع و کارایی آنها، میتوانیم انتخابهای متنوعی داشته باشیم از پروتکلهای باز گرفته تا محدود که انواع این روابط در این سند آنلاین قابل مشاهده است.
فاز تاکتیکی به تشریح فنی BCها میپردازد و مدلسازی تحلیلی/فنی در این بخش صورت میپذیرد. مهمترین عنصر در این مسیر، مدلسازی دقیقتر از فضای واقعی کسبوکار است. از آنجایی که مدلسازی خود مبنایی برای تولید کدهای متناظر است، لازم است تا این فرآیند با دقت بیشتری انجام شود. مدلسازیها فارغ از فناوری مورد استفاده در تولید محصول نرمافزاری خواهد بود. بدون توجه به استک و فناوریهای قابل استفاده، بیشتر روی مدلسازی زیردامنهها و تحلیل دقیقتر BCها تمرکز خواهیم داشت. هفت عنصر زیر به عنوان نقاط اساسی مدلسازی در این فاز قابل بیان هستند:
- موجودیتها (Entities): اشیائی هستند که دارای شناسه بوده و در طول زمان پایدار هستند. برای مثال یک سفارش خرید را در نظر بگیرید که دارای یک شناسه مشخص بوده و در طول زمان خرید تا تحویل، وجود دارد.
- اشیا دارای مقدار (Value Objects): مقادیر غیرقابل تغییر که اصول اولیه مدل مانند زمان، واحد پول و … را میسازند.
- مصالح (Aggregates): روابط بین موجودیتها و اشیا دارای مقدار را مشخص میکند. در واقع مجموعهای از اشیا را شامل میشود که میتوانند به عنوان یک واحد مشخص در نظر گرفته شده و در یک حالت مشخص باشند. برای مثال یک مشتری را در نظر بگیرید که صاحب یک کتاب است و سفارشی را نیز ثبت کرده است. در نتیجه همه این موارد میتوانند در یک Aggregate باشند.
- سرویسهای دامنه: یک مجموعه سرویس stateless بوده که بخشی از منطق یا عملکرد سیستم را پیادهسازی میکنند و میتواند دربرگیرنده چند موجودیت باشد.
- رویدادهای دامنه: آنچه که در معماری مایکروسرویس بیش از همه عناصر دیگر اهمیت پیدا میکند، رویدادهای دامنه هستند. باید مشخص شود تا در صورت رخداد یک رویداد، کدامیک از سرویسها باید مطلع شوند. برای مثال وقتی پرداخت سفارش خرید کاربر با موفقیت انجام شود، باید مشخص شود که این رویداد به چه سرویسها دیگری باید اطلاعرسانی شود.
- مخازن (Repositories): در اصل نگهدارنده پایداری برای Aggregateها به حساب میآیند که معمولا در فرم پایگاه دادهها ظاهر میشوند.
- کارخانهها (Factories): کارخانه مسئول تولید Aggregateهای جدید هستند.
اندازه مایکروسرویسها در DDD
سوال اساسی این است که در طراحی مبتنی بر دامنه، سایز مایکروسرویسها باید تا چه اندازه باشد. متر و معیار استانداردی که بر اساس تحقیقات علمی و تحلیل فنی ارائه شده، بر اساس شکل 5 است. در صورتی که تحلیل و مدلسازی DDD به درستی انجام شده باشد، بهتر است سایز یک مایکروسرویس از یک BC بزرگتر نباشد و از یک Aggregate نیز کوچکتر طراحی نشود. البته با توجه به بررسی بهترین الگوهای طراحی، BC اندازه مناسبی برای پیادهسازی مایکروسرویس در نظر گرفته شده است.
البته اکثر پروژههای نرمافزاری در ابتدا با ساختار Monolithic توسعه مییابند و در ادامه با توجه به کیفیت سرویسها، نیازمندیهای پروژه و بودجه، به سمت مایکروسرویسهای کارآمد تغییر مسیر میدهند. البته که این روند در شروع کار استارتاپها منطقی به نظر میرسد و در بسیاری از نمونههای داخلی و خارجی نیز موفقیتآمیز بوده است؛ اما اگر از پیش مسیر تحلیل و مدلسازی هموار باشد، استفاده از روش DDD، به سازماندهی بهتر و دقیقتر پروژههای نرمافزاری بزرگ منجر میشود. همانطور که در شکل 6 نمایش داده شده است، طراحی مبتنی بر DDD و مشخص کردن مایکروسرویسها، همانند ساخت یک شهر با برنامه از پیش تعیینشده است. وقتی برنامهریزی توسعه یک محصول نرمافزاری پیچیده در میان است، DDD یک متدولوژی هدفمند و کارا ارائه میدهد که تمامی تغییرات از این پس در ساختار آن جای میگیرد.
جمعبندی
در روش مبتی بر DDD، مایکروسرویسها و روابط بین آنها با الگوی طراحی راهبردی DDD قابل اجرا است و متعاقب آن، هر مایکروسرویس با استفاده از الگوی تاکتیکی DDD مدلسازی میشود. اینکه فناوری مورد استفاده در هر مایکروسرویس چه باشد و یا از چه روش توسعهای استفاده شود (مثلا BDD یا TDD)، در ساختار DDD به صورت صریح تعیین نمیگردد. از آنجایی که تیمهای توسعه در یک مایکروسرویس یا مجموعهای از آنها به صورت خودمختار عمل میکنند، میتوان فناوری و روشهای توسعه مستقلی را در هر مایکروسرویس متناسب با نیازهای دامنه به کار گرفت. همانطور که در این مقاله تشریح شد، استفاده از DDD در توسعه محصولهای نرمافزار بزرگ و پیچیده کمک شایانی میکند و علاوه بر مدیریت فرآیندهای مهندسی نرمافزار و توسعه هدفمند، به یکپارچگی دیدگاههای بین واحدهای فنی و کسبوکار میانجامد که نتیجهای از شکلگیری زبان مشترک بین افراد متخصص دامنه و توسعهدهندگان است.
سخن پایانی
قلب اصلی یک سیستم نرمافزاری در واقع توانایی حل مسائل مربوط به دامنهای از کسبوکار است که قرار است کاربر از آن بهره بگیرد. اریک ایونز در کتاب خود (رفرنس شماره 1) به این نکته اشاره دارد:
"The heart of software is its ability to solve domain-related problems for its user."
بازدید از ویدئوی مرتبط
پیش از این در رویداد کافه تکنولوژی، ارائهای در همین خصوص با جزئیات بیشتر و با شکلگیری مباحثی بین افراد متخصص توسط نویسنده انجام شده است. برای دیدن ویدئو، میتوانید از طریق لینک آپارات زیر اقدام نمایید:
https://www.aparat.com/v/VGuTK
منابع
[1] Eric Evan, "Domain-Driven Design: Tackling Complexity in the Heart of Software," Addison-Wesley Professional; 1st edition (August 20, 2003), 2003.
[2] Vladik Khononov, "What Is Domain-Driven Design?," O'Reilly Media, Inc., ISBN: 9781492057796, October 2019, Access via this link.
[3] Tomas Fernandez, "Domain-Driven Design Principles for Microservices," 8 Jul 2022, Access via this link.
[4] HiBit open articles, "Domain Driven Design: Layers," July 2021, Access via this link.
مطلبی دیگر از این انتشارات
معرفی نقش VP of Engineering و مقایسه آن با CTO در شرکتهای فناور
مطلبی دیگر از این انتشارات
مروری بر معماری Netflix
بر اساس علایق شما
کارما اومده یوهووو