شما اینجا هستید: خانه / مقالات آموزشی / چرا EF انتخاب خوبی برای پروژه های Domain-Driven نیست؟

چرا EF انتخاب خوبی برای پروژه های Domain-Driven نیست؟

Entity Framework یکی از محبوب ترین ORM های NET. می باشد که در سال ۲۰۰۸ توسط مایکروسافت به بازار عرضه شد. بسیاری از شرکت های ایرانی که تا قبل از آن از تکنولوژی های قدیمی تر (مانند Linq2Sql و Dataset و … ) و یا از ORM های دیگر (مانند NHibernate ) استفاده میکردند، به این تکنولوژی روی آوردند. همچنین در سال های اخیر شاهد فراگیرتر شدن رویکرد DDD و استفاده از آن در پروژه های Enterprise بوده ایم. بسیاری از شرکت ها از Entity Framework در پروژه های Domain-Driven خود نیز استفاده میکنند. در این مقاله قصد داریم تا به بررسی مشکلات EF و کمبود های آن برای پیاده سازی تکنیک های DDD بپردازیم.

نکته : در زمان نوشته شدن این مقاله، اخرین نسخه ی EntityFramework که بر روی سایت Nuget قراردارد، نسخه ی ۶٫۱٫۲ می باشد و ممکن است مشکلات زیر در نسخه های بعدی آن رفع شوند.

مشکل ۱ : عدم پشتیبانی کامل از Entity های Encapsulate شده

Encapsulate کردن کلاس های Domain در رویکرد DDD اهمیت بسیار زیادی دارد. با این روش می توانید Invariant ها را همیشه تحت کنترل داشته باشید و اشیاء را همیشه در حالت Valid نگه دارید. برای مثال :

متاسفانه Entity Framework قابلیت Map کردن فیلد های Private (اصطلاحا Backing-field) ها را ندارد. البته می توانید از Property های که set آنها به صورت private تعریف شده اند استفاده نمایید که EF از آنها پشتیبانی می کند :
اما مشکل کجاست؟

ممکن است استفاده از Property ها با Private set در سناریوهای ساده (مانند مثال بالا) بتواند مشکل شما را حل کند اما همچنان Encapsulate کردن Collection ها ممکن نیست. حتی اگر یک Collection را به صورت Private Set نیز تعریف نمایید، باز هم مشکل حل نخواهد شد. زیرا Collection از طریق متدهایی مانند Add, Remove و … قابل تغییر خواهد بود. تنها راه Encapsulate کردن کامل آنها استفاده از Collection های ReadOnly می باشد :

متاسفانه Map کردن کلاس فوق در Entity Framework امکان پذیر نمی باشد. هرچند راه حل هایی (۱ ۲ ۳) برای حل این مشکل ارائه شده اند اما هیچکدام راه حل مناسبی به نظر نمیرسد و ما را از اصل Persistence Ignorance دور میکند. این در حالی است که Map کردن کلاس فوق در NHibernate به راحتی امکان پذیر است.

مشکل ۲ : عدم پشتیبانی از Value Object ها

Value Object یکی از مفاهیمی است که در پیاده سازی Domain Model نقش اساسی دارد. Value Object ها فاقد Identity بوده و تنها توسط مقادیرشان شناخته می شوند. تنها راه حل ارائه شده توسط  EF برای Map کردن Value Object ها، Complex Type ها می باشد که با محدودیت های بسیار جدی روبرو است.  به مثال ساده زیر توجه کنید :

order-orderItem

در مثال فوق OrderItem ماهیت Value Object دارد و کاملا وابسته به Order می باشد. Map کردن کلاس فوق با Complex Type ها امکان پذیر نیست زیرا در EF امکان تعریف لیستی از Complex Type ها وجود ندارد.

به همین دلیل بسیاری از برنامه نویسان ValueObject ها را Immutable تعریف کرده ولی آنها را مانند دیگر Entity ها Map میکنند :

اما روش فوق مشکلات فراوانی دارد. اصلی ترین مشکل آن عدم کنترل چرخه حیات Value Object ها در Entity مربوط به آن است :

در صورتی که اقدام به ذخیره ی Order مورد نظر کنید، خطای زیر را دریافت میکنید :

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable

هر چند راه حل هایی برای مشکل فوق عنوان شده است اما هیچکدام مناسب نمی باشند و اغلب نیازمند Reference دادن به EF در لایه ی Domain می باشد.

 

مشکل کار با Value Object ها فقط به کار با لیست ها ختم نمی شود. EF راه حلی برای Map کردن مقادیر دیتابیس به Value Object های پیچیده را نیز ندارد. برای مثال فرض کنید شماره تماس افراد را در قالب یک رشته در دیتابیس ذخیره میکنید :

home=99669966;office=11223;mobile=0912111

ولی در Domain Model کلاسی مانند کلاس زیر برای آن تعریف کرده اید :

Map کردن کلاس فوق به صورت معمولی در EF امکان پذیر نیست و باید از روشی مانند روش فوق استفاده نمایید.

 

  • نتیجه گیری

به علت وجود دو مشکل فوق، استفاده از Entity Framework در پروژه های مبتنی بر DDD، ساخت Domain Model غنی و اصولی را محدود و مشکل (و حتی ناممکن) میکند. این در حالی است که هیچکدام از مشکلات عنوان شده، در NHibernate مشاهده نمی شوند. Entity Framework را می توان به عنوان بهترین ابزار برای پروژه های Data-Driven در نظر گرفت (به علت سادگی، بازدهی بهتر و …) اما استفاده از آن در پروژه های Enterprise که اغلب با رویکرد DDD طراحی شده و نیاز به Domain Model های غنی دارند، پیشنهاد نمی شود. در مقابل می توان NHibernate را بهترین گزینه برای پروژه های Domain-Driven دانست.

درباره هادی احمدی

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

20 نظر

    • هادی احمدی

      بله مطلب جالبی است
      البته بنده با نویسنده ی مطلب فوق در برخی موارد موافق نیستم. مثل موردی که با اسم Case #2 در مقاله مشخص شده. چون در EF بدون قراردادن کلید خارجی روی Entity هم میتوان Relation برقرار کرد.

  1. در اين مطلب سعي شده متدهاي Add و Remove به داخل كلاس‌هاي entity منتقل بشن. به اين روش اصطلاحا active recored‌ مي‌گن. اين روش مشكلات خاص خودش رو داره:
    http://www.mehdi-khalili.com/orm-anti-patterns-part-1-active-record

    • هادی احمدی

      سلام
      خیر دوست عزیز، روش استفاده شده ActiveRecord نیست. در این مثال چون Order و OrderItem در یک Aggregate قراردارند و Order به عنوان AggregateRoot مشخص شده است و مسئولیت چک کردن Invariant ها را برعهده دارد، لذا از ایجاد و حذف مستقیم OrderItem جلوگیری شده و به جای آن از متد های Add و Remove بر روی Entity استفاده شده است. اینجا بحث Object مطرح هست و نه دیتابیس. برخلاف ActiveRecord که بر روی متد Add، شی را در دیتابیس Insert میکند، اینجا OrderItem تنها به شیء Order اضافه شده است.
      برای اطلاعات بیشتر در مورد Aggregate ها و Invariant ها به پست زیر مراجعه کنید :

      آشنایی با مفهوم Aggregate ها

  2. يك سؤال: شما واقعا در كارهاتون شماره تماس رو رشته‌اي ذخيره مي‌كنيد به اين شكلي كه مثال زديد؟ بعد مشكلات گزارش گيري خاص و جستجوي دقيق پيدا نمي‌كنيد؟

    • هادی احمدی

      سلام محسن جان
      مورد ذکر شده صرفا یک مثال بود که مانند مثال های دیگر، از جزئیات پیاده سازی در پروژه ی واقعی برای آن پرهیز شده. امروزه در نرم افزارهای Enterprise تمرکز کاملا بر روی ساخت Domain Model غنی و کاربردی است و مواردی مانند گزارش گیری و جستجو دغدغه نیستند. زیرا راه حل هایی مانند CQRS با ساخت یک مدل جدا برای Query (در بسیاری موارد برای بالا بردن Performance با ساخت یک دیتابیس Denormal جدا) میتوان نیازهای گزارش گیری و جستجو را برطرف نمود. اطلاعات بیشتر در مورد CQRS :

      آشنایی با معماری نرم افزار در رویکرد DDD

      البته این به این معنی نیست که شماره تماس ها همیشه به این شکل باید ذخیره شوند ! Domain Model بر اساس نیازهای پروژه و به تصمیم طراحان سیستم طراحی می شود و ممکن است در صورت نیاز به شکل فوق باشد و یا نباشد.

  3. سلام
    چرا با وجود دو مشکل فوق باز هم کتابی در مورد متودولوژی DDD منتشر شده است.
    Applying Domain-Driven Design and Patterns

    • هادی احمدی

      سلام فرزاد جان
      راستش منظور شما رو دقیق متوجه نشدم. دو مشکل فوق صرفا مربوط به استفاده از Entity Framework به عنوان ORM در پروژه های با رویکرد DDD می باشد. کتاب فوق هم توسط Jimmy Nilsson در سال ۲۰۰۶ (دوسال قبل از Release اولین نسخه ی EF) نوشته شده و از NHibernate استفاده میکند.

      نکته ی دیگر اینکه DDD متدولوژی نیست، به لینک زیر مراجعه کنید :
      What is Domain Driven Design

  4. سلام
    آقای احمدی با توجه به دو مشکل Entity Framework شما NHibernate را تنها ORM مناسب برای پروژهای DDD می دانید یا ORM های مناسب دیگری وجود دارد

    • هادی احمدی

      سلام

      جناب اسماعیلی ممکن است ORM های دیگری هم وجود داشته باشند که بتوان از آنها در پروژه های DDD استفاده کرد (برای مثال LightSpeed که ادعا میکند بر پایه ی مفاهیم و الگوهای DDD مانند Entity، ValueObject ، Aggregate و … طراحی شده است). اما همانطور که میدانید انتخاب یک ابزار به عوامل زیادی مثل امکانات ابزار، مجوز استفاده، مستندات و کتاب های موجود، Community فعال و … بستگی دارد. به نظر من NHibernate شاید تنها انتخاب نباشد، اما میتوان گفت بهترین انتخاب برای پروژه های Domain-Driven است.

  5. سلام
    جناب احمدی این مطلبی رو که در مورد Ef فرمودین در مورد نسخه‌های اخیرش هم صادقه؟

  6. سلام. مطلب خوب و ارزشمندی بود. بابت نگارش مقالات ارزشمند در باب موضوعاتی که کمتر داخل کشور بهشون پرداخته شده بهتون تبریک میگم. دلایلی که فرمودید، درست و در مورد EF کاملا صادق هستند. در عین حال این حرف که EF انتخاب خوبی برای ddd نیست کمی شاید اغراق باشد. همانطور که خودتون فرمودید: “انتخاب یک ابزار به عوامل زیادی مثل امکانات ابزار، مجوز استفاده، مستندات و کتاب های موجود، Community فعال و … بستگی دارد”. همچنان معتقدم هزینه های پرداختی استفاده از EF در ddd در مقابل آنچه که بدست می آوریم بسیار ناچیز خواهد بود.ضمن اینکه بنظر میرسد مطالب زیر در پاسخ به مطلب شما برای خوانندگان مفید خواهد بود :
    https://msdn.microsoft.com/magazine/dn342868
    https://msdn.microsoft.com/magazine/mt842503

    • هادی احمدی

      سلام جناب کلاهی عزیز
      فکر میکنم اینکه میفرمایید “هزینه های پرداختی استفاده از EF در DDD در مقابل آنچه که بدست می آوریم بسیار ناچیز خواهد بود” با فرض این هست که تیم موجود بر روی EF مسلط هستند و تجربه دارند. یکی از عواملی که روی انتخاب ابزار تاثیرگذار می باشد، همین موضوع تجربه و دانش تیم هست. خود بنده هم در پروژه های مختلفی (به علت دانش تیم روی EF) تغییر ابزار رو پیشنهاد نکرده ام و مشکلات EF را با روش های مختلف موجود حل کرده ام.

      اما باید توجه داشته باشید که این مقاله موضوع را از زاویه کاملا فنی (و با حذف شرایط تیم) بیان میکند. از لحاظ فنی، ابزار NHibernate در Map کردن دومین مدل و مفاهیمی مثل Value Object بسیار موفق تر بوده و PI در آن بهتر رعایت می شود. البته مشکلات دیگری هم بوده اند که در این مقاله ذکر نشده اند، مثل عدم پشتیبانی EF از UserType ها که در مواردی مثل Map کردن State Pattern مشکل ساز می شود.

      مقالاتی که فرمودید رو مطالعه کردم، مطالب جالبی هستند اما علیرغم گذشت (تقریبا) ۳ سال از نوشتن این مقاله، همچنان مشکلات فوق در EF وجود دارند و رفع نشده اند. البته با توجه تمرکز جامعه ی معماران و طراحان بر روی موضوع DDD، فکر میکنم این مشکلات به زودی در EF رفع شوند.

  7. با سلام و تشکر از مطالب مفید سایت . میخواستم بدونم که این مشکلات در EF Core حل شده یا نه ؟

    با تشکر

  8. فک کنم هادی احمدی ها همشون برنامه نویسن

دادن پاسخ بههادی احمدی بی خیال پاسخ!

آدرس ایمیلتان منتشر نمیشودگزینه های الزامی ستاره دار شده اند *

*

شما می‌توانید از این دستورات HTML استفاده کنید: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

رفتن به بالا