为什么个人软件仍然这么难做:一位开发者的亲身实践
The Case for Personal Software
一位开发者想为六个朋友做一个只分享照片的私密应用,用 Claude Code 和 agents 尝试后仍未能轻松实现,Replit 生成的东西也要求每个人注册登录。他指出人们说不清自己想要什么,却清楚自己不想要什么,而现有软件都是为所有人构建的。他还把多个 Chrome 扩展串成求职流水线,由 LLM 驱动,但认为 LLM 并非确定性系统。
几年前我离开了社交媒体。严格来说,我还在每个平台上,但我停用了账号、删掉了应用,因为它对我不健康。我的朋友们留了下来。尤其是其中六个,想继续和我分享照片,而在我离开的那些应用之外,没有一个合适的地方可以做这件事。群聊会把照片埋在聊天记录下面,大多数照片根本就没发出来过。它们躺在某个人的相册里,直到我们通电话时有人说‘哦等等,你还没看过这些’,然后它们才被发过来。我们想要的是一个相册,一个所有东西都留在那里的地方。Instagram 有这功能,但它附带了你停不下来的 Reels,还有每一个发来好友请求、期待你同意的熟人。我不想和所有人分享我的生活。
于是我试着自己做一个。一个正好给六个人用的应用。界面也许像 Instagram,但只给我们用。我靠写代码为生,而且我有 Claude Code 和智能体。这本该是一个晚上的事。
但并不是。
把所有东西拼到一起花的时间远超预期。我确实试过 Replit。它做出了点东西。但没办法分享出去让六个人直接打开。他们每个人都得创建账号并登录,而且它不断添加我们谁都不需要的层级。我们只是六个分享照片的朋友。我们不需要那些。就在那时,我开始问:为什么只给你自己用的软件还是这么难拥有。
为所有人而建
不只是我尝试构建的应用。还有我使用的应用。
当我在 Reminders 里添加一个杂货条目时,它会建议把它移到农产品区。我不在乎。我真的不在乎。我不把农产品放在冰箱里。我是为了某次做饭才去买杂货的,我就是这么操作的。我不想要这种没必要的分类。它每次都让我心烦,而每一次我都有同样的想法:这个应用到底知不知道我想从它那里得到什么?它不知道。它是为所有人而建的。
我的一个朋友也讨厌 Reminders。当我问她想要什么替代品时,她说:‘我不知道。’但她确切地知道自己讨厌什么:通知如何作为众多通知中的一条进来,提醒是如何组织的,应用如何把那些她从未要求过的功能强加给她。
我觉得这就是我发现的关键。人们不知道自己想要什么,但他们确切地知道自己不想要什么。这不是技术问题。这是用户体验问题,而在此之前,没人能对此做些什么。你没法为‘我讨厌这种感觉’提交 bug。所以你只能抱怨,然后继续用这个应用,因为唯一的替代品是另一个为其他人而建的应用。现在软件很便宜。你不必为一个你勉强喜欢的提醒应用每月付 10 美元。
你可以做一个你真正喜欢的。
为一个人构建是什么感觉
为一个人构建软件比为所有人构建软件容易得多。你不必担心大公司所面临的种种限制。做出最初的粗糙版本非常容易。然后,当你开始使用这个粗糙版本时,你开始意识到它缺了点什么,又缺了另一点,应用不断演变成比你最初做的要大得多的东西。
这就是重点。一个属于你的应用可以每周都变,因为它唯一需要取悦的人就是你。
这就是我的经历。
流水线
我有一堆 Chrome 扩展,每个只做一件事,而且把那件事做得很好。一个能从我点击的招聘信息向招聘人员发送邮件。一个会打开 LinkedIn,找到最合适联系的人,并向他们发送连接请求。一个会撰写邮件回复。一个会给我的收件箱打标签。一个会定制我的简历并简化申请流程。一个会管理我的日历。每个单独用都很有用,但当我把它们全部连接在一起时,真正的超能力才被解锁。
正确地申请一份工作意味着很多步骤。查看职位。检查是否合适。定制简历。填写申请。在 LinkedIn 上找到公司里的人。与其中几个人建立联系。联系招聘人员,说你刚刚申请了。如果有需要完成的事情就写邮件,或者把某些内容添加到提醒列表或日历中。手工完成的话,每份工作要五到十分钟,每一份都是如此。
在我写这段话时,这条流水线已经成长了。我打开 Jobright 页面,它提取出职位,然后我开始点击。每次点击都会进入一个职位自动驾驶程序,它是一台服务器加上一个以调试模式运行 Playwright 的浏览器。它会定制简历,打开链接,填写每个字段,附上定制后的简历,并准备好提交。然后一个通过 Tailscale 连接的小型聊天服务器会向我的手机发送消息,由我批准或拒绝。如果我批准,申请就会提交。
完成之后,两个扩展接管,一个连接 LinkedIn,一个连接 Gmail。自动驾驶程序会从招聘信息中提取招聘经理的姓名,并在 LinkedIn 上找到匹配度最高的人,也就是我有较高概率建立联系的人。它把这些信息传给扩展,然后它们发送邮件和连接请求。
我很久以前就构建了这两个扩展,用于另一个目的:快速撰写邮件草稿,以及快速撰写 LinkedIn 连接请求。然后我把它们模块化,它们就成了更大事物的一部分。
整个流程中只有一个检查点:申请发出前我在手机上的批准。刚开始时有两个。第一个是我查看招聘信息,并决定这是不是我想要从事的工作。用了一段时间后,我意识到我只需要一个。
就是这样。我会看到一条职位列表,点击它,然后一整条流水线就会运行起来,它由我制作的一个个小型独立组件构成。它们全都组合在了一起。
确定性
LLM 肯定能让这一切更顺畅。但我对它们有一个问题。它们不是确定性的。
我的大脑会寻找可重复的动作。每次运行时,它都必须像上一次那样工作。模型并不保证这一点,而且每次尝试都会消耗 token。
我确实试过用浏览器代理而不是我自己的代码来运行整个流程。与确定性流程相比,它非常慢。成本更高。而且偶尔它会走一条不同的路线,对于一个要运行数百次的流程来说,这太频繁了。
所以我稍微试验了一下,一旦我开始用它申请一堆工作,我就能清楚地看到错误在哪里,以及哪里实际上需要模型主动介入。我就这样把它拆开了。几乎所有的浏览器交互都是确定性的:找到文本框、提取问题、填写字段。这些用普通代码比用浏览器代理更容易完成。简历定制是模型擅长的地方,所以让模型来做。像“你为什么想加入我们公司?”这样的自由形式问题也是模型擅长的,所以也让模型来做。其他所有事情每次都按同样的方式运行。
事情会坏掉
我还有很多以前构建的应用,现在都不用了。它们要么已经失去了原本的用途,要么我无法让它们继续运行。
Jobright 自动草稿扩展一直坏掉,因为 Jobright 和 LinkedIn 一直在改布局。LinkedIn 在这方面是出了名的。我不得不反复重建它。另一个是 GitTrack,用来跟踪我的练习题,因为 LeetCode 和 NeetCode 改了 UI 就停止工作了。同一个应用用 Supabase 作为数据库,而 Supabase 因为活动量不够一直暂停项目。这些都不难修。问题是它永远需要修。
维护是没人会为只有一个人使用的软件做的事情。人们没有更新应用并让它们保持运行的概念。他们以为自己的工作是使用应用,而让应用保持运行是应用提供者的工作。对于你自己构建的软件,没有应用提供者。只有你自己,而当你没时间的那一天,应用就死了。
分享更糟
我构建的第一个扩展恰好只有两个人需要,我和我的朋友,但它仍然得走完整个上架 Chrome Web Store 的流程。之后的那些我们真的是通过 AirDrop 分享的。
问题在于更新。老实说,我们没有人第一次就能做对。我会修点东西,或者加点东西,但没有好的办法把修正后的版本发给我的朋友。我有很多和朋友分享的应用都没在用,因为他们手上的版本是我几个月前发给他们的版本。
我很早就把工作自动驾驶分享给了一个朋友,分享更新非常困难。后来我重新架构了整个东西,让它可以通过 GitHub 分享,这并不太难,而且让更新变得容易。它也改变了它的运行方式。最初它运行在我自己登录的浏览器里,带着我的凭据和自动驾驶所需的所有账户。为了分享它,我不得不把它和一个内置于应用中的浏览器一起发布,这样才能正确控制流程。这也改善了我自己的整体体验。
为什么公司做不了这个
当一家大公司构建软件时,它必须考虑每个版本会如何影响其形象。
苹果最近宣布了 Apple Watch 的 Siri Recap,这个功能会全天聆听并总结你的对话。苹果特意解释说不会存储音频,没有文字记录,也不会识别任何人。我很可能会用这样的东西。它是在台上宣布的,而第二天苹果就发布了一份详细的说明,解释音频是如何处理的,那时还没有人用过它。它至今仍未发布。连他们都能老远就看出 backlash 要来了。
本来就该是这样。一家背负如此多信任的公司必须谨慎行事,因为每一个功能也都是一条新闻头条。
如果苹果给我一个能学习我击键的键盘,我会说:“这是个很棒的功能。”但一旦世界上任何地方的任何人说“苹果在追踪你的击键”,整个功能就变成了一场噩梦。大公司不能在个性化上大举冒险。牵扯的因素太多了。
同样的审视会落到每一个通过平台发布产品的人身上。无论我为自己构建什么,首要的限制因素都不是代码,而是规则。我写的第一个扩展因为权限范围过宽而被拒绝。它需要宽泛的权限,因为它必须追踪我在所有网站上申请的每一份工作。我重写了它,让追踪只发生在实际提交申请的网站上,结果追踪效果变差了。我理解这条规则为何存在。有些恶意行为者会利用这种访问权限,对你的数据另作他用。规则保护用户免受开发者之害。
但在这里,一切都是由我掌控。我既是开发者,也是用户。
再拿键盘那个想法来说。我来自印度,我用英文字母输入卡纳达语,也就是音译。自动建议只能猜中几个常见词,大多数都猜不中。如果我为自己的输入方式专门构建一个击键模型,我会既开心又自信,因为只有我知道它的存在。只有我会部署它。没有公司拥有我的数据。没有公司能试图向我推销东西。我不是别人图表上的一个指标。我可以随心所欲地推进它,一个每次都能预知下一个词的自动补全,我完全不介意,因为我知道这个模型是如何训练的,我知道是谁训练的,而且我知道数据永远不会流到别处。这份安心本身就是一种产品。
每一条限制都有理由,而那个理由不是你
每家公司都需要登录。不是因为你需要一个。而是因为它需要知道回来的是你。
他们不会发布有争议的功能,因为那是声誉风险。他们不会做像减少通知这样的小改动,因为他们需要你打开产品。他们总是会力推推送通知。
每个应用,或者说应用背后的公司,都是为他们而不是为你优化它。这就是我的论点。当我为自己构建一个应用时,我只考虑我自己,这意味着我为我自己优化一切。当每个人都获得构建的能力时,每个人都能为自己思考,就像公司一直为自己思考一样。
什么没有触达人们
还有一件事。所有这些 AI 的进步并没有公平地传递给消费者。
我从一家叫 Extend 的公司参加 YC 以来就一直在关注他们。创始人之一 Kushal Byatnal 是印度人,我喜欢他们的故事:他们进入 YC 时是在为企业构建一个 Chrome 扩展,后来转向了文档处理。他们做的事情之一是从杂乱的文档中提取干净的数据,包括 OCR 等等。我不是每天都需要这个,但有些特定的日子我需要。如果一个普通人需要一次高质量的文档提取,根本没有办法获得。要么他们付一个月的订阅费只用一次,要么就用不上。软件不该是这样运作的。
Pete Koomen 为这个问题的更大版本起了一个名字,叫“无马马车问题”,见 "AI Horseless Carriages"。当发动机被发明出来时,人们的第一反应是把马达装到马车上。马车是适合马的设计,却是错误的设计。设计必须改变以适应技术。如今大多数软件都是装上了 AI 马达的马车。那些限制依然存在,而且它们存在的原因与用户毫无关系。
你想要的方式
我可以向你保证,每个会写代码的开发者都有自己看待事物的方式。这是经典心理学:我们想要事情按自己的方式来。直到现在,让事情按你的方式来意味着你得自己构建它们,还得自己让它们活下去。那就是门槛,而它已经消失了。那位只能告诉我她讨厌什么的的朋友,不必弄清楚她想要什么。她只需要说出要省略什么。
又是六个人
我不断回到那个为我们六个人做的应用。这篇文章里的一切都在其中。本该互相通信却做不到的应用。没人付钱维护就会崩溃的软件。分享意味着通过 AirDrop 发送文件。为不是用户的构建者写的规则。没人要求过的登录。
它必须比那天晚上简单得多得多。简单到:“为我们六个人创建一个可以分享和使用的应用。” 这也是我开始构建 Midas 的原因之一。
你使用的每一个应用,都是为构建它的公司优化的。
现在轮到你了。
来源:Hacker News · bhuvanrj.me