No Comments, Then Quit: The Code Revenge That Haunts Teams
This article explores the nightmare of inheriting uncommented, poorly structured code from departed developers, illustrating anti-patterns like cryptic naming, deep nesting, magic numbers, and copy-paste duplication, while providing a four-step refactoring guide and team-level prevention strategies including code reviews, coding standards, and offboarding practices.
Introduction: The Morning the Tea Spilled
Imagine arriving at work, opening a departed colleague's order module, and finding 5,000 lines of code with only two and a half comments. Variables named a1 through z26, if nesting that circles the globe. You wonder: did they do this on purpose?
1. Classic "Revenge Code" Scenes
1.1 Overly Abstract Naming
A method doSomething(List list, Map map, int num) reveals nothing about its purpose. list turns out to be order IDs, map validation results, num a length threshold. Another file uses a, b, c for start date, end date, and a threshold — 200 lines later they appear in a conditional with no explanation.
1.2 Five Thousand Lines, Two and a Half Comments
Methods span hundreds of lines; comments read // loop, // judge, // return. A payment callback checks sign.length() == 32, status == "2", and type not in ["4","6"] with only // success and // fail as clues. The author spent an afternoon digging through three-year-old requirements to learn that sign is an MD5 hash, status=2 means payment success, and type=4,6 are test-environment callbacks. Another infamous comment: // Don't touch this, it will break — without saying what breaks. A // TODO later optimize survives three years untouched.
1.3 Nesting Hell: Seven Levels of if
A permission-check method nests seven if statements, pushing the innermost return 30 spaces right. Research shows humans struggle beyond three indentation levels. Adding a new role requires excavating layers, risking misplaced else branches and butterfly-effect bugs.
1.4 One Method Does Ten Things
A 1,200-line submitOrder method handles login validation, inventory check, pricing, payment, DB save, notifications, logging, inventory update, WebSocket push, coupon generation, and more. A variable temp assigned at line 300, mutated five times, used at line 800. A 200-line "temporary" block (commented // temporary, will delete later) remains for years. Changing SMS logic broke DB saves due to shared mutable state.
1.5 Magic Numbers Everywhere
if (order.getStatus() == 3)— 3 could mean any of eight statuses. The numeral 3 appears 87 times with different meanings. Negative numbers like -1 for failure lack constants for -2, -3.
1.6 Copy-Paste Programming
Identical logic duplicated in ten places. A requirement change took two days to update nine copies; an eleventh hidden copy caused a test failure. Another copy diverged slightly, causing inconsistencies when only one was updated.
2. Why Developers Write "Revenge Code"
2.1 Rushed Deadlines
"Requirements too urgent, ship now, comment later" — but later never comes. Writing orderList instead of list1 takes two seconds; a meaningful comment takes five. The "I'll refactor later" flag rots on the "when I have time" mountain.
2.2 "I Understand It, That's Enough"
One developer used pinyin variables: yonghuming, dingdanhao, shangpinlist. Another invented a private abbreviation system: usr, ord, prd, and usrOrdPrdRlt for "user order product relation". Colleagues resorted to debugging to guess meanings; the module was eventually rewritten.
2.3 Misunderstanding "Good Code"
Some equate good code with brevity and speed. A bitwise addition implementation return (a ^ b) + ((a & b) << 1); replaces a+b with zero readability gain. A one-liner stream chain does null-check, filter, map, collect — impossible to debug intermediate results.
3. Four-Step Guide to Writing Good Code
Step 1: Understand Before You Touch
Run it: Feed various inputs (null, empty, normal, boundary) and observe outputs to reverse-engineer logic.
Draw flowcharts: Map each step (e.g., token → format → expiry → role → result).
Write tests first: Cover critical paths with unit tests before refactoring.
Refactoring is not rewriting; it's optimizing on a foundation of understanding.
Step 2: Split First, Then Integrate
Break a 1,200-line method into verb-noun units: validatePreConditions, calculateAmount, saveOrderToDB, sendNotifications. Rules: clear names (no do1 / do2), limit parameters to five (encapsulate into UserContext if needed). The main method becomes a readable sequence; changes isolate to one small method.
Step 3: Standardize Naming and Comments
Variables: noun or adjective+noun ( orderList, maxLength), avoid temp (use tempOrderNo).
Methods: verb+noun ( validateOrder, calculatePrice).
Classes: PascalCase nouns ( OrderService, PriceCalculator).
Constants: UPPER_SNAKE_CASE ( MAX_LENGTH_THRESHOLD, ORDER_STATUS_PAID).
Comment essentials:
Public methods: purpose, params, return, side effects (Javadoc example shown).
Complex logic: business rule context (e.g., // Member 10% discount (rule changed from 15% in 2024)).
TODOs: what, why, when (e.g., // TODO: loop performance poor; switch to batch query in Q3).
Delete noise: // i++ // increment i.
Step 4: Optimize Logic — Flatten, Simplify, Deduplicate
Guard clauses over nesting: Return early for invalid cases; main flow stays left-aligned.
Switch over chained if-else: Cleaner, supports Java 14+ switch expressions.
Collection contains over multiple ORs: allowedRoles.contains(role) with constant list.
Extract duplicates: Common logic into validateToken, formatDate.
Design patterns for complex conditionals: Strategy + Factory for payment types — new processors added without modifying existing code (Open/Closed Principle).
4. Preventing "Revenge Code" at Team Level
4.1 Meaningful Code Reviews
Reject LGTM culture. Ask: "Can this variable name be clearer?" "Why this logic? Add a comment." "Nesting >3 levels — can guard clauses help?" Requires a supportive, not punitive, atmosphere.
4.2 Enforced Coding Standards
Adopt a concise standard (naming, comments, indentation, max method length). Automate with Checkstyle/ESLint; block non-compliant commits.
4.3 Regular Refactoring Sprints
Allocate ~20% of each iteration to technical debt. Apply the Boy Scout Rule: leave code cleaner than you found it.
4.4 Knowledge Sharing
Host sessions on "worst code I've seen" and refactoring workshops. Senior engineers mentor juniors via code walkthroughs.
4.5 Thorough Offboarding
Require departing developers to walk through core modules, write a "code self-description" covering design rationale and pitfalls. Ideal but often unrealistic when notice is one day.
Conclusion
The cruelest revenge isn't the uncommented code — it's making the maintainer hate you forever. Writing comments isn't for others; it's for yourself three months later when you've forgotten the context. Treat every departure as a test of your code's humanity: will the next person spill goji tea on their keyboard at 9:30 AM?
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
IT Services Circle
Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
