Mình vừa đọc xong cuốn Clean Architecture của Robert C.Martin (còn được gọi thân mật là Uncle Bob). Phải nói rằng đây là một cuốn sách không dễ đọc nhưng chứa đựng nhiều ý tưởng quan trọng cho việc phát triển sản phẩm và nên được đọc bởi tất cả lập trình viên lẫn những nhà quản lý công nghệ. Trong bài viết này mình sẽ tóm tắt những ý tưởng quan trọng nhất mà mình thu nhập được từ cuốn sách.
A. Sản phẩm thành bại tại kiến trúc
Không khó để đoán về nội dung chính của cuốn Clean Architecture chính là khuyến khích các lập trình viên thực hiện “clean design” (thiết kế sạch) cho sản phẩm của mình.
Từ kinh nghiệm của cá nhân mình, thì trong thực tế phát triển sản phẩm hiện nay, kiến trúc hay thiết kế của sản phẩm thường ít được quan tâm đúng mức. Nhà quản lý, khách hàng, và ngay cả các lập trình viên thường quan tâm nhiều tới tiến độ release tính năng (roadmap), tới những thứ sản phẩm sẽ làm được (user story/features), tính đẹp/dễ dùng (UI/UX), khả năng chịu tải (scalable)…Kiến trúc hay thiết kế, thường được coi là thứ đã được giải quyết sẵn bởi framework (như Django/Springboot…), hoặc là thứ màu mè, tốn thời gian, không phù hợp với xu hướng phát triển phần mềm theo mô hình Agile hiện nay. Và dẫn đến kiến trúc thường là khía cạnh không được suy nghĩ, tính toán kĩ của sản phẩm, chưa nói đến việc phát triển kiến trúc sạch (clean design).
Nhưng cũng từ nhiều kinh nghiệm đau thương của bản thân, mà mình phải thừa nhận một điều mà Uncle Bob nói đúng:”mọi vấn đề trong sản phẩm phần mềm đều là vấn đề thuộc về thiết kế (design)”. Và để dễ hiểu hơn, mình wording lại:”sản phẩm phần mềm thành bại là nằm ở kiến trúc”.
Vì sao lại thế?
Vì sản phẩm phần mềm có hai giá trị: thứ nhất là giá trị hành vi, nghĩa là nó “chạy được”, và giá trị thứ hai là nó “mềm”, dễ dàng nâng cấp, bảo trì, phát triển tiếp được.
Đáng tiếc là, việc phát triển một sản phẩm vừa “chạy được” vừa “mềm” đòi hỏi rất nhiều kinh nghiệm từ lập trình viên. Cộng thêm áp lực từ deadline từ nhà quản lý chỉ quan tâm tới chuyện phần mềm “chạy được”, dẫn tới tình trạng phổ biến đó là sản phẩm phần mềm càng phát triển lại càng “cứng”, khó thay đổi, khó nâng cấp, khó bảo trì. Càng phát triển, sản phẩm càng dễ lỗi, tiến độ release tính năng mới càng bị chậm lại, và thậm chí tới một mức độ sản phẩm biến thành một mớ hỗn độn mà không lập trình viên nào cảm thấy đủ sức động chạm vào nó nữa.
Tình trạng này cũng được biết tới với tên gọi “tech debt” và là vấn đề khó hiểu với đa số dân non-tech như các nhà quản lý, đội ngũ PM, BA…nhưng nó là nguyên nhân sâu xa hàng đầu dẫn tới sự thất bại của một sản phẩm/dự án phần mềm.
Chính vì kiến trúc phần mềm sẽ quyết định thành bại của sản phẩm, nên những gì mà Uncle Bob nêu ra trong Clean Architecture là rất giá trị.
B. Clean Architecture thực chất là gì?
Nếu bạn chưa từng đọc cuốn Clean Architecture hay một số cuốn sách khách của Uncle Bob như Clean Code, Clean Agile, Clean Craftsmanship…thì có lẽ nên tạm quên mọi định nghĩa bạn từng có về từ “kiến trúc”.
Bởi vì “kiến trúc” là một từ theo mình dễ bị hiểu nhầm/hiểu sai bởi các lập trình viên, vì ngay lập tức sẽ dẫn các bạn liên tưởng tới các biểu đồ cụ thể như UML Diagram, Cloud Service Diagram…Mặc dù đúng là kiến trúc của phần mềm có thể được tường minh hoá thành các biểu đồ, với các component, service, class…kết nối với nhau, và thường được trình bày trong các tài liệu dưới hình thức này, nhưng đó chỉ là thành phẩm cuối, chứ không phải là quá trình tư duy và các cân nhắc kĩ thuật cần đưa ra để tạo nên những thành phẩm ấy.
Vì thế, khi tiếp cận clean architecture, chúng ta nên hiểu nó không nhắc gì tới UML Diagram hay các loại diagram khác, mà nói chủ yếu về các nguyên tắc, chỉ dẫn để tư duy và đưa ra quyết định, nhằm tạo ra một thiết kế kiến trúc cuối phù hợp với từng dự án phần mềm. Và theo mình thì đây mới chính là chỗ giá trị nhất của cuốn Clean Architecture, vì nó đưa ra cho lập trình viên những nguyên tắc phổ quát, có giá trị sử dụng lâu dài, chứ không chỉ là một vài mô hình cụ thể như monolith, hay microservice…
Vậy thì những nguyên tắc quan trọng nhất đó là gì? Chúng ta sẽ tiếp tục tìm hiểu ở phần tiếp theo.
C. Các nguyên tắc của Clean Architecture?
Các nguyên tắc về thiết kế kiến trúc được trình bày trong sách cũng chính là nguyên tắc SOLID áp dụng trong thiết kế kiến trúc cho lập trình hướng đối tượng. Tuy nhiên các nguyên tắc này được tổng quát hoá lên, để áp dụng cho toàn bộ các thành phần lớn hơn cấp độ class như package, component, service…
1. SRP: The Single Responsibility Principle
Ở dạng tổng quát, nguyên tắc này được phát biểu là “một module chỉ nên chịu trách nhiệm cho một và chỉ một actor”. Một actor ở đây chính là một nhóm người dùng đồng loại mà hệ thống phần mềm cần phục vụ. Ví dụ hệ thống đăng ký tín chỉ của trường học sẽ có các actor là: học sinh, giáo viên, giáo vụ…
Mục đích của nguyên tắc này là giảm tối đa những thành phần trong hệ thống phần mềm cần phải thay đổi mỗi khi có một đề bài mới từ thực tế. Bởi vì phần lớn những đề bài mới sẽ xuất phát từ nhu cầu mới của một actor cụ thể thay vì nhiều actor cùng lúc, nên nếu giảm tối thiểu thành phần phải thay đổi thì cũng giảm được bug và chi phí phát triển khác.
SRP thường được sử dụng ở cấp độ class, ở mức component nó biến thành nguyên tắc “Common Closure”, ở mức kiến trúc, nó trở thành nguyên tắc “Axis of Change”.
2. OCP: The Open-Closed Principle
Nguyên tắc này được phát biểu lần đầu bởi Bertrand Meyer vào năm 1988, nội dung của nó là “một thực thể phần mềm nên dễ dàng được mở rộng nhưng nên hạn chế với việc sửa đổi”. Điều này có nghĩa là khi thực hiện tính năng mới, thì kiến trúc phần mềm tốt nên cho phép làm điều đó bằng cách “thêm” các thành phần mới, thay vì phải sửa các thành phần đã có.
Ở cấp độ class, điều này có nghĩa là nên sử dụng một số design pattern như Strategy pattern. Ở cấp độ component, nguyên tắc này khuyên ta nên duy trì “mũi tên phụ thuộc” theo hướng những thành phần thuộc về chi tiết và hay thay đổi như Database, UI…phải phụ thuộc vào các thành phần cốt lõi, ít thay đổi hơn như UseCase, Entity…
3. LSP: The Liskov Substitution Principle
Nguyên tắc này được mô tả bằng một định nghĩa toán học khá khó nhớ, vì thế mình wording lại cho dễ hiểu hơn như sau: nên thiết kế để các thành phần trong hệ thống mà có chức năng tương tự nhau có thể thay thế được hoàn toàn cho nhau. Ví dụ phụ tùng gương cho xe Honda cũng nên dùng chung được cho xe Vision hay xe Wave…
Về mặt ứng dụng, nguyên tắc này khuyến khích việc xây dựng các Interface chuẩn và để các thành phần có thể thay thế triển khai interface này.
4. ISP: The interface segregation principle
Nguyên tắc này có thể giải thích đơn giản là: cố gắng đừng sử dụng các module có chứa nhiều thứ hơn bạn cần, bởi vì các module này có thể phục vụ các nhu cầu khác và khi nhu cầu đó thay đổi, nó có thể ảnh hưởng tới chức năng mà bạn đang cần dùng.
5. DIP: The dependency inversion principle
Nguyên tắc này giải thích một kĩ thuật cho phép chúng ta điều khiển được chiều của mũi tên phụ thuộc và bảo đảm những thành phần hay thay đổi (như UI, Database…) sẽ phụ thuộc vào các thành phần ít thay đổi (Usecase, Entity) thay vì ngược lại. Nguyên tắc này hơi khó giải thích chỉ bằng lời, nhưng nó là nguyên tắc cơ bản được sử dụng rất nhiều trong các framework để giúp tạo ra kiến trúc tốt. Vì vậy những bạn quan tâm có thể search Google để đọc kĩ hơn về nguyên tắc này.
D. Còn gì nữa không?
Ngoài các nguyên tắc SOLID, thì cuốn Clean Architecture còn bàn chi tiết vào rất nhiều vấn đề khác như vì sao nên delay các quyết định kĩ thuật quan trọng, vì sao nên decouple core logic của phần mềm khỏi UI, Database, Firmware…tách component ở cấp độ nào là phù hợp: module, package, component, service, application? nên tách phần mềm theo layer, hay theo domain…monolith hay microservice….Đây đều là các chủ đề thú vị có giá trị thực tiễn nhưng được trình bày một cách hơi rời rạc trong cuốn sách, nên mình nghĩ tốt nhất nên để các bạn quan tâm tự đọc và cảm nhận.
Tổng quan chung thì mình nghĩ Clean Architecture và các cuốn có đầu Clean khác của Uncle Bob theo mình rất đáng đọc. Dù bác Uncle Bob thi thoảng hay lan man thích kể chuyện tí (kể từ thời ngày xưa lập trình với bìa đục lỗ thế nào, rồi quản lý code bằng băng từ ra sao….), rồi nội dung giữa các cuốn đôi khi bị trùng lặp, nhưng đây đều là những kiến thức có giá trị mà lập trình viên cần biết và thậm chí sẽ quyết định tới thành bại của sản phẩm như một số dự án mình đã được trải nghiệm.
Nếu bạn có thêm những suy nghĩ khác sau khi đọc cuốn sách này, hãy chia sẻ bằng cách để lại comment cho mình nhé 😀
COMMENTS