Building Something That Needs to Last? Try These 5 Clean Code Rules

| | 6 min read

In brief: Clean code rules should make the next change easier to make and harder to get wrong.

  • Separate concerns so one change does not ripple through unrelated parts.
  • DRY the rules and facts that must stay consistent, not every pair of similar lines.
  • KISS by choosing the clearest design that meets the real need.
  • Document public contracts, important constraints, and decisions the code cannot explain.
  • Use YAGNI to defer speculative features while keeping change manageable.

When a codebase becomes hard to change, the warning signs are familiar: one business rule lives in three places, a small update touches unrelated layers, or nobody knows why a strange workaround exists. These clean code rules can help reduce that friction. They do not guarantee scalability or robustness on their own, but they give teams a practical way to improve clarity and maintainability.

What clean code rules are meant to improve

“Clean code” is not a single measurable property, and these principles are not laws. They are prompts for design decisions. The aim is to make the system easier for people to understand, verify, and change without hiding important trade-offs behind slogans.

That distinction matters. A simple implementation that ignores security, performance, accessibility, or a real future requirement is not good design. Equally, an elaborate framework for a hypothetical use case adds work before it delivers value. The right design meets the requirements we know, makes its behaviour clear, and keeps likely changes within reach.

1. Separate concerns before they tangle

Separation of concerns means giving different responsibilities clear places in a system. Edsger Dijkstra used the phrase in a 1974 discussion about studying one aspect of a problem at a time. In software design, that idea supports boundaries such as presentation, business rules, and data access, so a change in one area does not require reasoning through every other area. See Dijkstra’s essay on separation of concerns.

For example, a web handler that validates input, calculates a price, writes to a database, and formats a response has several reasons to change. Moving price rules into a focused domain function makes them easier to read and test. But do not split every line into its own module: a boundary helps when the responsibilities can change or be understood independently.

If you want to explore how boundaries fit into a broader design, see this site’s guide to Clean Architecture, SOLID, DDD, and event-driven systems.

2. Apply DRY where clean code rules change together

DRY is often reduced to “never write similar code twice.” Its fuller meaning is about knowledge: a fact or rule should have one authoritative representation. That is the formulation in The Pragmatic Programmer.

If a tax rate or permission rule is duplicated in several places, each copy can drift. Put that knowledge behind one well-named function or data source. However, two pieces of code can look alike while representing different policies. If they change for different reasons, forcing them into one abstraction can couple them and make future edits harder. Remove duplicated knowledge, not similarity for its own sake.

3. KISS means choose the clearest solution

Keep it simple means avoid complexity that does not help meet the requirements. It does not mean write the fewest lines, avoid useful abstractions, or pretend a difficult problem is easy. Google’s Go guidance describes simple code as code that is easy to follow and has no unnecessary abstraction, while acknowledging that justified complexity sometimes needs documentation.

Prefer the familiar language feature or small function when it communicates the intent. Add a more sophisticated design when you can name the need, such as a measured performance constraint or multiple real consumers. If an implementation is much harder to understand than the problem sounds, pause and look for a clearer shape.

4. Document the contract and the reason

Good names and straightforward code should explain what is happening. Documentation adds the information a reader cannot reliably infer: what a public method promises, which inputs are valid, what errors it can return, or why a surprising constraint exists.

For example, a comment that repeats “increment the retry count” adds little. A short note explaining that a retry must happen after a remote lease expires may prevent someone from removing a necessary delay. API documentation should describe how to use the interface and its limitations. Google’s documentation guidance separates those contracts from inline explanations of why code takes an unusual path.

Documentation is also code to maintain. Keep it close to the interface or decision it describes, and revise it when that behaviour changes. A stale comment can mislead more than no comment at all.

5. YAGNI: build the need, not the guess

YAGNI means “You Aren’t Gonna Need It”: do not implement a feature solely because it might be useful later. The original Extreme Programming explanation says to implement things when they are actually needed, rather than when you merely foresee needing them.

Suppose an application currently has one payment provider. A plugin system for five imagined providers adds configuration, tests, and concepts that every maintainer must understand today. Wait until a second provider is a real requirement, then design around the evidence. YAGNI is not an excuse to skip sound foundations: privacy, security, regulatory duties, and compatibility constraints belong in the requirements when they apply. Nor does it mean making change deliberately difficult. Refactoring and tests help teams add the next real need safely.

Use these clean code rules with judgement

The principles can pull in different directions. DRY may encourage sharing a function, while separation of concerns may suggest keeping two similar implementations apart because they serve different policies. KISS may favour a direct implementation today, while a known compliance requirement justifies more structure from the start. Resolve the tension by asking what must stay consistent, what changes independently, and what the system is required to do now.

Before adding an abstraction or rewriting a module, try a small review:

  • Can I identify this part’s responsibility and reason to change?
  • Is the same rule duplicated, or only the code’s shape?
  • Would a reader understand the simplest version without hidden context?
  • Does a comment explain a contract, constraint, or non-obvious decision?
  • Is this feature required now, or am I building for a scenario I have only imagined?

These questions will not design a scalable system for you. They help keep complexity deliberate, so the architecture, tests, operational safeguards, and performance work needed for robustness remain visible. Start with one change that feels risky, apply the principle that addresses its real cause, and see whether the next change becomes easier.

The post Building Something That Needs to Last? Try These 5 Clean Code Rules appeared first on Alpesh Kumar.

Subscribe to Our Newsletter

We don’t spam! Read our privacy policy for more info.