معماری کد نویسی تمیز یا Clean Code

معماری Clean Code چیست

توسط admin | گروه برنامه نویسی | 1402/09/28

نظرات 1

Clean Code یک مفهوم مهم در توسعه نرم‌افزار است که به نحوه نوشتن کد قابل فهم، ساده، قابل نگهداری، و با کیفیت اشاره دارد. اصطلاح Clean Code توسط Robert C. Martin در کتابی به همین نام مطرح شده است. Clean Code در واقع به یک استایل نگارشی و الگوی نگارش کد اشاره دارد که هدف آن افزایش خوانائی و قابلیت نگهداری کد است. مزایا و ویژگی‌های Clean Code شامل:

خوانائی بالا: Clean Code باید به راحتی قابل خواندن و درک باشد. این امر برای توسعه‌دهندگانی که ممکن است بعداً کد را بخوانند یا تغییر دهند، بسیار مهم است.
سادگی: از اصول KISS (Keep It Simple, Stupid) پیروی می‌کند. کد باید به سادگی اجتناب ناپذیر باشد و از پیچیدگی غیرضروری پرهیز کند.
اصل KISS به این معناست که باید چیزها را به سادگی نگه داشت و از پیچیدگی‌های غیرضروری اجتناب کرد. این اصل توسعه دهندگان را تشویق می‌کند که کدهای خود را به سادگی و در سطحی که لازم است، طراحی کنند. در زیر یک مثال از اصل KISS در زبان C# آورده شده است:
// کد پیچیده
public class ComplexCalculator
{
    public int CalculateComplexSum(int[] numbers)
    {
        int sum = 0;
        foreach (var num in numbers)
        {
            if (IsEven(num))
            {
                sum += num * 2;
            }
            else
            {
                sum += num;
            }
        }
        return sum;
    }

    private bool IsEven(int number)
    {
        return number % 2 == 0;
    }
}

// کد ساده با اصل KISS
public class SimpleCalculator
{
    public int CalculateSimpleSum(int[] numbers)
    {
        int sum = 0;
        foreach (var num in numbers)
        {
            sum += num;
        }
        return sum;
    }
}
در مثال اول (ComplexCalculator)، تابع CalculateComplexSum از شرطی (IsEven(num)) برای تشخیص اعداد زوج استفاده می‌کند و بر اساس شرط یک محاسبه مختلف برای اعداد زوج انجام می‌دهد. این کد ممکن است پیچیده و دشوار به فهم باشد.
 
معماری Clean Code یا کد نویسی تمیز
 
در مثال دوم (SimpleCalculator)، کد تابع CalculateSimpleSum بسیار ساده‌تر است و تنها کاری که انجام می‌دهد، جمع اعداد آرایه است. این تابع از پیچیدگی‌های غیرضروری کاسته و به سادگی به هدف خود می‌رسد.
در کل، اصل KISS به ما یادآوری می‌کند که هنگامی که می‌توانیم با یک راه حل ساده به هدف خود برسیم، از پیچیدگی‌های غیرضروری خودداری کنیم.
 
نام‌گذاری مناسب: نام‌گذاری متغیرها، توابع، کلاس‌ها و ... باید معنادار و توضیح‌دهنده باشد.
کلاس با نام‌گذاری مناسب:
// نام‌گذاری مناسب
public class FileManager
{
    private string filePath;

    public FileManager(string path)
    {
        filePath = path;
    }

    public void CopyFile(string destinationPath)
    {
        // کپی فایل از مسیر فعلی به مسیر مقصد
        // ...
    }

    public void DeleteFile()
    {
        // حذف فایل از مسیر فعلی
        // ...
    }

    public void MoveFile(string destinationPath)
    {
        // انتقال فایل به مسیر مقصد
        // ...
    }
}

کلاس با نام‌گذاری نامناسب:
// نام‌گذاری نامناسب
public class XYZ
{
    private string abc;

    public XYZ(string def)
    {
        abc = def;
    }

    public void MNO(string ghi)
    {
        // ...
    }

    public void PQR()
    {
        // ...
    }

    public void STU(string jkl)
    {
        // ...
    }
}
در کلاس FileManager با نام‌گذاری مناسب، نام کلاس و متدها به وضوح نشان‌دهنده عملکرد آنها هستند. در مقابل، کلاس XYZ با نام‌گذاری نامناسب، نام متغیرها و متدها به کسری از اطلاعات لازم برای درک عملکرد آنها اشاره دارد. استفاده از نام‌های مناسب به افزایش خوانایی و نگهداری کد کمک می‌کند و ایجاد ابهام در نام‌گذاری نامناسب می‌تواند به کاهش کیفیت کد منجر شود.
 
استفاده از الگوهای طراحی: Clean Code از الگوهای طراحی معمولاً برای حل مشکلات استفاده می‌کند و از تکرار و کد تکراری جلوگیری می‌کند.
"Clean Code" اصول و الگوهای مختلفی را برای نوشتن کد به شکل خوانا، قابل نگهداری، و با کیفیت ترویج می‌دهد. از الگوهای طراحی نیز برای حل مسائل و بهبود ساختار کد استفاده می‌کند. الگوهای طراحی به صورت عمده در کتاب "Design Patterns: Elements of Reusable Object-Oriented Software" نوشته‌شده توسط Erich Gamma، Richard Helm، Ralph Johnson و John Vlissides مطرح شده‌اند. در زیر به توضیح تعدادی از الگوهای طراحی و نحوه ارتباط آنها با Clean Code می‌پردازیم:
1. Singleton Pattern (الگوی تک‌نمونه):
این الگو برای تضمین اینکه یک کلاس فقط یک نمونه از خود را داشته باشد و دسترسی به آن نمونه را از طریق یک نقطه ارائه می‌دهد. این الگو می‌تواند به بهبود مدیریت منابع و کاهش اشتباهات مرتبط با تعداد زیاد نمونه‌ها کمک کند.
public class Singleton
{
    private static Singleton instance;

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }

    public void DisplayMessage()
    {
        Console.WriteLine("Hello from Singleton!");
    }
}

2. Factory Method Pattern (الگوی متد کارخانه):
این الگو برای ایجاد یک محصول در دسته‌ای از محصولات مشخص استفاده می‌شود. این امکان را فراهم می‌کند که یک کلاس خود را از ایجاد نمونه‌های خاص مسئول سازهای فرعی کند. این الگو به ما کمک می‌کند تا ایجاد شیء را از جزئیات پنهان کرده و از ابتدا ساختار اشیاء را مشخص کنیم.
public interface IProduct
{
    void DisplayInfo();
}

public class ConcreteProductA : IProduct
{
    public void DisplayInfo()
    {
        Console.WriteLine("Product A");
    }
}

public class ConcreteProductB : IProduct
{
    public void DisplayInfo()
    {
        Console.WriteLine("Product B");
    }
}

public abstract class Creator
{
    public abstract IProduct FactoryMethod();
}

public class ConcreteCreatorA : Creator
{
    public override IProduct FactoryMethod()
    {
        return new ConcreteProductA();
    }
}

public class ConcreteCreatorB : Creator
{
    public override IProduct FactoryMethod()
    {
        return new ConcreteProductB();
    }
}


3. Observer Pattern (الگوی مشاهده‌گر):
در الگوی مشاهده‌گر، یک شیء (مشاهده‌شونده) تغییرات خود را به یک یا چند شیء (مشاهده‌گر) اطلاع می‌دهد. این الگو برای پیاده‌سازی رابطه‌های یک به چند بین شیء مشاهده‌شونده و مشاهده‌گرها مفید است و می‌تواند به کاهش وابستگی‌ها و افزایش انعطاف‌پذیری در کد کمک کند.
using System;
using System.Collections.Generic;

public interface IObserver
{
    void Update(string message);
}

public class ConcreteObserver : IObserver
{
    private string name;

    public ConcreteObserver(string name)
    {
        this.name = name;
    }

    public void Update(string message)
    {
        Console.WriteLine($"{name} received message: {message}");
    }
}

public class ConcreteSubject
{
    private List<IObserver> observers = new List<IObserver>();

    public void AddObserver(IObserver observer)
    {
        observers.Add(observer);
    }

    public void RemoveObserver(IObserver observer)
    {
        observers.Remove(observer);
    }

    public void NotifyObservers(string message)
    {
        foreach (var observer in observers)
        {
            observer.Update(message);
        }
    }
}

4. Strategy Pattern (الگوی استراتژی):
این الگو به شیوه‌ای امکان تعویض رفتارها یا الگوریتم‌ها در یک کلاس را فراهم می‌کند بدون اینکه کد مشترک را تغییر دهد. با استفاده از این الگو، می‌توان مفهومی متغیر مانند الگوریتم‌ها را جدا از کلاسی که از آن استفاده می‌کند نگه داشت.
public interface IStrategy
{
    void Execute();
}

public class ConcreteStrategyA : IStrategy
{
    public void Execute()
    {
        Console.WriteLine("Executing Strategy A");
    }
}

public class ConcreteStrategyB : IStrategy
{
    public void Execute()
    {
        Console.WriteLine("Executing Strategy B");
    }
}

public class Context
{
    private IStrategy strategy;

    public Context(IStrategy strategy)
    {
        this.strategy = strategy;
    }

    public void ExecuteStrategy()
    {
        strategy.Execute();
    }
}

5. Command Pattern (الگوی دستور):
این الگو برای پیکربندی یک درخواست به عنوان یک شیء کاربرد دارد. این الگو به ما امکان می‌دهد تا درخواست، پارامترها و عملیات را به یک شیء پیکربندی کرده و آن را به عنوان یک شیء ذخیره کنیم، برای مثال برای استفاده در یک صف یا یک باز‌گرا.
public interface ICommand
{
    void Execute();
}

public class ConcreteCommand : ICommand
{
    private Receiver receiver;

    public ConcreteCommand(Receiver receiver)
    {
        this.receiver = receiver;
    }

    public void Execute()
    {
        receiver.Action();
    }
}

public class Receiver
{
    public void Action()
    {
        Console.WriteLine("Receiver is performing an action");
    }
}

public class Invoker
{
    private ICommand command;

    public void SetCommand(ICommand command)
    {
        this.command = command;
    }

    public void ExecuteCommand()
    {
        command.Execute();
    }
}
استفاده از این الگوها به تنهایی یا در ترکیب با یکدیگر، به نوشتن کدی که ساده، قابل نگهداری، و قابل توسعه باشد، کمک می‌کند. الگوهای طراحی Clean Code به توسعه‌دهندگان کمک می‌کنند تا بهبود عملکرد و ساختار کد را دست یابند و از تکرارهای ناکارآمد جلوگیری کنند.

کاهش تکرار: تکرار در کد به بی‌ترتیبی و کاهش کیفیت منجر می‌شود. Clean Code تلاش می‌کند تا از تکرارهای غیرضروری جلوگیری کند.
کد مشترک را در توابع یا کلاس‌ها جمع‌آوری کنید:
درصورتی که قسمتی از کد در چندین قسمت استفاده می‌شود، بهتر است آن قسمت کد را به یک تابع یا یک کلاس جداگانه منتقل کنید. این کار باعث می‌شود تغییرات در این بخش‌ها تنها در یک مکان اعمال شوند و از تکرار کد جلوگیری شود.
// کد تکراری
int CalculateAreaOfRectangle(int length, int width)
{
    return length * width;
}

int CalculateAreaOfSquare(int side)
{
    return side * side;
}

// کد بهینه‌تر
int CalculateArea(int side)
{
    return side * side;
}

int CalculateArea(int length, int width)
{
    return length * width;
}
استفاده از توابع و متغیرها:
اگر قسمتی از کد در یک تابع تکرار شود، بهتر است آن تکرار را با استفاده از یک تابع جداگانه کاهش دهید. همچنین، از متغیرها برای ذخیره مقادیر تکراری استفاده کنید.
// کد تکراری
double CalculateCircleArea(double radius)
{
    return Math.PI * radius * radius;
}

double CalculateCircleCircumference(double radius)
{
    return 2 * Math.PI * radius;
}

// کد بهینه‌تر
double CalculateCircleArea(double radius)
{
    return Math.PI * Math.Pow(radius, 2);
}

double CalculateCircleCircumference(double radius)
{
    return 2 * Math.PI * radius;
}
استفاده از الگوهای طراحی:
الگوهای طراحی، مانند الگوی استراتژی، می‌توانند به کاهش تکرار و افزایش انعطاف‌پذیری کمک کنند. به‌ویژه الگوهایی که امکان استفاده مجدد از کد را فراهم می‌کنند می‌توانند تکرار را به شدت کاهش دهند.
// کد تکراری
if (condition)
{
    // بخش 1
    // ...
}
else
{
    // بخش 2
    // ...
}

// کد بهینه‌تر با الگوی استراتژی
IStrategy strategy;
if (condition)
{
    strategy = new StrategyA();
}
else
{
    strategy = new StrategyB();
}
strategy.Execute();
 
کاهش تکرار در Clean Code بهبود خوانایی، نگهداری، و توسعه کد را تسهیل می‌کند. این اصل به‌طور مستقیم با اصل "خوانایی بالا" (Readability) و "سادگی" (Simplicity) نیز مرتبط است.

قابلیت تست: Clean Code باید قابلیت تست و اعتبارسنجی را داشته باشد. این به معنای آن است که می‌توان به راحتی تست‌های واحد یا تست‌های یکپارچه را بر روی کد اجرا کرد. قابلیت تست یکی از اصول معماری Clean Code است که به معنای این است که کد باید به راحتی تست شود و این امکان را فراهم کند که تست‌های واحد (Unit Tests) یا تست‌های یکپارچه (Integration Tests) بر روی آن اجرا شوند. برای دستیابی به این هدف، معمولاً از اصولی مانند اصل Dependency Injection و اصل Inversion of Control (IoC) نیز استفاده می‌شود. در زیر چند نکته و کد نمونه برای توضیح این اصل آورده شده است:
1. استفاده از Dependency Injection (DI):
Dependency Injection یکی از اصولی است که در Clean Code برای ایجاد لایه‌های مستقل از یکدیگر به کار می‌رود. این اصل به کاهش وابستگی‌ها و افزایش تست‌پذیری کد کمک می‌کند.
// بدون استفاده از DI
public class ProductService
{
    private DatabaseContext dbContext;

    public ProductService()
    {
        dbContext = new DatabaseContext();
    }

    public List<Product> GetProducts()
    {
        return dbContext.Products.ToList();
    }
}

// با استفاده از DI
public class ProductService
{
    private readonly IDatabaseContext dbContext;

    public ProductService(IDatabaseContext dbContext)
    {
        this.dbContext = dbContext;
    }

    public List<Product> GetProducts()
    {
        return dbContext.Products.ToList();
    }
}
2. ایجاد کلاس‌های قابل تست:
کلاس‌های Clean Code باید به گونه‌ای باشند که بتوانند به راحتی توسط تست‌های واحد امتحان شوند. این به معنای جدا کردن منطق کسب‌وکار از جزئیات پیاده‌سازی و ایجاد کلاس‌هایی با واجدیت‌های تست‌پذیر است.
// بدون قابلیت تست
public class MathOperations
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}

// با قابلیت تست
public class MathOperations
{
    public virtual int Add(int a, int b)
    {
        return a + b;
    }
}
3. استفاده از Interfacing برای Mocking:
استفاده از رابطها (Interfaces) به شما این امکان را می‌دهد که برای تست کد، از شیء‌های Mock (شبیه‌ساز) استفاده کنید.

public interface IEmailSender
{
    void SendEmail(string to, string subject, string body);
}

public class UserManager
{
    private readonly IEmailSender emailSender;

    public UserManager(IEmailSender emailSender)
    {
        this.emailSender = emailSender;
    }

    public void RegisterUser(string email, string password)
    {
        // اعتبارسنجی و ثبت نام کاربر

        // ارسال ایمیل به کاربر برای تایید
        emailSender.SendEmail(email, "Registration Confirmation", "Please confirm your registration.");
    }
}
4. ایجاد تست‌های واحد:
تست‌های واحد به شما کمک می‌کنند تا تکنیک‌های کد را امتحان کنید و اطمینان حاصل کنید که کد به درستی عمل می‌کند.
[TestFixture]
public class MathOperationsTests
{
    [Test]
    public void Add_ShouldReturnSumOfTwoNumbers()
    {
        // Arrange
        MathOperations math = new MathOperations();

        // Act
        int result = math.Add(2, 3);

        // Assert
        Assert.AreEqual(5, result);
    }
}
توجه به این اصل به تست‌پذیری و اعتبارسنجی کد کمک می‌کند و باعث افزایش اطمینان از صحت عملکرد کد می‌شود. این امر به توسعه‌دهندگان امکان می‌دهد با آرامش تر تغییرات را اعمال کنند و از وجود باگ‌ها کاسته و یا اصلاح شوند.

کد قابل نگهداری: Clean Code باید به سادگی قابل نگهداری باشد. هر کدی که نیاز به تغییر دارد، باید به سهولت قابل تغییر باشد.
کلاس قابل نگهداری:
مفهوم قابل نگهداری بودن کد به این معناست که کد به سادگی قابل فهم، تغییر، و اصلاح باشد. این امکان برای توسعه‌دهندگان ضروری است تا بتوانند کد را با آسانی مدیریت کرده و بهبودهای لازم را اعمال کنند.
نمونه کد:
در اینجا یک نمونه کد C# برای یک کلاس Customer آورده شده است که با اصول Clean Code نوشته شده و قابل نگهداری است:
public class Customer
{
    private string firstName;
    private string lastName;
    private DateTime birthDate;
    private string email;

    // Constructor
    public Customer(string firstName, string lastName, DateTime birthDate, string email)
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.birthDate = birthDate;
        this.email = email;
    }

    // Properties
    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; }
    }

    public string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }

    public DateTime BirthDate
    {
        get { return birthDate; }
        set { birthDate = value; }
    }

    public string Email
    {
        get { return email; }
        set { email = value; }
    }

    // Methods
    public int CalculateAge()
    {
        DateTime currentDate = DateTime.Now;
        int age = currentDate.Year - birthDate.Year;

        // Adjust age if the birthday hasn't occurred yet this year
        if (birthDate > currentDate.AddYears(-age))
            age--;

        return age;
    }

    public bool IsAdult()
    {
        int age = CalculateAge();
        return age >= 18;
    }

    public void DisplayCustomerInfo()
    {
        Console.WriteLine($"Name: {FirstName} {LastName}");
        Console.WriteLine($"Birth Date: {BirthDate.ToShortDateString()}");
        Console.WriteLine($"Email: {Email}");
        Console.WriteLine($"Age: {CalculateAge()}");
        Console.WriteLine($"Adult: {IsAdult()}");
    }
}
ویژگی‌های کد قابل نگهداری:
Clear and Meaningful Names (نام‌گذاری واضح و معنادار): نام‌گذاری متغیرها، توابع و ویژگی‌ها به شکل واضح و معنادار است، که اطلاعات لازم برای فهم کد را فراهم می‌کند.
Encapsulation (تغلیظ): اطلاعات مرتبط با هر شیء (مانند Customer) در داخل کلاس مربوط به آن قرار گرفته و از تغلیظ (Encapsulation) استفاده شده است.
Readability (خوانایی): کد به شکل خوانا و ساختاردهی شده است. توابع کوچک با یک مسئولیت واحد دارند.
SOLID Principles (اصول SOLID): اصول SOLID (Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion) رعایت شده‌اند تا کد به اندازه ممکن انعطاف‌پذیر باشد و تغییرات به راحتی قابل اعمال باشند.
Comments (توضیحات): توضیحات اندک و ضروری برای فهم کد به اضافه شده‌اند. توضیحات اضافه برای توضیح قراردادهای خاص یا روش‌های پیچیده بکار رفته است.
Testability (قابلیت تست): از Dependency Injection برای اینکه قابلیت تست‌پذیری را افزایش دهد. توابع به شکلی نوشته‌شده‌اند که به راحتی تست‌های واحد را اجرا کنند.
Consistent Formatting (قالب‌بندی یکنواخت): کد با یک قالب‌بندی یکنواخت نوشته شده است که به سادگی قابل مدیریت است.
با توجه به این ویژگی‌ها، این کد به خوبی از اصول Clean Code پیروی کرده و قابلیت نگهداری و تست‌پذیری بالا را داراست.
تغییریابی (Changeability): Clean Code باید به راحتی قابل تغییر و گسترش باشد بدون اینکه برای انجام تغییرات نیاز به تغییرات گسترده در سایر بخش‌ها باشد.
توضیح Clean Code با تاکید بر تغییریابی (Changeability)
Clean Code یک مفهوم گسترده است که به مجموعه‌ای از اصول و رویه‌ها اشاره دارد که به تولید کد خوانا، قابل نگهداری، و قابل توسعه کمک می‌کنند. اما توجه به اصل تغییریابی یکی از جنبه‌های حیاتی Clean Code است. این اصل به معنای این است که کد باید به راحتی تغییر و گسترش پذیر باشد، بدون اینکه نیاز به تغییرات گسترده در سایر بخش‌ها یا باعث ایجاد خطاهای غیرمنتظره شود.

نکات برای تغییریابی در Clean Code:
1- Single Responsibility Principle (اصل مسئولیت واحد):
هر کلاس و تابع باید یک مسئولیت واحد داشته باشد. این باعث می‌شود تغییرات مرتبط به یک قسمت از سیستم، تنها در یک مکان اعمال شود.
// قبل از تغییریابی
public class ReportGenerator
{
    public void GenerateReport()
    {
        // گسترش وظایف به تولید فایل PDF
        // ...
    }
}

// بعد از تغییریابی
public class ReportGenerator
{
    public void GenerateReport()
    {
        // گسترش تولید گزارش
        // ...
    }

    public void GeneratePdf()
    {
        // اضافه کردن تولید فایل PDF
        // ...
    }
}

2- Dependency Inversion Principle (اصل وابستگی برعکس):
استفاده از وابستگی برعکس (Dependency Inversion) به شما کمک می‌کند که کدهای مبتنی بر abstraction (انتزاع) باشند و تغییرات در دیتیل‌ها (جزئیات) تاثیر کمتری داشته باشند.
// قبل از تغییریابی
public class ReportService
{
    private DatabaseConnection databaseConnection;

    public ReportService(DatabaseConnection databaseConnection)
    {
        this.databaseConnection = databaseConnection;
    }

    public void GenerateReport()
    {
        // استفاده از اتصال به دیتابیس
        // ...
    }
}

// بعد از تغییریابی
public class ReportService
{
    private IDatabaseConnection databaseConnection;

    public ReportService(IDatabaseConnection databaseConnection)
    {
        this.databaseConnection = databaseConnection;
    }

    public void GenerateReport()
    {
        // استفاده از اتصال به دیتابیس
        // ...
    }
}
3- Open/Closed Principle (اصل باز بسته):
این اصل به این معناست که یک کلاس باید باز برای گسترش و بسته برای تغییر باشد. از این اصل برای افزودن ویژگی‌ها یا تغییر کد بدون ایجاد تغییرات گسترده استفاده می‌شود.
// قبل از تغییریابی
public class PaymentProcessor
{
    public void ProcessPayment(Order order)
    {
        // پردازش پرداخت
        // ...
    }
}

// بعد از تغییریابی
public class PaymentProcessor
{
    public virtual void ProcessPayment(Order order)
    {
        // پردازش پرداخت
        // ...
    }
}

public class CreditCardPaymentProcessor : PaymentProcessor
{
    public override void ProcessPayment(Order order)
    {
        // پردازش پرداخت با کارت اعتباری
        // ...
    }
}
4- Interface Segregation Principle (اصل جداسازی رابطه):
تاکید بر جدا نگه‌داشتن رابطه‌ها و ارائه رابطه‌های کوچک و مرتبط با یک وظیفه خاص.
// قبل از تغییریابی
public interface IWorker
{
    void Work();
    void TakeBreak();
}

// بعد از تغییریابی
public interface IWorker
{
    void Work();
}
 
public interface IWorkerWithBreak
{
    void TakeBreak();
}
5- Composition Over Inheritance (ترکیب به جای ارث‌بری):
تاکید بر استفاده از ترکیب و انتزاع (Composition and Abstraction) به جای ارث‌بری. این کمک می‌کند تا کلاس‌ها کمتر وابسته به ساختار ارث‌بری باشند و از این راه تغییرات گسترده در سلسله مراتب کلاس‌ها ایجاد نشود.

// قبل از تغییریابی
public class OrderProcessor : DiscountProcessor
{
    // پردازش سفارش با تخفیف
}

// بعد از تغییریابی
public class OrderProcessor
{
    private readonly IDiscountCalculator discountCalculator;

    public OrderProcessor(IDiscountCalculator discountCalculator)
    {
        this.discountCalculator = discountCalculator;
    }
 
    // پردازش سفارش با تخفیف
}
با اعمال این اصول، کد به راحتی قابل تغییر و گسترش است و تغییرات محدود به بخش‌های مربوطه اعمال می‌شوند، بدون اینکه تغییرات گسترده و ناخواسته در سایر قسمت‌ها ایجاد شود. این موارد باعث افزایش توسعه‌پذیری و انعطاف‌پذیری کد می‌شوند.
یک مثال ساده و کلی از Clean Code:
 
// کد نه تمیز
public class MyClass
{
    public int a, b;

    public int AddNumbers()
    {
        return a + b;
    }
}

// کد تمیز
public class Calculator
{
    private int operand1, operand2;

    public Calculator(int operand1, int operand2)
    {
        this.operand1 = operand1;
        this.operand2 = operand2;
    }

    public int Add()
    {
        return operand1 + operand2;
    }
}
در این مثال، کد "تمیز" از نظر نام‌گذاری، انتزاع، و کاهش تکرار بهتر است. Class Calculator از اصول Clean Code پیروی کرده و قابلیت فهم و تغییر آسان تری دارد.
مثال 1: استفاده از نام‌های مناسب
کد تمیز باید از نام‌های مناسب و توضیح‌دهنده برای متغیرها، توابع و کلاس‌ها استفاده کند.
// کد نا تمیز
int a = 10;
int b = 20;
int result = a + b;
Console.WriteLine("Result: " + result);

// کد تمیز
int firstNumber = 10;
int secondNumber = 20;
int sum = firstNumber + secondNumber;
Console.WriteLine("Sum: " + sum);
مثال 2: تجزیه و تحلیل توابع
توابع باید وظایف مشخص و کوچکی داشته باشند. این اصل به اصل SRP (Single Responsibility Principle) مرتبط است.

// کد نا تمیز
public void ProcessData()
{
    // انجام محاسبات
    // ارسال ایمیل
    // ذخیره در پایگاه داده
}

// کد تمیز
public void ProcessData()
{
    Calculate();
    SendEmail();
    SaveToDatabase();
}

private void Calculate()
{
    // انجام محاسبات
}

private void SendEmail()
{
    // ارسال ایمیل
}

private void SaveToDatabase()
{
    // ذخیره در پایگاه داده
}
مثال 3: کاهش تکرار
تکرار باید حداقل باشد. اگر قسمتی از کد در چندین قسمت استفاده می‌شود، بهتر است آن را به یک تابع منفصل منتقل کنید.
// کد نا تمیز
int area1 = length * width;
int area2 = length * width;
int area3 = length * width;

// کد تمیز
int area = CalculateArea(length, width);

private int CalculateArea(int length, int width)
{
    return length * width;
}
این مثال‌ها نشان‌دهنده برخی از اصول کلی Clean Code هستند که می‌توانند به افزایش خوانایی، نگهداری، و قابلیت توسعه کد کمک کنند.

 

1 نظر

ارسال شده توسط علی حمید زاده
1402/09/28

سپاس بابت انتشار این مقاله پر محتوا و ارزشمند.

نظر محترم شما در مورد مقاله های وب سایت برنامه نویسی و پایگاه داده

نظرات محترم شما در خدمات رسانی بهتر ما را یاری می نمایند. لطفا اگر مایل بودید یک نظر ما را مهمان فرمائید. آدرس ایمیل و وب سایت شما نمایش داده نخواهد شد.

حرف 500 حداکثر