<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Software-Design on Thanh HV's Blog</title><link>https://thanhhv.github.io/tags/software-design/</link><description>Recent content in Software-Design on Thanh HV's Blog</description><generator>Hugo -- 0.146.7</generator><language>en-us</language><lastBuildDate>Fri, 17 Jul 2026 13:00:00 +0700</lastBuildDate><atom:link href="https://thanhhv.github.io/tags/software-design/index.xml" rel="self" type="application/rss+xml"/><item><title>5.4 — Tổng kết: toàn bộ tài liệu trên một trang, và con đường tiếp theo</title><link>https://thanhhv.github.io/series/software-design/level-5-architecture/04-tong-ket/</link><pubDate>Fri, 17 Jul 2026 13:00:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-5-architecture/04-tong-ket/</guid><description>&lt;h2 id="1-một-sợi-chỉ-xuyên-suốt">1. Một sợi chỉ xuyên suốt&lt;/h2>
&lt;p>Ba mươi ba chương quy về &lt;strong>một hàm mục tiêu duy nhất&lt;/strong>, phát biểu từ chương 1.1 và chưa từng đổi:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Tối thiểu hóa tổng chi phí thay đổi (hiểu + lan truyền + kiểm chứng + phối hợp), chiết khấu theo xác suất thay đổi đó xảy ra — với chi phí hiện tại chấp nhận được.&lt;/strong>&lt;/p>&lt;/blockquote>
&lt;p>Mọi thứ còn lại là công cụ phục vụ hàm đó, xếp thành bốn tầng:&lt;/p></description></item><item><title>5.3 — Production Case Studies: đọc pattern trong code thật đang chạy</title><link>https://thanhhv.github.io/series/software-design/level-5-architecture/03-case-studies/</link><pubDate>Fri, 17 Jul 2026 12:50:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-5-architecture/03-case-studies/</guid><description>&lt;p>Chương này là bài tập tổng hợp của toàn bộ tài liệu: soi các hệ thống lớn — mỗi hệ vài đoạn, theo cùng khung ba câu hỏi: &lt;strong>họ chọn pattern gì, vì sao (đánh đổi cái gì), và nếu chọn khác thì hệ quả ra sao&lt;/strong>. Nhiều case đã được nhắc rải rác ở các chương trước — ở đây gom lại thành chân dung trọn vẹn.&lt;/p>
&lt;hr>
&lt;h2 id="a-go-standard-library--bậc-thầy-của-interface-nhỏ">A. Go Standard Library — bậc thầy của interface nhỏ&lt;/h2>
&lt;h3 id="ioreader--iowriter">&lt;code>io.Reader&lt;/code> / &lt;code>io.Writer&lt;/code>&lt;/h3>
&lt;p>&lt;strong>Chọn gì&lt;/strong>: interface 1 method (ISP 2.4 cực hạn), hợp đồng ngữ nghĩa viết kỹ từng trường hợp biên (LSP 2.3), composition chồng vô hạn (Decorator 4.5: &lt;code>bufio&lt;/code> bọc &lt;code>gzip&lt;/code> bọc &lt;code>net.Conn&lt;/code>).
&lt;strong>Vì sao&lt;/strong>: số implementation là &lt;em>vô hạn và không biết trước&lt;/em> — hợp đồng phải tối thiểu để dễ thỏa mãn nhất có thể; đổi lại caller chịu khó (loop đọc cẩn thận) và stdlib bù bằng helper (&lt;code>io.ReadAll&lt;/code>, &lt;code>io.Copy&lt;/code> — kèm tối ưu sniff optional interface &lt;code>WriterTo/ReaderFrom&lt;/code>, kỹ thuật 2.4 bước 3).
&lt;strong>Nếu chọn khác&lt;/strong>: interface &amp;ldquo;tiện caller&amp;rdquo; kiểu &lt;code>ReadAll() []byte&lt;/code> → mất streaming (buộc load hết vào RAM), mất composition — cả hệ sinh thái streaming của Go không tồn tại. Một quyết định 1 method, hệ quả 15 năm.&lt;/p></description></item><item><title>5.2 — Event-driven Architecture &amp; CQRS: khi nào đáng trả giá cho bất đồng bộ</title><link>https://thanhhv.github.io/series/software-design/level-5-architecture/02-event-driven-cqrs/</link><pubDate>Fri, 17 Jul 2026 12:40:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-5-architecture/02-event-driven-cqrs/</guid><description>&lt;h2 id="1-event-driven-architecture--observer-48-phóng-to-hết-cỡ">1. Event-driven Architecture — Observer (4.8) phóng to hết cỡ&lt;/h2>
&lt;h3 id="con-đường-leo-thang--và-trạm-dừng-ở-mỗi-bậc">Con đường leo thang — và trạm dừng ở mỗi bậc&lt;/h3>
&lt;p>Toàn bộ nền đã xây: event là dữ liệu bất biến quá khứ (4.8), domain events sinh trong transaction (4.13), outbox đưa event rời process an toàn (4.13), consumer idempotent (4.9). Event-driven &lt;strong>architecture&lt;/strong> là quyết định dùng chuỗi đó làm &lt;strong>xương sống liên lạc giữa các bounded context&lt;/strong> (5.0): context phát sự kiện về điều đã xảy ra trong nó; context khác phản ứng — không ai gọi trực tiếp ai.&lt;/p></description></item><item><title>5.1 — Clean &amp; Hexagonal Architecture: một ý tưởng, nhiều tên gọi</title><link>https://thanhhv.github.io/series/software-design/level-5-architecture/01-clean-hexagonal/</link><pubDate>Fri, 17 Jul 2026 12:30:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-5-architecture/01-clean-hexagonal/</guid><description>&lt;h2 id="1-gỡ-rối-tên-gọi-trước--vì-chúng-là-một-ý-tưởng">1. Gỡ rối tên gọi trước — vì chúng là MỘT ý tưởng&lt;/h2>
&lt;p>Hexagonal/Ports &amp;amp; Adapters (Cockburn 2005), Onion (Palermo 2008), Clean Architecture (Martin 2012) — ba &amp;ldquo;trường phái&amp;rdquo; mà thực chất là &lt;strong>ba bản vẽ của cùng một nguyên tắc&lt;/strong>, nguyên tắc mà bạn đã học trọn ở chương 2.5:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Nghiệp vụ ở trung tâm, không biết gì về thế giới ngoài. Mọi mũi tên phụ thuộc trỏ VÀO trong. Thế giới ngoài (DB, HTTP, queue, UI) nói chuyện với trung tâm qua các cổng (interface) do TRUNG TÂM định nghĩa.&lt;/strong>&lt;/p></description></item><item><title>5.0 — Domain-Driven Design: thiết kế theo nghiệp vụ, không theo công nghệ</title><link>https://thanhhv.github.io/series/software-design/level-5-architecture/00-ddd/</link><pubDate>Fri, 17 Jul 2026 12:20:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-5-architecture/00-ddd/</guid><description>&lt;h2 id="1-problem-statement--căn-bệnh-mà-ddd-sinh-ra-để-chữa">1. Problem Statement — căn bệnh mà DDD sinh ra để chữa&lt;/h2>
&lt;p>Level 1–4 làm việc ở quy mô hàm, struct, package. Level 5 hỏi câu hỏi quy mô hệ thống — và bắt đầu bằng căn bệnh phổ biến nhất của hệ thống lớn, một căn bệnh &lt;strong>không phải về code&lt;/strong>:&lt;/p>
&lt;blockquote>
&lt;p>Team kỹ thuật và team nghiệp vụ nói hai ngôn ngữ khác nhau về cùng một thứ.&lt;/p>&lt;/blockquote>
&lt;p>Triệu chứng cụ thể, quen thuộc đến đau lòng: PM nói &amp;ldquo;khách hàng&amp;rdquo;, codebase có &lt;code>User&lt;/code>, &lt;code>Account&lt;/code>, &lt;code>Customer&lt;/code>, &lt;code>Client&lt;/code>, &lt;code>Member&lt;/code> — năm tên cho không-rõ-mấy khái niệm; bảng &lt;code>orders&lt;/code> có cột &lt;code>status&lt;/code> 14 giá trị trong đó 5 giá trị &amp;ldquo;không còn dùng nhưng không ai dám xóa&amp;rdquo;; tính năng mới cần ba cuộc họp để thống nhất &amp;ldquo;ý anh nói &lt;em>đơn hủy&lt;/em> là hủy kiểu nào?&amp;rdquo;; và bug nghiệp vụ sinh ra không phải vì code sai thuật toán, mà vì &lt;strong>dev hiểu sai luật chơi của domain&lt;/strong>.&lt;/p></description></item><item><title>4.13 — Pipeline, Plugin, Domain Events, Saga &amp; Outbox — và bản đồ tổng kết Level 4</title><link>https://thanhhv.github.io/series/software-design/level-4-patterns/13-pipeline-plugin-events-saga-outbox/</link><pubDate>Fri, 17 Jul 2026 12:10:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-4-patterns/13-pipeline-plugin-events-saga-outbox/</guid><description>&lt;p>Chương khép Level 4: hai idiom kiến trúc nhỏ (Pipeline, Plugin — phần lớn đã xây ở các chương trước, giờ chốt sổ), rồi bộ ba pattern của &lt;strong>thế giới phân tán&lt;/strong> (Domain Events → Saga → Outbox — ba nấc của cùng một câu chuyện), và bảng phân loại cuối cùng: đâu là GoF, đâu là Enterprise, đâu là idiom Go.&lt;/p>
&lt;hr>
&lt;h2 id="a-pipeline--chốt-sổ">A. Pipeline — chốt sổ&lt;/h2>
&lt;p>Đã xây ở 3.4 (Replace Loop with Strategy → tách khung khỏi rule) và 4.5 (middleware = pipeline của handler). Định nghĩa chốt: &lt;strong>chuỗi giai đoạn xử lý, output giai đoạn này là input giai đoạn sau, mỗi giai đoạn không biết gì về nhau ngoài hợp đồng dữ liệu&lt;/strong>. Ba hình dạng trong Go, chọn theo tải:&lt;/p></description></item><item><title>4.12 — Repository, Unit of Work &amp; Specification: bộ ba Enterprise Pattern quanh dữ liệu</title><link>https://thanhhv.github.io/series/software-design/level-4-patterns/12-repository-uow-specification/</link><pubDate>Fri, 17 Jul 2026 12:00:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-4-patterns/12-repository-uow-specification/</guid><description>&lt;p>Ba pattern từ danh mục &lt;strong>Enterprise&lt;/strong> (Fowler, &lt;em>Patterns of Enterprise Application Architecture&lt;/em>, 2002 — không phải GoF): sinh ra cho bài toán mà GoF chưa chạm tới — &lt;strong>ranh giới giữa mô hình nghiệp vụ trong RAM và cơ sở dữ liệu&lt;/strong>. Cũng là bộ ba bị cargo-cult nhiều bậc nhất trong thế giới backend; chương này dựng chúng từ bài toán thật và vạch rõ ngưỡng lạm dụng.&lt;/p>
&lt;hr>
&lt;h2 id="a-repository">A. Repository&lt;/h2>
&lt;h3 id="1-bài-toán--đã-gặp-giờ-gọi-đúng-tên">1. Bài toán — đã gặp, giờ gọi đúng tên&lt;/h3>
&lt;p>Toàn bộ Level 2 đã xây nó từng viên gạch: &lt;code>ProductSource&lt;/code> của pricing (2.5), &lt;code>FileStore&lt;/code> với contract test (2.3), &lt;code>UserGetter&lt;/code> phía consumer (2.4). &lt;strong>Repository = tổng hợp các viên gạch đó thành pattern có tên&lt;/strong>: một interface &lt;em>nói ngôn ngữ domain&lt;/em> đứng giữa nghiệp vụ và persistence, cho nghiệp vụ ảo tưởng có kiểm soát rằng aggregate nằm trong một &lt;strong>collection trong RAM&lt;/strong>:&lt;/p></description></item><item><title>4.11 — Dependency Injection &amp; DI Container: từ nguyên tắc đến công cụ, và ranh giới giữa hai thứ</title><link>https://thanhhv.github.io/series/software-design/level-4-patterns/11-dependency-injection/</link><pubDate>Fri, 17 Jul 2026 11:50:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-4-patterns/11-dependency-injection/</guid><description>&lt;h2 id="1-đặt-lại-nền--ba-khái-niệm-hay-bị-trộn-làm-một">1. Đặt lại nền — ba khái niệm hay bị trộn làm một&lt;/h2>
&lt;p>Chương 2.5 đã cắm mốc, giờ dựng thành khung hoàn chỉnh vì toàn bộ chương này đứng trên đó:&lt;/p>
&lt;pre tabindex="0">&lt;code>DIP (nguyên tắc) : chiều mũi tên — nghiệp vụ định nghĩa interface, hạ tầng implement
DI (kỹ thuật) : cách trao dependency — tạo ở ngoài, đưa vào qua constructor/tham số
DI Container (công cụ): máy tự động hóa việc trao — tự phân giải graph, tự gọi constructor
&lt;/code>&lt;/pre>&lt;p>Ba tầng độc lập: dùng container cả ngày vẫn vi phạm DIP được (inject thẳng concrete hạ tầng vào domain); tuân DIP hoàn hảo không cần container nào (wiring tay ở &lt;code>main&lt;/code>). Chương này trả lời câu hỏi thực dụng còn nợ: &lt;strong>khi nào kỹ thuật cần leo lên công cụ — và cái giá của cú leo đó.&lt;/strong>&lt;/p></description></item><item><title>4.10 — Template Method, Visitor, Iterator &amp; Memento: bốn số phận thời hậu GoF</title><link>https://thanhhv.github.io/series/software-design/level-4-patterns/10-template-visitor-iterator-memento/</link><pubDate>Fri, 17 Jul 2026 11:40:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-4-patterns/10-template-visitor-iterator-memento/</guid><description>&lt;p>Bốn pattern behavioral còn lại, điểm chung: &lt;strong>ngôn ngữ hiện đại đã thay đổi số phận của chúng mạnh nhất&lt;/strong> — hai cái tan gần hết vào ngôn ngữ (Template Method, Iterator), một cái thu hẹp về ngách chuyên môn (Visitor), một cái sống dưới các tên khác (Memento). Chương này ngắn có chủ đích, ưu tiên &amp;ldquo;nhận ra và chọn đúng thay thế&amp;rdquo; hơn là &amp;ldquo;cài đặt nguyên bản&amp;rdquo;.&lt;/p></description></item><item><title>4.9 — Command, Chain of Responsibility &amp; Mediator</title><link>https://thanhhv.github.io/series/software-design/level-4-patterns/09-command-chain-mediator/</link><pubDate>Fri, 17 Jul 2026 11:30:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-4-patterns/09-command-chain-mediator/</guid><description>&lt;p>Ba pattern behavioral về &lt;strong>tổ chức lời gọi&lt;/strong>: Command biến lời gọi thành &lt;em>dữ liệu&lt;/em>; Chain of Responsibility cho lời gọi &lt;em>chạy qua một hàng người xử lý&lt;/em>; Mediator gom các lời gọi chéo nhau về &lt;em>một trung tâm điều phối&lt;/em>.&lt;/p>
&lt;hr>
&lt;h2 id="phần-a--command">Phần A — Command&lt;/h2>
&lt;h3 id="1-bài-toán--khi-lời-gọi-hàm-cần-được-cầm-nắm">1. Bài toán — khi lời gọi hàm cần được cầm nắm&lt;/h3>
&lt;p>Lời gọi hàm thường: xảy ra ngay, không lưu được, không xếp hàng được, không hoàn tác được, không gửi đi xa được. Một loạt nhu cầu thực tế đòi hỏi ngược lại:&lt;/p></description></item><item><title>4.8 — Observer &amp; pub/sub: tách người gây chuyện khỏi người quan tâm</title><link>https://thanhhv.github.io/series/software-design/level-4-patterns/08-observer-pubsub/</link><pubDate>Fri, 17 Jul 2026 11:20:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-4-patterns/08-observer-pubsub/</guid><description>&lt;h2 id="1-problem-statement--code-evolution">1. Problem Statement — code evolution&lt;/h2>
&lt;p>Quay lại &lt;code>ConfirmOrder&lt;/code> (1.2). Khi đó ta tách &lt;code>Notifier&lt;/code> ra sau interface — nhưng service vẫn &lt;em>gọi&lt;/em> notifier. Giờ nghiệp vụ phình theo hướng khác: sau khi xác nhận đơn, cần &lt;strong>thêm nhiều việc ăn theo&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// ❌ V1 — use case chính trở thành danh bạ của mọi bên quan tâm&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> (&lt;span style="color:#a6e22e">s&lt;/span> &lt;span style="color:#f92672">*&lt;/span>&lt;span style="color:#a6e22e">Service&lt;/span>) &lt;span style="color:#a6e22e">ConfirmOrder&lt;/span>(&lt;span style="color:#a6e22e">ctx&lt;/span> &lt;span style="color:#a6e22e">context&lt;/span>.&lt;span style="color:#a6e22e">Context&lt;/span>, &lt;span style="color:#a6e22e">orderID&lt;/span> &lt;span style="color:#66d9ef">string&lt;/span>) &lt;span style="color:#66d9ef">error&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">/* ... load, confirm, save — NGHIỆP VỤ LÕI, 10 dòng ... */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// và cái đuôi mọc dài mãi:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">s&lt;/span>.&lt;span style="color:#a6e22e">notifier&lt;/span>.&lt;span style="color:#a6e22e">OrderConfirmed&lt;/span>(&lt;span style="color:#a6e22e">ctx&lt;/span>, &lt;span style="color:#a6e22e">o&lt;/span>) &lt;span style="color:#75715e">// gửi mail&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">s&lt;/span>.&lt;span style="color:#a6e22e">loyalty&lt;/span>.&lt;span style="color:#a6e22e">AddPoints&lt;/span>(&lt;span style="color:#a6e22e">ctx&lt;/span>, &lt;span style="color:#a6e22e">o&lt;/span>.&lt;span style="color:#a6e22e">CustomerID&lt;/span>, &lt;span style="color:#a6e22e">o&lt;/span>.&lt;span style="color:#a6e22e">Total&lt;/span>()) &lt;span style="color:#75715e">// cộng điểm&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">s&lt;/span>.&lt;span style="color:#a6e22e">analytics&lt;/span>.&lt;span style="color:#a6e22e">Track&lt;/span>(&lt;span style="color:#a6e22e">ctx&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;order_confirmed&amp;#34;&lt;/span>, &lt;span style="color:#a6e22e">o&lt;/span>) &lt;span style="color:#75715e">// sự kiện analytics&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">s&lt;/span>.&lt;span style="color:#a6e22e">recommender&lt;/span>.&lt;span style="color:#a6e22e">InvalidateCache&lt;/span>(&lt;span style="color:#a6e22e">ctx&lt;/span>, &lt;span style="color:#a6e22e">o&lt;/span>.&lt;span style="color:#a6e22e">CustomerID&lt;/span>) &lt;span style="color:#75715e">// xóa cache gợi ý&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">s&lt;/span>.&lt;span style="color:#a6e22e">fraud&lt;/span>.&lt;span style="color:#a6e22e">ReportSignal&lt;/span>(&lt;span style="color:#a6e22e">ctx&lt;/span>, &lt;span style="color:#a6e22e">o&lt;/span>) &lt;span style="color:#75715e">// tín hiệu chống gian lận&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Quan sát bệnh sinh: mỗi bên quan tâm mới (team Loyalty, team Analytics&amp;hellip;) = &lt;strong>mở use case lõi ra sửa&lt;/strong> + thêm một dependency vào struct — trong khi nghiệp vụ &amp;ldquo;xác nhận đơn&amp;rdquo; không hề đổi. Mũi tên phụ thuộc trỏ &lt;strong>sai chiều&lt;/strong>: module quan trọng nhất (order) phải biết mọi module ăn theo (analytics, recommender — những thứ đổi xoành xoạch). Vi phạm OCP theo trục &amp;ldquo;bên quan tâm&amp;rdquo;, vi phạm DIP về chiều ổn định. Và câu hỏi khó chịu bắt đầu xuất hiện: &lt;em>lỗi cộng điểm có nên làm hỏng việc xác nhận đơn không?&lt;/em> — trong V1, có, dù chẳng ai chủ đích quyết như vậy.&lt;/p></description></item><item><title>4.7 — Strategy &amp; State: hai anh em cùng cấu trúc, khác linh hồn</title><link>https://thanhhv.github.io/series/software-design/level-4-patterns/07-strategy-state/</link><pubDate>Fri, 17 Jul 2026 11:10:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-4-patterns/07-strategy-state/</guid><description>&lt;h2 id="1-strategy--pattern-bạn-đã-dùng-suốt-từ-đầu-tài-liệu">1. Strategy — pattern bạn đã dùng suốt từ đầu tài liệu&lt;/h2>
&lt;p>Không cần dựng lại code evolution — bạn đã đi trọn con đường của nó ba lần: rule tính phí ship thành &lt;code>[]FeeRule&lt;/code> (1.1 → 1.4), gateway thanh toán thành interface + registry (2.2), rule hoa hồng thành &lt;code>[]RateRule&lt;/code> (3.4). Chỉ cần chính danh hóa:&lt;/p>
&lt;p>&lt;strong>Intent (GoF)&lt;/strong>: đóng gói một &lt;em>họ thuật toán&lt;/em> thay thế được cho nhau, để thuật toán biến thiên độc lập với client dùng nó. &lt;strong>Cấu trúc GoF&lt;/strong>: interface &lt;code>Strategy&lt;/code> + N concrete class + context giữ tham chiếu strategy.&lt;/p></description></item><item><title>4.6 — Composite, Bridge &amp; Flyweight: ba pattern cấu trúc còn lại</title><link>https://thanhhv.github.io/series/software-design/level-4-patterns/06-composite-bridge-flyweight/</link><pubDate>Fri, 17 Jul 2026 11:00:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-4-patterns/06-composite-bridge-flyweight/</guid><description>&lt;p>Ba pattern khép lại nhóm Structural, mỗi cái một số phận khác nhau trong backend hiện đại: Composite sống khỏe ở một ngách rõ ràng (cấu trúc cây); Bridge là &lt;em>ý tưởng&lt;/em> quan trọng hơn &lt;em>hình thức&lt;/em>; Flyweight chủ yếu đã chuyển hộ khẩu xuống tầng runtime và thư viện.&lt;/p>
&lt;hr>
&lt;h2 id="phần-a--composite">Phần A — Composite&lt;/h2>
&lt;h3 id="1-bài-toán--khi-phần-tử-và-nhóm-phần-tử-phải-cư-xử-như-nhau">1. Bài toán — khi phần tử và nhóm phần tử phải cư xử như nhau&lt;/h3>
&lt;p>Bài toán thật: hệ thống phân quyền theo nhóm. Ban đầu chỉ có user:&lt;/p></description></item><item><title>4.5 — Decorator &amp; Proxy — và Middleware, đứa con lớn nhất của chúng</title><link>https://thanhhv.github.io/series/software-design/level-4-patterns/05-decorator-proxy/</link><pubDate>Fri, 17 Jul 2026 10:50:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-4-patterns/05-decorator-proxy/</guid><description>&lt;h2 id="1-vị-trí-xuất-phát">1. Vị trí xuất phát&lt;/h2>
&lt;p>Decorator không cần giới thiệu dài: chương 1.4 đã &lt;em>phát minh lại&lt;/em> nó khi tháo cây kế thừa Notifier — retry/rate-limit/logging thành các wrapper cùng interface, tổ hợp tự do. Chương này làm ba việc: gọi tên chính thức và nêu đủ cấu trúc; phân định với người anh em song sinh Proxy; và mổ &lt;strong>Middleware&lt;/strong> — hình thái Decorator quan trọng nhất của backend hiện đại, kèm những bài học production mà bản đồ chơi ở 1.4 chưa chạm tới.&lt;/p></description></item><item><title>4.4 — Adapter &amp; Facade: hai cách thuần hóa code không phải của mình</title><link>https://thanhhv.github.io/series/software-design/level-4-patterns/04-adapter-facade/</link><pubDate>Fri, 17 Jul 2026 10:40:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-4-patterns/04-adapter-facade/</guid><description>&lt;p>Mở màn nhóm Structural bằng cặp pattern hay bị dùng lẫn tên nhất. Cả hai đều đứng &lt;strong>ở ranh giới giữa code của bạn và code không phải của bạn&lt;/strong> (thư viện, hệ legacy, service ngoài) — nhưng giải hai bài toán khác hẳn: Adapter đổi &lt;strong>hình dạng&lt;/strong> một interface cho khớp ổ cắm có sẵn; Facade &lt;strong>thu nhỏ&lt;/strong> cả một mê cung thành vài cánh cửa.&lt;/p>
&lt;hr>
&lt;h2 id="phần-a--adapter">Phần A — Adapter&lt;/h2>
&lt;h3 id="1-problem-statement--code-evolution">1. Problem Statement — code evolution&lt;/h3>
&lt;p>Hệ thống notification của bạn (từ chương 1.4) đã chuẩn hóa quanh interface:&lt;/p></description></item><item><title>4.3 — Singleton &amp; Prototype: hai pattern thu hẹp đất sống</title><link>https://thanhhv.github.io/series/software-design/level-4-patterns/03-singleton-prototype/</link><pubDate>Fri, 17 Jul 2026 10:30:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-4-patterns/03-singleton-prototype/</guid><description>&lt;p>Hai pattern Creational còn lại thuộc nhóm số phận thứ ba của bản đồ 4.0: bài toán gốc của chúng hoặc đã có lời giải rẻ hơn, hoặc hiếm hơn xưa nhiều. Chương này ngắn hơn các chương khác &lt;strong>một cách chủ đích&lt;/strong> — độ dài tỉ lệ với tần suất bạn nên dùng chúng.&lt;/p>
&lt;hr>
&lt;h2 id="phần-a--singleton">Phần A — Singleton&lt;/h2>
&lt;h3 id="1-bài-toán-gốc--và-cú-trượt-dài-nửa-thế-kỷ">1. Bài toán gốc — và cú trượt dài nửa thế kỷ&lt;/h3>
&lt;p>Bài toán chính đáng: một tài nguyên &lt;strong>về bản chất chỉ nên tồn tại một&lt;/strong> trong process — connection pool, logger gốc, registry metric, config đã load. Tạo nhiều bản là lãng phí (N connection pool) hoặc sai (hai registry metric đếm lệch nhau).&lt;/p></description></item><item><title>4.2 — Builder &amp; Functional Options: khởi tạo phức tạp mà không phát điên</title><link>https://thanhhv.github.io/series/software-design/level-4-patterns/02-builder-functional-options/</link><pubDate>Fri, 17 Jul 2026 10:20:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-4-patterns/02-builder-functional-options/</guid><description>&lt;h2 id="1-problem-statement">1. Problem Statement&lt;/h2>
&lt;p>Factory (4.1) giải bài toán &lt;em>chọn loại nào&lt;/em>. Chương này giải bài toán trực giao: &lt;strong>một loại duy nhất nhưng khởi tạo phức tạp&lt;/strong> — nhiều tham số, đa số tùy chọn, có ràng buộc chéo giữa các tham số, có giá trị mặc định thông minh. Nạn nhân điển hình: HTTP client, server, DB connection, message consumer — thứ nào cũng 15+ nút vặn.&lt;/p>
&lt;h2 id="2-code-evolution--con-đường-đau-khổ-quen-thuộc">2. Code Evolution — con đường đau khổ quen thuộc&lt;/h2>
&lt;p>&lt;strong>V1 — constructor phình dần&lt;/strong> (Massive Constructor, đã điểm mặt trong danh sách anti-pattern từ đầu tài liệu):&lt;/p></description></item><item><title>4.1 — Factory Method &amp; Abstract Factory: kiểm soát điểm tạo object</title><link>https://thanhhv.github.io/series/software-design/level-4-patterns/01-factory/</link><pubDate>Fri, 17 Jul 2026 10:10:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-4-patterns/01-factory/</guid><description>&lt;h2 id="1-problem-statement">1. Problem Statement&lt;/h2>
&lt;p>Xâu chuỗi những gì đã có: chương 2.2 (OCP) đưa các phương thức thanh toán về interface &lt;code>Gateway&lt;/code> + registry; chương 3.4 kết thúc Replace Conditional with Polymorphism bằng câu: &lt;em>&amp;ldquo;nơi tạo object từ string trở thành điểm switch duy nhất còn lại — và nó có tên: Factory&amp;rdquo;&lt;/em>. Chương này trả lời nốt: điểm tạo object đó thiết kế thế nào cho tử tế — vì &lt;strong>&lt;code>new&lt;/code> (hay &lt;code>&amp;amp;Struct{}&lt;/code>) chính là dạng coupling cứng nhất&lt;/strong>: nơi nào gọi &lt;code>&amp;amp;MomoGateway{...}&lt;/code> là nơi đó dính chặt vào concrete type, biết cấu trúc field, chịu trách nhiệm truyền config.&lt;/p></description></item><item><title>4.0 — Design Patterns: cách đọc GoF bằng con mắt 2026</title><link>https://thanhhv.github.io/series/software-design/level-4-patterns/00-tong-quan-patterns/</link><pubDate>Fri, 17 Jul 2026 10:00:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-4-patterns/00-tong-quan-patterns/</guid><description>&lt;h2 id="1-pattern-là-gì--và-cuốn-sách-gof-thực-ra-nói-gì">1. Pattern là gì — và cuốn sách GoF thực ra nói gì&lt;/h2>
&lt;p>Năm 1994, bốn tác giả (Gang of Four) xuất bản &lt;em>Design Patterns: Elements of Reusable Object-Oriented Software&lt;/em> — danh mục 23 cấu trúc lặp đi lặp lại mà họ quan sát thấy trong các hệ thống C++/Smalltalk tốt. Ý tưởng mượn từ kiến trúc sư Christopher Alexander: pattern = &lt;strong>một giải pháp đã được kiểm chứng cho một bài toán lặp lại trong một ngữ cảnh cụ thể&lt;/strong> — kèm tên gọi chung để kỹ sư nói chuyện với nhau bằng một từ thay vì mười phút giải thích.&lt;/p></description></item><item><title>3.4 — Kỹ thuật refactoring cấu trúc: Replace Conditional with Polymorphism, Replace Inheritance with Composition, Replace Loop with Strategy</title><link>https://thanhhv.github.io/series/software-design/level-3-refactoring/04-ky-thuat-cau-truc/</link><pubDate>Fri, 17 Jul 2026 09:50:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-3-refactoring/04-ky-thuat-cau-truc/</guid><description>&lt;p>Ba kỹ thuật này khác nhóm 3.3 về tầm vóc: chúng không dọn dẹp &lt;em>bên trong&lt;/em> một hàm/class mà &lt;strong>đổi cấu trúc phân nhánh và quan hệ giữa các type&lt;/strong> — và điểm đến của chúng thường &lt;em>chính là&lt;/em> một design pattern. Đây là cây cầu sang Level 4: pattern không phải thứ áp vào từ đầu, mà là &lt;strong>hình dạng code sau khi các refactoring này hoàn thành&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="a-replace-conditional-with-polymorphism">A. Replace Conditional with Polymorphism&lt;/h2>
&lt;p>&lt;strong>Bài toán nó giải&lt;/strong>: cùng một cấu trúc switch/if-else trên cùng một &amp;ldquo;loại&amp;rdquo; bị lặp ở nhiều hàm — mỗi lần thêm loại phải đi săn đủ các bản sao (đã phân tích tiêu chí đầy đủ ở OCP, chương 2.2).&lt;/p></description></item><item><title>3.3 — Kỹ thuật refactoring cơ bản: Extract Method, Move Method, Extract Class, Introduce Parameter Object</title><link>https://thanhhv.github.io/series/software-design/level-3-refactoring/03-ky-thuat-co-ban/</link><pubDate>Fri, 17 Jul 2026 09:40:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-3-refactoring/03-ky-thuat-co-ban/</guid><description>&lt;p>Bốn thao tác &amp;ldquo;dao kéo hằng ngày&amp;rdquo; — 90% công việc refactoring thực tế là bốn thao tác này lặp đi lặp lại. Mỗi kỹ thuật trình bày: khi nào dùng → các bước cơ giới (mechanics) → bẫy đặc thù → ví dụ Go. Phần mechanics quan trọng hơn vẻ ngoài của nó: refactoring an toàn là &lt;em>chuỗi bước nhỏ đến mức nhàm chán&lt;/em>, mỗi bước giữ test xanh — không phải &amp;ldquo;đập ra sắp lại theo trí nhớ&amp;rdquo;.&lt;/p></description></item><item><title>3.2 — Code Smells nhóm coupling: Duplicate Code, Shotgun Surgery, Feature Envy, Message Chains, Middle Man</title><link>https://thanhhv.github.io/series/software-design/level-3-refactoring/02-smells-coupling/</link><pubDate>Fri, 17 Jul 2026 09:30:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-3-refactoring/02-smells-coupling/</guid><description>&lt;p>Nhóm smell này chung bệnh sinh: &lt;strong>tri thức đặt sai chỗ&lt;/strong> — hoặc một tri thức bị nhân bản nhiều nơi, hoặc hành vi sống xa dữ liệu của nó, hoặc cấu trúc nội bộ bị phơi ra cho kẻ khác dựa vào.&lt;/p>
&lt;hr>
&lt;h2 id="a-duplicate-code">A. Duplicate Code&lt;/h2>
&lt;h3 id="ví-dụ--ba-cấp-độ-cấp-sau-khó-thấy-hơn-cấp-trước">Ví dụ — ba cấp độ, cấp sau khó thấy hơn cấp trước&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Cấp 1 — trùng nguyên văn (dễ thấy, tool bắt được):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// hai handler cùng 12 dòng parse-validate-load-user y hệt nhau&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Cấp 2 — trùng cấu trúc, khác chi tiết:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">exportOrdersCSV&lt;/span>(&lt;span style="color:#a6e22e">orders&lt;/span> []&lt;span style="color:#a6e22e">Order&lt;/span>) []&lt;span style="color:#66d9ef">byte&lt;/span> { &lt;span style="color:#75715e">/* mở buffer, ghi header, loop, format, flush */&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">exportUsersCSV&lt;/span>(&lt;span style="color:#a6e22e">users&lt;/span> []&lt;span style="color:#a6e22e">User&lt;/span>) []&lt;span style="color:#66d9ef">byte&lt;/span> { &lt;span style="color:#75715e">/* mở buffer, ghi header, loop, format, flush */&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Cấp 3 — trùng TRI THỨC, code trông khác hẳn nhau (nguy hiểm nhất):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Rule &amp;#34;đơn &amp;gt;= 500k miễn ship&amp;#34; xuất hiện ở:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// - Go backend: if total &amp;gt;= 500_000 { fee = 0 }&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// - TS frontend: total &amp;gt;= 500_000 ? &amp;#34;Miễn phí&amp;#34; : &amp;#34;20.000đ&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// - SQL report: CASE WHEN total &amp;gt;= 500000 THEN 0 ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// - Chatbot config: &amp;#34;đơn từ 500 nghìn được freeship nha!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="nguyên-nhân">Nguyên nhân&lt;/h3>
&lt;p>Copy-paste là đường đi ngắn nhất lúc viết; hai người viết cùng logic không biết nhau; và ranh giới hệ thống (frontend/backend/report) khiến trùng lặp tri thức gần như &lt;em>bắt buộc&lt;/em> về mặt kỹ thuật — nhưng không ai ghi sổ để đồng bộ.&lt;/p></description></item><item><title>3.1 — Code Smells nhóm "phình to": Long Method, Large Class, God Object, Primitive Obsession, Data Clumps</title><link>https://thanhhv.github.io/series/software-design/level-3-refactoring/01-smells-phinh-to/</link><pubDate>Fri, 17 Jul 2026 09:20:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-3-refactoring/01-smells-phinh-to/</guid><description>&lt;p>Nhóm smell này chung một bệnh sinh: &lt;strong>một đơn vị code (hàm, struct, kiểu dữ liệu) ôm nhiều hơn mức nó nên ôm&lt;/strong> — cohesion giảm dần mà không ai để ý, vì mỗi lần chỉ thêm &amp;ldquo;một tí&amp;rdquo;.&lt;/p>
&lt;p>Mỗi smell trình bày theo khung: ví dụ → nguyên nhân → hậu quả → refactoring phù hợp → khi nào KHÔNG phải smell.&lt;/p>
&lt;hr>
&lt;h2 id="a-long-method">A. Long Method&lt;/h2>
&lt;h3 id="ví-dụ">Ví dụ&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// ❌ handler 150 dòng — rút gọn còn khung xương, bạn đã thấy nó ở mọi codebase&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> (&lt;span style="color:#a6e22e">h&lt;/span> &lt;span style="color:#f92672">*&lt;/span>&lt;span style="color:#a6e22e">Handler&lt;/span>) &lt;span style="color:#a6e22e">CreateOrder&lt;/span>(&lt;span style="color:#a6e22e">w&lt;/span> &lt;span style="color:#a6e22e">http&lt;/span>.&lt;span style="color:#a6e22e">ResponseWriter&lt;/span>, &lt;span style="color:#a6e22e">r&lt;/span> &lt;span style="color:#f92672">*&lt;/span>&lt;span style="color:#a6e22e">http&lt;/span>.&lt;span style="color:#a6e22e">Request&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// ...15 dòng parse + validate JSON...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// ...10 dòng check tồn kho, gọi inventory service...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// ...20 dòng tính giá: giảm giá theo hạng thành viên, mã coupon, phí ship...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// ...15 dòng ghi DB trong transaction, xử lý rollback...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// ...10 dòng gửi event Kafka, log, metric...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// ...10 dòng build response...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="nguyên-nhân">Nguyên nhân&lt;/h3>
&lt;p>Không ai &lt;em>viết&lt;/em> hàm 150 dòng — hàm 20 dòng &lt;em>lớn lên&lt;/em> thành 150 qua hai năm, mỗi PR thêm 5-10 dòng &amp;ldquo;tiện thể nhét vào đây vì context sẵn rồi&amp;rdquo;. Lực hấp dẫn tự nhiên: thêm code vào hàm có sẵn luôn &lt;em>dễ hơn&lt;/em> tạo cấu trúc mới. Long Method là default của entropy, không phải lỗi cá nhân.&lt;/p></description></item><item><title>3.0 — Technical Debt &amp; Legacy Code: kinh tế học của việc refactor</title><link>https://thanhhv.github.io/series/software-design/level-3-refactoring/00-technical-debt-legacy-code/</link><pubDate>Fri, 17 Jul 2026 09:10:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-3-refactoring/00-technical-debt-legacy-code/</guid><description>&lt;h2 id="1-problem-statement">1. Problem Statement&lt;/h2>
&lt;p>Level 1–2 cho bạn &lt;em>lý thuyết&lt;/em> về thiết kế tốt. Nhưng bạn không làm việc trên trang giấy trắng — bạn làm việc trên một codebase 4 năm tuổi, 200 nghìn dòng, viết bởi 15 người trong đó 10 người đã nghỉ, không có test, và đang chạy production nuôi sống công ty. Câu hỏi thực tế không phải &amp;ldquo;thiết kế đẹp trông thế nào&amp;rdquo; mà là:&lt;/p></description></item><item><title>2.6 — DRY, KISS, YAGNI, Law of Demeter, Tell Don't Ask</title><link>https://thanhhv.github.io/series/software-design/level-2-principles/06-dry-kiss-yagni-lod/</link><pubDate>Fri, 17 Jul 2026 09:00:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-2-principles/06-dry-kiss-yagni-lod/</guid><description>&lt;p>Năm nguyên tắc &amp;ldquo;dân gian&amp;rdquo; — được trích dẫn nhiều nhất và hiểu sai nhiều nhất. Chương này trả mỗi cái về đúng phát biểu gốc, chỉ ra dạng hiểu sai phổ biến, và quan trọng nhất: &lt;strong>chúng mâu thuẫn nhau ở đâu và trọng tài là gì&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="a-dry--dont-repeat-yourself">A. DRY — Don&amp;rsquo;t Repeat Yourself&lt;/h2>
&lt;h3 id="phát-biểu-gốc--và-phần-bị-quên">Phát biểu gốc — và phần bị quên&lt;/h3>
&lt;p>The Pragmatic Programmer (1999): &lt;em>&amp;ldquo;Every piece of &lt;strong>knowledge&lt;/strong> must have a single, unambiguous, authoritative representation within a system.&amp;rdquo;&lt;/em>&lt;/p></description></item><item><title>2.5 — Dependency Inversion Principle: đảo chiều phụ thuộc</title><link>https://thanhhv.github.io/series/software-design/level-2-principles/05-dip/</link><pubDate>Fri, 17 Jul 2026 08:50:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-2-principles/05-dip/</guid><description>&lt;h2 id="1-problem-statement">1. Problem Statement&lt;/h2>
&lt;p>DIP là nguyên tắc &lt;strong>kiến trúc&lt;/strong> nhất trong SOLID — nó không nói về một class hay một interface, mà về &lt;strong>chiều của các mũi tên trong toàn hệ thống&lt;/strong>. Và nó là nền móng trực tiếp của Clean Architecture, Hexagonal Architecture (Level 5).&lt;/p>
&lt;p>Phát biểu gốc gồm hai vế:&lt;/p>
&lt;blockquote>
&lt;ol>
&lt;li>High-level modules không nên phụ thuộc low-level modules. Cả hai nên phụ thuộc abstraction.&lt;/li>
&lt;li>Abstraction không nên phụ thuộc chi tiết. Chi tiết nên phụ thuộc abstraction.&lt;/li>
&lt;/ol>&lt;/blockquote>
&lt;p>&amp;ldquo;High-level&amp;rdquo; = chính sách, nghiệp vụ, lý do phần mềm tồn tại (&amp;ldquo;đơn hàng được xác nhận thì trừ kho và báo khách&amp;rdquo;). &amp;ldquo;Low-level&amp;rdquo; = cơ chế thực thi (Postgres, Kafka, SendGrid, HTTP). Trực giác nền (chương 1.3): &lt;strong>mũi tên phải trỏ từ thứ hay đổi về thứ ổn định&lt;/strong> — và nghiệp vụ ổn định hơn hạ tầng: công ty đổi Redis sang Memcached, đổi REST sang gRPC thường xuyên hơn nhiều so với đổi &amp;ldquo;đơn xác nhận thì trừ kho&amp;rdquo;.&lt;/p></description></item><item><title>2.4 — Interface Segregation Principle: interface nhỏ, phía consumer</title><link>https://thanhhv.github.io/series/software-design/level-2-principles/04-isp/</link><pubDate>Fri, 17 Jul 2026 08:40:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-2-principles/04-isp/</guid><description>&lt;h2 id="1-problem-statement">1. Problem Statement&lt;/h2>
&lt;p>Câu chuyện gốc của ISP đáng kể lại vì nó rất &amp;ldquo;đời&amp;rdquo;: Robert Martin tư vấn cho Xerox, hệ thống điều khiển máy in đa năng. Mọi tác vụ (in, scan, staple, fax) đều đi qua một class &lt;code>Job&lt;/code> khổng lồ. Task chỉ cần in cũng phụ thuộc &lt;code>Job&lt;/code> — nên mỗi khi ai đó sửa phần staple, &lt;strong>toàn bộ&lt;/strong> hệ thống recompile và redeploy (C++ thập niên 90: recompile tính bằng giờ). Thuốc của Martin: tách &lt;code>Job&lt;/code> thành các interface theo &lt;em>từng client&lt;/em> — &lt;code>PrintJob&lt;/code>, &lt;code>StapleJob&lt;/code> — mỗi client chỉ thấy phần nó dùng.&lt;/p></description></item><item><title>2.3 — Liskov Substitution Principle: hợp đồng hành vi</title><link>https://thanhhv.github.io/series/software-design/level-2-principles/03-lsp/</link><pubDate>Fri, 17 Jul 2026 08:30:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-2-principles/03-lsp/</guid><description>&lt;h2 id="1-problem-statement">1. Problem Statement&lt;/h2>
&lt;p>LSP nổi tiếng qua ví dụ Hình vuông/Hình chữ nhật, nhưng ví dụ đó khiến nhiều người nghĩ nó là chuyện hàn lâm về kế thừa. Thực tế, LSP là nguyên tắc &lt;strong>thực chiến nhất&lt;/strong> với dev Go/TS hiện đại — vì nó trả lời câu hỏi: &lt;em>&amp;ldquo;khi nào một implementation của interface là ĐÚNG?&amp;rdquo;&lt;/em>&lt;/p>
&lt;p>Phát biểu của Barbara Liskov (1987, diễn giải): &lt;strong>nếu S là subtype của T, thì mọi chỗ dùng T phải hoạt động đúng khi thay bằng S — mà không cần biết đó là S.&lt;/strong>&lt;/p></description></item><item><title>2.2 — Open/Closed Principle: mở rộng mà không sửa</title><link>https://thanhhv.github.io/series/software-design/level-2-principles/02-ocp/</link><pubDate>Fri, 17 Jul 2026 08:20:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-2-principles/02-ocp/</guid><description>&lt;h2 id="1-problem-statement">1. Problem Statement&lt;/h2>
&lt;p>Bài toán quen thuộc đến mức mọi backend engineer đều từng viết nó: &lt;strong>thanh toán qua nhiều cổng&lt;/strong>. Ngày đầu chỉ có COD. Rồi thêm Momo. Rồi VNPay, ZaloPay, thẻ quốc tế, trả góp&amp;hellip;&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// V1 — hoàn toàn ổn khi có 2 phương thức&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">ProcessPayment&lt;/span>(&lt;span style="color:#a6e22e">o&lt;/span> &lt;span style="color:#f92672">*&lt;/span>&lt;span style="color:#a6e22e">Order&lt;/span>) &lt;span style="color:#66d9ef">error&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">switch&lt;/span> &lt;span style="color:#a6e22e">o&lt;/span>.&lt;span style="color:#a6e22e">PaymentMethod&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> &lt;span style="color:#e6db74">&amp;#34;cod&amp;#34;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">o&lt;/span>.&lt;span style="color:#a6e22e">Status&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;awaiting_delivery&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> &lt;span style="color:#e6db74">&amp;#34;momo&amp;#34;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">callMomoAPI&lt;/span>(&lt;span style="color:#a6e22e">o&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">default&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">fmt&lt;/span>.&lt;span style="color:#a6e22e">Errorf&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;unsupported payment method: %s&amp;#34;&lt;/span>, &lt;span style="color:#a6e22e">o&lt;/span>.&lt;span style="color:#a6e22e">PaymentMethod&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>18 tháng sau, hàm này 400 dòng, 9 case, mỗi case gọi API khác nhau với retry/timeout khác nhau. Và điều tệ hơn: &lt;strong>cùng cái switch &lt;code>o.PaymentMethod&lt;/code> đó bị lặp ở 5 nơi khác&lt;/strong> — tính phí giao dịch, render UI text, xử lý refund, đối soát, webhook. Thêm ZaloPay nghĩa là tìm đủ 6 cái switch rải rác để thêm case — sót một cái là bug âm thầm (default nuốt lỗi hoặc panic ở production).&lt;/p></description></item><item><title>2.1 — Single Responsibility Principle: trục của sự thay đổi</title><link>https://thanhhv.github.io/series/software-design/level-2-principles/01-srp/</link><pubDate>Fri, 17 Jul 2026 08:10:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-2-principles/01-srp/</guid><description>&lt;h2 id="1-problem-statement">1. Problem Statement&lt;/h2>
&lt;p>SRP là nguyên tắc bị hiểu sai nhiều nhất trong SOLID. Cách hiểu sai phổ biến: &lt;em>&amp;ldquo;mỗi hàm/class chỉ làm một việc&amp;rdquo;&lt;/em> → dẫn đến trò chẻ code thành trăm hàm 3 dòng, mỗi lần đọc luồng nghiệp vụ phải nhảy 15 file. Đó &lt;strong>không phải&lt;/strong> SRP.&lt;/p>
&lt;p>Định nghĩa gốc của Martin:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>&amp;ldquo;A module should have one, and only one, reason to change.&amp;rdquo;&lt;/strong> — một module chỉ nên có MỘT LÝ DO ĐỂ THAY ĐỔI.&lt;/p></description></item><item><title>2.0 — SOLID: lịch sử ra đời và vấn đề nó thực sự giải quyết</title><link>https://thanhhv.github.io/series/software-design/level-2-principles/00-solid-tong-quan/</link><pubDate>Fri, 17 Jul 2026 08:00:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-2-principles/00-solid-tong-quan/</guid><description>&lt;h2 id="1-vấn-đề-lịch-sử--solid-sinh-ra-từ-nỗi-đau-nào">1. Vấn đề lịch sử — SOLID sinh ra từ nỗi đau nào?&lt;/h2>
&lt;p>SOLID không rơi từ trên trời xuống. Nó là sản phẩm của một thời điểm lịch sử rất cụ thể — và hiểu bối cảnh đó quyết định việc bạn áp dụng nó đúng hay mù quáng.&lt;/p>
&lt;p>&lt;strong>Thập niên 1990, thế giới C++/OOP doanh nghiệp.&lt;/strong> Các hệ thống lớn viết bằng C++ thời đó có đặc điểm: biên dịch một lần mất hàng giờ; sửa một header file kéo theo recompile cả dây chuyền phụ thuộc; deploy là chép binary khổng lồ; và cây kế thừa sâu là &amp;ldquo;best practice&amp;rdquo; được dạy chính thống. Robert C. Martin (Uncle Bob) quan sát các codebase như vậy và mô tả bốn triệu chứng của &amp;ldquo;thiết kế mục nát&amp;rdquo; (design rot):&lt;/p></description></item><item><title>1.5 — Interface &amp; Immutability: hai vũ khí thiết kế của Go</title><link>https://thanhhv.github.io/series/software-design/level-1-fundamentals/05-interface-immutability/</link><pubDate>Fri, 17 Jul 2026 07:50:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-1-fundamentals/05-interface-immutability/</guid><description>&lt;h2 id="phần-a--interface">Phần A — Interface&lt;/h2>
&lt;h3 id="1-problem-statement">1. Problem Statement&lt;/h3>
&lt;p>Interface đã xuất hiện ở mọi chương trước như &amp;ldquo;công cụ giảm coupling&amp;rdquo;. Chương này trả lời các câu hỏi mà kỹ sư senior thực sự vướng: interface đặt ở &lt;strong>đâu&lt;/strong>? To hay nhỏ? Khai báo &lt;strong>khi nào&lt;/strong>? Vì sao interface Go khác Java/TS ở tầng triết lý — và điều đó đổi cách thiết kế ra sao?&lt;/p>
&lt;h3 id="2-điều-làm-interface-go-khác-biệt-implicit-satisfaction">2. Điều làm interface Go khác biệt: implicit satisfaction&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">package&lt;/span> &lt;span style="color:#a6e22e">storage&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">type&lt;/span> &lt;span style="color:#a6e22e">Saver&lt;/span> &lt;span style="color:#66d9ef">interface&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">Save&lt;/span>(&lt;span style="color:#a6e22e">ctx&lt;/span> &lt;span style="color:#a6e22e">context&lt;/span>.&lt;span style="color:#a6e22e">Context&lt;/span>, &lt;span style="color:#a6e22e">key&lt;/span> &lt;span style="color:#66d9ef">string&lt;/span>, &lt;span style="color:#a6e22e">data&lt;/span> []&lt;span style="color:#66d9ef">byte&lt;/span>) &lt;span style="color:#66d9ef">error&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Bất kỳ type nào có method &lt;code>Save&lt;/code> đúng chữ ký — tự động thỏa mãn &lt;code>Saver&lt;/code>. Không &lt;code>implements&lt;/code>, không import package chứa interface. Hệ quả thiết kế sâu sắc:&lt;/p></description></item><item><title>1.4 — Composition vs Inheritance &amp; Polymorphism</title><link>https://thanhhv.github.io/series/software-design/level-1-fundamentals/04-composition-inheritance-polymorphism/</link><pubDate>Fri, 17 Jul 2026 07:40:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-1-fundamentals/04-composition-inheritance-polymorphism/</guid><description>&lt;h2 id="1-problem-statement">1. Problem Statement&lt;/h2>
&lt;p>Bài toán: hệ thống có nhiều loại thông báo — Email, SMS, Push. Chúng chia sẻ logic chung (retry, logging, rate-limit) nhưng khác nhau ở cách gửi. Làm sao tái sử dụng phần chung mà không copy-paste?&lt;/p>
&lt;p>Đây là bài toán mà &lt;strong>inheritance (kế thừa)&lt;/strong> sinh ra để giải. Và cũng là bài toán cho thấy vì sao inheritance thường là câu trả lời sai — đến mức chính GoF, trong cuốn sách 1994, đã viết ở trang 20: &lt;em>&amp;ldquo;Favor object composition over class inheritance&amp;rdquo;&lt;/em>. Go đi xa hơn: &lt;strong>loại bỏ hẳn class inheritance khỏi ngôn ngữ&lt;/strong>.&lt;/p></description></item><item><title>1.3 — Coupling, Cohesion &amp; Dependency: thước đo của mọi quyết định thiết kế</title><link>https://thanhhv.github.io/series/software-design/level-1-fundamentals/03-coupling-cohesion-dependency/</link><pubDate>Fri, 17 Jul 2026 07:30:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-1-fundamentals/03-coupling-cohesion-dependency/</guid><description>&lt;h2 id="1-problem-statement">1. Problem Statement&lt;/h2>
&lt;p>Đây là chương quan trọng nhất của Level 1. Mọi nguyên lý (SOLID), mọi pattern (Strategy, Observer&amp;hellip;), mọi kiến trúc (Clean, Hexagonal) — khi bóc hết vỏ — đều quy về đúng hai đại lượng:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Coupling: hai module dính nhau chặt đến đâu — sửa cái này có phải sửa cái kia không?&lt;/strong>
&lt;strong>Cohesion: những thứ trong cùng một module có thực sự thuộc về nhau không?&lt;/strong>&lt;/p></description></item><item><title>1.2 — Abstraction &amp; Encapsulation: che giấu đúng thứ cần che</title><link>https://thanhhv.github.io/series/software-design/level-1-fundamentals/02-abstraction-encapsulation/</link><pubDate>Fri, 17 Jul 2026 07:20:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-1-fundamentals/02-abstraction-encapsulation/</guid><description>&lt;h2 id="1-problem-statement">1. Problem Statement&lt;/h2>
&lt;p>Tiếp tục câu chuyện e-commerce. Team bạn cần gửi email xác nhận đơn hàng. Một dev viết:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// V1 — trong order_service.go&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> (&lt;span style="color:#a6e22e">s&lt;/span> &lt;span style="color:#f92672">*&lt;/span>&lt;span style="color:#a6e22e">OrderService&lt;/span>) &lt;span style="color:#a6e22e">ConfirmOrder&lt;/span>(&lt;span style="color:#a6e22e">ctx&lt;/span> &lt;span style="color:#a6e22e">context&lt;/span>.&lt;span style="color:#a6e22e">Context&lt;/span>, &lt;span style="color:#a6e22e">orderID&lt;/span> &lt;span style="color:#66d9ef">string&lt;/span>) &lt;span style="color:#66d9ef">error&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">order&lt;/span>, &lt;span style="color:#a6e22e">err&lt;/span> &lt;span style="color:#f92672">:=&lt;/span> &lt;span style="color:#a6e22e">s&lt;/span>.&lt;span style="color:#a6e22e">repo&lt;/span>.&lt;span style="color:#a6e22e">Find&lt;/span>(&lt;span style="color:#a6e22e">ctx&lt;/span>, &lt;span style="color:#a6e22e">orderID&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#a6e22e">err&lt;/span> &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#66d9ef">nil&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">err&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">order&lt;/span>.&lt;span style="color:#a6e22e">Status&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;confirmed&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#a6e22e">err&lt;/span> &lt;span style="color:#f92672">:=&lt;/span> &lt;span style="color:#a6e22e">s&lt;/span>.&lt;span style="color:#a6e22e">repo&lt;/span>.&lt;span style="color:#a6e22e">Save&lt;/span>(&lt;span style="color:#a6e22e">ctx&lt;/span>, &lt;span style="color:#a6e22e">order&lt;/span>); &lt;span style="color:#a6e22e">err&lt;/span> &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#66d9ef">nil&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">err&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Gửi email — chi tiết SMTP nằm ngay tại đây&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">auth&lt;/span> &lt;span style="color:#f92672">:=&lt;/span> &lt;span style="color:#a6e22e">smtp&lt;/span>.&lt;span style="color:#a6e22e">PlainAuth&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;noreply@shop.vn&amp;#34;&lt;/span>, &lt;span style="color:#a6e22e">os&lt;/span>.&lt;span style="color:#a6e22e">Getenv&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;SMTP_PASS&amp;#34;&lt;/span>), &lt;span style="color:#e6db74">&amp;#34;smtp.gmail.com&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">body&lt;/span> &lt;span style="color:#f92672">:=&lt;/span> &lt;span style="color:#a6e22e">fmt&lt;/span>.&lt;span style="color:#a6e22e">Sprintf&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;Subject: Đơn hàng %s đã xác nhận\r\n\r\nCảm ơn bạn!&amp;#34;&lt;/span>, &lt;span style="color:#a6e22e">order&lt;/span>.&lt;span style="color:#a6e22e">ID&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">smtp&lt;/span>.&lt;span style="color:#a6e22e">SendMail&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;smtp.gmail.com:587&amp;#34;&lt;/span>, &lt;span style="color:#a6e22e">auth&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;noreply@shop.vn&amp;#34;&lt;/span>, []&lt;span style="color:#66d9ef">string&lt;/span>{&lt;span style="color:#a6e22e">order&lt;/span>.&lt;span style="color:#a6e22e">CustomerEmail&lt;/span>}, []byte(&lt;span style="color:#a6e22e">body&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Chạy được. Ship được. Nhưng 3 tháng sau:&lt;/p></description></item><item><title>1.1 — Vì sao code trở nên khó bảo trì: bản chất của Software Design</title><link>https://thanhhv.github.io/series/software-design/level-1-fundamentals/01-vi-sao-code-kho-bao-tri/</link><pubDate>Fri, 17 Jul 2026 07:10:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/level-1-fundamentals/01-vi-sao-code-kho-bao-tri/</guid><description>&lt;h2 id="1-problem-statement">1. Problem Statement&lt;/h2>
&lt;p>Hãy bắt đầu bằng một sự thật mà mọi kỹ sư có kinh nghiệm đều biết nhưng ít khi nói thành lời:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Chi phí của phần mềm không nằm ở việc viết code lần đầu. Nó nằm ở việc thay đổi code sau đó.&lt;/strong>&lt;/p>&lt;/blockquote>
&lt;p>Một hệ thống backend điển hình sống 5–10 năm. Trong vòng đời đó, code được &lt;strong>đọc&lt;/strong> nhiều gấp 10 lần được viết, và được &lt;strong>sửa&lt;/strong> nhiều gấp nhiều lần được viết mới. Nghiên cứu kinh điển về chi phí phần mềm ước tính 60–80% tổng chi phí là maintenance — không phải development ban đầu.&lt;/p></description></item><item><title>Software Design &amp; Design Patterns — Từ First Principles đến Production</title><link>https://thanhhv.github.io/series/software-design/00-muc-luc/</link><pubDate>Fri, 17 Jul 2026 07:00:00 +0700</pubDate><guid>https://thanhhv.github.io/series/software-design/00-muc-luc/</guid><description>&lt;blockquote>
&lt;p>Tài liệu chuyên sâu dành cho Backend Engineer, Golang/Node.js Developer, Tech Lead và Solution Architect.
Viết bởi góc nhìn của một Principal Software Architect: &lt;strong>pattern không phải là mục tiêu — pattern là kết quả của việc giải quyết một vấn đề thiết kế cụ thể.&lt;/strong>&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h2 id="triết-lý-của-bộ-tài-liệu-này">Triết lý của bộ tài liệu này&lt;/h2>
&lt;p>Hầu hết tài liệu về Design Pattern bắt đầu bằng: &lt;em>&amp;ldquo;Singleton là&amp;hellip; Factory là&amp;hellip; Observer là&amp;hellip;&amp;rdquo;&lt;/em> — cách học này tạo ra những kỹ sư thuộc lòng 23 pattern nhưng không biết &lt;strong>khi nào&lt;/strong> dùng, và tệ hơn, dùng pattern ở nơi không cần thiết (over-engineering).&lt;/p></description></item></channel></rss>