قابلیت نگهداری، خوانایی و عملکرد کد پایتون خود را با تکنیکهای موثر بازسازی کد بهبود دهید. استراتژیها و بهترین شیوهها را برای بهبود کیفیت کد بیاموزید.
تکنیکهای بازسازی کد در پایتون: راهنمای جامع بهبود کیفیت کد
در چشمانداز همیشه در حال تحول توسعه نرمافزار، حفظ کد تمیز، کارآمد و قابل فهم بسیار مهم است. پایتون، که به خواناییاش معروف است، اگر به دقت مدیریت نشود، همچنان میتواند قربانی بوی بد کد و بدهی فنی شود. بازسازی کد فرآیند بازسازی کد کامپیوتری موجود است—تغییر فاکتورها—بدون تغییر رفتار خارجی آن. در اصل، این به معنای تمیز کردن کد خود بدون خراب کردن آن است. این راهنما به بررسی تکنیکهای مختلف بازسازی کد پایتون میپردازد و مثالهای عملی و بهترین شیوهها را برای ارتقای کیفیت کد شما ارائه میدهد.
چرا کد پایتون را بازسازی کنیم؟
بازسازی کد مزایای متعددی را ارائه میدهد، از جمله:
- بهبود خوانایی: کد را برای درک و نگهداری آسانتر میکند.
- کاهش پیچیدگی: منطق پیچیده را ساده میکند و احتمال بروز خطا را کاهش میدهد.
- بهبود قابلیت نگهداری: اصلاح و گسترش کد را آسانتر میکند.
- افزایش عملکرد: میتواند کد را برای سرعت اجرای بهتر بهینه کند.
- کاهش بدهی فنی: از انباشت کدی که نگهداری یا گسترش آن دشوار است، جلوگیری میکند.
- طراحی بهتر: منجر به معماری کد قویتر و انعطافپذیرتر میشود.
نادیده گرفتن بازسازی کد میتواند منجر به کدی شود که درک، اصلاح و آزمایش آن دشوار است. این میتواند به طور قابل توجهی زمان توسعه و خطر معرفی اشکالات را افزایش دهد.
چه زمانی بازسازی کنیم؟
دانستن زمان بازسازی بسیار مهم است. در اینجا چند سناریو رایج آورده شده است:
- قبل از افزودن ویژگیهای جدید: بازسازی کد موجود میتواند ادغام عملکردهای جدید را آسانتر کند.
- پس از رفع یک اشکال: بازسازی کد اطراف میتواند از تکرار اشکالات مشابه جلوگیری کند.
- در طول بررسی کد: مناطقی را که میتوان بهبود داد، شناسایی کرده و آنها را بازسازی کنید.
- هنگامی که با "بوی بد کد" مواجه میشوید: بوهای بد کد نشانگر مشکلات احتمالی در کد شما هستند.
- بازسازی کد به طور منظم برنامهریزی شده: بازسازی کد را به عنوان یک فعالیت منظم در فرآیند توسعه خود بگنجانید.
شناسایی بوهای بد کد
بوهای بد کد نشانههای سطحی هستند که معمولاً مربوط به یک مشکل عمیقتر در سیستم هستند. آنها همیشه نشان دهنده یک مشکل نیستند، اما اغلب نیاز به بررسی بیشتر دارند.
بوهای بد رایج کد پایتون:
- کد تکراری: کد یکسان یا بسیار مشابه که در چندین مکان ظاهر میشود.
- متد/تابع طولانی: متدها یا توابعی که بیش از حد طولانی و پیچیده هستند.
- کلاس بزرگ: کلاسهایی که مسئولیتهای زیادی دارند.
- لیست پارامتر طولانی: متدها یا توابعی با پارامترهای زیاد.
- تودههای داده: گروههایی از دادهها که اغلب با هم ظاهر میشوند.
- وسواس ابتدایی: استفاده از انواع دادههای ابتدایی به جای ایجاد اشیاء.
- عبارات Switch: زنجیرههای طولانی عبارات if/elif/else یا عبارات switch.
- جراحی با تفنگ ساچمهای: ایجاد یک تغییر واحد نیاز به ایجاد تغییرات کوچک زیادی در کلاسهای مختلف دارد.
- تغییر واگرا: یک کلاس معمولاً به روشهای مختلف برای دلایل مختلف تغییر میکند.
- حسادت ویژگی: یک متد به دادههای یک شی دیگر بیشتر از دادههای خودش دسترسی پیدا میکند.
- زنجیرههای پیام: یک مشتری از یک شی میخواهد که از یک شی دیگر بخواهد که از یک شی دیگر درخواست کند...
تکنیکهای بازسازی کد پایتون: یک راهنمای عملی
این بخش به تفصیل چندین تکنیک رایج بازسازی کد پایتون را با مثالهای عملی شرح میدهد.
1. استخراج متد/تابع
این تکنیک شامل گرفتن یک بلوک کد در یک متد یا تابع و انتقال آن به یک متد یا تابع جداگانه جدید است. این کار پیچیدگی متد اصلی را کاهش میدهد و کد استخراج شده را قابل استفاده مجدد میکند.
مثال:
def print_invoice(customer, details):
print("***********************")
print(f"Customer: {customer}")
print("***********************")
total_amount = 0
for order in details["orders"]:
total_amount += order["amount"]
print(f"Amount is : {total_amount}")
if total_amount > 1000:
print("You earned a discount!")
بازسازی شده:
def print_header(customer):
print("***********************")
print(f"Customer: {customer}")
print("***********************")
def calculate_total(details):
total_amount = 0
for order in details["orders"]:
total_amount += order["amount"]
return total_amount
def print_invoice(customer, details):
print_header(customer)
total_amount = calculate_total(details)
print(f"Amount is : {total_amount}")
if total_amount > 1000:
print("You earned a discount!")
2. استخراج کلاس
وقتی یک کلاس مسئولیتهای زیادی دارد، برخی از آنها را به یک کلاس جدید منتقل کنید. این اصل مسئولیت واحد را ترویج میکند.
مثال:
class Person:
def __init__(self, name, phone_number, office_area_code, office_number):
self.name = name
self.phone_number = phone_number
self.office_area_code = office_area_code
self.office_number = office_number
def get_name(self):
return self.name
def get_phone_number(self):
return f"({self.office_area_code}) {self.office_number}"
بازسازی شده:
class PhoneNumber:
def __init__(self, area_code, number):
self.area_code = area_code
self.number = number
def get_phone_number(self):
return f"({self.area_code}) {self.number}"
class Person:
def __init__(self, name, phone_number):
self.name = name
self.phone_number = phone_number
def get_name(self):
return self.name
3. متد/تابع درون خطی
این برعکس استخراج متد است. اگر بدنه یک متد به اندازه نام آن واضح است، میتوانید متد را با جایگزینی فراخوانیها با محتوای متد، درون خطی کنید.
مثال:
def get_rating(driver):
return more_than_five_late_deliveries(driver) ? 2 : 1
def more_than_five_late_deliveries(driver):
return driver.number_of_late_deliveries > 5
بازسازی شده:
def get_rating(driver):
return driver.number_of_late_deliveries > 5 ? 2 : 1
4. جایگزینی متغیر موقت با پرس و جو
به جای استفاده از یک متغیر موقت برای نگهداری نتیجه یک عبارت، عبارت را به یک متد منتقل کنید. این کار از تکرار کد جلوگیری میکند و خوانایی بهتری را ترویج میکند.
مثال:
def get_price(order):
base_price = order.quantity * order.item_price
discount_factor = 0.98 if base_price > 1000 else 0.95
return base_price * discount_factor
بازسازی شده:
def get_price(order):
return base_price(order) * discount_factor(order)
def base_price(order):
return order.quantity * order.item_price
def discount_factor(order):
return 0.98 if base_price(order) > 1000 else 0.95
5. معرفی شی پارامتر
اگر لیست طولانی از پارامترها دارید که اغلب با هم ظاهر میشوند، ایجاد یک شی پارامتر را برای کپسوله کردن آنها در نظر بگیرید. این کار طول لیست پارامتر را کاهش میدهد و سازماندهی کد را بهبود میبخشد.
مثال:
def calculate_total(width, height, depth, weight, shipping_method):
# Calculation logic
pass
بازسازی شده:
class ShippingDetails:
def __init__(self, width, height, depth, weight, shipping_method):
self.width = width
self.height = height
self.depth = depth
self.weight = weight
self.shipping_method = shipping_method
def calculate_total(shipping_details):
# Calculation logic using shipping_details attributes
pass
6. جایگزینی شرط با چندریختی
وقتی یک عبارت شرطی پیچیده دارید که رفتار را بر اساس نوع یک شی انتخاب میکند، استفاده از چندریختی را برای واگذاری رفتار به زیرکلاسها در نظر بگیرید. این کار سازماندهی کد را بهبود میبخشد و افزودن انواع جدید را آسانتر میکند.
مثال:
def calculate_bonus(employee):
if employee.employee_type == "SALES":
return employee.sales * 0.1
elif employee.employee_type == "ENGINEER":
return employee.projects_completed * 100
elif employee.employee_type == "MANAGER":
return 1000
else:
return 0
بازسازی شده:
class Employee:
def calculate_bonus(self):
return 0
class SalesEmployee(Employee):
def __init__(self, sales):
self.sales = sales
def calculate_bonus(self):
return self.sales * 0.1
class EngineerEmployee(Employee):
def __init__(self, projects_completed):
self.projects_completed = projects_completed
def calculate_bonus(self):
return self.projects_completed * 100
class ManagerEmployee(Employee):
def calculate_bonus(self):
return 1000
7. تجزیه شرطی
مشابه استخراج متد، این کار شامل تجزیه یک عبارت شرطی پیچیده به متدهای کوچکتر و قابل مدیریتتر است. این کار خوانایی را بهبود میبخشد و درک منطق شرطی را آسانتر میکند.
مثال:
if (platform.upper().index("MAC") > -1) and (browser.upper().index("IE") > -1) and was_initialized() and resize > MAX_RESIZE:
# Do something
pass
بازسازی شده:
def is_mac_os():
return platform.upper().index("MAC") > -1
def is_ie_browser():
return browser.upper().index("IE") > -1
if is_mac_os() and is_ie_browser() and was_initialized() and resize > MAX_RESIZE:
# Do something
pass
8. جایگزینی عدد جادویی با ثابت نمادین
مقادیر عددی تحتالفظی را با ثابتهای نامگذاری شده جایگزین کنید. این کار خوانایی را بهبود میبخشد و تغییر مقادیر را بعداً آسانتر میکند. این امر در مورد سایر مقادیر تحتالفظی مانند رشتهها نیز صدق میکند. کدهای ارزی (به عنوان مثال، 'USD'، 'EUR'، 'JPY') یا کدهای وضعیت (به عنوان مثال، 'ACTIVE'، 'INACTIVE'، 'PENDING') را از یک دیدگاه جهانی در نظر بگیرید.
مثال:
def calculate_area(radius):
return 3.14159 * radius * radius
بازسازی شده:
PI = 3.14159
def calculate_area(radius):
return PI * radius * radius
9. حذف واسطه
اگر یک کلاس به سادگی فراخوانیها را به کلاس دیگری واگذار میکند، حذف واسطه را در نظر بگیرید و به مشتری اجازه دهید مستقیماً به کلاس هدف دسترسی پیدا کند.
مثال:
class Person:
def __init__(self, department):
self.department = department
def get_manager(self):
return self.department.get_manager()
class Department:
def __init__(self, manager):
self.manager = manager
def get_manager(self):
return self.manager
بازسازی شده:
class Person:
def __init__(self, manager):
self.manager = manager
def get_manager(self):
return self.manager
10. معرفی ادعا
از ادعاها برای مستندسازی فرضیات در مورد وضعیت برنامه استفاده کنید. این میتواند به تشخیص زودهنگام خطاها و قویتر کردن کد کمک کند.
مثال:
def calculate_discount(price, discount_percentage):
if discount_percentage < 0 or discount_percentage > 100:
raise ValueError("Discount percentage must be between 0 and 100")
return price * (1 - discount_percentage / 100)
بازسازی شده:
def calculate_discount(price, discount_percentage):
assert 0 <= discount_percentage <= 100, "Discount percentage must be between 0 and 100"
return price * (1 - discount_percentage / 100)
ابزارهای بازسازی کد پایتون
چندین ابزار میتوانند به بازسازی کد پایتون کمک کنند:
- Rope: یک کتابخانه بازسازی کد برای پایتون.
- PyCharm: یک IDE محبوب پایتون با پشتیبانی داخلی از بازسازی کد.
- VS Code with Python Extension: یک ویرایشگر چندمنظوره با قابلیتهای بازسازی کد از طریق افزونهها.
- Sourcery: یک ابزار بازسازی کد خودکار.
- Bowler: یک ابزار بازسازی کد از فیسبوک برای اصلاحات کد در مقیاس بزرگ.
بهترین شیوهها برای بازسازی کد پایتون
- نوشتن تستهای واحد: قبل از بازسازی کد، مطمئن شوید که کد شما به خوبی آزمایش شده است.
- بازسازی کد در مراحل کوچک: برای به حداقل رساندن خطر معرفی خطا، تغییرات کوچک و تدریجی ایجاد کنید.
- تست بعد از هر مرحله بازسازی: تأیید کنید که تغییرات شما چیزی را خراب نکرده است.
- استفاده از کنترل نسخه: تغییرات خود را به طور مکرر ذخیره کنید تا در صورت لزوم به راحتی برگردید.
- ارتباط با تیم خود: تیم خود را از برنامههای بازسازی کد خود مطلع کنید.
- تمرکز بر خوانایی: اولویت را به آسانتر کردن درک کد خود بدهید.
- بازسازی کد فقط به خاطر بازسازی کد انجام ندهید: زمانی بازسازی کد کنید که یک مشکل خاص را حل کند.
- خودکارسازی بازسازی کد در صورت امکان: از ابزارها برای خودکارسازی وظایف تکراری بازسازی کد استفاده کنید.
ملاحظات جهانی برای بازسازی کد
هنگام کار بر روی پروژههای بینالمللی یا برای مخاطبان جهانی، این عوامل را در طول بازسازی کد در نظر بگیرید:
- بومیسازی (L10n) و بینالمللیسازی (I18n): اطمینان حاصل کنید که کد شما به درستی از زبانها، ارزها و فرمتهای تاریخ مختلف پشتیبانی میکند. برای جداسازی منطق خاص محلی، بازسازی کد کنید.
- رمزگذاری کاراکتر: از رمزگذاری UTF-8 برای پشتیبانی از طیف گستردهای از کاراکترها استفاده کنید. کد بازسازی کد که یک رمزگذاری خاص را فرض میکند.
- حساسیت فرهنگی: به هنجارهای فرهنگی توجه داشته باشید و از استفاده از زبان یا تصاویری که ممکن است توهینآمیز باشد، خودداری کنید. عناصر رشتهای و عناصر رابط کاربری را در طول بازسازی کد بررسی کنید.
- مناطق زمانی: تبدیلهای منطقه زمانی را به درستی مدیریت کنید. کد بازسازی کد که فرضیاتی را در مورد منطقه زمانی کاربر ایجاد میکند. از کتابخانههایی مانند `pytz` استفاده کنید.
- مدیریت ارز: از انواع دادهها و کتابخانههای مناسب برای مدیریت مقادیر پولی استفاده کنید. کد بازسازی کد که تبدیلهای دستی ارز را انجام میدهد. کتابخانههایی مانند `babel` مفید هستند.
مثال: بومیسازی فرمتهای تاریخ
import datetime
def format_date(date):
return date.strftime("%m/%d/%Y") # US date format
بازسازی شده:
import datetime
import locale
def format_date(date, locale_code):
locale.setlocale(locale.LC_TIME, locale_code)
return date.strftime("%x") # Locale-specific date format
# Example usage:
# format_date(datetime.date(2024, 1, 1), 'en_US.UTF-8') # Output: '01/01/2024'
# format_date(datetime.date(2024, 1, 1), 'de_DE.UTF-8') # Output: '01.01.2024'
نتیجهگیری
بازسازی کد یک عمل ضروری برای حفظ کد پایتون با کیفیت بالا است. با شناسایی و پرداختن به بوهای بد کد، استفاده از تکنیکهای مناسب بازسازی کد و پیروی از بهترین شیوهها، میتوانید به طور قابل توجهی خوانایی، قابلیت نگهداری و عملکرد کد خود را بهبود بخشید. به یاد داشته باشید که در طول فرآیند بازسازی کد، اولویت را به آزمایش و ارتباط بدهید. پذیرش بازسازی کد به عنوان یک فرآیند مداوم منجر به یک گردش کار توسعه نرمافزار قویتر و پایدارتر میشود، به ویژه هنگام توسعه برای مخاطبان جهانی و متنوع.