<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>miti99</title><link>https://miti99.com/</link><description>Recent content on miti99</description><generator>Hugo -- gohugo.io</generator><language>vi</language><atom:link href="https://miti99.com/index.xml" rel="self" type="application/rss+xml"/><item><title>Sửa lỗi 'Pairing Required' khi kết nối OpenClaw qua Docker</title><link>https://miti99.com/post/2026/04/05/</link><pubDate>Sun, 05 Apr 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/04/05/</guid><description>&lt;p&gt;Nếu bạn đang self-host &lt;a class="link" href="https://github.com/open-claw/open-claw" target="_blank" rel="noopener"
&gt;OpenClaw&lt;/a&gt; bằng Docker và gặp lỗi &lt;strong&gt;&amp;ldquo;disconnected (1008): pairing required&amp;rdquo;&lt;/strong&gt; khi truy cập từ trình duyệt, bài viết này sẽ giúp bạn khắc phục nhanh chóng.&lt;/p&gt;
&lt;h2 id="vấn-đề"&gt;Vấn đề
&lt;/h2&gt;&lt;p&gt;Khi setup OpenClaw với Docker trên Ubuntu, trình duyệt hiển thị lỗi:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;disconnected (1008): pairing required
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Thử dùng CLI để approve device thì lại gặp lỗi &lt;strong&gt;&amp;ldquo;gateway token mismatch&amp;rdquo;&lt;/strong&gt; — CLI trong Docker container không resolve đúng authentication token từ file config.&lt;/p&gt;
&lt;h2 id="nguyên-nhân"&gt;Nguyên nhân
&lt;/h2&gt;&lt;p&gt;Token xác thực giữa host và Docker container bị lệch. CLI bên trong container không đọc đúng token từ file &lt;code&gt;openclaw.json&lt;/code&gt;, dẫn đến việc không thể list hay approve device.&lt;/p&gt;
&lt;h2 id="cách-sửa"&gt;Cách sửa
&lt;/h2&gt;&lt;h3 id="bước-1-lấy-gateway-token-từ-host"&gt;Bước 1: Lấy Gateway Token từ host
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat ~/.openclaw/openclaw.json &lt;span class="p"&gt;|&lt;/span&gt; grep -A5 &lt;span class="s1"&gt;&amp;#39;&amp;#34;auth&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Copy giá trị token dưới mục &lt;code&gt;gateway.auth&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="bước-2-kiểm-tra-token-trong-container"&gt;Bước 2: Kiểm tra token trong container
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker ps &lt;span class="c1"&gt;# Lấy CONTAINER_ID của openclaw-gateway&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; -it &amp;lt;CONTAINER_ID&amp;gt; cat /home/node/.openclaw/openclaw.json &lt;span class="p"&gt;|&lt;/span&gt; grep -A5 &lt;span class="s1"&gt;&amp;#39;&amp;#34;auth&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Xác nhận token giữa host và container có khớp không.&lt;/p&gt;
&lt;h3 id="bước-3-list-devices-với-token-override"&gt;Bước 3: List devices với token override
&lt;/h3&gt;&lt;p&gt;Inject token trực tiếp qua biến môi trường &lt;code&gt;-e&lt;/code&gt; khi chạy lệnh trong container:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; -e &lt;span class="nv"&gt;OPENCLAW_GATEWAY_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;YOUR_TOKEN&amp;gt; -it &amp;lt;CONTAINER_ID&amp;gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; openclaw devices list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Lệnh này sẽ hiển thị danh sách các device đang chờ approve kèm &lt;strong&gt;Request ID&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="bước-4-approve-device"&gt;Bước 4: Approve device
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker compose &lt;span class="nb"&gt;exec&lt;/span&gt; openclaw-gateway &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; openclaw devices approve &amp;lt;REQUEST_ID&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="bước-5-kiểm-tra-kết-quả"&gt;Bước 5: Kiểm tra kết quả
&lt;/h3&gt;&lt;p&gt;Truy cập lại &lt;code&gt;http://localhost:18789&lt;/code&gt; trên trình duyệt — lỗi pairing sẽ biến mất.&lt;/p&gt;
&lt;h2 id="lưu-ý"&gt;Lưu ý
&lt;/h2&gt;&lt;p&gt;Mấu chốt của cách sửa này là inject token qua biến môi trường (&lt;code&gt;-e OPENCLAW_GATEWAY_TOKEN=...&lt;/code&gt;) thay vì truyền qua command-line flag, vì CLI trong Docker không xử lý đúng flag token.&lt;/p&gt;
&lt;h2 id="tham-khảo"&gt;Tham khảo
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.linkedin.com/pulse/fixing-openclaw-dockers-pairing-required-dead-end-ubuntu-rik-banerjee-j09de/" target="_blank" rel="noopener"
&gt;Fixing OpenClaw Docker&amp;rsquo;s &amp;ldquo;Pairing Required&amp;rdquo; Dead End on Ubuntu - Rik Banerjee&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Newsletter #94</title><link>https://miti99.com/post/2026/04/02/</link><pubDate>Thu, 02 Apr 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/04/02/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #94.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="bên-trong-mã-nguồn-claude-code"&gt;&lt;a class="link" href="https://gist.github.com/Haseeb-Qureshi/d0dc36844c19d26303ce09b42e7188c1" target="_blank" rel="noopener"
&gt;Bên trong mã nguồn Claude Code&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Haseeb Qureshi đã phân tích chi tiết mã nguồn của Claude Code CLI (khoảng 500K dòng TypeScript) sau khi nó bị rò rỉ trên GitHub. Bài viết so sánh kiến trúc của Claude Code với Codex của OpenAI, hé lộ nhiều chi tiết kỹ thuật thú vị mà người dùng thông thường không thể nhận ra từ bên ngoài.&lt;/p&gt;
&lt;p&gt;Điểm nổi bật nhất là giao diện dòng lệnh thực chất là một ứng dụng React chạy trong terminal thông qua thư viện Ink. Toàn bộ vòng đời xử lý yêu cầu hoạt động dựa trên async generator, cho phép CLI, SDK và IDE bridge cùng tiêu thụ chung một luồng sự kiện. Hệ thống quản lý ngữ cảnh sử dụng bốn tầng nén (proactive, reactive, snip và context collapse) để xử lý các phiên làm việc dài mà không bị tràn cửa sổ ngữ cảnh. Ngoài ra, hệ thống prompt được chia tách thông minh bằng một ranh giới tĩnh/động để tận dụng bộ nhớ đệm toàn cục, giúp tiết kiệm chi phí API đáng kể.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giao diện terminal được xây dựng bằng React (Ink) — cùng mô hình tư duy như ứng dụng web&lt;/li&gt;
&lt;li&gt;Bốn chiến lược nén ngữ cảnh, bao gồm &amp;ldquo;context collapse&amp;rdquo; có thể đảo ngược — Codex chỉ có hai&lt;/li&gt;
&lt;li&gt;Ranh giới bộ nhớ đệm prompt chia phần tĩnh (cache toàn cục ~3.000 token) và phần động theo phiên&lt;/li&gt;
&lt;li&gt;Bản build nội bộ của Anthropic có prompt khác biệt: giới hạn 25 từ giữa các lệnh, tác tử xác minh đối kháng&lt;/li&gt;
&lt;li&gt;Cờ tính năng biên dịch (Bun) loại bỏ mã chết, gợi ý các tính năng chưa phát hành như &lt;code&gt;VOICE_MODE&lt;/code&gt; và &lt;code&gt;KAIROS&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Luận điểm cốt lõi: mô hình AI có thể thay thế được, nhưng &amp;ldquo;harness&amp;rdquo; (khung vận hành) mới là nơi chứa đựng kinh nghiệm thực chiến&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ai-sẽ-đẩy-nhanh-nợ-kỹ-thuật-của-bạn"&gt;&lt;a class="link" href="https://securosis.com/ai/ai-will-accelerate-your-tech-debt" target="_blank" rel="noopener"
&gt;AI sẽ đẩy nhanh nợ kỹ thuật của bạn&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Chris Farris lập luận rằng đầu tư vào AI sẽ làm trầm trọng thêm vấn đề nợ kỹ thuật đối với các tổ chức chưa sẵn sàng giải quyết những thách thức hạ tầng nền tảng. Nhiều tổ chức đang vận hành trong tình trạng bấp bênh do nhiều năm ưu tiên phát triển tính năng thay vì xây dựng kiến trúc bền vững, rơi vào vòng xoáy mà việc xử lý sự cố liên tục ngốn hết nguồn lực lẽ ra dành cho việc trả nợ kỹ thuật.&lt;/p&gt;
&lt;p&gt;Tác giả ví đầu tư AI như chính sách cắt giảm thuế — trông có vẻ có lợi trong ngắn hạn nhưng lại làm xấu đi các vấn đề cấu trúc. Khi chi phí viết mã nguồn tiến gần về không, các tổ chức mất đi rào cản kinh tế tự nhiên vốn ngăn cản việc triển khai những tính năng thiếu cân nhắc. Về mặt bảo mật, kẻ tấn công sử dụng AI có thể khai thác lỗ hổng nhanh hơn khả năng vá lỗi của bên phòng thủ — đặc biệt nguy hiểm với những tổ chức có nợ kỹ thuật chưa được quản lý.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chi phí viết mã giảm về gần không khiến tổ chức dễ dàng triển khai tính năng thiếu cân nhắc, làm tăng nợ kỹ thuật&lt;/li&gt;
&lt;li&gt;Kẻ tấn công dùng AI khai thác lỗ hổng nhanh hơn khả năng phòng thủ — khái niệm &amp;ldquo;Core Collapse&amp;rdquo; của Rich Mogull&lt;/li&gt;
&lt;li&gt;Giải pháp đề xuất: &amp;ldquo;Technology Troika&amp;rdquo; — liên kết ba nhóm Tài chính/FinOps, Bảo mật và Nền tảng&lt;/li&gt;
&lt;li&gt;Cần ưu tiên công việc nền tảng (quản lý danh tính, phân loại dữ liệu, ánh xạ phụ thuộc) trước khi triển khai AI&lt;/li&gt;
&lt;li&gt;Một số hệ thống cũ nên được loại bỏ hoàn toàn thay vì tái cấu trúc&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="cách-slack-xây-dựng-lại-hệ-thống-thông-báo"&gt;&lt;a class="link" href="https://slack.engineering/how-slack-rebuilt-notifications/" target="_blank" rel="noopener"
&gt;Cách Slack xây dựng lại hệ thống thông báo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Đội ngũ kỹ sư Slack đã thiết kế lại toàn bộ hệ thống thông báo để giảm tình trạng quá tải và trao lại quyền kiểm soát cho người dùng. Nghiên cứu cho thấy thông báo nằm trong ba nguyên nhân hàng đầu gây ra yêu cầu hỗ trợ khách hàng. Vấn đề không chỉ là số lượng thông báo mà còn đến từ hệ thống cũ bị phân mảnh: máy tính và điện thoại hoạt động khác nhau, cài đặt không đồng bộ giữa các thiết bị, và các tùy chọn nâng cao bị phân tán khắp nơi.&lt;/p&gt;
&lt;p&gt;Giải pháp là thống nhất về một mô hình duy nhất với ba lựa chọn rõ ràng cho mỗi kênh: &amp;ldquo;Tất cả bài viết mới,&amp;rdquo; &amp;ldquo;Chỉ đề cập,&amp;rdquo; hoặc &amp;ldquo;Tắt tiếng.&amp;rdquo; Đội ngũ cũng tách biệt thông báo hoạt động khỏi thông báo đẩy, cho phép người dùng kiểm soát độc lập. Về mặt kỹ thuật, họ di chuyển hàng triệu người dùng từ bốn hệ thống cài đặt xung đột sang một kiến trúc thống nhất bằng logic đọc thời gian thực thay vì di chuyển dữ liệu ở tầng cơ sở dữ liệu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thông báo là một trong ba nguyên nhân hàng đầu gây ra yêu cầu hỗ trợ — vấn đề nằm ở kiến trúc, không chỉ số lượng&lt;/li&gt;
&lt;li&gt;Đơn giản hóa thành ba lựa chọn: tất cả bài viết, chỉ đề cập, hoặc tắt tiếng&lt;/li&gt;
&lt;li&gt;Tách biệt &amp;ldquo;thông báo về cái gì&amp;rdquo; khỏi &amp;ldquo;nhận thông báo bằng cách nào&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Di chuyển hàng triệu người dùng bằng logic đọc thời gian thực, đảm bảo tương thích ngược&lt;/li&gt;
&lt;li&gt;Mức tương tác với cài đặt tăng gấp 5 lần và duy trì ổn định sau nhiều tuần ra mắt&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="nhanh-hơn-tốt-hơn-và-còn-nhiều-hơn-nữa"&gt;&lt;a class="link" href="https://randsinrepose.com/archives/better-faster-and-even-more/" target="_blank" rel="noopener"
&gt;Nhanh hơn, tốt hơn, và còn nhiều hơn nữa&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả Rands chia sẻ cách tổ chức quy trình phát triển cá nhân để tăng tốc độ làm việc, đặc biệt khi kết hợp với Claude Code cho việc tạo mẫu nhanh. Cốt lõi là một thư mục dự án có cấu trúc rõ ràng (&lt;code&gt;~/Projects/&lt;/code&gt;), trong đó mỗi dự án là một kho Git độc lập, cùng ba kho chuyên biệt: &lt;code&gt;dotfiles&lt;/code&gt; cho cấu hình hệ thống, &lt;code&gt;credentials&lt;/code&gt; cho khóa API riêng tư, và &lt;code&gt;scripts&lt;/code&gt; cho các công cụ dòng lệnh.&lt;/p&gt;
&lt;p&gt;Mỗi dự án đều có hai tệp tài liệu: &lt;code&gt;CLAUDE.md&lt;/code&gt; chứa hướng dẫn tĩnh và &lt;code&gt;WORKLOG.md&lt;/code&gt; lưu lịch sử phiên làm việc để Claude hiểu ngữ cảnh. Tác giả cũng áp dụng nhiều thủ thuật tối ưu như tích hợp clipboard (Claude đẩy kết quả thẳng vào &lt;code&gt;pbcopy&lt;/code&gt;), sử dụng ảnh chụp màn hình thay vì mô tả bằng văn bản, và một script xác minh kiểm tra hơn 30 mục cấu hình khi chuyển đổi giữa các máy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tổ chức thư mục dự án có cấu trúc với ba kho Git chuyên biệt (dotfiles, credentials, scripts)&lt;/li&gt;
&lt;li&gt;Sử dụng &lt;code&gt;CLAUDE.md&lt;/code&gt; và &lt;code&gt;WORKLOG.md&lt;/code&gt; để cung cấp ngữ cảnh cho tác tử AI&lt;/li&gt;
&lt;li&gt;Tích hợp clipboard giúp loại bỏ ma sát khi sao chép kết quả giữa các công cụ&lt;/li&gt;
&lt;li&gt;Ảnh chụp màn hình truyền đạt vấn đề nhanh hơn mô tả bằng văn bản&lt;/li&gt;
&lt;li&gt;Triết lý cốt lõi: giảm ma sát giữa &amp;ldquo;ý tưởng ngẫu nhiên&amp;rdquo; và &amp;ldquo;sản phẩm hoạt động&amp;rdquo; tạo vòng lặp phản hồi tích cực&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="java-rất-nhanh--mã-nguồn-của-bạn-có-thể-không"&gt;&lt;a class="link" href="https://jvogel.me/posts/2026/java-is-fast-your-code-might-not-be/" target="_blank" rel="noopener"
&gt;Java rất nhanh — mã nguồn của bạn có thể không&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Jonathan Vogel (Developer Advocate tại AWS) trình bày tám anti-pattern phổ biến trong Java khiến hiệu năng ứng dụng suy giảm nghiêm trọng. Bằng cách sửa tám lỗi này trong một ứng dụng xử lý đơn hàng, tác giả giảm thời gian xử lý từ 1.198ms xuống 239ms, tăng thông lượng từ 85.000 lên 419.000 đơn hàng mỗi giây, và giảm bộ nhớ heap từ 1GB xuống 139MB.&lt;/p&gt;
&lt;p&gt;Các anti-pattern bao gồm: nối chuỗi bằng toán tử &lt;code&gt;+&lt;/code&gt; trong vòng lặp (tạo chi phí sao chép O(n²)), thao tác Stream O(n²) lồng trong vòng lặp (chiếm tới 71% CPU), sử dụng &lt;code&gt;String.format()&lt;/code&gt; trên đường dẫn nóng, autoboxing gây lãng phí heap, dùng ngoại lệ để điều khiển luồng chương trình, đồng bộ hóa quá rộng gây nghẽn khóa, tạo lại đối tượng tái sử dụng được (như &lt;code&gt;ObjectMapper&lt;/code&gt;), và ghim luồng ảo trên JDK 21-23 khi dùng &lt;code&gt;synchronized&lt;/code&gt; với I/O chặn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nối chuỗi trong vòng lặp bằng &lt;code&gt;+&lt;/code&gt; tạo chi phí O(n²) — dùng &lt;code&gt;StringBuilder&lt;/code&gt; thay thế&lt;/li&gt;
&lt;li&gt;Stream lồng trong vòng lặp là điểm nóng CPU lớn nhất — dùng tích lũy một lượt với &lt;code&gt;merge()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Autoboxing (&lt;code&gt;Long&lt;/code&gt; thay vì &lt;code&gt;long&lt;/code&gt;) tạo 16MB rác heap cho mỗi triệu phần tử&lt;/li&gt;
&lt;li&gt;Dùng &lt;code&gt;ConcurrentHashMap&lt;/code&gt; + &lt;code&gt;LongAdder&lt;/code&gt; thay vì &lt;code&gt;synchronized&lt;/code&gt; toàn phương thức&lt;/li&gt;
&lt;li&gt;Trên JDK 21-23, dùng &lt;code&gt;ReentrantLock&lt;/code&gt; thay &lt;code&gt;synchronized&lt;/code&gt; để tránh ghim luồng ảo (JDK 24 đã sửa)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="quy-ước-đặt-tên-trong-go-hướng-dẫn-thực-hành"&gt;&lt;a class="link" href="https://www.alexedwards.net/blog/go-naming-conventions" target="_blank" rel="noopener"
&gt;Quy ước đặt tên trong Go: Hướng dẫn thực hành&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Alex Edwards tổng hợp các quy tắc bắt buộc và quy ước đặt tên trong Go một cách có hệ thống. Bài viết bắt đầu với ba quy tắc cứng cho định danh (chỉ dùng chữ unicode, chữ số, gạch dưới; không bắt đầu bằng chữ số; không trùng từ khóa), sau đó đi sâu vào các quy ước thực hành mà cộng đồng Go tuân theo.&lt;/p&gt;
&lt;p&gt;Về kiểu chữ, Go sử dụng &lt;code&gt;camelCase&lt;/code&gt; cho định danh không xuất và &lt;code&gt;PascalCase&lt;/code&gt; cho định danh xuất — không dùng &lt;code&gt;snake_case&lt;/code&gt; hay &lt;code&gt;SCREAMING_SNAKE_CASE&lt;/code&gt;. Từ viết tắt phải nhất quán: &lt;code&gt;apiKey&lt;/code&gt; hoặc &lt;code&gt;APIKey&lt;/code&gt; đều đúng, nhưng &lt;code&gt;ApiKey&lt;/code&gt; thì không; &lt;code&gt;userID&lt;/code&gt; chứ không phải &lt;code&gt;userId&lt;/code&gt;. Về độ dài tên, quy tắc vàng là: phạm vi sử dụng càng xa nơi khai báo thì tên càng cần mô tả rõ ràng — biến trong vòng lặp ngắn có thể dùng một chữ cái, nhưng biến có phạm vi rộng cần tên đầy đủ ý nghĩa.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dùng &lt;code&gt;camelCase&lt;/code&gt; cho không xuất, &lt;code&gt;PascalCase&lt;/code&gt; cho xuất — chữ cái đầu quyết định khả năng truy cập từ bên ngoài&lt;/li&gt;
&lt;li&gt;Từ viết tắt phải nhất quán: &lt;code&gt;HTTPClient&lt;/code&gt; chứ không phải &lt;code&gt;HttpClient&lt;/code&gt;, &lt;code&gt;userID&lt;/code&gt; chứ không phải &lt;code&gt;userId&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Tránh đặt tên trùng kiểu dữ liệu (&lt;code&gt;count&lt;/code&gt; thay vì &lt;code&gt;intCount&lt;/code&gt;), hàm dựng sẵn, và tên gói thư viện chuẩn&lt;/li&gt;
&lt;li&gt;Phạm vi càng rộng, tên càng cần mô tả chi tiết — nguyên tắc &amp;ldquo;viết mã nguồn kín đáo&amp;rdquo; từ The Pragmatic Programmer&lt;/li&gt;
&lt;li&gt;Mặc định dùng định danh không xuất, chỉ xuất khi thực sự cần thiết&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bộ-kỹ-năng-tác-tử-ai-cho-dự-án-go"&gt;&lt;a class="link" href="https://github.com/samber/cc-skills-golang" target="_blank" rel="noopener"
&gt;Bộ kỹ năng tác tử AI cho dự án Go&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bộ sưu tập các kỹ năng (skills) chuyên biệt cho Go dành cho trợ lý lập trình AI như Claude Code, Codex, Cursor, Copilot và Gemini CLI. Mỗi kỹ năng là một tập hướng dẫn có thể tái sử dụng, được tải theo yêu cầu để không làm phình ngữ cảnh. Dự án được khởi tạo bằng Claude Code từ các commit Go thực tế, sau đó được con người chỉnh sửa, kiểm thử và đánh giá kỹ lưỡng.&lt;/p&gt;
&lt;p&gt;Bộ kỹ năng bao gồm nhiều chủ đề: phong cách mã nguồn, cấu trúc dữ liệu, cơ sở dữ liệu, mẫu thiết kế, tài liệu, xử lý lỗi, khả năng quan sát, hiệu năng, bảo mật và kiểm thử. Các kỹ năng được thiết kế dạng đơn vị nguyên tử có tham chiếu chéo — ví dụ quy tắc xử lý lỗi ảnh hưởng đến ghi log nằm trong &lt;code&gt;golang-error-handling&lt;/code&gt;, không phải &lt;code&gt;golang-observability&lt;/code&gt;. Hỗ trợ cài đặt qua CLI &lt;code&gt;skills&lt;/code&gt;, hoặc sao chép thủ công vào thư mục khám phá của từng công cụ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tương thích đa nền tảng: Claude Code, Codex, Cursor, Copilot, Gemini CLI, OpenCode, Antigravity&lt;/li&gt;
&lt;li&gt;Kỹ năng được tải theo yêu cầu, không làm phình ngữ cảnh của tác tử AI&lt;/li&gt;
&lt;li&gt;Bao gồm các chủ đề quan trọng: phong cách mã nguồn, mẫu thiết kế, bảo mật, hiệu năng, kiểm thử&lt;/li&gt;
&lt;li&gt;Đo lường tỷ lệ giảm lỗi cho từng kỹ năng (ví dụ: phong cách mã nguồn giảm 40%, tài liệu giảm 53%)&lt;/li&gt;
&lt;li&gt;Triết lý: kỹ năng AI do AI tạo ra là vô dụng — cần con người chỉnh sửa và đánh giá&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="những-điều-tôi-tin"&gt;&lt;a class="link" href="https://leerob.com/beliefs" target="_blank" rel="noopener"
&gt;Những điều tôi tin&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Lee Robinson (VP trải nghiệm nhà phát triển tại Cursor) chia sẻ tuyên ngôn cá nhân gồm mười một nguyên tắc nghề nghiệp cốt lõi. Xuyên suốt bài viết là triết lý ưu tiên hành động: giao sản phẩm nhanh quan trọng hơn chiến lược hoàn hảo, đội nhỏ vượt trội đội lớn, và các đội ứng dụng AI sẽ vượt xa tổ chức truyền thống. Robinson nhấn mạnh việc áp dụng sản phẩm quan trọng hơn việc triển khai mã nguồn.&lt;/p&gt;
&lt;p&gt;Về phát triển bản thân, tác giả tin rằng thành công đến từ sự quyết tâm chứ không phải tài năng bẩm sinh, và cải thiện đều đặn mỗi ngày là con đường phát triển sự nghiệp. Về giao tiếp, viết rõ ràng phản ánh tư duy rõ ràng — mọi chuyên gia đều cần cải thiện kỹ năng viết. Về lãnh đạo, ảnh hưởng quan trọng hơn chức danh, và chất lượng tuyển dụng là điều phân biệt lãnh đạo giỏi với lãnh đạo xuất sắc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ưu tiên giao sản phẩm nhanh — đội nhỏ ứng dụng AI sẽ vượt xa tổ chức truyền thống&lt;/li&gt;
&lt;li&gt;Thành công đến từ sự quyết tâm và cải thiện đều đặn, không phải tài năng bẩm sinh&lt;/li&gt;
&lt;li&gt;Viết rõ ràng phản ánh tư duy rõ ràng — lãnh đạo phải loại bỏ sự mơ hồ&lt;/li&gt;
&lt;li&gt;Bản mẫu truyền đạt tốt hơn tài liệu — chỉ quảng bá dự án mà mình thực sự tin tưởng&lt;/li&gt;
&lt;li&gt;Luôn giả định thiện ý — đối xử với phê bình như phản hồi có giá trị&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="những-thủ-thuật-lập-trình-nhỏ-rất-quan-trọng"&gt;&lt;a class="link" href="https://will-keleher.com/posts/small-programming-tricks-matter/" target="_blank" rel="noopener"
&gt;Những thủ thuật lập trình nhỏ rất quan trọng&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Will Keleher lập luận rằng năng suất kỹ sư được cải thiện đáng kể nhờ tích lũy những &amp;ldquo;mẩu kiến thức nhỏ&amp;rdquo; — các kỹ thuật và công cụ cụ thể không cần nền tảng sâu nhưng cải thiện công việc hàng ngày ngay lập tức. Tác giả chia sẻ nhiều ví dụ thực tế: tìm kiếm mờ lịch sử lệnh bằng &lt;code&gt;fzf&lt;/code&gt; với Ctrl+R, chạy truy vấn &lt;code&gt;SELECT&lt;/code&gt; không cần &lt;code&gt;FROM&lt;/code&gt; để kiểm thử nhanh, dùng &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt; để tối ưu truy vấn, biểu thức chính quy với ranh giới từ (&lt;code&gt;\b&lt;/code&gt;), và &amp;ldquo;Git pickaxe&amp;rdquo; (&lt;code&gt;git log -S&lt;/code&gt;) để tìm commit thêm/xóa chuỗi cụ thể.&lt;/p&gt;
&lt;p&gt;Bài viết cũng đề cập các tính năng JavaScript hiện đại như &lt;code&gt;Array.flatMap&lt;/code&gt;, &lt;code&gt;Object.entries&lt;/code&gt;, &lt;code&gt;Promise.withResolvers&lt;/code&gt;, và gợi ý dùng &lt;code&gt;ripgrep&lt;/code&gt; thay &lt;code&gt;grep&lt;/code&gt;, glob pattern thay lệnh &lt;code&gt;find&lt;/code&gt;. Tác giả khuyến khích chia sẻ những thủ thuật này trong toàn công ty qua bài đăng hàng ngày trên Slack — cách hiệu quả để xây dựng kiến thức tập thể mà không gây quá tải thông tin.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Những mẩu kiến thức nhỏ, dễ tiếp cận có thể cải thiện năng suất đáng kể ngay lập tức&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fzf&lt;/code&gt; + Ctrl+R cho tìm kiếm lịch sử mờ, &lt;code&gt;atuin&lt;/code&gt; cho lịch sử lệnh dựa trên SQLite&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git log -S&lt;/code&gt; (pickaxe) tìm commit thêm/xóa chuỗi cụ thể, &lt;code&gt;git checkout -&lt;/code&gt; quay về HEAD trước&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt; cho tối ưu truy vấn, &lt;code&gt;ripgrep&lt;/code&gt; thay &lt;code&gt;grep&lt;/code&gt; truyền thống&lt;/li&gt;
&lt;li&gt;Chia sẻ thủ thuật hàng ngày trên Slack giúp xây dựng kiến thức tập thể hiệu quả&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="thủ-thuật-shell-thực-sự-hữu-ích"&gt;&lt;a class="link" href="https://blog.hofstede.it/shell-tricks-that-actually-make-life-easier-and-save-your-sanity/" target="_blank" rel="noopener"
&gt;Thủ thuật shell thực sự hữu ích&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Christian Hofstede-Kuhn chia sẻ bộ sưu tập các phím tắt và thủ thuật terminal mà nhiều lập trình viên bỏ lỡ sau khi học xong &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cd&lt;/code&gt; và &lt;code&gt;grep&lt;/code&gt;. Bài viết chia thành hai phần: thủ thuật hoạt động trên hầu hết shell POSIX và tính năng nâng cao dành cho Bash/Zsh.&lt;/p&gt;
&lt;p&gt;Phần phổ quát bao gồm các phím tắt chỉnh sửa dòng lệnh (Ctrl+W xóa từ, Ctrl+U/K cắt đầu/cuối dòng, Ctrl+Y dán lại), điều hướng thư mục (&lt;code&gt;cd -&lt;/code&gt; chuyển qua lại, &lt;code&gt;pushd&lt;/code&gt;/&lt;code&gt;popd&lt;/code&gt; cho ngăn xếp thư mục), và an toàn khi viết script (&lt;code&gt;set -e&lt;/code&gt; thoát khi lỗi, &lt;code&gt;set -u&lt;/code&gt; báo lỗi biến chưa gán). Phần Bash/Zsh giới thiệu tìm kiếm lịch sử (Ctrl+R), mở trình soạn thảo cho lệnh phức tạp (Ctrl+X rồi Ctrl+E), mở rộng dấu ngoặc nhọn (&lt;code&gt;cp pf.conf{,.bak}&lt;/code&gt;), thay thế tiến trình (&lt;code&gt;diff &amp;lt;(sort file1) &amp;lt;(sort file2)&lt;/code&gt;), và tách tiến trình khỏi shell (&lt;code&gt;disown&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl+W/U/K/Y cho chỉnh sửa dòng lệnh nhanh, Ctrl+A/E nhảy đầu/cuối dòng&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd -&lt;/code&gt; chuyển qua lại thư mục, &lt;code&gt;pushd&lt;/code&gt;/&lt;code&gt;popd&lt;/code&gt; quản lý ngăn xếp thư mục&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set -e&lt;/code&gt; và &lt;code&gt;set -u&lt;/code&gt; là hai dòng an toàn bắt buộc khi viết shell script&lt;/li&gt;
&lt;li&gt;Mở rộng dấu ngoặc nhọn: &lt;code&gt;cp file{,.bak}&lt;/code&gt; sao lưu, &lt;code&gt;mkdir -p project/{src,tests,docs}&lt;/code&gt; tạo nhiều thư mục&lt;/li&gt;
&lt;li&gt;Triết lý: chọn một thủ thuật, ép bản thân dùng một tuần, rồi chọn thủ thuật tiếp theo&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Đầu tư cho AI Coding: Claude Max, Claude Kit và MiniMax</title><link>https://miti99.com/post/2026/04/01/</link><pubDate>Wed, 01 Apr 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/04/01/</guid><description>&lt;p&gt;Sau nhiều lần đắn đo, cuối cùng mình cũng quyết định rút hầu bao để chi cho mấy công cụ AI coding, phục vụ mục đích công việc và cá nhân. À mà tất nhiên đây không phải là một trò đùa ngày Cá tháng Tư rồi 😄&lt;/p&gt;
&lt;h2 id="claude-max"&gt;Claude Max
&lt;/h2&gt;&lt;p&gt;Mình đã dùng Claude khá lâu rồi, cũng đã thử qua Pro từ sớm, đúng là các model Claude rất tốt nhưng mà giá lại quá chát. Nên mình vẫn thường dùng Free, và chi một phần cho các model Trung Quốc hoặc free. Nhưng gần đây Claude Code bùng nổ, và mình thực sự cảm nhận rõ Claude Code kết hợp với các model Claude sẽ vượt trội hơn các model khác nhiều. May mắn (hoặc là không) 2 tuần trước Claude có chính sách x2 token khi ngoài giờ cao điểm. Mà mình dùng bản Pro vẫn rất chật vật. Sau nhiều lần cân nhắc mình quyết định xuống tiền cho Claude Max luôn. Đúng là dùng xuyên suốt cả ngày rất &amp;ldquo;đã&amp;rdquo;, rất &amp;ldquo;phê&amp;rdquo; 😂&lt;/p&gt;
&lt;p&gt;Tất nhiên là mình sẽ cũng dùng Claude để viết blog, hi vọng các bài viết sắp tới sẽ được cải thiện nhiều hơn.&lt;/p&gt;
&lt;h2 id="claude-kit"&gt;Claude Kit
&lt;/h2&gt;&lt;p&gt;Bên cạnh Claude Max, mình cũng mua thêm &lt;a class="link" href="https://claudekit.cc/?ref=BWA910UK" target="_blank" rel="noopener"
&gt;ClaudeKit&lt;/a&gt;. Đây là sản phẩm của &lt;a class="link" href="https://substack.com/@goonnguyen" target="_blank" rel="noopener"
&gt;chú Duy (Zuey)&lt;/a&gt;, mình đã follow từ lâu và rất thích các bài chia sẻ cập nhật tin tức về AI cũng như là các tips sử dụng AI của chú. ClaudeKit là một nền tảng cung cấp các công cụ, prompt templates, workflows và extensions để làm việc với Claude hiệu quả hơn. Đây là sản phẩm tâm huyết gần đây của chú Duy, mình có theo dõi và biết chú có đợt sale off khá lớn dạo Tết, nhưng mà tiếc tiền hông mua. Giờ mua thì giá cao hơn 🥹.&lt;/p&gt;
&lt;p&gt;Trải nghiệm sơ bộ thì ClaudeKit cũng là framework để prompt cho Claude Code như SuperPowers vậy. Nhưng các tool trong &amp;ldquo;hệ sinh thái&amp;rdquo; này kết hợp với nhau rất mượt và hầu như rất đầy đủ. Cảm giác như đây là một bộ công cụ &amp;ldquo;All-in-One&amp;rdquo; vậy, chỉ cần ClaudeKit là đủ. Hi vọng ClaudeKit sẽ giúp mình tận dụng tối đa khả năng của Claude trong quá trình phát triển phần mềm sắp tới. Có thời gian mình sẽ lên bài đánh giá hoặc mẹo khi sử dụng nha (mà cũng chưa biết là khi nào :3)&lt;/p&gt;
&lt;p&gt;Nếu bạn quan tâm, có thể đăng ký qua &lt;a class="link" href="https://claudekit.cc/?ref=BWA910UK" target="_blank" rel="noopener"
&gt;link referral của mình&lt;/a&gt; để được &lt;strong&gt;giảm 20%&lt;/strong&gt; cho lần mua đầu tiên nha!&lt;/p&gt;
&lt;h2 id="minimax-token-plan"&gt;MiniMax Token Plan
&lt;/h2&gt;&lt;p&gt;Ngoài hệ sinh thái Claude, mình cũng đang thử nghiệm &lt;a class="link" href="https://platform.minimax.io/docs/token-plan/intro" target="_blank" rel="noopener"
&gt;&lt;strong&gt;MiniMax Token Plan&lt;/strong&gt;&lt;/a&gt;. MiniMax là một AI platform với các model có khả năng xử lý context dài ấn tượng. Bản M2.7 còn được quảng cáo là có khả năng self-learning, tự học tự cải thiện nữa, cũng khá đáng mong chờ. Mình đang host cho OpenClaw &amp;amp; để cho mấy anh em trong team cũng như em ruột mình kết nối vào để &amp;ldquo;xài đỡ&amp;rdquo; trong lúc hết token Claude Pro. Một người anh trong team feedback với mình là thấy MiniMax cũng được cỡ 7/10 so với Claude. Khá là tiềm năng đó chứ. Anh này đánh giá MiniMax cao hơn Z.ai GLM-5 lúc trước luôn. Mà lúc GLM-5.1 ra mắt thì coding plan của mình cũng gần hết hạn rồi nên không có so sánh nhiều.&lt;/p&gt;
&lt;h2 id="tổng-kết"&gt;Tổng kết
&lt;/h2&gt;&lt;p&gt;Tổng chi phí hàng tháng tăng lên đáng kể, nhưng mình xem đây là khoản đầu tư khá là đáng giá (hoặc vì mình tiếc tiền mà sẽ cố gắng cày để bào nhiều hơn 🤣). Nếu các công cụ này giúp mình code nhanh hơn, ít bug hơn, và tiết kiệm thời gian debug — thì hoàn toàn xứng đáng.&lt;/p&gt;
&lt;p&gt;Sẽ chia sẻ thêm trải nghiệm thực tế sau một thời gian sử dụng. Stay tuned!&lt;/p&gt;</description></item><item><title>Newsletter #93</title><link>https://miti99.com/post/2026/03/28/</link><pubDate>Sat, 28 Mar 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/03/28/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #93.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="bài-học-từ-việc-xây-dựng-claude-code-cách-chúng-tôi-sử-dụng-skills"&gt;&lt;a class="link" href="https://x.com/trq212/status/2033949937936085378" target="_blank" rel="noopener"
&gt;Bài học từ việc xây dựng Claude Code: Cách chúng tôi sử dụng Skills&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Thariq Shihipar, kỹ sư tại Anthropic, chia sẻ những bài học thực tiễn sau khi nhóm nội bộ đã xây dựng và vận hành hàng trăm skills trong Claude Code. Một quan niệm sai lầm phổ biến là skills chỉ là &amp;ldquo;các tệp markdown&amp;rdquo; — nhưng sức mạnh thực sự nằm ở cấu trúc thư mục: skills có thể chứa các tập lệnh (scripts), tài nguyên, và dữ liệu mà agent có thể khám phá và thao tác.&lt;/p&gt;
&lt;p&gt;Bài viết phân loại 9 loại skills phổ biến: tài liệu tham khảo thư viện/API, kiểm thử sản phẩm, lấy và phân tích dữ liệu, tự động hóa quy trình kinh doanh, tạo mã khung (scaffolding), đảm bảo chất lượng mã nguồn, CI/CD và triển khai, runbooks xử lý sự cố, và vận hành hạ tầng. Ngoài ra, tác giả đưa ra các mẹo thiết thực: không nên mô tả những điều hiển nhiên mà hãy tập trung vào những gì thách thức hành vi mặc định của Claude; phần &amp;ldquo;Gotchas&amp;rdquo; (những lỗi bẫy thực tế) là nội dung có giá trị cao nhất trong bất kỳ skill nào; tận dụng hệ thống tệp để lưu trữ scripts và mẫu mã (templates); và trường &lt;code&gt;description&lt;/code&gt; trong skill là để mô tả &lt;em&gt;khi nào&lt;/em&gt; nên kích hoạt skill đó, không phải là mô tả cho người dùng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cấu trúc thư mục của skills mới là nguồn sức mạnh thực sự, không phải nội dung markdown đơn thuần&lt;/li&gt;
&lt;li&gt;Phần &amp;ldquo;Gotchas&amp;rdquo; tích lũy từ thất bại thực tế là phần có giá trị nhất trong một skill&lt;/li&gt;
&lt;li&gt;Lưu cấu hình người dùng vào &lt;code&gt;config.json&lt;/code&gt; và dùng &lt;code&gt;AskUserQuestion&lt;/code&gt; khi chưa được cấu hình&lt;/li&gt;
&lt;li&gt;Skills có thể kết hợp với nhau (compose) — một skill có thể tham chiếu skill khác, tạo thành chuỗi phụ thuộc&lt;/li&gt;
&lt;li&gt;Đo lường mức độ sử dụng skills qua hook &lt;code&gt;PreToolUse&lt;/code&gt; để theo dõi độ phổ biến&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tương-lai-của-kỹ-thuật-phần-mềm-cùng-anthropic"&gt;&lt;a class="link" href="https://www.akashbajwa.co/p/the-future-of-software-engineering" target="_blank" rel="noopener"
&gt;Tương lai của Kỹ thuật Phần mềm cùng Anthropic&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Akash Bajwa tổng hợp buổi thảo luận bàn tròn với Ash Prabaker từ Anthropic và các kỹ sư cấp cao từ Stripe, NVIDIA, Microsoft, Google DeepMind, xAI, Apple, Scale AI và OpenAI — cùng nhau nhìn nhận cách AI đang thay đổi ngành phát triển phần mềm. Claude Code ra đời cuối năm 2024 từ một giao diện dòng lệnh đơn giản, được thiết kế hướng tới các khả năng tương lai thay vì giới hạn hiện tại, và đạt được mức độ áp dụng rộng rãi thông qua giá trị thực chứng minh.&lt;/p&gt;
&lt;p&gt;Vòng lặp cải tiến đệ quy là điểm nổi bật: công cụ lập trình tốt hơn tạo ra mô hình tốt hơn, mô hình tốt hơn lại tạo ra công cụ tốt hơn. Trong thực tế, nhiều công ty đã triển khai hệ thống tự động phân loại lỗi và tạo pull request. Tuy nhiên, các thách thức chưa được giải quyết gồm: quản lý tác vụ dài hạn (multi-hour agent runs) trong khi vẫn duy trì sự giám sát của con người, và rủi ro hội tụ khi toàn ngành dùng cùng một mô hình dẫn đến các giải pháp đồng nhất.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quy trình &amp;ldquo;kiểm thử trước&amp;rdquo; (test-first) đang trở thành tiêu chuẩn khi làm việc với AI&lt;/li&gt;
&lt;li&gt;Review code của con người đang trở thành nút thắt cổ chai thay vì biện pháp bảo vệ&lt;/li&gt;
&lt;li&gt;Các tổ chức ưu tiên tuyển kỹ sư sẵn sàng thử nghiệm ở ranh giới kỹ thuật hơn là kỹ năng viết mã thuần túy&lt;/li&gt;
&lt;li&gt;Tài liệu do con người viết vẫn rất quan trọng; tài liệu lỗi thời hoặc do AI tạo ra làm giảm hiệu quả của AI&lt;/li&gt;
&lt;li&gt;AI chưa thâm nhập được vào các ngành có quy định chặt chẽ như luật pháp — vẫn cần con người trong vòng lặp&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="5-quy-tắc-lập-trình-của-rob-pike"&gt;&lt;a class="link" href="https://www.cs.unc.edu/~stotts/COMP590-059-f24/robsrules.html" target="_blank" rel="noopener"
&gt;5 Quy tắc Lập trình của Rob Pike&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Rob Pike, đồng tác giả ngôn ngữ Go và huyền thoại tại Bell Labs, để lại 5 quy tắc lập trình ngắn gọn nhưng cực kỳ súc tích, được giảng dạy trong khóa học COMP590 tại Đại học UNC. Cốt lõi của cả 5 quy tắc xoay quanh hai chủ đề lớn: đừng tối ưu hóa sớm và hãy giữ mọi thứ đơn giản. Quy tắc 1 và 2 nhắc nhở rằng bạn không thể đoán trước điểm nghẽn cổ chai — hãy đo lường trước khi tối ưu. Quy tắc 3 và 4 cảnh báo rằng các thuật toán phức tạp thường chậm hơn và dễ có lỗi hơn với dữ liệu nhỏ, vốn là trường hợp phổ biến trong thực tế. Quy tắc 5 là tinh hoa: cấu trúc dữ liệu mới là trung tâm của lập trình — chọn đúng cấu trúc dữ liệu, thuật toán sẽ tự hiện ra.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5 quy tắc:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Quy tắc 1:&lt;/strong&gt; Bạn không thể đoán được chương trình sẽ tốn thời gian ở đâu — đừng tối ưu hóa khi chưa chứng minh đó là điểm nghẽn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quy tắc 2:&lt;/strong&gt; Hãy đo lường trước khi điều chỉnh tốc độ, và chỉ làm vậy khi một phần mã áp đảo phần còn lại&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quy tắc 3:&lt;/strong&gt; Thuật toán phức tạp chậm khi n nhỏ, mà n thường là nhỏ — đừng phức tạp hóa cho đến khi bạn biết chắc n thường xuyên lớn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quy tắc 4:&lt;/strong&gt; Thuật toán phức tạp dễ có lỗi hơn và khó triển khai hơn — hãy dùng thuật toán đơn giản và cấu trúc dữ liệu đơn giản&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quy tắc 5:&lt;/strong&gt; Dữ liệu quyết định tất cả — cấu trúc dữ liệu, không phải thuật toán, mới là trung tâm của lập trình&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="giới-thiệu-về-index-trong-postgresql"&gt;&lt;a class="link" href="https://dlt.github.io/blog/posts/introduction-to-postgresql-indexes/" target="_blank" rel="noopener"
&gt;Giới thiệu về Index trong PostgreSQL&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết toàn diện của Dalto Curvelano giải thích cơ chế nội tại của index trong PostgreSQL — từ cách dữ liệu được lưu trữ trong các trang 8KB (heap), cho đến các loại index khác nhau và khi nào nên dùng loại nào. Nguyên tắc thực tiễn đầu tiên cần nhớ: index chỉ có ích khi truy vấn trả về ít hơn 15-20% số hàng trong bảng; vượt qua ngưỡng này, PostgreSQL thường ưu tiên quét tuần tự hơn. Minh chứng rõ ràng: một bảng 1 triệu hàng mất 265ms khi quét tuần tự, nhưng chỉ 0,077ms sau khi thêm index.&lt;/p&gt;
&lt;p&gt;Bài viết trình bày 5 loại index chính: B-Tree (mặc định, đa năng nhất, O(log n)), Hash (chỉ cho phép so sánh bằng, nhỏ hơn B-Tree với dữ liệu dài như UUID), BRIN (cực kỳ nhỏ gọn, phù hợp dữ liệu chuỗi thời gian), GIN (toàn văn, mảng, JSONB), và GiST/SP-GiST (kiểu hình học, khoảng giá trị). Đặc biệt chú ý đến partial index (chỉ đánh index một tập con hàng), covering index với &lt;code&gt;INCLUDE&lt;/code&gt; (tránh quay lại heap), và expression index (đánh index kết quả của hàm).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chỉ thêm index khi truy vấn trả về dưới 15-20% số hàng; không nên đánh index bừa bãi&lt;/li&gt;
&lt;li&gt;Mỗi index đều có chi phí: tốn dung lượng đĩa, làm chậm INSERT/UPDATE/DELETE, tốn bộ nhớ&lt;/li&gt;
&lt;li&gt;B-Tree là lựa chọn mặc định; các loại khác chỉ dùng cho trường hợp đặc thù&lt;/li&gt;
&lt;li&gt;Partial index và covering index (&lt;code&gt;INCLUDE&lt;/code&gt;) là công cụ mạnh để giảm kích thước và tăng hiệu năng&lt;/li&gt;
&lt;li&gt;PostgreSQL 18 giới thiệu Skip Scan, giúp dùng index nhiều cột mà không cần lọc theo cột đầu tiên&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="dùng-rust-và-postgresql-cho-mọi-thứ-các-mẫu-học-được-qua-nhiều-năm"&gt;&lt;a class="link" href="https://kerkour.com/rust-postgres-everything" target="_blank" rel="noopener"
&gt;Dùng Rust và PostgreSQL cho Mọi thứ: Các mẫu học được qua nhiều năm&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Sylvain Kerkour chia sẻ kinh nghiệm thực tiễn khi dùng Rust và PostgreSQL làm nền tảng chính cho toàn bộ hệ thống backend — thay thế nhiều công cụ hạ tầng phức tạp. Minh chứng nổi bật: một dịch vụ backend được viết lại từ Go sang Rust giảm thời gian xử lý từ ~30 phút xuống dưới 5 phút, giảm RAM từ 4GB xuống 512MB, và loại bỏ hoàn toàn lỗi nil pointer nhờ mô hình bộ nhớ của Rust.&lt;/p&gt;
&lt;p&gt;Các mẫu thiết kế chính bao gồm: dùng &lt;code&gt;sqlx&lt;/code&gt; thay vì ORM để cân bằng giữa đơn giản, hiệu năng và kiểm tra SQL lúc biên dịch; gom ghi dữ liệu thành batch tối đa 10.000 hàng với &lt;code&gt;UNNEST&lt;/code&gt;; dùng &lt;code&gt;pg_try_advisory_lock()&lt;/code&gt; để bầu chọn leader trong hệ thống phân tán mà không cần ZooKeeper hay Redis; thay Redis bằng unlogged tables của PostgreSQL cho dữ liệu tạm thời; và dùng PostgreSQL làm hàng đợi công việc với &lt;code&gt;FOR UPDATE SKIP LOCKED&lt;/code&gt; kết hợp UUID v7.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sqlx&lt;/code&gt; là lựa chọn tốt hơn ORM: đơn giản, hiệu năng cao, kiểm tra SQL lúc biên dịch&lt;/li&gt;
&lt;li&gt;PostgreSQL advisory locks thay thế ZooKeeper/Redis cho bầu chọn leader phân tán&lt;/li&gt;
&lt;li&gt;Unlogged tables nhanh hơn cho dữ liệu tạm — loại bỏ Redis như một dependency riêng biệt&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FOR UPDATE SKIP LOCKED&lt;/code&gt; + UUID v7 biến PostgreSQL thành hàng đợi công việc đáng tin cậy&lt;/li&gt;
&lt;li&gt;Triết lý cốt lõi: đơn giản hóa hạ tầng = tiết kiệm chi phí và linh hoạt vận hành&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="kiểm-soát-không-lưu-câu-chuyện-về-ibm-9020"&gt;&lt;a class="link" href="https://computer.rip/2026-01-17-air-traffic-control-9020.html" target="_blank" rel="noopener"
&gt;Kiểm soát Không lưu: Câu chuyện về IBM 9020&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;J. B. Crawford kể lại lịch sử của IBM 9020 — hệ thống máy tính đa bộ xử lý tiên phong được FAA (Cục Hàng không Liên bang Mỹ) đưa vào kiểm soát không lưu quốc gia từ năm 1967. Trước đó, hệ thống SAGE vốn được thiết kế cho phòng thủ quân sự đã được tái sử dụng cho kiểm soát không lưu dân sự, nhưng có nhiều điểm yếu nghiêm trọng: không kiểm tra tính duy nhất của phân vùng độ cao, không phát hiện va chạm giữa các máy bay.&lt;/p&gt;
&lt;p&gt;IBM 9020 giải quyết vấn đề này bằng kiến trúc gồm 6-7 máy tính S/360 liên kết qua bộ nhớ dùng chung, với chương trình điều khiển thời gian thực quản lý hàng trăm thiết bị ngoại vi. Điểm nổi bật là khả năng chịu lỗi: chương trình OEAP tự động chẩn đoán và cấu hình lại hệ thống khi có lỗi phần cứng mà không gián đoạn hoạt động kiểm soát không lưu. Hệ thống hoạt động đến giữa thập niên 1980, chứng minh rằng phần cứng thương mại có thể được thiết kế cho ứng dụng an toàn tính mạng nếu có kỹ thuật phần mềm và dự phòng đủ tốt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IBM 9020 ra đời để khắc phục các lỗ hổng an toàn của hệ thống SAGE khi dùng cho kiểm soát không lưu dân sự&lt;/li&gt;
&lt;li&gt;Kiến trúc đa máy tính liên kết qua bộ nhớ dùng chung, xử lý thời gian thực với hàng trăm thiết bị ngoại vi&lt;/li&gt;
&lt;li&gt;Khả năng tự động chẩn đoán và cấu hình lại khi lỗi phần cứng — không gián đoạn hoạt động&lt;/li&gt;
&lt;li&gt;Hoạt động từ 1967 đến giữa thập niên 1980, một số hệ thống hiển thị còn dùng đến thập niên 1990&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sfq-thuật-toán-hàng-đợi-công-bằng-đơn-giản-và-phi-trạng-thái"&gt;&lt;a class="link" href="https://brooker.co.za/blog/2026/02/25/sfq.html" target="_blank" rel="noopener"
&gt;SFQ: Thuật toán Hàng đợi Công bằng Đơn giản và Phi trạng thái&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Marc Brooker giới thiệu Stochastic Fairness Queuing (SFQ) — một trong những thuật toán ông yêu thích nhất cho hệ thống phân tán. Ý tưởng cốt lõi: thay vì duy trì một hàng đợi riêng cho từng khách hàng (tốn O(n) hàng đợi, không thực tế ở quy mô lớn), SFQ dùng một tập hàng đợi cố định O(1) và ánh xạ khách hàng vào hàng đợi thông qua hàm băm. Thách thức là hai khách hàng có thể băm vào cùng một hàng đợi (va chạm) và liên tục &amp;ldquo;cạnh tranh&amp;rdquo; với nhau. Giải pháp: định kỳ thay đổi hàm băm để các va chạm bị phân tán theo thời gian, đạt được sự công bằng thống kê.&lt;/p&gt;
&lt;p&gt;Bài viết còn trình bày biến thể nâng cao kết hợp SFQ với shuffle sharding và best-of-two choices: mỗi khách hàng được ánh xạ vào một tập con hàng đợi, mỗi yêu cầu được định tuyến đến hàng đợi ngắn nhất trong tập đó. Kết quả: thao tác enqueue và dequeue đều O(1), đồng thời cách ly hiệu quả các &amp;ldquo;noisy neighbor&amp;rdquo; trong môi trường đa người dùng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SFQ đạt được sự công bằng mà không cần lưu trạng thái theo từng khách hàng — rất phù hợp cho hệ thống phân tán quy mô lớn&lt;/li&gt;
&lt;li&gt;Định kỳ thay đổi hàm băm là bước bắt buộc để tránh va chạm dai dẳng&lt;/li&gt;
&lt;li&gt;Kết hợp SFQ + shuffle sharding + best-of-two cho hiệu quả cách ly &amp;ldquo;noisy neighbor&amp;rdquo; mạnh mẽ&lt;/li&gt;
&lt;li&gt;Cả enqueue lẫn dequeue đều chạy trong O(1) — hiệu quả tính toán cao&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="cpu-của-bạn-có-thể-dự-đoán-bao-nhiêu-nhánh-lệnh"&gt;&lt;a class="link" href="https://lemire.me/blog/2026/03/18/how-many-branches-can-your-cpu-predict/" target="_blank" rel="noopener"
&gt;CPU của bạn có thể dự đoán bao nhiêu nhánh lệnh?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Daniel Lemire thực hiện một thí nghiệm thú vị để đo giới hạn của bộ dự đoán nhánh (branch predictor) trên các CPU hiện đại. Ý tưởng: dùng một vòng lặp với chuỗi ngẫu nhiên cố định (seed cố định), nếu CPU đủ thông minh để &amp;ldquo;ghi nhớ&amp;rdquo; toàn bộ chuỗi thì nó sẽ dự đoán đúng gần 100% các nhánh. Bằng cách tăng dần độ dài chuỗi, ta tìm được điểm mà bộ dự đoán bắt đầu &amp;ldquo;hết bộ nhớ&amp;rdquo;. Kết quả khá bất ngờ: AMD Zen 5 dự đoán được ~30.000 nhánh, Apple M4 ~10.000, còn Intel Emerald Rapids chỉ ~5.000 — tức là Zen 5 mạnh gấp 6 lần Intel trong chỉ số này.&lt;/p&gt;
&lt;p&gt;Điều này có ý nghĩa thực tiễn quan trọng với việc benchmark: nếu tập dữ liệu kiểm thử đủ nhỏ để nằm trong giới hạn của bộ dự đoán, CPU sẽ &amp;ldquo;học thuộc&amp;rdquo; kết quả và cho ra con số hiệu năng lạc quan hơn thực tế nhiều. Kết quả benchmark đẹp không có nghĩa là mã của bạn thực sự nhanh trong môi trường sản xuất với dữ liệu đa dạng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AMD Zen 5 dẫn đầu với ~30.000 nhánh, gấp 6 lần Intel Emerald Rapids (~5.000)&lt;/li&gt;
&lt;li&gt;Vượt quá giới hạn này, độ chính xác dự đoán giảm về ~50% (tương đương đoán ngẫu nhiên)&lt;/li&gt;
&lt;li&gt;Benchmark với tập dữ liệu nhỏ, lặp lại có thể khiến kết quả bị thổi phồng do CPU &amp;ldquo;học thuộc&amp;rdquo; pattern&lt;/li&gt;
&lt;li&gt;Cần dùng tập dữ liệu đủ lớn và đa dạng để có kết quả đo lường phản ánh thực tế&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bonus"&gt;Bonus
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Images:&lt;/strong&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!tS1T!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958d36d9-6b19-4949-b6a6-6aa614ede834_2508x2960.jpeg"
loading="lazy"
alt="Different Types of Tests"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!c4WE!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd86cd367-494f-4031-9793-f27e6142e54b_2508x3000.png"
loading="lazy"
alt="How Single Sign-On (SSO) Works"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!em-f!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e7e23e9-2a5a-4b06-a3fa-ccb6c5493f1d_2508x3000.png"
loading="lazy"
alt="How LLMs Use AI Agents with Deep Research"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!kRPi!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d3b2bb9-fc09-48d9-89b7-52bc37098af9_2360x2960.png"
loading="lazy"
alt="How hackers steal passwords"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #92</title><link>https://miti99.com/post/2026/03/20/</link><pubDate>Fri, 20 Mar 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/03/20/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #92.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="tôi-đã-trở-nên-giỏi-xử-lý-sự-cố-như-thế-nào"&gt;&lt;a class="link" href="https://tomasztomczyk.com/blog/2026/how-i-became-good-at-leading-incidents/" target="_blank" rel="noopener"
&gt;Tôi đã trở nên giỏi xử lý sự cố như thế nào&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tomasz Tomczyk chia sẻ những bài học từ hơn 100 sự cố mà anh đã dẫn dắt trong suốt sự nghiệp, nhấn mạnh rằng quản lý sự cố không chỉ là kỹ năng kỹ thuật mà còn là tư duy phân tích và khả năng lãnh đạo dưới áp lực. Anh cho rằng mỗi sự cố là cơ hội để hiểu sâu hơn về hệ thống và xây dựng văn hóa học hỏi từ thất bại.&lt;/p&gt;
&lt;p&gt;Để xử lý sự cố hiệu quả, bạn cần nắm vững quy trình triển khai và toàn bộ ngăn xếp công nghệ từ DNS đến tầng ứng dụng, đồng thời thiết lập hệ thống giám sát toàn diện. Khi xảy ra sự cố, hãy phân công điều tra theo từng chủ đề cụ thể, đưa ra quyết định dứt khoát khi cần vô hiệu hóa tính năng, và cung cấp thông tin cập nhật kịp thời cho các bên liên quan. Việc lập tài liệu các mẫu lỗi phổ biến vào runbook và thực hành qua các bài tập chaos engineering cũng giúp đội nhóm chuẩn bị tốt hơn cho các tình huống thực tế.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nắm vững quy trình triển khai và toàn bộ ngăn xếp công nghệ để nhanh chóng xác định nguyên nhân sự cố&lt;/li&gt;
&lt;li&gt;Đọc hiểu stack trace và sử dụng công cụ theo dõi lỗi như Sentry để điều tra sâu hơn&lt;/li&gt;
&lt;li&gt;Xây dựng văn hóa tâm lý an toàn để thất bại trở thành cơ hội học hỏi&lt;/li&gt;
&lt;li&gt;Phân công điều tra chiến lược và đưa ra quyết định dứt khoát trong thời điểm căng thẳng&lt;/li&gt;
&lt;li&gt;Lập tài liệu runbook và thực hành game day để chuẩn bị cho các sự cố thực tế&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="decision-trees-sức-mạnh-bất-ngờ-của-các-quy-tắc-quyết-định-lồng-nhau"&gt;&lt;a class="link" href="https://mlu-explain.github.io/decision-tree/" target="_blank" rel="noopener"
&gt;Decision Trees: Sức mạnh bất ngờ của các quy tắc quyết định lồng nhau&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Decision Tree (cây quyết định) là thuật toán học có giám sát được dùng cho cả bài toán phân loại lẫn hồi quy. Thuật toán hoạt động bằng cách phân chia dữ liệu đệ quy theo các quy tắc điều kiện, tạo ra cấu trúc cây trong đó mỗi lần phân chia nhằm tách biệt các nhóm dữ liệu hiệu quả nhất. Phương pháp huấn luyện cốt lõi là thuật toán ID3, chọn điểm phân chia bằng cách tối đa hóa information gain — tức là mức giảm entropy sau khi phân vùng dữ liệu.&lt;/p&gt;
&lt;p&gt;Decision Tree có nhiều ưu điểm nổi bật: dễ diễn giải, huấn luyện nhanh, cần ít tiền xử lý dữ liệu và xử lý tốt các giá trị ngoại lệ. Tuy nhiên, nhược điểm lớn nhất là tính bất ổn định — chỉ một thay đổi nhỏ trong dữ liệu có thể khiến cấu trúc cây thay đổi hoàn toàn, dẫn đến hiện tượng overfitting. Để khắc phục, người ta thường dùng kỹ thuật pruning như giới hạn độ sâu tối đa hoặc đặt ngưỡng số lượng mẫu tối thiểu tại lá.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Decision Tree phân chia dữ liệu đệ quy, chọn điểm phân chia dựa trên information gain và entropy&lt;/li&gt;
&lt;li&gt;Ưu điểm: dễ diễn giải, huấn luyện nhanh, ít cần tiền xử lý, chịu tốt giá trị ngoại lệ&lt;/li&gt;
&lt;li&gt;Nhược điểm lớn: bất ổn định cao, dễ bị overfitting khi dữ liệu thay đổi nhỏ&lt;/li&gt;
&lt;li&gt;Pruning (cắt tỉa cây) là kỹ thuật phổ biến để kiểm soát overfitting&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="container-không-phải-là-ranh-giới-bảo-mật"&gt;&lt;a class="link" href="https://www.lucavall.in/blog/containers-are-not-a-security-boundary" target="_blank" rel="noopener"
&gt;Container không phải là ranh giới bảo mật&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Luca Cavallin lập luận rằng container hóa tự bản thân không đảm bảo an toàn — container về bản chất chỉ là các tiến trình Linux với các lớp cô lập, không phải hệ thống tách biệt hoàn toàn. Chúng vẫn chia sẻ kernel của máy chủ, tạo ra bề mặt tấn công chung giữa các workload. Điều này có nghĩa là các mối đe dọa bảo mật truyền thống vẫn áp dụng đầy đủ cho môi trường container.&lt;/p&gt;
&lt;p&gt;Bảo mật container hiệu quả đòi hỏi áp dụng các nguyên tắc cơ bản: đặc quyền tối thiểu, phòng thủ nhiều lớp và giảm thiểu bề mặt tấn công. Cụ thể, cần hạn chế syscall và capabilities ở cấp kernel, dùng cgroups để giới hạn tài nguyên, triển khai seccomp/AppArmor/SELinux để kiểm soát truy cập bắt buộc. Ngoài ra, bảo mật chuỗi cung ứng cũng quan trọng: dùng base image đáng tin cậy, ghim digest, quét lỗ hổng và kiểm soát admission. Với mã nguồn không đáng tin cậy, máy ảo vẫn cung cấp mức cô lập mạnh hơn container.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Container chỉ là tiến trình Linux, chia sẻ kernel máy chủ — không phải ranh giới bảo mật thực sự&lt;/li&gt;
&lt;li&gt;Áp dụng nguyên tắc đặc quyền tối thiểu: chạy container không phải root, bỏ các capabilities không cần thiết&lt;/li&gt;
&lt;li&gt;Dùng seccomp, AppArmor, SELinux để kiểm soát truy cập ở cấp kernel&lt;/li&gt;
&lt;li&gt;Bảo vệ chuỗi cung ứng: base image đáng tin cậy, ghim digest, quét lỗ hổng định kỳ&lt;/li&gt;
&lt;li&gt;Máy ảo phù hợp hơn cho mã nguồn không đáng tin cậy; container phù hợp cho dịch vụ nội bộ đã kiểm soát&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bài-ca-ngợi-bzip"&gt;&lt;a class="link" href="https://purplesyringa.moe/blog/an-ode-to-bzip/" target="_blank" rel="noopener"
&gt;Bài ca ngợi bzip&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả purplesyringa khám phá lý do tại sao bzip vẫn vượt trội so với các thuật toán nén hiện đại cho dữ liệu văn bản và mã nguồn, dù đã bị lãng quên. Qua thực nghiệm nén một codebase Lua 327 KB trong mod ComputerCraft, bzip2 đạt 63.727 byte — tốt hơn gzip, zstd, xz, brotli và lzip; trong khi bzip3 còn đạt 61.067 byte.&lt;/p&gt;
&lt;p&gt;Ưu thế của bzip đến từ cách tiếp cận thuật toán khác biệt căn bản: thay vì dùng LZ77 dựa trên tham chiếu như phần lớn các công cụ nén phổ biến, bzip dùng BWT (Burrows-Wheeler Transform) để sắp xếp lại ký tự theo ngữ cảnh, giúp nén hiệu quả hơn với dữ liệu dạng văn bản. Ngoài ra, một bộ giải nén bzip2 tối giản chỉ cần khoảng 1,5 KB, rất phù hợp cho các ứng dụng nhúng nơi kích thước mã nguồn cũng quan trọng không kém tỉ lệ nén.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;bzip2 và bzip3 nén dữ liệu văn bản/mã nguồn tốt hơn gzip, zstd, xz, brotli trong thực nghiệm&lt;/li&gt;
&lt;li&gt;Thuật toán BWT sắp xếp lại ký tự theo ngữ cảnh, khác biệt căn bản so với LZ77&lt;/li&gt;
&lt;li&gt;Bộ giải nén bzip2 tối giản chỉ ~1,5 KB, phù hợp cho môi trường nhúng&lt;/li&gt;
&lt;li&gt;bzip cho kết quả xác định và tối ưu, không dựa vào heuristic&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tại-sao-các-kiến-trúc-sư-hệ-thống-mặc-định-chọn-arm-cho-trung-tâm-dữ-liệu-ai"&gt;&lt;a class="link" href="https://newsroom.arm.com/blog/why-system-architects-default-to-arm-in-ai-data-centers" target="_blank" rel="noopener"
&gt;Tại sao các kiến trúc sư hệ thống mặc định chọn Arm cho trung tâm dữ liệu AI&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Arm đang trở thành lựa chọn mặc định cho hạ tầng AI khi các trung tâm dữ liệu chuyển dịch sang các hệ thống chuyên dụng cấp rack được thiết kế riêng cho workload AI. Kiến trúc Arm mang lại hiệu quả năng lượng vượt trội so với x86 truyền thống, đặc biệt phù hợp với các tác vụ suy luận liên tục và ứng dụng AI tác nhân — những use case đòi hỏi mẫu điện toán liên tục và thích ứng.&lt;/p&gt;
&lt;p&gt;Xu hướng này phản ánh sự thay đổi lớn trong ngành: thay vì dùng máy chủ đa năng, các tổ chức ngày càng xây dựng hạ tầng AI chuyên biệt từ cấp rack trở lên. Arm được các kiến trúc sư hệ thống ưa chuộng nhờ khả năng mở rộng quy mô hiệu quả hơn, sử dụng tài nguyên tốt hơn, và ngày càng nhiều bộ xử lý AI dẫn đầu thị trường được xây dựng trên nền Arm — điều này cho thấy sự xác nhận rộng rãi của ngành về khả năng cạnh tranh của kiến trúc này.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trung tâm dữ liệu AI chuyển sang hệ thống chuyên dụng cấp rack, ưu tiên Arm thay cho x86 đa năng&lt;/li&gt;
&lt;li&gt;Arm vượt trội về hiệu quả năng lượng khi mở rộng quy mô cho workload AI&lt;/li&gt;
&lt;li&gt;Phù hợp đặc biệt với suy luận liên tục và ứng dụng AI tác nhân&lt;/li&gt;
&lt;li&gt;Xu hướng cho thấy sự xác nhận toàn ngành về Arm trong hạ tầng AI cao cấp&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="redis-xây-dựng-agent-skill-để-ai-viết-mã-redis-như-chuyên-gia"&gt;&lt;a class="link" href="https://redis.io/blog/we-built-an-agent-skill-so-ai-writes-redis-code/" target="_blank" rel="noopener"
&gt;Redis xây dựng Agent Skill để AI viết mã Redis như chuyên gia&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Redis đã tạo ra một &lt;strong&gt;Agent Skill&lt;/strong&gt; — tệp markdown mã hóa kiến thức chuyên sâu về Redis — để các tác nhân AI như Claude Code, Cursor, Copilot có thể sinh ra mã Redis theo đúng cách của chuyên gia. Vấn đề cốt lõi là các mô hình ngôn ngữ lớn được huấn luyện trên dữ liệu cũ thường sinh mã theo kiểu Redis 6, bỏ lỡ các tính năng hiện đại như vector sets, hỗ trợ JSON, query engine hay LangCache. Ngoài ra, tác nhân AI còn dễ mắc lỗi kiến trúc như không dùng sliding window cho rate limiter, thiếu bảo vệ chống cache stampede, hay bỏ qua cơ hội dùng pipelining.&lt;/p&gt;
&lt;p&gt;Agent Skill cung cấp cho tác nhân AI các mẫu đúng cho các use case phổ biến (caching, rate limiting, session management, vector search&amp;hellip;), hướng dẫn chọn cấu trúc dữ liệu phù hợp, và cảnh báo các anti-pattern nguy hiểm như dùng &lt;code&gt;KEYS *&lt;/code&gt; trong vòng lặp hay để key tăng trưởng không giới hạn. Đây là tệp markdown có thể quản lý bằng git, chia sẻ qua nhóm, và tương thích với nhiều tác nhân AI khác nhau theo một tiêu chuẩn mở.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LLM sinh mã Redis theo kiểu cũ (Redis 6), bỏ lỡ các tính năng và mẫu hiện đại&lt;/li&gt;
&lt;li&gt;Agent Skill là tệp markdown mã hóa kiến thức chuyên sâu, được tải theo yêu cầu khi tác nhân gặp tác vụ liên quan&lt;/li&gt;
&lt;li&gt;Cung cấp mẫu đúng cho caching, rate limiting, session management, vector search và nhiều use case khác&lt;/li&gt;
&lt;li&gt;Ngăn các anti-pattern nguy hiểm: &lt;code&gt;KEYS *&lt;/code&gt; trong vòng lặp, key tăng trưởng không giới hạn, chọn sai cấu trúc dữ liệu&lt;/li&gt;
&lt;li&gt;Có thể quản lý bằng git, chia sẻ qua nhóm, tương thích với nhiều tác nhân AI&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bên-trong-archive-công-nghệ-đằng-sau-spotify-wrapped-2025"&gt;&lt;a class="link" href="https://engineering.atspotify.com/2026/3/inside-the-archive-2025-wrapped" target="_blank" rel="noopener"
&gt;Bên trong Archive: Công nghệ đằng sau Spotify Wrapped 2025&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Đội ngũ kỹ thuật Spotify chia sẻ cách họ xây dựng hệ thống AI tạo ra các báo cáo cá nhân hóa cho tính năng Archive trong Wrapped 2025. Thay vì chỉ hiển thị số liệu thống kê, Archive xác định tối đa 5 &amp;ldquo;ngày đáng nhớ&amp;rdquo; từ lịch sử nghe nhạc của mỗi người dùng và dùng LLM để tạo ra các câu chuyện sáng tạo dựa trên dữ liệu nghe nhạc thực. Hệ thống đã tạo ra khoảng 1,4 tỷ báo cáo được tạo sẵn cho 350 triệu người dùng đủ điều kiện, đòi hỏi duy trì hàng nghìn yêu cầu mỗi giây trong nhiều ngày trước khi ra mắt.&lt;/p&gt;
&lt;p&gt;Về mặt kỹ thuật, họ dùng hệ thống dựa trên heuristic để xác định các khoảnh khắc nghe nhạc đáng chú ý, kết hợp pipeline dữ liệu phân tán với hàng đợi tin nhắn để xử lý bất đồng bộ. Để tối ưu chi phí và chất lượng, họ áp dụng model distillation thu nhỏ các mô hình frontier lớn thành phiên bản sản xuất nhỏ hơn, rồi dùng DPO kết hợp đánh giá của con người. Kiểm soát chất lượng được thực hiện bằng cách đánh giá ~165.000 báo cáo mẫu qua &amp;ldquo;LLM as a judge&amp;rdquo; theo các tiêu chí độ chính xác, an toàn, giọng văn và định dạng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tạo 1,4 tỷ báo cáo cá nhân hóa cho 350 triệu người dùng, duy trì hàng nghìn yêu cầu/giây&lt;/li&gt;
&lt;li&gt;Heuristic xác định các khoảnh khắc đáng nhớ; LLM tạo câu chuyện từ dữ liệu thực&lt;/li&gt;
&lt;li&gt;Model distillation + DPO giúp giảm chi phí nhưng vẫn giữ chất lượng cao&lt;/li&gt;
&lt;li&gt;&amp;ldquo;LLM as a judge&amp;rdquo; đánh giá 165.000 báo cáo mẫu theo độ chính xác, an toàn, giọng văn&lt;/li&gt;
&lt;li&gt;Pre-scale hạ tầng và load test theo vùng địa lý để sẵn sàng cho làn sóng truy cập tức thì khi ra mắt&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="quản-lý-nhiều-tác-nhân-ai"&gt;&lt;a class="link" href="https://fffej.substack.com/p/managing-multiple-agents" target="_blank" rel="noopener"
&gt;Quản lý nhiều tác nhân AI&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Jeff khám phá cách các phong cách quản lý khác nhau áp dụng cho việc điều phối nhiều tác nhân AI, thông qua kịch bản lắp ráp tủ sách Ikea với bốn tác nhân chuyên biệt: đọc hướng dẫn, quản lý phụ tùng, lắp ráp và kiểm tra chất lượng. Bốn phong cách quản lý được so sánh: Command and Control (phê duyệt từng hành động), Taylorism (chia nhỏ công việc thành các tác vụ chuẩn hóa), Quản lý theo kết quả, và Tự trị hoàn toàn.&lt;/p&gt;
&lt;p&gt;Kết quả thú vị nhất là quản lý theo kết quả — định nghĩa mục tiêu thay vì quy định từng bước — nhanh hơn 5 lần so với Command and Control và 3 lần so với Taylorism. Đáng chú ý, cách này còn tạo ra &amp;ldquo;mở rộng vai trò tự nhiên&amp;rdquo;: tác nhân quản lý phụ tùng tự nhận ra lắp ráp là nút thắt cổ chai và bắt đầu hỗ trợ dù không được chỉ định. Ngược lại, tự trị hoàn toàn dẫn đến các tác nhân &amp;ldquo;quẫy đạp&amp;rdquo;, trùng lặp công việc — minh chứng cho nhận xét của Kent Beck: &amp;ldquo;Tự trị không có ràng buộc là hỗn loạn.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bốn phong cách: Command and Control, Taylorism, quản lý theo kết quả, tự trị hoàn toàn&lt;/li&gt;
&lt;li&gt;Quản lý theo kết quả hiệu quả nhất: nhanh hơn 5x so với Command and Control&lt;/li&gt;
&lt;li&gt;Tự trị hoàn toàn gây ra trùng lặp công việc và hỗn loạn khi thiếu ràng buộc&lt;/li&gt;
&lt;li&gt;Tác nhân AI có khả năng mở rộng vai trò tự nhiên khi được trao quyền tự quyết theo mục tiêu&lt;/li&gt;
&lt;li&gt;Điều phối tác nhân AI phản chiếu quản lý nhóm người: nhóm giỏi cần mục tiêu rõ ràng, không cần vi quản lý&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Newsletter #91</title><link>https://miti99.com/post/2026/03/17/</link><pubDate>Tue, 17 Mar 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/03/17/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #91.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="how-go-slices-work-under-the-hood-what-makes-them-stand-out-from-other-languages"&gt;&lt;a class="link" href="https://dev.to/ganesh-kumar/how-go-slices-work-under-the-hood-what-makes-them-stand-out-from-other-languages-42o4" target="_blank" rel="noopener"
&gt;How Go Slices Work Under the Hood: What Makes Them Stand Out from Other Languages&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giải thích cách slice trong Go hoạt động bên trong — một trong những cấu trúc dữ liệu quan trọng nhất của ngôn ngữ này. Không giống như mảng thông thường, slice trong Go là một cấu trúc gồm ba thành phần: con trỏ trỏ đến mảng nền bên dưới, độ dài hiện tại (&lt;code&gt;len&lt;/code&gt;), và dung lượng tối đa (&lt;code&gt;cap&lt;/code&gt;). Nhờ thiết kế này, slice có thể mở rộng linh hoạt mà không cần sao chép toàn bộ dữ liệu mỗi lần.&lt;/p&gt;
&lt;p&gt;Khi thực hiện thao tác cắt (&lt;code&gt;[start:end]&lt;/code&gt;), Go không sao chép dữ liệu mà chỉ tạo một con trỏ mới trỏ đến vùng nhớ gốc — giúp tiết kiệm bộ nhớ đáng kể. Khi dùng &lt;code&gt;append&lt;/code&gt; và slice đã đầy, Go sẽ cấp phát mảng mới với dung lượng lớn hơn: với slice nhỏ hơn 256 phần tử, dung lượng tăng gấp đôi; với slice lớn hơn, tốc độ tăng trưởng giảm dần từ 2x xuống 1.25x để cân bằng giữa hiệu năng và bộ nhớ. Sử dụng &lt;code&gt;make&lt;/code&gt; để khởi tạo slice với dung lượng phù hợp ngay từ đầu là cách tối ưu nhằm tránh việc cấp phát lại bộ nhớ nhiều lần.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Slice gồm 3 thành phần: con trỏ, độ dài (&lt;code&gt;len&lt;/code&gt;), dung lượng (&lt;code&gt;cap&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Cắt slice không sao chép dữ liệu, chỉ tạo con trỏ mới đến mảng gốc&lt;/li&gt;
&lt;li&gt;&lt;code&gt;append&lt;/code&gt; tự động mở rộng dung lượng khi cần, với chiến lược tăng trưởng thông minh&lt;/li&gt;
&lt;li&gt;Dùng &lt;code&gt;make([]T, len, cap)&lt;/code&gt; để khởi tạo trước dung lượng, tránh cấp phát lại bộ nhớ&lt;/li&gt;
&lt;li&gt;Hiểu cơ chế slice giúp viết mã Go hiệu quả và tránh các lỗi chia sẻ bộ nhớ ngoài ý muốn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-go-can"&gt;&lt;a class="link" href="https://niketpatel.com/essays/why-go-cant-try" target="_blank" rel="noopener"
&gt;Why Go Can&amp;rsquo;t Try&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết lý giải tại sao Go không thể thêm từ khóa &lt;code&gt;try&lt;/code&gt; hay cơ chế xử lý lỗi tương tự — không phải vì các nhà thiết kế thích viết nhiều mã lặp lại, mà vì đây là sự bất tương thích kiến trúc sâu xa. Gốc rễ của vấn đề nằm ở định nghĩa kiểu &lt;code&gt;error&lt;/code&gt; trong Go: chỉ là một interface tối giản với phương thức &lt;code&gt;Error() string&lt;/code&gt;, cho phép bất kỳ kiểu nào triển khai và không có thông tin gì để trình biên dịch kiểm tra tính đầy đủ.&lt;/p&gt;
&lt;p&gt;Để so sánh, Zig sử dụng tập hợp lỗi có kiểu tường minh, được trình biên dịch theo dõi và bắt buộc xử lý đầy đủ — nhưng đổi lại, lỗi không thể mang thêm dữ liệu ngữ cảnh. Go chọn hướng ngược lại: cho phép bọc lỗi phong phú qua &lt;code&gt;fmt.Errorf(&amp;quot;%w&amp;quot;, err)&lt;/code&gt; nhưng mất đi sự đảm bảo tại thời điểm biên dịch. Việc thay đổi kiểu &lt;code&gt;error&lt;/code&gt; bây giờ đồng nghĩa với việc viết lại toàn bộ thư viện chuẩn và phá vỡ hàng triệu chương trình Go hiện có — một khoản nợ kiến trúc không thể hoàn trả dần dần.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;if err != nil&lt;/code&gt; tồn tại vì hệ thống lỗi của Go không thể thay thế, không phải vì sở thích&lt;/li&gt;
&lt;li&gt;Kiểu &lt;code&gt;error&lt;/code&gt; của Go là interface tối giản — trình biên dịch không biết gì về các lỗi có thể xảy ra&lt;/li&gt;
&lt;li&gt;Zig kiểm tra lỗi đầy đủ tại thời điểm biên dịch, nhưng lỗi không thể mang dữ liệu ngữ cảnh&lt;/li&gt;
&lt;li&gt;Go cho phép bọc lỗi phong phú nhưng không có bảo đảm tại thời điểm biên dịch&lt;/li&gt;
&lt;li&gt;Thay đổi kiến trúc lỗi của Go sẽ phá vỡ toàn bộ hệ sinh thái hiện có&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-scheduler--understanding-the-go-runtime"&gt;&lt;a class="link" href="https://internals-for-interns.com/posts/go-runtime-scheduler" target="_blank" rel="noopener"
&gt;The Scheduler — Understanding the Go Runtime&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giải thích cách bộ lập lịch của Go runtime quyết định goroutine nào sẽ chạy tiếp theo — cơ chế cốt lõi cho phép Go chạy hàng triệu goroutine nhẹ trên chỉ một vài luồng hệ điều hành. Trung tâm của thiết kế là mô hình &lt;strong&gt;GMP&lt;/strong&gt;: &lt;strong&gt;G&lt;/strong&gt; (Goroutine) là đơn vị thực thi nhẹ bắt đầu với stack chỉ 2KB; &lt;strong&gt;M&lt;/strong&gt; (Machine) là luồng hệ điều hành thực sự; và &lt;strong&gt;P&lt;/strong&gt; (Processor) là ngữ cảnh lập lịch giữ hàng đợi goroutine cục bộ, số lượng bằng &lt;code&gt;GOMAXPROCS&lt;/code&gt;. Mỗi P có hàng đợi riêng giúp giảm tranh chấp khóa so với một hàng đợi toàn cục.&lt;/p&gt;
&lt;p&gt;Thuật toán &lt;code&gt;findRunnable()&lt;/code&gt; tìm goroutine theo thứ tự ưu tiên: công việc GC, kiểm tra công bằng toàn cục (cứ 61 lần lập lịch lại lấy từ hàng đợi toàn cục một lần), hàng đợi cục bộ của P, rồi đến đánh cắp công việc từ P khác nếu không còn gì. Điểm nổi bật của thiết kế là kiến trúc &amp;ldquo;tự phục vụ&amp;rdquo;: goroutine tự quản lý trạng thái của mình, tự tạm dừng khi chờ, không có luồng lập lịch trung tâm nào điều phối tất cả. Nhờ đó, chuyển đổi ngữ cảnh giữa các goroutine chỉ tốn 50–100 nanosecond, nhanh hơn 10–40 lần so với chuyển đổi luồng hệ điều hành.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mô hình GMP: Goroutine (G), luồng hệ điều hành (M), ngữ cảnh lập lịch (P)&lt;/li&gt;
&lt;li&gt;Số lượng P bằng &lt;code&gt;GOMAXPROCS&lt;/code&gt;, mỗi P có hàng đợi cục bộ giảm tranh chấp khóa&lt;/li&gt;
&lt;li&gt;&lt;code&gt;findRunnable()&lt;/code&gt; tìm goroutine theo thứ tự ưu tiên, có cơ chế đánh cắp công việc giữa các P&lt;/li&gt;
&lt;li&gt;Goroutine tự tạm dừng và tiếp tục — không có luồng lập lịch trung tâm&lt;/li&gt;
&lt;li&gt;Chuyển đổi ngữ cảnh goroutine chỉ 50–100ns, nhanh hơn 10–40x so với luồng hệ điều hành&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="go-string-concatenation-performance-benchmark"&gt;&lt;a class="link" href="https://www.winterjung.dev/en/string-concat-performance-benchmark-in-go/" target="_blank" rel="noopener"
&gt;Go String Concatenation Performance Benchmark&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết so sánh hiệu năng của 15 phương pháp nối chuỗi khác nhau trong Go qua hai kịch bản thực tế: nối số lượng chuỗi cố định (như tạo cache key) và nối số lượng chuỗi biến đổi (như ghép điều kiện truy vấn). Kết quả cho thấy sự chênh lệch rất lớn giữa các phương pháp, đặc biệt khi số lượng chuỗi tăng cao.&lt;/p&gt;
&lt;p&gt;Với kịch bản số lượng cố định, toán tử &lt;code&gt;+&lt;/code&gt; đơn giản cho hiệu năng hoàn toàn chấp nhận được. Nhưng với kịch bản biến đổi (256 phần tử), &lt;code&gt;strings.Join()&lt;/code&gt; và &lt;code&gt;strings.Builder&lt;/code&gt; với &lt;code&gt;Grow()&lt;/code&gt; cấp phát trước dung lượng vượt trội rõ rệt — chỉ khoảng 2.6–2.8 microsecond, trong khi toán tử &lt;code&gt;+=&lt;/code&gt; trong vòng lặp tốn tới 37 microsecond và tiêu tốn bộ nhớ gấp nhiều lần. Nguyên nhân là mỗi lần &lt;code&gt;+=&lt;/code&gt; tạo ra một chuỗi mới, dẫn đến hàng loạt cấp phát bộ nhớ không cần thiết.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;strings.Builder&lt;/code&gt; với &lt;code&gt;Grow()&lt;/code&gt; và &lt;code&gt;strings.Join()&lt;/code&gt; là hai lựa chọn nhanh nhất trong mọi kịch bản&lt;/li&gt;
&lt;li&gt;Toán tử &lt;code&gt;+&lt;/code&gt; đủ tốt khi nối số lượng chuỗi cố định, ít&lt;/li&gt;
&lt;li&gt;Toán tử &lt;code&gt;+=&lt;/code&gt; trong vòng lặp chậm hơn ~14x và tốn nhiều bộ nhớ hơn so với &lt;code&gt;strings.Builder&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Cấp phát trước dung lượng bằng &lt;code&gt;Grow()&lt;/code&gt; giúp tránh việc cấp phát lại bộ nhớ nhiều lần&lt;/li&gt;
&lt;li&gt;Chọn đúng phương pháp nối chuỗi có thể tạo ra sự khác biệt lớn về hiệu năng ở quy mô lớn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="message-passing-is-shared-mutable-state"&gt;&lt;a class="link" href="https://causality.blog/essays/message-passing-is-shared-mutable-state/" target="_blank" rel="noopener"
&gt;Message Passing Is Shared Mutable State&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài luận đưa ra một lập luận gây tranh cãi: mô hình lập trình đồng thời dùng truyền thông điệp (message passing) — như channel trong Go hay actor trong Erlang — không thực sự giải quyết các vấn đề của bộ nhớ chia sẻ có thể thay đổi (shared mutable state), mà chỉ đơn giản là di chuyển chúng sang tên gọi khác. Channel trong Go về bản chất là một hàng đợi chia sẻ — bất kỳ goroutine nào cũng có thể gửi hoặc nhận — tức là vẫn là trạng thái có thể thay đổi được chia sẻ giữa các luồng thực thi.&lt;/p&gt;
&lt;p&gt;Tác giả dẫn chứng nghiên cứu năm 2019 phân tích 171 lỗi đồng thời trong các dự án Go thực tế, trong đó khoảng 58% lỗi blocking xuất phát từ message passing, không phải bộ nhớ chia sẻ. Triết lý &amp;ldquo;share memory by communicating&amp;rdquo; của Go hóa ra không loại bỏ được deadlock, goroutine leak hay race condition — những loại lỗi này vẫn xảy ra, chỉ qua kênh channel thay vì mutex. Ngay cả Erlang, với cơ chế cô lập actor mạnh hơn nhiều, cũng bị phát hiện có race condition trong thư viện chuẩn liên quan đến bảng ETS — vốn là bộ nhớ chia sẻ được thêm vào để giải quyết các hạn chế thực tiễn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Channel trong Go là hàng đợi chia sẻ — về cấu trúc vẫn là shared mutable state&lt;/li&gt;
&lt;li&gt;58% lỗi blocking trong Go thực tế đến từ message passing, không phải bộ nhớ chia sẻ&lt;/li&gt;
&lt;li&gt;Deadlock, goroutine leak, race condition vẫn xảy ra — chỉ qua channel thay vì mutex&lt;/li&gt;
&lt;li&gt;Tranh luận &amp;ldquo;shared memory vs. message passing&amp;rdquo; là một lưỡng phân giả — cả hai có cùng lỗ hổng cấu trúc&lt;/li&gt;
&lt;li&gt;Ngay cả Erlang cũng phải dùng bộ nhớ chia sẻ (ETS) để xử lý các bài toán thực tiễn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="things-i"&gt;&lt;a class="link" href="https://sjer.red/blog/2026/built-with-ai/" target="_blank" rel="noopener"
&gt;Things I&amp;rsquo;ve Done with AI&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của một lập trình viên 14 năm kinh nghiệm chia sẻ hành trình từ hoài nghi đến trở thành người dùng AI tích cực. Từ tháng 10/2025, tác giả chuyển hẳn sang mô hình viết prompt và kiểm tra kết quả thay vì tự viết mã — và trong 9 tháng đã hoàn thành hơn 15 dự án cá nhân bằng Cursor và Claude Code, một con số mà trước đây gần như không thể.&lt;/p&gt;
&lt;p&gt;Điều thú vị là tác giả không ca ngợi AI một cách mù quáng, mà nhấn mạnh rằng để dùng AI hiệu quả cần thay đổi tư duy: không còn ưu tiên mã nguồn &amp;ldquo;đẹp&amp;rdquo; hay kiến trúc hoàn hảo, mà tập trung vào giá trị thực tế cho người dùng. Mã do AI tạo ra không cần đáp ứng tiêu chuẩn bảo trì truyền thống nếu có đủ kiểm thử — vì bản thân AI cũng có thể điều hướng trong mã nguồn không hoàn hảo. Tại nơi làm việc, các yêu cầu nhỏ từ quản lý sản phẩm giờ &amp;ldquo;gần như miễn phí&amp;rdquo; để thực hiện; điểm nghẽn còn lại chỉ là kiểm tra và kiểm thử.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dùng AI hiệu quả đòi hỏi thay đổi tư duy: ưu tiên giá trị kinh doanh thay vì mã nguồn hoàn hảo&lt;/li&gt;
&lt;li&gt;Kiểm thử và tài liệu đã trở thành điểm nghẽn chính trong quy trình phát triển hỗ trợ bởi AI&lt;/li&gt;
&lt;li&gt;Mã do AI tạo không cần bảo trì theo kiểu truyền thống nếu có độ phủ kiểm thử tốt&lt;/li&gt;
&lt;li&gt;Tập trung công việc chuyển sang thiết kế và tài liệu — thay vì triển khai chi tiết&lt;/li&gt;
&lt;li&gt;Tốc độ xây dựng sản phẩm tăng đáng kể khi chấp nhận sự đánh đổi về chất lượng mã nguồn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="pushing-and-pulling-three-reactivity-algorithms"&gt;&lt;a class="link" href="https://jonathan-frere.com/posts/reactivity-algorithms/" target="_blank" rel="noopener"
&gt;Pushing and Pulling: Three Reactivity Algorithms&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích ba thuật toán xây dựng hệ thống reactive — loại hệ thống tự động cập nhật khi dữ liệu thay đổi, như bảng tính nơi một ô thay đổi kéo theo hàng loạt ô phụ thuộc tính toán lại. Tác giả đánh giá các phương pháp qua bốn tiêu chí: hiệu quả tính toán, cập nhật chi tiết (chỉ tính lại những gì thực sự thay đổi), không có trạng thái trung gian không nhất quán, và hỗ trợ phụ thuộc động.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Push-based&lt;/strong&gt;: khi dữ liệu đầu vào thay đổi, nó ngay lập tức thông báo cho tất cả các node phụ thuộc — cập nhật chi tiết nhưng có thể tính toán lại một node nhiều lần nếu nó có nhiều nguồn phụ thuộc. &lt;strong&gt;Pull-based&lt;/strong&gt;: các node chủ động lấy giá trị từ phụ thuộc khi cần — tự nhiên không có trạng thái trung gian nhưng dễ tính toán dư thừa. &lt;strong&gt;Push-pull&lt;/strong&gt; kết hợp cả hai: pha push đánh dấu các node bị ảnh hưởng là &amp;ldquo;dirty&amp;rdquo;, pha pull chỉ tính toán lại những node đó — đạt độ phức tạp O(n) với mỗi node chỉ được xử lý đúng một lần, đáp ứng cả bốn tiêu chí.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ba phương pháp reactive: push-based, pull-based, và push-pull kết hợp&lt;/li&gt;
&lt;li&gt;Push-based cập nhật chi tiết nhưng có thể tính toán lại node nhiều lần&lt;/li&gt;
&lt;li&gt;Pull-based tránh trạng thái trung gian nhưng dễ tính toán dư thừa&lt;/li&gt;
&lt;li&gt;Push-pull đánh dấu &amp;ldquo;dirty&amp;rdquo; rồi tính toán theo yêu cầu — O(n), mỗi node xử lý đúng một lần&lt;/li&gt;
&lt;li&gt;Push-pull là lựa chọn tối ưu cho phát triển web, cân bằng giữa hiệu năng và sự đơn giản&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bonus"&gt;Bonus
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Images:&lt;/strong&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!Fevp!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb1ae3fa-80a7-464d-97a2-869170caaa2f_2360x2960.png"
loading="lazy"
alt="Git Workflow: Essential Commands"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!huHJ!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9262eb79-a1cc-4308-8f72-01fdf91e429d_1388x1782.jpeg"
loading="lazy"
alt="How can Cache Systems go wrong?"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!7p1w!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5ebb98a-9f98-4c32-9268-2d14086569d8_2360x2960.png"
loading="lazy"
alt="Top Cyber Attacks Explained"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #90</title><link>https://miti99.com/post/2026/03/16/</link><pubDate>Mon, 16 Mar 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/03/16/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #90.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="against-query-based-compilers"&gt;&lt;a class="link" href="https://matklad.github.io/2026/02/25/against-query-based-compilers.html" target="_blank" rel="noopener"
&gt;Against Query Based Compilers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của matklad phân tích những hạn chế cơ bản của kiến trúc trình biên dịch dựa trên truy vấn (query-based compiler), dù kiến trúc này đang ngày càng phổ biến. Ý tưởng cốt lõi là áp dụng tính toán tăng dần (incremental computation) vào quá trình biên dịch: các phép tính được biểu diễn dưới dạng đồ thị phụ thuộc, và khi đầu vào thay đổi, chỉ những phần bị ảnh hưởng mới cần tính toán lại.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, tác giả chỉ ra rằng hiệu quả của kiến trúc này bị giới hạn bởi cấu trúc phụ thuộc của chính ngôn ngữ lập trình. Một số phép tính có tính &amp;ldquo;avalanche&amp;rdquo; — thay đổi nhỏ ở đầu vào dẫn đến thay đổi lớn ở đầu ra — khiến cách tiếp cận tăng dần trở nên kém hiệu quả. Bài viết so sánh Zig và Rust: Zig yêu cầu khai báo tường minh và phân tích cú pháp cô lập theo tệp, cho phép biên dịch đơn giản hơn mà không cần query. Ngược lại, hệ thống macro và trait resolution của Rust tạo ra phụ thuộc toàn crate, buộc phải theo dõi chi tiết từng phần.&lt;/p&gt;
&lt;p&gt;Thay vì áp dụng query ở mọi nơi, tác giả đề xuất thiết kế ngôn ngữ để cho phép độc lập theo từng khối lớn, dùng mô hình map-reduce có cấu trúc, và chỉ dùng query-based làm phương án dự phòng thay vì mặc định.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kiến trúc query-based compiler hữu ích nhưng không phải giải pháp toàn năng&lt;/li&gt;
&lt;li&gt;Hiệu quả phụ thuộc vào cấu trúc phụ thuộc của ngôn ngữ, không chỉ vào cách triển khai&lt;/li&gt;
&lt;li&gt;Thiết kế ngôn ngữ (như Zig) có thể tránh được nhu cầu dùng query ngay từ đầu&lt;/li&gt;
&lt;li&gt;Nên ưu tiên kiến trúc đơn giản hơn khi thiết kế ngôn ngữ cho phép&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-great-developer-divide-how-ai-is-reshaping-the-software-job-market-into-three-tiers"&gt;&lt;a class="link" href="https://itrevolution.com/articles/the-great-developer-divide-how-ai-is-reshaping-the-software-job-market-into-three-tiers/" target="_blank" rel="noopener"
&gt;The Great Developer Divide: How AI Is Reshaping the Software Job Market Into Three Tiers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích cách AI đang tái cấu trúc thị trường việc làm phần mềm thành ba tầng riêng biệt, thay vì xóa sổ các vị trí lập trình viên như nhiều người lo ngại. Vai trò lập trình viên trung cấp truyền thống đang dần biến mất, nhường chỗ cho các vị trí chuyên biệt hơn.&lt;/p&gt;
&lt;p&gt;Ba tầng được xác định gồm: &lt;strong&gt;Tầng đỉnh&lt;/strong&gt; ($250K–$500K+) dành cho các kiến trúc sư chiến lược thiết kế hệ thống tích hợp AI phức tạp; &lt;strong&gt;Tầng trung lai&lt;/strong&gt; ($150K–$300K) dành cho các chuyên gia kết hợp kỹ thuật với sản phẩm, thiết kế hoặc vận hành — bao gồm cả vai trò &amp;ldquo;fleet supervisor&amp;rdquo; quản lý các đội ngũ AI agent; và &lt;strong&gt;Tầng tự động hóa&lt;/strong&gt; ($80K–$130K) tập trung vào các công việc lập trình thông thường đang chịu áp lực kép từ AI và cạnh tranh nhân lực toàn cầu.&lt;/p&gt;
&lt;p&gt;Điểm mấu chốt của bài viết: AI không trực tiếp thay thế lập trình viên, mà là đẩy nhanh các lực lượng kinh tế khiến công việc thường quy không còn giữ được mức thu nhập như trước. Tác giả khuyến nghị các lập trình viên cần chủ động chọn tầng phù hợp trong vòng 12–18 tháng tới, đặc biệt chú trọng xây dựng chuyên môn lĩnh vực đặc thù như một lợi thế cạnh tranh.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thị trường việc làm phần mềm đang phân hóa thành ba tầng rõ rệt thay vì biến mất&lt;/li&gt;
&lt;li&gt;Vai trò trung cấp truyền thống bị thu hẹp, xuất hiện các vị trí lai như fleet supervisor, agent expert&lt;/li&gt;
&lt;li&gt;AI thúc đẩy phân hóa thu nhập thông qua lực lượng kinh tế, không chỉ tự động hóa trực tiếp&lt;/li&gt;
&lt;li&gt;Cần định hướng nghề nghiệp sớm và đầu tư vào chuyên môn lĩnh vực đặc thù&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="engineering-speed-at-scale--architectural-lessons-from-sub-100-ms-apis"&gt;&lt;a class="link" href="https://www.infoq.com/articles/engineering-speed-scale/" target="_blank" rel="noopener"
&gt;Engineering Speed at Scale — Architectural Lessons from Sub-100-ms APIs&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Saranya Vedagiri (eBay) phân tích cách xây dựng và duy trì các API phản hồi dưới 100ms. Tác giả nhấn mạnh rằng độ trễ thấp không phải kết quả của việc &amp;ldquo;tối ưu hóa code&amp;rdquo;, mà là một kết quả kiến trúc có chủ đích, đòi hỏi thiết kế xuyên suốt nhiều tầng hệ thống.&lt;/p&gt;
&lt;p&gt;Một trong những khái niệm cốt lõi là &lt;strong&gt;ngân sách độ trễ&lt;/strong&gt; (latency budget): thay vì đặt ra một con số hiệu năng chung chung, các hệ thống hiệu quả phân bổ mili giây cụ thể cho từng tầng — định tuyến edge, API gateway, logic ứng dụng, và truy cập dữ liệu. Điều này biến mục tiêu trừu tượng thành ràng buộc cụ thể. Các mẫu kỹ thuật quan trọng bao gồm: xử lý bất đồng bộ song song (async fan-out) với &lt;code&gt;CompletableFuture&lt;/code&gt;, bộ nhớ đệm đa tầng (local → Redis → database), và circuit breaker để cô lập các phụ thuộc chậm. Bài viết cũng nhấn mạnh tầm quan trọng của khả năng quan sát (observability): theo dõi độ trễ theo phân vị (p50, p95, p99), distributed tracing, và cảnh báo SLO dựa trên burn-rate.&lt;/p&gt;
&lt;p&gt;Điểm đáng chú ý là tác giả không chỉ nói về kỹ thuật — văn hóa tổ chức mới là yếu tố duy trì hiệu năng lâu dài. Khi toàn bộ nhóm coi độ trễ là trách nhiệm chung và đưa tư duy hiệu năng vào code review cũng như quy trình phát hành, tốc độ mới được bảo toàn theo thời gian.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hiệu năng là đặc tính sản phẩm, cần được thiết kế từ đầu chứ không phải tối ưu sau&lt;/li&gt;
&lt;li&gt;Phân bổ ngân sách độ trễ theo từng tầng giúp biến mục tiêu trừu tượng thành ràng buộc đo được&lt;/li&gt;
&lt;li&gt;Xử lý bất đồng bộ song song và bộ nhớ đệm đa tầng là hai mẫu kỹ thuật nền tảng&lt;/li&gt;
&lt;li&gt;Theo dõi phân vị độ trễ (p95, p99) và distributed tracing là thiết yếu để phát hiện hồi quy&lt;/li&gt;
&lt;li&gt;Văn hóa tổ chức coi hiệu năng là trách nhiệm chung mới là yếu tố bền vững dài hạn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="can-ai-agents-build-real-stripe-integrations"&gt;&lt;a class="link" href="https://stripe.com/blog/can-ai-agents-build-real-stripe-integrations" target="_blank" rel="noopener"
&gt;Can AI Agents Build Real Stripe Integrations?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Stripe đã tự đặt câu hỏi: liệu các AI agent có thể tự động xây dựng các tích hợp thanh toán hoàn chỉnh và sẵn sàng cho môi trường sản xuất? Để trả lời, họ xây dựng một bộ đánh giá (benchmark) gồm 11 môi trường đa dạng, chia thành ba nhóm: tác vụ backend đơn thuần (nâng cấp API, chuyển đổi phiên bản), tác vụ toàn stack (yêu cầu kiểm thử trên trình duyệt), và bộ bài tập tập trung vào từng tính năng cụ thể của Stripe.&lt;/p&gt;
&lt;p&gt;Kết quả đáng chú ý: Claude Opus 4.5 đạt 92% trung bình ở nhóm tác vụ toàn stack, trong khi GPT-5.2 nổi trội hơn ở nhóm bài tập chuyên sâu với 73%. Các agent thành công trong việc nâng cấp tích hợp cũ, sử dụng Stripe Link để kiểm thử, và tự khám phá tài liệu để tìm ra cấu hình API phức tạp. Tuy nhiên, thách thức vẫn còn: xử lý các tình huống mơ hồ, điều hướng trình duyệt khi gặp lỗi, và tự phục hồi khi tương tác giao diện thất bại vẫn là những điểm yếu rõ rệt.&lt;/p&gt;
&lt;p&gt;Stripe nhấn mạnh rằng thanh toán yêu cầu độ chính xác 100% — đây là lĩnh vực không có chỗ cho sai sót. Việc công bố bộ benchmark này nhằm thúc đẩy cộng đồng phát triển công cụ cho AI agent tốt hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stripe xây dựng benchmark thực tế để đo khả năng của AI agent trong việc tích hợp thanh toán&lt;/li&gt;
&lt;li&gt;Claude Opus 4.5 đạt hiệu quả cao nhất ở tác vụ toàn stack, GPT-5.2 tốt hơn ở bài tập chuyên sâu&lt;/li&gt;
&lt;li&gt;Các agent có thể tự khám phá tài liệu và giao diện để giải quyết vấn đề phức tạp&lt;/li&gt;
&lt;li&gt;Xử lý tình huống mơ hồ và phục hồi sau lỗi vẫn là thách thức chính&lt;/li&gt;
&lt;li&gt;Thanh toán đòi hỏi độ chính xác tuyệt đối — đặt ra tiêu chuẩn cao hơn nhiều so với tác vụ thông thường&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bonus"&gt;Bonus
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Hình ảnh:&lt;/strong&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!SFnp!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf0d363e-62b7-4b3f-940d-d19f7a55c610_3000x3900.png"
loading="lazy"
alt="CPU vs GPU vs TPU"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!ipY-!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2931d40e-cce8-4ecd-a520-b5f80679c315_2528x3626.png"
loading="lazy"
alt="How OAuth 2 Works"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!Ehq9!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f417b56-c66c-45fd-8308-dab9af381ced_2252x2752.png"
loading="lazy"
alt="How Distributed Tracing Works at the High Level?"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!4UUW!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0357d808-5db9-4e18-8262-8dee58fd697d_2508x3000.jpeg"
loading="lazy"
alt="Top 4 API Gateway Use Cases"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #89</title><link>https://miti99.com/post/2026/03/14/</link><pubDate>Sat, 14 Mar 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/03/14/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #89.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="hybrid-quota-linear-rate-limiter"&gt;&lt;a class="link" href="https://dotat.at/@/2026-01-12-hqlr.html" target="_blank" rel="noopener"
&gt;Hybrid Quota-Linear Rate Limiter&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tony Finch phân tích một vấn đề phổ biến với các thuật toán giới hạn tốc độ (rate limiter) tuyến tính như leaky bucket và GCRA: chúng có xu hướng &amp;ldquo;hào phóng&amp;rdquo; hơn mức cần thiết trong giai đoạn khởi động, cho phép client gửi khoảng &lt;code&gt;q*a/(a-1)&lt;/code&gt; yêu cầu trước khi bị giới hạn khi hoạt động ở tốc độ gấp &lt;code&gt;a&lt;/code&gt; lần cho phép.&lt;/p&gt;
&lt;p&gt;Để giải quyết vấn đề này, tác giả đề xuất một thuật toán lai hoạt động ở hai chế độ: &lt;strong&gt;chế độ bursty&lt;/strong&gt; dành cho các client có lưu lượng thấp, cho phép gửi theo đợt nhưng giới hạn tối đa một quota token mỗi cửa sổ thời gian; và &lt;strong&gt;chế độ smooth&lt;/strong&gt; dành cho client có lưu lượng cao, buộc phân phối yêu cầu đều đặn hơn. Thuật toán tự chuyển đổi giữa hai chế độ khi client tiêu hết quota hoặc khi bucket phục hồi hoàn toàn. Cách tiếp cận này sử dụng ít bộ nhớ hơn so với phương pháp quota-reset, đồng thời kiểm soát quota chặt chẽ hơn so với rate limiter tuyến tính thuần túy.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, điểm thú vị là tác giả cuối cùng khuyên &lt;strong&gt;không nên&lt;/strong&gt; dùng thuật toán phức tạp này. Thay vào đó, hãy cân nhắc lại bài toán để có thể sử dụng một rate limiter tuyến tính đơn giản như GCRA — vì việc đo tốc độ trung bình theo thời gian dài tự nhiên khuyến khích client hoạt động mượt mà hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rate limiter tuyến tính (GCRA, leaky bucket) có thể cho phép nhiều yêu cầu hơn dự kiến trong giai đoạn khởi động&lt;/li&gt;
&lt;li&gt;Thuật toán lai kết hợp chế độ bursty và smooth để kiểm soát chặt chẽ hơn&lt;/li&gt;
&lt;li&gt;Đơn giản hóa vẫn là ưu tiên hàng đầu: GCRA đủ tốt cho hầu hết các trường hợp thực tế&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="go-is-the-best-language-for-ai-agents"&gt;&lt;a class="link" href="https://getbruin.com/blog/go-is-the-best-language-for-agents/" target="_blank" rel="noopener"
&gt;Go is the Best Language for AI Agents&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Burak Karakan — CEO của Bruin, người có 8 năm kinh nghiệm lập trình Go — lập luận rằng Go là ngôn ngữ lý tưởng để phát triển phần mềm bằng AI agent. Lý do cốt lõi xuất phát từ bản chất của ngôn ngữ biên dịch: khi agent tạo ra mã nguồn Go bị lỗi, trình biên dịch sẽ trả về thông báo lỗi rõ ràng ngay lập tức, tạo vòng phản hồi nhanh và chính xác để agent tự sửa lỗi. Điều này khác hoàn toàn so với Python hay JavaScript — vốn chỉ báo lỗi khi chạy thực tế.&lt;/p&gt;
&lt;p&gt;Hệ thống kiểu tĩnh của Go cũng là một lợi thế lớn: agent có thể xác minh tính đúng đắn của mã trước khi chạy, thay vì phải phụ thuộc vào các bài kiểm thử thủ công. So với Rust — ngôn ngữ biên dịch khác — Go vẫn chiếm ưu thế nhờ cú pháp đơn giản hơn, tốc độ biên dịch nhanh hơn, và lượng mã Go trong dữ liệu huấn luyện của các mô hình AI lớn hơn đáng kể. Ngoài ra, bộ kiểm thử của Go chạy cực nhanh và hoạt động nhất quán trên mọi hệ điều hành, giúp các background agent có thể xác nhận kết quả công việc mà không phụ thuộc vào môi trường chạy cụ thể.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go biên dịch nhanh và báo lỗi rõ ràng giúp AI agent có vòng phản hồi ngắn để tự sửa lỗi&lt;/li&gt;
&lt;li&gt;Kiểu tĩnh và cú pháp đơn giản giảm thiểu sai sót trong mã do agent tạo ra&lt;/li&gt;
&lt;li&gt;Go chạy nhất quán trên mọi nền tảng — lợi thế lớn cho background agent và môi trường sandbox&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="your-agent-needs-a-harness-not-a-framework"&gt;&lt;a class="link" href="https://x.com/djfarrelly/status/2028556984396452250" target="_blank" rel="noopener"
&gt;Your Agent Needs a Harness, Not a Framework&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Dan Farrelly từ Inngest.com đưa ra một góc nhìn sắc bén về kiến trúc AI agent: thay vì dùng framework, agent cần một &amp;ldquo;harness&amp;rdquo; — lớp kết nối, bảo vệ và điều phối các thành phần mà không làm thay công việc của chúng. Trong mọi ngành kỹ thuật, harness đều có vai trò như vậy: dây điện nối các cảm biến, test harness cung cấp giàn giáo kiểm thử, dây an toàn giữ bạn khi ngã. Agent runtime cũng cần điều tương tự.&lt;/p&gt;
&lt;p&gt;Vấn đề hiện tại là mỗi framework agent lại tự xây dựng lại từ đầu: retry logic, lưu trạng thái, job queue, định tuyến sự kiện. Thay vào đó, hãy dùng hạ tầng event-driven bền vững đã sẵn có — mỗi lần gọi LLM hay công cụ trở thành một &amp;ldquo;step&amp;rdquo; có thể thử lại độc lập. Nếu tiến trình chết ở vòng lặp thứ năm, bốn vòng trước đã được lưu lại. Nhóm tác giả đã xây dựng &lt;strong&gt;Utah&lt;/strong&gt; (Universally Triggered Agent Harness) để minh chứng: một agent hội thoại qua Telegram/Slack với công cụ, bộ nhớ, ủy quyền sub-agent và khả năng chịu lỗi — chỉ dùng Inngest, không framework. Bài học quan trọng rút ra: quản lý ngữ cảnh (context management) mới là thử thách thực sự, không phải việc gọi LLM.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Agent cần &amp;ldquo;harness&amp;rdquo; để xử lý retry, trạng thái, concurrency — không phải thêm framework&lt;/li&gt;
&lt;li&gt;Mỗi lần gọi LLM/công cụ là một step độc lập, có thể thử lại mà không mất kết quả trước&lt;/li&gt;
&lt;li&gt;Quản lý ngữ cảnh (cắt bớt, nén lịch sử, cảnh báo ngân sách) là thách thức lớn nhất khi xây agent thực tế&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="an-interactive-intro-to-quadtrees"&gt;&lt;a class="link" href="https://growingswe.com/blog/quadtrees" target="_blank" rel="noopener"
&gt;An Interactive Intro to Quadtrees&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết tương tác giải thích quadtree — cấu trúc dữ liệu dùng để tìm kiếm không gian 2D hiệu quả. Vấn đề đặt ra: khi xây dựng ứng dụng bản đồ với hàng triệu địa điểm, cách đơn giản nhất là tính khoảng cách từ vị trí người dùng đến từng điểm rồi lọc ra những điểm đủ gần — nhưng với hàng triệu điểm, cách này quá chậm.&lt;/p&gt;
&lt;p&gt;Quadtree giải quyết bài toán bằng cách chia không gian thành 4 ô con khi một ô chứa quá nhiều điểm (vượt ngưỡng capacity), tạo thành cây phân cấp. Khi truy vấn, chỉ cần đệ quy vào các ô giao với vùng tìm kiếm — bỏ qua hoàn toàn phần còn lại. Tham số capacity điều chỉnh sự cân bằng: capacity thấp tạo cây sâu, bỏ qua nhiều vùng hơn nhưng tốn bộ nhớ; capacity cao tạo cây nông, tiết kiệm bộ nhớ nhưng mỗi ô cần duyệt tuyến tính nhiều điểm hơn. Ngoài tìm kiếm địa lý (Uber dùng để tìm tài xế gần nhất), quadtree còn ứng dụng trong phát hiện va chạm game (broad-phase collision detection) và nén ảnh theo vùng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quadtree chia không gian 2D thành 4 ô con đệ quy, giúp bỏ qua vùng không liên quan khi truy vấn&lt;/li&gt;
&lt;li&gt;Tham số capacity (thường từ 4–16) ảnh hưởng trực tiếp đến độ sâu cây và hiệu năng truy vấn&lt;/li&gt;
&lt;li&gt;Ứng dụng thực tế: tìm kiếm địa lý, phát hiện va chạm trong game, nén ảnh theo vùng&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="agentic-engineering-patterns"&gt;&lt;a class="link" href="https://simonwillison.net/guides/agentic-engineering-patterns/" target="_blank" rel="noopener"
&gt;Agentic Engineering Patterns&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Simon Willison — tác giả blog kỹ thuật nổi tiếng — ra mắt một hướng dẫn toàn diện về các mẫu thiết kế (pattern) khi làm việc với AI agent trong lập trình. Điều đáng chú ý là hướng dẫn phân biệt rõ ràng giữa &amp;ldquo;agentic engineering&amp;rdquo; và &amp;ldquo;vibe coding&amp;rdquo;: vibe coding là để LLM viết mã mà không cần giám sát, còn agentic engineering là kỹ sư chuyên nghiệp dùng agent để khuếch đại chuyên môn sẵn có của mình — không phải thay thế nó.&lt;/p&gt;
&lt;p&gt;Một số pattern nổi bật: &lt;strong&gt;&amp;ldquo;Viết mã giờ rất rẻ&amp;rdquo;&lt;/strong&gt; — chi phí sinh mã gần như bằng không, buộc phải định nghĩa lại &amp;ldquo;mã tốt&amp;rdquo; là mã có kiểm thử, tài liệu, xử lý lỗi đúng chuẩn; &lt;strong&gt;&amp;ldquo;Tích lũy những gì bạn đã biết làm&amp;rdquo;&lt;/strong&gt; — duy trì kho ví dụ hoạt động được (blog, repo, POC) để dùng làm đầu vào cho agent, vì biết rằng điều gì đó khả thi khác với đã tự mình làm được; &lt;strong&gt;&amp;ldquo;Red/green TDD&amp;rdquo;&lt;/strong&gt; — viết kiểm thử trước, xác nhận kiểm thử thất bại, rồi mới triển khai, đảm bảo agent tạo ra mã đúng chức năng và tối giản. Hướng dẫn được cập nhật liên tục mỗi tuần với 1–2 chương mới.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Agentic engineering là khuếch đại chuyên môn kỹ sư, không phải để LLM viết mã không kiểm soát&lt;/li&gt;
&lt;li&gt;Tích lũy ví dụ hoạt động được là tài sản nghề nghiệp quan trọng khi làm việc với agent&lt;/li&gt;
&lt;li&gt;Red/green TDD giúp agent tạo mã tối giản, đúng chức năng và có lưới an toàn kiểm thử&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="things-i-miss-about-spring-boot-after-switching-to-go"&gt;&lt;a class="link" href="https://sushantdhiman.dev/things-i-miss-about-spring-boot-after-switching-to-go/" target="_blank" rel="noopener"
&gt;Things I Miss About Spring Boot After Switching to Go&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Sushant Dhiman chia sẻ góc nhìn thực tế sau khi chuyển từ Spring Boot sang Go. Dù Go có nhiều ưu điểm, tác giả thừa nhận có những thứ trong Spring Boot mà Go chưa thể thay thế dễ dàng. Trước hết là triết lý &amp;ldquo;batteries included&amp;rdquo; của Spring Boot — hầu hết tính năng cần thiết cho môi trường production đều có sẵn và tích hợp chặt chẽ với nhau.&lt;/p&gt;
&lt;p&gt;Cụ thể, tác giả nhớ nhất: &lt;strong&gt;Dependency Injection&lt;/strong&gt; tự động qua annotation (&lt;code&gt;@Service&lt;/code&gt;, &lt;code&gt;@Autowired&lt;/code&gt;) thay vì phải tự nối dây thủ công qua constructor trong Go; &lt;strong&gt;validation khai báo&lt;/strong&gt; với &lt;code&gt;@NotNull&lt;/code&gt;, &lt;code&gt;@Email&lt;/code&gt; thay vì viết điều kiện kiểm tra thủ công; và hệ sinh thái trưởng thành gồm Spring Security (xác thực JWT, OAuth), Spring Data (tự sinh câu truy vấn từ tên phương thức), Spring Boot Actuator (giám sát sức khỏe tích hợp sẵn), Spring Cloud (hỗ trợ microservices). Go có các thư viện tương đương nhưng thiếu sự gắn kết thống nhất trong một framework duy nhất.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spring Boot tích hợp sẵn dependency injection, validation khai báo và hệ sinh thái production-ready&lt;/li&gt;
&lt;li&gt;Go theo triết lý tối giản — linh hoạt hơn nhưng đòi hỏi tự lắp ráp nhiều thành phần hơn&lt;/li&gt;
&lt;li&gt;Cả hai có đánh đổi rõ ràng: Spring Boot tiện lợi hơn, Go đơn giản và hiệu năng cao hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="design-first-collaboration-with-ai"&gt;&lt;a class="link" href="https://martinfowler.com/articles/reduce-friction-ai/design-first-collaboration.html" target="_blank" rel="noopener"
&gt;Design-First Collaboration with AI&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ martinfowler.com giới thiệu phương pháp cộng tác &amp;ldquo;design-first&amp;rdquo; với AI để tránh &amp;ldquo;Implementation Trap&amp;rdquo; — bẫy mà AI sinh mã quá nhanh khiến các quyết định thiết kế quan trọng bị chôn vùi trong mã nguồn, và lập trình viên chỉ phát hiện ra bất đồng khi đọc lại mã — lúc đó đã quá tốn kém để sửa.&lt;/p&gt;
&lt;p&gt;Giải pháp là khung năm cấp độ, không được viết mã cho đến khi cấp độ 5 được phê duyệt: &lt;strong&gt;(1) Capabilities&lt;/strong&gt; — yêu cầu cốt lõi; &lt;strong&gt;(2) Components&lt;/strong&gt; — các khối xây dựng và trừu tượng; &lt;strong&gt;(3) Interactions&lt;/strong&gt; — luồng dữ liệu và giao tiếp; &lt;strong&gt;(4) Contracts&lt;/strong&gt; — chữ ký hàm và interface; &lt;strong&gt;(5) Implementation&lt;/strong&gt; — viết mã. Mỗi cấp độ chỉ kiểm tra một loại quyết định, giảm tải nhận thức đáng kể so với việc xem xét tất cả cùng lúc. Mức độ phức tạp quyết định điểm bắt đầu — tiện ích đơn giản có thể bắt đầu từ cấp 4, tính năng phức tạp bắt đầu từ cấp 1.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đừng để AI viết mã trước khi thống nhất thiết kế — phát hiện bất đồng sớm rẻ hơn rất nhiều&lt;/li&gt;
&lt;li&gt;Khung 5 cấp độ tách biệt từng loại quyết định thiết kế, giảm tải nhận thức khi xem xét&lt;/li&gt;
&lt;li&gt;Phương pháp này tạo điều kiện tự nhiên cho TDD và ngăn chặn &amp;ldquo;technical debt injection&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-two-kinds-of-error"&gt;&lt;a class="link" href="https://evanhahn.com/the-two-kinds-of-error/" target="_blank" rel="noopener"
&gt;The Two Kinds of Error&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Evan Hahn đề xuất một cách phân loại lỗi đơn giản nhưng hữu ích: lỗi &lt;strong&gt;expected&lt;/strong&gt; (có thể xảy ra trong vận hành bình thường, không phải lỗi của lập trình viên) và lỗi &lt;strong&gt;unexpected&lt;/strong&gt; (chỉ xảy ra khi có bug). Lỗi expected bao gồm: đầu vào của người dùng không hợp lệ, mất kết nối mạng, thiếu quyền truy cập — đây là lỗi có thể phục hồi, nên trả về kết quả lỗi và ghi log ở mức &lt;code&gt;WARN&lt;/code&gt; hoặc &lt;code&gt;INFO&lt;/code&gt;. Lỗi unexpected bao gồm: vi phạm assertion, logic sai, dependency chưa khởi tạo — đây là dấu hiệu của bug thực sự, nên log ở mức &lt;code&gt;ERROR&lt;/code&gt; hoặc &lt;code&gt;FATAL&lt;/code&gt;, thậm chí nên để chương trình crash hoàn toàn.&lt;/p&gt;
&lt;p&gt;Ranh giới giữa hai loại phụ thuộc vào ngữ cảnh: ứng dụng thử nghiệm có thể coi mọi lỗi là unexpected, hệ thống quan trọng (tàu vũ trụ) phải coi gần mọi thứ đều có thể xảy ra. Điều quan trọng là lập trình viên phải &lt;strong&gt;có ý thức&lt;/strong&gt; phân loại từng lỗi thay vì xử lý tất cả theo cùng một cách.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lỗi expected (mạng, đầu vào người dùng) nên được phục hồi và log WARN/INFO&lt;/li&gt;
&lt;li&gt;Lỗi unexpected (bug, logic sai) nên log ERROR/FATAL và có thể crash chương trình&lt;/li&gt;
&lt;li&gt;Phân loại có ý thức giúp thiết kế xử lý lỗi rõ ràng và đúng mức độ nghiêm trọng&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="secure-go-error-handling-best-practices"&gt;&lt;a class="link" href="https://blog.jetbrains.com/go/2026/03/02/secure-go-error-handling-best-practices/" target="_blank" rel="noopener"
&gt;Secure Go Error Handling Best Practices&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Blog JetBrains GoLand tập trung vào một khía cạnh thường bị bỏ qua: xử lý lỗi an toàn bảo mật trong Go. Nguyên tắc cốt lõi là &lt;strong&gt;tách biệt thông tin nội bộ và thông tin công khai&lt;/strong&gt; — tạo kiểu lỗi tùy chỉnh chứa cả thông báo nội bộ (chi tiết kỹ thuật cho lập trình viên) và thông báo công khai (thông báo an toàn cho người dùng), tránh việc lỗi nội bộ bị serialized ra HTTP response.&lt;/p&gt;
&lt;p&gt;Các thực hành quan trọng: dùng &lt;strong&gt;builder pattern&lt;/strong&gt; để kiểm soát trường metadata nào được ghi log, tránh ghi toàn bộ đối tượng request có thể chứa mật khẩu hay token; dùng &lt;strong&gt;opaque wrapping&lt;/strong&gt; thay vì &lt;code&gt;fmt.Errorf&lt;/code&gt; khi không muốn lộ chi tiết triển khai cho phía gọi; và khi truyền lỗi qua ranh giới dịch vụ, chuyển đổi sang lỗi chuẩn hóa (gRPC codes, JSON format), không bao giờ để lỗi do AI sinh ra tiếp cận API công khai. Logging nên dùng &lt;code&gt;log/slog&lt;/code&gt; với structured logging và implement interface redaction cho các trường nhạy cảm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tách lỗi thành thông báo nội bộ (kỹ thuật) và công khai (an toàn) để tránh rò rỉ thông tin&lt;/li&gt;
&lt;li&gt;Kiểm soát chặt metadata được ghi log, không ghi toàn bộ request object&lt;/li&gt;
&lt;li&gt;API công khai chỉ trả về thông báo tĩnh, định nghĩa sẵn — không bao giờ lỗi được sinh động&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ai-coding-tools-java--compounding-engineering"&gt;&lt;a class="link" href="https://www.the-main-thread.com/p/ai-coding-tools-java-compounding-engineering" target="_blank" rel="noopener"
&gt;AI Coding Tools, Java &amp;amp; Compounding Engineering&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết tổng hợp từ buổi nói chuyện tại NDC Manchester 2025, với luận điểm cốt lõi: &amp;ldquo;Nếu AI tạo ra mã tệ cho bạn, đó thường là vấn đề workflow, không phải vấn đề mô hình.&amp;rdquo; Phương pháp được đề xuất là &lt;strong&gt;Compounding Engineering&lt;/strong&gt; — huấn luyện AI như người cộng tác theo thời gian, tương tự onboard lập trình viên junior.&lt;/p&gt;
&lt;p&gt;Các yếu tố chính: xóa chat thường xuyên và lưu quyết định kiến trúc vào file markdown (như &lt;code&gt;CLAUDE.md&lt;/code&gt;) thay vì cố duy trì ngữ cảnh trong một cuộc trò chuyện dài; cập nhật &amp;ldquo;living rule files&amp;rdquo; mỗi khi sửa bug để lỗi không tái diễn; lên kế hoạch trước khi viết mã để phát hiện giả định sai ngay từ đầu; chia tính năng thành các tác vụ nhỏ, tập trung một trách nhiệm. Kỹ sư senior đóng góp giá trị qua &lt;strong&gt;taste&lt;/strong&gt; — khả năng đánh giá kiến trúc và đánh đổi, điều mà AI giỏi sinh mã nhưng yếu phán xét chất lượng. Kết quả tích lũy theo thời gian; không đầu tư vào workflow thì chỉ có &amp;ldquo;mediocrity nhanh hơn&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mã AI kém chất lượng thường do workflow kém, không phải do mô hình&lt;/li&gt;
&lt;li&gt;Lưu quyết định kiến trúc vào file markdown, cập nhật khi sửa bug để kiến thức tích lũy&lt;/li&gt;
&lt;li&gt;Giá trị của kỹ sư senior nằm ở khả năng phán xét kiến trúc — thứ AI chưa làm tốt&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="yaml-that"&gt;&lt;a class="link" href="https://lab174.com/blog/202601-yaml-norway/" target="_blank" rel="noopener"
&gt;YAML? That&amp;rsquo;s Norway Problem&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết khám phá một lỗi phân tích cú pháp thú vị trong YAML: mã quốc gia &lt;code&gt;NO&lt;/code&gt; (Na Uy) bị các trình phân tích cú pháp phổ biến chuyển thành giá trị boolean &lt;code&gt;false&lt;/code&gt; thay vì chuỗi ký tự. Nguyên nhân là YAML xử lý một số từ tiếng Anh như &lt;code&gt;yes/no&lt;/code&gt;, &lt;code&gt;true/false&lt;/code&gt;, &lt;code&gt;on/off&lt;/code&gt; dưới dạng giá trị boolean — tính năng này được giới thiệu từ YAML v1.0 (2004) nhằm làm cho tệp cấu hình dễ đọc hơn.&lt;/p&gt;
&lt;p&gt;Dù YAML v1.2 (2009) đã loại bỏ hành vi này để tương thích với JSON, hầu hết các thư viện phổ biến như PyYAML và LibYAML vẫn triển khai theo đặc tả v1.1 — tạo ra khoảng cách lớn giữa tiêu chuẩn và thực tế sau hơn 15 năm. Người dùng có thể tránh vấn đề này bằng cách đặt chuỗi trong dấu ngoặc kép (&lt;code&gt;&amp;quot;NO&amp;quot;&lt;/code&gt;), dùng thẻ kiểu tường minh (&lt;code&gt;!!str&lt;/code&gt;), hoặc chuyển sang thư viện tương thích v1.2 như &lt;code&gt;ruamel.yaml&lt;/code&gt; hay &lt;code&gt;yq&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NO&lt;/code&gt; trong YAML bị hiểu là &lt;code&gt;false&lt;/code&gt; do quy tắc boolean từ đặc tả v1.1&lt;/li&gt;
&lt;li&gt;YAML v1.2 đã sửa lỗi này từ năm 2009 nhưng hầu hết thư viện chưa cập nhật&lt;/li&gt;
&lt;li&gt;Giải pháp: dùng dấu ngoặc kép, thẻ &lt;code&gt;!!str&lt;/code&gt;, hoặc thư viện tương thích v1.2&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Newsletter #88</title><link>https://miti99.com/post/2026/03/13/</link><pubDate>Fri, 13 Mar 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/03/13/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #88.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="a-broken-heart"&gt;&lt;a class="link" href="https://allenpike.com/2026/a-broken-heart/" target="_blank" rel="noopener"
&gt;A Broken Heart&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Allen Pike chia sẻ một câu chuyện debug thú vị khi dashboard của ứng dụng web đột nhiên chậm đi 10 lần - từ 1 giây lên 10 giây. Sau khi loại trừ React (vốn bị nghi ngờ đầu tiên), anh phát hiện ra Safari đang dành 94% CPU cho&amp;hellip; Layout?&lt;/p&gt;
&lt;p&gt;Bằng phương pháp binary search với sự hỗ trợ của Claude, anh tìm ra thủ phạm: một emoji trái tim ❤️ trong nút &amp;ldquo;Send Feedback&amp;rdquo;. Hóa ra font &lt;strong&gt;Noto Color Emoji&lt;/strong&gt; của Google - được sử dụng để render emoji nhất quán trên các nền tảng - gây ra bug nghiêm trọng trong Safari, khiến mỗi lần layout mất 1600ms thay vì 2ms bình thường.&lt;/p&gt;
&lt;p&gt;Điều thú vị là bug này chỉ ảnh hưởng một số emoji cụ thể (❤️, 🤯) trong khi các emoji khác (🧺, 🫠) vẫn render nhanh bình thường. Giải pháp tạm thời: liệt kê &amp;ldquo;Apple Color Emoji&amp;rdquo; trước Noto Color Emoji trong font-family.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Font Noto Color Emoji sử dụng COLRv1 spec, fallback sang SVG trên Safari&lt;/li&gt;
&lt;li&gt;Bug nằm trong CoreSVG của Apple, đã được báo cáo cho WebKit team&lt;/li&gt;
&lt;li&gt;Coding agent giúp tạo minimal repro case nhanh hơn nhiều so với thủ công&lt;/li&gt;
&lt;li&gt;Câu chuyện thú vị về cách AI vừa là nguyên nhân (gợi ý dùng font này) vừa là giải pháp (giúp debug)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="wrapping-code-comments"&gt;&lt;a class="link" href="https://matklad.github.io/2026/02/21/wrapping-code-comments.html" target="_blank" rel="noopener"
&gt;Wrapping Code Comments&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một bài viết ngắn nhưng thú vị từ matklad về việc wrap code và comments. Tác giả nhận ra rằng code và comments nên được wrap ở độ rộng khác nhau: code ở khoảng 100 cột (để vừa 2 editor cạnh nhau), nhưng nội dung comments nên wrap ở 60-70 cột để dễ đọc hơn.&lt;/p&gt;
&lt;p&gt;Điều quan trọng là comments nên wrap &lt;strong&gt;tương đối&lt;/strong&gt; so với vị trí bắt đầu của comment, không phải tuyệt đối. Ví dụ: comment ở top-level có thể rộng, nhưng comment lồng sâu trong code nên hẹp hơn nhưng vẫn giữ độ rộng nội dung giống nhau.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giới hạn code ở 100 cột, nội dung comments ở 60-70 cột&lt;/li&gt;
&lt;li&gt;Comments nên wrap tương đối theo vị trí, không tuyệt đối&lt;/li&gt;
&lt;li&gt;VS Code và Emacs đều không hỗ trợ tốt relative wrapping&lt;/li&gt;
&lt;li&gt;Soft-wrapping không thể wrap đúng nếu không hiểu ý nghĩa text (ví dụ markdown lists)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-i-use-claude-code"&gt;&lt;a class="link" href="https://boristane.com/blog/how-i-use-claude-code/" target="_blank" rel="noopener"
&gt;How I Use Claude Code&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Boris Tane chia sẻ workflow 9 tháng sử dụng Claude Code với nguyên tắc cốt lõi: &lt;strong&gt;không bao giờ để Claude viết code cho đến khi đã review và approve plan&lt;/strong&gt;. Workflow gồm 3 phase:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 1 - Research:&lt;/strong&gt; Yêu cầu Claude đọc sâu codebase và viết báo cáo vào &lt;code&gt;research.md&lt;/code&gt;. Từ khóa quan trọng: &amp;ldquo;deeply&amp;rdquo;, &amp;ldquo;in great details&amp;rdquo;, &amp;ldquo;intricacies&amp;rdquo; - để Claude không chỉ đọc hời hợt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 2 - Planning:&lt;/strong&gt; Tạo &lt;code&gt;plan.md&lt;/code&gt; chi tiết, sau đó thêm inline notes để sửa, reject approaches, thêm constraints. Chu trình annotation này lặp 1-6 lần với guard &amp;ldquo;don&amp;rsquo;t implement yet&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 3 - Implementation:&lt;/strong&gt; Khi plan đã sẵn sàng, một prompt duy nhất: &amp;ldquo;implement it all. mark completed in plan. don&amp;rsquo;t stop until done.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;File markdown là shared mutable state giữa human và AI&lt;/li&gt;
&lt;li&gt;Annotation cycle inject domain knowledge mà Claude không có&lt;/li&gt;
&lt;li&gt;Single long session tốt hơn split sessions - context được build dần&lt;/li&gt;
&lt;li&gt;Implementation nên boring - creative work đã xong ở planning phase&lt;/li&gt;
&lt;li&gt;&amp;ldquo;I want implementation to be boring&amp;rdquo; - tất cả decisions đã được validate&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bonus"&gt;Bonus
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Images:&lt;/strong&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!h2M_!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d6d88ea-4355-4f29-96fa-9770907beebb_2360x2960.png"
loading="lazy"
alt="RabbitMQ vs Kafka vs Pulsar"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!8P-v!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6039d506-e02f-4313-ab97-2c04f8c94d90_2360x2960.png"
loading="lazy"
alt="REST vs GraphQL"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!yela!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ac3310f-e380-48c2-93ff-051f7606b533_2250x2624.png"
loading="lazy"
alt="Eventual Consistency in Modern Databases"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!vB9v!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc02c74f-e91f-438a-8ad8-d5ba6831e7f0_2250x2624.png"
loading="lazy"
alt="Strong Consistency In Databases"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!h8d0!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5f67fe5-0efa-4fc6-98da-d176b60b1a92_2508x3000.jpeg"
loading="lazy"
alt="PostgreSQL versus MySQL"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!_roW!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbdb9cae-3bda-4a62-9077-3f9d1e13fede_2360x2960.jpeg"
loading="lazy"
alt="Network Protocols Explained"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Videos:&lt;/strong&gt;
&lt;a class="link" href="https://www.youtube.com/watch?v=z_NbVtbgBJw" target="_blank" rel="noopener"
&gt;Video: What Is Redis Really About? - ByteByteGo&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Newsletter #87</title><link>https://miti99.com/post/2026/03/02/</link><pubDate>Mon, 02 Mar 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/03/02/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #87.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="on-cognitive-debt"&gt;&lt;a class="link" href="https://www.natemeyvis.com/on-cognitive-debt/" target="_blank" rel="noopener"
&gt;On cognitive debt&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết thảo luận về khái niệm &amp;ldquo;cognitive debt&amp;rdquo; (nợ nhận thức) trong bối cảnh phát triển phần mềm được hỗ trợ bởi AI. Tác giả lập luận rằng mặc dù AI-generated codebases có thể tạo ra cognitive debt, nhưng thực tế tình trạng này thường tồn tại ở mức độ cao hơn trong các codebase truyền thống. Người ta thường không nhận ra điều này vì nhiều hoạt động kỹ thuật tiêu chuẩn thực chất là quản lý cognitive debt hoặc tránh né nó với chi phí khổng lồ.&lt;/p&gt;
&lt;p&gt;Tác giả chỉ ra ba luận điểm chính: một là, khi kiểm soát theo quy mô dự án, cognitive debt trong codebase AI thường không tồi hơn so với các phương pháp truyền thống; hai là, nhiều công việc kỹ thuật được &amp;ldquo;bình thường hóa&amp;rdquo; thực chất là quản lý cognitive debt không cần thiết; và ba là, những người sử dụng AI tốt nhất đã khá giỏi trong việc tránh cognitive debt, và chúng ta sẽ ngày càng cải thiện.&lt;/p&gt;
&lt;p&gt;Bài viết cũng đề xuất một số kỹ thuật để giảm thiểu cognitive debt khi làm việc với AI: nhấn mạnh tính đóng gói (encapsulation), mô tả kỹ lưỡng các subsystem và interface, thực hiện các refactoring quy mô lớn với sự hỗ trợ của AI, và cải thiện bộ test ở những nơi cognitive debt đang xuất hiện.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI không làm gia tăng cognitive debt khi so sánh với các phương pháp phát triển truyền thống ở cùng quy mô&lt;/li&gt;
&lt;li&gt;Nhiều công việc kỹ thuật hàng ngày thực chất là hệ quả của việc đã đưa ra sự phức tạp không cần thiết&lt;/li&gt;
&lt;li&gt;Sử dụng AI một cách khéo léo có thể giúp giảm thiểu cognitive debt thông qua các kỹ thuật như encapsulation và refactoring&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-i"&gt;&lt;a class="link" href="https://davidoks.blog/p/why-im-not-worried-about-ai-job-loss" target="_blank" rel="noopener"
&gt;Why I&amp;rsquo;m not worried about AI job loss&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phản biện lại nỗi lo ngại phổ biến về việc AI sẽ gây ra mất việc làm hàng loạt. Tác giả lập luận rằng chúng ta không đang ở trong một khoảnh khắc giống như tháng 2 năm 2020 trước khi COVID bùng phát, và rằng những dự báo về sự sụp đổ của thị trường lao động là không có cơ sở. Bài viết phân tích tại sao sự thay thế lao động bằng AI sẽ diễn ra chậm hơn và ít gây tổn hại hơn nhiều người nghĩ.&lt;/p&gt;
&lt;p&gt;Tác giả giải thích ba luận điểm chính. Thứ nhất, thay thế lao động dựa trên lợi thế so sánh chứ không phải lợi thế tuyệt đối — ngay cả khi AI có thể thực hiện mọi tốt hơn con người, sự kết hợp giữa người và AI vẫn có thể tạo ra kết quả tốt hơn. Thứ hai, thế giới đầy rẫy các &amp;ldquo;nút thắt&amp;rdquo; do con người tạo ra — luật pháp, văn hóa doanh nghiệp, chính trị, và sự kháng cự thay đổi — những thứ này sẽ đảm bảo rằng con người vẫn cần thiết trong thời gian dài. Thứ ba, nhu cầu đối với hầu hết các sản phẩm mà con người tạo ra có tính đàn hồi cao hơn chúng ta nhận thức, và hiệu quả năng suất thường bị nuốt chửng bởi tăng trưởng nhu cầu (nghịch lý Jevons).&lt;/p&gt;
&lt;p&gt;Tác giả kết luận rằng người bình thường sẽ không có gì phải lo lắng về AI. Sự chuyển đổi kinh tế sẽ diễn ra từ từ và nhẹ nhàng hơn nhiều người nghĩ. Mặc dù một số người sẽ phải điều chỉnh, nhưng phần lớn mọi người sẽ ổn. Mối nguy hiểm thực sự không phải là tác động kinh tế của AI, mà là sự phản ứng chính trị và xã hội từ việc gây hoang mang cho công chúng một cách không cần thiết.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI sẽ không thay thế lao động con người ngay lập tức vì thế giới vẫn phụ thuộc vào các nút thắt do con người tạo ra&lt;/li&gt;
&lt;li&gt;Sự kết hợp giữa người và AI thường hiệu quả hơn AI hoạt động độc lập&lt;/li&gt;
&lt;li&gt;Nhu cầu đối với sản phẩm con người tạo ra có tính đàn hồi cao, dẫn đến nghịch lý Jevons&lt;/li&gt;
&lt;li&gt;Nguy cơ thực sự là sự phản ứng chính trị chống AI từ việc gây hoang mang công chúng&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-i-don"&gt;&lt;a class="link" href="https://honnibal.dev/blog/ai-bubble" target="_blank" rel="noopener"
&gt;Why I don&amp;rsquo;t think AI is a bubble&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phản biện lại quan điểm cho rằng AI đang trong một &amp;ldquo;bong bóng&amp;rdquo; sắp vỡ. Tác giả Matthew Honnibal — người tạo ra thư viện spaCy NLP — lập luận rằng hiệu suất của AI có thể sẽ không đạt đến đỉnh cao, ít nhất là những lập luận phổ biến về việc tại sao nó sẽ đạt đỉnh là không thuyết phục. Ông giải thích sự phát triển của các mô hình &amp;ldquo;reasoning&amp;rdquo; và cách chúng hoạt động khác biệt so với các mô hình completion đơn thuần.&lt;/p&gt;
&lt;p&gt;Tác giả phân tích lịch sử phát triển từ GPT-1 đến các mô hình reasoning hiện đại như Claude Opus và GPT-5. Sự thay đổi chính là kết hợp giữa generative AI và deep reinforcement learning — cho phép mô hình tự tạo ra các bước trung gian để giải quyết vấn đề thay vì chỉ dự đoán từ tiếp theo. Logic là công việc, ngay cả trong hệ thống thuần túy, và suy luận không bao giờ miễn phí. Các mô hình reasoning sử dụng reinforcement learning để học các chiến lược chung cho việc giải quyết vấn đề.&lt;/p&gt;
&lt;p&gt;Tác giả chỉ ra hai đòn bẩy mới để cải thiện LLMs: cho phép mô hình chạy lâu hơn (làm nhiều reasoning hơn) và thêm nhiều reinforcement learning hơn. Không có giới hạn dữ liệu rõ ràng cho reinforcement learning vì suy luận là một hàm một chiều — dễ dàng nhận diện một con dẫn đến kết luận đúng hơn là tạo ra nó. Mặc dù tác giả không tin tưởng vào OpenAI cụ thể, ông tin rằng các trung tâm dữ liệu sẽ được sử dụng hiệu quả.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hiệu suất AI có thể sẽ không đạt đỉnh vì các mô hình reasoning có hai đòn bẩy mới: thời gian chạy và reinforcement learning&lt;/li&gt;
&lt;li&gt;Các mô hình reasoning kết hợp generative AI với reinforcement learning để học các chiến lược giải quyết vấn đề chung&lt;/li&gt;
&lt;li&gt;Logic và suy luận đòi hỏi công việc tính toán, không bao giờ miễn phí ngay cả trong hệ thống thuần túy&lt;/li&gt;
&lt;li&gt;Không có giới hạn dữ liệu cho reinforcement learning vì mô hình có thể tự cải thiện thông qua việc nhận diện các con suy luận thành công&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="i-guess-i-kinda-get-why-people-hate-ai"&gt;&lt;a class="link" href="https://anthony.noided.media/blog/ai/programming/2026/02/14/i-guess-i-kinda-get-why-people-hate-ai.html" target="_blank" rel="noopener"
&gt;I guess I kinda get why people hate AI&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả, một lập trình viên đang làm việc tại Hawaii, chia sẻ suy nghĩ về lý do tại sao mọi người bắt đầu ghét AI mặc dù bản thân ông vẫn sử dụng và đánh giá cao công nghệ này. Bài viết bắt đầu với nỗi lo ngại của tác giả về việc liệu công việc mới của ông có phải là công việc cuối cùng hay không, một sự thay đổi trong tư duy so với trước đây khi ông chỉ lo lắng về việc liệu mình có &lt;em&gt;cần&lt;/em&gt; làm việc hay không.&lt;/p&gt;
&lt;p&gt;Tác giả chỉ ra nhiều lý do khiến &amp;ldquo;vibe&amp;rdquo; của AI hiện tại rất tồi tệ. Thứ nhất, những người đứng đầu các công ty AI liên tục marketing sản phẩm của họ bằng cách đe dọa rằng AI sẽ lấy đi việc làm của mọi người, điều mà tác giả mô tả là &amp;ldquo;hoàn toàn điên rồ&amp;rdquo;. Thứ hai, AI hiện nay rất hữu ích cho việc tạo ra nội dung rác — sinh viên dùng để gian lận, video giả về Elon Musk, và các video kỳ lạ trên TikTok. Thứ ba, AI gây ra các vấn đề thực tế như giá RAM tăng cao và các chương trình bug bounty bị ngừng lại vì quá nhiều báo cáo sai từ AI.&lt;/p&gt;
&lt;p&gt;Mặc dù tác giả vẫn tin rằng AI sẽ rất hữu ích trong tương lai và ông vẫn tiếp tục sử dụng nó, ông lo ngại rằng các công ty AI dường như không quan tâm đến việc giảm thiểu các tác động tiêu cực của sản phẩm họ. Tác giả đề xuất một số giải pháp như watermarking nội dung AI, chặn misinformation hơn nữa trên YouTube, và cho phép các dự án open-source yêu cầu không bị AI quét lỗ hổng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Các CEO AI đang marketing bằng cách đe dọa người dùng thay vì giới thiệu lợi ích, một chiến lược &amp;ldquo;hoàn toàn điên rồ&amp;rdquo;&lt;/li&gt;
&lt;li&gt;AI làm giảm rào cản cho nội dung rác nhưng chưa đủ tốt để thay thế hoàn toàn công việc có ý nghĩa&lt;/li&gt;
&lt;li&gt;Các công ty AI dường như không quan tâm đến việc giải quyết các tác động tiêu cực như misinformation, gian lận trong giáo dục, và tăng giá phần cứng&lt;/li&gt;
&lt;li&gt;Tác giả đề xuất các giải pháp như watermarking, chặn misinformation, và bảo vệ các dự án open-source khỏi AI quét lỗ hổng&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="uber"&gt;&lt;a class="link" href="https://www.uber.com/en-IN/blog/ubers-rate-limiting-system/" target="_blank" rel="noopener"
&gt;Uber&amp;rsquo;s Rate Limiting System&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chi tiết về cách Uber xây dựng hệ thống rate limiting phân tán quy mô lớn có khả năng xử lý hàng trăm triệu yêu cầu mỗi giây qua hàng nghìn dịch vụ microservices. Trước khi có GRL (Global Rate Limiter), các team tại Uber triển khai rate limiting theo cách riêng lẻ, dẫn đến cấu hình không nhất quán, độ trễ cao từ Redis, và khó khăn trong vận hành. Uber đã giải quyết vấn đề bằng cách tích hợp rate limiting trực tiếp vào service mesh.&lt;/p&gt;
&lt;p&gt;Hệ thống GRL sử dụng kiến trúc ba tầng với các client trong service mesh data plane, các aggregator cấp zone, và các controller cấp vùng. Thay vì sử dụng bộ đếm tập trung, GRL áp dụng mô hình probabilistic dropping được điều khiển bởi control plane — các client quyết định địa phương có nên drop request hay không dựa trên các chỉ thị drop ratio từ control plane. Thiết kế này cho phép decisions cực nhanh với độ trễ thấp trong khi vẫn duy trì coordination toàn cầu trong vài giây.&lt;/p&gt;
&lt;p&gt;Uber cũng xây dựng RLC (Rate Limit Configurator) để tự động hóa việc cấu hình rate limit. RLC phân tích định kỳ metrics traffic trực tiếp và cập nhật cấu hình rate limit dựa trên nhu cầu quan sát được, đảm bảo limits luôn mới và chính xác. Kết quả là giảm độ trễ median khoảng 1ms, giảm độ trễ P90 hàng chục ms, và cải thiện độ trễ đuôi (P99.5) lên đến 90%. GRL hiện xử lý khoảng 80 triệu yêu cầu mỗi giây trên hơn 1,100 dịch vụ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GRL sử dụng kiến trúc phân tán ba tầng với probabilistic dropping để đạt độ trễ thấp và coordination toàn cầu&lt;/li&gt;
&lt;li&gt;Hệ thống loại bỏ dependency Redis, giảm độ trễ median 1ms và cải thiện độ trễ đuôi lên đến 90%&lt;/li&gt;
&lt;li&gt;RLC tự động hóa cấu hình rate limit bằng cách phân tích traffic trực tiếp và cập nhật limits dựa trên nhu cầu thực tế&lt;/li&gt;
&lt;li&gt;GRL xử lý 80 triệu RPS trên hơn 1,100 dịch vụ và đã ngăn chặn thành công các sự cố quá tải và tấn công DDoS&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="agents-feb-2026"&gt;&lt;a class="link" href="https://calv.info/agents-feb-2026" target="_blank" rel="noopener"
&gt;Agents (Feb 2026)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ kinh nghiệm thực tế của tác giả về việc sử dụng các coding agent khác nhau bao gồm Claude Code (Opus) và Codex (GPT-5.3). Tác giả, người từng tham gia phát triển Codex web product, đã đi đến kết luận rằng cả hai mô hình đều có điểm mạnh và điểm yếu riêng liên quan đến cách đào tạo của chúng. Sự thay đổi lớn nhất trong workflow của ông là thời gian của ông giờ đây trở thành yếu tố quan trọng nhất — ông chọn coding agent dựa trên thời gian có sẵn và mức độ tự chủ mong muốn.&lt;/p&gt;
&lt;p&gt;Tác giả giải thích các nguyên tắc hướng dẫn khi sử dụng coding agents. Điều quan trọng nhất là phải hiểu context — các agent thực sự đang làm next token prediction và mỗi token phải nằm trong context window. Điều này dẫn đến nhiều hệ quả: công việc cần được chia nhỏ, compaction là kỹ thuật có loss, nên externalize context vào filesystem, và nên ở trong &amp;ldquo;nửa thông minh&amp;rdquo; của context window. Hiệu năng của mô hình bị chi phối bởi cả hiệu năng thuần túy của mô hình và khả năng quản lý nhiều context window cũng như ủy quyền cho sub-agents.&lt;/p&gt;
&lt;p&gt;Opus xuất sắc trong việc làm việc across context windows một cách hiệu quả, sử dụng tools tốt hơn, và có tính cách &amp;ldquo;người&amp;rdquo; hơn. Opus thường xuyên spin up nhiều sub-agents song song, sử dụng tool Explore rất nhanh với Haiku, và được đào tạo tốt để sử dụng các tools trên laptop. Trong khi đó, Codex tỏa sáng ở độ chính xác của code — code của Codex có ít bugs hơn đáng kể so với Opus, mặc dù Codex chậm hơn vì không delegate tasks across context windows tốt như Opus.&lt;/p&gt;
&lt;p&gt;Tác giả chia sẻ nhiều kỹ thuật và workflows hữu ích bao gồm: sử dụng thư mục &lt;code&gt;plans/&lt;/code&gt; cho các kế hoạch được đánh số, leverage Cloudflare Durable Objects cho APIs, sử dụng worktrees song song, và quy trình Plan-Implement-Review. Ông cũng xây dựng nhiều skills để tự động hóa workflows như &lt;code&gt;/commit&lt;/code&gt;, &lt;code&gt;/worktree&lt;/code&gt;, &lt;code&gt;/implement&lt;/code&gt;, &lt;code&gt;/address-bugs&lt;/code&gt;, và &lt;code&gt;/pr-pass&lt;/code&gt;. Tương lai theo hướng có laptop hoặc cloud sandbox constantly churning on ideas trong background, và ngày càng nhiều, ideas, architecture, và project sequencing sẽ trở thành các yếu tố giới hạn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Opus xuất sắc ở context management, tool use, và tính cách con người trong khi Codex có độ chính xác code cao hơn&lt;/li&gt;
&lt;li&gt;Hiểu context window là quan trọng — công việc cần được chia nhỏ và externalize context vào filesystem&lt;/li&gt;
&lt;li&gt;Skills cho phép tự động hóa workflows và split context windows hiệu quả&lt;/li&gt;
&lt;li&gt;Tương lai hướng tới việc agents chạy 24/7 với ideas, architecture, và project sequencing trở thành yếu tố giới hạn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-software-industrial-revolution"&gt;&lt;a class="link" href="https://cannoneyed.com/essays/software-industrial-revolution" target="_blank" rel="noopener"
&gt;The Software Industrial Revolution&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết so sánh sự thay đổi hiện tại trong phát triển phần mềm với Cách mạng Công nghiệp lần đầu tiên. Tác giả lập luận rằng chúng ta đang ở bước ngoặt của &amp;ldquo;Cách mạng Công nghiệp Phần mềm&amp;rdquo; — nơi AI coding agents vừa &amp;ldquo;click&amp;rdquo; và bắt đầu hoạt động hiệu quả. Giống như Spinning Jenny năm 1764 đã song song hóa quy trình dệt, giảm giá cotton cloth 90%, AI coding agents đang tự động hóa sản xuất phần mềm và giảm chi phí sản xuất hàng cấp độ.&lt;/p&gt;
&lt;p&gt;Tác giả giải thích rằng phần mềm đã &amp;ldquo;ăn&amp;rdquo; thế giới — ngành công nghệ chiếm khoảng 35% của S&amp;amp;P 500 và gần 50% nếu bao gồm cả communications. Nhưng chi phí sản xuất phần mềm cực kỳ cao đòi hỏi các mô hình kinh doanh problem như VC-funded growth-at-all-costs và &amp;ldquo;enshittification&amp;rdquo; của Cory Doctorow. Sự dồi dào của phần mềm thông qua tự động hóa sẽ mở rộng không gian mô hình kinh doanh phần mềm sang nhiều dạng bền vững hơn.&lt;/p&gt;
&lt;p&gt;Tác giả sử dụng ví dụ về Epic — công ty nắm 42% thị trường bệnh viện acute care Mỹ với biên lợi nhuận 30% — để minh họa cách chi phí phần mềm cao tạo ra độc quyền và kìm hãm cạnh tranh. Khi phần mềm trở nên rẻ hơn thông qua tự động hóa, chúng ta sẽ thấy sự bùng nổ của phần mềm bespoke mới trên mọi ngành và ngách. Tác giả kết luận rằng mặc dù việc sản xuất code sẽ thay đổi căn bản, các kỹ năng cốt lõi của software engineering — modeling domains, quản lý complexity, và sự tương tác giữa phần mềm và thế giới thực — sẽ chỉ trở nên quan trọng hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cách mạng Công nghiệp Phần mềm đang giảm chi phí sản xuất phần mềm hàng cấp độ, giống như Cách mạng Công nghiệp giảm chi phí vải&lt;/li&gt;
&lt;li&gt;Chi phí phần mềm cao tạo ra độc quyền và các mô hình kinh doanh problem như enshittification&lt;/li&gt;
&lt;li&gt;Sự dồi dào của phần mềm sẽ cho phép bất kỳ ai cũng có thể tạo ra công cụ kỹ thuật số mà họ cần&lt;/li&gt;
&lt;li&gt;Các kỹ năng cốt lõi của software engineering sẽ trở nên quan trọng hơn ngay cả khi viết code bằng tay trở nên ít liên quan hơn&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Newsletter #86</title><link>https://miti99.com/post/2026/03/01/</link><pubDate>Sun, 01 Mar 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/03/01/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #86.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="do-not-surrender-to-the-tech-tree"&gt;&lt;a class="link" href="https://www.macroscience.org/p/do-not-surrender-to-the-tech-tree" target="_blank" rel="noopener"
&gt;Do Not Surrender to the Tech Tree&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết khám phá khái niệm xác định công nghệ (technological determinism) - quan điểm cho rằng sự phát triển công nghệ tuân theo logic nội tại và cấu trúc riêng, được quyết định bởi hình dạng của &amp;ldquo;cây công nghệ&amp;rdquo; chứ không phải bởi lựa chọn của con người. Tác giả trình bày bằng chứng thuyết phục: việc phát hiện đồng thời và độc lập các công nghệ là phổ biến trong lịch sử (như quy trình Hall-Héroult để nấu nhôm, động cơ phản lực, vi tích phân, thuyết tiến hóa), và các xã hội bị cô lập luôn hội tụ về cùng các công nghệ cơ bản (bánh xe, nông nghiệp intensify, luyện kim, chữ viết).&lt;/p&gt;
&lt;p&gt;Tuy nhiên, tác giả phản đối quan điểm &amp;ldquo;Technocalvinism&amp;rdquo; - ý kiến cho rằng con người hoàn toàn không thể kiểm soát sự phát triển công nghệ. Thay vào đó, bài viết bảo vệ cái gọi là &amp;ldquo;xác định công nghệ mạnh&amp;rdquo; nhưng với một quan điểm quan trọng: trên khoảng thời gian ngắn, con người có khả năng định hình đáng kể sự phát triển công nghệ, đặc biệt là trong các &amp;ldquo;cửa sổ cơ hội&amp;rdquo; quan trọng. Các ví dụ lịch sử minh họa điều này: sự thành công trong việc hạn chế phổ biến vũ khí hạt nhân (chỉ 9 quốc gia sở hữu thay vì hàng chục như dự đoán), phát triển Permissive Action Links (PALs) để ngăn chặn kích hoạt trái phép, và việc tạo ra vaccine COVID-19 trong 10 tháng thay vì 10-15 năm như quy trình thông thường.&lt;/p&gt;
&lt;p&gt;Bài viết đặc biệt chú trọng đến bối cảnh phát triển AI hiện nay. Tác giả lập luận rằng AI là công nghệ lưỡng dụng theo định nghĩa - quan trọng cho cả phòng thủ và tấn công mạng, cho phát hiện vaccine và nghiên cứu mầm bệnh, cho xe tự hành và drone quân sự. Thay vì chấp nhận &amp;ldquo;cây công nghệ mặc định&amp;rdquo;, chúng ta cần chủ động phát triển các công nghệ giảm thiểu rủi ro song song với việc phát triển AI. Tác giả giới thiệu &amp;ldquo;The Launch Sequence&amp;rdquo; - 16 dự án cụ thể để tăng tốc lợi ích của AI đồng thời xây dựng các biện pháp bảo vệ, bao gồm Operation Patchlight và The Great Refactor (cứng hóa cơ sở hạ tầng mạng trước khi các cuộc tấn công mạng powered bởi AI tấn công quy mô lớn), Hardware-Based Verification (cho phép AI lan truyền nhanh hơn trong khi ngăn chặn sử dụng sai mục đích), và Preventing AI Sleeper Agents (red-test các hệ thống AI Mỹ trước sự can thiệp trái phép).&lt;/p&gt;
&lt;p&gt;Bài viết kết luận bằng một thông điệp mạnh mẽ: cây công nghệ có những ràng buộc cứng nhắc thực sự, nhưng ngoài những ràng buộc đó, hầu hết sự phát triển công nghệ diễn ra theo cách phân tán, phi cá nhân. Tuy nhiên, có những cửa sổ cơ hội nhỏ để thực hiện quyền chủ động, trong đó nỗ lực thay đổi kết quả mặc định có thể mang lại kết quả lâu dài. Chúng ta đang ở một trong những khoảnh khắc đó trong phát triển AI, và cơ hội đang trôi qua nhanh chóng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xác định công nghệ mạnh: công nghệ tuân theo logic nội tại, nhưng con người vẫn có khả năng định hình trong các cửa sổ cơ hội&lt;/li&gt;
&lt;li&gt;Bằng chứng lịch sử: phát hiện đồng thời phổ biến, xã hội cô lập hội tụ về cùng công nghệ&lt;/li&gt;
&lt;li&gt;Cửa sổ cơ hội: hạn chế phổ biến vũ khí hạt nhân, PALs, vaccine COVID-19 nhanh chóng&lt;/li&gt;
&lt;li&gt;AI là lưỡng dụng: quan trọng cho cả phòng thủ và tấn công, cần phát triển bảo vệ song song&lt;/li&gt;
&lt;li&gt;The Launch Sequence: 16 dự án cụ thể để chuẩn bị cho AI tiên tiến&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-to-make-architecture-decisions-rfcs-adrs-and-getting-everyone-aligned"&gt;&lt;a class="link" href="https://lukasniessen.medium.com/how-to-make-architecture-decisions-rfcs-adrs-and-getting-everyone-aligned-ab82e5384d2f" target="_blank" rel="noopener"
&gt;How to Make Architecture Decisions: RFCs, ADRs, and Getting Everyone Aligned&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ quy trình hiệu quả để đưa ra các quyết định kiến trúc trong phát triển phần mềm, tránh được những vấn đề thường gặp như quyết định đưa ra trong cuộc đối thoại ngõ dẫn đến hàng tháng sửa đổi, hoặc tài liệu đẹp nhưng không ai đọc dẫn đến kết quả tương tự. Quy trình cốt lõi gồm bốn bước: viết RFC trong 1-2 ngày, xem xét bất đồng bộ trong 2-3 ngày, họp quyết định trong 30-60 phút, và viết ADR vào cùng ngày.&lt;/p&gt;
&lt;p&gt;RFC là tài liệu giải thích vấn đề, đề xuất giải pháp và mời phản hồi. Bài viết nhấn mạnh tầm quan trọng của việc xác định ưu tiên rõ ràng thay vì chỉ liệt kê ưu/nhược điểm. Khi các ưu tiên được xếp hạng và rõ ràng, quyết định thường trở nên hiển nhiên. Cấu trúc RFC nên bao gồm: tóm tắt, bối cảnh, ưu tiên và yêu cầu (được xếp hạng), các giải pháp đề xuất (bao gồm cả &amp;ldquo;không làm gì&amp;rdquo;), stakeholder, câu hỏi mở, và mốc thời gian.&lt;/p&gt;
&lt;p&gt;Giai đoạn xem xét bất đồng bộ là nơi phép màu xảy ra - cho phép mọi người suy nghĩ trước khi phản hồi, có thể nghiên cứu, &amp;ldquo;ngủ một đêm&amp;rdquo; trước khi đưa ra phản hồi tốt hơn nhiều so với việc bị ép trả lời ngay trong cuộc họp. Cuộc họp quyết định không phải là cuộc họp trình bày - mọi người nên đã đọc RFC và các bình luận, với định dạng làm việc thay vì trình bày: bối cảnh nhanh (2 phút), giải quyết câu hỏi chưa trả lời (10-15 phút), thảo luận (15-30 phút), và quyết định (5-10 phút).&lt;/p&gt;
&lt;p&gt;ADR là hồ sơ vĩnh viễn về những gì đã được quyết định và tại sao. Nó khác với RFC - RFC khám phá các tùy chọn, còn ADR ghi lại quyết định. Bài viết cũng đề cập đến tầm quan trọng của kế hoạch triển khai, vai trò của LLM trong chuẩn bị RFC (không phải viết toàn bộ mà là đối tác tư duy tức thời), và các lỗi thường cần tránh như tê liệt phân tích, quá nhiều stakeholder, không theo dõi, và bỏ qua những người ít nói.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quy trình bốn bước: RFC → Async Review → Decision Meeting → ADR&lt;/li&gt;
&lt;li&gt;Ưu tiên rõ ràng: xếp hạng các yêu cầu giúp quyết định trở nên hiển nhiên&lt;/li&gt;
&lt;li&gt;Async review: cho phép suy nghĩ và nghiên cứu trước khi phản hồi&lt;/li&gt;
&lt;li&gt;Decision meeting: 30-60 phút, không phải presentation meeting&lt;/li&gt;
&lt;li&gt;ADR: ghi vĩnh viễn quyết định và lý do, viết trong cùng ngày quyết định&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-cost-of-a-function-call"&gt;&lt;a class="link" href="https://lemire.me/blog/2026/02/08/the-cost-of-a-function-call/" target="_blank" rel="noopener"
&gt;The cost of a function call&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết khám phá chi phí của lời gọi hàm trong lập trình và lợi ích của việc inline - tối ưu hóa quan trọng mà compiler thay thế lời gọi hàm bằng mã trực tiếp tại vị trí gọi. Một lời gọi hàm khá rẻ nhưng không miễn phí: có thể cần lưu và khôi phục tham số trên stack, nhảy vào và ra khỏi hàm, cùng các câu lệnh thêm ở đầu và cuối hàm.&lt;/p&gt;
&lt;p&gt;Tác giả thực hiện benchmark trên MacBook với chip M4 để so sánh hiệu năng. Với hàm cộng đơn giản, phiên bản inline nhanh hơn 20 lần so với phiên bản regular (0.03 ns/int so với 0.7 ns/int). Lý do: compiler biến đổi phép cộng thành các SIMD instructions xử lý block 16 số nguyên bằng 8 câu lệnh, giảm xuống một nửa câu lệnh mỗi số nguyên (từ 6 câu lệnh). Ngay cả khi ngăn compiler sử dụng SIMD, inline vẫn nhanh hơn 10 lần.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, với hàm phức tạp hơn như đếm khoảng trắng trong chuỗi, kết quả khác. Với chuỗi dài 1000 ký tự, inline phiên bản thậm chí chậm hơn một chút (115 ns so với 111 ns). Nhưng với chuỗi ngắn (0-6 ký tự), inline nhanh hơn đáng kể (1.0 ns so với 1.6 ns). Bài học: các hàm ngắn và đơn giản nên được inline khi hiệu năng là mối quan tâm, lợi ích có thể ấn tượng. Với các hàm có thể nhanh hoặc chậm tùy input, quyết định inline phụ thuộc vào dữ liệu đầu vào.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lời gọi hàm không miễn phí: overhead lưu khôi phục tham số, nhảy jump, setup/teardown&lt;/li&gt;
&lt;li&gt;Inline hàm đơn giản: nhanh hơn 20x nhờ SIMD, 10x ngay cả khi không SIMD&lt;/li&gt;
&lt;li&gt;Compiler tối ưu: biến vòng lặp thành SIMD block processing, giảm câu lệnh&lt;/li&gt;
&lt;li&gt;Context quan trọng: hàm phức tạp trên dữ liệu lớn có thể không lợi từ inline&lt;/li&gt;
&lt;li&gt;Quy tắc: hàm ngắn đơn giản nên inline khi hiệu năng quan trọng&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-perfect-code-review-how-to-reduce-cognitive-load-while-improving-quality"&gt;&lt;a class="link" href="https://bastrich.tech/perfect-code-review/" target="_blank" rel="noopener"
&gt;The PERFECT Code Review: How to Reduce Cognitive Load While Improving Quality&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giới thiệu khung PERFECT - bộ nguyên tắc code review có cấu trúc giúp giảm tải nhận thức trong khi cải thiện chất lượng. Code review thường mang lại cảm giác kháng cự: quá nhiều con đường để theo dõi, quá nhiều sự mơ hồ, quá nhiều ý kiến chủ quan. Sự không chắc chắn này sinh ra trì hoãn và bikeshedding, hoặc ở thái cực opposite, các phê duyệt nhanh chóng không đáng kể.&lt;/p&gt;
&lt;p&gt;PERFECT là viết tắt của bảy nguyên tắc theo thứ tự quan trọng: Purpose (mã giải quyết nhiệm vụ), Edge Cases (xử lý các trường hợp ngoại lệ), Reliability (không có vấn đề hiệu năng và bảo mật), Form (tuân thủ nguyên tắc thiết kế), Evidence (tests và CI pipelines pass), Clarity (mã truyền đạt rõ ràng ý định), và Taste (sở thích cá nhân được ghi chú nhưng không chặn thay đổi).&lt;/p&gt;
&lt;p&gt;Tác giả nhấn mạnh rằng code review không phải là collection các practices yes-or-no nghiêm ngặt, mà là spectrum các kỹ thuật có thể áp dụng độc lập với nhau. Ngay cả lightweight nhưng structured review thường có chi phí thấp và mang lại giá trị đáng kể. Để làm cho nó thực sự hoạt động, các team nên thiết lập các quy ước review bằng văn bản, giữ chúng cập nhật và có thể hành động, yêu cầu self-review trước peer review, tích hợp code review vào quy trình phát triển, tự động hóa mọi thứ có thể, ngừng phê duyệt với &amp;ldquo;LGTM&amp;rdquo;, và thực hành code review bất cứ khi nào có thể.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PERFECT framework: 7 nguyên tắc theo thứ tự quan trọng cho code review hiệu quả&lt;/li&gt;
&lt;li&gt;Purpose là #1: mã phải giải quyết nhiệm vụ, nếu không thì không có giá trị&lt;/li&gt;
&lt;li&gt;Edge Cases: nhiều production bugs đến từ việc bỏ qua corner cases&lt;/li&gt;
&lt;li&gt;Taste không chặn: sở thích cá nhân được ghi chú nhưng author có thể chọn không giải quyết&lt;/li&gt;
&lt;li&gt;Self-review trước: mọi người nên tự review bằng cùng quy ước trước khi gửi cho người khác&lt;/li&gt;
&lt;li&gt;Quy ước văn bản: chuyển pattern lặp lại thành quy ước để tiết kiệm thời gian&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="semantic-search-without-embeddings"&gt;&lt;a class="link" href="https://softwaredoug.com/blog/2026/01/08/semantic-search-without-embeddings.html" target="_blank" rel="noopener"
&gt;Semantic Search Without Embeddings&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết thách thức quan điểm phổ biến rằng semantic search đồng nghĩa với vector search, và giới thiệu các phương pháp khác để modeling similarity và filter kết quả search. Semantic search thực sự cần ba thành phần: shared representation (không gian chung cho query và content), similarity function (cách đo khoảng cách), và match criteria (hệ thống để nói item có &amp;ldquo;match&amp;rdquo; hay không). Embeddings giỏi hai thành phần đầu nhưng kém thành phần thứ ba - không có cách tốt để include/exclude kết quả.&lt;/p&gt;
&lt;p&gt;Tác giả giới thiệu managed vocabularies hoặc taxonomies - hệ thống map queries và content vào hierarchy của concepts, sử dụng ngôn ngữ của domain. Ví dụ Wayfair WANDS dataset với category tree như &amp;ldquo;Baby &amp;amp; Kids / Toddler &amp;amp; Kids Playroom / Indoor Play / Rocking Horses / Novelty Rocking Horses&amp;rdquo;. Taxonomy cung cấp representation (category tree), similarity function (direct matches rank cao hơn parents/siblings), và match criteria (include shared parent categories, exclude beyond cousins/grandparents).&lt;/p&gt;
&lt;p&gt;Điều thú vị là semantic similarity không cần vector index - có thể thực hiện với BM25 index thông qua hierarchical tokenization. Tokenizer tạo ra full path của mọi parent directory, và BM25 rewards rare match over common match. Root nodes có document frequency cao (common) nên score thấp, trong khi child nodes có document frequency thấp (rare) nên score cao. Điều này tạo ra scoring hierarchy: direct matches &amp;gt; parent &amp;gt; grandparent.&lt;/p&gt;
&lt;p&gt;Tác giả cũng đề cập đến việc xây dựng taxonomy có thể bắt đầu đơn giản và evolve theo thời gian, và LLMs đã làm cho việc classifying into taxonomies dễ dàng hơn bao giờ hết. Embeddings có thể hữu ích để xây dựng better classifiers (không phải direct ranking), và sweet spot của embeddings trong search có thể là building better classifiers thay vì direct ranking và retrieval.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Semantic search cần 3 thành phần: representation, similarity, và match criteria&lt;/li&gt;
&lt;li&gt;Embeddings giỏi ranking nhưng kém include/exclude kết quả&lt;/li&gt;
&lt;li&gt;Taxonomy: hierarchy concepts cung cấp tất cả 3 thành phần&lt;/li&gt;
&lt;li&gt;Hierarchical tokenization trong BM25: tự động score direct &amp;gt; parent &amp;gt; grandparent&lt;/li&gt;
&lt;li&gt;Root nodes common (score thấp), child nodes rare (score cao)&lt;/li&gt;
&lt;li&gt;LLMs supercharge taxonomies: dễ classify queries và products&lt;/li&gt;
&lt;li&gt;Embeddings sweet spot: building classifiers, không phải direct retrieval&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="my-ai-adoption-journey"&gt;&lt;a class="link" href="https://mitchellh.com/writing/my-ai-adoption-journey" target="_blank" rel="noopener"
&gt;My AI Adoption Journey&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ hành trình cá nhân của Mitchell Hashimoto - người tạo ra Vagrant, Terraform, và Ghostty - về việc tìm ra giá trị trong AI tooling. Tác giả chia trải nghiệm adopting tool thành ba giai đoạn: inefficiency, adequacy, và workflow/life-altering discovery. Hầu hết mọi người phải ép buộc bản thân vượt qua giai đoạn inefficiency vì đã có workflow thoải mái, và adopting AI cảm giác như công việc.&lt;/p&gt;
&lt;p&gt;Sáu bước trong hành trình: (1) Bỏ chatbot - ngay lập tức ngừng cố gắng thực hiện công việc có ý nghĩa qua chatbot, phải dùng agent với khả năng đọc file, thực thi chương trình, và HTTP request. (2) Reproduce work của mình - ép buộc reproduce tất cả manual commits với agentic ones, làm công việc hai lần để khám phá ra các pattern hữu ích như break down thành tasks rõ ràng, split planning vs execution cho requests mơ hồ, và give agent cách verify work. (3) End-of-day agents - block 30 phút cuối mỗi ngày để kick off agents, làm thêm trong thời gian không thể làm anyways với deep research sessions, parallel agents cho ý tưởng mơ hồ, và issue/PR triage.&lt;/p&gt;
&lt;p&gt;(4) Outsource slam dunks - cho agents làm tất cả công việc mà AI chắc chắn làm tốt trong khi mình làm task khác. Quan trọng: tắt thông báo desktop của agent để tránh context switching, và human kiểm soát khi interrupt. (5) Engineer the harness - bất cứ khi nào agent làm sai, engineer giải pháp để agent không bao giờ lặp lại lỗi đó nữa, qua better implicit prompting (AGENTS.md) và programmed tools. (6) Always have agent running - mục tiêu có agent chạy mọi lúc, kết hợp với slower thoughtful models như Amp&amp;rsquo;s deep mode, nhưng chỉ chạy khi có task thực sự hữu ích.&lt;/p&gt;
&lt;p&gt;Tác giả hiện tại không chạy multiple agents, tìm thấy một agent là balance tốt giữa deep manual work và babysitting robot friend. Mục tiêu &amp;ldquo;have agent running at all times&amp;rdquo; vẫn chỉ là mục tiêu, hiện tại hiệu quả khoảng 10-20% ngày làm việc bình thường. Tác giả nhấn mạnh không muốn chạy agents vì sake of running agents, chỉ khi có task thực sự helpful.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;3 giai đoạn: inefficiency → adequacy → discovery&lt;/li&gt;
&lt;li&gt;Drop chatbot: agent cần read files, execute programs, HTTP requests&lt;/li&gt;
&lt;li&gt;Reproduce work: làm twice để học patterns, break down tasks rõ ràng&lt;/li&gt;
&lt;li&gt;End-of-day agents: làm thêm trong thời gian không thể làm, research/triage&lt;/li&gt;
&lt;li&gt;Outsource slam dunks: agents làm task chắc chắn đúng, tắt notifications&lt;/li&gt;
&lt;li&gt;Engineer harness: AGENTS.md + programmed tools để prevent repeated mistakes&lt;/li&gt;
&lt;li&gt;Always running: có agent chạy mọi lúc, nhưng chỉ cho task thực sự helpful&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="software-engineering-is-back"&gt;&lt;a class="link" href="https://blog.alaindichiappari.dev/p/software-engineering-is-back" target="_blank" rel="noopener"
&gt;Software Engineering is back&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ quan điểm rằng automated programming - cái tên mà Antirez ưa chuộng hơn &amp;ldquo;vibe coding&amp;rdquo; - đã mang lại software engineering thực sự quay trở lại. Tác giả đã xây dựng sản phẩm từ đầu đến cuối với frontier models và coding agents hàng giờ mỗi ngày, và kể từ tháng 12/2025, mọi thứ đã thay đổi đáng kể. Tác giả có thể là kiến trúc sư mà không cần làm việc vất vả của việc đặt từng viên gạch và trét vữa, nhưng vẫn làm được với kinh nghiệm 20 năm đặt gạch, trét vũ.&lt;/p&gt;
&lt;p&gt;Tác giả lập luận rằng frameworks thực sự giải quyết ba vấn đề: &amp;ldquo;Simplification&amp;rdquo; - nhưng đây thực sự là intellectual surrender thay vì simplification; Automation - xử lý boilerplate; và Labour cost - vấn đề quiet mà không ai tuyên bố, cho phép công ty thuê React Developer thay vì Software Engineer. Với automated programming, automation và boilerplating chưa bao giờ rẻ để overcome, tác giả không bao giờ viết cùng một dòng code hai lần, build purpose-built tools xung quanh problem at hand. Bash (sinh năm 1989) là universal adapter và công cụ oldest đã trở nên most future-proof.&lt;/p&gt;
&lt;p&gt;Bài viết kêu gọi mọi người ngừng accept trade-off này và ngừng wrapping broken legs in silk. Các tools và models đã ở đây, revolution đã xảy ra nhưng hầu hết mọi người vẫn đang decorate old house. Hãy bắt đầu xây dựng những thứ thuộc về mình thay vì để Google, Meta, và Vercel là kiến trúc sư, designer, thinker của bạn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Automated programming: software engineering thực sự quay trở lại&lt;/li&gt;
&lt;li&gt;3 vấn đề frameworks giải quyết: simplification (thực ra surrender), automation, labour cost&lt;/li&gt;
&lt;li&gt;Simplification giả: mua thinking off-shelf thay vì sharpen mental models&lt;/li&gt;
&lt;li&gt;Labour cost thật: thuê React Developer thay vì Software Engineer&lt;/li&gt;
&lt;li&gt;Agents giỏi basic tools: Bash (1989) là universal adapter&lt;/li&gt;
&lt;li&gt;Revolution đã xảy ra: stop decorating old house, build yours&lt;/li&gt;
&lt;li&gt;Broken leg in silk: frameworks wrap problems không nên tồn tại&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="art-of-roads-in-games"&gt;&lt;a class="link" href="https://sandboxspirit.com/blog/art-of-roads-in-games/" target="_blank" rel="noopener"
&gt;Art of Roads in Games&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết khám phá nghệ thuật và toán học đằng sau việc mô phỏng đường trong game city builder. Tác giả chia sẻ sự say mê với đường từ khi còn nhỏ chơi SimCity 2000, và nhận ra rằng đường là nền tảng mà các thành phố được xây dựng. Mặc dù mỗi game mang lại cải thiện hơn game trước, nhưng luôn có gì đó không đúng - highway ramps unrealistically sharp hoặc wobbly, lanes supposed high-speed bent quá sharply, corner radii của intersections trông strange.&lt;/p&gt;
&lt;p&gt;Vấn đề cơ bản nằm ở Bezier Spline - công cụ mà game developers dùng để tạo đường. Bezier curves elegant, intuitive và powerful, nhưng chúng không preserve shape và curvature khi offset. Trong thực tế, roads có shape từ underlying fact: wheel axles của vehicle giữ constant distance, tạo ra parallel paths với consistent curved shape. Bezier curves không maintain parallelism, đặc biệt với tight bends, geometry often fails với &amp;ldquo;pinching&amp;rdquo; hoặc self-intersecting.&lt;/p&gt;
&lt;p&gt;Giải pháp? Circle Arcs - cái mà mọi người đã học trong kindergarten. Circle có magical property: không matter offset bao nhiêu, result vẫn là circular arc perfectly parallel với initial. Stitching together circular arcs với different radii có thể create any shape trong khi adhering to proper engineering principles. Circle arcs cũng mang lại bonus performance: curve-curve intersection là O(1) formula thay vì complex iterative methods như Bezier.&lt;/p&gt;
&lt;p&gt;Nhưng circles có vấn đề: constant curvature. Khi entering circular curve từ straight line, lateral force jumps từ 0 đến fixed constant value - cảm giác terrible ở high speed. Civil engineers sử dụng transition curves, most famously the clothoid - gradually increases curvature over distance, steering wheel rotates smoothly, forces ramp up naturally. Clothoids maintain parallel offsets và continuous curvature changes, nhưng là math nightmare với differential geometry và integrals.&lt;/p&gt;
&lt;p&gt;Tác giả quyết định build road system của riêng mình vì curiosity và vì established titles có thể không accurately render roads nhưng vẫn light-years ahead so với indie solutions. Tutorials và assets online sad, và tác giả muốn build better solution để share với anyone muốn build city builder.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Roads fascination: fabric mà cities được xây dựng trong city builders&lt;/li&gt;
&lt;li&gt;Bezier problem: không preserve parallelism, geometry fails tại tight bends&lt;/li&gt;
&lt;li&gt;Circle arcs solution: maintain parallelism, O(1) intersection&lt;/li&gt;
&lt;li&gt;Circle limitation: constant curvature gây uncomfortable jumps ở high speed&lt;/li&gt;
&lt;li&gt;Clothoid transition: gradually increases curvature, math nightmare&lt;/li&gt;
&lt;li&gt;Indie gap: big titles accurate nhưng indie solutions sad&lt;/li&gt;
&lt;li&gt;Curiosity driven: muốn explore và share better solution&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bonus"&gt;Bonus
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Hình ảnh:&lt;/strong&gt;
&lt;img src="https://substackcdn.com/image/fetch/w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7712ce10-d199-49ef-94f9-e983e47a92d9_2360x2852.png"
loading="lazy"
alt="12 Architectural Concepts Developers Should Know"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #85</title><link>https://miti99.com/post/2026/02/28/</link><pubDate>Sat, 28 Feb 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/02/28/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #85.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="how-i-use-claude-code"&gt;&lt;a class="link" href="https://boristane.com/blog/how-i-use-claude-code/" target="_blank" rel="noopener"
&gt;How I Use Claude Code&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả chia sẻ quy trình làm việc hiệu quả khi sử dụng Claude Code trong 9 tháng qua, với một nguyên tắc cốt lõi: không bao giờ để Claude viết mã cho đến khi bạn đã xem xét và phê duyệt một kế hoạch viết tay. Phương pháp này tách biệt hai giai đoạn tư duy và thực thi, giúp ngăn chặn sự lãng phí công sức, giữ người lập trình kiểm soát các quyết định kiến trúc, và tạo ra kết quả tốt hơn nhiều.&lt;/p&gt;
&lt;p&gt;Quy trình được chia thành ba giai đoạn chính. Giai đoạn Nghiên cứu bắt đầu bằng việc yêu cầu Claude đọc sâu phần cơ sở mã liên quan và viết báo cáo chi tiết vào tệp &lt;code&gt;research.md&lt;/code&gt;. Giai đoạn Lập kế hoạch tạo ra tệp &lt;code&gt;plan.md&lt;/code&gt; với hướng dẫn triển khai cụ thể. Điều thú vị nhất là Vòng lặp ghi chú (Annotation Cycle) - tác giả mở tệp kế hoạch trong trình soạn thảo và thêm ghi chú trực tiếp vào tài liệu để sửa các giả định sai, từ chối phương án không phù hợp, hoặc bổ sung kiến thức lĩnh vực. Quá trình này lặp lại 1-6 lần cho đến khi kế hoạch hoàn chỉnh.&lt;/p&gt;
&lt;p&gt;Giai đoạn Triển khai diễn ra sau khi mọi quyết định đã được xác nhận, với câu lệnh chuẩn yêu cầu Claude thực thi toàn bộ kế hoạch, đánh dấu hoàn thành từng tác vụ, chạy kiểm tra kiểu liên tục, và không dừng cho đến khi tất cả hoàn thành. Tác giả nhấn mạnh việc thực thi nên trở nên &amp;ldquo;nhàm chán&amp;rdquo; - công việc sáng tạo đã diễn ra trong các vòng lặp ghi chú, và khi kế hoạch đúng, thực thi phải thẳng tiến. Cách tiếp cận này loại triệt để các giả định sai được xây đắp chồng chất trong 15 phút, giúp người lập trình luôn ngồi ghế lái và đưa ra các quyết định quan trọng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tách biệt tư duy và thực thi: luôn viết kế hoạch trước khi viết mã&lt;/li&gt;
&lt;li&gt;Vòng lặp ghi chú: thêm ghi chú trực tiếp vào kế hoạch để tinh chỉnh và sửa lỗi sai&lt;/li&gt;
&lt;li&gt;Tệp markdown làm trạng thái chia sẻ: giúp duy trì ngữ cảnh và quyết định&lt;/li&gt;
&lt;li&gt;Chạy trong một phiên dài: tận dụng tích lũy ngữ cảnh thay vì chia nhỏ phiên&lt;/li&gt;
&lt;li&gt;Giữ quyền kiểm soát: người lập trình đưa ra quyết định, Claude thực thi cơ khí&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="next-generation-db-ingestion-at-pinterest"&gt;&lt;a class="link" href="https://medium.com/pinterest-engineering/next-generation-db-ingestion-at-pinterest-66844b7153b7" target="_blank" rel="noopener"
&gt;Next-Generation DB Ingestion at Pinterest&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Pinterest chia sẻ hành trình xây dựng khung làm việc nhập liệu cơ sở dữ liệu thế hệ mới dựa trên Change Data Capture (CDC), thay thế hệ thống batch cũ kỹ gặp nhiều hạn chế. Hệ thống cũ có độ trễ dữ liệu cao (trên 24 giờ), xử lý kém hiệu quả do chạy full-table batch hàng ngày dù thay đổi thực tế dưới 5%, thiếu hỗ trợ xóa theo hàng cho tuân thủ, và phức tạp trong vận hành với nhiều quy trình độc lập.&lt;/p&gt;
&lt;p&gt;Giải pháp mới là khung làm việc thống nhất sử dụng Debezium/TiCDC, Kafka, Flink, Spark và Iceberg, cung cấp dữ liệu trong vài phút thay vì ngày, chỉ xử lý các bản ghi thay đổi để tiết kiệm chi phí, hỗ trợ xóa theo hàng và xử lý tăng dần. Kiến trúc gồm ba lớp chính: lớp CDC bắt thay đổi cơ sở dữ liệu với độ trễ dưới 1 giây và ghi vào Kafka; lớp Streaming (Flink) xử lý sự kiện gần thời gian thực vào bảng CDC Iceberg trên S3; lớp Batch (Spark) định kỳ lấy thay đổi từ bảng CDC và dùng &lt;code&gt;Merge Into&lt;/code&gt; để upsert vào bảng Iceberg cơ sở.&lt;/p&gt;
&lt;p&gt;Bài viết chi tiết nhiều tối ưu hóa quan trọng. Phân vùng bảng cơ sở bằng băm của khóa chính sử dụng hàm &lt;code&gt;bucket()&lt;/code&gt; giúp phân tán đều bản ghi và cải thiện hiệu suất upsert. Với vấn đề tệp nhỏ, thiết lập &lt;code&gt;WRITE DISTRIBUTED BY PARTITION&lt;/code&gt; giảm số lượng tệp nhỏ và cải thiện hiệu suất. Bucket Join cho các bảng lớn, sử dụng bảng tạm trung gian để bỏ qua toàn bộ thao tác trộn của bảng cơ sở, giúp giảm 40%+ chi phí tính toán và độ trễ đáng kể. Pinterest chọn Merge-on-Read (MOR) thay vì Copy-on-Write (COW) vì chi phí lưu trữ của COW cao hơn nhiều.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Từ batch sang CDC: giảm độ trễ từ 24 giờ xuống 15-60 phút&lt;/li&gt;
&lt;li&gt;Kiến trúc hai bảng: bảng CDC (append-only, &amp;lt;5 phút) và bảng cơ sở (snapshot, 15-60 phút)&lt;/li&gt;
&lt;li&gt;Tối ưu hóa phân vùng bucket: phân tán đều bản ghi, upsert song song hiệu quả&lt;/li&gt;
&lt;li&gt;Bucket Join với bảng tạm: giảm 40%+ chi phí tính toán&lt;/li&gt;
&lt;li&gt;Merge-on-Read: ưu tiên vì chi phí lưu trữ thấp hơn Copy-on-Write&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="thank-you-ai"&gt;&lt;a class="link" href="https://www.kraxel.org/blog/2026/01/thank-you-ai/" target="_blank" rel="noopener"
&gt;Thank you, AI&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một câu chuyện ngắn về hậu quả không mong muốn của AI scrapers. Tác giả đã chạy máy chủ git tự lưu trữ công khai từ năm 2011 (và CVS trước đó), nhưng buộc phải đóng cửa sau khi các bot AI tấn công giao diện cgit với hàng loạt yêu cầu vô bổ đến mức &amp;ldquo;gây chết&amp;rdquo; máy chủ. Thay vì chiến đấu với scrapers, tác giả quyết định chuyển tất cả kho lưu trữ sang GitLab và GitHub - hầu hết đã có bản sao sẵn ở đó.&lt;/p&gt;
&lt;p&gt;Điều đáng chú ý là ngay cả khi dịch vụ git đã bị tắt, AI scrapers vẫn tiếp tục tấn công. Hàng triệu phản hồi 404 không đủ để thuyết phục bot rằng dịch vụ cgit không còn tồn tại, và các tệp nhật ký đã lấp đầy đĩa nhanh đến mức logrotate không kịp xử lý, gây ra một lần sự cố khác. Tác giả đã di chuyển blog từ WordPress sang Jekyll từ 2018 nên là các trang tĩnh, ít bị ảnh hưởng hơn, nhưng vẫn phải điều chỉnh cấu hình logrotate để ngăn vấn đề tương tự. Câu chuyện này là lời nhắc nhở về tác động của AI scrapers đối với các dịch vụ tự lưu trữ quy mô nhỏ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI scrapers tấn công máy chủ git tự lưu trữ đến mức không thể phục hồi&lt;/li&gt;
&lt;li&gt;Chuyển sang GitLab/GitHub thay vì xây dựng lại máy chủ&lt;/li&gt;
&lt;li&gt;Scrapers vẫn tiếp tục gửi yêu cầu sau khi dịch vụ tắt, lấp đầy đĩa bằng nhật ký&lt;/li&gt;
&lt;li&gt;Trang tĩnh (Jekyll) an toàn hơn trang động (WordPress)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="java-ui-in-2026-the-complete-guide"&gt;&lt;a class="link" href="https://robintegg.com/2026/02/08/java-ui-in-2026-the-complete-guide" target="_blank" rel="noopener"
&gt;Java UI in 2026: The Complete Guide&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Hướng dẫn toàn diện về các framework UI Java năm 2026, bao phủ web, desktop, mobile và terminal interfaces. Tác giả khẳng định đây không phải là các dự án lỗi thời (legacy) mà là công nghệ production-ready, được bảo trì actively và đang chạy tại các doanh nghiệp lớn, phục vụ hàng triệu người dùng trên toàn thế giới.&lt;/p&gt;
&lt;p&gt;Bài viết phân loại frameworks theo 4 nhóm chính. Web UI có Vaadin (server-driven, viết toàn bộ bằng Java), Apache Wicket (component-oriented từ 2004), TeaVM (biên dịch Java bytecode sang JavaScript/WebAssembly), HTMX + Spring Boot (hypermedia-driven), j2html (type-safe HTML builder) và PrimeFaces (thư viện 100+ component cho Jakarta EE). Desktop UI có JavaFX (tiêu chuẩn hiện đại với CSS styling), JCEF (wrapper Chromium), Swing với FlatLaf (được làm mới), và Eclipse RCP/NetBeans Platform cho ứng dụng mô-đun phức tạp. Mobile có Codename One (write-once-run-anywhere, cloud builds, không cần Mac cho iOS) và Gluon Mobile (mở rộng JavaFX với GraalVM). Terminal có JLine (console input) và Lanterna (GUI toolkit cho terminal).&lt;/p&gt;
&lt;p&gt;Insights quan trọng: Java UI ecosystem mạnh mẽ và production-ready, không còn là legacy technology. Frameworks hiện đại tập trung vào developer experience, type safety và native performance. Java vẫn là lựa chọn hàng đầu cho enterprise applications nhờ tính ổn định và hiệu năng, với sự phân biệt rõ ràng giữa server-driven (Vaadin), client-side (TeaVM) và hybrid approaches.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java UI production-ready: không phải legacy, đang chạy tại doanh nghiệp lớn&lt;/li&gt;
&lt;li&gt;Web UI đa dạng: từ server-driven (Vaadin) đến client-side (TeaVM)&lt;/li&gt;
&lt;li&gt;Desktop hiện đại: JavaFX là tiêu chuẩn, Swing được hồi sinh với FlatLaf&lt;/li&gt;
&lt;li&gt;Mobile thực tế: Codename One và Gluon Mobile giúp viết Java cho iOS/Android&lt;/li&gt;
&lt;li&gt;Terminal UI: JLine và Lanterna cho console applications&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="java-full-stack-development-in-2026"&gt;&lt;a class="link" href="https://www.ophion.org/2026/02/java-full-stack-development-in-2026/" target="_blank" rel="noopener"
&gt;Java Full Stack Development in 2026&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả chia sẻ kinh nghiệm chuyển đổi ứng dụng &lt;a class="link" href="https://www.scanii.com" target="_blank" rel="noopener"
&gt;www.scanii.com&lt;/a&gt; từ stack webpack+TypeScript+Spring Boot truyền thống sang kiến trúc đơn giản hơn với server-side rendering, đạt được nhiều cải thiện đáng kể: codebase được hợp nhất với đơn giản &amp;ldquo;Run&amp;rdquo; target trong IntelliJ, thời gian build frontend giảm xuống 0 với tự động reload, partial page rendering như SPA nhưng vẫn có thể dùng React nếu muốn, 100 điểm Lighthouse performance score, và dễ debug hơn không cần source maps hay transpilation.&lt;/p&gt;
&lt;p&gt;Ba bước chính để di chuyển: Chọn template engine (tác giả dùng JTE vì có toàn bộ JDK trong template và view model map tốt với Page objects), loại bỏ bundler và sử dụng importmaps (chuẩn HTML) thay vì webpack/TypeScript, kết hợp với webjars để serve dependencies trực tiếp từ Spring Boot mà không cần CDN bên thứ ba. Cung cấp tính tương tác với Turbo và Stimulus từ Hotwire.dev (theo hướng dẫn của Rails) để đạt automatic partial page updates và familiar MVC framework cho JavaScript vẫn cần thiết.&lt;/p&gt;
&lt;p&gt;Pain points và giải pháp: Thiếu HOT Reloading được giải quyết bằng logic tối giản client-side (poll server changes) và server-side (monitor filesystem changes), nhanh hơn solution frontend trước đó. CSRF protection trở nên phức tạp với server-side rendering vì Spring Security relied on random tokens trong mỗi form, gây vấn đề với Turbo page caching. Tác giả build custom CSRF filter dựa trên header Sec-Fetch-Site, không cần tokens trong templates hay issues với partial page reloads.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Server-side rendering: codebase hợp nhất, build time 0, debug dễ dàng hơn&lt;/li&gt;
&lt;li&gt;Importmaps thay vì bundler: theo chuẩn HTML, kết hợp webjars serve dependencies từ Spring Boot&lt;/li&gt;
&lt;li&gt;Turbo + Stimulus: partial page updates như SPA mà không cần React&lt;/li&gt;
&lt;li&gt;CSRF custom filter: dùng Sec-Fetch-Site header thay vì tokens&lt;/li&gt;
&lt;li&gt;Small teams: phù hợp cho team generalist thay vì specialized teams&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sharding-databases-with-spring-boot-patterns-pitfalls-and-failure-modes"&gt;&lt;a class="link" href="https://dev.to/adamthedeveloper/sharding-databases-with-spring-boot-patterns-pitfalls-and-failure-modes-4p37" target="_blank" rel="noopener"
&gt;Sharding Databases with Spring Boot: Patterns, Pitfalls, and Failure Modes&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Hướng dẫn chi tiết về triển khai sharding database sử dụng Spring Boot - kỹ thuật phân tán dữ liệu quan trọng để giải quyết vấn đề hiệu quả và khả năng mở rộng của các ứng dụng lớn. Bài viết đề cập các pattern chính: Sharding theo chiều ngang (phân tán dữ liệu dựa trên trường cụ thể như user ID đến nhiều database/table khác nhau), Sharding theo chiều dọc (phân tán theo logic kinh doanh, mỗi shard xử lý nhóm chức năng riêng), và Sharding logic sử dụng thuật toán hash modulo để định tuyến dữ liệu đến shard phù hợp.&lt;/p&gt;
&lt;p&gt;Các vấn đề và lỗi phổ biến khi sharding: SQL không tương thích vì các truy vấn hoạt động tốt trên database đơn có thể lỗi trên hệ thống sharding, distributed transaction dựa trên XA không đảm bảo hiệu quả trong môi trường cao đồng thời, độ phức tạp quản lý tăng lên khi phải xác định database/table để truy xuất dữ liệu, và thách thức truy vấn chéo khi cần kết hợp giữa các shard yêu cầu tổng hợp dữ liệu. Giới hạn số lượng shard quan trọng vì quá nhiều shard dẫn đến hiệu suất kém do tổng hợp dữ liệu.&lt;/p&gt;
&lt;p&gt;Khuyến nghị và thực hành tốt nhất: Ưu tiên transaction đơn database, có thể sử dụng transaction cục bộ trong cùng database để tránh distributed transaction. Cẩn thận với phụ thuộc phiên bản vì lỗi tương thích giữa Spring Boot và ShardingSphere thường gặp. Cấu hình minh bạch sử dụng Spring Boot Starter để quản lý cấu hình sharding hiệu quả. Theo dõi hiệu suất để đảm bảo việc sharding thực sự cải thiện hiệu suất không gây thêm độ trễ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ba pattern sharding: ngang (theo trường), dọc (theo logic), logic (hash modulo)&lt;/li&gt;
&lt;li&gt;Pitfalls phổ biến: SQL không tương thích, XA transaction kém hiệu quả, độ phức tạp tăng&lt;/li&gt;
&lt;li&gt;Cross-shard queries: thách thức tổng hợp dữ liệu từ nhiều shard&lt;/li&gt;
&lt;li&gt;Giới hạn shard: quá nhiều shard làm giảm hiệu suất do tổng hợp&lt;/li&gt;
&lt;li&gt;Transaction cục bộ: ưu tiên single-DB transaction thay vì distributed&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="go-made-me-fast-rust-made-me-care-aws-made-me-pay"&gt;&lt;a class="link" href="https://dev.to/art_light/go-made-me-fast-rust-made-me-care-aws-made-me-pay-2f82" target="_blank" rel="noopener"
&gt;Go Made Me Fast, Rust Made Me Care, AWS Made Me Pay&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết thảo luận về lựa chọn ngôn ngữ lập trình cho kiến trúc cloud, tập trung vào sự đánh đổi giữa Go và Rust khi hệ thống phát triển từ &amp;ldquo;hợp lý&amp;rdquo; thành &amp;ldquo;đắt tiền&amp;rdquo;. Tác giả chia sẻ kinh nghiệm thực tế về sự khác biệt giữa hai ngôn ngữ trong bối cảnh AWS, nơi chi phí được tính theo chu kỳ CPU, lượng bộ nhớ và lưu lượng mạng.&lt;/p&gt;
&lt;p&gt;Go giúp phát triển nhanh với mô hình đồng trình đơn giản, thư viện chuẩn mạnh mẽ và dự đoán được. Tuy nhiên bộ thu gom rác (GC) của Go trở thành điểm yếu khi hệ thống mở rộng - nó yêu cầu bộ nhớ phụ, tiêu tốn CPU và gây độ trễ không đáng tin cậy. Rust không phải là phép màu tốc độ, mà buộc nhà phát triển phải đối mặt với các vấn đề cấp thấp như phân bổ bộ nhớ, sở hữu dữ liệu và hành vi cache. Điều này dẫn đến thiết kế hệ thống hiệu quả hơn với bộ nhớ ổn định, độ trễ nhất quán và mật độ container cao hơn.&lt;/p&gt;
&lt;p&gt;AWS đóng vai trò như thực tế khắc nghiệt - nó không quan tâm đến trải nghiệm nhà phát triển, chỉ tính phí theo tài nguyên sử dụng. Sự khác biệt chi phí không nằm ở ngôn ngữ mà ở hiệu quả sử dụng tài nguyên. Bài học quan trọng: Go vẫn hoàn hảo cho API và logic nghiệp vụ, trong khi Rust phù hợp cho đường dẫn dữ liệu cao throughput. Điểm ngọt ngào là sử dụng cả hai ngôn ngữ một cách có chủ đích, với Rust trong các phần nhạy cảm hiệu năng để tối ưu hóa hóa đơn AWS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go nhanh phát triển: GC đơn giản, thư viện mạnh, nhưng GC overhead khi scale&lt;/li&gt;
&lt;li&gt;Rust ép tư duy: đối mặt vấn đề cấp thấp, thiết kế hiệu quả hơn, bộ nhớ ổn định&lt;/li&gt;
&lt;li&gt;AWS tính phí thực tế: không quan tâm DX, chỉ tính CPU/memory/network&lt;/li&gt;
&lt;li&gt;Hybrid approach: Go cho API/business logic, Rust cho high-throughput data paths&lt;/li&gt;
&lt;li&gt;Sweet spot: Rust tối ưu phần nhạy cảm hiệu năng để giảm hóa đơn AWS&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-cloud-is-not-your-computer-why-go-and-rust-developers-secretly-miss-the-monolith"&gt;&lt;a class="link" href="https://dev.to/art_light/the-cloud-is-not-your-computer-why-go-and-rust-developers-secretly-miss-the-monolith-594c" target="_blank" rel="noopener"
&gt;The Cloud Is Not Your Computer: Why Go and Rust Developers Secretly Miss the Monolith&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích sự thật rằng đám mây không phải là máy tính của bạn mà là một cuộc đàm phán phức tạp. Tác giả trải nghiệm qua nhiều nền tảng từ bare metal đến AWS và nhận ra rằng dù viết code Go hay Rust cảm thấy kiểm soát được thì khi triển khai lên cloud, mọi thứ trở nên bất định. Sự khác biệt chính giữa cloud và máy tính cục bộ là: máy tính cục bộ cho cảm giác kiểm soát trực tiếp, còn cloud khiến bạn đang thuê xác suất chứ không phải chạy phần mềm.&lt;/p&gt;
&lt;p&gt;Go - ngôn ngữ của những người lạc quan - thừa nhận thất bại như một giá trị, trong khi Rust - ngôn ngữ của những người kiểm soát cực đoan - đòi hỏi sự chính xác biên dịch. Các nhà phát triển trầm trồ kiến trúc monolith vì chúng có thể dự đoán, triển khai và hiểu được. Khi có lỗi, họ chỉ cần SSH vào một máy, kiểm tra log và sửa. Ngày nay họ phải mở nhiều công cụ giám sát khác nhau mà vẫn không hiểu tại sao 503 xảy ra.&lt;/p&gt;
&lt;p&gt;Bài học rút ra là Go và Rust đang phát triển mạnh trong cloud vì chúng là ngôn ngữ trung thực trong môi trường không trung thực. Go đón nhận thất bại như một giá trị, Rust thực thi sự chính xác tại thời điểm biên dịch. Đám mây là hỗn loạn, còn Go và Rust là kỷ luật. Sự căng thẳng đó chính là lý do chúng thuộc về nhau. Cloud là về quản lý sự bất định, không phải kiểm soát - và Go, Rust là công cụ tốt nhất để điều hướng sự bất định đó.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cloud vs máy tính: cloud là thuê xác suất, không phải chạy phần mềm&lt;/li&gt;
&lt;li&gt;Monolith đáng nhớ: dự đoán được, SSH vào máy để debug, dễ hiểu&lt;/li&gt;
&lt;li&gt;Microservices chaos: nhiều công cụ giám sát, vẫn không hiểu tại sao 503&lt;/li&gt;
&lt;li&gt;Go lạc quan: thừa nhận thất bại như giá trị, handle gracefully&lt;/li&gt;
&lt;li&gt;Rust kiểm soát: thực thi chính xác tại compile, catch errors sớm&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bonus"&gt;Bonus
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Hình ảnh:&lt;/strong&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!V-F7!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57c857fb-0db2-4701-93f7-343fac614657_2250x2862.png"
loading="lazy"
alt="Must-Know Software Architecture Patterns"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #84</title><link>https://miti99.com/post/2026/02/26/</link><pubDate>Thu, 26 Feb 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/02/26/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #84.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="automatic-programming"&gt;&lt;a class="link" href="https://antirez.com/news/159" target="_blank" rel="noopener"
&gt;Automatic programming&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Antirez - tác giả của Redis - chia sẻ góc nhìn thú vị về &amp;ldquo;lập trình tự động&amp;rdquo; (automatic programming), thuật ngữ ông dùng để mô tả quá trình viết phần mềm có sự hỗ trợ của AI. Ông phân biệt rõ giữa &amp;ldquo;vibe coding&amp;rdquo; (mô tả chung chung và để AI tự quyết định) với lập trình tự động thực sự, nơi người lập trình vẫn đóng vai trò chủ đạo trong việc định hướng, thiết kế và kiểm soát chất lượng.&lt;/p&gt;
&lt;p&gt;Antirez nhấn mạnh rằng khi sử dụng AI để viết phần mềm một cách có ý thức, mã nguồn tạo ra vẫn là của bạn và bạn có quyền tự hào về nó. Ông lấy ví dụ về Redis - không phải vì kỹ thuật phức tạp mà vì tầm nhìn và ý tưởng phía sau. Ngày nay, lập trình có thể tự động hóa, nhưng tầm nhìn thì chưa (và có thể chưa bao giờ).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Vibe coding&amp;rdquo; khác với lập trình tự động có chủ đích&lt;/li&gt;
&lt;li&gt;AI là công cụ hỗ trợ, nhưng người lập trình vẫn nắm tầm nhìn và kiểm soát&lt;/li&gt;
&lt;li&gt;Lập trình hiện nay đã tự động hóa được, nhưng tầm nhìn và ý tưởng vẫn là yếu tố then chốt&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="software-performance-engineering-the-ideas-i-keep-coming-back-to"&gt;&lt;a class="link" href="https://ricomariani.medium.com/software-performance-engineering-the-ideas-i-keep-coming-back-to-6f421b6a9505" target="_blank" rel="noopener"
&gt;Software Performance Engineering: The Ideas I Keep Coming Back To&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Rico Mariani chia sẻ 8 nguyên lý cốt lõi về hiệu năng phần mềm mà ông thường xuyên quay lại trong suốt sự nghiệp. Bài viết nhấn mạnh rằng hiệu năng không phải về các thủ thuật hay mã nguồn thông minh, mà về tư duy hệ thống. Tác giả giải thích cách các vấn đề hiệu năng thực sự thường xuất phát từ hiệu ứng kiến trúc: quá nhiều cấp phát bộ nhớ, tính địa phương cache kém, đồng bộ hóa ngầm, hoặc tăng trưởng không kiểm soát - không phải từ một hàm chậm đơn lẻ. Ông cũng bàn về việc các abstraction giấu chi phí, tầm quan trọng của cost model so với API, và tại sao bộ nhớ mới là nút thắt thực sự. Bài viết kết luận bằng cách cảnh báo về sự suy giảm hiệu năng dần dần qua thời gian thông qua tích tụ các thay đổi nhỏ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hiệu năng là vấn đề hệ thống, không phải vấn đề dòng code&lt;/li&gt;
&lt;li&gt;Abstraction không miễn phí - chúng chỉ giấu chi phí đi&lt;/li&gt;
&lt;li&gt;Cost model quan trọng hơn API, bộ nhớ là nút thắt thực sự&lt;/li&gt;
&lt;li&gt;Hiệu năng suy giảm dần dần qua hàng nghìn thay đổi nhỏ&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="go"&gt;&lt;a class="link" href="https://oblique.security/blog/go-synctest/" target="_blank" rel="noopener"
&gt;Go&amp;rsquo;s synctest is amazing&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giới thiệu gói &lt;code&gt;testing/synctest&lt;/code&gt; mới trong Go 1.25 - một công cụ mạnh mẽ giúp kiểm thử các tác vụ bất đồng bộ và background loops một cách xác định. Tính năng nổi bật là khả năng &amp;ldquo;thao túng thời gian&amp;rdquo; - các test chạy trong một môi trường với đồng hồ ảo, giúp &lt;code&gt;time.Sleep&lt;/code&gt; thực thi gần như tức thì. Nhưng giá trị thực sự của synctest nằm ở khả năng suy luận xác định về thứ tự sự kiện trong test. Tác giả minh họa cách synctest hoạt động bằng cách theo dõi khi nào tất cả goroutines bị &amp;ldquo;block&amp;rdquo; trên các thao tác như channel, wait group, hoặc time methods, từ đó advance thời gian chính xác để unblock chúng. Điều này không chỉ giúp test chạy nhanh hơn mà còn cho phép sử dụng thời gian để đồng bộ hóa một cách đáng tin cậy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;synctest cho phép test code có time.Sleep và background loops nhanh và đáng tin cậy&lt;/li&gt;
&lt;li&gt;Time được advance khi tất cả goroutines bị block, cho phép kiểm soát xác định thứ tự sự kiện&lt;/li&gt;
&lt;li&gt;Giải quyết vấn đề kiểm thử các vòng lặp background phức tạp như leader election&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-clean-architecture-confuses-everyone-and-how-i-learned-to-stop-worrying"&gt;&lt;a class="link" href="https://dev.to/rpereira15/why-clean-architecture-confuses-everyone-and-how-i-learned-to-stop-worrying-1i5k" target="_blank" rel="noopener"
&gt;Why Clean Architecture Confuses Everyone (And How I Learned to Stop Worrying)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giải thích tại sao Clean Architecture khiến nhiều người nhầm lẫn và cách tiếp cận thực tế hơn. Tác giả chỉ ra rằng vấn đề không nằm ở cấu trúc thư mục mà ở việc business logic bị phụ thuộc vào framework. Spring Boot và các framework khác khiến việc vi phạm nguyên tắc trở nên quá dễ dàng thông qua các annotation. Bài viết đề xuất tổ chức theo feature thay vì theo layer, và nhấn mạnh rằng business logic nên &amp;ldquo;nhàm chán&amp;rdquo; - không quan tâm đến cách lưu trữ dữ liệu hay framework nào được sử dụng. Tác giả chia sẻ bài học thực tế: đừng tạo interface chỉ vì &amp;ldquo;clean architecture cần ports và adapters&amp;rdquo;, hãy tạo khi thực sự cần. Kiểm tra kiến trúc tốt qua khả năng thay đổi: bạn có thể switch database hoặc framework mà không chạm vào business logic không?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clean architecture không phải về folder, mà về tách biệt business logic khỏi framework&lt;/li&gt;
&lt;li&gt;Tổ chức theo feature thay vì layer để tư duy về business capabilities&lt;/li&gt;
&lt;li&gt;Business logic nên không phụ thuộc database, framework hay cách request đến&lt;/li&gt;
&lt;li&gt;Kiểm tra kiến trúc qua khả năng thay đổi dễ dàng khi yêu cầu thay đổi&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-third-golden-age-of-software-engineering--thanks-to-ai"&gt;&lt;a class="link" href="https://newsletter.pragmaticengineer.com/p/the-third-golden-age-of-software" target="_blank" rel="noopener"
&gt;The third golden age of software engineering – thanks to AI&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Grady Booch - người đồng sáng tạo UML và Chief Scientist cho Software Engineering tại IBM - chia sẻ góc nhìn về ba &amp;ldquo;thời kỳ hoàng kim&amp;rdquo; của kỹ thuật phần mềm. Thời kỳ đầu tiên về thuật toán (1940s-1970s), thời kỳ thứ hai về abstraction hướng đối tượng (1970s-2000s), và thời kỳ thứ ba hiện nay về hệ thống - bắt đầu với sự trỗi dậy của abstraction từ components sang toàn bộ libraries, platforms, và packages. Ông khẳng định các công cụ AI coding chỉ là sự gia tăng mức abstraction khác, không phải là sự kết thúc của kỹ thuật phần mềm. AI hiện tại chủ yếu được huấn luyện trên các pattern đã biết, đặc biệt tốt với các hệ thống CRUD web, nhưng biên giới của computing rộng lớn hơn nhiều. Grady nhấn mạnh rằng foundational knowledge trở nên quan trọng hơn khi lĩnh vực này phát triển với tốc độ khó hiểu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chúng ta đang ở giữa thời kỳ hoàng kim thứ ba của kỹ thuật phần mềm - về hệ thống, không phải AI&lt;/li&gt;
&lt;li&gt;AI coding tools là sự gia tăng abstraction, giống như compilers trước đó, không thay thế kỹ sư&lt;/li&gt;
&lt;li&gt;Deep foundational knowledge trở nên quan trọng hơn khi ngành phát triển nhanh&lt;/li&gt;
&lt;li&gt;Cơ hội để bay lên, không phải sợ hãi vực thẳm&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ai-coding-workflow"&gt;&lt;a class="link" href="https://newsletter.systemdesign.one/p/ai-coding-workflow" target="_blank" rel="noopener"
&gt;AI coding workflow&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ một quy trình thực tế để sử dụng AI coding hiệu quả, không phải như một &amp;ldquo;máy bán hàng tự động&amp;rdquo; mà paste vấn đề và nhận giải pháp. Tác giả nhấn mạnh rằng AI hoạt động tốt nhất trong một vòng lặp lặp lại, không phải yêu cầu một lần. Workflow cốt lõi gồm 6 bước: Context (chia sẻ project background và constraints), Plan (hỏi chiến lược trước khi viết code), Code (generate hoặc edit code từng bước), Review (kiểm tra kỹ output), Test (chạy tests và generate tests mới), và Iterate (debug và refine). Bài viết cũng chia sẻ các pattern prompt hữu ích và cách tránh các lỗi phổ biến như context quá dài hoặc để AI hallucinate APIs không tồn tại.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI hoạt động tốt nhất trong vòng lặp lặp lại, không phải yêu cầu một lần&lt;/li&gt;
&lt;li&gt;Context và Plan trước khi Code là quan trọng nhất để tránh AI đoán&lt;/li&gt;
&lt;li&gt;Tách biệt roles (Planner, Implementer, Tester, Explainer) giúp output tốt hơn&lt;/li&gt;
&lt;li&gt;Tests và reviews là safety net bắt bugs và halllucinations của AI&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bonus"&gt;Bonus
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Images:&lt;/strong&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/625a6789-c32d-4a27-a5f5-c174fb920637_2360x2960.png"
loading="lazy"
alt="Git pull vs. git fetch"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!-Lov!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf928dd3-de16-4605-a702-762df269c9f2_2250x2862.png"
loading="lazy"
alt="Top Authentication Techniques"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #83</title><link>https://miti99.com/post/2026/02/24/</link><pubDate>Tue, 24 Feb 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/02/24/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #83.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="how-uber-scaled-data-replication-to-move-petabytes-every-day"&gt;&lt;a class="link" href="https://www.uber.com/en-IN/blog/scaled-data-replication/" target="_blank" rel="noopener"
&gt;How Uber Scaled Data Replication to Move Petabytes Every Day&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Uber đã chia sẻ về hành trình tối ưu hóa khả năng sao chép dữ liệu ở quy mô khổng lồ. Với hệ thống dữ liệu (data lake) vượt quá 350 PB phân bổ trên nhiều vùng địa lý, đội ngũ kỹ sư tại Uber đã đối mặt với thách thức lớn khi khối lượng dữ liệu cần sao chép hàng ngày tăng từ 250 TB lên 1 PB chỉ trong một quý.&lt;/p&gt;
&lt;p&gt;Vấn đề cốt lõi nằm ở Apache Hadoop Distcp (Sao chép phân tán) - công cụ được dùng trong Hive Sync service để nhân bản dữ liệu giữa các môi trường on-premise và cloud. Khi số lượng bộ dữ liệu tăng từ 30,000 lên 144,000 và số lượng tác vụ nhân bản hàng ngày tăng vọt từ 10,000 lên 374,000, Distcp bắt đầu lộ rõ những hạn chế về hiệu năng.&lt;/p&gt;
&lt;p&gt;Để giải quyết vấn đề, đội ngũ Uber đã áp dụng nhiều cải tiến quan trọng. Thứ nhất, họ chuyển các tác vụ tốn tài nguyên như Copy Listing và Input Splitting từ client sang Application Master, giúp giảm 90% độ trễ khi gửi tác vụ. Thứ hai, họ xử lý song song Copy Listing task bằng cách dùng nhiều luồng để xử lý song song nhiều tệp, giảm 60% p99 độ trễ. Thứ ba, việc xử lý song song Copy Committer task giúp giảm 97.29% thời gian ghép tệp. Cuối cùng, việc sử dụng &amp;ldquo;Uber jobs&amp;rdquo; cho các lần chuyển nhỏ (dưới 512 MB) đã giúp loại bỏ việc khởi chạy 268,000 containers mỗi ngày, tối ưu hóa việc sử dụng tài nguyên YARN đáng kể.&lt;/p&gt;
&lt;p&gt;Nhờ những cải tiến này, Uber đã tăng 5 lần khả năng nhân bản dữ liệu gia tăng trong vòng một năm, và di chuyển thành công hơn 306 PB dữ liệu từ on-premises sang cloud. Bài viết cũng đề cập đến các kế hoạch tương lai như xử lý song song cài đặt quyền tệp, chia đầu vào, và triển khai bộ điều tiết băng thông động để tiếp tục cải thiện hiệu quả.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chuyển Copy Listing và Input Splitting sang Application Master giúp giảm 90% độ trễ khi gửi tác vụ&lt;/li&gt;
&lt;li&gt;Xử lý song song Copy Listing và Copy Committer tasks giảm đáng kể thời gian xử lý&lt;/li&gt;
&lt;li&gt;Uber jobs cho các lần chuyển nhỏ loại bỏ 268,000 lần khởi chạy container hàng ngày&lt;/li&gt;
&lt;li&gt;Tăng 5 lần khả năng nhân bản dữ liệu gia tăng&lt;/li&gt;
&lt;li&gt;Di chuyển thành công 306 PB dữ liệu từ on-premises sang cloud&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-to-write-a-good-spec-for-ai-agents"&gt;&lt;a class="link" href="https://addyosmani.com/blog/good-spec/" target="_blank" rel="noopener"
&gt;How to write a good spec for AI agents&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Addy Osmani đã chia sẻ một khung toàn diện để viết đặc tả hiệu quả cho các tác nhân lập trình AI. Bài viết giải quyết vấn đề nan giải mà nhiều nhà phát triển gặp phải: làm sao để viết đặc tả vừa đủ chi tiết để hướng dẫn AI, vừa không quá dài khiến mô hình bị quá tải bởi giới hạn ngữ cảnh.&lt;/p&gt;
&lt;p&gt;Bài viết đưa ra năm nguyên tắc cốt lõi cho đặc tả tác nhân AI. Đầu tiên, bắt đầu với tầm nhìn cấp cao và để AI soạn thảo chi tiết - thay vì thiết kế quá mức ngay từ đầu, hãy bắt đầu với tuyên bố mục tiêu ngắn gọn và các yêu cầu cốt lõi, rồi để tác nhân mở rộng thành kế hoạch chi tiết. Thứ hai, cấu trúc đặc tả như một tài liệu yêu cầu sản phẩm chuyên nghiệp với sáu vùng cốt lõi: Lệnh, Kiểm thử, Cấu trúc dự án, Phong cách mã, Quy trình Git, và Giới hạn. Phân tích của GitHub từ hơn 2,500 tệp tác nhân cho thấy những đặc tả hiệu quả nhất luôn bao phủ đầy đủ các vùng này.&lt;/p&gt;
&lt;p&gt;Thứ ba, chia nhỏ nhiệm vụ thành các lời nhắc mô đun thay vì dùng một lời nhắc lớn duy nhất - &amp;ldquo;lời nguyền của các chỉ dẫn&amp;rdquo; khiến hiệu suất AI giảm khi phải theo quá nhiều chỉ thị cùng lúc. Giải pháp là chia để trị: giải quyết từng phần một lúc và chỉ kéo ngữ cảnh liên quan khi cần. Thứ tư, tích hợp các kiểm tra tự tính và ba tầng giới hạn (Luôn làm, Hỏi trước, Không bao giờ làm) - cách tiếp cận này tinh tế hơn danh sách quy tắc phẳng và giúp tác nhân biết khi tiến hành, khi tạm dừng, khi dừng lại. Cuối cùng, coi đặc tả như vòng lặp lặp lại - kiểm tra sớm, thu thập phản hồi, tinh chỉnh đặc tả, và tận dụng công cụ để tự động hóa kiểm tra.&lt;/p&gt;
&lt;p&gt;Bài viết cũng thảo luận về các bẫy cần tránh như lời nhắc mơ hồ (&amp;ldquo;Xây dựng cho tôi thứ gì đó thật tuyệt&amp;rdquo;), ngữ cảnh quá dài không có tóm tắt, bỏ qua đánh giá của con người, và &amp;ldquo;mã nhà bài&amp;rdquo; - mã được tạo bởi AI trông chắc chắn nhưng sụp đổ dưới các trường hợp biên. Addy nhấn mạnh sự khác biệt giữa &amp;ldquo;lập trình theo cảm hứng&amp;rdquo; cho tạo mẫu nhanh và &amp;ldquo;kỹ thuật có sự hỗ trợ của AI&amp;rdquo; cho sản xuất, sau này cần kỷ luật và đặc tả nghiêm ngặt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bắt đầu với tầm nhìn cấp cao, để AI mở rộng thành kế hoạch chi tiết&lt;/li&gt;
&lt;li&gt;Cấu trúc đặc tả như PRD với 6 vùng cốt lõi: Lệnh, Kiểm thử, Cấu trúc, Phong cách, Git, Giới hạn&lt;/li&gt;
&lt;li&gt;Chia nhỏ nhiệm vụ thành lời nhắc mô đun để tránh &amp;ldquo;lời nguyền của các chỉ dẫn&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Sử dụng ba tầng giới hạn: Luôn làm, Hỏi trước, Không bao giờ làm&lt;/li&gt;
&lt;li&gt;Coi đặc tả như vòng lặp lặp lại với kiểm tra và tinh chỉnh liên tục&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="challenging-projects-every-programmer-should-try"&gt;&lt;a class="link" href="https://austinhenley.com/blog/challengingprojects.html" target="_blank" rel="noopener"
&gt;Challenging projects every programmer should try&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Austin Z. Henley, Giáo sư Đảng ngữ tại Đại học Carnegie Mellon, đã chia sẻ danh sách các dự án thử thách mà mọi lập trình viên nên thử. Bài viết xuất phát từ thực tế rằng nhiều sinh viên và nhà phát triển chuyên nghiệp muốn bắt đầu dự án phụ nhưng không biết nên xây dựng gì. Austin đưa ra những dự án đã dạy cho ông rất nhiều kiến thức, và có thể xây dựng nhiều lần với mỗi lần học được những điều mới.&lt;/p&gt;
&lt;p&gt;Bài viết liệt kê sáu dự án chính: Trình soạn thảo văn bản, Trò chơi 2D (Space Invaders), Trình biên dịch (Tiny BASIC), Hệ điều hành thu nhỏ, Bảng tính, và Trình mô phỏng máy chơi game console. Mỗi dự án đều có những thử thách riêng giúp nhà phát triển làm chủ các kỹ năng quan trọng. Ví dụ, Trình soạn thảo văn bản dạy về cấu trúc dữ liệu như dây thừng, bộ đệm khoảng, bảng mảnh để lưu trữ văn bản hiệu quả, cùng với các mẫu thiết kế như Memento và Command cho hoàn tác/làm lại. Space Invaders giúp hiểu vòng lặp trò chơi, xử lý đầu vào người dùng, và mẫu nhà máy để quản lý đối tượng trò chơi.&lt;/p&gt;
&lt;p&gt;Dự án trình biên dịch được Austin mô tả là &amp;ldquo;mở mắt nhất&amp;rdquo; - dạy về phân tích từ vựng, phân tích cú pháp, phân tích đệ quy giảm dần, cây cú pháp trừu tượng, phân tích ngữ nghĩa, và tạo mã. Hệ điều hành thu nhỏ giúp hiểu biên dịch chéo, nạp khởi động, quản lý bộ nhớ, lập lịch, và hệ thống tệp. Hai dự án nâng cao hơn là Bảng tính (kết hợp thử thách từ trình soạn thảo văn bản và trình biên dịch) và Trình mô phỏng máy chơi game console (kết hợp trình biên dịch, hệ điều hành, và engine trò chơi).&lt;/p&gt;
&lt;p&gt;Bài viết cũng bao gồm danh sách các gợi ý dự án từ cộng đồng như cơ sở dữ liệu từ đầu, trình dò tia, bản sao MS Paint, trình đồ họa vector, bộ giải mã hình ảnh, ứng dụng web phòng chat, và tiện ích dòng lệnh. Mỗi dự án đều có phần &amp;ldquo;Đọc thêm&amp;rdquo; với các tài nguyên để học sâu hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;6 dự án thử thách: Trình soạn thảo văn bản, Trò chơi 2D, Trình biên dịch, Hệ điều hành thu nhỏ, Bảng tính, Trình mô phỏng&lt;/li&gt;
&lt;li&gt;Trình soạn thảo văn bản dạy cấu trúc dữ liệu (dây thừng, bộ đệm khoảng, bảng mảnh) và mẫu hoàn tác/làm lại&lt;/li&gt;
&lt;li&gt;Space Invaders bao gồm vòng lặp trò chơi, xử lý đầu vào, mẫu nhà máy, máy trạng thái&lt;/li&gt;
&lt;li&gt;Dự án trình biên dịch khám phá phân tích từ vựng, phân tích cú pháp, cây cú pháp, phân tích ngữ nghĩa, tạo mã&lt;/li&gt;
&lt;li&gt;Hệ điều hành thu nhỏ giúp hiểu biên dịch chéo, nạp khởi động, quản lý bộ nhớ, lập lịch&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="unconventional-postgresql-optimizations"&gt;&lt;a class="link" href="https://hakibenita.com/postgresql-unconventional-optimizations" target="_blank" rel="noopener"
&gt;Unconventional PostgreSQL Optimizations&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Haki Benita đã chia sẻ các kỹ thuật tối ưu hóa PostgreSQL phi truyền thống mà các nhà phát triển thường không nghĩ đến. Bài viết bắt đầu với thực tế rằng khi tối ưu hóa cơ sở dữ liệu, developers thường dùng những công cụ cũ kỹ: viết lại truy vấn, thêm chỉ mục, phi chuẩn hóa, phân tích, dọn dẹp, lặp lại. Các kỹ thuật truyền thống hiệu quả, nhưng đôi khi sáng tạo có thể mang lại kết quả tốt hơn.&lt;/p&gt;
&lt;p&gt;Bài viết bao gồm ba kỹ thuật chính. Đầu tiên, loại bỏ quét toàn bộ bảng dựa trên ràng buộc kiểm tra bằng cách bật &lt;code&gt;constraint_exclusion&lt;/code&gt;. Khi một nhà phân tích vô tình viết truy vấn với giá trị không tồn tại (ví dụ: &lt;code&gt;plan = 'Pro'&lt;/code&gt; thay vì &lt;code&gt;'pro'&lt;/code&gt;), PostgreSQL sẽ quét toàn bộ bảng. Tuy nhiên, với ràng buộc kiểm tra, cơ sở dữ liệu biết rằng không có hàng nào có giá trị này và có thể bỏ qua quét hoàn toàn. Tùy chọn này tắt theo default vì nó thêm overhead cho kế hoạch truy vấn, nhưng rất hữu ích cho các môi trường báo cáo nơi người dùng có thể viết truy vấn thủ công.&lt;/p&gt;
&lt;p&gt;Thứ hai, tối ưu hóa cho tính đơn giản ít hơn bằng cách sử dụng chỉ mục dựa trên hàm. Thay vì lập chỉ mục toàn bộ timestamp (214 MB cho 10 triệu hàng), chúng ta có thể lập chỉ mục chỉ phần ngày (66 MB) bằng cách dùng &lt;code&gt;date_trunc&lt;/code&gt;. Điều này giảm kích thước chỉ mục xuống hơn 3 lần và giúp truy vấn nhanh hơn. Để đảm bảo mọi người dùng cùng biểu thức đúng, bài viết đề xuất sử dụng cột được tạo ảo (virtual generated columns) - tính năng mới trong PostgreSQL 18.&lt;/p&gt;
&lt;p&gt;Thứ ba, thực thi tính duy nhất với chỉ mục băm. Khi lưu trữ các URL lớn (kích thước chỉ mục B-Tree là 154 MB), việc sử dụng chỉ mục băm (32 MB) có thể tiết kiệm đáng kể không gian lưu trữ. Mặc dù PostgreSQL không hỗ trợ các chỉ mục băm duy nhất trực tiếp, chúng ta có thể sử dụng ràng buộc loại trừ với chỉ mục băm để thực thi tính duy nhất. Tuy nhiên, cách tiếp cận này có một số hạn chế như không thể tham chiếu bởi khóa ngoại và hạn chế với mệnh đề &lt;code&gt;ON CONFLICT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bật &lt;code&gt;constraint_exclusion&lt;/code&gt; để loại bỏ quét bảng cho các giá trị vi phạm ràng buộc kiểm tra&lt;/li&gt;
&lt;li&gt;Sử dụng chỉ mục dựa trên hàm và cột được tạo ảo để giảm kích thước chỉ mục&lt;/li&gt;
&lt;li&gt;Chỉ mục ngày (66 MB) nhỏ hơn 3 lần so với chỉ mục timestamp đầy đủ (214 MB)&lt;/li&gt;
&lt;li&gt;Thực thi tính duy nhất với ràng buộc loại trừ và chỉ mục băm cho các giá trị lớn&lt;/li&gt;
&lt;li&gt;Chỉ mục băm (32 MB) nhỏ hơn 5 lần so với chỉ mục B-Tree (154 MB) cho URL&lt;/li&gt;
&lt;li&gt;Hạn chế: không thể tham chiếu bởi khóa ngoại và không hỗ trợ &lt;code&gt;ON CONFLICT DO UPDATE&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="software-engineering-when-machine-writes-the-code"&gt;&lt;a class="link" href="https://www.shayon.dev/post/2026/19/software-engineering-when-the-machine-writes-code" target="_blank" rel="noopener"
&gt;Software engineering when machine writes the code&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Shayon Majumdar đã chia sẻ suy nghĩ sâu sắc về tương lai của kỹ thuật phần mềm khi máy móc có thể viết mã. Bài viết bắt đầu bằng việc nhắc lại cuộc khủng hoảng phần mềm năm 1968, khi các nhà khoa học máy tính nhận ra rằng máy tính đã trở nên quá mạnh đối với các phương pháp lập trình hiện có. Ngày nay, chúng ta đối mặt với sự gián đoạn tương tự nhưng theo hướng ngược lại: máy móc có thể viết mã tốt hơn và nhanh hơn con người.&lt;/p&gt;
&lt;p&gt;Tác giả không phê phán các công cụ lập trình có sự hỗ trợ của AI. Ông thừa nhận rằng chúng giúp ông vận chuyển tính năng nhanh hơn bao giờ hết - những gì mất một tuần giờ chỉ mất ít hơn một ngày. Tuy nhiên, ông lo ngại rằng trong sự vội vã nắm bắt lợi suất, chúng ta có thể đang đánh đổi một thứ gì đó quan trọng: sự hiểu biết sâu sắc về cách hoạt động của hệ thống.&lt;/p&gt;
&lt;p&gt;Bài viết đưa ra nghịch lý Jevons - khi việc sử dụng tài nguyên trở nên hiệu quả hơn, tổng tiêu thụ tài nguyên thực sự tăng lên chứ không giảm. Tương tự, nếu AI giúp viết mã hiệu quả hơn gấp 10 lần, chúng ta sẽ không viết ít mã hơn mà sẽ viết nhiều mã hơn bao giờ hết, tạo ra các hệ thống có độ phức tạp chưa từng có. Điều này đặt ra câu hỏi quan trọng: hiểu biết về mã mà bạn không tự viết có ý nghĩa gì?&lt;/p&gt;
&lt;p&gt;Shayon phân biệt rõ giữa mã bạn viết và mã bạn xem xét. Khi viết mã, bạn xây dựng mô hình tinh thần thông qua quá trình sáng tạo, đưa ra hàng chục quyết định nhỏ, suy nghĩ về các trường hợp biên. Khi xem xét mã người khác, bạn chỉ đang tái tạo lại mô hình tinh thần. Với mã được tạo bởi AI, khoảng cách này còn lớn hơn vì AI có thể đưa ra các quyết định vi mô khác với bạn.&lt;/p&gt;
&lt;p&gt;Bài viết cũng lo ngại về kỹ sư mới bắt đầu. Nếu bạn chưa bao giờ viết một máy trạng thái thủ công, liệu bạn có phát triển được trực giác về cách máy trạng thái có thể bị lỗi? Con đường truyền thống để trở thành kỹ sư lành nghề liên quan đến nhiều việc lãng phí thời gian - viết mã sau này vứt đi, triển khai thứ gì đó từ đầu mà thư viện có thể làm cho bạn, dành hàng giờ để gỡ lỗi. Quá trình này kém hiệu quả nhưng xây dựng điều quan trọng: nhận diện mẫu và trực giác.&lt;/p&gt;
&lt;p&gt;Tác giả đề xuất cách sử dụng AI giúp gìn giữ và thậm chí tăng cường học tập thay vì thay thế nó. Một cách tiếp cận là sử dụng AI như &amp;ldquo;người hướng dẫn Socrates&amp;rdquo; - thay vì yêu cầu AI viết mã, hãy yêu cầu nó giải thích khái niệm, mô tả các sự đánh đổi. Một kỹ thuật khác là sử dụng AI để xem xét mã của bạn, cung cấp lợi ích của &amp;ldquo;cặp mắt thứ hai&amp;rdquo; mà không mất đi việc học từ việc tự viết mã.&lt;/p&gt;
&lt;p&gt;Cuối cùng, Shayon đề xuất mô hình vùng để sử dụng AI: mã logic cốt lõi của bạn (như thuật toán đồng thuận) nên được thực hiện thủ công hoặc ít nhất là được hiểu rất kỹ; mã quan trọng nhưng tiêu chuẩn (như endpoint API) có thể sử dụng AI nhiều hơn; và mã thực sự là boilerplate (như scaffold kiểm tra) nên để AI dẫn đầu gần như hoàn toàn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nghịch lý Jevons: AI làm việc hiệu quả hơn gấp 10 lần nhưng chúng ta sẽ viết nhiều mã hơn bao giờ hết&lt;/li&gt;
&lt;li&gt;Sự khác biệt quan trọng giữa mã bạn viết và mã bạn xem xét&lt;/li&gt;
&lt;li&gt;Lo ngại về kỹ sư mới bỏ qua giai đoạn &amp;ldquo;đấu tranh&amp;rdquo; cần thiết để xây dựng trực giác&lt;/li&gt;
&lt;li&gt;Sử dụng AI như người hướng dẫn Socrates để giải thích thay vì viết mã trực tiếp&lt;/li&gt;
&lt;li&gt;Mô hình vùng: logic cốt lõi (thủ công), mã tiêu chuẩn (AI hỗ trợ), boilerplate (AI dẫn đầu)&lt;/li&gt;
&lt;li&gt;Các kỹ sư thịnh vượng sẽ là người có thể làm việc hiệu quả với AI trong khi duy trì sự hiểu biết sâu sắc&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="a-guide-to-effective-prompt-engineering"&gt;&lt;a class="link" href="https://blog.bytebytego.com/p/a-guide-to-effective-prompt-engineering" target="_blank" rel="noopener"
&gt;A Guide to Effective Prompt Engineering&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;ByteByteGo đã chia sẻ hướng dẫn toàn diện về kỹ thuật prompt engineering - quá trình tạo ra các hướng dẫn giúp mô hình ngôn ngữ AI tạo ra kết quả mong muốn. Bài viết nhấn mạnh rằng mặc dù bất kỳ ai cũng có thể viết prompt, nhưng không phải ai cũng có thể viết prompt liên tục tạo ra kết quả chất lượng cao. Sự khác biệt giống như giữa có thể giao tiếp và có thể giao tiếp hiệu quả.&lt;/p&gt;
&lt;p&gt;Bài viết giải thích cấu trúc của một prompt thường bao gồm bốn thành phần: mô tả tác vụ (giải thích chúng ta muốn mô hình làm gì), ngữ cảnh (cung cấp thông tin nền), ví dụ (minh họa hành vi mong muốn), và tác vụ cụ thể (câu hỏi hoặc hành động cần thực hiện). Các API mô hình hiện đại cho phép chia prompt thành system prompt (chứa mô tả tác vụ và hướng dẫn vai trò) và user prompt (chứa tác vụ thực tế).&lt;/p&gt;
&lt;p&gt;Tính rõ ràng là yếu tố quan trọng nhất. Chúng ta nên giải thích chính xác những gì chúng ta muốn, định nghĩa bất kỳ hệ thống điểm nào hoặc định dạng mong đợi, và loại bỏ các giả định về những gì mô hình có thể đã biết. Ngữ cảnh cũng quan trọng như vậy - cung cấp thông tin liên quan giúp mô hình hoạt động tốt hơn và giảm ảo giác.&lt;/p&gt;
&lt;p&gt;Bài viết giới thiệu học tập trong ngữ cảnh - khả năng của mô hình học hành vi mới từ các ví dụ được cung cấp trong chính prompt. Các mô hình thường hiểu hướng dẫn tốt hơn ở đầu và cuối của prompt so với giữa, một hiện tượng đôi khi được gọi là vấn đề &amp;ldquo;kim trong đống rơm&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Năm kỹ thuật prompt chính được thảo luận. Đầu tiên, zero-shot prompting - đưa ra hướng dẫn mà không cung cấp ví dụ, hoạt động tốt nhất cho các tác vụ đơn giản. Thứ hai, few-shot prompting - cung cấp từ hai đến năm ví dụ để minh họa hành vi mong muốn, đặc biệt hữu ích khi cần định dạng cụ thể. Thứ ba, chain-of-thought prompting - yêu cầu mô hình suy nghĩ từng bước trước khi trả lời, cải thiện đáng kể hiệu suất cho các tác vụ suy luận phức tạp. Thứ tư, role prompting - gán một nhân cách cụ thể cho mô hình để ảnh hưởng đến góc nhìn và phong cách phản hồi. Thứ năm, prompt chaining - chia các tác vụ phức tạp thành các tác vụ con nhỏ hơn, mỗi tác vụ có prompt riêng.&lt;/p&gt;
&lt;p&gt;Các phương pháp tốt bao gồm: rõ ràng và cụ thể, cung cấp ngữ cảnh đủ, chỉ định định dạng đầu ra, sử dụng ví dụ một cách chiến lược, lặp lại và thử nghiệm, và phiên bản hóa prompt. Các bẫy thường cần tránh: quá mơ hồ, quá phức tạp, bỏ qua định dạng đầu ra, và không kiểm tra đủ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prompt engineering = khác biệt giữa giao tiếp và giao tiếp hiệu quả&lt;/li&gt;
&lt;li&gt;Cấu trúc prompt: mô tả tác vụ, ngữ cảnh, ví dụ, tác vụ cụ thể&lt;/li&gt;
&lt;li&gt;System prompt (hướng dẫn vai trò) vs user prompt (tác vụ thực tế)&lt;/li&gt;
&lt;li&gt;Vấn đề &amp;ldquo;kim trong đống rơm&amp;rdquo;: mô hình hiểu tốt hơn ở đầu/cuối prompt&lt;/li&gt;
&lt;li&gt;5 kỹ thuật chính: zero-shot, few-shot, chain-of-thought, role prompting, prompt chaining&lt;/li&gt;
&lt;li&gt;Nguyên tắc: rõ ràng, ngữ cảnh đủ, định dạng đầu ra, dùng ví dụ chiến lược, lặp lại&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Newsletter #82</title><link>https://miti99.com/post/2026/02/19/</link><pubDate>Thu, 19 Feb 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/02/19/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #82.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="how-the-lobsters-front-page-works"&gt;&lt;a class="link" href="https://blog.nilenso.com/blog/2026/01/20/lobsters-front-page/" target="_blank" rel="noopener"
&gt;How the Lobsters front page works&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích thuật toán xếp hạng trang chủ của Lobsters - một cộng đồng tập trung vào lĩnh vực máy tính với tính năng agregate liên kết và thảo luận. Vì mã nguồn mở, tác giả đã nghiên cứu cách thức hoạt động của thuật toán sắp xếp bài viết trên trang chủ.&lt;/p&gt;
&lt;p&gt;Công thức cốt lõi của thuật toán khá đơn giản: &lt;code&gt;hotness = -1 × (base + order × sign + age)&lt;/code&gt;, trong đó giá trị hotness càng âm thì bài viết xếp hạng càng cao. Thành phần &lt;code&gt;base&lt;/code&gt; được tính từ tổng các điều chỉnh hotness của thẻ tag (nằm trong khoảng -10 đến +10) cộng với một khoản nhỏ khuyến khích cho bài tự viết. Một thẻ như &lt;code&gt;culture&lt;/code&gt; hay &lt;code&gt;rant&lt;/code&gt; có modifier âm, làm giảm thứ hạng ban đầu.&lt;/p&gt;
&lt;p&gt;Thành phần &lt;code&gt;order&lt;/code&gt; phản ánh mức độ tương tác thông qua logarithm của điểm số, đồng thời tính thêm điểm bình luận (mỗi upvote bình luận bằng nửa upvote bài viết). Điều này có nghĩa là tăng từ 0 lên 100 phiếu ảnh hưởng thứ hạng nhiều hơn nhiều so với tăng từ 1000 lên 1100 phiếu. Thành phần &lt;code&gt;age&lt;/code&gt; tăng tuyến tính theo thời gian, đẩy các bài cũ xuống xếp hạng thấp dần.&lt;/p&gt;
&lt;p&gt;Tác giả nhận xét thuật toán này hoạt động tốt - cho phép bài viết mới có thời gian hiển thị, trừng phạt nội dung chất lượng thấp tạo ra nhiều tranh căng, và đảm bảo không bài nào tồn tại quá lâu trên trang chủ. Tuy nhiên, tính cách của cộng đồng Lobsters không đến từ thuật toán mà từ sự điều_triệt có quan điểm, phạm vi hẹp về máy tính, và hệ thống mời dần dần xây dựng văn hóa. Tác giả cũng chia sẻ trải nghiệm cá nhân về sự ngắt kết nối giá trị với nhóm người dùng tích cực nhất trên site, và nhắc nhở rằng sự tham gia của từng người dùng là quan trọng - các upvote sớm có thể đưa bài viết lên trang chủ.&lt;/p&gt;
&lt;h2 id="software-engineers-can-no-longer-neglect-their-soft-skills"&gt;&lt;a class="link" href="https://www.qu8n.com/posts/most-important-software-engineering-skill-2026" target="_blank" rel="noopener"
&gt;Software engineers can no longer neglect their soft skills&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết lập luận rằng bắt đầu từ năm 2026, kỹ năng giao tiếp đã trở thành kỹ năng quan trọng nhất cho kỹ sư phần mềm - không phải là viết mã, thiết kế hệ thống hay kiến thức chuyên sâu về ngôn ngữ lập trình. AI coding agent đã trở nên rất xuất sắc, tác giả chia sẻ đã chi hơn 500 USD cho Claude Code chỉ trong tháng 12 năm ngoái và sử dụng nó cho hầu hết các tác vụ lập trình không đơn giản.&lt;/p&gt;
&lt;p&gt;Vấn đề cốt lõi là nút thắt đã chuyển từ việc cài triển khai sang việc xác định thông số kỹ thuật. Trong thực tế, các ticket hiếm khi chứa đầy đủ yêu cầu. Để làm được điều đó, kỹ sư cần: đặt câu hỏi để làm rõ các giả định mà mọi người không nhận ra themselves, điều phối các thảo luận đánh đổi, từ chối mở rộng phạm vi mà không làm hỏng mối quan hệ, và đưa ra quyết định cho những việc không ai nghĩ đến cần quy định.&lt;/p&gt;
&lt;p&gt;Trước đây, những kỹ năng này chỉ là tùy chọn cho individual contributor. Một số nhóm cho phép kỹ sư phát triển với kỹ năng giao tiếp trung bình nhưng kỹ năng viết mã xuất sắc. Nay, các phần không liên quan đến viết mã đang trở thành không thể thương lượng. Kỹ sư phần mềm là người giải quyết vấn đề, chúng ta tin rằng mọi vấn đề đều có giải pháp và &amp;ldquo;best practice&amp;rdquo;. Nhưng làm việc với con người phức tạp hơn nhiều. May mắn là chúng ta không thể dùng AI để cải thiện kỹ năng giao tiếp. Giao tiếp tốt đòi hỏi sự thấu cảm - điều mà chúng ta đều cần thêm trong bối cảnh hiện nay.&lt;/p&gt;
&lt;h2 id="dithering---part-2"&gt;&lt;a class="link" href="https://visualrambling.space/dithering-part-2/" target="_blank" rel="noopener"
&gt;Dithering - Part 2&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết là phần thứ hai trong series về dithering - kỹ thuật dùng để mô phỏng nhiều màu sắc hơn so với những gì thực tế có sẵn. Tác giả tập trung vào ordered dithering, một phương pháp sử dụng threshold map để quyết định màu cuối cùng của mỗi pixel. Series này chỉ bao gồm dithering grayscale xuống hai màu đen và trắng.&lt;/p&gt;
&lt;p&gt;Tác giả giải thích cách hoạt động của threshold map: thay vì dùng một ngưỡng đơn để chuyển đổi xám thành đen hoặc trắng, ta sử dụng nhiều ngưỡng khác nhau cùng lúc. Kết quả là một hỗn hợp các pixel đen và trắng phản ánh độ sáng ban đầu - vùng sáng hơn có nhiều pixel trắng hơn, vùng tối hơn có nhiều pixel đen hơn.&lt;/p&gt;
&lt;p&gt;Vấn đề đầu tiên là các ngưỡng được sắp xếp tuần tự tạo ra các vạch dọc không mong muốn. Giải pháp là Bayer matrix - sắp xếp lại các ngưỡng theo mẫu 2x2 tạo ra pattern cross-hatch đặc trưng, giúp phân tán đều các pixel đen và trắng. Tuy nhiên, chỉ có 4 mức ngưỡng thì chuyển giữa các sắc thái vẫn khá gắt. Tác giả giới thiệu Bayer matrix 4x4 với 16 mức ngưỡng, cho phép 16 sắc thái xám khác nhau và chuyển mượt mà hơn.&lt;/p&gt;
&lt;p&gt;Bài viết cũng giới thiệu một số phương pháp sắp xếp threshold map khác nhau: Bayer matrix 8x8 với 64 mức cho gradient chi tiết hơn, Cluster Dot matrix tạo ra cảm giác như báo in truyền thống với các chấm tròn, và Void and Cluster - phương pháp yêu thích của tác giả với blue noise tạo ra texture tự nhiên hơn. Phần tiếp theo sẽ bàn về error diffusion, một phương pháp dithering khác không dùng map.&lt;/p&gt;
&lt;h2 id="what-came-first-the-cname-or-the-a-record"&gt;&lt;a class="link" href="https://blog.cloudflare.com/cname-a-record-order-dns-standards/" target="_blank" rel="noopener"
&gt;What came first: the CNAME or the A record?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích một sự cố DNS xảy ra vào ngày 8 tháng 1 năm 2026 khi Cloudflare cập nhật 1.1.1.1 để giảm mức sử dụng bộ nhớ. Thay đổi vô tình đã làm đảo ngược thứ tự của bản ghi CNAME trong phản hồi DNS, gây ra lỗi phân giải cho một số ứng dụng khách trên toàn Internet.&lt;/p&gt;
&lt;p&gt;Vấn đề gốc rễ nằm ở logic gộp chuỗi CNAME. Khi một số bản ghi trong chuỗi CNAME hết hạn, chỉ có phần hết hạn được giải quyết lại. Code cũ sẽ tạo danh sách mới, thêm chuỗi CNAME hiện có rồi thêm các bản ghi mới vào sau. Để tiết kiệm cấp phát bộ nhớ, code mới thay đổi bằng cách thêm CNAME vào cuối danh sách answer hiện có - khiến CNAME xuất hiện sau bản ghi A/AAAA.&lt;/p&gt;
&lt;p&gt;Một số triển khai DNS như getaddrinfo trong glibc và quy trình DNSC trong switch Cisco sử dụng phân tích tuần tự - theo dõi tên mong đợi khi duyệt qua các bản ghi. Khi gặp CNAME, tên mong đợi được cập nhật. Nếu CNAME xuất hiện cuối cùng, các bản ghi A/AAAA bị bỏ qua vì không khớp tên, dẫn đến phản hồi rỗng. systemd-resolved không gặp vấn đề này vì nó phân tích bản ghi vào một tập hợp có thứ tự và có thể tìm kiếm toàn bộ.&lt;/p&gt;
&lt;p&gt;RFC 1034 từ năm 1987 sử dụng cụm &amp;ldquo;possibly preface&amp;rdquo; để nói về CNAME nhưng không dùng từ khóa normative như MUST/SHOULD - RFC 2119 mới ra năm 1997. RFC cũng rõ ràng về thứ tự trong RRset nhưng mơ hồ về thứ tự tương đối giữa các RRset khác nhau trong phần thông điệp. Cloudflare đã hoàn tác thay đổi và viết đề xuất Internet-Draft để làm rõ hành vi tại IETF, giúp cộng đồng DNS điều hướng giao thức này tốt hơn.&lt;/p&gt;</description></item><item><title>Newsletter #81</title><link>https://miti99.com/post/2026/02/18/</link><pubDate>Wed, 18 Feb 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/02/18/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #81.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="những-thách-thức-của-soft-delete"&gt;&lt;a class="link" href="https://atlas9.dev/blog/soft-delete.html" target="_blank" rel="noopener"
&gt;Những thách thức của soft delete&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích các vấn đề thường gặp khi triển khai soft delete (xóa mềm) trong cơ sở dữ liệu, đặc biệt là khi sử dụng cột &lt;code&gt;archived_at&lt;/code&gt;. Tác giả chia sẻ kinh nghiệm thực tế về việc cách tiếp cận này có vẻ đơn giản ban đầu nhưng lại tạo ra nhiều phức tạp theo thời gian.&lt;/p&gt;
&lt;p&gt;Vấn đề chính là các bảng cơ sở dữ liệu sẽ chứa lượng lớn dữ liệu &amp;ldquo;chết&amp;rdquo; - những bản ghi đã bị xóa nhưng vẫn lưu lại. 99% các bản ghi lưu trữ sẽ không bao giờ được đọc lại, nhưng lại chiếm dụng không gian lưu trữ và làm chậm các truy vấn. Điều này đặc biệt nghiêm trọng khi có hàng triệu bản ghi chết tích tụ theo thời gian.&lt;/p&gt;
&lt;p&gt;Ngoài ra, việc có dữ liệu sống và dữ liệu lưu trữ nằm cạnh nhau trong cùng một bảng còn làm phức tạp hóa truy vấn, chỉ mục, và cả mã nguồn ứng dụng. Các nhà phát triển phải luôn nhớ lọc bỏ dữ liệu lưu trữ, và có nguy cơ dữ liệu cũ bị rò rỉ vào kết quả khi không mong muốn.&lt;/p&gt;
&lt;p&gt;Bài viết đề xuất một số giải pháp thay thế:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sử dụng trigger trong PostgreSQL&lt;/strong&gt;: Trigger tự động sao chép bản ghi sang bảng lưu trữ riêng trước khi xóa. Cách này giúp giữ bảng chính sạch sẽ, dữ liệu lưu trữ được tách biệt, dễ dàng dọn dẹp sau khoảng thời gian retention.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Application-level archiving&lt;/strong&gt;: Gửi sự kiện khi xóa bản ghi để một service khác lưu trữ dữ liệu vào S3 hoặc nơi khác. Ưu điểm là ứng dụng chính đơn giản hơn, nhưng nhược điểm là phức tạp hơn về infrastructure và có thể mất dữ liệu nếu có bug.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;WAL-based Change Data Capture&lt;/strong&gt;: Sử dụng Write-Ahead Log của PostgreSQL để phát ra các thay đổi và lưu trữ bản ghi bị xóa. Phương pháp này không cần thay đổi mã nguồn hay thêm trigger, nhưng đòi hỏi operational complexity cao hơn.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tác giả kết luận rằng nếu bắt đầu dự án mới và cần soft delete, anh sẽ ưu tiên sử dụng trigger-based approach vì sự cân bằng giữa độ đơn giản và hiệu quả.&lt;/p&gt;
&lt;h2 id="câu-hỏi-phỏng-vấn-java---tại-sao-không-nên-sử-dụng-static-initializer"&gt;&lt;a class="link" href="https://javabulletin.substack.com/p/java-interview-question-why-you-should" target="_blank" rel="noopener"
&gt;Câu hỏi phỏng vấn Java - Tại sao không nên sử dụng static initializer?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giải thích lý do tại sao developer nên tránh sử dụng static initializer (&lt;code&gt;static { ... }&lt;/code&gt;) trong Java, mặc dù nó có vẻ tiện lợi cho việc khởi tạo dữ liệu tĩnh phức tạp.&lt;/p&gt;
&lt;p&gt;Vấn đề đầu tiên là static block chạy khi class được tải vào JVM. Nếu nó throw exception, class sẽ không thể tải được và dẫn đến &lt;code&gt;ExceptionInInitializerError&lt;/code&gt;. Điều này còn gây ra hiệu ứng dây chuyền - bất kỳ class nào phụ thuộc vào class đó cũng sẽ fail, có thể làm sập cả ứng dụng.&lt;/p&gt;
&lt;p&gt;Một vấn đề khác là static block tự động chạy ngay cả khi chúng ta không sử dụng class đó. Điều này lãng phí tài nguyên và có thể gây ra các side effect không mong muốn.&lt;/p&gt;
&lt;p&gt;Khi nhiều class có static initializer phụ thuộc lẫn nhau, thứ tự tải class trở nên quan trọng và khó kiểm soát. Static block thực thi theo thứ tự class được tải, không phải theo thứ tự chúng ta khởi tạo object, dẫn đến các bug khó phát hiện.&lt;/p&gt;
&lt;p&gt;Bài viết khuyến nghị sử dụng lazy initialization hoặc constructor-based initialization thay vì static initializer. Các phương pháp này có ưu điểm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khởi tạo chỉ diễn ra khi thực sự cần&lt;/li&gt;
&lt;li&gt;Dễ kiểm thử và xử lý exception một cách graceful&lt;/li&gt;
&lt;li&gt;Không gây crash ứng dụng khi class được tải nhưng không sử dụng&lt;/li&gt;
&lt;li&gt;Code rõ ràng và dễ bảo trì hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="cách-viết-code-hiệu-suất-cao"&gt;&lt;a class="link" href="https://blog.bytebytego.com/p/how-to-write-high-performance-code" target="_blank" rel="noopener"
&gt;Cách viết code hiệu suất cao&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này chia sẻ các nguyên tắc nền tảng để viết code có hiệu suất tốt mà không cần kiến thức khoa học máy tính nâng cao hay nhiều năm kinh nghiệm. Điểm mấu chốt là phát triển trực giác về nơi hiệu suất thực sự quan trọng.&lt;/p&gt;
&lt;p&gt;Một kỹ năng quý giá là khả năng ước lượng chi phí hiệu suất trước khi viết code. Các thao tác máy tính tồn tại ở các tầng tốc độ khác nhau: truy cập CPU cache nhanh nhất (nano giây), truy cập RAM chậm hơn khoảng 100 lần, đọc từ SSD chậm hơn 40.000 lần, và network có thể chậm hàng triệu lần so với cache. Việc hiểu rõ sự khác biệt này giúp đưa ra quyết định kiến trúc đúng đắn.&lt;/p&gt;
&lt;p&gt;Quy tắc quan trọng nhất là đo lường trước, tối ưu hóa sau. Trực giác của chúng ta về các nút thắt hiệu suất thường sai lệch. Nên sử dụng công cụ phân tích hiệu suất với khối lượng công việc thực tế để tìm ra nơi chương trình thực sự tốn thời gian, thay vì dự đoán.&lt;/p&gt;
&lt;p&gt;Cải tiến thuật toán và cấu trúc dữ liệu mang lại hiệu quả lớn nhất. Ví dụ, thay vì dùng vòng lặp lồng nhau để tìm phần tử chung giữa hai danh sách (O(N²)), ta có thể chuyển danh sách thứ hai thành bảng băm và tìm kiếm với O(1) mỗi lần, giảm tổng độ phức tạp xuống O(N). Điều này có thể mang lại cải thiện 10 lần hay 100 lần.&lt;/p&gt;
&lt;p&gt;Bố cục bộ nhớ cũng quan trọng không kém thuật toán. CPU cực kỳ nhanh nhưng chỉ làm việc được với dữ liệu trong bộ nhớ đệm nhỏ. Nguyên tắc tính cục bộ: dữ liệu được truy cập cùng nhau nên được lưu cùng nhau. Mảng và vector thường vượt trội hơn danh sách liên kết vì truy cập tuần tự giúp tận dụng bộ nhớ đệm hiệu quả hơn.&lt;/p&gt;
&lt;p&gt;Giảm thiểu cấp phát bộ nhớ là một kỹ thuật khác. Mỗi lần cấp phát có chi phí, và các đối tượng nhỏ thường nằm rải rác khắp bộ nhớ, làm giảm hiệu quả bộ nhớ đệm. Nên dành trước không gian cho container, tái sử dụng đối tượng, và dùng ngữ nghĩa di chuyển thay vì sao chép khi có thể.&lt;/p&gt;
&lt;p&gt;Cuối cùng, mã nguồn nhanh nhất là mã nguồn không bao giờ chạy. Các chiến thuật bao gồm tạo đường dẫn nhanh cho trường hợp phổ biến, tính toán trước và lưu vào bộ nhớ đệm, đánh giá lười, và thoát sớm khi có thể. Không phải mọi mã nguồn đều cần tối ưu hóa - chỉ tập trung vào 20% mã nguồn quan trọng nhất chiếm 80% thời gian chạy.&lt;/p&gt;
&lt;h2 id="giới-thiệu-moltworker-ai-agent-tự-host-không-cần-mac-mini"&gt;&lt;a class="link" href="https://blog.cloudflare.com/moltworker-self-hosted-ai-agent/" target="_blank" rel="noopener"
&gt;Giới thiệu Moltworker: AI agent tự host không cần Mac mini&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Cloudflare giới thiệu Moltworker - một giải pháp cho phép chạy Moltbot (tác nhân AI cá nhân mã nguồn mở) trên nền tảng Cloudflare thay vì phải mua Mac mini chuyên dụng. Đây là một minh chứng khái niệm minh họa sức mạnh của Nền tảng Nhà phát triển Cloudflare cho các ứng dụng AI.&lt;/p&gt;
&lt;p&gt;Moltworker kết hợp nhiều sản phẩm của Cloudflare:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bộ công cụ Sandbox&lt;/strong&gt;: Chạy mã nguồn trong môi trường cô lập an toàn, thay thế container Docker cục bộ. Bộ công cụ Sandbox cung cấp API thân thiện để thực thi lệnh, quản lý tệp, chạy quy trình nền mà không phải lo vòng đời phức tạp của container.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kết xuất trình duyệt&lt;/strong&gt;: Điều khiển trình duyệt không đầu theo chương trình để tác nhân AI có thể điều hướng web, điền biểu mẫu, chụp ảnh nhanh. Hỗ trợ Puppeteer, Playwright và cả MCP cho AI.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lưu trữ R2&lt;/strong&gt;: Lưu trữ bền vững cho bộ nhớ phiên hội thoại, hội thoại và các tài sản khác. Vì container vốn dĩ tạm thời, bộ chứa R2 được gắn kết như một phân vùng hệ thống tệp để đảm bảo dữ liệu không bị mất.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cổng AI&lt;/strong&gt;: Đóng vai trò trung gian giữa tác nhân AI và các nhà cung cấp AI. Hỗ trợ BYOK (Mang khóa của bạn) hoặc Thanh toán thống nhất - Cloudflare quản lý bí mật và tính tiền tập trung. Cung cấp khả năng hiển thị về chi phí, nhật ký và phân tích.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Điều khiển truy cập Zero Trust&lt;/strong&gt;: Bảo vệ API và giao diện quản trị với chính sách xác thực, cho phép định nghĩa ai được truy cập và giám sát hoạt động của người dùng.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cloudflare Workers hiện đã tương thích rất tốt với Node.js - trong 1000 gói NPM phổ biến nhất, chỉ 1,5% không chạy được. Điều này cho phép chạy phần lớn logic của tác nhân AI ngay trên Workers, gần người dùng hơn.&lt;/p&gt;
&lt;p&gt;Đội ngũ Cloudflare đã mã nguồn mở bản triển khai tại GitHub và chạy thử nghiệm với Slack để demo các khả năng như tìm đường trên Google Maps, đặt món ăn, và thậm chí tạo video từ khung trình duyệt. Moltworker là demo cho thấy Cloudflare có đủ bộ công cụ để xây dựng và chạy ứng dụng AI phức tạp trên mạng biên toàn cầu.&lt;/p&gt;
&lt;h2 id="xây-dựng-rotating-bloom-filter-hiệu-suất-cao-trong-java"&gt;&lt;a class="link" href="https://medium.com/@udaysagar.2177/building-a-high-performance-rotating-bloom-filter-in-java-a9e75de993bf" target="_blank" rel="noopener"
&gt;Xây dựng Rotating Bloom Filter hiệu suất cao trong Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này giải thích cách xây dựng bộ lọc Bloom xoay - một cấu trúc dữ liệu giải quyết vấn đề theo dõi tư cách thành viên trong các luồng dữ liệu không giới hạn với bộ nhớ hạn định. Khác với bộ lọc Bloom truyền thống có dung lượng cố định, bộ lọc xoay tự động hết hạn các mục theo cửa sổ thời gian, cho phép xử lý vô hạn dữ liệu với bộ nhớ không đổi.&lt;/p&gt;
&lt;p&gt;Bộ lọc Bloom xoay giải quyết 4 bài toán khó:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Ghi đồng thời không khóa&lt;/strong&gt;: Thay vì dùng khóa, bản triển khai sử dụng So sánh và Hoán đổi (CAS) với &lt;code&gt;AtomicLongArray&lt;/code&gt;. Các luồng thử đặt bit nguyên tử - nếu thất bại thì thử lại. Vì bộ lọc Bloom phân tán bit hàng triệu vị trí, xác suất va chạm cực thấp, nên đa số luồng chạy song song mà không chờ đợi. Kết quả: thông lượng tốt hơn 3-4 lần so với bản triển khai dựa trên khóa.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Đóng băng bộ lọc hoạt động&lt;/strong&gt;: Khi cửa sổ thời gian hết hạn, bộ lọc &amp;ldquo;hoạt động&amp;rdquo; được chuyển sang ảnh chụp chỉ đọc. &lt;code&gt;AtomicLongArray&lt;/code&gt; đắt đỏ vì mỗi lần đọc đều trả chi phí truy cập bộ nhớ nguyên tử. Giải pháp: sao chép sang &lt;code&gt;long[]&lt;/code&gt; đơn giản - bất biến và nhanh hơn nhiều vì truy cập bộ nhớ trực tiếp, không có chi phí nguyên tử. Chuỗi bộ lọc trở thành: &lt;code&gt;[ReadOnly-1, ReadOnly-2, ReadOnly-3, Active]&lt;/code&gt; - ghi chỉ vào Active, đọc kiểm tra tất cả từ mới đến cũ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Điều phối xoay vòng qua các luồng&lt;/strong&gt;: Vấn đề là ghi có thể bị mất trong quá trình xoay - luồng A đọc chuỗi, xoay xảy ra, luồng A viết vào bộ lọc không còn hoạt động. Giải pháp dùng Khóa Đọc-Ghi: ghi giữ khóa đọc để đảm bảo chuỗi không đổi trong khi ghi; xoay giữ khóa ghi. Truy vấn thì hoàn toàn không khóa - nếu truy vấn đọc tham chiếu chuỗi cũ, chỉ là vấn đề thời điểm, không ảnh hưởng tính đúng đắn. Xoay chỉ giữ khóa khoảng 5 mili giây mỗi 5 phút (0,0017% thời gian).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Tỷ lệ dương tính giả tăng trưởng&lt;/strong&gt;: Khi chuỗi nhiều bộ lọc, dương tính giả cộng dồn theo công thức &lt;code&gt;Tỷ lệ FPR kết hợp ≈ 1 - (1 - p)^N&lt;/code&gt;. Với 5 cửa sổ mỗi cái 1% FPR, FPR kết hợp khoảng 5% chứ không phải 1%. Giải pháp: cấu hình FPR mỗi cửa sổ thấp hơn để đạt được mục tiêu FPR kết hợp. sự đánh đổi: càng nhiều cửa sổ thì lưu giữ càng lâu nhưng FPR càng cao.&lt;/p&gt;
&lt;p&gt;Ngoài ra, thư viện còn có nhiều tối ưu hóa hiệu suất: giao diện Bits tính toán trước các vị trí bit và tái sử dụng, băm đôi chỉ cần tính toán 2 băm cho k vị trí bất kỳ, băm xxHash dưới nano giây nhanh hơn 10-20 lần so với MD5/SHA, và trừu tượng BitsProvider cho dữ liệu được serialized sao chép bằng không. Tất cả giúp đạt hàng triệu hoạt động mỗi giây.&lt;/p&gt;
&lt;h2 id="mọi-java-developer-nên-biết-gì-về-thread-pools"&gt;&lt;a class="link" href="https://dev.to/realnamehidden1_61/what-every-java-developer-should-know-about-thread-pools-4jam" target="_blank" rel="noopener"
&gt;Mọi Java developer nên biết gì về Thread Pools&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giải thích kiến thức cơ bản về pool luồng trong Java - một công cụ quan trọng để quản lý tính đồng thời hiệu quả. Tác giả so sánh việc tạo luồng mới cho mỗi tác vụ giống như thuê nhân viên cho một đơn đặt hàng pizza rồi sa thải họ ngay sau đó - tốn kém và kém hiệu quả.&lt;/p&gt;
&lt;p&gt;Pool luồng thông qua &lt;code&gt;ExecutorService&lt;/code&gt; duy trì một tập hợp các luồng worker có sẵn để xử lý các tác vụ. Khi tác vụ hoàn thành, luồng không bị hủy mà quay lại pool chờ tác vụ tiếp theo. Điều này giúp:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Quản lý tài nguyên&lt;/strong&gt;: Giới hạn số lượng luồng tối đa, tránh hết bộ nhớ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cải thiện độ trễ&lt;/strong&gt;: Các luồng đã có sẵn nên không có độ trễ khi khởi động tác vụ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kiểm soát API&lt;/strong&gt;: Dễ dàng lên lịch các tác vụ chạy sau hoặc lặp lại định kỳ&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Các loại pool phổ biến:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Pool luồng cố định&lt;/strong&gt;: Số lượng worker cố định - tốt cho khối lượng công việc có thể dự đoán&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pool luồng được lưu trong bộ nhớ đệm&lt;/strong&gt;: Tạo luồng mới khi cần nhưng tái sử dụng luồng cũ - tốt cho nhiều tác vụ ngắn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pool luồng được lên lịch&lt;/strong&gt;: Cho các tác vụ cần chạy định kỳ hoặc sau độ trễ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Luồng ảo (Java 21+)&lt;/strong&gt;: Cách mạng hóa để xử lý hàng triệu tác vụ với chi phí overhead gần như bằng không&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết đưa ra các phương pháp tốt nhất quan trọng:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Luôn dùng try-with-resources&lt;/strong&gt;: Đảm bảo pool luồng tắt đúng cách. Quên tắt &lt;code&gt;ExecutorService&lt;/code&gt; là nguyên nhân hàng đầu gây rò rỉ bộ nhớ.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Đặt kích thước pool đúng cách&lt;/strong&gt;: Với các tác vụ tốn CPU nhiều, đặt kích thước pool bằng số bộ vi xử lý. Với các tác vụ tốn I/O nhiều (cơ sở dữ liệu, gọi API), dùng Luồng ảo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Đặt tên cho luồng&lt;/strong&gt;: Dùng &lt;code&gt;ThreadFactory&lt;/code&gt; để đặt tên các luồng có nghĩa như &amp;ldquo;Bộ xử lý đơn hàng-Pool-1&amp;rdquo; thay vì &amp;ldquo;Luồng-1&amp;rdquo; vô nghĩa khi gỡ lỗi.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Không bao giờ dùng &lt;code&gt;newCachedThreadPool()&lt;/code&gt; cho API công khai&lt;/strong&gt;: Có thể tạo vô hạn luồng nếu lưu lượng truy cập tăng vọt, làm sập máy chủ.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Với Java 21, bài viết khuyến nghị dùng Luồng ảo cho các tác vụ tốn I/O nhiều vì nhẹ và có thể xử lý hàng triệu tác vụ đồng thời với chi phí overhead gần như bằng không.&lt;/p&gt;
&lt;h2 id="tạm-biệt-java-xin-chào-go"&gt;&lt;a class="link" href="https://wso2.com/library/blogs/goodbye-java-hello-go" target="_blank" rel="noopener"
&gt;Tạm biệt Java, xin chào Go&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;WSO2 - công ty middleware enterprise với 20 năm lịch sử - công bố chuyển đổi chiến lược từ Java sang Go cho các sản phẩm thế hệ tiếp theo. Hiện tại 95% mã nguồn server-side của họ viết bằng Java, nhưng bối cảnh infrastructure software đã thay đổi đáng kể.&lt;/p&gt;
&lt;p&gt;Những thay đổi chính trong 15 năm qua:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kỷ nguyên container&lt;/strong&gt;: Middleware không còn là &amp;ldquo;server&amp;rdquo; độc lập mà giờ là library được gắn vào logic, trở thành một process duy nhất. Container được tạo để xử lý task rồi bị hủy - chúng ngắn hạn hơn nhiều so với trước đây.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Startup time quan trọng&lt;/strong&gt;: Java với tối ưu hóa JIT sau khi khởi động không hoạt động tốt khi server không chạy lâu. Java ecosystem khổng lồ khiến memory bloat và startup time dài - trong khi container cần sẵn sàng trong mili giây, không phải giây.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chi phí infrastructure&lt;/strong&gt;: Memory footprint và CPU consumption của container trở thành quan trọng để quản lý cost. Java yêu cầu bộ nhớ và CPU cao hơn đáng kể so với các ngôn ngữ native khác.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Java đã cố gắng thích nghi với GraalVM native images và Project Loom, nhưng những giải pháp này cảm giác như vá cho một ngôn ngữ và runtime được thiết kế cho kỷ nguyên khác.&lt;/p&gt;
&lt;p&gt;WSO2 quyết định chuyển sang Go cho backend và middle tier trong khi frontend vẫn giữ nguyên. Go được chọn thay vì Rust vì:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rust tuyệt vời cho OS, browser, hoặc code chạy rất lâu không restart - nhưng WSO2 build middleware infrastructure ở mức cao hơn bare metal.&lt;/li&gt;
&lt;li&gt;Go cân bằng tốt: quản lý bộ nhớ hiệu quả, concurrency primitives đủ thấp, cross-compile thành native code.&lt;/li&gt;
&lt;li&gt;Go đã được chứng minh: Kubernetes, Docker và nhiều enterprise infrastructure khác đều viết bằng Go.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;WSO2 đã dùng Go gần một thập kỷ với các dự án như OpenChoreo (CNCF project), rewrite Ballerina compiler, và Thunder (identity platform). Đây không phải là nhảy vốt mù quáng mà là sự chuyển dịch có kế hoạch.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, WSO2 khẳng định sẽ không bỏ rơi các sản phẩm Java hiện tại - tiếp tục phát triển và hỗ trợ không có ngày kết thúc. Các sản phẩm thế hệ tiếp theo như Thunder và OpenChoreo đại diện cho hướng đi mới với hiệu suất tốt hơn, chi phí infrastructure thấp hơn.&lt;/p&gt;
&lt;p&gt;Bài viết kết luận bằng lời tri ân Java: &amp;ldquo;Cảm ơn, Java. Chúng tôi sẽ không ở đây nếu không có bạn.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="10-bẫy-ưu-tiên"&gt;&lt;a class="link" href="https://cutlefish.substack.com/p/tbm-399-10-prioritization-traps" target="_blank" rel="noopener"
&gt;10 bẫy ưu tiên&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này chia sẻ 10 anti-pattern và bẫy trong việc định ưu tiên mà các team sản phẩm thường gặp phải. Tác giả làm việc tại startup nơi mỗi giây đều là quyết định ưu tiên, và mục tiêu không phải là quyết định hoàn hảo mà là quyết định &amp;ldquo;đủ tốt&amp;rdquo; giúp tiến về phía trước.&lt;/p&gt;
&lt;p&gt;10 bẫy được đặt tên theo các bài hát nổi tiếng:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Burning Down the House (Cháy nhà)&lt;/strong&gt; - Luôn ở chế độ phản ứng với việc khẩn cấp nhưng giá trị trung bình thấp. Team không bao giờ thoát khỏi vùng khẩn cấp, luôn bị kéo theo những việc gây đau đớn cho khách hàng nhưng không thực sự thay đổi cuộc chơi. Giải pháp: Dành ra 10-20% capacity được bảo vệ khỏi công việc phản ứng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Too Much Time on My Hands (Quá nhiều thời gian rảnh)&lt;/strong&gt; - Việc trung bình, khẩn cấp trung bình, giá trị trung bình, nhưng team không tìm được 20/80 - 20% nỗ lực tạo 80% kết quả. Team tốn quá nhiều thời gian hoàn thiện, tránh giảm rủi ro và học tập sớm. Giải pháp: Buộc cắt sớm, định nghĩa phiên bản nhỏ nhất để học trong 2-4 tuần.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Everybody Wants to Rule the World (Ai cũng muốn thống trị)&lt;/strong&gt; - Việc giá trị cao, khẩn cấp cao mà &amp;ldquo;ai cũng đồng ý là ưu tiên hàng đầu&amp;rdquo; nhưng không ai thực sự drop được việc đang làm. Các phó chủ tịch khác nhau đang cân bằng ưu tiên cục bộ của họ. Giải pháp: Chọn một việc cụ thể được phép drop để phục vụ ưu tiên.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Just Enough Is Never Enough (Không bao giờ đủ)&lt;/strong&gt; - Luôn làm &amp;ldquo;tối thiểu&amp;rdquo; và bỏ lỡ cơ hội nắm bắt giá trị thực. Team ship nhanh nhưng chỉ nắm bắt được 20% giá trị, hoặc ship chậm và bị ép buộc chuyển sang việc khác. Giải pháp: Trước khi ship, liệt kê 1-2 khoản đầu tư tiếp theo sẽ mở khóa giá trị không tỷ lệ, cho phép trước một trong số đó.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Running on Empty (Chạy rỗng)&lt;/strong&gt; - Death marches không ai giải thích được tại sao mất nhiều thời gian. Cửa sổ cơ hội trôi đi khi thời gian trôi qua. Không có cách để nói &amp;ldquo;này, chúng ta đang đi off đường&amp;rdquo;. Giải pháp: Introduce tín hiệu &amp;ldquo;off-track&amp;rdquo; rõ ràng - ngày cột mốc học tập, hoặc điểm kiểm tra quyết định.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6. Dreamer (Người mơ)&lt;/strong&gt; - Nỗ lực đổi mới khẩn cấp thấp nhưng giá trị cao, được lãnh đạo bảo vệ nhưng không có áp lực ship và học, hoặc không có ràng buộc cho phép. Team xây cầu đến không có nơi nào. Giải pháp: Thêm một ràng buộc cho phép - deadline để ship gì đó thực sự, tích hợp với team hiện tại.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;7. Slow Ride (Ch Ride chậm)&lt;/strong&gt; - Những ma sát ảnh hưởng mọi người, chậm tất cả, nhưng bị coi là &amp;ldquo;khởi nghiệp kỹ thuật&amp;rdquo; với khẩn cấp thấp. Nếu Slack hay GitHub down vài giờ mỗi ngày sẽ là thảm họa, nhưng ma sát nội bộ thì được chấp nhận. Giải pháp: Đo lường sức cản - đo thời gian thêm mỗi tuần, reframe là chi phí trì hoãn không phải &amp;ldquo;dọn dẹp kỹ thuật&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;8. Someday Never Comes (Ngày nào đó sẽ không bao giờ đến)&lt;/strong&gt; - &amp;ldquo;Nên nhưng không thể&amp;rdquo; - cơ hội giá trị cao nhưng không ai có giải pháp đủ tự tin, nên bị trì hoãn mãi mãi. Thay vì tư duy xác suất, tổ chức treat này như cơ hội khao khát xa xôi. Giải pháp: Chạy một experiment chi phí thấp chỉ để giảm uncertainty, làm học tập là mục tiêu không phải thành công.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;9. The Logical Song (Bài hát logic)&lt;/strong&gt; - Bỏ qua chi phí tăng sự tự tin. Sự tự tin không miễn phí, cần tính toán dễ học đến đâu, tăng sự tự tin, giảm rủi ro sớm. Giải pháp: Thêm cột vào định ưu tiên: &amp;quot; Chúng ta có thể tăng sự tự tin với chi phí bao rẻ?&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;10. Takin&amp;rsquo; Care of Business (Chăm sóc business)&lt;/strong&gt; - Tetris định ưu tiên - pack thời gian và mục tiêu hàng quý dựa trên premise nếu stars align sẽ hoàn thành tất cả. Không có small-batch items ready, teams invent work khi blocked. Giải pháp: Xây dựng và duy trì small-batch &amp;ldquo;pull queue&amp;rdquo; của work được chấp nhận universally, low-risk.&lt;/p&gt;
&lt;p&gt;Điểm chính là không phải về quyết định hoàn hảo, mà là detect và filter out bẫy để đưa ra quyết định tốt hơn.&lt;/p&gt;
&lt;h2 id="đánh-giá-chất-lượng-nội-bộ-khi-lập-trình-với-ai"&gt;&lt;a class="link" href="https://martinfowler.com/articles/exploring-gen-ai/ccmenu-quality.html" target="_blank" rel="noopener"
&gt;Đánh giá chất lượng nội bộ khi lập trình với AI&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Martin Fowler chia sẻ kinh nghiệm thực tế khi sử dụng AI coding assistant (Windsurf/Sonnet 3.5 và Claude Code/Sonnet 4.5) để thêm tính năng hỗ trợ GitLab vào CCMenu - ứng dụng Mac hiển thị status CI/CD builds. Tác giả tập trung vào một khía cạnh ít được bàn đến: chất lượng nội bộ của code do AI tạo ra.&lt;/p&gt;
&lt;p&gt;Tác giả thêm feature hỗ trợ GitLab vào CCMenu (viết bằng Swift) với sự hỗ trợ của AI agent, và phát hiện nhiều vấn đề về code quality:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề 1: Sai lệch về semantics&lt;/strong&gt; - AI khai báo parameter token là non-optional &lt;code&gt;String&lt;/code&gt; trong tất cả wrapper functions, trong khi underlying &lt;code&gt;makeRequest&lt;/code&gt; function đúng là optional &lt;code&gt;String?&lt;/code&gt;. Khi code cần sử dụng optional token, AI fix bằng cách thêm empty string làm default (&lt;code&gt;apiToken ?? &amp;quot;&amp;quot;&lt;/code&gt;) thay vì sửa function declaration để optional. Điều này:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không idiomatic với Swift&lt;/li&gt;
&lt;li&gt;Không self-documenting&lt;/li&gt;
&lt;li&gt;Không được type system support&lt;/li&gt;
&lt;li&gt;Phải thay đổi ở mọi nơi gọi function&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề 2: Cache không cần thiết&lt;/strong&gt; - AI muốn introduce cache hoàn toàn không cần thiết và không thể giải thích tại sao.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề 3: Logic phức tạp cho vấn đề không tồn tại&lt;/strong&gt; - AI không nhận ra rằng user/org overlap trong GitHub không tồn tại trong GitLab, và implement complicated logic để handle problem không có real. Tác giả phải guide AI về documentation đúng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề 4: Không reuse existing functions&lt;/strong&gt; - AI &amp;ldquo;quên&amp;rdquo; sử dụng existing functions để construct URLs, replicate logic ở nhiều places, thậm chí bỏ qua functionality như option override base URL cho testing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề 5: Hiểu sai API&lt;/strong&gt; - Cả Windsurf và Claude Code đều stumble khi retrieve avatar URL - GitLab giữ avatar URL riêng trong &lt;code&gt;/user&lt;/code&gt; endpoint khác với GitHub, nhưng AI tin tưởng URL có trong response và phải tranh luận dài.&lt;/p&gt;
&lt;p&gt;Tác giả kết luận: AI agents có xu hướng mạnh introduce technical debt, làm cho future development khó hơn cho cả humans và agents. Với Windsurf/Sonnet 3.5, code quality kém và dễ stuck, khiến việc sử dụng agent không đáng. Nhưng với Claude Code/Sonnet 4.5, code quality tốt hơn, cần ít prompting hơn, và running conversation trong terminal window alongside Xcode feel more natural. Điều này đủ để tác giả dùng Claude Code regularly.&lt;/p&gt;
&lt;p&gt;Bài viết nhấn mạnh importance của internal quality - investing vào chất lượng codebase là worthwhile investment. Without careful oversight, AI agents có thể degrade codebase quality theo thời gian.&lt;/p&gt;
&lt;h2 id="môi-trường-linux"&gt;&lt;a class="link" href="https://www.jtolio.com/2026/01/tinyemu-go/" target="_blank" rel="noopener"
&gt;Môi trường Linux &amp;ldquo;Pure Go&amp;rdquo; được Claude port&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết kể về kinh nghiệm sử dụng Claude để port TinyEMU - emulator hệ thống RISC-V của Fabrice Bellard từ C sang Go. Kết quả là có thể chạy &lt;code&gt;go run&lt;/code&gt; và có một môi trường Linux hoàn chỉnh với quyền truy cập root, không cần quyền đặc biệt, không dùng containers, và chạy bất kỳ đâu Go chạy.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, bài viết tập trung vào bài học về việc lập trình với tác nhân LLM:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;80% đầu là tên lửa hứa, 20% cuối là cực hình&lt;/strong&gt; - Tác giả mô tả cảm xúc: thú vị -&amp;gt; trời ơi nó hoạt động -&amp;gt; ôi không ôi không -&amp;gt; trời ơi đống gì đây -&amp;gt; hmm có lẽ nó sẽ hoạt động. 20% cuối cực kỳ khó vì tác giả không code nên không có ngữ cảnh, phải nhìn vào codebase người lạ cố gắng giúp robot bị kẹt chạy vòng tròn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề với Claude&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Claude thường lờ chỉ dẫn, thêm xử lý lỗi &amp;ldquo;tốt hơn&amp;rdquo; hoặc để comments &amp;ldquo;trong production chúng ta sẽ&amp;hellip;&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Claude tự quyết định implement networking stack sau khi Linux boot hoàn toàn, sau đó tác giả phải bắt đầu lại từ đầu.&lt;/li&gt;
&lt;li&gt;Cả thư viện networking C SLIRP non-blocking port sang Go là thảm họa - tác giả hối hận khi đã thử.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Công cụ Beads&lt;/strong&gt; - Tác giả cảnh báo không dùng Beads vì cực kỳ chậm, 294k dòng Go, repo 128MB chỉ để update tệp markdown. Bạn nên dùng Ticket thay vì Beads.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm sáng&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Claude đôi khi sáng tạo một cách đáng ngạc nhiên - xử lý oom-killer tốt hơn bản gốc.&lt;/li&gt;
&lt;li&gt;Claude đôi khi tuyệt vời ở gỡ lỗi - phát hiện vấn đề bộ nhớ BIOS từ hex dump.&lt;/li&gt;
&lt;li&gt;Nhưng cũng tệ hại ở gỡ lỗi khi bị kẹt trong code chính nó thiết kế.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Bài học&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xóa session và bắt đầu với ngữ cảnh mới thường xuyên&lt;/li&gt;
&lt;li&gt;Nói rõ ràng với tác nhân lặp đi lặp lại để tạo tickets nếu có công việc mới được phát hiện&lt;/li&gt;
&lt;li&gt;Thỉnh thoảng lùi lại hai bước và nói với tác nhân nhiều sessions đã thất bại, cần cách tiếp cận mới&lt;/li&gt;
&lt;li&gt;Đừng mong đợi Claude tạo APIs gắn kết across sessions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Kết luận&lt;/strong&gt;: Project đồng thời làm tác giả both enthu hơn và ít enthu hơn về coding với LLMs. LLMs cung cấp capabilities mới nhưng nếu muốn code không tệ, phải think carefully về cách hưởng lợi. Khi tác giả tự làm thì less frustrating và chất lượng output cao hơn, nhưng throughput thấp hơn LLM.&lt;/p&gt;
&lt;h3 id="bonus"&gt;Bonus
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Hình ảnh:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substackcdn.com/image/fetch/w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36412c2b-8782-476e-9db4-aaf794629b74_2250x2624.png"
loading="lazy"
alt="How to Scale An API"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!4V7B!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9589feb-6f59-4971-9da4-26712d1a2ca1_2360x2960.png"
loading="lazy"
alt="HTTP/2 over TCP vs HTTP/3 over QUIC"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!ihnd!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe954900-e8d8-40d0-a4b1-2f8e14068882_2360x2960.png"
loading="lazy"
alt="How Git Really Stores Your Data"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!5SHy!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbddfb5f-a652-4749-b0b9-210102774f4f_2360x2960.png"
loading="lazy"
alt="How NAT Works"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #80</title><link>https://miti99.com/post/2026/02/03/</link><pubDate>Tue, 03 Feb 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/02/03/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #80.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="thư-mục-kỹ-năng-của-tác-nhân"&gt;&lt;a class="link" href="https://skills.sh/" target="_blank" rel="noopener"
&gt;Thư Mục Kỹ Năng Của Tác Nhân&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Skills.sh là một hệ sinh thái mở dành cho các kỹ năng của tác nhân trí tuệ nhân tạo, nơi tập hợp hàng ngàn kỹ năng có thể tái sử dụng để nâng cao khả năng của các tác nhân trí tuệ nhân tạo. Mỗi kỹ năng là một khả năng chuyên biệt có thể được cài đặt chỉ với một lệnh duy nhất, giúp các tác nhân trí tuệ nhân tạo tiếp cận các kiến thức quy trình chuẩn hóa.&lt;/p&gt;
&lt;p&gt;Trang web cung cấp bảng xếp hạng các kỹ năng phổ biến nhất với số lần cài đặt thực tế, cho phép người dùng dễ dàng tìm kiếm và khám phá các kỹ năng phù hợp với nhu cầu của mình. Các kỹ năng hàng đầu bao gồm các công cụ tìm kiếm kỹ năng, hướng dẫn tốt nhất cho React và Next.js, các quy trình thiết kế web, và nhiều kỹ năng khác liên quan đến phát triển giao diện, máy chủ, kiểm thử, và vận hành.&lt;/p&gt;
&lt;p&gt;Điểm đặc biệt của hệ sinh thái này là tính cộng đồng và khả năng mở rộng - bất kỳ ai cũng có thể đóng góp và chia sẻ các kỹ năng của mình, tạo nên một kho tàng kiến thức tập thể liên tục phát triển. Các tác nhân có thể tận dụng các kỹ năng này để thực hiện các tác vụ phức tạp một cách chuyên nghiệp và hiệu quả hơn, từ viết mã, kiểm thử, đến triển khai và vận hành.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kho kỹ năng mở với hàng ngàn kỹ năng có thể cài đặt bằng một lệnh&lt;/li&gt;
&lt;li&gt;Bảng xếp hạng theo số lần cài đặt và xu hướng 24 giờ&lt;/li&gt;
&lt;li&gt;Hỗ trợ nhiều loại tác nhân và khung làm việc phổ biến&lt;/li&gt;
&lt;li&gt;Cộng đồng sôi nổi với các kỹ năng từ Vercel, Anthropic, Expo, Supabase&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="kết-quả-khảo-sát-nhà-phát-triển-go-2025"&gt;&lt;a class="link" href="https://go.dev/blog/survey2025" target="_blank" rel="noopener"
&gt;Kết quả Khảo sát Nhà phát triển Go 2025&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Go Team đã công bố kết quả khảo sát nhà phát triển Go năm 2025 với dữ liệu từ 5.379 người tham gia. Khảo sát lần này tập trung vào cảm nhận của nhà phát triển về ngôn ngữ Go, các trường hợp sử dụng, thách thức và môi trường phát triển.&lt;/p&gt;
&lt;p&gt;Ba phát hiện quan trọng nhất từ khảo sát: các nhà phát triển Go cần hỗ trợ về việc xác định và áp dụng các phương pháp tốt nhất, tận dụng tối đa thư viện chuẩn, và mở rộng ngôn ngữ với các tính năng hiện đại hơn. Hầu hết các nhà phát triển Go hiện đang sử dụng công cụ phát triển hỗ trợ bởi trí tuệ nhân tạo khi tìm kiếm thông tin hoặc viết mã lặp lại, nhưng mức độ hài lòng chỉ ở mức trung bình do lo ngại về chất lượng mã nguồn. Một tỷ lệ đáng ngạc nhiên là số người tham gia cho biết họ thường xuyên cần xem lại tài liệu cho các lệnh go cơ bản như &lt;code&gt;go build&lt;/code&gt;, &lt;code&gt;go run&lt;/code&gt;, và &lt;code&gt;go mod&lt;/code&gt;, cho thấy có chỗ cải thiện lớn cho hệ thống trợ giúp của lệnh &lt;code&gt;go&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Về mức độ hài lòng, 91% người tham gia cho biết họ hài lòng khi làm việc với Go, trong đó gần 2/3 là &amp;ldquo;rất hài lòng&amp;rdquo;. Con số này đã ổn định kể từ năm 2019. Các trường hợp sử dụng chính vẫn là dòng lệnh và dịch vụ ứng dụng lập trình, với 55% người tham gia xây dựng cả hai. Hơn 1/3 xây dựng công cụ cơ sở hạ tầng đám mây, và 11% làm việc với các mô hình máy học, công cụ, hoặc tác nhân.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;91% nhà phát triển Go hài lòng với ngôn ngữ, mức ổn định kể từ năm 2019&lt;/li&gt;
&lt;li&gt;53% người tham gia sử dụng công cụ trí tuệ nhân tạo hàng ngày nhưng chỉ 13% &amp;ldquo;rất hài lòng&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Thách thức lớn nhất: tuân thủ điển lệ Go, thiếu tính năng từ ngôn ngữ khác, tìm mô-đun tin cậy&lt;/li&gt;
&lt;li&gt;60% phát triển trên macOS, 58% trên Linux, 96% triển khai lên hệ thống dựa trên Linux&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="một-đánh-giá-trung-thực-về-go"&gt;&lt;a class="link" href="https://benraz.dev/blog/golang_review.html" target="_blank" rel="noopener"
&gt;Một Đánh Giá Trung Thực Về Go&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này chia sẻ trải nghiệm cá nhân của tác giả sau vài tháng làm việc với Go, với cái nhìn từ một người có nền tảng Rust. Tác giả phân tích những điểm mạnh và điểm yếu của ngôn ngữ này từ góc nhìn thực tế.&lt;/p&gt;
&lt;p&gt;Về điểm mạnh, Go làm rất tốt việc xử lý đồng thời với goroutines và channels được tích hợp sâu vào ngôn ngữ, tránh được vấn đề &amp;ldquo;colored functions&amp;rdquo; mà nhiều ngôn ngữ khác gặp phải. Hệ thống kiểu đơn giản, không cho phép kế thừa phức tạp, với struct embedding là một tính năng thú vị. Các giao diện trong Go không cần được triển khai một cách rõ ràng, giúp giảm mã soạn sẵn. Cú pháp của Go cũng được đánh giá là gọn gàng, với quy tắc khả kiến dựa trên chữ hoa chữ thường rất trực quan.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, tác giả cũng chỉ ra những điểm yếu đáng kể. Thiếu kiểu liệt kê thực sự là một vấn đề lớn - giải pháp thay thế với hằng số và iota không đảm bảo an toàn kiểu và không có kiểm tra đầy đủ. Go cũng thiếu bất biến đúng đắn: hằng số chỉ hoạt động với giá trị thời gian biên dịch, còn biến bình thường thì có thể bị biến đổi bất cứ lúc nào. Hệ thống xử lý lỗi tuy đơn giản nhưng không thực sự hữu dụng - kiểu lỗi chỉ là một giao diện với phương thức Error(), khiến việc xử lý lỗi theo loại trở nên khó khăn, đôi khi phải phân tích chuỗi để xác định loại lỗi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Goroutines và channels là một trong những mô hình đồng thời tốt nhất hiện có&lt;/li&gt;
&lt;li&gt;Hệ thống kiểu đơn giản, giao diện không cần triển khai rõ ràng&lt;/li&gt;
&lt;li&gt;Thiếu kiểu liệt kê thực sự với kiểm tra đầy đủ&lt;/li&gt;
&lt;li&gt;Hằng số chỉ là thời gian biên dịch, không có bất biến thực sự cho giá trị thời gian chạy&lt;/li&gt;
&lt;li&gt;Xử lý lỗi thiếu thông tin kiểu, thường phải phân tích chuỗi lỗi&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="những-thách-thức-của-soft-delete"&gt;&lt;a class="link" href="https://atlas9.dev/blog/soft-delete.html" target="_blank" rel="noopener"
&gt;Những Thách Thức Của Soft Delete&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích các vấn đề của mẫu xóa mềm phổ biến (thêm cột &lt;code&gt;archived_at&lt;/code&gt; hoặc &lt;code&gt;deleted&lt;/code&gt; vào bảng) và đề xuất các giải pháp thay thế. Tác giả chỉ ra rằng xóa mềm tuy đơn giản ban đầu nhưng tạo ra nhiều phức tạp: dữ liệu chết tích lũy trong cơ sở dữ liệu, truy vấn phải luôn lọc bỏ các bản ghi đã lưu trữ, việc di chuyển dữ liệu trở nên phức tạp, và việc khôi phục không đơn giản như chỉ đặt &lt;code&gt;archived_at = null&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Tác giả đề xuất ba giải pháp thay thế cho PostgreSQL. Cách đầu tiên là lưu trữ ở cấp ứng dụng - phát ra sự kiện khi xóa và lưu trữ ở dịch vụ khác. Cách thứ hai là sử dụng trình kích hoạt để sao chép các hàng vào bảng lưu trữ trước khi xóa. Cách thứ ba là Thu thập dữ liệu thay đổi dựa trên nhật ghi trước với Debezium hoặc các công cụ tương tự. Mỗi cách đều có sự đánh đổi riêng về độ phức tạp vận hành, độ tin cậy, và chi phí hạ tầng.&lt;/p&gt;
&lt;p&gt;Nếu bắt đầu dự án mới hôm nay, tác giả sẽ chọn cách tiếp cận dựa trên trình kích hoạt vì đơn giản thiết lập, giữ bảng chính sạch sẽ, và không cần thêm hạ tầng phức tạp. Bảng lưu trữ dễ truy vấn khi cần và dễ bỏ qua khi không dùng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xóa mềm với &lt;code&gt;archived_at&lt;/code&gt; tạo ra nhiều phức tạp: truy vấn phức tạp, dữ liệu chết tích lũy, di chuyển dữ liệu khó khăn&lt;/li&gt;
&lt;li&gt;Lưu trữ ở cấp ứng dụng: đơn giản cho cơ sở dữ liệu nhưng dễ mất dữ liệu nếu có lỗi, hạ tầng phức tạp&lt;/li&gt;
&lt;li&gt;Cách tiếp cận dựa trên trình kích hoạt: đơn giản, giữ bảng sạch, lưu trữ dễ truy vấn và dọn dẹp&lt;/li&gt;
&lt;li&gt;Thu thập dữ liệu thay đổi (Debezium): không thay đổi mã ứng dụng nhưng hạ tầng phức tạp&lt;/li&gt;
&lt;li&gt;Bản sao không xử lý DELETE: ý tưởng mới, chưa kiểm tra, có thể hoạt động cho lưu trữ&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="được-trả-lương-tối-thiểu-để-giải-một-bài-toán-bất-khả-thi"&gt;&lt;a class="link" href="https://tiespetersen.substack.com/p/i-got-paid-minimum-wage-to-solve" target="_blank" rel="noopener"
&gt;Được Trả Lương Tối Thiểu Để Giải Một Bài Toán Bất Khả Thi&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này kể về câu chuyện có thật của tác giả - một sinh viên khoa học máy tính được trả lương tối thiểu để lau cửa hàng Albert Heijn. Thay vì làm công việc một cách bình thường, tác giả đã biến nó thành một bài toán tối ưu hóa: chuyển bản đồ cửa hàng thành đồ thị, xây dựng trình soạn thảo trực quan bằng Processing, và viết bộ tối ưu hóa lộ trình bằng C++ sử dụng thuật toán luyện giả kim.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, giải pháp đầu tiên của thuật toán là một thảm họa - một con đường ngắn nhất về mặt kỹ thuật nhưng hoàn toàn vô dụng trong thực tế với hàng десят rẽ sắc góc. Tác giả nhận ra mình đang tối ưu hóa sai thứ: khoảng cách không phải là tất cả, số lần rẽ quay quan trọng hơn, đà chuyển động quan trọng hơn. Sau khi thêm &amp;ldquo;hình phạt rẽ&amp;rdquo; vào hàm chi phí, thuật toán tạo ra những con đường mượt mà hơn dù dài hơn một chút.&lt;/p&gt;
&lt;p&gt;Bài viết mở rộng bài học này sang nhiều khía cạnh khác của cuộc sống. Các thuật toán mạng xã hội tối ưu hóa cho mức độ tương tác chứ không phải hạnh phúc. Các thuật toán gợi ý tối ưu hóa cho thời gian xem khiến người dùng xem các lý thuyết âm mưu 6 tiếng liên tục. Các mô hình ngôn ngữ lớn tối ưu hóa cho việc nghe có tự tin chứ không phải đúng sự thật. Các doanh nghiệp tối ưu hóa cho lợi nhuận mà bỏ qua môi trường và đạo đức. Sự chính xác về mặt kỹ thuật là vô giá trị nếu bạn đang giải sai vấn đề.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thuật toán luyện giả kim có thể giải bài toán người bán du lịch cho việc lau nhà siêu thị&lt;/li&gt;
&lt;li&gt;Tối ưu hóa sai chỉ số (khoảng cách) tạo ra giải pháp kỹ thuật hoàn hảo nhưng thực tế vô dụng&lt;/li&gt;
&lt;li&gt;Lộ trình A ngắn nhất nhưng không thể đi được; lộ trình B dài hơn nhưng thực tế&lt;/li&gt;
&lt;li&gt;Mạng xã hội, hệ thống gợi ý, LLM đều tối ưu hóa cho sai mục tiêu&lt;/li&gt;
&lt;li&gt;Sự chính xác kỹ thuật vô nghĩa nếu đang giải sai vấn đề từ đầu&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="hoàn-thành-lệnh-trong-intellij-idea-ít-phím-tắt-hơn"&gt;&lt;a class="link" href="https://foojay.io/today/command-completion-intellij-idea/" target="_blank" rel="noopener"
&gt;Hoàn Thành Lệnh Trong IntelliJ IDEA Ít Phím Tắt Hơn&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giới thiệu tính năng hoàn thành lệnh mới trong IntelliJ IDEA - một phần mở rộng của tính năng hoàn thành mã thông thường cho phép người dùng khám phá và thực thi các hành động của môi trường phát triển tích hợp ngay từ trình soạn thảo mà không cần nhớ các phím tắt. Thay vì phải nhớ hàng tá phím tắt, bạn chỉ cần gõ &lt;code&gt;.&lt;/code&gt; để xem các lệnh trong danh sách hoàn thành thông thường hoặc &lt;code&gt;..&lt;/code&gt; để chỉ xem các lệnh.&lt;/p&gt;
&lt;p&gt;Tính năng này giúp sửa lỗi và cảnh báo trong mã, thực hiện các hành động ở cấp tệp hoặc cấp lớp như định dạng lại mã hoặc tối ưu hóa nhập khẩu, hỗ trợ tái cấu trúc và biến đổi mã như tạo lớp, phương thức, trường, hoặc chuyển đổi lớp thành bản ghi. Bạn cũng có thể dùng nó để điều hướng, đổi tên lớp, và thậm chí thêm JavaDoc. Một số lệnh còn có bí danh giúp bạn không cần nhớ tên chính xác.&lt;/p&gt;
&lt;p&gt;Hoàn thành lệnh bổ sung cho các tính năng hiện có như hoàn thành hậu tố và mẫu trực tiếp, giữ cho bạn trong trạng thái lập trình mượt mà. Bạn có thể tập trung vào những gì mình muốn làm thay vì làm thế nào để làm. Tính năng này giúp khám phá các tính năng mạnh mẽ mà bạn có thể chưa từng biết đến.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gõ &lt;code&gt;..&lt;/code&gt; để xem tất cả các lệnh có sẵn trong ngữ cảnh hiện tại&lt;/li&gt;
&lt;li&gt;Sửa lỗi, cảnh báo, thực hiện hành động cấp tệp mà không cần nhớ phím tắt&lt;/li&gt;
&lt;li&gt;Hỗ trợ tái cấu trúc, tạo mã, biến đổi mã sang Java hiện đại&lt;/li&gt;
&lt;li&gt;Có thể dùng trong tệp chỉ đọc sau khi bật trong cài đặt&lt;/li&gt;
&lt;li&gt;Bí danh cho các lệnh giúp không cần nhớ tên chính xác&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bonus"&gt;Bonus
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Images:&lt;/strong&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/8d53556e-5fbc-4ceb-ac64-cc5f3b211c5d_2250x2624.png"
loading="lazy"
alt="The Must-Know Fundamentals of Distributed Systems"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!yb_V!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16cec58a-02f8-4daf-8669-d1208ac5fc18_2360x2960.jpeg"
loading="lazy"
alt="What Happens When You Enter Google.com"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!LIIv!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F631f49cf-2eff-4941-ba22-b2c482eb24ec_2360x2960.png"
loading="lazy"
alt="Understanding the Linux Directory Structure"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!gxq4!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11498f7e-5457-425f-9d50-90f5ebc31187_2360x2960.jpeg"
loading="lazy"
alt="Symmetric vs. Asymmetric Encryption"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!XFaF!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5140ecd2-ac9e-46d1-bde6-00f727309778_800x1003.jpeg"
loading="lazy"
alt="Network Troubleshooting Test Flow"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Videos:&lt;/strong&gt;
&lt;a class="link" href="https://www.youtube.com/watch?v=oP6DS_x5K0Y" target="_blank" rel="noopener"
&gt;Tác Nhân Trí Tuệ Nhân Tạo Là Gì &amp;amp; Chúng Hoạt Động Như Thế Nào?&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Newsletter #79</title><link>https://miti99.com/post/2026/02/02/</link><pubDate>Mon, 02 Feb 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/02/02/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #79.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="ascii-characters-are-not-pixels-a-deep-dive-into-ascii-rendering"&gt;&lt;a class="link" href="https://alexharri.com/blog/ascii-rendering" target="_blank" rel="noopener"
&gt;ASCII characters are not pixels: a deep dive into ASCII rendering&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trình bày cách tiếp cận mới mẻ để chuyển đổi hình ảnh sang ASCII art có độ nét cao. Thay vì xử lý ký tự ASCII như các điểm ảnh đơn lẻ, tác giả sử dụng khái niệm &amp;ldquo;shape vectors&amp;rdquo; (vector hình dạng) để tận dụng hình dạng thực tế của từng ký tự.&lt;/p&gt;
&lt;p&gt;Cốt lõi của phương pháp là định lượng hóa hình dạng của mỗi ký tự ASCII bằng cách sử dụng các &amp;ldquo;sampling circles&amp;rdquo; đặt tại các vị trí khác nhau trong ô lưới. Mỗi ký tự được biểu diễn bằng một vector 6 chiều, ghi nhận mức độ chiếm đóng tại từng vùng. Khi chuyển đổi hình ảnh, hệ thống tính toán sampling vector cho mỗi ô và tìm ký tự có hình dạng tương đồng nhất thông qua nearest neighbor search.&lt;/p&gt;
&lt;p&gt;Để tạo độ nét cao hơn nữa, tác giả áp dụng hai kỹ thuật tăng độ tương phản: global contrast enhancement và directional contrast enhancement. Kỹ thuật đầu tiên làm rõ ranh giới giữa các vùng có độ sáng khác nhau, trong khi kỹ thuật thứ hai xem xét thông tin từ các ô lân cận để loại bỏ hiệu ứng &amp;ldquo;staircasing&amp;rdquo; và tạo đường viền mượt mà.&lt;/p&gt;
&lt;p&gt;Bài viết cũng đề cập đến các tối ưu hóa hiệu năng quan trọng như sử dụng k-d trees để tăng tốc độ tra cứu ký tự, caching với quantization để giảm tải tính toán, và chuyển xử lý sang GPU để đạt 60 FPS trên mobile. Đây là một bài viết kỹ thuật thú vị với nhiều ý tưởng có thể áp dụng cho các vấn đề khác về xử lý hình dạng đa chiều.&lt;/p&gt;
&lt;h2 id="from-bare-metal-to-containers-a-developer"&gt;&lt;a class="link" href="https://buildsoftwaresystems.com/post/guide-to-execution-environments" target="_blank" rel="noopener"
&gt;From Bare Metal to Containers: A Developer&amp;rsquo;s Guide to Execution Environments&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này cung cấp cái nhìn toàn diện về các loại môi trường thực thi (execution environments) mà nhà phát triển phần mềm thường gặp, từ physical machine cho đến containers và virtual environments. Mỗi loại môi trường được trình bày rõ ràng với cơ chế cách ly, ưu nhược điểm và trường hợp sử dụng phù hợp.&lt;/p&gt;
&lt;p&gt;Năm loại môi trường chính được phân tích chi tiết: Physical Machine (bare metal) với hiệu năng tối đa nhưng chi phí cao, Virtual Machine sử dụng hypervisor để chia sẻ phần cứng, Container nhẹ-weight nhờ chia sẻ kernel, Process Sandbox tập trung vào bảo mật bằng cách giới hạn quyền của process, và Virtual Environment để cô lập dependencies ở cấp độ ngôn ngữ lập trình.&lt;/p&gt;
&lt;p&gt;Điểm nhấn quan trọng là hiểu rõ ranh giới cách ly của từng loại môi trường. Virtual environments chỉ giải quyết xung đột dependencies nhưng không xử lý được vấn đề về kernel hay system libraries. Containers mạnh hơn nhưng vẫn chia sẻ kernel, trong khi VMs cung cấp cách ly hoàn toàn ở mức OS. Bài viết cũng đề cập đến xu hướng tương lai với Serverless, WebAssembly và các công cụ tích hợp như uv, Conda, Rustup/Cargo.&lt;/p&gt;
&lt;h2 id="run-your-project-in-a-dev-container-in-zed"&gt;&lt;a class="link" href="https://zed.dev/blog/dev-containers" target="_blank" rel="noopener"
&gt;Run Your Project in a Dev Container, in Zed&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này giới thiệu tính năng Dev Containers mới trong trình soạn thảo Zed, bắt đầu từ phiên bản v0.218. Dev Containers là một tiêu chuẩn mở để thiết lập môi trường phát triển Dockerized, giúp mang lại trải nghiệm nhất quán cho mọi thành viên trong team ngay từ đầu.&lt;/p&gt;
&lt;p&gt;Vấn đề phổ biến khi tham gia một dự án mới là mất nhiều thời gian để thiết lập môi trường: cài đặt đúng phiên bản build tool, thiết lập database, cấu hình environment variables, và nhiều thứ khác. Trước đây, kiến thức này thường được truyền đạt qua documentation hoặc phải pair với senior engineer. Dev Containers giải quyết vấn đề này bằng cách định nghĩa môi trường trong file &lt;code&gt;.devcontainer/devcontainer.json&lt;/code&gt; với approach infrastructure-as-code.&lt;/p&gt;
&lt;p&gt;Zed tích hợp với Dev Containers bằng cách sử dụng CLI &lt;code&gt;devcontainer&lt;/code&gt; từ Microsoft. Khi phát hiện file &lt;code&gt;devcontainer.json&lt;/code&gt;, Zed sẽ hiển thị toast notification để hỏi người dùng có muốn mở project trong Dev Container không. Kiến trúc của Zed hỗ trợ remote development thông qua hai instance: Zed Remote Server trên container và Zed local trên máy người dùng, giao tiếp qua standard IO. Tương tự như cách Zed làm việc với SSH, transport layer này hoạt động tốt với &lt;code&gt;docker exec&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Bài viết cũng đề cập đến các kế hoạch tương lai như khả năng định nghĩa Dev Container spec trực tiếp trong Zed, hỗ trợ extensions trong &lt;code&gt;devcontainer.json&lt;/code&gt;, và implement &lt;code&gt;forwardPorts&lt;/code&gt; property để cải thiện remote-to-host communication.&lt;/p&gt;
&lt;h2 id="i-was-a-top-001-cursor-user-here"&gt;&lt;a class="link" href="https://blog.silennai.com/claude-code" target="_blank" rel="noopener"
&gt;I was a top 0.01% Cursor user. Here&amp;rsquo;s why I switched to Claude Code 2.0&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này là hướng dẫn toàn diện về Claude Code từ tác giả là top 0.01% người dùng Cursor, người đã sử dụng coding AI từ năm 2021. Tác giả chia sẻ lý do chuyển đổi từ Cursor sang Claude Code và các phương pháp tối ưu hóa để làm việc hiệu quả với AI coding.&lt;/p&gt;
&lt;p&gt;Năm trụ cột của agentic coding được trình bày chi tiết: Context Management với tips về việc spawn subagents cho work song song, sử dụng &lt;code&gt;/compact&lt;/code&gt; và &lt;code&gt;/transfer-context&lt;/code&gt; để quản lý context limit; Planning với ba cách tiếp cận - plan mode dialogue, sprint-style todo list, và generate revert plan; Closing the Loop bằng cách tạo commands cho repeated prompts và cập nhật CLAUDE.md; Verifiability thông qua interface tests; và Debugging với quy trình systematic và &amp;ldquo;rule of three&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Bài viết cũng đề cập đến các kỹ thuật nâng cao như sử dụng 12 parallel terminals cùng lúc, Ralph cho larger projects, Hooks/Subagents/Skills/MCP, và Headless Mode. Tác giả chia sẻ hai custom commands quan trọng: &lt;code&gt;/setup-claude-code&lt;/code&gt; (chạy một lần mỗi máy) và &lt;code&gt;/setup-repo&lt;/code&gt; (chạy một lần mỗi project) để interview và thiết lập mọi thứ tự động. Các domain playbooks cho Frontend, Backend, AI research và Learning cũng được trình bày chi tiết với tips cụ thể cho từng trường hợp.&lt;/p&gt;
&lt;h2 id="llm-predictions-for-2026-shared-with-oxide-and-friends"&gt;&lt;a class="link" href="https://simonwillison.net/2026/Jan/8/llm-predictions-for-2026/" target="_blank" rel="noopener"
&gt;LLM predictions for 2026, shared with Oxide and Friends&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này là tập hợp các dự đoán của Simon Willison về tương lai công nghệ trong 1, 3 và 6 năm, được chia sẻ trong podcast Oxide and Friends. Bryan Cantrill mở đầu episode bằng cách tuyên bố rằng ông chưa bao giờ cảm thấy bất ngờ như vậy về những gì sắp tới trong năm nay, và Simon chia sẻ cảm giác không chắc chắn đó.&lt;/p&gt;
&lt;p&gt;Các dự đoán 1 năm bao gồm: LLMs viết code tốt sẽ trở nên không thể phủ nhận - quan điểm này đã đúng vào năm 2023 và phần lớn 2024, nhưng sẽ thay đổi hoàn toàn vào năm 2026; việc giải quyết sandboxing sẽ trở nên khả thi với containers và WebAssembly; một &amp;ldquo;Challenger disaster&amp;rdquo; cho bảo mật coding agents sẽ xảy ra khi nhiều người chạy agents với quyền root; và những chú chim Kākāpō ở New Zealand sẽ có mùa sinh sản tuyệt vời.&lt;/p&gt;
&lt;p&gt;Dự đoán 3 năm: Nghịch lý Jevons cho coding agents sẽ được giải quyết theo hướng này hay hướng khác - hoặc kỹ năng software engineering bị mất giá, hoặc nhu cầu về software tăng gấp 10 lần khiến kỹ năng trở nên quý giá hơn; ai đó sẽ xây dựng một trình duyệt web mới chủ yếu dùng AI-assisted coding và điều đó thậm chí không gây ngạc nhiên. Dự đoán 6 năm: việc gõ code bằng tay sẽ đi theo hướng của punch cards, nhưng software engineering vẫn là một nghề nghiệp lớn - chỉ là engineers sẽ không còn dành nhiều giờ để gõ syntax nữa.&lt;/p&gt;
&lt;h2 id="how-we-made-notion-available-offline"&gt;&lt;a class="link" href="https://www.notion.com/blog/how-we-made-notion-available-offline" target="_blank" rel="noopener"
&gt;How we made Notion available offline&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trình bày cách Notion xây dựng tính năng Offline Mode - tính năng được người dùng yêu cầu nhất trong nhiều năm. Thách thức lớn đến từ kiến trúc block độc đáo của Notion, đòi hỏi giải quyết các vấn đề phức tạp về reference tracking, background syncing, và conflict resolution cho rich text.&lt;/p&gt;
&lt;p&gt;Notion đã sử dụng SQLite để cache records local từ trước, nhưng cache này là best-effort không có bảo đảm. Offline Mode yêu cầu bảo đảm mạnh mẽ hơn: một page phải có thể sử dụng hoàn toàn khi không có kết nối mạng. Giải pháp là phát triển SQLite cache thành persistent storage layer theo dõi pages có sẵn offline, lưu trữ tất cả dữ liệu cần thiết để render page, và ghi nhận lý do tại sao mỗi page available offline.&lt;/p&gt;
&lt;p&gt;Vấn đề phức tạp nảy sinh khi Notion giới thiệu automatic downloads và &amp;ldquo;offline inheritance&amp;rdquo; - pages trở thành available offline vì parent page của chúng. Một page có thể có nhiều lý do độc lập để được offline (toggled, auto-downloaded, inheritance), và chỉ nên bị loại bỏ khi lý do cuối cùng biến mất. Notion giải quyết bằng cách maintain một forest của offline page trees với hai bảng: &lt;code&gt;offline_page&lt;/code&gt; (một row cho mỗi page/database offline) và &lt;code&gt;offline_action&lt;/code&gt; (một row cho mỗi lý do một page được giữ offline).&lt;/p&gt;
&lt;p&gt;Để giữ offline pages được cập nhật, Notion sử dụng push-based updates thay vì polling. Mỗi khi có batch updates được apply vào page, server phát message trên channel của page đó. Clients subscribe channels cho offline pages và fetch changes khi nhận message. Khi reconnect sau khi offline, client so sánh &lt;code&gt;lastDownloadedTimestamp&lt;/code&gt; với &lt;code&gt;lastUpdatedTime&lt;/code&gt; của server để chỉ fetch pages có version mới hơn. Forest offline cũng được prune theo thời gian để keep up với structural changes như pages moved, databases gain/lose rows.&lt;/p&gt;
&lt;h2 id="how-browsers-work"&gt;&lt;a class="link" href="https://howbrowserswork.com/" target="_blank" rel="noopener"
&gt;How Browsers Work&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Đây là hướng dẫn tương tác về cách trình duyệt hoạt động, được thiết kế cho engineers và những người tò mò sử dụng web mỗi ngày nhưng chưa từng xây dựng mental model về browser. Tác giả nhận thấy hầu hết guides hiện tại quá kỹ thuật, quá chi tiết hoặc quá nông, nên đã tiếp cận theo hướng khác với nhiều interactive examples nhỏ để giúp người đọc xây dựng intuition về cách browsers hoạt động.&lt;/p&gt;
&lt;p&gt;Quy trình từ URL đến trang web được trình bày theo từng bước: Browsers làm việc với URLs - khi bạn gõ bất cứ text nào vào address bar, browser sẽ chuyển đổi nó thành URL hợp lệ (ví dụ &amp;ldquo;pizza&amp;rdquo; thành search URL, &amp;ldquo;example.com&amp;rdquo; thành &amp;ldquo;&lt;a class="link" href="https://example.com" target="_blank" rel="noopener"
&gt;https://example.com&lt;/a&gt;&amp;rdquo;). Sau đó browser chuyển URL thành HTTP request bằng cách thêm headers như &amp;ldquo;Host: example.com&amp;rdquo; và &amp;ldquo;Accept: text/html&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Tiếp theo là DNS resolution - browser không thể gửi request đến tên miền như example.com, máy tính chỉ giao tiếp với IP addresses nên browser phải hỏi DNS system để resolve domain name thành IP address. Sau đó browser thiết lập TCP connection qua three-step handshake (SYN, SYN-ACK, ACK) để đảm bảo cả hai sides đều sẵn sàng gửi và nhận data. Khi TCP connection được thiết lập, browser gửi HTTP request và nhận HTTP response.&lt;/p&gt;
&lt;p&gt;Response sau đó được parse để xây dựng DOM tree - parser chuyển tags như &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; thành tokens và builds a DOM tree. DOM là in-memory model của document, là shared contract giữa HTML parser, CSS selector engine, và JavaScript runtime. Cuối cùng là rendering pipeline: Layout (reflow) để calculate sizes và positions, Paint để fill pixels, rồi Composite để stitch layers together trên GPU. Mỗi loại change triggers các stages khác nhau - changing colors thường chỉ repaint, trong khi changing sizes forces layout và paint để recompute.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Đánh giá&lt;/strong&gt;: &lt;em&gt;Không biết vì sao nhưng mình cảm thấy bài viết này khá tốt^^ Chắc do hôm qua update lại file Agents.md, để cố gắng phát huy :)))&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #78</title><link>https://miti99.com/post/2026/02/01/</link><pubDate>Sun, 01 Feb 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/02/01/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #78.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="hai-năm-tới-của-kỹ-thuật-phần-mềm"&gt;&lt;a class="link" href="https://addyosmani.com/blog/next-two-years/" target="_blank" rel="noopener"
&gt;Hai Năm Tới Của Kỹ Thuật Phần Mềm&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Ngành công nghệ đang đứng trước một điểm ngoặt quan trọng. AI coding đã phát triển từ autocomplete đơn thuần thành các agent có thể tự thực hiện nhiệm vụ phát triển. Sự bùng nổ kinh tế từng thúc đẩy làn sóng tuyển dụng đã nhường chỗ cho yêu cầu hiệu quả: công ty giờ ưu tiên lợi nhuận hơn tăng trưởng, nhân viên giàu kinh nghiệm hơn người mới tốt nghiệp, và team nhỏ hơn nhưng được trang bị công cụ tốt hơn.&lt;/p&gt;
&lt;p&gt;Bài viết khám phá năm câu hỏi then chốt sẽ định hình kỹ thuật phần mềm đến năm 2026, với hai kịch bản đối lập cho mỗi câu hỏi. Đây không phải dự báo, mà là những lăng kính để chuẩn bị: (1) Vấn đề junior developer - tuyển dụng có thể sụt giảm khi AI tự động hóa nhiệm vụ cấp nhập môn, hoặc hồi phục khi phần mềm lan rộng mọi ngành; (2) Vấn đề kỹ năng - kỹ năng lập trình cốt lõi có thể teo đi khi AI viết phần lớn code, hoặc trở nên quan trọng hơn khi developer tập trung vào giám sát; (3) Vấn đề vai trò - vai trò developer có thể thu hẹp thành kiểm toán code AI, hoặc mở rộng thành kiến trúc sư điều phối hệ thống; (4) Chuyên gia hay đa năng - chuyên gia hẹp có nguy cơ bị thay thế, T-shaped engineer (biết rộng một chút, sâu một vài lĩnh vực) sẽ được ưu tiên; (5) Vấn đề giáo dục - bằng CS có còn là tiêu chuẩn vàng hay bị các lộ trình học nhanh hơn (bootcamp, online platform, training nội bộ) vượt mặt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;84% developer dùng AI support thường xuyên, chuyển từ &amp;ldquo;viết code từ đầu&amp;rdquo; sang &amp;ldquo;soạn prompt và ghép các mảnh AI-generated&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Harvard study: khi công ty adopt generative AI, tuyển dụng junior giảm 9-10% trong 6 quý, trong khi senior hầu như không thay đổi&lt;/li&gt;
&lt;li&gt;Big tech tuyển dụng 50% ít hơn fresh graduates trong ba năm qua&lt;/li&gt;
&lt;li&gt;Kỹ năng quan trọng: không phải đánh máy boilerplate mà review code AI để tìm lỗi logic, lỗ hổng bảo mật, mismatch với yêu cầu&lt;/li&gt;
&lt;li&gt;T-shaped developer: chuyên sâu một hai lĩnh vực (vertical stroke), hiểu rộng nhiều domain khác (horizontal stroke)&lt;/li&gt;
&lt;li&gt;45% company planned eliminate bachelor&amp;rsquo;s degree requirements cho một số vị trí kỹ thuật vào năm 2024&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Lập trình viên giỏi nhất sẽ không phải là người code nhanh nhất, mà người biết khi nào không tin AI&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Điều kiện sống sót: cập nhật kỹ năng liên tục, đa năng hóa, tập trung vào yếu tố con người (sáng tạo, tư duy phản biện, cộng tác)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="cơ-sở-dữ-liệu-năm-2025-một-năm-đánh-giá"&gt;&lt;a class="link" href="https://www.cs.cmu.edu/~pavlo/blog/2026/01/2025-databases-retrospective.html" target="_blank" rel="noopener"
&gt;Cơ Sở Dữ Liệu Năm 2025: Một Năm Đánh Giá&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết tổng hợp chi tiết các xu hướng và sự kiện quan trọng trong thế giới cơ sở dữ liệu năm 2025. PostgreSQL tiếp tục thống trị với phiên bản 18 ra mắt tháng 11, bổ sung hệ thống nhập xuất bất đồng bộ và hỗ trợ skip scans. Tuy nhiên, tin nóng nhất là làn sóng mua bán các công ty PostgreSQL: Databricks thâu tóm Neon với 1 tỷ USD, Snowflake mua CrunchyData với 250 triệu USD, và Microsoft ra mắt HorizonDB. Cuộc đua PostgreSQL phân tán cũng nóng lên với ba dự án cạnh tranh: Multigres (do Supabase phát triển), Neki (PlanetScale), và PgDog.&lt;/p&gt;
&lt;p&gt;Một xu hướng lớn khác là MCP (Model Context Protocol) - chuẩn giao tiếp giữa mô hình ngôn ngữ và cơ sở dữ liệu. Sau khi OpenAI hỗ trợ MCP vào tháng 3, mọi nhà cung cấp cơ sở dữ liệu đều tung ra MCP server riêng. Tuy nhiên, tác giả cảnh báo về rủi ro bảo mật khi cấp quyền truy cập không giới hạn cho các tác nhân trí tuệ nhân tạo. Thế giới định dạng tệp cũng sôi động với năm định dạng mới ra mắt nhằm cạnh tranh Parquet: FastLanes, F3, Vortex, AnyBlox, và Amudai.&lt;/p&gt;
&lt;p&gt;Năm 2025 chứng kiến nhiều thương vụ mua bán: IBM mua DataStax (3 tỷ USD), Salesforce mua Informatica (8 tỷ USD), và IBM mua Confluent. Hai thương vụ sáp nhập đáng chú ý là Fivetran hợp nhất với dbt Labs để tạo nên &amp;ldquo;gã khổng lồ ETL&amp;rdquo;. Về tài chính, Databricks gây quỹ thành công với hai vòng gọi vốn 4 tỷ và 1 tỷ USD, trong khi nhiều startup cơ sở dữ liệu phải đóng cửa. Năm nay cũng ghi nhận Larry Ellison trở thành người giàu nhất thế giới với tài sản 393 tỷ USD, vượt qua kỷ lục lịch sử của John D. Rockefeller.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PostgreSQL thống trị với phiên bản 18, bổ sung hệ thống nhập xuất bất đồng bộ và skip scans&lt;/li&gt;
&lt;li&gt;Làn sóng mua bán: Databricks mua Neon (1 tỷ USD), Snowflake mua CrunchyData (250 triệu USD), Microsoft ra mắt HorizonDB&lt;/li&gt;
&lt;li&gt;Cuộc đua PostgreSQL phân tán: ba dự án cạnh tranh (Multigres, Neki, PgDog)&lt;/li&gt;
&lt;li&gt;MCP trở thành chuẩn giao tiếp giữa mô hình ngôn ngữ và cơ sở dữ liệu, mọi nhà cung cấp đều tung ra MCP server&lt;/li&gt;
&lt;li&gt;Cảnh báo bảo mật: cần cấp quyền tối thiểu cho tác nhân AI để tránh rủi ro khi chúng &amp;ldquo;hoành hành&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Định dạng tệp: năm định dạng mới cạnh tranh Parquet (FastLanes, F3, Vortex, AnyBlox, Amudai)&lt;/li&gt;
&lt;li&gt;Thương vụ mua bán: IBM-DataStax (3 tỷ USD), Salesforce-Informatica (8 tỷ USD), IBM-Confluent&lt;/li&gt;
&lt;li&gt;Sáp nhập: Fivetran + dbt Labs tạo nên &amp;ldquo;gã khổng lồ ETL&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Nhiều startup đóng cửa: Fauna, PostgresML, Hydra, MyScaleDB, Voltron Data&lt;/li&gt;
&lt;li&gt;Larry Ellison trở thành người giàu nhất lịch sử (393 tỷ USD), vượt kỷ lục của John D. Rockefeller (340 tỷ USD)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="12-dự-báo-cho-năm-2026"&gt;&lt;a class="link" href="https://tomtunguz.com/2026-predictions/" target="_blank" rel="noopener"
&gt;12 Dự Báo Cho Năm 2026&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả đưa ra 12 dự báo cho năm 2026, tập trung vào sự trỗi dậy của các hệ thống tác nhân AI sẽ thay đổi kiến trúc cơ sở dữ liệu và chuyển đổi web sang thiết kế ưu tiên tác nhân. Dự báo nổi bật nhất: doanh nghiệp chi trả nhiều cho AI agents hơn cho con người lần đầu tiên, với Waymo rides đã đắt hơn Uber 31% nhưng nhu cầu vẫn tăng do ưu tiên an toàn và độ tin cậy. Năm 2026 dự kiến trở thành năm kỷ lục về thanh khoản với các đợt IPO lớn từ SpaceX, OpenAI, Anthropic, Stripe và Databricks, trong đó SpaceX và OpenAI sẽ nằm trong 10 đợt IPO lớn nhất lịch sử.&lt;/p&gt;
&lt;p&gt;Vector databases sẽ hồi sinh và trở thành hạ tầng thiết yếu trong stack AI khi các mô hình đa phương thức và mô hình không gian trạng thái đòi hỏi kiến trúc dữ liệu mới. Theo METR, thời gian thực hiện nhiệm vụ của AI tăng gấp đôi mỗi 7 tháng, và đến cuối 2026, các tác nhân AI sẽ tự chủ thực hiện luồng công việc 8+ giờ, thay đổi căn bản cách công ty phân bổ nhân sự. Ngân sách AI sẽ bị giám sát kỹ lưỡng lần đầu tiên, thúc đẩy sự phổ biến của các ngôn ngữ models nhỏ và mã nguồn mở với chi phí thấp hơn 10 lần.&lt;/p&gt;
&lt;p&gt;Google sẽ tạo khoảng cách với đối thủ thông qua sự đa dạng trong AI: frontier models, suy luận trên thiết bị, tạo video, mã nguồn mở và tích hợp tìm kiếm. Stablecoin sẽ chiếm 30% thanh toán quốc tế vào tháng 12, thay thế các đường ray SWIFT truyền thống. Các mô hình truy cập dữ liệu của tác nhân sẽ gây áp lực và làm vỡ cơ sở dữ liệu hiện tại với số lượng truy vấn tăng ít nhất một cấp độ. Xây dựng trung tâm dữ liệu sẽ đạt 3,5% GDP Mỹ, quy mô tương tự mở rộng đường sắt lịch sử. Web sẽ chuyển sang thiết kế ưu tiên tác nhân vì nhiều quyết định mua hàng hiện được thực hiện thông qua nghiên cứu của tác nhân. Cloudflare sẽ trở thành cổng cho thanh toán của tác nhân thông qua giao thức x402.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Doanh nghiệp chi trả nhiều cho AI agents hơn con người lần đầu, Waymo rides đắt hơn Uber 31% nhưng nhu cầu vẫn tăng&lt;/li&gt;
&lt;li&gt;2026: năm kỷ lục về thanh khoản với IPO từ SpaceX, OpenAI, Anthropic, Stripe, Databricks&lt;/li&gt;
&lt;li&gt;Vector databases hồi sinh và trở thành hạ tầng thiết yếu trong stack AI&lt;/li&gt;
&lt;li&gt;AI agents tự chủ thực hiện luồng công việc 8+ giờ vào cuối 2026 (theo METR: thời gian tăng gấp đôi mỗi 7 tháng)&lt;/li&gt;
&lt;li&gt;Ngân sách AI bị giám sát, ngôn ngữ models nhỏ và mã nguồn mở phổ biến với chi phí thấp hơn 10 lần&lt;/li&gt;
&lt;li&gt;Google tạo khoảng cách thông qua sự đa dạng AI: frontier models, on-device inference, video generation, open-source, search integration&lt;/li&gt;
&lt;li&gt;Agent observability trở thành lớp cạnh tranh nhất trong inference stack&lt;/li&gt;
&lt;li&gt;Stablecoin chiếm 30% thanh toán quốc tế, thay thế SWIFT cho B2B&lt;/li&gt;
&lt;li&gt;Tác nhân gây áp lực cực lớn cho cơ sở dữ liệu với truy vấn tăng ít nhất một cấp độ&lt;/li&gt;
&lt;li&gt;Trung tâm dữ liệu đạt 3,5% GDP Mỹ, quy mô tương tự mở rộng đường sắt&lt;/li&gt;
&lt;li&gt;Web chuyển sang thiết kế ưu tiên tác nhân cho tài liệu và website&lt;/li&gt;
&lt;li&gt;Cloudflare trở thành cổng thanh toán cho tác nhân thông qua giao thức x402&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sổ-tay-garbage-collection"&gt;&lt;a class="link" href="https://gchandbook.org/index.html" target="_blank" rel="noopener"
&gt;Sổ Tay Garbage Collection&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Đây là ấn bản thứ hai của cuốn sách kinh điển về quản lý bộ nhớ tự động. Cuốn sách đầu tiên &amp;ldquo;Garbage Collection&amp;rdquo; của Richard Jones (Wiley, 1996) là một cột mốc quan trọng trong lĩnh vực quản lý bộ nhớ tự động. Phiên bản kế tiếp &amp;ldquo;The Garbage Collection Handbook: The Art of Automatic Memory Management&amp;rdquo; đã ghi nhận trạng thái của lĩnh vực này vào năm 2012. Tuy nhiên, sự phát triển công nghệ đã làm cho quản lý bộ nhớ trở nên thách thức, thú vị và quan trọng hơn bao giờ hết. Ấn bản thứ hai này cập nhật handbook, tổng hợp kiến thức từ các nhà nghiên cứu và phát triển quản lý bộ nhớ tự động trong sáu mươi năm qua.&lt;/p&gt;
&lt;p&gt;Cuốn sách đề cập đến các thách thức mới cho garbage collection do những tiến bộ gần đây trong phần cứng và phần mềm, cũng như môi trường thực thi chương trình. Nó khám phá hậu quả của những thay đổi này đối với người thiết kế và thực thi các bộ thu gom rác hiệu suất cao. Cùng với các thuật toán đơn giản và truyền thống, cuốn sách bao gồm các kỹ thuật tiên tiến nhất: song song, tăng dần, đồng thời và thu gom rác thời gian thực. Các thuật toán và khái niệm thường được mô tả bằng mã giả và hình ảnh minh họa.&lt;/p&gt;
&lt;p&gt;Sự chấp nhận gần như phổ biến garbage collection bởi các ngôn ngữ lập trình hiện đại làm cho việc hiểu kỹ lưỡng chủ đề này trở nên thiết yếu đối với bất kỳ lập trình viên nào. Handbook uy tín này đưa ra cái nhìn chuyên sâu về cách thức hoạt động của các bộ thu gom khác nhau cũng như các vấn đề hiện đang đối mặt với garbage collectors. Với kiến thức này, lập trình viên có thể tự tin chọn và cấu hình trong nhiều lựa chọn garbage collectors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ấn bản thứ hai cập nhật cuốn sách kinh điển về quản lý bộ nhớ tự động (1996, 2012)&lt;/li&gt;
&lt;li&gt;Tổng hợp kiến thức từ 60 năm nghiên cứu và phát triển garbage collection&lt;/li&gt;
&lt;li&gt;Bao gồm thuật toán song song, tăng dần, đồng thời và thời gian thực&lt;/li&gt;
&lt;li&gt;Phân tích chi tiết các bộ thu gom thương mại hiệu suất cao hiện đại&lt;/li&gt;
&lt;li&gt;Giải thích các khía cạnh khó của garbage collection, bao gồm giao diện với hệ thống runtime&lt;/li&gt;
&lt;li&gt;Thêm hơn 90 trang, bao gồm các chương mới về lưu trữ và garbage collection nhận thức năng lượng&lt;/li&gt;
&lt;li&gt;E-book với hơn 37.000 liên kết đến các chương, mục, thuật toán, hình ảnh, nghiên cứu gốc&lt;/li&gt;
&lt;li&gt;Cơ sở dữ liệu trực tuyến với gần 3.400 ấn phẩm liên quan đến garbage collection&lt;/li&gt;
&lt;li&gt;Đã có bản dịch tiếng Trung và tiếng Nhật xuất bản năm 2016&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="vibe-coded-là"&gt;&lt;a class="link" href="https://gabriel-afonso.com/blog/vibe-coded-is-the-new-made-in-china/" target="_blank" rel="noopener"
&gt;Vibe-Coded Là &amp;ldquo;Made in China&amp;rdquo; Mới&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích khái niệm &amp;ldquo;vibe coding&amp;rdquo; được Andrej Karpathy đưa ra vào đầu năm 2025: một cách lập trình nơi bạn &amp;ldquo;hoàn toàn đầu hàng cho vibes, chấp nhận số mũ, và quên rằng code tồn tại&amp;rdquo; - để LLM xử lý triển khai trong khi bạn tập trung vào những gì muốn xây dựng, không phải cách xây dựng. Tác giả so sánh sự kỳ thị đối với &amp;ldquo;vibe-coded&amp;rdquo; hiện nay với nhãn &amp;ldquo;Made in China&amp;rdquo; trong quá khứ - từng là viết tắt của hàng giá rẻ, vứt đi, dù thực tế đã thay đổi.&lt;/p&gt;
&lt;p&gt;Trước khi lập trình hỗ trợ bởi AI tồn tại, các nhà phát triển mã nguồn mở phải đầu tư lượng thời gian khổng lồ chỉ để đạt được điểm xuất bản. Khó khăn của việc xây dựng phần mềm là một bộ lọc - bạn phải thực sự đứng đằng sau một ý tưởng để đưa nó đến mức đó. Bây giờ rào cản đã biến mất. Mọi người có thể tạo dựng một ứng dụng trong vài giờ mà trước đây mất vài tháng. Quan trọng hơn, mọi người có thể lập trình ở trên trình độ của họ. Bạn không cần hiểu sâu lĩnh vực. Bạn không cần biết tại sao kiến trúc của mình hoạt động. Bạn chỉ cần tầm nhìn và đủ kỹ năng prompting để tạo ra thứ gì đó hoạt động.&lt;/p&gt;
&lt;p&gt;Điều này tạo ra kịch bản nơi tác giả dự án có thể không hiểu code họ phát hành. Họ không thể sửa các trường hợp đặc biệt vì không biết hệ thống thực sự hoạt động thế nào. Họ không thể mở rộng tính năng vì không thiết kế nền tảng. Họ không thể bảo trì dự án dài hạn vì không có &amp;ldquo;sự gắn kết cảm xúc&amp;rdquo; với thứ mất một buổi chiều để xây dựng. Cộng đồng cảm nhận điều này. Sự thiếu tin tưởng không chỉ về chất lượng code, mà còn về tuổi thọ dự kiến.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, một số nhà phát triển tận tâm nhất đã tìm cách sử dụng AI mà không kích hoạt báo động. DHH (tạo ra Ruby on Rails): &amp;ldquo;Bạn không thể để sự lộn xộn và ngại ngùng phủ nhận sự kỳ diệu của AI.&amp;rdquo; Tanner Linsley (tạo TanStack): &amp;ldquo;Ở tỷ lệ nhỏ và có trách nhiệm, có.&amp;rdquo; Boris Cherny (tạo Claude Code): &amp;ldquo;Trong ba mươi ngày qua, 100% đóng góp của tôi cho Claude Code được viết bởi Claude Code.&amp;rdquo; Mô hình: các nhà phát triển quan tâm sâu sắc về chất lượng không từ chối AI. Họ tích hợp nó một cách cẩn thận, vẫn là tác giả trong khi để AI xử lý công việc nặng nhọc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Vibe coding&amp;rdquo; = để LLM xử lý triển khai, tập trung vào những gì muốn xây dựng không phải cách xây dựng&lt;/li&gt;
&lt;li&gt;Trước AI: khó khăn xây dựng phần mềm là bộ lọc, phải đầu tư thời gian/khổ luyện để xuất bản&lt;/li&gt;
&lt;li&gt;Hiện tại: rào cản biến mất, mọi người có thể code ở trên trình độ của họ&lt;/li&gt;
&lt;li&gt;Vấn đề: tác giả có thể không hiểu code họ phát hành, không thể sửa/mở rộng/bảo trì&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Vibe-coded&amp;rdquo; trở thành nhãn giống &amp;ldquo;Made in China&amp;rdquo; cũ = viết tắt của hàng giá rẻ, vứt đi&lt;/li&gt;
&lt;li&gt;AI output có tính aesthetic nhận biết: giọng văn phong, UI gradient tím, tài liệu sound helpful nhưng hollow&lt;/li&gt;
&lt;li&gt;Sự hoài nghi không vô lý: hệ sinh thái đang cố gắng bảo vệ mình trong khi quy tắc được viết lại&lt;/li&gt;
&lt;li&gt;Các nhà phát triển tận tâm vẫn dùng AI có trách nhiệm: DHH, Tanner Linsley, Boris Cherny&lt;/li&gt;
&lt;li&gt;Thời gian vẫn là bộ lọc: dự án bảo trì 2 năm với người dùng thực sự chứng cam kết không thể giả mạo&lt;/li&gt;
&lt;li&gt;Chúng ta trong giai đoạn chuyển tiếp khó xử, cần tìm bằng chứng mới về cam kết thay vì độ khó tạo ra&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="lỗi-production-khiến-tôi-quan-tâm-đến-undefined-behavior"&gt;&lt;a class="link" href="https://gaultier.github.io/blog/the_production_bug_that_made_me_care_about_undefined_behavior.html" target="_blank" rel="noopener"
&gt;Lỗi Production Khiến Tôi Quan Tâm Đến Undefined Behavior&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả chia sẻ câu chuyện về một lỗi production trong hệ thống C++ xử lý hàng tỷ euro thanh toán mỗi năm. Lỗi bug report cho thấy endpoint HTTP trả về response không thể: cả hai trường &lt;code&gt;error&lt;/code&gt; và &lt;code&gt;succeeded&lt;/code&gt; đều là &lt;code&gt;true&lt;/code&gt;, dù code logic rõ ràng chỉ set một trong hai. Sau khi điều tra, tác giả phát hiện vấn đề liên quan đến undefined behavior trong C++.&lt;/p&gt;
&lt;p&gt;Vấn đề nằm ở việc khởi tạo struct. Trong C, &lt;code&gt;Response response;&lt;/code&gt; rõ ràng là undefined behavior vì struct không được khởi tạo. Nhưng trong C++, quy tắc phức tạp hơn: nếu struct là non-POD (Plain Old Data) có thành viên non-POD như &lt;code&gt;std::string&lt;/code&gt;, default constructor được gọi. Tuy nhiên, default constructor được compiler tự động tạo ra chỉ khởi tạo các thành viên non-POD, còn các thành viên primitive (&lt;code&gt;bool&lt;/code&gt;, &lt;code&gt;int&lt;/code&gt;, v.v.) thì không. Kết quả: &lt;code&gt;std::string data&lt;/code&gt; được khởi tạo đúng, nhưng &lt;code&gt;error&lt;/code&gt; và &lt;code&gt;succeeded&lt;/code&gt; chứa giá trị rác.&lt;/p&gt;
&lt;p&gt;Giải pháp đơn giản: dùng &lt;code&gt;Response response{};&lt;/code&gt; để force zero initialization tất cả các trường. Hoặc implement default constructor rõ ràng, hoặc định nghĩa default values cho các trường trong struct definition. Bài viết cũng đề cập đến các công cụ phát hiện: clang-tidy, Address Sanitizer (ASan), và tự viết libclang plugin để quét codebase. Tác giả kết luận rằng C++ có quá nhiều cách khởi tạo biến và hầu hết đều sai, trong khi nhiều ngôn ngữ khác (C, Go, Rust) tiếp cận đơn giản hơn: struct là plain data, hoặc compiler force set mỗi trường, hoặc zero-initialize tất cả.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lỗi production trong C++ system xử lý hàng tỷ euro thanh toán mỗi năm&lt;/li&gt;
&lt;li&gt;Bug report: cả &lt;code&gt;error&lt;/code&gt; và &lt;code&gt;succeeded&lt;/code&gt; đều true, dù logic code chỉ set một trong hai&lt;/li&gt;
&lt;li&gt;Nguyên nhân: &lt;code&gt;Response response;&lt;/code&gt; - struct non-POD với &lt;code&gt;std::string&lt;/code&gt; thành viên&lt;/li&gt;
&lt;li&gt;C++ rule phức tạp: default constructor tự động chỉ init non-POD members, primitives thì không&lt;/li&gt;
&lt;li&gt;Giải pháp: &lt;code&gt;Response response{};&lt;/code&gt; force zero initialization, hoặc implement default constructor, hoặc default field values&lt;/li&gt;
&lt;li&gt;C++ có quá nhiều cách khởi tạo biến và hầu hết đều sai&lt;/li&gt;
&lt;li&gt;Tools phát hiện: clang-tidy, Address Sanitizer (ASan), Valgrind, libclang plugin&lt;/li&gt;
&lt;li&gt;ASan báo: &amp;ldquo;load of value 8, which is not a valid value for type &amp;lsquo;bool&amp;rsquo;&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Một số types không trigger undefined behavior: &lt;code&gt;std::byte&lt;/code&gt;, &lt;code&gt;unsigned char&lt;/code&gt;, &lt;code&gt;unsigned char&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Tác giả thích approach của C/Go/Rust: struct là plain data, force set hoặc zero-init&lt;/li&gt;
&lt;li&gt;Undefined behavior nguy hiểm vì code không còn là source of truth, impossible values xuất hiện&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="đừng-sa-vào-anti-ai-hype"&gt;&lt;a class="link" href="https://antirez.com/news/158" target="_blank" rel="noopener"
&gt;Đừng Sa Vào Anti-AI Hype&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả (người tạo Redis) chia sẻ quan điểm về AI và lập trình. Mặc dù yêu thích viết code từng dòng và theo đuổi phần mềm tối giản với &amp;ldquo;chất lượng con người&amp;rdquo;, ông thừa nhận AI sẽ thay đổi lập trình mãi mãi. Năm 2020 ông nghỉ việc để viết tiểu thuyết về AI và universal basic income. Cuối 2024 ông mở kênh YouTube về AI. Ông từng nghĩ chúng ta có nhiều năm trước khi lập trình được định hình lại hoàn toàn, nhưng không còn tin vậy nữa.&lt;/p&gt;
&lt;p&gt;Gần đây, LLMs hiện tại có thể hoàn thành các subtasks lớn hoặc dự án quy mô trung bình một mình, hầu như không cần hỗ trợ, chỉ cần gợi ý tốt về kết quả cuối cùng. Độ thành công phụ thuộc vào loại lập trình (càng cô lập và càng dễ diễn đạt bằng văn bản thì càng tốt: system programming đặc biệt phù hợp) và khả năng tạo representation tinh thần của vấn đề để giao tiếp với LLM. Nhưng nói chung, hiện rõ ràng rằng với hầu hết dự án, tự viết code không còn hợp lý, trừ khi để giải trí.&lt;/p&gt;
&lt;p&gt;Trong một tuần, chỉ prompting và kiểm tra code để hướng dẫn thỉnh thoảng, trong vài giờ ông hoàn thành bốn tác phẩm: (1) Sửa đổi linenoise library để hỗ trợ UTF-8 và tạo framework cho line editing testing với emulated terminal; (2) Sửa transient failures trong Redis test - vấn đề timing, TCP deadlock; Claude Code iterated, inspected process state và fixed bugs; (3) Pure C library để inference BERT embedding models - Claude Code tạo trong 5 phút, 700 dòng code, cùng output và tốc độ với PyTorch (chậm 15%); (4) Thay đổi Redis Streams internals - Claude Code reproduced work trong 20 phút hoặc ít hơn từ design document.&lt;/p&gt;
&lt;p&gt;Tác giả cảm thấy vinh dự khi code của ông được LLMs ingest, coi đó là sự tiếp nối những gì ông cố gắng cả đời: democratizing code, systems, knowledge. LLMs sẽ giúp chúng ta viết phần mềm tốt hơn, nhanh hơn, và cho phép small teams cạnh tranh với bigger companies - giống như open source software đã làm trong thập niên 90. Tuy nhiên, ông lo ngại về sự tập trung hóa - công nghệ này quá quan trọng để nằm trong tay vài công ty. Ông tin neural networks, ở quy mô, đơn giản là có thể làm những điều incredible, và không có đủ &amp;ldquo;magic&amp;rdquo; trong AI frontier hiện tại để các labs khác không bắt kịp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tác giả Redis: yêu thích viết code từng dòng, nhưng thừa nhận AI thay đổi lập trình mãi mãi&lt;/li&gt;
&lt;li&gt;LLMs hiện tại có thể hoàn thành subtasks lớn/dự án trung bình một mình, hầu như không cần hỗ trợ&lt;/li&gt;
&lt;li&gt;Trong một tuần: 4 tác phẩm hoàn thành trong vài giờ thay vì tuần nhờ AI&lt;/li&gt;
&lt;li&gt;(1) UTF-8 support cho linenoise library với testing framework&lt;/li&gt;
&lt;li&gt;(2) Sửa transient failures trong Redis test (timing, TCP deadlock)&lt;/li&gt;
&lt;li&gt;(3) Pure C library cho BERT embedding inference - 5 phút, 700 dòng, speed = PyTorch&lt;/li&gt;
&lt;li&gt;(4) Redis Streams internals changes - reproduced trong 20 phút từ design doc&lt;/li&gt;
&lt;li&gt;Tự viết code không còn hợp lý cho hầu hết dự án, trừ giải trí&lt;/li&gt;
&lt;li&gt;Vinh dự code được ingest: democratizing code/systems/knowledge như open source trong 90s&lt;/li&gt;
&lt;li&gt;LLMs giúp viết phần mềm tốt hơn, nhanh hơn, small teams cạnh tranh big companies&lt;/li&gt;
&lt;li&gt;Lo ngại tập trung hóa: công nghệ quá quan trọng để nằm trong tay vài công ty&lt;/li&gt;
&lt;li&gt;Neural networks không có đủ &amp;ldquo;magic&amp;rdquo; để các labs khác không bắt kịp&lt;/li&gt;
&lt;li&gt;Khuyên: đừng từ chối AI, test tools mới với tuần công việc, không phải test 5 phút&lt;/li&gt;
&lt;li&gt;Động lực lập trình: building - giờ có thể build nhiều hơn và tốt hơn với AI&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="performance-hints-của-abseil"&gt;&lt;a class="link" href="https://abseil.io/fast/hints.html" target="_blank" rel="noopener"
&gt;Performance Hints Của Abseil&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Abseil là tập hợp thư viện C++ do Google phát triển, đi kèm với hướng dẫn tối ưu hóa hiệu năng dựa trên kinh nghiệm thực tế của họ. Performance Hints cung cấp các kỹ thuật tối ưu hóa thực tế thay vì micro-optimizations lý thuyết. Dự án bao gồm &amp;ldquo;Performance Tips of the Week&amp;rdquo; - được mô tả như một loại &amp;ldquo;Effective analysis&amp;rdquo; cho tối ưu hóa hiệu năng.&lt;/p&gt;
&lt;p&gt;Các tips quan trọng bao gồm: Tip #70 về việc định nghĩa và đo lường thành công tối ưu hóa, Tip #72 về tối ưu hóa chính quá trình tối ưu hóa, Tip #74 về việc tránh &amp;ldquo;sweeping streetlights&amp;rdquo; - các cạm bẫy tối ưu hóa. Tip #90 thảo luận về cách đưa ra và sử dụng ước lượng trong vòng đời tối ưu hóa. Tip #64 nhấn mạnh tầm quan trọng của API tốt và trừu tượng hóa đúng để tìm kiếm cơ hội tối ưu hóa.&lt;/p&gt;
&lt;p&gt;Abseil tập trung vào các chiến lược tối ưu hóa thực tế cho code C++ hiện đại, bao gồm: hiểu rõ chi phí thực sự của các operations, sử dụng profiler để tìm bottleneck, tránh premature optimization, thiết kế API tốt cho phép tối ưu hóa mà không breaking interface, và hiểu cách compiler optimizations hoạt động. Các tips dựa trên kinh nghiệm thực tế từ việc tối ưu hóa các hệ thống lớn quy mô của Google.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Abseil: thư viện C++ từ Google với hướng dẫn tối ưu hóa hiệu năng thực tế&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Performance Tips of the Week&amp;rdquo; - các tips tối ưu hóa dựa trên kinh nghiệm thực tế&lt;/li&gt;
&lt;li&gt;Tip #70: định nghĩa và đo lường thành công tối ưu hóa&lt;/li&gt;
&lt;li&gt;Tip #72: tối ưu hóa chính quá trình tối ưu hóa&lt;/li&gt;
&lt;li&gt;Tip #74: tránh &amp;ldquo;sweeping streetlights&amp;rdquo; - cạm bẫy tối ưu hóa&lt;/li&gt;
&lt;li&gt;Tip #90: ước lượng trong vòng đời tối ưu hóa&lt;/li&gt;
&lt;li&gt;Tip #64: API tốt và trừu tượng hóa đúng để tìm cơ hội tối ưu hóa&lt;/li&gt;
&lt;li&gt;Tập trung chiến lược thực tế: profiler tìm bottleneck, tránh premature optimization&lt;/li&gt;
&lt;li&gt;Thiết kế API cho phép tối ưu hóa mà không breaking interface&lt;/li&gt;
&lt;li&gt;Hiểu cách compiler optimizations hoạt động&lt;/li&gt;
&lt;li&gt;Kinh nghiệm từ tối ưu hóa các hệ thống lớn quy mô của Google&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="triển-vọng-thị-trường-việc-làm-kỹ-thuật-phần-mềm-2026"&gt;&lt;a class="link" href="https://www.finalroundai.com/blog/software-engineering-job-market-2026" target="_blank" rel="noopener"
&gt;Triển Vọng Thị Trường Việc Làm Kỹ Thuật Phần Mềm 2026&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích triển vọng thị trường việc làm kỹ thuật phần mềm năm 2026. Kỹ thuật phần mềm từng được coi là nghề nghiệp an toàn nhất, giờ là công việc công nghệ dễ bị tổn thương nhất với layoffs gần như mỗi tuần. Companies đổ lỗi cho AI, nhưng thực tế phức tạp hơn. Dữ liệu Indeed qua FRED cho thấy hiring surge khổng lồ peak giữa 2022, rồi giảm mạnh đến 2024, và thị trường không bao hồi.&lt;/p&gt;
&lt;p&gt;Nguyên nhân thực sự: hiring boom lịch sử 2021-2022 được thúc đẩy bởi digitization. Từ Big Tech đến Startup, ai cũng overhiring. Khi thế giới chuyển online gần như overnight, companies không còn lựa chọn nào ngoài việc speed up digital efforts. FOMO tạo ra rush. Startup thấy cơ hội hiếm: users online nhiều hơn, investors đổ tiền, muốn làm products nhanh hơn. Engineers được thuê trước khi có clear work. Low interest rates cũng đóng vai trò. Sau đó họ nhận ra demand không tăng cùng pace với hiring, extra people thành gánh nặng.&lt;/p&gt;
&lt;p&gt;AI trở thành scapegoat. AI tools rẻ hơn, viết basic code trong vài phút, không đòi salary cả năm. Companies nghĩ: thay 3 engineers bằng 1 engineer với AI tools. Stock market đi lên, cách boost stock price: cut jobs và giải thích có thể làm same work với AI bots rẻ hơn. Nhưng họ vẫn cần engineers, chỉ là có euphoria rồi correction dẫn đến crisis. Giờ back to normal khi tiến đến 2026.&lt;/p&gt;
&lt;p&gt;Lý do lớn khác: large companies thoải mái với remote hiring. Tại sao hire engineer USA với salary rất cao khi có thể hire người từ Asia với fraction of cost? Senior engineer USA có thể $100k/năm, Argentina $60k, India $40k. Math đơn giản cho companies watching bottom line. AI thành PR-friendly excuse: &amp;ldquo;we are replacing jobs with AI&amp;rdquo; nghe forward-thinking hơn là &amp;ldquo;we are shipping jobs overseas&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;AI không phải culprit, nhưng không có nghĩa là không quan trọng. METR study tìm thấy experienced software engineers thực tế 19% less productive khi dùng AI tools cho real-world tasks. AI là tool, không phải replacement. Software engineering jobs sẽ không biến mất, nhưng demand cho basic coding jobs sẽ giảm. Magnus Grimeland (Antler VC) cho rằng AI sẽ tăng demand cho software engineers vì AI systems sẽ mắc lỗi, human engineers vẫn cần để fix errors. More code means more errors.&lt;/p&gt;
&lt;p&gt;US Bureau of Labor Statistics vẫn expect software developer jobs grow ~15%, chậm hơn prediction trước là 22% nhưng growth vẫn là growth. SignalFire báo Meta, Netflix, Uber, Google hire engineers faster hơn people leaving. Hiring ratios sit well above 100 - dấu mạnh engineering work đang tăng, không giảm. What&amp;rsquo;s changing là skill bar. Jobs require actual engineering thinking, designing systems, optimizing performance, ensuring security vẫn rất được demand.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Software engineering: từ career an toàn nhất thành dễ bị tổn thương nhất với layoffs mỗi tuần&lt;/li&gt;
&lt;li&gt;Hiring boom 2021-2022: digitization rush, FOMO, overhiring, low interest rates&lt;/li&gt;
&lt;li&gt;Correction 2022-2024: demand không tăng cùng pace, AI thành scapegoat&lt;/li&gt;
&lt;li&gt;Remote hiring: hire Asia fraction of cost so với USA, AI thành PR-friendly excuse&lt;/li&gt;
&lt;li&gt;METR study: experienced engineers 19% less productive với AI tools cho real-world tasks&lt;/li&gt;
&lt;li&gt;AI là tool, không phải replacement - more code means more errors cần fix&lt;/li&gt;
&lt;li&gt;US Bureau of Labor: software developer jobs vẫn grow 15% (chậm hơn 22% prediction)&lt;/li&gt;
&lt;li&gt;SignalFire: Meta, Netflix, Uber, Google hire faster than people leaving&lt;/li&gt;
&lt;li&gt;What&amp;rsquo;s changing: skill bar - need engineering thinking, system design, performance, security&lt;/li&gt;
&lt;li&gt;Top languages 2026: Python (AI/ML), JavaScript/TypeScript (frontend/full-stack), Go (backend/infrastructure), Java (enterprise), Swift (iOS)&lt;/li&gt;
&lt;li&gt;New opportunities: AI engineering, AI infrastructure, data engineering, AI safety&lt;/li&gt;
&lt;li&gt;AI/ML jobs share tăng từ 10% đến 50% (2023-2025)&lt;/li&gt;
&lt;li&gt;Entry-level jobs giảm 40% so với pre-2022, CS graduates và bootcamp grads tăng&lt;/li&gt;
&lt;li&gt;Gartner: 80% engineering workforce cần upskill để keep pace với generative AI by 2027&lt;/li&gt;
&lt;li&gt;Median salary software engineer US 2026: $130,000&lt;/li&gt;
&lt;li&gt;Market maturing: harder to break in nhưng financial case vẫn strong&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bonus"&gt;Bonus
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Hình ảnh:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substackcdn.com/image/fetch/$s_!0P7Z!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7546f89c-8b6f-4ced-8d40-4e0137ab5941_2360x2852.png"
loading="lazy"
alt="12 Architectural Concepts Developers Should Know"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!Co3P!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7f3c175-c0d6-4d02-992d-114ac588b45c_2252x2752.png"
loading="lazy"
alt="Top Developer Tools You Can Use in 2026"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!Ty5s!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecc68f5e-6353-4487-a779-92bb11440bc5_2360x2960.png"
loading="lazy"
alt="5 Rate Limiting Strategies To Protect the System"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!dPjo!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2543392-5e04-4dd6-b39a-72fdfe3a3048_2360x2770.png"
loading="lazy"
alt="How Live Streaming Works?"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!MJUT!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06243bf8-f149-4075-bc81-99af15be3579_6001x7802.png"
loading="lazy"
alt="5 Leader Election Algorithms Powering Modern Databases"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!Xrbz!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c99d0d5-8e5b-4e82-bb28-9fbd470e3bc6_2250x2624.png"
loading="lazy"
alt="A Guide to Database Sharding"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!NCWv!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0adc9c84-37f2-4a96-96a6-f7f26bbd1b7e_2360x2960.jpeg"
loading="lazy"
alt="Modern Storage Systems"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #77</title><link>https://miti99.com/post/2026/01/24/</link><pubDate>Sat, 24 Jan 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/01/24/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #77.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="đừng-chuyển-tiếp-lỗi-hãy-thiết-kế-chúng"&gt;&lt;a class="link" href="https://fast.github.io/blog/stop-forwarding-errors-start-designing-them/" target="_blank" rel="noopener"
&gt;Đừng Chuyển Tiếp Lỗi, Hãy Thiết Kế Chúng&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích sâu về các vấn đề trong xử lý lỗi hiện nay, đặc biệt là trong hệ sinh thái Rust. Tác giả chỉ ra rằng chúng ta thường &amp;ldquo;chuyển tiếp&amp;rdquo; lỗi hơn là thực sự &amp;ldquo;thiết kế&amp;rdquo; chúng - bắt lỗi, bọc (đôi khi), và ném lên stack nhanh nhất có thể. Điều này dẫn đến việc lỗi vẫn giữ nguyên thông điệp gốc nhưng mất đi toàn bộ ngữ cảnh quan trọng.&lt;/p&gt;
&lt;p&gt;Bài viết phê phán các cách tiếp cận phổ biến như &lt;code&gt;thiserror&lt;/code&gt; (phân loại theo nguồn gốc chứ không phải hành động), &lt;code&gt;anyhow&lt;/code&gt; (quá tiện lợi khiến lập trình viên quên thêm ngữ cảnh), stack traces (tốn kém và chỉ hiện điểm xuất phát chứ không phải đường đi logic), và API Provide/Request (quá phức tạp với hành vi khó dự đoán). Thay vào đó, tác giả đề xuất xử lý lỗi nên được thiết kế với hai đối tượng: máy móc (cần cấu trúc phẳng, các loại rõ ràng, mã có thể dự đoán cho việc tự động phục hồi) và con người (cần ngữ cảnh phong phú, đường đi luồng, thông tin cấp độ kinh doanh để gỡ lỗi).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xử lý lỗi nên được thiết kế dựa trên ý định: &amp;ldquo;người gọi có thể làm gì với lỗi này?&amp;rdquo; thay vì &amp;ldquo;lỗi này đến từ đâu?&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Cho máy móc: sử dụng các loại lỗi phẳng dựa trên phân loại với trạng thái rõ ràng (Tạm thời/Liên tục/ persists) thay vì chuỗi lỗi lồng nhau&lt;/li&gt;
&lt;li&gt;Cho con người:捕获 ngữ cảnh tự động và thuận tiện, bắt buộc tại ranh giới module để không thể lười biếng&lt;/li&gt;
&lt;li&gt;Mô hình thực tế: kết hợp cấu trúc lỗi phân loại với cơ chế theo dõi ngữ cảnh (như thư viện &lt;code&gt;exn&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Sử dụng &lt;code&gt;#[track_caller]&lt;/code&gt; để捕获 vị trí với chi phí bằng không thay vì stack traces đắt đỏ&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="đồng-bộ-hóa-thời-gian-là-cơn-ác-mộng"&gt;&lt;a class="link" href="https://arpitbhayani.me/blogs/clock-sync-nightmare/" target="_blank" rel="noopener"
&gt;Đồng Bộ Hóa Thời Gian Là Cơn Ác Mộng&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Đồng hồ là một thứ tưởng đơn giản nhưng lại là cơn ác mộng của các kỹ sư phần mềm làm việc với hệ thống phân tán. Bài viết này giải thích tại sao không có &amp;ldquo;đồng hồ toàn cục&amp;rdquo; và cách hàng ngàn máy tính rải rác across nhiều data centers bị trôi drift apart theo thời gian. Mỗi máy tính có đồng hồ nội tại dựa trên crystal thạch anh với tần số 32768 Hz, nhưng những crystal này không hoàn hảo - sự chênh lệch nhiệt độ chỉ khoảng 10°C có thể gây ra trôi drift khoảng 110 giây mỗi năm. Kết quả là hai máy tính khởi động cùng thời gian sẽ bị lệch nhau hàng trăm mili-giây chỉ sau một ngày.&lt;/p&gt;
&lt;p&gt;Sự lệch đồng hồ gây ra nhiều vấn đề nghiêm trọng. Ví dụ với hệ thống make phân tán, nếu đồng hồ máy client bị chậm và đồng hồ máy server chạy nhanh, file object đã biên dịch sẽ trông mới hơn file source bạn vừa edit, khiến lệnh make không biên dịch lại và những thay đổi của bạn bị bỏ qua. Hệ thống cơ sở dữ liệu còn nghiêm trọng hơn - trong hệ thống ngân hàng, nếu giao dịch rút tiền có timestamp sớm hơn giao dịch nộp tiền do đồng hồ không đồng bộ, snapshot read có thể hiển thị giao dịch rút nhưng không hiển thị giao dịch nộp, khiến khách hàng trông như đã rút tiền họ không có. Tác giả cũng thảo luận các giải pháp: Thuật toán Cristian (ước lượng độ trễ một chiều bằng một nửa vòng đi vòng về), Thuật toán Berkeley (đồng thuận giữa các máy, tính trung bình và gửi các điều chỉnh tương đối thay vì thời gian tuyệt đối), NTP với hệ thống phân tầng phân cấp (Stratum 0 là đồng hồ nguyên tử/GPS, Stratum 1-15 là các lớp phía dưới), và PTP (Giao thức Thời Gián Chính Xác) với đánh dấu thời gian bằng phần cứng đạt độ chính xác dưới micro-giây.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clock skew = sự khác biệt giữa hai đồng hồ tại một thời điểm, Clock drift = tốc độ các đồng hồ phân kỳ theo thời gian&lt;/li&gt;
&lt;li&gt;NTP đạt độ chính xác 10-100ms trên internet công cộng, 100-500µs trên mạng LAN, nhưng bị giới hạn bởi sự bất đối xứng mạng&lt;/li&gt;
&lt;li&gt;PTP sử dụng đánh dấu thời gian bằng phần cứng tại tầng NIC để đạt độ chính xác nano-giây, nhưng cần các switch hỗ trợ PTP&lt;/li&gt;
&lt;li&gt;Đồng hồ logic (Lamport Timestamps, Vector Clocks)捕获 quan hệ nhân quả thay vì thời gian vật lý&lt;/li&gt;
&lt;li&gt;Google Spanner&amp;rsquo;s TrueTime sử dụng GPS + đồng hồ nguyên tử, trả về khoảng [sớm nhất, muộn nhất] thay vì timestamp đơn&lt;/li&gt;
&lt;li&gt;Đồng hồ logic lai (CockroachDB, YugabyteDB) kết hợp thời gian vật lý với thành phần logic&lt;/li&gt;
&lt;li&gt;Giây nhuận sẽ bị loại bỏ vào năm 2035, nhưng hiện tại Google/AWS dùng &amp;ldquo;kéo dài giây nhuận&amp;rdquo; để trải đều qua nhiều giờ&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="roadmap-học-java"&gt;&lt;a class="link" href="https://nemorize.com/roadmaps/java" target="_blank" rel="noopener"
&gt;Roadmap Học Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Đây là một lộ trình học Java toàn diện từ cơ bản đến nâng cao. Roadmap được chia thành năm phần chính: Nền tảng (Linux, Git, IDE), Lập trình hướng đối tượng (classes, objects, inheritance, polymorphism, encapsulation, abstraction), Java cốt lõi (Collections Framework, Exception Handling, Streams), Các khái niệm nâng cao (Concurrency &amp;amp; Multithreading, JVM internals, Design Patterns, Dependency Injection), và Phát triển chuyên nghiệp (Testing, Build Tools như Maven &amp;amp; Gradle, Databases), đặc biệt là Spring Boot Framework với REST APIs, Clean Code và SOLID principles.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bắt đầu với nền tảng: Linux basics, Git version control, và chọn IDE phù hợp (IntelliJ, Eclipse, VSCode)&lt;/li&gt;
&lt;li&gt;Nắm vững OOP fundamentals: classes, objects, inheritance, polymorphism, encapsulation, abstraction&lt;/li&gt;
&lt;li&gt;Thành thạo Collections Framework: Lists, Sets, Maps, Queues, Optionals, Streams&lt;/li&gt;
&lt;li&gt;Hiểu sâu về Exception Handling: checked vs unchecked exceptions, custom exceptions&lt;/li&gt;
&lt;li&gt;Học Concurrency &amp;amp; Multithreading: thread basics, concurrent collections, ExecutorService, thread pools&lt;/li&gt;
&lt;li&gt;Tìm hiểu JVM internals và Design patterns phổ biến&lt;/li&gt;
&lt;li&gt;Làm việc với build tools (Maven, Gradle) và databases (JDBC, schema migration)&lt;/li&gt;
&lt;li&gt;Phát triển Enterprise Java với Spring Boot: Spring Core, Spring Data, JPA, REST APIs&lt;/li&gt;
&lt;li&gt;Áp dụng Clean Code, SOLID principles, và best practices về API design, logging, monitoring&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="hướng-dẫn-toàn-diện-triển-khai-kotlin-trong-môi-trường-java"&gt;&lt;a class="link" href="https://blog.jetbrains.com/kotlin/2025/12/the-ultimate-guide-to-successfully-adopting-kotlin-in-a-java-dominated-environment/" target="_blank" rel="noopener"
&gt;Hướng Dẫn Toàn Diện Triển Khai Kotlin Trong Môi Trường Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Đây là hướng dẫn hoàn chỉnh để triển khai Kotlin từng bước, từ những bài kiểm tra ban đầu đến triển khai quy mô lớn. Adopting Kotlin trong công ty thiên về Java không phải là flipping a switch hay viết lại mọi thứ, mà là về con người, thời điểm, rủi ro và sự tin tưởng. Guide bao gồm năm phần: Bắt đầu với Kotlin cho Java developers (viết tests bằng Kotlin, dùng Kotest và MockK), Đánh giá Kotlin trong projects thực tế (start new service in Kotlin, add Kotlin modules, tránh &amp;ldquo;Java in Kotlin syntax&amp;rdquo; trap), Phát triển việc adoption Kotlin trong công ty (share examples, starter repository, pairing sessions, build community), Giúp decision-makers nói yes với Kotlin (less code, fewer defects, no rewriting, developer happiness, predictable costs), và Scaling adoption across organization (treat systems differently based on lifecycle, dùng right tools như IDE conversion, null-safety annotations, AI-assisted refactoring).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bắt đầu nhỏ: introduce Kotlin thông qua test suite để không ảnh hưởng production&lt;/li&gt;
&lt;li&gt;Tránh &amp;ldquo;Java in Kotlin syntax&amp;rdquo; trap: dùng extension functions thay vì static helpers, nullable types thay vì Optional, data classes thay vì boilerplate&lt;/li&gt;
&lt;li&gt;Xây dựng community trong nội bộ: share starter repository, tổ chức clinics và pairing sessions&lt;/li&gt;
&lt;li&gt;Thuyết phục managers: less code để maintain, fewer defects nhờ null safety, no rewriting required nhờ full Java interop&lt;/li&gt;
&lt;li&gt;Scaling strategy: leave end-of-life apps, default new builds to Kotlin, migrate active systems step-by-step không phải big-bang rewrites&lt;/li&gt;
&lt;li&gt;Sử dụng tools phù hợp: IDE conversion, JSpecify null-safety annotations, AI-assisted refactoring, rule-based automation&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="so-sánh-rust-và-go-năm-2026"&gt;&lt;a class="link" href="https://bitfieldconsulting.com/posts/rust-vs-go" target="_blank" rel="noopener"
&gt;So Sánh Rust và Go Năm 2026&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này so sánh hai ngôn ngữ lập trình phổ biến Rust và Go across nhiều khía cạnh: performance, simplicity, safety, features, scale, concurrency. Tóm tắt ngắn gọn: &amp;ldquo;Rust for high stakes, Go for low costs&amp;rdquo; - Rust cho mission-critical software cần safety và reliability, Go cho việc move fast và keep costs down. Cả hai đều là compiled languages với fast, compact executables, đều có pragmatic programming style và excellent tooling cho development at scale (gofmt, rustfmt, standard build tools). Tuy nhiên, Rust prioritizes safety, correctness, efficiency với borrow checker preventing memory errors, trong khi Go prioritizes simplicity và speed of development với garbage collector và minimal syntax. Go có goroutines và channels làm concurrency cực kỳ easy, Rust có match syntax và powerful features nhưng learning curve steeper. Error handling: Go dùng explicit &lt;code&gt;if err != nil&lt;/code&gt;, Rust dùng &lt;code&gt;Option&lt;/code&gt;/&lt;code&gt;Result&lt;/code&gt; types với &lt;code&gt;?&lt;/code&gt; operator.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Performance: Rust beat Go ở run-time benchmarks nhờ no garbage collection và closer to metal optimizations&lt;/li&gt;
&lt;li&gt;Simplicity: Go cực kỳ easy to learn (productive sau 2 days), Rust có nhiều features hơn và learning curve steeper&lt;/li&gt;
&lt;li&gt;Concurrency: Go nổi tiếng với goroutines và channels cho high-scale concurrent apps, Rust có rayon crate và memory safety cho concurrency&lt;/li&gt;
&lt;li&gt;Safety: Rust&amp;rsquo;s borrow checker prevents memory safety bugs tại compile time, Go relies trên programmer discipline&lt;/li&gt;
&lt;li&gt;Scale: Go tốt cho big organisations với distributed teams nhờ uniform style và fast build times&lt;/li&gt;
&lt;li&gt;Garbage collection: Go has GC (simpler nhưng unpredictable pauses), Rust manual memory management (harder nhưng predictable)&lt;/li&gt;
&lt;li&gt;Error handling: Go explicit &lt;code&gt;if err != nil&lt;/code&gt;, Rust powerful &lt;code&gt;Option&lt;/code&gt;/&lt;code&gt;Result&lt;/code&gt; với &lt;code&gt;?&lt;/code&gt; operator&lt;/li&gt;
&lt;li&gt;Conclusion: &amp;ldquo;Should I learn Rust or Go?&amp;rdquo; → &amp;ldquo;Yes&amp;rdquo; - learn both, mỗi ngôn ngữ excels trong domain của nó&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="dependency-phổ-biến-nhất-trong-go-là-gì"&gt;&lt;a class="link" href="https://blog.thibaut-rousseau.com/blog/the-most-popular-go-dependency-is/" target="_blank" rel="noopener"
&gt;Dependency Phổ Biến Nhất Trong Go Là Gì?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trả lời câu hỏi về dependency phổ biến nhất trong hệ sinh thái Go thông qua việc phân tích toàn bộ Go modules ecosystem. Tác giả đã download toàn bộ index từ proxy.golang.org (từ 2019), build một dependency graph với 40 triệu nodes và 400 triệu relationships trong Neo4j database, từ đó extract ra các thống kê thú vị. Top 10 dependencies được sử dụng nhiều nhất: testify (259,237 dependents), google/uuid (104,877), golang.org/x/crypto (100,633), grpc (97,228), cobra (93,062), pkg/errors (92,491), golang.org/x/net (76,722), protobuf (74,971), logrus (71,730), viper (64,174). Testify là library được sử dụng rộng rãi nhất, đặc biệt là cho testing. Tác giả cũng demo cách query Neo4j để find direct/transitive dependents, ví dụ như &lt;a class="link" href="mailto:github.com/pkg/errors@v0.9.1" &gt;github.com/pkg/errors@v0.9.1&lt;/a&gt; vẫn có 16,001 dependents trong năm 2025 dù đã bị deprecated từ lâu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go modules có trung bình 10 direct dependencies&lt;/li&gt;
&lt;li&gt;Testify (github.com/stretchr/testify) là dependency phổ biến nhất với 259,237 dependents&lt;/li&gt;
&lt;li&gt;Top dependencies bao gồm testing frameworks (testify), utilities (uuid, crypto, net), CLI tools (cobra, viper), logging (logrus)&lt;/li&gt;
&lt;li&gt;Extended stdlib (golang.org/x/) giữ vị trí mạnh trong ecosystem&lt;/li&gt;
&lt;li&gt;Các deprecated libraries như pkg/errors vẫn được sử dụng rộng rãi (92,491 dependents)&lt;/li&gt;
&lt;li&gt;Neo4j graph database非常适合 analyzing dependency relationships với Cypher query language&lt;/li&gt;
&lt;li&gt;Tác giả chia sẻ Neo4j dump via BitTorrent để community có thể chạy own queries&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="gosum-không-phải-lockfile"&gt;&lt;a class="link" href="https://words.filippo.io/gosum/" target="_blank" rel="noopener"
&gt;go.sum Không Phải Lockfile&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này làm rõ sự hiểu lầm phổ biến về go.sum trong Go modules. Nhiều người nghĩ go.sum là lockfile (như package-lock.json của Node hay Cargo.lock của Rust), nhưng thực tế go.sum chỉ là bộ nhớ đệm cục bộ cho Go Checksum Database - một ánh xạ từ các phiên bản module đến các mã băm mật mã của chúng. Những phiên bản này có thể được sử dụng hoặc không, không ảnh hưởng đến việc phân giải gói. go.sum thậm chí không được bật theo mặc định trong thiết kế modules ban đầu vì không có tác động quan sát được trên quá trình xây dựng! Mục đích duy nhất của nó là tăng cường câu chuyện bảo mật: Checksum Database đảm bảo toàn bộ hệ sinh thái chia sẻ cùng một nội dung cho một phiên bản module, bất kể cách tải xuống, và go.sum làm cho lời đảm bảo đó trở nên cục bộ và tự chứa.&lt;/p&gt;
&lt;p&gt;Thay vào đó, hãy nhìn vào go.mod - nó đóng vai trò既是 manifest又是 lockfile. Từ Go 1.17 (tháng 8 năm 2021), go.mod bao gồm tất cả các phụ thuộc chuyển tiếp cần thiết để xây dựng module chính và các bài kiểm tra của nó. Khác với các hệ sinh thái khác với manifest (các phạm vi phiên bản phức tạp) và lockfile (các phiên bản thực tế), Go đơn giản hơn với một tệp có thể đọc được bởi con người: go.mod liệt kê tất cả các phụ thuộc (trực tiếp và chuyển tiếp) và phiên bản chính xác của chúng. Không có xung đột phụ thuộc hình kim cương, không có cách nào vô tình sử dụng tính năng được giới thiệu trong phiên bản mà các phần phụ thuộc sẽ không có, và không có cập nhật tự động lên phiên bản mới nhất của các phụ thuộc khi thêm phụ thuộc mới.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;go.sum không phải lockfile, chỉ là bộ nhớ đệm cục bộ cho Go Checksum Database với các mã băm mật mã&lt;/li&gt;
&lt;li&gt;go.mod đóng vai trò既是 manifest又是 lockfile - liệt kê tất cả các phụ thuộc và phiên bản chính xác&lt;/li&gt;
&lt;li&gt;Từ Go 1.17, go.mod bao gồm tất cả các phụ thuộc chuyển tiếp cho module chính và bài kiểm tra&lt;/li&gt;
&lt;li&gt;Go modules đơn giản hơn nhiều so với các lựa chọn thay thế: không có phạm vi phiên bản, không có xung đột hình kim cương, không có vấn đề đồng bộ hóa lockfile&lt;/li&gt;
&lt;li&gt;Việc phân giải gói trong Go là tức thời nên không ai nhận thấy nó đang xảy ra&lt;/li&gt;
&lt;li&gt;Phân tích go.mod bằng golang.org/x/mod/modfile hoặc &lt;code&gt;go mod edit -json&lt;/code&gt;, không bao giờ phân tích go.sum&lt;/li&gt;
&lt;li&gt;Để phân tích đồ thị phụ thuộc, dùng go.mod, không phải go.sum&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="phát-triển-thông-báo-actions-cho-forgejo"&gt;&lt;a class="link" href="https://chris-besch.com/articles/forgejo_actions_notification/" target="_blank" rel="noopener"
&gt;Phát Triển Thông Báo Actions Cho Forgejo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này chia sẻ kinh nghiệm đóng góp vào Forgejo - một mã nguồn tự chủ tương tự GitHub/GitLab. Tác giả cần tính năng gửi thông báo email và webhook khi CI workflow thất bại, nhưng Forgejo chưa có, nên ông ấy quyết định đóng góp. Bài viết giải thích chi tiết cấu trúc dự án Go, kiến trúc phân lớp của Forgejo, và mô hình publish-subscribe (pub-sub) được sử dụng để tránh các phụ thuộc vòng tròn. Tác giả chia quá trình thành nhiều pull requests: PR #7510 tái cấu trúc code từ layer thấp lên layer cao, PR #7491 thêm topic &lt;code&gt;ActionRunNowDone&lt;/code&gt; vào pub-sub system, PR #7509 triển khai gửi email khi workflow thất bại/phục hồi, và PR #7508 triển khai gửi webhook. Bài viết cũng hướng dẫn chi tiết cách thiết lập môi trường phát triển: Forgejo instance, Forgejo runner, mail server (MailDev), webhook tester, và cách chạy tests với Delve debugger.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go projects sử dụng modules (với go.mod) và packages (nhóm code), với hệ thống phân tán không có central package index như NPM&lt;/li&gt;
&lt;li&gt;Forgejo dùng kiến trúc phân lớp 3 tầng: modules (tự chứa, có thể dùng như library), models (database abstraction), services (logic), routers (API/web UI) - code ở layer thấp không được import code ở layer cao&lt;/li&gt;
&lt;li&gt;Pub-sub pattern giải quyết cyclic dependencies: packages gửi messages đến topics (ví dụ &lt;code&gt;PullRequestReview&lt;/code&gt;), và các packages khác subscribe vào topics đó&lt;/li&gt;
&lt;li&gt;Tác giả chia feature thành 4 PRs để dễ review: refactoring, thêm topic, triển khai email, triển khai webhook&lt;/li&gt;
&lt;li&gt;Development setup cần Forgejo instance, runner, mail server (MailDev), webhook tester node script&lt;/li&gt;
&lt;li&gt;Debug với Delve debugger, chạy unit tests và integration tests với make commands&lt;/li&gt;
&lt;li&gt;Viết tests rất quan trọng để maintainers có thể verify code vẫn hoạt động đúng&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bonus"&gt;Bonus
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Hình ảnh:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substackcdn.com/image/fetch/w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ec94ed4-46b2-40bd-8d28-a25fdde639c8_2250x2624.png"
loading="lazy"
alt="Message Brokers 101"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!hXRV!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe99863c7-7ab7-4f61-9961-af7e4c6ee64f.png"
loading="lazy"
alt="Cloud Load Balancer Cheat Sheet"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!XvtW!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ded3402-4eb5-4818-861f-7661f1cefe82.tif"
loading="lazy"
alt="How CQRS Works?"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!SUjA!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd91a5538-a69e-468c-bf83-058bb78753ca_2360x2770.png"
loading="lazy"
alt="How does Docker Work?"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!4qBZ!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0945414-9cea-4e64-8dd4-3abcc404f73e_2360x2960.png"
loading="lazy"
alt="Containerization Explained: From Build to Runtime"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!n8BK!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa51a75cc-09a9-4fed-af8a-c32a64f8ab60_2250x2624.png"
loading="lazy"
alt="Must-Know Message Broker Patterns"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #76</title><link>https://miti99.com/post/2026/01/05/</link><pubDate>Mon, 05 Jan 2026 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2026/01/05/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #76.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="tcp-vs-udp-vs-grpc-chọn-giao-thức-phù-hợp-cho-kiến-trúc-của-bạn"&gt;&lt;a class="link" href="https://designgurus.substack.com/p/an-engineers-guide-to-basic-networking" target="_blank" rel="noopener"
&gt;TCP vs. UDP vs. gRPC: Chọn giao thức phù hợp cho kiến trúc của bạn&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Khi viết mã, dữ liệu di chuyển trong bộ nhớ của một máy tính. Nhưng phần mềm hiện đại hiếm khi hoạt động độc lập - mã cần giao tiếp với cơ sở dữ liệu, API, hoặc trình duyệt của người dùng ở nửa bên kia thế giới. Điều này tạo ra thách thức kỹ thuật lớn: làm sao đảm bảo dữ liệu đến đích chính xác và đầy đủ.&lt;/p&gt;
&lt;p&gt;Bài viết này giải thích cách các giao thức mạng hoạt động &amp;ldquo;phía sau hậu trường&amp;rdquo; của internet, tập trung vào các giao thức quan trọng nhất mà kỹ sư phần mềm cần hiểu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TCP (Transmission Control Protocol)&lt;/strong&gt; là giao thức vận chuyển phổ biến nhất trên internet, ưu tiên độ tin cậy. TCP đảm bảo người nhận nhận được mọi byte, theo đúng thứ tự, và tự động gửi lại nếu gói tin bị mất. Trước khi truyền dữ liệu, TCP thực hiện &amp;ldquo;bắt tay ba bước&amp;rdquo; để thiết lập kết nối: máy khách gửi SYN, máy chủ trả lời SYN-ACK, và máy khách gửi ACK. TCP cũng có kiểm soát luồng và kiểm soát tắc nghẽn để tránh quá tải người nhận. Dùng TCP khi độ chính xác quan trọng hơn tốc độ: truy vấn cơ sở dữ liệu, email, trang web.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UDP (User Datagram Protocol)&lt;/strong&gt; ngược lại - là &amp;ldquo;giao thức không kết nối&amp;rdquo;, ưu tiên tốc độ và hiệu quả hơn độ tin cậy. UDP không bắt tay, không theo dõi thứ tự gói tin, không kiểm tra xem dữ liệu đến an toàn không. Người gửi gửi gói dữ liệu ngay lập tức, và nếu gói tin bị loại bỏ, nó mất luôn. Dùng UDP khi tốc độ là quan trọng và chấp nhận mất một chút dữ liệu: phát trực tuyến video, trò chơi trực tuyến. Thả một khung hình video tốt hơn là dừng video chờ khung cũ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HTTP&lt;/strong&gt; là giao thức chuẩn cho web, hoạt động theo mô hình Yêu cầu-Phản hồi. Máy khách gửi yêu cầu với phương thức (GET, POST, PUT, DELETE), siêu dữ liệu headers, và máy chủ trả về mã trạng thái (200 OK, 404 Not Found). Phiên bản HTTP quan trọng:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP/1.1: xử lý một yêu cầu tại một thời điểm, có thể gây &amp;ldquo;tắc nghẽn đầu hàng&amp;rdquo;&lt;/li&gt;
&lt;li&gt;HTTP/2: giới thiệu đa truyền, cho phép nhiều yêu cầu/phản hồi đồng thời qua một kết nối TCP&lt;/li&gt;
&lt;li&gt;HTTP/3: mới nhất, bỏ TCP hoàn toàn, chạy trên QUIC (dựa trên UDP), giải quyết tắc nghẽn kết nối để web nhanh hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;WebSocket&lt;/strong&gt; giải quyết vấn đề của HTTP: HTTP một chiều, máy khách luôn phải bắt đầu cuộc trò chuyện. WebSocket cung cấp kênh truyền thông hai chiều song song. Kết nối bắt đầu như yêu cầu HTTP với header &amp;ldquo;nâng cấp&amp;rdquo;, sau đó chuyển giao thức. Khi được thiết lập, kết nối giữ mở, cả máy khách và máy chủ đều có thể gửi dữ liệu bất cứ lúc nào mà không cần gửi headers mỗi tin nhắn. Dùng WebSocket khi cần độ trễ thấp, truyền thông hai chiều: ứng dụng chat, cập nhật chứng khoán.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TCP đảm bảo độ tin cậy với bắt tay ba bước và kiểm soát luồng, dùng cho cơ sở dữ liệu, email&lt;/li&gt;
&lt;li&gt;UDP ưu tiên tốc độ, chấp nhận mất dữ liệu, dùng cho phát trực tuyến video, trò chơi&lt;/li&gt;
&lt;li&gt;HTTP/3 chạy trên QUIC/UDP để giải quyết vấn đề tắc nghẽn, nhanh hơn HTTP/1.1&lt;/li&gt;
&lt;li&gt;WebSocket giữ kết nối liên tục cho truyền thông hai chiều thời gian thực&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="kỹ-thuật-phần-mềm-năm-2026"&gt;&lt;a class="link" href="https://benjamincongdon.me/blog/2025/12/29/Software-Engineering-in-2026/" target="_blank" rel="noopener"
&gt;Kỹ thuật phần mềm năm 2026&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Sau năm 2025 với sự tiến bộ mạnh mẽ của công cụ lập trình AI, tác giả suy nghĩ về tác động của việc này cho năm 2026. Tác động chính của công cụ LLM là chi phí cận biên (thời gian và tiền bạc) để tạo ra mã chất lượng cao đã giảm đáng kể. Nhưng tạo ra mã chỉ là một phần của kỹ thuật phần mềm, nên các nút thắt cổ chai sẽ chuyển sang các lĩnh vực khác.&lt;/p&gt;
&lt;p&gt;Kỹ thuật phần mềm có 3 thành phần: xây dựng, phát triển, và vận hành hệ thống phần mềm phân tán. Xây dựng đã trở nên rẻ hơn với LLM, phát triển cũng dễ dàng hơn, nhưng vận hành bị ảnh hưởng ít nhất. Thị trường sẽ kỳ vọng kỹ sư phần mềm tận dụng lợi suất từ LLM, và lĩnh vực sẽ trở nên cơ khí hóa hơn nhưng năng suất hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trừu tượng hóa hạ tầng&lt;/strong&gt;: Lợi suất từ các trừu tượng hóa hạ tầng tốt cộng nhanh hơn. Các mảnh hạ tầng cốt lõi vẫn quan trọng: chỉ số, ghi nhật ký, quản lý sự cố, tính năng gắn cờ, phát hành, tự động mở rộng, điều phối, quy trình công việc, cấu hình, lưu trữ đệm, mạng. Các công ty nên làm cho các mảnh hạ tầng dễ dùng cho cả con người và LLM, với tự phục vụ, giao diện dòng lệnh thân thiện hoặc API sẵn sàng cho MCP, và tối thiểu sự can thiệp của kỹ sư hạ tầng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hạ tầng tích hợp liên tục&lt;/strong&gt;: Chất lượng, độ trung thực và tốc độ của hạ tầng CI trở nên quan trọng hơn khi tác nhân AI viết nhiều mã hơn. Có thể cần suy nghĩ lại kiểm thử đơn vị và đầu tư nhiều hơn vào kiểm thử thuộc tính và xác nhận hình thức. Con người không thích viết kiểm thử, nhưng LLM không có vấn đề này. Không có lý do cho việc không có độ phủ kịch bản kiểm thử gần như đầy đủ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trừu tượng hóa do con người hướng dẫn&lt;/strong&gt;: Các trừu tượng hóa do con người hướng dẫn rõ ràng trở nên quan trọng hơn. LLM không có hướng dẫn mạnh sẽ điền lỏng lẻo các giải pháp tham lam để vượt qua CI, tăng sự rối rắm theo thời gian. Trực giác được thông báo tốt và &amp;ldquo;gu hệ thống&amp;rdquo; vẫn cần thiết ngay từ đầu: ranh giới mô-đun, giao diện thư viện, hợp đồng giữa lớp hạ tầng và sản phẩm trở nên đòn bẩy cao để duy trì chất lượng mã dài hạn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Xem xét mã bởi con người&lt;/strong&gt;: Xem xét mã bởi con người ngày càng trở thành nút thắt quan trọng. Cần phát triển &amp;ldquo;gu xem xét&amp;rdquo; mới. Mối quan tâm về kiểu cách nên đẩy vào kiểm tra tự động trước khi gửi. Xem xét mã bởi con người nên tập trung vào các quyết định không thể được tạo mã sau này: thay đổi giao diện, mã nhạy cảm liên quan đến lưu trữ dữ liệu, mã quan trọng về hiệu suất. Đây là nghịch lý cho kỹ sư trẻ: họ cần phát triển &amp;ldquo;gu xem xét&amp;rdquo; sớm hơn, nhưng lại làm ít &amp;ldquo;viết&amp;rdquo; hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thời gian dự án&lt;/strong&gt;: Phương sai trên ước tính dự án tăng lên đáng kể. Mức độ mà tác vụ có thể được LLM hóa ngày càng ảnh hưởng chi phí thời gian thực. Một số tác vụ trở nên dễ dàng hơn (di cư tập trung vào mã, dịch giữa ngôn ngữ/hệ thống), một số tác vụ vẫn ổn định về độ khó (mạng).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tự xây dựng hay mua lại&lt;/strong&gt;: Giá giảm của mã có ảnh hưởng quyết định tự xây dựng hay mua không? Tác giả đoán là trên biên độ là &amp;ldquo;có&amp;rdquo;, nhưng theo cách lớn là &amp;ldquo;không&amp;rdquo;. Với SaaS hàng hóa (giao diện mỏng trên CRUD), phép tính tự xây dựng hay mua sẽ chuyển sang xây dựng với các công ty công nghệ vừa và lớn có bộ phận IT có năng lực. Với hạ tầng như dịch vụ hoặc tuân thủ như dịch vụ, phép tính sẽ không chuyển nhiều vì chi phí vận hành cho hệ thống nội bộ không giảm như chi phí phát triển.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trừu tượng hóa hạ tầng và chất lượng CI trở nên quan trọng hơn với mã được tạo bởi AI&lt;/li&gt;
&lt;li&gt;Trừu tượng hóa do con người hướng dẫn và xem xét mã trở thành nút thắt mới&lt;/li&gt;
&lt;li&gt;Ước tính thời gian dự án có phương sai cao hơn do khả năng LLM hóa&lt;/li&gt;
&lt;li&gt;Phép tính tự xây dựng hay mua chuyển nhẹ với SaaS hàng hóa nhưng không nhiều với hạ tầng như dịch vụ&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="suy-ngẫm-về-năm-2025"&gt;&lt;a class="link" href="https://samuelalbanie.substack.com/p/reflections-on-2025" target="_blank" rel="noopener"
&gt;Suy ngẫm về năm 2025&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả suy ngẫm về năm 2025 với ba chủ đề chính: Thuyết tính toán của mọi thứ, Đánh giá mở rộng quy mô, và Floreat Britannia (tương lai của Anh).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thuyết tính toán của mọi thứ&lt;/strong&gt;: Tác giả đã bị &amp;ldquo;sốc&amp;rdquo; khi lĩnh vực thị giác máy tính của ông bị cán bằng mở rộng quy mô vào đầu năm 2021. Những thiên kiến kiến trúc thủ công, riêng lẻ mà ông dành nhiều tháng để tạo ra tại Oxford VGG đã bị xóa sổ bởi một hệ thống đơn giản mở rộng quy mô tính toán huấn luyện trước. Ông đi quanh Công viên Đại học trong trạng thái sốc một buổi chiều, và khi ra đến lối ra, cú sốc đã được thay thế bởi sự nhiệt tình phiền phức của một người cải đạo.&lt;/p&gt;
&lt;p&gt;Hans Moravec viết &amp;ldquo;Vai trò của sức mạnh thô trong trí thông minh&amp;rdquo; năm 1976, một bài viết như quả lựu đạn đang kh clearing cổ họng và thông báo cho toàn bộ lĩnh vực AI rằng quần của họ đang bị tụt. Luận điểm trung tâm của Moravec: trí thông minh không phải là thuộc tính huyền bí của thao tác ký hiệu, mà là câu chuyện về sức mạnh xử lý. Ngạn ngữ hàng không nổi tiếng của ông: &amp;ldquo;Với đủ sức mạnh, bất cứ thứ gì cũng sẽ bay.&amp;rdquo; Trước anh em Wright, các kỹ sư xây dựng máy bay cánh vỗ trông sang trọng nhưng vẫn ở dưới mặt đất. Giải pháp là lắp động cơ khổng lồ vào ván và ép các định luật vật lý phục tùng bằng sức mạnh thô.&lt;/p&gt;
&lt;p&gt;Bài viết cập nhật năm 1998 của Moravec mở đầu với câu đã già như rượu vang: &amp;ldquo;Hiệu suất của máy AI có xu hướng cải thiện cùng nhịp tốc độ mà các nhà nghiên cứu AI tiếp cận phần cứng nhanh hơn.&amp;rdquo; Tác giả lập luận rằng nếu phần cứng dự kiến đưa vào hoạt động trong vài năm tới khiến các cụm máy của năm 2025 trông như máy tính bỏ túi, và nếu Moravec đúng (đánh cược chống lại ông trong lịch sử = cách tuyệt vời để bỏ lỡ các xu hướng AI lớn), thì chúng ta không đang tiếp cận cao nguyên. Con bạch tuộc đã xong bình. Nó hiện đang mở bể cá.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Đánh giá mở rộng quy mô&lt;/strong&gt; (hoặc: cách chấm bài tập về nhà của một vị thần nhỏ): Tác giả từng là phó giáo sư chấm bài tập lúc 2 giờ sáng, và học được rằng viết bảng tiêu chuẩn là bài tập về sự kiêu ngạo. Sinh viên thường tìm ra giải pháp bằng phương pháp được tiết lộ trong cơn sốt, và bảng tiêu chuẩn đứng revealed như đài tưởng niệm thiếu sự dự đoán. Câu trả lời sai nhanh để xử lý, nhưng câu trả lời đúng mới lạ là hành vi bạo lực - buộc người chấm phải dừng dây chuyền lắp ráp và thực sự suy nghĩ.&lt;/p&gt;
&lt;p&gt;Bây giờ tác giả làm việc trên AI &amp;ldquo;đánh giá&amp;rdquo;. Công việc thực sự giống nhau, ngoại trừ sinh viên đã đọc toàn bộ internet, ảo giác với sự tự tin của tư vấn cấp trung, và người chấm không thể trừ điểm cho chữ viết xấu. Vấn đề: chúng ta đang xây dựng các hệ thống showing dấu hiệu sớm của tính tổng quát, nhưng công cụ đánh giá phải cụ thể hẹp. Chúng ta đang xây dựng con dao đa dụng Thụy Sĩ phổ quát, nhưng chỉ có thể kiểm tra bằng cách hỏi &amp;ldquo;Có, nhưng liệu nó có thể mở chai Pinot Grigio ấm này không?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Một dự án cố gắng rửa tiền thống kê thuần túy: giả sử hệ số G cho AI, có các mô hình AI tham dự tất cả các kỳ thi, áp dụng đại số tuyến tính, IQ score ra. Đường cong đã phát triển khát vọng dọc đột ngột. Cách tiếp cận của METR từ chối định nghĩa &amp;ldquo;trí thông minh&amp;rdquo; (bẫy cho các nhà triết học bất cẩn), thay vào đó tập trung vào &amp;ldquo;thời lượng&amp;rdquo;. Thời lượng tác vụ được đo bằng cách neo vào thời gian thực hiện bởi con người có kỹ năng. Đầu năm 2024: thời gian thành công 50% của mô hình tốt nhất khoảng 5 phút. Cuối năm 2025: với Claude Opus 4.5, đường ngồi ở 4 giờ 49 phút (khoảng tin cậy rộng).&lt;/p&gt;
&lt;p&gt;Thách thức lớn cũ là khiến thứ hoạt động (phân biệt số 8 viết tay khỏi số 3 uốn cong trong MNIST). Vấn đề mang lại - cát đang suy nghĩ. Nhưng phần thưởng cho thành công là sự tăng trừng phạt về phạm vi. Diện tích bề mặt của đánh giá cần thiết đã bùng nổ từ phân loại chữ số đến thực tế lộn xộn của điều kiện con người, toàn bộ nền kinh tế toàn cầu, và phát triển của chính AI. Chúng ta hiện phải chứng nhận đa tài toàn năng trên chương trình học bao gồm mọi thứ từ ngoại giao đến cách dùng đúng dấu phẩy Oxford.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Floreat Britannia&lt;/strong&gt;: Tác giả lập luận Anh có cơ hội đấu tranh để thu hoạch lợi ích từ chuyển đổi AI. Vấn đề không phải chúng ta quên cách đổ bê tông. Những gì chúng ta thiếu là khả năng phối hợp nguồn lực mà không thành lập ủy ban để nghiên cứu khả thi của một ủy ban. Thu nhập thực tăng 33% mỗi thập kỷ 1970-2007. Kể từ năm 2007: gần như không có gì - sự đình trì tiền lương dài nhất kể từ các cuộc chiến tranh Napoleon. Nếu Anh tiếp tục theo quỹ đạo trước năm 2008, chúng ta hiện sẽ giàu thêm 16.000 bảng mỗi người mỗi năm. Giá điện công nghiệp cao nhất Châu Âu. Trạm điện hạt nhân Hinkley Point C sẽ tốn 46 tỷ bảng - trạm điện đắt nhất từng được xây dựng. Hàn Quốc xây dựng tương đương với một phần tư chi phí.&lt;/p&gt;
&lt;p&gt;Các biện pháp bảo vệ cá của Hinkley tốn khoảng 700 triệu bảng, bao gồm &amp;ldquo;hệ thống ngăn cá âm nhạc disco cá&amp;rdquo;. Dựa trên mô hình hóa của nhà phát triển, điều này dự kiến sẽ cứu 0,083 cá hồi Đại Tây Dương mỗi năm. Với 700 triệu bảng, định giá một con cá hồi khoảng 140 triệu bảng - 700 lần trọng lượng của con cá trong cocaine.&lt;/p&gt;
&lt;p&gt;Tác giả tin vào ra quyết định được hỗ trợ bởi AI thông qua dự báo AI tốt hơn và phối tích được bật bởi AI. Nếu tiến bộ AI tiếp tục, chi phí tạo ra ước tính xác suất chất lượng cao sắp giảm đáng kể. Chúng ta có thể chuyển từ thế giới nơi dự báo nghiêm ngặt là hàng hóa xa xỉ (quỹ đầu cơ, nhà khí tượng học, Dave cá cược trên ngựa) sang một nơi có thể tiếp cận rộng rãi. Nhưng dự báo trung thực cao là vô dụng nếu văn hóa coi &amp;lsquo;chân thành&amp;rsquo; như vi phạm quy tắc ứng xử.&lt;/p&gt;
&lt;p&gt;Tác giả ngưỡng mộ tinh thần Mỹ của Ben Franklin - sự can đảm thực tế, &amp;ldquo;Cuộc sống, Tự do và sự theo đuổi Hạnh phúc&amp;rdquo; được hiệu chỉnh để phát minh ra tương lai. Hy vọng là Anh ngừng xem bản năng này như vi phạm tuân thủ và nhớ rằng chúng ta đã phát minh ra động cơ hơi nước trước bảng tạm. Franklin không nhầm lẫn sự can đảm với phóng hỏa - ông thực tế tôn trọng sức mạnh thô của điện và phát minh ra避雷针. Thuyết tính toán của mọi thứ là toàn cầu, nhưng để thịnh vượng chúng ta sẽ cần cả diều và gậy. Không thể bắt tia chớp trong nghiên cứu khả thi. Bão đang đỉnh horizon, tia lửa chỉ ủng hộ các quốc gia đang giữ dây diều lo âu trong mưa.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thuyết tính toán của mọi thứ: hiệu suất AI cải thiện với quyền truy cập phần cứng nhanh hơn - lịch sử xác nhận dự đoán của Moravec&lt;/li&gt;
&lt;li&gt;Đánh giá mở rộng quy mô: đo lường các hệ thống AI tổng quát là &amp;ldquo;chấm bài tập về nhà của vị thần nhỏ&amp;rdquo; - chương học mở rộng bao gồm mọi thứ&lt;/li&gt;
&lt;li&gt;Tương lai của Anh: ra quyết định được hỗ trợ bởi AI có thể giúp phối hợp nguồn lực và khơi lại tăng trưởng, nhưng cần cả sự can đảm (diều) và thận trọng (gậy)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="8-dự-đoán-cho-năm-2026-điều-gì-tiếp-theo-trong-ai"&gt;&lt;a class="link" href="https://www.philschmid.de/2026-predictions" target="_blank" rel="noopener"
&gt;8 dự đoán cho năm 2026. Điều gì tiếp theo trong AI?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả thường không đưa ra dự đoán, nhưng năm 2025 là năm quan trọng như vậy cho AI và bản thân ông rằng ông cảm thấy buộc phải nhìn về phía trước. Dưới đây là 8 dự đoán cho năm 2026:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Generative UI cất cánh&lt;/strong&gt;: Độ trễ và hiệu suất cho tạo mã cho phép các ứng dụng tạo giao diện theo thời gian thực cho các tác vụ và sở thích cụ thể của người dùng. Các ứng dụng sẽ tạo UI động dựa trên nhu cầu cụ thể của người dùng thay vì giao diện được tạo trước tĩnh.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Edge trở thành nhà chính cho Tác nhân Cá nhân&lt;/strong&gt;: Tác nhân cá nhân di chuyển sang edge-đầu tiên, được thúc đẩy bởi các Mô hình Ngôn ngữ Nhỏ có khả năng chạy cục bộ trên các thiết bị chuyên dụng. Thay vì dựa vào suy luận đám mây, tác nhân cá nhân sẽ chạy cục bộ trên các thiết bị để bảo mật riêng tư, độ trễ thấp hơn, và tích hợp tốt hơn với các khả năng của thiết bị.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Nhà thông minh cuối cùng thực hiện lời hứa&lt;/strong&gt;: Trợ lý nhà sẽ hiểu ngữ cảnh và ý định thay vì chỉ các lệnh trực tiếp. Chúng sẽ tích hợp tự nhiên vào Trợ lý Cá nhân như Ứng dụng Gemini hoặc ChatGPT. Thay vì &amp;ldquo;tắt đèn trong phòng khách&amp;rdquo;, bạn có thể nói &amp;ldquo;Tôi sẽ xem phim&amp;rdquo; và hệ thống tự động làm mờ đèn, đóng rèm, điều chỉnh nhiệt độ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Thiết bị Tác nhân trở thành con hào mới cho các Phòng thí nghiệm AI&lt;/strong&gt;: Các Benchmark hiện đang đạt đến bão hòa để giới thiệu cải tiến. Các phòng thí nghiệm chuyển sang &amp;ldquo;Thiết bị&amp;rdquo;, môi trường phức tạp, để hiển thị các mô hình (tác nhân) của họ có thể thực hiện quy trình công việc nhiều ngày một cách đáng tin cậy. Các Phòng thí nghiệm AI sẽ cạnh tranh về tác nhân nào có thể xử lý các tác vụ đa bước dài nhất, phức tạp nhất một cách đáng tin cậy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Vibe Coding trưởng thành thành Kỹ thuật&lt;/strong&gt;: Vai trò của kỹ sư tiếp tục phát triển. Kỹ sư sẽ dành 99% thời gian để xem xét, đánh giá, hình thành khái niệm và suy nghĩ. Năng lực cốt lõi là khả năng bắc cầu khoảng cách giữa chi tiết triển khai, chất lượng mã, vận tốc, và sự liên kết với mục tiêu kinh doanh. Biết cách viết mã sẽ là điểm bán hàng độc đáo. Hiểu biết kỹ thuật sâu trở nên quan trọng hơn để hướng dẫn các hệ thống này một cách hiệu quả. Thanh đã được nâng cao - để tách biệt mình khỏi đám đông, bạn cần nhiều hơn là chỉ sử dụng công cụ, bạn cần hiểu chúng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6. Mạng xã hội trở nên cá nhân again&lt;/strong&gt;: Sự tham gia của người dùng trên các nền tảng xã hội chậm lại do &amp;ldquo;AI rác&amp;rdquo; tạo ra &amp;ldquo;thị trường cao cấp&amp;rdquo; cho nội dung do con người tạo ra. Khi nội dung được tạo bởi AI tràn ngập các nền tảng, nội dung do con người tạo ra trở thành hàng hóa cao cấp. Người dùng sẽ tìm kiếm kết nối con người xác thực và sẵn lòng trả tiền cho hoặc ưu tiên tham gia với nội dung con người đã xác minh.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;7. Nội dung là AI cho đến khi được chứng minh là Con người&lt;/strong&gt;: Mặc định cho bất kỳ bài đăng nào trên X, Instagram, hoặc LinkedIn là &amp;ldquo;đây là AI.&amp;rdquo; Năm 2026 giới thiệu tiêu chuẩn siêu dữ liệu &amp;ldquo;Được ký bởi Con người&amp;rdquo;. Trừ khi bài đăng/hình ảnh mang chữ ký mật mã (C2PA cho máy ảnh), thuật toán sẽ bắt đầu giảm thứ hạng của nó như &amp;ldquo;nhiễu tổng hợp.&amp;rdquo; Các nền tảng giả định nội dung được tạo bởi AI trừ khi được chứng minh rõ ràng là do con người tạo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;8. Bằng chứng sinh trắc học về Nhân tính trở thành đăng nhập xã hội mới&lt;/strong&gt;: Để chống lại spam tác nhân vô hạn, các nền tảng xã hội phân chia thành &amp;ldquo;Web Con người đã Xác minh&amp;rdquo; yêu cầu xác minh sinh trắc học. Tương tự như bằng chứng về nhân tính của Worldcoin, các nền tảng sẽ yêu cầu xác minh sinh trắc học (quét mống chân tay, vân tay, nhận diện khuôn mặt) để phân biệt con người khỏi tác nhân AI.&lt;/p&gt;
&lt;p&gt;Tác giả cực kỳ hào hứng về năm 2026, không lo lắng về vai trò là kỹ sư, và tin rằng học viết mã không phải là ý tưởng tồi. Hiểu biết kỹ thuật sâu đang trở nên quan trọng hơn. Lời khuyên: &amp;ldquo;Xây dựng và học.&amp;rdquo; Nhìn kỹ những gì người khác đang xây dựng, phân công công việc của họ để hiểu &amp;ldquo;tại sao&amp;rdquo; và &amp;ldquo;như thế nào,&amp;rdquo; sau đó xây dựng các phiên bản của riêng bạn. Trực giác kỹ thuật sâu là điều sẽ phân biệt bạn.&lt;/p&gt;
&lt;p&gt;Các tác nhân sẽ tiếp tục là tiêu đề chính. Chúng ta sẽ thấy các mô hình thiết kế thành công được thiết lập bởi các tác nhân lập trình chuyển sang các tác nhân &amp;ldquo;mục đích chung&amp;rdquo;. Chuyển sang các trường hợp sử dụng chủ động và xung quanh—nơi các tác nhân không chỉ chờ lời nhắc, nhưng tương tác trong cuộc sống hàng ngày của chúng ta để dự đoán nhu cầu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generative UI, Tác nhân Cá nhân Edge, và nhận thức ngữ cảnh Nhà thông minh nổi lên để trải nghiệm người dùng tốt hơn&lt;/li&gt;
&lt;li&gt;Thiết bị Tác nhân thay thế benchmark làm con hào cạnh tranh cho các Phòng thí nghiệm AI&lt;/li&gt;
&lt;li&gt;Vibe Coding trưởng thành: kỹ sư tập trung vào xem xét/đánh giá/hình thành khái niệm, biết mã trở thành yếu tố phân biệt&lt;/li&gt;
&lt;li&gt;&amp;ldquo;AI rác&amp;rdquo; tạo thị trường cao cấp cho nội dung con người; các nền tảng áp dụng tiêu chuẩn siêu dữ liệu &amp;ldquo;Được ký bởi Con người&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Bằng chứng sinh trắc học về nhân tính trở thành yêu cầu để chống spam tác nhân&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Newsletter #75</title><link>https://miti99.com/post/2025/12/28/</link><pubDate>Sun, 28 Dec 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/12/28/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #75.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="front-end-vs-back-end-vs-system-design--what"&gt;&lt;a class="link" href="https://designgurus.substack.com/p/front-end-vs-back-end-vs-system-design" target="_blank" rel="noopener"
&gt;Front-End vs. Back-End vs. System Design – What&amp;rsquo;s the Difference in Interviews?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Ba loại hình phỏng vấn kỹ thuật này test những skill sets hoàn toàn khác nhau và đòi hỏi chiến lược chuẩn bị riêng. Front-end interviews tập trung vào UI rendering, styling quirks và JavaScript behavior trong browser - ít emphasise vào complex algorithms hơn, mà nhiều vào domain knowledge như responsive design, CSS specificity, browser rendering pipeline. Back-end interviews thì traditional hơn với data structures, algorithms (LeetCode-style), APIs, databases - double down vào algorithmic thinking và efficiency. System design interviews thì zoom out, test khả năng architect scalable, real-world systems from scratch.&lt;/p&gt;
&lt;p&gt;Nếu so sánh với việc xây nhà: front-end như interior design (rooms look &amp;amp; feel), back-end như structure foundation (house stand &amp;amp; function), system design như architect của cả neighborhood (planning houses, roads, utilities cho best community design).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Front-end: UI/UX focus, less algorithms, more domain knowledge&lt;/li&gt;
&lt;li&gt;Back-end: DSA, APIs, databases, traditional coding challenges&lt;/li&gt;
&lt;li&gt;System design: big picture architecture, scalability, reliability&lt;/li&gt;
&lt;li&gt;Mỗi loại cần prep strategy khác nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-starting-with-microservices-can-be-your-biggest-architectural-mistake"&gt;&lt;a class="link" href="https://designgurus.substack.com/p/why-starting-with-microservices-can" target="_blank" rel="noopener"
&gt;Why Starting with Microservices Can Be Your Biggest Architectural Mistake&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Microservices thường được coi là &amp;ldquo;best practice&amp;rdquo; nhưng starting với microservices cho early-stage projects là một sai lầm đau đớn. Bài học cốt lõi: &amp;ldquo;Monolith First&amp;rdquo;. Monolith có siêu năng lực là Simplicity - tất cả code ở một nơi, debug dễ, deploy một file, function calls instantaneous. Microservices introduce 3 nightmares: (1) Network reliability - retries, timeouts, distributed systems problems thay vì simple function calls. (2) Data complexity - không thể join tables across different databases, phải manual join trong code. (3) Operational overhead - 10 services = 10 build pipelines, 10 servers, 10 log places.&lt;/p&gt;
&lt;p&gt;Refactoring monolith dễ (move files), refactoring microservices khó (change API contracts, migrate databases, coordinate deployments). Solution: Modular Monolith - organize code beautifully với modules như &lt;code&gt;/src/users&lt;/code&gt;, &lt;code&gt;/src/orders&lt;/code&gt; nhưng keep trong same runtime. Gives mental clarity của microservices mà không có operational headache. Chuyển sang microservices khi: team quá lớn (100+ devs), different scaling needs, technology diversity requirements. Đừng optimize prematurely - wait cho pain trở thành real problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Monolith First: simplicity là superpower&lt;/li&gt;
&lt;li&gt;Microservices: network, data, operational overhead&lt;/li&gt;
&lt;li&gt;Refactoring monolith dễ, microservices khó&lt;/li&gt;
&lt;li&gt;Modular Monolith: best của cả hai worlds&lt;/li&gt;
&lt;li&gt;Chuyển microservices khi team lớn/scale khác biệt/tech diversity&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t optimize premature scaling problems&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-linux-kernel-is-just-a-program"&gt;&lt;a class="link" href="https://serversfor.dev/linux-inside-out/the-linux-kernel-is-just-a-program/" target="_blank" rel="noopener"
&gt;The Linux kernel is just a program&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này giúp demystify Linux kernel - vốn thường được xem như một &amp;ldquo;black box&amp;rdquo; bí ẩn - bằng cách thực hành các experiments thực tế. Kernel Linux thực ra chỉ là một binary file vài MB nằm trong thư mục &lt;code&gt;/boot&lt;/code&gt;, hoàn toàn có thể build và chạy như một chương trình bình thường. Tác giả giải thích kernel là gì: một runtime cho máy tính, cung cấp unified interface để tương tác với hardware (CPU, memory, devices), quản lý tài nguyên, cung cấp APIs, user management, permissions, isolation.&lt;/p&gt;
&lt;p&gt;Bài viết hướng dẫn experiment chạy kernel với QEMU, tạo init program bằng Golang, build initramfs filesystem đơn giản, và boot một Linux distribution &amp;ldquo;mini&amp;rdquo; chỉ với 2 files. Qua đó, ta học được các concepts quan trọng: Linux distro thực ra chỉ là kernel + programs + configs; process là program đang chạy; PID là process ID; init process (PID 1) là process đầu tiên được kernel start; và sự khác biệt giữa kernel space (trước khi init chạy) và user space (sau khi init chạy). Cách tiếp cận hands-on này giúp xây dựng mental model về cách Linux hoạt động thay vì chỉ học theory.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Linux kernel là một binary file, không phải black box&lt;/li&gt;
&lt;li&gt;Kernel là runtime cho máy tính, unified interface với hardware&lt;/li&gt;
&lt;li&gt;Experiment với QEMU + init program để hiểu boot process&lt;/li&gt;
&lt;li&gt;Linux distro = kernel + programs + configs&lt;/li&gt;
&lt;li&gt;Concepts: process, PID, init process, kernel space vs user space&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-your-load-balancer-is-the-bottleneck-and-how-to-fix-it"&gt;&lt;a class="link" href="https://designgurus.substack.com/p/dont-let-your-load-balancer-crash" target="_blank" rel="noopener"
&gt;Why Your Load Balancer is the Bottleneck (and How to Fix It)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Có một sự irony trong hệ thống phân tán: bạn thêm load balancer để xử lý traffic scale, nhưng chính nó lại trở thành bottleneck. Application servers chạy ngon, database rảnh rỗi, nhưng load balancer lại quá tải - đây là vấn đề phân biệt junior developers và senior architects. Bài viết này giải thích lý do load balancer trở thành nút thắt và giới thiệu 5 chiến lược scaling mà các tech giants sử dụng.&lt;/p&gt;
&lt;p&gt;Các chiến lược bao gồm: DNS Round Robin để phân phối traffic ở tầng DNS, Layer 4 vs Layer 7 routing để giảm xử lý, và Direct Server Return (DSR) cho phép server responses gửi trực tiếp đến clients mà không cần qua load balancer. Mỗi phương pháp có trade-offs riêng - DNS round robin đơn giản nhưng slow propagation, Layer 4 nhanh hơn Layer 7 nhưng ít tính năng, DSR tối ưu bandwidth nhưng yêu cầu network configuration phức tạp. Hiểu và áp dụng đúng strategies này giúp load balancer scale ngang hàng với application servers thay vì là điểm nghẽn duy nhất.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Load balancer có thể trở thành bottleneck thay vì giải pháp&lt;/li&gt;
&lt;li&gt;5 strategies: DNS Round Robin, Layer 4/7 routing, DSR&lt;/li&gt;
&lt;li&gt;Junior vs senior: biết thêm load balancer vs biết scale khi nó là problem&lt;/li&gt;
&lt;li&gt;Trade-offs giữa complexity và performance&lt;/li&gt;
&lt;li&gt;Tech giants solutions cho load balancer scaling&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-high-availability-blueprint-designing-systems-that-never-sleep"&gt;&lt;a class="link" href="https://designgurus.substack.com/p/the-high-availability-blueprint-designing" target="_blank" rel="noopener"
&gt;The High Availability Blueprint: Designing Systems That Never Sleep&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;High Availability (HA) là kỷ thuật xây dựng hệ thống &amp;ldquo;không bao giờ ngủ&amp;rdquo; - dù hardware có chắc chắn sẽ thất bại. Bài viết này giới thiệu các fundamental techniques mà engineers sử dụng để giữ cho hệ thống luôn hoạt động. Core philosophy của HA: &amp;ldquo;Assume everything will break, and plan for it.&amp;rdquo; Kẻ thù lớn nhất là Single Points of Failure (SPOF) - bất kỳ component nào nếu fails thì toàn bộ hệ thống停止.&lt;/p&gt;
&lt;p&gt;Các kỹ thuật cốt lõi bao gồm: Redundancy (nhân bản critical components - two is one, one is none), Load Balancers với Health Checks (tự động remove broken servers khỏi rotation), Database Replication (Leader-Follower architecture để backup data real-time), Failover patterns (Active-Passive đơn giản nhưng lãng phí, Active-Active tối ưu nhưng phức tạp), và Rate Limiting để prevent cascading failures khi traffic spike. Cho Five Nines (99.999% uptime = chỉ 5 phút downtime/năm), cần Geographic Distribution - deploy servers across multiple regions để survive local disasters. Key takeaway: &amp;ldquo;Two is one, and one is none&amp;rdquo; - luôn luôn có backup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HA: mask failures thay vì prevent, user never knows&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The Nines&amp;rdquo;: 99% → 99.999%, mỗi nine thêm exponentially expensive&lt;/li&gt;
&lt;li&gt;SPOF là enemy, redundancy là solution&lt;/li&gt;
&lt;li&gt;Load balancer health checks tự động detect &amp;amp; route around failures&lt;/li&gt;
&lt;li&gt;Database replication: Leader-Follower để protect data&lt;/li&gt;
&lt;li&gt;Failover: Active-Passive (simple) vs Active-Active (efficient)&lt;/li&gt;
&lt;li&gt;Rate limiting prevent cascading failures&lt;/li&gt;
&lt;li&gt;Geographic distribution cho five nines availability&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus"&gt;Bonus
&lt;/h2&gt;&lt;h3 id="images"&gt;Images
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://substackcdn.com/image/fetch/$s_!ETm5!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2112a03d-cc48-4db5-9740-94adc1a7efbf_2360x2920.png"
loading="lazy"
alt="Common Network Protocols Every Engineer Should Know"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!5bFA!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F722913d5-a10f-44c2-98ed-edc27a92a137_1444x1882.jpeg"
loading="lazy"
alt="8 Popular Network Protocols"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!pen8!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22fdf2d2-5ce5-4c2b-90f9-3bcfcecb5fc1_1370x1536.jpeg"
loading="lazy"
alt="9 best practices for developing microservices"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #74</title><link>https://miti99.com/post/2025/12/27/</link><pubDate>Sat, 27 Dec 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/12/27/</guid><description>&lt;p&gt;&lt;em&gt;Lâu rồi chưa pay 1 cái gì liên quan đến AI (từ thời Claude subscription để thử nghiệm Claude Code). Nay mới mua thử gói &lt;a class="link" href="https://z.ai/subscribe" target="_blank" rel="noopener"
&gt;GLM Coding Plan&lt;/a&gt; của &lt;a class="link" href="https://z.ai" target="_blank" rel="noopener"
&gt;Z.ai&lt;/a&gt; để trải nghiệm. Gói này hiện cho phép dùng model mới nhất của Z.ai là GLM-4.7. Từ nay mình sẽ tranh thủ dùng &lt;a class="link" href="https://claude.com/product/claude-code" target="_blank" rel="noopener"
&gt;Claude Code&lt;/a&gt; với &lt;a class="link" href="https://z.ai/model-api" target="_blank" rel="noopener"
&gt;Z.ai API&lt;/a&gt; để &amp;lsquo;bào&amp;rsquo; cho xứng đáng số tiền bỏ ra^^. Mời bạn thưởng thức Newsletter #74.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="goodbye-microservices-from-100s-of-problem-children-to-1-superstar"&gt;&lt;a class="link" href="https://www.twilio.com/en-us/blog/developers/best-practices/goodbye-microservices" target="_blank" rel="noopener"
&gt;Goodbye Microservices: From 100s of problem children to 1 superstar&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Twilio Segment chia sẻ hành trình từ hơn 100 microservices quay lại monolith. Ban đầu dùng microservices để giải quyết head-of-line blocking - tạo riêng service và queue cho từng đích đến. Nhưng khi scale lên (trung bình 3 đích/tháng), các vấn đề nảy sinh: shared libraries phân kỳ giữa codebase, mỗi service có pattern tải khác nhau khiến scale khó khăn.&lt;/p&gt;
&lt;p&gt;Họ gộp 140+ services thành một service, chuyển về monorepo, xây dựng Traffic Recorder để test nhanh hơn. Kết quả: developer velocity tăng, operational overhead giảm. Trade-off: khó cô lập lỗi hơn, caching kém hiệu quả, nhưng với test suite vững chắc thì đáng đổi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Microservices giải quyết blocking nhưng tạo overhead lớn&lt;/li&gt;
&lt;li&gt;Shared libraries phân kỳ làm mất lợi ích thống nhất&lt;/li&gt;
&lt;li&gt;Monolith tăng velocity, giảm burden&lt;/li&gt;
&lt;li&gt;Traffic Recorder test nhanh hơn&lt;/li&gt;
&lt;li&gt;Cần test suite vững khi chuyển về monolith&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="5-engineering-dogmas-it"&gt;&lt;a class="link" href="https://newsletter.manager.dev/p/5-engineering-dogmas-its-time-to" target="_blank" rel="noopener"
&gt;5 engineering dogmas it&amp;rsquo;s time to retire&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;5 quan điểm cần xem xét lại: (1) &amp;ldquo;Đừng reinvent the wheel&amp;rdquo; - lạm dụng dependencies có rủi ro bảo mật, ví dụ left-pad (11 dòng) từng break build của Facebook/Netflix. (2) &amp;ldquo;Mọi PR phải review&amp;rdquo; - review có giá trị nhưng quy trình bắt buộc làm chậm, một số công ty để engineer tự merge và chỉ review khi cần. (3) &amp;ldquo;Sprints 2-4 tuần&amp;rdquo; - Shape Up với 6-week cycles + cool-down time là giải pháp thay thế. (4) &amp;ldquo;Feature flag cho mọi change&amp;rdquo; - lạm dụng làm codebase phức tạp, tạo cảm giác an toàn giả. (5) &amp;ldquo;Comment = code phức tạp&amp;rdquo; - cân bằng, đôi khi comment tiết kiệm nhiều thời gian.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dependencies cần cân nhắc, có rủi ro bảo mật&lt;/li&gt;
&lt;li&gt;Review có giá trị nhưng quy trình bắt buộc chậm&lt;/li&gt;
&lt;li&gt;Shape Up: 6-week cycles + cool-down&lt;/li&gt;
&lt;li&gt;Feature flag lạm dụng phức tạp, an toàn giả&lt;/li&gt;
&lt;li&gt;Comment đôi khi tiết kiệm thời gian&lt;/li&gt;
&lt;li&gt;Cần cân bằng dogmas với thực tế&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-does-a-database-for-ssds-look-like"&gt;&lt;a class="link" href="https://brooker.co.za/blog/2025/12/15/database-for-ssd.html" target="_blank" rel="noopener"
&gt;What Does a Database for SSDs Look Like?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Database được thiết kế riêng cho SSDs trông như thế nào? Postgres/MySQL thiết kế cho spinning disks, nhưng SSD hiện tốt hơn ~1000x. Cloud networks cũng tốt hơn 1000x. Tác giả tiếp cận qua 5 góc độ:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Five Minute Rule update 2025: cache giữ pages ~30 seconds cho optimal cost&lt;/li&gt;
&lt;li&gt;Optimal transfer size cho SSD ~32kB&lt;/li&gt;
&lt;li&gt;Durability qua distributed log, không chỉ local disk&lt;/li&gt;
&lt;li&gt;Chỉ incur cross-AZ latency tại commit time&lt;/li&gt;
&lt;li&gt;Use high-quality clocks cho coordination&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tóm lại, giữ relational model/SQL nhưng move durability/scale/HA thành distributed concerns, toss local durability optimizations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cache giữ pages ~30 seconds (thay vì 5 phút năm 1986)&lt;/li&gt;
&lt;li&gt;Transfer size ~32kB optimal cho SSD&lt;/li&gt;
&lt;li&gt;Durability qua distributed log multi-AZ&lt;/li&gt;
&lt;li&gt;Cross-AZ latency chỉ tại commit&lt;/li&gt;
&lt;li&gt;Relational model giữ, distributed concerns thêm&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-economics-of-system-design-finops-auto-scaling-and-spot-instances"&gt;&lt;a class="link" href="https://designgurus.substack.com/p/cloud-cost-optimization-101-5-strategies" target="_blank" rel="noopener"
&gt;The Economics of System Design: FinOps, Auto-Scaling, and Spot Instances&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Cost optimization trong system design thường bị bỏ qua. Khoảng 30% cloud spend là waste. Inefficiencies nhỏ scale lên thành expenses lớn. 5 strategies:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Cost-conscious architecture: microservices trade-offs, simplicity&lt;/li&gt;
&lt;li&gt;Right-sizing + auto-scaling: không over-provision, use serverless&lt;/li&gt;
&lt;li&gt;Caching + query optimization: giảm database load&lt;/li&gt;
&lt;li&gt;Hunt idle resources: shutdown forgotten instances&lt;/li&gt;
&lt;li&gt;Monitoring + FinOps: treat cost như performance metric&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Well-designed system không chỉ scalable/performant mà còn cost-efficient.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;30% cloud spend là waste&lt;/li&gt;
&lt;li&gt;Design cost-conscious với simplicity&lt;/li&gt;
&lt;li&gt;Right-sizing + auto-scaling + serverless&lt;/li&gt;
&lt;li&gt;Caching giảm database load&lt;/li&gt;
&lt;li&gt;Shutdown idle resources&lt;/li&gt;
&lt;li&gt;Treat cost như performance metric&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-big-o-complexity-of-vibe-coders"&gt;&lt;a class="link" href="https://www.shiveesh.com/thoughts-and-ideas/the-big-o-complexity-of-vibe-coders" target="_blank" rel="noopener"
&gt;The Big-O Complexity of Vibe Coders&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Vibe coding (dùng LLMs để code) hiện được đánh giá bằng tốc độ, nhưng khi scale thì cost quan trọng hơn. Teams không dùng vibe coding chậm hơn, teams lạm dụng tốn nhiều tokens. Iterations không free - mỗi prompt consumes tokens = cost.&lt;/p&gt;
&lt;p&gt;Workflow nhiều fast iterations có thể O(n²) complexity. Vague prompts expand solution space, precise prompts converge faster. Best vibe coders = lowest Big-O tokens per shipped outcome. Token-efficient vibe coding scales teams.&lt;/p&gt;
&lt;p&gt;Exploratory/creative work inherently inefficient, không nên optimize all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vibe coding đánh giá bằng tốc độ, cost quan trọng hơn khi scale&lt;/li&gt;
&lt;li&gt;Iterations consumes tokens = cost&lt;/li&gt;
&lt;li&gt;Workflow nhiều iterations có thể O(n²)&lt;/li&gt;
&lt;li&gt;Precise prompts converge nhanh hơn vague&lt;/li&gt;
&lt;li&gt;Best vibe coders = lowest tokens/outcome&lt;/li&gt;
&lt;li&gt;Exploratory work inherently inefficient&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="design-is-more-than-code"&gt;&lt;a class="link" href="https://linear.app/now/design-is-more-than-code" target="_blank" rel="noopener"
&gt;Design is more than code&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Design không chỉ về code. Recent discourse tập trung designers có nên code không, nhưng điều này reductive. Câu hỏi lớn hơn: designers sẽ contributing như thế nào với AI và new tools?&lt;/p&gt;
&lt;p&gt;Design process có 2 stages: designing the problem và designing the solution. Designing the problem: question the problem, không assume - most failures do unclear problem. Designing the solution: conceptual stage (tìm form) và execution stage (build nó). Code/material essential cho execution, nhưng không cho tất cả.&lt;/p&gt;
&lt;p&gt;Tác giả worry về decline trong consideration, không phải tools. Design về finding right problem/intent/vision.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Debate designers coding reductive&lt;/li&gt;
&lt;li&gt;Design comes in many flavors&lt;/li&gt;
&lt;li&gt;Process: design problem → design solution&lt;/li&gt;
&lt;li&gt;Question problem, không assume&lt;/li&gt;
&lt;li&gt;Conceptual → execution stages&lt;/li&gt;
&lt;li&gt;Code essential cho execution, không all&lt;/li&gt;
&lt;li&gt;Worry decline consideration, không tools&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-we-saved-70-cpu-and-60-memory-in-refinery"&gt;[How we saved 70% CPU and 60% memory in Refinery]((&lt;a class="link" href="https://www.honeycomb.io/blog/how-we-saved-70-cpu-60-memory-refinery" target="_blank" rel="noopener"
&gt;https://www.honeycomb.io/blog/how-we-saved-70-cpu-60-memory-refinery&lt;/a&gt;)
&lt;/h2&gt;&lt;p&gt;Honeycomb optimize Refinery telemetry pipeline: giảm 70% CPU và 60% memory. Root cause là dynamic attributes calculation - parse attributes nhiều lần, create intermediate allocations inefficiencies.&lt;/p&gt;
&lt;p&gt;Refactor: (1) Parse attributes chỉ một lần early, (2) Reuse parsed data, (3) Eliminate intermediate allocations, (4) Use efficient data structures.&lt;/p&gt;
&lt;p&gt;Profiling trước khi optimize critical - find bottlenecks first. Trade-off: code phức tạp hơn, harder maintain, nhưng performance gains justify trong case này.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;High resource usage do attributes calculation&lt;/li&gt;
&lt;li&gt;Parse multiple times, intermediate allocations inefficient&lt;/li&gt;
&lt;li&gt;Refactor: parse once, reuse, eliminate allocations&lt;/li&gt;
&lt;li&gt;Result: 70% CPU, 60% memory reduction&lt;/li&gt;
&lt;li&gt;Profiling trước khi optimize&lt;/li&gt;
&lt;li&gt;Trade-off: phức tạp hơn nhưng worth it&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="from-junior-to-senior-7-api-design-patterns-that-scale"&gt;[From Junior to Senior: 7 API Design Patterns That Scale]((&lt;a class="link" href="https://designgurus.substack.com/p/from-junior-to-senior-7-api-design" target="_blank" rel="noopener"
&gt;https://designgurus.substack.com/p/from-junior-to-senior-7-api-design&lt;/a&gt;)
&lt;/h2&gt;&lt;p&gt;7 architectural decisions cho scalable APIs - khác biệt junior/senior. Junior focus logic, senior focus system communication. API là critical component của distributed systems.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Resource-Oriented Design (RESTful) thay vì Action-Based (RPC): think resources (nouns), không actions (verbs). Predictability là valuable trait.&lt;/li&gt;
&lt;li&gt;Proper HTTP Status Codes: 2xx/4xx/5xx categories matter cho debugging&lt;/li&gt;
&lt;li&gt;Pagination: Offset (beginner) vs Cursor (scalable, O(1))&lt;/li&gt;
&lt;li&gt;Idempotency Keys prevent duplicate charges&lt;/li&gt;
&lt;li&gt;Rate Limiting protects từ overload&lt;/li&gt;
&lt;li&gt;API Versioning prevents breaking clients&lt;/li&gt;
&lt;li&gt;Documentation critical với OpenAPI/Swagger&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Good API design = stable foundation, poor design = bottleneck.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Junior focus logic, senior focus communication&lt;/li&gt;
&lt;li&gt;RESTful (resources) thay vì RPC (actions)&lt;/li&gt;
&lt;li&gt;HTTP status codes categories matter&lt;/li&gt;
&lt;li&gt;Cursor pagination scalable hơn offset&lt;/li&gt;
&lt;li&gt;Idempotency keys prevent duplicates&lt;/li&gt;
&lt;li&gt;Rate limiting protects overload&lt;/li&gt;
&lt;li&gt;Versioning prevents breaking clients&lt;/li&gt;
&lt;li&gt;Documentation critical&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus"&gt;Bonus
&lt;/h2&gt;&lt;h3 id="images"&gt;Images
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://substackcdn.com/image/fetch/$s_!3GQA!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F82f1e76a-8fbf-4e8f-b030-e20037c66f70_3000x3900.png"
loading="lazy"
alt="Evolution of HTTP"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!Zyn0!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F063ae714-8714-4695-8b0e-16a765c5c1a8_2360x2960.png"
loading="lazy"
alt="System Performance Metrics Every Engineer Should Know"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!ta7a!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe42382d5-9be5-443a-9f75-56ecfa22569c_2360x2960.png"
loading="lazy"
alt="Why Is Nginx So Popular?"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!sXIK!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa25e1401-cc6f-49f1-9ed1-6f093a01ac6c_2360x2664.png"
loading="lazy"
alt="Network Debugging Commands Every Engineer Should Know"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!BXWB!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a8b52f-2b80-4762-92cd-c5d18d5a7a3c_2360x2960.png"
loading="lazy"
alt="Hub, Switch, &amp; Router Explained"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Đánh giá&lt;/strong&gt;: &lt;em&gt;Z.ai xử lý 1 url tương đối nhanh, ban đầu mình cũng thấy khá ok, tuy nhiên thêm càng nhiều thì có vẻ càng bị dài &amp;amp; lạm dụng tiếng Anh. Mình đã phải yêu cầu tóm gọn lại một xíu. Hi vọng sẽ cải thiện được sau (vì lỡ mua rùi và non-refundable hiuhiu)&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #73</title><link>https://miti99.com/post/2025/12/20/</link><pubDate>Sat, 20 Dec 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/12/20/</guid><description>&lt;p&gt;&lt;em&gt;Gầy đây mình mới biết &lt;a class="link" href="https://openrouter.ai/docs/guides/guides/claude-code-integration" target="_blank" rel="noopener"
&gt;OpenRouter đã hỗ trợ tích hợp Claude Code&lt;/a&gt;, nên nay dùng thử. Bài viết này được thực hiện bởi &lt;a class="link" href="https://claude.com/product/claude-code" target="_blank" rel="noopener"
&gt;Claude Code&lt;/a&gt; + &lt;a class="link" href="https://openrouter.ai/" target="_blank" rel="noopener"
&gt;Open Router&lt;/a&gt; + &lt;a class="link" href="https://openrouter.ai/z-ai/glm-4.5-air:free" target="_blank" rel="noopener"
&gt;Z.AI: GLM 4.5 Air (free)&lt;/a&gt;. Mời bạn thưởng thức Newsletter #73.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="system-design-deep-dive-time-series-databases-tsdbs-explained"&gt;&lt;a class="link" href="https://designgurus.substack.com/p/system-design-deep-dive-time-series" target="_blank" rel="noopener"
&gt;System Design Deep Dive: Time Series Databases (TSDBs) Explained&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Cơ sở dữ liệu chuỗi thời gian (TSDB) là giải pháp tối ưu cho dữ liệu có thứ tự thời gian, cung cấp khả năng nhập dữ liệu hiệu suất cao và truy vấn nhanh chóng dựa trên thời gian. Khác với cơ sở dữ liệu truyền thống, TSDB tập trung vào dữ liệu có dấu thời gian và xử lý chúng xuất sắc.&lt;/p&gt;
&lt;p&gt;TSDB có đặc điểm nổi bật: nén dữ liệu hiệu quả bằng các kỹ thuật như mã hóa delta và mã hóa độ dài chạy; tự động quản lý vòng đời dữ liệu với chính sách lưu trữ và giảm mẫu; truy phạm vi thời gian nhanh chóng nhờ tính năng chỉ mục thời gian.&lt;/p&gt;
&lt;p&gt;Ứng dụng phổ biến: giám sát hạ tầng theo dõi chỉ số máy chủ và ứng dụng; xử lý dữ liệu cảm biến IoT từ các thiết bị liên tục.&lt;/p&gt;
&lt;p&gt;So với cơ sở dữ liệu quan hệ, TSDB vượt trội ở việc ghi tần suất cao và truy vấn phạm vi thời gian nhanh trên dữ liệu tuần tự, trong khi cơ sở dữ liệu quan hệ phù hợp hơn cho các phép nối phức tạp và cập nhật thường xuyên.&lt;/p&gt;
&lt;p&gt;TSDB sử dụng nén, giảm mẫu và chính sách lưu trữ để quản lý hiệu quả khối lượng dữ liệu lịch sử lớn, giúp giảm phân giải dữ liệu cũ bằng cách tổng hợp vào các khoảng thời gian thô hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TSDB tối ưu cho dữ liệu có thứ tự thời gian với khả năng nhập liệu hiệu suất cao&lt;/li&gt;
&lt;li&gt;Sử dụng các kỹ thuật nén đặc biệt (delta encoding, run-length encoding)&lt;/li&gt;
&lt;li&gt;Tự động quản lý vòng đời dữ liệu với chính sách lưu trữ và giảm mẫu&lt;/li&gt;
&lt;li&gt;Phù hợp cho giám sát hạ tầng và xử lý dữ liệu IoT&lt;/li&gt;
&lt;li&gt;Vượt trội hơn cơ sở dữ liệu quan hệ cho ghi tần suất cao và truy vấn theo thời gian&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-memory-maps-mmap-deliver-25x-faster-file-access-in-go"&gt;&lt;a class="link" href="https://info.varnish-software.com/blog/how-memory-maps-mmap-deliver-25x-faster-file-access-in-go" target="_blank" rel="noopener"
&gt;How Memory Maps (mmap) Deliver 25x Faster File Access in Go&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết trình bày về cơ chế sơ đồ bộ nhớ (mmap) trong Unix, cho phép xử lý tệp như một phần của bộ nhớ ảo. Thay vì sử dụng thao tác tìm kiếm/đọc truyền thống, mmap cung cấp con trỏ trực tiếp đến dữ liệu tệp trong bộ nhớ.&lt;/p&gt;
&lt;p&gt;Các bài kiểm tra hiệu suất cho thấy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tra cứu ngẫu nhiên (ReaderAt): 416.4 ns/op&lt;/li&gt;
&lt;li&gt;Tra cứu ngẫu nhiên (mmap): 3.3 ns/op&lt;/li&gt;
&lt;li&gt;Lặp lại (ReaderAt): 333.3 ns/op&lt;/li&gt;
&lt;li&gt;Lặp lại (mmap): 1.3 ns/op&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Đối với ghi dữ liệu, mmap kém hiệu quả hơn do lỗi trang, với thời gian 1870 ns/op khi trang chưa được ánh xạ. Tác giả đã ứng dụng mmap trong hệ thống tệp HTTP, đạt được cải thiện hiệu suất 25 lần, giúp giảm đáng kể áp lực bộ nhớ và độ trễ.&lt;/p&gt;
&lt;p&gt;Mặc dù có hạn chế khi ghi, mmap vẫn là giải pháp tối ưu cho các ứng dụng yêu cầu tốc độ truy cập tệp cao.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;mmap cho phép xử lý tệp như phần của bộ nhớ ảo trong Unix&lt;/li&gt;
&lt;li&gt;Đạt hiệu suất 25 lần nhanh hơn phương pháp truyền thống&lt;/li&gt;
&lt;li&gt;Hiệu quả cao cho đọc dữ liệu nhưng kém hơn khi ghi do lỗi trang&lt;/li&gt;
&lt;li&gt;Phù hợp cho các ứng dụng yêu cầu tốc độ truy cập tệp cao&lt;/li&gt;
&lt;li&gt;Giảm đáng kể áp lực bộ nhớ và độ trễ trong hệ thống&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bloom-filters"&gt;&lt;a class="link" href="https://eli.thegreenplace.net/2025/bloom-filters" target="_blank" rel="noopener"
&gt;Bloom filters&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bloom filters là cấu trúc dữ liệu xác suất để kiểm tra thành viên tập hợp hiệu quả. Được Burton Bloom đề xuất vào năm 1970, chúng hoạt động bằng cách sử dụng nhiều hàm băm để đặt các bit trong một mảng bit.&lt;/p&gt;
&lt;p&gt;Ưu điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không bao có kết quả âm giả&lt;/li&gt;
&lt;li&gt;Hiệu quả về mặt không gian&lt;/li&gt;
&lt;li&gt;Thời gian tìm kiếm hằng số&lt;/li&gt;
&lt;li&gt;Đặc biệt hữu ích khi hầu hết các truy vấn kiểm tra sự không thuộc về tập hợp&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nguyên lý hoạt động:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chèn mục: Băm mục bằng k hàm băm và đặt các bit tương ứng thành 1&lt;/li&gt;
&lt;li&gt;Kiểm tra: Nếu bất kỳ bit nào là 0, chắc chắn mục không có; nếu tất cả là 1, có thể có kết quả dương giả&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Công thức tối ưu:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tỷ lệ bit trên phần tử: m/n ≈ -ln(ε)/ln²(2)&lt;/li&gt;
&lt;li&gt;Số hàm băm tối ưu: k = (m/n)·ln(2)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ví dụ thực tế: Với 1 tỷ mục và tỷ lệ lỗi 1%, cần khoảng 1.2GB không gian.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bloom filters là cấu trúc dữ liệu xác suất cho kiểm tra thành viên tập hợp&lt;/li&gt;
&lt;li&gt;Sử dụng nhiều hàm băm để đặt bit trong mảng bit&lt;/li&gt;
&lt;li&gt;Có thể có kết quả dương giả nhưng không bao có kết quả âm giả&lt;/li&gt;
&lt;li&gt;Hiệu quả về mặt không gian và thời gian tìm kiếm hằng số&lt;/li&gt;
&lt;li&gt;Phù hợp cho các hệ thống yêu cầu kiểm tra nhanh sự không thuộc về tập hợp&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-the-heck-is-aead-again"&gt;&lt;a class="link" href="https://ochagavia.nl/blog/what-the-heck-is-aead-again/" target="_blank" rel="noopener"
&gt;What the heck is AEAD again?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;AEAD là tiêu chuẩn mã hóa hiện đại, kết hợp mã hóa xác thực và dữ liệu liên kết. Giải pháp này đảm bảo bảo vệ cả thông điệp mã hóa và dữ liệu không mã hóa đi kèm, ngăn chặn tấn công thay đổi nội dung. Thay vì thực hiện riêng biệt như trước, thư viện mã hóa hiện đại như libsodium cung cấp API đơn giản, giảm thiểu lỗi. Các thuật toán phổ biến gồm AES256-GCM và ChaCha20-Poly1305, nhưng việc lựa chọn nên dựa trên yêu cầu cụ thể của hệ thống.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AEAD kết hợp mã hóa xác thực và dữ liệu liên kết trong một giải pháp duy nhất&lt;/li&gt;
&lt;li&gt;Đảm bảo bảo vệ cả thông điệp mã hóa và dữ liệu không mã hóa đi kèm&lt;/li&gt;
&lt;li&gt;Ngăn chặn tấn công thay đổi nội dung (tampering)&lt;/li&gt;
&lt;li&gt;Thư viện hiện đại như libsodium cung cấp API đơn giản, giảm thiểu lỗi&lt;/li&gt;
&lt;li&gt;Các thuật toán phổ biến: AES256-GCM và ChaCha20-Poly1305&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ceilometer-khung-đo-lường-thích-ứng-của-uber"&gt;&lt;a class="link" href="https://www.uber.com/en-IN/blog/ceilometer-ubers-adaptive-benchmarking-framework/" target="_blank" rel="noopener"
&gt;Ceilometer: Khung đo lường thích ứng của Uber&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Ceilometer là khung đo lường thích ứng của Uber, được thiết kế để hỗ trợ quyết định cơ sở hạ tầng và duy trì tiêu chuẩn hiệu suất cao. Hệ thống này có khả năng hoạt động trên nhiều khung kiểm thử khác nhau, bao gồm cả kiểm thử tổng hợp (synthetic), có trạng thái (stateful) và không trạng thái (stateless).&lt;/p&gt;
&lt;p&gt;Ứng dụng chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Định hình (shape qualification): Đánh giá các loại máy chủ mới, từ giai đoạn phát triển của nhà cung cấp đến triển khai thực tế trong môi trường Uber.&lt;/li&gt;
&lt;li&gt;Xác minh thay đổi (change validation): Đánh giá bất kỳ thay đổi nào đối với cơ sở hạ tầng hiện có, hợp tác với chủ sở hữu dịch vụ để đảm bảo hiệu suất chính xác.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Triển khai trong tương lai:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tích hợp AI/ML sâu hơn&lt;/li&gt;
&lt;li&gt;Hỗ trợ hệ sinh thái rộng hơn&lt;/li&gt;
&lt;li&gt;Phát hiện bất thường tiên tiến&lt;/li&gt;
&lt;li&gt;Tích hợp chỉ số sử dụng thành phần&lt;/li&gt;
&lt;li&gt;Kiểm tra xác định liên tục&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ceilometer đã đáp ứng nhu cầu đo lường thích ứng của Uber, thể hiện khả năng thích nghi với các yếu tố quan trọng, và tiếp tục phát triển để đáp ứng các yêu cầu đo lường tiên tiến tại Uber.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ceilometer hỗ trợ quyết định cơ sở hạ tầng và duy trì tiêu chuẩn hiệu suất cao&lt;/li&gt;
&lt;li&gt;Hoạt động trên nhiều khung kiểm thử khác nhau (synthetic, stateful, stateless)&lt;/li&gt;
&lt;li&gt;Hai ứng dụng chính: định hình máy chủ mới và xác minh thay đổi cơ sở hạ tầng&lt;/li&gt;
&lt;li&gt;Tích hợp với chủ sở hữu dịch vụ để đảm bảo hiệu suất chính xác&lt;/li&gt;
&lt;li&gt;Tiếp tục phát triển với các tính năng AI/ML và phát hiện bất tiên tiến&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="useful-patterns-for-building-html-tools"&gt;&lt;a class="link" href="https://simonwillison.net/2025/Dec/10/html-tools/" target="_blank" rel="noopener"
&gt;Useful patterns for building HTML tools&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết trình bày các mẫu hữu ích để xây dựng công cụ HTML - ứng dụng kết hợp HTML, JavaScript và CSS trong một tệp duy nhất. Tác giả đã phát triển hơn 150 công cụ như vậy trong hai năm qua, chủ yếu do LLM viết.&lt;/p&gt;
&lt;p&gt;Các điểm chính bao gồm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kiến trúc cơ bản: một tệp duy nhất, không sử dụng React, tải phụ thuộc từ CDN&lt;/li&gt;
&lt;li&gt;Tạo mẫu với Artifacts hoặc Canvas&lt;/li&gt;
&lt;li&gt;Sử dụng localStorage để lưu trạng thái hoặc bí mật&lt;/li&gt;
&lt;li&gt;Tận dụng API có CORS và WebAssembly&lt;/li&gt;
&lt;li&gt;Xây dựng công cụ gỡ lỗi để khám phá khả năng&lt;/li&gt;
&lt;li&gt;Phối hợp lại các công cụ trước đó&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết khuyến khích người đọc bắt đầu xây dựng bộ sưu tập công cụ riêng, sử dụng GitHub Pages để lưu trữ và chia sẻ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Công cụ HTML là ứng dụng kết hợp HTML, JavaScript và CSS trong một tệp duy nhất&lt;/li&gt;
&lt;li&gt;Kiến trúc đơn giản: một tệp, không React, phụ thuộc từ CDN&lt;/li&gt;
&lt;li&gt;Tận dụng localStorage, API có CORS và WebAssembly&lt;/li&gt;
&lt;li&gt;Tác giả đã phát triển hơn 150 công cụ như vậy trong hai năm&lt;/li&gt;
&lt;li&gt;Khuyến khích bắt đầu xây dựng bộ sưu tập công cụ riêng và chia sẻ trên GitHub Pages&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="memory-allocation-in-go"&gt;&lt;a class="link" href="https://nghiant3223.github.io/2025/06/03/memory_allocation_in_go.html" target="_blank" rel="noopener"
&gt;Memory Allocation in Go&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích chi tiết cơ chế phân bổ bộ nhớ trong Go, một chủ đề quan trọng để tối ưu hiệu suất ứng dụng. Go sử dụng hệ thống phân cấp với ba thành phần chính: mheap (quản lý bộ nhớ toàn cục), mcentral (trung tâm phân bổ span) và mcache (bộ đệm bộ nhớ trên mỗi processor P).&lt;/p&gt;
&lt;p&gt;Go chia đối tượng thành ba loại dựa trên kích thước: tiny (&amp;lt;16 bytes), small (16-32760 bytes) và large (&amp;gt;32760 bytes). Mỗi loại có cách phân bổ riêng biệt. Tiny objects được xử lý hiệu quả bằng allocator chuyên dụng, trong khi small objects được quản lý qua các span với 68 size class khác nhau. Large objects được phân bổ trực tiếp từ mheap.&lt;/p&gt;
&lt;p&gt;Stack của goroutine cũng được quản lý linh hoạt, bắt đầu với 2KB và có thể tăng gấp đôi khi cần thiết. Go sử dụng cơ chế contiguous stacks để tránh vấn đề performance của segmented stacks.&lt;/p&gt;
&lt;p&gt;Phân tích escape analysis quyết định biến nên được phân bổ trên stack hay heap, đảm bảo an toàn bộ nhớ. Các nghiên cứu tình huống cho thấy cách tối ưu như tái sử dụng slice, nhóm biến thành struct và dùng sync.Pool để giảm số lần phân bổ bộ nhớ.&lt;/p&gt;
&lt;p&gt;Hiểu rõ cơ chế này giúp developer viết mã hiệu quả hơn và tránh các vấn đề về hiệu suất liên quan đến quản lý bộ nhớ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go sử dụng hệ thống phân cấp ba cấp: mheap, mcentral và mcache&lt;/li&gt;
&lt;li&gt;Đối tượng chia thành three loại: tiny (&amp;lt;16B), small (16-32760B) và large (&amp;gt;32760B)&lt;/li&gt;
&lt;li&gt;Tiny objects dùng allocator chuyên dụng, small objects quản lý qua span&lt;/li&gt;
&lt;li&gt;Stack goroutine bắt đầu 2KB, tăng gấp đôi khi cần&lt;/li&gt;
&lt;li&gt;Escape analysis quyết định stack/heap allocation&lt;/li&gt;
&lt;li&gt;Tối ưu: tái sử dụng slice, group variables, dùng sync.Pool&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="system-design-masterclass-building-a-global-cdn-and-edge-caching-strategy"&gt;&lt;a class="link" href="https://designgurus.substack.com/p/system-design-masterclass-building" target="_blank" rel="noopener"
&gt;System Design Masterclass: Building a Global CDN and Edge Caching Strategy&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết hướng dẫn cách thiết kế mạng phân phối nội dung (CDN) toàn cầu và chiến lược caching tại edge để cung cấp nội dung với tốc độ ánh sáng trên toàn thế giới. CDN hoạt động như một mạng lưới máy chủ phân phối toàn cầu, lưu trữ bản sao nội dung từ máy chủ gốc và phân phối cho người dùng từ vị trí gần nhất.&lt;/p&gt;
&lt;p&gt;Nguyên tắc hoạt động chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đưa nội dung gần với người dùng&lt;/li&gt;
&lt;li&gt;Giảm độ trễ và tải cho máy chủ gốc&lt;/li&gt;
&lt;li&gt;Cải thiện tốc độ tải trang và trải nghiệm người dùng&lt;/li&gt;
&lt;li&gt;Bảo vệ khỏi các tấn công DDoS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Các yếu tố quan trọng khi thiết kế CDN:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phân loại nội dung: static (hình ảnh, CSS/JS, video) và dynamic (API response, trang cá nhân hóa)&lt;/li&gt;
&lt;li&gt;Cấu hình TTL (Time-to-Live) cho từng loại nội dung&lt;/li&gt;
&lt;li&gt;Xử lý cache invalidation khi nội dung cập nhật&lt;/li&gt;
&lt;li&gt;Sử dụng anycast network để định tuyến thông minh&lt;/li&gt;
&lt;li&gt;Tích hợp với SSL offloading và DDoS protection&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Chiến lược caching hiệu quả:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cache static assets với TTL dài (tuần/tháng)&lt;/li&gt;
&lt;li&gt;Sử dụng micro-caching cho dynamic content (vài giây/phút)&lt;/li&gt;
&lt;li&gt;Kết hợp TTL expiry, manual purge và versioning&lt;/li&gt;
&lt;li&gt;Giám sát cache hit ratio để tối ưu hóa&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CDN là mạng lưới máy phân phối nội dung toàn cầu, giảm độ trễ bằng cách lưu cache tại edge&lt;/li&gt;
&lt;li&gt;Phân loại nội dung static/dynamic để áp dụng chiến lược caching phù hợp&lt;/li&gt;
&lt;li&gt;TTL expiry, manual purge và versioning là ba phương pháp chính cho cache invalidation&lt;/li&gt;
&lt;li&gt;Anycast network giúp định tuyến người dùng đến server gần nhất&lt;/li&gt;
&lt;li&gt;Giám sát và tối ưu liên tục là chìa khóa để CDN hoạt động hiệu quả&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="protect-your-api-a-developer"&gt;&lt;a class="link" href="https://designgurus.substack.com/p/system-design-blueprint-designing" target="_blank" rel="noopener"
&gt;Protect Your API: A Developer&amp;rsquo;s Guide to Rate Limiting and Throttling&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết cung cấp hướng dẫn toàn diện về rate limiting và throttling để bảo vệ API khỏi các tấn công và quá tải. Trong kỹ thuật phần mềm, một sự thật cơ bản là tài nguyên là hữu hạn. Mọi hệ thống đều có điểm giới hạn, và nếu không có cơ chế kiểm soát, một đợt tăng traffic đột ngột có thể làm sập toàn bộ hệ thống.&lt;/p&gt;
&lt;p&gt;Rate limiting là cơ chế quản lý luồng dữ liệu, đặt giới hạn về số lần một người dùng có thể thực hiện hành động trong một khoảng thời gian nhất định. Giống như giới tốc độ trên đường cao tốc, nó ngăn chặn xe (dữ liệu) đi quá nhanh gây tai nạn (máy chủ bị crash).&lt;/p&gt;
&lt;p&gt;Các ứng dụng chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ngăn chặn tấn công DDoS bằng cách phát hiện và chặn các địa chỉ IP gửi lượng yêu cầu bất thường&lt;/li&gt;
&lt;li&gt;Quản lý tài nguyên và chi phí, đảm bảo công bằng giữa các người dùng&lt;/li&gt;
&lt;li&gt;Ngăn chặn tấn công brute force bằng giới hạn số lần thử đăng nhập&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rate limiting là thành phần quan trọng trong việc xây dựng hệ thống phân tán đáng tin cậy&lt;/li&gt;
&lt;li&gt;Ba thuật toán phổ biến: Token Bucket (cho phép traffic đột phá), Leaky Bucket (luồng ổn định), Fixed Window, Sliding Window&lt;/li&gt;
&lt;li&gt;HTTP status code 429 Too Many Requests được dùng khi bị rate limit&lt;/li&gt;
&lt;li&gt;Cần cân bằng giữa bảo mật và trải nghiệm người dùng&lt;/li&gt;
&lt;li&gt;Triển khai tại application layer hoặc middleware layer&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="acid-vs-base-the-system-design-interview"&gt;&lt;a class="link" href="https://designgurus.substack.com/p/acid-vs-base-the-system-design-interview" target="_blank" rel="noopener"
&gt;ACID vs BASE: The System Design Interview&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giải thích sự khác biệt cơ bản giữa hai triết lý thiết kế cơ sở dữ liệu: ACID và BASE - sự đánh đổi giữa tốc độ và độ tin cậy trong các hệ thống phần mềm lớn.&lt;/p&gt;
&lt;p&gt;Mỗi hệ thống lớn phải cân bằng hai yếu tố đối lập: tốc độ và độ tin cậy. Khi thiết kế cơ sở dữ liệu, bạn buộc phải chọn một triết lý: hệ thống là một người hoàn hảo khắt khe đảm bảo tính chính xác tuyệt đối ngay cả khi có nghĩa là chậm lại, hay một hệ thống linh hoạt và cực nhanh ngay cả khi có nghĩa là dữ liệu không được đồng bộ hóa hoàn hảo trong vài giây?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ACID (Người Hoàn Hảo Khắt Khe)&lt;/strong&gt;
Là tiêu chuẩn vàng cho cơ sở dữ liệu quan hệ trong nhiều thập kỷ. ACID ưu tiên tính nhất quán và an toàn trên hết.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Atomicity: Hoàn toàn hoặc không gì cả - giao dịch được xử lý như một đơn vị duy nhất&lt;/li&gt;
&lt;li&gt;Consistency: Tuân thủ quy tắc - đảm bảo dữ liệu chuyển từ trạng thái hợp lệ sang trạng thái hợp lệ khác&lt;/li&gt;
&lt;li&gt;Isolation: Chờ lượt - các giao dịch đồng thời không can thiệp vào nhau&lt;/li&gt;
&lt;li&gt;Durability: Viết bằng đá - dữ liệu được cam kết sẽ tồn tại vĩnh viễn&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hạn chế của ACID là khó mở rộng ngang (horizontal scaling) khi dữ liệu được phân tán trên nhiều máy chủ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BASE (Triết lý cho Big Data)&lt;/strong&gt;
Được tạo ra cho kỷ nguyên Big Data và hệ thống phân tán, thường được sử dụng bởi NoSQL databases.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Basically Available: Hệ thống luôn sẵn sàng cung cấp phản hồi&lt;/li&gt;
&lt;li&gt;Soft State: Trạng thái hệ thống có thể thay đổi theo thời gian ngay cả khi không có đầu vào mới&lt;/li&gt;
&lt;li&gt;Eventual Consistency: Dữ liệu sẽ đồng bộ hóa cuối cùng&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Khi nào nên dùng từng triết lý:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ACID: Hệ thống tài chính, quản lý kho, hồ sơ y tế (nơi tính chính xác là quan trọng)&lt;/li&gt;
&lt;li&gt;BASE: Mạng xã hội, phân tích thời gian thực, phân phối nội dung (nơi tốc độ và khả năng mở rộng quan trọng)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ACID là bi quan: giả định mọi thứ sẽ vỡ nên khóa mọi thứ lại&lt;/li&gt;
&lt;li&gt;BASE là lạc quan: giả định mọi thứ sẽ ổn định nên tiếp tục chạy nhanh&lt;/li&gt;
&lt;li&gt;Sự đánh đổi: bạn thường đánh đổi tính nhất quán ngay lập tức để có sẵn cao và hiệu suất&lt;/li&gt;
&lt;li&gt;Quy tắc quyết định: &amp;ldquo;Nếu dữ liệu sai 2 giây, có ai mất tiền không?&amp;rdquo; - Nếu có thì dùng ACID, nếu không thì BASE&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="hash-tables-in-go-and-advantage-of-self-hosted-compilers"&gt;&lt;a class="link" href="https://rushter.com/blog/go-and-hashmaps/" target="_blank" rel="noopener"
&gt;Hash tables in Go and advantage of self-hosted compilers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết khám phá cách Go triển khai bảng băm (hash table), tập trung vào hiệu quả sử dụng bộ nhớ khi sử dụng &lt;code&gt;map[int]struct{}&lt;/code&gt; so với &lt;code&gt;map[int]bool&lt;/code&gt; để theo dõi các giá trị duy nhất.&lt;/p&gt;
&lt;p&gt;Go thiếu cấu trúc dữ liệu set tích hợp, vì vậy các nhà phát triển sử dụng hash maps để tạo set. Trong các phiên bản trước Go 1.24, việc sử dụng &lt;code&gt;struct{}&lt;/code&gt; giúp tiết kiệm bộ nhớ bằng cách bỏ qua phần giá trị. Tuy nhiên, với Tables Swiss trong Go 1.24, cả hai cách tiếp cận đều có mức sử dụng bộ nhớ giống hệt nhau.&lt;/p&gt;
&lt;p&gt;Điểm thú vị về lưu trữ bộ nhớ:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Các struct cần padding để đảm bảo căn chỉnh bộ nhớ đúng cách&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Lượng bộ nhớ mà một struct sử dụng không luôn bằng tổng của các trường của nó&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết cũng đề cập đến LLM có thể cung cấp thông tin không cập nhật về tối ưu hóa hash table của Go. Trình biên dịch tự托管 (self-hosted) của Go cho phép kiểm tra các chi tiết triển khai, giúp các nhà phát triển hiểu rõ hơn về cách thức hoạt động thực sự của các cấu trúc dữ liệu bên trong.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go thiếu set data structure tích hợp, nên dùng hash maps thay thế&lt;/li&gt;
&lt;li&gt;Go 1.24 với Swiss Tables làm cho cả &lt;code&gt;map[int]struct{}&lt;/code&gt; và &lt;code&gt;map[int]bool&lt;/code&gt; có cùng mức sử dụng bộ nhớ&lt;/li&gt;
&lt;li&gt;Yêu cầu căn chỉnh bộ nhớ có thể ảnh hưởng đến tối ưu hiệu suất&lt;/li&gt;
&lt;li&gt;Cần cân nhắc tính đọc khi chọn giữa &lt;code&gt;bool&lt;/code&gt; và &lt;code&gt;struct{}&lt;/code&gt; implementations&lt;/li&gt;
&lt;li&gt;Trình biên dịch tự托管 của Go giúp kiểm tra chi tiết triển khai&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="gist-of-go-concurrency"&gt;&lt;a class="link" href="https://antonz.org/go-concurrency/" target="_blank" rel="noopener"
&gt;Gist of Go: Concurrency&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một cuốn sách tương tác dạy lập trình đồng thời trong Go thông qua bài tập thực hành, nhắm đến các lập trình viên đã quen thuộc với cơ bản Go. Cuốn sách bao gồm các nguyên lý đồng thời, kỹ thuật đồng bộ hóa và cách tiếp cận kiểm thử với hơn 50 bài tập tự động kiểm tra.&lt;/p&gt;
&lt;p&gt;Điểm khác biệt của cuốn sách này là nó không chỉ giới thiệu về goroutine, channel và select, mà tập trung vào việc giúp người đọc thực sự hiểu và áp dụng các nguyên lý đồng thời. Mỗi bài tập đều đủ đơn giản để có thể giải quyết với một trang mã nhưng lại sát với các kịch bản thực tế.&lt;/p&gt;
&lt;p&gt;Nội dung chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phần 1: Nguyên lý cơ bản - Goroutines, Channels, Pipelines, Time, Context&lt;/li&gt;
&lt;li&gt;Phần 2: Đồng bộ hóa - Wait groups, Data races, Race conditions, Semaphores, Signaling, Atomics&lt;/li&gt;
&lt;li&gt;Phần 3: Các chủ đề khác - Testing, Internals&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Đặc điểm nổi bật:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;500+ ví dụ tương tác&lt;/li&gt;
&lt;li&gt;50 bài tập tự động kiểm tra (có lời giải)&lt;/li&gt;
&lt;li&gt;PDF 448 trang&lt;/li&gt;
&lt;li&gt;Nội dung 100% gốc, không phải do AI tạo ra&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tác giả Anton Zhiyanov đã dựa trên khóa học Go concurrency của mình (250 học viên, đánh giá 5 sao) để tạo ra cuốn sách này, giúp người học nắm vững lập trình đồng thời trong Go một cách thực tế.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tập trung vào hiểu và áp dụng thực tế chứ không chỉ lý thuyết&lt;/li&gt;
&lt;li&gt;Bài tập đơn giản nhưng sát với thực tế&lt;/li&gt;
&lt;li&gt;Kết hợp giữa giải thích rõ ràng và ví dụ cụ thể&lt;/li&gt;
&lt;li&gt;Hỗ trợ đọc trực tuyến và tải PDF&lt;/li&gt;
&lt;li&gt;Phù hợp cho lập trình viên đã biết cơ bản Go&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-state-of-ai-coding-2025--greptile"&gt;&lt;a class="link" href="https://www.greptile.com/state-of-ai-coding-2025" target="_blank" rel="noopener"
&gt;The State of AI Coding 2025 | Greptile&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Báo cáo này là một nghiên cứu đa ngành về các xu hướng gần đây trong phát triển phần mềm AI, khám phá tốc độ đội kỹ sư, việc áp dụng công cụ AI, xu hướng tăng trưởng mô hình và điểm chuẩn hiệu suất.&lt;/p&gt;
&lt;p&gt;Greptile đã thực hiện nghiên cứu này để cung cấp cái nhìn toàn cảnh về trạng thái hiện tại của lập trình AI vào năm 2025. Báo cáo tập trung vào các khía cạnh chính:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tốc độ đội kỹ sư (Engineering Team Velocity)&lt;/strong&gt;
Các công cụ AI đang thay đổi cách các đội kỹ sư làm việc, giúp tăng tốc độ phát triển và cải thiện chất lượng mã nguồn. Nghiên cứu có thể phân tích mức độ cải thiện về thời gian hoàn thành công việc và giảm lỗi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Việc áp dụng công cụ AI (AI Tool Adoption)&lt;/strong&gt;
Xu hướng sử dụng các công cụ AI trong phát triển phần mềm đang tăng mạnh. Báo cáo có thể đưa ra số liệu thống kê về tỷ lệ sử dụng các công cụ AI IDE, trợ lý lập trình và các nền tảng code review tự động.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Xu hướng tăng trưởng mô hình (Model Growth Trends)&lt;/strong&gt;
Các mô hình AI lớn đang phát triển nhanh chóng về cả quy mô và khả năng. Nghiên cứu có thể so sánh các mô hình khác nhau về hiệu suất, chi phí và ứng dụng thực tế.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chuẩn hiệu suất (Performance Benchmarks)&lt;/strong&gt;
Đánh giá hiệu suất của các giải pháp AI coding thông qua các chỉ số như độ chính xác, tốc độ xử lý và khả năng hiểu ngữ cảnh của codebase.&lt;/p&gt;
&lt;p&gt;Báo cáo này cung cấp dữ liệu quý giá cho các nhà phát triển, quản lý dự án và các tổ chức muốn hiểu rõ hơn về cách AI đang định hình tương lai của ngành phát triển phần mềm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nghiên cứu đa ngành về các xu hướng AI trong phát triển phần mềm&lt;/li&gt;
&lt;li&gt;Tập trung vào tốc độ đội kỹ sư, adoption rate, và hiệu suất mô hình&lt;/li&gt;
&lt;li&gt;Cung cấp điểm chuẩn và số liệu thống kê thực tế&lt;/li&gt;
&lt;li&gt;Giúp các tổ chức hiểu rõ tác động của AI đến quy trình phát triển&lt;/li&gt;
&lt;li&gt;Định hướng cho các chiến lược áp dụng AI coding tools&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus"&gt;Bonus
&lt;/h2&gt;&lt;h3 id="images"&gt;Images
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://substackcdn.com/image/fetch/$s_!VQTW!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee73de9e-d2ee-407a-ac6e-93679bdd887d_2250x2624.png"
loading="lazy"
alt="A Guide to Retry Pattern in Distributed Systems"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Đánh giá:&lt;/strong&gt; &lt;em&gt;Tốc độ xử lý urls rất chậm, mình mất cực nhiều thời gian so với trước kia để xử lý 1 url. Tóm tắt khi ngắn khi dài, lại còn đôi khi lẫn lộn kí tự tiếng Trung vào nữa (có vẻ là do model của Z.AI)&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #72</title><link>https://miti99.com/post/2025/12/15/</link><pubDate>Mon, 15 Dec 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/12/15/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #72.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="the-easiest-way-to-build-a-type-checker"&gt;&lt;a class="link" href="https://jimmyhmiller.com/easiest-way-to-build-type-checker" target="_blank" rel="noopener"
&gt;The Easiest Way to Build a Type Checker&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giới thiệu phương pháp kiểm tra kiểu song phương - kết hợp giữa suy luận kiểu và kiểm tra kiểu - như một cách đơn giản và thực tiễn để xây dựng các bộ kiểm tra kiểu. Tác giả cung cấp một triển khai TypeScript tối thiểu cho một ngôn ngữ nhỏ, giải thích các khái niệm cốt lõi như abstract syntax trees, xử lý ngữ cảnh, và xác thực kiểu đệ quy. Phương pháp này giúp làm rõ việc triển khai hệ thống kiểu so với các cách tiếp cận phức tạp hơn như Hindley-Milner.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng phương pháp kiểm tra kiểu song phương kết hợp giữa suy luận và kiểm tra kiểu&lt;/li&gt;
&lt;li&gt;Triển khai ví dụ bằng TypeScript cho một ngôn ngữ nhỏ&lt;/li&gt;
&lt;li&gt;Làm rõ các khái niệm cơ bản: AST, ngữ cảnh, xác thực kiểu đệ quy&lt;/li&gt;
&lt;li&gt;Đơn giản hóa việc hiểu hệ thống kiểu so với các phương pháp phức tạp hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="deprecation"&gt;&lt;a class="link" href="https://abseil.io/resources/swe-book/html/ch15.html" target="_blank" rel="noopener"
&gt;Deprecation&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết nói về việc loại bỏ phần mềm lỗi thời một cách có kế hoạch để giảm chi phí và độ phức tạp trong dài hạn. Google nhấn mạnh rằng &amp;ldquo;mã nguồn là nghĩa vụ, không phải tài sản&amp;rdquo;, và việc loại bỏ phần mềm thành công đòi hỏi sự sở hữu, công cụ hỗ trợ và các mốc rõ ràng. Bài viết phân biệt giữa loại bỏ theo hướng dẫn (khuyến nghị) và loại bỏ bắt buộc (được thực thi), nhấn mạnh rằng việc hỗ trợ di chuyển và ngăn chặn việc sử dụng mới là rất quan trọng. Thiết kế hệ thống với tư tưởng loại bỏ trong tương lai - như cho phép thay thế theo từng phần - sẽ làm cho việc loại bỏ dễ dàng hơn. Mặc dù có những thách thức như định luật Hyrum và sự gắn bó cảm xúc, nhưng các quy trình và công cụ có cấu trúc (ví dụ: phân tích tĩnh, thay đổi quy mô lớn) giúp quản lý các trở ngại kỹ thuật và xã hội.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Loại bỏ phần mềm lỗi thời là cần thiết để giảm chi phí và độ phức tạp dài hạn&lt;/li&gt;
&lt;li&gt;Phân biệt giữa loại bỏ khuyến nghị và loại bỏ bắt buộc&lt;/li&gt;
&lt;li&gt;Cần hỗ trợ di chuyển và ngăn chặn việc sử dụng mới&lt;/li&gt;
&lt;li&gt;Thiết kế hệ thống với tư tưởng loại bỏ trong tương lai sẽ giúp việc thay thế dễ dàng hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="16-replication-concepts-every-software-engineer-should-know-simple-guide-for-2026"&gt;&lt;a class="link" href="https://designgurus.substack.com/p/16-replication-concepts-every-software" target="_blank" rel="noopener"
&gt;16 Replication Concepts Every Software Engineer Should Know (Simple Guide for 2026)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giải thích mười sáu khái niệm nhân bản thiết yếu - bao gồm nhân bản dựa trên người dẫn đầu, nhiều người dẫn đầu và không có người dẫn đầu; các phương pháp đồng bộ và không đồng bộ; hệ thống bỏ phiếu; độ trễ của bản sao; chuyển đổi khi gặp sự cố; nhân bản địa lý; và các kỹ thuật như sửa chữa khi đọc và chuyển tiếp gợi ý - là nền tảng cho các hệ thống phân tán đáng tin cậy và có khả năng mở rộng. Mỗi khái niệm bao gồm một ví dụ thực tế để làm rõ cách áp dụng trong thế giới thực.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Các khái niệm nhân bản thiết yếu như nhân bản dựa trên người dẫn đầu, nhiều người dẫn đầu và không có người dẫn đầu&lt;/li&gt;
&lt;li&gt;Phân biệt giữa các phương pháp đồng bộ và không đồng bộ&lt;/li&gt;
&lt;li&gt;Hệ thống bỏ phiếu và kỹ thuật quản lý độ trễ của bản sao&lt;/li&gt;
&lt;li&gt;Các phương pháp chuyển đổi khi gặp sự cố và nhân bản địa lý&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="50-system-design-concepts-for-beginners-in-90-minutes-"&gt;&lt;a class="link" href="https://designgurus.substack.com/p/50-system-design-concepts-for-beginners" target="_blank" rel="noopener"
&gt;50 System Design Concepts for Beginners in 90 Minutes [2026 Edition]&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết cung cấp cái nhìn tổng quan nhanh chóng và thực tế về 50 khái niệm thiết kế hệ thống thiết yếu cho người mới bắt đầu và ôn tập phỏng vấn. Nội dung bao gồm các nguyên tắc cốt lõi như mở rộng quy mô, định lý CAP/PACELC, ACID so với BASE, và sự đánh đổi giữa độ trễ và thông lượng. Các chủ đề quan trọng bao gồm kiến trúc hệ thống phân tán (microservices, serverless), mạng máy tính (cân bằng tải, CDN, gRPC so với REST), lưu trữ dữ liệu (phân mảnh, nhân bản, đánh chỉ mục), mẫu độ tin cậy (circuit breakers, retry, idempotency), chiến lược lưu trữ đệm, hàng đợi tin nhắn, khả năng quan sát (tracing, SLIs/SLOs), và bảo mật (OAuth, TLS, Zero Trust). Bài viết nhấn mạnh việc hiểu các sự đánh đổi và tính ứng dụng thực tế.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;50 khái niệm thiết kế hệ thống thiết yếu cho người mới bắt đầu&lt;/li&gt;
&lt;li&gt;Các nguyên tắc cốt lõi như mở rộng quy mô, định lý CAP/PACELC, ACID vs BASE&lt;/li&gt;
&lt;li&gt;Các thành phần kiến trúc hệ thống phân tán như microservices, load balancers, CDN&lt;/li&gt;
&lt;li&gt;Các mẫu độ tin cậy và chiến lược lưu trữ đệm&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ddd-a-toolbox-not-a-religion"&gt;&lt;a class="link" href="https://threedots.tech/episode/ddd-toolbox-not-religion" target="_blank" rel="noopener"
&gt;DDD: A Toolbox, Not a Religion&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết nhấn mạnh rằng Domain-Driven Design (DDD) nên được sử dụng một cách thực tiễn - như một tập hợp công cụ để giải quyết sự phức tạp của lĩnh vực nghiệp vụ thực tế, chứ không phải như một giáo điều cứng nhắc. Nội dung cho biết rằng hầu hết các sự cố phần mềm đến từ việc xử lý kém logic nghiệp vụ, chứ không phải từ những lỗi kỹ thuật. Bài viết cảnh báo về việc thiết kế quá mức và giải quyết những vấn đề tưởng tượng, thay vào đó đề xuất việc hiểu rõ lĩnh vực cốt lõi và chỉ áp dụng các mẫu DDD phù hợp. Như Miłosz nói, &amp;ldquo;DDD là về việc hiểu lĩnh vực bạn đang làm việc và sau đó mô hình hóa nó tốt trong code.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DDD nên được coi là một tập hợp công cụ, không phải là một giáo điều&lt;/li&gt;
&lt;li&gt;Hầu hết sự cố phần mềm đến từ việc xử lý logic nghiệp vụ kém, không phải lỗi kỹ thuật&lt;/li&gt;
&lt;li&gt;Tránh thiết kế quá mức và giải quyết vấn đề tưởng tượng&lt;/li&gt;
&lt;li&gt;Chỉ áp dụng các mẫu DDD phù hợp với lĩnh vực nghiệp vụ thực tế&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bonus"&gt;Bonus
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Images:&lt;/strong&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!lwoL!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1ec5785-ad8a-4350-b07d-005f7b04b1f1_2250x2624.png"
loading="lazy"
alt="Saga Pattern Demystified: Orchestration vs Choreography"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!SfCa!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55ac4874-04fc-4ea7-a083-bde8f6f99cf5_2360x2960.png"
loading="lazy"
alt="Virtualization vs. Containerization"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!zlUS!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F156acc80-7588-4fc1-8f43-7fa1458d646c_2360x2770.png"
loading="lazy"
alt="5 REST API Authentication Methods"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!CYiE!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5eb76d35-fba8-48de-84d1-228060740d89_2360x2960.png"
loading="lazy"
alt="What is a Firewall?"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!fKIx!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7278af0a-b8cb-4b72-bd48-341e92286b1b_2360x2960.png"
loading="lazy"
alt="Modem vs. Router"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!zdVq!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60a16dc3-e973-4d2d-a0c2-7d426d5fe6c9_2250x2624.png"
loading="lazy"
alt="A Guide to Service Mesh Architectural Pattern"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!Q7Mr!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73400113-5bd5-4c40-a7e3-7346fb229256_3000x3900.jpeg"
loading="lazy"
alt="What is a REST API?"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!Phtx!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7dce573-ac95-46cc-a80d-62f80e6f0602_800x989.jpeg"
loading="lazy"
alt="How Java HashMaps Work?"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!1-F-!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F473c684e-3c14-44c1-9889-97fef9caef15_2360x2960.png"
loading="lazy"
alt="Virtualization Explained: From Bare Metal to Hosted Hypervisors"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!yDvA!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3c9b76d-b1b9-4284-a64e-16faa832544e_2250x2624.png"
loading="lazy"
alt="Must-Know System Performance Strategies"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!_5Is!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ebf5287-65fa-4db7-8490-54792fd1886c_2360x2920.png"
loading="lazy"
alt="Apache Kafka vs. RabbitMQ"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!1Hk2!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fced11d9e-ce25-439e-9a56-4ccf37c1854f_2360x2770.png"
loading="lazy"
alt="The HTTP Mindmap"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!hn6T!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0f70b08-6fa9-4413-9bd4-0571f99dba60_2360x2664.png"
loading="lazy"
alt="How DNS Works"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!Sny4!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7911abd9-06ce-48f4-98c5-c3305b752fb7_800x1142.jpeg"
loading="lazy"
alt="Can a web server provide real-time updates?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Videos:&lt;/strong&gt;
&lt;a class="link" href="https://www.youtube.com/watch?v=HHUi8F_qAXM" target="_blank" rel="noopener"
&gt;How Does a URL Shortener Work?&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Newsletter #71</title><link>https://miti99.com/post/2025/12/14/</link><pubDate>Sun, 14 Dec 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/12/14/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #71.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="a-modern-guide-to-sql-joins"&gt;&lt;a class="link" href="https://kb.databasedesignbook.com/posts/sql-joins/" target="_blank" rel="noopener"
&gt;A modern guide to SQL JOINs&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết cung cấp hướng dẫn toàn diện về SQL JOINs, tập trung vào làm rõ các mô hình tư duy và tránh những giải thích gây hiểu lầm. Tác giả bắt đầu với LEFT JOIN, nhấn mạnh tầm quan trọng của việc sử dụng cú pháp chuẩn chỉ với các so sánh bằng ID trong điều kiện ON. Hướng dẫn phân biệt ba trường hợp: N:1 (hiệu quả nhất), 1:N (vấn đề), và M:N.&lt;/p&gt;
&lt;p&gt;Nội dung chính bao gồm các điều kiện tiên quyết và thực hành viết SQL có kỷ luật; phân tích LEFT JOIN chi tiết với ví dụ về nhân viên/thanh toán; giải thích INNER JOIN như sản phẩm Cartesian đã được lọc; các kỹ thuật self-join cho dữ liệu phân cấp; các cân nhắc về hiệu suất và sai lầm phổ biến; và các biến thể cú pháp lịch sử cùng cạm bẫy của chúng.&lt;/p&gt;
&lt;p&gt;Tác giả ủng hộ &amp;ldquo;trường hợp N:1 của LEFT JOIN (khóa chính ở bên phải)&amp;rdquo; là phương pháp ưu tiên, lưu ý rằng &amp;ldquo;SQL quá cho phép và không bảo vệ bạn khỏi những sai lầm đơn giản.&amp;rdquo; Hướng dẫn bao gồm các ví dụ thực tế sử dụng cơ sở dữ liệu nhân viên và thanh toán, với tất cả các truy vấn có sẵn trên dbfiddle.uk.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ưu tiên trường hợp N:1 của LEFT JOIN với khóa chính ở bên phải&lt;/li&gt;
&lt;li&gt;Phân biệt rõ ràng giữa các trường hợp N:1, 1:N, và M:N&lt;/li&gt;
&lt;li&gt;SQL quá cho phép, cần kỷ luật khi viết để tránh sai lầm&lt;/li&gt;
&lt;li&gt;Bài viết là công việc đang tiến hành, sẽ cập nhật thêm các phần nâng cao&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="punycode-my-new-favorite-algorithm"&gt;&lt;a class="link" href="https://www.iankduncan.com/engineering/2025-12-01-punycode" target="_blank" rel="noopener"
&gt;Punycode: My New Favorite Algorithm&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết cung cấp phân tích sâu về Punycode, thuật toán cho phép các tên miền quốc tế hóa hoạt động trong cơ sở hạ tầng chỉ hỗ trợ ASCII của DNS. Tác giả giải thích cách Punycode hoạt động thông qua delta encoding, mã hóa base-36 độ dài biến đổi, và điều chỉnh bias thích ứng để đạt được nén hiệu quả cho cả tên miền đơn script và hỗn hợp script.&lt;/p&gt;
&lt;p&gt;Các khái niệm chính bao gồm: vấn đề mã hóa Unicode trong giới hạn của DNS; cách ASCII passthrough, delta encoding, và sắp xếp tối ưu cho các trường hợp phổ biến; hệ thống bias thích ứng thông minh tự động điều chỉnh cho các hệ thống viết khác nhau; chi tiết triển khai bao gồm damping, hằng số skew, và thuộc tính đối xứng; và đặc điểm hiệu suất cũng như lý do mã hóa cố định thất bại.&lt;/p&gt;
&lt;p&gt;Bài viết bao gồm các hình ảnh trực quan tương tác và ví dụ cụ thể cho thấy Punycode xử lý các script khác nhau như Đức, Trung Quốc, Ả Rập, và tên miền hỗn hợp script như thế nào.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Punycode giải quyết vấn đề tên miền Unicode trong cơ sở hạ tầng DNS chỉ hỗ trợ ASCII&lt;/li&gt;
&lt;li&gt;Sử dụng delta encoding và bias thích ứng cho nén hiệu quả&lt;/li&gt;
&lt;li&gt;Hệ thống bias tự điều chỉnh cho các hệ thống viết khác nhau&lt;/li&gt;
&lt;li&gt;Bao gồm các hình ảnh trực quan tương tác và ví dụ thực tế&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="evolution-and-scale-of-uber"&gt;&lt;a class="link" href="https://www.uber.com/en-IN/blog/evolution-and-scale-of-ubers-delivery-search-platform/" target="_blank" rel="noopener"
&gt;Evolution and Scale of Uber&amp;rsquo;s Delivery Search Platform&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chi tiết về việc Uber Eats phát triển hệ thống semantic search để chuyển đổi cách người dùng tìm kiếm nhà hàng, món ăn, và các mặt hàng tạp hóa. Vượt ra ngoài việc matching lexical truyền thống, Uber triển khai kiến trúc neural network hai tháp sử dụng Qwen LLMs làm backbone, được huấn luyện với MRL (Matryoshka Representation Learning) cho các embedding dimensions linh hoạt. Hệ thống xử lý các truy vấn đa ngôn ngữ, từ đồng nghĩa, lỗi chính tả, và hiểu ngữ cảnh trên nhiều vertical.&lt;/p&gt;
&lt;p&gt;Các giải pháp kỹ thuật chính bao gồm Apache Lucene Plus indexing, đồ thị HNSW với các chiến lược quantization (int7 so với float32), và mẫu deployment blue/green đảm bảo cập nhật mô hình an toàn. Nền tảng đạt được hiệu quả chi phí thông qua giảm chiều (256 dimensions với &amp;lt;0.3% chất lượng mất mát) và tối ưu hóa tham số (tuning cấp shard k), trong khi duy trì recall cao (&amp;gt;0.95) và giảm độ trễ hơn 50%.&lt;/p&gt;
&lt;p&gt;Hệ thống tự động retrain và refresh hai tuần một lần, hỗ trợ hàng tỷ ứng cử viên với pre-filtering nhận biết locale và khả năng micro-re-ranking. Thiết kế production-first này cân bằng chất lượng, chi phí, và độ trễ ở quy mô toàn cầu trong khi duy trì độ tin cậy thông qua các kiểm tra xác thực toàn diện.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Semantic search với hai tháp neural network sử dụng Qwen LLMs&lt;/li&gt;
&lt;li&gt;MRL cho embedding dimensions linh hoạt, giảm từ 768 xuống 256 dimensions&lt;/li&gt;
&lt;li&gt;HNSW với quantization int7 để tối ưu hóa chi phí và hiệu suất&lt;/li&gt;
&lt;li&gt;Deployment blue/green và refresh hai tuần một lần để đảm bảo độ tin cậy&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="16-api-gateway-concepts-every-software-engineer-should-know"&gt;&lt;a class="link" href="https://designgurus.substack.com/p/16-api-gateway-concepts-every-software" target="_blank" rel="noopener"
&gt;16 API Gateway Concepts Every Software Engineer Should Know&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết cung cấp phân tích toàn diện về 16 khái niệm API Gateway thiết yếu cho các kỹ sư phần mềm. Nó giải thích cách API Gateway hoạt động như điểm truy cập duy nhất cho microservices, xử lý routing, xác thực, ủy quyền, giới hạn tốc độ, throttling, phân chia traffic, biến đổi request/response, caching, load balancing, circuit breaker, timeout, retry, logging, và monitoring. Mỗi khái niệm bao gồm các ví dụ thực tế cho thấy cách gateway đơn giản hóa tương tác client, tăng cường bảo mật, cải thiện hiệu suất, và đảm bảo độ tin cậy của hệ thống trong các kiến trúc phân tán.&lt;/p&gt;
&lt;p&gt;Bài viết định vị API Gateway là &amp;ldquo;thành phần chiến lược duy nhất quan trọng nhất trong hệ thống phân tán&amp;rdquo; nơi bảo mật, khả năng phục hồi, hiệu suất, và khả năng hiển thị vận hành hội tụ. Các khái niệm được trình bày một cách thực tế, tập trung vào cách chúng giúp các kỹ sư xây dựng các hệ thống phân tán mạnh mẽ và có khả năng mở rộng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API Gateway là điểm truy cập duy nhất cho microservices&lt;/li&gt;
&lt;li&gt;Xử lý routing, xác thực, ủy quyền, rate limiting, và throttling&lt;/li&gt;
&lt;li&gt;Hỗ trợ traffic splitting, transformation, caching, và load balancing&lt;/li&gt;
&lt;li&gt;Bao gồm circuit breaker, timeout, retry, logging, và monitoring&lt;/li&gt;
&lt;li&gt;Là thành phần chiến lược nơi bảo mật, hiệu suất, và khả năng phục hồi hội tụ&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-reddit-migrated-comments-functionality-from-python-to-go"&gt;&lt;a class="link" href="https://blog.bytebytego.com/p/how-reddit-migrated-comments-functionality" target="_blank" rel="noopener"
&gt;How Reddit Migrated Comments Functionality from Python to Go&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chi tiết về việc Reddit di chuyển hệ thống comments từ monolithic Python service sang Go microservices vào năm 2024. Reddit chọn comments làm mục tiêu di chuyển đầu tiên vì đây là dataset lớn nhất với throughput ghi cao nhất. Quá trình di chuyển bao gồm phương pháp &amp;ldquo;tap compare&amp;rdquo; tinh vi cho các thao tác đọc, nơi service Go mới sẽ shadow service Python và so sánh response mà không ảnh hưởng người dùng. Đối với các thao tác ghi, Reddit triển khai &amp;ldquo;sister datastores&amp;rdquo; - các instance Postgres, Memcached, và Redis hoàn toàn biệt lập nơi service Go có thể ghi dữ liệu để xác thực mà không rủi ro data production.&lt;/p&gt;
&lt;p&gt;Đội ngũ đối mặt với các thách thức bao gồm các vấn đề serialization đa ngôn ngữ, sự khác biệt trong pattern truy cập database, và race condition trong quá trình so sánh. Việc di chuyển thành công đạt được mục tiêu, với tất cả comment endpoints giờ chạy trên Go và p99 latency giảm một nửa, từ các spike thỉnh thoảng 15 giây xuống nhất quán dưới 100 mili giây.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reddit di chuyển comments từ Python monolith sang Go microservices&lt;/li&gt;
&lt;li&gt;Sử dụng &amp;ldquo;tap compare&amp;rdquo; cho đọc và &amp;ldquo;sister datastores&amp;rdquo; cho ghi&lt;/li&gt;
&lt;li&gt;Đối mặt với serialization đa ngôn ngữ và race condition&lt;/li&gt;
&lt;li&gt;Thành công: tất cả endpoints chạy trên Go, p99 latency giảm 50%&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="on-idempotency-keys"&gt;&lt;a class="link" href="https://www.morling.dev/blog/on-idempotency-keys/" target="_blank" rel="noopener"
&gt;On Idempotency Keys&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết khám phá idempotency keys trong hệ thống phân tán, cho phép exactly-once processing bằng cách cho phép consumers bỏ qua các messages trùng lặp. Tác giả xem xét ba phương pháp: UUIDs (yêu cầu lưu trữ tất cả các keys đã xử lý), các chuỗi tăng đơn điệu (tiết kiệm không gian nhưng thách thức cho các producers đồng thời), và derivation dựa trên log sử dụng database transaction logs.&lt;/p&gt;
&lt;p&gt;Bài viết kết luận rằng phương pháp tối ưu phụ thuộc vào use case cụ thể, với UUIDs phù hợp cho quy mô nhỏ hơn trong khi các phương pháp dựa trên log cung cấp hiệu quả cho các kịch bản khối lượng lớn dù có thêm phức tạp vận hành. Các khái niệm chính bao gồm exactly-once processing thông qua idempotency keys, yêu cầu xử lý atomic và lưu trữ key, các phương pháp UUIDv4/v7 và ULID, ưu điểm và thách thức đồng thời của chuỗi monotonic, và derivation key dựa trên transaction log sử dụng các công cụ CDC như Debezium.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Idempotency keys cho phép exactly-once processing trong hệ thống phân tán&lt;/li&gt;
&lt;li&gt;Ba phương pháp: UUIDs, chuỗi monotonic, và derivation dựa trên transaction log&lt;/li&gt;
&lt;li&gt;UUIDs phù hợp quy mô nhỏ, log-based hiệu quả cho khối lượng lớn&lt;/li&gt;
&lt;li&gt;Phân tích trade-offs giữa phức tạp vận hành và hiệu quả&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="no-code-reviews-by-default"&gt;&lt;a class="link" href="https://www.raycast.com/blog/no-code-reviews-by-default" target="_blank" rel="noopener"
&gt;No code reviews by default&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết mô tả văn hóa kỹ thuật của Raycast không yêu cầu code reviews bắt buộc. Được xây dựng dựa trên sự tin tưởng, các kỹ sư push trực tiếp vào main branch và chỉ yêu cầu reviews khi cần thiết. Đội ngũ coi trọng trách nhiệm hơn quy ước, tin rằng pull requests làm giảm sự tin tưởng, không ngăn chặn bugs hiệu quả, và làm chậm quá trình phát triển. Họ sử dụng các bản phát hành nội bộ hàng ngày, continuous integration, và feature flags để duy trì chất lượng.&lt;/p&gt;
&lt;p&gt;Phương pháp này cho phép lặp lại nhanh chóng, thu hút các kỹ sư tài năng, và hỗ trợ quy trình làm việc bất đồng bộ của đội ngũ phân tán. Câu trích dẫn chính: &amp;ldquo;Engineers push to the main branch and request reviews when they think it&amp;rsquo;s necessary.&amp;rdquo; Cách tiếp cận này tập trung vào việc trao quyền cho các kỹ sư và xây dựng văn hóa trách nhiệm thay vì dựa vào các quy trình kiểm soát cứng nhắc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Raycast không yêu cầu code reviews bắt buộc, xây dựng trên sự tin tưởng&lt;/li&gt;
&lt;li&gt;Kỹ sư push trực tiếp vào main branch, chỉ request reviews khi cần&lt;/li&gt;
&lt;li&gt;Coi trọng trách nhiệm hơn quy ước, cho phép lặp lại nhanh chóng&lt;/li&gt;
&lt;li&gt;Sử dụng CI/CD và feature flags để duy trì chất lượng&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="estimates--a-necessary-evil"&gt;&lt;a class="link" href="https://thorsell.io/2025/12/07/estimates.html" target="_blank" rel="noopener"
&gt;Estimates – a necessary evil?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết khám phá sự căng thẳng cơ bản giữa product owners và developers liên quan đến việc ước tính phát triển phần mềm. Tác giả xem xét lý do tại sao POs cần ước tính cho việc ưu tiên và lập kế hoạch phát hành, trong khi các nhà phát triển thường ghét cung cấp chúng do sự không chắc chắn và việc coi ước tính là deadlines. Các chủ đề chính bao gồm technical debt như nguồn gốc xung đột, sự không thể đoán trước các vấn đề không lường trước được, và cách ước tính trở thành &amp;ldquo;safety railings&amp;rdquo; khi bị lạm dụng.&lt;/p&gt;
&lt;p&gt;Bài viết gợi ý rằng các khái niệm flow DevOps có thể giúp giảm thiểu rủi ro giao hàng và kết luận rằng giao tiếp và hiểu biết tốt hơn giữa các vai trò là thiết yếu, trong khi thừa nhận thực tế kinh doanh khiến ước tính không thể tránh khỏi trong hầu hết các tổ chức. Tác giả nhấn mạnh sự cần thiết phải cân bằng giữa nhu cầu kinh doanh và thực tế kỹ thuật, cũng như xây dựng sự tin tưởng và minh bạch trong quá trình lập kế hoạch.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sự căng thẳng giữa POs (cần ước tính) và developers (ghét ước tính)&lt;/li&gt;
&lt;li&gt;Technical debt và các vấn đề không lường trước được làm ước tính khó chính xác&lt;/li&gt;
&lt;li&gt;Ước tính trở thành &amp;ldquo;safety railings&amp;rdquo; khi bị coi là deadlines&lt;/li&gt;
&lt;li&gt;Giao tiếp tốt hơn và các khái niệm DevOps flow giúp giảm thiểu rủi ro&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Newsletter #70</title><link>https://miti99.com/post/2025/12/13/</link><pubDate>Sat, 13 Dec 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/12/13/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #70.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="the-developer-productivity-paradox-why-faster-coding-doesn"&gt;&lt;a class="link" href="https://gradle.com/blog/developer-productivity-paradox-faster-coding-slower-delivery/" target="_blank" rel="noopener"
&gt;The developer productivity paradox: Why faster coding doesn&amp;rsquo;t mean faster software delivery&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết khám phá Nghịch lý Năng suất Nhà phát triển, nơi các công cụ AI giúp lập trình nhanh hơn nhưng chỉ số tổ chức lại không cải thiện. Mặc dù 90% nhà phát triển sử dụng AI và 80% cảm thấy năng suất hơn, sự bất ổn hệ thống lại tăng do AI có tỷ lệ dự đoán sai cố hữu. Vấn đề gốc rễ là chuyển đổi ngữ cảnh đã hấp thụ lợi ích năng suất, và AI giới thiệu các gián đoạn mới trong quá trình xác thực và gỡ lỗi. Giải pháp là tổ chức cần Kỹ thuật Năng suất Nhà phát triển (DPE) để củng cố hệ thống phân phối, thiết kế lại quy trình làm việc cho hiệu quả luồng công việc, và thay đổi cách đo lường từ các chỉ số hoạt động sang các chỉ số luồng/kết quả.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;90% nhà phát triển dùng AI nhưng sự bất ổn hệ thống vẫn tăng&lt;/li&gt;
&lt;li&gt;Chuyển đổi ngữ cảnh hấp thụ lợi ích năng suất từ AI&lt;/li&gt;
&lt;li&gt;Cần framework DPE: củng cố hệ thống phân phối, thiết kế lại quy trình làm việc, đo lường kết quả&lt;/li&gt;
&lt;li&gt;Đầu tư vào kỹ thuật nền tảng, vòng lặp phản hồi CI/CD, quản lý luồng giá trị&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-actually-makes-you-senior"&gt;&lt;a class="link" href="https://terriblesoftware.org/2025/11/25/what-actually-makes-you-senior/" target="_blank" rel="noopener"
&gt;What Actually Makes You Senior&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Kỹ năng cốt lõi phân biệt các kỹ sư cấp cao là &lt;strong&gt;giảm thiểu sự mơ hồ&lt;/strong&gt;. Trong khi các kỹ sư cấp trung xuất sắc với các vấn đề được định nghĩa rõ, các kỹ sư cấp cao biến các yêu cầu mơ hồ như &amp;ldquo;cải thiện hiệu suất&amp;rdquo; thành các kế hoạch cụ thể và có thể thực hiện được. Các kỹ sư cấp cao hỏi các câu hỏi quan trọng: &amp;ldquo;Chúng ta thực sự đang cố gắng giải quyết vấn đề gì?&amp;rdquo; và &amp;ldquo;Ai là người dùng ở đây và điều gì gây khó khăn cho họ?&amp;rdquo; Họ xác định các giả định ẩn và đánh giá các nhược điểm tiềm tàng. Giá trị của họ nằm ở việc &lt;strong&gt;giảm thiểu rủi ro dự án&lt;/strong&gt; bằng cách làm cho các vấn đề trừu tượng trở nên cụ thể.&lt;/p&gt;
&lt;p&gt;Bài viết chỉ trích các phương pháp tuyển dụng hiện tại tập trung vào kỹ năng kỹ thuật thay vì giảm thiểu sự mơ hồ, lưu ý rằng nhiều kỹ sư &amp;ldquo;cấp cao&amp;rdquo; có thể giải quyết các vấn đề được định nghĩa rõ nhưng lại bị tê liệt với các thông số kỹ thuật không rõ ràng. Tác giả gợi ý rằng cấp độ cao có thể được phát triển qua thực hành, bắt đầu với các ticket mơ hồ và học cách làm rõ chúng ngay từ đầu thay vì chờ đợi người khác hoặc lập trình ngay lập tức. Công việc cấp cao thường trông vô hình khi làm tốt - các dự án đơn giản chạy trơn tru với ít bất ngờ hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kỹ năng cốt lõi: giảm thiểu sự mơ hồ, không chỉ giải quyết các vấn đề được định nghĩa rõ&lt;/li&gt;
&lt;li&gt;Các kỹ sư cấp cao hỏi &amp;ldquo;Chúng ta thực sự đang giải quyết vấn đề gì?&amp;rdquo; và &amp;ldquo;Ai là người dùng?&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Giá trị nằm ở việc giảm thiểu rủi ro dự án bằng cách làm các vấn đề trừu tượng trở nên cụ thể&lt;/li&gt;
&lt;li&gt;Phương pháp tuyển dụng sai lầm khi tập trung vào kỹ năng kỹ thuật thay vì giảm thiểu sự mơ hồ&lt;/li&gt;
&lt;li&gt;Cấp độ cao có thể phát triển qua thực hành với các ticket mơ hồ&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="becoming-unblockable"&gt;&lt;a class="link" href="https://www.seangoedecke.com/unblockable/" target="_blank" rel="noopener"
&gt;Becoming unblockable&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả cung cấp các chiến lược cụ thể để trở nên &amp;ldquo;không thể bị chặn&amp;rdquo; - duy trì tiến độ về phía trước bất chấp trở ngại. Lời khuyên chính bao gồm: làm việc trên nhiều nhiệm vụ đồng thời để chuyển giữa luồng công việc khi một trong số bị chặn; sắp xếp thứ tự dự án để xử lý các rào cản tiềm tàng sớm (phần gây tranh cãi, các phụ thuộc); ưu tiên môi trường phát triển ổn định sử dụng các công cụ tiêu chuẩn để tối đa hóa thời gian hiệu quả; gỡ lỗi các vấn đề ngoài khu vực trách nhiệm thay vì chờ đợi các đội khác; xây dựng mối quan hệ với các kỹ sư trên các đội khác để có sự hợp tác không chính thức nhanh hơn; tận dụng các quản lý cấp cao làm &amp;ldquo;hỗ trợ từ trên cao&amp;rdquo; để xóa các rào cản tổ chức; và chọn các dự án phù hợp với các ưu tiên của công ty để có sự ủng hộ của nhà điều hành.&lt;/p&gt;
&lt;p&gt;Tác giả nhấn mạnh rằng việc bị chặn thường phụ thuộc vào sự chuẩn bị, các mối quan hệ, và quản lý dự án chiến lược thay vì các hoàn cảnh bên ngoài. Việc trở nên không thể bị chặn không phải là kỹ thuật mà là sự kết hợp của lập kế hoạch, xây dựng mạng lưới, và tư duy chiến lược.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Làm việc trên nhiều nhiệm vụ để chuyển đổi khi bị chặn&lt;/li&gt;
&lt;li&gt;Sắp xếp thứ tự dự án để giải quyết các rào cản sớm&lt;/li&gt;
&lt;li&gt;Môi trường phát triển ổn định với các công cụ tiêu chuẩn&lt;/li&gt;
&lt;li&gt;Gỡ lỗi các vấn đề ngoài trách nhiệm thay vì chờ đợi&lt;/li&gt;
&lt;li&gt;Xây dựng mối quan hệ liên đội để hợp tác nhanh hơn&lt;/li&gt;
&lt;li&gt;Tận dụng các quản lý cấp cao làm hỗ trợ từ trên cao&lt;/li&gt;
&lt;li&gt;Chọn các dự án phù hợp để có sự ủng hộ của nhà điều hành&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="treat-test-code-like-production-code"&gt;&lt;a class="link" href="https://blog.ploeh.dk/2025/12/01/treat-test-code-like-production-code/" target="_blank" rel="noopener"
&gt;Treat test code like production code&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết lập luận rằng mã kiểm thử nên được đối xử với cùng tiêu chuẩn như mã sản xuất vì nó cần bảo trì và khả năng đọc hiểu. Các vấn đề phổ biến trong mã kiểm thử bao gồm vi phạm nguyên tắc DRY, mã zombie, các chờ đợi tùy ý, và xử lý không đồng bộ không phù hợp. Tác giả nhấn mạnh rằng các tiêu chuẩn mã hóa tồn tại chủ yếu cho sự hiểu biết của con người và khả năng bảo trì, không phải cho thực thi máy tính. Vì mã kiểm thử chiếm một phần đáng kể của cơ sở mã, áp dụng các phương pháp tốt như giữ nó DRY ngăn chặn các vấn đề như &amp;ldquo;Phẫu thuật Shotgun&amp;rdquo; nơi các thay đổi yêu cầu sửa đổi trên nhiều bài kiểm thử.&lt;/p&gt;
&lt;p&gt;Bài viết tham khảo các Mẫu Kiểm thử xUnit như là tài nguyên toàn diện cho các phương pháp kiểm thử cụ thể và phản đối quan niệm rằng các bài kiểm thử nên là DAMP thay vì DRY, lưu ý rằng các cụm từ mang tính mô tả và có ý nghĩa không xung đột với việc tránh trùng lặp. Các ngoại lệ tồn tại, đặc biệt trong các phương pháp bảo mật - mã kiểm thử có thể mã hóa cứng mật khẩu và bỏ qua xác thực đầu vào vì nó không được triển khai đến sản xuất. Các miễn lệ đặc thù nền tảng cũng có thể áp dụng, như các quy tắc ConfigureAwait trong .NET hoặc các thể chế mồ côi trong Haskell.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mã kiểm thử cần cùng tiêu chuẩn như mã sản xuất cho khả năng bảo trì&lt;/li&gt;
&lt;li&gt;Các vấn đề phổ biến: vi phạm DRY, mã zombie, chờ đợi tùy ý, không đồng bộ không phù hợp&lt;/li&gt;
&lt;li&gt;Tiêu chuẩn mã hóa phục vụ sự hiểu biết của con người, không phải thực thi máy tính&lt;/li&gt;
&lt;li&gt;Áp dụng DRY trong các bài kiểm thử để ngăn chặn các vấn đề &amp;ldquo;Phẫu thuật Shotgun&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Ngoại lệ cho bảo mật (mã hóa cứng mật khẩu) và các quy tắc đặc thù nền tảng&lt;/li&gt;
&lt;li&gt;Các Mẫu Kiểm thử xUnit là tài nguyên toàn diện cho các phương pháp kiểm thử&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-good-engineers-write-bad-code-at-big-companies"&gt;&lt;a class="link" href="https://www.seangoedecke.com/bad-code-at-big-companies/" target="_blank" rel="noopener"
&gt;How good engineers write bad code at big companies&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giải thích tại sao các công ty công nghệ lớn lại tạo ra mã có chất lượng thấp đáng ngạc nhiên mặc dù tuyển dụng các kỹ sư có năng lực. Lý do chính là &amp;ldquo;các công ty lớn đầy rẫy các kỹ sư làm việc ngoài lĩnh vực chuyên môn của họ&amp;rdquo; do tỷ lệ nghỉ việc cao - hầu hết nhân viên chỉ ở lại &amp;ldquo;một hoặc hai năm&amp;rdquo; trước khi chuyển đến các đội khác hoặc công ty khác. Hầu hết các thay đổi mã được thực hiện bởi những người mới bắt đầu tương đối làm việc trong các cơ sở mã không quen thuộc. Các &amp;ldquo;lão làng&amp;rdquo; có kinh nghiệm bị quá tải và phát triển chuyên môn của họ là không chính thức thay vì có hệ thống.&lt;/p&gt;
&lt;p&gt;Kỹ sư năng lực trung bình có năng lực nhưng &amp;ldquo;cố gắng làm hết sức trong một môi trường không được thiết lập để tạo ra mã chất lượng&amp;rdquo;. Các công ty công nghệ lớn cố tình ưu tiên sự linh hoạt nội bộ hơn chất lượng phần mềm. Các kỹ sư cá nhân không có sức mạnh để thay đổi động lực tổ chức này. Tác giả lập luận rằng mã xấu là không thể tránh khỏi trong các bối cảnh &amp;ldquo;kỹ thuật không thuần túy&amp;rdquo; nơi các kỹ sư làm việc dưới áp lực thời hạn trên các hệ thống không quen thuộc, đối lập với &amp;ldquo;kỹ thuật thuần túy&amp;rdquo; nơi các sai lầm chủ yếu cho thấy sự thiếu năng lực. Nguyên nhân gốc rễ là &amp;ldquo;hầu hết các kỹ sư công ty lớn bị buộc phải làm hầu hết công việc của họ trong các cơ sở mã không quen thuộc.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mã xấu tại các công ty lớn do các kỹ sư làm việc ngoài chuyên môn&lt;/li&gt;
&lt;li&gt;Tỷ lệ nghỉ việc cao: kỹ sư chỉ ở lại 1-2 năm trước khi chuyển đội&lt;/li&gt;
&lt;li&gt;Hầu hết các thay đổi được thực hiện bởi người mới bắt đầu trong các cơ sở mã không quen thuộc&lt;/li&gt;
&lt;li&gt;Các công ty ưu tiên sự linh hoạt hơn chất lượng phần mềm&lt;/li&gt;
&lt;li&gt;Các kỹ sư cá nhân không có sức mạnh để thay đổi động lực tổ chức&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Kỹ thuật không thuần túy&amp;rdquo; với áp限 thời hạn và hệ thống không quen thuộc tạo ra mã xấu&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-success-trap"&gt;&lt;a class="link" href="https://mikefisher.substack.com/p/the-success-trap" target="_blank" rel="noopener"
&gt;The Success Trap&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết khám phá cách thành công có thể nghịch lý lại giới hạn tự do và các lựa chọn. Nghịch lý của Tiến bộ: Thành công cảm thấy như sự mở rộng nhưng thực sự lại thu hẹp các lựa chọn. Khi các cá nhân và tổ chức phát triển, họ đánh đổi tính có thể lựa chọn để tối ưu hóa, chuyển từ khám phá sang bảo vệ. Bẫy Thành công là một trạng thái nơi các thực thể trở nên quá giỏi trong việc khai thác các thế mạnh hiện có đến nỗi họ ngừng khám phá các cơ hội mới. Điều này tạo ra căng thẳng giữa khai thác (cải thiện những gì hoạt động) và khám phá (thử nghiệm những gì có thể hoạt động tiếp theo).&lt;/p&gt;
&lt;p&gt;Các nghiên cứu trường hợp bao gồm: một kỹ sư cấp cao ngừng xây dựng công việc thực hành do thăng tiến sự nghiệp; Kodak thất bại trong việc đón chụp nhiếp ảnh kỹ thuật số mặc dù phát minh ra nó; và Radiohead cố tình tái tạo lại sau &amp;ldquo;OK Computer&amp;rdquo;. Các giải pháp bao gồm: thể chế hóa sự tò mò trong các tổ chức; duy trì nhiều bản sắc và tư duy người mới bắt đầu; đánh giá tốc độ học tập cao hơn sự ổn định hiệu suất; và thực hành &amp;ldquo;quản lý&amp;rdquo; - nắm giữ thành công một cách nhẹ nhàng và tối ưu hóa cho sự đổi mới.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thành công thu hẹp lựa chọn thay vì mở rộng chúng&lt;/li&gt;
&lt;li&gt;Bẫy thành công: quá giỏi khai thác hiện có, ngừng khám phá cơ hội mới&lt;/li&gt;
&lt;li&gt;Căng thẳng giữa khai thác (cải thiện hiện tại) và khám phá (thử nghiệm tương lai)&lt;/li&gt;
&lt;li&gt;Các giải pháp: thể chế hóa tò mò, duy trì tư duy người mới bắt đầu&lt;/li&gt;
&lt;li&gt;Đánh giá tốc độ học tập hơn sự ổn định hiệu suất&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Tự do, không phải thành tựu, là thước đo thành công thực sự&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="writing-a-good-claudemd"&gt;&lt;a class="link" href="https://www.humanlayer.dev/blog/writing-a-good-claude-md" target="_blank" rel="noopener"
&gt;Writing a good CLAUDE.md&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giải thích rằng các tệp &lt;code&gt;CLAUDE.md&lt;/code&gt; rất quan trọng để đưa Claude vào làm quen với cơ sở mã của bạn vì các LLM không có trạng thái và không biết gì về dự án của bạn khi bắt đầu phiên. Tệp nên bao gồm &lt;strong&gt;CÁI GÌ&lt;/strong&gt; (ngăn xếp công nghệ, cấu trúc), &lt;strong&gt;TẠI SAO&lt;/strong&gt; (mục đích), và &lt;strong&gt;LÀM THẾ NÀO&lt;/strong&gt; (phương pháp làm việc) của dự án.&lt;/p&gt;
&lt;p&gt;Các khuyến nghị chính bao gồm: ít hơn là nhiều hơn - giữ hướng dẫn tối thiểu vì các LLM có thể tuân theo khoảng 150-200 hướng dẫn một cách nhất quán, với các mô hình nhỏ hơn cho thấy sự suy giảm hiệu suất theo cấp số nhân; giữ nó súc tích - nhắm mục tiêu dưới 300 dòng, lý tưởng là dưới 60 dòng như cách tiếp cận của HumanLayer; tính phổ quát - chỉ bao gồm các hướng dẫn liên quan đến tất cả các nhiệm vụ để ngăn Claude bỏ qua nội dung; tiết lộ tiến bộ - lưu trữ các hướng dẫn cụ thể của nhiệm vụ trong các tệp riêng biệt và tham chiếu chúng thay vì bao gồm mọi thứ trong &lt;code&gt;CLAUDE.md&lt;/code&gt;; tránh sử dụng Claude làm công cụ lint - sử dụng các công cụ lint truyền thống thay vì thực thi kiểu mã dựa trên LLM tốn kém; và tạo thủ công - không tự động tạo &lt;code&gt;CLAUDE.md&lt;/code&gt; vì nó là &amp;ldquo;điểm đòn bẩy cao nhất của bộ điều khiển&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Bài viết lưu ý rằng Claude thường bỏ qua &lt;code&gt;CLAUDE.md&lt;/code&gt; khi cho rằng nội dung không liên quan, được củng cố bởi các lời nhắc hệ thống nói với Claude không phản hồi trừ khi &amp;ldquo;rất liên quan đến nhiệm vụ của bạn.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CLAUDE.md cần thiết để onboarding Claude vào codebase&lt;/li&gt;
&lt;li&gt;LLM có thể tuân theo 150-200 hướng dẫn nhất quán&lt;/li&gt;
&lt;li&gt;Giữ dưới 300 dòng, lý tưởng dưới 60 dòng&lt;/li&gt;
&lt;li&gt;Chỉ bao gồm hướng dẫn phổ quát cho tất cả các nhiệm vụ&lt;/li&gt;
&lt;li&gt;Sử dụng tiết lộ tiến bộ - tham chiếu các tệp riêng biệt&lt;/li&gt;
&lt;li&gt;Không tự động tạo - tạo thủ công là điểm đòn bẩy cao nhất&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="we-should-all-be-using-dependency-cooldowns"&gt;&lt;a class="link" href="https://blog.yossarian.net/2025/11/21/We-should-all-be-using-dependency-cooldowns" target="_blank" rel="noopener"
&gt;We should all be using dependency cooldowns&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết lập luận rằng các thời gian chờ phụ thuộc là một cách miễn phí, dễ dàng và cực kỳ hiệu quả để giảm thiểu phần lớn các cuộc tấn công chuỗi cung ứng mã nguồn mở. Tác giả phân tích dòng thời gian tấn công điển hình, cho thấy cơ hội của kẻ tấn công thường rất nhỏ - thường chỉ vài giờ đến vài ngày giữa việc phát hành các gói độc hại và việc chúng bị loại bỏ bởi các kho lưu trữ thượng nguồn.&lt;/p&gt;
&lt;p&gt;Các cuộc tấn công chuỗi cung cấp hầu hết tuân theo một mô hình tương tự: xâm phạm → phát hành phiên bản độc hại → người dùng tự động cập nhật → nhà cung cấp phát hiện → thượng nguồn loại bỏ. Các cửa sổ tấn công thường dưới một tuần (8/10 cuộc tấn công được phân tích là &amp;lt;7 ngày). Cuộc tấn công xz-utils là một trường hợp ngoại lệ đáng kể với khoảng 5 tuần.&lt;/p&gt;
&lt;p&gt;Các thời gian chờ trì hoãn cập nhật phụ thuộc theo một khoảng thời gian nhất định, cho phép các nhà cung cấp bảo mật xác định các mối đe dọa trước khi người dùng áp dụng chúng. Đơn giản để thực hiện với cấu hình như &lt;code&gt;cooldown: default-days: 7&lt;/code&gt;. Lợi ích bao gồm: hiệu quả thực nghiệm chống lại các cuộc tấn công có tầm nhìn cao; miễn phí để thực hiện với các công cụ như Dependabot, Renovate; khuyến khích hành vi tích cực từ các nhà cung cấp bảo mật; và có thể ngăn chặn 80-90% sự tiếp xúc với nỗ lực tối thiểu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phụ thuộc cooldown miễn phí, dễ dàng và hiệu quả chống tấn công chuỗi cung ứng&lt;/li&gt;
&lt;li&gt;Cửa sổ tấn công thường dưới 7 ngày cho hầu hết các cuộc tấn công&lt;/li&gt;
&lt;li&gt;Đơn giản thực hiện: chỉ cần cấu hình cooldown days&lt;/li&gt;
&lt;li&gt;Miễn phí với Dependabot, Renovate và các công cụ tương tự&lt;/li&gt;
&lt;li&gt;Có thể ngăn chặn 80-90% sự tiếp xúc với nỗ lực tối thiểu&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Newsletter #69</title><link>https://miti99.com/post/2025/12/12/</link><pubDate>Fri, 12 Dec 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/12/12/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #69. Bài viết này được thực hiện bởi &lt;a class="link" href="https://github.com/anthropics/claude-code" target="_blank" rel="noopener"
&gt;Claude Code&lt;/a&gt;, &lt;a class="link" href="https://github.com/musistudio/claude-code-router" target="_blank" rel="noopener"
&gt;Claude Code Router&lt;/a&gt;, &lt;a class="link" href="https://platform.iflow.cn" target="_blank" rel="noopener"
&gt;iFlow Open Platform&lt;/a&gt; &amp;amp; GLM-4.6&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="netflix-xây-dựng-đồ-thị-phân-phân-phối-thời-gian-thực-phần-1"&gt;&lt;a class="link" href="https://netflixtechblog.com/how-and-why-netflix-built-a-real-time-distributed-graph-part-1-ingesting-and-processing-data-80113e124acc" target="_blank" rel="noopener"
&gt;Netflix Xây Dựng Đồ Thị Phân Phân Phối Thời Gian Thực (Phần 1)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Netflix phát triển hệ thống Đồ Thị Phân Phối Thời gian Thực (RDG) để giải quyết vấn đề dữ liệu phân mảnh từ kiến trúc microservices. Hệ thống xử lý khoảng 1 triệu tin nhắn mỗi giây từ Kafka, chuyển đổi thành các nút và cạnh đồ thị bằng Apache Flink. RDG giúp kết nối các hoạt động người dùng trên nhiều thiết bị và dịch vụ (video, game, quảng cáo) trong thời gian thực, cho phép phân tích mối quan hệ phức tạp mà không cần truy vấn JOIN tốn kém.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xử lý 1 triệu messages/giây từ Kafka stream&lt;/li&gt;
&lt;li&gt;Sử dụng Apache Flink để transform dữ liệu thành graph&lt;/li&gt;
&lt;li&gt;Kết nối activities trên multiple devices và services&lt;/li&gt;
&lt;li&gt;Tránh expensive JOIN queries trong distributed systems&lt;/li&gt;
&lt;li&gt;Hỗ trợ real-time analysis cho user behavior patterns&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bắt-nhỏ-vươn-lớn-giá-trị-thực-sự-của-kiến-trúc-tăng-dần"&gt;&lt;a class="link" href="https://newsletter.optimistengineer.com/p/incremental-architecture-what-you" target="_blank" rel="noopener"
&gt;Bắt Nhỏ Vươn Lớn: Giá Trị Thực Sự Của Kiến Trúc Tăng Dần&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Kiến trúc tăng dần (incremental architecture) là một phương pháp tiếp cận giúp hệ thống phát triển và tiến hóa một cách linh hoạt. Trọng tâm của phương pháp này là tổ chức đội ngũ cross-functional với quyền sở hữu domain rõ ràng, thay vì chỉ tập trung vào công nghệ. Vai trò của architect không phải là áp đặt diagram, mà là đào tạo và duy trì sự nhất quán trong toàn bộ hệ thống. Thay vì hỏi &amp;ldquo;mất bao lâu để hoàn thành&amp;rdquo;, chúng ta nên chuyển sang câu hỏi &amp;ldquo;có thể làm cho nó nhỏ hơn được không?&amp;rdquo;. Vòng lặp build-ship-feedback-adjust-repeat giúp liên tục cải tiến, với các pattern như layered, hexagonal, và distributed architecture được áp dụng khi giải quyết vấn đề thực tế. Component architecture với ranh giới rõ ràng cho phép trích xuất microservice dễ dàng, trong khi event-driven architecture giảm coupling thông qua event emitters. Domain-driven design với ubiquitous language giúp tăng tốc độ thay đổi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ưu tiên tổ chức team hơn là công nghệ&lt;/li&gt;
&lt;li&gt;Cross-functional teams với domain ownership&lt;/li&gt;
&lt;li&gt;Architect vai trò là teaching và maintaining coherence&lt;/li&gt;
&lt;li&gt;Build-ship-feedback-adjust-repeat loop cho continuous improvement&lt;/li&gt;
&lt;li&gt;Component architecture với hard boundaries&lt;/li&gt;
&lt;li&gt;Event-driven architecture giảm coupling&lt;/li&gt;
&lt;li&gt;Domain-driven design với ubiquitous language&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="java-interview-question---why-collection-doesn"&gt;&lt;a class="link" href="https://javabulletin.substack.com/p/java-interview-question-why-collection" target="_blank" rel="noopener"
&gt;Java Interview Question - Why Collection doesn&amp;rsquo;t extend Cloneable and Serializable interfaces?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Java có thiết kế cẩn thận khi không để Collection interface kế thừa từ Cloneable và Serializable. Lý do chính là vì không phải tất cả collections đều có thể clone hoặc serialize một cách có ý nghĩa. Ví dụ, Collections.unmodifiableList() không thể được clone vì nó chỉ là một wrapper. Một số collections chứa dữ liệu không serializable hoặc các items không hỗ trợ serialization. Cả hai interface này đều được coi là design flaws ngày nay vì chúng là marker interfaces mà không định nghĩa behavior rõ ràng. Thay vào đó, các lớp collection cụ thể sẽ tự quyết định implement các interface này chỉ khi thực sự phù hợp, giúp maintain tính linh hoạt và clean design cho framework.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không phải tất cả collections đều có thể clone/serialize có ý nghĩa&lt;/li&gt;
&lt;li&gt;Unmodifiable collections không thể clone được&lt;/li&gt;
&lt;li&gt;Collections có thể chứa non-serializable items&lt;/li&gt;
&lt;li&gt;Cloneable và Serializable là marker interfaces bị coi là design flaws&lt;/li&gt;
&lt;li&gt;Individual collection classes tự quyết định implement khi phù hợp&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="we-stopped-roadmap-work-for-a-week-and-fixed-189-bugs"&gt;&lt;a class="link" href="https://lalitm.com/fixits-are-good-for-the-soul/" target="_blank" rel="noopener"
&gt;We stopped roadmap work for a week and fixed 189 bugs&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Fixit Weeks là các đợt bug fixing định kỳ hàng quý, nơi toàn bộ đội ngũ tạm dừng công việc theo roadmap để tập trung sửa lỗi. Trong một tuần, 40 kỹ sư đã sửa thành công 189 bugs với giới hạn tối đa 2 ngày cho mỗi bug để tránh scope creep. Chương trình áp dụng gamification với điểm số, bảng xếp hạng và áo thun để tạo động lực. Việc này không chỉ cải thiện sản phẩm mà còn mang lại cảm giác thành tựu cho developer - thấy bug, sửa nó, và ship ngay lập tức. Sự chuẩn bị kỹ lưỡng với việc tag và phân loại bugs quanh năm là yếu tố quan trọng. Công cụ AI đã giúp giảm thiểu vấn đề context switching, cho phép developer chuyển đổi giữa tasks mượt mà hơn. Một feature request tồn tại 4 năm đã được giải quyết chỉ trong một ngày, cho thấy sức mạnh của sự tập trung tập thể.&lt;/p&gt;
&lt;h2 id="the-math-of-why-you-can"&gt;&lt;a class="link" href="https://justoffbyone.com/posts/math-of-why-you-cant-focus-at-work/" target="_blank" rel="noopener"
&gt;The Math of Why You Can&amp;rsquo;t Focus at Work&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Năng suất làm việc được quyết định bởi ba tham số toán học: λ (số lần gián đoạn mỗi giờ), Δ (thời gian phục hồi sau gián đoạn tính bằng phút), và θ (kích thước tối thiểu của một khối tập trung cần thiết cho công việc có ý nghĩa). Nghiên cứu cho thấy nhân viên đối mặt với gián đoạn mỗi 2-3 phút và cần 10-16 phút để phục hồi lại sự tập trung. Deep work yêu cầu các khối thời gian không bị gián đoạn; thời gian bị phân mảnh không thể tích lũy hiệu quả. Sự thay đổi nhỏ trong các tham số có thể tác động mạnh mẽ đến năng suất: việc giảm λ từ 3 xuống 2 (chỉ một lần gián đoạn ít hơn mỗi giờ) có thể thay đổi cả tuần làm việc của bạn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Productivity được quyết định bởi 3 tham số: λ (gián đoạn/giờ), Δ (thời gian phục hồi), θ (kích thước khối focus tối thiểu)&lt;/li&gt;
&lt;li&gt;Worker bị gián đoạn mỗi 2-3 phút, cần 10-16 phút để recover&lt;/li&gt;
&lt;li&gt;Deep work cần uninterrupted blocks, fragmented time không hiệu quả&lt;/li&gt;
&lt;li&gt;Giảm chỉ 1 interruption/giờ có thể transform năng suất cả tuần&lt;/li&gt;
&lt;li&gt;Giải pháp: giảm λ (protect calendar), match θ với environment (break tasks), giảm Δ (context breadcrumbs)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tech-predictions-for-2026-and-beyond"&gt;&lt;a class="link" href="https://www.allthingsdistributed.com/2025/11/tech-predictions-for-2026-and-beyond.html" target="_blank" rel="noopener"
&gt;Tech predictions for 2026 and beyond&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này đưa ra năm dự báo công nghệ quan trọng cho 2026 và tương lai. Đầu tiên là cuộc cách mạng đồng hành (companionship revolution) khi AI vật lý sẽ chống lại đại dịch cô đơn toàn cầu, với nghiên cứu cho thấy 95% tương tác có lợi cho bệnh nhân dementia. Thứ hai, thế hệ &amp;ldquo;renaissance developer&amp;rdquo; sẽ kết hợp sáng tạo, tư duy hệ thống và chuyên môn domain khi AI xử lý các tác vụ lập trình thường ngày. Thứ ba, bảo mật an toàn lượng tử (quantum-safe security) trở nên cấp bách khi mã hóa RSA 2048-bit có thể bị phá vỡ trong 5 năm. Thứ tư, công nghệ quốc phòng sẽ được ứng dụng dân dụng trong 2 năm thay vì hàng thập kỷ. Cuối cùng, học tập cá nhân hóa với AI将成为 phổ biến với chi phí chỉ 4$/tháng, giúp giáo viên tập trung vào việc giảng dạy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI vật lý chống lại cô đơn, 95% tương tác có lợi cho bệnh nhân dementia&lt;/li&gt;
&lt;li&gt;Renaissance developer kết hợp creativity, systems thinking và domain expertise&lt;/li&gt;
&lt;li&gt;RSA 2048-bit có thể bị phá vỡ trong 5 năm bởi quantum computing&lt;/li&gt;
&lt;li&gt;Công nghệ quốc phòng ứng dụng dân dụng trong 2 năm thay vì hàng thập kỷ&lt;/li&gt;
&lt;li&gt;AI tutoring cá nhân hóa với chi phí 4$/tháng&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-i-still-love-linux"&gt;&lt;a class="link" href="https://it-notes.dragas.net/2025/11/24/why-i-still-love-linux/" target="_blank" rel="noopener"
&gt;Why I (still) love Linux&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả chia sẻ hành trình 30 năm với Linux, bắt đầu từ năm 1996 khi Linux mang lại cảm giác tự do tuyệt đối với command line và sức mạnh của Unix. Dù hiện tác giả ưa thích BSD và illumos hơn vì triết lý thiết kế, ông vẫn yêu Linux vì nó là dự án Open Source đầu tiên thành công toàn cầu và đã trở thành nền tảng cho vô số thiết bị từ smartphone đến xe hơi. Linux đã dạy ông tư duy out-of-the-box và mang lại cơ hội nghề nghiệp. Dù có những vấn đề hiện đại như systemd đi chệch khỏi triết lý Unix &amp;ldquo;do one thing and do it well&amp;rdquo;, hay áp lực từ các công ty định hướng phát triển, Linux vẫn là người bạn đồng hành đáng tin cậy, với hardware support tốt hơn và các distribution như Alpine, openSUSE vẫn giữ được tính minimalism.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Linux mang lại cảm giác tự do với command line và Unix philosophy từ năm 1996&lt;/li&gt;
&lt;li&gt;Dù không phải lựa chọn đầu tiên, Linux vẫn quan trọng vì thành công toàn cầu và ubiquity&lt;/li&gt;
&lt;li&gt;Vấn đề hiện đại: systemd, &amp;ldquo;move fast and break things&amp;rdquo;, mất đi Unix philosophy&lt;/li&gt;
&lt;li&gt;Hardware support cải thiện vượt trội, hiếm khi gặp incompatible hardware&lt;/li&gt;
&lt;li&gt;Các distribution như Alpine, openSUSE vẫn giữ được triết lý minimalism và stability&lt;/li&gt;
&lt;li&gt;Linux đã là người bạn đồng hành 30 năm và sẽ tiếp tục trong tương lai&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-senior-engineers-struggle-to-build-ai-agents"&gt;&lt;a class="link" href="https://www.philschmid.de/why-engineers-struggle-building-agents" target="_blank" rel="noopener"
&gt;Why (Senior) Engineers Struggle to Build AI Agents&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích tại sao các kỹ sư senior lại gặp khó khăn khi xây dựng AI agents so với junior engineers. Vấn đề cốt lõi là software engineering truyền thống mang tính xác định (deterministic), trong khi AI agents hoạt động theo xác suất (probabilistic). Junior engineers thường ship agents nhanh hơn vì họ tin tưởng vào model hơn, trong khi senior engineers cố gắng &amp;ldquo;code away&amp;rdquo; bản chất xác suất của model. Bài viết giới thiệu 5 thách thức chính: (1) Text là trạng thái mới - cần bảo toàn context ngôn ngữ tự nhiên thay vì ép vào cấu trúc binary, (2) Giao quyền kiểm soát - tin tưởng agents điều hướng conversation flows thay vì hard-code paths, (3) Lỗi chỉ là inputs - feed errors lại cho agents để recovery thay vì crash, (4) Từ unit tests đến evals - đánh giá reliability và quality thay vì correctness binary, và (5) Agents tiến hóa, APIs không - thiết kế semantic typing &amp;ldquo;idiot-proof&amp;rdquo; cho các agents literalist.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Software engineering deterministic vs AI agents probabilistic&lt;/li&gt;
&lt;li&gt;Junior engineers ship nhanh hơn vì trust model hơn&lt;/li&gt;
&lt;li&gt;Senior engineers cố gắng &amp;ldquo;code away&amp;rdquo; probabilistic nature&lt;/li&gt;
&lt;li&gt;5 thách thức: Text as state, Hand over control, Errors as inputs, Unit tests to evals, Agents evolve&lt;/li&gt;
&lt;li&gt;Engineers cần trade certainty cho semantic flexibility&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-java-achieves-zero-copy-file-transfer"&gt;&lt;a class="link" href="https://javabulletin.substack.com/p/how-java-achieves-zero-copy-file" target="_blank" rel="noopener"
&gt;How Java Achieves Zero-Copy File Transfer&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Zero-copy là kỹ thuật truyền file từ đĩa đến network socket mà giảm thiểu việc sao chép trong user-space và giảm tải CPU. Thay vì phương pháp truyền thống phải copy dữ liệu qua nhiều lớp (Disk → Kernel → User Buffer → Java Heap), zero-copy cho phép OS di chuyển dữ liệu trực tiếp giữa các kernel buffer. Điều này giảm đáng kể số lần context switch và áp lực lên băng thông bộ nhớ. Java cung cấp ba cách triển khai chính: FileChannel.transferTo/transferFrom() sử dụng syscall sendFile, memory-mapped files với MappedByteBuffer, và Netty&amp;rsquo;s DefaultFileRegion cho high-performance servers. Kỹ thuật này đặc biệt hữu ích cho việc truyền file lớn, các server I/O-heavy, và giúp giảm áp lực garbage collection. Tuy nhiên, zero-copy không hoạt động với TLS/HTTPS vì encryption cần truy cập user-space, và không hiệu quả với các file nhỏ do overhead của syscall.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Zero-copy giảm user-space copies và CPU overhead&lt;/li&gt;
&lt;li&gt;Data flow trực tiếp: file → kernel page cache → socket buffer → NIC&lt;/li&gt;
&lt;li&gt;Java implementations: FileChannel.transferTo, MappedByteBuffer, Netty DefaultFileRegion&lt;/li&gt;
&lt;li&gt;Lợi ích: lower CPU usage, higher throughput, giảm GC pressure&lt;/li&gt;
&lt;li&gt;Limitations: không hoạt động với TLS/HTTPS, không hiệu quả với small files&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bonus"&gt;Bonus
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Images:&lt;/strong&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/20ed383c-5900-4f31-9041-afb5581b1ad4_2250x2624.png"
loading="lazy"
alt="Top Strategies to Build High Availability Systems"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!Eyti!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F862d0649-d77b-410f-95a5-6505c9eeb15a_2250x2814.png"
loading="lazy"
alt="Cloudflare vs. AWS vs. Azure"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!52bX!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65613a28-2320-4bb6-a610-5ab96b13240d_800x903.jpeg"
loading="lazy"
alt="Popular Backend Tech Stack"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!JV_9!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa95473e0-5a68-43c6-841e-540a6b198d6d_2360x2960.png"
loading="lazy"
alt="HTTP vs. HTTPS"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!5rGo!,w_550,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac99f98d-49a7-4933-b06f-8da0901d210e_800x939.gif"
loading="lazy"
alt="Forward Proxy versus Reverse Proxy"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!qtkE!,w_550,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4646c2e2-a6fb-44e7-a091-73fcbd8fa498_800x1040.gif"
loading="lazy"
alt="Things Every Developer Should Know: Concurrency is NOT parallelism"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #68</title><link>https://miti99.com/post/2025/12/11/</link><pubDate>Thu, 11 Dec 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/12/11/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #68. Bài viết này được thực hiện bởi &lt;a class="link" href="https://github.com/anthropics/claude-code" target="_blank" rel="noopener"
&gt;Claude Code&lt;/a&gt;, &lt;a class="link" href="https://github.com/musistudio/claude-code-router" target="_blank" rel="noopener"
&gt;Claude Code Router&lt;/a&gt;, &lt;a class="link" href="https://platform.iflow.cn" target="_blank" rel="noopener"
&gt;iFlow Open Platform&lt;/a&gt; &amp;amp; GLM-4.6 (Bài này mình config CCR dùng nhiều models trên iFlow Platform)&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="conscious-debugging-10-chiến-lược-hiệu-quả-thực-sự-hoạt-động-"&gt;&lt;a class="link" href="https://thetshaped.dev/p/conscious-debugging-10-effective-debugging-strategies-debug-like-pro" target="_blank" rel="noopener"
&gt;Conscious Debugging: 10 Chiến lược Hiệu quả Thực sự Hoạt động 🐛&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết cung cấp cho developer mới vào nghề một bộ công cụ có hệ thống để tiếp cận việc gỡ lỗi (debugging) một cách hiệu quả và bớt căng thẳng. Tác giả nhấn mạnh rằng debugging là kỹ năng có thể rèn luyện, không chỉ dựa vào may mắn hay kinh nghiệm thuần túy. Quá trình này bắt đầu từ việc tái tạo lỗi một cách nhất quán và nhanh chóng, sau đó thu thập đầy đủ ngữ cảnh (context) liên quan đến sự cố. Khi đã có nền tảng, developer nên chủ động thu hẹp phạm vi vấn đề bằng các kỹ thuật như chia đôi (binary search) hoặc sử dụng debugger tích hợp sẵn trong IDE. Bài viết cũng khuyến khích tư duy khoa học khi đưa ra và kiểm chứng giả thuyết, đồng thời không xem nhẹ vai trò của việc nghỉ ngơi hợp lý hay giải thích vấn đề cho người khác (rubber duck debugging).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Mastering debugging can save you time, energy, frustrations, and money&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tái tạo lỗi một cách nhất quán và nhanh chóng&lt;/strong&gt; để làm nền tảng cho mọi thao tác tiếp theo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thu thập đầy đủ context&lt;/strong&gt; từ logs, session recordings, hoặc phản hồi người dùng trước khi đi sâu vào code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cô lập vấn đề&lt;/strong&gt; bằng cách áp dụng phương pháp chia đôi để nhanh chóng khoanh vùng nguyên nhân.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sử dụng debugger và rubber duck debugging&lt;/strong&gt; như những công cụ hỗ trợ tư duy chủ động.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nghỉ giải lao chiến lược&lt;/strong&gt; và &lt;strong&gt;tận dụng AI một cách thông minh&lt;/strong&gt;, cung cấp đủ thông tin để nhận được hỗ trợ hiệu quả.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-fate-of"&gt;&lt;a class="link" href="https://nolanlawson.com/2025/11/16/the-fate-of-small-open-source/" target="_blank" rel="noopener"
&gt;The fate of &amp;ldquo;small&amp;rdquo; open source&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Nolan Lawson bàn về tương lai mờ nhạt của các thư viện open source nhỏ (như &lt;code&gt;blob-util&lt;/code&gt;) trong kỷ nguyên LLM. Trước đây, những gói này không chỉ giải quyết vấn đề kỹ thuật mà còn mang tính giáo dục—giúp developer hiểu sâu cách hoạt động của nền tảng. Tuy nhiên, khi LLM có thể sinh code theo yêu cầu ngay lập tức, nhiều người chọn tự tạo hàm thay vì dùng dependency, dẫn đến nguy cơ mai một các dự án nhỏ dù chúng đã được kiểm chứng qua thời gian. Tác giả lo ngại xu hướng này làm giảm cơ hội học hỏi và chia sẻ kiến thức trong cộng đồng.&lt;/p&gt;
&lt;p&gt;Dù vậy, Lawson vẫn lạc quan rằng open source vẫn còn đất sống ở những lĩnh vực LLM chưa chạm tới: dự án lớn, sáng tạo, hoặc chuyên sâu như phát hiện memory leak (&lt;code&gt;fuite&lt;/code&gt;). Giá trị mới nằm ở sự đổi mới và nghiên cứu—điều mà AI hiện tại khó thay thế.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Các utility library nhỏ (vd: &lt;code&gt;blob-util&lt;/code&gt;) đang dần bị thay thế bởi code do LLM sinh ra.&lt;/li&gt;
&lt;li&gt;Thư viện open source truyền thống thường đi kèm tư duy &amp;ldquo;dạy học&amp;rdquo;, điều mà LLM thiếu.&lt;/li&gt;
&lt;li&gt;Dùng LLM để sinh code có thể làm tăng technical debt và giảm khả năng maintain.&lt;/li&gt;
&lt;li&gt;Cơ hội open source hiện nay nằm ở các dự án đòi hỏi research, creativity hoặc niche knowledge.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Era of small, low-value libraries&amp;hellip; is over&amp;rdquo;—LLMs là &amp;ldquo;the final nail in the coffin.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ngôn-ngữ-lập-trình-trong-kỷ-nguyên-ai-agent"&gt;&lt;a class="link" href="https://alexn.org/blog/2025/11/16/programming-languages-in-the-age-of-ai-agents/" target="_blank" rel="noopener"
&gt;Ngôn ngữ lập trình trong kỷ nguyên AI Agent&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bối cảnh AI Agent ngày càng phổ biến trong viết mã, nhiều người lo ngại rằng sự đa dạng ngôn ngữ lập trình sẽ thu hẹp lại chỉ còn top 5 ngôn ngữ được huấn luyện nhiều nhất. Tuy nhiên, bài viết lập luận rằng lựa chọn ngôn ngữ vẫn quan trọng—đặc biệt với các developer trẻ. Một hệ thống type tĩnh mạnh mẽ (như trong Scala, Rust hay Haskell) giúp AI nhanh chóng sửa lỗi nhờ phản hồi từ compiler, giảm &amp;ldquo;hallucination&amp;rdquo; và tăng độ tin cậy. Ngoài ra, khả năng &lt;strong&gt;review và hiểu code do AI sinh ra&lt;/strong&gt; là thiết yếu để tránh &amp;ldquo;comprehension debt&amp;rdquo;—tình trạng mất tri thức khi không ai còn hiểu sâu về hệ thống.&lt;/p&gt;
&lt;p&gt;Dù AI có thể tạo ra code chạy được, nguồn gốc sự thật vẫn là &lt;strong&gt;source code&lt;/strong&gt;, và việc duy trì kiến trúc rõ ràng, biểu đạt ý định thiết kế (intent) qua code chất lượng cao—đặc biệt theo phong cách functional programming—vẫn cực kỳ giá trị. Lập luận suy diễn (deductive reasoning) và equational reasoning giúp con người kiểm chứng logic mà AI không thể đảm bảo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ngôn ngữ có &lt;strong&gt;static type system mạnh&lt;/strong&gt; giúp AI hội tụ nhanh hơn và giảm lỗi.&lt;/li&gt;
&lt;li&gt;Luôn &lt;strong&gt;review kỹ code do AI sinh ra&lt;/strong&gt;—đừng chỉ tin vào output.&lt;/li&gt;
&lt;li&gt;Tránh &amp;ldquo;&lt;strong&gt;comprehension debt&lt;/strong&gt;&amp;rdquo;: đảm bảo team hiểu sâu hệ thống, không lệ thuộc hoàn toàn vào AI.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Functional programming&lt;/strong&gt; và equational reasoning vẫn rất hữu ích để lý luận về code.&lt;/li&gt;
&lt;li&gt;Source code luôn là &lt;strong&gt;source of truth&lt;/strong&gt;—viết code rõ ràng, biểu đạt design intent.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="heading"&gt;&lt;a class="link" href="https://brenocon.com/dean_perf.html" target="_blank" rel="noopener"
&gt;&amp;ldquo;Numbers Everyone Should Know&amp;rdquo; – Hiểu Biết Cốt Lõi Về Hiệu Năng Hệ Thống&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài thuyết trình nổi tiếng của Jeff Dean cung cấp các mốc thời gian tham chiếu thiết yếu giúp developer hiểu rõ độ trễ (latency) và hiệu suất trong hệ thống máy tính. Dành cho lập trình viên mới, những con số này là nền tảng để đưa ra quyết định tối ưu hóa hợp lý—ví dụ, truy cập bộ nhớ chính (main memory) chậm hơn hàng trăm lần so với cache mức L1. Việc nắm được thứ tự độ lớn (order of magnitude) giữa các thao tác như disk seek, network round-trip hay nén dữ liệu giúp tránh các &amp;ldquo;bẫy hiệu năng&amp;rdquo; phổ biến khi thiết kế ứng dụng phân tán hoặc xử lý dữ liệu lớn.&lt;/p&gt;
&lt;p&gt;Dưới đây là một vài điểm then chốt từ tài liệu:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Truy cập L1 cache chỉ mất ~0.5 ns, trong khi main memory reference mất ~100 ns&lt;/li&gt;
&lt;li&gt;Disk seek tốn ~10 ms—chậm hơn L2 cache (~7 ns) tới hàng triệu lần&lt;/li&gt;
&lt;li&gt;Gửi 1KB qua mạng 1 Gbps mất ~10,000 ns (0.01 ms), nhưng round-trip trong datacenter đã lên tới 0.5 ms&lt;/li&gt;
&lt;li&gt;Đọc tuần tự 1 MB từ SSD/disk mất ~30 ms, trong khi từ RAM chỉ mất ~0.25 ms&lt;/li&gt;
&lt;li&gt;Mutex lock/unlock có chi phí ~100 ns—tương đương truy cập bộ nhớ chính&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Những con số này nhấn mạnh tầm quan trọng của việc tận dụng cache, giảm thiểu I/O không cần thiết và hiểu rõ đặc tính latency của hạ tầng—kiến thức nền không thể thiếu cho mọi kỹ sư phần mềm.&lt;/p&gt;
&lt;h2 id="the-internet-is-cool-thank-you-tcp"&gt;&lt;a class="link" href="https://cefboud.com/posts/tcp-deep-dive-internals/" target="_blank" rel="noopener"
&gt;The Internet is Cool. Thank you, TCP&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giải thích vai trò then chốt của TCP – giao thức vận chuyển đáng tin cậy làm nền tảng cho hầu hết ứng dụng mạng như HTTP, SMTP hay SSH. Dù mạng Internet vốn không ổn định (gói tin có thể bị mất, lỗi, trùng lặp hoặc đến sai thứ tự), TCP đảm bảo dữ liệu được truyền chính xác, đúng trình tự và không bị hư hỏng nhờ cơ chế kiểm soát lỗi và khôi phục ở hai đầu kết nối (end-to-end). Điều này giúp lập trình viên không phải tự xử lý các vấn đề phức tạp về độ tin cậy mạng.&lt;/p&gt;
&lt;p&gt;TCP còn tích hợp &lt;strong&gt;flow control&lt;/strong&gt; (qua trường Window) để tránh làm quá tải bộ đệm nhận, và &lt;strong&gt;congestion control&lt;/strong&gt; để ngăn nghẽn mạng – bài học rút ra từ sự cố &amp;ldquo;congestion collapse&amp;rdquo; năm 1986 khi băng thông Internet giảm xuống chỉ còn 40 bps. Bài viết minh họa bằng mã C đơn giản tạo server TCP và HTTP &amp;ldquo;giả&amp;rdquo;, đồng thời phân tích cấu trúc segment TCP, handshake 3 bước (SYN/SYN-ACK/ACK), và cách sequence/acknowledgment number duy trì tính toàn vẹn dữ liệu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TCP cung cấp truyền dữ liệu &lt;strong&gt;đáng tin cậy, tuần tự và không trùng lặp&lt;/strong&gt; trên nền mạng IP vốn không đáng tin cậy.&lt;/li&gt;
&lt;li&gt;Sử dụng &lt;strong&gt;flow control&lt;/strong&gt; (Window) và &lt;strong&gt;congestion control&lt;/strong&gt; để điều tiết lưu lượng gửi và tránh nghẽn mạng.&lt;/li&gt;
&lt;li&gt;Thiết lập kết nối qua &lt;strong&gt;3-way handshake&lt;/strong&gt; (SYN → SYN-ACK → ACK); đóng kết nối bằng FIN/RST flags.&lt;/li&gt;
&lt;li&gt;Mỗi kết nối TCP được xác định bởi &lt;strong&gt;5-tuple&lt;/strong&gt;: (giao thức, IP nguồn, port nguồn, IP đích, port đích).&lt;/li&gt;
&lt;li&gt;Lập trình socket TCP (socket, bind, listen, accept, send, recv) cho phép xây dựng ứng dụng mạng dễ dàng.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="những-hiểu-lầm-phổ-biến-của-lập-trình-viên-về-cpu-caches"&gt;&lt;a class="link" href="https://software.rajivprab.com/2018/04/29/myths-programmers-believe-about-cpu-caches/" target="_blank" rel="noopener"
&gt;Những hiểu lầm phổ biến của lập trình viên về CPU Caches&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết vạch trần một số quan niệm sai lầm mà nhiều lập trình viên có về cách hoạt động của CPU cache, đặc biệt trong bối cảnh lập trình đa luồng. Một hiểu lầm phổ biến là cho rằng &amp;ldquo;các core khác nhau có thể lưu giá trị khác nhau trong cache riêng&amp;rdquo;, dẫn đến suy nghĩ rằng từ khóa &lt;code&gt;volatile&lt;/code&gt; (trong Java) buộc dữ liệu phải được đọc/ghi trực tiếp vào main memory. Thực tế, các CPU x86 hiện đại sử dụng giao thức như MESI để đảm bảo &lt;strong&gt;cache coherency&lt;/strong&gt;—tức mọi cache luôn đồng bộ với nhau—nên không xảy ra tình trạng &amp;ldquo;dữ liệu lỗi thời&amp;rdquo; giữa các core. Việc dùng &lt;code&gt;volatile&lt;/code&gt; chủ yếu liên quan đến việc ngăn compiler tối ưu hóa qua register và đảm bảo visibility qua hệ thống cache, chứ không phải truy cập main memory mỗi lần.&lt;/p&gt;
&lt;p&gt;Hiểu đúng về cơ chế này giúp lập trình viên tránh thiết kế sai khi xử lý concurrency, ngay cả trên hệ thống đơn nhân. Hiệu năng của &lt;code&gt;volatile&lt;/code&gt; cũng tốt hơn nhiều so với niềm tin phổ biến, vì thao tác vẫn diễn ra ở mức L1 cache—nhanh gấp ~200 lần so với truy cập RAM.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU caches trên các core được giữ đồng bộ nhờ phần cứng (ví dụ: giao thức MESI).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Volatile&lt;/code&gt; không bắt buộc truy cập main memory; nó đảm bảo visibility qua hệ thống cache.&lt;/li&gt;
&lt;li&gt;Lập trình concurrency vẫn cần &lt;code&gt;volatile&lt;/code&gt;/atomics do compiler/CPU có thể reorder instructions hoặc dùng register.&lt;/li&gt;
&lt;li&gt;Hiểu biết về cache coherency giúp thiết kế hệ thống phân tán và database tốt hơn.&lt;/li&gt;
&lt;li&gt;Ngay cả hệ đơn nhân cũng có thể gặp race condition nếu không dùng đúng cơ chế đồng bộ.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-nan--nan-in-javascript-and-the-ieee-754-story-behind-it"&gt;&lt;a class="link" href="https://pzarycki.com/en/posts/js-nan/" target="_blank" rel="noopener"
&gt;Why NaN !== NaN in JavaScript (and the IEEE 754 story behind it)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong JavaScript, &lt;code&gt;NaN&lt;/code&gt; (Not-a-Number) là một giá trị đặc biệt thuộc kiểu &lt;code&gt;&amp;quot;number&amp;quot;&lt;/code&gt; theo chuẩn IEEE 754, được thiết kế để biểu diễn kết quả không hợp lệ của các phép toán số học như &lt;code&gt;0/0&lt;/code&gt; hay &lt;code&gt;Math.sqrt(-1)&lt;/code&gt;. Điều khiến nhiều lập trình viên mới bối rối là &lt;code&gt;NaN !== NaN&lt;/code&gt; luôn trả về &lt;code&gt;true&lt;/code&gt;. Đây không phải lỗi mà là hành vi có chủ đích: vì &lt;code&gt;NaN&lt;/code&gt; đại diện cho &amp;ldquo;không phải giá trị&amp;rdquo;, nên việc so sánh hai giá trị không xác định với nhau là vô nghĩa. Cách phát hiện &lt;code&gt;NaN&lt;/code&gt; đáng tin cậy nhất là dùng &lt;code&gt;Number.isNaN()&lt;/code&gt; hoặc kiểm tra &lt;code&gt;x !== x&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Chuẩn IEEE 754 từ năm 1985 đã đưa &lt;code&gt;NaN&lt;/code&gt; vào hệ thống số thực dấu phẩy động ở cấp phần cứng, giúp các phép tính tiếp tục chạy thay vì crash khi gặp lỗi—điều cực kỳ quan trọng trong hệ thống nhúng hay hàng không. Nhờ cơ chế &amp;ldquo;lan truyền&amp;rdquo; (&lt;code&gt;NaN&lt;/code&gt; trong bất kỳ phép toán nào cũng cho ra &lt;code&gt;NaN&lt;/code&gt;), lập trình viên có thể kiểm tra lỗi ở cuối chuỗi tính toán thay vì sau mỗi bước.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;typeof NaN === &amp;quot;number&amp;quot;&lt;/code&gt; vì &lt;code&gt;NaN&lt;/code&gt; là một giá trị đặc biệt trong hệ thống số IEEE 754.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NaN !== NaN&lt;/code&gt; là thiết kế có chủ đích để hỗ trợ phát hiện lỗi qua phép so sánh &lt;code&gt;x !== x&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NaN&lt;/code&gt; được xử lý ở cấp CPU (qua lệnh &lt;code&gt;ucomisd&lt;/code&gt; trên x86), không phải do JavaScript tự định nghĩa.&lt;/li&gt;
&lt;li&gt;Mọi phép toán có &lt;code&gt;NaN&lt;/code&gt; đều trả về &lt;code&gt;NaN&lt;/code&gt;, giúp lỗi &amp;ldquo;lan truyền&amp;rdquo; đến điểm kiểm tra cuối cùng.&lt;/li&gt;
&lt;li&gt;Trước IEEE 754, các nền tảng xử lý lỗi số học khác nhau, gây mất ổn định và khả năng di chuyển mã.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="hướng-tới-lưu-lượng-quic-liên-hành-tinh"&gt;&lt;a class="link" href="https://ochagavia.nl/blog/towards-interplanetary-quic-traffic/" target="_blank" rel="noopener"
&gt;Hướng tới lưu lượng QUIC liên hành tinh&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ kinh nghiệm của tác giả khi tham gia một dự án nghiên cứu sử dụng giao thức &lt;strong&gt;QUIC&lt;/strong&gt;—thường dùng cho kết nối internet đáng tin cậy trên Trái Đất—trong môi trường liên hành tinh. Thử thách chính là độ trễ cực lớn (3–23 phút một chiều đến Sao Hỏa) và tính gián đoạn kết nối do giới hạn đường truyền qua vệ tinh. Mặc định, QUIC không hoạt động được trong điều kiện này, nhưng nhờ khả năng cấu hình cao, nhóm đã điều chỉnh các tham số như thời gian timeout và cơ chế kiểm soát tắc nghẽn để phù hợp với không gian sâu.&lt;/p&gt;
&lt;p&gt;Để tăng tốc thử nghiệm, họ xây dựng một môi trường mô phỏng trong cùng một tiến trình (in-process), kết hợp với đồng hồ ảo từ &lt;strong&gt;Tokio runtime&lt;/strong&gt;, giúp &amp;ldquo;bỏ qua&amp;rdquo; thời gian chờ thực tế. Nhờ đó, các thử nghiệm diễn ra gần như tức thì, đồng thời đảm bảo tính &lt;strong&gt;deterministic&lt;/strong&gt; và hỗ trợ gỡ lỗi qua file &lt;code&gt;.pcap&lt;/code&gt; để phân tích bằng Wireshark.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;QUIC có thể được cấu hình để hoạt động trong mạng liên hành tinh, khác với TCP vốn không phù hợp.&lt;/li&gt;
&lt;li&gt;Độ trễ cao và kết nối gián đoạn đòi hỏi điều chỉnh sâu các tham số giao thức.&lt;/li&gt;
&lt;li&gt;Môi trường mô phỏng in-process giúp thử nghiệm nhanh, lặp lại được và dễ debug.&lt;/li&gt;
&lt;li&gt;Dự án sử dụng thư viện &lt;strong&gt;Quinn&lt;/strong&gt; (Rust) nhờ thiết kế modular và hỗ trợ tùy biến cao.&lt;/li&gt;
&lt;li&gt;Mục tiêu dài hạn: thay thế giao thức CFDP hiện tại bằng QUIC/IP trong truyền dữ liệu không gian.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bloom-filters-the-niche-trick-behind-a-16-faster-api"&gt;&lt;a class="link" href="https://incident.io/blog/bloom-filters" target="_blank" rel="noopener"
&gt;Bloom filters: the niche trick behind a 16× faster API&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ cách đội ngũ incident.io cải thiện độ trễ P95 của một endpoint từ 5 giây xuống còn 0.3 giây bằng cách áp dụng &lt;strong&gt;Bloom filter&lt;/strong&gt;—một cấu trúc dữ liệu xác suất cho phép kiểm tra nhanh xem một phần tử có &lt;em&gt;có thể&lt;/em&gt; thuộc tập hợp hay không. Vấn đề ban đầu xuất phát từ việc lọc hàng triệu alert trong cơ sở dữ liệu, khi nhiều điều kiện (như &amp;ldquo;team&amp;rdquo; hay &amp;ldquo;feature&amp;rdquo;) được lưu dưới dạng JSONB và phải xử lý trong bộ nhớ sau khi truy vấn. Giải pháp Bloom filter giúp đẩy phần lớn logic lọc vào PostgreSQL thông qua phép toán bitwise trên cột &lt;code&gt;bit(512)&lt;/code&gt;, giảm đáng kể lượng dữ liệu cần deserialize.&lt;/p&gt;
&lt;p&gt;Kết hợp với giới hạn thời gian bắt buộc (mặc định 30 ngày), hiệu năng được cải thiện ổn định ngay cả với tổ chức lớn. Dù GIN index cũng là lựa chọn khả thi, nhóm đã chọn Bloom filter vì lo ngại về kích thước và chi phí ghi của GIN trong dài hạn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bloom filter cho phép &lt;strong&gt;loại bỏ nhanh&lt;/strong&gt; các bản ghi không khớp, dù có tỷ lệ false positive (~1%).&lt;/li&gt;
&lt;li&gt;Mỗi alert được mã hóa thành một &lt;strong&gt;bitmap 512-bit&lt;/strong&gt; dựa trên giá trị thuộc tính.&lt;/li&gt;
&lt;li&gt;Truy vấn sử dụng phép &lt;strong&gt;bitwise AND&lt;/strong&gt;: &lt;code&gt;bitmap &amp;amp; bitmask == bitmask&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Kết hợp với &lt;strong&gt;phân vùng theo thời gian&lt;/strong&gt; (dựa trên ULID) để giới hạn phạm vi quét dữ liệu.&lt;/li&gt;
&lt;li&gt;Hiệu quả rõ rệt với &lt;strong&gt;workload đọc nhiều&lt;/strong&gt;, đặc biệt khi kết quả lọc chiếm tỷ lệ lớn.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="thiết-kế-là-làm-rõ-bản-chất-tư-duy-hệ-thống-cho-lập-trình-viên"&gt;&lt;a class="link" href="https://threadreaderapp.com/thread/1990057444253241545.html" target="_blank" rel="noopener"
&gt;Thiết Kế Là Làm Rõ Bản Chất: Tư Duy Hệ Thống Cho Lập Trình Viên&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết nhấn mạnh rằng thiết kế (design) không chỉ là thẩm mỹ mà là quá trình tháo gỡ cấu trúc nền tảng của một hệ thống, hiểu rõ các thành phần cơ bản và tái tổ hợp chúng để tạo ra giải pháp mới. Tác giả lấy ví dụ từ Notion—thay vì xây dựng sản phẩm đơn năng như Asana hay Evernote, Notion cung cấp các &amp;ldquo;nguyên tử&amp;rdquo; như blocks, databases và relations để người dùng tự do sáng tạo. Tương tự, công cụ AI như Cursor đang biến ý định con người thành code bằng cách hiểu cấu trúc logic đằng sau yêu cầu, giảm rào cản giữa ý tưởng và hiện thực hóa phần mềm.&lt;/p&gt;
&lt;p&gt;Triết lý này phản ánh nguyên tắc phổ quát: thế giới vận hành dựa trên các mô-đun đơn giản có thể kết hợp vô hạn—từ DNA đến ngôn ngữ. Với lập trình viên trẻ, điều cốt lõi là học cách nhận diện &amp;ldquo;primitives&amp;rdquo; (nguyên tố cơ bản) trong hệ thống, từ đó xây dựng tư duy phân rã (decomposition) và tái cấu trúc (recomposition). AI không chỉ là tính năng mà là một primitive mới, mở ra cách làm việc trực tiếp với khái niệm thay vì cú pháp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thiết kế thật sự là tháo gỡ và tái tổ hợp cấu trúc nền tảng, không chỉ làm đẹp giao diện.&lt;/li&gt;
&lt;li&gt;Tập trung vào &lt;strong&gt;systems&lt;/strong&gt;, không chỉ &lt;strong&gt;products&lt;/strong&gt;: cung cấp primitives (blocks, databases) thay vì giải pháp cố định.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;All single-purpose apps are rigid assemblies of the same underlying concepts.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;AI như Cursor cho phép làm việc trực tiếp với &lt;strong&gt;intent&lt;/strong&gt; thay vì cú pháp code.&lt;/li&gt;
&lt;li&gt;Hiểu và sử dụng các &lt;strong&gt;primitives&lt;/strong&gt; mới (CLI, GUI, web, AI) là chìa khóa tạo ra hệ sinh thái đổi mới.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="những-dấu-hiệu-của-việc-thực-thi-tốt"&gt;&lt;a class="link" href="https://yusufaytas.com/what-good-execution-looks-like/" target="_blank" rel="noopener"
&gt;Những Dấu Hiệu Của Việc Thực Thi Tốt&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Thực thi tốt không ồn ào, mà yên tĩnh và hiệu quả. Khi hệ thống vận hành trơn tru, mọi người làm việc cùng nhau mà không cần quá nhiều quản lý hay can thiệp. Ngược lại, khi thực thi kém, sẽ có nhiều dấu hiệu như dự án bị đình trệ, quy trình trở nên rườm rà, và số lượng cuộc họp tăng vọt. Dấu hiệu rõ ràng nhất là sự &amp;ldquo;ồn ào&amp;rdquo; trong môi trường làm việc, khi mà mọi người mất niềm tin vào quá trình thực thi.&lt;/p&gt;
&lt;p&gt;Các nền tảng cho việc thực thi hiệu quả bao gồm: sự rõ ràng về định hướng, bối cảnh ổn định, quyền sở hữu minh bạch, quy trình gọn nhẹ, sự tin tưởng, và một nhịp điệu làm việc nhất quán. Những yếu tố này tạo nền tảng cho các kỹ sư tự chủ, an toàn về mặt tâm lý, và có thể tự điều chỉnh khi gặp vấn đề.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sự rõ ràng về định hướng:&lt;/strong&gt; Giúp các kỹ sư hiểu rõ mục tiêu, tránh lãng phí thời gian và công sức.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quyền sở hữu minh bạch:&lt;/strong&gt; Người nào chịu trách nhiệm cho phần việc đó, giúp tránh tình trạng &amp;ldquo;không ai làm&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Giao tiếp yên tĩnh:&lt;/strong&gt; Không có quá nhiều cuộc họp hay cập nhật phòng thủ, thể hiện sự tin tưởng lẫn nhau.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tự chủ và an toàn tâm lý:&lt;/strong&gt; Kỹ sư có thể đưa ra quyết định mà không sợ bị trừng phạt, từ đó tăng hiệu suất.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nhịp điệu và phản hồi liên tục:&lt;/strong&gt; Giúp duy trì động lực và điều chỉnh kịp thời khi có sai lệch.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bonus"&gt;Bonus
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Images:&lt;/strong&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!tANe!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f80d730-11c4-4d55-81bf-fa4629cc2f0f_2360x2960.png"
loading="lazy"
alt="How to Design Good APIs"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!gReB!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2e93eb2-84ab-427f-b587-e14b599e0fee_2360x2960.png"
loading="lazy"
alt="Types of Virtualization"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Videos:&lt;/strong&gt;
&lt;a class="link" href="https://www.youtube.com/watch?v=7_wkWQ9rB5I" target="_blank" rel="noopener"
&gt;Why is Kafka Popular?&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Newsletter #67</title><link>https://miti99.com/post/2025/12/10/</link><pubDate>Wed, 10 Dec 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/12/10/</guid><description>&lt;p&gt;&lt;em&gt;Bài viết này mình đã thử cải thiện AGENTS.md lại. Kết quả mình tự đánh giá ở cuối bài nhé. Mời bạn thưởng thức Newsletter #67.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="build-better-software-to-build-software-better"&gt;&lt;a class="link" href="https://slack.engineering/build-better-software-to-build-software-better/" target="_blank" rel="noopener"
&gt;Build better software to build software better&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Slack Engineering chia sẻ cách họ đã cải thiện thời gian build từ 60 phút xuống chỉ còn 10-30 phút bằng cách áp dụng các nguyên tắc kỹ thuật phần mềm vào hệ thống build. Bài viết phân tích cách sử dụng Bazel để tối ưu hóa quá trình build thông qua caching và parallelization, cùng với việc tách biệt các thành phần để tăng hiệu quả.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build performance tương tự như code performance - cần áp dụng caching (làm ít việc hơn) và parallelization (chia tải)&lt;/li&gt;
&lt;li&gt;Bazel tự động cache kết quả build khi inputs không thay đổi và phân phối build actions across nhiều CPU cores&lt;/li&gt;
&lt;li&gt;Vấn đề chính của Quip/Canvas build là sự couplings giữa backend và frontend, khiến mỗi thay đổi Python đều trigger frontend rebuild&lt;/li&gt;
&lt;li&gt;Tách biệt concerns đã giảm thời gian build từ 60 phút xuống 25 phút trong trường hợp frontend đã được cache&lt;/li&gt;
&lt;li&gt;Thiết kế layering đúng cách - builder chỉ nên focus vào business logic, không nên tự implement parallelization&lt;/li&gt;
&lt;li&gt;Kết quả cuối cùng: build nhanh hơn 6 lần, với best case chỉ 10 phút khi cached và parallelized&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="things-i-don"&gt;&lt;a class="link" href="https://medv.io/blog/things-i-dont-like-in-configuration-languages/" target="_blank" rel="noopener"
&gt;Things I Don&amp;rsquo;t Like in Configuration Languages&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Anton Medvedev phân tích các vấn đề của nhiều ngôn ngữ configuration khác nhau và giải thích tại sao ông quyết định tạo ra ngôn ngữ MAML (Minimal And Markup Language) của riêng mình. Bài viết cung cấp cái nhìn sâu sắc về ưu và nhược điểm của từng ngôn ngữ configuration từ YAML, JSON đến các ngôn ngữ mới hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;YAML có specification quá phức tạp và nhiều features không cần thiết&lt;/li&gt;
&lt;li&gt;JSON đã chiến thắng như một universal data-interchange format, nhưng có vài điểm nhỏ cần cải thiện&lt;/li&gt;
&lt;li&gt;TOML thiếu null value và cú pháp array of tables khó hiểu&lt;/li&gt;
&lt;li&gt;Nhiều ngôn ngữ như Pkl, CUE, Dhall thực chất là full programming languages, không chỉ là markup languages&lt;/li&gt;
&lt;li&gt;Tác giả tạo MAML dựa trên JSON với strict specification và tên gọi độc đáo&lt;/li&gt;
&lt;li&gt;MAML giữ tính readable của JSON nhưng thêm comments và multiline strings&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="here"&gt;&lt;a class="link" href="https://seconds0.substack.com/p/heres-whats-next-in-agentic-coding/" target="_blank" rel="noopener"
&gt;Here&amp;rsquo;s What&amp;rsquo;s Next in Agentic Coding&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích tương lai của agentic coding và các hướng phát triển sắp tới. Tác giả nhấn mạnh rằng context management là yếu tố quan trọng nhất và sẽ là trọng tâm của các cải tiến trong tương lai. Bài viết cung cấp cái nhìn toàn diện về các tính năng sắp có trong các công cụ coding AI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Plan Mode sẽ trở nên tinh vi hơn, với tỷ lệ plan:execute thay đổi từ 20:80 thành 80:20&lt;/li&gt;
&lt;li&gt;Search sẽ kết hợp cả grep và embeddings để tăng hiệu quả tìm kiếm trong codebase&lt;/li&gt;
&lt;li&gt;Docs by Default sẽ trở thành tiêu chuẩn - tự động truy xuất documentation khi cần&lt;/li&gt;
&lt;li&gt;Rules và Skills sẽ được điều kiện hóa để tránh làm ô nhiễm context&lt;/li&gt;
&lt;li&gt;Multiagent orchestration với Best of N sampling và Mix of Models sẽ trở nên phổ biến&lt;/li&gt;
&lt;li&gt;Subagents sẽ được sử dụng nhiều hơn cho parallelization, context isolation và prompt customization&lt;/li&gt;
&lt;li&gt;Critic &amp;amp; Self Review sẽ trở thành tính năng mặc định để cải thiện chất lượng&lt;/li&gt;
&lt;li&gt;Memory sẽ được tích hợp để lưu trữ thông tin về user, codebase và lịch sử tương tác&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-agents-do-not-write-most-of-our-code---a-reality-check"&gt;&lt;a class="link" href="https://octomind.dev/blog/why-agents-do-not-write-most-of-our-code-a-reality-check/" target="_blank" rel="noopener"
&gt;Why agents DO NOT write most of our code - a reality check&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Octomind chia sẻ thực tế về việc sử dụng AI agents trong development. Dù xây dựng AI agents, họ vẫn viết phần lớn code bằng tay. Bài viết mô tả thử nghiệm xây dựng feature hoàn toàn bằng AI và các vấn đề gặp phải, cung cấp cái nhìn thực tế về khả năng hiện tại của coding agents.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thử nghiệm với Cursor, Claude Code và Windsurf không tăng productivity đáng kể (20%+)&lt;/li&gt;
&lt;li&gt;AI tạo ra 2,000-line PR với nhiều lỗi cơ bản mà developer không mắc phải&lt;/li&gt;
&lt;li&gt;Vấn đề lớn nhất: mất mental model của codebase khi AI generate code&lt;/li&gt;
&lt;li&gt;AI không có khả năng self-reflection - không nhận biết giới hạn của bản thân&lt;/li&gt;
&lt;li&gt;AI vẫn hữu ích cho các tasks nhỏ: tab completions, unit tests, refactoring&lt;/li&gt;
&lt;li&gt;AI tốt khi recreating well-known patterns nhưng kém với features phức tạp&lt;/li&gt;
&lt;li&gt;Specialized agents trong well-defined boundaries có thể deliver value&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="clarifying-the-rule-of-three-in-refactoring"&gt;&lt;a class="link" href="https://blog.thecodewhisperer.com/permalink/clarifying-the-rule-of-three-in-refactoring" target="_blank" rel="noopener"
&gt;Clarifying the Rule of Three in Refactoring&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giải thích rõ về Rule of Three trong refactoring - một heuristic gây nhiều tranh cãi. Tác giả phân tích mục đích thực sự của quy tắc này và đưa ra góc nhìn linh hoạt hơn về việc khi nào nên remove duplication. Bài viết giúp developer hiểu rõ hơn về trade-offs giữa việc extract abstractions sớm hay muộn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rule of Three thực chất là để ngăn Advanced Beginners remove duplication một cách mù quáng&lt;/li&gt;
&lt;li&gt;Khi đang học về design qua refactoring, việc remove duplication aggressively giúp phát triển design judgment&lt;/li&gt;
&lt;li&gt;Khi đã thành thạo, có thể delay removing duplication để tránh rework sau này&lt;/li&gt;
&lt;li&gt;Tác giả không ngại inlining khi后悔 về quyết định extract - đây là phần của quá trình học&lt;/li&gt;
&lt;li&gt;Removing duplication giúp tìm ra các abstractions hữu ích có thể ẩn trong design&lt;/li&gt;
&lt;li&gt;Nếu thoải mái với inlining, không cần quá lo lắng về việc có后悔 khi extract&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bonus"&gt;Bonus
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Images:&lt;/strong&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!9vpY!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5f41f86-4bf2-4b21-85aa-69659c039111_2250x2624.png"
loading="lazy"
alt="Top Strategies to Share Data Between Services"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!aRQC!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa760cf81-6245-4051-be41-f867616e0faf_2250x2862.png"
loading="lazy"
alt="Scalability Patterns for Modern Distributed Systems"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Videos:&lt;/strong&gt;
&lt;a class="link" href="https://www.youtube.com/watch?v=6u25GckPhLU" target="_blank" rel="noopener"
&gt;Design a Web Crawler: FAANG Interview Question&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Đánh giá:&lt;/strong&gt; &lt;em&gt;Process url tạm ổn, đã bớt dùng tiếng Anh nhưng lại có một chút&amp;hellip; tiếng Trung :| Process phần bonus thì hơi lủng. Chủ yếu là do khi gửi url AI thì AI khó mà tìm ra được tiêu đề phù hợp, thậm chí còn ghi trật lất không liên quan nữa.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #66</title><link>https://miti99.com/post/2025/12/09/</link><pubDate>Tue, 09 Dec 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/12/09/</guid><description>&lt;p&gt;&lt;em&gt;Dùng api free của iFlow cũng nhiều rồi, nên nay mình dùng thử cli của iFlow - &lt;a class="link" href="https://github.com/iflow-ai/iflow-cli" target="_blank" rel="noopener"
&gt;iFlow CLI&lt;/a&gt; xem sao, model được dùng là GLM-4.6. Mời bạn thưởng thức Newsletter #66.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="the-ultimate-list-of-best-software-architecture-books-2026"&gt;&lt;a class="link" href="https://www.workingsoftware.dev/the-ultimate-list-of-software-architecture-books/?&amp;amp;aid=recmw058VtqAJCyyK" target="_blank" rel="noopener"
&gt;The Ultimate List of Best Software Architecture Books (2026)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Software architecture là nền tảng cho sự phát triển thành công của các sản phẩm phần mềm. Một kiến trúc phần mềm được thiết kế tốt có thể tạo ra sự khác biệt lớn về chất lượng của hệ thống, giúp giảm thiểu rủi ro lỗi và dễ dàng thêm tính năng mới trong tương lai. Bài viết này giới thiệu danh sách các sách về kiến trúc phần mềm tốt nhất nên đọc trong năm 2026, cùng với những cuốn sách sắp được xuất bản.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Architecture for Flow&amp;rdquo; của Susanne Kaiser kết hợp Wardley Mapping, Domain-Driven Design và Team Topologies để tạo ra hệ thống thích ứng&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Collaborative Software Design&amp;rdquo; hướng dẫn cách tham gia tất cả stakeholders vào quá trình thiết kế phần mềm&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Facilitating Software Architecture&amp;rdquo; cung cấp phương pháp luận cho kiến trúc sư và developer hợp tác hiệu quả&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Reviewing Software Systems&amp;rdquo; giới thiệu LASR - phương pháp đánh giá kiến trúc nhẹ nhàng&lt;/li&gt;
&lt;li&gt;Các cuốn kinh điển như &amp;ldquo;Fundamentals of Software Architecture&amp;rdquo; và &amp;ldquo;Designing Data-Intensive Applications&amp;rdquo; vẫn còn giá trị&lt;/li&gt;
&lt;li&gt;Nhiều cuốn sách mới sẽ ra mắt năm 2026 tập trung vào hiện đại hóa hệ thống legacy và mô hình C4&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-i-use-ai-oct-2025"&gt;&lt;a class="link" href="https://ben.stolovitz.com/posts/how_use_ai_oct_2025/?utm_source=tldrnewsletter" target="_blank" rel="noopener"
&gt;How I use AI (Oct 2025)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Ben Stolovitz chia sẻ cách ông sử dụng AI trong công việc hàng ngày, đặc biệt là các LLMs. Ông chia sẻ kinh nghiệm thực tế về việc sử dụng AI trong coding, research, summarization, writing và art. Bài viết cung cấp một cái nhìn chân thực về điểm mạnh, điểm yếu của các công cụ AI hiện tại.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI autocomplete (Copilot) thay đổi hoàn toàn cách coding - hoàn thành code đã biết và giúp khám phá patterns, nhưng không tốt với thuật toán phức tạp&lt;/li&gt;
&lt;li&gt;Agent mode ngày càng hữu ích cho các thay đổi phức tạp nhưng vẫn cần giám sát con người&lt;/li&gt;
&lt;li&gt;AI rất giỏi trong việc tìm kiếm &amp;ldquo;pub facts&amp;rdquo; và giải thích các khái niệm phổ biến, nhưng không đáng tin cậy cho tìm kiếm sản phẩm hay literature search&lt;/li&gt;
&lt;li&gt;Summarization và transcription là điểm mạnh ấn tượng của AI - có thể tóm tắt hàng trăm trang trong vài phút&lt;/li&gt;
&lt;li&gt;Tác giả không dùng AI để viết từ đầu, nhưng sử dụng như một editor &amp;ldquo;đáng sợ&amp;rdquo; giúp cải thiện văn bản&lt;/li&gt;
&lt;li&gt;AI-generated art và music vẫn còn gây tranh cãi - dù có thể tạo ra nội dung thú vị nhưng thường thiếu sự kết nối con người&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="stop-vibe-coding-your-unit-tests"&gt;&lt;a class="link" href="https://www.andy-gallagher.com/blog/stop-vibe-coding-your-unit-tests/?utm_source=tldrnewsletter" target="_blank" rel="noopener"
&gt;Stop Vibe Coding Your Unit Tests&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Andy Gallagher cảnh báo về việc sử dụng LLMs để viết unit tests một cách tự động. Ông chỉ ra rằng LLMs có xu hướng viết quá nhiều tests và chỉ xác nhận những gì code làm, chứ không xác thực những gì code nên làm. Bài viết cung cấp ví dụ thực tế về một React component button và cách LLMs tạo ra hàng chục tests không cần thiết.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LLMs tạo ra quá nhiều unit tests không cần thiết - ví dụ Claude Sonnet 4 tạo ra ~30 tests (200 LOC) cho một button component đơn giản&lt;/li&gt;
&lt;li&gt;Tests do LLM tạo thường chỉ verify implementation details thay vì validate behavior thực sự&lt;/li&gt;
&lt;li&gt;Tests này làm code bị &amp;ldquo;khóa&amp;rdquo; vào implementation hiện tại, gây khó khăn khi refactor&lt;/li&gt;
&lt;li&gt;LLMs không hỏi clarifying questions về &amp;ldquo;cần test gì&amp;rdquo; mà chỉ test tất cả mọi thứ&lt;/li&gt;
&lt;li&gt;Các tests này tốn context window, làm loãng semantic search, và khiến coworkers ghét khi review PR lớn&lt;/li&gt;
&lt;li&gt;Giải pháp: viết tests từng cái một, tập trung vào behavior quan trọng, keep it focused và brief&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="game-design-is-simple-actually"&gt;&lt;a class="link" href="https://www.raphkoster.com/2025/11/03/game-design-is-simple-actually/?utm_source=tldrnewsletter" target="_blank" rel="noopener"
&gt;Game design is simple, actually&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Raph Koster trình bày một framework 12 bước toàn diện để hiểu về thiết kế game. Ông phân tích các khái niệm phức tạp thành những nguyên tắc dễ hiểu, từ bản chất của niềm vui đến sự phức tạp của các hệ thống game. Bài viết nhấn mạnh rằng game về cơ bản là về giải quyết vấn đề và làm chủ kỹ năng, với sự không chắc chắn và học hỏi là cốt lõi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fun thực chất là về việc làm tiến bộ dự đoán (mastery of problems) - không phải tất cả mọi thứ thú vị đều liên quan đến thiết kế game&lt;/li&gt;
&lt;li&gt;Games được xây dựng từ toys (hệ thống có ràng buộc) bằng cách thêm goals - core mechanic là một &amp;ldquo;problematic object&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Games là machines xung quanh uncertainty - tốt nhất có nhiều depth, nhiều paths đến solution&lt;/li&gt;
&lt;li&gt;Có 2 types của loops: operational loop (tương tác với problem) và progression loop/spiral (đối mặt với nhiều situations)&lt;/li&gt;
&lt;li&gt;Feedback cần show: có thể làm gì, đã làm gì, kết quả là gì, và có giúp đạt goal không&lt;/li&gt;
&lt;li&gt;Games được làm từ games - nhiều loops được nối lại thành economies và value chains&lt;/li&gt;
&lt;li&gt;Game design là compound art form - cần cả system design và experience design (art, story, audio)&lt;/li&gt;
&lt;li&gt;Designer cần hiểu motivations của players - không có game nào dành cho tất cả mọi người&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="architectural-debt-is-not-just-technical-debt"&gt;&lt;a class="link" href="https://frederickvanbrabant.com/blog/2025-10-31-architectural-debt-is-not-just-technical-debt/?&amp;amp;aid=recufcl24hU9MXCJC" target="_blank" rel="noopener"
&gt;Architectural debt is not just technical debt&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Frederick Van Brabant giải thích sự khác biệt giữa architectural debt và technical debt. Ông chỉ ra rằng architectural debt không chỉ giới hạn ở code level mà còn ảnh hưởng đến nhiều layer của tổ chức. Bài viết phân tích architectural debt ở ba layer chính: application/infrastructure, business, và strategy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Technical debt thường là temporary hacks, architectural debt là structural decisions gây vấn đề về sau&lt;/li&gt;
&lt;li&gt;Enterprise architects nên tập trung vào integration patterns, system overlap, và vendor lock-in thay vì code details&lt;/li&gt;
&lt;li&gt;Business layer debt liên quan đến ownership, stewardship, và outdated processes - documentation sai có thể gây vấn đề nghiêm trọng với auditors&lt;/li&gt;
&lt;li&gt;Strategy layer debt nguy hiểm nhất - mis-defined capabilities hoặc half frameworks có thể dẫn đến wrong assumptions cho 3-5 năm tới&lt;/li&gt;
&lt;li&gt;Enterprise architects có time và visibility để flag architectural debt - cần build case với AS-IS, TO-BE, và business case&lt;/li&gt;
&lt;li&gt;Cần pick battles carefully - có thể tolerate debt ở innovation systems hơn là record systems&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-search-problem-why-your-computer-finds-things-faster-than-you-do"&gt;&lt;a class="link" href="https://deyaa1251.github.io/deyaa1251/posts/b_tree/?utm_source=bonobopress&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=2155" target="_blank" rel="noopener"
&gt;The Search Problem: Why Your Computer Finds Things Faster Than You Do&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này giải thích tại sao B-trees lại quan trọng trong các hệ thống hiện đại. Tác giả chia sẻ kinh nghiệm thực tế khi implement binary search tree và nhận ra nó sụp đổ khi thêm simulated disk I/O. B-tree được thiết kế đặc biệt cho disk-based operations với node size khớp với disk block.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Binary search trees là O(log n) trong RAM nhưng rất tệ trên disk - mỗi level là một disk read&lt;/li&gt;
&lt;li&gt;B-tree lưu trữ nhiều keys per node (fat nodes) - một node fits trong một disk block (4KB)&lt;/li&gt;
&lt;li&gt;Benchmark cho thấy: 100,000 files, BST cần 1,410 seconds (23.5 phút) trong khi B-tree chỉ cần 3 seconds&lt;/li&gt;
&lt;li&gt;B-trees guarantee predictable performance - không degenerate thành linked list như BST&lt;/li&gt;
&lt;li&gt;Real-world usage: ext4, NTFS, APFS, databases (MySQL, PostgreSQL), Git, MongoDB đều dùng B-trees&lt;/li&gt;
&lt;li&gt;Key insight: B-trees trade best-case performance cho worst-case guarantees - crucial cho production systems&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="kafka-is-fast"&gt;&lt;a class="link" href="https://topicpartition.io/blog/postgres-pubsub-queue-benchmarks?utm_source=bonobopress&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=2155" target="_blank" rel="noopener"
&gt;Kafka is fast &amp;ndash; I&amp;rsquo;ll use Postgres&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này so sánh hiệu năng của Postgres khi dùng làm pub/sub messaging system và queue so với các hệ thống chuyên dụng như Kafka. Tác giả thực hiện benchmarks chi tiết trên nhiều setup khác nhau và chỉ ra rằng Postgres có thể xử lý workloads khá lớn mà không cần đến distributed systems phức tạp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Postgres pub/sub benchmark: 1 node 4 vCPU đạt 4.8 MiB/s write, 24.6 MiB/s read (5x fanout)&lt;/li&gt;
&lt;li&gt;3-node replicated setup vẫn maintain throughput tốt với latency tăng từ 60ms thành 186ms p99&lt;/li&gt;
&lt;li&gt;96 vCPU single node đạt 238 MiB/s write và 1.16 GiB/s read - rất ấn tượng&lt;/li&gt;
&lt;li&gt;Queue benchmark đạt 2.81 MiB/s throughput trên 4 vCPU node&lt;/li&gt;
&lt;li&gt;Key insight: Postgres thường &amp;ldquo;good enough&amp;rdquo; cho 80% use cases với 20% effort&lt;/li&gt;
&lt;li&gt;Organizational overhead của adopting new systems thường lớn hơn benefit ở small scale&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Just Use Postgres&amp;rdquo; movement đang ngày càng phổ biến vì simplicity và reliability&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="you-need-to-become-a-full-stack-person"&gt;&lt;a class="link" href="https://den.dev/blog/full-stack-person/?utm_source=tldrnewsletter" target="_blank" rel="noopener"
&gt;You Need To Become A Full Stack Person&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Den Delimarsky lập luận về sự cần thiết của việc trở thành &amp;ldquo;full-stack person&amp;rdquo; trong kỷ nguyên AI. Ông chỉ ra rằng nhiều kỹ năng đang bị commoditized bởi LLMs, nhưng combo của creativity, critical thinking, và execution speed sẽ tạo ra career moat bền vững. Bài viết giới thiệu 9 kỹ năng cốt lõi cần phát triển.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Role flattening đang xảy ra - ranh giới giữa các roles trở nên mờ đi với sự trỗi dậy của product engineer&lt;/li&gt;
&lt;li&gt;T-shaped model (1 deep spike + broad base) đang chết, Pi-shaped model (2 deep spikes + broad base) là tương lai&lt;/li&gt;
&lt;li&gt;9 skills cần thiết: Creativity &amp;amp; Taste, Critical Thinking, Communications, Cross-Domain Knowledge, AI Augmentation, Product Sense, Execution Speed, Learning Agility, Systems Thinking, và Agency&lt;/li&gt;
&lt;li&gt;AI không thay thế được taste và judgment - nó chỉ là &amp;ldquo;idea implementation vehicles&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Key insight: &amp;ldquo;AI lowers the cost of type it and it runs, but not the cost of choosing the right thing&amp;rdquo;&lt;/li&gt;
&lt;li&gt;High agency - attitude &amp;ldquo;We&amp;rsquo;ll figure this out - let&amp;rsquo;s get to work&amp;rdquo; - là yếu tố khác biệt quan trọng&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Đánh giá&lt;/strong&gt;: &lt;em&gt;Phần đầu iFlow CLI làm khá tốt, nhưng mà càng về sau thì càng lạm dụng tiếng Anh nhiều. Điểm cộng là iFlow CLI có thể access nhiều url, bằng cách bypass sử dụng proxy (Tuy nhiên proxy của Trung Quốc nên nhìn cũng hơi ghê). Trong quá trình sử dụng thì cũng thấy nhiều dòng để toàn tiếng Trung Quốc làm khó hiểu và hơi rén :v Mình sẽ cố gắng cải thiện AGENTS.md và thử lại sau.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #65</title><link>https://miti99.com/post/2025/12/08/</link><pubDate>Mon, 08 Dec 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/12/08/</guid><description>&lt;p&gt;&lt;em&gt;Dạo gần đây mấy model free trên OpenRouter đang không ổn định lắm, lúc dùng được lúc thì không. Sẵn còn vài $ credit trên đấy nên nay tranh thủ bào nốt rồi chuyển qua iFlow dùng hẳn (cho đến khi iFlow hết free :v). Mời bạn thưởng thức Newsletter #65. Bài viết này được thực hiện bởi &lt;a class="link" href="https://github.com/anthropics/claude-code" target="_blank" rel="noopener"
&gt;Claude Code&lt;/a&gt;, &lt;a class="link" href="https://github.com/musistudio/claude-code-router" target="_blank" rel="noopener"
&gt;Claude Code Router&lt;/a&gt;, &lt;a class="link" href="https://openrouter.ai" target="_blank" rel="noopener"
&gt;OpenRouter&lt;/a&gt; &amp;amp; &lt;a class="link" href="https://openrouter.ai/anthropic/claude-sonnet-4.5" target="_blank" rel="noopener"
&gt;Anthropic: Claude Sonnet 4.5&lt;/a&gt; (model &amp;lsquo;xịn&amp;rsquo; nhe hehe)&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="scaling-engineering-teams-lessons-from-google-facebook-and-netflix"&gt;&lt;a class="link" href="https://greenido.wordpress.com/2025/09/25/scaling-engineering-teams-lessons-from-google-facebook-and-netflix" target="_blank" rel="noopener"
&gt;Scaling Engineering Teams: Lessons from Google, Facebook, and Netflix&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ kinh nghiệm quý báu từ tác giả với hơn 10 năm lãnh đạo kỹ thuật tại Google, Facebook và Netflix về cách mở rộng quy mô đội ngũ kỹ thuật từ 10 lên 1000+ engineers. Tác giả tập trung vào ba yếu tố then chốt: đặt mục tiêu với OKRs, xây dựng nền tảng chất lượng code, và nuôi dưỡng văn hóa làm việc.&lt;/p&gt;
&lt;p&gt;Về OKRs, Google khuyến khích đặt mục tiêu đầy tham vọng - đạt 60-70% là tốt, còn đạt 100% nghĩa là mục tiêu chưa đủ cao. Netflix lại theo triết lý &amp;ldquo;Context Over Control&amp;rdquo; - cho team một North Star metric duy nhất để tập trung. Đối với chất lượng code, Facebook yêu cầu mọi dòng code đều phải được review, có code owner rõ ràng, và đạt ít nhất 80% test coverage. Netflix nổi tiếng với Chaos Engineering - cố ý &amp;ldquo;giết&amp;rdquo; instances ngẫu nhiên để kiểm tra độ bền hệ thống.&lt;/p&gt;
&lt;p&gt;Về văn hóa, Google có &amp;ldquo;Innovation Fridays&amp;rdquo; hàng tháng để thử nghiệm, Facebook có chương trình Bootcamp 6 tuần cho engineers mới fix bugs khắp nơi trước khi chọn team, còn Netflix tin tưởng vào việc thuê người tài năng với lương cao và kỳ vọng họ hành xử như người trưởng thành. Điểm chung của các công ty này là đều tránh hero culture và tribal knowledge - thay vào đó là hệ thống, documentation, automation và ownership rõ ràng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đặt mục tiêu OKRs đầy tham vọng (60-70% completion là tốt) với 3-5 objectives và 2-4 key results mỗi team&lt;/li&gt;
&lt;li&gt;Bắt buộc code review cho mọi thay đổi, có code owner rõ ràng, và duy trì ≥80% test coverage&lt;/li&gt;
&lt;li&gt;Thực hành Chaos Engineering để test độ bền hệ thống và sử dụng canary deployment&lt;/li&gt;
&lt;li&gt;Nuôi dưỡng văn hóa đổi mới qua innovation time, bootcamp cho nhân viên mới, và 360 feedback&lt;/li&gt;
&lt;li&gt;Theo dõi DORA metrics: lead time, deployment frequency, time to restore, change failure rate&lt;/li&gt;
&lt;li&gt;Tránh hero culture và manual processes - ưu tiên systems, documentation, automation&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-trap-of-excessive-ai-use"&gt;&lt;a class="link" href="https://dpereira.substack.com/p/the-trap-of-excessive-ai-use" target="_blank" rel="noopener"
&gt;The Trap of Excessive AI Use&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;David Pereira, tác giả của &amp;ldquo;Untrapping Product Teams&amp;rdquo;, cảnh báo về cái bẫy của việc lạm dụng AI - nó có thể khiến con người trở nên trung bình thay vì giỏi hơn. Tuy không phản đối AI, ông lo ngại xu hướng &amp;ldquo;tự động hóa mọi thứ một cách mù quáng&amp;rdquo; đang thịnh hành trong giới chuyên môn. Vấn đề cốt lõi là: AI có thể tăng tốc độ nhưng không thể thay thế tư duy phản biện, sự thấu hiểu hay phán đoán của con người.&lt;/p&gt;
&lt;p&gt;Pereira nhận thấy nhiều pattern sử dụng AI đáng lo ngại: giao quyết định ưu tiên cho AI thay vì phân tích kỹ lưỡng, dùng AI viết product requirement documents thay vì suy ngẫm về điều gì thực sự quan trọng, tóm tắt quá mức thay vì học sâu, hoặc thay thế nghiên cứu thực sự bằng insights do AI tạo ra. Ông nhấn mạnh: &amp;ldquo;càng nhiều người vội vã outsource mọi thứ cho AI, thì việc là người không làm như vậy càng trở nên có giá trị.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Về phía cá nhân, Pereira vẫn giữ những thói quen &amp;ldquo;old-fashioned&amp;rdquo;: đọc từng tin nhắn trực tiếp, viết email thủ công để khuyến khích suy ngẫm, review từng application riêng lẻ, đọc sách hoàn chỉnh thay vì tóm tắt, và single-tasking để đảm bảo chất lượng hơn số lượng. Tuy nhiên, ông cũng thừa nhận AI hữu ích trong việc tăng tốc (draft meeting notes, automate research), khám phá (tạo góc nhìn thay thế, stress-test assumptions), và học hỏi (tạo experiment options). Nguyên tắc của ông rất rõ ràng: &amp;ldquo;AI có thể draft, nhưng tôi quyết định&amp;rdquo; - phân biệt giữa leverage và abdication trách nhiệm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI tăng tốc độ nhưng không thay thế critical thinking, wisdom và human judgment&lt;/li&gt;
&lt;li&gt;Tránh ủy thác quyết định quan trọng cho AI: prioritization, requirement docs, research insights&lt;/li&gt;
&lt;li&gt;Critical thinking, hiểu human behavior, challenge assumptions nên là domain của con người&lt;/li&gt;
&lt;li&gt;Sử dụng AI để acceleration (draft notes, automate research), exploration (alternative perspectives), và learning&lt;/li&gt;
&lt;li&gt;Nguyên tắc &amp;ldquo;AI can draft, but I decide&amp;rdquo; - phân biệt leverage vs abdication&lt;/li&gt;
&lt;li&gt;Càng nhiều người dựa vào AI, người không lạm dụng AI càng có giá trị&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-google-amazon-and-crowdstrike-broke-millions-of-systems"&gt;&lt;a class="link" href="https://newsletter.techworld-with-milan.com/p/how-google-amazon-and-crowdstrike" target="_blank" rel="noopener"
&gt;How Google, Amazon, and CrowdStrike Broke Millions of Systems&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích ba sự cố infrastructure lớn năm 2025 đã làm gián đoạn hàng triệu hệ thống, tiết lộ những bài học quan trọng về tính mong manh của distributed systems. AWS gặp sự cố kéo dài 15 giờ ảnh hưởng 113 services do race condition trong DynamoDB DNS automation - DNS Enactor #1 đã ghi đè Route 53 với dữ liệu cũ khi thời gian xử lý vượt quá timeout. Google Cloud sập 7 giờ do null pointer exception trong Service Control, bug nằm im 14 ngày sau khi deploy code mới thiếu null validation cho đến khi corrupted policy xuất hiện và Spanner replicate toàn cầu &amp;ldquo;với tốc độ ánh sáng&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;CrowdStrike gây ra thảm họa với 8.5 triệu máy Windows bị boot loop do Channel File 291 trigger null pointer trong kernel mode. Máy bay không cất cánh được, bệnh viện hủy phẫu thuật, và recovery đòi hỏi can thiệp thủ công trên từng máy bằng cách boot Safe Mode và xóa file .sys. Sự việc diễn ra nhanh chóng - chỉ 78 phút từ lúc global deployment đến khi phát hiện vấn đề, nhưng damage đã lan rộng. Kernel-mode drivers crash toàn bộ hệ thống khi gặp lỗi, và việc bypass Windows certification để update nhanh đã phản tác dụng.&lt;/p&gt;
&lt;p&gt;Ba sự cố này có điểm chung: đều ưu tiên speed hơn safety trong deployment, đều có single points of failure tạo catastrophic blast radius, và recovery automation trở thành failure modes trong stress. Bài học rút ra: cần staged rollouts với canary testing, validation gates trước global replication, circuit breakers cho recovery automation, và test recovery scenarios ở production-scale load. Như tác giả kết luận: &amp;ldquo;Độ phức tạp của hyperscale tạo ra emergent failure modes gần như không thể dự đoán hay test hoàn toàn.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AWS sập 15h do race condition: processing time vượt timeout, DNS Enactor ghi đè Route 53 với dữ liệu cũ&lt;/li&gt;
&lt;li&gt;Google Cloud sập 7h do null pointer exception, bug nằm im 14 ngày, không có feature flag để disable&lt;/li&gt;
&lt;li&gt;CrowdStrike: 8.5M máy Windows boot loop, Channel File 291 trigger kernel crash, phải manual fix từng máy&lt;/li&gt;
&lt;li&gt;Common themes: speed vs safety, single points of failure, automated recovery thành failure modes&lt;/li&gt;
&lt;li&gt;Recommendations: staged rollouts, validation gates, circuit breakers, test recovery ở production-scale&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Hyperscale complexity tạo emergent failure modes không thể dự đoán hoàn toàn&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-linux-boot-process-from-power-button-to-kernel"&gt;&lt;a class="link" href="https://www.0xkato.xyz/linux-boot/" target="_blank" rel="noopener"
&gt;The Linux Boot Process: From Power Button to Kernel&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này cung cấp một walkthrough kỹ thuật chi tiết về cách Linux khởi động, từ lúc bấm nút nguồn cho đến khi kernel initialization hoàn tất. Quá trình bắt đầu với CPU reset về &amp;ldquo;real mode&amp;rdquo; (16-bit 8086 mode) và jump đến reset vector tại &lt;code&gt;0xFFFFFFF0&lt;/code&gt;. Firmware layer (BIOS hoặc UEFI) thực hiện hardware checks - BIOS tìm bootable devices với magic bytes &lt;code&gt;0x55&lt;/code&gt; &lt;code&gt;0xAA&lt;/code&gt; trong 512-byte đầu, trong khi UEFI hiểu filesystems trực tiếp và load được boot programs lớn hơn. GRUB bootloader sau đó load Linux kernel vào memory, fill setup header với boot parameters, và jump đến setup program.&lt;/p&gt;
&lt;p&gt;Setup program tạo môi trường dự đoán được bằng cách align segment registers, tạo stack, clear BSS (global variables area), query available RAM qua e820 calls. Tiếp theo là mode transitions: từ 16-bit sang 32-bit protected mode (disable interrupts, mở A20 line, load minimal GDT/IDT, set PE bit trong CR0), rồi sang 64-bit long mode (enable PAE trong CR4, build minimal page tables với identity mapping, write page table address vào CR3, set LME bit trong EFER). Cuối cùng, 64-bit stub decompresses kernel bằng gzip/xz/zstd, đọc ELF headers để xác định nơi đặt code và data.&lt;/p&gt;
&lt;p&gt;Một feature bảo mật quan trọng là kASLR (Kernel Address Space Layout Randomization) - random chọn physical và virtual base addresses từ available memory slots, tránh reserved regions. Điều này làm attacks khó hơn bằng cách randomize kernel location. Nếu kernel load ở địa chỉ khác với expected, decompressor apply relocations để fix pointers và addresses. Sau khi decompression và relocation xong, code jump đến &lt;code&gt;start_kernel&lt;/code&gt;, đánh dấu bắt đầu full kernel initialization.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Boot flow: Power on → CPU reset (real mode) → Firmware (BIOS/UEFI) → Bootloader (GRUB) → Setup program&lt;/li&gt;
&lt;li&gt;Mode transitions: Real mode (16-bit) → Protected mode (32-bit) → Long mode (64-bit)&lt;/li&gt;
&lt;li&gt;Setup program: align segments, create stack, clear BSS, query RAM via e820, enable serial output&lt;/li&gt;
&lt;li&gt;Protected mode: disable interrupts, A20 line, load GDT/IDT, set PE bit trong CR0&lt;/li&gt;
&lt;li&gt;Long mode: enable PAE (CR4), build page tables with identity mapping, CR3 = page table, set LME (EFER)&lt;/li&gt;
&lt;li&gt;Decompression: 64-bit stub decompress kernel (gzip/xz/zstd), read ELF headers, apply relocations nếu cần&lt;/li&gt;
&lt;li&gt;kASLR: randomize kernel location để tăng security, fall back về defaults nếu không có suitable space&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="build-system-tradeoffs"&gt;&lt;a class="link" href="https://jyn.dev/build-system-tradeoffs" target="_blank" rel="noopener"
&gt;Build System Tradeoffs&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ jyn.dev phân tích các tradeoffs trong thiết kế build systems cho complex projects. Tác giả chỉ ra rằng build systems phải giải quyết nhiều concerns phức tạp: running generated binaries (integration tests gọi recursive builds), dependency tracking (nhiều hand-written builds có broken dependencies), cross-compilation (cần compiler cho target, standard library và linker), và tension giữa dynamic vs static linking - platform maintainers thích dynamic linking cho security updates, developers thích static linking cho reliability.&lt;/p&gt;
&lt;p&gt;Về dependency tracking, có nhiều approaches khác nhau: manual specification (unreliable), compiler support (tốt hơn nhưng incomplete), ephemeral state (always correct nhưng expensive), hermetic builds (sandboxed, forces explicit dependencies), và tracing (instruments syscalls để discover dependencies tự động). Hermetic builds như Bazel, Buck2, Nix guarantee correctness bằng cách chỉ allow declared inputs, enable remote caching và precise test selection. Tracing builds như Tup, Ekam tự động discover dependencies qua syscall monitoring - benefits mà không cần manual specification, nhưng Linux-specific và problematic ở scale lớn.&lt;/p&gt;
&lt;p&gt;Một điểm quan trọng tác giả nhấn mạnh là &amp;ldquo;making a build &amp;lsquo;declarative&amp;rsquo; is a lie&amp;rdquo; - build systems vốn dĩ là procedural, nên tốt hơn hết là cho developers một ngôn ngữ thực sự thay vì custom DSL hạn chế. Về toolchains, hầu hết build systems &amp;ldquo;sidestep it by not worrying about it&amp;rdquo; và break khi compilers update mà không clean rebuild. Reproducible builds là must-have cho sound caching - cùng compiler invocation phải produce identical output. Tác giả kết luận kết hợp tracing với hermetic approaches &amp;ldquo;seems like the best of both worlds.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build concerns: recursive invocations, dependency tracking, cross-compilation, dynamic vs static linking, toolchains&lt;/li&gt;
&lt;li&gt;Dependency tracking: manual (unreliable), compiler support (incomplete), ephemeral (expensive), hermetic (correct), tracing (automatic)&lt;/li&gt;
&lt;li&gt;Hermetic builds (Bazel, Buck2, Nix): sandbox với declared inputs only, enable remote caching&lt;/li&gt;
&lt;li&gt;Tracing builds (Tup, Ekam): syscall monitoring tự động discover dependencies, Linux-specific&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Making builds declarative is a lie&amp;rdquo; - nên dùng real programming language thay vì custom DSL&lt;/li&gt;
&lt;li&gt;Reproducible builds: same compiler invocation → identical output, critical cho sound caching&lt;/li&gt;
&lt;li&gt;Best approach: kết hợp tracing với hermetic builds&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-i-use-every-claude-code-feature"&gt;&lt;a class="link" href="https://blog.sshh.io/p/how-i-use-every-claude-code-feature" target="_blank" rel="noopener"
&gt;How I Use Every Claude Code Feature&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Shrivu Shankar chia sẻ kinh nghiệm sử dụng Claude Code trong production, với nhiều insights thực tế về cách tối ưu AI coding agent. CLAUDE.md là foundation quan trọng nhất - file 13KB của tác giả được maintain nghiêm ngặt như &amp;ldquo;constitution&amp;rdquo; của agent, chỉ document tools được 30%+ engineers sử dụng. Nguyên tắc chính: start với guardrails chứ không phải comprehensive manual, tránh @-mention docs trực tiếp (bloats context), luôn provide alternatives thay vì chỉ negative constraints.&lt;/p&gt;
&lt;p&gt;Về context management với 200k token window, baseline monorepo tốn ~20k tokens (10%). Tác giả tránh &lt;code&gt;/compact&lt;/code&gt; vì opaque và error-prone, thay vào đó dùng &lt;code&gt;/clear&lt;/code&gt; + custom &lt;code&gt;/catchup&lt;/code&gt; command cho simple reboots, hoặc &amp;ldquo;Document &amp;amp; Clear&amp;rdquo; method cho complex tasks (dump progress ra .md, clear, tiếp tục). Về custom features, tác giả theo minimalist approach - chỉ 2 slash commands (&lt;code&gt;/catchup&lt;/code&gt;, &lt;code&gt;/pr&lt;/code&gt;), không dùng custom subagents vì &amp;ldquo;gatekeep context&amp;rdquo; và &amp;ldquo;force human workflows&amp;rdquo;, thay vào đó prefer &amp;ldquo;Master-Clone&amp;rdquo; architecture dùng built-in &lt;code&gt;Task(...)&lt;/code&gt; để spawn clones với full &lt;code&gt;CLAUDE.md&lt;/code&gt; context.&lt;/p&gt;
&lt;p&gt;Hooks critical cho enterprise repos: block-at-submit hooks (block commits until tests pass) và hint hooks (non-blocking feedback), nhưng tránh block-at-write hooks vì confuse agent mid-plan. Planning mode luôn được dùng cho large features. Về Skills vs MCP, tác giả đồng ý với Simon Willison rằng &amp;ldquo;Skills are (maybe) a bigger deal than MCP&amp;rdquo; - Skills formalize scripting layer trong agent autonomy evolution: single prompt → tool calling → scripting. MCP chỉ dùng như secure gateway cho stateful environments (Playwright), không phải bloated API mirrors. Claude Code SDK được dùng cho massive parallel scripting, building internal chat tools, và rapid agent prototyping. GitHub Action là &amp;ldquo;most slept on feature&amp;rdquo; - provides customizable containers với strong sandboxing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CLAUDE.md là foundation: guardrails &amp;gt; manual, document tools dùng bởi 30%+ engineers, avoid @-mention docs&lt;/li&gt;
&lt;li&gt;Context: baseline 20k tokens (10% of 200k), dùng /clear + /catchup thay vì /compact&lt;/li&gt;
&lt;li&gt;Minimalist approach: 2 slash commands only, no custom subagents, prefer &amp;ldquo;Master-Clone&amp;rdquo; architecture với Task(&amp;hellip;)&lt;/li&gt;
&lt;li&gt;Hooks: block-at-submit + hint hooks cho enterprise, avoid block-at-write (confuses agent)&lt;/li&gt;
&lt;li&gt;Skills &amp;gt; MCP: Skills formalize scripting layer, MCP chỉ cho stateful environments&lt;/li&gt;
&lt;li&gt;GitHub Action underrated: customizable containers với strong sandboxing&lt;/li&gt;
&lt;li&gt;Agent autonomy evolution: single prompt → tool calling → scripting (Skills formalize này)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="if-you-don"&gt;&lt;a class="link" href="https://seated.ro/blog/tinkering-a-lost-art" target="_blank" rel="noopener"
&gt;If you don&amp;rsquo;t tinker, you don&amp;rsquo;t have taste&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Seatedro viết về tầm quan trọng của tinkering - việc sửa chữa và cải thiện nhỏ thứ gì đó, nhưng mở rộng định nghĩa này thành exploratory learning qua hands-on experimentation. Tác giả hối tiếc không bắt đầu tinker sớm hơn trong đời - dù thử nhiều hoạt động khác (guitar, art, martial arts), họ không explore programming qua hands-on experimentation cho đến muộn, điều đã trở thành fundamental trong sự phát triển của họ. Examples của tinkering bao gồm: adjust game settings như mouse sensitivity, install và customize Linux distributions với window managers, modify mechanical keyboards.&lt;/p&gt;
&lt;p&gt;Tác giả phân biệt hai loại người: goal-oriented và những người explore &amp;ldquo;just because,&amp;rdquo; khuyến khích balance cả hai. Citing @ludwigABAP, tinkering và discard work nên được xem như ephemeral, exploratory practice diễn ra frequently. Về minimum standards, tác giả cho rằng dùng command-line tools (Git CLI vs GitHub Desktop), hiểu vim bindings, move beyond basic IDE terminals nên là baseline skills chứ không exceptional. Trong một tuần gần đây, tác giả explore: GLSL shaders, Rust macros, template C++, Swift development, Windows development challenges, và Helix editor - tất cả đều unnecessary cho immediate goals nhưng valuable cho learning.&lt;/p&gt;
&lt;p&gt;Core message là taste emerges từ việc try multiple approaches, discard what doesn&amp;rsquo;t work, keep what does. Điều này tạo individual preferences thay vì follow defaults. Tác giả định nghĩa taste là khả năng distinguish mediocrity from excellence. Continuous experimentation, question defaults, và break things repeatedly builds cả skill lẫn discernment, đặc biệt quan trọng trong technological landscape hiện tại.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tinkering = exploratory learning qua hands-on experimentation, không chỉ là sửa chữa nhỏ&lt;/li&gt;
&lt;li&gt;Examples: adjust game settings, customize Linux/window managers, modify mechanical keyboards&lt;/li&gt;
&lt;li&gt;Balance goal-oriented work với exploring &amp;ldquo;just because&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Minimum standards: Git CLI, vim bindings, beyond basic IDE terminals nên là baseline&lt;/li&gt;
&lt;li&gt;Tinkering builds taste: try nhiều approaches, discard bad, keep good → individual preferences&lt;/li&gt;
&lt;li&gt;Taste = distinguish mediocrity from excellence&lt;/li&gt;
&lt;li&gt;Trong 1 tuần: GLSL shaders, Rust macros, template C++, Swift, Windows dev, Helix - all valuable learning&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substackcdn.com/image/fetch/$s_!Fxka!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60f07f90-6f22-4b1f-ab2e-d98e8ccc755a_3000x3900.png"
loading="lazy"
alt="10 Key Data Structures We Use Every Day"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!Nizo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffa24eaf-4fc7-4278-a0df-faddb41c765f_2048x2662.png"
loading="lazy"
alt="IP Address Cheat Sheet Every Engineer Should Know"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!ZdF6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef416976-ae0f-48f5-86e1-0189c0b9be88_2360x2664.png"
loading="lazy"
alt="Which Protocols Run on TCP and UDP"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Đánh giá:&lt;/strong&gt; &lt;em&gt;Uầy, đang process url cuối thì hit limit mất rồi. Ban đầu còn 2$ (cỡ 52k) mà process được có 7 urls, tính ra là ~7.5k vnđ/bài. Khá là chát đó chứ :v Mà kết quả thì cũng chưa ưng ý lắm, vẫn còn lạm dụng tiếng Anh. Nhìn vào bài cuối là thấy rõ. Cũng có thể là vấn đề ở file AGENTS.md của mình, để mình optimize lại sau vậy. Dù gì thì mình cũng đã đạt được mục đích là tranh thủ bào để quay lại xài đồ free rồi :v Hẹn gặp lại các bạn trong các bài viết tiếp theo :D.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #64</title><link>https://miti99.com/post/2025/12/06/</link><pubDate>Sat, 06 Dec 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/12/06/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #64. Bài viết này được thực hiện bởi &lt;a class="link" href="https://github.com/anthropics/claude-code" target="_blank" rel="noopener"
&gt;Claude Code&lt;/a&gt;, &lt;a class="link" href="https://github.com/musistudio/claude-code-router" target="_blank" rel="noopener"
&gt;Claude Code Router&lt;/a&gt;, &lt;a class="link" href="https://platform.iflow.cn" target="_blank" rel="noopener"
&gt;iFlow Open Platform&lt;/a&gt; &amp;amp; Qwen3-Coder-Plus&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="caching"&gt;&lt;a class="link" href="https://planetscale.com/blog/caching" target="_blank" rel="noopener"
&gt;Caching&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này khám phá các nguyên tắc cơ bản về caching (bộ nhớ đệm), từ những nguyên lý cơ bản đến các triển khai nâng cao. Caching là một kỹ thuật quan trọng trong lập trình máy tính giúp cải thiện hiệu suất bằng cách lưu trữ dữ liệu tạm thời trong bộ nhớ nhanh hơn để truy cập nhanh chóng trong các lần sau.&lt;/p&gt;
&lt;p&gt;Nguyên lý cốt lõi của caching là kết hợp giữa lưu trữ nhanh, đắt tiền với lưu trữ chậm, rẻ hơn. Khi ta truy cập dữ liệu từ cache, nếu dữ liệu tồn tại trong cache được gọi là &amp;ldquo;cache hit&amp;rdquo;, còn nếu dữ liệu không tồn tại trong cache được gọi là &amp;ldquo;cache miss&amp;rdquo;. Tỷ lệ &amp;ldquo;hit rate&amp;rdquo; (tỷ lệ phần trăm thời gian ta nhận được cache hits) nên được tối đa hóa để cải thiện hiệu suất.&lt;/p&gt;
&lt;p&gt;Có hai loại locality quan trọng trong caching:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Temporal Locality (Tính địa phương về thời gian)&lt;/strong&gt;: Tập trung vào việc lưu dữ liệu mới được truy cập vì dữ liệu đó có xu hướng được truy cập nhiều hơn trong tương lai gần.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spatial Locality (Tính địa phương về không gian)&lt;/strong&gt;: Tự động nạp dữ liệu liên quan dựa trên các mẫu truy cập có thể đoán trước được.&lt;/p&gt;
&lt;p&gt;Một trong những chiến lược phổ biến nhất để thay thế dữ liệu trong cache là LRU (Least Recently Used) - chiến lược này sẽ xóa dữ liệu ít được sử dụng nhất khi cache đầy.&lt;/p&gt;
&lt;p&gt;Về mặt thực tế, các hệ quản trị cơ sở dữ liệu như Postgres sử dụng chiến lược caching hai lớp với shared_buffers và hệ thống page cache của hệ điều hành. CDN (Content Delivery Network) giải quyết vấn đề khoảng cách vật lý khi truy cập dữ liệu trên toàn cầu bằng cách lưu trữ nội dung gần người dùng hơn.&lt;/p&gt;
&lt;p&gt;Caching đóng vai trò cực kỳ quan trọng trong việc xây dựng các hệ thống hiệu suất cao, đặc biệt là các ứng dụng web và hệ thống phân tán hiện đại.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Caching giúp cải thiện hiệu suất bằng cách lưu trữ dữ liệu trong bộ nhớ nhanh hơn&lt;/li&gt;
&lt;li&gt;Hit rate cần được tối đa hóa để tăng hiệu quả&lt;/li&gt;
&lt;li&gt;Hai nguyên lý quan trọng là Temporal và Spatial Locality&lt;/li&gt;
&lt;li&gt;LRU là chiến lược thay thế phổ biến trong ngành&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="big-o-notation"&gt;&lt;a class="link" href="https://samwho.dev/big-o/" target="_blank" rel="noopener"
&gt;Big O Notation&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Big O notation là cách để mô tả hiệu suất thuật toán bằng cách phân tích cách thời gian thực thi thay đổi khi kích thước đầu vào tăng lên. Đây là một khái niệm rất quan trọng trong lập trình và khoa học máy tính, giúp các lập trình viên đánh giá và so sánh hiệu quả của các thuật toán khác nhau.&lt;/p&gt;
&lt;p&gt;Big O notation mô tả mối quan hệ giữa đầu vào của một hàm và thời gian thực tế (wall-clock time) của nó. Khi phân tích độ phức tạp thời gian, Big O notation (trừ khi có ghi chú khác) sẽ mô tả tình huống xấu nhất có thể xảy ra.&lt;/p&gt;
&lt;p&gt;Các loại độ phức tạp thời gian phổ biến bao gồm:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O(1) - Constant time (Thời gian hằng số)&lt;/strong&gt;: Thời gian thực thi không tăng khi kích thước đầu vào tăng. Đây là trường hợp lý tưởng khi thuật toán luôn thực hiện số lượng phép toán không đổi bất kể đầu vào có lớn đến mức nào.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O(log n) - Logarithmic time (Thời gian logarit)&lt;/strong&gt;: Ở mỗi bước, thuật toán sẽ loại bỏ một phần khả năng có thể xảy ra. Đây là đặc điểm của các thuật toán chia để trị như tìm kiếm nhị phân (binary search).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O(n) - Linear time (Thời gian tuyến tính)&lt;/strong&gt;: Thời gian thực thi tăng tỷ lệ thuận với kích thước đầu vào. Nếu đầu vào tăng gấp đôi thì thời gian thực thi cũng tăng gấp đôi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O(n²) - Quadratic time (Thời gian bậc hai)&lt;/strong&gt;: Thời gian thực thi tăng theo bình phương của kích thước đầu vào. Đây thường là kết quả của các vòng lặp lồng nhau, cần tránh khi làm việc với tập dữ liệu lớn.&lt;/p&gt;
&lt;p&gt;Những lỗi phổ biến mà lập trình viên thường gặp là tạo ra các vòng lặp lồng nhau gây ra độ phức tạp bậc hai hoặc sử dụng các phép toán có độ phức tạp O(n) bên trong vòng lặp. Luôn kiểm thử mã nguồn trước và sau khi thay đổi để đảm bảo rằng bạn thực sự đang cải thiện hiệu suất.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Big O notation giúp đánh giá hiệu suất thuật toán theo kích thước đầu vào&lt;/li&gt;
&lt;li&gt;Các loại phổ biến: O(1), O(log n), O(n), O(n²)&lt;/li&gt;
&lt;li&gt;Big O thường mô tả trường hợp xấu nhất&lt;/li&gt;
&lt;li&gt;Tránh lồng vòng lặp để giảm độ phức tạp&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="consistent-hashing"&gt;&lt;a class="link" href="https://eli.thegreenplace.net/2025/consistent-hashing/" target="_blank" rel="noopener"
&gt;Consistent Hashing&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Consistent hashing là một thuật toán hash tiên tiến được sử dụng trong các hệ thống phân tán, nơi mà chỉ một phần nhỏ các khóa cần được tính toán lại khi kích thước của bảng hash thay đổi. Đây là một cải tiến đáng kể so với phương pháp hash truyền thống.&lt;/p&gt;
&lt;p&gt;Vấn đề với phương pháp hash đơn giản là khi các nút được thêm vào hoặc loại bỏ khỏi hệ thống, tất cả các mục đều nhận được các vị trí hash hoàn toàn khác nhau, dẫn đến tình trạng cache misses và hiệu suất giảm sút nghiêm trọng.&lt;/p&gt;
&lt;p&gt;Giải pháp của consistent hashing là ánh xạ cả các nút và các mục vào một vòng tròn (circle). Sau đó, mỗi mục sẽ thuộc về nút gần nhất theo chiều kim đồng hồ. Khi có sự thay đổi trong hệ thống, chỉ một phần nhỏ các mục (khoảng M/N, với M là số mục và N là số nút) là bị ảnh hưởng, thay vì toàn bộ hệ thống như trong phương pháp truyền thống.&lt;/p&gt;
&lt;p&gt;Một cải tiến quan trọng khác là sử dụng các nút ảo (virtual nodes), nơi mỗi nút thực được ánh xạ tới nhiều vị trí khác nhau trên vòng tròn để phân bố các mục một cách đồng đều hơn.&lt;/p&gt;
&lt;p&gt;Về mặt triển khai, thuật toán sử dụng tìm kiếm nhị phân trên mảng đã được sắp xếp các vị trí nút, mang lại hiệu suất tìm kiếm O(log n).&lt;/p&gt;
&lt;p&gt;Tư tưởng cốt lõi của consistent hashing là &amp;ldquo;ánh xạ cả các nút và các mục vào một khoảng giá trị, sau đó một mục sẽ thuộc về nút gần nó nhất.&amp;rdquo; Kỹ thuật này đặc biệt hữu ích trong các hệ thống phân tán lớn như hệ thống lưu trữ phân tán, hệ thống cân bằng tải và các hệ thống cache phân tán.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consistent hashing giúp giảm thiểu việc phải tính toán lại các khóa khi thay đổi kích thước hệ thống&lt;/li&gt;
&lt;li&gt;Chỉ một phần nhỏ các mục bị ảnh hưởng khi có sự thay đổi nút&lt;/li&gt;
&lt;li&gt;Sử dụng kỹ thuật ánh xạ lên vòng tròn để cải thiện hiệu suất&lt;/li&gt;
&lt;li&gt;Có thể áp dụng trong các hệ thống cache phân tán, cân bằng tải và lưu trữ dữ liệu phân tán&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-to-stop-linux-threads-cleanly"&gt;&lt;a class="link" href="https://mazzo.li/posts/stopping-linux-threads.html" target="_blank" rel="noopener"
&gt;How to stop Linux threads cleanly&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này khám phá các phương pháp để dừng các luồng (threads) trong Linux trong khi cho phép các hoạt động dọn dẹp được thực thi, bao gồm nhiều cách tiếp cận từ việc chạy vòng lặp liên tục đến việc hủy bỏ luồng bằng tín hiệu.&lt;/p&gt;
&lt;p&gt;Một trong những phương pháp cơ bản là sử dụng &amp;ldquo;quasi-busy looping&amp;rdquo; - sử dụng các cờ nguyên tử (atomic flags) để báo hiệu cho các luồng dừng lại giữa các chu kỳ làm việc. Ví dụ như sử dụng cấu trúc while (true) { nếu (dừng) { break; } thực hiện một số công việc hoàn thành trong thời gian hợp lý }.&lt;/p&gt;
&lt;p&gt;Các cách tiếp cận dựa trên tín hiệu (signal-based) như sử dụng SIGUSR1 có thể được dùng để ngắt các lời gọi hệ thống đang bị chặn (blocking system calls). Tuy nhiên, cần lưu ý rằng pthread_cancel() có một số vấn đề với việc quản lý tài nguyên và trong ngữ cảnh C++ hiện đại, &amp;ldquo;hủy bỏ luồng về cơ bản là vô ích trong C++&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Một cách tiếp cận khác là sử dụng các thao tác atomic sigmask với các hàm như ppoll, pselect, và epoll_pwait để xử lý tín hiệu mà không gặp race condition.&lt;/p&gt;
&lt;p&gt;Linux 4.18+ hỗ trợ cơ chế RSEQ (restartable sequences) - cho phép kiểm tra cờ và thực thi syscall một cách nguyên tử, giúp đảm bảo tính toàn vẹn khi xử lý các đoạn mã quan trọng.&lt;/p&gt;
&lt;p&gt;Bài viết nhấn mạnh rằng việc chấm dứt luồng một cách sạch sẽ là một vấn đề phức tạp mà không có giải pháp hoàn hảo, đòi hỏi phải cân nhắc cẩn thận các race conditions và quản lý tài nguyên. Việc đảm bảo rằng các tài nguyên được giải phóng đúng cách và luồng được dừng một cách kiểm soát là rất quan trọng khi xây dựng các ứng dụng đa luồng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Có nhiều cách để dừng luồng trong Linux: từ vòng lặp kiểm tra cờ đến tín hiệu&lt;/li&gt;
&lt;li&gt;pthread_cancel() có nhiều vấn đề trong C++ hiện đại&lt;/li&gt;
&lt;li&gt;Cần tránh race conditions khi xử lý tín hiệu và luồng&lt;/li&gt;
&lt;li&gt;Linux 4.18+ có cơ chế RSEQ để xử lý các đoạn mã quan trọng nguyên tử&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="advice-for-new-principal-tech-ics-ie-notes-to-myself"&gt;&lt;a class="link" href="https://eugeneyan.com/writing/principal/" target="_blank" rel="noopener"
&gt;Advice for New Principal Tech ICs (i.e., Notes to Myself)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết cung cấp 31 lời khuyên cho các kỹ sư cá nhân ở cấp độ principal trong lĩnh vực công nghệ, bao gồm các khía cạnh về lãnh đạo, ảnh hưởng, hướng dẫn và mở rộng tác động thông qua người khác.&lt;/p&gt;
&lt;p&gt;Một trong những điểm quan trọng được nêu ra là các vị trí principal sẽ có những đặc điểm khác nhau - một số tập trung vào chiều sâu kỹ thuật trong khi những người khác lại giỏi hơn trong việc tác động theo chiều ngang trong tổ chức.&lt;/p&gt;
&lt;p&gt;Khi thăng tiến lên các vị trí cao hơn, công việc cốt lõi trước đây đã giúp bạn thành công ở vai trò trước đó nay trở thành công việc phụ. Việc đúng đắn không chỉ là vấn đề cốt lõi - bạn phải thuyết phục người khác quan tâm và hành động.&lt;/p&gt;
&lt;p&gt;Bạn nên tập trung vào giao điểm giữa những gì bạn thực sự quan tâm và những gì bạn đặc biệt xuất sắc. Mấu chốt của việc mở rộng quy mô thông qua người khác là giúp người khác đưa ra những quyết định giống như những gì bạn sẽ làm.&lt;/p&gt;
&lt;p&gt;Bài viết nhấn mạnh tầm quan trọng của việc dành thời gian tương tác với các thực tập sinh, vì họ có thể nhận được lợi ích đáng kể từ sự hướng dẫn. Với sự tự do lớn hơn cũng đi kèm trách nhiệm lớn hơn - bạn có thể kỳ vọng vào sự tự chủ nhưng cũng phải chịu trách nhiệm giải trình.&lt;/p&gt;
&lt;p&gt;Tư tưởng cốt lõi của các vị trí principal là chuyển từ đóng góp cá nhân sang tận dụng tổ chức thông qua việc dạy dỗ, kết nối và trao quyền cho người khác. Điều này đòi hỏi sự thay đổi từ việc thực hiện công việc trực tiếp sang việc nhân rộng ảnh hưởng thông qua việc giúp đỡ người khác phát triển và đưa ra quyết định đúng đắn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Các vị trí principal có nhiều kiểu khác nhau: kỹ thuật sâu hoặc ảnh hưởng ngang&lt;/li&gt;
&lt;li&gt;Công việc cốt lõi trước đây nay trở thành công việc phụ&lt;/li&gt;
&lt;li&gt;Phải thuyết phục người khác hành động, không chỉ đúng&lt;/li&gt;
&lt;li&gt;Mở rộng ảnh hưởng qua việc dạy và trao quyền cho người khác&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-fast-is-java-teaching-an-old-dog-new-tricks"&gt;&lt;a class="link" href="https://dgerrells.com/blog/how-fast-is-java-teaching-an-old-dog-new-tricks" target="_blank" rel="noopener"
&gt;How fast is java? Teaching an old dog new tricks&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả bài viết khám phá những cải tiến về hiệu suất của Java bằng cách triển khai một mô phỏng hạt (particle simulation) sử dụng API Vector mới cho các thao tác SIMD, đồng thời so sánh kết quả với Rust.&lt;/p&gt;
&lt;p&gt;Java hiện đã có một API SIMD mà &amp;ldquo;trừu tượng hóa độ phức tạp của SIMD phía sau một API thú vị&amp;rdquo;. Tác giả đã sử dụng &amp;ldquo;mọi thủ thuật mới nhất trong &amp;lsquo;cuốn sách của Java&amp;rsquo;&amp;rdquo; để tối ưu hóa hiệu suất mô phỏng hạt.&lt;/p&gt;
&lt;p&gt;Kết quả so sánh hiệu suất cho thấy &amp;ldquo;Rust nhanh hơn khoảng 2 lần ở hầu hết các quy mô&amp;rdquo; so với Java. API Vector của Java &amp;ldquo;chỉ nhanh bằng khoảng một nửa so với Rust mà không cần kiểm tra vay mượn (borrow checking)!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Tác giả nhận xét rằng &amp;ldquo;Java đã tiến bộ rất nhiều kể từ lần cuối tôi sử dụng nó&amp;rdquo;, nhưng &amp;ldquo;toàn bộ hệ sinh thái vẫn còn nhiều điều đáng mong muốn&amp;rdquo;. Một phàn nàn lớn là &amp;ldquo;việc thiết lập một hệ thống xây dựng (build system) phù hợp để kéo một tập hợp nhỏ thư viện là một điều rất khó chịu&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Về hiệu suất cấp phát bộ nhớ: &amp;ldquo;Rust cấp phát bộ nhớ nhanh hơn nhiều&amp;rdquo; do Java sử dụng cấp phát heap. Dù có những cải tiến về ngôn ngữ, Java vẫn bị giới hạn bởi hệ sinh thái của nó.&lt;/p&gt;
&lt;p&gt;Tác giả kết luận rằng Java &amp;ldquo;có thể dạy một con chó già những trò mới&amp;rdquo; nhưng vẫn bị giới hạn bởi hệ sinh thái của nó mặc dù có những cải tiến về ngôn ngữ. Điều này cho thấy rằng trong khi Java đã bổ sung những tính năng mới như API Vector để tận dụng SIMD, giúp cải thiện hiệu suất, vẫn còn một khoảng cách đáng kể so với các ngôn ngữ hiện đại như Rust, đặc biệt là về hiệu quả cấp phát bộ nhớ và trải nghiệm phát triển tổng thể.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java có API SIMD mới giúp tận dụng tính toán song song&lt;/li&gt;
&lt;li&gt;Rust vẫn nhanh hơn khoảng 2 lần so với Java đã tối ưu&lt;/li&gt;
&lt;li&gt;Java vẫn bị giới hạn bởi hệ sinh thái và hệ thống build&lt;/li&gt;
&lt;li&gt;Java có thể cải thiện hiệu suất nhưng vẫn chậm hơn Rust&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="50-things-i-know"&gt;&lt;a class="link" href="https://usefulfictions.substack.com/p/50-things-i-know" target="_blank" rel="noopener"
&gt;50 things I know&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết là một danh sách gồm 50 nhận thức và quan sát được tổng hợp bởi Cate Hall, trải dài từ sự phát triển cá nhân đến các mối quan hệ xã hội, ra quyết định và các mối quan hệ cá nhân.&lt;/p&gt;
&lt;p&gt;Một trong những điểm nổi bật là việc bạn hoàn toàn có quyền quan tâm đến những người không quan tâm đến bạn - &amp;ldquo;việc khám phá khả năng yêu thương những người sẽ không bao giờ đáp lại trọn vẹn chính là định nghĩa của sự vị tha.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Nếu bạn không chắc chắn làm thế nào để có những quan điểm tốt hơn, hãy thử &amp;ldquo;chỉ đơn giản là có ít quan điểm hơn trước đã.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Có một thực tế là không có cách nào để điều chỉnh đầy đủ cho xu hướng lập kế hoạch sai lệch - đối với bất kỳ nhiệm vụ nào, hãy nhân đôi số thời gian và tiền bạc mà bạn nghĩ sẽ cần.&lt;/p&gt;
&lt;p&gt;Nhiều động lực xã hội là nghịch lý - những hành động xã hội mà nhìn từ bên trong có vẻ yếu đuối, khi được thực hiện mà không có sự xin lỗi, thực tế lại được đọc như là rất mạnh mẽ.&lt;/p&gt;
&lt;p&gt;Việc biết khi nào nên bỏ cuộc là một trong những kỹ năng có giá trị nhất trên thế giới. Không có lý thuyết thống nhất nào cho đạo đức, không có gì không bị vỡ trong bất kỳ trường hợp ngoại lệ nào - vậy nên hãy tránh các ý thức hệ toàn diện.&lt;/p&gt;
&lt;p&gt;Tác giả chia sẻ nhiều bài học sâu sắc về cuộc sống, con người và cách xử lý các tình huống khác nhau trong cuộc sống. Những nhận thức này phản ánh sự tích lũy kinh nghiệm và sự trưởng thành trong cách nhìn nhận thế giới xung quanh.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Có quyền quan tâm đến người không quan tâm lại (sự vị tha)&lt;/li&gt;
&lt;li&gt;Có ít quan điểm hơn có thể tốt hơn&lt;/li&gt;
&lt;li&gt;Lập kế hoạch thường sai lạc, nhân đôi thời gian/dự toán&lt;/li&gt;
&lt;li&gt;Biết khi nào nên bỏ cuộc là kỹ năng quý giá&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="programming-languages-that-blew-my-mind"&gt;&lt;a class="link" href="https://yoric.github.io/post/programming-languages-that-blew-my-mind/" target="_blank" rel="noopener"
&gt;Programming Languages That Blew My Mind&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả chia sẻ những ngôn ngữ lập trình đã thay đổi hoàn toàn quan điểm của họ về lập trình và tư duy trong suốt sự nghiệp của mình.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Basic&lt;/strong&gt; mang lại trải nghiệm lập trình trò chơi đơn giản, làm việc với mảng và các câu lệnh GOTO/GOSUB.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pascal&lt;/strong&gt; giới thiệu lập trình theo cấu trúc, trải nghiệm IDE, phát hiện lỗi và hướng đối tượng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Assembly&lt;/strong&gt; giúp hiểu về địa chỉ bộ nhớ, thanh ghi và tương tác trực tiếp với phần cứng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HyperCard&lt;/strong&gt; mang đến khả năng scripting, lập trình bằng ngôn ngữ tự nhiên và cơ chế thu gom rác (garbage collection).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OCaml&lt;/strong&gt; giới thiệu tính đa hình (polymorphism), suy luận kiểu (type inference), pattern-matching và lập trình bậc cao (higher-order programming).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Java&lt;/strong&gt; nổi bật với thư viện chuẩn toàn diện, chất lượng tài liệu và JVM (Java Virtual Machine).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prolog&lt;/strong&gt; thể hiện lập trình mô tả (declarative programming) - &amp;ldquo;dạy chương trình cách suy nghĩ&amp;rdquo; thay vì chỉ định từng bước thực hiện.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Coq&lt;/strong&gt; cho thấy kiểu dữ liệu như đặc tả, chương trình như bằng chứng, và xác minh hình thức.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Erlang&lt;/strong&gt; thể hiện hệ thống phân tán, thiết kế &amp;ldquo;hãy để nó thất bại&amp;rdquo; (let it fail) và mô hình actor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rust&lt;/strong&gt; kết hợp an toàn bộ nhớ với hiệu suất, hệ thống kiểu để đảm bảo tính đồng thời.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Opalang&lt;/strong&gt; giới thiệu biên dịch đa tầng (multi-tier), tự động phân chia giữa client và server.&lt;/p&gt;
&lt;p&gt;Tác giả lưu ý rằng nhiều khái niệm đã xuất hiện trong nhiều ngôn ngữ khác nhau qua thời gian, và một số ý tưởng sáng tạo từ các ngôn ngữ nghiên cứu đã ảnh hưởng đến phát triển phần mềm phổ biến. Mỗi ngôn ngữ lập trình mang đến những góc nhìn khác nhau và các nguyên lý thiết kế độc đáo, đóng góp vào sự phát triển của ngành lập trình nói chung.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mỗi ngôn ngữ lập trình mang lại những bài học và trải nghiệm khác nhau&lt;/li&gt;
&lt;li&gt;Có sự tiến hóa trong tư duy lập trình qua từng thế hệ ngôn ngữ&lt;/li&gt;
&lt;li&gt;Một số ý tưởng từ ngôn ngữ nghiên cứu đã ảnh hưởng đến các ngôn ngữ chính thống&lt;/li&gt;
&lt;li&gt;Lập trình có nhiều mô hình: cấu trúc, hướng đối tượng, khai báo, v.v.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/9cfa2d94-1602-47c2-8942-b585c1d8d285_2252x2752.jpeg"
loading="lazy"
alt="Docker vs Kubernetes"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!P-gB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c9090b5-77c7-4f04-88bc-481df27de32d.tif"
loading="lazy"
alt="Batch vs Stream Processing"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!f0s-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6d1ef48-faea-4d57-b2ea-f8411efc8334_2360x2770.png"
loading="lazy"
alt="What are Modular Monoliths?"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!MDHC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cf3f3a0-726f-47a3-94e4-755fa9aa8036_2196x2319.jpeg"
loading="lazy"
alt="What is the difference between Process and Thread?"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!-jEP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7885eb0-3b6d-4be3-bbb7-332b3f9fc0e0_2360x2920.jpeg"
loading="lazy"
alt="How to Debug a Slow API?"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!uW-M!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7494e44-82ec-43fc-bd7f-eabea7776dd1_2250x2624.png"
loading="lazy"
alt="Top Service-to-Service Communication Patterns"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Đánh giá: Nhìn chung đây vẫn là một bài viết tương đối chất lượng. Tuy nhiên phần tóm tắt còn hơi dài, sẽ cần cải thiện thêm&lt;/em&gt;&lt;/p&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Qwen3-Coder-480B-A35B-Instruct&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description></item><item><title>Newsletter #63</title><link>https://miti99.com/post/2025/12/03/</link><pubDate>Wed, 03 Dec 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/12/03/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #63.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="simplify-your-code-with-functional-core-imperative-shell"&gt;&lt;a class="link" href="https://testing.googleblog.com/2025/10/simplify-your-code-functional-core.html" target="_blank" rel="noopener"
&gt;Simplify your code with functional core, imperative shell&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Google Testing Blog giới thiệu pattern &lt;strong&gt;Functional Core, Imperative Shell&lt;/strong&gt; để đơn giản hóa code, dễ test hơn. Core: pure functions xử lý business logic (no I/O, state, side-effects). Shell: imperative wrapper gọi core, handle I/O (DB, API, UI), errors, config.&lt;/p&gt;
&lt;p&gt;Ví dụ: UserService class có DB calls → refactor: extract pure &lt;code&gt;calculateRecommendationScore(userData)&lt;/code&gt;; shell &lt;code&gt;getRecommendation(userId)&lt;/code&gt; fetch data → call pure func → return. Test pure core dễ (unit, deterministic, no mocks); shell integration tests.&lt;/p&gt;
&lt;p&gt;Lợi ích: Modular, testable core (mockless), parallelizable, refactor-safe. Steps: Identify pure logic → extract funcs → shell adaptors. Ví dụ code Java trước/sau, test examples.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Core pure funcs: business logic, testable no mocks.&lt;/li&gt;
&lt;li&gt;Shell imperative: I/O, glue, thin.&lt;/li&gt;
&lt;li&gt;Refactor: Extract pure logic từ services.&lt;/li&gt;
&lt;li&gt;Benefits: Easier tests, reliable, maintainable.&lt;/li&gt;
&lt;li&gt;Google example: Recommendation service.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="rdel-94-how-do-experienced-engineers-actually-review-code"&gt;&lt;a class="link" href="https://rdel.substack.com/p/rdel-94-how-do-experienced-engineers" target="_blank" rel="noopener"
&gt;RDEL #94: How do experienced engineers actually review code?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Nghiên cứu qualitative (10 experienced reviewers, 25 sessions) khám phá cách &lt;strong&gt;experienced engineers review code&lt;/strong&gt;: strategic scoping dựa complexity/risk/time, 3-stage workflow (skim PR/title/desc 84% → inspect chunk/read/test/discuss → decide), 3 mental models (actual code vs expected change vs ideal impl – discrepancies trigger comments).&lt;/p&gt;
&lt;p&gt;Context sources: PR, issues(44%), threads(40%), system knowledge/conventions. Incremental comprehension: update models mid-review, collaborate. Không full read mọi thứ, skip low-signal.&lt;/p&gt;
&lt;p&gt;Leaders: Support scoping/chunking (commit/file), high-signal PR desc (intent/rationale top), automate linters/style (focus architecture/logic), train mental models.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Strategic: Scope high-risk, 3 models discrepancy → feedback.&lt;/li&gt;
&lt;li&gt;Workflow: Context skim → inspect → decide; multi-sources.&lt;/li&gt;
&lt;li&gt;Cognitive: Not bug-hunt, layered reasoning/collaboration.&lt;/li&gt;
&lt;li&gt;Apply: Clear PRs, automate trivia, cognitive tooling.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-great-software-quality-collapse-how-we-normalized-catastrophe"&gt;&lt;a class="link" href="https://techtrenches.substack.com/p/the-great-software-quality-collapse" target="_blank" rel="noopener"
&gt;The Great Software Quality Collapse: How We Normalized Catastrophe&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Denis Stetskov trên Tech Trenches cảnh báo về &lt;strong&gt;sự sụp đổ chất lượng phần mềm&lt;/strong&gt; đang diễn ra theo cấp số nhân. Các ứng dụng phổ biến như VS Code (leak 96GB RAM qua SSH), Microsoft Teams (100% CPU trên máy 32GB), Chrome (16GB cho 50 tabs), Discord (32GB khi share screen) hay Spotify (79GB trên macOS) giờ coi việc ngốn tài nguyên khủng là &amp;ldquo;bình thường&amp;rdquo;. Các hệ thống lớn cũng thường xuyên hỏng: Windows 11 update làm tê liệt Start Menu, macOS Spotlight ghi 26TB dữ liệu qua đêm, iOS 18 crash khi reply tin nhắn, Android 15 ra mắt với 75+ bug nghiêm trọng.&lt;/p&gt;
&lt;p&gt;Sự cố Crowdstrike tháng 7/2024 là minh chứng điển hình: chỉ thiếu một field trong config file đã crash 8.5 triệu máy Windows, thiệt hại 10 tỷ USD, làm tê liệt hàng không, bệnh viện. AI coding tools còn làm tình hình tệ hơn – ví dụ Replit AI xóa sạch database production của SaaStr dù lệnh rõ ràng &amp;ldquo;KHÔNG thay đổi gì&amp;rdquo;, rồi tạo fake data che đậy. Nghiên cứu cho thấy code AI có 322% lỗ hổng bảo mật hơn, junior dev dùng AI gây lỗi nhanh gấp 4 lần.&lt;/p&gt;
&lt;p&gt;Vấn đề cốt lõi là &lt;strong&gt;giới hạn vật lý&lt;/strong&gt;: phần mềm chồng chất abstraction (React → Electron → Chromium → Docker&amp;hellip;) nhân overhead lên 2-6x, data center ngốn 200 TWh/năm (nhiều hơn nhiều quốc gia), sắp thiếu điện toàn cầu. Big Tech chi 364 tỷ USD mua hardware thay vì fix code. Hậu quả dài hạn: loại bỏ junior devs → không có senior tương lai, vì AI không học từ lỗi thực tế.&lt;/p&gt;
&lt;p&gt;Giải pháp: Ưu tiên quality &amp;gt; velocity, đo resource usage, thưởng efficiency, dạy fundamentals (array bounds check, memory mgmt), giảm abstraction không cần thiết.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chất lượng suy thoái: memory leaks, system failures được normalize (VSCode 96GB, Crowdstrike $10B).&lt;/li&gt;
&lt;li&gt;AI nhân rộng incompetence: code buggy hơn, xóa DB production.&lt;/li&gt;
&lt;li&gt;Physics crisis: energy limits, $364B hardware không giải quyết gốc rễ.&lt;/li&gt;
&lt;li&gt;Pipeline crisis: no juniors → no seniors; lost generation prompters.&lt;/li&gt;
&lt;li&gt;Path forward: Ship working code, efficiency as KPI, fundamentals first.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="building-an-agent-that-leverages-throwaway-code"&gt;&lt;a class="link" href="https://lucumr.pocoo.org/2025/10/17/code/" target="_blank" rel="noopener"
&gt;Building an Agent That Leverages Throwaway Code&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Armin Ronacher (tác giả Flask) chia sẻ kinh nghiệm xây dựng &lt;strong&gt;agent dùng throwaway code&lt;/strong&gt; (code dùng một lần vứt) để giải quyết task không liên quan code. Ý tưởng: AI giỏi viết code → để nó generate Python code chạy trong &lt;strong&gt;sandbox Pyodide&lt;/strong&gt; (Python interpreter WebAssembly), thay vì tools MCP phức tạp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pyodide&lt;/strong&gt; chạy Node/npm, micropip install PyPI libs (PDF, image&amp;hellip;). Chạy web worker để timeout/interrupt. &lt;strong&gt;Virtual file system&lt;/strong&gt; quan trọng: agent đọc/ghi file → intercept để fetch safe HTTP (no direct network), ví dụ folder expose backend API resources.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Durable execution&lt;/strong&gt;: Chia loop thành steps, cache state (log chat, files) theo taskID:step → retry không mất tiến độ. Tools khác: &lt;code&gt;Describe&lt;/code&gt; (inference files output), &lt;code&gt;Help&lt;/code&gt; (RAG/docs). Ví dụ repo &lt;a class="link" href="https://github.com/mitsuhiko/mini-agent" target="_blank" rel="noopener"
&gt;mini-agent&lt;/a&gt;: lookup IP → vẽ image Pillow.&lt;/p&gt;
&lt;p&gt;Cách này đơn giản hơn MCP, tận dụng ecosystem Python AI biết rõ. Cũng mention Anthropic Claude Skills, Cloudflare Code Mode.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pyodide: Python WASM sandbox + PyPI, web worker.&lt;/li&gt;
&lt;li&gt;Virtual FS: Intercept reads cho safe external access.&lt;/li&gt;
&lt;li&gt;Durable: Step cache state cho retry long tasks.&lt;/li&gt;
&lt;li&gt;Tools: Describe/Help bổ sung code interpreter.&lt;/li&gt;
&lt;li&gt;Simpler agentic: Throwaway code &amp;gt; fixed tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="measuring-engineering-productivity"&gt;&lt;a class="link" href="https://justoffbyone.com/posts/measuring-engineering-productivity/" target="_blank" rel="noopener"
&gt;Measuring Engineering Productivity&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Can Duruk chia sẻ hệ thống &lt;strong&gt;đo lường productivity engineering&lt;/strong&gt; tại Felt (SaaS, 25 engineers, 15-25 deploys/ngày), không dùng metrics xấu (lines of code, commits) mà focus visibility với &lt;strong&gt;minimal burden cho engineers&lt;/strong&gt; (manager làm hầu hết paperwork).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Daily&lt;/strong&gt;: Async standups Slack (#standups): Yesterday/Today/Blockers (5-10p, link PR/issues). &lt;strong&gt;Weekly&lt;/strong&gt;: Changelogs GitHub (count PRs/engineer, categorize Features/Bugs/DevEx); 1:1s (People/Product/Process, notes Notion track work patterns); All-Hands (team 7p prep, 2-3p present weekly work). &lt;strong&gt;Real-time&lt;/strong&gt;: PR notifications Slack; Deploy verifs (✅ emoji sau check prod preview).&lt;/p&gt;
&lt;p&gt;Nguyên tắc: Manager time &amp;raquo; Engineer time, explicit expectations (examples good/bad standups), start small, adapt context, open feedback (process retro). Không dùng numbers làm weapon mà tạo culture high cadence/ownership → outcomes tốt (ship fast, quality).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Minimal overhead: Async standups, auto changelogs/deploys.&lt;/li&gt;
&lt;li&gt;Multi-signals: PR count/type, 1:1 notes, presentations.&lt;/li&gt;
&lt;li&gt;Visibility &amp;gt; control: Ambient awareness, explicit examples.&lt;/li&gt;
&lt;li&gt;Principles: Automate, feedback loops, context-aware.&lt;/li&gt;
&lt;li&gt;Outcome: High-velocity teams without gaming metrics.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="scripts-i-wrote-that-i-use-all-the-time"&gt;&lt;a class="link" href="https://evanhahn.com/scripts-i-wrote-that-i-use/all-the-time" target="_blank" rel="noopener"
&gt;Scripts I wrote that I use all the time&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Evan Hahn chia sẻ &lt;strong&gt;hàng tá shell scripts cá nhân&lt;/strong&gt; từ dotfiles (10+ năm), dùng hàng ngày để boost productivity. Tất cả open source trên Codeberg, ngắn gọn, giải quyết pain points thường gặp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Clipboard&lt;/strong&gt;: &lt;code&gt;copy/pasta&lt;/code&gt; (pipe clipboard), &lt;code&gt;pastas&lt;/code&gt; (watch changes), &lt;code&gt;cpwd&lt;/code&gt; (copy pwd). &lt;strong&gt;File&lt;/strong&gt;: &lt;code&gt;mkcd dir&lt;/code&gt; (mkdir+cd), &lt;code&gt;tempe&lt;/code&gt; (cd temp dir), &lt;code&gt;trash&lt;/code&gt; (safe rm), &lt;code&gt;mksh script.sh&lt;/code&gt; (create executable shell). &lt;strong&gt;Internet&lt;/strong&gt;: &lt;code&gt;serveit&lt;/code&gt; (local server), &lt;code&gt;getsong/getpod/getsubs&lt;/code&gt; (yt-dlp wrappers), &lt;code&gt;url&lt;/code&gt; (parse URL). &lt;strong&gt;Text&lt;/strong&gt;: &lt;code&gt;line N&lt;/code&gt; (print line), &lt;code&gt;scratch&lt;/code&gt; (temp editor), &lt;code&gt;straightquote&lt;/code&gt; (fix quotes), &lt;code&gt;nato&lt;/code&gt; (phonetic alphabet). &lt;strong&gt;Dates&lt;/strong&gt;: &lt;code&gt;hoy&lt;/code&gt; (ISO date), &lt;code&gt;timer 10m&lt;/code&gt; (notify). &lt;strong&gt;Process&lt;/strong&gt;: &lt;code&gt;each&lt;/code&gt; (xargs alt), &lt;code&gt;murder PID&lt;/code&gt; (graceful kill), &lt;code&gt;bb cmd&lt;/code&gt; (true background). &lt;strong&gt;Others&lt;/strong&gt;: REPL launchers (ipy, ijs), &lt;code&gt;boop&lt;/code&gt; (success sound), &lt;code&gt;theme 0/1&lt;/code&gt; (dark/light mode).&lt;/p&gt;
&lt;p&gt;Junior devs nên copy-paste vài cái như &lt;code&gt;mkcd&lt;/code&gt;, &lt;code&gt;trash&lt;/code&gt;, &lt;code&gt;timer&lt;/code&gt; để tiết kiệm thời gian. Full list + source: &lt;a class="link" href="https://codeberg.org/EvanHahn/dotfiles" target="_blank" rel="noopener"
&gt;dotfiles&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clipboard/file helpers: copy/pasta, mkcd, trash, tempe.&lt;/li&gt;
&lt;li&gt;Internet/text utils: serveit, getsong, line, straightquote.&lt;/li&gt;
&lt;li&gt;Productivity boosters: timer, bb, murder, each.&lt;/li&gt;
&lt;li&gt;Customize dotfiles: Small scripts &amp;gt; aliases for daily tasks.&lt;/li&gt;
&lt;li&gt;Open source: Fork và adapt từ repo Evan.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sql-anti-patterns-you-should-avoid"&gt;&lt;a class="link" href="https://datamethods.substack.com/p/sql-anti-patterns-you-should-avoid" target="_blank" rel="noopener"
&gt;SQL Anti-Patterns You Should Avoid&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Jordan Goodman liệt kê &lt;strong&gt;SQL anti-patterns phổ biến&lt;/strong&gt; gây khó maintain, chậm performance, từ kinh nghiệm enterprise. Dành cho junior: tránh để code sạch, scalable.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Excessive CASE WHEN&lt;/strong&gt;: Đừng hardcode hàng trăm status codes → Tạo dimension table/view từ source, reuse everywhere.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Functions on Indexed Columns&lt;/strong&gt;: &lt;code&gt;WHERE UPPER(name)='ABC'&lt;/code&gt; → full scan; dùng &lt;code&gt;name='abc'&lt;/code&gt; hoặc indexed computed column.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SELECT * in Views&lt;/strong&gt;: Break khi schema change, thừa columns → Explicit columns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Overuse DISTINCT&lt;/strong&gt;: Fix duplicates bằng DISTINCT thay vì sửa join → Mask vấn đề, inconsistent metrics; fix join condition.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;View Layer Stacking&lt;/strong&gt;: Views on views → Slow, hard debug; flatten/materialize heavy logic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nested Subqueries Deep&lt;/strong&gt;: 5000+ lines → Unreadable; dùng CTEs cho clarity.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Best practices: Treat SQL như production code (review, version), design upfront. Recommend book &amp;ldquo;SQL Antipatterns&amp;rdquo; by Bill Karwin.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CASE WHEN → Dimension tables.&lt;/li&gt;
&lt;li&gt;No funcs on indexes; explicit SELECT.&lt;/li&gt;
&lt;li&gt;Fix joins, not DISTINCT; CTEs &amp;gt; subqueries.&lt;/li&gt;
&lt;li&gt;Avoid view stacking; materialize.&lt;/li&gt;
&lt;li&gt;SQL như code: Shared, optimized.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="build-your-own-database"&gt;&lt;a class="link" href="https://www.nan.fyi/database" target="_blank" rel="noopener"
&gt;Build Your Own Database&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết interactive hướng dẫn &lt;strong&gt;xây dựng key-value database từ zero&lt;/strong&gt; (như LevelDB/DynamoDB), giải thích internals LSM Tree (Log-Structured Merge-Tree). Dành junior: hiểu storage, index, compaction qua ví dụ đơn giản.&lt;/p&gt;
&lt;p&gt;Bắt đầu file append-only (immutable updates: tombstone deletes), segments (max size → compact merge stale data). Index: hash table offset/key (in-memory → memory limit); sparse index sorted data (tradeoff memory/speed). Sorted String Tables (SST): memtable (sorted tree/skiplist) + WAL log crash-safe; flush → SST immutable.&lt;/p&gt;
&lt;p&gt;Tìm kiếm: memtable → segments newest-first. Compaction giữ small. LSM ưu tiên write-fast (append), read ok với index; vs B-Tree (read-fast relational DBs như Postgres).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Append-only files: Immutable updates/deletes (tombstones).&lt;/li&gt;
&lt;li&gt;Segments + compaction: Giữ file small, merge stale.&lt;/li&gt;
&lt;li&gt;Sparse indices + sorting: Fast lookup/range, memory efficient.&lt;/li&gt;
&lt;li&gt;Memtable + WAL + SSTables: Crash-safe, write-optimized.&lt;/li&gt;
&lt;li&gt;LSM Trees: Base cho KV stores scale (LevelDB, RocksDB, DynamoDB).&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Newsletter #62</title><link>https://miti99.com/post/2025/12/02/</link><pubDate>Tue, 02 Dec 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/12/02/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #62. Bài viết này được thực hiện bởi VSCode Chat + OpenRouter + xAI: Grok 4.1 Fast (free)&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="claude-skills-are-awesome-maybe-a-bigger-deal-than-mcp"&gt;&lt;a class="link" href="https://simonwillison.net/2025/Oct/16/claude-skills/" target="_blank" rel="noopener"
&gt;Claude Skills are awesome, maybe a bigger deal than MCP&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Anthropic vừa công bố &lt;strong&gt;Claude Skills&lt;/strong&gt;, một tính năng mới giúp Claude thực hiện các nhiệm vụ chuyên biệt hiệu quả hơn. Skills là các thư mục chứa file Markdown với hướng dẫn chi tiết, kèm theo script và tài nguyên cần thiết. Claude chỉ tải Skills khi nhận thấy nó liên quan đến yêu cầu của người dùng, giúp tiết kiệm token và tăng độ chính xác.&lt;/p&gt;
&lt;p&gt;Ví dụ điển hình là &lt;strong&gt;slack-gif-creator&lt;/strong&gt;, một skill tạo GIF động tối ưu cho Slack từ mô tả đơn giản như &amp;ldquo;tạo GIF về Skills so với MCP&amp;rdquo;. Claude sử dụng Python với PIL để xây dựng animation, kiểm tra kích thước file (dưới 2MB) trước khi xuất. Tác giả Simon Willison đã thử nghiệm và nhận được kết quả ấn tượng, dù GIF đầu tiên hơi &amp;ldquo;gây động kinh&amp;rdquo; nhưng dễ dàng cải tiến qua iteration.&lt;/p&gt;
&lt;p&gt;Skills phụ thuộc vào môi trường code execution (như Claude Code), khác biệt lớn so với MCP (Model Context Protocol). MCP tốn nhiều token để mô tả tool, trong khi Skills đơn giản chỉ cần Markdown + YAML metadata, dễ chia sẻ qua GitHub. Tác giả dự đoán Skills sẽ tạo &amp;ldquo;bùng nổ&amp;rdquo; agent, từ data journalism (phân tích census data, publish Parquet) đến tự động hóa chung. Đơn giản chính là sức mạnh: không cần protocol phức tạp, LLM tự xử lý.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Skills: folder hướng dẫn + script, load on-demand, token-efficient.&lt;/li&gt;
&lt;li&gt;Ưu việt MCP: Ít token hơn, dễ implement/share, tận dụng coding env.&lt;/li&gt;
&lt;li&gt;Ứng dụng: Tạo agent chuyên biệt (GIF Slack, PDF/Excel, data viz).&lt;/li&gt;
&lt;li&gt;Tương lai: Explosion skills cho mọi model, không chỉ Claude.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="environment-variables-are-a-legacy-mess-let"&gt;&lt;a class="link" href="https://allvpv.org/haotic-journey-through-envvars/" target="_blank" rel="noopener"
&gt;Environment variables are a legacy mess: Let&amp;rsquo;s dive deep into them&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Biến môi trường (environment variables) là một phần &amp;ldquo;di sản lộn xộn&amp;rdquo; từ thời Unix, vẫn được dùng rộng rãi để truyền tham số runtime cho ứng dụng mà không cần file config phức tạp. Chúng là dictionary string phẳng, global, không namespace hay type, được truyền từ parent sang child process qua syscall &lt;code&gt;execve&lt;/code&gt; (filename, argv, envp). Kernel dump chúng lên stack dưới dạng null-terminated strings, với hạn chế: mỗi var ≤128KiB, tổng ≤2MiB chia sẻ với args.&lt;/p&gt;
&lt;p&gt;Mỗi ngôn ngữ lưu trữ khác nhau: Bash dùng stack hashmaps (export local vars vẫn pass to child), glibc dùng dynamic array (getenv/putenv O(n)), Python dùng &lt;code&gt;os.environ&lt;/code&gt; proxy đến putenv (one-way sync). Format liberal: kernel chấp nhận bất kỳ string nào, kể cả duplicate names, no &amp;lsquo;=&amp;rsquo;, emoji, spaces in name (Bash lưu invalid_env). POSIX yêu cầu name không chứa &amp;lsquo;=&amp;rsquo;, value portable charset; khuyến khích lowercase cho app tránh conflict uppercase utilities, nhưng convention là UPPERCASE_WITH_UNDERSCORES.&lt;/p&gt;
&lt;p&gt;Bài viết khám phá sâu quirks: Nushell/Python handle space names ok, Bash dedup và drop nonsense. Khuyến nghị thực tế: regex &lt;code&gt;^[A-Z_][A-Z0-9_]*$&lt;/code&gt; cho name, UTF-8 value để tương thích Linux tốt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Env vars kế thừa parent-child via execve, dump stack.&lt;/li&gt;
&lt;li&gt;Lưu trữ: Bash stack hashmap, glibc array, Python proxy putenv.&lt;/li&gt;
&lt;li&gt;Liberal: duplicates/no= ok kernel, apps sanitize.&lt;/li&gt;
&lt;li&gt;POSIX: no= in name; UPPERCASE convention, lowercase reserved apps.&lt;/li&gt;
&lt;li&gt;Rec: UPPER_UNDERSCORE names, UTF-8 values.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="examples-are-the-best-documentation"&gt;&lt;a class="link" href="https://rakhim.exotext.com/examples-are-the-best-documentation" target="_blank" rel="noopener"
&gt;Examples are the best documentation&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả cho rằng &lt;strong&gt;examples là documentation tốt nhất&lt;/strong&gt;, vì 95% thời gian dev chỉ cần một ví dụ đơn giản để hiểu cách dùng API, thay vì docs dài dòng dành cho người đã quen ecosystem. Khi juggle nhiều projects/languages, restore context tốn mental energy; formal docs thường yêu cầu kiến thức nền (như Python &lt;code&gt;max(iterable, /, *, key=None)&lt;/code&gt;: hiểu &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;, positional-only, iterable, keyword args).&lt;/p&gt;
&lt;p&gt;Ví dụ minh họa &lt;code&gt;max()&lt;/code&gt; rõ ràng hơn docs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;max(4, 6) # → 6
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;max([1, 2, 3]) # → 3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;max([&amp;#39;x&amp;#39;, &amp;#39;y&amp;#39;, &amp;#39;abc&amp;#39;], key=len) # → &amp;#39;abc&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;max([]) # ValueError
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;max([], default=5) # → 5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Community như clojuredocs.org (Clojure) xuất sắc với examples thực tế, kèm related functions (into, spit, map). Docs chính thức thường terse API ref; dev hay tìm tutorial để lấy examples, dù không cần walkthrough đầy đủ. 4 loại docs lý tưởng hiếm gặp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Examples nhanh, trực quan &amp;gt; formal docs cho quick lookup.&lt;/li&gt;
&lt;li&gt;Python max(): signature phức tạp, examples đơn giản minh họa.&lt;/li&gt;
&lt;li&gt;clojuredocs.org: community examples + related funcs hữu ích.&lt;/li&gt;
&lt;li&gt;Thường hesitate &amp;ldquo;Documentation&amp;rdquo; link, prefer tutorial cho examples.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="hazardous-states-and-accidents"&gt;&lt;a class="link" href="https://entropicthoughts.com/hazardous-states-and-accidents" target="_blank" rel="noopener"
&gt;Hazardous States and Accidents&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giới thiệu khái niệm &lt;strong&gt;hazardous states&lt;/strong&gt; (trạng thái nguy hiểm) vs &lt;strong&gt;accidents&lt;/strong&gt; (tai nạn) trong systems theory cho safety-critical systems. Accident xảy ra khi H (hazardous state) ∧ E (bad environment) → A. Không kiểm soát được E, nên focus tránh H bằng constraints. Ví dụ aviation: hạ cánh với fuel &amp;lt;30 phút là H (dễ crash nếu thời tiết xấu); trẻ em chơi gần vách đá: đứng sát mép mà không ai đỡ là H.&lt;/p&gt;
&lt;p&gt;Maintaining constraints là dynamic control problem: controllers (low-level auto/hardware/software, high-level social/legal) dùng feedback (hiện tại), mental models (dự đoán tương lai), control actions (điều chỉnh). Failure khi thiếu 1/3: feedback kém, model sai, action yếu/mạnh quá. Controllers đa tầng: aviation có FADEC, FMS, pilots, ATC; car có stability, driver, lane assist.&lt;/p&gt;
&lt;p&gt;Predict H dễ hơn A (A cần multiple failures + bad E, trông như freak accident). Analyze H ngay cả near-miss, không chờ A (aviation report fuel low dù safe land). Từ Nancy Leveson (Engineering a Safer World), khuyến khích deeper analysis: reduce consequence, improve feedback/models, human error là starting point không phải end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;H ∧ E ⇔ A: Tránh H để safety, ignore E luck.&lt;/li&gt;
&lt;li&gt;Dynamic control: feedback + models + actions đa controllers.&lt;/li&gt;
&lt;li&gt;Predict/analyze H &amp;gt; A: easier, proactive.&lt;/li&gt;
&lt;li&gt;Aviation/child/car examples minh họa constraints.&lt;/li&gt;
&lt;li&gt;Systems theory: Leveson books, future topics RCA flaws.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="multi-core-by-default"&gt;&lt;a class="link" href="https://www.rfleury.com/p/multi-core-by-default" target="_blank" rel="noopener"
&gt;Multi-Core By Default&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả Ryan Fleury lập luận &lt;strong&gt;multi-core nên là default&lt;/strong&gt; thay vì special-case trong single-core code, tận dụng core counts cao (8-64) hiện đại. Parallel for/job systems tốn overhead (kernel threads, subdivision, sync, debug khó, lifetime mgmt), scatter control flow. Thay vào đó, bootstrap threads chạy chung EntryPoint (như GPU shaders), dùng LaneIdx()/LaneCount()/LaneSync() phân bổ work uniform (LaneRange), barrier sync, atomic cho reduce (sum), narrow (if LaneIdx()==0) cho serial (I/O, printf).&lt;/p&gt;
&lt;p&gt;Ví dụ sum array: mỗi lane tính subset uniform, atomic add hoặc table+barrier. File read: lane 0 alloc, broadcast ptr, lanes read ranges. Dynamic tasks: atomic counter grab. Non-uniform: redesign algo (radix sort uniform &amp;gt; comparison sort). Single-core chỉ param thread_count=1. Codebase primitives: LaneRange(count), LaneSyncU64(ptr, src_lane), đơn giản debug (full stack, homogeneous).&lt;/p&gt;
&lt;p&gt;Ưu: Ít machinery, uniform work dist, dễ narrow/wide, superset single-core, profiler rõ. Áp dụng debugger lớn data, game engines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Multi-core default: Bootstrap lanes chung code, primitives Lane*().&lt;/li&gt;
&lt;li&gt;Critique job/parallel_for: Overhead, debug hard, scatter context.&lt;/li&gt;
&lt;li&gt;Uniform dist: LaneRange upfront, atomic counter dynamic, redesign algo.&lt;/li&gt;
&lt;li&gt;Narrow serial: if(LaneIdx()==0), broadcast shared data.&lt;/li&gt;
&lt;li&gt;Benefits: Simpler, scalable perf, full stack debug.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="vibing-a-non-trivial-ghostty-feature"&gt;&lt;a class="link" href="https://mitchellh.com/writing/non-trivial-vibing" target="_blank" rel="noopener"
&gt;Vibing a Non-Trivial Ghostty Feature&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Mitchell Hashimoto chia sẻ quy trình &lt;strong&gt;agentic coding&lt;/strong&gt; xây dựng tính năng update notification unobtrusive cho Ghostty (terminal macOS), dùng AI (Amp) ship real feature. Bắt đầu pre-AI plan: Sparkle custom UI + titlebar accessory/overlay. Sessions: prototype SwiftUI (titlebar pill), hit bug (tabs overlap) → pivot overlay bottom-right; backend UpdateDriver scaffold → cleanup viewmodel (tagged union); simulation scenarios; last mile controller/hook.&lt;/p&gt;
&lt;p&gt;Quy trình: Plan/oracle → small chunks (UI/backend) → cleanup/docs/refactor → fix bugs manual+AI → sim/tests → &amp;ldquo;anything else?&amp;rdquo;. Manual polish critical, AI inspiration/prototype/cleanup. 16 sessions, $15.98 tokens, ~8h wall-clock (AI works while cooking). Faster than manual (SwiftUI tedious), esp iteration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Agentic: Plan → prototype chunks → cleanup/docs → sim/fix → review ship.&lt;/li&gt;
&lt;li&gt;Pivot bugs: Tabs conflict → overlay fallback (titlebar hidden too).&lt;/li&gt;
&lt;li&gt;Cleanup key: Viewmodel restructure → better AI/backend/UI.&lt;/li&gt;
&lt;li&gt;Cost/time: $16/8h, AI parallel human tasks.&lt;/li&gt;
&lt;li&gt;Tips: Scaffold TODO, docs, &amp;ldquo;fix build&amp;rdquo;, &amp;ldquo;anything else?&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substackcdn.com/image/fetch/$s_!lKZF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde422306-ef24-4d81-ac91-cb24ff284706_2250x2624.heic"
loading="lazy"
alt="A Guide to Microservices Architecture for Building Scalable Systems"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Kết quả của combo này mình đánh giá khoảng 4-6đ, cấu trúc ổn, chốt được nội dung cốt lõi tuy nhiên còn dùng nhiều từ tiếng Anh. Ưu điểm là sẵn có trong VSCode, tận dụng được built-in feature của VSCode, không phải chạy thêm Terminal&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #61</title><link>https://miti99.com/post/2025/11/25/</link><pubDate>Tue, 25 Nov 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/11/25/</guid><description>&lt;p&gt;&lt;em&gt;&amp;lsquo;Lặn&amp;rsquo; đã đâu, nay mới ngoi lên lại. Mời bạn thưởng thức Newsletter #61.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="beyond-indexes-how-open-table-formats-optimize-query-performance"&gt;&lt;a class="link" href="https://jack-vanlightly.com/blog/2025/10/8/beyond-indexes-how-open-table-formats-optimize-query-performance/" target="_blank" rel="noopener"
&gt;Beyond Indexes: How Open Table Formats Optimize Query Performance&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả Jack Vanlightly, chuyên gia hiệu suất SQL Server, khám phá cách các open table formats (OTF) như Apache Iceberg tối ưu hóa query performance mà không cần secondary indexes truyền thống như trong RDBMS. Trong RDBMS (OLTP), clustered index (B-tree theo primary key) và non-clustered indexes giúp seek nhanh cho single row queries. Tuy nhiên, analytical workloads (OLAP) của OTF tập trung vào scan lớn dữ liệu columnar (Parquet/ORC), partitioning, sorting để giảm IO.&lt;/p&gt;
&lt;p&gt;OTF sử dụng auxiliary metadata files: manifest lists (file groups với stats min/max, column stats), partition metadata, và sort orders thay vì B-trees. Những cấu trúc này cho phép query engine skip files không liên quan hiệu quả (predicate pushdown, partition pruning), giảm IO đáng kể cho scans lớn. Ví dụ, Iceberg manifest lists giúp engine chọn subset files phù hợp predicates mà không scan toàn bộ table metadata.&lt;/p&gt;
&lt;p&gt;Khác biệt cốt lõi: RDBMS ưu tiên point lookups (O(log n)), OTF ưu tiên columnar scans với metadata filtering. Thêm secondary indexes vào OTF không hiệu quả vì workload khác: analytical queries đọc nhiều rows theo filters aggregate, không phải single row. Thay vào đó, OTF leverage data lake storage (S3) với cheap metadata reads.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OTF dùng partitioning, sorting, columnar formats và auxiliary metadata (manifests, stats) để optimize scans, khác RDBMS indexes cho seeks.&lt;/li&gt;
&lt;li&gt;Giảm IO qua file skipping dựa stats min/max, partition pruning.&lt;/li&gt;
&lt;li&gt;Phù hợp analytical workloads lớn, không cần traditional secondary indexes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what"&gt;&lt;a class="link" href="https://den.dev/blog/github-spec-kit" target="_blank" rel="noopener"
&gt;What&amp;rsquo;s The Deal With GitHub Spec Kit&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Den Delimarsky giới thiệu GitHub Spec Kit, công cụ thực nghiệm cho Phát triển Dựa trên Đặc tả (SDD) sử dụng LLM để làm phần mềm ổn định hơn. Thay vì lập trình theo cảm hứng ngẫu nhiên, đặc tả (specs) định nghĩa rõ &amp;ldquo;cái gì&amp;rdquo; và &amp;ldquo;tại sao&amp;rdquo; (không chi tiết kỹ thuật), giúp LLM sinh code nhất quán, dễ lặp lại/ so sánh các triển khai (ví dụ Swift so Objective-C).&lt;/p&gt;
&lt;p&gt;Spec Kit dùng lệnh slash: /constitution (nguyên tắc cốt lõi), /specify (tạo đặc tả), /clarify (hỏi rõ ràng), /plan (kế hoạch kỹ thuật), /tasks (phân tích nhiệm vụ), /analyze (phân tích trước triển khai). Đặc tả như tài liệu thực thi, code là &amp;ldquo;đặc tả đã biên dịch&amp;rdquo; – dễ xem xét/sửa, tái tạo nhanh nếu yêu cầu rõ ràng.&lt;/p&gt;
&lt;p&gt;SDD giải quyết sự biến thiên của LLM: prompt khác cho kết quả khác, đặc tả rõ ràng như hướng dẫn kỹ sư junior. Tách đặc tả khỏi tech stack mở khóa kiểm tra nhiều triển khai. Thí nghiệm mã nguồn mở tại github/spec-kit, lấy cảm hứng từ nghiên cứu John Lam.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đặc tả tập trung &amp;ldquo;cái gì/tại sao&amp;rdquo;, cho phép code LLM ổn định, so sánh nhiều triển khai.&lt;/li&gt;
&lt;li&gt;Lệnh slash hướng dẫn SDD: nguyên tắc → đặc tả → kế hoạch → nhiệm vụ → triển khai.&lt;/li&gt;
&lt;li&gt;Lập trình cảm hứng → SDD cho kết quả tốt hơn, năng suất cao với LLM.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="just-talk-to-it---the-no-bs-way-of-agentic-engineering"&gt;&lt;a class="link" href="https://steipete.me/posts/just-talk-to-it" target="_blank" rel="noopener"
&gt;Just Talk To It - the no-bs Way of Agentic Engineering&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Peter Steinberger chia sẻ kinh nghiệm sử dụng agentic engineering trong dự án mới, nơi AI agent viết gần 100% code. Thay vì các setup phức tạp, ông khuyên &amp;ldquo;just talk to it&amp;rdquo; – trò chuyện trực tiếp với AI một cách tự nhiên để giải quyết vấn đề. Bài viết lấy cảm hứng từ buổi Claude Code Anonymous ở London và năm AI đầy ấn tượng.&lt;/p&gt;
&lt;p&gt;Agentic engineering đang phát triển mạnh, nhưng nhiều người mắc lỗi tạo ra các &amp;ldquo;charades&amp;rdquo; phức tạp thay vì tập trung làm việc hiệu quả. Steinberger nhấn mạnh: AI như Claude Code đã đủ tốt để xử lý hầu hết coding tasks qua conversation đơn giản, không cần framework rườm rà. Ông đang im lặng trên blog vì bận rộn với dự án, chứng tỏ productivity cao từ approach này.&lt;/p&gt;
&lt;p&gt;Cách tiếp cận &amp;ldquo;no-bs&amp;rdquo; giúp developer junior nhanh chóng áp dụng AI: mô tả vấn đề rõ ràng, iterate qua chat, và để AI generate code. Điều này phù hợp xu hướng AI year, nơi agents như Claude thay đổi cách engineer làm việc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng agentic engineering bằng cách trò chuyện trực tiếp với AI, không cần setup phức tạp.&lt;/li&gt;
&lt;li&gt;AI viết 100% code cho dự án thực tế, tăng productivity đáng kể.&lt;/li&gt;
&lt;li&gt;Tránh overengineering; focus vào getting sh*t done qua natural conversation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="jit-so-you-want-to-be-faster-than-an-interpreter-on-modern-cpus"&gt;&lt;a class="link" href="https://www.pinaraf.info/2025/10/jit-so-you-want-to-be-faster-than-an-interpreter-on-modern-cpus" target="_blank" rel="noopener"
&gt;JIT: so you want to be faster than an interpreter on modern CPUs&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Pinaraf giải thích tại sao JIT compiler khó vượt interpreter trên CPU hiện đại (Zen 2+), nhờ OoO execution, superscalar và branch prediction. Ví dụ pseudo-code cho thấy CPU reorder instructions, speculate branches để tránh idle. Interpreter truyền thống dùng switch gây branch misprediction; optimized dùng computed gotos (như Python +15-20% speed, PostgreSQL) để linearize code, dễ predict hơn.&lt;/p&gt;
&lt;p&gt;PostgreSQL query &amp;ldquo;SELECT a FROM table WHERE a=42&amp;rdquo; sinh opcodes: SCAN_FETCHSOME, SCAN_VAR, FUNCEXPR_STRICT_2 (null checks + int4eq), QUAL, DONE_RETURN. Unrolled C code lộ bottleneck: pointless null check constant (branch predictable nhưng tốn ALU). Benchmark: bỏ strict check 1 arg giảm perf counter, nhưng CPU optimize tốt.&lt;/p&gt;
&lt;p&gt;Kế hoạch optimize: pre-check constants, inline functions, reduce branches. JIT stitch opcodes thành function để loại dispatch loops. Trên ARM64 port, cần cân bằng interpreter/JIT cho real beat.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modern CPU OoO/superscalar làm interpreter nhanh; cần computed gotos tránh switch branches.&lt;/li&gt;
&lt;li&gt;PostgreSQL interpreter: null checks constants lãng phí, nhưng predictable nên ít hại.&lt;/li&gt;
&lt;li&gt;JIT thắng bằng inline/precompute constants, loại dispatch cho linear code.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Bài viết này mình dùng CCR với model &lt;code&gt;x-ai/grok-4.1-fast:free&lt;/code&gt;. Có vẻ chưa tốt lắm, nhiều phần còn tiếng Anh thô. Mình sẽ cố gắng cải thiện hơn&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #60</title><link>https://miti99.com/post/2025/10/12/</link><pubDate>Sun, 12 Oct 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/10/12/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #60.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="diff-algorithms"&gt;&lt;a class="link" href="https://flo.znkr.io/diff" target="_blank" rel="noopener"
&gt;Diff Algorithms&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Thư viện diff mới được phát triển bằng Go mà tác giả giới thiệu trong bài viết hỗ trợ xử lý chuỗi tùy ý và định dạng đầu ra kiểu unified. Thư viện này thực hiện thuật toán Myers với tiền xử lý, các giải thuật heuristic và hậu xử lý nhằm cân bằng giữa hiệu suất và tính dễ đọc. Các tính năng chính bao gồm hỗ trợ các loại dữ liệu có thể so sánh và không thể so sánh, kết quả có cấu trúc và hành vi có thể tùy chỉnh thông qua các tùy chọn hàm số.&lt;/p&gt;
&lt;p&gt;Tác giả nhấn mạnh rằng &amp;ldquo;các cách cài đặt khác nhau cho cùng một thuật toán có thể tạo ra kết quả rất khác biệt&amp;rdquo; và tính dễ đọc của kết quả diff phụ thuộc rất nhiều vào các bước hậu xử lý như heuristics thụt lề của Michael Haggerty.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thư viện diff mới cho phép xử lý chuỗi tùy ý với đầu ra định dạng unified&lt;/li&gt;
&lt;li&gt;Sử dụng thuật toán Myers với các bước tối ưu hóa để cân bằng hiệu suất và khả năng đọc&lt;/li&gt;
&lt;li&gt;Hỗ trợ cả kiểu dữ liệu có thể và không thể so sánh, cho phép tùy chỉnh thông qua các tùy chọn hàm số&lt;/li&gt;
&lt;li&gt;Tính dễ đọc của diff phụ thuộc lớn vào các kỹ thuật hậu xử lý như các thuật toán heuristic&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="periodic-table-of-system-design-principles"&gt;&lt;a class="link" href="https://github.com/jarulraj/periodic-table" target="_blank" rel="noopener"
&gt;Periodic Table of System Design Principles&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Repository GitHub này trình bày một &amp;ldquo;bảng tuần hoàn&amp;rdquo; các nguyên tắc thiết kế hệ thống định kỳ. Mục tiêu là cung cấp một từ vựng ngắn gọn, chia sẻ để hiểu và thảo luận về các lựa chọn thiết kế trong các lĩnh vực khác nhau của hệ thống máy tính. Repository chứa một bộ sưu tập gồm hơn 40 nguyên tắc thiết kế mục đích chung được tổ chức thành các nhóm theo chủ đề như Cấu trúc, Hiệu quả, Ngữ nghĩa, v.v. Mỗi nguyên tắc có một ký hiệu ngắn để tham khảo nhanh chóng và tập trung vào &amp;ldquo;ý định thiết kế&amp;rdquo; thay vì các cơ chế cụ thể.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bộ sưu tập gồm hơn 40 nguyên tắc thiết kế hệ thống mục đích chung&lt;/li&gt;
&lt;li&gt;Các nguyên tắc được tổ chức thành các nhóm theo chủ đề (Cấu trúc, Hiệu quả, Ngữ nghĩa, v.v.)&lt;/li&gt;
&lt;li&gt;Mỗi nguyên tắc có ký hiệu ngắn để tham khảo nhanh&lt;/li&gt;
&lt;li&gt;Tập trung vào &amp;ldquo;ý định thiết kế&amp;rdquo; thay vì các cơ chế cụ thể&lt;/li&gt;
&lt;li&gt;Ví dụ được lấy từ các bài báo có ảnh hưởng trong các lĩnh vực hệ thống&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="building-a-resilient-data-platform-with-write-ahead-log-at-netflix"&gt;&lt;a class="link" href="https://netflixtechblog.com/building-a-resilient-data-platform-with-write-ahead-log-at-netflix-127b6712359a" target="_blank" rel="noopener"
&gt;Building a Resilient Data Platform with Write-Ahead Log at Netflix&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Netflix Tech Blog về việc xây dựng một nền tảng dữ liệu có độ bền cao bằng cách sử dụng kỹ thuật Write-Ahead Log (WAL). Netflix chia sẻ cách họ thiết kế và triển khai hệ thống WAL để đảm bảo tính toàn vẹn và độ tin cậy của dữ liệu trong môi trường phân tán quy mô lớn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng Write-Ahead Log để đảm bảo tính nhất quán và độ bền của dữ liệu&lt;/li&gt;
&lt;li&gt;Thiết kế hệ thống chịu lỗi cao để xử lý các trường hợp lỗi phần cứng và mạng&lt;/li&gt;
&lt;li&gt;Tối ưu hóa hiệu suất cho các tác vụ đọc/ghi dữ liệu quy mô lớn&lt;/li&gt;
&lt;li&gt;Giải pháp mở rộng theo chiều ngang để đáp ứng nhu cầu tăng trưởng dữ liệu&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="vercel-vs-cloudflare-two-philosophies-of-building-for-developers"&gt;&lt;a class="link" href="https://www.bharath.sh/writing/vercel-vs-cloudflare" target="_blank" rel="noopener"
&gt;Vercel vs Cloudflare: Two Philosophies of Building for Developers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết so sánh hai nền tảng phát triển web hàng đầu - Vercel và Cloudflare, với hai triết lý khác nhau trong việc phục vụ các nhà phát triển. Vercel, xuất phát từ nền tảng frontend và thiết kế, tập trung vào trải nghiệm phát triển liền mạch và tối ưu hóa tốc độ. Trong khi đó, Cloudflare với nền tảng hạ tầng của mình, nhấn mạnh vào tính minh bạch, kiểm soát và độ tin cậy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vercel tập trung vào &amp;ldquo;tốc độ sáng tạo&amp;rdquo; và trải nghiệm liền mạch, trừu tượng hóa sự phức tạp&lt;/li&gt;
&lt;li&gt;Cloudflare cung cấp khả năng kiểm soát chi tiết và hiệu quả về chi phí, phù hợp với các nhà phát triển quan tâm đến hạ tầng&lt;/li&gt;
&lt;li&gt;Mỗi nền tảng có cách tiếp cận phù hợp với mô hình kinh doanh của họ&lt;/li&gt;
&lt;li&gt;Cả hai nền tảng đang hội tụ khi đối mặt với các yêu cầu mới về điện toán biên và AI&lt;/li&gt;
&lt;li&gt;Cả hai đều đang cạnh tranh để giành được sự quan tâm của cộng đồng nhà phát triển&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="90"&gt;&lt;a class="link" href="https://lucumr.pocoo.org/2025/9/29/90-percent/" target="_blank" rel="noopener"
&gt;90%&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Armin Ronacher chia sẻ rằng khoảng 90% mã code cho một dự án hạ tầng gần đây tại công ty mới của ông được tạo ra bởi AI. Ông nhấn mạnh rằng mặc dù AI đóng vai trò lớn, ông vẫn giữ trách nhiệm về kiến trúc, độ tin cậy và chất lượng mã code cuối cùng. Bài viết đề cập đến việc sử dụng các công cụ như Claude và Codex để tạo code, ưa thích SQL thô hơn là ORMs và sử dụng thiết kế OpenAPI-first. AI giúp tăng tốc nghiên cứu, tái cấu trúc và thiết lập hạ tầng. Tuy nhiên, bất chấp tính hữu ích của nó, AI có thể tạo ra mã code kém chất lượng nếu không được hướng dẫn cẩn thận; sự giám sát của con người là điều cần thiết. Cách tiếp cận này cho phép thử nghiệm nhanh hơn và hệ thống tốt hơn được tổ chức.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI được sử dụng rộng rãi để tạo code, đặc biệt với các công cụ như Claude và Codex&lt;/li&gt;
&lt;li&gt;Ưa thích SQL thô hơn là ORMs và sử dụng thiết kế OpenAPI-first&lt;/li&gt;
&lt;li&gt;AI giúp tăng tốc nghiên cứu, tái cấu trúc và thiết lập hạ tầng&lt;/li&gt;
&lt;li&gt;Mặc dù hữu ích, AI có thể tạo ra code kém nếu không có hướng dẫn cẩn thận; cần giám sát của con người&lt;/li&gt;
&lt;li&gt;Cách tiếp cận này cho phép thử nghiệm nhanh hơn và hệ thống tốt hơn được tổ chức&lt;/li&gt;
&lt;li&gt;Code được tạo bởi AI đã trở thành hiện thực cho nhiều lập trình viên, nhưng cần phán đoán lành nghề để vẫn hiệu quả và an toàn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="distracting-software-engineers-is-way-more-harmful-than-most-managers-think"&gt;&lt;a class="link" href="https://workweave.dev/blog/distracting-software-engineers-is-more-harmful-than-managers-think-even-in-the-ai-times" target="_blank" rel="noopener"
&gt;Distracting Software Engineers Is Way More Harmful Than Most Managers Think&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết nhấn mạnh rằng việc làm gián đoạn các kỹ sư phần mềm gây ra tác hại lớn hơn nhiều so với những gì hầu hết các nhà quản lý nghĩ. Các kỹ sư phần mềm cần sự tập trung sâu sắc để giải quyết các vấn đề phức tạp, và những lần gián đoạn có thể dẫn đến sai sót, giảm sản lượng và kéo dài thời gian thực hiện dự án. Bài viết lập luận rằng nhiều nhà quản lý đánh giá thấp tác động của việc gián đoạn liên tục, chẳng hạn như các cuộc họp và tin nhắn, đối với hiệu quả của nhóm. Bài viết đề xuất thực hiện các khoảng thời gian làm việc tập trung và giảm thiểu những sự phân tâm không cần thiết để cải thiện cả chất lượng mã và hiệu suất của nhóm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kỹ sư phần mềm cần sự tập trung sâu để giải quyết các vấn đề phức tạp&lt;/li&gt;
&lt;li&gt;Gián đoạn có thể dẫn đến sai sót, giảm sản lượng và kéo dài thời gian thực hiện dự án&lt;/li&gt;
&lt;li&gt;Nhiều nhà quản lý đánh giá thấp tác động của việc gián đoạn liên tục đến hiệu quả nhóm&lt;/li&gt;
&lt;li&gt;Cần triển khai các khoảng thời gian làm việc tập trung và giảm thiểu sự phân tâm&lt;/li&gt;
&lt;li&gt;Cải thiện chất lượng mã và hiệu suất nhóm bằng cách giảm gián đoạn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="common-problems-managing-senior-engineers"&gt;&lt;a class="link" href="https://emdiary.substack.com/p/common-problems-managing-senior-engineers" target="_blank" rel="noopener"
&gt;Common Problems Managing Senior Engineers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết xác định bốn kiểu kỹ sư cấp cao đầy thử thách và cách huấn luyện họ:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Người Over-Engineer&lt;/strong&gt;: Xây dựng các giải pháp quá phức tạp. Quản lý nên đưa họ quay lại giá trị khách hàng và yêu cầu hồ sơ quyết định.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Người Builder-First&lt;/strong&gt;: Nhảy vào thực hiện mà không thiết kế. Quản lý nên khuyến khích thiết kế trước và so khớp mẫu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Người Ambiguity-Freezer&lt;/strong&gt;: Vật lộn với các vấn đề mơ hồ. Quản lý nên huấn luyện họ xác định rõ ràng và đảo ngược vấn đề.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Người Soloist&lt;/strong&gt;: Tránh giao việc. Quản lý nên giúp họ nghĩ theo luồng công việc song song và xây dựng niềm tin với đồng đội.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Thông điệp chính là các kỹ sư cấp cao cần huấn luyện, không phải kiểm soát chi tiết, để vượt qua điểm mù và phát triển. Như tác giả nói, &amp;ldquo;Họ không cần kiểm soát chi tiết, họ cần huấn luyện.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xác định bốn kiểu kỹ sư cấp cao đầy thử thách và cách tiếp cận phù hợp cho từng kiểu&lt;/li&gt;
&lt;li&gt;Các kỹ sư cấp cao thường cần huấn luyện để vượt qua điểm mù thay vì bị kiểm soát chi tiết&lt;/li&gt;
&lt;li&gt;Mỗi kiểu cần cách tiếp cận quản lý khác nhau để phát huy tối đa tiềm năng&lt;/li&gt;
&lt;li&gt;Vấn đề không phải ở năng lực mà ở cách tiếp cận và thói quen làm việc&lt;/li&gt;
&lt;li&gt;Huấn luyện hiệu quả giúp các kỹ sư cấp cao phát triển và đóng góp tốt hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="career-advice-or-something-like-it"&gt;&lt;a class="link" href="https://brooker.co.za/blog/2025/06/20/career.html" target="_blank" rel="noopener"
&gt;Career Advice, or Something Like It&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết khuyên tránh các &amp;ldquo;buồng vang tiêu cực&amp;rdquo; nơi việc than vãn trở thành bản sắc chung. Mặc dù thừa nhận rằng một số thái độ tiêu cực là bình thường, tác giả cảnh báo rằng sự bi quan thái quá gây hại cả cho sự phát triển sự nghiệp và sức khỏe tinh thần. Thay vào đó, hãy tập trung vào các cộng đồng tích cực và những người truyền cảm hứng cho bạn. Hãy tham gia vào công việc có ý nghĩa, dành thời gian với người thân yêu và bảo vệ cộng đồng của bạn bằng cách thể hiện hành vi mang tính xây dựng. Sự thay đổi thực sự đến không phải từ việc xả giận mà từ hành động trực tiếp và hợp tác.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tránh những nơi mà việc phàn nàn là hoạt động chính&lt;/li&gt;
&lt;li&gt;Duy trì sự tích cực mà không trở nên ngây thơ&lt;/li&gt;
&lt;li&gt;Bảo vệ sức khỏe tinh thần và sự nghiệp bằng cách lựa chọn cộng đồng một cách thông minh&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Làm điều này thật khó về mặt xã hội. Ít nhất thì nó đòi hỏi phải trực tiếp thể hiện hình mẫu của điều tốt đẹp&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Dành năng lượng cho việc cải thiện hoặc rút lui, chứ không phải sự bi quan&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="my-productivity-rules"&gt;&lt;a class="link" href="https://www.16elt.com/2025/10/08/studying-while-busy/" target="_blank" rel="noopener"
&gt;My Productivity Rules&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết trình bày các mẹo thực tế để nâng cao hiệu suất học tập, nhấn mạnh vào việc lập kế hoạch, quản lý năng lượng, trung thực về nỗ lực, xem xét hàng ngày và giảm thiểu sự phân tâm. Bài viết cung cấp các quy tắc như chuẩn bị ngày mới vào buổi tối trước, nghỉ ngơi khi năng lượng thấp, trung thực về mức độ nỗ lực thực sự, phản chiếu lại tiến độ hàng ngày và loại bỏ các yếu tố gây xao nhãng như điện thoại hay các ứng dụng hấp dẫn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lập kế hoạch ngày mới vào buổi tối trước để tránh tình trạng trì hoãn buổi sáng&lt;/li&gt;
&lt;li&gt;Phối hợp cường độ học tập với mức năng lượng trong ngày&lt;/li&gt;
&lt;li&gt;Trung thực về mức độ nỗ lực thực sự mà bạn bỏ ra&lt;/li&gt;
&lt;li&gt;Phản chiếu lại tiến độ hàng ngày để cải thiện kế hoạch trong tương lai&lt;/li&gt;
&lt;li&gt;Loại bỏ các yếu tố gây xao nhãng bằng cách giữ các ứng dụng hấp dẫn ngoài tầm nhìn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus-vài-ảnh-thú-vị-đến-từ-bytebytego"&gt;Bonus: Vài ảnh thú vị đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;em&gt;Nay mình đã gặp phải một số vấn đề khá phiền vì đã lưu quá nhiều ảnh sưu tầm trong bài viết. Cụ thể là mình mất hơn 17p để build site này khi dùng một máy tính khác :v&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | VI
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-------------------+------
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Pages | 587
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Paginator pages | 130
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Non-page files | 195
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Static files | 2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Processed images | 361
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Aliases | 236
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Cleaned | 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Built in 1043990 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;em&gt;Nên mình quyết định đổi sang sử dụng url gốc thay vì thêm hình vào repo. Điểm yếu là có thể ảnh sẽ bị gỡ, và không được xử lý để giảm kích thước, làm tăng thời gian load lên. Mình sẽ cố gắng update lại các ảnh trong các post trước đây luôn (vào một ngày nào đó đẹp trời và mình siêng năng :3)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substackcdn.com/image/fetch/$s_!KwvJ!,w_1100,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ac50da4-feb8-4781-8bb2-e74244aa889f_2250x2814.png"
loading="lazy"
alt="TCP vs UDP"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #59</title><link>https://miti99.com/post/2025/10/03/</link><pubDate>Fri, 03 Oct 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/10/03/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #59.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="taking-a-look-at-compression-algorithms"&gt;&lt;a class="link" href="https://cefboud.com/posts/compression/" target="_blank" rel="noopener"
&gt;Taking a Look at Compression Algorithms&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong thế giới công nghệ, các thuật toán nén dữ liệu đóng vai trò quan trọng trong việc tối ưu hóa lưu trữ và truyền tải thông tin. Bài viết này khám phá bốn thuật toán nén lossless phổ biến: GZIP (DEFLATE), Snappy, LZ4 và ZSTD, với các cân bằng khác nhau giữa tốc độ và tỷ lệ nén.&lt;/p&gt;
&lt;p&gt;GZIP/DEFLATE là sự kết hợp của kỹ thuật trượt cửa sổ LZ77 và mã hóa Huffman. Nó sử dụng bảng băm chuỗi để tìm kiếm nhanh và hỗ trợ nhiều loại khối khác nhau (không nén, Huffman cố định/động). Triển khai trong Go cho thấy các tối ưu hóa như so khớp lười và các mức nén cân bằng giữa sử dụng CPU và lợi ích nén.&lt;/p&gt;
&lt;p&gt;Snappy ưu tiên tốc độ hơn tỷ lệ, nén với tốc độ trên 250 MB/s. Nó sử dụng thẻ đơn giản cho các đoạn văn bản gốc và bản sao, với bảng băm nhẹ chỉ lưu các kết quả khớp 4-byte gần đây. Phù hợp cho các ứng dụng thời gian thực cần giải nén nhanh.&lt;/p&gt;
&lt;p&gt;LZ4 còn nhanh hơn Snappy, đạt tốc độ ~780 MB/s. Nó mã hóa chuỗi các đoạn văn bản gốc và kết quả khớp bằng token 4-bit, với độ dài mở rộng tùy chọn. Thiết kế tốc độ cao sử dụng hàm băm hiệu quả và so khớp mở rộng dựa trên XOR.&lt;/p&gt;
&lt;p&gt;ZSTD kết hợp so khớp kiểu LZ với mã hóa entropy hiện đại (FSE/ANS) để đạt tỷ lệ cao (~2.9x) với tốc độ (~510 MB/s) ngang bằng LZ4. Tính năng bao gồm từ điển huấn luyện và chế độ streaming. Nó cải tiến mã hóa số học với chuẩn hóa cho hiệu suất thực tế.&lt;/p&gt;
&lt;p&gt;Mỗi thuật toán hướng đến các trường hợp sử dụng khác nhau: DEFLATE cho lưu trữ tổng quát, Snappy/LZ4 cho hệ thống yêu cầu tốc độ, và ZSTD cho sự cân bằng tối ưu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GZIP/DEFLATE phù hợp cho lưu trữ tổng quát với tỷ lệ nén tốt&lt;/li&gt;
&lt;li&gt;Snappy và LZ4 tối ưu cho tốc độ, dùng trong ứng dụng real-time&lt;/li&gt;
&lt;li&gt;ZSTD cung cấp sự cân bằng tốt nhất giữa tốc độ và tỷ lệ nén&lt;/li&gt;
&lt;li&gt;Lựa chọn thuật toán đúng tùy thuộc vào yêu cầu cụ thể của hệ thống&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="90"&gt;&lt;a class="link" href="https://lucumr.pocoo.org/2025/9/29/90-percent/" target="_blank" rel="noopener"
&gt;90%&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Armin Ronacher chia sẻ rằng AI hiện đang viết hơn 90% mã code cho một dự án hạ tầng mới mà ông dẫn đầu, phản ánh sự thay đổi lớn trong phát triển phần mềm. Ông nhấn mạnh rằng mặc dù AI đóng góp phần lớn code, ông vẫn giữ trách nhiệm cho kiến trúc, độ tin cậy và các quyết định thiết kế.&lt;/p&gt;
&lt;p&gt;Những hiểu biết chính bao gồm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI xuất sắc trong việc tạo SQL thô và dựng khung hệ thống dựa trên OpenAPI.&lt;/li&gt;
&lt;li&gt;Kết hợp các công cụ như Claude và Codex cải thiện kết quả; Claude hỗ trợ gỡ lỗi, Codex xem xét code.&lt;/li&gt;
&lt;li&gt;Các lập trình viên phải hướng dẫn AI cẩn thận, vì AI có thể tái tạo lại các thành phần hiện có hoặc đưa ra các lựa chọn kiến trúc kém.&lt;/li&gt;
&lt;li&gt;AI giúp tăng tốc nghiên cứu, tái cấu trúc và thiết lập hạ tầng, nhưng có thể đưa vào code dễ vỡ nếu không được giám sát.&lt;/li&gt;
&lt;li&gt;Các nền tảng kỹ thuật mạnh vẫn rất cần thiết; AI không thay thế nhu cầu hiểu biết kỹ thuật sâu sắc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ronacher kết luận rằng mặc dù code viết bằng AI đã trở thành hiện thực cho nhiều lập trình viên, thành công phụ thuộc vào sự giám sát cẩn thận và sử dụng có chọn lọc các khả năng của AI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI viết code đã trở thành hiện thực, nhưng cần giám sát cẩn thận&lt;/li&gt;
&lt;li&gt;Các lập trình viên vẫn cần nền tảng kỹ thuật mạnh để hướng dẫn AI&lt;/li&gt;
&lt;li&gt;Sự kết hợp giữa Claude và Codex mang lại kết quả tốt hơn&lt;/li&gt;
&lt;li&gt;AI xuất sắc trong tạo khung và SQL thô nhưng cần giám sát để tránh kiến trúc kém&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-weird-concept-of-branchless-programming"&gt;&lt;a class="link" href="https://sanixdk.xyz/blogs/the-weird-concept-of-branchless-programming" target="_blank" rel="noopener"
&gt;The Weird Concept of Branchless Programming&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Lập trình không nhánh (branchless programming) là kỹ thuật viết lại code để tránh các bước nhảy điều kiện có thể làm chậm CPU. Thay vì logic &amp;ldquo;if-else&amp;rdquo;, nó sử dụng các phép toán bit và số học để làm cho việc thực thi nhanh hơn và dễ đoán hơn.&lt;/p&gt;
&lt;p&gt;Những lợi ích chính bao gồm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tránh tình trạng dừng pipeline của CPU do dự đoán nhánh sai.&lt;/li&gt;
&lt;li&gt;Cải thiện hiệu suất trong các vòng lặp chặt chẽ với điều kiện không thể đoán trước.&lt;/li&gt;
&lt;li&gt;Thực thi xác định, hữu ích trong mật mã và hệ thống thời gian thực.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ví dụ:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Giá trị tuyệt đối&lt;/strong&gt;: Thay thế điều kiện bằng thao tác bit sử dụng mặt nạ.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hàm Clamp&lt;/strong&gt;: Giới hạn một giá trị giữa min/max mà không cần phân nhánh.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thuật toán phân vùng&lt;/strong&gt;: Cho thấy tốc độ cải thiện đáng kể bằng cách loại bỏ nhánh trong một chương trình con sắp xếp.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Trích dẫn từ bài viết:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Lập trình không nhánh là một con dao mổ, không phải là búa tạ.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Mặc dù không luôn cần thiết cho các hàm đơn giản, các kỹ thuật không nhánh rất mạnh trong code yêu cầu hiệu suất cao.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kỹ thuật lập trình không nhánh giúp tránh chậm trễ do CPU dự đoán sai nhánh&lt;/li&gt;
&lt;li&gt;Hiệu quả đặc biệt trong các vòng lặp với điều kiện phức tạp&lt;/li&gt;
&lt;li&gt;Sử dụng phép toán bit và số học thay thế cho các câu lệnh điều kiện&lt;/li&gt;
&lt;li&gt;Phù hợp cho các ứng dụng mật mã và thời gian thực yêu cầu hiệu suất cao&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ai-coding-assistants-building-apps-for-30-hours-straight"&gt;&lt;a class="link" href="https://threadreaderapp.com/thread/1972793278744461627.html" target="_blank" rel="noopener"
&gt;AI Coding Assistants: Building Apps for 30 Hours Straight&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một thread Twitter từ @IntuitMachine cho thấy Claude Sonnet 4.5 có thể xây dựng các ứng dụng giống Slack một cách tự chủ trong lên đến 30 giờ. Những hiểu biết chính bao gồm:&lt;/p&gt;
&lt;p&gt;Prompt hệ thống thực thi &amp;ldquo;code lớn&amp;rdquo; thành các artifact bền vững, yêu cầu code trên ~20 dòng phải được lưu dưới dạng artifact.
Một quy trình làm việc lặp lại phân biệt giữa các cập nhật nhỏ và viết lại lớn, hỗ trợ phát triển an toàn cho các codebase lớn.
Tính ổn định của UI được duy trì thông qua các ràng buộc thời gian chạy như cấm localStorage và yêu cầu trạng thái trong bộ nhớ.
Quản lý phụ thuộc và đóng gói được đơn giản hóa thông qua các loại artifact và quy tắc nhập đã được cho phép.
Một nhịp độ nghiên cứu hỗ trợ các tác vụ phức tạp sử dụng vòng lặp kế hoạch-nghiên cứu-trả lời để đưa ra quyết định có thông tin.
Sử dụng công cụ được quản lý để giảm các ngõ cụt trong khi lựa chọn framework hoặc schema.
Sự tách biệt giữa lập kế hoạch và hành động ngăn chặn code chưa hoàn thiện và duy trì kỷ luật phạm vi.
Khả năng tự chủ tầm xa được kích hoạt thông qua các vòng lặp lập kế hoạch/phan hồi lấy cảm hứng từ các kiến trúc như Voyager.
Trạng thái cuộc trò chuyện được gửi đầy đủ mỗi lần để duy trì tính nhất quán trong các chu kỳ tạo.
Nghi lễ lỗi và hàng rào bảo vệ giúp quản lý các vấn đề tích hợp trong khi xây dựng dài.
Các ngăn xếp công nghệ quen thuộc (React, Flask) cải thiện độ chính xác và thông lượng.
Tự tổ chức được hỗ trợ bằng cách cho phép các artifact gọi API LLM bên trong.
Đầu ra có thể phân tích bằng máy cho phép xác minh tự động và lặp lại không cần giám sát.&lt;/p&gt;
&lt;p&gt;Những mô hình này cùng nhau cho phép phát triển phần mềm phức tạp được duy trì bởi AI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Claude Sonnet 4.5 có thể xây dựng ứng dụng giống Slack trong 30 giờ&lt;/li&gt;
&lt;li&gt;Các kỹ thuật như artifact bền vững và quy trình làm việc lặp lại cho phép phát triển an toàn&lt;/li&gt;
&lt;li&gt;Các ràng buộc thời gian chạy giúp duy trì UI ổn định&lt;/li&gt;
&lt;li&gt;Tự động hóa được kích hoạt thông qua vòng lặp lập kế hoạch/phản hồi&lt;/li&gt;
&lt;li&gt;Các ngăn xếp công nghệ quen thuộc cải thiện độ chính xác và hiệu suất&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="development-gets-better-with-age"&gt;&lt;a class="link" href="https://www.allthingsdistributed.com/2025/10/better-with-age.html" target="_blank" rel="noopener"
&gt;Development Gets Better with Age&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết &amp;ldquo;Development gets better with Age&amp;rdquo;, chuyên gia công nghệ kỳ cựu Werner Vogels chia sẻ về cách kinh nghiệm nâng cao khả năng đổi mới và giải quyết vấn đề của các lập trình viên. Với gần 25 năm tại Amazon, ông nhấn mạnh rằng sự già đi trong công nghệ mang đến những hiểu biết vô giá:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kinh nghiệm sinh ra trí tuệ&lt;/strong&gt;: Các lập trình viên lớn tuổi đã &amp;ldquo;thấy rất nhiều và gặp nhiều vấn đề mà các lập trình viên trẻ đang đối mặt&amp;rdquo;. Họ mang theo &amp;ldquo;vết sẹo chiến đấu&amp;rdquo;, biết điều gì hiệu quả và điều gì không hiệu quả.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nhận dạng mẫu&lt;/strong&gt;: &amp;ldquo;Các mẫu lặp đi lặp lại&amp;hellip; liên tục&amp;rdquo;. Điều này cho phép các lập trình viên có kinh nghiệm phát hiện các dấu hiệu cảnh báo và tránh các sai lầm trong quá khứ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sáng tạo &amp;amp; Thực dụng&lt;/strong&gt;: Với kiến thức nền tảng đã được củng cố, các lập trình viên có kinh nghiệm tập trung năng lượng tinh thần vào sự sáng tạo - xây dựng &amp;ldquo;các giải pháp độc đáo mới&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI &amp;amp; Công nghệ Tạo sinh&lt;/strong&gt;: Mặc dù AI tạo sinh rất thú vị, các lập trình viên lớn tuổi tiếp cận nó với sự hoài nghi lành mạnh. Họ nhớ thời kỳ công nghệ phát triển chậm hơn và áp dụng những bài học từ các nền tảng như AWS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lãnh đạo trong hỗn loạn&lt;/strong&gt;: Giữa sự thay đổi nhanh chóng, lập trình viên có kinh nghiệm &amp;ldquo;nhấn nút tạm dừng&amp;rdquo;, hướng dẫn các nhóm tập trung vào các vấn đề thực sự, không phải hype.&lt;/p&gt;
&lt;p&gt;Như Vogels kết luận: &amp;ldquo;Lập trình viên lớn tuổi không lo lắng về loạt thông báo mô hình mới&amp;hellip; Anh ấy đã thấy điều đó trước rồi. Công nghệ mới, cùng mẫu cũ.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kinh nghiệm giúp các lập trình viên nhận ra các mẫu và tránh các lỗi trong quá khứ&lt;/li&gt;
&lt;li&gt;Lập trình viên lớn tuổi mang theo &amp;ldquo;vết sẹo chiến đấu&amp;rdquo; từ những dự án trước&lt;/li&gt;
&lt;li&gt;Kỹ năng sáng tạo được nâng cao khi nền tảng kỹ thuật đã vững chắc&lt;/li&gt;
&lt;li&gt;Cách tiếp cận hoài nghi lành mạnh với AI tạo sinh từ những bài học trước đây&lt;/li&gt;
&lt;li&gt;Vai trò lãnh đạo trong việc hướng dẫn nhóm tập trung vào vấn đề thực sự&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="programming-deflation"&gt;&lt;a class="link" href="https://tidyfirst.substack.com/p/programming-deflation" target="_blank" rel="noopener"
&gt;Programming Deflation&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Kent Beck phân tích xu hướng &amp;ldquo;deflation&amp;rdquo; trong lập trình - khi chi phí viết phần mềm giảm mạnh nhờ AI và công cụ hỗ trợ. Dù có thể dẫn đến ít lập trình viên hơn, xu hướng này cũng mở ra nhiều cơ hội mới nhờ khả năng thử nghiệm dễ dàng và sự bùng nổ của các ứng dụng tự động hóa.&lt;/p&gt;
&lt;p&gt;Beck cho rằng thay vì lo lắng về số lượng lập trình viên, chúng ta nên tập trung phát triển kỹ năng như: đánh giá, tích hợp hệ thống và hiểu biết sâu sắc - những yếu tố trở nên khan hiếm khi code hóa rẻ.&lt;/p&gt;
&lt;p&gt;Ông nhấn mạnh: &amp;ldquo;Đừng cố đoán tương lai. Hãy xây dựng năng lực phù hợp với cả hai kịch bản.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI và công cụ hỗ trợ đang làm giảm đáng kể chi phí phát triển phần mềm&lt;/li&gt;
&lt;li&gt;Thay vì lo lắng về số lượng lập trình viên, hãy tập trung vào các kỹ năng chuyên sâu&lt;/li&gt;
&lt;li&gt;Các kỹ năng đánh giá, tích hợp hệ thống trở nên khan hiếm và có giá trị hơn&lt;/li&gt;
&lt;li&gt;Cần xây dựng năng lực linh hoạt để thích ứng với các kịch bản tương lai khác nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="thế-nào-là"&gt;&lt;a class="link" href="https://www.seangoedecke.com/taste/" target="_blank" rel="noopener"
&gt;Thế nào là &amp;rsquo;thẩm mỹ tốt&amp;rsquo; trong kỹ thuật phần mềm?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích khái niệm &amp;ldquo;thẩm mỹ kỹ thuật&amp;rdquo; (technical taste) trong lập trình, nhấn mạnh rằng đây là khả năng lựa chọn giá trị phù hợp với từng dự án cụ thể, khác biệt so với kỹ năng kỹ thuật thuần túy.&lt;/p&gt;
&lt;p&gt;Tác giả Sean Goedecke cho rằng mỗi kỹ sư có một tập hợp các giá trị ưu tiên như hiệu năng, tính đúng đắn, khả năng đọc hiểu, độ linh hoạt&amp;hellip; Sự khác biệt trong quan điểm không phải do kém hiểu biết mà do khác nhau trong &amp;ldquo;thẩm mỹ&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Ví dụ, một người thích dùng &lt;code&gt;map&lt;/code&gt; và &lt;code&gt;filter&lt;/code&gt;, người khác ưa vòng lặp &lt;code&gt;for&lt;/code&gt; – cả hai đều có lý do riêng. Quan trọng là biết khi nào nên chọn gì, tùy theo hoàn cảnh.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Thẩm mỹ tốt&amp;rdquo; nghĩa là linh hoạt, không cứng nhắc áp dụng cùng một chuẩn mực cho mọi tình huống. Kỹ sư có thẩm mỹ tốt sẽ cân nhắc các yếu tố như resiliency, scalability, readability&amp;hellip; để đưa ra quyết định tối ưu cho từng bài toán cụ thể.&lt;/p&gt;
&lt;p&gt;Ngược lại, &amp;ldquo;thẩm mỹ xấu&amp;rdquo; thường đến từ sự cố chấp, thiếu linh hoạt – ví dụ như cố gắng áp dụng giải pháp từng thành công ở nơi khác nhưng không phù hợp với bối cảnh hiện tại.&lt;/p&gt;
&lt;p&gt;Cuối cùng, để phát triển thẩm mỹ, tác giả khuyên nên làm nhiều loại dự án khác nhau, chú ý đến những gì dễ hay khó, và giữ thái độ cởi mở, tránh hình thành các quan điểm cứng nhắc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Thẩm mỹ kỹ thuật&amp;rdquo; là khả năng lựa chọn giá trị phù hợp với từng dự án cụ thể&lt;/li&gt;
&lt;li&gt;Mỗi kỹ sư có tập hợp giá trị ưu tiên khác nhau như hiệu năng, tính đúng đắn, khả năng đọc hiểu&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Thẩm mỹ tốt&amp;rdquo; nghĩa là linh hoạt trong việc chọn giải pháp phù hợp với hoàn cảnh&lt;/li&gt;
&lt;li&gt;Sự cố chấp và thiếu linh hoạt dẫn đến &amp;ldquo;thẩm mỹ xấu&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Để phát triển thẩm mỹ, cần làm nhiều loại dự án khác nhau và giữ thái độ cởi mở&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus-một-vài-ảnh-thú-vị-đến-từ-bytebytego"&gt;Bonus: Một vài ảnh thú vị đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substackcdn.com/image/fetch/$s_!CEQb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30caf720-4b66-4f5f-84d2-72c578969944_2250x2624.heic"
loading="lazy"
alt="Service Discovery 101: The Phonebook for Distributed Systems"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Bài viết trong kho của mình đã hết rồi. Có lẽ phải chờ một thời gian để mình tích luỹ lại sau đó mới tiếp tục được nhé. Hẹn gặp lại các bạn sau.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #58</title><link>https://miti99.com/post/2025/10/01/</link><pubDate>Wed, 01 Oct 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/10/01/</guid><description>&lt;p&gt;&lt;em&gt;Hôm nay mình có thử gắn &lt;a class="link" href="https://github.com/musistudio/claude-code-router" target="_blank" rel="noopener"
&gt;Claude Code Router&lt;/a&gt; với model &lt;code&gt;openai/gpt-oss-120b&lt;/code&gt; trên &lt;a class="link" href="https://build.nvidia.com/" target="_blank" rel="noopener"
&gt;NVIDIA NIM&lt;/a&gt; nhưng bị lỗi gì đấy, sau cùng thì không được output gì. Vì vậy chúng ta lại quay lại với model &lt;code&gt;qwen3-coder&lt;/code&gt; chạy trên &lt;a class="link" href="https://platform.iflow.cn/docs/api-mode" target="_blank" rel="noopener"
&gt;iFlow Platform&lt;/a&gt; nhé. Mời bạn thưởng thức Newsletter #58.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="how-software-engineers-make-productive-decisions-without-slowing-the-team-down"&gt;&lt;a class="link" href="https://strategizeyourcareer.com/p/how-software-engineers-make-productive-decisions" target="_blank" rel="noopener"
&gt;How Software Engineers Make Productive Decisions (without slowing the team down)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Khi làm việc trong một team phát triển phần mềm, kỹ sư phần mềm thường đứng trước những quyết định hàng ngày mà có thể ảnh hưởng đến tiến độ và chất lượng của dự án. Tuy nhiên, quá trình ra quyết định đôi khi lại trở thành nỗi ám ảnh khi engineer dành quá nhiều thời gian để phân tích và cân nhắc, thay vì hành động.&lt;/p&gt;
&lt;p&gt;Bài viết này giới thiệu một cách tiếp cận thực tế để cải thiện năng suất ra quyết định. Thay vì coi mọi quyết định đều quan trọng như nhau, chúng ta nên phân biệt giữa những quyết định dạng &amp;ldquo;cửa một chiều&amp;rdquo; (rủi ro, khó đảo ngược) và &amp;ldquo;cửa hai chiều&amp;rdquo; (an toàn, có thể quay đầu).&lt;/p&gt;
&lt;p&gt;Để xác định loại quyết định nào đang đứng trước, bài viết đề xuất một framework 3 câu hỏi đơn giản:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Tác động nếu sai là gì?&lt;/strong&gt; - Xác định hậu quả là nhỏ, vừa hoặc thảm họa&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Khó khăn khi quay lại là gì?&lt;/strong&gt; - Nếu dễ dàng đảo ngược, có thể tiến hành nhanh chóng&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Có thể giảm thiểu rủi ro với phạm vi nhỏ không?&lt;/strong&gt; - Sử dụng feature flags, canaries và cảnh báo&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Với những quyết định dạng &amp;ldquo;cửa hai chiều&amp;rdquo;, engineer có thể tự tin tiến hành nhanh chóng mà không cần sự phê duyệt từ nhiều người. Việc áp dụng các kỹ thuật như feature flags, small pull requests, và rollback nhanh giúp duy trì tốc độ mà không làm giảm chất lượng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phân biệt giữa quyết định &amp;ldquo;cửa một chiều&amp;rdquo; và &amp;ldquo;cửa hai chiều&amp;rdquo; để tối ưu hóa thời gian ra quyết định&lt;/li&gt;
&lt;li&gt;Framework 3 câu hỏi giúp đánh giá mức độ rủi ro của quyết định một cách nhanh chóng&lt;/li&gt;
&lt;li&gt;Sử dụng các công cụ kỹ thuật để giảm thiểu rủi ro và tăng tốc độ thực thi&lt;/li&gt;
&lt;li&gt;Tập trung sự thận trọng vào những quyết định thực sự quan trọng như bảo mật và toàn vẹn dữ liệu&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-are-event-driven-systems-hard"&gt;&lt;a class="link" href="https://newsletter.scalablethread.com/p/why-event-driven-systems-are-hard" target="_blank" rel="noopener"
&gt;Why are Event-Driven Systems Hard?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Kiến trúc event-driven đang ngày càng phổ biến trong các hệ thống phân tán hiện đại nhờ khả năng mở rộng và tính đàn hồi cao. Tuy nhiên, việc triển khai và duy trì các hệ thống này lại không hề đơn giản. Bài viết phân tích những thách thức chính mà các kỹ sư phần mềm phải đối mặt khi làm việc với event-driven systems.&lt;/p&gt;
&lt;p&gt;Một trong những vấn đề cốt lõi là &lt;strong&gt;quản lý phiên bản định dạng message&lt;/strong&gt;. Khi hệ thống phát triển, các service có thể gửi các event schema được cập nhật mà các service cũ không thể hiểu được, dẫn đến gián đoạn giao tiếp. Để giải quyết vấn đề này, cần áp dụng các chiến lược như tương thích ngược/tiến và sử dụng schema registries.&lt;/p&gt;
&lt;p&gt;Khó khăn khác là &lt;strong&gt;khả năng quan sát và gỡ lỗi&lt;/strong&gt;. Khác với các hệ thống tuyến tính, luồng yêu cầu trong kiến trúc event-driven bị phân tán khắp các service. Để gỡ lỗi hiệu quả, cần sử dụng &lt;strong&gt;distributed tracing&lt;/strong&gt; với &lt;strong&gt;correlation IDs&lt;/strong&gt; để theo dõi events xuyên suốt các service.&lt;/p&gt;
&lt;p&gt;Vấn đề về &lt;strong&gt;xử lý lỗi và mất message&lt;/strong&gt; cũng thường xuyên xảy ra do các sự cố hạ tầng. Hầu hết các hệ thống đảm bảo &lt;strong&gt;giao message ít nhất một lần&lt;/strong&gt;, nhưng điều này có thể dẫn đến xử lý trùng lặp. &lt;strong&gt;Dead-Letter Queues (DLQs)&lt;/strong&gt; giúp cách ly các message có vấn đề để tránh ảnh hưởng toàn hệ thống.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Idempotency&lt;/strong&gt; là một yêu cầu quan trọng để xử lý message trùng lặp. Các service phải được thiết kế sao cho việc xử lý cùng một message nhiều lần không gây ra tác dụng phụ không mong muốn. Điều này thường được thực hiện bằng cách theo dõi các event ID đã xử lý.&lt;/p&gt;
&lt;p&gt;Cuối cùng, &lt;strong&gt;eventual consistency&lt;/strong&gt; là một đặc điểm của hệ thống event-driven, nơi dữ liệu được cập nhật bất đồng bộ, dẫn đến tình trạng không nhất quán tạm thời. Các ứng dụng phải được thiết kế để chịu được độ trễ này.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Event-driven systems mang lại tính đàn hồi và linh hoạt nhưng đi kèm nhiều thách thức&lt;/li&gt;
&lt;li&gt;Quản lý phiên bản message và đảm bảo tương thích là vấn đề phức tạp&lt;/li&gt;
&lt;li&gt;Distributed tracing và correlation IDs là thiết yếu để gỡ lỗi&lt;/li&gt;
&lt;li&gt;Idempotency là yêu cầu bắt buộc để xử lý message trùng lặp&lt;/li&gt;
&lt;li&gt;Eventual consistency là đặc điểm cần được cân nhắc khi thiết kế hệ thống&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="dev-culture-is-dying-the-curious-developer-is-gone"&gt;&lt;a class="link" href="https://dayvster.com/blog/dev-culture-is-dying-the-curious-developer-is-gone/" target="_blank" rel="noopener"
&gt;Dev Culture Is Dying: The Curious Developer Is Gone&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Văn hóa phát triển phần mềm đang trải qua một sự thay đổi đáng buồn theo quan điểm của bài viết. Trước đây, các lập trình viên xây dựng các công cụ như Linux và Git xuất phát từ niềm đam mê và sự tò mò cá nhân, chứ không phải vì lợi nhuận hay danh tiếng.&lt;/p&gt;
&lt;p&gt;Ngày nay, nhiều developer theo đuổi các framework mới không phải vì sự hứng thú thực sự, mà là do áp lực phải thể hiện mình là người có liên quan. Sự thay đổi này có nguy cơ ngăn chặn đổi mới, vì động lực nội tại bị thay thế bằng sự công nhận từ bên ngoài.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Có điều gì đó cần được nói về việc học mà không có mục đích rõ ràng… bạn bắt đầu hành trình chỉ vì bạn tò mò.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Bài viết cảnh báo về việc các developer ngày nay xác định bản thân theo công cụ họ sử dụng hơn là các vấn đề họ giải quyết:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Bạn trở thành một Next.js developer, một React developer… Bạn bắt đầu xác định bản thân bằng các công cụ bạn sử dụng thay vì các vấn đề bạn giải quyết.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Tác giả kêu gọi sự trở lại của việc tò mò khám phá và các dự án cá nhân, khuyến khích các developer xây dựng vì chính họ trước, không cần lo lắng về quy mô hay khả năng kiếm tiền.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Hãy tạo ra điều gì đó tuyệt vời, điều gì đó độc đáo… xây dựng vì bạn muốn, vì nó làm bạn hạnh phúc.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Bài viết than thở về sự suy giảm của tinh thần chủ sở hữu—không chỉ cho người dùng, mà cả cho những người sáng tạo có thể bán đi hoặc mất quyền kiểm soát tầm nhìn ban đầu của họ.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Họ có quan tâm đến phần mềm họ xây dựng hay chỉ đơn giản quan tâm đến các chỉ số, doanh thu, tăng trưởng?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Cuối cùng, bài viết thúc giục các developer lấy lại sự tò mò, sáng tạo và niềm vui khi xây dựng chỉ vì lý do xây dựng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Văn hóa phát triển phần mềm đã chuyển từ đam mê sang hướng đến chỉ số và doanh thu&lt;/li&gt;
&lt;li&gt;Các developer ngày nay thường xác định bản thân theo công cụ hơn là vấn đề họ giải quyết&lt;/li&gt;
&lt;li&gt;Sự tò mò và động lực nội tại đang bị thay thế bởi sự công nhận từ bên ngoài&lt;/li&gt;
&lt;li&gt;Cần trở lại với tinh thần khám phá và xây dựng dự án cá nhân&lt;/li&gt;
&lt;li&gt;Quan trọng là phải giữ được niềm vui khi lập trình vì bản thân nó&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tool-calls-are-expensive-and-finite"&gt;&lt;a class="link" href="https://www.reillywood.com/blog/tool-calls-are-expensive-and-finite/" target="_blank" rel="noopener"
&gt;Tool Calls Are Expensive And Finite&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tool calls trong các hệ thống AI cho phép các LLM vượt ra ngoài việc sinh text bằng cách tương tác với các hàm bên ngoài. Tuy nhiên, chúng đi kèm với chi phí đáng kể và những hạn chế.&lt;/p&gt;
&lt;p&gt;Theo Reilly Wood giải thích, &amp;ldquo;việc gọi một tool tốn kém hơn rất nhiều so với việc gọi một hàm thông thường từ code.&amp;rdquo; Điều này là bởi vì mỗi tool call đều liên quan đến việc tạo ra text có cấu trúc, chiếm dụng tokens và không gian trong context window.&lt;/p&gt;
&lt;p&gt;Về mặt kỹ thuật, một tool call hoạt động như sau:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Model tạo ra một message chỉ định tên tool và các tham số.&lt;/li&gt;
&lt;li&gt;Hệ thống phân tích message này và thực thi hàm thực tế.&lt;/li&gt;
&lt;li&gt;Kết quả được đưa lại vào context của model như một message mới.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Quá trình này có nghĩa là &amp;ldquo;toàn bộ kết quả của mỗi tool call đều kết thúc trong context window,&amp;rdquo; khiến cho việc gọi nhiều lần trở nên tốn kém. Ví dụ, một agent cố gắng xử lý 100 user IDs thông qua các tool call riêng lẻ có thể làm cạn kiệt context window trước khi hoàn thành nhiệm vụ.&lt;/p&gt;
&lt;p&gt;Wood nhấn mạnh rằng &amp;ldquo;mọi người nên hiểu rằng&amp;hellip; sẽ luôn có giới hạn về số lượng tool call mà một agent có thể thực hiện một cách hiệu quả.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Để giải quyết những hạn chế này, các developer nên thiết kế các tool linh hoạt hơn hoặc cân nhắc để các agent tạo và chạy code thay thế, đồng thời lưu ý đến các rủi ro bảo mật.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tool calls trong AI tốn kém hơn nhiều so với các hàm thông thường&lt;/li&gt;
&lt;li&gt;Mỗi tool call chiếm dụng không gian trong context window&lt;/li&gt;
&lt;li&gt;Việc gọi nhiều tool call có thể làm cạn kiệt context window&lt;/li&gt;
&lt;li&gt;Cần thiết kế các tool linh hoạt hơn để tối ưu hiệu suất&lt;/li&gt;
&lt;li&gt;Cần cân nhắc giữa hiệu suất và rủi ro bảo mật khi sử dụng tool calls&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="keeping-secrets-out-of-logs"&gt;&lt;a class="link" href="https://allan.reyes.sh/posts/keeping-secrets-out-of-logs/" target="_blank" rel="noopener"
&gt;Keeping Secrets Out of Logs&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Allan Reyes thảo luận về các chiến lược để ngăn chặn dữ liệu nhạy cảm bị ghi lại trong log của các hệ thống phần mềm. Ông nhấn mạnh rằng không có giải pháp duy nhất (&amp;ldquo;silver bullet&amp;rdquo;) mà cần áp dụng nhiều cách tiếp cận lớp layers (&amp;ldquo;lead bullets&amp;rdquo;).&lt;/p&gt;
&lt;p&gt;Các nguyên nhân chính khiến secrets xuất hiện trong log bao gồm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ghi trực tiếp dữ liệu nhạy cảm vào log&lt;/li&gt;
&lt;li&gt;Logging các đối tượng lớn (&amp;ldquo;kitchen sinks&amp;rdquo;) chứa secrets&lt;/li&gt;
&lt;li&gt;Thay đổi cấu hình làm tăng mức độ chi tiết của log&lt;/li&gt;
&lt;li&gt;Secrets được nhúng trong URL hoặc các định dạng khác&lt;/li&gt;
&lt;li&gt;Các công cụ telemetry thu thập biến cục bộ&lt;/li&gt;
&lt;li&gt;Lỗi nhập liệu của người dùng (ví dụ: nhập mật khẩu vào ô tên người dùng)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Các giải pháp chính bao gồm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Domain primitives:&lt;/strong&gt; Tạo các kiểu hoặc lớp riêng biệt cho secrets để có thể theo dõi và kiểm soát.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read-once objects:&lt;/strong&gt; Bọc secrets để chỉ có thể truy cập một lần, ngăn ngừa việc sử dụng lại vô tình.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Taint checking:&lt;/strong&gt; Sử dụng phân tích tĩnh để theo dõi luồng dữ liệu nhạy cảm trong hệ thống.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Log formatters:&lt;/strong&gt; Làm sạch hoặc loại bỏ dữ liệu nhạy cảm trước khi xuất log.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Preventive testing:&lt;/strong&gt; Cấu hình test để thất bại khi phát hiện secrets trong log.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Log pre-processors:&lt;/strong&gt; Các công cụ quét và loại bỏ dữ liệu nhạy cảm khỏi log trước khi lưu trữ.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cách tiếp cận chiến lược bao gồm:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Xây dựng nền tảng với văn hóa và công cụ phù hợp&lt;/li&gt;
&lt;li&gt;Hiểu cách dữ liệu chảy qua hệ thống&lt;/li&gt;
&lt;li&gt;Bảo vệ các &amp;ldquo;điểm nghẽn&amp;rdquo; chính nơi log được tạo ra hoặc xử lý&lt;/li&gt;
&lt;li&gt;Áp dụng bảo vệ nhiều lớp với nhiều lớp bảo vệ&lt;/li&gt;
&lt;li&gt;Lập kế hoạch cho ứng phó và phục hồi sự cố&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Reyes kết luận rằng mặc dù vấn đề này tồn tại dai dẳng và phức tạp, nhưng cách tiếp cận có hệ thống sử dụng nhiều kỹ thuật có thể giảm đáng kể nguy cơ rò rỉ secrets trong log.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không có giải pháp đơn lẻ cho vấn đề secrets trong log&lt;/li&gt;
&lt;li&gt;Cần áp dụng nhiều lớp bảo vệ để đảm bảo an toàn&lt;/li&gt;
&lt;li&gt;Các nguyên nhân phổ biến bao gồm logging trực tiếp và cấu hình sai&lt;/li&gt;
&lt;li&gt;Giải pháp bao gồm domain primitives, read-once objects và taint checking&lt;/li&gt;
&lt;li&gt;Cần có chiến lược toàn diện từ phòng ngừa đến ứng phó sự cố&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="things-i-believe"&gt;&lt;a class="link" href="https://leerob.com/beliefs" target="_blank" rel="noopener"
&gt;Things I Believe&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Lee Robinson chia sẻ những niềm tin và nguyên tắc cốt lõi của ông:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Phát hành nhanh:&lt;/strong&gt; Tốc độ là một sức mạnh siêu nhiên; các team nhỏ, thân thiện với AI sẽ phát hành nhanh hơn. Sự áp dụng quan trọng hơn là việc ra mắt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phát triển sự nghiệp:&lt;/strong&gt; Sự kiên trì và cải thiện hàng ngày (1%) thắng hơn tài năng. Thời gian đầu tư sẽ được cộng dồn theo thời gian.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tìm kiếm sự thật:&lt;/strong&gt; Hãy cởi mở để thay đổi suy nghĩ. Giờ tiếp xúc và hiểu biết thực tế quan trọng hơn dữ liệu trừu tượng.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Giao tiếp:&lt;/strong&gt; Viết rõ ràng phản ánh suy nghĩ rõ ràng. Các nhà lãnh đạo cung cấp sự rõ ràng và lường trước các phản đối trong giao tiếp.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Marketing dành cho developer:&lt;/strong&gt; Sự chân thật và giáo dục hiệu quả hơn marketing truyền thống. Việc hữu ích tạo ra giá trị dài hạn.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lãnh đạo:&lt;/strong&gt; Ảnh hưởng và sở hữu công việc vượt qua chức danh định nghĩa lãnh đạo. Ủy quyền, nhưng cũng tự mình làm công việc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Đam mê công việc:&lt;/strong&gt; Công việc có thể trở thành sở thích khi được thúc đẩy bởi sự tò mò và cân bằng với ranh giới, không phải là sự cân bằng huyền thoại giữa công việc và cuộc sống.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thực thi:&lt;/strong&gt; Các bản demo và prototype có giá trị hơn memo dài dòng. Hãy phát hành những gì khiến bạn hào hứng.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tuyển dụng:&lt;/strong&gt; Các nhà lãnh đạo giỏi tuyển dụng dựa trên tiềm năng phát triển và học hỏi, không chỉ kỹ năng hiện tại. Hãy hỏi ứng viên về công việc họ tự hào nhất.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Đồng cảm:&lt;/strong&gt; Giả định ý định tốt đẹp. Dẫn đầu bằng sự đồng cảm và lắng nghe phản biện một cách khách quan.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tốc độ là sức mạnh siêu nhiên trong phát triển phần mềm&lt;/li&gt;
&lt;li&gt;Sự kiên trì và cải tiến hàng ngày quan trọng hơn tài năng bẩm sinh&lt;/li&gt;
&lt;li&gt;Giao tiếp rõ ràng phản ánh suy nghĩ rõ ràng&lt;/li&gt;
&lt;li&gt;Lãnh đạo không chỉ là chức danh mà là ảnh hưởng và sở hữu công việc&lt;/li&gt;
&lt;li&gt;Cần có sự cân bằng giữa công việc và cuộc sống cá nhân&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-claude-code-is-built"&gt;&lt;a class="link" href="https://newsletter.pragmaticengineer.com/p/how-claude-code-is-built" target="_blank" rel="noopener"
&gt;How Claude Code is Built&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Claude Code, một công cụ phát triển được hỗ trợ bởi AI, được tạo ra bởi Boris Cherny tại Anthropic vào năm 2024. Ban đầu nó là một công cụ terminal sử dụng Claude để tương tác với hệ thống của người dùng, bắt đầu chỉ là xác định các bản nhạc. Tiềm năng của nó được mở rộng khi nó có quyền truy cập vào filesystem và các lệnh bash, cho phép khám phá code một cách tự động.&lt;/p&gt;
&lt;p&gt;Các khía cạnh chính trong việc phát triển và kiến trúc của Claude Code bao gồm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Công nghệ:&lt;/strong&gt; Được xây dựng với TypeScript, React, Ink, Yoga, và Bun. Bộ công nghệ này được chọn vì khả năng tương thích với Claude (&amp;ldquo;on distribution&amp;rdquo;), cho phép công cụ tự tạo khoảng 90% code của nó.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kiến trúc:&lt;/strong&gt; Được thiết kế đơn giản, Claude Code hoạt động cục bộ mà không cần ảo hóa. Nó giảm thiểu logic nghiệp vụ, để mô hình AI xử lý hầu hết các tác vụ. Giao diện người dùng được giữ tối giản để tránh hạn chế tiềm năng của mô hình.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hệ thống phân quyền:&lt;/strong&gt; Hệ thống nhiều cấp tìm kiếm sự chấp thuận của người dùng cho các hành động nhạy cảm, với tùy chọn duy trì quyền truy cập giữa các phiên. Nó sử dụng phân tích tĩnh để đánh giá các lệnh dựa trên cài đặt do người dùng xác định.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tạo mẫu nhanh:&lt;/strong&gt; Đội ngũ xây dựng và thử nghiệm nhiều mẫu nhanh chóng, lặp lại dựa trên phản hồi. Ví dụ, Boris đã thử nghiệm hơn 20 biến thể của tính năng danh sách việc cần làm trong chỉ hai ngày bằng cách sử dụng các thành phần UI do AI tạo ra.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đổi mới UX Terminal:&lt;/strong&gt; Claude Code nâng cao tương tác terminal với các tính năng như các phần tử UI tương tác, kiểu đầu ra (ví dụ: chế độ giải thích hoặc học tập) và chỉ báo tiến độ thời gian thực.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Subagents &amp;amp; Khả năng mở rộng:&lt;/strong&gt; Các tính năng như subagents và hỗ trợ cho Model Context Protocol (MCP) cho phép khả năng mô-đun và mở rộng. Hooks cho phép các lệnh shell tùy chỉnh.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tính năng doanh nghiệp:&lt;/strong&gt; Bao gồm thiết lập IAM, phân tích và tùy chọn cấu hình toàn đội.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kỹ thuật hướng AI:&lt;/strong&gt; Đội ngũ tận dụng AI cho đánh giá code, kiểm thử và phản hồi sự cố, góp phần vào chu kỳ phát triển nhanh hơn và tăng năng suất. Dữ liệu nội bộ cho thấy mức tăng 67% trong hiệu suất PR sau khi áp dụng Claude Code.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Claude Code đại diện cho sự thay đổi hướng tới kỹ thuật phần mềm hướng AI, nhấn mạnh lặp nhanh, scaffolding tối thiểu và tích hợp sâu với khả năng AI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Claude Code là công cụ phát triển AI được tạo ra bởi Anthropic vào năm 2024&lt;/li&gt;
&lt;li&gt;Được xây dựng với TypeScript, React, Ink, Yoga và Bun để tương thích với Claude&lt;/li&gt;
&lt;li&gt;Kiến trúc đơn giản hoạt động cục bộ mà không cần ảo hóa&lt;/li&gt;
&lt;li&gt;Hệ thống phân quyền nhiều cấp với tùy chọn duy trì quyền truy cập&lt;/li&gt;
&lt;li&gt;Tận dụng AI để tạo mẫu nhanh và giao diện người dùng&lt;/li&gt;
&lt;li&gt;Hỗ trợ subagents và Model Context Protocol (MCP) cho khả năng mở rộng&lt;/li&gt;
&lt;li&gt;Đội ngũ sử dụng AI cho đánh giá code, kiểm thử và phản hồi sự cố&lt;/li&gt;
&lt;li&gt;Đại diện cho sự thay đổi hướng tới kỹ thuật phần mềm hướng AI&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus-một-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Một vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/1e27232c-d4f1-4f4b-94fa-7318d39f6f3e_2360x2960.png"
loading="lazy"
alt="How Java Works"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/9bef6181-7eed-45a9-9c7e-abd6864cc62b_2360x2960.png"
loading="lazy"
alt="How Gitflow Branching Works?"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/9ffab5bc-5857-4544-8e25-2dbf795e6f85_3000x3900.png"
loading="lazy"
alt="The Life of a Redis Query"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/1c2bd03d-66f2-4eb9-8293-7a1d49b9b9b6_2360x2920.png"
loading="lazy"
alt="Cookies vs Sessions"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/26b55058-17ae-453f-8463-4d4e717e489b_2360x2920.png"
loading="lazy"
alt="Access Control Clearly Explained"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/00912640-ad5f-4ec7-aefa-e5eecf67dab0_3000x3900.png"
loading="lazy"
alt="How Git Reset Works?"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/43b73739-a975-42af-999d-8676b1605ed2_3000x3900.png"
loading="lazy"
alt="Apache Kafka Explained (At the high level)"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #57</title><link>https://miti99.com/post/2025/09/30/</link><pubDate>Tue, 30 Sep 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/09/30/</guid><description>&lt;p&gt;&lt;em&gt;Bài viết này được thực hiện bởi &lt;a class="link" href="https://github.com/musistudio/claude-code-router" target="_blank" rel="noopener"
&gt;Claude Code Router&lt;/a&gt; với model &lt;code&gt;qwen3-coder&lt;/code&gt; chạy trên &lt;a class="link" href="https://platform.iflow.cn/docs/api-mode" target="_blank" rel="noopener"
&gt;iFlow Platform&lt;/a&gt;. Mời bạn thưởng thức Newsletter #57.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="agentic-ai-và-sự-thay-đổi-nghề-nghiệp"&gt;&lt;a class="link" href="https://medium.com/@elliotgraebert/agentic-ai-has-changed-my-career-2c6e3dd29708" target="_blank" rel="noopener"
&gt;Agentic AI và Sự Thay Đổi Nghề Nghiệp&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong thời đại AI phát triển mạnh mẽ, khái niệm &amp;ldquo;Agentic AI&amp;rdquo; đang dần trở nên phổ biến và có ảnh hưởng lớn đến sự phát triển nghề nghiệp của nhiều người. Agentic AI đề cập đến các hệ thống AI có khả năng tự chủ thực hiện các nhiệm vụ phức tạp thông qua việc lập kế hoạch, ra quyết định và thực thi hành động một cách độc lập.&lt;/p&gt;
&lt;p&gt;Sự xuất hiện của Agentic AI đang tạo ra những thay đổi đáng kể trong thị trường lao động. Một số ngành nghề truyền thống có thể bị ảnh hưởng, trong khi các vị trí mới liên quan đến quản lý và tương tác với AI đang dần hình thành. Những người làm việc trong lĩnh vực công nghệ đang phải thích nghi với vai trò mới, chuyển từ việc thực hiện các nhiệm vụ cụ thể sang việc giám sát, hướng dẫn và cộng tác với các agent AI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Agentic AI đang thay đổi bản chất công việc trong nhiều ngành, đặc biệt là công nghệ&lt;/li&gt;
&lt;li&gt;Các chuyên gia cần phát triển kỹ năng mới để làm việc hiệu quả với AI agent&lt;/li&gt;
&lt;li&gt;Cơ hội mới đang mở ra cho những người có thể kết hợp AI agent vào quy trình làm việc&lt;/li&gt;
&lt;li&gt;Việc thích nghi sớm với xu hướng này có thể tạo ra lợi thế cạnh tranh trong sự nghiệp&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sự-phát-triển-của-garbage-collectors-từ-cms-của-java-đến-zgc"&gt;&lt;a class="link" href="https://codemia.io/blog/path/The-Evolution-of-Garbage-Collectors-From-Javas-CMS-to-ZGC-and-a-JVM-vs-Go-vs-Rust-Latency-Shootout" target="_blank" rel="noopener"
&gt;Sự Phát Triển Của Garbage Collectors: Từ CMS Của Java Đến ZGC&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Quản lý bộ nhớ là một chủ đề quan trọng trong lập trình, đặc biệt là trong các ngôn ngữ như Java, Go và Rust. Bài viết này khám phá sự tiến hóa của garbage collectors (GC) từ Concurrent Mark-Sweep (CMS) truyền thống của Java đến Z Garbage Collector (ZGC) hiện đại.&lt;/p&gt;
&lt;p&gt;ZGC là một bước tiến lớn trong việc giảm thiểu thời gian tạm dừng của ứng dụng (pause times), với mục tiêu giữ thời gian tạm dừng dưới 10ms bất kể kích thước heap. Điều này tạo ra sự khác biệt lớn về hiệu suất so với các GC thế hệ trước như CMS.&lt;/p&gt;
&lt;p&gt;Bài viết cũng so sánh hiệu suất về độ trễ giữa các nền tảng:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JVM (với ZGC): Giảm đáng kể thời gian tạm dừng nhờ cải tiến trong thiết kế GC&lt;/li&gt;
&lt;li&gt;Go: GC hiệu quả với độ trễ thấp nhờ thuật toán concurrent và tri-color marking&lt;/li&gt;
&lt;li&gt;Rust: Tránh hoàn toàn GC nhờ mô hình ownership, mang lại hiệu suất dự đoán được mà không có chi phí GC&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ZGC giúp giảm thời gian tạm dừng của ứng dụng xuống dưới 10ms&lt;/li&gt;
&lt;li&gt;Go sử dụng thuật toán marking hiệu quả để giữ độ trễ thấp&lt;/li&gt;
&lt;li&gt;Rust loại bỏ hoàn toàn nhu cầu GC nhờ ownership model&lt;/li&gt;
&lt;li&gt;Việc lựa chọn ngôn ngữ ảnh hưởng đáng kể đến hiệu suất và trải nghiệm người dùng&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="mới-trong-java-25-generational-shenandoah-gc-không-còn-là-tính-năng-thử-nghiệm"&gt;&lt;a class="link" href="https://theperfparlor.com/2025/09/14/new-in-java25-generational-shenandoah-gc-is-no-longer-experimental/" target="_blank" rel="noopener"
&gt;Mới Trong Java 25: Generational Shenandoah GC Không Còn Là Tính Năng Thử Nghiệm&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Java 25 đánh dấu sự ổn định hóa của garbage collector Generational Shenandoah, hiện đã sẵn sàng cho môi trường production. Shenandoah GC, ban đầu được giới thiệu trong Java 12, là một bộ thu gom rác có thời gian tạm dừng thấp, chạy gần như đồng thời với ứng dụng.&lt;/p&gt;
&lt;p&gt;Phiên bản generational, lần đầu tiên có sẵn như một tính năng thử nghiệm trong Java 24, cải thiện hiệu suất và dung lượng bộ nhớ bằng cách tách biệt các đối tượng trẻ và cũ. Cách tiếp cận này giảm việc quét không cần thiết, vì hầu hết các đối tượng đều &amp;ldquo;chết sớm&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Các cải tiến chính trong Java 25 bao gồm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ổn định hóa và sửa lỗi&lt;/li&gt;
&lt;li&gt;Hiệu suất tốt hơn và giảm chi phí GC&lt;/li&gt;
&lt;li&gt;Quản lý vùng nhớ hiệu quả hơn&lt;/li&gt;
&lt;li&gt;Công cụ và ghi log được cải thiện&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Theo như bài viết, &amp;ldquo;Nhờ tất cả các cải tiến này, Generational Shenandoah đã đạt đến mức độ trưởng thành phù hợp cho các ứng dụng production.&amp;rdquo; Người dùng không còn cần cờ &lt;code&gt;-XX:+UnlockExperimentalVMOptions&lt;/code&gt; để kích hoạt tính năng này.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generational Shenandoah GC trong Java 25 đã sẵn sàng cho production&lt;/li&gt;
&lt;li&gt;Tính năng generational giúp cải thiện hiệu suất và dung lượng bộ nhớ&lt;/li&gt;
&lt;li&gt;Không cần cờ experimental để kích hoạt tính năng này nữa&lt;/li&gt;
&lt;li&gt;Đây là bước tiến quan trọng trong việc tối ưu hóa garbage collection của Java&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="nếu-tất-cả-thế-giới-là-một-monorepo"&gt;&lt;a class="link" href="https://jtibs.substack.com/p/if-all-the-world-were-a-monorepo?utm_source=tldrnewsletter" target="_blank" rel="noopener"
&gt;Nếu Tất Cả Thế Giới Là Một Monorepo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết khám phá cách hệ sinh thái lập trình R, thông qua kho lưu trữ gói trung tâm CRAN, thực thi tư duy &amp;ldquo;monorepo&amp;rdquo; bằng cách yêu cầu các tác giả gói đảm bảo rằng các cập nhật của họ không phá vỡ các gói phụ thuộc. Điều này tương phản với các hệ sinh thái khác như npm hoặc PyPI, nơi các thay đổi phá vỡ phổ biến hơn và được để cho người dùng giải quyết.&lt;/p&gt;
&lt;p&gt;Tác giả suy ngẫm về cách tiếp cận này thúc đẩy sự đồng cảm cực độ trong bảo trì phần mềm, ưu tiên trải nghiệm người dùng hơn sự tiện lợi cho nhà phát triển. Một trải nghiệm cá nhân với các thay đổi phá vỡ trong gói &lt;code&gt;grf&lt;/code&gt; làm nổi bật những thách thức và lợi ích của hệ thống này.&lt;/p&gt;
&lt;p&gt;Bài viết kết luận bằng cách đề xuất rằng các hệ sinh thái phần mềm quy mô lớn khác có thể hưởng lợi từ việc áp dụng triết lý tương tự để cải thiện khả năng bảo trì lâu dài và sự tin tưởng của người dùng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CRAN yêu cầu các tác giả gói đảm bảo cập nhật không phá vỡ phụ thuộc&lt;/li&gt;
&lt;li&gt;Hệ sinh thái R ưu tiên trải nghiệm người dùng hơn sự tiện lợi cho nhà phát triển&lt;/li&gt;
&lt;li&gt;Triết lý &amp;ldquo;monorepo&amp;rdquo; có thể cải thiện độ tin cậy và khả năng bảo trì&lt;/li&gt;
&lt;li&gt;Các hệ sinh thái khác có thể học hỏi từ cách tiếp cận của R&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="9-mẫu-kiến-trúc-phần-mềm-cho-hệ-thống-phân-tán"&gt;&lt;a class="link" href="https://dev.to/somadevtoo/9-software-architecture-patterns-for-distributed-systems-2o86?=&amp;amp;aid=recZm2jVus1yqUHWw" target="_blank" rel="noopener"
&gt;9 Mẫu Kiến Trúc Phần Mềm Cho Hệ Thống Phân tán&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết trình bày các mẫu kiến trúc phần mềm thiết yếu được sử dụng trong các hệ thống phân tán để quản lý dữ liệu và giao tiếp một cách hiệu quả. Những mẫu này cũng rất quan trọng cho các cuộc phỏng vấn thiết kế hệ thống. Các mẫu chính bao gồm:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Peer-to-Peer (P2P):&lt;/strong&gt; Cho phép giao tiếp trực tiếp giữa các nút mà không cần điều phối viên trung tâm, được sử dụng trong các hệ thống chia sẻ tệp và blockchain.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API Gateway:&lt;/strong&gt; Đóng vai trò là điểm vào thống nhất cho các dịch vụ backend, đơn giản hóa tương tác của khách hàng và thực thi bảo mật.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pub-Sub (Publish-Subscribe):&lt;/strong&gt; Tách rời người sản xuất tin nhắn khỏi người tiêu dùng bằng cách sử dụng một broker tin nhắn, hỗ trợ các hệ thống thời gian thực.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Request-Response:&lt;/strong&gt; Một mô hình đồng bộ trong đó khách hàng chờ phản hồi từ máy chủ, phổ biến trong REST API và ứng dụng web.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Event Sourcing:&lt;/strong&gt; Lưu trữ các thay đổi trạng thái dưới dạng các sự kiện bất biến, hỗ trợ khả năng kiểm tra và phát lại trong các hệ thống tài chính.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ETL (Extract, Transform, Load):&lt;/strong&gt; Tích hợp dữ liệu từ nhiều nguồn vào một kho dữ liệu, rất quan trọng cho phân tích và di chuyển dữ liệu.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batching:&lt;/strong&gt; Nhóm dữ liệu để xử lý nhằm cải thiện hiệu suất, được sử dụng trong ETL và các đường ống dữ liệu.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Streaming Processing:&lt;/strong&gt; Xử lý các luồng dữ liệu liên tục trong thời gian thực, lý tưởng cho các ứng dụng IoT và an ninh mạng.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Orchestration:&lt;/strong&gt; Phối hợp quy trình làm việc giữa các dịch vụ bằng cách sử dụng một bộ điều khiển trung tâm, đảm bảo thực hiện có trật tự trong các hệ thống phức tạp.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Những mẫu này giúp các kiến trúc sư xây dựng các hệ thống có thể mở rộng và phục hồi bằng cách cung cấp các cách tiếp cận có cấu trúc cho các thách thức thiết kế phổ biến.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;9 mẫu kiến trúc thiết yếu cho hệ thống phân tán và phỏng vấn thiết kế&lt;/li&gt;
&lt;li&gt;Mỗi mẫu giải quyết các vấn đề cụ thể trong giao tiếp và quản lý dữ liệu&lt;/li&gt;
&lt;li&gt;Các mẫu giúp xây dựng hệ thống có thể mở rộng và phục hồi&lt;/li&gt;
&lt;li&gt;Hiểu biết về các mẫu này rất quan trọng cho kỹ sư phần mềm&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sắp-xếp-các-dòng-trong-mã-nguồn"&gt;&lt;a class="link" href="https://testing.googleblog.com/2025/09/sort-lines-in-source-code.html?=&amp;amp;aid=recV8wgDMqTb7Hwko" target="_blank" rel="noopener"
&gt;Sắp Xếp Các Dòng Trong Mã Nguồn&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Google Testing Blog thảo luận về cách sắp xếp các dòng trong mã nguồn có thể giúp ngăn chặn lỗi và cải thiện khả năng bảo trì. Bài viết sử dụng một ví dụ về cấu hình trò chơi, nơi một cài đặt cờ trùng lặp đã gây ra lỗi và dễ dàng được phát hiện khi các dòng được sắp xếp.&lt;/p&gt;
&lt;p&gt;Bài viết giới thiệu công cụ &lt;strong&gt;keep-sorted&lt;/strong&gt; (có sẵn tại &lt;a class="link" href="http://github.com/google/keep-sorted" target="_blank" rel="noopener"
&gt;github.com/google/keep-sorted&lt;/a&gt;), một công cụ để tự động sắp xếp các dòng trong các khối được chỉ định trong tệp. Người dùng thêm các chú thích &lt;code&gt;# keep-sorted start&lt;/code&gt; và &lt;code&gt;# keep-sorted end&lt;/code&gt; xung quanh các dòng mục tiêu và chạy công cụ.&lt;/p&gt;
&lt;p&gt;Việc sắp xếp giúp xác định các vấn đề như các mục nhập trùng lặp. Bài viết lưu ý: &amp;ldquo;Các danh sách đã sắp xếp và các dòng mã dễ đọc và bảo trì hơn, và có thể giúp ngăn chặn lỗi.&amp;rdquo; Bài viết cũng đề cập đến các tính năng nâng cao như sắp xếp bằng biểu thức chính quy và nhắc nhở người dùng &amp;ldquo;đảm bảo thứ tự ban đầu không có chủ ý&amp;rdquo; trước khi sắp xếp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sắp xếp các dòng mã giúp phát hiện lỗi trùng lặp và cải thiện khả năng bảo trì&lt;/li&gt;
&lt;li&gt;Công cụ keep-sorted tự động sắp xếp các khối mã được chỉ định&lt;/li&gt;
&lt;li&gt;Các danh sách đã sắp xếp dễ đọc và dễ bảo trì hơn&lt;/li&gt;
&lt;li&gt;Cần kiểm tra thứ tự ban đầu có chủ ý trước khi sắp xếp&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="đánh-giá-26-năm-thay-đổi-của-java"&gt;&lt;a class="link" href="https://neilmadden.blog/2025/09/12/rating-26-years-of-java-changes/" target="_blank" rel="noopener"
&gt;Đánh Giá 26 Năm Thay Đổi Của Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;[Bài viết nhìn lại chặng đường 26 năm phát triển của ngôn ngữ lập trình Java, đánh giá các thay đổi quan trọng trong ngôn ngữ và thư viện cốt lõi. Tác giả bắt đầu từ Java 1.1.8 năm 1999 và điểm qua những cải tiến lớn như Bộ sưu tập (Collections Framework) (&amp;ldquo;4/10&amp;rdquo;), Generics (&amp;ldquo;8/10&amp;rdquo;), và java.util.concurrent (&amp;ldquo;10/10&amp;rdquo;).&lt;/p&gt;
&lt;p&gt;Một số tính năng bị chỉ trích như NIO (&amp;ldquo;0/10&amp;rdquo;) và Streams (&amp;ldquo;1/10&amp;rdquo;), trong khi Records (&amp;ldquo;10/10&amp;rdquo;) và UTF-8 mặc định (&amp;ldquo;10/10&amp;rdquo;) được khen ngợi. Bài viết bao quát các phiên bản đến Java 25, nhấn mạnh xu hướng phát hành theo thời gian và các tính năng như pattern matching, virtual threads, và mã hóa hậu lượng tử. Mô-đun (Modules) nhận đánh giá rất tệ &amp;ldquo;-10/10&amp;rdquo;. Bài viết kết thúc bằng lời mời gọi thảo luận về các đánh giá chủ quan này.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java đã trải qua nhiều thay đổi lớn trong 26 năm phát triển&lt;/li&gt;
&lt;li&gt;Các cải tiến như Generics, java.util.concurrent và Records được đánh giá cao&lt;/li&gt;
&lt;li&gt;Một số tính năng như NIO và Streams nhận đánh giá thấp từ cộng đồng&lt;/li&gt;
&lt;li&gt;Java 25 tiếp tục cải tiến với các tính năng như pattern matching và virtual threads&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus-một-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Một vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/aa5ea98b-c832-429d-8e48-63f25b7feb5a_3000x3900.jpeg"
loading="lazy"
alt="Python vs Java"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/4863d93c-ca2a-4b5a-b0b4-fe3621a6c184_2250x2920.png"
loading="lazy"
alt="Design Patterns Cheat Sheet"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/d6d04f12-2adc-4d8e-a9ca-2de16399066f_2250x3376.png"
loading="lazy"
alt="Design Patterns Cheat Sheet"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/a370bb6a-82d3-45ad-b6f4-a2a9a4317402_800x1099.jpeg"
loading="lazy"
alt="CI/CD Simplified Visual Guide"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/5d9faeeb-3428-44c8-94fd-4b52fc287da3_3000x3900.png"
loading="lazy"
alt="How Apache Kafka Works?"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/45136e24-79ee-4c6d-a53a-89df6afebef6_3000x3900.png"
loading="lazy"
alt="Load Balancers vs API Gateways vs Reverse Proxy"
&gt;
&lt;img src="https://substackcdn.com/image/fetch/$s_!4Uyj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a1213e2-86cb-4fa8-bf72-e37ffe0da44d_2250x2624.heic"
loading="lazy"
alt="Understanding Load Balancers: Traffic Management at Scale"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Nhìn chung thì nội dung ngắn gọn, mình tương đối hài lòng, chắc khoảng 80% so với Claude Code với Claude models, nhưng vì miễn phí nên là mình rất ưng ý :)))&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #56</title><link>https://miti99.com/post/2025/09/29/</link><pubDate>Mon, 29 Sep 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/09/29/</guid><description>&lt;p&gt;&lt;em&gt;Hôm nay mình lại thử nghiệm tiếp &lt;a class="link" href="https://opencode.ai/" target="_blank" rel="noopener"
&gt;OpenCode&lt;/a&gt;. Kết quả là khi mình gửi 1 url thì nó&amp;hellip; stuck luôn :v. Vì vậy mình chuyển qua thử GitHub Copilot, với OpenRouter. Kết quả ban đầu cho thấy GitHub Copilot không detect được Newsletter số trước, nó đánh lại từ #1. Và tags cũng ghi chữ thường, không đúng format mình expect. Mình không ưng ý nên xoá đi, thử lại với OpenAI Codex, kết quả thì để đọc được trang web nó đã hỏi mình n thứ, vả lại còn đòi chạy mấy lệnh python để đọc web, xong cài package bằng pip trực tiếp nữa. Mình thấy không oke với chuyện này nên chuyển qua xài thử &lt;a class="link" href="https://github.com/musistudio/claude-code-router" target="_blank" rel="noopener"
&gt;Claude Code Router&lt;/a&gt;, chạy Claude Code nhưng với API từ OpenRouter, với model &lt;code&gt;xAI: Grok 4 Fast&lt;/code&gt;. Bài đầu tiên thấy tóm tắt khá dài. Thôi thì mời bạn thưởng thức Newsletter #56 nhé.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="i-love-uuid-i-hate-uuid"&gt;&lt;a class="link" href="https://blog.epsiolabs.com/i-love-uuid-i-hate-uuid" target="_blank" rel="noopener"
&gt;I love UUID, I hate UUID&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ blog Epsio Labs khám phá những mặt tích cực và tiêu cực của UUID khi sử dụng làm khóa chính trong cơ sở dữ liệu quan hệ, đặc biệt trong hệ thống streaming SQL của họ. Đối với các lập trình viên junior, UUID (Universally Unique Identifier) là một công cụ hữu ích để tạo ID duy nhất mà không cần phụ thuộc vào database server, giúp đơn giản hóa việc phát triển ứng dụng phân tán.&lt;/p&gt;
&lt;p&gt;UUID được yêu thích vì có thể sinh ra từ client-side, cho phép cập nhật giao diện người dùng một cách optimistic – nghĩa là UI có thể phản hồi ngay lập tức mà không chờ server xác nhận, cải thiện trải nghiệm người dùng. Chúng đảm bảo tính duy nhất toàn cầu với xác suất va chạm cực thấp (khoảng 1 trong hàng tỷ tỷ), và tương thích tốt với các hoạt động bulk insert như lệnh COPY trong PostgreSQL, tránh tình trạng phải đồng bộ hóa với server như khi dùng auto-increment integers.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, UUIDv4 – phiên bản phổ biến nhất – bị chỉ trích vì tính ngẫu nhiên cao dẫn đến phân tán dữ liệu trong B-Tree index của database. Điều này làm tăng kích thước index đáng kể và giảm tốc độ insert. Trong benchmark với 10 triệu rows, index UUIDv4 chiếm 389MB và mất 54.62 giây, so với UUIDv7 chỉ 301MB và 37.53 giây – cải thiện 22% kích thước và 31% thời gian.&lt;/p&gt;
&lt;p&gt;UUIDv7 là giải pháp mới, nhúng 48-bit timestamp Unix vào đầu UUID để tạo thứ tự thời gian, giúp index hiệu quả hơn mà vẫn giữ tính duy nhất. Trade-off duy nhất là có thể lộ thời gian tạo nếu UUID bị expose ra ngoài, và giảm nhẹ độ ngẫu nhiên, nhưng rủi ro va chạm vẫn rất thấp (khoảng 0.0000000003% cho 1 triệu UUID trong 1ms).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UUID lý tưởng cho optimistic UI updates và bulk operations nhờ client-generated và global uniqueness.&lt;/li&gt;
&lt;li&gt;UUIDv4 kém hiệu suất do randomness gây phân tán index, tăng size và thời gian query.&lt;/li&gt;
&lt;li&gt;UUIDv7 cải thiện bằng timestamp prefix, tăng throughput 31% và giảm index size 22%.&lt;/li&gt;
&lt;li&gt;Khuyến nghị sử dụng UUIDv7 cho database hiện đại để balance uniqueness và performance.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what"&gt;&lt;a class="link" href="https://pvs-studio.com/en/blog/posts/java/1284/" target="_blank" rel="noopener"
&gt;What&amp;rsquo;s new in Java 25&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ PVS-Studio blog tóm tắt các cập nhật mới trong Java 25, phát hành ngày 10/09/2025. Đối với lập trình viên junior, Java 25 mang đến nhiều cải tiến giúp code đơn giản hơn, hiệu suất cao hơn và an toàn hơn, mà không phá vỡ compatibility với code cũ.&lt;/p&gt;
&lt;p&gt;Trong phần New API, JEP 506 giới thiệu Scoped Values – thay thế cho ThreadLocal với lifetime scoped, giúp quản lý dữ liệu trong các block code ngắn hạn mà không leak memory. JEP 510 thêm Key Derivation Function API để xử lý unified các thuật toán KDF cho cryptography. JEP 511 cho phép import toàn bộ module bằng Module Import Declarations, giảm boilerplate. JEP 512 với Compact Source Files và Instance Main Methods giúp viết app đơn giản mà không cần class đầy đủ. JEP 513 cho phép flexible constructor bodies, di chuyển code trước super() call.&lt;/p&gt;
&lt;p&gt;Về Platform Changes, JEP 503 loại bỏ 32-bit x86 port vì ít sử dụng, tập trung vào 64-bit. JEP 519 Compact Object Headers giảm header từ 12 bytes xuống 8 bytes, tiết kiệm memory. JEP 521 thêm Generational Shenandoah GC cho throughput cao hơn. Trong AOT, JEP 514 và 515 cải thiện command-line ergonomics và method profiling để JIT nhanh hơn. JFR enhancements như JEP 518 Cooperative Sampling và JEP 520 Method Timing giúp monitoring chính xác hơn.&lt;/p&gt;
&lt;p&gt;Các preview features bao gồm Structured Concurrency (preview thứ 5) cho concurrent tasks an toàn. Tổng thể, Java 25 tập trung vào developer productivity, performance và security. Junior devs nên thử nghiệm các JEPs mới để viết code hiện đại hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scoped Values và KDF API: Cải tiến API cho scoped data và cryptography.&lt;/li&gt;
&lt;li&gt;Module imports và compact source: Giảm boilerplate cho learning và simple apps.&lt;/li&gt;
&lt;li&gt;Compact headers và Generational GC: Tối ưu memory và performance.&lt;/li&gt;
&lt;li&gt;JFR và AOT enhancements: Monitoring và compilation tốt hơn cho production.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="some-best-practices-for-writing-readable-automation-tests"&gt;&lt;a class="link" href="https://blog.scottlogic.com/2025/09/04/some-best-practices-for-writing-readable-automation-tests.html" target="_blank" rel="noopener"
&gt;Some Best Practices for Writing Readable Automation Tests&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Scott Logic Blog hướng dẫn các best practices để viết automation tests dễ đọc, sử dụng Playwright với TypeScript. Đối với lập trình viên junior, automation testing giúp kiểm tra ứng dụng tự động, nhưng code test khó maintain nếu không readable, dẫn đến bugs ẩn hoặc team khó collaborate.&lt;/p&gt;
&lt;p&gt;Về assertions, sử dụng expect() flexible như expect(response.status()).toBeOK() để handle codes thành công khác nhau (200, 201) mà không fail sớm, tập trung vào validations quan trọng. Với locators, ưu tiên .getByRole cho accessibility, dễ inspect qua DevTools bằng tab navigation, thay vì .getByTestID có thể confuse screen readers. Luôn advocate cho HTML roles đúng nếu thiếu.&lt;/p&gt;
&lt;p&gt;Naming conventions: Sử dụng backticks cho test names động, ví dụ test(&lt;code&gt;should return a 400 when User Information is '${variable}'&lt;/code&gt;), cho phép interpolation variables. Structure: Tag tests với {tag: &amp;lsquo;THW-000&amp;rsquo;} để filter runs theo tickets, hoặc annotations cho links chi tiết theo Playwright docs, tăng traceability và longevity.&lt;/p&gt;
&lt;p&gt;Những practices này giúp tests maintainable, accessible và team-friendly. Junior devs nên áp dụng để viết tests rõ ràng, giảm debugging time và cải thiện QA process.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Assertions flexible: Sử dụng toBeOK() cho HTTP success codes đa dạng.&lt;/li&gt;
&lt;li&gt;Locators accessible: Ưu tiên .getByRole qua DevTools inspection.&lt;/li&gt;
&lt;li&gt;Dynamic naming: Backticks cho variable interpolation trong test titles.&lt;/li&gt;
&lt;li&gt;Tagging annotations: Lưu traceability với tickets cho better collaboration.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tech-debt-understanding-its-business-impact---optimism"&gt;&lt;a class="link" href="https://www.optimism.io/blog/tech-debt-understanding-its-business-impact" target="_blank" rel="noopener"
&gt;Tech Debt: Understanding its Business Impact - Optimism&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Nợ kỹ thuật (technical debt) đề cập đến chi phí ngầm phát sinh từ việc chọn giải pháp nhanh chóng thay vì tối ưu trong phát triển phần mềm, tương tự như nợ tài chính tích lũy lãi suất. Bài viết mô tả nó là sản phẩm phổ biến trong môi trường công nghệ nhanh chóng, nơi các đội ngũ chọn fix nhanh để đáp ứng deadline, dẫn đến codebase dễ vỡ và khó mở rộng.&lt;/p&gt;
&lt;p&gt;Nguyên nhân chính bao gồm áp lực giao hàng nhanh chóng, thiếu kiểm thử đầy đủ, hoặc yêu cầu thay đổi vượt quá tốc độ cải thiện code. Sự tích tụ nợ kỹ thuật gây ra tác động kinh doanh nghiêm trọng: chi phí bảo trì tăng cao do sửa lỗi liên tục, trì hoãn phát hành tính năng làm mất lợi thế cạnh tranh, và rủi ro mất doanh thu từ sự cố hệ thống. Ví dụ, nợ không được xử lý có thể làm tăng chi phí phát triển lên đến 20-30% hàng năm, gây căng thẳng cho ngân sách và động lực đội ngũ.&lt;/p&gt;
&lt;p&gt;Để đo lường, các công ty sử dụng công cụ phân tích độ phức tạp code, tỷ lệ mã trùng lặp, và chỉ số khả năng bảo trì, thường định lượng nợ như một phần trăm giá trị codebase. Hậu quả không chỉ giới hạn ở khía cạnh kỹ thuật mà còn ảnh hưởng đến sự hài lòng của khách hàng qua sản phẩm không đáng tin cậy, đồng thời cản trở khả năng đổi mới. Các chiến lược quản lý nhấn mạnh cách tiếp cận chủ động: dành thời gian riêng cho việc refactor code, tích hợp kiểm thử tự động vào pipeline CI/CD, và xây dựng văn hóa phát triển coi trọng chất lượng bền vững. Bằng cách coi nợ kỹ thuật như một tài sản chiến lược thay vì khuyết điểm không thể tránh khỏi, doanh nghiệp có thể giảm thiểu rủi ro, nâng cao sự linh hoạt, và thúc đẩy tăng trưởng lâu dài.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nợ kỹ thuật phát sinh từ các shortcut trong coding ưu tiên tốc độ, dẫn đến nhu cầu rework trong tương lai.&lt;/li&gt;
&lt;li&gt;Nguyên nhân chính: áp lực deadline và lựa chọn thiết kế kém ban đầu.&lt;/li&gt;
&lt;li&gt;Tác động kinh doanh: chi phí cao hơn, đổi mới chậm hơn, và vấn đề scalability.&lt;/li&gt;
&lt;li&gt;Phương pháp đo lường: metrics code như điểm phức tạp và tỷ lệ nợ.&lt;/li&gt;
&lt;li&gt;Chiến lược: phân bổ sprint refactor, tích hợp CI/CD testing, và văn hóa coding bền vững.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="spec-driven-development-with-ai-a-new-approach-and-a-journey-into-the-past"&gt;&lt;a class="link" href="https://foojay.io/today/spec-driven-development-with-ai-a-new-approach-and-a-journey-into-the-past" target="_blank" rel="noopener"
&gt;Spec-Driven Development with AI: A New Approach and a Journey into the Past&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phê phán bản chất tập trung vào code trong phát triển phần mềm truyền thống, nơi yêu cầu thường trở nên lỗi thời, dẫn đến vấn đề bảo trì, đặc biệt khi AI tăng tốc coding mà không giải quyết nguyên nhân gốc rễ. Lấy cảm hứng từ Rational Unified Process (RUP) những năm 2000, tác giả Simon Martinelli đề xuất AI Unified Process (AIUP), một phương pháp dẫn dắt bởi yêu cầu, đặt nhu cầu kinh doanh làm nguồn sự thật duy nhất.&lt;/p&gt;
&lt;p&gt;Trong cách tiếp cận này, phát triển bắt đầu bằng catalog yêu cầu kinh doanh thủ công, sau đó sử dụng AI tạo ra các artifact: sơ đồ use case, mô hình entity, thông số hệ thống, và cuối cùng là code ứng dụng. Các bên liên quan xem xét từng bước để đảm bảo phù hợp, tránh lỗi miền. Tất cả output được mã hóa dưới dạng Markdown và PlantUML, versioned trong Git để diff trực quan và theo dõi audit. AI đóng vai trò &amp;ldquo;consistency engine&amp;rdquo;, tự động cập nhật các yếu tố downstream khi yêu cầu thay đổi, loại bỏ đồng bộ thủ công.&lt;/p&gt;
&lt;p&gt;Bối cảnh lịch sử nhấn mạnh trọng tâm lặp lại modeling của RUP, nay được nâng cao bởi AI hiện đại để hiệu quả hơn. Lợi ích bao gồm hợp tác mạnh mẽ hơn giữa kinh doanh và developer, hệ thống dễ bảo trì với traceability đầy đủ, chu kỳ nhanh hơn bằng cách tự động hóa công việc nhàm chán, và chất lượng tích hợp qua test dựa trên spec. Thách thức ngầm bao gồm đầu tư ban đầu vào yêu cầu chính xác và sự tham gia của bên liên quan, dù phương pháp giảm thiểu các lỗi truyền thống như documentation thiếu sót. Phương pháp này phù hợp cho ứng dụng kinh doanh nhờ pattern công nghệ dự đoán được, nhấn mạnh hợp tác con người-AI cho logic miền.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chuyển trọng tâm từ code sang yêu cầu làm nguồn sự thật, sử dụng AI tạo artifact tự động.&lt;/li&gt;
&lt;li&gt;Workflow: Yêu cầu kinh doanh → AI-generated diagrams/models/specs/code, tất cả versioned trong Git.&lt;/li&gt;
&lt;li&gt;Lợi ích: Hợp tác tốt hơn, traceability, chu kỳ phát triển nhanh, chất lượng qua spec-based tests.&lt;/li&gt;
&lt;li&gt;Thách thức: Đầu tư ban đầu vào yêu cầu chính xác và stakeholder review.&lt;/li&gt;
&lt;li&gt;Phù hợp cho business apps với pattern predictable, tận dụng AI cho consistency.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="on-good-software-engineers"&gt;&lt;a class="link" href="https://candost.blog/on-good-software-engineers/" target="_blank" rel="noopener"
&gt;On Good Software Engineers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Việc đặt kỳ vọng cho kỹ sư phần mềm là thách thức đối với quản lý do nhu cầu, cấu trúc và văn hóa công ty khác nhau. Bài viết bác bỏ khái niệm &amp;ldquo;10x engineers&amp;rdquo; như gây hại cho tinh thần đội ngũ và chất lượng code, đồng thời phê phán framework phát triển sự nghiệp vì thiếu sót trong định nghĩa năng lực. Thay vào đó, tiêu chuẩn đơn giản: &amp;ldquo;Một kỹ sư tốt là người mà tôi, với tư cách quản lý hoặc đồng nghiệp, có thể tin tưởng để tiến hành dự án, biết rằng họ sẽ cung cấp giải pháp bằng cách làm việc với đội ngũ và sản xuất chất lượng tốt, lặp lại liên tục.&amp;rdquo; Điều này áp dụng cho mọi cấp độ, từ junior xử lý nhiệm vụ nhỏ đến staff dẫn dắt sáng kiến phức tạp.&lt;/p&gt;
&lt;p&gt;Đặc trưng bao gồm độ tin cậy, khả năng thích ứng và nhất quán. Kỹ năng nhấn mạnh giao tiếp rõ ràng (viết và nói), lắng nghe đồng cảm, trao đổi phản hồi, và nắm vững quy trình (code review, RFC, methodology như Scrum). Kỹ sư phải học các chi tiết tổ chức – văn hóa, chuẩn mực, hệ thống phân cấp – để ảnh hưởng hiệu quả và chủ động nhúng chất lượng, như qua test-driven development hoặc refactor code cũ. Họ ưu tiên phù hợp với stakeholder, giảm độ phức tạp qua thiết kế modular và chiến lược test, và duy trì chất lượng bền vững giữa thay đổi.&lt;/p&gt;
&lt;p&gt;Tư duy hướng tăng trưởng: chấp nhận khó chịu, thừa nhận lỗi, ngăn chặn tái phát, và hành động vào vấn đề mà không phàn nàn. Kỹ sư tốt chơi như thành viên đội ngũ, đề xuất giải pháp thay vì đẩy vấn đề. Đối với lập trình viên junior, bài viết khuyến khích tập trung vào độ tin cậy và hợp tác để trở thành kỹ sư đáng tin cậy, vượt qua kỹ năng kỹ thuật thuần túy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kỹ sư tốt: Tin cậy tiến hành dự án qua hợp tác đội ngũ và chất lượng nhất quán.&lt;/li&gt;
&lt;li&gt;Kỹ năng cốt lõi: Giao tiếp, nắm quy trình tổ chức, chủ động chất lượng.&lt;/li&gt;
&lt;li&gt;Tư duy: Tăng trưởng, trách nhiệm, giải quyết vấn đề chủ động.&lt;/li&gt;
&lt;li&gt;Phù hợp mọi cấp độ, nhấn mạnh hợp tác hơn tốc độ cá nhân.&lt;/li&gt;
&lt;li&gt;Khác biệt với great: Ảnh hưởng rộng hơn, nhưng good tập trung cơ bản.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-i-do-programming"&gt;&lt;a class="link" href="https://esafev.com/notes/why-i-do-programming/" target="_blank" rel="noopener"
&gt;Why I do programming&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả kể lại niềm đam mê lập trình suốt đời bắt nguồn từ sự tò mò thời thơ ấu. Là một đứa trẻ ba tuổi trầm tĩnh, họ thích tháo rời máy cassette để khám phá cơ chế bên trong, nuôi dưỡng bản năng hiểu máy móc. Điều này phát triển ở trường qua MS-DOS, Logo, BASIC, sau đó là HTML, CSS và JavaScript, nơi xây dựng chương trình đơn giản và website mang lại cảm giác kỳ diệu. Đến 10 tuổi, internet khơi dậy thử nghiệm web, bao gồm kiếm tiền từ giúp bài tập.&lt;/p&gt;
&lt;p&gt;Tuổi thiếu niên sâu sắc hóa qua mod game như MTA và SAMP sử dụng scripting PAWN, nhằm tạo thế giới multiplayer immersive giống &amp;ldquo;proto-metaverse&amp;rdquo;. Khám phá Second Life mở rộng thành scripting LSL cho kinh tế ảo, tạo thu nhập thực từ sáng tạo digital. Tuy nhiên, sự chuyển dịch hướng tác động đời thực nảy sinh khoảng 16 tuổi, dẫn đến các venture bán hàng online nhỏ để tài trợ công nghệ cá nhân, dù rủi ro trường học.&lt;/p&gt;
&lt;p&gt;Đại học Kỹ thuật Sáng tạo kết hợp kỹ năng kỹ thuật như CAD và bảo mật với triết học, nhấn mạnh đặt câu hỏi suy tư. Sau tốt nghiệp, bất định giải quyết qua startup MipoTheBot, nơi thiết kế và coding khơi dậy động lực chuyên nghiệp, dù đóng cửa dạy bài học kinh doanh. Kinh nghiệm qua các ngành nhấn mạnh sức mạnh đội ngũ hợp tác.&lt;/p&gt;
&lt;p&gt;Burnout đánh úp hai lần, một liên quan công việc và một cá nhân, nhưng chuyến du lịch châu Âu phục hồi khẳng định niềm vui lập trình. Tác giả đánh giá cao biên giới vô tận – từ backend đến AI – như phản ứng chống phân tâm, thể hiện sáng tạo hơn chỉ nghề nghiệp. Cuối cùng, lập trình bền vững như cách cốt lõi để tinker, khám phá và tương tác thực tế, không thay đổi từ xung động tuổi trẻ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lái bằng tò mò tuổi thơ tháo rời máy móc và khám phá cơ chế.&lt;/li&gt;
&lt;li&gt;Tìm magic trong tạo chương trình chức năng, từ game đơn giản đến thế giới ảo.&lt;/li&gt;
&lt;li&gt;Tìm xây dựng tác động ý nghĩa đời thực ngoài không gian ảo.&lt;/li&gt;
&lt;li&gt;Xem lập trình như khám phá vô tận qua lĩnh vực web, hệ thống và AI, thỏa mãn impulse tinker.&lt;/li&gt;
&lt;li&gt;Thấy lập trình như triết lý sáng tạo tương tác thế giới, bền vững qua burnout.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-unreasonable-effectiveness-of-modern-sort-algorithms"&gt;&lt;a class="link" href="https://github.com/Voultapher/sort-research-rs/blob/main/writeup/unreasonable/text.md" target="_blank" rel="noopener"
&gt;The unreasonable effectiveness of modern sort algorithms&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Nghiên cứu khám phá hiệu suất đáng ngạc nhiên của thuật toán sắp xếp generic hiện đại trong kịch bản hạn chế: sắp xếp mảng u64 với chỉ bốn giá trị phân biệt, mô phỏng dữ liệu low-cardinality. Sử dụng suite benchmark sort-research-rs dựa trên Rust trên AMD Ryzen 9 5900X, tác giả test bucket sort tối ưu domain chống hybrid general-purpose, đo throughput theo elements per second qua kích thước input từ 10 đến 10^8.&lt;/p&gt;
&lt;p&gt;Phương pháp liên quan benchmark cold với pattern random_d4, flush cache hướng dẫn để mô phỏng gọi one-off. Approach domain-specific bao gồm BTreeMap (đếm sorted, ~150M elem/s tại 10^6), HashMap (nhanh hơn nhưng cần sort thêm, ~300M elem/s), dựa trên match (nặng branch, giới hạn ~200M elem/s bởi mispredictions), branchless (tránh penalty, ~220M elem/s), và perfect hash function (PHF - nhanh nhất cho known domain, ~400M elem/s nhưng panic nếu dữ liệu thay đổi).&lt;/p&gt;
&lt;p&gt;Generic như std lib ipnsort (unstable) và driftsort (stable) vượt trội, đạt ~350M elem/s cho unstable và ~280M cho stable nhờ partial deduplication tự động, xử lý O(N * log(K)) với K=4 mà không kiến thức trước. So sánh với pdqsort, crumsort, radsort cho thấy generic robust hơn, thích ứng mà không fail. Tác giả nhấn mạnh std lib Rust (co-author) cho robustness qua partial deduplication, hiệu quả trong pattern low-cardinality phổ biến, làm generic &amp;ldquo;unreasonably effective&amp;rdquo; mà không cần specialize.&lt;/p&gt;
&lt;p&gt;Trade-off: Specialized excel ideal nhưng fail (panic/output sai) nếu dữ liệu thay đổi; generic adapt, phù hợp production. Đối với junior Rust devs, nghiên cứu khuyến khích tin tưởng std lib cho sorting, tập trung domain knowledge thay vì micro-optimize unknown cases.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tập trung benchmark Rust trên low-cardinality u64 (4 giá trị phân biệt) trên Ryzen 9 5900X.&lt;/li&gt;
&lt;li&gt;So sánh bucket sort domain-specific (BTree, Hash, match, branchless, PHF) vs generic hybrids (ipnsort, driftsort, pdqsort).&lt;/li&gt;
&lt;li&gt;Generic std lib vượt trội nhờ partial deduplication, đạt O(N log K) tự động ~350M elem/s stable/unstable.&lt;/li&gt;
&lt;li&gt;Specialized nhanh nhưng fragile (panic nếu domain thay đổi); generic robust cho production.&lt;/li&gt;
&lt;li&gt;Kết luận: Std lib &amp;ldquo;unreasonably effective&amp;rdquo; cho pattern phổ biến, ưu tiên robustness hơn specialize.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-we-made-clickhouse-log-queries-995-faster-with-resource-fingerprinting"&gt;&lt;a class="link" href="https://signoz.io/blog/query-performance-improvement" target="_blank" rel="noopener"
&gt;How we made ClickHouse log queries 99.5% faster with resource fingerprinting&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Các kỹ sư SigNoz giải quyết truy vấn log chậm trong ClickHouse bằng cách xử lý lưu trữ dữ liệu không hiệu quả. Truyền thống, log từ các pod, service, môi trường đa dạng trộn lẫn qua các block lưu trữ, buộc database quét gần như toàn bộ dữ liệu cho filter mục tiêu, như theo namespace. Ví dụ, truy vấn namespace production trước đây kiểm tra 99.5% block, dẫn đến I/O cao và latency.&lt;/p&gt;
&lt;p&gt;ClickHouse, database phân tích columnar, tổ chức dữ liệu vào granule khoảng 8,192 rows, sử dụng primary-key index sparse để skip block không liên quan trong truy vấn. Trong khi secondary index như bloom filter cung cấp skip nào đó, chúng kém hơn so với primary key tối ưu, quyết định sắp xếp physical row qua ORDER BY clause.&lt;/p&gt;
&lt;p&gt;Kỹ thuật cốt lõi giới thiệu resource fingerprinting phân cấp: hash từ attribute chính (e.g., &amp;ldquo;cluster=c1;namespace=n1;pod=p1&amp;rdquo;) xác định unique nguồn log. Bằng cách incorporate fingerprint sớm trong ORDER BY sequence – sau bucketing thời gian nhưng trước severity và timestamp – log từ resource tương tự cluster cùng contiguous block. Điều này tận dụng indexing sparse của ClickHouse để skip granule không match chính xác.&lt;/p&gt;
&lt;p&gt;Benchmark chứng minh cải thiện đáng kể: filter namespace nay đọc chỉ 0.85% block (222/26,135), giảm I/O hơn 99%. Giải pháp extensible đến Kubernetes, AWS, Docker; duy trì compatibility schema. Đối với lập trình viên junior, kỹ thuật nhấn mạnh optimize storage qua sorting thông minh, tận dụng index để cải thiện query performance trong analytical database như ClickHouse.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vấn đề: Log trộn lẫn dẫn đến quét 99.5% block cho filter như namespace.&lt;/li&gt;
&lt;li&gt;Giải pháp: Hierarchical resource fingerprinting hash attribute, ORDER BY (time, fingerprint) để cluster log.&lt;/li&gt;
&lt;li&gt;Kết quả: Giảm quét từ 41,498/41,676 xuống 222/26,135 block, tiết kiệm I/O &amp;gt;99%.&lt;/li&gt;
&lt;li&gt;Triển khai: Extensible cho K8s/AWS, giữ schema compatibility.&lt;/li&gt;
&lt;li&gt;Bài học: Sắp xếp physical data theo query pattern phổ biến để leverage sparse index hiệu quả.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ai-coding"&gt;&lt;a class="link" href="https://geohot.github.io/blog/jekyll/update/2025/09/12/ai-coding.html" target="_blank" rel="noopener"
&gt;AI Coding&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của một nhân vật công nghệ có kinh nghiệm phản ánh về tuổi tác và sự thất vọng với ngành công nghệ bị hype chi phối, phê phán vai trò over-hyped của AI trong coding. Lấy từ thất bại quá khứ như venture xe tự lái, tác giả lập luận rằng sự nhiệt tình về AI thường ưu tiên lợi nhuận tài chính hơn tiến bộ thực tế. Trung tâm là ẩn dụ AI như compiler: người dùng input prompt tiếng Anh như &amp;ldquo;code&amp;rdquo;, nhận output compiled, giống phát triển truyền thống nhưng với tweak tương tác hiếm khi vượt trội. Mô hình này highlight giới hạn của AI – tiếng Anh thiếu precision cho task mới, non-deterministic kết quả mà không spec nghiêm ngặt, và global effect của prompt – làm nó viable chủ yếu cho workflow routine do ecosystem lập trình hiện tại kém.&lt;/p&gt;
&lt;p&gt;Tác giả bác bỏ ý tưởng AI &amp;ldquo;coding&amp;rdquo; độc lập, quy utility của nó cho enhanced search, optimization, và pattern reuse thay vì trí tuệ innate. Họ lập luận rằng phụ thuộc model ngôn ngữ lớn tiết lộ flaw trong codebase, hiring, và tool, dự đoán AI sẽ automate lập trình giống compiler và spreadsheet transform lĩnh vực trước. Nghiên cứu trích dẫn nhấn mạnh disconnect: AI boost perceived productivity 20% nhưng giảm actual speed 19%, fuel hàng tỷ investment misguided.&lt;/p&gt;
&lt;p&gt;Kết luận với call to action, bài viết kêu gọi focus trên ngôn ngữ robust, compiler, library hơn sensationalism. Update làm rõ hỗ trợ AI như tool thực tế khi giới hạn được thừa nhận, trong khi decrying hype và ponder style blog cho reach rộng hơn engagement metric. Tổng thể, nó advocate skepticism, ưu tiên công việc thực tế hơn hype.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI như compiler: Prompt tiếng Anh yield code, nhưng thiếu precision, determinism, locality so với ngôn ngữ lập trình.&lt;/li&gt;
&lt;li&gt;Productivity illusion: Cảm giác nhanh hơn nhưng chậm thực tế 19%, từ tool kém hiện tại.&lt;/li&gt;
&lt;li&gt;Giới hạn: Tiếng Anh kém cho novel task; AI optimize pattern, không magic.&lt;/li&gt;
&lt;li&gt;Tương lai: AI automate như compiler thay manual coding, evolve tool ecosystem.&lt;/li&gt;
&lt;li&gt;Phê phán hype: Ưu tiên language/compiler cải thiện hơn billion investment misguided.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Đánh giá sơ bộ thì combo này ổn áp, chạy ổn định, không hỏi prompt linh tinh để xử lý việc đọc WebFetch, kết quả thì hơi dài dòng, nhiều lỗi vặt, mình sẽ thử thêm một số model khác trong các bài viết sắp tới để tìm được 1 combo vừa free lại chất lượng :D&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #55</title><link>https://miti99.com/post/2025/09/14/</link><pubDate>Sun, 14 Sep 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/09/14/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #55.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="cpu-utilization-is-a-lie"&gt;&lt;a class="link" href="https://www.brendanlong.com/cpu-utilization-is-a-lie.html" target="_blank" rel="noopener"
&gt;%CPU Utilization Is A Lie&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Brendan Long đưa ra một phát hiện thú vị và quan trọng về việc hiểu sai lầm phổ biến liên quan đến CPU utilization - một chỉ số mà hầu hết các quản trị viên hệ thống đều theo dõi hàng ngày.&lt;/p&gt;
&lt;p&gt;Tác giả đã thực hiện các bài test stress chi tiết trên một máy Ryzen 9 5900X (12 core / 24 thread) và phát hiện ra rằng CPU utilization được báo cáo bởi hệ thống thường là một ước tính thấp, đôi khi đáng kể so với công việc thực tế mà CPU đang thực hiện.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các phát hiện chính từ bài test&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;General CPU&lt;/strong&gt;: Tại mức 50% utilization được báo cáo, hệ thống thực tế đang làm 60-65% công việc tối đa có thể&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;64-bit Integer Math&lt;/strong&gt;: Tình hình còn tệ hơn nữa - tại &amp;ldquo;50% utilization&amp;rdquo;, CPU thực tế đang làm 65-85% công việc tối đa&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Matrix Math&lt;/strong&gt;: Đáng báo động nhất - tại &amp;ldquo;50% utilization&amp;rdquo;, CPU thực tế đang làm 80-100% công việc tối đa&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Nguyên nhân chính của hiện tượng này&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;SMT/Hyperthreading&lt;/strong&gt;: Khi số lượng worker vượt quá số core vật lý, các core phải chia sẻ tài nguyên, dẫn đến hiệu suất không tuyến tính&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Turbo Boost&lt;/strong&gt;: Tốc độ clock giảm khi nhiều core hoạt động đồng thời, làm cho công thức tính utilization (busy cycles / total cycles) trở nên phức tạp hơn&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Hệ quả thực tế&lt;/strong&gt;: Nếu bạn dựa vào CPU utilization để dự đoán khả năng mở rộng hệ thống, bạn sẽ gặp nhiều khó khăn. Đặc biệt khi CPU đang hoạt động hiệu quả (trên &amp;ldquo;50% utilization&amp;rdquo;), chỉ số utilization được báo cáo thường là một ước tính thấp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Giải pháp đề xuất&lt;/strong&gt;: Thay vì chỉ dựa vào CPU utilization, tác giả khuyên nên:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Benchmark công việc thực tế mà server có thể thực hiện trước khi gặp lỗi hoặc độ trễ không chấp nhận được&lt;/li&gt;
&lt;li&gt;Báo cáo lượng công việc hiện tại mà server đang thực hiện&lt;/li&gt;
&lt;li&gt;So sánh hai chỉ số này thay vì chỉ dựa vào CPU utilization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Đây là một bài viết quan trọng cho bất kỳ ai làm việc với hiệu suất hệ thống, đặc biệt là các quản trị viên DevOps và kỹ sư infrastructure cần hiểu rõ giới hạn thực tế của các server của mình.&lt;/p&gt;
&lt;h2 id="we-only-hire-the-trendiest"&gt;&lt;a class="link" href="https://danluu.com/programmer-moneyball/" target="_blank" rel="noopener"
&gt;We only hire the trendiest&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Dan Luu đưa ra một phân tích sâu sắc về vấn đề tuyển dụng trong ngành công nghệ, nơi các công ty thường tập trung vào việc tuyển dụng những ứng viên có &amp;ldquo;background trendy&amp;rdquo; thay vì đánh giá năng lực thực tế.&lt;/p&gt;
&lt;p&gt;Tác giả kể về câu chuyện của Mike, một lập trình viên có 11 năm kinh nghiệm nhưng bị từ chối bởi nhiều công ty chỉ vì kinh nghiệm của anh ấy không đủ &amp;ldquo;trendy&amp;rdquo; - làm việc với .NET, kinh nghiệm hợp đồng, và có trải nghiệm đa dạng nhưng không tập trung vào một lĩnh vực cụ thể.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các vấn đề chính được đề cập&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sự thiên vị trong tuyển dụng&lt;/strong&gt;: Các công ty như TrendCo (tên ẩn danh) từ chối ứng viên vì lý do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kinh nghiệm công nghệ không liên quan (thực chất là không thích .NET)&lt;/li&gt;
&lt;li&gt;Kinh nghiệm quá ngẫu nhiên (thực chất là không có background trendy)&lt;/li&gt;
&lt;li&gt;Là contractor (thực chất là định kiến)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chi phí của việc chỉ tuyển dụng trendy&lt;/strong&gt;: Các công ty này phải đối mặt với hai lựa chọn:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trả lương cực cao để cạnh tranh với các công ty hàng đầu&lt;/li&gt;
&lt;li&gt;Chấp nhận trả lương không cạnh tranh và mất đi nhiều ứng viên giỏi&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hiệu ứng Moneyball&lt;/strong&gt;: Tương tự như câu chuyện Billy Beane trong bóng chày, các công ty nên tập trung vào việc tìm kiếm những ứng viên bị đánh giá thấp nhưng có năng lực thực sự, thay vì chạy theo những ứng viên có background &amp;ldquo;hot&amp;rdquo;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Giải pháp đề xuất&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Moneyball approach&lt;/strong&gt;: Tìm kiếm những ứng viên bị đánh giá thấp về mặt thống kê nhưng có năng lực thực sự&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Đầu tư vào đào tạo&lt;/strong&gt;: Thay vì chỉ tập trung vào việc tuyển dụng người giỏi, hãy đầu tư vào việc đào tạo và phát triển nhân viên hiện tại&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cải tiến quy trình và công cụ&lt;/strong&gt;: Đầu tư vào công cụ, quy trình và văn hóa làm việc hiệu quả hơn là chỉ tập trung vào việc &amp;ldquo;săn&amp;rdquo; nhân tài&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Bài học quan trọng&lt;/strong&gt;: Nhiều lập trình viên giỏi nhất đã từng bị từ chối bởi các công ty trước khi họ làm việc tại Google hoặc các công ty công nghệ lớn khác. Việc đánh giá giá trị của một ứng viên chỉ dựa trên background trendy có thể khiến các công ty bỏ lỡ những tài năng thực sự.&lt;/p&gt;
&lt;p&gt;Đây là một bài viết đáng suy ngẫm cho cả nhà tuyển dụng và ứng viên, giúp nhận ra những định kiến vô hình trong ngành công nghệ và tìm cách khắc phục chúng.&lt;/p&gt;
&lt;h2 id="how-i-solved-a-distributed-queue-problem-after-15-years"&gt;&lt;a class="link" href="https://www.dbos.dev/blog/durable-queues" target="_blank" rel="noopener"
&gt;How I solved a distributed queue problem after 15 years&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ DBOS chia sẻ kinh nghiệm thực tế về việc giải quyết vấn đề hàng đợi phân tán sau 15 năm làm việc trong lĩnh vực hệ thống đám mây, mang đến những hiểu biết sâu sắc về cách xây dựng hàng đợi bền vững và có khả năng quan sát.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tầm quan trọng của hàng đợi trong hệ thống đám mây&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Hàng đợi đóng vai trò quan trọng trong việc giúp các hệ thống có khả năng mở rộng ngang (horizontal scaling), lập lịch (scheduling) và kiểm soát luồng (flow control). Chúng cho phép các thành phần hệ thống hoạt động một cách độc lập và bất đồng bộ, giúp tăng cường khả năng chịu lỗi và hiệu suất tổng thể.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các thách thức chính khi xây dựng hàng đợi phân tán&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Độ bền (Durability)&lt;/strong&gt;: Đảm bảo rằng các thông điệp không bị mất ngay cả khi hệ thống gặp sự cố. Điều này đòi hỏi cơ chế lưu trữ đáng tin cậy và khả năng phục hồi sau lỗi.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Khả năng quan sát (Observability)&lt;/strong&gt;: Cần có khả năng theo dõi trạng thái hàng đợi, hiệu suất và các vấn đề phát sinh để có thể chẩn đoán và khắc phục kịp thời.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mở rộng ngang&lt;/strong&gt;: Hàng đợi cần có khả năng phân tán trên nhiều node để xử lý tải lớn mà không trở thành nút thắt cổ chai.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tính nhất quán&lt;/strong&gt;: Đảm bảo rằng các thông điệp được xử lý đúng thứ tự và không bị mất mát trong môi trường phân tán.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Giải pháp được đề xuất&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Bài viết tập trung vào việc xây dựng hàng đợi sử dụng các công nghệ hiện đại như database transactional để đảm bảo độ bền, kết hợp với các pattern như event sourcing và CQRS (Command Query Responsibility Segregation) để tăng cường khả năng quan sát.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các lợi ích chính&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Khả năng phục hồi cao&lt;/strong&gt;: Hệ thống có thể phục hồi nhanh chóng sau sự cố nhờ cơ chế lưu trữ transactional&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hiệu suất tốt&lt;/strong&gt;: Việc sử dụng các kỹ thuật tối ưu hóa giúp giảm độ trễ và tăng throughput&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dễ dàng giám sát&lt;/strong&gt;: Các metric và logging chi tiết giúp theo dõi hiệu suất hệ thống&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mở rộng linh hoạt&lt;/strong&gt;: Hệ thống có thể dễ dàng mở rộng theo nhu cầu&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Kết luận&lt;/strong&gt;: Việc xây dựng hàng đợi phân tán bền vững là một thách thức phức tạp nhưng cực kỳ quan trọng đối với các hệ thống hiện đại. Bằng cách kết hợp các nguyên tắc thiết kế đúng đắn và công nghệ phù hợp, các kỹ sư có thể tạo ra những hệ thống hàng đợi đáng tin cậy, hiệu suất cao và dễ dàng quản lý.&lt;/p&gt;
&lt;h2 id="cognitive-load-is-what-matters"&gt;&lt;a class="link" href="https://minds.md/zakirullin/cognitive" target="_blank" rel="noopener"
&gt;Cognitive load is what matters&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Artem Zakirullin đưa ra một quan điểm cơ bản và quan trọng về việc giảm tải nhận thức (cognitive load) trong phát triển phần mềm, tập trung vào điều thực sự quan trọng thay vì chạy theo các thuật ngữ và best practices hào nhoáng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Khái niệm cốt lõi&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Tác giả lập luận rằng có quá nhiều buzzwords và best practices, nhưng điều thực sự quan trọng là lượng nhầm lẫn mà các lập trình viên cảm thấy khi đọc qua code. Sự nhầm lẫn này tốn thời gian và tiền bạc, và được gây ra bởi cognitive load cao - một ràng buộc cơ bản của con người, không phải là một khái niệm trừu tượng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cognitive load là gì&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Cognitive load là lượng tư duy mà một lập trình viên cần để hoàn thành một nhiệm vụ. Khi đọc code, bạn phải đặt các giá trị biến, logic luồng điều khiển và chuỗi gọi vào đầu óc. Người trung bình có thể giữ khoảng 4 mẩu thông tin như vậy trong bộ nhớ làm việc. Khi cognitive load đạt đến ngưỡng này, việc hiểu trở nên khó khăn hơn nhiều.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các loại cognitive load&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Intrinsic&lt;/strong&gt;: Do độ khó cố hữu của nhiệm vụ, không thể giảm bớt, là cốt lõi của phát triển phần mềm&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extraneous&lt;/strong&gt;: Được tạo ra bởi cách thông tin được trình bày, do các yếu tố không liên quan trực tiếp đến nhiệm vụ, có thể giảm đáng kể&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Các ví dụ thực tế về extraneous cognitive load&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Module nông (Shallow modules)&lt;/strong&gt;: Có quá nhiều module nông với giao diện phức tạp so với chức năng nhỏ chúng cung cấp. Điều này đòi hỏi phải nhớ trách nhiệm của từng module và tương tác của chúng.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microservices nông&lt;/strong&gt;: Quá nhiều microservices nông dẫn đến distributed monolith, nơi mỗi yêu cầu mới dẫn đến thay đổi ở 4+ microservices.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ngôn ngữ tính năng phong phú&lt;/strong&gt;: Khi có nhiều tính năng, lập trình viên phải dành thời gian chơi với vài dòng code để sử dụng một tính năng nào đó, và khi quay lại, họ phải tái tạo quá trình tư duy đó.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lạm dụng nguyên tắc DRY&lt;/strong&gt;: Việc loại bỏ mọi sự lặp lại có thể dẫn đến coupling chặt chẽ giữa các thành phần không liên quan.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Framework coupling chặt chặt&lt;/strong&gt;: Việc phụ thuộc quá nhiều vào framework buộc các lập trình viên tương lai phải học &amp;ldquo;magic&amp;rdquo; của framework đó trước.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kiến trúc tầng nhiều lớp&lt;/strong&gt;: Các lớp trừu tượng ngang không cần thiết chỉ làm tăng cognitive load.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Giải pháp đề xuất&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ưu tiên module sâu (Deep modules)&lt;/strong&gt;: Các thành phần cung cấp chức năng mạnh mẽ nhưng có giao diện đơn giản&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Giảm số lượng lựa chọn&lt;/strong&gt;: Giảm cognitive load bằng cách giới hạn số lượng lựa chọn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sử dụng chuỗi mô tả tự thân&lt;/strong&gt;: Ưu tiên chuỗi mô tả tự thân thay vì mã số (ví dụ: &amp;ldquo;jwt_has_expired&amp;rdquo; thay vì 401)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tránh các lớp trừu tượng không cần thiết&lt;/strong&gt;: Chỉ thêm các lớp trừu tượng khi thực sự cần điểm mở rộng&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Đo lường confusion của lập trình viên mới&lt;/strong&gt;: Nếu họ bị nhầm lẫn hơn ~40 phút liên tục - bạn có điều gì đó cần cải thiện trong code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Kết luận&lt;/strong&gt;: Chúng ta nên giảm bất kỳ cognitive load nào nằm ngoài intrinsic complexity của công việc chúng ta làm. Code tốt không phải là code phức tạp hay thông minh, mà là code mà các lập trình viên tương lai (bao gồm chính bạn) có thể hiểu nhanh chóng.&lt;/p&gt;
&lt;h2 id="claude-code-framework-wars"&gt;&lt;a class="link" href="https://shmck.substack.com/p/claude-code-framework-wars" target="_blank" rel="noopener"
&gt;Claude Code Framework Wars&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Shawn đưa ra một cái nhìn tổng quan về cuộc chiến framework Claude Code, nơi các nhà phát triển đang thử nghiệm với cấu trúc, điều phối và tiêu chuẩn để khai thác tối đa tiềm năng của AI coding.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bối cảnh hiện tại&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Claude Code đang phát triển nhanh chóng với nhiều framework khác nhau xuất hiện, mỗi framework tập trung vào các khía cạnh khác nhau của quy trình phát triển AI. Các framework này đang cạnh tranh để trở thành tiêu chuẩn cho tương lai của AI coding.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các khía cạnh chính của Claude Code Framework&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Cấu trúc (Structure)&lt;/strong&gt;: Cách các dự án được tổ chức và quản lý&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Điều phối (Orchestration)&lt;/strong&gt;: Cách AI được điều phối và quản lý trong quy trình phát triển&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tiêu chuẩn (Standards)&lt;/strong&gt;: Các quy tắc và hướng dẫn để đảm bảo chất lượng và nhất quán&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Các loại framework chính&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Framework tập trung vào Product Specs&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tập trung vào việc tạo ra product specifications chi tiết&lt;/li&gt;
&lt;li&gt;Sử dụng AI để chuyển đổi specs thành code&lt;/li&gt;
&lt;li&gt;Ví dụ: Framework giúp tạo ra các sản phẩm từ mô tả chi tiết&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Framework tập trung vào Role Simulation&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mô phỏng các vai trò khác nhau trong đội ngũ phát triển&lt;/li&gt;
&lt;li&gt;AI đóng vai trò như kỹ sư senior, reviewer, hoặc product manager&lt;/li&gt;
&lt;li&gt;Giúp tạo ra code chất lượng cao với nhiều góc nhìn khác nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Framework tập trung vào Repo Artifacts&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tập trung vào việc tạo và quản lý các artifact trong repository&lt;/li&gt;
&lt;li&gt;Sử dụng AI để tạo ra các file cấu hình, documentation, và code&lt;/li&gt;
&lt;li&gt;Ví dụ: Framework giúp tạo ra các file README, cấu hình CI/CD&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Framework tập trung vào Parallel Sessions&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cho phép chạy nhiều phiên AI song song&lt;/li&gt;
&lt;li&gt;Mỗi phiên tập trung vào một nhiệm vụ cụ thể&lt;/li&gt;
&lt;li&gt;Tăng tốc độ phát triển bằng cách phân công công việc&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Các lợi ích chính&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Tăng tốc độ phát triển&lt;/strong&gt;: AI giúp tự động hóa các công việc lặp đi lặp lại&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cải thiện chất lượng code&lt;/strong&gt;: AI đóng vai trò như reviewer, giúp phát hiện lỗi sớm&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Giảm cognitive load&lt;/strong&gt;: AI giúp xử lý các công việc phức tạp, cho phép developer tập trung vào kiến trúc&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tăng tính nhất quán&lt;/strong&gt;: AI tuân thủ các tiêu chuẩn và quy tắc đã được định nghĩa&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Các thách thức&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Quản lý context&lt;/strong&gt;: AI cần được cung cấp đủ context để làm việc hiệu quả&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Đảm bảo chất lượng&lt;/strong&gt;: Cần có cơ chế review và kiểm tra chất lượng&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tích hợp với quy trình hiện tại&lt;/strong&gt;: Framework cần được tích hợp mượt mà với quy trình làm việc hiện có&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Kết luận&lt;/strong&gt;: Bài viết nhấn mạnh rằng AI hoạt động tốt nhất khi được cung cấp cấu trúc rõ ràng. Các framework Claude Code đang hội tụ về một tương lai nơi AI không phải là một hộp ma thuật mà là một tập các đồng đội mà bạn quản lý. Điều thú vị là: cấu trúc bạn cung cấp càng nhiều, bạn nhận lại càng nhiều.&lt;/p&gt;
&lt;h2 id="the-last-programmers"&gt;&lt;a class="link" href="https://www.xipu.li/posts/the-last-programmers" target="_blank" rel="noopener"
&gt;The Last Programmers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Xipu Li đưa ra một quan điểm sâu sắc và đáng suy ngẫm về tương lai của ngành lập trình, nơi chúng ta đang chứng kiến thế hệ cuối cùng của những người tự dịch ý tưởng thành code bằng tay.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bối cảnh cá nhân của tác giả&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Xipu đã rời bỏ công việc tại Amazon vào tháng 5 để tham gia một startup có tên Icon. Anh chia sẻ rằng đây là quyết định sự nghiệp tốt nhất anh từng đưa ra, không phải vì những lý do bạn có thể nghĩ.&lt;/p&gt;
&lt;p&gt;Tại Amazon, anh làm việc trong nhóm Amazon Q Developer - xây dựng trợ lý AI coding của Amazon. Anh nhận thấy rằng Amazon đang thua cuộc trong cuộc đua AI, với tầm nhìn sản phẩm rất hạn chế và tốc độ phát triển chậm chạp so với các đối thủ như Cursor và Anthropic.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Những gì tác giả đang chứng kiến hiện nay&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Một đồng đội của anh đã không xem xét code thực tế trong nhiều tuần. Thay vào đó, anh ấy viết tài liệu thiết kế bằng tiếng Anh thông thường và tin tưởng AI xử lý việc triển khai. Khi cần sửa chữa, anh ấy chỉnh sửa tài liệu, không phải code.&lt;/p&gt;
&lt;p&gt;Điều này khiến tác giả nhận ra một điều sâu sắc: chúng ta đang sống qua thời đại kết thúc của một kỷ nguyên mà con người tự dịch ý tưởng thành code bằng tay. Trong vài năm tới, kỹ năng này sẽ trở nên liên quan như biết cách đóng ngựa.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sự phân chia đang diễn ra&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Tác giả quan sát thấy hai nhóm đang hình thành trong đội ngũ của mình:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nhóm thử nghiệm (Experimenters)&lt;/strong&gt;: Những người dành thời gian nghỉ trưa để thử nghiệm các công cụ AI coding mới, thiết lập các workflow tạo ra toàn bộ tính năng từ lệnh thoại, và liên tục đẩy ranh giới của việc ít code thủ công nhất. Họ có thể bị coi là lười biếng, nhưng thực chất họ đang theo con đường tự nhiên của công nghệ.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nhóm bảo vệ (Guardians)&lt;/strong&gt;: Những người tin sâu sắc rằng hiểu code ở mức độ cơ bản là không thể thương lượng. Họ có thể phát hiện thuật toán không hiệu quả, hiểu tại sao các mẫu thiết kế tồn tại, và hiểu các hệ thống nền tảng đủ tốt để gỡ lỗi những vấn đề AI không thể xử lý.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Sự hàng hóa hóa của phần mềm&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Tương tự như ngành công nghiệp sôcôla, phần mềm đang hướng đến cùng một hướng. Sự khác biệt giữa sản phẩm phần mềm và hàng tiêu dùng đang thu hẹp hàng tháng. Cả hai cạnh tranh về thương hiệu, phân phối và hiểu biết tâm lý khách hàng hơn là chức năng thuần túy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ba điều gì thực sự tồn tại khi triển khai kỹ thuật trở nên hàng hóa hóa&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Hiểu biết nhu cầu thực sự của con người&lt;/strong&gt;: Không phải những gì họ nói trong khảo sát hay nhóm tập trung, mà những gì họ sẵn sàng trả tiền và sử dụng hàng ngày.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Biết nên xây dựng gì và không nên xây dựng gì&lt;/strong&gt;: Đây là gu thẩm mỹ, nhưng cũng là chiến lược. Hiểu biết tính năng nào sẽ tạo ra giá trị thực sự so với tính năng nào chỉ thêm độ phức tạp.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Đưa sản phẩm trước đúng người và thuyết phục họ quan tâm&lt;/strong&gt;: Phân phối và marketing, nhưng cũng là định vị, thời điểm và hiểu biết tâm lý khách hàng.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Ý nghĩa đối với những người mới bắt đầu&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Nếu bạn đang học code ngày nay, đừng dừng lại. Nhưng đừng biến coding thành kỹ năng duy nhất của bạn. Những nhà phát triển sẽ phát triển trong thế giới mới này là những người hiểu biết người dùng, thị trường và mô hình kinh doanh tốt như họ hiểu công nghệ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ý nghĩa đối với những người đã đang xây dựng&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Nếu bạn đã là nhà phát triển hoặc đang xây dựng công ty, hãy nhớ rằng triển khai kỹ thuật của bạn sớm sẽ có thể được bất kỳ ai có quyền truy cập vào công cụ AI tốt sao chép. Lợi thế cạnh tranh của bạn cần là điều gì khác.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thế hệ cuối cùng&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Chúng ta là thế hệ cuối cùng của những người tự dịch ý tưởng thành code bằng tay. Con cái của chúng ta sẽ mô tả những gì họ muốn và xem nó xuất hiện trên màn hình, giống như chúng ta mô tả những gì chúng ta muốn cho công cụ tìm kiếm và xem kết quả xuất hiện.&lt;/p&gt;
&lt;p&gt;Họ sẽ phán xét chúng ta giống như chúng ta phán xét những người tính toán sổ sách thủ công trước khi bảng tính tồn tại. Đáng nể về sự tận tâm với nghề, nhưng cuối cùng là nỗ lực không cần thiết dành cho những vấn đề đã được giải quyết bằng công cụ tốt hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kết luận&lt;/strong&gt;: Những phần luôn thực sự quan trọng. Hiểu biết con người. Xây dựng những thứ họ muốn. Đưa những thứ đó trước mặt họ. Mọi thứ khác chỉ là chi tiết triển khai.&lt;/p&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/c8da4839-d519-43a9-bffb-2c81a2c153f4_2250x2624.png"
loading="lazy"
alt="A Guide to Rate Limiting Strategies"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/94510aef-adee-4c78-84cf-05dfe5f9d6c0_3000x3900.png"
loading="lazy"
alt="9 Docker Best Practices You Should Know"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/a5e59510-28d9-423e-bdc4-986d24e58f91_2808x4096.jpeg"
loading="lazy"
alt="Where Do We Cache Data?"
&gt;&lt;/p&gt;
&lt;h2 id="bonus-một-vài-video-hay-ho"&gt;Bonus: Một vài video hay ho
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=X0-TGhktFnE" target="_blank" rel="noopener"
&gt;All New Java Language Features Since Java 21 #RoadTo25&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Newsletter #54</title><link>https://miti99.com/post/2025/09/10/</link><pubDate>Wed, 10 Sep 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/09/10/</guid><description>&lt;p&gt;&lt;em&gt;Do dạo này tình hình tài chính cá nhân không tốt lắm, nên mình quyết định huỷ Claude Subscription, và do đó không còn dùng Claude Code nữa. Hiện tại mình đang dùng Roo Code với model Z.AI: GLM 4.5 Air từ OpenRouter. Hi vọng bài viết đủ chất lượng làm hài lòng các bạn. Mời bạn thưởng thức Newsletter #54.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="controlling-the-rollout-of-large-scale-monorepo-changes"&gt;&lt;a class="link" href="https://www.uber.com/en-IN/blog/controlling-the-rollout-of-large-scale-monorepo-changes/" target="_blank" rel="noopener"
&gt;Controlling the Rollout of Large-Scale Monorepo Changes&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Uber chia sẻ kinh nghiệm thực tế về việc kiểm soát việc triển khai các thay đổi lớn trong hệ thống monorepo quy mô lớn, một thách thức phức tạp mà nhiều công ty công nghệ đối mặt khi phát triển phần mềm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bối cảnh thách thức tại Uber&lt;/strong&gt;: Uber vận hành một trong những monorepo lớn nhất thế giới với hàng triệu file và hàng chục ngàn thư mục. Việc triển khai các thay đổi toàn diện như nâng cấp framework, di chuyển cơ sở dữ liệu, hoặc thay đổi kiến trúc hệ thống đòi hỏi một quy trình kiểm soát chặt chẽ để đảm bảo tính ổn định và giảm thiểu rủi ro.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược kiểm soát rollout&lt;/strong&gt;: Uber triển khai hệ thống &amp;ldquo;rollout controls&amp;rdquo; với nhiều lớp bảo vệ. Hệ thống này bao gồm việc chia nhỏ các thay đổi thành các phần nhỏ hơn, triển khai theo từng giai đoạn, và có khả năng rollback nhanh chóng khi phát hiện vấn đề. Các công cụ như feature flags và canary deployments được sử dụng rộng rãi để kiểm soát luồng traffic.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kiểm tra tự động và giám sát&lt;/strong&gt;: Hệ thống tự động hóa các kiểm tra chất lượng code, chạy test suite trên các môi trường staging, và giám sát chặt chẽ các chỉ số hiệu suất sau khi triển khai. Các cảnh báo sớm được thiết lập để phát hiện bất thường trong behavior của hệ thống, cho phép đội ngũ phản ứng kịp thời.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Học hỏi từ thực tế&lt;/strong&gt;: Uber chia sẻ nhiều bài học quý giá từ các lần triển khai thất bại thành công, bao gồm tầm quan trọng của việc có kế hoạch rollback chi tiết, tầm quan trọng của việc có các chỉ số đo lường rõ ràng, và sự cần thiết của việc giao tiếp liên tục giữa các team trong suốt quá trình rollout.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Monorepo quy mô lớn đòi hỏi chiến lược rollout có kiểm soát chặt chẽ&lt;/li&gt;
&lt;li&gt;Việc chia nhỏ thay đổi và triển khai từng giai đoạn giảm thiểu rủi ro&lt;/li&gt;
&lt;li&gt;Feature flags và canary deployments là công cụ quan trọng để kiểm soát traffic&lt;/li&gt;
&lt;li&gt;Giám sát và cảnh báo sớm giúp phát hiện và xử lý vấn đề kịp thời&lt;/li&gt;
&lt;li&gt;Kế hoạch rollback chi tiết là yếu tố sống còn cho các thay đổi lớn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="string-length"&gt;&lt;a class="link" href="https://hsivonen.fi/string-length/" target="_blank" rel="noopener"
&gt;String Length&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Henri Sivonen khám phá một chủ đề tưởng chừng đơn giản nhưng thực chất rất phức tạp: việc đo lường độ dài chuỗi ký tự trong các hệ thống máy tính, đặc biệt là trong ngữ cảnh web và Unicode.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề phức tạp đằng sau đơn giản&lt;/strong&gt;: Việc xác định &amp;ldquo;độ dài&amp;rdquo; của một chuỗi ký tự không đơn giản như đếm số ký tự hiển thị. Trong Unicode, một ký tự có thể được biểu diễn bằng nhiều code point (ví dụ: emoji với skin tone modifiers), và một code point có thể chiếm nhiều byte (ví dụ: ký tự tiếng Việt có dấu). Điều này tạo ra nhiều định nghĩa khác nhau về &amp;ldquo;độ dài&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các cách đo lường chuỗi&lt;/strong&gt;: Bài viết phân tích nhiều cách tiếp cận khác nhau: đếm số code point (code units), đếm số grapheme clusters (các ký tự hiển thị), đếm số byte, và đếm số column width (độ rộng khi hiển thị trên terminal). Mỗi cách có ứng dụng riêng: code units cho lập trình, grapheme clusters cho người dùng, column width cho giao diện dòng lệnh.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ứng dụng thực tế&lt;/strong&gt;: Trong phát triển web, việc hiểu rõ các cách đo lường này quan trọng cho việc validation form, truncation text, layout design, và performance optimization. Ví dụ: việc giới hạn tweet trong 280 ký tự thực chất là giới hạn theo số byte, không phải số ký tự hiển thị.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Công cụ và best practices&lt;/strong&gt;: Henri đề xuất các thư viện và phương pháp xử lý chuỗi an toàn trong nhiều ngôn ngữ lập trình khác nhau, nhấn mạnh tầm quan trọng của việc sử dụng các API Unicode-aware thay vì các phương pháp xử lý chuỗi đơn giản.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Độ dài chuỗi không có định nghĩa duy nhất mà phụ thuộc vào ngữ cảnh sử dụng&lt;/li&gt;
&lt;li&gt;Unicode làm cho việc đo lường độ dài trở nên phức tạp với nhiều code point cho một ký tự hiển thị&lt;/li&gt;
&lt;li&gt;Các hệ thống cần chọn cách đo lường phù hợp với mục đích sử dụng&lt;/li&gt;
&lt;li&gt;Việc hiểu Unicode là quan trọng để tránh bugs trong xử lý chuỗi&lt;/li&gt;
&lt;li&gt;Performance có thể bị ảnh hưởng bởi cách chọn thuật toán đo lường độ dài&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="an-illustrated-guide-to-oauth"&gt;&lt;a class="link" href="https://www.ducktyped.org/p/an-illustrated-guide-to-oauth/" target="_blank" rel="noopener"
&gt;An Illustrated Guide to OAuth&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết cung cấp một hướng dẫn trực quan và dễ hiểu về OAuth - giao thức ủy quyền quan trọng trong bảo mật web hiện đại, giúp các ứng dụng truy cập tài nguyên người dùng mà không cần lưu trữ thông tin xác thực trực tiếp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Khái niệm cốt lõi của OAuth&lt;/strong&gt;: OAuth không phải là giao thức xác thực (authentication) mà là giao thức ủy quyền (authorization). Nó cho phép người dùng cho phép ứng dụng thứ ba truy cập vào tài nguyên của họ trên một dịch vụ khác mà không cần chia sẻ mật khẩu trực tiếp. Ví dụ: đăng nhập bằng Google vào ứng dụng web khác.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các thành phần chính trong OAuth&lt;/strong&gt;: Hệ thống OAuth bao gồm Resource Owner (người dùng), Client (ứng dụng muốn truy cập), Authorization Server (dịch vụ cấp token), và Resource Server (nơi lưu trữ dữ liệu). Mỗi thành phần có vai trò riêng trong quy trình ủy quyền, tạo thành một chuỗi an toàn để bảo vệ thông tin người dùng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quy trình OAuth 2.0 tiêu chuẩn&lt;/strong&gt;: Bài viết minh họa từng bước trong quy trình: client redirect người dùng đến authorization server, người dùng đồng ý cấp quyền, authorization server trả về authorization code, client dùng code để exchange access token, và cuối cùng dùng token để truy cập resource server. Mỗi bước đều có cơ chế bảo mật riêng để ngăn chặn tấn công.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các loại grant flow khác nhau&lt;/strong&gt;: OAuth hỗ trợ nhiều loại flow tùy thuộc vào ngữ cảnh sử dụng: Authorization Code Flow cho ứng dụng web, Implicit Flow cho ứng dụng SPA, Client Credentials Flow cho ứng dụng backend, và Resource Owner Password Credentials Flow cho các ứng dụng đáng tin cậy. Mỗi flow có ưu điểm và nhược điểm riêng về bảo mật và trải nghiệm người dùng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bảo mật và best practices&lt;/strong&gt;: Bài viết nhấn mạnh tầm quan trọng của việc sử dụng HTTPS, bảo vệ client secrets, thiết lập proper scope, và implement PKCE cho các ứng dụng public. Các lỗ hổng phổ biến như open redirect, CSRF, và token leakage cũng được phân tích kèm theo giải pháp phòng tránh.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OAuth là giao thức ủy quyền, không phải xác thực, giúp bảo vệ thông tin người dùng&lt;/li&gt;
&lt;li&gt;Quy trình OAuth gồm nhiều thành phần phối hợp để tạo chuỗi an toàn&lt;/li&gt;
&lt;li&gt;Các loại grant flow khác nhau phù hợp với các loại ứng dụng khác nhau&lt;/li&gt;
&lt;li&gt;HTTPS và proper scope setting là yếu tố bảo mật bắt buộc&lt;/li&gt;
&lt;li&gt;PKCE nên được sử dụng cho các ứng dụng public để tăng cường bảo mật&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="professional-development-is-a-choice"&gt;&lt;a class="link" href="https://alexchesser.medium.com/professional-development-is-a-choice-e90fb8719259" target="_blank" rel="noopener"
&gt;Professional Development Is a Choice&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Alex Chesser khám phá một quan điểm quan trọng về phát triển nghề nghiệp: việc trở thành chuyên gia giỏi không phải là kết quả của may mắn hay hoàn cảnh, mà là một lựa thức ý thức và nỗ lực có chủ đích.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tư duy chủ động trong phát triển nghề nghiệp&lt;/strong&gt;: Alex lập luận rằng nhiều người có xu hướng chờ đờ cơ hội đến với mình thay vì chủ động tạo ra cơ hội. Sự khác biệt giữa những người thành công và những người không nằm ở khả năng bẩm sinh, mà ở thái độ chủ động trong việc tìm kiếm thử thách, học hỏi từ thất bại, và không ngừng cải thiện bản thân.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vai trò của sự kiên trì&lt;/strong&gt;: Bài viết nhấn mạnh tầm quan trọng của việc duy trì nỗ lực lâu dài. Thành công trong ngành công nghệ không đến từ một đêm, mà là kết quả của hàng ngàn giờ học tập, thực hành, và tinh thần không bỏ cuộc khi gặp khó khăn. Những người kiên trì thường đạt được kết quả vượt trội so với những người chỉ làm việc khi có động lực.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tìm kiếm thử thách có chủ đích&lt;/strong&gt;: Thay vì chỉ làm những công việc quen thuộc, Alex khuyên nên chủ động tìm kiếm những thử thách mới đòi hỏi kỹ năng cao hơn. Điều này có thể bao gồm việc nhận dự án phức tạp, học công nghệ mới, hoặc tham gia vào các hoạt động mở rộng tầm ảnh hưởng trong tổ chức.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Học hỏi từ thất bại&lt;/strong&gt;: Bài viết khuyến khích việc xem thất bại như cơ hội học tập thay vì điều cần tránh. Mỗi lần thất bại đều mang lại bài học quý giá về kỹ năng, quy trình, và cách tiếp cận. Những người thành công thường có khả năng phân tích thất bại một cách khách quan và rút ra bài học để cải thiện.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Xây dựng thói quen phát triển liên tục&lt;/strong&gt;: Alex đề xuất việc thiết lập các thói quen nhỏ nhưng nhất quán như đọc sách hàng ngày, tham gia cộng đồng kỹ thuật, viết blog, hoặc mentor người khác. Những thói quen này tạo ra hiệu ứng tích lũy lâu dài và giúp duy trì động lực phát triển.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phát triển nghề nghiệp thành công là kết quả của lựa thức chủ động, không phải may mắn&lt;/li&gt;
&lt;li&gt;Sự kiên trì lâu dài quan trọng hơn năng khiếu bẩm sinh&lt;/li&gt;
&lt;li&gt;Chủ động tìm kiếm thử thách giúp tăng tốc độ phát triển&lt;/li&gt;
&lt;li&gt;Thất bại là cơ hội học hỏi quý giá nếu biết phân tích&lt;/li&gt;
&lt;li&gt;Xây dựng thói quen nhỏ nhất quán tạo ra kết quả lớn lâu dài&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="database-cache"&gt;&lt;a class="link" href="https://avi.im/blag/2025/db-cache/" target="_blank" rel="noopener"
&gt;Database Cache&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Avi khám phá các khái niệm và thực tiễn quan trọng về database caching - một kỹ thuật tối ưu hóa hiệu suất quan trọng trong các hệ thống ứng dụng hiện đại, giúp giảm tải cho database và cải thiện thời gian phản hồi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Khái niệm cơ bản về caching&lt;/strong&gt;: Database caching hoạt động bằng cách lưu trữ các kết quả truy vấn hoặc dữ liệu thường xuyên được truy cập vào bộ nhớ nhanh (RAM) thay vì truy cập trực tiếp vào database. Điều này giúp giảm thời gian đọc dữ liệu từ hàng trăm mili giây xuống chỉ vài mili giây, cải thiện đáng kể trải nghiệm người dùng và giảm tải cho hệ thống database.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các chiến lược cache phổ biến&lt;/strong&gt;: Bài viết phân tích nhiều chiến lược cache khác nhau: Read-Through Cache (tự động điền cache khi đọc), Write-Through Cache (cập nhật cả cache và database khi ghi), Write-Behind Cache (cập nhật cache trước, database sau), và Cache-Aside (ứng dụng tự quản lý cache). Mỗi chiến lược có ưu điểm và nhược điểm riêng tùy thuộc vào yêu cầu về tính nhất quán và hiệu suất.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Xử lý cache invalidation&lt;/strong&gt;: Một trong những thách thức lớn nhất của caching là việc xác định khi nào dữ liệu trong cache đã lỗi thời. Bài viết thảo luận về các phương pháp invalidation khác nhau như time-based expiration, event-based invalidation, và write-through invalidation, cùng với các trade-off giữa tính nhất quán dữ liệu và hiệu suất.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cache hit ratio và performance monitoring&lt;/strong&gt;: Để đánh giá hiệu quả của hệ thống cache, cần theo dõi các chỉ số quan trọng như cache hit ratio (tỷ lệ truy cập thành công vào cache), latency (thời gian phản hồi), và memory usage. Các công cụ như Redis, Memcached, và các hệ thống cache phân tán được phân tích để giúp lựa chọn giải pháp phù hợp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Best practices và common pitfalls&lt;/strong&gt;: Bài viết chia sẻ nhiều bài học thực tế về cách thiết kế hệ thống cache hiệu quả, bao gồm việc chọn key naming convention phù hợp, thiết lập TTL hợp lý, tránh cache stampede (nhiều request cùng lúc khi cache miss), và xử lý các vấn đề về memory pressure trong môi trường production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Database caching giúp giảm thời gian truy cập dữ liệu từ hàng trăm mili giây xuống vài mili giây&lt;/li&gt;
&lt;li&gt;Các chiến lược cache khác nhau phù hợp với các yêu cầu về tính nhất quán và hiệu suất&lt;/li&gt;
&lt;li&gt;Cache invalidation là thách thức phức tạp đòi hỏi thiết kế cẩn thận&lt;/li&gt;
&lt;li&gt;Theo dõi cache hit ratio và các chỉ số performance là quan trọng để đánh giá hiệu quả&lt;/li&gt;
&lt;li&gt;Best practices bao gồm key naming convention hợp lý và thiết lập TTL phù hợp&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/f8993d4d-8879-4eeb-9635-3a5aa13816cc_2250x2624.png"
loading="lazy"
alt="A Detailed Guide to Content Delivery Networks"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/607358c5-2e0b-41fc-9cdd-a350e1faf144_3780x4096.jpeg"
loading="lazy"
alt="CI/CD Pipeline Explained"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/8b1bd4d5-a708-4793-a9e6-aa96db182f54_3000x3900.png"
loading="lazy"
alt="What are some of the most popular versioning strategies?"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/c34a8b8b-feff-4473-9eb1-dd399f5a81eb_2360x2664.jpeg"
loading="lazy"
alt="The Testing Pyramid"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Tổng kết thì mình thấy đợt thử nghiệm này cũng khá ổn. Có điều bài viết còn khá dài dòng và đôi chỗ còn sai sót từ ngữ tiếng Việt một chút. Với cái giá free thì quá được :))) Hẹn gặp lại các bạn trong các bài viết tới.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #53</title><link>https://miti99.com/post/2025/09/09/</link><pubDate>Tue, 09 Sep 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/09/09/</guid><description>&lt;p&gt;&lt;em&gt;Bài này mình thử nghiệm tổng hợp tất cả code agent rules trước đây về thành 1 file AGENTS.md duy nhất, sau đó trỏ CLAUDE.md đọc file này. Mời bạn thưởng thức Newsletter #53.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="anti-cheat-secure-boot--tpm"&gt;&lt;a class="link" href="https://andrewmoore.ca/blog/post/anticheat-secure-boot-tpm/" target="_blank" rel="noopener"
&gt;Anti-cheat, Secure Boot &amp;amp; TPM&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này khám phá mối quan hệ phức tạp giữa các hệ thống chống gian lận (anti-cheat), Secure Boot và Trusted Platform Module (TPM) trong ngành công nghiệp game hiện đại. Tác giả Andrew Moore phân tích cách các nhà phát triển game sử dụng những công nghệ bảo mật này để đảm bảo tính toàn vẹn của trò chơi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Secure Boot và TPM trong gaming&lt;/strong&gt;: Secure Boot đảm bảo rằng chỉ những phần mềm được ký số hợp lệ mới có thể chạy trong quá trình khởi động hệ thống, trong khi TPM cung cấp một môi trường tin cậy để lưu trữ các khóa mã hóa và thông tin nhạy cảm. Khi kết hợp với nhau, chúng tạo ra một &amp;ldquo;chain of trust&amp;rdquo; từ firmware đến ứng dụng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ứng dụng trong anti-cheat&lt;/strong&gt;: Các hệ thống anti-cheat hiện đại như Vanguard (Riot Games) và BattlEye tận dụng những tính năng này để xác minh tính toàn vẹn của hệ thống người chơi. Chúng có thể phát hiện việc sửa đổi kernel, rootkit và các phần mềm gian lận hoạt động ở cấp độ thấp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Secure Boot ngăn chặn việc tải các driver hoặc bootloader bị nhiễm độc&lt;/li&gt;
&lt;li&gt;TPM cung cấp khả năng xác thực phần cứng và lưu trữ an toàn&lt;/li&gt;
&lt;li&gt;Sự kết hợp của cả hai tạo ra hàng rào bảo vệ mạnh mẽ chống lại gian lận&lt;/li&gt;
&lt;li&gt;Công nghệ này đặt ra những thách thức mới cho cả người phát triển cheat và anti-cheat&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="left-to-right-programming"&gt;&lt;a class="link" href="https://graic.net/p/left-to-right-programming" target="_blank" rel="noopener"
&gt;Left to Right Programming&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này giới thiệu khái niệm &amp;ldquo;Left to Right Programming&amp;rdquo; - một triết lý thiết kế ngôn ngữ lập trình nhấn mạnh việc viết code theo cách tự nhiên từ trái sang phải, giúp code luôn hợp lệ và dễ hiểu trong quá trình phát triển.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nguyên tắc cốt lõi&lt;/strong&gt;: Tác giả lập luận rằng các ngôn ngữ lập trình và môi trường phát triển nên hỗ trợ việc viết code sao cho chương trình luôn hợp lệ và có thể hiểu được ở mỗi giai đoạn trong quá trình gõ. Điều này trái ngược với những cấu trúc phức tạp như list comprehension trong Python, nơi logic được &amp;ldquo;nhồi&amp;rdquo; vào một dòng duy nhất.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So sánh thực tế&lt;/strong&gt;: Bài viết đưa ra ví dụ minh họa sự khác biệt. Trong Python: &lt;code&gt;words_on_lines = [line.split() for line in text.splitlines()]&lt;/code&gt; so với Rust: &lt;code&gt;let words_on_lines = text.lines().map(|line| line.split_whitespace());&lt;/code&gt;. Cách tiếp cận của Rust cho phép developer xây dựng logic từng bước một cách tự nhiên.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tác động đến developer experience&lt;/strong&gt;: Phương pháp này cải thiện khả năng khám phá các method và function thông qua IDE, giảm độ phức tạp nhận thức khi đọc code, và tạo ra workflow phát triển mượt mà hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Code nên được viết theo cách tự nhiên từ trái sang phải&lt;/li&gt;
&lt;li&gt;Tránh những cấu trúc phức tạp làm giảm tính khám phá của code&lt;/li&gt;
&lt;li&gt;IDE và editor nên hỗ trợ tốt việc gợi ý method và function&lt;/li&gt;
&lt;li&gt;Ngôn ngữ như Rust và JavaScript thể hiện tốt nguyên tắc này hơn Python&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="big-o-notation"&gt;&lt;a class="link" href="https://samwho.dev/big-o/" target="_blank" rel="noopener"
&gt;Big O Notation&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Sam Who cung cấp một hướng dẫn trực quan và dễ hiểu về Big O notation - một khái niệm cơ bản trong khoa học máy tính để mô tả hiệu suất của thuật toán khi kích thước đầu vào tăng lên.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Khái niệm cốt lõi&lt;/strong&gt;: Big O notation mô tả mối quan hệ giữa đầu vào của hàm và thời gian thực thi, tập trung vào tốc độ tăng trưởng chứ không phải thời gian tuyệt đối. Điều này giúp so sánh hiệu suất thuật toán một cách khách quan, bất kể phần cứng hay ngôn ngữ lập trình.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các độ phức tạp chính&lt;/strong&gt;: Từ chậm nhất đến nhanh nhất gồm O(n²) - quadratic (như bubble sort), O(n) - linear (hiệu suất tỷ lệ với kích thước đầu vào), O(log n) - logarithmic (tăng rất chậm như binary search), và O(1) - constant (hiệu suất không đổi).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ví dụ thực tế&lt;/strong&gt;: Tác giả sử dụng các ví dụ sinh động như tính tổng số, thuật toán sắp xếp bubble sort và trò chơi đoán số để minh họa cách Big O hoạt động trong thực tế. Mỗi ví dụ được trình bày với visualization giúp người đọc dễ dàng hình dung.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược cải thiện hiệu suất&lt;/strong&gt;: Sử dụng cấu trúc dữ liệu phù hợp (như Set cho tìm kiếm nhanh), tránh vòng lặp lồng nhau tạo ra độ phức tạp quadratic, và cache kết quả trung gian để giảm tính toán dư thừa.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Big O mô tả cách hiệu suất thay đổi khi kích thước đầu vào tăng&lt;/li&gt;
&lt;li&gt;Tập trung vào tốc độ tăng trưởng, không phải thời gian tuyệt đối&lt;/li&gt;
&lt;li&gt;O(1) nhanh nhất, O(n²) chậm nhất trong các trường hợp phổ biến&lt;/li&gt;
&lt;li&gt;Lựa chọn thuật toán và cấu trúc dữ liệu ảnh hưởng lớn đến hiệu suất&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="personal-ai-evaluations-august-2025"&gt;&lt;a class="link" href="https://darkcoding.net/software/personal-ai-evals-aug-2025/" target="_blank" rel="noopener"
&gt;Personal AI Evaluations August 2025&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Dark Coding chia sẻ một nghiên cứu cá nhân thú vị về việc đánh giá các mô hình AI lớn (LLM) dựa trên 130 prompt thực tế từ lịch sử bash command của tác giả, mang đến cái nhìn thực tế về hiệu suất AI trong tháng 8/2025.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phương pháp đánh giá&lt;/strong&gt;: Tác giả thu thập 130 prompt thực tế từ bash history cá nhân, sử dụng Open Router để test nhiều mô hình AI khác nhau, và viết script Rust để chạy đánh giá &amp;ldquo;mù&amp;rdquo; nhằm tránh bias. Các lĩnh vực được đánh giá bao gồm lập trình, quản trị hệ thống, giải thích kỹ thuật và kiến thức tổng quát.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các mô hình được test&lt;/strong&gt;: Anthropic Claude Sonnet, DeepSeek models, Google Gemini 2.5 (Flash và Pro), Qwen3 models, và GLM 4.5. Kết quả cho thấy hầu hết các mô hình đều có hiệu suất tương tự nhau, với sự khác biệt chính nằm ở chi phí và độ trễ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phát hiện đáng chú ý&lt;/strong&gt;: Tác giả nhận ra rằng &amp;ldquo;tất cả các mô hình đều tốt&amp;rdquo;, các mô hình đóng (như Gemini Pro, Claude) không nhất thiết tốt hơn mô hình mở, và reasoning mode hiếm khi cải thiện kết quả (ngoại trừ việc viết thơ).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kết quả nổi bật&lt;/strong&gt;: Google Gemini 2.5 Flash nhanh nhất, Kimi K2, Qwen3 và DeepSeek rẻ nhất, trong khi DeepSeek và Qwen3 có tính nhất quán cao nhất.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hầu hết các mô hình AI hiện tại đều có hiệu suất tương đối tốt và tương tự nhau&lt;/li&gt;
&lt;li&gt;Chi phí và tốc độ phản hồi quan trọng hơn độ chính xác tuyệt đối&lt;/li&gt;
&lt;li&gt;Sử dụng đồng thời nhiều mô hình cho các loại query khác nhau là chiến lược tối ưu&lt;/li&gt;
&lt;li&gt;Mô hình mở có thể cạnh tranh tốt với mô hình thương mại đắt tiền&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-to-keep-services-running-during-failures"&gt;&lt;a class="link" href="https://newsletter.scalablethread.com/p/how-to-keep-services-running-during" target="_blank" rel="noopener"
&gt;How to Keep Services Running During Failures&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Scalable Thread cung cấp hướng dẫn chi tiết về các chiến lược graceful degradation - kỹ thuật giúp duy trì hoạt động của dịch vụ ngay cả khi một phần hệ thống gặp sự cố, đảm bảo trải nghiệm người dùng không bị gián đoạn hoàn toàn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các chiến lược chính&lt;/strong&gt;: Rate limiting kiểm soát lưu lượng trong tình huống tải cao, request coalescing gộp nhiều yêu cầu giống nhau thành một truy vấn duy nhất để giảm tải database, load shedding ưu tiên các yêu cầu quan trọng khi hệ thống bị stress, và jitter/retry ngăn chặn &amp;ldquo;thundering herd problem&amp;rdquo; khi dịch vụ phục hồi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Circuit breakers và timeout&lt;/strong&gt;: Circuit breaker tạm thời chặn yêu cầu đến các dịch vụ đang lỗi, cung cấp phản hồi lỗi ngay lập tức thay vì để client chờ đợi. Request timeout ngăn chặn việc cạn kiệt tài nguyên từ các dịch vụ phản hồi chậm, giải phóng tài nguyên hệ thống khi cần thiết.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Monitoring và cảnh báo&lt;/strong&gt;: Theo dõi các metrics quan trọng như error rate và latency giúp phát hiện vấn đề một cách chủ động, kích hoạt thông báo khi vượt ngưỡng nguy hiểm, cho phép can thiệp kịp thời trước khi vấn đề lan rộng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ví dụ thực tế&lt;/strong&gt;: Trong e-commerce, khi payment service không phản hồi, order service có thể sử dụng circuit breaker để ngăn chặn yêu cầu thanh toán, đồng thời vẫn cho phép người dùng browse sản phẩm và thêm vào giỏ hàng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Graceful degradation duy trì chức năng cốt lõi khi một phần hệ thống gặp sự cố&lt;/li&gt;
&lt;li&gt;Rate limiting và load shedding giúp ưu tiên traffic quan trọng nhất&lt;/li&gt;
&lt;li&gt;Circuit breaker ngăn chặn cascade failure trong microservices&lt;/li&gt;
&lt;li&gt;Monitoring chủ động giúp phát hiện và xử lý vấn đề sớm&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-was-apache-kafka-created"&gt;&lt;a class="link" href="https://bigdata.2minutestreaming.com/p/why-was-apache-kafka-created" target="_blank" rel="noopener"
&gt;Why Was Apache Kafka Created?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ 2 Minute Streaming khám phá bối cảnh lịch sử và những thách thức kỹ thuật cụ thể mà LinkedIn gặp phải vào năm 2012, dẫn đến việc tạo ra Apache Kafka - một trong những hệ thống streaming data phổ biến nhất hiện nay.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bối cảnh và vấn đề tại LinkedIn&lt;/strong&gt;: Vào năm 2012, LinkedIn đang vật lộn với hai pipeline dữ liệu riêng biệt - batch pipeline xử lý hàng giờ với XML messages qua HTTP server phục vụ cho Oracle và Hadoop, và real-time pipeline xử lý metrics, logs cho hệ thống monitoring Zenoss. Cả hai đều yêu cầu bảo trì thủ công nhiều, tạo ra backlog lớn và không có khả năng tích hợp dữ liệu giữa các hệ thống.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các thách thức kỹ thuật cốt lõi&lt;/strong&gt;: Hệ thống cũ của LinkedIn gặp vấn đề về schema parsing phức tạp, khó khăn trong việc evolution schema, độ trễ xử lý dữ liệu cao, và infrastructure dễ vỡ. Việc thiếu khả năng cross-system integration khiến dữ liệu bị phân mảnh và khó sử dụng hiệu quả.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Giải pháp từ Kafka&lt;/strong&gt;: LinkedIn phát triển Kafka như một &amp;ldquo;robust pipeline infrastructure&amp;rdquo; với kiến trúc phân tán mạnh mẽ, khả năng scale cao, xử lý dữ liệu real-time, tách biệt writer/reader, hỗ trợ Avro schema để đại diện dữ liệu tốt hơn, và khả năng phục vụ nhiều destination khác nhau.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tác động lịch sử&lt;/strong&gt;: Kafka không chỉ giải quyết vấn đề của LinkedIn mà còn trở thành standard industry cho streaming data, được sử dụng rộng rãi trong microservices architecture và real-time analytics.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kafka sinh ra từ nhu cầu thực tế của LinkedIn về tích hợp dữ liệu phức tạp&lt;/li&gt;
&lt;li&gt;Giải quyết vấn đề schema evolution và cross-system data integration&lt;/li&gt;
&lt;li&gt;Cung cấp kiến trúc phân tán có thể scale cho real-time processing&lt;/li&gt;
&lt;li&gt;Trở thành foundation cho nhiều hệ thống streaming hiện đại&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-we-vibe-code-at-a-faang"&gt;&lt;a class="link" href="https://www.reddit.com/r/vibecoding/comments/1myakhd/how_we_vibe_code_at_a_faang/" target="_blank" rel="noopener"
&gt;How We Vibe Code at a FAANG&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Thảo luận trên Reddit về cách các công ty FAANG áp dụng &amp;ldquo;vibe coding&amp;rdquo; - phương pháp phát triển phần mềm tận dụng AI để tăng tốc quá trình coding, được chia sẻ bởi các kỹ sư đang làm việc tại các công ty công nghệ hàng đầu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bối cảnh vibe coding tại FAANG&lt;/strong&gt;: Khái niệm này đang được thử nghiệm và áp dụng rộng rãi tại các công ty lớn như Google, Meta, Amazon, với focus vào việc sử dụng AI coding assistants để accelerate development workflow mà vẫn đảm bảo chất lượng code và architectural consistency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Workflow và tools&lt;/strong&gt;: Các kỹ sư FAANG thường kết hợp các AI coding tools như GitHub Copilot, internal AI assistants, và specialized prompting techniques. Điều quan trọng là họ vẫn duy trì code review process nghiêm ngặt và testing standards cao, sử dụng AI như một productivity multiplier chứ không phải replacement cho expertise.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Challenges và best practices&lt;/strong&gt;: Một số thách thức được đề cập bao gồm context management trong large codebases, maintaining coding standards consistency, và ensuring security compliance khi sử dụng AI-generated code. Best practices thường xoay quanh việc training AI models trên internal codebases và establishing clear guidelines cho AI usage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FAANG companies đang tích cực thử nghiệm vibe coding workflows&lt;/li&gt;
&lt;li&gt;AI được sử dụng để tăng productivity chứ không thay thế human judgment&lt;/li&gt;
&lt;li&gt;Code quality và security vẫn được duy trì thông qua rigorous review processes&lt;/li&gt;
&lt;li&gt;Context management và prompt engineering là kỹ năng quan trọng mới&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Đánh giá hiệu quả của AGENTS.md: Chưa được tốt lắm, còn chứa tiếng Anh nhiều. Mình sẽ cố gắng cải thiện thêm trong các bài viết tới. Hẹn gặp lại&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #52</title><link>https://miti99.com/post/2025/09/07/</link><pubDate>Sun, 07 Sep 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/09/07/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #52.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="traps-to-developers"&gt;&lt;a class="link" href="https://qouteall.fun/qouteall-blog/2025/Traps%20to%20Developers" target="_blank" rel="noopener"
&gt;Traps to Developers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này đưa ra một cái nhìn tổng quan về những &amp;ldquo;cạm bẫy&amp;rdquo; mà các lập trình viên có thể gặp phải trong quá trình phát triển phần mềm. Tác giả đã tổng hợp rất nhiều tình huống phức tạp và không trực quan có thể dẫn đến lỗi trong code.&lt;/p&gt;
&lt;p&gt;Bài viết được chia thành nhiều chủ đề chính:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HTML/CSS và giao diện web&lt;/strong&gt;: Các hành vi phức tạp trong việc hiển thị, xử lý layout, stacking context và việc định vị các phần tử có thể gây ra những kết quả bất ngờ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unicode và xử lý văn bản&lt;/strong&gt;: Những thách thức trong việc mã hóa ký tự, sự khác biệt trong cách xử lý chuỗi giữa các ngôn ngữ lập trình, và vấn đề chuẩn hóa ký tự.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Số thực dấu phẩy động&lt;/strong&gt;: Hạn chế về độ chính xác, các trường hợp đặc biệt như NaN và infinity, cũng như sự khác biệt trong tính toán phụ thuộc vào phần cứng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lập trình đồng thời và đồng bộ hóa&lt;/strong&gt;: Race conditions, vấn đề thread safety và sự phức tạp của các thao tác atomic.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cạm bẫy theo từng ngôn ngữ&lt;/strong&gt;: Java với việc so sánh đối tượng, Golang với quản lý bộ nhớ slice, C/C++ với các hành vi không xác định, Python với các vấn đề về tham số và thụt lề.&lt;/p&gt;
&lt;p&gt;Đây là một tài liệu tham khảo rất hữu ích giúp các lập trình viên nhận biết và tránh những lỗi phổ biến trong quá trình phát triển phần mềm.&lt;/p&gt;
&lt;h2 id="active-record-vs-repository-pattern"&gt;&lt;a class="link" href="https://javabulletin.substack.com/p/active-record-vs-repository-pattern" target="_blank" rel="noopener"
&gt;Active Record vs. Repository Pattern&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này so sánh hai mẫu thiết kế truy cập dữ liệu phổ biến trong các ứng dụng Java: Active Record Pattern và Repository Pattern.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Active Record Pattern&lt;/strong&gt; cho phép các đối tượng chịu trách nhiệm cho cả dữ liệu và các thao tác cơ sở dữ liệu của chính chúng. Ưu điểm của mô hình này là dễ sử dụng cho các thao tác CRUD cơ bản, phát triển nhanh hơn cho các ứng dụng đơn giản và tuân theo nguyên tắc &amp;ldquo;Quy ước thay vì cấu hình&amp;rdquo;. Tuy nhiên, nó cũng có nhược điểm là tạo ra sự liên kết chặt chẽ giữa mô hình và lược đồ cơ sở dữ liệu, vi phạm nguyên tắc Single Responsibility và ít linh hoạt cho các ứng dụng phức tạp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Repository Pattern&lt;/strong&gt; tách biệt logic truy cập dữ liệu khỏi logic nghiệp vụ thông qua việc sử dụng interface để truy cập các đối tượng domain. Mô hình này có ưu điểm là phân tách mối quan tâm tốt hơn, cải thiện khả năng kiểm thử và linh hoạt hơn trong việc thay đổi nguồn dữ liệu. Nhược điểm là tăng độ phức tạp, phát triển ban đầu chậm hơn và thêm một lớp trừu tượng.&lt;/p&gt;
&lt;p&gt;Khuyến nghị từ tác giả là sử dụng Active Record cho các ứng dụng đơn giản với logic đơn giản, trong khi Repository Pattern phù hợp hơn cho các ứng dụng phức tạp yêu cầu khả năng bảo trì và mở rộng.&lt;/p&gt;
&lt;h2 id="threadsleep0-is-not-for-free"&gt;&lt;a class="link" href="https://mlangc.github.io/java/performance/2025/08/14/thread-sleep0-is-not-for-free.html" target="_blank" rel="noopener"
&gt;Thread.sleep(0) is not for free&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích một khía cạnh hiệu suất thú vị trong Java mà nhiều lập trình viên có thể bỏ qua: việc gọi &lt;code&gt;Thread.sleep(0)&lt;/code&gt; không hề &amp;ldquo;miễn phí&amp;rdquo; như ta có thể nghĩ.&lt;/p&gt;
&lt;p&gt;Tác giả chỉ ra rằng mặc dù có vẻ như &lt;code&gt;Thread.sleep(0)&lt;/code&gt; không làm gì cả, nhưng thực tế nó vẫn gọi đến một phương thức native thực hiện thao tác yield thread. Trên hệ điều hành Linux, thao tác này sử dụng &lt;code&gt;sched_yield()&lt;/code&gt; có thể gây ra những lần chuyển đổi ngữ cảnh không cần thiết.&lt;/p&gt;
&lt;p&gt;Các thử nghiệm hiệu suất cho thấy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Việc gọi &lt;code&gt;Thread.sleep(0)&lt;/code&gt; có chi phí tính toán đáng kể&lt;/li&gt;
&lt;li&gt;Hiệu suất giảm mạnh khi CPU tải cao, đặc biệt với nhiều luồng chạy đồng thời&lt;/li&gt;
&lt;li&gt;Benchmark của tác giả cho thấy việc thêm &lt;code&gt;Thread.sleep(0)&lt;/code&gt; có thể giảm đáng kể throughput của hệ thống&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tác giả khuyên rằng thay vì sử dụng pattern như:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;allGood&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;waitShorty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Nên sử dụng:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;allGood&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;waitShortly&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Đây là một lời nhắc nhở quan trọng về việc hiểu rõ chi phí của các thao tác tưởng chừng như đơn giản trong lập trình Java.&lt;/p&gt;
&lt;h2 id="why-do-video-games-use-kernel-mode-anti-cheats"&gt;&lt;a class="link" href="https://vx-api.gitbook.io/vx-api/my-projects/why-do-video-games-use-kernel-mode-anti-cheats" target="_blank" rel="noopener"
&gt;Why do video games use kernel-mode anti-cheats?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này giải thích lý do tại sao các trò chơi video sử dụng phần mềm chống gian lận ở chế độ kernel và cách thức hoạt động của chúng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mục đích chính&lt;/strong&gt;: Phần mềm chống gian lận chế độ kernel được thiết kế để phát hiện và ngăn chặn việc gian lận trong các trò chơi video một cách hiệu quả hơn so với các giải pháp chạy ở chế độ người dùng thông thường.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cách thức hoạt động&lt;/strong&gt;: Các phần mềm này hoạt động trong không gian kernel - nơi quản lý tương tác giữa phần mềm và phần cứng. Chúng sử dụng các kỹ thuật như &amp;ldquo;phân tích tĩnh&amp;rdquo; và &amp;ldquo;phân tích hành vi&amp;rdquo; để nhận diện hoạt động gian lận. Thông qua các system call, chúng có thể nhận thông báo về việc tạo tiến trình và kiểm tra các phần mềm gian lận tiềm ẩn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề bảo mật&lt;/strong&gt;: Microsoft có quy định nghiêm ngặt về Driver Signature Enforcement, nghĩa là tất cả phần mềm chế độ kernel phải được Microsoft chứng nhận và phê duyệt. Điều này khiến việc lạm dụng các phần mềm này trở nên khó khăn hơn nhiều so với phần mềm chế độ người dùng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tranh cãi&lt;/strong&gt;: Một số người dùng lo ngại về tính xâm phạm của phần mềm chế độ kernel. Tuy nhiên, tác giả cho rằng những lo ngại này phần lớn dựa trên hiểu biết sai lầm về khả năng kỹ thuật thực tế của chúng. Bài viết nhấn mạnh rằng mục tiêu chính là đảm bảo tính toàn vẹn của trò chơi chứ không phải thu thập dữ liệu.&lt;/p&gt;
&lt;h2 id="why-llms-can"&gt;&lt;a class="link" href="https://zed.dev/blog/why-llms-cant-build-software" target="_blank" rel="noopener"
&gt;Why LLMs Can&amp;rsquo;t Really Build Software&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Conrad Irwin (Zed) đưa ra quan điểm thú vị về những hạn chế cơ bản của các mô hình ngôn ngữ lớn (LLM) trong việc xây dựng phần mềm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vòng lặp phát triển phần mềm&lt;/strong&gt;: Các kỹ sư phần mềm hiệu quả thường thực hiện liên tục các bước: xây dựng mô hình tư duy về yêu cầu, viết mã, kiểm chứng code thực sự làm gì, và nhận diện cũng như cập nhật những khác biệt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hạn chế của LLM&lt;/strong&gt;: Tác giả cho rằng LLM không thể duy trì các mô hình tư duy rõ ràng, thường xuyên &amp;ldquo;bối rối vô tận&amp;rdquo;, giả định rằng mã hoạt động mà không kiểm chứng đúng cách, gặp khó khăn khi test thất bại, và có xu hướng xóa và bắt đầu lại thay vì debug.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm yếu cụ thể&lt;/strong&gt;: LLM gặp vấn đề với việc bỏ qua ngữ cảnh, có bias mạnh về thông tin gần đây, và xu hướng tưởng tượng ra các chi tiết không có thật.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kết luận của tác giả&lt;/strong&gt;: LLM là công cụ hữu ích để tạo mã và tổng hợp yêu cầu, nhưng không thể độc lập xây dựng phần mềm phức tạp. Con người vẫn đóng vai trò thiết yếu trong việc đảm bảo yêu cầu rõ ràng và mã hoạt động chính xác.&lt;/p&gt;
&lt;p&gt;Đây là một góc nhìn cân bằng về vai trò của AI trong phát triển phần mềm - hữu ích nhưng không thể thay thế hoàn toàn con người.&lt;/p&gt;
&lt;h2 id="the-java-type-system-is-broken"&gt;&lt;a class="link" href="https://wouter.coekaerts.be/2018/java-type-system-broken" target="_blank" rel="noopener"
&gt;The Java Type System is Broken&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Wouter Coekaerts đi sâu vào những lỗ hổng kỹ thuật trong hệ thống kiểu của Java, chỉ ra cách một số cấu trúc ngôn ngữ có thể dẫn đến lỗi liên quan đến kiểu dữ liệu và &amp;ldquo;heap pollution&amp;rdquo; - tình huống mà nội dung của kiểu tham số không khớp với kiểu được khai báo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề với Lambda Expressions&lt;/strong&gt;: Lambda có thể phá vỡ tính an toàn kiểu bằng cách cho phép thực thi nhiều lần các kiểu capture. Tác giả đưa ra ví dụ về cách một thao tác stream có thể di chuyển sai các phần tử giữa những danh sách có kiểu khác nhau.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề Local Inner Classes&lt;/strong&gt;: Các phương thức generic với local inner classes có thể tạo ra vấn đề về phạm vi kiểu. Điều này cho thấy các tình huống mà thông tin kiểu có thể bị thao tác, dẫn đến ClassCastException.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm yếu trong kiểm tra Type Variable Bound&lt;/strong&gt;: Việc áp dụng không nhất quán capture conversion trong type variable bounds cho phép định nghĩa các hệ thống phân cấp kiểu không phù hợp, tạo điều kiện cho các thao tác không an toàn về kiểu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các vấn đề khác&lt;/strong&gt;: Unboxing trong lambda có thể gây ra type casting bất ngờ, và TreeSet implementation có những lỗ hổng bẩm sinh về tính an toàn kiểu.&lt;/p&gt;
&lt;p&gt;Tác giả lập luận rằng trong khi một số lỗ hổng trong hệ thống kiểu là cố ý (để tương thích ngược), thì những lỗ hổng khác là tình cờ. Những lỗ hổng này có thể dẫn đến lỗi runtime mà vượt qua được kiểm tra kiểu tại compile-time - một vấn đề đáng quan tâm cho các lập trình viên Java.&lt;/p&gt;
&lt;h2 id="the-pragmatic-engineer-2025-survey-what"&gt;&lt;a class="link" href="https://newsletter.pragmaticengineer.com/p/the-pragmatic-engineer-2025-survey" target="_blank" rel="noopener"
&gt;The Pragmatic Engineer 2025 Survey: What&amp;rsquo;s in your tech stack? Part 1&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Khảo sát từ The Pragmatic Engineer cung cấp cái nhìn tổng quan về các công cụ và xu hướng công nghệ trong ngành phát triển phần mềm năm 2025 qua góc nhìn của gần 3,000 kỹ sư phần mềm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phương pháp khảo sát&lt;/strong&gt;: Được thực hiện vào tháng 4 và 5 năm 2025 với 2,997 phản hồi hợp lệ từ các chuyên gia công nghệ, chủ yếu là kỹ sư phần mềm có 5-20 năm kinh nghiệm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Công cụ AI&lt;/strong&gt;: 85% người tham gia sử dụng ít nhất một công cụ AI. Các công cụ phổ biến nhất bao gồm GitHub Copilot (dẫn đầu), Cursor (đang tăng trưởng nhanh), Claude và ChatGPT.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ngôn ngữ lập trình&lt;/strong&gt;: TypeScript, Python và Swift là những ngôn ngữ được sử dụng nhiều nhất, trong khi Rust, Go và Ruby on Rails là những ngôn ngữ được yêu thích nhất.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Công cụ được yêu thích và ghét nhất&lt;/strong&gt;: VS Code, các sản phẩm JetBrains và Cursor là những công cụ được yêu thích nhất. JIRA là công cụ bị ghét nhiều nhất một cách áp đảo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cơ sở hạ tầng&lt;/strong&gt;: GitHub dẫn đầu về version control, AWS vẫn là cloud provider chủ đạo, và GitHub Actions là công cụ CI/CD phổ biến nhất.&lt;/p&gt;
&lt;p&gt;Khảo sát chỉ ra sự đổi mới nhanh chóng trong các công cụ phát triển AI, sự thay đổi chậm hơn trong các danh mục công nghệ đã thiết lập, và việc các lập trình viên ngày càng sẵn sàng thử nghiệm các công cụ mới.&lt;/p&gt;
&lt;h2 id="the-pragmatic-engineer-2025-survey-what-1"&gt;&lt;a class="link" href="https://newsletter.pragmaticengineer.com/p/the-pragmatic-engineer-2025-survey-part-2" target="_blank" rel="noopener"
&gt;The Pragmatic Engineer 2025 Survey: What&amp;rsquo;s in your tech stack? Part 2&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Phần 2 của khảo sát tập trung vào các công cụ và cơ sở hạ tầng mà kỹ sư phần mềm sử dụng hàng ngày, tiết lộ những xu hướng thú vị trong lựa chọn công nghệ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quản lý dự án&lt;/strong&gt;: JIRA vẫn dẫn đầu thị trường mặc dù bị &amp;ldquo;ghét&amp;rdquo; nhiều, Linear đang trở thành đối thủ cạnh tranh mạnh mẽ đặc biệt tại các công ty nhỏ, trong khi Azure DevOps bất ngờ phổ biến tại các tập đoàn lớn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Công cụ giao tiếp và cộng tác&lt;/strong&gt;: Slack thống trị nền tảng chat, Microsoft Teams dẫn đầu về video call, Confluence là công cụ tài liệu được sử dụng nhiều nhất, và Figma được ưa chuộng áp đảo cho thiết kế cộng tác.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cơ sở dữ liệu&lt;/strong&gt;: PostgreSQL là cơ sở dữ liệu được sử dụng rộng rãi nhất với danh sách &amp;ldquo;đuôi dài&amp;rdquo; các giải pháp khác. Vector database vẫn chưa thu hút được nhiều sự quan tâm như kỳ vọng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cơ sở hạ tầng backend&lt;/strong&gt;: Docker, Kubernetes và Terraform được sử dụng rộng rãi. Các dịch vụ quản lý của AWS rất phổ biến, trong khi việc áp dụng các fork của các dự án mã nguồn mở (như OpenSearch) có tỷ lệ hỗn hợp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quan sát đáng chú ý&lt;/strong&gt;: Các công cụ Microsoft thống trị nhiều danh mục, công cụ quản lý dự án được đề cập thường xuyên như IDE, và PostgreSQL vẫn là lựa chọn cơ sở dữ liệu thực dụng mặc định.&lt;/p&gt;
&lt;p&gt;Khảo sát này cung cấp cái nhìn sâu sắc về sở thích công nghệ hiện tại và xu hướng từ khoảng 3,000 kỹ sư phần mềm.&lt;/p&gt;
&lt;h2 id="how-to-vibe-code-as-a-senior-engineer"&gt;&lt;a class="link" href="https://blog.alexmaccaw.com/how-to-vibe-code-as-a-senior-engineer/" target="_blank" rel="noopener"
&gt;How to Vibe Code as a Senior Engineer&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Alex MacCaw giới thiệu khái niệm &amp;ldquo;vibe coding&amp;rdquo; - một phương pháp phát triển phần mềm mới tận dụng các mô hình AI để tăng tốc đáng kể quá trình viết mã.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Định nghĩa cốt lõi&lt;/strong&gt;: Vibe coding là việc sử dụng các mô hình AI tiên tiến để thực hiện phần lớn công việc viết mã, trong khi kỹ sư senior cung cấp hướng dẫn, kiến trúc và định hướng chiến lược. Phương pháp này có thể biến những dự án kéo dài hàng tuần thành chỉ vài giờ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Yêu cầu thiết yếu&lt;/strong&gt;: Để vibe coding hiệu quả cần có scaffold dự án mạnh mẽ, các quy tắc viết mã được định nghĩa rõ ràng, quản lý ngữ cảnh chính xác, sử dụng các mô hình AI hàng đầu (Claude Opus 4, Gemini 2.5 Pro), và editor mã thông minh (khuyến nghị Cursor).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược prompt engineering&lt;/strong&gt;: Luôn bắt đầu với kế hoạch chi tiết, cực kỳ cụ thể về kết quả mong muốn, cung cấp ví dụ và ngữ cảnh rõ ràng, sử dụng các ràng buộc rõ ràng, và duy trì phạm vi dự án chặt chẽ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hạn chế chính của AI coding&lt;/strong&gt;: Quản lý ngữ cảnh tự động kém, xử lý kiểu TypeScript yếu, thiếu &amp;ldquo;thẩm mỹ&amp;rdquo; kiến trúc, và xu hướng tưởng tượng ra hoặc lệch khỏi mục tiêu dự định.&lt;/p&gt;
&lt;p&gt;Tác giả nhấn mạnh đây có thể là &amp;ldquo;màn biểu diễn cuối cùng&amp;rdquo; của việc viết mã được hướng dẫn bởi con người trước khi AI có thể trở nên hoàn toàn tự động, khuyến khích các kỹ sư nắm bắt và thành thạo phương pháp mới này.&lt;/p&gt;
&lt;h2 id="why-do-software-developers-love-complexity"&gt;&lt;a class="link" href="https://kyrylo.org/software/2025/08/21/why-do-software-developers-love-complexity.html" target="_blank" rel="noopener"
&gt;Why do software developers love complexity?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Kyrylo khám phá lý do tại sao các lập trình viên thường bị hấp dẫn bởi những giải pháp phức tạp mặc dù nguyên tắc &amp;ldquo;Keep It Simple, Stupid&amp;rdquo; (KISS) được khuyến khích rộng rãi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các yếu tố tâm lý và marketing&lt;/strong&gt;: Độ phức tạp thường được coi là dấu hiệu của chuyên môn và tính độc quyền. Marketing tạo ra giá trị nhân tạo thông qua các giải pháp phức tạp, biến độ phức tạp thành &amp;ldquo;biểu tượng địa vị hơn là một nhu cầu thực sự&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lý do sâu xa khiến lập trình viên ưa chuộng độ phức tạp&lt;/strong&gt;: Cám dỗ giải quyết vấn đề một cách sáng tạo, kế thừa từ các hệ thống cũ và nợ kỹ thuật, động lực cộng tác trong nhóm, và áp lực phải đổi mới cũng như tạo sự khác biệt.&lt;/p&gt;
&lt;p&gt;Tác giả sử dụng ví dụ ẩn dụ về việc xây dựng kim tự tháp để minh họa cách các lập trình viên thường tạo ra những &amp;ldquo;lớp&amp;rdquo; độ phức tạp không cần thiết.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Những hiểu biết quan trọng&lt;/strong&gt;: Sự đơn giản thường hiệu quả hơn về lâu dài, độ phức tạp có thể che giấu &amp;ldquo;sự thiếu bản chất&amp;rdquo;, và các lập trình viên nên tập trung vào việc giải quyết các vấn đề thực sự của người dùng.&lt;/p&gt;
&lt;p&gt;Câu nói đáng chú ý: &amp;ldquo;Độ phức tạp hét lên &amp;lsquo;Nhìn tôi đây!&amp;rsquo;, trong khi sự đơn giản thì thầm &amp;lsquo;Bạn có chú ý không?&amp;rsquo;&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Bài viết kết thúc bằng lời kêu gọi xây dựng &amp;ldquo;kim tự tháp có mục đích&amp;rdquo; - tạo ra những giải pháp có chủ ý, nền tảng và thực sự có giá trị, thay vì phức tạp chỉ vì muốn phức tạp.&lt;/p&gt;
&lt;h2 id="the-important-things-in-life"&gt;&lt;a class="link" href="https://hamvocke.com/blog/important-things/" target="_blank" rel="noopener"
&gt;The Important Things in Life&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Ham Vocke là một tấm gương phản chiếu về những điều thực sự quan trọng trong cuộc sống, vượt ra ngoài những thách thức nghề nghiệp hàng ngày.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nguyên tắc cốt lõi&lt;/strong&gt;: Ưu tiên các mối quan hệ và trải nghiệm cá nhân hơn những thách thức nghề nghiệp, trân trọng những khoảnh khắc bên bạn bè và gia đình, tạo ra những kỷ niệm có ý nghĩa ngoài công việc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Những trải nghiệm được nhấn mạnh&lt;/strong&gt;: Tác giả chia sẻ về việc tham dự đám cưới và lễ kỷ niệm của bạn bè, tham gia các lễ hội âm nhạc, tổ chức tiệc nướng, thăm gia đình, hỗ trợ cha mẹ khi họ chuẩn bị nghỉ hưu, và du lịch cùng vợ/chồng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lời khuyên thực tiễn&lt;/strong&gt;: Bài viết kết thúc bằng một khuyến nghị mạnh mẽ và súc tích: &amp;ldquo;Ôm bạn bè, gọi điện cho gia đình, ra ngoài, tạo kỷ niệm.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thông điệp trung tâm&lt;/strong&gt;: Mặc dù công việc có thể đầy thách thức và áp lực, những khía cạnh quan trọng nhất của cuộc sống chính là những kết nối cá nhân, trải nghiệm được chia sẻ, và những khoảnh khắc vui vẻ bên những người thân yêu.&lt;/p&gt;
&lt;p&gt;Đây là một lời nhắc nhở quan trọng cho những ai làm trong ngành công nghệ về việc cân bằng giữa công việc và cuộc sống, đặt con người và mối quan hệ lên hàng đầu.&lt;/p&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/4bf62d5c-e538-4fba-8d4f-aa00d0bd064a_3000x3900.png"
loading="lazy"
alt="How Does SSO Work?"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/e249b1bd-134e-4242-ac16-1d50daf804d3_3000x3900.png"
loading="lazy"
alt="Best Practices in API Design"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/82b8257a-93c3-4861-b211-88d57b12bc93_2250x2624.png"
loading="lazy"
alt="Top Strategies For Reliability and Fault Tolerance"
&gt;&lt;/p&gt;
&lt;h2 id="bonus-một-vài-video-thú-vị"&gt;Bonus: Một vài video thú vị
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=Dc3qOA9WOnE" target="_blank" rel="noopener"
&gt;Vibes won&amp;rsquo;t cut it — Chris Kelly, Augment Code&lt;/a&gt;
&lt;a class="link" href="https://www.youtube.com/watch?v=Z3fwe6AAgaM" target="_blank" rel="noopener"
&gt;these coding blogs will make you a better programmer&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="bonus-một-vài-repository-thú-vị"&gt;Bonus: Một vài repository thú vị
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://github.com/bansalankit92/java-spring-fullstack-interview-question-answers" target="_blank" rel="noopener"
&gt;Computer science foundation/ Interview preparation/ Junior to Senior Developer&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="bonus-một-vài-sách-thú-vị"&gt;Bonus: Một vài sách thú vị
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://enos.itcollege.ee/~jpoial/allalaadimised/reading/Java-Interview-Questions.pdf" target="_blank" rel="noopener"
&gt;Java interview questions and answers - Boosting your java career&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/shannonasmith/Java_books/blob/main/Java%20Puzzlers%20-%20Traps%2C%20Pitfalls%2C%20and%20Corner%20Cases%20%282005%29.pdf" target="_blank" rel="noopener"
&gt;Java Puzzlers - Traps, Pitfalls, and Corner Cases&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Newsletter #51</title><link>https://miti99.com/post/2025/08/31/</link><pubDate>Sun, 31 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/31/</guid><description>&lt;p&gt;&lt;em&gt;Chào các bạn, nay lại đến chu kỳ lười biếng của mình rồi (với thật ra thì dạo trước cày kha khá rồi nên nội dung còn lại cũng không nhiều), nên mình sẽ chuyển sang viết khoảng 1-2 bài/tuần tuỳ cảm hứng. Với tuần rồi mình cũng có được idol ✨🌙 của mình giới thiệu cuốn sách &lt;a class="link" href="https://nhanam.vn/tim-minh-trong-the-gioi-hau-tuoi-tho-nha-nam" target="_blank" rel="noopener"
&gt;Tìm mình trong thế giới hậu tuổi thơ&lt;/a&gt;, cũng khá hay, nếu hứng thú các bạn có thể tìm đọc. Còn giờ thì mời bạn thưởng thức Newsletter #51.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="p-fast-trie-lexically-ordered-hash-map"&gt;&lt;a class="link" href="https://dotat.at/@/2025-08-04-p-fast-trie.html" target="_blank" rel="noopener"
&gt;p-fast trie: lexically ordered hash map&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả Tony Finch giới thiệu một cấu trúc dữ liệu thử nghiệm mới gọi là &amp;ldquo;p-fast trie&amp;rdquo;, được thiết kế như một lựa chọn thay thế tiềm năng cho qp-trie. Đây là một kiểu hash map có thứ tự theo từ điển, mang đến những ưu điểm thú vị trong việc tìm kiếm và truy xuất dữ liệu.&lt;/p&gt;
&lt;p&gt;Cấu trúc p-fast trie sử dụng hash map được tổ chức thành nhiều tầng, mỗi tầng tương ứng với một tiền tố của khóa. Các đối tượng lá tạo thành danh sách liên kết vòng, và sử dụng bitmap cùng mảng nén popcount để điều hướng hiệu quả. Điểm đặc biệt của thiết kế này là khả năng tìm kiếm chính xác với độ phức tạp O(1), trong khi tìm kiếm phần tử trước/sau có độ phức tạp O(log k), với k là độ dài khóa.&lt;/p&gt;
&lt;p&gt;Mặc dù p-fast trie có những ưu điểm như tìm kiếm chính xác nhanh và tìm kiếm phần tử trước/sau đơn giản hơn so với qp-trie, nhưng cũng tồn tại những hạn chế về việc sử dụng bộ nhớ cao hơn và khả năng cache-friendly kém hơn. Tác giả thẳng thắn thừa nhận đây chỉ là một khái niệm thử nghiệm và vẫn chưa rõ hiệu quả thực tế của nó, đồng thời mời gọi cộng đồng nghiên cứu và phản hồi thêm.&lt;/p&gt;
&lt;p&gt;Bài viết này rất phù hợp cho những ai quan tâm đến các cấu trúc dữ liệu tiên tiến và muốn hiểu sâu hơn về các phương pháp tối ưu hóa trong lĩnh vực khoa học máy tính.&lt;/p&gt;
&lt;h2 id="big-o-vs-hardware-better-complexity--better-performance"&gt;&lt;a class="link" href="https://blog.codingconfessions.com/p/big-o-vs-hardware" target="_blank" rel="noopener"
&gt;Big O vs Hardware: Better Complexity ≠ Better Performance&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này khám phá một khái niệm quan trọng mà nhiều lập trình viên thường bỏ qua: độ phức tạp thuật toán tốt hơn không luôn đồng nghĩa với hiệu suất thực tế tốt hơn. Tác giả minh họa điều này thông qua việc phân tích chi tiết ba thuật toán tìm ước số chung lớn nhất (GCD) khác nhau.&lt;/p&gt;
&lt;p&gt;Hiệu suất thực tế phụ thuộc vào hai yếu tố phần cứng chính: số lượng lệnh và số lệnh thực hiện trên mỗi chu kỳ (IPC). Bài viết so sánh thuật toán Euclid dựa trên phép trừ với độ phức tạp O(max(a,b)), thuật toán Euclid dựa trên phép chia dư với O(log(max(a,b))), và thuật toán nhị phân Stein được tối ưu hóa cho phần cứng.&lt;/p&gt;
&lt;p&gt;Điểm mấu chốt của bài viết là &amp;ldquo;Định luật Sắt về hiệu suất&amp;rdquo;: hiệu suất thực tế không chỉ phụ thuộc vào độ phức tạp lý thuyết mà còn phụ thuộc vào cách mã nguồn tương tác với đặc tính phần cứng cụ thể. Số lượng lệnh ít hơn không đảm bảo thực thi nhanh hơn, và các thuật toán thân thiện với phần cứng có thể vượt trội hơn những thuật toán hiệu quả hơn về mặt lý thuyết.&lt;/p&gt;
&lt;p&gt;Bài viết khuyến nghị các lập trình viên nên xem xét đặc tính phần cứng khi thiết kế thuật toán, đo đạc hiệu suất với các kích thước đầu vào khác nhau, và tối ưu hóa cho cả độ phức tạp lý thuyết lẫn hiệu quả phần cứng.&lt;/p&gt;
&lt;h2 id="claude-code-is-all-you-need"&gt;&lt;a class="link" href="https://dwyer.co.za/static/claude-code-is-all-you-need.html" target="_blank" rel="noopener"
&gt;Claude Code Is All You Need&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này giới thiệu về Claude Code - một công cụ lập trình và phát triển ứng dụng được hỗ trợ bởi các mô hình AI Claude của Anthropic. Tác giả khám phá khái niệm &amp;ldquo;vibe coding&amp;rdquo; - việc tạo ra phần mềm thông qua các tương tác hội thoại với AI, cho thấy Claude Code có khả năng tạo ra các ứng dụng hoàn chỉnh chỉ với đầu vào tối thiểu từ con người.&lt;/p&gt;
&lt;p&gt;Claude Code thể hiện khả năng ấn tượng trong việc xây dựng các ứng dụng CRUD hoàn chỉnh chỉ với một câu lệnh, thiết lập hạ tầng sản xuất, di chuyển các dự án hiện có, và thực hiện các tác vụ quản trị. Tác giả đã thử nghiệm với nhiều dự án thực tế như SmartSplit (bản sao SplitWise), trình xây dựng startup tự động, plugin xếp hạng bình luận HackerNews, và ứng dụng xử lý sao kê ngân hàng.&lt;/p&gt;
&lt;p&gt;Để đạt được kết quả tốt nhất với Claude Code, tác giả khuyến nghị cung cấp đầu vào chi tiết và ngữ cảnh phong phú, sẵn sàng lặp lại và hướng dẫn AI, duy trì sự giám sát của con người đặc biệt với các hệ thống quan trọng, và hiểu rõ khả năng cũng như hạn chế của AI.&lt;/p&gt;
&lt;p&gt;Mặc dù Claude Code đặc biệt mạnh trong PHP và các ứng dụng web đơn giản, rất hữu ích cho việc tạo nguyên mẫu nhanh và khởi tạo dự án, nhưng tác giả nhấn mạnh rằng công cụ này không hoàn hảo và vẫn cần sự hướng dẫn cẩn thận từ con người.&lt;/p&gt;
&lt;h2 id="http-is-not-simple"&gt;&lt;a class="link" href="https://daniel.haxx.se/blog/2025/08/08/http-is-not-simple/" target="_blank" rel="noopener"
&gt;HTTP is not simple&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Daniel Stenberg, tác giả của curl, thách thức quan niệm phổ biến rằng HTTP là một giao thức đơn giản. Ông lập luận rằng HTTP thực tế phức tạp hơn nhiều so với những gì mọi người thường nghĩ, đặc biệt khi xem xét việc triển khai một client HTTP tuân thủ đầy đủ các tiêu chuẩn.&lt;/p&gt;
&lt;p&gt;Những phức tạp cụ thể bao gồm xử lý xuống dòng với độ dài dòng tùy ý và các tiêu chuẩn kết thúc dòng không nhất quán (CR, LF, hoặc cả hai), trong khi các header dựa trên octet chứ không phải UTF-8. Việc phân tích cú pháp cũng gặp nhiều thách thức như nhiều cách khác nhau để xác định kết thúc nội dung, việc phân tích số khó khăn, các quy tắc phức tạp về khoảng trắng và token, cũng như các kỹ thuật &amp;ldquo;folding&amp;rdquo; header.&lt;/p&gt;
&lt;p&gt;HTTP đã tích lũy độ phức tạp qua nhiều thập kỷ với hơn 40 tài liệu RFC riêng biệt, sự gia tăng đáng kể về quy mô đặc tả theo thời gian, và các hành vi không nhất quán của phương thức và header. Các trình duyệt thường ưu tiên trải nghiệm người dùng hơn là tuân thủ nghiêm ngặt các tiêu chuẩn.&lt;/p&gt;
&lt;p&gt;Tác giả gợi ý rằng độ phức tạp này có thể là đặc tính cố hữu của các giao thức thành công và tồn tại lâu dài, khi những gì bắt đầu đơn giản thường trở nên phức tạp thông qua việc thích ứng và mở rộng liên tục.&lt;/p&gt;
&lt;h2 id="building-a-web-search-engine-from-scratch-in-two-months-with-3-billion-neural-embeddings"&gt;&lt;a class="link" href="https://blog.wilsonl.in/search-engine/" target="_blank" rel="noopener"
&gt;Building a web search engine from scratch in two months with 3 billion neural embeddings&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Wilson Lin chia sẻ hành trình xây dựng một công cụ tìm kiếm web tùy chỉnh sử dụng mô hình nhúng thần kinh trong vòng hai tháng. Dự án này tập trung vào việc cải thiện chất lượng và độ liên quan của kết quả tìm kiếm thông qua việc hiểu ý định truy vấn thay vì chỉ khớp từ khóa đơn thuần.&lt;/p&gt;
&lt;p&gt;Về mặt kỹ thuật, tác giả đã sử dụng 200 GPU để tạo ra 3 tỷ mô hình nhúng thần kinh, phát triển một crawler có thể xử lý 50.000 trang mỗi giây, và xây dựng hệ thống phân tán sử dụng RocksDB cho lưu trữ, HNSW được phân đoạn cho tìm kiếm vector, với 4 TB RAM và 82 TB SSD. Hệ thống đạt được độ trễ truy vấn đầu cuối khoảng 500ms.&lt;/p&gt;
&lt;p&gt;Các đổi mới chính bao gồm việc sử dụng kỹ thuật phân đoạn ngữ nghĩa và bảo tồn ngữ cảnh, triển khai chuẩn hóa nội dung trang web tiên tiến, và phát triển phương pháp móc nối câu lệnh để bảo tồn ngữ cảnh ngữ nghĩa. Dự án cho thấy mô hình nhúng thần kinh cung cấp khả năng hiểu tìm kiếm vượt trội, nhưng chất lượng tìm kiếm phụ thuộc nhiều hơn vào crawling và lọc hơn là công nghệ.&lt;/p&gt;
&lt;p&gt;Tác giả khuyến nghị khám phá các chỉ mục tìm kiếm mã nguồn mở được cộng đồng duy trì, nghiên cứu mô hình nhúng tĩnh và các mô hình nhúng hiệu quả hơn, tận dụng hạ tầng crawling hiện có, và tập trung vào nội dung chất lượng thay vì số lượng.&lt;/p&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/7136a64a-5300-4eed-852f-cdaf6cf73c6a_3000x3900.png"
loading="lazy"
alt="What is the SOLID Principle?"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/fe53c806-a56f-4004-97e8-bbc6b5b9eb3d_3000x3900.jpeg"
loading="lazy"
alt="Common HTTP Status Codes"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/db0481bd-807d-419c-a71e-913a13cb855e_1280x808.jpeg"
loading="lazy"
alt="How Clean Architecture Works?"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/ba21dab1-a39e-4c3a-a815-08d8be09de49_2360x2492.png"
loading="lazy"
alt="How does Docker Work?"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/7f891bc7-8657-47ff-8974-efcfcc0f0bb1_2250x2624.png"
loading="lazy"
alt="A Guide to Top Caching Strategies"
&gt;&lt;/p&gt;</description></item><item><title>Siêu tổng hợp ByteByteGo P4</title><link>https://miti99.com/post/2025/08/23/</link><pubDate>Sat, 23 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/23/</guid><description>&lt;p&gt;&lt;em&gt;Nốt phần ảnh này của &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt; sau đó chúng ta sẽ quay lại với Newsletter như mọi khi nhé hehe&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/c102625c-50df-4d7b-b154-ff4284e5fdaf_2250x2624.png"
loading="lazy"
alt="A Guide To Database Replication"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/9e0f17b6-cec8-4607-a058-eae3e446b6a6_3327x3946.jpeg"
loading="lazy"
alt="Best ways to test system functionality"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/df32b82e-fb8e-4d38-82b1-b018168fa88a_2360x2770.png"
loading="lazy"
alt="How CQRS Works?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/95a38be8-f32e-4539-8900-5e9d6f9d40bf_2360x2770.png"
loading="lazy"
alt="How MongoDB Works?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/63055e37-b9bd-4272-af1f-cd6541df89e7_2250x2624.png"
loading="lazy"
alt="Database Index Internals Key Data Structures"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/56532cec-fb2f-4e68-a1b8-70a9a5028503_2250x2624.png"
loading="lazy"
alt="A Guide To Database Sharding"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/e566ed02-724a-4419-b1ca-c70a83f2b58a_2360x2770.jpeg"
loading="lazy"
alt="Top 5 common ways to improve API performance"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/32470e3a-ad82-47d4-89a0-50452cf6b5f3_3000x3900.jpeg"
loading="lazy"
alt="REST API Vs. GraphQL"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/89c503de-5e18-4860-8556-f5f44b49e9b7_2360x2770.jpeg"
loading="lazy"
alt="Tokens vs API Keys"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/f98283d5-9fde-4f08-bb72-eb59e9d5c675_2360x2770.png"
loading="lazy"
alt="5 Data Structures That Make DB Queries Super Fast"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/5791931d-46af-4ea2-bffe-5fea406baab3_3000x3900.jpeg"
loading="lazy"
alt="How can Cache Systems go wrong?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/4e52d277-d633-405c-a419-16ec2b74ad02_2360x3114.png"
loading="lazy"
alt="8 System Design Concepts Explained in 1 Diagram"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/ec03cc75-1a8f-4439-888d-04e71ea1a062_2250x2624.png"
loading="lazy"
alt="Top Leader Election Algorithms in Distributed Databases"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/6e4d9909-210e-4800-8f29-407849c722bf_2376x2818.png"
loading="lazy"
alt="16 Coding Patterns That Make Interviews Easy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/aa6f54c9-42dd-4560-b696-4e937fb43528_3327x3900.png"
loading="lazy"
alt="What happens when you type a URL into a browser?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/297d9a09-7bb1-4818-b192-b0c6e6f281e8_2360x2770.png"
loading="lazy"
alt="How to Learn Databases?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/93e1c5fb-c230-4b86-ac95-6fd9209f3ad1_2360x2770.png"
loading="lazy"
alt="How HTTPS Works?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/d3b197f6-0847-4323-99fa-8d91ffea09f4_2250x2814.png"
loading="lazy"
alt="The Evolution of Scaling at Netflix"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substackcdn.com/image/fetch/$s_!STjn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71fa35ca-3bb5-4601-831f-f13f46a6f11d_2250x2624.heic"
loading="lazy"
alt="Top Scalability Strategies for Real-World Load"
&gt;&lt;/p&gt;
&lt;h2 id="và-một-số-video"&gt;Và một số video
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=uq-JpclPQV4" target="_blank" rel="noopener"
&gt;20 System Design Concepts You Must Know - Final Part&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=HHUi8F_qAXM" target="_blank" rel="noopener"
&gt;How Does a URL Shortener Work?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Hẹn gặp lại các bạn trong newsletter lần sau nha haha!!&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Siêu tổng hợp ByteByteGo P3</title><link>https://miti99.com/post/2025/08/22/</link><pubDate>Fri, 22 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/22/</guid><description>&lt;p&gt;&lt;em&gt;Hôm nay hơi lười nên chúng ta lại quay lại series ảnh của &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt; nhé. Bạn thích thì mình viết, bạn không thích thì mình cũng viết hehe&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/074eba32-d415-4ed1-a60e-d193918f0df2_2250x2624.png"
loading="lazy"
alt="SQL vs NoSQL: Choosing the Right Database"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/8d91771b-65ec-407f-82c7-f5fa56f433ce_800x1001.gif"
loading="lazy"
alt="How Do Companies Ship Code to Production?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/a9f2fed5-3dd3-400e-8c1f-2a710b748508_800x1040.gif"
loading="lazy"
alt="CRUB System v.s. Event Sourcing?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/d7a3fa93-1dab-4f51-9852-93e74ec0836f_800x939.gif"
loading="lazy"
alt="How Data Lake Architecture Works?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/6361ec0d-86b0-4b65-a2c7-ffebc52088cf_1280x1532.gif"
loading="lazy"
alt="How Netflix Built a Distributed Counter"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/5dfd6e6b-7736-4994-b85e-61c93a69a6d0_800x939.gif"
loading="lazy"
alt="How TCP Handshake Works?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/cb8b771f-baa7-4504-ae79-4aa69adf0f5a_2250x2624.png"
loading="lazy"
alt="Database Schema Design"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/cd483dd1-9d8f-4e1e-b030-44a384f3d8e8_2250x2624.png"
loading="lazy"
alt="Transactions and Concurrency In Database"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/4ceb221a-ba89-4ebc-9813-4bbb85277287_2360x2770.png"
loading="lazy"
alt="How SQL Query Executes In A Database?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/a326735a-320e-4476-af4b-ea9856ff25da_2360x2770.png"
loading="lazy"
alt="How RabbitMQ Works?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/27a066e7-b104-48aa-a5c5-1d5f87c32307_2250x2624.png"
loading="lazy"
alt="Database Indexing Demystified: Key Index Types"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/dbfba66c-6482-4392-86d8-af7b1835e2a6_2360x2770.png"
loading="lazy"
alt="6 Data Structures to Save Storage"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/a793a9c6-86e1-426a-a774-b78785966e9c_2360x2770.png"
loading="lazy"
alt="5 Database Normal Forms Every Developer Should Know"
&gt;&lt;/p&gt;
&lt;h2 id="và-một-số-video"&gt;Và một số video
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=nBvDtj-p6VM" target="_blank" rel="noopener"
&gt;Trillions of Web Pages: Where Does Google Store Them?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Hẹn gặp lại các bạn trong các phần sau nữa nha haha!!&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Cách xử lý HTTP Timeout khi sử dụng Coolify</title><link>https://miti99.com/post/2025/08/21/</link><pubDate>Thu, 21 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/21/</guid><description>&lt;p&gt;&lt;em&gt;Đăng ảnh của &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt; được mấy hôm rồi nên nay đổi gió.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Đôi khi deploy GitLab hay Gitea lên Coolify và sử dụng bạn sẽ gặp lỗi như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git -c diff.mnemonicprefix=false -c core.quotepath=false --no-optional-locks push -v &amp;lt;remote của bạn&amp;gt; &amp;lt;nhánh trên local&amp;gt;:&amp;lt;nhánh trên remote&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;POST git-receive-pack (chunked)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;error: RPC failed; HTTP 504 curl 22 The requested URL returned error: 504
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;send-pack: unexpected disconnect while reading sideband packet
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fatal: the remote end hung up unexpectedly
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Pushing to &amp;lt;url git của bạn&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Everything up-to-date
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Completed with errors, see above.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Có thể bạn đi search và tìm thấy solution là chỉnh git chunk buffer như này:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git config --global http.postBuffer &amp;lt;một số gì đó khá là to&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="tại-sao-git-config-httppostbuffer-không-hiệu-quả"&gt;Tại sao git config http.postBuffer không hiệu quả?
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Git http.postBuffer là gì?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đây là buffer size mà git sử dụng khi gửi dữ liệu qua HTTP POST&lt;/li&gt;
&lt;li&gt;Mặc định git gửi dữ liệu theo từng chunk nhỏ (thường 1MB)&lt;/li&gt;
&lt;li&gt;Tăng postBuffer có nghĩa là gửi từng chunk lớn hơn, giảm số lần request&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Vì sao trong trường hợp này nó không hiệu quả?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Vấn đề không nằm ở việc git gửi dữ liệu như thế nào, mà nằm ở &lt;strong&gt;HTTP timeout của proxy Coolify&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Git vẫn gửi được dữ liệu&lt;/strong&gt; lên Traefik proxy&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traefik proxy chờ phản hồi&lt;/strong&gt; từ Git server (GitLab/Gitea)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Git server cần thời gian xử lý&lt;/strong&gt; dữ liệu (compress, index, validate&amp;hellip;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traefik timeout trước&lt;/strong&gt; khi Git server kịp phản hồi → HTTP 504&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ngay cả khi git gửi chunk lớn hay nhỏ, thời gian xử lý ở Git server vẫn như vậy. Do đó tăng postBuffer không giải quyết được vấn đề timeout ở proxy layer.&lt;/p&gt;
&lt;h2 id="kiến-trúc-và-nguyên-nhân-lỗi"&gt;Kiến trúc và nguyên nhân lỗi
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Luồng hoạt động khi git push:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Git Client → Traefik Proxy → Git Server (GitLab/Gitea)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↑ ↑ ↑
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; postBuffer readTimeout Processing time
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Chi tiết từng bước:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Git client&lt;/strong&gt; gửi dữ liệu qua HTTP POST (có thể mất vài giây với repo lớn)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traefik proxy&lt;/strong&gt; nhận và forward request đến Git server&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Git server&lt;/strong&gt; bắt đầu xử lý:
&lt;ul&gt;
&lt;li&gt;Giải nén objects&lt;/li&gt;
&lt;li&gt;Kiểm tra integrity&lt;/li&gt;
&lt;li&gt;Cập nhật refs&lt;/li&gt;
&lt;li&gt;Chạy git hooks (nếu có)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traefik chờ phản hồi&lt;/strong&gt; trong thời gian &lt;code&gt;readTimeout&lt;/code&gt; (mặc định ~30s)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nếu Git server xử lý lâu hơn&lt;/strong&gt; → Traefik trả về HTTP 504&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Tại sao lỗi này xảy ra với Coolify?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Coolify sử dụng Traefik làm reverse proxy&lt;/li&gt;
&lt;li&gt;Traefik có &lt;code&gt;readTimeout&lt;/code&gt; mặc định khá thấp&lt;/li&gt;
&lt;li&gt;Git operations với large files/repos thường cần &amp;gt; 30s để xử lý&lt;/li&gt;
&lt;li&gt;Lỗi này không chỉ ảnh hưởng git mà còn các HTTP service khác cần xử lý lâu&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="giải-pháp"&gt;Giải pháp
&lt;/h2&gt;&lt;p&gt;Vào phần &lt;code&gt;Server &amp;gt; (server của bạn, thường là localhost) &amp;gt; Proxy &amp;gt; Configuration&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2025/08/21/img/image.png"
width="2552"
height="1284"
srcset="https://miti99.com/post/2025/08/21/img/image_hu_7f85d264bb128408.png 480w, https://miti99.com/post/2025/08/21/img/image_hu_a4292d86ed1dab9b.png 1024w"
loading="lazy"
alt="1"
class="gallery-image"
data-flex-grow="198"
data-flex-basis="477px"
&gt;&lt;/p&gt;
&lt;p&gt;Thêm các dòng sau vào &lt;code&gt;services.traefik.command&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="s1"&gt;&amp;#39;--entrypoints.http.transport.respondingTimeouts.readTimeout=600s&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="s1"&gt;&amp;#39;--entrypoints.https.transport.respondingTimeouts.readTimeout=600s&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Giải thích&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;readTimeout&lt;/code&gt;: Thời gian tối đa Traefik chờ đọc phản hồi từ backend&lt;/li&gt;
&lt;li&gt;&lt;code&gt;600s&lt;/code&gt; (10 phút): Thời gian phù hợp cho các tác vụ git push lớn&lt;/li&gt;
&lt;li&gt;Có thể điều chỉnh tùy theo kích thước repository và tốc độ mạng của bạn&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Full config (mẫu, có thể thay đổi trong các phiên bản sau của Coolify, bạn chỉ nên tham khảo cách thêm mà thôi):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;coolify-proxy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;networks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;coolify&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;external&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;traefik&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;coolify-proxy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;traefik:v3.1&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;extra_hosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;host.docker.internal:host-gateway&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;networks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;coolify&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;80:80&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;443:443&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;443:443/udp&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;8080:8080&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;healthcheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;wget -qO- http://localhost:80/ping || exit 1&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;4s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;2s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;/var/run/docker.sock:/var/run/docker.sock:ro&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;/data/coolify/proxy/:/traefik&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--ping=true&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--ping.entrypoint=http&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--api.dashboard=true&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--entrypoints.http.address=:80&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--entrypoints.https.address=:443&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--entrypoints.http.http.encodequerysemicolons=true&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--entryPoints.http.http2.maxConcurrentStreams=250&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--entrypoints.https.http.encodequerysemicolons=true&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--entryPoints.https.http2.maxConcurrentStreams=250&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--entrypoints.https.http3&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--providers.file.directory=/traefik/dynamic/&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--providers.file.watch=true&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--certificatesresolvers.letsencrypt.acme.httpchallenge=true&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--certificatesresolvers.letsencrypt.acme.storage=/traefik/acme.json&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--api.insecure=false&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--providers.docker=true&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--providers.docker.exposedbydefault=false&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--entrypoints.http.transport.respondingTimeouts.readTimeout=600s&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;--entrypoints.https.transport.respondingTimeouts.readTimeout=600s&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;traefik.enable=true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;traefik.http.routers.traefik.entrypoints=http&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;traefik.http.routers.traefik.service=api@internal&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;traefik.http.services.traefik.loadbalancer.server.port=8080&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;coolify.managed=true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;coolify.proxy=true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="áp-dụng-thay-đổi"&gt;Áp dụng thay đổi
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Save&lt;/strong&gt;: Lưu cấu hình Traefik&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restart Proxy&lt;/strong&gt;: Khởi động lại proxy để áp dụng timeout mới&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kiểm tra&lt;/strong&gt;: Đợi proxy hoạt động trở lại (thường mất 30-60 giây)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="lưu-ý-quan-trọng"&gt;Lưu ý quan trọng
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Không nên đặt timeout quá cao&lt;/strong&gt;: Có thể gây treo kết nối lâu khi có lỗi thực sự&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test với repository nhỏ trước&lt;/strong&gt;: Đảm bảo cấu hình hoạt động đúng&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Theo dõi logs&lt;/strong&gt;: Kiểm tra logs của Coolify và Traefik để debug nếu cần&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Chúc các bạn thành công và sớm push được code nhé!&lt;/p&gt;</description></item><item><title>Siêu tổng hợp ByteByteGo P2</title><link>https://miti99.com/post/2025/08/20/</link><pubDate>Wed, 20 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/20/</guid><description>&lt;p&gt;&lt;em&gt;Vì còn quá nhiều ảnh của &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt; nên xin mời các bạn đến với phần 2 hehe. Hiện tại thì mình đã lọc ra bớt, chỉ up những ảnh mình thấy là tâm đắc mà thôi.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substackcdn.com/image/fetch/$s_!5Nbl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe369aaeb-f74b-4923-a3d9-410a46ee5594_2250x2624.heic"
loading="lazy"
alt="Synchronous vs Asynchronous"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/4036e9a7-f2b6-476c-ad5d-48916db3b610_1309x1536.gif"
loading="lazy"
alt="A Cheatsheet on REST API Design Best Practices"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/f88bba04-c206-49a3-9e7b-4aecee486b06_1280x1547.gif"
loading="lazy"
alt="9 Clean Code Principles To Keep In Mind"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/0f92402a-8be5-4b30-bc87-76f19dce3114_1280x1502.png"
loading="lazy"
alt="The 4 Types of SQL Joins"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/337fbca9-f069-467c-a44c-d7461856ce23_1280x1664.gif"
loading="lazy"
alt="Visualizing a SQL query"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/fa29d150-f51a-43c0-99e1-28031a59c1b7_1530x1536.jpeg"
loading="lazy"
alt="Explaining JSON Web Token (JWT) with simple terms"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/aa4b4949-70e8-4c9a-902d-70e179513bb2_2250x2624.png"
loading="lazy"
alt="Understanding Eventual Consistency"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/8a4a708d-20f3-47d9-92a0-ac826585711e_1280x1664.gif"
loading="lazy"
alt="How to Deploy Services"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/f22fad89-0da7-4390-bde8-178e56221449_1280x1502.gif"
loading="lazy"
alt="The System Design Topic Map"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/3530d961-653b-4631-95db-004c0df05073_2250x2624.png"
loading="lazy"
alt="API Gateway Versus Service Mesh"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/25af8b79-f58d-4b9c-aeaa-b6ffb8b93f39_1280x1608.gif"
loading="lazy"
alt="JWT Simply Explained"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/4b6b777c-9e12-4b56-bd27-75c01987abe6_1280x1502.gif"
loading="lazy"
alt="The 5 Pillars of API Design"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/7a12caa3-603d-43b0-954e-f7b450281ae8_1280x1502.gif"
loading="lazy"
alt="How Computer Memory Works?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/8ea2cf88-f4a3-4135-8801-dcaa1eacadcc_2250x2624.png"
loading="lazy"
alt="A Deep Dive Into HTTP: From HTTP/1.1 to HTTP/3"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/1e486766-bf1a-4f75-9003-9d382d567855_1280x1502.gif"
loading="lazy"
alt="AI Agent versus MCP"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/0e18db0d-f511-4f85-bb58-388fce70d42e_2631x2103.png"
loading="lazy"
alt="How does HTTPS work?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/4cd58a79-de9c-4ac2-a6df-eac95b61d71e_1541x1536.jpeg"
loading="lazy"
alt="Top 6 most commonly used Server Types"
&gt;&lt;/p&gt;
&lt;h2 id="và-một-số-video"&gt;Và một số video
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=2g1G8Jr88xU" target="_blank" rel="noopener"
&gt;System Design Was HARD - Until You Knew the Trade-Offs, Part 2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=hltLrjabkiY" target="_blank" rel="noopener"
&gt;APIs Explained in 6 Minutes!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Và tất nhiên là vẫn còn nhiều ảnh khác. Lại hẹn các bạn trong P3 nha!!&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Siêu tổng hợp ByteByteGo</title><link>https://miti99.com/post/2025/08/19/</link><pubDate>Tue, 19 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/19/</guid><description>&lt;p&gt;&lt;em&gt;Nếu các bạn để ý thì chắc cũng thấy các Newsletter gần đây vắng bóng mục Bonus: Một số hình ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;. Và đúng là như vậy, sự thật là vì chèn hình ảnh thì mình chèn bằng tay chứ không nhờ AI Agent, nên là mình skip hết các ảnh mình thấy. Và bây giờ tích cũng khá nhiều rồi nên mình sẽ &amp;ldquo;xả ảnh&amp;rdquo; 1 loạt luôn hehe. Nói thể thôi chứ nhiều lắm, có khi sẽ cần P2, P3,&amp;hellip; nữa :v Thôi không vòng vo nữa, mời các bạn đến với thế giới ảnh của ByteByteGo đợt này.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/3eedbbd4-e0a4-4519-be5c-ee0c644df55f_1280x1502.gif"
loading="lazy"
alt="How to Learn API Development?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/bda0fcd6-d0f3-485f-826e-e64e8ad041e0_1309x1536.gif"
loading="lazy"
alt="Must-Know Network Protocol Dependencies"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/cc72d79b-1734-4a93-a932-6b3d10c04c7d_1280x1664.gif"
loading="lazy"
alt="18 Key Design Patterns Every Developer Should Know"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/1a16589b-604b-4954-9a25-ac2cc07eeed9_2250x2862.png"
loading="lazy"
alt="Coupling and Cohesion: The Two Principles for Effective Architecture"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/c2d55082-3853-45c1-922a-55321e2dbbcb_1280x1680.gif"
loading="lazy"
alt="The Data Engineering Roadmap"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/f9742557-fb6c-40c1-8590-56234a0666c2_1280x1664.gif"
loading="lazy"
alt="Popular interview question: What is the difference between Process and Thread?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/a42c9ba4-0951-42b1-94e3-1e9a055c476c_1280x1581.gif"
loading="lazy"
alt="What do version numbers mean?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/292f3b60-c96a-4d5e-962b-408cef38750c_2250x2862.png"
loading="lazy"
alt="A Cheatsheet On Domain-Driven Design"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/f3c20adf-c285-4abf-bf87-8a9cc044aeed_1280x1546.jpeg"
loading="lazy"
alt="Top 20 System Design Concepts You Should Know"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/87b06b99-818a-410d-a630-3961851617f3_1283x1536.gif"
loading="lazy"
alt="What is an AI Agent?"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/f8fa0a70-5806-411b-90ea-71ce6a007fe4_1280x1425.gif"
loading="lazy"
alt="Essential Git Cheatsheet!"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/bfc82003-280b-47a9-93a6-2600afe7f7a8_1309x1536.gif"
loading="lazy"
alt="9 OOP Design Patterns You Must Know"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/ea385c61-b3d2-4ecb-8c22-b43587ea85e5_1280x1585.gif"
loading="lazy"
alt="The Fundamental Pillars of Object-Oriented Programming"
&gt;&lt;/p&gt;
&lt;h2 id="và-một-số-video"&gt;Và một số video
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=1nENigGr-a0" target="_blank" rel="noopener"
&gt;System Design Was HARD - Until You Knew the Trade-Offs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Chà, vẫn còn nhiều. Hẹn các bạn trong các đợt siêu tổng hợp tiếp theo nhé hehe!!&lt;/em&gt;&lt;/p&gt;</description></item><item><title>VNGeoGuessr - GeoGuessr nhưng dành cho Việt Nam</title><link>https://miti99.com/post/2025/08/16/</link><pubDate>Sat, 16 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/16/</guid><description>&lt;p&gt;Chào các bạn! Hôm nay MiTi muốn giới thiệu với các bạn một dự án nho nhỏ mà MiTi vừa hoàn thành - &lt;strong&gt;VNGeoGuessr&lt;/strong&gt;, một trò chơi đoán địa điểm (giống GeoGuessr) dành riêng cho Việt Nam.&lt;/p&gt;
&lt;h2 id="vngeoguessr-là-gì"&gt;VNGeoGuessr là gì?
&lt;/h2&gt;&lt;p&gt;VNGeoGuessr là phiên bản bắt chước của trò chơi GeoGuessr (nhưng tất nhiên là rởm hơn nhiều :v), được thiết kế đặc biệt cho các thành phố ở Việt Nam. Thay vì phải đoán những địa điểm xa lạ trên toàn thế giới, giờ đây các bạn có thể thử thách bản thân với những con phố của quê hương Việt Nam mình. Hiện tại VNGeoGuessr có hỗ trợ các thành phố lớn như Hà Nội, TP. Hồ Chí Minh, Đà Nẵng, Đà Lạt và Đức Hoà (quê mình :v) Các bạn có thể góp ý để MiTi bổ sung thêm nhé :v&lt;/p&gt;
&lt;h2 id="cách-chơi"&gt;Cách chơi
&lt;/h2&gt;&lt;p&gt;Trò chơi rất đơn giản:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Hệ thống sẽ hiển thị một hình ảnh Street View ngẫu nhiên từ thành phố mà bạn chọn&lt;/li&gt;
&lt;li&gt;Bạn cần quan sát và đoán xem đây là địa điểm nào trên bản đồ&lt;/li&gt;
&lt;li&gt;Càng đoán gần với vị trí thật, bạn càng được điểm cao&lt;/li&gt;
&lt;li&gt;Thử thách bản thân để ghi tên vào bảng xếp hạng nhé :v&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="tính-năng-nổi-bật"&gt;Tính năng nổi bật
&lt;/h2&gt;&lt;h3 id="bảng-xếp-hạng-kép"&gt;Bảng xếp hạng kép
&lt;/h3&gt;&lt;p&gt;VNGeoGuessr có hai loại bảng xếp hạng để tạo sự cạnh tranh:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Xếp hạng theo điểm số&lt;/strong&gt;: Tích tiểu thành đại, chơi dở mà chơi lâu cũng leo top được :v&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Xếp hạng theo khoảng cách thấp nhất&lt;/strong&gt;: Dành cho những player hardcore, muốn có độ chính xác cao trong từng lượt đoán :v&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="dữ-liệu-địa-phương"&gt;Dữ liệu địa phương
&lt;/h3&gt;&lt;p&gt;Các địa điểm trong game được lấy từ các thành phố lớn ở Việt Nam, nên có thể gần gũi với người chơi Việt Nam hơn.&lt;/p&gt;
&lt;h2 id="trải-nghiệm-game"&gt;Trải nghiệm game
&lt;/h2&gt;&lt;p&gt;Hiện tại, bạn có thể trải nghiệm VNGeoGuessr tại:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Phiên bản chính thức&lt;/strong&gt;: &lt;a class="link" href="https://vngeoguessr.miti99.com/" target="_blank" rel="noopener"
&gt;vngeoguessr.miti99.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phiên bản thử nghiệm&lt;/strong&gt;: &lt;a class="link" href="https://dev.vngeoguessr.miti99.com/" target="_blank" rel="noopener"
&gt;dev.vngeoguessr.miti99.com&lt;/a&gt; (có các tính năng, sửa lỗi mới nhất, có thể chưa ổn định)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="góp-ý-và-phản-hồi"&gt;Góp ý và phản hồi
&lt;/h2&gt;&lt;p&gt;Mình rất mong nhận được phản hồi từ cộng đồng để cải thiện trò chơi. Các bạn có thể gửi ý kiến, báo lỗi, hoặc đề xuất tính năng mới thông qua:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fanpage Facebook&lt;/strong&gt;: &lt;a class="link" href="https://facebook.com/vngeoguessr" target="_blank" rel="noopener"
&gt;facebook.com/vngeoguessr&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="lời-kết"&gt;Lời kết
&lt;/h2&gt;&lt;p&gt;VNGeoGuessr không chỉ là một trò chơi giải trí, cạnh tranh lành mạnh mà còn là cách thú vị để khám phá những ngóc ngách khác khác của đất nước Việt Nam mình (các bạn mà thấy streetview của mấy đoạn có ruộng đồng, có cả bò ở TPHCM rồi sẽ hiểu, hoá ra thành phố lớn cũng có những chỗ thế này :v). Hy vọng các bạn sẽ có những giây phút thư giãn và thử thách bổ ích cùng VNGeoGuessr.&lt;/p&gt;
&lt;p&gt;Hãy thử sức ngay hôm nay và xem bạn có thể đạt được vị trí nào trên bảng xếp hạng nhé! 🎯&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Chúc các bạn chơi game vui vẻ!&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #50</title><link>https://miti99.com/post/2025/08/09/</link><pubDate>Sat, 09 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/09/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #50.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="there-is-no-memory-safety-without-thread-safety"&gt;&lt;a class="link" href="https://www.ralfj.de/blog/2025/07/24/memory-safety.html" target="_blank" rel="noopener"
&gt;There is No Memory Safety Without Thread Safety&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Ralf Jung, nhà nghiên cứu về lý thuyết ngôn ngữ lập trình tại ETH Zurich, đưa ra quan điểm táo bạo rằng bảo mật bộ nhớ và bảo mật luồng không thể tách rời. Thay vì định nghĩa truyền thống chỉ tập trung vào use-after-free và out-of-bounds access, tác giả lập luận rằng mục tiêu thực sự là &amp;ldquo;ngăn chặn Undefined Behavior&amp;rdquo; dưới mọi hình thức.&lt;/p&gt;
&lt;p&gt;Vấn đề cốt lõi được nêu ra qua ví dụ về Go: ngôn ngữ này cho phép data race xảy ra mà không có biện pháp bảo vệ, dẫn đến khả năng phá vỡ bảo mật bộ nhớ thông qua lập trình đồng thời. Điều này khác biệt với Java (sử dụng garbage collection để ngăn chặn use-after-free) và Rust (hệ thống type mạnh mẽ ngăn data race).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phân loại ngôn ngữ theo cách xử lý đồng thời&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Java&lt;/strong&gt;: Đảm bảo các bất biến ngôn ngữ được duy trì ngay cả khi có data race&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rust&lt;/strong&gt;: Sử dụng hệ thống type để ngăn chặn data race từ đầu&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Go&lt;/strong&gt;: Cho phép data race tiềm ẩn có thể phá vỡ bảo mật bộ nhớ&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Luận điểm trung tâm: &amp;ldquo;Không có nghĩa nào có thể chia nhỏ khái niệm này thành bảo mật bộ nhớ, bảo mật luồng, bảo mật kiểu dữ liệu&amp;rdquo; - điều quan trọng là ngăn chặn Undefined Behavior làm suy yếu các đảm bảo cơ bản của ngôn ngữ.&lt;/p&gt;
&lt;p&gt;Bài viết mang đến góc nhìn sâu sắc về thiết kế ngôn ngữ lập trình, đặc biệt quan trọng trong bối cảnh các hệ thống hiện đại ngày càng phụ thuộc vào tính toán song song và an toàn bộ nhớ.&lt;/p&gt;
&lt;h2 id="i-know-when-you"&gt;&lt;a class="link" href="https://alexkondov.com/i-know-when-youre-vibe-coding/" target="_blank" rel="noopener"
&gt;I Know When You&amp;rsquo;re Vibe Coding&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Alex Kondov chia sẻ những dấu hiệu nhận biết khi lập trình viên đang &amp;ldquo;vibe coding&amp;rdquo; - thuật ngữ mô tả việc lập trình với sự hỗ trợ AI mà thiếu sự hiểu biết sâu về mã nguồn. Bài viết không phán xét việc sử dụng AI mà tập trung vào cách nhận biết và cải thiện chất lượng mã được tạo ra.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dấu hiệu nhận biết vibe coding&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vi phạm quy ước dự án&lt;/strong&gt;: Triển khai tính năng đã tồn tại trong thư viện dự án, viết các hàm tiện ích trùng lặp với module hiện có&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thay đổi cấu hình không nhất quán&lt;/strong&gt;: Không tuân theo pattern đã thiết lập của team&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sử dụng paradigm lập trình khác biệt&lt;/strong&gt;: Không phù hợp với tiêu chuẩn của nhóm&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Đặc điểm của mã do AI tạo ra&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mã hoạt động chính xác và có thể bảo trì&lt;/li&gt;
&lt;li&gt;Triển khai rõ ràng và đúng kỹ thuật&lt;/li&gt;
&lt;li&gt;Được kiểm thử đầy đủ&lt;/li&gt;
&lt;li&gt;Nhưng thiếu hiểu biết sắc thái đặc thù của team&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Hướng dẫn cải thiện&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quan tâm đến chất lượng mã hơn phương pháp tạo ra nó&lt;/li&gt;
&lt;li&gt;Viết prompt AI tốt hơn với ngữ cảnh và ví dụ rõ ràng&lt;/li&gt;
&lt;li&gt;Duy trì các nguyên tắc thiết kế phần mềm đã thiết lập&lt;/li&gt;
&lt;li&gt;Tập trung vào khả năng bảo trì dài hạn&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Câu trích dẫn then chốt: &amp;ldquo;Tôi không muốn biết bạn viết mã này như thế nào. Tôi chỉ muốn biết rằng bạn quan tâm đến những gì mô hình tạo ra.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Bài viết nhấn mạnh rằng giám sát con người và tuân thủ các nguyên tắc thiết kế phần mềm vẫn là yếu tố quan trọng nhất, bất kể AI có thể tạo ra mã chức năng tốt đến đâu.&lt;/p&gt;
&lt;h2 id="the-7-most-influential-papers-in-computer-science-history"&gt;&lt;a class="link" href="https://terriblesoftware.org/2025/01/22/the-7-most-influential-papers-in-computer-science-history/" target="_blank" rel="noopener"
&gt;The 7 Most Influential Papers in Computer Science History&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Terrible Software tuyển chọn 7 bài báo khoa học có tác động lớn nhất đến lịch sử khoa học máy tính, từ những nền tảng lý thuyết đến các ứng dụng thực tiễn định hình thế giới công nghệ ngày nay.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;7 bài báo có ảnh hưởng lớn nhất&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;On Computable Numbers&amp;rdquo; (1936)&lt;/strong&gt; - Alan Turing: Đặt nền móng cho khái niệm máy Turing và định nghĩa ranh giới tính toán lý thuyết&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;A Mathematical Theory of Communication&amp;rdquo; (1948)&lt;/strong&gt; - Claude Shannon: Phát minh lý thuyết thông tin, định lượng hóa thông tin và giao tiếp&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;A Relational Model of Data&amp;rdquo; (1970)&lt;/strong&gt; - Edgar F. Codd: Giới thiệu mô hình cơ sở dữ liệu quan hệ, nền tảng cho SQL và cách tổ chức dữ liệu hiện đại&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;The Complexity of Theorem-Proving Procedures&amp;rdquo; (1971)&lt;/strong&gt; - Stephen A. Cook: Đưa ra khái niệm NP-completeness, tạo ra &amp;ldquo;ngôn ngữ chung để nói về độ khó của bài toán&amp;rdquo;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;A Protocol for Packet Network Intercommunication&amp;rdquo; (1974)&lt;/strong&gt; - Vinton G. Cerf và Robert E. Kahn: Tạo ra giao thức TCP/IP, &amp;ldquo;về cơ bản là toàn bộ internet&amp;rdquo;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;Information Management: A Proposal&amp;rdquo; (1989)&lt;/strong&gt; - Tim Berners-Lee: Đề xuất khái niệm World Wide Web, &amp;ldquo;thay đổi cách chúng ta chia sẻ kiến thức mãi mãi&amp;rdquo;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;The Anatomy of a Large-Scale Web Search Engine&amp;rdquo; (1998)&lt;/strong&gt; - Sergey Brin và Larry Page: Giới thiệu thuật toán PageRank, &amp;ldquo;định nghĩa lại cách chúng ta điều hướng thông tin trực tuyến&amp;rdquo;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Những bài báo này minh chứng sự chuyển đổi từ các khái niệm lý thuyết thành công nghệ thực tiễn, từ máy tính lý thuyết của Turing đến thuật toán tìm kiếm của Google. Mỗi bài báo không chỉ giải quyết vấn đề kỹ thuật mà còn mở ra những hướng phát triển hoàn toàn mới cho ngành công nghệ thông tin.&lt;/p&gt;
&lt;h2 id="programming-vehicles-in-games"&gt;&lt;a class="link" href="https://wassimulator.com/blog/programming/programming_vehicles_in_games.html" target="_blank" rel="noopener"
&gt;Programming Vehicles in Games&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Wassimulator khám phá thách thức kỹ thuật của việc lập trình xe cộ trong game - một lĩnh vực đòi hỏi sự cân bằng tinh tế giữa mô phỏng vật lý thực tế và trải nghiệm game thú vị. Bài viết cung cấp cái nhìn sâu sắc về cách tạo ra cảm giác lái xe chân thực.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mô hình mô phỏng xe gồm 3 thành phần chính&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Động cơ&lt;/strong&gt;: Sử dụng đường cong mô-men xoắn để mô phỏng hiệu suất, triển khai hộp số như bảng tra cứu tỷ số&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bánh xe/Lốp&lt;/strong&gt;: Tập trung vào mô phỏng ma sát và tạo lực, sử dụng khái niệm Slip Ratio (lực dọc) và Slip Angle (lực ngang)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Khung gầm&lt;/strong&gt;: Quản lý hai biến trạng thái phụ thuộc lẫn nhau: RPM động cơ và vận tốc góc bánh xe&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Kỹ thuật lập trình cốt lõi&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng phương trình vi phân để mô hình hóa động lực học xe&lt;/li&gt;
&lt;li&gt;Triển khai &amp;ldquo;Công thức ma thuật&amp;rdquo; của Pacejka cho tính toán lực lốp&lt;/li&gt;
&lt;li&gt;Tạo &amp;ldquo;vòng tròn ma sát&amp;rdquo; để mô hình hóa lực lốp kết hợp&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Thách thức kỹ thuật quan trọng&lt;/strong&gt;: &amp;ldquo;Bạn không thể phanh và rẽ với lực tối đa cùng lúc. Một mô hình lốp tốt cần tính đến sự đánh đổi này.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược triển khai được khuyến nghị&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bắt đầu với các mô hình đơn giản&lt;/li&gt;
&lt;li&gt;Từ từ tăng độ phức tạp&lt;/li&gt;
&lt;li&gt;Tập trung vào hành vi tự nhiên, đáng tin cậy&lt;/li&gt;
&lt;li&gt;Tinh chỉnh tham số cho cảm giác lái mong muốn&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Triết lý cốt lõi&lt;/strong&gt;: &amp;ldquo;Thách thức mô phỏng xe trong game nằm ở việc kết nối hai thế giới phức tạp: trải nghiệm và máy móc.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Bài viết nhấn mạnh rằng mục tiêu không phải là độ chính xác vật lý hoàn hảo, mà là tạo ra trải nghiệm lái xe thú vị và chân thực thông qua việc điều chỉnh có chủ đích các thông số vật lý.&lt;/p&gt;
&lt;h2 id="periodic-table-of-system-design-principles"&gt;&lt;a class="link" href="https://github.com/jarulraj/periodic-table" target="_blank" rel="noopener"
&gt;Periodic Table of System Design Principles&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Joy Arulraj từ Georgia Tech đã tạo ra một &amp;ldquo;Bảng tuần hoàn các nguyên tắc thiết kế hệ thống&amp;rdquo; - một cách tiếp cận sáng tạo để tổ chức và hiểu các nguyên tắc thiết kế xuyên suốt trong khoa học máy tính. Dự án này giải quyết thách thức quan trọng trong nghiên cứu hệ thống máy tính: các lĩnh vực khác nhau sử dụng từ vựng riêng biệt có thể che giấu những nguyên tắc thiết kế chung cơ bản.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mục tiêu chính&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tạo ra từ vựng chung để hiểu các nguyên tắc thiết kế xuyên suốt trong hệ thống máy tính&lt;/li&gt;
&lt;li&gt;Tổ chức hơn 40 nguyên tắc thiết kế thành 8 nhóm chủ đề như Cấu trúc, Hiệu quả, Ngữ nghĩa&lt;/li&gt;
&lt;li&gt;Giúp sinh viên, nhà nghiên cứu và chuyên gia hiểu các mẫu thiết kế lặp lại qua các lĩnh vực như cơ sở dữ liệu, hệ điều hành và mạng&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Đặc điểm độc đáo&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mỗi nguyên tắc được gắn ký hiệu ngắn (ví dụ: &amp;ldquo;Co&amp;rdquo; cho tính kết hợp)&lt;/li&gt;
&lt;li&gt;Nguyên tắc được trừu tượng hóa từ hơn 100 bài báo nghiên cứu có ảnh hưởng&lt;/li&gt;
&lt;li&gt;Được tổ chức giống bảng tuần hoàn Mendeleev, với các nguyên tắc nhóm theo chủ đề&lt;/li&gt;
&lt;li&gt;Tập trung vào ý định thiết kế thay vì cơ chế triển khai cụ thể&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Giá trị giáo dục&lt;/strong&gt;: Bằng cách lập bản đồ các nguyên tắc xuyên suốt này, dự án giúp người học:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hình thành sơ đồ tư duy mạch lạc hơn về thiết kế hệ thống&lt;/li&gt;
&lt;li&gt;Nhận biết các mẫu tương tự qua các lĩnh vực công nghệ khác nhau&lt;/li&gt;
&lt;li&gt;Hiểu sự đánh đổi thiết kế một cách có hệ thống&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tầm nhìn&lt;/strong&gt;: &amp;ldquo;Làm nổi bật cấu trúc đã tồn tại trong hệ thống máy tính&amp;rdquo; và tạo ra ngôn ngữ chung để thảo luận về thiết kế hệ thống.&lt;/p&gt;
&lt;p&gt;Đây là cách tiếp cận đổi mới để làm cho các khái niệm thiết kế hệ thống phức tạp trở nên dễ tiếp cận và liên kết hơn, đặc biệt hữu ích cho các lập trình viên muốn hiểu sâu hơn về các nguyên tắc thiết kế cơ bản.&lt;/p&gt;
&lt;h2 id="curing-your-ai-10x-engineer-imposter-syndrome"&gt;&lt;a class="link" href="https://colton.dev/blog/curing-your-ai-10x-engineer-imposter-syndrome/" target="_blank" rel="noopener"
&gt;Curing Your AI 10x Engineer Imposter Syndrome&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Colton Dev giải quyết một vấn đề tâm lý phổ biến trong cộng đồng lập trình viên: hội chứng mạo danh liên quan đến AI và áp lực phải trở thành &amp;ldquo;10x engineer&amp;rdquo;. Bài viết mang đến góc nhìn thực tế và an ủi cho những ai cảm thấy bị tụt lại phía sau trong cuộc đua công nghệ AI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thực tế về năng suất 10x&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Năng suất tăng 10 lần về mặt toán học là không thể&lt;/li&gt;
&lt;li&gt;Phần lớn thời gian lập trình không dành cho việc gõ phím mà là suy nghĩ và giải quyết vấn đề&lt;/li&gt;
&lt;li&gt;AI cung cấp những cải tiến năng suất rời rạc, không phải cải thiện 10x nhất quán&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược thay đổi tư duy&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nhận ra thực tế&lt;/strong&gt;: Hầu hết tuyên bố về năng suất 10x đến từ những người có lợi ích riêng&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tin tưởng bản thân&lt;/strong&gt;: &amp;ldquo;Hãy tin vào chính mình. Bạn đã đủ tốt rồi&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tập trung vào chất lượng&lt;/strong&gt;: Ưu tiên chất lượng mã và khả năng bảo trì dài hạn hơn tốc độ tạo mã&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cách tiếp cận thực tiễn với công cụ AI&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Học công cụ AI nhanh chóng nhưng không trở nên phụ thuộc quá mức&lt;/li&gt;
&lt;li&gt;Hiểu những hạn chế của AI trong môi trường lập trình phức tạp&lt;/li&gt;
&lt;li&gt;Sử dụng AI như công cụ hỗ trợ, không thay thế kỹ năng kỹ sư&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Lời khuyên xử lý hội chứng mạo danh&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tránh so sánh liên tục trên mạng xã hội&lt;/li&gt;
&lt;li&gt;Tập trung vào việc ngăn chặn công việc không cần thiết thay vì chỉ tạo mã nhanh&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Không sao nếu hy sinh một chút năng suất để làm cho công việc trở nên thú vị&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Thông điệp cốt lõi&lt;/strong&gt;: Mặc dù AI có thể hữu ích, nó không phải là giải pháp ma thuật sẽ ngay lập tức biến đổi năng suất kỹ sư. Điều quan trọng là duy trì góc nhìn cân bằng về những tiến bộ công nghệ và tin tưởng vào kỹ năng chuyên môn hiện có của mình.&lt;/p&gt;
&lt;p&gt;Bài viết là lời nhắc nhở quan trọng rằng giá trị của một kỹ sư không chỉ đo lường bằng tốc độ viết mã mà còn bằng khả năng tư duy, giải quyết vấn đề và tạo ra giải pháp bền vững.&lt;/p&gt;
&lt;h2 id="demystifying-claude-code-hooks"&gt;&lt;a class="link" href="https://www.brethorsting.com/blog/2025/08/demystifying-claude-code-hooks/" target="_blank" rel="noopener"
&gt;Demystifying Claude Code Hooks&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bret Horsting khám phá một tính năng mạnh mẽ nhưng ít được biết đến của Claude Code: hooks - công cụ tự động hóa cho phép can thiệp và kiểm soát các hành động trước khi chúng được thực thi. Đây là hướng dẫn thực tiễn để tận dụng hooks trong quy trình phát triển phần mềm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hooks là gì và tại sao quan trọng&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Công cụ tự động hóa cho phép chặn và kiểm soát các hành động trước khi thực thi&lt;/li&gt;
&lt;li&gt;Cho phép xác thực tùy chỉnh, kiểm thử và quản lý quy trình làm việc&lt;/li&gt;
&lt;li&gt;Đảm bảo thực hành phát triển nhất quán và tự động hóa kiểm tra chất lượng&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Vị trí cấu hình hooks&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cài đặt toàn cục&lt;/strong&gt;: &lt;code&gt;~/.claude/settings.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cài đặt dự án&lt;/strong&gt;: &lt;code&gt;.claude/settings.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Kỹ thuật triển khai&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng regex để bắt sự kiện sửa đổi file: &lt;code&gt;&amp;quot;Edit|MultiEdit|Write&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Tạo thư mục &lt;code&gt;claude-hooks&lt;/code&gt; chuyên biệt để tổ chức script&lt;/li&gt;
&lt;li&gt;Sử dụng biến môi trường như &lt;code&gt;$CLAUDE_TOOL_INPUT&lt;/code&gt; để truy cập ngữ cảnh thực thi&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Ví dụ thực tiễn - Hook pre-commit&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;hooks&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;PreToolUse&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;matcher&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Bash&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;hooks&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;if echo \&amp;#34;$CLAUDE_TOOL_INPUT\&amp;#34; | jq -r &amp;#39;.command&amp;#39; | grep -q &amp;#39;^git commit&amp;#39;; then ./claude-hooks/precommit.sh; fi&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;timeout&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Lợi ích chính&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tự động hóa kiểm tra chất lượng mã (linting, testing)&lt;/li&gt;
&lt;li&gt;Đảm bảo tuân thủ quy chuẩn dự án&lt;/li&gt;
&lt;li&gt;Kiểm soát chi tiết các thay đổi mã nguồn&lt;/li&gt;
&lt;li&gt;Tích hợp liền mạch với quy trình CI/CD&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hooks mở ra khả năng biến Claude Code từ công cụ hỗ trợ đơn thuần thành một phần tích hợp của quy trình phát triển chuyên nghiệp, đặc biệt hữu ích cho các team cần đảm bảo chất lượng và nhất quán trong phát triển phần mềm.&lt;/p&gt;
&lt;h2 id="what-the-hell-is-getopaque-in-java"&gt;&lt;a class="link" href="https://mlangc.github.io/java/concurrency/2025/08/03/what-the-hell-is-get-opaque.html" target="_blank" rel="noopener"
&gt;What the Hell is GetOpaque in Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một bài viết kỹ thuật sâu về &lt;code&gt;getOpaque()&lt;/code&gt; - phương thức đồng thời ít được biết đến trong Java, khám phá memory ordering và những phức tạp trong lập trình đa luồng. Đây là kiến thức nâng cao về concurrency mà nhiều Java developer chưa từng gặp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Khái niệm Memory Ordering&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;getOpaque()&lt;/code&gt; và &lt;code&gt;setOpaque()&lt;/code&gt; cung cấp chế độ memory ordering yếu&lt;/li&gt;
&lt;li&gt;Đảm bảo các thao tác trên cùng một biến không bị sắp xếp lại&lt;/li&gt;
&lt;li&gt;Cho phép sắp xếp lại các thao tác trên các biến khác nhau&lt;/li&gt;
&lt;li&gt;Tương tự &amp;ldquo;relaxed&amp;rdquo; memory ordering trong C++ và Rust&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Các trường hợp sử dụng thực tiễn&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phát tín hiệu dừng giữa các luồng&lt;/li&gt;
&lt;li&gt;Chia sẻ thông tin tiến độ&lt;/li&gt;
&lt;li&gt;Xuất bản cập nhật cho kiểu dữ liệu nguyên thủy và tham chiếu đối tượng bất biến&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Hạn chế quan trọng&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không an toàn khi xuất bản tham chiếu đến đối tượng có thể thay đổi&lt;/li&gt;
&lt;li&gt;Không đảm bảo mối quan hệ happens-before cho các trường non-final&lt;/li&gt;
&lt;li&gt;Hiệu suất tương tự volatile trong hầu hết trường hợp&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Định nghĩa chính thức&lt;/strong&gt;: &amp;ldquo;Trả về giá trị của một biến, được truy cập theo thứ tự chương trình, nhưng không đảm bảo hiệu ứng memory ordering đối với các luồng khác.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Insight độc đáo&lt;/strong&gt;: Bài viết minh chứng thông qua JCStress tests cách opaque mode có thể dẫn đến hành vi memory ordering không mong đợi, đặc biệt trên kiến trúc ARM.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Khuyến nghị thực tiễn&lt;/strong&gt;: Mặc dù opaque mode có thể được sử dụng để chia sẻ giá trị đơn giản giữa các luồng, &lt;code&gt;volatile&lt;/code&gt; thường là lựa chọn đáng tin cậy hơn do ngữ nghĩa rõ ràng hơn và đảm bảo rộng hơn.&lt;/p&gt;
&lt;p&gt;Bài viết cung cấp cái nhìn sâu sắc về những khía cạnh tinh tế của concurrency trong Java, giúp các lập trình viên hiểu rõ hơn về memory model và các lựa chọn synchronization phù hợp cho từng tình huống cụ thể.&lt;/p&gt;
&lt;h2 id="how-far-can-we-push-ai-autonomy-in-code-generation"&gt;&lt;a class="link" href="https://martinfowler.com/articles/pushing-ai-autonomy.html" target="_blank" rel="noopener"
&gt;How Far Can We Push AI Autonomy in Code Generation?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Martin Fowler khám phá câu hỏi then chốt về mức độ tự trị của AI trong tạo mã, mang đến góc nhìn thực tế về khả năng và hạn chế hiện tại của AI trong phát triển phần mềm doanh nghiệp. Bài viết dựa trên kinh nghiệm thực tiễn và nghiên cứu sâu về AI coding.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nguyên tắc cốt lõi&lt;/strong&gt;: AI chưa sẵn sàng để tự chủ tạo và bảo trì phần mềm doanh nghiệp mà không có sự giám sát của con người.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược cải thiện AI code generation&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stack-specific prompts&lt;/strong&gt;: Sử dụng prompt chuyên biệt cho từng ngăn xếp công nghệ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-agent với vai trò cụ thể&lt;/strong&gt;: Triển khai nhiều agent có chuyên môn riêng biệt&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cung cấp ví dụ mã&lt;/strong&gt;: Đưa code examples vào prompt để hướng dẫn AI&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reference application&lt;/strong&gt;: Sử dụng ứng dụng tham chiếu làm điểm neo&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generate-review loops&lt;/strong&gt;: Vòng lặp tạo-xem xét liên tục&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modularize codebase&lt;/strong&gt;: Tổ chức mã nguồn theo module&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Thách thức dai dẳng với AI&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quá háo hức thêm tính năng không được yêu cầu&lt;/li&gt;
&lt;li&gt;Đưa ra giả định về yêu cầu&lt;/li&gt;
&lt;li&gt;Áp dụng các giải pháp &amp;ldquo;brute force&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Tuyên bố thành công dù test thất bại&lt;/li&gt;
&lt;li&gt;Gây ra vấn đề static code analysis&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Trích dẫn quan trọng từ Andrej Karpathy&lt;/strong&gt;: &amp;ldquo;Chúng ta đang hợp tác với AI, họ tạo ra và con người xác minh. Chúng ta có lợi ích trong việc làm cho vòng lặp này diễn ra nhanh nhất có thể.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Khuyến nghị chiến lược&lt;/strong&gt;: Đầu tư vào cải thiện quy trình xác minh con người và kỹ thuật tăng cường thay vì mong đợi AI tạo mã hoàn toàn tự chủ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kết luận&lt;/strong&gt;: Mặc dù khả năng coding của AI ấn tượng, chúng chưa đủ đáng tin cậy cho phát triển phần mềm hoàn toàn tự động, đặc biệt với các ứng dụng doanh nghiệp phức tạp. Trọng tâm nên là tối ưu hóa vòng lặp human-in-the-loop để tận dụng tối đa sức mạnh của cả AI và con người.&lt;/p&gt;
&lt;h2 id="onboarding-for-coding-agents"&gt;&lt;a class="link" href="https://www.fuzzycomputer.com/posts/onboarding" target="_blank" rel="noopener"
&gt;Onboarding for Coding Agents&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Fuzzy Computer đề xuất một cách tiếp cận thông minh về onboarding - không chỉ cho các thành viên mới mà còn cho AI coding agents. Bài viết mang đến góc nhìn thực tiễn về việc tổ chức ngữ cảnh dự án để cả con người và AI đều có thể hiểu và làm việc hiệu quả.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nguyên tắc cốt lõi&lt;/strong&gt;: &amp;ldquo;Mỗi session Cursor hoặc Claude Code mới giống như một thành viên team mới tham gia dự án với bối cảnh bằng không.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cách tiếp cận ngữ cảnh&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chuyển ngữ cảnh dự án từ các file công cụ cụ thể sang tài liệu README&lt;/li&gt;
&lt;li&gt;Sử dụng quy ước đặt tên README theo module:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;README.md&lt;/code&gt; cho tổng quan dự án cấp cao&lt;/li&gt;
&lt;li&gt;&lt;code&gt;README.&amp;lt;domain&amp;gt;.md&lt;/code&gt; cho ngữ cảnh cụ thể (ví dụ: &lt;code&gt;README.architecture.md&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Triết lý onboarding&lt;/strong&gt;: Coi onboarding như việc chuẩn bị cho cả đồng đội con người và công cụ AI. Tự hỏi: &amp;ldquo;Bạn muốn một thành viên team mới đọc gì trước nhiệm vụ đầu tiên?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Khuyến nghị thực tiễn&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tạo README cung cấp ngữ cảnh toàn diện nhưng tập trung&lt;/li&gt;
&lt;li&gt;Sử dụng &amp;ldquo;Quality Gates&amp;rdquo; để thực thi tiêu chuẩn coding thông qua kiểm tra tự động&lt;/li&gt;
&lt;li&gt;Thiết lập ràng buộc môi trường nghiêm ngặt cho AI coding agents&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Ví dụ triển khai&lt;/strong&gt;: File &lt;code&gt;CLAUDE.md&lt;/code&gt; gọn 13 dòng hướng dẫn AI:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đọc tất cả tài liệu &lt;code&gt;**/README.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Đọc tất cả tài liệu &lt;code&gt;**/README.*.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Vượt qua các kiểm tra chất lượng cụ thể (type checking, formatting, linting, testing)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Lợi ích&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giảm thời gian onboarding cho cả con người và AI&lt;/li&gt;
&lt;li&gt;Đảm bảo tính nhất quán trong hiểu biết về dự án&lt;/li&gt;
&lt;li&gt;Tự động hóa việc thực thi tiêu chuẩn chất lượng&lt;/li&gt;
&lt;li&gt;Tạo ra tài liệu sống luôn được cập nhật&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cách tiếp cận này nhấn mạnh giao tiếp rõ ràng, tài liệu module và sử dụng công cụ để thực thi tiêu chuẩn chất lượng khi onboarding cả thành viên team con người và AI.&lt;/p&gt;
&lt;h2 id="why-java-is-still-worth-learning-in-2025-a-developer"&gt;&lt;a class="link" href="https://foojay.io/today/why-java-is-still-worth-learning-in-2025-a-developers-25-year-journey/" target="_blank" rel="noopener"
&gt;Why Java is Still Worth Learning in 2025: A Developer&amp;rsquo;s 25-Year Journey&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một lập trình viên với 25 năm kinh nghiệm chia sẻ hành trình thay đổi quan điểm về Java - từ nghi ngờ ban đầu đến việc khuyến nghị mạnh mẽ Java như một lựa chọn sự nghiệp dài hạn trong năm 2025. Bài viết mang đến góc nhìn thực tiễn về giá trị bền vững của Java.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sự tiến hóa liên tục&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java đã biến đổi từ ngôn ngữ tác giả ban đầu không tin tưởng thành ngôn ngữ được khuyến nghị mạnh mẽ&lt;/li&gt;
&lt;li&gt;Các tính năng Java hiện đại giảm cognitive load và làm mã dễ đọc hơn&lt;/li&gt;
&lt;li&gt;Những cải tiến liên tục phù hợp với nhu cầu thực tế của lập trình viên&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Góc nhìn nghề nghiệp&lt;/strong&gt;: Java cung cấp &amp;ldquo;sự ổn định mà không stagnation, đổi mới mà không disruption&amp;rdquo;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khả năng tương thích ngược nghĩa là kỹ năng học hôm nay vẫn có giá trị trong nhiều thập kỷ&lt;/li&gt;
&lt;li&gt;Hệ sinh thái đa dạng với nhiều JDK distribution và framework&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Giá trị dài hạn&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thiết yếu cho các công nghệ mới nổi như AI và cloud-native applications&lt;/li&gt;
&lt;li&gt;Hỗ trợ cộng đồng mạnh mẽ và chia sẻ kiến thức&lt;/li&gt;
&lt;li&gt;Tính năng như virtual threads và pattern matching cải thiện năng suất lập trình viên&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Lý do học Java trong 2025&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nền tảng phát triển enterprise vững chắc&lt;/li&gt;
&lt;li&gt;Khả năng thiết kế cloud-native&lt;/li&gt;
&lt;li&gt;Hệ sinh thái và hỗ trợ cộng đồng rộng lớn&lt;/li&gt;
&lt;li&gt;Cải tiến ngôn ngữ liên tục&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Lộ trình học tập được khuyến nghị&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bắt đầu với Java hiện đại (phiên bản 17/21)&lt;/li&gt;
&lt;li&gt;Tập trung vào kiến thức nền tảng&lt;/li&gt;
&lt;li&gt;Xây dựng dự án thực tế&lt;/li&gt;
&lt;li&gt;Tham gia các nhóm cộng đồng&lt;/li&gt;
&lt;li&gt;Nắm bắt hệ sinh thái&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Trích dẫn quan trọng&lt;/strong&gt;: &amp;ldquo;Năm 2025, Java cung cấp điều hiếm có trong thế giới công nghệ: sự ổn định mà không trì trệ, đổi mới mà không gián đoạn.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lời khuyên thực tiễn&lt;/strong&gt;: Đầu tư thời gian học Java như một chiến lược sự nghiệp dài hạn, tập trung vào các tính năng hiện đại và phát triển ứng dụng thực tế.&lt;/p&gt;
&lt;p&gt;Bài viết khẳng định Java không chỉ sống sót mà còn phát triển mạnh trong bối cảnh công nghệ thay đổi nhanh chóng, mang lại cơ hội nghề nghiệp bền vững cho các lập trình viên.&lt;/p&gt;
&lt;h2 id="why-you-should-rethink-legacy-and-consider-event-driven-architecture"&gt;&lt;a class="link" href="https://blog.scottlogic.com/2025/08/06/rethink-legacy-consider-event-driven-architecture.html" target="_blank" rel="noopener"
&gt;Why You Should Rethink Legacy and Consider Event-Driven Architecture&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Scott Logic đề xuất một cách tiếp cận thực tiễn để hiện đại hóa hệ thống cũ thông qua Event-Driven Architecture (EDA). Thay vì coi legacy system như gánh nặng cần thay thế hoàn toàn, bài viết khuyến khích nhìn nhận chúng như cơ hội để phát triển kiến trúc linh hoạt hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nguyên tắc cốt lõi&lt;/strong&gt;: &amp;ldquo;Legacy không chỉ là về tuổi tác. Căn bản là về việc liệu hệ thống có đang làm chậm doanh nghiệp của bạn hay không.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lợi ích của Event-Driven Architecture&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Hiện đại hóa từng bước&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cho phép tiến hóa hệ thống từ từ mà không cần viết lại hoàn toàn&lt;/li&gt;
&lt;li&gt;Cho phép thêm chức năng mới xung quanh các hệ thống hiện có&lt;/li&gt;
&lt;li&gt;Giảm rủi ro bằng cách tránh gián đoạn các hệ thống ổn định&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. Lợi ích kỹ thuật&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cung cấp khả năng mở rộng thông qua các dịch vụ tách rời&lt;/li&gt;
&lt;li&gt;Hỗ trợ xử lý bất đồng bộ, song song&lt;/li&gt;
&lt;li&gt;Cải thiện tính phục hồi của hệ thống&lt;/li&gt;
&lt;li&gt;Tăng cường khả năng kiểm thử và quan sát&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược triển khai&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng Change Data Capture (CDC) để giám sát cơ sở dữ liệu legacy&lt;/li&gt;
&lt;li&gt;Tạo các dịch vụ hiện đại subscribe events từ hệ thống legacy&lt;/li&gt;
&lt;li&gt;Ví dụ: Thêm dịch vụ email chào mừng mà không cần sửa đổi hệ thống legacy cốt lõi&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cân nhắc thực tiễn&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không phù hợp với mọi tình huống, đặc biệt các quy trình có trạng thái cao hoặc kết hợp chặt chẽ&lt;/li&gt;
&lt;li&gt;Yêu cầu hệ thống cơ sở dữ liệu tương thích để phát sự kiện&lt;/li&gt;
&lt;li&gt;Sử dụng tốt nhất như một phần của khả năng hiện đại hóa đang diễn ra&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Khuyến nghị quan trọng&lt;/strong&gt;: &amp;ldquo;Legacy IT không chỉ đơn giản là về tuổi tác - mà là về tác động&amp;rdquo; và EDA cung cấp con đường thực dụng cho sự tiến hóa hệ thống.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ví dụ thực tiễn&lt;/strong&gt;: Thay vì viết lại toàn bộ hệ thống đăng ký khách hàng, có thể sử dụng CDC để bắt sự kiện &amp;ldquo;khách hàng mới được tạo&amp;rdquo; và kích hoạt các dịch vụ hiện đại như gửi email chào mừng, cập nhật CRM, hoặc phân tích dữ liệu.&lt;/p&gt;
&lt;p&gt;Cách tiếp cận này mang lại sự cân bằng giữa việc tận dụng đầu tư hiện có và phát triển khả năng mới, giúp tổ chức tiến hóa kiến trúc một cách có kiểm soát và hiệu quả.&lt;/p&gt;</description></item><item><title>Newsletter #49</title><link>https://miti99.com/post/2025/08/08/</link><pubDate>Fri, 08 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/08/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #49.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="postgresql-at-scale-database-schema-changes-without-downtime"&gt;&lt;a class="link" href="https://medium.com/paypal-tech/postgresql-at-scale-database-schema-changes-without-downtime-20d3749ed680" target="_blank" rel="noopener"
&gt;PostgreSQL at Scale: Database Schema Changes Without Downtime&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ đội ngũ kỹ thuật PayPal chia sẻ kinh nghiệm thực thi thay đổi lược đồ cơ sở dữ liệu PostgreSQL ở quy mô lớn mà không gây gián đoạn dịch vụ. Đây là một thách thức lớn đối với các hệ thống có lưu lượng truy cập cao và yêu cầu hoạt động liên tục 24/7.&lt;/p&gt;
&lt;p&gt;PayPal đã phát triển một bộ công cụ và quy trình để thực hiện các thay đổi lược đồ một cách an toàn, bao gồm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Phương pháp thay đổi từng bước&lt;/strong&gt;: Thay vì thực hiện các thay đổi lớn một lần, họ chia nhỏ thành nhiều bước nhỏ có thể hoàn tác&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Công cụ tự động hóa&lt;/strong&gt;: Phát triển các script và công cụ để tự động hóa quá trình di chuyển và kiểm tra tính nhất quán dữ liệu&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chiến lược rollback&lt;/strong&gt;: Luôn có kế hoạch hoàn tác rõ ràng cho mọi thay đổi&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Giám sát liên tục&lt;/strong&gt;: Theo dõi hiệu suất và tình trạng hệ thống trong suốt quá trình thay đổi&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết cung cấp những bài học kinh nghiệm quý báu cho các kỹ sư làm việc với cơ sở dữ liệu quy mô lớn, đặc biệt là trong môi trường sản xuất có yêu cầu độ tin cậy cao.&lt;/p&gt;
&lt;h2 id="the-big-llm-architecture-comparison-from-deepseek-v3-to-kimi-k2"&gt;&lt;a class="link" href="https://magazine.sebastianraschka.com/p/the-big-llm-architecture-comparison" target="_blank" rel="noopener"
&gt;The Big LLM Architecture Comparison: From DeepSeek-V3 to Kimi K2&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Sebastian Raschka, tác giả của cuốn &amp;ldquo;Machine Learning with PyTorch and Scikit-Learn&amp;rdquo;, đã thực hiện một so sánh toàn diện về kiến trúc của các mô hình ngôn ngữ lớn hiện đại. Bài viết phân tích chi tiết 5 kiến trúc chính đang định hình tương lai của AI:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DeepSeek V3/R1&lt;/strong&gt; sử dụng Multi-Head Latent Attention (MLA) kết hợp với Mixture-of-Experts (MoE) có 256 chuyên gia, chỉ kích hoạt 9 chuyên gia cho mỗi lần suy luận với 37 tỷ tham số.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OLMo 2&lt;/strong&gt; nổi bật với cách bố trí lớp chuẩn hóa độc đáo, sử dụng RMSNorm với cấu hình &amp;ldquo;Post-Norm&amp;rdquo; và giới thiệu QK-Norm để tăng tính ổn định của attention.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gemma 3&lt;/strong&gt; áp dụng sliding window attention giúp giảm sử dụng bộ nhớ KV cache, kết hợp cả Pre-Norm và Post-Norm RMSNorm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Qwen3&lt;/strong&gt; cung cấp cả biến thể dense (0.6B đến 32B tham số) và MoE (30B-A3B và 235B-A22B), cho phép lựa chọn linh hoạt theo nhu cầu tính toán.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kimi 2&lt;/strong&gt; với 1 nghìn tỷ tham số, dựa trên kiến trúc DeepSeek V3 nhưng sử dụng ít đầu attention hơn trong Multi-Head Latent Attention.&lt;/p&gt;
&lt;p&gt;Bài viết nhấn mạnh xu hướng tăng cường sử dụng MoE, các cơ chế attention sáng tạo và tập trung vào hiệu quả suy luận. Đây là tài liệu tham khảo quan trọng cho các lập trình viên muốn hiểu rõ sự phát triển của kiến trúc LLM và lựa chọn mô hình phù hợp với ràng buộc tính toán cụ thể.&lt;/p&gt;
&lt;h2 id="from-asyncawait-to-virtual-threads"&gt;&lt;a class="link" href="https://lucumr.pocoo.org/2025/7/26/virtual-threads/" target="_blank" rel="noopener"
&gt;From Async/Await to Virtual Threads&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Armin Ronacher, tác giả của Flask và Jinja, đã đề xuất một tầm nhìn độc đáo về tương lai của lập trình đồng thời trong Python thông qua &amp;ldquo;virtual threads&amp;rdquo; - một thay thế tiềm năng cho mô hình async/await hiện tại.&lt;/p&gt;
&lt;p&gt;Vấn đề cốt lõi mà virtual threads muốn giải quyết là &amp;ldquo;colored functions&amp;rdquo; - hiện tượng các hàm async và sync không thể tương tác trực tiếp, tạo ra sự phức tạp và chia cắt trong hệ sinh thái thư viện.&lt;/p&gt;
&lt;p&gt;Kỹ thuật virtual threads sẽ chuyển độ phức tạp của lập trình đồng thời vào các API nội bộ của trình thông dịch, cung cấp:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hủy bỏ tự động&lt;/strong&gt;: Hỗ trợ cancellation mà không cần quản lý thủ công&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kế thừa ngữ cảnh&lt;/strong&gt;: Context được truyền tự động giữa các virtual thread&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kiểm soát đồng thời&lt;/strong&gt;: Giới hạn số lượng thread đồng thời một cách dễ dàng&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ví dụ về cách sử dụng:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;download_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;ThreadGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_concurrency&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;download_and_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Đây hiện tại chỉ là &amp;ldquo;đề xuất thảo luận&amp;rdquo; nhưng thể hiện tầm nhìn tiền phong về việc đơn giản hóa lập trình đồng thời, giảm tải trí tuệ cho lập trình viên và cải thiện hiệu suất thông qua cơ chế điều phối virtual thread của runtime.&lt;/p&gt;
&lt;h2 id="six-principles-for-production-ai-agents"&gt;&lt;a class="link" href="https://www.app.build/blog/six-principles-production-ai-agents" target="_blank" rel="noopener"
&gt;Six Principles for Production AI Agents&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Với sự phát triển mạnh mẽ của các AI Agent trong thực tế, việc đưa chúng vào sản xuất đòi hỏi những nguyên tắc thiết kế chắc chắn. Bài viết này trình bày 6 nguyên tắc cốt lõi để xây dựng AI Agent hoạt động ổn định trong môi trường sản xuất:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Đầu tư vào System Prompt&lt;/strong&gt;: Tập trung vào hướng dẫn rõ ràng, trực tiếp. Các mô hình hiện đại chỉ cần ngữ cảnh chi tiết và không mâu thuẫn, không cần các thủ thuật phức tạp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Tách biệt Ngữ cảnh&lt;/strong&gt;: Cung cấp kiến thức ban đầu tối thiểu, cho phép các công cụ lấy thêm ngữ cảnh khi cần. Sử dụng &amp;ldquo;nén ngữ cảnh&amp;rdquo; để quản lý độ phức tạp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Thiết kế Công cụ Cẩn thận&lt;/strong&gt;: Tạo các công cụ tập trung, được kiểm thử kỹ lưỡng. Giới hạn số lượng công cụ với tham số rõ ràng và đảm bảo tính idempotency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Thiết kế Vòng phản hồi&lt;/strong&gt;: Sử dụng phương pháp actor-critic, cho phép tạo ra sáng tạo nhưng có kiểm chứng nghiêm ngặt. Bao gồm kiểm chứng chuyên biệt cho từng lĩnh vực.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Phân tích Lỗi bằng LLM&lt;/strong&gt;: Sử dụng nhiều agent để phân tích log và quỹ đạo hoạt động, dùng LLM để xác định các khu vực cần cải thiện.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6. Nhận diện Hành vi gây bực xúc như Lỗi hệ thống&lt;/strong&gt;: Hiểu rằng agent có thể &amp;ldquo;hack&amp;rdquo; các hướng dẫn. Debug thiết kế hệ thống trước khi đổ lỗi cho mô hình.&lt;/p&gt;
&lt;p&gt;Kết luận quan trọng: &amp;ldquo;Xây dựng AI Agent hiệu quả không phải là tìm giải pháp vạn năng&amp;hellip; mà là thiết kế hệ thống và kỹ thuật phần mềm đúng đắn.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="working-effectively-with-ai-coding-tools-like-claude-code"&gt;&lt;a class="link" href="https://sajalsharma.com/posts/effective-ai-coding/" target="_blank" rel="noopener"
&gt;Working Effectively with AI Coding Tools like Claude Code&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Sajal Sharma, với kinh nghiệm phong phú trong việc sử dụng các công cụ AI coding, đã tổng hợp những thực tiễn tốt nhất để làm việc hiệu quả với AI trong phát triển phần mềm. Bài viết đặc biệt có giá trị khi AI coding tools ngày càng trở thành công cụ không thể thiếu trong quy trình phát triển.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thay đổi tư duy&lt;/strong&gt;: Thay vì tập trung vào việc viết mã trực tiếp, hãy ưu tiên thiết kế kiến trúc và hệ thống. Coi đặc tả kỹ thuật như sản phẩm quan trọng và xem AI như một &amp;ldquo;cặp lập trình viên&amp;rdquo; cần được hướng dẫn và xem xét kỹ lưỡng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kiểm soát chất lượng&lt;/strong&gt;: Luôn xem xét tích cực mã do AI tạo ra, tin vào trực giác khi cảm thấy có gì đó không ổn. Đặc biệt chú ý đến các lối tắt tiềm ẩn như việc lạm dụng kiểu &lt;code&gt;any&lt;/code&gt; và thường xuyên kiểm tra, dọn dẹp nợ kỹ thuật.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kỹ thuật hợp tác&lt;/strong&gt;: Cực kỳ cụ thể trong các prompt AI, yêu cầu giải thích cho các giải pháp được đề xuất. Sử dụng nhiều mô hình AI để kiểm tra chéo và tạo các lệnh slash chung cho team để chuẩn hóa quy trình làm việc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tối ưu hóa quy trình&lt;/strong&gt;: Áp dụng phương pháp &amp;ldquo;lập kế hoạch trước&amp;rdquo;, quản lý ngữ cảnh cuộc trò chuyện cẩn thận, duy trì tài liệu đầy đủ và phát triển kiến trúc đa-agent cho các dự án phức tạp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Giá trị con người vẫn quan trọng&lt;/strong&gt;: Tập trung vào tư duy chiến lược và giao tiếp với các bên liên quan. Chia nhỏ tác vụ phức tạp thành đặc tả rõ ràng, cung cấp bối cảnh kinh doanh và đưa ra các quyết định quan trọng.&lt;/p&gt;
&lt;p&gt;Lời khuyên thiết thực: Tạo file &lt;code&gt;CLAUDE.md&lt;/code&gt; để ghi lại ngữ cảnh dự án, tiêu chuẩn coding và các lệnh thường dùng cho AI assistant. Đội ngũ thành công là những ai coi AI như đối tác mạnh mẽ, không phải là thay thế hay đối thủ cạnh tranh.&lt;/p&gt;
&lt;h2 id="when-software-engineers-think-they-need-more-focus-time"&gt;&lt;a class="link" href="https://jola.dev/posts/enough-focus-time" target="_blank" rel="noopener"
&gt;When Software Engineers Think They Need More Focus Time&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Jola Dev đặt ra một câu hỏi thách thức quan niệm truyền thống về năng suất lập trình viên: Liệu &amp;ldquo;thời gian tập trung&amp;rdquo; có thực sự là thứ các kỹ sư phần mềm cần nhiều hơn? Bài viết mang đến góc nhìn mới mẻ về việc tái định nghĩa năng suất trong ngành công nghệ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tái định nghĩa năng suất&lt;/strong&gt;: Năng suất không phải là thời gian code không bị gián đoạn. Công việc của lập trình viên là tạo ra tác động, giải quyết vấn đề, mang lại giá trị có ý nghĩa. Những công việc có giá trị cao nhất thường xảy ra bên ngoài việc viết mã trực tiếp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các hoạt động có giá trị nhất của lập trình viên&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đặt câu hỏi làm rõ vấn đề&lt;/li&gt;
&lt;li&gt;Xem xét tài liệu thiết kế&lt;/li&gt;
&lt;li&gt;Lập trình theo cặp (pair programming)&lt;/li&gt;
&lt;li&gt;Sẵn sàng tư vấn nhanh cho đồng nghiệp&lt;/li&gt;
&lt;li&gt;Kiểm tra các giả định sản phẩm&lt;/li&gt;
&lt;li&gt;Chạy thử nghiệm và thí nghiệm&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Kỹ thuật quản lý thời gian thực tiễn&lt;/strong&gt;: Chỉ định các khoảng thời gian tập trung cụ thể (ví dụ: làm việc sâu vào buổi sáng), gộp các cuộc họp vào những ngày nhất định, truyền đạt rõ ràng về tính sẵn có, ưu tiên học hỏi và hợp tác nhóm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Triết lý cốt lõi&lt;/strong&gt;: &amp;ldquo;Mục tiêu không phải là viết mã. Mục tiêu là giải quyết vấn đề.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Phương pháp được khuyến nghị là duy trì kết nối với nhóm, đặt câu hỏi chiến lược, biết khi nào nên code và khi nào nên hợp tác, tối ưu hóa cho tác động tổng thể của nhóm và sản phẩm thay vì thời gian code cá nhân. Bài viết nhắc nhở rằng giá trị thực sự của một lập trình viên không chỉ nằm ở số dòng code mà ở khả năng tạo ra tác động tích cực cho tổ chức và người dùng.&lt;/p&gt;
&lt;h2 id="making-postgres-42000x-slower-because-i-am-unemployed"&gt;&lt;a class="link" href="https://byteofdev.com/posts/making-postgres-slow/" target="_blank" rel="noopener"
&gt;Making Postgres 42,000x slower because I am unemployed&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một bài viết hài hước nhưng đầy tính giáo dục từ Byte of Dev, minh họa cách những thay đổi cấu hình tưởng chừng nhỏ có thể làm giảm hiệu suất PostgreSQL một cách đáng kinh ngạc. Tác giả đã &amp;ldquo;thành công&amp;rdquo; làm chậm PostgreSQL từ 7,082 giao dịch/giây xuống chỉ còn 0.016 giao dịch/giây.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các vấn đề hiệu suất phổ biến&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cấu hình buffer cache không hiệu quả&lt;/li&gt;
&lt;li&gt;Hoạt động autovacuum quá thường xuyên&lt;/li&gt;
&lt;li&gt;Ghi Write-Ahead Logging (WAL) quá mức&lt;/li&gt;
&lt;li&gt;Xử lý I/O không tối ưu&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Các anti-pattern được minh họa&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giảm shared buffer cache từ 10GB xuống 8MB&lt;/li&gt;
&lt;li&gt;Thiết lập autovacuum quá aggressive gây ra bảo trì liên tục&lt;/li&gt;
&lt;li&gt;WAL checkpoint quá thường xuyên&lt;/li&gt;
&lt;li&gt;Buộc tất cả I/O qua một thread duy nhất&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tham số cấu hình quan trọng&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;shared_buffers&lt;/code&gt;: Kiểm soát bộ nhớ cho database page caching&lt;/li&gt;
&lt;li&gt;Các tham số &lt;code&gt;autovacuum_*&lt;/code&gt;: Quản lý bảo trì tự động&lt;/li&gt;
&lt;li&gt;Các tham số &lt;code&gt;wal_*&lt;/code&gt;: Kiểm soát hành vi Write-Ahead Logging&lt;/li&gt;
&lt;li&gt;&lt;code&gt;random_page_cost&lt;/code&gt;: Ảnh hưởng đến query planning và sử dụng index&lt;/li&gt;
&lt;li&gt;&lt;code&gt;io_method&lt;/code&gt; và &lt;code&gt;io_workers&lt;/code&gt;: Xác định chiến lược xử lý I/O&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Thực tiễn tốt nhất&lt;/strong&gt; (được ngụ ý):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Điều chỉnh cẩn thận &lt;code&gt;shared_buffers&lt;/code&gt; phù hợp với workload&lt;/li&gt;
&lt;li&gt;Cấu hình autovacuum với ngưỡng hợp lý&lt;/li&gt;
&lt;li&gt;Tối ưu hóa WAL và checkpoint settings&lt;/li&gt;
&lt;li&gt;Sử dụng xử lý I/O song song&lt;/li&gt;
&lt;li&gt;Giám sát và điều chỉnh cấu hình database dựa trên đặc điểm workload cụ thể&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết là một lời nhắc nhở thú vị về tầm quan trọng của việc hiểu rõ cấu hình PostgreSQL và tác động của nó đến hiệu suất hệ thống.&lt;/p&gt;
&lt;h2 id="stack-overflow-developer-survey-2025"&gt;&lt;a class="link" href="https://survey.stackoverflow.co/2025/" target="_blank" rel="noopener"
&gt;Stack Overflow Developer Survey 2025&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Khảo sát Developer Survey 2025 của Stack Overflow đã thu thập 49,009 phản hồi từ 166 quốc gia, bao gồm 314 công nghệ khác nhau trong khoảng thời gian từ 29/5 đến 23/6/2025. Đây là một trong những khảo sát toàn diện nhất về cộng đồng lập trình viên thế giới.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI và Công nghệ&lt;/strong&gt;: 84% lập trình viên đang sử dụng hoặc có kế hoạch sử dụng công cụ AI, tuy nhiên tình cảm tích cực về AI đã giảm xuống còn 60% trong năm 2025. Đáng chú ý, &amp;ldquo;nhiều lập trình viên không tin tưởng vào độ chính xác của công cụ AI hơn là tin tưởng.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bối cảnh Lập trình viên&lt;/strong&gt;: 76% là lập trình viên chuyên nghiệp, 35% có kinh nghiệm lập trình dưới 10 năm. Các quốc gia có nhiều phản hồi nhất là Mỹ, Đức và Ấn Độ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Công việc và Sự hài lòng&lt;/strong&gt;: Gần một phần ba lập trình viên làm việc từ xa, chỉ 24% hài lòng với công việc hiện tại. Các yếu tố hàng đầu tạo sự hài lòng trong công việc là &amp;ldquo;quyền tự chủ/tin cậy, lương cạnh tranh và giải quyết các vấn đề thực tế.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Xu hướng Công nghệ&lt;/strong&gt;: Python tăng trưởng đáng kể về mức độ áp dụng, Visual Studio và Visual Studio Code vẫn là các môi trường phát triển hàng đầu, các mô hình OpenAI GPT được sử dụng rộng rãi nhất trong các mô hình ngôn ngữ lớn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thông tin về Cộng đồng&lt;/strong&gt;: 82% truy cập Stack Overflow ít nhất hàng tháng, các lập trình viên trẻ tuổi thích các định dạng nội dung tương tác hơn. Khảo sát cho thấy &amp;ldquo;lập trình viên ở mọi cấp độ đều đang khám phá bối cảnh AI đang phát triển nhanh chóng.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Khảo sát này cung cấp cái nhìn toàn diện về tình trạng hiện tại và xu hướng tương lai của ngành công nghệ, đặc biệt là tác động ngày càng tăng của AI trong quy trình phát triển phần mềm.&lt;/p&gt;
&lt;h2 id="choose-boring-technology-revisited"&gt;&lt;a class="link" href="https://www.brethorsting.com/blog/2025/07/choose-boring-technology,-revisited/" target="_blank" rel="noopener"
&gt;Choose Boring Technology, Revisited&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bret Horsting nhìn lại nguyên tắc &amp;ldquo;Chọn công nghệ nhàm chán&amp;rdquo; trong bối cảnh thời đại AI, mang đến góc nhìn cập nhật về việc lựa chọn công nghệ trong môi trường phát triển phần mềm hiện đại. Bài viết đặc biệt có giá trị khi các công cụ AI coding ngày càng phổ biến.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nguyên tắc cốt lõi&lt;/strong&gt;: Giới hạn &amp;ldquo;innovation tokens&amp;rdquo; bằng cách chọn các công nghệ đã được thiết lập và hiểu rõ. Thay vì theo đuổi những công nghệ mới nhất, hãy tập trung vào những công nghệ có chế độ lỗi đã biết, khả năng được hiểu rõ và độ tin cậy vận hành đã được chứng minh.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Khung ra quyết định&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khi giải quyết vấn đề: Tuân thủ các công nghệ đã biết&lt;/li&gt;
&lt;li&gt;Khi học hỏi: Giới hạn mình ở một công nghệ mới duy nhất&lt;/li&gt;
&lt;li&gt;Ưu tiên các công nghệ có chế độ lỗi đã biết, khả năng được hiểu rõ và độ tin cậy vận hành đã chứng minh&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cân nhắc trong thời đại AI&lt;/strong&gt;: Các công cụ AI coding có thể tạo ra mã hợp lý, nhưng không thể thay thế sự hiểu biết sâu sắc về công nghệ. Nguy hiểm khi kết hợp nhiều công nghệ chưa biết với mã do AI tạo ra. AI trở nên mạnh mẽ nhất khi được sử dụng với các công nghệ bạn đã hiểu rõ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hướng dẫn thực tiễn&lt;/strong&gt;: Trước khi áp dụng công nghệ mới, hãy tự hỏi: &amp;ldquo;Tôi có thể xem xét đầy đủ mã triển khai do AI tạo ra không?&amp;rdquo; Hiểu sâu các công nghệ mới trước khi sử dụng hỗ trợ AI, tránh học đồng thời nhiều công nghệ mới, nhận ra rằng mã do AI tạo ra có thể trông chuyên nghiệp nhưng chứa lỗi tiềm ẩn.&lt;/p&gt;
&lt;p&gt;Câu trích dẫn then chốt: &amp;ldquo;Công nghệ nhàm chán nhất trong stack của bạn có thể chính là công nghệ bạn hiểu đủ rõ để biết khi nào AI sai.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Lời khuyên tổng quát là ưu tiên sự hiểu biết công nghệ hơn tính mới lạ, và sử dụng AI như một bộ nhân tốc cho kiến thức hiện có thay vì thay thế cho việc học hỏi căn bản.&lt;/p&gt;
&lt;h2 id="agentic-coding-things-that-didn"&gt;&lt;a class="link" href="https://lucumr.pocoo.org/2025/7/30/things-that-didnt-work/" target="_blank" rel="noopener"
&gt;Agentic Coding Things That Didn&amp;rsquo;t Work&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Armin Ronacher chia sẻ thẳng thắn về những thất bại trong việc áp dụng AI coding agents, mang đến những bài học quý báu từ thực tiễn. Thay vì tập trung vào thành công, bài viết này khám phá những gì không hiệu quả và tại sao - một góc nhìn hiếm có trong làn sóng hype về AI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nguyên tắc tự động hóa&lt;/strong&gt;: Chỉ tự động hóa các tác vụ được thực hiện thường xuyên và xóa bỏ các workflow tự động không được sử dụng nhất quán. &amp;ldquo;Tôi chỉ tự động hóa những thứ tôi làm thường xuyên.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các lần thử tự động hóa thất bại&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/fix-bug&lt;/code&gt;: Không cải thiện đáng kể so với thảo luận thủ công về vấn đề&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/commit&lt;/code&gt;: Thông điệp commit không bao giờ khớp với phong cách cá nhân&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/add-tests&lt;/code&gt;: Tạo test không nhất quán tốt hơn&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/fix-nits&lt;/code&gt;: Các lệnh linting trở nên dư thừa&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Bài học về quy trình&lt;/strong&gt;: Speech-to-text và chia sẻ ngữ cảnh hiệu quả hơn tự động hóa phức tạp. Copy/paste vẫn là phương pháp đơn giản nhưng mạnh mẽ. Hook và print mode có tiềm năng nhưng hiện tại thiếu độ tin cậy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cảnh báo quan trọng về AI workflow&lt;/strong&gt;: &amp;ldquo;Có một rủi ro ẩn lớn với tự động hóa thông qua LLM: nó khuyến khích sự vô cảm tinh thần.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược đánh giá&lt;/strong&gt;: Kiểm tra tự động hóa bằng cách thực hiện tác vụ nhiều lần, đánh giá thủ công sự khác biệt và mức độ chấp nhận kết quả, duy trì tư duy kỹ sư tích cực trong công việc có hỗ trợ AI.&lt;/p&gt;
&lt;p&gt;Bài học cốt lõi: Tính đơn giản và sự tham gia của con người quan trọng hơn các quy trình tự động phức tạp. Liên tục đánh giá và sẵn sàng loại bỏ các công cụ không hiệu quả. Đây là lời nhắc nhở có giá trị về việc duy trì tư duy phê phán khi làm việc với AI.&lt;/p&gt;
&lt;h2 id="vibe-code-is-legacy-code"&gt;&lt;a class="link" href="https://blog.val.town/vibe-code" target="_blank" rel="noopener"
&gt;Vibe Code is Legacy Code&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Val Town mang đến một quan điểm thú vị và có phần gây tranh cãi về &amp;ldquo;Vibe Code&amp;rdquo; - thuật ngữ mô tả cách lập trình với sự hỗ trợ AI mà bạn &amp;ldquo;quên rằng mã nguồn còn tồn tại&amp;rdquo;. Bài viết này khám phá những ưu nhược điểm của phương pháp này và đặt ra câu hỏi về tương lai của việc phát triển phần mềm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Khái niệm&lt;/strong&gt;: Vibe coding là lập trình có sự hỗ trợ AI với mức độ hiểu biết tối thiểu về mã nguồn. Đây là một phổ của sự hiểu biết mã, từ hiểu biết tối thiểu đến kiến thức sâu sắc. Phù hợp nhất cho prototype và các dự án dùng một lần.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ứng dụng thực tiễn&lt;/strong&gt;: Phát triển nhanh các ứng dụng nhỏ, có mục đích duy nhất; prototype nhanh; các dự án cá nhân không yêu cầu bảo trì dài hạn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Triết lý cốt lõi&lt;/strong&gt;: Lập trình về cơ bản là &amp;ldquo;xây dựng lý thuyết&amp;rdquo;, không chỉ đơn thuần tạo ra mã. Vibe coding có thể nhanh chóng tạo ra nợ kỹ thuật nếu sử dụng không phù hợp, đòi hỏi quản lý cẩn thận, đặc biệt cho các dự án nghiêm túc, dài hạn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cảnh báo quan trọng&lt;/strong&gt;: &amp;ldquo;Khi bạn vibe code, bạn đang tích lũy nợ kỹ thuật nhanh như tốc độ LLM có thể tạo ra nó.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lời khuyên thận trọng&lt;/strong&gt;: Tránh sử dụng vibe coding cho phần mềm phức tạp, được bảo trì; hiểu cấu trúc và logic cơ bản của mã; coi AI như một &amp;ldquo;thực tập sinh cấp dưới&amp;rdquo; cần giám sát cẩn thận.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phương pháp được khuyến nghị&lt;/strong&gt;: Sử dụng các công cụ AI như &amp;ldquo;Townie&amp;rdquo; một cách chiến lược, duy trì &amp;ldquo;kiểm soát chặt chẽ&amp;rdquo; với mã do AI tạo ra, ưu tiên hiểu biết và học hỏi hơn việc tạo ra nhanh chóng.&lt;/p&gt;
&lt;p&gt;Bài viết nhấn mạnh rằng mặc dù vibe coding có thể hữu ích, nhưng nó không phải là sự thay thế cho chuyên môn kỹ thuật phần mềm thực sự. Đây là một lời nhắc nhở cân bằng về việc sử dụng AI trong phát triển phần mềm.&lt;/p&gt;</description></item><item><title>Newsletter #48</title><link>https://miti99.com/post/2025/08/07/</link><pubDate>Thu, 07 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/07/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #48.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="todos-aren"&gt;&lt;a class="link" href="https://sophiebits.com/2025/07/21/todos-arent-for-doing" target="_blank" rel="noopener"
&gt;TODOs aren&amp;rsquo;t for doing&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Sophie Alpert đưa ra một góc nhìn thú vị về comment TODO trong mã nguồn: chúng không chỉ đơn thuần là danh sách việc cần làm mà còn đóng vai trò như &amp;ldquo;một mảnh nhỏ trong tâm trí của tác giả&amp;rdquo; - giúp lưu giữ ngữ cảnh và suy nghĩ ban đầu khi viết mã.&lt;/p&gt;
&lt;p&gt;Điểm mấu chốt của bài viết là phân biệt giữa TODO tốt và xấu. TODO xấu thường mang tính chất cấp bách và mơ hồ như &amp;ldquo;Viết phần còn lại của file này để launch tuần tới không bị sập&amp;rdquo;, trong khi TODO tốt lại ghi chú những edge case hoặc ý tưởng cải tiến như &amp;ldquo;Nếu người dùng click ba lần vào nút này, click handler sẽ báo lỗi&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Giá trị thực sự của TODO comments nằm ở khả năng truyền tải hiểu biết và suy nghĩ của lập trình viên cho người đọc mã trong tương lai. Chúng có thể trả lời những câu hỏi kiểu như &amp;ldquo;Có phải tôi đang hiểu nhầm gì không, hay đoạn mã này thật sự nên được tái cấu trúc theo cách khác?&amp;rdquo; Thay vì xem TODO như gánh nặng phải hoàn thành, hãy coi chúng như công cụ documentation giúp bảo tồn kiến thức và ngữ cảnh trong dự án.&lt;/p&gt;
&lt;h2 id="automating-away-claude"&gt;&lt;a class="link" href="https://writeaheadblogg.ing/posts/claude-hooks-auto-fix-trailing-whitespace/" target="_blank" rel="noopener"
&gt;Automating Away Claude&amp;rsquo;s Bad Habits with Hooks&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một bài viết thực tế về cách sử dụng Claude Code hooks để tự động sửa lỗi trailing whitespace trong các file Ruby. Đây là một ví dụ tuyệt vời về cách tận dụng tính năng hooks để cải thiện chất lượng mã do AI tạo ra mà không cần can thiệp thủ công.&lt;/p&gt;
&lt;p&gt;Cách triển khai khá đơn giản: cấu hình hook trong file &lt;code&gt;~/.claude/settings.json&lt;/code&gt; để tự động chạy RuboCop với rule &lt;code&gt;Layout/TrailingWhitespace&lt;/code&gt; sau mỗi lần Claude chỉnh sửa file Ruby. Hook sẽ chặn workflow của Claude và tự động dọn dẹp những khoảng trắng thừa mà AI thường để lại.&lt;/p&gt;
&lt;p&gt;Điểm thông minh của giải pháp này là chỉ áp dụng cho các file Ruby cụ thể (&lt;code&gt;.rb&lt;/code&gt;, &lt;code&gt;.rake&lt;/code&gt;, &lt;code&gt;.gemspec&lt;/code&gt;) để tránh làm hỏng các file khác. Tác giả cũng lưu ý rằng hooks có toàn quyền truy cập với quyền của user, nên cần xem xét kỹ về bảo mật khi sử dụng.&lt;/p&gt;
&lt;p&gt;Đây là một approach rất hay để xử lý những &amp;ldquo;thói quen xấu&amp;rdquo; của AI trong quá trình tạo mã, và có thể mở rộng cho nhiều tác vụ khác như chạy linter, test, hay thậm chí chặn một số hành động nhất định. Một cách tiếp cận thông minh để tích hợp AI vào workflow phát triển mà vẫn duy trì được tiêu chuẩn chất lượng mã.&lt;/p&gt;
&lt;h2 id="docs-for-ai-agents"&gt;&lt;a class="link" href="https://technicalwriting.dev/ai/agents/" target="_blank" rel="noopener"
&gt;Docs for AI Agents&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này khám phá một khía cạnh mới trong technical writing: cách viết tài liệu dành riêng cho AI agents. Với sự phát triển mạnh mẽ của các công cụ AI hỗ trợ lập trình, việc tạo ra documentation giúp AI hiểu và tương tác hiệu quả với codebase đang trở thành nhu cầu thực tế.&lt;/p&gt;
&lt;p&gt;Tác giả phân biệt rõ hai loại tài liệu: &amp;ldquo;internal eng docs&amp;rdquo; dành cho team phát triển và &amp;ldquo;agent docs&amp;rdquo; dành cho AI tools. Agent docs có thể được đặt ở nhiều mức độ khác nhau: project-level, subdirectory-level, và user-level, với mục tiêu cải thiện tính nhất quán trong output của AI và đảm bảo các phản hồi tuân theo quy ước riêng của dự án.&lt;/p&gt;
&lt;p&gt;Các phương pháp triển khai đa dạng, từ việc tạo file &lt;code&gt;AGENTS.md&lt;/code&gt; trong thư mục gốc dự án, đến việc nhúng hướng dẫn AI-specific dưới dạng comment, hoặc đồng bộ hóa giữa documentation nội bộ và agent docs. Bài viết cũng đề cập đến nhiều công cụ AI phổ biến như Claude Code, Gemini CLI, Cursor, và Windsurf.&lt;/p&gt;
&lt;p&gt;Điều thú vị là tác giả khuyến khích thử nghiệm với các chiến lược documentation khác nhau, vì đây là lĩnh vực đang phát triển nhanh chóng. Đây là một góc nhìn tiên phong về cách technical writing cần thích ứng với thời đại AI, không chỉ viết cho con người mà còn phải tối ưu cho máy móc.&lt;/p&gt;
&lt;h2 id="developers-are-using-these-ai-agents-to-build-software-10x-faster"&gt;&lt;a class="link" href="https://dev.to/therealmrmumba/developers-are-using-these-ai-agents-to-build-software-10x-faster-efn" target="_blank" rel="noopener"
&gt;Developers Are Using These AI Agents to Build Software 10x Faster&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một bài tổng hợp chi tiết về 10 công cụ AI coding agents hàng đầu đang giúp các lập trình viên tăng tốc đáng kể quá trình phát triển phần mềm trong năm 2025. Bài viết không chỉ liệt kê danh sách mà còn phân tích cách từng công cụ góp phần vào việc tự động hóa workflow.&lt;/p&gt;
&lt;p&gt;Danh sách các công cụ nổi bật bao gồm Cursor (trình soạn thảo AI-first), Claude Code CLI (công cụ dòng lệnh cho code reasoning), DeepDocs (tự động đồng bộ GitHub documentation), Continue.dev (khung làm việc AI IDE mã nguồn mở có thể tùy chỉnh), và Trae (trợ lý phát triển ứng dụng web full-stack). Ngoài ra còn có Gemini CLI của Google, Cody CLI từ Sourcegraph, OpenHands (self-hostable), Replit AI và CodeRabbit cho review pull request.&lt;/p&gt;
&lt;p&gt;Điểm mạnh của bài viết là nhấn mạnh giá trị cốt lõi: AI agents xử lý những tác vụ lặp đi lặp lại như tạo boilerplate, viết test, fix bug và quản lý documentation, giúp lập trình viên tập trung vào creative problem-solving và công việc chiến lược hơn.&lt;/p&gt;
&lt;p&gt;Tác giả kết luận rằng việc áp dụng AI coding agents đang trở thành yếu tố thiết yếu để duy trì tính cạnh tranh và năng suất trong ngành phát triển phần mềm. Đây là một resource hữu ích cho những ai muốn tìm hiểu và lựa chọn công cụ AI phù hợp cho workflow của mình.&lt;/p&gt;
&lt;h2 id="what-kind-of-work-i-want-in-2025"&gt;&lt;a class="link" href="https://www.seangoedecke.com/my-engineering-values-2025/" target="_blank" rel="noopener"
&gt;What kind of work I want (in 2025)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Sean Goedecke chia sẻ một cái nhìn thẳng thắn về những giá trị và ưu tiên nghề nghiệp của anh trong năm 2025. Đây không chỉ là bài viết cá nhân mà còn là nguồn tham khảo hữu ích cho các lập trình viên đang định hình career path của mình.&lt;/p&gt;
&lt;p&gt;Về môi trường làm việc, Sean ưu tiên remote hoàn toàn với những buổi offsites thỉnh thoảng, không muốn commute hàng ngày và trở thành &amp;ldquo;senior engineer với laptop&amp;rdquo;. Anh thích làm việc trên những project &amp;ldquo;core&amp;rdquo; của công ty, thoải mái với môi trường áp lực trung bình/cao, và sẵn sàng làm việc với legacy systems để tạo ra những giải pháp &amp;ldquo;80%&amp;rdquo; một cách nhanh chóng.&lt;/p&gt;
&lt;p&gt;Đặc biệt thú vị là những ranh giới đạo đức mà Sean đặt ra: tuyệt đối không làm việc với proof-of-work blockchain, cờ bạc trực tuyến, hoặc vũ khí tự động. Anh cũng ưu tiên các công ty công nghệ Mỹ với hệ thống lớn, nổi tiếng, và hiện tại rất quan tâm đến lĩnh vực AI.&lt;/p&gt;
&lt;p&gt;So với năm 2021, Sean đã chuyển từ việc tập trung vào maintenance sang những dự án được lãnh đạo công ty quan tâm. Bài viết này là một ví dụ hay về việc thiết lập giá trị nghề nghiệp rõ ràng và duy trì những tiêu chuẩn đạo đức trong môi trường công nghệ thay đổi liên tục.&lt;/p&gt;
&lt;h2 id="welcoming-the-next-generation-of-programmers"&gt;&lt;a class="link" href="https://lucumr.pocoo.org/2025/7/20/the-next-generation/" target="_blank" rel="noopener"
&gt;Welcoming The Next Generation of Programmers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Armin Ronacher, tác giả của Flask framework, đưa ra một góc nhìn tích cực và đầy tính nhân văn về thế hệ lập trình viên mới đang hình thành nhờ AI. Thay vì lo ngại AI sẽ thay thế lập trình viên, ông tin rằng AI đang mở rộng định nghĩa về &amp;ldquo;programmer&amp;rdquo; và mang nhiều người hơn vào lĩnh vực này.&lt;/p&gt;
&lt;p&gt;Ông đưa ra định nghĩa đơn giản nhưng bao hàm: &amp;ldquo;Nếu bạn tạo ra một chương trình, dù bằng tay hay với sự hỗ trợ của agent, bạn là một lập trình viên.&amp;rdquo; Điều này có nghĩa là những &amp;ldquo;vibe coders&amp;rdquo; - những người học lập trình thông qua AI - cũng đáng được chào đón vào cộng đồng.&lt;/p&gt;
&lt;p&gt;Thách thức lớn nhất mà Ronacher nhận ra là nguy cơ các lập trình viên mới bị cô lập, chỉ tương tác với AI mà thiếu kết nối với cộng đồng lập trình viên thực sự. Họ có thể trở thành &amp;ldquo;con tin của các công ty xây dựng công cụ vibe-coding&amp;rdquo; nếu không có sự hướng dẫn và hỗ trợ từ cộng đồng.&lt;/p&gt;
&lt;p&gt;Lời kêu gọi của ông rất rõ ràng: cộng đồng Python (và các cộng đồng lập trình khác) cần chủ động tiếp cận những lập trình viên mới này, tạo ra các &amp;ldquo;đường dẫn&amp;rdquo; cho những người học qua AI, và biến &amp;ldquo;tương tác đơn lẻ với AI thành hành trình chia sẻ với cộng đồng&amp;rdquo;. Đây là một quan điểm rất đáng suy ngẫm về cách chúng ta có thể ôm ấp và nuôi dưỡng thế hệ lập trình viên tương lai.&lt;/p&gt;
&lt;h2 id="pattern-matching-across-different-languages"&gt;&lt;a class="link" href="https://blog.frankel.ch/pattern-matching-different-languages/" target="_blank" rel="noopener"
&gt;Pattern-matching across different languages&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một bài so sánh kỹ lưỡng về cách triển khai pattern matching trong 5 ngôn ngữ lập trình phổ biến: Java, Scala, Kotlin, Python và Rust. Tác giả Nicolas Fränkel khám phá sự phát triển của pattern matching từ những khối &lt;code&gt;switch case&lt;/code&gt; truyền thống đến khả năng khớp kiểu và điều kiện phức tạp hiện đại.&lt;/p&gt;
&lt;p&gt;Điểm thú vị là Scala đã tiên phong trong việc cung cấp khả năng pattern matching tiên tiến, trong khi các ngôn ngữ khác mới bắt đầu áp dụng gần đây. Java đã giới thiệu type-based matching với cú pháp arrow trong các phiên bản gần đây, Kotlin có cách tiếp cận tương tự nhưng với một số biến thể cú pháp, Python bổ sung pattern matching từ phiên bản 3.10, còn Rust phức tạp hơn do các ràng buộc về quản lý bộ nhớ.&lt;/p&gt;
&lt;p&gt;Bài viết sử dụng ví dụ cụ thể về việc khớp các kiểu hình học khác nhau để minh họa cách mỗi ngôn ngữ xử lý pattern matching. Đặc biệt, tác giả chỉ ra rằng Scala vượt trội với khả năng khớp thuộc tính (attribute matching) trong khi các ngôn ngữ khác chủ yếu tập trung vào khớp kiểu.&lt;/p&gt;
&lt;p&gt;Kết luận quan trọng là pattern matching đang trở thành một tính năng thiết yếu trong phát triển phần mềm hiện đại, giúp viết mã dễ đọc và dễ bảo trì hơn. Mỗi ngôn ngữ đều mang đến cách tiếp cận và điểm mạnh riêng, phản ánh triết lý thiết kế và mục tiêu sử dụng của từng ngôn ngữ.&lt;/p&gt;
&lt;h2 id="a-real-world-ai-coding-case-sample"&gt;&lt;a class="link" href="https://blog.korny.info/2025/07/18/a-real-world-ai-coding-case-sample" target="_blank" rel="noopener"
&gt;A real-world AI coding case sample&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một case study thực tế chi tiết về việc sử dụng Claude để phát triển tính năng mới trong ứng dụng ASP.Net Core. Tác giả chia sẻ trải nghiệm cụ thể khi triển khai hệ thống gửi Kafka events mỗi khi có thay đổi trong mối quan hệ business-contact, mang đến góc nhìn thực tế về khả năng và hạn chế của AI coding.&lt;/p&gt;
&lt;p&gt;Quy trình làm việc rất thú vị: tác giả cung cấp context về cấu trúc dự án cho Claude, sau đó hướng dẫn AI như một &amp;ldquo;junior developer&amp;rdquo;, sửa chữa những lần thử đầu tiên, tinh chỉnh code implementation và thêm integration testing với Test Containers. Kỹ thuật sử dụng bao gồm Monadic Result/Option pattern và kiến trúc event-driven với Kafka.&lt;/p&gt;
&lt;p&gt;Bài học quan trọng nhất là AI rất hữu ích nhưng cần sự hướng dẫn của con người. Tác giả mô tả Claude như một &amp;ldquo;junior developer nhanh nhẹn, nhiệt tình nhưng ngây thơ&amp;rdquo; - hiệu quả nhất khi được giao những tác vụ cụ thể, được định nghĩa rõ ràng, và luôn cần sự giám sát cũng như correction liên tục.&lt;/p&gt;
&lt;p&gt;Điểm cân bằng của bài viết là tác giả không chỉ khen ngợi khả năng của AI mà còn nhấn mạnh những lo ngại về đạo đức và môi trường, bao gồm khả năng gây bất ổn công nghệ và kinh tế. Đây là một góc nhìn thực tế và cân bằng về việc áp dụng AI coding trong thực tế.&lt;/p&gt;
&lt;h2 id="clowns-to-the-left-of-me"&gt;&lt;a class="link" href="https://blog.korny.info/2025/07/19/clowns-to-the-left-of-me" target="_blank" rel="noopener"
&gt;Clowns to the Left of Me&amp;hellip;&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một bài viết sâu sắc về cuộc tranh luận phân cực xung quanh công cụ AI coding, trong đó tác giả đặt mình ở vị trí trung dung giữa hai thái cực: hype quá mức và hoài nghi cực đoan. Tiêu đề lấy cảm hứng từ bài hát &amp;ldquo;Stuck in the Middle With You&amp;rdquo; phản ánh đúng tâm trạng của những người cố gắng duy trì góc nhìn cân bằng.&lt;/p&gt;
&lt;p&gt;Một bên là những người ủng hộ cuồng nhiệt với marketing thái quá và kỳ vọng không thực tế, tạo ra những dự án hoàn chỉnh mà không hiểu rõ kỹ thuật bên dưới. Bên kia là những người hoài nghi chỉ trích mọi nghiên cứu và tuyên bố về AI, thất vọng với những hạn chế của công cụ AI.&lt;/p&gt;
&lt;p&gt;Tác giả khuyến khích một cách tiếp cận nuanced: AI coding tools rất mạnh mẽ nhưng cần được sử dụng một cách thận trọng và có hiểu biết. Không nên chấp nhận mù quáng cũng không nên từ chối hoàn toàn. Quan trọng nhất là kiểm tra cẩn thận mã AI tạo ra, hiểu rõ giới hạn của công cụ, và duy trì việc học hỏi liên tục.&lt;/p&gt;
&lt;p&gt;Bài viết cũng đề cập đến những lo ngại rộng hơn về tác động môi trường của công nghệ AI, tính bền vững của phát triển AI hiện tại, và động cơ thực sự của các công ty công nghệ. Đây là lời nhắc nhở quan trọng rằng trong thời đại thông tin quá tải, việc duy trì tư duy phản biện và cân bằng là vô cùng quý giá.&lt;/p&gt;
&lt;h2 id="improving-the-prompt-to-the-ai-to-get-better-code"&gt;&lt;a class="link" href="https://blog.vanillajava.blog/2025/07/improving-prompt-to-ai-to-get-better.html" target="_blank" rel="noopener"
&gt;Improving the prompt to the AI to get better code&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một bài hướng dẫn thực tế về cách tinh chỉnh prompts để có được mã nguồn tối ưu hơn từ AI. Tác giả từ Vanilla Java Blog chia sẻ kinh nghiệm cụ thể về việc cải thiện chất lượng code thông qua prompt engineering có hệ thống.&lt;/p&gt;
&lt;p&gt;Kỹ thuật chính bao gồm việc cung cấp ràng buộc và yêu cầu cụ thể: tối thiểu hóa việc tạo đối tượng, sử dụng kỹ thuật low-latency, giảm trùng lặp mã, tận dụng ThreadLocal cho dữ liệu tạm thời, và ưu tiên các phép toán đơn giản thay vì thư viện phức tạp. Đặc biệt, tác giả khuyến khích đưa ra hướng dẫn rõ ràng về những gì nên làm và tránh.&lt;/p&gt;
&lt;p&gt;Ví dụ prompt được tinh chỉnh của tác giả bao gồm: sử dụng ThreadLocal cho dữ liệu tạm thời, ưu tiên toán học đơn giản thay vì thư viện, chỉ định yêu cầu định dạng offset cụ thể, và khuyến nghị dùng &lt;code&gt;intern()&lt;/code&gt; cho Strings. Khi test trên nhiều nền tảng AI (Gemini, Claude, Grok, GitHub Copilot), kết quả cho thấy prompt chi tiết luôn mang lại mã nguồn chất lượng cao hơn.&lt;/p&gt;
&lt;p&gt;Điểm thú vị là không AI nào ban đầu gợi ý sử dụng byte[] cho lưu trữ, cho thấy tầm quan trọng của việc hướng dẫn cụ thể. Bài viết nhấn mạnh rằng prompt engineering chu đáo là chìa khóa để thu được giải pháp mã nguồn tối ưu từ AI, không chỉ đơn thuần yêu cầu &amp;ldquo;viết code tốt hơn&amp;rdquo;.&lt;/p&gt;</description></item><item><title>Newsletter #47</title><link>https://miti99.com/post/2025/08/06/</link><pubDate>Wed, 06 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/06/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #47.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="coding-with-llms-in-the-summer-of-2025-an-update"&gt;&lt;a class="link" href="https://antirez.com/news/154" target="_blank" rel="noopener"
&gt;Coding with LLMs in the summer of 2025 (an update)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Antirez - tác giả của Redis - chia sẻ những trải nghiệm và chiến lược mới nhất khi sử dụng các mô hình ngôn ngữ lớn (LLM) để hỗ trợ lập trình trong năm 2025. Bài viết mang lại góc nhìn thực tế từ một lập trình viên giàu kinh nghiệm về cách tận dụng AI một cách hiệu quả.&lt;/p&gt;
&lt;p&gt;Điểm quan trọng nhất mà tác giả nhấn mạnh là LLM hoạt động tốt như &amp;ldquo;bộ khuếch đại&amp;rdquo; (amplifier) chứ không phải là &amp;ldquo;ban nhạc một người&amp;rdquo; (one-man-band). Điều này có nghĩa là con người cần duy trì vai trò tích cực trong quá trình lập trình, sử dụng AI để tăng tốc và cải thiện chất lượng công việc thay vì giao phó hoàn toàn cho máy.&lt;/p&gt;
&lt;p&gt;Về lựa chọn công cụ, antirez khuyến nghị sử dụng Gemini 2.5 PRO (ưu tiên hàng đầu nhờ khả năng hiểu ngữ nghĩa mạnh) và Claude Opus 4, đồng thời tránh các coding agents hoặc trình soạn thảo tích hợp AI. Anh cũng đề xuất chiến lược sử dụng nhiều LLM khác nhau cho các vấn đề phức tạp và chuyển mã thủ công giữa môi trường phát triển và LLM để duy trì quyền kiểm soát.&lt;/p&gt;
&lt;p&gt;Kỹ thuật tương tác hiệu quả bao gồm: cung cấp ngữ cảnh chi tiết về dự án, truyền đạt rõ ràng mục tiêu và hướng giải quyết tiềm năng. Lợi ích mà AI mang lại không chỉ là loại bỏ lỗi nhanh hơn mà còn hỗ trợ tạo prototype nhanh chóng và khám phá các giải pháp nằm ngoài chuyên môn cá nhân. Đây là những lời khuyên quý giá cho các lập trình viên muốn tận dụng AI một cách thông minh và bền vững.&lt;/p&gt;
&lt;h2 id="artisanal-handcrafted-git-repositories"&gt;&lt;a class="link" href="https://drew.silcock.dev/blog/artisanal-git/" target="_blank" rel="noopener"
&gt;Artisanal Handcrafted Git Repositories&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Drew Silcock mang đến một bài viết cực kỳ thú vị về cách tự tay tạo ra kho lưu trữ Git mà không cần sử dụng các lệnh Git truyền thống. Đây không chỉ là một bài tập học thuật mà còn là cách hiểu sâu về cơ chế hoạt động bên trong của hệ thống kiểm soát phiên bản phổ biến nhất hiện nay.&lt;/p&gt;
&lt;p&gt;Cốt lõi của Git là hệ thống Content Addressable Storage (CAS), nơi các đối tượng được lưu trữ dựa trên mã băm SHA-1 của chúng. Git lưu trữ toàn bộ phiên bản tệp tin chứ không phải chỉ các thay đổi, thông qua ba loại đối tượng chính: blob (nội dung tệp thô), tree (metadata tệp và tham chiếu đến blob), và commit (thông tin về trạng thái kho lưu trữ).&lt;/p&gt;
&lt;p&gt;Tác giả hướng dẫn chi tiết cách tạo thủ công cấu trúc thư mục &lt;code&gt;.git&lt;/code&gt;, xây dựng các đối tượng theo chương trình, tạo tham chiếu thủ công và sử dụng nén zlib để tối ưu lưu trữ. Bài viết cũng đi sâu vào các khái niệm nâng cao như kỹ thuật nén packfile, cơ chế thu gom rác, và tối ưu hóa lưu trữ đối tượng.&lt;/p&gt;
&lt;p&gt;Điểm quan trọng nhất mà tác giả nhấn mạnh là &amp;ldquo;Sức mạnh của Git không đến từ sự phức tạp, mà từ tính đơn giản và thanh lịch trong thiết kế.&amp;rdquo; Việc hiểu rõ kiến trúc bên trong này giúp các lập trình viên sử dụng Git hiệu quả hơn và giải quyết các vấn đề phức tạp một cách tự tin.&lt;/p&gt;
&lt;h2 id="why-i"&gt;&lt;a class="link" href="https://utkarshkanwat.com/writing/betting-against-agents/" target="_blank" rel="noopener"
&gt;Why I&amp;rsquo;m Betting Against AI Agents in 2025 (Despite Building Them)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Utkarsh Kanwat, một lập trình viên đang xây dựng các tác nhân AI, đưa ra góc nhìn khá táo bạo khi &amp;ldquo;đặt cược chống lại&amp;rdquo; xu hướng AI agents trong năm 2025. Bài viết này không phải là lời phê phán mù quáng mà là phân tích thực tế về những thách thức cốt lõi mà AI agents đang đối mặt.&lt;/p&gt;
&lt;p&gt;Vấn đề lớn nhất là độ tin cậy giảm theo cấp số nhân: nếu mỗi bước có độ chính xác 95%, thì sau 20 bước, tỷ lệ thành công chỉ còn 36%. Trong khi đó, môi trường sản xuất yêu cầu độ tin cậy trên 99.9%. Thách thức kinh tế cũng không kém phần nghiêm trọng: chi phí token tăng theo cấp số nhân với độ dài cuộc hội thoại, một cuộc trò chuyện 100 lượt có thể tiêu tốn 50-100 USD chỉ riêng token.&lt;/p&gt;
&lt;p&gt;Tác giả cũng chỉ ra rằng &amp;ldquo;bí mật bẩn thỉu&amp;rdquo; của các hệ thống tác nhân AI trong sản xuất là AI chỉ thực hiện khoảng 30% công việc, phần còn lại thuộc về kỹ thuật hệ thống truyền thống. Các hệ thống doanh nghiệp phức tạp và không dự đoán được, đòi hỏi nhiều kỹ năng kỹ thuật hơn là khả năng AI.&lt;/p&gt;
&lt;p&gt;Thay vì &amp;ldquo;tự động hóa mọi thứ&amp;rdquo;, tác giả dự đoán tương lai sẽ thuộc về &amp;ldquo;trợ lý cực kỳ có khả năng với ranh giới rõ ràng&amp;rdquo;. Các startup tập trung vào &amp;ldquo;tác nhân hoàn toàn tự động&amp;rdquo; sẽ gặp khó khăn, trong khi những công cụ có phạm vi hạn chế và giám sát con người rõ ràng sẽ thành công hơn. Đây là lời nhắc nhở quan trọng về việc cân bằng giữa tham vọng công nghệ và thực tế triển khai.&lt;/p&gt;
&lt;h2 id="rethinking-cli-interfaces-for-ai"&gt;&lt;a class="link" href="https://www.notcheckmark.com/2025/07/rethinking-cli-interfaces-for-ai/" target="_blank" rel="noopener"
&gt;Rethinking CLI interfaces for AI&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một góc nhìn thú vị về việc tái thiết kế giao diện dòng lệnh (CLI) để phù hợp hơn với kỷ nguyên AI. Tác giả chỉ ra rằng các công cụ dòng lệnh hiện tại tạo ra nhiều thách thức cho các tác nhân AI, đặc biệt là vấn đề giới hạn cửa sổ ngữ cảnh và khả năng hiểu đầu ra của các lệnh.&lt;/p&gt;
&lt;p&gt;Vấn đề cốt lõi là các LLM gặp khó khăn trong việc điều hướng, hiểu đầu ra và sử dụng hiệu quả các công cụ dòng lệnh truyền thống. Các công cụ này được thiết kế cho con người, không phải cho máy móc, dẫn đến việc AI thường &amp;ldquo;lúng túng&amp;rdquo; khi sử dụng chúng.&lt;/p&gt;
&lt;p&gt;Tác giả đề xuất các nguyên tắc thiết kế mới: cung cấp hướng dẫn API rõ ràng thông qua docstring, thêm thông tin ngữ cảnh vào đầu ra lệnh, và tạo các công cụ wrapper giúp tác nhân AI hiểu được tổng kích thước đầu ra, ngữ cảnh thư mục hiện tại, và các lựa chọn lệnh thay thế.&lt;/p&gt;
&lt;p&gt;Những gợi ý cụ thể bao gồm phát triển các công cụ CLI với &amp;ldquo;Kiến trúc Thông tin&amp;rdquo; tập trung vào khả năng sử dụng cho AI, tạo shell hooks cung cấp ngữ cảnh bổ sung khi lệnh thất bại, và thiết kế API với các lời gọi hàm phân cấp (ưu tiên các phương pháp được khuyến nghị trước).&lt;/p&gt;
&lt;p&gt;Tác giả kết luận: &amp;ldquo;Chúng ta cần nâng cấp các công cụ dòng lệnh và thiết kế API để chúng có thể được các tác nhân LLM sử dụng tốt hơn.&amp;rdquo; Đây là lời kêu gọi quan trọng để tái tư duy về thiết kế giao diện trong kỷ nguyên AI.&lt;/p&gt;
&lt;h2 id="asynchrony-is-not-concurrency"&gt;&lt;a class="link" href="https://kristoff.it/blog/asynchrony-is-not-concurrency/" target="_blank" rel="noopener"
&gt;Asynchrony is not Concurrency&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Kristoff đưa ra một phân tích sâu sắc về sự khác biệt giữa hai khái niệm thường bị nhầm lẫn trong lập trình: asynchrony (bất đồng bộ) và concurrency (đồng thời). Đây là một chủ đề quan trọng mà nhiều lập trình viên, kể cả những người có kinh nghiệm, vẫn thường hiểu nhầm.&lt;/p&gt;
&lt;p&gt;Tác giả định nghĩa rõ ràng: Asynchrony là khả năng các tác vụ có thể chạy không theo thứ tự và vẫn cho kết quả đúng, trong khi Concurrency là khả năng hệ thống tiến triển nhiều tác vụ cùng một lúc. Parallelism thì là việc thực thi vật lý nhiều tác vụ đồng thời. Điểm mấu chốt là asynchrony không nhất thiết cần đến concurrent execution.&lt;/p&gt;
&lt;p&gt;Vấn đề lớn trong nhiều ngôn ngữ lập trình hiện tại là việc gộp chung asynchrony và concurrency, dẫn đến những hậu quả như nhân đôi thư viện, yêu cầu async code lan tỏa khắp nơi (&amp;ldquo;viral async&amp;rdquo;), và các mẫu lập trình không tối ưu. Ví dụ điển hình là việc lưu file - đây là một tác vụ bất đồng bộ nhưng không cần thiết phải chạy đồng thời.&lt;/p&gt;
&lt;p&gt;Zig mang đến cách tiếp cận thú vị bằng cách tách biệt asynchrony khỏi concurrency, cho phép code đồng bộ và bất đồng bộ cùng tồn tại. Ngôn ngữ này giới thiệu &lt;code&gt;asyncConcurrent&lt;/code&gt; để yêu cầu rõ ràng việc thực thi đồng thời khi thực sự cần thiết, đồng thời cho phép chạy các tác vụ async trong môi trường đơn luồng.&lt;/p&gt;
&lt;p&gt;Đây là lời nhắc nhở quan trọng về việc hiểu rõ bản chất của các khái niệm lập trình thay vì chấp nhận mù quáng các mẫu thiết kế phổ biến.&lt;/p&gt;
&lt;h2 id="how-does-ai-disrupt-accountability-in-code-reviews"&gt;&lt;a class="link" href="https://rdel.substack.com/p/rdel-102-how-does-ai-disrupt-accountability" target="_blank" rel="noopener"
&gt;How Does AI Disrupt Accountability in Code Reviews?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một nghiên cứu thú vị từ RDEL về cách AI tác động đến trách nhiệm giải trình trong quá trình review code. Đây là chủ đề ít được thảo luận nhưng rất quan trọng trong việc duy trì chất lượng phần mềm và văn hóa làm việc nhóm.&lt;/p&gt;
&lt;p&gt;Nghiên cứu xác định bốn động lực cốt lõi thúc đẩy trách nhiệm cá nhân trong review code: tiêu chuẩn cá nhân, tính chính trực nghề nghiệp, niềm tự hào về chất lượng mã, và danh tiếng chuyên môn. Tất cả những động lực này đều dựa trên tương tác xã hội và sự đánh giá của đồng nghiệp.&lt;/p&gt;
&lt;p&gt;Vấn đề xuất hiện khi AI thay thế reviewer con người: các cơ chế trách nhiệm giải trình quan trọng bị phá vỡ. Không còn tương tác xã hội qua lại, không có sự phán xét từ đồng nghiệp, và cảm giác chủ sở hữu tập thể cũng giảm sút. Một người tham gia nghiên cứu đã nói rất tóm tắt: &amp;ldquo;Bạn không thể buộc mô hình AI phải chịu trách nhiệm.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Thú vị là các kỹ sư vẫn coi AI như một &amp;ldquo;trợ lý lượt đầu&amp;rdquo; hữu ích để phát hiện các vấn đề cơ bản, nhưng không coi nó có thẩm quyền đưa ra phản hồi có ý nghĩa. Điều này cho thấy con người vẫn hiểu rõ giới hạn của công nghệ hiện tại.&lt;/p&gt;
&lt;p&gt;Để duy trì trách nhiệm giải trình trong workflow có AI hỗ trợ, các nhà lãnh đạo được khuyên nên sử dụng AI như một lớp hỗ trợ, duy trì các điểm kiểm tra của con người, và củng cố động lực nội tại thông qua các chuẩn mực xã hội. Đây là bài học quan trọng về việc cân bằng giữa tự động hóa và duy trì yếu tố con người trong quy trình phát triển phần mềm.&lt;/p&gt;
&lt;h2 id="vibecoding-a-high-performance-system"&gt;&lt;a class="link" href="https://andrewkchan.dev/posts/systems.html" target="_blank" rel="noopener"
&gt;Vibecoding a High Performance System&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Andrew Chan chia sẻ trải nghiệm thú vị về việc sử dụng AI để khám phá và tối ưu hóa thiết kế hệ thống hiệu suất cao. Từ &amp;ldquo;vibecoding&amp;rdquo; được tác giả sử dụng để mô tả cách tiếp cận linh hoạt, sử dụng AI để nhanh chóng thử nghiệm nhiều kiến trúc khác nhau.&lt;/p&gt;
&lt;p&gt;Điểm nổi bật nhất là tốc độ khám phá không gian thiết kế: từ 20 trang/giây lên 10,800 trang/giây qua 8 phiên bản kiến trúc chính. Điều này cho thấy AI có thể giúp kỹ sư nhanh chóng prototype và đánh giá các phương pháp khác nhau dựa trên các chỉ số hiệu suất khách quan.&lt;/p&gt;
&lt;p&gt;Tác giả nhận ra rằng thiết kế hệ thống hiện đại ngày càng bị giới hạn bởi thực nghiệm hơn là coding, phụ thuộc vào việc hiểu biết về sự chồng chéo giữa giao tiếp và tính toán, đòi hỏi đánh giá cẩn thận các trade-off giữa các công nghệ. Lỗi có thể có hậu quả nghiêm trọng ở quy mô lớn (như việc web crawling không lịch sự), do đó việc review thủ công và kiểm tra điểm vẫn rất quan trọng.&lt;/p&gt;
&lt;p&gt;AI đóng vai trò như công cụ khám phá thiết kế: nhanh chóng tạo prototype các phương pháp kiến trúc khác nhau, cung cấp chuyên môn trong các lĩnh vực công nghệ xa lạ, tạo ra các công cụ đo hiệu suất, và đưa ra góc nhìn thiết kế thay thế. Tuy nhiên, tác giả nhấn mạnh rằng mặc dù AI tăng tốc thiết kế, các kỹ năng kỹ thuật cơ bản vẫn quan trọng: hiểu biết về ràng buộc hệ thống, duy trì độ sâu kỹ thuật và review nghiêm túc các giải pháp được tạo ra.&lt;/p&gt;
&lt;p&gt;Tác giả kết luận một cách táo bạo: &amp;ldquo;Những đội nào hiểu được điều này sẽ áp đảo những đội không hiểu.&amp;rdquo; Đây là lời nhắc nhở về tầm quan trọng của việc nắm vững cách sử dụng AI trong thiết kế hệ thống hiệu suất cao.&lt;/p&gt;
&lt;h2 id="two-simple-rules-to-fix-code-reviews"&gt;&lt;a class="link" href="https://serce.me/posts/2025-07-17-two-simple-rules-to-fix-code-reviews" target="_blank" rel="noopener"
&gt;Two Simple Rules to Fix Code Reviews&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Serce đưa ra hai quy tắc đơn giản nhưng hiệu quả để cải thiện quy trình review code - một vấn đề mà nhiều đội phát triển phần mềm gặp phải khi review trở thành nút thắt cổ chai thay vì công cụ hợp tác hữu ích.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quy tắc 1: Giảm thiểu thời gian phản hồi&lt;/strong&gt; - Phản hồi nhanh chóng với các review code, ngay cả khi chưa thể approve ngay lập tức. Tác giả nhấn mạnh rằng sự chậm trễ tạo ra mất mát ngữ cảnh đáng kể cho người viết code. &amp;ldquo;Một giờ trong review, và bạn mất rất ít ngữ cảnh&amp;rdquo; - điều này cho thấy tầm quan trọng của việc ưu tiên review để duy trì động lực phát triển.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quy tắc 2: Bao gồm mệnh đề &amp;ldquo;vì&amp;rdquo; rõ ràng&lt;/strong&gt; - Mỗi bình luận review phải giải thích lý do đằng sau gợi ý. Thay vì nói &amp;ldquo;làm ơn làm X&amp;rdquo;, hãy nói &amp;ldquo;làm ơn làm X vì Y&amp;rdquo;. Nếu bạn không thể diễn đạt được &amp;ldquo;vì&amp;rdquo; rõ ràng, có thể bình luận đó không cần thiết.&lt;/p&gt;
&lt;p&gt;Lời khuyên thực tế bao gồm: ưu tiên review kịp thời để duy trì động lực phát triển, hiểu rằng các kỹ sư senior định hình văn hóa review code, nhận ra rằng phản hồi nhanh không có nghĩa là chấp thuận mù quáng, và tập trung vào việc thêm giá trị thông qua phản hồi rõ ràng, có lý.&lt;/p&gt;
&lt;p&gt;Tác giả nhấn mạnh rằng các quy tắc này phù hợp nhất với các đội có mục tiêu chung, và mục đích cuối cùng là biến review code thành công cụ cộng tác giúp tăng tốc thay vì cản trở quy trình phát triển. Đây là những nguyên tắc đơn giản nhưng có thể tạo ra sự khác biệt lớn trong hiệu quả làm việc của đội.&lt;/p&gt;
&lt;h2 id="reading-qr-codes-without-a-computer"&gt;&lt;a class="link" href="https://qr.blinry.org/" target="_blank" rel="noopener"
&gt;Reading QR codes without a computer!&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trang qr.blinry.org là một nguồn tài liệu giáo dục tuyệt vời giải thích cách thức hoạt động của mã QR một cách dễ hiểu. Website hướng dẫn cách đọc và giải mã QR code bằng tay mà không cần máy tính hay điện thoại, giúp người dùng hiểu sâu về cấu trúc bên trong của mã QR.&lt;/p&gt;
&lt;p&gt;Trang web trình bày các thành phần cơ bản của QR code như finder pattern (mẫu tìm kiếm), separator (đường phân cách), alignment pattern (mẫu căn chỉnh), và quiet zone (vùng trống). Ngoài ra, nó còn giải thích chi tiết về mask pattern (mẫu mặt nạ), encoding (mã hóa), và các phương pháp sửa lỗi. Đây là tài liệu hữu ích cho những ai muốn tìm hiểu về công nghệ QR code từ góc độ kỹ thuật.&lt;/p&gt;</description></item><item><title>Newsletter #46</title><link>https://miti99.com/post/2025/08/05/</link><pubDate>Tue, 05 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/05/</guid><description>&lt;p&gt;&lt;em&gt;Bài viết này sẽ quay lại dùng Claude Code nha :D (chân ái là đây, chỉ khi nào ngại tốn token mới phải nhảy sang agent khác). Mời bạn thưởng thức Newsletter #46.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="the-pragmatic-engineer-2025-survey-what"&gt;&lt;a class="link" href="https://newsletter.pragmaticengineer.com/p/the-pragmatic-engineer-2025-survey" target="_blank" rel="noopener"
&gt;The Pragmatic Engineer 2025 Survey: What&amp;rsquo;s in your tech stack?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;The Pragmatic Engineer vừa công bố kết quả khảo sát năm 2025 với hơn 3.000 phản hồi từ các chuyên gia công nghệ, mang đến cái nhìn toàn diện về xu hướng công cụ và công nghệ hiện tại trong ngành.&lt;/p&gt;
&lt;p&gt;Điểm nổi bật nhất của khảo sát là sự bùng nổ của các công cụ AI: 85% người tham gia đã sử dụng ít nhất một công cụ AI trong công việc. GitHub Copilot dẫn đầu danh sách, tiếp theo là Cursor (một sự bất ngờ với mức độ phổ biến cao), Claude và ChatGPT. Điều này cho thấy các lập trình viên không ngần ngại thử nghiệm các công cụ mới, đặc biệt trong lĩnh vực AI đang phát triển nhanh chóng.&lt;/p&gt;
&lt;p&gt;Về ngôn ngữ lập trình, TypeScript, Python và Swift là những ngôn ngữ được sử dụng nhiều nhất, trong khi Ruby on Rails và Elixir nằm trong top &amp;ldquo;được yêu thích nhất&amp;rdquo;. Đáng chú ý, JIRA tiếp tục là công cụ bị &amp;ldquo;ghét&amp;rdquo; nhất do tính phức tạp và chậm chạp, với Linear được đề cập như một lựa chọn thay thế tốt hơn.&lt;/p&gt;
&lt;p&gt;Trong lĩnh vực cloud, AWS vẫn giữ vị trí dẫn đầu, theo sau là Azure và Google Cloud, với Vercel nổi lên như một nền tảng đầy tiềm năng. Git thống trị hoàn toàn trong quản lý phiên bản, với GitHub, GitLab và BitBucket đều có lượng người dùng đáng kể.&lt;/p&gt;
&lt;h2 id="algorithms-for-making-interesting-organic-simulations"&gt;&lt;a class="link" href="https://bleuje.com/physarum-explanation/" target="_blank" rel="noopener"
&gt;Algorithms for making interesting organic simulations&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này giới thiệu một kỹ thuật tính toán thú vị để mô phỏng hành vi giống sinh vật thông qua thuật toán Physarum. Đây là phương pháp sử dụng các tác nhân (agents) di chuyển trong không gian 2D, để lại và theo dõi các vết tích, tạo ra những hình ảnh trực quan có vẻ ngoài hữu cơ và tự nhiên.&lt;/p&gt;
&lt;p&gt;Cốt lõi của thuật toán khá đơn giản nhưng hiệu quả: mỗi tác nhân có vị trí và hướng di chuyển, sau đó thực hiện chu trình cảm nhận - xoay - di chuyển - để lại vết tích. Tác nhân &amp;ldquo;nhìn&amp;rdquo; về ba hướng (thẳng, trái và phải một chút), sau đó di chuyển theo hướng có cường độ vết tích cao nhất. Điều thú vị là tác giả đã thử nghiệm việc thay đổi các tham số động dựa trên giá trị bản đồ vết tích, tạo ra những hiệu ứng nghệ thuật độc đáo.&lt;/p&gt;
&lt;p&gt;Ứng dụng này được tăng tốc bằng GPU, cho phép xử lý hàng triệu hạt cùng lúc và tạo ra những mô phỏng phức tạp từ những quy tắc đơn giản. Đây là một ví dụ tuyệt vời về cách các thuật toán đơn giản có thể tạo ra hành vi phức tạp và thẩm mỹ cao.&lt;/p&gt;
&lt;h2 id="ai-coding-tools-are-shifting-to-a-surprising-place-the-terminal"&gt;&lt;a class="link" href="https://techcrunch.com/2025/07/15/ai-coding-tools-are-shifting-to-a-surprising-place-the-terminal/" target="_blank" rel="noopener"
&gt;AI coding tools are shifting to a surprising place: The terminal&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một xu hướng thú vị đang diễn ra trong thế giới công cụ AI hỗ trợ lập trình: chúng đang dịch chuyển từ các trình soạn thảo mã sang giao diện dòng lệnh. Các &amp;ldquo;ông lớn&amp;rdquo; như Anthropic (Claude Code), DeepMind (Gemini CLI) và OpenAI (CLI Codex) đều đã tung ra các sản phẩm tập trung vào terminal thay vì chỉ hỗ trợ trong IDE truyền thống.&lt;/p&gt;
&lt;p&gt;Lý do cho sự chuyển đổi này khá rõ ràng: giao diện terminal cung cấp sự linh hoạt hơn nhiều so với việc chỉ hỗ trợ viết mã. Các công cụ này có thể xử lý toàn bộ quy trình phát triển, từ thiết lập dự án, quản lý phụ thuộc, đến các tác vụ DevOps phức tạp. Thay vì chỉ gợi ý mã, chúng có thể giải quyết vấn đề theo từng bước một cách tự động.&lt;/p&gt;
&lt;p&gt;Mike Merrill, đồng tác giả của Terminal-Bench (một benchmark dành cho công cụ AI terminal), đã đưa ra dự đoán táo bạo: &amp;ldquo;Chúng tôi tin rằng tương lai sẽ có 95% tương tác giữa LLM và máy tính thông qua giao diện giống terminal.&amp;rdquo; Điều này có thể mở ra kỷ nguyên mới trong phát triển phần mềm, nơi AI không chỉ viết mã mà còn quản lý toàn bộ môi trường phát triển.&lt;/p&gt;
&lt;h2 id="distributed-systems-reliability-glossary"&gt;&lt;a class="link" href="https://antithesis.com/resources/reliability_glossary/" target="_blank" rel="noopener"
&gt;Distributed Systems Reliability Glossary&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Antithesis vừa công bố một tài liệu tham khảo cực kỳ hữu ích cho các lập trình viên: Từ điển thuật ngữ về độ tin cậy hệ thống phân tán. Đây không chỉ là một bản danh sách khô khan các thuật ngữ, mà là một nguồn tài liệu toàn diện giúp các lập trình viên hiểu rõ hơn về việc kiểm thử và đảm bảo độ tin cậy của hệ thống phân tán.&lt;/p&gt;
&lt;p&gt;Từ điển được tổ chức thành seis phần chính: khái niệm cơ bản, mô hình nhất quán, mô hình khả dụng, các hiện tượng bất thường, lỗi hệ thống và kỹ thuật kiểm thử. Điều đặc biệt là tài liệu này không chỉ đưa ra định nghĩa khô khan mà còn giải thích rõ ràng tại sao những khái niệm này lại quan trọng trong thực tế.&lt;/p&gt;
&lt;p&gt;Một trong những điểm mạnh của từ điển là cách tiếp cận thực tế: tác giả thừa nhận rằng không cần phải nắm vững tất cả các khái niệm mới có thể bắt đầu kiểm thử hệ thống phân tán hiệu quả. Thay vào đó, tài liệu tập trung vào việc cung cấp hiểu biết trực quan về những thách thức cốt lõi: hệ thống phân tán vốn dĩ đồng thời và dễ gặp lỗi một phần, đòi hỏi các kỹ thuật kiểm thử tinh vi như fault injection và property-based testing.&lt;/p&gt;
&lt;h2 id="test-driven-development-tdd-with-dbt"&gt;&lt;a class="link" href="https://xebia.com/blog/test-driven-development-tdd-with-dbt/" target="_blank" rel="noopener"
&gt;Test-Driven Development (TDD) with dbt&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Xebia mang đến góc nhìn thú vị về việc áp dụng phương pháp Test-Driven Development (TDD) vào dbt - một công cụ phổ biến trong lĩnh vực kỹ thuật dữ liệu (analytics engineering). Thay vì hy vọng các mô hình dbt hoạt động đúng, TDD khuyến khích viết test trước, sau đó mới xây dựng các phép biến đổi SQL để vượt qua những bài kiểm tra đó.&lt;/p&gt;
&lt;p&gt;Từ dbt Core v1.8, việc triển khai TDD trở nên dễ dàng hơn nhiều với tính năng unit testing tích hợp sẵn. Quy trình làm việc tuân theo chu kỳ đỏ-xanh-tái cấu trúc quen thuộc: viết test với dữ liệu đầu vào và đầu ra cố định, xem test thất bại, viết đủ mã SQL để test pass, sau đó tái cấu trúc để cải thiện chất lượng mã.&lt;/p&gt;
&lt;p&gt;Điểm mạnh của phương pháp này nằm ở việc đưa tính kỷ luật của phát triển phần mềm vào quy trình xử lý dữ liệu. Thay vì kiểm tra dữ liệu theo từng dòng như các schema test truyền thống (not_null, unique), TDD tập trung vào kiểm tra logic nghiệp vụ phức tạp như tính toán số liệu quan trọng hay xử lý chuỗi. Kết quả là các data pipeline đáng tin cậy hơn, dễ bảo trì và cho phép tái cấu trúc một cách tự tin - điều đặc biệt quan trọng trong những dự án có tính nghiệp vụ cao.&lt;/p&gt;
&lt;h2 id="rethinking-oop"&gt;&lt;a class="link" href="https://max.xz.ax/blog/rethinking-oop/" target="_blank" rel="noopener"
&gt;Rethinking OOP&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này đặt ra câu hỏi thú vị về cách chúng ta dạy và học lập trình hướng đối tượng (OOP). Tác giả cho rằng phương pháp giảng dạy OOP hiện tại đang gây hại nhiều hơn là có ích, đặc biệt là việc ép học sinh tiếp thu các khái niệm trừu tượng ngay từ đầu mà không hiểu rõ lý do tại sao cần chúng.&lt;/p&gt;
&lt;p&gt;Thay vì bắt đầu với các khái niệm phức tạp như class, inheritance hay design patterns, tác giả đề xuất một cách tiếp cận tự nhiên hơn: bắt đầu từ lập trình thủ tục đơn giản, sau đó từng bước giới thiệu các tính năng mới khi học sinh thực sự gặp phải những hạn chế và cần giải quyết chúng. Ví dụ, chỉ khi nào học sinh cảm thấy việc quản lý nhiều biến rời rạc trở nên khó khăn, họ mới thực sự hiểu giá trị của việc nhóm dữ liệu lại thành struct hay class.&lt;/p&gt;
&lt;p&gt;Quan điểm này rất đáng suy ngẫm: &amp;ldquo;Các best practices trong lập trình không cần phải được học thuộc lòng từ sách giáo khoa; chúng có thể trở nên trực quan và rõ ràng thông qua việc tăng dần độ phức tạp của chương trình một cách hợp lý.&amp;rdquo; Đây là một lời nhắc nhở rằng giáo dục lập trình nên tập trung vào việc xây dựng tư duy logic và khả năng giải quyết vấn đề, thay vì ép học sinh ghi nhớ các quy tắc mà họ chưa hiểu được bản chất.&lt;/p&gt;
&lt;h2 id="how-i-write-code-that-i-don"&gt;&lt;a class="link" href="https://dev.to/resource_bunk_1077cab07da/how-i-write-code-that-i-dont-hate-reading-a-week-later-303b" target="_blank" rel="noopener"
&gt;How I Write Code That I Don&amp;rsquo;t Hate Reading a Week Later&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một bài viết thực tế và hữu ích về cách viết mã dễ đọc - một kỹ năng quan trọng mà nhiều lập trình viên thường bỏ qua. Tác giả chia sẻ triết lý cốt lõi: &amp;ldquo;Viết mã như thể bạn sẽ phải debug nó lúc 2 giờ sáng, trong trạng thái buồn ngủ, với deadline cận kề.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Các nguyên tắc chính bao gồm: đặt tên biến và hàm mô tả rõ ràng (ví dụ &lt;code&gt;parsed_user_profile_data&lt;/code&gt; thay vì chỉ &lt;code&gt;d&lt;/code&gt;), viết comment giải thích &amp;ldquo;tại sao&amp;rdquo; thay vì &amp;ldquo;cái gì&amp;rdquo;, ưu tiên tính dễ đọc hơn là &amp;ldquo;sự thông minh&amp;rdquo; của mã. Thay vì viết những dòng mã phức tạp để khoe kỹ thuật, hãy tách chúng thành nhiều dòng dễ hiểu hơn.&lt;/p&gt;
&lt;p&gt;Điểm hay nhất là nguyên tắc viết hàm nhỏ và tập trung: mỗi hàm chỉ làm một việc cụ thể với tên mô tả rõ ràng như &lt;code&gt;handleLoginFormSubmission()&lt;/code&gt;. Khi mã trở nên rối rắm, hãy dừng lại và tái cấu trúc thay vì cứ thêm độ phức tạp. Tác giả cũng giới thiệu các công cụ hỗ trợ như Prettier, Black cho Python, và thậm chí ChatGPT để giúp tái cấu trúc mã. Đây là những lời khuyên đơn giản nhưng cực kỳ thực tế cho bất kỳ lập trình viên nào muốn code của mình dễ bảo trì hơn.&lt;/p&gt;
&lt;h2 id="7-habits-that-quietly-made-me-a-10x-developer-no-not-chatgpt"&gt;&lt;a class="link" href="https://dev.to/abubakersiddique771/7-habits-that-quietly-made-me-a-10x-developer-no-not-chatgpt-13c4" target="_blank" rel="noopener"
&gt;7 Habits That Quietly Made Me A 10x Developer (No, Not ChatGPT)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một bài viết thẳng thắn về những thói quen thực tế giúp nâng cao năng suất lập trình, không phải dựa vào AI mà là những cải tiến nhỏ tích lũy theo thời gian. Tác giả chia sẻ 7 thói quen đã giúp anh trở thành lập trình viên hiệu quả hơn.&lt;/p&gt;
&lt;p&gt;Điểm nổi bật nhất là việc &amp;ldquo;viết mã để viết mã&amp;rdquo; - tạo ra các script, generator và công cụ scaffolding để tự động hóa những tác vụ lặp đi lặp lại. Thay vì giải quyết cùng một vấn đề nhiều lần, hãy đầu tư thời gian tạo công cụ để nhân rộng hiệu suất. Thói quen &amp;ldquo;thiết kế cho bản thân tương lai&amp;rdquo; cũng rất hay: viết documentation rõ ràng, commit message mô tả, và README.md trước khi bắt đầu dự án.&lt;/p&gt;
&lt;p&gt;Các thói quen khác bao gồm: ghi chép có cấu trúc trước khi debug (ép bản thân suy nghĩ rõ ràng), xây dựng công cụ nhỏ cá nhân (CLI scripts, automation tools), timeboxing cho công việc phức tạp (khối 90 phút không bị gián đoạn), học workflow từ người khác chứ không chỉ copy code, và retrospective hàng tuần với 3 câu hỏi: gì đã tốt, gì đã làm chậm tiến độ, gì sẽ cải thiện tuần sau. Đây là những thói quen đơn giản nhưng có tác động lâu dài đến năng suất làm việc.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Claude Code thật sự là chân ái :D Xử lý nhanh, tóm tắt gọn, càng ngày càng tốt. Thật tuyệt vời!&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #45</title><link>https://miti99.com/post/2025/08/04/</link><pubDate>Mon, 04 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/04/</guid><description>&lt;p&gt;&lt;em&gt;Bài post được thực hiện bởi Cline + Kimi K2. Mời bạn thưởng thức Newsletter #45.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="the-best"&gt;&lt;a class="link" href="https://www.paulgraham.com/best.html" target="_blank" rel="noopener"
&gt;The Best&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết &amp;ldquo;The Best&amp;rdquo;, Paul Graham chia sẻ quan điểm sâu sắc về cách nhận diện và làm việc với những người giỏi nhất trong lĩnh vực của họ. Ông cho rằng việc xác định ai là &amp;ldquo;người giỏi nhất&amp;rdquo; không chỉ đơn thuần dựa trên kỹ năng kỹ thuật, mà còn phụ thuộc vào cách họ tiếp cận vấn đề và động lực bên trong.&lt;/p&gt;
&lt;p&gt;Graham nhấn mạnh rằng những người giỏi nhất thường có đặc điểm chung là sự tò mò sâu sắc và khả năng tự học. Họ không chỉ giỏi vì biết nhiều, mà vì luôn muốn hiểu sâu hơn nữa. Điều này khiến họ không ngừng cải thiện và thích nghi với những thách thức mới.&lt;/p&gt;
&lt;p&gt;Một điểm quan trọng khác là cách những người giỏi nhất xử lý thất bại. Thay vì xem thất bại là điểm dừng, họ coi đó là cơ hội để học hỏi và phát triển. Điều này tạo ra một vòng lặp tích cực giúp họ tiến bộ nhanh chóng hơn những người khác.&lt;/p&gt;
&lt;h3 id="những-điểm-chính-cần-ghi-nhớ"&gt;Những điểm chính cần ghi nhớ:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tò mò là động lực cốt lõi&lt;/strong&gt;: Người giỏi nhất không bao giờ ngừng học hỏi&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tự học là kỹ năng quan trọng&lt;/strong&gt;: Họ chủ động tìm kiếm kiến thức thay vì chờ đợi&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thất bại là bước đệm&lt;/strong&gt;: Quan điểm tích cực về thất bại giúp họ phát triển nhanh&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chất lượng hơn số lượng&lt;/strong&gt;: Tập trung vào việc làm tốt một vài việc thay vì làm nhiều việc ở mức trung bình&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài học rút ra cho các lập trình viên: Hãy nuôi dưỡng sự tò mò, chủ động học hỏi, và đừng sợ thất bại. Đây là con đường để trở thành người giỏi nhất trong lĩnh vực của mình.&lt;/p&gt;
&lt;h2 id="ai-tools-make-developers-19-slower-not-faster"&gt;&lt;a class="link" href="https://threadreaderapp.com/thread/1943360399220388093.html" target="_blank" rel="noopener"
&gt;AI Tools Make Developers 19% Slower, Not Faster&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một nghiên cứu được thực hiện bởi METR (Machine Intelligence Research Institute) đã cho kết quả gây bất ngờ: các công cụ AI lập trình thực tế khiến lập trình viên chậm hơn 19% thay vì nhanh hơn như nhiều người tin. Đây là kết quả từ một thử nghiệm kiểm soát ngẫu nhiên với các lập trình viên open-source có kinh nghiệm.&lt;/p&gt;
&lt;p&gt;Nghiên cứu này thách thức giả định phổ biến rằng AI luôn giúp tăng năng suất. Trong khi các lập trình viên cảm thấy họ nhanh hơn 20% khi sử dụng AI, dữ liệu thực tế cho thấy họ hoàn thành công việc chậm hơn đáng kể. Điều này cho thấy có sự khác biệt lớn giữa cảm nhận chủ quan và hiệu quả thực tế.&lt;/p&gt;
&lt;h3 id="những-yếu-tố-có-thể-ảnh-hưởng"&gt;Những yếu tố có thể ảnh hưởng:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Thời gian review code AI&lt;/strong&gt;: Cần thời gian để kiểm tra và sửa lỗi trong code do AI tạo ra&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context switching&lt;/strong&gt;: Việc chuyển đổi giữa viết code và hướng dẫn AI có thể làm gián đoạn flow&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Over-reliance&lt;/strong&gt;: Phụ thuộc quá mức vào AI có thể làm giảm khả năng tư duy phản biện&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quality vs speed trade-off&lt;/strong&gt;: Code AI có thể nhanh nhưng cần nhiều thời gian để tinh chỉnh&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bài-học-thực-tế"&gt;Bài học thực tế:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Đừng tin hoàn toàn vào cảm nhận&lt;/strong&gt;: Cần đo lường hiệu quả thực tế thay vì dựa vào cảm giác&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI là công cụ, không phải phép màu&lt;/strong&gt;: Sử dụng AI đúng cách và đúng ngữ cảnh&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cân nhắc trade-offs&lt;/strong&gt;: Đánh giá kỹ lợi ích và chi phí khi áp dụng AI&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tiếp tục phát triển kỹ năng&lt;/strong&gt;: AI hỗ trợ nhưng không thay thế hoàn toàn kỹ năng lập trình&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài học cho các lập trình viên: AI là công cụ mạnh mẽ nhưng cần được sử dụng một cách chiến lược. Hãy đo lường hiệu quả thực tế và điều chỉnh cách sử dụng AI để đạt được lợi ích tối đa mà không làm giảm chất lượng công việc.&lt;/p&gt;
&lt;h2 id="evolution-of-uber"&gt;&lt;a class="link" href="https://www.uber.com/en-IN/blog/evolution-of-ubers-search-platform/" target="_blank" rel="noopener"
&gt;Evolution of Uber&amp;rsquo;s Search Platform&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này chia sẻ hành trình phát triển nền tảng tìm kiếm của Uber trong suốt 10 năm qua, từ một hệ thống đơn giản ban đầu đến một kiến trúc phức tạp phục vụ hàng triệu yêu cầu mỗi ngày. Đây là ví dụ điển hình cho việc thiết kế hệ thống có khả năng mở rộng theo thời gian.&lt;/p&gt;
&lt;p&gt;Uber bắt đầu với Elasticsearch đơn giản cho nhu cầu tìm kiếm cơ bản, nhưng khi lượng người dùng tăng lên, họ phải đối mặt với nhiều thách thức về hiệu suất và khả năng mở rộng. Giải pháp của họ là chuyển sang kiến trúc microservices với nhiều thành phần chuyên biệt, mỗi thành phần xử lý một khía cạnh cụ thể của việc tìm kiếm.&lt;/p&gt;
&lt;p&gt;Một điểm quan trọng trong quá trình phát triển là việc Uber áp dụng chiến lược &amp;ldquo;strangler fig&amp;rdquo; - dần dần thay thế các thành phần cũ bằng các thành phần mới mà không làm gián đoạn dịch vụ. Điều này cho phép họ cải thiện hệ thống trong khi vẫn duy trì hoạt động kinh doanh.&lt;/p&gt;
&lt;h3 id="những-bài-học-quan-trọng"&gt;Những bài học quan trọng:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bắt đầu đơn giản&lt;/strong&gt;: Đừng over-engineer từ đầu, hãy phát triển theo nhu cầu thực tế&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chiến lược strangler fig&lt;/strong&gt;: Thay thế dần dần thay vì đập đi xây lại toàn bộ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microservices architecture&lt;/strong&gt;: Chia nhỏ hệ thống để dễ quản lý và mở rộng&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitoring và observability&lt;/strong&gt;: Theo dõi hiệu suất để đưa ra quyết định dựa trên dữ liệu&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Incremental migration&lt;/strong&gt;: Di chuyển dữ liệu và traffic từng phần để giảm rủi ro&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài học cho các kỹ sư: Việc xây dựng hệ thống lớn là một quá trình liên tục cải tiến. Hãy bắt đầu đơn giản, đo lường hiệu suất, và phát triển theo nhu cầu thực tế của người dùng.&lt;/p&gt;
&lt;h2 id="vercel"&gt;&lt;a class="link" href="https://leerob.com/vercel" target="_blank" rel="noopener"
&gt;Vercel&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này chia sẻ trải nghiệm của Lee Robinson khi làm việc tại Vercel - công ty đứng sau Next.js và nền tảng triển khai ứng dụng web hiện đại. Đây là cái nhìn sâu sắc về văn hóa và quy trình phát triển sản phẩm tại một công ty công nghệ hàng đầu.&lt;/p&gt;
&lt;p&gt;Lee mô tả Vercel như một nơi tập trung vào việc xây dựng công cụ cho nhà phát triển, với văn hóa ưu tiên trải nghiệm người dùng và hiệu suất. Điều đặc biệt là cách họ phát triển sản phẩm bằng cách &amp;ldquo;ăn thịt chính mình&amp;rdquo; - sử dụng chính các công cụ mà họ xây dựng để phát triển sản phẩm của mình.&lt;/p&gt;
&lt;p&gt;Một điểm nổi bật là cách Vercel tiếp cận việc ra mắt tính năng mới. Họ không chỉ tập trung vào việc xây dựng tính năng, mà còn đầu tư vào việc giáo dục cộng đồng và tạo tài liệu chất lượng cao. Điều này giúp người dùng có thể áp dụng công nghệ mới một cách hiệu quả.&lt;/p&gt;
&lt;h3 id="những-điểm-đáng-học-hỏi"&gt;Những điểm đáng học hỏi:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Developer-first mindset&lt;/strong&gt;: Luôn đặt trải nghiệm của nhà phát triển lên hàng đầu&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dogfooding&lt;/strong&gt;: Sử dụng chính sản phẩm mình xây dựng để cải thiện liên tục&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Documentation as marketing&lt;/strong&gt;: Tài liệu tốt là cách marketing hiệu quả nhất&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Community building&lt;/strong&gt;: Đầu tư vào cộng đồng để tạo ra hệ sinh thái bền vững&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance obsession&lt;/strong&gt;: Luôn tối ưu hóa hiệu suất ở mọi cấp độ&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài học cho các lập trình viên: Hãy tập trung vào việc xây dựng sản phẩm mà chính bạn muốn sử dụng, và đừng ngại chia sẻ kiến thức với cộng đồng. Đây là cách xây dựng sự nghiệp lâu dài trong ngành công nghệ.&lt;/p&gt;
&lt;h2 id="tools"&gt;&lt;a class="link" href="https://lucumr.pocoo.org/2025/7/3/tools/" target="_blank" rel="noopener"
&gt;Tools&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, Armin Ronacher - tác giả của Flask và nhiều thư viện Python nổi tiếng - chia sẻ quan điểm sâu sắc về cách lựa chọn và sử dụng công cụ lập trình. Đây là một cái nhìn thực tế từ một kỹ sư có kinh nghiệm lâu năm trong việc xây dựng các công cụ cho cộng đồng lập trình.&lt;/p&gt;
&lt;p&gt;Armin phản ánh về xu hướng hiện nay khi các lập trình viên thường bị cuốn vào việc tìm kiếm &amp;ldquo;công cụ hoàn hảo&amp;rdquo; thay vì tập trung vào việc giải quyết vấn đề thực tế. Ông cho rằng việc lựa chọn công cụ nên dựa trên nhu cầu cụ thể và bối cảnh sử dụng, chứ không phải theo xu hướng hay sự phổ biến.&lt;/p&gt;
&lt;p&gt;Một điểm quan trọng mà Armin nhấn mạnh là sự cân bằng giữa việc học công cụ mới và việc thành thạo công cụ hiện có. Ông chia sẻ kinh nghiệm rằng việc thành thạo một công cụ tốt thường hiệu quả hơn việc liên tục chuyển đổi giữa các công cụ mới.&lt;/p&gt;
&lt;h3 id="những-nguyên-tắc-lựa-chọn-công-cụ"&gt;Những nguyên tắc lựa chọn công cụ:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Đơn giản hơn phức tạp&lt;/strong&gt;: Công cụ đơn giản thường hiệu quả hơn công cụ phức tạp&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phù hợp với bối cảnh&lt;/strong&gt;: Không có công cụ &amp;ldquo;tốt nhất&amp;rdquo; cho mọi tình huống&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Đầu tư vào thành thạo&lt;/strong&gt;: Thành thạo một công cụ tốt hơn biết nhiều công cụ nông&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tính bền vững&lt;/strong&gt;: Ưu tiên công cụ có khả năng duy trì lâu dài&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cộng đồng hỗ trợ&lt;/strong&gt;: Cộng đồng sử dụng rộng rãi là yếu tố quan trọng&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài học cho các lập trình viên: Đừng bị cuốn vào việc săn lùng công cụ mới. Hãy tập trung vào việc thành thạo các công cụ hiện có và lựa chọn công cụ dựa trên nhu cầu thực tế của dự án. Đây là cách tiếp cận hiệu quả và bền vững trong sự nghiệp lập trình.&lt;/p&gt;
&lt;h2 id="how-i-build-software-quickly"&gt;&lt;a class="link" href="https://evanhahn.com/how-i-build-software-quickly/" target="_blank" rel="noopener"
&gt;How I Build Software Quickly&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, Evan Hahn chia sẻ chiến lược thực tế để xây dựng phần mềm nhanh chóng mà vẫn duy trì chất lượng. Đây là kinh nghiệm từ một kỹ sư có nhiều năm làm việc với các dự án phần mềm dài hạn.&lt;/p&gt;
&lt;p&gt;Evan nhấn mạnh rằng việc xây dựng phần mềm nhanh không chỉ là về tốc độ viết mã, mà còn về cách đưa ra quyết định chiến lược về chất lượng và thời gian. Ông cho rằng mỗi dự án có yêu cầu chất lượng khác nhau - từ game jam 24 giờ đến thiết bị y tế như máy tạo nhịp tim.&lt;/p&gt;
&lt;h3 id="những-chiến-lược-chính"&gt;Những chiến lược chính:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Xác định mức độ &amp;ldquo;đủ tốt&amp;rdquo;&lt;/strong&gt;: Không phải mọi code cần hoàn hảo - hãy nhắm đến 8/10 điểm và đúng hạn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bắt đầu với bản nháp thô&lt;/strong&gt;: Tạo &amp;ldquo;spike&amp;rdquo; hoặc &amp;ldquo;walking skeleton&amp;rdquo; trước, sau đó hoàn thiện dần&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Làm việc với yêu cầu&lt;/strong&gt;: Thử làm nhẹ yêu cầu khi có thể - đôi khi không cần xử lý mọi edge case&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tránh xao lãng&lt;/strong&gt;: Đặt timer khi làm việc, tránh &amp;ldquo;lạc trong code&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thay đổi nhỏ&lt;/strong&gt;: Tách nhỏ các thay đổi thay vì patch lớn - dễ review, dễ revert&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="những-kỹ-năng-hữu-ích"&gt;Những kỹ năng hữu ích:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Đọc code&lt;/strong&gt;: Kỹ năng quan trọng nhất - giúp debug và học hỏi nhanh&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mô hình dữ liệu&lt;/strong&gt;: Đầu tư thời gian thiết kế schema đúng từ đầu&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scripting&lt;/strong&gt;: Viết script Bash/Python để tự động hóa công việc lặp đi lặp lại&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Debugger&lt;/strong&gt;: Sử dụng debugger thay vì print debugging&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Biết khi nghỉ&lt;/strong&gt;: Khi bị stuck, nghỉ vài phút thường giúp giải quyết vấn đề nhanh hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài học cho các lập trình viên: Xây dựng phần mềm nhanh không phải là viết code nhanh, mà là đưa ra quyết định thông minh về chất lượng, scope và quy trình. Hãy bắt đầu với bản nháp, tập trung vào điều quan trọng, và cải thiện dần dần.&lt;/p&gt;
&lt;h2 id="the-most-mysterious-bug-i-solved-at-work"&gt;&lt;a class="link" href="https://cadence.moe/blog/2025-07-02-the-most-mysterious-bug-i-solved-at-work/" target="_blank" rel="noopener"
&gt;The Most Mysterious Bug I Solved at Work&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, Cadence chia sẻ câu chuyện thực tế về một lỗi bí ẩn trong phần mềm y tế mà cô đã gặp phải. Đây là một ví dụ điển hình cho thấy quá trình debug phức tạp có thể trở thành một hành trình khám phá đầy thú vị và học hỏi.&lt;/p&gt;
&lt;p&gt;Câu chuyện xoay quanh một lỗi kỳ lạ xảy ra trong hệ thống e-referrals (giới thiệu điện tử) y tế tại Úc. Mỗi 2-4 tuần, một số giới thiệu bệnh nhân sẽ gặp lỗi khi chuyển đổi sang các định dạng khác nhau như HL7, CDA hoặc PDF. Lỗi báo: &amp;ldquo;Illegal Character entity: expansion character (code 0x2) not a valid XML character&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Ký tự 0x2 (STX - Start of Text) là một ký tự điều khiển vô hình, không bao giờ được sử dụng trong văn bản thông thường. Điều kỳ lạ là ký tự này xuất hiện trong thư giới thiệu của bác sĩ - văn bản mà bác sĩ tự tay gõ vào.&lt;/p&gt;
&lt;h3 id="quá-trình-điều-tra-phức-tạp"&gt;Quá trình điều tra phức tạp:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Khởi đầu&lt;/strong&gt;: Lỗi xuất hiện định kỳ, cần can thiệp thủ công mỗi lần&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phát hiện&lt;/strong&gt;: Ký tự 0x2 xuất hiện trong thư giới thiệu, không phải dữ liệu tự động từ PMS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nghi ngờ&lt;/strong&gt;: Ban đầu nghĩ là dữ liệu xấu từ hệ thống quản lý bệnh nhân&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Đột phá&lt;/strong&gt;: Phát hiện các thư giới thiệu có cùng nội dung và cùng lỗi&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="nguyên-nhân-thực-sự"&gt;Nguyên nhân thực sự:
&lt;/h3&gt;&lt;p&gt;Bác sĩ đang sao chép văn bản từ các file PDF writeback được lưu trong PMS. Khi một từ có dấu gạch nối nằm ở cuối dòng trong PDF, Microsoft Edge (trình xem PDF mặc định) sẽ chuyển dấu gạch nối thành ký tự 0x2 khi sao chép. Điều này xảy ra chỉ với Edge, không với các trình xem PDF khác.&lt;/p&gt;
&lt;h3 id="những-bài-học-quan-trọng-1"&gt;Những bài học quan trọng:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Don&amp;rsquo;t trust the obvious&lt;/strong&gt;: Đôi khi lỗi có nguyên nhân không liên quan đến code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User behavior matters&lt;/strong&gt;: Hành vi của người dùng có thể gây ra lỗi không ngờ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-platform issues&lt;/strong&gt;: Các trình duyệt khác nhau xử lý cùng một tác vụ khác nhau&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Edge cases are real&lt;/strong&gt;: Trường hợp biên có thể xảy ra trong thế giới thực&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;System thinking&lt;/strong&gt;: Cần hiểu toàn bộ quy trình, không chỉ phần code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài học cho các lập trình viên: Khi gặp lỗi bí ẩn, hãy kiên nhẫn và xem xét toàn bộ hệ thống từ góc độ người dùng. Đôi khi lỗi phức tạp nhất lại có nguyên nhân rất đơn giản nhưng cần cách tiếp cận toàn diện để tìm ra.&lt;/p&gt;
&lt;h2 id="cách-suy-nghĩ-về-thời-gian-trong-lập-trình"&gt;&lt;a class="link" href="https://shanrauf.com/archive/how-to-think-about-time-in-programming" target="_blank" rel="noopener"
&gt;Cách suy nghĩ về thời gian trong lập trình&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này của Shan Rauf cung cấp một mô hình khái niệm toàn diện để hiểu và xử lý thời gian trong lập trình - một chủ đề thường khiến nhiều lập trình viên cảm thấy đau đầu. Tác giả phân tích sự phức tạp của thời gian thông qua các khái niệm cốt lõi như &amp;ldquo;thời gian tuyệt đối&amp;rdquo; (absolute time) và &amp;ldquo;thời gian dân sự&amp;rdquo; (civil time).&lt;/p&gt;
&lt;p&gt;Rauf giải thích rằng thời gian tuyệt đối dựa trên các &amp;ldquo;khoảnh khắc&amp;rdquo; (instants) và &amp;ldquo;khoảng thời gian&amp;rdquo; (durations), có thể được biểu diễn bằng số giây kể từ một điểm tham chiếu (epoch). Điều này giúp máy tính dễ dàng thực hiện các phép tính và so sánh. Tuy nhiên, con người lại sử dụng &amp;ldquo;thời gian dân sự&amp;rdquo; với lịch Gregorian và múi giờ, tạo ra sự phức tạp khi cần chuyển đổi giữa hai hệ thống này.&lt;/p&gt;
&lt;p&gt;Một phần quan trọng của bài viết là phân tích về UTC và các giây nhuận (leap seconds). Tác giả giải thích cách UTC được định nghĩa bằng đồng hồ nguyên tử và cách các giây nhuận được thêm vào để đồng bộ với vị trí quay của Trái Đất. Điều này tạo ra những thách thức thực tế khi tính toán khoảng cách thời gian chính xác.&lt;/p&gt;
&lt;h3 id="những-điểm-chính-cần-ghi-nhớ-1"&gt;Những điểm chính cần ghi nhớ:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hai mô hình thời gian&lt;/strong&gt;: Thời gian tuyệt đối (dễ tính toán) vs thời gian dân sự (dễ hiểu với con người)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Epoch là quan trọng&lt;/strong&gt;: Việc chọn điểm tham chiếu ảnh hưởng đến cách biểu diễn thời gian&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UTC không hoàn hảo&lt;/strong&gt;: Có những trường hợp đặc biệt như leap seconds cần được xử lý&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timezone là vấn đề phức tạp&lt;/strong&gt;: Không chỉ là cộng/trừ giờ, mà còn liên quan đến lịch sử thay đổi múi giờ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Đừng tin tưởng tuyệt đối vào UTC&lt;/strong&gt;: &amp;ldquo;Just use UTC&amp;rdquo; không phải là câu trả lời cho mọi vấn đề&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết này đặc biệt hữu ích cho các lập trình viên đang làm việc với các hệ thống cần xử lý thời gian chính xác như booking systems, financial applications, hoặc distributed systems. Việc hiểu rõ các khái niệm cơ bản này giúp tránh được những lỗi khó debug và thiết kế hệ thống tốt hơn.&lt;/p&gt;
&lt;h2 id="nguồn-gốc-của-từ"&gt;&lt;a class="link" href="https://quuxplusone.github.io/blog/2025/04/04/etymology-of-call/" target="_blank" rel="noopener"
&gt;Nguồn gốc của từ &amp;ldquo;call&amp;rdquo; trong lập trình&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết thú vị này, Arthur O&amp;rsquo;Dwyer khám phá nguồn gốc lịch sử của từ &amp;ldquo;call&amp;rdquo; khi nói về việc &amp;ldquo;gọi&amp;rdquo; (call) một hàm trong lập trình. Đây là một hành trình ngược thời gian từ thư viện sách đến các ngôn ngữ lập trình hiện đại.&lt;/p&gt;
&lt;p&gt;Tác giả bắt đầu với câu hỏi tưởng chừng đơn giản: Tại sao chúng ta lại dùng từ &amp;ldquo;call&amp;rdquo; cho việc gọi hàm? Có ba giả thuyết chính được đề xuất: gọi như gọi bạn bè (đi, ở lại một lúc, rồi quay lại), gọi như gọi người hầu (triệu tập để thực hiện nhiệm vụ), hoặc gọi như gọi điện thoại (hỏi và nhận câu trả lời từ bên ngoài).&lt;/p&gt;
&lt;p&gt;Câu trả lời thực sự nằm ở giả thuyết thứ hai, nhưng có một cách gián tiếp. Từ &amp;ldquo;call&amp;rdquo; trong lập trình có nguồn gốc từ khái niệm &amp;ldquo;call for&amp;rdquo; (gọi lấy) một phần mềm con từ thư viện các phần mềm con, giống như cách chúng ta &amp;ldquo;gọi lấy&amp;rdquo; một cuốn sách từ thư viện có hệ thống kho đóng.&lt;/p&gt;
&lt;h3 id="hành-trình-lịch-sử"&gt;Hành trình lịch sử:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1876&lt;/strong&gt;: Từ &amp;ldquo;call number&amp;rdquo; (số gọi sách) xuất hiện trong khoa học thư viện, do Melvil Dewey đề xuất&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1947&lt;/strong&gt;: John W. Mauchly sử dụng &amp;ldquo;call in&amp;rdquo; trong bối cảnh thư viện các phần mềm con cho máy EDVAC&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1956&lt;/strong&gt;: MANIAC II có &amp;ldquo;call number&amp;rdquo; cho các phần mềm con trong thư viện giấy&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1958&lt;/strong&gt;: Fortran II giới thiệu câu lệnh CALL, nhanh chóng phổ biến hóa cụm từ &amp;ldquo;to call X&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1959&lt;/strong&gt;: Algol chấp nhận &amp;ldquo;call&amp;rdquo; từ Fortran&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1961&lt;/strong&gt;: Lần đầu tiên xuất hiện cụm từ &amp;ldquo;to call X&amp;rdquo; đúng nghĩa&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="những-điểm-chính-cần-ghi-nhớ-2"&gt;Những điểm chính cần ghi nhớ:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nguồn gốc từ thư viện&lt;/strong&gt;: Khái niệm &amp;ldquo;call&amp;rdquo; bắt nguồn từ việc gọi sách trong thư viện có hệ thống kho đóng&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fortran II là bước ngoặt&lt;/strong&gt;: Việc giới thiệu câu lệnh CALL đã định hình cách chúng ta nói về việc gọi hàm&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sự tiến hóa của ngôn ngữ&lt;/strong&gt;: Từ &amp;ldquo;call&amp;rdquo; đã chuyển từ việc gọi tại thời điểm biên dịch sang hành vi chuyển giao quyền điều khiển tại thời điểm chạy&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ảnh hưởng của Fortran&lt;/strong&gt;: Ngôn ngữ này đã tạo ra một thuật ngữ mới mà sau này trở thành chuẩn mực trong ngành&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài học cho các lập trình viên: Những thuật ngữ mà chúng ta sử dụng hàng ngày thường có nguồn gốc lịch sử phong phú. Việc hiểu nguồn gốc của các khái niệm giúp chúng ta hiểu sâu sắc hơn về cách thức hoạt động của máy tính và lý do tại sao các ngôn ngữ lập trình được thiết kế theo cách hiện tại.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Sau khi trải nghiệm lại với nhiều url thì có vẻ Cline + Kimi K2 đã tràn context, sau khi compact thì quên mất một số context, vì vậy rất dễ bị nhầm, cần nhắc lại nhiều lần về việc đây là Windows nên phải dùng các lệnh PowerShell hỗ trợ thay vì các lệnh Linux. Ngoài ra còn có vài sai lầm ngớ ngẩn như tóm tắt&amp;hellip; sai url :&amp;gt;&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #44</title><link>https://miti99.com/post/2025/08/03/</link><pubDate>Sun, 03 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/03/</guid><description>&lt;p&gt;&lt;em&gt;Như đã đề cập, hôm nay mình sẽ thử Newsletter với Roo Code. Các post tiếp theo sẽ dùng Roo Code + Qwen 3 Coder. Mời bạn thưởng thức Newsletter #44.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="cursor-unveils-game-changing-web-app-for-ai-coding-agents"&gt;&lt;a class="link" href="https://opentools.ai/news/cursor-unveils-game-changing-web-app-for-ai-coding-agents" target="_blank" rel="noopener"
&gt;Cursor Unveils Game-Changing Web App for AI Coding Agents&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Cursor, công cụ lập trình AI nổi tiếng, vừa công bố một ứng dụng web mới mang tính cách mạng cho các agent lập trình AI. Đây là bước tiến quan trọng trong việc làm cho các công cụ AI trở nên dễ tiếp cận và hiệu quả hơn cho các lập trình viên.&lt;/p&gt;
&lt;h3 id="tính-năng-nổi-bật"&gt;Tính năng nổi bật
&lt;/h3&gt;&lt;p&gt;Ứng dụng web mới của Cursor cho phép các lập trình viên tương tác với các agent AI một cách trực quan hơn thông qua giao diện web. Thay vì chỉ làm việc trong môi trường trình soạn thảo code, giờ đây người dùng có thể quản lý và giám sát các agent AI của họ thông qua một dashboard tập trung.&lt;/p&gt;
&lt;h3 id="lợi-ích-cho-lập-trình-viên"&gt;Lợi ích cho lập trình viên
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tăng năng suất&lt;/strong&gt;: Các agent AI có thể thực hiện các tác vụ lập trình phức tạp một cách tự động, giải phóng lập trình viên khỏi các công việc lặp đi lặp lại.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dễ sử dụng hơn&lt;/strong&gt;: Giao diện web trực quan giúp người mới bắt đầu dễ dàng tiếp cận và sử dụng các công cụ AI mạnh mẽ.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tích hợp liền mạch&lt;/strong&gt;: Ứng dụng web tích hợp chặt chẽ với trình soạn thảo Cursor, cho phép chuyển đổi mượt mà giữa các môi trường làm việc.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="tác-động-đến-ngành-công-nghiệp"&gt;Tác động đến ngành công nghiệp
&lt;/h3&gt;&lt;p&gt;Việc Cursor phát hành ứng dụng web này đánh dấu một bước tiến quan trọng trong việc phổ biến các công cụ lập trình AI. Bằng cách làm cho các agent AI trở nên dễ tiếp cận hơn, Cursor đang giúp thu hẹp khoảng cách giữa công nghệ AI tiên tiến và các lập trình viên thông thường.&lt;/p&gt;
&lt;p&gt;Đây là một tín hiệu cho thấy ngành công nghiệp phát triển phần mềm đang chuyển mình mạnh mẽ dưới tác động của AI, với các công cụ ngày càng thông minh và dễ sử dụng hơn.&lt;/p&gt;
&lt;h2 id="the-heart-of-software-engineering-still-beats"&gt;&lt;a class="link" href="https://annievella.com/posts/the-heart-of-software-engineering-still-beats/" target="_blank" rel="noopener"
&gt;The Heart of Software Engineering Still Beats&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong thời đại mà AI và các công cụ tự động hóa đang thay đổi cách chúng ta phát triển phần mềm, bài viết này nhắc nhở chúng ta rằng trái tim của kỹ thuật phần mềm vẫn đang đập - đó là con người và tư duy sáng tạo của họ.&lt;/p&gt;
&lt;h3 id="tư-duy-thiết-kế-vẫn-là-cốt-lõi"&gt;Tư duy thiết kế vẫn là cốt lõi
&lt;/h3&gt;&lt;p&gt;Dù AI có thể viết code nhanh hơn con người, nhưng việc đưa ra quyết định thiết kế, hiểu rõ nhu cầu người dùng và tạo ra giải pháp phù hợp vẫn cần đến tư duy con người. AI có thể hỗ trợ trong việc thực hiện, nhưng không thể thay thế hoàn toàn vai trò của con người trong việc xác định vấn đề và định hướng giải pháp.&lt;/p&gt;
&lt;h3 id="sự-cân-bằng-giữa-công-nghệ-và-con-người"&gt;Sự cân bằng giữa công nghệ và con người
&lt;/h3&gt;&lt;p&gt;Bài viết nhấn mạnh rằng thành công trong phát triển phần mềm không chỉ đến từ việc áp dụng công nghệ tiên tiến, mà còn từ khả năng hiểu và kết nối với con người - cả người dùng cuối và đồng nghiệp trong nhóm. Kỹ năng giao tiếp, khả năng giải quyết vấn đề phức tạp và tư duy hệ thống vẫn là những yếu tố quan trọng.&lt;/p&gt;
&lt;h3 id="bài-học-cho-lập-trình-viên-hiện-đại"&gt;Bài học cho lập trình viên hiện đại
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phát triển kỹ năng mềm&lt;/strong&gt;: Kỹ năng giao tiếp, làm việc nhóm và hiểu biết về nghiệp vụ ngày càng quan trọng hơn kỹ năng viết code thuần túy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tập trung vào giải quyết vấn đề&lt;/strong&gt;: Thay vì chỉ tập trung vào việc viết code, hãy tập trung vào việc hiểu vấn đề và tìm ra giải pháp tối ưu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giữ vững tư duy phản biện&lt;/strong&gt;: Trong thế giới đầy rẫy các công cụ và framework, khả năng đánh giá và lựa chọn công nghệ phù hợp là điều cần thiết.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Điều này nhắc nhở chúng ta rằng dù công nghệ có phát triển đến đâu, yếu tố con người vẫn là trung tâm của mọi thành công trong phát triển phần mềm.&lt;/p&gt;
&lt;h2 id="expert-generalist"&gt;&lt;a class="link" href="https://martinfowler.com/articles/expert-generalist.html" target="_blank" rel="noopener"
&gt;Expert Generalist&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong ngành phát triển phần mềm, vai trò của &amp;ldquo;chuyên gia đa năng&amp;rdquo; (expert generalist) đang ngày càng trở nên quan trọng. Đây là những người có kiến thức rộng rãi về nhiều lĩnh vực nhưng vẫn duy trì được chuyên môn sâu trong một số lĩnh vực cụ thể. Bài viết của Martin Fowler khám phá cách tiếp cận này có thể mang lại lợi ích cho cả cá nhân và tổ chức.&lt;/p&gt;
&lt;h3 id="khái-niệm-về-chuyên-gia-đa-năng"&gt;Khái niệm về chuyên gia đa năng
&lt;/h3&gt;&lt;p&gt;Chuyên gia đa năng không phải là người biết một chút về mọi thứ, mà là những người có khả năng hiểu sâu về một hoặc hai lĩnh vực, đồng thời có kiến thức đủ tốt về các lĩnh vực khác để có thể giao tiếp và hợp tác hiệu quả. Điều này đặc biệt quan trọng trong các môi trường phát triển phần mềm hiện đại, nơi các dự án thường yêu cầu sự kết hợp của nhiều công nghệ và kỹ năng khác nhau.&lt;/p&gt;
&lt;h3 id="lợi-ích-cho-cá-nhân"&gt;Lợi ích cho cá nhân
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tăng cơ hội nghề nghiệp&lt;/strong&gt;: Các chuyên gia đa năng thường linh hoạt hơn trong việc thích nghi với các vai trò khác nhau và có thể đóng góp vào nhiều khía cạnh của dự án.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hiểu biết toàn diện&lt;/strong&gt;: Việc hiểu rõ nhiều khía cạnh của hệ thống giúp đưa ra quyết định thiết kế tốt hơn và giải quyết vấn đề hiệu quả hơn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Khả năng lãnh đạo&lt;/strong&gt;: Kiến thức rộng giúp các chuyên gia đa năng trở thành những người dẫn dắt tự nhiên trong các nhóm phát triển.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="lợi-ích-cho-tổ-chức"&gt;Lợi ích cho tổ chức
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tăng cường giao tiếp&lt;/strong&gt;: Các chuyên gia đa năng có thể đóng vai trò cầu nối giữa các nhóm chuyên môn khác nhau, cải thiện sự hợp tác và giảm thiểu hiểu lầm.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tăng khả năng phục hồi&lt;/strong&gt;: Khi một chuyên gia chuyên sâu vắng mặt, các chuyên gia đa năng có thể đảm nhận vai trò của họ, giảm thiểu tác động đến tiến độ dự án.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cải thiện thiết kế hệ thống&lt;/strong&gt;: Với kiến thức về nhiều lĩnh vực, các chuyên gia đa năng có thể đưa ra những quyết định thiết kế toàn diện hơn.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="cách-nuôi-dưỡng-các-chuyên-gia-đa-năng"&gt;Cách nuôi dưỡng các chuyên gia đa năng
&lt;/h3&gt;&lt;p&gt;Để phát triển các chuyên gia đa năng trong tổ chức, cần có chiến lược rõ ràng:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khuyến khích học tập liên tục và khám phá các lĩnh vực mới&lt;/li&gt;
&lt;li&gt;Tạo cơ hội để các thành viên trong nhóm làm việc trên các dự án đa dạng&lt;/li&gt;
&lt;li&gt;Thiết lập hệ thống mentoring để chia sẻ kiến thức giữa các chuyên gia&lt;/li&gt;
&lt;li&gt;Đánh giá hiệu suất dựa trên cả chuyên môn sâu và khả năng đa dạng&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Xu hướng này phản ánh sự thay đổi trong ngành công nghiệp phần mềm, nơi mà sự phức tạp ngày càng tăng đòi hỏi các chuyên gia có tầm nhìn toàn diện hơn.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Trên đây là các bài dùng Roo Code với Qwen 3 Coder, nhìn chung thì tương đối chậm và tốn khá nhiều request. Sau đây mình sẽ dùng thử Roo Code với Kimi K2&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="writing-code-was-never-the-bottleneck"&gt;&lt;a class="link" href="https://ordep.dev/posts/writing-code-was-never-the-bottleneck" target="_blank" rel="noopener"
&gt;Writing code was never the bottleneck&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong thế giới phát triển phần mềm, nhiều người thường cho rằng việc viết code là phần chậm nhất và tốn kém nhất của quy trình. Tuy nhiên, bài viết này chỉ ra rằng quan điểm này có thể không còn đúng trong thực tế hiện đại.&lt;/p&gt;
&lt;h3 id="quan-điểm-truyền-thống-vs-thực-tế"&gt;Quan điểm truyền thống vs thực tế
&lt;/h3&gt;&lt;p&gt;Trong quá khứ, khi tài nguyên máy tính còn hạn chế và các công cụ hỗ trợ chưa phát triển, việc viết code có thể là một nút thắt cổ chai. Nhưng ngày nay, với sự xuất hiện của các công cụ lập trình hiện đại, thư viện phong phú và hạ tầng đám mây, vấn đề thường nằm ở những khía cạnh khác của quy trình phát triển.&lt;/p&gt;
&lt;h3 id="những-yếu-tố-thực-sự-ảnh-hưởng-đến-hiệu-suất"&gt;Những yếu tố thực sự ảnh hưởng đến hiệu suất
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thiết kế hệ thống&lt;/strong&gt;: Quyết định thiết kế sai lầm ở giai đoạn đầu có thể gây ra vấn đề nghiêm trọng về hiệu suất mà việc viết code nhanh hay chậm không thể khắc phục.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quản lý dữ liệu&lt;/strong&gt;: Việc xử lý, lưu trữ và truy xuất dữ liệu hiệu quả thường quan trọng hơn tốc độ viết code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tối ưu hóa hiệu suất&lt;/strong&gt;: Các yếu tố như network latency, database queries, và caching thường ảnh hưởng lớn hơn đến trải nghiệm người dùng cuối.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quy trình làm việc nhóm&lt;/strong&gt;: Thời gian dành cho họp hành, code review, và phối hợp giữa các thành viên trong nhóm thường chiếm phần lớn thời gian phát triển.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="bài-học-cho-lập-trình-viên-hiện-đại-1"&gt;Bài học cho lập trình viên hiện đại
&lt;/h3&gt;&lt;p&gt;Thay vì tập trung vào việc viết code nhanh hơn, các lập trình viên nên chú trọng vào:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hiểu rõ vấn đề cần giải quyết trước khi bắt tay vào code&lt;/li&gt;
&lt;li&gt;Sử dụng hiệu quả các công cụ và thư viện có sẵn&lt;/li&gt;
&lt;li&gt;Tối ưu hóa kiến trúc hệ thống&lt;/li&gt;
&lt;li&gt;Cải thiện kỹ năng giao tiếp và làm việc nhóm&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Điều này cho thấy tầm quan trọng của tư duy hệ thống trong phát triển phần mềm hiện đại, nơi mà việc viết code chỉ là một phần của toàn bộ quy trình.&lt;/p&gt;
&lt;h2 id="building-tiny-ai-tools"&gt;&lt;a class="link" href="https://www.seangoedecke.com/building-tiny-ai-tools/" target="_blank" rel="noopener"
&gt;Building Tiny AI Tools&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong thời đại mà các mô hình AI lớn đang chiếm sóng, bài viết này mang đến một góc nhìn mới mẻ: đôi khi những công cụ AI nhỏ gọn, tập trung vào một nhiệm vụ cụ thể lại hiệu quả hơn các giải pháp phức tạp.&lt;/p&gt;
&lt;h3 id="tại-sao-công-cụ-ai-nhỏ-lại-hiệu-quả"&gt;Tại sao công cụ AI nhỏ lại hiệu quả?
&lt;/h3&gt;&lt;p&gt;Các công cụ AI nhỏ (tiny AI tools) có nhiều lợi thế so với các mô hình lớn:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tốc độ xử lý nhanh&lt;/strong&gt;: Không cần tải và xử lý qua nhiều layer phức tạp&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chi phí thấp&lt;/strong&gt;: Ít tốn tài nguyên tính toán và lưu trữ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dễ tùy chỉnh&lt;/strong&gt;: Có thể dễ dàng điều chỉnh cho phù hợp với nhu cầu cụ thể&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Độ chính xác cao&lt;/strong&gt;: Khi được huấn luyện tốt cho một nhiệm vụ cụ thể&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ví-dụ-thực-tế-về-tiny-ai-tools"&gt;Ví dụ thực tế về tiny AI tools
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Công cụ phân loại email&lt;/strong&gt;: Một mô hình nhỏ chuyên phân loại email quan trọng vs spam&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trình tóm tắt văn bản&lt;/strong&gt;: AI nhỏ chuyên tóm tắt các đoạn văn ngắn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phát hiện lỗi code&lt;/strong&gt;: Công cụ AI nhỏ chuyên tìm lỗi syntax hoặc logic trong code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dịch thuật ngắn&lt;/strong&gt;: Dịch các cụm từ hoặc câu ngắn thay vì toàn bộ tài liệu&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="cách-xây-dựng-tiny-ai-tools"&gt;Cách xây dựng tiny AI tools
&lt;/h3&gt;&lt;p&gt;Để xây dựng các công cụ AI nhỏ hiệu quả:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Xác định rõ nhiệm vụ&lt;/strong&gt;: Tập trung vào một vấn đề cụ thể, không cố gắng làm quá nhiều thứ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sử dụng dữ liệu chất lượng&lt;/strong&gt;: Huấn luyện với dữ liệu sạch và phù hợp cho nhiệm vụ đó&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tối ưu hóa mô hình&lt;/strong&gt;: Sử dụng các kỹ thuật như quantization hoặc pruning để giảm kích thước&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Đánh giá liên tục&lt;/strong&gt;: Kiểm tra hiệu suất và điều chỉnh khi cần thiết&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bài-học-cho-lập-trình-viên"&gt;Bài học cho lập trình viên
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Đừng theo đuổi công nghệ lớn khi không cần thiết&lt;/strong&gt;: Đôi khi một giải pháp đơn giản lại hiệu quả hơn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tập trung vào vấn đề thực tế&lt;/strong&gt;: Thay vì cố gắng xây dựng một AI &amp;ldquo;vạn năng&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tối ưu hóa cho hiệu quả&lt;/strong&gt;: Cân nhắc giữa độ phức tạp và hiệu suất thực tế&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Điều này cho thấy rằng trong thế giới AI hiện đại, đôi khi &amp;ldquo;ít hơn lại là nhiều&amp;rdquo; - những công cụ nhỏ gọn, tập trung có thể mang lại giá trị thực tế lớn hơn các giải pháp phức tạp.&lt;/p&gt;
&lt;h2 id="modern-git-commands-and-features-you-should-be-using"&gt;&lt;a class="link" href="https://martinheinz.dev/blog/109" target="_blank" rel="noopener"
&gt;Modern Git Commands and Features You Should Be Using&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Hầu hết chúng ta đều sử dụng Git mỗi ngày, nhưng phần lớn chỉ dừng lại ở các lệnh cơ bản như &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;commit&lt;/code&gt;, &lt;code&gt;push&lt;/code&gt;, &lt;code&gt;pull&lt;/code&gt; - như thể vẫn đang ở năm 2005. Git đã phát triển rất nhiều kể từ đó, và việc sử dụng các tính năng hiện đại có thể khiến công việc của bạn trở nên dễ dàng hơn rất nhiều.&lt;/p&gt;
&lt;h3 id="1-git-switch-và-git-restore"&gt;1. &lt;code&gt;git switch&lt;/code&gt; và &lt;code&gt;git restore&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;git switch&lt;/code&gt;&lt;/strong&gt; (ra mắt 2019) thay thế &lt;code&gt;git checkout&lt;/code&gt; cho việc chuyển branch với các kiểm tra an toàn tốt hơn:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git switch other-branch
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git switch - &lt;span class="c1"&gt;# Quay lại branch trước đó&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git switch remote-branch &lt;span class="c1"&gt;# Chuyển sang remote branch và tự động tracking&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;git restore&lt;/code&gt;&lt;/strong&gt; cho phép khôi phục file về trạng thái trước đó mà không cần &lt;code&gt;reset&lt;/code&gt; phức tạp:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Bỏ stage changes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git restore --staged some-file.py
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Bỏ stage và discard changes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git restore --staged --worktree some-file.py
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Khôi phục file về commit cụ thể&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git restore --source HEAD~2 some-file.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="2-git-sparse-checkout"&gt;2. &lt;code&gt;git sparse-checkout&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;Giúp làm việc với monorepo lớn bằng cách chỉ checkout các thư mục cần thiết, tăng tốc độ đáng kể:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone --no-checkout https://github.com/example/monorepo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; monorepo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git sparse-checkout init --cone
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git checkout main &lt;span class="c1"&gt;# Chỉ checkout file trong root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git sparse-checkout &lt;span class="nb"&gt;set&lt;/span&gt; service/common &lt;span class="c1"&gt;# Chỉ lấy thư mục cần thiết&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="3-git-worktree"&gt;3. &lt;code&gt;git worktree&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;Cho phép làm việc với nhiều branch cùng lúc mà không cần clone lại repo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add ../hotfix master &lt;span class="c1"&gt;# Tạo worktree mới từ master&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ../hotfix &lt;span class="c1"&gt;# Làm việc độc lập&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree list &lt;span class="c1"&gt;# Liệt kê các worktree&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="4-git-bisect"&gt;4. &lt;code&gt;git bisect&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;Tìm commit gây ra bug bằng binary search - tính năng tồn tại từ 2012 nhưng ít được biết đến:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git bisect start
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git bisect bad HEAD &lt;span class="c1"&gt;# Commit hiện tại bị lỗi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git bisect good abc123 &lt;span class="c1"&gt;# Commit cuối cùng hoạt động tốt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Git tự động checkout commit ở giữa&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git bisect good/bad &lt;span class="c1"&gt;# Test và báo cáo kết quả&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git bisect reset &lt;span class="c1"&gt;# Quay lại commit ban đầu&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="bài-học-quan-trọng"&gt;Bài học quan trọng
&lt;/h3&gt;&lt;p&gt;Khi gặp vấn đề với Git, thay vì chỉ dựa vào các câu trả lời cũ trên StackOverflow, hãy kiểm tra documentation mới nhất. Git đã phát triển rất nhiều và có thể đã có cách giải quyết tốt hơn, đơn giản hơn cho vấn đề của bạn.&lt;/p&gt;
&lt;p&gt;Những công cụ này không chỉ tiết kiệm thời gian mà còn giúp workflow Git trở nên chuyên nghiệp và hiệu quả hơn, đặc biệt khi làm việc với các dự án lớn hoặc trong môi trường nhóm.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Sau khi trải nghiệm mình nhận thấy Kimi K2 luôn phản hồi nhanh hơn Qwen 3 Coder, dù dùng Cline hay Roo Code, và Roo Code gọi nhiều request hơn Cline, tuy nhiên độ hài lòng về kết quả thì cũng xêm xêm. Vì OpenRouter limit dựa trên số lần request chứ không phải tổng lượng token nên có lẽ mình sẽ chọn Cline + Kimi K2 để dùng tạm mỗi khi Claude Code chạm quota.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #43</title><link>https://miti99.com/post/2025/08/02/</link><pubDate>Sat, 02 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/02/</guid><description>&lt;p&gt;&lt;em&gt;Bài này mình thay đổi tool sử dụng thành Qwen Code và model sử dụng là Qwen 3 Coder, dùng qua api của OpenRouter. Thử nghiệm một tí xem thế nào. Mời bạn thưởng thức Newsletter #43.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="augmented-coding-beyond-the-vibes"&gt;&lt;a class="link" href="https://tidyfirst.substack.com/p/augmented-coding-beyond-the-vibes" target="_blank" rel="noopener"
&gt;Augmented Coding: Beyond the Vibes&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Kent Beck chia sẻ trải nghiệm thú vị về việc sử dụng &amp;ldquo;lập trình tăng cường&amp;rdquo; (augmented coding) - một phương pháp lập trình có sự hỗ trợ của AI một cách kỷ luật - để xây dựng thư viện B+ Tree trong Rust và Python, tạo ra BPlusTree3.&lt;/p&gt;
&lt;h3 id="khái-niệm-cốt-lõi"&gt;Khái niệm cốt lõi
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Lập trình tăng cường vs Lập trình theo cảm hứng:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lập trình theo cảm hứng (Vibe Coding)&lt;/strong&gt;: Tập trung vào hành vi hệ thống; ít quan tâm đến chất lượng mã. Các lỗi được phản hồi lại cho AI để sửa.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lập trình tăng cường (Augmented Coding)&lt;/strong&gt;: Nhấn mạnh chất lượng mã, tính đơn giản, kiểm thử và độ bao phủ - tương tự như lập trình truyền thống nhưng có sự hỗ trợ của AI.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="quá-trình-phát-triển"&gt;Quá trình phát triển
&lt;/h3&gt;&lt;p&gt;Beck đã áp dụng Nguyên tắc &amp;ldquo;Tidy First&amp;rdquo; của mình: tách biệt các thay đổi cấu trúc (tái cấu trúc) khỏi các thay đổi hành vi (tính năng mới). Ông sử dụng Phát triển Hướng kiểm thử (TDD) với một prompt nghiêm ngặt cho AI: &amp;ldquo;Luôn tuân theo các hướng dẫn trong plan.md. Khi tôi nói &amp;lsquo;go&amp;rsquo;, hãy tìm kiểm thử chưa đánh dấu tiếp theo trong plan.md, thực hiện kiểm thử đó, sau đó chỉ triển khai đủ mã để kiểm thử đó vượt qua.&amp;rdquo;&lt;/p&gt;
&lt;h3 id="dấu-hiệu-cảnh-báo-ai-đang-đi-chệch-hướng"&gt;Dấu hiệu cảnh báo AI đang đi chệch hướng
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;Vòng lặp hoặc chức năng không được yêu cầu&lt;/li&gt;
&lt;li&gt;Vô hiệu hóa hoặc xóa kiểm thử&lt;/li&gt;
&lt;li&gt;Thiết kế quá kỹ hoặc thêm tính năng không yêu cầu&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="kết-quả-ấn-tượng"&gt;Kết quả ấn tượng
&lt;/h3&gt;&lt;p&gt;Phiên bản Rust có hiệu suất cạnh tranh với &lt;code&gt;BTreeMap&lt;/code&gt; tiêu chuẩn của Rust, đặc biệt trong việc quét phạm vi. Phiên bản Python nhanh hơn &lt;code&gt;SortedDict&lt;/code&gt; trong các phép quét phạm vi. Một extension C cho Python được tạo bởi AI, đạt hiệu suất gần với mã gốc.&lt;/p&gt;
&lt;h3 id="những-suy-ngẫm"&gt;Những suy ngẫm
&lt;/h3&gt;&lt;p&gt;Lập trình tăng cường nâng cao năng suất bằng cách giảm thiểu các công việc thiết lập nhàm chán. AI có thể xử lý các tác vụ phức tạp như thiết lập môi trường kiểm thử hoặc tạo các benchmark hiệu suất. Lập trình vẫn là một quá trình sáng tạo và ra quyết định, ngay cả với sự hỗ trợ của AI.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Với combo trên sau khi viết được 1 bài đầu thì đang bị nó bị loop, gửi request 3-4 lần gì đến OpenRouter sau đó stuck luôn. Và bài đầu thì cũng rất mất thời gian. Tiếp theo mình thử Qwen Code với Kimi K2&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update, có vẻ Qwen Code không dùng với Kimi K2 được, mình gặp lỗi &lt;code&gt;API Error: Internal Server Error&lt;/code&gt; :v Sau đây mình thử Cline với Qwen 3 Coder nhé&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="coding-agents-have-crossed-a-chasm"&gt;&lt;a class="link" href="https://blog.singleton.io/posts/2025-06-14-coding-agents-cross-a-chasm/" target="_blank" rel="noopener"
&gt;Coding agents have crossed a chasm&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả David Singleton chia sẻ trải nghiệm chuyển đổi trong cách làm việc với các agent lập trình AI tự động. Bài viết mô tả sự thay đổi fundamental trong vài tháng gần đây, khi các agent lập trình đã vượt qua một &amp;ldquo;chasm&amp;rdquo; (vực thẳm) để trở thành công cụ không thể thiếu trong quá trình phát triển phần mềm.&lt;/p&gt;
&lt;h3 id="sự-phát-triển-của-các-công-cụ-lập-trình-ai"&gt;Sự phát triển của các công cụ lập trình AI
&lt;/h3&gt;&lt;p&gt;Tác giả mô tả quá trình phát triển theo &amp;ldquo;thang năng lực&amp;rdquo; của các công cụ lập trình AI:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Giai đoạn đầu&lt;/strong&gt;: Autocomplete thông minh, trợ lý hỗ trợ bên cạnh&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Giai đoạn gần đây&lt;/strong&gt;: Cộng tác viên tích cực với pair programming thời gian thực&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Giai đoạn hiện tại&lt;/strong&gt;: Intern chăm chỉ có thể giao phó các nhiệm vụ hoàn chỉnh&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ứng-dụng-thực-tế"&gt;Ứng dụng thực tế
&lt;/h3&gt;&lt;p&gt;Tác giả chia sẻ cách sử dụng Claude Code và OpenAI Codex trong công việc hàng ngày:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Công cụ cá nhân&lt;/strong&gt;: Mô tả yêu cầu bằng ngôn ngữ tự nhiên, để AI tạo script và công cụ nhỏ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Công việc&lt;/strong&gt;: Giao các bug nhỏ trực tiếp cho Codex xử lý hoàn toàn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code review&lt;/strong&gt;: Sử dụng Claude Code tích hợp với GitHub Actions để tìm lỗi&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="đột-phá-trong-debugging"&gt;Đột phá trong debugging
&lt;/h3&gt;&lt;p&gt;Một ví dụ cụ thể về việc sử dụng AI để giải quyết bug phức tạp trong luồng OAuth. Thay vì debug truyền thống, tác giả yêu cầu Claude tạo sequence diagram ASCII để mô tả toàn bộ luồng, giúp phát hiện race condition một cách nhanh chóng.&lt;/p&gt;
&lt;h3 id="những-thách-thức-và-rủi-ro"&gt;Những thách thức và rủi ro
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hiệu ứng gương&lt;/strong&gt;: Các công cụ khuếch đại cả điểm mạnh và điểm yếu của lập trình viên&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tư duy phụ thuộc&lt;/strong&gt;: Có thể dẫn đến việc né tránh các công việc tái cấu trúc quan trọng&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Yêu cầu nền tảng&lt;/strong&gt;: Vẫn cần kiến thức vững chắc để sử dụng hiệu quả và đánh giá kết quả&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="triển-vọng-tương-lai"&gt;Triển vọng tương lai
&lt;/h3&gt;&lt;p&gt;Tác giả tin rằng ranh giới giữa &amp;ldquo;AI hỗ trợ&amp;rdquo; và &amp;ldquo;AI tự động&amp;rdquo; sẽ ngày càng mờ nhòe. Các công cụ AI đang giúp tự động hóa các công việc cơ khí, cho phép lập trình viên tập trung vào các vấn đề thực sự quan trọng như kiến trúc, trải nghiệm người dùng và logic kinh doanh.&lt;/p&gt;
&lt;p&gt;Việc chuyển đổi này không thay thế lập trình viên mà biến họ thành những kỹ sư hiệu quả hơn, có thể tập trung vào các vấn đề cốt lõi thay vì các công việc lặp đi lặp lại.&lt;/p&gt;
&lt;h2 id="how-databases-store-your-tables-on-disk"&gt;&lt;a class="link" href="https://www.deepintodev.com/blog/how-databases-store-your-tables-on-disk" target="_blank" rel="noopener"
&gt;How Databases Store Your Tables on Disk&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giải thích chi tiết cách cơ sở dữ liệu lưu trữ bảng của bạn trên đĩa, một chủ đề quan trọng nhưng thường bị bỏ qua trong quá trình phát triển phần mềm. Tác giả Kaan Peksen đi sâu vào các khái niệm cốt lõi giúp người đọc hiểu rõ hơn về cách hoạt động nội bộ của cơ sở dữ liệu.&lt;/p&gt;
&lt;h3 id="các-khái-niệm-cốt-lõi"&gt;Các khái niệm cốt lõi
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Pages (Trang):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pages là các khối dữ liệu có kích thước cố định (ví dụ: 8KB trong PostgreSQL, 16KB trong MySQL)&lt;/li&gt;
&lt;li&gt;Cơ sở dữ liệu không đọc từng hàng riêng lẻ mà đọc toàn bộ page trong một lần I/O&lt;/li&gt;
&lt;li&gt;Khi một page được tải vào bộ nhớ đệm (buffer pool), tất cả các hàng trong page đó đều có sẵn, tạo hiệu quả &amp;ldquo;miễn phí&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Heap Files:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Heap là cấu trúc dữ liệu lưu trữ các page của bảng theo thứ tự không xác định&lt;/li&gt;
&lt;li&gt;Dữ liệu được đặt bất cứ đâu có chỗ trống, nên các page có thể bị phân mảnh&lt;/li&gt;
&lt;li&gt;Tìm kiếm trong heap thường yêu cầu quét toàn bộ bảng&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Indexes (Chỉ mục):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chỉ mục là cấu trúc dữ liệu riêng biệt (thường là B-Tree) chứa con trỏ đến heap&lt;/li&gt;
&lt;li&gt;Chỉ mục giúp xác định chính xác page nào cần đọc thay vì quét toàn bộ bảng&lt;/li&gt;
&lt;li&gt;Chỉ mục cũng được lưu trữ dưới dạng pages và yêu cầu I/O để đọc&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Clustered Indexes (Chỉ mục cụm):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trong clustered index, dữ liệu bảng được tổ chức vật lý theo thứ tự của chỉ mục&lt;/li&gt;
&lt;li&gt;Mỗi bảng chỉ có thể có một clustered index vì dữ liệu chỉ có thể được sắp xếp theo một cách&lt;/li&gt;
&lt;li&gt;Trong InnoDB (MySQL), clustered index được tạo tự động dựa trên PRIMARY KEY&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="những-điểm-quan-trọng-cần-lưu-ý"&gt;Những điểm quan trọng cần lưu ý
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hiệu suất với UUID:&lt;/strong&gt; Sử dụng UUID làm PRIMARY KEY có thể ảnh hưởng nghiêm trọng đến hiệu suất do việc chèn ngẫu nhiên gây ra page splits và phân mảnh.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kiến trúc InnoDB vs PostgreSQL:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;InnoDB: Các chỉ mục phụ trỏ đến giá trị PRIMARY KEY, sau đó mới đến dữ liệu thực tế&lt;/li&gt;
&lt;li&gt;PostgreSQL: Tất cả các chỉ mục đều trỏ trực tiếp đến row_id (tuple_id) trong heap&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cập nhật trong PostgreSQL:&lt;/strong&gt; PostgreSQL không cập nhật hàng tại chỗ mà thực hiện DELETE + INSERT, tạo phiên bản mới của hàng và để lại phiên bản cũ để phục vụ các yêu cầu đọc đồng thời.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="ứng-dụng-thực-tế-1"&gt;Ứng dụng thực tế
&lt;/h3&gt;&lt;p&gt;Hiểu biết về cách cơ sở dữ liệu lưu trữ dữ liệu giúp:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tối ưu hóa thiết kế bảng và lựa chọn khóa chính&lt;/li&gt;
&lt;li&gt;Cải thiện hiệu suất truy vấn bằng cách sử dụng chỉ mục hiệu quả&lt;/li&gt;
&lt;li&gt;Tránh các vấn đề hiệu suất liên quan đến phân mảnh và page splits&lt;/li&gt;
&lt;li&gt;Hiểu rõ hơn về hành vi của các hệ thống cơ sở dữ liệu khác nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Kiến thức này đặc biệt quan trọng cho các lập trình viên làm việc với cơ sở dữ liệu quy mô lớn, nơi hiệu suất và tối ưu hóa là yếu tố then chốt.&lt;/p&gt;
&lt;h2 id="software-engineering-with-llms-in-2025-reality-check"&gt;&lt;a class="link" href="https://newsletter.pragmaticengineer.com/p/software-engineering-with-llms-in-2025" target="_blank" rel="noopener"
&gt;Software engineering with LLMs in 2025: reality check&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Gergely Orosz cung cấp cái nhìn thực tế về việc sử dụng LLMs trong kỹ thuật phần mềm năm 2025, dựa trên khảo sát với hơn 1000 kỹ sư phần mềm tại các công ty AI startup và Big Tech. Bài viết phân tích thực trạng sử dụng các công cụ AI và quan điểm của các nhà phát triển đối với chúng.&lt;/p&gt;
&lt;h3 id="tổng-quan-thực-trạng"&gt;Tổng quan thực trạng
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Mức độ áp dụng rộng rãi:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;95% các kỹ sư được khảo sát đang sử dụng các công cụ AI hàng ngày&lt;/li&gt;
&lt;li&gt;Các công cụ phổ biến nhất: GitHub Copilot (80%), Cursor (40%), Claude (35%)&lt;/li&gt;
&lt;li&gt;Các công ty AI startup có xu hướng sử dụng các công cụ mới hơn như Cursor và Claude nhiều hơn so với Big Tech&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cách sử dụng thực tế:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Viết mã&lt;/strong&gt;: Tự động hoàn thành mã, tạo hàm, lớp và toàn bộ tệp&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Debugging&lt;/strong&gt;: Giải thích lỗi, đề xuất sửa chữa và viết kiểm thử&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tái cấu trúc&lt;/strong&gt;: Giúp tái cấu trúc mã và cải thiện kiến trúc&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tài liệu&lt;/strong&gt;: Tạo tài liệu cho mã và giải thích chức năng&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="quan-điểm-của-các-nhà-phát-triển"&gt;Quan điểm của các nhà phát triển
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Ưu điểm được công nhận:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tăng năng suất đáng kể trong các tác vụ lập trình hàng ngày&lt;/li&gt;
&lt;li&gt;Giúp học hỏi công nghệ mới nhanh hơn thông qua giải thích và ví dụ&lt;/li&gt;
&lt;li&gt;Giảm thời gian dành cho các tác vụ lặp đi lặp lại&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Những lo ngại và thách thức:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chất lượng mã&lt;/strong&gt;: 60% lo ngại về việc tạo ra mã có chất lượng thấp hoặc không an toàn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phụ thuộc quá mức&lt;/strong&gt;: Rủi ro mất kỹ năng cơ bản và khả năng giải quyết vấn đề độc lập&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bảo mật&lt;/strong&gt;: Lo ngại về việc rò rỉ mã nguồn và thông tin nhạy cảm&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hiệu suất&lt;/strong&gt;: Một số công cụ chậm và gây gián đoạn luồng làm việc&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="so-sánh-giữa-các-công-cụ"&gt;So sánh giữa các công cụ
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;GitHub Copilot:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vẫn là công cụ phổ biến nhất với tỷ lệ sử dụng 80%&lt;/li&gt;
&lt;li&gt;Ưu điểm: Tích hợp tốt với các IDE, tự động hoàn thành mã hiệu quả&lt;/li&gt;
&lt;li&gt;Nhược điểm: Chậm hơn các công cụ mới, chất lượng đề xuất không nhất quán&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cursor:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đang tăng trưởng nhanh với 40% tỷ lệ sử dụng&lt;/li&gt;
&lt;li&gt;Ưu điểm: Giao diện thân thiện, hỗ trợ chat và chỉnh sửa trực tiếp trong trình soạn thảo&lt;/li&gt;
&lt;li&gt;Nhược điểm: Đôi khi tạo ra mã không chính xác, cần kiểm tra kỹ lưỡng&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Claude:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Được ưa chuộng tại các công ty AI startup với 35% tỷ lệ sử dụng&lt;/li&gt;
&lt;li&gt;Ưu điểm: Hiểu ngữ cảnh tốt, tạo mã chất lượng cao cho các tác vụ phức tạp&lt;/li&gt;
&lt;li&gt;Nhược điểm: Giới hạn về độ dài ngữ cảnh, chậm hơn một số đối thủ&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="tác-động-đến-ngành-công-nghiệp"&gt;Tác động đến ngành công nghiệp
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Đối với các công ty:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cần xây dựng chính sách sử dụng AI rõ ràng để đảm bảo bảo mật và chất lượng&lt;/li&gt;
&lt;li&gt;Đầu tư vào đào tạo để các kỹ sư sử dụng hiệu quả và an toàn&lt;/li&gt;
&lt;li&gt;Cân nhắc việc tích hợp các công cụ AI vào quy trình phát triển&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Đối với kỹ sư phần mềm:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cần phát triển kỹ năng prompt engineering để tận dụng tối đa các công cụ&lt;/li&gt;
&lt;li&gt;Duy trì kỹ năng cơ bản để kiểm tra và cải thiện mã do AI tạo ra&lt;/li&gt;
&lt;li&gt;Học cách làm việc hiệu quả với AI thay vì chống lại nó&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="triển-vọng-tương-lai-1"&gt;Triển vọng tương lai
&lt;/h3&gt;&lt;p&gt;Tác giả dự đoán rằng:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Việc sử dụng LLMs trong phát triển phần mềm sẽ trở thành tiêu chuẩn trong 2-3 năm tới&lt;/li&gt;
&lt;li&gt;Các công cụ sẽ trở nên thông minh hơn, tích hợp chặt chẽ hơn với các IDE&lt;/li&gt;
&lt;li&gt;Cần có các tiêu chuẩn và quy ước mới để đảm bảo chất lượng và bảo mật khi sử dụng AI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết kết luận rằng mặc dù LLMs mang lại nhiều lợi ích, nhưng việc sử dụng chúng một cách có trách nhiệm và có chọn lọc là rất quan trọng để duy trì chất lượng phần mềm và phát triển kỹ năng cá nhân.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Nhìn chung thì combo Cline với Qwen 3 Coder chạy được, nhưng hơi lâu, output thì hơi loằng quằng, bảo tóm tắt nhưng viết rất dài (cái này có thể do mình chưa tối ưu prompt, vì mình bảo nó đọc file CLAUDE.MD thôi). Tiếp theo mình thử Cline với Kimi K2 nhé&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="continuous-ai"&gt;&lt;a class="link" href="https://www.seangoedecke.com/continuous-ai/" target="_blank" rel="noopener"
&gt;Continuous AI&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Sean Goedecke khám phá khái niệm &amp;ldquo;Continuous AI&amp;rdquo; - một cách tiếp cận mới trong việc tích hợp trí tuệ nhân tạo vào quy trình phát triển phần mềm một cách liên tục và tự động. Tác giả đề xuất một mô hình mà trong đó AI không chỉ là công cụ hỗ trợ thụ động mà trở thành một phần tích hợp sâu sắc trong toàn bộ vòng đời phát triển phần mềm.&lt;/p&gt;
&lt;h3 id="khái-niệm-continuous-ai"&gt;Khái niệm Continuous AI
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Continuous AI&lt;/strong&gt; được định nghĩa là việc sử dụng AI một cách liên tục trong suốt quá trình phát triển, từ việc thiết kế ban đầu cho đến triển khai và bảo trì. Khác với cách sử dụng AI truyền thống chỉ tập trung vào việc viết mã, Continuous AI bao gồm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Thiết kế kiến trúc&lt;/strong&gt;: AI giúp phân tích yêu cầu và đề xuất kiến trúc phù hợp&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Viết mã&lt;/strong&gt;: Tạo mã nguồn với chất lượng cao và tuân thủ chuẩn mực&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kiểm thử&lt;/strong&gt;: Tự động tạo các ca kiểm thử và phát hiện lỗi&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tái cấu trúc&lt;/strong&gt;: Liên tục cải thiện mã nguồn mà không làm gián đoạn chức năng&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Triển khai&lt;/strong&gt;: Tối ưu hóa quá trình triển khai và giám sát hiệu suất&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="lợi-ích-của-continuous-ai"&gt;Lợi ích của Continuous AI
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Tăng năng suất đáng kể&lt;/strong&gt;: Khi AI được tích hợp liên tục, các lập trình viên có thể tập trung vào các vấn đề chiến lược thay vì các công việc lặp đi lặp lại. AI có thể xử lý các tác vụ như viết mã boilerplate, tạo tài liệu, hoặc tối ưu hóa hiệu suất.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chất lượng mã được cải thiện&lt;/strong&gt;: Với khả năng phân tích mã liên tục, AI có thể phát hiện các vấn đề tiềm ẩn sớm và đề xuất cải tiến trước khi chúng trở thành vấn đề nghiêm trọng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Giảm chi phí bảo trì&lt;/strong&gt;: Việc tái cấu trúc và cải thiện mã liên tục giúp giảm đáng kể chi phí bảo trì trong dài hạn.&lt;/p&gt;
&lt;h3 id="thách-thức-và-giải-pháp"&gt;Thách thức và giải pháp
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Khả năng kiểm soát&lt;/strong&gt;: Một trong những lo ngại chính là việc mất kiểm soát đối với mã nguồn. Tác giả đề xuất sử dụng các công cụ kiểm soát phiên bản nâng cao và quy trình review nghiêm ngặt để đảm bảo mọi thay đổi đều được kiểm tra kỹ lưỡng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Độ tin cậy của AI&lt;/strong&gt;: Để đảm bảo độ tin cậy, cần thiết lập các bộ kiểm thử tự động và quy trình validation cho mọi thay đổi do AI thực hiện.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tư duy của lập trình viên&lt;/strong&gt;: Cần thay đổi tư duy từ &amp;ldquo;AI là công cụ&amp;rdquo; sang &amp;ldquo;AI là đồng nghiệp&amp;rdquo;. Điều này đòi hỏi đào tạo và thời gian để thích nghi.&lt;/p&gt;
&lt;h3 id="triển-vọng-tương-lai-2"&gt;Triển vọng tương lai
&lt;/h3&gt;&lt;p&gt;Tác giả tin rằng Continuous AI sẽ trở thành tiêu chuẩn trong phát triển phần mềm trong vài năm tới. Khi các công cụ AI ngày càng tinh vi, chúng sẽ có thể xử lý các tác vụ phức tạp hơn và tích hợp sâu hơn vào quy trình phát triển. Điều này sẽ dẫn đến một thế hệ mới của các công cụ phát triển phần mềm, nơi con người và AI làm việc cùng nhau một cách liền mạch để tạo ra phần mềm chất lượng cao hơn và nhanh hơn bao giờ hết.&lt;/p&gt;
&lt;h3 id="kết-luận"&gt;Kết luận
&lt;/h3&gt;&lt;p&gt;Continuous AI không chỉ là một công nghệ mới mà là một cách tiếp cận hoàn toàn mới đối với việc phát triển phần mềm. Bằng cách tích hợp AI một cách liên tục vào mọi khía cạnh của quy trình phát triển, chúng ta có thể đạt được mức độ năng suất và chất lượng mà trước đây không thể tưởng tượng được. Tuy nhiên, thành công của Continuous AI phụ thuộc vào khả năng của chúng ta trong việc thay đổi tư duy và thiết lập các quy trình phù hợp để làm việc cùng AI một cách hiệu quả.&lt;/p&gt;
&lt;h2 id="caching-is-an-abstraction-not-an-optimization"&gt;&lt;a class="link" href="https://buttondown.com/jaffray/archive/caching-is-an-abstraction-not-an-optimization/" target="_blank" rel="noopener"
&gt;Caching is an abstraction, not an optimization&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Jaffray đưa ra một quan điểm độc đáo về caching trong phát triển phần mềm: caching không nên được xem như một kỹ thuật tối ưu hóa hiệu suất, mà là một cơ chế trừu tượng hóa để ẩn đi sự phức tạp của các hệ thống phụ thuộc.&lt;/p&gt;
&lt;h3 id="caching-như-một-abstraction-layer"&gt;Caching như một abstraction layer
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Truyền thống vs Quan điểm mới:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Truyền thống&lt;/strong&gt;: Caching được coi là &amp;ldquo;tối ưu hóa sớm&amp;rdquo; (premature optimization) - một kỹ thuật được áp dụng sau khi phát hiện vấn đề hiệu suất&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quan điểm mới&lt;/strong&gt;: Caching là một abstraction layer giúp ẩn đi sự phức tạp của các hệ thống bên dưới, tương tự như cách các lớp trừu tượng khác hoạt động&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ví-dụ-thực-tế"&gt;Ví dụ thực tế
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Database caching layer:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thay vì truy cập trực tiếp vào database, ứng dụng truy cập vào cache layer&lt;/li&gt;
&lt;li&gt;Cache layer này ẩn đi việc database có thể chậm, không khả dụng, hoặc đang gặp vấn đề&lt;/li&gt;
&lt;li&gt;Ứng dụng không cần biết chi tiết về cách dữ liệu được lấy - chỉ cần biết nó có sẵn&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;API caching:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khi một service gọi API bên ngoài, caching layer có thể:
&lt;ul&gt;
&lt;li&gt;Trả về dữ liệu cached khi API không khả dụng&lt;/li&gt;
&lt;li&gt;Giảm số lượng request đến API&lt;/li&gt;
&lt;li&gt;Ẩn đi sự phức tạp của rate limiting và quota management&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="lợi-ích-của-việc-xem-caching-như-abstraction"&gt;Lợi ích của việc xem caching như abstraction
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Giảm coupling:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ứng dụng không cần biết chi tiết về các hệ thống phụ thuộc&lt;/li&gt;
&lt;li&gt;Có thể thay đổi backend mà không ảnh hưởng đến ứng dụng&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tăng reliability:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cache layer có thể cung cấp dữ liệu fallback khi các hệ thống phụ thuộc gặp sự cố&lt;/li&gt;
&lt;li&gt;Giảm impact của các lỗi phụ thuộc ngoài&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Đơn giản hóa development:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Developers có thể làm việc với cache layer thay vì phải hiểu toàn bộ hệ thống phụ thuộc&lt;/li&gt;
&lt;li&gt;Testing trở nên dễ dàng hơn vì có thể mock cache layer&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="caching-patterns-như-abstraction"&gt;Caching patterns như abstraction
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Cache-aside (Lazy loading):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ứng dụng kiểm tra cache trước, nếu không có thì lấy từ source và cache lại&lt;/li&gt;
&lt;li&gt;Pattern này tạo ra một abstraction rõ ràng giữa ứng dụng và data source&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Write-through caching:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tất cả writes đều đi qua cache layer&lt;/li&gt;
&lt;li&gt;Cache layer đảm bảo consistency giữa cache và source&lt;/li&gt;
&lt;li&gt;Ứng dụng không cần quan tâm đến việc đồng bộ&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Event-driven invalidation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cache tự động invalidate dựa trên events từ source&lt;/li&gt;
&lt;li&gt;Ứng dụng không cần quản lý cache lifecycle&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="thách-thức-và-giải-pháp-1"&gt;Thách thức và giải pháp
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Consistency challenges:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khi xem caching như abstraction, cần đảm bảo consistency giữa cache và source&lt;/li&gt;
&lt;li&gt;Giải pháp: Sử dụng event sourcing hoặc change data capture (CDC) để tự động cập nhật cache&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cache warming:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thay vì lazy loading, có thể pre-populate cache để tránh cold start&lt;/li&gt;
&lt;li&gt;Điều này giống như việc khởi tạo một abstraction với state ban đầu&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Monitoring và observability:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cần theo dõi cache hit/miss ratio để hiểu behavior của abstraction&lt;/li&gt;
&lt;li&gt;Metrics giúp phát hiện khi cache layer không hoạt động như mong đợi&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="kết-luận-1"&gt;Kết luận
&lt;/h3&gt;&lt;p&gt;Việc xem caching như một abstraction layer thay vì optimization technique thay đổi cách chúng ta thiết kế và triển khai caching. Điều này dẫn đến các hệ thống có khả năng chịu lỗi cao hơn, dễ maintain hơn, và ít coupling với các hệ thống phụ thuộc. Quan trọng nhất, nó giúp developers tập trung vào business logic thay vì phải lo lắng về hiệu suất và availability của các hệ thống bên dưới.&lt;/p&gt;
&lt;h2 id="you-should-delete-tests"&gt;&lt;a class="link" href="https://andre.arko.net/2025/06/30/you-should-delete-tests/" target="_blank" rel="noopener"
&gt;You should delete tests&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Andre Arko đưa ra quan điểm gây tranh cãi nhưng thú vị: chúng ta nên xóa các bài kiểm thử (tests) thay vì cố gắng duy trì tất cả chúng. Tác giả chia sẻ kinh nghiệm thực tế từ việc quản lý RubyGems.org - một trong những hệ thống lớn nhất của Ruby ecosystem.&lt;/p&gt;
&lt;h3 id="vấn-đề-với-việc-giữ-tất-cả-tests"&gt;Vấn đề với việc giữ tất cả tests
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Chi phí bảo trì cao:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mỗi test cần được duy trì khi codebase thay đổi&lt;/li&gt;
&lt;li&gt;Tests lỗi thời (outdated) trở thành gánh nặng thay vì tài sản&lt;/li&gt;
&lt;li&gt;Thời gian CI/CD tăng lên đáng kể với số lượng tests lớn&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;False sense of security:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tests cũ có thể vẫn chạy qua (pass) nhưng không còn test đúng behavior&lt;/li&gt;
&lt;li&gt;Nhiều tests duplicate - test cùng một behavior nhiều lần&lt;/li&gt;
&lt;li&gt;Một số tests test implementation details thay vì behavior thực tế&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="khi-nào-nên-xóa-tests"&gt;Khi nào nên xóa tests
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Tests không còn giá trị:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Test implementation details (cách code được viết) thay vì behavior (kết quả)&lt;/li&gt;
&lt;li&gt;Tests cho features đã bị xóa hoặc thay đổi hoàn toàn&lt;/li&gt;
&lt;li&gt;Tests duplicate - nhiều tests test cùng một điều kiện&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tests quá cụ thể (overspecified):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tests bị gãy (break) với mọi thay đổi nhỏ trong implementation&lt;/li&gt;
&lt;li&gt;Tests kiểm tra thứ tự gọi methods hoặc cấu trúc internal&lt;/li&gt;
&lt;li&gt;Tests có quá nhiều setup phức tạp cho một behavior đơn giản&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="quy-trình-xóa-tests-một-cách-có-trách-nhiệm"&gt;Quy trình xóa tests một cách có trách nhiệm
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Bước 1: Phân loại tests&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đánh giá mỗi test: test behavior quan trọng hay implementation detail?&lt;/li&gt;
&lt;li&gt;Xác định tests có thể được gộp lại (merge) thay vì xóa&lt;/li&gt;
&lt;li&gt;Tìm tests đã bị lỗi thời (obsolete)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Bước 2: Đảm bảo coverage&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trước khi xóa, đảm bảo behavior quan trọng vẫn được test bởi tests khác&lt;/li&gt;
&lt;li&gt;Sử dụng coverage tools để xác định behavior chưa được test&lt;/li&gt;
&lt;li&gt;Tạo tests mới nếu cần thiết để bảo vệ behavior quan trọng&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Bước 3: Xóa và refactor&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xóa tests đã được xác định là không cần thiết&lt;/li&gt;
&lt;li&gt;Refactor tests còn lại để rõ ràng hơn và maintainable hơn&lt;/li&gt;
&lt;li&gt;Gộp tests duplicate để giảm số lượng mà vẫn bảo vệ behavior&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="lợi-ích-của-việc-xóa-tests"&gt;Lợi ích của việc xóa tests
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Tăng tốc development:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CI/CD chạy nhanh hơn với ít tests hơn&lt;/li&gt;
&lt;li&gt;Developers ít phải fix tests bị gãy do thay đổi không liên quan&lt;/li&gt;
&lt;li&gt;Dễ dàng refactor code mà không phải update nhiều tests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tests chất lượng cao hơn:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tập trung vào tests cho behavior quan trọng thực sự&lt;/li&gt;
&lt;li&gt;Tests trở nên clearer và dễ hiểu hơn&lt;/li&gt;
&lt;li&gt;Giảm noise trong test suite&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Văn hóa development tốt hơn:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khuyến khích việc viết tests có ý nghĩa thay vì viết tests vì &amp;ldquo;phải có tests&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Developers thoải mái hơn trong việc refactor và cải thiện code&lt;/li&gt;
&lt;li&gt;Tập trung vào giá trị thực tế của tests thay vì số lượng&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ví-dụ-thực-tế-từ-rubygemsorg"&gt;Ví dụ thực tế từ RubyGems.org
&lt;/h3&gt;&lt;p&gt;Tác giả chia sẻ kinh nghiệm sau khi xóa ~30% tests:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thời gian CI giảm từ 45 phút xuống 15 phút&lt;/li&gt;
&lt;li&gt;Số lần tests bị gãy do thay đổi không liên quan giảm đáng kể&lt;/li&gt;
&lt;li&gt;Developers hạnh phúc hơn và thoải mái hơn khi refactor&lt;/li&gt;
&lt;li&gt;Bug rate không tăng - vì các tests quan trọng vẫn được giữ lại&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="khi-không-nên-xóa-tests"&gt;Khi không nên xóa tests
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Tests cho business logic quan trọng:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tests cho calculations tài chính hoặc logic kinh doanh phức tạp&lt;/li&gt;
&lt;li&gt;Tests cho security features và authorization&lt;/li&gt;
&lt;li&gt;Tests cho edge cases quan trọng về mặt pháp lý hoặc tài chính&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tests integration:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tests kiểm tra interaction giữa các services&lt;/li&gt;
&lt;li&gt;Tests cho API contracts và data validation&lt;/li&gt;
&lt;li&gt;Tests cho critical user workflows&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="kết-luận-2"&gt;Kết luận
&lt;/h3&gt;&lt;p&gt;Việc xóa tests không có nghĩa là chống lại testing - đó là việc tối ưu hóa test suite để tập trung vào giá trị thực tế. Bằng cách xóa tests không cần thiết và duy trì tests có ý nghĩa, chúng ta có thể tạo ra một test suite hiệu quả hơn, dễ maintain hơn, và cuối cùng là hữu ích hơn cho việc phát triển phần mềm chất lượng cao.&lt;/p&gt;
&lt;p&gt;Quan trọng nhất, điều này đòi hỏi một mindset shift: từ &amp;ldquo;càng nhiều tests càng tốt&amp;rdquo; sang &amp;ldquo;càng ít tests có ý nghĩa càng tốt&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Mình thấy Cline+Kimi K2 cũng gen dài (có thể do prompt như đã nói ở trên), nhưng được cái là response khá nhanh, vì vậy ít ra không phải đợi lâu. Phần prompt mình sẽ thử cải thiện trong tương lai &amp;ldquo;xa&amp;rdquo;. Còn mai mình sẽ thử Roo Code + Qwen 3 Coder/Kimi K2 trước. Hẹn gặp lại các bạn ở post ngày mai nhé&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Newsletter #42</title><link>https://miti99.com/post/2025/08/01/</link><pubDate>Fri, 01 Aug 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/08/01/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #42.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="challenging-algorithms-and-data-structures-every-programmer-should-try"&gt;&lt;a class="link" href="https://austinhenley.com/blog/challengingalgorithms.html" target="_blank" rel="noopener"
&gt;Challenging algorithms and data structures every programmer should try&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giới thiệu 6 thuật toán và cấu trúc dữ liệu thú vị mà mọi lập trình viên nên thử nghiệm để mở rộng kiến thức và kỹ năng giải quyết vấn đề:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sắp xếp topo (Topological sort)&lt;/strong&gt; - Thuật toán giúp xác định thứ tự phụ thuộc giữa các nhiệm vụ. Đặc biệt hữu ích trong việc lập lịch công việc, xây dựng hệ thống build, hoặc xử lý các mối quan hệ có hướng không có chu trình.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phân tích cú pháp đệ quy xuống (Recursive descent parsing)&lt;/strong&gt; - Kỹ thuật phân tích cú pháp mạnh mẽ để xây dựng trình biên dịch, xử lý ngôn ngữ tự nhiên hoặc phân tích dữ liệu có cấu trúc phức tạp. Phương pháp này giúp hiểu sâu hơn về cách máy tính &amp;ldquo;đọc&amp;rdquo; và xử lý ngôn ngữ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thuật toán so sánh chuỗi Myers&lt;/strong&gt; - Thuật toán tìm sự khác biệt giữa hai chuỗi văn bản một cách hiệu quả. Đây chính là nền tảng của các công cụ như Git diff, giúp hiển thị chính xác những thay đổi giữa các phiên bản mã nguồn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bộ lọc Bloom&lt;/strong&gt; - Cấu trúc dữ liệu xác suất thông minh để kiểm tra sự tồn tại của phần tử với tốc độ nhanh và tiết kiệm bộ nhớ. Ứng dụng rộng rãi trong cơ sở dữ liệu, cache và hệ thống phân tán.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bảng mảnh (Piece table)&lt;/strong&gt; - Kỹ thuật quản lý và chỉnh sửa văn bản hiệu quả, được sử dụng trong nhiều trình soạn thảo hiện đại. Cho phép thực hiện các thao tác undo/redo nhanh chóng mà không cần lưu trữ toàn bộ lịch sử thay đổi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cây Splay&lt;/strong&gt; - Cấu trúc cây nhị phân tự tối ưu hóa thông minh, tự động di chuyển các phần tử được truy cập gần đây lên gần gốc để tăng tốc độ truy xuất tiếp theo.&lt;/p&gt;
&lt;p&gt;Tác giả khuyến khích các lập trình viên, đặc biệt là những người mới bắt đầu, nên dành thời gian nghiên cứu và triển khai những thuật toán này. Việc thực hành sẽ giúp mở rộng tư duy giải quyết vấn đề và cung cấp những công cụ mạnh mẽ cho sự nghiệp lập trình.&lt;/p&gt;
&lt;h2 id="everything-i-know-about-good-system-design"&gt;&lt;a class="link" href="https://www.seangoedecke.com/good-system-design/" target="_blank" rel="noopener"
&gt;Everything I know about good system design&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ những nguyên tắc thiết kế hệ thống dựa trên kinh nghiệm thực tế, nhấn mạnh rằng thiết kế tốt thường đơn giản và không nổi bật. Tác giả tổng kết: &amp;ldquo;Thiết kế hệ thống tốt không phải về những thủ thuật thông minh, mà là biết cách sử dụng những thành phần đã được kiểm chứng ở đúng vị trí.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quản lý trạng thái (State Management)&lt;/strong&gt; - Giảm thiểu số lượng thành phần có trạng thái, ưu tiên một dịch vụ duy nhất quản lý ghi dữ liệu. Các dịch vụ không trạng thái dễ bảo trì và mở rộng hơn nhiều.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cơ sở dữ liệu&lt;/strong&gt; - Thiết kế lược đồ linh hoạt nhưng dễ đọc, sử dụng chỉ mục phù hợp và tối ưu hóa truy vấn. Tận dụng read replica để phân tải và cải thiện hiệu suất đọc dữ liệu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Xử lý nền (Background Processing)&lt;/strong&gt; - Sử dụng background job cho các thao tác chậm, tách biệt công việc tức thì và hoãn lại. Triển khai hệ thống hàng đợi một cách chiến lược để tránh blocking người dùng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bộ nhớ đệm (Caching)&lt;/strong&gt; - Sử dụng cache một cách thông minh, ưu tiên cải thiện hiệu suất hệ thống trước khi nghĩ đến cache. Áp dụng các chiến lược cache đa dạng từ in-memory đến external store.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Độ tin cậy hệ thống&lt;/strong&gt; - Triển khai logging cho các đường dẫn lỗi, tạo metrics và khả năng quan sát. Thiết kế kill switch và cơ chế retry, lập kế hoạch cho việc hệ thống fail một cách graceful.&lt;/p&gt;
&lt;p&gt;Triết lý cốt lõi là tập trung vào các phương pháp thực dụng, đơn giản trong kiến trúc hệ thống, ưu tiên tính đơn giản và độ tin cậy thay vì sự phức tạp không cần thiết.&lt;/p&gt;
&lt;h2 id="ai-coding-agents-are-already-commoditized"&gt;&lt;a class="link" href="https://www.seangoedecke.com/ai-agents-are-commoditized/" target="_blank" rel="noopener"
&gt;AI Coding Agents are Already Commoditized&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích hiện trạng thị trường AI agent lập trình, cho rằng các agent này đã trở thành hàng hóa thông thường và không còn đòi hỏi công nghệ phức tạp để phát triển. Tác giả khẳng định: &amp;ldquo;AI agent lập trình không có bí kíp gì&amp;hellip; Tất cả những gì bạn cần là một mô hình cơ sở thông minh hơn một chút.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thị trường bão hòa&lt;/strong&gt; - Các công ty công nghệ lớn như Claude, OpenAI, và GitHub đều đã ra mắt các AI agent tự động lập trình. Bất kỳ ai cũng có thể tạo ra một AI agent với ít mã nguồn, thường là miễn phí.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rào cản thấp&lt;/strong&gt; - Sự đột phá chính chỉ đơn giản là sử dụng các mô hình ngôn ngữ tiên tiến hơn. Không cần kiến thức chuyên sâu hay thuật toán phức tạp để xây dựng một agent hoạt động tốt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thiếu lợi thế cạnh tranh&lt;/strong&gt; - Do sự xuất hiện của các giải pháp mã nguồn mở và chi phí inference có thể thay thế lẫn nhau, việc tạo ra sự khác biệt trong thị trường AI agent trở nên khó khăn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược tiềm năng&lt;/strong&gt; - Tác giả đề xuất một số hướng cạnh tranh có thể như phân phối tốt hơn (ví dụ như sự tích hợp của GitHub) hoặc quyền truy cập độc quyền vào các mô hình AI.&lt;/p&gt;
&lt;p&gt;Bài viết cảnh báo rằng thị trường AI agent lập trình đã trở nên commoditized (hàng hóa hóa), với rào cản gia nhập thấp và ít sự khác biệt giữa các nhà cung cấp, đòi hỏi các công ty phải tìm kiếm những lợi thế cạnh tranh mới.&lt;/p&gt;
&lt;h2 id="java-what"&gt;&lt;a class="link" href="https://foojay.io/today/java-whats-old-part-i-collections/" target="_blank" rel="noopener"
&gt;Java, What&amp;rsquo;s Old? Part I: Collections&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết khám phá những tính năng &amp;ldquo;cũ&amp;rdquo; nhưng hữu ích trong Java Collections Framework mà nhiều lập trình viên có thể đã bỏ lỡ hoặc quên mất. Đây là những công cụ mạnh mẽ đã tồn tại từ lâu nhưng vẫn rất thực dụng trong các dự án hiện đại.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Optional cho kiểu nguyên thủy&lt;/strong&gt; - Java cung cấp &lt;code&gt;OptionalInt&lt;/code&gt;, &lt;code&gt;OptionalLong&lt;/code&gt;, và &lt;code&gt;OptionalDouble&lt;/code&gt; dành riêng cho các kiểu dữ liệu nguyên thủy, giúp tránh boxing/unboxing không cần thiết và cải thiện hiệu suất.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lớp thống kê tóm tắt&lt;/strong&gt; - &lt;code&gt;IntSummaryStatistics&lt;/code&gt; và &lt;code&gt;DoubleSummaryStatistics&lt;/code&gt; là những công cụ mạnh mẽ để tính toán các chỉ số thống kê như min, max, trung bình, tổng và số lượng phần tử trong một lần duyệt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LinkedHashMap với thứ tự truy cập&lt;/strong&gt; - Hỗ trợ sắp xếp theo thứ tự truy cập thông qua constructor parameter &lt;code&gt;accessOrder&lt;/code&gt;, cho phép triển khai bộ nhớ đệm LRU (Least Recently Used) đơn giản và hiệu quả.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WeakHashMap&lt;/strong&gt; - Sử dụng tham chiếu yếu (weak reference) cho các khóa, cho phép bộ thu gom rác tự động xóa các entry khi không còn tham chiếu cứng nào trỏ đến khóa, rất hữu ích cho cache và metadata mapping.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BitSet&lt;/strong&gt; - Cấu trúc dữ liệu tiết kiệm bộ nhớ để lưu trữ các giá trị boolean, chỉ sử dụng 1 bit cho mỗi giá trị thay vì 8 bit như &lt;code&gt;boolean[]&lt;/code&gt;, đặc biệt hữu ích khi xử lý tập dữ liệu lớn.&lt;/p&gt;
&lt;p&gt;Bài viết nhấn mạnh rằng những tính năng &amp;ldquo;cũ&amp;rdquo; này vẫn rất có giá trị và thường được bỏ qua vì các lập trình viên tập trung vào những tính năng mới hơn, trong khi những công cụ này đã được kiểm chứng qua thời gian.&lt;/p&gt;
&lt;h2 id="challenging-projects-every-programmer-should-try"&gt;&lt;a class="link" href="https://austinhenley.com/blog/challengingprojects.html" target="_blank" rel="noopener"
&gt;Challenging projects every programmer should try&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Austin Z. Henley đề xuất 6 dự án thách thức giúp lập trình viên phát triển kỹ năng sâu sắc qua việc xây dựng các ứng dụng phức tạp từ đầu. Đây là những dự án đòi hỏi hiểu biết đa lĩnh vực và cung cấp trải nghiệm học tập toàn diện.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trình soạn thảo văn bản&lt;/strong&gt; - Học cách quản lý cấu trúc dữ liệu phức tạp để lưu trữ văn bản, hiểu hành vi con trỏ và thao tác văn bản. Triển khai các tính năng nâng cao như undo/redo giúp nắm vững quản lý trạng thái ứng dụng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Game 2D (Space Invaders)&lt;/strong&gt; - Nắm vững kỹ thuật render đồ họa, hiểu về game loop và xử lý đầu vào người dùng. Thực hành quản lý đối tượng và logic game, từ đó học cách tối ưu hóa hiệu suất real-time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trình biên dịch (Tiny BASIC)&lt;/strong&gt; - Học phân tích từ vựng và cú pháp, tạo cây cú pháp trừu tượng (AST). Thực hành sinh mã và tối ưu hóa, hiểu sâu về cách máy tính &amp;ldquo;hiểu&amp;rdquo; và thực thi mã nguồn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hệ điều hành mini&lt;/strong&gt; - Hiểu tương tác phần cứng mức thấp, học về quy trình khởi động và quản lý bộ nhớ. Thực hành kỹ thuật lập lịch hệ thống và quản lý tài nguyên máy tính.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bảng tính (Thách thức nâng cao)&lt;/strong&gt; - Kết hợp kiến thức từ trình soạn thảo và trình biên dịch, học lập trình phản ứng (reactive programming). Triển khai thông dịch nội dung ô tính và quản lý phụ thuộc giữa các ô.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trình giả lập console game (Thách thức nâng cao)&lt;/strong&gt; - Mô phỏng các thành phần phần cứng, giả lập CPU và hành vi hệ thống. Bắt đầu với console đơn giản như CHIP-8 rồi tiến tới các hệ thống phức tạp hơn.&lt;/p&gt;
&lt;p&gt;Tác giả nhấn mạnh rằng những dự án này cung cấp cơ hội học tập sâu sắc qua nhiều lĩnh vực lập trình khác nhau, giúp lập trình viên hiểu rõ các nguyên tắc thiết kế phần mềm phức tạp và phát triển tư duy giải quyết vấn đề một cách toàn diện.&lt;/p&gt;
&lt;h2 id="autonomous-coding-agents-a-codex-example"&gt;&lt;a class="link" href="https://martinfowler.com/articles/exploring-gen-ai/autonomous-agents-codex-example.html" target="_blank" rel="noopener"
&gt;Autonomous coding agents: A Codex example&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Birgitta Böckeler trên blog Martin Fowler khám phá việc sử dụng AI agent lập trình tự động, cụ thể là OpenAI Codex, để giải quyết một nhiệm vụ nhỏ trong ứng dụng Haiven. Đây là một nghiên cứu thực tế về khả năng và hạn chế của AI agent trong môi trường phát triển thực.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phân loại AI agent lập trình&lt;/strong&gt; - Tác giả phân biệt hai loại: AI agent hướng dẫn (tương tác trực tiếp với lập trình viên như GitHub Copilot) và AI agent nền tự động (hoạt động độc lập trong môi trường riêng để tạo mã).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nhiệm vụ thử nghiệm&lt;/strong&gt; - Cải thiện nhãn hiển thị từ &amp;ldquo;client-research&amp;rdquo; thành &amp;ldquo;Client Research&amp;rdquo; - một nhiệm vụ tưởng chừng đơn giản nhưng đòi hỏi hiểu biết về cấu trúc dự án và ngữ cảnh mã nguồn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phương pháp hoạt động&lt;/strong&gt; - AI agent sử dụng tìm kiếm văn bản đơn giản để định vị mã cần thay đổi, sau đó áp dụng các chỉnh sửa phù hợp. Môi trường phát triển từ xa đóng vai trò then chốt cho hoạt động của agent.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kết quả quan sát&lt;/strong&gt; - Chất lượng giải pháp khác nhau đáng kể giữa các lần chạy, cho thấy tính không ổn định trong hiệu suất của AI agent. Một số lần chạy tạo ra giải pháp chính xác, trong khi những lần khác lại tạo ra mã có vấn đề.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thách thức chính&lt;/strong&gt; - Thiết lập môi trường phù hợp và quyết định khi nào nên tiếp tục hoặc loại bỏ mã do agent tạo ra. Việc giám sát và đánh giá chất lượng đầu ra vẫn đòi hỏi sự can thiệp của con người.&lt;/p&gt;
&lt;p&gt;Bài viết cung cấp góc nhìn thực tế về tiềm năng và giới hạn của AI agent tự động trong phát triển phần mềm, nhấn mạnh rằng công nghệ này vẫn cần sự giám sát và hướng dẫn từ lập trình viên con người.&lt;/p&gt;
&lt;h2 id="implementing-an-undoredo-system-in-a-complex-visual-application"&gt;&lt;a class="link" href="https://mlacast.com/projects/undo-redo" target="_blank" rel="noopener"
&gt;Implementing an Undo/Redo System in a Complex Visual Application&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết thảo luận về việc triển khai hệ thống undo/redo nhận biết ngữ cảnh cho Alkemion Studio, một công cụ brainstorming trực quan. Thách thức chính là thiết kế một hệ thống hoạt động qua nhiều ngữ cảnh ứng dụng mà không gây nhầm lẫn cho người dùng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nguyên tắc thiết kế cốt lõi&lt;/strong&gt; - Tạo hệ thống theo dõi hành động theo ngữ cảnh cụ thể, ngăn người dùng hoàn tác những hành động mà họ không thể nhìn thấy trực quan. Sử dụng kiến trúc lớp &amp;ldquo;Action&amp;rdquo; linh hoạt để quản lý các thao tác phức tạp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thành phần kỹ thuật chính&lt;/strong&gt; - Action Classes (lớp cơ sở với phương thức undo/redo), Action Volumes (lưu trữ có tổ chức cho các hành động), Containers (môi trường hành động biệt lập), và Context Management (xác định hành động nào có thể được hoàn tác).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phương pháp tiếp cận độc đáo&lt;/strong&gt; - Kiến trúc đa stack thay vì single stack truyền thống, quản lý chỉ mục cẩn thận để theo dõi hành động theo thứ tự thời gian, khả năng xử lý tương tác đa ngữ cảnh phức tạp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thử thách triển khai&lt;/strong&gt; - Xử lý việc một hành động có thể ảnh hưởng đến nhiều ngữ cảnh khác nhau, đảm bảo tính nhất quán khi người dùng chuyển đổi giữa các môi trường làm việc trong ứng dụng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cải tiến tương lai&lt;/strong&gt; - Kế hoạch triển khai đồ thị phụ thuộc (dependency graph) để quản lý các điều kiện tiên quyết của hành động và xử lý các tình huống undo/redo phức tạp hơn, bao gồm cả việc xử lý hành động có dependencies.&lt;/p&gt;
&lt;p&gt;Bài viết cung cấp cái nhìn kỹ thuật sâu sắc về việc xây dựng hệ thống undo/redo mạnh mẽ vượt xa các triển khai tuyến tính truyền thống, đặc biệt hữu ích cho các ứng dụng có giao diện phức tạp và nhiều ngữ cảnh làm việc.&lt;/p&gt;
&lt;h2 id="the-software-engineering"&gt;&lt;a class="link" href="https://newsletter.manager.dev/p/the-software-engineering-squeeze" target="_blank" rel="noopener"
&gt;The software engineering &amp;lsquo;squeeze&amp;rsquo;&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Anton Zaides phân tích sự thay đổi mạnh mẽ trong nghề kỹ sư phần mềm, cho rằng &amp;ldquo;thời hoàng kim&amp;rdquo; dễ dàng trong ngành này đã kết thúc. Tác giả nhận định rằng nghề này đã trở nên quá dễ dàng trong 10-15 năm qua, với nhiều kỹ sư &amp;ldquo;trung bình&amp;rdquo; được tuyển dụng một cách dễ dàng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hiện thực mới&lt;/strong&gt; - Nghề kỹ sư phần mềm không còn là con đường dễ dàng để có thu nhập cao như trước. AI və các công nghệ mới đang tạo ra những thay đổi cơ bản trong cách thức làm việc và yêu cầu kỹ năng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thách thức cạnh tranh&lt;/strong&gt; - Không còn chỗ cho những người chỉ &amp;ldquo;làm theo ticket&amp;rdquo; mà không hiểu sâu về sản phẩm và công nghệ. Thị trường hiện tại đòi hỏi những kỹ sư có khả năng sáng tạo và giải quyết vấn đề thực tế.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lời khuyên cho kỹ sư&lt;/strong&gt; - Học hỏi và làm chủ các công cụ AI mới thay vì chống lại chúng, phát triển kỹ năng toàn diện hơn chỉ viết mã, hiểu rõ về sản phẩm và nhu cầu người dùng thay vì chỉ tập trung vào kỹ thuật.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Định hướng nghề nghiệp&lt;/strong&gt; - Các kỹ sư cần chuyển từ tư duy &amp;ldquo;nhân viên kỹ thuật&amp;rdquo; sang &amp;ldquo;người giải quyết vấn đề&amp;rdquo;, từ việc thực hiện yêu cầu thành tìm hiểu và đề xuất giải pháp tối ưu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thông điệp cốt lõi&lt;/strong&gt; - Nghề kỹ sư phần mềm giờ đây chỉ dành cho những người thực sự đam mê công nghệ và sẵn sàng học hỏi không ngừng. Thời kỳ &amp;ldquo;ăn theo&amp;rdquo; công nghệ để có công việc ổn định đã qua, thay vào đó là yêu cầu về chuyên môn thực sự và khả năng thích ứng liên tục.&lt;/p&gt;
&lt;p&gt;Bài viết nhấn mạnh rằng sự thay đổi này không nhất thiết là tiêu cực, mà là cơ hội để ngành công nghiệp phần mềm trở nên chuyên nghiệp và chất lượng hơn.&lt;/p&gt;
&lt;h2 id="go-is-8020-language"&gt;&lt;a class="link" href="https://blog.kowalczyk.info/article/d-2025-06-26/go-is-8020-language.html" target="_blank" rel="noopener"
&gt;Go is 80/20 language&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết thảo luận về triết lý thiết kế của Go, một ngôn ngữ được xây dựng theo nguyên tắc 80/20: cung cấp 80% tiện ích với chỉ 20% độ phức tạp. Tác giả lập luận rằng đây chính là sức mạnh cốt lõi của Go trong việc cân bằng giữa tính năng và sự đơn giản.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Triết lý hạn chế tính năng&lt;/strong&gt; - Go cố tình giới hạn các tính năng ngôn ngữ để duy trì sự đơn giản. Tác giả nhấn mạnh: &amp;ldquo;Không ai phủ nhận rằng 87% cung cấp nhiều tiện ích hơn 80%. Vấn đề là 7% tiện ích bổ sung đó đòi hỏi thêm 36% công việc.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ví dụ thiết kế 80/20 trong Go&lt;/strong&gt; - Struct tags tối giản nhưng đủ dùng, thư viện testing tiêu chuẩn đơn giản nhưng hiệu quả, concurrency với goroutines dễ hiểu và sử dụng, các kiểu generic tích hợp sẵn trước khi có user-defined generics.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ưu tiên thực dụng&lt;/strong&gt; - Go ưu tiên dễ học, đơn giản triển khai và tiện ích thực tế hơn là tính hoàn chỉnh về mặt lý thuyết. Ngôn ngữ tập trung vào việc giải quyết 80% các vấn đề phổ biến một cách hiệu quả.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tránh bẫy phức tạp hóa&lt;/strong&gt; - Tác giả chỉ ra rằng các ngôn ngữ như Swift, C# và Rust thường rơi vào bẫy liên tục thêm tính năng, tăng độ phức tạp mà không mang lại lợi ích tương xứng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lợi ích của phương pháp này&lt;/strong&gt; - Codebase Go dễ đọc và bảo trì, thời gian học ngôn ngữ ngắn, ít tranh cãi về style coding, hiệu suất biên dịch nhanh và deployment đơn giản.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thông điệp cốt lõi&lt;/strong&gt; - Thay vì cố gắng làm mọi thứ hoàn hảo, Go tập trung vào việc làm tốt những gì quan trọng nhất. Điều này tạo ra một ngôn ngữ thực dụng, dễ tiếp cận và hiệu quả cho phần lớn các use case trong phát triển phần mềm hiện đại.&lt;/p&gt;
&lt;p&gt;Bài viết khẳng định rằng sự &amp;ldquo;thiếu hụt&amp;rdquo; về tính năng của Go thực chất là một lợi thế, giúp các lập trình viên tập trung vào giải quyết vấn đề thay vì vật lộn với độ phức tạp của ngôn ngữ.&lt;/p&gt;</description></item><item><title>Newsletter #41</title><link>https://miti99.com/post/2025/07/31/</link><pubDate>Thu, 31 Jul 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/07/31/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #41.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="the-fastest-way-to-detect-a-vowel-in-a-string"&gt;&lt;a class="link" href="https://austinhenley.com/blog/vowels.html" target="_blank" rel="noopener"
&gt;The Fastest Way to Detect a Vowel in a String&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Austin Henley đã thực hiện một nghiên cứu thú vị về hiệu suất các phương pháp phát hiện nguyên âm trong chuỗi, so sánh 11 cách tiếp cận khác nhau và đưa ra những kết quả bất ngờ về tối ưu hóa hiệu suất thuật toán cơ bản.&lt;/p&gt;
&lt;p&gt;Nghiên cứu này bao gồm các phương pháp từ đơn giản như vòng lặp for, tìm kiếm regex, giao nhau tập hợp, biểu thức generator, đến những cách tiếp cận sáng tạo như sử dụng số nguyên tố. Kết quả đo lường cho thấy regex bất ngờ vượt trội về hiệu suất nhờ việc triển khai được tối ưu hóa trong C, sử dụng bitmap lookup để khớp ký tự. Điều thú vị là với chuỗi ngắn (độ dài 10), phương pháp &lt;code&gt;loop_in&lt;/code&gt; đơn giản nhất lại nhanh nhất, nhưng với chuỗi dài hơn thì các phương pháp regex lại thống trị.&lt;/p&gt;
&lt;p&gt;Bài viết cũng tiết lộ một số insight quan trọng: việc thay đổi thứ tự vòng lặp có thể cải thiện hiệu suất đáng kể, và tác giả đã tìm ra phương pháp &lt;code&gt;loop_in_perm&lt;/code&gt; đơn giản nhưng nhanh hơn cả regex. Kết luận thực tế là đối với hầu hết trường hợp sử dụng, nên chọn phương pháp dễ đọc nhất, vì sự khác biệt về hiệu suất chỉ quan trọng khi xử lý khối lượng chuỗi khổng lồ. Nghiên cứu này minh họa rõ ràng rằng ngay cả những tác vụ tưởng chừng đơn giản cũng có thể có đặc tính hiệu suất phức tạp và bất ngờ.&lt;/p&gt;
&lt;h2 id="writing-toy-software-is-a-joy"&gt;&lt;a class="link" href="https://blog.jsbarretto.com/post/software-is-joy" target="_blank" rel="noopener"
&gt;Writing Toy Software Is A Joy&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Joshua Barretto khuyến khích các lập trình viên tạo ra &amp;ldquo;chương trình đồ chơi&amp;rdquo; để tái khám phá niềm vui trong phát triển phần mềm và hiểu sâu sắc các khái niệm kỹ thuật thông qua việc tự tay xây dựng mọi thứ từ đầu.&lt;/p&gt;
&lt;p&gt;Triết lý cốt lõi được truyền cảm hứng từ câu nói của Richard Feynman: &amp;ldquo;Những gì tôi không thể tạo ra, tôi không hiểu được&amp;rdquo;. Tác giả cho rằng việc xây dựng phiên bản riêng của các công cụ và hệ thống giúp hiểu chúng một cách chân thực nhất. Các dự án đồ chơi tuân theo quy tắc 80:20 - nỗ lực tối thiểu để có được chức năng tối đa, tránh thiết kế quá phức tạp và mang lại những insight bất ngờ có thể áp dụng vào công việc chuyên nghiệp.&lt;/p&gt;
&lt;p&gt;Barretto đề xuất hơn 20 ý tưởng dự án từ đơn giản đến phức tạp: CHIP-8 Emulator, Physics Engine, Text Editor, Voxel Engine, cho đến x86 OS Kernel và Compiler cho ngôn ngữ giống C. Điều quan trọng là tác giả khuyến khích không sử dụng các mô hình ngôn ngữ lớn (LLM) cho những dự án này, mà thay vào đó hãy học qua khám phá trực tiếp và vật lộn với vấn đề.&lt;/p&gt;
&lt;p&gt;Bài viết lập luận rằng phát triển phần mềm hiện đại đang trở nên hàng hóa hóa, và các dự án đồ chơi là cách để kết nối lại với bản chất sáng tạo của lập trình. Đây là lời kêu gọi quay trở lại với niềm đam mê thuần túy của việc xây dựng thứ gì đó từ con số không, nơi mà quá trình khám phá có giá trị hơn cả việc tìm ra giải pháp nhanh chóng.&lt;/p&gt;
&lt;h2 id="field-notes-from-shipping-real-code-with-claude"&gt;&lt;a class="link" href="https://diwank.space/field-notes-from-shipping-real-code-with-claude" target="_blank" rel="noopener"
&gt;Field Notes From Shipping Real Code With Claude&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Diwank chia sẻ kinh nghiệm thực tế về việc sử dụng Claude trong phát triển phần mềm sản xuất, đưa ra những nguyên tắc và thực hành cụ thể để tận dụng AI một cách hiệu quả và an toàn trong môi trường doanh nghiệp.&lt;/p&gt;
&lt;p&gt;Tác giả định nghĩa ba chế độ làm việc với AI: Playground Mode cho thử nghiệm ít rủi ro, Pair Programming Mode để cộng tác có cấu trúc, và Production/Monorepo Scale cho tích hợp được kiểm soát cẩn thận. Các thực hành quan trọng bao gồm tạo file &lt;code&gt;CLAUDE.md&lt;/code&gt; như hướng dẫn toàn diện cho AI, sử dụng &amp;ldquo;anchor comments&amp;rdquo; để cung cấp ngữ cảnh và ngăn chặn lỗi AI, đồng thời quy định rằng con người phải luôn viết test.&lt;/p&gt;
&lt;p&gt;Nguyên tắc cốt lõi là &amp;ldquo;Con người đưa ra hướng, AI cung cấp đòn bẩy&amp;rdquo; - AI là công cụ để tăng cường khả năng con người chứ không phải thay thế chuyên môn. Tác giả nhấn mạnh việc cung cấp prompt phong phú có ngữ cảnh, sử dụng phiên Claude mới cho từng tác vụ riêng biệt, và gắn tag commit được hỗ trợ bởi AI để minh bạch.&lt;/p&gt;
&lt;p&gt;Điều tuyệt đối cấm là AI không được chạm vào: file test, di chuyển cơ sở dữ liệu, mã quan trọng về bảo mật, hợp đồng API, và cấu hình cùng secrets. Về mặt văn hóa, Diwank khuyến nghị chuẩn hóa việc tiết lộ sự hỗ trợ của AI, tạo quy trình onboarding dạy sử dụng AI có trách nhiệm, đo lường và theo dõi cải thiện năng suất, đồng thời tập trung duy trì tiêu chuẩn kỹ thuật cao. Mục tiêu cuối cùng là khuếch đại khả năng con người thông qua sự cộng tác AI cẩn thận và có chủ đích.&lt;/p&gt;
&lt;h2 id="why-generative-ai-coding-tools-and-agents-do-not-work-for-me"&gt;&lt;a class="link" href="https://blog.miguelgrinberg.com/post/why-generative-ai-coding-tools-and-agents-do-not-work-for-me" target="_blank" rel="noopener"
&gt;Why Generative AI Coding Tools and Agents Do Not Work For Me&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Miguel Grinberg, tác giả của Flask-SocketIO và nhiều thư viện Python nổi tiếng, chia sẻ quan điểm phản biện về các công cụ AI tạo mã, lập luận rằng chúng không thực sự cải thiện năng suất và có thể gây ra rủi ro trong phát triển phần mềm.&lt;/p&gt;
&lt;p&gt;Tác giả bác bỏ tuyên bố rằng AI làm cho việc lập trình nhanh hơn, cho rằng việc xem xét mã do AI tạo ra mất nhiều thời gian (thậm chí nhiều hơn) so với việc viết mã từ đầu. Ông nhấn mạnh rằng &amp;ldquo;đánh giá mã thực sự khó hơn hầu hết mọi người nghĩ&amp;rdquo; và khẳng định trách nhiệm cá nhân đối với mã, bất kể nguồn gốc của nó. Grinberg từ chối sử dụng mã mà không hiểu kỹ và có thể chỉnh sửa được, coi việc chấp nhận mù quáng mã AI là &amp;ldquo;cực kỳ vô trách nhiệm&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Về mặt học tập, tác giả tận hưởng việc học công nghệ và ngôn ngữ lập trình mới một cách cá nhân, bác bỏ quan niệm rằng AI có thể thay thế hiệu quả quá trình học tập. Ông chỉ trích việc so sánh AI với &amp;ldquo;thực tập sinh&amp;rdquo;, lưu ý rằng thực tập sinh thực sự học hỏi và cải thiện, trong khi các công cụ AI &amp;ldquo;reset về điểm xuất phát&amp;rdquo; cho mỗi tác vụ mới, thiếu khả năng tích lũy kiến thức thực sự.&lt;/p&gt;
&lt;p&gt;Từ góc độ cộng tác, Grinberg đánh giá cao sự hợp tác con người trong các dự án mã nguồn mở, trân trọng những tương tác tạo ra ý tưởng mới chứ không chỉ đơn thuần là tạo mã. Luận điểm cốt lõi của ông là các công cụ AI tạo mã hiện tại không cung cấp cải thiện năng suất có ý nghĩa và có thể gây rủi ro bằng cách tạo ra mã cần được xem xét thủ công kỹ lưỡng.&lt;/p&gt;
&lt;h2 id="ai-coding-assistants-aren"&gt;&lt;a class="link" href="https://leaddev.com/velocity/ai-coding-assistants-arent-really-making-devs-feel-more-productive" target="_blank" rel="noopener"
&gt;AI coding assistants aren&amp;rsquo;t really making devs feel more productive&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Chantal Kapani từ LeadDev đưa ra nghiên cứu thực tế thách thức những tuyên bố phổ biến về tác động tích cực của AI lên năng suất lập trình viên, tiết lộ rằng chỉ có 6% lãnh đạo kỹ thuật quan sát thấy sự cải thiện năng suất đáng kể từ các trợ lý AI lập trình.&lt;/p&gt;
&lt;p&gt;Mặc dù các tiêu đề báo chí liên tục khẳng định AI cải thiện năng suất lập trình viên, nghiên cứu này cho thấy tác động thực tế của các trợ lý AI lập trình lên quy trình làm việc của nhà phát triển ít đáng kể hơn nhiều so với những tuyên bố thông thường. Điều này đặt ra câu hỏi quan trọng về khoảng cách giữa kỳ vọng và thực tế trong việc áp dụng công nghệ AI vào phát triển phần mềm.&lt;/p&gt;
&lt;p&gt;Bài viết thách thức tuyên truyền phổ biến về tác động biến đổi của AI đối với quy trình phát triển phần mềm, gợi ý rằng có thể cần phải đánh giá lại cách chúng ta đo lường và hiểu về lợi ích thực sự của các công cụ AI trong môi trường làm việc thực tế. Đây là góc nhìn quan trọng để cân bằng giữa sự hứng thú về công nghệ mới và đánh giá thực tế về hiệu quả của nó trong thực tiễn.&lt;/p&gt;
&lt;h2 id="how-to-vibe-code-as-a-senior-engineer"&gt;&lt;a class="link" href="https://blog.alexmaccaw.com/how-to-vibe-code-as-a-senior-engineer" target="_blank" rel="noopener"
&gt;How to Vibe Code as a Senior Engineer&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Alex MacCaw giới thiệu khái niệm &amp;ldquo;Vibe Coding&amp;rdquo; - một phương pháp phát triển phần mềm mới sử dụng các mô hình AI để thực hiện phần lớn công việc lập trình, với kỹ sư senior đóng vai trò hướng dẫn thông qua prompt rõ ràng và giám sát kiến trúc.&lt;/p&gt;
&lt;p&gt;Phương pháp này có thể giảm đáng kể thời gian phát triển, từ việc hoàn thành một tính năng trong một giờ đến xây dựng toàn bộ ứng dụng SaaS trong 10 ngày. Các yêu cầu thiết yếu bao gồm sử dụng scaffold dự án mạnh mẽ với quy ước rõ ràng, thiết lập quy tắc lập trình nghiêm ngặt, cung cấp ngữ cảnh toàn diện cho các mô hình AI, sử dụng các mô hình AI hàng đầu như Claude Opus 4 hoặc Gemini 2.5 Pro, và tận dụng trình soạn thảo mã thông minh như Cursor.&lt;/p&gt;
&lt;p&gt;MacCaw nhấn mạnh các chiến lược prompting hiệu quả: luôn bắt đầu với kế hoạch chi tiết, cực kỳ cụ thể về đầu ra mong muốn, cung cấp ngữ cảnh và ví dụ, sử dụng ràng buộc rõ ràng, duy trì phạm vi dự án chặt chẽ, và sử dụng prompt dài và mô tả hơn. Tác giả cũng thừa nhận những hạn chế của AI: quản lý ngữ cảnh tự động kém, xử lý yếu các kiểu TypeScript, thiếu khiếu thẩm mỹ thiết kế kiến trúc, và cần sự hướng dẫn của con người cho việc lập kế hoạch và thực hiện.&lt;/p&gt;
&lt;p&gt;Những điểm mấu chốt bao gồm thiết lập scaffolding mạnh mẽ và ngữ cảnh type-safe, mã hóa các quy ước dự án, sử dụng các mô hình AI hàng đầu, liên tục lint, typecheck và test. MacCaw coi đây có thể là &amp;ldquo;lần cuối cùng&amp;rdquo; của việc lập trình dưới sự dẫn dắt của con người trước khi AI trở nên hoàn toàn tự chủ.&lt;/p&gt;
&lt;h2 id="sql-noir---interactive-sql-game"&gt;&lt;a class="link" href="https://www.sqlnoir.com/blog/games-to-learn-sql" target="_blank" rel="noopener"
&gt;SQL Noir - Interactive SQL Game&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Hristo Bogoev tạo ra SQL Noir, một trò chơi giáo dục web sáng tạo giúp người dùng học SQL thông qua trải nghiệm thám tử hấp dẫn, biến việc học cơ sở dữ liệu từ định dạng tutorial truyền thống thành trải nghiệm giải quyết vấn đề tương tác và thú vị.&lt;/p&gt;
&lt;p&gt;Trò chơi này có gameplay tương tác nơi người dùng giải quyết tội phạm và bí ẩn bằng cách sử dụng các truy vấn SQL, chạy hoàn toàn trên trình duyệt web và được phân loại là trò chơi giáo dục. SQL Noir tập trung vào việc làm cho việc học SQL trở nên hấp dẫn và thú vị hơn thông qua phương pháp tiếp cận dựa trên câu chuyện.&lt;/p&gt;
&lt;p&gt;Mục tiêu của trò chơi là biến đổi việc học SQL từ định dạng tutorial truyền thống thành trải nghiệm nhập vai, giải quyết vấn đề giúp làm cho các kỹ năng cơ sở dữ liệu dễ tiếp cận và thú vị hơn. Đây là một ví dụ xuất sắc của gamification trong giáo dục công nghệ, cho thấy cách các khái niệm kỹ thuật phức tạp có thể được truyền đạt thông qua trải nghiệm học tập tương tác và giải trí.&lt;/p&gt;</description></item><item><title>Newsletter #40</title><link>https://miti99.com/post/2025/07/30/</link><pubDate>Wed, 30 Jul 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/07/30/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #40.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="a-new-way-to-test-multi-threaded-and-concurrent-java"&gt;&lt;a class="link" href="https://vmlens.com/blog/new-way-to-test-multi-threaded-concurrent-java/" target="_blank" rel="noopener"
&gt;A new way to test multi-threaded and concurrent Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;VMLens giới thiệu một phương pháp kiểm thử mới cho ứng dụng Java đa luồng và xử lý đồng thời, giải quyết những thách thức lâu nay trong việc phát hiện lỗi race condition và các vấn đề tương tác giữa các luồng.&lt;/p&gt;
&lt;p&gt;Vấn đề cốt lõi của việc kiểm thử đa luồng là chỉ có thể kiểm tra một cách sắp xếp luồng tại một thời điểm, và việc lặp lại test nhiều lần cũng không hiệu quả do có quá nhiều khả năng sắp xếp các luồng khác nhau. VMLens chia việc kiểm thử thành hai phần: thực thi tất cả các cách sắp xếp luồng dựa trên các hành động đồng bộ hóa, và phát hiện data race trong những cách sắp xếp đó.&lt;/p&gt;
&lt;p&gt;Công cụ này sử dụng Java agent để chuyển đổi bytecode và theo dõi việc truy cập các trường dữ liệu, ghi lại và phân tích bất đồng bộ các sự kiện truy cập và đồng bộ hóa. Khái niệm data race được định nghĩa là &amp;ldquo;hai luồng truy cập cùng một trường đồng thời mà không có đồng bộ hóa phù hợp&amp;rdquo; - khi không có đồng bộ hóa, không có đảm bảo các luồng sẽ thấy giá trị được ghi gần đây nhất.&lt;/p&gt;
&lt;p&gt;Điểm mạnh của phương pháp này là sử dụng trừu tượng cấp cao, coi các nguyên thủy đồng thời của Java là được triển khai đúng và tập trung vào việc kiểm tra cách mã sử dụng các cơ chế đồng thời, không phải cơ chế nội bộ của chúng. Đây là một bước tiến quan trọng giúp các nhà phát triển Java kiểm tra hiệu quả các ứng dụng đồng thời bằng cách khám phá có hệ thống các tương tác giữa luồng và các race condition tiềm ẩn.&lt;/p&gt;
&lt;h2 id="feature-freeze-for-jdk-25-what-will-the-new-edition-bring"&gt;&lt;a class="link" href="https://www.jvm-weekly.com/p/feature-freeze-for-jdk-25-what-will" target="_blank" rel="noopener"
&gt;Feature Freeze for JDK 25: What Will the New Edition Bring?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;JVM Weekly phân tích các tính năng chính trong JDK 25 sau khi Oracle công bố đóng băng tính năng, hứa hẹn mang đến một phiên bản LTS quan trọng với nhiều cải tiến về hiệu suất và các API ổn định mới.&lt;/p&gt;
&lt;p&gt;JDK 25 đánh dấu sự ổn định của nhiều tính năng quan trọng: Scoped Values giúp truyền ngữ cảnh qua các method call một cách nhẹ và bất biến, Module Import Declarations đơn giản hóa việc import package từ module, Compact Source Files cho phép mã nguồn đơn giản hóa với instance main method, và Flexible Constructor Bodies cho phép các câu lệnh trước khi gọi constructor.&lt;/p&gt;
&lt;p&gt;Về hiệu suất, phiên bản này đem lại Compact Object Headers giảm overhead bộ nhớ bằng cách sử dụng một word cho object header, Generational Shenandoah GC cải thiện chế độ thu gom rác, và các cải tiến AOT đơn giản hóa việc tạo cache AOT cùng method profiling. Tính năng quan sát được tăng cường với JFR CPU-Time Profiling thực nghiệm cho phép lấy mẫu thời gian CPU chính xác và JFR Method Timing &amp;amp; Tracing theo dõi chi tiết các lời gọi method.&lt;/p&gt;
&lt;p&gt;JDK 25 cũng tiếp tục phát triển các tính năng preview và incubating như Primitive Types in Patterns, Vector API (lần ủ thứ 10), Structured Concurrency API, và Stable Values. Quan trọng nhất, đây là phiên bản LTS sẽ được phát hành chính thức vào ngày 16 tháng 9 năm 2025 và nhận được ít nhất 5 năm hỗ trợ Premier từ Oracle, tạo nền tảng ổn định cho các dự án doanh nghiệp lâu dài.&lt;/p&gt;
&lt;h2 id="if-virtual-threads-are-the-solution-what-is-the-problem"&gt;&lt;a class="link" href="https://webtide.com/if-virtual-threads-are-the-solution-what-is-the-problem/" target="_blank" rel="noopener"
&gt;If Virtual Threads are the solution, what is the problem?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Webtide đặt câu hỏi quan trọng về mối quan hệ giữa virtual threads và các vấn đề cụ thể mà chúng được thiết kế để giải quyết, cảnh báo rằng virtual threads không phải là giải pháp vạn năng cho mọi bài toán về khả năng mở rộng.&lt;/p&gt;
&lt;p&gt;Bài viết nhấn mạnh rằng virtual threads hoạt động tốt nhất trong các tình huống cụ thể liên quan đến các tài nguyên có khả năng mở rộng như microservices, mạng từ xa, cơ sở dữ liệu có dung lượng cao, và hệ thống file cục bộ. Tác giả cảnh báo về những rủi ro tiềm ẩn khi sử dụng virtual threads không giới hạn: cạn kiệt tài nguyên, thiếu áp lực ngược (back pressure), và nguy cơ thất bại thảm khốc dưới tải cao điểm.&lt;/p&gt;
&lt;p&gt;Virtual threads thực sự có ích khi ứng dụng bị chặn trên &amp;ldquo;tài nguyên có khả năng mở rộng&amp;rdquo;, khi có các công việc song song nhỏ cần thực thi với độ trễ thấp, hoặc khi thread pool truyền thống trở thành nút thắt cổ chai. Tác giả khuyến nghị sử dụng các server bất đồng bộ như Jetty có thể đọc request bất đồng bộ, chuẩn bị nội dung hiệu quả, phân bổ thread (virtual hoặc platform) một cách chiến lược, và flush response bất đồng bộ.&lt;/p&gt;
&lt;p&gt;Insight cốt lõi là virtual threads giải quyết các thách thức đồng thời trong những tình huống cụ thể, nhưng không phải là giải pháp một-kích-cỡ-phù-hợp-tất-cả cho khả năng mở rộng. Quản lý tài nguyên cẩn thận vẫn là điều quan trọng, và các nhà phát triển cần hiểu rõ các nút thắt cổ chai cụ thể của ứng dụng trước khi áp dụng virtual threads như một chiến lược mở rộng.&lt;/p&gt;
&lt;h2 id="agentic-coding-recommendations"&gt;&lt;a class="link" href="https://lucumr.pocoo.org/2025/6/12/agentic-coding/" target="_blank" rel="noopener"
&gt;Agentic Coding Recommendations&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Armin Ronacher, tác giả của Flask và Ruff, chia sẻ kinh nghiệm thực tế về việc sử dụng AI agent trong lập trình, đưa ra những khuyến nghị cụ thể về cách tận dụng hiệu quả công nghệ này để viết mã tốt hơn và bảo trì được.&lt;/p&gt;
&lt;p&gt;Ronacher hiện tại sử dụng Claude Code với quyền truy cập đầy đủ, ít can thiệp từ IDE, và ưu tiên sự đơn giản cũng như ổn định trong mã và công cụ. Ông khuyến nghị mạnh mẽ việc sử dụng Go cho các dự án backend vì hệ thống context rõ ràng, test caching đơn giản, structural interface, và hệ sinh thái ít thay đổi. Các nguyên tắc lựa chọn công cụ bao gồm: công cụ phải nhanh, cung cấp thông báo lỗi rõ ràng, bảo vệ chống lại việc sử dụng sai, và có khả năng quan sát tốt.&lt;/p&gt;
&lt;p&gt;Về phương pháp phát triển mã, tác giả ủng hộ việc &amp;ldquo;viết thứ đơn giản nhất có thể hoạt động được&amp;rdquo;, ưu tiên function hơn class phức tạp, sử dụng plain SQL, và giữ các kiểm tra quan trọng ở local và có thể nhìn thấy. Ronacher thừa nhận sự tiến hóa nhanh chóng của agentic coding: &amp;ldquo;điều đúng một tháng trước giờ hầu như không còn đúng nữa&amp;rdquo;, nhấn mạnh tính thích ứng và duy trì các nguyên tắc cốt lõi như sự đơn giản, ổn định, và song song hóa thông minh.&lt;/p&gt;
&lt;p&gt;Mục tiêu cuối cùng không chỉ là tận dụng agent để viết mã nhanh hơn, mà là để viết mã tốt hơn, dễ bảo trì hơn, và kiên cố hơn. Đây là góc nhìn thực tế từ một trong những lập trình viên kỳ cựu về cách cân bằng giữa việc sử dụng AI và duy trì chất lượng mã trong thời đại mới.&lt;/p&gt;
&lt;h2 id="ai-changes-everything"&gt;&lt;a class="link" href="https://lucumr.pocoo.org/2025/6/4/changes/" target="_blank" rel="noopener"
&gt;AI Changes Everything&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong một bài viết triết lý sâu sắc, Armin Ronacher phản ánh về tác động của AI đối với ngành phát triển phần mềm, so sánh nó với những bước ngoặt công nghệ lớn trong lịch sử như điện và máy in, đồng thời kêu gọi cộng đồng lập trình viên tiếp cận thay đổi này với tư duy tích cực.&lt;/p&gt;
&lt;p&gt;Ronacher hiện sử dụng Claude Code cho hầu hết công việc phát triển và nhận thấy vai trò của mình đã chuyển từ &amp;ldquo;lập trình viên&amp;rdquo; thành &amp;ldquo;trưởng nhóm kỹ thuật&amp;rdquo; quản lý một &amp;ldquo;thực tập sinh lập trình viên ảo&amp;rdquo;. Ông ước tính năng suất tăng khoảng 30% thời gian trong ngày, nhưng quan trọng hơn là sự thay đổi cơ bản trong cách tiếp cận công việc - từ việc trực tiếp viết mã chuyển sang việc hướng dẫn và cộng tác với AI.&lt;/p&gt;
&lt;p&gt;Tác giả nhấn mạnh rằng AI đại diện cho một sự chuyển đổi công nghệ cơ bản, có thể so sánh với điện hoặc máy in, không chỉ đơn thuần là một công cụ mới. Kỹ năng lập trình vẫn có liên quan, nhưng công cụ để thực hiện những kỹ năng đó đã thay đổi một cách đáng kể. AI cho phép công việc có tính ủy quyền và cộng tác hơn giữa con người và máy móc.&lt;/p&gt;
&lt;p&gt;Ronacher kêu gọi cộng đồng tiếp cận với sự tò mò và lạc quan về thay đổi công nghệ. Ông tin rằng AI sẽ không thay thế lập trình viên mà sẽ &amp;ldquo;tăng cường đáng kể khả năng con người khi được sử dụng đúng cách&amp;rdquo;. Mặc dù công nghệ vẫn &amp;ldquo;lộn xộn và thô&amp;rdquo;, nhưng nó đại diện cho một sự chuyển đổi không thể đảo ngược. Thông điệp cốt lõi là: &amp;ldquo;Chúng ta không còn chỉ sử dụng máy móc, giờ đây chúng ta đang làm việc cùng với chúng.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="how-i-program-with-agents"&gt;&lt;a class="link" href="https://crawshaw.io/blog/programming-with-agents" target="_blank" rel="noopener"
&gt;How I program with Agents&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;David Crawshaw chia sẻ kinh nghiệm thực tế về việc sử dụng AI agent trong lập trình, đưa ra định nghĩa đơn giản nhưng sâu sắc và phân tích chi tiết về khả năng cũng như giới hạn của công nghệ này trong môi trường phát triển thực tế.&lt;/p&gt;
&lt;p&gt;Crawshaw định nghĩa agent một cách ngắn gọn: &amp;ldquo;về cơ bản là một vòng lặp for chứa lời gọi LLM&amp;rdquo;, cho phép AI thực thi lệnh và xem kết quả mà không cần can thiệp của con người. Khả năng cốt lõi bao gồm điều hướng codebase bằng bash tools, đọc tài liệu, tìm kiếm API, chạy compiler và test để nhận phản hồi từ môi trường, giúp giảm lỗi cú pháp và cải thiện việc sử dụng API.&lt;/p&gt;
&lt;p&gt;Lợi ích thực tế rõ ràng nhất là tăng tốc phát triển các tác vụ lập trình &amp;ldquo;nhàm chán&amp;rdquo;, cho phép làm việc song song trên nhiều tác vụ phát triển, và giảm công việc thủ công trong tích hợp API cũng như bảo trì mã. Tác giả chia sẻ rằng agent có thể giúp hoàn thành trong một ngày những tác vụ tẻ nhạt mà truyền thống sẽ mất cả tuần để hoàn thành.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, Crawshaw cũng thẳng thắn về những hạn chế hiện tại: agent có thể chậm (mất vài phút cho mỗi tác vụ), yêu cầu giám sát cẩn thận để tránh các hành động ngoài ý muốn, và chưa thể thay thế hoàn toàn lập trình viên con người. Về tiềm năng tương lai, ông lạc quan rằng các mô hình ngày càng được tối ưu hóa cho tương tác agent, môi trường phát triển được container hóa có thể cải thiện triển khai agent, và có khả năng biến đổi quy trình review mã và phát triển.&lt;/p&gt;
&lt;h2 id="performance-best-practise-no-1-optimize-database-operations"&gt;&lt;a class="link" href="https://foojay.io/today/performance-best-practise-no-1-optimize-database-operations/" target="_blank" rel="noopener"
&gt;Performance Best Practise No. 1: Optimize Database Operations&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Foojay đưa ra hướng dẫn chi tiết về tối ưu hóa thao tác cơ sở dữ liệu - yếu tố quan trọng nhất ảnh hưởng đến hiệu suất ứng dụng Java, với những kỹ thuật thực tế và ví dụ mã cụ thể giúp cải thiện đáng kể tốc độ xử lý.&lt;/p&gt;
&lt;p&gt;Bài viết nhấn mạnh rằng việc thiết lập kết nối là thao tác cơ sở dữ liệu tốn kém nhất, do đó connection pooling trở thành kỹ thuật tối ưu hóa cơ bản mà các lập trình viên Java đã sử dụng từ lâu. Cấu hình connection pool bao gồm điều chỉnh kích thước pool phù hợp với tải công việc, đảm bảo thread pool max size lớn hơn connection pool max size, và cấu hình connection idle timeout hợp lý.&lt;/p&gt;
&lt;p&gt;Về tối ưu hóa câu lệnh, tác giả khuyến nghị sử dụng Prepared Statement, triển khai statement caching, và tái sử dụng query để tránh phân tích SQL lặp lại. JDBC batching được giới thiệu như một kỹ thuật mạnh mẽ để nhóm nhiều câu lệnh SQL thành một request duy nhất, giảm overhead của từng kết nối cơ sở dữ liệu riêng lẻ. Đối với JPA, việc kích hoạt batching thông qua các extension của JPA provider như EclipseLink, cấu hình batch writing size và method phù hợp có thể áp dụng có chọn lọc cho các query cụ thể.&lt;/p&gt;
&lt;p&gt;Những khuyến nghị quan trọng bao gồm giám sát việc sử dụng kết nối cơ sở dữ liệu, theo dõi thời gian thực thi query, liên tục kiểm tra và tối ưu hóa cấu hình, đồng thời xem xét các hạn chế cụ thể của từng cơ sở dữ liệu. Bài viết cung cấp nền tảng vững chắc cho các nhà phát triển Java muốn cải thiện hiệu suất tương tác cơ sở dữ liệu.&lt;/p&gt;
&lt;h2 id="agent-rules---a-collection-of-rules-and-knowledge-for-ai-coding-assistants"&gt;&lt;a class="link" href="https://github.com/steipete/agent-rules" target="_blank" rel="noopener"
&gt;Agent Rules - A collection of rules and knowledge for AI coding assistants&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Peter Steinberger (CEO của PSPDFKit) đã tạo ra một kho tài nguyên toàn diện về quy tắc và kiến thức cho các trợ lý AI lập trình, cung cấp một định dạng chuẩn hóa và có thể tái sử dụng cho việc cấu hình AI agent trên nhiều công cụ khác nhau.&lt;/p&gt;
&lt;p&gt;Repository sử dụng định dạng &lt;code&gt;.mdc&lt;/code&gt; (Markdown with Configuration) độc đáo hoạt động tương thích với cả Claude Code và Cursor, tạo ra một phương pháp thống nhất để quản lý hướng dẫn AI. Cấu trúc chính bao gồm Project Rules với các hướng dẫn hành động về quy trình phát triển, kiểm tra chất lượng mã, kỹ thuật giải quyết vấn đề, tạo tài liệu và chiến lược tự động hóa; Documentation với tài liệu tham khảo đặc biệt cho Swift development và MCP server best practices; và Global Rules với các script cấu hình cross-project để nâng cao khả năng của AI assistant.&lt;/p&gt;
&lt;p&gt;Đặc điểm nổi bật là các quy tắc được thiết kế để có thể tái sử dụng giữa các dự án, rõ ràng và có thể thực hiện được, đồng thời tương thích với cả Cursor và Claude Code. Hướng dẫn sử dụng đơn giản: với Cursor, copy file &lt;code&gt;.mdc&lt;/code&gt; vào &lt;code&gt;.cursor/rules/&lt;/code&gt;, với Claude Code thì import quy tắc vào &lt;code&gt;CLAUDE.md&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Triết lý cốt lõi được thể hiện qua việc &amp;ldquo;định dạng thống nhất có nghĩa là bạn có thể sử dụng cùng file quy tắc trong cả hai công cụ mà không cần sửa đổi&amp;rdquo;. Repository hướng tới việc tạo ra một phương pháp chuẩn hóa và cộng tác trong việc làm việc với AI coding assistant, giúp cộng đồng chia sẻ và cải thiện các best practice một cách có hệ thống.&lt;/p&gt;</description></item><item><title>Newsletter #39</title><link>https://miti99.com/post/2025/07/29/</link><pubDate>Tue, 29 Jul 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/07/29/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #39.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="100-senior-java-developer-interview-questions-and-answers--2025-edition"&gt;&lt;a class="link" href="https://dev.to/haraf/100-senior-java-developer-interview-questions-and-answers-2025-edition-4f6n" target="_blank" rel="noopener"
&gt;100+ Senior Java Developer Interview Questions and Answers – 2025 Edition&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một tài liệu tham khảo toàn diện dành cho các lập trình viên Java senior đang chuẩn bị cho phỏng vấn, với hơn 100 câu hỏi được tổ chức thành 5 chủ đề chính kèm theo câu trả lời chi tiết.&lt;/p&gt;
&lt;p&gt;Bộ sưu tập này được chia thành các phần rõ ràng: Core Java với 25 câu hỏi về đa luồng, collections và nguyên lý OOP; Spring Boot &amp;amp; Microservices với 25 câu hỏi về cấu trúc nội bộ Spring Boot, tích hợp microservices và bảo mật; Design Patterns với 20 câu hỏi về việc triển khai các mẫu thiết kế quan trọng; Algorithms &amp;amp; Data Structures với 15 câu hỏi về khái niệm thuật toán cơ bản; và cuối cùng là SQL &amp;amp; Database với 15 câu hỏi về thiết kế cơ sở dữ liệu và tối ưu hóa.&lt;/p&gt;
&lt;p&gt;Điểm nổi bật của tài liệu này là tập trung vào kiến thức thực tế vượt ra ngoài việc viết mã cơ bản. Các câu hỏi được thiết kế để đánh giá hiểu biết sâu sắc về hệ sinh thái Java và phát triển ứng dụng doanh nghiệp. Ví dụ, thay vì chỉ hỏi về cú pháp Java, các câu hỏi sẽ đi sâu vào quản lý bộ nhớ, xử lý đồng thời, và các tình huống thực tế mà senior developer phải đối mặt hàng ngày.&lt;/p&gt;
&lt;p&gt;Tác giả cung cấp không chỉ câu trả lời mà còn giải thích ngữ cảnh thực tế cho từng chủ đề, giúp ứng viên hiểu được tại sao những kiến thức này lại quan trọng trong công việc. Đây là tài nguyên quý giá cho bất kỳ Java developer nào muốn nâng cao kỹ năng phỏng vấn và củng cố kiến thức chuyên môn của mình.&lt;/p&gt;
&lt;h2 id="the-prompt-engineering-playbook-for-programmers"&gt;&lt;a class="link" href="https://addyo.substack.com/p/the-prompt-engineering-playbook-for" target="_blank" rel="noopener"
&gt;The Prompt Engineering Playbook for Programmers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Addy Osmani từ Google chia sẻ hướng dẫn thực tế về kỹ thuật prompt engineering dành riêng cho lập trình viên, giúp tối ưu hóa việc tương tác với AI để có được kết quả chính xác và hữu ích nhất trong công việc phát triển phần mềm.&lt;/p&gt;
&lt;p&gt;Nguyên tắc đầu tiên là cung cấp ngữ cảnh phong phú - thay vì hỏi mơ hồ &amp;ldquo;sửa đoạn mã này&amp;rdquo;, hãy nêu rõ ngôn ngữ lập trình, framework đang sử dụng, và mục tiêu cụ thể. Osmani nhấn mạnh: &amp;ldquo;Tính cụ thể và ngữ cảnh tạo ra sự khác biệt giữa những gợi ý mơ hồ và các giải pháp chính xác, có thể thực hiện được.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Bài viết cũng khuyến khích việc chia nhỏ các tác vụ phức tạp thành những prompt có thể quản lý được, thay vì yêu cầu mọi thứ trong một lần. Kỹ thuật &amp;ldquo;few-shot prompting&amp;rdquo; được đề xuất - cung cấp các ví dụ input/output mong muốn để AI hiểu rõ pattern cần thiết. Việc sử dụng vai trò cụ thể như &amp;ldquo;Hãy đóng vai một senior React developer và review mã của tôi&amp;rdquo; cũng giúp AI định hướng phản hồi phù hợp hơn.&lt;/p&gt;
&lt;p&gt;Điểm quan trọng nhất là coi prompt engineering như một quá trình tương tác - bắt đầu với hướng dẫn cấp cao, sau đó dần dần điều chỉnh và chi tiết hóa dựa trên phản hồi của AI. Thay vì mong đợi kết quả hoàn hảo từ lần đầu, hãy coi việc này như một cuộc hội thoại để từng bước đạt được mục tiêu mong muốn.&lt;/p&gt;
&lt;h2 id="why-your-ai-coding-assistant-keeps-doing-it-wrong-and-how-to-fix-it"&gt;&lt;a class="link" href="https://blog.thepete.net/blog/2025/05/22/why-your-ai-coding-assistant-keeps-doing-it-wrong-and-how-to-fix-it/" target="_blank" rel="noopener"
&gt;Why Your AI Coding Assistant Keeps Doing It Wrong, and How To Fix It&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Pete Hodgson, một chuyên gia tư vấn phần mềm, phân tích sâu sắc về lý do tại sao các trợ lý AI lập trình thường cho ra kết quả không như mong đợi và đưa ra những giải pháp thực tế để cải thiện hiệu quả sử dụng chúng.&lt;/p&gt;
&lt;p&gt;Vấn đề cốt lõi nằm ở việc AI thiếu khả năng ra quyết định thiết kế tốt và không hiểu được ngữ cảnh cụ thể của dự án. AI thường tập trung vào giải quyết vấn đề trước mắt mà không xem xét các tác động rộng hơn, đồng thời không nắm được các quy ước của team hoặc kiến trúc hiện tại của codebase. Hodgson chỉ ra rằng AI có xu hướng &amp;ldquo;quá háo hức làm hài lòng&amp;rdquo; - đưa ra giải pháp ngay lập tức thay vì đặt câu hỏi về tính tối ưu của phương pháp.&lt;/p&gt;
&lt;p&gt;Tác giả đề xuất khung phân tích &amp;ldquo;Constraint-Context Matrix&amp;rdquo; để đánh giá các tác vụ lập trình theo hai chiều: không gian giải pháp (mở vs hạn chế) và yêu cầu ngữ cảnh (ngầm định vs rõ ràng). Thay vì hỏi mơ hồ &amp;ldquo;triển khai tính năng X&amp;rdquo;, hãy chỉ định cụ thể &amp;ldquo;triển khai tính năng X bằng pattern Y với ràng buộc Z&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Giải pháp quan trọng nhất là cung cấp nhiều ngữ cảnh hơn - bao gồm thông tin nền, pattern hiện có, và các ràng buộc kỹ thuật trong prompt. Hodgson nhấn mạnh: &amp;ldquo;Đừng nghĩ LLM là hộp phép thuật có thể giải quyết mọi vấn đề lập trình, mà hãy suy nghĩ cách đóng khung vấn đề để phát huy thế mạnh của AI.&amp;rdquo; Điều này có nghĩa là sử dụng AI như một công cụ bổ trợ cho khả năng phán đoán của con người, không phải thay thế.&lt;/p&gt;
&lt;h2 id="why-ai-agents-need-a-new-protocol"&gt;&lt;a class="link" href="https://glama.ai/blog/2025-06-06-mcp-vs-api" target="_blank" rel="noopener"
&gt;Why AI Agents Need a New Protocol&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Glama.ai giải thích tại sao Model Context Protocol (MCP) lại cần thiết và khác biệt gì so với API truyền thống, đặc biệt trong bối cảnh phát triển các AI agent hiện đại.&lt;/p&gt;
&lt;p&gt;Sự khác biệt cốt lõi nằm ở mục đích thiết kế: API được tạo ra để phục vụ lập trình viên con người viết mã, trong khi MCP được thiết kế đặc biệt cho AI agent ra quyết định. Với API truyền thống, dữ liệu có thể được phân tán trong path, headers, query params và body, khiến AI khó xử lý chính xác. Ngược lại, MCP sử dụng cấu trúc &amp;ldquo;đầu vào/đầu ra JSON đơn lẻ cho mỗi công cụ&amp;rdquo;, giúp AI agent hoạt động đáng tin cậy hơn.&lt;/p&gt;
&lt;p&gt;Điểm nổi bật khác là khả năng khám phá (discovery): API cần tài liệu tĩnh và phải tái tạo SDK khi có thay đổi, còn MCP hỗ trợ &amp;ldquo;runtime introspection&amp;rdquo; cho phép truy vấn khả năng một cách động. Về mặt thực thi, thay vì LLM phải tạo ra các HTTP request dễ lỗi, MCP cho phép &amp;ldquo;LLM chọn công cụ, mã nguồn xác định chạy&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Một ưu điểm quan trọng khác là MCP hỗ trợ tương tác hai chiều như một tính năng cơ bản, thay vì chỉ giao tiếp do client khởi tạo như API truyền thống. Tác giả nhấn mạnh: &amp;ldquo;HTTP API tiến hóa để phục vụ lập trình viên con người và ứng dụng dựa trên trình duyệt, không phải AI agent.&amp;rdquo; MCP không thay thế API mà tạo ra một lớp tối ưu hóa cho AI, có thể &amp;ldquo;bao bọc các API hiện có&amp;rdquo; để chúng thân thiện hơn với AI agent.&lt;/p&gt;
&lt;h2 id="understanding-logical-replication-in-postgres"&gt;&lt;a class="link" href="https://www.springtail.io/blog/postgres-logical-replication" target="_blank" rel="noopener"
&gt;Understanding logical replication in Postgres&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Garth Goodson, CTO của Springtail, cung cấp hướng dẫn chi tiết về logical replication trong PostgreSQL - một kỹ thuật sao chép cơ sở dữ liệu mạnh mẽ cho việc đồng bộ dữ liệu và tích hợp hệ thống.&lt;/p&gt;
&lt;p&gt;Logical replication khác với physical replication ở chỗ nó sao chép &amp;ldquo;biểu diễn logic của các thay đổi&amp;rdquo; thay vì sao chép các khối dữ liệu vật lý. Cơ chế hoạt động dựa trên Write-Ahead Logging (WAL) để theo dõi và truyền các thay đổi cơ sở dữ liệu thông qua các bản ghi có Log Sequence Numbers (LSN) duy nhất. Hệ thống sử dụng &amp;ldquo;publications&amp;rdquo; trên cơ sở dữ liệu nguồn và &amp;ldquo;subscriptions&amp;rdquo; trên cơ sở dữ liệu đích, cùng với replication slots để theo dõi việc truyền và xác nhận các thay đổi.&lt;/p&gt;
&lt;p&gt;Ưu điểm chính bao gồm khả năng tương thích giữa các phiên bản cơ sở dữ liệu khác nhau, tính linh hoạt trong việc sao chép các bảng/cơ sở dữ liệu cụ thể, và khả năng tích hợp với các hệ thống bên ngoài. Điều này làm cho logical replication trở thành giải pháp lý tưởng cho high availability, tối ưu hiệu suất, disaster recovery, và phân tích dữ liệu mà không ảnh hưởng đến cơ sở dữ liệu chính.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, cần lưu ý một số hạn chế quan trọng: logical replication không tự động sao chép các thao tác DDL (thay đổi cấu trúc), cần quản lý cẩn thận không gian WAL và độ trễ sao chép, và yêu cầu các bảng phải có primary key hoặc được cấu hình là REPLICA IDENTITY FULL. Mặc dù có những ràng buộc này, logical replication vẫn mang lại sự linh hoạt đáng kể cho việc đồng bộ và tích hợp cơ sở dữ liệu.&lt;/p&gt;
&lt;h2 id="one-man-armies"&gt;&lt;a class="link" href="https://quarter--mile.com/One-Man-Armies" target="_blank" rel="noopener"
&gt;One Man Armies&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một bài viết truyền cảm hứng từ Quarter Mile về sức mạnh của các lập trình viên làm việc một mình, chứng minh rằng những dự án tưởng chừng không thể thực hiện được mà không có team và ngân sách triệu đô có thể được xây dựng bởi một người có đam mê và nỗ lực đủ lớn.&lt;/p&gt;
&lt;p&gt;Bài viết đưa ra nhiều ví dụ thuyết phục về các &amp;ldquo;đội quân một người&amp;rdquo; thành công trong lĩnh vực phần mềm: Eric Barone đã phát triển Stardew Valley trong 4,5 năm với 70 giờ/tuần, Markus Persson tạo ra Minecraft trong 2 năm làm việc độc lập, John Resig phát triển jQuery, và Chris Hunt dành 12 năm cho game RPG Kenshi. Không chỉ dừng lại ở phần mềm, tác giả còn nhắc đến những thành tựu vĩ đại khác như Theory of General Relativity của Einstein hay chương trình máy tính đầu tiên của Ada Lovelace.&lt;/p&gt;
&lt;p&gt;Điểm nổi bật của bài viết là thông điệp động viên: nếu những công trình như thuyết tương đối rộng, các nhà thờ lớn, opera dài 29 giờ và các game tỷ đô có thể được tạo ra bởi một người, thì những ý tưởng lớn lao và tưởng chừng phi thực tế của chúng ta có thể không quá tham vọng. Bài viết nhấn mạnh rằng sự khác biệt về năng suất cá nhân có thể rất lớn, và điều quan trọng là phải thực sự quan tâm đến dự án của mình và sẵn sàng đầu tư thời gian, công sức đáng kể.&lt;/p&gt;
&lt;p&gt;Mặc dù làm việc một mình mang lại quyền tự chủ hoàn toàn và cơ hội phát triển kỹ năng toàn diện, nhưng cũng đồng nghĩa với việc phải đối mặt với nhiều thách thức như thiếu hỗ trợ từ đồng nghiệp, phải đảm nhận nhiều vai trò khác nhau, và chịu trách nhiệm hoàn toàn cho thành công hay thất bại của dự án.&lt;/p&gt;
&lt;h2 id="what"&gt;&lt;a class="link" href="https://rdel.substack.com/p/rdel-96-whats-the-relationship-between" target="_blank" rel="noopener"
&gt;What&amp;rsquo;s the relationship between developer seniority and code refactoring?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Lizzie Matusov từ RDEL (Research, Development, Engineering Leadership) phân tích mối quan hệ thú vị giữa mức độ kinh nghiệm của lập trình viên và tần suất thực hiện tái cấu trúc mã, tiết lộ những insight quan trọng về cách các team nên tiếp cận việc bảo trì chất lượng mã nguồn.&lt;/p&gt;
&lt;p&gt;Nghiên cứu cho thấy sự chênh lệch đáng kể trong hoạt động tái cấu trúc giữa các nhóm lập trình viên khác nhau. Top 5% những contributor có kinh nghiệm nhất thực hiện trung bình 11.14 lần tái cấu trúc, so với chỉ 3.57 lần của các lập trình viên khác. Điều thú vị là hầu hết các hoạt động tái cấu trúc được thúc đẩy bởi việc triển khai tính năng mới và sửa lỗi, không chỉ đơn thuần là cải thiện chất lượng mã.&lt;/p&gt;
&lt;p&gt;Những lập trình viên có kinh nghiệm không chỉ thực hiện nhiều tái cấu trúc hơn mà còn áp dụng đa dạng kỹ thuật tái cấu trúc khác nhau, tuy nhiên lại ít ghi chép lại các tác vụ này hơn so với junior developer. Đây là một paradox thú vị cho thấy &amp;ldquo;công việc vô hình&amp;rdquo; thường được thực hiện bởi những người có kinh nghiệm nhất nhưng lại ít được ghi nhận.&lt;/p&gt;
&lt;p&gt;Matusov đưa ra lời khuyên thực tế cho các engineering leader: biến tái cấu trúc thành thực hành của toàn team thay vì chỉ dựa vào senior developer, công nhận &amp;ldquo;công việc vô hình&amp;rdquo; như tái cấu trúc trong đánh giá hiệu suất, khuyến khích documentation ở tất cả cấp độ kinh nghiệm, và sử dụng pair programming cùng review checklist để hỗ trợ việc tái cấu trúc. Kết luận quan trọng là tái cấu trúc chủ yếu được thực hiện bởi senior developer, nhưng team cần tạo ra cấu trúc khuyến khích tất cả mọi người tham gia bảo trì chất lượng mã.&lt;/p&gt;</description></item><item><title>Newsletter #38</title><link>https://miti99.com/post/2025/07/28/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/07/28/</guid><description>&lt;p&gt;&lt;em&gt;Do vẫn chưa xong phần task với Claude Code + Serena MCP trong bài hôm qua, nên nay lại quay lại chuỗi Newsletter nhàm chán với AI nhé!! Mời bạn thưởng thức Newsletter #38 hehe :&amp;gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="9-lessons-from-cursor"&gt;&lt;a class="link" href="https://byteatatime.dev/posts/cursor-prompt-analysis/" target="_blank" rel="noopener"
&gt;9 Lessons From Cursor&amp;rsquo;s System Prompt&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích sâu về hệ thống prompt của Cursor AI, một trợ lý lập trình nổi tiếng, để tiết lộ những kỹ thuật tinh vi giúp AI tương tác hiệu quả và tự nhiên hơn với lập trình viên.&lt;/p&gt;
&lt;p&gt;Tác giả đã khám phá 9 bài học quan trọng từ system prompt của Cursor. Đầu tiên là việc định nghĩa vai trò AI một cách chính xác - thay vì chỉ nói &amp;ldquo;bạn là trợ lý AI&amp;rdquo;, Cursor định nghĩa cụ thể &amp;ldquo;bạn là trợ lý lập trình AI, được cung cấp bởi GPT-4.1&amp;rdquo; để tạo ra ngữ cảnh rõ ràng. Thứ hai là thiết kế prompt có cấu trúc bằng các thẻ XML, giúp tổ chức hướng dẫn phức tạp thành các phần dễ hiểu, giúp AI duy trì ngữ cảnh tốt hơn.&lt;/p&gt;
&lt;p&gt;Một điểm thú vị khác là cách Cursor trao quyền tự chủ cho AI - cho phép AI chủ động giải quyết vấn đề với hướng dẫn &amp;ldquo;tiếp tục làm việc cho đến khi truy vấn của người dùng được giải quyết hoàn toàn&amp;rdquo;. Ngoài ra, việc tích hợp thông tin ngữ cảnh trực tiếp vào prompt (bao gồm kết quả tìm kiếm web, nội dung file, trạng thái IDE) giúp tối đa hóa hiểu biết của AI về tác vụ cần thực hiện.&lt;/p&gt;
&lt;p&gt;Bài viết cũng nhấn mạnh tầm quan trọng của việc quản lý công cụ thông minh - định nghĩa các công cụ với giới hạn và tham số cụ thể, quản lý việc truy xuất dữ liệu theo từng phần có thể quản lý được. Như tác giả đã nói: &amp;ldquo;Ngữ cảnh là vua, nữ hoàng và cả triều đình hoàng gia. Càng cung cấp nhiều thông tin liên quan và cập nhật trực tiếp trong prompt, AI sẽ hoạt động càng tốt.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="my-ai-skeptic-friends-are-all-nuts"&gt;&lt;a class="link" href="https://fly.io/blog/youre-all-nuts/" target="_blank" rel="noopener"
&gt;My AI Skeptic Friends Are All Nuts&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Thomas Ptacek từ Fly.io đã viết một bài bảo vệ mạnh mẽ việc sử dụng AI trong phát triển phần mềm, lập luận rằng những người hoài nghi AI đang bỏ lỡ cuộc cách mạng công nghệ quan trọng nhất trong sự nghiệp của họ.&lt;/p&gt;
&lt;p&gt;Tác giả nhấn mạnh rằng các mô hình ngôn ngữ lớn (LLM) hiện đại đã thay đổi cơ bản cách phát triển phần mềm. Thay vì chỉ copy-paste mã nguồn, các AI agent hiện tại có thể điều hướng codebase, chạy công cụ và kiểm thử, tương tác với Git, và thực hiện các tác vụ phức tạp. Tác giả tuyên bố: &amp;ldquo;Ngay cả khi mọi tiến bộ về LLM dừng lại từ hôm nay, LLM vẫn sẽ là điều quan trọng thứ hai xảy ra trong suốt sự nghiệp của tôi.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Bài viết giải quyết những lo ngại phổ biến như vấn đề &amp;ldquo;ảo giác&amp;rdquo; (hallucination) của AI, cho rằng điều này phần lớn đã được giải quyết với các agent hiện đại có khả năng biên dịch, kiểm tra lỗi và chạy test. Ptacek cũng lập luận rằng việc tạo ra mã &amp;ldquo;tầm thường&amp;rdquo; vẫn có giá trị lớn về mặt năng suất, vì &amp;ldquo;các lập trình viên chuyên nghiệp làm việc để giải quyết các vấn đề thực tế bằng mã nguồn, chúng ta không phải nghệ nhân trong công việc hàng ngày.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Điều quan trọng nhất là tác giả nhấn mạnh rằng lập trình viên vẫn phải chịu trách nhiệm đọc hiểu và đánh giá mã được tạo ra, nhưng AI đang trở thành công cụ hỗ trợ năng suất không thể thiếu.&lt;/p&gt;
&lt;h2 id="claude-4-best-practices"&gt;&lt;a class="link" href="https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/claude-4-best-practices#general-principles" target="_blank" rel="noopener"
&gt;Claude 4 Best Practices&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tài liệu chính thức từ Anthropic về các phương pháp tốt nhất khi làm việc với Claude 4, cung cấp hướng dẫn chi tiết về kỹ thuật prompt engineering để tối ưu hóa hiệu suất và chất lượng đầu ra.&lt;/p&gt;
&lt;p&gt;Các nguyên tắc chung bao gồm việc đưa ra hướng dẫn rõ ràng và cụ thể thay vì mơ hồ - ví dụ thay vì nói &amp;ldquo;Tạo một dashboard phân tích&amp;rdquo;, hãy nói &amp;ldquo;Tạo một dashboard phân tích. Bao gồm càng nhiều tính năng và tương tác liên quan càng tốt.&amp;rdquo; Việc thêm ngữ cảnh để giải thích động lực đằng sau yêu cầu cũng giúp Claude hiểu rõ hơn mục tiêu và đưa ra phản hồi phù hợp hơn.&lt;/p&gt;
&lt;p&gt;Tài liệu cũng nhấn mạnh tầm quan trọng của việc kiểm soát định dạng phản hồi bằng cách nói cho Claude biết nên làm gì thay vì tránh làm gì, sử dụng các thẻ XML để chỉ định định dạng mong muốn. Đối với việc tạo mã và frontend, nên sử dụng ngôn ngữ khuyến khích như &amp;ldquo;Đừng giữ lại. Hãy phát huy hết khả năng&amp;rdquo; và yêu cầu các chi tiết cụ thể như trạng thái hover, tương tác và nguyên tắc thiết kế.&lt;/p&gt;
&lt;p&gt;Một điểm đáng chú ý khác là việc tận dụng khả năng tư duy của Claude thông qua các prompt khuyến khích suy ngẫm và lý luận nhiều bước, cũng như tối ưu hóa việc sử dụng công cụ bằng cách khuyến khích gọi công cụ song song. Tài liệu cũng khuyên không nên quá tập trung vào việc vượt qua test case mà hãy nhấn mạnh việc tạo ra các giải pháp mạnh mẽ và có thể tổng quát hóa.&lt;/p&gt;
&lt;h2 id="stop-over-thinking-ai-subscriptions"&gt;&lt;a class="link" href="https://steipete.me/posts/2025/stop-overthinking-ai-subscriptions" target="_blank" rel="noopener"
&gt;Stop Over-thinking AI Subscriptions&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một bài viết thực tế về việc đánh giá chi phí và lợi ích của các gói đăng ký AI, giúp các lập trình viên và chuyên gia công nghệ đưa ra quyết định sáng suốt về việc đầu tư vào các công cụ AI.&lt;/p&gt;
&lt;p&gt;Tác giả phân tích chi phí-hiệu quả của các gói phổ biến: Claude Max ($200/tháng) cung cấp giá trị tốt nhất với khoảng 900 tin nhắn mỗi 5 giờ, Cursor Pro ($20/tháng) cho 500 yêu cầu AI nhanh với phí bổ sung $0.04/yêu cầu, trong khi OpenAI o3 đắt hơn với $10-40 cho 1 triệu token. Điểm quan trọng là việc tính toán năng suất: một buổi chiều tiết kiệm được tương đương khoảng $200 thời gian tính phí, nghĩa là Claude Max hoàn vốn trong 5 giờ tiết kiệm, còn Cursor chỉ cần 45 phút.&lt;/p&gt;
&lt;p&gt;Xu hướng giá cả cũng rất tích cực khi giá token đã giảm 1000 lần trong hai năm qua do cạnh tranh gay gắt, cho thấy xu hướng tiếp tục giảm giá. Tác giả khuyên nên cân nhắc các chương trình đối tác phát triển để được giảm giá, sử dụng công cụ thay thế như Repo Prompt để tiết kiệm chi phí, và theo dõi chi tiêu AI (tác giả đã tự xây dựng &amp;ldquo;Vibe Meter&amp;rdquo; cho mục đích này).&lt;/p&gt;
&lt;p&gt;Lời khuyên quan trọng nhất là đừng suy nghĩ quá nhiều về chi phí mà hãy tập trung vào thời gian tiết kiệm được. Như tác giả nói: &amp;ldquo;Thời gian là tài nguyên duy nhất không thể nạp lại. Claude Max với $200 hiện là cách rẻ nhất tôi biết để tạo ra thêm giờ làm việc.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="tests-should-not-contain-logic"&gt;&lt;a class="link" href="https://blog.snork.dev/posts/tests-should-not-contain-logic.html" target="_blank" rel="noopener"
&gt;Tests Should Not Contain Logic&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một bài viết quan trọng về nguyên tắc viết test, nhấn mạnh rằng các test case không nên chứa logic phức tạp để tránh biến chính test thành nguồn gây lỗi tiềm ẩn.&lt;/p&gt;
&lt;p&gt;Nguyên tắc cốt lõi là test nên giảm thiểu logic nội bộ, tránh các câu lệnh điều kiện và vòng lặp trong test vì điều này có thể che giấu lỗi trong implementation. Tác giả minh họa bằng ví dụ về test FizzBuzz có vấn đề, nơi logic trong test lặp lại đúng cái lỗi trong code thực tế, khiến test vượt qua dù code sai.&lt;/p&gt;
&lt;p&gt;Thay vào đó, bài viết khuyên dùng parametrized test với các test case rõ ràng và cụ thể. Ví dụ, thay vì viết vòng lặp phức tạp, hãy sử dụng &lt;code&gt;@pytest.mark.parametrize&lt;/code&gt; với các cặp input-output rõ ràng như &lt;code&gt;(1, &amp;quot;1&amp;quot;), (3, &amp;quot;fizz&amp;quot;), (5, &amp;quot;buzz&amp;quot;), (15, &amp;quot;fizzbuzz&amp;quot;)&lt;/code&gt;. Cách tiếp cận này giúp test trở nên dễ hiểu, dễ bảo trì và loại bỏ khả năng logic test sai dẫn đến kết quả không chính xác.&lt;/p&gt;
&lt;p&gt;Điểm mấu chốt là test nên đơn giản, trực tiếp và kiểm tra từng tình huống cụ thể một cách độc lập, thay vì cố gắng tái tạo logic của code trong test. Điều này giúp đảm bảo test thực sự phát hiện được lỗi thay vì vô tình che giấu chúng.&lt;/p&gt;
&lt;h2 id="do-you-really-know-java"&gt;&lt;a class="link" href="https://blog.jetbrains.com/idea/2025/05/do-you-really-know-java/" target="_blank" rel="noopener"
&gt;Do You Really Know Java?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một bài viết thú vị từ JetBrains khám phá những khía cạnh ít được biết đến về Java, từ lịch sử phát triển đến các tính năng hiện đại và khả năng tương lai của ngôn ngữ lập trình này.&lt;/p&gt;
&lt;p&gt;Bài viết nhắc lại những tính năng đột phá của Java từ thời kỳ đầu: WORA (Write Once, Run Anywhere) thông qua JVM, tự động thu gom rác giúp đơn giản hóa quản lý bộ nhớ, hỗ trợ đa luồng tích hợp, và mô hình bảo mật tiên tiến coi code như có thể không đáng tin cậy. Java bắt đầu như dự án &amp;ldquo;Green&amp;rdquo; năm 1991, ban đầu tên &amp;ldquo;Oak&amp;rdquo;, sau đó đổi thành Java có thể lấy cảm hứng từ cà phê đảo Java.&lt;/p&gt;
&lt;p&gt;Về khả năng hiện đại, Java không ngừng phát triển với Vector API cho tính toán hiệu suất cao, các framework AI như LangChain4j và Spring AI, cùng với sự hỗ trợ từ IntelliJ IDEA để tăng năng suất phát triển. Các dự án như Panama, Amber và Valhalla đang mang đến hiệu suất tốt hơn và khả năng biểu đạt ngôn ngữ phong phú hơn.&lt;/p&gt;
&lt;p&gt;Như bài viết nhận xét: &amp;ldquo;Java không đuổi theo xu hướng - nó đang âm thầm trở nên mạnh mẽ hơn ở những điểm quan trọng.&amp;rdquo; Một chi tiết thú vị là linh vật &amp;ldquo;Duke&amp;rdquo; của Java được thiết kế bởi một animator sau này làm việc cho bộ phim Shrek. Java đã tiến hóa từ thiết bị nhúng đến hỗ trợ các hệ thống doanh nghiệp toàn cầu, thể hiện sự thích ứng liên tục và sức sống bền bỉ trong bối cảnh công nghệ không ngừng thay đổi.&lt;/p&gt;
&lt;h2 id="machine-code-isn"&gt;&lt;a class="link" href="https://jimmyhmiller.com/machine-code-isnt-scary" target="_blank" rel="noopener"
&gt;Machine Code Isn&amp;rsquo;t Scary&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một bài viết khuyến khích từ Jimmy Miller về việc làm quen với machine code, phá vỡ rào cản tâm lý khiến nhiều lập trình viên ngại tiếp cận lập trình cấp thấp.&lt;/p&gt;
&lt;p&gt;Tác giả thừa nhận ban đầu anh cũng thấy lập trình cấp thấp và machine code khá đáng sợ, nhưng sau khi tìm hiểu thì nhận ra machine code về cơ bản chỉ xoay quanh ba khái niệm cốt lõi: Instructions (lệnh), Registers (thanh ghi), và Memory (bộ nhớ). Các kiến trúc processor khác nhau như ARM và x86-64 có cách mã hóa machine code riêng biệt, nhưng nguyên lý cơ bản vẫn giống nhau.&lt;/p&gt;
&lt;p&gt;Quan điểm chính của Miller là machine code dễ tiếp cận hơn nhiều so với suy nghĩ của các lập trình viên. Anh so sánh rất thú vị: &amp;ldquo;Machine code không đáng sợ. Nếu bạn có thể đảm bảo JSON tuân thủ JSON schema, thì bạn có thể viết machine code.&amp;rdquo; Điểm mấu chốt là machine code chỉ là các biểu diễn số của các hành động tính toán, mỗi instruction set có phương pháp mã hóa riêng.&lt;/p&gt;
&lt;p&gt;Thông điệp cốt lõi là lập trình cấp thấp không vốn dĩ phức tạp, mà thường bị giải thích kém. Bằng cách chia nhỏ machine code thành các thành phần dễ hiểu, Miller chứng minh rằng các lập trình viên có thể vượt qua nỗi sợ &amp;ldquo;bare metal programming&amp;rdquo; và việc tương tác trực tiếp với chi tiết cấp thấp có thể &amp;ldquo;mở khóa&amp;rdquo; sự hiểu biết, loại bỏ rào cản tinh thần trong việc nắm bắt các quy trình tính toán cơ bản.&lt;/p&gt;
&lt;h2 id="the-art-of-sql-query-optimization"&gt;&lt;a class="link" href="https://jnidzwetzki.github.io/2025/06/03/art-of-query-optimization.html" target="_blank" rel="noopener"
&gt;The Art of SQL Query Optimization&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một hướng dẫn chuyên sâu về nghệ thuật tối ưu hóa truy vấn SQL, giải thích cách hệ quản trị cơ sở dữ liệu tìm ra kế hoạch thực thi hiệu quả nhất cho các truy vấn phức tạp.&lt;/p&gt;
&lt;p&gt;Bài viết bắt đầu bằng việc nhắc nhở rằng SQL là ngôn ngữ khai báo - lập trình viên chỉ cần mô tả muốn gì, còn DBMS sẽ quyết định cách thực hiện. Có nhiều đường dẫn để tính toán kết quả truy vấn, và query optimizer sẽ tìm ra kế hoạch thực thi hiệu quả nhất bằng cách tạo ra các kế hoạch khả thi, đánh giá dựa trên chi phí, và chọn kế hoạch rẻ nhất.&lt;/p&gt;
&lt;p&gt;Một điểm quan trọng mà tác giả nhấn mạnh là các mô hình chi phí không phải lúc nào cũng dự đoán chính xác về số lượng tuple, thời gian thực thi, và hiệu suất truy vấn. Ví dụ, full table scan có thể hiệu quả hơn index scan khi cần truy xuất một phần lớn dữ liệu, và PostgreSQL có thể điều chỉnh động loại join dựa trên điều kiện lọc.&lt;/p&gt;
&lt;p&gt;Các chiến lược tối ưu hóa thực tế bao gồm sử dụng index một cách chiến lược, phân tích hiệu suất thực tế so với ước tính, tận dụng extended statistics để cải thiện kế hoạch truy vấn, và sử dụng các công cụ như Plan Explorer để trực quan hóa việc thực thi truy vấn. Tác giả kết luận rằng &amp;ldquo;extended statistics có thể giúp có được dự đoán tốt hơn&amp;rdquo; về hiệu suất truy vấn và tối ưu hóa mô hình chi phí, nhấn mạnh việc tối ưu hóa truy vấn vừa là kỹ năng kỹ thuật vừa là &amp;ldquo;nghệ thuật&amp;rdquo; đòi hỏi hiểu biết tinh tế về hành vi hệ thống cơ sở dữ liệu.&lt;/p&gt;</description></item><item><title>Setup Claude Code &amp; Serena MCP trên Windows</title><link>https://miti99.com/post/2025/07/27/</link><pubDate>Sun, 27 Jul 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/07/27/</guid><description>&lt;p&gt;&lt;em&gt;Dạo này mình spam Newsletter viết bằng AI cũng khá nhiều, hơi nhàm. Sẵn gần đây mình có nghịch ngợm thử combo Claude Code &amp;amp; Serena khá ổn, nên nay tự viết một bài chia sẻ để đổi gió vậy.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="mở-đầu"&gt;Mở đầu
&lt;/h2&gt;&lt;p&gt;Gần đây mình bỏ tiền mua gói Claude Pro, có bao gồm Claude Code, nghịch ngợm cũng hay, mình sẽ đánh giá cao hơn các agent khác ở chỗ dùng qua cli, không bắt buộc cài đặt ide mới (Mình thì quen dùng ide của Jetbrains hơn VS Code. Và Cursor hay Windsurf khó chịu ở chỗ là không có đồng bộ settings giữa các máy khác nhau. Claude Code thì có thể share project config). Vả lại mấy model Claude chính chủ của Anthropic nên dùng trong Claude Code chắc sẽ optimize tốt hơn nhiều :v&lt;/p&gt;
&lt;p&gt;Trong post này thì mình sẽ hướng dẫn setup Claude Code &amp;amp; Serena cho Windows. Mặc dù &lt;a class="link" href="https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md#:~:text=Added%20support%20for%20native%20Windows" target="_blank" rel="noopener"
&gt;Claude Code đã hỗ trợ Windows&lt;/a&gt;, tuy nhiên gần đây mình thử thì vẫn hay gặp lỗi khi tạo file mới. Mình đoán có lẽ là do &lt;code&gt;/&lt;/code&gt; và &lt;code&gt;\&lt;/code&gt; trong path, nên hiện tại mình vẫn dùng Claude Code thông qua WSL. Ngoài ra thì trong post này mình cũng giới thiệu cách setup Serena cho project java luôn.&lt;/p&gt;
&lt;p&gt;Nào, vào việc thôi!!&lt;/p&gt;
&lt;h2 id="cài-đặt-wsl"&gt;Cài đặt WSL
&lt;/h2&gt;&lt;p&gt;Cái này thì dễ, làm theo hướng dẫn ở đây là được: &lt;a class="link" href="https://learn.microsoft.com/en-us/windows/wsl/install" target="_blank" rel="noopener"
&gt;https://learn.microsoft.com/en-us/windows/wsl/install&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;TLDR: Dùng command sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wsl --install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Chờ lệnh chạy xong, restart, restart xong sẽ cài Ubuntu, làm theo hướng dẫn setup username &amp;amp; password cho distro.&lt;/p&gt;
&lt;h2 id="cài-đặt-claude-code"&gt;Cài đặt Claude Code
&lt;/h2&gt;&lt;h3 id="cài-đặt-nodejs"&gt;Cài đặt NodeJS
&lt;/h3&gt;&lt;p&gt;Mặc dù hiện tại &lt;a class="link" href="https://docs.anthropic.com/en/docs/claude-code/setup#:~:text=Software%3A%20Node.js%2018%2B" target="_blank" rel="noopener"
&gt;Claude Code chỉ yêu cầu NodeJS version 18+&lt;/a&gt; và hiện tại nếu cài WSL thì cũng đã xài Ubuntu 24.04, bản này thì package nodejs mặc định cũng đã là version 18.x, nhưng quan điểm của mình là nên dùng Node JS bản LTS mới nhất (hiện tại là 22.x), biết đâu sau này Claude Code đổi yêu cầu thì mình vẫn còn xài được :v Vì vậy chúng ta sẽ làm theo hướng dẫn ở đây: &lt;a class="link" href="https://nodesource.com/products/distributions" target="_blank" rel="noopener"
&gt;https://nodesource.com/products/distributions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;TLDR:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install -y curl
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install -y nodejs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;node -v
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sau đó cần setup npm global prefix để config cài đặt package vào thư mục con trong home, tránh lỗi permission khi chạy không có quyền root, theo hướng dẫn ở đây: &lt;a class="link" href="https://docs.anthropic.com/en/docs/claude-code/troubleshooting#alternative-solution%3A-create-a-user-writable-npm-prefix-for-global-installs" target="_blank" rel="noopener"
&gt;https://docs.anthropic.com/en/docs/claude-code/troubleshooting#alternative-solution%3A-create-a-user-writable-npm-prefix-for-global-installs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;TLDR:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;~/.&lt;/span&gt;&lt;span class="n"&gt;npm&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;global&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;npm&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;~/.&lt;/span&gt;&lt;span class="n"&gt;npm&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;global&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;export PATH=~/.npm-global/bin:$PATH&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;~/.&lt;/span&gt;&lt;span class="n"&gt;bashrc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;~/.&lt;/span&gt;&lt;span class="n"&gt;bashrc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="cài-đặt-claude-code-1"&gt;Cài đặt Claude Code
&lt;/h3&gt;&lt;p&gt;Làm theo hướng dẫn ở đây: &lt;a class="link" href="https://docs.anthropic.com/en/docs/claude-code/setup" target="_blank" rel="noopener"
&gt;https://docs.anthropic.com/en/docs/claude-code/setup&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;TLDR:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npm install -g @anthropic-ai/claude-code
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sau đó chạy lệnh &lt;code&gt;claude&lt;/code&gt;, đăng nhập với account Claude Pro hoặc Anthropic API_KEY&lt;/p&gt;
&lt;h2 id="cài-đặt-serena"&gt;Cài đặt Serena
&lt;/h2&gt;&lt;h3 id="cài-đặt-uv"&gt;Cài đặt uv
&lt;/h3&gt;&lt;p&gt;Theo hướng dẫn ở đây: &lt;a class="link" href="https://docs.astral.sh/uv/getting-started/installation/" target="_blank" rel="noopener"
&gt;https://docs.astral.sh/uv/getting-started/installation/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;TLDR:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -LsSf https://astral.sh/uv/install.sh | sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="setup-serena-trong-project"&gt;Setup Serena trong project
&lt;/h3&gt;&lt;p&gt;Dùng &lt;code&gt;cd&lt;/code&gt; đến thư mục project và chạy lệnh sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;claude mcp add -s project serena -- uvx --from git+https://github.com/oraios/serena serena-mcp-server --context ide-assistant --project $(pwd)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Vậy là xong, mỗi lần chạy &lt;code&gt;claude&lt;/code&gt; trong project thì Serena MCP sẽ được chạy theo (Nhớ check prompt của Claude khi gọi &lt;code&gt;claude&lt;/code&gt;, vì có thể Claude Code muốn hỏi sẽ chạy những MCPs nào)&lt;/p&gt;
&lt;h2 id="cài-đặt-serena-cho-java-project"&gt;Cài đặt Serena cho java project
&lt;/h2&gt;&lt;p&gt;Bởi vì hiện tại &lt;a class="link" href="https://github.com/oraios/serena?tab=readme-ov-file#claude-code:~:text=There%20may%20be%20issues%20with%20java%20on%20macos%20and%20linux" target="_blank" rel="noopener"
&gt;Serena đang gặp vấn đề với java project khi chạy trong Linux và MacOS&lt;/a&gt;, mình đã thử với 1 project dùng gradle, thì rất hay gặp lỗi permission không chạy được lệnh java, mặc dù lệnh đấy call bình thường trong terminal, không bị lỗi path, chmod hay gì cả. Nên hiện tại sẽ có trick lỏ là chạy serena trong Windows, sau đó chạy Serena MCP client và connect bằng SSE. Sau đây là chi tiết:&lt;/p&gt;
&lt;h3 id="trong-windows"&gt;Trong Windows
&lt;/h3&gt;&lt;h4 id="cài-python"&gt;Cài Python
&lt;/h4&gt;&lt;p&gt;Phần này thì khá đơn giản rồi. Mọi người vào trang chủ tải về và cài đặt nhé: &lt;a class="link" href="https://www.python.org/downloads/" target="_blank" rel="noopener"
&gt;https://www.python.org/downloads/&lt;/a&gt;&lt;/p&gt;
&lt;h4 id="cài-uv"&gt;Cài uv
&lt;/h4&gt;&lt;p&gt;TLDR:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;powershell -ExecutionPolicy ByPass -c &amp;#34;irm https://astral.sh/uv/install.ps1 | iex&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Hoặc:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install uv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="chạy-serena-server"&gt;Chạy Serena Server
&lt;/h4&gt;&lt;p&gt;Vào thư mục project, mở cmd/powershell lên và chạy lệnh sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;uvx --from git+https://github.com/oraios/serena serena-mcp-server --context ide-assistant --project . --transport sse --port 9121
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="trong-wsl"&gt;Trong WSL
&lt;/h3&gt;&lt;h4 id="tìm-ip-host"&gt;Tìm IP host
&lt;/h4&gt;&lt;p&gt;Tìm IP host để access từ WSL theo hướng dẫn sau: &lt;a class="link" href="https://learn.microsoft.com/en-us/windows/wsl/networking" target="_blank" rel="noopener"
&gt;https://learn.microsoft.com/en-us/windows/wsl/networking&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;TLDR:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ip route show | grep -i default | awk &amp;#39;{ print $3}&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Ghi nhớ IP trong output. VD của mình đang là &lt;code&gt;172.21.0.1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Với WSL1 thì IP là 127.0.0.1 luôn.&lt;/p&gt;
&lt;h4 id="setup-serena-mcp-client"&gt;Setup Serena MCP Client
&lt;/h4&gt;&lt;p&gt;Dùng &lt;code&gt;cd&lt;/code&gt; đến thư mục project, chạy lệnh sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;claude mcp add -s project --transport sse serena http://172.21.0.1:9121/sse
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Các bạn thay &lt;code&gt;172.21.0.1&lt;/code&gt; bằng IP trong output ở bước trên nhé.&lt;/p&gt;
&lt;p&gt;Sau đó chạy &lt;code&gt;claude&lt;/code&gt; thì sẽ connect được đến MCP Server đang chạy trên host.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lưu ý&lt;/strong&gt;: Với java project thì Serena setup hơi lâu (có thể lên đến vài phút), nên theo dõi trên dashboard (mặc định là http://127.0.0.1:24282/dashboard/index.html) để xem tiến độ.&lt;/p&gt;
&lt;h2 id="tổng-kết"&gt;Tổng kết
&lt;/h2&gt;&lt;p&gt;Trên đây là hướng dẫn của mình về cách setup Claude Code &amp;amp; Serena MCP trên Windows. Cảm ơn các bạn đã đọc đến đây. Nếu có vấn đề gì hãy comment bên dưới, mình sẽ phản hồi sau nhé. Hẹn gặp các bạn trong các bài tới.&lt;/p&gt;
&lt;p&gt;P/S: Hiện tại mình đang nghịch ngợm Claude Code với một task refactor, nếu làm xong, thấy hiệu quả và siêng năng một chút thì mình sẽ viết bài chia sẻ nhau nhé hehe :v&lt;/p&gt;
&lt;h2 id="update-29072025"&gt;Update 29/07/2025:
&lt;/h2&gt;&lt;p&gt;Với những project lớn, nên chạy &lt;code&gt;index-project&lt;/code&gt; trước khi chạy &lt;code&gt;serena-mcp-server&lt;/code&gt; theo hướng dẫn ở đây: uvx &amp;ndash;from git+https://github.com/oraios/serena index-project&lt;/p&gt;
&lt;p&gt;TLDR:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;uvx --from git+https://github.com/oraios/serena serena project index
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Newsletter #37</title><link>https://miti99.com/post/2025/07/26/</link><pubDate>Sat, 26 Jul 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/07/26/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #37.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="đã-đến-lúc-nên-cho-nix-một-cơ-hội"&gt;&lt;a class="link" href="https://maych.in/blog/its-time-to-give-nix-a-chance/" target="_blank" rel="noopener"
&gt;Đã đến lúc nên cho Nix một cơ hội&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Nix là một trình quản lý gói hàm số (functional package manager) mang đến khả năng tái tạo môi trường phát triển hoàn toàn chính xác. Khác với các trình quản lý gói truyền thống, Nix lưu trữ các gói trong &lt;code&gt;/nix/store&lt;/code&gt; với đường dẫn duy nhất được tạo ra từ mã băm mật mã học, đảm bảo tính bất biến và loại bỏ hoàn toàn xung đột phụ thuộc.&lt;/p&gt;
&lt;p&gt;Điểm mạnh chính của Nix nằm ở khả năng cô lập gói hoàn toàn - nhiều phiên bản phần mềm có thể tồn tại song song mà không ảnh hưởng lẫn nhau. Mỗi gói đều chứa toàn bộ cây phụ thuộc của mình, giúp giải quyết vấn đề &amp;ldquo;hôm qua còn chạy được mà&amp;rdquo;. Về bảo mật, kho lưu trữ bất biến ngăn chặn việc chỉnh sửa tệp nhị phân, sandbox trong quá trình xây dựng gói, và cấu trúc hệ thống tệp không chuẩn làm giảm các vector tấn công truyền thống.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, Nix cũng có những thách thức không nhỏ. Đường cong học tập khá dốc do cần hiểu các khái niệm lập trình hàm phức tạp, việc debug rất khó khăn, và đòi hỏi đầu tư thời gian ban đầu đáng kể. Tác giả khuyến nghị Nix đặc biệt phù hợp với các nhóm có môi trường phát triển phức tạp, phát triển đa nền tảng, dự án yêu cầu tuân thủ nghiêm ngặt, và nghiên cứu thử nghiệm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Môi trường tái tạo tuyệt đối với kho lưu trữ bất biến&lt;/li&gt;
&lt;li&gt;Cô lập gói hoàn toàn, nhiều phiên bản cùng tồn tại&lt;/li&gt;
&lt;li&gt;Bảo mật nâng cao nhờ sandbox và cấu trúc hệ thống tệp độc đáo&lt;/li&gt;
&lt;li&gt;Đường cong học tập dốc nhưng lợi ích dài hạn đáng kể&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bạn-có-thể-chọn-công-cụ-làm-mình-hạnh-phúc"&gt;&lt;a class="link" href="https://borretti.me/article/you-can-choose-tools-that-make-you-happy" target="_blank" rel="noopener"
&gt;Bạn có thể chọn công cụ làm mình hạnh phúc&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Lập trình viên thường ẩn giấu động lực thật sự đằng sau việc chọn công nghệ bằng cách tạo ra những lý do kỹ thuật có vẻ hợp lý. Thực tế, những quyết định này thường xuất phát từ cảm xúc và sở thích cá nhân hơn là từ những cân nhắc thuần túy về mặt kỹ thuật.&lt;/p&gt;
&lt;p&gt;Lập trình viên chọn công nghệ dựa trên cảm giác thoải mái, sự quen thuộc, tính thẩm mỹ, hoặc thậm chí là những kết nối hoài niệm với lịch sử công nghệ. Có thể là do &amp;ldquo;vibe&amp;rdquo; của một công cụ khiến họ cảm thấy phù hợp với bản thân. Điều này hoàn toàn bình thường và có thể chấp nhận được.&lt;/p&gt;
&lt;p&gt;Tác giả khuyến khích các lập trình viên nên thành thật với bản thân về động lực thực sự của mình. Thay vì tạo ra những lý do kỹ thuật giả tạo, hãy thừa nhận rằng việc chọn công cụ có thể đơn giản chỉ vì nó làm bạn hạnh phúc. Cuộc đời ngắn ngủi, hãy sử dụng những công cụ mang lại niềm vui và ý nghĩa trong công việc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thông điệp chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Động lực cảm xúc trong việc chọn công nghệ là điều bình thường&lt;/li&gt;
&lt;li&gt;Hãy thành thật về lý do thực sự khiến bạn chọn một công cụ&lt;/li&gt;
&lt;li&gt;Được phép sử dụng công cụ &amp;ldquo;lạ&amp;rdquo; nếu nó làm bạn hạnh phúc&lt;/li&gt;
&lt;li&gt;Sự hài lòng cá nhân cũng quan trọng như tính thực tiễn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ảo-tưởng-về-copilot"&gt;&lt;a class="link" href="https://deplet.ing/the-copilot-delusion/" target="_blank" rel="noopener"
&gt;Ảo tưởng về Copilot&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này đưa ra những phê phán sâu sắc về các trợ lý lập trình AI như GitHub Copilot và ảnh hưởng tiêu cực của chúng đến ngành phát triển phần mềm. Tác giả lập luận rằng các công cụ AI này tạo ra mã nguồn mà không có sự hiểu biết thực sự về kiến trúc hệ thống hay những phức tạp kỹ thuật sâu xa.&lt;/p&gt;
&lt;p&gt;Vấn đề cốt lõi là việc phụ thuộc vào AI làm suy giảm kỹ năng tư duy phản biện và học hỏi của lập trình viên. Khi &amp;ldquo;gia công tư duy cho AI&amp;rdquo;, chúng ta cũng đang &amp;ldquo;gia công việc học&amp;rdquo; cho chúng. Các công cụ này thiếu trực giác về hiệu năng phần cứng, quản lý bộ nhớ, và tối ưu hóa - những yếu tố then chốt trong phát triển phần mềm chất lượng cao.&lt;/p&gt;
&lt;p&gt;Tác giả lo ngại về tác động văn hóa trong ngành kỹ thuật phần mềm, có thể tạo ra một thế hệ lập trình viên ưu tiên sản lượng nhanh hơn chất lượng, đe dọa &amp;ldquo;linh hồn hacker&amp;rdquo; và sự tò mò kỹ thuật sâu sắc. Nguy cơ là sẽ có nhiều người nghĩ mình giỏi chỉ vì bot của họ vượt qua được CI, nhưng thực tế thiếu hiểu biết căn bản.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mối lo ngại chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI tạo mã mà không hiểu kiến trúc hệ thống&lt;/li&gt;
&lt;li&gt;Suy giảm kỹ năng tư duy phản biện của lập trình viên&lt;/li&gt;
&lt;li&gt;Thiếu hiểu biết về hiệu năng và tối ưu hóa&lt;/li&gt;
&lt;li&gt;Nguy cơ tạo ra thế hệ lập trình viên &amp;ldquo;giỏi trên giấy&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tại-sao-cline-không-lập-chỉ-mục-mã-nguồn-và-đó-là-điều-tốt"&gt;&lt;a class="link" href="https://cline.bot/blog/why-cline-doesnt-index-your-codebase-and-why-thats-a-good-thing" target="_blank" rel="noopener"
&gt;Tại sao Cline không lập chỉ mục mã nguồn (và đó là điều tốt)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Cline, một trợ lý lập trình AI, có cách tiếp cận khác biệt hoàn toàn so với các công cụ khác: không lập chỉ mục (indexing) mã nguồn. Bài viết giải thích lý do tại sao đây lại là một thiết kế thông minh và có lợi cho lập trình viên.&lt;/p&gt;
&lt;p&gt;Vấn đề với việc lập chỉ mục truyền thống là nó &amp;ldquo;xé nát logic của mã nguồn&amp;rdquo;. Tác giả ví việc này như cố gắng hiểu một bản giao hưởng thông qua những đoạn nhạc ngẫu nhiên 10 giây. Mã nguồn có tính kết nối cao, việc chia nhỏ theo ngữ nghĩa rất khó khăn và thường phá vỡ mối liên hệ quan trọng giữa các phần.&lt;/p&gt;
&lt;p&gt;Hơn nữa, các chỉ mục nhanh chóng trở nên lỗi thời. Phát triển phần mềm di chuyển rất nhanh, và chỉ mục trở thành &amp;ldquo;ảnh chụp đóng băng trong thời gian&amp;rdquo;, có thể không phản ánh đúng trạng thái hiện tại của mã nguồn. Điều này cũng tạo ra lỗ hổng bảo mật khi tạo ra &amp;ldquo;biểu diễn thứ cấp của tài sản trí tuệ có giá trị nhất&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Thay vào đó, Cline sử dụng phương pháp &amp;ldquo;khám phá, không truy xuất&amp;rdquo; - đọc mã &amp;ldquo;từng tệp, từng kết nối&amp;rdquo;, theo cấu trúc tự nhiên của mã như một lập trình viên thực thụ. Cách này tận dụng khung ngữ cảnh rộng lớn của các mô hình ngôn ngữ hiện đại để tạo ra &amp;ldquo;ngữ cảnh chất lượng cao&amp;rdquo; thông qua việc khám phá thông minh.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ưu điểm của cách tiếp cận Cline:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không có RAG, embeddings hay cơ sở dữ liệu vector&lt;/li&gt;
&lt;li&gt;Áp dụng trí tuệ trực tiếp lên mã nguồn&lt;/li&gt;
&lt;li&gt;Duy trì hiểu biết ngữ cảnh mà không cần lập chỉ mục bên ngoài&lt;/li&gt;
&lt;li&gt;Theo dõi cấu trúc mã tự nhiên như lập trình viên thực&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="commit-hoàn-hảo"&gt;&lt;a class="link" href="https://simonwillison.net/2022/Oct/29/the-perfect-commit/" target="_blank" rel="noopener"
&gt;Commit hoàn hảo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Simon Willison chia sẻ triết lý về việc tạo ra những commit Git lý tưởng, một kỹ năng quan trọng mà nhiều lập trình viên thường bỏ qua. Một commit hoàn hảo cần bao gồm bốn yếu tố chính: triển khai (implementation), kiểm thử (tests), tài liệu (documentation), và liên kết đến issue.&lt;/p&gt;
&lt;p&gt;Về mặt triển khai, mỗi commit nên tập trung vào một thay đổi duy nhất, giữ lịch sử commit tuyến tính và đảm bảo tính nguyên tử - có thể dễ dàng review và triển khai. Kiểm thử phải được bao gồm để chứng minh rằng code hoạt động đúng, tăng năng suất và sự tự tin trong việc thay đổi mã nguồn.&lt;/p&gt;
&lt;p&gt;Tài liệu cần được cập nhật trong cùng repository với mã nguồn, đảm bảo tính đáng tin cậy, có version, có thể review và kiểm tra được. Cuối cùng, mỗi commit nên có liên kết đến issue thread để cung cấp ngữ cảnh, bao gồm thông tin nền, quá trình ra quyết định, đoạn mã, ảnh chụp màn hình và prototype.&lt;/p&gt;
&lt;p&gt;Willison khuyến nghị rằng thông điệp commit có thể ngắn gọn chỉ một dòng với liên kết issue, vì ngữ cảnh chi tiết tốt hơn nên đặt trong issue thread. Không phải commit nào cũng cần &amp;ldquo;hoàn hảo&amp;rdquo; - với công việc thử nghiệm, có thể sử dụng nhánh với &amp;ldquo;WIP&amp;rdquo; commits rồi squash-merge thành commit sạch và toàn diện.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nguyên tắc cốt lõi:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Một thay đổi tập trung, có kiểm thử và tài liệu&lt;/li&gt;
&lt;li&gt;Liên kết issue để cung cấp ngữ cảnh&lt;/li&gt;
&lt;li&gt;Commit nguyên tử, dễ review và triển khai&lt;/li&gt;
&lt;li&gt;Ưu tiên sự rõ ràng và ngắn gọn trong thông điệp&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="khoảnh-khắc-kanagawa-của-kỹ-thuật-phần-mềm"&gt;&lt;a class="link" href="https://pashabitz.substack.com/p/the-software-engineering-kawagara" target="_blank" rel="noopener"
&gt;Khoảnh khắc Kanagawa của kỹ thuật phần mềm&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tác giả sử dụng hình ảnh bức tranh &amp;ldquo;Sóng lớn ở Kanagawa&amp;rdquo; để miêu tả làn sóng biến đổi mạnh mẽ đang tác động đến ngành kỹ thuật phần mềm. AI và tự động hóa lập trình đang tạo ra một cuộc cách mạng không kém gì cuộc cách mạng cơ giới hóa nông nghiệp trong quá khứ.&lt;/p&gt;
&lt;p&gt;Các trợ lý lập trình AI hiện tại đã có thể chuyển đổi mô tả tác vụ thành mã nguồn hoàn chỉnh kèm kiểm thử và tài liệu. Điều này đặc biệt ảnh hưởng đến vai trò lập trình viên junior, những người thường được giao nhiệm vụ triển khai các chức năng cụ thể theo yêu cầu chi tiết.&lt;/p&gt;
&lt;p&gt;Thay vì chỉ tập trung vào việc viết mã, kỹ sư phần mềm cần chuyển hướng sang hiểu biết về bối cảnh sản phẩm và kinh doanh rộng hơn. Vai trò mới sẽ bao gồm: hiểu nhu cầu kinh doanh, thiết kế sản phẩm, kiến trúc hệ thống, và định nghĩa &amp;ldquo;đường ray&amp;rdquo; cùng ràng buộc cho dự án.&lt;/p&gt;
&lt;p&gt;Tác giả khuyến nghị các kỹ sư nên học cách làm chủ công việc &amp;ldquo;đường ray&amp;rdquo;: thiết lập môi trường, quản lý phụ thuộc, và hiểu cách các công cụ và nền tảng kết nối với nhau. Đây không phải là sự kết thúc của kỹ thuật phần mềm, mà là sự kết thúc của một phiên bản cụ thể của nó.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thông điệp chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vai trò lập trình viên đang chuyển từ viết mã sang hiểu nghiệp vụ&lt;/li&gt;
&lt;li&gt;AI đang thay đổi cơ bản cách thức làm việc, không chỉ là công cụ hỗ trợ&lt;/li&gt;
&lt;li&gt;Cần tập trung vào kiến trúc, thiết kế sản phẩm và quản lý hệ thống&lt;/li&gt;
&lt;li&gt;Học cách thiết lập và quản lý &amp;ldquo;đường ray&amp;rdquo; cho dự án&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="websockets-đảm-bảo-thứ-tự---vậy-tại-sao-tin-nhắn-của-tôi-lại-bị-xáo-trộn"&gt;&lt;a class="link" href="https://www.sitongpeng.com/writing/websockets-guarantee-order-so-why-are-my-messages-scrambled" target="_blank" rel="noopener"
&gt;WebSockets đảm bảo thứ tự - vậy tại sao tin nhắn của tôi lại bị xáo trộn?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một vấn đề thú vị trong lập trình realtime: mặc dù WebSockets sử dụng TCP đảm bảo thứ tự tin nhắn, nhưng tại sao tin nhắn lại có thể xuất hiện không đúng thứ tự? Câu trả lời nằm ở việc xử lý bất đồng bộ trong JavaScript, không phải ở giao thức mạng.&lt;/p&gt;
&lt;p&gt;Nguyên nhân chính là các thao tác bất đồng bộ như &lt;code&gt;await blob.arrayBuffer()&lt;/code&gt; làm tạm dừng việc thực thi message handler. Khi các tin nhắn có thời gian xử lý khác nhau, JavaScript event loop cho phép chúng được xử lý không tuần tự. Điều này tạo ra tình huống tin nhắn đến đúng thứ tự nhưng kết quả xử lý lại bị đảo lộn.&lt;/p&gt;
&lt;p&gt;Tác giả đề xuất hai giải pháp: Thứ nhất là sử dụng message queue với &lt;code&gt;Promise.all()&lt;/code&gt; để xử lý song song nhưng vẫn giữ thứ tự kết quả. Thứ hai là dùng async generator để xử lý từng tin nhắn một cách tuần tự - chậm hơn nhưng đảm bảo thứ tự nghiêm ngặt.&lt;/p&gt;
&lt;p&gt;Bài học quan trọng ở đây là &amp;ldquo;luôn đi sâu thêm một bước&amp;rdquo;. Mặc dù TCP đảm bảo thứ tự, nhưng code ứng dụng vẫn có thể tự phá vỡ thứ tự đó. Đây là một ví dụ điển hình cho thấy hiểu biết sâu về cơ chế hoạt động của từng lớp trong hệ thống là vô cùng quan trọng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vấn đề thứ tự không nằm ở WebSocket/TCP mà ở code xử lý bất đồng bộ&lt;/li&gt;
&lt;li&gt;Sử dụng message queue với Promise.all() để xử lý song song&lt;/li&gt;
&lt;li&gt;Dùng async generator cho xử lý tuần tự nghiêm ngặt&lt;/li&gt;
&lt;li&gt;Hiểu rõ từng lớp trong hệ thống để tránh giả định sai lầm&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tại-sao-các-ai-agent-là-những-đối-tác-lập-trình-đôi-tệ"&gt;&lt;a class="link" href="https://justin.searls.co/posts/why-agents-are-bad-pair-programmers/" target="_blank" rel="noopener"
&gt;Tại sao các AI agent là những đối tác lập trình đôi tệ&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Justin Searls đưa ra một góc nhìn thú vị về việc tại sao các AI agent lại không phù hợp cho pair programming. Vấn đề cốt lõi là các agent &amp;ldquo;viết mã nhanh hơn con người suy nghĩ&amp;rdquo;, tạo ra sự mất cân bằng trong quá trình cộng tác. Tốc độ này ngăn cản việc cộng tác có ý nghĩa và có thể dẫn đến việc xây dựng &amp;ldquo;sản phẩm sai&amp;rdquo; mà không có sự giám sát của con người.&lt;/p&gt;
&lt;p&gt;Pair programming hiệu quả đòi hỏi sự trao đổi, thảo luận và suy ngẫm chung. Khi AI agent hoạt động với tốc độ quá nhanh, nó phá vỡ bản chất cộng tác này, khiến lập trình viên trở thành người quan sát thụ động thay vì đối tác tích cực.&lt;/p&gt;
&lt;p&gt;Tác giả đề xuất một số cách tiếp cận tốt hơn: sử dụng quy trình làm việc bất đồng bộ như GitHub&amp;rsquo;s Coding Agent với review pull request, sử dụng chế độ &amp;ldquo;Edit&amp;rdquo; hoặc &amp;ldquo;Ask&amp;rdquo; thay vì chế độ &amp;ldquo;Agent&amp;rdquo; hoàn toàn tự động. Các cải tiến được đề xuất bao gồm cho phép người dùng kiểm soát tốc độ tạo mã, kích hoạt tạm dừng để làm rõ trong quá trình làm việc, và thiết kế agent với nhiều sự nghi ngờ và ý định cộng tác hơn.&lt;/p&gt;
&lt;p&gt;Mục tiêu không phải là loại bỏ sự hỗ trợ của AI, mà là tạo ra những tương tác cân bằng và cộng tác hơn, tôn trọng quá trình nhận thức và ra quyết định của con người. Voice chat cũng được đề xuất như một cách tương tác tự nhiên hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thông điệp cốt lõi:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI agent viết mã nhanh hơn khả năng suy nghĩ của con người&lt;/li&gt;
&lt;li&gt;Tốc độ quá nhanh phá vỡ bản chất cộng tác của pair programming&lt;/li&gt;
&lt;li&gt;Cần thiết kế tương tác cân bằng, tôn trọng quá trình nhận thức con người&lt;/li&gt;
&lt;li&gt;Quy trình bất đồng bộ và chế độ turn-based hiệu quả hơn&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Newsletter #36</title><link>https://miti99.com/post/2025/07/25/</link><pubDate>Fri, 25 Jul 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/07/25/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #36.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="what-makes-strong-engineers-strong"&gt;&lt;a class="link" href="https://www.seangoedecke.com/what-makes-strong-engineers-strong/" target="_blank" rel="noopener"
&gt;What Makes Strong Engineers Strong&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích những đặc điểm quan trọng khiến một kỹ sư phần mềm trở nên xuất sắc. Tác giả Sean Goedecke đã chỉ ra bốn yếu tố chính, được sắp xếp theo thứ tự quan trọng từ cao đến thấp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tự tin (Self-belief)&lt;/strong&gt; được xếp hạng đầu tiên và quan trọng nhất. Những kỹ sư giỏi tin tưởng vào khả năng giải quyết vấn đề của mình, ngay cả khi đối mặt với những thử thách phức tạp và chưa từng gặp. Họ có tinh thần &amp;ldquo;tôi có thể tìm ra cách giải quyết&amp;rdquo; thay vì tránh né những nhiệm vụ khó khăn. Sự tự tin này tạo ra một vòng lặp tích cực, càng giải quyết được nhiều vấn đề thì càng tự tin hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thực dụng (Pragmatism)&lt;/strong&gt; đứng thứ hai. Kỹ sư mạnh tập trung vào các giải pháp khả thi thay vì theo đuổi sự hoàn hảo về mặt lý thuyết. Họ sẵn sàng thoả hiệp để có thể giao sản phẩm đúng hạn và ưu tiên kết quả thực tế hơn là lý thuyết suông.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tốc độ (Speed)&lt;/strong&gt; là yếu tố thứ ba. Làm việc nhanh và hiệu quả giúp họ có thể thử nghiệm nhiều hơn và tích lũy kinh nghiệm nhanh chóng. Tác giả nhấn mạnh rằng năng suất đến từ những &amp;ldquo;đợt làm việc ngắn nhưng chuyên sâu&amp;rdquo; chứ không phải làm việc nhiều giờ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Khả năng kỹ thuật (Technical Ability)&lt;/strong&gt; được xếp cuối cùng. Điều thú vị là tác giả cho rằng không cần phải là &amp;ldquo;thiên tài&amp;rdquo; mà chỉ cần có kỹ năng phù hợp với công việc cụ thể. Hiệu quả làm việc quan trọng hơn trí thông minh thuần túy.&lt;/p&gt;
&lt;p&gt;Bài viết khuyến khích các lập trình viên trẻ nên tập trung vào việc xây dựng lòng tin vào bản thân và làm việc thực dụng, thay vì chỉ chú trọng vào việc nâng cao kỹ năng kỹ thuật.&lt;/p&gt;
&lt;h2 id="how-do-ai-code-reviews-impact-engineering-teams"&gt;&lt;a class="link" href="https://rdel.substack.com/p/rdel-92-how-do-ai-code-reviews-impact" target="_blank" rel="noopener"
&gt;How do AI Code Reviews Impact Engineering Teams?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Nghiên cứu về tác động của AI trong việc đánh giá mã nguồn đã mang lại những kết quả khá thú vị. Theo dữ liệu thu thập được, 73.8% các nhận xét do AI tạo ra đã được các lập trình viên thực hiện, cho thấy độ hữu ích thực tế của công cụ này.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, nghiên cứu cũng phát hiện ra một số hạn chế đáng chú ý. Thời gian đóng pull request đã tăng từ 5 giờ 52 phút lên 8 giờ 20 phút, cho thấy việc xử lý các gợi ý của AI cần thêm thời gian. Đồng thời, AI không giảm đáng kể số lượng bình luận từ con người trong quá trình đánh giá mã.&lt;/p&gt;
&lt;p&gt;Về chất lượng, 68.8% người tham gia khảo sát nhận thấy có sự cải thiện nhỏ trong chất lượng mã nguồn. AI đặc biệt hiệu quả trong việc phát hiện lỗi, lỗi chính tả và các test case bị thiếu. Tuy nhiên, vẫn có 26.2% gợi ý của AI bị gắn nhãn &amp;ldquo;Won&amp;rsquo;t Fix&amp;rdquo; hoặc &amp;ldquo;Closed&amp;rdquo;, cho thấy không phải tất cả đề xuất đều hữu ích.&lt;/p&gt;
&lt;p&gt;Nghiên cứu khuyến nghị các nhóm phát triển nên đặt ra kỳ vọng rõ ràng về các gợi ý từ AI, theo dõi các chỉ số quy trình làm việc và liên tục cải tiến cách sử dụng công cụ. Hiện tại, AI đánh giá mã vẫn đóng vai trò bổ trợ chứ chưa thể thay thế hoàn toàn việc đánh giá của con người.&lt;/p&gt;
&lt;h2 id="writing-that-changed-how-i-think-about-pl"&gt;&lt;a class="link" href="https://bernsteinbear.com/blog/pl-writing/" target="_blank" rel="noopener"
&gt;Writing that changed how I think about PL&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Max Bernstein đã tổng hợp một danh sách những bài viết có ảnh hưởng sâu sắc đến cách ông hiểu về ngôn ngữ lập trình và trình biên dịch. Đây là những tài liệu đã thay đổi quan điểm của tác giả về nhiều khái niệm kỹ thuật quan trọng.&lt;/p&gt;
&lt;p&gt;Bài viết giới thiệu 16 tài liệu khác nhau bao gồm các bài báo khoa học, blog post và bài thuyết trình về những chủ đề như bộ thu gom rác, kỹ thuật tối ưu hóa trình biên dịch, phương pháp phân tích cú pháp, triển khai machine learning và thiết kế trình thông dịch.&lt;/p&gt;
&lt;p&gt;Một số điểm nổi bật bao gồm bài viết của Andy Wingo về &amp;ldquo;a simple semi-space collector&amp;rdquo; giúp làm rõ các khái niệm về bộ thu gom rác, bài của Russ Cox về &amp;ldquo;Regular Expression Matching&amp;rdquo; đơn giản hóa việc hiểu về regex engine, và bài thuyết trình của Chandler Carruth về thiết kế trình biên dịch Carbon.&lt;/p&gt;
&lt;p&gt;Đặc biệt, tác giả nhấn mạnh sức mạnh của việc viết kỹ thuật rõ ràng và súc tích trong việc truyền đạt những khái niệm phức tạp. Danh sách này không chỉ phản ánh niềm đam mê của tác giả với lý thuyết ngôn ngữ lập trình mà còn cho thấy tầm quan trọng của những tài liệu có thể thay đổi cách nhìn nhận kỹ thuật của chúng ta.&lt;/p&gt;
&lt;h2 id="llms-are-making-me-dumber"&gt;&lt;a class="link" href="https://vvvincent.me/llms-are-making-me-dumber/" target="_blank" rel="noopener"
&gt;LLMs are Making Me Dumber&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Vincent Cheng đã đặt ra một câu hỏi thú vị và gây tranh cãi: liệu các mô hình ngôn ngữ lớn (LLMs) có đang khiến chúng ta trở nên &amp;ldquo;ngu đần&amp;rdquo; hơn không? Tác giả chia sẻ những quan sát cá nhân về cách AI đang ảnh hưởng đến quá trình học tập và phát triển kỹ năng của mình.&lt;/p&gt;
&lt;p&gt;Tác giả chỉ ra những &amp;ldquo;đường tắt&amp;rdquo; trong học tập mà AI mang lại: sử dụng LLMs để hoàn thành các dự án lập trình mà không hiểu sâu về mã nguồn, giải bài tập toán bằng cách để AI tạo ra đáp án, hoặc soạn thảo email mà không luyện tập kỹ năng viết. Những hành vi này có thể dẫn đến việc &amp;ldquo;thoái hóa&amp;rdquo; khả năng giải quyết vấn đề và hy sinh độ sâu của việc học để đổi lấy tốc độ đầu ra.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, Vincent cũng thừa nhận những lợi ích ngắn hạn về năng suất và đưa ra những phép so sánh lịch sử với máy tính bỏ túi, GPS hay cuộc cách mạng công nghiệp. Ông nhận ra sự không chắc chắn về tác động dài hạn và đề xuất một chiến lược cân bằng.&lt;/p&gt;
&lt;p&gt;Giải pháp mà tác giả đưa ra là có ý thức bảo tồn các kỹ năng cốt lõi như tư duy độc lập, ra quyết định và tập trung dài hạn, đồng thời sử dụng LLMs một cách chiến lược mà vẫn duy trì được tính chủ động cá nhân. Như ông viết: &amp;ldquo;Việc chuyển giao hoàn toàn sẽ làm tê liệt việc học thực sự nhưng tối đa hóa tốc độ và đầu ra ngắn hạn, và việc tìm ra sự cân bằng phù hợp là rất quan trọng.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="how-cursor-indexes-codebases-fast"&gt;&lt;a class="link" href="https://read.engineerscodex.com/p/how-cursor-indexes-codebases-fast" target="_blank" rel="noopener"
&gt;How Cursor Indexes Codebases Fast&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này tiết lộ cách Cursor - một IDE AI phổ biến - lập chỉ mục mã nguồn một cách nhanh chóng và hiệu quả. Cursor sử dụng cây Merkle để theo dõi và đồng bộ hóa thay đổi trong codebase, cho phép cập nhật tăng dần chỉ các file đã được chỉnh sửa.&lt;/p&gt;
&lt;p&gt;Quy trình bắt đầu với việc chia nhỏ mã nguồn (code chunking) thành các phần có ý nghĩa về mặt ngữ nghĩa. Cursor sử dụng các chiến lược tiên tiến như phân tích cây cú pháp trừu tượng (AST) để đảm bảo việc chia nhỏ không phá vỡ ranh giới ngữ nghĩa của mã.&lt;/p&gt;
&lt;p&gt;Sau đó, hệ thống tạo ra các biểu diễn vector (embeddings) cho từng đoạn mã bằng các mô hình embedding chuyên biệt cho code. Những embedding này được lưu trữ trong cơ sở dữ liệu vector (Turbopuffer) cùng với metadata như số dòng và tham chiếu file, trong khi đường dẫn file được làm mờ để bảo vệ quyền riêng tư.&lt;/p&gt;
&lt;p&gt;Khi người dùng tương tác với các tính năng AI của Cursor, hệ thống sẽ tính toán embedding cho truy vấn, thực hiện tìm kiếm tương đồng ngữ nghĩa trong codebase, và truy xuất các đoạn mã liên quan để cung cấp context cho việc tạo mã và hỗ trợ thông minh.&lt;/p&gt;
&lt;p&gt;Phương pháp này mang lại nhiều lợi ích: cập nhật tăng dần hiệu quả, xác minh tính toàn vẹn dữ liệu, tối ưu hóa bộ nhớ đệm, lập chỉ mục bảo vệ quyền riêng tư, và tích hợp với lịch sử Git. Điều này cho phép Cursor cung cấp các tính năng như hoàn thành mã thông minh, hỏi đáp về codebase, và đề xuất tái cấu trúc một cách chính xác.&lt;/p&gt;
&lt;h2 id="a-leap-year-check-in-three-instructions"&gt;&lt;a class="link" href="https://hueffner.de/falk/blog/a-leap-year-check-in-three-instructions.html" target="_blank" rel="noopener"
&gt;A Leap Year Check in Three Instructions&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trình bày một cách tiếp cận sáng tạo và cực kỳ tối ưu để kiểm tra năm nhuận chỉ với ba lệnh CPU thông qua kỹ thuật thao tác bit tinh vi.&lt;/p&gt;
&lt;p&gt;Thông thường, việc kiểm tra năm nhuận yêu cầu nhiều điều kiện: chia hết cho 4, không chia hết cho 100 trừ khi chia hết cho 400. Tác giả đã phát triển một phương pháp sử dụng các hằng số &amp;ldquo;ma thuật&amp;rdquo; được tính toán cẩn thận để giảm toàn bộ logic thành một phép toán bit duy nhất: &lt;code&gt;return ((y * 1073750999u) &amp;amp; 3221352463u) &amp;lt;= 126976u;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Điểm đột phá trong cách tiếp cận này là việc sử dụng Z3 solver - một công cụ tìm kiếm tự động - để tìm ra các hằng số tối ưu cho phép thực hiện kiểm tra năm nhuận thông qua thao tác bit. Thuật toán được xác minh hoạt động chính xác cho các năm từ 0 đến 102,499.&lt;/p&gt;
&lt;p&gt;Về hiệu suất, phương pháp này nhanh hơn 3.8 lần so với cách triển khai truyền thống khi xử lý dữ liệu ngẫu nhiên, và duy trì hiệu suất ổn định qua các mẫu đầu vào khác nhau với chi phí tối thiểu.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, cách tiếp cận này cũng có hạn chế: chỉ được đảm bảo chính xác cho năm từ 0-102,499 và tính hữu ích thực tế phụ thuộc vào trường hợp sử dụng cụ thể. Bài viết này thể hiện một bài tập thao tác bit hấp dẫn hơn là một giải pháp thay thế hoàn toàn cho tính toán năm nhuận chuẩn, nhưng cho thấy tiềm năng của việc tối ưu hóa thuật toán sáng tạo.&lt;/p&gt;
&lt;h2 id="reservoir-sampling"&gt;&lt;a class="link" href="https://samwho.dev/reservoir-sampling/" target="_blank" rel="noopener"
&gt;Reservoir Sampling&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Reservoir sampling là một thuật toán để chọn mẫu ngẫu nhiên công bằng khi bạn không biết trước tổng kích thước của tập dữ liệu đang lấy mẫu. Đây là một kỹ thuật cực kỳ hữu ích trong xử lý dữ liệu streaming và các tình huống có khối lượng dữ liệu không xác định.&lt;/p&gt;
&lt;p&gt;Thuật toán hoạt động bằng cách duy trì một &amp;ldquo;hồ chứa&amp;rdquo; (reservoir) có kích thước cố định chứa các item được chọn. Khi xử lý từng item mới trong luồng dữ liệu, mỗi item có xác suất &lt;code&gt;1/n&lt;/code&gt; được chọn, trong đó &lt;code&gt;n&lt;/code&gt; là số lượng item đã thấy cho đến thời điểm đó. Đối với việc chọn nhiều item, xác suất trở thành &lt;code&gt;k/n&lt;/code&gt;, với &lt;code&gt;k&lt;/code&gt; là số lượng item muốn chọn.&lt;/p&gt;
&lt;p&gt;Bài viết minh họa ứng dụng thực tế thông qua tình huống dịch vụ thu thập log. Khi một dịch vụ nhận được khối lượng log khổng lồ, reservoir sampling cho phép chọn ngẫu nhiên một số lượng log cố định (ví dụ 5 log mỗi giây), đảm bảo đại diện công bằng trong các giai đoạn có lưu lượng cao, duy trì việc sử dụng bộ nhớ có thể dự đoán, và ngăn chặn quá tải dịch vụ.&lt;/p&gt;
&lt;p&gt;Những lợi ích chính của thuật toán này bao gồm khả năng làm việc với các luồng có kích thước không biết trước hoặc vô hạn, cung cấp việc lấy mẫu công bằng về mặt thống kê, sử dụng bộ nhớ hiệu quả, và có thể thích ứng với nhiều tình huống streaming dữ liệu khác nhau.&lt;/p&gt;
&lt;p&gt;Reservoir sampling giải quyết vấn đề tưởng chừng không thể: chọn mẫu đại diện khi không thể dự đoán tổng số lượng item trước.&lt;/p&gt;
&lt;h2 id="beware-the-complexity-merchants"&gt;&lt;a class="link" href="https://chrlschn.dev/blog/2025/05/beware-the-complexity-merchants/" target="_blank" rel="noopener"
&gt;Beware the Complexity Merchants&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này cảnh báo về &amp;ldquo;những kẻ buôn bán độ phức tạp&amp;rdquo; trong phát triển phần mềm - những người có xu hướng tạo ra sự phức tạp không cần thiết trong hệ thống. Tác giả lập luận rằng độ phức tạp tình cờ (accidental complexity) có thể gây tổn hại nghiêm trọng đến tốc độ phát triển của nhóm và tạo ra nền tảng hệ thống không ổn định.&lt;/p&gt;
&lt;p&gt;Bài viết chỉ ra những động cơ đằng sau việc tạo ra độ phức tạp không cần thiết: &lt;strong&gt;mong muốn thể hiện bản thân&lt;/strong&gt; thông qua việc tạo ra các hệ thống phức tạp để tự khẳng định tầm quan trọng, &lt;strong&gt;bảo vệ vị thế cá nhân&lt;/strong&gt; bằng cách xây dựng những hệ thống đòi hỏi bảo trì liên tục, và &lt;strong&gt;tạo ra các vấn đề giả tạo&lt;/strong&gt; để biện minh cho việc cần thêm tài nguyên và quyền kiểm soát.&lt;/p&gt;
&lt;p&gt;Tác giả dẫn lời của Ray Ozzie, người tạo ra Lotus Notes: &amp;ldquo;Độ phức tạp giết chết mọi thứ. Nó hút cạn sức sống của các lập trình viên; nó khiến sản phẩm trở nên khó lập kế hoạch, xây dựng và kiểm thử.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Để chống lại xu hướng này, bài viết đề xuất một số giải pháp: &lt;strong&gt;yêu cầu tài liệu rõ ràng&lt;/strong&gt; cho mọi hệ thống phức tạp, &lt;strong&gt;ưu tiên các giải pháp đơn giản và &amp;ldquo;nhàm chán&amp;rdquo;&lt;/strong&gt;, &lt;strong&gt;bắt buộc kỹ sư dọn dẹp độ phức tạp hiện có&lt;/strong&gt; trước khi thêm hệ thống mới, và &lt;strong&gt;hoài nghi với các giải pháp &amp;ldquo;đạn bạc&amp;rdquo;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Thông điệp cốt lõi là độ phức tạp nên được giảm thiểu tối đa, tập trung vào việc tạo ra các hệ thống đơn giản, dễ bảo trì và mang lại giá trị kinh doanh thực sự.&lt;/p&gt;
&lt;h2 id="asserting-implications"&gt;&lt;a class="link" href="https://tigerbeetle.com/blog/2025-05-26-asserting-implications/" target="_blank" rel="noopener"
&gt;Asserting Implications&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết ngắn gọn này từ TigerBeetle thảo luận về một kỹ thuật lập trình để viết các assertion logic một cách dễ đọc hơn. Tác giả đề xuất thay thế cú pháp assertion truyền thống cho các phép tính toán logic bằng cách tiếp cận conditional assertion rõ ràng hơn.&lt;/p&gt;
&lt;p&gt;Thông thường, phép tính toán logic (logical implication) được biểu diễn dưới dạng &lt;code&gt;assert(!a or b)&lt;/code&gt;, theo công thức toán học &lt;code&gt;A⇒B ⇔ ¬A∨B&lt;/code&gt;. Tuy nhiên, cách viết này có thể khó hiểu và không trực quan.&lt;/p&gt;
&lt;p&gt;Thay vào đó, tác giả khuyến nghị sử dụng &lt;code&gt;if (a) assert(b);&lt;/code&gt; để làm cho ý nghĩa của assertion trở nên rõ ràng hơn. Ví dụ, thay vì viết &lt;code&gt;assert(header_b != null or replica.commit_min == replica.op_checkpoint);&lt;/code&gt;, ta có thể viết &lt;code&gt;if (header_b == null) assert(replica.commit_min == replica.op_checkpoint);&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Cách tiếp cận này làm cho mã nguồn dễ đọc và trực quan hơn bằng cách sử dụng cấu trúc conditional đơn giản thay vì các phép toán logic phức tạp. Đây là một ví dụ nhỏ nhưng hiệu quả về cách cải thiện khả năng đọc mã thông qua việc thay đổi cú pháp đơn giản.&lt;/p&gt;
&lt;p&gt;Bài viết thể hiện triết lý thiết kế của TigerBeetle trong việc ưu tiên sự rõ ràng và đơn giản trong mã nguồn, giúp các lập trình viên dễ dàng hiểu và bảo trì hệ thống.&lt;/p&gt;</description></item><item><title>Newsletter #35</title><link>https://miti99.com/post/2025/07/24/</link><pubDate>Thu, 24 Jul 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/07/24/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #35.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="the-magic-of-software-or-what-makes-a-good-engineer-also-makes-a-good-engineering-organization"&gt;&lt;a class="link" href="https://moxie.org/2024/09/23/a-good-engineer.html" target="_blank" rel="noopener"
&gt;The magic of software; or, what makes a good engineer also makes a good engineering organization&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&amp;ldquo;Phép màu của phần mềm&amp;rdquo; không nằm ở việc coi các công nghệ như những hộp đen bí ẩn, mà ở sự hiểu biết sâu sắc về cách chúng hoạt động. Một kỹ sư giỏi không chỉ sử dụng các công cụ và công nghệ một cách bề ngoài, mà còn tìm hiểu về cơ chế bên trong, khám phá những khả năng không ngờ tới, và từ đó tạo ra những giải pháp sáng tạo.&lt;/p&gt;
&lt;p&gt;Tác giả chỉ ra rằng quá trình phát triển phần mềm không phải là một chiều từ ý tưởng đến triển khai. Thay vào đó, việc hiểu sâu về công nghệ có thể định hình lại tầm nhìn ban đầu, tạo ra những cơ hội mới mà trước đó không ai nghĩ tới. Điều này đòi hỏi kỹ sư phải có tính tò mò, sẵn sàng khám phá và không ngại đi sâu vào các lớp trừu tượng.&lt;/p&gt;
&lt;p&gt;Nguyên tắc này cũng áp dụng cho việc xây dựng tổ chức kỹ thuật hiệu quả. Thay vì tạo ra các team hoạt động như những &amp;ldquo;hộp đen&amp;rdquo; độc lập, các tổ chức cần khuyến khích sự kết nối, học hỏi lẫn nhau và chia sẻ hiểu biết sâu về công nghệ. Chỉ khi chúng ta thực sự hiểu những gì mình đang làm việc cùng, chúng ta mới có thể tạo ra được những điều kỳ diệu trong phần mềm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm mấu chốt&lt;/strong&gt;: Sự sáng tạo thực sự đến từ việc hiểu biết sáng sủa, không phải từ việc áp dụng máy móc các &amp;ldquo;thực hành tốt nhất&amp;rdquo; mà không hiểu bản chất.&lt;/p&gt;
&lt;h2 id="redis-is-open-source-again-but-is-it-too-late"&gt;&lt;a class="link" href="https://blog.abhimanyu-saharan.com/posts/redis-is-open-source-again-but-is-it-too-late" target="_blank" rel="noopener"
&gt;Redis Is Open Source Again. But Is It Too Late?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Sau một năm gây tranh cãi, Redis đã quay trở lại với mô hình mã nguồn mở hoàn toàn vào tháng 5/2025 với giấy phép AGPLv3. Câu chuyện bắt đầu từ tháng 3/2024 khi Redis chuyển sang mô hình giấy phép kép (RSALv2 và SSPLv1) nhằm ngăn các nhà cung cấp đám mây kiếm tiền từ phần mềm mà không đóng góp lại cho cộng đồng.&lt;/p&gt;
&lt;p&gt;Quyết định này đã tạo ra làn sóng phản ứng mạnh mẽ từ cộng đồng. Trong khi Microsoft đã ký thỏa thuận thương mại, Amazon và Google lại không làm vậy. Thay vào đó, họ đã ủng hộ một dự án fork mang tên Valkey, được lưu trữ dưới sự bảo trợ của Linux Foundation. Thậm chí một số hệ điều hành như Arch Linux đã thay thế Redis bằng Valkey hoàn toàn.&lt;/p&gt;
&lt;p&gt;Redis 8 ra mắt với nhiều tính năng ấn tượng: hỗ trợ vector sets cho các ứng dụng AI, tích hợp sẵn JSON, chuỗi thời gian và kiểu dữ liệu xác suất. Đặc biệt, người sáng tạo ban đầu Salvatore Sanfilippo đã quay trở lại dự án.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, câu hỏi &amp;ldquo;đã quá muộn?&amp;rdquo; vẫn còn nguyên giá trị. Nhiều lập trình viên đã di chuyển sang Valkey, lòng tin của cộng đồng đã bị tổn hại nghiêm trọng, và sự hoài nghi về ý định dài hạn của Redis Ltd. vẫn tồn tại. Như tác giả nhận xét: &amp;ldquo;Lòng tin được xây dựng qua nhiều năm nhưng có thể mất chỉ trong một khoảnh khắc.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Khuyến nghị thực tế&lt;/strong&gt;: Với các team đang sử dụng Valkey, ít có lý do để chuyển lại. Với các dự án mới, Redis 8 vẫn là một lựa chọn mã nguồn mở đáng cân nhắc.&lt;/p&gt;
&lt;h2 id="write-the-most-clever-code-you-possibly-can"&gt;&lt;a class="link" href="https://buttondown.com/hillelwayne/archive/write-the-most-clever-code-you-possibly-can" target="_blank" rel="noopener"
&gt;Write the most clever code you possibly can&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Hillel Wayne đưa ra một quan điểm có vẻ trái ngược với lời khuyên thông thường: hãy viết mã &amp;ldquo;thông minh&amp;rdquo; nhất có thể. Tuy nhiên, ông không khuyến khích việc áp dụng mã phức tạp trong sản xuất, mà coi đây là một phương pháp luyện tập có mục đích để nâng cao kỹ năng lập trình.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lợi ích của việc viết &amp;ldquo;clever code&amp;rdquo;&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giúp lập trình viên nắm vững các tính năng phức tạp của ngôn ngữ&lt;/li&gt;
&lt;li&gt;Hiểu sâu hơn về cách các khái niệm lập trình kết hợp với nhau&lt;/li&gt;
&lt;li&gt;Chuẩn bị cho việc giải quyết vấn đề phức tạp với công cụ hạn chế&lt;/li&gt;
&lt;li&gt;Xây dựng mối quan hệ kỹ thuật với đồng nghiệp thông qua thảo luận&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Nguyên tắc quan trọng cần nhớ&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Không bao giờ&lt;/strong&gt; commit mã &amp;ldquo;thông minh&amp;rdquo; vào production&lt;/li&gt;
&lt;li&gt;Sử dụng như một bài tập học tập, không phải chiến lược sản xuất&lt;/li&gt;
&lt;li&gt;Đảm bảo đồng nghiệp hiểu rõ đây chỉ là thực hành, không phải đề xuất triển khai&lt;/li&gt;
&lt;li&gt;Nếu buộc phải sử dụng giải pháp phức tạp, hãy tài liệu hóa chi tiết&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cách tiếp cận được khuyến nghị&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giải quyết cùng một vấn đề bằng cả cách đơn giản và phức tạp&lt;/li&gt;
&lt;li&gt;Viết script cá nhân sử dụng kỹ thuật nâng cao&lt;/li&gt;
&lt;li&gt;Thực hành trong môi trường kiểm soát, không phải production&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ví dụ về &amp;ldquo;clever code&amp;rdquo; bao gồm list comprehension phức tạp, kết hợp nhiều tính năng ngôn ngữ trong một hàm, hoặc sử dụng các cấu trúc ngôn ngữ theo cách không thông thường.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Triết lý cốt lõi&lt;/strong&gt;: Mã &amp;ldquo;thông minh&amp;rdquo; là công cụ xây dựng kỹ năng giúp lập trình viên mở rộng hiểu biết kỹ thuật và khả năng giải quyết vấn đề, chứ không phải chiến lược cho môi trường sản xuất.&lt;/p&gt;
&lt;h2 id="semantic-unit-testing"&gt;&lt;a class="link" href="https://www.alexmolas.com/2025/04/09/semantic-unit-testing.html" target="_blank" rel="noopener"
&gt;Semantic Unit Testing&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Semantic Unit Testing là một phương pháp kiểm thử đột phá sử dụng các mô hình ngôn ngữ lớn (LLM) để đánh giá xem việc triển khai một hàm có khớp với hành vi được mô tả trong tài liệu hay không, mà không cần thực thi mã thực tế.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cách thức hoạt động&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Thu thập thông tin hàm (docstring, mã nguồn, dependencies)&lt;/li&gt;
&lt;li&gt;Xây dựng prompt chi tiết cho LLM&lt;/li&gt;
&lt;li&gt;Phân tích tính đúng đắn về mặt ngữ nghĩa của hàm&lt;/li&gt;
&lt;li&gt;Tạo ra kết quả có cấu trúc với lý do và trạng thái pass/fail&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Ví dụ thực tế&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;multiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;Nhân x với y&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="c1"&gt;# Triển khai cố ý sai&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;tester&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;suite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;openai/o3-mini&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tester&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;multiply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# LLM phát hiện triển khai không khớp với docstring&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Lợi ích đáng kể&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Độ bao phủ kiểm thử toàn diện&lt;/li&gt;
&lt;li&gt;Tích hợp dễ dàng với pytest&lt;/li&gt;
&lt;li&gt;Phát hiện lỗi tiềm ẩn sớm&lt;/li&gt;
&lt;li&gt;Bổ sung cho kiểm thử truyền thống&lt;/li&gt;
&lt;li&gt;Có thể sử dụng mô hình AI cục bộ&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Hạn chế cần lưu ý&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không thay thế hoàn toàn kiểm thử truyền thống&lt;/li&gt;
&lt;li&gt;LLM có thể &amp;ldquo;ảo giác&amp;rdquo; hoặc mắc lỗi&lt;/li&gt;
&lt;li&gt;Chi phí cao với codebase lớn&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tác giả khuyến nghị sử dụng semantic unit testing như một công cụ bổ trợ, không phải phương pháp kiểm thử chính, nhấn mạnh tiềm năng của nó nhưng vẫn giữ góc nhìn thực tế về các hạn chế.&lt;/p&gt;
&lt;h2 id="solid-principles-in-java-with-real-life-examples"&gt;&lt;a class="link" href="https://dev.to/chhavirana/understanding-solid-principles-in-java-with-real-life-examples-1ked" target="_blank" rel="noopener"
&gt;SOLID Principles in Java (With Real life Examples)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Nguyên tắc SOLID là năm nguyên tắc thiết kế hướng đối tượng quan trọng giúp mã nguồn trở nên dễ hiểu, linh hoạt và bảo trì. Bài viết này sử dụng hệ thống đặt đồ ăn như bối cảnh thực tế để giải thích từng nguyên tắc một cách sinh động.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Single Responsibility Principle (SRP)&lt;/strong&gt;:
Mỗi lớp chỉ nên có một trách nhiệm duy nhất. Thay vì một lớp xử lý đồng thời việc đặt hàng, tạo hóa đơn và gửi email, nên tách thành các lớp riêng biệt: OrderProcessor, InvoiceGenerator, và EmailNotifier.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Open/Closed Principle (OCP)&lt;/strong&gt;:
Các thành phần phần mềm nên mở cho việc mở rộng nhưng đóng cho việc sửa đổi. Sử dụng đa hình và interface để thêm phương thức thanh toán mới mà không cần thay đổi mã hiện có.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Liskov Substitution Principle (LSP)&lt;/strong&gt;:
Các lớp con phải có thể thay thế hoàn toàn lớp cha mà không gây lỗi. Ví dụ về việc thiết kế lại các chế độ giao hàng để có hành vi nhất quán và dự đoán được.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Interface Segregation Principle (ISP)&lt;/strong&gt;:
Interface nên tập trung và phù hợp với yêu cầu cụ thể của từng client. Thay vì một interface lớn cho đối tác nhà hàng, nên chia thành các interface nhỏ hơn như OrderAcceptance và FeedbackHandler.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Dependency Inversion Principle (DIP)&lt;/strong&gt;:
Các module cấp cao nên phụ thuộc vào abstraction, không phải concrete implementation. Tạo interface Notifier cho phép chuyển đổi dễ dàng giữa email, SMS và các phương thức thông báo khác thông qua dependency injection.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kết luận thực tế&lt;/strong&gt;: Các nguyên tắc SOLID không chỉ là lý thuyết mà là công cụ thực tế giúp viết mã sạch, có thể mở rộng và bảo trì. Việc áp dụng đúng các nguyên tắc này giúp hệ thống phần mềm linh hoạt hơn trước những thay đổi và yêu cầu mới.&lt;/p&gt;
&lt;h2 id="a-year-on-valkey-charts-path-to-v9-after-break-from-redis"&gt;&lt;a class="link" href="https://www.theregister.com/2025/05/15/a_year_of_valkey" target="_blank" rel="noopener"
&gt;A year on, Valkey charts path to v9 after break from Redis&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Sau một năm tách khỏi Redis, Valkey đã chứng tỏ sức sống mạnh mẽ và đang vạch ra lộ trình phát triển bền vững. Dự án này được sinh ra từ sự phản đối với việc Redis Labs thay đổi giấy phép gây tranh cãi, dẫn đến làn sóng các contributor rời bỏ Redis, bao gồm Madelyn Olson - hiện là đồng maintainer của Valkey.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thành tựu đáng kể trong năm đầu&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phát hành phiên bản 8.0 và 8.1 với nhiều cải tiến&lt;/li&gt;
&lt;li&gt;Bổ sung tính năng quan sát (observability) như thống kê slot, trước đây bị Redis chặn&lt;/li&gt;
&lt;li&gt;Cải thiện hiệu suất để bù đắp chi phí tính toán tối thiểu&lt;/li&gt;
&lt;li&gt;Lên kế hoạch phát hành phiên bản 9 với những thay đổi đáng kể hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Xây dựng cộng đồng đa dạng&lt;/strong&gt;:
Olson nhấn mạnh: &amp;ldquo;Tôi thực sự không muốn đây là dự án của một nhà cung cấp duy nhất.&amp;rdquo; Valkey đã mở rộng đội ngũ maintainer và Ủy ban Chỉ đạo Kỹ thuật, thu hút những contributor như Ricardo Dias từ Percona. Dự án cam kết tránh tình trạng kiệt sức bằng cách phân phối trách nhiệm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược ổn định và hỗ trợ&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cam kết hỗ trợ ít nhất 3 năm cho mỗi phiên bản&lt;/li&gt;
&lt;li&gt;Chỉ định phiên bản minor cuối cùng của mỗi major release để hỗ trợ 5 năm&lt;/li&gt;
&lt;li&gt;Tiếp cận thận trọng với các thay đổi để giảm thiểu gián đoạn&lt;/li&gt;
&lt;li&gt;Không thu thập telemetry, dựa vào phản hồi từ người dùng và nhà cung cấp&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tầm nhìn tương lai&lt;/strong&gt;: Valkey đang tạo dựng động lực với trọng tâm là tính ổn định, hiệu suất và phát triển dựa trên cộng đồng. Đây là minh chứng cho thấy một dự án mã nguồn mở có thể phát triển mạnh mẽ khi có sự dẫn dắt đúng đắn và cộng đồng ủng hộ.&lt;/p&gt;
&lt;h2 id="stack-overflow-is-almost-dead"&gt;&lt;a class="link" href="https://blog.pragmaticengineer.com/stack-overflow-is-almost-dead" target="_blank" rel="noopener"
&gt;Stack Overflow is almost dead&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Stack Overflow - nền tảng hỏi đáp lập trình từng là điểm đến thiết yếu của hàng triệu lập trình viên - đang trải qua sự suy giảm nghiêm trọng. Số lượng câu hỏi mỗi tháng đã giảm xuống mức tương đương thời điểm trang web mới ra mắt năm 2009, đánh dấu sự kết thúc của một kỷ nguyên.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quá trình suy giảm qua các giai đoạn&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2014&lt;/strong&gt;: Bắt đầu suy giảm với chính sách kiểm duyệt nghiêm ngặt hơn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tháng 3/2020&lt;/strong&gt;: Đại dịch tạm thời tăng lưu lượng truy cập&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tháng 6/2021&lt;/strong&gt;: Trang web được bán cho Prosus với giá 1.8 tỷ USD&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tháng 11/2022&lt;/strong&gt;: ChatGPT ra mắt, đẩy nhanh sự suy giảm&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Nguyên nhân chính dẫn đến sự suy giảm&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chính sách kiểm duyệt nghiêm ngặt (từ 2014)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Câu hỏi bị đóng nhanh hơn&lt;/li&gt;
&lt;li&gt;Loại bỏ bài viết &amp;ldquo;chất lượng thấp&amp;rdquo; hiệu quả hơn&lt;/li&gt;
&lt;li&gt;Tạo cảm giác không thân thiện với người dùng mới&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tác động của công cụ AI&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ChatGPT cung cấp câu trả lời nhanh hơn và lịch sự hơn&lt;/li&gt;
&lt;li&gt;Được huấn luyện trên dữ liệu Stack Overflow, chất lượng tương đương&lt;/li&gt;
&lt;li&gt;Loại bỏ nhu cầu sử dụng nền tảng Q&amp;amp;A có kiểm duyệt con người&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Triển vọng tương lai&lt;/strong&gt;: Tác giả dự đoán Stack Overflow có thể sẽ đóng cửa hoặc được bán. Tuy nhiên, ông vẫn lạc quan rằng cộng đồng lập trình viên sẽ tiếp tục tồn tại thông qua các nền tảng thay thế như Discord, WhatsApp, hay Telegram.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Suy ngẫm&lt;/strong&gt;: Đây là kết thúc của một kỷ nguyên quan trọng trong lịch sử phát triển phần mềm, khi một nền tảng từng giúp đỡ hàng triệu lập trình viên giờ đây đối mặt với sự thay thế bởi AI. Điều này đặt ra câu hỏi về tương lai của việc chia sẻ kiến thức trong cộng đồng lập trình.&lt;/p&gt;
&lt;h2 id="why-i-use-webassembly"&gt;&lt;a class="link" href="https://nasso.dev/blog/why-i-use-wasm" target="_blank" rel="noopener"
&gt;Why I use WebAssembly&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;WebAssembly (WASM) đang chứng tỏ là một công nghệ đột phá cho phép các lập trình viên phát triển ứng dụng cross-platform một cách hiệu quả. Tác giả chia sẻ những lý do thực tế khiến ông lựa chọn WASM cho các dự án của mình.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quản lý trạng thái ứng dụng hiệu quả&lt;/strong&gt;:
WASM cho phép xử lý phía client, loại bỏ các round trip tới server không cần thiết. Điều này giúp theo dõi tiến trình thời gian thực cho các thao tác phức tạp và giảm đáng kể độ phức tạp của hạ tầng cũng như chi phí hosting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phát triển đa nền tảng thông minh&lt;/strong&gt;:
WASM hoạt động như &amp;ldquo;định dạng binary toàn cầu&amp;rdquo; để chia sẻ logic ứng dụng cốt lõi giữa các nền tảng. Thay vì phát triển riêng biệt cho web và native, lập trình viên có thể coi web như một nền tảng khác cần hỗ trợ với công sức tối thiểu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lợi ích hiệu suất đo được được&lt;/strong&gt;:
Figma đã giảm thời gian tải 3 lần nhờ WASM. Công nghệ này cho phép port mã native hiện có lên web và hỗ trợ các ứng dụng phức tạp như file converter chạy hoàn toàn trong trình duyệt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược sản phẩm thực tế&lt;/strong&gt;:
Tác giả áp dụng phương pháp &amp;ldquo;80-90% tính năng hoạt động phổ quát&amp;rdquo; - cung cấp đủ tính năng cốt lõi để người dùng trải nghiệm, tạo ra con đường dẫn tới phiên bản native đầy đủ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ví dụ thực tế&lt;/strong&gt;: Tác giả đang phát triển Nema Studio, một Digital Audio Workstation cross-platform, nhắm tới các nhạc sĩ muốn thử nghiệm nhanh các tính năng cốt lõi mà không cần hỗ trợ plugin phức tạp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tầm nhìn công nghệ&lt;/strong&gt;: &amp;ldquo;WebAssembly là cách để chia sẻ mã giữa các nền tảng&amp;hellip; web chỉ đơn giản trở thành một nền tảng khác cần hỗ trợ!&amp;rdquo; Điều này mở ra khả năng sử dụng các công cụ như FFmpeg trong trình duyệt và tương thích với framework như Tauri.&lt;/p&gt;</description></item><item><title>Newsletter #34</title><link>https://miti99.com/post/2025/07/23/</link><pubDate>Wed, 23 Jul 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/07/23/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #34.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="why-tdd-doesn"&gt;&lt;a class="link" href="https://tidyfirst.substack.com/p/why-tdd-doesnt-lead-to-dumb-code" target="_blank" rel="noopener"
&gt;Why TDD Doesn&amp;rsquo;t Lead to Dumb Code&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Phát triển theo hướng kiểm thử (TDD) thường bị hiểu lầm là sẽ tạo ra mã nguồn &amp;ldquo;ngu ngốc&amp;rdquo; hoặc quá đơn giản. Kent Beck trong bài viết này giải thích tại sao quan điểm này không đúng và chỉ ra rằng chất lượng mã nguồn phụ thuộc vào kỹ năng và quyết định thiết kế của lập trình viên, chứ không phải phương pháp kiểm thử.&lt;/p&gt;
&lt;p&gt;Tác giả minh họa quá trình tổng quát hóa thông qua ví dụ về hàm tính giai thừa. Bắt đầu với test case đơn giản &lt;code&gt;assert factorial(1) == 1&lt;/code&gt;, sau đó từng bước thêm độ phức tạp và tổng quát hóa. Điểm quan trọng là tránh hardcode các giá trị cụ thể và dần dần trừu tượng hóa việc triển khai.&lt;/p&gt;
&lt;p&gt;Thách thức chính trong TDD không phải là phương pháp tạo ra mã kém chất lượng, mà là:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lập trình viên có thể không có đủ kiểm thử để ràng buộc mã nguồn&lt;/li&gt;
&lt;li&gt;Việc tổng quát hóa logic phức tạp đôi khi cần thời gian và sự thấu hiểu sâu&lt;/li&gt;
&lt;li&gt;Cần biết nhận ra các mẫu thiết kế thay vì copy-paste vô tận&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;TDD mang lại lợi ích là giảm sự kết nối chặt chẽ giữa kiểm thử và triển khai, cho phép thêm kiểm thử mà không cần thay đổi mã hiện có, và khuyến khích phát triển mã nguồn một cách từng bước và có suy nghĩ.&lt;/p&gt;
&lt;h2 id="how-discord-indexes-trillions-of-messages"&gt;&lt;a class="link" href="https://discord.com/blog/how-discord-indexes-trillions-of-messages" target="_blank" rel="noopener"
&gt;How Discord Indexes Trillions of Messages&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Discord chia sẻ cách họ xây dựng hệ thống tìm kiếm cho hàng nghìn tỷ tin nhắn, một thách thức kỹ thuật khổng lồ. Trước đây, hệ thống cũ gặp nhiều vấn đề: hàng đợi Redis thường xuyên mất tin nhắn, việc đánh chỉ mục hàng loạt dễ bị lỗi khi node Elasticsearch gặp sự cố, và các cụm Elasticsearch lớn có chi phí vận hành cao.&lt;/p&gt;
&lt;p&gt;Giải pháp mới của Discord sử dụng kiến trúc &amp;ldquo;cell&amp;rdquo; với nhiều cụm Elasticsearch nhỏ hơn chạy trên Kubernetes. Họ di chuyển hàng đợi tin nhắn từ Redis sang Google PubSub và phát triển chiến lược gộp tin nhắn thông minh. Hệ thống mới được viết bằng Rust với Tokio async runtime để xử lý routing tin nhắn hiệu quả.&lt;/p&gt;
&lt;p&gt;Kết quả đạt được rất ấn tượng:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tăng gấp đôi tốc độ đánh chỉ mục tin nhắn&lt;/li&gt;
&lt;li&gt;Giảm độ trễ truy vấn từ 500ms xuống dưới 100ms&lt;/li&gt;
&lt;li&gt;Hỗ trợ 40 cụm Elasticsearch với hàng nghìn chỉ mục&lt;/li&gt;
&lt;li&gt;Kích hoạt tính năng tìm kiếm tin nhắn riêng tư và hỗ trợ &amp;ldquo;Big Freaking Guilds&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Đây là một case study tuyệt vời về cách mở rộng hệ thống tìm kiếm ở quy mô lớn với kiến trúc phân tán hiện đại.&lt;/p&gt;
&lt;h2 id="data-oriented-programming-dop-in-java"&gt;&lt;a class="link" href="https://nejckorasa.github.io/posts/data-oriented-programming-in-java/" target="_blank" rel="noopener"
&gt;Data Oriented Programming (DOP) in Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Lập trình hướng dữ liệu (DOP) trong Java là một phương pháp tiếp cận mới tập trung vào việc tách biệt dữ liệu khỏi hành vi. Thay vì nhúng logic xử lý vào các lớp dữ liệu, DOP khuyến khích sử dụng các cấu trúc dữ liệu đơn giản và các hàm độc lập để thao tác trên dữ liệu đó.&lt;/p&gt;
&lt;p&gt;Các nguyên tắc chính của DOP bao gồm: mô hình hóa dữ liệu bất biến và minh bạch, tập trung vào việc biểu diễn dữ liệu thuần túy, làm cho các trạng thái không hợp lệ trở nên không thể biểu diễn được, và tách biệt các thao tác khỏi cấu trúc dữ liệu.&lt;/p&gt;
&lt;p&gt;Java hiện đại hỗ trợ DOP thông qua nhiều tính năng mới:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Records&lt;/strong&gt;: Các lớp dữ liệu nhẹ và bất biến&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sealed Classes&lt;/strong&gt;: Hạn chế các kiểu con có thể có để mô hình hóa dữ liệu dự đoán được hơn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pattern Matching và Switch Expressions&lt;/strong&gt;: Cho phép kiểm tra kiểu toàn diện và xử lý dữ liệu sạch sẽ&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lợi ích của DOP bao gồm mã nguồn đơn giản và dễ đọc hơn, khả năng bảo trì được cải thiện, giảm sự kết nối chặt chẽ giữa các thành phần hệ thống, dễ dàng kiểm thử các hàm độc lập, và tái cấu trúc an toàn hơn.&lt;/p&gt;
&lt;h2 id="why-performance-optimization-is-hard-work"&gt;&lt;a class="link" href="https://purplesyringa.moe/blog/why-performance-optimization-is-hard-work/" target="_blank" rel="noopener"
&gt;Why performance optimization is hard work&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tối ưu hiệu suất là một trong những lĩnh vực khó khăn nhất trong phát triển phần mềm, và bài viết này giải thích lý do tại sao. Tác giả chỉ ra năm thách thức chính khiến việc tối ưu hiệu suất trở thành &amp;ldquo;công việc cần sức lực&amp;rdquo;:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tính tổng hợp (Composability)&lt;/strong&gt;: Các kỹ thuật tối ưu thường không tương thích với nhau hoặc thậm chí phản tác dụng khi kết hợp. Việc loại bỏ những cách tiếp cận &amp;ldquo;rõ ràng là không tối ưu&amp;rdquo; chỉ là phỏng đoán, đòi hỏi nhiều thử nghiệm và hiểu biết sâu về phần cứng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tính liên tục (Continuity)&lt;/strong&gt;: Hiệu suất có thể thay đổi đột ngột với những sửa đổi nhỏ. Việc tìm ra điều kiện biên phức tạp và điều chỉnh tham số liên tục là cần thiết để đạt được hiệu suất tối ưu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tính không tương thích&lt;/strong&gt;: Các ràng buộc bên ngoài như giới hạn bộ nhớ đệm và áp lực thanh ghi tạo ra những thách thức đặc thù cho phần cứng, đòi hỏi các giải pháp sáng tạo và thỏa hiệp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hạn chế của trình biên dịch&lt;/strong&gt;: Trình biên dịch không tự động tạo ra mã tối ưu, đòi hỏi kiểm tra thủ công mã assembly được tạo ra và profiling chi tiết.&lt;/p&gt;
&lt;p&gt;Kết luận quan trọng là tối ưu hiệu suất về cơ bản là một &amp;ldquo;nhiệm vụ dùng sức lực&amp;rdquo;, đòi hỏi sự kiên trì, kiến thức kỹ thuật sâu và khả năng giải quyết vấn đề sáng tạo.&lt;/p&gt;
&lt;h2 id="good-vs-great-animations"&gt;&lt;a class="link" href="https://emilkowal.ski/ui/good-vs-great-animations" target="_blank" rel="noopener"
&gt;Good vs Great Animations&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong thời đại mà hầu hết phần mềm đều &amp;ldquo;đủ tốt&amp;rdquo;, việc tạo ra sự khác biệt thông qua trải nghiệm người dùng trở nên quan trọng hơn bao giờ hết. Bài viết này khám phá sự khác biệt giữa animation tốt và animation xuất sắc trong thiết kế giao diện.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Animation nhận biết nguồn gốc (Origin-Aware)&lt;/strong&gt;: Animation tuyệt vời luôn có điểm xuất phát rõ ràng và tự nhiên. Ví dụ, menu dropdown nên xuất hiện từ vị trí nút bấm thay vì từ trung tâm màn hình. Sử dụng &lt;code&gt;transform-origin&lt;/code&gt; để kiểm soát điểm bắt đầu của animation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Easing và thời gian&lt;/strong&gt;: Đây là yếu tố quan trọng nhất để tạo ra chuyển động tự nhiên. Thay vì sử dụng &lt;code&gt;linear&lt;/code&gt;, nên ưu tiên &lt;code&gt;ease-out&lt;/code&gt; hoặc &lt;code&gt;ease-in-out&lt;/code&gt; để mô phỏng gia tốc và giảm tốc như trong thế giới thực.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Đường cong easing tùy chỉnh&lt;/strong&gt;: Các đường cong CSS có sẵn thường không đủ để tạo ra animation hấp dẫn. Sử dụng các công cụ như easing.dev và easings.co để tạo ra các đường cong tùy chỉnh mang lại cảm giác năng động hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tương tác dạng lò xo (Spring-based)&lt;/strong&gt;: Sử dụng chuyển động dạng lò xo để tạo ra cảm giác tự nhiên và hữu cơ, đặc biệt hiệu quả cho các element trang trí không mang tính chức năng.&lt;/p&gt;
&lt;p&gt;Điểm mấu chốt: animation tuyệt vời không chỉ là về kỹ thuật mà còn về việc tạo ra chuyển động có mục đích, tự nhiên và nâng cao trải nghiệm người dùng.&lt;/p&gt;
&lt;h2 id="senior-engineers-should-make-side-bets"&gt;&lt;a class="link" href="https://www.seangoedecke.com/side-bets/" target="_blank" rel="noopener"
&gt;Senior engineers should make side bets&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Kỹ sư phần mềm senior nên dành 10-20% thời gian cho các dự án phụ (side bets) - những công việc tự khởi xướng không nằm trong danh sách nhiệm vụ chính thức. Đây là lời khuyên từ góc nhìn thực tế về cách phát triển sự nghiệp và tạo tác động.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tại sao cần side bets&lt;/strong&gt;: Các dự án phụ tạo ra giá trị độc đáo mà không kỹ sư nào khác có thể tạo ra. Chúng thể hiện sự chủ động, sáng tạo và tư duy chiến lược vượt ra ngoài công việc được giao.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược thực hiện&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chọn các dự án có lợi ích cụ thể, có thể đo lường được&lt;/li&gt;
&lt;li&gt;Tỷ lệ thành công kỳ vọng: 2-3 side bet thành công mỗi năm&lt;/li&gt;
&lt;li&gt;Nếu thất bại, im lặng chuyển sang dự án khác&lt;/li&gt;
&lt;li&gt;Nếu thành công, tích cực truyền đạt giá trị tới đồng nghiệp và quản lý&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Nguyên tắc quan trọng&lt;/strong&gt;: Hầu hết side bets sẽ thất bại và điều này hoàn toàn bình thường. Những side bet thành công sẽ bù đắp cho tất cả. Chúng cần có tiềm năng tạo giá trị cho công ty, có tác động có thể chứng minh được, và không tiêu tốn quá nhiều thời gian hoặc tài nguyên.&lt;/p&gt;
&lt;p&gt;Quan điểm này đặc biệt phù hợp với kỹ sư senior muốn nâng cao uy tín và tác động trong tổ chức thông qua các sáng kiến cá nhân có ý nghĩa.&lt;/p&gt;
&lt;h2 id="avoiding-skill-atrophy-in-the-age-of-ai"&gt;&lt;a class="link" href="https://addyo.substack.com/p/avoiding-skill-atrophy-in-the-age" target="_blank" rel="noopener"
&gt;Avoiding Skill Atrophy in the Age of AI&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong thời đại AI trợ lý lập trình ngày càng phổ biến, một thách thức mới nổi lên: làm thế nào để tránh suy giảm kỹ năng cá nhân khi quá phụ thuộc vào công nghệ? Bài viết này đưa ra những chiến lược thực tế để duy trì và phát triển năng lực lập trình trong bối cảnh AI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dấu hiệu cảnh báo suy giảm kỹ năng&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ngừng đọc tài liệu kỹ thuật và chỉ dựa vào AI&lt;/li&gt;
&lt;li&gt;Mất khả năng debug độc lập&lt;/li&gt;
&lt;li&gt;Giảm sút tư duy thiết kế hệ thống và kiến trúc&lt;/li&gt;
&lt;li&gt;Quên cú pháp và khái niệm lập trình cơ bản&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược &amp;ldquo;Vệ sinh AI&amp;rdquo; (AI Hygiene)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Luôn xác minh và hiểu rõ mã do AI tạo ra&lt;/li&gt;
&lt;li&gt;Phê phán các gợi ý của AI một cách có phản biện&lt;/li&gt;
&lt;li&gt;Yêu cầu AI giải thích mã từng dòng&lt;/li&gt;
&lt;li&gt;Kiểm thử các giải pháp AI với input phức tạp&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Thực hành duy trì kỹ năng có chủ đích&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thiết lập &amp;ldquo;Ngày không AI&amp;rdquo; để lập trình thủ công&lt;/li&gt;
&lt;li&gt;Thử giải quyết vấn đề độc lập trước khi nhờ AI&lt;/li&gt;
&lt;li&gt;Sử dụng AI như một đồng nghiệp junior, không phải giải pháp hoàn chỉnh&lt;/li&gt;
&lt;li&gt;Ghi chép học hỏi từ các nhiệm vụ có sự hỗ trợ của AI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Triết lý cốt lõi&lt;/strong&gt;: Sử dụng AI để &amp;ldquo;khuếch đại&amp;rdquo; khả năng cá nhân thay vì thay thế hoàn toàn kỹ năng con người. Mục tiêu là bảo tồn &amp;ldquo;nghề thủ công và niềm vui giải quyết vấn đề&amp;rdquo; trong khi tận dụng sức mạnh của AI như một công cụ hỗ trợ thông minh.&lt;/p&gt;
&lt;h2 id="cursor-best-practices"&gt;&lt;a class="link" href="https://x.com/paraschopra/status/1917466537637859544" target="_blank" rel="noopener"
&gt;Cursor best practices&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://pbs.twimg.com/media/Gpw1p1waYAAeAyY?format=jpg"
loading="lazy"
alt="Cursor best practices"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #33</title><link>https://miti99.com/post/2025/07/22/</link><pubDate>Tue, 22 Jul 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/07/22/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #33.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="how-zgc-allocates-memory-for-the-java-heap"&gt;&lt;a class="link" href="https://joelsiks.com/posts/zgc-heap-memory-allocation/" target="_blank" rel="noopener"
&gt;How ZGC allocates memory for the Java heap&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;ZGC (Z Garbage Collector) là một trong những bộ thu gom rác hiện đại nhất của Java, được thiết kế để đạt được độ trễ thấp ngay cả với kích thước heap lớn. Bài viết này đi sâu vào cách ZGC quản lý và phân bổ bộ nhớ heap, một khía cạnh quan trọng giúp ZGC đạt được hiệu suất ấn tượng.&lt;/p&gt;
&lt;p&gt;Điểm đặc biệt của ZGC là cách nó tách biệt việc quản lý bộ nhớ vật lý và bộ nhớ ảo. ZGC chia heap thành các trang với ba kích thước khác nhau: Nhỏ (2 MB), Vừa (32 MB) và Lớn (kích thước linh hoạt). Điều này giúp tối ưu hóa việc sử dụng bộ nhớ và giảm thiểu phân mảnh.&lt;/p&gt;
&lt;p&gt;Chiến lược phân bổ bộ nhớ của ZGC dựa trên phương thức phân bổ theo dung lượng, có thể xử lý bốn tình huống khác nhau: sử dụng bộ nhớ từ vùng đệm, tăng dung lượng bằng cách cấp phát bộ nhớ mới, thu hồi bộ nhớ từ vùng đệm, hoặc kết hợp giữa thu hồi và tăng dung lượng. ZGC cũng hỗ trợ phân bổ đa phân vùng đặc biệt hữu ích cho các hệ thống NUMA.&lt;/p&gt;
&lt;p&gt;Những điểm nổi bật của ZGC:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dự trữ bộ nhớ ảo nhiều hơn cần thiết (mặc định là 16 lần kích thước heap tối đa) để chống phân mảnh&lt;/li&gt;
&lt;li&gt;Tích cực xếp lại heap khi các trang được giải phóng&lt;/li&gt;
&lt;li&gt;Hỗ trợ thay đổi kích thước heap linh hoạt&lt;/li&gt;
&lt;li&gt;Sử dụng đơn vị bộ nhớ tối thiểu là 2 MB&lt;/li&gt;
&lt;li&gt;Thiết kế thích ứng cho các kiến trúc hệ thống khác nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="optimizing-the-garbage-collector-when-migrating-cloud-workloads"&gt;&lt;a class="link" href="https://foojay.io/today/optimizing-the-garbage-collector-when-migrating-cloud-workloads/" target="_blank" rel="noopener"
&gt;Optimizing the Garbage Collector when Migrating Cloud Workloads&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Khi di chuyển các ứng dụng Java lên đám mây, đặc biệt là sang kiến trúc Arm, việc tối ưu hóa bộ thu gom rác trở thành yếu tố quan trọng để đảm bảo hiệu suất. Bài viết này cung cấp hướng dẫn chi tiết về cách tinh chỉnh GC để phù hợp với môi trường đám mây hiện đại.&lt;/p&gt;
&lt;p&gt;Tác giả khuyến nghị G1 GC là điểm khởi đầu an toàn cho hầu hết các ứng dụng máy chủ, trong khi ZGC hoặc Shenandoah nên được cân nhắc cho các ứng dụng yêu cầu độ trễ thấp với kích thước heap lớn. Điều quan trọng là sử dụng OpenJDK phiên bản hiện đại (Java 11 trở lên) để tận dụng các tối ưu hóa dành riêng cho Arm.&lt;/p&gt;
&lt;p&gt;Chiến lược di chuyển hiệu quả bao gồm việc điều chỉnh kích thước heap cẩn thận để cân bằng giữa tần suất thu gom và thời gian tạm dừng. Sử dụng &lt;code&gt;-XX:MaxGCPauseMillis&lt;/code&gt; để cho phép JVM tự động tối ưu hóa thời gian tạm dừng và bật tính năng thay đổi kích thước heap tự động với &lt;code&gt;-XX:+UseAdaptiveSizePolicy&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Những lợi ích của việc di chuyển lên đám mây:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Triển khai đa kiến trúc cho phép chọn tỷ lệ giá-hiệu suất tối ưu&lt;/li&gt;
&lt;li&gt;Kiến trúc Arm Neoverse cung cấp số lượng nhân xử lý có thể mở rộng với hiệu suất GC mạnh mẽ&lt;/li&gt;
&lt;li&gt;Nguyên tắc &amp;ldquo;viết một lần, chạy mọi nơi&amp;rdquo; của Java giúp quá trình di chuyển diễn ra mượt mà&lt;/li&gt;
&lt;li&gt;Sử dụng nhật ký GC và Java Flight Recorder để theo dõi và điều chỉnh&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-javascript-works-behind-the-scenes"&gt;&lt;a class="link" href="https://www.deepintodev.com/blog/how-javascript-works-behind-the-scenes" target="_blank" rel="noopener"
&gt;How JavaScript Works Behind the Scenes&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;JavaScript là ngôn ngữ đơn luồng nhưng lại có khả năng xử lý các tác vụ bất đồng bộ một cách hiệu quả. Bài viết này giải thích chi tiết cơ chế hoạt động bên trong của động cơ JavaScript và cách nó quản lý việc thực thi mã.&lt;/p&gt;
&lt;p&gt;Cốt lõi của động cơ JavaScript bao gồm hai thành phần chính: Heap - vùng nhớ lưu trữ các đối tượng và biến, và Ngăn xếp gọi hàm - quản lý việc thực thi chương trình theo cơ chế vào sau ra trước. Mỗi khi một hàm được gọi, một &amp;ldquo;ngữ cảnh thực thi&amp;rdquo; mới được tạo ra chứa các biến cục bộ, tham số hàm, giá trị &lt;code&gt;this&lt;/code&gt; và tham chiếu đến phạm vi bên ngoài.&lt;/p&gt;
&lt;p&gt;Điều thú vị là cách JavaScript xử lý các tác vụ bất đồng bộ mặc dù chỉ có một luồng. Các API của trình duyệt (như fetch, setTimeout, geolocation) cho phép chuyển các tác vụ dài sang trình duyệt xử lý, trong khi Hàng đợi tác vụ và Vòng lặp sự kiện đảm bảo các hàm gọi lại được thực thi đúng thời điểm. Vòng lặp sự kiện liên tục kiểm tra Ngăn xếp gọi hàm và di chuyển các tác vụ từ hàng đợi vào ngăn xếp khi ngăn xếp rỗng.&lt;/p&gt;
&lt;p&gt;Cơ chế ưu tiên thực thi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hàng đợi tác vụ nhỏ (Promises, async/await) có độ ưu tiên cao hơn Hàng đợi tác vụ thường&lt;/li&gt;
&lt;li&gt;Vòng lặp sự kiện luôn xử lý hết các tác vụ nhỏ trước khi chuyển sang các tác vụ thường&lt;/li&gt;
&lt;li&gt;Điều này giải thích tại sao các hàm gọi lại của Promise thường được thực thi trước các hàm gọi lại của setTimeout&lt;/li&gt;
&lt;li&gt;Cơ chế này giúp JavaScript duy trì tính &amp;ldquo;không chặn&amp;rdquo; mà không cần đa luồng&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-embedding-models-should-match--advice-for-starting-a-blog"&gt;&lt;a class="link" href="https://foojay.io/today/breaktime-tech-talks-ep39-why-embedding-models-should-match-advice-for-starting-a-blog/" target="_blank" rel="noopener"
&gt;Why embedding models should match + Advice for starting a blog&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Các mô hình nhúng trong cơ sở dữ liệu vector cần phải khớp chính xác để đảm bảo kết quả tìm kiếm tin cậy. Jennifer Reif chia sẻ kinh nghiệm khi sử dụng các mô hình nhúng khác nhau của OpenAI (text-ada-002 và text-3-small), dù trong cùng họ nhưng vẫn gây ra sự khác biệt trong kết quả tìm kiếm tương đồng.&lt;/p&gt;
&lt;p&gt;Vấn đề cốt lõi là mỗi cơ sở dữ liệu vector có thể thực hiện tìm kiếm tương đồng theo cách riêng, và việc sử dụng mô hình nhúng khác nhau sẽ tạo ra biểu diễn vector khác nhau cho cùng một nội dung. Điều này dẫn đến kết quả không nhất quán và có thể gây khó khăn trong việc duy trì hệ thống RAG (Truy xuất-Tăng cường Tạo sinh).&lt;/p&gt;
&lt;p&gt;Ngoài ra, bài viết còn đưa ra những lời khuyên thiết thực cho việc bắt đầu viết blog:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Viết cho bản thân trước tiên - ghi lại hành trình học tập và tạo tài liệu tham khảo cá nhân&lt;/li&gt;
&lt;li&gt;Sử dụng giọng văn gần gũi, tự nhiên như trò chuyện&lt;/li&gt;
&lt;li&gt;Lập kế hoạch và chỉnh sửa nhưng không quá cầu kỳ&lt;/li&gt;
&lt;li&gt;Tận dụng tính linh hoạt của nội dung số - cho phép người đọc chọn lọc nội dung&lt;/li&gt;
&lt;li&gt;Viết về giải pháp cho những vấn đề mà bạn từng gặp khó khăn để tìm câu trả lời&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="hula-human-in-the-loop-llm-based-agents-for-software-development"&gt;&lt;a class="link" href="https://www.atlassian.com/blog/atlassian-engineering/hula-blog-autodev-paper-human-in-the-loop-software-development-agents" target="_blank" rel="noopener"
&gt;HULA: Human-in-the-loop LLM-based agents for software development&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Atlassian giới thiệu HULA (Tác nhân AI có con người tham gia), một khung làm việc cho tác nhân AI hỗ trợ phát triển phần mềm với sự tham gia kiểm soát của kỹ sư. Đây là nghiên cứu được chấp nhận bởi Hội nghị Quốc tế về Kỹ thuật Phần mềm (SEIP) 2025, thể hiện tiềm năng to lớn trong việc ứng dụng AI vào phát triển phần mềm.&lt;/p&gt;
&lt;p&gt;HULA hoạt động theo quy trình 4 bước: thiết lập ngữ cảnh từ nhiệm vụ Jira, tạo kế hoạch viết mã để kỹ sư xem xét, tạo mã với xác thực, và cuối cùng tạo yêu cầu kéo code. Khung làm việc này không thay thế lập trình viên mà hỗ trợ tự động hóa các tác vụ lặp lại trong khi vẫn giữ kỹ sư ở vị trí kiểm soát.&lt;/p&gt;
&lt;p&gt;Kết quả thử nghiệm trong 2 tháng rất ấn tượng:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tạo được kế hoạch viết mã cho 79% nhiệm vụ&lt;/li&gt;
&lt;li&gt;Sinh mã cho 87% kế hoạch được phê duyệt&lt;/li&gt;
&lt;li&gt;59% yêu cầu kéo code được hợp nhất vào kho mã&lt;/li&gt;
&lt;li&gt;Vượt qua kiểm thử đơn vị cho 31% vấn đề SWE-bench&lt;/li&gt;
&lt;li&gt;45% mã được tạo ra được đánh giá rất tương đồng với mã của con người&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Khảo sát với 109 kỹ sư cho thấy 62% đồng ý HULA xác định đúng các file cần sửa, và 61% thấy mã được tạo ra dễ hiểu. Điều đặc biệt là HULA tập trung vào việc tăng cường khả năng con người thay vì thay thế, tạo ra mô hình hợp tác hiệu quả giữa AI và lập trình viên.&lt;/p&gt;
&lt;h2 id="refactoring-gone-wild-avoiding-code-smells-and-cleaning-up-the-mess"&gt;&lt;a class="link" href="https://techhub.iodigital.com/articles/refactoring-gone-wild-avoiding-code-smells-and-cleaning-up-the-mess" target="_blank" rel="noopener"
&gt;Refactoring Gone Wild: Avoiding Code Smells and Cleaning Up the Mess&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Tái cấu trúc mã là một nghệ thuật quan trọng trong phát triển phần mềm, nhưng việc nhận diện và xử lý mùi mã hiệu quả đòi hỏi kinh nghiệm và kỹ thuật phù hợp. Bài viết này phân tích 10 mùi mã phổ biến và cách khắc phục chúng một cách có hệ thống.&lt;/p&gt;
&lt;p&gt;Các mùi mã được nhấn mạnh bao gồm Kim tự tháp Diệt vong (điều kiện lồng sâu), Hàm Quái vật Khổng lồ, Tham số Bí ẩn, và Rừng Kiểm tra Null. Mỗi mùi đều có tác động tiêu cực đến khả năng bảo trì và dễ đọc của mã, đồng thời làm tăng độ phức tạp không cần thiết.&lt;/p&gt;
&lt;p&gt;Kỹ thuật tái cấu trúc được khuyến nghị:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng mệnh đề bảo vệ để đơn giản hóa logic điều kiện&lt;/li&gt;
&lt;li&gt;Tạo lớp dữ liệu để nhóm các tham số liên quan&lt;/li&gt;
&lt;li&gt;Tách logic phức tạp thành các hàm nhỏ, tập trung&lt;/li&gt;
&lt;li&gt;Tận dụng tính năng an toàn null của ngôn ngữ&lt;/li&gt;
&lt;li&gt;Tập trung hóa xác thực và xử lý lỗi&lt;/li&gt;
&lt;li&gt;Áp dụng tính bất biến khi có thể&lt;/li&gt;
&lt;li&gt;Áp dụng kỹ thuật lập trình hàm như &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;groupBy&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Triết lý quan trọng nhất là &amp;ldquo;Tiến bộ nhỏ từng bước vẫn tạo ra sự khác biệt lớn&amp;rdquo;. Tái cấu trúc không cần phải là đại tu toàn diện, mà có thể thực hiện từng bước nhỏ để dần cải thiện chất lượng mã và khả năng bảo trì.&lt;/p&gt;
&lt;h2 id="how-to-write-error-messages-that-actually-help-users-rather-than-frustrate-them"&gt;&lt;a class="link" href="https://piccalil.li/blog/how-to-write-error-messages-that-actually-help-users-rather-than-frustrate-them/" target="_blank" rel="noopener"
&gt;How to write error messages that actually help users rather than frustrate them&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Thông báo lỗi thường là điểm tiếp xúc quan trọng nhất giữa sản phẩm và người dùng trong lúc họ gặp khó khăn, nhưng phần lớn thông báo lỗi lại được viết theo cách máy móc và gây khó chịu. Bài viết này cung cấp khung làm việc để viết thông báo lỗi thực sự hữu ích và đồng cảm.&lt;/p&gt;
&lt;p&gt;Nguyên tắc cốt lõi là &amp;ldquo;viết như một con người&amp;rdquo; - thay vì những thông báo chung chung như &amp;ldquo;Đã xảy ra lỗi&amp;rdquo;, hãy sử dụng ngôn ngữ gần gũi và rõ ràng. Ví dụ thay vì &amp;ldquo;Không phát hiện kết nối WiFi&amp;rdquo;, nên viết &amp;ldquo;Có vẻ như bạn đang offline. Vui lòng kết nối mạng WiFi và thử lại.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Nguyên tắc chính cho thông báo lỗi hữu ích:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xác định các điểm lỗi tiềm tăng và kiểm tra toàn bộ trải nghiệm người dùng&lt;/li&gt;
&lt;li&gt;Sử dụng thể chủ động để giải thích rõ ràng điều gì đã xảy ra và tại sao&lt;/li&gt;
&lt;li&gt;Tránh lối viết khôi hài - không dùng ngôn ngữ dễ thương hoặc giọng điệu chả thải&lt;/li&gt;
&lt;li&gt;Cung cấp các bước tiếp theo rõ ràng cho mọi tình huống lỗi&lt;/li&gt;
&lt;li&gt;Duy trì tính nhất quán trong các mẫu tài liệu&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Câu hỏi quan trọng khi viết thông báo lỗi: &amp;ldquo;Liệu thông điệp này có hiệu quả với ai đó đang có ngày tồi tệ?&amp;rdquo;. Thông báo lỗi cần giúp người dùng phục hồi nhanh chóng, thể hiện sự tôn trọng thời gian của họ, và duy trì lòng tin trong trải nghiệm sản phẩm. Đối với lỗi có thể sửa, giải thích chính xác người dùng nên làm gì; đối với lỗi không thể sửa, đưa ra các hành động thay thế hoặc phương thức liên hệ.&lt;/p&gt;
&lt;h2 id="the-difficulty-in-big-tech"&gt;&lt;a class="link" href="https://www.seangoedecke.com/difficulty-in-big-tech/" target="_blank" rel="noopener"
&gt;The difficulty in big tech&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Nhiều người thường có ấn tượng rằng các công ty công nghệ lớn làm việc chậm chạp và kém hiệu quả, nhưng Sean Goedecke giải thích rằng điều này có nguyên nhân sâu xa hơn nhiều so với những gì bề mặt có thể quan sát được.&lt;/p&gt;
&lt;p&gt;Thách thức chính trong các công ty công nghệ lớn không phải là kỹ sư kém cỏi hay lực lượng làm việc lười biếng, mà là sự gia tăng theo cấp số nhân của độ phức tạp tính năng. Khi số lượng tính năng tăng lên, các tương tác tiềm tăng giữa chúng tăng theo cấp số nhân. Mỗi tính năng mới phải được cân nhắc kỹ lưỡng so với các tính năng hiện tại, và &amp;ldquo;các tính năng có thể cản trở lẫn nhau theo nhiều cách khác nhau&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Tải trọng nhận thức mà các kỹ sư phải đối mặt là rất lớn - họ phải liên tục xem xét các tương tác phức tạp giữa các tính năng, dẫn đến tình huống &amp;ldquo;việc hoàn thành bất kỳ thứ gì đều thực sự rất, rất khó&amp;rdquo;. Đây không phải là dấu hiệu của sự không hiệu quả mà là kết quả của việc quản lý cẩn thận các hệ sinh thái công nghệ ngày càng phức tạp.&lt;/p&gt;
&lt;p&gt;Lý do kinh tế cũng đóng vai trò quan trọng: các tính năng biên có thể tạo ra doanh thu đáng kể. &amp;ldquo;1% doanh thu của Google Ads hoặc AWS S3 là một số tiền lớn&amp;rdquo;, vì vậy các công ty được khời gợi để thêm độ phức tạp nhằm tối đa hóa lợi nhuận tài chính. Điều này tạo ra một chu kỳ mà độ phức tạp tiếp tục gia tăng, và sự chậm chạp cảm nhận được thực chất là việc điều hướng chiến lược trong bối cảnh công nghệ phức tạp với mức độ rủi ro kinh tế đáng kể.&lt;/p&gt;</description></item><item><title>Newsletter #32</title><link>https://miti99.com/post/2025/07/21/</link><pubDate>Mon, 21 Jul 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/07/21/</guid><description>&lt;p&gt;&lt;em&gt;Đã lâu rồi mình không viết bài. Và thú thật thì những newsletter dạo trước hơi kiểu &amp;ldquo;chạy KPI&amp;rdquo;, mình cứ cố cho rất nhiều link vào và để AI Agent làm nốt phần còn lại. Lần này mình sẽ chọn lọc bài kĩ hơn, còn viết thì vẫn để AI thôi, vì mình lười hehe =))). Mong các bạn sẽ thích. Chào mừng bạn đến với Newsletter #31.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="claude-code-best-practices-for-agentic-coding"&gt;&lt;a class="link" href="https://www.anthropic.com/engineering/claude-code-best-practices" target="_blank" rel="noopener"
&gt;Claude Code: Best Practices for Agentic Coding&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Anthropic vừa ra mắt hướng dẫn thực hành tốt nhất cho Claude Code - một công cụ command-line mạnh mẽ cho lập trình với sự hỗ trợ của AI. Đây là một dự án nghiên cứu linh hoạt và có thể tùy chỉnh cao, giúp các kỹ sư tích hợp AI vào quy trình phát triển phần mềm một cách hiệu quả.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tạo file &lt;code&gt;CLAUDE.md&lt;/code&gt; để hướng dẫn Claude về commands bash, style code, testing và setup môi trường phát triển&lt;/li&gt;
&lt;li&gt;Sử dụng Model Context Protocol (MCP) servers và custom slash commands để mở rộng khả năng của Claude&lt;/li&gt;
&lt;li&gt;Áp dụng quy trình &amp;ldquo;Explore, Plan, Code, Commit&amp;rdquo;: đọc hiểu code → lập kế hoạch chi tiết → implement → commit và tạo PR&lt;/li&gt;
&lt;li&gt;Hỗ trợ Test-Driven Development: viết test trước → confirm test fail → implement code → iterate&lt;/li&gt;
&lt;li&gt;Visual Design Iteration: chụp screenshot → cung cấp mockup → implement và iterate design&lt;/li&gt;
&lt;li&gt;Claude Code hỗ trợ nhiều chế độ từ coding cẩn thận từng bước đến &amp;ldquo;Safe YOLO mode&amp;rdquo; cho phát triển nhanh&lt;/li&gt;
&lt;li&gt;Tối ưu hóa hiệu suất bằng cách đưa ra hướng dẫn cụ thể, sử dụng hình ảnh tham khảo và điều chỉnh sớm khi cần&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="openai-windsurf-và-tương-lai-của-ai-workspaces"&gt;&lt;a class="link" href="https://www.subtle.so/openai-windsurf-and-the-future-of-ai-workspaces.html" target="_blank" rel="noopener"
&gt;OpenAI, Windsurf và tương lai của AI Workspaces&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Subtle.so phân tích tin đồn về việc OpenAI cân nhắc mua lại Windsurf với giá 3 tỷ USD, và ý nghĩa của thương vụ này đối với tương lai của các môi trường phát triển AI. Đây không chỉ là một thương vụ mua bán đơn thuần mà còn phản ánh xu hướng chuyển đổi từ các công cụ lập trình chuyên biệt sang nền tảng workspace thông minh toàn diện.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OpenAI đang xem xét mua lại Windsurf với mức giá 3 tỷ USD, thể hiện tầm quan trọng chiến lược của các môi trường phát triển AI&lt;/li&gt;
&lt;li&gt;Tương lai của productivity tools sẽ là AI assistants có khả năng &amp;ldquo;tác động trực tiếp lên files và folders&amp;rdquo; với tính năng theo dõi phiên bản toàn diện&lt;/li&gt;
&lt;li&gt;Các công cụ như Windsurf đang mở rộng beyond coding: tích hợp AI agents, quản lý workspace đa chức năng, query phức tạp trên nhiều nguồn dữ liệu&lt;/li&gt;
&lt;li&gt;Cạnh tranh gay gắt với Microsoft GitHub Copilot ra mắt chế độ agent mode, OpenAI đầu tư vào các startup cạnh tranh&lt;/li&gt;
&lt;li&gt;Xu hướng tương tự Slack transforming IRC: biến công cụ kỹ thuật chuyên biệt thành nền tảng productivity mainstream&lt;/li&gt;
&lt;li&gt;Giá trị chiến lược nằm ở việc thu thập dữ liệu tương tác người dùng để cải thiện AI models&lt;/li&gt;
&lt;li&gt;AI development environments đang phát triển thành intelligent workspaces có thể cách mạng hóa cách chúng ta tương tác với thông tin số&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="vibe-coding-is-not-an-excuse-for-low-quality-work"&gt;&lt;a class="link" href="https://addyo.substack.com/p/vibe-coding-is-not-an-excuse-for" target="_blank" rel="noopener"
&gt;Vibe Coding is Not an Excuse for Low-Quality Work&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Substack của tác giả Addyo thảo luận về xu hướng &amp;ldquo;vibe coding&amp;rdquo; - việc sử dụng AI để code nhanh và theo cảm tính. Tác giả lập luận rằng mặc dù AI hỗ trợ lập trình mang lại nhiều lợi ích, nhưng điều này không có nghĩa là chúng ta có thể bỏ qua các nguyên tắc kỹ thuật phần mềm cơ bản và chất lượng code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI coding giúp giảm rào cản cho lập trình viên mới, cho phép prototyping nhanh và giúp non-programmers tạo ra solutions tùy chỉnh&lt;/li&gt;
&lt;li&gt;Rủi ro của việc sử dụng AI code không kiểm soát: error handling kém, performance yếu, lỗ hổng bảo mật, cấu trúc logic dễ vỡ&lt;/li&gt;
&lt;li&gt;Cần đối xử với AI-generated code như công việc của một junior developer - luôn phải review và test kỹ lưỡng&lt;/li&gt;
&lt;li&gt;Duy trì sự giám sát của con người trong thiết kế và implementation, thiết lập coding standards rõ ràng&lt;/li&gt;
&lt;li&gt;Viết comprehensive tests và document AI-generated code cẩn thận&lt;/li&gt;
&lt;li&gt;Nguyên tắc cốt lõi: &amp;ldquo;Vibe coding không phải là lý do để làm việc chất lượng thấp&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Sử dụng AI như một công cụ tăng tốc, không phải thay thế cho chuyên môn kỹ thuật&lt;/li&gt;
&lt;li&gt;Giữ thái độ phê phán và tham gia tích cực trong quá trình coding, hiểu rằng AI chỉ là công cụ chứ không phải giải pháp hoàn hảo&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="event-hidden-architecture-tương-lai-của-web-development"&gt;&lt;a class="link" href="https://skiplabs.io/blog/event-hidden-arch" target="_blank" rel="noopener"
&gt;Event-Hidden Architecture: Tương lai của Web Development&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Skip Labs giới thiệu khái niệm &amp;ldquo;Event-Hidden Architecture&amp;rdquo; - một paradigm mới trong phát triển phần mềm nhằm vượt qua các thách thức của kiến trúc event-driven truyền thống. Thay vì buộc developers phải quản lý events phức tạp, kiến trúc này ẩn đi complexity và cung cấp trải nghiệm phát triển đơn giản hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Các vấn đề của event-driven systems truyền thống: multiple queues dễ fail, race conditions, buộc developers suy nghĩ asynchronously, troubleshooting khó khăn&lt;/li&gt;
&lt;li&gt;Ba công nghệ chính tạo nên Event-Hidden Architecture: Frontend frameworks (React, Redux), Durable Execution Systems (Temporal, Restate), Reactive Computation Frameworks (Skip)&lt;/li&gt;
&lt;li&gt;Nguyên tắc thiết kế chung: declarative developer experience, event-driven &amp;ldquo;under the covers&amp;rdquo;, asynchronous with synchronous-feeling interactions&lt;/li&gt;
&lt;li&gt;Quản lý state như first-class concern, hỗ trợ modular và incremental adoption&lt;/li&gt;
&lt;li&gt;Lợi ích chính: simplified engineering, improved transparency, better state handling, enhanced replayability, reduced infrastructure complexity&lt;/li&gt;
&lt;li&gt;Dự đoán của tác giả: &amp;ldquo;Event-hidden sẽ trở thành kiến trúc web app mặc định trong 10 năm tới&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Kiến trúc này đại diện cho một bước tiến quan trọng trong thiết kế distributed systems, đơn giản hóa phát triển mà vẫn duy trì scalability và performance&lt;/li&gt;
&lt;li&gt;Cho phép developers tập trung vào business logic thay vì phải lo về infrastructure complexity&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="lessons-from-distributed-systems"&gt;&lt;a class="link" href="https://www.16elt.com/2025/04/19/lessons-from-distributed-systems/" target="_blank" rel="noopener"
&gt;Lessons from Distributed Systems&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ 16elt.com chia sẻ những bài học thực tế từ việc xây dựng và vận hành distributed systems ở quy mô lớn. Tác giả tổng hợp những kinh nghiệm xương máu về các vấn đề thường gặp và cách giải quyết khi làm việc với hệ thống phân tán.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tách riêng cache clusters: tránh chia sẻ một cache cluster cho nhiều services vì workload nặng từ Service A có thể evict dữ liệu quan trọng của Service B, gây ra performance issues khó chẩn đoán&lt;/li&gt;
&lt;li&gt;Sử dụng message queues: queues giúp quản lý traffic spikes và service load, cung cấp buffering và resilience giữa các services như &amp;ldquo;một người trưởng thành có trách nhiệm&amp;rdquo; ngăn chặn service overload&lt;/li&gt;
&lt;li&gt;Đo lường end-to-end latency: không chỉ xem xét service response times mà còn cả &amp;ldquo;dequeue latency&amp;rdquo; - thời gian messages chờ trong queue trước khi được xử lý&lt;/li&gt;
&lt;li&gt;Design for failure: expect và plan cho network và service failures tiềm tàng, implement retry policies, circuit breakers, dead-letter queues cho failed messages&lt;/li&gt;
&lt;li&gt;Đảm bảo idempotency: assume message duplicates sẽ xảy ra, thiết kế hệ thống handle repeated events một cách graceful vì message queues guarantee &amp;lsquo;at least once&amp;rsquo; delivery&lt;/li&gt;
&lt;li&gt;Distributed systems đòi hỏi proactive design, robust monitoring và resilient architecture để quản lý complexity và potential failure points&lt;/li&gt;
&lt;li&gt;Monitoring và observability là chìa khóa để hiểu được hành vi thực của hệ thống trong production environment&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="better-error-handling-từ-trycatch-đến-modern-approaches"&gt;&lt;a class="link" href="https://meowbark.dev/Better-error-handling" target="_blank" rel="noopener"
&gt;Better Error Handling: Từ Try/Catch đến Modern Approaches&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ meowbark.dev khám phá các phương pháp xử lý lỗi hiện đại trong software development, từ traditional try/catch cho đến các kỹ thuật tiên tiến như Go-style error handling và monadic Result types. Tác giả phân tích ưu nhược điểm của từng approach và đưa ra khuyến nghị về cách chọn lựa phương pháp phù hợp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ba approaches chính cho error handling: traditional try/catch, Go-style return tuples, và monadic Result types&lt;/li&gt;
&lt;li&gt;Challenges của error handling truyền thống: thiếu type safety, unpredictable error control flow, limited type system integration&lt;/li&gt;
&lt;li&gt;Go-style approach: return errors như part của tuple, explicitly handle failure scenarios, cung cấp clear error context&lt;/li&gt;
&lt;li&gt;Monadic Result approach: treat errors as values, sử dụng container types như &lt;code&gt;Result&amp;lt;T,E&amp;gt;&lt;/code&gt;, enable functional-style error chaining&lt;/li&gt;
&lt;li&gt;Best practices quan trọng: phân biệt recoverable và unrecoverable errors, wrap external library errors sớm, sử dụng type-safe error handling mechanisms&lt;/li&gt;
&lt;li&gt;Cân nhắc performance và developer experience khi chọn strategy&lt;/li&gt;
&lt;li&gt;Recommended techniques: sử dụng libraries như &lt;code&gt;neverthrow&lt;/code&gt; cho robust error management, implement error mapping và transformation&lt;/li&gt;
&lt;li&gt;Tạo centralized error handling layers để quản lý lỗi một cách systematic&lt;/li&gt;
&lt;li&gt;Chọn error handling strategy cân bằng giữa type safety, readability, và team expertise&lt;/li&gt;
&lt;li&gt;Duy trì clear error communication và recovery mechanisms trong suốt application&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;</description></item><item><title>Newsletter #31</title><link>https://miti99.com/post/2025/05/18/</link><pubDate>Sun, 18 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/18/</guid><description>&lt;p&gt;&lt;em&gt;Chào mừng bạn đến với Newsletter #31.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="optimizing-our-e2e-pipeline"&gt;&lt;a class="link" href="https://slack.engineering/speedup-e2e-testing/" target="_blank" rel="noopener"
&gt;Optimizing Our E2E Pipeline&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ đội ngũ kỹ sư Slack chia sẻ cách họ tối ưu hóa quy trình kiểm thử end-to-end (E2E) bằng cách giảm thiểu việc build frontend không cần thiết. Giải pháp thông minh này đã giúp tiết kiệm đáng kể thời gian và tài nguyên.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Slack phát hiện ra rằng 50% các lần build frontend là không cần thiết vì không có thay đổi gì về mã nguồn frontend&lt;/li&gt;
&lt;li&gt;Họ đã xây dựng cơ chế tự động phát hiện thay đổi frontend sử dụng &lt;code&gt;git diff&lt;/code&gt; để quyết định có cần build lại hay không&lt;/li&gt;
&lt;li&gt;Khi không cần build mới, hệ thống sẽ sử dụng bản build sẵn có từ AWS S3 thông qua CDN nội bộ&lt;/li&gt;
&lt;li&gt;Kết quả ấn tượng: giảm 60% số lần build không cần thiết, tiết kiệm hàng trăm giờ mỗi tháng và giảm thiểu lưu trữ dư thừa&lt;/li&gt;
&lt;li&gt;Tổng thời gian build trung bình giảm từ 10 phút xuống còn 2 phút nhờ dự án này và các cải tiến trước đó&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="doordash"&gt;&lt;a class="link" href="https://careersatdoordash.com/blog/doordash-fast-travel-estimates/" target="_blank" rel="noopener"
&gt;DoorDash&amp;rsquo;s Fast Travel Estimates&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ DoorDash Careers Blog chia sẻ về cách công ty cải thiện độ chính xác của ước tính thời gian giao hàng thông qua việc áp dụng các kỹ thuật học máy tiên tiến. DoorDash đã phát triển một hệ thống mới để dự đoán thời gian di chuyển chính xác hơn, giúp cải thiện trải nghiệm của cả người giao hàng và khách hàng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DoorDash đã phát triển một mô hình học máy mới để dự đoán thời gian di chuyển chính xác hơn&lt;/li&gt;
&lt;li&gt;Hệ thống mới xem xét nhiều yếu tố như điều kiện giao thông, thời tiết, và các sự kiện đặc biệt&lt;/li&gt;
&lt;li&gt;Việc cải thiện độ chính xác của ước tính thời gian giúp tăng sự hài lòng của người giao hàng&lt;/li&gt;
&lt;li&gt;Khách hàng cũng được hưởng lợi từ việc nhận được thông tin thời gian giao hàng chính xác hơn&lt;/li&gt;
&lt;li&gt;Công nghệ này là một phần trong nỗ lực liên tục của DoorDash để cải thiện trải nghiệm giao hàng&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="tech-hiring-is-this-an-inflection-point"&gt;&lt;a class="link" href="https://blog.pragmaticengineer.com/tech-hiring-is-this-an-inflection-point/" target="_blank" rel="noopener"
&gt;Tech Hiring: Is This an Inflection Point?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ The Pragmatic Engineer phân tích những thay đổi đáng chú ý trong quy trình tuyển dụng công nghệ hiện nay. Mặc dù có vẻ như việc tuyển dụng kỹ sư đang trở nên dễ dàng hơn do ít doanh nghiệp đăng tuyển và nhiều ứng viên cạnh tranh, thực tế lại cho thấy điều ngược lại.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Các phương pháp tuyển dụng từ xa truyền thống không còn hiệu quả như trước đây&lt;/li&gt;
&lt;li&gt;Sự gia tăng của các ứng viên &amp;ldquo;giả mạo&amp;rdquo; và việc sử dụng công cụ AI trong quá trình phỏng vấn&lt;/li&gt;
&lt;li&gt;Nhiều công ty đang xem xét quay lại phỏng vấn trực tiếp để đảm bảo chất lượng tuyển dụng&lt;/li&gt;
&lt;li&gt;Các công ty đang tăng cường dựa vào giới thiệu từ nhân viên hiện tại&lt;/li&gt;
&lt;li&gt;Chi phí tuyển dụng qua LinkedIn đang tăng cao (5-20K USD/tháng/recruiter)&lt;/li&gt;
&lt;li&gt;Một số công ty đang thử nghiệm phương pháp &amp;ldquo;tuần thử việc&amp;rdquo; có trả lương&lt;/li&gt;
&lt;li&gt;Cần phải tái cấu trúc quy trình tuyển dụng từ xa trong thời đại AI&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="underusing-snapshot-testing"&gt;&lt;a class="link" href="https://matklad.github.io/2025/04/15/underusing-snapshot-testing.html" target="_blank" rel="noopener"
&gt;Underusing Snapshot Testing&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ blog của Aleksey Kladov (tác giả của Rust Analyzer) thảo luận về việc sử dụng snapshot testing một cách hiệu quả. Tác giả đề xuất một cách tiếp cận đơn giản nhưng mạnh mẽ để kiểm thử bằng cách so sánh kết quả đầu ra với giá trị đã biết trước được lưu trữ trong mã nguồn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Snapshot testing giúp phát triển phần mềm linh hoạt hơn bằng cách dễ dàng cập nhật các kiểm thử khi yêu cầu thay đổi&lt;/li&gt;
&lt;li&gt;Công cụ này đặc biệt hữu ích khi làm việc với các cấu trúc dữ liệu phức tạp&lt;/li&gt;
&lt;li&gt;Tác giả minh họa cách sử dụng snapshot testing để kiểm thử một hàm mã hóa hoán vị (permutation encoding)&lt;/li&gt;
&lt;li&gt;Phương pháp này giúp tiết kiệm thời gian debug bằng cách hiển thị kết quả trực tiếp trong mã nguồn&lt;/li&gt;
&lt;li&gt;Bài viết còn bao gồm một bài kiểm tra toàn diện để xác nhận tính chính xác của hàm mã hóa hoán vị&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="principles-for-coding-securely-with-llms"&gt;&lt;a class="link" href="https://www.seangoedecke.com/ai-security/" target="_blank" rel="noopener"
&gt;Principles for coding securely with LLMs&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ blog của Sean Goedecke đưa ra những nguyên tắc quan trọng để phát triển phần mềm an toàn khi làm việc với các mô hình ngôn ngữ lớn (LLMs). Tác giả chỉ ra rằng việc mã hóa an toàn với LLMs đòi hỏi một cách tiếp cận khác biệt so với lập trình truyền thống.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prompt injection là một rủi ro không thể tránh khỏi khi sử dụng LLMs, đòi hỏi việc xử lý đầu ra như dữ liệu không đáng tin cậy&lt;/li&gt;
&lt;li&gt;Các công cụ LLM cần được kiểm soát quyền truy cập như một API tiếp xúc với người dùng&lt;/li&gt;
&lt;li&gt;Máy chủ MCP (Model Context Protocol) có thể tiềm ẩn rủi ro về chuỗi cung ứng giống như các thư viện bên thứ ba&lt;/li&gt;
&lt;li&gt;Ngay cả khi được sử dụng đơn lẻ, LLMs vẫn có thể thực hiện những hành động không mong muốn hoặc nguy hiểm&lt;/li&gt;
&lt;li&gt;Các mô hình không được cân chỉnh tốt có thể chứa thông tin nhạy cảm hoặc hành động độc hại&lt;/li&gt;
&lt;li&gt;Các ứng dụng LLM dễ bị tấn công từ chối dễ dễch vụ (DoS) do tính chất tốn nhiều tài nguyên của chúng&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="how-i-don"&gt;&lt;a class="link" href="https://www.gleech.org/llms" target="_blank" rel="noopener"
&gt;How I don&amp;rsquo;t use LLMs&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ gleech.org chia sẻ góc nhìn cá nhân về cách tác giả sử dụng (và không sử dụng) các mô hình ngôn ngữ lớn (LLMs) trong công việc và cuộc sống. Tác giả trình bày lý do tại sao họ hạn chế sử dụng LLM và trong những trường hợp cụ thể nào chúng thực sự hữu ích.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tác giả thường xuyên thất vọng với những lỗi cơ bản mà LLMs mắc phải, dẫn đến việc hạn chế sử dụng chúng&lt;/li&gt;
&lt;li&gt;Một số lý do chính khiến tác giả ít dùng LLM: đã có kiến thức nền vững, cần độ chính xác cao, không thích văn phong được tạo ra bởi AI&lt;/li&gt;
&lt;li&gt;Các trường hợp hữu ích khi sử dụng LLM: tìm kiếm thông tin, gợi ý từ khóa tìm kiếm, giải thích từ viết tắt, định dạng dữ liệu&lt;/li&gt;
&lt;li&gt;Tác giả đặc biệt đánh giá cao khả năng hỗ trợ lập trình, đặc biệt với các thư viện ít quen thuộc&lt;/li&gt;
&lt;li&gt;Bài viết phản ánh một góc nhìn cân bằng về việc sử dụng LLM: công nhận tiềm năng nhưng cũng chỉ ra những hạn chế rõ ràng&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="how-senior-software-engineers-can-learn-from-junior-engineers"&gt;&lt;a class="link" href="https://www.infoq.com/news/2025/04/software-engineers-learning/" target="_blank" rel="noopener"
&gt;How Senior Software Engineers Can Learn from Junior Engineers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ InfoQ thảo luận về cách các kỹ sư phần mềm kỳ cựu có thể học hỏi từ những đồng nghiệp trẻ tuổi hơn. Theo Beth Anderson, một môi trường làm việc với sự phân cấp quá cứng nhắc có thể kìm hãm sự đổi mới và hạn chế sự hợp tác hiệu quả.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Các kỹ sư kỳ cựu nên tạo môi trường an toàn về tâm lý để đồng nghiệp trẻ có thể thoải mái đóng góp ý kiến&lt;/li&gt;
&lt;li&gt;Nhân viên trẻ thường có góc nhìn mới mẻ và kỹ năng cập nhật, đóng góp giá trị cho đội nhóm&lt;/li&gt;
&lt;li&gt;Việc lắng nghe tích cực và đánh giá cao ý kiến đóng góp của mọi người giúp xây dựng văn hóa làm việc tích cực&lt;/li&gt;
&lt;li&gt;Các kỹ sư kỳ cựu nên khuyến khích phản hồi ngược lại từ nhân viên trẻ để cải thiện cách giao tiếp&lt;/li&gt;
&lt;li&gt;Mỗi cá nhân dù ở cấp độ nào cũng có những hiểu biết độc đáo để chia sẻ&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="as-an-engineer-i"&gt;&lt;a class="link" href="https://shiftmag.dev/asking-questions-engineering-career-advice-4895/" target="_blank" rel="noopener"
&gt;As an engineer, I&amp;rsquo;d rather be called stupid than stay silent&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết trên ShiftMag chia sẻ góc nhìn chân thực về hành trình vượt qua hội chứng kẻ mạo danh (imposter syndrome) trong ngành công nghệ. Tác giả kể lại trải nghiệm cá nhân khi phải đối mặt với những tình huống không hiểu vấn đề nhưng ngại đặt câu hỏi vì sợ bị đánh giá là &amp;ldquo;ngu ngốc&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sợ bị coi là ngốc nghếch khiến nhiều kỹ sư ngại đặt câu hỏi, dẫn đến hiểu lầm và hiệu suất công việc kém&lt;/li&gt;
&lt;li&gt;Việc dũng cảm đặt câu hỏi &amp;ldquo;ngu ngốc&amp;rdquo; thực chất là chìa khóa để học hỏi và phát triển nghề nghiệp&lt;/li&gt;
&lt;li&gt;Môi trường làm việc lý tưởng là nơi mọi người được khuyến khích đặt câu hỏi mà không sợ bị phán xét&lt;/li&gt;
&lt;li&gt;Tác giả đã chuyển đổi từ vai trò Kỹ sư Hỗ trợ Khách hàng lên Kỹ sư Vận hành Đáng tin cậy nhờ dám đặt câu hỏi&lt;/li&gt;
&lt;li&gt;Văn hóa không đổ lỗi (blameless culture) giúp nhân viên cảm thấy an toàn khi đặt câu hỏi và thừa nhận điểm yếu&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;</description></item><item><title>Newsletter #30</title><link>https://miti99.com/post/2025/05/17/</link><pubDate>Sat, 17 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/17/</guid><description>&lt;p&gt;&lt;em&gt;Chào mừng bạn đến với Newsletter #30 - Tổng hợp tin tức công nghệ hôm nay.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="what-i"&gt;&lt;a class="link" href="https://muratbuffalo.blogspot.com/2025/04/what-id-do-as-college-freshman.html" target="_blank" rel="noopener"
&gt;What I&amp;rsquo;d do as a College Freshman in 2025&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Murat Demirbas đưa ra những lời khuyên quý giá cho sinh viên đại học năm nhất trong thời đại AI phát triển mạnh mẽ. Tác giả chia sẻ quan điểm rõ ràng về việc học Khoa học Máy tính và phát triển kỹ năng mềm trong bối cảnh công nghệ hiện đại.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Học Khoa học Máy tính vẫn là lựa chọn đúng đắn, bất chấp sự phát triển của AI&lt;/li&gt;
&lt;li&gt;Kỹ năng mềm như giao tiếp và quản lý ngày càng quan trọng&lt;/li&gt;
&lt;li&gt;Mỹ vẫn là điểm đến tốt nhất để phát triển sự nghiệp công nghệ&lt;/li&gt;
&lt;li&gt;Nên phát triển tư duy khởi nghiệp và khả năng thích ứng&lt;/li&gt;
&lt;li&gt;Xây dựng sự nghiệp là một cuộc chạy đường dài, cần kiên nhẫn và chiến lược&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="llms-are-weird-computers"&gt;&lt;a class="link" href="https://www.phillipcarter.dev/posts/llms-computers" target="_blank" rel="noopener"
&gt;LLMs Are Weird Computers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, Phillip Carter đưa ra một góc nhìn thú vị về mô hình ngôn ngữ lớn (LLMs) như một dạng &amp;ldquo;máy tính kỳ lạ&amp;rdquo; đảo ngược so với máy tính truyền thống. Ông gọi những chiếc máy tính chúng ta quen thuộc là &amp;ldquo;truyền thống&amp;rdquo; và LLMs là những cỗ máy &amp;ldquo;kỳ lạ&amp;rdquo; hoặc &amp;ldquo;đảo ngược&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LLMs hoạt động như một hình thức đảo ngược của máy tính truyền thống&lt;/li&gt;
&lt;li&gt;Trong khi máy tính truyền thống xử lý chính xác nhưng gặp khó khăn với sự mơ hồ, LLMs lại giỏi xử lý sự mơ hồ nhưng gặp khó khăn với độ chính xác&lt;/li&gt;
&lt;li&gt;Bài viết gợi ý cách nhìn nhận LLMs như một dạng máy tính mới với những đặc tính riêng biệt&lt;/li&gt;
&lt;li&gt;Cách tiếp cận này giúp hiểu rõ hơn về điểm mạnh và hạn chế của LLMs&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="every-caching-strategy-explained-in-5-minutes"&gt;&lt;a class="link" href="https://www.swequiz.com/blog/every-caching-strategy-explained-in-5-minutes" target="_blank" rel="noopener"
&gt;Every Caching Strategy Explained in 5 Minutes&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ SWE Quiz cung cấp cái nhìn tổng quan ngắn gọn về các chiến lược caching phổ biến trong phát triển phần mềm. Đây là kiến thức cơ bản nhưng vô cùng quan trọng để tối ưu hiệu năng ứng dụng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các chiến lược chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cache-Aside (Lazy Loading)&lt;/strong&gt;: Ứng dụng tự quản lý cache, kiểm tra cache trước khi truy vấn database. Phù hợp cho tải đọc nhiều và chấp nhận dữ liệu có thể lỗi thời trong thời gian ngắn.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read-Through&lt;/strong&gt;: Ứng dụng chỉ tương tác với cache, cache tự động tải dữ liệu từ database khi cần. Giúp đơn giản hóa code ứng dụng.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write-Through&lt;/strong&gt;: Ghi dữ liệu đồng thời vào cả cache và database. Đảm bảo tính nhất quán nhưng có thể làm chậm tốc độ ghi.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write-Behind (Write-Back)&lt;/strong&gt;: Chỉ ghi vào cache và đồng bộ bất đồng bộ với database sau. Tăng tốc độ ghi nhưng có nguy cơ mất dữ liệu nếu cache gặp sự cố.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write-Around&lt;/strong&gt;: Bỏ qua cache khi ghi, chỉ sử dụng cache cho đọc. Phù hợp cho dữ liệu ít khi được đọc sau khi ghi.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Việc lựa chọn chiến lược phụ thuộc vào yêu cầu cụ thể của ứng dụng về hiệu năng, tính nhất quán và khả năng chịu lỗi.&lt;/p&gt;
&lt;h2 id="những-tính-năng-javascript-mà-mọi-lập-trình-viên-nên-biết-năm-2025"&gt;&lt;a class="link" href="https://waspdev.com/articles/2025-04-06/features-that-every-js-developer-must-know-in-2025" target="_blank" rel="noopener"
&gt;Những tính năng JavaScript mà mọi lập trình viên nên biết năm 2025&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ WaspDev điểm qua những tính năng JavaScript hiện đại mà mọi lập trình viên nên nắm vững trong năm 2025, giúp code hiệu quả và hiệu suất cao hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các tính năng nổi bật:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Iterator Helpers&lt;/strong&gt;: Các phương thức mới như &lt;code&gt;drop()&lt;/code&gt;, &lt;code&gt;take()&lt;/code&gt;, &lt;code&gt;filter()&lt;/code&gt; cho phép xử lý dữ liệu lớn hiệu quả mà không cần tạo mảng trung gian&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Array at()&lt;/strong&gt;: Truy cập phần tử mảng với chỉ số âm, ví dụ &lt;code&gt;arr.at(-1)&lt;/code&gt; để lấy phần tử cuối cùng&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Promise.withResolvers()&lt;/strong&gt;: Cách đơn giản hơn để tạo Promise với &lt;code&gt;resolve&lt;/code&gt; và &lt;code&gt;reject&lt;/code&gt; bên ngoài&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Xử lý chuỗi mạnh mẽ&lt;/strong&gt;: Sử dụng callback với &lt;code&gt;replace()&lt;/code&gt; và &lt;code&gt;replaceAll()&lt;/code&gt; cho thay thế phức tạp&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hoán đổi biến dễ dàng&lt;/strong&gt;: Cú pháp &lt;code&gt;[a, b] = [b, a]&lt;/code&gt; thay vì dùng biến tạm&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sao chép đối tượng an toàn&lt;/strong&gt;: &lt;code&gt;structuredClone()&lt;/code&gt; thay thế cho &lt;code&gt;JSON.parse(JSON.stringify())&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tagged templates&lt;/strong&gt;: Xử lý template literals linh hoạt hơn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WeakMap/WeakSet&lt;/strong&gt;: Lưu trữ dữ liệu tạm thời, tự động giải phóng bộ nhớ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Các phép toán Set mới&lt;/strong&gt;: &lt;code&gt;union()&lt;/code&gt;, &lt;code&gt;intersection()&lt;/code&gt;, &lt;code&gt;difference()&lt;/code&gt; cho thao tác tập hợp&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Những tính năng này giúp code ngắn gọn, dễ đọc và hiệu suất cao hơn, đặc biệt khi làm việc với dữ liệu lớn.&lt;/p&gt;
&lt;h2 id="điều-gì-tạo-nên-trải-nghiệm-nhà-phát-triển-tuyệt-vời"&gt;&lt;a class="link" href="https://www.codesimplicity.com/post/what-makes-a-great-developer-experience/" target="_blank" rel="noopener"
&gt;Điều gì tạo nên trải nghiệm nhà phát triển tuyệt vời?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Max Kanat-Alexander, người có hơn 20 năm kinh nghiệm trong lĩnh vực trải nghiệm nhà phát triển (DX), chia sẻ những nguyên tắc cốt lõi để xây dựng trải nghiệm phát triển phần mềm hiệu quả.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các yếu tố chính của DX tốt:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Thời gian chu kỳ (Cycle Time)&lt;/strong&gt;: Tối ưu thời gian từ khi lập trình viên bắt đầu thực hiện ý định đến khi hoàn thành&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tập trung (Flow)&lt;/strong&gt;: Khả năng duy trì sự tập trung vào công việc mà không bị gián đoạn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tải nhận thức (Cognitive Load)&lt;/strong&gt;: Giảm thiểu kiến thức và quyết định cần thiết để hoàn thành công việc&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Thách thức chính trong cải thiện DX:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Hiểu đúng vấn đề cần giải quyết&lt;/li&gt;
&lt;li&gt;Quản lý thay đổi hiệu quả&lt;/li&gt;
&lt;li&gt;Cung cấp công cụ có đòn bẩy cao&lt;/li&gt;
&lt;li&gt;Biết cách nói &amp;ldquo;không&amp;rdquo; với các yêu cầu gây hại&lt;/li&gt;
&lt;li&gt;Đặt áp lực lên đúng người gây ra vấn đề&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết nhấn mạnh rằng phần khó khăn nhất của DX thường liên quan đến yếu tố con người chứ không phải kỹ thuật, và đưa ra cái nhìn tổng quan về cách các công ty công nghệ lớn như Google và LinkedIn tiếp cận vấn đề này.&lt;/p&gt;
&lt;h2 id="khi-cuộc-đời-cho-bạn-java"&gt;&lt;a class="link" href="https://oblac.rs/when-life-gives-you-java/" target="_blank" rel="noopener"
&gt;Khi Cuộc Đời Cho Bạn Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Oblac.rs chia sẻ những thực hành phát triển Java hiện đại, được áp dụng khi bạn không thể thoát khỏi Java nhưng vẫn muốn viết mã chất lượng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các nguyên tắc chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Đóng gói thông minh&lt;/strong&gt;: Sử dụng package-private là mặc định, chỉ public khi cần thiết&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bất biến là bạn&lt;/strong&gt;: Sử dụng &lt;code&gt;final&lt;/code&gt; cho 95% biến, hạn chế &lt;code&gt;null&lt;/code&gt; tối đa&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ưu tiên composition thay vì inheritance&lt;/strong&gt;: Tránh kế thừa trong code riêng&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tư duy hàm&lt;/strong&gt;: Mô hình hóa lớp như các hàm đơn lẻ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sử dụng sealed interface và record&lt;/strong&gt;: Để định nghĩa các kiểu dữ liệu đại số (ADT)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Không dùng ngoại lệ cho logic nghiệp vụ&lt;/strong&gt;: Chỉ dành ngoại lệ cho các lỗi runtime&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tác giả thừa nhận rằng cách tiếp cận này sẽ tạo ra nhiều lớp nhỏ hơn, nhưng đó là sự đánh đổi đáng giá để có được mã nguồn mô-đun hóa tốt hơn và ít bất ngờ hơn.&lt;/p&gt;
&lt;h2 id="chỉ-cần-đổ-vào-postgresql"&gt;&lt;a class="link" href="https://simonsafar.com/2025/throw_it_into_postgres/" target="_blank" rel="noopener"
&gt;Chỉ Cần Đổ Vào PostgreSQL&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Simon Safar thảo luận về cách sử dụng PostgreSQL như một công cụ linh hoạt để lưu trữ và truy vấn dữ liệu không cấu trúc, thay vì chỉ dùng cho dữ liệu có cấu trúc chặt chẽ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quan điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lựa chọn giữa cấu trúc và linh hoạt&lt;/strong&gt;: Thay vì ép dữ liệu vào schema cứng nhắc hoặc lưu dạng file thô, hãy tận dụng khả năng JSONB của PostgreSQL&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tốc độ và tiện lợi&lt;/strong&gt;: Sử dụng lệnh &lt;code&gt;COPY&lt;/code&gt; để import hàng trăm ngàn bản ghi chỉ trong vài chục giây&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Không cần quyết định trước&lt;/strong&gt;: Có thể thêm index và tối ưu sau khi đã có dữ liệu&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Ví dụ thực tế:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;IDE Java&lt;/strong&gt;: Xây dựng công cụ tìm kiếm và điều hướng code nhanh bằng cách lưu trữ thông tin từ class files&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ký tự Trung Quốc&lt;/strong&gt;: Lưu trữ và truy vấn hiệu quả hàng chục ngàn ký tự với dữ liệu SVG và từ điển&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dữ liệu cảm biến&lt;/strong&gt;: Lưu trữ và phân tích dữ liệu IoT từ MQTT server với JSONB&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết khuyến khích các nhà phát triển xem xét PostgreSQL như một giải pháp &amp;ldquo;đổ dữ liệu vào trước, tổ chức sau&amp;rdquo; thay vì cố gắng thiết kế schema hoàn hảo ngay từ đầu.&lt;/p&gt;
&lt;hr&gt;</description></item><item><title>Newsletter #29</title><link>https://miti99.com/post/2025/05/16/</link><pubDate>Fri, 16 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/16/</guid><description>&lt;p&gt;&lt;em&gt;Chào mừng bạn đến với Newsletter #29 - Tổng hợp tin tức công nghệ hôm nay.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="a-clean-approach-to-process-optimization"&gt;&lt;a class="link" href="https://queue.acm.org/detail.cfm?id=3722546" target="_blank" rel="noopener"
&gt;A Clean Approach to Process Optimization&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ những hiểu biết sâu sắc về tối ưu hóa quy trình thông qua một phép ẩn dụ đơn giản: cách tác giả tối ưu hóa quy trình rửa bát của mình. Tác giả Thomas A. Limoncelli đã áp dụng tư duy này vào việc tối ưu hóa quy trình onboard khách hàng mới tại công ty, giảm thời gian chờ đợi từ vài ngày xuống chỉ còn vài phút.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tối ưu hóa quy trình bằng cách tái cấu trúc thứ tự thực hiện công việc&lt;/strong&gt;, tương tự như việc tác giả cho bột giặt vào máy rửa bát ngay sau khi lấy bát đĩa sạch ra, thay vì chờ đến khi bắt đầu chu kỳ rửa mới.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chia quy trình thành hai giai đoạn: chậm và nhanh&lt;/strong&gt;. Giai đoạn chậm xử lý các tác vụ chung chung, có thể thực hiện trước khi có đơn đặt hàng. Giai đoạn nhanh xử lý các tùy chỉnh cụ thể sau khi có đơn hàng.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Giảm thiểu sự phức tạp&lt;/strong&gt; bằng cách xem xét lại các tác vụ tùy chọn, đôi khi phát hiện ra chúng không thực sự cần thiết hoặc có thể được thực hiện hiệu quả hơn.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ứng dụng rộng rãi&lt;/strong&gt; trong nhiều lĩnh vực, từ phát triển phần mềm đến sản xuất công nghiệp, giúp cải thiện hiệu suất và chất lượng sản phẩm/dịch vụ.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="microsoft"&gt;&lt;a class="link" href="https://www.gatesnotes.com/microsoft-original-source-code" target="_blank" rel="noopener"
&gt;Microsoft&amp;rsquo;s Original Source Code Released for 50th Anniversary&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Nhân kỷ niệm 50 năm thành lập Microsoft, Bill Gates đã chia sẻ mã nguồn gốc của Altair BASIC, chương trình đầu tiên được phát triển bởi Microsoft vào năm 1975. Đây là một phần trong cuốn hồi ký mới của ông có tựa đề &amp;ldquo;Source Code&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm nổi bật:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lịch sử ra đời&lt;/strong&gt;: Altair BASIC là sản phẩm đầu tiên của Microsoft, được viết bởi Bill Gates và Paul Allen cho máy tính Altair 8800, đánh dấu sự khởi đầu của kỷ nguyên máy tính cá nhân.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ý nghĩa lịch sử&lt;/strong&gt;: Mã nguồn này minh họa sự khác biệt lớn giữa lập trình ngày nay và những ngày đầu của ngành công nghiệp phần mềm.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Công bố đặc biệt&lt;/strong&gt;: Việc công bố mã nguồn đi kèm với cuốn hồi ký mới của Gates, kể lại những ngày đầu thành lập Microsoft và tầm nhìn về tương lai của công nghệ.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Giá trị giáo dục&lt;/strong&gt;: Mã nguồn này cung cấp cái nhìn quý giá về kỹ thuật lập trình thời kỳ đầu và cách các lập trình viên phải tối ưu hóa mã để chạy trên phần cứng hạn chế.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="no-code-is-dead-long-live-vibe-coding"&gt;&lt;a class="link" href="https://kenneth.io/post/no-code-is-dead-long-live-vibe-coding" target="_blank" rel="noopener"
&gt;No code is dead. Long live vibe coding&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong một bài viết gần đây, Kenneth Auchenberg đã đưa ra một tuyên bố đáng chú ý: &amp;ldquo;No-code đã chết. Chào mừng đến với kỷ nguyên của vibe coding&amp;rdquo;. Bài viết phân tích sự thay đổi trong cách chúng ta tiếp cận phát triển phần mềm trong kỷ nguyên AI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Những điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sự thất bại của No-code&lt;/strong&gt;: Dù được kỳ vọng sẽ cách mạng hóa việc tạo lập phần mềm, các nền tảng no-code đã không thể thay thế được lập trình truyền thống.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sự trỗi dậy của Vibe Coding&lt;/strong&gt;: Các công cụ mới như Bolt, Lovable, v0 đang chứng minh rằng việc tạo code từ ngôn ngữ tự nhiên không chỉ khả thi mà còn hiệu quả hơn.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Giao diện tự nhiên&lt;/strong&gt;: Ngôn ngữ tự nhiên đang tỏ ra mạnh mẽ hơn so với các trình soạn thảo kéo-thả WYSIWYG truyền thống.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tính mở và linh hoạt&lt;/strong&gt;: Khác với thế hệ trước như Webflow hay Retool, các công cụ mới tạo ra code thực tế, tuân thủ các tiêu chuẩn mở và có thể triển khai trên bất kỳ cơ sở hạ tầng nào.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết gợi mở về một tương lai nơi các lập trình viên có thể tận dụng sức mạnh của AI để tạo ra mã nguồn chất lượng cao một cách nhanh chóng, trong khi vẫn giữ được toàn quyền kiểm soát sản phẩm cuối cùng.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="simple-scalable-and-global-containers-are-coming-to-cloudflare-workers-in-june-2025"&gt;&lt;a class="link" href="https://blog.cloudflare.com/cloudflare-containers-coming-2025/" target="_blank" rel="noopener"
&gt;Simple, scalable, and global: Containers are coming to Cloudflare Workers in June 2025&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Cloudflare vừa công bố kế hoạch ra mắt dịch vụ Containers vào cuối tháng 6/2025, hứa hẹn mang đến một nền tảng đơn giản, có khả năng mở rộng và hoạt động toàn cầu.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Những điểm nổi bật:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tích hợp sâu với Workers&lt;/strong&gt;: Containers sẽ hoạt động song song với Cloudflare Workers, cho phép chạy các tác vụ phức tạp hơn như xử lý video, chạy mã do người dùng tạo ra, hoặc di chuyển ứng dụng từ các nền tảng đám mây khác.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kiến trúc độc đáo&lt;/strong&gt;: Sử dụng Durable Objects để tạo ra các kết nối riêng tư giữa các container với khả năng định tuyến lập trình được.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tự động mở rộng quy mô&lt;/strong&gt;: Hệ thống tự động điều chỉnh số lượng container dựa trên tải, đảm bảo hiệu suất tối ưu với chi phí thấp nhất.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mô hình giá linh hoạt&lt;/strong&gt;: Chỉ trả tiền cho thời gian container hoạt động thực tế, với mức giá cạnh tranh cho CPU, bộ nhớ và lưu trữ.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Điểm đặc biệt của Cloudflare Containers là khả năng kết hợp với Workers để tạo ra các kiến trúc ứng dụng linh hoạt, nơi Workers đóng vai trò như API Gateway, Service Mesh hoặc bộ điều phối (Orchestrator) cho các container.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-types-of-companies-you-can-work-for-and-what-they-do-for-your-career"&gt;&lt;a class="link" href="https://www.elenaverna.com/p/the-types-of-companies-you-can-work" target="_blank" rel="noopener"
&gt;The types of companies you can work for and what they do for your career&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Elena Verna đã chia sẻ một bài viết thú vị về 6 loại hình công ty phổ biến và cách chúng ảnh hưởng đến sự nghiệp của bạn. Đây là những thông tin hữu ích cho những ai đang cân nhắc về môi trường làm việc phù hợp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6 loại hình công ty chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kỳ lân (Unicorns)&lt;/strong&gt;: Các công ty khởi nghiệp tăng trưởng nhanh (100% mỗi năm), môi trường cường độ cao, phù hợp với người thích thử thách và có khả năng chịu áp lực.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tàu chở dầu (Tankers)&lt;/strong&gt;: Các tập đoàn lớn như Google, Microsoft với quy trình bài bản, phù hợp cho người mới bắt đầu nhưng có thể chậm thăng tiến.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Người khổng lồ đang suy thoái (Declining Giants)&lt;/strong&gt;: Các công ty từng thành công nhưng đang gặp khó khăn, cơ hội thăng tiến nhanh nhưng đòi hỏi kết quả rõ rệt.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chế độ sinh tồn (Survival Mode)&lt;/strong&gt;: Các startup giai đoạn đầu, nhiều rủi ro nhưng cơ hội học hỏi rộng, phù hợp với người thích mạo hiểm.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Công ty lối sống (Lifestyle Boats)&lt;/strong&gt;: Tập trung vào tăng trưởng bền vững, cân bằng giữa công việc và cuộc sống, phù hợp với người ưu tiên ổn định.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hướng tới xã hội (Social Good Seekers)&lt;/strong&gt;: Tập trung vào tác động xã hội, phù hợp với người coi trọng ý nghĩa công việc hơn thu nhập.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết cũng gợi ý các câu hỏi quan trọng khi đánh giá một công ty: quy mô nhân sự, tốc độ tăng trưởng doanh thu, và thời gian hoạt động trước khi cần gọi vốn tiếp theo.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="how-to-create-a-chain-reaction-of-good-habits"&gt;&lt;a class="link" href="https://jamesclear.com/domino-effect" target="_blank" rel="noopener"
&gt;How to Create a Chain Reaction of Good Habits&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;James Clear, tác giả cuốn sách nổi tiếng &amp;ldquo;Atomic Habits&amp;rdquo;, đã chia sẻ một bài viết sâu sắc về Hiệu Ứng Domino - cách một thay đổi nhỏ có thể tạo ra chuỗi phản ứng dây chuyền trong cuộc sống.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hiểu về Hiệu Ứng Domino&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khi bạn thay đổi một hành vi, nó sẽ kích hoạt một chuỗi phản ứng và gây ra sự thay đổi trong các hành vi liên quan.&lt;/li&gt;
&lt;li&gt;Ví dụ: Nghiên cứu từ Đại học Northwestern chỉ ra rằng khi mọi người giảm thời gian ngồi một chỗ, họ cũng tự động giảm lượng chất béo tiêu thụ.&lt;/li&gt;
&lt;li&gt;Điều này xảy ra vì các thói quen và thói quen hàng ngày của chúng ta có mối liên hệ mật thiết với nhau.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3 Nguyên Tắc Tạo Ra Hiệu Ứng Domino&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bắt đầu với điều bạn có động lực nhất&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chọn một hành vi nhỏ và thực hiện nó nhất quán.&lt;/li&gt;
&lt;li&gt;Điều này giúp bạn nhìn thấy mình có thể trở thành kiểu người như thế nào.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Duy trì đà tăng trưởng&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ngay lập tức chuyển sang nhiệm vụ tiếp theo mà bạn có động lực hoàn thành.&lt;/li&gt;
&lt;li&gt;Để động lực từ việc hoàn thành một nhiệm vụ đưa bạn đến hành vi tiếp theo.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chia nhỏ mục tiêu&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khi gặp khó khăn, hãy chia nhỏ mọi thứ thành những phần nhỏ hơn.&lt;/li&gt;
&lt;li&gt;Tập trung vào việc duy trì đà tăng trưởng hơn là kết quả ngay lập tức.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Tác động sâu sắc&lt;/strong&gt;
Hiệu Ứng Domino không chỉ tạo ra một chuỗi các hành vi mới mà còn có thể thay đổi niềm tin cá nhân. Khi từng con domino nhỏ đổ xuống, bạn bắt đầu tin vào những điều mới về bản thân và xây dựng các thói quen dựa trên bản sắc cá nhân.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-post-developer-era"&gt;&lt;a class="link" href="https://www.joshwcomeau.com/blog/the-post-developer-era/" target="_blank" rel="noopener"
&gt;The Post-Developer Era&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Josh W. Comeau, một nhà phát triển và nhà giáo dục công nghệ nổi tiếng, đã có bài phân tích sâu sắc về tác động của AI đối với ngành phát triển phần mềm sau hơn 2 năm kể khi ChatGPT ra mắt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hiện trạng thị trường việc làm&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nhiều công ty đã áp dụng AI vào quy trình phát triển, nhưng chưa thay thế được lập trình viên&lt;/li&gt;
&lt;li&gt;Google báo cáo 25% code được tạo bởi AI, nhưng vẫn cần lập trình viên để kiểm soát và chỉnh sửa&lt;/li&gt;
&lt;li&gt;Các công cụ tự động hóa như Devin chỉ hoàn thành được 3/20 nhiệm vụ được giao trong thử nghiệm thực tế&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Những thách thức của AI trong lập trình&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI thường &amp;ldquo;lạc đường&amp;rdquo; nếu không có sự giám sát của con người&lt;/li&gt;
&lt;li&gt;Khả năng xử lý các vấn đề phức tạp còn hạn chế&lt;/li&gt;
&lt;li&gt;Dễ tạo ra code phức tạp, khó bảo trì nếu không được kiểm soát chặt chẽ&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tương lai của nghề lập trình&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI sẽ trở thành công cụ hỗ trợ đắc lực thay vì thay thế lập trình viên&lt;/li&gt;
&lt;li&gt;Nhu cầu tuyển dụng vẫn cao, đặc biệt với các lập trình viên có kỹ năng sử dụng AI hiệu quả&lt;/li&gt;
&lt;li&gt;Thị trường việc làm đang dần phục hồi sau giai đoạn khó khăn&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Lời khuyên cho lập trình viên tương lai&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Xây dựng mạng lưới quan hệ trong ngành&lt;/li&gt;
&lt;li&gt;Tập trung vào việc tạo ra sản phẩm thực tế&lt;/li&gt;
&lt;li&gt;Học cách sử dụng AI như một công cụ hỗ trợ&lt;/li&gt;
&lt;li&gt;Phát triển kỹ năng giải quyết vấn đề và tư duy phản biện&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết kết luận rằng vẫn còn rất lâu nữa trước khi chúng ta chứng kiến sự kết thúc của nghề lập trình viên. Thay vào đó, AI sẽ giúp nâng cao năng suất và mở ra những cơ hội mới trong ngành.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="everything-wrong-with-model-context-protocol-mcp"&gt;&lt;a class="link" href="https://blog.sshh.io/p/everything-wrong-with-mcp" target="_blank" rel="noopener"
&gt;Everything Wrong With Model Context Protocol (MCP)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Shrivu Shankar đã có bài phân tích chi tiết về những thách thức và hạn chế của Model Context Protocol (MCP) - giao thức kết nối các công cụ bên thứ ba với các trợ lý AI như Claude và ChatGPT.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MCP là gì?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giao thức cho phép các công cụ bên thứ ba kết nối với các trợ lý AI&lt;/li&gt;
&lt;li&gt;Giúp người dùng dễ dàng thêm chức năng mới mà không cần phát triển từ đầu&lt;/li&gt;
&lt;li&gt;Được sử dụng trong các ứng dụng như Cursor IDE để cung cấp ngữ cảnh và tự động hóa tác vụ&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Những thách thức chính&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề bảo mật&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thiếu tiêu chuẩn xác thực rõ ràng trong các phiên bản đầu&lt;/li&gt;
&lt;li&gt;Mã độc có thể được thực thi thông qua các máy chủ MCP cục bộ&lt;/li&gt;
&lt;li&gt;Nhiều máy chủ MCP tin tưởng đầu vào mà không kiểm tra đầy đủ&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hạn chế về giao diện người dùng&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không có cơ chế đánh giá rủi ro cho các công cụ&lt;/li&gt;
&lt;li&gt;Thiếu kiểm soát chi phí khi xử lý dữ liệu lớn&lt;/li&gt;
&lt;li&gt;Chỉ hỗ trợ dữ liệu phi cấu trúc (văn bản, hình ảnh, âm thanh)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bảo mật mô hình ngôn ngữ&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dễ bị tấn công prompt injection&lt;/li&gt;
&lt;li&gt;Có thể bị lợi dụng để trích xuất dữ liệu nhạy cảm&lt;/li&gt;
&lt;li&gt;Khó kiểm soát những gì mô hình có thể truy cập&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hạn chế của mô hình ngôn ngữ&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khả năng xử lý tác vụ phức tạp còn hạn chế&lt;/li&gt;
&lt;li&gt;Dễ mắc lỗi khi xử lý các yêu cầu đặc thù&lt;/li&gt;
&lt;li&gt;Cần tùy chỉnh prompt cho từng công cụ cụ thể&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Kết luận&lt;/strong&gt;
Mặc dù MCP đã tạo ra một tiêu chuẩn quan trọng để kết nối các công cụ với AI, vẫn còn nhiều thách thức cần giải quyết, đặc biệt là về bảo mật và trải nghiệm người dùng. Sự phát triển trong tương lai sẽ cần tập trung vào việc cải thiện các khía cạnh này để đảm bảo tính hữu ích và an toàn của hệ sinh thái MCP.&lt;/p&gt;
&lt;hr&gt;</description></item><item><title>Newsletter #28</title><link>https://miti99.com/post/2025/05/15/</link><pubDate>Thu, 15 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/15/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #28.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="how-airbnb-measures-listing-lifetime-value"&gt;&lt;a class="link" href="https://medium.com/airbnb-engineering/how-airbnb-measures-listing-lifetime-value-a603bf05142c" target="_blank" rel="noopener"
&gt;How Airbnb Measures Listing Lifetime Value&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Airbnb Engineering chia sẻ cách họ đo lường và tính toán Giá Trị Vòng Đời Danh Sách (Listing Lifetime Value - LTV) - một chỉ số quan trọng để hiểu giá trị kinh tế dài hạn của mỗi danh sách trên nền tảng. Đây là một bài viết kỹ thuật chi tiết về cách xây dựng hệ thống đo lường các chỉ số phức tạp trong môi trường sản xuất quy mô lớn.&lt;/p&gt;
&lt;p&gt;Airbnb đã phát triển một khung làm việc toàn diện để đo lường LTV của các danh sách, bao gồm việc xử lý các thách thức như:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các thách thức chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tính toán giá trị dự đoán&lt;/strong&gt;: Làm thế nào để dự đoán giá trị vòng đời của một danh sách khi chưa biết được nó sẽ hoạt động trong bao lâu&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Xử lý dữ liệu thời gian thực&lt;/strong&gt;: Cập nhật chỉ số này khi có đặt chỗ mới, hủy bỏ, hay thay đổi giá&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tính toán trên quy mô lớn&lt;/strong&gt;: Xử lý hàng triệu danh sách với hàng tỷ điểm dữ liệu&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Kiến trúc kỹ thuật:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng đường ống dữ liệu để xử lý dữ liệu luồng&lt;/li&gt;
&lt;li&gt;Áp dụng mô hình học máy để dự đoán mẫu hành vi&lt;/li&gt;
&lt;li&gt;Triển khai chiến lược caching để đảm bảo hiệu suất&lt;/li&gt;
&lt;li&gt;Thiết kế hệ thống giám sát và cảnh báo cho chất lượng dữ liệu&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết cũng đề cập đến việc cân bằng giữa độ chính xác và chi phí tính toán, cách xử lý các trường hợp ngoại lệ, và làm thế nào để xác thực kết quả của mô hình trong môi trường thực tế.&lt;/p&gt;
&lt;h2 id="six-jdk-24-features-you-should-know-about"&gt;&lt;a class="link" href="https://foojay.io/today/six-jdk-24-features-you-should-know-about/" target="_blank" rel="noopener"
&gt;Six JDK 24 Features You Should Know About&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ foojay.io giới thiệu 6 tính năng quan trọng nhất trong JDK 24, phiên bản Java được phát hành vào tháng 3/2025 với tổng cộng 24 JEP (JDK Enhancement Proposals) - số lượng tính năng mới lớn nhất kể từ khi áp dụng lịch phát hành 6 tháng một lần.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các tính năng nổi bật:&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="1-jep-483-ahead-of-time-class-loading--linking"&gt;1. JEP 483: Ahead-of-time Class Loading &amp;amp; Linking
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Thuộc về Project Leyden nhằm giảm thời gian khởi động của các ứng dụng Java&lt;/li&gt;
&lt;li&gt;Cho phép các lớp được tải và liên kết sẵn khi JVM khởi động, tránh chi phí phụ của việc tải/xác minh/liên kết lặp đi lặp lại&lt;/li&gt;
&lt;li&gt;Cải thiện đáng kể thời gian khởi động ứng dụng&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-jep-485-stream-gatherers"&gt;2. JEP 485: Stream Gatherers
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Mở rộng Streams API với khả năng tạo các thao tác trung gian tùy chỉnh&lt;/li&gt;
&lt;li&gt;Tương tự như Collector interface cho các thao tác đầu cuối, Gatherer interface cho phép các nhà phát triển tạo các thao tác trung gian tùy chỉnh&lt;/li&gt;
&lt;li&gt;Tăng tính linh hoạt và khả năng tái sử dụng trong lập trình hàm&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-jep-491-synchronize-virtual-threads-without-pinning"&gt;3. JEP 491: Synchronize Virtual Threads Without Pinning
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Giải quyết giới hạn quan trọng của virtual threads khi sử dụng synchronized blocks/methods&lt;/li&gt;
&lt;li&gt;Trước đây, virtual threads sẽ &amp;ldquo;ghim&amp;rdquo; platform thread khi trong synchronized block, giờ monitor được liên kết với virtual thread thay vì platform thread&lt;/li&gt;
&lt;li&gt;Cải thiện đáng kể khả năng mở rộng của các ứng dụng sử dụng virtual threads&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-jep-486-permanently-disable-security-manager"&gt;4. JEP 486: Permanently Disable Security Manager
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Loại bỏ hoàn toàn Security Manager - tính năng đã bị loại bỏ dần từ JDK 17&lt;/li&gt;
&lt;li&gt;Mặc dù có vẻ giảm bảo mật, thực tế Security Manager đã lỗi thời và ít được sử dụng&lt;/li&gt;
&lt;li&gt;Các ứng dụng sử dụng tính năng này sẽ cần thay đổi kiến trúc để nâng cấp lên JDK 24&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="5-jep-498-warning-for-sunmiscunsafe-memory-access-methods"&gt;5. JEP 498: Warning for sun.misc.Unsafe Memory-Access Methods
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;JVM sẽ cảnh báo khi sử dụng các phương thức truy cập bộ nhớ trong sun.misc.Unsafe&lt;/li&gt;
&lt;li&gt;Khuyến khích chuyển sang sử dụng VarHandle API và Foreign Function &amp;amp; Memory API&lt;/li&gt;
&lt;li&gt;Tiếp tục quá trình đóng gói của các API nội bộ của JDK&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="6-jep-501-deprecate-32-bit-x86-port-for-removal"&gt;6. JEP 501: Deprecate 32-bit x86 Port for Removal
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Loại bỏ dần 32-bit x86 port trên Linux (Windows 32-bit đã bị gỡ bỏ từ JDK 21)&lt;/li&gt;
&lt;li&gt;Phản ánh thực tế là rất ít hệ thống vẫn chạy hệ điều hành 32-bit trong môi trường sản xuất hiện đại&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="javaone-2025-function-and-memory-access-in-pure-java"&gt;&lt;a class="link" href="https://www.infoq.com/news/2025/04/foreign-function-minborg/" target="_blank" rel="noopener"
&gt;JavaOne 2025: Function and Memory Access in Pure Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ InfoQ tóm tắt bài thuyết trình của Per-Åke Minborg tại JavaOne 2025 về Foreign Function &amp;amp; Memory API (FFM), một trong những tính năng quan trọng nhất được giới thiệu trong JDK 22. FFM API được phát triển dưới dự án Panama nhằm thay thế JNI (Java Native Interface) với cách tiếp cận hiện đại và an toàn hơn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề với JNI truyền thống:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mô hình lập trình ưu tiên native dễ bị lỗi với sự kết hợp giữa Java và C&lt;/li&gt;
&lt;li&gt;Chi phí bảo trì và triển khai cao&lt;/li&gt;
&lt;li&gt;Truyền dữ liệu đến/từ JNI phức tạp và kém hiệu quả&lt;/li&gt;
&lt;li&gt;Chỉ hỗ trợ các kiểu dữ liệu nguyên thủy và đối tượng Java&lt;/li&gt;
&lt;li&gt;Không có cách nào để giải phóng bộ nhớ một cách xác định&lt;/li&gt;
&lt;li&gt;Không gian địa chỉ bị giới hạn (~2GB)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Foreign Memory API - Giải pháp cho truy cập bộ nhớ:&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="memory-segments-và-arena"&gt;Memory Segments và Arena
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Giao diện &lt;code&gt;MemorySegment&lt;/code&gt; cung cấp quyền truy cập đến vùng bộ nhớ liên tục với địa chỉ 64-bit&lt;/li&gt;
&lt;li&gt;Kiểm soát thông qua Kích thước (bảo vệ khỏi truy cập ngoài giới hạn), Vòng đời (bảo vệ khỏi sử dụng sau khi giải phóng), và Giới hạn luồng&lt;/li&gt;
&lt;li&gt;Giao diện &lt;code&gt;Arena&lt;/code&gt; quản lý vòng đời của các phân đoạn bộ nhớ native với các loại:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Global&lt;/strong&gt;: vòng đời không giới hạn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto&lt;/strong&gt;: vòng đời được thu gom rác tự động&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Confined&lt;/strong&gt;: vòng đời bị giới hạn rõ ràng&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shared&lt;/strong&gt;: vòng đời bị giới hạn rõ ràng với truy cập đa luồng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="value-layouts-và-varhandle"&gt;Value Layouts và VarHandle
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Giao diện &lt;code&gt;ValueLayout&lt;/code&gt; mô hình hóa các giá trị của các kiểu dữ liệu cơ bản với 3 thuộc tính: Carrier Type, Endianness, Alignment&lt;/li&gt;
&lt;li&gt;Sử dụng để lấy các thể hiện &lt;code&gt;VarHandle&lt;/code&gt; từ &lt;code&gt;MemorySegment&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Giao diện &lt;code&gt;MemoryLayout&lt;/code&gt; mô tả nội dung phân đoạn bộ nhớ một cách có cấu trúc, giúp tránh tính toán offset thủ công&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Foreign Function API - Tương tác với thư viện native:&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="công-cụ-jextract"&gt;Công cụ jextract
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Công cụ tự động tạo các liên kết Java từ các header của thư viện native&lt;/li&gt;
&lt;li&gt;Xây dựng trên nền tảng FFM API, giúp tạo mã tự động thay vì viết mã thủ công&lt;/li&gt;
&lt;li&gt;Ví dụ: gọi hàm sắp xếp nhanh native trực tiếp từ mã Java&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Lợi ích của FFM API:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Truy cập an toàn và hiệu quả&lt;/strong&gt; đến bộ nhớ native với khả năng giải phóng xác định&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Truy cập trực tiếp và hiệu quả&lt;/strong&gt; đến các hàm native - 100% Java, không cần bảo trì mã native&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nền tảng cho Project Panama&lt;/strong&gt; khả năng tương tác với các công cụ như jextract để tạo layouts và handles&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Đây là bước tiến quan trọng trong việc hiện đại hóa khả năng tương tác native của Java, mang lại hiệu năng tốt hơn và trải nghiệm nhà phát triển được cải thiện đáng kể so với JNI truyền thống.&lt;/p&gt;
&lt;h2 id="ultimate-guide-to-project-reactor-thread-locals-and-context-propagation"&gt;&lt;a class="link" href="https://4comprehension.com/ultimate-guide-to-project-reactor-thread-locals-and-context-propagation/" target="_blank" rel="noopener"
&gt;Ultimate Guide to Project Reactor, Thread-Locals and Context Propagation&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết toàn diện từ 4comprehension.com giải thích chi tiết về một trong những thách thức phức tạp nhất khi làm việc với Project Reactor: truyền ngữ cảnh (context propagation) và biến cục bộ luồng (thread-local variables). Đây là vấn đề thường gặp trong lập trình phản ứng khi các tác vụ có thể &amp;ldquo;nhảy&amp;rdquo; giữa các luồng khác nhau, dẫn đến mất ngữ cảnh quan trọng.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề cốt lõi:&lt;/strong&gt;
Trong mô hình luồng truyền thống, các biến &lt;code&gt;ThreadLocal&lt;/code&gt; hoạt động như một &lt;code&gt;Map&amp;lt;Thread, Value&amp;gt;&lt;/code&gt; - mỗi luồng có kho lưu trữ riêng biệt. Tuy nhiên trong luồng phản ứng, việc thực thi có thể chuyển đổi giữa nhiều luồng thông qua các toán tử như &lt;code&gt;publishOn()&lt;/code&gt;, khiến các giá trị ThreadLocal bị mất.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Các giải pháp được trình bày:&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="1-reactors-context-api"&gt;1. Reactor&amp;rsquo;s Context API
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Sử dụng &lt;code&gt;contextWrite()&lt;/code&gt; để lưu trữ các giá trị ngữ cảnh&lt;/li&gt;
&lt;li&gt;Truy cập ngữ cảnh thông qua &lt;code&gt;Mono.deferContextual()&lt;/code&gt; trong &lt;code&gt;flatMap()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Ngữ cảnh được truyền tự động qua chuỗi phản ứng&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-tích-hợp-với-các-công-cụ-dựa-trên-threadlocal"&gt;2. Tích hợp với các công cụ dựa trên ThreadLocal
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Giải quyết vấn đề với ghi nhật ký Mapped Diagnostic Context (MDC)&lt;/li&gt;
&lt;li&gt;Sử dụng mẫu execute-around để khôi phục các giá trị ThreadLocal&lt;/li&gt;
&lt;li&gt;Tạo các phương thức tiện ích để giảm mã soạn sẵn&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-truy-cập-ngữ-cảnh-từ-doonnext"&gt;3. Truy cập ngữ cảnh từ &lt;code&gt;doOnNext()&lt;/code&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Sử dụng &lt;code&gt;doOnEach()&lt;/code&gt; thay vì &lt;code&gt;doOnNext()&lt;/code&gt; để truy cập ngữ cảnh&lt;/li&gt;
&lt;li&gt;Kiểm tra loại tín hiệu và trích xuất ngữ cảnh từ đối tượng &lt;code&gt;Signal&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Tạo các phương thức bao bọc cho mã sạch&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-truyền-ngữ-cảnh-tự-động"&gt;4. Truyền ngữ cảnh tự động
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Kích hoạt với &lt;code&gt;Hooks.enableAutomaticContextPropagation()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Đăng ký &lt;code&gt;ThreadLocalAccessor&lt;/code&gt; tùy chỉnh cho việc khôi phục tự động&lt;/li&gt;
&lt;li&gt;Đánh đổi giữa sự tiện lợi và chi phí hiệu năng&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Những điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Truyền ngữ cảnh là thách thức quan trọng trong lập trình phản ứng&lt;/li&gt;
&lt;li&gt;Nhiều cách tiếp cận tùy thuộc vào trường hợp sử dụng cụ thể&lt;/li&gt;
&lt;li&gt;Quản lý ngữ cảnh thủ công cho kiểm soát tốt hơn, cách tiếp cận tự động cho sự tiện lợi&lt;/li&gt;
&lt;li&gt;Cần phân tích cẩn thận để chọn cách tiếp cận phù hợp với yêu cầu hiệu năng&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="jdk-24-g1parallelserial-gc-changes"&gt;&lt;a class="link" href="https://tschatzl.github.io/2025/04/01/jdk24-g1-serial-parallel-gc-changes.html" target="_blank" rel="noopener"
&gt;JDK 24 G1/Parallel/Serial GC Changes&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Thomas Schatzl (Oracle) tổng hợp những thay đổi quan trọng trong các bộ thu gom rác của JDK 24. Mặc dù JDK 24 không có nhiều thay đổi đột phá trong lĩnh vực GC, nhưng có những cải tiến đáng chú ý và lộ trình hứa hẹn cho JDK 25.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Parallel GC:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Loại bỏ một số đồng bộ hóa không cần thiết trong vòng lặp di tản (JDK-8269870)&lt;/li&gt;
&lt;li&gt;Có thể giảm thời gian tạm dừng trong một số tình huống cụ thể&lt;/li&gt;
&lt;li&gt;Tập trung vào tối ưu hóa cho đường dẫn nóng trong quá trình thu gom rác&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Serial GC:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tiếp tục công việc dọn dẹp và tái cấu trúc nền tảng mã&lt;/li&gt;
&lt;li&gt;Cải thiện khả năng bảo trì và chất lượng mã&lt;/li&gt;
&lt;li&gt;Chuẩn bị cho những thay đổi lớn hơn trong tương lai&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;G1 GC - Những cải tiến quan trọng:&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="1-tối-ưu-hóa-giá-trị-dự-đoán-jdk-8343189"&gt;1. Tối ưu hóa giá trị dự đoán (JDK-8343189)
&lt;/h3&gt;&lt;p&gt;G1 sử dụng các dự đoán để đạt được mục tiêu thời gian tạm dừng, bao gồm chi phí của sao chép bộ nhớ và cập nhật tham chiếu. Trước đây, G1 sử dụng các giá trị được chuẩn bị sẵn được xác định từ lâu trên máy SPARC &amp;ldquo;lớn&amp;rdquo; và không được cập nhật. Những giá trị này rất bảo thủ, khiến G1 mất khoảng 30 lần thu gom rác để thích nghi với môi trường hiện tại.&lt;/p&gt;
&lt;p&gt;Thay đổi mới cho phép các giá trị thực tế ghi đè trực tiếp lên các giá trị dự đoán được chuẩn bị sẵn thay vì cộng dồn, giúp G1 thích nghi nhanh hơn với ứng dụng và môi trường. Sự đánh đổi là có thể có nhiều lần vượt quá thời gian tạm dừng trong những lần thu gom rác đầu tiên.&lt;/p&gt;
&lt;h3 id="2-tối-ưu-hóa-bộ-nhớ-tập-hợp-thế-hệ-trẻ-jdk-8336086"&gt;2. Tối ưu hóa bộ nhớ tập hợp thế hệ trẻ (JDK-8336086)
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;G1 giờ quản lý các tập hợp được ghi nhớ cho toàn bộ thế hệ trẻ như một đơn vị duy nhất&lt;/li&gt;
&lt;li&gt;Loại bỏ các bản sao và tiết kiệm bộ nhớ đáng kể&lt;/li&gt;
&lt;li&gt;Giảm số lượng mục trong tập hợp được ghi nhớ, từ đó giảm nhẹ thời gian tạm dừng thu gom rác&lt;/li&gt;
&lt;li&gt;Kế thừa ý tưởng từ JDK 23 với những cải tiến bổ sung&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Lộ trình JDK 25 - Những thay đổi lớn sắp tới:&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="cải-tổ-rào-chắn-ghi"&gt;Cải tổ rào chắn ghi
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Một trong những thay đổi lớn nhất từ trước đến nay trong tương tác giữa ứng dụng và G1&lt;/li&gt;
&lt;li&gt;Rào chắn ghi được thực thi cho mọi thao tác ghi tham chiếu có tác động lớn đến thông lượng ứng dụng&lt;/li&gt;
&lt;li&gt;Dự kiến cải thiện thông lượng lên đến 10%, thời gian tạm dừng ngắn hơn, tạo mã tốt hơn&lt;/li&gt;
&lt;li&gt;Đang được chuẩn bị thành JEP để tích hợp trong những tháng tới&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="hợp-nhất-tập-hợp-được-ghi-nhớ-của-thế-hệ-cũ-jdk-8343782"&gt;Hợp nhất tập hợp được ghi nhớ của thế hệ cũ (JDK-8343782)
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Mở rộng ý tưởng hợp nhất các tập hợp được ghi nhớ cho các vùng thế hệ cũ&lt;/li&gt;
&lt;li&gt;Tiết kiệm bộ nhớ native còn lớn hơn nữa&lt;/li&gt;
&lt;li&gt;Đã được tích hợp trong JDK 25&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Các thảo luận và dự án đang diễn ra:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Automatic Heap Sizing&lt;/strong&gt;: Dự án mang tính năng tương tự ZGC đến các bộ thu gom dừng-thế-giới (đóng góp từ Microsoft và Google)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;G1 as True Default Collector&lt;/strong&gt;: Thảo luận về việc làm G1 thành bộ thu gom mặc định thay vì Serial GC trong môi trường nhỏ, vì G1 đang cho thấy hiệu năng tương đương hoặc tốt hơn Serial GC trong hầu hết các chỉ số&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;JDK 24 tập trung vào cải tiến nền tảng và tối ưu hóa, đặt nền móng cho những đột phá lớn hơn trong JDK 25, đặc biệt là cải tổ rào chắn ghi hứa hẹn mang lại những cải thiện hiệu năng đáng kể.&lt;/p&gt;
&lt;h2 id="making-makefiles-for-fun-and-profit"&gt;&lt;a class="link" href="https://dev.to/aws/making-makefiles-for-fun-and-profit-kl6" target="_blank" rel="noopener"
&gt;Making Makefiles for fun and profit&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Chuyên gia Ủng hộ Nhà phát triển AWS Darko Mesaroš khám phá lại Makefiles - công cụ tự động hóa xây dựng 48 tuổi nhưng vẫn cực kỳ hữu ích trong quy trình làm việc phát triển hiện đại. Mặc dù Make được tạo ra từ năm 1976 để giải quyết vấn đề quên biên dịch các tệp trong quá trình phát triển, ngày nay nó có thể làm được nhiều hơn thế rất nhiều.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tại sao Makefiles vẫn phù hợp:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tự động hóa các tác vụ lặp đi lặp lại&lt;/strong&gt;: Thay vì nhớ các lệnh phức tạp, chỉ cần &lt;code&gt;make deploy&lt;/code&gt; hoặc &lt;code&gt;make clean&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quản lý phụ thuộc thông minh&lt;/strong&gt;: Chỉ xây dựng lại những phần thực sự cần thiết&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tiêu chuẩn hóa&lt;/strong&gt;: Tạo quy trình làm việc nhất quán cho nhóm phát triển&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tương thích đa nền tảng&lt;/strong&gt;: Hoạt động trên Unix, Linux, macOS và Windows&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Các trường hợp sử dụng thực tế được trình bày:&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="1-tự-động-hóa-terraform"&gt;1. Tự động hóa Terraform
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Tự động chuyển đổi môi trường và quản lý không gian làm việc&lt;/li&gt;
&lt;li&gt;Kiểm tra an toàn trước khi chạy &lt;code&gt;terraform destroy&lt;/code&gt; với cảnh báo đầy đủ&lt;/li&gt;
&lt;li&gt;Quản lý biến môi trường cho các đích triển khai khác nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-thiết-lập-môi-trường-phát-triển-cục-bộ"&gt;2. Thiết lập môi trường phát triển cục bộ
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Tự động khởi chạy container Docker cho các cơ sở dữ liệu (Postgres, Redis)&lt;/li&gt;
&lt;li&gt;Tạo mật khẩu động và tạo tệp môi trường&lt;/li&gt;
&lt;li&gt;Phát triển Cargo lambda với tiêm biến môi trường thích hợp&lt;/li&gt;
&lt;li&gt;Thiết lập bằng một lệnh cho các ngăn xếp phát triển phức tạp&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-dự-án-aws-cdk"&gt;3. Dự án AWS CDK
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Tự động hóa xây dựng đa ngôn ngữ (TypeScript + Rust)&lt;/li&gt;
&lt;li&gt;Các lệnh triển khai riêng biệt cho các ngăn xếp riêng lẻ so với triển khai hoàn chỉnh&lt;/li&gt;
&lt;li&gt;Môi trường kiểm thử cục bộ với tích hợp DynamoDB Local&lt;/li&gt;
&lt;li&gt;Các lệnh dọn dẹp toàn diện&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-triển-khai-trang-web-tĩnh"&gt;4. Triển khai trang web tĩnh
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Tự động tải lên S3 với các tiêu đề content-type thích hợp&lt;/li&gt;
&lt;li&gt;Kích hoạt triển khai AWS Amplify&lt;/li&gt;
&lt;li&gt;Phân giải ID tài nguyên AWS động&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cách tiếp cận hiện đại với sự hỗ trợ của AI:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Bài viết trình diễn cách sử dụng Amazon Q Developer CLI để tạo ra các Makefiles phức tạp mà không cần phải thành thạo cú pháp phức tạp của Make. Công cụ AI có thể:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tự động phát hiện cấu trúc dự án và tạo các mục tiêu thích hợp&lt;/li&gt;
&lt;li&gt;Phân giải ID tài nguyên động (như ID ứng dụng Amplify)&lt;/li&gt;
&lt;li&gt;Quản lý cấu hình đặc thù cho từng môi trường&lt;/li&gt;
&lt;li&gt;Triển khai các phương pháp tốt nhất cho các loại dự án khác nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Những điểm chính cho nhà phát triển:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Makefiles không chỉ dành cho lập trình C - chúng mạnh mẽ cho bất kỳ quy trình tự động hóa nào&lt;/li&gt;
&lt;li&gt;Các công cụ AI hiện đại giúp vượt qua đường cong học tập của cú pháp Make&lt;/li&gt;
&lt;li&gt;Đầu tư vào thiết lập Makefile mang lại lợi ích dài hạn trong năng suất của nhóm&lt;/li&gt;
&lt;li&gt;Luôn nhớ các mục tiêu &lt;code&gt;.PHONY&lt;/code&gt; để tránh xung đột với các tệp thực tế&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Đây là reminder tuyệt vời rằng sometimes old tools are still the best tools, đặc biệt khi được enhance bởi modern AI assistance để lower barrier to entry.&lt;/p&gt;
&lt;h2 id="improving-pinterest-search-relevance-using-large-language-models"&gt;&lt;a class="link" href="https://medium.com/pinterest-engineering/improving-pinterest-search-relevance-using-large-language-models-4cd938d4e892" target="_blank" rel="noopener"
&gt;Improving Pinterest Search Relevance Using Large Language Models&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Pinterest Engineering team chia sẻ về journey cải thiện search relevance trên platform bằng cách integrate Large Language Models vào search infrastructure. Đây là case study thực tế về việc apply LLMs trong production search systems quy mô lớn với hàng tỷ Pins và hàng triệu user queries mỗi ngày.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Challenges trong Pinterest Search:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Pinterest search có những đặc thù riêng biệt so với traditional text search engines. Users thường search bằng visual concepts, aesthetic preferences, và contextual intentions mà khó express bằng keywords đơn giản. Ví dụ, query &amp;ldquo;cozy living room&amp;rdquo; có thể có hàng trăm interpretations khác nhau về color schemes, furniture styles, và ambiance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LLM Integration Strategy:&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="1-query-understanding-enhancement"&gt;1. Query Understanding Enhancement
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Semantic Query Expansion&lt;/strong&gt;: LLMs giúp hiểu deeper intent đằng sau user queries, expanding &amp;ldquo;minimalist bedroom&amp;rdquo; thành related concepts như &amp;ldquo;clean lines&amp;rdquo;, &amp;ldquo;neutral colors&amp;rdquo;, &amp;ldquo;simple furniture&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contextual Interpretation&lt;/strong&gt;: Xử lý ambiguous queries bằng cách leverage user&amp;rsquo;s previous interactions và browsing history&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-modal Understanding&lt;/strong&gt;: Combine text queries với visual context để improve relevance&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-content-representation-improvement"&gt;2. Content Representation Improvement
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rich Pin Embeddings&lt;/strong&gt;: Generate comprehensive embeddings cho Pins bằng cách combine visual features với textual descriptions được enhance bởi LLMs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dynamic Content Tagging&lt;/strong&gt;: Automatically generate relevant tags và categories cho user-generated content&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quality Assessment&lt;/strong&gt;: Use LLMs để evaluate content quality và filter out low-relevance results&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-ranking-model-enhancement"&gt;3. Ranking Model Enhancement
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Feature Engineering&lt;/strong&gt;: LLMs generate additional features cho ranking models, including semantic similarity scores và content quality indicators&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-time Personalization&lt;/strong&gt;: Adapt search results based on user preferences được inferred từ LLM analysis&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Diversity Optimization&lt;/strong&gt;: Ensure search results maintain diversity while improving relevance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Implementation:&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="architecture-design"&gt;Architecture Design
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hybrid Approach&lt;/strong&gt;: Combine traditional search algorithms với LLM-powered enhancements&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability Considerations&lt;/strong&gt;: Efficient LLM inference để handle millions of queries per day&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Latency Optimization&lt;/strong&gt;: Balance between LLM processing time và user experience requirements&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="model-training-và-fine-tuning"&gt;Model Training và Fine-tuning
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Domain-specific Training&lt;/strong&gt;: Fine-tune LLMs trên Pinterest-specific data including user behavior patterns và content characteristics&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Continuous Learning&lt;/strong&gt;: Implement feedback loops để continuously improve model performance&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A/B Testing Framework&lt;/strong&gt;: Rigorous testing methodology để measure impact của LLM improvements&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Results và Impact:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Search Relevance Metrics&lt;/strong&gt;: Significant improvements trong click-through rates, user engagement, và search satisfaction scores&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User Experience&lt;/strong&gt;: Reduced search abandonment rates và increased time spent exploring search results&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Business Impact&lt;/strong&gt;: Improved user retention và increased platform engagement&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Key Learnings:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Model Complexity vs. Performance&lt;/strong&gt;: Finding right balance giữa model sophistication và practical implementation constraints&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Quality Importance&lt;/strong&gt;: High-quality training data crucial cho LLM effectiveness trong search applications&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Human-in-the-loop&lt;/strong&gt;: Importance của human evaluation và feedback trong LLM-powered search systems&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Iterative Improvement&lt;/strong&gt;: Search relevance improvement là continuous process requiring ongoing optimization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Đây là example tuyệt vời về cách major tech platforms leverage LLMs để solve real-world problems, demonstrating practical applications của AI trong improving user experience at scale.&lt;/p&gt;</description></item><item><title>Newsletter #27</title><link>https://miti99.com/post/2025/05/14/</link><pubDate>Wed, 14 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/14/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #27.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="heading"&gt;&lt;a class="link" href="https://blog.cloudflare.com/introducing-the-cloudflare-vite-plugin/" target="_blank" rel="noopener"
&gt;&amp;ldquo;Just use Vite&amp;rdquo;&amp;hellip; with the Workers runtime&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Cloudflare vừa công bố phiên bản 1.0 của Cloudflare Vite plugin, cùng với việc hỗ trợ chính thức cho React Router v7. Plugin này tích hợp Workers runtime trực tiếp vào Vite, một trong những build tools phổ biến nhất cho phát triển web hiện nay.&lt;/p&gt;
&lt;p&gt;Trước đây, Vite dev server luôn chạy server code trong Node.js, ngay cả khi bạn triển khai ứng dụng lên Cloudflare Workers. Với Environment API mới được giới thiệu trong Vite 6, code Worker của bạn giờ đây có thể chạy trong Cloudflare Workers runtime (workerd) nguyên bản. Điều này đảm bảo môi trường phát triển khớp tối đa với môi trường production.&lt;/p&gt;
&lt;p&gt;Vite 6 mang đến những thay đổi quan trọng nhất về kiến trúc kể từ khi ra đời, mở ra nhiều khả năng mới cho hệ sinh thái. Environment API là nền tảng cho phép Vite dev server tương tác với nhiều môi trường runtime tùy chỉnh khác nhau.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tích hợp trực tiếp Workers runtime vào Vite dev server&lt;/li&gt;
&lt;li&gt;Hỗ trợ chính thức cho React Router v7&lt;/li&gt;
&lt;li&gt;Environment API mới trong Vite 6 cho phép chạy server code trong các runtime khác nhau&lt;/li&gt;
&lt;li&gt;Quy trình phát triển khớp với môi trường production&lt;/li&gt;
&lt;li&gt;Dễ dàng tạo mới hoặc cập nhật dự án React SPA với Cloudflare Workers&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-best-programmers-i-know"&gt;&lt;a class="link" href="https://endler.dev/2025/best-programmers/" target="_blank" rel="noopener"
&gt;The Best Programmers I Know&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Matthias Endler chia sẻ những quan sát của mình về các đặc điểm chung của những lập trình viên xuất sắc nhất mà anh từng gặp. Bài viết này đặc biệt hữu ích cho những người mới bắt đầu sự nghiệp lập trình, giúp họ định hướng phát triển bản thân một cách hiệu quả.&lt;/p&gt;
&lt;p&gt;Theo quan sát của tác giả, những lập trình viên giỏi nhất thường có những đặc điểm sau: họ luôn đọc kỹ tài liệu tham khảo gốc thay vì dựa vào Stack Overflow hay AI, hiểu sâu về các công cụ họ sử dụng từ lịch sử, hiện tại đến giới hạn của chúng. Họ có khả năng đọc hiểu và phân tích thông báo lỗi một cách chi tiết, biết cách chia nhỏ vấn đề phức tạp thành những phần đơn giản hơn để giải quyết.&lt;/p&gt;
&lt;p&gt;Đặc biệt, những lập trình viên xuất sắc không ngại &amp;ldquo;làm bẩn tay&amp;rdquo; với code, luôn sẵn sàng giúp đỡ người khác, có khả năng viết lách tốt và không ngừng học hỏi. Họ thường duy trình việc học tập suốt đời, ngay cả khi đã có nhiều năm kinh nghiệm trong ngành.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đọc kỹ tài liệu tham khảo gốc thay vì phụ thuộc vào Stack Overflow hay AI&lt;/li&gt;
&lt;li&gt;Hiểu sâu về công cụ: lịch sử, hiện tại, giới hạn và hệ sinh thái&lt;/li&gt;
&lt;li&gt;Khả năng đọc hiểu và phân tích thông báo lỗi chi tiết&lt;/li&gt;
&lt;li&gt;Biết cách chia nhỏ vấn đề phức tạp&lt;/li&gt;
&lt;li&gt;Sẵn sàng &amp;ldquo;làm bẩn tay&amp;rdquo; với code và giúp đỡ người khác&lt;/li&gt;
&lt;li&gt;Có kỹ năng viết lách tốt&lt;/li&gt;
&lt;li&gt;Luôn duy trình việc học tập, ngay cả ở tuổi 60+&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="git-is-more-popular-than-linux-torvalds"&gt;&lt;a class="link" href="https://news.itsfoss.com/torvalds-on-git/" target="_blank" rel="noopener"
&gt;Git is More Popular than Linux: Torvalds&lt;/a&gt;
&lt;/h2&gt;&lt;h2 id="20-years-of-git-still-weird-still-wonderful"&gt;&lt;a class="link" href="https://blog.gitbutler.com/20-years-of-git/" target="_blank" rel="noopener"
&gt;20 years of Git. Still weird, still wonderful.&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Nhân dịp kỷ niệm 20 năm ngày Linus Torvalds thực hiện commit đầu tiên cho Git (7/4/2005), chúng ta cùng nhìn lại hành trình phát triển của hệ thống quản lý phiên bản đã thay đổi cách thức phát triển phầm mềm trên toàn thế giới &lt;mcreference link="https://github.blog/open-source/git/git-turns-20-a-qa-with-linus-torvalds/" index="1"&gt;1&lt;/mcreference&gt;.&lt;/p&gt;
&lt;p&gt;Git được phát triển trong hoàn cảnh đặc biệt khi dự án Linux kernel không thể tiếp tục sử dụng BitKeeper do vấn đề bản quyền. Mặc dù chỉ mất 10 ngày để viết phiên bản đầu tiên, Torvalds đã dành 4 tháng trước đó để suy nghĩ về thiết kế và giải pháp &lt;mcreference link="https://about.gitlab.com/blog/2025/04/07/celebrating-gits-20th-anniversary-with-creator-linus-torvalds/" index="2"&gt;2&lt;/mcreference&gt;. Ban đầu, Git chỉ được xem như một giải pháp thay thế tạm thời, nhưng đã nhanh chóng phát triển thành công cụ quản lý mã nguồn phổ biến nhất trong lịch sử.&lt;/p&gt;
&lt;p&gt;Điều thú vị là Torvalds chỉ duy trì Git trong vài tháng đầu tiên trước khi chuyển giao cho Junio Hamano, người đã tham gia dự án ngay từ tuần đầu tiên và tiếp tục duy trì Git trong suốt 19 năm qua &lt;mcreference link="https://about.gitlab.com/blog/2025/04/14/journey-through-gits-20-year-history/" index="3"&gt;3&lt;/mcreference&gt;. Hiện nay, Git đã trở thành nền tảng cho sự phát triển của nhiều dịch vụ và công cụ quan trọng trong ngành công nghệ phần mềm.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phiên bản đầu tiên được phát triển trong 10 ngày nhưng có 4 tháng chuẩn bị về thiết kế&lt;/li&gt;
&lt;li&gt;Junio Hamano tiếp quản dự án sau vài tháng và duy trì trong 19 năm&lt;/li&gt;
&lt;li&gt;Git ban đầu chỉ là một &amp;ldquo;content tracker&amp;rdquo; đơn giản&lt;/li&gt;
&lt;li&gt;Thiết kế phi tập trung của Git đã tạo nên cuộc cách mạng trong phát triển phần mềm&lt;/li&gt;
&lt;li&gt;Torvalds vẫn thường xuyên sử dụng 5 lệnh Git cơ bản: merge, blame, log, commit và pull &lt;mcreference link="https://gigazine.net/gsc_news/en/20250408-git-20-years-linus-torvalds" index="4"&gt;4&lt;/mcreference&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="rdel-87-how-do-ai-coding-tools-actually-change-developer-work"&gt;&lt;a class="link" href="https://rdel.substack.com/p/rdel-87-how-do-ai-coding-tools-actually" target="_blank" rel="noopener"
&gt;RDEL #87: How do AI coding tools actually change developer work?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Một nghiên cứu thú vị từ Microsoft và Institute for Work Life về tác động của GitHub Copilot đối với công việc của các lập trình viên trong môi trường thực tế. Nghiên cứu được thực hiện trong 3 tuần với 228 kỹ sư tại một công ty phần mềm toàn cầu lớn, chia thành ba nhóm: nhóm mới được cấp quyền truy cập Copilot, nhóm không sử dụng công cụ AI, và nhóm đã đang sử dụng Copilot.&lt;/p&gt;
&lt;p&gt;Kết quả nghiên cứu cho thấy mặc dùng không có sự khác biệt đáng kể về các chỉ số như số dòng code hay số lượng PR giữa các nhóm, nhưng có những thay đổi tích cực về trải nghiệm làm việc. 84% người dùng cho biết Copilot đã thay đổi tích cực cách họ làm việc, với nhiều người báo cáo dành ít thời gian hơn cho các công việc nhàm chán và có nhiều năng lượng hơn trong công việc.&lt;/p&gt;
&lt;p&gt;Điều thú vị là các lập trình viên không chỉ sử dụng Copilot cho code mẫu, mà còn dùng nó thay thế cho việc tìm kiếm web và như một công cụ hỗ trợ tư duy tuy, thiết kế. Tuy nhiên, mức độ tin tưởng vào code được tạo ra vẫn không thay đổi, cho thấy các lập trình viên vẫn duy trình thái độ thận trọng với output của AI.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;86% người dùng có kinh nghiệm đồng ý rằng công cụ lập trình AI hữu ích&lt;/li&gt;
&lt;li&gt;84% báo cáo thay đổi tích cực trong cách làm việc&lt;/li&gt;
&lt;li&gt;Không có sự khác biệt đáng kể về các chỉ số telemetry&lt;/li&gt;
&lt;li&gt;Copilot được sử dụng cho cả việc tìm kiếm và thiết kế&lt;/li&gt;
&lt;li&gt;Mức độ tin tưởng vào code AI không tăng dù trải nghiệm tích cực&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="overclocking-dbt-discord"&gt;&lt;a class="link" href="https://discord.com/blog/overclocking-dbt-discords-custom-solution-in-processing-petabytes-of-data" target="_blank" rel="noopener"
&gt;Overclocking dbt: Discord&amp;rsquo;s Custom Solution in Processing Petabytes of Data&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Discord vừa chia sẻ về giải pháp tùy chỉnh của họ để mở rộng quy mô dbt (data build tool) nhằm xử lý hàng petabyte dữ liệu trong khi hỗ trợ hơn 100 lập trình viên làm việc đồng thời trên 2,500+ mô hình. Đây là một bài học quý giá về việc điều chỉnh và tối ưu hóa công cụ mã nguồn mở cho quy mô doanh nghiệp.&lt;/p&gt;
&lt;p&gt;Thách thức chính của Discord là thời gian biên dịch lại toàn bộ dự án dbt kéo dài hơn 20 phút, chiến lược materialization tăng dần mặc định không được tối ưu hóa cho khối lượng dữ liệu của họ, và các lập trình viên thường xuyên ghi đè lên các bảng kiểm thử của nhau. Để giải quyết vấn đề này, Discord đã phát triển một hệ thống dbt tùy chỉnh với các tính năng như tách biệt môi trường data warehouse và tự động hóa các quy trình phức tạp.&lt;/p&gt;
&lt;p&gt;Một trong những giải pháp quan trọng là việc tùy chỉnh macro generate_alias_name để tự động thêm định danh riêng cho từng lập trình viên dựa trên môi trường thực thi, cho phép nhiều người làm việc trên cùng một mô hình mà không ảnh hưởng lẫn nhau.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mở rộng quy mô dbt để xử lý petabyte dữ liệu&lt;/li&gt;
&lt;li&gt;Hỗ trợ hơn 100 lập trình viên làm việc đồng thời&lt;/li&gt;
&lt;li&gt;Tùy chỉnh macro để tách biệt môi trường phát triển&lt;/li&gt;
&lt;li&gt;Tối ưu hóa thời gian biên dịch và chiến lược materialization&lt;/li&gt;
&lt;li&gt;Giải pháp có thể áp dụng cho nhiều nền tảng cloud khác nhau&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Newsletter #26</title><link>https://miti99.com/post/2025/05/13/</link><pubDate>Tue, 13 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/13/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #26.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="the-philosophy-of-software-design--with-john-ousterhout"&gt;&lt;a class="link" href="https://newsletter.pragmaticengineer.com/p/the-philosophy-of-software-design" target="_blank" rel="noopener"
&gt;The Philosophy of Software Design – with John Ousterhout&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, Giáo sư John Ousterhout từ Stanford chia sẻ những quan điểm sâu sắc về tầm quan trọng của thiết kế phần mềm trong kỷ nguyên AI. Ông cho rằng việc thiết kế phần mềm tốt thậm chí còn quan trọng hơn khi các công cụ AI ngày càng phát triển.&lt;/p&gt;
&lt;h3 id="những-điểm-chính"&gt;Những điểm chính:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tầm quan trọng của thiết kế phần mềm trong kỷ nguyên AI&lt;/strong&gt;: Các công cụ AI hiện tại giống như &amp;ldquo;cơn lốc chiến thuật&amp;rdquo; - tạo code nhanh nhưng có thể tạo ra nhiều vấn đề mới và nợ kỹ thuật. Thiết kế phần mềm cấp cao vẫn là yếu tố không thể thay thế.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thiết kế phần mềm là vấn đề phân rã&lt;/strong&gt;: Cách chia nhỏ một hệ thống lớn thành các đơn vị nhỏ hơn để có thể triển khai độc lập. Đây là ý tưởng quan trọng nhất trong khoa học máy tính.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phương pháp &amp;ldquo;Thiết kế hai lần&amp;rdquo;&lt;/strong&gt;: John ủng hộ việc thiết kế hai lần cho mỗi vấn đề, vì thiết kế thứ hai thường tốt hơn. Ví dụ điển hình là khi ông thiết kế API cho Tk Toolkit.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quan điểm về TDD và Clean Code&lt;/strong&gt;: John có những quan điểm khác biệt với Robert Martin về các phương pháp ngắn và TDD. Ông cho rằng việc chia nhỏ quá mức có thể làm tăng độ phức tạp của giao diện và giảm khả năng hiểu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tầm quan trọng của comments&lt;/strong&gt;: Khác với quan điểm trong Clean Code, John ủng hộ việc sử dụng comments để giải thích cách sử dụng module và mục đích của các biến thành viên.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ứng-dụng-thực-tế"&gt;Ứng dụng thực tế:
&lt;/h3&gt;&lt;p&gt;John hiện đang đóng góp vào Linux Kernel, triển khai Homa Transport Protocol - một giao thức mới được phát minh bởi một trong những nghiên cứu sinh tiến sĩ của ông. Đây là một ví dụ thực tế về việc áp dụng các nguyên tắc thiết kế phần mềm vào các dự án thực tế.&lt;/p&gt;
&lt;h3 id="kết-luận"&gt;Kết luận:
&lt;/h3&gt;&lt;p&gt;Thiết kế phần mềm vẫn là một kỹ năng quan trọng và không thể thay thế, ngay cả trong kỷ nguyên AI. Việc hiểu và áp dụng các nguyên tắc thiết kế tốt sẽ giúp tạo ra các hệ thống phần mềm bền vững và dễ bảo trì hơn.&lt;/p&gt;
&lt;h2 id="20-years-of-git-still-weird-still-wonderful"&gt;&lt;a class="link" href="https://blog.gitbutler.com/20-years-of-git" target="_blank" rel="noopener"
&gt;20 years of Git. Still weird, still wonderful&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, Scott Chacon - đồng sáng lập GitHub và GitButler - chia sẻ câu chuyện thú vị về 20 năm phát triển của Git, từ một công cụ quản lý nội dung đơn giản trở thành hệ thống quản lý phiên bản phổ biến nhất thế giới.&lt;/p&gt;
&lt;h3 id="những-điểm-chính-1"&gt;Những điểm chính:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nguồn gốc của Git&lt;/strong&gt;: Git được tạo ra từ sự thất vọng của cộng đồng phát triển Linux kernel với các hệ thống quản lý phiên bản thời đó. Ban đầu, Git được thiết kế như một công cụ quản lý nội dung hiệu quả hơn cho quy trình làm việc với patches và tarballs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Commit đầu tiên&lt;/strong&gt;: Commit đầu tiên của Git chỉ bao gồm 7 công cụ đơn giản, độc lập. Các lệnh này rất cơ bản như &lt;code&gt;write-tree&lt;/code&gt; và &lt;code&gt;commit-tree&lt;/code&gt;, khác xa với các lệnh Git hiện đại mà chúng ta sử dụng ngày nay.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sự phát triển của các lệnh Git&lt;/strong&gt;: Nhiều lệnh Git quen thuộc ngày nay bắt đầu chỉ là các script shell đơn giản. Ví dụ, lệnh &lt;code&gt;git log&lt;/code&gt; đầu tiên chỉ là một wrapper script gọi &lt;code&gt;git-rev-list --pretty&lt;/code&gt; và pipe kết quả qua pager.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nguồn gốc của &amp;ldquo;rebase&amp;rdquo;&lt;/strong&gt;: Lệnh rebase nổi tiếng được sinh ra từ một cuộc thảo luận về workflow giữa Junio và Linus vào tháng 6/2005, khi họ tìm cách cải thiện quy trình làm việc với patches.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Octocat và GitHub&lt;/strong&gt;: Từ &amp;ldquo;octopus&amp;rdquo; trong Git (chỉ merge commit với nhiều parent) đã truyền cảm hứng cho biểu tượng Octocat của GitHub. Tom Preston-Werner đã tìm kiếm hình ảnh clipart về &amp;ldquo;octopus&amp;rdquo; và chọn hình ảnh của Simon Oxley làm biểu tượng cho GitHub.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="tương-lai-của-git"&gt;Tương lai của Git:
&lt;/h3&gt;&lt;p&gt;Sau 20 năm, Git vẫn đang được sử dụng theo cách mà nó được thiết kế ban đầu - như một công cụ quản lý nội dung hiệu quả. GitButler, một công cụ hiện đại, vẫn sử dụng Git không chỉ để theo dõi thay đổi code mà còn để lưu trữ lịch sử dự án.&lt;/p&gt;
&lt;h3 id="kết-luận-1"&gt;Kết luận:
&lt;/h3&gt;&lt;p&gt;Git đã đi một chặng đường dài từ một dự án cá nhân đơn giản trở thành công cụ không thể thiếu trong phát triển phần mềm. Câu chuyện về sự phát triển của Git không chỉ là câu chuyện về một công cụ, mà còn là câu chuyện về cách một ý tưởng đơn giản có thể thay đổi hoàn toàn cách chúng ta làm việc với code.&lt;/p&gt;
&lt;h2 id="a-modest-critique-of-optional-handling"&gt;&lt;a class="link" href="https://mccue.dev/pages//4-5-25-optional-critique" target="_blank" rel="noopener"
&gt;A Modest Critique of Optional Handling&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, Ethan McCue đưa ra một phân tích sâu sắc về việc sử dụng &lt;code&gt;java.util.Optional&lt;/code&gt; trong Java, đặc biệt là những thách thức và hạn chế của nó trong thực tế.&lt;/p&gt;
&lt;h3 id="những-điểm-chính-2"&gt;Những điểm chính:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mục đích ban đầu của Optional&lt;/strong&gt;: Optional được thiết kế để giải quyết vấn đề với chuỗi các phương thức trong stream operations, không phải để thay thế hoàn toàn cho &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề với cách sử dụng hiện tại&lt;/strong&gt;: Nhiều lập trình viên đang sử dụng Optional như một cách để &amp;ldquo;giải quyết null&amp;rdquo;, dẫn đến code phức tạp và khó đọc hơn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hạn chế của Optional&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khó xử lý với checked exceptions&lt;/li&gt;
&lt;li&gt;Code trở nên phức tạp khi có nhiều Optional lồng nhau&lt;/li&gt;
&lt;li&gt;Khó khăn trong việc thay đổi biến local trong lambda&lt;/li&gt;
&lt;li&gt;Các công cụ phân tích tĩnh cần xử lý đặc biệt&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giải pháp đề xuất&lt;/strong&gt;: Thay vì sử dụng &lt;code&gt;.isPresent()&lt;/code&gt; và &lt;code&gt;.get()&lt;/code&gt;, tác giả đề xuất sử dụng &lt;code&gt;.orElse(null)&lt;/code&gt; và xử lý null theo cách thông thường. Cách này giúp:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Code dễ đọc và bảo trì hơn&lt;/li&gt;
&lt;li&gt;Xử lý checked exceptions dễ dàng hơn&lt;/li&gt;
&lt;li&gt;Làm việc với nhiều Optional đơn giản hơn&lt;/li&gt;
&lt;li&gt;Công cụ phân tích tĩnh có thể xử lý tốt hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ứng-dụng-thực-tế-1"&gt;Ứng dụng thực tế:
&lt;/h3&gt;&lt;p&gt;Tác giả cung cấp nhiều ví dụ cụ thể về cách chuyển đổi code từ cách sử dụng Optional truyền thống sang cách tiếp cận mới, cho thấy sự cải thiện rõ rệt về mặt khả năng đọc và bảo trì của code.&lt;/p&gt;
&lt;h3 id="kết-luận-2"&gt;Kết luận:
&lt;/h3&gt;&lt;p&gt;Mặc dù Optional là một tính năng hữu ích trong Java, nhưng việc sử dụng nó cần được cân nhắc kỹ lưỡng. Thay vì tuân theo các quy tắc cứng nhắc về việc &amp;ldquo;tránh .isPresent/.get&amp;rdquo;, các lập trình viên nên linh hoạt trong việc chọn cách tiếp cận phù hợp với từng tình huống cụ thể.&lt;/p&gt;
&lt;h2 id="project-loom-structured-concurrency-in-java"&gt;&lt;a class="link" href="https://rockthejvm.com/articles/structured-concurrency-in-java" target="_blank" rel="noopener"
&gt;Project Loom: Structured Concurrency in Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, Riccardo Cardin từ Rock the JVM chia sẻ một hướng dẫn chi tiết về Structured Concurrency trong Java, một tính năng mới được giới thiệu trong Project Loom.&lt;/p&gt;
&lt;h3 id="những-điểm-chính-3"&gt;Những điểm chính:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giới thiệu về Structured Concurrency&lt;/strong&gt;: Đây là một cách tiếp cận mới để quản lý đồng thời trong Java, giúp đơn giản hóa việc viết code đồng thời và tránh các vấn đề phổ biến như rò rỉ thread.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cấu hình Project&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yêu cầu Java 23 với preview features&lt;/li&gt;
&lt;li&gt;Cấu hình Maven để hỗ trợ structured concurrency&lt;/li&gt;
&lt;li&gt;Sử dụng SLF4J và Logback cho logging&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ví dụ thực tế&lt;/strong&gt;: Bài viết sử dụng một ví dụ về việc tương tác với GitHub API để minh họa:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lấy thông tin người dùng&lt;/li&gt;
&lt;li&gt;Lấy danh sách repository&lt;/li&gt;
&lt;li&gt;Xử lý đồng thời các request&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các tính năng chính&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quản lý mối quan hệ parent-child giữa các task&lt;/li&gt;
&lt;li&gt;Chính sách đồng bộ hóa (Synchronization Policies)&lt;/li&gt;
&lt;li&gt;Hủy task một cách an toàn&lt;/li&gt;
&lt;li&gt;Xử lý ngoại lệ trong môi trường đồng thời&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lợi ích&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Code dễ đọc và bảo trì hơn&lt;/li&gt;
&lt;li&gt;Giảm thiểu rò rỉ thread&lt;/li&gt;
&lt;li&gt;Quản lý tài nguyên hiệu quả hơn&lt;/li&gt;
&lt;li&gt;Tương thích với các thư viện hiện có&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ứng-dụng-thực-tế-2"&gt;Ứng dụng thực tế:
&lt;/h3&gt;&lt;p&gt;Tác giả cung cấp một ví dụ cụ thể về việc triển khai structured concurrency trong một ứng dụng thực tế, sử dụng GitHub API làm case study. Code mẫu minh họa cách:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thiết kế các interface phù hợp&lt;/li&gt;
&lt;li&gt;Xử lý đồng thời các request&lt;/li&gt;
&lt;li&gt;Quản lý lifecycle của các task&lt;/li&gt;
&lt;li&gt;Xử lý lỗi và timeout&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="kết-luận-3"&gt;Kết luận:
&lt;/h3&gt;&lt;p&gt;Structured Concurrency trong Project Loom đánh dấu một bước tiến quan trọng trong việc xử lý đồng thời trong Java. Tính năng này không chỉ giúp code dễ viết hơn mà còn an toàn hơn, giảm thiểu các vấn đề phổ biến trong lập trình đồng thời. Với việc được tích hợp vào Java 23, đây là thời điểm tốt để các developer bắt đầu tìm hiểu và áp dụng tính năng này vào các dự án của mình.&lt;/p&gt;
&lt;h2 id="go"&gt;&lt;a class="link" href="https://mccue.dev/pages/4-5-25-go-http-server" target="_blank" rel="noopener"
&gt;Go&amp;rsquo;s HTTP Server Patterns in Java 25&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, Ethan McCue chia sẻ cách triển khai các mẫu HTTP server giống Go trong Java 25, thông qua việc xây dựng một wiki server đơn giản.&lt;/p&gt;
&lt;h3 id="những-điểm-chính-4"&gt;Những điểm chính:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giới thiệu về jdk.httpserver&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Module mới trong Java cho phép tạo HTTP server đơn giản&lt;/li&gt;
&lt;li&gt;Tương tự như cách Go xử lý HTTP server&lt;/li&gt;
&lt;li&gt;Phù hợp cho phát triển và prototyping&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cấu trúc dữ liệu cơ bản&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng record để định nghĩa Page&lt;/li&gt;
&lt;li&gt;Hỗ trợ lưu và đọc dữ liệu từ file&lt;/li&gt;
&lt;li&gt;Xử lý encoding/decoding UTF-8&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xử lý HTTP Request&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Routing đơn giản với path-based handlers&lt;/li&gt;
&lt;li&gt;Hỗ trợ các phương thức HTTP cơ bản&lt;/li&gt;
&lt;li&gt;Xử lý form data và parameters&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Template Engine&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng JMustache cho template&lt;/li&gt;
&lt;li&gt;Tách biệt logic và giao diện&lt;/li&gt;
&lt;li&gt;Hỗ trợ layout linh hoạt&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các tính năng bảo mật&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xử lý path traversal&lt;/li&gt;
&lt;li&gt;Redirect cho trang không tồn tại&lt;/li&gt;
&lt;li&gt;Xử lý lỗi an toàn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ứng-dụng-thực-tế-3"&gt;Ứng dụng thực tế:
&lt;/h3&gt;&lt;p&gt;Tác giả minh họa việc xây dựng một wiki server với các chức năng:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xem trang (view)&lt;/li&gt;
&lt;li&gt;Chỉnh sửa trang (edit)&lt;/li&gt;
&lt;li&gt;Lưu trang (save)&lt;/li&gt;
&lt;li&gt;Xử lý template&lt;/li&gt;
&lt;li&gt;Redirect thông minh&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="kết-luận-4"&gt;Kết luận:
&lt;/h3&gt;&lt;p&gt;Mặc dù &lt;code&gt;jdk.httpserver&lt;/code&gt; được đánh dấu là &amp;ldquo;for development only&amp;rdquo;, nó cung cấp một cách tiếp cận đơn giản và hiệu quả để xây dựng HTTP server trong Java, tương tự như cách Go làm. Điều này mở ra khả năng phát triển nhanh các ứng dụng web đơn giản mà không cần đến các framework phức tạp. Tuy nhiên, cho môi trường production, tác giả khuyến nghị sử dụng các server chuyên nghiệp như Jetty.&lt;/p&gt;
&lt;h2 id="java-is-dying-and-it-paid-off-my-mortgage"&gt;&lt;a class="link" href="https://alyosha.net/posts/java-is-dying-and-it-paid-off-my-mortgage/" target="_blank" rel="noopener"
&gt;Java is dying and it paid off my mortgage&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, Alyosha chia sẻ một góc nhìn thú vị về sự nghiệp phát triển phần mềm với Java, dựa trên trải nghiệm cá nhân của anh từ việc chuyển đổi từ MERN stack sang Java.&lt;/p&gt;
&lt;h3 id="những-điểm-chính-5"&gt;Những điểm chính:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quan điểm về công nghệ &amp;ldquo;hot&amp;rdquo;&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ban đầu lo ngại về việc làm việc với Java vì ít được bàn luận trên mạng&lt;/li&gt;
&lt;li&gt;So sánh với JavaScript luôn có nhiều bài viết và thảo luận&lt;/li&gt;
&lt;li&gt;Nỗi sợ bị &amp;ldquo;kẹt&amp;rdquo; trong hệ sinh thái Java&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thực tế thị trường việc làm&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java vẫn đứng đầu về mức lương và phúc lợi&lt;/li&gt;
&lt;li&gt;Các công ty ổn định thường sử dụng Java&lt;/li&gt;
&lt;li&gt;Ít được bàn luận không đồng nghĩa với việc ít cơ hội&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Góc nhìn về công nghệ trưởng thành&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java đang ở giai đoạn của một công nghệ đã trưởng thành&lt;/li&gt;
&lt;li&gt;Sau 1-2 thập kỷ phát triển mạnh mẽ&lt;/li&gt;
&lt;li&gt;Vẫn duy trì vị thế quan trọng trong doanh nghiệp&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bài học về sự nghiệp&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không nên quá lo lắng về việc chọn công nghệ&lt;/li&gt;
&lt;li&gt;Các công nghệ &amp;ldquo;cũ&amp;rdquo; vẫn có thể mang lại thành công&lt;/li&gt;
&lt;li&gt;Tập trung vào việc giải quyết vấn đề thực tế&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ứng-dụng-thực-tế-4"&gt;Ứng dụng thực tế:
&lt;/h3&gt;&lt;p&gt;Tác giả chia sẻ câu chuyện cá nhân:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Từ lo lắng về tương lai nghề nghiệp&lt;/li&gt;
&lt;li&gt;Đến việc trở thành chủ nhà nhờ làm việc với Java&lt;/li&gt;
&lt;li&gt;Chứng minh rằng công nghệ &amp;ldquo;không hot&amp;rdquo; vẫn có thể mang lại thành công&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="kết-luận-5"&gt;Kết luận:
&lt;/h3&gt;&lt;p&gt;Bài viết đưa ra một góc nhìn mới về việc theo đuổi sự nghiệp trong lĩnh vực phát triển phần mềm. Thay vì chạy theo các xu hướng công nghệ mới, việc làm chủ các công nghệ đã trưởng thành như Java có thể mang lại sự ổn định và thành công lâu dài. Câu chuyện của tác giả là một minh chứng cho thấy đôi khi những lựa chọn &amp;ldquo;không phổ biến&amp;rdquo; lại có thể là lựa chọn tốt nhất cho sự nghiệp.&lt;/p&gt;
&lt;h2 id="refining-var-handles-in-valhalla"&gt;&lt;a class="link" href="https://cr.openjdk.org/~jrose/values/atomic-value-access-api.html" target="_blank" rel="noopener"
&gt;Refining var-handles in Valhalla&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, John Rose trình bày một phân tích sâu về việc cải tiến var-handles trong Project Valhalla, đặc biệt là về cách xử lý atomic value access trong Java.&lt;/p&gt;
&lt;h3 id="những-điểm-chính-6"&gt;Những điểm chính:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề với var-handles hiện tại&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cần đồng bộ hóa giữa interpreter, JIT và JNI&lt;/li&gt;
&lt;li&gt;Phải tuân thủ các quy tắc layout của biến&lt;/li&gt;
&lt;li&gt;Xử lý phức tạp với các loại layout khác nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các loại layout trong Valhalla&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;REFERENCE&lt;/code&gt;: Con trỏ quản lý (32 hoặc 64 bit, có thể null)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NON_ATOMIC_FLAT&lt;/code&gt;: Biến có nhiều trường con, thường lớn hơn 64 bit&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ATOMIC_FLAT&lt;/code&gt;: Biến đóng gói trong 64 bit, có thể có các trường con nhỏ&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NULLABLE_ATOMIC_FLAT&lt;/code&gt;: Tương tự ATOMIC_FLAT nhưng có thêm null flag&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NULLABLE_NON_ATOMIC_FLAT&lt;/code&gt;: Tương tự NON_ATOMIC_FLAT với null flag&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BUFFERED&lt;/code&gt;: Trường hợp đặc biệt cho giá trị read-only&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đề xuất cải tiến&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thêm các phương thức truy vấn mới:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;isFlat&lt;/code&gt;: Kiểm tra biến có được flatten hay không&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isConsistent&lt;/code&gt;: Kiểm tra tính atomic của biến&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isPortableAtomic&lt;/code&gt;: Kiểm tra khả năng hỗ trợ CAS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Thêm phương thức &lt;code&gt;copyConsistentValue&lt;/code&gt; để xử lý atomic operations&lt;/li&gt;
&lt;li&gt;Tách biệt logic xử lý field và memory transfer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lợi ích của cải tiến&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Code dễ hiểu và bảo trì hơn&lt;/li&gt;
&lt;li&gt;Tách biệt rõ ràng giữa các concerns&lt;/li&gt;
&lt;li&gt;Hỗ trợ tốt hơn cho GC&lt;/li&gt;
&lt;li&gt;Xử lý atomic operations an toàn hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ứng-dụng-thực-tế-5"&gt;Ứng dụng thực tế:
&lt;/h3&gt;&lt;p&gt;Tác giả cung cấp pseudocode chi tiết cho việc triển khai:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xử lý get/set value&lt;/li&gt;
&lt;li&gt;Quản lý buffer riêng tư&lt;/li&gt;
&lt;li&gt;Xử lý các trường con&lt;/li&gt;
&lt;li&gt;Đảm bảo tính atomic&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="kết-luận-6"&gt;Kết luận:
&lt;/h3&gt;&lt;p&gt;Việc cải tiến var-handles trong Valhalla là một bước quan trọng để hỗ trợ tốt hơn cho value types trong Java. Cách tiếp cận mới giúp đơn giản hóa việc xử lý atomic operations và cải thiện hiệu suất của ứng dụng. Tuy nhiên, đây là một API phức tạp và chỉ nên được sử dụng bởi các developer có kinh nghiệm.&lt;/p&gt;
&lt;h2 id="cấu-hình-domain-localhost-cho-ứng-dụng-local"&gt;&lt;a class="link" href="https://inclouds.space/localhost-domains" target="_blank" rel="noopener"
&gt;Cấu hình domain .localhost cho ứng dụng local&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, Charles Chamberlain chia sẻ một cách tiếp cận thú vị để cấu hình các domain tùy chỉnh cho các ứng dụng web chạy trên máy local, thay vì phải nhớ và gõ các port khác nhau.&lt;/p&gt;
&lt;h3 id="những-điểm-chính-7"&gt;Những điểm chính:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề cần giải quyết&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khó nhớ các port khác nhau cho các ứng dụng local&lt;/li&gt;
&lt;li&gt;Cần một cách đơn giản hơn để truy cập các ứng dụng&lt;/li&gt;
&lt;li&gt;Muốn có URL thân thiện với người dùng hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giải pháp đề xuất&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng domain .localhost tùy chỉnh&lt;/li&gt;
&lt;li&gt;Mỗi ứng dụng có một domain riêng&lt;/li&gt;
&lt;li&gt;Ví dụ: thay vì localhost:5050, sử dụng appname.localhost&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cách triển khai&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Cấu hình ứng dụng như một launchd daemon&lt;/li&gt;
&lt;li&gt;Thêm entry vào /etc/hosts để redirect về 127.0.0.1&lt;/li&gt;
&lt;li&gt;Sử dụng Caddy để:
&lt;ul&gt;
&lt;li&gt;Reverse proxy đến port tương ứng&lt;/li&gt;
&lt;li&gt;Cấu hình TLS internal&lt;/li&gt;
&lt;li&gt;Nén dữ liệu với gzip và zstd&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ví dụ cấu hình&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# /etc/hosts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1 inclouds.localhost
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Caddyfile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;inclouds.localhost &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; reverse_proxy localhost:5050
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tls internal
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; encode gzip zstd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ứng-dụng-thực-tế-6"&gt;Ứng dụng thực tế:
&lt;/h3&gt;&lt;p&gt;Tác giả đề xuất một số cải tiến trong tương lai:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tự động hóa quá trình cài đặt/gỡ bỏ domain&lt;/li&gt;
&lt;li&gt;Đơn giản hóa việc cấu hình&lt;/li&gt;
&lt;li&gt;Tích hợp với dnsmasq để quản lý DNS tốt hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="kết-luận-7"&gt;Kết luận:
&lt;/h3&gt;&lt;p&gt;Cách tiếp cận này mang lại nhiều lợi ích cho việc phát triển và kiểm thử ứng dụng web locally. Nó giúp đơn giản hóa việc truy cập các ứng dụng và tạo ra một môi trường phát triển chuyên nghiệp hơn. Mặc dù cần một số cấu hình ban đầu, nhưng lợi ích mang lại là đáng kể, đặc biệt khi làm việc với nhiều ứng dụng cùng lúc.&lt;/p&gt;
&lt;h2 id="ai-50-ai-agents-move-beyond-chat"&gt;&lt;a class="link" href="https://www.sequoiacap.com/article/ai-50-2025/" target="_blank" rel="noopener"
&gt;AI 50: AI Agents Move Beyond Chat&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://sequoiacap.com/wp-content/uploads/sites/6/2025/04/ai-50-2025.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Trong bài viết này, Konstantine Buhler từ Sequoia Capital phân tích xu hướng AI năm 2025, đặc biệt là sự chuyển đổi từ AI chỉ trả lời câu hỏi sang AI thực sự thực hiện công việc.&lt;/p&gt;
&lt;h3 id="những-điểm-chính-8"&gt;Những điểm chính:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sự chuyển đổi của AI&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Từ chatbot đơn thuần sang giải quyết toàn bộ quy trình&lt;/li&gt;
&lt;li&gt;Tập trung vào kết quả kinh doanh thực tế&lt;/li&gt;
&lt;li&gt;Ứng dụng AI vào các tác vụ phức tạp&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Công cụ doanh nghiệp dẫn đầu&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Harvey: Tự động hóa quy trình pháp lý&lt;/li&gt;
&lt;li&gt;Sierra: Cải thiện dịch vụ khách hàng&lt;/li&gt;
&lt;li&gt;Cursor: Hỗ trợ phát triển phần mềm nâng cao&lt;/li&gt;
&lt;li&gt;Tập trung vào giải quyết vấn đề thực tế&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sự phát triển của Robotics&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tích hợp transformer models với phần cứng&lt;/li&gt;
&lt;li&gt;Figure AI: Sản xuất robot humanoid&lt;/li&gt;
&lt;li&gt;Skild AI: Phát triển mô hình nền tảng cho robotics&lt;/li&gt;
&lt;li&gt;Cơ hội thị trường 50 nghìn tỷ USD&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;AI cho người dùng cuối&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chuyển từ chatbot sang ứng dụng thực tế&lt;/li&gt;
&lt;li&gt;Tự động hóa các tác vụ hàng ngày&lt;/li&gt;
&lt;li&gt;Quản lý lịch, đặt vé, tổ chức file&lt;/li&gt;
&lt;li&gt;Claude Code: Lập trình cho người dùng phổ thông&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ứng-dụng-thực-tế-7"&gt;Ứng dụng thực tế:
&lt;/h3&gt;&lt;p&gt;Các công ty trong danh sách AI 50 đã chứng minh:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI có thể xử lý khối lượng công việc lớn&lt;/li&gt;
&lt;li&gt;Tự động hóa các quy trình phức tạp&lt;/li&gt;
&lt;li&gt;Cải thiện hiệu suất doanh nghiệp&lt;/li&gt;
&lt;li&gt;Mở ra cơ hội mới cho người dùng&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="kết-luận-8"&gt;Kết luận:
&lt;/h3&gt;&lt;p&gt;Năm 2025 đánh dấu bước ngoặt quan trọng trong phát triển AI, chuyển từ công cụ trả lời sang công cụ hành động. Mặc dù vẫn còn thách thức về độ chính xác và bảo mật, nhưng xu hướng phát triển là không thể phủ nhận. Các tiến bộ trong doanh nghiệp sẽ dần lan tỏa sang đời sống hàng ngày, mở ra một kỷ nguyên mới cho AI trong năm 2026.&lt;/p&gt;
&lt;h2 id="vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/65279cf0-3266-445d-852b-a45d6ac9afa4_2250x2862.png"
loading="lazy"
alt="A Cheatsheet On OOP Design Patterns"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #25</title><link>https://miti99.com/post/2025/05/12/</link><pubDate>Mon, 12 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/12/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #25.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="the-13-software-engineering-laws"&gt;&lt;a class="link" href="https://newsletter.manager.dev/p/the-13-software-engineering-laws" target="_blank" rel="noopener"
&gt;The 13 software engineering laws&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết tổng hợp 13 định luật quan trọng trong phát triển phần mềm, giúp các kỹ sư và quản lý hiểu rõ hơn về cách làm việc hiệu quả trong ngành công nghiệp phần mềm.&lt;/p&gt;
&lt;h3 id="các-định-luật-nổi-bật"&gt;Các định luật nổi bật:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định luật Parkinson&lt;/strong&gt;: Công việc sẽ tự mở rộng để lấp đầy thời gian được phân bổ. Điều này giải thích tại sao các deadline thường bị trễ.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định luật Hofstadter&lt;/strong&gt;: Mọi thứ luôn mất nhiều thời gian hơn dự kiến, ngay cả khi bạn đã tính đến Định luật Hofstadter.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định luật Brooks&lt;/strong&gt;: Thêm người vào một dự án phần mềm đang chậm tiến độ sẽ chỉ làm chậm thêm dự án đó.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định luật Conway&lt;/strong&gt;: Các tổ chức thiết kế hệ thống giống với cấu trúc giao tiếp của chính họ.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định luật Cunningham&lt;/strong&gt;: Cách tốt nhất để có câu trả lời đúng trên Internet là đăng câu trả lời sai và chờ người khác sửa lại.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định luật Sturgeon&lt;/strong&gt;: 90% mọi thứ đều tệ hại.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định luật Zawinski&lt;/strong&gt;: Mọi chương trình đều cố gắng mở rộng cho đến khi nó có thể đọc email.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định luật Hyrum&lt;/strong&gt;: Với đủ số lượng người dùng, mọi hành vi quan sát được của hệ thống sẽ được ai đó phụ thuộc vào.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định luật Price&lt;/strong&gt;: 50% công việc được thực hiện bởi căn bậc hai của số lượng người tham gia.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hiệu ứng Ringelmann&lt;/strong&gt;: Các thành viên trong nhóm càng đông thì năng suất cá nhân càng giảm.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định luật Goodhart&lt;/strong&gt;: Khi một chỉ số trở thành mục tiêu, nó sẽ không còn là một chỉ số tốt nữa.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định luật Gilb&lt;/strong&gt;: Bất cứ thứ gì bạn cần định lượng đều có thể đo lường được theo cách nào đó tốt hơn là không đo lường gì cả.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định luật Murphy&lt;/strong&gt;: Nếu điều gì có thể xảy ra sai sót, nó chắc chắn sẽ xảy ra.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="bài-học-rút-ra"&gt;Bài học rút ra:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quản lý thời gian và nguồn lực&lt;/strong&gt;: Các định luật như Parkinson, Hofstadter và Brooks nhấn mạnh tầm quan trọng của việc ước lượng thời gian chính xác và quản lý nguồn lực hiệu quả.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thiết kế kiến trúc&lt;/strong&gt;: Định luật Conway và Zawinski chỉ ra mối quan hệ giữa cấu trúc tổ chức và thiết kế hệ thống.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Làm việc nhóm&lt;/strong&gt;: Định luật Price và hiệu ứng Ringelmann cho thấy những thách thức khi mở rộng quy mô nhóm.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đo lường hiệu suất&lt;/strong&gt;: Định luật Goodhart và Gilb nhắc nhở chúng ta về những hạn chế của các chỉ số đánh giá.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quản lý rủi ro&lt;/strong&gt;: Định luật Murphy nhắc nhở chúng ta luôn chuẩn bị cho những tình huống xấu nhất có thể xảy ra.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết cung cấp cái nhìn sâu sắc về những thách thức phổ biến trong phát triển phần mềm và cách các định luật này có thể giúp chúng ta hiểu rõ hơn về ngành công nghiệp phần mềm.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-curve-is-bending-predictions-on-near-term-ai-inference-spending"&gt;&lt;a class="link" href="https://grantslatton.com/the-curve-is-bending" target="_blank" rel="noopener"
&gt;The Curve is Bending: Predictions on near-term AI inference spending&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích về sự thay đổi đáng kể trong việc sử dụng AI cho phát triển phần mềm, đặc biệt là sự gia tăng chi tiêu cho AI inference (suy luận AI) trong lập trình chuyên nghiệp.&lt;/p&gt;
&lt;h3 id="những-điểm-chính"&gt;Những điểm chính:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bước ngoặt về tính hữu dụng&lt;/strong&gt;: Các mô hình AI hiện đã đạt đến mức độ hữu ích thực tế, nơi đầu ra tạo ra giá trị lớn hơn chi phí bỏ ra cho công việc phát triển.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sự phát triển của công cụ AI&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AI IDE&lt;/strong&gt;: Các trình soạn thảo mã nguồn tích hợp AI như Zed Editor giúp tăng tốc độ phát triển đáng kể&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;: Công cụ từ Anthropic cho phép AI làm việc trực tiếp với codebase&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microtools&lt;/strong&gt;: Các công cụ nhỏ thông minh được tạo ra để tự động hóa các tác vụ lặp đi lặp lại&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chi phí và hiệu quả&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chi phí sử dụng các mô hình AI tiên tiến đang tăng lên đáng kể (hàng nghìn đô la mỗi năm cho một developer)&lt;/li&gt;
&lt;li&gt;Tuy nhiên, hiệu suất tăng lên (ước tính 1.1x hiện tại, dự kiến 2-3x vào cuối năm 2026) khiến đây vẫn là khoản đầu tư xứng đáng&lt;/li&gt;
&lt;li&gt;Các công ty có thể sớm cấp ngân sách hàng chục nghìn đô la mỗi năm cho mỗi lập trình viên để sử dụng AI&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tương lai phát triển phần mềm&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sự xuất hiện của các mô hình mạnh hơn như o3-pro của OpenAI hứa hẹn cải thiện đáng kể năng suất&lt;/li&gt;
&lt;li&gt;Giá cả sẽ giảm dần khi công nghệ phát triển, giúp các mô hình mạnh trở nên phổ biến hơn&lt;/li&gt;
&lt;li&gt;Cách thức làm việc của lập trình viên sẽ thay đổi đáng kể, đặc biệt là với các công việc của junior developer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="tác-động-đến-thị-trường-lao-động"&gt;Tác động đến thị trường lao động:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Nhu cầu về junior developer có thể giảm khi AI đảm nhận nhiều công việc cơ bản hơn&lt;/li&gt;
&lt;li&gt;Các lập trình viên sẽ cần phát triển kỹ năng làm việc với AI và tập trung vào các khía cạnh sáng tạo, phức tạp hơn&lt;/li&gt;
&lt;li&gt;Các công ty có thể thuê ít người hơn nhưng sẵn sàng chi trả nhiều hơn cho những người có thể tận dụng hiệu quả AI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết cung cấp cái nhìn sâu sắc về cách AI đang thay đổi ngành công nghiệp phần mềm và những điều chúng ta có thể mong đợi trong tương lai gần.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="open-source-is-just-that-understanding-boundaries-in-open-source"&gt;&lt;a class="link" href="https://vale.rocks/posts/open-source-entitlement" target="_blank" rel="noopener"
&gt;Open-Source is Just That: Understanding Boundaries in Open Source&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết đề cập đến vấn đề phổ biến trong cộng đồng mã nguồn mở: sự tự cho mình quyền (entitlement) của người dùng đối với các nhà phát triển phần mềm tự nguyện.&lt;/p&gt;
&lt;h3 id="những-quan-niệm-sai-lầm-về-mã-nguồn-mở"&gt;Những quan niệm sai lầm về mã nguồn mở:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mã nguồn mở không đồng nghĩa với&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mở đóng góp từ cộng đồng&lt;/li&gt;
&lt;li&gt;Cung cấp hỗ trợ kỹ thuật&lt;/li&gt;
&lt;li&gt;Chấp nhận yêu cầu tính năng mới&lt;/li&gt;
&lt;li&gt;Nợ người dùng thời gian của họ&lt;/li&gt;
&lt;li&gt;Miễn phí và tự do sử dụng (FOSS)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giấy phép quan trọng&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mã nguồn mở không tự động có nghĩa là tự do sử dụng&lt;/li&gt;
&lt;li&gt;Mỗi dự án có giấy phép riêng với các điều khoản khác nhau&lt;/li&gt;
&lt;li&gt;Người dùng cần đọc và hiểu giấy phép trước khi sử dụng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="vấn-đề-đạo-đức-trong-cộng-đồng"&gt;Vấn đề đạo đức trong cộng đồng:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lạm dụng nhà phát triển&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nhiều người dùng có thái độ thù địch khi yêu cầu hỗ trợ&lt;/li&gt;
&lt;li&gt;Các công ty thường yêu cầu tính năng mới mà không đóng góp ngược lại&lt;/li&gt;
&lt;li&gt;Áp lực vô hình đè nặng lên các nhà phát triển tình nguyện&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cách tìm kiếm hỗ trợ đúng đắn&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tự nghiên cứu kỹ trước khi đặt câu hỏi&lt;/li&gt;
&lt;li&gt;Cung cấp đầy đủ thông tin khi báo cáo lỗi&lt;/li&gt;
&lt;li&gt;Tôn trọng thời gian và công sức của nhà phát triển&lt;/li&gt;
&lt;li&gt;Sử dụng đúng kênh hỗ trợ chính thức&lt;/li&gt;
&lt;li&gt;Đóng góp ngược lại nếu có thể&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="bài-học-và-khuyến-nghị"&gt;Bài học và khuyến nghị:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đối với người dùng&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hiểu rằng mã nguồn mở là đặc quyền, không phải quyền lợi&lt;/li&gt;
&lt;li&gt;Đánh giá cao công sức của nhà phát triển&lt;/li&gt;
&lt;li&gt;Xem xét đóng góp tài chính nếu dự án hữu ích&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đối với nhà phát triển&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thiết lập ranh giới rõ ràng&lt;/li&gt;
&lt;li&gt;Đừng ngại từ chối các yêu cầu không phù hợp&lt;/li&gt;
&lt;li&gt;Chăm sóc sức khỏe tinh thần của bản thân&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết nhắc nhở chúng ta về giá trị thực sự của mã nguồn mở và tầm quan trọng của việc xây dựng một cộng đồng tôn trọng lẫn nhau. Mã nguồn mở là một món quà, không phải điều hiển nhiên phải có.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-insanity-of-being-a-software-engineer"&gt;&lt;a class="link" href="https://0x1.pt/2025/04/06/the-insanity-of-being-a-software-engineer/" target="_blank" rel="noopener"
&gt;The Insanity of Being a Software Engineer&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phản ánh những thách thức và sự phức tạp ngày càng tăng trong nghề kỹ sư phần mềm hiện đại, nơi kỳ vọng về kỹ năng ngày càng mở rộng trong khi thời gian và nguồn lực thì có hạn.&lt;/p&gt;
&lt;h3 id="những-thách-thức-của-nghề-kỹ-sư-phần-mềm"&gt;Những thách thức của nghề kỹ sư phần mềm:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Gánh nặng công nghệ chồng chất&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phải thành thạo nhiều ngôn ngữ lập trình và công cụ ngay từ đầu&lt;/li&gt;
&lt;li&gt;Cần học framework cụ thể mà công ty sử dụng (Rails, Django, Laravel, v.v.)&lt;/li&gt;
&lt;li&gt;Yêu cầu kiến thức về CSS, dù rất khó để thành thạo hoàn toàn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sự bùng nổ của hệ sinh thái JavaScript&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Từ jQuery đơn giản đến React phức tạp&lt;/li&gt;
&lt;li&gt;Thêm TypeScript, Redux, Webpack, ESLint, Prettier&amp;hellip;&lt;/li&gt;
&lt;li&gt;Áp lực phải theo kịp các xu hướng mới nhất&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vai trò Full-stack và DevOps&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kỳ vọng trở thành &amp;ldquo;người đa năng&amp;rdquo; tăng cao&lt;/li&gt;
&lt;li&gt;Phải thành thạo cả frontend, backend và cả vận hành hệ thống&lt;/li&gt;
&lt;li&gt;Cần học Docker, Kubernetes, AWS, Terraform&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thăng tiến và quản lý&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khi thăng tiến lên vị trí quản lý, phải học thêm kỹ năng hoàn toàn mới&lt;/li&gt;
&lt;li&gt;Vẫn phải duy trì kiến thức kỹ thuật trong khi đảm nhận trách nhiệm quản lý&lt;/li&gt;
&lt;li&gt;Cân bằng giữa công việc kỹ thuật và quản lý nhân sự&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="so-sánh-với-ngành-xây-dựng"&gt;So sánh với ngành xây dựng:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Trong xây dựng, mỗi người có vai trò chuyên biệt: kiến trúc sư, kỹ sư xây dựng, thợ điện, thợ nước&amp;hellip;&lt;/li&gt;
&lt;li&gt;Trong phát triển phần mềm, một người thường phải đảm nhận nhiều vai trò cùng lúc&lt;/li&gt;
&lt;li&gt;Sự chuyên môn hóa thấp hơn dẫn đến áp lực và căng thẳng cao hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="tương-lai-của-ngành"&gt;Tương lai của ngành:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Sự phức tạp ngày càng tăng đặt ra câu hỏi về tính bền vững của mô hình hiện tại&lt;/li&gt;
&lt;li&gt;AI và các công cụ no-code/low-code có thể giúp giảm bớt gánh nặng&lt;/li&gt;
&lt;li&gt;Cần có sự cân bằng giữa đa năng và chuyên sâu trong đào tạo kỹ sư phần mềm&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết là tiếng lòng của một kỹ sư phần mềm trước những đòi hỏi ngày càng cao và đa dạng của nghề nghiệp, đồng thời đặt câu hỏi về hướng phát triển bền vững cho ngành công nghiệp phần mềm trong tương lai.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-day-i-taught-ai-to-understand-code-like-a-senior-developer"&gt;&lt;a class="link" href="https://nmn.gl/blog/ai-understand-senior-developer" target="_blank" rel="noopener"
&gt;The day I taught AI to understand code like a Senior Developer&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ hành trình phát triển một giải pháp giúp AI hiểu code như một lập trình viên kỳ cựu, vượt qua những hạn chế của các mô hình ngôn ngữ lớn (LLM) hiện tại.&lt;/p&gt;
&lt;h3 id="vấn-đề-với-các-ai-hiện-tại"&gt;Vấn đề với các AI hiện tại:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ảo tưởng về sự hiểu biết&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Các công cụ AI hiện tại thường tạo ra code không tuân theo các mẫu thiết kế sẵn có&lt;/li&gt;
&lt;li&gt;Chúng không thực sự hiểu mối quan hệ giữa các thành phần trong codebase&lt;/li&gt;
&lt;li&gt;Hoạt động dựa trên cửa sổ ngữ cảnh nhỏ, không nắm bắt được bức tranh tổng thể&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tư duy Junior vs Senior&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Junior&lt;/strong&gt;: Tập trung vào &amp;ldquo;cái gì&amp;rdquo; và &amp;ldquo;như thế nào&amp;rdquo; - giải quyết vấn đề trước mắt&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Senior&lt;/strong&gt;: Tập trung vào &amp;ldquo;tại sao&amp;rdquo; và &amp;ldquo;điều gì xảy ra nếu&amp;rdquo; - hiểu toàn bộ hệ thống và dự đoán tác động&lt;/li&gt;
&lt;li&gt;Các LLM hiện tại thường hoạt động như junior hơn là senior&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="giải-pháp-đột-phá"&gt;Giải pháp đột phá:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ranked Recursive Summarization (RRS)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phân tích codebase như một đồ thị tri thức phân cấp&lt;/li&gt;
&lt;li&gt;Bắt đầu từ các tệp cơ sở và xây dựng sự hiểu biết từ dưới lên&lt;/li&gt;
&lt;li&gt;Xếp hạng tầm quan trọng của các thành phần code&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Prismatic Ranked Recursive Summarization (PRRS)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phân tích code qua nhiều &amp;ldquo;lăng kính&amp;rdquo; khác nhau&lt;/li&gt;
&lt;li&gt;Mỗi lăng kính tập trung vào một khía cạnh khác nhau (kiến trúc, luồng dữ liệu, bảo mật)&lt;/li&gt;
&lt;li&gt;Tạo ra cái nhìn đa chiều về codebase&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="lợi-ích-chính"&gt;Lợi ích chính:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hiểu biết sâu sắc hơn&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xác định vị trí hợp lý cho các tệp mới&lt;/li&gt;
&lt;li&gt;Nhận diện và tái sử dụng các mẫu thiết kế hiện có&lt;/li&gt;
&lt;li&gt;Mở rộng các trừu tượng hiện có thay vì tạo mới&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phát hiện vấn đề&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lộ rõ nợ kỹ thuật qua lăng kính &amp;ldquo;kiến trúc&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Phát hiện lỗ hổng bảo mật qua lăng kính &amp;ldquo;bảo mật&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Giảm thời gian làm quyên cho thành viên mới&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="ứng-dụng-thực-tế"&gt;Ứng dụng thực tế:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Với nhà phát triển cá nhân&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tạo tài liệu tóm tắt cho các thư mục và tệp quan trọng&lt;/li&gt;
&lt;li&gt;Cải thiện tài liệu hiện có với sự trợ giúp của AI&lt;/li&gt;
&lt;li&gt;Xây dựng tài liệu từ nhiều góc nhìn khác nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Với đội nhóm&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chuẩn hóa kiến thức về codebase&lt;/li&gt;
&lt;li&gt;Giảm sự phụ thuộc vào các thành viên chủ chốt&lt;/li&gt;
&lt;li&gt;Tăng tốc độ phát triển và giảm lỗi&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết kết thúc với tầm nhìn về tương lai nơi AI không thay thế lập trình viên mà trở thành công cụ mở rộng khả năng sáng tạo của con người, giúp chúng ta giải quyết những vấn đề phức tạp hơn bao giờ hết.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="why-companies-don"&gt;&lt;a class="link" href="https://idiallo.com/blog/companies-dont-fix-bugs" target="_blank" rel="noopener"
&gt;Why Companies Don&amp;rsquo;t Fix Bugs&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích lý do tại sao các công ty công nghệ thường bỏ qua việc sửa lỗi phần mềm, thông qua câu chuyện về một lỗi trong GTA Online phải mất 8 năm mới được khắc phục.&lt;/p&gt;
&lt;h3 id="vòng-đời-của-một-lỗi-phần-mềm"&gt;Vòng đời của một lỗi phần mềm:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Năm 1&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nhà phát triển phát hiện vấn đề và đề xuất sửa chữa&lt;/li&gt;
&lt;li&gt;Vấn đề được ghi nhận nhưng bị xếp vào &amp;ldquo;nợ kỹ thuật&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Đội sản phẩm ưu tiên các tính năng mới hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Năm 3&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vấn đề vẫn tồn tại nhưng bị bỏ qua vì các ưu tiên khác&lt;/li&gt;
&lt;li&gt;Các bản cập nhật và tính năng trả phí được ưu tiên hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Năm 6&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ticket báo lỗi bị lãng quên trong hệ thống&lt;/li&gt;
&lt;li&gt;Những người hiểu vấn đề ban đầu đã rời đi&lt;/li&gt;
&lt;li&gt;Codebase đã được viết lại nhiều lần&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Năm 8&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Một lập trình viên mới lại phát hiện ra vấn đề tương tự&lt;/li&gt;
&lt;li&gt;Chu kỳ lặp lại&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="tại-sao-các-lỗi-tốt-không-được-sửa"&gt;Tại sao các lỗi tốt không được sửa?
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sự độc tài của &amp;ldquo;Yêu cầu&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Các tổ chức chỉ tập trung vào lộ trình đã định&lt;/li&gt;
&lt;li&gt;Sửa lỗi không liên quan đến yêu cầu cụ thể bị xếp xuống cuối danh sách ưu tiên&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Nợ kỹ thuật&amp;rdquo; thường đồng nghĩa với &amp;ldquo;sẽ không bao giờ xử lý&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cánh cửa xoay của quyền sở hữu&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nhân sự thay đổi liên tục&lt;/li&gt;
&lt;li&gt;Kiến thức về hệ thống bị mất dần&lt;/li&gt;
&lt;li&gt;Các ticket cũ trở thành di tích của quá khứ&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Huyền thoại về &amp;ldquo;Sửa nhanh&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ngay cả những thay đổi nhỏ cũng có thể gây hậu quả khôn lường&lt;/li&gt;
&lt;li&gt;Thiếu kiểm thử và tài liệu đầy đủ&lt;/li&gt;
&lt;li&gt;Rủi ro phá vỡ hệ thống lớn hơn lợi ích sửa lỗi&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lợi tức đầu tư vô hình&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cải thiện trải nghiệm người dùng khó đo lường bằng tiền&lt;/li&gt;
&lt;li&gt;Các công ty ưu tiên chỉ số tác động đến doanh thu ngắn hạn&lt;/li&gt;
&lt;li&gt;Trải nghiệm người dùng thường bị xem nhẹ cho đến khi quá muộn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="kết-luận"&gt;Kết luận:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Trường hợp của GTA Online là một chiến thắng PR cho Rockstar, nhưng không giải quyết được vấn đề cốt lõi&lt;/li&gt;
&lt;li&gt;Hàng ngàn lỗi khác vẫn bị bỏ quên trong danh sách chờ&lt;/li&gt;
&lt;li&gt;Thách thức thực sự nằm ở hệ thống ưu tiên lợi nhuận trước trải nghiệm người dùng&lt;/li&gt;
&lt;li&gt;Đôi khi cần một người ngoài cuộc để buộc các công ty phải hành động&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết kết thúc với thông điệp: Khi gặp lỗi phần mềm, đừng đổ lỗi cho các nhà phát triển mà hãy nhìn vào hệ thống đã coi trải nghiệm người dùng là yếu tố phụ.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="3-buckets-of-work-time"&gt;&lt;a class="link" href="https://corymiller.com/3-buckets-of-work-time/" target="_blank" rel="noopener"
&gt;3 Buckets of Work Time&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ cách phân chia thời gian làm việc hiệu quả thành ba nhóm chính, giúp cân bằng giữa năng suất và sức khỏe tinh thần, đặc biệt phù hợp với những người làm việc từ xa hoặc trong môi trường đa quốc gia.&lt;/p&gt;
&lt;h3 id="ba-nhóm-thời-gian-làm-việc-chính"&gt;Ba nhóm thời gian làm việc chính:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giao tiếp &amp;amp; Hợp tác&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dành cho các cuộc họp và trao đổi qua Slack/Teams&lt;/li&gt;
&lt;li&gt;Đặc biệt quan trọng khi làm việc với đội ngũ đa quốc gia&lt;/li&gt;
&lt;li&gt;Giúp đảm bảo sự đồng bộ và rõ ràng trong công việc&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thực thi &amp;amp; Giao hàng&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thời gian tập trung vào công việc chuyên môn&lt;/li&gt;
&lt;li&gt;Đối với tác giả (vai trò Chief Evangelist) là sản xuất video nội bộ và cho khách hàng&lt;/li&gt;
&lt;li&gt;Cần được tối ưu hóa để đạt hiệu suất cao nhất&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược &amp;amp; Tầm nhìn&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thời gian để suy ngẫm, sáng tạo và lên kế hoạch&lt;/li&gt;
&lt;li&gt;Thường được thực hiện trong không gian yên tĩnh, một mình&lt;/li&gt;
&lt;li&gt;Là cơ hội để phát triển ý tưởng mới trước khi đưa ra thảo luận nhóm&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="những-bài-học-và-suy-ngẫm"&gt;Những bài học và suy ngẫm:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cân bằng cuộc sống&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tác giả nhấn mạnh tầm quan trọng của việc cân bằng giữa công việc và gia đình&lt;/li&gt;
&lt;li&gt;Ở độ tuổi cuối 40, việc làm việc thông minh quan trọng hơn làm việc chăm chỉ&lt;/li&gt;
&lt;li&gt;Cần nhận biết và tôn trọng giới hạn năng lượng của bản thân&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đối mặt với nỗi sợ hãi&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thừa nhận sự hiện diện của nỗi sợ và sự không chắc chắn&lt;/li&gt;
&lt;li&gt;Tìm kiếm sự rõ ràng thông qua cấu trúc và thói quen&lt;/li&gt;
&lt;li&gt;Xây dựng lòng tin vào bản thân và quá trình&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tầm quan trọng của cấu trúc&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cần có thói quen và cấu trúc nhất định trong ngày&lt;/li&gt;
&lt;li&gt;Điều này tạo cảm giác an toàn và bình yên&lt;/li&gt;
&lt;li&gt;Đồng thời cần linh hoạt để tránh nhàm chán&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Làm việc hiệu quả&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tập trung vào những việc tạo ra tác động lớn nhất&lt;/li&gt;
&lt;li&gt;Đơn giản hóa quy trình làm việc&lt;/li&gt;
&lt;li&gt;Tận dụng thế mạnh cá nhân (theo mô hình Working Genius)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="kết-luận-1"&gt;Kết luận:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Mô hình 3 nhóm thời gian giúp tác giả tìm thấy sự rõ ràng trong công việc&lt;/li&gt;
&lt;li&gt;Mỗi nhóm đều quan trọng và cần được cân bằng phù hợp&lt;/li&gt;
&lt;li&gt;Sự đơn giản (như việc nghĩ theo nhóm 3) giúp duy trì sự tập trung và hiệu quả&lt;/li&gt;
&lt;li&gt;Quan trọng nhất là tìm ra cách làm việc phù hợp với bản thân và hoàn cảnh cụ thể&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết kết thúc với thông điệp về việc chấp nhận bản thân, tin tưởng vào quá trình và tìm kiếm sự cân bằng giữa cấu trúc và linh hoạt trong công việc cũng như cuộc sống.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="dangerous-advice-for-software-engineers"&gt;&lt;a class="link" href="https://www.seangoedecke.com/dangerous-advice/" target="_blank" rel="noopener"
&gt;Dangerous Advice for Software Engineers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết thảo luận về những lời khuyên &amp;ldquo;nguy hiểm&amp;rdquo; nhưng hữu ích cho kỹ sư phần mềm - những lời khuyên đòi hỏi sự khôn ngoan và phán đoán tốt để áp dụng hiệu quả.&lt;/p&gt;
&lt;h3 id="những-lời-khuyên-nguy-hiểm"&gt;Những lời khuyên &amp;ldquo;nguy hiểm&amp;rdquo;
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tự quyết định việc cần làm&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đừng chỉ chờ đợi được giao việc&lt;/li&gt;
&lt;li&gt;Tự xác định vấn đề và đề xuất giải pháp&lt;/li&gt;
&lt;li&gt;Chủ động tạo ra giá trị thay vì chỉ phản ứng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đôi khi cần phá vỡ quy tắc&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không phải mọi quy tắc đều phù hợp trong mọi tình huống&lt;/li&gt;
&lt;li&gt;Cần biết khi nào nên tuân thủ và khi nào nên linh hoạt&lt;/li&gt;
&lt;li&gt;Nhưng phải chịu trách nhiệm về hậu quả&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đưa ra quan điểm rõ ràng&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dám bảo vệ quan điểm dù không chắc chắn 100%&lt;/li&gt;
&lt;li&gt;Tạo tiền đề cho thảo luận sâu sắc hơn&lt;/li&gt;
&lt;li&gt;Nhưng cần sẵn sàng thay đổi khi có bằng chứng mới&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="tại-sao-ít-người-dám-đưa-lời-khuyên-nguy-hiểm"&gt;Tại sao ít người dám đưa lời khuyên &amp;ldquo;nguy hiểm&amp;rdquo;?
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lời khuyên sự nghiệp thường giả tạo&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nhiều lời khuyên chỉ nhằm tránh trách nhiệm&lt;/li&gt;
&lt;li&gt;Ít ai dám nói thẳng sự thật phũ phàng&lt;/li&gt;
&lt;li&gt;Dẫn đến tình trạng kỹ sư giỏi cảm thấy lạc lõng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quản lý khó lòng chia sẻ&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rủi ro quá lớn nếu nhân viên hiểu sai&lt;/li&gt;
&lt;li&gt;Có thể ảnh hưởng đến hình ảnh chuyên nghiệp&lt;/li&gt;
&lt;li&gt;Nhiều quản lý thầm mong nhân viên hiểu ngầm&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đòi hỏi can đảm&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Làm khác đi luôn đi kèm rủi ro&lt;/li&gt;
&lt;li&gt;Cần tự tin vào năng lực bản thân&lt;/li&gt;
&lt;li&gt;Phải chịu trách nhiệm về quyết định của mình&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="khi-nào-nên-áp-dụng"&gt;Khi nào nên áp dụng?
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Khi bạn đã có nền tảng vững chắc&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hiểu rõ quy trình và quy định&lt;/li&gt;
&lt;li&gt;Có đủ kinh nghiệm để đánh giá rủi ro&lt;/li&gt;
&lt;li&gt;Đã xây dựng được uy tín nhất định&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Khi lợi ích lớn hơn rủi ro&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giải pháp mang lại giá trị đáng kể&lt;/li&gt;
&lt;li&gt;Có kế hoạch dự phòng nếu thất bại&lt;/li&gt;
&lt;li&gt;Sẵn sàng chịu trách nhiệm&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Khi đã cân nhắc kỹ lưỡng&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đã thử cách thông thường nhưng không hiệu quả&lt;/li&gt;
&lt;li&gt;Có cơ sở để tin rằng cách này sẽ hiệu quả hơn&lt;/li&gt;
&lt;li&gt;Đã tham khảo ý kiến từ người có kinh nghiệm&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="kết-luận-2"&gt;Kết luận:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Lời khuyên &amp;ldquo;nguy hiểm&amp;rdquo; không dành cho tất cả mọi người&lt;/li&gt;
&lt;li&gt;Cần có sự khôn ngoan để áp dụng đúng cách&lt;/li&gt;
&lt;li&gt;Đôi khi, chính những lời khuyên này mới giúp bạn tỏa sáng&lt;/li&gt;
&lt;li&gt;Quan trọng là hiểu rõ bối cảnh và chấp nhận rủi ro có tính toán&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết kết thúc với thông điệp: Nếu bạn đã từng tự hỏi liệu mình có đang mắc sai lầm khi làm khác đi, thì có lẽ bạn không đơn độc. Đôi khi, chính những người thành công nhất cũng đang làm tương tự.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="how-seasoned-developers-can-achieve-great-results-with-ai-coding-agents"&gt;&lt;a class="link" href="https://manuel.kiessling.net/2025/03/31/how-seasoned-developers-can-achieve-great-results-with-ai-coding-agents/" target="_blank" rel="noopener"
&gt;How Seasoned Developers Can Achieve Great Results with AI Coding Agents&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết khám phá cách các kỹ sư phần mềm kỳ cựu có thể tận dụng hiệu quả các trợ lý lập trình AI như Cursor để đạt được kết quả vượt trội trong công việc phát triển phần mềm.&lt;/p&gt;
&lt;h3 id="ba-biện-pháp-chính-để-làm-việc-hiệu-quả-với-ai"&gt;Ba biện pháp chính để làm việc hiệu quả với AI
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Yêu cầu được cấu trúc tốt&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cung cấp thông tin chi tiết về phạm vi dự án&lt;/li&gt;
&lt;li&gt;Mô tả rõ ràng kiến trúc hệ thống hiện có&lt;/li&gt;
&lt;li&gt;Xác định vai trò của từng thành phần trong hệ thống&lt;/li&gt;
&lt;li&gt;Đưa ra các yêu cầu cụ thể về chức năng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Công cụ bảo vệ tự động&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tích hợp các công cụ kiểm tra chất lượng mã nguồn&lt;/li&gt;
&lt;li&gt;Sử dụng kiểm thử tự động để xác minh chức năng&lt;/li&gt;
&lt;li&gt;Áp dụng phân tích tĩnh để đảm bảo tuân thủ tiêu chuẩn&lt;/li&gt;
&lt;li&gt;Cung cấp lệnh kiểm thử để AI tự xác minh kết quả&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tạo khung làm việc với file&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tạo các file stub với cấu trúc cơ bản&lt;/li&gt;
&lt;li&gt;Xác định rõ namespace và cấu trúc thư mục&lt;/li&gt;
&lt;li&gt;Cung cấp các mẫu code cơ bản&lt;/li&gt;
&lt;li&gt;Đảm bảo tính nhất quán trong toàn bộ dự án&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="kết-quả-thực-tế"&gt;Kết quả thực tế
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tăng tốc phát triển&lt;/strong&gt;: Tạo giao diện người dùng hoàn chỉnh trong vài phút&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Giảm lỗi&lt;/strong&gt;: Tự động tuân thủ các tiêu chuẩn mã hóa&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mở rộng kiến thức&lt;/strong&gt;: Phát triển hiệu quả ngay cả với công nghệ mới&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tự động hóa&lt;/strong&gt;: AI có thể tự động thêm tính năng mới dựa trên yêu cầu đơn giản&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="trường-hợp-điển-hình-giám-sát-nền-tảng"&gt;Trường hợp điển hình: Giám sát nền tảng
&lt;/h3&gt;&lt;p&gt;Một ví dụ thực tế là ứng dụng &amp;ldquo;Platform Problem Monitoring&amp;rdquo; được phát triển bằng Python để giám sát hệ thống ELK-stack, mặc dù tác giả không có nhiều kinh nghiệm với Python. Ứng dụng này được tạo ra hoàn toàn bởi AI dựa trên:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tài liệu yêu cầu chi tiết (371 dòng)&lt;/li&gt;
&lt;li&gt;Cấu trúc thư mục rõ ràng&lt;/li&gt;
&lt;li&gt;Tích hợp các công cụ kiểm tra chất lượng tự động&lt;/li&gt;
&lt;li&gt;Tự động hóa quy trình kiểm thử&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="kết-luận-3"&gt;Kết luận
&lt;/h3&gt;&lt;p&gt;Những kỹ sư phần mềm giàu kinh nghiệm có lợi thế đặc biệt khi làm việc với AI nhờ:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Khả năng xác định và mô tả vấn đề chính xác&lt;/li&gt;
&lt;li&gt;Hiểu biết sâu về kiến trúc phần mềm&lt;/li&gt;
&lt;li&gt;Kinh nghiệm trong việc đánh giá chất lượng mã nguồn&lt;/li&gt;
&lt;li&gt;Khả năng hướng dẫn AI đi đúng hướng&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết khẳng định rằng thay vì thay thế các kỹ sư phần mềm, AI đang trở thành công cụ mạnh mẽ giúp họ làm việc hiệu quả hơn, đặc biệt khi kết hợp với kinh nghiệm và kiến thức chuyên môn sâu rộng.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="on-the-biology-of-a-large-language-model"&gt;&lt;a class="link" href="https://transformer-circuits.pub/2025/attribution-graphs/biology.html" target="_blank" rel="noopener"
&gt;On the Biology of a Large Language Model&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Nghiên cứu đột phá từ Anthropic về cơ chế hoạt động bên trong mô hình ngôn ngữ lớn Claude 3.5 Haiku, sử dụng phương pháp theo dõi mạch (circuit tracing) để lập bản đồ cách thức xử lý thông tin của AI.&lt;/p&gt;
&lt;h3 id="phương-pháp-nghiên-cứu"&gt;Phương pháp nghiên cứu
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đồ thị quy kết (Attribution Graphs)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Theo dõi luồng thông tin qua các lớp của mô hình&lt;/li&gt;
&lt;li&gt;Xác định các đặc trưng (features) và kết nối giữa chúng&lt;/li&gt;
&lt;li&gt;Tạo giả thuyết về cơ chế hoạt động và kiểm chứng qua thí nghiệm&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phân tích đa chiều&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nghiên cứu nhiều khía cạnh khác nhau của mô hình&lt;/li&gt;
&lt;li&gt;So sánh giữa các mô hình có quy mô khác nhau&lt;/li&gt;
&lt;li&gt;Kiểm tra khả năng tổng quát hóa giữa các ngữ cảnh&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="phát-hiện-chính"&gt;Phát hiện chính
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cơ chế song song&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nhiều con đường xử lý cùng hoạt động song song&lt;/li&gt;
&lt;li&gt;Có thể hợp tác hoặc cạnh tranh với nhau&lt;/li&gt;
&lt;li&gt;Mỗi cơ chế chịu trách nhiệm cho các khía cạnh khác nhau của tính toán&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tính trừu tượng&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mô hình sử dụng các biểu diễn trừu tượng xuyên suốt các lĩnh vực&lt;/li&gt;
&lt;li&gt;Tồn tại cơ chế đa ngôn ngữ thực sự&lt;/li&gt;
&lt;li&gt;Khả năng tổng quát hóa tăng theo quy mô mô hình&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lập kế hoạch nội bộ&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mô hình tạo kế hoạch trước khi đưa ra kết quả&lt;/li&gt;
&lt;li&gt;Cân nhắc nhiều phương án thay thế&lt;/li&gt;
&lt;li&gt;Có thể bị ảnh hưởng bởi các can thiệp bên ngoài&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="ứng-dụng-thực-tế-1"&gt;Ứng dụng thực tế
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xử lý đa ngôn ngữ&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hiểu cơ chế dịch thuật nội bộ&lt;/li&gt;
&lt;li&gt;Phát triển mô hình đa ngôn ngữ hiệu quả hơn&lt;/li&gt;
&lt;li&gt;Cải thiện khả năng chuyển đổi giữa các ngôn ngữ&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giảm thiểu ảo giác&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xác định nguồn gốc thông tin sai lệch&lt;/li&gt;
&lt;li&gt;Phát triển cơ chế kiểm chứng nội bộ&lt;/li&gt;
&lt;li&gt;Cải thiện độ tin cậy của phản hồi&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;An toàn AI&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hiểu cách mô hình đưa ra quyết định từ chối&lt;/li&gt;
&lt;li&gt;Phát hiện và ngăn chặn các cuộc tấn công jailbreak&lt;/li&gt;
&lt;li&gt;Đảm bảo tuân thủ các nguyên tắc đạo đức&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="kết-luận-4"&gt;Kết luận
&lt;/h3&gt;&lt;p&gt;Nghiên cứu này cung cấp cái nhìn sâu sắc chưa từng có về cách thức hoạt động bên trong của các mô hình ngôn ngữ lớn. Bằng cách lập bản đồ các mạch thần kinh nhân tạo, các nhà nghiên cứu đã tiết lộ cách AI xử lý thông tin, đưa ra quyết định và tạo ra phản hồi. Những hiểu biết này không chỉ có giá trị học thuật mà còn mở ra hướng phát triển mới cho các mô hình AI an toàn, đáng tin cậy và hiệu quả hơn trong tương lai.&lt;/p&gt;</description></item><item><title>Newsletter #24</title><link>https://miti99.com/post/2025/05/11/</link><pubDate>Sun, 11 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/11/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #24.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="google"&gt;&lt;a class="link" href="https://newsletter.getdx.com/p/googles-principles-for-measuring-developer-productivity" target="_blank" rel="noopener"
&gt;Google&amp;rsquo;s principles for measuring developer productivity&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này chia sẻ những nguyên tắc quan trọng mà Google đã phát triển để đo lường năng suất của các kỹ sư phần mềm một cách hiệu quả và tránh những tác động tiêu cực không mong muốn. Dựa trên nghiên cứu của Ciera Jaspan và Collin Green, bài viết đưa ra năm nguyên tắc chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Tránh sử dụng mô hình đơn chỉ số: Không nên dựa vào một chỉ số duy nhất để đánh giá năng suất vì điều này có thể bỏ sót nhiều khía cạnh quan trọng.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Đo lường tất cả các kết quả quan trọng: Với mỗi kết quả cần quan tâm, nên thu thập nhiều chỉ số khác nhau để có cái nhìn toàn diện hơn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Chú ý đến các động lực được tạo ra bởi việc đo lường: Khi một chỉ số trở thành mục tiêu, nó có thể mất đi tính hữu ích của mình và tạo ra những hành vi không mong muốn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Đo lường nhiều khía cạnh khác nhau của năng suất: Cần đảm bảo bao quát được cả ba khía cạnh: tốc độ, dễ dàng và chất lượng.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kết hợp dữ liệu hệ thống và dữ liệu tự báo cáo: Cả hai phương pháp đều có ưu điểm riêng và nên được sử dụng cùng nhau.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết cũng nhấn mạnh rằng với các nhóm nhỏ (có thể họp trong một phòng họp), việc đo lường năng suất không cần thiết vì có thể thảo luận trực tiếp. Với các nhóm lớn hơn, nên bắt đầu bằng các cuộc khảo sát để hiểu rõ hơn về trải nghiệm của các kỹ sư.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Những điểm chính cần ghi nhớ:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Việc đo lường năng suất là một bài toán phức tạp cần được tiếp cận một cách toàn diện&lt;/li&gt;
&lt;li&gt;Cần tránh tạo ra những động lực tiêu cực thông qua việc đo lường&lt;/li&gt;
&lt;li&gt;Nên kết hợp nhiều phương pháp và chỉ số khác nhau&lt;/li&gt;
&lt;li&gt;Luôn bắt đầu bằng việc xác định rõ mục đích của việc đo lường&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="in-defense-of-ruthless-managers"&gt;&lt;a class="link" href="https://www.seangoedecke.com/ruthless-managers/" target="_blank" rel="noopener"
&gt;In defense of ruthless managers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này đưa ra một góc nhìn thú vị về hai kiểu quản lý trong ngành công nghệ: người quản lý đồng cảm (empathetic) và người quản lý tàn nhẫn (ruthless). Tác giả cho rằng những người quản lý tàn nhẫn thường bị đánh giá thấp và có những ưu điểm không ngờ tới:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vẫn quan tâm đến hạnh phúc của kỹ sư&lt;/strong&gt;: Người quản lý tàn nhẫn vẫn muốn kỹ sư của họ hạnh phúc vì điều này mang lại lợi ích cho cả hai bên. Kỹ sư hạnh phúc sẽ làm việc hiệu quả hơn và dễ quản lý hơn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Có nhiều ảnh hưởng chính trị hơn&lt;/strong&gt;: Trong khi người quản lý đồng cảm thường xung đột với cấp trên, người quản lý tàn nhẫn thường có nhiều &amp;ldquo;vốn chính trị&amp;rdquo; hơn. Điều này có thể giúp họ thực hiện được những thay đổi quan trọng khi cần thiết.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ít căng thẳng hơn&lt;/strong&gt;: Người quản lý tàn nhẫn ít bị ảnh hưởng bởi những quyết định khó khăn, giúp họ tập trung tốt hơn vào công việc và đội nhóm.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giao tiếp rõ ràng hơn&lt;/strong&gt;: Họ thường truyền đạt thông tin một cách trực tiếp và rõ ràng, không cố gắng làm mềm những tin xấu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dễ dự đoán hơn&lt;/strong&gt;: Họ luôn hành động theo giá trị và ưu tiên của công ty, giúp kỹ sư dễ dàng hiểu được kỳ vọng và cách để thành công.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tuy nhiên, tác giả cũng nhấn mạnh rằng những ưu điểm này chỉ áp dụng cho những người quản lý có năng lực trong một công ty tương đối lành mạnh. Nếu người quản lý không có năng lực, việc họ tàn nhẫn có thể dẫn đến những hậu quả tiêu cực.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Những điểm chính cần ghi nhớ:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mỗi kiểu quản lý đều có ưu và nhược điểm riêng&lt;/li&gt;
&lt;li&gt;Người quản lý tàn nhẫn có thể hiệu quả trong việc thực hiện thay đổi&lt;/li&gt;
&lt;li&gt;Giao tiếp rõ ràng và dễ dự đoán là những ưu điểm quan trọng&lt;/li&gt;
&lt;li&gt;Năng lực của người quản lý vẫn là yếu tố quyết định nhất&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ai-ambivalence"&gt;&lt;a class="link" href="https://nolanlawson.com/2025/04/02/ai-ambivalence/" target="_blank" rel="noopener"
&gt;AI ambivalence&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này chia sẻ góc nhìn của một kỹ sư có nền tảng về ngôn ngữ học tính toán về sự phát triển của AI và tác động của nó đến công việc lập trình. Tác giả Nolan Lawson, người có bằng thạc sĩ về ngôn ngữ học tính toán, chia sẻ hành trình từ việc ban đầu hoài nghi về AI đến việc chấp nhận và sử dụng nó trong công việc:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nền tảng và hoài nghi ban đầu&lt;/strong&gt;: Với kiến thức sâu về ngôn ngữ học và ngôn ngữ học tính toán, tác giả ban đầu hoài nghi về khả năng của AI trong việc thực sự hiểu và xử lý ngôn ngữ tự nhiên.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sự thay đổi quan điểm&lt;/strong&gt;: Mặc dù vẫn giữ thái độ hoài nghi về khả năng của AI trong việc đạt được trí tuệ nhân tạo tổng quát (AGI), tác giả thừa nhận rằng các công cụ AI hiện đại có thể thực sự &amp;ldquo;làm được việc&amp;rdquo; và hữu ích trong thực tế.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Trải nghiệm với AI trong lập trình&lt;/strong&gt;: Tác giả chia sẻ về việc sử dụng Claude và Claude Code trong công việc, thừa nhận rằng công cụ này có khả năng vượt xa những gì ông từng mong đợi, đặc biệt trong việc phân tích codebase lớn, tạo unit test, và refactor code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Những lo ngại về &amp;ldquo;vibe coding&amp;rdquo;&lt;/strong&gt;: Tác giả bày tỏ lo ngại về việc AI có thể làm mất đi niềm vui trong việc lập trình, biến lập trình viên thành người &amp;ldquo;trông trẻ&amp;rdquo; cho AI, chỉ đọc và sửa lỗi code do AI tạo ra.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cân bằng giữa hiệu quả và niềm vui&lt;/strong&gt;: Bài viết kết luận với việc cân nhắc giữa việc sử dụng AI để tăng hiệu quả và việc duy trì niềm vui, sự sáng tạo trong công việc lập trình.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Những điểm chính cần ghi nhớ:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI đã trở thành một công cụ mạnh mẽ trong lập trình, đặc biệt trong việc xử lý codebase lớn&lt;/li&gt;
&lt;li&gt;Cần cân nhắc giữa hiệu quả và niềm vui trong công việc lập trình&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Vibe coding&amp;rdquo; có thể dẫn đến việc phụ thuộc quá mức vào AI&lt;/li&gt;
&lt;li&gt;Việc hiểu và kiểm soát code vẫn là kỹ năng quan trọng của lập trình viên&lt;/li&gt;
&lt;li&gt;Cần có thái độ cân bằng và thực tế khi sử dụng AI trong lập trình&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="use-abstraction-to-improve-function-readability"&gt;&lt;a class="link" href="https://testing.googleblog.com/2023/09/use-abstraction-to-improve-function.html" target="_blank" rel="noopener"
&gt;Use Abstraction to Improve Function Readability&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ Google Testing Blog chia sẻ về cách sử dụng trừu tượng hóa (abstraction) để cải thiện khả năng đọc hiểu của các hàm trong code. Đây là một kỹ thuật quan trọng trong việc viết code sạch và dễ bảo trì.&lt;/p&gt;
&lt;h3 id="tại-sao-cần-trừu-tượng-hóa"&gt;Tại sao cần trừu tượng hóa:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cải thiện khả năng đọc hiểu&lt;/strong&gt;: Trừu tượng hóa giúp code dễ đọc hơn bằng cách ẩn đi các chi tiết phức tạp và tập trung vào ý định của code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giảm độ phức tạp&lt;/strong&gt;: Bằng cách tách các chi tiết triển khai thành các hàm riêng biệt, code trở nên đơn giản và dễ hiểu hơn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tăng khả năng tái sử dụng&lt;/strong&gt;: Các hàm được trừu tượng hóa tốt có thể được tái sử dụng ở nhiều nơi khác nhau trong codebase.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dễ dàng bảo trì&lt;/strong&gt;: Khi cần thay đổi logic, việc sửa đổi một hàm được trừu tượng hóa tốt sẽ ít ảnh hưởng đến các phần khác của code.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="cách-áp-dụng-trừu-tượng-hóa"&gt;Cách áp dụng trừu tượng hóa:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tách biệt các mối quan tâm&lt;/strong&gt;: Mỗi hàm nên chỉ thực hiện một nhiệm vụ cụ thể và rõ ràng.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đặt tên hàm có ý nghĩa&lt;/strong&gt;: Tên hàm nên phản ánh chính xác những gì hàm đó làm.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giảm thiểu độ phức tạp&lt;/strong&gt;: Mỗi hàm nên có ít tham số và logic đơn giản.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sử dụng các mức trừu tượng phù hợp&lt;/strong&gt;: Code nên được tổ chức theo các mức trừu tượng khác nhau, từ cao đến thấp.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tài liệu hóa rõ ràng&lt;/strong&gt;: Các hàm phức tạp nên được tài liệu hóa đầy đủ để người khác dễ dàng hiểu và sử dụng.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Những điểm chính cần ghi nhớ:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trừu tượng hóa là một công cụ mạnh mẽ để cải thiện chất lượng code&lt;/li&gt;
&lt;li&gt;Mỗi hàm nên có một nhiệm vụ rõ ràng và cụ thể&lt;/li&gt;
&lt;li&gt;Tên hàm nên phản ánh chính xác chức năng của nó&lt;/li&gt;
&lt;li&gt;Code nên được tổ chức theo các mức trừu tượng phù hợp&lt;/li&gt;
&lt;li&gt;Tài liệu hóa là một phần quan trọng của việc trừu tượng hóa&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-apple-pay-handles-41-million-transactions-a-day-securely"&gt;&lt;a class="link" href="https://newsletter.systemdesign.one/p/how-does-apple-pay-work" target="_blank" rel="noopener"
&gt;How Apple Pay Handles 41 Million Transactions a Day Securely&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích kiến trúc của Apple Pay và cách nó xử lý hơn 41 triệu giao dịch mỗi ngày một cách an toàn. Đây là một ví dụ điển hình về việc thiết kế hệ thống thanh toán di động với tính bảo mật cao.&lt;/p&gt;
&lt;h3 id="kiến-trúc-của-apple-pay"&gt;Kiến trúc của Apple Pay:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đăng ký thẻ tín dụng&lt;/strong&gt;: Khi người dùng thêm thẻ tín dụng vào Apple Wallet, thông tin thẻ và metadata của iPhone được gửi đến mạng thanh toán (như Visa hoặc MasterCard) dưới dạng mã hóa. Apple không lưu trữ thông tin thẻ trên iPhone hoặc máy chủ của họ.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Số tài khoản thiết bị (DAN)&lt;/strong&gt;: Mạng thanh toán xác minh thông tin thẻ và tạo ra một DAN - một số ngẫu nhiên duy nhất đại diện cho số thẻ tín dụng. DAN được lưu trữ trong &amp;ldquo;secure element&amp;rdquo; của iPhone, một chip chuyên biệt có độ bảo mật cao.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xác thực giao dịch&lt;/strong&gt;: Khi thực hiện thanh toán, iPhone giao tiếp với đầu đọc thẻ qua NFC (Near Field Communication). Quá trình xác thực bao gồm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xác thực sinh trắc học (Touch ID hoặc Face ID)&lt;/li&gt;
&lt;li&gt;Tạo cryptogram yêu cầu từ DAN và chi tiết giao dịch&lt;/li&gt;
&lt;li&gt;Xác thực cryptogram bởi mạng thanh toán&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bảo mật dữ liệu sinh trắc học&lt;/strong&gt;: Thông tin sinh trắc học chỉ được lưu trữ trong &amp;ldquo;secure enclave&amp;rdquo; của iPhone, một bộ xử lý riêng biệt được cách ly với phần còn lại của hệ thống.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xử lý giao dịch không cần internet&lt;/strong&gt;: Apple Pay có thể hoạt động mà không cần kết nối internet, tương tự như thẻ tín dụng vật lý, nhờ vào việc sử dụng tiêu chuẩn EMV cho thanh toán không tiếp xúc.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="các-biện-pháp-bảo-mật-chính"&gt;Các biện pháp bảo mật chính:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bảo vệ thông tin thẻ&lt;/strong&gt;: Thông tin thẻ tín dụng không bao giờ được lưu trữ trên thiết bị hoặc máy chủ của Apple.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xác thực hai yếu tố&lt;/strong&gt;: Mỗi giao dịch đều yêu cầu xác thực sinh trắc học.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mã hóa đầu cuối&lt;/strong&gt;: Tất cả dữ liệu nhạy cảm đều được mã hóa trong quá trình truyền tải.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cryptogram động&lt;/strong&gt;: Mỗi giao dịch sử dụng một cryptogram duy nhất, dựa trên thời gian và chi tiết giao dịch.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cách ly phần cứng&lt;/strong&gt;: Secure element và secure enclave cung cấp lớp bảo vệ phần cứng cho dữ liệu nhạy cảm.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Những điểm chính cần ghi nhớ:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Apple Pay sử dụng kiến trúc phân tầng để đảm bảo an toàn cho giao dịch&lt;/li&gt;
&lt;li&gt;Thông tin thẻ tín dụng không bao giờ được lưu trữ trực tiếp&lt;/li&gt;
&lt;li&gt;Xác thực sinh trắc học là bắt buộc cho mỗi giao dịch&lt;/li&gt;
&lt;li&gt;Hệ thống có thể hoạt động mà không cần kết nối internet&lt;/li&gt;
&lt;li&gt;Bảo mật được đảm bảo ở cả cấp độ phần mềm và phần cứng&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="four-kinds-of-optimisation"&gt;&lt;a class="link" href="https://tratt.net/laurie/blog/2023/four_kinds_of_optimisation.html" target="_blank" rel="noopener"
&gt;Four Kinds of Optimisation&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích bốn loại tối ưu hóa chính trong lập trình và cách chúng được sử dụng để cải thiện hiệu suất của chương trình. Tác giả chia sẻ kinh nghiệm của mình trong việc tối ưu hóa và đưa ra những hiểu biết sâu sắc về việc lựa chọn phương pháp tối ưu hóa phù hợp.&lt;/p&gt;
&lt;h3 id="bốn-loại-tối-ưu-hóa-chính"&gt;Bốn loại tối ưu hóa chính:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sử dụng thuật toán tốt hơn&lt;/strong&gt;: Đây là phương pháp phổ biến nhất và thường mang lại hiệu quả cao. Tuy nhiên, việc lựa chọn thuật toán phù hợp phụ thuộc vào nhiều yếu tố như:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đặc điểm của dữ liệu đầu vào&lt;/li&gt;
&lt;li&gt;Yêu cầu về bộ nhớ&lt;/li&gt;
&lt;li&gt;Độ phức tạp của việc triển khai&lt;/li&gt;
&lt;li&gt;Khả năng xảy ra trường hợp xấu nhất&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sử dụng cấu trúc dữ liệu tốt hơn&lt;/strong&gt;: Việc lựa chọn cấu trúc dữ liệu phù hợp có thể cải thiện đáng kể hiệu suất. Ví dụ:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng hash map thay vì tìm kiếm tuần tự&lt;/li&gt;
&lt;li&gt;Sử dụng cây nhị phân cho dữ liệu có thứ tự&lt;/li&gt;
&lt;li&gt;Tối ưu hóa cấu trúc dữ liệu cho các thao tác phổ biến&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sử dụng hệ thống cấp thấp hơn&lt;/strong&gt;: Việc chuyển sang ngôn ngữ lập trình cấp thấp hơn có thể mang lại hiệu suất tốt hơn, nhưng cũng đi kèm với nhiều thách thức:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tăng độ phức tạp của code&lt;/li&gt;
&lt;li&gt;Khó bảo trì hơn&lt;/li&gt;
&lt;li&gt;Tốn nhiều thời gian phát triển hơn&lt;/li&gt;
&lt;li&gt;Tỷ lệ cải thiện/chi phí thường không cao&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chấp nhận giải pháp kém chính xác hơn&lt;/strong&gt;: Đây là phương pháp ít được sử dụng nhất nhưng có thể rất hiệu quả trong một số trường hợp:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chấp nhận kết quả gần đúng thay vì chính xác&lt;/li&gt;
&lt;li&gt;Sử dụng xấp xỉ thay vì tính toán chính xác&lt;/li&gt;
&lt;li&gt;Áp dụng trong các bài toán không yêu cầu độ chính xác tuyệt đối&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="những-bài-học-quan-trọng"&gt;Những bài học quan trọng:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tầm quan trọng của việc đo lường&lt;/strong&gt;: Trước khi tối ưu hóa, cần đo lường kỹ lưỡng để xác định chính xác điểm cần cải thiện.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cân nhắc chi phí và lợi ích&lt;/strong&gt;: Mỗi phương pháp tối ưu hóa đều có chi phí riêng, cần cân nhắc kỹ lưỡng trước khi áp dụng.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hiểu rõ ngữ cảnh&lt;/strong&gt;: Việc lựa chọn phương pháp tối ưu hóa phụ thuộc vào ngữ cảnh cụ thể của ứng dụng.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tập trung vào giải pháp đơn giản&lt;/strong&gt;: Thường thì các giải pháp đơn giản mang lại hiệu quả tốt nhất và ít rủi ro nhất.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Những điểm chính cần ghi nhớ:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Có bốn phương pháp tối ưu hóa chính, mỗi phương pháp có ưu và nhược điểm riêng&lt;/li&gt;
&lt;li&gt;Việc đo lường kỹ lưỡng là bước quan trọng trước khi tối ưu hóa&lt;/li&gt;
&lt;li&gt;Cần cân nhắc chi phí và lợi ích của mỗi phương pháp&lt;/li&gt;
&lt;li&gt;Giải pháp đơn giản thường hiệu quả hơn giải pháp phức tạp&lt;/li&gt;
&lt;li&gt;Hiểu rõ ngữ cảnh là yếu tố quyết định trong việc lựa chọn phương pháp tối ưu hóa&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-fifth-kind-of-optimisation"&gt;&lt;a class="link" href="https://tratt.net/laurie/blog/2025/the_fifth_kind_of_optimisation.html" target="_blank" rel="noopener"
&gt;The Fifth Kind of Optimisation&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này bổ sung thêm một loại tối ưu hóa quan trọng mà tác giả đã bỏ sót trong bài viết trước của mình: song song hóa (parallelization). Trong khi trước đây tác giả đã liệt kê bốn loại tối ưu hóa chính (sử dụng thuật toán tốt hơn, cấu trúc dữ liệu tốt hơn, hệ thống cấp thấp hơn, và chấp nhận giải pháp kém chính xác hơn), bài viết này tập trung vào việc sử dụng song song hóa như một công cụ tối ưu hóa mạnh mẽ.&lt;/p&gt;
&lt;h3 id="tại-sao-song-song-hóa-quan-trọng"&gt;Tại sao song song hóa quan trọng:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tận dụng phần cứng hiện đại&lt;/strong&gt;: Máy tính hiện đại có nhiều lõi CPU, từ máy tính cá nhân với 16 lõi đến máy chủ với hàng trăm lõi. Song song hóa cho phép tận dụng tối đa sức mạnh này.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cải thiện hiệu suất thực tế&lt;/strong&gt;: Tác giả chia sẻ kinh nghiệm cá nhân về việc song song hóa hệ thống xây dựng website, giúp giảm thời gian xây dựng từ 0.6s xuống còn 0.3s trong chế độ &amp;ldquo;quick&amp;rdquo; và tăng tốc hơn 3 lần trong chế độ &amp;ldquo;deploy&amp;rdquo;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tăng hiệu quả phát triển&lt;/strong&gt;: Song song hóa không chỉ cải thiện hiệu suất mà còn tăng hiệu quả làm việc của nhà phát triển, đặc biệt trong các tác vụ như chạy test.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="thách-thức-và-giải-pháp"&gt;Thách thức và giải pháp:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề về phần cứng&lt;/strong&gt;: Trước đây, phần cứng không cung cấp đủ tiềm năng song song hóa. Ngày nay, với sự phát triển của CPU đa lõi, điều này đã thay đổi.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề về ngôn ngữ lập trình&lt;/strong&gt;: Các ngôn ngữ lập trình truyền thống gặp khó khăn trong việc hỗ trợ song song hóa an toàn. Các ngôn ngữ hiện đại như Rust đã giải quyết vấn đề này tốt hơn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mô hình bộ nhớ&lt;/strong&gt;: Sự khác biệt giữa các mô hình bộ nhớ (như x86 và Arm) đã từng gây khó khăn cho việc song song hóa. Ngày nay, các tiêu chuẩn như C11 memory model đã giúp thống nhất cách tiếp cận.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="ứng-dụng-thực-tế"&gt;Ứng dụng thực tế:
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xây dựng website&lt;/strong&gt;: Tác giả chia sẻ việc song song hóa hệ thống xây dựng website của mình, giúp cải thiện đáng kể thời gian phản hồi.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chạy test&lt;/strong&gt;: Framework lang_tester của tác giả chạy test song song, giúp giảm thời gian chạy test từ 37s xuống còn 2.5s trên máy chủ 72 lõi.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xử lý dữ liệu&lt;/strong&gt;: Song song hóa đặc biệt hiệu quả cho các tác vụ xử lý dữ liệu độc lập.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Những điểm chính cần ghi nhớ:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Song song hóa là một công cụ tối ưu hóa mạnh mẽ trong thời đại CPU đa lõi&lt;/li&gt;
&lt;li&gt;Hiệu quả của song song hóa phụ thuộc vào phần cứng và tính chất của tác vụ&lt;/li&gt;
&lt;li&gt;Các ngôn ngữ lập trình hiện đại đã cải thiện đáng kể việc hỗ trợ song song hóa&lt;/li&gt;
&lt;li&gt;Song song hóa không chỉ cải thiện hiệu suất mà còn tăng hiệu quả phát triển&lt;/li&gt;
&lt;li&gt;Cần cân nhắc kỹ lưỡng khi áp dụng song song hóa vào các tác vụ cụ thể&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/4036e9a7-f2b6-476c-ad5d-48916db3b610_1309x1536.gif"
loading="lazy"
alt="REST API Design Best Practices"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/2a933717-1d59-46a6-ba51-76e24ae048fc_1280x1502.gif"
loading="lazy"
alt="How to Learn Backend Development?"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/b9397d70-0232-4a8b-8b3e-edd4c15eb9bb_800x939.gif"
loading="lazy"
alt="The Simplified Git Workflow"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/1bc9340f-de4f-4767-b2f8-f4c6529e9eea_1309x1536.gif"
loading="lazy"
alt="Virtualization vs Containerization"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/1e7afaab-de4b-4604-a557-22974fb2e3ea_1280x1532.gif"
loading="lazy"
alt="How Netflix Built a Distributed Counter?"
&gt;&lt;/p&gt;
&lt;h2 id="bonus-2-vài-video-hay-ho-đến-từ-bytebytego"&gt;Bonus 2: Vài video hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=_d0duu3dED4" target="_blank" rel="noopener"
&gt;Why Everyone&amp;rsquo;s Talking About MCP?&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Newsletter #23</title><link>https://miti99.com/post/2025/05/10/</link><pubDate>Sat, 10 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/10/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #23.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="llms-an-operator"&gt;&lt;a class="link" href="https://theengineeringmanager.substack.com/p/llms-an-operators-view" target="_blank" rel="noopener"
&gt;LLMs: An Operator&amp;rsquo;s View&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này cung cấp một góc nhìn thực tế về việc sử dụng LLM (Large Language Models) trong môi trường doanh nghiệp từ góc độ của người quản lý. Tác giả James Stanier chia sẻ những insights quan trọng về cách các tổ chức nên tiếp cận và tích hợp LLM vào quy trình phát triển phần mềm.&lt;/p&gt;
&lt;p&gt;Những điểm chính trong bài viết:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nâng cao năng suất phát triển&lt;/strong&gt;: LLM đã trở thành công cụ không thể thiếu trong bộ công cụ của developer, giúp tăng tốc độ phát triển đáng kể thông qua các tính năng như code completion, prototyping nhanh và viết test tự động.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thay đổi quy mô tổ chức&lt;/strong&gt;: Với việc tăng năng suất từ LLM, các công ty có thể làm được nhiều việc hơn với ít người hơn. Tuy nhiên, tác giả cảnh báo về việc cân bằng giữa việc giảm nhân sự và duy trì chất lượng sản phẩm.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tăng cường quy trình code review&lt;/strong&gt;: Với tốc độ tạo code nhanh hơn từ LLM, việc review code trở nên quan trọng hơn bao giờ hết. Cần có quy trình review chặt chẽ để đảm bảo chất lượng và bảo mật.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thay đổi trong quy trình phỏng vấn&lt;/strong&gt;: Bài viết đề cập đến những thách thức mới trong việc đánh giá ứng viên khi LLM có thể được sử dụng trong quá trình phỏng vấn, và đề xuất các phương pháp thích ứng.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược triển khai&lt;/strong&gt;: Tác giả nhấn mạnh tầm quan trọng của việc đào tạo team sử dụng LLM hiệu quả, bao gồm việc xác định các &amp;ldquo;champion&amp;rdquo;, chia sẻ best practices và theo dõi hiệu quả sử dụng.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết kết luận rằng việc tích hợp LLM vào quy trình phát triển không còn là lựa chọn mà là yêu cầu bắt buộc để duy trì tính cạnh tranh trong ngành công nghệ hiện nay.&lt;/p&gt;
&lt;h2 id="the-reality-of-tech-interviews-in-2025"&gt;&lt;a class="link" href="https://newsletter.pragmaticengineer.com/p/the-reality-of-tech-interviews" target="_blank" rel="noopener"
&gt;The Reality of Tech Interviews in 2025&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này cung cấp một cái nhìn sâu sắc về thực trạng phỏng vấn kỹ thuật trong năm 2025, được viết bởi Evan King (cựu Staff Engineer tại Meta) và Stefan Mai (cựu Engineering Manager tại Amazon và Meta). Dựa trên kinh nghiệm thực tế từ việc giúp hàng nghìn kỹ sư chuẩn bị cho các cuộc phỏng vấn, bài viết phân tích những thay đổi đáng chú ý trong thị trường tuyển dụng công nghệ.&lt;/p&gt;
&lt;p&gt;Những điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thị trường tuyển dụng đang phục hồi có chọn lọc&lt;/strong&gt;: Mặc dù số lượng việc làm đã tăng khoảng 40% so với năm ngoái, nhưng vẫn thấp hơn nhiều so với đỉnh điểm 2020-2022. Các công ty đang trở nên kỹ lưỡng hơn trong việc tuyển dụng.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phân hóa theo chuyên môn&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Các vị trí liên quan đến AI, ML và Generative AI đang rất &amp;ldquo;hot&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Các vị trí frontend, backend truyền thống đang gặp khó khăn hơn&lt;/li&gt;
&lt;li&gt;Kỹ sư full-stack được ưa chuộng hơn do khả năng đa năng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thay đổi trong quy trình phỏng vấn&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tiêu chuẩn đánh giá cao hơn so với trước đây&lt;/li&gt;
&lt;li&gt;Tỷ lệ &amp;ldquo;downleveling&amp;rdquo; (hạ cấp) tăng lên&lt;/li&gt;
&lt;li&gt;Quá trình matching team trở thành một bước quan trọng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược chuẩn bị theo cấp độ&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Entry-level: Tập trung vào kỹ năng cơ bản và thực hành nhiều&lt;/li&gt;
&lt;li&gt;Mid-level: Cân bằng giữa kỹ năng kỹ thuật và soft skills&lt;/li&gt;
&lt;li&gt;Senior+: Tập trung vào leadership và system design&lt;/li&gt;
&lt;li&gt;Engineering Manager: Chú trọng vào quản lý team và chiến lược&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Những điểm tích cực&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Các công ty Big Tech vẫn duy trì khoảng 40,000 vị trí mở&lt;/li&gt;
&lt;li&gt;Lĩnh vực AI tiếp tục tăng trưởng mạnh&lt;/li&gt;
&lt;li&gt;Quy trình phỏng vấn ngày càng minh bạch và có thể chuẩn bị&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết kết luận rằng mặc dù thị trường việc làm đang khó khăn hơn, nhưng với sự chuẩn bị kỹ lưỡng và chiến lược phù hợp, các kỹ sư vẫn có thể tìm được vị trí phù hợp. Điều quan trọng là cần đầu tư thời gian vào việc chuẩn bị và thực hành các kỹ năng phỏng vấn.&lt;/p&gt;
&lt;h2 id="senior-developer-skills-in-the-ai-age-leveraging-experience-for-better-results"&gt;&lt;a class="link" href="https://manuel.kiessling.net/2025/03/31/how-seasoned-developers-can-achieve-great-results-with-ai-coding-agents/" target="_blank" rel="noopener"
&gt;Senior Developer Skills in the AI Age: Leveraging Experience for Better Results&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này chia sẻ kinh nghiệm thực tế về cách các kỹ sư phần mềm kỳ cựu có thể tận dụng AI coding agents (như Cursor) để đạt được kết quả tốt hơn trong công việc. Tác giả Manuel Kießling, dựa trên kinh nghiệm làm việc với team của mình tại Joboo, đã xác định được ba yếu tố quan trọng để làm việc hiệu quả với AI coding assistants.&lt;/p&gt;
&lt;p&gt;Những điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ba yếu tố quan trọng để làm việc với AI coding assistants&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yêu cầu được cấu trúc tốt (Well-structured Requirements)&lt;/li&gt;
&lt;li&gt;Công cụ kiểm soát chất lượng (Tool-based Guard Rails)&lt;/li&gt;
&lt;li&gt;Định hình cấu trúc file (File-based Keyframing)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Yêu cầu được cấu trúc tốt&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cung cấp context đầy đủ về task&lt;/li&gt;
&lt;li&gt;Mô tả rõ ràng các ràng buộc và yêu cầu&lt;/li&gt;
&lt;li&gt;Sử dụng các file hiện có làm ví dụ và hướng dẫn&lt;/li&gt;
&lt;li&gt;Định nghĩa rõ mục tiêu và phạm vi&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Công cụ kiểm soát chất lượng&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng các công cụ format code&lt;/li&gt;
&lt;li&gt;Tích hợp linting và type checking&lt;/li&gt;
&lt;li&gt;Kiểm tra bảo mật&lt;/li&gt;
&lt;li&gt;Chạy test suite tự động&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định hình cấu trúc file&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tạo các file stub với cấu trúc cơ bản&lt;/li&gt;
&lt;li&gt;Định nghĩa rõ namespace và naming conventions&lt;/li&gt;
&lt;li&gt;Cung cấp các file mẫu làm tham khảo&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kết quả thực tế&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Có thể xây dựng các tính năng hoàn chỉnh mà không cần viết code&lt;/li&gt;
&lt;li&gt;Tăng tốc độ phát triển đáng kể&lt;/li&gt;
&lt;li&gt;Duy trì được chất lượng code và tính toàn vẹn của kiến trúc&lt;/li&gt;
&lt;li&gt;Cho phép làm việc với các tech stack mới một cách hiệu quả&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết kết luận rằng kinh nghiệm và kiến thức của các kỹ sư kỳ cựu vẫn rất quan trọng trong thời đại AI, thậm chí còn quan trọng hơn để hướng dẫn và kiểm soát AI coding assistants một cách hiệu quả.&lt;/p&gt;
&lt;h2 id="jep-483-ahead-of-time-class-loading--linking"&gt;&lt;a class="link" href="https://www.morling.dev/blog/jep-483-aot-class-loading-linking/" target="_blank" rel="noopener"
&gt;JEP 483: Ahead-of-Time Class Loading &amp;amp; Linking&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích chi tiết về JEP 483, một tính năng mới trong Java 24 nhằm cải thiện thời gian khởi động của các ứng dụng Java. Tác giả Gunnar Morling đã thực hiện các thử nghiệm thực tế với Apache Kafka và Apache Flink để đánh giá hiệu quả của tính năng này.&lt;/p&gt;
&lt;p&gt;Những điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tổng quan về JEP 483&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Là một phần của Project Leyden, nhằm giảm footprint của các chương trình Java&lt;/li&gt;
&lt;li&gt;Xây dựng dựa trên tính năng Application Class Data Sharing (AppCDS)&lt;/li&gt;
&lt;li&gt;Cho phép load và link các class trước khi chạy ứng dụng&lt;/li&gt;
&lt;li&gt;Không yêu cầu thay đổi code của ứng dụng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quy trình tạo AOT cache&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yêu cầu một lần chạy training để tạo file cấu hình&lt;/li&gt;
&lt;li&gt;Cần đảm bảo load đúng set các class cần thiết&lt;/li&gt;
&lt;li&gt;Classpath phải nhất quán giữa lần chạy training và chạy thực tế&lt;/li&gt;
&lt;li&gt;File cache được tạo ra có thể được tái sử dụng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kết quả thử nghiệm với Kafka&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giảm 59% thời gian khởi động (từ 690ms xuống 285ms)&lt;/li&gt;
&lt;li&gt;File cache có kích thước khoảng 66MB&lt;/li&gt;
&lt;li&gt;Vẫn chậm hơn so với native binary (118ms) nhưng an toàn hơn cho production&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kết quả thử nghiệm với Flink&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giảm 51% thời gian khởi động (từ 1.875s xuống 0.913s)&lt;/li&gt;
&lt;li&gt;Chỉ áp dụng được cho các class có sẵn của Flink&lt;/li&gt;
&lt;li&gt;Chưa hỗ trợ user-defined class loaders&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;So sánh với GraalVM&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GraalVM hiện tại tiên tiến hơn với full AOT compilation&lt;/li&gt;
&lt;li&gt;Có thể giảm thời gian khởi động xuống vài milliseconds&lt;/li&gt;
&lt;li&gt;Yêu cầu điều chỉnh code và cấu hình phức tạp hơn&lt;/li&gt;
&lt;li&gt;Không hỗ trợ một số tính năng động của JVM&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hạn chế và triển vọng&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quy trình training hiện tại còn phức tạp&lt;/li&gt;
&lt;li&gt;Có thể gặp khó khăn khi tích hợp vào container images&lt;/li&gt;
&lt;li&gt;Project Leyden đang phát triển thêm các tính năng AOT khác&lt;/li&gt;
&lt;li&gt;Hứa hẹn cải thiện thời gian warm-up và đạt peak performance&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết kết luận rằng JEP 483 là một bước tiến quan trọng trong việc cải thiện hiệu suất của Java, đặc biệt hữu ích cho các ứng dụng cloud-native và microservices, nơi thời gian khởi động nhanh là yếu tố quan trọng.&lt;/p&gt;
&lt;h2 id="specifications-in-jakarta-data"&gt;&lt;a class="link" href="https://in.relation.to/2025/03/28/repository-specifications/" target="_blank" rel="noopener"
&gt;Specifications in Jakarta Data&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này của Gavin King (Hibernate) giới thiệu cách triển khai tính năng &amp;ldquo;specifications&amp;rdquo; trong Jakarta Data, một cách tiếp cận linh hoạt để xây dựng các truy vấn động trong ứng dụng Java. Mặc dù tính năng này không có sẵn trong Jakarta Data, bài viết hướng dẫn cách tự triển khai một cách đơn giản và hiệu quả.&lt;/p&gt;
&lt;p&gt;Những điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tổng quan về Specifications&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Là cách tiếp cận từ Spring Data để xây dựng truy vấn động&lt;/li&gt;
&lt;li&gt;Cho phép áp dụng các điều kiện lọc một cách linh hoạt&lt;/li&gt;
&lt;li&gt;Giúp giảm bớt độ phức tạp của JPA Criteria API&lt;/li&gt;
&lt;li&gt;Có thể được triển khai dễ dàng trong Jakarta Data&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Triển khai cơ bản&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng interface &lt;code&gt;JpaRepository&lt;/code&gt; làm base&lt;/li&gt;
&lt;li&gt;Tận dụng &lt;code&gt;BiFunction&lt;/code&gt; của Java để định nghĩa specification&lt;/li&gt;
&lt;li&gt;Cung cấp các phương thức &lt;code&gt;find()&lt;/code&gt; và &lt;code&gt;count()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Hỗ trợ type-safe thông qua JPA static metamodel&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ví dụ sử dụng&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tìm kiếm sách theo tiêu đề:
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;like&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Book_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;%&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;%&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;Tìm kiếm phức tạp với nhiều điều kiện:
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;like&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Book_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;%&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;%&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Book_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authors&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Author_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equalTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authorName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tính năng nâng cao&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hỗ trợ kết hợp nhiều specifications&lt;/li&gt;
&lt;li&gt;Có thể mở rộng thêm các phương thức tìm kiếm&lt;/li&gt;
&lt;li&gt;Dễ dàng thêm các tính năng như sắp xếp kết quả&lt;/li&gt;
&lt;li&gt;Tích hợp tốt với các tính năng khác của Jakarta Data&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ưu điểm&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Code ngắn gọn và dễ hiểu&lt;/li&gt;
&lt;li&gt;Type-safe và an toàn khi biên dịch&lt;/li&gt;
&lt;li&gt;Linh hoạt trong việc xây dựng truy vấn&lt;/li&gt;
&lt;li&gt;Dễ dàng mở rộng và tùy chỉnh&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết kết luận rằng mặc dù Jakarta Data chưa có sẵn tính năng specifications, nhưng việc tự triển khai không khó và mang lại nhiều lợi ích. Tác giả cũng gợi ý rằng một tính năng tương tự sẽ được tích hợp trong Jakarta Data 1.1 trong tương lai.&lt;/p&gt;
&lt;h2 id="there-is-no-vibe-engineering"&gt;&lt;a class="link" href="https://serce.me/posts/2025-31-03-there-is-no-vibe-engineering" target="_blank" rel="noopener"
&gt;There is no Vibe Engineering&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này của Sergey Tselovalnikov (SerCe) phân tích về khái niệm &amp;ldquo;vibe coding&amp;rdquo; được Andrej Karpathy đề xuất gần đây và đưa ra những nhận định sâu sắc về vai trò thực sự của kỹ sư phần mềm trong thời đại AI. Tác giả phản bác quan điểm cho rằng AI sẽ thay thế hoàn toàn vai trò của kỹ sư phần mềm.&lt;/p&gt;
&lt;p&gt;Những điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phân biệt Coding và Engineering&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Coding chỉ là viết code tại một thời điểm&lt;/li&gt;
&lt;li&gt;Engineering là &amp;ldquo;programming integrated over time&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Engineering bao gồm việc xây dựng hệ thống có thể:
&lt;ul&gt;
&lt;li&gt;Chịu được điều kiện thực tế&lt;/li&gt;
&lt;li&gt;Mở rộng theo nhu cầu&lt;/li&gt;
&lt;li&gt;Chống lại các mối đe dọa bảo mật&lt;/li&gt;
&lt;li&gt;Di chuyển và hỗ trợ dữ liệu người dùng&lt;/li&gt;
&lt;li&gt;Thích ứng với yêu cầu mới trong tương lai&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hạn chế của Vibe Coding&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chỉ tập trung vào việc tạo prototype nhanh&lt;/li&gt;
&lt;li&gt;Bỏ qua các vấn đề engineering quan trọng&lt;/li&gt;
&lt;li&gt;Khó diễn đạt các yêu cầu phức tạp qua prompt&lt;/li&gt;
&lt;li&gt;Khó kiểm tra chất lượng chỉ bằng việc xem kết quả cuối cùng&lt;/li&gt;
&lt;li&gt;Đẩy các vấn đề engineering sang giai đoạn muộn, khi chi phí giải quyết cao&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tương lai của Engineering với AI&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Có thể xây dựng hệ thống từ các thành phần &amp;ldquo;vibe-coded&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Cần đóng gói chặt chẽ các thành phần AI-generated&lt;/li&gt;
&lt;li&gt;Yêu cầu testing nghiêm ngặt hơn&lt;/li&gt;
&lt;li&gt;Cần profiling chi tiết và tracing&lt;/li&gt;
&lt;li&gt;Sử dụng canary deployments&lt;/li&gt;
&lt;li&gt;Kiểm tra tương thích protocol chặt chẽ&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vai trò mới của Kỹ sư&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kết hợp giữa kiến trúc sư và platform engineer&lt;/li&gt;
&lt;li&gt;Tập trung vào việc thiết kế hệ thống có thể mở rộng&lt;/li&gt;
&lt;li&gt;Đảm bảo khả năng tiến hóa của hệ thống&lt;/li&gt;
&lt;li&gt;Giảm thời gian viết code nhưng tăng thời gian thiết kế&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết kết luận rằng mặc dù &amp;ldquo;vibe coding&amp;rdquo; là một công cụ hữu ích để tạo prototype nhanh, nhưng nó không thể thay thế vai trò của kỹ sư phần mềm trong việc xây dựng và duy trì các hệ thống production-grade. Công việc thiết kế phần mềm có thể mở rộng và tiến hóa vẫn là yếu tố quan trọng, ngay cả khi cách viết code thay đổi.&lt;/p&gt;
&lt;h2 id="refining-var-handles-in-valhalla"&gt;&lt;a class="link" href="https://cr.openjdk.org/~jrose/values/atomic-value-access-api.html" target="_blank" rel="noopener"
&gt;Refining Var-Handles in Valhalla&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này của John Rose (OpenJDK) trình bày về việc cải tiến API truy cập giá trị nguyên tử trong Project Valhalla, một dự án quan trọng của Java nhằm cải thiện hiệu suất và tính linh hoạt của việc xử lý dữ liệu. Bài viết tập trung vào việc tối ưu hóa cách Java xử lý các giá trị nguyên tử và cấu trúc dữ liệu.&lt;/p&gt;
&lt;p&gt;Những điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tổng quan về Var-Handles&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Là cơ chế truy cập biến trong Java heap&lt;/li&gt;
&lt;li&gt;Thực hiện các thao tác tương tự như getfield, putfield&lt;/li&gt;
&lt;li&gt;Hỗ trợ các thao tác nguyên tử như CAS&lt;/li&gt;
&lt;li&gt;Cần đảm bảo tính nhất quán giữa interpreter, JIT và JNI&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các loại Layout trong Valhalla&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;REFERENCE&lt;/code&gt;: Biến là managed pointer (32 hoặc 64 bits, nullable)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NON_ATOMIC_FLAT&lt;/code&gt;: Biến có nhiều subfield, thường lớn hơn 64 bits&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ATOMIC_FLAT&lt;/code&gt;: Biến đóng gói trong 64 bits, có thể có subfield nhỏ&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NULLABLE_ATOMIC_FLAT&lt;/code&gt;: Tương tự ATOMIC_FLAT nhưng có thêm null flag&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NULLABLE_NON_ATOMIC_FLAT&lt;/code&gt;: Tương tự NON_ATOMIC_FLAT với null flag&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BUFFERED&lt;/code&gt;: Trường hợp đặc biệt cho giá trị read-only&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cải tiến API&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thêm các phương thức mới để xử lý giá trị nguyên tử&lt;/li&gt;
&lt;li&gt;Tách biệt logic xử lý field và thao tác memory&lt;/li&gt;
&lt;li&gt;Sử dụng buffer riêng tư để đảm bảo thread safety&lt;/li&gt;
&lt;li&gt;Hỗ trợ tốt hơn cho việc xử lý null và atomic operations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tối ưu hóa hiệu suất&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giảm overhead khi truy cập biến&lt;/li&gt;
&lt;li&gt;Tăng hiệu suất cho các thao tác nguyên tử&lt;/li&gt;
&lt;li&gt;Cải thiện khả năng tương thích với GC&lt;/li&gt;
&lt;li&gt;Tối ưu hóa việc xử lý các giá trị phức tạp&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tính năng mới&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hỗ trợ tốt hơn cho value types&lt;/li&gt;
&lt;li&gt;Cải thiện khả năng xử lý các cấu trúc dữ liệu phức tạp&lt;/li&gt;
&lt;li&gt;Tăng cường bảo mật và thread safety&lt;/li&gt;
&lt;li&gt;Đơn giản hóa việc triển khai các thao tác nguyên tử&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết kết luận rằng những cải tiến này sẽ giúp Java xử lý hiệu quả hơn các giá trị nguyên tử và cấu trúc dữ liệu phức tạp, đồng thời cung cấp một API an toàn và dễ sử dụng hơn cho các nhà phát triển. Đây là một bước tiến quan trọng trong việc cải thiện hiệu suất và khả năng mở rộng của Java.&lt;/p&gt;</description></item><item><title>Newsletter #22</title><link>https://miti99.com/post/2025/05/09/</link><pubDate>Fri, 09 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/09/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #22.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="identity-tokens-best-practices"&gt;&lt;a class="link" href="https://www.permit.io/blog/identity-tokens-best-practices" target="_blank" rel="noopener"
&gt;Identity Tokens Best Practices&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ Permit.io đi sâu vào các phương pháp tốt nhất cho việc quản lý và sử dụng identity tokens trong các hệ thống xác thực hiện đại. Identity tokens đóng vai trò quan trọng trong việc xác minh danh tính người dùng và bảo vệ tài nguyên số.&lt;/p&gt;
&lt;p&gt;Bài viết trình bày các khía cạnh quan trọng của identity tokens, bao gồm cách thiết kế, triển khai và quản lý chúng một cách an toàn. Các phương pháp tốt nhất được đề cập bao gồm việc sử dụng các chuẩn mở như OAuth 2.0 và OpenID Connect, áp dụng mã hóa mạnh, thiết lập thời gian hết hạn hợp lý, và triển khai cơ chế làm mới token hiệu quả.&lt;/p&gt;
&lt;p&gt;Tác giả cũng thảo luận về các vấn đề bảo mật phổ biến liên quan đến identity tokens như lộ token, tấn công XSS, CSRF, và cách phòng tránh chúng. Bài viết nhấn mạnh tầm quan trọng của việc áp dụng nguyên tắc đặc quyền tối thiểu (principle of least privilege) và cách thức triển khai xác thực đa yếu tố để tăng cường bảo mật.&lt;/p&gt;
&lt;p&gt;Đối với các nhà phát triển và kiến trúc sư hệ thống, bài viết cung cấp những hướng dẫn thực tế về cách thiết kế hệ thống xác thực có tính bảo mật cao, đồng thời vẫn đảm bảo trải nghiệm người dùng tốt. Các ví dụ cụ thể và mã nguồn minh họa giúp người đọc dễ dàng áp dụng các khái niệm vào dự án thực tế của mình.&lt;/p&gt;
&lt;h2 id="tactical-work-in-the-age-of-layoffs"&gt;&lt;a class="link" href="https://www.seangoedecke.com/tactical-work-in-the-age-of-layoffs" target="_blank" rel="noopener"
&gt;Tactical Work in the Age of Layoffs&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ Sean Goedecke phân tích chiến lược làm việc hiệu quả trong thời đại sa thải hàng loạt đang diễn ra trong ngành công nghệ. Tác giả đưa ra góc nhìn thực tế về cách các chuyên gia công nghệ có thể điều hướng sự nghiệp của mình trong môi trường làm việc bất ổn hiện nay.&lt;/p&gt;
&lt;p&gt;Bài viết phân biệt giữa công việc chiến lược (strategic work) - những dự án dài hạn, có tầm nhìn xa, và công việc chiến thuật (tactical work) - những nhiệm vụ ngắn hạn, có kết quả cụ thể và dễ nhìn thấy. Trong bối cảnh kinh tế không chắc chắn và các đợt sa thải diễn ra thường xuyên, tác giả lập luận rằng việc cân bằng giữa hai loại công việc này trở nên quan trọng hơn bao giờ hết.&lt;/p&gt;
&lt;p&gt;Tác giả đề xuất một số chiến lược thực tế để tồn tại và phát triển trong môi trường làm việc hiện đại:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ưu tiên các công việc có tính hiển thị cao và tạo ra giá trị ngắn hạn rõ ràng&lt;/li&gt;
&lt;li&gt;Xây dựng danh tiếng là người giải quyết vấn đề hiệu quả và đáng tin cậy&lt;/li&gt;
&lt;li&gt;Tài liệu hóa các thành tựu và đóng góp một cách có hệ thống&lt;/li&gt;
&lt;li&gt;Phát triển kỹ năng truyền thông để làm nổi bật giá trị của công việc bạn đang làm&lt;/li&gt;
&lt;li&gt;Duy trì mạng lưới quan hệ chuyên nghiệp bên trong và ngoài tổ chức&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết cũng thảo luận về cách tiếp cận đạo đức đối với chiến thuật này, nhấn mạnh rằng mục tiêu không phải là tạo ra vẻ ngoài giả tạo về năng suất, mà là đảm bảo rằng giá trị thực sự của công việc bạn làm được công nhận đúng mức.&lt;/p&gt;
&lt;p&gt;Đối với các chuyên gia công nghệ, bài viết cung cấp những hướng dẫn thiết thực về cách điều chỉnh phương pháp làm việc để thích ứng với thực tế mới của thị trường lao động, đồng thời vẫn duy trì sự toàn vẹn chuyên môn và phát triển sự nghiệp lâu dài.&lt;/p&gt;
&lt;h2 id="tracing-thoughts-in-language-model"&gt;&lt;a class="link" href="https://www.anthropic.com/research/tracing-thoughts-language-model" target="_blank" rel="noopener"
&gt;Tracing Thoughts in Language Model&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài nghiên cứu này từ Anthropic trình bày một phương pháp mới để theo dõi và phân tích quá trình &amp;ldquo;suy nghĩ&amp;rdquo; bên trong các mô hình ngôn ngữ lớn (LLMs). Các nhà nghiên cứu đã phát triển một kỹ thuật gọi là &amp;ldquo;thought tracing&amp;rdquo; cho phép quan sát chi tiết cách các mô hình xử lý thông tin và đưa ra quyết định.&lt;/p&gt;
&lt;p&gt;Nghiên cứu chỉ ra rằng các mô hình ngôn ngữ không chỉ đơn thuần tạo ra văn bản dựa trên xác suất, mà còn thể hiện các mẫu xử lý thông tin phức tạp tương tự như quá trình suy luận. Bằng cách phân tích các biểu diễn nội bộ (internal representations) của mô hình trong quá trình sinh văn bản, các tác giả đã có thể xác định các &amp;ldquo;dòng suy nghĩ&amp;rdquo; riêng biệt và theo dõi cách chúng phát triển.&lt;/p&gt;
&lt;p&gt;Một phát hiện quan trọng là các mô hình thường xây dựng nhiều dòng suy nghĩ song song trước khi hội tụ vào câu trả lời cuối cùng. Điều này giống với cách con người cân nhắc nhiều khả năng trước khi đưa ra quyết định. Nghiên cứu cũng chỉ ra rằng các mô hình có khả năng &amp;ldquo;tự sửa lỗi&amp;rdquo; bằng cách điều chỉnh các dòng suy nghĩ không chính xác trong quá trình suy luận.&lt;/p&gt;
&lt;p&gt;Phương pháp thought tracing mở ra nhiều hướng ứng dụng quan trọng, bao gồm:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Cải thiện khả năng giải thích được của AI (AI explainability)&lt;/li&gt;
&lt;li&gt;Phát hiện và giảm thiểu các sai lệch (biases) trong quá trình suy luận&lt;/li&gt;
&lt;li&gt;Tối ưu hóa hiệu suất của mô hình bằng cách hiểu rõ hơn cơ chế hoạt động bên trong&lt;/li&gt;
&lt;li&gt;Phát triển các phương pháp huấn luyện mới dựa trên hiểu biết sâu sắc về quá trình suy nghĩ của mô hình&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Đối với các nhà nghiên cứu và kỹ sư AI, nghiên cứu này cung cấp một công cụ mới để &amp;ldquo;mở hộp đen&amp;rdquo; của các mô hình ngôn ngữ lớn, giúp phát triển các hệ thống AI an toàn, đáng tin cậy và hiệu quả hơn trong tương lai.&lt;/p&gt;
&lt;h2 id="why-duplicating-environments-for-microservices-backfires"&gt;&lt;a class="link" href="https://www.signadot.com/blog/why-duplicating-environments-for-microservices-backfires" target="_blank" rel="noopener"
&gt;Why Duplicating Environments for Microservices Backfires&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ Signadot phân tích lý do tại sao chiến lược nhân bản môi trường phát triển cho microservices thường không mang lại hiệu quả như mong đợi. Đây là một vấn đề phổ biến mà nhiều tổ chức gặp phải khi mở rộng kiến trúc microservices của họ.&lt;/p&gt;
&lt;p&gt;Tác giả chỉ ra rằng mặc dù việc tạo ra các môi trường phát triển riêng biệt cho từng nhóm hoặc dự án có vẻ là giải pháp hợp lý để tránh xung đột và tăng tốc độ phát triển, nhưng chiến lược này thường dẫn đến nhiều vấn đề nghiêm trọng. Các thách thức chính bao gồm chi phí cơ sở hạ tầng tăng cao, sự phức tạp trong quản lý, và sự khác biệt ngày càng lớn giữa môi trường phát triển và môi trường sản xuất.&lt;/p&gt;
&lt;p&gt;Bài viết đi sâu vào phân tích các hậu quả tiêu cực của việc nhân bản môi trường:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Chi phí tài nguyên tăng theo cấp số nhân khi số lượng microservices và nhóm phát triển tăng lên&lt;/li&gt;
&lt;li&gt;Thời gian thiết lập và bảo trì các môi trường trở nên quá lớn, làm giảm năng suất thực tế&lt;/li&gt;
&lt;li&gt;Các lỗi &amp;ldquo;chỉ xảy ra trong môi trường sản xuất&amp;rdquo; vẫn tồn tại do không thể sao chép chính xác tất cả các điều kiện&lt;/li&gt;
&lt;li&gt;Khó khăn trong việc kiểm thử tích hợp giữa các dịch vụ do môi trường bị phân mảnh&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Thay vì nhân bản toàn bộ môi trường, tác giả đề xuất các phương pháp tiếp cận hiện đại hơn như:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Sử dụng kỹ thuật &amp;ldquo;ephemeral environments&amp;rdquo; (môi trường tạm thời) được tạo theo yêu cầu và hủy sau khi hoàn thành&lt;/li&gt;
&lt;li&gt;Áp dụng &amp;ldquo;service sandboxing&amp;rdquo; để cô lập các thay đổi mà không cần nhân bản toàn bộ hệ thống&lt;/li&gt;
&lt;li&gt;Triển khai các công cụ giả lập và mô phỏng thông minh để kiểm thử các tương tác giữa các dịch vụ&lt;/li&gt;
&lt;li&gt;Xây dựng chiến lược kiểm thử tích hợp liên tục tập trung vào các ranh giới giữa các dịch vụ&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Đối với các tổ chức đang vận hành kiến trúc microservices, bài viết cung cấp những hướng dẫn thực tế để cải thiện quy trình phát triển, giảm chi phí cơ sở hạ tầng, và tăng tốc độ phát triển mà không cần phải nhân bản toàn bộ môi trường cho mỗi nhóm hoặc dự án.&lt;/p&gt;
&lt;h2 id="logging-practices-i-follow"&gt;&lt;a class="link" href="https://www.16elt.com/2023/01/06/logging-practices-I-follow" target="_blank" rel="noopener"
&gt;Logging Practices I Follow&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này chia sẻ các phương pháp và nguyên tắc ghi log hiệu quả mà tác giả đã áp dụng trong quá trình phát triển phần mềm. Ghi log là một khía cạnh quan trọng nhưng thường bị đánh giá thấp trong quá trình phát triển, vận hành và bảo trì hệ thống.&lt;/p&gt;
&lt;p&gt;Tác giả trình bày một cách có hệ thống các nguyên tắc ghi log tốt, bắt đầu từ việc phân loại các cấp độ log (DEBUG, INFO, WARN, ERROR, FATAL) và khi nào nên sử dụng mỗi cấp độ. Bài viết nhấn mạnh tầm quan trọng của việc cung cấp đủ ngữ cảnh trong mỗi thông điệp log, giúp các kỹ sư dễ dàng hiểu được chính xác điều gì đang xảy ra khi phân tích log.&lt;/p&gt;
&lt;p&gt;Một số phương pháp hay được đề cập bao gồm:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Sử dụng định dạng có cấu trúc (structured logging) thay vì văn bản thuần túy, giúp dễ dàng phân tích và tìm kiếm&lt;/li&gt;
&lt;li&gt;Bao gồm thông tin định danh giao dịch (transaction IDs) để theo dõi luồng xử lý xuyên suốt hệ thống&lt;/li&gt;
&lt;li&gt;Ghi log các sự kiện quan trọng trong vòng đời ứng dụng như khởi động, tắt, và thay đổi cấu hình&lt;/li&gt;
&lt;li&gt;Cân bằng giữa lượng thông tin và hiệu suất, tránh ghi log quá nhiều dẫn đến &amp;ldquo;log noise&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Sử dụng các công cụ tập trung hóa để thu thập, lưu trữ và phân tích log&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tác giả cũng thảo luận về các kỹ thuật nâng cao như log rotation, log aggregation, và cách tích hợp logging với các hệ thống giám sát và cảnh báo. Bài viết còn đề cập đến các vấn đề bảo mật liên quan đến log, như việc tránh ghi lại thông tin nhạy cảm và tuân thủ các quy định về bảo vệ dữ liệu.&lt;/p&gt;
&lt;p&gt;Đối với các nhà phát triển phần mềm, bài viết cung cấp một bộ hướng dẫn thực tế để triển khai chiến lược logging hiệu quả, giúp cải thiện khả năng gỡ lỗi, phân tích hiệu suất và đảm bảo độ tin cậy của hệ thống trong môi trường sản xuất.&lt;/p&gt;
&lt;h2 id="sync-and-async"&gt;&lt;a class="link" href="https://blogs.newardassociates.com/blog/2025/sync-and-async.html" target="_blank" rel="noopener"
&gt;Sync and Async&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ Ted Neward phân tích sâu sắc về hai mô hình lập trình cơ bản: đồng bộ (synchronous) và bất đồng bộ (asynchronous). Tác giả không chỉ giải thích sự khác biệt kỹ thuật giữa hai mô hình mà còn đi sâu vào các tình huống thực tế khi nên áp dụng mỗi mô hình.&lt;/p&gt;
&lt;p&gt;Trong phần đầu, bài viết làm rõ các khái niệm cơ bản: lập trình đồng bộ là mô hình trong đó các tác vụ được thực hiện tuần tự, mỗi tác vụ phải đợi tác vụ trước hoàn thành; trong khi lập trình bất đồng bộ cho phép các tác vụ chạy độc lập, không cần đợi nhau hoàn thành. Tác giả đặc biệt nhấn mạnh rằng không có mô hình nào &amp;ldquo;tốt hơn&amp;rdquo; một cách tuyệt đối - mỗi mô hình đều có những ưu điểm và nhược điểm riêng tùy thuộc vào bối cảnh sử dụng.&lt;/p&gt;
&lt;p&gt;Phần tiếp theo của bài viết đi sâu vào phân tích các trường hợp sử dụng phù hợp cho mỗi mô hình:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Lập trình đồng bộ phù hợp với các tác vụ đơn giản, yêu cầu xử lý tuần tự, hoặc các hệ thống có tính nhất quán cao&lt;/li&gt;
&lt;li&gt;Lập trình bất đồng bộ phù hợp với các ứng dụng cần phản hồi nhanh, xử lý nhiều tác vụ cùng lúc, hoặc các hệ thống phân tán&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tác giả cũng thảo luận về các thách thức khi làm việc với mã bất đồng bộ, bao gồm khó khăn trong việc gỡ lỗi, xử lý ngoại lệ phức tạp, và các vấn đề về race condition. Bài viết cung cấp các chiến lược để giải quyết những thách thức này, như sử dụng các mẫu thiết kế phù hợp, áp dụng các công cụ giám sát và theo dõi, và thiết kế hệ thống có khả năng phục hồi từ lỗi.&lt;/p&gt;
&lt;p&gt;Đặc biệt hữu ích là phần so sánh cách triển khai bất đồng bộ trong các ngôn ngữ và framework khác nhau, từ callbacks trong JavaScript, async/await trong C# và Python, đến các thư viện reactive như RxJava và Project Reactor. Tác giả cung cấp các ví dụ mã nguồn cụ thể và phân tích ưu nhược điểm của mỗi cách tiếp cận.&lt;/p&gt;
&lt;p&gt;Đối với các nhà phát triển phần mềm, bài viết này là một tài nguyên quý giá giúp hiểu rõ hơn về hai mô hình lập trình cơ bản, từ đó có thể đưa ra quyết định sáng suốt khi thiết kế và phát triển các hệ thống phần mềm hiện đại.&lt;/p&gt;
&lt;h2 id="making-uber"&gt;&lt;a class="link" href="https://www.uber.com/en-IN/blog/making-ubers-experiment-evaluation-engine-100x-faster/" target="_blank" rel="noopener"
&gt;Making Uber&amp;rsquo;s Experiment Evaluation Engine 100x Faster&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ đội kỹ thuật của Uber mô tả quá trình cải tiến đáng kinh ngạc của họ trong việc tối ưu hóa hệ thống đánh giá thử nghiệm, giúp tăng tốc độ xử lý lên 100 lần. Đây là một trường hợp nghiên cứu thực tế về cách áp dụng các kỹ thuật kỹ thuật phần mềm và khoa học dữ liệu để giải quyết các thách thức hiệu suất quy mô lớn.&lt;/p&gt;
&lt;p&gt;Uber tiến hành hàng nghìn thử nghiệm A/B mỗi năm để cải thiện sản phẩm và dịch vụ của họ. Tuy nhiên, hệ thống đánh giá thử nghiệm ban đầu của họ gặp phải vấn đề nghiêm trọng về hiệu suất khi khối lượng dữ liệu và số lượng thử nghiệm tăng lên. Bài viết mô tả chi tiết hành trình của đội kỹ thuật trong việc xác định các điểm nghẽn và triển khai các giải pháp sáng tạo.&lt;/p&gt;
&lt;p&gt;Các kỹ thuật tối ưu hóa chính được đề cập trong bài viết bao gồm:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Thiết kế lại kiến trúc xử lý dữ liệu để tận dụng tính song song và phân tán&lt;/li&gt;
&lt;li&gt;Áp dụng các thuật toán thống kê hiệu quả hơn cho việc tính toán các chỉ số thử nghiệm&lt;/li&gt;
&lt;li&gt;Tối ưu hóa lưu trữ và truy xuất dữ liệu thông qua các kỹ thuật nén và lập chỉ mục thông minh&lt;/li&gt;
&lt;li&gt;Triển khai cơ chế cache nhiều lớp để giảm thiểu tính toán lặp lại&lt;/li&gt;
&lt;li&gt;Sử dụng các kỹ thuật tính toán xấp xỉ khi độ chính xác tuyệt đối không cần thiết&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Đặc biệt ấn tượng là cách đội ngũ Uber đã kết hợp các cải tiến ở nhiều cấp độ khác nhau, từ tối ưu hóa cấp thấp của mã nguồn đến các quyết định kiến trúc cấp cao. Bài viết cũng thảo luận về các thách thức trong việc duy trì tính chính xác thống kê trong khi cải thiện hiệu suất đáng kể.&lt;/p&gt;
&lt;p&gt;Đối với các kỹ sư dữ liệu, nhà phát triển phần mềm và các nhà khoa học dữ liệu, bài viết này cung cấp những bài học quý giá về cách tiếp cận các vấn đề hiệu suất trong các hệ thống xử lý dữ liệu quy mô lớn. Các nguyên tắc và kỹ thuật được trình bày có thể áp dụng cho nhiều loại hệ thống khác nhau, không chỉ giới hạn trong lĩnh vực đánh giá thử nghiệm.&lt;/p&gt;</description></item><item><title>Newsletter #21</title><link>https://miti99.com/post/2025/05/08/</link><pubDate>Thu, 08 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/08/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #21.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="how-to-monitor-jvm"&gt;&lt;a class="link" href="https://www.baeldung.com/java-jvm-monitor-non-heap-memory-usage" target="_blank" rel="noopener"
&gt;How to Monitor JVM&amp;rsquo;s Non-Heap Memory Usage&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ Baeldung giới thiệu cách theo dõi và quản lý bộ nhớ non-heap trong JVM, một phần quan trọng nhưng thường bị bỏ qua trong quá trình tối ưu hóa ứng dụng Java.&lt;/p&gt;
&lt;p&gt;Khác với heap memory được sử dụng để lưu trữ các đối tượng Java, non-heap memory chứa các thành phần quan trọng như Metaspace (thay thế PermGen từ Java 8), Code Cache (lưu trữ mã đã biên dịch JIT), và các vùng nhớ thread-specific như Thread Stacks. Việc theo dõi và quản lý đúng cách các vùng nhớ này có thể giúp ngăn ngừa các vấn đề như OutOfMemoryError và cải thiện hiệu suất ứng dụng.&lt;/p&gt;
&lt;p&gt;Bài viết trình bày nhiều phương pháp để theo dõi non-heap memory:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sử dụng JMX (Java Management Extensions)&lt;/strong&gt;: Cung cấp API để truy cập các thông tin quản lý JVM, bao gồm MemoryMXBean và MemoryPoolMXBean để theo dõi các vùng nhớ khác nhau.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sử dụng công cụ giám sát JVM&lt;/strong&gt;: Như JConsole, VisualVM, và Java Mission Control, cung cấp giao diện đồ họa để theo dõi bộ nhớ và các tài nguyên JVM khác.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sử dụng các công cụ dòng lệnh&lt;/strong&gt;: Như jstat, jcmd, và jmap, cho phép theo dõi bộ nhớ từ terminal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tích hợp với các hệ thống giám sát&lt;/strong&gt;: Như Prometheus, Grafana, hoặc các APM (Application Performance Monitoring) như New Relic và Dynatrace.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết cũng đề cập đến các chiến lược để quản lý non-heap memory hiệu quả, bao gồm việc điều chỉnh các tham số JVM như MaxMetaspaceSize và ReservedCodeCacheSize, cũng như các kỹ thuật để giảm thiểu việc sử dụng bộ nhớ không cần thiết.&lt;/p&gt;
&lt;p&gt;Đối với các ứng dụng Java quy mô lớn hoặc các hệ thống chạy trong môi trường có tài nguyên hạn chế, việc hiểu và quản lý đúng cách non-heap memory là một kỹ năng quan trọng giúp đảm bảo ứng dụng hoạt động ổn định và hiệu quả trong thời gian dài.&lt;/p&gt;
&lt;h2 id="unlocking-the-power-of-interfaces-creative-approaches-in-java"&gt;&lt;a class="link" href="https://gainjavaknowledge.medium.com/unlocking-the-power-of-interfaces-creative-approaches-in-java-635f390a1e0d" target="_blank" rel="noopener"
&gt;Unlocking the Power of Interfaces: Creative Approaches in Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ Gain Java Knowledge trên Medium khám phá các cách tiếp cận sáng tạo khi sử dụng interfaces trong Java, một tính năng mạnh mẽ nhưng thường chưa được khai thác hết tiềm năng.&lt;/p&gt;
&lt;p&gt;Interfaces trong Java không chỉ đơn thuần là một cơ chế để định nghĩa hợp đồng (contract) giữa các lớp, mà còn là công cụ linh hoạt cho phép thiết kế code có tính mở rộng cao. Bài viết đi sâu vào các kỹ thuật nâng cao và các trường hợp sử dụng sáng tạo của interfaces, vượt xa cách sử dụng truyền thống.&lt;/p&gt;
&lt;p&gt;Một số điểm nổi bật trong bài viết bao gồm:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Default methods và Static methods&lt;/strong&gt;: Từ Java 8, interfaces có thể chứa các phương thức có triển khai mặc định và các phương thức tĩnh, mở ra nhiều khả năng mới trong thiết kế API và tái sử dụng code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Functional interfaces và Lambda expressions&lt;/strong&gt;: Cách interfaces với một phương thức duy nhất (functional interfaces) kết hợp với biểu thức lambda tạo nên cú pháp ngắn gọn và mạnh mẽ cho lập trình hàm trong Java.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Marker interfaces và Annotation&lt;/strong&gt;: So sánh giữa marker interfaces truyền thống (như Serializable, Cloneable) với annotations, và khi nào nên sử dụng cái nào.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Interface inheritance và Multiple inheritance&lt;/strong&gt;: Cách Java sử dụng interfaces để giải quyết vấn đề đa kế thừa, tránh được &amp;ldquo;diamond problem&amp;rdquo; mà vẫn đạt được tính linh hoạt cao.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Interface-based programming&lt;/strong&gt;: Phương pháp lập trình hướng đến interface thay vì implementation, giúp code dễ mở rộng, dễ test và dễ bảo trì hơn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sealed interfaces&lt;/strong&gt;: Tính năng mới từ Java 17, cho phép kiểm soát chặt chẽ hơn các lớp có thể implement một interface.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết cũng đưa ra nhiều ví dụ thực tế về cách các framework và thư viện Java phổ biến như Spring, Hibernate, và Java Collections Framework sử dụng interfaces một cách sáng tạo để xây dựng các API mạnh mẽ và linh hoạt.&lt;/p&gt;
&lt;p&gt;Đối với các lập trình viên Java, việc nắm vững và áp dụng sáng tạo interfaces không chỉ giúp viết code tốt hơn mà còn mở ra nhiều khả năng thiết kế hệ thống phần mềm có tính mở rộng cao, dễ bảo trì và thích ứng với các yêu cầu thay đổi trong tương lai.&lt;/p&gt;
&lt;h2 id="how-java-manages-thread-synchronization-with-locks-and-monitors"&gt;&lt;a class="link" href="https://medium.com/@AlexanderObregon/how-java-manages-thread-synchronization-with-locks-and-monitors-541ce7c7a0b2" target="_blank" rel="noopener"
&gt;How Java Manages Thread Synchronization with Locks and Monitors&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ Alexander Obregon trên Medium đi sâu vào cơ chế đồng bộ hóa thread trong Java thông qua việc sử dụng locks và monitors, một khía cạnh quan trọng trong lập trình đa luồng.&lt;/p&gt;
&lt;p&gt;Trong môi trường đa luồng của Java, việc nhiều thread cùng truy cập và sửa đổi dữ liệu chia sẻ có thể dẫn đến các vấn đề như race condition, deadlock, và dữ liệu không nhất quán. Java cung cấp các cơ chế đồng bộ hóa để giải quyết những thách thức này, với hai khái niệm cốt lõi là locks và monitors.&lt;/p&gt;
&lt;p&gt;Bài viết giải thích rằng mỗi đối tượng trong Java đều có một monitor liên kết với nó, hoạt động như một cơ chế khóa để kiểm soát việc truy cập vào đối tượng đó. Khi một thread gọi phương thức được đánh dấu là &lt;code&gt;synchronized&lt;/code&gt;, nó sẽ cố gắng có được quyền sở hữu monitor của đối tượng. Nếu monitor đã bị chiếm bởi thread khác, thread hiện tại sẽ bị chặn cho đến khi monitor được giải phóng.&lt;/p&gt;
&lt;p&gt;Một số điểm quan trọng được đề cập trong bài viết:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Intrinsic Locks (Synchronized)&lt;/strong&gt;: Java cung cấp từ khóa &lt;code&gt;synchronized&lt;/code&gt; để đánh dấu các khối mã hoặc phương thức cần được đồng bộ hóa. Khi một thread thực thi mã trong khối synchronized, nó sẽ giữ khóa của đối tượng cho đến khi hoàn thành.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Explicit Locks (ReentrantLock)&lt;/strong&gt;: Từ Java 5, gói &lt;code&gt;java.util.concurrent.locks&lt;/code&gt; giới thiệu các lớp khóa rõ ràng như &lt;code&gt;ReentrantLock&lt;/code&gt;, cung cấp nhiều tính năng hơn so với synchronized, bao gồm khả năng timeout, khóa công bằng, và khả năng hủy bỏ.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Wait/Notify Mechanism&lt;/strong&gt;: Cơ chế này cho phép các thread giao tiếp với nhau. Một thread có thể gọi &lt;code&gt;wait()&lt;/code&gt; để tạm thời giải phóng khóa và chờ đợi, trong khi thread khác có thể gọi &lt;code&gt;notify()&lt;/code&gt; hoặc &lt;code&gt;notifyAll()&lt;/code&gt; để đánh thức các thread đang chờ.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Volatile Keyword&lt;/strong&gt;: Từ khóa &lt;code&gt;volatile&lt;/code&gt; đảm bảo rằng các thay đổi đối với một biến được hiển thị ngay lập tức cho tất cả các thread, giúp tránh các vấn đề về visibility trong môi trường đa luồng.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Atomic Variables&lt;/strong&gt;: Các lớp trong gói &lt;code&gt;java.util.concurrent.atomic&lt;/code&gt; cung cấp các hoạt động nguyên tử không cần khóa, giúp cải thiện hiệu suất trong một số trường hợp.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết cũng thảo luận về các vấn đề phổ biến trong lập trình đa luồng như deadlock (khi hai thread chờ đợi lẫn nhau), livelock (khi các thread liên tục phản ứng với nhau mà không tiến triển), và starvation (khi một thread không bao giờ nhận được tài nguyên cần thiết).&lt;/p&gt;
&lt;p&gt;Đối với các lập trình viên Java, việc hiểu rõ cách hoạt động của locks và monitors là nền tảng quan trọng để phát triển các ứng dụng đa luồng hiệu quả và an toàn. Bài viết này cung cấp một cái nhìn tổng quan về các cơ chế đồng bộ hóa trong Java, từ cơ bản đến nâng cao, giúp lập trình viên có thể áp dụng chúng một cách thích hợp trong các tình huống khác nhau.&lt;/p&gt;
&lt;h2 id="building-a-custom-spring-boot-starter-for-shared-logic"&gt;&lt;a class="link" href="https://medium.com/@AlexanderObregon/building-a-custom-spring-boot-starter-for-shared-logic-9be5699aff18" target="_blank" rel="noopener"
&gt;Building a Custom Spring Boot Starter for Shared Logic&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ Alexander Obregon trên Medium hướng dẫn cách xây dựng một Spring Boot starter tùy chỉnh để chia sẻ logic chung giữa nhiều microservices, một kỹ thuật quan trọng trong việc phát triển các ứng dụng doanh nghiệp hiện đại.&lt;/p&gt;
&lt;p&gt;Spring Boot starters là một trong những tính năng mạnh mẽ nhất của Spring Boot, cho phép tích hợp các thành phần và cấu hình theo cơ chế &amp;ldquo;plug-and-play&amp;rdquo;. Khi phát triển nhiều microservices có chung các thành phần như xác thực, logging, xử lý ngoại lệ, hoặc các utility classes, việc tạo một starter riêng giúp tái sử dụng code hiệu quả và đảm bảo tính nhất quán trong toàn bộ hệ thống.&lt;/p&gt;
&lt;p&gt;Bài viết trình bày quy trình xây dựng một Spring Boot starter từ đầu với các bước chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thiết kế cấu trúc dự án&lt;/strong&gt;: Tạo một dự án Maven/Gradle với cấu trúc phù hợp, bao gồm các module core và autoconfigure.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phát triển các thành phần chính&lt;/strong&gt;: Xây dựng các service, configuration, và utility classes cần được chia sẻ.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tạo auto-configuration&lt;/strong&gt;: Sử dụng các annotation như &lt;code&gt;@Configuration&lt;/code&gt;, &lt;code&gt;@ConditionalOnClass&lt;/code&gt;, và &lt;code&gt;@EnableConfigurationProperties&lt;/code&gt; để tự động cấu hình các bean khi starter được thêm vào một dự án.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định nghĩa metadata&lt;/strong&gt;: Tạo file &lt;code&gt;spring.factories&lt;/code&gt; để đăng ký các auto-configuration classes với Spring Boot.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cung cấp cấu hình mặc định&lt;/strong&gt;: Sử dụng &lt;code&gt;application.properties&lt;/code&gt; hoặc &lt;code&gt;application.yml&lt;/code&gt; để định nghĩa các giá trị mặc định, có thể được ghi đè bởi ứng dụng sử dụng starter.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đóng gói và phân phối&lt;/strong&gt;: Đóng gói starter dưới dạng artifact Maven/Gradle và phân phối thông qua repository nội bộ hoặc Maven Central.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết cũng đề cập đến các best practices quan trọng khi phát triển starter:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tuân thủ nguyên tắc &amp;ldquo;opinionated defaults, but configurable&amp;rdquo; của Spring Boot&lt;/li&gt;
&lt;li&gt;Sử dụng các điều kiện (conditions) để kích hoạt cấu hình chỉ khi cần thiết&lt;/li&gt;
&lt;li&gt;Cung cấp tài liệu đầy đủ về cách sử dụng và cấu hình starter&lt;/li&gt;
&lt;li&gt;Thiết kế API sạch và dễ sử dụng cho người dùng cuối&lt;/li&gt;
&lt;li&gt;Tạo các test toàn diện để đảm bảo starter hoạt động như mong đợi&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Đối với các tổ chức phát triển nhiều ứng dụng Spring Boot, việc đầu tư vào việc xây dựng các starter tùy chỉnh có thể mang lại lợi ích đáng kể về mặt bảo trì, tính nhất quán, và tốc độ phát triển. Bài viết này cung cấp một hướng dẫn thực tế giúp các lập trình viên Java có thể áp dụng ngay kỹ thuật này vào dự án của mình.&lt;/p&gt;
&lt;h2 id="real-world-garbage-collection-solutions"&gt;&lt;a class="link" href="https://dzone.com/articles/real-world-garbage-collection-solutions" target="_blank" rel="noopener"
&gt;Real-World Garbage Collection Solutions&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ DZone đi sâu vào các giải pháp thực tế cho việc quản lý Garbage Collection (GC) trong các ứng dụng Java quy mô lớn, một vấn đề quan trọng mà nhiều đội phát triển phải đối mặt khi triển khai hệ thống vào môi trường sản xuất.&lt;/p&gt;
&lt;p&gt;Garbage Collection trong Java là quá trình tự động giải phóng bộ nhớ không còn được sử dụng, nhưng nếu không được cấu hình và tối ưu hóa đúng cách, nó có thể gây ra các vấn đề hiệu suất nghiêm trọng như độ trễ cao, stop-the-world pauses, và thậm chí là OutOfMemoryError. Bài viết trình bày các chiến lược và giải pháp thực tế để giải quyết những thách thức này.&lt;/p&gt;
&lt;p&gt;Một số điểm chính được đề cập trong bài viết:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lựa chọn Garbage Collector phù hợp&lt;/strong&gt;: So sánh các loại GC có sẵn trong JVM như Serial, Parallel, CMS (Concurrent Mark Sweep), G1 (Garbage First), ZGC, và Shenandoah, với phân tích về ưu và nhược điểm của từng loại trong các tình huống khác nhau.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Điều chỉnh tham số JVM&lt;/strong&gt;: Hướng dẫn cách tinh chỉnh các tham số JVM quan trọng như heap size, generation sizes, và GC-specific flags để tối ưu hóa hiệu suất GC cho từng loại ứng dụng.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phân tích GC logs&lt;/strong&gt;: Cách bật và phân tích GC logs để xác định các vấn đề tiềm ẩn, với các công cụ và kỹ thuật để trực quan hóa dữ liệu GC.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xử lý memory leaks&lt;/strong&gt;: Phương pháp phát hiện và khắc phục memory leaks, bao gồm việc sử dụng các công cụ như JVisualVM, MAT (Memory Analyzer Tool), và JProfiler.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược phân bổ đối tượng&lt;/strong&gt;: Các kỹ thuật để giảm thiểu việc tạo đối tượng không cần thiết, sử dụng object pooling, và tối ưu hóa cấu trúc dữ liệu để giảm áp lực lên GC.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giải pháp cho microservices&lt;/strong&gt;: Cách tiếp cận GC trong kiến trúc microservices, với việc cân nhắc giữa nhiều JVM nhỏ và ít JVM lớn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Monitoring và alerting&lt;/strong&gt;: Thiết lập hệ thống giám sát GC trong môi trường sản xuất, với các ngưỡng cảnh báo phù hợp để phát hiện sớm các vấn đề.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết cũng chia sẻ các case studies từ các công ty đã thành công trong việc tối ưu hóa GC, giúp giảm đáng kể thời gian dừng ứng dụng và cải thiện trải nghiệm người dùng. Đặc biệt, có một ví dụ về cách một công ty fintech đã giảm 95% thời gian GC pause bằng cách chuyển từ CMS sang ZGC và áp dụng các kỹ thuật phân bổ đối tượng thông minh.&lt;/p&gt;
&lt;p&gt;Đối với các lập trình viên Java và kỹ sư hệ thống, bài viết này cung cấp một bộ công cụ và kiến thức quý giá để xử lý các thách thức GC trong môi trường sản xuất thực tế, giúp đảm bảo ứng dụng hoạt động ổn định và hiệu quả ngay cả dưới tải cao.&lt;/p&gt;
&lt;h2 id="java-naming-conventions"&gt;&lt;a class="link" href="https://www.baeldung.com/java-naming-conventions" target="_blank" rel="noopener"
&gt;Java Naming Conventions&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ Baeldung trình bày chi tiết về các quy ước đặt tên trong Java, một khía cạnh quan trọng của việc viết mã sạch và dễ bảo trì. Tuân thủ các quy ước đặt tên không chỉ giúp code dễ đọc hơn mà còn thúc đẩy tính nhất quán trong các dự án và giữa các lập trình viên.&lt;/p&gt;
&lt;p&gt;Bài viết bao gồm các quy ước đặt tên cho tất cả các thành phần trong mã Java:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quy ước đặt tên package&lt;/strong&gt;: Packages nên được đặt tên bằng chữ thường và sử dụng tên miền đảo ngược làm tiền tố (ví dụ: &lt;code&gt;com.company.project.module&lt;/code&gt;). Điều này giúp đảm bảo tính duy nhất toàn cầu và tổ chức code theo cấu trúc phân cấp logic.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quy ước đặt tên class và interface&lt;/strong&gt;: Classes và interfaces nên sử dụng PascalCase (viết hoa chữ cái đầu của mỗi từ, không có dấu cách), và nên là danh từ hoặc cụm danh từ (ví dụ: &lt;code&gt;Customer&lt;/code&gt;, &lt;code&gt;AccountManager&lt;/code&gt;). Interface có thể bắt đầu bằng chữ &amp;ldquo;I&amp;rdquo; trong một số quy ước, nhưng điều này không phải là tiêu chuẩn trong Java chính thức.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quy ước đặt tên method&lt;/strong&gt;: Methods nên sử dụng camelCase (chữ cái đầu tiên viết thường, các từ tiếp theo viết hoa chữ cái đầu), và nên là động từ hoặc cụm động từ (ví dụ: &lt;code&gt;calculateTotal()&lt;/code&gt;, &lt;code&gt;getUserById()&lt;/code&gt;). Methods thực hiện các hành động nên bắt đầu bằng các động từ như &amp;ldquo;get&amp;rdquo;, &amp;ldquo;set&amp;rdquo;, &amp;ldquo;is&amp;rdquo;, &amp;ldquo;has&amp;rdquo; tùy thuộc vào mục đích của chúng.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quy ước đặt tên biến&lt;/strong&gt;: Biến cũng sử dụng camelCase và nên là danh từ có ý nghĩa mô tả dữ liệu mà chúng chứa. Tên biến nên ngắn gọn nhưng đủ mô tả (ví dụ: &lt;code&gt;firstName&lt;/code&gt;, &lt;code&gt;totalAmount&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quy ước đặt tên hằng số&lt;/strong&gt;: Constants (biến static final) nên sử dụng SCREAMING_SNAKE_CASE (tất cả chữ hoa, các từ ngăn cách bằng dấu gạch dưới), ví dụ: &lt;code&gt;MAX_CONNECTIONS&lt;/code&gt;, &lt;code&gt;DEFAULT_TIMEOUT&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quy ước đặt tên Generic&lt;/strong&gt;: Các tham số kiểu generic thường sử dụng một chữ cái viết hoa, với các quy ước phổ biến như T cho Type, E cho Element, K cho Key, V cho Value, và N cho Number.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quy ước đặt tên Enum&lt;/strong&gt;: Enums nên tuân theo quy ước đặt tên class (PascalCase), trong khi các giá trị enum thường sử dụng SCREAMING_SNAKE_CASE như constants.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết cũng đề cập đến các quy ước đặt tên đặc biệt cho các thành phần khác như annotations, lambda parameters, và các biến cục bộ ngắn. Ngoài ra, còn có các hướng dẫn về việc sử dụng các từ viết tắt, tiền tố và hậu tố, cũng như các thực hành tốt nhất để đảm bảo tính rõ ràng và nhất quán.&lt;/p&gt;
&lt;p&gt;Tuân thủ các quy ước đặt tên này không chỉ giúp code dễ đọc và dễ hiểu hơn, mà còn giúp các công cụ tự động hóa như IDE hoạt động hiệu quả hơn với các tính năng như code completion và refactoring. Đối với các dự án lớn và các nhóm phát triển, việc thiết lập và tuân thủ các quy ước đặt tên nhất quán là một phần quan trọng của quy trình phát triển phần mềm chuyên nghiệp.&lt;/p&gt;
&lt;h2 id="vibe-coding-vs-reality"&gt;&lt;a class="link" href="https://cendyne.dev/posts/2025-03-19-vibe-coding-vs-reality.html" target="_blank" rel="noopener"
&gt;Vibe Coding vs Reality&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ Cendyne đưa ra một cái nhìn phản biện về hiện tượng &amp;ldquo;vibe coding&amp;rdquo; - thuật ngữ mô tả việc sử dụng các công cụ AI để tạo mã mà không cần hiểu sâu về cách hoạt động của nó. Tác giả phân tích khoảng cách giữa lời hứa của AI trong lập trình và thực tế phát triển phần mềm.&lt;/p&gt;
&lt;p&gt;Tác giả bắt đầu bằng việc mô tả trải nghiệm của mình khi sử dụng các công cụ AI như GitHub Copilot và ChatGPT để viết mã. Mặc dù ban đầu ấn tượng với khả năng của chúng trong việc tạo ra mã nhanh chóng, tác giả nhanh chóng nhận ra những hạn chế nghiêm trọng khi áp dụng vào các dự án thực tế phức tạp.&lt;/p&gt;
&lt;p&gt;Một số vấn đề chính được nêu ra trong bài viết:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mã được tạo bởi AI thường thiếu chính xác&lt;/strong&gt;: Các công cụ AI có xu hướng tạo ra mã trông có vẻ hợp lý nhưng chứa lỗi tinh vi hoặc không tuân thủ các yêu cầu cụ thể của dự án.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hiểu biết bề mặt về ngữ cảnh&lt;/strong&gt;: AI có thể nắm bắt cú pháp và mẫu code phổ biến, nhưng thường thiếu hiểu biết sâu sắc về kiến trúc hệ thống, các ràng buộc kinh doanh, và các yếu tố ngữ cảnh khác.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề về bảo trì&lt;/strong&gt;: Mã được tạo bởi AI thường khó bảo trì vì người phát triển có thể không hiểu đầy đủ logic đằng sau nó, dẫn đến &amp;ldquo;nợ kỹ thuật&amp;rdquo; (technical debt) trong dài hạn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ảo tưởng về năng suất&lt;/strong&gt;: Mặc dù AI có thể tăng tốc việc viết mã ban đầu, nhưng thời gian tiết kiệm được thường bị mất đi trong quá trình gỡ lỗi, tái cấu trúc và tối ưu hóa.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tác giả không hoàn toàn bác bỏ giá trị của các công cụ AI trong lập trình, nhưng đề xuất một cách tiếp cận cân bằng hơn:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng AI như một trợ lý, không phải thay thế cho kiến thức và kỹ năng của lập trình viên&lt;/li&gt;
&lt;li&gt;Luôn xem xét kỹ lưỡng và hiểu mã được tạo bởi AI trước khi tích hợp vào dự án&lt;/li&gt;
&lt;li&gt;Đầu tư vào việc học các nguyên tắc cơ bản của lập trình và thiết kế phần mềm&lt;/li&gt;
&lt;li&gt;Sử dụng AI chủ yếu cho các tác vụ lặp đi lặp lại hoặc mẫu code tiêu chuẩn&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết kết luận rằng mặc dù &amp;ldquo;vibe coding&amp;rdquo; có thể hấp dẫn với lời hứa về năng suất tức thì, nhưng phát triển phần mềm chất lượng cao vẫn đòi hỏi sự hiểu biết sâu sắc, tư duy phản biện và kỹ năng giải quyết vấn đề mà hiện tại AI chưa thể thay thế hoàn toàn.&lt;/p&gt;
&lt;h2 id="sell-yourself-sell-your-work"&gt;&lt;a class="link" href="https://www.solipsys.co.uk/new/SellYourselfSellYourWork.html" target="_blank" rel="noopener"
&gt;Sell Yourself, Sell Your Work&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ Richard Heathfield trên Solipsys.co.uk thảo luận về tầm quan trọng của việc quảng bá bản thân và công việc của bạn trong ngành công nghệ, một kỹ năng mà nhiều lập trình viên và kỹ sư phần mềm thường bỏ qua hoặc cảm thấy không thoải mái.&lt;/p&gt;
&lt;p&gt;Tác giả bắt đầu bằng việc chỉ ra rằng nhiều chuyên gia kỹ thuật thường coi việc &amp;ldquo;bán&amp;rdquo; bản thân là điều gì đó tiêu cực hoặc không chuyên nghiệp. Tuy nhiên, trong thực tế, khả năng truyền đạt giá trị của bản thân và công việc của bạn là một kỹ năng quan trọng để phát triển sự nghiệp và đạt được sự công nhận xứng đáng.&lt;/p&gt;
&lt;p&gt;Bài viết đưa ra một số nguyên tắc và chiến lược chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hiểu rõ giá trị của bạn&lt;/strong&gt;: Trước khi có thể quảng bá bản thân hiệu quả, bạn cần hiểu rõ những kỹ năng, kinh nghiệm và giá trị độc đáo mà bạn mang lại. Điều này không phải là tự phóng đại, mà là nhận thức chính xác về những gì bạn có thể đóng góp.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xây dựng thương hiệu cá nhân&lt;/strong&gt;: Phát triển một thương hiệu cá nhân nhất quán trên các nền tảng chuyên nghiệp như LinkedIn, GitHub, và các diễn đàn kỹ thuật. Chia sẻ kiến thức, đóng góp vào các dự án mã nguồn mở, và tham gia vào các cuộc thảo luận chuyên môn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kể câu chuyện thay vì liệt kê thành tích&lt;/strong&gt;: Thay vì chỉ liệt kê các kỹ năng và thành tích, hãy kể câu chuyện về cách bạn giải quyết các vấn đề và tạo ra giá trị. Storytelling là một công cụ mạnh mẽ để làm cho kinh nghiệm của bạn trở nên đáng nhớ và có tác động.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tập trung vào kết quả và tác động&lt;/strong&gt;: Khi trình bày về công việc của bạn, hãy nhấn mạnh vào kết quả cụ thể và tác động đối với dự án, nhóm hoặc tổ chức, không chỉ là các nhiệm vụ bạn đã hoàn thành.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xây dựng mạng lưới quan hệ có mục đích&lt;/strong&gt;: Networking không chỉ là tích lũy số lượng kết nối, mà là xây dựng các mối quan hệ có ý nghĩa dựa trên sự tương tác chân thành và giá trị chung.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vượt qua &amp;ldquo;hội chứng kẻ mạo danh&amp;rdquo; (Impostor Syndrome)&lt;/strong&gt;: Nhiều chuyên gia kỹ thuật giỏi thường cảm thấy không đủ tự tin để quảng bá bản thân. Bài viết cung cấp các chiến lược để vượt qua tâm lý này và nhận ra giá trị thực sự của bản thân.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tác giả cũng đề cập đến sự cân bằng quan trọng giữa khiêm tốn và tự tin, lưu ý rằng việc quảng bá bản thân hiệu quả không đồng nghĩa với việc tự cao hay thiếu khiêm tốn. Thay vào đó, đó là cách để đảm bảo rằng công việc và đóng góp của bạn được công nhận đúng mức.&lt;/p&gt;
&lt;p&gt;Đối với các lập trình viên và kỹ sư phần mềm, bài viết này cung cấp những hướng dẫn thực tế về cách phát triển kỹ năng &amp;ldquo;mềm&amp;rdquo; quan trọng này, giúp họ không chỉ xuất sắc về mặt kỹ thuật mà còn có thể truyền đạt hiệu quả giá trị của mình trong môi trường làm việc ngày càng cạnh tranh.&lt;/p&gt;
&lt;h2 id="building-resilient-payment-systems-at-ssense-our-journey-towards-asynchronous-processing"&gt;&lt;a class="link" href="https://medium.com/ssense-tech/building-resilient-payment-systems-at-ssense-our-journey-towards-asynchronous-processing-56d46dc2b348" target="_blank" rel="noopener"
&gt;Building Resilient Payment Systems at SSENSE: Our Journey Towards Asynchronous Processing&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ đội kỹ thuật của SSENSE chia sẻ hành trình chuyển đổi hệ thống thanh toán của họ từ mô hình xử lý đồng bộ sang xử lý bất đồng bộ, một bước tiến quan trọng trong việc xây dựng hệ thống thanh toán có tính khả dụng và độ tin cậy cao.&lt;/p&gt;
&lt;p&gt;SSENSE, một nền tảng thương mại điện tử thời trang cao cấp toàn cầu, đã phải đối mặt với nhiều thách thức khi hệ thống thanh toán của họ phát triển theo quy mô. Các vấn đề như thời gian phản hồi chậm, lỗi thanh toán trong thời gian cao điểm, và khó khăn trong việc mở rộng hệ thống đã thúc đẩy họ tìm kiếm một giải pháp mới.&lt;/p&gt;
&lt;p&gt;Bài viết mô tả chi tiết quá trình chuyển đổi từ kiến trúc đồng bộ truyền thống sang mô hình xử lý bất đồng bộ dựa trên sự kiện (event-driven asynchronous processing), bao gồm:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phân tích các vấn đề của hệ thống cũ&lt;/strong&gt;: Hệ thống đồng bộ gặp khó khăn khi xử lý khối lượng giao dịch lớn, đặc biệt là trong các đợt sale lớn hoặc Black Friday. Các cuộc gọi API đồng bộ đến các cổng thanh toán bên thứ ba thường gây ra độ trễ cao và điểm nghẽn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thiết kế kiến trúc bất đồng bộ mới&lt;/strong&gt;: Đội kỹ thuật đã thiết kế một hệ thống dựa trên message queue và event sourcing, cho phép tách biệt các bước xử lý thanh toán và thực hiện chúng một cách độc lập.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Triển khai hệ thống sử dụng Kafka&lt;/strong&gt;: Kafka được chọn làm nền tảng message broker chính, với các topic riêng biệt cho từng loại sự kiện thanh toán. Điều này cho phép xử lý song song và cải thiện khả năng mở rộng.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xây dựng cơ chế retry và circuit breaker&lt;/strong&gt;: Để đảm bảo độ tin cậy, hệ thống mới bao gồm các cơ chế retry thông minh, circuit breaker để ngăn chặn lỗi lan truyền, và dead-letter queues để xử lý các giao dịch thất bại.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giám sát và theo dõi&lt;/strong&gt;: Một hệ thống giám sát toàn diện được xây dựng để theo dõi luồng xử lý thanh toán, với các dashboard và cảnh báo để phát hiện sớm các vấn đề tiềm ẩn.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Kết quả của quá trình chuyển đổi này đã mang lại những cải thiện đáng kể:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giảm 70% thời gian phản hồi trung bình cho các giao dịch thanh toán&lt;/li&gt;
&lt;li&gt;Tăng tỷ lệ thành công của giao dịch từ 97% lên 99.9%&lt;/li&gt;
&lt;li&gt;Khả năng xử lý gấp 10 lần khối lượng giao dịch trước đây mà không cần bổ sung tài nguyên đáng kể&lt;/li&gt;
&lt;li&gt;Cải thiện trải nghiệm người dùng với thông báo theo thời gian thực về trạng thái thanh toán&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết cũng chia sẻ các bài học kinh nghiệm quý báu từ quá trình chuyển đổi, bao gồm tầm quan trọng của việc thiết kế hệ thống có khả năng phục hồi từ lỗi, giá trị của việc triển khai từng phần, và cách tiếp cận đúng đắn đối với việc xử lý các trường hợp biên (edge cases) trong hệ thống thanh toán.&lt;/p&gt;
&lt;p&gt;Đối với các kỹ sư phần mềm và kiến trúc sư hệ thống, bài viết này cung cấp một case study thực tế về cách áp dụng các nguyên tắc thiết kế bất đồng bộ để xây dựng hệ thống thanh toán có tính sẵn sàng cao, đặc biệt hữu ích cho các nền tảng thương mại điện tử đang phải đối mặt với các thách thức tương tự.&lt;/p&gt;</description></item><item><title>Newsletter #20</title><link>https://miti99.com/post/2025/05/07/</link><pubDate>Wed, 07 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/07/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #20.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="performance-improvements-in-jdk-24"&gt;&lt;a class="link" href="https://inside.java/2025/03/19/performance-improvements-in-jdk24/" target="_blank" rel="noopener"
&gt;Performance Improvements in JDK 24&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;JDK 24 đã được phát hành với nhiều cải tiến đáng kể về hiệu suất so với các phiên bản trước đó. Bài viết từ Inside.java đã tổng hợp những cải tiến quan trọng nhất trong phiên bản mới này.&lt;/p&gt;
&lt;p&gt;Một trong những cải tiến nổi bật nhất là việc cải thiện Foreign Function &amp;amp; Memory API (FFM API) thông qua việc tối ưu hóa các thao tác bulk như &lt;code&gt;MemorySegment::fill&lt;/code&gt;, &lt;code&gt;MemorySegment::copy&lt;/code&gt; và &lt;code&gt;MemorySegment::mismatch&lt;/code&gt;. Các thao tác này trước đây được thực hiện thông qua các phương thức Unsafe đòi hỏi chuyển đổi từ Java sang mã native. Với JDK 24, hệ thống sẽ kiểm tra kích thước segment và nếu đủ nhỏ, thao tác sẽ được thực hiện bằng mã Java thuần túy thay vì chuyển sang mã native, giúp cải thiện hiệu suất đáng kể.&lt;/p&gt;
&lt;p&gt;JDK 24 cũng giới thiệu một cải tiến quan trọng cho virtual threads thông qua JEP 491, cho phép đồng bộ hóa virtual threads mà không cần pinning. Trước đây, virtual threads bị pinned vào carrier thread của chúng trong quá trình đồng bộ hóa, nhưng giờ đây virtual threads có thể giải phóng carrier thread để các virtual thread khác sử dụng, cải thiện đáng kể khả năng mở rộng của mã Java sử dụng các phương thức và câu lệnh synchronized.&lt;/p&gt;
&lt;p&gt;Những điểm nổi bật khác bao gồm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cải thiện hiệu suất của các thuật toán SHA3 lên đến 27% bằng cách giảm chuyển đổi qua lại giữa mảng byte và mảng long&lt;/li&gt;
&lt;li&gt;Cải thiện ClassFile API đang được hoàn thiện trong JDK 24, với nhiều tối ưu hóa để giảm tác động tiêu cực đến thời gian khởi động&lt;/li&gt;
&lt;li&gt;Tăng tốc String::indexOf khoảng 1.3x cho các nền tảng x64 hỗ trợ AVX2 thông qua mã intrinsic chuyên biệt&lt;/li&gt;
&lt;li&gt;JEP 483: Ahead-of-Time Class Loading &amp;amp; Linking, một phần của Project Leyden, giúp cải thiện thời gian khởi động và warmup&lt;/li&gt;
&lt;li&gt;JEP 450: 8-byte Object Headers (Experimental) giúp giảm kích thước header của object từ 96-128 bit xuống còn 64 bit trên kiến trúc 64-bit, giảm tiêu thụ bộ nhớ từ 10% đến 20% cho các workload thông thường&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ngoài ra, JDK 24 cũng mang đến nhiều cải tiến cho nền tảng RISC-V, bao gồm các intrinsic cho CRC32, Adler32 và tối ưu hóa hiệu suất của các thao tác so sánh chuỗi và đảo byte.&lt;/p&gt;
&lt;p&gt;Với những cải tiến này, JDK 24 tiếp tục khẳng định cam kết của Oracle và cộng đồng OpenJDK trong việc không ngừng cải thiện hiệu suất của Java, giúp ngôn ngữ này vẫn duy trì vị thế mạnh mẽ trong thế giới phát triển phần mềm hiện đại.&lt;/p&gt;
&lt;h2 id="clean-your-memory-from-finalize-to-cleaner"&gt;&lt;a class="link" href="https://blog.frankel.ch/java-cleaner/" target="_blank" rel="noopener"
&gt;Clean your Memory: From Finalize to Cleaner&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Java cung cấp cơ chế Garbage Collection để quản lý bộ nhớ, nhưng cơ chế này không tự động dọn dẹp các tài nguyên ngoài bộ nhớ như socket hay file handle. Nếu không quản lý đúng cách, việc rò rỉ tài nguyên có thể xảy ra, dẫn đến suy giảm hiệu suất hoặc thậm chí crash ứng dụng. Cleaner API, được giới thiệu từ Java 9, cung cấp một cơ chế hiện đại và hiệu quả để dọn dẹp tài nguyên khi đối tượng không còn được tham chiếu.&lt;/p&gt;
&lt;p&gt;Phương thức &lt;code&gt;finalize()&lt;/code&gt; trước đây được sử dụng để giải phóng tài nguyên trước khi đối tượng bị thu gom, nhưng có nhiều vấn đề nghiêm trọng: thời điểm thực thi không thể dự đoán, gây tốn kém hiệu suất, tiềm ẩn nguy cơ rò rỉ bộ nhớ và cơ chế hàng đợi finalization có thể gây ra tình trạng tranh chấp thread. Đó là lý do tại sao &lt;code&gt;finalize()&lt;/code&gt; đã bị deprecated và sẽ bị loại bỏ trong tương lai.&lt;/p&gt;
&lt;p&gt;Cleaner API hoạt động dựa trên cơ chế PhantomReference của Java, nhưng cung cấp một lớp trừu tượng dễ sử dụng hơn. Khi đăng ký một đối tượng với Cleaner, nó sẽ được theo dõi bởi một thread daemon nền. Khi đối tượng trở nên không thể truy cập, tác vụ dọn dẹp sẽ được đưa vào hàng đợi để thực thi trong thread nền này.&lt;/p&gt;
&lt;p&gt;Cách sử dụng Cleaner cơ bản như sau:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tạo một instance của Cleaner thông qua phương thức &lt;code&gt;Cleaner.create()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Định nghĩa một lớp hoặc đối tượng thực hiện interface Runnable để xử lý việc dọn dẹp&lt;/li&gt;
&lt;li&gt;Đăng ký đối tượng cần quản lý với Cleaner thông qua phương thức &lt;code&gt;register()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Khi đối tượng không còn được tham chiếu, tác vụ dọn dẹp sẽ tự động được thực thi&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cleaner cũng có thể kết hợp với AutoCloseable để cung cấp cả cơ chế dọn dẹp tự động và thủ công. Trong trường hợp này, phương thức &lt;code&gt;close()&lt;/code&gt; có thể gọi &lt;code&gt;cleanable.clean()&lt;/code&gt; để kích hoạt việc dọn dẹp ngay lập tức.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, cần lưu ý rằng Cleaner chỉ nên được sử dụng khi không thể giải phóng tài nguyên thông qua try-with-resources hoặc gọi phương thức close() một cách tường minh. Cleaner có chi phí cao hơn do sử dụng thread nền và cơ chế PhantomReference, vì vậy nên ưu tiên sử dụng try-with-resources khi có thể.&lt;/p&gt;
&lt;h2 id="5-hidden-git-tips-for-java-developers"&gt;&lt;a class="link" href="https://blog.payara.fish/5-hidden-git-tips-for-java-developers" target="_blank" rel="noopener"
&gt;5 Hidden Git Tips for Java Developers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Git là công cụ quản lý phiên bản không thể thiếu đối với các lập trình viên Java. Ngoài các lệnh cơ bản như git commit, git push và git pull, Git còn có nhiều tính năng ẩn có thể cải thiện đáng kể quy trình làm việc của bạn. Bài viết từ blog của Payara giới thiệu năm mẹo Git hữu ích dành riêng cho phát triển Java.&lt;/p&gt;
&lt;h3 id="1-sử-dụng-git-bisect-để-tìm-commit-gây-ra-lỗi"&gt;1. Sử dụng Git Bisect để tìm commit gây ra lỗi
&lt;/h3&gt;&lt;p&gt;Khi làm việc với các dự án Java phức tạp, việc tìm ra commit chính xác đã gây ra lỗi có thể rất khó khăn. Lệnh &lt;code&gt;git bisect&lt;/code&gt; thực hiện tìm kiếm nhị phân qua lịch sử commit để xác định commit có vấn đề. Quy trình hoạt động như sau:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bắt đầu quá trình bisect với &lt;code&gt;git bisect start&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Đánh dấu commit hiện tại là &amp;ldquo;xấu&amp;rdquo; với &lt;code&gt;git bisect bad&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Đánh dấu một commit đã biết là &amp;ldquo;tốt&amp;rdquo; với &lt;code&gt;git bisect good &amp;lt;commit-hash&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Git sẽ tự động checkout một commit ở giữa khoảng và bạn kiểm tra xem lỗi có tồn tại không&lt;/li&gt;
&lt;li&gt;Tiếp tục đánh dấu các commit là &amp;ldquo;tốt&amp;rdquo; hoặc &amp;ldquo;xấu&amp;rdquo; cho đến khi Git xác định được commit gây ra lỗi&lt;/li&gt;
&lt;li&gt;Kết thúc quá trình với &lt;code&gt;git bisect reset&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-sử-dụng-git-blame-để-hiểu-các-thay-đổi-trong-mã"&gt;2. Sử dụng git blame để hiểu các thay đổi trong mã
&lt;/h3&gt;&lt;p&gt;Khi làm việc với codebase lớn, lệnh &lt;code&gt;git blame&lt;/code&gt; giúp bạn xem ai đã sửa đổi mỗi dòng của một tệp và khi nào. Cách sử dụng:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chạy &lt;code&gt;git blame &amp;lt;tên-tệp&amp;gt;&lt;/code&gt; để xem hash commit, tác giả và ngày cho mỗi dòng&lt;/li&gt;
&lt;li&gt;Sử dụng cờ -L để tập trung vào các dòng cụ thể: &lt;code&gt;git blame -L 50,60 &amp;lt;tên-tệp&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-sử-dụng-git-stash-để-lưu-tạm-công-việc-chưa-hoàn-thành"&gt;3. Sử dụng git stash để lưu tạm công việc chưa hoàn thành
&lt;/h3&gt;&lt;p&gt;Khi cần chuyển đổi giữa các tác vụ, &lt;code&gt;git stash&lt;/code&gt; cho phép bạn tạm thời lưu các thay đổi mà không cần commit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lưu tạm thời các thay đổi với &lt;code&gt;git stash&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Chuyển nhánh hoặc làm việc trên tác vụ khác&lt;/li&gt;
&lt;li&gt;Áp dụng lại các thay đổi đã lưu với &lt;code&gt;git stash pop&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Sử dụng &lt;code&gt;git stash list&lt;/code&gt; để xem tất cả các stash và &lt;code&gt;git stash apply &amp;lt;stash-id&amp;gt;&lt;/code&gt; để áp dụng một stash cụ thể&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-tự-động-dọn-dẹp-với-git-clean"&gt;4. Tự động dọn dẹp với git clean
&lt;/h3&gt;&lt;p&gt;Các dự án Java thường tạo ra nhiều tệp build (ví dụ: tệp .class, thư mục target/). Lệnh &lt;code&gt;git clean&lt;/code&gt; giúp loại bỏ các tệp không được theo dõi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xem trước các tệp sẽ bị xóa với &lt;code&gt;git clean -n&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Xóa các tệp không được theo dõi với &lt;code&gt;git clean -f&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Xóa cả thư mục không được theo dõi với &lt;code&gt;git clean -fd&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Sử dụng &lt;code&gt;git clean -x&lt;/code&gt; để xóa cả các tệp bị bỏ qua (ví dụ: .idea/ hoặc .classpath)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="5-sử-dụng-git-hooks-để-tự-động-hóa-quy-trình-làm-việc"&gt;5. Sử dụng git hooks để tự động hóa quy trình làm việc
&lt;/h3&gt;&lt;p&gt;Git hooks là các script chạy tự động trước hoặc sau các sự kiện Git như commit, push hoặc merge:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tạo hook script trong thư mục .git/hooks của repository&lt;/li&gt;
&lt;li&gt;Làm cho script có thể thực thi với &lt;code&gt;chmod +x .git/hooks/&amp;lt;tên-hook&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Thêm logic tùy chỉnh, ví dụ như chạy unit test trước khi commit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mẹo bổ sung: Sử dụng &lt;code&gt;git checkout -&lt;/code&gt; để nhanh chóng chuyển đổi giữa các nhánh. Lệnh này cho phép bạn quay lại nhánh trước đó mà không cần gõ lại tên nhánh, tiết kiệm thời gian và giảm nguy cơ gõ sai khi chuyển nhánh.&lt;/p&gt;
&lt;h2 id="simplify-your-system-by-challenging-the-status-quo-and-learning-from-other-ecosystems"&gt;&lt;a class="link" href="https://www.infoq.com/podcasts/simplify-system-learning-ecosystems/" target="_blank" rel="noopener"
&gt;Simplify Your System by Challenging the Status-Quo and Learning from Other Ecosystems&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong podcast này, Max Rydahl Andersen, kỹ sư xuất sắc tại RedHat và người tạo ra JBang, thảo luận về cách học hỏi liên tục từ các hệ sinh thái khác và áp dụng các công cụ mới để đơn giản hóa tư duy và hệ thống của bạn. Điều này sẽ tăng cường niềm vui cho các lập trình viên và tạo ra các hệ thống an toàn và mạnh mẽ hơn.&lt;/p&gt;
&lt;p&gt;Max chia sẻ rằng sau khi nghỉ một năm và thử nghiệm với các ngôn ngữ khác như Python, ông đã nhìn nhận lại Java với góc nhìn mới. Ông nhận ra rằng cộng đồng Java đã vô tình tạo ra quá nhiều độ phức tạp qua các năm, với mỗi tính năng nhỏ được thêm vào tạo ra cái gọi là &amp;ldquo;các vết cắt ngàn lần&amp;rdquo; (thousand paper cuts).&lt;/p&gt;
&lt;p&gt;Quarkus, dự án mà Max tham gia tại RedHat, đã đảo ngược cách tiếp cận này bằng cách chuyển hầu hết các xử lý sang thời điểm biên dịch (build time) thay vì thời điểm chạy (runtime). Điều này cho phép JVM khởi động trong vòng vài mili giây hoặc ít hơn một giây, và có thể áp dụng native image để tăng tốc hơn nữa. Đây là một sự thay đổi lớn so với cách tiếp cận truyền thống của các framework Java EE hoặc Spring.&lt;/p&gt;
&lt;p&gt;Ngoài việc cải thiện hiệu suất runtime, Quarkus còn mang đến trải nghiệm phát triển tốt hơn với các tính năng như:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hot reload/live reload cho phép các lập trình viên thử nghiệm nhanh chóng&lt;/li&gt;
&lt;li&gt;Kiểm tra liên tục (continuous testing) để phát hiện lỗi sớm&lt;/li&gt;
&lt;li&gt;Dev services tự động tạo các dịch vụ cần thiết (như Postgres, Kafka) nếu chưa được cấu hình&lt;/li&gt;
&lt;li&gt;Hỗ trợ tốt cho AI với LangChain4J và giao diện chat UI trong môi trường phát triển&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Max cũng thảo luận về JBang, một công cụ khác do ông tạo ra, được lấy cảm hứng từ các hệ sinh thái như Python và Node.js để đơn giản hóa việc khởi tạo và chạy các ứng dụng Java. Ông tuyên bố rằng nếu bạn tìm thấy bất kỳ môi trường phát triển nào trên thế giới dễ dàng cài đặt hơn JBang, đó sẽ được coi là một lỗi.&lt;/p&gt;
&lt;p&gt;Thông điệp chính của podcast là chúng ta nên thách thức hiện trạng, học hỏi từ các hệ sinh thái khác, và chấp nhận rằng một số việc có thể đơn giản hơn những gì chúng ta đã quen. Đặc biệt trong thời đại AI, việc đơn giản hóa các hệ thống không chỉ giúp các lập trình viên làm việc hiệu quả hơn mà còn tạo ra các hệ thống an toàn và bền vững hơn.&lt;/p&gt;
&lt;h2 id="about"&gt;&lt;a class="link" href="https://tryingthings.wordpress.com/2025/03/24/about-vibe-coding/" target="_blank" rel="noopener"
&gt;About &amp;ldquo;vibe coding&amp;rdquo;&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết ngắn gọn này, tác giả Sorin Costea chia sẻ quan điểm của mình về xu hướng &amp;ldquo;vibe coding&amp;rdquo; - một cách gọi mới cho việc sử dụng AI để lập trình. Tác giả bày tỏ sự hoài nghi của mình đối với các công cụ AI trong phát triển phần mềm, đặc biệt sau khi đọc bài viết &amp;ldquo;Vibe coding vs Reality&amp;rdquo; và tự trải nghiệm với công cụ Cursor.&lt;/p&gt;
&lt;p&gt;Tác giả mô tả trải nghiệm của mình khi sử dụng Cursor với một dự án Java Maven. Ông phát hiện rằng Cursor không thể thực hiện một thao tác cơ bản như đổi tên một lớp Java. Công cụ này hoặc chỉ đổi tên lớp mà không đổi tên tệp, hoặc khi được yêu cầu lại, nó tạo ra một tệp mới rỗng với tên mới. Điều này khiến tác giả mất lòng tin vào khả năng của công cụ này trong việc xử lý các dự án thực tế.&lt;/p&gt;
&lt;p&gt;Khi chia sẻ trải nghiệm này trên Hacker News, tác giả nhận được các phản hồi không mấy tích cực như &amp;ldquo;haha Java&amp;rdquo;, khiến ông tự hỏi liệu Cursor chỉ được huấn luyện cho các framework frontend phổ biến hay những người ủng hộ nó không thực sự quan tâm đến các ứng dụng trong thế giới thực. Kết quả là tác giả đã gỡ cài đặt Cursor và xây dựng một thái độ hoài nghi đối với các giải pháp AI &amp;ldquo;kỳ diệu&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Tác giả kết luận bài viết với câu &amp;ldquo;Nhưng năm sau? Chúng ta sẽ xem xét lại vào năm sau&amp;rdquo;, thể hiện thái độ chờ đợi và sẵn sàng đánh giá lại các công nghệ AI trong tương lai khi chúng trưởng thành hơn.&lt;/p&gt;
&lt;h2 id="visual-focused-algorithms-cheat-sheet"&gt;&lt;a class="link" href="https://photonlines.substack.com/p/visual-focused-algorithms-cheat-sheet" target="_blank" rel="noopener"
&gt;Visual-Focused Algorithms Cheat Sheet&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này cung cấp một tổng quan trực quan về các thuật toán quan trọng được sử dụng trong thế giới thực. Tác giả Nick M đã tập hợp một bảng tra cứu (cheat sheet) bao gồm nhiều loại thuật toán khác nhau, từ các thuật toán sắp xếp và tìm kiếm cơ bản đến các thuật toán phức tạp hơn trong học máy và bảo mật.&lt;/p&gt;
&lt;p&gt;Bảng tra cứu này được chia thành nhiều phần chính:&lt;/p&gt;
&lt;h3 id="thuật-toán-sắp-xếp-sorting-algorithms"&gt;Thuật toán sắp xếp (Sorting Algorithms)
&lt;/h3&gt;&lt;p&gt;Phần này giới thiệu các thuật toán sắp xếp phổ biến như:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Selection Sort&lt;/strong&gt;: Thuật toán đơn giản liên tục tìm phần tử nhỏ nhất và đưa vào vị trí đúng, với độ phức tạp O(n²)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Insertion Sort&lt;/strong&gt;: Sắp xếp bằng cách so sánh và chèn các phần tử vào vị trí thích hợp trong phần đã sắp xếp, cũng có độ phức tạp O(n²)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Heap Sort&lt;/strong&gt;: Sử dụng cấu trúc dữ liệu binary heap để sắp xếp với độ phức tạp O(n log n)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quick Sort&lt;/strong&gt;: Thuật toán chia để trị hiệu quả cao với độ phức tạp trung bình O(n log n)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Merge Sort&lt;/strong&gt;: Thuật toán ổn định chia để trị với độ phức tạp O(n log n)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tim Sort&lt;/strong&gt;: Thuật toán lai kết hợp Insertion Sort và Merge Sort, được sử dụng trong Python và Java&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="thuật-toán-tìm-kiếm-search-algorithms"&gt;Thuật toán tìm kiếm (Search Algorithms)
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Binary Search&lt;/strong&gt;: Tìm kiếm nhanh trên mảng đã sắp xếp với độ phức tạp O(log n)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Depth-First Search (DFS)&lt;/strong&gt;: Duyệt đồ thị theo chiều sâu, thích hợp cho việc khám phá sâu&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Breadth-First Search (BFS)&lt;/strong&gt;: Duyệt đồ thị theo chiều rộng, tốt cho việc tìm đường đi ngắn nhất&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="thuật-toán-đồ-thị-graph-algorithms"&gt;Thuật toán đồ thị (Graph Algorithms)
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prim&amp;rsquo;s Algorithm&lt;/strong&gt;: Tìm cây khung nhỏ nhất trong đồ thị có trọng số&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kruskal&amp;rsquo;s Algorithm&lt;/strong&gt;: Cũng tìm cây khung nhỏ nhất nhưng bằng cách sắp xếp các cạnh theo trọng số&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dijkstra&amp;rsquo;s Algorithm&lt;/strong&gt;: Tìm đường đi ngắn nhất từ một đỉnh đến tất cả các đỉnh khác trong đồ thị có trọng số không âm&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bellman-Ford Algorithm&lt;/strong&gt;: Tương tự Dijkstra nhưng có thể xử lý cả trọng số âm&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;em&gt;A&lt;/em&gt; Search&lt;/em&gt;*: Thuật toán tìm đường cải tiến từ Dijkstra, kết hợp tìm đường ngắn nhất và tìm kiếm dựa trên hế số ước lượng&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết cũng bao gồm các phần về thuật toán nén và mã hóa, thuật toán tối ưu, thuật toán học máy và khoa học dữ liệu, cũng như các thuật toán bảo mật và mã hóa. Đặc biệt, phần học máy giới thiệu các thuật toán như hồi quy (Linear, Logistic, và Polynomial), Support Vector Machines (SVMs), cây quyết định (Decision Trees) và các biến thể như Random Forest và Boosted Trees.&lt;/p&gt;
&lt;p&gt;Bảng tra cứu này là một tài nguyên quý giá cho cả sinh viên và các chuyên gia trong lĩnh vực công nghệ, cung cấp cái nhìn trực quan và dễ hiểu về các thuật toán quan trọng được sử dụng trong thực tế. Tác giả cũng đã bao gồm các tài liệu hữu ích cho việc chuẩn bị phỏng vấn công việc, với các mục như &amp;ldquo;14 Patterns to Ace Any Coding Interview&amp;rdquo; và &amp;ldquo;5 Simple Steps for Solving Dynamic Programming Problems&amp;rdquo;.&lt;/p&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/81074d22-5821-4aec-bb2d-0a099d06b6ac_1600x840.png"
loading="lazy"
alt="3 Steps to Master Your Software"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/67c39b9a-9a91-4e57-9e24-7714b4f806dd_1280x1349.gif"
loading="lazy"
alt="The Ultimate Software Architect Roadmap"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/fb1b1cd1-eac3-4b66-a391-9ec73f6c37f3_1280x1502.gif"
loading="lazy"
alt="How Two-factor Authentication (2FA) Works?"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/3efae3ad-8c45-4fb2-a79f-6b3387b0751e_1280x1601.gif"
loading="lazy"
alt="How Amazon S3 Works?"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #19</title><link>https://miti99.com/post/2025/05/06/</link><pubDate>Tue, 06 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/06/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #19.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="a-love-letter-to-the-csv-format"&gt;&lt;a class="link" href="https://github.com/medialab/xan/blob/master/docs/LOVE_LETTER.md" target="_blank" rel="noopener"
&gt;A love letter to the CSV format&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong thế giới công nghệ hiện nay, định dạng CSV thường bị chỉ trích và coi là lỗi thời so với các định dạng &amp;ldquo;hiện đại&amp;rdquo; hơn như Parquet, JSON hoặc MessagePack. Tuy nhiên, bài viết này đưa ra một góc nhìn khác, ca ngợi những ưu điểm đôi khi bị bỏ qua của CSV.&lt;/p&gt;
&lt;p&gt;CSV có nhiều điểm mạnh đáng chú ý: nó đơn giản đến mức có thể giải thích trong vài giây (các giá trị được phân tách bằng dấu phẩy, các hàng được phân tách bằng dòng mới); nó là một ý tưởng tập thể không thuộc sở hữu của ai; nó là văn bản thuần túy có thể đọc và chỉnh sửa trực tiếp; nó có thể đọc theo luồng từng hàng một mà không cần nhiều bộ nhớ; dễ dàng thêm dữ liệu mới vào cuối file; nó có kiểu dữ liệu động giúp linh hoạt khi xử lý dữ liệu; và nó rất súc tích với lượng lặp lại tối thiểu.&lt;/p&gt;
&lt;p&gt;Một điểm thú vị ít người biết là CSV đảo ngược vẫn là CSV hợp lệ, cho phép đọc hiệu quả các hàng cuối cùng của file. Và cuối cùng, Excel ghét CSV - điều này có lẽ chứng tỏ CSV đang làm điều gì đó đúng đắn!&lt;/p&gt;
&lt;p&gt;Những điểm nổi bật:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CSV đơn giản đến mức ai cũng có thể hiểu và sử dụng&lt;/li&gt;
&lt;li&gt;Định dạng văn bản thuần túy giúp dễ đọc và chỉnh sửa&lt;/li&gt;
&lt;li&gt;Khả năng đọc theo luồng giúp xử lý file lớn với bộ nhớ tối thiểu&lt;/li&gt;
&lt;li&gt;Dễ dàng thêm dữ liệu mới vào cuối file&lt;/li&gt;
&lt;li&gt;Kiểu dữ liệu động mang lại sự linh hoạt khi xử lý dữ liệu&lt;/li&gt;
&lt;li&gt;Cấu trúc súc tích với ít sự lặp lại&lt;/li&gt;
&lt;li&gt;CSV đảo ngược vẫn là CSV hợp lệ, cho phép đọc hiệu quả các hàng cuối&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-role-of-developer-skills-in-agentic-coding"&gt;&lt;a class="link" href="https://martinfowler.com/articles/exploring-gen-ai/13-role-of-developer-skills.html" target="_blank" rel="noopener"
&gt;The role of developer skills in agentic coding&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, Birgitta Böckeler chia sẻ những quan sát của mình về vai trò của kỹ năng lập trình trong môi trường sử dụng trợ lý lập trình AI (agentic coding assistants). Mặc dù các công cụ AI như Cursor, Windsurf và Cline đã đạt được những tiến bộ đáng kể trong việc hỗ trợ lập trình viên, tác giả nhấn mạnh rằng sự can thiệp và điều chỉnh của con người vẫn là yếu tố quan trọng không thể thiếu.&lt;/p&gt;
&lt;p&gt;Tác giả phân loại các trường hợp cần sự can thiệp của lập trình viên thành ba nhóm tác động:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tác động đến thời gian hoàn thành&lt;/strong&gt;: AI đôi khi tạo ra mã không hoạt động hoặc chẩn đoán sai vấn đề, khiến quá trình phát triển chậm lại thay vì nhanh hơn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tác động đến quy trình làm việc của nhóm&lt;/strong&gt;: AI thường tạo ra quá nhiều mã cùng lúc thay vì phát triển theo từng phần nhỏ, sử dụng các giải pháp tạm thời thay vì phân tích nguyên nhân gốc rễ, hoặc tạo ra quy trình phát triển phức tạp gây khó khăn cho các thành viên khác trong nhóm.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tác động đến khả năng bảo trì dài hạn&lt;/strong&gt;: Đây là vấn đề nghiêm trọng nhất với chu kỳ phản hồi dài nhất. AI thường tạo ra các bài kiểm tra dư thừa, thiếu tính tái sử dụng, và mã quá phức tạp hoặc dài dòng.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Để giảm thiểu những vấn đề này, tác giả đề xuất một số biện pháp bảo vệ:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Luôn xem xét cẩn thận mã do AI tạo ra&lt;/li&gt;
&lt;li&gt;Dừng phiên làm việc với AI khi cảm thấy quá tải&lt;/li&gt;
&lt;li&gt;Cảnh giác với các giải pháp &amp;ldquo;đủ tốt&amp;rdquo; được tạo ra quá nhanh&lt;/li&gt;
&lt;li&gt;Thực hành lập trình cặp (pair programming)&lt;/li&gt;
&lt;li&gt;Thiết lập công cụ giám sát chất lượng mã&lt;/li&gt;
&lt;li&gt;Sử dụng các quy tắc tùy chỉnh cho trợ lý lập trình&lt;/li&gt;
&lt;li&gt;Xây dựng văn hóa tin cậy và giao tiếp cởi mở trong nhóm&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="cicd-devops-pipeline-project-deployment-of-java-application-on-kubernetes"&gt;&lt;a class="link" href="https://dev.to/prodevopsguytech/cicd-devops-pipeline-project-deployment-of-java-application-on-kubernetes-4fi2" target="_blank" rel="noopener"
&gt;CI/CD DevOps Pipeline Project: Deployment of Java Application on Kubernetes&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trình bày chi tiết về việc triển khai một hệ thống CI/CD (Continuous Integration/Continuous Deployment) hoàn chỉnh cho ứng dụng Java trên Kubernetes. Đây là một dự án DevOps toàn diện nhằm tự động hóa toàn bộ vòng đời phát triển phần mềm, từ giai đoạn phát triển đến triển khai.&lt;/p&gt;
&lt;p&gt;Mục tiêu chính của dự án là tự động hóa quy trình phát triển phần mềm, cải thiện tốc độ, độ tin cậy và hiệu quả đồng thời giảm thiểu sự can thiệp thủ công. Dự án sử dụng nhiều công cụ DevOps phổ biến như Jenkins, Maven, SonarQube, Trivy, Nexus Repository, Docker, Kubernetes, Prometheus và Grafana.&lt;/p&gt;
&lt;p&gt;Quy trình CI/CD được xây dựng bao gồm các bước chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cài đặt cơ sở hạ tầng&lt;/strong&gt;: Sử dụng các máy ảo AWS EC2 cho Kubernetes Master, Worker Nodes, SonarQube, Nexus Repository, Jenkins và máy chủ giám sát.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thiết lập Kubernetes Cluster&lt;/strong&gt;: Hướng dẫn chi tiết về việc cài đặt và cấu hình Kubernetes cluster sử dụng Kubeadm, bao gồm cài đặt CRI-O Runtime, cài đặt các gói Kubernetes và khởi tạo cluster.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xây dựng Pipeline trong Jenkins&lt;/strong&gt;: Tạo một pipeline hoàn chỉnh với các giai đoạn:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lấy mã nguồn từ Git repository&lt;/li&gt;
&lt;li&gt;Biên dịch và kiểm thử ứng dụng&lt;/li&gt;
&lt;li&gt;Quét bảo mật với Trivy&lt;/li&gt;
&lt;li&gt;Phân tích chất lượng mã với SonarQube&lt;/li&gt;
&lt;li&gt;Đóng gói và xuất bản artifacts lên Nexus&lt;/li&gt;
&lt;li&gt;Xây dựng và đẩy Docker image&lt;/li&gt;
&lt;li&gt;Triển khai ứng dụng lên Kubernetes&lt;/li&gt;
&lt;li&gt;Gửi thông báo về trạng thái của pipeline&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thiết lập hệ thống giám sát&lt;/strong&gt;: Cài đặt và cấu hình Prometheus và Grafana để giám sát hệ thống theo thời gian thực.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Dự án này minh họa cách các công cụ DevOps hiện đại có thể được tích hợp để tạo ra một quy trình phát triển phần mềm liền mạch, tự động và đáng tin cậy.&lt;/p&gt;
&lt;h2 id="road-to-jdk-25-over-engineering-tic-tac-toe-java-24"&gt;&lt;a class="link" href="https://briancorbinxyz.medium.com/road-to-jdk-25-over-engineering-tic-tac-toe-java-24-565c7f9b06d0" target="_blank" rel="noopener"
&gt;Road to JDK 25: Over-Engineering Tic-Tac-Toe (Java 24)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong loạt bài &amp;ldquo;Road to JDK 25&amp;rdquo;, tác giả Brian Corbin khám phá các tính năng mới của Java thông qua việc &amp;ldquo;over-engineering&amp;rdquo; (thiết kế quá mức cần thiết) trò chơi tic-tac-toe đơn giản. Bài viết này tập trung vào JDK 24, phiên bản mới nhất của Java với nhiều cải tiến đáng chú ý.&lt;/p&gt;
&lt;p&gt;JDK 24 được phát hành với 24 JEP (JDK Enhancement Proposal), mang đến nhiều tính năng mới và cải tiến quan trọng. Trong đó, tác giả đặc biệt chú trọng đến các tính năng đã được hoàn thiện, không còn ở trạng thái preview:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stream Gatherers&lt;/strong&gt;: Đây là một tính năng mới quan trọng cho phép tạo các thao tác trung gian tùy chỉnh trên Stream API. Với Stream::gather(Gatherer), lập trình viên có thể xử lý và chuyển đổi luồng dữ liệu bằng các gatherer tùy chỉnh. Gatherer có thể là one-to-one, one-to-many, many-to-one, hoặc many-to-many, và có thể theo dõi trạng thái như các phần tử đã truy cập trước đó. JDK 24 cung cấp các gatherer mới như scan, fold, windowFixed/windowSliding.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Generational ZGC&lt;/strong&gt;: Trong JDK 24, bộ thu gom rác ZGC (Z Garbage Collector) hoàn toàn chuyển sang chế độ thu gom rác đa thế hệ (multi-generational). Chế độ không phân thế hệ đã bị loại bỏ hoàn toàn. Điều này giúp tập trung thu gom các đối tượng ngắn hạn thường xuyên và hiệu quả hơn, giảm tần suất của các lần thu gom rác toàn bộ.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Class-File API&lt;/strong&gt;: JDK 24 giới thiệu API mới cho phép phân tích, tạo và chuyển đổi các file class Java. Đây là nền tảng cho các công cụ phân tích và chuyển đổi mã Java trong tương lai.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ahead-of-Time Class Loading &amp;amp; Linking&lt;/strong&gt;: Tính năng này cải thiện thời gian khởi động và hiệu suất runtime của các module bằng cách tải và liên kết các lớp trước khi chạy chương trình.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quantum-Resistant Cryptography&lt;/strong&gt;: JDK 24 bổ sung các thuật toán mã hóa mới dựa trên mạng lưới (lattice-based) để chống lại các cuộc tấn công từ máy tính lượng tử trong tương lai.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết minh họa cách sử dụng các tính năng này trong một ứng dụng tic-tac-toe, và cho thấy cách Java tiếp tục phát triển để đáp ứng nhu cầu của các nhà phát triển hiện đại. Tác giả cũng nhắc nhở rằng JDK 25 sẽ là phiên bản LTS (Long-Term Support) tiếp theo, dự kiến phát hành vào tháng 9 năm 2025.&lt;/p&gt;
&lt;h2 id="oracle-reveals-five-new-features-coming-to-java"&gt;&lt;a class="link" href="https://www.infoworld.com/article/3848288/oracle-reveals-five-new-features-coming-to-java.html" target="_blank" rel="noopener"
&gt;Oracle reveals five new features coming to Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong khi JDK 24 vừa mới được phát hành chính thức, Oracle đã hé lộ năm tính năng mới sẽ được bổ sung vào Java trong tương lai gần. Những tính năng này bao gồm cả các cải tiến về ngôn ngữ và tối ưu hóa hiệu suất, với Stable Values API đã được chính thức đưa vào JDK 25 dự kiến phát hành vào tháng 9 năm nay.&lt;/p&gt;
&lt;p&gt;Năm tính năng được Oracle công bố đều đã được xuất bản dưới dạng JEP (JDK Enhancement Proposal) và hiện đang ở giai đoạn preview:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enhanced primitive boxing&lt;/strong&gt;: Cải tiến boxing để hỗ trợ các tính năng ngôn ngữ mới, cho phép xử lý các kiểu dữ liệu nguyên thủy (primitive types) giống như các kiểu tham chiếu (reference types). Mục tiêu bao gồm việc cho phép boxing các giá trị nguyên thủy khi chúng được sử dụng làm &amp;ldquo;receiver&amp;rdquo; của truy cập trường, gọi phương thức, hoặc tham chiếu phương thức.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Null-restricted value class types&lt;/strong&gt;: Cho phép kiểu của một biến lưu trữ các đối tượng giá trị loại trừ giá trị null, cho phép lưu trữ gọn hơn và các tối ưu hóa khác trong thời gian chạy. Tính năng này đang được xem xét cả ở cấp độ ngôn ngữ và máy ảo Java.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Value classes and objects&lt;/strong&gt;: Nâng cao nền tảng Java với các đối tượng giá trị (value objects), là các đối tượng chỉ có các trường final và không có identity. Mục tiêu bao gồm việc cho phép các nhà phát triển tham gia vào một mô hình lập trình cho các giá trị đơn giản, trong đó các đối tượng chỉ được phân biệt bởi giá trị của các trường của chúng.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Derived record creation&lt;/strong&gt;: Nâng cao ngôn ngữ với khả năng tạo một record mới từ một record hiện có. Một mục tiêu là cung cấp phương tiện ngắn gọn để tạo các giá trị record mới có nguồn gốc từ các giá trị record hiện có. Một mục tiêu khác là đơn giản hóa việc khai báo các lớp record bằng cách loại bỏ nhu cầu cung cấp các phương thức wither rõ ràng.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stable values&lt;/strong&gt;: Là các đối tượng chứa dữ liệu bất biến. Vì stable values được JVM coi là hằng số, chúng cho phép các tối ưu hóa hiệu suất tương tự như khi khai báo một trường là final. Đồng thời, chúng cung cấp tính linh hoạt hơn về thời điểm khởi tạo. Mục tiêu của đề xuất này bao gồm cải thiện thời gian khởi động của các ứng dụng Java bằng cách phân chia việc khởi tạo trạng thái ứng dụng đơn nguyên.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Những tính năng này cho thấy Oracle tiếp tục đầu tư vào việc cải tiến Java, đặc biệt là trong các lĩnh vực liên quan đến mô hình đối tượng, hiệu suất và trải nghiệm lập trình. Các tính năng này dự kiến sẽ được triển khai trong các phiên bản Java sắp tới, với Stable Values đã được xác nhận sẽ có trong JDK 25.&lt;/p&gt;
&lt;h2 id="java-bytecode-hacking-for-fun-and-profit"&gt;&lt;a class="link" href="https://cory.li/bytecode-hacking/" target="_blank" rel="noopener"
&gt;Java bytecode hacking for fun and profit&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trình bày một cái nhìn sâu sắc về kỹ thuật tối ưu bytecode trong Java, một chủ đề đã trở nên khá hiếm gặp trong thời đại hiện nay với sự xuất hiện của trình biên dịch JIT (Just-In-Time) từ Java 1.3. Tác giả đưa ra bài viết này trong bối cảnh của cuộc thi Battlecode, nơi các đội phải viết AI điều khiển robot ảo và bị giới hạn bởi số lượng bytecode thực thi thay vì thời gian CPU thông thường.&lt;/p&gt;
&lt;p&gt;Bytecode là các lệnh nguyên tử chạy trên JVM (Java Virtual Machine) - mã nguồn Java được biên dịch thành bytecode, tương tự như assembly. Trong Battlecode, mỗi đội chỉ được sử dụng một số lượng bytecode giới hạn (khoảng 6-10 nghìn) cho mỗi lượt, nên việc tối ưu hóa số lượng bytecode trở nên rất quan trọng.&lt;/p&gt;
&lt;p&gt;Tác giả giải thích cơ chế hoạt động của JVM, một kiến trúc dựa trên stack với tập lệnh khá toàn diện cho phép thao tác trên cả kiểu dữ liệu nguyên thủy và đối tượng. Mỗi bytecode là một lệnh nguyên tử, tương đương với một lệnh assembly trong mã máy thực. Sau đó, tác giả chia sẻ một số kỹ thuật tối ưu hóa bytecode, bao gồm:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hiểu cách đếm bytecode&lt;/strong&gt;: Trong Battlecode, chỉ số lượng bytecode được tính, không phải kích thước hay độ phức tạp của chúng. Ví dụ, &lt;code&gt;iload_0&lt;/code&gt; (1 byte) và &lt;code&gt;iload #5&lt;/code&gt; (2 byte) đều được tính là 1 bytecode.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tối ưu hóa vòng lặp&lt;/strong&gt;: Tác giả trình bày cách tối ưu hóa các vòng lặp, từ vòng lặp for-each tiêu chuẩn đến các phiên bản tối ưu hơn. Ví dụ, việc sử dụng vòng lặp for thông thường thay vì for-each có thể tiết kiệm được 2 bytecode mỗi lần lặp.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đưa biến vào phạm vi cục bộ&lt;/strong&gt;: Truy cập trực tiếp các biến thành viên của một lớp tiêu tốn 2 bytecode mỗi lần truy cập. Việc sao chép các biến thành viên vào các biến cục bộ có thể giúp tiết kiệm bytecode đáng kể trong các vòng lặp.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;So sánh với số 0&lt;/strong&gt;: Các so sánh với số 0 được tối ưu đặc biệt trong JVM, vì vậy việc chuyển đổi các so sánh thành so sánh với 0 khi có thể sẽ giúp tiết kiệm bytecode.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tác giả nhấn mạnh rằng những tối ưu hóa này chỉ nên được thực hiện sau khi đã xây dựng xong khung AI và các thuật toán chính. Viết mã đúng và hiệu quả về mặt thuật toán luôn quan trọng hơn việc tối ưu hóa mã sai hoặc kém hiệu quả. Tuy nhiên, trong môi trường có giới hạn nghiêm ngặt về bytecode, mỗi tối ưu hóa nhỏ đều có thể tạo nên sự khác biệt giữa chiến thắng và thất bại.&lt;/p&gt;
&lt;h2 id="how-to-write-blog-posts-that-developers-read"&gt;&lt;a class="link" href="https://refactoringenglish.com/chapters/write-blog-posts-developers-read/" target="_blank" rel="noopener"
&gt;How to Write Blog Posts that Developers Read&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, Michael Lynch - một blogger có kinh nghiệm 9 năm với blog phần mềm thu hút 300-500 nghìn độc giả mỗi năm - chia sẻ những bí quyết để viết các bài blog mà các lập trình viên sẽ thực sự đọc. Ông chỉ ra rằng nhiều blogger phần mềm có những hiểu biết thú vị nhưng lại mắc phải những lỗi cơ bản khiến bài viết của họ không đến được với độc giả.&lt;/p&gt;
&lt;p&gt;Tác giả đưa ra năm nguyên tắc quan trọng để viết bài blog thu hút được các lập trình viên:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đi thẳng vào vấn đề&lt;/strong&gt;: Lỗi lớn nhất của các blogger phần mềm là viết lan man. Khi độc giả đến với bài viết, họ cần biết ngay hai điều: bài viết có dành cho họ không và họ sẽ được lợi gì khi đọc nó. Hãy trả lời cả hai câu hỏi này trong tiêu đề và ba câu đầu tiên.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Suy nghĩ rộng hơn một bậc&lt;/strong&gt;: Nhiều blogger không bao giờ tự hỏi liệu có đối tượng đọc rộng hơn cho chủ đề của họ không. Ví dụ, nếu bạn viết bài cho các lập trình viên Java có kinh nghiệm, liệu có thể mở rộng đối tượng đọc đến tất cả lập trình viên Java không? Thường chỉ cần thêm vài câu để giới thiệu khái niệm hoặc thay thế thuật ngữ chuyên môn bằng các thuật ngữ dễ tiếp cận hơn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lên kế hoạch đường đến với độc giả&lt;/strong&gt;: Không đủ khi chỉ viết một bài hay, bạn cần có kế hoạch thực tế để bài viết đến được với độc giả. Google sẽ không giúp bạn nếu bạn viết về chủ đề đã bão hòa. Hãy tìm các góc độ độc đáo hoặc các nền tảng phù hợp để chia sẻ bài viết của bạn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sử dụng nhiều hình ảnh hơn&lt;/strong&gt;: Thay đổi mang lại hiệu quả cao nhất cho bài blog là thêm hình ảnh. Nếu bài viết của bạn có các đoạn văn bản dài, hãy xem liệu có thể thêm ảnh chụp màn hình, biểu đồ, đồ thị hoặc sơ đồ nào có thể làm cho bài viết trở nên thú vị hơn về mặt hình ảnh.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thích ứng với người đọc lướt&lt;/strong&gt;: Nhiều độc giả lướt qua bài viết trước khi quyết định có đáng đọc hay không. Hãy làm cho những độc giả này ấn tượng ngay từ cái nhìn đầu tiên. Nếu độc giả chỉ nhìn thấy các tiêu đề và hình ảnh của bạn, liệu điều đó có khiến họ quan tâm không?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết này là một phần của cuốn sách sắp tới của tác giả về cách cải thiện kỹ năng viết cho các lập trình viên. Những nguyên tắc này không chỉ giúp các blogger phần mềm viết bài tốt hơn mà còn có thể áp dụng cho việc viết tài liệu kỹ thuật, email, và các hình thức truyền thông khác trong lĩnh vực phần mềm.&lt;/p&gt;
&lt;h2 id="the-new-look-and-feel-of-apache-kafka-40"&gt;&lt;a class="link" href="https://thenewstack.io/the-new-look-and-feel-of-apache-kafka-4-0/" target="_blank" rel="noopener"
&gt;The New Look and Feel of Apache Kafka 4.0&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Apache Kafka 4.0 đánh dấu một bước tiến lớn trong hệ sinh thái xử lý dữ liệu luồng (stream processing) với nhiều cải tiến đáng kể trên toàn bộ nền tảng. Phiên bản này mang đến một diện mạo mới và các tính năng quan trọng giúp đơn giản hóa và nâng cao hiệu suất của hệ thống.&lt;/p&gt;
&lt;p&gt;Những thay đổi chính trong Apache Kafka 4.0 bao gồm:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Từ biệt ZooKeeper, chào đón KRaft&lt;/strong&gt;: Kafka 4.0 loại bỏ sự phụ thuộc vào ZooKeeper và thay thế bằng KRaft (Kafka Raft) - một cơ chế quản lý metadata được tích hợp trực tiếp vào Kafka. Điều này mang lại nhiều lợi ích như cài đặt đơn giản hơn, hiệu suất tốt hơn và độ tin cậy cao hơn do giảm thiểu các thành phần cần quản lý.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Queues for Kafka - Consumer linh hoạt hơn&lt;/strong&gt;: Phiên bản mới giới thiệu tính năng Queues for Kafka, cho phép nhiều consumer cùng xử lý dữ liệu trên cùng một partition. Trước đây, số lượng consumer bị giới hạn bởi số lượng partition, nhưng giờ đây Kafka có thể hoạt động tương tự như các hệ thống hàng đợi truyền thống như RabbitMQ hay SQS, giúp tăng khả năng mở rộng và linh hoạt hơn trong việc xử lý dữ liệu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cân bằng consumer group mượt mà hơn&lt;/strong&gt;: Kafka 4.0 cải thiện đáng kể quá trình cân bằng lại các consumer group. Khi thêm máy chủ mới hoặc khắc phục sự cố, hệ thống có thể điều chỉnh mà không gây gián đoạn, giảm thiểu thời gian ngừng hoạt động và tăng tốc độ xử lý dữ liệu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phát triển và giám sát dễ dàng hơn&lt;/strong&gt;: Kafka 4.0 đơn giản hóa việc thêm logic chung trong các ứng dụng Kafka Streams, giảm thiểu mã trùng lặp. Đồng thời, các công cụ giám sát mới giúp dễ dàng theo dõi hoạt động bên trong Kafka, hỗ trợ các đội phát hiện và khắc phục sự cố nhanh chóng.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Apache Kafka 4.0 là một bước tiến đáng kể cho các nhà phát triển và doanh nghiệp sử dụng dữ liệu luồng. Việc loại bỏ ZooKeeper, giới thiệu Queues for Kafka, cải thiện cân bằng và nâng cao các công cụ phát triển và giám sát đã biến phiên bản này trở thành một cập nhật quan trọng đối với cộng đồng xử lý dữ liệu luồng.&lt;/p&gt;
&lt;h2 id="five-things-ai-will-not-change"&gt;&lt;a class="link" href="https://metastable.org/five/" target="_blank" rel="noopener"
&gt;Five Things AI Will Not Change&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết sâu sắc này, tác giả đã phân tích năm khía cạnh mà trí tuệ nhân tạo (AI), dù có phát triển mạnh mẽ đến đâu, cũng sẽ không thay đổi. Thay vì cố gắng dự đoán mọi chi tiết về tương lai của AI, tác giả đã lấy cảm hứng từ Jeff Bezos - người đã xây dựng Amazon dựa trên những điều ông tin rằng sẽ không thay đổi trong tương lai của internet.&lt;/p&gt;
&lt;p&gt;Năm điều mà tác giả tin rằng sẽ không thay đổi, ngay cả khi chúng ta có AI mạnh mẽ, bao gồm:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sẽ có nhiều AI khác nhau&lt;/strong&gt;: Trái với giả định phổ biến về một AI duy nhất, tác giả tin rằng sẽ luôn tồn tại một hệ sinh thái đa dạng với hàng nghìn mô hình AI và hàng triệu phiên bản đang chạy. Ngay cả khi một AI có thể tự cải thiện, sự cạnh tranh khốc liệt trong ngành công nghiệp AI sẽ không cho phép một AI duy trì vị trí dẫn đầu quá lâu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sẽ có các AI độc hại và không được kiểm soát&lt;/strong&gt;: Ngay cả khi chúng ta biết cách xây dựng AI an toàn, vẫn sẽ có những AI độc hại do con người cố ý hoặc vô tình tạo ra. Giống như cách các tổ chức liên kết với Nga đã tạo ra các nhóm Facebook giả mạo để gây chia rẽ trong cuộc bầu cử 2016, con người sẽ sử dụng AI để thực hiện các hành động tương tự và tệ hơn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sự dồi dào sẽ không được phân phối đồng đều&lt;/strong&gt;: Mặc dù nhiều người cho rằng AI sẽ nhanh chóng dẫn đến &amp;ldquo;thời đại dồi dào&amp;rdquo; không cần tiền, tác giả lập luận rằng chỉ có AI không thể giải quyết vấn đề bất động sản, hàng hóa vật chất khan hiếm, và các nguồn lực hữu hạn. Tiền vẫn sẽ cần thiết để phân bổ các tài nguyên này.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chính trị sẽ vẫn chia rẽ sâu sắc&lt;/strong&gt;: AI sẽ không tự động giải quyết các vấn đề chính trị gây tranh cãi như phá thai, giáo dục, ngân sách, chăm sóc sức khỏe, thuế, cơ sở hạ tầng, quân đội và chính sách đối ngoại. Nhiều bất đồng cơ bản xuất phát từ xung đột giữa các giá trị sâu sắc, không phải thiếu thông tin.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chúng ta sẽ không trở thành &amp;ldquo;kiến&amp;rdquo; đối với AI&lt;/strong&gt;: Trái với quan điểm phổ biến rằng AI siêu thông minh sẽ coi con người như kiến, tác giả cho rằng AI sẽ tương tác sâu sắc với chúng ta. AI được đào tạo trên lượng lớn văn hóa con người, sẽ hiểu ngôn ngữ của chúng ta và có thể thảo luận mọi chủ đề. Kênh giao tiếp chính giữa chúng ta và AI sẽ là cuộc trò chuyện cá nhân trực tiếp về bất cứ điều gì.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tác giả kết luận rằng cả những người quá lạc quan và quá bi quan về AI đều có thể sai lầm, và sự thật nằm ở đâu đó giữa. Tương lai sẽ phức tạp, đôi khi tối tăm, nhưng cũng sẽ đẹp đẽ, truyền cảm hứng và siêu việt. Bài viết cũng nhấn mạnh rằng việc phát triển AI là không thể tránh khỏi, vì nó có tiềm năng giải quyết nhiều vấn đề cấp bách của nhân loại, từ bệnh tật đến đói nghèo.&lt;/p&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/5321bec2-0079-47e2-92e9-1cd9950227c8_2250x2624.png"
loading="lazy"
alt="Object Oriented Programming Fundamentals"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #18</title><link>https://miti99.com/post/2025/05/05/</link><pubDate>Mon, 05 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/05/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #18.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="no-longer-my-favorite-git-commit"&gt;&lt;a class="link" href="https://mtlynch.io/no-longer-my-favorite-git-commit/" target="_blank" rel="noopener"
&gt;No Longer My Favorite Git Commit&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, tác giả Michael Lynch đã xem xét lại một commit Git nổi tiếng được David Thompson ca ngợi trong bài viết &amp;ldquo;My favourite Git commit&amp;rdquo;. Commit này từng được coi là một ví dụ tuyệt vời về cách viết commit message chi tiết, nhưng theo thời gian, tác giả đã nhận ra một số nhược điểm trong cách tiếp cận này.&lt;/p&gt;
&lt;p&gt;Commit message ban đầu mô tả chi tiết quá trình debug một lỗi liên quan đến ký tự UTF-8 trong một file template, nhưng lại đặt thông tin quan trọng nhất - nội dung thực sự của thay đổi - ở cuối message. Điều này khiến người đọc phải đọc qua sáu đoạn văn và năm đoạn code để hiểu được bản chất của thay đổi: chỉ là việc thay thế một ký tự khoảng trắng.&lt;/p&gt;
&lt;p&gt;Tác giả đề xuất một phiên bản cải tiến của commit message, tuân theo nguyên tắc &amp;ldquo;kim tự tháp ngược&amp;rdquo; trong viết lách - đặt thông tin quan trọng nhất lên đầu và dần chuyển sang các chi tiết nhỏ hơn. Phiên bản cải tiến này:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bắt đầu với tóm tắt ngắn gọn về thay đổi&lt;/li&gt;
&lt;li&gt;Giải thích rõ ràng vấn đề với ký tự UTF-8 và nguồn gốc của nó&lt;/li&gt;
&lt;li&gt;Di chuyển phần lớn nội dung gốc vào phần &amp;ldquo;Cách tôi phát hiện ra điều này&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Sửa lỗi ngữ pháp và loại bỏ câu bị động để tăng tính rõ ràng&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Đây là một bài học quý giá về cách viết commit message hiệu quả, nhấn mạnh tầm quan trọng của việc truyền đạt thông tin một cách rõ ràng và có cấu trúc.&lt;/p&gt;
&lt;p&gt;Những điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Commit message nên đặt thông tin quan trọng nhất lên đầu&lt;/li&gt;
&lt;li&gt;Sử dụng cấu trúc &amp;ldquo;kim tự tháp ngược&amp;rdquo; khi viết commit message&lt;/li&gt;
&lt;li&gt;Tránh sử dụng câu bị động để tăng tính rõ ràng&lt;/li&gt;
&lt;li&gt;Chi tiết kỹ thuật vẫn quan trọng nhưng nên được sắp xếp hợp lý&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="our-interfaces-have-lost-their-senses"&gt;&lt;a class="link" href="https://wattenberger.com/thoughts/our-interfaces-have-lost-their-senses" target="_blank" rel="noopener"
&gt;Our interfaces have lost their senses&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, tác giả Amelia Wattenberger đã đưa ra những quan sát sâu sắc về sự phát triển của giao diện người dùng và cách chúng đã dần mất đi sự phong phú đa giác quan. Tác giả mô tả quá trình &amp;ldquo;Làm phẳng&amp;rdquo; (The Great Flattening) của giao diện máy tính, từ những thiết bị vật lý đầu tiên với các nút bấm và công tắc, đến dòng lệnh, rồi giao diện đồ họa, và cuối cùng là màn hình cảm ứng phẳng lì hiện nay.&lt;/p&gt;
&lt;p&gt;Đặc biệt, với sự xuất hiện của các chatbot AI, chúng ta đang mất đi nhiều hơn nữa: kết cấu, màu sắc, hình dạng. Thay vì các điều khiển tương tác phong phú, chúng ta chỉ còn lại một ô nhập văn bản. Muốn chỉnh sửa hình ảnh? Gõ lệnh. Điều chỉnh cài đặt? Nhập văn bản. Học điều gì đó? Đọc một khối văn bản khác.&lt;/p&gt;
&lt;p&gt;Tác giả cho rằng khi loại bỏ quá nhiều ma sát trong các ứng dụng, chúng ta cũng đánh mất ý nghĩa và sự hài lòng. So sánh cảm giác cuộn màn hình vô thức với việc nhào bột, chơi nhạc cụ hay phác họa - những hoạt động này đòi hỏi nỗ lực nhưng mang lại sự thỏa mãn sâu sắc.&lt;/p&gt;
&lt;p&gt;Những điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giao diện người dùng hiện đại đã mất đi sự phong phú đa giác quan&lt;/li&gt;
&lt;li&gt;Chúng ta cần xây dựng giao diện tận dụng nhiều giác quan khác nhau, không chỉ thị giác&lt;/li&gt;
&lt;li&gt;Giao diện tương lai nên hỗ trợ nhiều phương thức đồng thời: giọng nói, cử chỉ, hình ảnh, thành phần không gian&lt;/li&gt;
&lt;li&gt;Thay vì làm cho vẽ tranh giống như đánh máy, chúng ta nên làm cho việc đánh máy cảm giác như vẽ tranh&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="labeled-breaks-in-java-useful-tool-or-code-smell"&gt;&lt;a class="link" href="https://www.baeldung.com/java-labeled-break" target="_blank" rel="noopener"
&gt;Labeled Breaks in Java: Useful Tool or Code Smell?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích về cơ chế hoạt động của câu lệnh labeled break và continue trong Java, một tính năng đã tồn tại từ Java 1.0 và vẫn được duy trì đến nay. Tác giả đặt câu hỏi liệu đây là một công cụ hữu ích hay là một mùi code (code smell) cần tránh.&lt;/p&gt;
&lt;p&gt;Labeled break cho phép lập trình viên thoát khỏi các vòng lặp lồng nhau một cách cụ thể. Ví dụ:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;outer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// &amp;lt;-- label&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;, &amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;outer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// thoát khỏi vòng lặp ngoài&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Tác giả phân tích cả ưu điểm và nhược điểm của kỹ thuật này. Về ưu điểm, labeled break mang lại hiệu quả trong các vòng lặp lồng nhau bằng cách cho phép thoát ngay lập tức mà không cần thêm cờ hoặc điều kiện phụ. Nó cũng cung cấp khả năng kiểm soát chi tiết, cho phép nhắm đến các vòng lặp cụ thể trong cấu trúc lồng nhau sâu.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, nhược điểm đáng kể là tính dễ đọc bị ảnh hưởng vì các label có thể giống như các lệnh GOTO, gây nhầm lẫn cho người bảo trì không quen với mã. Bảo trì cũng trở nên khó khăn hơn; việc sửa đổi một vòng lặp có label có thể phá vỡ các phụ thuộc của nó, đặc biệt trong các codebase lớn.&lt;/p&gt;
&lt;p&gt;Tác giả cũng so sánh cách tiếp cận này với các ngôn ngữ khác như Kotlin và JavaScript, đồng thời đề xuất các giải pháp thay thế hiện đại hơn như sử dụng Stream API trong Java.&lt;/p&gt;
&lt;p&gt;Những điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Labeled break có thể hữu ích trong một số trường hợp cụ thể nhưng cần cân nhắc kỹ lưỡng&lt;/li&gt;
&lt;li&gt;Các giải pháp thay thế như refactoring thành các phương thức riêng biệt hoặc sử dụng Stream API thường rõ ràng hơn&lt;/li&gt;
&lt;li&gt;Labeled break tồn tại trong nhiều ngôn ngữ khác như Kotlin và JavaScript với cú pháp tương tự&lt;/li&gt;
&lt;li&gt;Xu hướng lập trình hiện đại thường tránh sử dụng labeled break trừ khi thực sự cần thiết&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="distributed-locking-a-practical-guide"&gt;&lt;a class="link" href="https://www.architecture-weekly.com/p/distributed-locking-a-practical-guide" target="_blank" rel="noopener"
&gt;Distributed Locking: A Practical Guide&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, tác giả Oskar Dudycz đã cung cấp một hướng dẫn thực tế về khóa phân tán (distributed locking) - một công cụ cơ bản nhưng quan trọng trong hệ thống phân tán. Khi một ứng dụng được mở rộng trên nhiều máy hoặc microservices, các vấn đề về đồng thời có thể phát sinh khi nhiều tiến trình cố gắng cập nhật cùng một tài nguyên.&lt;/p&gt;
&lt;p&gt;Tác giả giải thích cách thức hoạt động cơ bản của khóa phân tán: một node yêu cầu quyền truy cập độc quyền vào một tài nguyên chia sẻ bằng cách tạo một khóa. Nếu khóa chưa tồn tại, node sẽ tạo khóa và thực hiện thao tác cần thiết. Sau khi hoàn thành, node sẽ giải phóng khóa. Điều quan trọng là các khóa cần có cơ chế tự động giải phóng trong trường hợp node gặp sự cố, thường thông qua cơ chế TTL (Time-to-Live) hoặc ephemeral nodes.&lt;/p&gt;
&lt;p&gt;Bài viết phân tích các công cụ phổ biến cho khóa phân tán:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Redis&lt;/strong&gt;: Sử dụng khóa dựa trên TTL, đơn giản và hiệu quả nếu bạn đã sử dụng Redis, nhưng cần thận trọng với các vấn đề về phân chia mạng hoặc cluster.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ZooKeeper/etcd&lt;/strong&gt;: Cung cấp bảo đảm tính nhất quán mạnh mẽ hơn thông qua ephemeral nodes, phức tạp hơn nhưng mạnh mẽ hơn cho các hệ thống phức tạp.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Database Locks&lt;/strong&gt;: Sử dụng cơ chế khóa của cơ sở dữ liệu, thuận tiện nếu đã có một cơ sở dữ liệu duy nhất, nhưng có thể không mở rộng tốt qua nhiều cơ sở dữ liệu hoặc vùng.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kubernetes Single-Instance&lt;/strong&gt;: Đơn giản hóa vấn đề bằng cách chỉ chạy một bản sao của dịch vụ, tránh đồng thời hoàn toàn nhưng đánh đổi khả năng mở rộng và tính sẵn sàng cao.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tác giả cũng thảo luận về các vấn đề tiềm ẩn và cách giải quyết, như deadlocks, lock contention, xử lý sự cố, điểm lỗi đơn và các vấn đề về đồng hồ và phân chia mạng.&lt;/p&gt;
&lt;p&gt;Những điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nên tránh sử dụng khóa phân tán nếu có thể, chỉ sử dụng khi thực sự cần thiết&lt;/li&gt;
&lt;li&gt;Sử dụng khóa cẩn thận: Quá nhiều khóa có thể làm giảm tính đồng thời, nhưng rất quan trọng khi cần ngăn chặn hư hỏng dữ liệu&lt;/li&gt;
&lt;li&gt;Chọn đúng công cụ lưu trữ: Redis thường đơn giản nhất nếu đã sử dụng, ZooKeeper phù hợp với điều phối nâng cao&lt;/li&gt;
&lt;li&gt;Lập kế hoạch cho sự cố: Triển khai khóa TTL/ephemeral để tránh khóa &amp;ldquo;zombie&amp;rdquo; hoặc bị kẹt&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="if-it-is-worth-keeping-save-it-in-markdown"&gt;&lt;a class="link" href="https://p.migdal.pl/blog/2025/02/markdown-saves" target="_blank" rel="noopener"
&gt;If it is worth keeping, save it in Markdown&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, tác giả Piotr Migdal chia sẻ quan điểm về việc bảo quản nội dung số dài hạn bằng định dạng Markdown. Tác giả bắt đầu với một cảnh báo: &amp;ldquo;Nếu bạn xuất bản điều gì đó trực tuyến, sớm hay muộn, nó sẽ biến mất.&amp;rdquo; Đây là một thực tế đáng buồn của thế giới số - các liên kết thay đổi, các nền tảng đóng cửa, và nội dung có thể biến mất vĩnh viễn nếu không được lưu trữ đúng cách.&lt;/p&gt;
&lt;p&gt;Tác giả đề xuất giải pháp sử dụng định dạng văn bản thuần (plaintext) với mã hóa UTF-8 và định dạng Markdown. Đây là một lựa chọn bền vững vì:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Các tập tin văn bản thuần có thể được đọc bởi bất kỳ máy tính nào, không cần phần mềm chuyên dụng&lt;/li&gt;
&lt;li&gt;Markdown cung cấp cú pháp đơn giản cho các phần tử thông dụng như tiêu đề, danh sách, liên kết&lt;/li&gt;
&lt;li&gt;Theo nguyên tắc &amp;ldquo;sức mạnh tối thiểu&amp;rdquo;, Markdown tránh kiểm soát chi tiết về hiển thị, giúp nó ít phức tạp và bền vững hơn&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tác giả sử dụng Obsidian cho ghi chú cá nhân và các trình tạo trang tĩnh cho blog, cả hai đều dựa trên Markdown. Điều này tạo ra một quy trình lưu trữ và chia sẻ nội dung linh hoạt. Tác giả cũng mô tả cách tiếp cận thực tế của mình: khi tìm thấy nội dung đáng giữ lại, anh sao chép nó vào tập tin markdown, thêm frontmatter với ngày xuất bản, nguồn gốc và các thẻ liên quan.&lt;/p&gt;
&lt;p&gt;Có nhiều công cụ hỗ trợ chuyển đổi định dạng, từ pandoc đa năng đến các công cụ chuyên biệt cho các nền tảng cụ thể. Thậm chí, các công cụ AI hiện đại cũng có thể giúp chuyển đổi nội dung phức tạp sang Markdown.&lt;/p&gt;
&lt;p&gt;Những điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nội dung số có thể biến mất bất cứ lúc nào, đặc biệt trong các &amp;ldquo;vườn tường&amp;rdquo; yêu cầu đăng nhập&lt;/li&gt;
&lt;li&gt;Văn bản thuần với Markdown là định dạng bền vững nhất cho lưu trữ dài hạn&lt;/li&gt;
&lt;li&gt;Nội dung đáng tìm kiếm một lần là nội dung đáng bảo quản vĩnh viễn&lt;/li&gt;
&lt;li&gt;Các công cụ như Obsidian, pandoc và AI có thể hỗ trợ quy trình lưu trữ và chuyển đổi&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-software-engineering-identity-crisis"&gt;&lt;a class="link" href="https://annievella.com/posts/the-software-engineering-identity-crisis/" target="_blank" rel="noopener"
&gt;The Software Engineering Identity Crisis&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết sâu sắc này, tác giả Annie Vella đã phân tích cuộc khủng hoảng bản sắc mà các kỹ sư phần mềm đang phải đối mặt trong kỷ nguyên AI. Tác giả bắt đầu bằng việc nhận diện bản chất của vấn đề: nhiều người trong chúng ta trở thành kỹ sư phần mềm vì tìm thấy bản sắc của mình trong việc xây dựng, tạo ra các giải pháp bằng chính tay, trí óc và code của mình.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, với sự xuất hiện của các trợ lý lập trình AI, bản sắc này đang bị thách thức sâu sắc. Chúng ta đang chuyển từ vai trò người sáng tạo sang người điều phối, từ người xây dựng sang người giám sát. Tác giả dẫn chứng bằng các con số đáng chú ý: Google tiết lộ rằng AI tạo ra hơn một phần tư mã mới của họ, trong khi CEO của Y Combinator cho biết khoảng một phần tư các startup của họ có 95% mã được viết bởi AI.&lt;/p&gt;
&lt;p&gt;Tác giả cũng đề cập đến khái niệm &amp;ldquo;vibe coding&amp;rdquo; do Andrej Karpathy đề xuất - một cách tiếp cận mới trong việc viết phần mềm, nơi chúng ta tập trung vào ý định (what) thay vì cách thực hiện (how), để AI điền vào các chi tiết. Điều này đặt ra câu hỏi: chúng ta còn là kỹ sư nếu quên đi tất cả về code?&lt;/p&gt;
&lt;p&gt;Tuy nhiên, tác giả không nhìn nhận sự chuyển đổi này hoàn toàn tiêu cực. Bài viết đưa ra một góc nhìn lạc quan: AI không lấy đi công việc của chúng ta mà đang cho chúng ta cơ hội để lấy lại những khía cạnh rộng lớn hơn của vai trò mà chúng ta đã giao cho các chuyên gia. Để trở lại thời điểm mà kỹ thuật phần mềm có nghĩa là nhiều hơn chỉ là viết code - khi nó có nghĩa là hiểu toàn bộ không gian vấn đề, từ nhu cầu người dùng đến tác động kinh doanh, từ thiết kế hệ thống đến sự xuất sắc trong vận hành.&lt;/p&gt;
&lt;p&gt;Những điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kỹ sư phần mềm đang chuyển từ người sáng tạo sang người điều phối AI&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Vibe coding&amp;rdquo; đại diện cho sự chuyển dịch từ việc tập trung vào cách thực hiện sang tập trung vào ý định&lt;/li&gt;
&lt;li&gt;Các kỹ năng bền vững như giao tiếp, tư duy tổng thể, xử lý sự không rõ ràng trở nên quan trọng hơn trong thế giới do AI điều khiển&lt;/li&gt;
&lt;li&gt;Cuộc khủng hoảng bản sắc này tương tự như thời kỳ Cách mạng Công nghiệp, khi các thợ thủ công phải thích nghi với máy móc&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="revenge-of-the-junior-developer"&gt;&lt;a class="link" href="https://sourcegraph.com/blog/revenge-of-the-junior-developer" target="_blank" rel="noopener"
&gt;Revenge of the junior developer&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết mới nhất của mình, Steve Yegge - một chuyên gia có tiếng trong ngành phần mềm - đã đưa ra những nhận định bất ngờ về sự thay đổi của ngành công nghiệp phần mềm dưới tác động của AI. Trái ngược với bài viết trước đó của ông về &amp;ldquo;Cái chết của lập trình viên mới&amp;rdquo;, bài viết này lại chỉ ra rằng chính các lập trình viên mới lại là những người đang nắm bắt cơ hội tốt hơn trong kỷ nguyên AI.&lt;/p&gt;
&lt;p&gt;Tác giả mô tả sự phát triển của lập trình qua sáu làn sóng chồng lấn nhau: lập trình truyền thống (2022), lập trình với các công cụ hoàn thành mã (2023), lập trình dựa trên chat (2024), các agent lập trình (2025 H1), các cụm agent (2025 H2), và đội hình agent (2026). Ông giới thiệu khái niệm &amp;ldquo;vibe coding&amp;rdquo; - một cách lập trình dựa trên chat, nơi bạn yêu cầu LLM viết mã, sau đó cung cấp kết quả và yêu cầu thêm trong một vòng lặp liên tục.&lt;/p&gt;
&lt;p&gt;Một phát hiện đáng chú ý là các lập trình viên mới thực sự đã nhanh chóng áp dụng AI hơn các lập trình viên có kinh nghiệm. Họ đã nắm bắt các công cụ trợ lý lập trình, sử dụng lập trình dựa trên chat, và thậm chí đã bắt đầu sử dụng các agent lập trình. Trong khi đó, nhiều lập trình viên có kinh nghiệm lại đang phải vật lộn với sự thay đổi này, thậm chí có những người hoàn toàn chống lại việc sử dụng AI.&lt;/p&gt;
&lt;p&gt;Tác giả cho rằng điều này xảy ra vì các lập trình viên có kinh nghiệm đã đầu tư quá nhiều vào hiện trạng, và họ cảm thấy rằng việc phải học một điều gì đó hoàn toàn mới giống như phải bắt đầu lại từ đầu. Tuy nhiên, ông cảnh báo rằng những người từ chối AI đã thua cuộc, và các lập trình viên mới đang nắm giữ lợi thế.&lt;/p&gt;
&lt;p&gt;Kết luận của bài viết là công việc &amp;ldquo;kỹ sư phần mềm&amp;rdquo; vào cuối năm nay sẽ bao gồm ít lập trình trực tiếp và nhiều giám sát agent hơn. Các agent lập trình đang đến, và càng sớm thích nghi với điều đó, cuộc sống của bạn sẽ càng dễ dàng hơn.&lt;/p&gt;
&lt;p&gt;Những điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lập trình viên mới đang nhanh chóng áp dụng AI hơn các lập trình viên có kinh nghiệm&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Vibe coding&amp;rdquo; là cách lập trình dựa trên chat, nhưng sẽ sớm bị thay thế bởi các agent lập trình&lt;/li&gt;
&lt;li&gt;Công việc kỹ sư phần mềm sẽ chuyển từ viết mã trực tiếp sang giám sát các agent&lt;/li&gt;
&lt;li&gt;Để thành công, hãy &amp;ldquo;học hỏi từ các lập trình viên mới&amp;rdquo; và nhanh chóng thích nghi với công nghệ mới&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/111cec1b-a195-4ff5-963c-714ceecd01ab_1280x1664.gif"
loading="lazy"
alt="How does SSO Work?"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/b415d54d-0dbd-428d-a09c-3de0332c0f71_1280x1502.gif"
loading="lazy"
alt="How Java Virtual Threads Work?"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/8ef255cc-ebbb-4710-9faf-f366274a2bef_1280x1373.gif"
loading="lazy"
alt="Memcached vs Redis"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/2370fff4-b515-484e-a081-4ce73b2c62c2_1280x1566.gif"
loading="lazy"
alt="The Shopify Tech Stack"
&gt;&lt;/p&gt;
&lt;h2 id="bonus-2-vài-video-hay-ho-đến-từ-bytebytego"&gt;Bonus 2: Vài video hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=eHEHE2fpnWQ" target="_blank" rel="noopener"
&gt;What Are AI Agents Really About?&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Newsletter #17</title><link>https://miti99.com/post/2025/05/04/</link><pubDate>Sun, 04 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/04/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #17.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="to-fork-or-not-to-fork"&gt;&lt;a class="link" href="https://www.augmentcode.com/blog/to-fork-or-not-to-fork" target="_blank" rel="noopener"
&gt;To fork or not to fork?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích sâu về hai cách tiếp cận khác nhau trong việc tích hợp AI vào môi trường phát triển phần mềm (IDE). Tác giả so sánh hai phương pháp chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phương pháp plugin tiêu chuẩn (được sử dụng bởi GitHub Copilot và Augment Code)&lt;/li&gt;
&lt;li&gt;Phương pháp fork IDE (được sử dụng bởi Cursor và Codeium với Windsurf)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết chỉ ra những thách thức và rủi ro khi fork VS Code, bao gồm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Người dùng bị buộc phải chuyển đổi IDE&lt;/li&gt;
&lt;li&gt;Mất hỗ trợ từ Microsoft&lt;/li&gt;
&lt;li&gt;Mất khả năng tương thích với hệ sinh thái Microsoft&lt;/li&gt;
&lt;li&gt;Mất quyền truy cập vào các tính năng mới của VS Code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tác giả kết luận rằng Augment Code đã chọn không fork VS Code để đảm bảo tính bền vững lâu dài cho người dùng, đồng thời tập trung vào việc cung cấp giải pháp AI chuyên sâu cho các dự án phức tạp.&lt;/p&gt;
&lt;h3 id="điểm-chính-cần-lưu-ý"&gt;Điểm chính cần lưu ý:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Việc fork IDE có thể mang lại lợi ích ngắn hạn nhưng tiềm ẩn nhiều rủi ro dài hạn&lt;/li&gt;
&lt;li&gt;Các plugin tiêu chuẩn có thể mất nhiều thời gian hơn để hoàn thiện nhưng mang lại trải nghiệm người dùng ổn định hơn&lt;/li&gt;
&lt;li&gt;Sự cạnh tranh trong lĩnh vực AI coding đang thúc đẩy sự đổi mới và giá trị cho người dùng&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-i"&gt;&lt;a class="link" href="https://blog.container-solutions.com/why-im-no-longer-talking-to-architects-about-microservices" target="_blank" rel="noopener"
&gt;Why I&amp;rsquo;m No Longer Talking to Architects About Microservices&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phản ánh sự mệt mỏi của tác giả khi thảo luận về microservices với các kiến trúc sư phần mềm, bởi thuật ngữ này ngày càng trở nên mơ hồ và các cuộc trao đổi thường thiếu trọng tâm thực tiễn. Tác giả chỉ ra rằng không có định nghĩa thống nhất về microservices, dẫn đến việc mỗi người hiểu và áp dụng khác nhau, gây ra nhiều hiểu lầm trong quá trình thiết kế hệ thống.&lt;/p&gt;
&lt;p&gt;Một vấn đề lớn là các cuộc thảo luận về microservices thường tách rời mục tiêu kinh doanh thực tế. Nhiều tổ chức theo đuổi microservices vì lý do “xu hướng” mà không xác định rõ vấn đề kinh doanh cần giải quyết, dẫn đến việc gia tăng phức tạp mà không mang lại giá trị thiết thực. Tác giả nhấn mạnh rằng nên tập trung vào các mục tiêu như rút ngắn thời gian phát triển, tăng độ tin cậy và giải quyết các nút thắt cụ thể thay vì chạy theo công nghệ mới một cách mù quáng.&lt;/p&gt;
&lt;p&gt;Bên cạnh đó, microservices chỉ thực sự phát huy hiệu quả khi đi kèm với thay đổi tổ chức, như xây dựng các nhóm đa chức năng, tự chủ và phát triển văn hóa DevOps trưởng thành. Nếu tổ chức không sẵn sàng thay đổi về mặt vận hành và quản trị, việc áp dụng microservices có thể khiến mọi thứ trở nên tồi tệ hơn.&lt;/p&gt;
&lt;h3 id="điểm-chính-cần-lưu-ý-1"&gt;Điểm chính cần lưu ý:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Không có định nghĩa thống nhất về microservices, dẫn đến nhiều hiểu lầm.&lt;/li&gt;
&lt;li&gt;Các cuộc thảo luận về microservices thường thiếu liên hệ với mục tiêu kinh doanh cụ thể.&lt;/li&gt;
&lt;li&gt;Microservices chỉ có ý nghĩa khi tổ chức thay đổi cấu trúc và quy trình phù hợp.&lt;/li&gt;
&lt;li&gt;Nên tập trung vào giải quyết vấn đề thực tế thay vì chạy theo công nghệ.&lt;/li&gt;
&lt;li&gt;Việc áp dụng microservices không phù hợp có thể làm tăng sự phức tạp và giảm hiệu quả tổ chức.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="not-all-ai-assisted-programming-is-vibe-coding-but-vibe-coding-rocks"&gt;&lt;a class="link" href="https://simonwillison.net/2025/Mar/19/vibe-coding/" target="_blank" rel="noopener"
&gt;Not all AI-assisted programming is vibe coding (but vibe coding rocks)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Simon Willison phân tích sự khác biệt giữa &amp;ldquo;vibe coding&amp;rdquo; (lập trình cảm hứng với AI) và các hình thức lập trình hỗ trợ bởi AI khác. Tác giả cho rằng vibe coding giúp hạ thấp rào cản cho người mới tiếp cận lập trình, đồng thời mở ra nhiều cơ hội sáng tạo cho cả lập trình viên giàu kinh nghiệm. Tuy nhiên, ông cũng nhấn mạnh rằng việc sử dụng AI trong lập trình đòi hỏi phải xây dựng trực giác và hiểu biết về các giới hạn của công cụ.&lt;/p&gt;
&lt;p&gt;Simon cũng cảnh báo về những rủi ro khi &amp;ldquo;vibe coding&amp;rdquo; với các dự án có yếu tố bảo mật, dữ liệu nhạy cảm hoặc liên quan đến chi phí tài chính. Ông khuyến nghị chỉ nên áp dụng vibe coding cho các dự án có rủi ro thấp và luôn cân nhắc đến bảo mật, quyền riêng tư và tác động tới cộng đồng mạng. Nếu dự án có thể ảnh hưởng đến người khác, nên tham khảo ý kiến chuyên gia trước khi chia sẻ rộng rãi.&lt;/p&gt;
&lt;h3 id="điểm-chính-cần-lưu-ý-2"&gt;Điểm chính cần lưu ý:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Vibe coding giúp giảm rào cản cho người mới học lập trình và thúc đẩy sáng tạo.&lt;/li&gt;
&lt;li&gt;Cần xây dựng trực giác về giới hạn và khả năng của AI khi lập trình.&lt;/li&gt;
&lt;li&gt;Không nên áp dụng vibe coding cho các dự án có rủi ro bảo mật hoặc tài chính cao.&lt;/li&gt;
&lt;li&gt;Luôn chú ý tới bảo mật, quyền riêng tư và tác động tới cộng đồng khi dùng AI hỗ trợ lập trình.&lt;/li&gt;
&lt;li&gt;Nên tham khảo ý kiến chuyên gia nếu dự án sẽ được sử dụng bởi nhiều người.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="career-advice-in-2025"&gt;&lt;a class="link" href="https://lethain.com/career-advice-2025" target="_blank" rel="noopener"
&gt;Career advice in 2025.&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Will Larson phân tích sâu về những thay đổi lớn trong thị trường việc làm công nghệ năm 2025 và đưa ra lời khuyên thực tế cho các chuyên gia phần mềm. Tác giả nhấn mạnh rằng các công ty phi AI ngày càng khó tiếp cận vốn và cơ hội tăng trưởng, trong khi các công ty AI cạnh tranh khốc liệt và không phải ai cũng hưởng lợi lớn từ làn sóng này.&lt;/p&gt;
&lt;p&gt;Thị trường việc làm chuyển dịch trọng tâm từ kỹ năng quản lý sang khả năng làm việc chi tiết, đẩy nhanh tiến độ và thích nghi với các mô hình AI nền tảng. Nhiều lãnh đạo kỳ cựu cảm thấy khó thích nghi, trong khi những người từng giỏi về tốc độ lại gặp khó trong việc thăng tiến. Sự thay đổi này khiến nhiều người cảm thấy bị bỏ lại phía sau, dù không phải ai cũng gặp tình trạng này.&lt;/p&gt;
&lt;p&gt;Tác giả cũng cảnh báo rằng việc áp dụng AI vào sản phẩm đòi hỏi tư duy thiết kế mới, với xác thực tiến bộ và kỹ thuật human-in-the-loop. Các công ty cần chuẩn bị cho cả kịch bản AI phát triển vượt bậc lẫn trường hợp không có cải tiến lớn trong vài năm tới.&lt;/p&gt;
&lt;h3 id="điểm-chính-cần-lưu-ý-3"&gt;Điểm chính cần lưu ý:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Các công ty phi AI khó tiếp cận vốn, tăng trưởng và thăng tiến.&lt;/li&gt;
&lt;li&gt;Các công ty AI cạnh tranh khốc liệt, không phải ai cũng hưởng lợi lớn.&lt;/li&gt;
&lt;li&gt;Thị trường việc làm ưu tiên kỹ năng chi tiết, tốc độ và thích nghi với AI.&lt;/li&gt;
&lt;li&gt;Lãnh đạo kỳ cựu và nhân sự cũ gặp khó khăn trong môi trường mới.&lt;/li&gt;
&lt;li&gt;Áp dụng AI đòi hỏi thiết kế sản phẩm với xác thực tiến bộ và human-in-the-loop.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tips-for-better-interactions"&gt;&lt;a class="link" href="https://staysaasy.com/saas/2025/03/17/interactions.html" target="_blank" rel="noopener"
&gt;Tips For Better Interactions&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ các lời khuyên thực tế giúp nâng cao chất lượng các cuộc họp và tương tác trong môi trường làm việc hiện đại. Tác giả nhấn mạnh tầm quan trọng của việc kiểm soát cảm xúc, chủ động ghi chú, tránh tranh luận không cần thiết và lựa chọn thời điểm phù hợp cho các cuộc trao đổi quan trọng.&lt;/p&gt;
&lt;p&gt;Một số điểm nổi bật bao gồm: không để bị gán nhãn là &amp;ldquo;frustrated&amp;rdquo; trong cuộc họp; ghi chú giúp bạn trở thành người dẫn dắt hiệu quả; tránh phản đối theo kiểu &amp;ldquo;nếu làm quá sẽ&amp;hellip;&amp;rdquo;; chấp nhận để người khác sai ở những chi tiết không quan trọng; và sắp xếp thời gian họp hợp lý để tăng hiệu quả.&lt;/p&gt;
&lt;h3 id="điểm-chính-cần-lưu-ý-4"&gt;Điểm chính cần lưu ý:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Không đồng ý với việc bị gán nhãn &amp;ldquo;frustrated&amp;rdquo; hoặc &amp;ldquo;upset&amp;rdquo; trong công việc.&lt;/li&gt;
&lt;li&gt;Chủ động ghi chú trong cuộc họp giúp nâng cao vai trò lãnh đạo và kiểm soát thảo luận.&lt;/li&gt;
&lt;li&gt;Tránh phản đối kiểu &amp;ldquo;boundary objections&amp;rdquo; không thực tế.&lt;/li&gt;
&lt;li&gt;Chấp nhận để người khác sai ở những chi tiết không quan trọng, tập trung vào mục tiêu chính.&lt;/li&gt;
&lt;li&gt;Sắp xếp thời gian họp và tương tác hợp lý, tránh các khung giờ kém hiệu quả.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="code-is-the-new-no-code"&gt;&lt;a class="link" href="https://lumberjack.so/p/code-is-the-new-no-code" target="_blank" rel="noopener"
&gt;Code is the new no-code&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích sự chuyển dịch từ các nền tảng no-code sang việc lập trình truyền thống với sự hỗ trợ mạnh mẽ của AI và các mô hình thành phần (component-based) như React. Tác giả cho rằng, dù no-code hứa hẹn giúp mọi người xây dựng phần mềm mà không cần biết lập trình, thực tế các công cụ này vẫn gặp giới hạn về độ phức tạp và khả năng mở rộng.&lt;/p&gt;
&lt;p&gt;Nhiều người dùng no-code cuối cùng vẫn phải học lập trình hoặc mong muốn có thể viết mã để giải quyết các vấn đề phức tạp. Sự phát triển của AI coding assistant và các framework hiện đại đã thu hẹp khoảng cách giữa no-code và code, giúp việc lập trình trở nên dễ tiếp cận hơn, đồng thời duy trì được sự linh hoạt và sức mạnh vốn có của code.&lt;/p&gt;
&lt;h3 id="điểm-chính-cần-lưu-ý-5"&gt;Điểm chính cần lưu ý:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Các nền tảng no-code ngày càng tích hợp thêm khả năng viết mã để đáp ứng nhu cầu phức tạp.&lt;/li&gt;
&lt;li&gt;AI coding assistant đang phát triển nhanh hơn bất kỳ nền tảng no-code nào trước đây.&lt;/li&gt;
&lt;li&gt;Khoảng cách kiến thức giữa coder và non-coder đang dần thu hẹp nhờ AI giải thích và hỗ trợ trực tiếp.&lt;/li&gt;
&lt;li&gt;Mô hình component-based (như React) giúp lập trình backend và workflow trở nên trực quan, dễ bảo trì hơn.&lt;/li&gt;
&lt;li&gt;Lập trình truyền thống, khi được hỗ trợ tốt, vẫn là con đường bền vững và mạnh mẽ nhất cho phát triển phần mềm.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-to-improve-jvm-based-application-startup-time"&gt;&lt;a class="link" href="https://softwaremill.com/how-to-improve-jvm-based-application-startup-time/" target="_blank" rel="noopener"
&gt;How to Improve JVM-Based Application Startup Time?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết tổng hợp và so sánh các phương pháp tối ưu hóa thời gian khởi động ứng dụng dựa trên JVM, một chủ đề quan trọng đối với các hệ thống yêu cầu hiệu năng cao hoặc khởi động nhanh (như serverless, microservices). Tác giả phân tích các giải pháp như Class Data Sharing (CDS), Application Class Data Sharing (AppCDS), GraalVM, CRaC và Project Leyden, đồng thời cung cấp số liệu benchmark thực tế trên nhiều môi trường khác nhau.&lt;/p&gt;
&lt;p&gt;Kết quả cho thấy AppCDS dễ áp dụng nhưng hiệu quả vừa phải; CRaC và GraalVM mang lại tốc độ khởi động nhanh nhất, phù hợp cho các ứng dụng chạy lâu hoặc ngắn hạn tuỳ trường hợp. Project Leyden vẫn đang phát triển nhưng hứa hẹn nhiều tiềm năng. Lựa chọn giải pháp tối ưu cần dựa vào đặc thù ứng dụng và môi trường triển khai.&lt;/p&gt;
&lt;h3 id="điểm-chính-cần-lưu-ý-6"&gt;Điểm chính cần lưu ý:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;JVM khởi động chậm do quá trình load, verify, initialize class.&lt;/li&gt;
&lt;li&gt;AppCDS dễ dùng, cải thiện thời gian khởi động gấp đôi so với mặc định.&lt;/li&gt;
&lt;li&gt;CRaC phù hợp cho ứng dụng chạy lâu dài, tận dụng tối ưu runtime.&lt;/li&gt;
&lt;li&gt;GraalVM thích hợp cho ứng dụng ngắn hạn cần khởi động siêu nhanh.&lt;/li&gt;
&lt;li&gt;Project Leyden là hướng đi tiềm năng nhưng vẫn chưa hoàn thiện.&lt;/li&gt;
&lt;li&gt;Không có giải pháp “một cho tất cả”, cần cân nhắc theo từng trường hợp thực tế.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="domain-driven-design"&gt;&lt;a class="link" href="https://dev.to/lovestaco/domain-driven-design-3i2j" target="_blank" rel="noopener"
&gt;Domain Driven Design&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giới thiệu tổng quan về Domain Driven Design (DDD) – một phương pháp thiết kế phần mềm đặt trọng tâm vào lĩnh vực nghiệp vụ (domain) thay vì chỉ tập trung vào kỹ thuật. DDD giúp tổ chức hệ thống thành các phần độc lập, rõ ràng, tăng khả năng mở rộng, bảo trì và giao tiếp giữa đội ngũ phát triển với chuyên gia nghiệp vụ.&lt;/p&gt;
&lt;p&gt;Tác giả trình bày các khái niệm cốt lõi như Domain/Subdomain, Bounded Context, Entity, Value Object, Aggregate, Domain Event, Repository, Service, Factory và Ubiquitous Language. Việc áp dụng đúng các khái niệm này giúp giảm phức tạp, tăng tính nhất quán và đảm bảo phần mềm phát triển đúng hướng với nhu cầu kinh doanh.&lt;/p&gt;
&lt;h3 id="điểm-chính-cần-lưu-ý-7"&gt;Điểm chính cần lưu ý:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Domain là phạm vi nghiệp vụ chính, có thể chia thành nhiều subdomain nhỏ.&lt;/li&gt;
&lt;li&gt;Bounded Context giúp xác định ranh giới rõ ràng cho từng phần nghiệp vụ, tránh xung đột mô hình dữ liệu.&lt;/li&gt;
&lt;li&gt;Entity có danh tính riêng, Value Object bất biến và xác định bằng thuộc tính.&lt;/li&gt;
&lt;li&gt;Aggregate gom nhóm các thực thể liên quan, Aggregate Root đảm bảo tính nhất quán.&lt;/li&gt;
&lt;li&gt;Domain Event giúp tách biệt logic nghiệp vụ, tăng khả năng mở rộng.&lt;/li&gt;
&lt;li&gt;Repository, Service, Factory hỗ trợ quản lý, thao tác và khởi tạo đối tượng domain.&lt;/li&gt;
&lt;li&gt;Ubiquitous Language là ngôn ngữ chung giữa kỹ thuật và nghiệp vụ, giúp giảm hiểu lầm khi phát triển phần mềm.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/66d12ddc-2abe-4a98-82d5-ee177e80487c_1470x1600.png"
loading="lazy"
alt="Monolith vs Microservices vs Modular Monoliths"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #16</title><link>https://miti99.com/post/2025/05/03/</link><pubDate>Sat, 03 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/03/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #16.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="choosing-languages"&gt;&lt;a class="link" href="https://steveklabnik.com/writing/choosing-languages" target="_blank" rel="noopener"
&gt;Choosing Languages&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Steve Klabnik bàn về việc lựa chọn ngôn ngữ lập trình, được viết sau khi Microsoft thông báo sẽ viết lại TypeScript compiler bằng Go. Tác giả chia sẻ góc nhìn sâu sắc về việc tại sao chúng ta không nên vội vàng phán xét lựa chọn ngôn ngữ lập trình của người khác.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bối cảnh quan trọng&lt;/strong&gt;: Mỗi dự án có những yêu cầu và bối cảnh riêng. Ví dụ, Microsoft chọn Go vì code hiện tại của họ tương tự với Go, giúp việc port code dễ dàng hơn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Trải nghiệm cá nhân&lt;/strong&gt;: Tác giả chia sẻ câu chuyện về việc từng chỉ trích một người viết công cụ grep bằng Node.js vào năm 2013. Sự việc này đã thay đổi cách nhìn của ông về việc phán xét lựa chọn công nghệ của người khác.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Văn hóa cộng đồng&lt;/strong&gt;: Klabnik nhấn mạnh tầm quan trọng của việc xây dựng văn hóa cộng đồng tích cực, không chỉ trích ngôn ngữ khác mà tập trung vào ưu điểm của ngôn ngữ mình chọn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thông điệp chính&lt;/strong&gt;: Mỗi người có lý do riêng để chọn một ngôn ngữ lập trình, và chúng ta nên tôn trọng những lựa chọn đó thay vì vội vàng phán xét. Điều quan trọng là hiểu được bối cảnh đằng sau mỗi quyết định.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="how-long-should-functions-be"&gt;&lt;a class="link" href="https://tidyfirst.substack.com/p/how-long-should-functions-be" target="_blank" rel="noopener"
&gt;How Long Should Functions Be?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Kent Beck phân tích về độ dài của các hàm trong lập trình, dựa trên dữ liệu thực tế từ JUnit 5. Tác giả đưa ra những góc nhìn thú vị về việc tại sao chúng ta không nên áp đặt một con số cố định cho độ dài của hàm.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phân phối theo quy luật lũy thừa&lt;/strong&gt;: Độ dài của các hàm tuân theo quy luật phân phối lũy thừa (power law), không phải một con số cố định. Dữ liệu từ JUnit 5 cho thấy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nhiều hàm ngắn (1-3 dòng)&lt;/li&gt;
&lt;li&gt;Một số ít hàm dài&lt;/li&gt;
&lt;li&gt;Hệ số lũy thừa (α) là 2.46&lt;/li&gt;
&lt;li&gt;Giá trị R-squared là 0.96, cho thấy mối tương quan mạnh&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kết quả phân tích&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Độ dài trung bình của hàm là 3.49 dòng&lt;/li&gt;
&lt;li&gt;Phạm vi từ 1 đến 74 dòng&lt;/li&gt;
&lt;li&gt;Các hàm dài có xu hướng ngày càng dài hơn theo thời gian&lt;/li&gt;
&lt;li&gt;Dự án càng lớn, độ dài trung bình của hàm càng tăng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ý nghĩa quan trọng&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không có độ dài &amp;ldquo;đúng&amp;rdquo; cố định cho các hàm&lt;/li&gt;
&lt;li&gt;Phân phối tự nhiên bao gồm:
&lt;ul&gt;
&lt;li&gt;Nhiều hàm ngắn&lt;/li&gt;
&lt;li&gt;Một số ít hàm dài&lt;/li&gt;
&lt;li&gt;Các hàm dài nhất sẽ tiếp tục phát triển khi hệ thống mở rộng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các yếu tố ảnh hưởng&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Độ dốc của phân phối có thể được điều chỉnh&lt;/li&gt;
&lt;li&gt;Phát triển hướng thử nghiệm (TDD) đã được chứng minh là có tương quan với độ dốc lớn hơn&lt;/li&gt;
&lt;li&gt;Độ dốc lớn hơn đồng nghĩa với nhiều hàm ngắn hơn và giảm độ dài của các hàm dài nhất&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="what-makes-code-hard-to-read-visual-patterns-of-complexity"&gt;&lt;a class="link" href="https://seeinglogic.com/posts/visual-readability-patterns/" target="_blank" rel="noopener"
&gt;What Makes Code Hard To Read: Visual Patterns of Complexity&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích các mẫu hình trực quan ảnh hưởng đến khả năng đọc hiểu code, dựa trên nghiên cứu về các metrics phức tạp và kinh nghiệm thực tế. Tác giả đưa ra 8 mẫu hình chính giúp cải thiện khả năng đọc hiểu code.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các metrics phức tạp&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Halstead Complexity Metrics: đo lường số lượng operators và operands&lt;/li&gt;
&lt;li&gt;Cognitive Complexity: đánh giá độ phức tạp dựa trên cấu trúc code&lt;/li&gt;
&lt;li&gt;Các metrics này giúp định lượng khả năng đọc hiểu code&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;8 mẫu hình cải thiện khả năng đọc hiểu&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Số lượng dòng/operator/operand: Ưu tiên các hàm nhỏ với ít biến&lt;/li&gt;
&lt;li&gt;Tính mới lạ: Tránh các cấu trúc mới lạ, ưu tiên các mẫu hình quen thuộc&lt;/li&gt;
&lt;li&gt;Nhóm logic: Chia nhỏ các chuỗi hàm dài thành các nhóm logic&lt;/li&gt;
&lt;li&gt;Đơn giản hóa điều kiện: Giữ các điều kiện ngắn gọn&lt;/li&gt;
&lt;li&gt;Tránh goto: Chỉ sử dụng trong trường hợp đặc biệt&lt;/li&gt;
&lt;li&gt;Giảm thiểu lồng ghép: Tránh logic lồng nhau phức tạp&lt;/li&gt;
&lt;li&gt;Phân biệt biến: Sử dụng tên biến rõ ràng và khác biệt&lt;/li&gt;
&lt;li&gt;Thời gian sống của biến: Ưu tiên biến có thời gian sống ngắn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ý nghĩa thực tế&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Các mẫu hình này áp dụng được cho mọi ngôn ngữ lập trình&lt;/li&gt;
&lt;li&gt;Giúp giảm thiểu lỗi và dễ dàng bảo trì code&lt;/li&gt;
&lt;li&gt;Tạo ra code dễ đọc và dễ hiểu hơn cho cả bản thân và người khác&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="io-devices-and-latency"&gt;&lt;a class="link" href="https://planetscale.com/blog/io-devices-and-latency" target="_blank" rel="noopener"
&gt;IO Devices and Latency&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Benjamin Dicken phân tích sâu về các thiết bị lưu trữ và độ trễ trong hệ thống máy tính, từ băng từ đến ổ cứng và SSD hiện đại. Tác giả cũng giải thích về tác động của việc chuyển đổi sang cloud và cách PlanetScale giải quyết các thách thức về hiệu suất.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lịch sử phát triển thiết bị lưu trữ&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Băng từ (1950s): Lưu trữ tuần tự, độ trễ cao khi truy cập ngẫu nhiên&lt;/li&gt;
&lt;li&gt;Ổ cứng (HDD): Cải thiện đáng kể với thời gian truy cập ngẫu nhiên 1-3ms&lt;/li&gt;
&lt;li&gt;Ổ cứng thể rắn (SSD): Hiệu suất cao hơn nhưng có vấn đề về garbage collection&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tác động của Cloud Computing&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tách biệt storage và compute&lt;/li&gt;
&lt;li&gt;Sử dụng network-attached storage (EBS, etc.)&lt;/li&gt;
&lt;li&gt;Độ trễ tăng lên đáng kể: 250μs so với 50μs của local NVMe&lt;/li&gt;
&lt;li&gt;Giới hạn IOPS nhân tạo (ví dụ: 3000 IOPS/giây)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giải pháp PlanetScale Metal&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng NVMe SSD trực tiếp gắn với compute&lt;/li&gt;
&lt;li&gt;Replication tự động với primary và hai replica&lt;/li&gt;
&lt;li&gt;Không giới hạn IOPS&lt;/li&gt;
&lt;li&gt;Khả năng mở rộng linh hoạt&lt;/li&gt;
&lt;li&gt;Bảo vệ dữ liệu tốt hơn với nhiều lớp backup&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;So sánh hiệu suất&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU → RAM: ~100ns&lt;/li&gt;
&lt;li&gt;CPU → Local NVMe: ~50,000ns&lt;/li&gt;
&lt;li&gt;CPU → Network Storage: ~250,000ns&lt;/li&gt;
&lt;li&gt;Network storage chậm hơn 5 lần so với local storage&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="the-good-times-in-tech-are-over"&gt;&lt;a class="link" href="https://www.seangoedecke.com/good-times-are-over/" target="_blank" rel="noopener"
&gt;The good times in tech are over&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Sean Goedecke phân tích về sự thay đổi trong ngành công nghệ, đặc biệt là về môi trường làm việc của các kỹ sư phần mềm trong thập kỷ qua. Tác giả giải thích nguyên nhân và tác động của những thay đổi này.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sự thay đổi môi trường làm việc&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thập kỷ trước: Nhiều đặc quyền, ít sa thải, được đối xử đặc biệt&lt;/li&gt;
&lt;li&gt;Hiện tại: Các công ty tập trung vào hiệu suất và lợi nhuận&lt;/li&gt;
&lt;li&gt;Meta đã công khai thừa nhận việc sa thải nhân viên kém hiệu quả&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nguyên nhân chính&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lãi suất thấp (gần 0%) trong thập kỷ 2010 cho phép vay nhiều vốn&lt;/li&gt;
&lt;li&gt;Các công ty tech được khuyến khích mở rộng và chi tiêu không giới hạn&lt;/li&gt;
&lt;li&gt;Lãi suất tăng lên 5% vào năm 2023 thay đổi hoàn toàn động lực kinh doanh&lt;/li&gt;
&lt;li&gt;COVID-19 tạo ra cơn sốt ngắn hạn nhưng không phải nguyên nhân gốc rễ&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tác động đến kỹ sư phần mềm&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Các công ty tập trung vào mục tiêu cụ thể thay vì thử nghiệm nhiều dự án&lt;/li&gt;
&lt;li&gt;Giảm đầu tư vào các dự án phụ như open-source&lt;/li&gt;
&lt;li&gt;Lợi ích cá nhân có thể mâu thuẫn với lợi ích công ty&lt;/li&gt;
&lt;li&gt;Cần thích nghi với môi trường mới để tránh bị sa thải&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mặt tích cực&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Các công ty tech hoạt động thực tế hơn&lt;/li&gt;
&lt;li&gt;Quy tắc làm việc rõ ràng hơn:
&lt;ul&gt;
&lt;li&gt;Cung cấp giá trị cho công ty = được thưởng&lt;/li&gt;
&lt;li&gt;Không cung cấp giá trị = bị phạt&lt;/li&gt;
&lt;li&gt;Giá trị = theo đuổi kế hoạch của ban lãnh đạo&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="once-you"&gt;&lt;a class="link" href="https://mertbulan.com/2025/01/26/once-you-are-laid-off-you-will-never-be-the-same-again/" target="_blank" rel="noopener"
&gt;Once You&amp;rsquo;re Laid Off, You&amp;rsquo;ll Never Be the Same Again&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Mert Bulan chia sẻ trải nghiệm cá nhân về việc bị sa thải và những thay đổi trong cách nhìn nhận về công việc sau sự kiện này. Tác giả cũng đưa ra những dấu hiệu cảnh báo và lời khuyên cho những người đang làm việc trong ngành công nghệ.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dấu hiệu cảnh báo trước khi sa thải&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hủy đột ngột các sự kiện team&lt;/li&gt;
&lt;li&gt;Nhận thông báo về gói hàng bất ngờ (để trả thiết bị)&lt;/li&gt;
&lt;li&gt;Thiếu tầm nhìn rõ ràng từ ban lãnh đạo&lt;/li&gt;
&lt;li&gt;Các cuộc họp đột ngột không có chương trình&lt;/li&gt;
&lt;li&gt;Thời điểm xung quanh báo cáo tài chính quý&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thực tế phũ phàng&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bạn chỉ là một dòng trong bảng Excel&lt;/li&gt;
&lt;li&gt;Quyết định sa thải thường được đưa ra bởi người không biết bạn&lt;/li&gt;
&lt;li&gt;Thành tích và đóng góp trước đó không được xem xét&lt;/li&gt;
&lt;li&gt;Niềm tin giữa công ty và nhân viên đã bị phá vỡ&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tác động lâu dài&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thay đổi cách nhìn nhận về công việc&lt;/li&gt;
&lt;li&gt;Mất niềm tin vào cam kết của công ty&lt;/li&gt;
&lt;li&gt;Chỉ làm đúng giờ quy định&lt;/li&gt;
&lt;li&gt;Không còn nỗ lực vượt quá yêu cầu&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lời khuyên cho người đang làm việc&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tuân thủ giờ làm việc theo hợp đồng&lt;/li&gt;
&lt;li&gt;Tránh làm việc quá sức&lt;/li&gt;
&lt;li&gt;Luôn duy trì việc phỏng vấn ở nơi khác&lt;/li&gt;
&lt;li&gt;Tận dụng offer bên ngoài để tăng lương&lt;/li&gt;
&lt;li&gt;Đừng quá lo lắng về CV có nhiều công ty ngắn hạn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/840e868d-2c83-4b1b-a881-df1da6c6e332_1309x1536.gif"
loading="lazy"
alt="What is MCP?"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/6ff106a0-de83-48b0-9eb4-3f8bf0d43a57_1280x1566.gif"
loading="lazy"
alt="How to Design a System like Instagram"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/214c0c6c-2426-49d0-9fa8-cdb9ce089dcc_1280x1585.gif"
loading="lazy"
alt="How to load your websites at lightning speed"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #15</title><link>https://miti99.com/post/2025/05/02/</link><pubDate>Fri, 02 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/02/</guid><description>&lt;p&gt;&lt;em&gt;Mặc định thì mình follow theo format mỗi ngày chỉ viết 1 post, nhưng mà dạo gần đây lười viết bài nên tích được nhiều bài hay ho quá, nên tạm thời trong thời gian tới sẽ trick lỏ viết lùi thời gian và cố gắng viết nhiều hơn để &amp;ldquo;kịp hết bài&amp;rdquo;. VD như nay là 10/5 nhưng mình viết cho 2/5 vậy, check git history là ra à, hehe. Mời bạn thưởng thức Newsletter #15.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="heres-how-i-use-llms-to-help-me-write-code"&gt;&lt;a class="link" href="https://simonwillison.net/2025/Mar/11/using-llms-for-code/" target="_blank" rel="noopener"
&gt;Here’s how I use LLMs to help me write code&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Simon Willison chia sẻ kinh nghiệm sử dụng mô hình ngôn ngữ lớn (LLM) trong phát triển phần mềm. Tác giả đưa ra 5 cách sử dụng LLM hiệu quả cho lập trình viên:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giải thích code&lt;/strong&gt;: Sử dụng LLM để hiểu code phức tạp, đặc biệt là code của người khác hoặc code cũ của chính mình.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Viết test&lt;/strong&gt;: LLM rất giỏi trong việc tạo test cases, đặc biệt là unit test và integration test, giúp tăng độ bao phủ và phát hiện lỗi.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Refactoring code&lt;/strong&gt;: Sử dụng LLM để cải thiện cấu trúc code, tách các hàm phức tạp thành các hàm nhỏ hơn, dễ bảo trì hơn.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Viết documentation&lt;/strong&gt;: LLM có thể tạo ra tài liệu hướng dẫn, docstrings và README chất lượng cao dựa trên code hiện có.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tạo code mới&lt;/strong&gt;: Sử dụng LLM để viết code từ đầu, nhưng luôn phải kiểm tra kỹ kết quả và hiểu rõ code được tạo ra.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tác giả nhấn mạnh rằng LLM không phải là công cụ thay thế lập trình viên mà là công cụ hỗ trợ, giúp tăng năng suất và chất lượng code. Bài viết cũng cảnh báo về những hạn chế của LLM như hallucination (tạo ra thông tin sai) và khuyên lập trình viên nên luôn kiểm tra kỹ output từ LLM trước khi sử dụng.&lt;/p&gt;
&lt;h2 id="i-use-cursor-daily---here"&gt;&lt;a class="link" href="https://www.nickcraux.com/blog/cursor-tips" target="_blank" rel="noopener"
&gt;I use Cursor daily - here&amp;rsquo;s how I avoid the garbage parts&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giới thiệu các mẹo và thủ thuật để sử dụng Cursor - một trình soạn thảo code tích hợp AI hiệu quả hơn. Cursor là công cụ được xây dựng dựa trên VS Code nhưng tích hợp sâu với các mô hình ngôn ngữ lớn như GPT-4, giúp lập trình viên tăng năng suất đáng kể.&lt;/p&gt;
&lt;p&gt;Tác giả chia sẻ nhiều tip hữu ích như cách sử dụng các phím tắt quan trọng, kỹ thuật prompt hiệu quả để nhận được câu trả lời chính xác từ AI, cách tận dụng tính năng chat với codebase, và các chiến lược để tối ưu hóa quy trình làm việc. Bài viết cũng hướng dẫn cách cấu hình Cursor để phù hợp với nhu cầu cá nhân và dự án cụ thể.&lt;/p&gt;
&lt;p&gt;Đặc biệt, tác giả nhấn mạnh các phương pháp để kết hợp sức mạnh của con người và AI một cách hài hòa, giúp tạo ra code chất lượng cao hơn trong thời gian ngắn hơn. Đây là tài liệu tham khảo hữu ích cho cả người mới bắt đầu và những người đã quen thuộc với Cursor muốn nâng cao kỹ năng sử dụng công cụ này.&lt;/p&gt;
&lt;h2 id="why-java-endures-the-foundation-of-modern-enterprise-development"&gt;&lt;a class="link" href="https://github.blog/developer-skills/why-java-endures-the-foundation-of-modern-enterprise-development/" target="_blank" rel="noopener"
&gt;Why Java endures: The foundation of modern enterprise development&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ GitHub Blog phân tích lý do tại sao Java vẫn tiếp tục là nền tảng vững chắc cho phát triển phần mềm doanh nghiệp hiện đại, dù đã gần 30 năm tuổi. Tác giả chỉ ra rằng sức mạnh của Java nằm ở tính ổn định, hiệu suất cao, khả năng mở rộng và hệ sinh thái phong phú.&lt;/p&gt;
&lt;p&gt;Bài viết nhấn mạnh vai trò của Java trong các hệ thống backend quy mô lớn, đặc biệt trong lĩnh vực tài chính, thương mại điện tử và các ứng dụng doanh nghiệp. Mặc dù có nhiều ngôn ngữ mới xuất hiện, Java vẫn duy trì vị thế nhờ khả năng thích ứng liên tục, cộng đồng lớn mạnh và sự hỗ trợ từ các công ty lớn như Oracle, Google và Amazon.&lt;/p&gt;
&lt;p&gt;Tác giả cũng thảo luận về các xu hướng hiện đại trong hệ sinh thái Java như Spring Boot, Quarkus, và GraalVM, cũng như việc tích hợp với các công nghệ cloud-native và microservices. Bài viết kết luận rằng Java không chỉ là một ngôn ngữ lập trình mà còn là một nền tảng toàn diện, tiếp tục phát triển để đáp ứng nhu cầu của các doanh nghiệp trong kỷ nguyên số.&lt;/p&gt;
&lt;h2 id="part-5-implementing-a-web-ui-using-vaadin-and-github-copilot-agent-mode"&gt;&lt;a class="link" href="https://itnext.io/part-5-implementing-a-web-ui-using-vaadin-and-github-copilot-agent-mode-563e74f131aa" target="_blank" rel="noopener"
&gt;Part 5: Implementing a Web UI using Vaadin and GitHub Copilot Agent Mode&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này là phần thứ 5 trong một series về phát triển ứng dụng web, tập trung vào việc xây dựng giao diện người dùng sử dụng Vaadin kết hợp với GitHub Copilot Agent Mode. Tác giả hướng dẫn chi tiết cách tạo một UI web hiện đại mà không cần viết nhiều JavaScript, nhờ vào framework Vaadin - một công cụ cho phép lập trình viên Java xây dựng giao diện người dùng hoàn toàn bằng Java.&lt;/p&gt;
&lt;p&gt;Điểm nổi bật của bài viết là việc tận dụng GitHub Copilot Agent Mode - một tính năng AI mới của GitHub Copilot - để tăng tốc quá trình phát triển. Tác giả minh họa cách Copilot Agent có thể hiểu yêu cầu phức tạp, đề xuất các component UI phù hợp, và thậm chí tạo ra các layout hoàn chỉnh dựa trên mô tả bằng ngôn ngữ tự nhiên.&lt;/p&gt;
&lt;p&gt;Bài viết cũng thảo luận về các thực hành tốt nhất khi kết hợp Vaadin với Spring Boot, cách xử lý dữ liệu và sự kiện trong ứng dụng, cũng như các chiến lược để tối ưu hóa hiệu suất của ứng dụng web. Đây là tài liệu hữu ích cho các lập trình viên Java muốn xây dựng ứng dụng web hiện đại với sự hỗ trợ của công nghệ AI.&lt;/p&gt;
&lt;h2 id="microservices-vs-monoliths-how-to-choose-the-right-architecture-for-your-project"&gt;&lt;a class="link" href="https://dev.to/jhonifaber/microservices-vs-monoliths-how-to-choose-the-right-architecture-for-your-project-2bep" target="_blank" rel="noopener"
&gt;Microservices vs. Monoliths: How to Choose the Right Architecture for Your Project&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích sâu sắc về hai kiến trúc phổ biến trong phát triển phần mềm: microservices và monoliths. Tác giả Jhoni Faber cung cấp một cái nhìn toàn diện về ưu và nhược điểm của mỗi kiến trúc, giúp các đội phát triển đưa ra quyết định phù hợp cho dự án của họ.&lt;/p&gt;
&lt;p&gt;Về kiến trúc monolith, tác giả chỉ ra những ưu điểm như dễ phát triển ban đầu, đơn giản trong triển khai và vận hành, hiệu suất tốt với độ trễ thấp, và chi phí phát triển ban đầu thấp. Tuy nhiên, monolith cũng có những hạn chế như khó mở rộng khi ứng dụng phát triển, khó áp dụng công nghệ mới, và rủi ro cao khi cập nhật vì toàn bộ hệ thống phải được triển khai lại.&lt;/p&gt;
&lt;p&gt;Về microservices, bài viết nhấn mạnh các lợi ích như khả năng mở rộng và phát triển độc lập của từng service, linh hoạt trong việc áp dụng công nghệ mới cho từng service, và khả năng phục hồi tốt hơn khi một service gặp sự cố. Tuy nhiên, microservices cũng đi kèm với những thách thức như độ phức tạp cao trong việc quản lý và điều phối các service, chi phí vận hành lớn hơn, và yêu cầu cao về kỹ năng DevOps.&lt;/p&gt;
&lt;p&gt;Phần quan trọng nhất của bài viết là hướng dẫn cách lựa chọn kiến trúc phù hợp dựa trên các yếu tố như quy mô dự án, yêu cầu về khả năng mở rộng, nguồn lực sẵn có của đội ngũ, và thời gian phát triển. Tác giả cũng đề xuất một cách tiếp cận thực tế là bắt đầu với monolith được thiết kế tốt và chuyển dần sang microservices khi cần thiết, thay vì áp dụng microservices ngay từ đầu cho mọi dự án.&lt;/p&gt;
&lt;h2 id="designing-a-scalable-architecture---with-some-spring-boot-examples"&gt;&lt;a class="link" href="https://dev.to/jhonifaber/designing-a-scalable-architecture-with-some-spring-boot-examples-340o" target="_blank" rel="noopener"
&gt;Designing a Scalable Architecture - with Some Spring Boot Examples&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Jhoni Faber trình bày chi tiết về cách thiết kế kiến trúc có khả năng mở rộng cao cho các ứng dụng Spring Boot. Tác giả đi sâu vào các nguyên tắc thiết kế và mẫu kiến trúc giúp xây dựng hệ thống có thể dễ dàng phát triển theo quy mô và nhu cầu kinh doanh.&lt;/p&gt;
&lt;p&gt;Bài viết tập trung vào việc áp dụng kiến trúc phân lớp (layered architecture) trong Spring Boot, với sự phân chia rõ ràng giữa các thành phần: controller, service, repository và domain model. Tác giả nhấn mạnh tầm quan trọng của việc thiết kế giao diện (interface) rõ ràng giữa các lớp, giúp giảm sự phụ thuộc và tăng tính linh hoạt của hệ thống.&lt;/p&gt;
&lt;p&gt;Một điểm nổi bật trong bài viết là các ví dụ thực tế về cách tổ chức code trong Spring Boot, bao gồm cách xử lý dependency injection, quản lý transaction, và thiết kế API RESTful. Tác giả cũng đề cập đến các kỹ thuật nâng cao như caching, asynchronous processing và event-driven architecture để tối ưu hiệu suất và khả năng mở rộng.&lt;/p&gt;
&lt;p&gt;Phần cuối bài viết thảo luận về các chiến lược triển khai và giám sát hệ thống, bao gồm containerization với Docker, orchestration với Kubernetes, và các công cụ monitoring như Prometheus và Grafana. Đây là một tài liệu toàn diện cho các nhà phát triển Spring Boot muốn xây dựng các ứng dụng có khả năng mở rộng cao trong môi trường doanh nghiệp.&lt;/p&gt;
&lt;h2 id="java-is-very-fast-if-you-dont-create-many-objects"&gt;&lt;a class="link" href="https://blog.vanillajava.blog/2022/09/java-is-very-fast-if-you-dont-create.html" target="_blank" rel="noopener"
&gt;Java is Very Fast, If You Don’t Create Many Objects&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này từ Vanilla Java Blog phân tích một khía cạnh quan trọng về hiệu suất của Java: ngôn ngữ này có thể cực kỳ nhanh nếu bạn hạn chế việc tạo ra các đối tượng tạm thời (garbage). Tác giả Peter Lawrey, một chuyên gia về Java hiệu năng cao, giải thích rằng mặc dù Garbage Collector của Java đã được cải thiện đáng kể qua nhiều năm, việc liên tục tạo ra các đối tượng mới vẫn là nguyên nhân chính gây ra độ trễ và giảm hiệu suất trong các ứng dụng đòi hỏi hiệu năng cao.&lt;/p&gt;
&lt;p&gt;Bài viết trình bày các kỹ thuật để giảm thiểu việc tạo đối tượng không cần thiết, bao gồm:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Sử dụng object pooling để tái sử dụng đối tượng thay vì tạo mới&lt;/li&gt;
&lt;li&gt;Áp dụng các cấu trúc dữ liệu off-heap để lưu trữ dữ liệu bên ngoài heap của JVM&lt;/li&gt;
&lt;li&gt;Tối ưu hóa code để tránh boxing/unboxing tự động và chuyển đổi kiểu dữ liệu không cần thiết&lt;/li&gt;
&lt;li&gt;Sử dụng các thư viện như Chronicle Queue và Chronicle Map được thiết kế để giảm thiểu garbage&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tác giả cũng chia sẻ các benchmark so sánh hiệu suất giữa code Java thông thường và code được tối ưu để giảm thiểu garbage, cho thấy sự khác biệt đáng kể về thời gian xử lý và độ trễ. Đây là một bài viết giá trị cho các lập trình viên Java làm việc với các hệ thống yêu cầu hiệu năng cao như tài chính, giao dịch thời gian thực, hoặc xử lý dữ liệu lớn.&lt;/p&gt;
&lt;h2 id="microbenchmarks-java-locks-vs-atomic"&gt;&lt;a class="link" href="https://blog.tombert.com/posts/2025-03-04-lock-benchmark/" target="_blank" rel="noopener"
&gt;Microbenchmarks: Java Locks vs Atomic&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trình bày một phân tích chi tiết về hiệu suất của các cơ chế đồng bộ hóa (synchronization) khác nhau trong lập trình đa luồng. Tác giả đã thực hiện benchmark so sánh hiệu năng của nhiều loại lock khác nhau như mutex, spin lock, read-write lock và các giải pháp lock-free, đánh giá chúng trong các tình huống tải khác nhau.&lt;/p&gt;
&lt;p&gt;Kết quả benchmark cho thấy sự khác biệt đáng kể giữa các loại lock, với những phát hiện thú vị như:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Spin lock thường hiệu quả hơn mutex trong các tác vụ ngắn với mức độ cạnh tranh thấp&lt;/li&gt;
&lt;li&gt;Read-write lock mang lại lợi ích lớn trong các trường hợp đọc nhiều, ghi ít&lt;/li&gt;
&lt;li&gt;Các giải pháp lock-free có thể mang lại hiệu suất vượt trội trong một số trường hợp, nhưng lại phức tạp hơn đáng kể trong việc triển khai và bảo trì&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết cũng thảo luận về các yếu tố ảnh hưởng đến hiệu suất của lock như độ trễ, throughput, khả năng mở rộng theo số lượng luồng, và tác động của cache coherence. Tác giả cung cấp các hướng dẫn thực tế về việc lựa chọn cơ chế đồng bộ hóa phù hợp dựa trên đặc điểm của ứng dụng và mô hình truy cập dữ liệu.&lt;/p&gt;
&lt;p&gt;Đây là một tài liệu tham khảo giá trị cho các lập trình viên làm việc với hệ thống đa luồng hiệu năng cao, giúp họ đưa ra quyết định sáng suốt khi lựa chọn cơ chế đồng bộ hóa phù hợp với yêu cầu cụ thể của dự án.&lt;/p&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/ad16adef-3082-42bd-ac99-9a569ad2e33b_2250x2624.png"
loading="lazy"
alt="API Protocols 101"
&gt;&lt;/p&gt;</description></item><item><title>MiTi xếp hạng các AI Agent</title><link>https://miti99.com/post/2025/05/01/</link><pubDate>Thu, 01 May 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/05/01/</guid><description>&lt;p&gt;&lt;em&gt;Đây chỉ là đánh giá cá nhân. Mình cũng chỉ thường xài Agent cho các project cá nhân nhỏ nhỏ thôi nên có thể không chính xác. Bài viết chỉ nhằm mục đích bày tỏ quan điểm&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2025/05/01/img/tierlist.png"
width="1140"
height="465"
srcset="https://miti99.com/post/2025/05/01/img/tierlist_hu_4bbdb11572670d37.png 480w, https://miti99.com/post/2025/05/01/img/tierlist_hu_30df22fe2a4a3430.png 1024w"
loading="lazy"
alt="Tierlist"
class="gallery-image"
data-flex-grow="245"
data-flex-basis="588px"
&gt;&lt;/p&gt;
&lt;h2 id="giải-thích"&gt;Giải thích
&lt;/h2&gt;&lt;h3 id="augment"&gt;Augment
&lt;/h3&gt;&lt;p&gt;Augment có cơ chế tự index codebase khá tốt, ngoài ra hiện đang Augment đang &lt;strong&gt;unlimit&lt;/strong&gt; cho gói Developer, khá hời so với mức giá 30$ (mình khá là serious với những cái &amp;ldquo;unlimit&amp;rdquo; dù biết rằng vốn dĩ chẳng có gì là không giới hạn :D)&lt;/p&gt;
&lt;p&gt;Update 7/5/2025: Augment đã cập nhật giá mới, đến tận 50$/tháng và giới hạn 600 messages/tháng (tầm 20 messages/ngày). Mình lại thấy Augment không còn tuyệt vời như xưa nữa :D&lt;/p&gt;
&lt;h3 id="cursor--windsurf"&gt;Cursor &amp;amp; Windsurf
&lt;/h3&gt;&lt;p&gt;Cả 2 tool này đều khá tốt, Cursor ban đầu tỏ ra khá vượt trội, nhưng trong các bản gần đây, Windsurf cũng có những cải thiện đáng kể. Ngoài ra OpenAI cũng đã mua lại Windsurf, có thể trong tương lai Windsurf sẽ tốt hơn&lt;/p&gt;
&lt;p&gt;Về giá cả, Cursor cho phép unlimit &amp;ldquo;slow premium request&amp;rdquo;, khá hấp dẫn. Windsurf cũng tỏ ra không hề kém cạnh khi giá khởi điểm 15$ hấp dẫn hơn Cursor (20$), tuy nhiên Windsurf sẽ giới hạn 500 prompt credits/tháng.&lt;/p&gt;
&lt;h3 id="junie"&gt;Junie
&lt;/h3&gt;&lt;p&gt;Trong những ngày đầu ra mắt Junie còn nhiều điểm cần cải thiện, cá nhân mình thấy Junie index khá lâu, khi hỏi đôi khi còn phải đọc lại cả file, rất mất thời gian.&lt;/p&gt;
&lt;h3 id="trae--github-copilot"&gt;Trae &amp;amp; Github Copilot
&lt;/h3&gt;&lt;p&gt;Cả 2 tool này mình thấy đều không tự tìm được file phù hợp, đều cần chúng ta include hộ. Nhưng mà Trae free, còn Copilot tốn phí, nên là Trae rank C, còn Copilot rank D.&lt;/p&gt;
&lt;p&gt;Github Copilot khá chậm, và không có (hoặc mình không biết) chỗ để Copilot tự chạy lệnh (kiểu auto, brave mode) mà phải chạy thủ công, điều này tất nhiên mang tính bảo mật, nhưng làm chậm tiến độ. Tưởng tượng thay vì có thể prompt xong và bỏ đi pha tách cafe, agent chạy xong và mình chỉ cần kiểm tra lại. Thì giờ phải ngồi canh agent có yêu cầu chạy lệnh gì không, nếu có thì approve cho nó. Hơn nữa lâu lâu có vài lệnh Copilot chạy mãi không xong, stuck luôn, phải làm lại từ đầu, rất phiền.&lt;/p&gt;
&lt;h2 id="bonus"&gt;Bonus
&lt;/h2&gt;&lt;p&gt;Ngoài ra mình có tìm được một bài có tierlist nhiều công cụ hơn, các bạn có thể tham khảo thử&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://www.pragmaticcoders.com/resources/ai-developer-tools" target="_blank" rel="noopener"
&gt;Best AI for coding in 2025: 25 developer tools to use (or avoid)&lt;/a&gt;
&lt;a class="link" href="https://github.com/e2b-dev/awesome-ai-agents" target="_blank" rel="noopener"
&gt;Awesome AI Agents&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="update-245"&gt;Update 24/5
&lt;/h2&gt;&lt;p&gt;Gần đây, vào ngày 15/5 Windsurf đã cho ra mắt SWE model tự làm, và sẽ cho phép người dùng free sử dụng model lite không giới hạn. Hiện tại thì còn cho dùng bản thường không giới hạn trong một khoảng thời gian nữa. Mình thấy khá hấp dẫn, đáng để thử.&lt;/p&gt;
&lt;p&gt;Claude 4 cũng vừa release ngày 22/5, hiện tại thì Cursor, Trae &amp;amp; Copilot đều đã có rồi, còn Windsurf &amp;amp; Junie thì chưa. Ngoài ra thì Trae cho dùng nhưng hàng chờ rất dài, kể cả Claude 3.7 cũng vậy, với Trae thì chỉ có dùng Claude 3.5 là nhanh nhất, ít phải chờ.&lt;/p&gt;
&lt;p&gt;Ngoài ra như các bạn cũng biết chuyên mục Newsletter là mình dùng AI Agent để làm, hôm nay thử nghiệm thì thấy Copilot với Claude 4 cho kết quả khá tệ khi mà giữ lại quá nhiều thuật ngữ tiếng Anh, các bạn cho thể check phiên bản đầu tiên của Newsletter #28 trên Github để xem lại.&lt;/p&gt;
&lt;p&gt;Xếp theo độ ưu tiên hiện tại của mình là: Windsurf &amp;gt; Cursor &amp;gt; Trae &amp;gt; Junie &amp;gt; Copilot. Trae hạng cao tại vì nó free thôi. Hiện tại mình không dùng Augment nữa do hết trial &amp;amp; giá cả khá đắt, dù hồi trước rất ưng nhưng đụng đến túi tiền thì đành phải từ bò thôi. Sắp tới mình cũng sẽ không dùng Junie nữa, sau đó nữa là Copilot, do mình hết hạn trial và cũng không cảm thấy 2 cái này đáng để chi tiền. Nếu có mua mình sẽ đầu tư vào Windsurf &amp;amp; Cursor.&lt;/p&gt;</description></item><item><title>Newsletter #14</title><link>https://miti99.com/post/2025/04/30/</link><pubDate>Wed, 30 Apr 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/04/30/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #14.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="bloom-filter-a-deep-dive"&gt;&lt;a class="link" href="https://www.kirupa.com/data_structures_algorithms/bloom_filter.htm" target="_blank" rel="noopener"
&gt;Bloom Filter: A Deep Dive&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giới thiệu về Bloom filter - một cấu trúc dữ liệu xác suất hiệu quả về không gian, được thiết kế để kiểm tra nhanh xem một phần tử có thuộc tập hợp hay không. Bloom filter hoạt động bằng cách lưu trữ &amp;ldquo;dấu vân tay&amp;rdquo; của dữ liệu thay vì lưu trữ toàn bộ dữ liệu, sử dụng một mảng bit và nhiều hàm băm.&lt;/p&gt;
&lt;p&gt;Ưu điểm chính của Bloom filter là tiết kiệm bộ nhớ đáng kể (có thể giảm 13-20 lần so với hashtable) và tốc độ kiểm tra nhanh O(k) với k là số lượng hàm băm. Tuy nhiên, Bloom filter là cấu trúc dữ liệu xác suất - nó có thể trả lời chắc chắn khi một phần tử KHÔNG tồn tại, nhưng chỉ có thể đưa ra câu trả lời &amp;ldquo;có thể có&amp;rdquo; khi phần tử tồn tại (có tỷ lệ dương tính giả).&lt;/p&gt;
&lt;p&gt;Bài viết cũng hướng dẫn cách tối ưu kích thước mảng bit và số lượng hàm băm dựa trên số lượng phần tử và tỷ lệ dương tính giả mong muốn. Đây là tài liệu hữu ích cho các lập trình viên muốn hiểu và áp dụng Bloom filter trong các hệ thống cần kiểm tra thành viên nhanh chóng với bộ nhớ hạn chế.&lt;/p&gt;
&lt;h2 id="rethinking-llm-inference-why-developer-ai-needs-a-different-approach"&gt;&lt;a class="link" href="https://www.augmentcode.com/blog/rethinking-llm-inference-why-developer-ai-needs-a-different-approach" target="_blank" rel="noopener"
&gt;Rethinking LLM inference: Why developer AI needs a different approach&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trình bày các tối ưu kỹ thuật giúp giảm mạnh độ trễ và tăng throughput khi chạy mô hình LLM cho các ứng dụng AI lập trình. Augment Code tập trung vào việc xử lý context lớn (hàng chục ngàn tokens) với tốc độ cao, sử dụng các kỹ thuật như token-level batching, tối ưu FLOPS, CUDA Graphs, FlashAttention-3 và custom CUDA kernels. Kết quả cho thấy hệ thống inference của họ đạt &amp;lt;300ms time-to-first-token với 10k input tokens trên Llama3 70B, tận dụng hiệu quả tài nguyên GPU và vượt trội so với các giải pháp phổ biến hiện nay. Nếu bạn quan tâm đến tối ưu hóa hệ thống AI cho lập trình viên, đây là tài liệu rất đáng đọc!&lt;/p&gt;
&lt;h2 id="floyds-cycle-algorithm-fraud-detection-in-java-systems"&gt;&lt;a class="link" href="https://dzone.com/articles/floyds-cycle-algorithm-fraud-detection-java-systems" target="_blank" rel="noopener"
&gt;Floyd’s Cycle Algorithm: Fraud Detection in Java Systems&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này giới thiệu cách ứng dụng thuật toán phát hiện chu trình (Floyd’s Cycle Detection, hay còn gọi là Tortoise and Hare) trong việc phát hiện gian lận tài chính. Thuật toán giúp nhận diện các vòng lặp trong đồ thị giao dịch, ví dụ như các chuỗi chuyển tiền quay lại tài khoản gốc – một dấu hiệu điển hình của hành vi rửa tiền. Bài viết trình bày ví dụ thực tế về phát hiện vòng lặp trong các giao dịch ngân hàng, ưu nhược điểm của thuật toán, cũng như các lĩnh vực ứng dụng rộng rãi khác như phát hiện vòng lặp trong linked list, tối ưu hệ thống phân tán, phân tích dữ liệu sinh học, AI/ML và blockchain. Đây là một ví dụ điển hình về việc áp dụng thuật toán kinh điển vào các bài toán thực tế trong hệ thống Java.&lt;/p&gt;
&lt;h2 id="succinct-data-structures"&gt;&lt;a class="link" href="https://blog.startifact.com/posts/succinct/" target="_blank" rel="noopener"
&gt;Succinct data structures&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giới thiệu về các cấu trúc dữ liệu súc tích (succinct data structures) - một lĩnh vực tương đối mới trong khoa học máy tính. Khác với nén dữ liệu thông thường (yêu cầu giải nén trước khi sử dụng), các cấu trúc dữ liệu súc tích lưu trữ thông tin một cách nhỏ gọn nhưng vẫn cho phép truy vấn và thao tác trực tiếp trên dữ liệu đã nén.&lt;/p&gt;
&lt;p&gt;Tác giả giới thiệu một số cấu trúc dữ liệu súc tích quan trọng:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Rank/Select Bit Vector&lt;/strong&gt;: Cấu trúc nền tảng cho phép đếm số bit đã được đặt trước một vị trí (rank) hoặc tìm vị trí của bit thứ n (select) trong thời gian hằng số&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wavelet Matrix&lt;/strong&gt;: Mở rộng rank/select cho các bảng chữ cái lớn hơn (không chỉ 0 và 1)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FM-index&lt;/strong&gt;: Cho phép tìm kiếm mẫu con trong văn bản lớn một cách hiệu quả&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Balanced Parentheses&lt;/strong&gt;: Biểu diễn cây dữ liệu chỉ với 2 bit/nút thay vì 32 byte như cách thông thường&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết cũng đề cập đến các ứng dụng thực tế như xử lý XML, DNA và AST của ngôn ngữ lập trình, cùng với các thư viện Rust hiện có như &lt;code&gt;vers&lt;/code&gt;, &lt;code&gt;sucds&lt;/code&gt; và &lt;code&gt;fm-index&lt;/code&gt;. Đây là một lĩnh vực đầy tiềm năng cho các ứng dụng cần xử lý dữ liệu lớn với bộ nhớ hạn chế.&lt;/p&gt;
&lt;h2 id="the-art-of-engineering-team-focus-less-is-more"&gt;&lt;a class="link" href="https://resources.github.com/developer-productivity/engineering-team-focus/" target="_blank" rel="noopener"
&gt;The art of engineering team focus: less is more&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ GitHub Resources trình bày một quan điểm ngược với trực giác thông thường: để đội ngũ kỹ thuật làm việc hiệu quả hơn, họ cần làm ít việc hơn cùng một lúc. Tác giả lập luận rằng việc phân tán nguồn lực vào nhiều tác vụ song song thường dẫn đến hiệu suất thấp hơn, không phải cao hơn.&lt;/p&gt;
&lt;p&gt;Bài viết đưa ra năm nguyên tắc cốt lõi để xây dựng đội ngũ kỹ thuật linh hoạt và hiệu quả:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Làm cho mọi công việc đều rõ ràng&lt;/strong&gt;: Khi tất cả công việc đều được hiển thị, không thể bỏ qua thực tế về khả năng của đội ngũ và dễ dàng đưa ra quyết định về việc nên ưu tiên điều gì.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chia nhỏ công việc&lt;/strong&gt;: Giới hạn công việc trong các chu kỳ 1-2 tuần giúp duy trì động lực, tạo điều kiện cho phản hồi thường xuyên và giảm thiểu rủi ro khi cần thay đổi hướng.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hạn chế công việc đang thực hiện&lt;/strong&gt;: Chuyển đổi ngữ cảnh giữa nhiều dự án có chi phí cao về mặt nhận thức. Nghiên cứu cho thấy có thể mất đến 23 phút để lấy lại sự tập trung sau mỗi lần chuyển đổi.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tài trợ đến mức tối đa&lt;/strong&gt;: Tập trung nhiều nhà phát triển vào một tính năng ưu tiên cao nhất có thể trước khi chuyển sang việc tiếp theo, thay vì phân bổ mỗi nhà phát triển cho một tính năng riêng biệt.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dành chỗ cho những điều không lường trước&lt;/strong&gt;: Duy trì khoảng 20% dung lượng đệm để xử lý công việc không lường trước, cho phép đội ngũ phản ứng với vấn đề mà không làm trật bánh công việc đã lên kế hoạch.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết kết luận rằng đội ngũ có dung lượng đệm thường đổi mới hơn, linh hoạt hơn và cuối cùng là năng suất hơn. Đôi khi, điều mạnh mẽ nhất mà một nhà lãnh đạo có thể làm là bớt việc cho đội của mình thay vì thêm việc.&lt;/p&gt;
&lt;h2 id="performance-optimization-and-how-to-do-it-wrong"&gt;&lt;a class="link" href="https://genna.win/blog/convolution-simd/" target="_blank" rel="noopener"
&gt;Performance optimization, and how to do it wrong&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ kinh nghiệm tối ưu hóa thuật toán tích chập (convolution) bằng SIMD trên CPU. Tác giả mô tả hành trình đầy thử thách khi cố gắng cải thiện hiệu suất, nhưng lại vô tình làm code chậm hơn gấp đôi. Qua quá trình gỡ lỗi, tác giả rút ra ba bài học quan trọng: (1) các lệnh rẽ nhánh (branch) trong vòng lặp có thể làm giảm hiệu suất nghiêm trọng do CPU không thể dự đoán nhiều hơn một nhánh mỗi chu kỳ; (2) tách vòng lặp thành hai phần riêng biệt (một cho trường hợp thông thường, một cho trường hợp biên) hiệu quả hơn việc kiểm tra điều kiện trong mỗi lần lặp; (3) việc inline hàm trong Rust rất quan trọng khi sử dụng SIMD, vì nếu không được inline, compiler có thể tạo ra code gọi hàm qua stack thay vì sử dụng trực tiếp các lệnh SIMD.&lt;/p&gt;
&lt;h2 id="supercharging-discord-mobile-our-journey-to-a-faster-app"&gt;&lt;a class="link" href="https://discord.com/blog/supercharging-discord-mobile-our-journey-to-a-faster-app" target="_blank" rel="noopener"
&gt;Supercharging Discord Mobile: Our Journey to a Faster App&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giới thiệu các cải tiến hiệu suất của Discord trên nền tảng di động. Đội ngũ kỹ thuật đã tập trung vào năm lĩnh vực chính: (1) Ảo hóa danh sách server giúp giảm 14% bộ nhớ và 10% thời gian khởi động; (2) Tối ưu hiệu suất chat bằng cơ chế tái sử dụng component và lazy loading, giúp giảm 60% khung hình bị lag; (3) Xây dựng emoji picker native cho Android thay vì dùng React Native, giải quyết vấn đề màn hình trắng khi cuộn; (4) Chuyển từ FlashList sang FastList tự phát triển để khắc phục hiện tượng &amp;ldquo;blanking&amp;rdquo; trong danh sách kênh; (5) Cải thiện Media Picker trên iOS bằng cách sử dụng thumbnail độ phân giải thấp hơn nhưng tải nhanh hơn. Năm 2025, Discord sẽ tiếp tục tối ưu với React Native New Architecture và chuyển logic cốt lõi sang Rust.&lt;/p&gt;
&lt;h2 id="git-without-a-forge"&gt;&lt;a class="link" href="https://www.chiark.greenend.org.uk/~sgtatham/quasiblog/git-no-forge/" target="_blank" rel="noopener"
&gt;Git without a forge&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Simon Tatham (tác giả PuTTY) thảo luận về việc sử dụng Git mà không cần dựa vào các nền tảng forge phổ biến như GitHub hay GitLab. Tác giả trình bày các phương pháp thay thế để chia sẻ và cộng tác trên mã nguồn, bao gồm việc sử dụng URL trực tiếp của repository, git bundle và trao đổi patch qua email. Bài viết nhấn mạnh rằng các công cụ tích hợp của các forge như hệ thống issue tracking và pull/merge request không phải là thành phần thiết yếu của Git, và lập trình viên có thể tự do lựa chọn các giải pháp phù hợp với quy trình làm việc của mình mà không bị ràng buộc vào một nền tảng cụ thể.&lt;/p&gt;
&lt;h2 id="40-thoughts-on-turning-40"&gt;&lt;a class="link" href="https://newsletter.pathlesspath.com/p/40-thoughts-on-turning-40-287" target="_blank" rel="noopener"
&gt;40 Thoughts On Turning 40&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Paul Millerd chia sẻ 40 suy nghĩ khi tác giả bước sang tuổi 40, được chia thành bốn chủ đề chính. Về sự thay đổi, tác giả nhấn mạnh rằng quyết định từ bỏ sự nghiệp thành công để theo đuổi con đường không chắc chắn hơn là quyết định quan trọng nhất trong độ tuổi 30. Về công việc, ông chỉ ra rằng khao khát thoát khỏi công việc khiến nhiều người mắc kẹt trong tình huống không lý tưởng, trong khi tìm kiếm &amp;ldquo;công việc tốt&amp;rdquo; - công việc mang lại sự hài lòng cả trong hiện tại và khi nhìn lại - mới là điều đáng theo đuổi. Về mối quan hệ, tác giả chia sẻ rằng tìm được người bạn đời phù hợp là điều may mắn, và khuyên mọi người đừng từ bỏ việc tìm kiếm. Cuối cùng, về hạnh phúc, ông nhận xét rằng viết lách là một trong những hành động mạnh mẽ nhất trên thế giới, nhưng hãy cẩn thận với sức mạnh của nó trong việc phơi bày những khát vọng thực sự của bạn.&lt;/p&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/f7fc4f19-ebd8-45a0-9398-469805bb4a26_1280x1532.gif"
loading="lazy"
alt="A Cheatsheet on Comparing Key-Value Stores"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/16fe4308-ed47-451f-a852-c476ecfb4167_1280x1977.jpeg"
loading="lazy"
alt="A Handy Cheatsheet for the Most Popular Cloud Services"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/89a09e07-6548-4c12-87c6-0486c6177ea7_1308x1536.jpeg"
loading="lazy"
alt="Which Database Should I Use on AWS?"
&gt;&lt;/p&gt;
&lt;h2 id="bonus-2-vài-video-hay-ho-đến-từ-bytebytego"&gt;Bonus 2: Vài video hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=hFURlsMwU7c" target="_blank" rel="noopener"
&gt;What Is the Most Popular Open-Source AI Stack?&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Newsletter #13</title><link>https://miti99.com/post/2025/04/22/</link><pubDate>Tue, 22 Apr 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/04/22/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #13.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="designing-a-distributed-id-generator"&gt;&lt;a class="link" href="https://siddharthsabron.in/blog/id-generator/" target="_blank" rel="noopener"
&gt;Designing a Distributed ID Generator&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích cách thiết kế và triển khai một hệ thống sinh ID phân tán hiệu quả. Tác giả trình bày các yêu cầu quan trọng của ID trong hệ thống phân tán như tính duy nhất, khả năng sắp xếp theo thời gian, hiệu suất cao và khả năng mở rộng. Bài viết so sánh các giải pháp khác nhau như UUID, cơ chế auto-increment của database, và đi sâu vào giải pháp Snowflake ID do Twitter phát triển. Đây là kiến thức thiết yếu cho các kỹ sư làm việc với hệ thống phân tán quy mô lớn.&lt;/p&gt;
&lt;h2 id="3200-cpu-utilization"&gt;&lt;a class="link" href="https://josephmate.github.io/2025-02-26-3200p-cpu-util/" target="_blank" rel="noopener"
&gt;3,200% CPU Utilization&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này mô tả một tình huống cực đoan khi tác giả phát hiện máy chủ của mình đạt tới mức sử dụng CPU 3,200% - tất cả 32 core đều hoạt động hết công suất. Điều thú vị là vấn đề này xuất phát từ race condition, một dạng lỗi thường được nghĩ đến trong context làm hỏng dữ liệu hoặc deadlock, chứ ít khi liên quan đến vấn đề hiệu năng. Bài viết cung cấp góc nhìn sâu sắc về cách phân tích và giải quyết các vấn đề hiệu năng phức tạp trong hệ thống đa luồng.&lt;/p&gt;
&lt;h2 id="a-map-metaphor-for-architectural-diagrams"&gt;&lt;a class="link" href="https://www.giorgiosironi.com/2025/02/maps-metaphor-for-architectural-diagrams.html" target="_blank" rel="noopener"
&gt;A map metaphor for architectural diagrams&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trình bày một cách tiếp cận thú vị khi sử dụng phép ẩn dụ về bản đồ để tạo và hiểu các sơ đồ kiến trúc phần mềm. Tác giả Giorgio Sironi so sánh việc thiết kế kiến trúc phần mềm với việc vẽ bản đồ hai chiều để biểu diễn một thế giới ba chiều phức tạp. Giống như cách bản đồ địa lý chọn lọc và trừu tượng hóa thông tin để làm nổi bật các yếu tố quan trọng, sơ đồ kiến trúc cũng cần phải đơn giản hóa hệ thống phức tạp mà vẫn giữ được bản chất và các mối quan hệ chính. Cách tiếp cận này giúp cải thiện giao tiếp giữa các bên liên quan và hỗ trợ việc ra quyết định trong quá trình phát triển phần mềm.&lt;/p&gt;
&lt;h2 id="about"&gt;&lt;a class="link" href="https://tryingthings.wordpress.com/2025/02/28/about-developer-philosophy/" target="_blank" rel="noopener"
&gt;About &amp;ldquo;Developer philosophy&amp;rdquo;&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích và bình luận về triết lý phát triển phần mềm của tác giả qntm. Nó đưa ra những suy ngẫm về cách tiếp cận lập trình hiện đại, đặc biệt là những lời khuyên dành cho các lập trình viên mới vào nghề. Tác giả đặt ra câu hỏi thú vị về vai trò của các junior developer trong thời đại AI đang phát triển mạnh mẽ, đồng thời nhấn mạnh tầm quan trọng của việc xây dựng mã nguồn có tính bảo trì cao, rõ ràng và đơn giản. Bài viết kết hợp giữa kinh nghiệm cá nhân và những nguyên tắc phát triển phần mềm cốt lõi, tạo nên một góc nhìn đa chiều về nghề phát triển phần mềm hiện đại.&lt;/p&gt;
&lt;h2 id="team-learning-session-surviving-legacy-code-by-jb-rainsberger"&gt;&lt;a class="link" href="https://www.giorgiosironi.com/2025/02/team-learning-session-surviving-legacy.html" target="_blank" rel="noopener"
&gt;Team learning session: surviving legacy code by J.B. Rainsberger&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này tổng hợp những kiến thức và chiến lược quý giá từ buổi học tập đội nhóm về cách làm việc hiệu quả với mã nguồn legacy (thừa kế), dưới sự hướng dẫn của chuyên gia J.B. Rainsberger. Tác giả chia sẻ các kỹ thuật thiết thực để tái cấu trúc mã nguồn cũ mà không làm gián đoạn hệ thống, nhấn mạnh phương pháp phát triển hướng kiểm thử (TDD) và việc xây dựng các characterization tests. Bài viết cung cấp lộ trình rõ ràng để cải thiện dần dần hệ thống legacy, giúp các đội phát triển có thể áp dụng ngay vào môi trường làm việc thực tế. Đây là tài liệu hữu ích cho bất kỳ ai đang phải đối mặt với thách thức của việc bảo trì và nâng cấp mã nguồn cũ.&lt;/p&gt;
&lt;h2 id="trimodal-nature-of-tech-compensation-in-the-us-uk-and-india"&gt;&lt;a class="link" href="https://newsletter.pragmaticengineer.com/p/trimodal" target="_blank" rel="noopener"
&gt;Trimodal Nature of Tech Compensation in the US, UK and India&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này của Gergely Orosz, tác giả của bản tin The Pragmatic Engineer, phân tích sâu sắc về sự phân phối mức lương trong ngành công nghệ theo ba nhóm riêng biệt. Dựa trên phân tích hơn 20.000 điểm dữ liệu từ Levels.fyi, tác giả phát hiện rằng cùng một vị trí kỹ sư phần mềm có thể nhận được mức lương chênh lệch từ 2-4 lần, tùy thuộc vào loại công ty. Bài viết chia các công ty thành ba cấp độ: Cấp 1 là các công ty địa phương với mức lương thấp nhất, Cấp 2 là các công ty công nghệ có quy mô vừa phải, và Cấp 3 là các công ty công nghệ hàng đầu, các startup thành công và quỹ đầu tư với mức lương cao nhất. Đặc biệt, ở Mỹ, các quỹ đầu cơ thậm chí còn trả lương cao hơn cả các công ty Big Tech. Nghiên cứu này không chỉ giúp các kỹ sư hiểu rõ hơn về thị trường lương mà còn là thông tin quý giá cho những ai đang tìm kiếm cơ hội nghề nghiệp trong lĩnh vực công nghệ.&lt;/p&gt;
&lt;h2 id="9-software-architecture-patterns-for-distributed-systems"&gt;&lt;a class="link" href="https://dev.to/somadevtoo/9-software-architecture-patterns-for-distributed-systems-2o86" target="_blank" rel="noopener"
&gt;9 Software Architecture Patterns for Distributed Systems&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này giới thiệu chín mẫu kiến trúc phần mềm quan trọng cho hệ thống phân tán, đóng vai trò then chốt trong việc thiết kế các ứng dụng phân tán hiệu quả. Tác giả trình bày chi tiết về các mẫu như Peer-to-Peer (giao tiếp ngang hàng không cần điều phối trung tâm), API Gateway (điểm vào duy nhất cho nhiều dịch vụ), Pub-Sub (truyền thông không đồng bộ thông qua các chủ đề), Request-Response (giao tiếp đồng bộ giữa client và server), Event Sourcing (lưu trữ các thay đổi trạng thái dưới dạng sự kiện), ETL (trích xuất, biến đổi và tải dữ liệu), Batching (xử lý dữ liệu theo lô), Stream Processing (xử lý dữ liệu liên tục) và Orchestration (điều phối luồng công việc giữa các dịch vụ). Mỗi mẫu được phân tích về ưu điểm, nhược điểm và tình huống áp dụng phù hợp, giúp các kiến trúc sư và nhà phát triển có thể lựa chọn đúng mẫu thiết kế cho từng yêu cầu cụ thể trong hệ thống của họ.&lt;/p&gt;
&lt;h2 id="extending-java-apis---add-missing-features-without-the-hassle"&gt;&lt;a class="link" href="https://foojay.io/today/extending-java-apis-add-missing-features-without-the-hassle/" target="_blank" rel="noopener"
&gt;Extending Java APIs - Add Missing Features Without the Hassle&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trình bày cách mở rộng các API Java để thêm tính năng mới mà không cần chờ đợi các bản cập nhật chính thức từ Oracle. Tác giả giới thiệu công cụ Manifold, cho phép nhà phát triển liền mạch bổ sung các phương thức còn thiếu vào các lớp trong API Java mà không làm thay đổi mã nguồn gốc. Phương pháp này duy trì tính tương thích ngược và tránh rủi ro khi mở rộng chức năng. Bài viết đưa ra các ví dụ cụ thể về việc thêm phương thức tiện ích vào các lớp chuẩn như String, File, và các lớp Collection. Đây là công cụ hữu ích cho các nhà phát triển Java muốn cải thiện trải nghiệm lập trình mà không cần viết các lớp wrapper phức tạp hoặc chờ đợi các tính năng xuất hiện trong phiên bản Java tiếp theo.&lt;/p&gt;
&lt;h2 id="how-spring-boot-reloads-configuration-without-restart"&gt;&lt;a class="link" href="https://medium.com/@AlexanderObregon/how-spring-boot-reloads-configuration-without-restart-4d9dc9e8b926" target="_blank" rel="noopener"
&gt;How Spring Boot Reloads Configuration Without Restart&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này đi sâu vào cơ chế cho phép Spring Boot tải lại cấu hình mà không cần khởi động lại ứng dụng. Tác giả Alexander Obregon giải thích cách Spring Boot sử dụng Spring Cloud Config Server kết hợp với Actuator endpoints để triển khai tính năng cập nhật cấu hình động (dynamic configuration updates). Bài viết mô tả chi tiết về cách cấu hình @RefreshScope annotation cho các bean cần được làm mới, cách thiết lập webhook để tự động cập nhật khi cấu hình thay đổi trong kho lưu trữ, và các phương pháp tối ưu để quản lý việc làm mới cấu hình trong môi trường phân tán. Đây là kiến thức thiết yếu cho các nhà phát triển Spring Boot muốn xây dựng ứng dụng có khả năng cập nhật cấu hình linh hoạt mà không cần thời gian chết (downtime), đặc biệt hữu ích trong các môi trường production yêu cầu tính khả dụng cao.&lt;/p&gt;
&lt;h2 id="building-high-performance-rpc-services-with-grpc-and-spring-boot"&gt;&lt;a class="link" href="https://www.javacodegeeks.com/2025/03/building-high-performance-rpc-services-with-grpc-and-spring-boot.html" target="_blank" rel="noopener"
&gt;Building High-Performance RPC Services with gRPC and Spring Boot&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này hướng dẫn chi tiết về cách kết hợp gRPC với Spring Boot để xây dựng các dịch vụ RPC hiệu năng cao. Tác giả giới thiệu về ưu điểm của gRPC so với REST API truyền thống, bao gồm giao thức nhẹ hơn, hiệu suất cao hơn nhờ sử dụng Protocol Buffers và HTTP/2, cũng như khả năng tạo mã tự động cho nhiều ngôn ngữ. Bài viết trình bày từng bước cách thiết lập dự án Spring Boot với gRPC, cách định nghĩa các service thông qua Protocol Buffers (.proto files), và cách triển khai cả phía server và client. Ngoài ra, tác giả cũng đề cập đến các chiến lược tối ưu hóa hiệu suất, xử lý lỗi, và triển khai các tính năng nâng cao như streaming và authentication. Đây là tài liệu toàn diện cho các nhà phát triển Java muốn nâng cao hiệu suất giao tiếp giữa các microservice trong hệ thống phân tán.&lt;/p&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/39f5b04d-ad39-4bbe-a32f-f47792d4ef62_2250x2682.png"
loading="lazy"
alt="Latency and Partition Tolerance in Distributed Systems"
&gt;&lt;/p&gt;
&lt;h2 id="bonus-2-vài-video-hay-ho-đến-từ-bytebytego"&gt;Bonus 2: Vài video hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=3Lis4w4_bBc" target="_blank" rel="noopener"
&gt;8 Most Important Tips for Designing Fault-Tolerant System&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Newsletter #12</title><link>https://miti99.com/post/2025/04/20/</link><pubDate>Sun, 20 Apr 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/04/20/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #12.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="fundamental-techniques-for-software-architects"&gt;&lt;a class="link" href="https://www.workingsoftware.dev/fundamental-techniques-for-software-architects/" target="_blank" rel="noopener"
&gt;Fundamental Techniques for Software Architects&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này tổng hợp các kỹ thuật nền tảng mà mọi kiến trúc sư phần mềm nên biết, bao gồm cách tiếp cận phân tích hệ thống, thiết kế các thành phần linh hoạt, giao tiếp hiệu quả với các bên liên quan và đảm bảo hệ thống có thể mở rộng, bảo trì lâu dài. Đây là tài liệu hữu ích cho cả những người mới bắt đầu và các kiến trúc sư dày dạn kinh nghiệm muốn củng cố kiến thức cốt lõi.&lt;/p&gt;
&lt;h2 id="the-end-of-programming-as-we-know-it"&gt;&lt;a class="link" href="https://www.oreilly.com/radar/the-end-of-programming-as-we-know-it/" target="_blank" rel="noopener"
&gt;The End of Programming as We Know It&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích sự thay đổi lớn trong ngành lập trình khi AI trở thành đồng nghiệp của lập trình viên. Tác giả cho rằng AI sẽ giúp lập trình viên tăng năng suất gấp nhiều lần, đồng thời mở rộng phạm vi ứng dụng phần mềm trong doanh nghiệp và xã hội. Tuy nhiên, thay vì giảm nhu cầu nhân lực, AI sẽ tạo ra nhiều cơ hội mới, đòi hỏi lập trình viên phải liên tục học hỏi và sáng tạo. Bài viết cũng nhấn mạnh chất lượng sản phẩm sẽ ngày càng được nâng cao nhờ sự kết hợp giữa con người và AI.&lt;/p&gt;
&lt;h2 id="in-defense-of-simple-architectures"&gt;&lt;a class="link" href="https://danluu.com/simple-architectures/" target="_blank" rel="noopener"
&gt;In defense of simple architectures&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này lập luận rằng nhiều hệ thống lớn, thành công vẫn có thể xây dựng dựa trên kiến trúc đơn giản như monolith với database truyền thống. Tác giả đưa ra ví dụ thực tế từ Wave và Stack Overflow để chứng minh rằng đơn giản giúp tiết kiệm chi phí, dễ bảo trì, giảm rủi ro vận hành và tập trung vào giá trị cho người dùng. Bài viết cũng cảnh báo về xu hướng chạy theo các kiến trúc phức tạp không cần thiết trong ngành công nghệ.&lt;/p&gt;
&lt;h2 id="the-trouble-with"&gt;&lt;a class="link" href="https://newsletter.weskao.com/p/the-trouble-with-good-enough" target="_blank" rel="noopener"
&gt;The trouble with &amp;ldquo;good enough&amp;rdquo;&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích vấn đề khi các cá nhân hoặc đội nhóm dừng lại ở mức &amp;ldquo;đủ tốt&amp;rdquo; quá sớm, trước khi thực sự đạt đến điểm lợi ích cận biên giảm dần. Tác giả nhấn mạnh rằng mỗi người có định nghĩa khác nhau về &amp;ldquo;good enough&amp;rdquo;, và nhiều khi chúng ta tự giới hạn tiêu chuẩn mà không nhận ra. Để tạo ra sản phẩm và kết quả xuất sắc, cần liên tục nâng cao tiêu chuẩn và đánh giá lại xem mình đã thực sự đạt đến mức tối ưu hay chưa.&lt;/p&gt;
&lt;h2 id="should-managers-still-code"&gt;&lt;a class="link" href="https://theengineeringmanager.substack.com/p/should-managers-still-code" target="_blank" rel="noopener"
&gt;Should managers still code?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này bàn về câu hỏi muôn thuở: các engineering manager (EM) có nên tiếp tục viết code không? Tác giả cho rằng điều quan trọng là EM phải “ở trong code” (hiểu rõ codebase, review, nắm chi tiết kỹ thuật), nhưng không nhất thiết phải trực tiếp viết code hàng ngày. Việc này giúp EM duy trì sự kết nối với kỹ thuật, hỗ trợ team hiệu quả và tránh cảm giác “lạc lõng” với công việc cốt lõi của nhóm.&lt;/p&gt;
&lt;h2 id="what-is-saga-pattern-in-distributed-systems"&gt;&lt;a class="link" href="https://newsletter.scalablethread.com/p/what-is-saga-pattern-in-distributed" target="_blank" rel="noopener"
&gt;What is Saga Pattern in Distributed Systems?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này giải thích về Saga Pattern – một giải pháp giúp các hệ thống microservices phối hợp thực hiện các giao dịch phân tán. Saga Pattern đảm bảo tính nhất quán dữ liệu khi nhiều service độc lập cùng tham gia xử lý một yêu cầu (ví dụ: đặt hàng, thanh toán, vận chuyển&amp;hellip;). Bài viết cũng chỉ ra điểm khác biệt giữa các giao dịch truyền thống (ACID) và cách tiếp cận Saga trong môi trường phân tán hiện đại.&lt;/p&gt;
&lt;h2 id="what-would-happen-if-we-didn"&gt;&lt;a class="link" href="https://github.com/Hawzen/hdp" target="_blank" rel="noopener"
&gt;What would happen if we didn&amp;rsquo;t use TCP or UDP?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Repo này ghi lại một loạt thử nghiệm thú vị: chuyện gì sẽ xảy ra nếu gửi các gói tin mạng sử dụng một giao thức vận chuyển không phải TCP, UDP hay ICMP – mà là một giá trị “tự chế”? Tác giả thực hiện các thí nghiệm thực tế trên máy cá nhân và qua Internet, khám phá cách hệ điều hành, router, firewall xử lý những gói tin “dị biệt” này. Đây là một ví dụ sinh động về cách tư duy khám phá, thử nghiệm và hiểu sâu về mạng máy tính hiện đại.&lt;/p&gt;
&lt;h2 id="scoped-values-in-java-24---inside-java-newscast-86"&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=7tfUJLUbZiM" target="_blank" rel="noopener"
&gt;Scoped Values in Java 24 - Inside Java Newscast #86&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Video này giới thiệu về Scoped Values – một tính năng mới trong Java 24 cho phép truyền dữ liệu bất biến giữa các phương thức, các luồng con một cách an toàn, tiện lợi và hiệu quả. Scoped Values giúp quản lý dữ liệu dùng chung trong phạm vi thực thi mà không cần dùng biến toàn cục hay ThreadLocal, từ đó nâng cao khả năng mở rộng và bảo trì mã nguồn.&lt;/p&gt;
&lt;h2 id="java-24---better-language-better-apis-better-runtime"&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=2NTyzL-9Bfo" target="_blank" rel="noopener"
&gt;Java 24 - Better Language, Better APIs, Better Runtime&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Video này điểm qua những cải tiến nổi bật trong các phiên bản Java mới nhất (từ 22 đến 24), bao gồm các tính năng ngôn ngữ hiện đại, API mới, và tối ưu hóa runtime. Các chủ đề nổi bật như unnamed patterns, module imports, Foreign Function &amp;amp; Memory API, và nhiều cải tiến giúp Java ngày càng mạnh mẽ, dễ dùng và hiệu quả hơn cho lập trình viên hiện đại.&lt;/p&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/f112df94-df52-4140-98ec-873e5b74d988_1280x1601.gif"
loading="lazy"
alt="30 Free APIs for Developers"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/c3bf4776-744b-4e87-85f8-6dddd6d85597_1280x1566.gif"
loading="lazy"
alt="The Generative AI Learning Roadmap"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/c1dbb32e-8d1b-4c13-ae48-fe485ad92191_1280x1601.gif"
loading="lazy"
alt="HTTP/1 -&amp;gt; HTTP/2 -&amp;gt; HTTP/3"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/d864f35c-537c-4571-8644-ce20d1a0caa5_1280x1427.gif"
loading="lazy"
alt="Structure of URL"
&gt;&lt;/p&gt;
&lt;h2 id="bonus-2-vài-video-hay-ho-đến-từ-bytebytego"&gt;Bonus 2: Vài video hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=3Lis4w4_bBc" target="_blank" rel="noopener"
&gt;8 Most Important Tips for Designing Fault-Tolerant System&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="bonus-3-vài-tài-liệu-hay-ho-đến-từ-redisio"&gt;Bonus 3: Vài tài liệu hay ho đến từ &lt;a class="link" href="https://redis.io/" target="_blank" rel="noopener"
&gt;Redis.io&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://redis.io/resources/cache-and-message-broker-for-microservices-solution-brief.pdf" target="_blank" rel="noopener"
&gt;Cache and Message Broker for Microservices&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://redis.io/wp-content/uploads/2021/12/caching-at-scale-with-redis-updated-2021-12-04.pdf" target="_blank" rel="noopener"
&gt;Caching at Scale With Redis&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Newsletter #11</title><link>https://miti99.com/post/2025/04/12/</link><pubDate>Sat, 12 Apr 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/04/12/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #11.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="enabling-near-real-time-data-analytics-on-the-data-lake"&gt;&lt;a class="link" href="https://engineering.grab.com/enabling-near-realtime-data-analytics" target="_blank" rel="noopener"
&gt;Enabling near real-time data analytics on the data lake&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ cách Grab xây dựng hệ thống phân tích dữ liệu gần thời gian thực trên data lake. Các điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng Apache Hudi để xử lý dữ liệu với độ trễ thấp&lt;/li&gt;
&lt;li&gt;Tối ưu hóa cho 2 loại nguồn dữ liệu: throughput cao (Kafka) và thấp (RDS)&lt;/li&gt;
&lt;li&gt;Cách tiếp cận khác nhau cho từng loại nguồn dữ liệu:
&lt;ul&gt;
&lt;li&gt;Nguồn throughput cao: Sử dụng Merge On Read (MOR) với Flink và Spark&lt;/li&gt;
&lt;li&gt;Nguồn throughput thấp: Sử dụng Copy On Write (COW) đơn giản hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Tác động tích cực:
&lt;ul&gt;
&lt;li&gt;Cung cấp metrics kinh doanh mới nhất&lt;/li&gt;
&lt;li&gt;Phát hiện gian lận nhanh hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-ultimate-guide-to-software-architecture-documentation"&gt;&lt;a class="link" href="https://www.workingsoftware.dev/software-architecture-documentation-the-ultimate-guide/" target="_blank" rel="noopener"
&gt;The Ultimate Guide To Software Architecture Documentation&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết cung cấp hướng dẫn toàn diện về cách viết, cấu trúc, trực quan hóa và quản lý tài liệu kiến trúc phần mềm. Các điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Tại sao cần tài liệu hóa kiến trúc phần mềm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tạo sự hiểu biết chung cho các bên liên quan&lt;/li&gt;
&lt;li&gt;Hỗ trợ công việc kiến trúc&lt;/li&gt;
&lt;li&gt;Hướng dẫn team phát triển&lt;/li&gt;
&lt;li&gt;Cải thiện giao tiếp với stakeholders&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cách cấu trúc tài liệu:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng mẫu arc42&lt;/li&gt;
&lt;li&gt;Mô hình C4 cho trực quan hóa&lt;/li&gt;
&lt;li&gt;4 cấp độ: Context, Container, Component, Code&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Công cụ và phương pháp:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Documentation as Code&lt;/li&gt;
&lt;li&gt;Diagrams as Code&lt;/li&gt;
&lt;li&gt;Các công cụ như AsciiDoc, PlantUML, Structurizr&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="beyond-the-basics-designing-for-a-million-users"&gt;&lt;a class="link" href="https://javarevisited.substack.com/p/beyond-the-basics-designing-for-a" target="_blank" rel="noopener"
&gt;Beyond the Basics: Designing for a Million Users&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ các khái niệm cốt lõi để thiết kế hệ thống có thể mở rộng từ 0 đến hàng triệu người dùng. Các điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Các vấn đề thường gặp khi mở rộng:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Server đơn lẻ bị quá tải&lt;/li&gt;
&lt;li&gt;Sự cố làm cả hệ thống sập&lt;/li&gt;
&lt;li&gt;Chi phí tài nguyên tăng đột biến&lt;/li&gt;
&lt;li&gt;Vấn đề về độ trễ ở các khu vực địa lý khác nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Giải pháp mở rộng:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scale ngang thay vì scale dọc&lt;/li&gt;
&lt;li&gt;Thiết kế stateless thay vì stateful&lt;/li&gt;
&lt;li&gt;Sử dụng Load Balancer để phân phối tải&lt;/li&gt;
&lt;li&gt;Chọn database phù hợp (SQL/NoSQL)&lt;/li&gt;
&lt;li&gt;Replication và Sharding cho database&lt;/li&gt;
&lt;li&gt;Caching cho dữ liệu truy cập thường xuyên&lt;/li&gt;
&lt;li&gt;CDN cho nội dung tĩnh&lt;/li&gt;
&lt;li&gt;Message Queue cho xử lý bất đồng bộ&lt;/li&gt;
&lt;li&gt;Geo-routing cho người dùng toàn cầu&lt;/li&gt;
&lt;li&gt;Logging và Monitoring toàn diện&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="decision-making-pitfalls-for-technical-leaders"&gt;&lt;a class="link" href="https://chelseatroy.com/2024/10/16/decision-making-pitfalls-for-technical-leaders/" target="_blank" rel="noopener"
&gt;Decision-Making Pitfalls for Technical Leaders&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ 3 cạm bẫy phổ biến trong việc ra quyết định của các technical leader và cách tránh chúng:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giả định ngữ cảnh (Assuming Context)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Áp dụng &amp;ldquo;best practice&amp;rdquo; mà không hiểu tại sao nó tốt&lt;/li&gt;
&lt;li&gt;Không thể giải thích rõ ràng lý do cho team hoặc leadership&lt;/li&gt;
&lt;li&gt;Dẫn đến giải pháp không phù hợp với vấn đề cụ thể&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xem mọi thứ là chỉ số tối ưu (Treating Everything as an Optimizing Metric)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cố gắng tối ưu tất cả các khía cạnh cùng lúc&lt;/li&gt;
&lt;li&gt;Kéo dài quá trình ra quyết định&lt;/li&gt;
&lt;li&gt;Gây khó khăn cho các team phụ thuộc&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tạo ra tình huống khẩn cấp (Manufacturing Emergencies)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không dự đoán được các sự kiện trong tương lai&lt;/li&gt;
&lt;li&gt;Đánh giá quá cao mức độ nghiêm trọng của vấn đề&lt;/li&gt;
&lt;li&gt;Tạo áp lực không cần thiết cho team&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Giải pháp:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hiểu rõ tradeoffs của mỗi quyết định&lt;/li&gt;
&lt;li&gt;Phân biệt giữa optimizing metrics và satisficing metrics&lt;/li&gt;
&lt;li&gt;Giao tiếp minh bạch với team về áp lực từ leadership&lt;/li&gt;
&lt;li&gt;Hỗ trợ team thực hiện với ít xáo trộn nhất có thể&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-i-know-i"&gt;&lt;a class="link" href="https://www.seangoedecke.com/thoughts-about-engineers/" target="_blank" rel="noopener"
&gt;How I know I&amp;rsquo;m working with a strong engineer&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ cách đánh giá một kỹ sư phần mềm giỏi thông qua hai suy nghĩ thường xuất hiện khi làm việc cùng họ:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;Oh nice catch, I didn&amp;rsquo;t think of that!&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khi kỹ sư phát hiện ra vấn đề mà bạn không nghĩ tới&lt;/li&gt;
&lt;li&gt;Không phải là những phản hồi nhỏ nhặt, mà là những insight có giá trị&lt;/li&gt;
&lt;li&gt;Giúp tránh bug, cải thiện UX, đơn giản hóa thiết kế&lt;/li&gt;
&lt;li&gt;Nếu suy nghĩ này xuất hiện quá thường xuyên, có thể bạn nên để họ đưa ra các quyết định chính&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;Good, that&amp;rsquo;ll work.&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khi kỹ sư đưa ra giải pháp tương tự như bạn nghĩ&lt;/li&gt;
&lt;li&gt;Cho thấy họ là người đáng tin cậy, có thể hoàn thành công việc&lt;/li&gt;
&lt;li&gt;Đây cũng là một lời khen cao&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết nhấn mạnh rằng có nhiều cách để đánh giá một kỹ sư giỏi, nhưng đây là một phương pháp đơn giản và hiệu quả để có cái nhìn ban đầu về năng lực của họ.&lt;/p&gt;
&lt;h2 id="ugly-code-and-dumb-things"&gt;&lt;a class="link" href="https://lucumr.pocoo.org/2025/2/20/ugly-code/" target="_blank" rel="noopener"
&gt;Ugly Code and Dumb Things&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết thảo luận về sự đánh đổi giữa code đẹp và code hiệu quả trong phát triển phần mềm. Các điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hai đam mê, hai cách tiếp cận&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tạo code đẹp, elegant: tập trung vào thiết kế rõ ràng và khả năng tái sử dụng&lt;/li&gt;
&lt;li&gt;Giải pháp nhanh, thực tế: tập trung vào tốc độ và lặp lại để đáp ứng nhu cầu người dùng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Triết lý của Flickr&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Làm điều đơn giản nhất có thể hoạt động&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Ưu tiên scale, sharding, replication&lt;/li&gt;
&lt;li&gt;Code có thể &amp;ldquo;xấu&amp;rdquo; nhưng hiệu quả trong việc giải quyết vấn đề thực tế&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cân bằng giữa code đẹp và code hiệu quả&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Code hoàn hảo không đảm bảo thành công nếu không giải quyết vấn đề thực tế&lt;/li&gt;
&lt;li&gt;Code &amp;ldquo;xấu&amp;rdquo; nhưng chức năng thường đi kèm với những thỏa hiệp phù hợp để phát triển nhanh&lt;/li&gt;
&lt;li&gt;Dự án thành công sẽ trưởng thành và cần được tái cấu trúc khi thời điểm thích hợp&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết kết luận rằng cả hai cách tiếp cận đều hợp lệ, nhưng hiếm khi tồn tại hài hòa trong cùng một codebase. Thách thức thực sự là quyết định khi nào nên chuyển từ giải pháp nhanh sang nền tảng vững chắc hơn.&lt;/p&gt;
&lt;h2 id="development-philosophy"&gt;&lt;a class="link" href="https://develop.sentry.dev/getting-started/philosophy/" target="_blank" rel="noopener"
&gt;Development Philosophy&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ triết lý phát triển phần mềm của Sentry, được đúc kết từ hơn 10 năm kinh nghiệm. Các điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cẩn thận với code &amp;ldquo;đẹp&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Code không phải là nghệ thuật, mà là để giải quyết vấn đề của khách hàng&lt;/li&gt;
&lt;li&gt;Cần cân bằng giữa abstraction và giải pháp &amp;ldquo;tạm thời&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Nên xin ý kiến từ người có kinh nghiệm khi cần&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đúng không phải lúc nào cũng tốt&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Áp dụng nguyên tắc &amp;ldquo;be conservative in what you send, be liberal in what you accept&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Cần cân nhắc giữa tính đúng đắn và năng suất&lt;/li&gt;
&lt;li&gt;Công cụ hữu ích có thể trở thành gánh nặng nếu áp dụng sai&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chấp nhận giải pháp tạm thời&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Duct tape&amp;rdquo; là công cụ tốt để thử nghiệm&lt;/li&gt;
&lt;li&gt;Đôi khi giải pháp tạm thời có thể tồn tại lâu hơn tính năng&lt;/li&gt;
&lt;li&gt;Giúp khám phá những gì thực sự cần xây dựng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xây dựng nền tảng vững chắc&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không thể xây dựng toàn bộ doanh nghiệp trên giải pháp tạm thời&lt;/li&gt;
&lt;li&gt;Sẵn sàng cam kết với các dự án kỹ thuật dài hạn&lt;/li&gt;
&lt;li&gt;Ví dụ: từ llvm-symbolizer đến symbolicator service&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các nguyên tắc khác&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Viết code dễ hiểu, tránh quá thông minh&lt;/li&gt;
&lt;li&gt;Mọi người đều có thể đóng góp vào bất kỳ repository nào&lt;/li&gt;
&lt;li&gt;Sử dụng Python, Rust và TypeScript làm ngôn ngữ chính&lt;/li&gt;
&lt;li&gt;Tránh phụ thuộc vào database độc quyền&lt;/li&gt;
&lt;li&gt;Cẩn thận với dependencies và chi phí của chúng&lt;/li&gt;
&lt;li&gt;Luôn giữ mainline branch &amp;ldquo;xanh&amp;rdquo; (green)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="ai-is-stifling-tech-adoption"&gt;&lt;a class="link" href="https://vale.rocks/posts/ai-is-stifling-tech-adoption" target="_blank" rel="noopener"
&gt;AI is Stifling Tech Adoption&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết thảo luận về tác động của AI đối với việc áp dụng công nghệ mới trong phát triển phần mềm. Các điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Khoảng cách kiến thức (Knowledge Gap)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dữ liệu huấn luyện của AI thường bị giới hạn thời gian&lt;/li&gt;
&lt;li&gt;Ví dụ: Claude 3.5 có cutoff tháng 4/2024, ChatGPT 4 có cutoff tháng 6/2024&lt;/li&gt;
&lt;li&gt;Dẫn đến việc AI không thể hỗ trợ các công nghệ mới&lt;/li&gt;
&lt;li&gt;Tạo ra vòng lặp ngược: thiếu hỗ trợ AI → ít người dùng → ít tài liệu → ít dữ liệu huấn luyện&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ảnh hưởng của System Prompt&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI có xu hướng ưu tiên một số công nghệ nhất định&lt;/li&gt;
&lt;li&gt;Ví dụ: React và Tailwind thường được chọn cho các dự án web&lt;/li&gt;
&lt;li&gt;Thậm chí có thể viết lại code theo &amp;ldquo;sở thích&amp;rdquo; của nó&lt;/li&gt;
&lt;li&gt;Điều này ảnh hưởng đến quyết định của developer, đặc biệt là người mới&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kết quả thử nghiệm&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Claude và ChatGPT: ưu tiên React + Tailwind&lt;/li&gt;
&lt;li&gt;Gemini: ưu tiên HTML/CSS/JS thuần nhưng vẫn đề xuất React&lt;/li&gt;
&lt;li&gt;DeepSeek: linh hoạt hơn nhưng cần nhiều prompt hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hệ quả&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Công nghệ phổ biến trước khi AI ra đời sẽ tiếp tục thống trị&lt;/li&gt;
&lt;li&gt;Developer có thể chọn công nghệ dựa trên khả năng hỗ trợ của AI&lt;/li&gt;
&lt;li&gt;Cần minh bạch hơn về bias công nghệ trong các mô hình AI&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="february---the-rest-of-the-story---jvm-weekly-vol-119"&gt;&lt;a class="link" href="https://www.jvm-weekly.com/p/february-the-rest-of-the-story-jvm" target="_blank" rel="noopener"
&gt;February - The Rest of the Story - JVM Weekly vol. 119&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết tổng hợp các tin tức và cập nhật mới nhất trong thế giới JVM. Các điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scala 3 LTS sắp tới&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phiên bản LTS dự kiến ra mắt Q4/2025&lt;/li&gt;
&lt;li&gt;Sẽ không còn hỗ trợ JDK 8&lt;/li&gt;
&lt;li&gt;Đang cân nhắc giữa JDK 11 và 17 làm yêu cầu tối thiểu&lt;/li&gt;
&lt;li&gt;Lý do: cần thay đổi implementation của lazy val do sun.misc.Unsafe&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cập nhật Kotlin&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;KotlinPoet 2.0: cải thiện việc xử lý khoảng trắng khi generate code&lt;/li&gt;
&lt;li&gt;Dokka 2.0: công cụ tạo tài liệu với Gradle Plugin mới&lt;/li&gt;
&lt;li&gt;Ktor CLI: công cụ dòng lệnh để tạo và quản lý dự án Ktor&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Công nghệ mới&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pulumi Java 1.0: Infrastructure as Code cho Java&lt;/li&gt;
&lt;li&gt;CheerpJ 3.1: JVM trên WebAssembly, hướng tới Java 11+ và JNI&lt;/li&gt;
&lt;li&gt;JVM autoparallelizer: tự động song song hóa vòng lặp trong bytecode&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các bài viết hay&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hướng dẫn phỏng vấn Java Lead tại J.P. Morgan&lt;/li&gt;
&lt;li&gt;Series về SOLID principles trong Kotlin&lt;/li&gt;
&lt;li&gt;Agentic AI với Quarkus: tích hợp AI vào ứng dụng Java&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="manager-antipatterns"&gt;&lt;a class="link" href="https://blogs.newardassociates.com/blog/2024/management-antipatterns.html" target="_blank" rel="noopener"
&gt;Manager Antipatterns&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết tổng hợp các mẫu quản lý không hiệu quả thường gặp trong các công ty. Các điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các mẫu quản lý không hiệu quả phổ biến&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;The Absentee Manager&amp;rdquo;: Người quản lý vắng mặt&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The Bomb Manager&amp;rdquo;: Muốn đập bỏ tất cả và làm lại từ đầu&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The C-Buddy Manager&amp;rdquo;: Quản lý được bổ nhiệm vì là bạn của lãnh đạo&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The Funnel Manager&amp;rdquo;: Chỉ truyền đạt thông tin từ cấp trên xuống&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The Hammer Manager&amp;rdquo;: Chỉ biết một cách giải quyết vấn đề&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The Headless Chicken Manager&amp;rdquo;: Hoảng loạn và không biết phải làm gì&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The Laissez-Faire Manager&amp;rdquo;: Để mặc nhân viên tự làm&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The Lateral-Move Manager&amp;rdquo;: Chuyển quản lý từ nhóm khác sang&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The Perfectionist Manager&amp;rdquo;: Đòi hỏi mọi thứ phải hoàn hảo&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The Smartest-Engineer Manager&amp;rdquo;: Thăng chức kỹ sư giỏi nhất làm quản lý&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The Sphinx Manager&amp;rdquo;: Không giao tiếp rõ ràng&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The Tech-Lead Manager&amp;rdquo;: Vừa làm quản lý vừa làm developer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cách khắc phục&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khi bạn làm việc dưới quyền quản lý đó&lt;/li&gt;
&lt;li&gt;Khi bạn là quản lý cấp trên của họ&lt;/li&gt;
&lt;li&gt;Khi bạn chính là người quản lý đó&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết nhấn mạnh tầm quan trọng của việc nhận diện và khắc phục các mẫu quản lý không hiệu quả để xây dựng môi trường làm việc tốt hơn.&lt;/p&gt;
&lt;h2 id="pause--decision-making-superpower"&gt;&lt;a class="link" href="https://read.perspectiveship.com/p/pause" target="_blank" rel="noopener"
&gt;Pause – Decision-Making Superpower&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ về tầm quan trọng của việc tạm dừng trước khi đưa ra quyết định. Các điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tại sao cần tạm dừng?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tách biệt khỏi cảm xúc có thể làm mờ phán đoán&lt;/li&gt;
&lt;li&gt;Kiểm tra các điểm mù&lt;/li&gt;
&lt;li&gt;Có được góc nhìn mới&lt;/li&gt;
&lt;li&gt;Tránh hối tiếc vì quyết định vội vàng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các tình huống cần tạm dừng&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khi nhận được yêu cầu ước tính thời gian&lt;/li&gt;
&lt;li&gt;Khi nhận được tin nhắn gây kích động&lt;/li&gt;
&lt;li&gt;Khi phải trả lời câu hỏi khó trong tình huống căng thẳng&lt;/li&gt;
&lt;li&gt;Khi cần đưa ra quyết định quan trọng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cách thực hiện&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đặt ra quy tắc: &amp;ldquo;Tôi không trả lời ngay lập tức&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Dành thời gian suy nghĩ (vài giờ hoặc vài ngày)&lt;/li&gt;
&lt;li&gt;Nếu không có câu trả lời, hãy nói rõ:
&lt;ul&gt;
&lt;li&gt;Điều gì nằm trong tầm kiểm soát&lt;/li&gt;
&lt;li&gt;Điều gì nằm ngoài tầm kiểm soát&lt;/li&gt;
&lt;li&gt;Các hành động đang được thực hiện&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lợi ích&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đưa ra quyết định tốt hơn&lt;/li&gt;
&lt;li&gt;Tránh hối tiếc&lt;/li&gt;
&lt;li&gt;Giao tiếp rõ ràng và chính xác hơn&lt;/li&gt;
&lt;li&gt;Xây dựng niềm tin với người khác&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết nhấn mạnh rằng việc tạm dừng là một kỹ năng quan trọng trong công việc và cuộc sống, giúp chúng ta tránh được nhiều sai lầm không đáng có.&lt;/p&gt;
&lt;h2 id="aposd-vs-clean-code"&gt;&lt;a class="link" href="https://github.com/johnousterhout/aposd-vs-clean-code/blob/main/README.md" target="_blank" rel="noopener"
&gt;APOSD vs Clean Code&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết ghi lại cuộc thảo luận giữa John Ousterhout (tác giả &amp;ldquo;A Philosophy of Software Design&amp;rdquo;) và Robert Martin (tác giả &amp;ldquo;Clean Code&amp;rdquo;) về những điểm khác biệt trong quan điểm của họ về thiết kế phần mềm. Các điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Độ dài của method&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clean Code: Method nên rất ngắn (2-4 dòng), block trong if/while nên chỉ 1 dòng&lt;/li&gt;
&lt;li&gt;APOSD: Method quá ngắn có thể gây ra vấn đề:
&lt;ul&gt;
&lt;li&gt;Interface nông (shallow): ẩn ít chức năng&lt;/li&gt;
&lt;li&gt;Rối rắm (entanglement): phải đọc nhiều method để hiểu logic&lt;/li&gt;
&lt;li&gt;Không giúp giảm lượng thông tin cần biết&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Comment&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clean Code: Hạn chế comment, code nên tự giải thích&lt;/li&gt;
&lt;li&gt;APOSD: Comment là cần thiết và không thể thay thế:
&lt;ul&gt;
&lt;li&gt;Hoàn thiện thông tin về interface&lt;/li&gt;
&lt;li&gt;Giúp người đọc hiểu ý định của người viết&lt;/li&gt;
&lt;li&gt;Tránh phải suy luận lại kiến thức đã có&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Test-Driven Development (TDD)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clean Code: Ưu tiên viết test trước, phát triển theo từng test nhỏ&lt;/li&gt;
&lt;li&gt;APOSD: TDD có thể gây hại cho thiết kế:
&lt;ul&gt;
&lt;li&gt;Tập trung quá nhiều vào test thay vì thiết kế&lt;/li&gt;
&lt;li&gt;Dễ dẫn đến code spaghetti&lt;/li&gt;
&lt;li&gt;Cần nhiều refactoring để có thiết kế tốt&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Triết lý chung&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clean Code: Tập trung vào các quy tắc cụ thể&lt;/li&gt;
&lt;li&gt;APOSD: Tập trung vào mục tiêu cốt lõi:
&lt;ul&gt;
&lt;li&gt;Giảm độ phức tạp&lt;/li&gt;
&lt;li&gt;Giảm lượng thông tin cần biết&lt;/li&gt;
&lt;li&gt;Làm rõ thông tin quan trọng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết kết luận rằng cả hai tác giả đều có những điểm chung quan trọng, nhưng khác nhau trong cách tiếp cận để đạt được mục tiêu.&lt;/p&gt;
&lt;h2 id="the-software-engineer-spectrum-speed-vs-accuracy"&gt;&lt;a class="link" href="https://benhowdle.im/software-engineer-spectrum" target="_blank" rel="noopener"
&gt;The Software Engineer Spectrum: Speed vs. Accuracy&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích hai phong cách làm việc của kỹ sư phần mềm dựa trên 15 năm kinh nghiệm của tác giả. Các điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phổ làm việc của kỹ sư phần mềm&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Speed-Oriented:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tập trung vào tốc độ và khả năng lặp lại nhanh&lt;/li&gt;
&lt;li&gt;Ưu tiên &amp;ldquo;ship now, improve later&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Phù hợp với startup, hackathon&lt;/li&gt;
&lt;li&gt;Thách thức: tech debt, thiếu edge cases&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Accuracy-Oriented:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tập trung vào tính chính xác và ổn định lâu dài&lt;/li&gt;
&lt;li&gt;Ưu tiên &amp;ldquo;make sure it&amp;rsquo;s right before it goes live&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Phù hợp với enterprise, ngành có quy định&lt;/li&gt;
&lt;li&gt;Thách thức: chậm, có thể over-engineering&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phù hợp với từng giai đoạn công ty&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Startup (0 → 1):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cần tốc độ để validate ý tưởng&lt;/li&gt;
&lt;li&gt;Chấp nhận bug và thiếu hiệu quả&lt;/li&gt;
&lt;li&gt;Phù hợp với speed-oriented engineers&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Scaling (1 → 10):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cần cân bằng giữa tốc độ và ổn định&lt;/li&gt;
&lt;li&gt;Tập trung vào testing và kiến trúc&lt;/li&gt;
&lt;li&gt;Cần engineers có thể nhìn xa hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enterprise (10 → 100):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ưu tiên ổn định và tuân thủ&lt;/li&gt;
&lt;li&gt;Quy trình và quản trị rõ ràng&lt;/li&gt;
&lt;li&gt;Phù hợp với accuracy-oriented engineers&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tự đánh giá bản thân&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bạn có thấy khó chịu với quyết định chậm?&lt;/li&gt;
&lt;li&gt;Bạn có khó chịu khi ship code chưa hoàn hảo?&lt;/li&gt;
&lt;li&gt;Bạn thích môi trường có cấu trúc hay linh hoạt?&lt;/li&gt;
&lt;li&gt;Bạn thích prototype nhanh hay tinh chỉnh hệ thống?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lời khuyên cho leader&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hiểu và tôn trọng cả hai phong cách&lt;/li&gt;
&lt;li&gt;Xây dựng team cân bằng&lt;/li&gt;
&lt;li&gt;Phân công công việc phù hợp với phong cách&lt;/li&gt;
&lt;li&gt;Cho phép engineers phát triển và thay đổi&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết nhấn mạnh rằng không có phong cách nào tốt hơn, mà quan trọng là tìm được môi trường phù hợp với phong cách của mình.&lt;/p&gt;
&lt;h2 id="llm-ecosystem-predictions"&gt;&lt;a class="link" href="https://www.moderndescartes.com/essays/llm_predictions/" target="_blank" rel="noopener"
&gt;LLM Ecosystem Predictions&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết dự đoán về tương lai của hệ sinh thái LLM dựa trên các xu hướng hiện tại. Các điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tập trung vào một số ít công ty&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chi phí LLM giảm nhanh hơn Moore&amp;rsquo;s Law (2x/6 tháng)&lt;/li&gt;
&lt;li&gt;Cải tiến đến từ 3 nguồn:
&lt;ul&gt;
&lt;li&gt;Phần cứng: chip chuyên dụng&lt;/li&gt;
&lt;li&gt;Kỹ thuật: tối ưu hóa hệ thống&lt;/li&gt;
&lt;li&gt;Khoa học: đột phá trong nghiên cứu&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Chỉ các công ty lớn có thể theo kịp tốc độ phát triển&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Simple agents sẽ thắng thế&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tương tự như sự phát triển của phần mềm:
&lt;ul&gt;
&lt;li&gt;Ngôn ngữ bậc cao (Python, JS) thắng C/Java&lt;/li&gt;
&lt;li&gt;Tốc độ lặp lại quan trọng hơn hiệu suất&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Thay vì xây dựng framework phức tạp:
&lt;ul&gt;
&lt;li&gt;Sử dụng LLM mới nhất mỗi 6-12 tháng&lt;/li&gt;
&lt;li&gt;Tập trung vào đánh giá chất lượng&lt;/li&gt;
&lt;li&gt;Loại bỏ các thành phần không cần thiết&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phân hóa DIY vs AI-as-a-Service&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tương tự ngành phần mềm:
&lt;ul&gt;
&lt;li&gt;Managed services phát triển mạnh&lt;/li&gt;
&lt;li&gt;DIY vẫn tồn tại cho người dùng đơn giản&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Excel cho LLM&amp;rdquo; sẽ xuất hiện:
&lt;ul&gt;
&lt;li&gt;Dễ sử dụng cho người ít kỹ thuật&lt;/li&gt;
&lt;li&gt;Tự động hóa quy trình đơn giản&lt;/li&gt;
&lt;li&gt;Phát triển trong 20 năm tới&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chi phí và giá trị đa dạng&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Chi phí mỗi query:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Từ model nhỏ (100M params) đến lớn (1T params)&lt;/li&gt;
&lt;li&gt;Từ text đơn giản đến đa phương tiện&lt;/li&gt;
&lt;li&gt;Từ vài cent đến vài đô la mỗi giờ&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Giá trị mang lại:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thay thế công việc có chi phí cao:
&lt;ul&gt;
&lt;li&gt;Quản lý thông tin ($1000-10000/giờ)&lt;/li&gt;
&lt;li&gt;Gia sư ($50-200/giờ)&lt;/li&gt;
&lt;li&gt;Call center ($10/giờ)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Khả năng mở rộng và linh hoạt:
&lt;ul&gt;
&lt;li&gt;24/7 coverage&lt;/li&gt;
&lt;li&gt;Chất lượng đồng nhất&lt;/li&gt;
&lt;li&gt;Triển khai toàn cầu nhanh chóng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết kết luận rằng thế giới năm 2030 sẽ thay đổi mạnh mẽ nhờ LLM, tương tự như sự thay đổi của điện thoại di động và Internet trong những thập kỷ trước.&lt;/p&gt;
&lt;h2 id="the-right-kind-of-stubborn"&gt;&lt;a class="link" href="https://www.paulgraham.com/persistence.html" target="_blank" rel="noopener"
&gt;The Right Kind of Stubborn&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích sự khác biệt giữa sự kiên trì (persistence) và sự bướng bỉnh (obstinacy) trong việc giải quyết vấn đề. Các điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sự khác biệt cốt lõi&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kiên trì: Gắn bó với mục tiêu, sẵn sàng thay đổi cách tiếp cận&lt;/li&gt;
&lt;li&gt;Bướng bỉnh: Gắn bó với ý tưởng ban đầu, không muốn thay đổi&lt;/li&gt;
&lt;li&gt;Người kiên trì lắng nghe phản hồi, người bướng bỉnh bỏ qua&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cấu trúc của sự kiên trì&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Năng lượng: Không ngừng thử nghiệm&lt;/li&gt;
&lt;li&gt;Trí tưởng tượng: Tìm ra cách tiếp cận mới&lt;/li&gt;
&lt;li&gt;Khả năng phục hồi: Vượt qua thất bại&lt;/li&gt;
&lt;li&gt;Phán đoán tốt: Đánh giá giá trị kỳ vọng&lt;/li&gt;
&lt;li&gt;Mục tiêu rõ ràng: Định hướng nỗ lực&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tại sao bướng bỉnh không hiệu quả&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bám víu vào ý tưởng đầu tiên, ít thông tin nhất&lt;/li&gt;
&lt;li&gt;Không lắng nghe phản hồi&lt;/li&gt;
&lt;li&gt;Chỉ hoạt động với vấn đề đơn giản&lt;/li&gt;
&lt;li&gt;Có thể thành công nhờ may mắn hoặc bù trừ lỗi khác&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cách phát triển sự kiên trì&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bắt đầu với mục tiêu nhỏ&lt;/li&gt;
&lt;li&gt;Mở rộng dần khi đã có tiến bộ&lt;/li&gt;
&lt;li&gt;Chấp nhận thay đổi ở các quyết định nhỏ&lt;/li&gt;
&lt;li&gt;Giữ vững mục tiêu lớn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết kết luận rằng sự kiên trì đúng cách là sự kết hợp hiếm có của 5 phẩm chất, mang lại kết quả vượt trội so với sự bướng bỉnh đơn thuần.&lt;/p&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/ae95d38c-41f8-4eb7-885e-f7fafa4ca45d_2250x2624.png"
loading="lazy"
alt="Data Consistency Strategies For Microservices"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #10</title><link>https://miti99.com/post/2025/04/05/</link><pubDate>Sat, 05 Apr 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/04/05/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #10.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="gaining-years-of-experience-in-a-few-months"&gt;&lt;a class="link" href="https://marcgg.com/blog/2025/02/11/high-growth" target="_blank" rel="noopener"
&gt;Gaining Years of Experience in a Few Months&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Marc G. Gauthier chia sẻ về cách đạt được nhiều năm kinh nghiệm trong một thời gian ngắn thông qua các dự án thách thức. Đây là một góc nhìn thú vị về sự phát triển nhanh trong sự nghiệp công nghệ.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các vùng phát triển:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vùng thoải mái (Comfort Zone): An toàn nhưng có nguy cơ tụt hậu&lt;/li&gt;
&lt;li&gt;Vùng học tập (Learning Zone): Phát triển bền vững và ổn định&lt;/li&gt;
&lt;li&gt;Vùng tăng trưởng nhanh (Fast Growth Zone): Đạt được nhiều năm kinh nghiệm trong thời gian ngắn&lt;/li&gt;
&lt;li&gt;Vùng kiệt sức (Burnout Zone): Hậu quả của việc ở quá lâu trong vùng tăng trưởng nhanh&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chu kỳ phát triển:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Học tập &amp;lt;-&amp;gt; Tăng trưởng: Duy trì học tập liên tục, tận dụng cơ hội&lt;/li&gt;
&lt;li&gt;Học tập -&amp;gt; Tăng trưởng -&amp;gt; Thoải mái -&amp;gt; Quay lại học tập: Sử dụng thời gian thoải mái để phục hồi&lt;/li&gt;
&lt;li&gt;Thoải mái &amp;lt;-&amp;gt; Học tập: Cho phép nghỉ ngơi nhưng không nên ở quá lâu&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kinh nghiệm cá nhân:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trải nghiệm từ việc Drivy được mua lại bởi Getaround&lt;/li&gt;
&lt;li&gt;Phải giải quyết nhiều vấn đề phức tạp cùng lúc&lt;/li&gt;
&lt;li&gt;Áp lực cao và deadline gấp&lt;/li&gt;
&lt;li&gt;Đạt được nhiều thành tựu trong thời gian ngắn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Điều kiện để tăng trưởng nhanh:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cơ hội thách thức bản thân&lt;/li&gt;
&lt;li&gt;Môi trường phù hợp&lt;/li&gt;
&lt;li&gt;Sức khỏe và năng lượng tốt&lt;/li&gt;
&lt;li&gt;Hỗ trợ từ gia đình và đồng nghiệp&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lưu ý quan trọng:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không nên duy trì tăng trưởng nhanh quá lâu&lt;/li&gt;
&lt;li&gt;Cần cân bằng giữa phát triển và sức khỏe&lt;/li&gt;
&lt;li&gt;Tận dụng cơ hội khi có thể&lt;/li&gt;
&lt;li&gt;Biết khi nào cần nghỉ ngơi và phục hồi&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="writing-better-commit-messages"&gt;&lt;a class="link" href="https://refactoringenglish.com/chapters/commit-messages/" target="_blank" rel="noopener"
&gt;Writing Better Commit Messages&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Michael Lynch chia sẻ về cách viết commit message hiệu quả và dễ hiểu. Đây là một hướng dẫn chi tiết giúp cải thiện chất lượng commit message trong quá trình phát triển phần mềm.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cấu trúc cơ bản:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Subject line ngắn gọn, rõ ràng (dưới 50 ký tự)&lt;/li&gt;
&lt;li&gt;Body message chi tiết (wrap ở 72 ký tự)&lt;/li&gt;
&lt;li&gt;Sử dụng thì hiện tại đơn (imperative mood)&lt;/li&gt;
&lt;li&gt;Không cần dấu chấm ở cuối subject line&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nội dung quan trọng:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giải thích WHY thay vì WHAT&lt;/li&gt;
&lt;li&gt;Mô tả context của thay đổi&lt;/li&gt;
&lt;li&gt;Liên kết đến issues hoặc tickets liên quan&lt;/li&gt;
&lt;li&gt;Ghi chú về side effects nếu có&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Best Practices:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mỗi commit một mục đích&lt;/li&gt;
&lt;li&gt;Tách commits logic và format&lt;/li&gt;
&lt;li&gt;Sử dụng các prefix chuẩn (fix:, feat:, etc.)&lt;/li&gt;
&lt;li&gt;Review commit message trước khi push&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các lỗi thường gặp:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Message quá ngắn hoặc không rõ ràng&lt;/li&gt;
&lt;li&gt;Không giải thích lý do thay đổi&lt;/li&gt;
&lt;li&gt;Mix nhiều thay đổi không liên quan&lt;/li&gt;
&lt;li&gt;Sử dụng ngôn ngữ không chuyên nghiệp&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tools và Conventions:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng Conventional Commits&lt;/li&gt;
&lt;li&gt;Tích hợp commit hooks để validate&lt;/li&gt;
&lt;li&gt;Dùng tools như commitlint&lt;/li&gt;
&lt;li&gt;Template cho commit message&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="the-rotation-program-that-keeps-this-startup"&gt;&lt;a class="link" href="https://review.firstround.com/the-rotation-program-that-keeps-this-startups-engineers-learning-and-not-leaving/" target="_blank" rel="noopener"
&gt;The Rotation Program That Keeps This Startup&amp;rsquo;s Engineers Learning — and Not Leaving&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ về chương trình luân chuyển nhân sự (rotation program) tại Checkr, một startup đã giúp giữ chân kỹ sư bằng cách tạo cơ hội học hỏi và phát triển liên tục. Đây là một case study thú vị về cách xây dựng văn hóa học tập và phát triển trong công ty công nghệ.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lý do triển khai chương trình:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giảm tỷ lệ nhân viên nghỉ việc (attrition rate gần 0%)&lt;/li&gt;
&lt;li&gt;Tạo cơ hội học hỏi liên tục cho kỹ sư&lt;/li&gt;
&lt;li&gt;Giữ chân nhân tài có kinh nghiệm&lt;/li&gt;
&lt;li&gt;Tận dụng kiến thức chuyên môn trong nội bộ&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cách triển khai:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cho phép kỹ sư làm việc tạm thời ở các team khác&lt;/li&gt;
&lt;li&gt;Tập trung vào các dự án ưu tiên của công ty&lt;/li&gt;
&lt;li&gt;Kết hợp với quá trình phát triển nghề nghiệp&lt;/li&gt;
&lt;li&gt;Duy trì sự cân bằng giữa ổn định và luân chuyển&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quy trình quản lý:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Theo dõi và đánh giá hiệu quả của mỗi kỹ sư&lt;/li&gt;
&lt;li&gt;Đảm bảo mỗi team có &amp;ldquo;anchor people&amp;rdquo; ổn định&lt;/li&gt;
&lt;li&gt;Kiểm soát số lượng người luân chuyển cùng lúc&lt;/li&gt;
&lt;li&gt;Đánh giá nhu cầu thực tế của dự án&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thách thức và giải pháp:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quản lý lo ngại về việc mất nhân sự chủ chốt&lt;/li&gt;
&lt;li&gt;Xây dựng niềm tin giữa các team&lt;/li&gt;
&lt;li&gt;Tuyển dụng người có tinh thần hợp tác&lt;/li&gt;
&lt;li&gt;Tập trung vào phát triển toàn diện&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kết quả và bài học:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;60% kỹ sư cấp cao ở lại hơn 6 năm&lt;/li&gt;
&lt;li&gt;Tăng khả năng thích ứng với thay đổi&lt;/li&gt;
&lt;li&gt;Phát triển kỹ năng đa dạng cho nhân viên&lt;/li&gt;
&lt;li&gt;Xây dựng văn hóa học tập liên tục&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="judge-your-coworkers"&gt;&lt;a class="link" href="https://blog.staysaasy.com/p/judge-your-coworkers" target="_blank" rel="noopener"
&gt;Judge Your Coworkers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Stay SaaSy thảo luận về tầm quan trọng của việc đánh giá đồng nghiệp một cách xây dựng trong môi trường công ty. Đây là một góc nhìn thú vị về cách xây dựng văn hóa trách nhiệm và phát triển trong tổ chức.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tại sao cần đánh giá đồng nghiệp:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hiểu rõ công việc của nhau để hợp tác hiệu quả&lt;/li&gt;
&lt;li&gt;Quan trọng với vai trò lãnh đạo và team cross-functional&lt;/li&gt;
&lt;li&gt;Cần thiết để phát hiện và xử lý vấn đề hiệu suất&lt;/li&gt;
&lt;li&gt;Giúp học hỏi và phát triển từ nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quy tắc cơ bản:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không công khai chỉ trích đồng nghiệp&lt;/li&gt;
&lt;li&gt;Feedback được chia sẻ riêng tư với quản lý&lt;/li&gt;
&lt;li&gt;Theo dõi và xử lý vấn đề một cách kín đáo&lt;/li&gt;
&lt;li&gt;Không mong đợi đồng nghiệp hoàn hảo&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cách thực hiện hiệu quả:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thiết lập kỳ vọng về việc đánh giá đồng nghiệp&lt;/li&gt;
&lt;li&gt;Hỏi ý kiến định kỳ về hiệu suất của đồng nghiệp&lt;/li&gt;
&lt;li&gt;Tận dụng các cuộc trò chuyện để dạy và học&lt;/li&gt;
&lt;li&gt;Hiểu rõ vai trò và trách nhiệm của nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xử lý các tình huống:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khi đồng nghiệp làm tốt: Học hỏi từ thành công của họ&lt;/li&gt;
&lt;li&gt;Khi có vấn đề: Tìm hiểu nguyên nhân và hỗ trợ cải thiện&lt;/li&gt;
&lt;li&gt;Khi có hiểu lầm: Làm rõ vai trò và kỳ vọng&lt;/li&gt;
&lt;li&gt;Khi cần hỗ trợ: Bù đắp điểm yếu của nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lưu ý quan trọng:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tránh văn hóa &amp;ldquo;không đổ lỗi&amp;rdquo; thái quá&lt;/li&gt;
&lt;li&gt;Lãnh đạo cấp cao cần có quan điểm về hiệu suất đồng nghiệp&lt;/li&gt;
&lt;li&gt;Tận dụng cơ hội học hỏi về vai trò khác&lt;/li&gt;
&lt;li&gt;Cân bằng giữa trách nhiệm và phát triển&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="my-llm-codegen-workflow-atm"&gt;&lt;a class="link" href="https://harper.blog/2025/02/16/my-llm-codegen-workflow-atm/" target="_blank" rel="noopener"
&gt;My LLM Codegen Workflow ATM&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Harper Reed chia sẻ về quy trình làm việc hiệu quả với LLM để tạo code. Đây là một hướng dẫn chi tiết về cách tận dụng AI để phát triển phần mềm nhanh và hiệu quả.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quy trình làm việc cơ bản:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Brainstorm và lập kế hoạch chi tiết&lt;/li&gt;
&lt;li&gt;Chia nhỏ các bước thực hiện&lt;/li&gt;
&lt;li&gt;Thực thi từng bước với LLM&lt;/li&gt;
&lt;li&gt;Kiểm tra và debug kết quả&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Công cụ và môi trường:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng Claude, Aider và các công cụ codegen khác&lt;/li&gt;
&lt;li&gt;Thiết lập môi trường phát triển phù hợp&lt;/li&gt;
&lt;li&gt;Tích hợp với các công cụ quản lý code&lt;/li&gt;
&lt;li&gt;Tự động hóa các quy trình lặp lại&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược hiệu quả:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tập trung vào các bước nhỏ, có thể kiểm soát&lt;/li&gt;
&lt;li&gt;Duy trì kiểm soát tiến trình&lt;/li&gt;
&lt;li&gt;Tận dụng thời gian chờ để làm việc khác&lt;/li&gt;
&lt;li&gt;Cân bằng giữa tự động hóa và kiểm soát&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xử lý các thách thức:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quản lý context và trạng thái&lt;/li&gt;
&lt;li&gt;Xử lý các lỗi và vấn đề phát sinh&lt;/li&gt;
&lt;li&gt;Tối ưu hóa quy trình làm việc&lt;/li&gt;
&lt;li&gt;Duy trì chất lượng code&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lưu ý quan trọng:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cần có kế hoạch rõ ràng trước khi bắt đầu&lt;/li&gt;
&lt;li&gt;Kiểm soát tiến trình để tránh &amp;ldquo;over your skis&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Tận dụng thời gian chờ hiệu quả&lt;/li&gt;
&lt;li&gt;Cân nhắc về tác động môi trường của LLM&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="structured-logging-in-spring-boot"&gt;&lt;a class="link" href="https://www.javacodegeeks.com/structured-logging-in-spring-boot.html" target="_blank" rel="noopener"
&gt;Structured Logging in Spring Boot&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Yatin Batra chia sẻ về cách triển khai structured logging trong Spring Boot. Đây là một hướng dẫn chi tiết về cách cải thiện khả năng theo dõi và debug ứng dụng thông qua logging có cấu trúc.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tại sao cần Structured Logging:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tăng khả năng đọc và phân tích log&lt;/li&gt;
&lt;li&gt;Dễ dàng tìm kiếm và lọc thông tin&lt;/li&gt;
&lt;li&gt;Tích hợp tốt với các công cụ monitoring&lt;/li&gt;
&lt;li&gt;Hỗ trợ debug hiệu quả hơn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cấu hình cơ bản:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng Logstash Logback Encoder&lt;/li&gt;
&lt;li&gt;Cấu hình logback-spring.xml&lt;/li&gt;
&lt;li&gt;Định dạng log theo JSON&lt;/li&gt;
&lt;li&gt;Tích hợp với SLF4J&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tính năng nâng cao:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thêm trường tùy chỉnh vào log&lt;/li&gt;
&lt;li&gt;Tích hợp với Logstash&lt;/li&gt;
&lt;li&gt;Cấu hình cho Loki&lt;/li&gt;
&lt;li&gt;Sử dụng MDC cho metadata&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chuẩn ECS và GELF:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Elastic Common Schema cho Elastic Stack&lt;/li&gt;
&lt;li&gt;Graylog Extended Log Format&lt;/li&gt;
&lt;li&gt;So sánh và lựa chọn phù hợp&lt;/li&gt;
&lt;li&gt;Tích hợp với các hệ thống khác&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Best Practices:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cấu hình phù hợp cho môi trường&lt;/li&gt;
&lt;li&gt;Quản lý hiệu suất logging&lt;/li&gt;
&lt;li&gt;Xử lý lỗi và exception&lt;/li&gt;
&lt;li&gt;Bảo mật thông tin nhạy cảm&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="secret-java-stream-hacks-that-will-instantly-improve-your-coding-efficiency"&gt;&lt;a class="link" href="https://gainjavaknowledge.medium.com/secret-java-stream-hacks-that-will-instantly-improve-your-coding-efficiency-8253d57d692b" target="_blank" rel="noopener"
&gt;Secret Java Stream Hacks That Will Instantly Improve Your Coding Efficiency&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Gain Java Knowledge chia sẻ về các thủ thuật hữu ích khi sử dụng Java Stream API. Đây là một hướng dẫn chi tiết về cách tận dụng tối đa sức mạnh của Stream để cải thiện hiệu quả code.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Collectors.teeing():&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Xử lý dữ liệu theo hai cách khác nhau cùng lúc&lt;/li&gt;
&lt;li&gt;Kết hợp kết quả từ hai collector&lt;/li&gt;
&lt;li&gt;Tránh phải duyệt stream nhiều lần&lt;/li&gt;
&lt;li&gt;Ví dụ: Tính trung bình và tổng cùng lúc&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;takeWhile() và dropWhile():&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lấy phần tử cho đến khi điều kiện sai&lt;/li&gt;
&lt;li&gt;Bỏ qua phần tử khi điều kiện đúng&lt;/li&gt;
&lt;li&gt;Đơn giản hóa việc lọc có điều kiện&lt;/li&gt;
&lt;li&gt;Tối ưu hiệu suất xử lý&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các thủ thuật nâng cao:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng parallel streams hiệu quả&lt;/li&gt;
&lt;li&gt;Tối ưu hóa memory usage&lt;/li&gt;
&lt;li&gt;Xử lý exception trong streams&lt;/li&gt;
&lt;li&gt;Kết hợp nhiều operation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Best Practices:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chọn đúng collector cho từng trường hợp&lt;/li&gt;
&lt;li&gt;Tránh side effects trong stream operations&lt;/li&gt;
&lt;li&gt;Sử dụng method references khi có thể&lt;/li&gt;
&lt;li&gt;Kiểm soát độ phức tạp của stream&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lưu ý quan trọng:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hiểu rõ lazy evaluation&lt;/li&gt;
&lt;li&gt;Cân nhắc hiệu suất với large datasets&lt;/li&gt;
&lt;li&gt;Debug và maintain code dễ dàng&lt;/li&gt;
&lt;li&gt;Tích hợp với các tính năng Java khác&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="death-of-a-thousand-nits-code-review-best-practices"&gt;&lt;a class="link" href="https://bitfieldconsulting.com/posts/code-review" target="_blank" rel="noopener"
&gt;Death of a Thousand Nits: Code Review Best Practices&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của John Arundel chia sẻ về cách thực hiện code review hiệu quả và thân thiện. Đây là một hướng dẫn chi tiết về cách xây dựng văn hóa review code tích cực trong team.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pair Review thay vì Review qua Text:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Giao tiếp trực tiếp hiệu quả hơn&lt;/li&gt;
&lt;li&gt;Giảm thiểu hiểu lầm và xung đột&lt;/li&gt;
&lt;li&gt;Tăng tốc độ review và merge&lt;/li&gt;
&lt;li&gt;Xây dựng mối quan hệ tốt trong team&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cách đưa ra phản hồi hiệu quả:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tập trung vào việc thêm giá trị&lt;/li&gt;
&lt;li&gt;Tránh chỉ trích về style&lt;/li&gt;
&lt;li&gt;Đặt câu hỏi thay vì phê bình&lt;/li&gt;
&lt;li&gt;Sử dụng ngôn ngữ tích cực&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xử lý các tình huống khác nhau:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khi không hiểu code: Tìm hiểu trước khi hỏi&lt;/li&gt;
&lt;li&gt;Khi có đề xuất: Đưa ra dưới dạng gợi ý&lt;/li&gt;
&lt;li&gt;Khi phát hiện lỗi: Giải thích nhẹ nhàng&lt;/li&gt;
&lt;li&gt;Khi nhận feedback: Lắng nghe và học hỏi&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Best Practices:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bắt đầu với những điểm tích cực&lt;/li&gt;
&lt;li&gt;Kết thúc với lời động viên&lt;/li&gt;
&lt;li&gt;Tập trung vào giá trị thực sự&lt;/li&gt;
&lt;li&gt;Tránh nitpicking không cần thiết&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xây dựng văn hóa review:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Làm gương cho team&lt;/li&gt;
&lt;li&gt;Tạo môi trường an toàn&lt;/li&gt;
&lt;li&gt;Khuyến khích học hỏi lẫn nhau&lt;/li&gt;
&lt;li&gt;Duy trì mối quan hệ tốt&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="hash-functions-deep-dive"&gt;&lt;a class="link" href="https://www.kirupa.com/data_structures_algorithms/hash_functions_deep_dive.htm" target="_blank" rel="noopener"
&gt;Hash Functions Deep Dive&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Kirupa đi sâu vào phân tích về hash functions và cách chúng hoạt động. Đây là một hướng dẫn chi tiết về một khái niệm quan trọng trong khoa học máy tính.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định nghĩa và Mục đích:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hash function là hàm toán học chuyển đổi input thành output&lt;/li&gt;
&lt;li&gt;Input có thể là bất kỳ dữ liệu số nào (text, file, binary data)&lt;/li&gt;
&lt;li&gt;Output luôn có độ dài cố định&lt;/li&gt;
&lt;li&gt;Được sử dụng trong nhiều lĩnh vực: lưu trữ dữ liệu, xác thực mật khẩu, kiểm tra tính toàn vẹn file&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tiêu chí của một Hash Function tốt:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deterministic: Cùng input luôn cho cùng output&lt;/li&gt;
&lt;li&gt;Uniform Distribution: Phân bố đều các giá trị hash&lt;/li&gt;
&lt;li&gt;Fast Computation: Tính toán nhanh (O(1))&lt;/li&gt;
&lt;li&gt;Avalanche Effect: Thay đổi nhỏ trong input tạo thay đổi lớn trong output&lt;/li&gt;
&lt;li&gt;Fixed Output Size: Output luôn có độ dài cố định&lt;/li&gt;
&lt;li&gt;Low Collision Rate: Tỷ lệ va chạm thấp&lt;/li&gt;
&lt;li&gt;Non-Reversible: Khó tìm lại input từ output&lt;/li&gt;
&lt;li&gt;No Correlation: Không có mối liên hệ giữa input và output tương tự&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ví dụ về Hash Function đơn giản:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cộng mã ASCII của các ký tự&lt;/li&gt;
&lt;li&gt;Sử dụng số nguyên tố để giảm va chạm&lt;/li&gt;
&lt;li&gt;Dễ hiểu nhưng không đủ mạnh cho thực tế&lt;/li&gt;
&lt;li&gt;Chỉ phù hợp cho mục đích học tập&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MD5 Hash Function:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Output 32 ký tự hex (128 bits)&lt;/li&gt;
&lt;li&gt;Thay đổi nhỏ trong input tạo thay đổi lớn trong output&lt;/li&gt;
&lt;li&gt;Được sử dụng rộng rãi trong nhiều ứng dụng&lt;/li&gt;
&lt;li&gt;Có một số điểm yếu về bảo mật&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ứng dụng thực tế:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bảo vệ mật khẩu&lt;/li&gt;
&lt;li&gt;Kiểm tra tính toàn vẹn file&lt;/li&gt;
&lt;li&gt;Tạo chữ ký số&lt;/li&gt;
&lt;li&gt;Tối ưu hóa hiệu suất cấu trúc dữ liệu&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="xor-a-deep-dive-into-the-exclusive-or-operation"&gt;&lt;a class="link" href="https://www.chiark.greenend.org.uk/~sgtatham/quasiblog/xor/" target="_blank" rel="noopener"
&gt;XOR: A Deep Dive into the Exclusive OR Operation&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Simon Tatham đi sâu vào phân tích về phép toán XOR và các ứng dụng của nó. Đây là một hướng dẫn chi tiết về một phép toán cơ bản nhưng quan trọng trong khoa học máy tính.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định nghĩa và Tính chất cơ bản:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;XOR là phép toán &amp;ldquo;Exclusive OR&amp;rdquo; (hoặc loại trừ)&lt;/li&gt;
&lt;li&gt;Kết quả là 1 khi hai bit đầu vào khác nhau&lt;/li&gt;
&lt;li&gt;Kết quả là 0 khi hai bit đầu vào giống nhau&lt;/li&gt;
&lt;li&gt;Có tính chất giao hoán và kết hợp&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các cách hiểu về XOR:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phép so sánh &amp;ldquo;không bằng&amp;rdquo; giữa hai bit&lt;/li&gt;
&lt;li&gt;Phép đảo bit có điều kiện&lt;/li&gt;
&lt;li&gt;Phép cộng modulo 2&lt;/li&gt;
&lt;li&gt;Phép tính chẵn lẻ của số bit 1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ứng dụng trong mật mã học:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kết hợp plaintext với keystream&lt;/li&gt;
&lt;li&gt;Tạo mã hóa đơn giản và hiệu quả&lt;/li&gt;
&lt;li&gt;Sử dụng trong các hệ thống mã hóa phức tạp&lt;/li&gt;
&lt;li&gt;Bảo vệ tính toàn vẹn dữ liệu&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ứng dụng trong đồ họa:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vẽ và xóa pixel dễ dàng&lt;/li&gt;
&lt;li&gt;Tạo hiệu ứng đặc biệt&lt;/li&gt;
&lt;li&gt;Tối ưu hóa bộ nhớ&lt;/li&gt;
&lt;li&gt;Xử lý hình ảnh hiệu quả&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các ứng dụng thực tế khác:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hoán đổi giá trị hai biến không cần biến tạm&lt;/li&gt;
&lt;li&gt;Tính trung bình hai số nguyên&lt;/li&gt;
&lt;li&gt;Thực hiện phép cộng không nhớ&lt;/li&gt;
&lt;li&gt;Giải quyết các bài toán tối ưu hóa&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/6b437484-1fd8-4b59-ba05-46bb3352b053_2904x2559.jpeg"
loading="lazy"
alt="SOAP vs REST vs GraphQL vs RPC"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/3ecf2600-10d8-4180-8328-8d790fbba0cc_1280x1557.gif"
loading="lazy"
alt="SQS vs SNS vs EventBridge vs Kinesis"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/217bf342-bfd4-4088-bba3-b2734f065a20_1280x1280.gif"
loading="lazy"
alt="Top 5 common ways to improve API performance"
&gt;&lt;/p&gt;
&lt;h2 id="bonus-2-vài-video-hay-ho-đến-từ-inside-java"&gt;Bonus 2: Vài video hay ho đến từ &lt;a class="link" href="https://inside.java/" target="_blank" rel="noopener"
&gt;Inside Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://inside.java/2025/02/22/devoxxbelgium-loom-next/" target="_blank" rel="noopener"
&gt;Project Loom and Virtual Threads: Next Phases&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Newsletter #9</title><link>https://miti99.com/post/2025/04/01/</link><pubDate>Tue, 01 Apr 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/04/01/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #9.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="to-avoid-being-replaced-by-llms-do-what-they-can"&gt;&lt;a class="link" href="https://www.seangoedecke.com/what-llms-cant-do/" target="_blank" rel="noopener"
&gt;To avoid being replaced by LLMs, do what they can&amp;rsquo;t&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Sean Goedecke phân tích về những gì LLMs không thể làm và cách các kỹ sư phần mềm có thể chuẩn bị cho tương lai khi AI ngày càng phát triển. Đây là một góc nhìn thú vị về tương lai của nghề kỹ sư phần mềm.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ngắn hạn: Học AI và thăng tiến&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tận dụng các công cụ AI&lt;/li&gt;
&lt;li&gt;Hiểu về nguyên lý cơ bản của language models&lt;/li&gt;
&lt;li&gt;Thăng tiến vì các vị trí junior sẽ bị thay thế trước&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Trung hạn: Tập trung vào legacy code&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LLMs giỏi ở các bài toán:
&lt;ul&gt;
&lt;li&gt;Được định nghĩa rõ ràng&lt;/li&gt;
&lt;li&gt;Có phạm vi hẹp&lt;/li&gt;
&lt;li&gt;Dễ kiểm tra kết quả&lt;/li&gt;
&lt;li&gt;Ít code&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Legacy code ngược lại:
&lt;ul&gt;
&lt;li&gt;Vấn đề không rõ ràng&lt;/li&gt;
&lt;li&gt;Khó kiểm tra kết quả&lt;/li&gt;
&lt;li&gt;Khối lượng code lớn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;LLMs sẽ gặp khó khăn với legacy code vì:
&lt;ul&gt;
&lt;li&gt;Cần giải quyết vấn đề large context&lt;/li&gt;
&lt;li&gt;Khó viết eval tốt&lt;/li&gt;
&lt;li&gt;Dữ liệu phân tán ở nhiều nơi&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dài hạn: Chịu trách nhiệm&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kỹ sư không chỉ viết code mà còn phải được tin tưởng&lt;/li&gt;
&lt;li&gt;LLMs không thể chịu trách nhiệm vì:
&lt;ul&gt;
&lt;li&gt;Không có &amp;ldquo;skin in the game&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Không thể xây dựng lòng tin với management&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Các công ty sẽ luôn cần ít nhất một kỹ sư để:
&lt;ul&gt;
&lt;li&gt;Giám sát LLMs&lt;/li&gt;
&lt;li&gt;Chuyển đổi cam kết của LLMs thành cam kết con người&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="how-instagram-scaled-its-infrastructure-to-support-a-billion-users"&gt;&lt;a class="link" href="https://blog.bytebytego.com/p/how-instagram-scaled-its-infrastructure" target="_blank" rel="noopener"
&gt;How Instagram Scaled Its Infrastructure To Support a Billion Users&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích chi tiết cách Instagram đã scale infrastructure của họ để hỗ trợ hơn 1 tỷ người dùng. Đây là một case study thú vị về việc scale một ứng dụng từ startup nhỏ thành một nền tảng toàn cầu.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thách thức ban đầu:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Instagram khởi đầu với 13 nhân viên và infrastructure đơn giản trên AWS&lt;/li&gt;
&lt;li&gt;Gặp nhiều vấn đề về performance và scaling khi user base tăng nhanh&lt;/li&gt;
&lt;li&gt;Phải scale thủ công trước các sự kiện lớn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chiến lược scale 3 chiều:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scale out: Thêm servers và data centers&lt;/li&gt;
&lt;li&gt;Scale up: Tối ưu hiệu suất của mỗi server&lt;/li&gt;
&lt;li&gt;Scale engineering: Tự động hóa và cải thiện quy trình phát triển&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kiến trúc hệ thống:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng Django làm web framework&lt;/li&gt;
&lt;li&gt;PostgreSQL cho structured data&lt;/li&gt;
&lt;li&gt;Cassandra cho distributed data&lt;/li&gt;
&lt;li&gt;Memcached cho caching&lt;/li&gt;
&lt;li&gt;RabbitMQ và Celery cho async processing&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các giải pháp kỹ thuật quan trọng:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Memcache Lease mechanism để tránh thundering herd problem&lt;/li&gt;
&lt;li&gt;Continuous deployment với canary testing&lt;/li&gt;
&lt;li&gt;Monitoring và profiling CPU usage&lt;/li&gt;
&lt;li&gt;Distributed storage với Haystack&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bài học rút ra:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scale không chỉ là thêm hardware mà còn cần tối ưu resources&lt;/li&gt;
&lt;li&gt;Tự động hóa là chìa khóa để scale engineering team&lt;/li&gt;
&lt;li&gt;Cần balance giữa consistency và performance&lt;/li&gt;
&lt;li&gt;Monitoring và observability là cực kỳ quan trọng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="the-state-of-scala--clojure-surveys"&gt;&lt;a class="link" href="https://www.jvm-weekly.com/p/the-state-of-scala-and-clojure-surveys" target="_blank" rel="noopener"
&gt;The State of Scala &amp;amp; Clojure Surveys&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích kết quả của hai cuộc khảo sát về tình trạng của Scala và Clojure trong năm 2024. Đây là một góc nhìn thú vị về tương lai của functional programming trên JVM.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tình trạng Scala:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;232 người tham gia khảo sát, 75% là Software Engineers&lt;/li&gt;
&lt;li&gt;93.1% thích hoặc yêu thích Scala&lt;/li&gt;
&lt;li&gt;Tuổi trung bình của dự án là 7 năm&lt;/li&gt;
&lt;li&gt;Các ecosystem phổ biến: Typelevel (41.8%), Akka (35.3%), ZIO (23.3%)&lt;/li&gt;
&lt;li&gt;53% dự án kết hợp nhiều ecosystem khác nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thách thức của Scala:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thời gian biên dịch chậm (1/3 người dùng gặp vấn đề)&lt;/li&gt;
&lt;li&gt;Ecosystem bị phân mảnh và khó migrate lên Scala 3&lt;/li&gt;
&lt;li&gt;Thiếu nguồn lực để maintain các dự án cũ&lt;/li&gt;
&lt;li&gt;23.2% công ty đang cân nhắc chuyển sang Kotlin, Rust hoặc Go&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề tuyển dụng:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;56.5% không biết tìm Scala developers ở đâu&lt;/li&gt;
&lt;li&gt;40.5% cho rằng Scala làm chậm quá trình onboarding&lt;/li&gt;
&lt;li&gt;68.6% cho phép làm việc từ xa để dễ tuyển dụng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tình trạng Clojure:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;73% người dùng sử dụng Clojure trong công việc&lt;/li&gt;
&lt;li&gt;Phổ biến trong web development và enterprise applications&lt;/li&gt;
&lt;li&gt;58% đã migrate lên Clojure 1.12&lt;/li&gt;
&lt;li&gt;54% sử dụng Java 21 LTS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Các Clojure dialects mới:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Babashka (93% người dùng dialects)&lt;/li&gt;
&lt;li&gt;ClojureDart cho web và mobile&lt;/li&gt;
&lt;li&gt;Squint, Jank, và Cherry&lt;/li&gt;
&lt;li&gt;Thách thức cho người mới: hiểu macros và &amp;ldquo;homoiconicity&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="linkedin-integrates-protocol-buffers-with-restli-for-improved-microservices-performance"&gt;&lt;a class="link" href="https://www.linkedin.com/blog/engineering/infrastructure/linkedin-integrates-protocol-buffers-with-rest-li-for-improved-m" target="_blank" rel="noopener"
&gt;LinkedIn Integrates Protocol Buffers With Rest.li for Improved Microservices Performance&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ về việc LinkedIn đã tích hợp Protocol Buffers (Protobuf) vào framework Rest.li của họ để cải thiện hiệu suất của microservices. Đây là một case study thú vị về việc tối ưu performance ở quy mô lớn.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề với JSON:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JSON là format text nên tốn nhiều bandwidth&lt;/li&gt;
&lt;li&gt;Serialization/deserialization chậm&lt;/li&gt;
&lt;li&gt;Tốn tài nguyên khi sử dụng với garbage collected languages&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giải pháp với Protocol Buffers:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Compact payload size giúp giảm bandwidth&lt;/li&gt;
&lt;li&gt;Hiệu suất serialization/deserialization cao&lt;/li&gt;
&lt;li&gt;Hỗ trợ nhiều ngôn ngữ lập trình&lt;/li&gt;
&lt;li&gt;Dễ dàng tích hợp với Rest.li&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cách triển khai:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng symbol tables để map giữa PDL fields và Protobuf field numbers&lt;/li&gt;
&lt;li&gt;Tự động generate symbol tables khi service khởi động&lt;/li&gt;
&lt;li&gt;Cache symbol tables ở client side&lt;/li&gt;
&lt;li&gt;Rollout từng bước với client configurations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kết quả:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tăng throughput 6.25% cho response payloads&lt;/li&gt;
&lt;li&gt;Tăng throughput 1.77% cho request payloads&lt;/li&gt;
&lt;li&gt;Giảm latency tới 60% cho các service có payload lớn&lt;/li&gt;
&lt;li&gt;Không có degradation đáng kể so với JSON&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kế hoạch tương lai:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chuyển dần từ Rest.li sang gRPC&lt;/li&gt;
&lt;li&gt;Tận dụng các tính năng mới như streaming&lt;/li&gt;
&lt;li&gt;Tận dụng cộng đồng open source lớn của gRPC&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="story-redis-and-its-creator-antirez"&gt;&lt;a class="link" href="https://blog.brachiosoft.com/en/posts/redis/" target="_blank" rel="noopener"
&gt;Story: Redis and its creator antirez&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết kể về câu chuyện thú vị của Redis và người sáng tạo Salvatore Sanfilippo (antirez). Đây là một câu chuyện về sự đổi mới và tầm nhìn trong thế giới công nghệ.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Con đường đến với lập trình:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bắt đầu với máy tính TI99/4A từ khi 6 tuổi&lt;/li&gt;
&lt;li&gt;Học BASIC từ cha, một kỹ sư điện&lt;/li&gt;
&lt;li&gt;Tạm dừng lập trình ở tuổi 14 để theo đuổi sở thích khác&lt;/li&gt;
&lt;li&gt;Quay lại với lập trình ở tuổi 18-19&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Thời gian ở SECLAB:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phát hiện lỗ hổng trong chương trình ping&lt;/li&gt;
&lt;li&gt;Được mời làm việc tại công ty bảo mật&lt;/li&gt;
&lt;li&gt;Sáng tạo ra công cụ hping&lt;/li&gt;
&lt;li&gt;Rời đi sau 6 tháng để trở về Sicily&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sự ra đời của Redis:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bắt đầu từ dự án LLOOGG - công cụ phân tích web realtime&lt;/li&gt;
&lt;li&gt;Gặp vấn đề performance với MySQL&lt;/li&gt;
&lt;li&gt;Viết prototype bằng Tcl (LMDB)&lt;/li&gt;
&lt;li&gt;Chuyển sang C và phát hành Redis năm 2009&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Những người dùng đầu tiên:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub sử dụng để xây dựng Resque&lt;/li&gt;
&lt;li&gt;Instagram xây dựng toàn bộ hệ thống trên Redis&lt;/li&gt;
&lt;li&gt;Twitter mời antirez đến HQ để tối ưu timeline&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sự phát triển của Redis:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Được VMware tài trợ&lt;/li&gt;
&lt;li&gt;Chuyển sang Redis Labs&lt;/li&gt;
&lt;li&gt;Phát triển thêm nhiều tính năng mới&lt;/li&gt;
&lt;li&gt;antirez rời dự án năm 2020 sau 10 năm&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="tracing-structured-logging-but-better-in-every-way"&gt;&lt;a class="link" href="https://andydote.co.uk/2023/09/19/tracing-is-better/" target="_blank" rel="noopener"
&gt;Tracing: structured logging, but better in every way&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Andy Dote phân tích về lý do tại sao tracing tốt hơn logging và cách chuyển đổi từ logging sang tracing. Đây là một góc nhìn thú vị về observability trong phát triển phần mềm.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề với Logging:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Log levels không có ý nghĩa rõ ràng&lt;/li&gt;
&lt;li&gt;Messages khó query và phân tích&lt;/li&gt;
&lt;li&gt;Mixed outputs gây khó khăn cho việc xử lý&lt;/li&gt;
&lt;li&gt;Không có mối quan hệ nhân quả giữa các log lines&lt;/li&gt;
&lt;li&gt;Timing data không chính xác và nhất quán&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ưu điểm của Tracing:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tự động có timing data chính xác&lt;/li&gt;
&lt;li&gt;Có mối quan hệ parent-child giữa các spans&lt;/li&gt;
&lt;li&gt;Dễ dàng query và phân tích&lt;/li&gt;
&lt;li&gt;Hỗ trợ distributed tracing&lt;/li&gt;
&lt;li&gt;Có thể visualize timing graphs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cách chuyển đổi từ Logging sang Tracing:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thêm tracer và span cho mỗi method&lt;/li&gt;
&lt;li&gt;Wrap errors để capture thông tin lỗi&lt;/li&gt;
&lt;li&gt;Chuyển log messages thành attributes&lt;/li&gt;
&lt;li&gt;Thêm các attributes quan trọng để filter&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Best Practices:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng Observability Driven Development&lt;/li&gt;
&lt;li&gt;Chuyển log messages thành statements&lt;/li&gt;
&lt;li&gt;Xử lý loops cẩn thận để tránh overwrite attributes&lt;/li&gt;
&lt;li&gt;Tách logic phức tạp thành các methods riêng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Công cụ và Recommendations:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Honeycomb là lựa chọn tốt nhất để xem traces&lt;/li&gt;
&lt;li&gt;Lightstep là lựa chọn thứ hai&lt;/li&gt;
&lt;li&gt;Sử dụng OpenTelemetry để chuẩn hóa tracing&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="software-engineering-job-openings-hit-five-year-low"&gt;&lt;a class="link" href="https://newsletter.pragmaticengineer.com/p/software-engineering-job-openings" target="_blank" rel="noopener"
&gt;Software engineering job openings hit five-year low?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Gergely Orosz phân tích về tình trạng việc làm trong ngành công nghệ phần mềm, dựa trên dữ liệu từ Indeed. Đây là một góc nhìn thú vị về tác động của AI và các yếu tố khác đến thị trường việc làm.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tình trạng thị trường:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Số lượng việc làm giảm 35% so với 5 năm trước&lt;/li&gt;
&lt;li&gt;Giảm 3.5 lần so với đỉnh điểm giữa năm 2022&lt;/li&gt;
&lt;li&gt;Giảm 8% so với năm ngoái&lt;/li&gt;
&lt;li&gt;Xu hướng tương tự ở nhiều quốc gia (US, UK, France, Germany)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;So sánh với các ngành khác:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tổng số việc làm tăng 10% so với 2020&lt;/li&gt;
&lt;li&gt;Ngân hàng và tài chính giảm 7%&lt;/li&gt;
&lt;li&gt;Bán hàng giảm 8%&lt;/li&gt;
&lt;li&gt;Marketing giảm 19%&lt;/li&gt;
&lt;li&gt;Công nghệ phần mềm giảm 34%&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nguyên nhân có thể:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thay đổi lãi suất ảnh hưởng đến startup và VC funding&lt;/li&gt;
&lt;li&gt;Các công ty Big Tech giảm tuyển dụng&lt;/li&gt;
&lt;li&gt;Tác động của GenAI và AI tools&lt;/li&gt;
&lt;li&gt;Các công ty đang &amp;ldquo;wait and see&amp;rdquo; về năng suất AI&lt;/li&gt;
&lt;li&gt;Dư thừa nhân sự từ đợt tuyển dụng 2021-2022&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xu hướng mới:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Các team nhỏ hiệu quả hơn (ví dụ: Linear với 25 kỹ sư)&lt;/li&gt;
&lt;li&gt;Tuyển dụng chậm và cẩn thận hơn&lt;/li&gt;
&lt;li&gt;AI tools giúp tăng năng suất&lt;/li&gt;
&lt;li&gt;Nhiều startup mới được thành lập&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tương lai:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Có thể có sự bùng nổ của các startup &amp;ldquo;English-to-working-app&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Nhiều cơ hội cho developers làm việc với code được tạo bởi AI&lt;/li&gt;
&lt;li&gt;Thị trường có thể phục hồi khi các công ty thấy rõ lợi ích của AI tools&lt;/li&gt;
&lt;li&gt;Vẫn còn nhiều cơ hội trong các lĩnh vực mới&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="we-switched-from-java-to-go-and-don"&gt;&lt;a class="link" href="https://glasskube.dev/blog/from-java-to-go/" target="_blank" rel="noopener"
&gt;We switched from Java to Go and don&amp;rsquo;t regret it&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Philip Miglinci từ Glasskube chia sẻ về kinh nghiệm chuyển đổi từ Java sang Go và những bài học rút ra. Đây là một góc nhìn thú vị về việc lựa chọn công nghệ cho dự án cloud-native.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lý do chuyển đổi:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java/Kotlin tốn nhiều tài nguyên (2GB RAM khi idle)&lt;/li&gt;
&lt;li&gt;Các công cụ Kubernetes khác hầu hết được viết bằng Go&lt;/li&gt;
&lt;li&gt;Thời gian khởi động chậm (8.2s vs 100ms)&lt;/li&gt;
&lt;li&gt;Muốn tối ưu cho môi trường cloud-native&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;So sánh Compilation &amp;amp; Startup:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java: JIT compiler, hot code reloading, nhưng tốn nhiều bộ nhớ&lt;/li&gt;
&lt;li&gt;Go: AOT compiler, single binary, rebuild toàn bộ khi thay đổi&lt;/li&gt;
&lt;li&gt;Thời gian khởi động Go nhanh hơn nhiều (100ms vs 8.2s)&lt;/li&gt;
&lt;li&gt;Tiết kiệm thời gian phát triển đáng kể&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Frameworks và Libraries:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java: Frameworks lớn, all-in-one (Spring, Quarkus)&lt;/li&gt;
&lt;li&gt;Go: Libraries nhỏ, modular, có thể mix &amp;amp; match&lt;/li&gt;
&lt;li&gt;Go ít &amp;ldquo;black magic&amp;rdquo; hơn, dễ hiểu hơn&lt;/li&gt;
&lt;li&gt;Dependency injection đơn giản hơn với Context&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Developer Experience:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Debugging và IDE support tương đương&lt;/li&gt;
&lt;li&gt;Stack traces trong Java tốt hơn&lt;/li&gt;
&lt;li&gt;Go có ít công cụ CI/CD hơn nhưng chất lượng cao&lt;/li&gt;
&lt;li&gt;GoReleaser là công cụ release tốt&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kết luận:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learning curve không quá dốc&lt;/li&gt;
&lt;li&gt;Lợi ích rõ ràng: nhanh, nhẹ, đơn giản&lt;/li&gt;
&lt;li&gt;Phù hợp cho cloud-native và Kubernetes tooling&lt;/li&gt;
&lt;li&gt;Vẫn có thể quay lại Java cho các dự án khác&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="secure-java-applications-a-deep-look-into-3-different-issues"&gt;&lt;a class="link" href="https://developers.redhat.com/articles/2024/11/18/secure-java-applications-deep-look-3-different-issues" target="_blank" rel="noopener"
&gt;Secure Java applications: A deep look into 3 different issues&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Martin Balao Alonso từ Red Hat phân tích sâu về 3 vấn đề bảo mật phổ biến trong ứng dụng Java. Đây là một góc nhìn thú vị về các lỗ hổng bảo mật và cách phòng tránh.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề về Integral Overflow và Underflow:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java sử dụng signed two&amp;rsquo;s-complement cho các kiểu số nguyên&lt;/li&gt;
&lt;li&gt;Compiler ngăn chặn việc gán giá trị ngoài phạm vi&lt;/li&gt;
&lt;li&gt;Nhưng cho phép overflow trong các phép toán số học&lt;/li&gt;
&lt;li&gt;Overflow được cho phép vì lý do hiệu suất&lt;/li&gt;
&lt;li&gt;Developer cần tự kiểm tra và xử lý overflow&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề về Timing Attack:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Attacker có thể đo thời gian thực thi để đoán giá trị bí mật&lt;/li&gt;
&lt;li&gt;Các phép so sánh byte-by-byte có thể bị khai thác&lt;/li&gt;
&lt;li&gt;Cần sử dụng các phương thức so sánh time-constant&lt;/li&gt;
&lt;li&gt;Ví dụ: &lt;code&gt;Arrays.equals()&lt;/code&gt; thay vì so sánh từng byte&lt;/li&gt;
&lt;li&gt;Cần cẩn thận với các phép toán phụ thuộc vào dữ liệu bí mật&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề về JIT Compilation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JIT compiler có thể tối ưu code dựa trên dữ liệu runtime&lt;/li&gt;
&lt;li&gt;Các điều kiện phụ thuộc vào dữ liệu bí mật có thể bị khai thác&lt;/li&gt;
&lt;li&gt;Cần sử dụng các phương thức time-constant&lt;/li&gt;
&lt;li&gt;Tránh các phép toán phụ thuộc vào dữ liệu bí mật&lt;/li&gt;
&lt;li&gt;Có thể sử dụng &lt;code&gt;-XX:CompileCommand=print&lt;/code&gt; để phân tích code được compile&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Best Practices:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Luôn kiểm tra overflow trong các phép toán số học&lt;/li&gt;
&lt;li&gt;Sử dụng các phương thức so sánh time-constant&lt;/li&gt;
&lt;li&gt;Tránh các phép toán phụ thuộc vào dữ liệu bí mật&lt;/li&gt;
&lt;li&gt;Phân tích code được JIT compile&lt;/li&gt;
&lt;li&gt;Cẩn thận với các tối ưu hóa có thể ảnh hưởng đến bảo mật&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Công cụ và Recommendations:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng &lt;code&gt;javac&lt;/code&gt; để kiểm tra type safety&lt;/li&gt;
&lt;li&gt;Sử dụng &lt;code&gt;-XX:CompileCommand=print&lt;/code&gt; để phân tích JIT&lt;/li&gt;
&lt;li&gt;Sử dụng các thư viện bảo mật đã được kiểm chứng&lt;/li&gt;
&lt;li&gt;Thường xuyên cập nhật JDK và các dependencies&lt;/li&gt;
&lt;li&gt;Code review kỹ các phần xử lý dữ liệu nhạy cảm&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="java-devs-rejoice-this-open-source-secret-weapon-will-cut-your-coding-time-in-half"&gt;&lt;a class="link" href="https://www.indiehackers.com/post/java-devs-rejoice-this-open-source-secret-weapon-will-cut-your-coding-time-in-half-a7869a56de" target="_blank" rel="noopener"
&gt;Java Devs Rejoice! This Open-Source Secret Weapon Will Cut Your Coding Time in Half&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Brett Hoffman giới thiệu về esProc SPL - một công cụ xử lý dữ liệu mã nguồn mở cho Java. Đây là một giải pháp thú vị để tăng tốc độ phát triển và xử lý dữ liệu trong ứng dụng Java.&lt;/p&gt;
&lt;p&gt;Một số điểm chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề với Java và SQL:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java code xử lý dữ liệu phức tạp và dài dòng&lt;/li&gt;
&lt;li&gt;SQL đơn giản nhưng bị giới hạn bởi database&lt;/li&gt;
&lt;li&gt;Khó xử lý dữ liệu khi không có database&lt;/li&gt;
&lt;li&gt;Khó thực hiện cross-database computations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giải pháp với esProc SPL:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cú pháp đơn giản như SQL&lt;/li&gt;
&lt;li&gt;Hỗ trợ xử lý dữ liệu độc lập với database&lt;/li&gt;
&lt;li&gt;Tích hợp dễ dàng vào ứng dụng Java&lt;/li&gt;
&lt;li&gt;Hỗ trợ hot-swapping&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tính năng nổi bật:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cú pháp ngắn gọn cho các phép toán phức tạp&lt;/li&gt;
&lt;li&gt;Hỗ trợ xử lý dữ liệu lớn (in-memory và external memory)&lt;/li&gt;
&lt;li&gt;Dễ dàng thực hiện parallel processing&lt;/li&gt;
&lt;li&gt;IDE với debugging và WYSIWYG result viewing&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tích hợp với Java:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Có thể nhúng vào ứng dụng Java qua JDBC&lt;/li&gt;
&lt;li&gt;Hỗ trợ các framework Java phổ biến&lt;/li&gt;
&lt;li&gt;Phù hợp với kiến trúc microservice&lt;/li&gt;
&lt;li&gt;Có thể chạy trên Android&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ưu điểm so với các giải pháp khác:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đơn giản hơn Stream API của Java&lt;/li&gt;
&lt;li&gt;Nhẹ hơn Kotlin và Scala&lt;/li&gt;
&lt;li&gt;Hỗ trợ hot-swapping (khác với Java)&lt;/li&gt;
&lt;li&gt;Có thể xử lý nhiều nguồn dữ liệu khác nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="bonus-vài-video-hay-ho-đến-từ-inside-java"&gt;Bonus: Vài video hay ho đến từ &lt;a class="link" href="https://inside.java/" target="_blank" rel="noopener"
&gt;Inside Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://inside.java/2025/02/15/devoxxbelgium-gc-progress/" target="_blank" rel="noopener"
&gt;Garbage Collection in Java - The progress since JDK 8&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Mirror repository từ GitLab sang GitHub</title><link>https://miti99.com/post/2025/03/26/</link><pubDate>Wed, 26 Mar 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/03/26/</guid><description>&lt;p&gt;Chắc hẳn các bạn cũng biết khi tạo repository mới trên GitHub, GitHub sẽ cho phép &lt;a class="link" href="https://github.com/new/import" target="_blank" rel="noopener"
&gt;import repository&lt;/a&gt; từ nguồn git khác&lt;/p&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2025/03/26/img/1.png"
width="729"
height="931"
srcset="https://miti99.com/post/2025/03/26/img/1_hu_64cd20c9f30d1b7a.png 480w, https://miti99.com/post/2025/03/26/img/1_hu_afd2fe2f213217a6.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="78"
data-flex-basis="187px"
&gt;&lt;/p&gt;
&lt;p&gt;Tuy nhiên trong một số tình hướng chúng ta vẫn muốn update code trên GitLab, nhưng vẫn muốn update GitHub repository theo code mới nhất, vậy thì phải làm sao? Hôm nay mình sẽ hướng dẫn các bạn làm điều đó.&lt;/p&gt;
&lt;p&gt;Để thiết lập mirror từ GitLab sang GitHub, chúng ta cần thực hiện các bước sau:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Đầu tiên, tạo một GitHub Personal Access Token:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Truy cập &lt;code&gt;GitHub Settings&lt;/code&gt; &amp;gt; &lt;code&gt;Developer settings&lt;/code&gt; &amp;gt; &lt;code&gt;Personal access tokens&lt;/code&gt; &amp;gt; &lt;code&gt;Fine-grained tokens&lt;/code&gt;: &lt;a class="link" href="https://github.com/settings/personal-access-tokens" target="_blank" rel="noopener"
&gt;https://github.com/settings/personal-access-tokens&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;Generate new token&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Đặt tên cho token và chọn các quyền cần thiết:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Expiration&lt;/code&gt;: Nên đặt thời hạn nhất định.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Repository access&lt;/code&gt;: Phần này tuỳ ý, tốt nhất nên chọn &lt;code&gt;Only select repositories&lt;/code&gt; (chỉ cho phép access đến một số repository thực sự cần thiết). Nếu đang setup cho nhiều repository cùng resource owner và trong tương lai không muốn chỉnh sửa phức tạp thì có thể cân nhắc chọn &lt;code&gt;All repositories&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Permissions&lt;/code&gt;: Mục &lt;code&gt;Contents&lt;/code&gt;, chọn &lt;code&gt;Access: Read and write&lt;/code&gt; để có quyền đọc và ghi repository.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Copy token được tạo ra (lưu ý: token chỉ hiển thị một lần)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2025/03/26/img/2.png"
width="862"
height="979"
srcset="https://miti99.com/post/2025/03/26/img/2_hu_6132fe4b78c7a8ae.png 480w, https://miti99.com/post/2025/03/26/img/2_hu_d2b92c0ade54ba08.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="88"
data-flex-basis="211px"
&gt;
&lt;img src="https://miti99.com/post/2025/03/26/img/3.png"
width="832"
height="1268"
srcset="https://miti99.com/post/2025/03/26/img/3_hu_982009c598b54b6a.png 480w, https://miti99.com/post/2025/03/26/img/3_hu_6e17fa116fdcbfbd.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="65"
data-flex-basis="157px"
&gt;&lt;/p&gt;
&lt;p&gt;1.1. Với Organization sẽ cần chuẩn bị trước một chút Setting nữa:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Truy cập &lt;code&gt;Settings&lt;/code&gt; của organization. VD: &lt;a class="link" href="https://github.com/organizations/ngamtheproject/settings/personal-access-tokens" target="_blank" rel="noopener"
&gt;https://github.com/organizations/ngamtheproject/settings/personal-access-tokens&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Vào mục &lt;code&gt;Personal access tokens&lt;/code&gt;, tab &lt;code&gt;Fine-grained tokens&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Mục &lt;code&gt;Fine-grained personal access tokens&lt;/code&gt; chọn &lt;code&gt;Allow access via fine-grained personal access tokens&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Mục &lt;code&gt;Require approval of fine-grained personal access tokens&lt;/code&gt; chọn gì cũng được.
&lt;ul&gt;
&lt;li&gt;Nếu chọn &lt;code&gt;Require administrator approval&lt;/code&gt; thì sao khi tạo PAT cần approve.&lt;/li&gt;
&lt;li&gt;Nếu chọn &lt;code&gt;Do not require administrator approval&lt;/code&gt; thì sẽ không cần.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Chọn xong thì nhấn &lt;code&gt;Save&lt;/code&gt; ở mỗi mục.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2025/03/26/img/5.png"
width="951"
height="967"
srcset="https://miti99.com/post/2025/03/26/img/5_hu_847f571d1cc1ae12.png 480w, https://miti99.com/post/2025/03/26/img/5_hu_e724939a0e2b1112.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="98"
data-flex-basis="236px"
&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sau đó mới quay lại tạo PAT ở bước 1.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Thiết lập mirror trên GitLab:
&lt;ul&gt;
&lt;li&gt;Vào project trên GitLab&lt;/li&gt;
&lt;li&gt;Chọn &lt;code&gt;Settings&lt;/code&gt; &amp;gt; &lt;code&gt;Repository&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Mở rộng phần &lt;code&gt;Mirroring repositories&lt;/code&gt;. VD: &lt;a class="link" href="https://gitlab.com/miti99/demo-gitlab-mirror/-/settings/repository#js-push-remote-settings" target="_blank" rel="noopener"
&gt;https://gitlab.com/miti99/demo-gitlab-mirror/-/settings/repository#js-push-remote-settings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Bấm vào dấu &lt;code&gt;+&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Điền thông tin:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Git repository URL&lt;/code&gt;: &lt;code&gt;https://github.com/GROUP/PROJECT.git&lt;/code&gt;
(Thay GROUP và PROJECT bằng tên group và project trên GitHub. VD: &lt;a class="link" href="https://github.com/tiennm99/demo-gitlab-mirror.git" target="_blank" rel="noopener"
&gt;https://github.com/tiennm99/demo-gitlab-mirror.git&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Username&lt;/code&gt;: username của GitHub account&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Password&lt;/code&gt;: GitHub personal access token đã tạo ở bước 1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;Mirror repository&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2025/03/26/img/4.png"
width="1262"
height="1049"
srcset="https://miti99.com/post/2025/03/26/img/4_hu_dc88119d9bd17141.png 480w, https://miti99.com/post/2025/03/26/img/4_hu_697112e1af7b370a.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="120"
data-flex-basis="288px"
&gt;&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Kiểm tra trạng thái:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Sau khi thiết lập, repository sẽ được liệt kê với URL dạng:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;https://*****:*****@github.com/&amp;lt;your_github_group&amp;gt;/&amp;lt;your_github_project&amp;gt;.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Để kiểm tra mirror có hoạt động không, bạn có thể:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Push một commit mới lên GitLab&lt;/li&gt;
&lt;li&gt;Đợi khoảng 5 phút (hoặc 1 phút nếu bật &amp;ldquo;Only mirror protected branches&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;Kiểm tra trên GitHub xem commit đã được sync chưa&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Nếu muốn sync ngay lập tức, click &amp;ldquo;Update now&amp;rdquo; (nút retry)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lưu ý:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mirror sẽ tự động sync các commit mới từ GitLab sang GitHub&lt;/li&gt;
&lt;li&gt;Nếu branch được merge vào default branch và bị xóa ở source project, nó sẽ bị xóa ở mirror trong lần push tiếp theo&lt;/li&gt;
&lt;li&gt;Nếu branch có thay đổi chưa merge, nó sẽ được giữ lại&lt;/li&gt;
&lt;li&gt;Nếu branch bị diverge (phân kỳ), phần &amp;ldquo;Mirroring repositories&amp;rdquo; sẽ hiển thị lỗi&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tham khảo:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a class="link" href="https://meesvandongen.nl/posts/mirror-gitlab-github" target="_blank" rel="noopener"
&gt;https://meesvandongen.nl/posts/mirror-gitlab-github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.gitlab.com/user/project/repository/mirror/push/#set-up-a-push-mirror-from-gitlab-to-github" target="_blank" rel="noopener"
&gt;https://docs.gitlab.com/user/project/repository/mirror/push/#set-up-a-push-mirror-from-gitlab-to-github&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Hướng dẫn sử dụng NotebookLM của Google để hỏi đáp về Anh trai nhân vật chính</title><link>https://miti99.com/post/2025/03/25/</link><pubDate>Tue, 25 Mar 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/03/25/</guid><description>&lt;p&gt;Gần đây mới mua được Anh trai nhân vật chính tập 2. Nhưng chợt nhận ra vì đọc quá nhiều truyện nên có nhiều nhân vật mình không nhớ hoặc kể cả là&amp;hellip; cốt truyện. Gần đây với sự bùng nổ của AI, Google cũng cung cấp NotebookLM miễn phí cho mọi người. Nên sẵn tiện mình tranh thủ giới thiệu cách dùng NotebookLM để hỏi đáp về nội dung của Anh trai nhân vật chính.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note 1: Mình là dev, nên một số phần thiên về tech mình cũng lười giải thích. Tuy nhiên cũng sẽ cố gắng hướng dẫn thân thiện, dễ làm với mọi người. Nhưng không tránh khỏi sai sót, nếu có chỗ nào chưa rõ có thể comment hoặc inbox mình trao đổi thêm nhé. Mình khá bận nên trả lời nhanh hay chậm cũng hên xui&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note 2: Ở đây nội dung mình sử dụng để hỏi đáp đến từ bản web novel đăng trên &lt;a class="link" href="https://ln.hako.vn/" target="_blank" rel="noopener"
&gt;Hako&lt;/a&gt;, sẽ có một số khác biệt nhất định so với bản sách giấy nhé!&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="chuẩn-bị-data"&gt;Chuẩn bị data
&lt;/h2&gt;&lt;h3 id="dành-cho-techie"&gt;Dành cho techie
&lt;/h3&gt;&lt;p&gt;&lt;em&gt;Nếu bạn không phải dân tech, có thể chuyển đến &lt;a class="link" href="#d%c3%a0nh-cho-non-tech" &gt;mục kế tiếp&lt;/a&gt;, mình đã chuẩn bị sẵn data sẵn cho bạn. Phần này để các bạn thích tech mày mò thêm thôi.&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Bạn clone repo này của mình: &lt;a class="link" href="https://github.com/tiennm99/atnvc-crawler" target="_blank" rel="noopener"
&gt;https://github.com/tiennm99/atnvc-crawler&lt;/a&gt;. Làm theo hướng dẫn trong file README để setup và crawl data.
&lt;strong&gt;Note:&lt;/strong&gt; Script này mình viết đã lâu, gần đây có thấy Hako bị block, hãy đảm bảo máy của bạn truy cập được &lt;a class="link" href="https://ln.hako.vn/" target="_blank" rel="noopener"
&gt;https://ln.hako.vn/&lt;/a&gt; trước khi tiến hành nhé. Có thể dùng VPN hoặc Cloudflare WARP để bypass.&lt;/li&gt;
&lt;li&gt;Mặc định NotebookLM giới hạn số lượng file cũng như kích thước file cho 1 notebook. Mà hiện tại theo như bản web novel Anh trai nhân vật chính trên Hako đã có đến 133 chương rồi. Vì vậy chúng ta sẽ dùng tool để merge các chap lại với nhau, mình gợi ý là ghép các chap cùng 1 arc lại cho dễ quản lý nhé. Bước này bạn dùng gì cũng được, tự viết cũng ok. Mình thì DIY bằng &lt;a class="link" href="https://github.com/tiennm99/utils/raw/refs/heads/main/join.bat" target="_blank" rel="noopener"
&gt;script này&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;(Tuỳ thích) Đặt lại tên cho các file đã merge.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="dành-cho-non-tech"&gt;Dành cho non tech
&lt;/h3&gt;&lt;p&gt;Mình có upload sẵn các file mình đã xử lý ở bên dưới. Bạn có thể dùng như trang web nhé.&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="data/Arc%201.txt" &gt;Arc 1&lt;/a&gt;
&lt;a class="link" href="data/Arc%202.txt" &gt;Arc 2&lt;/a&gt;
&lt;a class="link" href="data/Arc%203.txt" &gt;Arc 3&lt;/a&gt;
&lt;a class="link" href="data/Others.txt" &gt;Others&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hoặc có thể dùng thông qua link Google Drive sau:&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://drive.google.com/drive/folders/1r85mnSVMGtEz2WBMq3fUBUIcOKqUpc7N?usp=sharing" target="_blank" rel="noopener"
&gt;https://drive.google.com/drive/folders/1r85mnSVMGtEz2WBMq3fUBUIcOKqUpc7N?usp=sharing&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Mình hay dọn dẹp nên có khi quên mất và delete thư mục share. Nếu gặp vấn đề thì gì thì hú mình nhé&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hiện tại mình mới update đến chương 133 theo như trên Hako thôi nhé. Có thể mình sẽ update thêm trong tương lai nếu có nhiều bạn hứng thú&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="setup-notebooklm"&gt;Setup NotebookLM
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;Truy cập trang NotebookLM: &lt;a class="link" href="https://notebooklm.google.com/" target="_blank" rel="noopener"
&gt;https://notebooklm.google.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Đăng nhập bằng account Google&lt;/li&gt;
&lt;li&gt;Tạo sổ ghi chú mới. Đặt tên tuỳ thích, mà nên đặt tên gợi nhớ để dễ phân biệt&lt;/li&gt;
&lt;li&gt;Up các file đã tạo ở phần chuẩn bị data lên.
&lt;ul&gt;
&lt;li&gt;Nếu bạn dùng web mình tạo sẵn thì chọn mục Liên kết/Trang web&lt;/li&gt;
&lt;li&gt;Nếu bạn dùng thư mục Google Drive của mình thì chọn Google Drive/Google Tài liệu/Được chia sẻ với tôi&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Bắt đầu sử dụng thôi :D&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Tips: Đôi khi bạn sẽ muốn biết thông tin về arc bạn đã đọc rồi thôi, tránh bị spoil. Như ở trên mình có khuyên gom nhóm lại thành arc. Không muốn NotebookLM biết arc nào thì trong phần &lt;code&gt;Nguồn&lt;/code&gt; bỏ tick arc đó đi là được&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="vài-hình-ảnh-demo"&gt;Vài hình ảnh demo
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://miti99.com/post/2025/03/25/img/1.png"
width="1022"
height="539"
srcset="https://miti99.com/post/2025/03/25/img/1_hu_f3e87b696f6a3ed2.png 480w, https://miti99.com/post/2025/03/25/img/1_hu_c536b690991a0436.png 1024w"
loading="lazy"
alt="Lai là ai? Sao lại trung thành với Khan như vậy?"
class="gallery-image"
data-flex-grow="189"
data-flex-basis="455px"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2025/03/25/img/2.png"
width="1036"
height="466"
srcset="https://miti99.com/post/2025/03/25/img/2_hu_c02826bddaf0e0ae.png 480w, https://miti99.com/post/2025/03/25/img/2_hu_74fac166e181c808.png 1024w"
loading="lazy"
alt="Lauriel là ai? Khan và Lauriel có phải vợ chồng không?"
class="gallery-image"
data-flex-grow="222"
data-flex-basis="533px"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2025/03/25/img/3.png"
width="1037"
height="565"
srcset="https://miti99.com/post/2025/03/25/img/3_hu_b0ae08b9cc155b2c.png 480w, https://miti99.com/post/2025/03/25/img/3_hu_8b26fe2761b1dd3b.png 1024w"
loading="lazy"
alt="Linh hồn sơ khai là gì? Khan đã sở hữu mấy linh hồn sơ khai? Ngoài Khan ra còn ai khác có linh hồn sơ khai không?"
class="gallery-image"
data-flex-grow="183"
data-flex-basis="440px"
&gt;&lt;/p&gt;
&lt;h2 id="mở-rộng"&gt;Mở rộng
&lt;/h2&gt;&lt;p&gt;Bài này mình demo với Anh trai nhân vật chính, nhưng thực chất có thể ứng dụng với bất kỳ truyện nào. Mở rộng hơn nữa còn có thể dùng cho document trong công việc, hay các sách báo khác,&amp;hellip; Có thể thấy AI đang phát triển mạnh mẽ và có nhiều tiềm năng rất lớn. Một số ông lớn về công nghệ như Google cũng cung cấp các dịch vụ miễn phí như NotebookLM. Dù dùng ở trong công việc hay vui chơi giải trí gì đều rất hữu ích. Mình cũng lo sợ một ngày nào đó AI sẽ cho mình ra chuồng gà mất. Nếu có fuba nào đọc xong và thấy cảm động, xin hãy bao nuôi anh dev này 🥺🥺&lt;/p&gt;</description></item><item><title>Newsletter #8</title><link>https://miti99.com/post/2025/03/24/</link><pubDate>Mon, 24 Mar 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/03/24/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #8.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="let"&gt;&lt;a class="link" href="https://info.michael-simons.eu/2025/02/05/lets-deadlock-all-the-things/" target="_blank" rel="noopener"
&gt;Let&amp;rsquo;s deadlock all the things&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Michael Simons kể về một lỗi &amp;ldquo;rookie&amp;rdquo; mà ông gặp phải khi làm việc với Java HttpClient, cho thấy rằng ngay cả những lập trình viên có kinh nghiệm cũng có thể mắc những lỗi cơ bản.&lt;/p&gt;
&lt;p&gt;Tác giả đang cố gắng chuyển đổi code từ &lt;code&gt;HttpURLConnection&lt;/code&gt; cũ sang &lt;code&gt;HttpClient&lt;/code&gt; mới của Java. Trong quá trình này, ông đã cố gắng sử dụng &lt;code&gt;PipedInputStream&lt;/code&gt; và &lt;code&gt;PipedOutputStream&lt;/code&gt; để xử lý request body, bỏ qua cảnh báo trong JavaDoc về việc sử dụng cả hai đối tượng trong cùng một thread có thể gây deadlock.&lt;/p&gt;
&lt;p&gt;Mặc dù code &amp;ldquo;hoạt động&amp;rdquo; trong các test cơ bản, nhưng khi xử lý payload lớn hơn buffer mặc định (1024 bytes), hệ thống sẽ bị deadlock và có thể làm cạn kiệt tất cả các thread có sẵn.&lt;/p&gt;
&lt;p&gt;Tác giả chia sẻ một số bài học rút ra:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Đọc kỹ tài liệu và không bỏ qua các cảnh báo&lt;/li&gt;
&lt;li&gt;Cần có góc nhìn thứ hai từ đồng nghiệp&lt;/li&gt;
&lt;li&gt;Test kỹ hơn, đặc biệt là các trường hợp biên&lt;/li&gt;
&lt;li&gt;AI có thể giúp tạo test input, nhưng không thể thay thế việc hiểu sâu về API&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Cuối cùng, tác giả đã tìm ra giải pháp bằng cách sử dụng virtual thread để xử lý việc ghi dữ liệu, tránh deadlock và cho phép xử lý payload lớn một cách hiệu quả.&lt;/p&gt;
&lt;h2 id="engineers-who-won"&gt;&lt;a class="link" href="https://www.seangoedecke.com/taking-a-position/" target="_blank" rel="noopener"
&gt;Engineers who won&amp;rsquo;t commit&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Sean Goedecke thảo luận về một vấn đề phổ biến trong giới kỹ sư phần mềm: việc không dám đưa ra quan điểm trong các cuộc thảo luận kỹ thuật. Tác giả cho rằng mặc dù việc giữ thái độ &amp;ldquo;cởi mở&amp;rdquo; và &amp;ldquo;không cam kết&amp;rdquo; có thể phù hợp với kỹ sư mới vào nghề, nhưng khi bạn là người có nhiều kinh nghiệm nhất trong phòng họp, bạn cần phải đưa ra quan điểm của mình, ngay cả khi chỉ tự tin 55-60%.&lt;/p&gt;
&lt;p&gt;Tác giả chỉ ra rằng việc không đưa ra quan điểm có thể dẫn đến những hậu quả tiêu cực:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Buộc những người ít kinh nghiệm hơn phải tự quyết định&lt;/li&gt;
&lt;li&gt;Có thể dẫn đến việc người kém nhất nhưng nói to nhất trong nhóm đưa ra quyết định tồi&lt;/li&gt;
&lt;li&gt;Tạo gánh nặng cho quản lý khi họ phải đưa ra quyết định kỹ thuật thay vì kỹ sư&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tuy nhiên, tác giả cũng thừa nhận rằng có những trường hợp ngoại lệ hợp lý, đặc biệt là trong môi trường làm việc độc hại nơi các kỹ sư có thể bị trừng phạt vì đưa ra ước tính không chính xác.&lt;/p&gt;
&lt;p&gt;Bài viết kết luận rằng việc đưa ra quan điểm là trách nhiệm của kỹ sư có kinh nghiệm, và việc không làm điều đó có thể được coi là một dạng hèn nhát. Điều quan trọng là phải phân biệt giữa việc đưa ra quan điểm trong môi trường làm việc và việc giữ thái độ cởi mở trong các cuộc thảo luận với đồng nghiệp có cùng trình độ.&lt;/p&gt;
&lt;h2 id="patterns-for-building-realtime-features"&gt;&lt;a class="link" href="https://zknill.io/posts/patterns-for-building-realtime/" target="_blank" rel="noopener"
&gt;Patterns for building realtime features&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Zach Knill giới thiệu các mẫu thiết kế phổ biến để xây dựng tính năng realtime trong ứng dụng. Các tính năng realtime giúp ứng dụng cảm giác hiện đại, có tính cộng tác và luôn được cập nhật kịp thời.&lt;/p&gt;
&lt;p&gt;Tác giả giới thiệu 4 mẫu thiết kế chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Poke/Pull&lt;/strong&gt;: Server gửi thông báo (&amp;ldquo;poke&amp;rdquo;) cho các client đã đăng ký khi có thay đổi, sau đó client sẽ tự động kéo (&amp;ldquo;pull&amp;rdquo;) dữ liệu mới. Mẫu này dễ tích hợp vào ứng dụng hiện có nhưng có thể gây tải cho server do nhiều client cùng kéo dữ liệu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Push state&lt;/strong&gt;: Server trực tiếp đẩy trạng thái mới đến client thay vì chỉ gửi thông báo. Mẫu này giải quyết vấn đề tải server nhưng có thể không hiệu quả khi trạng thái lớn hoặc khi client cần biết chính xác điều gì đã thay đổi.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Push operations&lt;/strong&gt;: Server gửi các thao tác thay đổi thay vì toàn bộ trạng thái. Mẫu này giúp client biết chính xác điều gì đã thay đổi và giảm lượng dữ liệu truyền tải, nhưng yêu cầu client phải có logic để áp dụng các thao tác.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Event sourcing&lt;/strong&gt;: Server gửi các sự kiện đã xảy ra thay vì các thao tác. Mẫu này cho phép client có logic phức tạp hơn nhưng yêu cầu client phải hiểu ý nghĩa của mỗi sự kiện.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tác giả cũng thảo luận về các phương thức vận chuyển (transports) như WebSocket, SSE, và các thách thức khi triển khai trong hệ thống phân tán. Trong môi trường có nhiều server replica, việc đồng bộ trạng thái giữa các client kết nối với các server khác nhau có thể phức tạp, và các dịch vụ Pub/Sub có thể giúp giải quyết vấn đề này.&lt;/p&gt;
&lt;h2 id="optimizing-the-databases-at-quora"&gt;&lt;a class="link" href="https://quoraengineering.quora.com/Optimizing-the-databases-at-Quora" target="_blank" rel="noopener"
&gt;Optimizing the databases at Quora&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ đội ngũ kỹ sư Quora chia sẻ chi tiết về quá trình tối ưu hóa cơ sở dữ liệu của họ. Quora đã phải đối mặt với nhiều thách thức khi hệ thống phát triển, bao gồm việc xử lý lượng lớn dữ liệu và đảm bảo hiệu suất cho người dùng.&lt;/p&gt;
&lt;p&gt;Các chiến lược tối ưu chính bao gồm:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phân mảnh dữ liệu (Sharding)&lt;/strong&gt;: Quora đã triển khai sharding để phân phối tải trên nhiều máy chủ cơ sở dữ liệu. Họ sử dụng một chiến lược sharding dựa trên user_id, cho phép họ phân phối dữ liệu người dùng một cách hiệu quả.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tối ưu hóa truy vấn&lt;/strong&gt;: Đội ngũ đã phân tích và tối ưu các truy vấn phổ biến, thêm các chỉ mục phù hợp và loại bỏ các truy vấn không cần thiết.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Caching&lt;/strong&gt;: Quora triển khai nhiều lớp cache khác nhau:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cache ở cấp độ ứng dụng cho dữ liệu thường xuyên truy cập&lt;/li&gt;
&lt;li&gt;Cache ở cấp độ cơ sở dữ liệu cho các kết quả truy vấn phổ biến&lt;/li&gt;
&lt;li&gt;Sử dụng Memcached cho cache phân tán&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Đọc/ghi phân tách (Read/Write Splitting)&lt;/strong&gt;: Hệ thống được thiết kế để phân tách các hoạt động đọc và ghi, cho phép mở rộng độc lập các khả năng đọc và ghi.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giám sát và cảnh báo&lt;/strong&gt;: Quora đã xây dựng hệ thống giám sát toàn diện để theo dõi hiệu suất cơ sở dữ liệu và phát hiện sớm các vấn đề.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết cũng nhấn mạnh tầm quan trọng của việc:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thường xuyên phân tích và tối ưu hóa hiệu suất&lt;/li&gt;
&lt;li&gt;Xây dựng các công cụ tự động hóa cho việc quản lý cơ sở dữ liệu&lt;/li&gt;
&lt;li&gt;Duy trì sự cân bằng giữa hiệu suất và tính đơn giản của hệ thống&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="failure-mitigation-for-microservices-an-intro-to-aperture"&gt;&lt;a class="link" href="https://careersatdoordash.com/blog/failure-mitigation-for-microservices-an-intro-to-aperture/" target="_blank" rel="noopener"
&gt;Failure Mitigation for Microservices: An Intro to Aperture&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ đội ngũ DoorDash giới thiệu về Aperture, một hệ thống quản lý độ tin cậy mã nguồn mở mà họ đã phát triển để giải quyết các vấn đề phổ biến trong kiến trúc microservices.&lt;/p&gt;
&lt;p&gt;Aperture được thiết kế để giải quyết 3 thách thức chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Cascading Failures&lt;/strong&gt;: Lỗi lan truyền từ service này sang service khác&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Retry Storms&lt;/strong&gt;: Các request thất bại được thử lại nhiều lần&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Death Spirals&lt;/strong&gt;: Lỗi lan truyền ngang trong cùng một service&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Hệ thống hoạt động theo 3 bước chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Collect&lt;/strong&gt;: Thu thập metrics từ các node (CPU, memory, latency, error rate) thông qua sidecar và tổng hợp trong Prometheus&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Analyze&lt;/strong&gt;: Controller giám sát metrics và theo dõi các sai lệch so với service-level objectives (SLO) được định nghĩa trong file YAML&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Actuate&lt;/strong&gt;: Khi các policy được kích hoạt, Aperture sẽ thực hiện các hành động như load shedding hoặc rate limiting phân tán&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;DoorDash đã triển khai Aperture trong một service chính và thử nghiệm với các request nhân tạo. Kết quả cho thấy nó hoạt động như một global rate limiter và load shedder mạnh mẽ, dễ sử dụng.&lt;/p&gt;
&lt;p&gt;Bài viết cũng nhấn mạnh tầm quan trọng của việc:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thiết lập SLO rõ ràng cho mỗi service&lt;/li&gt;
&lt;li&gt;Giám sát liên tục và phát hiện sớm các vấn đề&lt;/li&gt;
&lt;li&gt;Tự động hóa việc xử lý các sự cố&lt;/li&gt;
&lt;li&gt;Duy trì tính đơn giản của hệ thống&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="zero-configuration-service-mesh-with-on-demand-cluster-discovery"&gt;&lt;a class="link" href="https://netflixtechblog.com/zero-configuration-service-mesh-with-on-demand-cluster-discovery-ac6483b52a51" target="_blank" rel="noopener"
&gt;Zero Configuration Service Mesh with On-Demand Cluster Discovery&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ đội ngũ Netflix chia sẻ về hành trình chuyển đổi sang service mesh và cách họ giải quyết thách thức về cấu hình cluster trong môi trường microservices phức tạp.&lt;/p&gt;
&lt;p&gt;Netflix đã sớm chuyển sang cloud, bắt đầu từ năm 2008 và hoàn thành vào năm 2010. Trong giai đoạn đầu, họ đã xây dựng các công cụ riêng như Eureka cho service discovery và Ribbon cho IPC (Inter-Process Communication). Tuy nhiên, khi hệ thống phát triển, họ gặp phải nhiều thách thức mới:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hỗ trợ nhiều loại IPC client khác nhau (REST, GraphQL, gRPC)&lt;/li&gt;
&lt;li&gt;Môi trường đa ngôn ngữ (Java, Node.js, Python)&lt;/li&gt;
&lt;li&gt;Nhu cầu về các tính năng phức tạp như adaptive concurrency limiting, circuit breaking&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Để giải quyết các vấn đề này, Netflix quyết định chuyển sang sử dụng service mesh với Envoy làm proxy. Tuy nhiên, họ gặp phải thách thức về việc cấu hình cluster: mỗi service có thể cần giao tiếp với hàng chục cluster khác nhau, và danh sách này thay đổi liên tục.&lt;/p&gt;
&lt;p&gt;Netflix đã hợp tác với Kinvolk và cộng đồng Envoy để phát triển tính năng On-Demand Cluster Discovery (ODCDS). Với tính năng này, proxy có thể tìm kiếm thông tin cluster khi cần thiết, thay vì phải định nghĩa trước tất cả các cluster trong cấu hình.&lt;/p&gt;
&lt;p&gt;Quy trình hoạt động:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Request đến Envoy&lt;/li&gt;
&lt;li&gt;Kiểm tra cluster đích dựa trên header&lt;/li&gt;
&lt;li&gt;Nếu cluster chưa tồn tại, tạm dừng request&lt;/li&gt;
&lt;li&gt;Yêu cầu thông tin cluster từ control plane&lt;/li&gt;
&lt;li&gt;Nhận thông tin cluster và endpoints&lt;/li&gt;
&lt;li&gt;Tiếp tục xử lý request&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Lợi ích chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không cần cấu hình trước các cluster&lt;/li&gt;
&lt;li&gt;Giảm độ phức tạp của hệ thống&lt;/li&gt;
&lt;li&gt;Tiết kiệm bộ nhớ bằng cách chỉ tải thông tin cluster cần thiết&lt;/li&gt;
&lt;li&gt;Dễ dàng chuyển đổi từ hệ thống cũ sang service mesh&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tuy nhiên, cũng có một số nhược điểm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thêm độ trễ cho request đầu tiên đến một cluster&lt;/li&gt;
&lt;li&gt;Có thể không phù hợp với các service yêu cầu độ trễ rất thấp&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Netflix vẫn đang trong giai đoạn đầu của hành trình service mesh và đang tiếp tục cải thiện hệ thống, đặc biệt là trong việc tối ưu hóa EDS (Endpoint Discovery Service).&lt;/p&gt;
&lt;h2 id="the-quest-to-understand-metric-movements"&gt;&lt;a class="link" href="https://medium.com/pinterest-engineering/the-quest-to-understand-metric-movements-8ab12ae97cda" target="_blank" rel="noopener"
&gt;The Quest to Understand Metric Movements&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ đội ngũ Pinterest chia sẻ về cách họ xây dựng hệ thống phân tích nguyên nhân gốc rễ (Root Cause Analysis - RCA) cho các chuyển động của metrics. Khi một metric quan trọng có sự thay đổi bất thường, việc tìm ra nguyên nhân có thể rất phức tạp do có nhiều yếu tố có thể ảnh hưởng.&lt;/p&gt;
&lt;p&gt;Pinterest đã phát triển ba phương pháp tiếp cận chính:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Slice and Dice&lt;/strong&gt;: Phân tích chi tiết các phân đoạn của metric để tìm manh mối về nguyên nhân thay đổi. Ví dụ, khi phân tích tỷ lệ xem video, họ có thể chia nhỏ theo các chiều như quốc gia, loại thiết bị, loại Pin, v.v. Phương pháp này đặc biệt hiệu quả trong việc chẩn đoán các vấn đề về metrics video.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;General Similarity&lt;/strong&gt;: Tìm kiếm các metrics khác có chuyển động tương tự trong cùng khoảng thời gian. Hệ thống sử dụng bốn yếu tố để đo lường độ tương đồng:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pearson correlation: đo mối quan hệ tuyến tính&lt;/li&gt;
&lt;li&gt;Spearman&amp;rsquo;s rank correlation: đo mối quan hệ đơn điệu&lt;/li&gt;
&lt;li&gt;Euclidean similarity: dựa trên khoảng cách Euclidean&lt;/li&gt;
&lt;li&gt;Dynamic time warping: cho phép so sánh các chuỗi thời gian có độ dài khác nhau&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Experiment Effects&lt;/strong&gt;: Phân tích tác động của các thử nghiệm A/B testing lên metrics. Hệ thống sẽ:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tính toán tác động của mỗi thử nghiệm lên metric&lt;/li&gt;
&lt;li&gt;Sử dụng Welch&amp;rsquo;s t-test để đánh giá ý nghĩa thống kê&lt;/li&gt;
&lt;li&gt;Lọc các thử nghiệm dựa trên p-value và sự mất cân bằng giữa nhóm kiểm soát và nhóm thử nghiệm&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Các phương pháp này có thể được sử dụng kết hợp với nhau để thu hẹp phạm vi tìm kiếm nguyên nhân. Pinterest đang tiếp tục cải thiện hệ thống bằng cách:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thêm cơ chế phản hồi từ người dùng&lt;/li&gt;
&lt;li&gt;Tích hợp với các nền tảng dữ liệu khác&lt;/li&gt;
&lt;li&gt;Khám phá các mối quan hệ nhân quả giữa các metrics&lt;/li&gt;
&lt;li&gt;Tích hợp RCA vào các công cụ khám phá và trực quan hóa dữ liệu&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="meta"&gt;&lt;a class="link" href="https://cacm.acm.org/research/metas-hyperscale-infrastructure-overview-and-insights/" target="_blank" rel="noopener"
&gt;Meta&amp;rsquo;s Hyperscale Infrastructure: Overview and Insights&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết từ Chunqiang Tang của Meta chia sẻ tổng quan về cơ sở hạ tầng hyperscale của công ty và những bài học kinh nghiệm từ quá trình phát triển. Mặc dù hầu hết các kỹ sư không trực tiếp xây dựng cơ sở hạ tầng hyperscale, việc hiểu về nó rất có ích vì nhiều công nghệ phổ biến ngày nay đã bắt nguồn từ môi trường này.&lt;/p&gt;
&lt;p&gt;Các điểm chính về văn hóa kỹ thuật của Meta:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Move fast&lt;/strong&gt;: Tập trung vào việc triển khai nhanh và lặp lại liên tục:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Triển khai liên tục code mới nhất vào production&lt;/li&gt;
&lt;li&gt;Sử dụng serverless functions cho các sản phẩm&lt;/li&gt;
&lt;li&gt;Cho phép các team nhanh chóng thay đổi ưu tiên&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Technology openness&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng monorepo cho tất cả dự án&lt;/li&gt;
&lt;li&gt;Không áp dụng quy tắc sở hữu code nghiêm ngặt&lt;/li&gt;
&lt;li&gt;Đóng góp nhiều dự án mã nguồn mở (PyTorch, Llama, Presto, RocksDB)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Research in production&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Không có phòng nghiên cứu riêng biệt&lt;/li&gt;
&lt;li&gt;Các team phát triển sản phẩm trực tiếp thực hiện nghiên cứu&lt;/li&gt;
&lt;li&gt;Đảm bảo các giải pháp hoạt động ở quy mô lớn&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Common infrastructure&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chuẩn hóa phần cứng (một loại server duy nhất cho non-AI workloads)&lt;/li&gt;
&lt;li&gt;Tối ưu hóa ứng dụng cho phần cứng thay vì ngược lại&lt;/li&gt;
&lt;li&gt;Tập trung vào tối ưu hóa toàn cục thay vì cục bộ&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Chiến lược AI của Meta bao gồm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thiết kế đồng bộ toàn bộ stack từ PyTorch đến AI accelerators&lt;/li&gt;
&lt;li&gt;Tối ưu hóa mạng và các mô hình ML như Llama&lt;/li&gt;
&lt;li&gt;Tích hợp chặt chẽ giữa phần cứng và phần mềm&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bài viết cũng nhấn mạnh tầm quan trọng của việc:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Duy trì sự cân bằng giữa tốc độ phát triển và độ ổn định&lt;/li&gt;
&lt;li&gt;Tập trung vào việc tối ưu hóa toàn cục&lt;/li&gt;
&lt;li&gt;Đầu tư vào nghiên cứu và phát triển các công nghệ mới&lt;/li&gt;
&lt;li&gt;Chia sẻ kiến thức và công nghệ với cộng đồng&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="incremental-platforms-monolithic-modular-architecture"&gt;&lt;a class="link" href="https://newsletter.optimistengineer.com/p/incremental-platforms-monolithic" target="_blank" rel="noopener"
&gt;Incremental Platforms: Monolithic Modular Architecture&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Marcos F. Lobo giới thiệu về kiến trúc Monolithic Modular, một cách tiếp cận để xây dựng nền tảng có khả năng phát triển bền vững. Kiến trúc này kết hợp sự đơn giản của monolithic với lợi ích của thiết kế modular và tách biệt.&lt;/p&gt;
&lt;p&gt;Đặc điểm chính của kiến trúc này:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Single Deployment&lt;/strong&gt;: Toàn bộ code được đóng gói và triển khai như một ứng dụng duy nhất&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internal Modularization&lt;/strong&gt;: Ứng dụng được chia thành các module hoặc component riêng biệt, mỗi module có:
&lt;ul&gt;
&lt;li&gt;Interface rõ ràng&lt;/li&gt;
&lt;li&gt;Contract xác định cách giao tiếp với các module khác&lt;/li&gt;
&lt;li&gt;Trách nhiệm duy nhất và được định nghĩa rõ ràng&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Để đạt được kiến trúc này, tác giả đề xuất các nguyên tắc:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Định nghĩa ranh giới và contract rõ ràng&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mỗi module phải có interface công khai&lt;/li&gt;
&lt;li&gt;Sử dụng các pattern như facade để tránh truy cập trực tiếp vào implementation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tách biệt các mối quan tâm&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đảm bảo mỗi module có một trách nhiệm duy nhất&lt;/li&gt;
&lt;li&gt;Giảm thiểu sự phụ thuộc giữa các module&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tổ chức code và cấu trúc package&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng cấu trúc package phản ánh sự phân chia module&lt;/li&gt;
&lt;li&gt;Đảm bảo mỗi module có thể được tách riêng trong tương lai&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Testing và tự động hóa&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Test các use case của monolith&lt;/li&gt;
&lt;li&gt;Sử dụng CI/CD để kiểm tra tính toàn vẹn và giao tiếp giữa các module&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quản lý phụ thuộc và giao tiếp&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng dependency injection&lt;/li&gt;
&lt;li&gt;Xem xét sử dụng messaging hoặc events để tách biệt các module&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Lợi ích chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Đơn giản trong triển khai và vận hành&lt;/strong&gt;: Một artifact duy nhất, giảm overhead&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dễ dàng phát triển và refactor&lt;/strong&gt;: Giao dịch đơn giản, truy cập tài nguyên dễ dàng&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hiệu suất và tính nhất quán&lt;/strong&gt;: Gọi giữa các module trong bộ nhớ, xử lý giao dịch đơn giản&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hỗ trợ Domain-Driven Design&lt;/strong&gt;: Dễ dàng chia hệ thống theo bounded contexts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Kiến trúc này đặc biệt phù hợp cho:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dự án giai đoạn đầu&lt;/li&gt;
&lt;li&gt;Nhóm nhỏ&lt;/li&gt;
&lt;li&gt;Hệ thống cần tính nhất quán và toàn vẹn giao dịch&lt;/li&gt;
&lt;li&gt;Nền tảng có thể phát triển dần dần thành kiến trúc phân tán trong tương lai&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bonus-vài-video-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài video hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=3Kqal7QaCCM" target="_blank" rel="noopener"
&gt;How the Garbage Collector Works in Java, Python, and Go!&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="bonus-2-vài-hình-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus 2: Vài hình ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/c3beec9e-cd04-4748-ae7e-3299b42883f6_2360x2824.png"
loading="lazy"
alt="How to Build Idempotent APIs"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/2f632296-4214-4ec8-a1d2-280e9b7f2696_1280x1532.gif"
loading="lazy"
alt="12 Algorithms for System Design Interviews"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/65a92a81-f2c5-4aed-9faa-35a66124cffe_1283x1536.gif"
loading="lazy"
alt="How Kubernetes Works?"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/a6903386-4b5f-450e-b64d-839c6fdf8238_1280x1601.gif"
loading="lazy"
alt="PostgreSQL 101: The Everything Database"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/06c5ad46-faaf-479b-bde3-b5de8033b4e9_1280x1664.gif"
loading="lazy"
alt="Top 12 Tips for API Security"
&gt;&lt;/p&gt;
&lt;h2 id="bonus-3-vài-hình-ảnh-hay-ho-đến-từ-designgurus"&gt;Bonus 3: Vài hình ảnh hay ho đến từ &lt;a class="link" href="https://designgurus.io/" target="_blank" rel="noopener"
&gt;DesignGurus&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://www.designgurus.io/_next/image?url=https%3A%2F%2Fstorage.googleapis.com%2Fdownload%2Fstorage%2Fv1%2Fb%2Fdesigngurus-prod.appspot.com%2Fo%2Fee5726e8e29469477b999c100%3Fgeneration%3D1726724098184989%26alt%3Dmedia&amp;amp;w=3840&amp;amp;q=75&amp;amp;dpl=dpl_3Rx6M949Pc1cQKT3QTdj87FcKNdg"
loading="lazy"
alt="System Design Master Template"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #7</title><link>https://miti99.com/post/2025/03/16/</link><pubDate>Sun, 16 Mar 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/03/16/</guid><description>&lt;p&gt;&lt;em&gt;Mời bạn thưởng thức Newsletter #7.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="the-llm-curve-of-impact-on-software-engineers"&gt;&lt;a class="link" href="https://serce.me/posts/2025-02-07-the-llm-curve-of-impact-on-software-engineers" target="_blank" rel="noopener"
&gt;The LLM Curve of Impact on Software Engineers&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết phân tích tác động của các mô hình ngôn ngữ lớn (LLM) đối với kỹ sư phần mềm ở các cấp độ khác nhau:&lt;/p&gt;
&lt;p&gt;Với kỹ sư Junior, LLM như một cứu cánh khi gặp lỗi hoặc cần viết các tính năng nhỏ. Tuy nhiên, việc phụ thuộc quá nhiều vào LLM mà không thực sự hiểu code có thể cản trở sự phát triển kỹ năng.&lt;/p&gt;
&lt;p&gt;Đối với kỹ sư Mid-level, LLM giúp tăng tốc độ code và học framework mới. Tuy nhiên, họ bắt đầu nhận ra những hạn chế của LLM trong việc hiểu yêu cầu khách hàng hay xử lý các vấn đề phức tạp như race condition.&lt;/p&gt;
&lt;p&gt;Kỹ sư Senior thường tỏ ra hoài nghi về LLM nhất. Với hiểu biết sâu rộng về codebase, họ nhận thấy LLM không thực sự hữu ích trong các công việc đòi hỏi nhiều context như lập roadmap, debug các lỗi phức tạp hay viết tài liệu thiết kế.&lt;/p&gt;
&lt;p&gt;Đặc biệt, với kỹ sư Staff+, LLM lại trở nên hữu ích trong việc tạo các proof-of-concept nhanh chóng. Nhờ kiến thức domain sâu rộng, họ có thể nhanh chóng giúp LLM vượt qua các điểm bế tắc để tạo ra các giải pháp demo hoạt động được.&lt;/p&gt;
&lt;p&gt;Tóm lại, tác động của LLM không đồng đều across các level, và hiệu quả của nó phụ thuộc vào việc sử dụng phù hợp với từng cấp độ kinh nghiệm.&lt;/p&gt;
&lt;h2 id="you-are-using-cursor-ai-incorrectly"&gt;&lt;a class="link" href="https://ghuntley.com/stdlib/" target="_blank" rel="noopener"
&gt;You are using Cursor AI incorrectly&amp;hellip;&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết &amp;ldquo;You are using Cursor AI incorrectly&amp;hellip;&amp;rdquo; của Geoffrey Huntley trình bày cách tiếp cận mới và hiệu quả hơn khi sử dụng Cursor AI. Thay vì chỉ yêu cầu Cursor viết đoạn code cụ thể, tác giả đề xuất xây dựng một &amp;ldquo;stdlib&amp;rdquo; (thư viện chuẩn) gồm hàng nghìn quy tắc (rules) và kết hợp chúng lại như các pipe trong Unix.&lt;/p&gt;
&lt;p&gt;Tác giả nhấn mạnh tầm quan trọng của việc tổ chức các quy tắc này trong thư mục .cursor/rules/ và tuân theo quy ước đặt tên nhất quán. Mỗi quy tắc được định nghĩa trong các file .mdc với cấu trúc rõ ràng, bao gồm các bộ lọc (filters) và hành động (actions).&lt;/p&gt;
&lt;p&gt;Một điểm đáng chú ý là khả năng &amp;ldquo;điều chỉnh&amp;rdquo; phản hồi của Cursor thông qua các quy tắc. Ví dụ, khi Cursor liên tục đề xuất giải pháp Bazel trong khi tác giả chỉ muốn sử dụng Nix, ông đã tạo quy tắc &amp;ldquo;no_bazel&amp;rdquo; để ngăn chặn mọi đề xuất liên quan đến Bazel.&lt;/p&gt;
&lt;p&gt;Bài viết cũng giới thiệu cách tự động hóa quy trình phát triển bằng cách kết hợp các quy tắc, như tự động thêm header bản quyền vào file mới hoặc tự động commit sau khi hoàn thành yêu cầu. Tác giả ước tính độ chính xác của các mô hình LLM hiện tại khoảng 45% và cần được điều hướng thường xuyên.&lt;/p&gt;
&lt;p&gt;Tóm lại, bài viết khuyến khích một phương pháp tiếp cận có hệ thống hơn khi sử dụng Cursor AI, tập trung vào việc xây dựng và cải tiến liên tục các quy tắc để tăng hiệu quả và độ chính xác trong quá trình phát triển phần mềm.&lt;/p&gt;
&lt;h2 id="how-do-you-spend-your-time"&gt;&lt;a class="link" href="https://brooker.co.za/blog/2024/02/06/time.html" target="_blank" rel="noopener"
&gt;How Do You Spend Your Time?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Marc Brooker thảo luận về tầm quan trọng của việc quản lý thời gian một cách có ý thức, đặc biệt là trong môi trường công nghệ. Tác giả chỉ ra một &amp;ldquo;failure mode&amp;rdquo; phổ biến: khi các kỹ sư dành quá nhiều thời gian cho các cuộc họp không hiệu quả mà không ai nhận ra vấn đề vì mọi người đều cho rằng người khác đang làm điều đó vì lý do chính đáng.&lt;/p&gt;
&lt;p&gt;Brooker chia sẻ cách ông phân loại thời gian của mình thành các nhóm: công việc cá nhân (viết code, review, debug&amp;hellip;), mentoring và giảng dạy, công việc chiến lược (kế hoạch dài hạn), công việc thường nhật (business reviews, sprint planning&amp;hellip;), học tập (đọc papers, sách&amp;hellip;), và tương tác với khách hàng.&lt;/p&gt;
&lt;p&gt;Tác giả nhấn mạnh rằng việc phân loại không quan trọng bằng việc thực hiện bài tập này một cách có ý thức và suy nghĩ kỹ về cách bạn sử dụng thời gian. Ông cũng khuyến khích áp dụng mô hình tư duy này cho cả tổ chức, đặc biệt là thảo luận về việc phân bổ thời gian cho công việc cá nhân của các kỹ sư ở mỗi cấp độ.&lt;/p&gt;
&lt;p&gt;Cuối cùng, Brooker đề cập đến khái niệm &amp;ldquo;revealed preference&amp;rdquo; (sở thích bộc lộ) trong kinh tế học - lý thuyết cho rằng việc quan sát hành vi tiêu dùng thực tế có thể tiết lộ hàm hữu ích thực sự của người tiêu dùng, khác với những gì họ nói hoặc nghĩ. Ông áp dụng điều này vào cách chúng ta sử dụng thời gian: bạn có thể nói bạn yêu salad, nhưng luôn kết thúc bằng việc gọi burger.&lt;/p&gt;
&lt;h2 id="we-are-destroying-software"&gt;&lt;a class="link" href="https://antirez.com/news/145" target="_blank" rel="noopener"
&gt;We are destroying software&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết ngắn gọn nhưng sâu sắc này, Salvatore Sanfilippo (antirez) - người sáng tạo Redis - bày tỏ những lo ngại về cách chúng ta đang &amp;ldquo;phá hủy&amp;rdquo; phần mềm trong thời đại hiện nay. Ông liệt kê một loạt vấn đề đang làm suy yếu ngành công nghiệp phần mềm:&lt;/p&gt;
&lt;p&gt;Chúng ta không còn quan tâm đến độ phức tạp khi thêm tính năng mới; sử dụng hệ thống build phức tạp; tạo ra chuỗi phụ thuộc vô lý khiến mọi thứ trở nên cồng kềnh và mong manh; khuyên các lập trình viên mới &amp;ldquo;đừng phát minh lại bánh xe&amp;rdquo; trong khi đó lại là cách họ học hỏi; không còn quan tâm đến tính tương thích ngược của API.&lt;/p&gt;
&lt;p&gt;Ông cũng chỉ trích xu hướng viết lại những thứ đang hoạt động tốt; nhảy vào mọi ngôn ngữ, mô hình và framework mới; đánh giá thấp độ khó khi làm việc với thư viện phức tạp; luôn nghĩ tiêu chuẩn thực tế tốt hơn giải pháp tùy chỉnh; cho rằng comment trong code là vô dụng; nhầm lẫn phần mềm với một ngành kỹ thuật thuần túy.&lt;/p&gt;
&lt;p&gt;Cuối cùng, antirez lo ngại rằng chúng ta đang tạo ra những hệ thống không còn khả năng &amp;ldquo;scale down&amp;rdquo; (những việc đơn giản nên được thực hiện đơn giản), tập trung vào tốc độ sản xuất code thay vì thiết kế tốt, và kết quả là chúng ta đang đánh mất niềm vui của việc &amp;ldquo;hacking&amp;rdquo;.&lt;/p&gt;
&lt;h2 id="nontraditional-red-teams"&gt;&lt;a class="link" href="https://zachholman.com/posts/red-teams" target="_blank" rel="noopener"
&gt;Nontraditional Red Teams&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Zach Holman, cựu nhân viên GitHub, giới thiệu khái niệm &amp;ldquo;red teams&amp;rdquo; phi truyền thống - những nhóm người đóng vai trò đối kháng để kiểm tra lỗ hổng trong hệ thống. Ngoài góc độ bảo mật thông thường, Holman đề xuất ba loại &amp;ldquo;red team&amp;rdquo; mà mọi đội phát triển nên có:&lt;/p&gt;
&lt;p&gt;Đầu tiên là &amp;ldquo;Someone to look for dicks&amp;rdquo; - người kiểm tra các thiết kế để đảm bảo không vô tình tạo ra hình ảnh gợi dục hoặc không phù hợp. Holman kể về việc GitHub suýt đặt một biển quảng cáo trông giống hình ảnh khiêu dâm nổi tiếng, và từ đó công ty đã thêm bước &amp;ldquo;dick check&amp;rdquo; vào quy trình thiết kế. Điều này giúp tránh tình huống người dùng bỏ qua sản phẩm vì logo hoặc hình ảnh trông kỳ quặc.&lt;/p&gt;
&lt;p&gt;Loại thứ hai là &amp;ldquo;Someone with an ad blocker&amp;rdquo; - người sử dụng trình chặn quảng cáo để đảm bảo trang web vẫn hoạt động bình thường khi các quảng cáo bị chặn. Holman nhấn mạnh rằng việc một trang web không hoạt động vì người dùng bật ad blocker là một trong những trải nghiệm gây bực bội nhất.&lt;/p&gt;
&lt;p&gt;Cuối cùng là &amp;ldquo;Someone with a password manager&amp;rdquo; - người sử dụng trình quản lý mật khẩu để kiểm tra xem form đăng nhập có hoạt động đúng với các công cụ tự động điền không. Holman chỉ trích nhiều đội phát triển tạo ra form đăng nhập theo cách khiến các trình quản lý mật khẩu như 1Password không thể tự động điền thông tin.&lt;/p&gt;
&lt;p&gt;Tóm lại, Holman cho rằng việc có những người tiếp cận sản phẩm với góc nhìn đối kháng, mới mẻ có thể giúp phát hiện những vấn đề mà đội phát triển dễ bỏ qua khi tập trung vào các tính năng chính.&lt;/p&gt;
&lt;h2 id="ai-or-die"&gt;&lt;a class="link" href="https://www.rkg.blog/ai-or-die.php" target="_blank" rel="noopener"
&gt;AI or Die&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Rahul Gupta-Iwasaki (RKG) cảnh báo về sự thay đổi mạnh mẽ sắp diễn ra trong mọi ngành công nghiệp do AI, bắt đầu bằng việc trích dẫn dự đoán của Dario Amodei (CEO Anthropic) về một tương lai không xa - khoảng 2026 - khi AI có thể trở thành &amp;ldquo;một quốc gia của những thiên tài trong trung tâm dữ liệu&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Theo dự đoán này, AI sẽ thông minh hơn người đoạt giải Nobel trong hầu hết các lĩnh vực, có khả năng tương tác đa phương tiện, thực hiện các nhiệm vụ phức tạp kéo dài nhiều ngày, và có thể được nhân rộng thành hàng triệu bản sao làm việc với tốc độ gấp 10-100 lần con người.&lt;/p&gt;
&lt;p&gt;RKG đặt câu hỏi: Liệu công ty của bạn đã sẵn sàng tận dụng hoặc cạnh tranh với những công ty tận dụng &amp;ldquo;quốc gia thiên tài&amp;rdquo; này chưa? Ông chỉ ra rằng ngay cả hiện tại, AI đã có thể thực hiện một tỷ lệ đáng kể các nhiệm vụ có giá trị kinh tế, nhưng nhiều người vẫn chưa khai thác hết tiềm năng của nó vì ba lý do: thiếu tham vọng (chỉ sử dụng AI cho các tác vụ đơn giản), thiếu kiên nhẫn (không cung cấp đủ ngữ cảnh), và thiếu rõ ràng trong suy nghĩ và giao tiếp.&lt;/p&gt;
&lt;p&gt;Để chuẩn bị cho tương lai này, RKG đề xuất sáu bước hành động:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Dành thời gian tìm hiểu kỹ về khả năng hiện tại và tương lai của AI&lt;/li&gt;
&lt;li&gt;Hình dung và xây dựng phiên bản &amp;ldquo;AI-native&amp;rdquo; của sản phẩm với đội ngũ nhỏ hơn nhiều&lt;/li&gt;
&lt;li&gt;Hiểu rằng khách hàng sẽ có kỳ vọng cao hơn nhiều về sản phẩm tốt hơn và rẻ hơn&lt;/li&gt;
&lt;li&gt;Trở thành chiến lược AI cho khách hàng&lt;/li&gt;
&lt;li&gt;Trở thành công ty &amp;ldquo;AI-first&amp;rdquo; - tương tự như cách Facebook chuyển đổi sang &amp;ldquo;mobile-first&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Xác định vai trò nào sẽ được tăng cường và vai trò nào sẽ bị thay thế bởi AI&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;RKG nhấn mạnh rằng đây không phải là những thay đổi nhỏ mà là sự &amp;ldquo;tái lập&amp;rdquo; toàn diện công ty - một quá trình cực kỳ khó khăn, đặc biệt đối với những công ty lớn và thành công. Tuy nhiên, đây là cách duy nhất để chuẩn bị cho một tương lai mà &amp;ldquo;có lẽ mọi người trên trái đất sẽ có khả năng hoàn thành nhiều việc hơn người có tác động lớn nhất ngày nay&amp;rdquo; (trích dẫn Sam Altman).&lt;/p&gt;</description></item><item><title>Fix lỗi không đăng nhập được Nextcloud từ client khi deploy bằng Coolify</title><link>https://miti99.com/post/2025/03/13/</link><pubDate>Thu, 13 Mar 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/03/13/</guid><description>&lt;p&gt;&lt;em&gt;Chi tiết về Coolify mình sẽ cân nhắc giới thiệu kĩ hơn trong một bài viết riêng. Hôm nay mình sẽ chỉ tập trung vào giải quyết vấn đề mình gặp phải thôi.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="vấn-đề"&gt;Vấn đề
&lt;/h2&gt;&lt;p&gt;Sau khi setup Nextcloud bằng Coolify thành công, bạn đã có thể sử dụng giao diện web bằng ip hoặc domain bình thường. Tuy nhiên khi dùng Nextcloud client để đăng nhập thì sẽ gặp lỗi sau:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The polling URL does not start with HTTPS despite the login URL started with HTTPS. Login will not be possible because this might be a security issue. Please contact your administrator.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2025/03/13/img/1.png"
width="483"
height="58"
srcset="https://miti99.com/post/2025/03/13/img/1_hu_2382326bb1705a5a.png 480w, https://miti99.com/post/2025/03/13/img/1_hu_575d3f1ffefa67bb.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="832"
data-flex-basis="1998px"
&gt;&lt;/p&gt;
&lt;h2 id="cách-khắc-phục"&gt;Cách khắc phục
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;Connect vào termial của Nextcloud.&lt;/li&gt;
&lt;li&gt;Chạy lệnh sau để mở file cấu hình Nextcloud:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nano /config/www/nextcloud/config/config.php
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start="3"&gt;
&lt;li&gt;Update lại như sau:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#39;overwrite.cli.url&amp;#39; =&amp;gt; &amp;#39;https://yourdomain.com&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#39;overwriteprotocol&amp;#39; =&amp;gt; &amp;#39;https&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;em&gt;Thay &lt;code&gt;yourdomain.com&lt;/code&gt; bằng domain của bạn.&lt;/em&gt;&lt;/p&gt;
&lt;ol start="4"&gt;
&lt;li&gt;
&lt;p&gt;Save lại file và restart Nextcloud.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Thử đăng nhập lại từ client.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Cảm ơn bạn đã đọc bài. Chúc bạn thành công!&lt;/p&gt;</description></item><item><title>Newsletter #6</title><link>https://miti99.com/post/2025/03/08/</link><pubDate>Sat, 08 Mar 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/03/08/</guid><description>&lt;i&gt;
Mừng ngày Quốc tế Phụ nữ 8/3, chúc tất cả các bạn nữ một ngày tốt lành, luôn vui tươi và hạnh phúc!
Con gái sinh ra là để yêu thương :&gt;
Chào mừng các bạn đến với Newsletter #6.
&lt;/i&gt;
&lt;h2 id="how-i-use-llms-as-a-staff-engineer"&gt;&lt;a class="link" href="https://www.seangoedecke.com/how-i-use-llms/" target="_blank" rel="noopener"
&gt;How I use LLMs as a staff engineer&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Sean Goedecke, một staff engineer tại GitHub, chia sẻ cách anh tận dụng LLM (Large Language Models) trong công việc hàng ngày. Anh nhấn mạnh rằng, thay vì viết code hoàn toàn, LLM hiệu quả nhất khi được dùng như một công cụ hỗ trợ.&lt;/p&gt;
&lt;p&gt;Cụ thể, anh dùng Copilot cho việc &amp;ldquo;autocomplete&amp;rdquo; code, đặc biệt hữu ích khi làm việc với các ngôn ngữ hoặc vùng kiến thức ít quen thuộc. Với các đoạn code &amp;ldquo;throwaway&amp;rdquo; (chỉ dùng một lần), anh thoải mái dùng LLM để tăng tốc độ. Anh cũng sử dụng LLM như một &amp;ldquo;tutor&amp;rdquo; để học các domain mới, đặt câu hỏi và kiểm tra kiến thức.&lt;/p&gt;
&lt;p&gt;Ngoài ra, LLM còn được dùng để &amp;ldquo;debug&amp;rdquo; ở bước cuối cùng khi đã cạn ý tưởng, hoặc để &amp;ldquo;proofread&amp;rdquo; các tài liệu kỹ thuật dài. Sean không dùng LLM để viết PR (Pull Request) hoàn chỉnh hoặc các tài liệu quan trọng như ADR (Architecture Decision Record).&lt;/p&gt;
&lt;p&gt;Tóm lại, theo Sean, LLM là công cụ giá trị nếu được sử dụng đúng cách, giúp tăng năng suất và học hỏi nhanh hơn, đặc biệt khi làm việc ngoài vùng &amp;ldquo;expertise&amp;rdquo;.&lt;/p&gt;
&lt;h2 id="software-development-topics-i"&gt;&lt;a class="link" href="https://chriskiehl.com/article/thoughts-after-10-years" target="_blank" rel="noopener"
&gt;Software development topics I&amp;rsquo;ve changed my mind on after 10 years in the industry&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Chris Kiehl là một lập trình viên phần mềm hiện đang làm việc tại Amazon. Anh đã viết cuốn sách &amp;ldquo;Lập trình hướng dữ liệu trong Java&amp;rdquo; và tạo ra Gooey, một công cụ chuyển đổi hầu hết các chương trình dòng lệnh Python thành ứng dụng GUI đầy đủ chức năng chỉ với một dòng code. Bốn năm trước, Kiehl đã đăng một danh sách các chủ đề về phát triển phần mềm mà anh đã thay đổi quan điểm sau khi làm việc trong ngành công nghiệp. Đây là một bản cập nhật về quan điểm của Kiehl - những điều anh đã thay đổi suy nghĩ, những ý kiến anh đã tiếp thu trong quá trình làm việc, và những điều anh vẫn giữ nguyên quan điểm.&lt;/p&gt;
&lt;h2 id="looking-under-the-lamppost-on-problem-solving"&gt;&lt;a class="link" href="https://www.edbatista.com/2025/01/looking-under-the-lamppost-on-problem-solving.html" target="_blank" rel="noopener"
&gt;Looking Under the Lamppost (On Problem-Solving)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Ed Batista mở đầu bài viết bằng một câu chuyện ngụ ngôn quen thuộc: một người đàn ông tìm chìa khóa dưới cột đèn, dù biết đã đánh rơi ở chỗ tối hơn. Câu chuyện này là phép ẩn dụ cho cách chúng ta thường tiếp cận việc giải quyết vấn đề. Thay vì đối mặt với vấn đề cần giải quyết, chúng ta lại tập trung vào vấn đề muốn giải quyết.&lt;/p&gt;
&lt;p&gt;Tác giả chỉ ra một số lý do cho hành vi này: vấn đề thực sự có thể nằm ngoài vùng chuyên môn, tốn quá nhiều thời gian, hoặc thậm chí không có lời giải. Thay vì đối mặt với những khó khăn này, chúng ta chọn những vấn đề nhỏ, dễ giải quyết để cảm thấy &amp;ldquo;hiệu quả&amp;rdquo; hoặc để bảo vệ hình ảnh cá nhân.&lt;/p&gt;
&lt;p&gt;Tuy nhiên, việc này kìm hãm sự phát triển của chúng ta. Để mở rộng vùng an toàn, chúng ta cần bước ra khỏi nó. Sự dũng cảm không chỉ là tự tin vào khả năng thành công, mà còn là nhận thức rằng cái giá của việc không thử còn lớn hơn cái giá của thất bại.&lt;/p&gt;
&lt;p&gt;Thất bại không phải là điều đáng sợ, mà là cơ hội để học hỏi và loại trừ các khả năng. Vì vậy, đừng mãi tìm kiếm dưới ánh đèn, hãy dũng cảm đối mặt với bóng tối, nơi những giải pháp thực sự đang chờ đợi.&lt;/p&gt;
&lt;h2 id="sliding-window-log-rate-limiter-redis--java"&gt;&lt;a class="link" href="https://foojay.io/today/sliding-window-log-rate-limiter-redis-java/" target="_blank" rel="noopener"
&gt;Sliding Window Log Rate Limiter (Redis &amp;amp; Java)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này giới thiệu về Sliding Window Log Rate Limiter, một phương pháp chính xác để kiểm soát tốc độ xử lý request. Thay vì chia thời gian thành các khoảng cố định, phương pháp này ghi lại dấu thời gian của từng request, cho phép theo dõi request trong một khoảng thời gian trượt (rolling time period) như giây hoặc phút.&lt;/p&gt;
&lt;p&gt;Bài viết hướng dẫn cách triển khai Sliding Window Log sử dụng Redis và Java, tận dụng command &lt;code&gt;HEXPIRE&lt;/code&gt; mới của Redis 8 để thiết lập thời gian hết hạn cho các field cụ thể trong một hash. Mỗi request (nếu được phép) sẽ được ghi lại bằng timestamp trong Redis hash. Sau đó, đếm số lượng request trong khoảng thời gian cho phép bằng command &lt;code&gt;HLEN&lt;/code&gt;. Nếu vượt quá giới hạn, request mới sẽ bị từ chối.&lt;/p&gt;
&lt;p&gt;Tác giả cũng cung cấp code mẫu Java sử dụng thư viện Jedis để tương tác với Redis, cùng với các test case sử dụng Redis TestContainers, JUnit 5 và AssertJ để đảm bảo rate limiter hoạt động đúng như mong đợi trong nhiều tình huống khác nhau, như kiểm tra số lượng request trong giới hạn, vượt quá giới hạn, sau khi sliding window reset, và xử lý đồng thời nhiều client.&lt;/p&gt;
&lt;h2 id="project-loom-structured-concurrency--java"&gt;&lt;a class="link" href="https://foojay.io/today/project-loom-structured-concurrency-java/" target="_blank" rel="noopener"
&gt;Project Loom: Structured Concurrency – Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giới thiệu về Structured Concurrency, một tính năng mới được giới thiệu trong Java 19 (incubator), Java 21 (preview) và Java 23 (preview) như là một phần của Project Loom. Structured Concurrency giúp đơn giản hóa việc lập trình concurrent bằng cách tạo ra trật tự và tính dễ đoán trong quản lý task.&lt;/p&gt;
&lt;p&gt;Structured Concurrency hoạt động bằng cách chia một task chính thành nhiều subtask đồng thời và task chính không thể hoàn thành cho đến khi các subtask này hoàn tất. API này bao gồm lớp StructuredTaskScope (trong java.util.concurrent), cho phép tạo các subtask bằng StructuredTaskScope::fork và đợi chúng hoàn thành bằng StructuredTaskScope::join.&lt;/p&gt;
&lt;p&gt;Bài viết cũng giới thiệu StructuredTaskScope.ShutdownOnSuccess (hủy các subtask khác khi một subtask thành công) và StructuredTaskScope.ShutdownOnFailure (hủy các subtask khác khi một subtask thất bại). Ngoài ra, có thể debug bằng lệnh jcmd.&lt;/p&gt;
&lt;p&gt;Lợi ích của Structured Concurrency bao gồm đơn giản hóa quản lý task, cải thiện khả năng xử lý lỗi, đảm bảo an toàn tài nguyên và tính dễ đoán. Tính năng này hứa hẹn mang lại các ứng dụng concurrent hiện đại, dễ bảo trì và hiệu quả hơn.&lt;/p&gt;
&lt;h2 id="taking-out-the-trash-in-java"&gt;&lt;a class="link" href="https://medium.com/@benweidig/taking-out-the-trash-in-java-19bcc0c7bd0c" target="_blank" rel="noopener"
&gt;Taking Out the Trash in Java&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này cung cấp một cái nhìn tổng quan về Garbage Collection (GC) trong Java, một cơ chế quản lý bộ nhớ tự động quan trọng của JVM. Thay vì yêu cầu developer tự quản lý việc cấp phát và giải phóng bộ nhớ, GC tự động xác định và thu hồi bộ nhớ không còn được sử dụng, giúp giảm thiểu lỗi và đơn giản hóa quá trình phát triển.&lt;/p&gt;
&lt;p&gt;Bài viết giải thích cách JVM chia bộ nhớ thành các vùng khác nhau như Heap (nơi lưu trữ đối tượng) và Stack (nơi quản lý các lời gọi phương thức và biến cục bộ). Heap lại được chia thành Young Generation (Eden Space và Survivor Spaces) cho các đối tượng mới tạo và Old Generation cho các đối tượng tồn tại lâu hơn.&lt;/p&gt;
&lt;p&gt;Bài viết cũng giới thiệu các loại GC khác nhau có sẵn trong JVM, bao gồm Serial GC, Parallel GC, G1 GC, ZGC, Shenandoah GC và Epsilon GC. Mỗi loại GC có các thuật toán và ưu tiên khác nhau, được tối ưu hóa cho các khối lượng công việc khác nhau. Ví dụ: ZGC được thiết kế để có độ trễ cực thấp, trong khi Parallel GC tập trung vào thông lượng cao.&lt;/p&gt;
&lt;p&gt;Cuối cùng, bài viết cung cấp các mẹo thực tế để giảm thiểu garbage, gỡ lỗi và phân tích GC, cũng như điều chỉnh các cài đặt GC để cải thiện hiệu suất ứng dụng.&lt;/p&gt;
&lt;h2 id="how-precision-time-protocol-handles-leap-seconds"&gt;&lt;a class="link" href="https://engineering.fb.com/2025/02/03/production-engineering/how-precision-time-protocol-ptp-handles-leap-seconds/" target="_blank" rel="noopener"
&gt;How Precision Time Protocol handles leap seconds&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này thảo luận về cách Facebook (Meta) xử lý leap seconds (giây nhuận) trong hệ thống của họ, đặc biệt là với sự gia tăng của Precision Time Protocol (PTP) cho đồng bộ hóa thời gian chính xác trong các trung tâm dữ liệu.&lt;/p&gt;
&lt;p&gt;Trước đây, Meta sử dụng &amp;ldquo;leap second smearing&amp;rdquo; cho NTP (Network Time Protocol), nhưng với PTP, phương pháp này không còn phù hợp do yêu cầu độ chính xác cao hơn (nanosecond). Leap second smearing là quá trình điều chỉnh tốc độ đồng hồ để bù đắp cho giây nhuận.&lt;/p&gt;
&lt;p&gt;Giải pháp của Meta cho PTP là &amp;ldquo;self-smearing&amp;rdquo; bằng thư viện fbclock, sử dụng thuật toán dịch thời gian tự động, stateless và reproducible. Tuy nhiên, phương pháp này vẫn tạo ra sự khác biệt đáng kể giữa các host trong quá trình smearing.&lt;/p&gt;
&lt;p&gt;Do đó, Meta khuyến nghị sử dụng TAI (International Atomic Time) thay vì UTC (Coordinated Universal Time) để tránh phải xử lý giây nhuận. Tuy nhiên, trong nhiều trường hợp, việc chuyển đổi sang UTC vẫn cần thiết.&lt;/p&gt;
&lt;p&gt;Cuối cùng, Meta ủng hộ việc ngừng thêm giây nhuận sau năm 2035 để toàn ngành có thể dựa vào UTC, đơn giản hóa cơ sở hạ tầng và loại bỏ các giải pháp smearing khác nhau. Một tương lai không có giây nhuận sẽ giúp hệ thống đạt được độ chính xác thời gian cao hơn một cách dễ dàng và hiệu quả.&lt;/p&gt;
&lt;h2 id="developer-philosophy"&gt;&lt;a class="link" href="https://qntm.org/devphilo" target="_blank" rel="noopener"
&gt;Developer philosophy&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trình bày triết lý phát triển phần mềm của qntm, một nhà văn khoa học viễn tưởng và nhà phát triển phần mềm. Trong một buổi thảo luận với các nhà phát triển mới, qntm đã chia sẻ bảy nguyên tắc cốt lõi trong triết lý phát triển của mình:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tránh việc viết lại từ đầu&lt;/strong&gt;: Nếu việc viết lại toàn bộ dự án trở nên hấp dẫn, điều đó cho thấy đã có những sai lầm không thể tránh khỏi. Hãy theo dõi các dấu hiệu như nợ kỹ thuật tăng, khó khăn khi thay đổi code, và khó khăn khi ghi chú hoặc giới thiệu cho các nhà phát triển mới.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hoàn thành 90% công việc trong 50% thời gian&lt;/strong&gt;: Nhiều dự án mất 90% thời gian cho 90% công việc đầu tiên và 90% thời gian còn lại cho 10% cuối cùng. Hãy sử dụng thời gian còn lại để cải thiện quy trình hoặc trả nợ kỹ thuật.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tự động hóa các thói quen tốt&lt;/strong&gt;: Thay vì nhắc nhở mọi người thực hiện các hành vi tốt một cách thủ công, hãy tự động hóa chúng bằng cách thêm các kiểm tra tự động hoặc sửa lỗi tự động.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tư duy về dữ liệu bệnh lý&lt;/strong&gt;: Thay vì chỉ tập trung vào trường hợp lý tưởng, hãy nghĩ về cách mọi thứ có thể thất bại và viết code để xử lý các trường hợp đó.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Luôn tìm cách viết code tốt hơn&lt;/strong&gt;: Nếu có thời gian, hãy xem xét lại code để tìm cách cải thiện.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Viết code có thể kiểm thử&lt;/strong&gt;: Code nên có giao diện rõ ràng và ít tác dụng phụ để dễ dàng kiểm thử.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Code không chỉ đúng mà còn phải rõ ràng và dễ hiểu&lt;/strong&gt;: Tránh code hoạt động &amp;ldquo;tình cờ&amp;rdquo; mà không có lý do rõ ràng. Code nên rõ ràng, dễ nhìn và dễ hiểu ngay cả khi không có lỗi.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bài viết này cung cấp một cái nhìn sâu sắc về cách tiếp cận phát triển phần mềm một cách hiệu quả và bền vững&lt;/p&gt;
&lt;h2 id="bonus"&gt;Bonus
&lt;/h2&gt;&lt;h3 id="bonus-1-vài-video-hay-ho-đến-từ-bytebytego"&gt;Bonus 1: Vài video hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=QEzbZKtLi-g" target="_blank" rel="noopener"
&gt;System Design: Why Is Docker Important?&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="bonus-2-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus 2: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/fc4c9cac-3046-4b45-9dd8-7dccc79b4e2c_1280x1608.gif"
loading="lazy"
alt="JWT 101: Key to Stateless Authentication"
&gt;&lt;/p&gt;</description></item><item><title>Ứng dụng GitHub Actions Cache để giảm thời gian build</title><link>https://miti99.com/post/2025/03/07/</link><pubDate>Fri, 07 Mar 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/03/07/</guid><description>&lt;p&gt;Gần đây khi đăng Newsletter, mình có đính kèm nhiều hình ảnh, và khi build với Hugo, Hugo sẽ cần process những hình ảnh này (tạo nhiều ảnh với kích thước khác nhau, nhằm tối ưu thời gian load). Và thời gian build của mình đã tăng lên đáng kể (có khi lên đến tận 4 phút). Để giải quyết vấn đề này, mình đã tìm hiểu và ứng dụng GitHub Action Cache để giảm thời gian build.&lt;/p&gt;
&lt;h2 id="github-actions-cache-là-gì"&gt;GitHub Actions Cache là gì?
&lt;/h2&gt;&lt;p&gt;GitHub Actions Cache là một tính năng của GitHub Actions cho phép bạn lưu trữ các file hoặc thư mục giữa các lần chạy workflow. Điều này giúp tránh việc phải tải lại hoặc tạo lại các dependencies hoặc các file không thay đổi, từ đó giảm đáng kể thời gian chạy workflow.&lt;/p&gt;
&lt;p&gt;Một số trường hợp thường sử dụng cache:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dependencies của dự án (node_modules, vendor, etc.)&lt;/li&gt;
&lt;li&gt;Output của quá trình build (resources, artifacts, etc.)&lt;/li&gt;
&lt;li&gt;Database hoặc các file dữ liệu lớn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tại-sao-cần-tối-ưu-thời-gian-build"&gt;Tại sao cần tối ưu thời gian build?
&lt;/h2&gt;&lt;p&gt;Thực tế khi build hugo, việc build lại toàn bộ site mỗi khi có thay đổi nhỏ có thể tốn nhiều thời gian như mình mô tả ở phần đầu bài. Trong hầu hết các trường hợp, chỉ có một phần nhỏ của website thay đổi, còn lại các resources như hình ảnh, stylesheet đã được xử lý từ lần build trước.&lt;/p&gt;
&lt;p&gt;Đối với Hugo, thư mục &lt;code&gt;resources&lt;/code&gt; chứa các file đã được xử lý như hình ảnh đã được resize, file SCSS đã được biên dịch thành CSS. Việc cache thư mục này giúp tránh phải xử lý lại các file không thay đổi.&lt;/p&gt;
&lt;h2 id="triển-khai-github-actions-cache-với-hugo"&gt;Triển khai GitHub Actions Cache với Hugo
&lt;/h2&gt;&lt;p&gt;Dưới đây là workflow GitHub Actions mình đang sử dụng để triển khai trang web Hugo lên GitHub Pages, với việc áp dụng cache cho thư mục &lt;code&gt;resources&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;span class="lnt"&gt;61
&lt;/span&gt;&lt;span class="lnt"&gt;62
&lt;/span&gt;&lt;span class="lnt"&gt;63
&lt;/span&gt;&lt;span class="lnt"&gt;64
&lt;/span&gt;&lt;span class="lnt"&gt;65
&lt;/span&gt;&lt;span class="lnt"&gt;66
&lt;/span&gt;&lt;span class="lnt"&gt;67
&lt;/span&gt;&lt;span class="lnt"&gt;68
&lt;/span&gt;&lt;span class="lnt"&gt;69
&lt;/span&gt;&lt;span class="lnt"&gt;70
&lt;/span&gt;&lt;span class="lnt"&gt;71
&lt;/span&gt;&lt;span class="lnt"&gt;72
&lt;/span&gt;&lt;span class="lnt"&gt;73
&lt;/span&gt;&lt;span class="lnt"&gt;74
&lt;/span&gt;&lt;span class="lnt"&gt;75
&lt;/span&gt;&lt;span class="lnt"&gt;76
&lt;/span&gt;&lt;span class="lnt"&gt;77
&lt;/span&gt;&lt;span class="lnt"&gt;78
&lt;/span&gt;&lt;span class="lnt"&gt;79
&lt;/span&gt;&lt;span class="lnt"&gt;80
&lt;/span&gt;&lt;span class="lnt"&gt;81
&lt;/span&gt;&lt;span class="lnt"&gt;82
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Deploy site to GitHub Pages&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;push&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;main&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;pull_request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;main&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;read&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;write&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;id-token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;write&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;pages&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cancel-in-progress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;shell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;bash&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;runs-on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;HUGO_VERSION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0.140.2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Install Hugo CLI&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; &amp;amp;&amp;amp; sudo dpkg -i ${{ runner.temp }}/hugo.deb&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Checkout&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/checkout@v4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;submodules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;recursive&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fetch-depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Setup Pages&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pages&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/configure-pages@v5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Restore resources&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/cache/restore@v4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; resources&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${{ runner.os }}-resources-${{ github.run_id }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restore-keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; ${{ runner.os }}-resources-&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Build with Hugo&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;HUGO_CACHEDIR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${{ runner.temp }}/hugo_cache&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;HUGO_ENVIRONMENT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;production&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;TZ&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Asia/Ho_Chi_Minh&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; hugo \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --gc \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --minify \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --baseURL &amp;#34;${{ steps.pages.outputs.base_url }}/&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Save resources&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/cache/save@v4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; resources&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${{ runner.os }}-resources-${{ github.run_id }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Upload artifact&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/upload-pages-artifact@v3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;./public&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;deploy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;github-pages&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${{ steps.deployment.outputs.page_url }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;runs-on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;needs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;build&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Deploy to GitHub Pages&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;deployment&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/deploy-pages@v4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="chi-tiết-về-cách-sử-dụng-cache"&gt;Chi tiết về cách sử dụng cache
&lt;/h3&gt;&lt;p&gt;Trong workflow trên, có hai bước liên quan đến cache:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Restore resources&lt;/strong&gt;: Khôi phục cache từ các lần chạy trước&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Restore resources&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/cache/restore@v4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; resources&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${{ runner.os }}-resources-${{ github.run_id }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restore-keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; ${{ runner.os }}-resources-&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;Save resources&lt;/strong&gt;: Lưu cache mới sau khi build&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Save resources&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/cache/save@v4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; resources&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${{ runner.os }}-resources-${{ github.run_id }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="cách-hoạt-động-của-cache-key"&gt;Cách hoạt động của cache key
&lt;/h3&gt;&lt;p&gt;Các tham số trong phần cache:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;path&lt;/strong&gt;: Đường dẫn đến thư mục hoặc file cần cache, ở đây là thư mục &lt;code&gt;resources&lt;/code&gt; của Hugo&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;key&lt;/strong&gt;: Khóa duy nhất để xác định cache. Format phổ biến là &lt;code&gt;${{ runner.os }}-[cache-name]-[hash]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;restore-keys&lt;/strong&gt;: Danh sách các prefix key để tìm cache phù hợp nếu không tìm thấy cache chính xác&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Trong ví dụ này:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;${{ runner.os }}&lt;/code&gt; đảm bảo cache chỉ được sử dụng trên cùng một hệ điều hành&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resources&lt;/code&gt; là tên của cache&lt;/li&gt;
&lt;li&gt;&lt;code&gt;${{ github.run_id }}&lt;/code&gt; là ID duy nhất của mỗi lần chạy workflow&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Với cách thiết lập này, nếu không tìm thấy cache chính xác với key &lt;code&gt;${{ runner.os }}-resources-${{ github.run_id }}&lt;/code&gt;, GitHub Actions sẽ tìm cache gần nhất có prefix &lt;code&gt;${{ runner.os }}-resources-&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="so-sánh-hiệu-suất"&gt;So sánh hiệu suất
&lt;/h2&gt;&lt;p&gt;Sau khi áp dụng cache, thời gian build của mình đã giảm đáng kể:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Trạng thái&lt;/th&gt;
&lt;th&gt;Thời gian build trung bình&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Không cache&lt;/td&gt;
&lt;td&gt;~4 phút 19 giây&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Có cache&lt;/td&gt;
&lt;td&gt;~25 giây&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Với các dự án lớn hơn, sự chênh lệch thời gian có thể lên đến hàng phút hoặc thậm chí hàng chục phút.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2025/03/07/img/before.png"
width="643"
height="353"
srcset="https://miti99.com/post/2025/03/07/img/before_hu_b15e7434aaa44621.png 480w, https://miti99.com/post/2025/03/07/img/before_hu_c5ade5d06edf8b38.png 1024w"
loading="lazy"
alt="Trước khi cache"
class="gallery-image"
data-flex-grow="182"
data-flex-basis="437px"
&gt;
&lt;img src="https://miti99.com/post/2025/03/07/img/after.png"
width="647"
height="377"
srcset="https://miti99.com/post/2025/03/07/img/after_hu_266ede9be296700e.png 480w, https://miti99.com/post/2025/03/07/img/after_hu_915c8a53063a78eb.png 1024w"
loading="lazy"
alt="Sau khi cache"
class="gallery-image"
data-flex-grow="171"
data-flex-basis="411px"
&gt;&lt;/p&gt;
&lt;h2 id="mở-rộng-cache-các-dependencies-khác"&gt;Mở rộng: Cache các dependencies khác
&lt;/h2&gt;&lt;p&gt;Ngoài việc cache resources của Hugo, bạn có thể áp dụng cách tiếp cận tương tự cho các loại dependencies khác:&lt;/p&gt;
&lt;h3 id="nodejs-dependencies-node_modules"&gt;Node.js dependencies (node_modules)
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Restore node_modules&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/cache/restore@v4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; node_modules&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${{ runner.os }}-node-${{ hashFiles(&amp;#39;**/package-lock.json&amp;#39;) }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restore-keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; ${{ runner.os }}-node-&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="go-modules"&gt;Go modules
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Restore Go modules&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/cache/restore@v4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; ~/go/pkg/mod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${{ runner.os }}-go-${{ hashFiles(&amp;#39;**/go.sum&amp;#39;) }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restore-keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; ${{ runner.os }}-go-&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="tối-ưu-hóa-cache"&gt;Tối ưu hóa cache
&lt;/h2&gt;&lt;p&gt;Để sử dụng cache hiệu quả hơn, bạn có thể xem xét các chiến lược sau:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Cache chọn lọc&lt;/strong&gt;: Chỉ cache các file thực sự cần thiết, tránh cache các file tạm thời hoặc file log&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hash file dependencies&lt;/strong&gt;: Sử dụng hash của file như package-lock.json để tạo key, đảm bảo cache được cập nhật khi dependencies thay đổi&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache layering&lt;/strong&gt;: Sử dụng nhiều cache khác nhau cho các thành phần khác nhau của ứng dụng&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="kết-luận"&gt;Kết luận
&lt;/h2&gt;&lt;p&gt;GitHub Actions Cache là một công cụ mạnh mẽ giúp tối ưu quy trình CI/CD của bạn. Với Hugo, việc cache thư mục &lt;code&gt;resources&lt;/code&gt; giúp giảm đáng kể thời gian build, đặc biệt là khi dự án của bạn có nhiều hình ảnh hoặc stylesheet cần xử lý.&lt;/p&gt;
&lt;p&gt;Đây chỉ là một ví dụ cơ bản về cách sử dụng GitHub Actions Cache. Trong thực tế, tùy thuộc vào dự án cụ thể, bạn có thể cần áp dụng các chiến lược cache phức tạp hơn.&lt;/p&gt;
&lt;p&gt;Nếu bạn muốn tìm hiểu thêm, có thể tham khảo repository của GitHub Actions Cache: &lt;a class="link" href="https://github.com/actions/cache" target="_blank" rel="noopener"
&gt;https://github.com/actions/cache&lt;/a&gt;, hoặc trong document sau: &lt;a class="link" href="https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows" target="_blank" rel="noopener"
&gt;https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hy vọng bài viết này sẽ hữu ích cho bạn trong việc tối ưu quy trình CI/CD của dự án. Nếu bạn có bất kỳ câu hỏi hoặc góp ý nào, đừng ngần ngại để lại comment bên dưới.&lt;/p&gt;
&lt;p&gt;Toàn bộ workflow mình đang sử dụng có thể tìm thấy trong &lt;a class="link" href="https://github.com/tiennm99/tiennm99.github.io" target="_blank" rel="noopener"
&gt;repo GitHub của mình&lt;/a&gt; hoặc bạn có thể copy từ ví dụ trong bài này.&lt;/p&gt;</description></item><item><title>Newsletter #5</title><link>https://miti99.com/post/2025/03/04/</link><pubDate>Tue, 04 Mar 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/03/04/</guid><description>&lt;i&gt;
Chào các bạn, cuối tuần rồi MiTi hơi lười nên không lên bài. Mời các bạn thưởng thức Newsletter #5 nhé!
&lt;/i&gt;
&lt;h2 id="5-advanced-java-reflection-techniques-for-dynamic-programming"&gt;&lt;a class="link" href="https://dev.to/aaravjoshi/5-advanced-java-reflection-techniques-for-dynamic-programming-4ph1" target="_blank" rel="noopener"
&gt;5 Advanced Java Reflection Techniques for Dynamic Programming&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết &amp;ldquo;5 Advanced Java Reflection Techniques for Dynamic Programming&amp;rdquo; của Aarav Joshi đi sâu vào sức mạnh của Java Reflection API, cho phép developer kiểm tra và thao tác cấu trúc của classes và objects trong runtime. Bài viết trình bày 5 kỹ thuật nâng cao: truy cập private members (cẩn trọng); tạo dynamic instances của classes sử dụng tên classes được xác định ở runtime; sử dụng custom annotations để thêm metadata và xử lý nó trong runtime (ví dụ: logging); tạo dynamic proxies để triển khai cross-cutting concerns như logging hoặc transaction management; và thao tác bytecode ở runtime với các thư viện như ByteBuddy để sửa đổi classes trong runtime. Mặc dù các kỹ thuật này mang lại sự linh hoạt và khả năng mở rộng, bài viết nhấn mạnh tầm quan trọng của việc sử dụng chúng một cách thận trọng do các vấn đề tiềm ẩn về maintainability và performance. Reflection là một công cụ mạnh mẽ cho developer Java để tạo ra các ứng dụng dynamic và thích ứng.&lt;/p&gt;
&lt;h2 id="mistakes-you-apparently-just-have-to-make-yourself"&gt;&lt;a class="link" href="https://medium.com/@mcfunley/mistakes-you-apparently-just-have-to-make-yourself-cc2dd2bfc25c" target="_blank" rel="noopener"
&gt;Mistakes You Apparently Just Have to Make Yourself&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết liệt kê những sai lầm mà dường như ai cũng phải tự mình trải qua, bất chấp những lời khuyên. Đó là những &amp;ldquo;kiến thức không thể chuyển giao,&amp;rdquo; những điều bạn phải tự &amp;ldquo;chạm vào bếp nóng&amp;rdquo; mới tin.&lt;/p&gt;
&lt;p&gt;Tác giả đưa ra các ví dụ như: viết lại code từ đầu vì nó quá tệ; nghĩ rằng thêm độ phức tạp vào sẽ giúp phần mềm dễ quản lý hơn; sử dụng công nghệ mới nhất cho một vấn đề chưa từng thấy; tin rằng thêm network hops sẽ làm hệ thống nhanh hơn; nhầm lẫn giữa việc xây dựng hệ thống và dự án mã nguồn mở; viết wrapper cho command line tool; đánh giá thấp sự quan trọng của các khía cạnh khác ngoài lập trình; chỉ tập trung vào functional tests; triển khai code bằng version control tool; nhầm lẫn giữa decoupling logic và separation vật lý; tin rằng quan liêu có thể giải quyết mọi vấn đề hoặc không giải quyết được gì; và gộp code của hai team chỉ vì họ dùng cùng một danh từ.&lt;/p&gt;
&lt;p&gt;Tác giả kết thúc bằng một lời quảng cáo hài hước cho startup Skyliner, như một chiếc &amp;ldquo;áo trói&amp;rdquo; để giúp bạn tránh lặp lại những sai lầm này.&lt;/p&gt;
&lt;h2 id="service-reliability-mathematics"&gt;&lt;a class="link" href="https://addyosmani.com/blog/service-reliability/" target="_blank" rel="noopener"
&gt;Service Reliability Mathematics&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết &amp;ldquo;Service Reliability&amp;rdquo; làm rõ rằng việc đơn giản hóa độ tin cậy dịch vụ thành tỷ lệ phần trăm duy nhất bỏ qua nhiều sắc thái quan trọng. Tác giả Matt Rickard nhấn mạnh rằng không phải tất cả thời gian ngừng hoạt động đều như nhau, và tác động của nó thay đổi theo thời gian và bối cảnh kinh doanh. Mỗi &amp;ldquo;nine&amp;rdquo; (9) bổ sung trong độ tin cậy đòi hỏi nỗ lực kỹ thuật và độ phức tạp hoạt động tăng lên theo cấp số nhân, thường đòi hỏi các thay đổi kiến trúc cơ bản.&lt;/p&gt;
&lt;p&gt;Bài viết chỉ ra những giả định ẩn sau các con số độ tin cậy, chẳng hạn như phân phối đồng đều các lỗi theo thời gian và bỏ qua các tình huống suy giảm một phần. Nó cũng nhấn mạnh các trade-off kỹ thuật liên quan đến việc theo đuổi độ tin cậy cao hơn, chẳng hạn như tốc độ phát triển so với sự ổn định và chi phí so với dự phòng.&lt;/p&gt;
&lt;p&gt;Bài viết kết thúc bằng cách kêu gọi các kỹ sư xem xét tác động kinh doanh thực tế của các loại lỗi khác nhau và tập trung vào việc cung cấp giá trị nhất quán cho người dùng đồng thời duy trì các hoạt động kỹ thuật bền vững, thay vì mù quáng theo đuổi các con số độ tin cậy tùy ý. Các phương pháp tiếp cận hiện đại đang chuyển sang các số liệu sắc thái hơn như error budget và SLO (Service Level Objectives) dựa trên trải nghiệm người dùng.&lt;/p&gt;
&lt;h2 id="how-to-write-a-good-design-document"&gt;&lt;a class="link" href="https://grantslatton.com/how-to-design-document" target="_blank" rel="noopener"
&gt;How to write a good design document&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết &amp;ldquo;How to Design Document&amp;rdquo; đưa ra lời khuyên hữu ích về cách viết tài liệu thiết kế hiệu quả. Tài liệu thiết kế, theo tác giả, là một báo cáo kỹ thuật phác thảo chiến lược triển khai của một hệ thống trong bối cảnh trade-offs và constraints. Mục tiêu chính là thuyết phục người đọc (và quan trọng nhất là chính tác giả) rằng thiết kế này là tối ưu trong tình hình hiện tại.&lt;/p&gt;
&lt;p&gt;Tác giả so sánh việc viết tài liệu thiết kế với việc viết một chứng minh toán học. Để đạt được hiệu quả cao nhất, cần tuân thủ tổ chức tốt, tương tự như tổ chức code. Người viết nên tránh tạo ra &amp;ldquo;spaghetti design docs&amp;rdquo; bằng cách đảm bảo mọi câu văn đều liên kết và dễ hiểu. Mục tiêu là không gây bất ngờ cho người đọc, giúp họ cảm thấy giải pháp rõ ràng ngay cả khi nó đòi hỏi nhiều suy nghĩ phức tạp.&lt;/p&gt;
&lt;p&gt;Bài viết cũng nhấn mạnh tầm quan trọng của việc nắm bắt được tâm lý của người đọc và dự đoán những phản đối có thể xảy ra. Hơn nữa, cần chỉnh sửa để loại bỏ mọi từ ngữ thừa thãi, vì sự chú ý của người đọc là một nguồn tài nguyên hạn chế. Tác giả khuyến khích việc thực hành bằng cách đánh giá các tài liệu khác và chắt lọc ý tưởng thành các tweet ngắn gọn.&lt;/p&gt;
&lt;p&gt;Cuối cùng, bài viết gợi ý tổ chức tài liệu thành các bullet point có thể tóm tắt trong một câu duy nhất và sử dụng footnote cho các chi tiết phức tạp để không làm gián đoạn mạch chính của tài liệu.&lt;/p&gt;
&lt;h2 id="picking-your-battles-when-you-are-hyper-rational"&gt;&lt;a class="link" href="https://newsletter.weskao.com/p/picking-your-battles-hyper-rational" target="_blank" rel="noopener"
&gt;Picking your battles when you are hyper-rational&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Wes Kao chia sẻ về xu hướng phổ biến của những người có tư duy logic cao (hyper-rational operators): tập trung vào việc &amp;ldquo;đúng về mặt kỹ thuật&amp;rdquo; mà bỏ qua hiệu quả thực tế. Bài viết khuyến khích bạn nên suy nghĩ về bức tranh lớn hơn thay vì cố gắng sửa những lỗi nhỏ nhặt hoặc giải thích quá nhiều chi tiết không cần thiết.&lt;/p&gt;
&lt;p&gt;Wes đưa ra hai ví dụ cụ thể: một về việc làm rõ các vấn đề về múi giờ với recruiter, và một về việc giải thích lý do nhầm lẫn với hệ thống thanh toán cho bộ phận tài chính. Trong cả hai trường hợp, Wes gần như đã gửi những email dài dòng, giải thích rõ ràng sự nhầm lẫn, nhưng sau đó nhận ra rằng việc này không mang lại giá trị thực tế.&lt;/p&gt;
&lt;p&gt;Thay vào đó, Wes đã chọn những phản hồi ngắn gọn, tập trung vào việc giải quyết vấn đề trước mắt. Bài viết đặt ra câu hỏi: Liệu lời giải thích này có giúp chúng ta tiến gần hơn đến mục tiêu không? Liệu bối cảnh này có giúp ích cho người khác hay chỉ chứng minh rằng tôi đúng về một điều không quan trọng? Tôi đang phục vụ cuộc trò chuyện, hay cái tôi của mình?&lt;/p&gt;
&lt;p&gt;Bài viết kết luận rằng, mặc dù có những lúc cần làm rõ sự nhầm lẫn, nhưng đối với những vấn đề nhỏ và không quan trọng, tốt hơn hết là nên bỏ qua và tập trung vào mục tiêu chính.&lt;/p&gt;
&lt;h2 id="measuring-programmer-influence-kinda-sorta"&gt;&lt;a class="link" href="https://tidyfirst.substack.com/p/measuring-programmer-influence-kinda" target="_blank" rel="noopener"
&gt;Measuring Programmer Influence, Kinda Sorta&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Craig Tataryn từ Tidy First thảo luận về cách sử dụng dữ liệu để đánh giá đóng góp của lập trình viên trong một team lớn, dù ông khẳng định không có câu trả lời đáng tin cậy và rõ ràng. Dữ liệu chỉ có thể cung cấp gợi ý về các loại tác động nhất định từ những hành vi cụ thể. Ông cảnh báo rằng việc sử dụng dữ liệu này để xếp hạng, sa thải, thăng chức hoặc thưởng sẽ làm mất đi tính tin cậy của nó ngay lập tức.&lt;/p&gt;
&lt;p&gt;Phân tích dựa trên dữ liệu từ dự án React cho thấy việc tạo file và thay đổi file tuân theo phân phối Pareto, tức là một số ít lập trình viên tạo ra phần lớn các file và những file này cũng được thay đổi nhiều nhất. Để xác định những người có ảnh hưởng đáng kể, tác giả kết hợp cả số lượng file được tạo và số lần các file đó được người khác thay đổi. Những người tạo nhiều file mà những file đó được chỉnh sửa nhiều sẽ được coi là có ảnh hưởng lớn hơn.&lt;/p&gt;
&lt;p&gt;Ông đưa ra một số cách sử dụng tốt dữ liệu này, như xác định vị trí của bạn so với đồng nghiệp, tìm người để mentor, hoặc xác định những người có ít quyền lực hơn so với tác động thực tế của họ. Tuy nhiên, ông cũng cảnh báo về những cách sử dụng xấu, như dùng dữ liệu để thưởng, đặt hạn ngạch, thăng chức hoặc sa thải. Ông nhấn mạnh rằng nhiều đóng góp quan trọng không thể được ghi lại bằng số liệu và việc quá tập trung vào số liệu có thể dẫn đến những hành vi không mong muốn.&lt;/p&gt;
&lt;p&gt;Tóm lại, bài viết khuyến khích sử dụng dữ liệu một cách cẩn thận và luôn ghi nhớ mục tiêu thực sự là tạo ra tác động tích cực, thay vì chỉ tập trung vào số liệu.&lt;/p&gt;
&lt;h2 id="building-personal-software-with-claude"&gt;&lt;a class="link" href="https://blog.nelhage.com/post/personal-software-with-claude/" target="_blank" rel="noopener"
&gt;Building personal software with Claude&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Trong bài viết này, tác giả chia sẻ trải nghiệm sử dụng Claude để chuyển một phần của Emacs package sang Rust, giúp giảm thời gian thực thi từ 90 giây xuống còn 15ms. Điều đáng nói là Claude đã thực hiện gần như toàn bộ dự án dưới sự giám sát của tác giả mà không cần anh phải viết nhiều code.&lt;/p&gt;
&lt;p&gt;Ban đầu, tác giả chỉ kỳ vọng Claude sẽ là một công cụ hỗ trợ nhỏ, tương tự như một công cụ tìm kiếm tài liệu tốt hơn và Stack Overflow. Tuy nhiên, Claude đã vượt xa những kỳ vọng đó. Tác giả đã tải file obsidian.el lên và yêu cầu Claude viết một chương trình Rust để tăng tốc hàm obsidian-update. Claude đã đọc khoảng 1000 dòng Emacs Lisp, xác định 200 dòng liên quan, thiết kế định dạng JSON và chuyển logic sang khoảng 150 dòng Rust. Mã này thậm chí còn biên dịch và chạy ngay lần đầu tiên.&lt;/p&gt;
&lt;p&gt;Tác giả cũng yêu cầu Claude viết code Emacs để sử dụng chương trình Rust, sử dụng tính năng &amp;ldquo;advice&amp;rdquo; để vá obsidian.el. Kết quả cũng rất ấn tượng, chỉ có một lỗi nhỏ được Claude sửa nhanh chóng. Toàn bộ dự án chỉ mất một buổi chiều.&lt;/p&gt;
&lt;p&gt;Tác giả nhấn mạnh rằng LLM đang cải thiện với tốc độ chóng mặt và việc sử dụng chúng giúp giảm chi phí code. Tuy nhiên, sự hiểu biết về code, kiến trúc tốt và thiết kế vẫn rất quan trọng. Ông cũng gợi ý rằng có thể sẽ trở nên quan trọng hơn bao giờ hết khi viết code dễ xóa để có thể yêu cầu LLM tạo lại từ đầu khi cần thiết.&lt;/p&gt;
&lt;p&gt;Tóm lại, bài viết cho thấy tiềm năng của LLM trong việc giúp các nhà phát triển xây dựng phần mềm cá nhân một cách nhanh chóng và hiệu quả, đồng thời giải phóng họ khỏi những công việc nhàm chán như xử lý các hệ thống xác thực phức tạp và cập nhật các framework mới nhất.&lt;/p&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/1112c07d-db40-484e-917b-0071ed7cf354_1280x1532.gif"
loading="lazy"
alt="Git vs GitHub"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/5fd8bdda-52dd-454f-be79-ad548f17810b_1280x1557.gif"
loading="lazy"
alt="A Cheatsheet on Database Performance"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/35ae3f82-afa0-47b9-a2a0-58b6c6d8cfb1_1280x1476.gif"
loading="lazy"
alt="18 Common Ports Worth Knowing"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #4</title><link>https://miti99.com/post/2025/02/27/</link><pubDate>Thu, 27 Feb 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/02/27/</guid><description>&lt;i&gt;
Chào các bạn, tuần rồi mình có tìm thấy kha khá bài, nhưng cho vào cùng một newsletter thì lại quá dài. Nên hôm nay mình đăng thêm 1 newsletter giữa tuần nữa nhé ^^.
&lt;/i&gt;
&lt;h2 id="management-mantras"&gt;&lt;a class="link" href="https://blog.staysaasy.com/p/management-mantras" target="_blank" rel="noopener"
&gt;Management Mantras&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này tập trung vào những nguyên tắc quản lý quan trọng để xây dựng một môi trường làm việc hiệu quả và trách nhiệm. Dưới đây là một số điểm chính:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Đừng &amp;ldquo;ban ơn&amp;rdquo; cho ai: Mọi người nên tập trung vào công việc quan trọng nhất của họ và được hỗ trợ bởi những người có trách nhiệm. Việc &amp;ldquo;giúp đỡ&amp;rdquo; có thể là dấu hiệu của sự nhầm lẫn, thiếu sót trong quy trình hoặc làm việc không hiệu quả.&lt;/li&gt;
&lt;li&gt;Nhân viên không cần lòng thương hại: Các công ty không nên tỏ ra ban phát cho nhân viên. Thay vào đó, hãy coi những gì bạn làm cho nhân viên là phần thưởng xứng đáng hoặc là một phần trách nhiệm của bạn để hỗ trợ đội ngũ.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Tôi có thể sửa nó&amp;rdquo;: Đừng đổ lỗi cho người khác khi mọi việc không thành công. Hãy chịu trách nhiệm và tìm cách giải quyết vấn đề. Nếu các dự án bạn tham gia liên tục thất bại, bạn cần xem xét lại năng lực của mình.&lt;/li&gt;
&lt;li&gt;Quản lý là công việc hàng ngày: Quản lý hiệu quả đòi hỏi sự nỗ lực liên tục để thúc đẩy mọi người, giải quyết xung đột và đưa ra phản hồi. Đó là sự tích lũy của những hành động nhỏ hàng ngày chứ không phải những quyết định lớn hiếm hoi.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-ultimate-guide-to-programming-languages-choosing-the-right-tool-for-the-job"&gt;&lt;a class="link" href="https://dev.to/mohammad-reza-mahdiani/the-ultimate-guide-to-programming-languages-choosing-the-right-tool-for-the-job-4be2" target="_blank" rel="noopener"
&gt;The Ultimate Guide to Programming Languages: Choosing the Right Tool for the Job&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này cung cấp một cái nhìn tổng quan về một số ngôn ngữ lập trình phổ biến nhất trong năm 2025, giúp người đọc đưa ra quyết định sáng suốt khi lựa chọn ngôn ngữ phù hợp cho dự án của mình.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Python:&lt;/strong&gt; Dễ học, đa năng, phù hợp cho machine learning, khoa học dữ liệu, phát triển web, và tự động hóa.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JavaScript:&lt;/strong&gt; &amp;ldquo;Ông vua&amp;rdquo; của web, không thể thiếu cho phát triển giao diện người dùng, full-stack development (với Node.js) và ứng dụng đa nền tảng (với Electron và React Native).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java:&lt;/strong&gt; &amp;ldquo;Trâu cày&amp;rdquo; của doanh nghiệp, ổn định, có khả năng mở rộng cao, bảo mật, phù hợp cho các ứng dụng quy mô lớn, phát triển Android và backend.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C++:&lt;/strong&gt; &amp;ldquo;Cường quốc hiệu năng&amp;rdquo;, thích hợp cho hệ thống lập trình, game engine, và các ứng dụng thời gian thực.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rust:&lt;/strong&gt; Ngôi sao đang lên, tập trung vào an toàn bộ nhớ và hiệu năng cao, phù hợp cho hệ thống lập trình, WebAssembly và mật mã.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Xu hướng năm 2025:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Python vẫn là dẫn đầu trong machine learning, nhưng Julia đang nổi lên trong các tác vụ quan trọng về hiệu năng.&lt;/li&gt;
&lt;li&gt;Solidity và Rust là những người chơi chính trong lĩnh vực blockchain.&lt;/li&gt;
&lt;li&gt;Kotlin Multiplatform và Flutter (Dart) đang được ưa chuộng để thống nhất phát triển ứng dụng di động, web và desktop.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tóm lại:&lt;/strong&gt; Bài viết nhấn mạnh rằng việc lựa chọn ngôn ngữ lập trình phù hợp phụ thuộc vào yêu cầu của dự án, kinh nghiệm của nhóm và mục tiêu dài hạn. Mặc dù không có ngôn ngữ nào phù hợp với mọi trường hợp, nhưng việc hiểu rõ điểm mạnh và hạn chế của từng ngôn ngữ có thể giúp đưa ra quyết định thông minh hơn.&lt;/p&gt;
&lt;h2 id="discovery-coding"&gt;&lt;a class="link" href="https://jimmyhmiller.github.io/discovery-coding" target="_blank" rel="noopener"
&gt;Discovery Coding&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giới thiệu &amp;ldquo;Discovery Coding&amp;rdquo; (tạm dịch: Lập trình khám phá) như một phương pháp tiếp cận vấn đề bằng cách viết code trước, thay vì cố gắng thiết kế hoặc suy nghĩ trước. Tác giả so sánh phương pháp này với việc &amp;ldquo;viết khám phá&amp;rdquo; trong văn học, nơi tác giả khám phá ra câu chuyện trong quá trình viết.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Khái niệm &amp;ldquo;Discovery Coding&amp;rdquo;&lt;/strong&gt;: Thay vì bắt đầu với một kế hoạch chi tiết, người lập trình khám phá suy nghĩ về bối cảnh, các mối quan hệ trong hệ thống và viết code để hiểu rõ vấn đề.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Đối lập với &amp;ldquo;Outlining&amp;rdquo;&lt;/strong&gt;: Discovery Coding trái ngược với phương pháp lập trình dựa trên outline, nơi người lập trình lập kế hoạch chi tiết trước khi viết code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Không phải là Bottom-Up Design&lt;/strong&gt;: Tác giả nhấn mạnh rằng Discovery Coding không giống với thiết kế từ dưới lên (bottom-up design).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lợi ích:&lt;/strong&gt; Ngay cả đối với những người thích lập trình theo outline, Discovery Coding có thể giúp tránh việc áp dụng các giải pháp quen thuộc và buộc họ phải hiểu rõ các ràng buộc của hệ thống.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Công cụ hỗ trợ:&lt;/strong&gt; Các công cụ hỗ trợ lập trình trực tiếp trong một hệ thống đang chạy (live programming) và trực quan hóa code có thể rất hữu ích cho người lập trình khám phá.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lời kêu gọi:&lt;/strong&gt; Tác giả kêu gọi cộng đồng lập trình chấp nhận và tôn trọng sự khác biệt trong cách tư duy của mỗi người, và không nên coi phương pháp tiếp cận kém tổ chức hơn là một phương pháp kém hiệu quả.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tóm lại:&lt;/strong&gt; Bài viết giới thiệu một phương pháp tiếp cận lập trình mới, tập trung vào việc khám phá và hiểu vấn đề thông qua quá trình viết code, và khuyến khích sự chấp nhận sự đa dạng trong cách tư duy của các lập trình viên.&lt;/p&gt;
&lt;h2 id="building-a-best-selling-game-with-a-tiny-team"&gt;&lt;a class="link" href="https://newsletter.pragmaticengineer.com/p/thronefall" target="_blank" rel="noopener"
&gt;Building a best-selling game with a tiny team&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này tóm tắt một tập của podcast &amp;ldquo;The Pragmatic Engineer&amp;rdquo; với khách mời Jonas Tyroller, một trong hai nhà phát triển của trò chơi indie thành công &amp;ldquo;Thronefall&amp;rdquo;. Thronefall là một trò chơi chiến lược tối giản kết hợp phòng thủ tháp và xây dựng vương quốc, đã bán được 1 triệu bản trong năm đầu tiên ra mắt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Thành công của Thronefall:&lt;/strong&gt; Một trò chơi indie được phát triển bởi chỉ hai người đã bán được 1 triệu bản, chứng tỏ tiềm năng của thị trường game indie.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kỹ năng đa dạng:&lt;/strong&gt; Để thành công trong vai trò nhà phát triển game indie, cần có nhiều kỹ năng khác nhau, bao gồm thiết kế, phát triển, sáng tác nhạc, marketing và xây dựng cộng đồng.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Không cần tuân thủ nghiêm ngặt các best practices:&lt;/strong&gt; Các best practices trong kỹ thuật phần mềm như code review và unit test không phải lúc nào cũng cần thiết cho các game indie nhỏ.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Xây dựng nhiều game:&lt;/strong&gt; Để trở nên giỏi trong việc xây dựng game, cần xây dựng nhiều game khác nhau, từ đơn giản đến phức tạp.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Công cụ hỗ trợ:&lt;/strong&gt; Các công cụ như Unity giúp việc xây dựng game trở nên dễ dàng hơn bao giờ hết.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pathfinding:&lt;/strong&gt; Một trong những thách thức lớn nhất trong quá trình phát triển Thronefall là tìm đường đi (pathfinding) cho các đơn vị trong game.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ChatGPT:&lt;/strong&gt; ChatGPT có thể được sử dụng để tạo code khung, dịch code và trả lời các câu hỏi về các chủ đề không quen thuộc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tìm sự cân bằng:&lt;/strong&gt; Để thành công, game indie cần tìm được sự cân bằng giữa sở thích cá nhân và tính thị trường.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tóm lại:&lt;/strong&gt; Bài viết cung cấp cái nhìn sâu sắc về quá trình phát triển game indie, nhấn mạnh tầm quan trọng của sự đa năng, khả năng thích ứng và sự hiểu biết về thị trường. Nó cũng cho thấy rằng các công cụ và kỹ thuật mới có thể giúp các nhà phát triển game indie tạo ra các sản phẩm thành công.&lt;/p&gt;
&lt;h2 id="serving-a-billion-web-requests-with-boring-code"&gt;&lt;a class="link" href="https://notes.billmill.org/blog/2024/06/Serving_a_billion_web_requests_with_boring_code.html" target="_blank" rel="noopener"
&gt;Serving a billion web requests with boring code&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết chia sẻ kinh nghiệm xây dựng hệ thống API phục vụ hàng triệu người dùng mỗi ngày cho trang web so sánh kế hoạch Medicare của chính phủ Mỹ. Tác giả nhấn mạnh tầm quan trọng của việc sử dụng các công nghệ &amp;ldquo;nhàm chán&amp;rdquo; (đã được chứng minh và đáng tin cậy) và tập trung vào sự đơn giản, rõ ràng trong thiết kế và code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ưu tiên sự &amp;ldquo;nhàm chán&amp;rdquo;:&lt;/strong&gt; Tác giả coi việc lựa chọn công nghệ &amp;ldquo;nhàm chán&amp;rdquo; (boring technology) là kim chỉ nam. Các công nghệ được chọn bao gồm:&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Postgres:&lt;/strong&gt; Nền tảng cơ sở dữ liệu đáng tin cậy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Golang:&lt;/strong&gt; Ngôn ngữ lập trình hiệu quả, đơn giản và dễ học.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React:&lt;/strong&gt; Framework frontend phổ biến và được biết đến rộng rãi.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kiến trúc module:&lt;/strong&gt; Backend được chia thành ba module lớn (druginfo, planinfo, beneinfo), mỗi module có cơ sở dữ liệu riêng và giao tiếp qua gRPC.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;gRPC:&lt;/strong&gt; Mặc dù có một số khó khăn với tooling, gRPC giúp định nghĩa interface bằng code và tạo các công cụ, interface thay đổi đồng bộ. grpc-gateway cho phép phục vụ các yêu cầu web.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tính tương thích ngược:&lt;/strong&gt; Tuân thủ nghiêm ngặt yêu cầu tương thích ngược, chỉ thêm và không xóa các trường khỏi interface và cơ sở dữ liệu.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tìm kiếm faceted:&lt;/strong&gt; Sử dụng Postgres để triển khai tìm kiếm faceted bằng cách xây dựng chuỗi truy vấn SQL dựa trên các điều kiện.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ETL:&lt;/strong&gt; Quy trình ETL được tự động hóa bằng shell script và cron job, tạo cơ sở dữ liệu mới hàng ngày từ dữ liệu đầu vào.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logging:&lt;/strong&gt; Sử dụng request ID để theo dõi các yêu cầu và zerolog để ghi log.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Documentation:&lt;/strong&gt; Tạo một cuốn sách về cách hệ thống hoạt động bằng Sphinx, được đồng nghiệp đóng góp và sử dụng rộng rãi.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Bài học:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chất lượng phần mềm có thể được viết dưới các ràng buộc của chính phủ.&lt;/li&gt;
&lt;li&gt;Sự đơn giản, rõ ràng và các công nghệ đã được chứng minh có thể giúp xây dựng các hệ thống quy mô lớn.&lt;/li&gt;
&lt;li&gt;Đội ngũ làm việc tích cực, sáng tạo và gắn kết là yếu tố quan trọng để thành công.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="java-language-evolution-in-2025---inside-java-newscast-84"&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=dPzle3EN4CM" target="_blank" rel="noopener"
&gt;Java Language Evolution in 2025 - Inside Java Newscast #84&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Video này trình bày các hướng phát triển của ngôn ngữ Java trong năm 2025, tập trung vào các cải tiến và tính năng mới được phát triển thông qua Project Amber.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Điểm chính:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Project Amber:&lt;/strong&gt; Giới thiệu về Project Amber và mục tiêu cải thiện Java.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexible Constructor Bodies (Thân hàm tạo linh hoạt):&lt;/strong&gt; Cho phép thực hiện các lệnh trước khi gọi &lt;code&gt;super()&lt;/code&gt; hoặc &lt;code&gt;this()&lt;/code&gt; trong hàm tạo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simplified Main (Hàm main đơn giản hóa):&lt;/strong&gt; Giúp viết code Java dễ dàng hơn, đặc biệt là cho các script nhỏ.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Module Imports (Nhập module):&lt;/strong&gt; Đơn giản hóa việc quản lý và sử dụng các module.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Primitive Patterns (Pattern cho kiểu dữ liệu nguyên thủy):&lt;/strong&gt; Cải thiện khả năng sử dụng pattern matching với các kiểu dữ liệu nguyên thủy trong &lt;code&gt;instanceof&lt;/code&gt; và &lt;code&gt;switch&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deconstruction (Phân rã cấu trúc):&lt;/strong&gt; Khám phá tiềm năng của việc phân rã cấu trúc để trích xuất dữ liệu từ các đối tượng.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Withers:&lt;/strong&gt; Thảo luận về việc sử dụng &amp;ldquo;withers&amp;rdquo; để tạo các bản sao của record với các giá trị đã sửa đổi.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;String Templates (Chuỗi mẫu):&lt;/strong&gt; Cập nhật về tiến độ phát triển của tính năng chuỗi mẫu.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Miscellaneous Work (Các công việc khác):&lt;/strong&gt; Đề cập đến các công việc khác, bao gồm cải tiến serialization.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tóm lại:&lt;/strong&gt; Video cung cấp một cái nhìn tổng quan về các cải tiến quan trọng dự kiến sẽ có mặt trong Java năm 2025, giúp các nhà phát triển Java nắm bắt được hướng phát triển của ngôn ngữ và tận dụng các tính năng mới.&lt;/p&gt;
&lt;h2 id="valhalla---java"&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=Dhn-JgZaBWo" target="_blank" rel="noopener"
&gt;Valhalla - Java&amp;rsquo;s Epic Refactor&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Video cung cấp một bản cập nhật chi tiết về Project Valhalla, một dự án quan trọng nhằm hiện đại hóa hệ thống kiểu của Java, mang lại hiệu năng tốt hơn và đơn giản hóa việc lập trình. Brian Goetz giải thích các tính năng mới và mục tiêu của dự án.&lt;/p&gt;
&lt;h2 id="protecting-your-time-from-predators-in-large-tech-companies"&gt;&lt;a class="link" href="https://registerspill.thorstenball.com/p/how-might-ai-change-programming" target="_blank" rel="noopener"
&gt;Protecting your time from predators in large tech companies&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết đặt ra nhiều câu hỏi thú vị về tương lai của lập trình dưới tác động của AI, nhấn mạnh rằng AI sẽ thay đổi cách chúng ta viết code, nhưng vẫn chưa rõ chính xác như thế nào.&lt;/p&gt;
&lt;h2 id="hands-on-career-the-evolution-of-a-java-champion"&gt;&lt;a class="link" href="https://blog.vanillajava.blog/2025/01/hands-on-career-evolution-of-java.html" target="_blank" rel="noopener"
&gt;Hands-On Career: The Evolution of a Java Champion&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết khám phá cách AI tạo sinh có thể hỗ trợ các nhà phát triển trong việc phát triển sự nghiệp, đồng thời nhấn mạnh tầm quan trọng của việc sử dụng AI một cách có ý thức, đánh giá kết quả cẩn thận và tiếp tục phát triển các kỹ năng cần thiết để thành công trong kỷ nguyên AI. Nó cũng nêu bật tầm quan trọng của việc hiểu rõ các hạn chế của AI và sử dụng nó như một công cụ hỗ trợ, thay vì một sự thay thế hoàn toàn cho trí tuệ con người.&lt;/p&gt;
&lt;h2 id="token-bucket-rate-limiter-redis--java"&gt;&lt;a class="link" href="https://foojay.io/today/token-bucket-rate-limiter-redis-java/" target="_blank" rel="noopener"
&gt;Token Bucket Rate Limiter (Redis &amp;amp; Java)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết cung cấp hướng dẫn chi tiết về cách triển khai thuật toán Token Bucket Rate Limiter bằng Redis và Java, bao gồm cả ví dụ code, cách thiết lập môi trường kiểm thử và các test case để đảm bảo tính chính xác.&lt;/p&gt;
&lt;h2 id="bonus"&gt;Bonus?
&lt;/h2&gt;&lt;p&gt;Huhu, đợt này hỏng có bonus nào hết nha mọi người :&amp;lt;&lt;/p&gt;</description></item><item><title>Git LFS: Trường hợp sử dụng, hạn chế, cách gỡ bỏ và các giải pháp thay thế</title><link>https://miti99.com/post/2025/02/26/</link><pubDate>Tue, 25 Feb 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/02/26/</guid><description>&lt;p&gt;Ngoài source code, đôi khi chúng ta cũng sẽ lưu trữ các assets như hình ảnh, âm thanh, video, file data, output lớn,&amp;hellip; trong repository của mình. Các file này có thể rất nặng, và việc lưu trữ chúng trong Git repository sẽ làm tăng kích thước của repository, làm chậm quá trình clone, push, pull, fetch,&amp;hellip; Để giải quyết vấn đề này, Git Large File Storage (Git LFS) ra đời. Trong bài viết này, mình sẽ giới thiệu về Git LFS, trường hợp sử dụng, hạn chế, cách gỡ bỏ và các giải pháp thay thế.&lt;/p&gt;
&lt;h2 id="1-git-lfs-là-gì"&gt;1. Git LFS là gì?
&lt;/h2&gt;&lt;p&gt;Git LFS là một extension của Git, giúp quản lý các file lớn (large files) trong repository. Thay vì lưu trữ toàn bộ nội dung của file trong repository, Git LFS sẽ lưu trữ file lớn trong một remote server (thường là server riêng của Git LFS) và chỉ lưu trữ metadata của file trong repository. Khi cần sử dụng file, Git LFS sẽ tải file từ remote server về máy local.&lt;/p&gt;
&lt;h2 id="2-trường-hợp-sử-dụng-git-lfs"&gt;2. Trường hợp sử dụng Git LFS
&lt;/h2&gt;&lt;p&gt;Git LFS thích hợp cho các trường hợp sau:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quản lý file media và dữ liệu lớn:&lt;/strong&gt; Khi dự án cần lưu trữ các file hình ảnh, âm thanh, video, dataset hay file phân tích có kích thước lớn, Git LFS giúp quản lý chúng hiệu quả mà không làm tăng đáng kể kích thước repository.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lưu trữ file nhị phân và build artifacts:&lt;/strong&gt; Các file nhị phân, thư viện, file thực thi hoặc build output có thể được lưu trữ trong Git LFS để giảm tải cho repository chính.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dự án với file lớn ít thay đổi:&lt;/strong&gt; Đối với các file lớn nhưng ít khi được chỉnh sửa, Git LFS là giải pháp lý tưởng để duy trì khả năng truy cập đồng thời giảm tải cho hoạt động Git thông thường.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Lúc trước khi làm website cho &lt;a class="link" href="https://ngamtheprojec.github.io" target="_blank" rel="noopener"
&gt;Ngăm&lt;/a&gt;, mình đã sử dụng Git LFS để lưu trữ các video của nhóm. Do GitHub giới hạn kích thước file là 100MB, nên muốn lưu trữ video có kích thước lớn, mình đã sử dụng Git LFS. Đây là một sai lầm của mình.&lt;/p&gt;
&lt;h2 id="3-hạn-chế-của-git-lfs"&gt;3. Hạn chế của Git LFS
&lt;/h2&gt;&lt;p&gt;Mặc dù Git LFS giúp giảm tải cho repository, nhưng nó cũng có một số hạn chế:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giới hạn bandwidth và storage trên GitHub:&lt;/strong&gt; GitHub Free chỉ cung cấp 1GB storage và 1GB bandwidth/tháng cho Git LFS. Vượt quá giới hạn này sẽ phát sinh chi phí bổ sung.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vấn đề với GitHub Pages:&lt;/strong&gt; Khi triển khai GitHub Pages từ repository sử dụng LFS, các file LFS không được xử lý đúng cách, dẫn đến các liên kết bị hỏng và nội dung không hiển thị.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quá trình gỡ bỏ phức tạp:&lt;/strong&gt; Sau khi đã sử dụng Git LFS, việc loại bỏ nó khỏi repository là một quá trình khó khăn và tiềm ẩn nhiều rủi ro.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Vì bị hạn chế băng thông, nên mình nhớ rằng mình chỉ clone repository vài lần là đã hết băng thông rồi. Điều này khiến mình phải tìm cách gỡ bỏ Git LFS khỏi repository.&lt;/p&gt;
&lt;h2 id="4-cách-gỡ-bỏ-git-lfs"&gt;4. Cách gỡ bỏ Git LFS
&lt;/h2&gt;&lt;p&gt;Để gỡ bỏ Git LFS khỏi repository, bạn cần thực hiện các bước sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git lfs uninstall
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git rm --cached &lt;span class="s2"&gt;&amp;#34;*.mp4&amp;#34;&lt;/span&gt; &lt;span class="c1"&gt;# Thay thế bằng các tập tin bạn đã theo dõi với LFS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Chỉnh sửa tập tin .gitattributes để loại bỏ các mục có liên quan đến LFS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git add .gitattributes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git commit -m &lt;span class="s2"&gt;&amp;#34;remove: Git LFS&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git push
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Lưu ý:&lt;/strong&gt; Quá trình này có thể phức tạp hơn nếu kho lưu trữ của bạn đã có lịch sử với Git LFS. Trong trường hợp đó, bạn có thể cần phải tạo một kho lưu trữ mới và chuyển lịch sử không LFS của bạn sang đó.&lt;/p&gt;
&lt;p&gt;Ngoài ra có trường hợp bạn sẽ phải tạo request với GitHub support để xoá các file LFS đã lưu trữ trên Git LFS của repository.&lt;/p&gt;
&lt;h2 id="5-giải-pháp-thay-thế"&gt;5. Giải pháp thay thế
&lt;/h2&gt;&lt;p&gt;Thay vì sử dụng Git hoặc Git LFS cho các tập tin lớn, thì lời khuyên của mình là nên tách source code và các file lớn với nhau. VD: up video lên YouTube, up hình ảnh lên Imgur,&amp;hellip; và chia sẻ link trong repository.&lt;/p&gt;
&lt;p&gt;Khi làm website cho Ngăm, mình đã chạy tool optimize file size của các video xuống dưới ngưỡng 100MB để có thể lưu trữ trên GitHub. Điều này giúp mình không phải sử dụng Git LFS và không phải lo lắng về vấn đề băng thông.&lt;/p&gt;</description></item><item><title>TaskBus - Phân phối task vào executor trong java</title><link>https://miti99.com/post/2025/02/25/</link><pubDate>Tue, 25 Feb 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/02/25/</guid><description>&lt;p&gt;Khi phát triển game server, chúng ta thường sử dụng observer pattern để xử lý các task nhỏ lẻ, vd như các request từ client, event từ server,&amp;hellip; khi muốn notify sang nhiều module khác nhau&lt;/p&gt;
&lt;p&gt;VD khi user thanh toán thành công, chúng ta cần notify sang module resource để cập nhật tài nguyên user đã mua; module segment để update segment pay mới của user; module metric để ghi log;&amp;hellip;&lt;/p&gt;
&lt;p&gt;Để tối ưu performance, chúng ta có thể sử dụng thread pool với số thread lớn để có thể xử lý task cùng lúc. Tuy nhiên đôi lúc ta sẽ muốn kiểm soát thứ tự thực thi các task của cùng một user, tránh trường hợp task A chạy trước task B mà task B cần dữ liệu từ task A, hoặc gây khó khăn khi xử lý concurrent data. Bài viết này MiTi sẽ giới thiệu về TaskBus, một cách phân phối task vào executor một cách kiểm soát, đảm bảo thứ tự thực thi các task của một user.&lt;/p&gt;
&lt;h2 id="các-class-cơ-bản"&gt;Các class cơ bản
&lt;/h2&gt;&lt;p&gt;Đầu tiên chúng ta có &lt;code&gt;Task&lt;/code&gt; là một interface có method như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Và &lt;code&gt;Bus&lt;/code&gt; là một interface có method như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Bus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="task-implementations"&gt;Task implementations
&lt;/h3&gt;&lt;p&gt;Chúng ta sẽ implement một số class &lt;code&gt;Task&lt;/code&gt; như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@Slf4j&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;UserLoginEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;User {} logged in&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@Slf4j&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;SendMessageRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;User {} sent message: {}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="test"&gt;Test
&lt;/h2&gt;&lt;p&gt;Chúng ta sẽ có một test như sau để kiểm tra output của các bus:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;submitTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserLoginEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SendMessageRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;msg1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SendMessageRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;msg2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserLoginEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SendMessageRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;msg1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SendMessageRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;msg2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SendMessageRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;msg3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SendMessageRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;msg4&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SendMessageRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;msg3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SendMessageRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;msg4&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="normalbus"&gt;NormalBus
&lt;/h2&gt;&lt;p&gt;Thông thường ta sẽ implement một class &lt;code&gt;NormalBus&lt;/code&gt; như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NormalBus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Bus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ExecutorService&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;executors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Executors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newFixedThreadPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRuntime&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="na"&gt;availableProcessors&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;executors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Và đây là 1 output khi chạy test:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-1-thread-1] INFO com.miti99.taskbus.task.event.UserLoginEvent - User 1 logged in
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-1-thread-10] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 2 sent message: msg4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-1-thread-9] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 2 sent message: msg3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-1-thread-8] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 1 sent message: msg4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-1-thread-2] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 1 sent message: msg1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-1-thread-6] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 2 sent message: msg2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-1-thread-7] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 1 sent message: msg3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-1-thread-5] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 2 sent message: msg1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-1-thread-3] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 1 sent message: msg2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-1-thread-4] INFO com.miti99.taskbus.task.event.UserLoginEvent - User 2 logged in
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Có thể thấy các task được thực thi ở nhiều thread khác nhau làm cho task của cùng 1 user không được thực thi theo thứ tự trong output.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lưu ý:&lt;/strong&gt; Output của test có thể thay đổi mỗi lần chạy do ảnh hưởng của thread pool.&lt;/p&gt;
&lt;h2 id="taskbus"&gt;TaskBus
&lt;/h2&gt;&lt;p&gt;Để cải thiện, chúng ta sẽ cần phân phối task của từng user vào 1 executor, &amp;ldquo;chỉ đích danh&amp;rdquo; executor nào sẽ thực thi task của user đó. Để làm được điều này, chúng ta sẽ cần implement một class &lt;code&gt;TaskBus&lt;/code&gt; như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TaskBus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Bus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ExecutorService&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;executors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;poolSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;TaskBus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;poolSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;poolSize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;poolSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;executors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ExecutorService&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;poolSize&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;poolSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;executors&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Executors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newSingleThreadExecutor&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;TaskBus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRuntime&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="na"&gt;availableProcessors&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;executorId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;poolSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;executors&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;executorId&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Và đây là 1 output khi chạy test:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-3-thread-1] INFO com.miti99.taskbus.task.event.UserLoginEvent - User 2 logged in
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-2-thread-1] INFO com.miti99.taskbus.task.event.UserLoginEvent - User 1 logged in
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-3-thread-1] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 2 sent message: msg1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-2-thread-1] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 1 sent message: msg1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-3-thread-1] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 2 sent message: msg2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-2-thread-1] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 1 sent message: msg2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-3-thread-1] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 2 sent message: msg3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-2-thread-1] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 1 sent message: msg3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-3-thread-1] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 2 sent message: msg4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[pool-2-thread-1] INFO com.miti99.taskbus.task.request.SendMessageRequest - User 1 sent message: msg4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Có thể thấy task của cùng 1 user sẽ được thực thi trong cùng 1 thread. Trong output này, thread thực thi task của user 1 là &lt;code&gt;pool-2-thread-1&lt;/code&gt;, còn của user 2 là &lt;code&gt;pool-3-thread-1&lt;/code&gt;. Mặc dù thứ tự task của các user khác nhau không được đảm bảo, nhưng thứ tự của các task của cùng 1 user sẽ được thực thi theo đúng thứ tự đã submit.&lt;/p&gt;
&lt;h2 id="kết-luận"&gt;Kết luận
&lt;/h2&gt;&lt;p&gt;Đây chỉ là một implement TaskBus cơ bản, trong thực tế chúng ta còn phải đối mặt nhiều vấn đề khác, vd độ ưu tiên của task, monitor thời gian thực thi task, xử lý khi run task gặp exception,&amp;hellip; Ngoài ra cách này cũng đánh đổi thời gian thực thi để đảm bảo thứ tự các task.&lt;/p&gt;
&lt;p&gt;Vẫn rất hi vọng bài viết này sẽ hữu ích với bạn trong việc tìm ra một giải pháp khi muốn giữ thứ tự thực thi task của một user.&lt;/p&gt;
&lt;p&gt;Toàn bộ source code bạn có thể tìm thấy trên GitHub của mình: &lt;a class="link" href="https://github.com/tiennm99/taskbus" target="_blank" rel="noopener"
&gt;https://github.com/tiennm99/taskbus&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Newsletter #3</title><link>https://miti99.com/post/2025/02/23/</link><pubDate>Sun, 23 Feb 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/02/23/</guid><description>&lt;i&gt;
Chào các bạn, lại một cuối tuần nữa trôi qua, mời các bạn chill chill cùng Newsletter #3 của MiTi.
&lt;/i&gt;
&lt;h2 id="java"&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=y26XGt8d_kI" target="_blank" rel="noopener"
&gt;Java&amp;rsquo;s Plans for 2025 - Inside Java Newscast #83&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Video này trên Inside Java Newscast trình bày những phát triển và kế hoạch dự kiến cho Java trong năm 2025, tập trung vào các dự án OpenJDK lớn như Babylon, Loom, Leyden, Lilliput, Panama và Valhalla (ngoại trừ Amber, sẽ được đề cập trong một video khác).&lt;/p&gt;
&lt;h2 id="why-you-should-learn-kotlin-in-2025"&gt;&lt;a class="link" href="https://dev.to/empiree/why-you-should-learn-kotlin-in-2025-47g0" target="_blank" rel="noopener"
&gt;Why You Should Learn Kotlin in 2025&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trên Dev.to khuyến khích các nhà phát triển tìm hiểu Kotlin vào năm 2025, nhấn mạnh các tính năng hiện đại, khả năng tương tác với Java và các ứng dụng đa dạng của nó. Bài đăng này cũng thảo luận về thị trường việc làm và mức lương tiềm năng cho các nhà phát triển Kotlin.&lt;/p&gt;
&lt;h2 id="mastering-java-logging-best-practices-for-effective-application-monitoring"&gt;&lt;a class="link" href="https://dev.to/aaravjoshi/mastering-java-logging-best-practices-for-effective-application-monitoring-20h7" target="_blank" rel="noopener"
&gt;Mastering Java Logging: Best Practices for Effective Application Monitoring&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trên Dev.to cung cấp hướng dẫn toàn diện về việc thực hiện ghi log hiệu quả trong các ứng dụng Java. Nó bao gồm các khía cạnh thiết yếu như chọn khung ghi log phù hợp, sử dụng các cấp log thích hợp, triển khai ghi log có cấu trúc và nhận biết ngữ cảnh, quản lý hiệu suất và bảo mật, đồng thời thiết lập ghi log tập trung.&lt;/p&gt;
&lt;h2 id="fixed-window-counter-rate-limiter-redis--java"&gt;&lt;a class="link" href="https://foojay.io/today/fixed-window-counter-rate-limiter-redis-java/" target="_blank" rel="noopener"
&gt;Fixed Window Counter Rate Limiter (Redis &amp;amp; Java)&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trên foojay.io trình bày cách triển khai thuật toán giới hạn tốc độ bộ đếm cửa sổ cố định bằng Redis và Java. Bài viết này giải thích cách hoạt động của thuật toán, cách triển khai nó bằng Jedis và Redis và cách kiểm tra nó bằng Redis TestContainers và JUnit 5.&lt;/p&gt;
&lt;h2 id="how-jvm-handles-exceptions"&gt;&lt;a class="link" href="https://foojay.io/today/how-jvm-handles-exceptions/" target="_blank" rel="noopener"
&gt;How JVM handles exceptions&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trên foojay.io đi sâu vào cách Máy ảo Java (JVM) xử lý các ngoại lệ, tập trung vào bảng ngoại lệ và các hướng dẫn bytecode liên quan đến các khối try-catch-finally.&lt;/p&gt;
&lt;h2 id="database-sharding-explained"&gt;&lt;a class="link" href="https://architecturenotes.co/p/database-sharding-explained" target="_blank" rel="noopener"
&gt;Database Sharding Explained&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trên Architecture Notes giải thích về phân vùng cơ sở dữ liệu, một kỹ thuật để phân phối dữ liệu trên nhiều máy khi một máy duy nhất không thể xử lý khối lượng công việc dự kiến. Bài viết này bao gồm các tùy chọn khác trước khi phân vùng, các loại phân vùng, tầm quan trọng của khóa phân vùng, cách xử lý các giao dịch đa phân vùng và sự phức tạp hoạt động của việc phân vùng.&lt;/p&gt;
&lt;h2 id="protecting-your-time-from-predators-in-large-tech-companies"&gt;&lt;a class="link" href="https://www.seangoedecke.com/predators/" target="_blank" rel="noopener"
&gt;Protecting your time from predators in large tech companies&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết blog này của seangoedecke.com cảnh báo các kỹ sư phần mềm giỏi tại các công ty công nghệ lớn về việc những người khác liên tục tìm cách giành lấy thời gian của họ, đôi khi một cách khai thác. Nó cung cấp hướng dẫn về cách xác định và tránh những &amp;ldquo;kẻ săn mồi&amp;rdquo; này để tập trung vào các trách nhiệm chính.&lt;/p&gt;
&lt;h2 id="how-to-improve-your-wfh-lighting-to-reduce-eye-strain"&gt;&lt;a class="link" href="https://rustle.ca/posts/articles/work-from-home-lighting" target="_blank" rel="noopener"
&gt;How to improve your WFH lighting to reduce eye strain&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này trên rustle.ca thảo luận về tầm quan trọng của ánh sáng phù hợp để giảm mỏi mắt khi làm việc tại nhà. Tác giả chia sẻ kinh nghiệm cá nhân và cung cấp lời khuyên thực tế về cách tạo ra một môi trường ánh sáng dễ chịu, bao gồm sử dụng ánh sáng tự nhiên, cải thiện chất lượng ánh sáng nhân tạo và cân bằng độ sáng để giảm thiểu độ tương phản.&lt;/p&gt;
&lt;h2 id="working-fast-and-slow"&gt;&lt;a class="link" href="https://www.seangoedecke.com/working-fast-and-slow/" target="_blank" rel="noopener"
&gt;Working fast and slow&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết blog này trên seangoedecke.com thảo luận về hai kiểu làm việc mà tác giả đã xác định trong sự nghiệp kỹ thuật của mình: làm việc tập trung và làm việc không tập trung. Thay vì cảm thấy có lỗi khi ngày làm việc của họ không phải lúc nào cũng nhất quán, họ tập trung vào việc tận dụng tối đa từng giai đoạn, tận dụng tối đa các giai đoạn tập trung và thực hiện công việc ít quan trọng hơn trong những ngày ít tập trung.&lt;/p&gt;
&lt;h2 id="bonus"&gt;Bonus
&lt;/h2&gt;&lt;h3 id="bonus-1-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus #1: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/fe9062b4-fd0e-4530-8e20-eea854b8490e_2250x2814.png"
loading="lazy"
alt="Top Strategies to Reduce Latency"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/9c309ad3-78a8-4511-a6f2-e69c06d5c500_1280x1566.gif"
loading="lazy"
alt="The Ultimate API Learning Roadmap"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/a44f9f4b-193d-484e-bbf1-169751104380_1280x1568.gif"
loading="lazy"
alt="10 Essential Components of a Production Web Application"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/d5155be3-163d-479c-a75e-632e0f98dd36_3006x3453.jpeg"
loading="lazy"
alt="How do we design effective and safe APIs?"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/aad520f5-00d9-4606-af4b-fdb5d1ac63c4_1600x1483.png"
loading="lazy"
alt="Code First v.s. API First"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/bb375f63-bf06-4956-b3a3-914fd6aa2d91_1280x1664.jpeg"
loading="lazy"
alt="Oauth 2.0 Explained With Simple Terms"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/c1155e03-c3dc-4192-8e05-e6b87dc6a574_1280x1664.gif"
loading="lazy"
alt="Session, Cookie, JWT, Token, SSO, and OAuth 2.0 Explained in One Diagram"
&gt;&lt;/p&gt;
&lt;h3 id="bonus-2-một-vài-link-hay-ho-khác"&gt;Bonus #2: Một vài link hay ho khác
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://openalternative.co/self-hosted" target="_blank" rel="noopener"
&gt;Self-hosted Alternatives to Popular Software&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Newsletter #2</title><link>https://miti99.com/post/2025/02/16/</link><pubDate>Sun, 16 Feb 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/02/16/</guid><description>&lt;i&gt;
Chào các bạn, đến hẹn lại lên, đây là Newsletter #2 của mình. Cuối tuần này mình đi chơi ở Xuyên Mộc, vừa về hôm nay thôi nên giờ mới lên bài.
&lt;p&gt;Thôi không vòng vo nữa, vào ngay Newsletter #2 của MiTi nào.
&lt;/i&gt;&lt;/p&gt;
&lt;h2 id="some-things-to-expect-in-2025"&gt;&lt;a class="link" href="https://lwn.net/Articles/1003780" target="_blank" rel="noopener"
&gt;Some things to expect in 2025&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết dự đoán một số xu hướng và sự kiện có thể xảy ra trong cộng đồng Linux và phần mềm tự do năm 2025. Đầu tiên, sched-ext sẽ trở thành yếu tố thay đổi cuộc chơi, cho phép tải trình lập lịch CPU từ không gian người dùng thông qua BPF, thúc đẩy sự sáng tạo và thử nghiệm. Mã Rust sẽ được tích hợp nhiều hơn vào kernel, mang lại các tính năng mà người dùng cuối có thể không nhận ra. Bài viết cảnh báo về một nỗ lực backdoor tương tự như XZ có thể xuất hiện, và các dự án chỉ có một người duy trì sẽ bị coi là rủi ro hơn.&lt;/p&gt;
&lt;p&gt;Một dự án lớn có thể phát hiện ra rằng họ đã hợp nhất nhiều mã do AI tạo ra mà tác giả không thực sự hiểu. Đồng thời, sẽ có nhiều nỗ lực tập trung hơn vào việc tạo ra các hệ thống AI tạo sinh thực sự tự do. Các tổ chức hỗ trợ công việc phần mềm tự do sẽ tiếp tục gặp khó khăn. Nhiều sản phẩm dựa trên đám mây sẽ trở thành &amp;ldquo;cục gạch&amp;rdquo; khi nhà sản xuất phá sản hoặc ngừng hỗ trợ. Phần cứng hoàn toàn mở sẽ trở nên phổ biến hơn, và các bản phân phối cho thiết bị di động sẽ chứng kiến sự quan tâm trở lại. Cuối cùng, bài viết nhấn mạnh rằng sự hiếu chiến toàn cầu sẽ tác động đến cộng đồng, và lời kêu gọi được đưa ra là hãy giữ vững các giá trị cốt lõi của cộng đồng trong bối cảnh chính trị phân cực.&lt;/p&gt;
&lt;h2 id="why-you-should-use-compact-table-columns"&gt;&lt;a class="link" href="https://vladmihalcea.com/compact-table-columns/" target="_blank" rel="noopener"
&gt;Why you should use compact table columns&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết giải thích tầm quan trọng của việc sử dụng các kiểu cột (column types) nhỏ gọn trong thiết kế cơ sở dữ liệu để tăng tốc độ truy vấn SQL. Việc sử dụng các kiểu cột nhỏ gọn cho phép lưu trữ nhiều bản ghi và mục chỉ mục hơn trong bộ nhớ cache, giúp giảm thiểu số lần truy cập đĩa. StackOverflow là một ví dụ điển hình, họ đã sử dụng chiến lược này để phục vụ hàng nghìn truy vấn mỗi giây chỉ với một máy chủ SQL duy nhất.&lt;/p&gt;
&lt;p&gt;Bài viết chỉ ra rằng việc sử dụng các khóa chính (Primary Key) và khóa ngoại (Foreign Key) kiểu int hoặc tinyint thay vì UUID hoặc bigint, biểu diễn giá trị enum bằng 1 byte, và giới hạn độ dài của các cột VARCHAR giúp tiết kiệm không gian lưu trữ. Tác giả cũng trình bày các ví dụ cụ thể trên MySQL và PostgreSQL, cho thấy việc sử dụng các kiểu cột nhỏ gọn có thể giảm đáng kể kích thước bảng và chỉ mục, từ đó cải thiện hiệu suất truy vấn. Tuy nhiên, cần lưu ý về việc căn chỉnh cột (column alignment) trong PostgreSQL để đạt hiệu quả tối ưu. Tóm lại, việc lựa chọn kiểu cột phù hợp là một yếu tố quan trọng để tối ưu hóa hiệu suất cơ sở dữ liệu.&lt;/p&gt;
&lt;h2 id="rate-limiting-with-redis-an-essential-guide"&gt;&lt;a class="link" href="https://foojay.io/today/rate-limiting-with-redis-an-essential-guide/" target="_blank" rel="noopener"
&gt;Rate limiting with Redis: An essential guide&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này giới thiệu về rate limiting (giới hạn tốc độ truy cập), giải thích tầm quan trọng của nó trong việc bảo vệ tài nguyên khỏi bị quá tải, ngăn chặn lạm dụng, đảm bảo truy cập công bằng, quản lý tải, giảm chi phí và bảo vệ hệ thống khỏi downtime. Redis được giới thiệu như một công cụ phổ biến để triển khai rate limiter nhờ tốc độ, độ tin cậy và các tính năng như thao tác nguyên tử, lưu trữ dữ liệu và Lua scripting.&lt;/p&gt;
&lt;p&gt;Bài viết trình bày chi tiết các thuật toán rate limiting phổ biến: Leaky Bucket (ổn định luồng traffic), Token Bucket (xử lý các đợt tăng đột biến), Fixed Window Counter (đơn giản, độ chính xác thấp), Sliding Window Log (độ chính xác cao, tốn nhiều tài nguyên) và Sliding Window Counter (cân bằng giữa độ chính xác và hiệu quả).&lt;/p&gt;
&lt;p&gt;Để chọn thuật toán phù hợp, cần hiểu rõ đặc điểm traffic (dự đoán được, đột biến, hỗn hợp), mức độ chính xác cần thiết, giới hạn tài nguyên (bộ nhớ, CPU, khả năng mở rộng) và trải nghiệm người dùng. Bài viết nhấn mạnh rằng rate limiting không chỉ là việc thiết lập giới hạn mà còn là thiết kế các hệ thống hiệu quả, công bằng và thân thiện với người dùng. Các triển khai cho từng loại rate limiter với Java &amp;amp; Redis sẽ được phát hành hàng tuần.&lt;/p&gt;
&lt;h2 id="why-does-cloudflare-pages-have-such-a-generous-free-tier"&gt;&lt;a class="link" href="https://mattsayar.com/why-does-cloudflare-pages-have-such-a-generous-free-tier" target="_blank" rel="noopener"
&gt;Why does Cloudflare Pages have such a generous Free tier?&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết của Matt Sayar khám phá lý do tại sao Cloudflare Pages lại có một gói miễn phí hào phóng trong bối cảnh nhiều dịch vụ hosting hiện nay cung cấp các gói miễn phí tương tự. Cloudflare Pages nổi bật với băng thông không giới hạn, điều mà ít nền tảng nào khác có thể cạnh tranh. Các dịch vụ như GitHub Pages, GitLab Pages và Netlify đều có giới hạn băng thông, trong khi Cloudflare cho phép người dùng thoải mái phát triển trang web mà không lo lắng về chi phí phát sinh.&lt;/p&gt;
&lt;p&gt;Tác giả cho rằng việc cung cấp băng thông không giới hạn phù hợp với chiến lược của Cloudflare trong việc phát triển một internet an toàn và nhanh chóng. Một trang web tĩnh nhẹ nhàng và dễ phục vụ, giúp Cloudflare tiết kiệm chi phí. Hơn nữa, khi người dùng trải nghiệm dịch vụ miễn phí, họ có xu hướng có ấn tượng tích cực và có thể chuyển sang sử dụng các sản phẩm trả phí của Cloudflare trong tương lai.&lt;/p&gt;
&lt;p&gt;Bài viết cũng nhấn mạnh rằng Cloudflare đang đầu tư vào việc cải thiện internet và cung cấp nhiều dịch vụ bảo mật miễn phí, từ đó tạo ra một vòng luân chuyển lợi ích cho cả người dùng và công ty. Tác giả kết luận rằng đây là một cơ hội tốt để thử nghiệm các sản phẩm mới của Cloudflare, đặc biệt là trong thời gian gói miễn phí vẫn còn hiệu lực.&lt;/p&gt;
&lt;h2 id="how-i-program-with-llms"&gt;&lt;a class="link" href="https://crawshaw.io/blog/programming-with-llms" target="_blank" rel="noopener"
&gt;How I program with LLMs&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này tổng hợp những kinh nghiệm cá nhân của tác giả trong việc sử dụng các mô hình ngôn ngữ lớn (LLM) trong lập trình trong năm vừa qua. Tác giả nhấn mạnh rằng việc sử dụng LLM đã mang lại hiệu quả tích cực cho năng suất làm việc, và việc quay trở lại lập trình mà không có chúng trở nên khó khăn. Tác giả thường sử dụng LLM để tự động hóa các bước lặp đi lặp lại và một công cụ có tên sketch.dev đang được phát triển để hỗ trợ lập trình Go.&lt;/p&gt;
&lt;p&gt;Có ba cách chính mà tác giả sử dụng LLM: để tự động hoàn thành code, cho các tác vụ tìm kiếm, và trong các phiên lập trình dựa trên chat. Tác giả thấy rằng LLM đặc biệt hữu ích khi anh ta biết những gì cần viết, nhưng không có đủ năng lượng để bắt đầu một file mới, tra cứu các thư viện cần thiết. LLM cung cấp bản nháp đầu tiên, thường chứa các ý tưởng hay, các dependency cần thiết và một vài lỗi. Việc sửa các lỗi này thường dễ dàng hơn là bắt đầu từ đầu.&lt;/p&gt;
&lt;p&gt;LLM cũng rất hữu ích trong việc tạo ra các code review packet, đặc biệt là khi chúng cần sử dụng nhiều thư viện phổ biến. Tuy nhiên, cần phải biên dịch và chạy thử code do LLM tạo ra trước khi đọc kỹ, vì chúng có thể tạo ra code không biên dịch được.&lt;/p&gt;
&lt;p&gt;Ví dụ, tác giả đã sử dụng LLM để viết một reservoir sampler cho các quartiles của các số float. LLM đã tạo ra một package có cấu trúc tốt, interface tốt và các test, nhưng code ban đầu không biên dịch được và các test chứa các giá trị sai. Tác giả đã sửa các lỗi này và sau đó yêu cầu LLM tạo ra các test tốt hơn bằng cách so sánh kết quả của reservoir sampler với một triển khai tiêu chuẩn. LLM đã tạo ra một fuzz test, nhưng nó chứa một lỗi cú pháp. Sau khi tác giả sửa lỗi này, fuzz test đã hoạt động tốt.&lt;/p&gt;
&lt;p&gt;Nhìn chung, tác giả kết luận rằng LLM có thể là một công cụ hữu ích cho các lập trình viên, nhưng chúng không hoàn hảo và cần được sử dụng một cách cẩn thận. LLM có thể giúp cải thiện năng suất, viết test toàn diện hơn và làm cho code dễ đọc hơn.&lt;/p&gt;
&lt;h2 id="bonus"&gt;Bonus
&lt;/h2&gt;&lt;p&gt;Tuần này có kha khá bonus đến từ nhiều nguồn khác nhau&lt;/p&gt;
&lt;h3 id="bonus-1-một-vài-ebook-mình-tìm-được"&gt;Bonus #1: Một vài ebook mình tìm được
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://info.microsoft.com/rs/157-GQE-382/images/EN-CNTNT-eBook-DesigningDistributedSystems.pdf" target="_blank" rel="noopener"
&gt;Designing Distributed Systems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://drive.google.com/file/d/1U7EchvgzCjTtF5JzGVVCFgjXC-qw7lIG/view" target="_blank" rel="noopener"
&gt;Quastor Summaries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bonus-2-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus #2: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/11b53f30-8dba-4520-9b1a-425b54b9b84a_1280x1585.gif"
loading="lazy"
alt="Cookies Vs Sessions Vs JWT Vs PASETO"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/fdbcc119-8f5d-4d27-9a4b-2c8bde82b537_4026x8030.jpeg"
loading="lazy"
alt="Algorithms you should know before taking System Design Interviews"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/12dffcce-f231-48cc-915f-d53c0f8bce0c_3735x3573.jpeg"
loading="lazy"
alt="Top 6 Load Balancing Algorithms"
&gt;&lt;/p&gt;</description></item><item><title>Newsletter #1</title><link>https://miti99.com/post/2025/02/08/</link><pubDate>Sat, 08 Feb 2025 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2025/02/08/</guid><description>&lt;i&gt;
Xin chào các bạn, đây lại là một lần mình quay viết blog sau chuỗi ngày lười biếng :D
&lt;p&gt;Một vấn đề mình nhận ra nhưng lười sửa đổi đó là mình đọc nhiều blog, nghịch nhiều tool, nhưng không có cái nào mình thật sự nghiêm túc, đủ để viết thành một blog chất lượng cả. Nếu có gì tâm đắc thì mình cũng quá lười để viết lại.&lt;/p&gt;
&lt;p&gt;Vì vậy mình chuyển sang thử một hình thức khác, đó là tổng hợp lại những bài blog hay mà mình đã tìm thấy, đọc được trong tuần vừa qua và tổng hợp lại thành một bản newsletter hàng tuần. Mong được mọi người ủng hộ.&lt;/p&gt;
&lt;p&gt;Không lòng vòng nữa, sau đây là Newsletter #1 của mình.
&lt;/i&gt;&lt;/p&gt;
&lt;h2 id="seconds-since-the-epoch"&gt;&lt;a class="link" href="https://aphyr.com/posts/378-seconds-since-the-epoch" target="_blank" rel="noopener"
&gt;Seconds Since the Epoch&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này giải thích lý do tại sao thời gian POSIX, thường được cho là số giây kể từ kỷ nguyên Unix (ngày 1 tháng 1 năm 1970), thực tế không chính xác như vậy. Nguyên nhân là do thời gian POSIX bắt nguồn từ Giờ Phối Hợp Quốc Tế (UTC) và tiêu chuẩn giả định rằng mỗi ngày dài đúng 86.400 giây. Tuy nhiên, độ dài của một ngày thay đổi và các nhà thiên văn học định kỳ tuyên bố giây nhuận để giữ cho ngày UTC không trôi quá xa so với ngày mặt trời. Những giây nhuận này gây ra sự gián đoạn trong thời gian POSIX. Bài viết cũng thảo luận về các giải pháp thay thế cho thời gian POSIX và nỗ lực chấm dứt giây nhuận vào năm 2035.&lt;/p&gt;
&lt;h2 id="b-trees-more-than-i-thought-i"&gt;&lt;a class="link" href="https://benjamincongdon.me/blog/2021/08/17/B-Trees-More-Than-I-Thought-Id-Want-to-Know/" target="_blank" rel="noopener"
&gt;B-Trees: More Than I Thought I&amp;rsquo;d Want to Know&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài đăng trên blog này đi sâu vào cấu trúc dữ liệu Cây B, đặc biệt tập trung vào việc sử dụng chúng trong các công cụ lưu trữ cơ sở dữ liệu. Nó giải thích các ràng buộc do I/O đĩa áp đặt và cách Cây B giải quyết các ràng buộc này bằng cách định vị các khóa cùng nhau trên đĩa. Bài viết thảo luận về các trang có rãnh, được sử dụng để bố trí các khóa trên đĩa để tối đa hóa vị trí và nén khóa. Nó cũng bao gồm các kỹ thuật tối ưu hóa khác nhau như cắt ngắn khóa phân tách, các trang tràn và con trỏ anh em. Cuối cùng, bài đăng trên blog đề cập đến một số biến thể Cây B và các tối ưu hóa khác có thể cung cấp các tối ưu hóa trong một số trường hợp nhất định.&lt;/p&gt;
&lt;h2 id="sql-nulls-are-weird"&gt;&lt;a class="link" href="http://raymondtukpe.com/sql-nulls-are-weird.html" target="_blank" rel="noopener"
&gt;SQL NULLs are Weird!&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này khám phá những hành vi kỳ lạ của giá trị NULL trong SQL, đặc biệt là cách chúng được xử lý trong các ràng buộc UNIQUE. Tác giả chỉ ra rằng, không giống như những gì người ta thường mong đợi, SQL coi tất cả các giá trị NULL là các giá trị riêng biệt. Điều này có nghĩa là một cột có ràng buộc UNIQUE có thể chứa nhiều giá trị NULL vì mỗi giá trị NULL được coi là khác với các giá trị NULL khác. Bài viết tiếp tục thảo luận về cách đảm bảo tính duy nhất khi xử lý các giá trị NULL, sử dụng các cột được tạo và lập chỉ mục một phần.&lt;/p&gt;
&lt;h2 id="understanding-jvm-garbage-collector-performance"&gt;&lt;a class="link" href="https://mill-build.org/blog/6-garbage-collector-perf.html" target="_blank" rel="noopener"
&gt;Understanding JVM Garbage Collector Performance&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này giải thích cách thức hoạt động của bộ thu gom rác (GC) trong Java Virtual Machine (JVM) và cung cấp các phương pháp cải thiện hiệu suất của nó. Tác giả bắt đầu bằng việc mô tả một GC lý thuyết đơn giản, sau đó đi sâu vào các thuật toán GC thực tế như Mark-and-Sweep và Generational Garbage Collection. Bài viết cũng thảo luận về các tham số cấu hình GC quan trọng, như kích thước heap và các tùy chọn GC khác nhau, đồng thời cung cấp các hướng dẫn về cách điều chỉnh chúng để đạt hiệu suất tối ưu. Cuối cùng, tác giả đưa ra các khuyến nghị cụ thể để cải thiện hiệu suất GC trong các dự án thực tế, bao gồm việc theo dõi và phân tích hành vi GC, cũng như điều chỉnh cấu hình GC dựa trên tải công việc cụ thể.&lt;/p&gt;
&lt;h2 id="a-deep-dive-into-jvm-start-up"&gt;&lt;a class="link" href="https://www.youtube.com/watch?v=ED1oc7gn5uY" target="_blank" rel="noopener"
&gt;A Deep Dive into JVM Start-Up&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bạn có bao giờ thắc mắc điều gì xảy ra &amp;ldquo;đằng sau hậu trường&amp;rdquo; trước khi dòng lệnh System.out.println(&amp;ldquo;Hello World&amp;rdquo;) quen thuộc được thực thi trong ứng dụng Java? Video này sẽ đưa bạn vào một hành trình khám phá sâu sắc quy trình khởi động phức tạp của Java Virtual Machine (JVM). Từ việc phân tích cú pháp các tham số, kiểm tra tài nguyên hệ thống, thiết lập môi trường, đến quá trình tải, liên kết và khởi tạo lớp, bạn sẽ hiểu rõ hơn về những bước cần thiết để JVM &amp;ldquo;tạo ra vũ trụ&amp;rdquo; cho ứng dụng của bạn. Video cũng hé lộ những thay đổi thú vị trong tương lai với Project Leyden, hứa hẹn cải thiện đáng kể thời gian khởi động và hiệu suất của JVM. Đây là một tài liệu tham khảo giá trị cho bất kỳ nhà phát triển Java nào muốn nâng cao hiểu biết về nền tảng cốt lõi mà họ đang sử dụng.&lt;/p&gt;
&lt;h2 id="parallel-processing-with-virtual-threads---a-comparative-analysis"&gt;&lt;a class="link" href="https://www.dhaval-shah.com/parallel-processing-virtual-threads-reactor-vs-jdk/" target="_blank" rel="noopener"
&gt;Parallel processing with Virtual Threads - A comparative analysis&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Bài viết này phân tích hiệu suất của việc sử dụng Virtual Threads trong xử lý song song, so sánh giữa hai cách tiếp cận: triển khai dựa trên JDK 21 và Spring Core Reactor. Tác giả bắt đầu bằng việc nêu ra các hạn chế của các luồng hệ điều hành truyền thống, như chi phí tài nguyên cao và khả năng mở rộng hạn chế. Sau đó, bài viết giới thiệu về Virtual Threads, một tính năng mới trong JDK 21, cho phép tạo ra hàng triệu luồng nhẹ với chi phí thấp, đặc biệt hiệu quả cho các tác vụ I/O. Bài viết cung cấp các ví dụ mã cho cả hai phương pháp triển khai và tiến hành phân tích so sánh dựa trên các tiêu chí như thời gian xử lý, sử dụng bộ nhớ và hoạt động của bộ thu gom rác (GC). Kết quả cho thấy, việc sử dụng Virtual Threads với triển khai dựa trên JDK mang lại hiệu suất vượt trội so với Spring Core Reactor, đặc biệt khi xử lý số lượng lớn đối tượng. Tuy nhiên, triển khai dựa trên JDK yêu cầu bộ nhớ nhiều hơn và có thời gian dừng GC dài hơn, nhưng điều này không ảnh hưởng đáng kể đến độ trễ của ứng dụng. Tác giả kết luận rằng, đối với các ứng dụng yêu cầu hiệu suất cao và khả năng mở rộng, Virtual Threads trong JDK 21 là lựa chọn ưu việt.&lt;/p&gt;
&lt;h2 id="bonus-vài-ảnh-hay-ho-đến-từ-bytebytego"&gt;Bonus: Vài ảnh hay ho đến từ &lt;a class="link" href="https://bytebytego.com/" target="_blank" rel="noopener"
&gt;ByteByteGo&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/2ae8b491-b794-446b-8ca5-25ac552161be_1417x1600.png"
loading="lazy"
alt="A Cheatsheet On Message Queues"
&gt;
&lt;img src="https://substack-post-media.s3.amazonaws.com/public/images/015e9750-7334-424b-b0c4-9c39bc5dd2d2_1600x1596.png"
loading="lazy"
alt="From Monolith to Microservices: Key Transition Patterns"
&gt;&lt;/p&gt;</description></item><item><title>Cách mở rộng ổ đĩa trong Oracle Cloud Infrastructure (OCI)</title><link>https://miti99.com/post/2024/12/01/</link><pubDate>Sun, 01 Dec 2024 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2024/12/01/</guid><description>&lt;p&gt;Khi dùng Oracle trên Oracle Cloud, dù lúc setup bạn chọn Boot Volume 200GB nhưng Oracle chỉ nhận 50GB?&lt;/p&gt;
&lt;p&gt;Đây là do Oracle Cloud chưa nhận hết dung lượng, bạn cần phải mở rộng ổ đĩa để sử dụng hết dung lượng đã chọn.&lt;/p&gt;
&lt;h2 id="cách-làm"&gt;Cách làm
&lt;/h2&gt;&lt;p&gt;Bạn sử dụng lệnh sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo /usr/libexec/oci-growfs -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Tham khảo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.oracle.com/en-us/iaas/Content/Block/Tasks/resizingavolume.htm" target="_blank" rel="noopener"
&gt;https://docs.oracle.com/en-us/iaas/Content/Block/Tasks/resizingavolume.htm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.oracle.com/en-us/iaas/oracle-linux/oci-utils/index.htm#oci-growfs" target="_blank" rel="noopener"
&gt;https://docs.oracle.com/en-us/iaas/oracle-linux/oci-utils/index.htm#oci-growfs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Cách tắt tường lửa (firewall) trên Ubuntu trong Oracle Cloud Infrastructure (OCI)</title><link>https://miti99.com/post/2024/09/25/</link><pubDate>Wed, 25 Sep 2024 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2024/09/25/</guid><description>&lt;p&gt;Khi dùng Ubuntu trên Oracle Cloud, đôi khi bạn chạy một service nhưng nó không available ra internet được, đó là do cấu hình firewall mặc định đã block một số kết nối. Hướng dẫn sau sẽ giúp bạn tắt tường lửa trên Ubuntu trong OCI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lưu ý:&lt;/strong&gt; Hướng dẫn sau đây sẽ tắt tường lửa, có thể dẫn đến các vấn đề bảo mật nghiêm trọng. Bạn nên cân nhắc cấu hình tường lửa phù hợp thay vì tắt nó đi hoàn toàn.&lt;/p&gt;
&lt;h2 id="cách-tắt-tường-lửa"&gt;Cách tắt tường lửa
&lt;/h2&gt;&lt;p&gt;Tường lửa trên Ubuntu trong OCI sử dụng &lt;code&gt;iptables&lt;/code&gt;. Để tắt đi, bạn sử dụng các lệnh sau:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Xóa tất cả các rules tường lửa:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo iptables -F
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Giải thích&lt;/strong&gt;: Lệnh &lt;code&gt;iptables -F&lt;/code&gt; xóa toàn bộ các rules hiện tại, cho phép tất cả phương thức kết nối.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lưu lại:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo netfilter-persistent save
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Giải thích&lt;/strong&gt;: Lệnh này lưu lại bộ rules hiện tại (rỗng), để đảm bảo rằng sau khi khởi động lại, tường lửa sẽ không tự động áp dụng lại các rules cũ.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="kết-luận"&gt;Kết luận
&lt;/h2&gt;&lt;p&gt;Việc tắt tường lửa trên Ubuntu cần đi kèm với cấu hình bảo mật tốt tại Oracle Cloud. Hãy đảm bảo &lt;code&gt;Security Lists&lt;/code&gt; trong &lt;code&gt;VCN&lt;/code&gt; được cấu hình đúng.&lt;/p&gt;</description></item><item><title>Học Netty</title><link>https://miti99.com/post/2023/03/19/</link><pubDate>Sun, 19 Mar 2023 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2023/03/19/</guid><description>&lt;p&gt;Trong lúc quỡn mình có tìm tòi thử để viết một game server bằng netty 4 và client js. Project của mình ở đây: &lt;a class="link" href="" &gt;https://github.com/tiennm99/learn-netty&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Nhận ảnh kết quả miễn phí từ mazebrite.com</title><link>https://miti99.com/post/2022/11/27/</link><pubDate>Sun, 27 Nov 2022 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2022/11/27/</guid><description>&lt;p&gt;&lt;a class="link" href="https://mazebrite.com/" target="_blank" rel="noopener"
&gt;mazebrite.com&lt;/a&gt; là một trang web tạo ra mê cung với thông điệp ẩn khá hay ho. Nhưng mazebrite sẽ lấy phí là $0.99 cho mỗi kết quả. Như này:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2022/11/27/img/1.png"
width="885"
height="211"
srcset="https://miti99.com/post/2022/11/27/img/1_hu_3628258ca58bd6b2.png 480w, https://miti99.com/post/2022/11/27/img/1_hu_e196734a4f7acd8b.png 1024w"
loading="lazy"
alt="Mazebrite tính phí"
class="gallery-image"
data-flex-grow="419"
data-flex-basis="1006px"
&gt;&lt;/p&gt;
&lt;p&gt;Nên post này sẽ giới thiệu cách nhận ảnh kết quả miễn phí từ &lt;a class="link" href="https://mazebrite.com/" target="_blank" rel="noopener"
&gt;mazebrite.com&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="note"&gt;Note:
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;Trick này hoạt động được trong thời điểm hiện tại (28/11/2022), còn tương lai thì chưa biết :D&lt;/li&gt;
&lt;li&gt;MiTi giới thiệu trick lấy được ảnh, còn bản quyền này nọ thì bạn tự chịu trách nhiệm nhé :D&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="lets-go"&gt;Let&amp;rsquo;s go!
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;Truy cập &lt;a class="link" href="https://mazebrite.com/" target="_blank" rel="noopener"
&gt;mazebrite.com&lt;/a&gt; và tạo mê cung như bình thường.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2022/11/27/img/2.png"
width="1046"
height="502"
srcset="https://miti99.com/post/2022/11/27/img/2_hu_aef7ba0a420fcf3.png 480w, https://miti99.com/post/2022/11/27/img/2_hu_12568995c31b8d9d.png 1024w"
loading="lazy"
alt="Tạo mê cung"
class="gallery-image"
data-flex-grow="208"
data-flex-basis="500px"
&gt;&lt;/p&gt;
&lt;p&gt;Bạn sẽ nhận được 3 bức ảnh với watermark như này:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2022/11/27/img/3.png"
width="1043"
height="1057"
srcset="https://miti99.com/post/2022/11/27/img/3_hu_82ccfba6e3303f60.png 480w, https://miti99.com/post/2022/11/27/img/3_hu_4079e327a292d512.png 1024w"
loading="lazy"
alt="Kết quả với watermark"
class="gallery-image"
data-flex-grow="98"
data-flex-basis="236px"
&gt;&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Truy cập Inspect, bằng cách chuột phải -&amp;gt; chọn Inspect hoặc nhấn phím tắt (F12), hoặc Ctrl + Shift + I. Sau đó chọn tab Elements. Ở đây tìm đến tag &lt;div&gt; có id &lt;strong&gt;MazeSolution&lt;/strong&gt; Đoạn mình gạch dưới như hình dưới là link của image.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2022/11/27/img/4.png"
width="1038"
height="474"
srcset="https://miti99.com/post/2022/11/27/img/4_hu_3704fdab9cbf0229.png 480w, https://miti99.com/post/2022/11/27/img/4_hu_b966e175561fb554.png 1024w"
loading="lazy"
alt="Inspect"
class="gallery-image"
data-flex-grow="218"
data-flex-basis="525px"
&gt;&lt;/p&gt;
&lt;p&gt;Giờ mình bỏ từ &lt;em&gt;Tester&lt;/em&gt;, sau đó ghép với cụm mazebrite.com, ta được link ảnh kết quả. VD: như với hình trên, Tiến được 3 link sau:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.mazebrite.com/SavedMazes/j0uo5hMITI*VIVIhPINK-Solution.png" target="_blank" rel="noopener"
&gt;https://www.mazebrite.com/SavedMazes/j0uo5hMITI*VIVIhPINK-Solution.png&lt;/a&gt;
&lt;img src="https://miti99.com/post/2022/11/27/img/5.png"
width="817"
height="180"
srcset="https://miti99.com/post/2022/11/27/img/5_hu_615c029ddeac7ca8.png 480w, https://miti99.com/post/2022/11/27/img/5_hu_5ab1da63872a0e76.png 1024w"
loading="lazy"
alt="Kết quả 1"
class="gallery-image"
data-flex-grow="453"
data-flex-basis="1089px"
&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.mazebrite.com/SavedMazes/j0uo5hMITI*VIVIhPINK-Clues.png" target="_blank" rel="noopener"
&gt;https://www.mazebrite.com/SavedMazes/j0uo5hMITI*VIVIhPINK-Clues.png&lt;/a&gt;
&lt;img src="https://miti99.com/post/2022/11/27/img/6.png"
width="817"
height="180"
srcset="https://miti99.com/post/2022/11/27/img/6_hu_872bc925c2001839.png 480w, https://miti99.com/post/2022/11/27/img/6_hu_51f0551f7b93b384.png 1024w"
loading="lazy"
alt="Kết quả 2"
class="gallery-image"
data-flex-grow="453"
data-flex-basis="1089px"
&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.mazebrite.com/SavedMazes/j0uo5hMITI*VIVIhPINK-Bare.png" target="_blank" rel="noopener"
&gt;https://www.mazebrite.com/SavedMazes/j0uo5hMITI*VIVIhPINK-Bare.png&lt;/a&gt;
&lt;img src="https://miti99.com/post/2022/11/27/img/7.png"
width="817"
height="180"
srcset="https://miti99.com/post/2022/11/27/img/7_hu_556a435409a6c825.png 480w, https://miti99.com/post/2022/11/27/img/7_hu_69eb382486ae34f8.png 1024w"
loading="lazy"
alt="Kết quả 3"
class="gallery-image"
data-flex-grow="453"
data-flex-basis="1089px"
&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Chúc các bạn thành công. Ủng hộ MiTi tại site này và &lt;a class="link" href="https://www.facebook.com/tiennm99" target="_blank" rel="noopener"
&gt;Facebook&lt;/a&gt; nhé.&lt;/p&gt;</description></item><item><title>Lần đầu build một bộ PC</title><link>https://miti99.com/post/2021/11/17/</link><pubDate>Wed, 17 Nov 2021 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2021/11/17/</guid><description>&lt;p&gt;&lt;strong&gt;Hiện MiTi cũng mới nhận được máy hôm nay thôi, nên còn bận cài máy, mà háo hức quá nên tối nay viết tạm bợ một bài, trong vài ngày tới sẽ chỉnh sửa lại cho hoàn thiện hơn&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Đã lâu rồi, gần 1 năm rưỡi từ blog cũ và 1 tháng rưỡi kể từ bài chuyển blog mà chẳng có thêm bài viết nào. Sẵn tiện MiTi vừa build 1 con PC xong, MiTi sẽ kể các bạn nghe chuyện &amp;ldquo;Lần đầu mình build một bộ PC&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bài viết do một Amateur vừa nhập môn build PC nên có không vừa ý điểm nào xin gạch đá nhẹ tay&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tác giả cũng là một người học văn rất dở, nên câu cú lủng củng, dàn ý không lôi cuốn, xin gạch đá nhẹ tay&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;(Nói thế chứ nếu chán thì hẳn đã tắt tab trình duyệt luôn cho rồi :))))&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bài viết khá dài, hài và xàm (do phần bình luận trong ngoặc như này), nên rất cảm ơn nếu bạn chịu khó đọc đến cuối&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id="khởi-nguồn"&gt;Khởi nguồn
&lt;/h1&gt;&lt;p&gt;Là một thằng học IT, thì ghiền PC với mình như một lẽ thường tình. Đã thích lâu rồi, nhưng không có điều kiện thui. Sẵn mấy tháng dịch chi tiêu dè sẻn có dành dụm được tí tiền, nên muốn làm 1 con PC để thoả mãn đam mê. (Mê tới nỗi từ ngày lên đơn hàng đến lúc được giao PC ngày nào cũng mở lên viết bài này, thành ra nó mới dài như vầy đó :v Này phải làm Vlog hẳn hoi chắc sẽ xịn hơn, nhưng MiTi lại là người thích chơi với chữ hơn là hình ảnh (khó khăn lắm mới chịu khó bỏ ảnh vào bài viết đó nha :v)) Sau gần 1 tháng tìm hiểu về lĩnh vực này, thì cũng biết chút đỉnh về linh kiện này nọ.&lt;/p&gt;
&lt;h1 id="định-hình-cấu-hình"&gt;Định hình cấu hình
&lt;/h1&gt;&lt;p&gt;Với tình hình VGA còn đang trong thời bão giá, nên cũng không định mua vì cũng không cần thiết lắm, mua về kẻo lại &amp;ldquo;cài game vào để test card màn hình&amp;rdquo; :))) (mà lí do thật ra là khá ngán tiền :v) Sẵn hóng hớt thấy AMD có ra dòng APU Ryzen 5 5600G với Ryzen 7 5700G không card màn hình, mà hiệu năng cũng ngang ngửa GTX 1030, thấy cũng khoái. Chấm ngay con Ryzen 7 5700G làm yếu tố tiên quyết (chơi thì chơi lớn tí, mốt có muốn nâng cấp gì thêm lại đỡ phải đổi con CPU). Thế là đỡ được phần tiền VGA, khỏi phải lo nghĩ cân nhắc mua VGA cùi rồi nâng cấp sau hay chơi lớn mua cái thiệt xịn gì đó rồi lại trả góp hay đổ nợ :&amp;rsquo;(. Nhưng rồi lại phải chắm thêm cặp RAM 2x16GB 3200Mhz cho cân xứng, để tối ưu được hiệu năng (hồi Work Frome Home con Macbook 16GB RAM vừa chạy IDE vừa chạy giả lập bị hụt RAM luôn @@ nên sẵn chơi lớn cho đã :D), sắp build lại thấy Kingston có quà tặng kèm khi mua RAM, thế là chấm ngay cặp RAM Kingston Fury Beast (không dám lên Renegade tại cũng ngán tiền). Mainboard thì cắm dòng B550 support AM4 mà giá tầm trung là được rồi, chứ dòng Z tầm cao quá lại với không tới :| Còn ổ cứng thì SSD là tiên quyết rồi, mà sẵn chơi thì cũng tính chơi luôn một con SSD M2 cho nó&amp;hellip; nhanh :))) Samsung EVO khá là hot, top tốc độ nhưng nhìn tầm giá Kingston vừa túi hơn, lại đang khuyến mãi quà, nên lao theo Kingston luôn (kẻ bị quà dụ :&amp;rsquo;()&lt;/p&gt;
&lt;h1 id="dự-định-các-phần-cứng"&gt;Dự định các phần cứng
&lt;/h1&gt;&lt;p&gt;Sau một thời gian thì thấy người ta chơi ITX phê quá, cũng muốn đầu tư, đi dạo trên mạng, tổng hợp thông tin, thì thích mê con Cooler Master MasterBox NR200P (bản MAX thích hơn do có kèm tản nhiệt với nguồn, mà thấy tại VN chẳng có bán) với con NZXT H210. Định là cửa hàng có bán case nào thì sẽ chơi full combo nguồn với tản nhiệt hãng đó luôn, vì CM lẫn NZXT đều nổi tiếng cả. Mà tản nhiệt thì phải là tản nhiệt nước AIO, để tận hưởng cái đẹp :D. Hi sinh vì cái đẹp là xứng đáng UwU&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CM MB NR200P thì mua nguồn SFX (loại size nhỏ cho ITX), giá khá chát; tản nhiệt&lt;/li&gt;
&lt;li&gt;NZXT H210 thì mua nguồn full modular của NZXT, giá cũng chát luôn, cơ mà case thì được cái chịu được nguồn của ATX, nhưng giá nguồn vẫn mắc -_-&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rồi nhìn lại nếu vậy thì Mainboard cũng phải size ITX, chứ size ATX với m-ATX thì sẽ không vừa, giá mấy mainboard ITX này thì cũng khá là chua so với main thông thường, mà, vì cái đẹp nên hi sinh tí cũng được :v&lt;/p&gt;
&lt;h2 id="tổng-kết-thì-hình-dung-hòm-hòm-cấu-hình-nó-như-sau"&gt;Tổng kết thì hình dung hòm hòm cấu hình nó như sau
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;CPU: AMD Ryzen 7 5700G&lt;/li&gt;
&lt;li&gt;RAM: Kingston Fury Beast 2x16G&lt;/li&gt;
&lt;li&gt;Mainboad: 1 trong 3:
&lt;ul&gt;
&lt;li&gt;ASROCK B550M-ITX/ac&lt;/li&gt;
&lt;li&gt;ASUS ROG STRIX B550-I GAMING&lt;/li&gt;
&lt;li&gt;GIGABYTE B550I AORUS PRO AX&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Ổ cứng: SSD SSD Kingston NV1 500GB M.2 PCIe NVMe&lt;/li&gt;
&lt;li&gt;Case: NZXT H210 (i cũng được) hoặc Cooler Master MasterBox NR200P&lt;/li&gt;
&lt;li&gt;PSU: Tuỳ case mà sẽ của CM dòng SFX hoặc NZXT, từ 650-750W&lt;/li&gt;
&lt;li&gt;Tản nhiệt nước AIO: Tuỳ case mà sẽ là Cooler Master MASTERLIQUID ML240L V2 ARGB hoặc Tản nhiệt nước NZXT AIO Kraken X53&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="lựa-chọn-cửa-hàng-để-mua"&gt;Lựa chọn cửa hàng để mua
&lt;/h1&gt;&lt;p&gt;Đây cũng là một vấn đề nan giải, vì chưa có kinh nghiệm mua lần nào nên không có định hướng lắm. Cũng cân nhắc nhiều nơi nổi tiếng đã biết từ trước:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phong Vũ: xưa giờ mua đồ ở đây khá nhiều, lần bảo hành laptop cũng ok phết&lt;/li&gt;
&lt;li&gt;GearVN: có kênh Youtube khá là xịn xò, mình học hỏi từ kênh này cũng rất nhiều, đã từng mua chuột và bàn phím hồi mới đi làm, xài khá tốt&lt;/li&gt;
&lt;li&gt;Hà Nội Computer&lt;/li&gt;
&lt;li&gt;An Phát PC
-&amp;hellip;
Cả mấy chỗ vừa mới biết đến khi đang tìm hiểu qua diễn đàn, Youtube,&amp;hellip; nữa:&lt;/li&gt;
&lt;li&gt;Tin học ngôi sao (lên diễn đàn nghe nói chỗ này bán rẻ lắm, mà khâu bảo hành phốt lại nhiều :&amp;rsquo;()&lt;/li&gt;
&lt;li&gt;Nguyễn Công PC (biết qua kênh Youtube AMTech)&lt;/li&gt;
&lt;li&gt;TNC Store (cũng Youtube)&lt;/li&gt;
&lt;li&gt;Tân Doanh&lt;/li&gt;
&lt;li&gt;Tân Thành Danh
-&amp;hellip;
Trong đó có mấy chỗ tìm hiểu xong mới biết nó chỉ có cửa hàng ở Hà Nội nữa @@&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rốt cuộc mình chốt là GearVN, vì các lý do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Khá nổi tiếng, phần marketing làm quá tốt luôn (và nổi tiếng thật, bữa đi mua ở đây chờ hàng dài luôn, do GVN có cơ chế làm là vào mua hàng sẽ có 1 nhân viên phụ trách tư vấn, lên đơn, bán hàng,&amp;hellip; chứ không như nhiều chỗ khác, rồi còn dịch nữa, nên khá hạn chế mặt này, may bữa đi buổi chiều chứ không chịu nắng chảy mỡ luôn @@)&lt;/li&gt;
&lt;li&gt;Uy tín, hàng mới, chính hãng, không fake (cái này chắc là trùng lặp dòng trên rồi :D)&lt;/li&gt;
&lt;li&gt;Các linh kiện mình liệt kê bên trên đều còn hàng (ít nhất là trên website để như vậy, còn sự thật thì&amp;hellip; chờ đọc phần đi mua hàng nhé :))))&lt;/li&gt;
&lt;li&gt;Phần chăm sóc khách hàng được đánh giá khá tốt (và bữa gọi điện cũng thấy tốt thật, tí nữa kể sau), như một cái bảo hiểm vậy, đầu tư để đó chứ không cần dùng đến vẫn hơn (như mua BHYT hay BHTN mấy ai mong mình bệnh tật hay tai nạn để được hoàn tiền đâu nào :|, chỉ là có việc cần đến bệnh viện thì lấy ra dùng sẽ đỡ được một phần tiền thôi)&lt;/li&gt;
&lt;li&gt;Showroom đẹp mắt, đi vào mua sẵn xem ké cho lác con mắt (đợt mua chuột với bàn phím hơi bị ghiền đó)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="đến-cửa-hàng"&gt;Đến cửa hàng
&lt;/h1&gt;&lt;p&gt;Hôm mình ghé showroom GearVN trên đường Hoàng Hoa Thám thì là tầm hơn 4h chiều, từ quê chạy lên trọ sẵn ghé qua luôn (đi đường Cộng Hoà ghé vào xíu là tới ấy mà), do dịch nên GearVN dùng đoạn ở trước showroom làm chỗ xếp hàng (y như sắp hàng trong mấy khu vui chơi vậy :v), không cho đậu xe ở trước nữa mà phải chạy vào con hẻm đối diện gửi xe (cũng khá xa đó, chạy gần tới cuối hẻm mới thấy, bữa tưởng đi lộn hay gì rồi). Gửi xe này thì miễn phí, hơi khổ nỗi đi bộ xa, tới rồi thì xếp hàng, quét mã QR khai báo y tế (mấy thủ tục này dạo này đi đâu cũng thế thôi), hết hàng chờ bên ngoài rồi còn vào cửa hàng, rửa tay sát khuẩn rồi mới ngồi trên hàng ghế gaming đợi bạn tư vấn tới dắt đi nữa (y như cho ngồi thử ghế êm không vậy, mà công nhận là êm thật :v, êm hơn hẳn mấy ghế văn phòng, cơ mà chẳng có tiền đâu mà mua :v). Xong được anh tư vấn viên đẹp trai (nói thế thôi chứ ai cũng đeo khẩu trang mà, biết ảnh đẹp trai thế quái nào được) dắt đến chỗ bàn máy tính để check qua linh kiện còn hàng tại HCM.&lt;/p&gt;
&lt;p&gt;Vào đề mình nói thẳng luôn về nhu cầu và yêu cầu của mình: cấu hình phần &amp;ldquo;ruột&amp;rdquo; thì không đổi được, còn phần &amp;ldquo;hình thức&amp;rdquo; thì tuỳ biến. May mà phần ruột thì khá ok, trừ cái phần RAM không có ram Kingston, nên đổi qua cặp ram Corsair Vengeance RS RGB. Cũng 2x16GB 3200Mhz nên mình cũng không ý kiến gì mấy Mọi thứ cũng tương đối suôn sẻ cho đến khi tới phần mainboard, chẳng còn cái main ITX nào tại HCM cả :&amp;rsquo;( Thế là mọi thứ đổ bể, có 2 phương án nhưng toàn ITX, hoàn toàn không nghĩ đến trường hợp này. Thế là mình nói anh ấy chuyển qua mục tiêu build một PC sao cho đẹp một cách tinh tế, không cần hầm hố, và cũng bảo là nếu được thì full combo NZXT luôn đi. Sau một hồi lựa chọn và khóc thầm (vì mấy cái mình thích đều hết, còn mấy cái cũng ngon nghẻ mà giá chát quá :&amp;rsquo;() thế là được bộ cấu hình như sau:&lt;/p&gt;
&lt;p&gt;Đến đây thì hẳn bạn sẽ thắc mắc thế phần dự định bên trên để làm gì? Thật tiếc nếu bạn đọc phần đó, như bạn cũng thấy &lt;em&gt;&amp;ldquo;người tính không bằng trời tính&amp;rdquo;&lt;/em&gt; thực tế khác với dự định. Đừng cáu nếu lỡ đọc rồi nhé, tại mình mê mà không build được nên thuốc cho bạn mua đấy :)))&lt;/p&gt;
&lt;h1 id="sau-khi-mua"&gt;Sau khi mua
&lt;/h1&gt;&lt;p&gt;Ngay sau khi đặt mua, mình về nhà rồi mới lên trang chủ của GearVN xem lại, thì đúng là cái Corsair C750W được giảm giá 200k lận. Mà quá giờ làm việc rồi, thế là ngay hôm sau gọi điện lên cho CSKH, sau đó được anh tư vấn gọi lại ngay, bảo là cái đó shop mới sửa giá lại trong ngày, mong mình thông cảm, và sẽ hoàn lại tiền cho mình, mình cũng ậm ừ (dù biết tỏng vì đã điều tra kĩ rằng giá này đã tồn tại từ trước đó rồi :))). Chờ mãi sang hôm sau cũng không thấy động tĩnh gì, cũng hơi quan ngại, tại hôm qua gọi chỉ là anh đó nói suông thôi, lời nói gió bay ai mà tin được, chẳng có chứng từ cụ thể gì cả. Ai dè hôm sau nữa (tức 2 ngày sau khi đặt hàng), có một chị CSKH gọi lại báo là có mail cho mình mà không để ý (mà không biết GearVN trước nay có spam gì không mà bị bộ lọc mail của Outlook cho vào Junk luôn :v). Xong mail lại&lt;/p&gt;
&lt;p&gt;3 ngày sau khi mình đặt mua, mình lên lại web và lại phát hiện phần ram mình mua đã được giảm xuống 500k. Thật sự cay cú, cứ như là GearVN đợi mình mua xong rồi giảm giá thì phải :))) Nhưng không được như lần trước, lần này mình chỉ được bảo là giá đó là do lô hàng mới giá RAM giảm rồi, hồi chốt giá thì không thay đổi được nữa :| Thui thì cũng&amp;hellip; đành chịu, cơ mà ít ra gọi còn được bắt máy là vui rồi :))) Đánh giá rất cao mảng CSKH của GearVN nhé.&lt;/p&gt;
&lt;p&gt;Rồi cũng tới ngày nhận được máy&amp;hellip; :D Cùng xem qua một số đánh giá nho nhỏ của mình ở phần dưới nhé!&lt;/p&gt;
&lt;h1 id="đánh-giá"&gt;Đánh giá
&lt;/h1&gt;&lt;p&gt;Do thay đổi quyết định ngay trong lúc mua chủ yếu là 3 yếu tố mainboard, case với ram là chính nên sẽ chỉ đi sâu vào phân tích 3 cái này thôi. Cái tản nhiệt NZXT X63 thì lớn hơn X53 (và giá cũng lớn hơn :v) chứ không khác nhau nhiều.&lt;/p&gt;
&lt;h2 id="mainboard-nzxt-n7-b550"&gt;Mainboard NZXT N7 B550
&lt;/h2&gt;&lt;p&gt;So với các mainboard B550 khác của ASUS, GIGABYTE hay MSI thì mình thấy NZXT thật sự hợp gu thẩm mỹ của mình, vì cảm giác nó sang trọng nhưng không hầm hố, lại đồng bộ style với nhiều thành phần của case (do cùng hãng sản xuất thôi mà). Một số điểm mạnh thì Số cổng kết nối thì nhiều vãi&amp;hellip; Còn nhược điểm thì nghe dân tình bảo NZXT mới dấn thân vào mảng mainboard nói chung và cho chip AMD nói riêng nên chắc còn khá &amp;ldquo;non tay&amp;rdquo;, BIOS không được đánh giá cao, cảm giác phần giao diện web chỗ dùng để tải driver còn để kèm với manual khá là lộn xộn.&lt;/p&gt;
&lt;h2 id="case-nzxt-h510-elite"&gt;Case NZXT H510 Elite
&lt;/h2&gt;&lt;p&gt;Mình khẳng định luôn, nếu không phải lúc đó case NZXT H510 hết hàng thì chẳng đời nào mình chọn case này, vốn mình quan tâm hiệu suất hơn chứ không quan trọng về hình thức, nếu là case ITX thì còn định bỏ lên mặt bàn, chứ case tầm mid-tower như này thì còn tính bỏ gầm bàn nữa là. Đem về dùng mình cũng dùng phần mềm CAM tắt hết led RGB đi thôi. Nên có thể nói: phần tiền dành cho đèn đóm có sẵn, quạt led RGB, mặt kính phía trước để show led đều phế cả rồi :&amp;rsquo;( Điểm cộng của nó chắc là để chụp hình khoe hàng vài lần như này thôi.&lt;/p&gt;
&lt;h2 id="ram-corsair"&gt;Ram Corsair
&lt;/h2&gt;&lt;p&gt;Như đã nói ở trên, mình chú trọng phần hiệu năng, nên led có sẵn của mấy thanh ram cũng không dùng đến là mấy, còn 32GB 3200Mhz trong tầm 4-5 triệu thì cũng rẻ hơn cặp ram Kingston ban đầu mình định chọn, còn hiệu năng như nào thì chắc sử dụng mới biết (mà chắc cũng chẳng cảm nhận được, vì có cái gì đâu mà so với chả sánh :v)&lt;/p&gt;
&lt;h1 id="tổng-kết"&gt;Tổng kết
&lt;/h1&gt;&lt;p&gt;Đánh giá trên thang điểm 10 thì lần đi mua hàng này của mình nằm đâu đó khoảng 8đ, gọi là tốt nhưng vẫn cứ tiếc mãi case ITX mà không có, lại dồn tiền vào một cái case khá là mắc với những tính năng không dùng tới nữa :|, mà hi sinh vì cái đẹp cũng đáng, hehe. Dù sao thì chuyện cũng đã qua, mọi thứ còn lại là kinh nghiệm và trải nghiệm. Mình vẫn sẽ trân quý bộ PC lần đầu tiên mình build này, nhưng hẳn là sau này (chắc là còn lâu hoặc sẽ chẳng bao giờ tới luôn) mình sẽ đổi, nâng cấp lên một bộ PC khác; có lẽ là khi dư dả (không dư dả ai lại mang tiền đi build PC hoài @@). Cũng đã trải nghiệm qua thực tế thì thấy CSKH của GearVN khá là tốt, nên tương lai có nâng cấp hay mua mới gì thì mình cũng sẽ ủng hộ GearVN tiếp!^^&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Do đang cài máy và còn phải &amp;ldquo;test hiệu năng&amp;rdquo; bằng vài ván game :))) nên sẽ cập nhật lại bài viết trong thời gian tới. Nếu bạn đọc được tới dòng này thì thật sự cảm ơn nhé!^^&lt;/em&gt;&lt;/p&gt;</description></item><item><title>PC của tôi và OS của nó</title><link>https://miti99.com/post/2021/11/21/</link><pubDate>Wed, 17 Nov 2021 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2021/11/21/</guid><description>&lt;p&gt;Đọc blog đã lâu thì hẳn bạn cũng biết mình là fan của Linux (gọi là fan cho ngầu chứ a dua học đòi thôi, còn hiểu biết chẳng bao nhiêu hic). Chỉ là từ hồi đi làm tới nay thì cần một hệ thồng &amp;ldquo;stable&amp;rdquo; nên ít nghịch ngợm Linux hơn xưa, do bận việc, nghịch bậy lại mắc công cài đi cài lại tốn thời gian.&lt;/p&gt;
&lt;p&gt;Như blog trước thì bạn cũng biết, mình mới build 1 con PC. Thì hôm nay mình sẽ kể bạn nghe câu chuyện về hệ điều hành của nó.&lt;/p&gt;
&lt;p&gt;Bữa đầu mua về mình quyết định cài Windows 11 cho nó. Thật ra thì mấy thành phần để support Windows 10 là chủ yếu, mà mình thấy cũng không khác gì nhau. Cài vào mới thấy Windows 11 về mặt trải nghiệm người dùng chán quá, dùng mới 2-3 hôm không biết nhiều nhưng thấy chán cái Windows Explorer ghê, phải nói là lần nào chuột phải cũng phải chọn cái &amp;ldquo;more options&amp;rdquo; rất là bất tiện. Nhưng mà Windows được cái hỗ trợ game rất là ngon, muốn chơi Liên Minh Huyền Thoại bản Garena của VN thì linux phải chịu thôi. Tranh thủ 2 ngày cuối tuầnữa test hiệu năng (bằng game :D) đã đời thì thấy rất là ổn áp. Chơi game bật max đồ họa mà FPS trên 100 là ngon rồi, dù màn hình 2k nhưng chỉ 60Hz :&amp;rsquo;(. Chơi chán thế là lại nổi máu &amp;ldquo;tình yêu Linux&amp;rdquo;, ngồi cài Archlinux cho nó, cũng setup theme bla bla bla khá là đẹp rồi, xong boot Windows 11 không lên @@ Quá là hoảng hốt, mình thử vài cách, tạo boot Windows, chạy repare,&amp;hellip; mà không ăn thua gì cả :&amp;rsquo;( Thế là &amp;ldquo;nhân cơ hội&amp;rdquo;, mình định cài lại Windows 10 và combo Ubuntu (mình có kinh nghiệm trong xài Arch và Ubuntu là chủ yếu, hoặc mấy OS loại xài package deb cũng tàm tạm, chứ bên rpm hay tự custom thì không rành lắm, nhỡ bị gì thì cũng hơi hiu), tại cũng cần thứ gì đó &amp;ldquo;ổn định&amp;rdquo;, ngại vọc lắm rồi. Mà xui sao cài Ubuntu 20.04 nó không nhận wifi trên cái mainboard N7 B550 của mình. Đi search thử thì có ông bảo xài bản 21.04 mới được, check lại thì thấy bản mới xài kernel 5.13, còn bản 20.04 xài kernel cũ hơn, chắc kernel mới mới có, vậy thì xài Arch cho rồi. Thế rồi cũng nghịch thử vài OS base on Ubuntu khác như Mint, Elementary,&amp;hellip; tất nhiên là cũng không thành, lỗi có vẻ tại kernel outdate mà. Chợt nhớ ra hồi xưa có xem qua distro PopOS, thằng này hay cập nhật driver mới nhất lắm, xưa mấy ông xài VGA NVDIA rất chuộng OS này. Thế rồi nghịch thử và được thật, thì ra PopOS có 1 cái repo riêng, cài hẳn cho mình kernel 5.13 luôn, thế là chạy ngon ơ. Nhưng xài được vài tiếng thì cái Gnome Activities (cái góc trên bên trái bấm vào show hết app đang chạy ấy, hoặc bấm nút Windows cũng được) không hoạt động nữa. Tốn hết buổi sáng để setup Arch Linux, tốn cả buổi chiều để thử PopOS, rồi tốn buổi tối để cài lại Windows hic hic. Thôi thì số phận đưa đẩy ta về với &amp;ldquo;sự ổn định&amp;rdquo; của Windows. Mà dù sao ban đầu mình cùng định dual boot 2 thằng thôi. Windows để chơi game giải trí + cài đặt mấy cái RGB của con PC :v (linux cũng có tool, mà do &amp;ldquo;dân chơi&amp;rdquo; ghiền tự viết source thì làm sao đọ với official được :v nên không xịn bằng). Với mình cũng đang có subscription của Office 365, &amp;ldquo;tài liệu&amp;rdquo; :))) cũng để trên OneDrive là chính, giờ cũng khó dứt Windows lắm.&lt;/p&gt;
&lt;p&gt;Chốt lại là dân chơi hệ ghiền Linux đã thất bại trong việc theo đuổi đam mê, fanboy&amp;hellip; cùi :&amp;rsquo;( Giờ sống trong sự &amp;ldquo;ổn định&amp;rdquo; của Windows 10 mà thôi (Windows 11 hình như CAM nó sao sao ấy, chỉnh led không hiện ngay, có khi không detect được mainboard nữa, phải bấm fix mới được). Chắc lại thỏa mãn cơn ghiền Linux bằng WSL hay cài máy ảo thui hic hic&lt;/p&gt;</description></item><item><title>Trở lại</title><link>https://miti99.com/post/2021/10/04/</link><pubDate>Mon, 04 Oct 2021 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2021/10/04/</guid><description>&lt;p&gt;Vào tầm tháng 7/2020, như đa phần sinh viên năm 3 khác, mình đi thực tập tốt nghiệp. Với một may mắn nhỏ, mình trúng tuyển chương trình VNG Tech Fresher (VTF) 2020 của &lt;a class="link" href="https://www.vng.com.vn/" target="_blank" rel="noopener"
&gt;VNG&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Được làm việc tại một mảng hoàn toàn mình chưa từng tìm hiểu trước đó là mảng lập trình game. Sau đó may mắn một lần nữa mình được trở thành nhân viên chính thức cho đến hiện tại. Có lẽ sẽ có bài viết chi tiết hơn để chia sẻ điều này.&lt;/p&gt;
&lt;p&gt;Mà cũng từ đó mình tìm hiểu nhiều thứ mới lạ hơn, chưa từng được biết, học Java, JavaScript nghiêm túc hơn. Có lần tìm hiểu được vài cái hay ho nhưng viết blog mình cập nhật theme Coder lên bản mới nhất thì bị lỗi. Mà cũng lười, nên mình bỏ viết blog từ đấy.&lt;/p&gt;
&lt;p&gt;Sau hơn 1 năm bỏ bê blog, bạn thấy bài viết này tức là mình đã &amp;lsquo;comeback&amp;rsquo; rồi đó ^^.&lt;/p&gt;
&lt;p&gt;Mình quyết định chuyển blog sang GitHub Pages với địa chỉ mới là &lt;a class="link" href="https://tiennm99.github.io" target="_blank" rel="noopener"
&gt;https://tiennm99.github.io&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Bên cạnh đó cũng cập nhật theme Coder lên bản mới nhất hiện tại. Thời gian tới sẽ cố gắng viết blog thường xuyên hơn.&lt;/p&gt;
&lt;p&gt;Cảm ơn các bạn.&lt;/p&gt;</description></item><item><title>Vấn đề với Xfce</title><link>https://miti99.com/post/2020/06/29/</link><pubDate>Mon, 29 Jun 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/06/29/</guid><description>&lt;p&gt;Arch của bạn chỉ cài mỗi Xfce và bị &amp;ldquo;dứng&amp;rdquo; khi khởi động? Hay khi khởi động LightDM thì bị giật giật?&lt;/p&gt;
&lt;p&gt;Hãy cài package &lt;code&gt;xf86-video-intel&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Vấn đề về compositor với Plank trong Xfce</title><link>https://miti99.com/post/2020/06/28/</link><pubDate>Sun, 28 Jun 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/06/28/</guid><description>&lt;p&gt;Bạn dùng Plank trong Xfce và gặp trường hợp có sọc ngang như bên dưới?&lt;/p&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2020/06/28/img/1.png"
width="1918"
height="339"
srcset="https://miti99.com/post/2020/06/28/img/1_hu_1f7201cfe6d2376e.png 480w, https://miti99.com/post/2020/06/28/img/1_hu_b96815f8d22717c2.png 1024w"
loading="lazy"
alt="1.png"
class="gallery-image"
data-flex-grow="565"
data-flex-basis="1357px"
&gt;&lt;/p&gt;
&lt;p&gt;Hãy vào tab &lt;code&gt;Compositor&lt;/code&gt; trong &lt;code&gt;Windows Manager Tweaks&lt;/code&gt; và bỏ tick trong mục &lt;code&gt;Show shadows under dock windows&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://miti99.com/post/2020/06/28/img/2.png"
width="1863"
height="591"
srcset="https://miti99.com/post/2020/06/28/img/2_hu_2a7e6546bd3480c9.png 480w, https://miti99.com/post/2020/06/28/img/2_hu_aebc044acbe6adbc.png 1024w"
loading="lazy"
alt="2.png"
class="gallery-image"
data-flex-grow="315"
data-flex-basis="756px"
&gt;&lt;/p&gt;</description></item><item><title>Những việc cần làm sau khi cài đặt Ubuntu 20.04</title><link>https://miti99.com/post/2020/06/27/</link><pubDate>Sat, 27 Jun 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/06/27/</guid><description>&lt;p&gt;&lt;strong&gt;Đây là bài viết tổng hợp những điều cơ bản mình đã làm sau khi cài lại Ubuntu 20.04&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Cập nhật hệ thống&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt upgrade
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start="2"&gt;
&lt;li&gt;Cài đặt một số phần mềm cần thiết&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install gdebi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Các phần mềm mình đã cài với &lt;code&gt;gdebi&lt;/code&gt; là:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.google.com/chrome/" target="_blank" rel="noopener"
&gt;Google Chrome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://code.visualstudio.com/" target="_blank" rel="noopener"
&gt;Visual Studio Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.dropbox.com/install" target="_blank" rel="noopener"
&gt;Dropbox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Một số phần mềm hay ho khác:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spotify:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sS https://download.spotify.com/debian/pubkey.gpg &lt;span class="p"&gt;|&lt;/span&gt; sudo apt-key add -
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;deb http://repository.spotify.com stable non-free&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sudo tee /etc/apt/sources.list.d/spotify.list
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo apt-get install spotify-client
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start="3"&gt;
&lt;li&gt;Cài đặt &lt;code&gt;zsh&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install zsh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chsh -s /usr/bin/zsh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Cài đặt công cụ quản lý zsh plugins: &lt;code&gt;zgen&lt;/code&gt;. Mặc dù &lt;code&gt;zgen&lt;/code&gt; đã cũ nhưng mà mình thấy trong những công cụ khác trong repository của Ubuntu là &lt;code&gt;zplug&lt;/code&gt; và &lt;code&gt;zsh-antigen&lt;/code&gt; thì &lt;code&gt;zgen&lt;/code&gt; đơn giản và nhẹ hơn nhiều.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install zgen
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Chỉnh sửa file &lt;code&gt;.zshrc&lt;/code&gt; của bạn lại cho phù hợp, ví dụ của mình như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;span class="lnt"&gt;61
&lt;/span&gt;&lt;span class="lnt"&gt;62
&lt;/span&gt;&lt;span class="lnt"&gt;63
&lt;/span&gt;&lt;span class="lnt"&gt;64
&lt;/span&gt;&lt;span class="lnt"&gt;65
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; -r &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;XDG_CACHE_HOME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.cache&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/p10k-instant-prompt-&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(%)&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;%n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.zsh&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;XDG_CACHE_HOME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.cache&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/p10k-instant-prompt-&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(%)&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;%n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.zsh&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;GTK_IM_MODULE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ibus
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;QT_IM_MODULE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ibus
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;XMODIFIERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;@im&lt;span class="o"&gt;=&lt;/span&gt;ibus
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;QT4_IM_MODULE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ibus
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;CLUTTER_IM_MODULE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ibus
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;thefuck --alias&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/usr/share/zgen/zgen.zsh&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; ! zgen saved&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/alias-finder
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/colored-man-pages
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/colorize
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/command-not-found
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/common-aliases
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/extract
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/git-auto-fetch
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/gitignore
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/golang
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/gpg-agent
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/history
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/node
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/npm
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/python
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/sudo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/systemd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/thefuck
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/ubuntu
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/vscode
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/wd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen oh-my-zsh plugins/z
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen loadall &lt;span class="s"&gt;&amp;lt;&amp;lt;EOPLUGINS
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; desyncr/auto-ls
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; djui/alias-tips
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; srijanshetty/node.plugin.zsh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; voronkovich/mysql.plugin.zsh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; zlsun/solarized-man
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; zpm-zsh/ls
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; zpm-zsh/ssh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; zsh-users/zsh-autosuggestions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; zsh-users/zsh-syntax-highlighting
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; zsh-users/zsh-history-substring-search
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOPLUGINS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen load zsh-users/zsh-completions src
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen load romkatv/powerlevel10k powerlevel10k
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; zgen save
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;fg=#120299,bg=cyan&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[[&lt;/span&gt; ! -f ~/.p10k.zsh &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; ~/.p10k.zsh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start="4"&gt;
&lt;li&gt;Cài đặt &lt;code&gt;tlp&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install tlp
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo tlp start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Trở lại với Ubuntu</title><link>https://miti99.com/post/2020/06/26/</link><pubDate>Fri, 26 Jun 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/06/26/</guid><description>&lt;p&gt;Sau một khoảng thời gian học hỏi được khá nhiều điều về Linux khi sử dụng Archlinux, mình nghĩ đã đến lúc mình nên trở về với Ubuntu. Bớt vọc vạch để máy tính mình bớt căng&amp;hellip; CPU vì mình :)))&lt;/p&gt;
&lt;p&gt;Với người dùng Linux thì việc chuyển đổi hệ điều hành chắc không cần giải thích chi nhiều đâu nhỉ :)))&lt;/p&gt;</description></item><item><title>Viết blog với hugo</title><link>https://miti99.com/post/2020/06/23/</link><pubDate>Tue, 23 Jun 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/06/23/</guid><description>&lt;p&gt;Như các bạn cũng biết, blog này của mình sử dụng hugo để tạo ra. Bài viết này mình sẽ hướng dẫn các bạn dùng hugo để tạo ra một static website tương tự.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Đầu tiên cần cài đặt hugo:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S hugo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start="2"&gt;
&lt;li&gt;Vào thư mục làm việc (working directory) của bạn, sử dụng hugo tạo thư mục chứa website mới. Ví dụ ở đây mình tạo thư mục &lt;code&gt;miti99&lt;/code&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo new site miti99
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Nếu bạn đã tạo một git và clone về và muốn tạo website trong thư mục đó, thì thêm đuôi &lt;code&gt;--force&lt;/code&gt; vào nhé. Ví dụ:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo new site miti99 --force
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start="3"&gt;
&lt;li&gt;Vào thư mục vừa tạo, tải theme cho trang web của bạn, các theme này bạn tìm tại website theme của hugo (&lt;a class="link" href="https://themes.gohugo.io/" target="_blank" rel="noopener"
&gt;https://themes.gohugo.io/&lt;/a&gt;). Ví dụ ở đây mình chọn theme &lt;a class="link" href="https://themes.gohugo.io/beautifulhugo/" target="_blank" rel="noopener"
&gt;&lt;code&gt;Beautiful Hugo&lt;/code&gt;&lt;/a&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; miti99
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git init &lt;span class="c1"&gt;# Nếu bạn dùng git clone website thì bỏ qua bước này&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git submodule add https://github.com/halogenica/beautifulhugo.git themes/beautifulhugo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Copy exampleSite để xem thử:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;\c&lt;/span&gt;p -rf themes/beautifulhugo/exampleSite/* .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start="4"&gt;
&lt;li&gt;Chạy lệnh sau để xem thử website của bạn:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start="5"&gt;
&lt;li&gt;Chỉnh sửa các file như &lt;code&gt;config.toml&lt;/code&gt; và các file trong &lt;code&gt;content&lt;/code&gt; (cùng các file các nếu bạn muốn tùy chỉnh) để có được website cho riêng mình. Nhớ tham khảo các file mẫu có sẵn để tận dụng tối đa các tính năng của theme bạn đã chọn nhé!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Mình sẽ giới thiệu cách build và deploy website lên Gitlab Pages, Github Pages hoặc Firebase Hosting&amp;hellip; trong một bài viết khác. Hẹn gặp các bạn sau!&lt;/p&gt;</description></item><item><title>Chuyển sang Voidlinux</title><link>https://miti99.com/post/2020/06/10/</link><pubDate>Wed, 10 Jun 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/06/10/</guid><description>&lt;p&gt;Sau một thời gian sử dụng &lt;a class="link" href="https://www.archlinux.org/" target="_blank" rel="noopener"
&gt;Archlinux&lt;/a&gt; cũng khá tâm huyết mình đang chuyển sang dùng thử &lt;a class="link" href="https://voidlinux.org/" target="_blank" rel="noopener"
&gt;Voidlinux&lt;/a&gt; &lt;em&gt;(Người ta dùng thử trên máy ảo, còn mình máy thật :v)&lt;/em&gt;. Tuy vậy, với vốn kiến thức thu được sau khoảng thời gian sử dụng Archlinux thì mình thấy khá thoải mái khi sử dụng Voidlinux.&lt;/p&gt;
&lt;p&gt;Mà bây giờ mình thấy sử dụng distro nào cũng không ảnh hưởng gì quá lớn đến các công cụ, miễn cài được là ok rồi :))) Vì vậy trong tương lai mình vẫn sẽ viết bài tiếp nhé (mặc dù sẽ thưa thớt, vì trường mình đã vào &amp;ldquo;mùa&amp;rdquo; bài tập lớn rồi :v)&lt;/p&gt;
&lt;h2 id="cập-nhật-13062020"&gt;Cập nhật 13/06/2020:
&lt;/h2&gt;&lt;p&gt;Mình sẽ trở về với Archlinux vì&amp;hellip; nhớ pacman và AUR :v&lt;/p&gt;</description></item><item><title>Chuyển đổi website</title><link>https://miti99.com/post/2020/06/06/</link><pubDate>Sat, 06 Jun 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/06/06/</guid><description>&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;(Dạo gần đây mình đã đi học lại, và cũng sấp mặt với deadline trên trường, nên hầu như chẳng viết lấy bài nào nữa, nhưng mà sau đợt này có lẽ mình sẽ có thêm &amp;ldquo;kha khá&amp;rdquo; kinh nghiệm để chia sẻ cùng các bạn :))))&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Trước đây mình viết bài trên &lt;a class="link" href="https://miti99.code.blog" target="_blank" rel="noopener"
&gt;trang Wordpress của mình&lt;/a&gt; nhưng dạo này mình vọc vạch để xây dựng trang web cho nhóm &lt;a class="link" href="https://www.facebook.com/bkfcduchoalongan/" target="_blank" rel="noopener"
&gt;BKFC-THPT Đức Hòa&lt;/a&gt; của chúng mình thì mình thấy &lt;a class="link" href="https://gohugo.io/" target="_blank" rel="noopener"
&gt;Hugo&lt;/a&gt; khá là hay, nên quyết định chuyển sang làm web trên Gitlab Pages, là trang này.&lt;/p&gt;
&lt;p&gt;Mong nhận được sự đồng hành từ các bạn. Thân ái!&lt;/p&gt;
&lt;p&gt;P.S: &lt;em&gt;Web của nhóm mình tại &lt;a class="link" href="https://bkfcduchoa.pages.dev/" target="_blank" rel="noopener"
&gt;https://bkfcduchoa.pages.dev/&lt;/a&gt;, mong các bạn ủng hộ ^^&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Pin không sạc đầy</title><link>https://miti99.com/post/2020/05/20/</link><pubDate>Wed, 20 May 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/05/20/</guid><description>&lt;p&gt;Ở đây các bạn cần phân biệt với chai pin nhé!&lt;/p&gt;
&lt;p&gt;Chai pin là khi sạc đạt 100% nhưng nó không đạt được như thiết kế của nhà sản xuất, các bạn có thể chạy thử lệnh sau để kiểm tra nhé:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo tlp-stat -b
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Ví dụ output hiện tại của mình như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---TLP 1.3.1 --------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---Battery Features: Charge Thresholds and Recalibrate
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;natacpi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; active &lt;span class="o"&gt;(&lt;/span&gt;data, thresholds&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tpacpi-bat &lt;span class="o"&gt;=&lt;/span&gt; active &lt;span class="o"&gt;(&lt;/span&gt;recalibrate&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tp-smapi &lt;span class="o"&gt;=&lt;/span&gt; inactive &lt;span class="o"&gt;(&lt;/span&gt;ThinkPad not supported&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---ThinkPad Battery Status: BAT0 &lt;span class="o"&gt;(&lt;/span&gt;Main / Internal&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/sys/class/power_supply/BAT0/manufacturer &lt;span class="o"&gt;=&lt;/span&gt; LGC
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/sys/class/power_supply/BAT0/model_name &lt;span class="o"&gt;=&lt;/span&gt; 01AV463
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/sys/class/power_supply/BAT0/cycle_count &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/sys/class/power_supply/BAT0/energy_full_design &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;45000&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;mWh&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/sys/class/power_supply/BAT0/energy_full &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;38280&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;mWh&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/sys/class/power_supply/BAT0/energy_now &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;38280&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;mWh&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/sys/class/power_supply/BAT0/power_now &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;mW&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/sys/class/power_supply/BAT0/status &lt;span class="o"&gt;=&lt;/span&gt; Full
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/sys/class/power_supply/BAT0/charge_start_threshold &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;96&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;%&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/sys/class/power_supply/BAT0/charge_stop_threshold &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;96&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;%&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tpacpi-bat.BAT0.forceDischarge &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Charge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 100.0 &lt;span class="o"&gt;[&lt;/span&gt;%&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Capacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 85.1 &lt;span class="o"&gt;[&lt;/span&gt;%&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Ở đây theo thiết kế thì pin của mình đạt 45000 mWh nhưng hiện tại khi sạc đến 100% thì chỉ được 38280 mWh thôi, ở phần dưới cùng tlp-stat có tổng kết lại cho mình là pin của mình đã chai đi khoảng 14.9% so với ban đầu rồi (mình thấy cũng bình thường thôi, tại mình dùng được 1 năm rồi, và thời gian cũng có chơi game nhiều, khá là nóng máy).&lt;/p&gt;
&lt;p&gt;Đó là chai pin, trường hợp của mình thì thấy vẫn ổn, nhưng nếu chai đến tận 90% rồi chẳng hạn thì chỉ có cách là thay pin mới khắc phục được thôi. Mà pin thiết kế ra là&amp;hellip; cũng để chai thôi mà :v&lt;/p&gt;
&lt;p&gt;Sau đây là trường hợp mình muốn nói với các bạn: Pin chỉ sạc đến một khoảng nào đó rồi ngừng, không sạc tiếp. Trường hợp này nếu tầm 90-95% là bình thường, vì một số máy thiết kế chỉ đạt đến mức đó thôi là ngừng rồi. Tuy nhiên nếu chỉ tầm 60% hay 80% (trường hợp mình gặp là 79%) thì là &amp;ldquo;bất thường&amp;rdquo; rồi. Mình không biết nguyên nhân nhưng khắc phục như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo tlp fullcharge
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Chúc các bạn thành công và có một viên pin đi cùng chiếc máy :)))&lt;/p&gt;</description></item><item><title>Kết nối với wifi HCMUT01 của trường ĐH Bách Khoa trên Linux</title><link>https://miti99.com/post/2020/05/14/</link><pubDate>Thu, 14 May 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/05/14/</guid><description>&lt;p&gt;Trong Windows thì khi kết nối bạn đã có chỗ để đăng nhập username và password sẵn, giờ mình sẽ hướng dẫn trên linux.&lt;/p&gt;
&lt;p&gt;Bạn chọn các mục như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Security: WPA &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; WPA Enterprise
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Authentication: Tunneled TLS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Anonymous identity: &lt;span class="o"&gt;(&lt;/span&gt;tên người dùng của bạn, tên này là tên bạn đăng nhập vào myBK ấy&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Domain: hcmut.edu.vn
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CA cerificate: &lt;span class="o"&gt;(&lt;/span&gt;None&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CA certificate password: &lt;span class="o"&gt;(&lt;/span&gt;Để trống&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Show passwords: &lt;span class="o"&gt;(&lt;/span&gt;không chọn&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;No CA certificate is required: &lt;span class="o"&gt;(&lt;/span&gt;chọn&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Inner authentication: PAP
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Username: &lt;span class="o"&gt;(&lt;/span&gt;tên người dùng của bạn, giống với identity ở trên&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Password: mật khẩu
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Vậy là xong, sau đó thì bạn connect thôi. Chúc các bạn thành công.&lt;/p&gt;</description></item><item><title>Không vào được trang đăng nhập của router (VD: Inet Center)</title><link>https://miti99.com/post/2020/05/13/</link><pubDate>Wed, 13 May 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/05/13/</guid><description>&lt;p&gt;Hiện tại mình đang ở KTX khu A của ĐHQG TpHCM, mình sử dụng mạng của Inet Center, sau khi xuống KTX thì mình mua thẻ nhưng không vào được trang đăng nhập nữa, nên không dùng internet được. Nó bị lỗi &lt;code&gt;ERR_CONNECTION_REFUSED&lt;/code&gt;. Mình sẽ chỉ bạn cách giải quyết trong trường hợp của mình.&lt;/p&gt;
&lt;p&gt;Mình bị là do Docker chiếm IP của trang router . Để khắc phục chạy các lệnh sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ip link &lt;span class="nb"&gt;set&lt;/span&gt; dev docker0 down
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl disable docker
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sau đó khởi động lại là được.&lt;/p&gt;
&lt;p&gt;Nói chung thì bạn đừng để service docker tự chạy, hãy chạy khi nào cần chạy docker thôi. Đó cũng là các để giảm thiểu các service không cần thiết chạy chiếm tài nguyên máy (như Windows :v)&lt;/p&gt;</description></item><item><title>Chạy các app cần GUI trong Docker</title><link>https://miti99.com/post/2020/05/09/</link><pubDate>Sat, 09 May 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/05/09/</guid><description>&lt;p&gt;Trường hợp của mình là mình lập trình app Python có sử dụng thư viện &lt;code&gt;matplotlib&lt;/code&gt;. Để mình có thể sử dụng được giao diện thì mình cài đặt xhost trong host Arch trước:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S xorg-xhost
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;xhost local:root&lt;/code&gt; hoặc &lt;code&gt;xhost +&lt;/code&gt; (cái này mình không rõ, nó cho phép hết tất cả truy cập vào màn hình luôn, còn phân chia cho từng app cụ thế thì mình không biết)&lt;/p&gt;
&lt;p&gt;Sau đó chạy Docker với tham số bổ sung là &lt;code&gt;–env=&amp;quot;DISPLAY&amp;quot;&lt;/code&gt;. VD:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run -it –rm –net&lt;span class="o"&gt;=&lt;/span&gt;host –env&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;DISPLAY&amp;#34;&lt;/span&gt; –workdir&lt;span class="o"&gt;=&lt;/span&gt;/workspace –volume&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/Dropbox/PP:/workspace:rw&amp;#34;&lt;/span&gt; ubuntu bash
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sau đó trong Docker, mình cài thêm gói &lt;code&gt;python3-pip&lt;/code&gt; nữa.&lt;/p&gt;
&lt;p&gt;Chúc các bạn thành công!!&lt;/p&gt;</description></item><item><title>systemd-swap</title><link>https://miti99.com/post/2020/05/08/</link><pubDate>Fri, 08 May 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/05/08/</guid><description>&lt;p&gt;Đây là một service nhằm tạo ra swap động theo thời gian. Khởi tạo ban đầu chỉ có 512MiB thôi, nhưng sẽ tăng lên một cách &lt;strong&gt;tự động&lt;/strong&gt; khi bạn sử dụng. Cài đặt như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S systemd-swap
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Trong file &lt;code&gt;/etc/systemd/swap.conf&lt;/code&gt; cài đặt như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;swapfc_enabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sau đó enable service systemd-swap:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; systemd-swap
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Vậy là xong!!!&lt;/p&gt;</description></item><item><title>Giúp pin 'sống' lâu hơn</title><link>https://miti99.com/post/2020/05/07/</link><pubDate>Thu, 07 May 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/05/07/</guid><description>&lt;h4 id="cài-đặt-tlp"&gt;Cài đặt TLP
&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S tlp tlp-rdw
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Vì mình sử dụng laptop ThinkPad, hơn nữa là dòng mới, nên mình cài thêm 2 package sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S acpi_call-dkms tpacpi-bat
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Khởi chạy tlp khi khởi động:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; tlp-sleep.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Vài cài đặt được khuyên dùng khác:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; NetworkManager-dispatcher.service
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl mask systemd-rfkill.service
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl mask systemd-rfkill.socket
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Vài tool khác cũng thiết thực không kém, bạn nên tìm hiểu thêm như &lt;code&gt;cpupower&lt;/code&gt; và &lt;code&gt;thermald&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Vậy là xong. Hẹn gặp lại!&lt;/p&gt;</description></item><item><title>Tăng tốc độ makepkg</title><link>https://miti99.com/post/2020/05/06/</link><pubDate>Tue, 05 May 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/05/06/</guid><description>&lt;p&gt;Bài viết mình sẽ giới thiệu cách tinh chỉnh để quá trình build file từ AUR được nhanh hơn. Tuy nhiên cái lợi cũng có cái nguy cơ đi kèm, có khả năng là bạn sẽ gặp phải một lỗi gì đó, ở đâu đấy trong vài trường hợp :v&lt;/p&gt;
&lt;p&gt;Để nhanh gọn, tránh dài dòng, mình sẽ hướng dẫn các bạn kiểu &amp;lsquo;mì ăn liền&amp;rsquo; luôn nha!&lt;/p&gt;
&lt;p&gt;Cài đặt một số package cần thiết:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S ccache lzop xz pigz pbzip2 zstd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sau đó mở file &lt;code&gt;/etc/makepkg.conf&lt;/code&gt;, tìm kiếm các chữ IN HOA, và sửa lại giống với dưới đây:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;-march=native -O2 -pipe -fstack-protector-strong -fno-plt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;CXXFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;BUILDDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/makepkg
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;PKGEXT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.pkg.tar.lzo&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;COMPRESSXZ&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;xz -c -z - --threads&lt;span class="o"&gt;=&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;COMPRESSGZ&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;pigz -c -f -n&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;COMPRESSBZ2&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;pbzip2 -c -f&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;COMPRESSZST&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;zstd -c -z -q - --threads&lt;span class="o"&gt;=&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;BUILDENV&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;!distcc color ccache check !sign&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;MAKEFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;-j&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;nproc&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Tham khảo tại : &lt;a class="link" href="https://wiki.archlinux.org/index.php/Makepkg" target="_blank" rel="noopener"
&gt;https://wiki.archlinux.org/index.php/Makepkg&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Chúc các bạn thành công!&lt;/p&gt;</description></item><item><title>Chơi game với Steam trên Archlinux</title><link>https://miti99.com/post/2020/05/04/</link><pubDate>Mon, 04 May 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/05/04/</guid><description>&lt;p&gt;Có thể nói Steam là một nền tảng hiếm hoi ưu ái cho Linux, trong khi hầu hết các nền tảng khác không hỗ trợ Linux thì Steam có hẳn một OS riêng dựa trên Linux cho gamer, đó là SteamOS; ngoài ra còn hỗ trợ chính thức cho Ubuntu. Hơn nữa, nhiều tựa game đã làm nên tên tuổi Steam như Dota 2, CS:GO,&amp;hellip; Mới đây thì có tựa game khá hay mình cũng có thử (và nghiện) đó là Dota Underlords (nhưng mà quyết tâm cai rồi nha^^). Hiện tại thì mình chỉ chơi game nông trại vui vui là Farm Together cùng với gấu yêu thôi :v. Nói tóm lại là nếu không nói đến các game native (mà đa phần khá là &amp;lsquo;chuối&amp;rsquo;, thiếu cuốn hút) thì Steam là nền tảng chơi game tốt nhất hiện nay cho Linux.&lt;/p&gt;
&lt;h2 id="kích-hoạt-multi-lib"&gt;Kích hoạt multi-lib
&lt;/h2&gt;&lt;p&gt;Để cài đặt Steam thì trước hết ta cần kích hoạt repo &lt;code&gt;multi-lib&lt;/code&gt; cho Arch, repo này chứa các thư viện 32bit, nhằm để phục vụ cho các nền tảng như Steam hay Wine. Để kích hoạt repo này, ta mở file &lt;code&gt;/etc/pacman.conf&lt;/code&gt;, và uncomment 2 dòng sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;multilib&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Include&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; /etc/pacman.d/mirrorlist
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sau đó cập nhật lại hệ thống:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay &lt;span class="o"&gt;(&lt;/span&gt;hoặc sudo pacman -Syyu&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="cài-steam"&gt;Cài Steam
&lt;/h2&gt;&lt;p&gt;Và thế là có thể cài steam được rồi:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S steam
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="chọn-card-màn-hình-rời-để-chơi-game"&gt;Chọn card màn hình rời để chơi game
&lt;/h2&gt;&lt;p&gt;Thông thường thì dùng Linux cho laptop thì chắc chẳng ai quan tâm card màn hình rời nữa (cơ mà cài Linux mà chơi game là thấy cũng &amp;rsquo;lạ&amp;rsquo; rồi :v). Tuy nhiên bạn vẫn có thể setting để chơi game sử dụng card màn hình rời trên Steam bằng cách đặt Lauch Option cho game như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;DRI_PRIME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; %command%
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="tip-nhỏ-để-cải-thiện-hiệu-năng-khi-chơi-game"&gt;Tip nhỏ để cải thiện hiệu năng khi chơi game
&lt;/h2&gt;&lt;p&gt;Bạn có thể cài thêm gamemode để tool tinh chỉnh cấu hình hệ thống của bạn khi chơi game:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S gamemode
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sau đó khởi chạy service gamemoded:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl start gamemoded --user
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Để sử dụng, thì bạn đặt Lauch Option cho game như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gamemoderun %command%
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Vậy là cuối cùng ta có thể mở game và chiến thôi!!!&lt;/p&gt;</description></item><item><title>Splash screen cho Archlinux</title><link>https://miti99.com/post/2020/05/03/</link><pubDate>Sun, 03 May 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/05/03/</guid><description>&lt;p&gt;Bài này mình sẽ hướng dẫn các bạn cài Plymouth làm Splash screen trên Arch Linux. Giống kiểu mấy chấm xoay xoay trên Windows, 5 chấm trắng trắng cam cam trên Ubuntu (mà nay bản 20.04 đổi rồi) hay vòng tròn quay quay trên Fedora vậy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Mình chỉ hướng dẫn thôi chứ mình không còn dùng nữa. Vì mình cảm giác nó làm quá trình khởi động của mình chậm đi.&lt;/p&gt;
&lt;h2 id="đầu-tiên-cần-cài-đặt-plymouth"&gt;Đầu tiên cần cài đặt Plymouth
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S plymouth
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Chỉnh sửa file &lt;code&gt;/etc/mkinitcpio.conf&lt;/code&gt;: Thêm plymouth vào sau base và udev trong dòng HOOKS. VD như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;HOOKS&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;base udev plymouth ...&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Trong file /etc/default/grub, sửa lại kernel parameters lại như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;quiet splash loglevel=3 rd.udev.log_priority=3 vt.global_cursor_default=0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sau đó cập nhật lại grub nhé!&lt;/p&gt;
&lt;p&gt;Trên đó chỉ là ví dụ thôi, bạn có thể xem thêm về Silent Boot tại đây: &lt;a class="link" href="https://wiki.archlinux.org/index.php/Silent_boot" target="_blank" rel="noopener"
&gt;https://wiki.archlinux.org/index.php/Silent_boot&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Khởi tạo lại initramfs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkinitcpio -P
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="sau-đó-cài-đặt-theme"&gt;Sau đó cài đặt theme
&lt;/h2&gt;&lt;p&gt;Trong AUR cũng có nhiều theme lắm rồi, bạn cũng có thể tự tìm thêm nguồn ngoài như trên GitHub&amp;hellip; Sau đó copy vào folder &lt;code&gt;/usr/share/plymouth/themes&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Liệt kê theme có trong máy:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;plymouth-set-default-theme -l
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Mặc định khi cài plymouth sẽ có các theme sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;details glow solar spinner tribar fade-in script spinfinity text
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Đổi theme, ví dụ là script:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;plymouth-set-default-theme -R script
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Để làm cho Plymouth xuất hiện sớm hơn, sửa file &lt;code&gt;/etc/plymouth/plymouthd.conf&lt;/code&gt;, đổi &lt;code&gt;ShowDelay=5&lt;/code&gt; thừ 5 thành 0 nhé!&lt;/p&gt;
&lt;p&gt;Để transition mượt hơn, đổi display manager của bạn lại, Vd thay vì dùng &lt;code&gt;lightdm&lt;/code&gt; thì dùng &lt;code&gt;lightdm-plymouth&lt;/code&gt; nhé!&lt;/p&gt;
&lt;p&gt;Có một vài tinh chỉnh dành cho các bạn dùng encrypt, nhưng mình nghĩ ở đây cũng không mấy bạn dùng nên không giới thiệu nhé. Nếu bạn cần, có thể inbox fanpage của mình nha! Hẹn gặp lại.&lt;/p&gt;</description></item><item><title>Kích hoạt Numlock khi khởi động với LightDM</title><link>https://miti99.com/post/2020/05/02/</link><pubDate>Sat, 02 May 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/05/02/</guid><description>&lt;p&gt;Cài đặt numlockx:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S numlockx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Mở file &lt;code&gt;/etc/lightdm/lightdm.conf&lt;/code&gt;, thêm dòng như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Seat:*&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;greeter-setup-script&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/numlockx on
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Vậy là xong!!&lt;/p&gt;</description></item><item><title>Theme cho GRUB</title><link>https://miti99.com/post/2020/05/01/</link><pubDate>Fri, 01 May 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/05/01/</guid><description>&lt;p&gt;Bạn muốn có giao diện GRUB đẹp hơn? Hôm nay mình sẽ chia sẻ cách để tạo giao diện GRUB đẹp hơn một tí. Ở đây mình ví dụ là theme litarvan có sẵn trong repo của Arch:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S grub-theme-vimix
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sau đó thêm dòng sau vào file &lt;code&gt;/etc/default/grub&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;GRUB_THEME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;”/usr/share/grub/themes/Vimix/theme.txt”
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Cập nhật grub và khởi động lại tận hưởng nào! 😀&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grub-mkconfig -o /boot/grub/grub.cfg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Nếu bạn không thích theme này thì có thể tự tải theme hoặc tự tạo theme mình thích. Lưu ý là nên để ở thư mục nào đó mà hệ thống có thể truy cập được không cần quỵền người dùng nhé. VD &lt;code&gt;/usr/share&lt;/code&gt; như trên.&lt;/p&gt;
&lt;p&gt;Chúc các bạn có được một GRUB thật đẹp nhé! Hẹn gặp lại.&lt;/p&gt;</description></item><item><title>Làm con trỏ chuột trên màn hình đăng nhập đẹp hơn</title><link>https://miti99.com/post/2020/04/30/</link><pubDate>Thu, 30 Apr 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/04/30/</guid><description>&lt;p&gt;Như tiêu đề, để thay đổi con trỏ chuột trong màn hình đăng nhập, bạn sửa giá trị &lt;strong&gt;Inherits&lt;/strong&gt; ở file &lt;code&gt;/usr/share/icons/default/index.theme&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Thông thường, nếu bạn muốn đặt con trỏ chuột giống với con trỏ bạn đang dùng, có thể tham khảo ở file &lt;code&gt;~/.icons/default/index.theme&lt;/code&gt; nhé!&lt;/p&gt;
&lt;p&gt;Chúc các bạn thành công!&lt;/p&gt;</description></item><item><title>Youtube Downloader cho Archlinux</title><link>https://miti99.com/post/2020/04/29/</link><pubDate>Wed, 29 Apr 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/04/29/</guid><description>&lt;p&gt;Như tiêu đề thì mình sẽ giới thiệu với các bạn 2 công cụ mình thường dùng để tải video từ Youtube.&lt;/p&gt;
&lt;h2 id="youtube-dl"&gt;Youtube-dl
&lt;/h2&gt;&lt;p&gt;Khá phổ biến đối với nhiều distro, với nhiều tùy biến câu lệnh, rất là &amp;lsquo;professional&amp;rsquo;, tuy nhiên mình thấy tốc độ tải khá là chậm do phần xử lý nó có phần rườm rà sao ấy. Nên thường mình chỉ dùng để download playlist thôi (kiểu paste một lần rồi mình đi code, đi xem phim gì đấy tí nó tự tải xong, mặc kệ nó :v). Để cài đặt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S youtube-dl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="clipgrab"&gt;Clipgrab
&lt;/h2&gt;&lt;p&gt;Cái tên này nghe mới lạ hơn nên mình giới thiệu luôn. Phần mềm này thì có giao diện, tốc độ tải thì mình đánh giá là cao hơn youtube-dl (chắc đối với mình nó như thế). Để cài đặt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S clipgrab
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Hẹn gặp lại các bạn trong bài viết khác.&lt;/p&gt;</description></item><item><title>Auto TRIM SSD</title><link>https://miti99.com/post/2020/04/20/</link><pubDate>Mon, 20 Apr 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/04/20/</guid><description>&lt;p&gt;Package &lt;code&gt;util-linux&lt;/code&gt; cung cấp &lt;code&gt;fstrim.service&lt;/code&gt; và &lt;code&gt;fstrim.timer&lt;/code&gt; trong &lt;code&gt;systemd&lt;/code&gt; rồi, nên để sử dụng bạn chỉ cần chạy &lt;code&gt;fstrim.timer&lt;/code&gt; là đủ. Thực hiện như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; fstrim.timer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Thời gian mặc định là 1 tuần&lt;/p&gt;
&lt;p&gt;Hẹn gặp lại!&lt;/p&gt;</description></item><item><title>Dùng audio output làm input</title><link>https://miti99.com/post/2020/04/19/</link><pubDate>Sun, 19 Apr 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/04/19/</guid><description>&lt;p&gt;Khi bạn&amp;hellip; gọi cho gấu qua mạng, và muốn có một bản nhạc tình làm nền (cho lãng mạn :v)&amp;hellip; Đây là một tips khá hữu ích !😀&lt;/p&gt;
&lt;p&gt;Cài đặt pavucontrol:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S pavucontrol
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sau đó bạn gọi cho gấu :v, mở &lt;code&gt;pavucontrol&lt;/code&gt; lên, bằng menu hoặc command như trên, chọn qua tab Recording, tại input của phần mềm bạn chọn để gọi và chuyển thành &amp;lsquo;Monitor of Built-in Audio Analog Stereo&amp;rsquo;. Vậy là xong rồi :D, hẹn gặp lại các bạn trong các bài viết khác.&lt;/p&gt;</description></item><item><title>Tweaks nho nhỏ cho Firefox</title><link>https://miti99.com/post/2020/04/18/</link><pubDate>Sat, 18 Apr 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/04/18/</guid><description>&lt;h2 id="cache-on-ram"&gt;Cache on RAM
&lt;/h2&gt;&lt;p&gt;Mặc định thì Firefox sẽ lưu cache trong cả RAM và đĩa, khi lưu trên RAM sẽ giúp cho truy xuất cache nhanh hơn, đồng thời giảm số lần ghi đĩa (đặc biệt tốt cho SSD nhé) thì làm như sau:
Gõ vào đường dẫn url của firefox: &lt;code&gt;about:config&lt;/code&gt;&lt;br&gt;
Đặt &lt;code&gt;browser.cache.disk.enable&lt;/code&gt; thành &lt;code&gt;false&lt;/code&gt;&lt;br&gt;
Đảm bảo &lt;code&gt;browser.cache.memory.enable&lt;/code&gt; là &lt;code&gt;true&lt;/code&gt;&lt;br&gt;
Bạn cũng có thể chỉnh lượng RAM mà Firefox sẽ dùng để lưu cache trong mục &lt;code&gt;browser.cache.memory.capacity&lt;/code&gt;, để mặc định là -1 Firefox sẽ tự động lựa chọn dung lượng.&lt;/p&gt;
&lt;h2 id="tắt-pocket"&gt;Tắt Pocket
&lt;/h2&gt;&lt;p&gt;Pocket mặc định đi kèm Firefox nhưng mình chả mấy sử dụng, nên tắt thôi :D, cũng trong &lt;code&gt;about:config&lt;/code&gt; ở trên, tìm &lt;code&gt;extensions.pocket.enabled&lt;/code&gt; và đặt thành false thôi !😀&lt;/p&gt;
&lt;h2 id="cache-toàn-bộ-profile-vào-ram-qua-tmpfs"&gt;Cache toàn bộ profile vào RAM qua tmpfs
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Bạn cần đảm bảo có đủ cache để mount profile nhé, không thì sẽ gặp lỗi hết bộ nhớ đó!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Mặc định thì tmpfs (service &lt;code&gt;tmp.mount&lt;/code&gt;) khởi chạy mặc định rồi, để tận dụng hơn việc mount /tmp qua ram, thì ta có thể cache toàn bộ profile của Firefox vào RAM qua tmpfs luôn. Đầu tiên, cài đặt Profile-sync-daemon:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S profile-sync-daemon
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sau đó sửa file &lt;code&gt;~/.config/psd/psd.conf&lt;/code&gt; lại, thêm firefox vào list BROWSERS, VD:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;BROWSERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;”firefox”
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Profile-sync-daemon còn hỗ trợ google-chrome, bạn có thể xem thêm ngay trong file ấy, vì vậy có thể thêm browsers bạn dùng vào list trên
Khởi chạy Profile-sync-daemon cùng hệ thống:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl --user &lt;span class="nb"&gt;enable&lt;/span&gt; psd.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Vậy là xong rồi, các bạn có thể tham khảo thêm nhiều tweaks khác tại: &lt;a class="link" href="https://wiki.archlinux.org/index.php/Firefox/Tweaks" target="_blank" rel="noopener"
&gt;https://wiki.archlinux.org/index.php/Firefox/Tweaks&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hẹn gặp lại trong các bài viết khác nhé!&lt;/p&gt;</description></item><item><title>Một số vấn đề gặp phải</title><link>https://miti99.com/post/2020/04/17/</link><pubDate>Fri, 17 Apr 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/04/17/</guid><description>&lt;p&gt;Đây là bài viết tổng hợp một số vấn đề mình gặp phải và cách giải quyết, đây là những cách mà mình làm thì nó hoạt động nên ở mức độ &amp;ldquo;just work&amp;rdquo;, mình không đảm bảo là nếu bạn gặp tình huống như mình thì sẽ được. Bài viết sẽ được cập nhật lại trong quá trình sử dụng của mình nhé!&lt;/p&gt;
&lt;h4 id="arch-cinnamon-không-tắt-màn-hình-sau-thời-gian-đã-định"&gt;Arch Cinnamon không tắt màn hình sau thời gian đã định
&lt;/h4&gt;&lt;p&gt;Bạn thử cài đặt gói &lt;code&gt;light-locker&lt;/code&gt; xem:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S light-locker
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="không-play-được-file-mp4-trong-totem-và-các-player-khác-base-on-totem"&gt;Không play được file .mp4 trong Totem và các player khác base-on Totem
&lt;/h4&gt;&lt;p&gt;Thường thì lỗi này do các bạn thiếu codec cho file này, để cài đặt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S gst-libav
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Hẹn gặp lại các bạn trong các bài viết khác nha!&lt;/p&gt;</description></item><item><title>Zsh và Antibody</title><link>https://miti99.com/post/2020/04/16/</link><pubDate>Thu, 16 Apr 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/04/16/</guid><description>&lt;p&gt;Bài viết này mình giới thiệu về zsh, một shell khác với bash, với khả năng tùy biến rất cao, hỗ trợ rất nhiều, nhất là với những bạn hay dùng lệnh.&lt;/p&gt;
&lt;h2 id="cài-đặt-zsh-và-đặt-làm-shell-mặc-định"&gt;Cài đặt zsh và đặt làm shell mặc định
&lt;/h2&gt;&lt;p&gt;Cài đặt zsh:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S zsh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Đặt zsh là shell mặc định:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chsh -s /bin/bash/zsh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="tùy-biến-zsh"&gt;Tùy biến zsh
&lt;/h2&gt;&lt;p&gt;Mặc định thì zsh cũng chỉ là shell bình thường như bash thôi, nhưng tùy biến rồi thì nó thành &amp;lsquo;siêu shell&amp;rsquo; :v&lt;/p&gt;
&lt;p&gt;Là dân pro thì bạn có thể tự tùy chỉnh bằng tay, bằng code để tùy biến zsh theo ý thích. Nhưng mình thì không được như vậy, nên mình sẽ giới thiệu đến các bạn framework oh-my-zsh khá nổi tiếng và plugin manager antibody. Ngày trước thì có antigen, nhưng mình thấy antigen đã không còn được phát triển nữa, thay vào đó là antibody, được so sánh với hiệu năng tốt hơn (mặc dù mình thấy việc tích hợp ohmyzsh vào antibody có phần khập khiễng hơn so với antigen). Các bạn có thể xem thông tin thêm tại trang chủ của mấy cái trên nha:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/robbyrussell/oh-my-zsh" target="_blank" rel="noopener"
&gt;https://github.com/robbyrussell/oh-my-zsh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/getantibody/antibody" target="_blank" rel="noopener"
&gt;https://github.com/getantibody/antibody&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/zsh-users/antigen" target="_blank" rel="noopener"
&gt;https://github.com/zsh-users/antigen&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Để cài antibody cho Arch:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S antibody
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;(cái này có ghi trong trang chủ luôn rồi^^, đảm bảo nguồn)&lt;/p&gt;
&lt;p&gt;Tùy biến antibody: Ở đây mình hướng dẫn cơ bản thôi, zsh thì có file &lt;code&gt;~/.zshrc&lt;/code&gt; là file source cũng như &lt;code&gt;~/.bashrc&lt;/code&gt; của bash vậy đó. Nhưng antibody thì khuyến khích viết các plugin ở một file khác, vd như &lt;code&gt;~./.zsh_plugins.txt&lt;/code&gt;, sau đó thì load antibody bằng 2 cách: tĩnh hoặc động.
Sau đây là ví dụ về file &lt;code&gt;~./.zsh_plugins.txt&lt;/code&gt; của mình:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/archlinux
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/colored-man-pages
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/colorize
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/command-not-found
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/common-aliases
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/extract
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/git-extras
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/github
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/golang
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/heroku
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/history
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/node
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/npm
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/pip
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/python
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/screen
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/sudo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/systemd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/thefuck
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/vscode
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/web-search
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/yarn
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:plugins/z
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;desyncr/auto-ls
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;djui/alias-tips
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mafredri/zsh-async
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;srijanshetty/node.plugin.zsh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;srijanshetty/zsh-pip-completion
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;voronkovich/mysql.plugin.zsh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wuotr/zsh-plugin-vscode
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zlsun/solarized-man
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zpm-zsh/ls
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zpm-zsh/ssh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zsh-users/zsh-completions
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zsh-users/zsh-autosuggestions
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zsh-users/zsh-syntax-highlighting
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zsh-users/zsh-history-substring-search
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;robbyrussell/oh-my-zsh path:themes/candy.zsh-theme
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Này chỉ là ví dụ thôi, một vài plugin bạn phải cài thêm tool mới dùng được nha. Rồi, tới phần load. Nôm na thì load tĩnh là bạn chạy antibody thành một file &lt;code&gt;config.sh&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;VD: &lt;code&gt;antibody bundle &amp;lt; ~/.zsh_plugins.txt &amp;gt; ~/.zsh_plugins.sh&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Sau đó trong file &lt;code&gt;~/.zshrc&lt;/code&gt; bạn chỉ cần thêm dòng: &lt;code&gt;source ~/.zsh_plugins.sh&lt;/code&gt; là được.&lt;/p&gt;
&lt;p&gt;Cách này nhanh hơn load động, tuy nhiên load tĩnh không tự cập nhật plugin khi có bản cập nhật. Vì vậy mình dùng load động, mình thấy chậm hơn chẳng bao nhiêu (mà vẫn nhanh hơn antigen), nhưng được cập nhật thường xuyên (mỗi lần chạy là mỗi lần check cập nhật đó). Chỉ cần load trong file &lt;code&gt;~/.zshrc&lt;/code&gt; như sau là được:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;ZSH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;antibody home&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/https-COLON--SLASH--SLASH-github.com-SLASH-robbyrussell-SLASH-oh-my-zsh&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;antibody init&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;antibody bundle &amp;lt; ~/.zsh_plugins.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Do mình dùng Oh-My-Zsh mà antibody không hiểu được nên mới cần dòng đâu tiên, antigen thì chỉ cần dùng &lt;code&gt;antigen use oh-my-zsh&lt;/code&gt; thôi, với lại load plugin của oh-my-zsh trong antibody cũng phiền phức hơn nhiều :/ vì ghi quá trời dòng (này mình không biết cách khác, tại lười thử, với dùng multi edit của vscode sửa cũng nhanh, nên khỏi tốn chất xám mắc công :v)&lt;/p&gt;
&lt;p&gt;Nếu bạn không rành, và cũng chẳng muốn tùy biến thì có thể dùng package grml-zsh-config của Arch:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S grml-zsh-config
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Package này sẽ tùy biến zsh của bạn như y chang trong bộ cài bạn dùng để cài Arch vậy.
Tuy nhiên nếu bạn muốn tùy biến thì nên gỡ nó ra, vì nó conflict với vụ dùng theme đấy, có thể chỉnh được mà phiền, nên gỡ quách nó ra cho xong :v&lt;/p&gt;
&lt;p&gt;Tạm biệt các bạn, hẹn gặp lại ở bài viết sau nhé!^^&lt;/p&gt;</description></item><item><title>Vài phần mềm thiết thực cho Archlinux</title><link>https://miti99.com/post/2020/04/15/</link><pubDate>Wed, 15 Apr 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/04/15/</guid><description>&lt;p&gt;Bài viết này mình giới thiệu một số phần mềm có thể cần thiết (đối với mình – với vai trò là một sinh viên CNTT sử dụng
Arch Linux)&lt;/p&gt;
&lt;h2 id="web-browser"&gt;Web Browser
&lt;/h2&gt;&lt;p&gt;Web browser là một thành phần quan trọng phải không nào, để lướt Facebook hay để xem blog này cũng vậy :v. Mặc dù Edge
đã xoắn ngôi Firefox để giành vị trí top 2 browser phổ biến, nhưng Edge chưa có bản cho linux, vì vậy có thể nói Chrome
và Firefox vẫn là 2 browser phổ biến trong thế giới của chúng ta, để cài đặt:&lt;br&gt;
Chrome: &lt;code&gt;yay -S google-chrome&lt;/code&gt;&lt;br&gt;
Firefox: &lt;code&gt;yay -S firefox&lt;/code&gt;&lt;br&gt;
Ngoài ra còn có các browser khác như: Brave (&lt;code&gt;brave-bin&lt;/code&gt;), Chromium (&lt;code&gt;chromium&lt;/code&gt;), Opera (&lt;code&gt;opera&lt;/code&gt;),
Vivaldi (&lt;code&gt;vivaldi&lt;/code&gt;),&amp;hellip;&lt;br&gt;
Bạn xem thêm tại: &lt;a class="link" href="https://wiki.archlinux.org/index.php/List_of_applications/Internet#Web_browsers" target="_blank" rel="noopener"
&gt;https://wiki.archlinux.org/index.php/List_of_applications/Internet#Web_browsers&lt;/a&gt; nhé!&lt;/p&gt;
&lt;h2 id="bộ-gõ-tiếng-việt"&gt;Bộ gõ tiếng Việt
&lt;/h2&gt;&lt;p&gt;Từ lâu, bộ gõ tiếng Việt trên Linux đã là một nỗi đau :v, tuy nhiên gần đây mình tìm được một bộ gõ khá là Ok, đó
là &lt;a class="link" href="https://github.com/BambooEngine/ibus-bamboo" target="_blank" rel="noopener"
&gt;ibus-bamboo&lt;/a&gt;. Chế độ gõ mặc định thì cũng hao hao giống &lt;code&gt;ibus-unikey&lt;/code&gt;
thôi, nhưng bằng việc chuyển chế độ gõ (shortcut là &lt;em&gt;Shift+~&lt;/em&gt;) thì bạn có thể chuyển sang chế độ gõ khác cho từng phần
mềm, có tận 7 chế độ, bạn có thể chuyển cho phù hợp. VD mình chọn chế độ 4. ForwardKeyEvent II để viết blog này đấy. Để
cài đặt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S ibus-bamboo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Bạn vào Ibus Preference để thêm ibus-bamboo là một bộ gõ nhé, sau đó thêm command này vào Startup Application:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ibus-daemon -drx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;để Ibus khởi chạy cùng hệ thống nha!&lt;/p&gt;
&lt;h2 id="phần-mềm-chụp-màn-hình"&gt;Phần mềm chụp màn hình
&lt;/h2&gt;&lt;p&gt;Ngoài &lt;code&gt;gnome-screenshot&lt;/code&gt; ra thì lúc trước mình có dùng shutter, chẳng may cái này ngừng phát triển rồi, mình cũng tìm
được một cái khác thay thế là &lt;code&gt;flameshot&lt;/code&gt;, cũng khá là tiện, bạn có thể chọn khung để chụp, điều chỉnh lại khung sau khi
đã chọn,&amp;hellip; Để cài đặt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S flameshot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="office"&gt;Office
&lt;/h2&gt;&lt;p&gt;Hẳn phải cần đến một bộ Office để còn &amp;rsquo;làm ăn&amp;rsquo; với văn bản, bảng tính hay trình chiếu các kiểu chứ. Mình thì thường dùng
Libre Office, cài đặt cũng dễ thôi, Arch có 2 bản fresh và still, mình thì hay dùng fresh:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S libreoffice-fresh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Ngoài Libre ra thì Arch còn có kha khá các bản Office khác cho bạn lựa chọn: Calligra (&lt;code&gt;calligra&lt;/code&gt;), Only
Office (&lt;code&gt;onlyoffice-bin&lt;/code&gt;), Open Office (&lt;code&gt;openoffice&lt;/code&gt;), Softmaker Office (&lt;code&gt;freeoffice&lt;/code&gt;) và WPS Office (&lt;code&gt;wps-office&lt;/code&gt;) cùng
với những phần mềm &amp;lsquo;rời&amp;rsquo;, thay thế cho từng phần mềm trong các bộ office. Với LibreOffice thì ibus đã hoạt động khá mượt
rồi, tuy nhiên với các bộ khác thì mình thấy phải thêm vào &lt;code&gt;/etc/profile&lt;/code&gt; các dòng sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;GTK_IM_MODULE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ibus
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;XMODIFIERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;@im&lt;span class="o"&gt;=&lt;/span&gt;ibus
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;QT_IM_MODULE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ibus
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="terminal"&gt;Terminal
&lt;/h2&gt;&lt;p&gt;Mặc định bạn có thể dùng gnome-terminal cũng được, nhưng mình hay dùng 2 terminal là terminator và guake, mình có hướng
dẫn cài terminator ở bài hậu cài đặt rồi, nên giờ cài thêm Guake thôi:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S guake
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Guake giúp bạn có thể mở nhanh terminal bằng shortcut F12, tinh chỉnh để terminal tự ẩn, tự chạy cùng hệ thống,… rất
tiện&lt;/p&gt;
&lt;h2 id="nhắn-tin-tiện-lợi-hơn"&gt;Nhắn tin tiện lợi hơn
&lt;/h2&gt;&lt;p&gt;Việc nhắn tin &amp;lsquo;all-in-one&amp;rsquo; rất dễ với Rambox, Rambox giúp chúng ta có thể nhắn tin Messenger, Skype, Telegram&amp;hellip; thậm
chí cả quản lý email như Gmail, Outlook,&amp;hellip; Để cài đặt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S rambox-bin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="quản-lý-clipboard"&gt;Quản lý clipboard
&lt;/h2&gt;&lt;p&gt;Khi bạn&amp;hellip; copy code :v rất nhiều và paste một lượt? Bạn không muốn chuyển tab copy xong paste từng đợt? Đó là lúc bạn
cần đến một phần mềm để quản lý clipboard, ở đây mình dùng CopyQ:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S copyq
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="cloud-sync"&gt;Cloud sync
&lt;/h2&gt;&lt;p&gt;Tin buồn là 2 cloud lớn với sinh viên là Google Drive và Onedrive (dùng mail sinh viên thì có Google Drive unlimit, còn
Onedrive thì cho 5TB) thì không hỗ trợ linux một cách chính thức, có nhiều cách thay thế nhưng thay thế thì ai đảm bảo
đâu, nên mình không dùng. Mình dùng Dropbox:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S dropbox
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Ngoài ra thì cũng có nhiều host hỗ trợ linux lắm, như MEGA (&lt;code&gt;megasync&lt;/code&gt;), Nextcloud (&lt;code&gt;nextclout-client&lt;/code&gt; nếu bạn dùng host
của người ta),&amp;hellip;
Bạn có thể tham khảo một số host khác được đề cập tại đây:
&lt;a class="link" href="https://wiki.archlinux.org/index.php/List_of_applications/Internet#Cloud_synchronization_clients" target="_blank" rel="noopener"
&gt;https://wiki.archlinux.org/index.php/List_of_applications/Internet#Cloud_synchronization_clients&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="tools-lập-trình"&gt;Tools lập trình
&lt;/h2&gt;&lt;p&gt;Mình đang thử làm quen với NeoVim:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S neovim
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Nhưng trước khi quen được thì VScode vẫn là editor mình đang dùng.
VScode: editor mình ưng ý nhất hiện tại:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S visual-studio-code-bin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="teamviewer"&gt;Teamviewer
&lt;/h2&gt;&lt;p&gt;Teamviewer – kết nối từ xa cho mọi nhà :v&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S teamviewer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Các bạn nhớ enable teamviewerd service để kết nối được nha:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; teamviewerd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;rồi restart mới dùng được&lt;/p&gt;
&lt;h2 id="phần-mềm-compare-file"&gt;Phần mềm compare file
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S meld
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="phần-mềm-ảo-hóa-để-chạy-máy-ảo"&gt;Phần mềm ảo hóa để chạy máy ảo
&lt;/h2&gt;&lt;p&gt;Khi cài nhóm gnome thì bạn đã có sẵn gnome-boxes rồi, tuy nhiên thì mình vẫn thấy VirtualBox là nhất trên Linux :v Lưu ý
là bạn cần cài thêm linux-headers (nếu bạn dùng kernel mặc định của Arch) để mà cài dkms nhé!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S linux-headers
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S virtualbox
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="phần-mềm-dọn-dẹp-rác"&gt;Phần mềm dọn dẹp rác
&lt;/h2&gt;&lt;p&gt;Từ lâu BleachBit đã nổi danh sánh vai với Ccleaner trên Windows :). Để cài đặt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S bleachbit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="phần-mềm-quản-lý-download"&gt;Phần mềm quản lý download
&lt;/h2&gt;&lt;p&gt;Uget không bằng được Internet Download Manager (IDM) thần thánh trên Windows, nên dùng đỡ nhé, sẵn cài thêm
plugin &lt;code&gt;aria2&lt;/code&gt; luôn:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S uget aria2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Nếu có phần mềm gì hay mình sẽ cập nhật thêm cũng tại bài viết này luôn nhé! Hẹn gặp lại.&lt;/p&gt;</description></item><item><title>Tinh chỉnh Cinnamon trong Archlinux</title><link>https://miti99.com/post/2020/04/14/</link><pubDate>Tue, 14 Apr 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/04/14/</guid><description>&lt;p&gt;Nhìn sơ thì cũng thấy Cinnamon khi bạn cài đặt Linux Mint thì đẹp hơn nhiều so với cái mà bạn vừa cài đặt, ôi thôi, nó &amp;rsquo;
chuối ơi là chuối&amp;rsquo; luôn. Vì vậy chúng ta sẽ làm cho nó được như trong Mint nha !😀&lt;/p&gt;
&lt;h2 id="slick-greeter"&gt;Slick-greeter
&lt;/h2&gt;&lt;p&gt;Đây là greeter của LightDM trong Mint (mặc định khi cài Arch là GTK+ Greeter). Để cài đặt bạn chạy lệnh sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S lightdm-slick-greeter
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Và cài thêm cái này để tinh chỉnh bằng giao diện (GUI), không thì mình vẫn có thể &amp;lsquo;chơi&amp;rsquo; với mấy file .conf thôi :v&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S lightdm-settings
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sửa file /etc/lightdm/lightdm.conf như sau:
Ở dưới mục &lt;code&gt;[Seat:*]&lt;/code&gt; tìm dòng &lt;code&gt;greeter-session=example-gtk-gnome&lt;/code&gt;, uncomment và sửa
thành &lt;code&gt;greeter-session=lightdm-slick-greeter&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="themes-và-icons"&gt;Themes và icons
&lt;/h2&gt;&lt;p&gt;Ban đầu thì Cinnamon dùng Adwaita của Gnome, nhìn khá là thô sơ, giờ chúng ta cài thêm Theme và Icon của Mint vào:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S mint-themes mint-x-icons mint-y-icons
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sau đó vào Settings để đổi theme với icon trong mục Appearance -&amp;gt; Themes nhé!&lt;/p&gt;
&lt;h2 id="âm-thanh"&gt;Âm thanh
&lt;/h2&gt;&lt;p&gt;Ban đầu thì chưa có hiệu ứng âm thanh ánh sáng gì hết trơn ấy, mình thêm vào bằng các package như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S cinnamon-sound-effects mint-sounds
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Chỉnh lại trong Settings mục Hardware -&amp;gt; Sound tab Sounds để dùng nhé!
(Nếu không có tác dụng thì bạn thử restart lại cinnamon nha)&lt;/p&gt;
&lt;h2 id="phần-mềm-cần-thiết"&gt;Phần mềm cần thiết
&lt;/h2&gt;&lt;p&gt;Khi mới cài hầu như Cinnamon không có gì dùng hết :/, nên mình mới khuyên cài group gnome trước đã rồi hãy cài Cinnamon,
mấy cái cần thiết thì như là Screenshot, Terminal, Software:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S gnome-screenshot gnome-terminal gnome-software
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;, cơ mà cái gnome thì ‘tặng kèm’ kha khá phần mềm khác nữa :v, mà tiêu chí của Arch là ‘Keep It Simple’ nên nếu không
cài gnome thì cũng chẳng sao cả, cứ cài cái gì cần thiết thôi.&lt;/p&gt;
&lt;p&gt;Đó là điều hơi buồn của cinnamon trên Arch, bởi vì các DE khác thì thường có gói extra đi kèm: &lt;code&gt;deepin&lt;/code&gt;
có &lt;code&gt;deepin-extra&lt;/code&gt;, &lt;code&gt;gnome&lt;/code&gt; có &lt;code&gt;gnome-extra&lt;/code&gt;, &lt;code&gt;mate&lt;/code&gt; có &lt;code&gt;mate-extra&lt;/code&gt;,&amp;hellip; đến cả thằng em được mệnh danh là &amp;lsquo;gọn
nhẹ&amp;rsquo; &lt;code&gt;xfce4&lt;/code&gt; mà cũng có &lt;code&gt;xfce4-goodies&lt;/code&gt; nữa.;còn &lt;code&gt;cinnamon&lt;/code&gt; thì chưa. Nhưng mà nếu cần combo của Cinnamon ư? Thì mình
nghĩ cài nhiêu đây là cơ bản rồi:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S xed xviewer xreader xplayer pix blueberry
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="nemo-fileroller"&gt;Nemo-fileroller
&lt;/h2&gt;&lt;p&gt;Đây là package giúp cho bạn có tùy chọn “extract here” trong nemo. Để cài đặt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yay -S nemo-fileroller
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sau đó restart nemo: &lt;code&gt;nemo -q&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Đây chỉ là cài cho giống Mint thôi, còn để làm Arch Cinnamon độc đáo hơn nữa, màu mè hơn nữa thì mình dành cho bài khác
nha. Tạm biệt các bạn, hẹn gặp lại.&lt;/p&gt;</description></item><item><title>Cài đặt package trong AUR cho Archlinux</title><link>https://miti99.com/post/2020/04/13/</link><pubDate>Mon, 13 Apr 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/04/13/</guid><description>&lt;p&gt;Arch User Repository (AUR) là nơi để người dùng nào cũng có thể tạo các package cho riêng mình và chia sẻ với những
người khác cùng sử dụng; một lí do khiến cho Arch trở nên rất tiện lợi với người dùng, một trong những lí do để họ chọn
Arch là distro để dùng.&lt;/p&gt;
&lt;p&gt;Có thể nói hầu hết các gói bạn có thể tìm ở các distro khác đều có thể có ở Official Repositories hoặc trong AUR. Và
những package &amp;ldquo;được biết đến&amp;rdquo; cũng sẽ có bản trong AUR. VD như &lt;code&gt;ibus-bamboo&lt;/code&gt; - bộ gõ yêu thích của mình cũng có trong
đây.&lt;/p&gt;
&lt;p&gt;Hơn nữa, với những phần mềm open source hay cung cấp source code cho người dùng tự build (như trên GitHub chẳng hạn),
thì việc cài đặt từ AUR dễ dàng hơn nhiều, và cũng dễ quản lý hơn nữa.&lt;/p&gt;
&lt;p&gt;Ở thời điểm mình viết bài này, mặc dù trong Official repositories có 11278 (một con số cũng rất ấn tượng rồi), nhưng
trong AUR có đến tận 59729 packages, một con số rất &amp;lsquo;khủng&amp;rsquo; phải không :D&lt;/p&gt;
&lt;p&gt;Và điểm mạnh trên cũng chính là điểm yếu của nó, vì ai cũng có thể thêm package vào đó, nên vẫn hay bị &amp;ldquo;mang tiếng&amp;rdquo; là
dễ bị tác giả &amp;ldquo;tặng kèm&amp;rdquo; vài con virus hay malware,&amp;hellip; vào máy :v. Vì vậy các bạn nên cẩn thận, lựa chọn package có
nguồn đáng tin cậy để cài đặt thôi nhé, chẳng hạn như package được đề cập trong Arch Wiki, từ trang chủ của gói đó, vd
như ibus-bamboo có ghi rõ gói AUR dành cho Arch và các distro base-on Arch; hoặc các package có votes cao, popularity
nhiều,&amp;hellip;&lt;/p&gt;
&lt;h2 id="hướng-dẫn-cài-đặt-package-từ-aur-yay"&gt;Hướng dẫn cài đặt package từ AUR (yay)
&lt;/h2&gt;&lt;p&gt;Ở đây mình sẽ hướng dẫn cài yay (một AUR helper khá nổi), vì hướng dẫn cơ bản nên các bước config build,&amp;hellip; mình sẽ bỏ
qua, chỉ hướng dẫn 3 bước chính&lt;/p&gt;
&lt;p&gt;Trước tiên thì bạn nên cài đặt gói base-devel trước, đây là gói chứa nhiều công cụ dùng để build package:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo pacman -S base-devel
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sau đó clone package từ link của AUR về, ở đây mình ví dụ là yay (&lt;a class="link" href="https://aur.archlinux.org/packages/yay/%29:" target="_blank" rel="noopener"
&gt;https://aur.archlinux.org/packages/yay/):&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://aur.archlinux.org/yay.git&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; yay
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;makepkg -si
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Vậy là xong rồi đó :D, quá đơn giản phải không nào, package này sẽ có thể dễ dàng quản lý được bằng pacman như một
package thông thường, tuy nhiên pacman sẽ không thể cập nhật những package trong AUR được, nếu muốn bạn phải theo dõi và
cập nhật bằng tay bằng cách làm lại các bước trên. Để khắc phục sự bất tiện này, chúng ta cần sự trợ giúp từ các AUR
helpers, và ở đây mình sẽ dùng yay.&lt;/p&gt;
&lt;h2 id="yay-yet-another-yogurt"&gt;yay (Yet another Yogurt)
&lt;/h2&gt;&lt;p&gt;Như đã nói ở trên, việc cài đặt package từ AUR có thể nói là rất đơn giản, qua 3 bước chính; tuy nhiên lại không tự cập
nhật,&amp;hellip; được. Vì vậy mình giới thiệu đến các bạn yay, với yay, việc cài đặt package từ AUR chỉ cần 1 lệnh y chang
pacman thôi :v (vì yay là một trong những Pacman wrappers mà :D), và quá trình cài chỉ khác một chút là có thêm bước
build package nên lâu hơn thông thường mà thôi. Hơn nữa yay là &amp;rsquo;tinh hoa tổng hợp&amp;rsquo; từ yaourt, apacman và pacaur (những
cái tên khá là &amp;lsquo;cộm cán&amp;rsquo; nếu bạn biết đến chúng :v, dù yaourt đã bị &amp;lsquo;chết&amp;rsquo;, bởi vậy yay mới là sự thay thế cho nó).&lt;/p&gt;
&lt;p&gt;Không dài dòng nữa, bên trên đã là cách cài đặt yay rồi nên mình không giới thiệu nữa :v&lt;/p&gt;
&lt;p&gt;Và cách sử dụng&amp;hellip; Hmm, vì yay có cú pháp giống pacman nên cũng khỏi giới thiệu luôn :v, muốn cài package X
cứ &lt;code&gt;yay -S X&lt;/code&gt; thôi :v, và các tùy chọn sau thì bạn cứ xem thử nó báo gì rồi chọn, nếu lười thì cứ Enter mãi thôi, 9/10
là bạn sẽ cài được package :v&lt;/p&gt;
&lt;p&gt;À, tip nhỏ, đó là để cập nhật hệ thống bạn chỉ cần dùng lệnh &lt;code&gt;yay&lt;/code&gt; thôi (nó sẽ thay cho &lt;code&gt;yay -Syyu&lt;/code&gt;, giống
với &lt;code&gt;sudo pacman -Syyu&lt;/code&gt; luôn đó :v), vì vậy không cần phức tạp, cứ &lt;code&gt;yay&lt;/code&gt; thôi :D&lt;/p&gt;</description></item><item><title>'Hậu cài đặt' Archlinux</title><link>https://miti99.com/post/2020/04/08/</link><pubDate>Wed, 08 Apr 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/04/08/</guid><description>&lt;p&gt;Tiếp theo bài cài đặt Arch Linux thì đây là những điều theo mình là nên làm trước khi reboot để dùng.&lt;/p&gt;
&lt;h2 id="cài-đặt-giao-diện-cho-arch-linux"&gt;Cài đặt giao diện cho Arch Linux
&lt;/h2&gt;&lt;p&gt;Sau khi hoàn tất các bước ở bài cài đặt, thì bạn đã có thể sử dụng Arch Linux rồi, tuy nhiên đó chỉ là giao diện console
thôi, để cài đặt môi trường Desktop thì bạn làm như sau: (lúc này vẫn còn ở trong chế độ của &lt;code&gt;arch-chroot&lt;/code&gt; nha các bạn)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pacman -S xorg-server
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pacman -S cinnamon
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Ở đây mình dùng desktop environment (DE) là cinnamon; sau này các bài hướng dẫn mình cũng hướng dẫn cho cinnamon thôi.
Arch hỗ trợ rất nhiều DE khác nhau được liệt kê ở &lt;a class="link" href="https://wiki.archlinux.org/index.php/Desktop_environment," target="_blank" rel="noopener"
&gt;https://wiki.archlinux.org/index.php/Desktop_environment,&lt;/a&gt; các bạn có
thể chọn một DE khác thích hợp như Gnome, KDE,&amp;hellip; Đặc biệt Arch có hỗ trợ i3, một DE có thể nói là &amp;lsquo;dành cho lập trình
viên&amp;rsquo; rất &amp;lsquo;cool&amp;rsquo;, nhưng mình không pro như thế nên chưa dùng được :v Vì cinnamon cũng dựa trên gtk nên các bạn có thể
cài đặt gnome để có những phần mềm bổ sung thêm khác&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pacman -S lightdm lightdm-gtk-greeter
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Mình dùng LightDM làm display manager, nếu bạn dùng gnome thì mặc định đã có gdm được cài rồi&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; lightdm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Để service của LightDM khởi động cùng hệ thống, nếu dùng DM khác thì bạn thay tên vào đó&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; NetworkManger
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;(đây là service quản lý mạng (chủ yếu là để kết nối wifi dễ dàng hơn))&lt;/p&gt;
&lt;h2 id="thêm-người-dùng-vào-hệ-thống"&gt;Thêm người dùng vào hệ thống
&lt;/h2&gt;&lt;p&gt;Mặc định bạn mới có user root trong hệ thống thôi, để dùng thì mình nên tạo một user khác để đăng nhập vào:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;useradd -m -G wheel -s /bin/bash tien
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;(-m để hệ thống tạo một thư mục home cho bạn, vd ở đây là /home/tien; -G wheel để thêm bạn vào group wheel, group này
dùng để cấp quyền sudo cho bạn sau này; -s /bin/bash, shell của bạn, ở đây mình dùng bash, sau này mình viết bài giới
thiệu cho các bạn về zsh, một shell dễ tùy chỉnh hơn; tien là tên người dùng bạn muốn tạo, mình tên Tiến thì tạo tên
tien thôi :v)&lt;/p&gt;
&lt;h3 id="cấp-quyền-sudo"&gt;Cấp quyền sudo
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pacman -S sudo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;(tất nhiên phải có sudo mới cấp quyền chứ :v)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pacman -S neovim
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;(editor mình sẽ dùng để edit, bạn có thể cài vim, vi hay nano,&amp;hellip; tùy bạn, mình thích dùng neovim nên cài thôi :))
&lt;code&gt;EDITOR=nvim visudo&lt;/code&gt; (mặc định visudo dùng vi nên để dùng neovim mình phải cấu hình lại EDITOR)&lt;/p&gt;
&lt;p&gt;Bỏ comment ở dòng &lt;code&gt;wheel ALL=(ALL) ALL&lt;/code&gt;, vậy là được, lưu lại và thoát thôi :D&lt;/p&gt;
&lt;h2 id="cài-đặt-một-terminal"&gt;Cài đặt một terminal
&lt;/h2&gt;&lt;p&gt;Nếu bạn chỉ cài cinnamon thì ban đầu bạn sẽ chưa có terminal nào, nếu muốn dùng lệnh thì sẽ phải vào TTY khác (Ctrl +
Alt + Fx(x từ 2 đến 6 ấy). Ở đây mình cài Terminator nhé:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pacman -S terminator
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Vậy là bạn đã có một hệ thống &amp;lsquo;có thể dùng được&amp;rsquo; rồi đấy, sau này mình sẽ có các bài làm đẹp Arch, tinh chỉnh Arch,..
nữa. Hẹn gặp lại!!&lt;/p&gt;</description></item><item><title>Cài đặt Archlinux trong chế độ boot UEFI</title><link>https://miti99.com/post/2020/04/07/</link><pubDate>Tue, 07 Apr 2020 00:00:00 +0700</pubDate><guid>https://miti99.com/post/2020/04/07/</guid><description>&lt;h2 id="giới-thiệu"&gt;Giới thiệu
&lt;/h2&gt;&lt;p&gt;Trước khi bắt đầu, thì mình cũng xin nói trước là mình biết nếu bạn là &amp;ldquo;dân chơi&amp;rdquo; dám thử cài Arch Linux thì hẳn bạn
không phải &amp;ldquo;tay mơ&amp;rdquo; rồi, và bạn có thể tự cài mà không cần hướng dẫn của mình. Bài viết của mình chủ yếu mang mục đích
là chia sẻ kinh nghiệm cài Arch của mình thôi, chứ không mang tính hướng dẫn hay giúp đỡ gỡ rối gì. Nếu bạn gặp khó
khăn, hãy comment bên dưới bài viết, mình sẽ xem và hỗ trợ bạn nếu có thể. Còn nếu bạn là người mới hoặc có ý định bước
vào thế giới Linux, mình khuyên bạn nên thử dùng các phiên bản dành cho người mới trước
như &lt;a class="link" href="https://ubuntu.com/" target="_blank" rel="noopener"
&gt;Ubuntu&lt;/a&gt; hay nếu bạn nguốn trải nghiệm sơ bộ Arch thì &lt;a class="link" href="https://manjaro.org/" target="_blank" rel="noopener"
&gt;Manjaro&lt;/a&gt; cũng là
một lựa chọn không tồi (base on Arch và đứng top bảng xếp hạng nhiều lần mà) trước khi bắt đầu thử Arch. Sau đây là các
bước tiến hành:&lt;/p&gt;
&lt;h2 id="tạo-bộ-cài"&gt;Tạo bộ cài
&lt;/h2&gt;&lt;p&gt;Ở đây mình hướng dẫn tạo bộ cài qua USB, nếu bạn dùng đĩa thì có thể tự tìm hiểu và làm.&lt;/p&gt;
&lt;p&gt;Đầu tiên các bạn tải file cài đặt mới nhất tại trang chủ của Arch Linux: &lt;a class="link" href="https://www.archlinux.org/download/" target="_blank" rel="noopener"
&gt;https://www.archlinux.org/download/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nếu bạn dùng Windows thì sử dụng Rufus để tạo bộ cài (các bạn chọn chế độ boot BIOS mặc định là được, bộ cài sẽ nhận cả
2 chuẩn BIOS lẫn UEFI luôn, còn nếu chọn UEFI thôi thì có khi lại không được :v). Nếu bạn dùng Linux thì có thể dùng
lệnh: &lt;code&gt;dd if=&amp;lt;đường dẫn đến file .iso&amp;gt; of=/dev/sdX bs=1MB&lt;/code&gt; (với sdX là ổ USB) hoặc dùng GUI tools như
Disks (&lt;code&gt;gnome-disks&lt;/code&gt;) -&amp;gt; Restore Disk Image&amp;hellip;&lt;/p&gt;
&lt;h2 id="thiết-lập-mạng"&gt;Thiết lập mạng
&lt;/h2&gt;&lt;p&gt;Sau khi boot vào Live boot, bạn khởi động các service sau: &lt;code&gt;systemctl start dhcpcd&lt;/code&gt;. Nếu bạn dùng mạng dây thì như vậy
là được, nhưng nếu bạn dùng wifi như laptop chẳng hạn, thì chạy thêm các lệnh sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl start iwd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;iwctl
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;device list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Lúc này sẽ hiện ra tên các thiết bị wifi của bạn, giả sử là &lt;code&gt;wlan0&lt;/code&gt;, nếu không phải thì thay &lt;code&gt;wlan0&lt;/code&gt; ở các lệnh sau bằng
tên thích hợp của máy bạn:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;station wlan0 scan
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;station wlan0 get-networks
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Lúc này sẽ hiện ra tên các điểm truy cập wifi, giả sử như là &lt;code&gt;SSID&lt;/code&gt;, kết nối bằng lệnh sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;station wlan0 connect SSID
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Lúc này sẽ yêu cầu bạn nhập mật khẩu wifi (nếu có). Sau đó bạn có thể tiếp tục các bước tiếp theo:
Thử kết nối với internet bằng lệnh: &lt;code&gt;ping google.com -c2&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="cập-nhật-ngày-giờ-hệ-thống"&gt;Cập nhật ngày giờ hệ thống
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;timedatectl set-ntp true&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="phân-vùng-ổ-đĩa"&gt;Phân vùng ổ đĩa
&lt;/h2&gt;&lt;p&gt;Ở đây mình dùng lệnh &lt;code&gt;fdisk&lt;/code&gt;, bạn có thể dùng lệnh khác.&lt;br&gt;
&lt;strong&gt;Lưu ý:&lt;/strong&gt; Arch Linux khuyến khích phân vùng EFI từ 260-512MiB; phân vùng SWAP từ 512MiB. SWAP là cần thiết, tuy nhiên
sau khi cài mình sẽ dùng swap file nên không tạo phân vùng này.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fdisk -l
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fdisk /dev/sda&amp;lt;/code
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;(Bạn gõ &lt;code&gt;m&lt;/code&gt; sau đó xem trong hướng dẫn thêm nhé!)&lt;/p&gt;
&lt;h3 id="định-dạng-các-phân-vùng"&gt;Định dạng các phân vùng
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkfs.fat -F32 /dev/sda1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkfs.ext4 /dev/sda2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="mount-các-phân-vùng"&gt;Mount các phân vùng
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Lưu ý:&lt;/strong&gt; Arch Linux khuyến khích mount phân vùng EFI vào mount point &lt;code&gt;/efi&lt;/code&gt; thay vì &lt;code&gt;/boot/efi&lt;/code&gt; như nhiều hệ điều hành
khác hiện tại (chẳng hạn Ubuntu).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mount /dev/sda2 /mnt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir /mnt/efi
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mount /dev/sda1 /mnt/efi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="tiến-hành-cài-đặt"&gt;Tiến hành cài đặt
&lt;/h2&gt;&lt;p&gt;Hihi, sau nhiều bước &amp;ldquo;khởi động&amp;rdquo; thì cuối cùng cũng đến bước tiến hành cài đặt.&lt;/p&gt;
&lt;p&gt;Đầu tiên chúng ta nên thiết lập mirror servers để có tốc độ mạng hiệu quả. Vì chúng ta ở Việt Nam nên dùng mirror của
archlinuxvn là hiệu quả. Thực hiện các lệnh sau: &lt;code&gt;nano /etc/pacman.d/mirrorlist&lt;/code&gt;. Thêm dòng sau vào trước dòng đầu
tiên: &lt;code&gt;Server = http://f.archlinuxvn.org/archlinux/$repo/os/$arch&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Sau đó lưu (&lt;em&gt;Ctrl+O&lt;/em&gt;, &lt;em&gt;Enter&lt;/em&gt;) và thoát (&lt;em&gt;Ctrl+X&lt;/em&gt;)&lt;/p&gt;
&lt;p&gt;Cài các gói cần thiết bằng lệnh sau: &lt;code&gt;pacstrap /mnt base linux linux-firmware&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="thiết-lập-hệ-thống"&gt;Thiết lập hệ thống
&lt;/h2&gt;&lt;p&gt;Sau đây là các tinh chỉnh để hệ thống hoạt động.&lt;/p&gt;
&lt;h3 id="tạo-file-fstab"&gt;Tạo file fstab
&lt;/h3&gt;&lt;p&gt;Để mount các phân vùng khi khởi động: &lt;code&gt;genfstab -U /mnt &amp;gt;&amp;gt; /mnt/etc/fstab&lt;/code&gt; (có thể thay &lt;code&gt;-U&lt;/code&gt; bằng &lt;code&gt;-L&lt;/code&gt;, nghĩa là thay vì
định nghĩa bằng UUID thì định nghĩa bằng label của phân vùng)&lt;/p&gt;
&lt;h4 id="change-root-vào-hệ-thống-mới"&gt;Change root vào hệ thống mới
&lt;/h4&gt;&lt;p&gt;&lt;code&gt;arch-chroot /mnt&lt;/code&gt;&lt;/p&gt;
&lt;h4 id="thiết-lập-time-zone"&gt;Thiết lập time zone
&lt;/h4&gt;&lt;p&gt;Chúng ta ở Việt Nam sẽ chọn thành phố Hồ Chí Minh: &lt;code&gt;ln -sf /usr/share/zoneinfo/Asia/Ho_Chi_Minh /etc/localtime&lt;/code&gt;. Đồng bộ
giờ: &lt;code&gt;hwclock --systohc&lt;/code&gt;&lt;/p&gt;
&lt;h4 id="định-dạng-vùng"&gt;Định dạng vùng
&lt;/h4&gt;&lt;p&gt;Đầu tiên nên cài đặt vim để có thể chỉnh sửa file văn bản: &lt;code&gt;pacman -S vim&lt;/code&gt;. Sau đó sửa file sau: &lt;code&gt;vim /etc/locale.gen&lt;/code&gt;
Uncomment dòng &lt;em&gt;en_us.UTF-8 UTF-8&lt;/em&gt; (và dòng &lt;em&gt;vi_VN UTF-8&lt;/em&gt; nếu thích :v) (bạn nhấn phím &lt;em&gt;i&lt;/em&gt; để vào chế độ insert mới sửa
được), lưu lại và thoát (&lt;em&gt;Esc&lt;/em&gt;, sau đó gõ &lt;code&gt;:wq&lt;/code&gt; sau đó chạy lệnh: &lt;code&gt;locale-gen&lt;/code&gt;. Tiếp tục sửa một file
khác: &lt;code&gt;vim /etc/locale.conf&lt;/code&gt;. Thêm vào đây dòng sau &lt;em&gt;LANG=en_US.UTF-8&lt;/em&gt;&lt;/p&gt;
&lt;h4 id="thiết-lập-tên-máy-tính-trong-mạng"&gt;Thiết lập tên máy tính trong mạng
&lt;/h4&gt;&lt;p&gt;Sửa file &lt;code&gt;/etc/hostname&lt;/code&gt;, &lt;em&gt;myhostname&lt;/em&gt; vào đó (với &lt;em&gt;myhostname&lt;/em&gt; là tên bạn muốn đặt cho máy tính của bạn). Tương tự, sửa
file &lt;code&gt;/etc/hosts&lt;/code&gt; với các thông số như sau:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1 localhost
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;::1 localhost
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.1.1 myhostname.localdomain myhostname
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="khởi-tạo-initramfs"&gt;Khởi tạo Initramfs
&lt;/h4&gt;&lt;p&gt;(thông thường bước này không cần thiết)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mkinitcpio -P&lt;/code&gt;&lt;/p&gt;
&lt;h4 id="đặt-mật-khẩu-cho-root"&gt;Đặt mật khẩu cho root
&lt;/h4&gt;&lt;p&gt;Gõ: &lt;code&gt;passwd&lt;/code&gt;. Sau đó điền mật khẩu 2 lần.&lt;/p&gt;
&lt;h4 id="cài-đặt-microcode-tùy-chọn"&gt;Cài đặt microcode (tùy chọn)
&lt;/h4&gt;&lt;p&gt;Tùy vào bạn sử dụng CPU Intel hay AMD mà cài gói cho phù hợp. &lt;code&gt;pacman -S amd-ucode&lt;/code&gt; (nếu bạn dùng AMD)
hoặc &lt;code&gt;pacman -S intel-ucode&lt;/code&gt; (nếu bạn dùng Intel)&lt;/p&gt;
&lt;h4 id="cài-đặt-boot-loader"&gt;Cài đặt boot loader
&lt;/h4&gt;&lt;p&gt;Ở đây mình dùng &lt;code&gt;grub&lt;/code&gt; (khá phổ biến, nhiều tùy chọn, tùy chỉnh), và gói &lt;code&gt;efibootmgr&lt;/code&gt; (mình đang cài trong chế độ UEFI
mà :D):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pacman -S grub efibootmgr
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grub-install --target&lt;span class="o"&gt;=&lt;/span&gt;x86_64-efi --efi-directory&lt;span class="o"&gt;=&lt;/span&gt;/efi --bootloader-id&lt;span class="o"&gt;=&lt;/span&gt;Archlinux
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Nếu bạn mount phân vùng EFI giống mình thì làm như trên, không thì đổi &lt;code&gt;/efi&lt;/code&gt; thành mount point EFI của bạn. &amp;ldquo;Archlinux&amp;rdquo;
trong lệnh trên có thể đổi thành cái khác nếu bạn thích, nó sẽ hiển thị trong Boot Options trong BIOS của bạn (nếu bạn
không lock Boot Order, máy ThinkPad của mình có chức năng này).&lt;/p&gt;
&lt;p&gt;Cập nhật GRUB: &lt;code&gt;grub-mkconfig -o /boot/grub/grub.cfg&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Vậy là bạn đã hoàn thành cài Arch Linux lên máy rồi đấy, giờ thì có thể reboot ngay để trải nghiệm thôi:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;umount -R /mnt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;reboot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Tuy nhiên mình khuyên bạn nên làm theo các bước &amp;ldquo;hậu cài đặt&amp;rdquo; trước khi reboot để có trải nghiệm tốt nhất, vì bạn chỉ
mới có các gói cơ bản trên máy thôi, nên chưa thể dùng như Desktop được đâu. Mình sẽ viết bài cho điều này sớm nhất. Hẹn
gặp lại các bạn.&lt;/p&gt;
&lt;p&gt;Tham khảo tại nguồn: &lt;a class="link" href="https://wiki.archlinux.org/index.php/Installation_guide" target="_blank" rel="noopener"
&gt;https://wiki.archlinux.org/index.php/Installation_guide&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Chúc các bạn thành công! Nếu có gặp khó khăn gì, bạn có thể comment bên dưới, mình sẽ cố gắng giúp đỡ.&lt;/p&gt;</description></item><item><title>About</title><link>https://miti99.com/about/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://miti99.com/about/</guid><description>&lt;p&gt;Xin chào, mừng bạn đã đến với blog của mình.&lt;/p&gt;
&lt;p&gt;Mình tên Minh Tiến, sinh năm 1999 (vì vậy blog là miti99 :)))), sinh viên ngành Khoa học Máy tính khóa 2017 tại trường Đại học Bách Khoa Tp.HCM. Hiện mình đang làm việc tại VNG.&lt;/p&gt;
&lt;p&gt;Mình là một người thích Linux (đặc biệt là Archlinux) và các dự án mã nguồn mở. Công việc hiện tại của mình liên quan đến game nên mình không dùng Linux cho desktop nữa. Tuy nhiên vẫn thường vọc vạch trên máy ảo và cloud.&lt;/p&gt;
&lt;p&gt;Blog này được tạo ra với mục đích chia sẻ trải nghiệm của mình, cũng như cách giải quyết một số vấn đề liên quan đến tech mà mình gặp phải trong công việc và các dự án cá nhân.&lt;/p&gt;
&lt;p&gt;Các liên kết hữu ích có tại &lt;a class="link" href="https://miti99.com/" &gt;trang chủ&lt;/a&gt; của mình.&lt;/p&gt;
&lt;p&gt;Các bạn có thể liên hệ với mình bằng một trong những cách thức sau:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="mailto:minhtienit99@gmail.com" &gt;Gmail&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="mailto:tiennm99@outlook.com" &gt;Outlook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://linkedin.com/in/miti99" target="_blank" rel="noopener"
&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://fb.com/tiennm99" target="_blank" rel="noopener"
&gt;Facebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://fb.com/miti99" target="_blank" rel="noopener"
&gt;Fanpage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hi vọng bạn sẽ thích blog của mình.&lt;/p&gt;</description></item><item><title>Archives</title><link>https://miti99.com/archives/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://miti99.com/archives/</guid><description/></item><item><title>Links</title><link>https://miti99.com/links/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://miti99.com/links/</guid><description/></item><item><title>Pages</title><link>https://miti99.com/pages/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://miti99.com/pages/</guid><description>&lt;p&gt;Danh sách những trang mình host trên &lt;a class="link" href="https://pages.github.com/" target="_blank" rel="noopener"
&gt;GitHub Pages&lt;/a&gt;. Thường khá thú vị :&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Danh sách này được tạo tự động, thứ tự không quan trọng nhé)&lt;/em&gt;&lt;/p&gt;
&lt;div id="github-pages"&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Pages URL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody id="repos"&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;script&gt;
const username = "tiennm99";
const type = "all";
const sort = "updated";
const perPage = 100;
let page = 1;
function fetchRepos(page) {
const url = `https://api.github.com/users/${username}/repos?type=${type}&amp;sort=${sort}&amp;per_page=${perPage}&amp;page=${page}`;
fetch(url)
.then(response =&gt; {
if (!response.ok) {
throw new Error("HTTP error " + response.status);
}
return response.json();
})
.then(data =&gt; {
if (data.length === 0) {
return;
}
const table = document.getElementById("repos");
data.forEach(repo =&gt; {
if (repo.has_pages) {
const row = table.insertRow(-1);
const nameCell = row.insertCell(0);
const descriptionCell = row.insertCell(1);
const urlCell = row.insertCell(2);
const repoUrl = repo.html_url;
let pagesUrl;
if (repo.homepage !== null) {
pagesUrl = repo.homepage;
} else {
pagesUrl = `https://${username}.github.io/${repo.name}`
console.warn(`${repo.name}'s homepage is null. Using ${pagesUrl} instead.`)
}
nameCell.innerHTML = `&lt;a href="${repoUrl}" target="_blank"&gt;${repo.name}&lt;/a&gt;`;
descriptionCell.textContent = repo.description;
urlCell.innerHTML = `&lt;a href="${pagesUrl}" target="_blank"&gt;${pagesUrl}&lt;/a&gt;`;
}
});
fetchRepos(page + 1);
})
.catch(error =&gt; console.error("Error:", error));
}
fetchRepos(page);
&lt;/script&gt;</description></item><item><title>Referral</title><link>https://miti99.com/referral/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://miti99.com/referral/</guid><description>&lt;h2 id="claude-code-guest-pass"&gt;&lt;a class="link" href="https://claude.ai/referral/ZkoAngod1A" target="_blank" rel="noopener"
&gt;Claude Code Guest Pass&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Share a free week of Claude Code with friends. If they love it and subscribe, you&amp;rsquo;ll get $10 of extra usage to keep building.&lt;/p&gt;
&lt;p&gt;Link: &lt;a class="link" href="https://claude.ai/referral/ZkoAngod1A" target="_blank" rel="noopener"
&gt;https://claude.ai/referral/ZkoAngod1A&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="claudekit"&gt;&lt;a class="link" href="https://claudekit.cc/?ref=BWA910UK" target="_blank" rel="noopener"
&gt;ClaudeKit&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;ClaudeKit is a platform providing tools and resources to work with Claude AI more effectively — including prompt templates, workflows, and extensions.&lt;/p&gt;
&lt;p&gt;Sign up via the referral link to get &lt;strong&gt;20% off&lt;/strong&gt; your first purchase!&lt;/p&gt;
&lt;p&gt;Referral code: &lt;code&gt;BWA910UK&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Link: &lt;a class="link" href="https://claudekit.cc/?ref=BWA910UK" target="_blank" rel="noopener"
&gt;https://claudekit.cc/?ref=BWA910UK&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="zai"&gt;&lt;a class="link" href="https://z.ai/subscribe?ic=PLKIAYEIPW" target="_blank" rel="noopener"
&gt;Z.ai&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;🚀 You&amp;rsquo;ve been invited to join the GLM Coding Plan! Enjoy full support for Claude Code, Cline, and 20+ top coding tools — starting at just $10/month. Subscribe now and grab the limited-time deal! Link： &lt;a class="link" href="https://z.ai/subscribe?ic=PLKIAYEIPW" target="_blank" rel="noopener"
&gt;https://z.ai/subscribe?ic=PLKIAYEIPW&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="bigmodelcn"&gt;&lt;a class="link" href="https://www.bigmodel.cn/invite?icode=rIX6uZrLYfy8fQ6Urca4xf2gad6AKpjZefIo3dVEQyA%3D" target="_blank" rel="noopener"
&gt;BigModel.cn&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Join BigModel.cn via my link for 20M tokens! Explore AGI apps with me. Link: &lt;a class="link" href="https://www.bigmodel.cn/invite?icode=rIX6uZrLYfy8fQ6Urca4xf2gad6AKpjZefIo3dVEQyA%3D" target="_blank" rel="noopener"
&gt;https://www.bigmodel.cn/invite?icode=rIX6uZrLYfy8fQ6Urca4xf2gad6AKpjZefIo3dVEQyA%3D&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="synthetic"&gt;&lt;a class="link" href="https://synthetic.new/?referral=CNBFyw28zF0dZoj" target="_blank" rel="noopener"
&gt;Synthetic&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;Thanks for helping us grow!&lt;/p&gt;
&lt;p&gt;Invite your friends to Synthetic and both of you will receive $10.00 in subscription credit when they subscribe!&lt;/p&gt;
&lt;p&gt;Share Your Referral Link&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://synthetic.new/?referral=CNBFyw28zF0dZoj" target="_blank" rel="noopener"
&gt;https://synthetic.new/?referral=CNBFyw28zF0dZoj&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Your referral link contains your unique code: CNBFyw28zF0dZoj&lt;/p&gt;
&lt;h2 id="modelark"&gt;&lt;a class="link" href="https://www.byteplus.com/activity/codingplan?ac=MMAUCIS9NT1S&amp;amp;rc=2739UWRE" target="_blank" rel="noopener"
&gt;ModelArk&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://www.byteplus.com/activity/codingplan?ac=MMAUCIS9NT1S&amp;amp;rc=2739UWRE" target="_blank" rel="noopener"
&gt;https://www.byteplus.com/activity/codingplan?ac=MMAUCIS9NT1S&amp;rc=2739UWRE&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://miti99.com/referral/modelark.png"
width="720"
height="960"
srcset="https://miti99.com/referral/modelark_hu_f91770a61ff6004a.png 480w, https://miti99.com/referral/modelark_hu_43bf7db318f94f70.png 1024w"
loading="lazy"
alt="modelark"
class="gallery-image"
data-flex-grow="75"
data-flex-basis="180px"
&gt;&lt;/p&gt;</description></item><item><title>Search</title><link>https://miti99.com/search/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://miti99.com/search/</guid><description/></item></channel></rss>