পাঠ ৫১ · ৫৮-এর মধ্যে · মডিউল ১১
Home / Courses / Software Engineering Principles & Git / টেকনিক্যাল ডেট

টেকনিক্যাল ডেট

Technical debt
৭ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • টেকনিক্যাল ডেট রূপকটি ঠিক কী বোঝায় এবং কেন এটি একটি দরকারি মানসিক মডেল
  • "সুদ" জমা হওয়ার কম্পাউন্ড-গ্রোথ ধারণা, একটি স্পষ্ট সূত্র সহ
  • ইচ্ছাকৃত বনাম অগোছালো ডেট — কেন প্রথমটি প্রায়ই যুক্তিসঙ্গত, দ্বিতীয়টি প্রকৃত ঝুঁকি
  • একটি real project_cost_over_time ফাংশন দিয়ে সময়ের সাথে খরচ প্রজেক্ট করা ও হাতে-যাচাই করা

১ · টেকনিক্যাল ডেট রূপক কী

টেকনিক্যাল ডেটTechnical Debtআর্থিক ঋণ থেকে ধার করা একটি রূপক — একটি সহজ/দ্রুত সমাধান বেছে নেওয়ার সঞ্চিত খরচ, যা সময়ের সাথে "সুদ" আকারে বাড়ে। একটি ইচ্ছাকৃতভাবে বেছে নেওয়া রূপক — আর্থিক ঋণের সাথে সাদৃশ্য একেবারে নির্ভুল নয়, কিন্তু অত্যন্ত কার্যকর: ঠিক যেমন কেউ এখন দ্রুত টাকা ধার নিয়ে পরে সুদসহ ফেরত দেয়, একজন ডেভেলপার এখন একটি সহজ/দ্রুত সমাধান বেছে নিতে পারেন (একটি আদর্শ, বেশি-effort সমাধানের বদলে) — কিন্তু এই "ধার" সময়ের সাথে সাথে একটি সঞ্চিত খরচ তৈরি করে।

২ · "সুদ" জমা হয় কীভাবে

M11/L49-এর একটি কোড স্মেল যত বেশি দিন অসমাধিত থাকে, তা ঠিক করার খরচ সাধারণত বাড়তে থাকে — কারণ আশপাশের কোড ক্রমশ সেই শর্টকাটের উপস্থিতি ধরে নিয়ে লেখা হতে থাকে, ফলে পরে সঠিকভাবে ঠিক করা আরও কঠিন হয়ে যায়। একই সাথে, এই এলাকার চলমান ডেভেলপমেন্টও ধীর হতে থাকে (M1/L03-এর maintainability অ্যাট্রিবিউট ক্রমশ অবনতির দিকে যায়)। এই "সুদ" মডেল করার সবচেয়ে স্বাভাবিক গাণিতিক উপায় কম্পাউন্ড গ্রোথ:

$$cost = initial\_cost \times (1 + rate)^{sprints}$$

এখানে rate মানে প্রতি স্প্রিন্টে ফিক্স-করার-খরচ কতটা বাড়ে (একটি শতাংশ), এবং sprints মানে কতগুলো স্প্রিন্ট ধরে ডেটটি অসমাধিত রাখা হয়েছে — ঠিক যেমন আর্থিক কম্পাউন্ড ইন্টারেস্টে সময় বাড়ার সাথে সাথে মোট দেনা এক্সপোনেনশিয়ালি বাড়ে।

ফিক্স-করার খরচ (ঘণ্টা) এখনই: 20 ৩ স্প্রিন্ট: ~30 ৬ স্প্রিন্ট: ~46 ১২ স্প্রিন্ট: ~107
একই ফিক্স যত দেরিতে করা হয়, বার তত লম্বা হতে থাকে — কম্পাউন্ড গ্রোথের কারণে বৃদ্ধি রৈখিক নয়, এক্সপোনেনশিয়াল।

৩ · ইচ্ছাকৃত বনাম অগোছালো ডেট

সৎ, প্রায়ই মিস হওয়া একটি সূক্ষ্মতা

টেকনিক্যাল ডেট সবসময় একটি ভুল নয়। কখনো কখনো ইচ্ছাকৃতভাবে ডেট নেওয়া একটি সম্পূর্ণ যুক্তিসঙ্গত সিদ্ধান্ত — যেমন একটি জরুরি ডেডলাইন পূরণ করতে একটি দ্রুত, অসম্পূর্ণ সমাধান শিপ করা, সাথে পরে তা "শোধ" করার একটি স্পষ্ট পরিকল্পনা থাকা। আসল সমস্যা হলো অগোছালো বা অট্র্যাকড ডেট — এমন ডেট যা কেউ সচেতনভাবে জানে না বা ট্র্যাক করে না, এবং তাই কখনো "শোধ" হয় না। M13/L57-এর রিস্ক ম্যানেজমেন্টের সাথে সরাসরি সংযোগ: টেকনিক্যাল ডেটকে অন্য যেকোনো প্রজেক্ট রিস্কের মতোই ট্র্যাক ও প্রায়োরিটাইজ করা উচিত, উপেক্ষা নয়।

৪ · সময়ের সাথে খরচ প্রজেক্ট করা

নিচের কোড সেলে একটি TechnicalDebtItem ক্লাস আছে, এবং একটি project_cost_over_time ফাংশন উপরের কম্পাউন্ড গ্রোথ সূত্র দিয়ে ফিক্স-করার খরচ গণনা করে। তাৎক্ষণিক ফিক্সের খরচের সাথে ৩, ৬, ১২ স্প্রিন্ট অসমাধিত রাখলে কত খরচ হবে তা তুলনা করে দেখানো হয়েছে, এবং একটি ডেটা পয়েন্ট হাতে-হিসাব করে কোডের ফলাফলের সাথে মিলিয়ে যাচাই করা হয়েছে।

Python
class TechnicalDebtItem:
    def __init__(self, description, estimated_fix_cost_hours, interest_rate):
        self.description = description
        self.estimated_fix_cost_hours = estimated_fix_cost_hours
        self.interest_rate = interest_rate  # প্রতি স্প্রিন্টে বৃদ্ধির হার (যেমন 0.15 = ১৫%)


def project_cost_over_time(debt_item, sprints_unaddressed):
    # cost = initial_cost * (1 + rate) ^ sprints -- কম্পাউন্ড গ্রোথ সূত্র
    return debt_item.estimated_fix_cost_hours * ((1 + debt_item.interest_rate) ** sprints_unaddressed)


debt = TechnicalDebtItem(
    description="পেমেন্ট মডিউলে হার্ডকোডেড কনফিগ, কোনো টেস্ট কভারেজ নেই",
    estimated_fix_cost_hours=20,
    interest_rate=0.15,
)

print(f"টেকনিক্যাল ডেট: {debt.description}")
print(f"তাৎক্ষণিকভাবে ঠিক করলে খরচ: {project_cost_over_time(debt, 0):.1f} ঘণ্টা\n")

for sprints in [3, 6, 12]:
    cost = project_cost_over_time(debt, sprints)
    print(f"{sprints} স্প্রিন্ট অবহেলা করলে খরচ: {cost:.1f} ঘণ্টা")

# --- হাতে-হিসাব করে যাচাই: ৩ স্প্রিন্ট পরে ---
hand_calc_3 = 20 * (1.15 ** 3)
code_calc_3 = project_cost_over_time(debt, 3)
print(f"\nহাতে-হিসাব: 20 * (1.15)^3 = 20 * {1.15**3:.4f} = {hand_calc_3:.2f}")
print(f"কোডের হিসাব: {code_calc_3:.2f}")
print(f"মিলেছে: {abs(hand_calc_3 - code_calc_3) < 1e-9}")

    
লক্ষ্য করুন — ০ থেকে ৩ স্প্রিন্টে খরচ বাড়ে মাত্র ~১০.৪ ঘণ্টা (20 → 30.4), কিন্তু ৬ থেকে ১২ স্প্রিন্টে বাড়ে ~৬১ ঘণ্টা (46.3 → 107.0) — সমান "৬ স্প্রিন্ট বেশি অপেক্ষা" করলেও বৃদ্ধির পরিমাণ অনেক বড়। এটাই কম্পাউন্ড গ্রোথের বৈশিষ্ট্য: প্রতিটি নতুন স্প্রিন্টের বৃদ্ধি আগের, ইতিমধ্যে-বেড়ে-যাওয়া খরচের উপর প্রয়োগ হয় — ঠিক আর্থিক ঋণে সুদের-উপর-সুদের মতোই।
মূল কথা · Key takeaway

টেকনিক্যাল ডেট একটি রূপক, কিন্তু এর গাণিতিক আচরণ (কম্পাউন্ড গ্রোথ) বাস্তব — যত দেরি, তত বেশি ব্যয়বহুল, এবং রৈখিকভাবে নয়, এক্সপোনেনশিয়ালিভাবে বেশি। এটাই মূল যুক্তি কেন M11/L49-এর স্মেল ও M11/L50-এর রিফ্যাক্টরিং তাড়াতাড়ি করা উচিত — অপেক্ষা করা মানেই ভবিষ্যতে আরও বড় খরচ, ইচ্ছাকৃতভাবে ট্র্যাক করা না হলে।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ যদি interest_rate = 0 হতো, project_cost_over_time-এর ফলাফল কেমন হতো, এবং এটি বাস্তবে কোন ধরনের টেকনিক্যাল ডেটের প্রতিনিধিত্ব করে?

(1 + 0) ** sprints = 1 সবসময়, তাই খরচ সব সময় estimated_fix_cost_hours-এর সমান থাকবে, স্প্রিন্ট যতই বাড়ুক — অর্থাৎ কোনো "সুদ" জমে না। এটি এমন এক ধরনের টেকনিক্যাল ডেটের প্রতিনিধিত্ব করে যা বিচ্ছিন্ন, স্থিতিশীল (কোনো আশপাশের কোড এর উপর নির্ভর করে গড়ে ওঠেনি) — বিরল, কিন্তু তাত্ত্বিকভাবে সম্ভব একটি কেস, যেখানে অপেক্ষা করাও তেমন ব্যয়বহুল নয়।

প্র ০২ একটি টিম কেন কখনো কখনো ইচ্ছাকৃতভাবে টেকনিক্যাল ডেট নেওয়ার সিদ্ধান্ত নেয়, যদি তারা জানে এটি সময়ের সাথে ব্যয়বহুল হবে?

কারণ কখনো কখনো এখনই একটি সম্পূর্ণ, নিখুঁত সমাধান তৈরির খরচ (সময়, সুযোগ) সেই ভবিষ্যতের "সুদ"-এর চেয়ে বেশি গুরুত্বপূর্ণ — যেমন একটি বাজার-সুযোগ দ্রুত ধরার জন্য একটি প্রোডাক্ট শিপ করা। মূল কথা হলো এটি একটি সচেতন, পরিমাপ করা ট্রেড-অফ হওয়া উচিত (M13/L56-এর এস্টিমেশনের সাথে সরাসরি সম্পর্কিত), যেখানে টিম জানে ঠিক কী ঋণ নেওয়া হচ্ছে এবং কবে তা শোধ করার পরিকল্পনা আছে — অন্ধভাবে শর্টকাট নেওয়া নয়।

প্র ০৩ "অগোছালো/অট্র্যাকড" টেকনিক্যাল ডেট কেন "ইচ্ছাকৃত" ডেটের চেয়ে বেশি ঝুঁকিপূর্ণ, যদিও গাণিতিকভাবে দুটোর "সুদ"-এর সূত্র একই?

কারণ ঝুঁকি শুধু গাণিতিক বৃদ্ধিতে নয়, বরং দৃশ্যমানতায় — একটি ইচ্ছাকৃত, ট্র্যাক-করা ডেট টিমের পরিচিত, তাই কেউ সিদ্ধান্ত নিতে পারে কবে "শোধ" করবে (M13/L57-এর রিস্ক-প্রায়োরিটাইজেশনের মতো)। একটি অগোছালো ডেট কারো জানাই নেই যে এটি বিদ্যমান — তাই এটি নিঃশব্দে বাড়তে থাকে, কোনো সিদ্ধান্ত ছাড়াই, যতক্ষণ না হঠাৎ একটি বড় সমস্যা (একটি বাগ, একটি ব্লকড ফিচার) আকারে প্রকাশ পায় — তখন প্রায়ই অনেক দেরি হয়ে যায়।

অনুশীলন

  1. পরীক্ষা করুন: উপরের কোডে interest_rate-কে 0.30-এ পাল্টে রান করুন — ১২ স্প্রিন্ট পরে খরচ কত হয়, এবং 0.15-এর তুলনায় পার্থক্য কতটা বড়?

    interest_rate = 0.30-এ ১২ স্প্রিন্ট পরে খরচ হবে 20 * (1.30)**12 ≈ 20 * 23.30 ≈ 465.9 ঘণ্টা — 0.15-এর ~১০৭ ঘণ্টার তুলনায় প্রায় সাড়ে চার গুণ বেশি। এটি এক্সপোনেনশিয়াল গ্রোথের একটি শক্তিশালী বাস্তব ফল দেখায় — সুদের হার দ্বিগুণ করলে চূড়ান্ত খরচ শুধু দ্বিগুণ হয় না, বরং অনেক বেশি বাড়ে, কারণ পার্থক্যটি প্রতিটি স্প্রিন্টে যৌগিক (কম্পাউন্ড) হয়।

  2. চিন্তা করুন: একটি স্মেল যার interest_rate খুবই কম (যেমন 0.02) — এটি কি এখনই ঠিক করার অগ্রাধিকার পাওয়া উচিত?

    সবসময় না — একটি কম interest_rate মানে এই ডেটটি খুব ধীরে "বাড়ে", অর্থাৎ অপেক্ষা করার সত্যিকারের খরচ কম। M13/L57-এর রিস্ক ম্যানেজমেন্টের ভাষায়, এটি টিমকে সীমিত সময় অন্য, উচ্চ-সুদের (দ্রুত বাড়তে থাকা) ডেট আইটেমে ফোকাস করার সুযোগ দেয় — সব ডেট সমান জরুরি নয়, ঠিক যেমন সব আর্থিক ঋণ একই সুদের হারে হয় না।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

পূর্ববর্তী পাঠ
রিফ্যাক্টরিং টেকনিক