SOLID Principles & Code Quality
SOLID Principles
Section titled “SOLID Principles”1. Single Responsibility Principle (SRP)
Section titled “1. Single Responsibility Principle (SRP)”A class should have only one reason to change. Each class owns one job, making it easier to test, reuse, and modify.
Bad:
public class Report { public void GenerateReport() { /* ... */ } public void SaveToFile() { /* ... */ } public void SendEmail() { /* ... */ }}Good:
public class ReportGenerator { public Report Generate() { /* ... */ } }public class FileSaver { public void Save(Report r) { /* ... */ } }public class EmailSender { public void Send(Report r) { /* ... */ } }2. Open/Closed Principle (OCP)
Section titled “2. Open/Closed Principle (OCP)”Open for extension, closed for modification. Add new behavior without changing existing code—extend, don’t edit.
Bad:
public class PaymentProcessor { public void Process(string method) { if (method == "Credit") { /* credit logic */ } else if (method == "PayPal") { /* paypal logic */ } }}Good:
public interface IPaymentMethod { void Process(); }public class CreditCard : IPaymentMethod { public void Process() { /* ... */ } }public class PayPalMethod : IPaymentMethod { public void Process() { /* ... */ } }public class PaymentProcessor { public void Process(IPaymentMethod method) { method.Process(); } }3. Liskov Substitution Principle (LSP)
Section titled “3. Liskov Substitution Principle (LSP)”Subclasses must be substitutable for their base type. If Bird flies, all birds should fly—no surprises.
Bad:
public class Rectangle { public int Width { get; set; } public int Height { get; set; } }public class Square : Rectangle { /* forces Width == Height */ }Good:
public interface IShape { int Area(); }public class Rectangle : IShape { public int Area() { return Width * Height; } }public class Square : IShape { public int Area() { return Side * Side; } }4. Interface Segregation Principle (ISP)
Section titled “4. Interface Segregation Principle (ISP)”Don’t force clients to depend on methods they don’t use. Small, focused interfaces beat one fat interface.
Bad:
public interface IMultiFunctionDevice { void Print(); void Scan(); void Fax(); }public class SimplePrinter : IMultiFunctionDevice { public void Print() { /* ... */ } public void Scan() { throw new NotImplementedException(); } public void Fax() { throw new NotImplementedException(); }}Good:
public interface IPrinter { void Print(); }public interface IScanner { void Scan(); }public interface IFaxer { void Fax(); }public class SimplePrinter : IPrinter { public void Print() { /* ... */ } }5. Dependency Inversion Principle (DIP)
Section titled “5. Dependency Inversion Principle (DIP)”Depend on abstractions, not concretions. High-level modules shouldn’t care how low-level modules work—inject the abstraction.
Bad:
public class UserService { private EmailSender _sender = new EmailSender(); public void NotifyUser(User u) { _sender.Send(u.Email); }}Good:
public interface IMessageSender { void Send(string recipient); }public class UserService { private IMessageSender _sender; public UserService(IMessageSender sender) { _sender = sender; } public void NotifyUser(User u) { _sender.Send(u.Email); }}Bonus Principles
Section titled “Bonus Principles”| Principle | Definition | When It Matters |
|---|---|---|
| DRY (Don’t Repeat Yourself) | One source of truth per concept. Duplicate code = future bugs. | Refactoring duplicates is your first red flag. |
| KISS (Keep It Simple, Stupid) | Simple code beats clever code. Readability > cleverness. | Over-engineering often hides under “design patterns.” |
| YAGNI (You Aren’t Gonna Need It) | Don’t build features you might use later. | Speculative generality is a code smell—cut it. |
| Composition over Inheritance | Favor “has-a” over “is-a”. Inheritance chains = rigid, fragile. | Mixins, traits, and interfaces are your friends. |
Code Smells & Red Flags
Section titled “Code Smells & Red Flags”Code smells aren’t bugs—they’re warning signs. They cluster around SOLID violations.
| Smell | Definition | Interview Q |
|---|---|---|
| Bloaters | Long Method, Large Class, Primitive Obsession, Long Parameter List | ”How would you reduce a 500-line method?” (Decompose.) |
| OO Abusers | Switch Statements, Temp Fields, Refused Bequest | ”Why is a switch statement a smell?” (Usually violates OCP.) |
| Change Preventers | Divergent Change, Shotgun Surgery | ”What’s Shotgun Surgery?” (One change, many files.) |
| Dispensables | Duplicate Code, Dead Code, Lazy Class | ”How do you find dead code?” (Coverage reports + linters.) |
| Couplers | Feature Envy, Message Chains, Middle Man | ”What’s Feature Envy?” (Method uses another class’s data.) |
TLDR Smell Mnemonics
Section titled “TLDR Smell Mnemonics”BOCS-D: Bloaters, OO Abusers, Change preventers, Dispensables, Couplers.
Refactoring Checklist
Section titled “Refactoring Checklist”- Write tests FIRST. Establish a baseline; don’t refactor blind.
- Eliminate duplicated code. Extract common logic into helper methods or base classes.
- Improve naming. Rename variables/methods to clarify intent (takes courage, massive payoff).
- Simplify conditionals. Replace nested if/else with guards, polymorphism, or strategy patterns.
- Decompose large methods. Extract logical chunks into separate methods (aim for <20 lines).
- Remove dead code. Delete unused variables, methods, branches—no sentimental code.
- Apply SOLID & patterns. Use these principles to guide bigger refactors.
- Check security. Ensure no new injection points, data leaks, or validation gaps introduced.
- Run unit tests. Green = safe. Red = you broke something; fix it before continuing.
- Code review. Fresh eyes catch things you miss. Discuss trade-offs.
- Performance test. Refactored code should not regress speed; profile before/after if performance matters.