قدرت سادگی را در مهندسی نرمافزار در آغوش بگیرید
در دنیای توسعه نرمافزار، یک اصل قدرتمند وجود دارد که اغلب در شتاب برای ساختن محصول بزرگ بعدی نادیده گرفته میشود: سادهترین کاری را انجام بده که احتمالاً کار میکند. این فقط یک عبارت جذاب نیست؛ بلکه یک فلسفه راهنماست که میتواند در همه چیز، از رفع یک باگ جزئی گرفته تا معماری یک سیستم کاملاً جدید، به کار گرفته شود.
بسیاری از مهندسان برای تصور یک سیستم «ایدهآل» آموزش دیدهاند—یک شاهکار کاملاً مهندسیشده، بینهایت مقیاسپذیر و با طراحی زیبا. با این حال، این رویکرد اغلب اشتباه است. به جای دنبال کردن یک آینده فرضی، استادی واقعی در درک عمیق سیستم فعلی و پیادهسازی سرراستترین راهحلی است که نیاز فوری را برآورده میکند.
چرا راهحلهای ساده بیهیجان به نظر میرسند (و چرا این چیز خوبی است)
همانطور که مهندسان با ابزارهایی مانند پایگاههای داده، حافظههای پنهان (cache) و صفها (queue) مهارت پیدا میکنند، یک وسوسه طبیعی برای استفاده از همه آنها به وجود میآید. ساختن سیستمهای پیچیده با قطعات متحرک زیاد هیجانانگیز است. اما، بسیار شبیه به یک استاد هنرهای رزمی که از حرکات حداقلی و دقیق استفاده میکند، یک مهندس خبره میداند چه زمانی کمتر کار کند، نه بیشتر.
طراحی نرمافزار عالی اغلب به طرز فریبندهای ساده به نظر میرسد. پیچیدگی را فریاد نمیزند. در عوض، افکاری مانند «نمیدانستم مشکل اینقدر آسان بود» یا «چه خوب که برای این کار به یک راهاندازی پیچیده نیاز نداریم» را برمیانگیزد. وب سرور Unicorn را در نظر بگیرید که با تکیه بر اصول اولیه یونیکس به جداسازی درخواستها و مقیاسپذیری دست مییابد. زرق و برق ندارد، اما به دلیل سادگیاش، یک قطعه طراحی درخشان است.
تصور کنید که باید به یک برنامه Go قابلیت محدودسازی نرخ درخواست (rate limiting) اضافه کنید. سادهترین رویکرد چیست؟
- ایده پیچیده: یک نمونه جدید Redis راهاندازی کنید تا درخواستهای کاربر را با الگوریتم leaky-bucket ردیابی کند.
- ایدهای سادهتر: چه میشود اگر تعداد درخواستها را در حافظه (in-memory) ردیابی کنید؟ بله، ممکن است دادهها هنگام راهاندازی مجدد از بین بروند، اما آیا این یک شکست حیاتی است؟
- سادهترین ایده: آیا پراکسی لبه (edge proxy) موجود شما میتواند محدودسازی نرخ را انجام دهد؟ چند خط در یک فایل پیکربندی ممکن است کل مشکل را حل کند، بدون نوشتن حتی یک خط کد در برنامه.
نکته کلیدی این است که با سادهترین گزینه شروع کنید و تنها زمانی پیچیدگی را اضافه کنید که یک نیاز جدید آن را کاملاً ضروری کند. این کاربرد نهایی اصل YAGNI («شما به آن نیاز نخواهید داشت») است.
پاسخ به شکاکان: نگرانیهای رایج در مورد سادگی
البته، این رویکرد سوالات معتبری را مطرح میکند:
۱. آیا این رویکرد به یک «گلوله بزرگ گلی» (Big Ball of Mud) منجر نمیشود؟
برخی ممکن است استدلال کنند که انتخاب همیشگی سادهترین مسیر به یک کدبیس نامرتب و غیرقابل نگهداری منجر میشود. اما یک راهحل سریع و موقتی (hack) ساده نیست. یک هک پیچیدگی پنهان را معرفی میکند—قانون دیگری که باید به خاطر بسپارید. یک راهحل واقعاً ساده، که اغلب به تفکر بیشتر و درک عمیقتری از سیستم نیاز دارد، معمولاً تمیزتر و نگهداری آن آسانتر از یک وصله پینه سریع است.
۲. «ساده» اصلاً به چه معناست؟
سادگی امری ذهنی است، اما میتوانیم آن را تعریف کنیم. یک سیستم ساده به طور کلی قطعات متحرک کمتر و اتصالات داخلی کمتری دارد. اجزای آن رابطهای واضح و سرراستی دارند. هنگام مقایسه دو گزینه، از خود بپرسید: کدام یک در صورت عدم تغییر نیازمندیها، به کار و نگهداری مداوم کمتری نیاز خواهد داشت؟ راهحلی که به استقرار، نظارت و نگهداری یک سرویس کاملاً جدید (مانند Redis) نیاز ندارد، ذاتاً سادهتر است.
۳. در مورد مقیاسپذیری چطور؟ آیا نباید برای آینده بسازیم؟
وسواس برای ساختن محصولی با «مقیاس وب» از روز اول، یک گناه کبیره در مهندسی نرمافزار است. این امر منجر به سیستمهای بیش از حد مهندسیشده و انعطافناپذیر میشود که برای حل مشکلاتی ساخته شدهاند که شما هنوز ندارید. شما نمیتوانید به طور دقیق پیشبینی کنید که تنگناها در ترافیک ۱۰۰ برابر فعلی شما در کجا ظاهر میشوند. بسیار مؤثرتر است که سیستمی بسازید که اکنون به خوبی کار میکند، بتواند رشد ۲ تا ۵ برابری را مدیریت کند و آماده انطباق با ظهور مشکلات واقعی باشد. افزودن پیچیدگی به صورت زودهنگام، تغییرات آینده را سختتر میکند، نه آسانتر.
یک تفکر نهایی در مورد طراحی
پیشبینی وضعیت آینده یک سیستم فوقالعاده دشوار است. یک استراتژی عملیتر و مؤثرتر، طراحی بهترین سیستم ممکن برای نیازمندیهایی است که همین الان دارید. با انجام مداوم سادهترین کاری که احتمالاً کار میکند، شما سیستمهایی میسازید که قوی، قابل نگهداری و کاملاً مناسب برای هدف واقعی خود هستند.