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

Numerical সমস্যার অনুশীলন — COCOMO, function point, CPM-PERT আর complexity, পূর্ণ সমাধানসহ

Software Engineering Numericals — COCOMO, Function Points, CPM-PERT and Complexity, Fully Solved

Taught in Bangla, this page offers 46 fully solved numericals in seven groups: estimation with function points, COCOMO and velocity; scheduling with CPM, PERT probability, crashing and earned value; risk and quality; design metrics; testing with boundaries, V(G), coverage and mutation; process and flow with Little's law and DORA; and Git counting, plus conventions and a formula sheet.

এই পর্বে যা পাবেন

  • মডিউল ১১-এর পাঁচটি পাতা কীভাবে একসাথে কাজ করে, আর বিশ্ববিদ্যালয়, চাকরির লিখিত পরীক্ষা ও ইন্টারভিউর জন্য আলাদা পড়ার পথ
  • Software engineering-এর প্রতিটি ধরনের numerical-এর সূত্র, নিয়ম আর সাধারণ ফাঁদ — এক জায়গায়, কোর্সের পর্বগুলোর ধ্রুবক আর রীতির সাথে মিলিয়ে
  • CPM-এর forward-backward pass, PERT-এর সম্ভাবনা আর crashing-এর টেবিল এমনভাবে লেখার অভ্যাস, যাতে পরীক্ষক প্রতিটি ধাপ মেলাতে পারেন
  • উল্টো দিকের প্রশ্ন সামলানো: “৬০ person-month-এ কত বড় software?”, “৯৫% নিশ্চয়তার তারিখ কবে?”, “কত মিনিটের MTTR লাগবে?”
  • ছোট প্রোগ্রাম আর আসল Git দিয়ে নিজের উত্তর যাচাই, আর AI-এর দেওয়া হিসাব সন্দেহের চোখে দেখা

১ · মডিউল ১১-এর শুরু — পাঁচটি অনুশীলন পর্ব, এই পাতার নিয়ম আর খাতার কৌশল

মডিউল ১১-এ স্বাগতম। প্রথম ৬৫টি পর্বে আপনি দেখেছেন software কীভাবে পরিকল্পনা, নকশা, test আর release হয়, আর Git দিয়ে একটি দল কীভাবে একসাথে কাজ করে। শেষ পাঁচটি পর্ব নতুন কিছু শেখায় না — সেই জ্ঞান পরীক্ষার খাতায়, MCQ-এর ঘড়ির সামনে আর ইন্টারভিউর টেবিলে কাজে লাগানোর অনুশীলন করায়। বাড়ি বানানো শেষ হলে যেমন রাজমিস্ত্রি নকশার সাথে প্রতিটি দেয়াল মিলিয়ে দেখেন, এই মডিউলও তেমন — প্রতিটি অধ্যায় একবার করে মিলিয়ে দেখা।

পাঁচটি পাতার কাজ আলাদা, তবে একটি অন্যটির পরিপূরক:

পর্বপাতাকী আছেকোন দক্ষতা তৈরি করে
৬৬এই পাতা — NumericalFP, COCOMO, CPM-PERT, earned value, risk, metric, coverage, DORA আর Git-এর গোনাগুনি, পূর্ণ সমাধানসহসূত্র বেছে নেওয়া, নিয়ম ঘোষণা, ধাপে ধাপে হিসাব, উল্টো চেক
৬৭MCQ প্রশ্নব্যাংকপুরো কোর্সের বহুনির্বাচনি প্রশ্ন, মডিউল ধরে, প্রতিটি অপশনের ব্যাখ্যাসহদ্রুত চেনা, ফাঁদের অপশন বাদ দেওয়া, সময় সামলানো
৬৮লিখিত ও মৌখিক প্রশ্নProcess, requirement, design, testing আর management-এর বর্ণনামূলক প্রশ্ন আর ভাইভার উত্তরের কাঠামোসংজ্ঞা, তুলনা, ছবি আঁকা আর গুছিয়ে লেখা
৬৯Git ইন্টারভিউGit-এর ধারণা, পরিস্থিতিভিত্তিক সমস্যা আর command-এর অনুশীলন“এখন কী করবেন” ধরনের প্রশ্নে নিরাপদ, যাচাই করা উত্তর
৭০Software engineering ইন্টারভিউSOLID, design pattern, testing, code review আর আচরণগত প্রশ্ননকশার যুক্তি মুখে বলা, অভিজ্ঞতার গল্প সাজানো

কোন পরীক্ষার জন্য কোন পথে

🎓 বিশ্ববিদ্যালয়ের লিখিত পরীক্ষা

Software Engineering বা Software Project Management কোর্সে numerical প্রায় নিশ্চিত নম্বর। প্রথমে এই পাতার ভাগ ২ আর ৩ (COCOMO, FP, CPM-PERT) — এগুলো খাতায় পুরো লিখে অনুশীলন করুন; তারপর ভাগ ৬ (testing-এর গোনা); তারপর পর্ব ৬৮-এর বর্ণনামূলক উত্তর; শেষে পর্ব ৬৭ দিয়ে নিজেকে যাচাই।

📝 চাকরির লিখিত পরীক্ষা

IT অফিসার বা assistant programmer পদের লিখিত পরীক্ষায় software engineering অংশ প্রায়ই ছোট থাকে — MCQ আর এক-দুই লাইনের হিসাব। তাই আগে পর্ব ৬৭, তারপর এই পাতার ছোট অঙ্কগুলো (VAF, cost slope, V(G), RE, DRE, MTBF, n(n − ১) ÷ ২), যেগুলো দুই মিনিটে করা যায়।

💼 Developer ইন্টারভিউ

ইন্টারভিউতে COCOMO খুব কমই আসে, কিন্তু DORA metric, Little-এর সূত্র, bisect-এর ধাপ, A..B-তে কয়টি commit, coverage বনাম mutation score — এগুলো আলোচনায় আসতেই পারে। পর্ব ৬৯ আর পর্ব ৭০ মূল প্রস্তুতি; এই পাতার ভাগ ৭ আর ৮ সাথে রাখুন।

কোন ভাগে কী, কোন পর্ব ঝালাবেন

ভাগকী আছেমূল পর্ব
২Function point (UFP, VAF, AFP), Basic ও Intermediate COCOMO, COCOMO II, তিন-বিন্দু অনুমান, velocity থেকে পরিসর০৫, ৬০
৩CPM-এর forward-backward pass, float, critical path, PERT-এর Z আর সম্ভাবনা, crashing, earned value৬১
৪Risk exposure, RRL, EMV-এর decision tree, MTBF-MTTR আর availability, defect density, DRE, control chart০৩, ০৪, ৬২
৫Ca, Ce, instability, abstractness, distance, LCOM4, যোগাযোগের পথ, bus factor২৫, ৬০, ৬৩
৬Equivalence class আর boundary value-এর সংখ্যা, decision table, pairwise, V(G) তিনভাবে, statement-branch-MC/DC-এর ন্যূনতম test, mutation score, exhaustive test৪৫, ৪৭, ৫০
৭Little-এর সূত্র, flow efficiency, percentile forecast, DORA, Kano, RICE আর WSJF০৬, ২৪, ৫৯
৮Bisect-এর ⌈log2 n⌉, A..B range-এ কোন commit, ahead/behind০৯, ১৪, ১৫, ৫৫

এই পাতার নিয়ম (convention) — প্রশ্নে অন্য কিছু না বললে

বিষয়নিয়ম
Function pointIFPUG-ধাঁচের weight: EI 3/4/6, EO 4/5/7, EQ 3/4/6, ILF 7/10/15, EIF 5/7/10 (low/avg/high); VAF = 0.65 + 0.01 × ΣGSC, ১৪টি GSC প্রতিটি ০–৫ (পর্ব ৬০)
COCOMO 81Basic: organic 2.4/1.05/0.38, semi-detached 3.0/1.12/0.35, embedded 3.6/1.20/0.32 (a/b/d), c = 2.5. Intermediate-এ a বদলে 3.2/3.0/2.8, b আর d একই, সাথে EAF
COCOMO II.2000A = 2.94, B = 0.91, C = 3.67, D = 0.28; PM = A × SizeE × ΠEM, E = B + 0.01 × ΣSF, TDEV = C × PMF, F = D + 0.2 × (E − B)
CPMActivity-on-node; দিন ০ থেকে শুরু, তাই ES = পূর্বসূরিদের EF-এর সর্বোচ্চ, EF = ES + সময়; TF = LS − ES, FF = উত্তরসূরিদের সর্বনিম্ন ES − EF (পর্ব ৬১)
PERTte = (a + 4m + b) ÷ ৬, σ² = ((b − a) ÷ ৬)²; activity-গুলো স্বাধীন, তাই পথের variance যোগ হয়, σ নয়; Φ(z) = ½(১ + erf(z/√২)), টেবিল থেকে পড়লে দুই দশমিকে গোল করা Z
Earned valueSV = EV − PV, CV = EV − AC, SPI = EV ÷ PV, CPI = EV ÷ AC; EAC-এর মূল রূপ BAC ÷ CPI; ঋণাত্মক বা ১-এর কম = খারাপ
ReliabilityMTBF মানে দুটি failure-এর মাঝে চলার গড় সময় (মেরামত বাদ), তাই A = MTBF ÷ (MTBF + MTTR); বছর = ৮৭৬০ ঘণ্টা (পর্ব ০৩)
Control chartকেন্দ্র = গড়, সীমা = গড় ± ৩σ, σ নমুনার (n − ১ দিয়ে ভাগ); LCL ঋণাত্মক হলে ০ (পর্ব ৬২)
Package metricCa আর Ce গোনা হয় package ধরে (class নয়); Ca + Ce = ০ হলে I = ০; D = |A + I − ১|, D ≥ ০.৫ হলে zone of pain বা uselessness (পর্ব ২৫)
BVAISTQB-এর ২-মান (সীমা + অন্য পাশের নিকটতম মান) আর ৩-মান (সীমা + দুই পাশের প্রতিবেশী); integer ইনপুট (পর্ব ৪৭)
Percentile ও medianNearest-rank: সাজানো তালিকার ⌈q × n⌉-তম মান — DORA-র median-ও এভাবে (পর্ব ০৬, ৫৯)
Bisectn = সন্দেহভাজন commit (জানা ভালো commit বাদ, জানা খারাপটি সহ); skip না থাকলে ⌈log2 n⌉টি পরীক্ষা (পর্ব ৫৫)
পরীক্ষার কৌশল — খাতায় উত্তর সাজানোর ছয় নিয়ম

১. দেওয়া তথ্য আর একক এক লাইনে। “Size = 50 KLOC, mode = organic, effort person-month-এ, সময় মাসে” — এক লাইনেই অর্ধেক কাজ, আর KLOC বনাম LOC-এর ভুল সেখানেই ধরা পড়ে।

২. নিয়ম ঘোষণা করুন। “ধরে নিলাম COCOMO 81-এর Basic রূপ; activity-গুলো স্বাধীন; দিন ০ থেকে শুরু।” প্রশ্নে স্পষ্ট না থাকলে এটাই আপনার রক্ষাকবচ — পরীক্ষক অন্য নিয়ম ধরলেও যুক্তি দেখে নম্বর দেন।

৩. সূত্র আগে, মান পরে। “E = a × KLOCb” লিখে তারপর সংখ্যা বসান। গণনায় ভুল হলেও সূত্রের নম্বর থাকে।

৪. টেবিলে উত্তর দিন। FP-এর পাঁচ সারি, CPM-এর ES-EF-LS-LF-TF, crashing-এর ধাপ, decision table, MC/DC-এর জোড়া — সবই টেবিলের অঙ্ক। কলামের নাম আগে লিখুন।

৫. একটি sanity check দিন। VAF ০.৬৫–১.৩৫-এর মধ্যে? Critical path-এর দৈর্ঘ্য = project-এর সময়? সম্ভাবনা ০ আর ১-এর মধ্যে? V(G) তিন পদ্ধতিতে একই? এক লাইনের এই চেক অনেক ভুল ধরে।

৬. শেষ উত্তর আলাদা করুন, এক লাইনের মন্তব্যসহ। “E ≈ ১৪৫.৯ PM; দল গড়ে ৯ জন — মানে ১৭ মাসের project” — তুলনা বা সিদ্ধান্তের প্রশ্নে এই এক লাইন প্রায়ই পূর্ণ নম্বর আনে।

২ · Estimation — function point, COCOMO 81, COCOMO II আর velocity

ঝালিয়ে নিন: পর্ব ৬০ · Software estimation (FP, COCOMO, three-point), পর্ব ০৫ · Agile আর Scrum (velocity আর forecast).

সূত্রের কার্ড

Function point: UFP = Σ (সংখ্যা × weight); VAF = 0.65 + 0.01 × ΣGSC (০.৬৫–১.৩৫); AFP = UFP × VAF. Backfiring: KLOC ≈ AFP × (LOC/FP) ÷ ১০০০ — মোটা দাগের অনুমান।

COCOMO 81: E = a × KLOCb person-month, D = 2.5 × Ed মাস, দল = E ÷ D; Intermediate-এ E গুণ EAF (১৫টি cost driver-এর গুণফল)।

COCOMO II: E = 0.91 + 0.01 × ΣSF; PM = 2.94 × SizeE × ΠEM; F = 0.28 + 0.2 × (E − 0.91); TDEV = 3.67 × PMF.

তিন-বিন্দু অনুমান: te = (O + 4M + P) ÷ ৬, σ = (P − O) ÷ ৬; কয়েকটি কাজ যোগে variance যোগ। Velocity: সেরা = ⌈কম backlog ÷ সর্বোচ্চ velocity⌉, খারাপ = ⌈বেশি backlog ÷ সর্বনিম্ন velocity⌉.

Function point

২.১(সহজ) একটি কাল্পনিক পাড়ার লাইব্রেরি অ্যাপে ৫টি EI, ৪টি EO, ৩টি EQ, ২টি ILF আর ১টি EIF — সবগুলোর জটিলতা average. ১৪টি GSC-র যোগফল ৪২. UFP, VAF আর AFP কত? (ঝালিয়ে নিন: পর্ব ৬০)
average weights: EI 4, EO 5, EQ 4, ILF 10, EIF 7
UFP = 5x4 + 4x5 + 3x4 + 2x10 + 1x7 = 20 + 20 + 12 + 20 + 7 = 79
VAF = 0.65 + 0.01 x 42 = 1.07
AFP = 79 x 1.07 = 84.53

Sanity check: VAF ০.৬৫ আর ১.৩৫-এর মধ্যে, আর ΣGSC ৩৫-এর বেশি বলে VAF ১-এর একটু বেশি — আকার ৭% বাড়ল। সবচেয়ে সাধারণ ভুল EQ-কে EO-র weight (৫) দেওয়া; EQ কোনো হিসাব ছাড়া হুবহু ফেরত দেয়, তাই তার weight কম। UFP = ৭৯, VAF = ১.০৭, AFP ≈ ৮৪.৫৩.

২.২(মাঝারি) একটি কাল্পনিক ক্লিনিকের appointment অ্যাপ: EI — low ৩, average ২, high ২; EO — low ১, average ২, high ১; EQ — low ২, average ১; ILF — average ৩, high ১; EIF — low ২. ১৪টি GSC-র দশটির রেটিং ৩, চারটির ৫. ভাষার জন্য ধরা হলো ৫০ LOC/FP (একটি অনুমান, মানদণ্ড নয়)। UFP, AFP আর আনুমানিক KLOC কত?
EI : 3x3 + 2x4 + 2x6  = 9 + 8 + 12  = 29
EO : 1x4 + 2x5 + 1x7  = 4 + 10 + 7  = 21
EQ : 2x3 + 1x4 + 0x6  = 6 + 4       = 10
ILF: 0x7 + 3x10 + 1x15 = 30 + 15    = 45
EIF: 2x5 + 0x7 + 0x10 = 10          = 10
UFP = 29 + 21 + 10 + 45 + 10 = 115
sum GSC = 10x3 + 4x5 = 50  ->  VAF = 0.65 + 0.50 = 1.15
AFP = 115 x 1.15 = 132.25   ->   size ~ 132.25 x 50 / 1000 = 6.61 KLOC

খেয়াল করুন, ILF একাই ৪৫ — মোটের প্রায় ৩৯%. Data function-এর weight বেশি, কারণ ফাইল রক্ষণাবেক্ষণে কাজ বেশি। Sanity check: ΣGSC ৫০ ≤ ৭০ আর VAF ১.১৫ ≤ ১.৩৫. Backfiring-এর ফল (৬.৬১ KLOC) খুব মোটা দাগের — ভাষা আর দলভেদে LOC/FP অনেক বদলায়। UFP = ১১৫, AFP ≈ ১৩২.২৫, আকার প্রায় ৬.৬ KLOC.

# Function point calculator (IFPUG-style weights, VAF = 0.65 + 0.01 x sum of 14 GSC).
WEIGHTS = {"EI": (3, 4, 6), "EO": (4, 5, 7), "EQ": (3, 4, 6),
           "ILF": (7, 10, 15), "EIF": (5, 7, 10)}          # low, average, high

def function_points(counts, gsc_sum, loc_per_fp=None):
    ufp = 0
    for kind, (lo, av, hi) in counts.items():
        w = WEIGHTS[kind]
        sub = lo * w[0] + av * w[1] + hi * w[2]
        ufp += sub
        print(f"  {kind:3}: {lo}x{w[0]} + {av}x{w[1]} + {hi}x{w[2]} = {sub}")
    assert 0 <= gsc_sum <= 70, "14 GSC ratings, each 0..5"
    vaf = 0.65 + 0.01 * gsc_sum
    afp = ufp * vaf
    print(f"  UFP = {ufp}, VAF = 0.65 + 0.01 x {gsc_sum} = {vaf:.2f}, AFP = {afp:.2f}")
    if loc_per_fp:                                          # backfiring (rough!)
        print(f"  size ~ {afp:.2f} x {loc_per_fp} LOC/FP = {afp * loc_per_fp / 1000:.2f} KLOC")
    return afp

print("2.1 library app (all average)")
function_points({"EI": (0, 5, 0), "EO": (0, 4, 0), "EQ": (0, 3, 0),
                 "ILF": (0, 2, 0), "EIF": (0, 1, 0)}, 42)
print("2.2 clinic app (mixed complexity)")
function_points({"EI": (3, 2, 2), "EO": (1, 2, 1), "EQ": (2, 1, 0),
                 "ILF": (0, 3, 1), "EIF": (2, 0, 0)}, 10 * 3 + 4 * 5, loc_per_fp=50)

আউটপুট:

2.1 library app (all average)
  EI : 0x3 + 5x4 + 0x6 = 20
  EO : 0x4 + 4x5 + 0x7 = 20
  EQ : 0x3 + 3x4 + 0x6 = 12
  ILF: 0x7 + 2x10 + 0x15 = 20
  EIF: 0x5 + 1x7 + 0x10 = 7
  UFP = 79, VAF = 0.65 + 0.01 x 42 = 1.07, AFP = 84.53
2.2 clinic app (mixed complexity)
  EI : 3x3 + 2x4 + 2x6 = 29
  EO : 1x4 + 2x5 + 1x7 = 21
  EQ : 2x3 + 1x4 + 0x6 = 10
  ILF: 0x7 + 3x10 + 1x15 = 45
  EIF: 2x5 + 0x7 + 0x10 = 10
  UFP = 115, VAF = 0.65 + 0.01 x 50 = 1.15, AFP = 132.25
  size ~ 132.25 x 50 LOC/FP = 6.61 KLOC

দুটি লাইনই ২.১ আর ২.২-এর হাতের হিসাবের সাথে হুবহু মেলে: ৭৯ → ৮৪.৫৩, আর ১১৫ → ১৩২.২৫ → ৬.৬১ KLOC. assert লাইনটি একটি sanity check — ১৪টি GSC-র যোগফল ০ থেকে ৭০-এর বাইরে গেলে প্রোগ্রাম থেমে যাবে। নিজের বইয়ের অঙ্ক বসাতে counts-এর পাঁচটি tuple (low, average, high) আর GSC-র যোগফল বদলান।

COCOMO 81 আর COCOMO II

২.৩(সহজ) ১০ KLOC-এর একটি organic project. Basic COCOMO দিয়ে effort, সময় আর গড় দলের আকার বের করুন।
organic: a = 2.4, b = 1.05, c = 2.5, d = 0.38
10^1.05 = 11.22
E = 2.4 x 11.22 = 26.9 person-months
D = 2.5 x 26.9^0.38 = 2.5 x 3.50 = 8.7 months
team = 26.9 / 8.7 = 3.1 people     (productivity 10000 / 26.9 = 371 LOC/PM)

Sanity check: E ≈ ২৭ PM মানে একজন মানুষের সোয়া দুই বছর; তিনজনে প্রায় নয় মাস — বাস্তবসম্মত। ক্যালকুলেটরে xy না থাকলে log দিয়ে: ১০১.০৫ = e১.০৫ × ln ১০. E ≈ ২৬.৯ PM, D ≈ ৮.৭ মাস, দল প্রায় ৩ জন।

২.৪(মাঝারি) একই ৫০ KLOC-এর project তিনটি mode-এ (organic, semi-detached, embedded) Basic COCOMO দিয়ে তুলনা করুন। কোন সংখ্যা সবচেয়ে বেশি বদলায়, কোনটি প্রায় একই থাকে?
mode           E (PM)   D (months)   team   LOC/PM
organic         145.9      16.6        8.8     343
semi-detached   239.9      17.0       14.1     208
embedded        393.6      16.9       23.3     127

Effort প্রায় ২.৭ গুণ বাড়ে (১৪৫.৯ থেকে ৩৯৩.৬), কিন্তু সময় প্রায় একই (১৬.৬–১৭.০ মাস) — বাড়তি কাজ আসে বড় দল থেকে। কারণ সময়ের exponent d ছোট আর mode-ভেদে কমে (০.৩৮ → ০.৩২); তাই embedded-এর সময় (১৬.৯) semi-detached-এর (১৭.০) চেয়ে সামান্য কমও আসে। উৎপাদনশীলতা ৩৪৩ থেকে ১২৭ লাইনে নামে — কঠোর শর্তে প্রতিটি লাইনের পেছনে বেশি যাচাই। Effort আর দল সবচেয়ে বেশি বদলায়; সময় প্রায় স্থির।

২.৫(মাঝারি) ৪০ KLOC-এর semi-detached project, Intermediate COCOMO. Cost driver: RELY very high (১.৪০), DATA high (১.০৮), ACAP high (০.৮৬), TOOL low (১.১০); বাকি ১১টি nominal (১.০০)। EAF, effort আর সময় কত?
EAF = 1.40 x 1.08 x 0.86 x 1.10 = 1.4304
Intermediate semi-detached: a = 3.0, b = 1.12, d = 0.35
40^1.12 = 62.27 ;  nominal E = 3.0 x 62.27 = 186.8 PM
E = 186.8 x 1.4304 = 267.2 PM
D = 2.5 x 267.2^0.35 = 2.5 x 7.07 = 17.7 months ;  team = 15.1

Semi-detached-এ Intermediate-এর a (৩.০) Basic-এর মতোই; organic (৩.২) আর embedded (২.৮)-এ আলাদা — এটি পরীক্ষার প্রিয় ফাঁদ। দক্ষ analyst (০.৮৬) effort কমালেও খুব উঁচু নির্ভরযোগ্যতা আর দুর্বল tool মিলে মোট ৪৩% বাড়িয়েছে। Sanity check: EAF ১-এর বেশি, তাই E nominal-এর চেয়ে বেশি হওয়ারই কথা। EAF ≈ ১.৪৩০, E ≈ ২৬৭.২ PM, D ≈ ১৭.৭ মাস।

২.৬(কঠিন) COCOMO II.2000, আকার ৫০ KSLOC. Scale factor: PREC high (২.৪৮), FLEX nominal (৩.০৪), RESL high (২.৮৩), TEAM very high (১.১০), PMAT nominal (৪.৬৮)। Effort multiplier: RELY high (১.১০), CPLX high (১.১৭), PCAP high (০.৮৮), TOOL high (০.৯০); বাকি ১৩টি ১.০০. Exponent, PM, TDEV আর দল কত? আকার দ্বিগুণ হলে PM কত গুণ হবে?
sum SF = 2.48 + 3.04 + 2.83 + 1.10 + 4.68 = 14.13
E   = 0.91 + 0.01 x 14.13 = 1.0513
Pi EM = 1.10 x 1.17 x 0.88 x 0.90 = 1.0193
50^1.0513 = 61.11
PM  = 2.94 x 61.11 x 1.0193 = 183.1 person-months
F   = 0.28 + 0.2 x (1.0513 - 0.91) = 0.3083
TDEV = 3.67 x 183.1^0.3083 = 3.67 x 4.98 = 18.3 months ;  team = 10.0
doubling the size: PM x 2^1.0513 = x 2.072

সব scale factor nominal হলে ΣSF হতো ১৮.৯৭ আর E ≈ ১.১০; এখানে অভিজ্ঞতা, দলের সমন্বয় আর আগেভাগে ঝুঁকি মীমাংসা exponent কমিয়ে ১.০৫-এ এনেছে। দ্বিগুণ আকারে PM ২.০৭২ গুণ — দ্বিগুণের সামান্য বেশি, অর্থাৎ diseconomy of scale এখনো আছে, তবে কম। সাধারণ ভুল: scale factor-কে EM-এর মতো গুণ করা — SF বসে exponent-এ, EM বসে গুণফলে। E = ১.০৫১৩, PM ≈ ১৮৩.১, TDEV ≈ ১৮.৩ মাস, দল প্রায় ১০ জন।

২.৭(কঠিন) উল্টো প্রশ্ন: একটি organic project-এর বাজেট সর্বোচ্চ ৬০ person-month. Basic COCOMO অনুযায়ী সর্বোচ্চ কত KLOC-এর software এই বাজেটে বানানো যায়, আর nominal সময় কত?
E = 2.4 x KLOC^1.05   ->   KLOC = (E / 2.4)^(1 / 1.05)
KLOC = (60 / 2.4)^(0.9524) = 25^0.9524 = 21.45
check: 2.4 x 21.45^1.05 = 60.0 PM
D = 2.5 x 60^0.38 = 11.8 months

উল্টো প্রশ্নে ঘাতকে উল্টাতে হয়: ১ ÷ ১.০৫ ≈ ০.৯৫২৪. Sanity check: ৬০ ÷ ২.৪ = ২৫, আর exponent ১-এর একটু কম বলে উত্তর ২৫-এর একটু কম — মেলে। উত্তর বসিয়ে আবার effort বের করা (৬০.০) সবচেয়ে ভালো উল্টো চেক। প্রায় ২১.৪৫ KLOC, সময় প্রায় ১১.৮ মাস।

// COCOMO 81 (Basic + Intermediate) and COCOMO II.2000 in one calculator.
const BASIC = { organic: [2.4, 1.05, 0.38], semidetached: [3.0, 1.12, 0.35], embedded: [3.6, 1.20, 0.32] };
const INTER_A = { organic: 3.2, semidetached: 3.0, embedded: 2.8 };      // same b and d as Basic
const prod = xs => xs.reduce((p, x) => p * x, 1);
function cocomo81(kloc, mode, eaf = 1, intermediate = false) {
  const [a, b, d] = BASIC[mode];
  const E = (intermediate ? INTER_A[mode] : a) * kloc ** b * eaf;  // person-months
  const D = 2.5 * E ** d;                                           // months
  return `E=${E.toFixed(1)} PM  D=${D.toFixed(1)} mo  team=${(E / D).toFixed(1)}  LOC/PM=${(kloc * 1000 / E).toFixed(0)}`;
}
function cocomo2(ksloc, sf, em) {
  const E = 0.91 + 0.01 * sf.reduce((s, x) => s + x, 0);
  const PM = 2.94 * ksloc ** E * prod(em);
  const F = 0.28 + 0.2 * (E - 0.91);
  const T = 3.67 * PM ** F;
  return `E=${E.toFixed(4)} PiEM=${prod(em).toFixed(4)} PM=${PM.toFixed(1)} F=${F.toFixed(4)} TDEV=${T.toFixed(1)} team=${(PM / T).toFixed(1)}`;
}
console.log("2.3 organic 10 KLOC:", cocomo81(10, "organic"));
for (const m of Object.keys(BASIC)) console.log("2.4 " + m.padEnd(12) + " 50 KLOC:", cocomo81(50, m));
const eaf = prod([1.40, 1.08, 0.86, 1.10]);             // RELY VH, DATA H, ACAP H, TOOL L
console.log("2.5 EAF =", eaf.toFixed(4), "->", cocomo81(40, "semidetached", eaf, true));
// scale factors PREC H, FLEX N, RESL H, TEAM VH, PMAT N; EMs RELY H, CPLX H, PCAP H, TOOL H
console.log("2.6", cocomo2(50, [2.48, 3.04, 2.83, 1.10, 4.68], [1.10, 1.17, 0.88, 0.90]));
console.log("2.6 doubling size multiplies PM by 2^E =", (2 ** 1.0513).toFixed(3));
const k = (60 / 2.4) ** (1 / 1.05);                     // inverse: organic, 60 PM budget
console.log("2.7 max size for 60 PM:", k.toFixed(2), "KLOC; D =", (2.5 * 60 ** 0.38).toFixed(1), "months");

আউটপুট:

2.3 organic 10 KLOC: E=26.9 PM  D=8.7 mo  team=3.1  LOC/PM=371
2.4 organic      50 KLOC: E=145.9 PM  D=16.6 mo  team=8.8  LOC/PM=343
2.4 semidetached 50 KLOC: E=239.9 PM  D=17.0 mo  team=14.1  LOC/PM=208
2.4 embedded     50 KLOC: E=393.6 PM  D=16.9 mo  team=23.3  LOC/PM=127
2.5 EAF = 1.4304 -> E=267.2 PM  D=17.7 mo  team=15.1  LOC/PM=150
2.6 E=1.0513 PiEM=1.0193 PM=183.1 F=0.3083 TDEV=18.3 team=10.0
2.6 doubling size multiplies PM by 2^E = 2.072
2.7 max size for 60 PM: 21.45 KLOC; D = 11.8 months

প্রথম লাইন ২.৩ (২৬.৯ PM, ৮.৭ মাস), পরের তিন লাইন ২.৪-এর টেবিল, তারপর ২.৫-এর EAF ১.৪৩০৪ আর ২৬৭.২ PM, ২.৬-এর COCOMO II (E = ১.০৫১৩, PM ১৮৩.১, TDEV ১৮.৩) আর ২.০৭২ গুণ, শেষে ২.৭-এর উল্টো প্রশ্ন (২১.৪৫ KLOC). intermediate চিহ্ন দিলে a বদলে INTER_A থেকে আসে — Basic আর Intermediate-এর একমাত্র পার্থক্য সেখানেই, b আর d একই।

তিন-বিন্দু অনুমান আর velocity

২.৮(সহজ) চারটি স্বাধীন কাজের (O, M, P) দিনে: login (২, ৪, ৮), search (৩, ৫, ৯), payment (৪, ৭, ১৬), report (১, ২, ৩)। প্রতিটির te আর σ, মোট প্রত্যাশিত সময় আর মোট σ বের করুন।
task      te = (O + 4M + P)/6        sigma = (P - O)/6   variance
login     (2 + 16 + 8)/6  = 4.33      1.00               1.00
search    (3 + 20 + 9)/6  = 5.33      1.00               1.00
payment   (4 + 28 + 16)/6 = 8.00      2.00               4.00
report    (1 + 8 + 3)/6   = 2.00      0.33               0.11
total mean = 19.67 days ; total variance = 6.11 ; total sigma = sqrt(6.11) = 2.47

ফাঁদ: σ-গুলো সরাসরি যোগ করলে ৪.৩৩ আসে — ভুল। স্বাধীন কাজে variance যোগ হয়, তারপর বর্গমূল। payment-এর গড় (৮) M (৭)-এর চেয়ে বেশি, কারণ দেরির দিকের লেজ লম্বা। Normal ধরে মোটামুটি ৮৪% সম্ভাবনায় ১৯.৬৭ + ২.৪৭ ≈ ২২.১ দিনের মধ্যে — সেই হিসাবের পূর্ণ রূপ ভাগ ৩-এ। মোট ≈ ১৯.৬৭ দিন, σ ≈ ২.৪৭ দিন।

২.৯(মাঝারি) একটি দলের শেষ পাঁচটি Sprint-এর velocity: ২১, ১৮, ২৪, ১৯, ২৩ point. বাকি backlog ১৬০ থেকে ১৯০ point-এর মধ্যে, Sprint দুই সপ্তাহের। কত Sprint আর কত সপ্তাহ লাগবে — একটি পরিসর হিসেবে বলুন।
average velocity = (21 + 18 + 24 + 19 + 23) / 5 = 105 / 5 = 21
best  = ceil(160 / 24) = ceil(6.67)  = 7 sprints
mid   = ceil(175 / 21) = ceil(8.33)  = 9 sprints
worst = ceil(190 / 18) = ceil(10.56) = 11 sprints
range: 7 to 11 sprints = 14 to 22 weeks

Sprint অর্ধেক হয় না, তাই প্রতিটিতে ওপরের দিকে গোল (⌈ ⌉)। সেরা ক্ষেত্রে সবচেয়ে কম কাজ ভাগ সর্বোচ্চ velocity, খারাপ ক্ষেত্রে সবচেয়ে বেশি কাজ ভাগ সর্বনিম্ন velocity — পর্ব ০৫-এর নিয়মেই। একটি সংখ্যা (৯) না বলে পরিসর বলাই সৎ forecast. ৭ থেকে ১১ Sprint, অর্থাৎ ১৪ থেকে ২২ সপ্তাহ; মাঝামাঝি অনুমান ৯ Sprint.

(সহজ) Function point গণনায় ১৪টি general system characteristic-এর রেটিংয়ের যোগফল ৫৫ হলে VAF কত?

  • 1.55
  • 1.20
  • 0.55
  • 1.35

(মাঝারি) Basic COCOMO-তে ২০ KLOC-এর একটি organic project-এর effort প্রায় কত? (a = 2.4, b = 1.05)

  • 48.0 PM
  • 86.0 PM
  • 11.5 PM
  • 55.8 PM

(সহজ) COCOMO II.2000-এ পাঁচটি scale factor-এর যোগফল ২০ হলে size exponent E কত?

  • 1.11
  • 1.20
  • 0.91
  • 1.0997

(সহজ) একটি কাজের তিন-বিন্দু অনুমান: O = ৪, M = ৬, P = ১৪ দিন। PERT-এর প্রত্যাশিত সময় আর standard deviation কত?

  • 6 দিন, σ = 1.67
  • 8 দিন, σ = 3.33
  • 7 দিন, σ = 1.67
  • 7 দিন, σ = 2.78

৩ · Scheduling — CPM, PERT-এর সম্ভাবনা, crashing আর earned value

ঝালিয়ে নিন: পর্ব ৬১ · Project planning (CPM, PERT, crashing, earned value), পর্ব ৬০ (তিন-বিন্দু অনুমান)।

সূত্রের কার্ড

CPM: forward pass-এ ES = max(পূর্বসূরির EF), EF = ES + সময়; backward pass-এ LF = min(উত্তরসূরির LS), LS = LF − সময়। TF = LS − ES; FF = min(উত্তরসূরির ES) − EF. TF = ০-এর শিকল = critical path.

PERT: μ = পথের Σte, σ = √(পথের Σσ²); Z = (T − μ) ÷ σ, P(≤ T) = Φ(Z); উল্টো প্রশ্নে T = μ + Z × σ (৯০% → Z ≈ ১.২৮২, ৯৫% → ১.৬৪৫, ৯৯% → ২.৩২৬)।

Crashing: cost slope = (crash খরচ − normal খরচ) ÷ (normal সময় − crash সময়); প্রতিবার সব critical path কাটে এমন সবচেয়ে সস্তা activity-সেট এক দিন কমান; slope দৈনিক পরোক্ষ খরচের চেয়ে বেশি হলে থামুন।

Earned value: SV = EV − PV, CV = EV − AC, SPI = EV ÷ PV, CPI = EV ÷ AC, EAC = BAC ÷ CPI, ETC = EAC − AC, VAC = BAC − EAC.

একটি পূর্ণ CPM + PERT উত্তর

একটি কাল্পনিক পাড়ার লাইব্রেরি অ্যাপের আটটি activity (দিনে)। প্রতিটির সময় CPM-এর জন্য, আর বন্ধনীতে (a, m, b) PERT-এর জন্য — এমনভাবে নেওয়া যে te ঠিক CPM-এর সময়ের সমান: A requirement ৩ (২, ৩, ৪) · B API ৫, A-র পরে (৩, ৫, ৭) · C UI নকশা ৪, A-র পরে (২, ৪, ৬) · D database ৬, B-র পরে (৩, ৬, ৯) · E login ৩, B আর C-র পরে (১, ৩, ৫) · F UI কোড ৫, C-র পরে (৩, ৫, ৭) · G integration ৪, D আর E-র পরে (২, ৩, ১০) · H test ও release ২, F আর G-র পরে (১, ২, ৩)।

লাইব্রেরি অ্যাপের AON network — critical path লাল

Each box: ES · duration · EF on top, LS · float · LF below

লাইব্রেরি অ্যাপের AON network — critical path A-B-D-G-H, ২০ দিন ০৩ দিন৩A · চাহিদা০F ০৩ ৩৫ দিন৮B · API৩F ০৮ ৩৪ দিন৭C · UI নকশা৭F ৪১১ ৮৬ দিন১৪D · database৮F ০১৪ ৮৩ দিন১১E · login১১F ৩১৪ ৭৫ দিন১২F · UI কোড১৩F ৬১৮ ১৪৪ দিন১৮G · মেলানো১৪F ০১৮ ১৮২ দিন২০H · release১৮F ০২০
ছবি ৬৬.১ — প্রতিটি বাক্সে ওপরে ES, সময়, EF; নিচে LS, float (F), LF. Critical path A → B → D → G → H, মোট ২০ দিন। C-এর total float ৪ কিন্তু free float ০; E-এর float ৩, F-এর ৬.
ধাপ ১দেওয়া তথ্য আর নিয়ম
act  dur  pred   (a, m, b)
 A    3    -     (2, 3, 4)
 B    5    A     (3, 5, 7)
 C    4    A     (2, 4, 6)
 D    6    B     (3, 6, 9)
 E    3    B,C   (1, 3, 5)
 F    5    C     (3, 5, 7)
 G    4    D,E   (2, 3, 10)
 H    2    F,G   (1, 2, 3)
AON · day 0 · independent tasks
ধাপ ২forward pass
A: ES 0                   EF 3
B: ES 3                   EF 8
C: ES 3                   EF 7
D: ES 8                   EF 14
E: ES max(8, 7)  = 8      EF 11
F: ES 7                   EF 12
G: ES max(14, 11) = 14    EF 18
H: ES max(12, 18) = 18    EF 20
project duration T = 20 days
ধাপ ৩backward pass
H: LF 20                   LS 18
G: LF 18                   LS 14
F: LF 18                   LS 13
E: LF 14                   LS 11
D: LF 14                   LS 8
C: LF min(11, 13) = 11     LS 7
B: LF min(8, 11)  = 8      LS 3
A: LF min(3, 7)   = 3      LS 0
ধাপ ৪float আর critical path
act  TF   FF = min ES(succ) - EF
 A    0    0
 B    0    0
 C    4    min(8, 7) - 7 = 0
 D    0    0
 E    3    14 - 11 = 3
 F    6    18 - 12 = 6
 G    0    0
 H    0    0
CP: A-B-D-G-H = 3+5+6+4+2 = 20
ধাপ ৫PERT: μ আর σ
on the critical path only:
act  te = (a+4m+b)/6   var
 A   (2+12+4)/6  = 3   0.111
 B   (3+20+7)/6  = 5   0.444
 D   (3+24+9)/6  = 6   1.000
 G   (2+12+10)/6 = 4   1.778
 H   (1+8+3)/6   = 2   0.111
mu=20  var=3.444  sigma=1.856
ধাপ ৬Z আর সম্ভাবনা
P(T<=22): Z = 2 / 1.856 = 1.078
  table Z = 1.08  -> 0.8599
  exact (erf)     -> 0.8594
P(T<=18): Z = -1.078
  -> 1 - 0.8594 = 0.1406
about 86% by day 22, 14% by 18
ধাপ ৭উল্টো প্রশ্ন আর যাচাই
95%: T = mu + 1.645 x sigma
       = 20 + 1.645 x 1.856
       = 23.05 days
near-critical A-B-E-G-H:
  mu 17, var 2.889, P(<=22) 0.998
check: CP length = last EF = 20
check: P(<=18) + P(<=22) = 1
20 days · A-B-D-G-H · P(22)~0.86
  1. তথ্য আর নিয়ম। প্রথম লাইনে টেবিলটি কপি করুন আর নিয়ম লিখুন: activity-on-node, দিন ০ থেকে শুরু, activity-গুলো পরস্পর স্বাধীন। (a, m, b) এমনভাবে দেওয়া যে প্রতিটির te ঠিক CPM-এর সময়ের সমান।
  2. Forward pass. শুরুর A-র ES ০, EF ৩. যেখানে একাধিক পূর্বসূরি, সেখানে সবচেয়ে বড় EF: E-র ES = max(৮, ৭) = ৮, G-র ES = max(১৪, ১১) = ১৪, H-এর ES = max(১২, ১৮) = ১৮. শেষ EF ২০ — project-এর ন্যূনতম সময়।
  3. Backward pass. শেষের H-এর LF = ২০, LS = ১৮. একাধিক উত্তরসূরি হলে সবচেয়ে ছোট LS: C-র LF = min(E-র ১১, F-এর ১৩) = ১১, B-র LF = min(D-র ৮, E-র ১১) = ৮, A-র LF = min(৩, ৭) = ৩, তাই LS ০ — শুরুতে ফিরে শূন্য মিলল, হিসাব ঠিক।
  4. Float আর critical path. TF শূন্য: A, B, D, G, H — যোগফল ৩ + ৫ + ৬ + ৪ + ২ = ২০ দিন। C-র TF ৪ কিন্তু FF ০, কারণ C-র EF ৭ আর উত্তরসূরি F-এর ES-ও ৭; E-র দুটিই ৩, F-এর দুটিই ৬.
  5. PERT-এর μ আর σ. শুধু critical path-এর পাঁচটি activity. te-এর যোগ ২০; variance-এর যোগ ৩.৪৪৪, যার অর্ধেকের বেশি (১.৭৭৮) G-র লম্বা লেজ থেকে। σ = √৩.৪৪৪ ≈ ১.৮৫৬ — σ-গুলো যোগ নয়।
  6. Z আর সম্ভাবনা। ২২ দিনে Z ≈ ১.০৭৮; টেবিলে ১.০৮ পড়লে ০.৮৫৯৯, erf দিয়ে হুবহু ০.৮৫৯৪. ১৮ দিন গড় থেকে একই দূরত্বে উল্টো দিকে, তাই ১ − ০.৮৫৯৪ = ০.১৪০৬.
  7. উল্টো প্রশ্ন আর যাচাই। ৯৫%-এর জন্য Z = ১.৬৪৫, তাই ২০ + ১.৬৪৫ × ১.৮৫৬ ≈ ২৩.০৫ দিন। Near-critical A-B-E-G-H-এর গড় ১৭ — ২২ দিনে ৯৯.৮% সম্ভাবনায় শেষ, তাই merge bias সামান্য। শেষ লাইনে উত্তর এক বাক্যে।
৩.১(মাঝারি) ওপরের আট activity-র network-এ ES, EF, LS, LF, total float আর free float-এর টেবিল বানান। Critical path আর project-এর সময় কত? কোন activity-র total float আর free float আলাদা, আর কেন?
act dur  ES  EF  LS  LF  TF  FF
 A   3    0   3   0   3   0   0
 B   5    3   8   3   8   0   0
 C   4    3   7   7  11   4   0
 D   6    8  14   8  14   0   0
 E   3    8  11  11  14   3   3
 F   5    7  12  13  18   6   6
 G   4   14  18  14  18   0   0
 H   2   18  20  18  20   0   0
paths: A-B-D-G-H = 20, A-B-E-G-H = 17, A-C-E-G-H = 16, A-C-F-H = 14

E-র ES = max(B-র EF ৮, C-র EF ৭) = ৮ — “সামনে বড়টি”। C-র LF = min(E-র LS ১১, F-এর LS ১৩) = ১১ — “পেছনে ছোটটি”। C-র TF ৪ হলেও FF ০, কারণ C-র EF ৭ আর তার উত্তরসূরি F-এর ES-ও ৭: C এক দিন দেরি করলে F-কেও পিছাতে হয় — float-টি C, E আর F ভাগ করে নেয়। Sanity check: critical path-এর দৈর্ঘ্য (২০) = সবচেয়ে বড় EF (২০), আর সব পথের মধ্যে এটিই দীর্ঘতম। Critical path A-B-D-G-H, ২০ দিন।

৩.২(মাঝারি) একই network-এ (a, m, b) দেওয়া আছে ওপরে। Project ২২ দিনের মধ্যে আর ১৮ দিনের মধ্যে শেষ হওয়ার সম্ভাবনা কত? ৯৫% নিশ্চয়তার তারিখ কোনটি? Near-critical পথটি কি চিন্তার কারণ?
critical path A-B-D-G-H:
  te  : 3 + 5 + 6 + 4 + 2 = 20 days
  var : 0.111 + 0.444 + 1.000 + 1.778 + 0.111 = 3.444 ;  sigma = 1.856
P(T <= 22): Z = (22 - 20) / 1.856 = 1.078 ~ 1.08  ->  Phi = 0.8599 (exact 0.8594)
P(T <= 18): Z = -1.078  ->  1 - 0.8594 = 0.1406
95% date  : 20 + 1.645 x 1.856 = 23.05 days
near-critical A-B-E-G-H: mu = 17, var = 2.889 -> P(<= 22) = 0.998

G-র অনুমান (২, ৩, ১০) ডান দিকে লম্বা — মোট variance-এর অর্ধেকের বেশি (১.৭৭৮ ÷ ৩.৪৪৪) শুধু এখান থেকে। টেবিল থেকে Z = ১.০৮ পড়লে ০.৮৫৯৯, দশমিক না কেটে ০.৮৫৯৪ — দুটোই পূর্ণ নম্বর পাওয়ার মতো, কোনটি নিলেন তা লিখুন। Sanity check: P(≤ ১৮) + P(≤ ২২) = ১, কারণ দুটি T গড় থেকে সমান দূরে, দুই দিকে। Near-critical পথটি ২২ দিনে প্রায় নিশ্চিত শেষ, তাই এখানে merge bias সামান্য। প্রায় ৮৬% আর ১৪%; ৯৫%-এর তারিখ প্রায় ২৩.০৫ দিন।

৩.৩(মাঝারি) ওপরের network-এ C (UI নকশা) যদি ৩ দিন দেরি করে, project-এর শেষ তারিখ বদলাবে? আর ৫ দিন দেরি করলে?
C: TF = 4, FF = 0
C late 3 days: C = 7 days, EF = 10 -> E starts 10, F starts 10; T stays 20
C late 5 days: C = 9 days, EF = 12 -> path A-C-E-G-H = 3 + 9 + 3 + 4 + 2 = 21
               new critical path A-C-E-G-H, T = 21 (1 day late)

Total float ৪ মানে চার দিন পর্যন্ত দেরি project-কে ছোঁয় না — কিন্তু free float ০ বলে প্রথম দিন থেকেই E আর F-এর শুরু পিছায়, তাদের নিজের float খেয়ে। পাঁচ দিনে float শেষ হয়ে এক দিন বেশি, আর critical path বদলে যায়। ৩ দিনে কোনো প্রভাব নেই (২০ দিন); ৫ দিনে project ২১ দিন, নতুন critical path A-C-E-G-H.

// CPM: forward pass, backward pass, total/free float and every critical path.
// activity: [duration in days, predecessors]; listed in a valid topological order.
function cpm(acts, table = true) {
  const ids = Object.keys(acts), ES = {}, EF = {}, LS = {}, LF = {};
  const succ = Object.fromEntries(ids.map(k => [k, ids.filter(s => acts[s][1].includes(k))]));
  for (const k of ids) { ES[k] = Math.max(0, ...[...acts[k][1]].map(p => EF[p])); EF[k] = ES[k] + acts[k][0]; }
  const T = Math.max(...ids.map(k => EF[k]));
  for (const k of [...ids].reverse()) { LF[k] = Math.min(T, ...succ[k].map(s => LS[s])); LS[k] = LF[k] - acts[k][0]; }
  if (table) console.log("act dur  ES  EF  LS  LF  TF  FF");
  for (const k of ids) {
    if (!table) break;
    const FF = Math.min(T, ...succ[k].map(s => ES[s])) - EF[k];
    console.log([k, acts[k][0], ES[k], EF[k], LS[k], LF[k], LS[k] - ES[k], FF].map((v, i) => String(v).padStart(i ? 4 : 3)).join(""));
  }
  const crit = k => LS[k] === ES[k];
  const walk = (k, p) => succ[k].length ? succ[k].filter(s => crit(s) && ES[s] === EF[k]).flatMap(s => walk(s, p + "-" + s)) : [p];
  const cps = ids.filter(k => !acts[k][1].length && crit(k)).flatMap(k => walk(k, k));
  console.log("project =", T, "days; critical path(s):", cps.join(", "));
  return T;
}
const lib = { A: [3, ""], B: [5, "A"], C: [4, "A"], D: [6, "B"], E: [3, "BC"],
              F: [5, "C"], G: [4, "DE"], H: [2, "FG"] };
cpm(lib);
console.log("3.3 C late by 3 days ->"); cpm({ ...lib, C: [7, "A"] }, false);
console.log("3.3 C late by 5 days ->"); cpm({ ...lib, C: [9, "A"] }, false);

আউটপুট:

act dur  ES  EF  LS  LF  TF  FF
  A   3   0   3   0   3   0   0
  B   5   3   8   3   8   0   0
  C   4   3   7   7  11   4   0
  D   6   8  14   8  14   0   0
  E   3   8  11  11  14   3   3
  F   5   7  12  13  18   6   6
  G   4  14  18  14  18   0   0
  H   2  18  20  18  20   0   0
project = 20 days; critical path(s): A-B-D-G-H
3.3 C late by 3 days ->
project = 20 days; critical path(s): A-B-D-G-H
3.3 C late by 5 days ->
project = 21 days; critical path(s): A-C-E-G-H

টেবিলটি ৩.১-এর উত্তর আর stepper-এর ধাপ ২–৪-এর সাথে মেলে। শেষ চার লাইন ৩.৩: C তিন দিন দেরিতে project ২০ দিনই, পাঁচ দিনে ২১ আর critical path বদলে A-C-E-G-H. walk একাধিক critical path থাকলে সবগুলো ছাপে; activity-গুলো এমন ক্রমে লিখতে হবে যাতে প্রতিটির পূর্বসূরি আগে আসে (topological order).

৩.৪(মাঝারি) একটি project-এর critical path-এর μ = ৪০ দিন, variance = ১৬. (ক) ৪৫ দিনের মধ্যে শেষ হওয়ার সম্ভাবনা, (খ) ৩৬ থেকে ৪৪ দিনের মধ্যে শেষ হওয়ার সম্ভাবনা, (গ) ৪৮ দিনের বেশি লাগার সম্ভাবনা, (ঘ) ৯৯% নিশ্চয়তার তারিখ বের করুন।
sigma = sqrt(16) = 4
(a) Z = (45 - 40) / 4 = 1.25        P = Phi(1.25) = 0.8944
(b) Z = -1 .. +1                    P = Phi(1) - Phi(-1) = 0.8413 - 0.1587 = 0.6827
(c) Z = (48 - 40) / 4 = 2           P = 1 - Phi(2) = 1 - 0.9772 = 0.0228
(d) Z = 2.326                       T = 40 + 2.326 x 4 = 49.30 days

ফাঁদ: variance ১৬-কে σ ধরে Z = ৫ ÷ ১৬ লেখা। আগে বর্গমূল নিন। “বেশি লাগার” প্রশ্নে ১ − Φ, আর “মাঝে” প্রশ্নে দুই Φ-এর বিয়োগ। Sanity check: (খ)-তে ±১σ, তাই প্রায় ৬৮% — normal বণ্টনের চেনা মান। (ক) ≈ ০.৮৯৪৪, (খ) ≈ ০.৬৮২৭, (গ) ≈ ০.০২২৮, (ঘ) ≈ ৪৯.৩ দিন।

# Three-point (PERT) estimates per task, path probability with Z and the normal CDF.
import math

def pert(a, m, b):
    return (a + 4 * m + b) / 6, ((b - a) / 6) ** 2      # expected time, variance

Phi = lambda z: 0.5 * (1 + math.erf(z / math.sqrt(2)))  # standard normal CDF

def path(name, tasks, targets=(), sure=()):
    mu = var = 0.0
    for k, (a, m, b) in tasks.items():
        te, v = pert(a, m, b)
        mu += te
        var += v                                        # variances add, sigmas do not
        print(f"  {k:8} a={a} m={m} b={b}  te={te:.3f}  var={v:.3f}")
    sd = math.sqrt(var)
    print(f"{name}: mu={mu:.3f} var={var:.3f} sigma={sd:.3f}")
    for T in targets:
        z = (T - mu) / sd
        print(f"  P(T <= {T}) : Z = {z:+.4f}  p = {Phi(z):.4f}")
    for p, z in sure:                                   # z read from the normal table
        print(f"  {p:.0%} sure by mu + {z} x sigma = {mu + z * sd:.2f}")

path("2.8 four tasks", {"login": (2, 4, 8), "search": (3, 5, 9),
                        "payment": (4, 7, 16), "report": (1, 2, 3)})
path("3.2 critical path A-B-D-G-H", {"A": (2, 3, 4), "B": (3, 5, 7), "D": (3, 6, 9),
                                     "G": (2, 3, 10), "H": (1, 2, 3)},
     targets=(18, 22), sure=((0.90, 1.2816), (0.95, 1.645)))
print("3.4 mu=40 sigma=4:", f"P(<=45)={Phi(1.25):.4f}", f"P(36..44)={Phi(1) - Phi(-1):.4f}",
      f"P(>48)={1 - Phi(2):.4f}", f"99% by {40 + 2.326 * 4:.2f}")

আউটপুট:

  login    a=2 m=4 b=8  te=4.333  var=1.000
  search   a=3 m=5 b=9  te=5.333  var=1.000
  payment  a=4 m=7 b=16  te=8.000  var=4.000
  report   a=1 m=2 b=3  te=2.000  var=0.111
2.8 four tasks: mu=19.667 var=6.111 sigma=2.472
  A        a=2 m=3 b=4  te=3.000  var=0.111
  B        a=3 m=5 b=7  te=5.000  var=0.444
  D        a=3 m=6 b=9  te=6.000  var=1.000
  G        a=2 m=3 b=10  te=4.000  var=1.778
  H        a=1 m=2 b=3  te=2.000  var=0.111
3.2 critical path A-B-D-G-H: mu=20.000 var=3.444 sigma=1.856
  P(T <= 18) : Z = -1.0776  p = 0.1406
  P(T <= 22) : Z = +1.0776  p = 0.8594
  90% sure by mu + 1.2816 x sigma = 22.38
  95% sure by mu + 1.645 x sigma = 23.05
3.4 mu=40 sigma=4: P(<=45)=0.8944 P(36..44)=0.6827 P(>48)=0.0228 99% by 49.30

প্রথম অংশ ২.৮-এর চারটি কাজ: মোট ১৯.৬৬৭ দিন, σ ২.৪৭২. দ্বিতীয় অংশ ৩.২ আর stepper-এর ধাপ ৫–৭: μ = ২০, σ ≈ ১.৮৫৬, P(≤ ২২) = ০.৮৫৯৪, ৯৫%-এর তারিখ ২৩.০৫. শেষ লাইন ৩.৪-এর চারটি উত্তর। sure-এ Z-এর মান টেবিল থেকে হাতে দেওয়া (১.২৮১৬, ১.৬৪৫), যেমন পরীক্ষায় করবেন।

Crashing

৩.৫(কঠিন) ছয়টি activity (হাজার টাকা): P normal ৪ দিন, crash ৩, slope ৯; Q (P-র পরে) ৬ → ৪, slope ৫; R (P-র পরে) ৫ → ৪, slope ৩; S (Q-র পরে) ৩ → ২, slope ১০; T (R-এর পরে) ৩ → ২, slope ৬; U (S আর T-র পরে) ২, কমানো যায় না। Normal-এ সরাসরি খরচ মোট ২০০, পরোক্ষ খরচ দিনে ১২. (ক) একটি activity normal ৮ দিনে ৪০ হাজার, crash ৫ দিনে ৬১ হাজার হলে তার slope কত? (খ) ওপরের project সবচেয়ে কম মোট খরচে কত দিনে শেষ করা উচিত?
(a) slope = (61 - 40) / (8 - 5) = 21 / 3 = 7 thousand taka per day
(b) paths: P-Q-S-U = 4+6+3+2 = 15 ;  P-R-T-U = 4+5+3+2 = 14
 T   critical      cheapest cut          direct  indirect  total
 15  PQSU          -                      200     180      380
 14  PQSU          Q (5)                  205     168      373
 13  PQSU, PRTU    Q+R (5+3 = 8)          213     156      369
 12  PQSU, PRTU    P (9)                  222     144      366   <- minimum
 11  PQSU, PRTU    S+T (10+6 = 16 > 12)   238     132      370

প্রথম ধাপে শুধু P-Q-S-U critical; সেখানে সবচেয়ে সস্তা Q (৫)। R-এর slope (৩) কম হলেও তখন R critical নয় — কমালে টাকা নষ্ট। ১৪ দিনে দুটি পথই critical, তাই দুটিকেই কাটতে হয়: সাধারণ activity P (৯) বনাম প্রতিটি পথ থেকে একটি করে Q+R (৮) — Q+R সস্তা। Q তখন crash সীমায় (৪), R-ও (৪)। এরপর P (৯) — দুই পথেই আছে। শেষ বিকল্প S+T (১৬) দৈনিক পরোক্ষ খরচ ১২-র বেশি, তাই মোট খরচ বাড়ে। (ক) দিনে ৭ হাজার টাকা; (খ) ১২ দিনে, মোট খরচ ৩৬৬ হাজার টাকা।

// Crashing: shorten one day at a time by the cheapest set that cuts EVERY critical path.
// activity: [normal days, crash days, cost slope in thousand taka per day]
const A = { P: [4, 3, 9], Q: [6, 4, 5], R: [5, 4, 3], S: [3, 2, 10], T: [3, 2, 6], U: [2, 2, 0] };
const paths = ["PQSU", "PRTU"], INDIRECT = 12;          // overhead: 12 thousand taka per day
const dur = Object.fromEntries(Object.entries(A).map(([k, v]) => [k, v[0]]));
const len = p => [...p].reduce((s, k) => s + dur[k], 0);
let direct = 200, T = Math.max(...paths.map(len));     // direct cost at normal durations
const show = () => console.log(`T=${T}  paths ${paths.map(p => p + "=" + len(p)).join(" ")}  direct=${direct}  total=${direct + INDIRECT * T}`);
show();
for (;;) {
  const crit = paths.filter(p => len(p) === T);
  const can = Object.keys(A).filter(k => dur[k] > A[k][1]);
  let best = null;
  for (let mask = 1; mask < 1 << can.length; mask++) {
    const set = can.filter((_, i) => (mask >> i) & 1);
    if (!crit.every(p => set.some(k => p.includes(k)))) continue;
    const cost = set.reduce((s, k) => s + A[k][2], 0);
    if (!best || cost < best.cost || (cost === best.cost && set.length < best.set.length)) best = { set, cost };
  }
  if (!best) { console.log("cannot crash further"); break; }
  const verdict = best.cost < INDIRECT ? "saves money" : "costs more than it saves";
  console.log(`  crash ${best.set.join("+")} (+${best.cost}/day) -> ${verdict}`);
  best.set.forEach(k => dur[k]--); direct += best.cost; T = Math.max(...paths.map(len));
  show();
}

আউটপুট:

T=15  paths PQSU=15 PRTU=14  direct=200  total=380
  crash Q (+5/day) -> saves money
T=14  paths PQSU=14 PRTU=14  direct=205  total=373
  crash Q+R (+8/day) -> saves money
T=13  paths PQSU=13 PRTU=13  direct=213  total=369
  crash P (+9/day) -> saves money
T=12  paths PQSU=12 PRTU=12  direct=222  total=366
  crash S+T (+16/day) -> costs more than it saves
T=11  paths PQSU=11 PRTU=11  direct=238  total=370
cannot crash further

প্রতিটি ধাপ ৩.৫-এর টেবিলের সারি: Q (+৫), Q+R (+৮), P (+৯) — তিনটিই দৈনিক পরোক্ষ খরচ ১২-র কম, তাই মোট খরচ কমে ৩৬৬-তে নামে। শেষ ধাপ S+T (+১৬) মোট খরচ বাড়িয়ে ৩৭০ করে, আর তারপর আর কমানো যায় না। প্রোগ্রামটি প্রতিটি ধাপে সব সম্ভাব্য activity-সেট (bitmask) পরীক্ষা করে — ছোট network-এ এটিই সবচেয়ে নিরাপদ।

Earned value

৩.৬(মাঝারি) একটি project-এর মোট বাজেট (BAC) ৫০০ হাজার টাকা। ৬ সপ্তাহ শেষে: PV = ২৪০, EV = ২০০, AC = ২৩০. SV, CV, SPI, CPI, EAC (BAC ÷ CPI), ETC আর VAC বের করুন। Project-এর অবস্থা এক বাক্যে লিখুন।
SV  = EV - PV = 200 - 240 = -40      SPI = 200 / 240 = 0.833
CV  = EV - AC = 200 - 230 = -30      CPI = 200 / 230 = 0.870
EAC = BAC / CPI = 500 / 0.870 = 575.0
ETC = EAC - AC = 575 - 230 = 345.0 ;  VAC = BAC - EAC = -75.0
other EAC forms: AC + (BAC - EV) = 530.0 ;  AC + (BAC - EV)/(CPI x SPI) = 644.0
TCPI = (BAC - EV) / (BAC - AC) = 300 / 270 = 1.111

SPI আর CPI দুটিই ১-এর কম: পরিকল্পনার চেয়ে পিছিয়ে, আর যতটুকু কাজ হয়েছে তাতেও বেশি খরচ — প্রতি ১ টাকায় ০.৮৭ টাকার কাজ। এখনকার হারে চললে শেষে ৫৭৫, অর্থাৎ ৭৫ হাজার বেশি। কোন EAC নেবেন তা নির্ভর করে বাড়তি খরচ কেন হলো তার ওপর: একবারের ঘটনা হলে ৫৩০, দেরি আর খরচ দুটিই চলতে থাকলে ৬৪৪. TCPI (কিছু বইয়ে থাকে) বলে বাজেটে শেষ করতে বাকি কাজে ১.১১১ দক্ষতা লাগবে — এখনকার ০.৮৭ থেকে যা অবাস্তব লাফ। SV −৪০, CV −৩০, SPI ০.৮৩৩, CPI ০.৮৭০, EAC ৫৭৫, ETC ৩৪৫, VAC −৭৫ — পিছিয়ে এবং বাজেট ছাড়িয়ে।

৩.৭(মাঝারি) চারটি work package-এর বাজেট ৪০, ৬০, ৮০ আর ২০ হাজার টাকা। আজ পর্যন্ত পরিকল্পনা: প্রথম তিনটি শেষ আর চতুর্থটির অর্ধেক। বাস্তবে প্রথম দুটি শেষ, তৃতীয়টি শুরু হয়েছে (developer বলছেন “৬০% শেষ”), চতুর্থটি শুরু হয়নি। খরচ হয়েছে ১৫০. 50/50 নিয়মে আর 0/100 নিয়মে EV, SPI আর CPI কত?
PV = 40 + 60 + 80 + 0.5 x 20 = 190
50/50 rule: started = 50%, finished = 100%
   EV = 40 + 60 + 0.5 x 80 + 0 = 140   SPI = 140/190 = 0.737   CPI = 140/150 = 0.933
0/100 rule: only finished work counts
   EV = 40 + 60 + 0 + 0 = 100          SPI = 100/190 = 0.526   CPI = 100/150 = 0.667

দুই নিয়মের কোনোটিই “৬০% শেষ” দাবি গোনে না — software-এ “৯০% শেষ” সমস্যা এড়াতেই এগুলোর জন্ম (পর্ব ৬১)। 0/100 সবচেয়ে রক্ষণশীল; তাই একই অবস্থায় SPI অনেক খারাপ দেখায়। Sanity check: EV কখনো BAC (২০০)-এর বেশি হতে পারে না। 50/50: EV ১৪০, SPI ০.৭৩৭, CPI ০.৯৩৩; 0/100: EV ১০০, SPI ০.৫২৬, CPI ০.৬৬৭.

# Earned value: SV, CV, SPI, CPI and three common EAC forms (amounts in thousand taka).
def earned_value(name, BAC, PV, EV, AC):
    SV, CV, SPI, CPI = EV - PV, EV - AC, EV / PV, EV / AC
    print(f"{name}: BAC={BAC} PV={PV} EV={EV} AC={AC}")
    print(f"  SV={SV:+} CV={CV:+} SPI={SPI:.3f} CPI={CPI:.3f}")
    eacs = {"BAC/CPI": BAC / CPI, "AC+(BAC-EV)": AC + (BAC - EV),
            "AC+(BAC-EV)/(CPI*SPI)": AC + (BAC - EV) / (CPI * SPI)}
    for form, eac in eacs.items():
        print(f"  EAC {form:22} = {eac:7.1f}  VAC = {BAC - eac:+.1f}")
    print(f"  ETC (BAC/CPI - AC) = {BAC / CPI - AC:.1f}  TCPI = {(BAC - EV) / (BAC - AC):.3f}")

earned_value("3.6 week 6", BAC=500, PV=240, EV=200, AC=230)

# 3.7: EV from work packages under two progress rules
packages = [  # (budget, planned % by today, actual % done, started?)
    (40, 100, 100, True), (60, 100, 100, True), (80, 100, 60, True), (20, 50, 0, False)]
PV = sum(b * p / 100 for b, p, _, _ in packages)
AC = 150
for rule in ("50/50", "0/100"):
    EV = 0
    for b, _, done, started in packages:
        if done == 100:
            EV += b                                    # finished: full budget earned
        elif started and rule == "50/50":
            EV += b / 2                                # started: half, whatever the "% done"
    print(f"3.7 rule {rule}: PV={PV:.0f} EV={EV:.0f} AC={AC} SPI={EV / PV:.3f} CPI={EV / AC:.3f}")

আউটপুট:

3.6 week 6: BAC=500 PV=240 EV=200 AC=230
  SV=-40 CV=-30 SPI=0.833 CPI=0.870
  EAC BAC/CPI                =   575.0  VAC = -75.0
  EAC AC+(BAC-EV)            =   530.0  VAC = -30.0
  EAC AC+(BAC-EV)/(CPI*SPI)  =   644.0  VAC = -144.0
  ETC (BAC/CPI - AC) = 345.0  TCPI = 1.111
3.7 rule 50/50: PV=190 EV=140 AC=150 SPI=0.737 CPI=0.933
3.7 rule 0/100: PV=190 EV=100 AC=150 SPI=0.526 CPI=0.667

প্রথম অংশ ৩.৬: SV −৪০, CV −৩০, SPI ০.৮৩৩, CPI ০.৮৭০, তিন রূপের EAC ৫৭৫, ৫৩০ আর ৬৪৪, ETC ৩৪৫, TCPI ১.১১১. শেষ দুই লাইন ৩.৭-এর দুই নিয়ম — একই কাজের অবস্থায় 0/100 নিয়মে SPI ০.৫২৬, 50/50-এ ০.৭৩৭. “৬০% শেষ” তথ্যটি কোড ইচ্ছা করে ব্যবহার করে না।

(সহজ) একটি activity-র সময় ৪ দিন, আর তার তিনটি পূর্বসূরির EF যথাক্রমে ৯, ১২ আর ৭. Forward pass-এ এর ES আর EF কত?

  • ES 7, EF 11
  • ES 28, EF 32
  • ES 12, EF 16
  • ES 9, EF 13

(মাঝারি) একটি activity-র ES = ৫, EF = ৯, LS = ৮; তার উত্তরসূরিদের সবচেয়ে ছোট ES = ১০. Total float আর free float কত?

  • TF 3, FF 1
  • TF 1, FF 3
  • TF 3, FF 3
  • TF 3, FF 5

(মাঝারি) PERT-এ critical path-এর প্রত্যাশিত সময় ৩০ দিন আর σ = ২ দিন। Normal বণ্টন ধরে project ৩৩ দিনের মধ্যে শেষ হওয়ার সম্ভাবনা প্রায় কত?

  • 0.5000
  • 0.8413
  • 0.9987
  • 0.9332

(মাঝারি) একটি project-এ PV = ১০০, EV = ৯০, AC = ১২০ (হাজার টাকা)। কোন বিবরণটি ঠিক?

  • SPI 0.90, CPI 1.33 — পিছিয়ে কিন্তু বাজেটের নিচে
  • SPI 0.90, CPI 0.75 — পিছিয়ে এবং বাজেট ছাড়িয়ে
  • SPI 1.11, CPI 1.33 — এগিয়ে এবং বাজেটের নিচে
  • AC > PV, তাই শুধু বাজেট ছাড়িয়েছে, সময়মতো আছে

৪ · Risk আর quality — RE, RRL, EMV, availability, DRE আর control chart

ঝালিয়ে নিন: পর্ব ০৩ · Software quality (MTBF, availability, DRE), পর্ব ০৪ · SDLC আর process model (spiral-এর risk exposure), পর্ব ৬২ · Risk আর quality management (RRL, EMV, control chart).

সূত্রের কার্ড

Risk exposure: RE = P × L (প্রত্যাশিত ক্ষতি); RRL = (REআগে − REপরে) ÷ প্রতিকারের খরচ — ১-এর বেশি মানে লাভজনক।

EMV: chance node-এ Σ(p × মূল্য), decision node-এ সবচেয়ে বড় (EMV − খরচ) — decision tree ভেতর থেকে বাইরে হিসাব।

Availability: A = MTBF ÷ (MTBF + MTTR); বছরে বন্ধ = (১ − A) × ৮৭৬০ ঘণ্টা; লক্ষ্য A-র জন্য MTTR = MTBF × (১ − A) ÷ A.

Defect: defect density = defect ÷ KLOC; DRE = আগে পাওয়া ÷ (আগে + পরে পাওয়া)। Control chart: গড় ± ৩σ, LCL ঋণাত্মক হলে ০.

৪.১(সহজ) একটি কাল্পনিক অনলাইন বাজার অ্যাপের চারটি ঝুঁকি (ক্ষতি লাখ টাকায়): R1 payment gateway বদল — P ০.৩, L ২০; R2 মূল developer চলে যাওয়া — P ০.৬, L ৫; R3 ঈদের ভিড়ে server বসে যাওয়া — P ০.১, L ৫০; R4 নতুন আইনে data নিয়ম বদল — P ০.২৫, L ১৬. প্রতিটির RE, অগ্রাধিকারের ক্রম আর মোট RE বের করুন।
R1: 0.3  x 20 = 6.0
R2: 0.6  x 5  = 3.0
R3: 0.1  x 50 = 5.0
R4: 0.25 x 16 = 4.0
order by RE: R1 (6) > R3 (5) > R4 (4) > R2 (3) ;  total RE = 18.0 lakh

সম্ভাবনায় সবচেয়ে বড় (R2, ০.৬) তালিকার শেষে, আর ক্ষতিতে সবচেয়ে বড় (R3, ৫০) দ্বিতীয় — RE দুটিকে একসাথে দেখে বলেই এটি দরকারি। তবে R3-এর মতো “কম সম্ভাবনা, বিশাল ক্ষতি” ঝুঁকি শুধু RE দেখে নিচে নামানো বিপজ্জনক হতে পারে; পর্ব ৬২-এ দেখেছেন, ছোট প্রতিষ্ঠানের জন্য একটি খারাপ ফলই যথেষ্ট। ক্রম R1, R3, R4, R2; মোট RE ১৮ লাখ।

৪.২(মাঝারি) ৪.১-এর R1 (RE ৬ লাখ) কমানোর দুটি প্রস্তাব: M1 — দুটি gateway-র জন্য একটি adapter স্তর, খরচ ১.৫ লাখ, P নামবে ০.১-এ, ক্ষতি একই; M2 — নিজস্ব payment module, খরচ ৩ লাখ, P ০.০৫ আর ক্ষতি ১২ লাখে নামবে। কোনটি ভালো বিনিয়োগ?
M1: RE after = 0.1 x 20 = 2.0    RRL = (6 - 2.0) / 1.5 = 2.67
M2: RE after = 0.05 x 12 = 0.6   RRL = (6 - 0.6) / 3   = 1.80
cost + residual RE:  M1 = 1.5 + 2.0 = 3.5 ;  M2 = 3 + 0.6 = 3.6 ;  do nothing = 6

দুটিরই RRL ১-এর বেশি, অর্থাৎ দুটিই খরচের চেয়ে বেশি প্রত্যাশিত ক্ষতি কমায়। প্রতি টাকায় M1 বেশি কাজ করে (২.৬৭ বনাম ১.৮০), আর “খরচ + বাকি ঝুঁকি”-র মোটেও M1 সামান্য কম। M2-এর residual ঝুঁকি কম — ঝুঁকি একেবারেই সইতে না পারলে সেটিও যুক্তিসঙ্গত। M1 (RRL ≈ ২.৬৭) ভালো বিনিয়োগ।

৪.৩(কঠিন) Build বনাম buy (লাখ টাকা)। Build: খরচ ৩০; সফল হওয়ার সম্ভাবনা ০.৭ হলে মূল্য ১০০, ব্যর্থ (০.৩) হলে ৪০. Buy: খরচ ৪৫; ভালো মিল (০.৯) হলে ১০০, দুর্বল মিল (০.১) হলে ৬০. EMV দিয়ে সিদ্ধান্ত নিন, আর build-এর সাফল্যের সম্ভাবনা কত হলে দুটি সমান হয়?
build: 0.7 x 100 + 0.3 x 40 = 70 + 12 = 82 ;  82 - 30 = 52
buy  : 0.9 x 100 + 0.1 x 60 = 90 + 6  = 96 ;  96 - 45 = 51
decision: build (52 > 51)
tie: 100p + 40(1 - p) - 30 = 51  ->  60p = 41  ->  p = 0.683

পার্থক্য মাত্র ১ লাখ, আর সমতার বিন্দু ০.৬৮৩ — দলের ০.৭ অনুমান একটু আশাবাদী হলেই সিদ্ধান্ত উল্টে যায়। এমন ক্ষেত্রে sensitivity লিখে দেওয়াই পূর্ণ উত্তর। Build-এর খারাপ ফল (৪০ − ৩০ = ১০) buy-এর খারাপ ফলের (৬০ − ৪৫ = ১৫) চেয়েও খারাপ — ঝুঁকি এড়াতে চাইলে buy. EMV-তে build (৫২ বনাম ৫১); সম্ভাবনা ০.৬৮৩-এর নিচে নামলে buy.

৪.৪(মাঝারি) (ক) একটি ফলাফল পোর্টালের MTBF ৫০০ ঘণ্টা, MTTR ২ ঘণ্টা। Availability আর বছরে প্রত্যাশিত বন্ধ সময় কত? ৯৯.৯% পেতে MTTR কত হওয়া দরকার (MTBF একই)? (খ) আরেকটি system ৩০ দিন (৭২০ ঘণ্টা) পর্যবেক্ষণে ৪বার বসে গেছে, মোট মেরামতে লেগেছে ৬ ঘণ্টা। MTBF, MTTR আর availability কত?
(a) A = 500 / (500 + 2) = 0.99602 = 99.602%
    downtime = (1 - 0.99602) x 8760 = 34.9 hours per year
    target 99.9%: MTTR = 500 x 0.001 / 0.999 = 0.5005 h = 30.0 minutes
(b) uptime = 720 - 6 = 714 h ;  MTBF = 714 / 4 = 178.5 h ;  MTTR = 6 / 4 = 1.5 h
    A = 178.5 / (178.5 + 1.5) = 99.167%     (check: 714 / 720 = 99.167%)

(খ)-তে MTBF মানে চলার গড় সময়, তাই মেরামতের ৬ ঘণ্টা বাদ দিয়ে ভাগ — ৭২০ ÷ ৪ = ১৮০ নিলে MTBF আর MTTR যোগ হয়ে যায় (কিছু বই একে MTTF-এর সাথে মিলিয়ে বলে, পর্ব ০৩ দেখুন)। Sanity check: দীর্ঘ সময়ের availability = চলা সময় ÷ মোট সময় = ৭১৪ ÷ ৭২০ — একই উত্তর। (ক)-এর শিক্ষা: availability বাড়াতে failure কমানো ছাড়াও দ্রুত ফেরা (MTTR ২ ঘণ্টা থেকে ৩০ মিনিট) সমান কার্যকর। (ক) ৯৯.৬০২%, বছরে প্রায় ৩৪.৯ ঘণ্টা, MTTR ৩০ মিনিট; (খ) MTBF ১৭৮.৫ ঘণ্টা, MTTR ১.৫ ঘণ্টা, A ≈ ৯৯.১৬৭%.

৪.৫(সহজ) ২৫ KLOC-এর একটি release-এ review-তে ৬০টি আর test-এ ৯০টি defect ধরা পড়েছে; release-এর পরের ৯০ দিনে ব্যবহারকারীরা আরও ৩০টি জানিয়েছেন। DRE, মোট defect density আর release-পরবর্তী defect density কত?
before release = 60 + 90 = 150 ;  after = 30 ;  total = 180
DRE = 150 / 180 = 0.833 = 83.3%
density (all)          = 180 / 25 = 7.20 per KLOC
density (post-release) =  30 / 25 = 1.20 per KLOC

DRE সবসময় “এখন পর্যন্ত জানা” defect-এর ওপর — ৯০ দিনের পরে আরও বেরোলে DRE কমবে। দুটি density দুটি ভিন্ন প্রশ্নের উত্তর দেয়, তাই রিপোর্টে কোনটি দিচ্ছেন স্পষ্ট লিখুন। Sanity check: DRE ১-এর বেশি হতে পারে না, আর আগে-পরে যোগ মোটের সমান। DRE ≈ ৮৩.৩%, ৭.২০ আর ১.২০ প্রতি KLOC.

৪.৬(মাঝারি) একটি দলের দশ সপ্তাহের defect সংখ্যা: ১২, ১৫, ১১, ১৪, ১৩, ১৬, ১২, ১০, ১৪, ১৩. নমুনার σ দিয়ে control limit বের করুন। এগারোতম সপ্তাহে ২১টি defect এলে কী বলবেন?
mean = 130 / 10 = 13.0
squared deviations: 1, 4, 4, 1, 0, 9, 1, 9, 1, 0  -> sum = 30
sample sigma = sqrt(30 / 9) = sqrt(3.333) = 1.826
UCL = 13 + 3 x 1.826 = 18.48 ;  LCL = 13 - 3 x 1.826 = 7.52
week 11: 21 > 18.48  ->  outside the limits: look for a special cause

সীমার ভেতরের ওঠানামা (যেমন ১৬) স্বাভাবিক — একে নিয়ে তদন্ত করলে সময় নষ্ট। ২১ সীমার বাইরে, তাই কোনো বিশেষ কারণ খুঁজুন (একটি তাড়াহুড়োর release, নতুন module). পর্ব ৬২-এর মতো এখানে সরলতার জন্য নমুনার σ; আনুষ্ঠানিক XmR chart-এ moving range থেকে σ আসে, তাতে সংখ্যা সামান্য বদলায়। Population σ (১০ দিয়ে ভাগ, ১.৭৩২) নিলে UCL ১৮.২০ — প্রশ্নে কোনটি চাওয়া, দেখে নিন। UCL ≈ ১৮.৪৮, LCL ≈ ৭.৫২; ২১ out of control.

// Risk and quality numbers: RE, RRL, EMV, availability, DRE, control limits.
const f = (x, d = 2) => x.toFixed(d);
const risks = { R1: [0.3, 20], R2: [0.6, 5], R3: [0.1, 50], R4: [0.25, 16] };   // [P, loss in lakh taka]
const re = Object.entries(risks).map(([id, [p, L]]) => [id, p * L]).sort((a, b) => b[1] - a[1]);
console.log("4.1 RE ranking:", re.map(([id, v]) => `${id}=${f(v, 1)}`).join(" "),
  " total =", f(re.reduce((s, r) => s + r[1], 0), 1));
const rrl = (before, after, cost) => (before - after) / cost;               // Boehm's RRL
console.log("4.2 M1 RRL =", f(rrl(6, 0.1 * 20, 1.5)), " M2 RRL =", f(rrl(6, 0.05 * 12, 3)));
// EMV: chance node = sum(p x payoff); decision = best (EMV - cost)
const chance = branches => branches.reduce((s, [p, v]) => s + p * v, 0);
const build = chance([[0.7, 100], [0.3, 40]]) - 30, buy = chance([[0.9, 100], [0.1, 60]]) - 45;
console.log("4.3 EMV build =", f(build, 1), " buy =", f(buy, 1), " ->", build > buy ? "build" : "buy",
  " tie at P(success) =", f((buy + 30 - 40) / 60, 3));
const avail = (mtbf, mttr) => mtbf / (mtbf + mttr);
const A = avail(500, 2);
console.log("4.4 A =", f(100 * A, 3) + "%", " downtime/year =", f((1 - A) * 8760, 1), "h",
  " MTTR for 99.9% =", f(500 * (1 - 0.999) / 0.999 * 60, 1), "min");
const up = 720 - 6, n = 4;                                   // 30 days, 4 failures, 6 h of repair
console.log("4.4b MTBF =", f(up / n, 1), "h  MTTR =", f(6 / n, 1), "h  A =", f(100 * avail(up / n, 6 / n), 3) + "%");
const pre = 60 + 90, post = 30, kloc = 25;
console.log("4.5 DRE =", f(100 * pre / (pre + post), 1) + "%", " density total =", f((pre + post) / kloc),
  "/KLOC  post-release =", f(post / kloc), "/KLOC");
const wk = [12, 15, 11, 14, 13, 16, 12, 10, 14, 13];
const m = wk.reduce((s, x) => s + x, 0) / wk.length;
const sd = Math.sqrt(wk.reduce((s, x) => s + (x - m) ** 2, 0) / (wk.length - 1));   // sample sigma
console.log("4.6 mean =", f(m), " sigma =", f(sd, 3), " UCL =", f(m + 3 * sd), " LCL =", f(Math.max(0, m - 3 * sd)));

আউটপুট:

4.1 RE ranking: R1=6.0 R3=5.0 R4=4.0 R2=3.0  total = 18.0
4.2 M1 RRL = 2.67  M2 RRL = 1.80
4.3 EMV build = 52.0  buy = 51.0  -> build  tie at P(success) = 0.683
4.4 A = 99.602%  downtime/year = 34.9 h  MTTR for 99.9% = 30.0 min
4.4b MTBF = 178.5 h  MTTR = 1.5 h  A = 99.167%
4.5 DRE = 83.3%  density total = 7.20 /KLOC  post-release = 1.20 /KLOC
4.6 mean = 13.00  sigma = 1.826  UCL = 18.48  LCL = 7.52

প্রতিটি লাইন ভাগ ৪-এর একটি প্রশ্নের উত্তর: RE-র ক্রম আর মোট ১৮, RRL ২.৬৭ আর ১.৮০, EMV ৫২ বনাম ৫১ আর সমতার বিন্দু ০.৬৮৩, availability ৯৯.৬০২% আর ৩০ মিনিটের MTTR, log থেকে MTBF ১৭৮.৫, DRE ৮৩.৩%, আর control limit ১৮.৪৮ ও ৭.৫২. σ-এর হিসাবে wk.length - 1 দিয়ে ভাগ — নমুনার σ; wk.length দিলে population σ হতো।

(সহজ) একটি ঝুঁকির ঘটার সম্ভাবনা ০.৪ আর ঘটলে ক্ষতি ১৫ লাখ টাকা। Risk exposure কত?

  • ৬ লাখ টাকা
  • ১৫ লাখ টাকা
  • ৩৭.৫ লাখ টাকা
  • ৯ লাখ টাকা

(মাঝারি) একটি প্রতিকারে খরচ ৪ লাখ; এতে একটি ঝুঁকির RE ১০ লাখ থেকে ২ লাখে নামে। Risk reduction leverage কত, আর প্রতিকারটি কেমন?

  • 2.5 — লাভজনক
  • 0.5 — অলাভজনক
  • 2.0 — লাভজনক
  • 8.0 — খুব লাভজনক

(সহজ) MTBF ৯৯৯ ঘণ্টা আর MTTR ১ ঘণ্টা হলে availability আর বছরে প্রত্যাশিত বন্ধ সময় প্রায় কত?

  • 99.99%, প্রায় ৫৩ মিনিট
  • 99.9%, প্রায় ৮.৭৬ ঘণ্টা
  • 99%, প্রায় ৮৭.৬ ঘণ্টা
  • 99.9%, ১ ঘণ্টা

(সহজ) Release-এর আগে review আর test-এ ৪৫টি defect ধরা পড়েছে, release-এর পরে ব্যবহারকারীরা ৫টি পেয়েছেন। Defect removal efficiency কত?

  • 11.1%
  • 88.9%
  • 10%
  • 90%

৫ · Design metric — coupling, LCOM4, যোগাযোগের পথ আর bus factor

ঝালিয়ে নিন: পর্ব ২৫ · Modularity, coupling আর cohesion (Ca, Ce, I, A, D, LCOM4), পর্ব ৬০ (Brooks আর যোগাযোগের পথ), পর্ব ৬৩ · দলগত কাজ আর open source (bus factor).

সূত্রের কার্ড

Package: Ca = কতজন আমার ওপর নির্ভর করে, Ce = আমি কতজনের ওপর; I = Ce ÷ (Ca + Ce); A = abstract ÷ মোট class; D = |A + I − ১| — main sequence থেকে দূরত্ব; D ≥ ০.৫ আর A + I < ১ হলে zone of pain, A + I > ১ হলে zone of uselessness.

LCOM4: method-গুলোর graph-এ connected component-এর সংখ্যা (দুটি method যুক্ত, যদি একটি attribute ভাগ করে বা একটি অন্যটিকে ডাকে); ১ = cohesive. যোগাযোগের পথ: n(n − ১) ÷ ২. Bus factor: সবচেয়ে কম কয়জন সরে গেলে অর্ধেকের বেশি ফাইল “অনাথ”।

৫.১(সহজ) একটি package-এর ওপর বাইরের ৩টি package নির্ভর করে, আর এটি নিজে ১টির ওপর নির্ভর করে। এর ৮টি class-এর ৬টি interface বা abstract. I, A আর D কত? Package-টি কোথায় দাঁড়িয়ে?
Ca = 3, Ce = 1
I = Ce / (Ca + Ce) = 1 / 4 = 0.25
A = 6 / 8 = 0.75
D = |0.75 + 0.25 - 1| = 0.00

Stable (অনেকে নির্ভর করে) আর abstract (বেশিরভাগ interface) — ঠিক main sequence-এর ওপর। এটিই Martin-এর stable abstractions principle-এর আদর্শ: যাকে অনেকে ব্যবহার করে, তাকে বদলানো কঠিন, তাই তার ভেতরে interface রাখুন যাতে বাড়ানো যায়। I = ০.২৫, A = ০.৭৫, D = ০ — ভারসাম্যপূর্ণ।

৫.২(মাঝারি) একটি কাল্পনিক অনলাইন বাজারের সাতটি package (তীর = “নির্ভর করে”; বন্ধনীতে মোট class / abstract): app → orders, payment, report (৫/০); orders → domain, db (৬/১); payment → domain, gateway (৪/১); report → domain, db (৩/০); db → domain (৪/৩); gateway → কেউ নয় (২/০); domain → কেউ নয় (৮/০)। প্রতিটির Ca, Ce, I, A, D বের করে সমস্যার package চিহ্নিত করুন।
package  Ca Ce    I     A     D
app       0  3  1.00  0.00  0.00
orders    1  2  0.67  0.17  0.17
payment   1  2  0.67  0.25  0.08
report    1  2  0.67  0.00  0.33
db        2  1  0.33  0.75  0.08
gateway   1  0  0.00  0.00  1.00   zone of pain
domain    4  0  0.00  0.00  1.00   zone of pain

Ca গুনতে প্রতিটি package-এর দিকে আসা তীর গুনুন: domain-এর দিকে orders, payment, report আর db — ৪টি। domain পুরো stable (I = ০) অথচ পুরো concrete (A = ০) — বদলানো কঠিন, বাড়ানোর জায়গাও নেই: zone of pain. Domain model-এর ক্ষেত্রে এটি প্রায়ই মেনে নেওয়া হয়, যদি domain খুব কম বদলায়; gateway-র ক্ষেত্রে বেশি চিন্তার — বাইরের payment সেবা বদলালে payment-কেও বদলাতে হবে, তাই একটি PaymentGateway interface রাখাই ভালো। domain আর gateway, দুটিই D = ১.০০.

৫.৩(মাঝারি) ResultService class-এর method আর তারা কোন attribute ছোঁয়: addMarks {marks}, totalMarks {marks}, gpa {scale}, exportCsv {marks}, sendEmail {mailer}, formatEmail {template}, logAccess {logfile}. gpa ডাকে totalMarks-কে, sendEmail ডাকে formatEmail-কে। LCOM4 কত, আর class-টি কীভাবে ভাঙবেন?
shared attribute: addMarks - totalMarks - exportCsv   (marks)
call links      : gpa -> totalMarks ;  sendEmail -> formatEmail
components:
  1. addMarks, totalMarks, gpa, exportCsv
  2. sendEmail, formatEmail
  3. logAccess
LCOM4 = 3

gpa নিজে marks ছোঁয় না, কিন্তু totalMarks-কে ডাকে — তাই LCOM4-এ সে প্রথম দলে। sendEmail আর formatEmail কোনো attribute ভাগ করে না, তবু ডাকার সম্পর্কে এক দল। তিনটি টুকরো মানে তিনটি দায়িত্ব: ফল হিসাব (ResultCalculator), নোটিশ (Notifier) আর logging — SRP-র (পর্ব ২৭) সংখ্যাগত ইঙ্গিত। LCOM4 = ৩; তিনটি class-এ ভাঙা যায়।

// Martin's package metrics (Ca, Ce, I, A, D), LCOM4 and communication paths.
// Counting PACKAGES (not classes) for Ca and Ce, as in the coupling lesson.
const pkgs = { app: [["orders", "payment", "report"], 5, 0], orders: [["domain", "db"], 6, 1],
  payment: [["domain", "gateway"], 4, 1], report: [["domain", "db"], 3, 0],
  db: [["domain"], 4, 3], gateway: [[], 2, 0], domain: [[], 8, 0] };   // [deps, classes, abstract]
const ca = Object.fromEntries(Object.keys(pkgs).map(p => [p, 0]));
for (const [deps] of Object.values(pkgs)) deps.forEach(d => ca[d]++);
console.log("package  Ca Ce    I    A    D");
for (const [p, [deps, n, abs]] of Object.entries(pkgs)) {
  const Ce = deps.length, Ca = ca[p], I = Ca + Ce ? Ce / (Ca + Ce) : 0, A = abs / n, D = Math.abs(A + I - 1);
  const zone = D >= 0.5 ? (A + I < 1 ? "  zone of pain" : "  zone of uselessness") : "";
  console.log(p.padEnd(8), String(Ca).padStart(2), String(Ce).padStart(2), ...[I, A, D].map(x => x.toFixed(2).padStart(4)), zone);
}
// LCOM4: methods linked if they share an attribute or one calls the other
const uses = { addMarks: ["marks"], totalMarks: ["marks"], gpa: ["scale"], exportCsv: ["marks"],
  sendEmail: ["mailer"], formatEmail: ["template"], logAccess: ["logfile"] };
const calls = [["gpa", "totalMarks"], ["sendEmail", "formatEmail"]];
const link = Object.fromEntries(Object.keys(uses).map(m => [m, m]));
const root = m => link[m] === m ? m : root(link[m]);
const ms = Object.keys(uses);
ms.forEach((a, i) => ms.slice(i + 1).forEach(b => { if (uses[a].some(x => uses[b].includes(x))) link[root(a)] = root(b); }));
calls.forEach(([a, b]) => { link[root(a)] = root(b); });
const groups = {}; ms.forEach(m => (groups[root(m)] ||= []).push(m));
console.log("LCOM4 =", Object.keys(groups).length, "->", Object.values(groups).map(g => g.join(",")).join(" | "));
const paths = n => n * (n - 1) / 2;
console.log("communication paths: 6 people =", paths(6), " 9 people =", paths(9), " added =", paths(9) - paths(6));

আউটপুট:

package  Ca Ce    I    A    D
app       0  3 1.00 0.00 0.00 
orders    1  2 0.67 0.17 0.17 
payment   1  2 0.67 0.25 0.08 
report    1  2 0.67 0.00 0.33 
db        2  1 0.33 0.75 0.08 
gateway   1  0 0.00 0.00 1.00   zone of pain
domain    4  0 0.00 0.00 1.00   zone of pain
LCOM4 = 3 -> addMarks,totalMarks,gpa,exportCsv | sendEmail,formatEmail | logAccess
communication paths: 6 people = 15  9 people = 36  added = 21

টেবিলটি ৫.২-এর উত্তর: domain আর gateway দুটিই zone of pain-এ (D = ১.০০)। LCOM4-এর লাইন ৫.৩ — তিনটি দল; শেষ লাইন ৫.৪-এর ১৫, ৩৬ আর ২১. LCOM4 বের করা হয়েছে union-find দিয়ে: যুক্ত দুটি method-এর “মূল” এক করে দেওয়া, শেষে কয়টি আলাদা মূল থাকল তা গোনা।

৫.৪(সহজ) ৬ জনের একটি দলে কতগুলো যোগাযোগের পথ? দেরি হওয়া project-এ আরও ৩ জন যোগ করলে কতগুলো নতুন পথ তৈরি হয়?
paths(n) = n(n - 1) / 2
paths(6) = 6 x 5 / 2 = 15
paths(9) = 9 x 8 / 2 = 36
new paths = 36 - 15 = 21

লোক ৫০% বাড়ল (৬ → ৯), কিন্তু যোগাযোগের পথ বাড়ল ১৪০% (১৫ → ৩৬)। সাথে নতুনদের শেখানোর সময় — এটাই Brooks-এর সূত্রের (১৯৭৫) পেছনের হিসাব: দেরি হওয়া project-এ লোক যোগ করলে তা আরও দেরি করে। ছোট দল আর পরিষ্কার interface এই সংখ্যা কমায়। ১৫টি পথ; নতুন ২১টি, মোট ৩৬.

৫.৫(কঠিন) আটটি ফাইলের commit-সংখ্যা: auth.py — Rafi ১২, Mitu ৩; cart.py — Rafi ৭, Tanvir ৫; pay.py — Rafi ৯; search.py — Mitu ১০, Rafi ১; ui.js — Sumi ৮, Mitu ৪; form.js — Sumi ৬; deploy.yml — Rafi ৪, Tanvir ১; README.md — Sumi ২, Rafi ২, Tanvir ১. সরল নিয়ম: কোনো লেখক একটি ফাইল “জানেন” যদি তার অন্তত ২৫% commit তাঁর; প্রতিবার যিনি সবচেয়ে বেশি ফাইল জানেন তাঁকে সরান (সমান হলে বর্ণক্রমে আগে), অর্ধেকের বেশি ফাইল অনাথ হলে থামুন। Bus factor কত?
knows (>= 25%):
  auth: Rafi (12/15 = 0.80; Mitu 0.20)      cart: Rafi 0.58, Tanvir 0.42
  pay: Rafi                                  search: Mitu (Rafi 0.09)
  ui: Sumi 0.67, Mitu 0.33                   form: Sumi
  deploy: Rafi (Tanvir 0.20)                 README: Sumi 0.40, Rafi 0.40 (Tanvir 0.20)
files known: Rafi 5, Sumi 3, Mitu 2, Tanvir 1
remove Rafi -> orphans: auth, pay, deploy = 3/8   (not more than half)
recount: Sumi 3, Mitu 2, Tanvir 1 -> remove Sumi
-> orphans: auth, pay, deploy, form, README = 5/8 > 4   stop
bus factor = 2

দুজন (Rafi আর Sumi) হঠাৎ না থাকলে আটটির পাঁচটি ফাইল কেউ জানেন না। ২৫%-এর সীমায় Tanvir README জানেন না (২০%) — সীমা বদলালে উত্তরও বদলায়, আর গবেষণার আসল পদ্ধতি (পর্ব ৬৩-এ উল্লেখিত Avelino ও সহকর্মীদের ২০১৬ সালের কাজ) আরও সূক্ষ্ম। তাই উত্তরে নিয়মটি লিখে দিন। প্রতিকার: pairing আর review-তে auth ও pay-এ দ্বিতীয় একজনকে যুক্ত করা। Bus factor = ২.

# Bus (truck) factor, simplified: an author "knows" a file if they made >= 25% of
# its commits; remove the author who knows most files until > half the files are orphaned.
commits = {
    "src/auth.py":    {"Rafi": 12, "Mitu": 3},
    "src/cart.py":    {"Rafi": 7, "Tanvir": 5},
    "src/pay.py":     {"Rafi": 9},
    "src/search.py":  {"Mitu": 10, "Rafi": 1},
    "web/ui.js":      {"Sumi": 8, "Mitu": 4},
    "web/form.js":    {"Sumi": 6},
    "ops/deploy.yml": {"Rafi": 4, "Tanvir": 1},
    "docs/README.md": {"Sumi": 2, "Rafi": 2, "Tanvir": 1},
}
SHARE = 0.25
knows = {f: {a for a, c in m.items() if c / sum(m.values()) >= SHARE} for f, m in commits.items()}
for f, who in knows.items():
    print(f"{f:15} known by {', '.join(sorted(who))}")
removed, n = [], len(knows)
while True:
    left = {f: who - set(removed) for f, who in knows.items()}
    orphans = sorted(f for f, who in left.items() if not who)
    print(f"removed {removed or '-'} -> orphans {len(orphans)}/{n} {orphans}")
    if len(orphans) > n / 2:
        break
    count = {}
    for who in left.values():
        for a in who:
            count[a] = count.get(a, 0) + 1
    removed.append(max(sorted(count), key=count.get))   # ties: alphabetical first
print("bus factor =", len(removed))

আউটপুট:

src/auth.py     known by Rafi
src/cart.py     known by Rafi, Tanvir
src/pay.py      known by Rafi
src/search.py   known by Mitu
web/ui.js       known by Mitu, Sumi
web/form.js     known by Sumi
ops/deploy.yml  known by Rafi
docs/README.md  known by Rafi, Sumi
removed - -> orphans 0/8 []
removed ['Rafi'] -> orphans 3/8 ['ops/deploy.yml', 'src/auth.py', 'src/pay.py']
removed ['Rafi', 'Sumi'] -> orphans 5/8 ['docs/README.md', 'ops/deploy.yml', 'src/auth.py', 'src/pay.py', 'web/form.js']
bus factor = 2

৫.৫-এর হাতের হিসাবের সাথে মেলে: প্রথমে Rafi (৫টি ফাইল জানেন) সরলে ৩টি অনাথ, তারপর Sumi সরলে ৫টি — আটটির অর্ধেকের বেশি, তাই bus factor ২. SHARE ০.২০ করলে Tanvir README আর deploy.yml-ও “জানেন”, উত্তর বদলায় কি না দেখুন — নিয়মই উত্তর ঠিক করে।

(সহজ) একটি package-এর ওপর ৬টি package নির্ভর করে, আর এটি ২টির ওপর নির্ভর করে। Martin-এর instability I কত?

  • 0.75
  • 3.00
  • 0.33
  • 0.25

(সহজ) ৮ জনের একটি দলে দুজন-দুজন করে মোট কতগুলো যোগাযোগের পথ?

  • 64
  • 28
  • 56
  • 7

(মাঝারি) একটি package-এর abstractness A = ০.২ আর instability I = ০.৩. Main sequence থেকে দূরত্ব D কত, আর এটি কোন দিকে?

  • 0.5 — zone of pain-এর দিকে
  • 0.5 — zone of uselessness-এর দিকে
  • 0.1 — main sequence-এর কাছে
  • 0.5 — ঠিক main sequence-এর ওপর

৬ · Testing — partition, boundary, decision table, pairwise, V(G), coverage আর mutation

ঝালিয়ে নিন: পর্ব ৪৫ · Testing-এর মৌলিক (exhaustive testing কেন অসম্ভব), পর্ব ৪৭ · Test case নকশা (EP, BVA, decision table, pairwise), পর্ব ৫০ · Coverage আর complexity (V(G), MC/DC, mutation).

সূত্রের কার্ড

EP ও BVA: k-টি valid range পাশাপাশি থাকলে partition k + ২ (দুই পাশে invalid); ২-মান BVA-তে ২k + ২টি আর ৩-মান BVA-তে ৪k + ২টি মান (integer, পুনরাবৃত্তি বাদে)। এক range-এ: EP ৩, ২-মান ৪, ৩-মান ৬.

Decision table: n-টি Y/N শর্তে 2nটি rule; একই কাজ আর এক শর্তে পার্থক্য হলে দুটি rule মিশে “−”। Pairwise: ন্যূনতম suite ≥ দুটি সবচেয়ে বড় মান-সংখ্যার গুণফল।

V(G): E − N + ২P = decision + ১ = region-এর সংখ্যা (planar graph). MC/DC: n-টি শর্তের and/or-এ সাধারণত n + ১টি test; multiple-condition 2n. Mutation score = killed ÷ (মোট − equivalent).

Black-box: partition, boundary, decision table আর pairwise

৬.১(সহজ) একটি অর্ডার ফর্মে “পরিমাণ” integer, বৈধ ১ থেকে ৫০. Equivalence class কয়টি, আর ২-মান ও ৩-মান BVA-তে কোন মানগুলো test করবেন?
classes: invalid low (<= 0) | valid 1..50 | invalid high (>= 51)   -> 3
2-value BVA: 0, 1, 50, 51                  -> 4 values
3-value BVA: 0, 1, 2, 49, 50, 51           -> 6 values

২-মানে প্রতিটি সীমা আর অন্য পাশের নিকটতম মান; ৩-মানে সীমার দুই প্রতিবেশীও। ৩-মানের ২ এমন ভুল ধরে, যেখানে কোডে qty >= 1-এর বদলে qty == 1 লেখা — ২-মানের ০ আর ১ তা ধরতে পারে না; ৪৯ ওপরের সীমায় একই কাজ করে। খালি ঘর, অক্ষর বা দশমিকের মতো ধরনের দিক থেকে invalid partition আলাদা গুনতে হবে, যদি প্রশ্ন চায়। ৩টি class; ২-মানে ৪টি, ৩-মানে ৬টি মান।

৬.২(মাঝারি) বাসের ভাড়ায় বয়স (integer) অনুযায়ী তিন দল: শিশু ০–১২, প্রাপ্তবয়স্ক ১৩–৫৯, প্রবীণ ৬০–১২০. সংখ্যার দিকে partition কয়টি? ২-মান আর ৩-মান BVA-র মানগুলোর তালিকা আর সংখ্যা দিন।
partitions: <0 | 0-12 | 13-59 | 60-120 | >120         -> 5
2-value: -1, 0, 12, 13, 59, 60, 120, 121               -> 8
3-value: -1, 0, 1, 11, 12, 13, 14, 58, 59, 60, 61,
         119, 120, 121                                  -> 14

পাশাপাশি দুটি partition-এর সীমা (১২ আর ১৩, ৫৯ আর ৬০) একে অপরের off point, তাই ২-মানে বাড়তি মান লাগে শুধু দুই প্রান্তে (−১, ১২১)। ৩-মানে পুনরাবৃত্তি বাদ দিতে ভুলবেন না — ১২-র প্রতিবেশী ১৩ আর ১৩-র প্রতিবেশী ১২ একই মান। সূত্রে মিলিয়ে দেখুন: k = ৩ হলে ২k + ২ = ৮ আর ৪k + ২ = ১৪. ৫টি partition; ৮টি আর ১৪টি মান।

৬.৩(মাঝারি) একটি কাল্পনিক বৃত্তির নিয়ম: GPA ≥ ৩.৫ আর পারিবারিক আয় সীমার নিচে হলে ১০০%; GPA ≥ ৩.৫ কিন্তু আয় বেশি হলে ৫০%; GPA ৩.৫-এর কম হলে খেলোয়াড় কোটায় ২৫%, নইলে ০. তিনটি শর্ত (C1 GPA ≥ ৩.৫, C2 আয় কম, C3 খেলোয়াড়)। পূর্ণ decision table-এ কয়টি rule, আর ছোট করার পরে কয়টি?
full table: 2^3 = 8 rules
 C1 GPA>=3.5   Y   Y   Y   Y   N   N   N   N
 C2 low income Y   Y   N   N   Y   Y   N   N
 C3 sports     Y   N   Y   N   Y   N   Y   N
 waiver %     100 100  50  50  25   0  25   0
collapsed:
 C1            Y   Y   N   N
 C2            Y   N   -   -
 C3            -   -   Y   N
 waiver %     100  50  25   0      -> 4 rules (4 tests)

YYY আর YYN-এর কাজ একই (১০০) আর শুধু C3-এ পার্থক্য, তাই মিশে YY−। একইভাবে YN−, আর N-এর দিকে C2-র প্রভাব নেই বলে NYY ও NNY মিশে N−Y, NYN ও NNN মিশে N−N. প্রতিটি “−” একটি দাবি — কোডে সত্যিই প্রভাব নেই কি না, ঝুঁকি থাকলে একটি বাড়তি test দিয়ে দেখা ভালো। ৮টি rule; ছোট করে ৪টি।

৬.৪(মাঝারি) (ক) তিনটি parameter — browser (৩টি মান), ভাষা (৩টি), ভূমিকা (২টি)। সব মিলনে কয়টি test, আর pairwise suite-এ সবচেয়ে কম কয়টি? (খ) পাঁচটি on/off setting-এর ক্ষেত্রে একই প্রশ্ন।
(a) all combinations = 3 x 3 x 2 = 18
    lower bound = 3 x 3 = 9 (every browser-language pair must appear once)
    a 9-test suite covering all pairs exists -> minimum = 9
(b) all combinations = 2^5 = 32
    lower bound = 2 x 2 = 4, but the true minimum is 6
    (exhaustive search: no 5-row suite covers all 40 pairs)

দুটি বড় parameter-এর সব জোড়া অন্তত একবার আসতেই হবে — তাই গুণফলটি নিম্নসীমা। (ক)-তে এই সীমা পূরণ করা যায়: প্রতিটি browser-ভাষা জোড়ার সাথে ভূমিকা এমনভাবে বসানো যে প্রতিটি browser আর প্রতিটি ভাষার সাথে দুই ভূমিকাই আসে। (খ) ফাঁদ: নিম্নসীমা ৪ হলেও পাঁচটি binary parameter-এ ৬টির কমে হয় না — এটি একটি স্ক্রিপ্টে সব ৫-সারির সমন্বয় পরীক্ষা করে যাচাই করা (চারটি parameter হলে ৫টিই যথেষ্ট)। পরীক্ষায় সাধারণত নিম্নসীমা আর একটি বাস্তব suite চাওয়া হয়। (ক) ১৮ বনাম ৯; (খ) ৩২ বনাম ৬.

White-box: V(G), coverage আর MC/DC

৬.৫(মাঝারি) একটি লাইব্রেরির জরিমানার function: fine = 0; for d = 1..days: if d <= 7: continue; fine += member ? 5 : 10; শেষে if fine > 500: fine = 500; return fine. CFG-র node: ১ শুরু, ২ loop-এর শর্ত, ৩ d <= 7, ৪ member?, ৫ +৫, ৬ +১০, ৭ d বাড়ানো, ৮ fine > 500, ৯ ৫০০-তে আটকানো, ১০ return. Edge: ১→২, ২→৩, ২→৮, ৩→৭, ৩→৪, ৪→৫, ৪→৬, ৫→৭, ৬→৭, ৭→২, ৮→৯, ৮→১০, ৯→১০. V(G) তিন পদ্ধতিতে বের করুন।
(1) E - N + 2P = 13 - 10 + 2 x 1 = 5
(2) decision nodes (2 outgoing edges): 2 (loop), 3 (if), 4 (?:), 8 (if) = 4  ->  4 + 1 = 5
(3) regions (planar drawing, outer one included) = E - N + 2 = 5
basis path testing -> 5 independent paths to test

Ternary ?:-ও একটি দুই-মুখী decision — অনেকে এটি বাদ দিয়ে ৪ লেখেন। tool-ভেদে ?: আর &&-কে গোনার নিয়ম আলাদা (পর্ব ৫০), তাই খাতায় নিয়মটি লিখুন। Sanity check: তিনটি হিসাব একই। Loop থাকায় basis-এর কিছু পথ হুবহু চালানো যায় না (যেমন শূন্যবার loop-এ fine > ৫০০ অসম্ভব) — তখন পর্ব ৫০-এর নিয়মে কাছাকাছি একটি সম্ভব পথ বেছে নিতে হয়। V(G) = ৫.

৬.৬(সহজ) def ship(w, express): cost = 50; if w > 5: cost += 20; if express: cost *= 2; return cost. ১০০% statement coverage, ১০০% branch coverage আর ১০০% path coverage-এর জন্য সবচেয়ে কম কয়টি test লাগে? প্রতিটির একটি উদাহরণ দিন।
statement: 1 test   ship(6, True)  -> 140 (both if-bodies run)
branch   : 2 tests  ship(6, True) -> 140 ;  ship(3, False) -> 50
path     : 4 tests  (T,T) (T,F) (F,T) (F,F): e.g. 140, 70, 100, 50
MC/DC    : 2 tests here (each decision has a single condition = branch)

else ছাড়া if-এ statement আর branch-এর পার্থক্য সবচেয়ে স্পষ্ট: একটি test-এ দুটি body-ই চলে, কিন্তু দুটি F শাখা একবারও নেওয়া হয় না। দুটি স্বাধীন if পরপর থাকায় path ২ × ২ = ৪. Sanity check: branch coverage statement-কে subsume করে, তাই branch-এর suite (২) কখনো statement-এর (১)-এর চেয়ে ছোট হয় না। ১, ২ আর ৪টি test.

৬.৭(কঠিন) Decision (a || b) && c. সত্যসারণির আটটি সারি (a, b, c) ক্রমে T1 = 000 থেকে T8 = 111. প্রতিটি শর্তের independence pair খুঁজে MC/DC-এর ন্যূনতম test-সেট বের করুন। Multiple-condition coverage-এ কয়টি লাগত?
row  a b c  out        independence pairs (only one condition differs, outcome differs)
T1   0 0 0   0         a : (T2, T6)   001 -> 0, 101 -> 1
T2   0 0 1   0         b : (T2, T4)   001 -> 0, 011 -> 1
T3   0 1 0   0         c : (T3, T4), (T5, T6), (T7, T8)
T4   0 1 1   1
T5   1 0 0   0         a and b each have ONE pair, both use T2
T6   1 0 1   1         -> must take T2, T4, T6; add one c pair that reuses them:
T7   1 1 0   0            (T3, T4) or (T5, T6)
T8   1 1 1   1         minimum MC/DC = 4 tests: {T2, T3, T4, T6} or {T2, T4, T5, T6}
multiple-condition coverage = 2^3 = 8 tests

a-র প্রভাব দেখাতে b = ০ আর c = ১ রাখতেই হয় (b = ১ হলে a || b এমনিতেই সত্য, c = ০ হলে পুরোটা এমনিতেই মিথ্যা) — তাই একটিমাত্র জোড়া। ন্যূনতম সংখ্যা n + ১ = ৪, যা and/or-এর decision-এ সাধারণ ফল। Sanity check: সেটে প্রতিটি শর্ত T আর F দুটিই পেয়েছে, আর decision-ও দুই ফল দিয়েছে। ৪টি test (যেমন T2, T3, T4, T6); MCC-তে ৮টি।

# V(G) three ways from an edge list, and a brute-force minimum MC/DC test-set finder.
from itertools import product, combinations

edges = [(1, 2), (2, 3), (2, 8), (3, 7), (3, 4), (4, 5), (4, 6), (5, 7), (6, 7),
         (7, 2), (8, 9), (8, 10), (9, 10)]               # CFG of fine(days, member)
nodes = {x for e in edges for x in e}
out = {}
for a, _ in edges:
    out[a] = out.get(a, 0) + 1
decisions = sum(1 for k in out.values() if k == 2)
print(f"6.5 E={len(edges)} N={len(nodes)} -> V(G) = E - N + 2 = {len(edges) - len(nodes) + 2}; "
      f"decisions + 1 = {decisions + 1}")

def mcdc(name, n, decision):
    rows = list(product([0, 1], repeat=n))
    res = {r: int(bool(decision(*r))) for r in rows}
    pairs = {k: [(i + 1, j + 1) for (i, r), (j, s) in combinations(enumerate(rows), 2)
                 if [x != y for x, y in zip(r, s)].count(True) == 1 and r[k] != s[k] and res[r] != res[s]]
             for k in range(n)}
    for k, p in pairs.items():
        print(f"  condition {k + 1} independence pairs (row numbers): {p}")
    for size in range(1, len(rows) + 1):
        best = [t for t in combinations(range(1, len(rows) + 1), size)
                if all(any(a in t and b in t for a, b in pairs[k]) for k in range(n))]
        if best:
            print(f"{name}: minimum MC/DC = {size} tests (n + 1 = {n + 1}); sets: {best}")
            return

mcdc("6.7 (a or b) and c", 3, lambda a, b, c: (a or b) and c)
mcdc("a and b and c", 3, lambda a, b, c: a and b and c)

আউটপুট:

6.5 E=13 N=10 -> V(G) = E - N + 2 = 5; decisions + 1 = 5
  condition 1 independence pairs (row numbers): [(2, 6)]
  condition 2 independence pairs (row numbers): [(2, 4)]
  condition 3 independence pairs (row numbers): [(3, 4), (5, 6), (7, 8)]
6.7 (a or b) and c: minimum MC/DC = 4 tests (n + 1 = 4); sets: [(2, 3, 4, 6), (2, 4, 5, 6)]
  condition 1 independence pairs (row numbers): [(4, 8)]
  condition 2 independence pairs (row numbers): [(6, 8)]
  condition 3 independence pairs (row numbers): [(7, 8)]
a and b and c: minimum MC/DC = 4 tests (n + 1 = 4); sets: [(4, 6, 7, 8)]

প্রথম লাইন ৬.৫: E − N + ২ = ৫ আর decision + ১ = ৫. তারপর ৬.৭-এর independence pair — a-র একটিই (T2, T6), b-র একটিই (T2, T4) — আর ন্যূনতম দুটি সেট {২, ৩, ৪, ৬} ও {২, ৪, ৫, ৬}. শেষ অংশ a and b and c: সব-T (T8) আর প্রতিটি শর্ত একবার F — ৪টি, যা MCQ-এর উত্তরও। প্রোগ্রামটি ছোট থেকে বড় সব সেট পরীক্ষা করে, তাই যা ছাপে তা সত্যিই ন্যূনতম।

Mutation আর exhaustive testing

৬.৮(মাঝারি) একটি mutation tool ৪০টি mutant বানিয়েছে। Test suite ২৮টি মেরেছে, ১২টি টিকে আছে; পরীক্ষা করে দেখা গেল টিকে থাকাদের ৪টি equivalent. Mutation score কত? নতুন test আরও ৫টি mutant মারলে score কত হবে?
score = killed / (total - equivalent) = 28 / (40 - 4) = 28 / 36 = 77.8%
naive (wrong): 28 / 40 = 70.0%
after 5 more kills: 33 / 36 = 91.7%   (3 non-equivalent survivors left)

Equivalent mutant কোনো test-ই মারতে পারে না, তাই হর থেকে বাদ — নইলে ১০০% কখনো সম্ভব নয়। কোনটি equivalent তা সাধারণভাবে যন্ত্রে নির্ধারণ করা যায় না, মানুষকে দেখতে হয়। বাকি ৩টি টিকে থাকা mutant-ই এখন সবচেয়ে দামি তথ্য: কোন ভুল আপনার test ধরে না। ৭৭.৮%; পরে ৯১.৭%.

৬.৯(সহজ) (ক) একটি function দুটি 16-bit integer নেয়। সব ইনপুট-মিলন test করতে কয়টি test, আর সেকেন্ডে ১০ লাখ test চালালে কত সময়? (খ) একটি ফর্মে চারটি drop-down, মান-সংখ্যা ৩, ৪, ৫ আর ২ — সব মিলন কয়টি?
(a) 2^16 x 2^16 = 2^32 = 4,294,967,296 cases
    4,294,967,296 / 10^6 per second = 4295 s = 71.6 minutes
    three 32-bit inputs: 2^96 ~ 7.9 x 10^28 -> about 2.5 x 10^15 years at the same speed
(b) 3 x 4 x 5 x 2 = 120 combinations

দুটি ছোট integer-এই এক ঘণ্টার বেশি, তিনটি 32-bit-এ মহাবিশ্বের বয়সের চেয়ে অনেক বেশি — এটাই “exhaustive testing অসম্ভব” নীতির সংখ্যাগত রূপ (পর্ব ৪৫), আর EP, BVA আর pairwise-এর কারণ। (ক) ২৩২ ≈ ৪২৯ কোটি test, প্রায় ৭১.৬ মিনিট; (খ) ১২০টি।

// Mutation score = killed / (all mutants - equivalent mutants), on a tiny real function.
const ORIGINAL = `if (weight <= 0) return -1;
let cost = weight > 5 ? 80 : 50;
if (express) cost = cost * 2;
return cost;`;
const MUTANTS = [["M1", "weight > 5", "weight >= 5"], ["M2", "weight <= 0", "weight < 0"],
  ["M3", "cost * 2", "cost + 2"], ["M4", "? 80", "? 81"], ["M5", "cost * 2", "cost + cost"],
  ["M6", "if (express)", "if (!express)"]];
const EQUIVALENT = new Set(["M5"]);                 // a human decided: no input tells M5 apart
const make = body => new Function("weight", "express", body);
const fee = make(ORIGINAL);
const WEAK = [[3, false, 50], [8, true, 160]];
const STRONG = [...WEAK, [5, false, 50], [0, false, -1]];
function score(name, suite) {
  suite.forEach(([w, e, want]) => { if (fee(w, e) !== want) throw new Error("bad test"); });
  let killed = 0;
  for (const [id, find, repl] of MUTANTS) {
    const m = make(ORIGINAL.replace(find, repl));
    const hit = suite.find(([w, e, want]) => m(w, e) !== want);
    if (hit) killed++;
    console.log(`  ${id} ${(find + " -> " + repl).padEnd(28)} ${hit ? "killed by (" + hit.slice(0, 2) + ")" : EQUIVALENT.has(id) ? "survived (equivalent)" : "SURVIVED"}`);
  }
  const s = killed / (MUTANTS.length - EQUIVALENT.size);
  console.log(`${name}: killed ${killed} of ${MUTANTS.length - EQUIVALENT.size} -> score ${(100 * s).toFixed(1)}%`);
}
score("weak suite", WEAK);
score("strong suite", STRONG);
console.log("6.8 score =", (100 * 28 / (40 - 4)).toFixed(1) + "%, after 5 more kills =", (100 * 33 / 36).toFixed(1) + "%");
console.log("6.9 two 16-bit inputs:", 2 ** 32, "cases =", (2 ** 32 / 1e6 / 60).toFixed(1), "min at 1e6 tests/s");

আউটপুট:

  M1 weight > 5 -> weight >= 5    SURVIVED
  M2 weight <= 0 -> weight < 0    SURVIVED
  M3 cost * 2 -> cost + 2         killed by (8,true)
  M4 ? 80 -> ? 81                 killed by (8,true)
  M5 cost * 2 -> cost + cost      survived (equivalent)
  M6 if (express) -> if (!express) killed by (3,false)
weak suite: killed 3 of 5 -> score 60.0%
  M1 weight > 5 -> weight >= 5    killed by (5,false)
  M2 weight <= 0 -> weight < 0    killed by (0,false)
  M3 cost * 2 -> cost + 2         killed by (8,true)
  M4 ? 80 -> ? 81                 killed by (8,true)
  M5 cost * 2 -> cost + cost      survived (equivalent)
  M6 if (express) -> if (!express) killed by (3,false)
strong suite: killed 5 of 5 -> score 100.0%
6.8 score = 77.8%, after 5 more kills = 91.7%
6.9 two 16-bit inputs: 4294967296 cases = 71.6 min at 1e6 tests/s

দুর্বল suite (৩, false) আর (৮, true)-এর branch coverage পূর্ণ, তবু M1 আর M2 টিকে যায় — দুটিই সীমার ভুল (>= বনাম >), আর কোনো test সীমায় নেই। Score ৩ ÷ ৫ = ৬০%. (৫, false) আর (০, false) যোগ করলে দুটিই মরে, score ১০০%. M5 (cost + cost) equivalent — কোনো ইনপুটেই আলাদা ফল দেয় না, তাই হরে নেই। শেষ দুই লাইন ৬.৮ আর ৬.৯-এর সংখ্যা।

(সহজ) একটি function-এর control-flow graph-এ ১৫টি edge আর ১২টি node (একটিই connected অংশ)। Cyclomatic complexity কত?

  • 3
  • 27
  • 5
  • 4

(সহজ) একটি integer ঘরের বৈধ পরিসর ১০ থেকে ২০ (একটিই range). ৩-মান boundary value analysis-এ কয়টি মান test করবেন?

  • 6
  • 4
  • 3
  • 11

(মাঝারি) Decision a && b && c-এর জন্য MC/DC পূরণ করতে সবচেয়ে কম কয়টি test লাগে?

  • 8
  • 2
  • 3
  • 4

(মাঝারি) ৫০টি mutant-এর মধ্যে ৫টি equivalent, আর test suite ৩৬টি মেরেছে। Mutation score কত?

  • 72%
  • 80%
  • 82%
  • 90%

৭ · Process আর flow — Little-এর সূত্র, flow efficiency, DORA আর অগ্রাধিকার

ঝালিয়ে নিন: পর্ব ০৬ · Kanban আর lean (Little, flow efficiency, percentile), পর্ব ২৪ · Requirement management (Kano, RICE, WSJF), পর্ব ৫৯ · Continuous delivery আর DevOps (DORA).

সূত্রের কার্ড

Little: গড় cycle time = গড় WIP ÷ গড় throughput — স্থিতিশীল ব্যবস্থায়, তিনটিই একই সীমানায় মাপা। Flow efficiency = সক্রিয় কাজের সময় ÷ lead time. Percentile = সাজানো তালিকার ⌈q × n⌉-তম মান।

DORA: deployment frequency = সফল deploy ÷ দিন; lead time for changes = commit থেকে production, median; change failure rate = সমস্যা ঘটানো deploy ÷ মোট; time to restore = incident-এর median.

অগ্রাধিকার: RICE = Reach × Impact × Confidence ÷ Effort; WSJF = (business value + time criticality + risk reduction) ÷ job size = cost of delay ÷ size; Kano-তে প্রতিটি উত্তর-জোড়া টেবিল থেকে শ্রেণি, সবচেয়ে বেশিবার আসা শ্রেণিই উত্তর।

৭.১(সহজ) একটি দলের Kanban board-এ গড়ে ২৪টি card চলমান, আর দল সপ্তাহে গড়ে ৬টি card শেষ করে। গড় cycle time কত? Throughput একই রেখে cycle time ২ সপ্তাহে নামাতে WIP কত রাখতে হবে? আর আরেকটি দলে cycle time ৫ দিন, throughput দিনে ৩ — গড় WIP কত?
cycle time = WIP / throughput = 24 / 6 = 4 weeks
target 2 weeks: WIP = cycle time x throughput = 2 x 6 = 12 cards
second team: WIP = 5 days x 3 per day = 15 cards

সূত্রটি গড়ের, আর স্থিতিশীল ব্যবস্থার — যত card ঢোকে প্রায় তত বেরোয়। প্রতি সপ্তাহে backlog বাড়তে থাকলে (আগমন > throughput) পুরো ব্যবস্থায় এটি খাটে না। তিনটি সংখ্যাই একই “শুরু” আর “শেষ” বিন্দু দিয়ে মাপতে হবে। ৪ সপ্তাহ; WIP ১২; দ্বিতীয় দলে গড়ে ১৫টি card.

৭.২(মাঝারি) একটি card-এর যাত্রা (ঘণ্টায়): ready-তে অপেক্ষা ২০, development ৬, review-এর অপেক্ষা ১৪, review ১, test-এর অপেক্ষা ২২, test ৩, deploy-এর অপেক্ষা ৬. Lead time আর flow efficiency কত? সবচেয়ে বড় অপচয় কোথায়?
active = 6 + 1 + 3 = 10 h
waiting = 20 + 14 + 22 + 6 = 62 h
lead time = 10 + 62 = 72 h
flow efficiency = 10 / 72 = 13.9%

কাজের সময়ের প্রায় ছয় গুণ সময় card অপেক্ষায়। সবচেয়ে বড় অপেক্ষা test-এর আগে (২২ ঘণ্টা) — tester-দের WIP বা automated test বাড়ানো সবচেয়ে বেশি লাভ দেবে। developer-কে আরও দ্রুত কোড লেখানো (৬ ঘণ্টা কমানো) প্রায় কিছুই বদলাবে না। Lead time ৭২ ঘণ্টা, flow efficiency প্রায় ১৩.৯%.

৭.৩(মাঝারি) ১৪ দিনে ৮টি production deploy. প্রতিটির commit-গুলোর lead time (ঘণ্টা) আর ফল: D1 — ৩, ২৬; D2 — ৫, সমস্যা, ২৫ মিনিটে স্বাভাবিক; D3 — ২, ৮, ৪; D4 — ৩০; D5 — ৬, ১, সমস্যা, ৯০ মিনিট; D6 — ৭; D7 — ১২; D8 — ৩, সমস্যা, ৪০ মিনিট। Nearest-rank median ধরে DORA-র চারটি metric বের করুন।
deployment frequency = 8 / 14 = 0.57 per day (about 4 per week)
lead times sorted (12 commits): 1 2 3 3 4 5 6 7 8 12 26 30
   median = ceil(0.5 x 12) = 6th value = 5 h      (mean 8.92 h)
change failure rate = 3 / 8 = 37.5%
restore times sorted: 25 40 90 -> ceil(0.5 x 3) = 2nd = 40 min

Lead time প্রতিটি commit-এর জন্য একটি মান — deploy-এর জন্য নয়। গড় (৮.৯২) দুটি দীর্ঘ commit (২৬, ৩০) টেনে তোলে, median নয়; তাই DORA median নেয়। ছোট নমুনায় একটি deploy এদিক-ওদিক হলেই CFR ১২.৫ শতাংশ-বিন্দু বদলায় — সংখ্যার পাশে নমুনার আকারও লিখুন। পড়ার কথা: গতি ভালো, কিন্তু প্রায় তিনটির একটি deploy সমস্যা ঘটাচ্ছে। ০.৫৭/দিন, ৫ ঘণ্টা, ৩৭.৫%, ৪০ মিনিট।

# DORA's four metrics from a small log, plus Little's law, flow efficiency and p85.
from math import ceil

def nearest_rank(xs, q):                     # the q-th percentile, nearest-rank method
    s = sorted(xs)
    return s[ceil(q * len(s)) - 1]

DAYS = 14
deploys = [  # (lead time of each commit in hours, caused a failure?, minutes to restore)
    ([3, 26], False, None), ([5], True, 25), ([2, 8, 4], False, None), ([30], False, None),
    ([6, 1], True, 90), ([7], False, None), ([12], False, None), ([3], True, 40)]
leads = [h for d in deploys for h in d[0]]
fails = [d for d in deploys if d[1]]
print(f"7.3 deploys {len(deploys)} in {DAYS} days -> frequency {len(deploys) / DAYS:.2f}/day")
print(f"    lead time median = {nearest_rank(leads, 0.5)} h of {len(leads)} commits"
      f" (mean {sum(leads) / len(leads):.2f} h)")
print(f"    change failure rate = {sum(d[1] for d in deploys)}/{len(deploys)}"
      f" = {100 * sum(d[1] for d in deploys) / len(deploys):.1f}%")
restores = [d[2] for d in fails]
print(f"    time to restore median = {nearest_rank(restores, 0.5)} min over {len(restores)} incidents")

wip, thru = 24, 6
print(f"7.1 cycle time = WIP / throughput = {wip}/{thru} = {wip / thru:.1f} weeks;"
      f" for 2 weeks keep WIP at {2 * thru}")
active, waits = [6, 1, 3], [20, 14, 22, 6]
lead = sum(active) + sum(waits)
print(f"7.2 flow efficiency = {sum(active)}/{lead} = {100 * sum(active) / lead:.1f}%")
cycle = [2, 3, 1, 5, 2, 8, 4, 3, 2, 6, 3, 1, 12, 4, 2, 3, 7, 5, 2, 9]
print(f"7.5 p50={nearest_rank(cycle, 0.5)} p85={nearest_rank(cycle, 0.85)} "
      f"p95={nearest_rank(cycle, 0.95)} mean={sum(cycle) / len(cycle):.2f} days")

আউটপুট:

7.3 deploys 8 in 14 days -> frequency 0.57/day
    lead time median = 5 h of 12 commits (mean 8.92 h)
    change failure rate = 3/8 = 37.5%
    time to restore median = 40 min over 3 incidents
7.1 cycle time = WIP / throughput = 24/6 = 4.0 weeks; for 2 weeks keep WIP at 12
7.2 flow efficiency = 10/72 = 13.9%
7.5 p50=3 p85=7 p95=9 mean=4.20 days

প্রথম চার লাইন ৭.৩: দিনে ০.৫৭টি deploy, lead time-এর median ৫ ঘণ্টা (১২টি commit-এর ৬ষ্ঠ মান), CFR ৩৭.৫%, আর restore-এর median ৪০ মিনিট। তারপর ৭.১-এর ৪ সপ্তাহ ও WIP ১২, ৭.২-এর ১৩.৯%, আর ৭.৫-এর p50 ৩, p85 ৭, p95 ৯. nearest_rank একটি ফাংশনেই DORA-র median আর Kanban-এর percentile দুটোই হয় — একই নিয়ম।

৭.৪(মাঝারি) তিনটি কাল্পনিক feature. RICE-এর জন্য (reach/quarter, impact, confidence, effort person-month): F1 ডিজিটাল wallet-এ পেমেন্ট (২০০০, ২, ৮০%, ৪); F2 বাংলায় পণ্য খোঁজা (৫০০০, ১, ১০০%, ২); F3 ভর্তি-মৌসুমের বিশেষ delivery slot (৮০০, ৩, ৫০%, ১)। WSJF-এর জন্য (business value, time criticality, risk reduction, job size): F1 (৮, ৩, ২, ৮); F2 (৫, ২, ১, ৩); F3 (৬, ১৩, ৩, ২)। দুই পদ্ধতিতে ক্রম বের করে পার্থক্য ব্যাখ্যা করুন।
RICE = R x I x C / E
  F1: 2000 x 2 x 0.8 / 4 = 800
  F2: 5000 x 1 x 1.0 / 2 = 2500
  F3:  800 x 3 x 0.5 / 1 = 1200      order: F2 > F3 > F1
WSJF = (BV + TC + RR) / size
  F1: (8 + 3 + 2) / 8  = 1.63
  F2: (5 + 2 + 1) / 3  = 2.67
  F3: (6 + 13 + 3) / 2 = 11.00       order: F3 > F2 > F1

RICE-এ বেশি মানুষের কাছে পৌঁছানো F2 এগিয়ে; WSJF-এ সময়ের চাপ (time criticality ১৩) F3-কে এক নম্বরে তোলে — মৌসুম পেরিয়ে গেলে এর মূল্য অনেক কমে, যা RICE-এ ধরা পড়ে না। দুটিতেই F1 শেষে: বড় effort বা বড় job size. সংখ্যাগুলো অনুমান — সূত্র অনুমানকে সাজায়, সত্য বানায় না (পর্ব ২৪)। RICE: F2, F3, F1; WSJF: F3, F2, F1.

৭.৫(মাঝারি) শেষ ২০টি শেষ হওয়া card-এর cycle time (দিন): ২, ৩, ১, ৫, ২, ৮, ৪, ৩, ২, ৬, ৩, ১, ১২, ৪, ২, ৩, ৭, ৫, ২, ৯. Nearest-rank-এ p50, p85 আর p95 বের করুন। আজ শুরু হওয়া একটি card সম্পর্কে ৮৫% নিশ্চয়তায় কী বলবেন?
sorted: 1 1 2 2 2 2 2 3 3 3 3 4 4 5 5 6 7 8 9 12
p50 = ceil(0.50 x 20) = 10th = 3 days
p85 = ceil(0.85 x 20) = 17th = 7 days
p95 = ceil(0.95 x 20) = 19th = 9 days        (mean = 84 / 20 = 4.2 days)

সৎ উত্তর: “৮৫% সম্ভাবনায় ৭ দিনের মধ্যে, ৯৫% সম্ভাবনায় ৯ দিনের মধ্যে।” গড় ৪.২ দিন বললে প্রায় অর্ধেক card-ই দেরিতে মনে হবে, কারণ লম্বা লেজ (১২) গড়কে টানে। Percentile-এর অন্য পদ্ধতিতে (interpolation) সংখ্যা সামান্য বদলাতে পারে, তাই পদ্ধতির নাম লিখুন। p50 = ৩, p85 = ৭, p95 = ৯ দিন।

৭.৬(সহজ) “অর্ডারের live tracking” feature নিয়ে ৮ জনের Kano উত্তর-জোড়া (functional, dysfunctional; ১ পছন্দ, ২ প্রত্যাশিত, ৩ নিরপেক্ষ, ৪ মেনে নেব, ৫ অপছন্দ): ১৫, ২৫, ১৫, ১৪, ১৫, ২৫, ১৩, ১৫. পর্ব ২৪-এর মূল্যায়ন টেবিল ধরে feature-টির শ্রেণি কী?
table (row = functional, column = dysfunctional):
  row 1: Q A A A O     rows 2-4: R I I I M     row 5: R R R R Q
15 -> O (one-dimensional)  x4
25 -> M (must-be)           x2
14 -> A (attractive)        x1
13 -> A (attractive)        x1
majority: O = 4 of 8  ->  one-dimensional (performance) feature

“থাকলে পছন্দ, না থাকলে অপছন্দ” (১৫) মানে যত ভালো, তত খুশি — performance বা one-dimensional. দুজনের কাছে এটি ইতিমধ্যে must-be (২৫) — সময়ের সাথে আনন্দদায়ক feature মৌলিক হয়ে যায়, Kano-র একটি পরিচিত পর্যবেক্ষণ। Sanity check: ৪ + ২ + ১ + ১ = ৮. One-dimensional (performance).

(সহজ) একটি স্থিতিশীল Kanban ব্যবস্থায় গড় WIP ১৮টি card আর throughput দিনে ৩টি। Little-এর সূত্রে গড় cycle time কত?

  • ৫৪ দিন
  • ৬ দিন
  • ০.১৭ দিন
  • ২১ দিন

(সহজ) একটি card-এর lead time ৬৪ ঘণ্টা, যার মধ্যে কেউ সক্রিয়ভাবে কাজ করেছেন মাত্র ৮ ঘণ্টা। Flow efficiency কত?

  • 87.5%
  • 800%
  • 14.3%
  • 12.5%

(মাঝারি) একটি feature-এর reach প্রতি quarter-এ ১০০০ জন, impact ২, confidence ৫০%, effort ২ person-month. RICE score কত?

  • 2000
  • 1000
  • 500
  • 250

(সহজ) এক মাসে ২০টি production deploy-এর ৩টির পরে rollback বা hotfix লেগেছে। Change failure rate কত?

  • 15%
  • 85%
  • 3
  • 17.6%

৮ · Git-এর গোনাগুনি — bisect-এর ধাপ, range আর ahead/behind

সূত্রের কার্ড

Bisect: n টি সন্দেহভাজন commit-এ skip ছাড়া ⌈log2 n⌉টি পরীক্ষা; প্রতিটি skip একটি বাড়তি চালানো।

Range: A..B = B থেকে reachable কিন্তু A থেকে নয় এমন commit; A...B = যেকোনো একটি থেকে reachable কিন্তু দুটি থেকেই নয় (symmetric difference). Merge commit-এর মাধ্যমে যা reachable, তা-ও গোনা হয়।

Ahead/behind: ahead = upstream..local-এর সংখ্যা, behind = local..upstream-এর সংখ্যা; একসাথে git rev-list --left-right --count local...upstream.

৮.১(সহজ) v2.0 tag-এ software ঠিক ছিল, HEAD-এ ভাঙা। v2.0-র পরে HEAD পর্যন্ত (HEAD-সহ) commit আছে (ক) ৩০০টি, (খ) ১০২৪টি, (গ) ১০২৫টি। কোনো commit skip না হলে git bisect-এ সবচেয়ে বেশি কয়টি পরীক্ষা লাগবে? একে একে দেখলে খারাপ ক্ষেত্রে কয়টি?
n = suspects = commits after the good one, up to and including the bad one
(a) n = 300  : 2^8 = 256 < 300 <= 512 = 2^9   -> ceil(log2 300)  = 9 tests
(b) n = 1024 : 2^10 = 1024 exactly            -> ceil(log2 1024) = 10 tests
(c) n = 1025 : just above 2^10                -> ceil(log2 1025) = 11 tests
one by one, worst case: n - 1 tests (299, 1023, 1024) - the last one needs no test

প্রতিটি পরীক্ষা সন্দেহের তালিকা অর্ধেক করে, তাই k টি পরীক্ষায় ২kটি সম্ভাবনা আলাদা করা যায়। ফাঁদ: জানা ভালো commit-টিকেও n-এ গোনা — সেটি সন্দেহভাজন নয়। জানা খারাপটি গোনা হয়, কারণ সেটিই প্রথম খারাপ হতে পারে (পর্ব ৫৫)। একে একে দেখার খারাপ ক্ষেত্রে n − ১টি, কারণ বাকি একটি থাকলে সেটিই উত্তর। Skip করা commit থাকলে সংখ্যা বাড়ে। (ক) ৯, (খ) ১০, (গ) ১১.

৮.২(মাঝারি) main-এ c1 → c2 → c3; c3 থেকে feature branch-এ f1 → f2; তারপর main-এ c4 → c5. (ক) git log main..feature আর git log feature..main কোন commit দেখাবে? (খ) main...feature-এ কয়টি? (গ) feature-এ বসে git rebase main কয়টি commit নতুন করে বসাবে?

একটি scratch repository-তে ঠিক এই ইতিহাস বানিয়ে Git ২.৫৩-এ চালানো হয়েছে (hash আপনার repository-তে আলাদা হবে):

$ git log --oneline --graph --all
* 026020c c5
* 8af12f3 c4
| * b286ca6 f2
| * f4c41e8 f1
|/
* 8e33805 c3
* 632d184 c2
* bf0d89c c1
$ git log --oneline main..feature
b286ca6 f2
f4c41e8 f1
$ git log --oneline feature..main
026020c c5
8af12f3 c4
$ git rev-list --count main...feature
4
$ git rev-list --left-right --count main...feature
2	2
$ git log --oneline -1 $(git merge-base main feature)
8e33805 c3

main..feature মানে “feature থেকে পৌঁছানো যায়, main থেকে নয়” — f1, f2. উল্টো দিকে c4, c5. তিন বিন্দুতে দুই দিকের যোগ, ২ + ২ = ৪; --left-right --count দুটিকে আলাদা করে দেখায় (বাঁয়ে main-এর ২, ডানে feature-এর ২)। merge base c3, তাই rebase ঠিক main..feature-এর commit-গুলো — f1 আর f2 — c5-এর ওপর নতুন hash-এ বসাবে। (ক) f2, f1 আর c5, c4; (খ) ৪; (গ) ২টি।

ধাপ ১ইতিহাস (git log --graph)
* ee82f0c c4         <- main
*   bde15bc M: merge feature
|\
* | 4db7579 c3
| | * 5754fdd f3     <- feature
| |/
| * dc70ad0 f2
| * 1ca1ffb f1
|/
* 42181b9 c2
* 569c0d6 c1
ধাপ ২feature থেকে reachable
from feature (f3), follow parents:
f3 -> f2 -> f1 -> c2 -> c1
R(feature) = {f3,f2,f1,c2,c1}  (5)
ধাপ ৩main থেকে reachable
from main (c4):
c4 -> M; M has 2 parents: c3, f2
c3 -> c2 -> c1    f2 -> f1 -> c2
R(main) = {c4,M,c3,f2,f1,c2,c1} (7)
first-parent: c4,M,c3,c2,c1  (5)
ধাপ ৪বিয়োগ
main..feature = R(feature) - R(main)
  = {f3}              (1)
feature..main = R(main) - R(feature)
  = {c4, M, c3}       (3)
--left-right --count main...feature
3	1
  1. ইতিহাস। c2 থেকে feature-এ f1, f2; main-এ c3; তারপর M-এ feature main-এ merge হয়েছে। এরপর feature-এ f3 আর main-এ c4. Hash-গুলো একটি scratch repository-তে Git ২.৫৩-এ বানানো আসল ইতিহাসের।
  2. feature থেকে কোথায় পৌঁছানো যায়। f3 থেকে parent ধরে পেছনে: f2, f1, c2, c1 — মোট ৫টি commit. এদের কোনোটি থেকে M বা c3-এ যাওয়া যায় না, কারণ তীর শুধু parent-এর দিকে।
  3. main থেকে কোথায় পৌঁছানো যায়। c4 থেকে M; M-এর দুটি parent — c3 আর f2. তাই f2 আর f1-ও main থেকে reachable — মোট ৭টি। শুধু প্রথম parent ধরলে (--first-parent) f1, f2 বাদ, থাকে ৫টি।
  4. বিয়োগ। main..feature-এ থাকে শুধু f3 — অনেকে ভুল করে তিনটি লেখেন। feature..main-এ c4, M আর c3. --left-right --count একসাথে দেখায় ৩ আর ১ — main ৩টি এগিয়ে, feature ১টি।
৮.৩(কঠিন) main-এ c1 → c2; c2 থেকে feature-এ f1 → f2; main-এ c3, তারপর feature-কে main-এ merge করে merge commit M; এরপর feature-এ f3 আর main-এ c4. main..feature আর feature..main-এ কয়টি করে commit? main থেকে মোট কয়টি commit reachable, আর --first-parent ধরে কয়টি?
$ git log --oneline --graph --all
* ee82f0c c4
*   bde15bc M: merge feature
|\
* | 4db7579 c3
| | * 5754fdd f3
| |/
| * dc70ad0 f2
| * 1ca1ffb f1
|/
* 42181b9 c2
* 569c0d6 c1
$ git log --oneline main..feature
5754fdd f3
$ git log --oneline feature..main
ee82f0c c4
bde15bc M: merge feature
4db7579 c3
$ git rev-list --count main
7
$ git rev-list --count --first-parent main
5
$ git log --oneline -1 $(git merge-base main feature)
dc70ad0 f2

বহু উত্তরদাতা main..feature-এ f1, f2, f3 — তিনটি লেখেন। কিন্তু M-এর দ্বিতীয় parent f2, তাই f1 আর f2 এখন main থেকেও reachable; বাকি থাকে শুধু f3. উল্টো দিকে c3, M আর c4 — merge commit-ও একটি commit, গোনা হয়। main থেকে reachable: c1, c2, c3, f1, f2, M, c4 = ৭; প্রথম parent ধরে হাঁটলে f1 আর f2 বাদ, তাই ৫. Merge base এখন f2 (dc70ad0), c2 নয়। ১ আর ৩; reachable ৭, first-parent ৫.

৮.৪(মাঝারি) রাফি আর নীলা একই remote-এ কাজ করেন। দুটি commit-এর পরে নীলা ৩টি commit push করেছেন, আর রাফি নিজের কম্পিউটারে ২টি commit করেছেন (push করেননি)। রাফি git fetch করার পরে git status কী বলবে? তারপর git rebase origin/main (বা git pull --rebase) করলে, কোনো conflict না হলে, ahead/behind কত হবে?
$ git fetch
From ../origin
   bf4ebf7..2312357  main       -> origin/main
$ git status -sb
## main...origin/main [ahead 2, behind 3]
$ git status
On branch main
Your branch and 'origin/main' have diverged,
and have 2 and 3 different commits each, respectively.
  (use "git pull" if you want to integrate the remote branch with yours)
…
$ git rev-list --left-right --count main...origin/main
2	3
$ git rebase origin/main
Successfully rebased and updated refs/heads/main.
$ git status -sb
## main...origin/main [ahead 2]
$ git log --oneline --graph
* db41281 r2
* d447b78 r1
* 2312357 n3
* 4e31114 n2
* f894430 n1
* bf4ebf7 c2
* b23e050 c1

Fetch শুধু origin/main সরায়, রাফির main-কে ছোঁয় না — তাই “diverged”: রাফির ২টি commit remote-এ নেই (ahead ২), নীলার ৩টি রাফির কাছে নেই (behind ৩)। Rebase রাফির ২টি commit নীলার ৩টির ওপরে নতুন করে বসায়; এখন রাফির main origin/main-এর সব commit ধারণ করে (behind ০), আর নিজের ২টি এখনো push হয়নি (ahead ২)। এরপর সাধারণ git push-ই যথেষ্ট, force লাগে না। Fetch-এর পরে ahead ২, behind ৩; rebase-এর পরে ahead ২, behind ০.

(সহজ) git bisect-এ জানা ভালো আর জানা খারাপ commit-এর মাঝে ৫০০টি সন্দেহভাজন commit (খারাপটি সহ)। কোনো skip না হলে সবচেয়ে বেশি কয়টি পরীক্ষা লাগবে?

  • 9
  • 8
  • 250
  • 10

(মাঝারি) main-এ c1 → c2 → c3 → c4. c2 থেকে feature branch-এ f1 → f2 → f3; কোনো merge হয়নি। git rev-list --count main..feature কত দেখাবে?

  • 2
  • 5
  • 3
  • 7

(মাঝারি) git fetch-এর পরে git status -sb দেখাল ## main...origin/main [ahead 2, behind 3]. কোনো conflict ছাড়া git pull --rebase হলে অবস্থা কী হবে?

  • ahead 0, behind 0
  • ahead 5, behind 0
  • ahead 2, behind 3
  • ahead 2, behind 0

৯ · শেষ মুহূর্তের সূত্র-তালিকা

পরীক্ষার আগের রাতে বা হলে ঢোকার আগে এই এক টেবিলই যথেষ্ট। প্রতিটি সারির শেষ কলামে সবচেয়ে সাধারণ ফাঁদ — সূত্রের চেয়ে ওটা মনে রাখাই বেশি কাজের।

বিষয়সূত্রফাঁদ
Function pointUFP = Σ সংখ্যা × weight; VAF = 0.65 + 0.01ΣGSC; AFP = UFP × VAFEQ-কে EO-র weight; VAF ১.৩৫-এর বেশি
Basic COCOMOE = a·KLOCb; D = 2.5·Ed; দল = E/D (organic 2.4/1.05/0.38, semi 3.0/1.12/0.35, embedded 3.6/1.20/0.32)KLOC-এর বদলে LOC; D-তে KLOC বসানো
IntermediateE = ai·KLOCb·EAF, ai = 3.2/3.0/2.8Basic-এর a দিয়ে EAF গুণ
COCOMO IIE = 0.91 + 0.01ΣSF; PM = 2.94·SizeE·ΠEM; TDEV = 3.67·PM0.28 + 0.2(E − 0.91)SF-কে গুণ করা; COCOMO 81-এর ধ্রুবক মেশানো
তিন-বিন্দুte = (O + 4M + P)/6; σ = (P − O)/6; Σvarianceσ যোগ করা
Velocity⌈কম backlog ÷ max v⌉ থেকে ⌈বেশি backlog ÷ min v⌉একটি সংখ্যা বলা; নিচে গোল করা
CPMES = max EFpred; LF = min LSsucc; TF = LS − ES; FF = min ESsucc − EFTF আর FF গুলিয়ে ফেলা
PERTZ = (T − μ)/σ; P = Φ(Z); T = μ + Zσ (৯০% 1.282, ৯৫% 1.645, ৯৯% 2.326)variance-কে σ ধরা; “বেশি লাগার” প্রশ্নে ১ − Φ ভুলে যাওয়া
Crashingslope = ΔC/ΔT; সব critical path কাটে এমন সবচেয়ে সস্তা সেট; slope > দৈনিক পরোক্ষ খরচ হলে থামাnon-critical activity কমানো
Earned valueSV = EV − PV; CV = EV − AC; SPI = EV/PV; CPI = EV/AC; EAC = BAC/CPI; VAC = BAC − EACPV আর AC সরাসরি তুলনা
RiskRE = P × L; RRL = ΔRE ÷ খরচ; EMV = Σp·মূল্য − খরচRRL-এর লবে RE-এর পুরো মান
ReliabilityA = MTBF/(MTBF + MTTR); বন্ধ = (১ − A)·৮৭৬০ hMTBF-এ মেরামতের সময় ঢুকে যাওয়া
Defectdensity = defect/KLOC; DRE = আগে ÷ (আগে + পরে)কোন density দিচ্ছেন না লেখা
Control chartগড় ± ৩σ (নমুনা σ), LCL ≥ ০±২σ বা population σ না বলে নেওয়া
Package metricI = Ce/(Ca + Ce); A = Na/Nc; D = |A + I − ১|Ca আর Ce উল্টে ফেলা
দলপথ = n(n − ১)/২; LCOM4 = component-এর সংখ্যাn² বা n(n − ১) লেখা
BVAএক range: EP ৩, ২-মান ৪, ৩-মান ৬; k পাশাপাশি range: ২k + ২ আর ৪k + ২পুনরাবৃত্তি বাদ না দেওয়া
Decision table ও pairwise2n rule; pairwise ≥ দুই বড় মান-সংখ্যার গুণফলনিম্নসীমাকেই সবসময় উত্তর ধরা
V(G)E − N + 2P = decision + ১ = region?: আর && গোনার নিয়ম না বলা
Coveragestatement ≤ branch ≤ MC/DC (n + ১) ≤ MCC (2n)condition coverage-কে branch-এর চেয়ে শক্ত ভাবা
Mutationscore = killed ÷ (মোট − equivalent)হরে equivalent রাখা
FlowCT = WIP ÷ throughput; FE = সক্রিয় ÷ lead time; pq = ⌈qn⌉-তম মানঅস্থিতিশীল ব্যবস্থায় Little খাটানো
DORAdeploy/দিন; lead time median (commit ধরে); CFR = সমস্যা ÷ deploy; restore mediandeploy ধরে lead time; গড় নেওয়া
অগ্রাধিকারRICE = R·I·C/E; WSJF = (BV + TC + RR)/sizeconfidence শতাংশে রেখে গুণ
Gitbisect ⌈log2 n⌉; A..B = B-এর reachable − A-এর reachable; ahead = up..localmerge-এর মাধ্যমে reachable commit ভুলে যাওয়া

১০ · AI-এর যুগে — numerical-এর উত্তর যাচাই

AI-কে একটি COCOMO বা CPM-এর অঙ্ক দিলে উত্তর আসে পরিষ্কার টেবিলে, আত্মবিশ্বাসী গলায় — আর বেশ প্রায়ই ভুল। ভুলের ধরনগুলো চেনা: COCOMO 81-এর organic ধ্রুবকের সাথে COCOMO II-এর ২.৯৪ মিশিয়ে ফেলা, PERT-এ σ-গুলো সরাসরি যোগ করা, crashing-এ non-critical কিন্তু সস্তা activity কমানো, DRE-তে হর ভুল নেওয়া, mutation score-এ equivalent mutant রেখে দেওয়া, আর Git-এ merge-এর মাধ্যমে reachable commit-গুলো A..B-তে গুনে ফেলা। AI কখনো মনগড়া “standard” মানও বলে (যেমন “IEEE অনুযায়ী V(G) ৭-এর বেশি হলে অবৈধ”) — এমন কোনো নিয়ম নেই।

AI সাধারণত যেখানে ভুল করে

AI-এর ভুলপরিণামকীভাবে ধরবেন
COCOMO-র দুই সংস্করণের ধ্রুবক মেশানো; Intermediate-এ Basic-এর aEffort ২০–৩০% ভুলপর্ব ৬০-এর টেবিল বা মূল model manual-এর সাথে মেলান
PERT-এ σ যোগ, বা variance-কে σ ধরে Zসম্ভাবনা অনেক কম বা বেশিΣvariance-এর বর্গমূল আলাদা লাইনে দেখতে চান
CPM-এর backward pass-এ “বড়টি” নেওয়া; FF-কে TF ধরাভুল critical pathCritical path-এর দৈর্ঘ্য = শেষ EF কি না দেখুন
Crashing-এ শুধু সবচেয়ে কম slope দেখাটাকা নষ্ট, সময় কমে নাপ্রতিটি ধাপে সব পথের দৈর্ঘ্য আবার লিখুন
Bisect-এ জানা ভালো commit-কেও গোনা; A..B-তে merge উপেক্ষাএক ধাপ বেশি; ভুল commit-তালিকাএকটি throwaway repository-তে git rev-list --count চালান
মনগড়া মানদণ্ড, বছর বা “গবেষণায় প্রমাণিত” শতাংশভুল তথ্য উদ্ধৃতিমূল বই, standard বা প্রবন্ধ খুঁজে দেখুন

AI-কে উত্তরদাতা নয়, যাচাইকারী আর প্রশ্ন-বানানোর সহকারী হিসেবে ব্যবহার করুন:

আমি software engineering-এর numerical অনুশীলন করছি। নিচে প্রশ্ন, নিয়ম আর আমার হাতে করা সমাধান দিলাম। প্রশ্ন: [যেমন: ৫০ KLOC semi-detached-এর Intermediate COCOMO / ৮ activity-র CPM আর PERT / একটি decision-এর MC/DC] নিয়ম: COCOMO 81 Basic ও Intermediate (organic 3.2 ইত্যাদি) অথবা COCOMO II.2000 (A = 2.94, B = 0.91); CPM দিন ০ থেকে; PERT-এ activity স্বাধীন; control chart-এ নমুনার σ; percentile nearest-rank. আমার সমাধান: [টেবিল বা ধাপগুলো পেস্ট করুন] ১. পুরো উত্তর আগে দিও না। আমার সমাধানের প্রথম যে ধাপে ভুল আছে, শুধু সেই ধাপটি বলো। ২. তুমি নিজে হিসাব করলে প্রতিটি ঘাত, বর্গমূল আর Z আলাদা লাইনে দেখাও, কোন ধ্রুবক কোন উৎস থেকে নিলে তাও লেখো। ৩. শেষে একটি sanity check দাও: উত্তর বসিয়ে উল্টো হিসাব, critical path-এর দৈর্ঘ্য = শেষ EF, সম্ভাবনা ০–১-এর মধ্যে, V(G) দুই পদ্ধতিতে একই। ৪. একই নিয়মে একটি নতুন, ফাঁদওয়ালা প্রশ্ন দাও — উত্তর লুকিয়ে রাখো। ৫. কোনো standard বা বইয়ের নাম বললে বছরসহ বলো, আর নিশ্চিত না হলে সেটা স্পষ্ট লেখো।

যাচাইয়ের চেকলিস্ট

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

প্রতিটি প্রশ্নে খাতায় হিসাব করে তবে উত্তর বাছুন। ভুল হলে কারণসহ ব্যাখ্যা পাবেন। ওপরের ভাগগুলোর ২৬টি প্রশ্নের সাথে এগুলো মিলিয়ে মোট ৩২টি।

ক্রমপরীক্ষার খাতায় একটি পূর্ণ CPM + PERT উত্তরের ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. Activity, সময় আর পূর্বসূরির টেবিল থেকে network আঁকা
  2. Forward pass — প্রতিটির ES আর EF
  3. Backward pass — প্রতিটির LF আর LS
  4. Total float আর free float, তারপর critical path আর project-এর সময়
  5. Critical path-এর te আর variance যোগ করে μ আর σ
  6. Z = (T − μ) ÷ σ, normal table থেকে সম্ভাবনা, আর এক লাইনের সিদ্ধান্ত

(মাঝারি) চারটি parameter, প্রতিটির ৩টি মান। সব মিলন কয়টি, আর pairwise suite-এর ন্যূনতম আকার কত?

  • 12 আর 6
  • 81 আর 9
  • 27 আর 9
  • 81 আর 3

(মাঝারি) Critical path A-C-E-তে cost slope (হাজার টাকা/দিন): A ১০, C ৪, E ৭; non-critical B-র slope ২. Project এক দিন ছোট করতে প্রথমে কোনটি crash করবেন?

  • B
  • A
  • E
  • C

(সহজ) BAC ৮০০ হাজার টাকা আর বর্তমান CPI ০.৮. এখনকার খরচের হার চললে EAC = BAC ÷ CPI কত?

  • 1000
  • 640
  • 800
  • 960

(সহজ) চারটি স্বাধীন Y/N শর্তের পূর্ণ decision table-এ (ছোট করার আগে) কয়টি rule?

  • 8
  • 4
  • 16
  • 32

(সহজ) সাপ্তাহিক defect-এর গড় ৫০ আর নমুনার σ ৪. প্রচলিত ৩σ নিয়মে control limit কত?

  • UCL 58, LCL 42
  • UCL 62, LCL 38
  • UCL 54, LCL 46
  • UCL 53, LCL 47

(মাঝারি) একটি বিকল্পে খরচ ৩০; সম্ভাবনা ০.৬-এ মূল্য ৮০, আর ০.৪-এ মূল্য ২০ (লাখ টাকা)। এর EMV (খরচ বাদে) কত?

  • 56
  • 20
  • 26
  • 50

শব্দকোষ

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

মনে রাখুন

  1. নিয়ম আর একক আগে: COCOMO-র সংস্করণ, দিন ০ থেকে না ১ থেকে, sample না population σ, nearest-rank, ২-মান না ৩-মান BVA — উত্তরের প্রথম লাইনে লিখুন; নিয়ম বদলালে উত্তর বদলায়।
  2. Estimation: VAF ০.৬৫–১.৩৫; COCOMO-র exponent ১-এর বেশি, তাই আকার দ্বিগুণে কাজ দ্বিগুণের বেশি, অথচ সময় প্রায় একই থাকে; SF exponent-এ, EM গুণফলে; velocity থেকে সবসময় পরিসর।
  3. Schedule: সামনে বড়টি, পেছনে ছোটটি; TF ≥ FF; PERT-এ variance যোগ হয়; crashing-এ সব critical path একসাথে কাটুন আর slope পরোক্ষ খরচ ছাড়ালে থামুন; SPI ও CPI ১-এর কম মানে খারাপ।
  4. Risk, quality আর design: RE = P × L, RRL > ১ লাভজনক; A = MTBF ÷ (MTBF + MTTR); DRE-র হরে মোট defect; I = Ce ÷ (Ca + Ce), D = |A + I − ১|; পথ n(n − ১) ÷ ২.
  5. Testing, flow আর Git: V(G) তিন পদ্ধতিতে একই; MC/DC n + ১; mutation-এর হর থেকে equivalent বাদ; Little = WIP ÷ throughput; DORA-র median commit ধরে; bisect ⌈log2 n⌉; A..B-তে merge-এর মাধ্যমে reachable commit বাদ যায়।

পরের পর্বে: পুরো কোর্সের MCQ প্রশ্নব্যাংক — software engineering আর Git, মডিউল ধরে সাজানো, প্রতিটি অপশনের ব্যাখ্যাসহ। এই পাতার হিসাবগুলো সেখানে দ্রুত সিদ্ধান্তে কাজে লাগবে।

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

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