S.O.L.I.D - Nguyên Tắc Cơ Bản Trong Coding

Nguyễn Thị Anh Thơ
22/05/2026
Chia sẻ kiến thứcKỹ năng mềm

SOLID là bộ 5 nguyên tắc thiết kế hướng đối tượng giúp developer viết code dễ đọc, dễ maintain và dễ mở rộng hơn. Bài viết giới thiệu lần lượt các nguyên tắc SRP, OCP, LSP, ISP và DIP thông qua những ví dụ thực tế bằng Ruby, từ đó giúp lập trình viên hiểu cách refactor code để giảm phụ thuộc, tăng tính linh hoạt và nâng cao chất lượng hệ thống phần mềm.

SOLID là viết tắt của 5 chữ cái đầu trong 5 nguyên tắc thiết kế hướng đối tượng, giúp cho developer viết ra những đoạn code dễ đọc, dễ hiểu, dễ maintain, được đưa ra bởi Bob Martin và Michael Feathers. Việc theo sát 5 nguyên tắc này nói thì để đáp ứng cả 5 nguyên tắc e là điều không đơn giản. 5 nguyên tắc đó bao gồm:

  • Single responsibility priciple (SRP)
  • Open/Closed principle (OCP)
  • Liskov substitution principe (LSP)
  • Interface segregation principle (ISP)
  • Dependency inversion principle (DIP) Trong bài viết này mình sẽ giới thiệu từng nguyên tắc trong 5 nguyên tắc trên cũng như cách áp dụng nó làm tăng chất lượng code trong Ruby

1. Single responsibility priciple

Nguyên lý đầu tiên ứng với chữ S trong SOLID, có ý nghĩa là một class chỉ nên giữ một trách nhiệm duy nhất. Một class có quá nhiều chức năng sẽ trở nên cồng kềnh và trở nên khó đọc, khó maintain. Mà đối với ngành IT việc requirement thay đổi, cần thêm sửa chức năng là rất bình thường, nên việc code trong sáng, dễ đọc dễ hiểu là rất cần thiết. Để hiểu rõ hơn, ta cũng soi vào đoạn code vi phạm nguyên tắc này:

class DealProcessor
  def initialize(deals)
    @deals = deals
  end

  def process
    @deals.each do |deal|
      Commission.create(deal: deal, amount: calculate_commission)
      mark_deal_processed
    end
  end

  private

  def mark_deal_processed
    @deal.processed = true
    @deal.save!
  end

  def calculate_commission
    @deal.dollar_amount * 0.05
  end
end

Class này ngoài việc đánh dấu giao dịch đã được xử lý, còn thực hiện tính hoa hồng cho mỗi giao dịch nữa. Ngoài ra sau này còn có thể thêm chức năng ví dụ như là gửi mail nội dung cụ thể về hoa hồng cho người có liên quan, gửi thông báo v.v.. dẫn đến việc class này làm nhiều hơn 1 nhiệm vụ và đã vi phạm nguyên tắc đơn trách nhiệm trong SOLID. Có thể refactor lại như sau:

class DealProcessor
  def initialize(deals)
    @deals = deals
  end

  def process
    @deals.each do |deal|
      mark_deal_processed
      CommissionCalculator.new.create_commission(deal)
    end
  end

  private

  def mark_deal_processed
    @deal.processed = true
    @deal.save!
  end
end

class CommissionCalculator
  def create_commission(deal)
    Commission.create(deal: deal, amount: deal.dollar_amount * 0.05)
  end
end

Giờ thì chúng ta đã có 2 class nhỏ hơn thực hiện 2 nhiệm vụ riêng biệt: một processor chiệu trách nhiệm lưu lại việc xử lý và 1 calculator chịu trách nhiệm tính toán và tạo ra các dữ liệu liên quan tới tiền hoa hồng.

2. Open/Closed principle

Nguyên lý thứ 2 ứng với chữ O trong SOLID. Nội dung 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) Ta có đoạn code sau:

class Report
  def body
     generate_reporty_stuff
  end

  def print
     body.to_json
  end
end

Đoạn code trên vi phạm OCP bởi nếu ta muốn thay đổi định dạng của report được print ra, ta sẽ cần phải sửa đổi code của class. Refactor lại như sau:

class Report
  def body
     generate_reporty_stuff
  end

  def print(formatter: JSONFormatter.new)
     formatter.format body
  end
end

Làm theo cách này thì ta vừa mở rộng tính năng mà khi thay đổi format sẽ không cần phải thay đổi code

report = Report.new
report.print(formatter: XMLFormatter.new)

3. Liskov substitution principle

Nguyên tắc thứ 3, ứng với chữ L trong SOLID. Nội dung nguyên tắc này được phát biểu như sau: Bất cứ instance nào của class cha cũng có thể được thay thế bởi instance của class con của nó mà không làm thay đổi tính đúng đắn của chương trình Hãy cùng xem ví dụ về việc vi phạm nguyên tắc Liskov dưới đây

class Rectangle
  def set_height(height)
    @height = height
  end

  def set_width(width)
    @width = width
  end
end

class Square < Rectangle
  def set_height(height)
    super(height)
    @width = height
  end

  def set_width(width)
    super(width)
    @height = width
  end
end

Hình vuông (Square) là con của hình chữ nhật (Rectangle), vì vậy để hợp lý hóa, khi ta gọi method set_height hay set_width của Square thì đều phải modify cả @width@height. Ở đây việc ứng dụng tính đa hình chưa đúng có thể gây hiểu lầm, ví dụ trong trường hợp iterate qua 1 collection của Rectangle, mà trong đó lại có 1 instance của class Square, việc gọi method set_height nhưng lại gây ra hậu quả không mong muốn là thay đổi cả width. Một ví dụ điển hình của việc vi phạm nguyên tắc Liskov đó là throw exception trong overridden method ở class con.

4. Interface segregation principle

Nguyên tắc thứ 4 ứng với chữ I trong SOLID, nội dung nguyên tắc này như sau: 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ể Client không nên phụ thuộc vào interface mà nó không sử dụng. Nguyên tắc này tương đối dể hiểu, thay vì gộp hết lại trong 1 interface lớn, ta có thể chia nhỏ thành nhiều interface nhỏ hơn gồm các method liên quan tới nhau, như vậy sẽ dễ quản lý hơn.

class Car
  def open
  end

  def start_engine
  end

   def change_engine
   end
end

class Driver
  def drive
    @car.open
    @car.start_engine
  end
end

class Mechanic
  def do_stuff
    @car.change_engine
  end
end

Trong đoạn code trên, class Car có một interface được sử riêng rẽ bởi cả DriverMechanic. Ta có thể refactor lại code như sau:

class Car
  def open
  end

  def start_engine
  end
end

class CarInternals
   def change_engine
   end
end

class Driver
  def drive
    @car.open
    @car.start_engine
  end
end

class Mechanic
  def do_stuff
    @car_internals.change_engine
  end
end

Bằng việc tách ra là 2 interface nhỏ hơn, code ta đã đảm bảo tuân thủ nguyên tắc ISP

5. Dependency inversion principle

Nguyên tắc thứ 5 ứng với chữ D trong SOLID, nội dung nguyên tắc này như sau: 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. Abstraction không nên phụ thuộc vào chi tiết, mà ngược lại. Chúng ta hãy cùng quay trở lại với ví dụ đưa ra ở mục 2, nguyên tắc đóng/mở, tuy nhiên sẽ có một chút thay đổi:

class Report
  def body
    generate_reporty_stuff
  end
  
  def print
    JSONFormatter.new.format body
  end
end

class JSONFormatter
  def format body
    ...
  end
end

Bây giờ chúng ta đã có một lớp để thực hiện việc định dạng in ra của báo cáo. Tuy nhiên, dễ thấy rằng code trong method print của class Report vẫn đang được fix cứng, từ đó sẽ tạo nên sự phụ thuộc của class này vào class JSONFormatter. Vì Report là class trừu tượng ở mức cao hơn so với JSONFormatter, cách viết này đang vi phạm nguyên tắc đảo ngược dependency.

Có thể giải quyết vấn đề này tương tự như cách chúng ta đã thực hiện với nguyên tắc đóng/mở, bằng cách sử dụng kỹ thuật dependency injection:

class Report
  def body
    generate_reporty_stuff
  end
  
  def print formatter: JSONFormatter.new
    formatter.format body
  end
end

Sau khi được refactor, class Report đã không phụ thuộc vào class JSONFormatter và có thể sử dụng bất kỳ định dạng nào mà có định nghĩa method format.

KẾT LUẬN

Trên đây là bài giới thiêu sơ qua về 5 nguyên tắc SOLID trong việc design. Hi vọng bài viết phần nào có ích trong công việc của các bạn.

Cre: VIBLO


Nếu bạn muốn không chỉ hiểu SOLID trong lý thuyết mà còn biết cách áp dụng vào dự án thực tế, hãy thử Internship OneConnect (IOC) để trải nghiệm môi trường làm việc chuyên nghiệp, tham gia dự án thực chiến và tích lũy kinh nghiệm thực tế ngay từ khi còn là sinh viên.

Chia sẻ bài viết:

Bài viết liên quan

HÈ BỨT PHÁ CÙNG ĐỒNG ĐỘI: HỌC PHÍ GIẢM ĐẾN 30%, RINH HOA HỒNG KHỦNG TỪ CHƯƠNG TRÌNH ĐẠI SỨ IOC!
Sự kiệnThông báo

HÈ BỨT PHÁ CÙNG ĐỒNG ĐỘI: HỌC PHÍ GIẢM ĐẾN 30%, RINH HOA HỒNG KHỦNG TỪ CHƯƠNG TRÌNH ĐẠI SỨ IOC!

Internship OneConnect chính thức mang đến combo chương trình siêu hấp dẫn dành riêng cho cộng đồng sinh viên: Chương trình Mua chung/Đăng ký nhóm và Chương trình Đại sứ Truyền thông giúp bạn rinh tiền mặt dễ dàng. Hãy cùng khám phá chi tiết ngay dưới đây!

admin
admin
19/06/2026
WORKSHOP: AI & XU HƯỚNG NGHỀ NGHIỆP CNTT 2026 – TỪ GIẢNG ĐƯỜNG ĐẾN DOANH NGHIỆP
Định hướng nghề nghiệpQ&A

WORKSHOP: AI & XU HƯỚNG NGHỀ NGHIỆP CNTT 2026 – TỪ GIẢNG ĐƯỜNG ĐẾN DOANH NGHIỆP

Chiều ngày 29/01/2026, Rikkei Education đã phối hợp cùng Khoa Công nghệ Thông tin tổ chức Workshop với chủ đề “AI & Xu hướng nghề nghiệp CNTT 2026 – Từ giảng đường đến Doanh nghiệp”. Chương trình thu hút sự quan tâm và tham gia của đông đảo cán bộ, giảng viên cùng hơn 200 sinh viên Khoa CNTT.

N
Nguyễn Thị Anh Thơ
10/06/2026
Chọn Internship OneConnect (IOC) tại Rikkei Education – Bước tiến rõ rệt trong tư duy nghề nghiệp
Q&ASự kiện

Chọn Internship OneConnect (IOC) tại Rikkei Education – Bước tiến rõ rệt trong tư duy nghề nghiệp

Từ việc được giới thiệu chương trình, tìm hiểu thông tin cho đến quyết định tham gia Internship OneConnect (IOC) tại Rikkei Education, với Hoàng Minh Thiện – K20, Công nghệ Phần mềm, Đại học CMC, đây không chỉ là một kỳ thực tập, mà là hành trình “va chạm thật” với môi trường làm việc chuyên nghiệp ngay khi còn là sinh viên.

N
Nguyễn Thị Anh Thơ
10/06/2026

Internship OneConnect