Fundamental Programming Principles: KISS, YAGNI, Separation of Concerns, SOLID and More
This article presents a comprehensive overview of essential programming principles—including KISS, YAGNI, separation of concerns, DRY, SOLID, inversion of control, and the scout rule—explaining why each matters and offering practical guidance on how to apply them to write clean, maintainable software.
KISS (Keep It Simple Stupid)
Most systems work best when they remain simple rather than complex.
Less code means less time to write, fewer bugs, and easier modification.
Simplicity is the highest form of sophistication.
Perfection is achieved without unnecessary clutter.
YAGNI (You Aren't Gonna Need It)
Do not implement features until they are truly required.
Spending effort on future features diverts resources from current work.
Unnecessary code inflates the codebase and adds complexity.
Do the Simplest Thing
Ask yourself, "What is the simplest thing to solve the problem?"
Separation of Concerns
This design principle divides a program into distinct parts, each focusing on a single concern (e.g., business logic vs. UI), so changes in one area do not require changes in another.
"I sometimes call it 'separation of concerns'… it is the only thinking technique I know that works. It means focusing on one aspect while ignoring others, not that they are unimportant." – Edsger W. Dijkstra, 1974
Simplifies development and maintenance.
Enables reuse and independent evolution of modules.
Don’t Repeat Yourself (DRY)
Each piece of knowledge should have a single, authoritative representation in the system.
Unintentional duplication leads to maintenance nightmares and logical contradictions.
Changing a single element should not require changes elsewhere.
Consistent changes across related logic become predictable.
Write business rules, long expressions, if‑statements, formulas, metadata, etc., in only one place.
Identify the unique source for each concept and use it everywhere.
Apply the Rule of Three when appropriate.
Write Code for the Maintainer
Maintenance is the most expensive phase of any project.
Become the future maintainer.
Write code as if the maintainer is a meticulous, possibly obsessive, person.
Make the code enjoyable to read and learn from.
Don’t make me think.
Follow the Principle of Least Astonishment.
Avoid Premature Optimization
"Programmers waste a lot of time worrying about the speed of non‑critical parts. Premature optimization is the root of all evil, but we should not ignore the critical 3% where performance matters." – Donald Knuth
The bottleneck is often unknown.
Optimizing too early can make code harder to read and maintain.
Make it work, make it right, then make it fast.
Only optimize after a real bottleneck is identified.
Minimize Coupling
Coupling measures how much one module depends on another; lower coupling is better.
Changes in one module can ripple to others.
Higher dependency increases assembly effort.
Highly coupled modules are harder to reuse or test.
Developers may fear changes due to unknown impact.
Eliminate or reduce unnecessary dependencies.
Hide implementation details to lower coupling.
Apply the Law of Demeter.
Law of Demeter (Principle of Least Knowledge)
“Talk only to your immediate friends.”
Reduces tight coupling.
Prevents exposure of too many implementation details.
Allowed method calls:
Methods of the object itself.
Methods of objects passed as parameters.
Methods of objects created within the method.
Methods of the object's direct fields.
Composition Over Inheritance
Reduces coupling between classes.
Inheritance can lead to violations of the Liskov Substitution Principle.
Test LSP to decide when inheritance is appropriate.
Use composition for “has‑a” relationships; inheritance for “is‑a”.
Orthogonality
“Conceptually unrelated things should not be related in a system.” – Be Orthogonal
Source: Be Orthogonal
“The simpler the design, the fewer exceptions; orthogonal features are independent of the environment, emphasizing symmetry and consistency.” – Orthogonality
Robustness Principle (Postel’s Law)
Be conservative in what you send, liberal in what you accept.
Services should evolve without breaking existing clients.
Sending code must strictly follow the specification; receiving code should tolerate reasonable deviations.
Inversion of Control (Hollywood Principle)
"Don’t call us, we’ll call you." Custom code receives control flow from a generic framework.
Improves modularity and scalability.
Separates task execution from implementation.
Keeps modules focused on their design responsibilities.
Avoids assumptions about how other systems operate.
Prevents side effects when modules are swapped.
Use Factory Pattern.
Use Service Locator.
Use Dependency Injection.
Use Dependency Lookup.
Use Template Method.
Use Strategy Pattern.
Maximize Cohesion
High cohesion means a module’s responsibilities form a meaningful unit.
Low cohesion makes modules harder to understand.
Changes in one domain affect many modules, increasing maintenance difficulty.
Unnecessary functionality hampers reuse.
Group related functionality under a single responsibility (e.g., within one class).
Liskov Substitution Principle (LSP)
Objects should be replaceable by instances of their subtypes without altering program correctness.
Open/Closed Principle
Software entities should be open for extension but closed for modification.
Minimizes changes to existing code, improving maintainability and stability.
Write classes that can be extended without modifying their source.
Expose only the parts that need to change; hide everything else.
Single Responsibility Principle (SRP)
A class should have only one reason to change.
Improves maintainability by limiting the impact of changes.
Apply Curry’s Law (Curly’s Law): Do one thing.
Hide Implementation Details
Modules expose interfaces while keeping internal details private.
Clients remain unaffected when implementations change.
Minimize the visibility of classes and members.
Do not expose member data.
Avoid leaking private implementation details into the public API.
Reduce coupling to hide more details.
Curry’s Law (Rule of One)
Do one thing and do it well.
Encapsulate Frequently Changing Code
Identify hotspots likely to change and encapsulate them behind an API so modifications stay local.
Minimize the amount of code that needs to be changed when a modification occurs.
Encapsulate different concepts behind separate modules.
Interface Segregation Principle (ISP)
Split bulky interfaces into several small, client‑specific ones; interfaces should depend more on the callers than on the implementations.
Clients should not be forced to depend on methods they do not use.
Avoid fat interfaces; a class should not implement methods it does not need.
Scout Rule
Leave the campsite cleaner than you found it; similarly, each commit should improve code quality.
Every change should not degrade the codebase; technical debt accumulates if quality is ignored.
Ensure each commit does not lower quality.
Whenever you see unclear code, take the opportunity to fix it.
Command Query Separation (CQS)
Methods should either perform an action (command) or return data (query), never both.
Queries can be used in any order without side effects; commands require careful handling.
Implement each method as either a query or a command.
Use naming conventions to indicate the method type.
Author: Mouse Source: http://r6d.cn/N3Sz (translated from http://java-design-patterns.com/principles/)
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
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.