آیا لازمه پروژه ASP.NET MVC خودتون رو به چند پروژه تقسیم کنید؟

این سوالی هست که ممکنه برای خیلی ها موقع کار روی یک پروژه MVC براشون پیش اومده باشه، اینکه یک پروژه رو به چند پروژه تقسیم بندی کنند؛ و جواب در یک کلام این هست که خیر!

دقیقا نمی دونم این داستان از کجا شروع شد اما برنامه نویس های زیادی رو دیدم که به دلایلی پروژه خودشون رو به چند پروژه دیگه تقسیم بندی می کنند، یک پروژه وب جهت لایه ارائه یا presentation، در کنار دو پروژه دیگه که معمولا با نام های MyProject.BLL و MyProject.DAL شناخته می شوند.

سطح بندی یا Tier !

خیلی اوقات اینطور فرض می شود که این لایه بندی باعث میگردد پروژه ی ما n-tier  و یا multi-tier شود، اصلا یک برنامه n-tier یعنی چی؟ به طور مختصر یعنی که یک برنامه از لحاظ فیزیکی جدا سازی شده باشه و روی چند کامپیوتر مختلف یا چند جای شبکه توزیع شده باشه. اغلب برنامه های تحت وب ذاتا n-tier هستند، از این جهت که ما در یک برنامه تحت وب سطوح زیر رو به صورت پیش فرض داریم:

1- لایه نمایش / سمت کلاینت: قسمت هایی که روی کامپیوتر کاربر اجرا می شوند.

2- لایه منطق / سمت سرور: قسمتی که توسط یک تکنولوژی سمت سرور (مثل ASP.NET MVC یا PHP) ساخته میشه و روی کامپیوتر سرور اجرا میشه.

3- لایه داده / بانک اطلاعاتی: شامل بانک اطلاعاتی، فایل سیستم یا هر نوع سیستم ذخیره سازی اطلاعات.

وقتی که داریم درباره ASP.NET MVC صحبت می کنیم، در واقع منظورمون همون قسمت سمت سرور هست، تقسیم بندی پروژه MVC به چند پروژه دیگه عملا باعث نمیشه که یک tier جدید به طراحیمون اضافه بشه. شما لایه DAL رو روی یک کامپیوتر دیگه قرار نمی دید. بیشتر اوقات (اگر نگیم همیشه) شما این سه پروژه رو یکجا کامپایل کرده و طی یک پروسه روی یک ماشین توسعه می دهید، ماشینی که همون وب سرور شماست. بنابراین وقتی که یه نفر از سایت شما بازدید می کنه، این سه dll با هم درون یک (یا چند) پروسه بارگذاری شده و توسط IIS پردازش می شوند.

لایه (Layer) و سطح (Tier)

لایه بندی و سطح بندی معمولا به یک منظور به کار برده می شوند اما این دو اساسا دو مفهوم متفاوت هستند. لایه ها جداسازی های منطقی هستند، سطوح جداسازی های فیزیکی هستند: یعنی توزیع کردن بخش های برنامه روی چند کامپیوتر مختلف. لایه یک مفهوم انتزاعی در ذهن برنامه نویس هست. یک class library یا یک پوشه یک لایه نیست، شما می تونید چند کلاس رو در یک پوشه و یا کلاس های لایه های مختلف برنامه رو در یک پوشه قرار بدید اما وابسته به یکدیگر باشند! این نشونه ای از یک طراحی بد و بهم پیچیده یا coupling هست. قرار دادن کلاس های مختلف در یک پوشه یا یک پروژه جداگانه به اسم DAL باعث نمیشه که شما ناگهان صاحب یک معماری تمیز و لایه بندی شده شوید.

البته منظور من این هست که این قسمت های DAL و BLL رو میشه (بهتره) که در همون پروژه وب قرارشون داد و صرفا انتقال اونها به یک پروژه ی دیگه هیچ ارزشی رو بهمون اضافه نمی کنه و به شکل جادویی باعث نمیشه که طراحیمون لایه بندی بشه.

اساسا به دو دلیل ما یک پروژه رو به چند پروژه تقسیم بندی می کنیم: قابلیت استفاده مجدد (reusability) و طراحی مستقل (independently deploying).

قابلیت استفاده مجدد (reusability)

یکی از علت های تقسیم یک پروژه به چند پروژه قابلیت استفاده مجدد هست. تا حالا برای من پیش نیامده و لازم نشده که بخوام از لایه های DAL و BLL یک برنامه در برنامه ی دیگه ای استفاده مجدد کنم، این یک ذهنیت قدیمی هست و در عمل برنامه های مدرن خیلی خاص هستند و من حتی در یک سازمان به خصوص هم ندیدم که پیش بیاد که لایه های یک برنامه بدرد یک برنامه دیگه در همون سازمان بخورند. خیلی اوقات کدهایی که شما در این لایه می نویسید به طور خاص برای همون برنامه نوشته می شوند تا منطق خاص اون برنامه رو به اجرا بگذارند و این چنین کدها و کلاس هایی رو نمیشه به راحتی طوری نوشت که دارای قابلیت استفاده مجدد باشند (اصلا اگر امکانش باشه!).

طراحی مستقل (independently deploying)

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

کتابخانه Entity Framework مثال خوبی توی این زمینه هست، این کتابخانه از چند اسمبلی مختلف تشکیل شده که هر کدوم امکانات خاصی رو ارائه می کنند. ما یک اسمبلی پایه داریم که شامل کدهای هسته کتابخانه هست، اسمبلی دیگه ای برای کار با SQL داریم و اسمبلی دیگه ای برای کار با SQLite و به همین منوال با این طراحی ما می تونیم فقط بخش هایی که لازم داریم رو دانلود کنیم و بهشون ارجاع بدیم.

تصور کنید که کل کتابخانه Entity Framework فقط یک اسمبلی بود، اونوقت ما با یک کتابخانه سنگین پر از کدهایی که بهشون احتیاج نداریم مواجه بودیم. همچنین هر موقع که تیم پشتیبانی یک قابلیت جدید اضافه، یا یک باگ رو رفع می کردند باید تمامی اسمبلی از ابتدا کامپایل شده و در اختیار برنامه نویسان قرار می گرفت. و در اون صورت این اسمبلی بسیار ناپایدار و شکننده  می شد. فرض کنیم شما دارید از این کتابخانه در کنار بانک اطلاعاتی SQL استفاده می کنید، چرا یک رفع ایراد در قسمت کار با بانک اطلاعاتی SQLite باید روی برنامه ما تاثیر بزاره؟ خب نباید بزاره و به همین دلیل این کتابخانه به شکل مستقل از هم و ماژولار طراحی شده است.

در اکثر پروژه های واقعی سازمانی، ما این لایه های DAL و BLL رو با هم نسخه بندی می کنیم پس انتقال اونها به سه اسمبلی مختلف سودی برای ما نداره.

سناریو های جداسازی فیزیکی

حالا سوال اینه که چه موقع ما واقعا نیاز داریم که پروژه مون رو از لحاظ فیزیکی به چند پروژه تقسیم بندی کنیم. چند تا سناریو رو بررسی می کنیم:

1- وجود چند لایه نمایش: فرض کنیم یه برنامه پردازش سفارش خرید داریم، این برنامه ویندوزی توسط کارمندان سازمان شما در حال استفاده هست و شما تصمیم می گیرید که برای این برنامه ویندوزی یه واسط تحت وب هم پیاده سازی کنید تا کارمندان بتونند از هرجایی با برنامه شما کار کنند. شما قصد دارید که از منطق تجاری و داده های موجود در پروژه جاری استفاده مجدد کنید و همینطور که قبلا اشاره کردم یکی از دلایل تقسیم سازی، قابلیت استفاده مجدد هست. بنابراین در این سناریو لازم هست که شما پروژه خودتون رو به سه پروژه تقسیم بندی کنید:

OrderProcessing.Core
OrderProcessing.Web
OrderProcessing.Desktop

توجه کنید که همینجا هم من دو لایه DAL و BLL رو ندارم و در واقع هر دوی اونها رو در یک پروژه OrderProcessing.Core کپسوله کرده ام.

خب چرا این پروژه رو به دو قسمت تقسیم نکردم (DAL و BLL)؟ چون تمام هدف DAL فراهم کردن نحوه ذخیره سازی اطلاعات برای لایه BLL هست، و خیلی بعید هست که این پروژه به تنهایی برای یک برنامه دیگه استفاده شود.

همچنین طبق اصل معکوس سازی وابستگی در طراحی شی گراء، وابستگی باید از DAL به BLL باشه و نه طور دیگه ای. و این به این معناست که هرجا که به به اسمبلی DAL ارجاعی وجود داره باید به BLL هم ارجاعی وجود داشته باشه. در واقع این دو به شدت در هم تنیده و غیر قابل جدا سازی هستند. وقتی که چیزهای منسجم رو از هم جدا می کنید، بعدا با مشکلات عجیب و غریبی مواجهه خواهید شد.

2- چند برنامه تحت یک پورتال: یک حالت دیگه هاست شدن چندین برنامه کوچک تحت یک پوتال هست که در نظر کاربر نهایی این سایت ها جدا نیستند و دامنه های (حوزه کاری) مختلف یک برنامه هستند. اما از نقطه نظر توسعه دهنده هر برنامه مستقل از دیگری هست. هر برنامه می تواند بانک اطلاعاتی خودش رو داشته باشه؛ یکی از Excel استفاده کنه یکی دیگه از SQL Server و دیگری از Oracle.

در این سناریو، احتمالا هر برنامه توسط تیم یا توسعه دهنده ی متفاوتی کار میشه و معمولا مستقل از هم توسعه/ورژن بندی/پیاده سازی می شوند. که می رسیم به  علت دوم جهت جدا سازی فیزیکی.

در این سناریو ما می تونیم پروژه مون رو به شکل زیر داشته باشیم:

OrderProcessing.Core (a class library)
Shipping.Core
CustomerSupport.Core
MainPortal (an ASP.NET MVC project)

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

 

خلاصه

  • لایه ها (Layer)، همون سطوح (Tier) نیستند.
  • سطح، یعنی جداسازی و توزیع فیزیکی یک نرم افزار روی کامپیوتر های مختلف.
  • لایه ها مفاهیم انتزاعی هستند، دقیقا یک مدل ارائه فیزیکی در کد نویسی برای اونها وجود نداره، داشتن یک پوشه یا یک اسمبلی با نام DAL به این معنی نیست که شما پروژه تون رو به خوبی لایه بندی کرده اید و یا قابلیت نگهداری (maintainability) رو افزایش داده اید.
  • قابلیت نگهدای یعنی کدهای تمیز، متد های کوچک، کلاس های کوچک که تنها یک وظیفه دارند و وابستگی محدود شده بین این کلاس ها. جدا سازی یک پروژه با کلی متد ها و کلاس های بزرگ به دو تا پروژه DAL/BLL هیچ قابلیت نگهداری رو در سیستم افزایش نمی دهد.
  • اسمبلی ها واحد های ورژن بندی و توسعه هستند.
  • در صورتی یک پروژه رو به چند پروژه تقسیم کنید که بخواهید از یک بخش بخصوص در پروژه ی دیگه ای استفاده کنید و یا قصد دارید به طور مستقل هر پروژه رو ورژن بندی و توسعه و منتشر کنید.

همیشه اصل KISS رو به خاطر داشته باشید و همه چیز رو ساده نگه دارید 🙂

 

منبع: programmingwithmosh

5 دیدگاه در “آیا لازمه پروژه ASP.NET MVC خودتون رو به چند پروژه تقسیم کنید؟

  1. سلام دوست عزیز.
    ممنون از مقاله ی خوبتون اما لازم می دونم مواردی رو خدمتتون عرض کنم.
    مزایایی در داشتن چند پروژه در یک Solution وجود داره که به شرح زیر هستند:
    – توانایی معرفی کلاس هایی که نباید خارج از اسمبلی قابل دیدن باشن (این مورد بسیار مهم هست)
    – استفاده از چند زبان برنامه نویسی
    – پروژه هایی که به هم وابسته هستند. مثلا من هم Cordova دارم و هم Web API. و برنامه Cordova من نیاز داره که ابتدا Web API اجرا بشه.
    – وقتی من Unit Test می نویسم، چرا باید کل پروژه کامپایل بشه؟ VS اینقدر هوشمند هست که بدونه یک پروژه تغییری نداشته و نیازی به کامپایل اون نیست. بنابراین فقط یک اسمبلی خاص رو تست می کنم و زمان کامپایل کاهش پیدا می کنه
    – وقتی یک نفر میاد و پروژه ی شما رو باز می کنه، از روی لایه ها میتونه یک دید کلی از نحوه ی ساختار پروژه و حتی ابزارهایی که در اون استفاده شده داشته باشه و همون KISS که اشاره فرمودید رو محقق میشه

    موفق باشید.

    • درسته، منظور مقاله هم بیشتر درباره تقسیم سازی با درک صحیح از علت اینکار هست.
      به عنوان مثال داشتن Cordova و هم Web API می تونه مصداقی از وجود چند لایه نمایش در سناریو جداسازی فیزیکی باشه.

پاسخ دهید

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