我公司真有“古法编程”程序员:全栈不用AI,代码全靠手敲
上周,V2EX 上有个帖子火了。标题很直白:《我公司真的有古法编程程序员》。帖主说他建议同事用 AI,同事回了一句“习惯了,AI 也有搞不定的时候”。帖主暗中观察,确认对方真的是在“古法编程”——而且,还是全栈。
评论区一片“膜拜”“上古神兽”“我司也有同款”的呼声。作为一个天天在编辑器里跟 AI 插件打交道的开发者,我第一反应是:这哥们儿是不是在“内卷”?但冷静下来一想,这个现象背后其实藏着很多值得初级开发者深思的东西。
今天,我就以一个实战案例的视角,拆解一下“古法编程”到底是怎么回事,它对新手是毒药还是良药,以及——我们到底应该怎么看待 AI 辅助编程。
一、什么是“古法编程”?——不是不用工具,而是不用“外脑”
先别急着嘲笑。所谓“古法编程”,并不是指还在用纸带打孔、用汇编写 GUI。在 2025 年的语境下,它通常指:
- 不用 AI 代码补全(比如 GitHub Copilot、Cursor、通义灵码)
- 不依赖 Stack Overflow 复制粘贴
- 遇到问题先自己翻文档、读源码、写测试
- 整个开发流程全靠大脑记忆 + 手动敲击
听起来是不是有点“反人类”?但帖子里那位“古法程序员”是全栈,意味着他从前端 React/Vue、后端 Node/Go、数据库 SQL 调优,到 CI/CD 部署,全部自己手写,不借助任何 AI 生成代码。

二、我亲自“复现”了一个古法编程场景:从零手写一个 REST API
为了写这篇文章,我特意关掉了所有 AI 插件,尝试用“古法”写一个简单的用户注册接口。目标:不查 AI,不复制现成代码,只靠大脑和官方文档。
2.1 手动搭建项目结构
没有 create-react-app 或 nest new 的脚手架提示,我手动创建了以下目录:
user-api/
├── src/
│ ├── controllers/
│ ├── models/
│ ├── routes/
│ └── app.js
├── package.json
└── .env
2.2 手写 Express 路由
// src/routes/userRoutes.js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
router.post('/register', userController.register);
module.exports = router;
这段代码很简单,但如果你习惯了 AI 自动补全 router.post(…),你会发现——你其实记不住 require 的路径写法。我写的时候愣了一下:“../controllers/userController 还是 ./controllers/userController?” 这就是古法编程的第一个“副作用”:倒逼你记住文件路径和模块系统。
2.3 手写控制器与模型
// src/controllers/userController.js
const User = require('../models/User');
exports.register = async (req, res) => {
try {
const { username, email, password } = req.body;
// 手动校验逻辑
if (!username || !email || !password) {
return res.status(400).json({ error: 'Missing fields' });
}
const user = new User({ username, email, password });
await user.save();
res.status(201).json({ message: 'User created' });
} catch (err) {
res.status(500).json({ error: err.message });
}
};
看到这里,你可能觉得“这有什么难的?” 但请注意:没有 AI 提示,你写 await user.save() 之前,必须自己记得 User 模型导出了 save 方法,并且记得要加 try/catch。如果在真实项目中,你还要手动处理数据库连接、环境变量、错误码映射——这些全是 AI 最擅长的“样板代码”,但也恰恰是初级开发者最容易忽略的细节。
三、AI 也有搞不定的时候——哪些场景必须“古法”?
帖子里那位老哥说“AI 也有搞不定的时候”,这句话不是凡尔赛。我总结了几个 AI 确实容易翻车的场景:
3.1 遗留系统的“魔法常量”
假设你维护一个 2018 年用 jQuery + PHP 写的后台系统,里面有一个 status 字段,值是 1、2、3,分别代表“待审核”、“已通过”、“已驳回”。但实际业务逻辑里,还有一个隐藏的 4 代表“人工复审”,这个逻辑写在某个 500 行的 switch 语句里。
你问 AI:“请帮我重构这段逻辑。” AI 很可能会给你生成一个漂亮的枚举,然后把 4 当成正常状态处理——但它不会告诉你,这个 4 只在凌晨 3 点的定时任务里才会被触发。这种“隐性知识”,只有手写过那段代码的人才知道。
3.2 极度复杂的边界条件
比如金融系统的“四舍五入”规则。在 JavaScript 里,0.1 + 0.2 !== 0.3 是常识,但 AI 生成的代码往往会直接使用 Number.toFixed(),而忽略了银行家舍入法(四舍六入五成双)。如果你没有手动测试过这些边界,AI 生成的代码上线后就会产生“一分钱误差”。
3.3 安全敏感场景
AI 生成的 SQL 查询经常忘记做参数化查询,直接拼接字符串。虽然你可以在 prompt 里加一句“注意 SQL 注入”,但 AI 在生成复杂 JOIN 语句时,依然可能漏掉 ? 占位符。古法程序员手动写 preparedStatement,虽然慢,但安全。
[配图:抽象的安全与边界意象——一个由半透明几何体构成的迷宫,中心有一个发光的红色节点,周围环绕着无数细小的金色线条,象征着代码中的边界条件和安全漏洞,整体色调为冷蓝色与暖橙色交织]
四、初级开发者该不该学“古法编程”?
我的答案是:应该学,但不用全学。
4.1 你需要“古法”来打地基
如果你刚开始学编程,建议至少手写 100 个 API、50 个前端组件、20 个 SQL 查询。因为只有当你亲手敲过 SELECT * FROM users WHERE id = ?,你才会理解为什么 ORM 框架能帮你解决 N+1 问题;只有当你手动处理过 undefined is not a function 错误,你才会珍惜 TypeScript 的类型检查。
古法编程的核心价值不是“慢”,而是“理解”。
4.2 但不要拒绝 AI 这个“加速器”
效率也是生产力。当你已经理解了基础原理,再用 AI 去生成样板代码、写测试用例、做代码审查,就是合理的外包。比如:
- 用 AI 生成 CRUD 接口的骨架,然后手动填充业务逻辑
- 用 AI 写单元测试,但手动验证边界条件
- 用 AI 解释报错信息,但手动定位根因
4.3 一个折中方案:混合模式
我在团队里推行过一种“3+2”工作法:
- 前 3 分钟:关掉 AI,自己思考问题域,画草图、写伪代码
- 后 2 分钟:打开 AI,用 prompt 验证思路,或者生成基础代码框架
- 最后:手动 review AI 生成的代码,逐行检查
这样既保留了“古法”的深度思考,又享受了 AI 的效率红利。
五、从“古法”到“心法”——真正的程序员素养是什么?
回到 V2EX 那个帖子,底下有个回复很扎心:“他不是古法,他是真的强。” 这句话点出了一个真相:
真正的程序员素养,不是会不会用 AI,而是能不能在没有 AI 的时候依然写出高质量代码。
那些“古法编程”的全栈程序员,他们之所以能坚持不用 AI,是因为:
这些能力,恰恰是初级开发者最缺的。
六、写在最后:AI 是工具,不是大脑
我每天也在用 AI:写周报、生成测试数据、甚至帮我润色这篇文章。但我依然会每周抽一个下午,关掉所有 AI,手写一个小项目——可能是一个命令行工具,也可能是一个简易的博客系统。
不为别的,就为了提醒自己:代码是我写的,不是机器替我写的。
如果你现在还是初级开发者,不妨试试“古法编程”一个月。你会发现,当你不再依赖自动补全时,你对代码的理解会上升一个台阶。等到你重新打开 AI,你会发现——它不再是你的老师,而是你的助手。
最后留个思考题:你身边有“古法编程”的程序员吗?你觉得自己能坚持多久不用 AI 写代码?欢迎在评论区聊聊。



