Design Principles - II
Beyond the foundational SOLID principles, software engineers rely on a secondary tier of heuristics and best practices to keep codebases readable, maintainable, and robust.
1. Law of Demeter (LoD)
Section titled “1. Law of Demeter (LoD)”Also known as the Principle of Least Knowledge. An object should only talk to its immediate neighbors. It should not reach through objects to access other objects.
Avoid “train wrecks” or long chains of method calls (e.g., a.getB().getC().doSomething()).
Visualizing LoD: Don’t talk to strangers. The Driver talks to the Car; the Car encapsulates the Engine.
Guideline
Section titled “Guideline”A method inside an object should only invoke methods of:
- The object itself.
- Objects passed in as parameters.
- Objects instantiated within the method.
- Direct component objects (instance variables).
Violating LoD:
// The Driver reaches through the Car to touch the Engine directly.// If the Engine API changes, the Driver breaks.car.getEngine().start();Following LoD:
// The Car provides an abstract start() method.// How it starts the engine is encapsulated.car.start();2. The Boy Scout Rule
Section titled “2. The Boy Scout Rule”“Always leave the code better than you found it.”
Software entropy is real; codebases naturally degrade over time. The Boy Scout Rule is a continuous refactoring mindset.
Refactoring messy code as you touch it prevents technical debt accumulation.
When you open a file to add a feature or fix a bug, take a few extra minutes to:
- Rename a poorly named variable.
- Break down a massive function.
- Add missing encapsulation (changing
publicfields toprivategetters/setters). - Delete commented-out “zombie” code.
3. Code for the Maintainer
Section titled “3. Code for the Maintainer”“Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.” — John Woods
Write code that is readable, self-explanatory, and predictable. Code is read 10x more than it is written.
Bad Practice:
// Cryptic variable names and magic numbersclass C { int x, y; void p() { x = 10; y = 20; System.out.println(x + y); }}Good Practice:
class Calculator { private int firstNumber; private int secondNumber;
// Meaningful names and clear intent public void printSum() { System.out.println(firstNumber + secondNumber); }}4. Principle of Least Astonishment (POLA)
Section titled “4. Principle of Least Astonishment (POLA)”A component of a system should behave in a way that most users (or developers) will expect it to behave. It should minimize surprises.
Functions should do exactly what their name implies, and nothing more. Hidden side-effects are the root of many bugs.
Violating POLA:
class LightSwitch { public void toggle() { // Astonishing: Why does toggling a light turn on a fan? System.out.println("Fan turned ON"); }}Following POLA:
class LightSwitch { private boolean isOn = false;
public void toggle() { isOn = !isOn; System.out.println(isOn ? "Light ON" : "Light OFF"); }}5. Coupling and Cohesion
Section titled “5. Coupling and Cohesion”Understanding the push-and-pull between Coupling and Cohesion is the hallmark of a senior engineer.
Aim for Loose Coupling and High Cohesion.
Tight vs. Loose Coupling
Section titled “Tight vs. Loose Coupling”Coupling refers to the degree of direct knowledge one element has of another.
- Tight Coupling: Classes depend heavily on concrete implementations. A change in Class A breaks Class B.
- Loose Coupling: Classes depend on interfaces/abstractions. They can be swapped out easily.