I hear you. You want the technical specifications on how to stop being an embarrassment to your team. Fine. Writing code that scales and doesn’t induce chronic migraines is all about discipline, not magic. Forget your complex patterns for a second—master the basics first.
Here are the seven commandments I live by. Read them, implement them, and maybe, just maybe, your code review won't look like a war crime report.
The HotfixHero code Manifesto: Seven Rules to Live By
- DRY (Don’t Repeat Yourself) Every piece of logic, every business rule, and every data definition must live in exactly one place. If you copy-paste, you're not coding; you're creating technical debt. The cost of fixing a bug multiplies by the number of times you repeated yourself. That's a terrible ROI.
Bad Example (Duplicate Validation):
function createUser(data) {
if (data.password.length < 8 || data.email.includes(' ')) {
throw new Error('Invalid input');
}
// User creation logic...
}
function updateUserPassword(data) {
// Same exact validation repeated here
if (data.newPassword.length < 8 || data.email.includes(' ')) {
throw new Error('Invalid input');
}
// Password update logic...
}
HH Way (Refactored to a Utility):
// Single source of truth for validation rules
function validateUserData(data) {
if (data.password && data.password.length < 8) {
throw new Error('Password too short');
}
if (data.email.includes(' ')) {
throw new Error('Email must not contain spaces');
}
}
function createUser(data) {
validateUserData(data);
// User creation logic...
}
- KISS (Keep It Simple, Stupid) The goal is to solve the problem, not win a Turing Award for the most convoluted solution. Simple code is cheaper to maintain, easier to test, and less likely to introduce subtle bugs. Your complexity doesn't impress anyone but junior developers.
Bad Example (Overly Complex Conditional):
function getDiscount(user) {
let status = user.isPremium ? 0.20 :
(user.totalOrders > 5 && user.joinedYear < 2024) ? 0.15 :
user.totalOrders > 10 ? 0.10 : 0;
// Now try debugging that nested ternary hell at 3 AM.
return status;
}
HH Way (Using Clear Logic):
function getDiscount(user) {
if (user.isPremium) {
return 0.20;
}
if (user.totalOrders > 5 && user.joinedYear < 2024) {
return 0.15;
}
if (user.totalOrders > 10) {
return 0.10;
}
return 0; // The default, simple case
}
- YAGNI (You Are Not Going to Need It) Stop guessing what the Product Owner might ask for next year. Build only what is required today. Every line of code you write that isn't solving a current problem is wasted time and creates unnecessary complexity.
Bad Example (Pre-building for Future Features):
# The current requirement is only 'File' storage.
# The developer adds hooks for 'S3' and 'Azure' just in case.
class StorageManager:
def __init__(self, storage_type='FILE'): # <-- YAGNI violation
if storage_type == 'FILE':
self.driver = FileStorage()
elif storage_type == 'S3':
self.driver = S3Storage() # <-- Unused code path
elif storage_type == 'AZURE':
self.driver = AzureStorage() # <-- Unused code path
else:
raise ValueError("Invalid storage type")
HH Way (Building Only What's Needed):
# If the only requirement is file storage, that's all we build.
class FileStorage:
def save(self, data):
# Implementation for saving to local disk
pass
# When S3 is actually requested, we introduce the abstract concept and the new driver.
- SOLID (Single Responsibility Principle - SRP) Focus on SRP: A class or function should have only one reason to change. If your function is responsible for fetching data, formatting it, and sending an email, it's doing too much. When the email format changes, the fetching function shouldn't have to change.
Bad Example (God Function):
function processAndFormatUserData(id) {
// 1. Fetch data (reason to change: database schema)
const user = database.fetchUser(id);
// 2. Calculate Age (reason to change: calculation logic)
const age = new Date().getFullYear() - new Date(user.dob).getFullYear();
// 3. Format output (reason to change: UI/API requirement)
return { id: user.id, fullName: `${user.first} ${user.last}`, age };
}
HH Way (Separated Responsibilities):
// 1. Data Retrieval
function fetchUserFromDB(id): User {
return database.fetchUser(id);
}
// 2. Business Logic/Calculation
function calculateAge(dob): number {
return new Date().getFullYear() - new Date(dob).getFullYear();
}
// 3. Formatting/Presentation
function formatUserPresentation(user: User): UserDTO {
return {
id: user.id,
fullName: `${user.first} ${user.last}`,
age: calculateAge(user.dob) // Calls focused logic
};
}
- Separation of Concerns This principle is about dividing an application into distinct features that overlap as little as possible. Your data access layer shouldn't know about HTTP request headers, and your controller shouldn't contain complex formatting logic.
Bad Example (Mixing Data Access and Business Logic):
// Inside a Web Controller/Endpoint
@GetMapping("/users/{id}")
public UserDetails getUserDetails(@PathVariable Long id) {
// Concern 1: Database Access is mixed here
UserEntity user = entityManager.find(UserEntity.class, id);
// Concern 2: Business Logic is mixed here
if (user.getBalance() < 0) {
throw new IllegalStateException("User is in debt.");
}
// Concern 3: Formatting/Presentation Logic is mixed here
UserDetails details = new UserDetails();
details.setFullName(user.getFirstName() + " " + user.getLastName());
return details;
}
HH Way (Delegated Concerns):
Controller calls a Service layer.
Service layer contains business logic (e.g., checking balance).
Service layer calls a Repository layer for database access.
Avoid Premature Optimizations
If you optimize before you measure, you are just making your code harder to read and more error-prone. Only optimize when you have proven, with a profiler, that a specific piece of code is the actual bottleneck.
Bad Example (Unnecessary Low-Level Loop for Readability Sacrifice):
// Bad: Using a simple 'for' loop and length decrement for micro-optimization
// Less readable than native methods, and modern engines optimize 'map' and 'forEach' just as well.
let i = items.length;
while (i--) {
processed.push(items[i].toUpperCase());
}
HH Way (Readable and Maintainable):
// Good: Clear intent, relies on optimized built-in methods.
const processed = items.map(item => item.toUpperCase());
- Law of Demeter (Principle of Least Knowledge) Don't talk to strangers. An object should only communicate with its immediate friends (objects it created, its parameters, its properties). Reaching through a chain of methods means your code is tightly coupled to deep internal structures, which is brittle.
Bad Example (Method Chaining Violation):
// We are asking the 'user' object for its 'wallet', then asking the 'wallet' for its 'card',
// then asking the 'card' for its 'security code'. Too much knowledge.
String code = user.getWallet().getPrimaryCard().getSecurityCode();
HH Way (Delegation):
// We only ask the 'user' to perform the action. The user object handles the internal structure.
String code = user.getSecurityCodeForPrimaryCard();
Top comments (0)