手机端不是缩小的桌面端:它只做三件事——收通知、看结论、发新任务。 值守要成立,三个前提得同时满足:叫得醒、看得懂、回得去。 它是桥,不是主力:把「跑完了」送到你眼前,不替你判断该不该合。
这一节短,因为结论也短:手机上不该干重活。 但短不等于可以跳过。 任务从「你盯着它跑」变成「它自己跑完通知你」,中间隔着的就是这个入口。 这个转变比它看起来重要——它把「你必须坐在电脑前」这件事取消了。 Demo 里三条推送消息,两条卡在前提上:一条太长,锁屏只剩半句;一条没有 commit,回不去。
一、手机上能干什么、不能干什么
判断依据只有一条:六寸屏加一根手指。所有「能」和「不能」都是这一条的推论。
| 事 | 手机上能做 | 为什么 |
|---|---|---|
| 看它跑完没有 | 能 | 一条消息就够 |
| 判断结果好不好 | 能,但要有人写结论 | 结论得脚本给,不是你看 diff |
| 叫它改一版 | 能 | 再发一条任务单 |
| 看完整 diff | 不能 | 六寸屏看不了两百行 |
| 处理冲突 | 不能 | 得在编辑器里看三方合并 |
| 决定要不要合 | 不能,只能延后 | 该在电脑上先跑一遍测试 |
「判断结果好不好」那一格要读两遍。 「能,但要有人写结论」——这个「人」其实是脚本。 结论必须由跑测试的那一步生成,不能指望你在手机上读 diff 自己判断。 所以手机能不能用,取决于你的任务有没有「自动结论」这一步。 没有它,手机只能告诉你「跑完了」,而「跑完了」离「做对了」还有一段。
二、值守场景的三个前提
值守这个词的意思是:你不看着它,但你能随时接管。 它要成立,三个前提缺一不可。
| 前提 | 具体是什么 | 缺了会怎样 |
|---|---|---|
| 叫得醒 | 通知通道通,锁屏可见 | 跑完了你也不知道 |
| 看得懂 | 结论由脚本给,一句话说清 | 知道跑完了,不知道对不对 |
| 回得去 | 有 commit 才能回滚 | 知道不对,但收不了场 |
三条里最容易漏的是第三条,而且漏在最不起眼的地方:超时的任务。 Demo 里那条超时的没有 commit,因为它根本没跑完。 可它可能已经改了一半——改了一半又没有 sha,你连回哪儿都不知道。 正确做法是把「记 sha」放在开跑之前,不是放在提交之后。 不管成不成,那个 sha 都在。 这是流程问题,不是工具问题——任何任务单系统都该这么设计。
三、它是桥,不是主力
桥的职责是转达,不是决策。 手机把「跑完了」这件事送到你眼前,这一件事它做得很好。 但「合进去」这个动作不该在手机上做。 理由很实在:那一刻你没跑测试、没看完整 diff、没看别人的评论。 三样都没看就合,等于闭眼签字。 一个可操作的分工: 手机上只做两个决定——「继续等」和「叫它改」。 「合进去」永远留到电脑前,哪怕只隔十分钟。 顺带说一句「生态桥接层」这个说法。 手机端常常还兼一个职责:把别的系统的消息接进来——工单系统、群消息、监控告警。 它是个入口,不是个平台。
四、动手 Demo:值守:三条推送消息,卡在三个前提上
这个 Demo 真跑一个值守脚本:三个任务的结果写成三个 JSON 文件,脚本扫目录、拼消息、 再逐条检查三个前提。 消息是真拼的,宽度是真量的(中文算两个字符宽),锁屏一行按四十个字符宽估算。
for f in sorted(os.listdir(os.path.join(base, u"jobs"))):
j = json.load(fh)
mm, ss = j[u"秒"] // 60, j[u"秒"] % 60
m = u"%s %s · %d 分 %02d 秒 · 回滚 %s | %s" % (
icon[j[u"状态"]], j[u"标题"], mm, ss,
j[u"commit"] or u"无", j[u"结论"])
fit = [p for p in prefix if U.w(p) <= 40] # 锁屏放得下几条
has = sum(1 for j in jobs if j[u"commit"]) # 回得去几条
实跑输出:
--------------------------------------------------------------------
值守:三条推送消息,卡在三个前提上
--------------------------------------------------------------------
① 三个任务跑完了,谁来告诉你
--------------------------------------------------------------------
值守脚本每十秒扫一遍 jobs 目录,把结果拼成一条消息:
[完成] 改 calc 的除零 · 2 分 14 秒 · 回滚 c1a2f3d | check.py 通过 4 / 失败 0
[失败] 补 add 的测试并让它覆盖负数 · 1 分 03 秒 · 回滚 9f2b7e1 | check.py 通过 1 / 失败 3
[超时] 通读 payment 模块 · 10 分 00 秒 · 回滚 无 | 十分钟未出结果
② 三个前提,一条一条查
--------------------------------------------------------------------
[过] 前提一 能被叫醒 通知通道 1 个,锁屏可见
[完成] 改 calc 的除零 · 2 分 14 秒 锁屏一行放得下
[失败] 补 add 的测试并让它覆盖负数 · 1 分 03 秒 宽 47,放不下
[超时] 通读 payment 模块 · 10 分 00 秒 锁屏一行放得下
[不过] 前提二 一眼能判断 2/3 条在四十宽以内
[不过] 前提三 一键能回滚 2/3 条带 commit
前提二挂一条:任务名一长,锁屏就只剩半句。前提三挂一条:超时那个根本没产出 commit,回不了。
! 两条都是值守最容易漏的地方。第一条靠写标题时手短一点;
第二条得改流程——跑失败的任务也要能回滚,因为它可能已经改了一半。
做法是开跑之前先记一个 sha,不管成不成,那个 sha 都在。
③ 手机能干什么,不能干什么
--------------------------------------------------------------------
| 事 | 手机上能做 | 为什么 |
|---|---|---|
| 看它跑完没有 | 能 | 一条消息就够 |
| 判断结果好不好 | 能,但要有人写结论 | 结论得由脚本给,不是你看 diff |
| 叫它改一版 | 能 | 再发一条任务单 |
| 看完整 diff | 不能 | 六寸屏看不了两百行 |
| 处理冲突 | 不能 | 得在编辑器里看三方合并 |
| 决定要不要合 | 不能,只能延后 | 该在电脑上先跑一遍测试 |
! 手机是桥,不是主力。它负责把「跑完了」这件事送到你眼前,不负责替你判断该不该合。
最长那条四十七宽,锁屏只剩半句。 这不是文案问题,是「谁写标题」的问题——任务名是你起的,起长了自己受罪。下次写短点。 第三条超时,没有 commit。 这一条暴露的是流程漏洞:sha 记在提交之后,而不是开跑之前。 改法只有一句:开跑先记 sha。 「手机上能判断结果好不好」那一格我写的是「能,但要有人写结论」。 这个「人」是脚本——你的任务里必须有一步生成结论,否则手机只能告诉你「跑完了」。 手机真正省掉的不是时间,是「你必须坐在电脑前等」。 这一点在长任务上价值最大——一个跑四十分钟的活,你可以去开会,回来再看。
30 秒实验
- 找一个你真会跑很久的任务,给它配一条通知。 只写三样:成没成、用了多久、怎么回滚。
- 把通知发到自己手机上,看锁屏能显示多少字。 超出一行的部分,就是你白写的部分。
- 下次跑长任务之前,先
git rev-parse HEAD记下 sha。 不管成不成,这个 sha 都是你的退路。
常见误区
- 「手机能改代码,那就用手机改。」 能改和该改是两件事。 改三行以内可以,改一个函数就不该了——你看不见上下文。
- 「有通知就行了。」
通知只说「跑完了」,不说「跑得对不对」。
结论得有人写,通常是一行
通过 4 / 失败 0。 - 「超时了重跑一次就行。」 它可能已经改了一半。 超时任务同样要能回滚,所以 sha 要记在开跑之前。
自测三问(点开对答案)
1. 值守的三个前提是哪三个?哪个最容易漏? —— **叫得醒、看得懂、回得去。** **最容易漏「回得去」**,而且漏在超时任务上——它没跑完,所以没有 commit。 2. 为什么「跑失败的任务」也需要能回滚? —— **因为它可能已经改了一半。** **失败不等于什么都没发生**,恰恰相反,失败的任务最容易留下半截改动。 3. 手机上为什么不该做「合进去」这个决定? —— **那一刻你没跑测试、没看完整 diff、没看别人的评论。** **三样都没看就合,等于闭眼签字。**下一篇 4.4 讲本地与云端怎么分:三个判据,顺序不能换。
- ☐ (本篇完,下一篇 4.4 哪些任务适合放在本地,哪些任务适合放在云端)