Better code is easier to understand, change, test, and maintain. The practical goal is not to make every line clever or short; it is to reduce the effort another person needs to work out what the program does. These 11 rules, drawn from software developer and manager Nick Hodges’s experience, offer a useful starting point. They are guidelines, not laws: apply them in light of the language, project, and changes you can reasonably expect.
1. Prefer the simplest solution that works
Choose straightforward language features and familiar data structures unless a more complex approach delivers a clear, necessary benefit. Cleverness has a maintenance cost: the next person must understand not only what the code does, but why it is written in an unusual way.
Simplicity does not mean avoiding useful structure. It means not adding complexity merely because a technique is available. A direct loop may be easier to maintain than an intricate abstraction; an abstraction is worthwhile when it makes a real requirement simpler to meet.
2. Make the code clear, even if it takes more lines
Names should tell readers what a value or routine represents. For example, transactionManager communicates more than txMgrObj. Use names that make sense in the domain, not just abbreviations that are familiar to the original author.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errors#1 Best Overall
Clarity can also justify an explaining variable or a few extra lines. Avoid compressing several operations into a dense expression when naming an intermediate result would make the intent obvious. Comments can explain why a non-obvious decision exists, but they should not have to compensate for misleading names or unnecessarily tangled logic.
Readable formatting helps, too. Use consistent spacing, sensible line lengths, and logical sections. The 2024 Australian Economic Review guidance by Hirschberg recommends code that is easy to read, understand, debug, maintain, replicate, extend, and reuse; it also recommends descriptive names and clear separation of tasks. Read the article.
3. Limit what a method needs to know
The Law of Demeter is a reminder to minimize the objects and details one piece of code must interact with. Pass a method the specific information it needs rather than handing it a large object or query container and making it reach through that object’s internals.
For example, if a routine only needs a customer’s identifier, passing the identifier can create less coupling than passing an entire customer record. The trade-off is that passing a whole object may be more convenient; it is justified when the method genuinely needs that object’s behavior or data. The aim is not to ban objects, but to keep dependencies intentional and limited.
Recommended Free Tools
4. Design for zero, one, or many items
Do not build in arbitrary fixed limits when the domain can naturally contain any number of items. A collection may be empty, contain one item, or contain many. Code that assumes a fixed number can fail as soon as a real use case falls outside that assumption.
Check the boundary cases that fit the requirement: what happens when there are no results, exactly one result, or several? If the business rule truly imposes a limit, represent that rule explicitly rather than letting an unexplained number silently constrain the implementation.
5. Replace unexplained hard-coded values
A literal buried in code is difficult to interpret and expensive to update consistently. Give meaningful values names, and keep changeable choices out of routines that should not own them. For instance, use a named constant for a domain threshold rather than repeating its numeric value in several places.
Concrete implementations can also be a form of hard-coding. If a dependency is likely to vary, an interface, configuration setting, or dependency injection can make that change manageable. Do not abstract every value in advance: the reason to introduce a seam is a meaningful change or testability need, not a preference for more layers.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Rank #3
- Used Book in Good Condition
6. Use apparent over-engineering when it solves a real problem
An interface or extension point can look like extra work when there is only one implementation. It may still be good engineering if it addresses a known change, such as supporting a second provider or isolating an external service for tests.
Judge the abstraction by the problem it removes. It should make a foreseeable change cheaper or keep an important boundary clear. If no concrete need exists, extra indirection can make the code harder to follow without making it more adaptable.
7. Prepare for changes that are reasonably foreseeable
“You aren’t going to need it” is a useful warning against speculative features, but it is not a reason to ignore a change that is already likely and costly to retrofit. If requirements, architecture, or a known business plan point to a coming variation, a small amount of flexibility now may avoid a larger rewrite later.
Separate a plausible, evidence-based change from an imagined possibility. Build for the former; keep the latter out until it becomes a real requirement. This balances flexibility with the simplicity of solving today’s problem.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →8. Keep business logic usable without the graphical interface
Hodges recommends making the command line the first user interface. The broader design lesson is to keep core business logic independent of a particular presentation layer. When rules are entangled with screens, it becomes harder to test them, run them in other contexts, or see which part of the program owns a decision.
Where practical, make the same core operations callable from a command-line interface or test harness as well as a graphical interface. This does not mean every application must ship a command-line tool. It means the underlying work should not require a screen merely to be invoked or verified.
9. Treat deeply nested conditionals as a warning
An if statement is not inherently a problem. A long chain of conditions or several levels of nesting, however, can make it difficult to see which cases lead to which outcomes. That may indicate that the logic should be split into focused routines, or that different behaviors belong in separate classes.
Before refactoring, make sure each branch reflects a real rule and that the proposed split improves understanding. Replacing a clear conditional with a more elaborate pattern does not automatically make the code simpler.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Best Value
10. Give each unit one clear responsibility
A line, routine, or class that takes on several unrelated jobs is harder to change safely. Keep each unit focused on one purpose, and extract a routine when a portion of a larger block has a distinct responsibility or a useful name.
“One thing” is a guide to cohesion, not a demand that every line or method be tiny. A unit can perform several steps that belong together; the problem is combining work that changes for different reasons or serves unrelated goals. Separating those responsibilities makes behavior easier to locate and test.
11. Keep complexity—and unnecessary optimization—under control
Complexity consumes the reader’s attention. Hodges’s summary is that good code should be simple, clear, and “boring,” minimizing the mental effort required to understand it. That is a design objective, not a claim that all code can or should be trivial.
Optimize when there is a demonstrated performance need, and keep the optimization understandable where possible. For ordinary code, clarity often matters more than shaving a few lines or pursuing speed without evidence. Hirschberg’s 2024 article notes that early computers could have about 124 k of memory, while a modern PC may have more than 10,000 times the space for code and data. Those figures are historical context, not proof that performance no longer matters; they help explain why readability can take priority over constraints that no longer apply to a particular program.
Hodges puts the maintainability case memorably: “Writing good code means writing simple, clear, ‘boring’ code—code that minimizes the cognitive effort required to understand it.” He also attributes this warning to John Woods: “Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.” The second line is a joke, not a measurement; its point is to write for the person who inherits the code.
How to apply the rules in a real code review
Use the rules as questions, not a checklist that every change must satisfy mechanically. A focused review can ask:
- Can a reader understand the names and intent without decoding abbreviations?
- Does this code handle the valid zero-, one-, and many-item cases?
- Are literals, dependencies, or implementation choices likely to change—and if so, are they named or isolated?
- Does each routine have a coherent responsibility, or do nested branches reveal separate behaviors?
- Is added flexibility tied to a foreseeable requirement, rather than hypothetical future needs?
- Is complexity or optimization justified by a real constraint, and is the result still understandable?
Hirschberg’s guidance also recommends documenting a program’s file name, version, author or initials, modification date, purpose, and data references; using version control; separating distinct tasks into separate programs; and favoring clarity over premature optimization. The exact documentation practices should suit the project, but the underlying aim is consistent: make code easier for someone else to understand, reproduce, and maintain.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Free tools Windows power users keep installed
One-click scans. No signup required.

