1. Software design – Tổng quan về software design
Tổng quan về software design, ta có thể phân chia thành 5 level
- General & OO Concept (coupling, cohesion, …): Đây là tầng thấp nhất, cũng là tầng basic nhất làm nền móng cho các design pattern hay các nguyên lý thiết kế khác
- Specific Data Structures, Algorithmic Approaches (sort, tree, backtracking, …): Cách tổ chức các cấu trúc dữ liệu, các thuật toán. Việc nắm vững các cấu trúc dữ liệu & thuật toán sẽ giúp cho việc thiết kế phần mềm trở nên tối ưu hơn.
- OOD Principles (SOLID, …): Dựa trên các concept về hướng đối tượng và cách tổ chức cấu trúc dữ liệu, các nguyên lý thiết kế được ra đời.
- OOD Pattern (Creational patterns, structural patterns, behavioral patterns): Dựa trên các nguyên lý thiết kế được xây dựng trước đó, các lập trình viên hay software architecture đã sáng tạo ra các pattern để giải quyết được các vấn đề đã đặt ra ở các level trước đó. Các design pattern này bắt buộc các lập trình viên phải tinh chỉnh mã nguồn cho phù hợp và tuân theo các nguyên lý của từng bản thiết kế.
- Architecture/Framework (J2EE, Financial System, …): Việc áp dụng các design pattern đã được xây dựng sẵn sẽ giúp chúng ta hiện thực hoá được các ý tưởng, các nguyên lý thiết kế trước đó.
2. Design concept
Ý tưởng thiết kế chúng ta sẽ có 2 khái niệm như dưới đây:
- GENERAL: Cohesion, Coupling, Information hiding
- OO Specific: Behavior & follow data, Class & interface, OO (object oriented)
3. Coupling
Coupling: Được hiểu là sự móc nối, kết dính giữa các module. Có thể hiểu rằng trong một module, các thành phần liên kết với nhau quá chặt chẽ, quá phụ thuộc lẫn nhau, việc 1 thành phần phát sinh lỗi sẽ ảnh hưởng đến các thành phần khác.
Cụ thể ta có thể xem hình ảnh dưới đây
3 module A, B, C, mỗi module đều có các thành phần (sub-module) của riêng nó. Có thể thấy rằng các sub-module này liên kết với nhau rất chặt và rối. Bản thiết kế này đã vi phạm các nguyên tắc của Coupling.
Ta sẽ đi sâu vào các Coupling dưới đây
3.1 Content coupling – worse coupling
Đây là Coupling tồi nhất, vì một lý do nào đó, nội dung của element trong module này lại có thể bị chỉnh sửa bởi một module khác. Điều này đã vi phạm nghiêm trọng tính đóng gói (Encapsulation) và che giấu dữ liệu (information hiding).
Ví dụ:
- Thay đổi dữ liệu (modify data)
- Thay đổi local data
- Thay đổi mã nguồn (assembly)
Đoạn mã nguồn phía trên đã vị phạm Content coupling khi class DatabaseCleaner có thể truy cập và chỉnh sửa dữ liệu của class Database, việc này có thể khiến cho dữ liệu của class Database không được kiểm soát.
Chúng ta sẽ cải thiện đoạn mã nguồn đó như sau
3.2 Common coupling – poor coupling
Khái niệm: Các module cùng sử dụng chung một dữ liệu toàn cục
Việc này cũng vi phạm tính đóng gói và che giấu dữ liệu khi bất cứ module nào cũng có thể truy cập được vào dữ liệu.
Loại Coupling này sẽ thường gặp trong lập trình hướng thủ tục như C/C++
Có một số cách có thể cải thiện việc này như:
- OOP: Quản lý data trong một module, cung cấp các method cho data đó
- Lập trình hướng thủ tục: Cung cấp các function đọc/ghi data
3.3 Control coupling – bad coupling
Khái niệm: Module khác điều khiển luồng của module được gọi
Việc này chứng tỏ rằng các module gọi tới phải biết được thuật toán của module được gói. Lúc này module được gọi sẽ không còn là “nhà cung cấp” các function nữa mà chính nó đã bị các module khác can thiệp vào luồng hoạt động cũng như thuật toán. Điều này có thể dẫn đến các luồng hoạt động nội trong module bị sai hoặc không còn hoạt động.
Phân tích đoạn mã nguồn trên, class Drawer cung cấp phương thức draw và nhận vào 3 tham số là toạ độ của 3 điểm. Hàm draw này dựa vào drawType để quyết định xem sẽ gọi tới hàm drawTriangle hay drawLine. Điều này có nghĩa là, bất cứ module nào gọi tới hàm draw này cần biết được nên truyền tham số drawType bằng bao nhiêu? Tại sao các module này biết được muốn drawTriangle phải truyền drawType = 1? Việc này tức là thuật toán của hàm draw đã bị lộ cho các module khác.
Chúng ta có thể có 1 số cách để improve tuỳ thuộc vào context và nghiệp vụ cho từng bài toán
3.4 Stamp coupling
Khái niệm: Truyền tham số nhưng không dùng hết
Các lập trình viên thường sẽ hay mắc phải coupling này
class SalaryProcessor chỉ cần tham số salary để tính lương nhưng lại truyền cả class Employee vào => dư thừa và bị lộ những dữ liệu không cần thiết
Ta có thể improve bằng cách chỉ truyền các tham số dạng nguyên thuỷ
3.5 Data coupling – best coupling
Khái niệm
- Tham số truyền vào là tham số về dữ liệu, không phải để điều khiển
- Simple argument
Các tham số truyền vào với mục đích tính toán, làm việc với dữ liệu
4. Tổng kết
Một bản thiết kế tốt sẽ giúp cho mã nguồn trở nên dễ đọc, dễ hiểu và dễ maintain hơn
Tháp coupling dưới đây là để chi cho mức độ nghiêm trọng của từng coupling