Dead Code: গুদামঘরে পুরনো জিনিস 'যদি লাগে' বলে আটকে রাখা
Dead Code smell শেখো একটা গুদামঘরের গল্প দিয়ে। দেখো কেন না-চলা কোড আসলে টাকা আর সময় নষ্ট করে, Knight Capital-এর ৪৪০ মিলিয়ন ডলারের ঘটনা থেকে শিখো, আর সহজভাবে সমাধান করো।
🪑 যে গুদামঘরে আর ঢোকা যায় না
ধরো জামাল সাহেবের বাড়িতে একটা গুদামঘর আছে। বাংলাদেশের প্রায় প্রতিটা বাড়িতেই এরকম একটা ঘর থাকে — সেই এক কোণের ঘর বা চিলেকোঠা যেখানে জিনিসপত্র "নিরাপদে রাখার" জন্য যায়। জামাল সাহেবের বাড়িতে এই গুদামঘরের রক্ষক হলেন তার মা। কোনো কিছুই বের হয় না। কখনোই না।
দরজা খোলো। সাবধান! একটা ভাঙা টেবিল দেয়ালে হেলান দিয়ে আছে — "একদিন পা ঠিক করা যাবে," বলেন মা। তার পেছনে একটা শিশুর খাট; সেই শিশু, রুবেল, এখন কলেজের দ্বিতীয় বর্ষে। ছেঁড়া বেতের আসনের তিনটা চেয়ার — "পরের বিয়ের আগে নতুন বেত লাগানো হবে।" ওয়াশিং মেশিনের সাইজের একটা পুরনো টিভি। ২০১৪ সাল থেকে কেউ খোলেনি এমন দুটো ট্রাংক। আর কোণে একটা কুলার যেটা এক গরমের মৌসুমে নষ্ট হয়ে গেছে, রাখা আছে কারণ "মোটরটা একা বেচলেও দাম পাওয়া যাবে।"
প্রতিটা জিনিসই একই যাদুর কথা বলে রাখা হয়েছে: "যদি লাগে।"
এখন হিসাব করো এই "বিনামূল্যের" storage আসলে কত খরচ করাচ্ছে। গুদামঘর এতটাই ভরা যে পরিবারের আসলে দরকারি জিনিস — মই, টুলবক্স, ঈদের সাজসজ্জা — পাঁচটা মৃত জিনিস সরানো ছাড়া পাওয়া যায় না। প্রতিটা ঈদের আগের পরিষ্কারে একটা পুরো দিন বেশি লাগে। প্রতিটা জিনিস তুলতে হয়, ধুলো ঝাড়তে হয়, আলোচনা করতে হয় — "এটা রাখব?" — "মাকে জিজ্ঞেস করো" — "মা বলেন রাখো" — আর আবার রেখে দিতে হয়। দুই বছর আগে পরিবার বাড়ি বদলানোর সময়, মুভারদের ভাঙা টেবিলটা pack, load আর unload করতে টাকা দিতে হয়েছিল। এমন একটা টেবিলে কেউ আর কখনো বসবে না।
আর তারপর, গত গরমে, তারিক বেড়াতে এলো। গরম ছিল। সে গুদামঘরে পুরনো কুলারটা পেল। ভাবল — "কাজ না করলে রাখবে কেন?" — হলঘরে টেনে আনল, পানি ভরল, আর প্লাগ লাগাল। Short circuit-এ পুরো ফ্লোরের বিদ্যুৎ চলে গেল। Inverter থেকে এমন একটা শব্দ বের হলো যেটা কেউ inverter থেকে শুনতে চায় না।
এটাই হলো Dead Code smell — একটার পর একটা: এটা দরকারি জিনিস আটকে রাখে, প্রতিটা পরিষ্কার আর প্রতিটা বদলে খরচ যোগ করে, আর একদিন কেউ না কেউ এটা plug করে দেয়।
🤔 এই smell আসলে কী?
Dead Code হলো এমন কোড যেটা কখনো execute হতে পারে না, অথবা যার result কখনো ব্যবহার হয় না। একটা uncalled method, একটা unreachable branch, একটা unread parameter, একটা computed-but-ignored variable, একটা commented-out block, এক বছর ধরে সব জায়গায় বন্ধ থাকা flag-এর পেছনে একটা feature — সবই project-এর বোঝা। কোনো কাজ নেই, শুধু ওজন।
এটা যেসব রূপে আসে:
| Dead code-এর রূপ | উদাহরণ |
|---|---|
| অব্যবহৃত method/class/field | গত বছরের refactor থেকে কেউ reference করে না এমন একটা helper |
| Unreachable branch | if (false), exhaustive return-এর পরে একটা case, সবসময় একটাই মান থাকে এমন flag |
| Unread parameter | প্রতিটা caller পাঠায়, কিন্তু function-এর ভেতরে কখনো পড়া হয় না |
| Unused result | একটা variable হিসাব করা হয়, তারপর ignore করা হয় |
| Commented-out code | চল্লিশ লাইন ঘুমন্ত কোড "যদি দরকার হয়" বলে রাখা |
| Dark feature | পুরো একটা module শুধুমাত্র একটা config switch দিয়ে পৌঁছানো যায় যেটা এক বছর ধরে প্রতিটা environment-এ বন্ধ |
একটু ভাবো — আমাদের আগের পোস্টের সাথে এর মিল আছে। Commented-out code হলো Comments smell আর Dead Code smell হাত মেলাচ্ছে। এটা হলো comment-কে ছদ্মবেশ হিসেবে পরা dead code।
Dead code নিয়ে সবচেয়ে মুক্তির কথা হলো: version control ইতিমধ্যেই সবকিছু রাখে। তুমি যে line-ই মুছো না কেন, সেটা Git history-তে চিরকাল থাকে। git log -S "functionName" দিলে সেকেন্ডের মধ্যে পাবে। Codebase থেকে মুছে ফেলা মানে ধ্বংস করা না — মানে হলো living room থেকে একটা নিখুঁতভাবে সাজানো museum-এ নিয়ে যাওয়া। "হয়তো একদিন দরকার হবে" — এটা একটা ভালো commit message লেখার কারণ হতে পারে, codebase-এ লাশ রেখে দেওয়ার কারণ না।
এখানে একটা map-এ পুরো ছবিটা দেখো:
🔍 কীভাবে চিনবে
তোমার পরের code-reading session-এ এই checklist দিয়ে দেখো:
- একটা method, class, বা field যেটা project-wide search করলে শূন্য reference পাওয়া যায়।
- এমন একটা condition যেটা কখনো true হতে পারে না — কোনো flag hard-code করা, exhaustive return-এর পরে একটা check, অসম্ভব case-এর জন্য একটা
else। - এমন একটা parameter যেটা আসে কিন্তু function-এর ভেতরে কখনো পড়া হয় না।
- এমন একটা variable যেটা হিসাব করা হয় কিন্তু আর কখনো ব্যবহার হয় না।
- Commented-out block — বিশেষ করে বড়গুলো যেগুলোর নিজেদের commented-out comment আছে।
- একটা "feature" শুধুমাত্র একটা configuration switch-এর মাধ্যমে পৌঁছানো যায় যেটা যতদিন কেউ মনে রাখতে পারে ততদিন ধরে প্রতিটা environment-এ বন্ধ।
- Defensive branch এমন পরিস্থিতির জন্য যেটা সিস্টেমের বাকি অংশ বছরের পর বছর ধরে আর তৈরি করে না।
তোমার tools হলো চমৎকার লাশ-সন্ধানী। এগুলো ব্যবহার করো:
| Tool | কী খোঁজে |
|---|---|
| Compiler warnings | Unused variables, unreachable statements |
| Linters (ESLint, Roslyn analyzers) | Unused imports, parameters, private members |
| IDE inspections | Solution জুড়ে zero usage আছে এমন symbols |
| Real run থেকে code coverage | পুরো traffic-এর নিচেও যে path কখনো execute হয় না |
| Dependency analysis | কিছুই import করে না এমন পুরো module |
| Feature-flag dashboards | মাসের পর মাস একটা মানে আটকে থাকা flag |
দল যখন পুরনো codebase-এ এরকম audit চালায়, লাশগুলো সাধারণত এই ভাগে পড়ে:
⚠️ এটা কেন সমস্যা
"কিন্তু এটা তো চলে না — ক্ষতি কী?" চারটা উপায়ে ক্ষতি করে।
খরচ ১: এটা জীবিতের মতো পড়া হয়। ধরো নাসরিন নতুন team-এ join করেছে। সে unused method মনোযোগ দিয়ে পড়ে, trace করে এটা কী করে, ভাবে কোথায় fits করে — বিশ মিনিট পরে আবিষ্কার করে কোথাও fits করে না। Dead code নিজেকে announce করে না। ঠিক living code-এর মতোই দেখায়। তাই প্রতিটা মানুষের, প্রতিবার, সময় চুরি করে।
খরচ ২: এটা সিস্টেম সম্পর্কে মিথ্যা বলে। পাঠকরা এমন behavior নিয়ে চিন্তা করে যেটা কখনো হতে পারে না। "আহ, তাহলে legacy format চাইলে আলাদাভাবে render করি" — না, ২০২২ সাল থেকে সেই path unreachable। ভুল mental model মানে ভুল সিদ্ধান্ত।
খরচ ৩: এটা প্রতিটা বড় পরিবর্তনে কর নেয়। একটা class rename করো, একটা framework upgrade করো, একটা API migrate করো — dead code-ও build ভেঙে দেয়। তুমি ঠিক করো, test করো, review করো। পুরো maintenance মূল্য, শূন্য value। ঠিক যেন মুভাররা সাবধানে ভাঙা টেবিল pack করছে।
এই কর constant না — লাশের সংখ্যা বাড়ার সাথে সাথে বাড়তে থাকে। কারণ প্রতিটা survey, প্রতিটা upgrade, আর প্রতিটা onboarding সবগুলোর পাশ দিয়ে হেঁটে যায়:
খরচ ৪: এটা জেগে উঠতে পারে — আর এটাই বিপর্যয়। ২০১২ সালে Knight Capital নামের একটা বিশাল আমেরিকান trading firm নতুন কোড deploy করেছিল। সেটা একটা পুরনো feature flag পুনরায় ব্যবহার করেছিল। সেই flag তখনও একটা dead code-এর সাথে সংযুক্ত ছিল — "Power Peg" নামের একটা অপ্রচলিত test routine, প্রায় আট বছর ধরে dormant। Deployment আটটার মধ্যে একটা server miss করেছিল। Repurposed flag লাশটাকে সক্রিয় করল। Dead code real orders live stock market-এ fire করতে শুরু করল। প্রায় ৪৫ মিনিটে Knight Capital প্রায় ৪৪০ মিলিয়ন ডলার হারাল আর প্রায় শেষ হয়ে গেল। পুরনো কুলার plug করা হলো, আর এটা মাত্র একটা ফ্লোরের বিদ্যুতের চেয়ে অনেক বেশি ধ্বংস করল।
Knight Capital-এর sequence দেখো — শেষটা পর্যন্ত প্রতিটা পদক্ষেপ ছোট আর যুক্তিযুক্ত মনে হয়:
কলেজ কর্নার: Knight Capital হলো deployment-risk literature-এর canonical case study। আর শিক্ষাটা শুধু "dead code মুছে ফেলো"-র চেয়ে আরো গভীর। SEC-এর post-incident report একটা compound failure দেখিয়েছে: আট বছর ধরে রাখা dead code, retire না করে repurposed একটা feature flag, একটা manual deployment যেটা চুপচাপ একটা server miss করল, আর অষ্টম server যে আলাদা হয়ে গেছে তার কোনো alert নেই। আনুষ্ঠানিকভাবে, dead code সিস্টেমের state space বড় করে — সিস্টেম যত বেশি configuration-এ থাকতে পারে, কেউ তার সব নিয়ে চিন্তা করে না। প্রতিটা dormant path deployment, flag flip, বা config edit থেকে তৈরি হতে পারা combination বাড়িয়ে দেয়। Dead code মুছে ফেলা তাই housekeeping না — এটা হলো reachable state space-কে তুমি আসলে যেটা test করো সেই অংশে কমিয়ে আনা।
এখানে প্রতিটা dead code-এর জীবনের গল্প — আর সেই cleanup-day exit যেটা আমরা সবার জন্য চাই:
💻 বাস্তব code উদাহরণ
ধরো জামাল সাহেবের গুদামঘর, এখন একটা billing module হিসেবে। প্রতিটা ধরনের লাশ আছে এখানে।
// Smelly version: a storeroom with the door barely closing
class InvoiceService {
// no caller passes legacyFormat=true since the 2023 migration
renderInvoice(order: Order, legacyFormat = false): string {
if (legacyFormat) {
return this.renderLegacy(order); // unreachable in practice
}
const lines = order.lines.map(formatLine);
const discount = this.computeDiscount(order); // computed, never used!
const gstNote = "GST as applicable"; // never used either
return buildDocument(lines);
}
// the broken table: nothing calls this anymore
private renderLegacy(order: Order): string {
return order.lines.map((l) => l.name).join(" | ");
}
// the old cooler: kept because "the motor is worth something"
private computeDiscount(order: Order): number {
return order.total > 5000 ? order.total * 0.05 : 0;
}
// exportToFloppyFormat(order: Order): string {
// // 30 more lines of commented-out 2019 code
// // "do not delete - might need for the old client"
// // (the old client closed in 2021)
// }
}লাশের তালিকা:
legacyFormatparameter — প্রতিটা callerfalse(বা কিছুই না) pass করে। প্রতিটা call site-এ একটা unread knob।if (legacyFormat)branch আরrenderLegacy— unreachable। কিন্তু পাঠকরা এখনও এগুলো পড়বে।discountআরgstNote— হিসাব করা হয়ে ফেলে দেওয়া হয়। অকেজো থেকেও খারাপ: একজন পাঠক এখন ভাবে invoice-এ discount প্রযোজ্য। সেটা হয় না। কোড মিথ্যা বলছে।exportToFloppyFormat— ২০১৯ সাল থেকে commented-out, এমন একটা client-এর কথা বলে রাখা যেটা ২০২১ সালে বন্ধ হয়ে গেছে।
Class-diagram আকারে গুদামঘরটা এরকম দেখায় — দেখো কতটা structure আসলে লাশ:
🧹 ধাপে ধাপে পরিষ্কার করা
Dead code-এর সমাধান পুরো smell catalog-এ সবচেয়ে সহজ: মুছে ফেলো। কিন্তু professional হিসেবে করো, bulldozer চালানোর মতো না।
ধাপ ১: দাফনের আগে মৃত্যু নিশ্চিত করো। প্রতিটা suspect-এর জন্য পুরো project search করো। কৌশলী caller-দের কথা মনে রেখো: reflection, dependency injection, serialization, string-keyed routes, scheduled jobs, আর public API-এর বাইরের consumer। renderLegacy private আর unreferenced: নিরাপদ। legacyFormat parameter: প্রতিটা call site check করো।
ধাপ ২: ছোট, labeled commit-এ মুছে ফেলো। প্রতিটা লাশের জন্য একটা commit। Message রাখো এরকম: Remove unused legacy invoice rendering (unreachable since 2023 migration)। ভবিষ্যতে কেউ এটা খুঁজতে চাইলে এই commit হলো museum label।
ধাপ ৩: প্রতিটা deletion পরেরটা দেখিয়ে দেবে। legacyFormat branch সরালে renderLegacy formally uncalled হয়ে যায় — একই pass-এ মুছে ফেলো। discount সরালে computeDiscount uncalled হয় — সেটাও যায়। Dead code chain-এ আসে। পুরো chain টানো।
ধাপ ৪: Test চালাও, তারপর যা বাকি আছে দেখো।
// Clean version: only the living remain
class InvoiceService {
renderInvoice(order: Order): string {
const lines = order.lines.map(formatLine);
return buildDocument(lines);
}
}চল্লিশের বদলে বারো লাইন। যে line গুলো থাকে সেগুলো সত্য — চলে, গুরুত্বপূর্ণ, আর একজন পাঠক সম্পূর্ণ বিশ্বাস করতে পারে।
ধাপ ৫: একটু জীবিতদের জন্য কোমল refactoring ব্যবহার করো। মাঝে মাঝে deletion একটা class বা method এত পাতলা করে দেয় যে সে আর তার জায়গা পায় না:
- Deletion-এর কারণে ফাঁকা হয়ে যাওয়া একটা class তার শেষ remaining user-এর সাথে ভাঁজ করা যায় Inline Class দিয়ে — এখানেই Dead Code তার cousin Lazy Class-এর সাথে দেখা হয়।
- ঠিক একটা জায়গা থেকে call হয় এমন একটা method, কোনো স্পষ্টতা যোগ না করে, Inline Method দিয়ে caller-এ মিশিয়ে দেওয়া যায়।
🟦 C#-এ একই smell (আর Python bonus)
ধরো একটা C# order processor তার নিজের গুদামঘর নিয়ে বসে আছে:
// Before: three corpses in fifteen lines
public class OrderProcessor
{
private const bool UseNewPipeline = true; // always true since v2
public Receipt Process(Order order, bool audit = false) // audit: never read
{
if (!UseNewPipeline)
{
return ProcessOld(order); // unreachable forever
}
var tax = order.Total * 0.18m; // computed, never used
return new Receipt(order.Total);
}
private Receipt ProcessOld(Order order) => // uncalled
new Receipt(order.Total * 1.02m);
}দাফনের পর:
// After: everything present is alive
public class OrderProcessor
{
public Receipt Process(Order order) => new Receipt(order.Total);
}আর classic Python version, Fowler-এর catalog spirit থেকে:
# Before: a parameter and a branch nothing can reach
def render_invoice(order, legacy_format=False):
if legacy_format: # no caller passes True anymore
return _render_legacy(order)
lines = [format_line(l) for l in order.lines]
discount = compute_discount(order) # computed, never used
return build_document(lines)
# After
def render_invoice(order):
lines = [format_line(l) for l in order.lines]
return build_document(lines)ছোট, সৎ, দ্রুত পড়া যায় — আর _render_legacy একই commit-এ বেরিয়ে যায়।
কলেজ কর্নার: Compiler আর bundler machine level-এ এই smell-এর বিরুদ্ধে স্বয়ংক্রিয়ভাবে লড়াই করে — নামগুলো জেনে রাখা ভালো। Dead-code elimination (DCE) হলো একটা standard compiler optimization যেটা provably unreachable instructions সরিয়ে দেয়। JavaScript bundler-এ (Rollup, esbuild, webpack) tree shaking shipped bundle থেকে unimported module exports বাদ দেয়। কিন্তু সীমাবদ্ধতা মনে রেখো: এই tools machine যা বহন করে তা optimize করে, human যা বহন করে তা না। Tree shaking bundle থেকে bytes সরায়, কিন্তু source file এখনও repository-তে বসে প্রতিটা পাঠককে confused করছে। Machine-level DCE স্বয়ংক্রিয়। Human-level DCE — মানে git rm করা — তোমাকেই করতে হবে। আরেকটা কথা: DCE শুধুমাত্র provably unreachable যেটা সেটাই সরাতে পারে। Reflection বা dynamic imports যেটা তোমার text search-কে confuse করে, সেটা optimizer-কেও confuse করে।
🏢 বাস্তব project-এ এই smell কোথায় লুকায়
- Zombie feature flags। Flag কয়েক সপ্তাহ বেঁচে থাকার কথা, অনেক বছর বেঁচে থাকে। সব জায়গায় "off" আটকে থাকা flag মানে dead feature রক্ষিত। সব জায়গায় "on" আটকে থাকা flag মানে অন্য branch-টা dead। আরও খারাপ — পুরনো flag repurposed হয়। Knight Capital disaster-এ ঠিক এটাই হয়েছিল। ভালো দল flag-এ expiry date দেয় আর flag ship করার দিনই cleanup ticket schedule করে।
- Commented-out code blocks। সবচেয়ে সাধারণ লাশ। কিছু "DO NOT DELETE" warning বহন করে ২০২০ সালে চলে যাওয়া developer-দের কাছ থেকে। মুছে ফেলো। Git মনে রাখে।
- পরিত্যক্ত experiments। A/B test দুই বছর আগে শেষ হয়েছে। Variant B-এর কোড এখনও 0% traffic নিয়ে deploy করা আছে।
- Refactor-এর পর orphaned helper। নতুন implementation ship হয়েছে, পুরনো helper কখনো সরানো হয়নি আর এখনও বিশ্বস্তভাবে compile হচ্ছে।
- Unused endpoint আর handler। API route কোনো client এক বছরে call করেনি — access log-এ দেখা যায়, code review-এ অদৃশ্য।
- অসম্ভব state-এর জন্য defensive branch। Null-এর জন্য check যেটা type system বছরের পর বছর ধরে আটকে রেখেছে।
- Dead dependency।
package.jsonবা.csproj-এ পুরো package যেটা কিছুই import করে না — প্রতিটা একটা security-patch burden।
⚖️ কখন ignore করা যায়
বেশিরভাগ সময় মুছে ফেলাই সঠিক উত্তর। কিন্তু এই কয়েকটা ক্ষেত্রে থামো:
| পরিস্থিতি | Dead না alive? | কী করবে |
|---|---|---|
| Internal caller নেই এমন public library API | হয়তো বাইরে alive | ছাঁটার আগে published contracts আর consumer check করো |
| Reflection / DI / serialization দিয়ে পৌঁছানো code | Alive কিন্তু search-এ অদৃশ্য | শুধু text search না, runtime evidence দিয়ে verify করো |
| String-keyed lookups (routes, job names, configs) | Alive কিন্তু অদৃশ্য | String-ও খোঁজো, আর dashboard check করো |
| চালু হওয়ার জন্য scheduled dark-launched feature | Dormant, dead না | রাখো — এর birth date আছে, track করো |
| একটা implementation-এ no-op body সহ interface member | Contract দ্বারা required | Member রাখো, contract দাবি করে |
| শুধুমাত্র "হয়তো একদিন" বলে রাখা code | Dead | মুছে ফেলো, git log এর জন্যই আছে |
এই judgment একটা chart হিসেবে দেখা যায়। এক অক্ষে মৃত্যুর confidence, অন্যটায় ভুল হলে blast radius:
বিপজ্জনক মধ্যবর্তী অবস্থা হলো এমন কোড যেটা তুমি prove করতে পারছ না dead। শুধু সন্দেহের ওপর ভিত্তি করে মুছো না। Suspected path-এ logging বা metric যোগ করো, একটা পুরো business cycle অপেক্ষা করো — month-end! year-end! — আর dashboard-এর শূন্য দিয়ে death certificate sign করতে দাও। তারপর নির্ভয়ে মুছে ফেলো।
🛠️ কোন refactoring সমস্যা সারায়
| Symptom | Cure |
|---|---|
| Uncalled method, class, বা field | মুছে ফেলো (version control হলো safety net) |
| Unreachable branch | Branch আর condition মুছে ফেলো |
| Unread parameter | Remove Parameter |
| Computed-but-unused value | Computation মুছে ফেলো, কী orphan হয় দেখো |
| Commented-out block | দেখামাত্র মুছে ফেলো |
| Deletion-এর কারণে প্রায় খালি class | Inline Class |
| সামান্য জীবিত, একটা caller, কোনো স্পষ্টতা নেই এমন method | Inline Method |
| Zombie feature flag | Flag + dead branch সরাও, winning path রাখো |
📦 Quick revision box
+--------------------------------------------------------------+
| DEAD CODE — QUICK REVISION |
+--------------------------------------------------------------+
| Story : A storeroom of broken furniture kept "just in |
| case", blocking everything actually useful. |
| Smell : Code that can never run, or whose result is |
| never used — methods, branches, params, blocks. |
| Why bad : Read-tax on every reader, lies about behavior, |
| drag on every big change, and it can WAKE UP |
| (Knight Capital: $440M in 45 minutes). |
| Cure : DELETE. Small labeled commits. Git remembers |
| everything; the codebase is for the living. |
| Caution : Reflection, DI, public APIs, serialization, and |
| dark launches look dead but may be alive. Verify, |
| then delete with confidence. |
| Helpers : Compiler warnings, linters, coverage reports, |
| Inline Class, Inline Method, Remove Parameter. |
+--------------------------------------------------------------+✏️ অনুশীলন
এখানে একটা parking-charge module আছে যেটা তিনটা rewrite টিকে গেছে। তোমাকে দাফন সম্পন্ন করতে হবে।
const ENABLE_VALET = false; // valet service cancelled in 2024
class ParkingCharges {
calculate(hours: number, vehicle: string, useCoupon = false): number {
let rate = vehicle === "car" ? 40 : 20;
const surge = this.surgeMultiplier(); // computed, never used below
let total = rate * hours;
if (ENABLE_VALET) {
total += 100; // unreachable
}
if (vehicle === "bullock-cart") { // last seen: never
return 5;
}
// if (useCoupon) {
// total = total - 15; // old coupon scheme, ended Diwali 2023
// }
return total;
}
private surgeMultiplier(): number {
return new Date().getHours() > 18 ? 1.5 : 1.0;
}
private valetGreeting(): string { // nothing calls this
return "Welcome! Your car is in safe hands.";
}
}তোমার কাজ:
- একটা লাশের তালিকা তৈরি করো: প্রতিটা dead code চিহ্নিত করো। কমপক্ষে ছয়টা item আছে — unread parameter-ও গুনো।
- একটা item সন্দেহজনক কিন্তু provably dead না:
bullock-cartbranch। Figure 10-এর quadrant chart-এ এটা রাখো আর describe করো কীভাবে মুছে ফেলার আগে এটা dead prove করবে। Hint: logs/metrics একটা পুরো season জুড়ে — যদি বছরে একটা মেলা থাকে যেখানে cart park করে? surgevariable হিসাব করা হয় কিন্তু কখনো ব্যবহার হয় না। এটা একটা possible bug-ও হতে পারে — হয়তো surge pricing apply করার কথা ছিল! "delete" আর "actually use it"-এর মধ্যে বেছে নেওয়ার আগে কীভাবে original intent খুঁজে পাবে সেটা এক বাক্যে লেখো। Hint:git log, ticket history, দলকে জিজ্ঞেস করা।- ক্রমানুসারে deletion করো, একটা logical commit এক সময়ে। Chain লক্ষ্য করো: valet branch সরালে
ENABLE_VALETআরvaletGreetingkill হয়। Coupon comment সরালেuseCouponkill হয়। তোমার commit message লেখো। - Final clean class দেখাও। আগে আর পরে line গুনো।
- Bonus: দল একটা নতুন "EV charging" feature একটা flag-এর পেছনে চায়। দলের জন্য দুই লাইনের একটা policy লেখো যাতে এই flag কখনো zombie না হয়। Hint: owner + expiry date — ঠিক সেই discipline যেটা Knight Capital-এর ছিল না।
তোমার class-এ যা বাকি থাকে সেটা সব provably চলে আর provably গুরুত্বপূর্ণ হলে, গুদামঘর অবশেষে আবার একটা ঘর হয়ে যায়। আর কেউ আর পুরনো কুলার plug করতে পারবে না।
সচরাচর জিজ্ঞাসা
- Dead code মানে সহজ ভাষায় কী?
- Dead code হলো এমন কোড যেটা কখনো চলে না, বা যার result কেউ ব্যবহার করে না। যেমন: এমন একটা function যাকে কেউ call করে না, এমন একটা branch যার condition সবসময় false, এমন একটা parameter যেটা কেউ পড়ে না, এমন একটা variable যেটা হিসাব করা হয় কিন্তু ফেলে দেওয়া হয়, আর commented-out block যেটা 'যদি লাগে' বলে রেখে দেওয়া হয়েছে। এটা শুধুই বোঝা — কোনো কাজ নেই।
- Dead code কখনো না চললে ক্ষতি কী?
- কারণ মানুষ এটা পড়ে, maintain করে, আর বিশ্বাস করে। নতুন developer এমন কোড বুঝতে সময় নষ্ট করে যেটা কোনো কাজেই আসে না। Rename বা upgrade-এর সময় এটাও ঠিক করতে হয়। আর সবচেয়ে ভয়ের কথা — এটা ভুলবশত আবার চালু হয়ে যেতে পারে। Knight Capital ঠিক এভাবেই ৪৫ মিনিটে ৪৪০ মিলিয়ন ডলার হারিয়েছিল।
- Dead code মুছে ফেলা কি নিরাপদ? পরে দরকার হলে?
- হ্যাঁ, একদম নিরাপদ — version control ঠিক এই কাজের জন্যই আছে। Git প্রতিটা মুছে ফেলা line চিরকাল মনে রাখে। 'হয়তো একদিন দরকার হবে' — এটা একটা ভালো commit message লেখার কারণ হতে পারে, codebase-এ লাশ রেখে দেওয়ার কারণ না।
- বড় project-এ dead code কীভাবে খুঁজব?
- Tools ব্যবহার করো: compiler warnings, linters, static analyzers, IDE inspections for unused symbols, আর production-এর মতো run থেকে code-coverage reports। এগুলো লাশ খুঁজে বের করে। তুমি references যাচাই করো — reflection আর dependency injection-এর ব্যাপারে সাবধান — তারপর নির্ভয়ে মুছে ফেলো।
- কখন অব্যবহৃত দেখতে কোড আসলে dead না?
- Public library API-তে বাইরের caller থাকতে পারে যেটা তুমি দেখতে পাচ্ছ না। Reflection, serialization, dependency injection, বা string-keyed lookups দিয়ে পৌঁছানো কোড unreferenced দেখায় কিন্তু জীবিত। শীঘ্রই চালু হবে এমন dark-launched feature-flag code dormant, dead না। আর interface member রাখতে হবে এমনকি যদি একটা implementation-এর body খালিও থাকে।
আরো দেখো
সম্পর্কিত পাঠ
Comments Smell: যখন স্টিকি নোট একটা এলোমেলো আলমারি লুকিয়ে রাখে
জানো কেন বেশি comment একটা code smell হতে পারে। ভালো WHY comment আর খারাপ WHAT comment-এর পার্থক্য বোঝো — স্টিকি নোটের আলমারির গল্প দিয়ে, সহজ উদাহরণ দিয়ে।
Speculative Generality: যে সুইমিং পুলের জন্য পাইপ বসালে, পুলটাই হলো না
বাড়ি বানানোর গল্প দিয়ে Speculative Generality smell বোঝো। YAGNI কী, ভবিষ্যতের অনুমানে কোড লেখা কেন ক্ষতিকর, আর অব্যবহৃত abstraction কীভাবে সরাতে হয় — সব পরিষ্কার হয়ে যাবে।
Lazy Class: যে চাকরির কাজ শুধু একটা বাটন চাপা
Lazy Class code smell শিখো একটা মজার গল্পের মাধ্যমে। কোন class-গুলো টিকে থাকার যোগ্যতা রাখে না সেটা বুঝতে পারবে, আর Inline Class দিয়ে সেগুলো ঠিক করতে পারবে।
Inline Class: যে Class কিছুই করে না, তাকে মিলিয়ে দাও
Inline Class refactoring শেখো একটা school committee-র গল্পের মাধ্যমে। যে class কিছুই করে না তাকে তার user-এর সাথে মিলিয়ে দাও আর অকারণ layer মুছে ফেলো।