چرا باید مفاهیم S.O.L.I.D. رو یاد بگیریم؟

آقاا خیلی وقتا من شنیدم که برنامه نویس های تازه کار و یا حتی برنامه نویسای با تجربه تر نسبت به این اصول جبهه دارن یا با design pattern ها قاطیش میکنن یا حتی جدیشن نمیگیرن گفتم یه چند خط بنویسم براتون که اصلا داستان چیه ؟ پنج اصل SOLID توسط Robert C. Martin معروف به (Uncle Bob) برای اولین بار مطرح شد.هدف از SOLID توسعه کدهای با خوانایی بالاتر و توسعه پذیر تر و همچنین ایجاد یک استاندارد بین تمامی توسعه دهندگان است.استفاده از اصول سالید از به وجود آمدن مشکلاتی نظیر : Duplication ، Viscosity ، Immobility، Fragility و ... جلوگیری میکندتفاوت این دو مفهوم اینه که الگوهای طراحی یا design pattern ها ، مجموعه ای از کدها و راه حل‌های از پیش نوشته شده هستند که هر کدام مشکلی رو حل می کنند، یعنی در شرایط خاص از الگوهای طراحی برای حل مشکل استفاده کرد. اما، SOLID قوانینی هستند که برای نوشتن کدها استفاده میشوند , و یا به عبارت دیگه حین توسعه نرم افزار اگر از این قوانین استفاده کنیم در آینده موقع نگه داری محصولمون خیلی راحت تریم :) حالا به جز نگه داری پروژمون scalable و testable هم میشه( اگر اونقدری کارکرد نرم افزارمون برامون مهمه و بخوایم بدون باگ باشه و بخوایم از روش درستیابی فرمال استفاده کنیم خیلی کمکمون میکنه وقتی این اصول و رعایت کرده باشیم)سوالی که این وسط برای همه پیش میاد اینه که میگن من مفاهیم شی گرایی رو بلدم و دیگه نیازی به قواعد S.O.L.I.D. ندارم که یاد بگیرم. بذارید این دو مسئله رو از هم جدا کنیم. اگه بخوام یه مثال ساده بزنم، برای یادگیری و استفاده از هر دو مسئله اینه که شما تمام ابزارهای چوب بری رو در اختیار داشته باشی و بگی که خب نیازی نیست که علم چوب بری هم یاد بگیرم.با یادگیری برنامه نویسی شئ گرا، در حقیقت یاد میگیرد که چطوری از کلاس ها استفاده کنید ، چگونه برای یک کلاس خصوصیت تعریف کنیم و به طور کلی یه دید انتزاعی نسبت به اشیا و موجودیت هامون پیدا میکنیم ، اما اینکه بتونیم از این قابلیت‌ها در مسیر درست استفاده کنیم داستان فرق میکنه.S.O.L.I.D. در واقع یک چهارچوب منظم رو برای ما ایجاد میکنه که مکمل شی گرایی است و با حرکت در این مسیر میتوانیم کدهای بهینه تری بنویسیم.SOLID مخفف پنج عبارته زیر است:سعی میکنم یه توضیح مختصر راجع به هر کدوم بدم ، اگه در آینده حالشو داشتم هر کدوم رو میشکافم و با نمونه کد تو یه مقاله دیگه بررسیش میکنم فعلا خستم :)1) S: Single Responsibility Principleهر بخش از نرم افزار حالا کلاس ، تابع یا حتی یه کامپوننت وظیفه انجام تنها و تنها یک کار را دارد هیچ یک نباید دو یا چند عملیات انجام دهد.یا به عبارت دیگه هر بخش از نرم افزارمون وظیفه هندل کردن یک نگرانی رو داشته باشه (اگر این جمله رو متوجه نمیشید بهتره که راجع به مفهوم Seperation of concern تحقیق کنید)2) O: Open/Closed Principleهر کلاسی باید برای توسعه یافتن قابلیت‌هایش اصطلاحاً Open بوده و دست برنامه‌نویس برای افزودن فیچرهای جدید به آن باز باشد اما اگر وی خواست تا تغییری در کلاس ایجاد کند، چنین امکان باید Closed بوده و او اجازهٔ چنین کاری را نداشته باشد.ضمانت می‌کند که کلاس ها قابل ارث بری و استفاده هستند ولی نباید از بیرون قابل تغییر باشند.3) L: Liskov Substitution Principleاین دوستمون میگه که که کلاس‌های فرزند باید آن‌قدر کامل و جامع از کلاس والد خود ارث‌بری کرده باشند که به سادگی بتوان همان رفتاری که با کلاس والد می‌کنیم را با کلاس‌های فرزند هم داشته باشیم به طوری که اگر در شرایطی قرار گرفتید که با خود گفتید کلاس فرزند می‌تواند تمامی کارهای کلاس والدش را انجام دهد به جزء برخی موارد خاص، اینجا است که این اصل رو خیلی زیبا نقض کردید :)4) I: Interface Segregation Principleاینترفیس‌ها فقط مشخص می‌کنند که یک کلاس از چه متدهایی حتماً باید برخوردار باشد. در همین راستا و بر اساس این قانون، چندین اینترفیس تک‌منظوره به مراتب بهتر است از یک اینترفیس چندمنظوره است به طوری که اگر یک اینترفیس چندمنظورهٔ کامل و جامع داشته باشیم و سایر کلاس‌های ما از آن اصطلاحاً implements کنند،‌ در چنین صورتی ممکن است برخی خصوصیات، متدها و رفتارها را به برخی کلاس‌هایی که اصلاً نیازی به آن‌ها ندارند تحمیل کنیم و خب این بده ! ، اما اگر از چندین اینترفیس تخصصی استفاده کنیم، به سادگی می‌توانیم از هر اینترفیسی که نیاز داشته باشیم در کلاس‌های مد نظر خود استفاده نماییم و در صورتی هم کلاسی وجود داشت که نیاز به استفاده از چندین اینترفیس مختلف داشت، دست ما باز خواهد بود تا آن کلاس را از چندین اینترفیس implements کنیم.5) D: Dependency Inversion Principleاین آخرین اصل سالیده و از نظر من غول مرحله آخرم میشه اسمشو گذاشت.. XD اول بگم که این غول مرحله آخر رو با Dependency injection قاطی نکنید فرق دارن درک این دوستمون یکم سخته.. به طور خلاصه، در OOP باید تمام تلاش خود را به کار بندیم تا Dependency (وابستگی) را مابین کلاس‌ها، ماژول‌ها و آبجکت‌های سطح بالا با ماژول‌های سطح پایین به حداقل برسانیم که با این کار، اِعمال تغییرات در آینده به مراتب راحت‌تر صورت خواهد پذیرفت :) ما باید این وابستگی هارو معکوس کنیم یعنی ماژول‌های سطح بالا نباید به ماژول‌های سطح پایین وابسته باشند. هر دوی آن‌ها (ماژول‌های سطح بالا و پایین) باید به Abstraction‌ ها وابسته باشند و باز هم به زبان ساده تر : Abstraction‌ ها نباید به جزئیات وابسته باشند. جزئیات باید به Abstraction‌ ها وابسته باشند.