Giới Thiệu
Trong phần này, chúng ta sẽ cùng nhau tìm hiểu một ví dụ thực tế về nguyên tắc Đóng/Mở trong lập trình, làm nổi bật quyết định giữa việc mở rộng hay sửa đổi phần mềm. Bài viết sẽ trình bày giải pháp cho chức năng chuyển đổi một mô hình thành một trang markup (như HTML hoặc XML).
Tình Huống
Trong dự án của tôi, có hai thành phần chính cần nói đến: PageParser (phần code cũ) và NodeParser (phần code mới được tái cấu trúc). PageParser là phần mã đã được sử dụng rộng rãi, trong khi NodeParser là phần mã mới, được tách ra từ một hàm gần 1000 dòng trong PageParser. Khi tiến hành tái cấu trúc, tôi đã quyết định chỉ tách NodeParser vì nó chỉ được sử dụng nội bộ, trong khi PageParser vẫn cần được giữ nguyên ở hiện trạng do nó tác động đến nhiều vị trí khác trong hệ thống.
Gần đây, đã xuất hiện yêu cầu rằng trong một số trường hợp cụ thể, LinkNodeParser không cần hoạt động và nên trả về null ngay lập tức. Với yêu cầu này, tôi đã thực hiện các thay đổi như sau:
- Thêm Điều Kiện Kiểm Tra: Trong LinkNodeParser, tôi đã thêm đoạn mã kiểm tra điều kiện trong
ParsingOptions
để trả về giá trị null nếu cần thiết. - Sửa Danh Sách Tham Số: Tôi điều chỉnh danh sách tham số cho hàm Parse trong PageParser, thêm tham số
byPassLinkNodeParser
với giá trị mặc định là false. - Cập Nhật Các Lớp Khác: Sửa đổi hàm PageParser.Parse đồng nghĩa với việc sửa đổi một số lớp khác trong hệ thống, đặc biệt là những lớp có cho phép
byPassLinkNodeParser = true
. - Giảm Rủi Ro: Tôi nhận thấy việc sửa đổi các lớp không liên quan tiềm ẩn nhiều rủi ro, vì vậy tôi tìm cách giảm thiểu sự thay đổi ở những nơi không cần thiết.
- Phát Triển Giải Pháp Thay Thế: Sau cùng, tôi nhận ra rằng không cần phải thay đổi LinkNodeParser. Với thiết kế hiện tại, tôi đã tạo một
ByPassLinkNodeParserDecorator
và cập nhậtNodeParserFactory
để thực hiện việc trang trí (decorates) LinkNodeParser mà không làm thay đổi nghiệp vụ chính của nó.
Ý Nghĩa Quy Trình
Quá trình nêu trên minh chứng rằng: Dù chỉnh sửa hay mở rộng, thì mọi thứ đều có liên quan đến việc sửa đổi. Trong tất cả mọi tình huống, bạn vẫn phải sửa đổi ở một số nơi. Tuy nhiên, điều quan trọng là bảo vệ nghiệp vụ chính, hay còn gọi là core business logic.
Nguyên Tắc Mở Rộng
Mở rộng không có nghĩa là bạn nên mở rộng mà không cân nhắc. Chúng ta cần phải có sự thận trọng với những đoạn mã khó sửa đổi. Thay vì đưa ra giải pháp khiến ảnh hưởng đến nhiều phần khác trong hệ thống, đôi khi tốt hơn là refactor những đoạn mã thiết yếu từng chút một. Đối với các nhóm Scrum, những nhiệm vụ như vậy có thể không được ưu tiên do ảnh hưởng đến điểm story của sprint.
Thiết Kế Linh Hoạt
Khi thiết kế để mở rộng, bạn có thể thực hiện các thay đổi một cách nhanh chóng mà không cần sửa lại nguyên tắc core business logic. Thực tế, với NodeParser, mọi thứ trở nên đơn giản nhờ vào thiết kế đã cho phép lòng ghép những giá trị bổ sung mà không cần những điều chỉnh lớn.
Việc tạo một decorator cho tính năng đơn giản có thể cảm thấy thừa thãi nhưng lại mang đến một ý nghĩa lớn hơn: “Tiền lệ.” Nó như một gợi ý cho các thay đổi trong tương lai.
Kết Luận
Hy vọng rằng qua ví dụ thực tế này, bạn sẽ hiểu rõ hơn nguyên tắc Đóng/Mở và tìm được cách áp dụng nó trong thiết kế phần mềm của mình.
source: viblo