Software Development Design Principles (trong bài viết này mình sẽ gọi tắt là Design Princples), tạm dịch là những nguyên tắc thiết kế phần mềm, là một khái niệm quan yếu trong ngành nghề kỹ thuật phần mềm. Design Principles sở hữu thể coi là những "lời khuyên" mang tính cơ bản, để giúp bạn thiết kế một sản phẩm tiện lợi để phát triển, tiện lợi để bảo trì, hay thuần tuý là sở hữu thể vận hành tốt. Design Principles thỉnh thoảng sở hữu hay được so sánh với một khái niệm khác hay gây nhầm lẫn, là Design Patterns, và do thiên nhiều về mặt lý thuyết, nên ko phải người nào cũng chú trọng hay thích tìm hiểu về chúng.
Cách đây hơn 4 năm, mình đã từng làm một seminar về nội dung Object Oriented Design Principles (những nguyên lý thiết kế hướng đối tượng) để giới thiệu qua về SOLID Principles, và sở hữu một bài viết bao gồm slide only tại đây . Hồi trước thuần tuý là chỉ đưa slide lên trước để thỉnh thoảng nhắc nhở bản thân lúc nhìn lại danh sách bài viết của mình mà nhớ ra rằng, một lúc nào đó cần phải sở hữu một bài viết đi sâu vào vấn đề này. Thấm thoắt đã 4 năm trôi qua (^^;)
Hồi đó số lượng bài viết trên Viblo cũng chưa nhiều, và cũng chẳng mấy người nào nhắc hay viết về Design Principles cả. Seminar, hay Slide cũ của mình cũng là tập trung nói về SOLID Principles là chính. Tuy nhiên, hiện tại ngày nay cũng khác xưa nhiều. Search trên Viblo, những bạn sẽ tìm thấy phải tới vài chục bài viết về SOLID cũng nên Nếu những bạn muốn tìm hiểu sâu về SOLID, sở hữu thể tham khảo những bài trên Viblo với tag solid tại https://viblo.asia/tags/solid , hoặc sở hữu thể tham khảo slide cũ của mình tại bài viết này. Trước đây, mình cũng sở hữu tạo một repo code mẫu cho từng nguyên lý trong SOLID, nếu bạn sở hữu thể đọc hiểu PHP, thì bạn sở hữu thể tham khảo source code tại https://github.com/wataridori/solid-php-example
Cũng chính vì giờ người người viết về SOLID, nhà nhà bàn về SOLID tương tự, thế nên trong bài viết này, mình sẽ ko tập trung vào nó nữa, mà thay vào đó sẽ giới thiệu tới mọi người một số Design Principles khác, sở hữu thể ít được biết tới hơn, nhưng cũng thú vị ko kém. Kỳ vọng sở hữu thể giúp ích được cho mọi người.
Tuy nhiên, trước lúc đi vào nội dung những Design Principles cụ thể, chúng ta hãy cùng tìm hiểu sâu hơn về khái niệm này trước nhé, để xem Design Principles và Design Patterns khác nhau như thế nào đã nhé
Design Principles vs Design Patterns
Design Principles hiểu thuần tuý là những nguyên tắc, nguyên lý thiết kế, trong lúc Design Patterns là những khuôn mẫu thiết kế. Tức Design Principles đưa ra cho chúng ta những "gợi ý", "lời khuyên", "hướng dẫn", còn Design Patterns đưa ra cho chúng ta luôn một "lời giải mẫu" cho một bài toán cụ thể trong thực tế. Hay Design Principles là ở mức low-level, còn Design Patterns là ở mức high-level, và trên thực tế thì những Design Patterns tốt đều sẽ thỏa mãn những Design Principles tốt.
Trên Viblo cũng sở hữu khác nhiều bài viết về chủ đề Design Patterns rồi, những bạn sở hữu thể tìm hiểu thêm ở đây. Còn trong bài viết này, mình sẽ tập trung giới thiệu về một số Software Development Design Principles nổi tiếng là chủ yếu. Thông qua đó kỳ vọng những bạn cũng sẽ sở hữu được dòng nhìn tổng quan xem như thế nào được gọi là Design Principles
Một số Design Principles bạn nên biết
DRY
DRY là viết tắt của từ Don't Repeat Yourself, tức đừng lặp lại chính bạn. DRY mang hàm ý hãy nỗ lực đừng lặp lại những đoạn code, hay những xử lý ở nhiều nơi khác nhau. DRY ko chỉ ứng dụng trong việc code, mà còn cả trong việc viết documentation, hay thiết kế database schemas ...
Việc thực hiện tốt DRY sẽ giúp bạn maintain code tốt hơn, hay khắc phục vấn đề thay đổi logic code của một đoạn xử lý tiện lợi hơn sau này.
Kế bên DRY, người ta còn hay nhắc tới một khái niệm đối lập, khá là vui là WET =)) WET sở hữu thể hiểu là "write every time" (viết mọi lúc), "write everything twice" (viết mỗi thứ hai lần), "we enjoy typing" (chúng tôi thích việc đánh máy) or "waste everyone's time" (tốn thời kì của tất cả mọi người). Nhìn chung, lúc bạn vi phạm DRY, thì bạn sẽ WET
KISS
KISS là viết tắt của từ Keep It Simple, Stupid, tức để nó thuần tuý thôi, đồ ngốc. Nguyên lý KISS nhắc tới việc tính thuần tuý (simple) nên được đặt là mục tiêu của việc thiết kế hệ thống, và hầu hết những hệ thống sẽ làm việc tốt nhất lúc nó được giữ ở trạng thái thuần tuý, thay vì bị phức tạp hóa vấn đề hơn. Những sự phức tạp hóa vấn đề một cách ko cần thiết luôn cần được loại bỏ.
Bạn sở hữu thể sẽ thấy nguyên lý KISS mang ý nghĩa rất giống với một số câu nói nổi tiếng khác như "Simple is the best", "Simplicity is the ultimate sophistication", "Make Simple Tasks Simple" ... chúng đều đề cao tính "thuần tuý" trong việc khắc phục vấn đề.
Tuy nhiên nguyên lý này cần phải hiểu cho đúng cách. "Simple" ở đây là chỉ một "cách khắc phục được vấn đề", chứ ko phải "thuần tuý" tới mức ko thể vận hành được hệ thống theo ý muốn, thì chỉ sở hữu toang =))
YAGNI
YAGNI là viết tắt của từ You aren't gonna need it, tức bạn sở hữu thể sẽ ko cần tới nó đâu. YAGNI là một principle được giới thiệu trong extreme programming. Nó miêu tả rằng bạn ko nên đưa vào những chức năng cho tới lúc chúng thực sự cần thiết, hay chỉ tiến hành implement những chức năng mà bạn cảm thấy là mình cần tới nó, chứ ko phải là bạn cảm thấy sau này sở hữu thể sẽ cần tới nó.
Nội dung thì thuần tuý là tương tự, nhưng để hiểu rõ và thấm nhuần YAGNI lại ko phải là một việc tiện lợi. Bạn sở hữu thể tìm hiểu thêm về YAGNI trên bài blog của Martin Fowler tại đây.
Trong bài giới thiệu về YAGNI của mình, Martin Fowler sở hữu nhắc tới 4 vấn đề lúc vi phạm YAGNI:
- Cost of building: Lúc bạn làm chức năng mà cuối cùng ko cần tới nó. Nó làm bạn tốn nhiều effort trong việc lên thiết kế, code, test ...
- Cost of repair: Lúc chức năng mà bạn hướng tới là cần thiết, nhưng bạn lại implement theo một cách ko hợp lý. Nó sẽ làm bạn tốn effort để lên kế hoạch lại, code lại, và test lại chức năng đã làm, bởi nó ko thực sự là những gì bạn cần
- Cost of delay: Dù trong bất kỳ trường hợp nào, bạn cũng sẽ gặp phải vấn đề này. Bạn đang mất thời kì vào một chức năng mà mình chưa cần tới ở thời khắc hiện tại, nó kéo theo việc những chức năng cần thiết ở thời khắc hiện tại ko thể được hoàn thiện và release sớm
- Cost of carry: Dù trong bất kỳ trường hợp nào, bạn cũng sẽ gặp phải vấn đề này. Bạn đang thêm một lượng code mới vào trong project của mình, làm cho hệ thống phức tạp hơn và sẽ mất công để maintain, modify, debug hơn
Thực tế cũng rất khó để khái niệm ranh rới của YAGNI. Sở hữu rất nhiều tính năng, hay đoạn xử lý logic bạn sẽ phải đắn đo cân nhắc xem sở hữu phải YAGNI hay ko. Do đó việc sở hữu được suy nghĩ thoáng về YAGNI là một điều cần thiết. Martin Fowler cũng sở hữu đưa ra một gợi ý rằng "Yagni only applies to capabilities built into the software to support a presumptive feature, it does not apply to effort to make the software easier to modify", tức nguyên lý YAGNI chỉ nên sử dụng lúc bạn định thêm vào phần mềm một Feature mà bạn "dự đoán" sẽ sử dụng trong tương lai, chứ ko nên apply YAGNI vào việc nỗ lực để làm cho phần mềm trở nên tiện lợi chỉnh sửa, maintain hơn.
Boy Scout Rule
Boy Scout Rule là một nguyên lý sở hữu nội dung dựa trên quy tắc sở hữu thật của hội hướng đạo sinh Mỹ (Boy Scouts of America). Quy tắc đó sở hữu nội dung là "Leave the campground cleaner than you found it", tức hãy giữ cho khu cắm trại sạch sẽ hơn lúc bạn tới.
Boy Scout Rule được vận dụng trong thiết kế phần mềm với nội dung dạng như hãy giữ cho code được sạch đẹp hơn lúc bạn chưa chỉnh sửa nó =)) Tức đừng sở hữu mà làm cho một đoạn code đã sở hữu sẵn trở nên tồi tệ hơn.
Boy Scout Rule được phát biểu dưới nhiều dạng khác nhau như: "always leave the code you're editing a little better than you found it", "always leave the code cleaner/better than you found it", "Always check a module in cleaner than when you checked it out" ...
Separation of Concerns (SoC)
Separation of Concerns sở hữu tức là phân tích phụ thuộc hay chia tách quan hệ.
Tư tưởng của Separation of Concerns là phân tích hệ thống ra thành những thành phần, chức năng nhỏ hơn, sao cho chúng càng ít điểm chung (về mặt chức năng), hay càng ít phụ thuộc vào nhau càng tốt. Lúc những thành phần được ghép nối vào trong hệ thống, chúng sẽ tương tác với nhau thông qua thông tin về Interface, hay những open API, mà ko cần phải biết những thành phần kia được xây dựng như thế nào, bên trong đó được lập trình (implement) ra sao.
Separation of Concerns là một nguyên lý rất quan yếu và được sử dụng rất nhiều trong thiết kế và phát triển phầm mềm hiện đại. Bạn sở hữu thể bắt gặp nó ở rất nhiều nơi, ở những tầng sở hữu quy mô to, hay ở những mức quy mô nhỏ. Trước đây cũng đã từng sở hữu một bạn đặt thắc mắc về Separation of Concerns trên Viblo tại đây và mình cũng đã sở hữu một câu trả lời khá kỹ về nguyên lý này, những bạn muốn tìm hiểu thêm sở hữu thể xem qua tại đây
Low Coupling
Low Coupling, hay Loose Coupling, hay Weak Coupling, hay Minimise Coupling, là tên một nguyên lý thiết kế miêu tả về "độ phục thuộc" (coupling) giữa những modules, hay components (ví dụ như classes, interfaces, services) trong hệ thống. Lúc đó độ phụ thuộc của những module là càng thấp thì càng tốt. Tức một component biết càng ít, và sở hữu càng ít quan hệ với một component khác thì càng tốt.
Một hệ thống trái ngược với Low Coupling gọi là High Coupling, hay Tight Coupling.
Một hệ thống High Coupling là hệ thống mà ở đó một component biết quá nhiều về cách hoạt động bên trong của một component khác. Chính việc phụ thuộc chặt chẽ vào nhau tương tự kéo theo một sự thay đổi ở component này làm cho nhiều components khác cũng phải thay đổi theo. Hay việc sử dụng lại một component sẽ trở nên khó khăn hơn, lúc mà nó sở hữu hàng tá dependencies được kéo theo. Đồng thời những lập trình viên sẽ ngày một trở nên e nghại việc maintain, update một component hơn, lúc mà ko thể nắm rõ được nó sẽ tác động như thế nào với những component khác
High Cohesion
High Cohesion, hay Strong Cohesion hay Maximize Cohesion là tên một nguyên lý miêu tả về mức độ quan hệ giữa những method bên trong một class (hay giữa những classes bên trong một module). Một hệ thống sở hữu High Cohesion được thể hiện qua việc những chức năng bên trong Class sở hữu thể được access thông qua một số methods của nó, và những methods public đó thì sẽ thực hiện một số những hoạt động sở hữu liên quan.
Khái niệm High Cohesion thường đi kèm với Low Coupling, tạo thành một "cặp đôi tuyệt vời" cho việc thiết kế quan hệ bên trong một component, cũng như giữa những component với nhau. Nhìn chung, một hệ thống tốt là một hệ thống High Cohesion, Low Coupling.
Law of Demeter (LoD)
Law of Demeter, hay principle of least knowledge (nguyên lý "hiểu biết ít nhất"), là một principle thường được vận dụng trong lập trình hướng đối tượng, để giúp đảm bảo tính Low Coupling giữa những component.
Law of Demeter sở hữu thể được miêu tả bởi một trong những cách sau:
- Những unit chỉ nên sở hữu một số lượng hiểu biết sở hữu giới hạn về những units khác. Chúng chỉ nên biết về những units sở hữu mối quan hệ trực tiếp, sắp gũi với chúng.
- Những unit chỉ nên "nói chuyện" với bạn bè của chúng, ko "nói chuyện" với người lạ
- Chỉ nói chuyện với bạn bè trực tiếp của bạn (ko nên nói chuyện với bạn của bạn của bạn)
Theo đó thì một method m
của một object O
chỉ nên "nói chuyện" (thực hiện lời gọi hàm) với những hàm nằm trong những objects như sau:
- Bản thân
O
- Những objects là thông số truyền vào bên trong
m
- Những objects được khởi tạo bên trong
m
- Những objects nằm trực tiếp bên trong
O
- Những biến global mà sở hữu thể được access từ bên trong scope của
m
Ví dụ như những trường hợp sau là vi phạm nguyên lý Law of Demeter:
email = user.getProfile().getEmail(); // object user đã "biết quá nhiều" lúc thực hiện lời gọi hàm getEmail() từ kết quả trả về của hàm getProfile() familyName = user.getProfile().getName().getFamilyName(); // object user ở đây còn biết nhiều hơn cả trường hợp ở trên nữa =))
Để implement theo nguyên lý Law of Demeter, ta sẽ cần viết những hàm wrapper để tạo điều kiện cho object sẽ sở hữu thể gọi thẳng tới hàm mà nó mong muốn. Ví dụ như viết hàm getEmail()
bên trong User để ta sở hữu thể gọi trực tiếp email = user.getEmail()
. Điều này sẽ tạo điều kiện cho code trở nên dễ đọc, dễ hiểu và dễ maintain hơn. Về sau nếu sở hữu cần thay đổi logic lấy ra email thì ta sẽ chỉ cần update bên trong hàm getEmail()
của class User là được, chứ ko cần phải tìm tới tất cả những chỗ sở hữu xử lý user.getProfile().getEmail()
để update từng dòng một nữa.
Tuy nhiên, việc tuân thủ máy móc theo Law of Demeter sẽ dẫn tới một vấn đề là trong code của bạn sẽ xuất hiện quá nhiều những hàm wrapper, trái lại sẽ làm cho khối lượng code trở nên cồng kềnh hơn, và cũng mất nhiều thời kì để viết những hàm wrapper tương tự hơn Chính vì thế việc vận dụng Law of Demeter ra sao và vào những thời khắc nào cũng nên được cân nhắc cho kỹ.
Curly's Law
Curly's Law là một nguyên lý với nội dung thuần tuý là Do One Thing, hay chỉ làm một việc duy nhất. Theo đó thì mỗi đơn vị trong source code (method, class, module) đều cần phải sở hữu một mục tiêu rõ ràng, và duy nhất. Những bản sở hữu thể tưởng tượng nguyên lý này sắp tương tự với Single Responsibility Principle (nguyên tắc đơn trách nhiệm, hay nguyên tắc trách nhiệm duy nhất) trong SOLID.
Principle of least astonishment (POLA)
Principle of least astonishment hay còn gọi là principle of least surprise, tức nguyên tắc bất thần nhỏ nhất. Đây là nguyên lý sở hữu nội dung liên quan tới việc thiết kế tính năng, giao diện, hay trải nghiệm người sử dụng. Nội dung của nó được miêu tả là "If a necessary feature has a high astonishment factor, it may be necessary to redesign the feature", tức nếu một chức năng cần thiết mà sở hữu yếu tố gây bất thần cao, thì sở hữu thể chúng ta cần phải thiết kế lại chức năng đó Hay nói cách khác thì Principle of least astonishment nói rằng một thành phần của hệ thống nên hoạt động theo cách mà hầu hết người sử dụng mong đợi nó sẽ hoạt động, hay cách thức hoạt động của một thành phần của hệ thống ko nên gây ngạc nhiên cho người sử dụng.
Principle of least privilege (PoLP)
Principle of least privilege, hay còn gọi là principle of minimal privilege hay principle of least authority, tức nguyên tắc quyền hạn tối thiểu, là một nguyên tắc được vận dụng nhiều trong những ngành khoa học máy tính, thiết kế phần mềm, bảo mật máy tính. Nó miêu tả rằng từng module (như process, user, hay program ...) của hệ thống chỉ sở hữu thể truy cập thông tin và tài nguyên cần thiết cho mục đích hợp pháp của nó. Nó sẽ giúp hệ thống trở nên ổn định hơn, lúc từng thành phần, từng chương trình đều sở hữu quyền đã được giới hạn của riêng nó, từ đó ko thể gây tác động ko mong muốn tới những chương trình khác, hay gây ra crash hệ thống. Ngoài ra, nó sẽ giúp hệ thống trở nên bảo mật hơn, lúc mà một lỗ hổng của chương trình này sẽ khó để sở hữu thể bị khai thác, hay gây tác động tới toàn hệ thống hơn...
Tổng kết
Trên đây là một số Software Development Design Principles mình cảm thấy khá hay và sở hữu tính ứng dụng cao, kỳ vọng nó cũng sẽ giúp ích cho mọi người. Ngoài ra, như đã nhắc ngay từ ban sơ, thì bài này mình ko nhắc tới 5 Design Principles vô cùng quan yếu trong Object Oriented Programming là SOLID, bởi vì trên Viblo cũng đã sở hữu quá nhiều bài viết về SOLID rồi. Nếu bạn nào chưa nắm rõ về SOLID thì thử tìm đọc những bài viết về SOLID tại đây nhé, sẽ rất là hữu ích đấy
Xin hứa gặp lại những bạn ở những bài viết sau
References
- https://java-design-patterns.com/principles/
- http://wiki.c2.com/?CouplingAndCohesion
- https://blog.codinghorror.com/curlys-law-do-one-thing/
- https://nalexn.github.io/separation-of-concerns/
- https://en.wikipedia.org/wiki/Principle_of_least_privilege
- https://en.wikipedia.org/wiki/Don't_repeat_yourself
- https://en.wikipedia.org/wiki/KISS_principle
- https://en.wikipedia.org/wiki/You_aren't_gonna_need_it
- https://martinfowler.com/bliki/Yagni.html
- https://en.wikipedia.org/wiki/Separation_of_concerns
- https://en.wikipedia.org/wiki/Law_of_Demeter
- https://blog.codinghorror.com/curlys-law-do-one-thing/
- https://en.wikipedia.org/wiki/Principle_of_least_astonishment