دانستنی‌ها

ترس از کاهش وابستگی

اگر زمانی که پای برنامه‌نویسی شی‌گرا به میان بیاید، از حذف وابستگی‌های بین اشیا واهمه دارید، تا انتهای این مقاله با ما همراه باشید.

اشیا از طریق متدهایشان با یکدیگر صحبت می‌کنند.

در زبان‌های برنامه‌نویسی پیشرفته مانند Java یا #C، یک شی ممکن است تعدادی متد مختلف داشته باشد که اگر شی مذکور، واسط یا واسط‌هایی را بخواهد پیاده‌سازی کند، متدهای آن واسط‌ها نیز به جمع متدهایش اضافه خواهد شد. تجربه صحبت با تعداد زیادی برنامه‌نویس، می‌گوید که اکثر ما از اشیایی که متدهای واسطی (interface methods) زیادی دارند، می‌ترسیم. زیرا از آن‌جایی که این متدها چندریختی (polymorphic) و متعاقبا غیرقابل اطمینان هستند، دوست نداریم با آن‌ها سر و کله بزنیم. ترس منطقی‌ای هم هست. اما بیایید تحلیل کنیم و ببینیم که این ترس دقیقا ناشی از چیست.

طبق معمول، با یک مثال جاوایی ساده شروع می‌کنیم. در این‌جا، مقدار پولی که قصد داریم به یک کاربر دیگر مثلا از طریق PayPal API ارسال کنdم مشخص است.

interface Money {
  double cents();
}

حالا، در اینجا متدی داریم که این پول را ارسال می‌کند.

void send(Money m) {
  double c = m.cents();
  // Send them over via the API...
}
دو تکه‌کد بالا به هم وابسته نیستند. چرا که متد ()send هیچ ایده‌ای ندارد که متد ()cents چگونه و توسط چه کلاسی پیاده‌سازی شده است. شاید مثلا یک کلاس constant ساده برای یک دلاری است:
class OneDollar implements Money {
  @Override
  double cents() {
    return 100.0d;
  }
}
یا شاید، یک موجودیت بسیار پیچیده‌تر باشد که ابتدا به منظور به دست آوردن نرخ فعلی تبدیل دلار به یورو، به شبکه وصل می‌شود، پایگاه‌داده را به‌روزرسانی می‌کند و سپس نتیجه حاصل از یک سری محاسبات را بر می‌گرداند.
class EmployeeHourlyRate implements Money {
  @Override
  double cents() {
    // Fetch the exchange rate;
    // Update the database;
    // Calculate the hourly rate;
    // Return the value.
  }
}
متد ()send از این که دقیقا چه چیزی در آرگومان اولش قرار دارد، آگاه نیست. تنها کاری که می‌تواند بکند، این است که امیدوار باشد متد ()cents به درستی کار کند. اما، اگر درست کار نکند چه؟
اگر من توسعه‌دهنده متد ()send باشم و احتمال دهم که برای اشتباهاتی که ممکن است متدم ایجاد کند، سرزنش می‌شوم، دوست دارم بدانم که کدم با چه متدهای دیگری تعامل دارد و سپس کاملا مطمئن شوم که آن‌ متدها کار می‌کنند. نه اینکه فقط کار کنند، بلکه دقیقا مطابق چیزی که ازشان انتظار داریم کار کنند. بنابراین، ترجیح خواهم داد که شخصا آن متدها را نوشته و اطمینان حاصل کنم که پس از آنکه من آن‌ها را پیاده‌سازی کردم، هیچ کس دیگری به آن‌ها دست نزده و تغییرشان ندهد. قطعا طنز موقعیت را درک می‌کنید. مگر نه؟
ممکن است مثل یک جک به نظر برسد، اما این برهان و استدلال را بارها از زبان برنامه‌نویسان مختلف شنیده‌ایم. آن‌ها می‌گویند که «به جای آن‌ که به چندریختی اعتماد کنیم و بعد هم ساعت‌ها برای دیباگ کردن کدی که خودمان ننوشته‌ایم وقت صرف کنیم، بهتر است کاملا مطمئن شویم که دو تکه‌کد مورد نظر، به درستی با هم کار می‌کنند. حق هم دارند. با استفاده از چندریختی- زمانی که یک شی ظاهرا primivite از نوع Money، هر کاری که دلش بخواهد (مثل درخواست‌های HTTP و کوئری‌های SQL UPDATE) می‌کند- قطعا قابلیت اطمینان اپلیکیشن افزایش نمی‌یابد.
مشخصا، چندریختی زندگی را برای توسعه‌دهندگان نوع Money، بسیار ساده‌تر می‌کند. زیرا آن‌ها خیلی مجبور نیستند به کاربرهایشان فکر کنند و تنها دغدغه‌شان این است که وقتی متد ()cents فراخوانی شد، به چه صورتی یک مقدار double برگردانند. نیازی نیست به سرعت، استثناهای بالقوه، استفاده از حافظه و خیلی چیزهای دیگر فکر کنند. زیرا واسط چنین نیازی را ایجاب نمی‌کند و صرفا به آن‌ها می‌گوید که اگر یه روزی این متد فراخوانی شد، یک مقدار double برگردان و بگذار یک نفر دیگر نگران چیزهای دیگر باشد. راحت است نه؟ اما ممکن است بگویید که «این طرز فکر، کودکانه و خودخواهانه است». درسته؟
بله درسته.
در هر صورت، اکثر شما ایده «شکست سریع (Fail-Fast)» را شنیده‌اید. به طور خلاصه، این ایده ادعا می‌کند که جهت قدرتمندی و پایداری یک اپلیکیشن، باید اطمینان حاصل کنیم که اجزایش تا حد ممکن در برابر هر موقعیتِ بالقوه بروز استثنا، شکننده و آسیب‌پذیر باشد. این اجزا باید هر زمان که شد، از کار بیفتند و اجازه دهند کاربرانشان با این شکست مقابله کنند. با این فلسفه، هیچ شی‌ای هیچ فرض مثبتی در مورد همتایان خود نکرده و مشکلاتش را به سطوح بالاتر و در نهایت به کاربر ارسال می‌کند. سپس کاربر خطا را به تیم توسعه گزارش می‌کند. تیم توسعه نیز تمام خطاهای گزارش‌شده را برطرف کرده و به مرور کل محصول پایدار می‌شود.
اگر عکس این طرز فکر را در نظر بگیریم و هر شی سعی کند که در سطح کوچک و شخصی خودش، مشکلات را برطرف کند، اکثریت مواقع استثناخیز برای کاربران، از دید تست‌کننده‌ها، معمارها و برنامه‌نویسانی که قرار است با آن مشکلات سر و کله بزنند و راه حلی برای ]ن‌ها پیدا کنند، پنهان خواهد ماند. با تشکر از این طرز تفکرِ مراقبت فردی از اشیا، ثبات و استحکام کل برنامه آسیب می‌بیند.
حالا چنین منطقی را می‌توان به مساله ترس از کاهش وابستگی هم بسط داد.
زمانی که نگرانیم ()Money.cents چطور کار خواهد کرد و سعی می‌کنیم رفتارش را کنترل کنیم، به خودمان و کل پروژه ضربه بزرگی می‌زنیم. در بلندمدت، ما به جای ایجاد ثبات، آن محصول را بی ثبات می‌سازیم.
بعضی‌ها حتی می‌خواهند با تعریف متد ()send به صورت زیر، از چندریختی جلوگیری کنند:
void send(EmployeeHourlyRate m) {
  // Now I know that it's not some abstract Money,
  // but a very specific class EmployeeHourlyRate, which
  // was implemented by Bobby, a good friend of mine.
}

در اینجا، تعداد اشتباهاتِ ممکن کدمان را محدود می‌کنیم، زیرا Bobby را می‌شناسیم و کدش را دیده‌ایم و می‌دانیم که چطور کار می‌کند و انتظار چه استثناهایی را باید داشته باشیم. فعلا در امانیم. اما از لحاظ استراتژیک، با اجازه ندادن به نرم‌افزار در ایجاد اشتباهات احتمالی و پرتاب تمام استثنائات ممکن در همه شرایط غیرمعمول، امکان به درستی آزمایش شدنش را به طور جدی محدود می‌کنیم. به این ترتیب، نرم‌افزار بی‌ثبات می‌شود.

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

در عوض، نه تنها به Bobby، بلکه به همه باید اجازه دهیم Money را پیاده‌سازی کنند. بله، بعضی از این پیاده‌سازی‌ها ممکن است باعث بروز خطاهای قابل مشاهده در UI بشوند. اما اگر مدیر، مفهوم کیفیت نرم‌افزار را به درستی درک کرده باشد، ما را سرزنش نخواهد کرد. بلکه ما را تشویق می‌کند هر چه بیشتر، باگ‌ها را پیدا کرده و با کمک تست‌های خودکار، آن مواقع بروز خطا را مجددا ایجاد کرده، مشکل را حل کنیم و مجددا کد را deploy کنیم.

بنابراین، ترس از کاهش وابستگی، چیزی نیست جز ناقص امنیت اپلیکیشن

منبع

نوشته های مشابه

یک دیدگاه

دیدگاهتان را بنویسید

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

دکمه بازگشت به بالا