সরাসরি পর্বে যান
পর্ব ০২ · ৭০-এর মধ্যে · মডিউল ১

Software crisis আর software engineering-এর ইতিহাস — ১৯৬৮-র NATO সম্মেলন থেকে আজ

The Software Crisis and the History of Software Engineering — from the 1968 NATO Conference to Today

Taught in Bangla, this lesson traces the software crisis of the 1960s and the 1968 NATO conference, Dijkstra's goto letter and structured programming, Brooks's law, No Silver Bullet and essential versus accidental complexity, then dissects Therac-25, Ariane 5, Mars Climate Orbiter and Knight Capital. Runnable JS models recreate an integer-overflow and a unit-mismatch bug, and the page explains how to read CHAOS-style statistics carefully.

এই পর্বে যা শিখবেন

  • “Software crisis” কী ছিল, আর ১৯৬৮-র NATO সম্মেলন কেন একটি মোড়
  • Dijkstra-র goto-বিতর্ক আর structured programming-এর মূল ধারণা
  • Brooks’s law, second-system effect, conceptual integrity আর essential বনাম accidental complexity
  • চারটি নথিভুক্ত ব্যর্থতার কারিগরি কারণ — নিজের হাতে কোড চালিয়ে দুটি bug-এর ধরন পুনরায় তৈরি করা
  • Structured programming থেকে AI পর্যন্ত বিবর্তন, আর পরিসংখ্যান (যেমন CHAOS report) সাবধানে পড়ার নিয়ম

১ · শুরুর দিন — যখন প্রোগ্রাম লেখা ছিল এক ধরনের কারিগরি

পর্ব ১-এ (Software engineering কী) দেখেছেন, কোড লেখা আর টেকসই software বানানো এক জিনিস নয়। এই পর্বে প্রশ্নটি ইতিহাসের: মানুষ কবে, কোন ব্যথা থেকে এই পার্থক্যটি বুঝল? উত্তর খুঁজতে একটু পেছনে যেতে হবে।

১৯৫০-এর দশকে কম্পিউটার ছিল ঘরভর্তি যন্ত্র, সংখ্যায় খুব কম, আর দামে আকাশছোঁয়া। প্রোগ্রাম লিখতেন অল্প কয়েকজন — প্রায়ই গণিতবিদ বা বিজ্ঞানী, যিনি নিজের সমস্যাটি নিজেই সমাধান করছেন। প্রোগ্রাম ছোট, ব্যবহারকারী একজনই, আর ভুল হলে যিনি লিখেছেন তিনিই ঠিক করে নেন। ১৯৫৭ সালে FORTRAN আর ১৯৫৯ সালে COBOL-এর মতো high-level ভাষা আসার পর কোড লেখা সহজ হলো, কিন্তু “কীভাবে বড় দলে বড় প্রোগ্রাম বানাতে হয়” — এর কোনো লিখিত নিয়ম তখনো ছিল না।

গ্রামের একজন দক্ষ রাজমিস্ত্রির কথা ভাবুন। একতলা টিনের ঘর তিনি নকশা ছাড়াই, নিজের অভিজ্ঞতায় চমৎকার বানাতে পারেন। কিন্তু তাঁকেই যদি বিশতলা ভবন বানাতে বলা হয় — দুশো শ্রমিক, ভূমিকম্পের হিসাব, পানি-বিদ্যুতের লাইন — তখন শুধু হাতের দক্ষতায় চলে না। নকশা, হিসাব, পরিদর্শন আর দায়িত্ব ভাগ লাগে। ১৯৬০-এর দশকে software ঠিক এই একতলা থেকে বিশতলায় লাফ দিয়েছিল।

১৯৬০-এর দশকে কম্পিউটার ব্যাংক, বিমান সংস্থা, সামরিক বাহিনী আর মহাকাশ গবেষণায় ঢুকে পড়ল। প্রোগ্রাম হলো লক্ষ লাইনের, লিখতে লাগল শত শত মানুষ, আর ব্যবহার করবেন এমন লোক যাঁরা কোড কখনো দেখবেন না। সবচেয়ে আলোচিত উদাহরণ IBM-এর OS/360 — System/360 কম্পিউটার পরিবারের অপারেটিং সিস্টেম। এর উন্নয়ন দেরিতে চলেছিল, খরচ বেড়েছিল, আর প্রথম দিকের সংস্করণে অনেক ভুল ছিল; এর ব্যবস্থাপনার অভিজ্ঞতা থেকেই পরে Fred Brooks তাঁর বিখ্যাত বইটি লেখেন (অংশ ৪)।

“Bug” শব্দটির সাথে একটি গল্প জড়িয়ে আছে: ১৯৪৭ সালে Harvard Mark II কম্পিউটারের logbook-এ একটি সত্যিকারের মথ টেপ দিয়ে আটকে রাখা হয়েছিল, পাশে লেখা ছিল “First actual case of bug being found”. Grace Hopper-এর দল গল্পটি জনপ্রিয় করে। তবে প্রকৌশলে যন্ত্রের ত্রুটি বোঝাতে “bug” শব্দটি এর অনেক আগে থেকেই চালু ছিল — মথটি শব্দের জন্ম নয়, একটি মজার প্রমাণ মাত্র।

২ · Software crisis আর ১৯৬৮-র NATO সম্মেলন

১৯৬০-এর দশকের শেষ ভাগে প্রকৌশলী ও গবেষকেরা যে অবস্থার কথা বলতেন, তাকেই পরে বলা হলো software crisis. লক্ষণগুলো ছিল পরিচিত, আজও শোনা যায়:

  • সময় ও বাজেট ছাড়িয়ে যাওয়া: এক বছরের কাজ তিন বছরে গড়ায়, খরচ বাড়তেই থাকে।
  • অনির্ভরযোগ্য system: ব্যবহারকারীর হাতে পৌঁছানোর পর একের পর এক ভুল বের হয়।
  • যা চাওয়া হয়েছিল তা নয়: শেষে দেখা যায়, ব্যবহারকারীর আসল প্রয়োজন কেউ ঠিকমতো বোঝেননি।
  • রক্ষণাবেক্ষণ প্রায় অসম্ভব: কোড এত জট পাকানো যে একটি জিনিস ঠিক করতে গেলে আরেকটি ভাঙে।

মূল কারণটি সবচেয়ে সুন্দর করে বলেছিলেন Edsger W. Dijkstra, তাঁর ১৯৭২ সালের Turing Award বক্তৃতা “The Humble Programmer”-এ। তাঁর যুক্তির সারকথা: যন্ত্র যখন দুর্বল ছিল, প্রোগ্রামও ছোট ছিল; যন্ত্র যত শক্তিশালী হলো, মানুষ তত বড় ও জটিল প্রোগ্রাম বানাতে চাইল — আর প্রোগ্রাম লেখার পদ্ধতি সেই গতিতে বড় হয়নি। অর্থাৎ সমস্যাটা যন্ত্রের নয়, মানুষের চিন্তা ও কাজের পদ্ধতির।

Garmisch, অক্টোবর ১৯৬৮

এই অবস্থা নিয়ে আলোচনা করতে NATO-র Science Committee ১৯৬৮ সালের অক্টোবরে তখনকার পশ্চিম জার্মানির Garmisch শহরে একটি সম্মেলনের আয়োজন করে। বিভিন্ন দেশের প্রায় পঞ্চাশজন বিশেষজ্ঞ — বিশ্ববিদ্যালয়ের গবেষক, কম্পিউটার কোম্পানির প্রকৌশলী, বড় ব্যবহারকারী প্রতিষ্ঠানের প্রতিনিধি — এক সপ্তাহ ধরে design, উৎপাদন, পরীক্ষা আর রক্ষণাবেক্ষণের সমস্যা নিয়ে কথা বলেন। প্রতিবেদনটি সম্পাদনা করেন Peter Naur ও Brian Randell, প্রকাশিত হয় ১৯৬৯ সালে।

সম্মেলনের নামটিই ছিল বার্তা: “Software Engineering”. প্রতিবেদনের ভূমিকায় বলা হয়েছে, নামটি ইচ্ছে করে উসকানিমূলকভাবে বাছা হয়েছিল — বোঝাতে যে software বানানোকেও প্রতিষ্ঠিত প্রকৌশল শাখাগুলোর মতো তাত্ত্বিক ভিত্তি আর ব্যবহারিক শৃঙ্খলার ওপর দাঁড়াতে হবে। নামটির প্রস্তাবক হিসেবে প্রায়ই জার্মান কম্পিউটার বিজ্ঞানী Friedrich L. Bauer-এর নাম বলা হয়। তবে শব্দটি এর আগেও কিছু লেখায় ব্যবহৃত হয়েছিল; NATO সম্মেলন শব্দটি আবিষ্কার করেনি, জনপ্রিয় করেছে — এভাবে বলাই নিরাপদ।

পরের বছর, ১৯৬৯ সালের অক্টোবরে রোমে দ্বিতীয় সম্মেলন হয় (প্রতিবেদনের সম্পাদক J. N. Buxton ও Brian Randell). Randell-সহ অংশগ্রহণকারীদের পরের লেখা অনুযায়ী দ্বিতীয়টি প্রথমটির মতো সফল হয়নি — তত্ত্বের মানুষ আর বাস্তবের মানুষের মধ্যে আলোচনা মেলেনি। এই টানাপোড়েন আজও আছে: গবেষণাগারের পদ্ধতি আর কারখানার বাস্তবতা সবসময় এক কথা বলে না।

মূল ধারণা

Software engineering হলো software তৈরি, চালানো আর রক্ষণাবেক্ষণে পদ্ধতিগত, শৃঙ্খলাবদ্ধ ও মাপা যায় এমন পথ ব্যবহার করা — শুধু “কোড চলছে” নয়, বরং সময়, খরচ, মান, দল আর দীর্ঘ জীবন সব মিলিয়ে ভাবা। সংজ্ঞার বিভিন্ন রূপ আর তাদের পার্থক্য পর্ব ১-এ আছে।

Margaret Hamilton আর Apollo: একই সময়ে MIT Instrumentation Laboratory-তে Margaret Hamilton Apollo মহাকাশযানের on-board flight software-এর দলের নেতৃত্ব দিচ্ছিলেন। তিনি নিজে বলেছেন, software-এর কাজকে হার্ডওয়্যারের মতোই গুরুত্ব দেওয়াতে তিনি “software engineering” কথাটি ব্যবহার শুরু করেন — যদিও “প্রথম কে বলেছিলেন” প্রশ্নের নিশ্চিত উত্তর ইতিহাসবিদদের কাছে নেই। ১৯৬৯ সালে Apollo 11-এর অবতরণের সময় computer বারবার 1202 ও 1201 alarm দেখায়; প্রকাশিত বিবরণ অনুযায়ী অতিরিক্ত কাজের চাপে software কম জরুরি কাজ বাদ দিয়ে জরুরি কাজগুলো চালিয়ে যেতে পেরেছিল — অগ্রাধিকারভিত্তিক নকশার একটি বিখ্যাত উদাহরণ। ২০১৬ সালে তিনি যুক্তরাষ্ট্রের Presidential Medal of Freedom পান।

৩ · Dijkstra, goto আর structured programming

NATO সম্মেলনের বছরেই, ১৯৬৮ সালের মার্চে, Communications of the ACM-এ Dijkstra-র একটি ছোট চিঠি ছাপা হয়: “Go To Statement Considered Harmful”. শিরোনামটি দিয়েছিলেন পত্রিকার সম্পাদক Niklaus Wirth; Dijkstra-র নিজের শিরোনাম ছিল আরও শান্ত। চিঠির মূল কথা: goto দিয়ে প্রোগ্রামের যেকোনো জায়গা থেকে যেকোনো জায়গায় লাফ দেওয়া যায়, ফলে কোড পড়ে বোঝা কঠিন হয় — এই মুহূর্তে প্রোগ্রাম কোন অবস্থায় আছে, তা লেখা দেখে আর বলা যায় না।

ঢাকা থেকে রাজশাহীর ট্রেনের সময়সূচি ভাবুন। স্টেশনগুলো একটির পর একটি, ক্রম মেনে। এখন যদি নিয়ম থাকে “চালক চাইলে যেকোনো স্টেশন থেকে যেকোনো স্টেশনে লাফ দিতে পারবেন”, তাহলে কোনো যাত্রী আর বলতে পারবেন না পরের স্টেশন কোনটি। goto-ভরা কোড ঠিক এমন — যাকে বলা হতো “spaghetti code”, সেদ্ধ নুডলসের মতো জট পাকানো।

এর আগেই, ১৯৬৬ সালে Corrado Böhm ও Giuseppe Jacopini দেখিয়েছিলেন যে যেকোনো হিসাব তিনটি মাত্র কাঠামো দিয়ে লেখা যায়: ক্রম (একটির পর একটি), বাছাই (if-else) আর পুনরাবৃত্তি (loop). এই তিনটির ওপর দাঁড়ানো লেখার ধারাকে বলা হয় structured programming. ১৯৭২ সালে Ole-Johan Dahl, Dijkstra ও Tony Hoare-এর Structured Programming বইটি ধারণাটিকে ছড়িয়ে দেয়।

কাঠামোকী করেআজকের কোডে
Sequence (ক্রম)কাজ একটির পর একটিপরপর লেখা statement
Selection (বাছাই)শর্ত দেখে এক পথ বাছাif / else, switch
Iteration (পুনরাবৃত্তি)শর্ত সত্য থাকা পর্যন্ত বারবারfor, while

বিতর্কটি এক পক্ষের জয়ে শেষ হয়নি। ১৯৭৪ সালে Donald Knuth “Structured Programming with go to Statements” লিখে দেখান, কিছু জায়গায় (যেমন loop থেকে তাড়াতাড়ি বেরোনো বা error হলে পরিষ্কারের কোডে যাওয়া) নিয়ন্ত্রিত লাফ কোডকে বরং পরিষ্কার করে। আজকের break, return, try/catch সেই নিয়ন্ত্রিত লাফেরই নিরাপদ রূপ, আর C-র Linux kernel-এ এখনো error-পরিষ্কারের জন্য goto দেখা যায়। আসল শিক্ষা “goto নিষিদ্ধ” নয়; শিক্ষা হলো কোড এমনভাবে লিখুন, যাতে পড়ে তার আচরণ বোঝা যায়।

Dijkstra-র আরেকটি বিখ্যাত কথা প্রায়ই উদ্ধৃত হয়, ১৯৭০ সালের কাছাকাছি সময়ের লেখা থেকে: testing দিয়ে bug-এর উপস্থিতি দেখানো যায়, কিন্তু অনুপস্থিতি প্রমাণ করা যায় না। পর্ব ৪৫-এ testing-এর মৌলিক কথায় এই সীমাটি আবার আসবে।

৪ · Brooks — The Mythical Man-Month আর No Silver Bullet

Fred Brooks ১৯৬০-এর দশকে IBM-এ System/360 আর তার অপারেটিং সিস্টেম OS/360-এর উন্নয়ন পরিচালনা করেছিলেন। সেই অভিজ্ঞতা থেকে ১৯৭৫ সালে প্রকাশিত হয় The Mythical Man-Month: Essays on Software Engineering. বইটির নামেই একটি ভ্রান্ত ধারণাকে আক্রমণ করা হয়েছে: “man-month” বা “মানুষ-মাস” — অর্থাৎ ১০ জন × ৬ মাস = ৬০ মানুষ-মাস, তাই ২০ জন দিলে ৩ মাসেই হবে। Brooks দেখান, মানুষ আর মাস এভাবে অদলবদল করা যায় না।

Brooks’s law

বইয়ের সবচেয়ে বিখ্যাত বাক্যটি Brooks’s law: “Adding manpower to a late software project makes it later.” — দেরি হওয়া software project-এ লোক বাড়ালে সেটি আরও দেরি হয়। Brooks তিনটি কারণ দেখান:

  1. শেখার সময় (ramp-up): নতুন মানুষ প্রথম কয়েক সপ্তাহ প্রায় কিছুই দিতে পারেন না, উল্টো পুরোনোদের সময় নেন — তাঁদের বোঝাতে হয় কোড কোথায়, নিয়ম কী।
  2. যোগাযোগের খরচ: n জনের দলে প্রতি দুজনের মধ্যে একটি যোগাযোগের পথ; মোট পথ n(n−1)/2 — লোক বাড়লে পথ বাড়ে বর্গের হারে।
  3. সব কাজ ভাগ করা যায় না: Brooks-এর উদাহরণ — একটি শিশুর জন্ম নিতে নয় মাস লাগে, যত জন মা-ই নিয়োগ করুন না কেন।

নিচের stepper-এ দলের আকার বাড়ানোর সাথে যোগাযোগের পথ কীভাবে বাড়ে, দেখুন। ধরে নেওয়া হলো প্রতিটি পথে সপ্তাহে গড়ে ১ ঘণ্টা সমন্বয় লাগে (সংখ্যাটি শেখার জন্য ধরা)।

দলের আকার আর যোগাযোগ
মানুষ (n)
প্রতিজনের সঙ্গী (n − 1)
মোট পথ n(n−1)/2
সমন্বয়ে সপ্তাহে মোট ঘণ্টা
  1. দুজন: একটিমাত্র পথ। দুই বন্ধু মিলে একটি ছোট app — চায়ের দোকানে বসেই সব ঠিক হয়ে যায়।
  2. তিনজন: পথ ৩টি (ক–খ, ক–গ, খ–গ)। এখনো সহজ, তবে কেউ একজন কোনো সিদ্ধান্ত জানতে না পারার সম্ভাবনা শুরু হলো।
  3. চারজন: পথ ৬টি। মানুষ দ্বিগুণ (২ থেকে ৪), কিন্তু পথ ছয় গুণ।
  4. ছয়জন: পথ ১৫টি। দলীয় ক্রিকেট ম্যাচের মতো — মাঠে সবাইকে প্রতিটি পরিকল্পনা জানাতে হলে আলাদা সভা লাগে।
  5. দশজন: পথ ৪৫টি। ছয় থেকে দশ — মানুষ প্রায় ১.৭ গুণ, পথ ৩ গুণ (১৫ থেকে ৪৫)। প্রতি পথে সপ্তাহে ১ ঘণ্টা ধরলে দলের ৪৫ ঘণ্টা শুধু সমন্বয়ে যায়।
  6. বিশজন: পথ ১৯০টি। এজন্যই বড় প্রতিষ্ঠান সবাইকে সবার সাথে কথা বলতে দেয় না — ছোট দল, পরিষ্কার interface আর নির্দিষ্ট যোগাযোগের পথ বানায়। ছোট দলের ধারণাটি পর্ব ৫-এর Scrum দলেও দেখবেন।

এবার একটি খেলনা মডেলে Brooks’s law নিজেই চালিয়ে দেখুন। অনুমানগুলো কোডের প্রথম লাইনগুলোতে স্পষ্ট লেখা — সংখ্যাগুলো বানানো, কিন্তু প্রতিটি অনুমান Brooks-এর তিনটি কারণের একটির প্রতিনিধি। দিনে দিনে কাজের সামান্য ওঠানামা একটি নির্দিষ্ট seed-এর PRNG থেকে আসে, তাই প্রতিবার ফল একই।

// Brooks's law toy model. Assumptions are stated, numbers are made up.
// - 4 people; work turns out to be 200 person-days; 1 unit/day per expert
// - each person loses 0.03 of the day per other team member (communication)
// - a newcomer produces 0 for 20 days, then 0.5 for 20 days, then 1
// - while a newcomer is under 40 days old, one expert spends 0.25 day/day on them
// - day-to-day noise +-5% from a seeded PRNG (same for every run)
function mulberry32(a) { return function () { a = (a + 0x6D2B79F5) | 0;
  let t = Math.imul(a ^ (a >>> 15), 1 | a); t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
  return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; }
function finishDay(addPeople, addOnDay) {
  const rand = mulberry32(1975);
  let left = 200, day = 0;
  const joined = [0, 0, 0, 0];                       // day each person joined
  while (left > 0) {
    day++;
    if (day === addOnDay) for (let k = 0; k < addPeople; k++) joined.push(day);
    const n = joined.length;
    let work = 0, mentoring = 0;
    for (const j of joined) {
      const age = day - j, base = j === 0 ? 1 : age < 20 ? 0 : age < 40 ? 0.5 : 1;
      if (j > 0 && age < 40) mentoring += 0.25;
      work += base * (1 - 0.03 * (n - 1));
    }
    left -= (work - mentoring) * (0.95 + 0.1 * rand());
  }
  return day;
}
console.log("no one added        : day", finishDay(0, 1));
for (const k of [2, 4, 8]) console.log("add " + k + " on day 30     : day", finishDay(k, 30));
console.log("add 4 on day 1      : day", finishDay(4, 1));

আউটপুট:

no one added        : day 55
add 2 on day 30     : day 59
add 4 on day 30     : day 63
add 8 on day 30     : day 71
add 4 on day 1      : day 53

কেউ না এলে ৪ জনের দল দিনে নিট 4 × (1 − 0.03 × 3) = 3.64 একক কাজ করে; ২০০ একক শেষ হয় ৫৫তম দিনে। ৩০তম দিনে ২ জন এলে শেষ হয় ৫৯তম দিনে, ৪ জন এলে ৬৩তম, ৮ জন এলে ৭১তম দিনে — যত বেশি লোক, তত দেরি। কারণ নতুনরা প্রথম ২০ দিন কিছুই দেন না, পুরোনোদের সময় নেন, আর সবার যোগাযোগের খরচ বেড়ে যায়; ততদিনে বাকি কাজ প্রায় শেষের দিকে। প্রথম দিনেই ৪ জন নিলে শেষ হয় ৫৩তম দিনে — মাত্র দুই দিন আগে। শিক্ষা: লোক বাড়ানো কাজ করে তখনই, যখন কাজ ভাগ করা যায় এবং শেখার সময় শোধ হওয়ার মতো যথেষ্ট সময় সামনে থাকে। মডেলটি বাস্তব নয় — 0.03, 20 বা 0.25 বদলে দেখুন, কোন অনুমানে ফল উল্টে যায়।

Second-system effect আর conceptual integrity

Brooks আরও দুটি ধারণা দিয়েছেন, যা আজও design review-তে শোনা যায়। Second-system effect: একজন নকশাকার প্রথম system-টি সাবধানে, সংযত হয়ে বানান; সফল হলে দ্বিতীয়টিতে প্রথমবার বাদ রাখা সব “সুন্দর ইচ্ছা” ঢুকিয়ে দেন — ফলে দ্বিতীয় system ফুলে-ফেঁপে ভারী হয়ে যায়। Brooks-এর ভাষায় দ্বিতীয়টিই একজন নকশাকারের জীবনের সবচেয়ে বিপজ্জনক system.

Conceptual integrity: Brooks দাবি করেন, system design-এ সবচেয়ে গুরুত্বপূর্ণ বিবেচনা হলো পুরো system-এর পেছনে একটি সুসংগত ধারণা থাকা — যেন একজন মানুষের মাথা থেকে এসেছে। তিনি উদাহরণ দেন ফ্রান্সের Reims ক্যাথেড্রালের, যা বহু প্রজন্ম ধরে বানানো হলেও নকশায় এক। এর জন্য তিনি architecture (কী বানানো হবে, ব্যবহারকারী কী দেখবেন) আর implementation (কীভাবে বানানো হবে) আলাদা করার পরামর্শ দেন — অল্প কয়েকজন architect, অনেক implementer.

বিয়েবাড়ির আয়োজনের তালিকা ভাবুন। দশজন আত্মীয় যদি নিজের নিজের পছন্দে আলাদা করে মেনু, সাজসজ্জা আর গানের ব্যবস্থা করেন, অনুষ্ঠান হবে খিচুড়ি। একজন “মূল আয়োজক” সামগ্রিক রূপটি ঠিক করেন, বাকিরা সেই রূপের মধ্যে নিজের কাজ করেন — তখনই অনুষ্ঠানে একটি সুর থাকে। এটিই conceptual integrity.

No Silver Bullet (১৯৮৬)

১৯৮৬ সালে IFIP সম্মেলনে Brooks পড়েন “No Silver Bullet — Essence and Accidents of Software Engineering” (১৯৮৭ সালে IEEE Computer-এ পুনর্মুদ্রিত)। ইউরোপীয় লোককথায় রুপার গুলিই একমাত্র অস্ত্র যা নেকড়ে-মানবকে মারতে পারে। Brooks-এর দাবি: আগামী এক দশকে এমন কোনো একক প্রযুক্তি বা ব্যবস্থাপনা কৌশল আসবে না, যা একাই উৎপাদনশীলতা, নির্ভরযোগ্যতা বা সরলতায় দশ গুণ উন্নতি দেবে।

যুক্তিটি দাঁড়িয়ে আছে দুই ধরনের জটিলতার পার্থক্যের ওপর:

Essential complexity

Essential complexity — সমস্যার নিজের জটিলতা। ব্যাংকের সুদের নিয়ম, পরীক্ষার ফলের নীতিমালা, বাস্তব জগতের ব্যতিক্রম — এগুলো কোনো ভাষা বা টুল বদলালে কমে না।

complexity, conformity, changeability, invisibility

Accidental complexity

Accidental complexity — আমাদের হাতিয়ার আর পদ্ধতির কারণে আসা বাড়তি ঝামেলা: assembly-তে লেখা, ধীর compile, হাতে memory সামলানো। ভালো টুল এগুলো অনেকটা কমিয়েছে।

high-level ভাষা, IDE, time-sharing

Brooks-এর হিসাব: high-level ভাষা আর ভালো টুল ইতিমধ্যে accidental জটিলতার বড় অংশ সরিয়ে দিয়েছে; যা বাকি, তার বেশিরভাগই essential. তাই টুল যত ভালোই হোক, দশ গুণ লাফ আর আসবে না। তিনি essential জটিলতার চারটি দিক দেখান — জটিলতা নিজেই, বাইরের জগতের নিয়মের সাথে মানিয়ে চলা (conformity), সারাক্ষণ বদলানো (changeability) আর অদৃশ্যতা (software-এর কোনো ছবি চোখে দেখা যায় না)। আশার পথ হিসেবে বলেন: তৈরি জিনিস কেনা, prototype দিয়ে requirement পরিষ্কার করা, software-কে “বানানো” নয় বরং ধাপে ধাপে “বাড়ানো” (incremental — পর্ব ৪), আর মহান নকশাকার তৈরি করা।

১৯৯৫ সালে বইটির ২০তম বার্ষিকী সংস্করণে “No Silver Bullet” প্রবন্ধটি আর “‘No Silver Bullet’ Refired” নামে একটি পুনর্বিবেচনা যোগ হয়। আর Brooks’s law-কে Brooks মূল ১৯৭৫ সালের বইয়েই “চরম অতিসরলীকরণ” (oversimplifying outrageously) বলে উপস্থাপন করেছিলেন — নিয়মটি সবচেয়ে বেশি খাটে দেরিতে, ভাগ করা কঠিন কাজে লোক বাড়ালে।

৫ · Therac-25 — যখন software-কে অন্ধ বিশ্বাস করা হলো

এখন থেকে চারটি নথিভুক্ত ব্যর্থতা দেখব। লক্ষ্য কাউকে দোষ দেওয়া নয়, বরং কী ধরনের ভুল কীভাবে ঘটে তা চেনা। বিবরণগুলো সরকারি তদন্ত প্রতিবেদন আর প্রকাশিত গবেষণার ওপর ভিত্তি করে, সরল করে বলা — খুঁটিনাটির জন্য মূল উৎস পড়ুন।

Therac-25 ছিল Atomic Energy of Canada Limited (AECL)-এর তৈরি একটি radiation therapy যন্ত্র। ১৯৮৫ থেকে ১৯৮৭ সালের মধ্যে যুক্তরাষ্ট্র ও কানাডায় অন্তত ছয়টি দুর্ঘটনায় রোগীরা মাত্রাতিরিক্ত বিকিরণ পান; কয়েকজন মারা যান। সবচেয়ে বিখ্যাত বিশ্লেষণটি Nancy Leveson ও Clark Turner-এর, ১৯৯৩ সালে IEEE Computer-এ প্রকাশিত। তাঁদের বিশ্লেষণ অনুযায়ী মূল সমস্যাগুলো:

  • Hardware নিরাপত্তা সরিয়ে software-এর ওপর ভরসা: আগের মডেলগুলোতে বিপজ্জনক অবস্থা আটকানোর জন্য যান্ত্রিক interlock ছিল। Therac-25-এ সেই দায়িত্ব মূলত software-কে দেওয়া হয়।
  • পুরোনো কোডের পুনর্ব্যবহার: আগের মডেলের কোডের অংশ নেওয়া হয়েছিল; সেখানে লুকানো ভুল হার্ডওয়্যার interlock-এর কারণে কখনো বিপদ ঘটায়নি, তাই “পরীক্ষিত” মনে হয়েছিল।
  • Race condition: operator খুব দ্রুত data সম্পাদনা করলে যন্ত্রের একাধিক কাজ ভিন্ন সময়ে ভিন্ন মান পড়ত। আরেকটি ঘটনায় একটি এক-byte counter-এর overflow একটি নিরাপত্তা-যাচাই এড়িয়ে যেতে দিয়েছিল।
  • অস্পষ্ট error বার্তা আর অতি-আত্মবিশ্বাস: যন্ত্র দুর্বোধ্য সংক্ষিপ্ত বার্তা দেখাত, operator-রা অভ্যাসবশত এগিয়ে যেতেন; প্রথম দিকের অভিযোগে software-এর সম্ভাবনা গুরুত্ব পায়নি।

নিচের stepper race condition-এর ধারণাটি খুব সরল করে দেখায় — আসল যন্ত্রের কোড বা চিকিৎসা-বিবরণ নয়, শুধু ধরনটি। একটি shared variable mode; একটি কাজ (data entry) সেটি লেখে, আরেকটি কাজ (setup) পড়ে, আর setup শেষ হতে কয়েক সেকেন্ড লাগে। Race condition-এর সাধারণ তত্ত্ব আছে Operating Systems কোর্সের Race condition পর্বে।

shared অবস্থা (শেখার জন্য সরলীকৃত)
সময়
Operator-এর screen
shared mode
Setup কাজ
অংশ A (শক্তির মাত্রা)
অংশ B (অবস্থান)
ফল
  1. t = 0 s: operator ভুল করে mode X লিখে Enter চাপলেন। screen আর shared mode দুটোই X. এখনো কোনো সমস্যা নেই।
  2. t = 1 s: setup কাজ mode একবার পড়ল (X) আর সেই অনুযায়ী অংশ A সাজানো শুরু করল। Setup ধীর — কয়েক সেকেন্ড লাগবে। এই সময়ে সে নতুন সম্পাদনা খেয়াল করছে না।
  3. t = 5 s: operator ভুল বুঝে দ্রুত mode E করলেন। screen আর shared mode এখন E. কিন্তু setup কাজ ব্যস্ত; “data বদলেছে” — এই সংকেত সে যে মুহূর্তে যাচাই করে, সম্পাদনাটি তার বাইরে পড়েছে।
  4. t = 9 s: setup-এর শেষ অংশ mode আবার পড়ল — এবার E — আর অংশ B সাজাল E অনুযায়ী। ফলে অংশ A আছে X-এর মানে, অংশ B আছে E-এর মানে: একই যন্ত্রের দুই অংশ দুই ভিন্ন সময়ের data দিয়ে চলছে।
  5. t = 10 s: যন্ত্র “প্রস্তুত” দেখাল, screen-এ সবকিছু E — operator-এর চোখে কোনো ভুল নেই। ধীর গতিতে কাজ করলে এই ভুল কখনো ঘটে না, তাই সাধারণ testing-এ ধরা পড়াও কঠিন। দক্ষ operator যত দ্রুত, ঝুঁকি তত বেশি।
  6. সংশোধিত নকশা: shared data লেখা-পড়া একটি lock-এর ভেতরে, setup শুরুর আগে সব মানের একটি snapshot, শেষে সব অংশের মান আবার যাচাই, আর software ভুল করলেও যান্ত্রিক interlock বিপজ্জনক অবস্থা আটকাবে। নিরাপত্তা একটি স্তরে নয়, কয়েক স্তরে।

Therac-25-এর সবচেয়ে বড় শিক্ষা কোনো একটি bug নয়। শিক্ষা হলো “software তো ক্লান্ত হয় না, তাই ভুলও করে না” — এই ধারণাটি বিপজ্জনক। জীবন-মরণের system-এ software-কে একমাত্র পাহারাদার বানালে, তার প্রতিটি অজানা ভুল সরাসরি মানুষের ক্ষতি। পর্ব ৬৪-এ পেশাগত নৈতিকতায় এই দায়িত্বের কথা আবার আসবে।

৬ · Ariane 5 আর Mars Climate Orbiter — reuse আর এককের ভুল

Ariane 5 Flight 501 (১৯৯৬)

১৯৯৬ সালের ৪ জুন European Space Agency-র নতুন Ariane 5 রকেটের প্রথম উড্ডয়ন। উৎক্ষেপণের প্রায় ৪০ সেকেন্ডের মাথায় রকেট পথ থেকে সরে গিয়ে ভেঙে পড়ে এবং আত্মধ্বংস ব্যবস্থা চালু হয়। Jacques-Louis Lions-এর নেতৃত্বে তদন্ত বোর্ডের প্রতিবেদন (Lions report) কারণটি খুব স্পষ্টভাবে বলে, আর এটি software engineering-এর সবচেয়ে বেশি পড়ানো case study-গুলোর একটি।

রকেটের দিক ও অবস্থান মাপে Inertial Reference System (SRI). এর software নেওয়া হয়েছিল Ariane 4 থেকে — সেখানে বহু বছর ঠিকঠাক চলেছে। কিন্তু Ariane 5-এর উড্ডয়নের ধরন আলাদা: শুরুর দিকে তার horizontal velocity অনেক দ্রুত বাড়ে। একটি অংশে horizontal velocity-সম্পর্কিত একটি মান 64-bit floating-point থেকে 16-bit signed integer-এ রূপান্তর করা হতো। 16-bit signed integer ধরতে পারে শুধু −32768 থেকে 32767; Ariane 5-এ মানটি এই সীমা পেরিয়ে যায়।

  1. ReuseAriane 4 SRIপুরোনো, “পরীক্ষিত” কোড
  2. নতুন পথবেশি velocityপুরোনো অনুমান ভাঙল
  3. রূপান্তরfloat64 → int16Operand Error
  4. দুই SRI বন্ধno handlerbackup-ও একই কোড
  5. ভুল datadiagnosticflight data ভাবা হলো
  6. শিক্ষাrequirement + testreuse মানে অনুমানও reuse
  1. Reuse: SRI-এর software Ariane 4 থেকে নেওয়া। Lions report অনুযায়ী যে alignment অংশে ভুলটি ঘটে, সেটি উড্ডয়নের পরে Ariane 5-এ কোনো কাজেই লাগত না — Ariane 4-এ countdown থামলে দ্রুত আবার শুরু করার সুবিধার জন্য সেটি উড্ডয়নের পরেও কিছুক্ষণ চলত।
  2. নতুন পথ, পুরোনো অনুমান: Ariane 4-এর উড্ডয়নপথে মানটি কখনো 16-bit-এর সীমা ছাড়াত না, তাই সেখানে সুরক্ষা দরকার মনে হয়নি। প্রতিবেদন অনুযায়ী Ariane 5-এর উড্ডয়নপথের data দিয়ে এই অংশের পূর্ণ পরীক্ষা হয়নি — নতুন রকেটের requirement-এ এই পুরোনো অনুমান যাচাই হয়নি।
  3. রূপান্তরে overflow: উৎক্ষেপণের প্রায় ৩৭ সেকেন্ডে 64-bit float থেকে 16-bit signed integer-এ রূপান্তরের সময় মান সীমা ছাড়াল। Ada ভাষায় এটি একটি exception (Operand Error) তুলল। প্রতিবেদন অনুযায়ী computer-এর কাজের চাপ সীমার মধ্যে রাখতে কয়েকটি রূপান্তরে সুরক্ষা রাখা হয়নি, এটি তাদের একটি।
  4. দুই SRI বন্ধ: exception-এর কোনো handler ছিল না; নকশা অনুযায়ী SRI নিজেকে বন্ধ করে দিল। Backup SRI-তে একই software, একই data — তাই সেটিও একই কারণে মুহূর্ত আগে বন্ধ হয়েছিল। একই কোডের দুই কপি redundancy দেয় hardware ভাঙলে, software-এর ভুলে নয়।
  5. Diagnostic-কে flight data ভাবা: বন্ধ হওয়ার আগে SRI একটি diagnostic bit pattern পাঠাল; প্রধান computer সেটিকে উড্ডয়নের data হিসেবে পড়ে nozzle পুরো একদিকে ঘুরিয়ে দিল। বাতাসের প্রচণ্ড চাপে রকেট ভাঙতে শুরু করল, আর আত্মধ্বংস ব্যবস্থা চালু হলো।
  6. শিক্ষা: reuse করা কোড শুধু কোড নয় — তার ভেতরে লুকানো অনুমানগুলোও সাথে আসে। নতুন প্রেক্ষাপটে প্রতিটি অনুমান requirement হিসেবে লিখে যাচাই করা, বাস্তবসম্মত data দিয়ে integration test, আর অপ্রয়োজনীয় কোড না চালানো — এগুলোই প্রতিকার। Requirement-এর কথা পর্ব ২০–২৪-এ, boundary value test-এর কথা পর্ব ৪৭-এ।

এবার ভুলটির ধরন নিজের হাতে তৈরি করুন। নিচের প্রোগ্রামে একটি float মান প্রতি সেকেন্ডে বাড়ছে, আর তিনভাবে সেটিকে 16-bit signed integer-এ রাখা হচ্ছে: (ক) শুধু নিচের 16 bit রেখে দেওয়া — যা অনেক ভাষায় integer রূপান্তরে ঘটে; (খ) Ada-র মতো সীমা ছাড়ালে exception; (গ) একটি range check যা নিরাপদে ব্যর্থ হয় — সীমায় আটকে দেয় আর alarm তোলে। সংখ্যাগুলো শেখার জন্য বানানো, আসল উড্ডয়নের data নয়।

// Ariane 5-class bug. ILLUSTRATIVE numbers only, not flight data.
function mulberry32(a) { return function () { a = (a + 0x6D2B79F5) | 0;
  let t = Math.imul(a ^ (a >>> 15), 1 | a); t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
  return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; }
const rand = mulberry32(501);              // fixed seed: same output every run
const MIN16 = -32768, MAX16 = 32767;       // range of a 16-bit signed integer
function wrap16(x) {                       // keep only the low 16 bits
  const b = Math.trunc(x) & 0xFFFF;
  return b > MAX16 ? b - 65536 : b;
}
function strict16(x) {                     // Ada-style: out of range -> exception
  const v = Math.trunc(x);
  if (v < MIN16 || v > MAX16) throw new RangeError("Operand Error " + v);
  return v;
}
function safe16(x) {                       // range check that fails safe
  const v = Math.trunc(x);
  if (v > MAX16) return MAX16 + " (clamped, alarm)";
  if (v < MIN16) return MIN16 + " (clamped, alarm)";
  return String(v);
}
console.log("t  float64    wrap16  strict16   safe16");
for (let t = 0; t <= 6; t++) {
  const x = 20000 + 3000 * t + (rand() - 0.5) * 100;   // grows every second
  let s;
  try { s = String(strict16(x)); } catch (e) { s = "EXCEPTION"; }
  console.log(t + "  " + x.toFixed(1).padStart(8) + "  " + String(wrap16(x)).padStart(7) +
    "  " + s.padEnd(9) + "  " + safe16(x));
}

আউটপুট:

t  float64    wrap16  strict16   safe16
0   20036.5    20036  20036      20036
1   22968.1    22968  22968      22968
2   26027.2    26027  26027      26027
3   29044.4    29044  29044      29044
4   31999.2    31999  31999      31999
5   35000.8   -30536  EXCEPTION  32767 (clamped, alarm)
6   38042.5   -27494  EXCEPTION  32767 (clamped, alarm)

০ থেকে ৪ সেকেন্ড পর্যন্ত মান 32767-এর নিচে, তিন পদ্ধতিই একই উত্তর দেয় — এখানে কোনো test-ই ভুল ধরবে না। ৫ সেকেন্ডে মান 35000.8: wrap16 চুপচাপ দেয় −30536 (35000 − 65536) — একটি বড় ধনাত্মক মান হঠাৎ বড় ঋণাত্মক হয়ে গেল, কোনো সতর্কতা ছাড়াই। strict16 exception তোলে — Ariane 5-এ ঠিক এটিই হয়েছিল, আর সেটি ধরার কেউ ছিল না। safe16 মানটিকে 32767-এ আটকে রাখে আর alarm দেয়, যাতে উপরের স্তর জানে data-টি আর বিশ্বাসযোগ্য নয়। কোন আচরণ “নিরাপদ”, তা প্রেক্ষাপটে নির্ভর করে — উড্ডয়নের মাঝে system বন্ধ করে দেওয়া নিরাপদ ছিল না। এই কারণেই range check আর ব্যর্থতার পরে কী হবে, দুটোই requirement-এ লেখা দরকার। integer-এর ভেতরের রূপ জানতে Computer Architecture কোর্সের Integer representation পর্ব দেখুন।

Mars Climate Orbiter (১৯৯৯)

১৯৯৯ সালের ২৩ সেপ্টেম্বর NASA-র Mars Climate Orbiter মঙ্গলের কক্ষপথে ঢোকার সময় হারিয়ে যায়। NASA-র Mishap Investigation Board-এর প্রতিবেদন অনুযায়ী মূল কারণ: মাটিতে চলা একটি software-এর ফাইল (contractor Lockheed Martin-এর তৈরি) thruster-এর ছোট ছোট জ্বালানির ধাক্কা (impulse) হিসাব করত pound-force·second (lbf·s) এককে, অথচ দুই দলের মধ্যে সই করা interface specification অনুযায়ী মানটি হওয়ার কথা ছিল metric একক newton·second (N·s)-এ। JPL-এর navigation দল সংখ্যাটিকে N·s ধরে ব্যবহার করে। ১ lbf·s ≈ 4.448222 N·s, তাই প্রতিটি ছোট ধাক্কার প্রভাব প্রায় ৪.৪৫ গুণ কম ধরা হলো। মাসের পর মাস এই ছোট ভুল জমে মহাকাশযানের পথ মঙ্গলের অনেক কাছে নিয়ে যায়।

দর্জির কাছে জামার মাপ পাঠালেন: “বুক ৩৮”. আপনি ভেবেছেন ইঞ্চি, দর্জি ভাবলেন সেন্টিমিটার। সংখ্যা ঠিক, একক ভুল — জামাটি শিশুর মাপের হলো। সমস্যাটা কারও গণিতে নয়, দুজনের মধ্যের চুক্তিতে: কাগজে শুধু সংখ্যা ছিল, একক ছিল না।

নিচের কোডে প্রথম অংশ ভুলটি পুনরায় তৈরি করে, দ্বিতীয় অংশ একটি ছোট typed-unit wrapper দিয়ে তা ধরে। Thruster-এর ধাক্কাগুলো seed দেওয়া PRNG থেকে বানানো, আসল মিশনের data নয়।

// Mars Climate Orbiter-class bug. ILLUSTRATIVE burns, not mission data.
function mulberry32(a) { return function () { a = (a + 0x6D2B79F5) | 0;
  let t = Math.imul(a ^ (a >>> 15), 1 | a); t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
  return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; }
const rand = mulberry32(1999);
const N_S_PER_LBF_S = 4.448222;             // 1 lbf*s = 4.448222 N*s
// Team A: the spec says N*s, but this module really outputs lbf*s (a bare number).
const burns = Array.from({ length: 5 }, () => 0.5 + Math.round(rand() * 10) / 10);
const sentNumber = burns.reduce((a, b) => a + b, 0);
// Team B (navigation) reads the bare number as N*s.
console.log("burns (lbf*s):", burns.join(", "));
console.log("navigation used :", sentNumber.toFixed(3), "N*s");
console.log("real impulse    :", (sentNumber * N_S_PER_LBF_S).toFixed(3), "N*s");
console.log("underestimated by factor", N_S_PER_LBF_S);

// Fix: a tiny typed-unit wrapper. A bare number is rejected.
const TO_N_S = { "N*s": 1, "lbf*s": N_S_PER_LBF_S };
class Impulse {
  constructor(value, unit) {
    if (!(unit in TO_N_S)) throw new TypeError("unknown unit " + unit);
    this.value = value; this.unit = unit;
  }
  inNs() { return this.value * TO_N_S[this.unit]; }
}
function navUpdate(imp) {
  if (!(imp instanceof Impulse)) throw new TypeError("navUpdate needs an Impulse with a unit");
  return imp.inNs();
}
try { navUpdate(sentNumber); } catch (e) { console.log("caught:", e.message); }
console.log("typed  :", navUpdate(new Impulse(sentNumber, "lbf*s")).toFixed(3), "N*s");

আউটপুট:

burns (lbf*s): 0.9, 0.7, 1.4, 0.9, 0.6
navigation used : 4.500 N*s
real impulse    : 20.017 N*s
underestimated by factor 4.448222
caught: navUpdate needs an Impulse with a unit
typed  : 20.017 N*s

পাঁচটি ধাক্কার যোগফল 4.5 — কিন্তু এককটি lbf·s. Navigation সংখ্যাটিকে N·s ধরে 4.500 ব্যবহার করল, অথচ আসল impulse 4.5 × 4.448222 = 20.017 N·s; প্রভাব ধরা হলো আসলের মাত্র প্রায় ২২% (১/৪.৪৪৮)। খালি সংখ্যা কোনো সতর্কতা দেয় না। দ্বিতীয় অংশে Impulse class মান আর একক একসাথে বহন করে; navUpdate খালি সংখ্যা নিতে অস্বীকার করে (caught: লাইন), আর lbf·s-এ দেওয়া মান নিজেই ঠিকভাবে 20.017 N·s-এ রূপান্তর করে। এই ধারণাকে বলে unit of measure type: F#-এর মতো কিছু ভাষায় একক type system-এর অংশ, অন্য ভাষায় library দিয়ে করা হয়। মডিউলের মধ্যে চুক্তি (contract) কীভাবে লিখতে হয়, তা পর্ব ৩১-এ; দুই দলের অংশ জুড়ে test করার কথা পর্ব ৫১-এ।

৭ · Knight Capital, ব্যর্থতার শিক্ষা আর CHAOS বিতর্ক

Knight Capital (২০১২)

২০১২ সালের ১ আগস্ট যুক্তরাষ্ট্রের শেয়ারবাজারের বড় একটি ট্রেডিং প্রতিষ্ঠান Knight Capital নতুন একটি বাজার-কর্মসূচির জন্য তাদের order-routing software হালনাগাদ করে। যুক্তরাষ্ট্রের Securities and Exchange Commission (SEC)-এর ২০১৩ সালের নথি অনুযায়ী ঘটনাটি এমন:

  • নতুন কোড আটটি server-এ হাতে হাতে বসানোর কথা ছিল; একজন প্রকৌশলী একটিতে বসাতে ভুলে যান, আর কেউ দ্বিতীয়বার যাচাই করেননি।
  • নতুন কোড একটি পুরোনো flag-কে নতুন অর্থে ব্যবহার করছিল। ওই flag আগে “Power Peg” নামের বহু বছর ধরে অব্যবহৃত একটি পুরোনো ফাংশন চালু করত — যার কোড তখনো server-এ রয়ে গিয়েছিল (dead code).
  • বাজার খোলার পর বাদ পড়া ওই একটি server নতুন বার্তার flag দেখে পুরোনো পথটি চালাল এবং অনিয়ন্ত্রিতভাবে order পাঠাতে লাগল। প্রায় ৪৫ মিনিটে প্রতিষ্ঠানটির ৪৬০ মিলিয়ন ডলারের বেশি ক্ষতি হয় (SEC-এর হিসাব)।
  • SEC আরও উল্লেখ করে, deployment যাচাইয়ের লিখিত পদ্ধতি আর এমন ঘটনায় কী করতে হবে তার স্পষ্ট নির্দেশনা ছিল না।

শিক্ষাগুলো সরাসরি আধুনিক delivery-র ভিত্তি: deployment হাতে নয়, স্বয়ংক্রিয় ও পুনরাবৃত্তিযোগ্য pipeline-এ; প্রতিটি server-এ কী version চলছে তা যাচাই; পুরোনো feature flag নতুন অর্থে পুনর্ব্যবহার নয়; অব্যবহৃত কোড মুছে ফেলা; আর দ্রুত বন্ধ করার “kill switch”. Feature flag আর trunk-based development-এর কথা পর্ব ১৭-এ, deployment pipeline পর্ব ৫৯-এ, আর release-এর কৌশল (canary, rollback) System Design কোর্সের Deployment আর release পর্বে।

চার ঘটনা, চার শিক্ষা

ঘটনাকারিগরি মূলযে অভ্যাস রক্ষা করতকোর্সে কোথায়
Therac-25 (১৯৮৫–৮৭)Race condition, overflow, hardware interlock বাদSafety analysis, স্তরে স্তরে সুরক্ষা, স্বাধীন review, পরিষ্কার error বার্তাপর্ব ৩, ৪৫, ৬৪
Ariane 5 (১৯৯৬)Reuse-এর অনুমান, float→int16 overflow, handler নেইRequirement-এ অনুমান লেখা, boundary test, বাস্তব data-য় integration testপর্ব ২১, ৪৭, ৫১
Mars Climate Orbiter (১৯৯৯)Interface-এ এককের অমিলInterface চুক্তি, typed unit, দুই দলের যৌথ test, সন্দেহ উঠলে জানানোপর্ব ৩১, ৫১
Knight Capital (২০১২)হাতে deployment, পুরোনো flag, dead codeস্বয়ংক্রিয় deployment, version যাচাই, dead code মোছা, kill switchপর্ব ১৭, ৪৩, ৫৯
মূল ধারণা

চারটি ঘটনার কোনোটিতেই একজন “খারাপ programmer” একা দায়ী নয়। প্রতিটিতে একাধিক ছোট ফাঁক একসাথে সারিতে দাঁড়িয়েছিল — requirement, review, test, deployment, সংগঠনের সংস্কৃতি। তাই আধুনিক দলগুলো ঘটনার পর দোষারোপহীন postmortem লেখে: কে নয়, কোন ব্যবস্থা ভুলটি ঘটতে দিল।

সংখ্যা দিয়ে ব্যর্থতা মাপা — CHAOS report বিতর্ক

Software project কত শতাংশ ব্যর্থ হয় — এই প্রশ্নে সবচেয়ে বেশি উদ্ধৃত উৎস Standish Group-এর CHAOS report, প্রথমটি ১৯৯৪ সালে। বহু বই আর বক্তৃতায় এর নাটকীয় শতাংশ “সত্য” হিসেবে ব্যবহার হয়েছে। কিন্তু গবেষকেরা এর পদ্ধতি নিয়ে গুরুতর প্রশ্ন তুলেছেন: Robert Glass (Communications of the ACM, ২০০৬) জিজ্ঞেস করেছেন এটি আসলেই “crisis” প্রমাণ করে কি না; Magne Jørgensen ও Kjetil Moløkken-Østvold (২০০৬) ১৯৯৪-এর রিপোর্টের খরচ-বৃদ্ধির হিসাবকে অন্য গবেষণার সাথে অসংগত পেয়েছেন; আর J. Laurenz Eveleens ও Chris Verhoef (IEEE Software, ২০১০) দেখিয়েছেন যে “ব্যর্থতা”-র সংজ্ঞা — প্রথম অনুমানের সাথে তুলনা — সংখ্যাগুলোকে এক দিকে হেলিয়ে দেয়। সমালোচনাগুলোর মূল কথা: কোন project নমুনায় এল, “ব্যর্থ” কাকে বলা হলো আর raw data প্রকাশ হয়নি কেন।

তাই এই কোর্সে CHAOS-এর কোনো শতাংশ তথ্য হিসেবে লেখা হলো না। কেউ “৭০% software project ব্যর্থ হয়” বললে জিজ্ঞেস করুন: কোন বছরের, কার জরিপ, “ব্যর্থ”-এর সংজ্ঞা কী, নমুনা কীভাবে বাছা? Software engineering-এ প্রমাণের মান যাচাই করাও engineering-এর অংশ।

৮ · Structured থেকে AI — যুগের পর যুগ

১৯৬৮-র পর software engineering এক জায়গায় দাঁড়িয়ে থাকেনি। প্রতিটি নতুন যুগ আগের যুগের কোনো একটি ব্যথার উত্তর হিসেবে এসেছে — আর প্রায়ই নিজের নতুন ব্যথা নিয়ে এসেছে। নিচের ছবিতে দশক ধরে মূল ধারাগুলো:

Software engineering-এর যুগ, ১৯৫০ থেকে ২০২০-এর দশক

Eras of software engineering, 1950s–2020s (years are approximate where marked ~)

Software engineering-এর যুগ, ১৯৫০ থেকে ২০২০-এর দশক ১৯৫০১৯৬০১৯৭০১৯৮০ ১৯৯০২০০০২০১০২০২০ প্রথম high-level ভাষা Software crisis Structured আর process Object-oriented Pattern আর open source Agile আর version control Cloud আর CI/CD AI-সহায়তায় উন্নয়ন FORTRAN ১৯৫৭ · COBOL ১৯৫৯ OS/360 · NATO সম্মেলন ১৯৬৮ Royce ১৯৭০ · Brooks ১৯৭৫ C++ · No Silver Bullet ১৯৮৬ Linux ১৯৯১ · GoF ১৯৯৪ Manifesto ২০০১ · Git ২০০৫ DevOps ~২০০৯ · container code assistant · নতুন ঝুঁকি
ছবি ২.১ — প্রতিটি দশকের প্রধান ধারা আর একটি-দুটি চিহ্ন-ঘটনা। সীমারেখাগুলো ঝাপসা: object-oriented ভাষার শুরু ১৯৬০-এর দশকে (Simula), আর DevOps শব্দটি ২০০৯-এর কাছাকাছি সময় থেকে জনপ্রিয়।

এবার প্রতিটি মোড় ধাপে ধাপে দেখুন — কোন ব্যথা থেকে কোন উত্তর এল।

  1. ১৯৬৮NATOনাম আর লক্ষ্য
  2. ১৯৭০Royceধাপে ধাপে process
  3. ১৯৭৫MMMমানুষ আর সময়
  4. ১৯৮৬NSBরুপার গুলি নেই
  5. ১৯৯৪GoFনকশার ভাষা
  6. ২০০১Agileছোট ধাপ, feedback
  7. ~২০০৯DevOpsবানানো + চালানো
  8. ২০২০-এর দশকAIদ্রুত কোড, নতুন যাচাই
  1. ১৯৬৮ — NATO সম্মেলন: ব্যথা: বড় project দেরি, বাজেট-ছাড়া আর ভুলে ভরা। উত্তর: software বানানোকে প্রকৌশলের শৃঙ্খলায় আনার লক্ষ্য আর একটি নাম। একই বছরে Dijkstra-র goto-চিঠি কোড পড়ার যোগ্যতাকে কেন্দ্রে আনে।
  2. ১৯৭০ — Royce-এর paper: Winston Royce-এর “Managing the Development of Large Software Systems” ধাপে ধাপে উন্নয়নের একটি ছবি দেয়, যাকে পরে “waterfall” বলা হয় — যদিও Royce নিজে শব্দটি ব্যবহার করেননি এবং একটানা এক-দিকের প্রবাহকে ঝুঁকিপূর্ণ বলেছিলেন। Process model-এর পুরো গল্প পর্ব ৪-এ (SDLC আর process model).
  3. ১৯৭৫ — The Mythical Man-Month: ব্যথা: “লোক বাড়ালেই দ্রুত হবে” ভাবনা। উত্তর: Brooks’s law, conceptual integrity, ছোট দল। Estimation-এর আধুনিক পদ্ধতি (COCOMO II, story point) পর্ব ৬০-এ।
  4. ১৯৮৬ — No Silver Bullet: ব্যথা: প্রতিটি নতুন টুলকে “সব সমাধান” ভাবা। উত্তর: essential আর accidental জটিলতার পার্থক্য; ধাপে ধাপে বাড়ানো, prototype, ভালো নকশাকার। একই দশকে Boehm-এর spiral model ঝুঁকিকে কেন্দ্রে আনে (পর্ব ৪)।
  5. ১৯৯৪ — Gang of Four: Gamma, Helm, Johnson ও Vlissides-এর Design Patterns বই object-oriented নকশার বারবার আসা সমাধানগুলোকে নাম দেয় — দলগুলো একই ভাষায় নকশা নিয়ে কথা বলতে পারে। Object-oriented ধারণা এসেছিল আগেই (Simula, Smalltalk, C++). Design pattern-এর বিস্তারিত পর্ব ৩২ থেকে।
  6. ২০০১ — Agile Manifesto: ফেব্রুয়ারি ২০০১-এ যুক্তরাষ্ট্রের Utah-র Snowbird-এ ১৭ জন উন্নয়নকারী Agile Manifesto লেখেন। ব্যথা: ভারী কাগজপত্র, দেরিতে feedback. উত্তর: ছোট ধাপ, চালানো যায় এমন software, গ্রাহকের সাথে সহযোগিতা, পরিবর্তনকে স্বাগত। এর আগে-পরে open source (Linux ১৯৯১) দেখিয়েছে বিশ্বজুড়ে ছড়ানো দলও কাজ করতে পারে, আর ২০০৫ সালে Linus Torvalds Git বানান (পর্ব ৭)। Agile-এর বিস্তারিত পর্ব ৫-এ (Agile আর Scrum), lean-এর ধারণা পর্ব ৬-এ (Kanban আর lean).
  7. ~২০০৯ — DevOps: ব্যথা: উন্নয়ন দল কোড “ছুড়ে দেয়”, operations দল চালাতে গিয়ে বিপদে পড়ে। ২০০৯ সালে বেলজিয়ামের Ghent-এ Patrick Debois-এর আয়োজিত DevOpsDays থেকে শব্দটি ছড়ায়। উত্তর: এক দল, স্বয়ংক্রিয় continuous integration ও continuous delivery, cloud-এ দ্রুত পরিবেশ। DevOps আর DORA metric-এর কথা পর্ব ৫৮–৫৯-এ।
  8. ২০২০-এর দশক — AI-সহায়তায় উন্নয়ন: AI code assistant কোড, test আর ব্যাখ্যা দ্রুত লিখে দেয় — accidental জটিলতার আরেকটি বড় অংশ কমায়। কিন্তু essential জটিলতা — কী বানাতে হবে, কোন অনুমান সত্য, কোন ঝুঁকি গ্রহণযোগ্য — রয়ে যায়; সাথে আসে নতুন ঝুঁকি: আত্মবিশ্বাসী ভুল কোড, license আর গোপন তথ্যের প্রশ্ন। অংশ ৯-এ এর বিস্তারিত।

আরও গভীরে: মূল উৎসগুলো অনলাইনে পড়া যায়: NATO সম্মেলনের ১৯৬৮ ও ১৯৬৯-এর প্রতিবেদন (Naur ও Randell; Buxton ও Randell), Dijkstra-র লেখার সংগ্রহ (EWD manuscripts), Ariane 5-এর Lions report আর Mars Climate Orbiter-এর Mishap Investigation Board-এর Phase I প্রতিবেদন। Therac-25-এর পূর্ণ বিশ্লেষণ আছে Nancy Leveson-এর Safeware (১৯৯৫) বইয়ে; আর Bertrand Meyer ও Jean-Marc Jézéquel ১৯৯৭ সালে IEEE Computer-এ যুক্তি দিয়েছিলেন যে design by contract পদ্ধতিতে Ariane-এর অনুমানটি কোডেই লেখা থাকলে review-তে ধরা পড়ত — যদিও অনেকে এই দাবিকে অতিসরল মনে করেন।

পরীক্ষা ও ইন্টারভিউতে — বিশ্ববিদ্যালয়, চাকরি বা ইন্টারভিউর পরীক্ষায় এই ধরনের প্রশ্ন আসতে পারে:

  • Software crisis কী, এর তিনটি লক্ষণ বলুন। ১৯৬০-এর দশকের শেষের অবস্থা: সময় ও বাজেট ছাড়ানো, অনির্ভরযোগ্য system, চাহিদার সাথে অমিল, রক্ষণাবেক্ষণে কষ্ট।
  • “Software engineering” শব্দটি কোন সম্মেলনে জনপ্রিয় হয়? NATO Software Engineering Conference, Garmisch, অক্টোবর ১৯৬৮; পরেরটি রোম, ১৯৬৯।
  • Brooks’s law কী, এবং কেন? দেরি হওয়া project-এ লোক দিলে আরও দেরি হয় — ramp-up, n(n−1)/2 যোগাযোগ পথ, অবিভাজ্য কাজ।
  • Essential আর accidental complexity-র পার্থক্য? সমস্যার নিজের জটিলতা বনাম হাতিয়ার-পদ্ধতির বাড়তি জটিলতা; টুল শুধু দ্বিতীয়টি কমায়।
  • Ariane 5 Flight 501 কেন ব্যর্থ হয়? Ariane 4-এর reuse করা কোডে 64-bit float থেকে 16-bit integer রূপান্তরে overflow, handler নেই, দুই SRI বন্ধ।

৯ · AI-এর যুগে — ইতিহাসের শিক্ষা মনে রেখে AI ব্যবহার

আজকের AI code assistant যেন Brooks-এর প্রশ্নের নতুন পরীক্ষা: এটি কি রুপার গুলি? অভিজ্ঞতা বলছে, AI accidental কাজ — boilerplate, পরিচিত pattern, প্রথম খসড়া test — অনেক দ্রুত করে। কিন্তু এই পর্বের চারটি ব্যর্থতার একটিও “কোড টাইপ করতে দেরি”-র কারণে ঘটেনি। ঘটেছে অনুমান, interface, deployment আর বিশ্বাসের ভুলে — ঠিক যেখানে AI সবচেয়ে আত্মবিশ্বাসী ভুল করতে পারে।

AI টাইপ করার গতি বাড়ায়, বোঝার দায়িত্ব কমায় না।
Essential জটিলতা এখনো আপনার টেবিলে।

AI সাধারণত যেসব ভুল করে — software engineering-এ

AI-এর ভুলকেন বিপজ্জনককীভাবে যাচাই করবেন
ইতিহাস, সাল বা উদ্ধৃতি বানিয়ে বলা (যেমন ভুল সালে NATO সম্মেলন, Brooks-এর মুখে না-বলা কথা)রিপোর্ট বা পরীক্ষার উত্তরে ভুল তথ্য ছড়ায়মূল উৎস (প্রতিবেদন, বই) খুলে মেলানো
উৎসহীন পরিসংখ্যান (“৭০% project ব্যর্থ”)ভুল সিদ্ধান্তের ভিত্তি হয়কার জরিপ, কোন বছর, সংজ্ঞা কী — জিজ্ঞেস করা
কোনো সতর্কতা ছাড়াই git reset --hard বা git push --force পরামর্শ দেওয়াঅন্যের বা নিজের কাজ মুছে যেতে পারেআগে একটি ফেলে-দেওয়া clone-এ চালানো, git help <command> পড়া (পর্ব ১১)
অস্তিত্বহীন command flag বা standard-এর ভুল version বলাকোড চলে না, বা ভুল নিয়ম মানা হয়সরকারি documentation মেলানো
এমন test লেখা যা কিছুই যাচাই করে না, বা কোডের হুবহু প্রতিচ্ছবিAriane-এর মতো সীমার ভুল ধরা পড়ে নাইচ্ছে করে ভুল ঢুকিয়ে দেখা test ব্যর্থ হয় কি না (mutation testing, পর্ব ৫০)
সব জায়গায় pattern চাপানো, বিশ্বাসযোগ্য কিন্তু ভুল UML আঁকাSecond-system effect-এর মতো অকারণ ভারপ্রতিটি অংশের দরকার নিজে ব্যাখ্যা করতে পারা
License না দেখে কোড কপি, prompt-এ গোপন key বা password পাঠানোআইনি ঝুঁকি, নিরাপত্তা ফাঁসLicense যাচাই, prompt-এ গোপন তথ্য না দেওয়া

ইতিহাস বা case study নিয়ে AI-কে প্রশ্ন করলে তাকে উৎস দিতে আর অনিশ্চয়তা স্বীকার করতে বাধ্য করুন:

আমি software engineering শিখছি। Ariane 5 Flight 501 (১৯৯৬) ব্যর্থতার কারিগরি কারণ সহজ বাংলায় ব্যাখ্যা করো। ১. প্রতিটি দাবির পাশে লেখো সেটি কোন উৎস থেকে (যেমন Lions report-এর কোন অংশ)। ২. যে তথ্য নিয়ে তুমি নিশ্চিত নও, সেটি আলাদা করে "অনিশ্চিত" লিখে চিহ্নিত করো। ৩. কোনো শতাংশ, টাকার অঙ্ক বা উদ্ধৃতি বানিয়ে দিও না। ৪. শেষে বলো, এই ঘটনা থেকে requirement, reuse আর testing নিয়ে তিনটি শিক্ষা কী।

AI-এর লেখা কোড বা পরামর্শ হাতে পেলে — যাচাইয়ের চেকলিস্ট

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

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

প্র ০১১৯৬৮-তে নামটি “উসকানিমূলক” ছিল — software বানানো কি সত্যিই civil বা electrical engineering-এর মতো প্রকৌশল?

NATO প্রতিবেদন নিজেই স্বীকার করেছিল, নামটি একটি আকাঙ্ক্ষা, বাস্তবতার বর্ণনা নয়। প্রায় ষাট বছর পরেও প্রশ্নটি জীবন্ত, কারণ মিল আর অমিল দুটোই বড়।

  • মিল: দুই ক্ষেত্রেই সীমিত সময়-টাকায় এমন জিনিস বানাতে হয় যা মানুষের ওপর প্রভাব ফেলে; দুই ক্ষেত্রেই নকশা, হিসাব, পরিদর্শন, মান আর দায়িত্বের ভাগ লাগে। Ariane 5 বা Therac-25-এর মতো ঘটনা দেখায় software-এর ভুলও সেতু ভেঙে পড়ার মতোই বাস্তব ক্ষতি করতে পারে।
  • অমিল ১ — পদার্থবিদ্যার সীমা নেই: সেতুর প্রকৌশলী মাধ্যাকর্ষণ আর উপাদানের শক্তির নিয়ম জানেন, যা বদলায় না। Software-এর “উপাদান” হলো চিন্তা — প্রায় সীমাহীন নমনীয়। Brooks একেই বলেছেন changeability আর invisibility.
  • অমিল ২ — বিচ্ছিন্ন আচরণ: একটি বিম ১০% বেশি ভার পেলে একটু বেশি বাঁকে; একটি integer এক বেশি হলে 32767 থেকে −32768 হয়ে যায়। ছোট পরিবর্তনে বিশাল লাফ — তাই সেতুর মতো “নিরাপত্তার মার্জিন” হিসাব করা কঠিন।
  • অমিল ৩ — পেশার কাঠামো: অনেক দেশে civil engineer হতে লাইসেন্স লাগে; software-এ সাধারণত লাগে না। David Parnas-এর মতো গবেষকেরা বহুদিন ধরে software-কে পূর্ণ পেশাদার প্রকৌশল শাখা বানানোর পক্ষে বলেছেন; IEEE Computer Society-র SWEBOK (Software Engineering Body of Knowledge) সেই জ্ঞানভান্ডার গোছানোর একটি চেষ্টা।

বাস্তবে উত্তরটি ক্ষেত্রভেদে আলাদা। বিমান, চিকিৎসা-যন্ত্র বা রেলের signalling software-এ কঠোর standard আর সনদ লাগে — সেখানে কাজটি প্রায় প্রথাগত প্রকৌশলের মতোই। একটি ছোট অনলাইন বাজার অ্যাপে (কাল্পনিক) এত কঠোরতা অপচয়; সেখানে দ্রুত শেখা আর বদলানোই বড় গুণ।

মূল উপলব্ধি: “Engineering” মানে নির্দিষ্ট কোনো রীতি নয়, বরং ঝুঁকির মাপে শৃঙ্খলা বাছাই করা — আর সিদ্ধান্তের দায় নেওয়া। ভালো software engineer জানেন কোথায় কতটা কঠোর হতে হবে।

প্র ০২Brooks’s law কি সবসময় সত্য? Open source project-এ তো হাজার মানুষ যোগ দেন, তবু কাজ এগোয় — কীভাবে?

Brooks নিজেই ১৯৭৫ সালে নিয়মটি দেওয়ার সময় একে “চরম অতিসরলীকরণ” বলেছিলেন। নিয়মটি আসলে একটি নির্দিষ্ট অবস্থার কথা বলে: দেরি হওয়া project, যেখানে কাজ শক্তভাবে জোড়া, নতুনদের শেখার সময় বেশি, আর বাকি সময় কম।

Open source এই শর্তগুলোর কয়েকটি ভেঙে দেয়। Eric S. Raymond তাঁর ১৯৯৭ সালের প্রবন্ধ “The Cathedral and the Bazaar”-এ Linux-এর অভিজ্ঞতা থেকে বলেছিলেন, “যথেষ্ট চোখ থাকলে সব bug সহজ” — যাকে তিনি নাম দেন Linus’s law. এখানে বেশির ভাগ নতুন মানুষ ছোট, আলাদা, স্বাধীন কাজ করেন — একটি driver, একটি bug, একটি অনুবাদ। তাঁদের সবার সাথে সবার কথা বলতে হয় না; কথা চলে mailing list, issue আর pull request-এর মাধ্যমে, আর একটি ছোট maintainer দল conceptual integrity রক্ষা করে। অর্থাৎ যোগাযোগের পথ n(n−1)/2 নয়, অনেকটা একটি তারার মতো — সবাই কেন্দ্রের সাথে।

তবু Brooks-এর মূল কথা সেখানেও খাটে। বড় open source project-এ নতুন contributor-কে ঢোকাতে maintainer-দের সময় যায় — review, প্রশ্নের উত্তর, ভুল ধরানো। অনেক maintainer এই চাপকে burnout-এর বড় কারণ বলেছেন। আর মূল নকশা বদলানোর কাজ (যেমন একটি core অংশ নতুন করে লেখা) ভাগ করা কঠিন — সেখানে অল্প কয়েকজনই কাজ করেন।

আধুনিক দলগুলো Brooks-এর শিক্ষা কাজে লাগায় দুইভাবে: (১) দল ছোট রাখা আর দলের মধ্যে পরিষ্কার interface বানানো — module, API, microservice-এর সীমা (পর্ব ২৫-এ coupling-cohesion); (২) নতুন মানুষ project-এর শুরুর দিকে নেওয়া, যখন শেখার সময় শোধ হওয়ার মতো যথেষ্ট সময় সামনে থাকে — খেলনা মডেলেও প্রথম দিনে লোক নিলে দেরি হয়নি।

মূল উপলব্ধি: Brooks’s law কোনো প্রাকৃতিক সূত্র নয়, যোগাযোগ আর শেখার খরচের একটি সতর্কবার্তা। কাজ যত ভাগযোগ্য আর interface যত পরিষ্কার, লোক বাড়ানো তত কার্যকর।

প্র ০৩Ariane 5-এর দোষ কার — যে programmer রূপান্তরটি লিখেছিলেন, যাঁরা reuse-এর সিদ্ধান্ত নিয়েছিলেন, নাকি যাঁরা test করেছিলেন?

Lions report এই প্রশ্নের উত্তর দিয়েছে একটি পরিষ্কার বার্তায়: ব্যর্থতাটি একটি system specification ও design-এর ভুল, একজন মানুষের টাইপের ভুল নয়।

  • কোডের সিদ্ধান্তটি যুক্তিসংগত ছিল — Ariane 4-এর জন্য। কয়েকটি রূপান্তরে সুরক্ষা না রাখার সিদ্ধান্ত নেওয়া হয়েছিল computer-এর কাজের চাপ সীমায় রাখতে, আর বিশ্লেষণ বলেছিল Ariane 4-এর উড্ডয়নপথে মানগুলো সীমা ছাড়াবে না। সেই প্রেক্ষাপটে এটি ঠিকই ছিল।
  • Reuse-এর সিদ্ধান্তে অনুমানটি হারিয়ে গেল। “এই মান কখনো 32767 ছাড়াবে না” — এই অনুমানটি কোথাও requirement হিসেবে লেখা ছিল না যা Ariane 5-এর নতুন উড্ডয়নপথের সাথে মেলানো যায়। অনুমান কোডের সাথে এসেছে, কিন্তু কাগজে আসেনি।
  • Test-এ বাস্তব data ছিল না। প্রতিবেদন অনুযায়ী SRI-কে Ariane 5-এর উড্ডয়নপথের data দিয়ে পূর্ণাঙ্গ simulation-এ পরীক্ষা করা হয়নি; করলে ভুলটি মাটিতেই ধরা পড়ত।
  • সংস্কৃতি: প্রতিবেদন একটি মনোভাবের সমালোচনা করে — software-কে ভুল প্রমাণ না হওয়া পর্যন্ত সঠিক ধরে নেওয়া, আর exception হলেই system বন্ধ করার নকশা, যা hardware-এর এলোমেলো ত্রুটির জন্য ঠিক, কিন্তু একই software-এর দুই কপিতে একই ভুলের জন্য নয়।

Bertrand Meyer ও Jean-Marc Jézéquel ১৯৯৭ সালে যুক্তি দিয়েছিলেন, অনুমানটি precondition হিসেবে কোডে লেখা থাকলে (design by contract) reuse-এর সময় চোখে পড়ত। অন্যরা পাল্টা বলেছেন, সমস্যাটা ছিল প্রক্রিয়া আর review-এর, শুধু একটি ভাষার বৈশিষ্ট্যে তা মিটত না। দুই পক্ষই একমত — অনুমান লুকিয়ে রাখা চলবে না।

মূল উপলব্ধি: বড় ব্যর্থতায় “কার দোষ” প্রশ্নটি ভুল দিকে নিয়ে যায়। সঠিক প্রশ্ন: কোন অনুমান কোথায় লেখা ছিল না, কোন test হয়নি, আর কোন নকশা একটি ভুলকে বিপর্যয়ে বদলাতে দিল।

প্র ০৪Therac-25-এর পরে জীবন-মরণের software বানানোর নিয়ম কীভাবে বদলেছে? সাধারণ app-এর জন্য এর কোনো শিক্ষা আছে কি?

Therac-25 safety-critical software-এর ইতিহাসে একটি সতর্কবার্তা হয়ে আছে, আর Leveson ও Turner-এর বিশ্লেষণ আজও বহু কোর্সে পড়ানো হয়। এর পরের দশকগুলোতে কয়েকটি পরিবর্তন স্পষ্ট:

  • Standard আর জীবনচক্রের নিয়ম: চিকিৎসা-যন্ত্রের software-এর জন্য IEC 62304 (প্রথম সংস্করণ ২০০৬) উন্নয়নের প্রতিটি ধাপে ঝুঁকি বিশ্লেষণ আর নথি চায়; বিমানের software-এর জন্য DO-178 পরিবারের নির্দেশিকা (DO-178B, পরে DO-178C) আছে। এগুলোর খুঁটিনাটি দেশ আর নিয়ন্ত্রক সংস্থাভেদে আলাদা।
  • Defence in depth: software ভুল করবেই ধরে নিয়ে hardware interlock, স্বাধীন monitor আর নিরাপদ default রাখা।
  • Concurrency-কে গুরুত্ব: race condition-এর মতো ভুল সাধারণ testing-এ কদাচিৎ দেখা দেয়; তাই নকশায় shared state কমানো, lock, আর formal বা static analysis-এর ব্যবহার বেড়েছে।
  • মানুষ আর যন্ত্রের সংযোগ: দুর্বোধ্য error বার্তা আর “চাপ দিয়ে এগিয়ে যান” অভ্যাস যে ঝুঁকি, তা human factors-এর আলোচনায় স্থায়ী জায়গা পেয়েছে।
  • ঘটনার রিপোর্ট আর শেখা: একটি দুর্ঘটনার তথ্য অন্য ব্যবহারকারী ও নির্মাতার কাছে দ্রুত পৌঁছানোর ব্যবস্থা।

সাধারণ app-এও শিক্ষাগুলো ছোট আকারে খাটে। একটি বিশ্ববিদ্যালয়ের ফলাফল পোর্টালে (কাল্পনিক) দুজন শিক্ষক একই সময়ে একই ছাত্রের নম্বর সম্পাদনা করলে race condition-এ একজনের কাজ হারিয়ে যেতে পারে; একটি পেমেন্ট app-এ “আবার চেষ্টা করুন” বোতাম দুবার টাকা কাটতে পারে। এখানে মৃত্যু নেই, কিন্তু আস্থা আর টাকা আছে। স্পষ্ট error বার্তা, server-এ শেষবার যাচাই, আর “কম্পিউটার তো ভুল করে না” ধারণা বর্জন — সবখানেই কাজে লাগে।

মূল উপলব্ধি: নিরাপত্তা একটি একক বৈশিষ্ট্য নয়, পুরো system আর সংগঠনের বৈশিষ্ট্য। ঝুঁকি যত বড়, তত বেশি স্তর আর তত বেশি স্বাধীন যাচাই।

প্র ০৫AI code assistant কি অবশেষে সেই “silver bullet”? Brooks-এর essential আর accidental জটিলতার ভাষায় বিচার করুন।

Brooks-এর যুক্তির কাঠামো এখানে খুব কাজের। প্রশ্ন হলো, AI কোন জটিলতা কমায়?

  • Accidental জটিলতায় বড় সাহায্য: boilerplate, পরিচিত API-র ব্যবহার, ভাষা থেকে ভাষায় রূপান্তর, error বার্তার ব্যাখ্যা, প্রথম খসড়া test — এগুলোতে AI অনেক সময় বাঁচায়। ঠিক যেমন high-level ভাষা একসময় assembly-র ঝামেলা কমিয়েছিল।
  • Essential জটিলতায় সীমিত: Ariane 5-এর অনুমান, Mars Climate Orbiter-এর interface চুক্তি, Knight Capital-এর deployment প্রক্রিয়া — এগুলো কোড লেখার গতির সমস্যা ছিল না। কোন requirement সত্য, কোন দল কোন একক বোঝে, কোন ঝুঁকি গ্রহণযোগ্য — এসব প্রশ্নের উত্তর প্রতিষ্ঠান আর মানুষের কাছে, training data-য় নয়।
  • নতুন accidental জটিলতা: AI-এর আত্মবিশ্বাসী ভুল ধরতে review-এর খরচ বাড়ে; বেশি কোড দ্রুত তৈরি মানে রক্ষণাবেক্ষণের ভার বাড়তে পারে; license, গোপন তথ্য আর supply-chain-এর নতুন প্রশ্ন আসে।

উৎপাদনশীলতা নিয়ে গবেষণাও এখনো মিশ্র ও প্রাথমিক: কিছু নিয়ন্ত্রিত পরীক্ষায় নির্দিষ্ট কাজ দ্রুত শেষ হয়েছে, আবার কিছু গবেষণায় অভিজ্ঞ উন্নয়নকারীদের বাস্তব project-এ সুবিধা কম বা অস্পষ্ট দেখা গেছে। CHAOS report-এর শিক্ষা মনে রাখুন — এক-দুটি নাটকীয় শতাংশ দেখে উপসংহার টানা ঠিক নয়; কাজের ধরন, মাপার পদ্ধতি আর মান (quality) — সব দেখতে হবে।

Brooks নিজে ১৯৮৬ সালে যেসব “আশার পথ” বলেছিলেন — prototype দিয়ে requirement পরিষ্কার করা, ধাপে ধাপে বাড়ানো, তৈরি জিনিস ব্যবহার — AI এগুলোর প্রতিটিকে দ্রুত করে। তাই হয়তো AI রুপার গুলি নয়, বরং অনেকগুলো ছোট সীসার গুলির একটি শক্তিশালী সংগ্রহ।

মূল উপলব্ধি: যিনি essential জটিলতা বোঝেন — requirement, নকশা, ঝুঁকি, যাচাই — AI তাঁর হাতেই সবচেয়ে কার্যকর। এই কোর্সের বাকি পর্বগুলো ঠিক সেই দক্ষতার জন্য।

অনুশীলন

হিসাব, পূর্বাভাস আর সমালোচনা — খাতা-কলম নিয়ে বসুন।

  1. হিসাব (numerical): (ক) একটি দলে ৬ জন আছেন; আরও ৪ জন যোগ দিলেন। যোগাযোগের পথ কত থেকে কত হলো, কত গুণ? (খ) খেলনা মডেলের মতো প্রতিজন প্রতিটি সহকর্মীর জন্য দিনের ০.০৩ ভাগ সময় হারান। ৪, ৮ আর ১৬ জনের দলের নিট দৈনিক কাজ কত? কত জনে নিট কাজ সর্বোচ্চ? (গ) একটি ফাইলে 120 lbf·s লেখা; N·s-এ কত? (ঘ) 40000 মানটিকে নিচের 16 bit রেখে signed integer বানালে কী হয়?

    (ক) ৬ জনে 6 × 5 / 2 = ১৫টি পথ; ১০ জনে 10 × 9 / 2 = ৪৫টি পথ। মানুষ ১.৬৭ গুণ, পথ ৩ গুণ।

    (খ) নিট কাজ = n × (1 − 0.03 × (n − 1)). n = ৪: 4 × 0.91 = 3.64; n = ৮: 8 × 0.79 = 6.32 (মানুষ দ্বিগুণ, কাজ ১.৭৪ গুণ); n = ১৬: 16 × 0.55 = 8.8. সর্বোচ্চ খুঁজতে f(n) = n − 0.03n(n − 1)-এর ঢাল শূন্য করুন: 1 − 0.03(2n − 1) = 0, অর্থাৎ n ≈ ১৭.২; পূর্ণসংখ্যায় n = ১৭, নিট কাজ 17 × 0.52 = 8.84 (১৮ জনে 8.82, কমতে শুরু)। এর পরে প্রতিটি নতুন মানুষ মোট কাজ কমায় — এই মডেলে, এই অনুমানে।

    (গ) 120 × 4.448222 = 533.787 N·s (তিন দশমিকে)। কেউ একক না দেখে 120-কে N·s ধরলে প্রভাব ধরা হবে আসলের প্রায় ২২%.

    (ঘ) 40000 > 32767, তাই 16 bit-এ ধরে না। 40000 − 65536 = −25536. বড় ধনাত্মক মান চুপচাপ বড় ঋণাত্মক হয়ে গেল — Ariane-ধরনের ভুলের চিহ্ন।

  2. আউটপুট অনুমান করুন (predict the output): চালানোর আগে খাতায় লিখুন নিচের লাইনটি কী ছাপবে, তারপর যেকোনো JavaScript console-এ মিলিয়ে নিন।
    function wrap16(x) { const b = Math.trunc(x) & 0xFFFF; return b > 32767 ? b - 65536 : b; }
    console.log(wrap16(32767), wrap16(32768), wrap16(-1.9), wrap16(65536), wrap16(70000));
    32767 -32768 -1 0 4464

    32767 সীমার ভেতরে, অপরিবর্তিত। 32768-এর নিচের 16 bit = 32768 > 32767, তাই 32768 − 65536 = −32768 — সীমা পেরোনোর ঠিক এক ধাপে সবচেয়ে ছোট মান। −1.9: Math.trunc শূন্যের দিকে কাটে, −1 হয়; −1-এর নিচের 16 bit = 65535, তা থেকে 65536 বাদ = −1. 65536 = 216, নিচের 16 bit সব শূন্য, তাই 0. 70000 − 65536 = 4464 — বড় মান হঠাৎ ছোট ধনাত্মক মান; কোনো সতর্কতা ছাড়াই “বিশ্বাসযোগ্য” দেখায়, এটাই সবচেয়ে বিপজ্জনক।

  3. সমালোচনা (design / critique): একটি বিশ্ববিদ্যালয়ের ফলাফল পোর্টালে (কাল্পনিক) পুরোনো একটি module প্রতিটি বিষয়ের মোট নম্বর এক byte-এর unsigned integer-এ (0–255) রাখে, কারণ পুরোনো নিয়মে সর্বোচ্চ নম্বর ছিল ২০০। নতুন নিয়মে একটি বিষয়ে ৩০০ নম্বর। দল বলছে: “Module-টি দশ বছর ভুল ছাড়া চলেছে, সরাসরি reuse করি।” এই পরিকল্পনার ঝুঁকি আর আপনার প্রস্তাব লিখুন।

    ঝুঁকি: এটি Ariane 5-এর হুবহু ধরন। “দশ বছর ভুল ছাড়া” মানে শুধু পুরোনো প্রেক্ষাপটে (সর্বোচ্চ ২০০) ভুল দেখা দেয়নি। ২৫৬ বা তার বেশি পেলে মান wrap করতে পারে (যেমন ২৮০ হয়ে যায় ২৪) — ভাষাভেদে চুপচাপ ভুল, exception বা সীমায় আটকে যাওয়া। ফলাফলে একজন ভালো ছাত্র অকৃতকার্য দেখাতে পারেন।

    প্রস্তাব: (১) module-এর লুকানো অনুমানগুলো তালিকা করুন (সর্বোচ্চ নম্বর, দশমিক নম্বর আছে কি না, বিষয়ের সংখ্যা) এবং নতুন requirement-এ লিখুন; (২) প্রকার বদলে বড় integer-এ নিন; (৩) সীমার মান — 0, 255, 256, 299, 300, 301 — দিয়ে boundary test লিখুন (পর্ব ৪৭); (৪) সীমা ছাড়ালে নিরাপদ আচরণ ঠিক করুন — চুপচাপ কাটা নয়, error আর মানুষের পর্যালোচনা; (৫) পুরোনো আর নতুন system পাশাপাশি চালিয়ে কিছু আসল (গোপনীয়তা রক্ষা করা) data-য় ফল মিলিয়ে দেখুন।

  4. Postmortem লিখুন: Knight Capital-এর প্রকাশিত তথ্য (অংশ ৭) থেকে পাঁচ লাইনের একটি দোষারোপহীন postmortem লিখুন: কী ঘটেছিল, প্রভাব, মূল কারণগুলো, কোন ব্যবস্থা থাকলে আটকাত, আর তিনটি পদক্ষেপ।

    একটি নমুনা উত্তর (উৎস: SEC-এর প্রকাশিত নথি; খুঁটিনাটি সরলীকৃত):

    1. কী ঘটেছিল: নতুন কোডের deployment আটটি server-এর একটিতে হয়নি; নতুন বার্তায় ব্যবহৃত পুরোনো flag ওই server-এ বহু বছর আগের অব্যবহৃত কোডপথ চালু করল।
    2. প্রভাব: বাজার খোলার পর প্রায় ৪৫ মিনিট অনিয়ন্ত্রিত order; প্রতিষ্ঠানের বিপুল আর্থিক ক্ষতি।
    3. মূল কারণ: হাতে করা deployment, দ্বিতীয় যাচাই না থাকা, flag-এর অর্থ পুনর্ব্যবহার, মুছে না ফেলা dead code, আর জরুরি অবস্থার স্পষ্ট পদ্ধতির অভাব — কোনো একক ব্যক্তির ভুল নয়।
    4. যা আটকাত: স্বয়ংক্রিয় pipeline যা প্রতিটি server-এ version মিলিয়ে দেখে; পুরোনো কোড মোছা; নতুন flag নাম; অস্বাভাবিক আচরণে স্বয়ংক্রিয় kill switch.
    5. পদক্ষেপ: deployment স্বয়ংক্রিয় করা (পর্ব ৫৯), প্রতি মাসে dead code আর পুরোনো flag পরিষ্কার (পর্ব ৪৩), আর একটি লিখিত incident runbook ও মহড়া।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমএই ঘটনাগুলো সময়ের ক্রমে সাজান — আগেরটি ওপরে (▲▼ চেপে সরান)

  1. Garmisch-এ NATO Software Engineering Conference
  2. The Mythical Man-Month প্রকাশ
  3. “No Silver Bullet” প্রবন্ধ
  4. Gang of Four-এর Design Patterns বই
  5. Agile Manifesto লেখা
  6. Ghent-এ প্রথম DevOpsDays

“Software engineering” নামটি জনপ্রিয় করা NATO সম্মেলনটি কোথায় ও কবে হয়েছিল?

  • রোম, ১৯৬৯
  • Garmisch, ১৯৬৮
  • Snowbird, ২০০১
  • Ghent, ২০০৯

একটি project দেরিতে চলছে। ম্যানেজার শেষ মাসে ৬ জনের দলে আরও ৬ জন নতুন developer যোগ করলেন। Brooks’s law অনুযায়ী সবচেয়ে সম্ভাব্য ফল কী?

  • কাজ অর্ধেক সময়ে শেষ হবে
  • সময়ের ওপর কোনো প্রভাব পড়বে না
  • Project সম্ভবত আরও দেরিতে শেষ হবে
  • সময় একই থাকবে, কিন্তু মান নিশ্চিতভাবে ভালো হবে

Ariane 5 Flight 501 (১৯৯৬)-এর ব্যর্থতার সরাসরি কারিগরি কারণ কোনটি?

  • 64-bit float থেকে 16-bit signed integer-এ রূপান্তরে overflow, যার handler ছিল না
  • দুই দলের মধ্যে lbf·s আর N·s এককের অমিল
  • Operator-এর দ্রুত সম্পাদনায় race condition
  • একটি server-এ নতুন কোড deploy না হওয়া

একটি module force × time হিসাব করে খালি সংখ্যা পাঠায় lbf·s-এ, আর গ্রহণকারী module সেটিকে N·s ধরে নেয় (1 lbf·s ≈ 4.448 N·s). গ্রহণকারী আসল impulse-এর প্রায় কত ভাগ ধরবে, আর কোন অভ্যাস এটি সবচেয়ে সরাসরি আটকায়?

  • প্রায় ৪৪৫% — বেশি করে code comment লেখা
  • ১০০% — বেশি RAM ব্যবহার করা
  • প্রায় ৫০% — দ্রুততর CPU
  • প্রায় ২২% — মানের সাথে একক বহন করা typed unit আর interface চুক্তির test

Brooks-এর “No Silver Bullet” (১৯৮৬) অনুযায়ী নিচের কোনটি essential complexity-র উদাহরণ?

  • Assembly-তে হাতে register সামলানো
  • ব্যাংকের সুদ ও জরিমানার জটিল, বারবার বদলানো নিয়ম
  • ধীর compile-এর জন্য অপেক্ষা
  • হাতে memory মুক্ত করার ঝামেলা

একটি trading প্রতিষ্ঠান নতুন কোড আটটি server-এ হাতে বসাল, একটিতে ভুলে বাদ পড়ল। নতুন কোড একটি পুরোনো flag-কে নতুন অর্থে ব্যবহার করে, আর বাদ পড়া server-এ সেই flag বহু বছর আগের অব্যবহৃত কোড চালু করে। কোন অভ্যাসটি এই ধরনের ঘটনা সবচেয়ে সরাসরি আটকায়?

  • কোডে বেশি comment লেখা
  • অন্য programming ভাষায় নতুন করে লেখা
  • স্বয়ংক্রিয় deployment-এ version যাচাই, নতুন flag নাম আর dead code মুছে ফেলা
  • দলে আরও developer নিয়োগ

একজন বক্তা বললেন, “CHAOS report বলছে বেশির ভাগ software project ব্যর্থ হয়, তাই এটি প্রমাণিত সত্য।” সবচেয়ে যুক্তিসংগত প্রতিক্রিয়া কোনটি?

  • এর পদ্ধতি নিয়ে গবেষকদের সমালোচনা আছে; সংজ্ঞা, নমুনা আর বছর না জেনে শতাংশকে প্রমাণিত সত্য ধরা ঠিক নয়
  • বহু বইয়ে উদ্ধৃত, তাই সংখ্যাটি নিশ্চিতভাবে সঠিক
  • Software project আসলে কখনো ব্যর্থ হয় না
  • এটি একটি সরকারি তদন্ত প্রতিবেদন, তাই প্রশ্নের অবকাশ নেই

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. Software crisis (১৯৬০-এর দশকের শেষ): বড় project দেরি, বাজেট-ছাড়া, অনির্ভরযোগ্য; NATO সম্মেলন, Garmisch ১৯৬৮ “software engineering” নামটি জনপ্রিয় করে।
  2. Structured programming: ক্রম, বাছাই, পুনরাবৃত্তি — লক্ষ্য এমন কোড যা পড়ে বোঝা যায়।
  3. Brooks: দেরি হওয়া project-এ লোক দিলে আরও দেরি; পথ n(n−1)/2; conceptual integrity; আর No Silver Bullet — essential জটিলতা কোনো টুলে মেটে না।
  4. চার শিক্ষা: Therac-25 — software-কে একমাত্র পাহারাদার নয়; Ariane 5 — reuse মানে অনুমানও reuse; Mars Climate Orbiter — সংখ্যার সাথে একক; Knight Capital — deployment স্বয়ংক্রিয়, dead code মুছুন।
  5. বিবর্তন: structured → OO → pattern → open source → Agile → DevOps → cloud/CI-CD → AI; আর CHAOS-এর মতো পরিসংখ্যান যাচাই না করে বিশ্বাস নয়।

পরের পর্বে: “ভালো software” বলতে আসলে কী বোঝায়? ISO/IEC 25010-এর quality model, maintainability আর reliability — আর quality কীভাবে মাপা যায়।

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

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান