۱۳۹۰/۰۸/۰۱

آشنايي با Refactoring - قسمت 11


قسمت يازدهم آشنايي با Refactoring به توصيه‌هايي جهت بالا بردن خوانايي تعاريف مرتبط با اعمال شرطي مي‌پردازد.

الف) شرط‌هاي تركيبي را كپسوله كنيد

عموما حين تعريف شرط‌هاي تركيبي، هدف اصلي از تعريف آن‌ها پشت انبوهي از && و || گم مي‌شود و براي بيان مقصود، نياز به نوشتن كامنت خواهند داشت. مانند:

using System;

namespace Refactoring.Day11.EncapsulateConditional.Before
{
    public class Element
    {
        private string[] Data { get; set; }
        private string Name { get; set; }
        private int CreatedYear { get; set; }

        public string FindElement()
        {
            if (Data.Length > 1 && Name == "E1" && CreatedYear > DateTime.Now.Year - 1)
                return "Element1";

            if (Data.Length > 2 && Name == "RCA" && CreatedYear > DateTime.Now.Year - 2)
                return "Element2";

            return string.Empty;
        }
    }
}

براي بالا بردن خوانايي اين نوع كدها كه برنامه نويس در همين لحظه‌ي تعريف آن‌ها دقيقا مي‌داند كه چه چيزي مقصود اوست، بهتر است هر يك از شرط‌ها را تبديل به يك خاصيت با معنا كرده و جايگزين كنيم. براي مثال مانند:

using System;

namespace Refactoring.Day11.EncapsulateConditional.After
{
    public class Element
    {
        private string[] Data { get; set; }
        private string Name { get; set; }
        private int CreatedYear { get; set; }

        public string FindElement()
        {
            if (hasOneYearOldElement)
                return "Element1";

            if (hasTwoYearsOldElement)
                return "Element2";

            return string.Empty;
        }

        private bool hasTwoYearsOldElement
        {
            get { return Data.Length > 2 && Name == "RCA" && CreatedYear > DateTime.Now.Year - 2; }
        }

        private bool hasOneYearOldElement
        {
            get { return Data.Length > 1 && Name == "E1" && CreatedYear > DateTime.Now.Year - 1; }
        }
    }
}


همانطور كه ملاحظه مي‌كنيد پس از اين جايگزيني، خوانايي متد FindElement بهبود يافته است و برنامه نويس اگر 6 ماه بعد به اين كدها مراجعه كند نخواهد گفت: «من اين كدها رو نوشتم؟!»؛ چه برسد به سايريني كه احتمالا قرار است با اين كدها كار كرده و يا آن‌ها را نگهداري كنند.


ب) از تعريف خواص Boolean با نام‌هاي منفي پرهيز كنيد

يكي از مواردي كه عموما علت اصلي بروز بسياري از خطاها در برنامه است، استفاده از نام‌هاي منفي جهت تعريف خواص است. براي مثال در كلاس مشتري زير ابتدا بايد فكر كنيم كه مشتري‌هاي علامتگذاري شده كدام‌ها هستند كه حالا علامتگذاري نشده‌ها به اين ترتيب تعريف شده‌اند.

namespace Refactoring.Day11.RemoveDoubleNegative.Before
{
    public class Customer
    {
        public decimal Balance { get; set; }

        public bool IsNotFlagged
        {
            get { return Balance > 30m; }
        }
    }
}

همچنين از تعريف اين نوع خواص در فايل‌هاي كانفيگ برنامه‌ها نيز جدا پرهيز كنيد؛ چون عموما كاربران برنامه‌ها با اين نوع نامگذاري‌هاي منفي، مشكل مفهومي دارند.
Refactoring قطعه كد فوق بسيار ساده است و تنها با معكوس كردن شرط و نحوه‌ي نامگذاري خاصيت IsNotFlagged پايان مي‌يابد:

namespace Refactoring.Day11.RemoveDoubleNegative.After
{
    public class Customer
    {
        public decimal Balance { get; set; }

        public bool IsFlagged
        {
            get { return Balance <= 30m; }
        }
    }
}