C#/.NET Developer
آموزش Domain Driven Design - زبان و زمینه
در آغاز این فصل، اشاره ای به تفاوت های زبانشناسی در یک زبان کردیم. ما از زبان انگلیسی که در امریکا و انگلیس استفاده می شد مثال زدیم که جملات مشترک ممکن است معانی مختلفی در این دو کشور داشته باشند. مثال های فراوانی از این دست وجود دارد. همین اتفاق در زبان گروههای حرفه ای نیز مشاهده می شود. جایی که افراد اصطلاحات تخصصی را توسعه می دهند. مثال هایی از این موارد هم اشاره کردیم.
این مثال ها، اهمیت تعریف دقیق معانی کلمات را مشخص می کنند. اجتناب از سردرگمی در واقع یکی از اهداف شناسایی زبان مشترک و فراگیر (Ubiquitous Language) است.
فهم این نکته اهمیت زیادی دارد که زبان مشترک و فراگیر تنها داخل زمینه (context) خودش اعتبار دارد. یک زمینه متفاوت با زبان متفاوتی تعریف می شود. یک اشتباه رایج در درک زبان مشترک و فراگیر وجود دارد که عبارت مشترک و فراگیر اشاره به یک زبان واحد برای کل کسب و کار، سازمان یا دامین دارد. در حالی که اینطور نیست. مشترک و فراگیر بودن آن، افقی نیست. بلکه عمودی است. هر زمینه ممکن است زبان خاص به خود را داشته باشد،در عین حال این امکان وجود دارد تمامی لایه ها در این زمینه؛ یک زبان مشترک و فراگیر واحد را به اشتراک گذارند.
بیایید نگاهی به یک مثال کلاسیک از عبارت محصول (product) در زمینه های متفاوت از دامین خرید و فروش بیاندازیم:
اگر چه ما در یک دامین مشترک هستیم، اما واژه Product معانی و مفاهیم مختلفی در هر یک از زمینه های مشخص شده دارد:
- فروش (Sales): برای فروشندگان، محصول به معنی قیمت فروش و حتی حاشیه سود است. جایی که شرکت از آنجا پول بدست می آورد و سایر خصوصیات محصول اهمیتی ندارد.
- خرید (Purchasing): اگر یک محصول را خریداری کرده باشیم به نیت فروش مجدد آن، ما بیشتر از همه به قیمت خرید علاقمند هستیم. اینکه چقدر از یک کالای در انبار تامین کننده موجود است؟ و اینکه آن کالاها در چه فاصله زمانی بعد از سفارش به ما خواهند رسید؟
- فهرست موجودی (Inventory): ما بیشتر از همه علاقمند به دانستن تعداد هر چیزی در انبارمان هستیم. اگر موجودی کالایی کمتر از حد انتظار باشد، می توان تاریخ تخمینی برای سفارش و دریافت مجدد کالا را در این زمینه (context) در نظر گرفت. در اینجا ما احتمالا برخی خصوصیات داخلی محصول مانند شماره انبار آن محصول را نیز تعریف می کنیم.
- انبار (Warehouse): نیاز به مدیریت فضایی دارد که برای نگهداری محصولات مورد نیاز است. پس افرادی که در این زمینه حظور دارند، نیاز دارند تا زمان رسیدن کالاهای جدید به انبار را بدانند. و اینکه چگونه باید آنها را دسته بندی کنند. و در کجا هر محصول را ذخیره سازی کنند.
همانطور که می بینید، اگر چه ما یک اصطلاح رایج مانند محصول را داریم، اما دپارتمان های مختلف از یک دامین مشترک یا سازمان نیز خصیصه های مشترک بسیار کمی از مفهوم آن در بخش های خودشان دارند و هر زمانی که در هر بخش به معنی و مفهوم آن عمیق می شویم، مشاهده می شود که ویژگی های خاص به آن بخش به آن کلمه اعتبار و مفهوم متفاوت می دهد.
مثال بالا نشاندهنده این است که حتی در یک دامین خاص، زمینه های مختلفی می تواند وجود داشته باشد که زبان در آنجا تغییر نموده و برخی اوقات این تغییرات بسیار فاحش هستند. اما چه اتفاقی رخ می دهد اگر ما از یک معنی در تمام زمینه ها استفاده کنیم؟ این کار باعث می شود که مسائل، کمتر صریح باشند. درجات ابهام با هر زمینه جدید، افزایش می یابد و باعث می شود در تفکیک و شناسایی آنها در زمینه های مختلف به مشکل بر بخوریم. اینها باعث ایجاد یک مدل غیرشفاف می شوند و در نتیجه مسبب کد مبهم می شود. جائیکه نیاز پیدا می کنیم مشخص کنیم که منظور ما از آن کلمه در آن زمینه، دقیقا چیست؟
مخلوط کردن زمینه های مختلف در یک محیط کاری نیز شما را به سمت چیزی به نام تغییر زمینه (context switching) هدایت می کند. جرالد وینبرگ در کتاب خود اینطور تخمین می زند که بالا رفتن تعداد پروژه هایی که یک فرد روی آن کار می کند، باعث افت شدید بهره وری آن شخص بدلیل همین تغییر زمینه می شود.
افزودن یک پروژه به پروژه های کنونی به معنی کاهش 20 درصدی بهره وری شما می باشد. اگر تعداد زمینه های مختلف شما به 5 برسد، مقدار زمانی که مفید روی کارها می گذارید، به شدت کاهش می یابد. زمان زیادی از شما صرف این مساله می شود که متوجه شوید کدام زمینه متعلق به پروژه یا تسک جاری شماست.
این قاعده فقط برای پروژه ها معتبر نیست. ممکن است زمانیکه تعمیم (generalization)، بر دقت و عدم ابهام غالب شود، پدیده تغییر زمینه بوجود آمده و به همان اندازه که گفته شد، بر روی عملکرد شما تاثیر گذار باشد. در مثالی که در مورد Product بیان شد، اگر ما تمام خصوصیات Product که از هر زاویه دیدی وجود دارد را در یک کلاس تعریف کنیم، کار با چنین آبجکتی مستلزم تلاش بیشتر و همچنین تلاش برای درک آن بخش از Product با توجه به زمینه ای که در حال کار با آن هستیم، دارد. بنابراین، با اینکه داریم بر روی یک چیز کار می کنیم، دچار تغییر زمینه مخفی شده ایم و به مضرات آن دچار خواهیم شد.
فرض کنید که تمرکزگرایی و تعمیم پذیری، چیزهای خوبی بودند و بسیاری از شرکت ها، کلاس هایی (God classes) مانند Customer یا Product ایجاد می کردند که شامل تمام خصوصیات ممکن از همه زوایای مختلف بود. علاوه بر تغییر زمینه ای که رخ می داد، معایب دیگری نیز بوجود می آمد.
یکی از معایب واضح، این است که در طول یک چرخه عمر مشخص از چنین آبجکتی در سیستم، همه خصوصیات مورد نیاز ما نیستند. برای مثال، محصول از رده خارج شده، هیچ ویژگی ای ندارد که مرتبط با بخش فروش باشد. اما چون ما یک کلاس برای همه خصوصیات داریم، مجبور هستیم مقادیر خالی را برای تمامی محصولات ایجاد کنیم. چنین رویکردی ما را به سطح بالایی از سردرگمی می رساند چرا که ما به سختی متوجه این خواهیم شد که چرا این خصوصیات، بی استفاده هستند. اشتباهی در سیستم هستند و یا یک وضعیت معمولی با توجه به وضعیت آبجکت هستند؟
مساله دیگر این است که ناچارا این کلاس ها دارای وابستگی های زیادی می شوند. احتمالا دیتامدل هایی را دیده اید که سیستم با تمام پیچیدگی هایش، فقط یک دیتابیس SQL بزرگ دارد که جداول آن رفرنس های زیادی به یکدیگر دارند. می توانیم اینطور فرض کنیم که جدولی مانند Product با جداولی چون Order,ShoppingCart, Catalogue,Invoice,PurchaseInvoice, Return, CreditNote و ... رفرنس دارد. این مدل به سرعت درهم می شود و نگهداری آن بسیار دشوار می شود. برخی اوقات، اوضاع از این هم خراب تر می شود. مثلا فرض کنید مشخصات یک محصول تغییر می کند. اما نباید مشخصات محصول برای خرید های قبلی که از آن انجام شده دچار تغییر شود. هر سفارش باید کپی خودش از محصول خریداری شده را در لحظه خرید، ضبط کند.
به اندازه کافی علت اینکه باید مراقب فراموش نکردن زمینه ها باشیم را متوجه شدیم. زبان مشترک و فراگیر (Ubiquitous Language)، همیشه باید بدون ابهام، صریح و مختص به زمینه (context) باشد. به محض اینکه حس کردید معانی کلمات شروع به تغییر در بخش های مختلف سیستم کردند، باید هشداری در درون شما را فعال کند که در حال عبور از مرزبندی های آن زمینه هستید.
هنگام بحث در مورد کاربران، زمینه مطرح می شود. توسعه دهندگان مایل اند به مردم به عنوان کاربر نگاه کنند. این اصطلاح خیلی مبهم است. تا آنجائیکه تقریبا می توان تضمین داد که زمانی که در مورد کاربران در حال صحبت هستیم، در حال تغییر بین زمینه های مختلف هستیم.
به دامین نمونه خودمان بازگردیم. جایی که توسعه دهندگان در حال بحث در مورد چگونگی امتیازدهی کاربران به معاملات خودشان هستند. آنها به این فکر کردند که اگر مردم بتوانند به یکدیگر امتیاز دهند، به آنها در ایجاد اعتماد در جامعه شان در نرم افزار کمک می کند. برخی از آنان متوجه شدند که از کلمات << کاربر، فروشندگان، آنها که می فروشند، آنها که می خرند و خریداران>> دارند به جای هم استفاده می کنند. وقتی که اصطلاح عمومی کاربر استفاده می شد، همیشه نیاز به شفاف سازی داشت: این کاربر چه نقشی در آن لحظه دارد ایفا می کند؟ همزمان، وقتی کاربران را به نام های خریدار یا فروشنده صدا می زدند، ابهامی بوجود نمی آمد و نیاز به شفاف سازی نبود.
پس از این، گروه متوجه شد که المنت های جدیدی از Ubiquitous Language را کشف کرده و شروع به استفاده از این اصطلاحات کرد. این کار بینش خوبی به آنها داد که زمانی زیادی از بحث آنها را در مورد مدل ها صرفه جویی نمود و ابهام در کد را نیز از بین برد.
همزمان، تفکیک مردم به خریدار یا فروشنده در قسمت اعتبار سنجی (authorization) سیستم منطقی به نظر نمی رسید. آنها فقط کاربر هستند که می توانند به سیستم لاگین کرده و برخی عملیات انجام دهند. مانند بروزرسانی پروفایلشان. بدون توجه به اینکه بین خریدار بودن یا فروشنده بودن آن فرد در سیستم، تمایزی قائل شویم. این خود یک زمینه دیگر است که کلمه user ابهامی ندارد و صریح است.
بعدا، مجددا آنها گونه دیگری از کاربران را یافت کردند که نیاز به مدل شدن در سیستم داشت. جائیکه کاربران شروع به گرفتن نقش های مختلف می کردند. و مجددا ابهام بوجود آمد تا آنها شروع کردند به استفاده از اصطلاحاتی چون administrator، support assistant و reviewer. زمینه جدیدی یافت شد و مدل جدید برای آن ایجاد شد که از زمینه های دیگر با توجه به معانی کلمات استفاده شده در آنها تفکیک گشت.
مطلبی دیگر از این انتشارات
آموزش Domain Driven Design. پیچیدگی ها
مطلبی دیگر از این انتشارات
آموزش Domain Driven Design - طوفان رویداد (بخش اول)
مطلبی دیگر از این انتشارات
آموزش Domain Driven Design - دانایی در برابر جهالت!