Answer
Overview
Software engineering principles are guidelines that help write maintainable, scalable, and clean code. The most important ones are SOLID, DRY, KISS, YAGNI, and others.
1. SOLID Principles
S — Single Responsibility Principle
A class should have only one reason to change.
dart// ❌ Bad — UserService does too much class UserService { Future<User> fetchUser(int id) async { ... } void sendEmail(String email) { ... } // Wrong place void saveToDatabase(User user) { ... } // Wrong place } // ✅ Good — split responsibilities class UserService { Future<User> fetchUser(int id) async { ... } } class EmailService { void sendEmail(String email) { ... } } class UserRepository { void save(User user) { ... } }
O — Open/Closed Principle
Open for extension, closed for modification.
dartabstract class Shape { double area(); } class Circle extends Shape { double area() => 3.14 * r * r; } class Rectangle extends Shape { double area() => w * h; } // Add new shapes without modifying existing code
L — Liskov Substitution Principle
Subclasses should be substitutable for their parent.
dartclass Animal { void makeSound() => print('...'); } class Dog extends Animal { void makeSound() => print('Woof'); } void speak(Animal a) => a.makeSound(); // Works with Dog too
I — Interface Segregation Principle
Don't force clients to depend on interfaces they don't use.
dart// ❌ Fat interface abstract class Worker { void work(); void eat(); void sleep(); } // ✅ Segregated abstract class Workable { void work(); } abstract class Eatable { void eat(); } class HumanWorker implements Workable, Eatable { ... } class RobotWorker implements Workable { void work() { ... } }
D — Dependency Inversion Principle
Depend on abstractions, not concretions.
dart// ❌ Depends on concrete class class OrderService { final SqlDatabase db = SqlDatabase(); } // ✅ Depends on abstraction abstract class Database { Future<void> save(Order order); } class OrderService { final Database db; // Can be SQL, NoSQL, mock OrderService(this.db); }
2. DRY — Don't Repeat Yourself
Extract repeated code into reusable functions/widgets.
dart// ✅ Reusable Widget primaryButton(String text, VoidCallback onTap) => ElevatedButton(onPressed: onTap, child: Text(text));
3. KISS — Keep It Simple, Stupid
Write the simplest solution that works.
4. YAGNI — You Aren't Gonna Need It
Don't add functionality until it's actually needed.
5. Separation of Concerns
Each layer/module handles only its own responsibility (UI, Logic, Data).
Summary Table
| Principle | Core Idea |
|---|---|
| SOLID | Object-oriented design rules |
| DRY | No code duplication |
| KISS | Keep code simple |
| YAGNI | Don't over-engineer |
| SoC | Separate UI, logic, data |
| Law of Demeter | Talk only to immediate friends |