TinyPilot: Month 43

Michael Lynch

TinyPilot:第 43 个月

原文由 Michael Lynch 发布,订阅该博客

一句话总结

我不小心把 TinyPilot 的发布流程攥在了自己手里。

目标完成情况

每个月初,我都会定下本月想完成的目标。以下是完成情况:

发布年度回顾

这篇文章比计划晚了几周才发布,但我对最终的呈现很满意。

文章登上了 Hacker News 热榜第一,这很有意思,但也凸显了谈钱是一把双刃剑。分享具体数字时,读者的兴趣和热情会明显更高,但大多数评论也都只盯着数字讨论。

联系五位博主洽谈 TinyPilot 合作

  • 结果:联系了两位博主
  • 评分:C

梳理 TinyPilot 发布流程文档花的时间比预期多得多,所以能用来联系博主的精力就少了。最后只联系了两位,而且都没有收到回复。

整理 2023 年报税材料

  • 结果:所有报税材料已准备就绪
  • 评分:A

报税总是很枯燥,但今年一切都按计划进行。

TinyPilot 数据一览

指标2023 年 12 月2024 年 1 月变化
独立访客6,7007,800+1,100 (+16%)
销售收入$75,198.00$100,008.98+$24,810.98 (+33%)
企业订阅$290.70$290.700
版税$1,792.51$3,313.11+$1,520.60 (+85%)
总收入$77,281.21$103,612.79+$26,331.58 (+34%)
利润$-59,117.41$79,764.14+$138,881.55 (+inf%)

TinyPilot 迎来了历史上收入第二高的月份。除了正常的销售波动,我找不到其他原因。我们平常的月收入一般在 7.5 万至 9.5 万美元之间,这个月算是赶上了波动的高点,几笔大额订单把我们推过了 10 万美元。

利润高得离谱,但这同样是因为在转向代工厂后,原材料费用的支出非常集中、波动很大。好在三个月的平均利润为正,尽管比平时略低一些,我还是很满意的。

我不小心把 TinyPilot 的发布流程攥在了自己手里

刚开始卖 TinyPilot 设备时,我在自己的开发机上没法正确地批量复制 microSD 卡。于是只能一张张手动处理:先把 Linux 刷到 microSD 卡上,再在每台设备上手动运行 TinyPilot 的安装脚本。

从那以后,我对硬件设备的软件发布流程了解得多了很多。我们的发布流程也变得更加成熟:测试更全面、可复现性更好,自动化程度也更高。

我把发布流程都记录在了 TinyPilot 共享的 Notion 工作区里,并且把大部分步骤都交给了团队成员,这样新版本的发布就不会卡在我一个人身上。

至少,我本以为自己已经把大部分流程都记录下来了。

在最近一次发布中,我刻意要求自己不直接参与任何发布步骤,而是让同事完全根据文档来执行。

还没等我请同事开始第一个任务,就意识到有多少流程细节其实还只存在于我脑子里。发布中的每一步确实都写了下来,但却没有一份说明来讲清楚这些步骤是如何串联起来的。

我还发现,流程中的一些任务,比如“更新更新日志”或“撰写发布公告”,远比这几个字看起来要复杂得多。公告里该突出哪些功能?在解释功能时,有哪些不成文的规则,能让我们把事情说清楚又不陷入枯燥的细节?

把流程写下来的好处在于,它迫使我认真审视自己的每一个决定。很多时候,我回顾过去的版本,试图总结规律,却发现自己的决策其实并不一致。还有些时候,虽然做法一直很一致,但当需要解释原因时,才意识到其实有更好的方案。

把整个发布工作交出去,比我自己做要慢,但这是一次很有价值的尝试。它让发布流程不再那么依赖我,也给了我们改进流程的机会,未来也更容易把其中的子环节并行起来。

个人项目

用 Zig 实现字节码解释器

过去几个月我一直在探索 Zig,学习过程中最大的障碍之一就是找到适合用 Zig 做的项目。

我的大多数项目想法都是 Web 应用,这通常会让我选择 Go,因为 Go 本就是为构建 Web 应用而设计的,而 Zig 则被设计为更通用的 C 语言替代品。

过去几个月里,我断断续续在读 Bob Nystrom 的Crafting Interpreters和 Andreas M. Antonopoulos 与 Gavin Wood 合著的Mastering Ethereum。前者演示了如何用 C 实现字节码解释器,后者则介绍了以太坊的核心其实就是一个名为以太坊虚拟机(EVM)的字节码解释器。

我意识到可以把几个兴趣结合起来,用 Zig 来实现一个以太坊虚拟机。于是我启动了一个叫 eth-zvm 的项目。

目前我只实现了大约 2% 的以太坊功能,但解释器已经可以运行真实的以太坊程序并返回结果。

下面是我的解释器运行一个编译成以太坊字节码的简单程序时的输出:

$ echo '600160005260206000f3' | xxd -r -p | zig-out/bin/eth-zvm -v
PUSH1 0x01
  Stack: push 0x1
---
PUSH1 0x00
  Stack: push 0x0
---
MSTORE
  Stack: pop 0x0
  Stack: pop 0x1
  Memory: Writing value=0x1 to memory offset=0
  Memory: 0x00000000000000000000000000000001
---
PUSH1 0x20
  Stack: push 0x20
---
PUSH1 0x00
  Stack: push 0x0
---
RETURN
  Stack: pop 0x0
  Stack: pop 0x20
  Memory: reading size=32 bytes from offset=0
  Return value: 0x0000000000000000000000000000000000000000000000000000000000000001
---
EVM gas used:    18
execution time:  792.395µs
0x0000000000000000000000000000000000000000000000000000000000000001

你可以把我的解释器结果和 evm.codes playground 上的 JavaScript 实现对比一下。

我本来以为凭借 Zig 本身对性能的极致优化,我的解释器能在性能上轻松碾压其他实现,结果发现以太坊官方的 Go 实现其实已经相当快了:

我的以太坊虚拟机实现与官方 Go 版本的性能对比基准测试(数值越低越好)

我的解释器还有很多性能优化的空间没做,我相信只要花些时间减少内存分配,就能超过其他实现。

我不确定会把这个项目做到什么程度,但它已经成为我深入学习 Zig、以太坊和解释器的一种实用方式。这也是一种我很久没做过的、有趣的编程方式,因为我必须对从操作系统读取或分配的每一个字节都精打细算。

收尾

完成了什么?

经验教训

  • 只有当有人真正照着文档把流程走通时,这个流程才算真正被文档化。

下月目标

  • 发布 TinyPilot Pro 2.6.3。
  • 在内部完成 TinyPilot Pro 发布流程的文档化。
  • 完成 2023 年报税。

本文章由 muse-spark-1.2-contributor 进行翻译

评论