Solid trong Javascript: Cách sử dụng nguyên tắc SOLID để thiết kế hệ thống có tính năng mở rộng

Nội dung bài viết

Video học lập trình mỗi ngày

Solid là một khái niệm trong lập trình Javascript được sử dụng để thể hiện một hệ thống lập trình có tính năng đơn giản, dễ dàng quản lý và dễ dàng mở rộng. Solid được định nghĩa bởi các nguyên tắc SOLID, mỗi nguyên tắc đề cập đến một khía cạnh quan trọng của việc thiết kế hệ thống lập trình tốt.

Thật sự mà nói, tôi từ bỏ java cách đây 5 năm để chuyển sang làm BE. Nhưng trước khi đến với BE thì tôi cũng đã từng nghe nói về nguyên lý SOLID của Uncle Bob, nghe nói khác với khái niệm hiểu. Chính vì vậy sau bao năm, thì hôm qua tôi gặp một bài viết quảng cáo trên FB, nói về SOLID là gì? Vì sao nó lại quan trọng trong thiết kế phần mềm?

Chính vì thế, tôi quyết định đi tìm hiểu lại một lần nữa, và cũng là khẳng định rằng cái gì không hiểu thì chúng ta sẽ tìm hiểu lại môt lần nữa. Đương nhiên, khi tôi hiểu thì bạn cũng hiểu, đó cũng là phương châm của blog này. Trong bài viết này bạn sẽ nghe được một vài cụm từ như OOP, OOD, SOLID và quang trọng là những ví dụ thực tế trong cuộc sống của chúng ta.

SOLID là gì?

OOD viết tắt từ Object-Oriented Design, xét về lĩnh vực phát triển phần mềm thì OOD đóng vài trò quan trọng giúp bạn viết code một cách linh hoạt, mở rộng dễ dàng, có thể giúp ngắn thời gian bảo trì và hơn nữa là tái sử dụng, tiết kiệm được nhiều thời gian hơn. Nói như vậy nó liên quan gì đến khái niệm SOLID ở đây, đúng không liên quan những bạn cũng nên có kiến ​​thức về nguyên tắc SOLID để thiết kế hướng đối tượng tốt trong lập trình. Nguyên tắc SOLID được giới thiệu bởi đại ca Robert C. Martin , còn được gọi là Uncle Bobvà nó là một tiêu chuẩn mã hóa trong lập trình. Nguyên tắc SOLID này là từ viết tắt của năm nguyên tắc được đưa ra dưới đây

  • Single Responsibility Principle (SRP)
  • Open/Closed Principle
  • Liskov’s Substitution Principle (LSP)
  • Interface Segregation Principle (ISP)
  • Dependency Inversion Principle (DIP)

Đừng sợ, đừng đóng bài ở đây, bạn cũng như tôi khi nhìn vào 5 nguyên tắc này thì không đọc nữa, nhưng hãy dừng lại bởi vì bài viết này không có tý code nào hết, mà giải thích bằng những câu chuyện đời thường mà thôi. Tin tôi đí, bạn có 1 phút thôi. OK chứ? Trước khi đi vào giải thích 5 nguyên tắc trên kìa thì, cũng phải văn vở một chút.

SOLID là Nguyên tắc thiết kế lập trinh giúp giảm sự phụ thuộc lẫn nhau, hay nói rõ hơn là giảm sự chặt chẽ trong code. Kết hợp chặt chẽ có nghĩa là một nhóm các lớp phụ thuộc nhiều vào nhau mà bạn nên tránh trong mã của mình. Đối lập với khớp nối chặt chẽ là khớp nối lỏng lẻo và mã của bạn được coi là mã tốt khi nó có các lớp được ghép nối lỏng lẻo. Các lớp được ghép nối lỏng lẻo sẽ giảm thiểu những thay đổi trong mã của bạn, giúp làm cho mã dễ sử dụng hơn, có thể bảo trì, linh hoạt và ổn định hơn.

Bây giờ đến lượt tôi, giải thích theo kiểu dân thường...

Single Responsibility Principle (SRP) - Nguyên tắc Trách nhiệm Duy nhất

Nguyên tắc này nói rằng một lớp chỉ nên có một lý do để thay đổi có nghĩa là mỗi lớp phải có một trách nhiệm duy nhất hoặc một công việc hoặc một mục đích duy nhất. Đó là định nghĩa, còn bạn và tôi hiểu dưới đây là được.

Ví dụ trong cuộc sống đời thường, đường một chiều là một ví dụ điển hình, đường một chiều chỉ làm một việc là đi về một hướng, nhanh gọn an toàn hơn đường hai chiều. Đường hai chiều luôn nguy hiểm, nguy cơ rủi ro hơn nhiều. Single Responsibility Principle (SRP


Giống như trong team làm việc vậy, test một bộ phận, code một bộ phận, thiết kế một bộ phận... Chứ một mình làm như fullstack thì khổ, cái gì cũng đụng, mà chuyên thì được mấy chỗ, còn lại là làm cho xong là được. Ok vậy thôi, nói chung là hiểu khái niệm SRP như vậy là ok rồi.

Open/Closed Principle - Nguyên tắc Mở / Đóng

Nguyên tắc này nói rằng `các thực thể phần mềm (class, module, function, v.v.) phải mở để mở rộng, nhưng đóng để sửa đổi có nghĩa là bạn có thể mở rộng hành vi của class mà không cần sửa đổi nó. Hiểu thực tế xem ..

Ví dụ trong cuộc sống đời thường Code A làm một module như thế này:

class IceCreamMachine {
    constructor() {
        this.flavors = ['chocolate', 'vanilla'];
    }
    create() {
        if (this.flavors.includes(flavor)) { // warning, ES7 Array.prototype.includes
            console.log('Great success. You now can eat your ice cream');
        } else {
            console.log('A bad choice, not ice cream today');
        }
    }
}

export default IceCreamMachine

A đóng gói lại, giờ đây chỉ có hai hương vị kem mà thôi ['chocolate', 'vanilla']. Giờ B muốn bán kem và muốn thêm một hương vị nữa vào và quan trọng là không muốn sửa code của A thì làm sao, làm thế này nè:

class IceCreamMachine {
    constructor() {
        this.flavors = ['chocolate', 'vanilla'];
    }
    create() {
        if (this.flavors.includes(flavor)) {
            console.log('Great success. You now can eat your ice cream');
        } else {
            console.log('A bad choice, not ice cream today');
        }
    }
    flavorAdd(flavor) {
        this.flavors = [...this.flavors, flavor];
    }
}

Để tuân theo OCP, chúng ta có thể dễ dàng thay đổi điều đó với flavorAdd().

Ngon chưa, hiểu dễ hơn chưa??? Tiếp hén.

Liskov’s Substitution Principle (LSP) - Nguyên tắc thay thế Liskov

Nguyên tắc thay thế Liskov đúng là khó hiểu nhất trong những khái niệm lập trình. Nguyên tắc được đưa ra bởi Barbara Liskov vào năm 1987 và theo nguyên tắc này:

Các lớp con hoặc lớp con phải được thay thế cho các lớp cơ sở hoặc lớp cha của chúng. Nguyên tắc này đảm bảo rằng bất kỳ lớp nào là con của lớp cha đều có thể sử dụng được thay cho lớp cha của nó mà không có bất kỳ khó khăn nào.

Đọc xong, không hiểu luôn, nhưng hãy xem ví dụ đời thường. Ví dụ bạn là người con trai của một người nông dân và bạn cũng thừa kế việc làm đồng án của gia đình mình, khi Cha của bạn không thể làm việc đồng án, thì bạn sẽ sẵn sàng thay thế Cha mình nều cần thiết. Nhưng giả sử nếu con trai của người nông dân ấy muốn trở thành cầu thủ bóng đá thì chắc chắn người con trai không thể thay thế cha mình mặc dù cả hai đều thuộc gia đình Nông Dân. Nguyên tắc thay thế Liskov


Một trong những ví dụ cổ điển của nguyên tắc này là một hình chữ nhật có bốn cạnh và hình vuông. Thật ra hình vuông cũng là hình chữ nhật, chỉ là các cạnh nó bằng nhau, chỉ cần làm chức năng cho hình chữ nhật thì sẽ làm được hình vuông. Xem video Nguyên tắc thay thế Liskov về để hiểu hơn.

Interface Segregation Principle (ISP) - Nguyên tắc phân tách giao diện

Nguyên tắc này là nguyên tắc đầu tiên áp dụng cho các Giao diện thay vì các lớp trong SOLID và nó tương tự như nguyên tắc đầu tiên Single Responsibility Principle (SRP) bạn có thể đọc lại nếu chưa rõ. Vì trong javascript không có interfaces nên bạn cũng không cần quan tâm cho lắm, nhưng không có nghĩa là không cần hiểu. Nguyên tắc thay thế Liskov


Giả sử nếu bạn bước vào một nhà hàng và bạn là người ăn chay trường. Khi bạn ngồi vào bàn, thì người phục vụ sẽ đưa cho bạn một menu trong đó bao gồm các món không chay, chay... tùm lum và hỗn loạn. bạn sẽ mất thời gian chọn lựa điều đó sẽ khiến bạn không hài lòng. Trong trường hợp này, với tư cách là khách hàng, bạn nên có một menu riêng chỉ bao gồm các món chay, không phải tất cả những gì bạn không ăn trong thực phẩm của mình. Ở đây thực đơn nên khác nhau cho các loại khách hàng khác nhau. Menu chung hoặc chung cho mọi người có thể được chia thành nhiều Menu thay vì chỉ một Menu. Sử dụng nguyên tắc này giúp giảm các tác dụng phụ và tần suất thay đổi cần thiết.

Dependency Inversion Principle (DIP) - Nguyên tắc đảo ngược phụ thuộc

Trước khi chúng ta thảo luận về chủ đề này, hãy nhớ rằng Dependency Inversion và Dependency Injection cả hai đều là những khái niệm khác nhau. Hầu hết mọi người đều nhầm lẫn về nó và coi cả hai đều giống nhau. Bây giờ hai điểm chính ở đây cần ghi nhớ về nguyên tắc này.

High-level modules/classes không nên phụ thuộc vào low-level modules/classes. Cả hai đều phải phụ thuộc vào abstractions.

Tóm tắt không nên phụ thuộc vào chi tiết. Thông tin chi tiết nên phụ thuộc vào sự trừu tượng. Khó hiểu cho những ai chưa từng viết về ngôn ngữ JAVA. Nhưng không sao bạn hay xem xét vấn đề này qua một ví dụ thực tế dưới đây. Dependency Inversion Principle (DIP)


Bạn có thể xem xét ví dụ thực tế về pin điều khiển TV. Điều khiển từ xa của bạn cần pin nhưng không phụ thuộc vào thương hiệu pin. Bạn có thể sử dụng bất kỳ nhãn hiệu XYZ nào bạn muốn và nó sẽ hoạt động mà không cần quan tâm bạn đang xài hàng nào. Vì vậy, chúng tôi có thể nói rằng điều khiển từ xa TV được kết hợp lỏng lẻo với tên thương hiệu. Dependency Inversion làm cho mã của bạn có thể tái sử dụng nhiều hơn. Chốt hạ từ đây, ok.

Bài viết có tham khảo từ: SOLID Principle in Programming: Understand With Real Life Examples 5 principles that will make a more SOLID Javascript Engineer

Có thể bạn đã bị missing