Open hoangquochung1110 opened 3 months ago
Khả năng nhận biết độ phức tạp là một kĩ năng then chốt. Nhằm có quyết định đúng đắn giữa các lựa chọn thiết kế
Ở high level, có 2 tác nhân chính:
Nếu chúng ta tìm ra các kĩ thuật thuyết kế mà giảm thiểu dependencies và obscurity thì có thể tạo ra hệ thống đơn giản hơn
Module ở đây tức bất kì đơn vị code nào mà có interface và implementation. Nếu interface ở 1 module đơn giản hơn implementation của nó, càng có nhiều cơ hội để module này đc sửa đổi mà ko ảnh hưởng đến module khác
Thay đổi mindset từ tactical programming sang strategic programming vì working code thôi thì chưa đủ.
Tactical programming:
Strategic programming: yêu cầu tư duy đầu tư, tức dành nhiều thời gian cải thiện thiết kế hệ thống thay vì tìm đường đi ngắn nhất để hoàn thành 1 tác vụ.
Có 2 hình thức đầu tư chính: đầu tư chủ động (proactive) và đầu tư phản ứng (reactive). Đầu tư chủ động: dành thời gian để thử nhiều các lựa chọn thiết kế khác nhau trước khi chọn 1 Đầu tư phản ứng: khi có bug trong hệ thống, thay vì vá hay thậm chí làm ngơ thì dành thêm thời gian để sửa lỗi 1 cách triệt để
Ở thiết kế module, hệ thống phần mềm đc phân tách thành nhiều module mà một cách tương đối chúng độc lập với nhau. Tuy nhiên ở đk thực tế điều này ko xảy ra, các module thường phải gọi các method của nhau để hoàn thành 1 tác vụ, vì vậy dependencies giữa chúng là ko thể tránh khỏi.
💼 Quản lí, giảm thiểu dependencies giữa các module trong hệ thống: Dependencies giữa các module có thể hiểu: khi 1 module sửa đổi, các module khác có thể cần phải sửa đổi theo. Ví dụ, module A thay đổi 1 argument bắt buộc ở 1 method của nó, tất cả các module khác mà gọi method này buộc phải thay đổi theo để đáp ứng đúng signature của method.
💼 Xây dựng module có chiều sâu (Deep module): Bằng cách tách biệt interface (của module) khỏi implementation (của nó), chúng ta có thể che giấu đi complexity khỏi phần còn lại của hệ thống.
Ví dụ: cho 1 chiếc máy giặt có các thành phần cấu tạo chính như sau: lồng giặt, motor máy giặt, van cấp nước, dây curoa. Giả sử máy giặt cung cấp 2 chế độ giặt chính cho users (Interface): giặt quần áo và giặt chăn màn. Về bản chất bên trong, máy giặt sẽ cài đặt cái thông số kĩ thuật khác nhau, tương ứng từng chế độ. Ví dụ chế độ quần áo, van cấp nước đổ vào 50L ở nhiệt độ 40 độ C, motor tạo công suất 100W/h trong khi chế độ chăn màn, nó sẽ cung cấp 100L nước tại 100 độ C và yêu cầu motor tạo ra công suất 200W/h. Dĩ nhiên users ko cần hiểu biết sâu về vận hành, việc của họ đơn giản chỉ vặn núm xoay chọn chế độ giặt.
Các nguyên lí thiết kế cơ bản
Module có thể chia thành 2 thành phần: Interface và Implementation Module có chiều sâu tức: Cung cấp interface đơn giản cho users trong khi hỗ trợ rất nhiều tính năng đằng sau
❌ Các lời khuyên thường đc truyền bá như: class nên ngắn gọn (small), method nên dài dưới N dòng. Thoạt đầu các module này 1 cách đơn lẻ trông đơn giản -> giảm complexity. Tuy nhiên, bản thân chúng ko mang lại nhiều tính năng lớn cho hệ thống -> Cần nhiều chúng, mỗi cái lại có interface khác nhau, khi cộng dồn/tích luỹ chúng lại làm tăng complexity về mặt tổng thể toàn hệ thống. Ngoài ra, việc các module ngắn gọn gọi nhau để hoàn thành 1 tác vụ dẫn đến phong cách lập trình dài dòng (do boilerplate code cần có cho mỗi module)
Là 1 trong các kĩ thuật quan trọng để đạt đc module có chiều sâu Các thông tin cần che giấu bao gồm:
Information hiding giảm complexity theo 2 cách:
Dev: ❌ Để users đối diện với sự phức tạp, ví dụ: khi bạn ko rõ về một điều kiện xảy ra, bạn quăng exception và để caller xử lí nó. Hay khi bạn ko chắc về 1 policy đc vận hành như thế nào thì bạn định nghĩa một parameter để control nó và đùn đẩy trách nhiệm tìm ra giá trị phù hợp cho người dùng -> khuếch đại complexity, thay vì một mình bạn (module developer) đối phó vơí nó thì rất nhiều người (users) phải xử lí nó ✅ Dev cần "đấu tranh" (strive/fight) để làm cho việc sử dụng module của người dùng càng đơn giản càng tốt
Nhận biết và phòng tránh các redflag khi thiết kế hệ thống
Classification