menusearch
javapro.ir

10 نکته سریع برای نوشتن کد تمیز

جستجو
سه شنبه ۲۵ شهریور ۱۴۰۴ | ۱۳:۵۹:۳۴
۱۴۰۴/۶/۲۵ سه شنبه
(1)
(0)
10 نکته سریع برای نوشتن کد تمیز
10 نکته سریع برای نوشتن کد تمیز

 

شیوه و اصول کدنویسی تمیز

 

۱۰ نکته سریع برای نوشتن کد تمیز

یکی از مهم‌ترین ویژگی‌های سیستم‌هایی که طراحی خوبی دارن و عمر طولانی می‌کنن، اینه که بتونن با تغییر نیازمندی‌ها سازگار بشن و در عین حال نگهداری ساده‌ای داشته باشن. وقتی اصول کدنویسی تمیز (Clean Code) رو رعایت کنیم، کدهامون خواناتر می‌شن؛ و این خوانایی خیلی مهمه چون واقعیت اینه که بخش عمده زمان یک برنامه‌نویس صرف خواندن کد می‌شه، نه نوشتن اون.

اینجا ۱۰ نکته سریع آوردم که بهت کمک می‌کنه کدی تمیزتر و حرفه‌ای‌تر بنویسی.

۱. متدها رو کوتاه نگه دار — ترجیحاً زیر ۱۰ خط

سعی کن متدها بیشتر از ۱۰ خط نشه. متدهای کوتاه هم راحت‌تر خونده می‌شن، هم ساده‌تر تست و نگهداری می‌شن. هر وقت دیدی یک متد زیادی بزرگ شده، بهترین کار اینه که اون رو به چند متد کوچیک‌تر تقسیم کنی؛ متدهایی که هر کدوم یک وظیفه مشخص رو انجام بدن. یه نشونه خوب برای فهمیدن اینکه متدت زیادی بزرگ شده اینه که نتونی براش یه اسم کوتاه و دقیق پیدا کنی. وقتی اسم‌گذاری برات سخت می‌شه، یعنی احتمالا متدت داره چندین کار رو همزمان انجام می‌ده و باید خرد بشه.

 

/ Original
public double calculatePrice(int customerId, int productId, int quantity) {
    Product product = productRepository.findById(productId);

    double singlePrice = product.getSinglePrice();
    double baseTotal = singlePrice * quantity;

    double taxRate = 0.07;
    double totalWithTax = baseTotal + (baseTotal * taxRate);

    double discount = 0.0;
    double loyaltyDiscount = 0.0;
    double bulkDiscount = 0.0;

    Customer customer = customerRepository.findById(customerId);

    if (customer.isSilver()) {
        discount = 0.10;
        if (quantity > 10) {
            bulkDiscount = 0.05;
        }
    } else if (customer.isGold()) {
        discount = 0.15;
        if (quantity > 5) {
            bulkDiscount = 0.10;
        }
    } else if (customer.isPlatinum()) {
        discount = 0.20;
        if (quantity > 3) {
            bulkDiscount = 0.15;
        }
    }

    if (customer.getYearsAsCustomer() > 5) {
        loyaltyDiscount = 0.03;
    }

    double totalDiscount = discount + bulkDiscount + loyaltyDiscount;
    if (totalDiscount > 0.30) {
        totalDiscount = 0.30;
    }

    double discountedPrice = totalWithTax - (totalWithTax * totalDiscount);
    double finalPrice = Math.round(discountedPrice * 100.0) / 100.0;

    return finalPrice;
}

 

 

 

// After Refactoring
public double calculatePrice(int customerId, int productId, int quantity) {
    Product product = productRepository.findById(productId);
    Customer customer = customerRepository.findById(customerId);

    double baseTotal = calculateBaseTotal(product, quantity);
    double totalWithTax = applyTax(baseTotal);
    double totalDiscount = calculateTotalDiscount(customer, quantity);
    double discountedPrice = applyDiscount(totalWithTax, totalDiscount);

    return roundToTwoDecimalPlaces(discountedPrice);
}

private double calculateBaseTotal(Product product, int quantity) {
    return product.getSinglePrice() * quantity;
}

private double applyTax(double baseTotal) {
    double taxRate = 0.07;
    return baseTotal + (baseTotal * taxRate);
}

private double calculateTotalDiscount(Customer customer, int quantity) {
    double tierDiscount = calculateTierDiscount(customer, quantity);
    double loyaltyDiscount = calculateLoyaltyDiscount(customer);
    double totalDiscount = tierDiscount + loyaltyDiscount;

    return Math.min(totalDiscount, 0.30);
}

private double calculateTierDiscount(Customer customer, int quantity) {
    double discount = 0.0;
    double bulkDiscount = 0.0;

    if (customer.isSilver()) {
        discount = 0.10;
        if (quantity > 10) bulkDiscount = 0.05;
    } else if (customer.isGold()) {
        discount = 0.15;
        if (quantity > 5) bulkDiscount = 0.10;
    } else if (customer.isPlatinum()) {
        discount = 0.20;
        if (quantity > 3) bulkDiscount = 0.15;
    }

    return discount + bulkDiscount;
}

private double calculateLoyaltyDiscount(Customer customer) {
    return customer.getYearsAsCustomer() > 5 ? 0.03 : 0.0;
}

private double applyDiscount(double total, double discountRate) {
    return total - (total * discountRate);
}

private double roundToTwoDecimalPlaces(double value) {
    return Math.round(value * 100.0) / 100.0;
}



۲. کلاس‌ها رو کوتاه نگه دار — ترجیحاً زیر ۲۰۰ خط

این نکته تقریباً واضحه. وقتی یک کلاس زیر ۲۰۰ خط باشه، معمولاً داری یکی از اصول مهم SOLID یعنی Single Responsibility رو رعایت می‌کنی. کلاس‌های کوچک‌تر چندتا مزیت خیلی مهم دارن:

  • دیباگ کردن ساده‌تر می‌شه
  • ریفکتور کردن راحت‌تر می‌شه
  • تست‌نویسی سریع‌تر انجام می‌شه
  • جایگزین کردنش با پیاده‌سازی‌های دیگه آسون‌تره

۳. تعداد متدهای عمومی رو به یک یا دو تا محدود کن

وقتی یک کلاس فقط برای انجام یک کار مشخص طراحی شده (طبق اصل Single Responsibility)، معمولاً نیازی نداره چندین متد عمومی داشته باشه. اگه بیشتر از یک متد پابلیک تعریف می‌کنی، باید دلیل منطقی پشتش باشه؛ مثلاً وقتی داری متدها رو Overload می‌کنی تا استفاده از کلاس برای Caller ساده‌تر بشه. مهم اینه که این کار رو آگاهانه انجام بدی، نه از روی عادت.

۴. از کامنت‌گذاری زیاد خودداری کن

در بیشتر مواقع کامنت‌ها رو می‌شه با نام‌گذاری درست متدها جایگزین کرد. بذار کدت خودش حرف بزنه. اگه اسم متدها و کلاس‌هات واضح و گویا باشه، نیاز به توضیح اضافه توی کامنت‌ها از بین می‌ره.

 

// With Comments
private void validateProduct(Product product) {
    // Check if the product is null
    if (product == null) {
        throw new IllegalArgumentException("Product cannot be null");
    }

    // Check if the product has a valid name
    if (product.getName() == null || product.getName().trim().isEmpty()) {
        throw new IllegalArgumentException("Product must have a name");
    }

    // Check if the product price is greater than zero
    if (product.getSinglePrice() <= 0) {
        throw new IllegalArgumentException("Product price must be greater than zero");
    }

    // Check if the product category is valid
    if (!isValidCategory(product.getCategory())) {
        throw new IllegalArgumentException("Invalid product category: " + product.getCategory());
    }

    // Check if the product is active
    if (!product.isActive()) {
        throw new IllegalStateException("Product must be active");
    }
}

private boolean isValidCategory(String category) {
    return category != null && List.of("Electronics", "Books", "Clothing", "Food").contains(category);
}

 

 

 

// Without comments
private void validateProduct(Product product) {
    ensureProductIsNotNull(product);
    ensureProductHasName(product);
    ensurePriceIsPositive(product);
    ensureCategoryIsValid(product);
    ensureProductIsActive(product);
}

private void ensureProductIsNotNull(Product product) {
    if (product == null) {
        throw new IllegalArgumentException("Product cannot be null");
    }
}

private void ensureProductHasName(Product product) {
    if (product.getName() == null || product.getName().trim().isEmpty()) {
        throw new IllegalArgumentException("Product must have a name");
    }
}

private void ensurePriceIsPositive(Product product) {
    if (product.getSinglePrice() <= 0) {
        throw new IllegalArgumentException("Product price must be greater than zero");
    }
}

private void ensureCategoryIsValid(Product product) {
    if (!isValidCategory(product.getCategory())) {
        throw new IllegalArgumentException("Invalid product category: " + product.getCategory());
    }
}

private void ensureProductIsActive(Product product) {
    if (!product.isActive()) {
        throw new IllegalStateException("Product must be active");
    }
}

private boolean isValidCategory(String category) {
    return category != null && List.of("Electronics", "Books", "Clothing", "Food").contains(category);
}

 

5. ترجیح بده فقط یک Return داشته باشی

وجود چندین دستور return همیشه مشکل‌ساز نیست، اما می‌تونه باعث بروز خطا بشه؛ مخصوصاً وقتی که تست‌ها کامل و پوشش‌دهی خوبی نداشته باشن. داشتن یک نقطه خروجی مشخص باعث می‌شه منطق شرطی (branching logic) توی کدت شفاف‌تر بشه و قبل از انتشار راحت‌تر فرصت ریفکتور کردن داشته باشی.

 

// With multiple returns
private double calculateProductDiscount(Customer customer, int quantity) {
    if (customer.isPlatinum()) {
        if (quantity > 10) {
            return 0.25;
        }
        return 0.20;
    }

    if (customer.isGold()) {
        if (quantity > 10) {
            return 0.20;
        }
        return 0.15;
    }

    if (customer.isSilver()) {
        if (quantity > 10) {
            return 0.15;
        }
        return 0.10;
    }

    return 0.0;
}

کد بعدی

//With single return
private double calculateProductDiscount(Customer customer, int quantity) {
    double discount = 0.0;

    if (customer.isPlatinum()) {
        discount = (quantity > 10) ? 0.25 : 0.20;
    } else if (customer.isGold()) {
        discount = (quantity > 10) ? 0.20 : 0.15;
    } else if (customer.isSilver()) {
        discount = (quantity > 10) ? 0.15 : 0.10;
    }

    return discount;
}

 

6. از final برای متغیرها و پارامترها استفاده کن

در برنامه‌های مدرن، به‌خصوص وقتی با عملیات بیت‌محور حساس به عملکرد سروکار نداری، بهتره متغیرها و پارامترها رو final اعلام کنی. وقتی یک مقدار بهش اختصاص داده شد، دیگه نباید تغییر کنه. این کار باعث می‌شه اسم متغیر با هدفش همخوانی داشته باشه و احتمال اشتباه کمتر بشه.
البته گاهی متغیرها باید تغییر کنن (مثل همون چیزی که اسمشون نشون می‌ده)، اما این موارد باید استثنا باشن، نه قاعده.

۷. کلاس‌های Utility بدون Attribute

این نکته خودش واضحه. اگه به یک کلاس Utility ویژگی (attribute) اضافه می‌کنی، دیگه اون کلاس Utility محسوب نمی‌شه. کلاس‌های Utility باید فقط شامل عملیات استاتیک باشن که روی پارامترهایی که دریافت می‌کنن کار می‌کنن، مثل متدهای دستکاری رشته‌ها (toLowerCase، isEmpty) که تو خیلی از کتابخونه‌ها هستن.

۸. کلاس‌های Utility رو به کلاس‌های Instantiable منتقل کن

اگه چند کلاس Utility داری، یا یک کلاس Utility با متدهای زیاد، ممکنه وقتش رسیده باشه بعضی متدها یا حتی کل کلاس رو به کلاس‌های معمولی قابل نمونه‌سازی (instantiable) منتقل کنی. این روش نگهداری کد رو بهتر می‌کنه، تست واحد (unit testing) رو راحت‌تر می‌کنه، امکان Dependency Injection رو فراهم می‌کنه و با اصول طراحی شیءگرای SOLID همخوانی داره.

۹. پیچیدگی سایکلوماتیک (Cyclomatic Complexity) رو زیر ۵ نگه دار

پیچیدگی سایکلوماتیک یکی از معیارهای مهم کیفیت کده. نگه داشتن این عدد زیر ۵ باعث می‌شه کدت راحت‌تر فهمیده، تست و نگهداری بشه.

 

public String determineAccessLevel(User user, Resource resource) {
    if (user == null || resource == null) {
        return "DENIED";
    }

    if (!user.isActive()) {
        return "DENIED";
    }

    if (user.isAdmin()) {
        return "FULL_ACCESS";
    } else if (user.isManager() && resource.isInternal()) {
        return "limitED_ACCESS";
    } else if (user.isEmployee()) {
        switch (resource.getType()) {
            case "PUBLIC":
                return "READ_ONLY";
            case "CONFIDENTIAL":
                if (user.hasClearance()) {
                    return "limitED_ACCESS";
                } else {
                    return "DENIED";
                }
            default:
                return "DENIED";
        }
    }

    return "DENIED";
}

 


برای کاهش پیچیدگی، کد را به متدهای با نام مناسب تقسیم کن

برای کاهش پیچیدگی، بخش‌های مختلف کد رو به متدهای کوچک و با اسم‌های واضح و گویا تقسیم کن. این کار هم خوانایی منطق کد رو بالا می‌بره و هم باعث می‌شه ساختار برنامه ماژولار باشه، یعنی هر بخش وظیفه مشخص خودش رو داشته باشه و تغییر یا تستش راحت‌تر باشه.

 

public String determineAccessLevel(User user, Resource resource) {
    String accessLevel;

    if (isInvalid(user, resource)) {
        accessLevel = "DENIED";
    } else if (isAdmin(user)) {
        accessLevel = "FULL_ACCESS";
    } else if (isManagerAccess(user, resource)) {
        accessLevel = "limitED_ACCESS";
    } else if (isEmployee(user)) {
        accessLevel = getEmployeeAccessLevel(user, resource);
    } else {
        accessLevel = "DENIED";
    }

    return accessLevel;
}

private boolean isInvalid(User user, Resource resource) {
    return user == null || resource == null || !user.isActive();
}

private boolean isAdmin(User user) {
    return user.isAdmin();
}

private boolean isManagerAccess(User user, Resource resource) {
    return user.isManager() && resource.isInternal();
}

private boolean isEmployee(User user) {
    return user.isEmployee();
}

private String getEmployeeAccessLevel(User user, Resource resource) {
    switch (resource.getType()) {
        case "PUBLIC":
            return "READ_ONLY";
        case "CONFIDENTIAL":
            return user.hasClearance() ? "limitED_ACCESS" : "DENIED";
        default:
            return "DENIED";
    }
}

 


10. به جای Constants از Enums استفاده کن

استفاده از Enums به جای Constants چند مزیت مهم داره:

ایمنی نوع (Type safety): Enums در زمان کامپایل بررسی می‌شن و از اختصاص دادن مقادیر اشتباه جلوگیری می‌کنن.

محدوده‌بندی مقادیر (Scoped values): مقادیر Enum فقط در همون نوع Enum معتبر هستن و باعث نمی‌شن فضای نام جهانی آلوده بشه.

قابلیت توسعه (Extensibility): Enums می‌تونن فیلد، سازنده و متد داشته باشن و رفتارهای پیچیده‌تر مثل toString() یا fromString() رو ارائه بدن.

نگهداری آسان (Maintainability): اضافه کردن یا تغییر مقادیر Enum امن‌تر و واضح‌تر از ویرایش String Constants هست.

هماهنگی با ابزارها (Tool integration): Enums به خوبی با قابلیت‌های IDE مثل Autocomplete و Refactoring کار می‌کنن و با فریمورک‌هایی مثل Jackson یا JPA هم به راحتی ادغام می‌شن.

جلوگیری از استفاده نادرست (Prevents misuse): برخلاف Interface Constants، نمی‌تونی مقادیر Enumهای غیرمرتبط رو با هم قاطی کنی یا ازشون نمونه بسازی.

 

 

منبع: نوشته شده توسط Renan Schmitt

نظرات کاربران
*نام و نام خانوادگی
* پست الکترونیک
* متن پیام

بستن
*نام و نام خانوادگی
* پست الکترونیک
* متن پیام

0 نظر
هدر سایت
دوره جامع نخبگان معماری میکروسرویس ها با Java و Spring Boot
دوره برنامه نویسی Spring Core
مشاهده سرفصل ها و ثبت نام در دوره Spring Boot جاواپرو  [کلیک کنید]
آموزش پروژه محور اسپرینگ بوت(Spring Boot)-سیستم دانشگاه
ثبت نام در دوره آموزش Spring security
دوره پرتاب | آموزش پیش نیازهای برنامه نویسی
دوره آموزش مبانی زبان برنامه نویسی جاوا
دوره آموزش مفاهیم پیشرفته زبان برنامه نویسی جاوا
مقدمه ای از زبان برنامه نویسی جاوا(java)
آموزش زبان برنامه نویسی جاوا
آموزش گرافیک در زبان برنامه نویسی جاوا
آموزش مدیریت چیدمان گرافیکی در زبان جاوا
آموزش ساخت بازی دوبعدی در زبان جاوا
Collection ها در زبان برنامه نویسی جاوا
آموزش پروژه محور ساخت برنامه مدیریت بانک با JavaFX
نمونه پروژه های رایگان زبان جاوا
آموزش دیتابیس در زبان برنامه نویسی جاوا
نمونه مثال پایه ای زبان برنامه نویسی جاوا
نمونه مثال String در زبان برنامه نویسی جاوا
آموزش جامع برنامه نویسی JavaFX
آموزش ساخت برنامه آزمون تستی در JavaFX
آموزش برنامه نویسی سوکت در جاوا
آموزش ساخت برنامه دفترچه تلفن با JavaFX
آموزش ساخت ربات ساده تلگرام با زبان جاوا
آموزش ساخت برنامه ماشین حساب با JavaFX
آموزش ساخت برنامه ساده مدیریت ایمیل ها با JavaFX
دوره آموزش Spring Boot
سفارش انجام پروژه زبان برنامه نویسی جاوا(JAVA)
سفارش انجام پروژه برنامه نویسی متلب(MATLAB) با قیمت منصفانه و تحویل به موقع
سفارش انجام پروژه زبان برنامه نویسی سی شارپ (#C)
سفارش انجام پروژه زبان برنامه نویسی سی(C)
سفارش انجام پروژه زبان برنامه نویسی پایتون(Python)
سفارش انجام پروژه زبان برنامه نویسی PHP (پی اچ پی)
سفارش انجام پروژه زبان برنامه نویسی اسمبلی(Assembly)
سفارش انجام پروژه زبان برنامه نویسی جاوا اسکریپت (Javascript)
سفارش انجام پروژه هوش مصنوعی
سفارش انجام پروژه طراحی الگوریتم
سفارش انجام پروژه ساختمان داده ها
سفارش انجام پروژه مهندسی نرم افزار
سفارش انجام پروژه شبکه های کامپیوتری
سفارش انجام پروژه پایگاه داده: دیتابیس (database)
 سفارش انجام پروژه سیستم عامل
سفارش انجام پروژه پاورپوینت(PowerPoint)
سفارش انجام پروژه اکسل (Excel)
سفارش انجام تحقیق و تهیه مقاله
سوالات متداول برنامه نویسی
جدیدترین مطالب
طراحی توسط سایت ساز خبری