Introduction to SOLID Principles
SOLID is an acronym representing five design principles that help developers create more maintainable, understandable, and flexible software.
The Five Principles
| Letter | Principle | Description |
|---|---|---|
| S | Single Responsibility | A class should have one reason to change |
| O | Open/Closed | Open for extension, closed for modification |
| L | Liskov Substitution | Derived classes must be substitutable for base classes |
| I | Interface Segregation | Many small interfaces beat one large interface |
| D | Dependency Inversion | Depend on abstractions, not concretions |
Why SOLID Matters
Without SOLID principles, code tends to become:
- Rigid: Hard to change because every change affects many parts
- Fragile: Changes break unexpected parts of the system
- Immobile: Hard to reuse because code is too intertwined
- Viscous: Doing things wrong is easier than doing them right
With SOLID principles, code becomes:
- Flexible: Easy to modify and extend
- Maintainable: Changes are isolated
- Testable: Components can be tested independently
- Reusable: Components can be used in different contexts
Real-World Impact
// Without SOLID - A common anti-pattern
public class UserService
{
public void RegisterUser(string email, string password)
{
// Validate input
if (!email.Contains("@"))
throw new Exception("Invalid email");
// Hash password
var hashedPassword = BCrypt.HashPassword(password);
// Save to database
using var connection = new SqlConnection("...");
connection.Execute("INSERT INTO Users ...", new { email, hashedPassword });
// Send welcome email
using var smtp = new SmtpClient("smtp.gmail.com");
smtp.Send("Welcome!", email);
// Log activity
File.AppendAllText("log.txt", $"User registered: {email}");
}
}
// Problems:
// - Violates SRP: handles validation, hashing, DB, email, logging
// - Violates DIP: depends on concrete implementations
// - Hard to test: can't test without real DB, email server, file system
// - Hard to change: switching email providers requires changing this class
// With SOLID principles
public interface IUserValidator { ValidationResult Validate(string email, string password); }
public interface IPasswordHasher { string Hash(string password); }
public interface IUserRepository { Task AddAsync(User user); }
public interface IEmailService { Task SendWelcomeAsync(string email); }
public interface ILogger { void Log(string message); }
public class UserRegistrationService
{
private readonly IUserValidator _validator;
private readonly IPasswordHasher _hasher;
private readonly IUserRepository _repository;
private readonly IEmailService _emailService;
private readonly ILogger _logger;
public UserRegistrationService(
IUserValidator validator,
IPasswordHasher hasher,
IUserRepository repository,
IEmailService emailService,
ILogger logger)
{
_validator = validator;
_hasher = hasher;
_repository = repository;
_emailService = emailService;
_logger = logger;
}
public async Task RegisterAsync(string email, string password)
{
var validation = _validator.Validate(email, password);
if (!validation.IsValid)
throw new ValidationException(validation.Errors);
var hashedPassword = _hasher.Hash(password);
var user = new User(email, hashedPassword);
await _repository.AddAsync(user);
await _emailService.SendWelcomeAsync(email);
_logger.Log($"User registered: {email}");
}
}
// Benefits:
// - Each class has one responsibility (SRP)
// - New email provider? Just implement IEmailService (OCP)
// - Dependencies injected via interfaces (DIP)
// - Easy to test with mocks
// - Easy to modify individual components
Common Misconceptions
âSOLID means more classes = betterâ
No. SOLID guides design decisions but shouldnât lead to over-engineering. A simple script doesnât need 10 interfaces.
âEvery class needs an interfaceâ
No. Create interfaces when you need abstraction - for testing, multiple implementations, or dependency injection boundaries.
âSOLID is only for large projectsâ
No. SOLID principles help at any scale. Even small projects benefit from clear responsibilities and loose coupling.
How Principles Work Together
The SOLID principles are complementary:
SRP â Smaller, focused classes
â
OCP â Classes that are easy to extend
â
LSP â Proper inheritance hierarchies
â
ISP â Focused interfaces
â
DIP â Loose coupling throughout
â
Result: Maintainable, testable, flexible code
Interview Tips
Common Questions:
- âExplain SOLID principlesâ
- âWhich principle do you find most important?â
- âGive an example of violating/following [X] principleâ
Key Points:
- Know all five principles by heart
- Have concrete examples for each
- Understand trade-offs (SOLID can lead to over-engineering)
- Know when to apply them (not every class needs every principle)
The following pages explore each principle in detail with practical C# examples.