نوشتن کدی که در ظاهر درست کار کند قدم اول برنامهنویسی است، اما تغییر دادن آن بدون خراب شدن سایر بخشهای سیستم، چالش اصلی توسعهدهندگان محسوب میشود.
اصول پنجگانه SOLID ساختار تفکر شما را در طراحی شیءگرا دگرگون میکنند تا کدهایی انعطافپذیر، پایدار و مقیاسپذیر بنویسید. نادیده گرفتن این اصول معمولاً به کدهای کلافهکنندهای ختم میشود که با اصلاح یک بخش، دهها خطای ناخواسته در بخشهای دیگر آن رخ میدهد.
در این درس، با تمرکز روی اصول پرکاربردی مانند Open/Closed و Liskov Substitution و از طریق مثالهای ملموس و پایتونی، یاد میگیرید کلاسهایی بسازید که افزون بر خوانایی بالا، فرآیند توسعه و اضافه کردن ویژگیهای جدید به پروژه را سریع و بدون ریسک کنند.
مفهوم معماری تمیز و معرفی الفبای SOLID
توسعه نرمافزار شباهت زیادی به ساختن یک ساختمان دارد. اگر پایههای اولیه را سست بنا کنید، با اضافه شدن طبقات جدید کل سازه فرو میریزد. در دنیای کدنویسی، معماری تمیز همان نقشهای است که جلوی این سقوط را میگیرد.
هدف اصلی معماری تمیز، جداسازی بخشهای مختلف برنامه است تا تغییر در یک قسمت، بخشهای دیگر را از کار نیندازد. وقتی کدهای مربوط به ذخیرهسازی دادهها، منطق اصلی برنامه و ظاهر سیستم کاملاً از هم مستقل باشند، نرمافزار شما انعطافپذیر و زنده میماند.
رابرت سی مارتین، معروف به عمو باب، پنج اصل کلیدی را برای طراحی نرمافزارهای شیءگرا معرفی کرد. کنار هم قرار گرفتن حرف اول این متدولوژیها، کلمه SOLID را میسازد. برنامهنویسان این پنج اصل را به عنوان الفبای طراحی تمیز میشناسند که راهنمای ساختارهای محکم نرمافزاری هستند.
اصل اول با حرف S نشانه اصل تکمسئولیتی (Single Responsibility) است. این قاعده میگوید یک کلاس یا تابع فقط باید یک کار مشخص را انجام دهد و تنها یک دلیل برای تغییر داشته باشد.
حرف O به اصل باز/بسته (Open/Closed) اشاره دارد. طبق این مفهوم، کدهای شما باید برای توسعه باز و برای تغییر بسته باشند. یعنی باید بتوانید بدون دستکاری کدهای قدیمی، امکانات جدید را به سیستم اضافه کنید.
حرف L نماینده اصل جانشینی لیسکوف (Liskov Substitution) است. این اصل تاکید میکند که کلاسهای فرزند باید بدون ایجاد اختلال در برنامه، توانایی جایگزینی کلاس پدر را داشته باشند.
حرف I به اصل تفکیک اینترفیسها (Interface Segregation) تعلق دارد. این دیدگاه ساخت ابزارهای چندکاره و شلوغ را ممنوع میکند. طراحی چند اینترفیس کوچک و تخصصی، همیشه بر ساخت یک اینترفیس بزرگ و همهکاره اولویت دارد.
حرف D نشاندهنده اصل وارونگی وابستگی (Dependency Inversion) است. این فرمول میگوید ماژولهای حیاتی و سطح بالا نباید به جزییات کوچک و ماژولهای سطح پایین وابسته باشند، بلکه هر دو گروه باید از ساختارهای انتزاعی تبعیت کنند.
درک درست این الفبا به شما کمک میکند کدهایی بنویسید که با گذشت زمان فرسوده نشوند و فرآیند توسعه پروژه را متوقف نکنند. در بخشهای بعدی، هر کدام از این اصول پنجگانه را با سناریوهای واقعی و کدهای کاربردی پایتون کالبدشکافی میکنیم.
اصل تکمسئولیتی (Single Responsibility Principle - SRP)
اصل تکمسئولیتی (Single Responsibility Principle) که به اختصار SRP نامیده میشود، پایهایترین جزء از اصول پنجگانه SOLID است. این اصل بیان میکند یک کلاس، ماژول یا تابع فقط و فقط باید یک مسئولیت مشخص داشته باشد. رابرت سی مارتین این مفهوم را با یک جمله کلیدی تعریف میکند: «یک کلاس باید تنها یک دلیل برای تغییر داشته باشد.»
بسیاری از برنامهنویسان در درک کلمه «مسئولیت» دچار اشتباه میشوند. مسئولیت در اینجا به معنای انجام دادن تنها یک کار یا یک عملیات ریاضی نیست، بلکه به این معناست که طراحی کلاس باید طوری باشد که فقط در پاسخ به نیازهای یک بازیگر (Actor) یا یک بخش خاص از کسبوکار تغییر کند.
وقتی کلاسی وظایف مربوط به بخشهای مختلف سیستم را در خود جای دهد، تغییر در خواسته یک بخش میتواند به طور ناخواسته بخشهای دیگر را با باگهای پیشبینینشده مواجه کند.
کد زیر نمونهای از نقض آشکار اصل SRP را نشان میدهد:
class OrderManager:
def calculate_total(self, items):
total = sum(item['price'] * item['quantity'] for item in items)
return total
def save_to_database(self, order_id, total):
print(f"Saving order {order_id} with total {total} to database.")
def send_confirmation_email(self, customer_email, order_id):
print(f"Sending confirmation email for order {order_id} to {customer_email}.")
کلاس بالا سه دلیل متفاوت برای تغییر دارد. اگر فرمول محاسبه قیمت تغییر کند، اگر دیتابیس پروژه از یک سیستم به سیستم دیگر منتقل شود، یا اگر سرویس ارسال ایمیل عوض شود، این کلاس باید دستکاری شود. این انباشتگی وظایف، نگهداری پروژه را سخت و احتمال بروز خطا را به شدت بالا میبرد.
برای اعمال صحیح این اصل، باید وظایف را تفکیک کنید و هر کدام را به یک کلاس مستقل بسپارید:
class PriceCalculator:
def calculate_total(self, items):
return sum(item['price'] * item['quantity'] for item in items)
class OrderRepository:
def save(self, order_id, total):
print(f"Saving order {order_id} with total {total} to database.")
class NotificationService:
def send_email(self, customer_email, order_id):
print(f"Sending confirmation email for order {order_id} to {customer_email}.")
اکنون هر کلاس وظیفه منحصربهفرد خود را انجام میدهد. تغییر در منطق ذخیرهسازی دادهها هیچ تاثیری روی فرمولهای محاسباتی یا سرویس ایمیل نمیگذارد.
جلوگیری از ایجاد کلاسهای همهکاره (God Classes)، افزایش چشمگیر قابلیت تستنویسی، و امکان بازآفرینی کدهای تمیز از دستاوردهای اصلی رعایت این اصل است. کدهایی که از اصل تکمسئولیتی پیروی میکنند، به راحتی خوانده میشوند و در پروژههای بزرگ به سادگی قابل توسعه هستند.
اصل باز/بسته (Open/Closed Principle - OCP)
نوشتن کدی که با هر تغییر کوچک در نیازهای کسبوکار نیاز به جراحی قلب باز داشته باشد، کابوس تمام تیمهای توسعه است. اصل باز/بسته (Open/Closed Principle) یا همان OCP دقیقاً برای حل همین چالش فرموله شده است.
این اصل که دومین بخش از الفبای SOLID محسوب میشود، میگوید: «قطعات نرمافزاری (کلاسها، ماژولها، توابع و...) باید برای توسعه باز (Open for extension) اما برای تغییر بسته (Closed for modification) باشند.»
معنی این جمله در دنیای واقعی بسیار ساده است. شما باید ساختار کدهای خود را طوری طراحی کنید که وقتی میخواهید ویژگی یا رفتار جدیدی به برنامه اضافه کنید، نیازی به دستکاری و ویرایش کدهای قبلی که در حال حاضر درست کار میکنند، نداشته باشید. دست بردن در کدهای قدیمی همیشه ریسک ایجاد باگهای جدید در بخشهای تستشده و پایدار سیستم را به همراه دارد.
کد زیر نمونهای متداول از نقض این اصل را در یک سیستم مدیریت تخفیف فروشگاهی نشان میدهد:
class DiscountManager:
def apply_discount(self, customer_type, price):
if customer_type == "regular":
return price * 0.9
elif customer_type == "vip":
return price * 0.8
else:
return price
این متد در ظاهر ساده و بدون مشکل است. چالش اصلی زمانی رخ میدهد که مدیر کسبوکار تصمیم بگیرد نوع جدیدی از مشتری، مثلاً "مشتری وفادار" (Loyal) با تخفیف ۱۵ درصد را اضافه کند. برای این کار مجبور هستید کدهای این کلاس را باز کنید، یک شرط elif دیگر به زنجیره شرطها اضافه کنید و دوباره کل سیستم را تست کنید. این رویکرد یعنی کلاس شما برای تغییر باز است، که دقیقاً نقض قانون OCP به شمار میرود.
در پایتون، بهترین و پایتونیکترین راه برای پیادهسازی اصل باز/بسته، استفاده از کلاسهای انتزاعی (Abstract Base Classes) با کمک ماژول درونی abc و بهرهگیری از ویژگی چندریختی (Polymorphism) است. ساختار اصلاحشده را ببینید:
from abc import ABC, abstractmethod
class DiscountStrategy(ABC):
@abstractmethod
def calculate(self, price):
pass
class RegularCustomerDiscount(DiscountStrategy):
def calculate(self, price):
return price * 0.9
class VIPCustomerDiscount(DiscountStrategy):
def calculate(self, price):
return price * 0.8
class DiscountManager:
def apply_discount(self, discount_strategy: DiscountStrategy, price):
return discount_strategy.calculate(price)
با این بازآفرینی، کلاس DiscountManager به یک ساختار انتزاعی متصل شده است و کاری به جزئیات ندارد. اگر فردا بخواهید تخفیف جدیدی اضافه کنید، کافی است یک کلاس جدید بسازید که از DiscountStrategy ارثبری میکند:
class LoyalCustomerDiscount(DiscountStrategy):
def calculate(self, price):
return price * 0.85
بدون اینکه حتی یک خط از کدهای قبلی یا کلاس مدیریت تخفیف را دستکاری کنید، ویژگی جدید به سیستم اضافه شد. این یعنی کدهای شما برای توسعه کاملاً باز و در برابر تغییرات مخرب کاملاً بسته و مصون هستند. افزایش انعطافپذیری سیستم، کاهش شدید ریسک بروز باگ در کدهای قدیمی و تسهیل فرآیند تستنویسی، از نتایج مستقیم رعایت این اصل در پروژههای پایتون است.
اصل جانشینی لیسکوف (Liskov Substitution Principle - LSP)
اصل جانشینی لیسکوف یا همان LSP، سومین قاعده از اصول پنجگانه SOLID است که نام آن از دانشمند علوم کامپیوتر، باربارا لیسکوف، گرفته شده است. این اصل یک مفهوم بسیار حیاتی را در برنامهنویسی شیءگرا بیان میکند: «کلاسهای فرزند باید به گونهای طراحی شوند که بتوان آنها را بدون تغییر در صحت رفتار برنامه، جایگزین کلاسهای پدر کرد.»
ارثبری در برنامهنویسی صرفاً به معنای اشتراکگذاری کدها یا شباهتهای ظاهری نیست، بلکه به معنای تعهد به رفتار کلاس پایه است. وقتی کلاسی را از کلاس دیگر مشتق میکنید، یک قرارداد پنهان امضا میکنید. کلاس فرزند باید تمام انتظاراتی که از کلاس پدر میرود را برآورده کند.
اگر جایگزین کردن کلاس فرزند باعث خراب شدن منطق برنامه، ایجاد رفتارهای غیرمنتظره یا پرتاب استثناهای عجیب شود، شما این اصل را نقض کردهاید.
یکی از معروفترین سناریوها برای درک نقض این اصل، رابطه کلاس مستطیل و مربع است. در ریاضیات، مربع نوعی مستطیل است؛ بنابراین ممکن است وسوسه شوید کلاس مربع را از مستطیل ارثبری کنید. به این نمونه دقت کنید:
class Rectangle:
def __init__(self, width: float, height: float):
self._width = width
self._height = height
def set_width(self, width: float):
self._width = width
def set_height(self, height: float):
self._height = height
def get_area(self) -> float:
return self._width * self._height
class Square(Rectangle):
def set_width(self, width: float):
self._width = width
self._height = width # در مربع طول و عرض برابرند
def set_height(self, height: float):
self._width = height
self._height = height
در نگاه اول همه چیز منطقی به نظر میرسد، اما وقتی این کلاسها را در یک تابع استفاده کنید، مشکل بزرگی رخ میدهد:
def modify_rectangle(rectangle: Rectangle):
rectangle.set_width(5)
rectangle.set_height(4)
# بر اساس منطق مستطیل، مساحت باید ۲۰ شود (۵ ضربدر ۴)
assert rectangle.get_area() == 20, "مساحت اشتباه است!"
اگر شیئی از کلاس Square را به تابع بالا پاس دهید، متد set_height(4) هم طول و هم عرض را به ۴ تغییر میدهد. در نتیجه، مساحت به جای ۲۰ برابر با ۱۶ میشود و برنامه با خطا متوقف میشود. این یعنی کلاس Square نتوانسته است به درستی جانشین Rectangle شود و رفتار پیشبینیپذیر کلاس پدر را خراب کرده است.
برای حل این چالش و رعایت اصل لیسکوف، باید ساختار ارثبری اشتباه را رها کنید و هر دو کلاس را به یک ریشه انتزاعیتر متصل کنید که رفتارهای مشترک اما مستقل را تعریف کند:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def get_area(self) -> float:
pass
class Rectangle(Shape):
def __init__(self, width: float, height: float):
self.width = width
self.height = height
def get_area(self) -> float:
return self.width * self.height
class Square(Shape):
def __init__(self, side: float):
self.side = side
def get_area(self) -> float:
return self.side * self.side
اکنون هر دو کلاس رفتاری کاملاً پیشبینیپذیر دارند. هر تابعی که به شیئی از جنس Shape نیاز داشته باشد، میتواند بدون هیچگونه غافلگیری یا تغییر در صحت اجرای برنامه، با Rectangle یا Square کار کند.
برای پایبندی به این اصل در پایتون، همیشه بررسی کنید که کلاسهای فرزند نوع خروجی متدها را تغییر ندهند، پیششرطها را سختتر نکنند و استثناهایی خارج از چارچوب کلاس پدر ایجاد نکنند. رعایت این اصل تضمین میکند که ساختار چندریختی (Polymorphism) در سیستم شما همیشه پایدار و قابل اعتماد باقی بماند.
اصل تفکیک اینترفیسها (Interface Segregation Principle - ISP)
اصل تفکیک اینترفیسها (Interface Segregation Principle) یا همان ISP، چهارمین جزو از الفبای اصول SOLID است.
این اصل نگاه ویژهای به نحوه طراحی مرزها و قراردادهای برنامه دارد و بیان میکند: «هیچ کلاسی نباید مجبور شود متدهایی را پیادهسازی کند که به آنها نیاز ندارد.» به زبان سادهتر، ساخت چند اینترفیس کوچک و لاغر، همیشه بر ساخت یک اینترفیس بزرگ و چاق ترجیح دارد.
بسیاری از برنامهنویسان پایتون تصور میکنند چون در این زبان مفهوم اینترفیس (Interface) مانند جاوا یا سیشارپ به صورت یک کلمه کلیدی اختصاصی وجود ندارد، پس اصل ISP در پایتون کاربردی ندارد.
این یک تصور کاملاً اشتباه است. در پایتون ما از کلاسهای انتزاعی (Abstract Base Classes) برای ساخت قراردادها استفاده میکنیم و نقض این اصل میتواند ساختار برنامه را به شدت لرزان کند.
کد زیر نمونهای از نقض این اصل را در سیستم مدیریت پرندگان یک باغوحش نشان میدهد:
from abc import ABC, abstractmethod
class Bird(ABC):
@abstractmethod
def fly(self):
pass
@abstractmethod
def swim(self):
pass
class Duck(Bird):
def fly(self):
print("Duck is flying")
def swim(self):
print("Duck is swimming")
class Penguin(Bird):
def fly(self):
# پنگوئنها پرواز نمیکنند! مجبوریم استثنا پرتاب کنیم یا متد را خالی بگذاریم.
raise NotImplementedError("Penguins cannot fly")
def swim(self):
print("Penguin is swimming")
کلاس Penguin به دلیل ارثبری از کلاس چاق Bird مجبور شده است متد fly را پیادهسازی کند، در حالی که این رفتار اصلاً متعلق به پنگوئن نیست. مجبور شدن به پرتاب خطا (NotImplementedError) یا رها کردن متد به صورت خالی، نشانه بارز نقض اصل تفکیک اینترفیسها است. این کار باعث میشود کدهایی که با کلاس پدر کار میکنند، در مواجهه با برخی فرزندان دچار رفتارهای پیشبینینشده شوند.
برای اعمال صحیح این اصل، باید قرارداد بزرگ را به قراردادهای کوچکتر و تخصصیتر تفکیک کنید:
from abc import ABC, abstractmethod
class Flyable(ABC):
@abstractmethod
def fly(self):
pass
class Swimmable(ABC):
@abstractmethod
def swim(self):
pass
class Duck(Flyable, Swimmable):
def fly(self):
print("Duck is flying")
def swim(self):
print("Duck is swimming")
class Penguin(Swimmable):
def swim(self):
print("Penguin is swimming")
با این بازآفرینی، پایتون به شما اجازه میدهد از ویژگی چندارثی (Multiple Inheritance) به بهترین شکل استفاده کنید. کلاس Penguin حالا فقط به قرارداد Swimmable متعهد است و هیچ بار اضافهای را به دوش نمیکشد.
تفکر پایتونیک در مواجهه با این اصل، فراتر از کلاسهای انتزاعی میرود و به مفهوم Duck Typing (رفتارگرایی) پیوند میخورد. در پایتون، برخلاف زبانهای سختگیر، مهم نیست شیء شما از چه کلاسی مشتق شده است؛ اگر شیء شما متد fly را داشته باشد، پایتون آن را به عنوان یک موجود پروازکننده میپذیرد.
با رعایت اصل ISP، کدهای شما منعطفتر میشوند، وابستگیهای بیهوده بین ماژولها از بین میروند و فرآیند توسعه سرعت بیشتری به خود میگیرد.
اصل وارونگی وابستگی (Dependency Inversion Principle - DIP)
اصل وارونگی وابستگی یا همان DIP، آخرین جزء از اصول پنجگانه SOLID است که معماری کلان نرمافزار شما را هدایت میکند. این اصل رابطهای مستقیم با میزان جفتشدگی (Coupling) ماژولها دارد و فرآیند ساختاردهی به کدهای پروژه را دگرگون میکند. اصل وارونگی وابستگی شامل دو قاعده طلایی است:
ماژولهای سطح بالا (High-level modules) نباید به ماژولهای سطح پایین (Low-level modules) وابسته باشند؛ هر دو گروه باید به انتزاع (Abstractions) وابسته باشند.
انتزاعها نباید به جزئیات وابسته باشند؛ بلکه جزئیات (Implementations) هستند که باید به انتزاعها وابسته شوند.
ماژولهای سطح بالا شامل همان منطق اصلی کسبوکار (Business Logic) پروژه شما هستند؛ یعنی هسته اصلی برنامه که ارزش واقعی سیستم را خلق میکند. ماژولهای سطح پایین شامل کدهای عملیاتی فرعی مانند اتصال به دیتابیس، ارسال پیامک، یا فراخوانی یک API بیرونی هستند.
نقض این اصل زمانی رخ میدهد که منطق اصلی برنامه شما مستقیماً به جزئیات فنی یک دیتابیس یا یک سرویسدهنده خاص گره بخورد. با تغییر ابزار سطح پایین، کل ماژول سطح بالای شما نیز از کار میافتد یا نیاز به بازنویسی پیدا میکند.
کد زیر نمونهای از نقض آشکار اصل وارونگی وابستگی را در پایتون نشان میدهد:
class SmsGateway:
def send_sms(self, message: str, receiver: str):
print(f"Sending message via SMS Gateway: {message} to {receiver}")
class OrderProcessor:
def __init__(self):
self.sms_gateway = SmsGateway() # وابستگی مستقیم به ماژول سطح پایین
def process(self, order_id: int, user_phone: str):
print(f"Processing order {order_id}...")
self.sms_gateway.send_sms("Order processed successfully", user_phone)
کلاس OrderProcessor یک ماژول سطح بالا است که مستقیماً در متد سازنده خود شیئی از کلاس SmsGateway (ماژول سطح پایین) را ساخته است. اگر فردا بخواهید به جای پیامک از ایمیل استفاده کنید، یا سرویسدهنده پیامک خود را عوض کنید، مجبور هستید کدهای کلاس پردازش سفارش را دستکاری کنید.
برای اصلاح این ساختار بر اساس اصل DIP، باید از تکنیک تزریق وابستگی (Dependency Injection) و یک کلاس انتزاعی به عنوان واسط استفاده کنید تا وابستگیها را وارونه کنید:
from abc import ABC, abstractmethod
class NotificationChannel(ABC):
@abstractmethod
def send(self, message: str, receiver: str):
pass
class SmsGateway(NotificationChannel):
def send(self, message: str, receiver: str):
print(f"SMS: {message} sent to {receiver}")
class EmailGateway(NotificationChannel):
def send(self, message: str, receiver: str):
print(f"Email: {message} sent to {receiver}")
class OrderProcessor:
def __init__(self, notification_channel: NotificationChannel):
self.notification_channel = notification_channel # وابستگی به انتزاع
def process(self, order_id: int, user_contact: str):
print(f"Processing order {order_id}...")
self.notification_channel.send("Order processed successfully", user_contact)
اکنون جهت وابستگیها کاملاً تغییر کرده است. کلاس OrderProcessor دیگر هیچ شناختی از نحوه ارسال پیام یا ابزارهای سطح پایین ندارد؛ این کلاس فقط با پروتکل NotificationChannel تعامل میکند. هنگام استفاده از این سیستم، ابزار ارسال پیام را از بیرون به کلاس تزریق میکنید:
sms_provider = SmsGateway()
processor = OrderProcessor(notification_channel=sms_provider)
processor.process(1024, "09123456789")
رعایت اصل وارونگی وابستگی کدهای شما را به شدت انعطافپذیر میکند. تعویض قطعات فنی سیستم مانند پایگاه داده یا سرویسهای اطلاعرسانی بدون تغییر در منطق تجاری برنامه انجام میشود و فرآیند نوشتن تستهای واحد (Unit Tests) با استفاده از اشیای شبیهسازیشده (Mock Objects) بسیار سادهتر خواهد شد.
جمعبندی و تفکر پایتونیک در مواجهه با SOLID
اصول SOLID به عنوان قوانین جهانی در مهندسی نرمافزار شیءگرا شناخته میشوند، اما پایتون یک زبان معمولی نیست. پایتون با فلسفه پایتونیک (Pythonic) و شعار «سادگی بر پیچیدگی اولویت دارد» مدیریت میشود.
هضم کردن مستقیم اصول سختگیرانه SOLID (که ریشه در زبانهایی مثل جاوا و سیشارپ دارند) در ساختار پویا و منعطف پایتون، به یک نگاه هوشمندانه و منعطف نیاز دارد. پیادهسازی کورکورانه این اصول میتواند کدهای پایتون را بیهوده پیچیده، طولانی و از اصالت خود دور کند.
برنامهنویسان پایتون برای اعمال این اصول نیازی به ساخت ساختارهای غولآسا از کلاسهای انتزاعی متوالی ندارند. ویژگی Duck Typing در پایتون (اینکه بگوییم اگر موجودی شبیه اردک راه راه میرود و مثل اردک کواک میکند، پس اردک است) بسیاری از گرههای مربوط به اصول LSP و ISP را به سادهترین شکل ممکن باز میکند.
در پایتون، رفتار اشیا اهمیت دارد، نه تیپ و اصرار بر ارثبریهای پیچیده. شما بدون تعریف اینترفیسهای صلب، فقط با طراحی متدهای همنام و تخصصی، اصول تفکیک را رعایت میکنید.
رعایت تعادل، مرز بین یک پایتونکار حرفهای و یک برنامهنویس متعصب است. اصول SOLID ابزارهایی برای رسیدن به کدی خوانا و قابل نگهداری هستند، نه زنجیرهایی برای محدود کردن خلاقیت شما. هر جا که احساس کردید اعمال یکی از این اصول (مثل ساخت کلاسهای بیش از حد برای رعایت دقیق SRP یا OCP) دارد خوانایی کد را از بین میبرد و فهم آن را سختتر میکند، باید متوقف شوید. خوانایی و سادگی کد همیشه در اولویت اول تفکر پایتونیک قرار دارد.
یک توسعهدهنده پایتون خلاق، از ابزارهای بومی این زبان برای تمیز نگهداشتن پروژه استفاده میکند. ماژولهای درونی، دکوراتورها (Decorators)، ویژگی چندارثی و حتی توابع ساده مستقلی که در ماژولها تفکیک شدهاند، همگی ابزارهایی هستند که بدون ایجاد لایههای نرمافزاری اضافه، شما را به اهداف SOLID میرسانند.
هدف نهایی این است که کدهای شما با تغییرات آینده بیزینس به راحتی سازگار شوند، بدون اینکه پویایی و زیبایی پایتون فدای معماریهای سنگین و خستهکننده شود.