معماری Domain Driven Design چیست و چه کاربردی دارد؟ + مثال عملی DDD

سلام من حسام رسولیان هستم و با یک مقاله دیگه در زمینه برنامه نویسی و مهندسی کامپیوتر در خدمت شما هستم.

معماری DDD یا Domain-Driven Design (طراحی دامنه محور) یک متودولوژی طراحی نرم‌افزار است که توسط اریک اِوَن‌س (Eric Evans) در کتابی با همین نام معرفی شده است.

DDD با تأکید بر درک بهتر دامنه‌ی کاربردی نرم‌افزار و انعکاس آن در طراحی، بهبود فهم مشترک بین توسعه‌دهندگان و کارفرماها را هدف قرار می‌دهد.

در این مقاله به شکل ساده و ابتدایی با این معماری آشنا خواهیم شد.

اگر در زمینه برنامه نویسی وب طراحی اپلیکیشن , هوش مصنوعی و یا بخش دیگری از مهندسی کامپیوتر فعالیت میکنید این پست را از دست ندهید.

تاریخچه پیدایش معماری DDD

تاریخچه اولیه Domain-Driven Design (DDD) به زمانی برمی‌گردد که اریک اِوَن‌س (Eric Evans)، که در آن زمان به عنوان مشاور فنی در پروژه‌های توسعه نرم‌افزار فعالیت می‌کرد، این متودولوژی را ارائه داد.

او ابتدا تجربه‌ها و دیدگاه‌های خود را در مدل‌سازی دامنه‌های پیچیده که در آن زمان به صورت غیرساختاری و تصادفی انجام می‌شد، جمع‌آوری کرد.

پیدایش Domain Driven Design به علت مشکلاتی بود که در پروژه‌های نرم‌افزاری پیچیده رخ می‌داد.

در این پروژه‌ها، مدل‌ها به دلیل پیچیدگی‌ها و ابهام‌های دامنه، تراکنش‌های بزرگ و تغییرات پیچیده مورد نیاز بود. همچنین، تیم‌های توسعه‌دهنده و متخصصان دامنه به دلیل زبان‌های مختلفی که در ارتباط با دامنه‌ها استفاده می‌کردند، با مشکلات هم‌صدا شدن مواجه بودند.

اونز برای حل این مشکلات و بهبود فرآیند توسعه نرم‌افزارها، معماری نرم افزار DDD را ارائه کرد.

اصلی‌ترین هدف این رویکرد، ایجاد یک مدل غنی و قابل درک از دامنه‌های کاربردی بود تا مفاهیم دامنه‌ای به خوبی در مدل‌های نرم‌افزاری نمایش داده شود و بازیابی بهتر اطلاعات و یکپارچگی بیشتر در سیستم ایجاد شود.

DDD با تأکید بر استفاده از زبان مشترک (یوبیکیتی) بین متخصصان دامنه و توسعه‌دهندگان، تحلیل دامنه (Domain Analysis)، تقسیم بندی محدوده‌ای از دامنه‌ها (محدوده‌بندی) و مدل‌سازی غنی، بهبود در فهم و انعکاس صحیح دامنه‌ها در طراحی نرم‌افزارها را فراهم می‌آورد.

این رویکرد به خوبی برای پروژه‌های پیچیده و با دامنه‌های کاربردی مشخص کارآمد است و به تیم‌های توسعه‌دهنده و متخصصان دامنه کمک می‌کند با یکدیگر در یک زبان مشترک و تفاهم انطباق پیدا کنند.

نحوه کار DDD چگونه است؟

دامنه‌محوری یا Domain-Driven Design (DDD) یک رویکرد به طراحی نرم‌افزار است که متمرکز بر درک بهتر وضعیت‌ها و مسائل مربوط به مسئله‌ی خاص نرم‌افزاری می‌شود. اصطلاح “دامنه” به مجموعه‌ای از مفاهیم، قوانین و فرآیندها اطلاق می‌شود که به نرم‌افزار اهمیت می‌دهند.

در DDD، مراحل کلیدی طراحی به شکل زیر هستند:

تحلیل دامنه (Domain Analysis)

بخش تحلیل دامنه (Domain Analysis) یکی از مراحل کلیدی در متودولوژی Domain-Driven Design (DDD) است که هدف اصلی آن فهم بهتر وضعیت‌ها و مسائل مرتبط با دامنه‌ی کاربردی نرم‌افزاری است.

در این مرحله، توسعه‌دهندگان و متخصصان دامنه با همکاری و تعامل با یکدیگر، مفاهیم و قوانین مربوط به دامنه‌ی کاربردی را شناسایی و به صورت دقیق‌تری درک می‌کنند.

بررسی تفاوت های زبان جاوا و کاتلین, انتخاب زبان برنامه نویسی مناسب

برخی اصول و مفاهیم کلیدی بخش تحلیل دامنه عبارت‌اند از:

  1. همکاری توسعه‌دهندگان و متخصصان دامنه (Collaboration): توسعه‌دهندگان و متخصصان دامنه با همکاری و تعامل با یکدیگر، مفاهیم و فرآیندهای مربوط به دامنه‌ی کاربردی را مطالعه و تحلیل می‌کنند. همکاری میان این دو گروه از کلیدی‌ترین عوامل موفقیت بخش تحلیل دامنه است.
  2. شناخت مفاهیم دامنه‌ای (Understanding Domain Concepts): در این مرحله، مفاهیم مهم و کلیدی دامنه‌ی کاربردی شناسایی می‌شوند و به گونه‌ای توصیف می‌شوند که همه اعضای تیم (از توسعه‌دهندگان تا کاربران نهایی) بتوانند به طور واضح و بدون ابهام به آن‌ها پی ببرند. این اصول هم‌فهمی را در مدل‌ها، کد نویسی و مستندات نمایش می‌دهند.
  3. استفاده از یوبیکیتی (Ubiquitous Language): استفاده از زبان مشترک یا یوبیکیتی در ارتباطات بین توسعه‌دهندگان و متخصصان دامنه بسیار مهم است. این زبان مشترک باید قابل درک و قابل اطمینان برای همه باشد و به کاهش ابهامات و اشتباهات در تفاهم مفاهیم کمک می‌کند.
  4. مدل‌سازی دامنه‌ها (Modeling Domain Concepts): در این مرحله، مدل‌های غنی‌تری از دامنه‌های کاربردی ساخته می‌شود. این مدل‌ها حاوی منطق تجاری مهمی هستند و به صورت شی‌گرا پیاده‌سازی می‌شوند.
  5. تفکر مفهوم‌محور (Conceptual Thinking): توسعه‌دهندگان در این مرحله باید به صورت مفهوم‌محور (conceptual thinking) به مدل‌سازی دامنه‌ها بپردازند و تمرکز خود را بر روی اصول و مفاهیم دامنه‌ای تمرکز دهند.

بخش تحلیل دامنه با همکاری توسعه‌دهندگان و متخصصان دامنه به کاهش ابهامات در دامنه‌ها و ایجاد یک مدل غنی و قابل درک از دامنه‌های کاربردی نرم‌افزاری منجر می‌شود. این مرحله بهبود در فهم مشترک بین توسعه‌دهندگان و متخصصان دامنه را فراهم می‌کند و به تیم‌ها کمک می‌کند با تمامی زبان مشترک در طراحی و پیاده‌سازی نرم‌افزارها همخوانی داشته باشند.

یوبیکیتی (Ubiquitous Language)

یوبیکیتی (Ubiquitous Language) اصطلاحی است که در راستای تحلیل دامنه و ایجاد ارتباط بهتر بین توسعه‌دهندگان، طراحان، متخصصان دامنه و کاربران نهایی در متودولوژی Domain-Driven Design (DDD) استفاده می‌شود.

اصول ویژه‌ی یوبیکیتی عبارت‌اند از:

  1. زبان مشترک (Shared Language): همه اعضای تیم (از جمله برنامه‌نویسان، طراحان و متخصصان دامنه) از یک زبان مشترک برای توصیف مفاهیم و فرآیندهای مربوط به دامنه‌ی کاربردی استفاده می‌کنند. این زبان مشترک باید قابل درک و قابل اطمینان برای همه باشد.
  2. ترجمه‌ی مستقیم (Direct Translation): مفاهیم دامنه‌ای که توسط متخصصان دامنه شناسایی شده‌اند، بدون ایجاد ابهامات و دخل و تصرف توسط برنامه‌نویسان، به شکل یک به یک و با ترجمه‌ی مستقیم در مدل‌ها و کد نرم‌افزاری نمایش داده می‌شوند.
  3. هم‌فهمی (Clear Understanding): توصیف مفاهیم دامنه‌ای باید به گونه‌ای باشد که همه اعضای تیم (از توسعه‌دهندگان تا کاربران نهایی) بتوانند به طور واضح و بدون ابهام به آن پی ببرند. این هم‌فهمی در مدل‌ها، کدنویسی و مستندات نمایش داده می‌شود.

تأکید بر یوبیکیتی در DDD به دلیل مهم بودن ارتباط و هم‌فهمی بین توسعه‌دهندگان و متخصصان دامنه است.
با استفاده از زبان مشترک، اشتباهات در تفاهم مفاهیم دامنه‌ای کاهش می‌یابد و تیم‌ها بهبود یافته در هم‌صدا شدن و تعامل با یکدیگر دارند.
این اصول کمک می‌کنند تا مفاهیم دامنه به صورت دقیق‌تر و قابل‌فهم‌تری در مدل‌های نرم‌افزاری نمایش داده شوند و همچنین برای استفاده‌ی بهتر از تجربه‌ی کاربری و اهداف کسب‌وکار نهایی تاثیرگذار باشند.

مدل‌سازی غنی (Rich Domain Model)

بخش مدل‌سازی غنی (Rich Domain Model) در متودولوژی Domain-Driven Design (DDD)، یکی از اصول اساسی و کلیدی است که هدف آن ایجاد یک مدل غنی‌تر و قابل درک‌تر از دامنه‌های کاربردی نرم‌افزاری است. این مدل‌ها حاوی منطق تجاری مهمی هستند و به صورت شی‌گرا پیاده‌سازی می‌شوند.

توضیح مدل‌سازی غنی به شکل زیر است:

  1. تعریف مفاهیم دامنه‌ای: در این مرحله، مفاهیم مهم و اصلی مرتبط با دامنه‌های کاربردی نرم‌افزاری شناسایی می‌شوند و به طور دقیق و کامل توصیف می‌شوند. این مفاهیم می‌توانند اشیاءی مثل محصول، سفارش، کاربر و … باشند.
  2. تبیین قوانین و منطق تجاری: در این مرحله، قوانین و منطق تجاری که مرتبط با دامنه‌های کاربردی هستند، به صورت دقیق‌تری توضیح داده می‌شوند. این قوانین ممکن است شامل محدودیت‌ها، رفتارها، محاسبات و سایر منطق‌های کسب‌وکاری باشند.
  3. طراحی کلاس‌ها و ارتباطات: با توجه به مفاهیم و منطق تجاری شناسایی‌شده، کلاس‌های غنی‌تری از دید برنامه‌نویسی و شی‌گرایی طراحی می‌شوند. این کلاس‌ها حاوی مفاهیم دامنه‌ای و منطق تجاری هستند و تعاملاتی که بین آنها صورت می‌گیرد نیز مشخص می‌شود.
  4. استفاده از زبان مشترک (یوبیکیتی): در مدل‌های غنی، از زبان مشترک یا یوبیکیتی استفاده می‌شود که به توسعه‌دهندگان، طراحان، متخصصان دامنه و کاربران نهایی کمک می‌کند با مفاهیم دامنه‌ای درک بهتری داشته باشند و بازیابی اطلاعات و تبادل اطلاعات با یکدیگر راحت‌تر باشد.
  5. جداکنندگی بین لایه‌ها: مدل‌های غنی باید جدا از لایه‌های دیگر سیستم مثل لایه‌های ذخیره‌سازی داده (Repository)، لایه‌های واسط کاربری (UI) و سایر لایه‌ها باشند. این جداکنندگی به تست‌پذیری بیشتر و انعطاف‌پذیری نرم‌افزار کمک می‌کند.

آموزش تعریف متغیر در زبان برنامه نویسی کاتلین

محدوده‌بندی (Bounded Contexts)

محدوده‌بندی (Bounded Contexts) یکی از مفاهیم مهم در متودولوژی Domain-Driven Design (DDD) است که به تقسیم بندی دامنه‌های کاربردی نرم‌افزار به بخش‌های کوچک‌تر و محدودتر کمک می‌کند. هدف اصلی این مفهوم، مسئولیت‌ها و قوانین مربوط به هر بخش از دامنه‌ها را جدا و محدود کردن است.

توضیح محدوده‌بندی به شکل زیر است:

  1. تقسیم بندی منطقی دامنه: برای پروژه‌های نرم‌افزاری پیچیده، ممکن است دامنه‌های کاربردی بسیار گسترده و پیچیده باشند. این دامنه‌ها می‌توانند شامل انواع مختلفی از مفاهیم، قوانین و فرآیندها باشند. محدوده‌بندی به تقسیم بندی این دامنه‌ها به بخش‌های کوچکتر و منطقی کمک می‌کند.
  2. جداکنندگی مسئولیت‌ها: هر بخش از دامنه‌ها (یا همان محدوده‌ها) مسئولیت‌ها و قوانین مخصوص به خود را دارد و با بخش‌های دیگر دامنه تمامی مفاهیم و قوانین را به اشتراک نمی‌گذارد. این جداکنندگی کمک می‌کند تا هر بخش به صورت مستقل و متمرکز بر مسئولیت‌های خود عمل کند.
  3. استفاده از زبان مشترک در هر محدوده: در هر محدوده‌بندی، از یک زبان مشترک یا یوبیکیتی استفاده می‌شود که به اعضای تیم در آن محدوده کمک می‌کند با هم کلمات و مفاهیم مشترک را درک کنند و از ابهامات در ارتباط با دامنه‌ها جلوگیری شود.
  4. تعامل با بخش‌های دیگر: در متودولوژی DDD، ممکن است یک محدوده به بخش‌های دیگر نیاز داشته باشد. در این حالت، از مفاهیم آگریگیت‌ها (Aggregates) و سرویس‌های دامنه‌ای (Domain Services) برای تعامل با بخش‌های دیگر استفاده می‌شود.

محدوده‌بندی به تیم‌های توسعه‌دهنده و متخصصان دامنه کمک می‌کند تا کاربردها و مسئولیت‌ها را در سیستم به بهترین شکل ممکن تقسیم بندی کنند و با این تقسیم‌بندی، هر بخش می‌تواند به صورت مستقل اداره شود. این اصل به استفاده‌ی بهتر و منطقی‌تر از منابع توسعه و انجام کارها منجر می‌شود و به هماهنگی و تفاهم بهتر بین تیم‌ها کمک می‌کند.

آگریگیت‌ها (Aggregates)

آگریگیت‌ها (Aggregates) نیز یکی از مفاهیم کلیدی در متودولوژی Domain-Driven Design (DDD) هستند که به سازماندهی و گروه‌بندی مفاهیم و اجزای مرتبط با دامنه‌های کاربردی نرم‌افزاری کمک می‌کنند.
هدف اصلی استفاده از آگریگیت‌ها، مدیریت ارتباطات و انجام عملیات‌ها بین مفاهیم و اجزا را به صورت اتمیک و یکپارچه مدیریت کنند.

توضیح آگریگیت‌ها به شکل زیر است:

  1. گروه‌بندی مفاهیم مرتبط: آگریگیت‌ها به مفاهیم و اجزا مرتبط در دامنه‌های کاربردی نرم‌افزاری گروه‌بندی می‌شوند. این گروه‌بندی بر اساس وابستگی‌ها و ارتباطات بین اجزا انجام می‌شود تا مفاهیم مرتبط با یکدیگر در یک واحد متمرکز شوند.
  2. ریشه آگریگیت (Aggregate Root): هر آگریگیت یک ریشه دارد که به عنوان نقطه شروع برای دسترسی به سایر اجزا درون آن استفاده می‌شود. ریشه آگریگیت همچنین مسئولیت انجام عملیات‌های اتمیک و یکپارچه در داخل آگریگیت را دارد.
  3. جداکنندگی آگریگیت‌ها: آگریگیت‌ها از یکدیگر جدا بوده و تعاملات بین آنها از طریق ریشه‌هایشان انجام می‌شود. این جداکنندگی کمک می‌کند تا هر آگریگیت به صورت مستقل از دیگر آگریگیت‌ها عمل کند و به طور موثرتری در کنار محدوده‌بندی‌ها و تقسیم‌بندی‌های مختلف دامنه‌ها قرار بگیرد.
  4. حفظ انسجام و همگرایی: آگریگیت‌ها اجزای مرتبط را درون خود جمع‌آوری می‌کنند و به این ترتیب، انسجام و همگرایی مفاهیم مرتبط را حفظ می‌کنند.
    این اصول باعث می‌شوند هر آگریگیت به عنوان یک واحد منطقی عمل کند و بتواند عملیات‌ها و تغییرات را به صورت اتمیک انجام دهد.
  5. ساده‌سازی ارتباط با سایر اجزا: تعاملات بین مفاهیم و اجزا در داخل یک آگریگیت ساده‌تر و شفاف‌تر است. این اصل باعث می‌شود که بخش‌های مختلف نرم‌افزار به راحتی با یکدیگر همکاری کنند و پیچیدگی‌های غیرضروری کاهش یابد.

استفاده از آگریگیت‌ها در DDD، به تیم‌های توسعه‌دهنده کمک می‌کند تا منطق تجاری را بهتر سازماندهی کنند و با دقت و کارآیی بیشتر عملیات‌ها را انجام دهند. همچنین، این مفهوم به مدیریت پیچیدگی‌ها و تفاوت‌های دامنه‌ها کمک می‌کند و بهبود در ارتباط و هماهنگی میان اجزا کمک میکند.

مستعارهای دامنه‌ای (Domain Aliases)

مستعارهای دامنه‌ای (Domain Aliases) در متودولوژی Domain-Driven Design (DDD) به تکنیک‌هایی اطلاق می‌شود که برای ایجاد نقشه‌برداری میان مدل‌های غنی‌تر دامنه‌های کاربردی و مدل‌های ساده‌تر یا DTO‌ها (Data Transfer Objects) استفاده می‌شود.
هدف اصلی استفاده از مستعارهای دامنه‌ای، مدیریت انتقال داده‌ها بین لایه‌ها و اجتناب از نمونه‌های غیرضروری مدل‌ها در سطوح مختلف است.

توضیح مستعارهای دامنه‌ای به شکل زیر است:

  1. جداکنندگی لایه‌ها: استفاده از مستعارهای دامنه‌ای کمک می‌کند تا لایه‌های مختلف نرم‌افزار (مانند لایه‌های سرویس، لایه‌های دسترسی به داده، لایه‌های واسط کاربری و …) به صورت مستقل از هم عمل کنند.
    این جداکنندگی کمک می‌کند تا تغییرات در یک لایه تأثیری بر لایه‌های دیگر نداشته باشد.
  2. انتقال داده‌ها بین لایه‌ها: مدل‌های غنی‌تر دامنه‌های کاربردی معمولاً شامل منطق و قوانین تجاری هستند و به عنوان نقطه مرجع برای انجام عملیات‌ها به صورت اتمیک عمل می‌کنند.
    اما در مواجهه با لایه‌های دیگر مثل لایه‌های واسط کاربری، این مدل‌ها ممکن است پیچیده و غیرقابل استفاده باشند.
    به همین دلیل، از مستعارهای دامنه‌ای استفاده می‌شود تا داده‌ها به صورت مناسب و ساده‌تر از مدل‌های غنی‌تر دامنه‌ها به سایر لایه‌ها منتقل شوند.
  3. ساده‌سازی واسط‌ها: استفاده از مستعارهای دامنه‌ای باعث می‌شود که واسط‌ها (مثل API‌ها و سرویس‌ها) با داده‌ها به صورت ساده‌تر و با کمترین پیچیدگی مواجه شوند. این کار باعث افزایش کارآیی و کاهش تأثیر تغییرات در دامنه‌ها بر روی واسط‌ها می‌شود.
  4. حفظ انسجام در دامنه‌ها: با استفاده از مستعارهای دامنه‌ای، انسجام مفاهیم و قوانین دامنه‌ها حفظ می‌شود و اطلاعات به صورت منطقی بر اساس نیازهای هر لایه‌ی نرم‌افزار منتقل می‌شود.

به طور کلی، مستعارهای دامنه‌ای کمک می‌کنند تا نقشه‌برداری و تعامل داده‌ها بین لایه‌ها به بهترین شکل انجام شود و پیچیدگی‌ها و تأثیرات نامطلوب برنامه را در نرم‌افزار کاهش دهند.
این اصول باعث می‌شوند که کد نرم‌افزار شفاف‌تر و قابل‌تعامل‌تر باشد و تغییرات در سطوح مختلف سیستم به بهترین شکل مدیریت شوند.

پیاده سازی عملی DDD به زبان پایتون

به عنوان مثال عملی از کل معماری Domain Driven Design در زبان برنامه‌نویسی پایتون، فرض کنید که شما یک سیستم مدیریت محصولات (Product Management System) را پیاده‌سازی می‌کنید.

در این مثال، به برخی اصول DDD اشاره می‌کنیم که شامل ایجاد مدل‌های غنی‌تر دامنه، تعریف آگریگیت‌ها، استفاده از مستعارهای دامنه‌ای و جداکنندگی لایه‌ها می‌شود.

ابتدا مدل‌های غنی‌تر دامنه‌ها را تعریف می‌کنیم:

class Book:
    def __init__(self, book_id, title, authors):
        self.book_id = book_id
        self.title = title
        self.authors = authors





class Author:
    def __init__(self, author_id, name, biography):
        self.author_id = author_id
        self.name = name
        self.biography = biography




حالا به تعریف آگریگیت‌ها می‌پردازیم. آگریگیت “کتاب” شامل مدل کتاب و مدل نویسنده‌های آن خواهد بود و آگریگیت “نویسنده” نیز شامل مدل نویسنده و لیست کتاب‌های نوشته‌شده توسط او خواهد بود.

class BookAggregate:
    def __init__(self, book, authors):
        self.book = book
        self.authors = authors





class AuthorAggregate:
    def __init__(self, author, written_books):
        self.author = author
        self.written_books = written_books




حالا لایه‌ها را جدا می‌کنیم. در این مثال، از یک سرویس فیک به نام BookService برای ارتباط با لایه‌های دیگر استفاده می‌کنیم. شبیه‌سازی دیتابیس و لیست نمونه‌ها را انجام می‌دهیم.


class BookService:
    def get_book_by_id(self, book_id):

        book_data = {"book_id": 1, "title": "Book 1", "authors": ["Author 1", "Author 2"]}

        book = Book(book_data["book_id"], book_data["title"], book_data["authors"])
        authors = [Author(author_id, author_name, "") for author_id, author_name in enumerate(book_data["authors"], start=1)]
        return BookAggregate(book, authors)


book_service = BookService()

حالا می‌توانیم از آگریگیت‌ها و مدل‌های دامنه‌ای در لایه‌ی کنترلر استفاده کنیم:

from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/books/<int:book_id>', methods=['GET'])
def get_book(book_id):

    book_aggregate = book_service.get_book_by_id(book_id)
    
    book_dto = {
        "book_id": book_aggregate.book.book_id,
        "title": book_aggregate.book.title,
        "authors": [author.name for author in book_aggregate.authors]
    }
    
    return jsonify(book_dto)

if __name__ == '__main__':
    app.run(debug=True)

در این مثال، از آگریگیت‌ها و مدل‌های دامنه‌ای برای جداکنندگی لایه‌ها، ایجاد منطق تجاری مرتبط با هر آگریگیت و انتقال داده‌ها به صورت ساده‌تر به لایه‌های دیگر استفاده می‌شود.

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *