اصول SOLID در کد واقعی: پنج نشانه، پنج تصمیم

نرم‌افزار · · زمان مطالعه: ۵ دقیقه

پنج بلوک شیشه‌ای رنگی در چیدمان طاقی پایدار و رشتهٔ نوری که از میان آن‌ها می‌گذرد

اصول SOLID را معمولاً به‌عنوان «پنج قانون برای نوشتن کد تمیز» معرفی می‌کنند و همین معرفی، بزرگ‌ترین آسیب را به آن زده است: تیم‌ها آن را فهرستی از کارهای خوب می‌بینند و می‌کوشند همه‌اش را همزمان رعایت کنند. نتیجه، کدی است پر از رابط‌های تک‌متدی و لایه‌هایی که هیچ‌کس جرئت حذفشان را ندارد. اگر SOLID را از زاویهٔ دیگری ببینیم — ابزاری برای مهار «انتشار تغییر» — تصمیم‌ها بسیار ساده‌تر می‌شوند و مجبور نیستیم هر اصل را در هر قطعهٔ کد پیاده کنیم.

مسئلهٔ واقعی: تغییر در یک نقطه، شکستن در ده نقطه

هر تغییر در نرم‌افزار یک موج دارد. اگر برای اضافه کردن یک فیلد به گزارش فروش مجبور شوید پنج فایل را باز کنید و سه جا را همزمان دست بزنید، مشکل «کد زشت» نیست؛ مشکل این است که مرزهای کد با محورهای تغییر هم‌راستا نیستند. اصول SOLID دقیقاً همین را هدف می‌گیرد: کد را طوری بچینیم که تغییرِ برخاسته از یک دلیل، در یک جای مشخص بماند. دو مفهوم پشت این هدف است: وابستگی (coupling) کم و هم‌بستگی (cohesion) بالا؛ یعنی قطعه‌ها کم به هم تکیه کنند و هر قطعه یک کار منسجم انجام دهد.

پنج اصل، پنج نشانه در کد واقعی

بهتر است هر اصل را با نشانه‌ای بشناسید که در بازبینی کد می‌بینید، نه با تعریف کتابی. برای هر نشانه، کوچک‌ترین درمان را هم آورده‌ام.

اصل تک‌مسئولیتی (Single Responsibility Principle)

نشانه: کلاسی که نامش به «Manager» یا «Service» ختم می‌شود و هر کار مربوط به آن حوزه در آن جمع شده؛ قالب صورتحساب و قواعد دسترسی هر دو در همان فایل تغییر می‌کنند. درمان: محور تغییر را پیدا کنید، نه محور «موضوع» را. این اصل نمی‌گوید هر کلاس فقط یک متد داشته باشد؛ می‌گوید یک کلاس باید یک دلیل برای تغییر داشته باشد.

اصل باز/بسته (Open/Closed Principle)

نشانه: با هر نوع تازه — یک نوع درخواست، یک درگاه پرداخت، یک قالب خروجی — یک switch یا زنجیرهٔ if در مرکز کد باز می‌شود. مثلاً در سامانهٔ تیکتینگ و مدیریت پروژه اضافه شدن نوع تازه‌ای از درخواست نباید قلب گردش‌کار را دستکاری کند. درمان: یک نقطهٔ توسعهٔ روشن بگذارید (رابط یا ثبت‌نام پیاده‌سازی) و انواع تازه را از بیرون اضافه کنید؛ اما این کار را فقط وقتی بکنید که آن نوع تغییر واقعاً چند بار تکرار شده باشد.

اصل جانشینی لیسکوف (Liskov Substitution Principle)

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

اصل تفکیک رابط (Interface Segregation Principle)

نشانه: رابطی چاق که پیاده‌سازها مجبورند برای بخشی از متدها بدنهٔ خالی یا استثنای «پیاده‌سازی نشده» بنویسند. درمان: رابط را در مرز مصرف‌کننده بشکنید؛ هر مصرف‌کننده فقط چیزی را ببیند که واقعاً به‌کار می‌برد. رابط‌های کوچک، تست نوشتن را هم ساده‌تر می‌کنند، چون کمترین رفتار لازم را توصیف می‌کنند.

اصل وارونگی وابستگی (Dependency Inversion Principle)

نشانه: منطق دامنه که مستقیم به کتابخانهٔ ارسال ایمیل، ORM یا سرویس بیرونی وصل است؛ تا جایی که تست کردن یک قاعدهٔ کسب‌وکار نیاز به پایگاه‌داده و شبکه پیدا می‌کند. درمان: مرز را در سمت دامنه تعریف کنید — یک رابط با زبان کسب‌وکار — و پیاده‌سازی را در لایهٔ بیرونی بگذارید. توجه کنید که این اصل با «تزریق وابستگی» یکی نیست؛ تزریق فقط یک ابزار پیاده‌سازی است.

جایی که SOLID به ضرر تبدیل می‌شود

هر انتزاع هزینه دارد: یک فایل اضافه، یک پرش ذهنی، و یک لایه که هنگام عیب‌یابی باید از آن رد شوید. اگر آن محور تغییر عملاً اتفاق نمی‌افتد، انتزاع فقط خوانایی را کم می‌کند و کد را از چیزی که هست پیچیده‌تر نشان می‌دهد. قاعدهٔ سرانگشتی: تا وقتی شباهت را در دو جای واقعی ندیده‌اید، از انتزاع دوری کنید؛ سه بار تکرار، شاهدِ کافی برای استخراج است. تکرارِ کم‌هزینه و صریح از انتزاعِ زودهنگام و مبهم بهتر است — و انتزاع اشتباه هم خودش نوعی بدهی فنی است که بهره‌اش را از سرعت فهم کد می‌گیرد.

راهنمای تصمیم‌گیری پیش از بازآرایی

کد را به نام SOLID نشکنید؛ به نام یک تصمیم مشخص بشکنید. پیش از هر بازآرایی، این پرسش‌ها را جواب بدهید:

  1. تغییرهای اخیر در کدام فایل‌ها متمرکز بوده‌اند؟ تاریخچهٔ نسخه‌ها گزارش واقعی می‌دهد، نه حس شخصی.
  2. اگر همان تغییر دوباره تکرار شود، چند فایل باز می‌شود؟ اگر تعداد پایین است، دست نزنید.
  3. آیا این شباهت را جای دیگری هم دیده‌اید یا فقط یک نمونه است؟
  4. این مرز، مرز «مسئله» است یا مرز «فناوری»؟ مرز فناوری (ایمیل، پایگاه‌داده) معمولاً بیرونی است، نه در قلب دامنه.
  5. آیا پس از تغییر، نوشتن تست ساده‌تر شد؟ اگر نه، احتمالاً انتزاع در جهت اشتباه رفته است.

و یک قاعدهٔ اجرایی: هر بار فقط یک گام بردارید — یک تست، یک استخراج، یک کامیت. بازآرایی بزرگ در یک قدم، همان چیزی است که تیم‌ها را از SOLID زده می‌کند. محل طبیعی اجرای این قواعد هم بازبینی کد است؛ همان‌جا که پرسش «چرا این قطعه این‌جاست؟» ارزان‌تر از پرسش «چرا اینجا شکست؟» تمام می‌شود.

جمع‌بندی

اصول SOLID مجموعه‌ای از ممنوعیت‌های زیبایی‌شناسانه نیست؛ راهی است برای اینکه هزینهٔ تغییر در نرم‌افزار قابل پیش‌بینی بماند. برای هر اصل، نشانه‌ای در کد امروز پیدا کنید، کوچک‌ترین درمان را انتخاب کنید و نتیجه را با تست بسنجید. جایی که تغییری انتظار نمی‌رود، صریح و ساده بنویسید و انتزاع را برای محورهایی نگه دارید که واقعاً تکان می‌خورند.

← بازگشت به همه مقالات