Kênh Tên Miền chuyên cung cấp tên miền đẹp, giá rẻ! Hãy liên hệ kỹ thuật: 0914205579 - Kinh doanh: 0912191357 để được tư vấn, hướng dẫn miễn phí, Cảm ơn quý khách đã ủng hộ trong thời gian qua!
Friday, April 3, 2015

SOLID là 5 nguyên tắc đầu tiên và cơ bản mà bất cứ programmer nào cũng cần phải hiểu rõ:
  1. S – SRP – Single Responsibility Principle
  2. O – OCP – Open/Closed Principle
  3. L – LSP – Liskop Substitution Principle
  4. I – ISP – Interface Segregation Principle
  5. D – DIP – Dependency Inversion Principle
Những nguyên tắc này tuy rất khó nhớ tên nhưng ít nhiều ta đều tiếp xúc trong công việc hàng ngày. Vì vậy nhận ra khi nào ta đang follow nguyên tắc gì sẽ rất có lợi cho công việc.
Ý nghĩa của từng nguyên tắc như sau:
  1. SRP

    – 1 piece of software chỉ nên thực hiện 1 mục đích, 1 trách nhiệm duy nhất. Về cơ bản, các đơn vị cấu trúc của program gồm có:
    • Statement
    • Code block
    • Method/function
    • Class/Interface
    • Module
    • Project/Library
    • Solution
    Đối với mỗi level, chúng ta cần phải rất rõ ràng về công việc mà chúng thực hiện. Điều này giúp cho code dễ đọc, program dễ hiểu và dễ maintain. Sau khi viết code xong, khi đọc lại hoặc khi ng khác đọc sẽ dễ dàng follow đc vấn đề.
    Ví dụ 1

    Dòng code trên làm 2 việc: in ra index hiện tại và tăng nó lên 1. Đối với ng viết, do đã là thói quen nên họ dễ dàng nhận ra giá trị của biến i sau dòng này. Nhưng đối với ng khác, rất dễ xảy ra nhầm lẫn.
    Ví dụ 2

    Đoạn code trên có 2 vấn đề:
    1. Trong using block, thực hiện 2 việc là insert object và gọi messageService. Mặc dù code chạy bình thường nhưng đây vẫn là bad practice, messageService cần phải nằm ngoài using ctx.
    2. Trong function Insert thực hiện 2 nhiệm vụ khác nhau. Nếu trong tương lai phát sinh ra nhu cầu Insert nhưng ko kèm notify cho messageService thì function này sẽ phải sửa lại (cùng với tất cả những nơi đã dùng tới nó)
    Cứ tiếp tục như thế, đôi khi chúng ta cảm thấy sẽ “tiện lợi” ghi gộp nhiều thứ lại với nhau. Nhưng thực tế sẽ tạo ra những vấn đề tiềm ẩn cho sau này (technical debt)
  2. OCP

    open for extension but close for modification? tức là sao?
    Nôm na là ta phải thiết kế software sao cho nó có thể mở rộng dễ dàng mà ko cần phải đập đi làm lại. Còn gì bực bội hơn khi được giao viết thêm functionality cho 1 hệ thống mà phát hiện ra cần phải sửa rất nhiều mới support đc chức năng ABC? Điều này cũng giống như thiết kế 1 chiếc xe hơi với các bộ phận tiêu chuẩn có thể dễ dàng thay thế hoặc nâng cấp mà ko cần phải chế tạo lại cả chiếc xe.
    Nguyên tắc này thường đc triển khai dựa trên tính kế thừa và tính đa hình của OOP như trong sơ đồ sau:
    superhero
    Ở đây tôi đã define Superman và Spiderman, và method Fight của 2 entity này đã fixed và không thay đổi được, tức là Closed. Vậy hệ thống có Open hay không? Làm gì để tùy chỉnh?
    • có thể extend và override method của class cũ, chẳng hạn tạo class AmazingSpiderman -> Spiderman với khả năng Fight more amazing
    • extend từ Abstract class và implement abstract method Fight
    Như vậy hệ thống đảm bảo đc tính OCP.
  3. LSP

    có khi nào bạn thấy ko hài lòng về 1 property nào đó của 1 class và viết 1 class con để modify property đó? chẳng hạn property của base class chỉ trả về integer từ 1..10, bạn subclass để nó trả về 1..100? Như vậy là bạn đang violate nguyên tắc LSP.
    Lý do: khi đoạn code nào đó sử dụng đến property này với understanding là nó sẽ trả về 1..10, sẽ bị surprised khi nó trả về 1..100 và ko thể handle từ 11..100
    Ví dụ sau ko hoàn toàn về LSP nhưng cũng cho thấy sự vi phạm tính đa hình của class

    Đoạn code trên đã phải convert đối tượng về một subtype để thực hiện method cần thiết.
  4. ISP

    khi bạn implement 1 interface mà có những method bạn ko dùng đến, đó là dấu hiệu của problem.

    Có thể thấy Striker sẽ ko implement đc method Catch. Và nếu ta gọi Player.Catch() có thể sẽ dẫn đến runtime expception. Vì vậy việc class Striker ko thể implement đc method Catch cho thấy 1 technical debt.

    Như vậy, rõ ràng mọi method trong class đều có ý nghĩa rất rõ ràng, ko lỗi.
  5. DIP

    – hmm… đây là 1 nguyên tắc về decoupled, thuộc về design nhiều hơn là coding, vì vậy tương đối khó để nắm bắt. Có thể liên tưởng qua ví dụ thực tế như sau:
    Ex: giả sử A làm ăn với B, A mua dịch vụ do B cung cấp. Đôi khi B ko thực hiện đúng trách nhiệm của mình, A mặc dù bực bội về việc đó, nhưng đã ký kết làm ăn nên ko thể đổi được, và cũng ko có đủ khả năng tìm đối tác khác. Như vậy A đã phụ thuộc chặt chẽ vào B.
    Tuy nhiên, nếu ban đầu A ko trực tiếp làm việc với B, mà thông qua trung gian X. A đưa ra yêu cầu dành cho nhà phân phối của mình và X sẽ tìm người đáp ứng được nhu cầu đó, giả sử ban đầu là B. Nếu sau đó B ko thực hiện đúng trách nhiệm, X sẽ thay B bằng nhà cung cấp C. Như vậy việc sử dụng dịch vụ của A sẽ ko bị gián đoạn và A cũng ko cần làm việc trực tiếp với B hay C.
    Điều này minh họa trong code như sau


    Ta có thể thấy Messi phụ thuộc hoàn toàn vào Xavi. Có thể sửa lại như sau
Tóm lại, các principle trên có tác dụng chính là giúp chúng ta nắm được và dự đoán được các vấn đề tiềm ẩn của program thông qua các dấu hiệu vi phạm 5 principle này để giải quyết chúng 1 cách triệt để.

0 comments:

Post a Comment

Popular Posts