0% found this document useful (0 votes)
22 views70 pages

Software Design Principles

The document outlines key software design principles, focusing on the importance of high cohesion and low coupling for creating maintainable code. It introduces the SOLID principles, which aim to enhance software flexibility and reusability, while providing examples of good and poor design practices. The document emphasizes the benefits of adhering to these principles to avoid common design pitfalls.

Uploaded by

duypham150805
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
22 views70 pages

Software Design Principles

The document outlines key software design principles, focusing on the importance of high cohesion and low coupling for creating maintainable code. It introduces the SOLID principles, which aim to enhance software flexibility and reusability, while providing examples of good and poor design practices. The document emphasizes the benefits of adhering to these principles to avoid common design pitfalls.

Uploaded by

duypham150805
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Software Design

Software Design Principles

1
MSc. Ngô Ngọc Đăng Khoa
Software Design

Design Principles
Learning Objectives
☕ Understand and apply fundamental design principles
☕ Master SOLID principles
☕ Gain the ability to create flexible and maintainable code
Main Content
1 Coupling & Cohesion

2 SOLID, DRY, KISS, YAGNI principles

2
MSc. Ngô Ngọc Đăng Khoa
Software Design

WHY

Problems with Poor Design Benefits of Good Design


☕ Hard to maintain: Fixing one part affects many others ☕ Easy to read and understand
☕ Hard to extend: Adding new features requires ☕ Easy to modify and extend
modifying old code
☕ Easy to test
☕ Hard to test: Code is tightly coupled ☕ High reusability
☕ Hard to understand: Complex logic, disorganized
functionality

3
MSc. Ngô Ngọc Đăng Khoa
Software Design

COUPLING & COHESION

4
MSc. Ngô Ngọc Đăng Khoa
Software Design

Cohesion

Cohesion is the degree to which components within a module/class work together to achieve a clear
purpose.

Classification:
☕ High Cohesion (Good): Closely related methods/attributes
☕ Low Cohesion (Bad): Unrelated methods/attributes

5
MSc. Ngô Ngọc Đăng Khoa
Software Design

Low Cohesion
Problem: Employee class does too many things: data management, printing, database, email.

// Class performs too many unrelated tasks


public class Employee {
private String name;
private double salary;

public void calculateSalary() { } // Employee business logic


public void printReport() { } // Print report
public void saveToDatabase() { } // Save to database
public void sendEmail() { } // Send email
}

6
MSc. Ngô Ngọc Đăng Khoa
Software Design

High Cohesion
Benefits: Each class has a clear responsibility, easy to test and maintain.

// Class only manages employee data // Separate class for report printing
public class ReportPrinter {
public class Employee { public void printEmployeeReport(Employee emp) { }
private String name, double salary; }
public String getName() { return name; }
// Separate class for database
public double getSalary() { return salary; } public class EmployeeRepository {
public void calculateSalary() { } public void save(Employee emp) { }
} }
// Separate class for email
public class EmailService {
public void sendToEmployee(Employee emp, String message) { }
}

7
MSc. Ngô Ngọc Đăng Khoa
Software Design

Coupling

Coupling is the degree of dependency between modules/classes .

Classification
☕ Loose Coupling: Fewer dependencies, changing one module has minimal impact on others
☕ Tight Coupling: Strong dependencies, changing one module affects many others

8
MSc. Ngô Ngọc Đăng Khoa
Software Design

9
MSc. Ngô Ngọc Đăng Khoa
Software Design

Tight Coupling

Problem
// OrderProcessor is tightly coupled to MySQLDatabase
public class OrderProcessor {
private MySQLDatabase database; ☕ Cannot switch to PostgreSQL/MongoDB
public OrderProcessor() {
// Hard initialization - TIGHT COUPLING
☕ Hard to test due to dependence on a real
[Link] = new MySQLDatabase(); database
}

public void processOrder(Order order) { ☕ Changes in MySQLDatabase affect


// Logic xử lý
[Link](order); OrderProcessor
}
}

10
MSc. Ngô Ngọc Đăng Khoa
Software Design

Loose Coupling

public interface Database {


Benefits
void save(Order order);
} ☕ Easy to switch from MySQL to MongoDB
public class MySQLDatabase implements Database {

}
public void save(Order order) { /* MySQL implementation */ } ☕ Easy to test with mock/fake database
public class MongoDatabase implements Database {
public void save(Order order) { /* MongoDB implementation */ }
☕ Changes in MySQLDatabase do not affect
}
OrderProcessor
// OrderProcessor depends on an interface
public class OrderProcessor {
private Database database;

// Dependency Injection
public OrderProcessor(Database database) {
[Link] = database;
}

public void processOrder(Order order) {


[Link](order);
}
}

11
MSc. Ngô Ngọc Đăng Khoa
Software Design

Golden Goal

High Cohesion + Low Coupling = Maintainable Code

12
MSc. Ngô Ngọc Đăng Khoa
Software Design

SOLID PRINCIPLES

13
MSc. Ngô Ngọc Đăng Khoa
Software Design

Overview
☕ S - Single Responsibility Principle
☕ O - Open/Closed Principle
☕ L - Liskov Substitution Principle
☕ I - Interface Segregation Principle
☕ D - Dependency Inversion Principle

14
MSc. Ngô Ngọc Đăng Khoa
Software Design

Purpose
☕ Make software understandable, flexible, and maintainable
☕ Reduce complexity when making changes
☕ Increase reusability

15
MSc. Ngô Ngọc Đăng Khoa
Software Design

Single Responsibility Principle (SRP)

A class should have only one reason to change

Explanation
☕ Each class performs only one single task
☕ Only one actor (user/stakeholder) can request changes to a class

☕ Avoid God Class - a class that does everything

16
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Violate SRP


Problem: User class has 5 reasons to change!

public class User { // Email - Reason for change #4


private String name; public void sendWelcomeEmail() {
private String email;
// Email sending code
// User business logic }
public void updateProfile(String name, String email) {
[Link] = name; // Report - Reason for change #5
[Link] = email;
} public String generateReport() {
return "User: " + name;
// Validation - Reason for change #2 }
public boolean validateEmail() { }
return [Link]("@");
}

// Database - Reason for change #3


public void saveToDatabase() { ... }

17
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Follow SRP


// 1. Only manage user data // 3. Only database processing
public class User { public class UserRepository {
private String name; public void save(User user) { /* DB code */ }
public User findById(String id) { /* DB code */ return null; }
private String email; }
public void updateProfile(String name, String email) { // 4. Only email sending
[Link] = name; public class EmailService {
[Link] = email; public void sendWelcomeEmail(User user) { /* Email code */ }
} }

// 5. Only report generation


public String getName() { return name; } public class UserReportGenerator {
public String getEmail() { return email; } public String generate(User user) {
} return "User Report: " + [Link]();
}
// 2. Only validation }
public class UserValidator {
public boolean validateEmail(String email) {
return [Link]("@") && [Link](".");
}
}

18
MSc. Ngô Ngọc Đăng Khoa
Software Design

Advantages of SRP
☕ Easy to understand: Each class has a clear purpose
☕ Easy to test: Test each responsibility separately
☕ Easy to maintain: Changing validation doesn't affect the database
☕ Reusability: EmailService can be used for Order , Product ...
☕ Reduce conflicts: Teams can work in parallel

Check question: How many reasons does this class have to change?"

19
MSc. Ngô Ngọc Đăng Khoa
Software Design

Open/Closed Principle (OCP)


Explanation
☕ Open for extension: Can add new features
☕ Closed for modification: Do not modify old code when adding new features
Method
☕ Use abstraction (interface, abstract class)
☕ Add features by creating new classes
☕ Do not modify code that is already tested and working well

20
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Violate OCP

Analysis
public class PaymentProcessor {
public void processPayment(String type, double amount) {
if ([Link]("CREDIT_CARD")) {
[Link]("Processing credit card: " + amount);
☕ Each time a new payment method is added,
// Credit card logic PaymentProcessor must be modified
}
else if ([Link]("PAYPAL")) {
[Link]("Processing PayPal: " + amount);
// PayPal logic
☕ All code must be retested -> Risk of
}
// Adding Momo -> must MODIFY this code! breaking old code
else if ([Link]("MOMO")) {
[Link]("Processing Momo: " + amount);
// Momo logic
}
}
}

21
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Follow OCP


// Interface - abstraction // Implementation 3 - ADD NEW without MODIFYING old code
public interface PaymentMethod { public class MomoPayment implements PaymentMethod {
void process(double amount); public void process(double amount) {
} [Link]("Processing Momo: " + amount);
// Momo logic
}
// Implementation 1 }
public class CreditCardPayment implements PaymentMethod {
public void process(double amount) { // Processor does not need modification
[Link]("Processing credit card: " + amount); public class PaymentProcessor {
// Credit card logic public void processPayment(PaymentMethod method, double amount) {
} [Link](amount);
} }
}
// Implementation 2
public class PayPalPayment implements PaymentMethod {
public void process(double amount) {
[Link]("Processing PayPal: " + amount);
// PayPal logic
}
}

22
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Follow OCP (cont)

Benefits
public class Main {
public static void main(String[] args) {
PaymentProcessor processor = new PaymentProcessor(); ☕ Adding a new payment method -> create a
// Use Credit Card new class
[Link](new CreditCardPayment(), 100.0);

// Use PayPal
[Link](new PayPalPayment(), 200.0);
☕ No modification of tested code
// Use Momo - NO NEED TO MODIFY PaymentProcessor
[Link](new MomoPayment(), 150.0);
☕ No risk of breaking old code
}
} ☕ Easy to maintain and extend

23
MSc. Ngô Ngọc Đăng Khoa
Software Design

Liskov Substitution Principle (LSP)

Liskov Substitution Principle: Objects of a subclass must be replaceable by objects of the parent
class without altering the correctness of the program.

Explanation

☕ If S is a subtype of T , then T can be replaced with S without errors

☕ Subclass must comply with the contract of the superclass


☕ Expected behavior must not be changed

Parent p = new Child(); // Must work correctly

24
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Violate LSP

public class Rectangle { public class Square extends Rectangle {


protected int width; @Override
protected int height; public void setWidth(int width) {
[Link] = width;
[Link] = width; // Violates expectations!
public void setWidth(int width) { }
[Link] = width;
} @Override
public void setHeight(int height) {
public void setHeight(int height) { [Link] = height; // Violates expectations!
[Link] = height; [Link] = height;
} }
}
public int getArea() {
return width * height;
}
}

25
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Violate LSP (cont)

public class Test {


Problem:
public static void main(String[] args) {
Rectangle rect = new Square(); // Substitution
[Link](5); ☕ Square changes the behavior of Rectangle
[Link](4);

// Expected: 5 * 4 = 20
// Actual: 4 * 4 = 16 (because Square changes both width and height!)
☕ Cannot replace Rectangle with Square
[Link]([Link]()); // 16 ???
}
}
☕ Violates the contract of Rectangle

26
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Follow LSP

// Common interface public int getArea() {


public interface Shape { return width * height;
int getArea(); }
} }

// Rectangle - independent // Square - independent


public class Rectangle implements Shape { public class Square implements Shape {
private int width; private int side;
private int height;
public Square(int side) {
public Rectangle(int width, int height) { [Link] = side;
[Link] = width; }
[Link] = height;
} public int getArea() {
return side * side;
}
}

27
MSc. Ngô Ngọc Đăng Khoa
Software Design

Interface Segregation Principle (ISP)

Interface Segregation Principle: Clients should not be forced to depend on interfaces they do not
use

Explanation
☕ Split large interfaces into multiple small, specialized interfaces
☕ Clients only implement what is necessary
☕ Avoid fat interfaces - interfaces with too many methods
🌿 Transform into multiple focused interfaces

28
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Violate ISP


Problem: RobotWorker is forced to implement unnecessary eat() and sleep() methods.

// Fat Interface - too many methods // Robot worker - VIOLATION!


public interface Worker { public class RobotWorker implements Worker {
void work(); public void work() { [Link]("Working..."); }
void eat();
void sleep(); // Robot doesn't eat/sleep but is MANDATED to implement!
void getPaid(); public void eat() {
} throw new UnsupportedOperationException("Robot doesn't eat");
}
// Human worker - OK public void sleep() {
public class HumanWorker implements Worker { throw new UnsupportedOperationException("Robot doesn't sleep");
public void work() { [Link]("Working..."); } }
public void eat() { [Link]("Eating..."); } public void getPaid() { [Link]("Getting charged..."); }
public void sleep() { [Link]("Sleeping..."); } }
public void getPaid() { [Link]("Getting paid..."); }
}

29
MSc. Ngô Ngọc Đăng Khoa
Software Design

Follow ISP

// Split into multiple small interfaces // Human implements all


public class HumanWorker implements Workable, Eatable, Sleepable, Payable {
public interface Workable { public void work() { [Link]("Working..."); }
public void eat() { [Link]("Eating..."); }
void work(); public void sleep() { [Link]("Sleeping..."); }
} }
public void getPaid() { [Link]("Getting paid..."); }

// Robot only implements what is needed


public interface Eatable { public class RobotWorker implements Workable, Payable {
void eat(); public void work() { [Link]("Working..."); }
public void getPaid() { [Link]("Getting charged..."); }
} // No need for eat(), sleep()!
}

public interface Sleepable {


void sleep();
}

public interface Payable {


void getPaid();
}

30
MSc. Ngô Ngọc Đăng Khoa
Software Design

Advantages of ISP
☕ Flexibility: Classes only implement what's needed
☕ Easy to understand: Small interfaces with a clear purpose
☕ Reduce coupling: Changing an interface has minimal impact
☕ Easy to test: Easier to mock/stub

31
MSc. Ngô Ngọc Đăng Khoa
Software Design

Realworld Example

// DAO pattern
public interface ReadableRepository<T> {
T findById(String id);
List<T> findAll();
}

public interface WritableRepository<T> {


void save(T entity);
void delete(String id);
}

// Read-only service only needs ReadableRepository


public class ReportService {
private ReadableRepository<Order> orderRepo;
// Cannot call save() or delete()
}

32
MSc. Ngô Ngọc Đăng Khoa
Software Design

Dependency Inversion Principle (DIP)

Dependency Inversion Principle


☕ High-level modules should not depend on low-level modules. Both should depend on
abstractions.

☕ Abstractions should not depend on details. Details should depend on abstractions.

Explanation
☕ Depend on interfaces/abstract classes, not on concrete classes
☕ Invert the dependency direction: from high -> low to both -> abstraction

33
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Violate DIP

// Low-level module
Problem
public class MySQLDatabase {
public void save(String data) {
[Link]("Saving to MySQL: " + data);
☕ UserService direct dependency on
} MySQLDatabase
}

// High-level module DEPENDS on low-level


public class UserService { ☕ Cannot switch to PostgreSQL, MongoDB
private MySQLDatabase database; // Depends on concrete class!

public UserService() { ☕ Hard to test without a real MySQL database


[Link] = new MySQLDatabase(); // Tight coupling!
}

public void createUser(String userData) {


// Business logic
[Link](userData);
}
}

34
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Follow DIP


// Abstraction // High-level module depends on abstraction
public interface Database { public class UserService {
void save(String data); private Database database; // Depends on interface!
}
// Dependency Injection
// Low-level module depends on abstraction public UserService(Database database) {
public class MySQLDatabase implements Database { [Link] = database;
public void save(String data) { }
[Link]("Saving to MySQL: " + data);
} public void createUser(String userData) {
} // Business logic
[Link](userData);
public class PostgreSQLDatabase implements Database { }
public void save(String data) {
[Link]("Saving to PostgreSQL: " + data); }
}
}

35
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Usage of DIP

Benefits
public class Main {
public static void main(String[] args) {
// Inject MySQL ☕ Easy to change implementations
Database mysqlDb = new MySQLDatabase();
UserService userService1 = new UserService(mysqlDb);
[Link]("John Doe"); ☕ Easy to test with mock/stub
// Switch to PostgreSQL - NO CHANGE to UserService
Database postgresDb = new PostgreSQLDatabase(); ☕ Reduced coupling
UserService userService2 = new UserService(postgresDb);
[Link]("Jane Doe");
☕ Increased flexibility
// Test with Mock
Database mockDb = new MockDatabase();
UserService testService = new UserService(mockDb);
[Link]("Test User");
}
}

36
MSc. Ngô Ngọc Đăng Khoa
Software Design

Summary
Principle Meaning Mnemonic

SRP 1 class = 1 responsibility Do one thing!

OCP Open for extension, closed for modification Add new, don't touch old

LSP Subclass replaceable for Parent Child can replace parent

ISP Small, specialized interface Don't force unnecessary work

DIP Depend on abstraction Depend on interface , not concrete

37
MSc. Ngô Ngọc Đăng Khoa
Software Design

38
MSc. Ngô Ngọc Đăng Khoa
Software Design

OTHER PRINCIPLES

39
MSc. Ngô Ngọc Đăng Khoa
Software Design

DRY - Don't Repeat Yourself

Every piece of knowledge must have a single, unambiguous, authoritative representation within a
system

Explanation
☕ Each logic segment should appear only once
☕ Avoid copy-pasting code
☕ Reuse via function , class , module

40
MSc. Ngô Ngọc Đăng Khoa
Software Design

41
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Violate DRY (WET - Write Everything Twice)

Problem: Validation logic is duplicated -> Fixed in one place, forgotten in another!

public class OrderService { public void updateOrder(Order order) {


public void createOrder(Order order) { // DUPLICATE validation logic
// Validate
if ([Link]().isEmpty()) { if ([Link]().isEmpty()) {
throw new IllegalArgumentException("Order must have items"); throw new IllegalArgumentException("Order must have items");
} }
if ([Link]() == null) { if ([Link]() == null) {
throw new IllegalArgumentException("Order must have customer"); throw new IllegalArgumentException("Order must have customer");
} }
// Save // Update
[Link](order); [Link](order);
} }
}

42
MSc. Ngô Ngọc Đăng Khoa
Software Design

Follow DRY

public class OrderService {


Benefits
// Extract validation logic
private void validateOrder(Order order) {
if ([Link]().isEmpty()) { ☕ Change in one place, affects everything
throw new IllegalArgumentException("Order must have items");
}
if ([Link]() == null) { ☕ Easy to maintain
throw new IllegalArgumentException("Order must have customer");

}
}
☕ Fewer bugs
public void createOrder(Order order) {
validateOrder(order); // Reuse
[Link](order);
☕ More concise code
}

public void updateOrder(Order order) {


validateOrder(order); // Reuse
[Link](order);
}
}

43
MSc. Ngô Ngọc Đăng Khoa
Software Design

DRY - Should
☕ Identical business logic
☕ Validation rules
☕ Complex calculations
☕ Database queries

44
MSc. Ngô Ngọc Đăng Khoa
Software Design

DRY - Shouldn't

Duplication is better than wrong abstraction

☕ Identical code but different business meanings


☕ Simple code (1-2 lines)
☕ Logic can change independently

// These two methods are IDENTICAL but have different business meanings
public double calculateOrderTotal() { return price * quantity; }
public double calculateTax() { return price * quantity; } // Coincidentally identical

45
MSc. Ngô Ngọc Đăng Khoa
Software Design

KISS - Keep It Simple, Stupid

Simplicity should be a key goal in design, and unnecessary complexity should be avoided

Explanation
☕ The simplest solution is usually the best
☕ Avoid over-engineering
☕ Readable code > Smart code

46
MSc. Ngô Ngọc Đăng Khoa
Software Design

47
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Violate KISS (Over-engineer)

// Cách phức tạp không cần thiết


Problem
public class NumberChecker {
public boolean isEven(int number) {
// Sử dụng bitwise operation "cho pro" ☕ Hard to read, hard to understand
return (number & 1) == 0;

☕ Unnecessarily complex
}

public String getStatus(boolean active) {


// Ternary lồng nhau
}
return active ? (active == true ? "ACTIVE" : "INACTIVE") : "INACTIVE";
☕ Error-prone
public int sum(int[] numbers) {
// Stream phức tạp cho việc đơn giản
return [Link](numbers)
.boxed()
.collect(Collectors
.summingInt(Integer::intValue));
}
}

48
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Follow KISS

Benefits
// Simple, easy-to-understand solution
public class NumberChecker {
public boolean isEven(int number) { ☕ Easy to read, easy to understand, even for
return number % 2 == 0; // Simple freshmen
}

public String getStatus(boolean active) { ☕ Easy to maintain


return active ? "ACTIVE" : "INACTIVE"; // Clear
} ☕ Fewer bugs
public int sum(int[] numbers) { // Simplest
int total = 0;
for (int num : numbers) {
total += num;
}
return total;
}
}

49
MSc. Ngô Ngọc Đăng Khoa
Software Design

KISS - HOW

Can others understand this code?

☕ Tránh premature optimization:


// Không cần: Optimize trước khi có vấn đề
// Nên: Code đơn giản trước, optimize sau khi đo đạc

☕ Sử dụng tên biến rõ ràng:


// Xấu: int d;
// Tốt: int daysSinceCreation;

50
MSc. Ngô Ngọc Đăng Khoa
Software Design

KISS - HOW
☕ Giữ function ngắn gọn:
// Mỗi function làm 1 việc, < 20 dòng

☕ Tránh deep nesting:


// Tránh if-else lồng nhau > 3 cấp

51
MSc. Ngô Ngọc Đăng Khoa
Software Design

YAGNI - You Aren't Gonna Need It

Do the Simplest Thing That Could Possibly Work

Explanation
☕ Only implement what is NECESSARY now
☕ Don't code for a potential future use
☕ Avoid over-engineering

52
MSc. Ngô Ngọc Đăng Khoa
Software Design

53
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Violate YAGNI

// Requirement: Lưu user vào MySQL public class MySQLUserRepository implements UserRepository {
public void save(User user) { /* Implementation */ }
public interface UserRepository {
void save(User user); // Must implement ALL unnecessary methods!
public void saveToMongoDB(User user) {
throw new UnsupportedOperationException("Not needed yet");
// "Maybe needed in the future" }
void saveToMongoDB(User user); // ... 7 more unused methods
void saveToRedis(User user); }
void saveToElasticsearch(User user);
void export ToJSON(User user);
void exportToXML(User user); ☕ Unnecessarily complex code
void exportToCSV(User user);
☕ Time-consuming to implement
// "Maybe needed for analytics"
void saveUserActivity(User user); ☕ Hard to maintain
void trackUserBehavior(User user);
} ☕ Might never be used

54
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: Follow YAGNI

// Only implement what is NEEDED


Benefits
public interface UserRepository {

}
void save(User user); // Only need MySQL for now
☕ More simple code
public class MySQLUserRepository implements UserRepository {
public void save(User user) {
// MySQL implementation
☕ Faster development
}
} ☕ Easier to maintain
// When MongoDB is ACTUALLY needed -> create new
// public class MongoDBUserRepository implements UserRepository { ... }
☕ Focus on real-world requirements
// When export is ACTUALLY needed -> create new service
// public class UserExportService { ... }

55
MSc. Ngô Ngọc Đăng Khoa
Software Design

YAGNI says NO to YAGNI does NOT say NO to


☕ Code for "might need" ☕ Clean code practices
☕ Features no one requested ☕ SOLID principles
☕ Premature optimization ☕ Design patterns
☕ Complex abstraction not needed ☕ Testing

56
MSc. Ngô Ngọc Đăng Khoa
Software Design

DRY vs KISS vs YAGNI


Principle Purpose When to Use

DRY Avoid duplication Shared logic in multiple places

KISS Keep it simple Solution design

YAGNI No redundant code Deciding to implement a feature

57
MSc. Ngô Ngọc Đăng Khoa
Software Design

Eg: DRY ft. KISS ft. YAGNI

// YAGNI: Only need the sum (no need for average, product, ...)
// KISS: Use a simple for loop (don't use complex Stream)
// DRY: Extract into a reusable method

public class Calculator {


// Simple, needed, reusable
public int sum(int[] numbers) {
int total = 0;
for (int num : numbers) {
total += num;
}
return total;
}
}

58
MSc. Ngô Ngọc Đăng Khoa
Software Design

Best Practices
Before implementation After implementation
☕ [ ] Are requirements clear? (YAGNI) ☕ [ ] Is the code understandable? (KISS)
☕ [ ] Is it the simplest solution? (KISS) ☕ [ ] Is it replaceable? (LSP)
☕ [ ] Is abstraction needed? (OCP, DIP) ☕ [ ] Is coupling low? (DIP)
During implementation
☕ [ ] Does each class do one thing? (SRP)
☕ [ ] Is there duplicate logic? (DRY)
☕ [ ] Is the interface too large? (ISP)

59
MSc. Ngô Ngọc Đăng Khoa
Software Design

Code Smell Principle Violated Solution

God Class SRP Split into multiple classes

Duplicate Code DRY Extract method/class

Long Method SRP, KISS Split method

Switch Statements OCP Use polymorphism

Tight Coupling DIP Use interface

Fat Interface ISP Split interface

Dead Code YAGNI Remove

60
MSc. Ngô Ngọc Đăng Khoa
Software Design

Problem
Scenario: Which principles does this order management system violate? Suggest adjustments?

public class OrderManager { // Payment


public void processOrder(Order order) {
// Validate if ([Link]("CARD")) {
if ([Link]()) throw new Exception("Empty order"); // Process card
} else if ([Link]("CASH")) {
// Calculate
double total = 0; // Process cash
for (Item item : [Link]) { }
total += [Link] * [Link];
}
// Save
// Apply discount [Link]("INSERT INTO orders...");
if ([Link]("VIP")) total *= 0.9;
else if ([Link]("MEMBER")) total *= 0.95;
// Send email
[Link]([Link], "Order confirmed");
}
}

61
MSc. Ngô Ngọc Đăng Khoa
Software Design

Solution
Refactor according to SOLID
// SRP: Separate responsibilities private PriceCalculator calculator;
public class OrderValidator { ... } private DiscountService discountService;
public class PriceCalculator { ... } private OrderRepository repository;
public class DiscountService { ... } private EmailService emailService;

public void processOrder(Order order, PaymentMethod payment) {


// OCP: Easy extension [Link](order);
public interface PaymentMethod { void process(double amount); } double total = [Link](order);
public class CardPayment implements PaymentMethod { ... } total = [Link](total, [Link]());
public class CashPayment implements PaymentMethod { ... } [Link](total);
[Link](order);
// DIP: Depend on abstraction [Link]([Link]().getEmail(), "Order confirmed");
public interface OrderRepository { void save(Order order); } }
public interface EmailService { void send(String to, String msg); } }

// Main service
public class OrderService {
private OrderValidator validator;

62
MSc. Ngô Ngọc Đăng Khoa
Software Design

Anti-Patterns

Over-Engineering

// Unnecessary: Interface for a class with only 1 implementation


public interface UserService { ... }
public class UserServiceImpl implements UserService { ... }

Under-Engineering

// Too simple: No abstraction where needed


public class OrderService {
private MySQLDatabase db = new MySQLDatabase(); // Tight coupling
}

63
MSc. Ngô Ngọc Đăng Khoa
Software Design

Anti-Patterns (cont)

Premature Abstraction

// Create abstraction before knowing the pattern


public interface Strategy { ... } // Don't know if strategy pattern is needed yet

Make it work, make it right, make it fast - Kent Beck

64
MSc. Ngô Ngọc Đăng Khoa
Software Design

Tools & Metrics


Static Analysis Metrics
☕ SonarQube: Detects code smells, ☕ Cyclomatic Complexity: Complexity
duplications (should be < 10)

☕ CheckStyle: Checks coding standards ☕ Coupling: Number of dependencies


between classes
☕ PMD: Finds potential bugs
Code Coverage ☕ Cohesion: LCOM (Lack of Cohesion of
Methods)
☕ Test coverage: should be > 80%
☕ Note: high coverage ≠ good code!

65
MSc. Ngô Ngọc Đăng Khoa
Software Design

Evolution of Design
☕ Good design doesn't come immediately
☕ Refactor frequently
☕ Refactor in small steps
☕ Test before refactoring

66
MSc. Ngô Ngọc Đăng Khoa
Software Design

67
MSc. Ngô Ngọc Đăng Khoa
Software Design

Common Questions
Q: When should SOLID be violated?
A: When compliance makes code unnecessarily complex. Principles are guidelines, not laws.

Q: Does DRY conflict with KISS?


A: No. DRY removes duplication, KISS keeps logic simple. Both aim for maintainable code.

Q: How to know when there's enough abstraction?


A: "Rule of Three" - When you see duplication for the 3rd time, abstract it. Times 1-2 might be early.

Q: Does YAGNI mean no design?


A: No. YAGNI means not implementing unnecessary features, but good design is still needed for current
code.

68
MSc. Ngô Ngọc Đăng Khoa
Software Design

Mindset Shift

Shift from To
☕ "Working code is enough" ☕ "Code must be easy to maintain"
☕ "Write fast, fix later" ☕ "Write it right from the start, refactor
frequently"
☕ "Only I read this code"
☕ "Code for the team and future self"

"Any fool can write code that a computer can understand. Good programmers write code that
humans can understand." - Martin Fowler

69
MSc. Ngô Ngọc Đăng Khoa
Software Design

Q&A

70
MSc. Ngô Ngọc Đăng Khoa

You might also like