تمیزکد(1) - امان از وابستگی ....

وابستگی‎هاسلام مجدد خدمت شما عزیزان، امیدوارم شاد و خوش باشید، با قسمت دوم از سلسله مطلب تمیزکد در خدمت شما هستم.توی قسمت صفرم یکم از دردسرای کدای کثیف و غیر اصولی گفتم که در عین حال که درست کار می‌‎کنن می‎‌تونن انرژی و منابع زیادی از ما یا صاحب برنامه بگیرن.خودمم یه کوچولو برنامه نویس هستم و میدونم که مقاومت دربرابر تغییر سبک کاری توی خون خیلی از برنامه نویس‎‌هاست؛ خیلیامون تا یه ذره بهمون ایراد می‌گیرن سریع می‌ریم روی سر طرف که: عامو اون موقع که تو توی خونتون آتاری دستی دستت بود من با NET. کار می‌کردم و کد می‌نوشتم . اما باید بپذیریم که یه کوچولو تغییر روش بد هم نیست. این جمله رو از مارتین فاولر(Martin Fowler) یه جا دیدم که بد نیست اینجا بگمش :هر احمقی می‌تونه کدهایی بنویسه که کامپیوتر بفهمه اما برنامه‌نویس خوب کدهایی می‌نویسه که دیگر انسان‌ها هم بتونن درک کنن.خب حالا که یه ذره نرم شدیم بهتره ببینیم اصلا دعوا سر چی هست؟ حقیقتش رو بخواید خیلی از دغدغه‌‎ها و چالش‌هایی که ما توی دنیای نرم افزار باهاش رو به رو هستیم زیر سر یک موضوع به نام وابستگی(Dependency) هستش !خیلی از معماری‎‌ها، الگوهای طراحی، تکنولوژی‌ها مثل package manager ها و... که امروز روی سر ما ریختن و ما باید باهاشون سر و کله بزنیم مربوط میشن به مدیریت وابستگی‌ها(Dependency Management) .وابستگی و مدیریت وابستگی خیلی کم پیش میاد که ما یک پروژه نرم افزاری رو به صورت ایزوله و بدون استفاده از کتابخونه، توابع، پکیج‌ها و یا سایر ابزار در دسترس توسعه بدیم. معمولا یک پروژه نرم افزاری وابستگی زیادی به توابعی با استفاده مجدد داره که به صورت کتابخونه یا اجزای جدا شده از سیستم استفاده می‎‌شن.(اینو می‌‎تونیم تعریف وابستگی بدونیم !)مدیریت وابستگی هم یک تکنیک برای شفاف سازی، حل پیچیدگی و استفاده کم دردسر از وابستگی‏‌های یک پروژه است‎.توی توسعه نرم افزار از نگرانی‌های مهم و فنی ما انسجام و پایداری همیشگی سیستم هستش که متاسفانه با بزرگتر شدن یک سیستم و به دنبال اون افزایش حجم و پیچیدگی وابستگی‌ها ویژگی‌هایی مثل استفاده مجدد و انعطاف پذیری سیستم به مرور کم می‌شه! مدیریت وابستگی‌ها به ما کمک میکنه این چالش‌ها رو بدون دردسر پشت سر بذاریم و سیستم پایدارتری داشته باشیم.خب حالا که فهمیدیم وابستگی و مدیریت اون چیه و چه اهمیتی داره، بریم ببینیم اگه توی یه سیستم وابستگی‌ها رو درست مدیریت نکنیم چه بلایی سرمون میاد و چه فاجعه ای رخ میده(سیستم می‌تونه یه نرم افزار غول یا حتی یه برنامه محاسبه فاکتوریل ساده باشه زیاد به چیزای عجیب فکر نکنید).فاجعه مدیریت وابستگی عمو باب (Uncle Bob) میگه: سیستمی که مدیریت درستی توی وابستگی‌ها نداره چهارتا بوی بد داره! یعنی اگه یه سیستم وابستگی‌هاش درست مدیریت نشده باشه چهارتا مشکل داره(یا یکی یا چندتا از این چهارتا)؛ این چهارتا بو چیا هستن؟سختی یا Rigidityشکنندگی یا Fragilityعدم تحرک(لَختی) Immobilityچسبناکی یا Viscosityدر ادامه می‎‌خوایم درمورد هرکدوم از این مشکلات چندتا چیز رو بررسی کنیم (چی هست؟ چرا پیش میاد؟ چطور تشخیص بدیم؟ دلیلش چیه؟)سختیچی هست؟به زبون ساده بخوام بگم، سختی یعنی ناتوانی در تغییر! یعنی ما یه تیکه کد نوشتیم(یا استفاده کردیم) اما الان نمی‎‌تونیم تغییرش بدیم، مثلا بهترش کنیم یا یه چیزی بهش اضافه یا ازش کم کنیم(به احتمال زیاد چون سیستم می‌پوکه!)چرا اینجور می‌شه ؟چرا تغییر سیستم سخت یا نشدنی می‌‎شه؟ چون هزینه تغییر میره بالا! هزینه می‎‌تونه هزینه مالی باشه، می‎‌تونه زمان باشه، می‌تونه منابع سیستم باشه یا هرچیزی که برای ما ارزشمنده باشه. یه مثال بزنیم که یکم بهتر جا بیفته: فرض کنید برای نوشتن، کامپایل و تست یک سیستم 2 ساعت وقت گذاشتید، حالا بعد از یک تغییر کوچیک مجبورید دوباره همین اندازه وقت بذارید! اینجا سیستم شما دچار سختی شده و هزینه هم اینجا زمان هستش.چطوری تشخیص بدیم سیستم ما با سختی رو به رو شده؟وقتی به ازای یک تغییر کوچیک مجبور میشیم کل سیستم رو rebuild کنیم وقتی به ازای یک تغییر کوچیک هزینه زیادی می‎پردازیم.اگر این نشانه‌‎ها رو توی کدتون دیدین یعنی سیستم شما دچار سختی شده(یعنی برنامه نویس‎‌هاتون یا خودتون بی حوصله و بی دقت هستین)چرا کدهامون سخت میشه ؟کدها به صورت رویه‌ای (Procedural) نوشته شده‌اند: برای مثال تمام کدها داخل یک فایل و به صورت if-elseهای متوالیT تو در تو و پیوسته نوشته شدن. استفاده از این روش کد نویسی شاید در اندازه تکه کدهای کوچیک و یا سیستم‌های کوچیک ما رو از دست سربار و انتزاعاتی مثل OOP راحت کنه اما به مرور و با گسترش پروژه این شکل کدنویسی تیم رو به دردسر زیادی می‌اندازه.مفهوم انتزاعی‌ای توی کدها وجود نداره: این مورد موقعی اتفاق میفته که کدها توی پایین‎ترین سطح ممکن نوشته شدن! برای مثال، به جای اینکه از یک کلاس برای مدل کردن استفاده کنید از مفهوم سطح پایین‎تری مثل آرایه استفاده کنید!یک کد کلی اما با جزئیات زیاد: فرض کنید یک متد برای چاپ کردن یه ماتریس به صورت جدول‎های HTML نوشتید. خب این یه چیز کلی هستش و شما می‎تونید هر ماتریسی رو برای چاپ به صورت جدول به عنوان ورودی به این تابع بدید و تابع هم براتون این جدول رو به صورت HTML رسم می‌کنه؛ حالا توی این چیز کلی شما میاید و رنگ و فونت سر ستون‌ها رو تعریف میکنید! درصورتی که این جزئیات می‎تونه جدول به جدول فرق کنه.چند وظیفگی : تابع یا تیکه کد شما بیش از یک کار رو انجام میده. فرض کنید یک تابع برای محاسبه مساحت یک مربع دارید که ضلع مربع رو به عنوان ورودی می‎گیره و مساحت اون رو بر می‎گردونه و یک تابع دیگه هم برای رسم مربع روی صفحه نمایش دارید. تا این‌جا قضیه درسته، مشکل از اونجا شروع میشه که شما از تابع دوم(رسم مربع) هر دو کار رو بخواید. یعنی هم مساحت رو حساب کنه و هم مربع رو بکشه.شکنندگیچی هست؟مفهوم شکنندگی و سختی خیلی نزدیک به هم هستن، درواقع میشه این دوتا رو علت و معلول هم دیگه دونست. شکنندگی یعنی اگر شما جایی از سیستم رو تغییر دادید، یه جای دیگه سیستم از کار بیفته! مثلا رادیو ماشین رو تعمییر کنید بعد موتور از کار بیفته /:به مرور که نرم افزار ما بزرگتر می‌‎‎شه این اتفاقات هم بیشتر می‌‎شن و بعد از هر تغییر ممکنه نرم افزار ما یه سکته ناقص بزنه! که این مشکل به اعتبار ما پیش مشتری‌ها و همکارامون لطمه می‌زنه. چون به ازای هر تغییر کوچیک ما باید زمان زیادی رو صرف رفع خطا کنیم به همین خاطر توی تحویل‎‌هامون تاخیر داریم و کیفیت محصولمون هم پایین میاد :(چرا اینجور میشه ؟خب دلایل این مشکل خیلی به دلایل مشکل سختی نزدیک هستن و تقریبا همونا هستنچطور تشخیص بدیم کدهامون شکننده شده ؟به ازای هر تغییر مجبوریم تغییرات متوالی توی جاهای مختلف اعمال کنیمدر اثر یک تغییر خطاهایی توی قسمت‌های دیگه سیستم که ربطی به هم ندارن رخ بدناگر یه قسمت از سیستم رو جدا کردیم، مجبور بشیم خیلی از جاها رو بازنویسی کنیمچرا دچار شکنندگی می‌شیم ؟جواب خیلی ساده ست؛ قسمت‎‌های مختلف(توابع، کلاس‌ها، کامپوننت‌ها، ماژول‎ها و....) سیستم از هم ایزوله نیستنخب فکر کنم برای این قسمت کافی باشه:) خیلی شد ! بررسی دو مشکل بعدی بمونه برای قسمت بعدی. ممنونم از توجه شما.قسمت‌های دیگه رو می‎‌تونید توی لینک‌های زیر ببینید:تمیز کد(0)تمیز کد(2)