Comments Smell: যখন স্টিকি নোট একটা এলোমেলো আলমারি লুকিয়ে রাখে
জানো কেন বেশি comment একটা code smell হতে পারে। ভালো WHY comment আর খারাপ WHAT comment-এর পার্থক্য বোঝো — স্টিকি নোটের আলমারির গল্প দিয়ে, সহজ উদাহরণ দিয়ে।
স্টিকি নোটে ঢাকা আলমারি
ধরো ফাতেমাদের বাড়িতে একটা বড় স্টিলের আলমারি আছে। হলের কোণে দাঁড়িয়ে আছে — ধূসর, ভারী, আর ফাতেমার জন্মের আগে থেকেই সেখানে। ভেতরটা একদম জগাখিচুড়ি। স্কুলের বই মিশে গেছে আচারের বয়ামের সাথে। শীতের সোয়েটার চাপা পড়ে আছে বিদ্যুৎ বিলের উপরে। সেলাইয়ের বাক্স লুকিয়ে আছে একটা জুতার বাক্সের ভেতরে। আব্বার পুরনো ক্যামেরা মোড়ানো আছে এমন একটা শাড়িতে যেটা কেউ আর পরে না।
ফাতেমার মা, নাসরিন আন্টি, খোঁজাখুঁজিতে ক্লান্ত হয়ে গেলেন। প্রতিদিন সকালে একই নাটক — "জ্যামিতি বক্স কোথায়? গ্যাসের বিল কোথায়? ওষুধ কে সরিয়েছে?" এক রোববার তিনি সমস্যা ঠিক করার সিদ্ধান্ত নিলেন। কিন্তু আলমারি সাজানোর বদলে — যেটায় পুরো একটা বিকেল লাগত — তিনি দ্রুত একটা কাজ করলেন। হলুদ স্টিকি নোটের একটা প্যাড নিলেন আর দরজায় চারদিকে লাগিয়ে দিলেন।
- "গণিতের বই আচারের বয়ামের পেছনে, তৃতীয় তাক।"
- "সতর্কতা: লাল বাক্স সরাবে না, বিল নিচে আছে।"
- "সোয়েটার সাদা কভারে, নীল কভারে না। নীল কভারে পুরনো পর্দা।"
- "ওষুধ: নিচের তাক, বাম দিক, ইস্ত্রির পেছনে।"
কাজ হলো। প্রায় দুই সপ্তাহ।
তারপর জীবন ঘটল। আব্বা সোয়েটার নীল কভারে রাখলেন কারণ সাদাটা ছিঁড়ে গেছে। কেউ নোট আপডেট করল না। আচারের বয়াম শেষ হলো, নতুনগুলো অন্য তাকে এলো। সেই নোটও কেউ আপডেট করল না। নতুন নোট পুরনো নোটের উপর লাগানো হলো। কিছু নোট পড়ে গিয়ে ঝাড়ু দিয়ে ফেলা হলো। শীঘ্রই চল্লিশটা স্টিকি নোট — আর কেউ বলতে পারে না কোনগুলো এখনও সত্যি।
একদিন ফাতেমা একটা নোট বিশ্বাস করে নীল কভার খুলল পর্দা খুঁজতে। পেল তার হারানো স্কুল project চূর্ণ হয়ে — সেই সোয়েটারের নিচে যেগুলো নোট বলেছিল সাদা কভারে আছে। জমা দেওয়া মিস হলো। ফাতেমা খুশি হলো না।
এখন একটু ভাবো। স্টিকি নোটগুলো কি আলমারি ঠিক করল? না। আলমারি এখনও এলোমেলো। নোটগুলো শুধু এলোমেলো অবস্থার বর্ণনা দেয়। আর জিনিসপত্র সরলে কেউ নোট আপডেট করে না, তাই অর্ধেক নোট এখন মিথ্যা। আরও খারাপ — নোটগুলো পরিবারকে মনে করিয়ে দিল সমস্যাটা "সামলানো হয়েছে", তাই কেউ আর আসলে আলমারি সাজানোর চাপ অনুভব করল না।
সবসময় একটা ভালো সমাধান ছিল: আলমারি ঠিকমতো সাজাও। একটা তাকে বই। আরেকটায় কাপড়। বিল একটা labeled folder-এ। তখন বেশিরভাগ স্টিকি নোট অপ্রয়োজনীয় হয়ে যায় — কারণ আলমারি নিজেই ব্যাখ্যা করে।
Code ঠিক একইভাবে কাজ করে। Code এলোমেলো আর বিভ্রান্তিকর হলে অনেক programmer তার উপর "স্টিকি নোট" লাগায় — comment যেটা ব্যাখ্যা করে বিভ্রান্তিকর code কী করছে। Comment এলোমেলো অবস্থা ঠিক করে না। শুধু বর্ণনা দেয়। আর নাসরিন আন্টির নোটের মতো, এগুলো ধীরে ধীরে পুরনো আর ভুল হয়ে যায়।
এটাই হলো Comments code smell। কিন্তু সাবধান — এই smell-এর একটা twist আছে। কিছু স্টিকি নোট সত্যিই মূল্যবান, আর আমরা সেই পার্থক্যটা শিখব।
সেই journey-র শেষ অংশটা দেখো। খুশির score শুধু তখনই আসে যখন আলমারি নিজেই সাজানো হয় — আরও নোট যোগ করলে না।
এই smell কী?
সংজ্ঞাটা মনোযোগ দিয়ে পড়ো। অনেকে এটা ভুল বোঝে।
Comments smell হলো যখন comment-কে অস্পষ্ট code-এর ব্যান্ডেজ হিসেবে ব্যবহার করা হয়। Code পড়তে কঠিন, তাই কেউ উপরে একটা বাক্য লেখে ব্যাখ্যা করতে যে এটা কী করছে — code-টা ঠিক করার বদলে।
লক্ষ্য করো সংজ্ঞাটা কী বলে না। এটা বলে না "comment খারাপ"। এটা বলে comment যেগুলো অস্পষ্ট code-এর ক্ষতিপূরণ করে সেগুলো একটা সতর্ক সংকেত। Martin Fowler তার Refactoring বইতে এই ধরনের comment-কে deodorant বলেন — একটা মিষ্টি স্প্রে যেটা খারাপ গন্ধ দূর করার বদলে লুকিয়ে রাখে। তুমি comment লেখার ইচ্ছা অনুভব করলে, Fowler বলেন, আগে code refactor করার চেষ্টা করো যাতে comment অপ্রয়োজনীয় হয়।
Comment-এর দুটো বড় পরিবার আছে। পুরো পাঠটা এই দুটোর মাঝের ফাঁকে:
- WHAT comment — code কী করছে তা ব্যাখ্যা করে। উদাহরণ: একটা লম্বা বিভ্রান্তিকর condition-এর উপরে
// check if customer gets discount। এগুলোই smell। Code-এর নিজেই এটা বলা উচিত — ভালো নামের মাধ্যমে। - WHY comment — কেন code এরকম তা ব্যাখ্যা করে। উদাহরণ:
// we retry only 3 times because the payment gateway takes 90 seconds to recover। এগুলো সোনা। কোনো variable name, কোনো method name, কোনো চালাক refactoring এই গল্প ধরে রাখতে পারে না। এটা শুধু কোনো comment-এ বা কারো মাথায় থাকে — আর মাথা কোম্পানি ছেড়ে চলে যায়।
যেকোনো comment-এর জন্য একটা সহজ পরীক্ষা — জিজ্ঞেস করো: "একটা ভালো নাম বা ছোট refactoring কি এই comment-টা অকেজো করতে পারে?" যদি হ্যাঁ হয়, refactor করো আর comment মুছে দাও। যদি না হয় — কারণ comment একটা কারণ, ইতিহাসের একটা টুকরো, বা সতর্কতা ধরে রাখছে — গর্বের সাথে রাখো। কয়েকটা ভালো WHY comment সহ ভালো code হলো লক্ষ্য, শূন্য comment নয়।
University corner: এই পার্থক্যটা software engineering গবেষণার একটা ধারণার সাথে সুন্দরভাবে মেলে। Code তার mechanics সম্পর্কে self-documenting হতে পারে — কিন্তু rationale সম্পর্কে কখনও পারে না। মানে হলো, code বলতে পারে "আমি কী করছি", কিন্তু "কেন এই design বাকিগুলোর বদলে বেছে নেওয়া হলো" — এটা পারে না। সেই কারণেই mature team clean code-এর সাথে WHY comment রাখে। Robert C. Martin-এর Clean Code-এর comment অধ্যায়টা পড়লে দেখবে তিনি যে "ভালো comment" categories-এর তালিকা করেছেন (legal, intent, warning, external API-র clarification) — প্রায় সবই rationale, mechanics নয়।
এই smell-এর পুরো এলাকা একটা মানচিত্রে:
কীভাবে চিনবে
Code পড়ার সময় এই checklist ব্যবহার করো। যেগুলো মিলে সেগুলো চিহ্নিত করো।
- একটা comment পরের লাইনটা English-এ পুনরাবৃত্তি করছে।
count++-এর উপরে// increase count by one। - একটা comment একটা code block কী করছে তার নাম দিচ্ছে। সেই block সেই নামসহ একটা method হওয়ার জন্য অপেক্ষা করছে।
- একটা comment একটা লম্বা, জটিল
ifcondition-কে একটা বাক্যে অনুবাদ করছে। - একটা comment আর নিচের code ভিন্ন কথা বলছে — comment পুরনো হয়ে গেছে।
- ফাইলটা
// TODO,// FIXME,// HACKচিহ্নে ভর্তি যেগুলো কেউ মাসের পর মাস ধরে ছুঁয়ে দেখেনি। - "যদি লাগে" বলে বড় অংশের commented-out code ফাইলে ঘুমাচ্ছে।
- একটা comment ক্ষমা চাইছে:
// sorry, this part is confusing। Code-কে ক্ষমা চাওয়ার বদলে বোধগম্য করো।
একটা পুরনো project খুলে comment-গুলো bucket-এ সাজালে ছবিটা সাধারণত এরকম দেখায়:
মাত্র এক চতুর্থাংশ নোট তাদের কাজ করছে। বাকিগুলো আলমারিতে স্টিকি নোট — আর দশটার মধ্যে একটা সক্রিয়ভাবে মিথ্যা বলছে।
এখানে এই পুরো আলোচনার সবচেয়ে গুরুত্বপূর্ণ table। এটা smell করা comment আর উজ্জ্বল comment-এর পার্থক্য দেখায়।
| Comment | ধরন | রায় | কেন |
|---|---|---|---|
i++-এর উপরে // add 1 to i | WHAT | খারাপ — মুছে দাও | Code-ই এটা বলছে |
একটা ৩-লাইনের condition-এর উপরে // check loyalty discount eligibility | WHAT | খারাপ — refactor করো | isEligibleForLoyaltyDiscount নামে একটা method extract করো |
// retry 3 times: gateway has a 90-second failover window | WHY | ভালো — রাখো | কারণটা আর কোথাও নেই |
// do not reorder these fields; serialization breaks | WARNING | ভালো — রাখো | পরের জনকে একটা লুকানো ফাঁদ থেকে বাঁচায় |
/* old code: ... 40 lines ... */ | DEAD CODE | খারাপ — মুছে দাও | Git চিরকাল মনে রাখে |
একটা public API-তে /** Returns the invoice total including VAT. */ | DOCS | ভালো — রাখো | তোমার library-র tools আর users এটা পড়ে |
// TODO: fix this someday (২ বছর পুরনো) | STALE | খারাপ — সমাধান করো বা মুছো | কেউ রাখে না এমন প্রতিশ্রুতি শুধু noise |
// see circular 2024-17 for this rounding rule | WHY | ভালো — রাখো | Code-কে বাস্তব-বিশ্বের নিয়মের সাথে যুক্ত করে |
আর এখানে একটা দ্রুত decision chart যা review করার সময় মাথায় রাখতে পারো। তোমার ফাইলের প্রতিটা comment কোথায় পড়ে?
কেন এটা সমস্যা
WHAT comment কেন এত বিপজ্জনক? খরচগুলো ধীরে ধীরে গুনে দেখি।
খরচ ১: Comment মিথ্যা বলতে পারে, কেউ থামায় না। Code compiler আর test দিয়ে চেক হয়। Comment কেউ চেক করে না। কেউ code edit করলে কিন্তু comment ভুলে গেলে, দুটো দ্বিমত পোষণ করতে শুরু করে। পাঠকের কাছে তখন দুটো গল্প — কোনটা সত্যি বলতে পারে না। ভুল comment কোনো comment না থাকার চেয়ে খারাপ। কারণ এটা সক্রিয়ভাবে বিপথে নিয়ে যায় — নাসরিন আন্টির স্টিকি নোটের মতো যেটা ভুল কভার দেখাচ্ছিল।
খরচ ২: সব comment-এর প্রতি বিশ্বাস মরে যায়। প্রথমবার একটা comment পাঠককে ধোঁকা দিলে, পাঠক project-এর সব comment বিশ্বাস করা বন্ধ করে দেয় — মূল্যবান WHY comment-সহ। একটা মিথ্যা নোট চল্লিশটা নোটের বিশ্বাসযোগ্যতা নষ্ট করে। ফাতেমা এখন আলমারির সঠিক নোটগুলোও উপেক্ষা করে — কারণ কোনটা সত্যি সে কীভাবে জানবে?
খরচ ৩: Code ঠিক করার চাপ অদৃশ্য হয়। এলোমেলো code ব্যাখ্যা করা comment সেই mess-কে "বেঁচে থাকার মতো" করে তোলে। কেউ এটা পরিষ্কার করার জন্য যথেষ্ট ব্যথা অনুভব করে না। এটাই deodorant effect — গন্ধ এখনও আছে, শুধু সুগন্ধযুক্ত।
খরচ ৪: দুবার পড়তে হয়। যে comment code পুনরাবৃত্তি করে, সে পাঠককে সবকিছু দুবার পড়তে বাধ্য করে — একবার English-এ, একবার code-এ। তারপর তুলনা করো দুটো মিলছে কিনা। অতিরিক্ত কাজ, শূন্য নতুন তথ্য।
দেখো বিশ্বাসঘাতকতা আসলে কীভাবে ঘটে — একজন developer-এর বিকেলে, ধাপে ধাপে:
আর এখানে একটা WHAT comment-এর জীবনের গল্প — slow motion-এ। লক্ষ্য করো এটা কখনও একদিনে "সত্য" থেকে "মিথ্যা"-তে লাফ দেয় না। এটা নিঃশব্দে সেখানে ভেসে যায়, যখন সবাই ব্যস্ত:
project যত বেশি দিন বাঁচে, এটা তত খারাপ হয়। এখানে সেই সাধারণ pattern যা team-গুলো দেখায় যখন তারা track করে তাদের comment base কতটুকু এখনও সত্য বলছে:
University corner: এখানে সত্যিকারের empirical সমর্থন আছে। দীর্ঘস্থায়ী codebase-এর উপর গবেষণা ধারাবাহিকভাবে দেখায় যে comment-গুলো তারা যে code বর্ণনা করে তার চেয়ে অনেক কম ঘন ঘন আপডেট হয়। আর inconsistent comment ভবিষ্যতের bug-এর সাথে সম্পর্কিত। Compiler natural language সম্পর্কে কিছুই enforce করে না — তাই comment হলো একটা source file-এর একমাত্র অংশ যার কোনো feedback loop নেই। এটাই formal কারণ যে WHY comment গুলো WHAT comment-এর চেয়ে বেশি সময় ভালো থাকে। একটা কারণ ("gateway ৯০ সেকেন্ড সময় নেয় recover করতে") সত্য থাকে এমনকি আশেপাশের implementation পুনরায় লেখা হলেও। কিন্তু একটা বর্ণনা প্রতিবার implementation পরিবর্তনের সাথে ভেঙে পড়ে।
diagram-এর দুটো পথ দেখো। Comment path আজ সস্তা মনে হয়, কিন্তু বিশ্বাস হারানোয় শেষ হয়। Refactor path আজ দশ মিনিট খরচ করে — আর এরপর প্রতিটা দিন ফেরত দেয়।
একটা বাস্তব code উদাহরণ
ধরো ফাতেমার আলমারিকে code হিসেবে লিখছি। একটা ছোট স্কুলে একটা স্টোর আলমারি আছে, আর এই program সেটা manage করে। দেখো স্টিকি নোটগুলো কীভাবে জমতে থাকে।
// Smelly version: sticky notes everywhere
class StoreCupboard {
items: { name: string; shelf: number; box: string; qty: number }[] = [];
// this function gives items to a student
issueItem(name: string, qty: number, studentClass: number): string {
// find the item in the list
const item = this.items.find((i) => i.name === name);
// if item is not there return error
if (!item) return "Not found";
// check if student is allowed: classes 6 and above can take
// science items, and quantity must be available, and quantity
// should not be more than 5 per student as per store rule
if (
((item.box === "science" && studentClass >= 6) ||
item.box !== "science") &&
item.qty >= qty &&
qty <= 5
) {
// reduce the quantity
item.qty = item.qty - qty;
// return success
return "Issued";
}
// return failure
return "Denied";
}
// old issue function, keeping just in case
// issueOld(name: string) {
// const item = this.items.filter(i => i.name === name)[0];
// if (item) { item.qty--; return true; }
// return false;
// }
}সমস্যাগুলো গুনি:
// find the item in the list— পরের লাইন ইতোমধ্যেfindবলছে। শুদ্ধ পুনরাবৃত্তি।if-এর উপরের বড় comment একটা method name যা কাজ করা উচিত তাই করছে। Condition এত জটিল যে decode করতে English দরকার হলো।// reduce the quantityআর// return success— স্পষ্ট লাইনের kindergarten বর্ণনা।- Commented-out
issueOldছদ্মবেশে dead code। - আর এখানে মূল আঘাত — comment বলছে "৬ এবং তার উপরের শ্রেণী", কিন্তু ধরো পরের মাসে নিয়ম পরিবর্তন হয়ে "৮ এবং তার উপরের শ্রেণী" হলো, আর কেউ শুধু code-এ
6সংখ্যাটা8-এ পরিবর্তন করল। Comment এখনও ৬ বলছে। ভবিষ্যতের পাঠক comment বিশ্বাস করল। ধাক্কা — ভুল বোঝাপড়া, সম্ভাব্য bug। এটাই ঠিক সেই বিশ্বাসঘাতকতা যা চিত্র ৫-এ দেখলাম।
ধাপে ধাপে পরিষ্কার করা
আমরা এটা পরিষ্কার করব যেভাবে ফাতেমার পরিবারের আলমারি পরিষ্কার করা উচিত — লেবেল লাগিয়ে না, সাজিয়ে।
ধাপ ১: বর্ণনামূলক comment মুছে দাও। // find the item in the list, // reduce the quantity, // return success — সব গেল। Code ইতোমধ্যে এই কথাগুলো বলছে।
ধাপ ২: Commented-out code মুছে দাও। Git চিরকাল issueOld মনে রাখবে। কেউ যদি কখনও এটার দরকার হয়, git log খুঁজে পাবে। এটাই Dead Code post-এ বর্ণিত cure।
ধাপ ৩: বড় WHAT comment-কে নামে রূপান্তর করো। এটাই মূল কাজ: Extract Method। Comment "check if student is allowed..." একটা method canIssue হয়ে যায়। এর ভেতরে আমরা Extract Variable ব্যবহার করি প্রতিটা ছোট নিয়মের নাম দিতে।
ধাপ ৪: একটা WHY comment রাখো। "৫ per student" নিয়মটা স্টোরের নিয়মবই থেকে এসেছে। সেই কারণটা একটা comment-এর যোগ্য — কারণ কোনো variable name এটা ধরে রাখতে পারে না।
// Clean version: the code reads like the comments we deleted
const MAX_QTY_PER_STUDENT = 5; // store rule book, page 12: prevents hoarding
class StoreCupboard {
items: StoreItem[] = [];
issueItem(name: string, qty: number, studentClass: number): IssueResult {
const item = this.items.find((i) => i.name === name);
if (!item) return "NotFound";
if (!this.canIssue(item, qty, studentClass)) return "Denied";
item.qty -= qty;
return "Issued";
}
private canIssue(item: StoreItem, qty: number, studentClass: number): boolean {
const allowedAge = item.box !== "science" || studentClass >= 6;
const inStock = item.qty >= qty;
const withinLimit = qty <= MAX_QTY_PER_STUDENT;
return allowedAge && inStock && withinLimit;
}
}
type StoreItem = { name: string; shelf: number; box: string; qty: number };
type IssueResult = "Issued" | "Denied" | "NotFound";canIssue জোরে পড়ো: "allowed age, and in stock, and within limit।" এটা পুরনো comment-এর মতোই পড়া যাচ্ছে — কিন্তু এখন compiler এটা চেক করে, test এটা cover করে, আর এটা কখনও পুরনো হতে পারে না। একমাত্র যে comment বাকি আছে সেটা constant-এর WHY comment — আর সেটা তার জায়গা অর্জন করেছে।
পরিষ্কার করা design-এর গঠন এরকম দেখায়:
আরেকটা কাজের কৌশল — যদি একটা comment "balance এখানে কখনও negative হয় না" এরকম কোনো assumption জানায়, সেটাকে Introduce Assertion দিয়ে একটা real check-এ রূপান্তর করো। Assumption ভাঙলে assertion জোরে চিৎকার করে। একটা comment শুধু চুপ করে বসে থাকে যখন সব কিছু পুড়ছে।
এখানে রূপান্তরের সম্পূর্ণ তালিকা — স্টিকি নোট থেকে self-explaining code পর্যন্ত:
C#-এ একই smell
C#-এ একই রোগ, একই চিকিৎসা। আগে:
// Check if the customer is eligible for the loyalty discount
if (customer.Orders.Count > 12
&& customer.AccountAgeInMonths >= 6
&& !customer.HasOutstandingBalance)
{
ApplyDiscount(customer);
}Comment একটা বাক্য যেটা method name হতে চাইছে। হতে দাও।
if (IsEligibleForLoyaltyDiscount(customer))
{
ApplyDiscount(customer);
}
private static bool IsEligibleForLoyaltyDiscount(Customer customer) =>
customer.Orders.Count > 12
&& customer.AccountAgeInMonths >= 6
&& !customer.HasOutstandingBalance;Comment চলে গেছে, কিন্তু এর অর্থ টিকে আছে — এমন একটা নামের ভেতরে যেটা compiler সৎ রাখবে। এর মধ্যে, C#-এ একটা genuine WHY comment অপরিবর্তিত থাকে:
// We retry exactly 3 times because the upstream gateway returns a
// transient 503 during its 90-second failover window; more retries
// only increase user waiting time without improving success.
private const int MaxRetries = 3;পৃথিবীর কোনো renaming ব্যাখ্যা করতে পারবে না কেন সংখ্যাটা ৩। সেই comment এমন একটা কাজ করছে যা code করতে পারে না।
আর একটা Python উদাহরণ — কারণ smell সব ভাষায় কথা বলে:
# Smelly: narration and a block-label comment
def monthly_fee(student):
# calculate base fee
fee = 2000
# check if student has sibling and apply ten percent discount
if student.has_sibling:
fee = fee * 0.9
return fee
# Clean: the names carry the meaning
SIBLING_DISCOUNT = 0.10 # society rule: one discount per family, AGM 2024
def monthly_fee(student):
fee = BASE_FEE
if student.has_sibling:
fee *= (1 - SIBLING_DISCOUNT)
return feeবাস্তব project-এ এই smell কোথায় লুকায়
বাস্তব কোম্পানিতে এই smell অনেক রূপে আসে:
- লম্বা method-এর ভেতরে section-divider comment।
// ---- validation ----,// ---- calculation ----,// ---- saving ----। প্রতিটা divider একটা method চিহ্নিত করে যেটা extract হওয়ার অপেক্ষায়। এটা Long Method smell যেটা Comments smell-এর সাথে হাত ধরে আছে। - Commented-out code-এর কবরস্থান। পুরনো API call, পুরনো SQL query, পুরনো algorithm — "যদি লাগে" বলে বছরের পর বছর রাখা। বড় codebase-এর গবেষণায় নিয়মিত এরকম block পাওয়া যায় যেগুলো অনেক release জুড়ে কেউ ছোঁয়নি।
- Auto-generated noise। প্রতিটা private method-এ বাধ্য করা documentation generator তৈরি করে
GetName()-এ/// <summary>Gets the name.</summary>-এর মতো জিনিস। Volume আছে, value নেই। - Stale TODO farm। শত শত
// TODOচিহ্ন, কিছু তাদের পড়া intern-দের চেয়ে বেশি বয়স্ক। Ticket আর owner ছাড়া TODO হলো একটা ইচ্ছা, পরিকল্পনা নয়। - Apology comment।
// I know this is ugly, don't ask। সৎ, কিন্তু ক্ষমা চাওয়ায় যে শক্তি গেল তা দিয়ে একটা method extract হতে পারত। - Business code-এ tutorial comment।
// a for loop iterates over the array— program-এর বদলে language ব্যাখ্যা করছে।
University corner: Code review culture-এ "comment-driven refactoring" নামে একটা দরকারী heuristic আছে। যখন একটা pull request একটা block-এর উপর comment যোগ করে, reviewer জিজ্ঞেস করে — comment-টা কি extracted function-এর নাম হতে পারত? Kent Beck-এর intention-revealing names-এর ধারণা এর পেছনের তত্ত্ব। একটা method-এর নাম হলো এমন একটা comment যা type system, IDE-র rename tool, আর তোমার test suite বিনামূল্যে synchronized রাখে। একটা comment-এর শূন্য enforcement আছে, একটা নামের তিনটা layer আছে।
কখন উপেক্ষা করা ঠিক
এই smell সবচেয়ে সহজে over-correct হওয়া smell। কিছু team ঘোষণা করে "কোনো comment অনুমতি নেই!" — এটা প্রতিটা লাইনে comment করার মতোই ভুল। এখানে সৎ table:
| পরিস্থিতি | Comment রাখব? | কারণ |
|---|---|---|
| WHY ব্যাখ্যা (business rule, workaround, tradeoff) | হ্যাঁ, সবসময় | Code কারণ আর ইতিহাস প্রকাশ করতে পারে না |
| Public API docs (XML docs, JSDoc, docstring) | হ্যাঁ | Tools, IDE, আর library users এগুলো পড়ে |
| Legal আর license header | হ্যাঁ | আইন বা কোম্পানির নীতি দরকার করে |
| Non-obvious পরিণতি সম্পর্কে সতর্কতা | হ্যাঁ | "এই order পরিবর্তন করলে serialization ভাঙে" কারো সপ্তাহান্ত বাঁচায় |
| Spec, ticket, বা নিয়মের link | হ্যাঁ | Code-কে বাইরের বিশ্বের সাথে সংযুক্ত করে |
| স্পষ্ট লাইনের বর্ণনা করা comment | না — মুছে দাও | শুদ্ধ noise |
| Code block-এর নাম দেওয়া comment | না — Extract Method | নামটা code-এ থাকা উচিত |
| Commented-out code | না — মুছে দাও | Version control হলো archive |
| Code-এর সাথে একমত নয় এমন পুরনো comment | না — ঠিক করো বা মুছো | জানা মিথ্যা কখনও থাকতে পারে না |
কখনও এমন comment রেখো না যেটা তুমি জানো ভুল। একটা পুরনো comment হলো পরের পাঠকের জন্য সশস্ত্র ফাঁদ। যে মুহূর্তে একটা দেখবে, হয় ঠিক করো বা মুছে দাও — এমনকি যদি তুমি অন্য কিছুর মাঝখানে থাকো। এটা ত্রিশ সেকেন্ড নেয় আর কারো খারাপ বিকেল বাঁচায়।
কোন refactoring এটা সারায়
| লক্ষণ | সারানোর refactoring | এটা কী করে |
|---|---|---|
| Comment একটা code block-এর নাম দেয় | Extract Method | Block একটা method হয়ে যায়, comment তার নাম হয় |
| Comment একটা বিভ্রান্তিকর expression decode করে | Extract Variable | প্রতিটা sub-rule একটা অর্থপূর্ণ boolean নাম পায় |
| Comment একটা খারাপ নামের method ব্যাখ্যা করে | Rename Method | ব্যাখ্যাটা নামের ভেতরে ভাঁজ করো |
| Comment একটা assumption জানায় | Introduce Assertion | Assumption একটা executable check হয়ে যায় |
| Commented-out code | মুছে দাও (version control বিশ্বাস করো) | Git হলো museum, codebase হলো living room |
| পুরনো বা পুনরাবৃত্তি করা comment | মুছে দাও বা ঠিক করো | সত্যের একটাই উৎস থাকা উচিত |
দ্রুত revision box
+--------------------------------------------------------------+
| COMMENTS SMELL — QUICK REVISION |
+--------------------------------------------------------------+
| Story : Sticky notes describing a messy cupboard |
| instead of arranging the cupboard. |
| Smell : Comments explaining WHAT unclear code does. |
| NOT smell: Comments explaining WHY (reasons, warnings, |
| specs, API docs) — these are GOLD. Keep them. |
| Danger : Comments are never compiled or tested, |
| so they silently go stale and start lying. |
| Test : "Can a better name make this comment useless?" |
| Yes -> refactor & delete. No -> keep proudly. |
| Cures : Extract Method, Extract Variable, Rename |
| Method, Introduce Assertion, plain deletion. |
| Motto : Arrange the cupboard. Do not label the mess. |
+--------------------------------------------------------------+অনুশীলনী
এখন পরিষ্কারকারী হওয়ার সময়। একটা রেলওয়ে টিকেট program থেকে একটা ছোট smelly function:
// this function calculates fare
function fare(d: number, age: number, w: boolean): number {
// base fare is distance times 1.5
let f = d * 1.5;
// senior citizens above 60 get 40 percent off and
// children below 5 travel free as per railway rules
if (age > 60) f = f * 0.6;
if (age < 5) f = 0;
// if w is true add 20 rupees
// (w means window seat which costs extra)
if (w) f = f + 20;
// old calculation, do not delete
// let f = d * 1.4 + 10;
return f;
}তোমার কাজ:
- প্রতিটা WHAT comment খুঁজে বের করো আর তার ভাগ্য ঠিক করো — মুছে দাও, অথবা একটা নামে পরিণত করো।
d,w, আরfrename করো যাতে parameter-গুলো নিজেদের ব্যাখ্যা করে। (Hint:wসম্পর্কে commentwantsWindowSeat-এর মতো একটা নাম হতে চাইছে।)- Senior citizen আর শিশু নিয়মগুলো
applyAgeDiscount-এর মতো একটা ভালো নামের method-এ extract করো। Comment text বিনামূল্যে নামটা দিচ্ছে। - Commented-out "old calculation" মুছে দাও। কেন এটা নিরাপদ সে সম্পর্কে একটা বাক্য লিখো।
- সিদ্ধান্ত নাও — এখানে কোনো WHY তথ্য আছে কি যা comment হিসেবে থাকার যোগ্য? (Hint: "as per railway rules" একটা কারণ — এটা কি আসল নিয়মের link করে একটা comment হতে পারে?)
- চিত্র ৬-এর নিজস্ব version আঁকো — comment life cycle — তোমার নিজের অতীত code-এর একটা comment-এর জন্য। এটা কি কখনও "Lying" অবস্থায় পৌঁছেছিল?
- তোমার নিজের অতীত code থেকে একটা comment লিখো যেটা WHAT ব্যাখ্যা করে, আর একটা যেটা WHY ব্যাখ্যা করে। প্রথমটা refactor করো। দ্বিতীয়টাকে সালাম জানাও।
যখন তোমার version বোঝার জন্য শূন্য comment লাগে — কিন্তু railway নিয়ম রেকর্ড করে এমন একটা comment রেখেছ — তুমি এই smell সম্পূর্ণ বুঝে গেছ।
সচরাচর জিজ্ঞাসা
- প্রোগ্রামিংয়ে কি সব comment খারাপ?
- না, একদমই না। যে comment ব্যাখ্যা করে কেন code এটা করছে — কোনো business-এর কারণ, কোনো bug-এর workaround, কোনো কঠিন সিদ্ধান্ত — সেটা অনেক মূল্যবান। Smell শুধু সেই comment-এ আছে যেটা বলে code কী করছে, কারণ সেটা মানে code নিজেই অস্পষ্ট — আর সেটা পরিষ্কার করা দরকার।
- ভুল comment কেন কোনো comment না থাকার চেয়ে খারাপ?
- কারণ compiler বা test কেউই comment চেক করে না। code পরিবর্তন হলে কিন্তু comment না হলে, comment মিথ্যা বলা শুরু করে। যে পাঠক সেই মিথ্যা comment বিশ্বাস করে সে code ভুল বুঝবে। একবার ধোঁকা খেলে, পাঠক project-এর সব comment বিশ্বাস করা বন্ধ করে দেয়।
- একটা code block ব্যাখ্যা করে comment লেখার বদলে কী করব?
- Extract Method করো। block-টা নাও, একটা নতুন method-এ নিয়ে যাও, আর method-টাকে সেই নামটা দাও যেটা তুমি comment-এ লিখতে যাচ্ছিলে। এখন code নিজেই একটা বাক্যের মতো পড়া যায় — আর comment-এর দরকার নেই।
- Commented-out code কি এই smell-এর অংশ?
- হ্যাঁ। Commented-out code হলো ছদ্মবেশে dead code। ভয় ছাড়াই delete করো। Git-এর মতো version control tool প্রতিটা পুরনো version মনে রাখে, তাই সত্যিই দরকার হলে যেকোনো সময় ফিরিয়ে আনতে পারবে।
- কখন গর্বের সাথে একটা comment রাখব?
- রাখো যখন এটা এমন কিছু রেকর্ড করে যা code বলতে পারে না — কেন একটা magic number 3, কোন bug-এর বিরুদ্ধে একটা অদ্ভুত workaround কাজ করে, কোনো অদ্ভুত condition-এর পেছনের rule বা ticket-এর link, public API documentation, বা legal header। এই comment-গুলো এমন জ্ঞান বহন করে যা শুধু মানুষের মাথায় থাকে।
আরো দেখো
সম্পর্কিত পাঠ
Dead Code: গুদামঘরে পুরনো জিনিস 'যদি লাগে' বলে আটকে রাখা
Dead Code smell শেখো একটা গুদামঘরের গল্প দিয়ে। দেখো কেন না-চলা কোড আসলে টাকা আর সময় নষ্ট করে, Knight Capital-এর ৪৪০ মিলিয়ন ডলারের ঘটনা থেকে শিখো, আর সহজভাবে সমাধান করো।
Long Method: যখন একটা function সব কিছু করতে চায়
Long Method code smell শিখো সহজ গল্পের মাধ্যমে — TypeScript আর C# example সহ, Extract Method দিয়ে step-by-step refactoring। একদম beginner-friendly গাইড।
Duplicate Code: ৫০টা বিয়ের কার্ডে হাতে লেখা একই ঠিকানা
বিয়ের কার্ডের গল্প দিয়ে Duplicate Code smell বোঝো। DRY, Rule of Three, আর Extract Method দিয়ে copy-paste কোডের বিপদ থেকে বাঁচো।
Extract Method: একটা বিশাল ফাংশনকে ছোট ছোট নামওয়ালা helper-এ ভাগ করো
Extract Method ধাপে ধাপে শিখে নাও। একটা লম্বা ফাংশন থেকে এলোমেলো block বের করে তাকে একটা পরিষ্কার নাম দাও, আর তোমার কোডকে একটা সহজ to-do লিস্টের মতো পড়ার যোগ্য করে তোলো।