بازی تتریس و بدهی فنی
در انجام کارها در تولید نرمافزار، توسعهدهنده ممکن است به دلایلی مانند محدودیت زمان، راهحلی ساده، دمدستی و سریعتر را بهجای راهحل بهتر و اصولیتر انتخاب کند. انتخاب این راهحلهای دمدستی، اصطلاحا منجر به ایجاد بدهی فنی در نرمافزار میشود. مانند بدهیهای مالی برای جلوگیری از ورشکستگی، باید از انباشتِ بدهیهای فنی نیز جلوگیری کرد؛ به عبارت دیگر باید در آیندهای نهچندان دور، مدت زمانی را برای اصلاح این کارها تخصیص داد تا بدهی فنی مربوط به این کارها تسویه شود. هر چه بدهیهای فنی بیشتری روی هم انباشت شود، مدت زمان لازم برای تسویه آنها نیز افزایش مییابد.
در ادامه، داستان Eric Higgins در مورد بدهی فنی و شباهتی که با بازی تتریس دارد را از زبان وی میخوانیم.
مانند اکثر افرادی که تتریس بازی کردهاند، من هم عاشق تتریسام. هنوز اولین باری که بازی کردم را به خاطر دارم. تتریس نه تنها یکی از بهترین بازیهای تاریخ است، بلکه یک مثال خیلی خوب برای بدهی فنی هم هست. من با اثرات بدهی فنی عمیقا آشنایی دارم و در واقع هر روز با آن سر و کار دارم.
همانطور که گفتم، بدهی فنی، شباهت زیادی به بازی تتریس دارد. قصد دارم در این مقاله، کمی در مورد این شباهتها بگویم و سپس یک داستان شخصی و واقعی در رابطه با همین موضوع را تعریف کنم. داستانِ این که من و تیمم چگونه با رفع یک باگ یک میلیون دلاری در کد صدور صورتحساب، بدهی فنی خود را کاهش دادیم.
در ابتدا که پیچیدگی کمتر است، کارها آسانترند.
در شرکتهای نرمافزاری، مدیران پروژه و محصول، با توسعهدهندگان نرمافزار در خصوص اولویتبندی اینکه در قدم بعدی چه کدی باید نوشته و به مشتری تحویل داده شود، تعامل میکنند. تکمیل یک سطر از تتریس، مانند تحویل یک ویژگی جدید به مشتری است. همینطور، تحویل یک ویژگی بزرگ و پیچیده، نیازمند تکمیل چند سطر از تتریس است.
با تسویه یک بدهی فنی کوچک، کار ایجاد ویژگیهای پیچیده هم راحت میشود.
اغلب، نیازمندیهای کسبوکاری (ویژگی جدید، محصول جدید) برای آن که به موقع به مشتری تحویل داده شوند، باعث ایجاد مصالحه در کد میشوند. یا این که تغییرات در استراتژی محصول، موجب ناسازگاری با طراحی پیشین خواهد شد که نیازمند تلاش بیشتر در مهاجرت مشتریان و پشتیبانی از هر دو منطق «قدیمی» و «جدید» است.
مقدار کمِ بدهی فنی، عادی و قابل مدیریت است.
سناریوهای اینچنینی، موجب ایجاد بدهی فنی در کد محصول میشوند. یک سوراخ یا فضای خالی در سطرهای پایینی تتریس، نشاندهنده بدهی فنی است.
همه کدها، بدهی فنی دارند. کاملا هم عادی است. با داشتن چند سوراخ و فضای خالی کوچک، همچنان میتوانید به بازی ادامه دهید.
تعداد زیادی بدهی فنی قدیمی!
اگر بدهیهای فنی زیاد شوند، مانع تحویل ویژگیهای جدید و یا رفع باگها در یک مدت زمان منطقی میشوند.
این مشکل، با اضافه کردن توسعهدهندههای بیشتر به تیم یا حتی با جایگزینی توسعهدهندههای فعلی هم حل نمیشود. به این دلیل به آن بدهی فنی میگویند که به هر حال یک زمانی باید حتما پرداخت شود و هیچ راهی برای طفره رفتن از پرداخت ندارید.
با پرداخت بدهیهای فنی، میتوانید همچنان در بازی و رقابت باقی بمانید.
پایان بازی
مشابه چرخاندن کسبوکار، تتریس هم هر چه بیشتر بازی کنی، سختتر میشود. قطعات سریعتر پایین میآیند و جاگذاری صحیحشان دشوارتر میشود.
مشابه چرخاندن کسبوکار، هیچ وقت نمیتوانید برنده تتریس باشید. هیچ خط پایانی وجود ندارد. صرفا میتوانید کنترل کنید که چقدر دیرتر ببازید.
مشابه چرخاندن کسبوکار، اگر اجازه دهید حفرههای زیادی در ساختمان تتریس ایجاد شود، به زودی خواهید باخت.
و اما…
باگ یکمیلیون دلاری
من در بخش IT یک شرکت مالی کار میکنم. چند وقت پیش، برای پشتیبانی از طرحهای جدید قیمتگذاری، درگاه پرداخت جدید و یک بهبود در جریان کار (workflow) صورتحساب، به تیم ما وظیفه بهروزرسانی منطق ساخت صورتحساب در کد محصول داده شد. برخی از جزییات هنوز در مرحله تصمیمگیری از سوی تیم محصول بود و از زمان خالیای که داشتیم، برای بررسی عمیق کد موجود استفاده کردیم. این کار، درک ما را از کد بالا برد و به این ترتیب، میتوانستیم تخمین دقیقتری از توانایی تیم برای تکمیل تغییرات پیشرو به دست آوریم.
هدف اصلی کدی که برررسیاش میکردیم، بازبینی حساب همه مشتریان، محاسبه صورتحساب و ارسال آن به API پرداخت بود. کد خوانا بود و مشخص بود با اهمیت و دقت نوشته شده است و به نسبتی که انعطافپذیر بود، شلوغ و کثیف نبود. به یک تابع یکپارچه برخورد کردیم که هیچ تستی برایش نوشته نشده بود و لاگها و مستندات خیلی کمی هم داشت. در این تابع، یکسری تصادفیسازیهای غیرقابل توجیه به چشم میخورد که بیش از پنج سال پیش توسط یکی از co-founderها نوشته شده بود و تنها تغییراتی که از آن زمان داده شده بود، توسط یکی از کارمندان که دیگر در شرکت نبود، داده شده بود.
آیا این مساله واقعا مشکلی به حساب میآمد؟ صورتحسابها صادر میشدند و شرکت هم پول در میآورد. هیچ نشانهای از مشکل وجود نداشت. همه اینها میتوانست ما را از انجام بازآرایی منصرف کند، اما ما میدانستیم که تغییرات بزرگی در راه است و کد فعلی با نیازمندیهای ما نمیتواند scale شود و اگر این تکهکد سادهسازی شود، با سرعت بیشتری میتوانیم پیش برویم.
کد را در یک اسپرینت بازآرایی کردیم و مقدار خوبی لاگهای مورد نیاز را به آن اضافه کردیم. تازه آن زمان بود که فهمیدیم چه چیزی را واقعا حل کردهایم. یک نفر از تیم مالی سراغ ما آمد و پرسید که تعداد صورتحسابهای خروجی به شکل غیرمنتظرهای افزایش داشته؟ کد قدیمی به شکل نامحسوسی خطا میداد وصورتحساب مشتری به درستی محاسبه نمیشد. آیا مشکل از همان تصادفیسازیهای غیرقابل توجیه بود؟ بله! این مشکل، هر الگویی که میتوانست به ما در مورد صورتحسابهای گمشده هشدار دهد را از دید ما مخفی کرده بود.
زمانی که تخمین زدیم، دیدیم که این مشکل در صورتحسابها، در مجموع حدود یک میلیون دلار در سال به ما خسارت وارد میکرده.
کاهش بدهی، همیشه به معنی تسویه نیست
درست است که این داستان واقعی بود، اما کاهش بدهی فنی، همیشه هم چنین نتایج دراماتیکی ندارد. ما شانس آوردیم.
در مقدار بدهی فنی، تعادل را حفظ کنید
کاش میتوانستم پیشنهاد حکیمانهای بدهم که چه زمانی باید بدهی فنی را کم کرد؟ متاسفانه، پاسخ این است: پیچیدهاست و باید همیشه تعادل را حفظ کنید. شما میتوانید تمیزترین و تستشدهترین کد در کل جهان را داشته باشید اما هیچ مشتریای نداشته باشید که پول بدهد. برعکس، شرکت شما ممکن است کدهای واقعا کثیفی داشته باشد که مشتریان را راضی میکند و پول خوبی هم به دست میآورد.
در هر دو صورت، صاحبان محصول و توسعهدهندگان باید درک مشترکی از اینکه بدهی فنی چیست، داشته باشند. همچنین باید بدانند که بدهی فنی همواره غیرقابل اجتناب است و در نرمافزار هم، مشابه تتریس هیچگاه نمیتوانید برنده باشید.
.
.
.
آدرس کانال تلگرام: JavaCupIR@
آدرس اکانت توییتر: JavaCupIR@
آدرس صفحه اینستاگرام: javacup.ir
آدرس گروه لینکدین: Iranian Java Developers