بررسی مفاهیم Cohesion و Coupling در توسعه نرم افزار

بررسی مفاهیم Cohesion و Coupling در توسعه نرم افزار

در این پست از وبسایت پرووید در رابطه با بررسی مفاهیم Cohesion و Coupling در توسعه نرم افزار صحبت خواهیم کرد.

در این آموزش در رابطه با مفهوم Cohesion و Coupling صحبت خواهیم کرد. این دو موضوع از مهمترین اصول و مفاهیم در توسعه ی نرم افزار می باشند. شاید اغلب شنیده اید که در زمان کار کردن بر روی کد باید سعی کنیم که سطح Coupling به حداقل رسیده و سطح Cohesion را به حداکثر برسانیم. اما موضوع مهمتر این است که مفهوم کلمه Coupling و Cohesion چیست و بدست آوردن حداقل Coupling و حداکثر Cohesion به ما چه کمکی می کند. در این مطلب از وب سایت پرووید در رابطه با این موضوع صحبت خواهیم کرد و در قالب مثالهایی در رابطه با تفاوت Cohesion و Coupling با یکدیگر صحبت خواهیم کرد. در ابتدا در رابطه با تفاوت Cohesion و Coupling صحبت کنیم.

Cohesion و Coupling چه هستند؟

در ابتدا قصد داریم به شما توصیه کنیم که در استفاده از این دو کلمه بدنبال ترجمه ی فارسی نباشید و از آنها به عنوان دو کلمه ی فنی و تخصصی در حوزه ی توسعه ی نرم افزار استفاده کنید. معنی فارسی هر دو کلمه شاید اندکی مشابه باشد و به همین دلیل توصیه می کنیم از خود کلمه ها و نه ترجمه ی آنها استفاده کنید. به هرحال می توان کلمه ی Cohesion را به چسبندگی و کلمه ی Coupling را به درهم تنیدگی ترجمه کرد. شاید جالب باشد بدانید که تفاوت این دو مفهوم اغلب گنگ و مبهم و گاهی برای افرادمشابه هم است. با این وجود تفاوتهای بسیار مهمی نیز وجود دارند.

مفهوم Cohesion به سطح چسبندگی قسمتهای مختلفی از کد بعنوان یک واحد تک و Atomic اشاره می کند. منظور از چسبندگی این است که قسمتهای مختلف یک کد در کنار هم تا چه حدی یک واحد تک منطقی را تشکیل می دهند. علاوه بر این می توان Cohesion را در قالب تعداد ارتباطات بین یک واحد کد تعریف کرد. اگر این تعداد کم باشد بنابراین مرز و یا Boundary آن واحد از کد به درستی انتخاب نشده است و کدهای درون آن واحد و یا اصطلاحاً Unit از لحاظ منطقی مرتبط نمی باشند. دقت کنید که منظور از واحد در این قسمت لزوماً یک کلاس نیست. یک واحد از کد می تواند یک متد و یا یک کلاس و یا حتی گروهی از کلاسها در قالب یک Namespace و یا Module و یا حتی یک Assembly باشد. موضوع دیگر اینکه مفهوم Cohesion و همچنین Coupling در سطوح مختلف تعریف می شوند. در رابطه با این سطوح بیشتر صحبت خواهیم کرد.

مفهوم Coupling و یا اصطلاحاً در هم تنیدگی، درجه ی استقلال و یا عدم وابستگی یک واحد کد نسبت به دیگر واحدها را نشان می دهد. به عبارت دیگر مفهوم Coupling به معنی تعداد ارتباطات بین دو یا چند واحد کد است. هر چقدر این ارتباطات کمتر باشد Coupling نیز کمتر است. در ادامه در رابطه با این موضوع صحبت خواهیم کرد که چرا بدست آوردن حداکثر Cohesion و حداقل Coupling مناسب می باشد.

بدست آوردن حداکثر Cohesion و حداقل Coupling

بطور کلی Cohesion بالا به این معنی استکه قسمتهای مختلف یک کد که باهم در ارتباط هستند و باید در یک مکان تک و یکسان قرار بگیرند در حالی که Coupling حداقل به این معنی است که قسمتهای غیر مرتبط یک کد را باید تا حد امکان از یکدیگر جدا کنیم. شاید مفهوم این موضوع و این اصل در توسعه ی نرم افزار بسیار ساده باشد اما پیاده سازی عملی آن مستلزم این موضوع است که شما Domain Model خود را بخوبی بشناسید و بتوانید تشخیص بدهید کدام قسمت از کدتان به دیگر قسمتها مرتبط هست و یا مرتبط نیست. موضوع مهم دیگر این است که علی رغم اتفاقی که در معیار Cyclomatic Complexity اتفاق می افتد، مشخص کردن حداکثر Cohesion و حداقل Coupling چیزی نیست که بتوان آن را بطور مستقیم اندازه گیری کرد. در رابطه با Cyclomatic Complexity که یکی از معیارهای بسیار مهم در توسعه ی نرم افزار می باشد بعداً بر روی وب سایت پرووید آموزشهایی را منتشر خواهیم کرد.

علی رغم چیزی که در رابطه با Cyclomatic Complexity وجود دارد، بدست آوردن Cohesion حداکثر و Coupling حداقل بیشتر به Domain Model مربوط به نرم افزار مورد نظر برمی گردد. موضوع دیگر اینکه بحث مربوط به Cohesion حداکثر و Coupling حداقل به یکی از اصول بسیار مهم در توسعه ی نرم افزار به نام Separation of Concerns مرتبط می شود که در رابطه با آن نیز بر روی وب سایت پرووید مقاله ای را منتشر خواهیم کرد.

انواع کد از نقطه نظر Cohesion و Coupling

در کنار کدی که کاملاً Cohesive می باشد و دارای حداقل Coupling نیز هست، حداقل سه نوع دیگر از کدها را داریم که در این قسمت در رابطه با آنها صحبت خواهیم کرد.

2015 09 02 1 e1575508063388 - بررسی مفاهیم Cohesion و Coupling در توسعه نرم افزار

کد ایده آل (Ideal)

این نوع کد از اصل به حداقل رساندن Coupling و به حداکثر رساندن Cohesion تبعیت می کند و کاملاً Cohesive است و سطح Coupling آن حداقل است. برای درک بهتر این نوع از کد می توانیم به تصویر زیر نگاهی بیاندازیم.

2015 09 02 1 01 e1575508117405 - بررسی مفاهیم Cohesion و Coupling در توسعه نرم افزار

در تصویر بالا دایره هایی که یک رنگ هستند نمایانگر قستمهایی از کد می باشند که با یکدیگر مرتبط هستند.

شیء خدا (God Object)

این نوع از Object ها که با بدست آوردن Cohesion حداکثری و همچنین Coupling حداکثری بوجود می آیند. در واقع God Object نمایانگر یک ضد الگو و یا Anti-pattern می باشند. در مورد ضدالگوها در بسته ی آموزش ویدئویی AntiPattern ها در توسعه ی نرم افزار بیشتر صحبت کرده ایم. به عبارت ساده یک God Object یک تکه کد است که تمامی کارهای محوله در یک نرم افزار را بصورت تک و انفرادی انجام می دهد. نام دیگری که برای این نوع از کد می گذارند Big Ball of Mud یا گوله ی بزرگی از گل و لای می باشد. توصیه می کنیم که با رجوع کردن به کتاب Domain Driven Design از Eric Evans در رابطه با این موضوع اطلاعات بیشتری کسب کنید. ضمناً می توانید از بسته ی آموزش ویدئویی کاربردی طراحی نرم افزار Domain Driven Design نیز استفاده کنید. برای درک بهتر این نوع از کد می توانیم به تصویر زیر نگاهی بیاندازیم.

2015 09 02 1 02 e1575508177280 - بررسی مفاهیم Cohesion و Coupling در توسعه نرم افزار

مزرهای اشتباه

نوع سوم از کدها زمانی رخ می دهد که مرزها و یا Boundary های بین کلاسها و ماژولهای مختلف به خوبی انتخاب نشده باشند. به تصویر زیر نگاهی بیاندازید.

2015 09 02 1 03 e1575508187248 - بررسی مفاهیم Cohesion و Coupling در توسعه نرم افزار

در مقایسه با God Object این نوع از کدها مرز و یا Boundary دارند، منتهی مشکل در این قسمت است که این مرزها به درستی انتخاب نشده اند و معنای واقعی Domain را نشان نمی دهند. یکی دیگر از موضوعاتی که باید به آن اشاره کنیم این است که این نوع از کد اصل بسیار مهم Single Responsibility Principle را در توسعه ی نرم افزار نقض می کنند.

از هم باز کردن مخرب (Destructive Decoupling)

این نوع از کد از دیگر نوع های قسمت بالا بسیار جذاب تر می باشد. در واقع زمانی که یک برنامه نویس سعی می کند یک کد را بشدت Decouple کند نتیجه ی کار کدی است که کاملاً نقاط تمرکز خود را از دست داده است. در رابطه با این نوع از کد که به آن Destructive Decoupling می گوئیم بیشتر صحبت خواهیم کرد.

بررسی Destructive Decoupling

اغلب دیده شده است که زمانی که یک برنامه نویس سعی می کند مفهوم Low Coupling و High Cohesion را پیاده سازی کند، بیشتر تمرکز خود را بر روی قسمت به حداقل رساندن Coupling قرار می دهد و از به حداکثر رساندن Cohesion غافل می شود. نتیجه ی کار کدی می شود که تا حد بسیار شدیدی از هم Decouple شده است و قسمتهای مختلف آن از همدیگر گسسته اند.

2015 09 02 2 04 e1575508295178 - بررسی مفاهیم Cohesion و Coupling در توسعه نرم افزار

در چنین شرایطی نمی توان براحتی معنا و مفهوم و دلیل کد را درک کرد، چرا که از دیگر قسمتهای خود تا حد بسیار زیادی جدا شده است. این موضوع را Destructive Decoupling می نامیم. برای روشن تر شدن مثال، به کد زیر نگاه کنید.

public class Order
{
    public Order(IOrderLineFactory factory, IOrderPriceCalculator calculator)
    {
        _factory = factory;
        _calculator = calculator;
    }
 
    public decimal Amount
    {
        get { return _calculator.CalculateAmount(_lines); }
    }
 
    public void AddLine(IProduct product, decimal price)
    {
        _lines.Add(_factory.CreateOrderLine(product, price));
    }
}

مثال بالا نمایانگر مسأله ی Destructive Decoupling می باشد. خب اگر به این کد با دقت نگاه کنید متوجه می شوید که کلاس Order کاملاً از کلاس Product و OrderLine اصطلاحاً Decouple شده است. علاوه بر این مسئولیت محاسبه ی قیمت یک سفارش و یا همان Order به یک اینترفیس به نام IOrderPriceCalculator داده شده است. از این گذشته ایجاد OrderLine ها توسط یک Factory که یک الگوی طراحی می باشد انجام می شود. برای کسب اطلاعات بیشتر به بسته ی آموزش ویدئویی Design Pattern ها در سی شارپ رجوع کنید. این کد نتیجه ی تمرکز بیش از حد بر روی به حداقل رساندن Coupling می باشد. از طرفی چسبندگی یا Cohesion این کد شدیداً پائین می باشد. بعبارت دیگر کلاسهایی که از لحاظ معنایی با همدیگر مرتبط هستند کاملاً از هم جدا شده اند. هرچند که این مثال یک مثال ساده است اما مطمئن هستم که موضوع و معنی پدیده ی Destructive Decoupling در این کد مشاهده می کنید.

حال فرض کنید که پدیده ی Destructive Decoupling در یک نرم افزار بسیار بزرگ که در رابطه با یک Domain Model کاملاً غیر آشنا برای شما اتفاق افتاده است. یکی از موضوعاتی که از پدیده ی Destructive Decoupling نشأت می گیرد کم شدن قابلیت خوانایی و یا Readability کد می باشد. یکی دیگر از موضوعاتی که در کنار Destructive Decoupling به چشم می خورد نگرش استفاده ی بیش از حد از Interface ها می باشد. همه ما می دانیم که می توان از اینترفیس ها برای Decouple کردن برنامه استفاده کرد. در واقع استفاده کردن از اینترفیس ها بجای Concrete Type ها می تواند به Loosely Coupled کد کمک کند. اما این تصور که در هرجایی از برنامه باید بجای استفاده از یک Concrete Class از یک Interface استفاده کرد کاملاً اشتباه می باشد. حال به کد زیر که بازنویسی کد قبلی می باشد نگاه کنید.

public class Order
{
    public decimal Amount
    {
        get { return _lines.Sum(x => x.Price); }
    }
 
    public void AddLine(Product product, decimal amount)
    {
        _lines.Add(new OrderLine(product, amount));
    }
}

در این کد توانسته ایم ارتباطات بین کلاسهای Order و OrdeLine و Product را ایجاد کنیم. این کد هم از Cohesion بالایی برخوردار است و هم ساده می باشد.

سطوح مختلف Cohesion و Coupling

همانطور که قبلاً اشاره کردیم مفهوم Cohesion و Coupling می تواند در سطوح مختلف تعریف بشود. ساده ترین سطحی که به ذهن می رسد سطح کلاس می باشد. یک مثال دیگر از مفهوم Cohesion و Coupling استفاده کردن از آنها در ساختار یک پروژه و فایل های درون پروژه می باشد. لطفاً به تصویر زیر نگاه کنید.

2015 09 02 2 - بررسی مفاهیم Cohesion و Coupling در توسعه نرم افزار

در نگاه اول این پروژه کاملاً سازمان یافته به چشم می خورد چرا که فولدرهای مجزایی برای Entity ها و Factory ها و غیره تعریف شده اند. اما قضیه این است که این ساختار از Cohesion کمی برخوردار است. در واقع این ساختار پروژه مطابق با تعریف سومی است که در نمودار بالا ارائه کردیم. در این پروژه مرزها بدرستی انتخاب نشده اند. هرچند که موارد درونی پروژه بصورت Loosely Coupled می باشند اما مرزها نمایانگر مفهوم درست قسمتهای مختلف پروژه نیستند. اگر بخواهیم این ساختار را طوری تغییر بدهیم که از Cohesion بالا و Coupling حداقلی برخوردار باشند چیزی شبیه به تصویر زیر را خواهیم داشت.

2015 09 02 3 - بررسی مفاهیم Cohesion و Coupling در توسعه نرم افزار

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

رابطه ی Cohesion و اصل Single Responsibility Principle

مفهوم چسبندگی و یا Cohesion با اصل Single Responsibility Principle در حوزه ی نرم افزار گره خورده است. همانطور که می دانید بر اساس اصل SRP یک کلاس فقط باید یک وظیفه ی تک را داشته باشد. و یا حتی می توانیم بگوئیم یک کلاس فقط باید به یک دلیل تغییر کند. این موضوع بسیار شبیه به چیزی است که کدهای بهم چسبیده که از Cohesion بالایی برخوردار هستند از خود نشان می دهند. تفاوتی که بین مفهوم Cohesion و اصل Single Responsibility وجود دارد در این است که براساس Cohesion نیازی نداریم که یک کلاس فقط یک تک وظیفه را داشته باشد بلکه وظایف باید بهم چسبنده باشند. این در حالی است که بر اساس اصل SRP یک کلاس فقط می تواند یک وظیفه داشته باشد که اجزای آن وظیفه باید از Cohesion بالایی برخوردار باشند. به نظر می آید که از این نقطه نظر اصل Single Responsibility Principle نسبت به موضوع Cohesion حداکثری، کد مورد نظر را محدودتر کند.

این مقاله را در این قسمت به پایان می رسانیم. در این مقاله سعی کردیم که در رابطه با Coupling و Cohesion صحبت کنیم. به حداکثر رساندن Cohesion و به حداقل رساندن Coupling از مهمترین اصول توسعه ی موفق نرم افزار می باشند که حتماً باید به آن توجه کرد. همانطور که گفتیم Cohesion نمایانگر سطح ارتباط اجزای درون یک واحد کد می باشد. به عبارت دیگر زمانی که اجزای درونی یک قسمت و یا واحد از کد از لحاظ منطقی باهم در ارتباط باشد می توانیم بگوئیم که آن واحد از کد از Cohesion بالای برخوردار است.

و اما Coupling سطح مستقل بودن و یا عدم وابسته بودن یک واحد از کد نسبت به دیگر واحدها را نشان می دهد. فراموش نکنید که بدست آوردن حداقل Coupling بدون آسیب رساندن به Cohesion کاملاً غیر ممکن است. به عبارت دیگر بدست آوردن یک تعادل بین حداکثر رساندن Cohesion و به حداقل رساندن Coupling باید هدف ما باشد و نه اینکه با تمرکز کامل بر روی یکی از این دو مورد، مورد دیگر را فراموش کنیم و به پدیده ی Destructive Decoupling دچار بشویم. موضوع آخر اینکه سعی کنید در سطوح مختلفی از کدتان به به حداکثر رساندن Cohesion و به حداقل رساندن Coupling دقت کنید این موضوع هم می تواند در کلاسها، متدها و یا حتی در اسمبلی ها لحاظ شود. ساختار پروژه ی شما نیز می تواند یکی دیگر از سطوح به حداکثر رساندن Cohesion و به حداقل رساندن Coupling باشد.

مرتضی گیتی
۲ نظرات
  • عارف
    پاسخ
    Posted at 2:11 ب.ظ, دسامبر 6, 2019

    سلام و تشکر بابت مقاله
    مقاله جامعی در این رابطه بود که در نت فارسی با این جزئیات به ان پرداخته نشده بود

ارسال نظر

نظر
نام
ایمیل
وب سایت