اصول SOLID در مهندسی نرم افزار

در این آموزش قصد دارم اصول SOLID در مهندسی نرم افزار تشریح کنم و برای درک بهتر مطلب از مثال های کاملا خوب و کاربردی استفاده میکنم.

یادگیری و بکارگیری این قوانین به شدت روی کیفیت کدنویسی و توسعه پذیری نرم افزار تاثیر می گذارد. همچنین توسعه نرم افزار شما دارای مزایای زیر خواهد بود.

  • کد نویسی تمیز
  • مقیاس پذیری کد
  • افزایش استفاده مجدد از کد
  • تست نویسی راحت تر
  • توسعه سریعتر

چگونه اصول SOLID بوجود آمدند؟

از وقتی که برنامه نویسی شی گرا جایگزین برنامه نویسی تابعی گردید برنامه نویسان زیادی به سمت شی گرایی رفتند و چون شی گرایی تازه اول راه بود هر برنامه نویسی به شیوه خود کدنویسی می کرد و چارچوب و اصول خود را بکار می گرفت، پس تجربه موفقیت آمیزی وجود نداشت که به عنوان اصل یا روشی استفاده شود.

از این رو نرم افزار های تولید شده زیادی با شکست مواجه شدند و اکثر آنها توانایی تغییر و توسعه پذیری بسیار پایینی داشتند، در نتیجه اکثرا عمر کوتاهی داشتند.

توسعه دهندگان با تجربه وارد عمل شدند

با افزایش این مشکلات، توسعه دهندگان نرم افزار شروع به ارائه راه حل های متنوع کردند و به جمع آوری و تکمیل تجربیات خودشان کردند. بعد با همفکری یکدیگر به تکمیل آنها پرداختند.

بعد از آن اقدام به ثبت تجربیات موفق خود به صورت طرح کردند، که بعدا این طرح ها به اصولی تبدیل شدند که به آنها Design Pattern گفته شد.

یکی از کاربردی ترین Design Pattern های موجود که بسیار از آن استقبال می شود SOLID نام گرفت.

بگذارید قبل از پرداختن به اصول SOLID کمی در رابطه با مشکلات توسعه صحبت کنیم.

مشکلات رایج توسعه نرم افزار شی گرا

با بزرگتر شدن نرم افزارها، تعداد کلاسها و بسته ها بیشتر میشوند. و از آنجایی که کلاسها با هم ارتباط دارند بهتر است به نحوی به یکدیگر متصل شوند که دچار پیچیدگی و هرج و مرج نشود.

این پیچیدگی و نامنظمی ممکن است موجب شود کلاس های نرم افزار همچون کلاف درهم پیچیده ای شود که پیدا کردن خطا در آن و یا تغییر آن به امری محال تبدیل گردد.

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

اگر اتفاقات بالا رخ دهد، قطع به یقین با مشکل کندی پیشرفت کدنویسی مواجه خواهید بود.

این موضوع برای کارفرمایان و سازمان ها به معنی ضرر است و ضرر یعنی ورشکستگی و هدر رفت منابع سازمان.

مشکل اساسی بعد، ساخت چرخ از ابتدا است. یعنی کدی که نوشته میشود را باید بتوان در قسمت های دیگر نرم افزار استفاده نمود و با اعمال تغییر در آن نیاز به تغییر در تمام قسمت ها نباشد. از این رو، توسعه نرم افزارهای نامنظم بسیار سخت خواهد بود و اعمال تغییر در آن موجب رخداد خطاهای بسیاری می شود.

در نرم افزار هر قسمت (کلاس، ماژول، بسته) باید کار خود را انجام دهد. و ارتباط منظم بین قسمت های مختلف یعنی مدیریت خوب و نتیجه مدیریت و ارتباطات خوب سیستمی منعطف و قابل تغییر به وجود خواهد آورد.

پس برای این که بخش های مختلف هر کدام کار خود را به خوبی انجام دهند و در کار ماژول های دیگر اخلال ایجاد نکنند باید قوانین مدیریت ارتباطات نرم افزاری یاد بگیریم.

اصول SOLID

۵ اصل SOLID جزو بهترین تجربیات برنامه نویسی شی گرا (تا الان) هستند. که در زیر به بررسی تک تک ۵ اصل SOLID خواهیم پرداخت.

اصل شماره ۱ سالید (Single Responsibility)

هر کلاس می بایست، فقط یک کار انجام دهد و تغییر آن فقط به دلیل همان کار باشد.

ما میتوانیم مانند تصویر بالا همه چیز را در یک کلاس به نام Employee بگنجانیم یا این که بین سه کلاس Engineer، NewspaperEditor و یا Author تقسیم کنیم.

این سه نقش نقش های یک دفتر روزنامه می باشند که هرکدام وظایف منحصر بفرد خود را دارند.

اگر برای مدیریت این نقش ها بخواهید برنامه بنویسید این قانون از اوجب واجبات و جزو کلیدی ترین قوانین 5 گانه SOLID است.

برای درک بهتر به نمودار قبل دقت فرمایید.

در مثال بالا بخش های مختلف را به کلاس های متعدد تقسیم نمودیم و به هر کدام وظایف منحصر بفرد و تفکیک شده اختصاص دادیم.

هر کلاس فقط باید یک کار انجام دهد و به همین دلیل هم تغییر می کند.

دلیل استفاده از این اصل چیست؟

  • هماهنگی اعضای تیم
  • در این حالت اعضای تیم میتوانند به خوبی کار را تفکیک نمایند.
  • خطایابی سریع تر
  • برای یافتن خطا نیاز به زیرورو کردن تمام کدها نیست. چرا که شما با تغییر یک قسمت از کد خطا را برطرف خواهید کرد.
  • تست نویسی راحت تر و سریعتر
  • برای نوشتن تست نیاز به ترکیب چند کلاس نیست.
  • میتوان یک تست را برای هر کلاس و توابع بطور مجزا انجام داد و به خوبی تفکیک کرد.

اصل شماره ۲ سالید (اصل باز و بسته یا Open – Close)

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

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

برای درک بهتر این اصل فرض کنید، سیستم شما می تواند به شبکه های اجتماعی آخرین پست ها را بفرستد. از این رو شما روز اول برای سیستم تلگرام یا پیام رسان های داخلی مثل سروش کدنویسی کرده اید.

بعد از آن متوجه میشوید که می توانید در شبکه اجتماعی اینستاگرام نیز فعالیت کنید.

از این رو سیستم شما باید بتواند بدون تغییراتی که منجر به خراب شدن ارتباطات قبلی شود ، ارتباط با سیستم اینستاگرام را نیز به کد خود اضافه نمایید.

راهکار پیاده سازی اصل باز و بسته SOLID

مفهومی در برنامه نویسی شی گرا وجود دارد که به این موضوع کمک می کند. ما به جای دست به دست کردن کلاس اصلی بین سایر کلاس ها (که نباید تغییر کند) اینترفیس آن را دست به دست می کنیم.

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

در واقع اسکلت یک کلاس را با اینترفیس می سازیم تا این کلاس را به شکل های مختلف توسعه دهیم.

اینترفیس (Interface)

اینترفیس مانند کلاس است، با این تفاوت که توابع موجود در اینترفیس پیاده سازی نمی شوند و بیشتر از اسم و تعریف پارامترهای ورودی چیزی در آن ها نیست. به این تعریف امضاء یک کلاس یا اینترفیس گفته می شود.

مثلا یک تابع برای ارسال پیام در تمام کلاسهای شبکه اجتماعی وجود دارد. از این رو ، امضاء آن در اینترفیس تعریف می شود تا همه کلاس های اصلی مرتبط با شبکه اجتماعی آن را پیاده سازی نمایند.

کلاس استفاده کننده (صدا زننده) میداند که یک متد به نام مورد نظر (مثلا sendMessage) وجود دارد، در نتیجه تنها آن را صدا می زند و کاری ندارد که پیام به کدام پیام رسان ارسال می گردد.

از این رو تفاوتی بین پیام رسان ها قائل نمی شود.

اصل شماره 3 سالید (اصل Liskov substitution)

شی های قدیمی را با ارث بری توسعه دهید، اصل کد رو دستکاری نکنید.

این اصل بسیار ساده است و توسط ارث بری شی گرا پیاده سازی می گردد.

مثلا فرض کنید کلاس اینستاگرام توسعه پیدا می کند و فیلدی مثل توضیحات نیز بدان اضافه می شود. شما باید کد نویسی کلاس اصلی را دستکاری نکنید اما یک کلاس جدید مثلا ExtendInstagram تعریف می کنید و از کلاس اصلی اینستاگرام ارث بری می کنید. از این پس می توانید جای این کلاس رو با کلاس قبلی عوض کنید.

اصل 4 (Interface Segregation)

این اصل به جدایی اینترفیس ها اشاره دارد. یعنی یک اینترفیس را بین دو مفهوم به اشتراک نگذاریم. بلکه اینترفیس های مجزا بسازیم که بتوانیم به کلاس های مختلف اختصاص دهیم.

مثلا فرض کنید ما کارمندان زیر را در فروشگاه خود داریم.

  • پشتیبان
  • توسعه دهنده

فرض کنید کارمند پشتیبان فقط پشتیبانی می کند. و کاربر توسعه دهنده علاوه بر توسعه نرم افزار وظیفه پشتیبانی را نیز به عهده دارد.

پس برای کد نویسی ممکن است بدین شکل عمل کنیم.

یک اینترفیس EmpJob تعریف می کنیم که امضاء توابع کارمندان را درون خود نگهداری می کند. بعد از آن کلاس Developer ساختار آن را پیاده سازی می کند.

و هر دو عملیات کار خود را به درستی انجام میدهند.

اما زمانی که نوبت به پیاده سازی کارمند Support گردید آن را بدین شکل راه اندازی می کنیم.

بعد در جایی که کارمند پشتیبان باشد خروجی تابع developing را null بازگردانی می کند.

قطعا شما هم متوجه شده اید که این شیوه کد نویسی تمیز و منظم نیست.

پس راهکار چیست؟

مانند تصویر زیر برای هر کارمند یک اینترفیس مجزا ایجاد می کنیم.

از این رو برای استفاده از اینترفیس در کلاس Developer هر دو اینترفیس را پیاده سازی می کنیم تا هر دو متد کاربردی را داشته باشد.

\"\"

و اما برای کلاس Support میتوان تنها اینترفیس SupporterInterFace را پیاده سازی کرد تا تنها امکانات مربوط به پشتیبانی را داشته باشد.

این همان اصل Interface Segregation است.

اصل 5 سالید (Dependency Inversion)

کلاس های سطح بالا نباید به کلاس های سطح پایین وابسته باشند.

برای پیاده سازی این اصل، که یکی از اصل های زیر مجموعه اصل باز و بسته است، مانند نمودار زیر عمل می کنیم.

مانند مثال قبل یک اینترفیس با نام SenderInterface ایجاد می کنیم و در کلاسهای TelegramSender و InstagramSender آن را پیاده سازی می نماییم. و از آن پس برای استفاده از آن ها می توان اینترفیس مورد نظر را دست به دست نمود.

اگر این اصل شبیه به روش 2 به نظر می آید درست متوجه شدید، چرا که اصل 5 درواقع زیرمجموعه اصل 2 است.

یا یک مثال بهتر ارسال اطلاعیه به کاربران است. فرض کنید سیستم ما باید در مواقع مختلف برای کاربر اطلاعیه ارسال کند.

  • ثبت سفارش
  • ثبت نام
  • سررسید فاکتور
  • و موارد دیگر

امروز شاید با ایمیل اطلاع رسانی شود و در آینده تمایل داشته باشیم از SMS استفاده کنیم.

کد نویسی باید به گونه ای باشد که ما وابسته به سیستم زیر کلاس نباشیم.

مثلا اگر ما سیستم را طوری طراحی کنیم که وابسته به کلاسی به نام Mailer باشد، هنگام مهاجرت به سیستم پیامکی این وظیفه به سختی انجام خواهد شد.

پس می توانیم با کمک گرفتن از اینترفیس ها این وابستگی را از بین ببریم.

دیدگاه‌ خود را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

سبد خرید
پیمایش به بالا