TinyPilot: Month 41

Michael Lynch

TinyPilot:第 41 个月

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

一句话总结

次日达配送,能有多难?

初次来访?

嗨,我是 Michael。我是一名软件开发者,也是独立计算机硬件公司 TinyPilot 的创始人。我在 2020 年创办了这家公司,目前月收入为 8 万至 10 万美元,团队共有其他六名成员。

每个月,我都会像这样发布一篇回顾,分享公司和我个人职业发展的近况。

本月亮点

  • 在提供次日达配送选项时遇到了意想不到的困难。
  • 参加了 Handmade Seattle 大会。
  • 尝试了 Zig 语言和一款开源 AI 聊天机器人。

目标完成情况

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

尽快将生产转移至代工厂

  • 结果:转移已全部完成。
  • 评分:A

代工厂现在生产出的 TinyPilot 设备质量与我们自己组装时相当。代工厂现在直接将设备发往我们的第三方物流(3PL)仓库,这也让 TinyPilot 不再必须拥有自己的办公室。

进行五次客户回访

  • 结果:我们联系了三位客户,实际完成的通话为零次
  • 评分:F

这次我没有把这件事放在优先位置。我因参加大会和假期出行耽误了将近两周,客服团队的人手也比平时紧张。我本应多跟进团队、推动这项工作的优先级,因为这对公司的长期可持续发展很重要。

清理 TinyPilot 办公室的所有旧库存和备件

  • 结果:我决定暂停这一进程
  • 评分:N/A

事实证明,房东对我们何时搬离并不苛刻,所以关闭办公室的紧迫性比我预想的要低。而且,不把所有东西直接扔掉就想清空办公室,比我想象的要难。我们有几十种物品,每件价值 1 到 50 美元,但每种通常只有几件。

举个例子,我们有三块二手 Arduino Uno 开发板,每块零售价 28 美元。我们或许能在 eBay 上把三块一共卖 30 美元,但从头到尾处理整个流程大约需要两个小时。算下来,员工工资成本比卖板子赚的钱还多。

我新的计划是,等到临近搬离时,发布一个开放时间,让有需要的人过来免费拿走想要的东西。

TinyPilot 数据一览

指标2023 年 10 月2023 年 11 月变化
独立访客8,7006,400-2,300 (-26%)
销售收入$98,896.81$84,055.05-$14,841.76 (-15%)
企业订阅$290.70$290.700
版税$2,609.84$2,824.46+$214.62 (+8%)
总收入$101,797.35$87,170.21-$14,627.14 (-14%)
利润$69,280.58-$5,407.96-$74,688.54 (-inf%)

利润看起来很吓人,但这只是因为转向代工厂后,我的支出变得更加集中爆发。10 月份我没有任何原材料账单,但 11 月份却有 5.7 万美元的原材料支出。我其实应该把这些记为销售成本,但目前我只是按简单的现金流水来统计。

8 万至 10 万美元是 TinyPilot 正常的月收入区间,我们目前稳稳处于这个范围内。我本可以借黑色星期五/网络星期一的机会促销,但由于正值生产转移,库存偏低,没法降价。

次日达配送,能有多难?

在 TinyPilot 的大部分时间里,我们都没有提供隔夜达或次日达配送。

当我们还在内部履约时,办公室每周六天都有人处理订单,但每天只有一个人值班。我之所以不提供次日达,是因为我知道总会有人生病或休假,导致无法保证一日内处理完毕。

当我们把履约外包给第三方物流仓库(3PL)后,人手不足的问题就消失了。3PL 的人员冗余比我们多得多,所以无论如何,订单都应该能在 1 个工作日内发出。

转向 3PL 意味着我们终于可以提供次日达选项了!

复杂的配送技术栈

在切换到 3PL 后,管理配送选项的逻辑变得更加复杂。我们过去向 TinyPilot 客户展示配送选项的方式是这样的:

  1. 我在 Shopify 中选择要向客户开放哪些配送选项。
  2. 客户在结账时选择一种配送方式。
  3. 我们通过 Shopify 购买与客户选择相匹配的邮资。

在这套体系下,Shopify 端到端地掌控着整个体验,而且做得很好。

我们的 3PL 使用的是一套(不太好用的)仓库管理系统 ShipStation。该工具与我们的 Shopify 商店集成,所以现在整个技术栈变成了这样:

  1. ShipStation 向 3PL 提供其支持的配送选项列表。
  2. 3PL 从该列表中选择愿意向其客户(TinyPilot)提供的配送选项。
  3. Shopify 向 ShipStation 查询双方共同认可的配送选项。
  4. 我再从 Shopify 中挑选要向客户开放的配送选项。
  5. 结账时,ShipStation 会不透明地猜测哪些选项对客户“最合适”,并将配送选项缩减为两到三个。
  6. 客户在结账时选择一种配送方式。
  7. 3PL 通过 ShipStation 或其他供应商购买与客户选择相匹配的邮资。

牵涉方这么多,出错的环节也多,互相推诿的机会也多。

我尝试开通次日达时发现,等配置从 3PL 经 ShipStation 再到 Shopify 最终到我这里时,已经没有任何次日达选项可用了。

经过数月的来回排查,我们把问题锁定在了 ShipStation 身上。他们不显示次日达选项,是因为他们认为次日达和两日达选项“相似”,而两日达总是更便宜,所以他们永远不会展示次日达选项。

没错,你没看错。ShipStation 这家主营业务就是帮你购买包裹邮资的公司,居然不明白为什么有人会愿意选择更贵的次日达,而不是更便宜的两日达。

ShipStation 无法理解为什么有人会选择 USPS Priority Mail Express,而不选更便宜但更慢的非 Express 选项。

ShipStation 的问题太多,我决定在向客户展示配送选项时切回旧的技术栈。现在,我们直接通过 Shopify 向客户展示配送选项和运费,不再向 ShipStation 查询运费。

把 ShipStation 排除在结账流程之外的问题在于,3PL 是按 ShipStation 较高的费率购买邮资,而 Shopify 则是按较低的 Shopify 费率向客户收取运费。因此,客户可能只需支付 30 美元的隔夜运费,但通过 ShipStation 的实际邮资却是 100 美元,这中间 70 美元的差价就得由 TinyPilot 来承担。

不过,这个方案至少让 TinyPilot 能够提供我们想要的配送选项,而不会被 ShipStation 愚蠢地覆盖掉。而且,承担 70 美元的额外运费,也比直接丢掉这笔订单要好。

选择次日达的客户,要求高出 4 倍

大多数情况下,3PL 都能在 1 个工作日内发出我们的订单。偶尔会遇到一些情况,需要两个工作日,极少数情况下则需要三天。我们在网站上宣传的处理时效是最长三天,但客户似乎并不留意这一点。

90% 的情况下,选择普通陆运或两日达的客户即使遇到一天的处理延迟,也不会说什么。

黑色星期五过后的那个周一,UPS 出现了一个奇怪的问题:他们取走的所有包裹都没有更新物流追踪信息。仓库坚称 UPS 已经取件,但 UPS 的追踪系统却什么都没显示。

这次 UPS 追踪故障影响了五位选择次日达的客户。24 小时内,其中两人就发邮件来抱怨延迟。也就是说,40% 的次日达客户提出了投诉,而选择陆运或两日达的客户中只有约 10% 会注意到延迟。

我也能理解。当我自己选择次日达下单时,我也会急着收货,如果商家拖上好几天才发货,我也会很恼火。

这些选择次日达的客户是一把双刃剑。如果他们愿意花五倍于普通陆运的价格来求快,他们很可能是能提升 TinyPilot 销售额的大客户。但我也发现,他们也相当挑剔,会给客服团队带来压力,因为他们对时效的期望远高于普通客户。

我的首届 Handmade 大会

11 月,我参加了在西雅图举办的首届 Handmade 大会。这是一个面向底层软件开发者的独立大会。

以下是我从大会中得到的一些体会。

主流技术栈之外,还有别的选择

大卫·福斯特·华莱士在他著名的 2005 年凯尼恩学院毕业演讲 中讲过一个关于鱼的笑话:

有两条小鱼一起游着,恰好遇到一条迎面游来的老鱼,老鱼向它们点头说道:“早上好,孩子们,水怎么样啊?”两条小鱼继续往前游了一会儿,最后其中一条看了看另一条,说道:“水是什么鬼东西?”

对我来说,浏览器就是水。

我太习惯于把软件想成用户最终通过 HTML 和 JavaScript 来交互的东西,以至于几乎忘了还有其他可能性。距离我上一次认真思考“把一切都围绕上世纪 90 年代为渲染静态文档而创造的技术来设计有多奇怪”已经很久了。

但在 Handmade 大会上,我遇到的大多数开发者根本不碰浏览器,也不用我熟悉的那些技术。

我见到了 MobileCode 的开发者,这是一款可以在手机和平板上写代码的应用。我问他用的什么语言,本以为他会说 Flutter,八成是 React Native,结果他回答“C 语言”时,我大吃一惊。

不仅如此,他还说用 C 语言做移动开发体验不错。相比通过现代框架的重重抽象,他可以直接调用 iOS 和 Android 的原生图形 API。

不懈的独立抱负

我最初听说 Handmade,正是因为关注了 Andreas Kling,也就是 SerenityOS 的创始人。他完全不依赖任何第三方库,单枪匹马从零开始写出了这个操作系统,并在 2021 年的 Handmade 大会上做了分享。

Handmade 大会也经常有关于 Zig 的分享,这门独立编程语言我已经关注一段时间了。Zig 的创始人 Andrew Kelly 在 2021 年做客 CoRecursive 播客 时谈到,他想用 Zig 取代世界上所有的 C 代码。

Adam:当你干掉 C 语言后,世界会是什么样子?

Andrew:哦,那太美好了。世界看起来基本没变,只是你所有的应用都运行得稍微好一点,更少崩溃,占用更少内存,速度更快……

当教科书想要展示操作系统或嵌入式设备是如何工作时,就会理所当然地用 Zig 作为示例代码,因为人人都在用它。

我觉得 Andrew 这种对软件的野心和热情特别酷、特别让人振奋,而这正是我来 Handmade 想寻找的东西。

Handmade 没有让我失望,它确实展现了这种独立野心。大会推崇“重新发明轮子”的做法。

在软件行业,说某人“重新发明轮子”通常是贬义,但在 Handmade,大家却拥抱这种做法。为什么重新发明轮子呢?也许你造的轮子会比大家现在用的更好。哪怕只是尝试去重新发明,你也会对轮子是如何运转的有更深的理解。

Cameron Riekes 还是一名本科生,他分享了自己做一款 2D 角色扮演游戏的经历。但做着做着,他 “顺手”从零写了一个 3D 游戏引擎

Yasser Arguelles 才二十出头,正在做 Tilde,这是一个从零开始重写的 LLVM 替代品。要知道,LLVM 作为编译器后端已经持续开发了 20 年。他在演讲中提到,自己并没有编译器背景,只是在 Handmade 的讨论中看到很多人都在呼吁需要一个 LLVM 的替代方案,于是他想:“行,那我来做吧。”

我还有幸见到了 Andrew Kelly,他人非常友善。这次交流也终于激励我去 尝试写了一些 Zig 代码

对大厂的极度怀疑

我对大会有一个不满,就是那种批判大厂的论调到了我觉得不太理性的程度。

贯穿整个大会的叙事基本上是:大厂就是毒药。他们生产的一切都充满 bug、臃肿、不可靠且定价过高。

按发言者的说法,更多人没有意识到大厂这些缺点的原因,是大厂控制了软件大会,禁止演讲者诚实地谈论大厂软件中的问题。我也参加过几场中等规模的大会,从来没有人告诉我不能批评大厂,所以这种说法在我听来不太可信。

我同情反大厂的观点。只要可能,我也更喜欢独立技术,但我也认为大厂在很多方面做得很好,并且在推动技术前进方面承担了大部分重任。一味地对大厂嗤之以鼻、认定独立技术一定比大厂方案更好,我觉得是一种误判。

相关文章

如果你知道其他相关的总结文章,欢迎告诉我,我会加上链接。

业余项目

WanderJest

WanderJest 是我几年前启动的一个网页应用,旨在帮人们发现身边的现场喜剧演出。我在 疫情来袭时搁置了它,但之后又时不时拿出来捣鼓。

WanderJest 最大的挑战之一是获取演出的相关信息。一场喜剧演出的权威信息通常就是一张这样的海报:

一场本地喜剧演出的海报

演出者不想做好海报后,还要到别处再把信息重新输入一遍,所以我一直在思考如何“免费”从海报中提取信息。

我的第一个想法是做一个帮演出方制作海报的工具。我 捣鼓了几天,但第一个去推销的喜剧演员并不感兴趣。这个想法我还没有完全放弃,但也没有足够热情去继续迭代。

不过,现在 AI 图像识别越来越强,我的另一个想法是直接找到演出的海报,然后用开源 AI 工具抓取其中的演出信息。

当我读到 Simon Willison 关于使用 Llamafile 的文章 时,我意识到现在尝试带图像理解能力的聊天机器人是多么容易,于是就拿海报这个问题试了试。

遗憾的是,LLaVA 1.5 对图像的识别准确率似乎还不足以胜任这项任务。当我给它看一张喜剧演出海报并提问时,它的回答只有约 70% 是准确的:

Llamafile 网页界面的截图,LLaVA 1.5 对我关于海报的提问给出了半准确的回答。它正确识别了一个名字,但对另外两个名字产生了幻觉,给出了变体。

用 Llamafile 让 LLaVA 跑起来很容易,但它在描述喜剧演出海报方面的准确率仍然偏弱。

我胡乱调整了一下参数,但没能改善结果。

尽管如此,看到开源方案在这个领域的进步和竞争,我还是很兴奋。更多细节请见:

总结

完成了什么?

  • 发布了 TinyPilot Pro 2.6.2
  • 参加了 Handmade Seattle 大会
  • 解决了一个关键供应商的发货导出问题

经验教训

  • 提供次日达能吸引愿意多花钱的客户,但这些客户也更挑剔、要求更高。

下月目标

  • 完成 TinyPilot 授权验证的设计工作。
  • 建立对每批新生产设备的抽检流程。
  • 处理 TinyPilot 的年终税务事宜。

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

评论