<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://benjamindaoson.github.io/daoson_website/feed.xml" rel="self" type="application/atom+xml" /><link href="https://benjamindaoson.github.io/daoson_website/" rel="alternate" type="text/html" /><updated>2026-10-12T12:18:36+08:00</updated><id>https://benjamindaoson.github.io/daoson_website/feed.xml</id><title type="html">Benjamin Taoson · 赖建铭</title><subtitle>Benjamin Taoson（赖建铭）的个人网站。探索大模型、智能体与机器人学习，分享项目设计、实验结果与技术思考，连接交流、合作与教学。</subtitle><author><name>Benjamin Taoson</name></author><entry xml:lang="en"><title type="html">Why I’m Building a Digital Employee System</title><link href="https://benjamindaoson.github.io/daoson_website/posts/2026/06/05/why-build-digital-employee-system.en/" rel="alternate" type="text/html" title="Why I’m Building a Digital Employee System" /><published>2026-06-05T10:00:00+08:00</published><updated>2026-06-05T10:00:00+08:00</updated><id>https://benjamindaoson.github.io/daoson_website/posts/2026/06/05/why-build-digital-employee-system.en</id><content type="html" xml:base="https://benjamindaoson.github.io/daoson_website/posts/2026/06/05/why-build-digital-employee-system.en/"><![CDATA[<p>I am building a digital employee system.</p>

<p>Let me set the boundary first: this is not a mature product, and it is not a complete public case study yet. The repository, demo, and implementation details are still being organized. What I can share now is the direction, the problem context, the hypothesis I am testing, and the build notes I plan to publish next.</p>

<p>I am writing this down because I increasingly believe the important question for AI agents is not whether they can produce an impressive demo. The question is whether they can complete a piece of work inside a real workflow in a way that is reliable, recoverable, and supervised.</p>

<h2 id="there-is-a-gap-between-demos-and-work">There Is a Gap Between Demos and Work</h2>

<p>Many agent demos look impressive. An agent can read files, call tools, write code, generate plans, and simulate a full task chain.</p>

<p>But a working demo is not the same as a reliable system.</p>

<p>Once agents enter a real workflow, the questions become much more concrete:</p>

<ul>
  <li>Are the task boundaries clear?</li>
  <li>How does context move between agents?</li>
  <li>When a tool call fails, does the system know where it failed?</li>
  <li>Which parts of the state are still trustworthy?</li>
  <li>Should the next step be automatic recovery or human review?</li>
  <li>How is the result verified?</li>
</ul>

<p>These questions are less flashy than model capability, but they decide whether an agent can move from a one-off demo to a repeatable system.</p>

<h2 id="what-i-mean-by-digital-employee">What I Mean by Digital Employee</h2>

<p>By digital employee, I do not mean “a chatbot that sounds more capable.”</p>

<p>I mean a working system:</p>

<ul>
  <li>It receives a clear work objective.</li>
  <li>It breaks the work into executable steps.</li>
  <li>It calls tools to complete parts of the task.</li>
  <li>It preserves state and recovers from failures.</li>
  <li>It asks for human judgment when uncertainty matters.</li>
  <li>It leaves a trace that can be reviewed and improved.</li>
</ul>

<p>In other words, a digital employee is not a single model. It is a system made of models, tools, state, protocols, evaluation, and human checkpoints.</p>

<h2 id="the-hard-part-is-not-chat">The Hard Part Is Not Chat</h2>

<p>Chat ability matters, but it is not the part I care about most.</p>

<p>The engineering questions matter more:</p>

<ol>
  <li><strong>Coordination protocols</strong>: how do agents divide work? Who plans, who executes, and who reviews?</li>
  <li><strong>Tool reliability</strong>: what happens when a tool call fails? When should the system retry, and when should it stop?</li>
  <li><strong>State recovery</strong>: if execution fails halfway through, which intermediate state can still be trusted?</li>
  <li><strong>Human review</strong>: which steps must ask for human confirmation, and which can safely run automatically?</li>
  <li><strong>Result verification</strong>: how does the system know it completed the work, instead of merely appearing to complete it?</li>
</ol>

<p>None of these problems can be solved completely by a single prompt. They need system design, and they need many small experiments.</p>

<h2 id="current-state">Current State</h2>

<p>This project is currently active.</p>

<p>I am organizing three directions:</p>

<ul>
  <li>task boundaries and context handoff between agents</li>
  <li>recovery behavior after failed tool use</li>
  <li>human checkpoints and system boundaries</li>
</ul>

<p>I have not packaged this as a product, and I have not published a specific repository yet. That boundary matters. If I cannot explain what the system can and cannot do, I should not present it as a finished result.</p>

<h2 id="what-i-want-to-validate-next">What I Want to Validate Next</h2>

<p>The next step is to clarify the system before showing more interface.</p>

<p>I want to document:</p>

<ul>
  <li>what the current prototype can actually do</li>
  <li>which steps still require human review</li>
  <li>how the system responds when tool calls fail</li>
  <li>which implementation details can be public</li>
  <li>whether a more specific repository or small demo can be opened</li>
</ul>

<p>These notes should become part of the build log, not remain private thoughts.</p>

<h2 id="why-this-is-worth-doing-long-term">Why This Is Worth Doing Long Term</h2>

<p>I believe AI agents will change work not because of one impressive demo, but because many reliability details slowly become stronger:</p>

<ul>
  <li>clearer boundaries</li>
  <li>recoverable failures</li>
  <li>better human checkpoints</li>
  <li>traceable work</li>
  <li>systems that can be maintained over time</li>
</ul>

<p>That is also why I am building this site. It is not meant to present a perfect image. It is meant to turn judgment, experiments, and writing into a long-term research system.</p>

<p>The digital employee system is only one experiment, but it will be one of my most important build objects for the next phase.</p>]]></content><author><name>Benjamin Taoson</name></author><category term="AI" /><category term="agents" /><category term="engineering" /><summary type="html"><![CDATA[The digital employee system is not a product launch. It is my long-term experiment for studying how agents move from demos to reliable workflows.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-06-05-why-build-digital-employee-system.en.png" /><media:content medium="image" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-06-05-why-build-digital-employee-system.en.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="zh"><title type="html">我为什么在构建数字员工系统</title><link href="https://benjamindaoson.github.io/daoson_website/posts/2026/06/05/why-build-digital-employee-system/" rel="alternate" type="text/html" title="我为什么在构建数字员工系统" /><published>2026-06-05T10:00:00+08:00</published><updated>2026-06-05T10:00:00+08:00</updated><id>https://benjamindaoson.github.io/daoson_website/posts/2026/06/05/why-build-digital-employee-system</id><content type="html" xml:base="https://benjamindaoson.github.io/daoson_website/posts/2026/06/05/why-build-digital-employee-system/"><![CDATA[<p>我正在构建一个数字员工系统。</p>

<p>先把边界说清楚：它目前不是成熟产品，也不是已经公开的完整项目案例。具体仓库、演示和实现细节还在整理中。现在可以公开的是方向、问题背景、我正在验证的假设，以及接下来准备补充的构建记录。</p>

<p>我之所以要把这些写出来，是因为我越来越觉得，AI 智能体最重要的问题不是“能不能做一个惊艳演示”，而是：<strong>它能不能在真实工作流里稳定、可恢复、可监督地完成一段工作。</strong></p>

<h2 id="演示和工作之间有一道鸿沟">演示和工作之间有一道鸿沟</h2>

<p>现在很多智能体演示看起来都很强。它可以读文件、调用工具、写代码、生成计划，甚至模拟一个完整任务链。</p>

<p>但演示能跑，不等于系统可靠。</p>

<p>真正进入工作流以后，问题会变得具体很多：</p>

<ul>
  <li>任务边界是否清楚？</li>
  <li>上下文在多个智能体之间如何交接？</li>
  <li>工具调用失败后，系统知道失败在哪里吗？</li>
  <li>哪些状态仍然可信？</li>
  <li>下一步应该自动恢复，还是交给人确认？</li>
  <li>结果如何被验证？</li>
</ul>

<p>这些问题看起来不如模型能力本身耀眼，但它们决定了智能体能不能从一次性演示变成可反复运行的系统。</p>

<h2 id="我说的数字员工是什么">我说的数字员工是什么</h2>

<p>我说的数字员工，不是“一个更会聊天的机器人”。</p>

<p>我更关心的是一个工作系统：</p>

<ul>
  <li>它能接收一个明确的工作目标。</li>
  <li>它能把工作拆成可执行步骤。</li>
  <li>它能调用工具完成部分任务。</li>
  <li>它能在失败时保留状态并恢复。</li>
  <li>它能在不确定时请求人类判断。</li>
  <li>它能留下过程记录，方便复盘和改进。</li>
</ul>

<p>换句话说，数字员工不是单个模型，而是模型、工具、状态、协议、评估和人在回路共同组成的系统。</p>

<h2 id="真正难的不是聊天">真正难的不是聊天</h2>

<p>聊天能力当然重要，但它不是我最关心的部分。</p>

<p>我更关心这些工程问题：</p>

<ol>
  <li><strong>协作协议</strong>：多个智能体之间如何分工？谁负责计划，谁负责执行，谁负责检查？</li>
  <li><strong>工具可靠性</strong>：工具调用失败后如何重试？什么时候停止重试？</li>
  <li><strong>状态恢复</strong>：执行到一半失败，哪些中间状态可以继续用？</li>
  <li><strong>人工确认</strong>：什么环节必须让人确认？什么环节可以自动完成？</li>
  <li><strong>结果验证</strong>：系统如何知道自己做对了，而不是只是“看起来完成了”？</li>
</ol>

<p>这些问题没有一个能靠一句提示词彻底解决。它们需要系统设计，也需要大量小实验。</p>

<h2 id="当前状态">当前状态</h2>

<p>目前这个项目处在持续构建阶段。</p>

<p>我正在整理三个方向：</p>

<ul>
  <li>智能体之间的任务分工和上下文交接。</li>
  <li>工具调用失败后的恢复机制。</li>
  <li>人在回路的确认点和系统边界。</li>
</ul>

<p>我还没有把它包装成产品，也没有公开具体仓库。这个边界很重要：如果我还不能清楚说明系统做到了什么、没做到什么，就不应该把它说成成熟成果。</p>

<h2 id="接下来要验证什么">接下来要验证什么</h2>

<p>下一步，我想先把系统说明补清楚，而不是急着展示更多界面。</p>

<p>我会优先整理：</p>

<ul>
  <li>当前原型到底能完成什么。</li>
  <li>哪些环节仍然需要人类确认。</li>
  <li>工具调用失败时系统如何响应。</li>
  <li>哪些实现细节可以公开。</li>
  <li>是否能开放一个更具体的仓库或小型演示。</li>
</ul>

<p>这些内容会进入构建记录，而不是只留在脑子里。</p>

<h2 id="为什么这值得长期做">为什么这值得长期做</h2>

<p>我相信 AI 智能体真正改变工作方式的时刻，不会来自某个炫酷演示，而会来自很多可靠性细节慢慢变稳：</p>

<ul>
  <li>边界更清楚。</li>
  <li>失败更可恢复。</li>
  <li>人类介入点更合理。</li>
  <li>工作过程更可追踪。</li>
  <li>系统能被长期维护。</li>
</ul>

<p>这也是我建设这个网站的原因。它不是为了展示一个完美形象，而是为了把判断、实验和写作沉淀成一个长期研究系统。</p>

<p>数字员工系统只是其中一个实验，但它会成为我接下来一段时间最重要的构建对象。</p>]]></content><author><name>Benjamin Taoson</name></author><category term="AI" /><category term="智能体" /><category term="工程" /><summary type="html"><![CDATA[数字员工系统不是成熟产品发布，而是我用来研究智能体如何从演示走向可靠工作流的长期实验。]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-06-05-why-build-digital-employee-system.png" /><media:content medium="image" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-06-05-why-build-digital-employee-system.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="en"><title type="html">Building a Modern Frontend Project with Vite</title><link href="https://benjamindaoson.github.io/daoson_website/posts/2026/05/20/vite-modern-frontend.en/" rel="alternate" type="text/html" title="Building a Modern Frontend Project with Vite" /><published>2026-05-20T10:00:00+08:00</published><updated>2026-05-20T10:00:00+08:00</updated><id>https://benjamindaoson.github.io/daoson_website/posts/2026/05/20/vite-modern-frontend.en</id><content type="html" xml:base="https://benjamindaoson.github.io/daoson_website/posts/2026/05/20/vite-modern-frontend.en/"><![CDATA[<p>This note records how I set up a clean, fast, maintainable frontend
experiment with Vite. It is a practical setup note, not a complete framework
tutorial.</p>

<blockquote>
  <p>“Tools should serve thought, not the other way around.”</p>
</blockquote>

<h2 id="why-vite">Why Vite</h2>

<p>Vite leans on the browser’s native ES Modules support, so dev mode skips
bundling entirely — and startup feels instant. Compared to the traditional
Webpack flow, the wins are:</p>

<ul>
  <li>Cold start drops from <strong>seconds</strong> to <strong>milliseconds</strong></li>
  <li>HMR is essentially instant; the bigger your project, the more obvious the gap</li>
  <li>TypeScript, JSX, and CSS preprocessors work out of the box</li>
  <li>Production builds use Rollup, with smaller output than Webpack</li>
</ul>

<p>The terminal output below shows what <code class="language-plaintext highlighter-rouge">npm run dev</code> looks like — note the 187ms
startup:</p>

<p><img src="/assets/img/posts/vite-modern-frontend/dev-server.svg" alt="Vite dev server terminal output" />
<em>Vite dev server · cold start in 187ms</em></p>

<h2 id="getting-started">Getting started</h2>

<p>A single command bootstraps a new project:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>npm create vite@latest my-app <span class="nt">--</span> <span class="nt">--template</span> vue-ts
<span class="nb">cd </span>my-app
npm <span class="nb">install
</span>npm run dev
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Open <code class="language-plaintext highlighter-rouge">http://localhost:5173</code> and you’ll see the default page.</p>

<p>I am not embedding a video demo here yet. If I record a real project walkthrough,
I will link it from Elsewhere or add it to the article later.</p>

<h2 id="common-configuration">Common configuration</h2>

<p>Here’s the <code class="language-plaintext highlighter-rouge">vite.config.ts</code> I keep around:</p>

<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">import</span> <span class="p">{</span> <span class="nx">defineConfig</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">vite</span><span class="dl">'</span>
<span class="k">import</span> <span class="nx">vue</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">@vitejs/plugin-vue</span><span class="dl">'</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">fileURLToPath</span><span class="p">,</span> <span class="nx">URL</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">node:url</span><span class="dl">'</span>

<span class="k">export</span> <span class="k">default</span> <span class="nf">defineConfig</span><span class="p">({</span>
  <span class="na">plugins</span><span class="p">:</span> <span class="p">[</span><span class="nf">vue</span><span class="p">()],</span>
  <span class="na">resolve</span><span class="p">:</span> <span class="p">{</span>
    <span class="na">alias</span><span class="p">:</span> <span class="p">{</span>
      <span class="dl">'</span><span class="s1">@</span><span class="dl">'</span><span class="p">:</span> <span class="nf">fileURLToPath</span><span class="p">(</span><span class="k">new</span> <span class="nc">URL</span><span class="p">(</span><span class="dl">'</span><span class="s1">./src</span><span class="dl">'</span><span class="p">,</span> <span class="k">import</span><span class="p">.</span><span class="nx">meta</span><span class="p">.</span><span class="nx">url</span><span class="p">))</span>
    <span class="p">}</span>
  <span class="p">},</span>
  <span class="na">server</span><span class="p">:</span> <span class="p">{</span>
    <span class="na">port</span><span class="p">:</span> <span class="mi">3000</span><span class="p">,</span>
    <span class="na">open</span><span class="p">:</span> <span class="kc">true</span>
  <span class="p">}</span>
<span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="closing">Closing</h2>

<p>Tools change. The shape of the problem doesn’t. I hope this saves you a few
of the potholes I’ve stepped in. Drop me an email if you’ve found a sharper
approach — I’d love to hear it.</p>

<hr />

<p><em>Written in May 2026. Corrections welcome.</em></p>]]></content><author><name>Benjamin Taoson</name></author><category term="frontend" /><category term="tools" /><summary type="html"><![CDATA[From zero, step by step, to a clean, fast, maintainable frontend dev environment.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-05-20-vite-modern-frontend.en.png" /><media:content medium="image" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-05-20-vite-modern-frontend.en.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="zh"><title type="html">使用 Vite 搭建现代化前端项目</title><link href="https://benjamindaoson.github.io/daoson_website/posts/2026/05/20/vite-modern-frontend/" rel="alternate" type="text/html" title="使用 Vite 搭建现代化前端项目" /><published>2026-05-20T10:00:00+08:00</published><updated>2026-05-20T10:00:00+08:00</updated><id>https://benjamindaoson.github.io/daoson_website/posts/2026/05/20/vite-modern-frontend</id><content type="html" xml:base="https://benjamindaoson.github.io/daoson_website/posts/2026/05/20/vite-modern-frontend/"><![CDATA[<p>这篇记录我如何用 Vite 搭一个干净、快速、可维护的前端实验环境。
它不是完整框架教程，而是一份偏实践的项目初始化笔记。</p>

<blockquote>
  <p>「工具应该服务于思想，而不是相反。」</p>
</blockquote>

<h2 id="为什么选择-vite">为什么选择 Vite</h2>

<p>Vite 利用浏览器原生的 ES Modules 能力，开发时无需打包，启动速度极快。
相比传统的 Webpack，它在以下几个方面有明显优势：</p>

<ul>
  <li>冷启动时间从「秒级」缩短到「毫秒级」</li>
  <li>HMR（热更新）几乎是即时的，文件越多优势越明显</li>
  <li>开箱即用支持 TypeScript、JSX、CSS 预处理器</li>
  <li>生产环境用 Rollup 打包，输出更精简</li>
</ul>

<p>下面这张图是 <code class="language-plaintext highlighter-rouge">npm run dev</code> 启动后的终端输出示意，注意那个 187ms 的启动时间：</p>

<p><img src="/assets/img/posts/vite-modern-frontend/dev-server.svg" alt="Vite 开发服务器启动后的终端输出" />
<em>Vite dev server · 冷启动 187ms</em></p>

<h2 id="快速开始">快速开始</h2>

<p>用一行命令就能创建一个新项目：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>npm create vite@latest my-app <span class="nt">--</span> <span class="nt">--template</span> vue-ts
<span class="nb">cd </span>my-app
npm <span class="nb">install
</span>npm run dev
</pre></td></tr></tbody></table></code></pre></div></div>

<p>就这么简单。打开 <code class="language-plaintext highlighter-rouge">http://localhost:5173</code>，你就能看到默认页面了。</p>

<p>这篇文章暂时不放视频演示。等有真实录制的项目过程，再补到外部发布或文章里。</p>

<h2 id="常用配置">常用配置</h2>

<p>下面是我常用的 <code class="language-plaintext highlighter-rouge">vite.config.ts</code> 配置：</p>

<div class="language-typescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">import</span> <span class="p">{</span> <span class="nx">defineConfig</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">vite</span><span class="dl">'</span>
<span class="k">import</span> <span class="nx">vue</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">@vitejs/plugin-vue</span><span class="dl">'</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">fileURLToPath</span><span class="p">,</span> <span class="nx">URL</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">node:url</span><span class="dl">'</span>

<span class="k">export</span> <span class="k">default</span> <span class="nf">defineConfig</span><span class="p">({</span>
  <span class="na">plugins</span><span class="p">:</span> <span class="p">[</span><span class="nf">vue</span><span class="p">()],</span>
  <span class="na">resolve</span><span class="p">:</span> <span class="p">{</span>
    <span class="na">alias</span><span class="p">:</span> <span class="p">{</span>
      <span class="dl">'</span><span class="s1">@</span><span class="dl">'</span><span class="p">:</span> <span class="nf">fileURLToPath</span><span class="p">(</span><span class="k">new</span> <span class="nc">URL</span><span class="p">(</span><span class="dl">'</span><span class="s1">./src</span><span class="dl">'</span><span class="p">,</span> <span class="k">import</span><span class="p">.</span><span class="nx">meta</span><span class="p">.</span><span class="nx">url</span><span class="p">))</span>
    <span class="p">}</span>
  <span class="p">},</span>
  <span class="na">server</span><span class="p">:</span> <span class="p">{</span>
    <span class="na">port</span><span class="p">:</span> <span class="mi">3000</span><span class="p">,</span>
    <span class="na">open</span><span class="p">:</span> <span class="kc">true</span>
  <span class="p">}</span>
<span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="小结">小结</h2>

<p>工具会变，但解决问题的本质不会。希望这篇文章能帮你少踩一些坑。
如果你有更好的实践，欢迎给我发邮件交流。</p>

<hr />

<p><em>本文写于 2026 年 5 月。如有疏漏，欢迎指正。</em></p>]]></content><author><name>Benjamin Taoson</name></author><category term="前端" /><category term="工具" /><summary type="html"><![CDATA[从零开始，一步步配置一个干净、快速、可维护的前端开发环境。]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-05-20-vite-modern-frontend.png" /><media:content medium="image" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-05-20-vite-modern-frontend.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="zh"><title type="html">代码可读性的本质是什么</title><link href="https://benjamindaoson.github.io/daoson_website/posts/2026/05/12/code-readability/" rel="alternate" type="text/html" title="代码可读性的本质是什么" /><published>2026-05-12T14:30:00+08:00</published><updated>2026-05-12T14:30:00+08:00</updated><id>https://benjamindaoson.github.io/daoson_website/posts/2026/05/12/code-readability</id><content type="html" xml:base="https://benjamindaoson.github.io/daoson_website/posts/2026/05/12/code-readability/"><![CDATA[<p>为什么有的代码读起来像散文，有的却像加密电报？</p>

<p>写代码这么多年，我越来越觉得，<strong>代码的可读性，本质上是「认知负担」的问题</strong><sup id="fnref:cognitive-load"><a href="#fn:cognitive-load" class="footnote" rel="footnote" role="doc-noteref">1</a></sup>——读者每读一行，要在脑子里维护多少状态？</p>

<h2 id="命名是第一道关">命名是第一道关</h2>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="c1">// 不好</span>
<span class="kd">function</span> <span class="nf">f</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">x</span><span class="p">.</span><span class="nf">filter</span><span class="p">(</span><span class="nx">i</span> <span class="o">=&gt;</span> <span class="nx">i</span><span class="p">.</span><span class="nx">s</span> <span class="o">===</span> <span class="nx">y</span><span class="p">);</span> <span class="p">}</span>

<span class="c1">// 好</span>
<span class="kd">function</span> <span class="nf">findUsersByStatus</span><span class="p">(</span><span class="nx">users</span><span class="p">,</span> <span class="nx">status</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">return</span> <span class="nx">users</span><span class="p">.</span><span class="nf">filter</span><span class="p">(</span><span class="nx">user</span> <span class="o">=&gt;</span> <span class="nx">user</span><span class="p">.</span><span class="nx">status</span> <span class="o">===</span> <span class="nx">status</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>短变量名节省了打字时间，但偷走了未来读者的时间——而后者通常是几十倍的代价<sup id="fnref:read-write-ratio"><a href="#fn:read-write-ratio" class="footnote" rel="footnote" role="doc-noteref">2</a></sup>。</p>

<h2 id="抽象层级要一致">抽象层级要一致</h2>

<p>一个函数里，如果一会儿在做高层级的业务编排，一会儿又在做底层的字节操作，
读者就得不停地切换视角，非常累。</p>

<h2 id="写给未来的自己">写给未来的自己</h2>

<p>我的一个习惯：<strong>在每个稍复杂的函数前，写一句话告诉未来的自己「这是什么、为什么」</strong>。</p>

<p>不是注释每一行（那是糟糕的注释），而是告诉读者「上下文」。</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="c1"># 因为后端在 v2 之前会返回字符串型的 ID，
# 这里强制转 int 以保证前后端类型一致
</span><span class="n">user_id</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span><span class="n">payload</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">id</span><span class="sh">'</span><span class="p">))</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>这种注释，写代码的人自己半年后回来看都会感谢自己。</p>

<h2 id="小结">小结</h2>

<p>可读性不是「好看」，而是<strong>「下一个人接手时的痛苦最小化」</strong>。
而那个「下一个人」，大概率就是几个月后的你自己。</p>
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:cognitive-load">
      <p>「认知负担」是 John Sweller 1988 年提出的概念，原指学习者处理新信息时占用的工作记忆容量。代码上下文也遵循同一规则：人类工作记忆约能维持 4±1 个组块。变量名差、缩进乱、抽象层级跳跃，都会让组块数迅速超载。 <a href="#fnref:cognitive-load" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:read-write-ratio">
      <p>Robert C. Martin 在《Clean Code》里提到，代码”读”与”写”的时间比是 <strong>10:1</strong> 以上。意味着任何让”读”变快的微小投入，回报率都是正数。 <a href="#fnref:read-write-ratio" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Benjamin Taoson</name></author><category term="编程" /><category term="思考" /><summary type="html"><![CDATA[为什么有的代码读起来像散文，有的却像加密电报？聊聊命名、抽象层级和「写给未来的自己看」的几条心得。]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-05-12-code-readability.png" /><media:content medium="image" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-05-12-code-readability.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="zh"><title type="html">我的 Mac 工作流配置 2026</title><link href="https://benjamindaoson.github.io/daoson_website/posts/2026/04/28/mac-workflow-2026/" rel="alternate" type="text/html" title="我的 Mac 工作流配置 2026" /><published>2026-04-28T20:00:00+08:00</published><updated>2026-04-28T20:00:00+08:00</updated><id>https://benjamindaoson.github.io/daoson_website/posts/2026/04/28/mac-workflow-2026</id><content type="html" xml:base="https://benjamindaoson.github.io/daoson_website/posts/2026/04/28/mac-workflow-2026/"><![CDATA[<p>每年我都会写一篇当下的工作流配置，一是给自己留个备份，二是分享给可能感兴趣的朋友。</p>

<h2 id="终端--shell">终端 &amp; Shell</h2>

<ul>
  <li><strong>终端</strong>：Ghostty —— 速度极快、配置即代码</li>
  <li><strong>Shell</strong>：zsh + <a href="https://ohmyz.sh/">oh-my-zsh</a></li>
  <li><strong>提示符</strong>：<a href="https://starship.rs/">Starship</a> —— 跨 Shell 通用</li>
  <li><strong>复用</strong>：tmux + tmuxinator</li>
</ul>

<h2 id="编辑器">编辑器</h2>

<ul>
  <li><strong>主力</strong>：VS Code（Vim 插件 + Copilot）</li>
  <li><strong>轻量编辑</strong>：Helix（终端里直接 <code class="language-plaintext highlighter-rouge">hx</code>）</li>
  <li><strong>写作</strong>：Obsidian + iA Writer</li>
</ul>

<h2 id="必装的命令行工具">必装的命令行工具</h2>

<table>
  <thead>
    <tr>
      <th>工具</th>
      <th>替代了什么</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">bat</code></td>
      <td><code class="language-plaintext highlighter-rouge">cat</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">eza</code></td>
      <td><code class="language-plaintext highlighter-rouge">ls</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">fd</code></td>
      <td><code class="language-plaintext highlighter-rouge">find</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">rg</code></td>
      <td><code class="language-plaintext highlighter-rouge">grep</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">zoxide</code></td>
      <td><code class="language-plaintext highlighter-rouge">cd</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">fzf</code></td>
      <td>所有需要模糊搜索的场景</td>
    </tr>
  </tbody>
</table>

<h2 id="快捷键">快捷键</h2>

<p>最近发现一个超好用的：用 <a href="https://karabiner-elements.pqrs.org/">Karabiner</a> 把 CapsLock 改成”按下是 Escape，长按是 Ctrl”。
适配 Vim 用户来说，效率提升至少 30%。</p>

<h2 id="小结">小结</h2>

<p>工具是为人服务的，不要陷进去为了配置而配置。
我每年都会忍痛删掉一些「装了但没怎么用」的工具——保持轻量很重要。</p>]]></content><author><name>Benjamin Taoson</name></author><category term="工具" /><category term="效率" /><summary type="html"><![CDATA[分享一下今年我每天都在用的软件、Shell 配置、快捷键。]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-04-28-mac-workflow-2026.png" /><media:content medium="image" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-04-28-mac-workflow-2026.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="zh"><title type="html">读《程序员的自我修养》有感</title><link href="https://benjamindaoson.github.io/daoson_website/posts/2026/04/15/reading-programmer-self-cultivation/" rel="alternate" type="text/html" title="读《程序员的自我修养》有感" /><published>2026-04-15T21:00:00+08:00</published><updated>2026-04-15T21:00:00+08:00</updated><id>https://benjamindaoson.github.io/daoson_website/posts/2026/04/15/reading-programmer-self-cultivation</id><content type="html" xml:base="https://benjamindaoson.github.io/daoson_website/posts/2026/04/15/reading-programmer-self-cultivation/"><![CDATA[<p>写代码很多年，直到读了《程序员的自我修养——链接、装载与库》，
我才第一次真正「看见」代码是怎么变成可执行程序的。</p>

<h2 id="你以为你懂其实你不懂">你以为你懂，其实你不懂</h2>

<p>我以为我懂编译：源码 → 编译器 → 可执行文件。</p>

<p>但你知道吗？</p>
<ul>
  <li><strong>链接器</strong> 才是真正决定符号位置的人</li>
  <li><strong>重定位</strong> 是为了让代码在任意地址都能跑</li>
  <li><strong>动态链接</strong> 让多个程序可以共享同一份代码</li>
</ul>

<p>这些底层细节，决定了你写的 <code class="language-plaintext highlighter-rouge">printf</code> 到底是怎么被调用的。</p>

<h2 id="印象最深的一段">印象最深的一段</h2>

<blockquote>
  <p>内存中的程序和磁盘上的程序，看起来都是一堆字节，
但它们之间的鸿沟，需要操作系统、编译器、链接器、加载器
配合无间地才能跨越。</p>
</blockquote>

<p>读到这里，我突然对每一个能跑起来的程序，都有了一种新的敬畏。</p>

<h2 id="推荐指数">推荐指数</h2>

<p>★★★★★</p>

<p>适合所有「写过几年代码但从没认真想过底层」的人。
准备好一杯咖啡和几个安静的晚上。</p>]]></content><author><name>Benjamin Taoson</name></author><category term="读书" /><category term="随笔" /><summary type="html"><![CDATA[链接、装载、运行——这本书让我第一次真正「看见」了代码是如何变成可执行程序的。]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-04-15-reading-programmer-self-cultivation.png" /><media:content medium="image" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-04-15-reading-programmer-self-cultivation.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="zh"><title type="html">CSS 容器查询完全指南</title><link href="https://benjamindaoson.github.io/daoson_website/posts/2026/03/30/css-container-queries/" rel="alternate" type="text/html" title="CSS 容器查询完全指南" /><published>2026-03-30T16:00:00+08:00</published><updated>2026-03-30T16:00:00+08:00</updated><id>https://benjamindaoson.github.io/daoson_website/posts/2026/03/30/css-container-queries</id><content type="html" xml:base="https://benjamindaoson.github.io/daoson_website/posts/2026/03/30/css-container-queries/"><![CDATA[<p>很长一段时间，”响应式设计”约等于”媒体查询”。但媒体查询有个根本问题：
<strong>它只能根据视口（viewport）来响应，而不是组件所在的容器</strong>。</p>

<p>容器查询（Container Queries）解决了这个问题。</p>

<h2 id="基本用法">基本用法</h2>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="c">/* 1. 把父元素声明为容器 */</span>
<span class="nc">.card-wrapper</span> <span class="p">{</span>
  <span class="nl">container-type</span><span class="p">:</span> <span class="nb">inline-size</span><span class="p">;</span>
  <span class="nl">container-name</span><span class="p">:</span> <span class="n">card</span><span class="p">;</span>
<span class="p">}</span>

<span class="c">/* 2. 根据容器宽度调整子元素 */</span>
<span class="k">@container</span> <span class="n">card</span> <span class="p">(</span><span class="n">min-width</span><span class="p">:</span> <span class="m">400px</span><span class="p">)</span> <span class="p">{</span>
  <span class="nc">.card</span> <span class="p">{</span>
    <span class="nl">display</span><span class="p">:</span> <span class="nb">grid</span><span class="p">;</span>
    <span class="nl">grid-template-columns</span><span class="p">:</span> <span class="m">1fr</span> <span class="m">2fr</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>注意，这个查询关心的不是浏览器窗口宽度，而是 <code class="language-plaintext highlighter-rouge">.card-wrapper</code> 的宽度。</p>

<h2 id="为什么这是革命性的">为什么这是革命性的</h2>

<p>想象一个 <code class="language-plaintext highlighter-rouge">&lt;UserCard&gt;</code> 组件，它可能出现在：</p>
<ul>
  <li>侧边栏（窄）</li>
  <li>主内容区（宽）</li>
  <li>模态框（中等）</li>
</ul>

<p>用媒体查询，你只能基于整个页面的宽度决定它的布局，
但同一个页面里，同一个组件可能既在侧边栏又在主区域——
这时容器查询才是唯一的解法。</p>

<h2 id="浏览器支持">浏览器支持</h2>

<p>到 2026 年，所有主流浏览器（Chrome、Safari、Firefox、Edge）都已经稳定支持。
可以放心使用了。</p>

<hr />

<p><em>容器查询配合 CSS Grid 的 <code class="language-plaintext highlighter-rouge">auto-fit/auto-fill</code>，几乎可以让你扔掉 99% 的媒体查询。</em></p>]]></content><author><name>Benjamin Taoson</name></author><category term="前端" /><category term="CSS" /><summary type="html"><![CDATA[媒体查询的时代正在过去——容器查询让组件真正实现「响应式」。]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-03-30-css-container-queries.png" /><media:content medium="image" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-03-30-css-container-queries.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="zh"><title type="html">周末骑行去山里</title><link href="https://benjamindaoson.github.io/daoson_website/posts/2026/03/18/weekend-cycling/" rel="alternate" type="text/html" title="周末骑行去山里" /><published>2026-03-18T18:00:00+08:00</published><updated>2026-03-18T18:00:00+08:00</updated><id>https://benjamindaoson.github.io/daoson_website/posts/2026/03/18/weekend-cycling</id><content type="html" xml:base="https://benjamindaoson.github.io/daoson_website/posts/2026/03/18/weekend-cycling/"><![CDATA[<p>周末看天气预报说连续两天晴，于是临时决定骑车去山里。</p>

<p>清晨五点出发，避开城市的车流。一路向北，沿着河道骑行，
空气里有早春的草木气息，自行车链条偶尔吱呀一声，
整个世界安静得只剩下风的声音。</p>

<p>40 公里之后，到了一片半山腰的露营地。</p>

<h2 id="露营装备">露营装备</h2>

<ul>
  <li>单人帐篷（1.2 kg）</li>
  <li>充气垫 + 羽绒睡袋</li>
  <li>小折叠桌、马扎</li>
  <li>摩卡壶 + 小炉子</li>
  <li><strong>一本翻不完的书</strong></li>
</ul>

<p>我带的是 Hannah Arendt 的《人的境况》。说实话，
这本书躺在我书架上三年了，每次想读都被工作打断。</p>

<p>这次终于读完了第一章。</p>

<h2 id="山里的下午">山里的下午</h2>

<p>下午没什么事，就煮了一壶咖啡，
坐在小马扎上看着远处的山。</p>

<blockquote>
  <p>「Action, the only activity that goes on directly between men without the intermediary of things or matter, corresponds to the human condition of plurality.」</p>
</blockquote>

<p>读累了就抬头看看天。</p>

<p>第二天早上回来的时候，腿肌酸痛，
但脑子从未如此清晰过。</p>

<hr />

<p><em>我们需要离开屏幕的时间，比想象中更多。</em></p>]]></content><author><name>Benjamin Taoson</name></author><category term="随笔" /><category term="生活" /><summary type="html"><![CDATA[逃离屏幕，骑了 40 公里到山里露营。山风、咖啡、和一本翻不完的书。]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-03-18-weekend-cycling.png" /><media:content medium="image" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-03-18-weekend-cycling.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="zh"><title type="html">工程实践中，为什么保持简单这么难</title><link href="https://benjamindaoson.github.io/daoson_website/posts/2026/02/22/three-years-of-work/" rel="alternate" type="text/html" title="工程实践中，为什么保持简单这么难" /><published>2026-02-22T22:00:00+08:00</published><updated>2026-02-22T22:00:00+08:00</updated><id>https://benjamindaoson.github.io/daoson_website/posts/2026/02/22/three-years-of-work</id><content type="html" xml:base="https://benjamindaoson.github.io/daoson_website/posts/2026/02/22/three-years-of-work/"><![CDATA[<p>工程实践中，我反复遇到一个问题：
<strong>「保持简单」比想象中难得多</strong>。</p>

<h2 id="简单不是少做">简单不是少做</h2>

<p>刚入行的时候，我以为简单就是「代码少」。所以我会用一堆三元表达式、
箭头函数、链式调用，把十行代码压缩成一行。</p>

<p>后来才明白，简单不是「字符少」，而是「概念少」。</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="c1">// 字符少，但概念多</span>
<span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">items</span><span class="p">.</span><span class="nf">reduce</span><span class="p">((</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">a</span><span class="p">.</span><span class="nf">set</span><span class="p">(</span><span class="nx">b</span><span class="p">.</span><span class="nx">k</span><span class="p">,</span> <span class="p">(</span><span class="nx">a</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="nx">b</span><span class="p">.</span><span class="nx">k</span><span class="p">)</span> <span class="o">||</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">),</span> <span class="k">new</span> <span class="nc">Map</span><span class="p">());</span>

<span class="c1">// 字符多，但每一步都清楚</span>
<span class="kd">const</span> <span class="nx">counts</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Map</span><span class="p">();</span>
<span class="k">for </span><span class="p">(</span><span class="kd">const</span> <span class="nx">item</span> <span class="k">of</span> <span class="nx">items</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">current</span> <span class="o">=</span> <span class="nx">counts</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="nx">item</span><span class="p">.</span><span class="nx">k</span><span class="p">)</span> <span class="o">||</span> <span class="mi">0</span><span class="p">;</span>
  <span class="nx">counts</span><span class="p">.</span><span class="nf">set</span><span class="p">(</span><span class="nx">item</span><span class="p">.</span><span class="nx">k</span><span class="p">,</span> <span class="nx">current</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>后者多了几行，但读的时候不需要”解码”，反而更”简单”。</p>

<h2 id="简单的本质是克制">简单的本质是「克制」</h2>

<p>写代码时，一个值得反复练习的能力，
是判断「<strong>不做某些事</strong>」：</p>

<ul>
  <li>不做过度抽象</li>
  <li>不做超前设计</li>
  <li>不引入用不上的依赖</li>
  <li>不为了优雅而牺牲清晰</li>
  <li>不在还没需求时就准备好「扩展点」</li>
</ul>

<p>每一次克制都需要勇气，因为它意味着——
当未来真的有需求时，可能要返工。</p>

<p>但十次假想的扩展性需求中，真正发生的可能只有一两次。
为这一两次提前付出的”复杂度税”，往往得不偿失。</p>

<h2 id="小结">小结</h2>

<p>简单 = 克制 + 清晰 + 谦逊。</p>

<p>谦逊指的是：承认你不知道未来会怎么变。</p>]]></content><author><name>Benjamin Taoson</name></author><category term="编程" /><category term="思考" /><summary type="html"><![CDATA[不是某种语言或者框架——而是「保持简单」这件事比想象中难得多。]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-02-22-three-years-of-work.png" /><media:content medium="image" url="https://benjamindaoson.github.io/daoson_website/assets/og-cards-png/2026-02-22-three-years-of-work.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>