TinyPilot:第38个月
原文由 Michael Lynch 于 发布,订阅该博客
一句话总结
我在软件上的投入方向对吗?
第一次来?
你好,我是 Michael。我是一名软件开发者,也是 TinyPilot 的创始人,这是一家独立的计算机硬件公司。我在 2020 年创办了这家公司,目前月营收为 6 万至 8 万美元,团队中还有另外七名成员。
每个月,我都会发布一篇像这样的回顾,分享公司业务和我个人职业发展的近况。
亮点
- 没能成功推行 TinyPilot 许可证的按期订阅。
- 意识到我把 TinyPilot 做得过度可配置了。
- 原本以为自己在 TinyPilot 开发上的投入很失败,但写这篇回顾时才发现,大体上还是走在正轨上的。
目标完成度
每月月初,我都会定下当月想要完成的目标。以下是本月目标的完成情况:
尽快将生产转移给代工厂
- 结果:我及时帮代工厂扫清了障碍,但在提速方面错过了一些机会。
- 评分:B-
每当代工厂需要我的反馈而被卡住时,我都优先做到快速、完整地回应,在这方面我觉得自己做得不错。
但我很晚才意识到,自己本该更主动地推进项目管理。代工厂有自己的项目经理,所以我以为他们会把一切安排妥当,但归根结底,如果进度延误,损失最大的还是我。
比如他们就包装设计或说明书征求意见时,我会很快回复,然后就抛在脑后,直到对方来催才想起。直到临近寄送最终样品时,我才发现自从上次反馈后,我就再也没看过包装和说明书的定稿。结果设计还需要进一步修改,白白耽误了时间。
制定搬离 TinyPilot 本地办公室的详细计划
- 结果:我们现在已经有了按月细化的搬迁计划,明确了目标日期和关键节点。
- 评分:A
计划已经确定,大家对时间安排也达成了共识。
有些设备要卖掉还存在先有鸡还是先有蛋的问题。比如把打印机卖了,我们还怎么打印快递单去卖别的东西?不过最坏的情况,大不了把剩下的东西先搬回我家,再慢慢处理。
测试 TinyPilot 许可证的自动续费方案
- 结果:我评估了几种方案,但没有一个真正好用。
- 评分:B
我原本希望能找到一款 Shopify 应用来实现 TinyPilot Pro 按期订阅的销售,但一个合适的都没找到。详情见下文。
TinyPilot 数据一览
| 指标 | 2023 年 7 月 | 2023 年 8 月 | 变化 |
|---|---|---|---|
| 独立访客 | 7,800 | 6,900 | -900 (-12%) |
| 销售收入 | $79,635.02 | $91,670.46 | +$12,035.44 (+15%) |
| 企业订阅 | $290.70 | $290.70 | 0 |
| 版税 | $3,777.52 | $2,969.62 | -$807.90 (-21%) |
| 总收入 | $83,703.24 | $94,930.78 | +$11,227.54 (+13%) |
| 利润 | $26,359.62 | $28,454.42 | +$2,094.80 (+8%) |
营收和利润总体保持平稳。营收比 7 月略有上升,我认为主要是因为 7 月的大部分时间里我们在亚马逊上的商品排名被下调了。
我在按期订阅上的失败尝试
上个月,我试图寻找方法来评估是否有必要更严格地执行 TinyPilot 的许可证限制。最后我认为性价比最高的方案是为购买许可证提供自动续费选项。
Shopify 本身并不支持按期订阅,所以我不得不去翻遍 50 多款提供该功能的第三方 Shopify 应用。问题在于,几乎所有这些应用都是为实体商品设计的。少数支持数字产品的,又只能在 Shopify 原生商店上使用,而我的商店并非原生搭建的。
题外话:挑选 Shopify 插件的体验糟透了。很少有插件提供公开演示,要了解它们的功能,唯一办法就是把它们装进自己的商店,并授予其访问所有商品和客户数据的权限。我不愿意这么做,所以用了一个没有任何真实客户数据的测试商店,但很多功能在商品数据不全的情况下根本无法正常展示。更烦的是,因为插件获取了我的真实 Shopify 邮箱,我只是在测试商店里装了一小时就删掉的应用,现在却给我发来大量垃圾邮件。
目前摆在我面前的选择有:
- 完全在 Shopify 之外销售自动续费订阅(例如通过 Paddle、LemonSqueezy、Stripe)。
- 将 TinyPilot 的购买流程迁移到 Shopify 原生商店,再重新考虑使用第三方的订阅应用。
方案一需要开发团队搭建大量基础设施来支持站外结算,并确保客服团队在 Shopify 之外依然能访问客户信息。
方案二能让所有流程都留在 Shopify 内,但同样是个大工程。上次我找人询价,对方报价 2 万美元。长远来看我确实想做,因为原生 Shopify 商店还有很多其他好处,但目前实在抽不出精力。
让 TinyPilot 不再过度可配置
TinyPilot 最大的技术债之一就是对 Ansible 的使用。创建 TinyPilot 时,我还不知道如何在 Linux 上分发软件,只会用 Ansible,于是 TinyPilot 的安装程序就是一个极简的 shell 脚本,先启动 Ansible,再由 Ansible 完成大部分安装工作。
久而久之,Ansible 显然不是合适的工具。更隐蔽的错误在于,我把安装程序做得过于可配置了。
在发布 Ansible 角色时,把不同操作系统和硬件架构的差异抽象出来是一种好实践。例如,要把一组文件复制到某个目录,你不会直接写“把所有东西装到 /opt/whatever”。而是会写“把所有东西装到 {{ my_target_dir }}”,然后在 defaults.yml 文件中定义 my_target_dir: /opt/whatever。这样,如果 FreeBSD 系统需要安装到不同位置,就只需在 FreeBSD 上覆写 my_target_dir,让它指向类似 /usr/local/whatever 的路径。
但 TinyPilot 只支持一种操作系统和一种硬件平台:树莓派 4 上的 Debian。
出于习惯,我把路径、名称和各种取值都抽象到了不同的文件里,结果让代码变得更难理解。要搞清楚 Ansible 在实际安装时会如何填充这些变量,往往需要在三个甚至更多文件之间来回跳转。
当然,也确实有用户喜欢这种灵活性,这样他们就能在我们官方不支持的系统上使用 TinyPilot。但这些用户几乎都不是付费客户,我们为这种灵活性付出了不小的成本,却并未服务于真正为 TinyPilot 开发提供资金的客户。
在最新的 TinyPilot 版本中,我们不仅去掉了 Ansible,还取消了网页界面之外的大部分配置选项。至今没有收到任何升级问题的反馈,这强烈表明我们的客户根本不需要这些可配置性。
TinyPilot 开发中的本质工作与偶然工作
在那篇著名的文章《没有银弹》中,Fred Brooks 将软件工作分为“本质性困难”和“偶然性困难”。
本质性困难包括明确需求、设计界面这类工作。即使拥有完美的工具和无限的资源,如果没搞清楚软件该做什么、用户如何与之交互,也无法做出有用的应用。
偶然性困难则是指那些仅仅因为工具本身的局限而不得不去做的事情。例如,在 C 语言中管理内存,如果有自动引用追踪或无限的内存,我们根本不需要关心这件事。
最近我经常结合这篇文章来思考 TinyPilot 的开发工作。我们做的很多事情,感觉都属于偶然性困难。
我把 TinyPilot 上一个冲刺中的任务分成了“本质性困难”(绿色)和“偶然性困难”(红色):

TinyPilot 2.6.1 中的任务,按本质性困难(绿色)与偶然性困难(红色)着色区分
有 9 项任务(24%)属于本质性困难,比如新增或优化功能;而 28 项(76%)属于偶然性困难,比如回归修复、依赖包更新或重构。
我没有按开发工时来精确衡量工作量的方法,但我感觉偶然性困难的任务平均耗时更长。我们可能有多达 90% 的时间都花在了偶然性困难上。
如何减少偶然性困难?
进一步思考这个分类后,我发现它并不完全符合我对 TinyPilot 开发工作的理解。我更关心三个类别,以及希望在每类上投入的大致时间比例:
| 类别 | 理想投入占比 |
|---|---|
| 改进产品 | 70% |
| 自动化与降低复杂度 | 20% |
| 日常维护 | 10% |
问题在于这些比例很难平衡。每一行新增代码都会增加维护成本。一个 5 万行的代码库所需的维护工作量,至少会比 3000 行的库高出一个数量级。
当然,投入 20% 的精力来消除复杂度应该能降低维护成本,但并不总能抵消新功能带来的负担。去年我们增加了对 H.264 视频的支持,为此不得不集成第三方 WebRTC 服务 Janus。WebRTC 极其复杂,仅这一个功能就让我们的维护负担一夜间增加了 20% 到 30%。
进一步思考后,也许这是应用我的 50% 原则的好机会。我们应该把 50% 的时间用于改进产品,然后完成必要的维护工作,剩下的时间再用于自动化和降低复杂度。
用这个视角重新审视上一个版本,我们的情况是:
| 类别 | 任务数 | 占比 |
|---|---|---|
| 改进产品 | 8 | 22% |
| 自动化与降低复杂度 | 26 | 70% |
| 日常维护 | 3 | 8% |

TinyPilot 2.6.1 版本中的任务,按改进产品(绿色)、自动化与降低复杂度(蓝色)和日常维护(红色)着色区分
由于我们大力推进去除 Ansible,工作重心偏向了自动化,但实际上比我想象中更接近理想的比例。
通过这三个类别来看,我觉得自己在开发上的投入方向是对的,毕竟在团队规模不变的情况下,不可能无止境地扩展功能。
总结
完成了哪些工作?
- 发布了 TinyPilot Pro 2.6.1。
- 从 TinyPilot 的安装流程中移除了 Ansible,大幅提升了性能并降低了复杂度。
- 发布了 “Aardvark’d:18 年后的 Fog Creek 纪录片”。
经验教训
- 不能永远不停地开发新功能。
- 随着软件项目逐渐成熟,要么增加开发人员来应对额外的维护工作,要么将重心更多地转向简化。
- 可配置性会带来隐性的维护成本。
- 项目中的每一个配置选项都会让行为更难理解,并增加改动的成本。只保留真正需要的可配置选项。
- 不要想当然地认为项目经理一定会把项目管好。
- 因为代工厂有自己的项目经理,我就不再操心生产转移的项目管理。回过头看,我本该更积极地跟进待办事项。
下月目标
这有点取巧,因为这篇回顾写得比较晚,所以实际上是未来一周的目标。
- 尽快将生产转移给代工厂。
- 分配清理 TinyPilot 办公室的相关任务。
- 用完所有剩余的树莓派来组装 TinyPilot 设备。
随机一篇博客
评论
登录后参与讨论