Compare commits

..
10 Commits
32 changed files with 308 additions and 1702 deletions
+1 -1
View File
@@ -61,7 +61,7 @@ nav a:first-of-type img {
--hx-color-dark: #000; --hx-color-dark: #000;
--hextra-max-page-width: 76rem; --hextra-max-page-width: 76rem;
--hextra-max-content-width: 76rem; --hextra-max-content-width: 76rem;
--hextra-max-navbar-width: 58rem; --hextra-max-navbar-width: 57rem;
--hextra-max-footer-width: 57rem; --hextra-max-footer-width: 57rem;
} }
+1 -1
View File
@@ -11,5 +11,5 @@ layout: hextra-home
{{< /hextra-hero-headline >}} {{< /hextra-hero-headline >}}
{{< hextra-hero-subtitle >}} {{< hextra-hero-subtitle >}}
一周更新两次,让脑袋泡泡冰浴 不忙就更新,忙就不更新。
{{< /hextra-hero-subtitle >}} {{< /hextra-hero-subtitle >}}
+5 -11
View File
@@ -9,21 +9,15 @@ poet: |
我是傅堃。 我是傅堃。
央企TL,个人开发者,新晋奶爸。当然大部分时间精力还是贡献给了体制内的职业发展,干过IT运维智能化、营业计费系统建设、大规模IT资源池安全能力建设、企业身份账号权限治理,挺有意思的。 上班族,平时写写代码,带带娃。工作这些年干过营业系统建设、运维自动化、安全系统、身份治理之类的事情,踩的坑挺多。
这个站点主要讨论的不是道与术,是本应凌驾于身份角色之上的**自我**。总觉得人其实很难承认自己被所谓靠自己努力成为的身份角色定义,从出生起人的单一身份很难未维持超过5年,情绪有所触动时与五岁时其实没多大区别。 这个网站没什么宏大主题,就是记录一些折腾过的技术、翻过的书、和偶尔冒出来的想法。如果你也在日常的琐碎里给自己留了一小块空间,这里或许能找到点共鸣。
如果你也想在日常的繁杂中找一个属于自我的空间,挑战落地一些奇思妙想,或是研究一些稀奇古怪,这里的文章会给你启发。 公司规定不接商务合作。
由于公司管理制度,我不可以参与盈利项目,所以无法接洽商务合作。
Hey, I'm FuKun. Hey, I'm FuKun.
Solo developer. Ex-product manager. China state-owned enterprise manager. New dad. Most of my waking hours go to my career — I've done IT operations automation at scale, built billing systems handling massive transaction volumes, architected security for enormous resource pools, and untangled enterprise identity governance. It's been fun. I work in tech management at a state-owned enterprise. I code on the side and raise a kid. Over the years I've bounced around ops automation, billing systems, security architecture, identity governance — nothing too fancy, just enough to learn what not to do.
This site isn't about methodology or technique. It's about the **self** that should sit above all the roles we play. I think people struggle to admit how much their identity gets defined by their roles — and yet, no identity you've held has lasted more than five years since birth. When emotions hit, you still react the same way you did at five. This site has no grand agenda. It's where I stash things I've tinkered with, books I've read, and thoughts that surfaced between meetings. If you've carved out a corner of your own amid the noise, maybe you'll find something here.
If you're trying to carve out space for your own self amid the chaos — chasing down a wild idea, researching something obscure, building something that's just yours — the writing here might spark something.
A note on logistics: due to company policy, I can't participate in for-profit projects, so I don't take on business collaborations.
-50
View File
@@ -1,50 +0,0 @@
---
title: "从 5G 到算力网络:通信行业的技术演进观察"
date: 2026-05-12T23:00:00+08:00
draft: false
poet: |
沉舟侧畔千帆过,
病树前头万木春。
——刘禹锡,中国,772–842
description: "5G 商用五年,哪些超出预期,哪些没达预期。以及下一个五年通信行业的关键方向:云网融合、通感算一体化、AI 原生网络和低空经济。运营商面临的结构性挑战和机会。"
tags:
- 通信
- 5G
- 行业观察
---
入行通信这些年,看着技术代际更迭,有些感触想记下来。
## 5G 的这五年
5G 商用五年,回头看当初的 hype 和现实之间的差距很有意思:
**超预期**的部分:
- 网络能力和覆盖远超 4G
- 行业应用从概念走到落地
- 切片、边缘计算等特性开始产生价值
**没达到预期的部分**:
- C 端杀手级应用迟迟未出现
- 资费下降快,增量不增收
- 数字化转型需求 vs 实际付费意愿之间的鸿沟
## 下一个五年:算力网络
行业现在提的更多的是「算力网络」—— 把通信网络和计算资源统一调度。
几个值得关注的方向:
1. **云网融合** — 网络即服务,算力即服务
2. **通感算一体化** — 通信、感知、计算在基站层面融合
3. **AI 原生网络** — 用 AI 管网络,从辅助运维到自动运维
4. **低空经济** — 无人机、飞行汽车对网络覆盖的新需求
## 运营商面临的挑战
- 传统语音+流量模式见顶
- 云业务面临互联网厂商竞争
- 组织流程迭代跟不上技术迭代速度
- 人才结构转型压力大
不过换个角度看,通信基础设施作为数字经济的「水电煤」,长期价值不会消失,只是价值形态在变。关键是找到自己在价值链中的新位置。
+25 -80
View File
@@ -1,116 +1,61 @@
--- ---
title: "善假说" title: "养虾试玩报告"
date: 2026-05-16T01:30:00+08:00 date: 2026-05-16T01:30:00+08:00
draft: false draft: false
poet: | poet: |
君子生非异也, 君子生非异也,
善假于物也。 善假于物也。
——《荀子·劝学》 ——《荀子·劝学》
description: "近以AI智能体为幕僚,五日亲历,颇有所得。录之以证荀子之言。" description: "搭了个 AI 智能体,试了五天,记录一下它能干什么。"
tags: tags:
- AI - AI
- 效率 - 效率
- 杂文
--- ---
{{< figure src="/images/fusheng.jpg" caption="杜堇《伏生授经图》,明,大都会艺术博物馆藏" alt="杜堇《伏生授经图》" >}} {{< figure src="/images/fusheng.jpg" caption="杜堇《伏生授经图》,明,大都会艺术博物馆藏" alt="杜堇《伏生授经图》" >}}
荀子说,君子生非异也,善假于物也。我以前读完也就过了,没细想。 荀子有句话:"君子生非异也,善假于物也。"说白了就是,人和人差别没那么大,关键看你会不会用工具。以前我觉得这话挺对,但也没多想。
AI 这两年用得不少,ChatGPT、Claude、DeepSeek 都试过。问问题、写代码、润文字,确实方便。但模式始终是单向的——它等你问,你问它答,问完结束。 AI 这两年没少用,ChatGPT、Claude、DeepSeek 都试过。问问题、写代码、润文字,确实方便。但模式一直是你问它答,问完就完了。
直到我用上一个能自己干活的智能体。它叫"爪子",跑在腾讯云一台轻量服务器上,4 核 4G,配置不高。搭起来很简单:在服务器上装了一个叫 OpenClaw 的智能体框架,绑好微信,配上 Todoist 和 Git 的 API 密钥,就能远程使唤了。这东西驻扎在服务器上,能直接执行 Shell 命令、读写文件、操作 Git 仓库、浏览网页。从有想法到跑起来,花了半晚上。 直到最近搭了个能自己干活的 AI 智能体,体验不太一样。
## 役物和任人 它叫"爪子",跑在腾讯云一台轻量服务器上,4 核 4G。说起来也是薅羊毛——一百块拿下的,跑着网站、Git 仓库、密码管理一堆服务,性能还绰绰有余。在服务器上装了 OpenClaw,绑好微信、Todoist 和 Git 的 API,就能远程指挥了。这东西驻扎在服务器上,能跑 Shell 命令、读写文件、操作 Git、浏览网页。从有想法到跑起来,花了半个晚上。
同样是 AI,心态不同,用法天差地别。 ## 它和 ChatGPT 的区别在哪
**役物**——问一句答一句,答错了你纠,纠完再问。你是指挥,还得盯着每一步。 以前用 AI:你问一句,它答一句。答错了你纠正,纠完继续问。你得盯着。
**任人**——说清楚方向,交给它去做。做完验收就行,中间过程不必过问。 现在用智能体:说清楚要干什么,剩下的它自己弄。做完告诉你一声。
前者把你绑在操作台前,后者让你从执行中抽身。区别不在技术,在心法。 前者把你绑在屏幕前,后者让你可以走开。区别不在技术,在用它的方式。
## 三件事 ## 试了五天,举三个例子
试了五天,挑三件说说。 ### 搭博客
### 博客 午休时突然想建个站,跟它说了一句。它自己 SSH 上服务器开始干活:装 Hugo、配 Nginx、设 HTTPS、修 404,全自己折腾完。后来换主题换了三次,都是睡前丢一句话,第二天醒来网站已经换好了。
午间忽想建站,交代了一句。它 SSH 上服务器就开始干活。 ### 每天早上的资讯推送
```mermaid 我让它写了个脚本,每天早上 8:30 把国际新闻、科技动态、通信消息编译成简报,推送到微信。
flowchart LR
A[我:建个博客] --> B[SSH 登录服务器]
B --> C[安装 Hugo + Nginx]
C --> D[配置 HTTPS]
D --> E{测试通过?}
E -->|否| F[自修权限问题]
F --> D
E -->|是| G[回复就绪]
```
装 Hugo、配 Nginx、设 HTTPS、修 404 错误,全是它自己弄的。后来主题换了三次——PaperMod、terminal、Hextra——都是半夜一句话的事。第二天醒来网站已经跑在新主题上了。 第三天推送没来。没等我问,它自己查了日志发现 DeepSeek API 响应变慢超时了,自动调长时限重发了。
### 资讯推送 ### 工作对话转待办
每天早上想看国际新闻、科技动态和通信消息。我让它写了个定时脚本,每天 8:30 推送微信。 同事发的聊天截图丢给它,说一句"入待办"。它读图、认人、提取待办事项、写入 Todoist、标优先级和截止日。原来一分钟的事,现在十秒。
```mermaid ## 试着放了更多权限
flowchart LR
A[Cron 8:30] --> B[拉取待办 + 新闻]
B --> C[编译简报]
C --> D[推送微信]
D --> E{成功?}
E -->|失败| F[自查超时]
F --> G[延长时限重发]
G --> D
E -->|成功| H[记入日志]
```
第三天推送没来。没等我问,它已经查了日志,发现 DeepSeek API 响应变慢导致超时,自动调长时限重发了。 一开始不敢给太多权限,只让它看看日志。后来发现它出错能自己修、操作有日志可查、半夜发消息秒回——慢慢就放心了。
### 工单管理 后来给了它邮箱权限,让它每天扫收件箱:找出只发给我没抄送下属的邮件,拆附件、正文转 markdown、写摘要、关联已有资料,归档到本地工作目录。第二天上班打开文件夹,摘要和附件已经摆好了。
工作对话截图丢过去,说一句"入待办"。 ## 最后
```mermaid 有人问这和 ChatGPT 有什么区别。我觉得可以这么理解:ChatGPT 像字典,能查东西但不会替你干活。智能体像秘书,不一定比你懂行,但能替你跑腿。
flowchart LR
A[我:发聊天截图] --> B[读取并提取信息]
B --> C[创建 Todoist 任务]
C --> D[标优先级 + 截止日]
D --> E[回复确认]
```
读图、识人、提取待办、写入 Todoist、标优先级、定截止期。原来要折腾一分钟的事,现在十秒。 投入也不大:薅腾讯云羊毛,一百块拿下 4 核 4G,几套 API 凭证,半晚上就搭好了。
## 信任是试出来的 回头想荀子那句话——"善假于物"。最好的工具不一定是最强的,是能让你少干杂事的。用着用着你会发现,真正要琢磨的不是"怎么问 AI",而是"什么可以交给 AI"。
一开始不放心,只让它看看日志、查查状态。后来发现出错能自愈、操作有日志可查、半夜发消息也能秒回——慢慢就放手了。
**邮件过滤。** 信任更进一步,我给了它 IMAP 权限,让它每天扫收件箱。
```mermaid
flowchart LR
A[每日扫描收件箱] --> B{发给我但<br>没给下属?}
B -->|是| C[建文件夹存档]
C --> D[附件存 / 正文转 md]
D --> E[撰写摘要]
E --> F[关联已有文件信息]
F --> G[入待办跟进]
B -->|否| H[跳过]
```
筛出发给我但没抄送下属的邮件,拆附件、正文转 markdown、写摘要、关联已有资料,分类归档到我本地工作目录的 inbox。第二天上班打开文件夹,摘要和附件已经摆好了。
## 写在最后
有人问:这和 ChatGPT 有什么区别?
我说:**ChatGPT 是字典,这是秘书。** 字典再全,不会替你写材料。秘书不一定比你懂行,但会替你跑腿。
需要什么投入?一台低配云服务器,一套 API 凭证,花半晚上搭环境。门槛不高。
回头看荀子那句话——"善假于物"。最好的工具不是功能最强的,而是能让你从琐事中脱身的。用到某个程度你会发现,真正费脑子的不是"怎么问 AI",而是"什么可以交给 AI"。
这念头一转,效率的瓶颈就从工具变成了自己的想象力。
+268
View File
@@ -0,0 +1,268 @@
---
title: "Vibe-coding工具栈的别样用途"
date: 2026-06-17T22:00:00+08:00
draft: false
description: "分享两个日常使用的 AI 辅助办公场景:如何让 AI 帮助梳理待办事项,以及如何利用 AI 进行数据模型分析。"
poet: |
工欲善其事,
必先利其器。
——《论语》
tags:
- AI
- 效率
- 教程
---
给部门同事做了一次内部分享,讲了两个我在日常办公中高频使用 AI 的场景。两个场景:一是用 AI 管理工作任务,二是用 AI 分析数据模型。都是真实工作场景。
---
## 场景一:培养一个越来越熟悉你工作的助手
### 不只是记待办
一开始我只用它记录待办事项,后来发现它的作用远不止于此——它逐渐变成了一个熟悉我工作的助手。
怎么做到的?不是靠"训练",是靠积累。我的工作任务目录里逐步沉淀了几十个任务文件夹,每个里面都有 AI 协助整理的 README,记录了任务背景、执行思路和产出物的位置。当接到临时取数需求时,它知道参考历史口径。当上级布置多项并行工作时,它能协助理清各条线的推进重点。
它不需要反复解释业务术语和项目背景——因为此前的任务记录中都有上下文。每次新任务启动,它会先在存档中检索相关材料,提示"这个和之前的某次任务有关联,可以借鉴当时的处理方式"。
换句话说,它不是每次从零开始。它是带着你的工作积累在辅助你。
### 具体操作方法
**第一步:建立目录结构。** 规则很简单,每个任务一个文件夹,命名格式为 `日期@任务主题`:
```
Todo/
├── @持续关注/ ← 持续跟进的事项,不归档
├── 20260616@某业务创新方案/ ← 每个任务独立文件夹
├── 20260616@某系统升级改造/
└── 20260617@某数据治理专项/
```
为什么要这样做?几个好处:
- **状态一目了然**:看目录名就知道有哪些活跃任务,不需要打开任何文件
- **上下文自包含**:每个任务的所有内容(需求背景、沟通记录、产出文档)都在同一个文件夹里,不会散落在微信、邮件、本地文件各处
- **历史可追溯**:三个月前处理过的任务,文件夹还在,README 还在,随时可以回顾当时的思路
**第二步:将新任务交给它。** 拿到一个新任务时,不需要自己先想一遍再告诉它。直接交给它即可。例如——
> "年底前请协助排查全年重点工作,逐项对照当前进展,梳理出存在延误风险的事项"
它会自动完成以下步骤:
1. **定位信息源**:先找到重点工作清单(可能是快捷方式指向的 Excel 表格,也可能在某个 Project 目录下)
2. **逐项比对**:读取清单中的每个事项,再逐一检查各任务文件夹中的 README 状态和已有产出物
3. **输出风险清单**:自动生成一份延误风险报告,按优先级列出——哪些尚未启动、哪些推进受阻、哪些已完成但缺少收尾文档
整个过程只需要在看结果时复核确认,不必亲自去翻阅几十个文件夹。
**第三步:日常运转。** 每次接到新任务,操作流程如下:
1. 把任务信息告知 AI(可以口述、粘贴聊天记录、或直接给一个快捷方式)
2. AI 自动创建 `日期@主题` 格式的文件夹,写一份 README 把任务背景、关键信息、初步思路固化下来
3. 看一遍 README,确认理解无误,补充或修正
4. AI 开始执行,过程中产出的分析、方案、报告都放在这个文件夹里
5. 任务完成后,AI 提醒:"这份产出应归档至 Project 目录,那份应归入 Archive 存档,临时文件可删除"
持续使用一段时间后,能发现一个明显的变化:它越来越不需要做背景解释。因为它已阅读过所有的 README、了解项目结构、知道此前同类任务的处理方式。用得越多,它对工作理解越深。
就像一位经验丰富的助手——不需要每次都从头交代。
### 为什么比传统方式好
传统工作方式的问题不在于"记不住",而在于信息的**碎片化**:微信聊两句、邮件发一份、会议上提一嘴、桌面还扔个快捷方式。出一个任务,信息散落在四五个地方,过两周谁都拼不回来。
这个方案的核心就是**强制归集**——所有信息收拢到一个文件夹里,由 AI 协助整理成结构化的 README。从此任何任务只需要看这一个文件,就知道全貌。
### 三个核心原则
1. **一事一夹**:每个任务一个独立文件夹,不混放
2. **文档驱动**:AI 协助整理思路并记录,人确认后执行
3. **自动关联**:由 AI 检索历史相关材料,避免重复劳动
### 前后对比
```
之前:多渠道接收 → 人脑跟进 → 可能遗漏 → 被动应对 → 临时赶工
现在:任何来源 → 告知 AI → 自动建档+记录 → 状态可追溯 → 闭环归档
```
---
## 场景二:让 AI 分析数据模型
### 背景
工作中需要维护一套数据模型文件(.ndm2 格式),共十多个模型,近两千张表。跨模型关联关系复杂,过去需要逐个打开模型文件,查看表结构,手动记录关联关系,一个模块就需要小半天。
.ndm2 文件本质上是 JSON 格式,每个文件内部完整记录了该模型的所有表定义、字段结构、视图定义、注释信息。AI 可以直接读取其完整结构——不需要做任何格式转换。下面按照实际分析流程展开。
### 分析前的准备
第一步不是让 AI 分析,而是让它**了解你有哪些素材**。把数据模型目录的路径告诉它,它会先列一遍目录,确认有几个文件、每个文件多大,做到心中有数。
然后才是分析。
### 第一步:快速摸底——谁大谁小
**对 AI 说:**
> "分析数据模型目录下所有 .ndm2 文件,汇总每个模型包含的表数量和视图数量,按表数降序排列"
AI 编写脚本遍历所有 JSON 文件,提取关键统计指标,几秒输出结果。一眼就能看出:
- **核心模块**:表数最多、视图数也最多的那个,通常是整个系统的数据中枢
- **中量模块**:表数在 100-300 之间,各有独立业务领域
- **轻量模块**:表数只在两位数甚至个位数,通常是配置管理、服务注册等辅助模块
- **特殊模块**:某个模块的视图数特别少(甚至为零),说明它可能是纯数据存储层,业务逻辑在其他地方
有了这个总览,就知道分析的重心该放在哪些模块上。
### 第二步:画架构拓扑图——谁和谁有关
**对 AI 说:**
> "对比所有 .ndm2 文件,找出同名表在多个模型中同时出现的情况。按共享表的数量从高到低排列,列出每对模型之间共享的表名和数量"
AI 逐个比对,输出一张关联关系矩阵。实际案例中会发现几种典型模式:
**模式一:主数据源 + 下游副本。** 比如模块 A 和模块 B 共享了二十多张表(用户主表、资源映射表、角色表、菜单表、密码策略表……)。一看就知道模块 A 是主数据源,模块 B 是其数据副本,用于运营分析或对外接口。
**模式二:基础版 + 多租户版。** 发现模块 C 和模块 D 共享了六十多张表——资产、部署主机、用户、权限、标签……且字段数几乎一致。这说明模块 D 就是模块 C 的多租户部署版本,两者维护同一套核心表结构。
**模式三:基础设施跨模块复用。** 定时调度框架的表在所有模块中完全一致(表名、字段数都相同)。这说明了系统的技术选型,也为后续运维评估提供了信息——比如调度框架升级时要同时关注六个模块。
有了这张拓扑图,以后做数据变更时,事先就能知道改一张表会波及哪些模块。
### 第三步:定位核心表——按字段数排名
**对 AI 说:**
> "找出所有表中字段数量最多的前 20 张表,列出表名、所属模块、字段数和业务注释"
AI 输出结果后,能看到清晰的层级:
```
xxx_performance_data 模块X 298 字段 ← 性能指标宽表,数据分析类
u_user 模块A 140 字段 ← 用户主表,系统最核心实体
u_user_encrypt 模块A 134 字段 ← 加密用户信息(与主表同构)
u_user_his 模块A 134 字段 ← 用户变更历史
u_resource 模块A 127 字段 ← IT 资源主表
u_entry_resource 模块A 118 字段 ← 入口资源
u_res_account 模块A 95 字段 ← 资源-账号映射
u_res_account 模块B 90 字段 ← 同上的运营副本
...
```
从这个排名里能获得很多信息:
- **用户主表 140 字段**:这是整个系统的核心实体,任何对它的变更影响面最大,需要最严格的评审
- **性能宽表 298 字段**:虽然字段最多,但属于数据分析类,业务变更影响相对小,更重要的是关注其查询性能
- **资源-账号映射表在两个模块中出现**:印证了上一步的架构结论——模块 B 是模块 A 的下游副本
- **加密/历史表与主表字段数接近**:说明数据安全策略完善,账号数据有加密存储和历史追溯
### 第四步:按业务语义理解模块职责
**对 AI 说:**
> "分析某核心模块中所有有注释的表,按业务语义分组归纳该模块管理了哪些类型的实体。列出每个实体类型的代表表名和职责说明"
AI 提取所有含注释字段的表,归纳出清晰的业务分类:
| 实体类型 | 代表表 | 职责说明 |
|----------|--------|----------|
| 用户身份 | u_user, u_user_encrypt, u_user_his | 账号全生命周期管理,含加密存储和历史追溯 |
| IT 资源 | u_resource, u_res_account, u_entry_resource | 被管 IT 资源及账号-资源映射 |
| 权限控制 | u_role, u_menu, u_role_menu_rel | RBAC 角色权限模型,菜单功能点定义 |
| 密码策略 | u_pwd_policy, u_history_pwd | 密码复杂度策略与历史密码管理 |
| 审计日志 | u_portal_log, u_oper_log | 用户操作审计追踪,满足合规要求 |
| 机构人员 | u_organization, u_user_group | 组织架构与用户组管理 |
| 定时调度 | 调度框架相关表 | 定时任务配置与管理 |
不需要看一行代码,仅通过表结构和注释就能理解模块管理了七类业务实体,每类的职责边界清晰。这对于接手维护一个新模块、或者给新同事做技术交接,价值巨大。
同样的方法可以应用到其他模块。比如资源管理模块,AI 会归纳出"资产管理、部署管理、权限管理、监控管理"四类实体,告诉你这个模块管的是 IT 基础设施而非用户身份。
### 第五步:逐模块深度拆解
到了这一步,已经知道谁大谁小、谁和谁有关、核心表是哪些。接下来让 AI 逐个模块出详细报告:
**对 AI 说:**
> "针对每个模块,分别列出:1) 其核心业务表(非日志/历史/运维类)的清单及字段数;2) 其关系映射表的数量和主要关联实体;3) 其历史/日志表的数量和审计覆盖范围;4) 对照全局统计,分析该模块在整体架构中的角色"
AI 逐个模块生成分析报告。以实际中最复杂的模块为例:
- 核心业务表 25 张,涵盖用户、资源、权限、密码、审计五条业务线
- 关系映射表 62 张,远超其他模块——因为 RABC 权限模型需要大量的多对多关联(用户↔角色↔菜单、资源↔账号↔权限、组织↔用户……)
- 历史/日志表 128 张,占比最高——系统重度依赖审计追踪
- 运维辅助表 19 张,主要是调度任务
而对比资源管理模块:
- 核心业务表 22 张,聚焦资产管理和部署管理
- 关系映射表仅 14 张,且都是 2-5 字段的轻量关联——说明其数据模型更扁平,权限控制由账号管理模块统一负责
- 运维辅助表 56 张,远超业务表——因为这个模块负责日常运维监控
两个模块一对比,各自的定位就非常清楚了:一个管"人"(身份与权限),一个管"物"(资产与设备)。
### 第六步:变更影响分析
**对 AI 说:**
> "如果需要对某张核心表增加一个字段,列出所有受影响的模块、各自的引用方式(主表/副本/轻量引用)、以及对应的字段数"
AI 交叉检索后,能给出精确的影响范围:
- **模块 A(主表)**:140 字段 —— 变更在此执行
- **模块 B(副本)**:87 字段 —— 持有用户信息运营副本,需同步变更
- **模块 C(轻量引用)**:2 字段 —— 仅存储用户标识,不需要同步
有了这份评估,变更方案一目了然:先改主表,再同步副本,轻量引用模块无需操作。
### 第七步:全局分类统计
**对 AI 说:**
> "按表的命名规则将所有表分类,统计每个模块中各类表的数量和占比"
AI 的分类统计结果告诉我们一个关键事实:
| 分类 | 识别规则 | 大致占比 |
|------|----------|----------|
| 核心业务表 | 业务主实体及扩展 | ~5% |
| 关联映射表 | _rel 等关系表 | ~6% |
| 历史/日志表 | _his/_log/_record 结尾 | ~12% |
| 运维辅助表 | 调度/监控/临时/通知类 | ~9% |
| 其他业务表 | 非以上规则 | ~68% |
真正需要重点关注的业务核心表占比不到 5%。接近 70% 的表属于"其他业务表"——它们是日常业务运行的表,虽然不是实体核心但承载了大量业务逻辑。12% 是历史日志表,说明系统重视审计追溯。
这个分类的最大价值在于:接手一个新模块时,不用从海量表中找重点。先把那 5% 的核心实体表搞懂,再根据业务需求逐步深入。
### 这个分析流程的可复用性
以上七步不是一次性分析。它是一个**可重复的模板**。
当你接手一个新系统、或者现有的系统做了大版本升级后,把数据模型文件重新喂给 AI,跑一遍这七步,就能快速建立对系统数据架构的全局认知。过去需要两三天人工梳理的事情,现在几十分钟就能完成。
---
## 总结
两个场景的底层逻辑一致:**将结构化数据提供给 AI → AI 完成聚合、比对、关联分析 → 人工判断决策。** AI 负责"算",人负责"懂"。
### 工具与门槛
不需要昂贵的企业级产品。日常使用的工具组合:
- **[Zed](https://zed.dev)** — 高性能代码编辑器,内置 AI 面板,支持与多种大模型直接对话
- **[DeepSeek V4](https://chat.deepseek.com)** — 大语言模型,理解力强,支持超长上下文
- **[Reasonix](https://reasonix.ai)** — AI 编码助手,提供文件读写、目录浏览、内容搜索、Shell 执行等工具能力
三者配合:Zed 作为交互界面,DeepSeek 作为推理引擎,Reasonix 作为执行层(操作文件、跑脚本、搜目录)。全部基于现有工具,零额外采购成本。
关键在于思维转换:不把 AI 仅仅当作问答工具,而是作为能帮助翻阅材料、统计数据、整理提纲的工作助手。只需要明确"让它做什么",具体的执行过程由它自行完成。
+2 -2
View File
@@ -1,6 +1,6 @@
--- ---
title: "AI 生产力的唯一落点" title: "AI 生产力现状"
date: 2026-05-17T18:10:00+08:00 date: 2026-02-27T18:10:00+08:00
draft: false draft: false
poet: | poet: |
We are stuck with technology when what we really want is just stuff that works. We are stuck with technology when what we really want is just stuff that works.
-54
View File
@@ -1,54 +0,0 @@
---
title: "2026 年 AI 工具链实用观察"
date: 2026-05-12T21:00:00+08:00
draft: false
poet: |
The mind is its own place, and in itself
Can make a Heaven of Hell, a Hell of Heaven.
— John Milton, UK, 1608–1674
description: "2026 年 AI 工具进入务实阶段。实测 DeepSeek V4 Flash 和 Pro 模型的不同场景表现,Agent 智能体的四个落地方向,以及怎么用更少 token 做更多事。"
tags:
- AI
- 工具
- DeepSeek
---
2026 年的 AI 工具生态可以用一个词形容——**务实**。经过前两年的概念爆发,现在已经进入落地阶段。
## DeepSeek 实测
最近深度体验了 DeepSeek V4 系列模型,几点感受:
### V4-Flash
日常使用首选。响应快、性价比高,适合:
- 代码辅助和 debug
- 文档撰写和润色
- 信息检索和整理
- 日常问答
### V4-Pro
复杂场景下表现出色,适合:
- 长文分析和总结
- 多步推理任务
- 代码架构设计
- 领域专业知识问答
账户余额 ¥74.31,按目前用量够跑一阵子。
## 智能体(Agent)趋势
今年 Agent 是主题词。从单纯对话到能独立执行任务的智能体,有几个方向值得关注:
1. **编码 Agent** — 从写代码到提 PR,全流程自动化
2. **文档 Agent** — 自动生成周报、会议纪要、汇报材料
3. **运维 Agent** — 日志分析、异常告警、故障排查
4. **个人助理 Agent** — 日程管理、信息聚合、任务委派
## 怎么用更划算
- 大部分日常任务用 Flash 就行
- 复杂任务才上 Pro,避免资源浪费
- 善用上下文缓存,减少重复 token 消耗
- 配合工具链(MCP、Function Calling)发挥更大价值
AI 工具的价值不在于它能做什么,而在于你用它做了什么。
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
title: "子弹日记三年记:极简记录的力量" title: "子弹日记三年记:极简记录的力量"
date: 2026-05-12T22:00:00+08:00 date: 2025-10-22T22:00:00+08:00
draft: false draft: false
poet: | poet: |
纸上得来终觉浅, 纸上得来终觉浅,
-101
View File
@@ -1,101 +0,0 @@
---
title: "CI/CD Patterns with GitHub Actions"
date: 2026-05-15T09:00:00+08:00
draft: false
poet: |
大音希声,大象无形。
——老子,中国,约前571–约前471
description: "Build matrices, caching strategies, environment-specific deployments, and reusable workflows. Patterns that scale from solo projects to team repos."
tags:
- CI/CD
- GitHub
- DevOps
---
GitHub Actions is now the default CI for most open-source projects. Build matrices save config lines, caching `node_modules` and Go modules saves minutes per run. Reusable workflows keep things DRY across repos.
## Build Matrices
Don't copy-paste job definitions for different Node versions or OS targets. Use a matrix:
```yaml
jobs:
test:
strategy:
matrix:
node: [18, 20, 22]
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm test
```
This single definition expands to 6 parallel jobs. Add `fail-fast: false` if you want all runs to complete even when one fails — helpful for catching platform-specific bugs in one CI run.
## Smart Caching
Caching is the easiest way to cut CI minutes:
```yaml
- uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
restore-keys: npm-${{ runner.os }}-
```
The `restore-keys` fallback is important: even a partial cache hit saves time. For Go modules, cache `~/go/pkg/mod`. For Docker builds, use BuildKit's registry cache (`--cache-from type=registry`) for layer caching across CI runs.
## Environment-Specific Deployments
Use environments to gate production deploys:
```yaml
deploy-prod:
needs: [test, build]
environment: production
steps:
- run: ./deploy.sh production
```
The `environment: production` lets you set required reviewers, wait timers, and environment-specific secrets in the GitHub UI. No more accidentally deploying to prod from a feature branch.
## Reusable Workflows
When you maintain multiple repos, reusable workflows prevent drift:
```yaml
# .github/workflows/deploy.yml in a shared repo
on:
workflow_call:
inputs:
environment:
required: true
type: string
secrets:
AWS_ROLE:
required: true
```
Call it from any repo:
```yaml
jobs:
deploy:
uses: org/shared-workflows/.github/workflows/deploy.yml@main
with:
environment: staging
secrets:
AWS_ROLE: ${{ secrets.AWS_ROLE }}
```
Update the shared workflow once, and every repo benefits. This pattern scales well for orgs with 10+ services.
## Practical Tips
- Set `timeout-minutes` on every job — the default is 360 minutes, and you don't want a hung test burning your quota.
- Use `concurrency` to cancel redundant runs when pushing to the same PR multiple times.
- Pin action versions to SHA hashes for supply-chain security, not just tags.
-52
View File
@@ -1,52 +0,0 @@
---
title: "数据库索引优化实战"
date: 2026-05-10T16:00:00+08:00
draft: false
poet: |
众里寻他千百度,
蓦然回首,那人却在,灯火阑珊处。
——辛弃疾,中国,1140–1207
description: "慢查询分析、联合索引的最左前缀原则、覆盖索引与回表的性能差异。几个真实 SQL 优化案例,从几秒降到毫秒级。"
tags:
- 数据库
- SQL
- 性能
---
`EXPLAIN` 是 DBA 的眼睛。看 `type` 字段从 `ALL` 变成 `ref` 是最有成就感的事。
## 从慢查询开始
一切优化从定位问题开始。打开 MySQL 的慢查询日志(`slow_query_log`),设置 `long_query_time = 0.1`,跑一段时间后分析。PostgreSQL 用 `pg_stat_statements` 扩展,同样有效。
拿到慢查询,先 `EXPLAIN` 看执行计划。关注几个关键字段:
| 字段 | 含义 | 目标 |
|------|------|------|
| type | 访问类型 | 至少到 range,最好到 ref/const |
| key | 使用的索引 | 不为 NULL |
| rows | 扫描行数 | 越小越好 |
| Extra | 额外信息 | 避免 Using filesort / Using temporary |
## 最左前缀原则
联合索引是最容易出错的地方。假设索引是 `(a, b, c)`:
- `WHERE a = 1` ✅ 用到索引
- `WHERE a = 1 AND b = 2` ✅ 用到索引
- `WHERE b = 2` ❌ 用不到
- `WHERE a = 1 AND c = 3` ⚠️ 只用到了 a 列
排序也受这个规则约束。`ORDER BY a, b` 没问题,`ORDER BY b, c` 就需要额外排序。
## 覆盖索引
如果查询需要的所有列都在索引里,就不需要回表取数据。`Extra` 列显示 `Using index` 就是覆盖索引。对一个高频查询,覆盖索引能减少大量随机 I/O。
代价是索引变大了。不要为了覆盖索引把所有列都塞进索引——算一笔写入性能和存储空间的账。
## 真实案例
某个订单列表查询,原始 SQL 跑了 8 秒。`EXPLAIN` 一看,`type: ALL`,全表扫描 200 万行。加了 `(user_id, created_at)` 联合索引后,`type: ref`,扫描 20 行,耗时 12ms。
**索引不是越多越好**——每个索引都会拖慢写入速度并占用磁盘空间。建索引前问自己:这个查询的执行频率值得一个索引吗?
-80
View File
@@ -1,80 +0,0 @@
---
title: "Go Concurrency Patterns in Practice"
date: 2026-05-15T10:00:00+08:00
draft: false
poet: |
To see a World in a Grain of Sand
And a Heaven in a Wild Flower
— William Blake, UK, 1757–1827
description: "Go concurrency beyond the basics. Worker pools for bounded parallelism, context propagation for cancellation, select loops for channel coordination — three patterns that hold up in production."
tags:
- Go
- Concurrency
- Programming
---
I've been writing Go for a few years now, and concurrency remains one of those topics where textbook knowledge doesn't quite prepare you for production. Here are a few patterns I've found genuinely useful.
## The Worker Pool
The classic. Useful when you need bounded parallelism:
```go
func workerPool(jobs <-chan Job, results chan<- Result, count int) {
var wg sync.WaitGroup
for i := 0; i < count; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for job := range jobs {
results <- process(job)
}
}()
}
wg.Wait()
close(results)
}
```
## Context Propagation
Probably the single most important practice I've adopted: **every long-running goroutine should accept a context**. It makes cancellation and timeout handling explicit rather than an afterthought.
```go
func fetchWithTimeout(ctx context.Context, url string) ([]byte, error) {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return nil, err
}
// ...
}
```
## The Select Loop
When you need to coordinate multiple channels, `select` is your friend. A common pattern:
```go
for {
select {
case msg := <-messages:
handle(msg)
case <-ctx.Done():
return ctx.Err()
case <-ticker.C:
flush()
}
}
```
## Things I Wish I Knew Earlier
1. **Channel ownership** — the goroutine that writes should also close the channel
2. **Buffered channels aren't a fix for deadlocks** — they just push the problem further out
3. **`sync.WaitGroup` copies by value** — pass it by pointer, always
4. **The race detector is free** — `go test -race` should be part of your CI
Concurrency in Go is *easy to write* but *hard to get right*. The compiler won't save you from logical races. That's on us.
-52
View File
@@ -1,52 +0,0 @@
---
title: "家庭网络与 NAS 搭建方案"
date: 2026-05-17T15:00:00+08:00
draft: false
poet: |
此心安处是吾乡。
——苏轼,中国,1037–1101
description: "软路由、Wi-Fi 6 AP、自建 NAS 的硬件选型和软件方案。Plex 媒体服务器 + Syncthing 文件同步 + Tailscale 远程访问,一套低成本高品质的家庭网络实践。"
tags:
- NAS
- 网络
- 硬件
---
折腾家庭网络的终点是克制。和 Linux 桌面美化一样,容易用力过猛。本文记录一套低成本但够用的家庭网络方案。
## 网络拓扑
```
光猫 → 软路由(OpenWrt)→ 交换机
├── Wi-Fi 6 AP ×2
├── NAS(TrueNAS)
└── 有线设备
```
软路由选 J4125 或 N100 这类低功耗 x86,刷 OpenWrt,负责拨号、DHCP、科学上网。AP 选 Wi-Fi 6 的,TP-Link XDR 系列性价比不错,刷 OpenWrt 或者用原厂固件都可以。
两个 AP 组 Mesh,不需要折腾 AC 控制器。家里 120 平米基本无死角覆盖。
## NAS 硬件与系统
旧电脑加几块硬盘就是一台 NAS。电费要算:不要拿老 i7 加独显当 NAS,待机功耗四五十瓦,一个月电费够买半块硬盘。
推荐方案:J4125 或 N100 小板 + 8GB 内存 + 2~4 块 4TB 硬盘组 RAID-Z1。系统选 TrueNAS Scale,基于 Linux,容器和虚拟机支持比 Core 版更好。待机功耗 15W 左右,一年电费不到一百块。
## 软件方案
三个核心应用:
| 软件 | 用途 | 替代方案 |
|------|------|----------|
| **Plex** | 媒体服务器,自动刮削海报和元数据 | Jellyfin(开源免费) |
| **Syncthing** | 文件同步,多设备自动备份照片和文档 | Resilio Sync |
| **Tailscale** | 虚拟局域网,外面也能访问家里的服务 | ZeroTier、WireGuard 裸配 |
Plex 装在 TrueNAS 的 App 里,显卡直通给 Plex 做硬件转码——手机上用较低码率看片时自动转码,画质损失不大。Syncthing 每台设备装一个,照片目录设为"仅发送",电脑上的文档文件夹设为"双向同步"。
Tailscale 是真正的体验质变。不需要公网 IP,不需要端口转发,不需要记 IP 地址。手机、笔记本、NAS 在同一个虚拟局域网里,出门在外访问 Plex 和 NAS 文件就像在家一样。免费版支持最多 100 台设备,个人用完全够。
## 总结
方案的核心思路:**够用即可**。不要想着一步到位,先从旧硬件开始跑起来,哪里不够补哪里。家庭网络的价值在于稳定无声地跑着,不是折腾本身。
-36
View File
@@ -1,36 +0,0 @@
---
title: "Linux 桌面美化指北"
date: 2026-05-11T10:00:00+08:00
draft: false
poet: |
My house, my house, though you are small,
You are a mansion to me after all.
— Robert Herrick, UK, 1591–1674
description: "从默认 Gnome 到一套顺手的桌面环境。GTK 主题、图标包、终端配色、窗口管理器的选择与配置思路。不追求花哨,追求每天盯着看不累。"
tags:
- Linux
- 桌面
- 效率
---
Linux 桌面环境的选择很多,但真正好用的配置往往很简单。本文记录从 Ubuntu 默认桌面开始,逐步调整到一套耐看、高效的配置。
## 主题选择
白天用亮色主题降低反光,晚上切暗色保护眼睛。推荐 **Nord** 和 **Catppuccin** 两套配色——前者冷峻克制,后者柔和温暖,每天盯着看八小时不累。
GTK 主题建议选择维护活跃的项目,避免 Gnome 大版本升级后样式错乱。Qt 应用在 Gnome 下可以用 `qt5ct` 统一风格。
## 字体配置
终端字体一定要等宽且清晰。推荐 **Fira Code** 做编程字体,连字(ligatures)让 `=>`、`!=`、`>=` 这类符号组合更易读。中文字体用 **Noto Sans CJK**,和西文搭配自然。
## 终端与 Shell
终端模拟器推荐 **Alacritty**——GPU 加速,配置文件清晰。配合 zsh + **starship** 提示符,日常使用效率提升不少。Starship 的优势在于跨 shell 兼容,换到 fish 或 nu 不用重新配置。
## 窗口管理
Gnome 默认的三指滑动切换工作区已经很好用。如果追求更极致的键盘操作,可以试试 **Pop Shell** 平铺扩展,或者直接上 **i3/sway**。但对大多数人来说,Gnome 的默认交互已经够用。
关键原则:**不追求花哨,追求每天盯着看不累。**
-63
View File
@@ -1,63 +0,0 @@
---
title: "Hugo 站点中嵌入视频与图片的最佳实践"
date: 2026-05-16T12:00:00+08:00
draft: false
poet: |
一花一世界,
一叶一菩提。
——《华严经》
description: "静态站点不等于只能放文字。B 站视频的自适应嵌入方案、图片懒加载与响应式处理、以及如何在 Hugo 里保持多媒体内容的可维护性。"
---
静态博客常被认为只能承载纯文本,但实际上 Hugo 对多媒体内容的支持相当完整。本文记录本站的视频嵌入和图片排版方案,供有类似需求的读者参考。
## B 站视频嵌入
Hugo 的 `unsafe: true` 配置允许直接插入 `<iframe>`,这让嵌入第三方播放器变得简单。下面是本站文章中使用的 B 站视频嵌入代码:
<div style="position: relative; padding-bottom: 75%; height: 0; overflow: hidden; margin: 1.5rem 0;">
<iframe
src="//player.bilibili.com/player.html?bvid=BV1AWRVB2EAz&page=1&high_quality=1&autoplay=0"
scrolling="no"
border="0"
frameborder="no"
framespacing="0"
allowfullscreen="true"
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;">
</iframe>
</div>
几个关键参数:`high_quality=1` 默认启用高清画质,`autoplay=0` 禁用自动播放(避免对读者造成打扰)。外层容器的 `padding-bottom: 75%` 是 4:3 比例,如果视频是 16:9 改成 `56.25%` 即可。
## 图片排版实践
### 宽幅配图
对于需要烘托氛围的宽幅图片,直接使用 Markdown 默认语法即可,Hugo 会自动处理响应式缩放:
![AI 主题图](/images/ai.jpg)
{{< caption >}}宽幅配图适合放在文章开头,作为视觉呼吸点。{{< /caption >}}
这类图片适合放在文章开头或章节之间作为视觉呼吸点。
### 多图并列
需要对比展示时,可以将图片连续排列。配合 Hugo 的渲染引擎,相邻图片会自动获得合适的间距:
![编程](/images/coding.jpg)
{{< caption >}}编程与思考。{{< /caption >}}
![思考](/images/thinking.jpg)
### 配图居中
适量使用图片比堆砌更能提升阅读体验。一张位置恰当的配图可以给段落之间留出自然的停顿:
![子弹日记](/images/journal.jpg)
{{< caption >}}一张位置恰当的配图,给段落之间留出自然的停顿。{{< /caption >}}
## 多媒体文件的组织
本站将所有图片和字体统一放入 `static/` 目录,引用时使用绝对路径 `/images/xxx.jpg`。这样做的好处是路径清晰、不受页面层级影响,也方便后续迁移到 CDN。
如果你也在用 Hugo 搭建个人站点,多媒体内容的处理原则就一条:**路径统一、格式克制、体积有数**。祝搭建愉快。
-150
View File
@@ -1,150 +0,0 @@
---
title: "Mermaid 图表语法示例"
date: 2026-05-19T10:00:00+08:00
draft: false
description: "Mermaid 官方语法示例合集:流程图、时序图、类图、状态图、甘特图、饼图、Git 图等全部图表示范。"
tags:
- Mermaid
- 图表
- 语法
poet: |
大音希声,大象无形。
——老子,中国,约前571–约前471
---
> 原文:[Mermaid Examples](https://mermaid.js.org/syntax/examples.html)
# Examples
This page contains a collection of examples of diagrams and charts that can be created through mermaid and its myriad applications.
**If you wish to learn how to support mermaid on your webpage, read the [Beginner's Guide](../config/usage.md?id=usage).**
**If you wish to learn about mermaid's syntax, Read the [Diagram Syntax](../syntax/flowchart.md?id=flowcharts-basic-syntax) section.**
## Basic Pie Chart
```mermaid
pie title NETFLIX
"Time spent looking for movie" : 90
"Time spent watching it" : 10
```
```mermaid
pie title What Voldemort doesn't have?
"FRIENDS" : 2
"FAMILY" : 3
"NOSE" : 45
```
## Basic sequence diagram
```mermaid
sequenceDiagram
Alice ->> Bob: Hello Bob, how are you?
Bob-->>John: How about you John?
Bob--x Alice: I am good thanks!
Bob-x John: I am good thanks!
Note right of John: Bob thinks a long<br/>long time, so long<br/>that the text does<br/>not fit on a row.
Bob-->Alice: Checking with John...
Alice->John: Yes... John, how are you?
```
## Basic flowchart
```mermaid
graph LR
A[Square Rect] -- Link text --> B((Circle))
A --> C(Round Rect)
B --> D{Rhombus}
C --> D
```
## SequenceDiagram: Loops, alt and opt
```mermaid
sequenceDiagram
loop Daily query
Alice->>Bob: Hello Bob, how are you?
alt is sick
Bob->>Alice: Not so good :(
else is well
Bob->>Alice: Feeling fresh like a daisy
end
opt Extra response
Bob->>Alice: Thanks for asking
end
end
```
## SequenceDiagram: Message to self in loop
```mermaid
sequenceDiagram
participant Alice
participant Bob
Alice->>John: Hello John, how are you?
loop HealthCheck
John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts<br/>prevail...
John-->>Alice: Great!
John->>Bob: How about you?
Bob-->>John: Jolly good!
```
## Sequence Diagram: Blogging app service communication
```mermaid
sequenceDiagram
participant web as Web Browser
participant blog as Blog Service
participant account as Account Service
participant mail as Mail Service
participant db as Storage
Note over web,db: The user must be logged in to submit blog posts
web->>+account: Logs in using credentials
account->>db: Query stored accounts
db->>account: Respond with query result
alt Credentials not found
account->>web: Invalid credentials
else Credentials found
account->>-web: Successfully logged in
Note over web,db: When the user is authenticated, they can now submit new posts
web->>+blog: Submit new post
blog->>db: Store post data
par Notifications
blog--)mail: Send mail to blog subscribers
blog--)db: Store in-site notifications
and Response
blog-->>-web: Successfully posted
end
end
```
## A commit flow diagram.
```mermaid
gitGraph:
commit "Ashish"
branch newbranch
checkout newbranch
commit id:"1111"
commit tag:"test"
checkout main
commit type: HIGHLIGHT
commit
merge newbranch
commit
branch b2
commit
```
<!--- cspell:ignore Ashish newbranch --->
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
title: "极简主义的实用指南:少即是多" title: "极简主义的实用指南:少即是多"
date: 2026-05-12T17:00:00+08:00 date: 2025-12-05T17:00:00+08:00
draft: false draft: false
description: "极简不等于空无一物。从手机关通知、统一信息入口、减少收藏即学到,到物品的一年法则和精神层面的少承诺、少比较、少内耗,一套可立刻上手的实用方法。" description: "极简不等于空无一物。从手机关通知、统一信息入口、减少收藏即学到,到物品的一年法则和精神层面的少承诺、少比较、少内耗,一套可立刻上手的实用方法。"
poet: "驾驶教练机拉杆起飞的那一刻,宇治城的小溪边被斜阳刺痛双眼的那一刻,在广汕国道上骑自行车听到路旁大爷大喊加油的那一刻,我清楚的感受到我是我自己" poet: "驾驶教练机拉杆起飞的那一刻,宇治城的小溪边被斜阳刺痛双眼的那一刻,在广汕国道上骑自行车听到路旁大爷大喊加油的那一刻,我清楚的感受到我是我自己"
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
title: "用宝可梦解释 Prolog 基础" title: "用宝可梦解释 Prolog 基础"
date: 2026-05-18T13:30:00+08:00 date: 2026-01-18T13:30:00+08:00
draft: false draft: false
description: "通过宝可梦对战系统理解逻辑编程语言 Prolog 的核心概念——事实、规则、查询,以及它为什么比 SQL 和电子表格更灵活。" description: "通过宝可梦对战系统理解逻辑编程语言 Prolog 的核心概念——事实、规则、查询,以及它为什么比 SQL 和电子表格更灵活。"
tags: tags:
-70
View File
@@ -1,70 +0,0 @@
---
title: "Python Async: Beyond the Basics"
date: 2026-05-12T11:00:00+08:00
draft: false
poet: |
They also serve who only stand and wait.
— John Milton, UK, 1608–1674
description: "Understanding the event loop, writing proper async context managers, and avoiding the most common pitfalls with asyncio.gather and cancel scopes."
tags:
- Python
- Async
- Programming
---
Async Python is no longer optional if you're doing any kind of I/O-bound work. Beyond the basics of `async`/`await`, understanding the event loop helps debug elusive issues.
## The Event Loop in Practice
The event loop runs one coroutine at a time, switching at `await` points. This is cooperative multitasking — a coroutine that never awaits blocks everything else. If you have CPU-bound work inside an async function, offload it to a thread pool with `asyncio.to_thread()`.
```python
import asyncio
# Bad: blocks the event loop
async def bad():
result = heavy_computation() # CPU-bound, no await
return result
# Good: offloads to a thread
async def good():
result = await asyncio.to_thread(heavy_computation)
return result
```
## Async Context Managers
Writing proper async context managers is essential for managing connections and locks:
```python
class AsyncConnection:
async def __aenter__(self):
self.conn = await create_connection()
return self.conn
async def __aexit__(self, *args):
await self.conn.close()
```
The `contextlib.asynccontextmanager` decorator makes this even cleaner for simple cases.
## Common Pitfalls with `asyncio.gather`
`gather` runs tasks concurrently, but one failing task doesn't cancel the others by default. If you need all-or-nothing semantics, use `asyncio.TaskGroup` (Python 3.11+):
```python
async with asyncio.TaskGroup() as tg:
t1 = tg.create_task(fetch(url1))
t2 = tg.create_task(fetch(url2))
# Both succeeded, or both were cancelled
```
## Cancel Scopes
Cancellation in asyncio is cooperative: `asyncio.CancelledError` is raised at the next `await`. If your coroutine catches and suppresses it, the task becomes uncancellable — usually a bug. Use `asyncio.shield()` sparingly to protect critical cleanup code.
## Structured Concurrency
The trend across languages (Trio in Python, Kotlin coroutines, Swift concurrency) is toward structured concurrency: every task has a clear parent scope that determines its lifetime. `TaskGroup` is Python's step in this direction. Embrace it over bare `create_task()` calls.
Async Python has matured significantly. Most of the old footguns have been addressed, but the fundamentals — understand the event loop, respect cancellation, and structure your concurrency — remain essential.
-49
View File
@@ -1,49 +0,0 @@
---
title: "2026 上半年阅读清单与推荐"
date: 2026-05-12T16:00:00+08:00
draft: false
poet: |
书卷多情似故人,
晨昏忧乐每相亲。
——于谦,中国,1398–1457
description: "上半年读过值得推荐的几本书。《软件设计的哲学》讲复杂度管理,《深度工作》讲专注力训练,《凤凰项目》用小说讲 DevOps。附我的阅读节奏安排。"
tags:
- 阅读
- 书单
- 推荐
---
上半年读了十几本书,挑几本值得推荐的记一下。
## 技术类
### 《软件设计的哲学》
不是讲设计模式的,而是讲**复杂度管理**。核心观点:软件设计的本质是降低复杂度。写得深入浅出,适合有几年经验想突破瓶颈的开发者。
### 《凤凰项目》
用小说的形式讲 DevOps 转型。IT 运维的日常在书里无比真实,读起来很有代入感。
## 效率类
### 《深度工作》
Cal Newport 的代表作。核心论点:在这个随时被打断的时代,深度专注的能力越来越稀缺,也越来越有价值。
书里给了一些具体的训练方法,比如:
- 安排固定的深度工作时间段
- 社交媒体断舍离
- 用仪式感帮助进入状态
## 人文类
### 《你以为你以为的就是你以为的吗?》
一本有意思的思维训练书,帮助识别日常思考中的逻辑漏洞。适合碎片时间翻几页。
## 阅读习惯
今年调整了阅读方式:
- **早上的时间给深度阅读** — 30 分钟,不碰手机
- **通勤时间给信息类阅读** — RSS、Newsletter、技术文章
- **周末下午给整本书** — 泡杯茶,一次读一两章
读书不求多,读完、消化、能用上,一本顶十本。
-76
View File
@@ -1,76 +0,0 @@
---
title: "REST API Design: Mistakes I've Made So You Don't Have To"
date: 2026-05-13T09:00:00+08:00
draft: false
poet: |
Form follows function.
— Louis Sullivan, US, 1856–1924
description: "Lessons from real-world API design. Why version early, paginate everything, standardize error responses, and add idempotency keys. Plus a practical deprecation strategy with Sunset headers."
tags:
- API
- REST
- Backend
---
I've designed, built, and maintained enough REST APIs to have made most of the classic mistakes. Here's what I wish someone had told me upfront.
## 1. Versioning Early
Don't wait until you need it. Version your API from day one, either in the URL (`/v1/users`) or via the `Accept` header. Retrofitting versioning onto an unversioned API is painful for everyone involved.
My preference: **URL-based versioning**. It's visible, impossible to forget, and trivially cacheable.
## 2. Pagination by Default
Every list endpoint should be paginated. Every. Single. One.
```json
{
"data": [...],
"pagination": {
"cursor": "eyJpZCI6MTIzfQ==",
"has_more": true,
"total": 847
}
}
```
I've moved from offset-based to cursor-based pagination almost everywhere. Cursors handle real-time data changes gracefully and perform better on large datasets.
## 3. Error Responses Should Be Consistent
A predictable error shape means less client-side code:
```json
{
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Account balance too low for this transaction",
"details": {
"required": 29.99,
"available": 12.50
}
}
}
```
Never expose stack traces in production. Never leak internal IDs without intent.
## 4. Idempotency Keys
For any mutating endpoint, support an `Idempotency-Key` header. Your payment team will thank you, and so will your users when a retry doesn't double-charge them.
## 5. Think in Terms of Deprecation
Add a `Deprecation` and `Sunset` header to old endpoints:
```
Deprecation: true
Sunset: Sat, 01 Aug 2026 00:00:00 GMT
```
Give consumers time to migrate, then actually follow through on removal. Keeping deprecated endpoints around "just in case" is technical debt with interest.
---
Good API design is mostly about **empathy for the consumer**. Ask yourself: would *you* enjoy integrating with this?
-99
View File
@@ -1,99 +0,0 @@
---
title: "Rust Error Handling: From unwrap to anyhow"
date: 2026-05-16T13:00:00+08:00
draft: false
poet: |
If you can meet with Triumph and Disaster
And treat those two impostors just the same;
— Rudyard Kipling, UK, 1865–1936
description: "The journey from panic-driven development to proper error types. When to use thiserror for library crates and anyhow for applications."
tags:
- Rust
- Error Handling
- Programming
---
Rust forces you to think about errors. Starting with `unwrap()` everywhere is fine for prototypes, but production code needs proper error types.
## Stage 1: The Unwrap Phase
```rust
let config = read_config().unwrap();
let db = connect(&config).unwrap();
let result = query(&db).unwrap();
```
Every Rust beginner goes through this. It's fine for scripts and prototypes — if something fails, the panic message with a line number is good enough. The problem starts when you need graceful error handling or meaningful error messages for users.
## Stage 2: Box<dyn Error>
The quick upgrade path:
```rust
fn do_thing() -> Result<(), Box<dyn std::error::Error>> {
let config = read_config()?;
let db = connect(&config)?;
query(&db)?;
Ok(())
}
```
The `?` operator works with any error type that implements `From<T>`. `Box<dyn Error>` catches everything. But you lose type information — the caller can't match on specific error variants.
## Stage 3: Proper Error Types with thiserror
For libraries, define explicit error types:
```rust
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AppError {
#[error("configuration error: {0}")]
Config(String),
#[error("database error: {0}")]
Database(#[from] sqlx::Error),
#[error("not found: {0}")]
NotFound(String),
}
```
The `#[from]` attribute auto-implements `From<T>`, so `?` works seamlessly. Callers can match on variants:
```rust
match do_thing().await {
Err(AppError::NotFound(id)) => { /* handle 404 */ }
Err(e) => { /* log and return 500 */ }
Ok(data) => { /* success */ }
}
```
## Stage 4: Application Errors with anyhow
For binaries, `anyhow` provides flexible error handling without the ceremony:
```rust
use anyhow::{Context, Result};
fn main() -> Result<()> {
let config = read_config()
.with_context(|| "failed to read config file")?;
let db = connect(&config)
.context("database connection failed")?;
Ok(())
}
```
`context()` and `with_context()` attach human-readable messages at each fallible step. The error output is a chain of contexts, making debugging straightforward.
## The Ecosystem Split
| Crate | Use Case | Key Feature |
|-------|----------|-------------|
| `thiserror` | Library crates | Derive macro, typed errors |
| `anyhow` | Application binaries | Context chains, easy `?` |
| `eyre` | Applications (alternative) | Colorful error reports, custom hooks |
The ecosystem has settled on this pragmatic split: **thiserror for libraries, anyhow for binaries**. Libraries expose typed errors so callers can react programmatically; applications benefit from rich, human-readable error chains.
Remember: `unwrap()` and `expect()` still have their place — in tests, in examples, and when an invariant violation truly merits a panic. But for production code paths, make errors part of your type signature.
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
title: "从零搭建个人博客:Hugo + PaperMod 实践记录" title: "从零搭建个人博客:Hugo + PaperMod 实践记录"
date: 2026-05-12T20:00:00+08:00 date: 2025-09-08T20:00:00+08:00
draft: false draft: false
poet: | poet: |
千门万户曈曈日, 千门万户曈曈日,
-286
View File
@@ -1,286 +0,0 @@
---
title: "域名折腾记录"
date: 2026-05-21T15:00:00+08:00
draft: false
description: "基于腾讯云的域名申请、工信部 ICP 备案、SSL 证书部署、Nginx HTTPS 配置、公安备案的全流程实操记录。"
tags:
- 教程
- 建站
- Nginx
- HTTPS
poet: |
千门万户曈曈日,
总把新桃换旧符。
——王安石,中国,1021–1086
---
把个人网站从 `http://IP` 变成一个正经的 `https://域名`,中间要走的路比想象中多。这篇文章记录我的实际操作过程,供有同样需求的朋友参考。
## 前提
- 服务器:腾讯云 Lighthouse,Ubuntu 24.04,4 核 4G
- 网站:Hugo 静态博客,Nginx 提供服务
- 域名注册商:腾讯云
## 一、域名申请
**控制台路径**:腾讯云控制台 → 产品 → 域名注册 → 域名注册
在腾讯云域名注册页面搜索想要的域名,`.com` 早就被抢光了,`.net` 还有一些。我选了 `fukun.net`,首年 90 元。
购买后进入 **控制台 → 产品 → 域名注册 → 我的域名**,找到刚买的域名,点击「实名认证」。上传身份证正反面,审核大约半小时到两小时。通过后域名状态变为「正常」。
回到我的域名页面,点击域名进入 **域名管理 → DNS 解析 → 添加记录**:
| 主机记录 | 记录类型 | 记录值 |
|---------|---------|--------|
| @ | A | 62.234.90.54 |
| www | A | 62.234.90.54 |
TTL 默认 600(即 10 分钟)即可。关于 TTL 的设置经验:
- **日常使用**:600 足够。DNS 修改后最迟 10 分钟全球生效,实际通常更快。
- **迁移前夕**:如果计划更换服务器 IP,提前 24 小时把 TTL 降到 60–120,这样迁移时 DNS 切换更快。
- **不要设太短**:TTL 过短(如 10 秒)会增加 DNS 查询量,对个人站点没必要。
- **不要设太长**:TTL 过长(如 86400)会导致修改后一天才能生效,出问题时无法快速切换。
生效很快,几分钟后 `ping fukun.net` 就能看到正确 IP。
## 二、工信部 ICP 备案
这是整个流程里最耗时的环节。根据《互联网信息服务管理办法》,中国大陆境内提供互联网信息服务的网站必须取得 ICP 备案号。
**控制台路径**:腾讯云控制台 → 产品 → 网站备案 → 开始备案
### 操作流程
1. 进入备案系统,选择「首次备案」
2. 填写主体信息(个人姓名、身份证号、详细通信地址)
3. 填写网站信息:
- 网站名称:注意不能包含「中国」「中华」等字样,个人备案也不能用太过商业化的名称(我填了「FuKun 技术笔记」)
- 网站域名:`fukun.net`
- 网站简介:如实描述,不要写「论坛」「商城」等需要前置审批的内容
4. 上传证件照片(身份证正反面、手持身份证照)
5. 进行人脸识别验证(微信扫码完成)
6. 提交初审
### 时间线
| 阶段 | 耗时 | 说明 |
|------|------|------|
| 腾讯云初审 | 1 个工作日 | 审核材料完整性,不合格会退回修改 |
| 提交管局 | 3 个工作日 | 初审通过后提交至通信管理局 |
| 工信部短信核验 | 即时 | 收到短信后 24 小时内点击链接确认 |
| 通信管理局审核 | 10–15 个工作日 | 各地管局速度不同,广东大约 12 天 |
我从提交到拿到备案号大约用了 **12 个工作日**。通过后会在 **控制台 → 网站备案 → 我的备案** 看到备案号和电子证书。
### 关键注意事项
- 备案期间网站**必须关闭**(Nginx 先别配域名,或者返回 403)
- 个人备案不得涉及企业、商品、新闻等内容
- 备案号需要在网站底部展示,链接到 `beian.miit.gov.cn`
- 备案通过后 30 天内需完成公安备案
## 三、SSL 证书申请
备案通过后域名可以解析了,此时网站还是 HTTP。下一步申请 SSL 证书开启 HTTPS。
**控制台路径**:腾讯云控制台 → 产品 → SSL 证书 → 我的证书 → 申请免费证书
我使用的是腾讯云「SSL 单域名证书(一年期)」,TrustAsia DV 品牌,RSA 2048 位加密,SHA256 签名算法。证书覆盖主域名 `fukun.net` 和 `www.fukun.net`。
证书链:`fukun.net` → TrustAsia DV TLS RSA CA 2025 → DigiCert Global Root G2。
### 操作步骤
1. 在 SSL 证书控制台点击「申请免费证书」(或购买对应类型的证书,¥64.6/年)
2. 填写申请信息:
- 证书绑定域名:`fukun.net`
- 选择「自动添加 DNS 验证记录」— 腾讯云会自动添加一条 TXT 记录
3. 提交申请,等待验证通过(通常 1–5 分钟)
4. 验证通过后状态变为「已签发」,点击「下载」
5. 选择「Nginx」格式下载,得到一个 zip 包
解压后得到四个文件:
| 文件 | 用途 |
|------|------|
| `fukun.net.csr` | 证书请求文件,申请时自动生成,部署不需要 |
| `fukun.net.key` | 私钥,Nginx ssl_certificate_key 使用 |
| `fukun.net_bundle.crt` | CRT 格式证书,含中间证书,Nginx 使用 |
| `fukun.net_bundle.pem` | PEM 格式证书,与 CRT 同内容,备用 |
## 四、Nginx SSL 配置
### 上传证书到服务器
```bash
# 将证书文件传到服务器
scp fukun.net.key fukun.net_bundle.crt ubuntu@62.234.90.54:~/
# SSH 登录服务器
ssh ubuntu@62.234.90.54
# 移动到 Nginx SSL 目录并设置权限
sudo mv ~/fukun.net.key ~/fukun.net_bundle.crt /etc/nginx/ssl/
sudo chown root:root /etc/nginx/ssl/fukun.net*
sudo chmod 600 /etc/nginx/ssl/fukun.net.key
```
### Nginx 站点配置
编辑 `/etc/nginx/sites-available/hugo-blog`:
```nginx
# HTTP → HTTPS 重定向
server {
listen 80;
server_name fukun.net www.fukun.net;
return 301 https://$host$request_uri;
}
# HTTPS 站点
server {
listen 443 ssl http2;
server_name fukun.net www.fukun.net;
ssl_certificate /etc/nginx/ssl/fukun.net_bundle.crt;
ssl_certificate_key /etc/nginx/ssl/fukun.net.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
root /home/hugo/hugo-blog/public;
index index.html;
location / {
try_files $uri $uri/ =404;
}
# 静态资源缓存
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|webp)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
```
```bash
# 启用站点
sudo ln -sf /etc/nginx/sites-available/hugo-blog /etc/nginx/sites-enabled/
# 测试配置
sudo nginx -t
# 重载 Nginx
sudo systemctl reload nginx
```
## 五、备案号悬挂
工信部要求备案号须挂在网站首页底部。在 Hugo 的 `hugo.yaml` 配置:
```yaml
params:
footer:
icp: "粤ICP备2026061516号"
```
在布局文件 `layouts/_partials/footer.html` 中渲染:
```go-html-template
{{- with .Site.Params.footer.icp }}
<div class="hx:mt-2 hx:text-xs">
<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener noreferrer">
{{ . }}
</a>
</div>
{{- end }}
```
## 六、公安部网站备案
ICP 备案通过后 30 天内,还需进行公安机关互联网站备案。注意需要先完成主体备案,再完成网站备案,两步都要做。
**网站**:www.beian.gov.cn → 全国公安机关互联网站安全服务平台
**第一步:主体备案**
1. 注册账号并登录
2. 进入「办事大厅」→「开办主体管理」→「新增主体」
3. 填写主体信息(个人姓名、身份证号、地址、联系方式等)
4. 提交审核,通过后可进行网站备案
**第二步:网站备案**
1. 进入「办事大厅」→「新办网站申请」
2. 填写网站信息:网站名称、域名、IP 地址、服务器所在地
3. 选择网络接入服务商:腾讯云
4. 提交审核(约 7–10 个工作日)
5. 审核通过后获取公安备案号,格式为「粤公网安备 XXXXXXX 号」
公安备案号也需要悬挂在网站上(通常放在 ICP 备案号旁边)。
## 七、新增二级域名
网站上线后如需新增二级域名(如 `gallery.fukun.net`),二级域名与主域名共用同一个 ICP 备案号,公安备案同理,不需要重复办理。只需要做好DNS解析、证书申请、Nginx配置。
**DNS 解析**:在域名管理 → DNS 解析中新增 A 记录,主机记录填 `gallery`,指向同一 IP。
**SSL 证书**:单域名证书覆盖不到新二级域名,需要为新二级域名单独申请一张(流程同第三章,约 5 分钟)。
**Nginx 配置**:新增站点文件 `/etc/nginx/sites-available/gallery`:
```nginx
server {
listen 443 ssl http2;
server_name gallery.fukun.net;
ssl_certificate /etc/nginx/ssl/gallery_bundle.crt;
ssl_certificate_key /etc/nginx/ssl/gallery.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
root /home/hugo/blog-site/public;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
# HTTP 跳转 HTTPS
server {
listen 80;
server_name gallery.fukun.net;
return 301 https://$host$request_uri;
}
```
启用并重载:
```bash
sudo ln -sf /etc/nginx/sites-available/gallery /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
| 事项 | 耗时 | 费用 | 控制台路径 |
|------|------|------|-----------|
| 云服务器 | 1 天 | ¥99/月 | 控制台 → Lighthouse |
| 域名注册 | — | ¥90/年 | 控制台 → 域名注册 |
| 实名认证 | — | — | 控制台 → 域名注册 → 我的域名 |
| DNS 解析 | — | — | 域名管理 → DNS 解析 |
| ICP 备案 | 10–15 工作日 | — | 控制台 → 网站备案 |
| SSL 证书 | — | ¥64.6/年 | 控制台 → SSL 证书 → 我的证书 |
| CDN 加速 | — | ¥14/年 | 控制台 → CDN |
| 云硬盘扩容 | — | ¥70 | 控制台 → Lighthouse → 云硬盘 |
| Nginx 配置 | — | — | 无 |
| 公安备案 | 7–10 工作日 | — | beian.gov.cn |
| **合计** | **约 25–33 天** | **¥337.6** | |
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
title: "SSH 隧道实用指南" title: "SSH 隧道实用指南"
date: 2026-05-09T14:00:00+08:00 date: 2025-07-15T14:00:00+08:00
draft: false draft: false
poet: | poet: |
山重水复疑无路, 山重水复疑无路,
-49
View File
@@ -1,49 +0,0 @@
---
title: "Svelte 初体验:不一样的思路"
date: 2026-05-10T09:30:00+08:00
draft: false
poet: |
Do not go gentle into that good night.
Rage, rage against the dying of the light.
— Dylan Thomas, UK, 1914–1953
description: "试用了 Svelte 5 的 runes 语法和 SvelteKit 框架。没有虚拟 DOM,编译时直接把组件转成 DOM 操作代码,打包体积小得惊人。"
tags:
- Svelte
- 前端
- JavaScript
---
用惯了 React 和 Vue,第一次接触 Svelte 的时候确实有种新鲜感。最直观的感受:**代码量少了很多**。
## Runes 语法
Svelte 5 引入了 runes 语法,让响应式声明更显式:
- **`$state`** — 声明响应式变量,替代了之前靠赋值触发响应式的隐式规则。
- **`$derived`** — 衍生值,类似 Vue 的 computed。
- **`$effect`** — 副作用,自动追踪依赖并在变化时执行。
```svelte
<script>
let count = $state(0);
let doubled = $derived(count * 2);
$effect(() => {
console.log(`count is now ${count}`);
});
</script>
```
逻辑清晰,没有 `useEffect` 的依赖数组心智负担。
## 编译时魔法
Svelte 的核心理念:没有虚拟 DOM,编译器在构建时直接把组件转成高效的 DOM 操作代码。打包体积小得惊人,一个简单的组件可能只有几百字节。对移动端场景尤其友好。
## SvelteKit
SvelteKit 是 Svelte 的全栈框架,文件路由设计简洁。约定优于配置——新建一个 `src/routes/about/+page.svelte`,就自动有了 `/about` 路由。内置 SSR、SSG、CSR 多种渲染模式,服务器端数据加载用 `load` 函数,类型安全做得不错。
## 总结
Svelte 适合想要减少样板代码、追求小打包体积的项目。React 和 Vue 的生态更成熟,但 Svelte 的思路值得关注。下一步打算用 SvelteKit 重写个人博客试试看。
-67
View File
@@ -1,67 +0,0 @@
---
title: "Migrating to Tailwind CSS v4"
date: 2026-05-13T08:00:00+08:00
draft: false
poet: |
苟日新,日日新,又日新。
——《礼记·大学》,中国
description: "CSS-first configuration, the new @theme directive, container queries, and what actually changed from v3. A practical migration log."
tags:
- CSS
- Tailwind
- Frontend
---
Tailwind v4 drops the JavaScript config file in favor of CSS-based configuration. The migration is mostly mechanical but there are gotchas with the `@apply` directive and custom variants.
## CSS-First Configuration
The biggest change: `tailwind.config.js` is replaced by CSS. Your design tokens live in the `@theme` directive:
```css
@import "tailwindcss";
@theme {
--color-primary: #2563eb;
--color-primary-dark: #1d4ed8;
--font-sans: "Inter", sans-serif;
--spacing-container: 1280px;
}
```
VSCode IntelliSense still works — the Tailwind CSS extension reads theme values from your stylesheet.
## The Migration Path
1. Install v4: `npm install tailwindcss@next`
2. Run the automatic migration tool: `npx @tailwindcss/upgrade`
3. Manually check `@apply` usages — the tool handles most cases, but deeply nested `@apply` with custom utilities sometimes breaks.
4. Replace `theme.extend` in your old config with `@theme` blocks in CSS.
## New Features Worth Using
### Container Queries
No more media queries for component-level responsiveness. Tailwind v4 ships container query utilities:
```html
<div class="@container">
<div class="grid @lg:grid-cols-2">...</div>
</div>
```
### Dynamic Utility Values
Arbitrary values are simpler: `w-(--sidebar-width)` references a CSS custom property. No more bracket syntax for common cases.
### Native Cascade Layers
Tailwind v4 uses `@layer` to control specificity. Base, components, and utilities are layered in the correct order — `@apply` in component layer no longer risks specificity wars.
## Gotchas
- Custom variants defined in old JS config need to be re-registered via `@variant` in CSS.
- The `important` config option now needs an explicit CSS strategy.
- Some plugins haven't updated yet — check compatibility before migrating production projects.
Overall, the migration took about two hours for a mid-sized project. The CSS-first approach feels more natural, and the build is noticeably faster thanks to the new Oxide engine.
-76
View File
@@ -1,76 +0,0 @@
---
title: "Deploying to AWS ECS with Terraform"
date: 2026-05-14T10:00:00+08:00
draft: false
poet: |
If you have built castles in the air,
your work need not be lost;
that is where they should be.
Now put the foundations under them.
— Henry David Thoreau, US, 1817–1862
description: "Infrastructure as code from scratch: VPC, subnets, security groups, ECR repository, ECS service with Fargate, and an ALB in front. Every resource explained."
tags:
- AWS
- Terraform
- DevOps
---
ECS with Fargate is the sweet spot between managing servers and going full serverless. Terraform makes it reproducible.
## The Stack
Here's what we need to provision:
| Resource | Purpose |
|----------|---------|
| VPC | Isolated network |
| Public & private subnets | Multi-AZ placement |
| Security groups | Network access control |
| ECR repository | Container image storage |
| ECS cluster + service | Run containers |
| ALB + target group | Traffic distribution |
## Security Groups: Getting Them Right
The key is getting the security groups right — one misconfigured rule and your containers can't talk to each other, or worse, your database is exposed to the internet.
```hcl
resource "aws_security_group" "ecs_service" {
name = "ecs-service-sg"
vpc_id = aws_vpc.main.id
ingress {
from_port = 3000
to_port = 3000
protocol = "tcp"
security_groups = [aws_security_group.alb.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
```
The principle: **allow the minimum**. The ALB security group allows inbound from the internet on 80/443. The ECS security group only allows inbound from the ALB. The database security group only allows inbound from ECS.
## Fargate Configuration
Fargate abstracts the EC2 instances. You specify CPU and memory, and AWS handles the rest. For most web services, 0.25 vCPU / 512 MB is a good starting point — scale up based on load testing, not guessing.
## CI/CD Integration
After Terraform creates the infrastructure, your CI pipeline needs to:
1. Build and tag the Docker image
2. Push to ECR
3. Update the ECS service with the new task definition
Use a Terraform backend with state locking — S3 + DynamoDB is the standard approach. Without state locking, two people running `terraform apply` at the same time can corrupt your infrastructure state.
## Cost Notes
Fargate is more expensive per vCPU-hour than raw EC2, but you save the operational cost of patching instances and managing capacity. For small-to-medium workloads, the difference is negligible compared to the engineering time saved.
-47
View File
@@ -1,47 +0,0 @@
---
title: "我的效率工具链 2026"
date: 2026-05-12T18:00:00+08:00
draft: false
poet: |
磨刀不误砍柴工。
——中国谚语,中国
description: "折腾多年终于稳定下来的工具链。子弹日记做规划,Todoist 管任务,DeepSeek V4 当主力 AI,VS Code 写代码。选工具的原则就四个字:够用就好。"
tags:
- 工具
- 效率
- 推荐
---
持续折腾工具多年,今年终于稳定下来。记录一下目前的工具链,给想优化工作流的朋友参考。
## 笔记与知识管理
**子弹日记(纸笔)** — 每日规划和自我对话的核心载体。具体用法之前写过,不再重复。
**Hugo + Hextra** — 个人博客,用于对外输出。纯静态,零维护成本。
**GitHub** — 技术笔记和代码片段的存档。Markdown 文件 + 搜索,比任何笔记软件都好用。
## 任务管理
**Todoist** — 短期任务和提醒工具。优点是快速、跨平台、自然语言识别能力强。「今天要做的事」用它就够了。
## AI 工具
**DeepSeek V4** — 主力 AI 助手。Flash 模型日常用,Pro 模型处理复杂任务。API 接入各种场景。
## 开发相关
- **VS Code** — 主力编辑器
- **Hugo** — 静态博客生成器
- **Nginx** — Web 服务器
- **Git** — 版本控制
## 选工具的原则
1. **够用就好** — 不追求功能最全,追求用得顺手
2. **数据可控** — 优先选能导出、能自托管的方案
3. **学习成本低** — 花在学工具上的时间要能赚回来
4. **跨平台** — 手机和电脑都能用
好工具的标准不是功能多,而是让你忘记工具的存在,专注于事情本身。
-55
View File
@@ -1,55 +0,0 @@
---
title: "Vim Motions That Actually Save Time"
date: 2026-05-14T14:00:00+08:00
draft: false
poet: |
Practice does not make perfect.
Only perfect practice makes perfect.
— Vince Lombardi, US, 1913–1970
description: "Which Vim motions are worth the muscle memory investment? A practical three-tier ranking from non-negotiable (ci, %, dot) to nice-to-have (macros, jump list), based on three years of daily use."
tags:
- Vim
- Productivity
- Editor
---
Everyone tells you to learn Vim, but nobody tells you *which* motions are worth the muscle memory investment. After three years of daily use, here's my honest ranking.
## Tier 1: Non-Negotiable
These pay for themselves within a week:
| Motion | What it does | Why it matters |
|--------|-------------|----------------|
| `ci"` | Change inside quotes | Editing strings, attributes |
| `ci(` / `ci{` | Change inside brackets | Refactoring arguments |
| `%` | Jump to matching bracket | Navigating code blocks |
| `*` / `#` | Search word under cursor | Quick variable tracing |
| `.` | Repeat last change | The single biggest time-saver |
## Tier 2: Worth Practicing
These take a few weeks to internalize but compound:
- `f{char}` / `F{char}` — find character inline. Faster than `h`/`l` spam
- `t{char}` / `T{char}` — find *until* character. Perfect for deleting `until` a comma
- `ctrl+d` / `ctrl+u` — half-page scroll. Keeps your eyes on the same spot
- `zz` — center current line. Eliminates mental reorientation
## Tier 3: Nice to Have
Useful but not essential for daily work:
- `gt` / `gT` — switch tabs
- `ctrl+o` / `ctrl+i` — jump back/forward in the jumplist
- Macros (`q{register}`) — only worth it for repetitive tasks of 10+ iterations
## What I Don't Use
- **Line numbers as targets** (`:42`) — too slow mentally
- **Visual block mode** — I use multi-cursor in VS Code instead
- **`/` search with regex** — I just use `*` and `f` 90% of the time
---
The real productivity gain isn't in any single motion — it's in **not thinking about navigation**. When your fingers just move the cursor without conscious effort, that's when the payoff arrives.
-88
View File
@@ -1,88 +0,0 @@
---
title: "VPS 新手入门:从购买到上线一个网站"
date: 2026-05-12T19:00:00+08:00
draft: false
poet: |
路漫漫其修远兮,
吾将上下而求索。
——屈原,中国,约前340–前278
description: "买了一台云服务器之后怎么让它跑起来。从 SSH 登录、创建普通用户、配置密钥认证、设置 ufw 防火墙到用 Nginx 部署静态网站,一套完整的新手流程。"
tags:
- Linux
- VPS
- 教程
---
买了一台云服务器之后,怎么让它真正跑起来?这篇文章记录基本的 VPS 初始化和安全配置流程。
## 购买后的第一件事
拿到服务器 IP 和 root 密码后:
### 1. SSH 登录
```bash
ssh root@你的服务器IP
```
第一次登录会提示确认主机指纹,输入 `yes` 即可。
### 2. 创建普通用户
root 权限太大,日常操作应该用普通用户:
```bash
adduser 用户名
usermod -aG sudo 用户名
```
### 3. 配置 SSH 密钥登录
```bash
# 在本地机器上生成密钥
ssh-keygen -t ed25519
# 把公钥传到服务器
ssh-copy-id 用户名@服务器IP
```
然后编辑 `/etc/ssh/sshd_config`,关闭密码登录:
```
PasswordAuthentication no
```
### 4. 防火墙配置
用 ufw 简单配置:
```bash
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
```
### 5. 安装必要的软件
```bash
apt update && apt upgrade -y
apt install -y nginx curl wget git
```
## 部署静态网站
最简单的方式是用 Nginx:
1. 把构建好的静态文件放到 `/var/www/html` 或自定义目录
2. 配置 Nginx 站点文件指向该目录
3. 运行 `nginx -t && systemctl reload nginx`
## 安全底线
- 不要用 root 直接操作日常任务
- 关闭 SSH 密码登录
- 定期更新系统包
- 非必要不开放额外端口
服务器就像一间屋子,基础装修做好才能住得安心。
+1 -2
View File
@@ -91,8 +91,7 @@ params:
columns: columns:
- title: FuKun.Net - title: FuKun.Net
desc: | desc: |
央企TL、个人开发者、新晋奶爸。 晴耕雨读 心灯不夜
记录技术与生活,探索自我边界。
- title: 站点 - title: 站点
links: links:
- name: 博客 - name: 博客