之前翻译一段英文或者一个词总是需要复制,再打开有道词典 app 再找到“翻译” tab,接着再粘贴进去,点翻译按钮,最后才能看到结果,而欧陆词典仅需双击 command + c 即可在光标位置展示翻译结果窗口,用了好几年直到最近升级到 macOS 15.1 版本后又坏了,一直在忍受这个时好时坏的功能只是因为它太方便了,方便到我已经完全依赖了它。就在昨天,我终于对欧陆词典忍无可忍,自己用了刚好 24 小时的时间做了一个更好用的替代品。

背景

很离谱,我以为自己应该不会再遇到系统升级后 app 功能异常的问题,因为能够活到现在的 app 和公司甚至是个人开发者都已经非常成熟非常稳定,因为升级到了正式版系统后导致功能各种异常的 case 几乎没有了,但就是每年你都会遇到,虽然很想理解,但还是很难理解。从 22 年开始已经发布了两年的 apple silicon,整整两年啊!泼辣修图都支持得不好,现在我估计肯定支持了,但已无心去用,当时也用了一个月的时间,那会还在广州出差,每天晚上回到酒店后就吃着夜宵开撸自己的修图软件 PhotoP,坑不少,毕竟修图软件说现在开发流程成熟了但配合上纯 SwiftUI 的数据流转方式还是很痛苦的。目前主要是我用了更精细化修图的 Lightroom,自己的 PhotoP 就没有动力去维护了,等待 Adobe 真的完全退出中国,且在国内无法下载和续费正版的 Lightroom 后我可能会继续动手完善它。

这个事情发生在了昨天下午的 17 点左右,我那会正在写另外一篇博客《我和 iPhone 的故事》,写着写着发现怎么欧陆词典的 command + c 快捷键双击功能又废了,正在忆往昔峥嵘岁月的我热血上头,马上决定必须解决一下这个问题。颅内快速编译了一遍可能的实现方案,发现一晚上可以搞出 demo,马上就开干。

开发过程

SwiftUI

选型非常简单,必须 SwiftUI,否则现在回过头去看可能现在都还在纠结各种 AppKit 的 API,如果说过去几年 Apple 最伟大的发明我觉得除了 Apple silicon 和 vision pro 外,前三的位置必须有 SwiftUI,我到现在都还记得当时坐在场下看到 keynote 放出这个王炸时,我整个人直接就沸腾了!当时正在看 Flutter 相关的东西,只是觉得 Flutter 这种平台无关的 DSL UI 写法非常现代化,但还是有点复杂,反而 SwiftUI 给到的解决方案更上一层。

但还是因为刚推出的框架,整体还是比较新,很多 API 没法支持,写起来非常难受总是绕不过 UIKit,最后还真不如拿 UIKit 来重写,确实中间是放弃了一段时间不想碰,后来是看到了也可以在 macOS 上用了再次沸腾了起来。大学那会手撸过 AppKit 写了一个词法/语法分析器的编译原理作业,就只是想简单的写一个列表,差点就放弃了,跟 UIKit 完全不是东西,思维转变一开始还是比较困难的。

后来因为来到了剪映,写了剪映专业版,破除了一些自己对写 PC 应用的枷锁,不知道大家之前有没有写过 PC 应用开发,我之前完全没有写过,刚开始唯唯诺诺深怕犯下什么大错,但也就是这段如履薄冰的锻炼,总算是打破了对 PC 开发的刻板印象,现在反而更加喜欢写桌面应用,因为自己平常每天用的最多的设备反而不是手机,而是电脑,而且也累计不少使用 Mac 这差不多 10 年时间里的问题,现在一言不合就是接着 SwiftUI 更符合现代化开发思路的跨平台框架如鱼得水,我非常推荐大家多多少少都来写点 SwiftUI,如果你也在用 macOS/iOS,抽空周末自己写点小 app 那是最好不过啦!

不过 SwiftUI 问题也不是没有,说到底还是太新,在 macOS 上想要做些精细化的操作几乎没有不用 AppKit 的地方,但大大缩减了拿 AppKit 去写原生 UI 的痛苦。但基本上 SwiftUI 和 Swift 本身互相调用的成本已经降得非常低,拿几个 @State 修饰符标记变量暂存下通过 Swift 调 AppKit 得到的值非常好用,几乎没有理解成本。我估计这种关系是去不掉了,日后 SwiftUI 会几乎完全取代原本 AppKit 画 UI 的部分,AppKit 只需处理和系统交互以及一些更细节操作的 API。

SwiftUI 在发布时 Apple 玩了一个文字游戏,别人家都是“一次编写,处处运行”,SwiftUI 是“一次学习,处处可写”(大概意思),我对 PhotoP 前段时间还痴心妄想从 macOS 无缝迁移到 iOS 上,后来发现只能复用一些最基础譬如TextImageListButton 等之类的纯 UI 组件,稍微多写一些平台相关的组件都不行,就算复用 UI 组件,不同平台之间的布局也不一样,到头来写了一堆的 if-else 还不如重写。

所以最近开始逐渐流行在各个 app 内拿 rust 来写多端逻辑而不拿 C++ 的原因大家普遍表示都是复杂、不好写和容易内存泄漏等对 C++ 长久的印象,说实话在我没有大量写 C++ 代码之前我也是这么认为的,但被赶鸭子上架写了一年多的 C++ 后发现,道理确实是这个道理,内存和野指针问题几乎每天都充斥着团队内部的讨论,但没有传的那么玄乎,仔细拆解 case 后发现基本上都是写错了或没有理解就一顿写,解决的方案无非指针判空,越界校验等,C++ 的水平没有上涨太多,但对边界情况和可能异常的地方多了好几个心眼,养成了不相信的习惯。

反倒是到了 Swift 和 SwiftUI 这边,写多了 SwiftUI 都要不知道 UIKit 咋写了,总而言之就是一个字——爽!

Cursor

现在应该没有人写代码不选个 AI 工具来协助吧?就跟这波 AI 工具浪潮来之前没有人会写代码的时候不开个浏览器等着查资料一样,我觉得要积极拥抱这个变化,没必要去记那些鸡毛蒜皮的 API 和属性,把时间留出来去思考更值得花费时间的事情上。比如这次写 TranslateP,在决定动手后,我真的只是在脑子里过了一遍核心逻辑,觉得下图这个核心逻辑没有什么卡点没有什么一晚上搞不定的环节,才放手去干,在 Cursor 的帮助下,刚好 24 点完成了最核心的 demo。开心的发了一条朋友圈,没想到吊出来了这么多对这个小工具感兴趣的小伙伴,还挺意外的。

现在在生活或者工作中使用 AI 协助真的也是跟之前离不开搜索引擎是一样的,正是因为搜索引擎聚合信息的能力太弱,以至于还出现了类似 Dribble、Pinterest 之类供你只查某一个分类某一个类型下的图片,我还记得 17、18 年那会观察实习公司里的设计同事,每天的工作时间里有一大部分都在浏览大量的图片,最后找到几张确定主视觉,再找几张确定框架,最后结合需求才能非常极限的把成品做出来,这跟设计类工作思维模式有关,当然我认为参照物难以找到合适的更有关系。

反观如今,我们只需要维护好自己准确的提示词就可以生产出众多符合诉求的素材,我们只是在选一个更适合的,而不是像之前那般找一个合适的,就这短短的几个字只差,却用了将近一代人的时间去发展。曾经我还冒出来过感觉这个世界发展得太慢了,应该要更快更猛,计算机能够带来的改变会更大才对,疫情的时候觉得宛如世界停滞,但从去年开始才觉得世界开始往前走了,总算是开始做出了一些这个时代才会做出来的事情。但我知道自己永远不会是第一个吃螃蟹的人,说实话确实没有这个能力和精力,但我是非常乐于看到这种变化,只是这种变化如果很难切入我的生活中时,会选择当那只把头埋进土里的鸵鸟,先埋一段时间,看看再说。

在这么多的 AI 工具里我首先拒绝的就是国产工具,只要是国产的我都先打个问号,不是不喜欢,而是被搞怕了,永远都会有弹窗,永远都会有广告,永远都会有误操作,永远都会有摇一摇,永远都会有你不想要的。而且我一直不理解的是为什么不能安心的做收费,而是一定要接广告,好端端的一个体验完全被消磨没了。现在的这些 AI 工具每个月的订阅费用都是按十几甚至二十几美金去计算,换算成人民币将近六七十甚至一百多元一个月,但就是有人愿意心甘情愿的去按月订阅,甚至按年订阅,在这种 AI 工具范围里我也模模糊糊,看不透的东西我先选择随大流。

说回 Cursor。Cursor 说实话它就一点我非常喜欢,你可以在工程代码里的任何一个地方问它某个方法怎么写,某个 API 怎么用,甚至丢给它一张 UI 稿,让它用工程里已有的逻辑写一份,它给你的回答是综合整个工程目录下的回答,而不是纯资料库,它是以你的本地工程库来进行的回答,这一点能省非常多的事。

很多时候一个 manager 挤在一个文件里,上上下下三四千行,有时候都不知道从哪开始看起,按照一开始可能就得搜方法名,看调用栈,有些同事做的好的会写一份完整的完整,给你一个流程图和类图,告诉你模块间的关键调用方法是哪些,基本上一个下午也就摸得差不多了,但之前试过问 Cursor 里的 Claude 3.5 Sonnet 模型一个类是在干嘛,都怎么干的,确实这个模型更适合编程,而且结合 Cursor 的交互,非常清晰的给出了所有环节。后来我也就放心的交给了它,在修复一些方法里可能存在的越界问题,经常会用它扫一遍。

但局限性还是有的,我已经多次尝试过从 0 开始搭建一个 app,包括这次 TranslateP 也是如此,刚开始好像挺快,迅速的就出来了一套可运行的代码,但问题就出在了他不知道正确性,大模型的结果都是降噪出来,经常给你几个错误或者不存在的 API,反反复复帮他纠正,有时候还绕了一大圈才实现这一个功能,总之他结合的都是历史经验给出的答案,确实是搜索引擎的集大成者和继任者,但正确性和滞后性是目前最大的问题。比如 Cursor 里我常用的 Claude 3.5 Sonnet 模型完全不知道 apple 在今年 WWDC24 上发布的 Translation 框架,因为他的数据只到了今年 4 月份。我绕了一大圈反复纠正他告诉他代码错了,可以用 WWDC24 上新推出的 Translation 框架来继续生成代码,不要再用 Google 翻译已经关闭的接口,他却告诉我现在是 2024 年 4 月,WWDC24 还没有召开。

但我目前还是会继续用下去的,目前这种 Copilot AI 工具对程序员甚至个人开发者来说就是“十倍效率”生活的缔造者,可以让我们更加专注到具体的问题核心,不要跌入去记去背 API 和属性等浮于表面的事情。

一定要小

那既然说到了专注,那就接着来说说个人开发者,或者独立开发者这件事。这两年身边冒出了非常多厉害的个人开发者学弟学妹,做的事情都是当年的我所不可望及的,不光是做出来了,还是实打实的跑着几千用户量的产品,我当年能做出来就觉得已经很了不起了,更别说还有心思和能力去上架去维护去推广和运营,这其中涉及到的事情确实不少。

但这也可能是个人兴趣有关吧,我虽然确实很喜欢做些好玩的小工具小产品,但给更多的人用这件事我却直到了这两年才慢慢改变过来,主要是思想转变过来了。之前总是写完一个 app,完善得非常好,就差那么一脚,开个开发者账号就可以上架了,反而是直接开源再写篇博客发到社区里,赚个吆喝也就罢了。如果把那会做的东西都推上架了,现在少说也得十几个 app 了。但那会咱是真没钱啊,是真舍不得一下子拿出这 688 元的生活费去上架几个 app。哪像现在,我一直在等一个机会让我回馈 ifLab,想等一个比较合适的时机赞助几台 mac mini,顺便再长期维护一个社团开发者账号,激励下与我当年一样有类似想法但困于生活费的同学,期待!

最近这两年做 app 改变最大的一点是完全没有精力去做大的东西了,首先是真没时间,其次是就算有时间也已经完全不想继续碰已经碰了一天的电脑了,反而想去看书骑车跑步,时间再多一些就多出去走走看看,去感受下这个周围的环境,去看下之前自己从未踏足的地方,最后是感觉自己敢闯的劲少了不少,没有动力去做更大的事情了,慢慢的感觉也没啥必要,因为微信上其实并没有人找你,你也其实并不想看朋友圈,那些 B 站里的视频和小红书上的生活跟自己也没啥关系,最重要的是,真没什么问题非得需要你来解决,不解决这些问题也有绕过这些问题的方式,它可能并不一定真的是问题。

等等之类的吧,总之就是心态不一样了,现在完全不想做也不想了解那些所谓更大的东西,总感觉不真实,特别虚,特别空。所以做 TranslateP 的过程里我并不想做大,也不想做到极致,虽然昨晚脑子还是不争气的一直在想怎么把这个 app 给做好,未来可以迭代什么功能,可以玩哪些收费的方式等等一大坨想法都钻脑子里来了,上床已是凌晨 12 点半,后来好不容易迷迷糊糊中睡着了,早上 5 点多又醒了,脑子迅速又闯入了这些点子,比如是不是可以做翻译次数统计,自动把翻译过的词加到生词本中,每天设置固定时间推送到邮箱或者生成一份 txt 文档等等,就这样想着想着,又在迷迷糊糊中天亮了,但我还是没能继续睡着,困是真的困,但想法这玩意儿它是来了就真的挡不住啊!

到了今天早上 8 点,我想了想算了不睡了,起床接着写,但越写越大,开始慢慢的离开了主线,离开了我要做这个 app 去解决的核心问题,到了中午感觉自己绕不出去了,但此时外面的天气很好,我原本打算是写到中午之前结束开发这个 app,好好出去骑一次车,过一个阳光灿烂的周末。但没想到绕在了实现 app 菜单栏入口的功能上了,MenuBarExtraWindowGroup 存在冲突,二者怎么调都调不好它们的关系,眼看过了中午 12 点,然而我连饭还没吃,果断停下所有事情,给自己下了碗面。吃好后就装好车穿好衣服,丢三落四的,反反复复开了几次大门才把东西全部拿完下楼骑车。

但好巧不巧,今天的好天气全是靠风吹来的,所以外面的风很大,阵风 7 级已经让我的车头摇摇晃晃了,果断调头回家,重新把车放回骑行台上,在台子上骑了 1 小时,折腾了到了下午三点多才让自己的心情舒服了一些。重新坐回电脑面前,梳理自己想要的到底是什么,调整了工程逻辑,最终自己画了个 icon,在下午 17 点 22 分提交了 testflight 审核。

所以啊,人做事啊,一定不要搞太大,我几乎每次写新的 app 都会越高越大,明明我只是需要造一个勺去打碗汤喝,但不知道为啥造着造着,都想着能不能通过造的这勺把地给种了。我深知自己的这个毛病,所以毕业后再写 app 会变得很小心,能不写就不写,能少写就少写,要不然真的很容易宛如一个深渊把自己整个人拖累了,都是速战速决,PhotoP 用了 1 个月,完全是因为后来出差回京了回家了不想写了,后来还是逼自己放弃了好几个周末出去骑车的时间才憋出来的,现在想起来真是太痛苦了。这次 TranslateP 从昨天下午 17 点左右到今天下午 17 点 22 分,满打满算其实差不多 24 小时,自我感觉还算及格,主要是又激发了点子太多的臭毛病导致睡不好,甚至有时候我都分不出来这到底是毛病还是天赋hhhhh。

总结

好了,截止到目前为止,我总算在 app store 上存活了两个 app,都还挺感兴趣的,前后发布的 app 共计 4 个,今年算是交差了,看着去年给 PhotoP 规划的今年功能列表,那长长的一串真是可怕,希望大家都可以把事情做小,把人生做大,把体验打满!

这是 TranslateP app 的 testflight 测试链接,截止到本文结束时,apple reviewer 还在测试中,链接点进去是无法下载的,但我会一直保持这个链接不变,直到 TranslateP app 上架。但说到上架这个事我现在都不太确定我这种做法会不会被拒审,你用了就知道啦!我觉得这应该是最不想让用户知道它存在的产品了hhhhhh。

我 “p” app 家族