در دنیای طراحی نرم افزار معماران, توسعه دهندگان و همه و همه به دنبال یک چیز هستیم, سادگی! به دنبال سیستم هایی هستیم که قدرتمند و ساده باشند, برای همین سعی می کنیم با به کارگیری اصول معماری, دیزاین پترن ها و... سیستم هایی بسازیم که نگهداری و توسعه آن ها ساده باشد. اما اغلب اوقات با تصمیم های به ظاهر منطقی اما اشتباهی که میگیریم در تله سادگی افتاده و یکسری پیچیدگی پنهان به نرم افزار اضافه می کنیم که خودشان را با رشد نرم افزار در آینده نشان می دهند.
ما بیشتر اوقات فکر می کنیم که با استفاده از پترن ها, ابزارها و رعایت اصول داریم کار درست را انجام می دهیم و نرم افزار را با چارچوب استاندارد و ساده جلو می بریم. اما همین ابزارها, پترن ها و اصول مثل یک شمشیر دو لبه عمل می کنند و منجر به ایجاد پیچیدگی های عجیب و غریب در سیستم می شوند. برای مثال انتخاب معماری اشتباه بدون توجه به نیازهای سیستم, استفاده بیش از حد و اشتباه از دیزاین پترن ها, اضافه کردن بیش از حد ماژول ها و یکسری موارد دیگر که در آن لحظه منطقی به نظر می رسیدند, باعث می شود که نرم افزار به شکل عجیبی دچار پیچیدگی هایی شود که خود را در آینده وقتی نرم افزار بزرگ تر می شود نشان می دهند. این دقیقا همان تله سادگی می باشد. این فریب نه از بیرون بلکه از داخل سیستم به دستان توانمند خودمان به وجود می آید.
یکی از اصلی ترین موارد وابستگی ها می باشند. وابستگی های پنهانی شاید زمان طراحی مشخص نباشند اما به مرور زمان باعث پیچیده تر شدن و شکست سیستم می شوند. در یک مثال ساده دوتا ماژول را در نظر بگیرید که در سیستم بهم وابسته هستند و این وابستگی ها نیز منطقی هستند. خیلی از اوقات با رشد نرم افزار و بزرگ شدن متوجه میشویم که به صورت ناخواسته وابستگی های بیشتری از این جنس در سیستم شکل گرفته که در حال حاضر هر تغییر کوچکی در یکی از آن ها می تواند ماژول های دیگر و در نهایت کل سیستم را ایمپکت کند. وابستگی بین ماژول ها اجتناب ناپذیر است ولی اینجا بحث سر مدیریت درست وابستگی ها مثل استفاده از Dependency Injection, Interface ها و... می باشد.
یکی از موارد دیگر استفاده از دیزاین پترن ها می باشد. درست است که دیزاین پترن ها قدرتمند و کاربردی هستند اما این قدرت و کارایی را زمانی به ما می دهند که درست و به جا از آن ها استفاده کنیم. استفاده اشتباه و نادرست برای راه حل های ساده یا متفاوت از آن به مرور باعث افزایش پیچیدگی در سیستم می شوند. سوالاتی که قبل از استفاده از هر دیزاین پترن از خود باید بپرسیم این است که قرار است دقیقا چه مشکلی را حل کنیم؟ آیا این پترن راه حل مناسبی می باشد؟ استفاده از آن باعث چه مشکلاتی می شود؟
مورد دیگر مدیریت نادرست خطاها و عدم توجه به آن ها می باشد. خیلی از اوقات به جای اینکه خطاها را به صورت کامل شناسایی و مدیریت کنیم به شکلی با آن ها برخورد می کنیم که انگار مشکلی وجود ندارد(اگر بتوانیم نهایت خطاها رو لاگ می کنیم). این کار احتمالا در کوتاه مدت مشکلات را رفع(پنهان) می کند, اما به مرور به مشکلات بزرگ تر و جدی تری تبدیل می شوند که هزینه های رفع آن ها بسیار بیشتر از قبل می باشد.
موارد دیگر می توان به مشکلاتی مانند
Over-Modularization:
درست است که ماژولار بودن به مدیریت بهتر سیستم کمک می کند اما تقسیم بندی بیش از حد سیستم به ماژول های جداگانه باعث سردرگمی و پیچیده شدن مدیریت و هماهنگی بین آن ها می شود.
Over-Abstraction:
زمانی که بیش از حد abstract می کنیم درک سیستم را سخت تر کرده و تغییراتی را که راحت می توانستیم انجام بدهیم حال باید در لایه های پایین تر انجام دهیم.
Over-Engineering:
دست از پیش بینی و مدیریت بیش از حد نیازها و مشکلات آینده که هنوز به وجود نیامنده اند برداریم! مواردی که شاید هیج وقت رخ ندهند.
در پایان, باید قبول کنیم که افتادن در این تله اجتناب ناپذیر است. اما می توان با درک عمیق تر از نیازهای واقعی سیستم قبل از شروع و مواردی که باعث این تله می شوند تا حدود زیادی این پیچیدگی ها را کاهش داد. تمام تصمیمات کوچک و بزرگی که میگیریم در طول عمر نرم افزار تاثیر گذار هستند.