<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nguyễn Anh Tuấn</title>
    <description>The latest articles on DEV Community by Nguyễn Anh Tuấn (@anhtuank7c).</description>
    <link>https://dev.to/anhtuank7c</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1175240%2F9ec09b15-2160-4d06-a9d9-6a7fac3f84dc.jpeg</url>
      <title>DEV Community: Nguyễn Anh Tuấn</title>
      <link>https://dev.to/anhtuank7c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anhtuank7c"/>
    <language>en</language>
    <item>
      <title>Lynx: Giải pháp mới cho ứng dụng đa nền tảng - JS Engine</title>
      <dc:creator>Nguyễn Anh Tuấn</dc:creator>
      <pubDate>Thu, 13 Mar 2025 02:21:38 +0000</pubDate>
      <link>https://dev.to/anhtuank7c/lynx-giai-phap-moi-cho-ung-dung-da-nen-tang-js-engine-2fdo</link>
      <guid>https://dev.to/anhtuank7c/lynx-giai-phap-moi-cho-ung-dung-da-nen-tang-js-engine-2fdo</guid>
      <description>&lt;p&gt;Vì sao Lynx nhanh và nhấn mạnh đặc điểm không bị màn hình trắng (blank screen)?&lt;/p&gt;

&lt;p&gt;Định nghĩa NHANH ở đây có thể xem xét đến yếu tố hiệu năng, và yếu tố cảm giác phản hồi. &lt;/p&gt;

&lt;p&gt;Như ở bài trước tôi có đề cập tới con số &lt;strong&gt;0.1s&lt;/strong&gt;, nếu UI cập nhật dưới ngưỡng này thì cho ta cảm giác chung là hệ thống phản hồi  ngay lập tức, ta có cảm giác nó nhanh, còn thực sự tác vụ tính toán đó đã hoàn thành hay chưa thì tạm chưa bàn đến.&lt;/p&gt;

&lt;p&gt;Lynx có cách tiếp cận hướng người dùng, nghĩa là nó đang hướng tới sự chiều chuộng khách hàng, cho người ta có cảm giác UI phản hồi ngay tức khắc.&lt;/p&gt;

&lt;p&gt;Để đáp ứng được hướng tiếp cận này thì đội ngũ Lynx đã chọn cách build &lt;strong&gt;PrimJS JS engine&lt;/strong&gt; dựa trên &lt;strong&gt;QuickJS&lt;/strong&gt;, đây một engine JS nhúng (embeddable Javascript engine) với các đặc điểm sau:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Siêu nhẹ 210 KiB, nó không sử dụng bất kỳ depenency nào&lt;/li&gt;
&lt;li&gt;Sử dụng ngôn ngữ C&lt;/li&gt;
&lt;li&gt;Chiếm dụng cực ít tài nguyên RAM&lt;/li&gt;
&lt;li&gt;Thời gian khởi động rất nhanh&lt;/li&gt;
&lt;li&gt;Sử dụng trình dọn rác đơn giản&lt;/li&gt;
&lt;li&gt;QuickJS là một Intepreter JS engine, không hỗ trợ JIT (Just In Time)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Đội ngũ thực hiện một số thay đổi trên PrimJS khiến nó tối ưu hơn QuickJS như:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tối ưu interpreter: hỗ trợ cache và cải thiện hiệu năng&lt;/li&gt;
&lt;li&gt;Tích hợp mô hình đối tượng liền mạch: các object của JS Engine tích hợp hiệu quả với Lynx Object, giảm thiểu trao đổi thông tin và nâng cao hiệu suất (để so sánh thì React Native old Arch từng bị nghẽn cổ chai khi thực hiện batching message qua bridge)&lt;/li&gt;
&lt;li&gt;Trình dọn rác nâng cao: phân tích bộ hiệu quả hơn,  giảm thiểu rủi ro leak memory. (QuickJS nguyên bản chỉ đơn giản là tìm, đếm và dọn các reference)&lt;/li&gt;
&lt;li&gt;Hỗ trợ trình debug Chrome đầy đủ (Chrome DevTools Protocol)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vậy là Lynx được thừa hưởng toàn bộ các ưu điểm của QuickJS cộng thêm các tính năng custom riêng.&lt;/p&gt;

&lt;p&gt;Mặc dù QuickJS có nhiều ưu điểm nhưng để so sánh với Engine V8 thì cũng có những điểm chưa tốt bằng.&lt;/p&gt;

&lt;p&gt;Ví dụ như:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;V8 parse JSON (large object) hết đâu đó tầm ~50ms, trong khi QuickJS thì chậm hơn 2-3 lần.&lt;/li&gt;
&lt;li&gt;V8 loop 100M iteration trong ~100-150ms, còn QuickJS thì chậm hơn 3-4 lần.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tuy vậy, mỗi JS engine lại có ưu điểm riêng biệt khiến nó nổi trội hơn trong những use case cụ thể.&lt;/p&gt;

&lt;p&gt;Điển hình trong trường hợp này Lynx đánh đổi việc tối ưu thời gian khởi động cũng như giảm thiểu communicate giữa các object khiến nó trở nên hiệu quả, một hướng tiếp cận khá thông minh.&lt;/p&gt;

&lt;p&gt;Mình đang xây dựng Cộng đồng Lynx Vietnam tại: &lt;a href="https://lynx-vietnam.dev" rel="noopener noreferrer"&gt;https://lynx-vietnam.dev&lt;/a&gt;, các bạn có ý kiến đóng góp hoặc yêu cầu gì xin vui lòng comment bên dưới. Mình rất trân quý và sẽ nỗ lực hết sức để giúp ích nhiều hơn cho cộng đồng.&lt;/p&gt;

&lt;p&gt;Chúc các bạn ngày mới làm việc hiệu quả.&lt;/p&gt;

&lt;p&gt;[edit]:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trong phần lớn trường hợp RN dùng Hermes&lt;/li&gt;
&lt;li&gt;Nếu Hermes bị disable thì nó sẽ chuyển qua dùng JSC (Javascript Core).&lt;/li&gt;
&lt;li&gt;Khi dùng Chrome debug thì code sẽ thực thi trên Chrome vốn sử dụng V8&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>javascript</category>
      <category>lynx</category>
    </item>
    <item>
      <title>Lynx: Giải pháp mới cho ứng dụng đa nền tảng - Giới thiệu</title>
      <dc:creator>Nguyễn Anh Tuấn</dc:creator>
      <pubDate>Thu, 13 Mar 2025 02:20:21 +0000</pubDate>
      <link>https://dev.to/anhtuank7c/lynx-giai-phap-moi-cho-ung-dung-da-nen-tang-1ppe</link>
      <guid>https://dev.to/anhtuank7c/lynx-giai-phap-moi-cho-ung-dung-da-nen-tang-1ppe</guid>
      <description>&lt;p&gt;Lynx là một framework mới, ra mắt vào ngày 05/03/2025, được thiết kế để khắc phục những hạn chế của các nền tảng phát triển ứng dụng đa nền tảng hiện tại như React Native và Flutter.&lt;/p&gt;

&lt;p&gt;Lynx giúp các lập trình viên web có thể tận dụng ngay kỹ năng của mình để xây dựng ứng dụng di động và web từ một mã nguồn duy nhất, mà không cần phải học thêm một ngôn ngữ lập trình mới.&lt;/p&gt;

&lt;p&gt;Với mục tiêu đạt hiệu suất cao và mang đến trải nghiệm người dùng mượt mà, Lynx đem lại một cách tiếp cận hoàn toàn mới trong việc phát triển ứng dụng đa nền tảng.&lt;/p&gt;

&lt;p&gt;Vì sao Lynx ra đời?&lt;/p&gt;

&lt;p&gt;Hiện nay, React Native và Flutter là hai nền tảng phổ biến nhất để xây dựng ứng dụng di động đa nền tảng. Tuy nhiên, cả hai đều có những hạn chế nhất định:&lt;/p&gt;

&lt;p&gt;React Native sử dụng JavaScript/TypeScript, cho phép tái sử dụng mã nguồn.&lt;br&gt;
Tuy nhiên, nó gặp vấn đề về hiệu suất do phải sử dụng cầu nối (bridge) để giao tiếp giữa JavaScript và mã native. &lt;br&gt;
Dù đã có New Architecture, nhưng React Native vẫn đối mặt với lỗi màn hình trắng (blank screen) khi ứng dụng khởi chạy hay khi scroll nhanh một Flatlist nhiều item với các item có chiều cao bất kỳ.&lt;/p&gt;

&lt;p&gt;Flutter có hiệu suất gần như ứng dụng native, nhưng lại yêu cầu lập trình viên học ngôn ngữ Dart – một rào cản không nhỏ. Đồng thời, việc tận dụng lại kỹ năng của web developers là không khả thi, khiến nhiều người không thể chuyển đổi nhanh chóng sang Flutter.&lt;br&gt;
Lynx ra đời để giải quyết những vấn đề này bằng cách cung cấp một framework:&lt;/p&gt;

&lt;p&gt;✅ Hiệu suất cao như Flutter&lt;br&gt;
✅ Dễ tiếp cận như React Native&lt;br&gt;
✅ Tận dụng công nghệ web (HTML, CSS) giúp lập trình viên nhanh chóng xây dựng ứng dụng đa nền tảng.&lt;/p&gt;

&lt;p&gt;Vì sao Lynx nhanh?&lt;/p&gt;

&lt;p&gt;Lynx có một cải tiến quan trọng trong kiến trúc, giúp tăng tốc độ xử lý bằng cách chia script thành hai luồng chạy song song:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Main Thread – Luồng chính&lt;br&gt;
👉 Sử dụng PrimJS, một engine JavaScript tốc độ cao, được tối ưu riêng cho Lynx.&lt;br&gt;
👉 Xử lý các tác vụ UI đồng bộ như khởi chạy ứng dụng và các sự kiện có độ ưu tiên cao.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Background Thread – Luồng nền&lt;br&gt;
👉 Xử lý phần lớn mã của lập trình viên, giúp giảm tải công việc trên Main Thread.&lt;br&gt;
👉 Đảm bảo ứng dụng chạy mượt mà, không bị blocking, ngay cả khi thực thi các tác vụ phức tạp.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nhờ vào kiến trúc này, Lynx có thể đạt được hai tính năng quan trọng giúp tăng tốc độ xử lý:&lt;/p&gt;

&lt;p&gt;🔥 Instant First-Frame Rendering (IFR)&lt;br&gt;
Theo nghiên cứu từ Nielsen Norman Group, thời gian phản hồi dưới 0.1 giây khiến người dùng cảm nhận ứng dụng phản hồi ngay lập tức [Nguồn &lt;a href="https://www.nngroup.com/articles/response-times-3-important-limits" rel="noopener noreferrer"&gt;https://www.nngroup.com/articles/response-times-3-important-limits&lt;/a&gt;].&lt;/p&gt;

&lt;p&gt;Lynx chặn Main Thread cho đến khi khung hình đầu tiên được vẽ hoàn chỉnh, giúp loại bỏ hiện tượng màn hình trắng (blank screen) khi mở ứng dụng. Điều này giúp tạo ra trải nghiệm người dùng mượt mà và tức thì.&lt;/p&gt;

&lt;p&gt;🚀 Main Thread Scripting (MTS)&lt;br&gt;
Lynx có một cơ chế đặc biệt: một đoạn mã tĩnh nhỏ sẽ được lập lịch và chạy trên Main Thread.&lt;br&gt;
👉 Ưu tiên xử lý các sự kiện UI quan trọng như cử chỉ (gestures) và thao tác người dùng.&lt;br&gt;
👉 Đảm bảo giao diện luôn mượt mà, không bị giật lag, mang lại trải nghiệm nhanh như ứng dụng native.&lt;/p&gt;

&lt;p&gt;Kết luận&lt;br&gt;
Lynx không chỉ giúp các lập trình viên web dễ dàng xây dựng ứng dụng đa nền tảng, mà còn giải quyết những vấn đề về hiệu suất mà các framework trước đây gặp phải.&lt;br&gt;
Lynx hứa hẹn sẽ trở thành một lựa chọn hàng đầu cho việc phát triển ứng dụng di động và web trong tương lai. 🚀&lt;/p&gt;

&lt;p&gt;[còn tiếp]&lt;/p&gt;

&lt;p&gt;Mình đang xây dựng Cộng đồng Lynx Vietnam tại: &lt;a href="https://lynx-vietnam.dev" rel="noopener noreferrer"&gt;https://lynx-vietnam.dev&lt;/a&gt;, các bạn có ý kiến đóng góp hoặc yêu cầu gì xin vui lòng comment bên dưới. Mình rất trân quý và sẽ nỗ lực hết sức để giúp ích nhiều hơn cho cộng đồng.&lt;br&gt;
Chúc các bạn ngày mới làm việc hiệu quả.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>lynx</category>
    </item>
    <item>
      <title>Review code</title>
      <dc:creator>Nguyễn Anh Tuấn</dc:creator>
      <pubDate>Sun, 28 Jan 2024 03:42:06 +0000</pubDate>
      <link>https://dev.to/anhtuank7c/review-code-iki</link>
      <guid>https://dev.to/anhtuank7c/review-code-iki</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanhtuank7c.dev%2Fassets%2Fimages%2Freview-code-fe2e64d0a4fdeb73c737b5f59c8d3558.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanhtuank7c.dev%2Fassets%2Fimages%2Freview-code-fe2e64d0a4fdeb73c737b5f59c8d3558.webp" alt="Review code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Review code là gì?
&lt;/h2&gt;

&lt;p&gt;Review code là một hoạt động quan trọng trong quá trình phát triển phần mềm, nơi các đồng nghiệp kiểm tra và đánh giá chéo mã code của nhau.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vì sao cần review code?
&lt;/h2&gt;

&lt;p&gt;Việc con người gây ra lỗi là điều không mong muốn nhưng cũng không hoàn toàn tránh được (Có nhiều yếu tố khiến con người gây ra lỗi như thể trạng sức khỏe, tâm lý, tiếng ồn, suy giảm sự tập chung, etc...). Vì vậy chúng ta cần review code để giảm thiểu rủi ro tiềm tàng cho hệ thống càng sớm càng tốt.&lt;/p&gt;

&lt;p&gt;Mục tiêu chính của việc review code bao gồm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tìm và sửa lỗi&lt;/li&gt;
&lt;li&gt;Đảm bảo code tuân thủ các tiêu chuẩn, các nguyên tắc mà dự án đang áp dụng&lt;/li&gt;
&lt;li&gt;Cung cấp cơ hội chia sẻ kiến thức giữa các thành viên&lt;/li&gt;
&lt;li&gt;Gia tăng giao tiếp giúp các thành viên hiểu nhau hơn&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Các vấn đề chính khi review code
&lt;/h2&gt;

&lt;p&gt;Bạn cần tạo ra một danh sách (checklist) những câu hỏi và quy tắc được xác định trước mà dự án (và nhóm của bạn) sẽ tuân theo trong quá trình review.&lt;/p&gt;

&lt;p&gt;Danh sách này thường tập chung vào các vấn đề chính sau:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Readability&lt;/strong&gt; (Khả năng đọc): Có bất kỳ đoạn comment dư thừa nào trong code không?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; (Bảo mật): Đoạn mã có khả năng khiến hệ thống bị tấn công mạng không?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test coverage&lt;/strong&gt; (Độ bao phủ test): Có cần thêm các test case khác không?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architecture&lt;/strong&gt; (Kiến trúc): Mã có tính bao đóng, mô đun hóa để đạt được sự phân tách mối quan ngại không (separation of concerns)? Pattern áp dụng có chính xác không?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusability&lt;/strong&gt; (Khả năng tái sử dụng): Mã có tái sử dụng các components, functions hay services có sẵn không?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bằng cách kiểm tra danh sách câu hỏi những vấn đề trong đoạn code sẽ được phơi bày một cách chi tiết và tường minh, không mang cảm tính. Việc sửa lỗi cũng trở nên rõ ràng và dễ hiểu hơn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Những lưu ý khi review code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Để lại review chi tiết
&lt;/h3&gt;

&lt;p&gt;Khi bạn review code, đừng chỉ để lại những đánh giá chung chung hoặc chỉ gợi ý thay đổi, thay vào đó hãy giải thích vấn đề hiện tại là gì, vì sao nên thực hiện thay đổi.&lt;/p&gt;

&lt;p&gt;Vì sao cần giải thích chi tiết như vậy?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Đó là cách mà bạn biện minh cho nhận xét của mình, họ sẽ k cần hỏi lại bạn vì sao nên thực hiện những thay đổi mà bạn khuyến nghị. Điều này sẽ tiết kiệm thời gian cho bạn và cho người đánh giá.&lt;/li&gt;
&lt;li&gt;Bạn review code cẩn thận hơn, không xuề xòa cho qua, nói có sách, mách có chứng.&lt;/li&gt;
&lt;li&gt;Người được đánh giá code sẽ biết lý do cụ thể vì sao họ cần thực hiện thay đổi, điều này giúp họ giải quyết vấn đề tương tự trong tương lai.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Giữ thái độ đúng mực, cầu tiến
&lt;/h3&gt;

&lt;p&gt;Việc review code suy cho cùng là khiến cho con tàu đi đúng hướng, mục tiêu dự án hoàn thành một cách đúng đắn. Mọi người cần giữ thái độ đúng mực, cầu tiến khi review cũng như khi nhận được review. Hãy loại bỏ yếu tố cảm xúc để tránh ảnh hưởng tới công việc.&lt;/p&gt;

&lt;p&gt;Nếu bạn viết code chưa được tốt, những feedback đáng giá sẽ giúp bạn viết code tốt hơn, điều này tốt cho bạn.&lt;/p&gt;

&lt;h3&gt;
  
  
  Không review đoạn code dài hơn 200 dòng
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://static1.smartbear.co/support/media/resources/cc/book/code-review-cisco-case-study.pdf" rel="noopener noreferrer"&gt;Nghiên cứu tại Cisco Systems năm 2006&lt;/a&gt; chỉ ra rằng khả năng tìm ra bug của developer giảm dần khi phải review nhiều hơn 200 dòng code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mỗi commit chỉ nên chứa một ý nghĩa
&lt;/h3&gt;

&lt;p&gt;Những commit chứa quá nhiều code, nhiều thay đổi không liên quan tới nhau cũng làm giảm khả năng khôi phục mã code trong các nhánh (branch) đồng thời cũng làm khó người review.&lt;/p&gt;

&lt;p&gt;Ví dụ: bạn có một commit đảm nhiệm 02 thay đổi: format code, add thêm business logic&lt;/p&gt;

&lt;p&gt;Khi này bạn cần tách ra làm 02 commit riêng lẻ, 01 commit cho format code, 01 commit cho việc add thêm business logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tự động hóa quá trình review codeTrên thị trường có nhiều công cụ review code tự động có thể kể đến SonarQube, ESLint, SwiftLint, JSHint, Codestriker, Deepscan etc...
&lt;/h3&gt;

&lt;p&gt;Tùy thuộc dự án và chi phí mà bạn tìm công cụ phù hợp với mình.&lt;/p&gt;

&lt;p&gt;Đa phần các công cụ này đều rất dễ dàng tích hợp vào CI/CD, developer có thể nhận được phản hồi rất sớm sau khi commit code (hoặc trước khi commit code như sử dụng precommit kết hợp Linter).&lt;/p&gt;

&lt;p&gt;Việc này cũng làm giảm tải đáng kể cho người review.&lt;/p&gt;

&lt;p&gt;Tuy nhiên những công cụ này không hoàn toàn thay thế cho con người được, có thể kể đến những nguyên tắc mà team bạn đề ra, lấy ví dụ như SOLID principles, bạn cần yếu tố con người để review khía cạnh này một cách chuẩn xác hơn.&lt;/p&gt;

&lt;h3&gt;
  
  
  Developer cần hiểu rõ trách nhiệm
&lt;/h3&gt;

&lt;p&gt;Dù review code giúp nâng cao chất lượng code và giảm thiểu lỗi, tuy nhiên không ai chắc chắn 100% phương pháp này sẽ loại bỏ hoàn toàn những lỗi tiềm tàng.&lt;/p&gt;

&lt;p&gt;Bạn với tư cách là người viết code cần chịu trách nhiệm cao nhất về tính đúng đắn của code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kết bài
&lt;/h2&gt;

&lt;p&gt;Code review là một hoạt động thú vị nhưng mất thời gian và công sức. Tuy nhiên kết quả có tốt hay không còn phụ thuộc vào sự cam kết của team bạn.&lt;/p&gt;

&lt;p&gt;Team bạn áp dụng quy trình review code như thế nào?&lt;/p&gt;

&lt;p&gt;Nếu bạn thấy bài viết này còn thiếu sót hay cần bổ sung gì thì đừng ngần ngại liên hệ với mình qua các kênh mxh bên dưới nhé.&lt;/p&gt;

&lt;p&gt;Chúc bạn và team có những buổi review code hiệu quả.&lt;/p&gt;

&lt;p&gt;Bài viết gốc &lt;a href="https://anhtuank7c.dev/blog/review-code" rel="noopener noreferrer"&gt;tại đây&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reviewcode</category>
      <category>softwaredevelopment</category>
      <category>codequality</category>
      <category>qualitycontrol</category>
    </item>
    <item>
      <title>Dependency Inversion Principle (DIP)</title>
      <dc:creator>Nguyễn Anh Tuấn</dc:creator>
      <pubDate>Wed, 13 Dec 2023 15:04:26 +0000</pubDate>
      <link>https://dev.to/anhtuank7c/dependency-inversion-principle-dip-2b19</link>
      <guid>https://dev.to/anhtuank7c/dependency-inversion-principle-dip-2b19</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanhtuank7c.dev%2Fassets%2Fimages%2Fdependency-inversion-principle-77f1b3daeff9f057918d933eedded01f.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanhtuank7c.dev%2Fassets%2Fimages%2Fdependency-inversion-principle-77f1b3daeff9f057918d933eedded01f.webp" alt="Dependency Inversion Principle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tiếp nối chuỗi bài SOLID principles, bài này chúng ta cùng tìm hiểu nguyên tắc đảo ngược phụ thuộc (dependency inversion principle) là gì và nó quan trọng ra sao nhé.&lt;/p&gt;

&lt;p&gt;Đây là nguyên tắc cuối cùng trong bộ 05 nguyên tắc SOLID.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependency Inversion Principle (DIP) là gì?
&lt;/h2&gt;

&lt;p&gt;Nguyên tắc đảo ngược phụ thuộc (DIP) là nguyên tắc mà trong đó nhấn mạnh &lt;strong&gt;module cấp cao&lt;/strong&gt; chỉ được phụ thuộc vào các lớp trừu tượng (abstraction/interface) của &lt;strong&gt;module cấp thấp&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Nguyên tắc này được giới thiệu bởi &lt;a href="https://en.wikipedia.org/wiki/Robert_C._Martin" rel="noopener noreferrer"&gt;Robert C. Martin&lt;/a&gt; hay còn gọi là &lt;strong&gt;Uncle Bob&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Có thể thấy &lt;strong&gt;Uncle Bob&lt;/strong&gt; đã đóng góp 3/5 nguyên tắc trong bộ &lt;a href="https://anhtuank7c.dev/blog/solid-principles" rel="noopener noreferrer"&gt;SOLID principles&lt;/a&gt; bao gồm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://anhtuank7c.dev/blog/single-responsibility-principle" rel="noopener noreferrer"&gt;Single Resonsibility Principle (SRP)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anhtuank7c.dev/blog/interface-segregation-principle" rel="noopener noreferrer"&gt;Interface Segregation Principle (ISP)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anhtuank7c.dev/blog/dependency-inversion-principle" rel="noopener noreferrer"&gt;Dependency Inversion Principle (DIP)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Trong định nghĩa trên có 02 điểm chưa rõ ràng, module cấp cao là gì? module cấp thấp là gì?&lt;/p&gt;

&lt;h3&gt;
  
  
  Module cấp cao (high-level modules) là gì?:
&lt;/h3&gt;

&lt;p&gt;Là các module mà trong đó nó phụ thuộc vào các module cấp thấp khác để implement business logic với mục đích cụ thể như xử lý thanh toán giỏ hàng, book lịch họp etc...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// high-level module&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderProcessorService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// PaymentRepository and ShippingRepository are injected too loose coupled&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PaymentRepository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;shipping&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ShippingRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;checkout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shipping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ở ví dụ này module &lt;strong&gt;OrderProcessorService&lt;/strong&gt; là module cấp cao, nó phụ thuộc vào module cấp thấp hơn là &lt;strong&gt;PaymentRepository&lt;/strong&gt; và &lt;strong&gt;ShippingRepository&lt;/strong&gt; (trình bày bên dưới).&lt;/p&gt;

&lt;h3&gt;
  
  
  Module cấp thấp (low-level modules) là gì?:
&lt;/h3&gt;

&lt;p&gt;Ngược lại với module bậc cao, module cấp thấp là các module mà trong đó nó có thể hoạt động độc lập, không phụ thuộc vào bất cứ module nào khác. Nó có thể dễ dàng tái sử dụng ở bất kỳ đâu mà không bị ràng buộc vào phụ thuộc nào khác.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// abstraction&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PaymentRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// abstraction&lt;/span&gt;
&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShippingRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// low-level module&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaypalPaymentRepository&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;PaymentRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// call Paypal API&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Processing paypal payment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// low-level module&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AirplaneShippingRepository&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ShippingRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// call Delivery API&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Processing shipping with A320 Airplane&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ở ví dụ này, các module cấp thấp như &lt;strong&gt;PaymentRepository&lt;/strong&gt;, &lt;strong&gt;ShippingRepository&lt;/strong&gt; không phụ thuộc vào bất cứ module nào khác, vì thế 02 modules này rất linh hoạt trong việc tái sử dụng.&lt;/p&gt;

&lt;p&gt;Hãy làm rõ hơn vấn đề qua ví dụ sau&lt;/p&gt;

&lt;h2&gt;
  
  
  Ví dụ vi phạm nguyên tắc đảo ngược phụ thuộc (DIP)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Violating DIP&lt;/span&gt;

&lt;span class="c1"&gt;// concrete implemented class&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SMSSender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`sending SMS: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// violate since NotificationService depend on concrete implementation of SMSSender&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SMSSender&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// tight coulped&lt;/span&gt;

    &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notiService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ở ví dụ này, high-level module &lt;strong&gt;NotificationService&lt;/strong&gt; phụ thuộc vào low-level module &lt;strong&gt;SMSSender&lt;/strong&gt;  trong khi nguyên tắc chỉ ra rằng module bậc cao chỉ được phụ thuộc vào lớp trừu tượng (abstract/interface) của module bậc thấp.&lt;/p&gt;

&lt;p&gt;Việc phụ thuộc vào một module/class đã được implement chi tiết là vi phạm nguyên tắc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ví dụ tuân theo nguyên tắc đảo ngược phụ thuộc (DIP)
&lt;/h2&gt;

&lt;p&gt;Chúng ta hãy thiết kế lại ví dụ trên để tuân theo nguyên tắc đảo ngược phụ thuộc nhé.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Adhering DIP&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;SenderRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// low-level module&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SmsSenderRepository&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;SenderRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// calling sms api&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// low-level module&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSenderRepository&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;SenderRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// calling smtp&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// high-level module&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// adhering since NotificationService depend on an abstraction of low-level abstraction/interface&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SenderRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// loose coupled by using dependency injection&lt;/span&gt;

    &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;smsSenderRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SmsSenderRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notiServiceSMS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;smsSenderRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailSenderRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EmailSenderRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notiServiceEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emailSenderRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ở ví dụ này mình đã triển khai interface &lt;strong&gt;SenderRepository&lt;/strong&gt;, class &lt;strong&gt;NotificationService&lt;/strong&gt; nay chỉ phụ thuộc vào interface &lt;strong&gt;SenderRepository&lt;/strong&gt;, bạn có thể truyền bất cứ class nào implement interface &lt;strong&gt;SenderRepository&lt;/strong&gt; đều được.&lt;/p&gt;

&lt;p&gt;Chúng ta sử dụng kỹ thuật tiêm vào sự phụ thuộc (Dependency injection technique) để truyền bất cứ class nào implement interface &lt;strong&gt;SenderRepository&lt;/strong&gt; vào class &lt;strong&gt;NotificationService&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Một vài khái niệm nhắc đến trong bài:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dependency injection&lt;/strong&gt;: Là một kỹ thuật mà trong đó các class hoặc module nhận instance/object của class phụ thuộc thông qua constructor thay vì khởi tạo instance đó trong class chỉ định.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PaymentRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// low-level module&lt;/span&gt;
  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MomoPaymentRepository&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;PaymentRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// high-level module&lt;/span&gt;
  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShoppingCartService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PaymentRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;// depend on PaymentRepository interface&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;momoPaymentRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MomoPaymentRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shoppingCartService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ShoppingCartService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;momoPaymentRepo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// inject dependency momoPaymentRepo into class via constructor&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;tight coupled&lt;/strong&gt;: Liên kết chặt chẽ. Điều này không tốt, các module phụ thuộc chặt chẽ sẽ làm giảm khả năng mở rộng, nâng cấp.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Xét ví dụ sau&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentRepository&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;BasePaymentRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderProcessorService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PaymentRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// tight coupled&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderProcessorService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OrderProcessorService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;loose coupled&lt;/strong&gt;: Liên kết lỏng lẻo. Việc này khiến các module trở nên độc lập hơn, dễ mở rộng và nâng cấp hơn.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thiết kế lại ví dụ bên trên&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentRepository&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;BasePaymentRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderProcessorService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BasePaymentRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;// loose coupled&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;paymentRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PaymentRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderProcessorService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OrderProcessorService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paymentRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// dependency injection paymentRepository&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Unit test
&lt;/h2&gt;

&lt;p&gt;Codebase tuân theo SOLID principles luôn luôn nhấn mạnh tính dễ bảo trì, linh động và khả năng test cao. Vì thế mình luôn luôn cung cấp unit test để trình diễn khả năng này.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SmsSenderRepository&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;able to send SMS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;smsSenderRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SmsSenderRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;smsSenderRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toThrow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EmailSenderRepository&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;able to send email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailSenderRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EmailSenderRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emailSenderRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toThrow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;NotificationService&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;able to send sms&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;smsSenderRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SmsSenderRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notiServiceSMS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;smsSenderRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;notiServiceSMS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toThrow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;able to send email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailSenderRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EmailSenderRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notiServiceEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emailSenderRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;notiServiceEmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toThrow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Hỏi đáp
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Làm sao để ứng dụng nguyên tắc đảo ngược phụ thuộc vào code của bạn?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A: Để ứng dụng nguyên tắc đảo ngược phụ thuộc, tôi làm theo các bước sau:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tạo ra các module cấp cao phụ thuộc vào lớp trừu tượng chứ không phụ thuộc vào lớp cụ thể.&lt;/li&gt;
&lt;li&gt;Tạo ra các module cấp thấp implements/extends lớp trừu tượng mà module cấp cao phụ thuộc vào.&lt;/li&gt;
&lt;li&gt;Sử dụng kỹ thuật dependency injection để cung cấp object của module cấp thấp cho module cấp cao.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Kết luận
&lt;/h2&gt;

&lt;p&gt;Nguyên tắc đảo ngược phụ thuộc (Dependency Inversion Principle) giúp chúng ta thiết kế ra các module/class theo hướng dễ dàng mở rộng và không bị ràng buộc chặt chẽ vào module khác.&lt;/p&gt;

&lt;p&gt;Đây là cũng nguyên tắc cuối cùng trong bộ 05 nguyên tắc SOLID. Mong các bạn đọc kỹ từng bài và thực hành thuần thục hơn.&lt;/p&gt;

&lt;p&gt;Nếu bạn phát hiện sai sót, đừng ngần ngại báo lại cho mình qua các kênh mạng xã hội bên dưới website.&lt;/p&gt;

&lt;p&gt;Tiếp nối chủ đề &lt;a href="https://anhtuank7c.dev/blog/solid-principles" rel="noopener noreferrer"&gt;SOLID principles&lt;/a&gt;, bài viết tiếp theo mình sẽ tạo ra một ứng dụng cơ bản ứng dụng các nguyên tắc SOLID để các bạn có cái nhìn tổng thể.&lt;/p&gt;

&lt;p&gt;Chúc bạn ngày mới tốt lành, nếu thấy bài viết hữu ích đừng quên chia sẻ và lan tỏa nhé.&lt;/p&gt;

&lt;p&gt;Bài viết gốc &lt;a href="https://anhtuank7c.dev/blog/dependency-inversion-principle" rel="noopener noreferrer"&gt;tại đây&lt;/a&gt;&lt;/p&gt;

</description>
      <category>solidprinciples</category>
      <category>anhtuank7c</category>
      <category>dependencyinversion</category>
    </item>
    <item>
      <title>Interface Segregation Principle (ISP)</title>
      <dc:creator>Nguyễn Anh Tuấn</dc:creator>
      <pubDate>Tue, 12 Dec 2023 09:49:19 +0000</pubDate>
      <link>https://dev.to/anhtuank7c/interface-segregation-principle-isp-3aai</link>
      <guid>https://dev.to/anhtuank7c/interface-segregation-principle-isp-3aai</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xWbX4MzR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://anhtuank7c.dev/assets/images/interface-segregation-principle-5c5e87f46ff469b9bc79b8abcc2b7354.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xWbX4MzR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://anhtuank7c.dev/assets/images/interface-segregation-principle-5c5e87f46ff469b9bc79b8abcc2b7354.webp" alt="Interface Segregation Principle (ISP)" width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tiếp theo chuỗi bài về &lt;a href="https://anhtuank7c.dev/blog/solid-principles"&gt;SOLID principles&lt;/a&gt;, bài này chúng ta sẽ tìm hiểu về nguyên tắc phân tách Interface nhé&lt;/p&gt;

&lt;h2&gt;
  
  
  Interface Segregation Principle (ISP) là gì?
&lt;/h2&gt;

&lt;p&gt;Nguyên tắc phân tách Interface khẳng định rằng &lt;strong&gt;không nên&lt;/strong&gt; buộc các entities (như class, module...) phải phụ thuộc vào các phương thức (method) mà nó không sử dụng đến.&lt;/p&gt;

&lt;p&gt;Hay giải thích bằng cách khác: Bạn không nên tạo ra interface lớn, mục đích chung chung bao gồm quá nhiều method, hãy ưu tiên tạo ra nhiều interface nhỏ, mục đích cụ thể. Theo đó các class chỉ cần implement các interface mà nó thực sự dùng đến.&lt;/p&gt;

&lt;p&gt;Nguyên tắc này được giới thiệu bởi &lt;a href="https://en.wikipedia.org/wiki/Robert_C._Martin"&gt;Robert C. Martin&lt;/a&gt; hay còn gọi là &lt;strong&gt;Uncle Bob&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nghe có vẻ khó hiểu phải không?&lt;/p&gt;

&lt;p&gt;Chúng ta hãy làm rõ vấn đề qua các ví dụ nhé.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ví dụ về sự vi phạm nguyên tắc phân tách interface (ISP)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Worker&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Worker&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Person can eat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Person can work&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Person can sleep&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Robot&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Worker&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// forced to eat =&amp;gt; violate&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Robot cannot eat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Robot can work&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// forced to eat =&amp;gt; violate&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Robot cannot sleep&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ở ví dụ này ta thấy class &lt;strong&gt;Person&lt;/strong&gt; hoàn toàn có đủ các hành vi như &lt;code&gt;work&lt;/code&gt; &lt;code&gt;eat&lt;/code&gt; và &lt;code&gt;sleep&lt;/code&gt; nhưng điều này không hoàn toàn đúng với class &lt;strong&gt;Robot&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Robot&lt;/strong&gt; không &lt;code&gt;eat&lt;/code&gt; mà cũng không &lt;code&gt;sleep&lt;/code&gt;, việc ép buộc class &lt;strong&gt;Robot&lt;/strong&gt; phải implement 02 method này đã &lt;em&gt;vi phạm nguyên tắc phân tách interface&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Chúng ta cùng thiết kế lại ví dụ trên theo nguyên tắc phân tách interface nhé&lt;/p&gt;

&lt;h2&gt;
  
  
  Ví dụ tuân theo nguyên tắc phân tách interface
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Adhering&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Eatable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Workable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Sleepable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Eatable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Workable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Sleepable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Person can eat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Person can work&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Person can sleep&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Robot&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Workable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Robot can work&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ở ví dụ này chúng ta đã phân tách các hành vi ra thành các interface riêng biệt.&lt;/p&gt;

&lt;p&gt;Với class Person, hiển nhiên con người có thể &lt;code&gt;eat&lt;/code&gt; &lt;code&gt;work&lt;/code&gt; và &lt;code&gt;sleep&lt;/code&gt; nên chúng ta implement toàn bộ 3 interface &lt;code&gt;Eatable&lt;/code&gt; &lt;code&gt;Workable&lt;/code&gt; và &lt;code&gt;Sleepable&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Còn với class Robot, rotbot chỉ có thể &lt;code&gt;work&lt;/code&gt; nên chúng ta chỉ implement interface &lt;code&gt;Workable&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Điều này giúp làm giảm lượng code rác, không cần thiết và cũng khiến cho hệ thống linh hoạt hơn, implement vừa đủ, không thừa không thiếu&lt;/p&gt;

&lt;h2&gt;
  
  
  Unit test
&lt;/h2&gt;

&lt;p&gt;Tiết mục unit test quen thuộc lại xuất hiện&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Person&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;able to eat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toThrow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;able to work&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toThrow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;able to sleep&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toThrow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Robot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;able to work&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;robot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Robot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;robot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toThrow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Hỏi đáp
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Làm thế nào để có thể ứng dụng nguyên tắc phân tách interface trong code của bạn?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt;: Để ứng dụng nguyên tắc phân tách interface, tôi làm theo các bước sau:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Định nghĩa ra các interface nhỏ, tập chung vào yếu tố chuyên biệt, cụ thể của interface đó.&lt;/li&gt;
&lt;li&gt;Tránh tạo ra các interface lớn (gồm nhiều method) mà các class phải implements những method không cần dùng tới.&lt;/li&gt;
&lt;li&gt;Ưu tiên sử dụng nhiều interface chuyên biệt thay vì sử dụng một interface lớn hoặc interface mang tính chất chung chung.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tổng kết
&lt;/h2&gt;

&lt;p&gt;Nguyên tắc phân tách interface (ISP) giúp hạn chế code rác, tập chung vào sự chuyên biệt của từng interface, nâng cao nhận thức với từng hành vi.&lt;/p&gt;

&lt;p&gt;Điều này rất tốt cho việc tổ chức code và bảo trì cũng như khả năng kiểm thử (test)&lt;/p&gt;

&lt;p&gt;Nếu bạn phát hiện sai sót, đừng ngần ngại báo lại cho mình qua các kênh mạng xã hội bên dưới website.&lt;/p&gt;

&lt;p&gt;Các bài viết tiếp nối chủ đề &lt;a href="https://anhtuank7c.dev/blog/solid-principles"&gt;SOLID principles&lt;/a&gt; sẽ sớm được cập nhật.&lt;/p&gt;

&lt;p&gt;Chúc bạn ngày mới tốt lành.&lt;/p&gt;

&lt;p&gt;Đọc bài gốc &lt;a href="https://anhtuank7c.dev/blog/interface-segregation-principle"&gt;tại đây&lt;/a&gt;&lt;/p&gt;

</description>
      <category>solidprinciples</category>
      <category>interfacesegregation</category>
      <category>anhtuank7c</category>
    </item>
    <item>
      <title>Liskov Substitution Principle (LSP)</title>
      <dc:creator>Nguyễn Anh Tuấn</dc:creator>
      <pubDate>Tue, 12 Dec 2023 09:22:09 +0000</pubDate>
      <link>https://dev.to/anhtuank7c/liskov-substitution-principle-lsp-4e9i</link>
      <guid>https://dev.to/anhtuank7c/liskov-substitution-principle-lsp-4e9i</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EEUoKHjA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://anhtuank7c.dev/assets/images/liskov-substitution-principle-cfefa0f8693ce36fa901daa0eceea755.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EEUoKHjA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://anhtuank7c.dev/assets/images/liskov-substitution-principle-cfefa0f8693ce36fa901daa0eceea755.webp" alt="Liskov Substitution Principle" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tiếp nối chuỗi bài viết &lt;a href="https://anhtuank7c.dev/blog/solid-principles"&gt;SOLID principles&lt;/a&gt;, hôm nay chúng ta sẽ tìm hiểu về Nguyên tắc thay thế Liskov (Liskov Substitution Principle)&lt;/p&gt;

&lt;h2&gt;
  
  
  Liskov Substitution Principle (LSP) là gì?
&lt;/h2&gt;

&lt;p&gt;Nếu &lt;strong&gt;S&lt;/strong&gt; là kiểu con của &lt;strong&gt;T&lt;/strong&gt; thì các đối tượng kiểu &lt;strong&gt;T&lt;/strong&gt; trong chương trình có thể được thay thế bằng các đối tượng kiểu &lt;strong&gt;S&lt;/strong&gt; mà &lt;strong&gt;&lt;em&gt;không làm thay đổi&lt;/em&gt;&lt;/strong&gt; bất kỳ thuộc tính/hành vi mong muốn nào của chương trình.&lt;/p&gt;

&lt;p&gt;Hay nói cách khác, Liskov Substitution Principle định nghĩa ra một hợp đồng mà các lớp dẫn xuất (derived classes) phải tuân thủ để có thể thay thế thực sự cho các lớp cơ sở của chúng.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mục tiêu của LSP
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Khả năng thay thế&lt;/strong&gt;: đối tượng (object) của lớp dẫn xuất có thể thay thế các đối tượng của lớp cơ sở mà không ảnh hưởng tới tính chính xác của chương trình. Điều này cho phép đa hình (polymorphism) và tăng cường tính linh hoạt của chương trình.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bảo tồn hành vi&lt;/strong&gt;: các lớp dẫn xuất nên duy trì hoặc mở rộng hành vi của lớp cơ sở.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dễ dàng hoán đổi&lt;/strong&gt;: các lớp dẫn xuất dễ dàng hoán đổi cho lớp cơ sở trong mọi ngữ cảnh. Điều này thúc đẩy mức trừu tượng cao, và cho phép viết mã code được viết theo cách độc lập và triển khai cụ thể. (specific concrete implementation)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tính nhất quán&lt;/strong&gt;: LSP giúp tạo ra hành vi nhất quán và có thể đoán trước được trong hệ thống phân cấp của các lớp. Nó ngăn chặn tác dụng phụ không mong muốn hoặc ngăn chặn thay đổi hành vi khi sử dụng các lớp dẫn xuất.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nguyên tắc thay thế Liskov được &lt;a href="https://en.wikipedia.org/wiki/Barbara_Liskov"&gt;Barbara Liskov&lt;/a&gt; giới thiệu trong một hội nghị năm 1987.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ví dụ
&lt;/h2&gt;

&lt;p&gt;Hãy tìm hiểu sâu hơn về nguyên tắc này qua ví dụ sau&lt;/p&gt;

&lt;h3&gt;
  
  
  Vi phạm nguyên tắc thay thế Liskov
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Violating LSP&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="nf"&gt;setWidth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;setHeight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;area&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Violates LSP by changing behavior&lt;/span&gt;
    &lt;span class="nf"&gt;setHeight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Violates LSP by changing behavior&lt;/span&gt;
    &lt;span class="nf"&gt;setWidth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;printArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Rectangle&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setWidth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Area: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;area&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;printArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 50 correct&lt;/span&gt;
&lt;span class="nf"&gt;printArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;square&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 100 =&amp;gt; What the heck is that?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ở ví dụ này mình đã ép 2 cạnh &lt;em&gt;width&lt;/em&gt; và &lt;em&gt;height&lt;/em&gt; bằng nhau khi &lt;em&gt;setWidth&lt;/em&gt;, &lt;em&gt;setHeight&lt;/em&gt; trong class Square. Hành vi &lt;em&gt;setWidth&lt;/em&gt;, &lt;em&gt;setHeight&lt;/em&gt; của lớp cơ sở (class Rectangle) đã bị thay đổi.&lt;/p&gt;

&lt;p&gt;Điều này rõ ràng là đã vi phạm nguyên tắc Liskov Substitution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tuân theo nguyên tắc thay thế Liskov
&lt;/h3&gt;

&lt;p&gt;Chúng ta hãy cùng thiết kế lại các class trong ví dụ trên nhé&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Adhering to LSP with an abstract class&lt;/span&gt;
&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;setDimensions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nf"&gt;area&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;area&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setDimensions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Adheres to LSP by maintaining the base class behavior&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setDimensions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;area&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Function expecting a Shape&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;printArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Shape&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setDimensions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Area: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;area&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Create an instance of Square (derived class)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Use the function with the derived class object&lt;/span&gt;
&lt;span class="nf"&gt;printArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;square&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Output: Area: 50 (adheres to LSP)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ở ví dụ này chúng ta bảo tồn được hành vi &lt;code&gt;setDimensions(number, number)&lt;/code&gt;  và &lt;code&gt;area()&lt;/code&gt; ở lớp cơ sở (class Shape), bạn có thể mở rộng thêm nữa sang các class như Hexagon, Circle nếu muốn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unit test
&lt;/h2&gt;

&lt;p&gt;Vẫn như mọi khi, unit test là điều không thể thiếu khi tuân theo &lt;a href="https://anhtuank7c.dev/blog/solid-principles"&gt;SOLID principles&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;able to calculate square area&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;square&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setDimentions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;square&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;area&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;able to replace subtype by base class instance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shape&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;square&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Shape&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setDimentions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;area&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Hỏi đáp
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Làm thế nào để ứng dụng nguyên tắc thay thế Liskov trong code của bạn?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A: Để ứng dụng nguyên tắc thay thế Liskov, tôi làm theo các bước sau:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Đảm bảo các object của lớp con có thể thay thế bằng object của lớp cha mà không làm thay đổi bất kỳ thuộc tính, hành vi nào của chương trình.&lt;/li&gt;
&lt;li&gt;Các lớp con không được thay đổi hành vi của lớp cha.&lt;/li&gt;
&lt;li&gt;Các lớp con không được đưa ra các ngoại lệ mới mà nó không tồn tại trong lớp cha.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tổng kết
&lt;/h2&gt;

&lt;p&gt;Nguyên tắc thay thế Liskov (Liskov Substitution Principle) hữu ích trong việc đảm bảo hành vi luôn nhất quán và dễ dàng đoán trước xuyên suốt chương trình.&lt;/p&gt;

&lt;p&gt;Việc thực hành nguyên tắc này giúp bạn nhận thức rõ ràng hơn về tính mạch lạc, tin cậy, đồng thời cũng giúp viết unit test dễ dàng hơn.&lt;/p&gt;

&lt;p&gt;Nếu bạn phát hiện sai sót, đừng ngần ngại báo lại cho mình qua các kênh mạng xã hội bên dưới website.&lt;/p&gt;

&lt;p&gt;Các bài viết tiếp nối chủ đề &lt;a href="https://anhtuank7c.dev/blog/solid-principles"&gt;SOLID principles&lt;/a&gt; sẽ sớm được cập nhật.&lt;/p&gt;

&lt;p&gt;Chúc bạn ngày mới tốt lành.&lt;/p&gt;

&lt;p&gt;Đọc bài gốc &lt;a href="https://anhtuank7c.dev/blog/liskov-substitution-principle"&gt;tại đây&lt;/a&gt;&lt;/p&gt;

</description>
      <category>solidprinciples</category>
      <category>liskovsubstitution</category>
      <category>anhtuank7c</category>
    </item>
    <item>
      <title>Open Close Principle (OCP)</title>
      <dc:creator>Nguyễn Anh Tuấn</dc:creator>
      <pubDate>Tue, 12 Dec 2023 09:21:13 +0000</pubDate>
      <link>https://dev.to/anhtuank7c/open-close-principle-ocp-nk</link>
      <guid>https://dev.to/anhtuank7c/open-close-principle-ocp-nk</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IZyWGI_J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://anhtuank7c.dev/assets/images/open-close-principle-e25fb6cb5b64a26e11346d5fe8d9f2e1.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IZyWGI_J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://anhtuank7c.dev/assets/images/open-close-principle-e25fb6cb5b64a26e11346d5fe8d9f2e1.webp" alt="Open Close Principle" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tiếp nối chuỗi bài viết &lt;a href="https://anhtuank7c.dev/blog/solid-principles"&gt;SOLID principles&lt;/a&gt;, hôm nay chúng ta sẽ tìm hiểu về Nguyên tắc đóng mở (Open Close Principle)&lt;/p&gt;

&lt;h2&gt;
  
  
  Định nghĩa
&lt;/h2&gt;

&lt;p&gt;Nguyên tắc đóng mở (Open Close Principle) khuyến khích việc thiết kế các thực thể (entities) như class, module... theo hướng mở cửa cho việc mở rộng (open for extension)  và đóng cửa với việc sửa đổi (close for modification)&lt;/p&gt;

&lt;p&gt;Hay đơn giản hơn là mỗi khi muốn thêm chức năng nào đó, bạn hãy viết class mới để mở rộng bằng cách kế thừa class cũ, không được sửa class cũ.&lt;/p&gt;

&lt;p&gt;Nguyên tắc này được giới thiệu bởi &lt;a href="https://en.wikipedia.org/wiki/Bertrand_Meyer"&gt;Bertrand Meyer&lt;/a&gt; năm 1988.&lt;/p&gt;

&lt;p&gt;Chúng ta hãy tìm hiểu kỹ hơn qua ví dụ thực tế nhé.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ví dụ vi phạm nguyên tắc đóng mở (OCP)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Violating OCP&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Circle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ở ví dụ này, class &lt;code&gt;Shape&lt;/code&gt; vẫn ổn cho tới khi mở rộng tới class &lt;code&gt;Circle&lt;/code&gt;. Cách tính diện tích của hình tròn hoàn toàn khác biệt với hình vuông và hình chữ nhật. Khi này bạn cần sửa đổi method &lt;code&gt;getArea&lt;/code&gt; ở class &lt;code&gt;Shape&lt;/code&gt; để có thể chứa được trường hợp lớp mở rộng là hình tròn (Circle)&lt;/p&gt;

&lt;p&gt;Việc sửa đổi này hoàn toàn đi ngược lại với nguyên tắc đóng mở vì cần phải sửa đổi class &lt;code&gt;Shape&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ví dụ tuân theo nguyên tắc đóng mở (OCP)
&lt;/h2&gt;

&lt;p&gt;Chúng ta hãy thiết kế lại các class này để giúp nó dễ dàng mở rộng mà lại không cần sửa đổi nhé.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Adhering OCP&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;side&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;area of square&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;square&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;area of rectangle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ở lần sửa đổi này mình dùng interface (các bạn cũng có thể dùng abstract class, miễn sao các class kế thừa từ abstract class có thể tự triển khai business logic mà không cần sửa đổi ở lớp abstract).&lt;/p&gt;

&lt;p&gt;Bạn có thể mở rộng ra các class mới như Hexagon (hình lục giác) hay nhiều hình dạng khác (Circle, Square, Rectangle, Hexagon, Triangle, Star, etc...) mà vẫn tuân theo Open Close Principle, không cần sửa đổi gì ở interface Shape.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Adhering OCP&lt;/span&gt;

&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Circle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Hexagon&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;side&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ở ví dụ này mình dùng abstract class và mở rộng ra tận class Hexagon, kết quả tương tự ví dụ trên. Tất cả class đều tuân theo nguyên tắc Mở cho việc mở rộng, và đóng với việc sửa đổi.&lt;/p&gt;

&lt;p&gt;Các bạn có nhận ra các class này có điều gì quen quen không nhỉ?&lt;/p&gt;

&lt;p&gt;Bật mí nhé, đó là mỗi class đều đảm nhiệm một và chỉ một nhiệm vụ riêng. VD class Square thì chỉ tính diện tích cho Square, class Rectangle chỉ tính diện tích cho Rectangle. &lt;/p&gt;

&lt;p&gt;Bạn hãy nhớ tới bài viết trước &lt;a href="https://anhtuank7c.dev/blog/single-responsibility-principle"&gt;Single Responsibility Principle (SRP)&lt;/a&gt; xem có đúng nó không nào?&lt;/p&gt;

&lt;p&gt;Việc áp dụng thành thục các tập nguyên tắc SOLID (principles) sẽ giúp bạn rất nhiều đó, cố gắng luyện tập thành thói quen tốt nhé.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unit test
&lt;/h2&gt;

&lt;p&gt;Đây là phần không thể thiếu và luôn được nhấn mạnh (emphasize) khi tuân theo SOLID principle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;calculate square area correctly&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;square&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;calculate rectangle area correctly&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Unit test mình luôn sử dụng Jest nhé. Các bạn muốn tìm hiểu thêm về jest thì mình sẽ viết riêng một hoặc vài bài về jest.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Hỏi đáp
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Làm thế nào để ứng dụng nguyên tắc đóng mở vào code của bạn?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A: Để ứng dụng nguyên tắc đóng mở, tôi thực hiện các bước sau:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thiết kế class có thể dễ dàng mở rộng&lt;/li&gt;
&lt;li&gt;Sử dụng các abstract class hoặc interface để định nghĩa phần mở rộng&lt;/li&gt;
&lt;li&gt;Tránh sửa đổi code cũ khi thêm tính năng hay chức năng mới.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Kết luận
&lt;/h2&gt;

&lt;p&gt;Nguyên tắc đóng mở (Open Close Principle) mang lại rất nhiều lợi ích khi bạn mở rộng mà không phá vỡ hệ thống. Đảm bảo hệ thống hoạt động ổn định đồng thời dễ bảo trì, dễ kiểm thử (unit test), dễ đọc và dễ nắm bắt.&lt;/p&gt;

&lt;p&gt;Nếu bạn phát hiện sai sót, đừng ngần ngại báo lại cho mình qua các kênh mạng xã hội bên dưới website.&lt;/p&gt;

&lt;p&gt;Các bài viết tiếp nối chủ đề SOLID principles sẽ sớm được cập nhật.&lt;/p&gt;

&lt;p&gt;Chúc bạn ngày mới tốt lành.&lt;/p&gt;

&lt;p&gt;Đọc bài gốc &lt;a href="https://anhtuank7c.dev/blog/open-close-principle"&gt;tại đây&lt;/a&gt;&lt;/p&gt;

</description>
      <category>solidprinciples</category>
      <category>opencloseprinciple</category>
      <category>anhtuank7c</category>
    </item>
    <item>
      <title>Single Resonsibility Principle (SRP)</title>
      <dc:creator>Nguyễn Anh Tuấn</dc:creator>
      <pubDate>Tue, 12 Dec 2023 09:20:22 +0000</pubDate>
      <link>https://dev.to/anhtuank7c/single-resonsibility-principle-srp-jmc</link>
      <guid>https://dev.to/anhtuank7c/single-resonsibility-principle-srp-jmc</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7C_1sRLv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://anhtuank7c.dev/assets/images/single-responsibility-principle-64adfeeada471c8768021e1d5d6f7763.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7C_1sRLv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://anhtuank7c.dev/assets/images/single-responsibility-principle-64adfeeada471c8768021e1d5d6f7763.webp" alt="single responsibility principle" width="800" height="437"&gt;&lt;/a&gt;&lt;br&gt;
Tiếp diễn chuỗi bài viết về &lt;a href="https://anhtuank7c.dev/blog/solid-principles"&gt;SOLID principle&lt;/a&gt;, bài này mình sẽ đi sâu vào &lt;strong&gt;Single Responsibility Principle (SRP)&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Single Responsibility Principle (SRP) là gì?
&lt;/h2&gt;

&lt;p&gt;SRP được dịch một cách ngắn gọn là &lt;strong&gt;nguyên tắc đơn nhiệm&lt;/strong&gt;. Mỗi class chỉ nên chịu trách nhiệm về một và chỉ một nhiệm vụ cụ thể.&lt;/p&gt;

&lt;p&gt;Nguyên tắc này được &lt;a href="https://en.wikipedia.org/wiki/Robert_C._Martin"&gt;Robert C. Martin&lt;/a&gt; giới thiệu năm 2003, ông còn hay được gọi với cái tên &lt;strong&gt;Uncle Bob&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Vì sao lại đơn nhiệm?&lt;/p&gt;

&lt;p&gt;Vì nó đơn giản, dễ hiểu và dễ nắm bắt, dễ dàng bảo trì và mở rộng, đồng thời dễ dàng trong việc viết unit test.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ví dụ
&lt;/h2&gt;

&lt;p&gt;Dưới dây là ví dụ về class vi phạm (violate) nguyên tắc đơn nhiệm (Single Responsibility Principle)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Violating SRP&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nf"&gt;checkout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;processPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;processShipping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;processPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;processing payment with paypal or momo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;processShipping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;processing shipping&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Class &lt;code&gt;OrderProcessor&lt;/code&gt; bên trên đang đảm nhiệm 03 nhiệm vụ (checkout, processPayment và processShipping), vậy class này đã vi phạm nguyên tắc đơn nhiệm.&lt;/p&gt;

&lt;p&gt;Chúng ta sẽ thiết kế lại class này tuân theo (adhere) nguyên tắc đơn nhiệm nhé&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Adhering SRP&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;processing payment with paypal or momo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShipppingProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;processing shipping&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PaymentProcessor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;shipping&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ShippingProcessor&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;checkout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shipping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mình tách nhiệm vụ process payment ra một class độc lập là &lt;code&gt;PaymentProcessor&lt;/code&gt;, làm tương tự với process shipping mình tạo ra class &lt;code&gt;ShipppingProcessor&lt;/code&gt;. Vậy là 02 class này đã tuân theo nguyên tắc đơn nhiệm.&lt;/p&gt;

&lt;p&gt;Tiếp theo đó, mình chỉ định class &lt;code&gt;OrderProcessor&lt;/code&gt; chỉ làm một nhiệm vụ duy nhất là &lt;code&gt;checkout&lt;/code&gt; , việc payment diễn ra như thế nào thì để cho &lt;code&gt;PaymentProcessor&lt;/code&gt; đảm nhiệm, với kết quả payment nhận được, mình sẽ tiếp tục cho class &lt;code&gt;ShippingProcessor&lt;/code&gt; đảm nhiệm việc ship hàng.&lt;/p&gt;

&lt;p&gt;Vậy class &lt;code&gt;OrderProcessor&lt;/code&gt; cũng đã tuân theo nguyên tắc đơn nhiệm rồi.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unit test
&lt;/h2&gt;

&lt;p&gt;Việc viết unit test bây giờ trở nên cực kỳ dễ dàng vì chúng ta đã phân tách ra 03 class, mỗi class đảm nhiệm một nhiệm vụ riêng biệt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// PaymentProcessor&lt;/span&gt;
&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;able to process payment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PaymentProcessor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ShipppingProcessor&lt;/span&gt;
&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;able to process shipping&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shipping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ShipppingProcessor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shipping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hanoi, Vietnam&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toThrow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// OrderProcessor&lt;/span&gt;
&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;able to checkout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PaymentProcessor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shipping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ShipppingProcessor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderProcesser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OrderProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;shipping&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orderProcesser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hanoi, Vietnam&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toThrow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Các bạn xem, chúng ta vừa có code tường minh, dễ nắm bắt, lại dễ dàng viết unit test.&lt;/p&gt;

&lt;p&gt;Nếu như bạn bị lỗi ở khâu payment, bạn biết ngay rằng mình sẽ cần tìm class Payment để kiểm tra mà không cần đọc code dài dòng khó hiểu nữa.&lt;/p&gt;

&lt;p&gt;Trong ví dụ trên mình sử dụng &lt;code&gt;jest&lt;/code&gt; để viết unit test, bạn có thể tìm thấy tài liệu tại đây: &lt;a href="https://jestjs.io/docs/getting-started"&gt;Getting Started · Jest (jestjs.io)&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Hỏi đáp
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Làm thế nào để đảm bảo code của bạn tuân theo nguyên tắc đơn nhiệm (Single Responsibility Principle)?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A: Để đảm bảo code tuân theo nguyên tắc đơn nhiệm, tôi thực hiện các bước sau:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Đảm bảo rằng mỗi class chỉ làm một nhiệm vụ duy nhất. Nếu có nhiều hơn một nhiệm vụ thì chứng tỏ cần phải phân tách ra nhỏ hơn nữa.&lt;/li&gt;
&lt;li&gt;Mỗi class chỉ có duy nhất một lý do để thay đổi.&lt;/li&gt;
&lt;li&gt;Mỗi class chỉ làm duy nhất một việc, và làm việc ấy thật tốt.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Kết luận
&lt;/h2&gt;

&lt;p&gt;Tuân theo nguyên tắc đơn nhiệm có nhiều lợi ích như: code đơn giản, dễ đọc, dễ nắm bắt, dễ viết unit test.&lt;/p&gt;

&lt;p&gt;Tuy nhiên đi kèm đó là việc số lượng file phát sinh ra cũng lớn.&lt;/p&gt;

&lt;p&gt;Nếu bạn cảm thấy bài này hữu ích thì hãy chia sẻ, lan tỏa tới cộng đồng nhé.&lt;/p&gt;

&lt;p&gt;Nếu bạn phát hiện sai sót, đừng ngần ngại báo lại cho mình qua các kênh mạng xã hội bên dưới website.&lt;/p&gt;

&lt;p&gt;Các bài viết tiếp nối chủ đề SOLID principles sẽ sớm được cập nhật.&lt;/p&gt;

&lt;p&gt;Chúc bạn ngày mới tốt lành.&lt;/p&gt;

&lt;p&gt;Bạn có thể đọc bài gốc &lt;a href="https://anhtuank7c.dev/blog/single-responsibility-principle"&gt;ở đây&lt;/a&gt;&lt;/p&gt;

</description>
      <category>solidprinciples</category>
      <category>singleresponsibility</category>
      <category>anhtuank7c</category>
    </item>
    <item>
      <title>SOLID principles là gì?</title>
      <dc:creator>Nguyễn Anh Tuấn</dc:creator>
      <pubDate>Tue, 12 Dec 2023 09:18:22 +0000</pubDate>
      <link>https://dev.to/anhtuank7c/solid-principles-la-gi-1cph</link>
      <guid>https://dev.to/anhtuank7c/solid-principles-la-gi-1cph</guid>
      <description>&lt;h2&gt;
  
  
  SOLID principles là gì?
&lt;/h2&gt;

&lt;p&gt;SOLID principles là một tập các nguyên tắc (principle) giúp tổ chức code theo cách dễ bảo trì, linh động và dễ dàng kiểm thử hơn.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SOLID là viết tắt chữ cái đầu tiên của các nguyên tắc sau&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S: &lt;a href="https://anhtuank7c.dev/blog/single-responsibility-principle"&gt;Single Responsibility Principle(SRP)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;O: &lt;a href="https://anhtuank7c.dev/blog/open-close-principle"&gt;Open Close Principle(OCP)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;L: Liskov Substitution Principle(LSP)&lt;/li&gt;
&lt;li&gt;I: Interface Segregation Principle(ISP)&lt;/li&gt;
&lt;li&gt;D: Dependency Inversion Principle(DIP)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Lưu ý: một vài thuật ngữ mình sẽ không dịch ra Tiếng Việt, hoặc dịch nhưng vẫn để từ khóa Tiếng Anh bên cạnh để tránh hiểu lầm hoặc sai ý nghĩa. Mong các bạn thông cảm.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Ưu và nhược điểm của SOLID principles?
&lt;/h2&gt;

&lt;p&gt;Mặc dù SOLID sinh ra là để tổ chức code tốt hơn, tuy nhiên điều đó không có nghĩa là bạn nên tuân theo trong mọi trường hợp, đặc biệt khi team của bạn không hiểu rõ về SOLID, project nhỏ hoặc gấp gáp về thời gian. &lt;/p&gt;

&lt;p&gt;Hãy đảm bảo rằng bạn thảo luận kỹ với team của mình để chỉ ra được những lợi ích mà SOLID thực sự mang lại trong project mà team sắp triển khai.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ưu điểm
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Dễ bảo trì (Maintainability): Code tuân theo SOLID principles dễ bảo trì và dễ thay đổi hơn do được tổ chức rõ ràng và tường minh&lt;/li&gt;
&lt;li&gt;Linh hoạt và thích ứng (Flexibility &amp;amp; Adaptability): SOLID code rất linh hoạt, việc thay đổi một phần của hệ thống ít có khả năng gây ra hậu quả ngoài ý muốn ở các phần khác của hệ thống.&lt;/li&gt;
&lt;li&gt;Kiểm thử dễ dàng (Testability): SOLID code thực sự dễ dàng để viết test case do được tổ chức phân tách mối lo ngại (separation of concerns) và phụ thuộc nghịch đảo (dependency inversion)&lt;/li&gt;
&lt;li&gt;Tái sử dụng code (Code reusability): Nguyên tắc đóng mở (Open Close Principle) khuyến khích tạo ra những class dễ dàng mở rộng nhưng lại không khuyến khích sửa đổi các lớp đó. Điều này tạo điều kiện (facititate) cho việc tái sử dụng code sẵn có khi mở rộng tính năng thay vì sửa đổi code cũ.&lt;/li&gt;
&lt;li&gt;Dễ đọc và dễ hiểu (Readability and understandability): SOLID principles thúc đẩy (promote) thiết kế rõ ràng (clear), trực quan (intuitive). Code được tổ chức theo cách phản ánh (reflects) quan hệ giữa các thành phần (components), điều này khiến lập trình viên dễ hiểu toàn bộ cấu trúc cũng như hành vi tổng thể của hệ thống.&lt;/li&gt;
&lt;li&gt;Giảm thiểu code trùng lặp (Reduce code duplication): Bằng cách tuân theo DRY principle (Don't Repeat Yourself), SOLID principles giúp giảm thiểu code trùng lặp, các function có thể được đóng gói trong các thành phần có thể chia sẻ (sharable components) , tái sử dụng và tránh dư thừa (redundancy) code.&lt;/li&gt;
&lt;li&gt;Phân tách mối lo ngại (Separation of concerns): SOLID principles phân tách rõ ràng các mối lo ngại (separation of concerns), đảm bảo rằng mỗi thành phần (components) có trách nhiệm riêng cụ thể (specific responsibility). Sự phân tách này giúp dễ dàng suy luận về các thành phần của hệ thống, đơn giản hóa (simplifies) việc gỡ lỗi (debugging) và bảo trì (maintenance)&lt;/li&gt;
&lt;li&gt;Dễ dàng hợp tác (Easier to collaboration): Một cấu trúc code được tổ chức tốt, tuân theo SOLID principles giúp các lập trình viên dễ dàng hợp tác, phối hợp với nhau. Thiết kế mô đun cho phép các nhóm hoặc các lập trình viên có thể làm việc trên những phần của hệ thống với sự can thiệp tối thiểu, không bị block chéo.&lt;/li&gt;
&lt;li&gt;Phụ thuộc nghịch đảo (Dependency inversions): Nguyên tắc phụ thuộc nghịch đảo (Dependency Inversion Principle) khuyến khích sử dụng các lớp trừu tượng và phụ thuộc trực tiếp (dependency injection) vốn giúp giảm thiểu sự liên kết giữa các thành phần (loosely coupled components). Điều này khiến cho việc thay thế (substitution), nâng cấp (upgrade) các gói phụ thuộc trở nên dễ dàng hơn mà không làm ảnh hưởng tới toàn bộ hệ thống.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bên cạnh hàng loạt những ưu điểm thì SOLID principles cũng bộc lộ những nhược điểm nhất định.  Không có nguyên tắc thiết kế nào hoàn hảo cho mọi hoàn cảnh, mọi project. Chính vì vậy mình luôn khuyên các bạn nên thận trọng và cân nhắc kỹ trước khi áp dụng.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nhược điểm
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Phức tạp hóa vấn đề thái quá (Over-engineering): Ứng dụng toàn bộ SOLID principles một cách nghiêm ngặt (rigorously) trong mọi trường hợp có thể dẫn tới việc phức tạp hóa vấn đề một cách thái quá trong những dự án đơn giản, những dự án nhỏ. Không phải dự án nào cũng nhận được lợi ích từ tất cả các nguyên tắc (principle), bạn cần phải cân bằng những nguyên tắc đó dựa trên quy mô và độ phức tạp của dự án.&lt;/li&gt;
&lt;li&gt;Tốn thời gian học tập (Learning curve): Với những lập trình viên chưa từng ứng dụng SOLID principles, họ cần phải bỏ thời gian ra để học thêm, điều này khiến cho chi phí thời gian tăng cao trong khi dự án cần phải đẩy tiến độ nhanh, đồng thời sẽ gặp khó trong việc ứng dụng SOLID principle triệt để và đúng cách, thậm chí nếu họ hiểu không sâu còn có thể ứng dụng sai cách.&lt;/li&gt;
&lt;li&gt;Gia tăng số lượng class và abstraction (Increase number of class and abstraction): Tuân theo SOLID principles thường dẫn tới việc tăng đáng kể số lượng các class, abstraction class/interface. Mặc dù SOLID giúp codebase trở nên dễ bảo trì hơn, nhưng lại gia tăng sự phức tạp với các dự án nhỏ.&lt;/li&gt;
&lt;li&gt;Tiềm tàng abstraction quá mức (Potential for abstraction overhead): Đưa ra quá nhiều lớp trừu tượng (abstraction class/interface) để tuân theo SOLID principle có thể gia tăng sự phức tạp. Nó có thể khiến code trở nên khó hiểu hơn, đặc biệt là với những lập trình viên không quen với những lớp trừu tượng (abstract class/interface) được sử dụng.&lt;/li&gt;
&lt;li&gt;Tốn thời gian khởi tạo hơn (Increase initial development time): Tuân theo SOLID principles một cách nghiêm ngặt có thể cần nhiều thời gian hơn trong quá trình khởi tạo dự án. Lập trình viên cần thiết kế những lớp trừu tượng (abstract class/interface) một cách cẩn thận, và cơ chế phụ thuộc trực tiếp. Điều này làm giảm đáng kể tốc độ phát triển dự án tại pha khởi tạo (initial phase).&lt;/li&gt;
&lt;li&gt;Quá lệ thuộc vào các gói phụ thuộc trực tiếp (Dependency Injection overhead): Việc sử dụng các gói phụ thuộc trực tiếp được khuyến khích theo nguyên tắc SOLID, tuy nhiên đôi khi việc dùng quá nhiều gói phụ thuộc trực tiếp lại làm cho lập trình viên khó cấu hình cũng như hiểu flow của các gói này. Trong vài trường hợp, một dự án đơn giản không hề nhận lại được lợi ích khi sử dụng kiểu phụ thuộc này.&lt;/li&gt;
&lt;li&gt;Thách thức trong việc ứng dụng vào dự án cũ (Challenging in legacy codebase): Ứng dụng SOLID principle vào dự án cũ là một thách thức lớn. Code cũ có thể không tuân theo SOLID một chút nào, và việc tái cấu trúc (refactoring) và tuân theo (adhere) tốn nhiều thời gian cũng như gây ra các lỗi tiềm tàng.&lt;/li&gt;
&lt;li&gt;Gia tăng thời gian nhận thức (Increase cognitive load): Với những lập trình viên có ít kinh nghiệm hoặc không có kinh nghiệm với SOLID principles thì họ cần thêm thời gian để hiểu các quy tắc (rules) và các hướng dẫn (guidelines). Điều này có thể dẫn tới việc hiểu sai (misunderstanding) hoặc vi phạm (violates) các nguyên tắc một cách vô ý (unintentional).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tổng kết
&lt;/h2&gt;

&lt;p&gt;Việc ứng dụng SOLID principles cần được thảo luận và cân nhắc kỹ càng về nguồn lực, sự hiểu biết cũng như quy mô và sự phức tạp của dự án.&lt;/p&gt;

&lt;p&gt;Nếu team của bạn triển khai dự án nhỏ, đơn giản và cần ít người thực hiện thì câu trả lời là bạn không nên áp dụng hoặc áp dụng một cách cơ bản, không quá nghiêm ngặt.&lt;/p&gt;

&lt;p&gt;Nếu bạn muốn triển khai SOLID, hãy đảm bảo rằng team của bạn triển khai đào tạo nội bộ và ứng dụng SOLID trong các dự án bên lề (side project) trước khi triển khai cho khách hàng. Điều này sẽ cứu bạn một bàn thua trông thấy.&lt;/p&gt;

&lt;p&gt;Chi tiết về 5 nguyên tắc SOLID sẽ được mình trình bày trong các bài viết tiếp theo do bài này đã quá dài rồi.&lt;/p&gt;

&lt;p&gt;Cảm ơn bạn đã quan tâm, theo dõi.&lt;/p&gt;

&lt;p&gt;Nếu bạn cảm thấy bài này giúp ích cho bạn, hãy chia sẻ, lan tỏa tới mọi người giúp mình nhé.&lt;/p&gt;

&lt;p&gt;Trân trọng,&lt;/p&gt;

&lt;p&gt;Đọc bài gốc &lt;a href="https://anhtuank7c.dev/blog/solid-principles"&gt;tại đây&lt;/a&gt;&lt;/p&gt;

</description>
      <category>solidprinciples</category>
      <category>anhtuank7c</category>
    </item>
    <item>
      <title>Xin chào</title>
      <dc:creator>Nguyễn Anh Tuấn</dc:creator>
      <pubDate>Tue, 12 Dec 2023 09:17:38 +0000</pubDate>
      <link>https://dev.to/anhtuank7c/xin-chao-30ej</link>
      <guid>https://dev.to/anhtuank7c/xin-chao-30ej</guid>
      <description>&lt;h2&gt;
  
  
  &lt;a href="https://anhtuank7c.dev/blog/welcome#gi%E1%BB%9Bi-thi%E1%BB%87u"&gt;Giới thiệu​&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Cảm ơn bạn đã ghé thăm blog công nghệ của mình.&lt;/p&gt;

&lt;p&gt;Mình xin giới thiệu, mình là Nguyễn Anh Tuấn. Một kỹ sư phần mềm tràn đầy nhiệt huyết có sự quan tâm sâu sắc về các nguyên tắc thiết kế phần mềm, các ngôn ngữ lập trình &lt;code&gt;TypeScript&lt;/code&gt; &lt;code&gt;Javascript&lt;/code&gt; &lt;code&gt;Kotlin&lt;/code&gt; &lt;code&gt;Swift&lt;/code&gt; và các framework &lt;code&gt;ReactJS&lt;/code&gt; &lt;code&gt;React Native&lt;/code&gt; &lt;code&gt;Expo&lt;/code&gt; &lt;code&gt;Svelte&lt;/code&gt; &lt;code&gt;SvelteKit&lt;/code&gt; &lt;code&gt;Elysia&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Tuấn phát triển app di động với &lt;code&gt;React Native&lt;/code&gt; &lt;code&gt;Expo&lt;/code&gt; bên cạnh phát triển web app với &lt;code&gt;ReactJS&lt;/code&gt; &lt;code&gt;SvelteKit&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Không ai là hoàn hảo và chính bản thân mình cũng vậy. Tuấn luôn luôn làm mới bản thân, cập nhật kiến thức mới cũng như rèn luyện và thực hành thật nhiều để hiểu sâu hơn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dấu ấn&lt;a href="https://anhtuank7c.dev/blog/welcome#d%E1%BA%A5u-%E1%BA%A5n"&gt;​&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Dự án đáng ghi nhớ trong sự nghiệp của mình là app &lt;a href="https://equilab.horse/"&gt;Equilab&lt;/a&gt;, mình theo dự án hơn 5 năm cho tới tháng 03 năm 2023. Đây là một hành trình đầy màu sắc và đáng quý. Mình được làm chung với đồng nghiệp từ Thụy Điển, Pháp, Đức và Mỹ. Sản phẩm chuyên biệt dành cho việc huấn luyện ngựa từ 15 nghìn users và đạt 1 triệu 500 nghìn users vào cuối 2022.&lt;/p&gt;

&lt;p&gt;Mình đảm nhiệm vị trí React Native Leader, giúp phát triển các tính năng như Training Calendar, Social Feed, Stable Chat, Challenges và nhiều đóng góp vào native iOS/Android project. Tại đây mình còn phát triển cả backend nữa nhé.&lt;/p&gt;

&lt;p&gt;Bên cạnh đó, với vai trò là quản trị viên dẫn dắt cộng đồng &lt;a href="https://www.facebook.com/groups/reactnativevietnam"&gt;React Native Vietnam trên Facebook&lt;/a&gt; với hơn 31 nghìn thành viên, mình luôn chia sẻ mẹo, kinh nghiệm làm việc với React Native, Swift, Kotlin đồng thời giúp các member gỡ lỗi cũng như giới thiệu các công nghệ mới.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lời kết&lt;a href="https://anhtuank7c.dev/blog/welcome#l%E1%BB%9Di-k%E1%BA%BFt"&gt;​&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Gần đây Tuấn quyết định mở kênh &lt;a href="https://www.youtube.com/@anhtuank7c"&gt;Youtube&lt;/a&gt;, &lt;a href="https://www.tiktok.com/@anhtuank7c"&gt;Tiktok&lt;/a&gt; và viết Blog tại địa chỉ &lt;a href="https://anhtuank7c.dev/"&gt;anhtuank7c.dev&lt;/a&gt; với mục tiêu lưu lại những kiến thức mình mình lĩnh hội được, cũng như chia sẻ chúng với cộng đồng lập trình viên Việt Nam.&lt;/p&gt;

&lt;p&gt;Nếu bạn có bất kỳ dự án mobile app, web app cần triển khai, đừng ngần ngại liên hệ với mình tại địa chỉ email: &lt;a href="//mailto:anhtuank7c@hotmail.com"&gt;anhtuank7c@hotmail.com&lt;/a&gt; nhé.&lt;/p&gt;

&lt;p&gt;Tuấn rất mong nhận được sự hỗ trợ về nội dung cũng như về các dự án, công việc từ các bạn, các quý công ty.&lt;/p&gt;

&lt;p&gt;Một lần nữa cảm ơn bạn đã ghé thăm.&lt;/p&gt;

&lt;p&gt;Chúc bạn ngày mới tốt lành và gặt hái nhiều thành công.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tuấn Nguyễn&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>anhtuank7c</category>
      <category>hello</category>
      <category>xinchao</category>
    </item>
  </channel>
</rss>
