SOLID là gì – Áp dụng các nguyên lý SOLID để trở thành lập trình viên code “cứng”

Trong quá trình học, hầu như các bạn sinh viên đều được học một số khái niệm OOP cơ bản như sau:

  • Abstraction (Tính trừu tượng)
  • Encapsulation (Tính bao đóng)
  • Inheritance (Tính kế thừa)
  • Polymophirsm (Tính đa hình)

Những khái niệm này đã được dạy khá rõ ràng, và hầu như những buổi phỏng vấn nào cũng có những câu hỏi liên quan đến khái niệm này. Vì 4 khái niệm này khá cơ bản, bạn nào chưa vũng có thể google để tìm hiểu thêm.

Những nguyên lý mình giới thiệu hôm nay là những nguyên lý thiết kế trong OOP. Đây là những nguyên lý được đúc kết bởi máu xương vô số developer, rút ra từ hàng ngàn dự án thành công và thất bại. Một project áp dụng những nguyên lý này sẽ có code dễ đọc, dễ test, rõ ràng hơn. Và việc quan trọng nhất là việc maintainace code sẽ dễ hơn rất nhiều (Ai có kinh nghiệm trong ngành IT đều biết thời gian code chỉ chiếm 20-40%, còn lại là thời gian để maintainance: thêm bớt chức năng và sửa lỗi).  Nắm vững những nguyên lý này, đồng thời áp dụng chúng trong việc thiết kế + viết code sẽ giúp bạn tiến thêm 1 bước trên con đường thành senior nhé (1 ông senior bên FPT Software từng bảo mình thế).

keepcalm

Ok, 10 phút quảng cáo đã qua, bây giờ đến phần giới thiệu. SOLID tức là “cứng”, áp dụng nhiều thì bạn sẽ code “cứng”. Đùa thôi, nó là tập hợp 5 nguyên tắc sau đây:

  1. Single responsibility principle
  2. Open/closed principle
  3. Liskov substitution principle
  4. Interface segregation principle
  5. Dependency inversion principle

Trong nội dung bài viết này, mình chỉ giới thiệu tổng quát để các bạn có cái nhìn tổng quan về các nguyên lý này.

1. Single responsibility principle

image_thumb_698FFA0C.png

Nguyên lý đầu tiên, tương ứng với chữ S trong SOLID. Nội dung nguyên lý:

Một class chỉ nên giữ 1 trách nhiệm duy nhất 
(Chỉ có thể sửa đổi class với 1 lý do duy nhất)

Để hiểu nguyên lý này, ta hãy lấy ví dụ với 1 class vi phạm nguyên lý. Ta có 1 class như sau

public class ReportManager()
{
   public void ReadDataFromDB();
   public void ProcessData();
   public void PrintReport();
}

Class này giữ tới 3 trách nhiệm: Đọc dữ liệu từ DB, xử lý dữ liệu, in kết quả. Do đó, chỉ cần ta thay đổi DB, thay đổi cách xuất kết quả, … ta sẽ phải sửa đổi class này. Càng về sau class sẽ càng phình to ra. Theo đúng nguyên lý, ta phải tách class này ra làm 3 class riêng. Tuy số lượng class nhiều hơn những việc sửa chữa sẽ đơn giản hơn, class ngắn hơn nên cũng ít bug hơn.

2. Open/closed principle

openclosed_principle_thumb

Nguyên lý thứ hai, tương ứng với chữ O trong SOLID. Nội dung nguyên lý:

Có thể thoải mái mở rộng 1 class, nhưng không được sửa đổi bên trong class đó 
(open for extension but closed for modification).

Theo nguyên lý này, mỗi khi ta muốn thêm chức năng,.. cho chương trình, chúng ta nên viết class mới mở rộng class cũ ( bằng cách kế thừa hoặc sở hữu class cũ) không nên sửa đổi class cũ.

3. Liskov Substitution Principle

liskov_substitution_principle_thumb

Nguyên lý thứ ba, tương ứng với chữ L trong SOLID. Nội dung nguyên lý:

Trong một chương trình, các object của class con có thể thay thế class cha mà không làm thay đổi tính đúng đắn của chương trình

Hơi khó hiểu? Không sao, lúc mới đọc mình cũng vậy. Hãy tưởng tượng bạn có 1 class cha tên Vịt. Các class VịtBầu, VịtXiêm có thể kế thừa class này, chương trình chạy bình thường. Tuy nhiên nếu ta viết class VịtChạyPin, cần pin mới chạy được. Khi class này kế thừa class Vịt, vì không có pin không chạy được, sẽ gây lỗi. Đó là 1 trường hợp vi phạm nguyên lý này.

4. Interface Segregation Principle

interface_segregation_principle_thumb

Nguyên lý thứ tư, tương ứng với chữ I trong SOLID. Nội dung nguyên lý:

Thay vì dùng 1 interface lớn, ta nên tách thành nhiều interface nhỏ, với nhiều mục đích cụ thể

Nguyên lý này khá dễ hiểu. Hãy tưởng tượng chúng ta có 1 interface lớn, khoảng 100 methods. Việc implements sẽ khá cực khổ, ngoài ra còn có thể dư thừa vì 1 class không cần dùng hết 100 method. Khi tách interface ra thành nhiều interface nhỏ, gồm các method liên quan tới nhau, việc implement và quản lý sẽ dễ hơn.

5. Dependency inversion principle

dependency_inversion_principle_thumb

Nguyên lý cuối cùng, tương ứng với chữ D trong SOLID. Nội dung nguyên lý:

1. Các module cấp cao không nên phụ thuộc vào các modules cấp thấp. 
   Cả 2 nên phụ thuộc vào abstraction.
2. Interface (abstraction) không nên phụ thuộc vào chi tiết, mà ngược lại.
( Các class giao tiếp với nhau thông qua interface, 
không phải thông qua implementation.)

Nguyên lý này khá lắt léo, mình sẽ lấy ví dụ thực tế. Chúng ta đều biết 2 loại đèn: đèn tròn và đèn huỳnh quang. Chúng cùng có đuôi tròn, do đó ta có thể thay thế đèn tròn bằng đèn huỳnh quanh cho nhau 1 cách dễ dàng.

20817695_images1672955_bong

Ở đây, interface chính là đuôi tròn, implementation là bóng đèn trònbóng đèn huỳnh quang. Ta có thể swap dễ dàng giữa 2 loại bóng vì ổ điện chỉ quan tâm tới interface (đuôi tròn), không quan tâm tới implementation.

Trong code cũng vậy, khi áp dụng Dependency Inverse, ta chỉ cần quan tâm tới interface. Để kết nối tới database, ta chỉ cần gọi hàm Get, Save … của Interface IDataAccess. Khi thay database, ta chỉ cần thay implementation của interface này.

Mình nói khá kĩ về nguyên lí này vì nó khá quan trọng. Về sau mình sẽ viết 1 bài riêng về Dependency Injection (Dependency Injection chỉ là 1 trong những pattern để hiện thực Dependency Inversion, Dependency Injection != Dependency Inversion nhé các bạn), cùng với 1 số Dependency Injection Framework cơ bản.

Bài viết khá dài, xin có lời khen với các bạn đã kiên nhẫn đọc hết. Ở những bài viết sau mình sẽ giải thích rõ hơn về từng nguyên lý SOLID này, cùng với code mình họa + cách áp dụng nguyên lí vào quá trình code.

Lượt dịch từ bản gốc: http://blogs.msdn.com/b/cdndevs/archive/2009/07/15/the-solid-principles-explained-with-motivational-posters.aspx

30s quảng cáo

book.jpg

Đây là một bài viết được trích dẫn từ cuốn sách “Code dạo kí sự – Lập trình viên đâu phải chỉ biết code” do mình viết. Quyển sách bao gồm những kĩ năng từ mềm đến cứng mà mỗi developer phải có, đảm bảo sẽ rất có ích cho các bạn sinh viên hoặc lập trình viên đã đi làm. Các bạn xem thông tin và đặt mua sách tại đây nhé: Sách Code Dạo Ký Sự

38 thoughts on “SOLID là gì – Áp dụng các nguyên lý SOLID để trở thành lập trình viên code “cứng””

  1. Chữ D là thứ mình thích nhất, cám ơn bạn đã chia sẻ khá dễ hiểu 😀

    Like

  2. Trích một đoạn kết luận về SOLID trong cuốn sách Design Patterns in PHP and Laravel

    Single Responsibility Principle
    Don’t put all your worker eggs in a single basket. A class should have one reason to change.

    Open/Closed Principle
    Don’t change the same class over and over. If you find this happening, abstract out what is changing.

    Listov Substitution Principle
    Return the same type in an overridden subclass method as a parent class method. The same applies for a method’s parameters. Be consistent.

    Interface Segregation Principle
    Don’t create interfaces with many (more than five) methods. This is a sign that you’re doing too much in one place.

    Dependency Inversion Principle
    Rely on interfaces and abstract classes more than concrete classes. This will be more flexible.

    Like

  3. Thanks bro, nguyên lý thứ 2. Open/closed principle là mình hay vi phạm nhất. Mỗi lần có thay đổi gì toàn sửa luôn trong class ban đầu dẫn đến những cái dùng nó cũng phải thay đổi theo.

    Liked by 1 person

  4. Cảm ơn anh rất nhiều, đang học đến framework mới thấy nó nhiều cái hay. Bảo sao Service, Repository toàn thấy thấy interface.
    Từ laptrinhjavaweb.com qua :v

    Like

Leave a reply to Couhp Cancel reply