برای بررسی مفهوم abstraction و information hiding که به پنهان کردن پیچیدگی های بخشی از یک سیستم از بخش های دیگر گفته می شود، و اعتبار آن باید ابتدا نوع نرم افزاری که می نویسیم را مد نظر داشته باشیم. یک مقاله خوب در باره کاربرد مناسب information hiding در بخش خوبی از نرم افزار ها http://www.stevemcconnell.com/ieeesoftware/bp02.htm می باشد. نویسنده مقاله ، همچنین نویسنده کتاب بسیار عالی Code Complete می باشد که دید شخص بنده را به برنماه نویسی تغییر داد و آن را به همه پیشنهاد می کنم.
انواع مختلف نرم افزار عمر های متفاوتی دارند و از ویژگی های متفاوتی نیز برخوردار هستند. برای مثال نرم افزار های شاتل های فضایی عموما بدون هیچ تابعی نوشته می شوند و چند هزار خط کد پشت سر هم هستند (زیر 5 هزار خط). دلیل این کار نیاز به مشخص بودن دقیق تمام کارهایی است که اتفاق می افتد. در این گونه نرم افزار ها این است که هر خواننده ای بتواند بدون رفتن به تابع دیگری یا ... بداند کد دارد دقیقا چه کاری انجام می دهد. بازی ها نوع دیگری از نرم افزار هستند که معمولا عمر نسبتا کوتاه چند ساله دارند و کد آن ها در آینده خیلی مورد استفاده قرار نمی گیرد. به این دلیل خیلی از مسایل مربوط به آماده سازی کد برای تغییرات شدید در آینده در آن ها صورت نمی گیرد. همچنین چون بازی ها در لایه نزدیکتری نسبت به سخت افزار سیستم نوشته می شوند تا performance بهتری داشته باشند، خیلی از کارهایی که در نوشتن نرم افزار های اداری مناسب هستند در آن ها قابل پیاده سازی نیستند. در مقابل برخی نرم افزار های اداری بیش از 50 سال سن دارند و در طول زمان تغییرات فراوانی می کنند.
از نظر من، پنهان کردن پیچیدگی ها پشت توابع جذابترین نوع information hiding می باشد زیرا شما بدون پرداخت هزینه زیادی کد را بسیار خواناتر و بسیار قابل تغییرتر می کنید. در مقابل قرار دادن برخی بخش های برنامه پشت abstraction های مختلف مثل interface ها هیچ سود خاصی ندارد زیرا در صورت تغییر آن بخش نوع رویکرد شما با آن نیز تغییر می کند. تکنولوژی WCF به شدت از این مشکل رنج می برد و برنامه نویس هایی که در تمام توابع به جای برگرداندن یک نوع collection خاص (مثل آرایه یا لیست) یک نوع عمومی (مثل IEnumerable در .NET) را برمی گردانند نیز با این مشکل روبه رو هستند. واقعیت این است که اگر لیست شما به صف یا پشته تبدیل شود ، نوع کارکرد شما و دید شما به آن تفاوت شدیدی خواهد کرد، شما می توانید با یک لیست کتاب در فروشگاه به عنوان یک abstraction برخورد کنید ولی درون این ماژول یا کلاس یا ... باید دقیقا مساله لیست کتاب ها را با توجه به ساختمان های داده مورد استفاده حل کنید. هر برنامه در نهایت یک سری ورودی و یک سری تابع برای تغییر داده ها و ارسال داده ها به خروجی است و به جز این تغییرات هیچ ارزش دیگری ندارد. ما در دنیای واقعی زندگی می کنیم و در حال تلاش برای حل مسایل واقعی روی سخت افزار های واقعی هستیم و همیشه نمی توانیم این مسایل را به مسایلی abstract تبدیل کنیم و خیلی اوقات خیلی از ما این حقیقت را فراموش می کنیم. هنگامی که شما از IEnumerable استفاده می کنید، هنگامی که از Linq استفته می کنید ، تعداد زیادی memory allocation و virtual method call اضافه دارید که می توانستید نداشته باشید. اگر یک وب سایت ساده می نویسید که روزی 300 نفر از آن بازدید می کنند، این مساله اهمیتی ندارد اما اگر در حال ساخت کتابخانه ای برای دیگران هستید، اگر یک نرم افزار high performance یا نرم افزاری برای سرور و یا سخت افزار های کوچک و ضعیف می نویسید باید به این مسایل دقت کنید. من ترجیح می دهم هنگام نوشتن ساده ترین نرم افزار ها هم کار خود را به بهینه ترین شکل ممکن برای حل مساله واقعی پیش رویم انجام دهم تا با مصرف کمتری از منابع ، کار خود را به شکل بهتری انجام داده باشم. اصلا پیشنهاد نمی کنم که برای بهینه کردن برنامه هایی که نیاز ندارند دنبال optimize کردن تمام خطوط باشید بلکه پیشنهاد می کنم به جای نوشتن ابزار و به نوعی compiler و general problem solver سعی کنید مساله پیش روی خود را حل کنید مگر این که دلیلی برای حل مساله ای کلیتر وجود داشته باشد. خیلی وقت ها واقعا شما در حال مساله ای کلی هستید اما خیلی وقت ها این طور نیست. فراموش نکنید خیلی وقت ها تغییرات مورد نظر شما با تغییر یک interface و پیاده سازیش امکان پذیر نیستند، مثلا اگر شما به جای TCP از UDP استفاده کنید و یا به جای SQL Server از Riak به عنوان پایگاه داده استفاده کنید، نمی توانید تمام مسایل مربوط به این تغییرات را پشت یک interface پنهان کنید و خیلی وقت ها رویکرد شما در بخش های مختلف برنامه با این تغییرات نیاز به تغییر خواهد داشت. به این دلیل خوب است اول فکر کنیم که آیا باید برای انجام کاری از abstraction ها استفاده کنیم یا خیر.
نکته آخری که در باره abstraction ها و روش معمول پیاغده سازی آن ها در سیستم های object oriented وجود دارد این است که ساخت سلسله مراتب های بزرگ از object ها ساخت مدلی ذهنی از برنامه را برای دیگران (و خودتان پس از گذشت یکی دو ماه) سخت خواهد کرد و شما با ساختن این سلسله مراتب ها و آماده سازی خود برای آینده ، امروز در حال پرداخت هزینه ای هستید که ممکن است سودش هیچ وقت حاصل نشود. برای درک این موضوع فکر کنید که چند بار این abstraction ها به شما سود رسانده اند و چند بار به دلیل نداشتن توانایی حل مساله شما در ساختار کلی خود، مجبور به تغییر آن ها شده اید. حل مسایل کلی یا خاص و تعریف abstraction ها مسایلی مربوط به هم هستند و معمولا با هم و در کنار هم قرار می گیرند. برخی مسایل بسیار عمومی وجود دارند که از داشتن abstraction بهره می برند و حتی همین abstraction ها هم گاه و بی گاه باید شکسته شودند و شما باید بدانید پشتشان چه خبر است تا بتوانید کارتان را به شکل بهینه انجام دهید. هدفم از نوشتن این پست این بود که تلنگری به ذهن خودم و خوانندگان بزنم که هنگام تولید abstraction ها به هزینه آن ها و میزان فایده آن ها بیشتر فکر کنیم.