Bài viết được sự cho phép của tác giả Lê Nhật Thanh
Những dòng chữ bên dưới là một trong những kiến thức cực kì quan trọng để build một hệ thống backend. Bạn nếu muốn đi con đường backend hoặc fullstack developer thì hãy đọc một cách cẩn thận. Có thể đọc đi đọc lại nhiều lần, vì bài viết về Loose Coupling này mình thật sự rất tâm huyết. Trong bài viết này sẽ nhiều khái niệm như Dependency injection, DIP, IoC hi vọng các bạn sẽ thật sự hiểu được tụi này.
Bản thân là một software engineer, mình đã làm ở trong ngành cũng được một thời gian dài. Mình đã từng trãi rất nhiều hệ thống lớn có nhỏ có, và trong số đó đa phần đều bị vướng một lỗi rất lớn (Lỗi gì thì mình nói sau). Nhưng với lỗi đó, mỗi khi bạn muốn sửa một đoạn code nào đó thì sẽ ảnh hưởng để rất nhiều nơi khác. (Điều này bạn nào có kinh nghiệm rồi làm việc rồi chắc chắn sẽ từng gặp). Mình hay gọi nó với cái từ là impact list, kiểu mình fix một cái bug A nào đó, thì sau khi fix xong, 1 đống bug B, C, D, E, F xuất hiện.
Nói một cách ví von, cái nhà (hệ thống) mình xây lên, chỉ cần ai đó rung nhẹ cái là sập nguyên căn. Đó là một vấn đề rất lớn của những lập trình viên chưa có kinh nghiệm.
Loose Coupling là một khái niệm dễ hiểu, nhưng khó đạt được. Và khái niệm này cũng khá rộng lớn. Ở trong phạm vi bài viết này, mình chỉ đề cập tới Loose Coupling OOP (lập trình hướng đối tượng). Và cụ thể hơn là Loose Coupling trong việc quản lý dependency. Chứ khái niệm này khá rộng, ví dụ như việc quản lý state, flow,… . Ngoài ra khái niệm này còn xuất hiện trong cả khi thiết kế hệ thống lớn, database distributed,… khi mà các node… phụ thuộc lẫn nhau. Hoặc các module lớn phụ thuộc lẫn nhau.
Ok, quay lại vấn đề của chúng ta là Loose Coupling trong OOP.
Trong lập trình hướng đối tượng Tight Coupling và Loose Coupling là hai thuật ngữ liên quan đến mức độ mà một lớp (class hay module) phụ thuộc vào lớp khác.
Tight Coupling (phụ thuộc chặt chẽ): Khi một lớp phụ thuộc chặt chẽ vào lớp khác, nghĩa là bất kỳ thay đổi nào trong lớp này cũng có thể ảnh hưởng đến lớp kia. Điều này làm giảm khả năng maintenance, tái sử dụng (reusable) và mở rộng (extendable) của mã nguồn (source code).
Loose Coupling (phụ thuộc lỏng lẻo): Khi một lớp phụ thuộc lỏng lẻo vào lớp khác, nghĩa là nó chỉ phụ thuộc vào một phần nhỏ của lớp kia, thường là thông qua interface hoặc lớp trừu tượng (abstraction). Điều này giúp mã nguồn dễ dàng mở rộng (extendable), tái sử dụng (reusability) và bảo dưỡng (maintenance) hơn.
Xem ví dụ bên dưới:
classUserService{privateMySQLUserRepository$userRepository;publicfunction__construct(){// Dòng ở dưới là tạo ra một hard dependency// Dẫn tới tight coupling$this->userRepository=newMySQLUserRepository();}publicfunctiongetById(int$id):string{// Application logic herereturn$this->userRepository->getById($id);}}classMySQLUserRepository{publicfunctiongetById(int$id):string{// Code to interact with DB}}
Bạn hãy nhìn từ khoá new!
Như ví dụ này thì UserService phụ thuộc chặt vào MySQLUserRepository với new keywork.
Đây là tight coupling. Vì khi chúng ta thay đổi class MySQLUserRepository (ví dụ đổi tên, thay đổi param constructor) thì sẽ dẫn tới class UserService bị đổi theo. Giả sử có hàng trăm class sử dụng MySQLUserRepository thì chúng ta phải sửa hàng trăm class đó trong khi mục đích là chỉ sửa đúng 1 class.
Và trong giới lập trình, class MySQLUserRepository được gọi là một dependency của UserService.
Và khi chúng ta khởi tạo trực tiếp class (với từ khoá new) thì đây được gọi là hard dependency.
Thử tưởng tượng hệ thống của bạn có hàng ngàn class và những class này chằng chịch hard dependency thì chuyện gì xảy ra? Hệ thống của bạn sẽ cực kì khó maintain, mở rộng và tái sử dụng, điều dễ thấy nhất đối với hệ thống bị tight coupling là khi refactor, hoặc fix cái gì đó rất nhỏ, nhưng impact list của nó thì rất lớn, và người ta rất ngại refactor, đôi khi phải đập đi xây lại hoàn toàn. Ngoài ra viết unit test với những trường hợp như vậy là cực hình. Và hard dependency gây ra Tight Coupling – cũng chính là cái lỗi mình đề cập ở đầu bài viết.
Bây giờ chúng ta sẽ đi theo flow bên dưới từng bước từng bước một. Để từ Tight Coupling là ví dụ trên, chúng ta sẽ tiến đến Loose Coupling.