14 ساعت قبل

بدهی فنی در توسعه نرم‌افزار

Technical Debt چیست و چرا برای برنامه‌نویسان مهم است؟

 
یکی از سؤال‌هایی که هنگام کار روی پروژه‌های نرم‌افزاری ممکن است برای برنامه‌نویسان پیش بیاید این است:
 

چرا بعضی پروژه‌ها در ابتدا خیلی سریع پیشرفت می‌کنند، اما بعد از مدتی کوچک‌ترین تغییر در آن‌ها دردسرساز می‌شود؟

 
فرض کنید یک تیم در حال ساخت یک فروشگاه اینترنتی است. زمان تحویل پروژه نزدیک است و تیم باید هرچه سریع‌تر قابلیت پرداخت آنلاین را اضافه کند. برنامه‌نویس برای اینکه پروژه زودتر آماده شود، بخشی از کد را ساده و موقتی پیاده‌سازی می‌کند و با خودش می‌گوید:
 
«بعداً این قسمت را تمیز و اصولی می‌کنیم.»
 
پروژه تحویل داده می‌شود و همه چیز در ابتدا خوب به نظر می‌رسد. چند ماه بعد، تیم تصمیم می‌گیرد سیستم تخفیف، پرداخت اقساطی و کیف پول را هم اضافه کند. ناگهان همان کدی که قرار بود «بعداً درست شود»، تبدیل به یکی از دردسرهای اصلی پروژه می‌شود.
 
این اتفاق نمونه‌ای از چیزی است که در دنیای برنامه‌نویسی به آن Technical Debt یا بدهی فنی می‌گویند.
 

اما بدهی فنی دقیقاً چیست و آیا همیشه چیز بدی است؟

Technical Debt چیست؟

 
Technical Debt یا بدهی فنی به مشکلات، تصمیم‌های موقتی یا کدهای غیراستانداردی گفته می‌شود که ممکن است در کوتاه‌مدت باعث سریع‌تر شدن توسعه نرم‌افزار شوند، اما در آینده هزینه بیشتری برای تغییر، توسعه، تست و نگهداری پروژه ایجاد می‌کنند.
 
به زبان ساده:
 
بدهی فنی یعنی امروز کار را سریع‌تر انجام دهیم و هزینه آن را در آینده پرداخت کنیم.
 
این هزینه ممکن است به شکل زمان بیشتر برای توسعه، باگ‌های بیشتر، سخت‌تر شدن تغییرات یا حتی کاهش کیفیت نرم‌افزار ظاهر شود.
 
نکته مهم این است که بدهی فنی لزوماً به معنی «کد بد» نیست. گاهی یک تصمیم کاملاً آگاهانه و منطقی برای رسیدن سریع‌تر به یک هدف گرفته می‌شود؛ مشکل زمانی شروع می‌شود که این بدهی برای مدت طولانی باقی بماند.
 

چرا به آن «بدهی» می‌گویند؟

 
تصور کنید برای انجام یک کار ضروری، امروز ۱۰ میلیون تومان قرض می‌گیرید. این کار ممکن است در کوتاه‌مدت مشکل شما را حل کند، اما اگر بدهی را پرداخت نکنید، در آینده باید اصل پول و هزینه بیشتری را پس بدهید.
 
در برنامه‌نویسی هم تقریباً همین اتفاق می‌افتد.
 
مثلاً امروز نوشتن یک کد سریع و غیراستاندارد ممکن است فقط ۲ ساعت زمان ببرد؛ اما اگر همان کد بدون اصلاح وارد بخش‌های مختلف پروژه شود، چند ماه بعد تغییر دادن آن شاید چند روز زمان نیاز داشته باشد.
 
بنابراین:
 
بدهی فنی = صرفه‌جویی کوتاه‌مدت + هزینه احتمالی در آینده
 
یک مثال ساده از بدهی فنی
 
فرض کنید در یک اپلیکیشن سفارش غذا، قرار است اطلاعات رستوران‌ها از پایگاه داده دریافت شود.
 
برنامه‌نویس برای سرعت بیشتر، همه کد مربوط به دریافت اطلاعات، پردازش داده‌ها و نمایش آن‌ها را داخل یک متد بسیار بزرگ می‌نویسد.
 
در ابتدا برنامه به‌خوبی کار می‌کند.
 
اما چند ماه بعد امکانات جدیدی اضافه می‌شود:
 
جستجوی رستوران، فیلتر قیمت، امتیاز کاربران، نمایش رستوران‌های نزدیک و پیشنهادهای هوشمند.
 
حالا هر تغییری نیازمند دستکاری همان متد بزرگ است.
 

نتیجه چیست؟

 
کدی که در ابتدا باعث صرفه‌جویی در زمان شده بود، حالا توسعه پروژه را سخت‌تر کرده است.
 
این همان بدهی فنی است.
 

یک مثال جذاب‌تر؛ پروژه هوش مصنوعی

 
فرض کنید تیمی در حال ساخت یک سیستم هوش مصنوعی برای پاسخ‌گویی به سؤالات کاربران است.
 
برای اینکه نسخه اولیه سریع‌تر آماده شود، تیم تصمیم می‌گیرد فعلاً اطلاعات کاربران را به شکل ساده‌ای ذخیره کند و ساختار مناسبی برای مدیریت داده‌ها طراحی نکند.
 
نسخه اولیه خیلی سریع آماده می‌شود و حتی کاربران هم از آن استفاده می‌کنند.
 
اما بعد از مدتی تعداد کاربران افزایش پیدا می‌کند و امکاناتی مثل:
 
تاریخچه گفتگوها، شخصی‌سازی پاسخ‌ها، سطح دسترسی کاربران و گزارش‌گیری
 
به سیستم اضافه می‌شود.
 
حالا ساختار اولیه دیگر پاسخگوی نیازهای جدید نیست و تیم مجبور می‌شود بخش بزرگی از سیستم را بازطراحی کند.
 
پس یک تصمیم کوچک برای «سریع‌تر جلو رفتن» می‌تواند در آینده هزینه زیادی ایجاد کند.
 

بدهی فنی چگونه ایجاد می‌شود؟

 
بدهی فنی دلایل مختلفی دارد و همیشه هم به دلیل بی‌دقتی برنامه‌نویس ایجاد نمی‌شود.
 
فشار زمانی
 
گاهی تیم باید پروژه را خیلی سریع تحویل دهد.
 
در چنین شرایطی ممکن است برنامه‌نویس بخشی از کد را به‌صورت موقت پیاده‌سازی کند تا نسخه اولیه سریع‌تر آماده شود.
 
تغییر مداوم نیازمندی‌ها
 
گاهی نیازهای پروژه دائماً تغییر می‌کنند.
 
ممکن است معماری پروژه بر اساس نیازهای اولیه ساخته شده باشد، اما چند ماه بعد مشخص شود که نرم‌افزار به امکانات بسیار بیشتری نیاز دارد.
 
تجربه کم تیم
 
برنامه‌نویسان تازه‌کار ممکن است راه‌حل‌هایی انتخاب کنند که در پروژه‌های کوچک مناسب به نظر می‌رسند، اما در پروژه‌های بزرگ مشکلات زیادی ایجاد می‌کنند.
 
کپی کردن کد
 
یکی دیگر از دلایل رایج، کپی کردن بخش‌های مختلف کد به جای طراحی یک ساختار قابل استفاده مجدد است.
 
کپی کردن کد ممکن است در کوتاه‌مدت سریع باشد، اما زمانی که نیاز به تغییر آن بخش داشته باشید، مجبور می‌شوید چندین قسمت مختلف را اصلاح کنید.
 
مستندسازی ضعیف
 
گاهی کد درست کار می‌کند، اما توضیحی درباره منطق آن وجود ندارد.
 
چند ماه بعد، حتی خود برنامه‌نویس ممکن است فراموش کند چرا آن بخش از کد به آن شکل نوشته شده است.
 
تست نکردن کد
 
وقتی برای صرفه‌جویی در زمان تست‌های مناسب نوشته نشوند، تغییرات بعدی پروژه می‌توانند خطرناک‌تر شوند؛ چون تیم دقیقاً نمی‌داند کدام قسمت‌ها ممکن است خراب شوند.
 

آیا Technical Debt همیشه بد است؟

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

تفاوت بدهی فنی با کد بد چیست؟

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

بدهی فنی چه مشکلاتی ایجاد می‌کند؟

 
هرچه بدهی فنی بیشتر شود، نگهداری پروژه دشوارتر خواهد شد.
 
یکی از اولین نشانه‌ها این است که تغییرات ساده زمان زیادی می‌گیرند.
 
مثلاً اضافه کردن یک دکمه یا تغییر یک قانون ساده کسب‌وکار، به‌جای چند ساعت، چند روز زمان می‌برد.
 
از طرف دیگر، احتمال ایجاد باگ هم افزایش پیدا می‌کند؛ چون تغییر یک بخش ممکن است بخش‌های دیگری را که به آن وابسته هستند تحت تأثیر قرار دهد.
 
همچنین برنامه‌نویسان جدید هنگام ورود به پروژه باید زمان زیادی صرف فهمیدن کدهای پیچیده و قدیمی کنند.
 
در پروژه‌های بزرگ، این مشکل می‌تواند باعث کاهش سرعت کل تیم شود.
 

Technical Debt یک مفهوم فقط مربوط به برنامه‌نویس نیست

 
بدهی فنی فقط مشکل برنامه‌نویس نیست؛ بلکه می‌تواند روی کل تیم و حتی کسب‌وکار تأثیر بگذارد.
 
وقتی توسعه یک قابلیت جدید سخت شود، شرکت دیرتر محصول جدید را منتشر می‌کند.
 
وقتی باگ‌ها بیشتر شوند، پشتیبانی و رفع خطا هزینه بیشتری خواهد داشت.
 
و وقتی تغییر دادن سیستم دشوار شود، ممکن است شرکت نتواند به‌سرعت به نیازهای جدید بازار پاسخ دهد.
 
بنابراین بدهی فنی فقط یک مسئله مربوط به کدنویسی نیست؛ بلکه می‌تواند مستقیماً روی زمان، هزینه و رشد یک محصول نرم‌افزاری تأثیر بگذارد.
 

چگونه بدهی فنی را کاهش دهیم؟

 
کاهش بدهی فنی معمولاً نیازمند انجام کارهای بسیار پیچیده نیست.
 
اولین قدم این است که تیم مشکلات موجود را شناسایی کند.
 
برای مثال:
 
«این بخش کد بسیار پیچیده است.»
 
«این قسمت تست ندارد.»
 
«این ماژول چند مسئولیت مختلف دارد.»
 
«این کد چند بار در پروژه کپی شده است.»
 
بعد از شناسایی، بهتر است مشکلات مهم‌تر در اولویت قرار بگیرند.
 
یکی از روش‌های رایج برای این کار Refactoring یا بازآرایی کد است.
 
در Refactoring، رفتار اصلی برنامه تغییر نمی‌کند، اما ساختار داخلی کد بهتر و قابل نگهداری‌تر می‌شود.
 
مثلاً می‌توان یک متد بسیار بزرگ را به چند متد کوچک‌تر تقسیم کرد یا کدهای تکراری را به یک بخش مشترک منتقل کرد.
 

یک نمونه کوتاه در برنامه‌نویسی

 
برای مثال، ممکن است یک برنامه‌نویس ابتدا کدی شبیه این بنویسد:
 
if (user.IsAdmin)
{
    // نمایش پنل مدیریت
}
 
این کد به‌تنهایی مشکلی ندارد.
 
اما فرض کنید همین شرط در ۲۰ نقطه مختلف پروژه تکرار شود.
 
بعداً قانون دسترسی تغییر می‌کند و باید همه این قسمت‌ها اصلاح شوند.
 
یک طراحی بهتر می‌تواند منطق تعیین دسترسی را در یک بخش مشخص متمرکز کند تا تغییر آن ساده‌تر شود.
 
اینجاست که اهمیت طراحی مناسب، اصول برنامه‌نویسی و کاهش بدهی فنی مشخص می‌شود.
 

آیا Refactoring همان پرداخت بدهی فنی است؟

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

چه زمانی باید Technical Debt را جدی بگیریم؟

 
اگر موارد زیر در پروژه شما زیاد دیده می‌شوند، احتمالاً بدهی فنی پروژه در حال افزایش است:
 
تغییرات ساده به زمان زیادی نیاز دارند.
 
برنامه‌نویسان از دست زدن به بعضی قسمت‌های کد می‌ترسند.
 
یک تغییر کوچک باعث ایجاد چند باگ جدید می‌شود.
 
کدهای مشابه در قسمت‌های مختلف پروژه تکرار شده‌اند.
 
تست کردن پروژه دشوار است.
 
برنامه‌نویسان جدید برای درک پروژه به زمان زیادی نیاز دارند.
 
تیم دائماً می‌گوید: «فعلاً درستش نکن، بعداً سراغش می‌رویم.»
 
مورد آخر شاید یکی از خطرناک‌ترین نشانه‌ها باشد.
 
بدهی فنی در پروژه‌های واقعی کاملاً طبیعی است
 
تقریباً هیچ پروژه نرم‌افزاری بزرگی وجود ندارد که در طول عمر خود هیچ بدهی فنی ایجاد نکرده باشد.
 
نیازهای کاربران تغییر می‌کنند، فناوری‌ها به‌روزرسانی می‌شوند، اعضای تیم تغییر می‌کنند و کسب‌وکار رشد می‌کند.
 
بنابراین هدف این نیست که Technical Debt را به صفر برسانیم.
 
هدف این است که آن را بشناسیم، کنترل کنیم و اجازه ندهیم به یک مشکل بزرگ تبدیل شود.
 
بهتر است تیم بداند:
 
چه بدهی‌ای داریم؟
 
چرا ایجاد شده است؟
 
چقدر مهم است؟
 
و چه زمانی باید آن را پرداخت کنیم؟
 

جمع‌بندی

 
Technical Debt یا بدهی فنی به هزینه‌ای گفته می‌شود که یک تیم نرم‌افزاری به دلیل تصمیم‌های فنی سریع، موقت یا غیراصولی ممکن است در آینده مجبور به پرداخت آن شود.
 
بدهی فنی همیشه نشانه یک پروژه بد نیست. گاهی ایجاد مقدار مشخصی از آن برای انتشار سریع‌تر یک محصول کاملاً منطقی است.
 
اما اگر بدهی‌های فنی نادیده گرفته شوند، به مرور زمان توسعه پروژه سخت‌تر، رفع باگ‌ها پرهزینه‌تر و تغییر قابلیت‌های جدید زمان‌برتر می‌شود.
 
به همین دلیل یک برنامه‌نویس حرفه‌ای فقط به این فکر نمی‌کند که:
 
«چطور این قابلیت را امروز پیاده‌سازی کنم؟»
 
بلکه باید به این سؤال هم توجه داشته باشد:
 
«آیا این تصمیم، کار فردای تیم را سخت‌تر می‌کند؟»
 
درک مفهوم Technical Debt به برنامه‌نویسان کمک می‌کند علاوه بر نوشتن کدی که امروز کار می‌کند، به کیفیت، نگهداری و آینده پروژه نیز فکر کنند.
 
فرایانه؛ جایی که مفاهیم پیچیده برنامه‌نویسی را به زبان ساده، کاربردی و قابل فهم آموزش می‌دهیم. 💚
بدهی فنی در توسعه نرم‌افزار