<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Shaun Nguyen's blog]]></title><description><![CDATA[Blog của Sơn (Shaun), gồm mẹo tìm được trong quá trình học code, và Linux. Chủ blog vừa yêu vừa hận Python và Typescript.]]></description><link>https://truongson.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/64666ef20a99831c63466a63/0087342d-c0dd-443f-8e59-afdd19514a8d.png</url><title>Shaun Nguyen&apos;s blog</title><link>https://truongson.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 11 Jun 2026 19:09:23 GMT</lastBuildDate><atom:link href="https://truongson.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Chasing the shiny toys]]></title><description><![CDATA[I'm actually a person who like living on-the-edge. Anything that looks new, like Svelte, Turso, PocketBase, Bun or something shiny that people will hype about it on X for like, 3 months, I will give i]]></description><link>https://truongson.dev/chasing-the-shiny-toys</link><guid isPermaLink="true">https://truongson.dev/chasing-the-shiny-toys</guid><dc:creator><![CDATA[Shaun Nguyen]]></dc:creator><pubDate>Thu, 11 Jun 2026 12:04:23 GMT</pubDate><content:encoded><![CDATA[<p>I'm actually a person who like living on-the-edge. Anything that looks new, like Svelte, Turso, PocketBase, Bun or something shiny that people will hype about it on X for like, 3 months, I will give it a try IN PRODUCTION 🤡 Not actually, I mean my small project, but it just not toys, it actually something that I sell to people.</p>
<p>Yeah, it's like gambling. Why do not use industry-recommended option, like React, to make it works? I love the hype when people optimistic about new thing that (maybe?) change the industry forever. Like Svelte, people expect it to make the webdev simple and magic. But now? It just become React with reactivity idea just like React. And lack of library. Oh, c'mon, you can write it in plain JS, you say. But it is painful to make complex things. Simple things like to-do app in Youtube tutorials can be written in pure JS, but in more complex, production-ready app, write it in plain JS is suck. How you can make sure your implementation is secure enough?</p>
<p>With the rise of vibe-coding, I figured out: I must choose the common techstack, so LLM can do it just right. The obvious choice was NextJS, though the syntax is ugly. The whole Internet is full of NextJS tutorial, and LLM learns from them, which make it become superstar when come to React or NextJS-related.</p>
<p>But in the end of day, while fixing almost all of the code, the pain comes again. Why make everything so complex, while I can just put them on Wordpress and it do the hard works? All the toy is trying to solve specific problems</p>
<p>Seem like it's me problem more. Any toys will not work without fundamental knowledge. Instead of chasing edge, maybe I should enrich my JS knowledge.</p>
]]></content:encoded></item><item><title><![CDATA[Từ Windows, Linux sang MacOS]]></title><description><![CDATA[Hà Nội, một tối mưa buồn. Con mạc bục mình mới setup tắc tịt không kết nối được với máy in cơ quan, và mình bị ăn chửi. Má mình mua cái máy này để code nên mấy cái tình huống máy in này thực sự mình k]]></description><link>https://truongson.dev/t-windows-linux-sang-macos</link><guid isPermaLink="true">https://truongson.dev/t-windows-linux-sang-macos</guid><category><![CDATA[macOS]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Windows]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Shaun Nguyen]]></dc:creator><pubDate>Thu, 11 Jun 2026 11:45:36 GMT</pubDate><content:encoded><![CDATA[<p>Hà Nội, một tối mưa buồn. Con mạc bục mình mới setup tắc tịt không kết nối được với máy in cơ quan, và mình bị ăn chửi. Má mình mua cái máy này để code nên mấy cái tình huống máy in này thực sự mình không nắm được.</p>
<p>Sau đây sẽ tổng hợp 1 vài khó khăn của người từ thế giới khác sang Mac. Bài sau mình sẽ chia sẻ cách setup dev env trên Mac Pro 2019 nhé. Đây là Mac Intel, còn ai có Mac dòng M thì share cho mình trải nghiệm để viết bài với nhé.</p>
<p><em>Setup hiện tại:</em></p>
<ul>
<li>Macbook Pro 2019, i9-9980HK, 32GB RAM, Radeon Pro 5300M. Bản mình chọn móp 4 góc :)))</li>
<li>MacOS Sequoia 15.4.1</li>
<li>Dev Env: <ul>
<li>"Core": Docker, uv, Bun </li>
<li>IDE/Editor: Pycharm, WebStorm, Cursor</li>
<li>Terminal: Kitty + Starship.rs + IntoneMono Nerd Font</li>
</ul>
</li>
<li>Ultilties: Pock (customize TouchBar), Raycast (replace Spotlight)</li>
</ul>
<p>Rồi, bắt đầu thôi.</p>
<h2>Vậy rốt cục tại sao lại là Mac?</h2>
<p>Ban đầu mình chốt 1 con trạm Dell, mình tính cài Fedora lên đó; xong shop bảo hết rồi, dùng tạm Mac đi, ưng thì dùng tiếp còn khi nào có Precision thì anh đổi lại cho mày, chứ có mấy con ThinkPad mà nó sâu quá mày dùng không đủ. Mình trộm nghĩ, ờ, thôi cũng được, dù sao thì dùng mạc bục cho nhẹ cầm đi lại các thứ.</p>
<h2>Thế có gì ngon không?</h2>
<p>Có chứ, chắc chắn rồi. Mình không chơi game, nên mình đánh giá nó cao. UX tốt, nhìn gọn gàng, đẹp, nịnh mắt. Touchbar rất hay ho, tôi thích. Mặc dù date sâu (2019) nhưng phần mềm vẫn cho cảm giác ok. Vỏ nhôm, hoàn thiện tốt, mình nghĩ là cái máy chà vỏ nhà Táo làm khá tốt vì khi mình sờ thì cảm nhận rõ luôn mấy cái vân tay trên ngón á. Màn thì thôi không bàn nhé, quá đẹp, kiểu đang nhìn TV đen trắng lên TV màu. </p>
<p>Đặc biệt là, vẫn có cảm giác làm việc với lệnh giống ở Linux. Dễ hiểu thôi, 1 giuộc Unix-like, thì command line ultities cũng khá giống nhau. Cảm giác nó không dở hơi nửa mùa như WSL, mặc dù WSL bây giờ cũng rất ngon rồi :)) (nói chung mình bị thượng đẳng)</p>
<p>1 cái ngon nữa là giờ mình có thể cài mấy cái chuyên làm cho Mac và Win mà trước kia không có. Thật tuyệt vời, tôi đã có thể dùng Zalo. Ước gì tất cả mọi người trù dập Zalo và đưa Tele lên, làm ơn.</p>
<h2>Thế bị ngu cái gì</h2>
<p>Tưởng tượng đi, mọi hôm anh chị em ăn bún trộn sinh viên, cái gì cũng có đủ dù ăn nó hơi lôm côm. Đột nhiên 1 ngày lên đời ăn beefsteak, sẽ thấy miếng thịt ồ ngon quá nhưng mấy cái khác đâu rồi? Anh chị em quyết định trộn nước mắm với rau húng ăn cùng :)))</p>
<p>Thì dùng MacOS như vậy nhé, cái base của nó chán òm, đúng kiểu máy cho người low tech nhưng mà lại vô cùng rắc rối nếu muốn làm gì đó ngoài lướt web và làm văn phòng. Such a pain in the a**. Mình bị mất cảm giác tự do của Arch, không có đồ chùa đàng hoàng để xài. Xong phải cài những con app free nhưng không phải nguồn mở để chỉnh những cái setting rất hiển nhiên nhưng MacOS không có.</p>
<p>Tự "thuốc" đồ cũng khó chịu hơn 1 chút. Pháp sư trung hoa đã cố hết sức, nhưng để "thuốc" app Adobe thì phải đợi người ta thuốc cho trên MacLife chứ không tự làm được. Pháp sư Trung Hoa cũng không cứu được. Mà đến đoạn đó là mình cho cook chứ mình là antifan Fshare. Đợi có tiền thì bố thí cho.</p>
<h2>Có cái gì bỡ ngỡ</h2>
<p>Đầu tiên, máy nóng và sụt pin nhanh nhé (ý là so với trải nghiệm từng dùng Mac Air chip M :v Thật khập khiễng). Chip đuôi HK với màn kiểu này thì on-screen căng đét được khoảng 4 tiếng rưỡi thôi anh chị em chú ý nhé. Có thể bật tiết kiệm pin, nhưng dùng không sướng, làm văn phòng lướt web vớ vẩn thì ok. Nói chung là trạm mỏng nhẹ trá hình. Anh chị em dư dả thì mua luôn Pro M4 nhé, chạy LLM local rất oke. Còn con này để mình test trên model 7B trước xem sao.</p>
<p>Chuột ngược. Cái này quỷ lắm, mình phải đánh vật với nó để làm quen. Bàn phím thì layout cánh bướm, ai ngón tay dài sẽ lệch phím liên tục.</p>
<p>Mình nghĩ là, nhà táo tối ưu thao tác chuột, cho cái trackpad to đùng. Nên có thể nói là rất nhiều bỡ ngỡ. Rất nhiều phím tắt phải học lại từ đầu. Tốc độ thao tác của mình phải nói là giảm x3. Nút Meta (trên Windows thì nó chính là nút cửa sổ đó) sang Mac dùng không khác gì nút Ctrl. Ví dụ, Meta + C trên Mac = Control + C trên Windows và Linux. Ảo chưa?</p>
<p>Tiếp theo đó là phần thao tác cửa sổ.  Nó lạ lắm. Bình thường mình sẽ kỳ vọng bấm tắt thì nó tắt chứ. Không, nó ẩn đi thôi. Có vẻ người dùng Mac có thói quen ẩn nó đi xong gập máy chứ không tắt hẳn. Mình nhìn app vẫn bật là mình rất ngứa mắt.</p>
<p>Hơn nữa mình cũng kỳ vọng là khi mình kéo cửa sổ vào viền thì nó sẽ tự co hay gì đó cho mình. Không nha. Cái đó chỉ có ở phiên bản Sequoia thôi, lúc mình mua ở shop là cài sẵn Ventura, và kéo vào góc không hề có vụ này. Mọi người mua máy cũ chú ý vụ này nhé, phải nâng cấp OS.</p>
<p>Tiếp nữa là bộ gõ. Shop cài sẵn cho mình, và cái bộ gõ ôi chao nó ngu. Nó không tự đổi dấu cho mình, gõ sai cái ốm liền. Em nhớ Unikey 3.1 và iBus Bamboo lắm huhu...</p>
<p>Còn gì nữa nhỉ? À, không đăng nhập iCloud thì 1 nửa cái máy thành phế vật :)) Không sao, mình vẫn cài được Zalo và Tele thì mọi chuyện đều OK.</p>
<h2>Vậy thì có gì quen?</h2>
<p>Giống GNOME thật. Với lại, như mình vừa nói, làm việc trên command line vẫn rất quen thuộc với lệnh y chang. </p>
<p>Tạm thế đã, mỏi tay rồi. Bài này sẽ được liên tục update trong tuần này.</p>
]]></content:encoded></item><item><title><![CDATA[Setup NextJS debug on VSCode Windows + MS Edge]]></title><description><![CDATA[Damn, I got stucked when following NextJS recommendation, because it only work on UNIX-like system which have shell that can run .sh file. Totally bullshit.
This instruction prefer Bun, because it is ]]></description><link>https://truongson.dev/setup-nextjs-debug-on-vscode-windows-ms-edge</link><guid isPermaLink="true">https://truongson.dev/setup-nextjs-debug-on-vscode-windows-ms-edge</guid><category><![CDATA[Next.js]]></category><category><![CDATA[ vscode]]></category><category><![CDATA[debugging]]></category><category><![CDATA[Windows]]></category><category><![CDATA[msedge]]></category><dc:creator><![CDATA[Shaun Nguyen]]></dc:creator><pubDate>Thu, 11 Jun 2026 11:43:41 GMT</pubDate><content:encoded><![CDATA[<p>Damn, I got stucked when following <a href="https://nextjs.org/docs/pages/building-your-application/configuring/debugging#debugging-with-vs-code">NextJS recommendation</a>, because it only work on UNIX-like system which have shell that can run <code>.sh</code> file. Totally bullshit.</p>
<p>This instruction prefer Bun, because it is Typescript native and spin up dev quick. You can choose NPM or Yarn, or PNPM as your favorite package manager.</p>
<p>After some conversation with Claude, I figure it out by edit the <code>program</code> part of <code>Next.js: debug full stack</code> to direct <code>next</code> executable.</p>
<p>This is <code>.vscode/launch.json</code> code for lazy person:</p>
<pre><code class="language-json">{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Next.js: debug server-side",
      "type": "node-terminal",
      "request": "launch",
      "command": "bun dev"
    },
    {
      "name": "Next.js: debug client-side",
      "type": "msedge",
      "request": "launch",
      "url": "http://localhost:3000"
    },
    {
      "name": "Next.js: debug full stack",
      "type": "node",
      "request": "launch",
      "program": "${workspaceFolder}/node_modules/next/dist/bin/next",
      "args": [
        "dev"
      ],
      "runtimeArgs": [
        "--inspect"
      ],
      "skipFiles": [
        "&lt;node_internals&gt;/**"
      ],
      "serverReadyAction": {
        "action": "debugWithEdge",
        "killOnServerStop": true,
        "pattern": "- Local:\\s+(https?://\\S+)",
        "uriFormat": "%s",
        "webRoot": "${workspaceFolder}"
      },
      "env": {
        "NODE_OPTIONS": "--inspect"
      },
      "console": "internalConsole",
      // "outputCapture": "std"
    }
  ]
}
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Thực tập đần]]></title><description><![CDATA[Cái ngày Khoa Toán đăng tin tuyển thực tập sinh cho công ty giải pháp X, tớ cũng hồ hởi viết thư xin thực tập, và đính kèm một chiếc CV lịch sự theo mẫu Oxford, lại còn viết bằng tiếng Anh hẳn hoi. Oá]]></description><link>https://truongson.dev/thuc-tap-dan</link><guid isPermaLink="true">https://truongson.dev/thuc-tap-dan</guid><category><![CDATA[internships]]></category><category><![CDATA[interview]]></category><category><![CDATA[learning]]></category><dc:creator><![CDATA[Shaun Nguyen]]></dc:creator><pubDate>Thu, 11 Jun 2026 11:42:02 GMT</pubDate><content:encoded><![CDATA[<p>Cái ngày Khoa Toán đăng tin tuyển thực tập sinh cho công ty giải pháp X, tớ cũng hồ hởi viết thư xin thực tập, và đính kèm một chiếc CV lịch sự theo mẫu Oxford, lại còn viết bằng tiếng Anh hẳn hoi. Oách chưa? Tớ tự tin vô cùng về vốn tiếng Anh của mình, cũng như khả năng học hỏi bất kỳ thứ gì mà người ta sẵn sàng tọng vào cái cuống họng của tớ. Với kinh nghiệm "thực tập" hẳn 2 năm ở bộ Y (trái ngành, chả liên quan gì), liệu có thứ gì đánh đổ được sự tự tin ngất ngưởng của tớ đây?</p>
<p>Thằng ngu thì có bao giờ nghĩ đến cái đoạn mình là thằng ngu.</p>
<p>Mở đầu buổi phỏng vấn, ông anh cầm CV của tớ lên đọc, hoang mang vô cùng. "Em làm gì ở bộ Y?", anh ấy hỏi. Tớ bảo là tớ hỗ trợ bên đó xử lý dữ liệu này kia bằng Python. Xong ông anh bảo luôn là bên tớ cũng đâu có được sở hữu sáng chế giải pháp gì đâu. Trời má, đáng nhẽ ra khúc đấy tớ nên nhận ra là tớ không nên thanh minh giải thích thêm cái gì nữa, người ta chỉ quan tâm đến kinh nghiệm làm việc đúng chuyên ngành thôi, mà mình ghi tào lao vào cái CV làm gì không biết.</p>
<p>Tớ có nói rằng tớ đang năm 3. Lúc đọc vị khuôn mặt ngỡ ngàng của ông anh là tớ biết đây là kèo thối ngồi tâm sự rồi chứ thực tập cái gì nữa. Ông anh thử var xem tớ biết cái gì</p>
<ul>
<li>"Em thạo Python ở mức nào?" Dạ em biết qua loa còn cái gì không biết thì em hỏi ChatGPT ạ...</li>
<li>"Em thử kể tên một vài cấu trúc dữ liệu trong Python đi." Cứng họng luôn, đâu có nghĩ đến cái này đâu ba. Lúc đó tớ còn bối rối không hiểu ông anh muốn hỏi cái gì, cấu trúc chung chung như bọn tớ học DSA hay cấu trúc kiểu dictionary với list các thứ?</li>
<li>"CPU có bộ nhớ không, nếu có thì gọi là gì?" Tớ kịp nghĩ ra Register, nhưng nhớ nhầm nó nằm trên RAM.</li>
</ul>
<p>Đọc thêm 1 hồi, ông anh đá qua dự án tớ đang làm, tớ bảo tớ dùng có 4 bảng thôi. Ông anh chốt hạ là các dự án mà bọn anh phải làm toàn trăm bảng đổ lên, em làm 4 bảng thì làm SQL để làm gì cho phí. Xong ông anh hỏi tiếp là có muốn hỏi gì không. Đoạn này tớ quên rồi, nhưng tớ nhớ mang máng là tớ hỏi ngu đến độ ông anh bối rối hẳn luôn. Ý là hỏi không liên quan chuyên môn gì hết.</p>
<p>Hôm nay thì không có mail từ chối đâu, nhưng tớ biết thừa. Thôi cũng được, tớ nghĩ là buổi phỏng vấn này giúp tớ nhận ra là tớ chả biết cái gì :) Thất vọng chứ, nhưng cảm giác còn nhiều thứ để học cũng làm tớ hào hứng vô cùng. Còn thở là còn gỡ mà.</p>
]]></content:encoded></item><item><title><![CDATA[Electron on WINE]]></title><description><![CDATA[Listen, I know you have many question for me. Do I have no life when trying to use Electron Windows app on Linux, why do not just run it on a browser instead?
Let me tell you about Zalo, a purely pain]]></description><link>https://truongson.dev/electron-on-wine</link><guid isPermaLink="true">https://truongson.dev/electron-on-wine</guid><category><![CDATA[wine]]></category><category><![CDATA[Electron]]></category><category><![CDATA[Linux]]></category><category><![CDATA[zalo]]></category><dc:creator><![CDATA[Shaun Nguyen]]></dc:creator><pubDate>Thu, 11 Jun 2026 11:40:27 GMT</pubDate><content:encoded><![CDATA[<p>Listen, I know you have many question for me. Do I have no life when trying to use Electron Windows app on Linux, why do not just run it on a browser instead?</p>
<p>Let me tell you about Zalo, a purely pain-in-the-ass chat app in Vietnam. It's suck, I always prefer Telegram, or at least Viber, to this Wechat clone shit. At least Wechat run smoothly on my previous Kylin OS. Why I need to install it when it have web version? Because web version cannot sync, or backup data.</p>
<p>And run it on Linux is <strong>totally painful</strong>.</p>
<p>Okay, enough, if you want to try, I will show you how.</p>
<p>My current setup is Arch Linux with multilib repo enabled, flatpack installed and Bottle, a Wine GUI. I will not tell you how to install those, figure it out yourself bro. To get the Zalo executable file, go to dev mode in your browser, toggle device toolbar and switch to the device that you think will use Windows OS (in my case it is Asus Zenbook Fold). After that, just install it using Bottle.</p>
<p>What's then? Okay, this is crucial part: How to config it so it <strong>can run</strong></p>
<ul>
<li>Options &gt; Settings &gt; Components &gt; Runner &gt; <code>sys-wine-10.0</code></li>
<li>In same Settings page, Compatibility &gt; DLL Overrides &gt; New Override &gt; libglesv2.dll, Disabled</li>
<li>Go back, Dependencies &gt; install <code>allfonts</code>. This will make Wine display Vietnamese correctly</li>
<li>Go back, click 3-dots button beside Zalo program that we've installed, then Change launch option... Add <code>--no-sandbox</code> to command argument, save and exit.</li>
</ul>
<p>Now run it, and you will see your machine heat up and explode lmao. It will be laggy af, and the font will not beautiful as in Windows native.</p>
<p>But at least it can run and no problem, right?</p>
<p>Nah. Whenever you have a call, please pick it up on your phone. Wine cannot handle it, you cannot make call on Wine.</p>
<p>That's it. Have fun experimenting, and remove it after being frustrated with this piece of shit.</p>
]]></content:encoded></item><item><title><![CDATA[Tất cả sự bối rối về môn Toán sẽ được ném vào đây]]></title><description><![CDATA[Tại sao mọi người lại cố gắng dịch khái niệm Toán sang tiếng Việt nhở, nó làm tớ bối rối vô cùng. Tớ sẽ để cái này làm từ điển, mỗi lần sẽ cập nhật 1 chút
Siêu phẳng (Hyperplane)
Mặt phẳng (Plane) thư]]></description><link>https://truongson.dev/tu-dien-toan</link><guid isPermaLink="true">https://truongson.dev/tu-dien-toan</guid><category><![CDATA[Math]]></category><category><![CDATA[learning]]></category><dc:creator><![CDATA[Shaun Nguyen]]></dc:creator><pubDate>Thu, 11 Jun 2026 11:38:34 GMT</pubDate><content:encoded><![CDATA[<p>Tại sao mọi người lại cố gắng dịch khái niệm Toán sang tiếng Việt nhở, nó làm tớ bối rối vô cùng. Tớ sẽ để cái này làm từ điển, mỗi lần sẽ cập nhật 1 chút</p>
<h2>Siêu phẳng (Hyperplane)</h2>
<p>Mặt phẳng (Plane) thường bị hiểu trong không gian 2 chiều hoặc 3 chiều. Vì vậy nên đẻ ra vụ "hyper", tức là vượt qua khái niệm phẳng đấy. Nhưng mà sao lại dùng chữ "siêu" ta, nó dễ được hiểu thành "extreme" hoặc "super" thay vì "hyper".</p>
<p>Về cơ bản, định nghĩa của siêu phẳng là 1 tổ hợp tuyến tính có tổng bằng 1 hằng (constant), nôm na là có chạy trong cái "không gian" đó như thế nào thì giá trị vẫn như vậy. Nó sẽ cắt không gian xung quanh thành 2 nửa, 1 phần lớn hơn hoặc bằng, 1 phần nhỏ hơn hoặc bằng.</p>
<p>$$
\sum_{i = 0}^{n} \lambda_i x_i = const
$$</p>
<h2>Thứ nguyên (Dimension)</h2>
<p>Lý do không dùng từ "Chiều" ở đây, mặc dù nó cũng có nghĩa là dimension, là để nhấn mạnh vào số lượng biến số, chứ không nằm gói gọn trong không gian nữa. Nó xuất phát từ cụm 次元, với 次 - thứ bậc (degree), 元 - cơ bản, cốt lõi. Cách giải thích này tương đối gần với môn Abstract Algebra.</p>
<h2>Siêu phẳng tựa và thứ đẻ ra từ nó - Diện</h2>
<p>Gọi là tựa, vì tập lồi "tựa" vào siêu phẳng tạo thành bề mặt tiếp xúc. Bề mặt tiếp xúc này gọi là diện (face). cái "diện" này sinh ra để xác định ranh giới của tập lồi.</p>
<h2>Bao affine và bao lồi</h2>
<p>Ban đầu tớ bị lú cái này. Về sau thì theo tớ hiểu nôm na là</p>
<ul>
<li>Tổ hợp affine: Là tổ hợp có dạng</li>
</ul>
<p>$$
\sum_{i = 0}^{n} \lambda_i x_i = const, \sum \lambda_i = 1
$$</p>
<p>và không có ràng buộc gì thêm. Nếu hiểu nôm na kiểu hình học là nó sẽ bung xòe ra lung tung cả trong không gian \(\mathbb{R}^n\).</p>
<ul>
<li><p>Tổ hợp lồi: Nó không bung ra nữa, lần này ràng buộc sẽ là \(0 \leq \lambda_i \leq 1 \). Hiểu nôm na là nó sẽ thiết lập 1 vùng chặn bao mà mọi thứ chỉ được phép nằm trong vùng bao đó.</p>
</li>
<li><p>Bao của \(\mathbb{S}\) sẽ là tập nhỏ nhất chứa \(\mathbb{S}\). Từ 2 định nghĩa bên trên chắc mọi người cũng đoán được bao lồi và bao affine ha.</p>
</li>
</ul>
<h2>Hướng lùi xa, nón lùi xa</h2>
<ul>
<li><p>Hướng lùi xa (Recession Direction): là 1 đặc tính (property) của tập lồi. Đơn giản nó là 1 vector (phép dịch) vô hạn lên 1 điểm trong tập lồi mà sau khi dịch thì nó vẫn không chạy ra khỏi tập lồi. Nếu nó bị chặn (bounded) thì đương nhiên là không có hướng lùi xa.</p>
</li>
<li><p>Nón (Cone): một tập \(\mathbb{K}\) sao cho 1 vector trong tập đó có kéo dãn theo bất kỳ hệ số \(\lambda\) nào thì vẫn nằm gọn trong \(\mathbb{K}\)</p>
</li>
<li><p>Bị chặn: Có 1 quả cầu (ball), nó là hình tròn hay cầu 3D, tròn méo gì cũng được, nhưng nó sẽ phủ được bên ngoài tập với bán kính hữu hạn thôi.</p>
</li>
<li><p>Nón lùi xa: Tập hợp toàn bộ hướng lùi xa.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Quy trình code với LLM]]></title><description><![CDATA[Đầu xuân năm Bính Ngọ, đất trời hân hoan. Tiện tranh thủ khai bút, mình viết luôn một bài đăng chia sẻ cách mình sử dụng LLM để code, cũng coi như một cái mốc để mình nhìn thử xem sau sáu tháng, hoặc ]]></description><link>https://truongson.dev/quy-trinh-code-voi-llm</link><guid isPermaLink="true">https://truongson.dev/quy-trinh-code-voi-llm</guid><category><![CDATA[Developer]]></category><category><![CDATA[llm]]></category><dc:creator><![CDATA[Shaun Nguyen]]></dc:creator><pubDate>Thu, 11 Jun 2026 11:30:53 GMT</pubDate><content:encoded><![CDATA[<p>Đầu xuân năm Bính Ngọ, đất trời hân hoan. Tiện tranh thủ khai bút, mình viết luôn một bài đăng chia sẻ cách mình sử dụng LLM để code, cũng coi như một cái mốc để mình nhìn thử xem sau sáu tháng, hoặc một năm nữa, AI sẽ phát triển như thế nào nhé.</p>
<h2>Bối cảnh</h2>
<p>Mình chủ yếu code web, động tay chân với NextJS và Typescript. Trước đây phải ngồi đọc docs và sửa syntax rất khổ, mất thời gian setup codebase. Nhờ có LLM, thay vì mất thời gian vào language syntax và viết test case, mình đã có nhiều thời gian để tập trung vào những thứ căn bản hơn, như phân tích thiết kế và system design. Mình cũng lần đầu tiên bắt đầu đi phân tích đề bài và đi khảo sát người dùng để xây dựng sản phẩm phù hợp thị trường.</p>
<p>Mình theo dõi quá trình phát triển của các công cụ LLM từ năm 2022. Trong suốt 4 năm, workflow của mình, cũng như quan điểm về LLM thay đổi liên tục để thích ứng với công cụ mới. Ban đầu mình chỉ để LLM sửa linh tinh vớ vẩn, còn hiện tại một số tính năng nhỏ đã có thể để LLM chạy không cần duyệt.Cứ mỗi ba tháng lại có một mô hình mới vượt trội hơn, làm được nhiều việc hơn trước, nhưng cho đến hiện tại, mình cảm thấy đặc tính của các mô hình cũng tương đối ổn định. Giống như là mỗi một mô hình sẽ có một tính cách vậy.</p>
<p>Mình cũng cảm thấy khá may mắn, vì thời gian mình còn code C++ và cày DSA thuần chay thì LLM chưa phổ biến như hiện tại. Nhờ những "khó khăn" đó mà mình có thể nhanh chóng bù khuyết những tác vụ LLM chưa làm tốt mà không bị lệ thuộc. Code từ LLM viết chuẩn chỉ syntax, nhưng mình phải dành nhiều thời gian để review business logic và phân tích thiết kế hơn. Mình vẫn sợ LLM thay thế mình, vì trình độ mình yếu, học nghệ chưa tinh, mình phải học system design và architecture để chuyển dịch vai trò từ người triển khai sang người ra quyết định. Mình thấy gian khổ lắm, nhưng mà phải sống chết với nghề thôi. Suy cho cùng, nhiệm vụ của kỹ sư là giải quyết vấn đề mà.</p>
<p>Má nó, từ ngày dùng LLM, chưa thấy nhàn đi, chỉ ước một ngày có 48 tiếng để làm được nhiều việc hơn.</p>
<h2>Công cụ sử dụng</h2>
<h3>Mô hình LLM</h3>
<p>Các model mình thường xuyên sử dụng là Anthropic Claude (Opus 4.5, Sonnet 4.5, Haiku), Google Gemini (Gemini 3 Pro, Gemini 3 Flash).</p>
<h4>Họ Anthropic Claude</h4>
<p>Theo trải nghiệm cá nhân của mình </p>
<ul>
<li><strong>Cladue Opus 4.5</strong> phân tích đề bài và lập kế hoạch rất tốt. </li>
<li><strong>Sonnet 4.5</strong> có thể dùng để sửa một vài bug nhỏ. </li>
<li><strong>Haiku</strong> thì thôi ... thực sự là mô hình này vẫn hơi phế, mình nghĩ là cần phải finetune để function calling hoặc call tool tốt hơn, chứ diff edit và code tạo ra từ mô hình vẫn chưa đủ tốt.</li>
</ul>
<h4>Họ Google Gemini</h4>
<p>So với Claude, các mô hình của Google (Gemini 3 Pro, Gemini 3 Flash) cho kết quả chấp nhận được, hợp lý với chi phí, hoặc do mình quen với mức giá cắt cổ từ Anthropic, nên giá token của Google đúng nghĩa rẻ gần như cho. Cũng phải thôi, <em>Google không cần mua chip từ NVIDIA</em>. </p>
<ul>
<li><strong>Gemini 3 Pro</strong> có 1M context window, đọc codebase lớn rất tốt, tuy nhiên khi suy luận phức tạp thì bắt đầu trả về nội dung sai loạn, lặp lại nội dung. </li>
<li><strong>Gemini 3 Flash</strong> sửa code, gọi tool rất tốt, nhưng cũng gặp phải vấn đề trên, đặc biệt là thường xuyên đi lệch vấn đề, phải cầm tay chỉ việc rất nhiều chứ không one-shot được như Claude.</li>
</ul>
<p>Điểm chung của 2 mô hình này là ảo giác mạnh, cần grounding. Mình giảm bớt ngẫu nhiên bằng cách tận dụng tính năng research sẵn có, hoặc review trên codebase cho trước, nhìn chung phải mớm context. Mình cũng tận dụng ảo giác của Gemini để brainstorm hoặc làm giao diện rất ổn. Còn để code 1 feature lớn thì nah.</p>
<p>Sinh viên tiết kiệm chi phí nên tháng nào dư xăng, mình đăng ký Pro subscription của Claude, còn lại xài chùa Google Antigravity và Github Student. Antigravity cung cấp quyền truy cập đến các mô hình của Claude và Google, còn Copilot bật riêng Claude Sonnot 4.5.</p>
<p>Ngoài ra, Google cũng cho 1 năm sử dụng Gemini Pro, mình tận dụng làm market research.</p>
<p>Thời điểm mình viết bài này thì Opus 4.6 đã ra mắt với 1M context window. Mình và bá tánh nghi ngờ là dùng foundation model của Google vì Opus 4.6 cũng bị ảo giác. Kỳ vọng của mình vào Opus rất cao, nên mình chọn đợi đến Opus 5 thì nhảy thuyền.</p>
<h3>Công cụ sử dụng</h3>
<p>Trước đây, mình tải cả 3 code editor: Antigravity, VS Code, Cursor, cả ba đều chung ruột của VS Code, cái nào có AI thì dùng cái đó, hết token thì xoay luân phiên, cài thêm cả Claude Code hỗ trợ. Hiện tại mình xoá hết, chỉ để lại VS Code và cài OpenCode. </p>
<p>Vậy tại sao là OpenCode chứ không phải Claude Code? Không phải 2 bên đều là TUI à?</p>
<p>OpenCode tích hợp sẵn LSP, bắt lỗi syntax và linting cho LLM rất nhanh, đồng nghĩa với việc LLM được grounding tốt hơn và luôn luôn đảm bảo là sẽ follow syntax. Tool call của OpenCode cũng thông minh, nếu không thể gọi tool thì nó sẽ tự động chuyển sang bash command. Đến thời điểm viết bài thì OpenCode thông minh hơn hẳn Claude Code rồi :) Biết sao được, Anthropic làm mô hình ngu đi để vắt cực khô người dùng mà.</p>
<h4>Thiết lập codebase</h4>
<p>Với mỗi project, chúng ta đều phải tạo một file <code>CLAUDE.md</code> cho Claude Code sử dụng ha, mọi người có thể dùng <code>/init</code> trên Claude Code để tổng hợp thông tin codebase: mô tả sản phẩm, thư viện đang dùng, cấu trúc thư mục, coding convention giúp Claude navigate tốt hơn nhé. Rồi mình lại phải tạo lại <code>GEMINI.md</code>, <code>AGENTS.md</code> cho các AI editor khác nhau, mình thấy rất khó chịu, nên mình softlink <code>CLAUDE.md</code> thành <code>GEMINI.md</code>, <code>AGENTS.md</code> để đỡ phải tạo nhiều file, cũng đỡ phải copy paste nhiều lần. Có lẽ mình sẽ cân nhắc softlink luôn thành <code>README.md</code>, còn gì tuyệt hơn một file README cho cả AI và contributor dùng chung chứ? Sau khi tạo, mình cũng kiểm tra lại và viết tay bổ sung một số phần quan trọng như business logic, chứ mình vẫn chưa tin LLM lắm, còn viết cho người đọc nữa chứ. Mà thôi, lỡ đâu người ta cũng dùng LLM để đọc...</p>
<p>Ngoài ra, mình cũng tạo thư mục <code>docs/</code> và yêu cầu LLM mỗi lần thực hiện thay đổi hoặc nghiên cứu sẽ tạo file trong đó. Thư mục này sẽ được thêm vào <code>.gitignore</code> để tránh bị commit lên repo.</p>
<h4>MCP và Skill</h4>
<p>Để tiết kiệm context cho LLM và grounding chống bịa, mình cài cắm MCP cho LLM, và sử dụng các skill để LLM thực hiện các tác vụ cụ thể.</p>
<p>Hiện giờ mình chỉ dùng Context7, nhưng vẫn giới thiệu đủ:</p>
<ul>
<li><del>Serena (đã ngừng sử dụng, gây context rotting trong các codebase của mình):</del> Hỗ trợ index codebase và memory.</li>
<li>Context7: Hỗ trợ tra cứu tài liệu của các thư viện để LLM cài đặt đúng syntax.</li>
<li><del>ShadCN (đã ngừng sử dụng, Context7 là đủ):</del> Tra cứu tài liệu của ShadCN component library.</li>
<li><del>Next Devtool (ngừng sử dụng do OpenCode không câu móc được log của Next)</del>: Giúp LLM debug NextJS và tra tài liệu</li>
</ul>
<p>Riêng Skill, mọi người có thể sử dụng <a href="https://skills.sh/">Vercel SKILL.sh</a> để xem skill nào ưng ý rồi tải về. Nhưng mọi người cũng nhớ chú ý nguy cơ prompt injection nhé, kẻo đến ngày auto approve xong code của mình bị cắm mã độc lúc nào chẳng hay. Mình khó tính nên manual approve từng lệnh một nhưng cũng mệt mỏi lắm.</p>
<p>Có hai skill mình thấy rất hay và muốn giới thiệu với mọi người:</p>
<ul>
<li>BMAD method: Đóng gói Agile vào làm quy trình cho LLM. Ngày đẹp trời mà mọi người không muốn để LLM đọc thì tự đọc cũng được, có thể xem cách làm việc với Agile.</li>
<li>vercel-react-best-practices: Tinh hoa đúc kết kinh nghiệm làm việc với React của team Vercel hàng chục năm.
Cá nhân mình chỉ dùng 2 chiếc này. Skill.sh cũng có phần tự tìm tự cài skill thì phải, nhưng mình thích kiểm soát hơn.</li>
</ul>
<h4>Linting và type generator</h4>
<p>Đây là hai thứ mà mình thấy không thể thiếu vì nó giúp vạch ranh giới cho LLM rất tốt. Linting để LLM không sai syntax, type generator để nhanh chóng lấy type từ OpenAPI Swagger thay vì để LLM tự mò mẫm. Trước kia thì mình thường để LLM tự truy cập Swagger JSON, nhưng giờ thì không cần nữa, vì type generated không bao giờ sai :) Nếu có gì bất hợp lý, mình có thể quay qua sửa backend.</p>
<p>Mình sử dụng biome cho linting vì thay thế được phần lớn Prettier và ESLint. Orval generate TS type + Zod. Thực ra có <code>openapi-typescript-codegen</code> nhưng không xịn bằng Orval ở khoản không chơi cùng với Zod.</p>
<p>Ngoài ra còn có <code>knip</code> dùng để tìm deadcode trong repo nữa, dùng để phát hiện rác thải từ LLM rất tốt.</p>
<h4>Các công cụ khác</h4>
<p>Để làm việc với codebase kỹ hơn, không để LLM cho ăn quả lừa kèm 1 nùi slop, mình cũng xài cả các công cụ này nữa</p>
<ul>
<li><a href="https://codewiki.google/">Google CodeWiki</a> giúp mình tìm hiểu nhanh cơ chế hoạt động của 1 thư viện/framework nổi tiếng. Tài liệu được tạo bằng Gemini 3.</li>
<li><a href="https://stitch.withgoogle.com/">Google Stitch</a> tạo UI draft rất ngon, nhưng chưa có kéo thả, mỗi lần muốn làm gì lại phải chat, rất tốn thời gian. Từ xương sườn này có thể để LLM phát triển tiếp giao diện và adapt vào codebase cũng như system design hiện tại.</li>
<li><a href="https://developer.apple.com/design/human-interface-guidelines">Apple Human Design Interface Guideline</a> cung cấp các phương pháp, từ khoá để thiết kế chỉn chu hơn chứ LLM làm gì có taste :)</li>
<li><a href="https://detail.design/">Detail Design</a> các mẹo sửa tiểu tiết, handcrafting giao diện đến tận cùng</li>
<li><a href="https://agentation.dev/">Agentaton</a> chú thích thẳng vào UI, copy dán ngược vào LLM sửa lỗi giao diện rất chuẩn</li>
<li><a href="https://tweakcn.com/">TweakCN</a> tạo Tailwind theme cho ShadCN để đồng nhất giao diện</li>
<li><a href="https://dribbble.com/">Dribble</a>, <a href="https://mobbin.com/">Mobbin</a>, <a href="https://component.gallery/">Component Gallery</a>, <a href="https://www.awwwards.com/">Awwwards</a>, <a href="are.na">Arena</a> để tìm cảm hứng tham khảo</li>
<li><a href="https://claudekit.cc/">ClaudeKit</a> nâng tầm LLM vô địch thiên hạ, setup codebase và tạo sản phẩm nhanh. 99 đô na, của anh Goon Nguyen phát triển.</li>
</ul>
<h2>Quy trình làm việc</h2>
<p>Trước khi sử dụng BMAD thì mình thực hiện theo trình tự sau thù công, về sau BMAD hỏi luôn thành khung rồi nên cũng tiện. Đọc rất là sách giáo khoa, nhưng mình tuân thủ khá chặt chẽ. Mất 1-2 ngày setup codebase còn hơn là làm nửa chừng đập đi xây lại, căn cơ phải chắc chứ đúng không?</p>
<h3>Xác định yêu cầu</h3>
<p>Ngay khi mình nhận brief của khách, mình bẻ nó ra. Trên trường mình cũng được học môn phân tích thiết kế hệ thống, nên mình cũng hiểu được sườn câu hỏi. Mình là người giải quyết vấn đề, vậy nên tập trung vào vấn đề. Nhiều khi khách nhảy thẳng đến giải pháp (anh muốn làm 1 cái app để quản lý cửa hàng) thì mình cũng kiên nhẫn hỏi lại xem là anh hay làm kiểu gì, và gặp vấn đề ở đâu trong quy trình. Nhiều khi họ cứ nói vậy vì có người xui họ, nhiệm vụ của mình là tư vấn cho phù hợp với túi tiền của khách mà lại giải quyết vấn đề trơn tru. Còn khách nhét tiền thì bảo gì cũng ừ bảo sao cũng gật.</p>
<p>Tiếp theo là nắm bắt được cái taste của khách. Bước này thì mình sẽ đi stalk FB của khách, của quý công ty xem gu thẩm mỹ của khách như thế nào, công ty ngành nghề ra sao để xem họ sẽ thích kiểu gì. Thậm chí có công ty muốn giao diện phải thật nhiều chữ, phải rực rỡ, mà mình sửa tới hồi mới hiểu ý của khách là đẩy tất cả thành màu đỏ. Thậm chí có khách quái thai hơn, muốn chữ nhỏ xíu để nhồi càng nhiều nội dung càng tốt. Những tình huống đó sẽ được giải quyết ở bước 3.</p>
<p>Sau bước này, ta sẽ xác định được cơ bản</p>
<ul>
<li>Vấn đề của khách</li>
<li>Gu của khách</li>
<li>Cách làm việc, trao đổi của khách. Mình cũng sẽ một phần dự đoán được là khi nào khách trả tiền cho mình</li>
</ul>
<p>Nếu được và tốt nhất thì làm cái việc khách đang kẹt 1 lần, mình trước khi code web cũng lăn lộn đủ việc chân tay, nên thừa hiểu cái việc đó nhức nhối ở đâu, và nhanh chóng đưa tư vấn phù hợp cho khách. Bằng không thì cứ thân với nhân viên là họ cũng kể khổ với mình cho khách quan. Đoạn nào họ nói xấu sếp thì cứ ừ gật chứ đừng hùa nhé kẻo người ta bẫy mình bật ghi âm ghi hình.</p>
<h3>Phân tích yêu cầu</h3>
<p>Từ các vấn đề và thông tin khách đưa ra, mình sẽ bẻ vấn đề ra nhỏ hơn, rồi nghiên cứu thử có hệ thống nào tồn tại trước đó mà giải quyết bài toán này không. Tìm các vấn đề chính để xác định demo phải trưng ra cho khách xem cái gì. Chi tiết thì mọi người tìm hiểu từ khoá design system, nhiều người viết lắm rồi. Phần này mình cũng brainstorm cùng với LLM, mình tìm dẫn chứng phản biện, đến đoạn nào mà đọc ổn ổn rồi thì validate lại lần cuối bằng cách bắt LLM research tiếp.</p>
<p>Sau bước này thì mình hòm hòm biết được mình cần làm những tính năng nào, ước tính thời gian, cũng như biết là phải dùng tool gì rồi. Có thể bắt đầu báo giá.</p>
<h3>Prototype</h3>
<p>Khách cọc xong thì mình bắt đầu setup codebase, viết file <code>CLAUDE.md</code> mô tả, rồi đem trích một phần lên Stitch để tạo layout. Đưa cho khách duyệt, ưng phương án nào thì lấy phương án đấy triển khai tiếp. Trong lúc đó, tranh thủ đi xem reference, copy ảnh đưa vào Gemini lấy design keyword. Nhớ lưu lại lịch sử thay đổi nhé, phòng tình huống 7749 option xong khách chốt cái đầu tiên. Tình huống mà mình đề xuất sửa gáy khách thì cứ làm 1 bản khách 1 bản của mình rồi cho họ quyết định, nhiều khi khách còn chả biết mình muốn gì nên Prototype phải làm thật tốt để cho thấy mình phân tích ngon đét còn hơn cả khách.</p>
<p>Trong lúc đấy, tranh thủ giấu dốt, lên CodeWiki đọc tài liệu về công cụ sẽ sử dụng. Nó sẽ rất phụ thuộc tình huống. Landing page kèm tin tức thì Hugo, tối ưu SEO thì NextJS, cần lưu trữ quản lý thì Postgres, lưu lượng cao thì Redis cache, task chạy lâu thì thêm RabbitMQ. Cắm thêm backend Django rồi charge tiền khách.</p>
<p>Trong trường hợp budget của khách kẹt sỉ mà đòi phải ổn thì sử dụng stack của Cloudflare (D1, R2, Workers). Free Tier của CF khá ổn cho phần lớn nhu cầu. Cần thì lại tận dụng cả Supabase/Neon nữa. Muốn nhàn thân với NextJS thì deploy Vercel, nhưng coi chừng vendor locking.</p>
<p>Khách duyệt các thứ OK thì sẽ đến màu. Mình sẽ lấy màu dựa trên màu thương hiệu của khách, hoặc brand guideline. Nếu khách làm thương hiệu không OK thì xem tuổi khách hợp mệnh nào rồi chọn color pallete là xong.</p>
<p>Sau đó thì bắt đầu ngồi nghĩ layout, lên awwward tìm mỏi mắt, làm visual board tổng hợp ref vào Arena. Bần cùng nữa thì dùng Pinterest.</p>
<p>Sau đó thì bắt tay vào implement. Trong quá trình implement nhớ phòng chừa trường hợp khách muốn sửa yêu cầu, đặc biệt nhằm vào các phần mà khách hay đòi đổi như Hero Section, hoặc là cái này phải trông như thế này. Dùng ShadCN sẽ đỡ nhiều công, bảo LLM sửa component theo ý khách là được, nhưng trước đó phải lập danh sách task để đảm bảo LLM sửa đủ file. Tập trung các tính năng giải quyết nỗi vất vả to nhất của khách hàng làm prototype. Bước này ưu tiên dùng được.</p>
<h3>Triển khai</h3>
<p>Ở đây mình đổi mô hình liên tục. Dùng OpenCode, mình để Plan rồi chọn Opus 4.5 để xác định danh sách tính năng, sau đó bổ sung bằng tay, và hỏi ngược lại để LLM đóng vai người dùng và hoài nghi. Tranh luận và chốt xong sẽ bắt đầu chuyển về Sonnet 4.5 để bắt đầu triển khai từng mục một. Thường LLM sẽ chạy rất nhanh cho ra một bộ khung 70% nhưng mà tasteless. Bước này thì có thể tiếp tục xoay tua Opus và Claude để viết test case. Nếu có bug pátt sinh, xử lý bằng Gemini Flash, cái nào khó quá thì Sonnet là được.</p>
<p>Khi nào mà khách ưng layout rồi và codebase ổn định thì mình mới bắt đầu cải thiện design hiện tại.</p>
<h2>Kết</h2>
<p>Tay mình mỏi nên cũng chưa nghĩ ra gì thêm. Mọi người góp ý mình qua thư <a href="mailto:contact@truongson.dev">contact@truongson.dev</a> nhé. Mình rất muốn nghe setup của mọi người, cũng như các mong muốn để mình xem có thể viết phần nào kỹ hơn nữa. Cảm ơn mọi người đã đọc.</p>
]]></content:encoded></item><item><title><![CDATA[Cào 1M+ bài viết từ VnExpress]]></title><description><![CDATA[Trong đợt thực tập này, nhiệm vụ đầu tiên của tớ là cào ra đủ 1M+ post từ VnExpress. Nhiệm vụ tân thủ mà. Tớ đã ngây thơ, và ngạo mạn nghĩ rằng chỉ cần lần dò thì có thể dễ dàng có đủ 1M+ đường dẫn để]]></description><link>https://truongson.dev/cao-1m-bai-viet-tu-vnexpress</link><guid isPermaLink="true">https://truongson.dev/cao-1m-bai-viet-tu-vnexpress</guid><category><![CDATA[web scraping]]></category><category><![CDATA[Data Mining]]></category><category><![CDATA[statistics]]></category><category><![CDATA[internships]]></category><dc:creator><![CDATA[Shaun Nguyen]]></dc:creator><pubDate>Thu, 11 Jun 2026 11:05:43 GMT</pubDate><content:encoded><![CDATA[<p>Trong đợt thực tập này, nhiệm vụ <strong>đầu tiên</strong> của tớ là cào ra đủ 1M+ post từ VnExpress. Nhiệm vụ tân thủ mà. Tớ đã ngây thơ, và ngạo mạn nghĩ rằng chỉ cần lần dò thì có thể dễ dàng có đủ 1M+ đường dẫn để cào. Nhưng đời không như mơ, tớ ăn ban, tớ chỉ được 7k6 link với cách cũ mặc dù thử đủ loại chiến thuật. Rồi cuối cùng, nhờ người bạn ChatGPT, tớ đã tìm ra hướng xử lý hahahaha.</p>
<p>Bài viết này sẽ mô tả lại toàn bộ quá trình tớ tìm ra cách cào bài (mà tớ nghĩ là) siêu thông minh này, từ việc tuyệt vọng thử hết mọi cách trước khi đầu hàng, rồi có được khoảnh-khắc-aha nhờ <strong>uniform sampling</strong>.</p>
<p>Nào, bắt đầu thôi.</p>
<hr />
<h2>Đề bài từ sếp</h2>
<p>Sếp: Anh khoán đề bài cho các em cào được 1M+ bài từ VnExpress. Xong bước này thì ta tiến hành các bước tiếp theo. Anh gợi ý là các em có thể dò vào từng link để tìm các link liên quan.</p>
<p>Tớ: Xời, đơn giản, em sẽ nhảy vào <code>sitemap.xml</code></p>
<p>Sếp: Em cứ làm đi, mọi thứ cần có số liệu.</p>
<p>Cái đầu tự ngạo của tớ nghĩ rằng chỉ cần ChatGPT thì tớ có thể dễ dàng đạt mục tiêu thôi. Không. Tớ là đồ ngu.</p>
<h2>Phân tích bài toán và chiến lược đầu tiên</h2>
<p>Để có được 1M+ bài, thì ta phải tìm được 1M+ link. Để có cái link đó thì tớ bới <code>sitemap.xml</code> nhứ tớ có bảo sếp. Web nào lớn mà chả phải có cái này.</p>
<p>Các cậu nhìn thấy phần này chắc là sẽ lạc quan đầy niềm tin lắm ha, trúng mánh ha:</p>
<pre><code class="language-xml">&lt;sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"&gt;
	&lt;sitemap&gt;
		&lt;loc&gt;https://vnexpress.net/categories-sitemap.xml&lt;/loc&gt;
		&lt;lastmod&gt;2025-04-13T04:45:12+07:00&lt;/lastmod&gt;
	&lt;/sitemap&gt;
	&lt;sitemap&gt;
		&lt;loc&gt;https://vnexpress.net/google-news-sitemap.xml&lt;/loc&gt;
		&lt;lastmod&gt;2025-04-13T04:45:12+07:00&lt;/lastmod&gt;
	&lt;/sitemap&gt;
	&lt;sitemap&gt;
		&lt;loc&gt;https://vnexpress.net/latestnews-sitemap.xml&lt;/loc&gt;
		&lt;lastmod&gt;2025-04-13T04:45:12+07:00&lt;/lastmod&gt;
	&lt;/sitemap&gt;
	&lt;sitemap&gt;
		&lt;loc&gt;https://vnexpress.net/articles-2025-sitemap.xml&lt;/loc&gt;
		&lt;lastmod&gt;2025-04-13T04:45:12+07:00&lt;/lastmod&gt;
	&lt;/sitemap&gt;
	&lt;sitemap&gt;
		&lt;loc&gt;https://vnexpress.net/articles-2024-sitemap.xml&lt;/loc&gt;
		&lt;lastmod&gt;2025-04-13T04:45:12+07:00&lt;/lastmod&gt;
	&lt;/sitemap&gt;
	&lt;sitemap&gt;
		&lt;loc&gt;https://vnexpress.net/articles-2023-sitemap.xml&lt;/loc&gt;
		&lt;lastmod&gt;2025-04-13T04:45:12+07:00&lt;/lastmod&gt;
	&lt;/sitemap&gt;
	&lt;sitemap&gt;
		&lt;loc&gt;https://vnexpress.net/articles-2022-sitemap.xml&lt;/loc&gt;
		&lt;lastmod&gt;2025-04-13T04:45:12+07:00&lt;/lastmod&gt;
	&lt;/sitemap&gt;
	&lt;sitemap&gt;
		&lt;loc&gt;https://vnexpress.net/articles-2021-sitemap.xml&lt;/loc&gt;
		&lt;lastmod&gt;2025-04-13T04:45:12+07:00&lt;/lastmod&gt;
	&lt;/sitemap&gt;
&lt;/sitemapindex&gt;
</code></pre>
<p>Biết gì không, thử truy cập vào là <strong>bị redirect về trang chủ</strong>. Bẩn bựa vô cùng. Liệu đây có phải là 1 cái honeytrap?</p>
<blockquote>
<p>VnExpress chơi đẹp mặt tiền, nhưng khóa sạch cổng sau. Không crawl được.</p>
</blockquote>
<p>Không bỏ cuộc, tớ thử đóng giả làm bot Google dùng User Agent. Làm gì có chuyện nó giấu không cho Google biết chứ, đúng không, SEO là cái sống còn của 1 trang tin tức mà. Đoán xem kết quả như thế nào. Haha, vẫn tạch lô, vẫn bị redirect.</p>
<p>Nhìn chung là tạch lô phát đầu. Không sao cả, mình có thể làm nông dân, tự tin giảm xuống 70%.</p>
<hr />
<h3>Nông dân trâu cày: Quét khắp trang lấy số</h3>
<p>Tớ nghĩ đến vụ này khi thử navigation loanh quanh như gợi ý của sếp: Đâm sâu. Thử mấy cái chuyên mục xem sao nhỉ? Chà, thật bất ngờ. Mỗi khi navigate, nó sẽ đội lên 1 số, và tiếp tục đến khi redirect về <code>https://timkiem.vnexpress.net/</code>. Đại khái, cái link sẽ như thế này:</p>
<pre><code class="language-plaintext">https://vnexpress.net/thoi-su/chinh-tri-p{i}
</code></pre>
<p>Cứ vậy mà dò <code>i</code> đến khi không được nữa, tức là đã <em>hết bài</em> trong mục. Như vậy, chỉ cần dò theo từng mục là ngon ăn rồi.</p>
<p>Có vẻ là có tiềm năng đấy, triển khai thôi. Game dễ nhỉ?</p>
<p>Không. Kết quả là 7k6 link, chính xác là 7638. So với 1M, thì đúng là con muỗi. Với 7k6 link này, tớ chỉ có được các bài từ 26/12/2024 đến 13/04/2025. Còn xa mới đủ. Được có 3 tháng thì làm ăn được cái trò trống gì chứ?</p>
<p>À đúng rồi, tiện đây nói luôn: <code>newspaper4k</code> không cào ra được ngày tháng viết bài của VnExpress, thông tin đấy phải tìm ở tag <code>meta</code>.</p>
<p>Cook luôn. Tớ ngồi thở dài ôm đầu.</p>
<hr />
<h2>Con khỉ tìm ra gà rán KFC</h2>
<p>Tuyệt vọng lắm rồi đấy. Tớ bảo với sếp là, ôi anh ơi hay là mình lấy bài từ Dân Trí, có sẵn xml đẹp xinh chỉ việc ngồi chấm mút.</p>
<p>Sếp: Như vậy là lạc quan đó, tiến thêm được ~30x rồi. 👍 Chỉ cần x8 số đấy nữa là đến đích rồi, tiếp tục nhé.</p>
<p>Tớ: Để em thử đổi nguồn khác xem sao ạ, em vừa kiểm tra nhanh thì Dân Trí có sitemap đủ từ 2005 đến giờ có vẻ lạc quan hơn</p>
<p>Sếp: Nghĩa là thay vì ta về đích thì chọn cách dễ hơn là… đi về đích khác à? Tiếp cận kiểu này thì có cách dễ hơn nữa. Lên tải luôn bộ wiki data về, nó có sẵn hơn trăm triệu bài. Cần dữ liệu dạng đó thì có thể lên đây tải để dùng nhé. Không có vấn đề gì. Nhưng tập trung bài toán hiện tại, cái này có thể dùng sau.</p>
<p>Ơ cay thật, tức là có cách hay hơn? Tham vọng trong tớ bùng lên, và tớ hỏi ChatGPT xem là với 2 chiến thuật tớ đã xài thì có cách nào tiếp không. Nó gợi ý cho 3 chiến thuật: 1 là lấy sitemap bằng request thuần không qua trình duyệt, 2 là lật tung Wayback Machine lên.</p>
<p>Tớ chú ý đến cái chiến thuật số 3 hơn cả. Nó bảo là, mày thử xem cái ID phía cuối xem, có thể có bất ngờ.</p>
<p>Đây, ví dụ 1 bài viết sẽ có link như thế này:</p>
<pre><code class="language-plaintext">https://vnexpress.net/thong-qua-du-thao-phuong-huong-nhan-su-trung-uong-khoa-14-4873218.html
</code></pre>
<p>Thấy số <code>4873218</code> chứ? Tớ quyết định thử giữ nguyên số đó, và đổi phần slug đằng trước. Link đó thành như thế này:</p>
<pre><code class="language-plaintext">https://vnexpress.net/bombarido-crocodio-4873218.html
</code></pre>
<p>Voila! Nó redirect về link cũ 🤯 Xong tớ đổi số đi, lùi về tầm vài chục. Ra bài viết khác mới toanh. Khoảnh khắc a-ha tới rồi</p>
<blockquote>
<p>Hóa ra là <strong>chỉ cần đúng ID (7 chữ số), slug là rác cũng được.</strong></p>
</blockquote>
<hr />
<h2>Đến lúc toán học được xài vào đây</h2>
<p>Trong quá trình test, tớ có thử nghiên cứu quy luật. 2 số đầu sẽ quyết định năm đăng bài, ví dụ <code>48</code> sẽ là 2024-2025, <code>47</code> sẽ là 2024-2023. Tớ nhớ lại đoạn xml kia, năm bắt đầu là 2001. Thử trừ đi xem sao. Ồ không, nó lại là năm 2006, tức là có thể lùi xuống nữa. Lùi tới lùi hồi, xuống đến 18 thì thực sự là 2001.</p>
<p>Xong tớ phát hiện ra tiếp, là không phải cứ lùi thẳng là sẽ có bài. Giữa những khoảng ngẫu nhiên, nó cho 1 vố toàn ra 404. Hay lắm, thách đố trí thông minh của ta. Nếu giờ cứ cào chay cho lùi từ 4 triệu về 1 triệu thì căng nhỉ, vạn năm mới fetch xong được.</p>
<p>Tớ chợt nhớ ra sếp bảo là: Mình là kỹ sư, không cần đủ, chỉ cần đúng. Nhẩm lúc nãy ngồi test thì ước chừng có khoảng 70% là sẽ có bài. Voila, tớ có thể sử dụng xác suất ở đây.</p>
<p>Vậy là tớ hỏi ChatGPT là bây giờ có chiến lược nào để đạt được khoảng 95-98% số lượng không, chấp nhận vài % rơi rớt. Thừa dư 1M, chả lo, có gì điều chỉnh lên sau.</p>
<p>Nó tư vấn cho ngay: Bây giờ mày chặt ra thành đoạn nhỏ, lấy hẳn theo block 10k đi, rồi tiến hành sampling 1 vài mẫu thôi. Xong tớ hỏi tiếp là giờ lấy sample ra sao ní? Nó bèn cung cấp cho 1 công thức tính số sample trên quần thể hữu hạn (finite population), với 4 tham số là N - kích thước tổng thể, Z - độ tin cậy, e - sai số, p - tỷ lệ kỳ vọng bài hợp lệ:</p>
<p>$$n = \frac{N \cdot Z^2 \cdot p (1 - p)}{(N - 1) \cdot e^2 + Z^2 \cdot p (1 - p)}$$</p>
<p>Trong tình huống này, ta cho rằng p = 0.5 do chưa biết là có bao nhiêu hợp lệ, vậy cứ giả định là 50%. Vậy ta sẽ có các số cần thay</p>
<ul>
<li><p>\(N = 10000\)</p>
</li>
<li><p>\(Z = 1.96\) (cho 95% độ tin cậy)</p>
</li>
<li><p>\(p = 0.5\)</p>
</li>
<li><p>\(e = 0.05\)</p>
</li>
</ul>
<p>Thay số, ta có \(n \approx 370\)</p>
<blockquote>
<p>Vậy chỉ cần lấy khoảng <strong>370 ID random đều</strong> trong tập để ước lượng tỷ lệ bài hợp lệ <strong>với sai số ±5%</strong>.</p>
</blockquote>
<p>Mút chỉ chưa. Nếu tăng sai số lên ±8% thì chỉ cần khoảng 150 mẫu thôi. Nhưng mà thôi, chúng ta phải khó tính lên chứ. 300 mẫu cũng khá mút chỉ rồi.</p>
<p>Sau đó, ta tính tỷ lệ số bài fetch được trong block với số sample. Coi như với giả thiết mình đặt ra ban đầu là tồn tại khoảng 70% bài, như vậy tỷ lệ mà trên mốc 70% thì mình quét bằng hết.</p>
<p>Còn trên 40%? Cào ngẫu nhiên một nửa số ID. Trên 15%? Lấy 1/10. Bần cùng bất đắc dĩ thì quét 1 2 bài lấy lệ rồi té. Cái nào dính 404 thì cache lại kiểm tra.</p>
<p>Thấy không, siêu thông minh.</p>
]]></content:encoded></item><item><title><![CDATA[Sử dụng Jupyter Notebook để viết báo cáo khoa học thay cho LaTeX]]></title><description><![CDATA[Jupyter Notebook là một công cụ rất mạnh để viết tài liệu cho các dự án, đặc biệt là data researching. Những người quen viết Markdown như mình rất muốn tận dụng sức mạnh của các thư viện Python, và kế]]></description><link>https://truongson.dev/jupyter-notebook-to-pdf</link><guid isPermaLink="true">https://truongson.dev/jupyter-notebook-to-pdf</guid><category><![CDATA[Jupyter Notebook ]]></category><category><![CDATA[latex]]></category><category><![CDATA[Python]]></category><category><![CDATA[markdown]]></category><dc:creator><![CDATA[Shaun Nguyen]]></dc:creator><pubDate>Thu, 18 May 2023 18:53:31 GMT</pubDate><content:encoded><![CDATA[<p>Jupyter Notebook là một công cụ rất mạnh để viết tài liệu cho các dự án, đặc biệt là data researching. Những người quen viết Markdown như mình rất muốn tận dụng sức mạnh của các thư viện Python, và kết hợp chúng cùng LaTeX để tạo tài liệu.</p>
<p>Đây là thành phẩm sau khi "thao túng" Jupyter Notebook.</p>
<p>Ở đây, chúng ta sẽ sử dụng trình soạn thảo VSCode, cùng trình quản lý gói Mamba.<br />Theo hướng dẫn chính thức của VSCode thì sẽ yêu cầu cài Anaconda, nhưng Anaconda có nhược điểm trí mạng là chậm khủng khiếp, và không tường minh.</p>
<p>Hướng dẫn này mình viết cho Arch Linux, các hệ điều hành nhân Linux khác tiến hành tương tự. Riêng với Windows, mình không sử dụng nên nếu bạn cần hướng dẫn, hãy nhắn tin cho mình <a href="https://www.facebook.com/alaire.sena/">tại đây</a>.</p>
<h2>Cài đặt texlive</h2>
<p>Đây là điều bắt buộc để xuất ra được văn bản giống y sì văn bản LaTeX, vì Jupyter sẽ chuyển đổi file .ipynb thành file .tex rồi mới xuất thành pdf.</p>
<p>Tiến hành cài đặt các gói cần thiết cho LaTeX:</p>
<pre><code class="language-bash">sudo pacman -S texlive-most texlive-langextra texlive-bibtexextra
</code></pre>
<h2>Cài đặt mamba, jupyter và ipykernel</h2>
<p>Với Arch Linux, máy mặc định có sẵn python nên bạn không cần cài thêm python.</p>
<p>Tiến hành cài đặt Mamba bằng cách chạy các lệnh sau trong Terminal:</p>
<pre><code class="language-bash">curl -L -O "https://github.com/conda-forge/miniforge/releases/latest/download/Mambaforge-\((uname)-\)(uname -m).sh"
bash Mambaforge-\((uname)-\)(uname -m).sh
mamba init bash
</code></pre>
<p>Sau đó, tắt Terminal đi và bật lại, chạy tiếp các lệnh sau để cài đặt jupyter và ipykernel. Tiện thể chúng ta cũng sẽ cài luôn numpy, scipy, sympy, mathplotlib và numba:</p>
<pre><code class="language-bash">mamba install jupyter ipykernel numpy scipy sympy mathplotlib numba
</code></pre>
<h2>Cài đặt VSCode</h2>
<p>Có thể bạn cài đặt CodeOSS nhưng hên xui sẽ cài được các Plugin chính thức của Microshit. Mình ghét một mớ Telemetry của VSCode, nhưng tiện thì xài vậy.</p>
<p>Với Arch Linux, bạn hãy cài VSCode từ Arch User Repository. Để tiện lợi cho bạn, mình khuyến khích sử dụng <a href="https://github.com/Jguer/yay#installation">yay - Yet Another Yogurt</a> làm trình quản lý gói.</p>
<p>Bạn tiến hành cài đặt VSCode như sau:</p>
<pre><code class="language-bash">yay -S visual-studio-code-bin
</code></pre>
<p>Sau đó, mở mục Extension lên và cài đủ bộ Plugin sau:</p>
<p>Có 4 thứ phải cài: Python, Pylance, Jupyter và LaTeX Workshop. Cài 4 thứ đó thì những thứ còn lại tự cài đặt vào cùng.</p>
<h2>Tiến hành thao túng Jupyter Notebook</h2>
<p>Sau 3 ngày mất ăn mất ngủ lần mò, mình đã tìm ra cách để chỉnh sửa file PDF LaTeX xuất ra.</p>
<p>Nếu bạn không biết, khi Jupyter xuất PDF thì file PDF mặc định có phần đầu đề là tên file và ngày tháng. Ví dụ file của bạn là test.ipynb thì tiêu đề sẽ là test cùng ngày tháng năm tạo file, nhìn rất thiếu chuyên nghiệp.</p>
<p>Để thay đổi cục diện này, bạn hãy chỉnh sửa file \(HOME\)/mambaforge/share/jupyter/nbconvert/templates/latex/base.tex.j2. Xóa trắng và dán toàn bộ nội dung trong <a href="https://pastebin.com/raw/aYHPa8Fu">link này</a> vào file.</p>
<p>Tiếp theo, chỉnh sửa metadata của Jupyter Notebook. Trong file Notebook của bạn, chọn lần lượt như sau:</p>
<p>Bấm theo thứ tự trong ảnh nhé!</p>
<p>Sau đó, một file JSON sẽ xuất hiện để bạn chỉnh sửa cho lẹ. Bây giờ bạn có thể cuộn xuống tầm gần cuối và sửa thông tin từa tựa như trong ảnh nhé:</p>
<p>Chú<br />ý sửa phần authors và title là được, mấy cái còn lại không có cũng<br />được. Để giúp bạn tùy biến thêm các thông tin như email với viện trường,<br />mình sẽ viết một bài riêng sau.</p>
<p>Cuối cùng là cấu hình VSCode sao cho tạo file thuận lợi nhất. Trên thanh công cụ ở trên dầu, chọn "Terminal &gt; Configure Default Build Task ... &gt; Create tasks.json from template &gt; Others". Sau đó sẽ xuất hiện 1 file tasks.json cho bạn chỉnh sửa, và bạn xóa trắng nội dung file, sau đó dán đoạn code này vào:</p>
<pre><code class="language-json">{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "PDF Build [xelatex]",
            "type": "shell",
            "command": "echo | jupyter nbconvert --to pdf ${fileBasename} --template latex",
            "problemMatcher": [],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "presentation": {
                "reveal": "silent",
                "revealProblems": "onProblem",
                "close": true
            }
        }
    ]
}
</code></pre>
<p>Nhớ lưu lại file này. Sau đó, chọn file Notebook bạn đang làm, ấn tổ hợp Ctrl Shift B hoặc chọn "Terminal  &gt; Run Build Task &gt; PDF Build [xelatex]". Kết quả trả về 1 file PDF sạch sẽ gọn gàng.</p>
<h2>Kết</h2>
<p>Trên đây là hướng dẫn cơ bản cách để tạo tài liệu "nhái" LaTeX từ Jupyter Notebook.</p>
]]></content:encoded></item></channel></rss>