普通视图

发现新文章,点击刷新页面。
昨天以前Randy's Blog

我如何使用 Apple Notes 做笔记

2025年2月9日 08:00

我从两年前开始放弃了所有笔记软件,换用 Apple Notes 记录我的所有笔记。这个举动缘于我读了 Tiago Forte 的一本书 The PARA method.

the para method

可能大家比较熟悉他的另一本书 Build The Second Brain, 是关于如何使用笔记软件构建自己的「第二大脑」。这本书也有提到他的 PARA 理论(我在我之前的文章也有提到过我如何应用这个理论管理我的笔记)。两本书都读过以后,我认为 The PARA Method 这本书更偏向实操,我从中收获了更多的方法论。如果你只想读一本,那么我推荐读这一本。

读完这本书后,我立即在 Apple Notes 中基于 PARA 方法建立起了笔记组织的形式,这一套组织形式一直用到了两年后的今天都没有改变过。也就是说,这两年来,在做笔记时我再也没有花过时间去想应该如何组织我的笔记,光从这一点,就让我受益颇深,我可以没有任何心智负担地迅速记下我需要的东西,不用担心我应该怎么记,一切都是那么的简单。

这篇文章就是想和你分享我如何在 Apple Notes 记笔记,我在 PARA 的基础上根据我自己的实际场景做了一点小小的改良。希望对你也有所启发。

为什么是 Apple Notes

在分享方法论之前,我想先解释为什么我选择了 Apple Notes. 我认为 Apple Notes 有很多优点。

  1. 它是系统自带的,我在手机、电脑上可以直接使用,不需要安装额外的 App
  2. 它天然是支持同步的,不需要注册账号,不需要把资料上传到别人的服务器上。It just work.
  3. 你可以直接在 Apple Notes 中粘贴文件、图片、音频,没有限额(严格地说这也占用你的 iCloud 存储,但我本身已经买了存储,这变成了边际成本)。
  4. Apple Notes 打开的速度很快。

当然 Apple Notes 也有缺点,但两年使用下来,我没有因为这些缺点感到被限制,比如:

Apple Notes 支持的格式有限,只有最基本的列表、标题、加粗等等的文字样式格式。但我用下来发现,我根本不需要使用什么高级的格式。有人问我 Apple Notes 不支持代码块,你是怎么记代码相关的笔记的?我说我基本不会把代码片段作为笔记来记。比较多的场景是一些 JSON 格式的片段,我只会直接粘贴到笔记里,不加任何的格式。

我找到了两条比较经典的笔记:

可以看到,里面不仅有 JSON, 还有 toml, 还有命令行。甚至还会有 spell check 的红线让它显示得很丑。但是我一点也不在意。因为它们是拿来用的,不是拿来看的,我不在乎它好不好看,只要我需要用到的时候能找到拿来用就好了。

也就是说,「美观」在我记笔记的需求里排不上什么优先级,我的最高优先级是能快速打开,快速记录,让我记东西的摩擦力降到最低。能帮我当下的想法、要处理的事情相关的信息记下来才是最重要的。所以我看过很多人把 Notion 模板做得很漂亮,也不为所动,因为对我来说这不是我需要的东西。不可否认,美观的笔记系统能给人情绪价值,它没有对错之分,只要合适自己就好。所以最重要的是知道自己是否需要,如果你认为这对你来说不是很重要,就回归简单吧。

Apple Notes 也没有「双链」功能,这是现代流行的笔记软件中很重要的功能,我在用 Logseq 的时候也被这个功能打动,因为它能把相关的笔记自然地关联到一起,带来额外的启发。最初用 Apple Notes 时我也担心会不会因此失去了这个优势,但用下来才发现,我并不是那么的需要它,即使没有,也没有让我感觉因为没有了他而失去了灵感。

Apple Notes 的标签功能也很弱,但我不使用标签。

PARA 是什么

虽然在之前的博客也提到过 PARA, 但我还是想在这里简短地解释一下我所理解的 PARA 是什么。

PARA 的全称是 Project, Area, Resource, Archive. 翻译成中文就是「项目」「领域」「资源」「归档」。它代表了一个笔记应该放在什么地方以及一个笔记的流动过程。

PARA

没错,在 PARA 的方法论中,笔记是可以「流动」的,它有时候在 Project, 当项目结束后,它不再被需要,就会流动到 Archive. 如果它在以后有利用价值,它可能会流动到 Area 或者 Resource.

  • Project 指的是你现在正在进行的项目,比如你正在构思的一篇文章,你正在做的一个项目等等
  • Area 指的是和你有关的领域,比如如果你是设计师,那么设计就是一个你的领域。
  • Resource 指的是你会用到的资源,个人理解它和 Area 是一样的,只是优先级的不同。假如你是设计师,你偶尔会了解数字货币,但它在你生活中的优先级比较低,那么数字货币相关的笔记应该归类为 Resource
  • Archive 指的是不再需要的笔记。通过我会把 Project 中完成的或者难产的项目拖动到 Archive.

理解 PARA 的关键是理解 PARA 的哲学:你记下的笔记应该要服务于你的行动

也就是说,在 PARA 的系统里,当你想要把东西记下来时,你的 mindset 应该是,这条笔记和我接下来的行动有什么关系?如果没有关系,那么它应该放在 Area 还是 Resource?

在 The PARA Method 一书中,开篇的一句话能解释这个哲学:


Every word in this book is designed to do one thing: propel you forward into taking action

这本书中的每一个词都是为了一个目的:推动你付诸行动。

Apple Notes 中的 PARA

简单了解了 PARA 后,看看我如何在 Apple Notes 中使用 PARA.

我在 Apple Notes 中会单独建立一个 PARA 目录:

PARA 目录

里面有基本的 Projects, Areas, Resources, Archived 文件夹。在这个基础上,我有两个改良,第一个是添加了一个 Drafts 文件夹,用于记录我日常的零碎想法:

这些想法一般是在手机上记录下来,在有空的时候进行深度思考和研究,有些会最终成为一篇推文,或者基于想法变成一篇博客文章。

第二个改良是增加了一个 Inbox 文件夹,用来存放打算做的项目,这些项目还没进行深入的思考,不确定是否立项来做。如果想清楚要做,我会把它拖动到 Projects 中。否则直接拖到 Archive 归档。

Projects 目录是我最常用的,因为里面都是当前正在进行的项目:

比如,当我决定要写一篇长文,就会在 Projects 中新建一个文件夹,比如现在这篇文章,就是在 Apple Notes 里写的。有了这个文件夹后,当我看到任何和这个项目相关的信息,就会把它记在这个文件夹当中:

也就是说,当我看到任何关于 Note taking 主题的值得记下来的东西时,我很清楚要把它放在哪里,因为它和我正在进行的项目有关系。

这也解决了一个很普遍的问题,很多人想记笔记,想有「第二大脑」,却不知道应该记什么,或者记下来很多,最后都只是放在自己的笔记软件里,发挥不出任何作用。而在 PARA 的系统中,你清楚地知道你应该记什么笔记,因为你知道哪些信息和你正在做的事情有关系。这些笔记才是真正能发挥作用的

比如我即将写一篇在我 30 岁时发布的博客文章,虽然还没开始写,但它是我的一个 Project, 那么当我读到和这个主题相关的信息,就会把它记在这个 Project 里,当我真正写这篇文章的时候,能直接参考它们,对于我来说,这才是有用的笔记:

Projects 不仅仅是项目,它还可以是即将到来的一个事件(Event),也可以是你正在研究的一个课题。比如你约了一个重要的人,你需要记下来这次约会需要准备点什么。约会结束后,就把它拖动到 Archive.

再举一个例子,比如你正在开发一个软件,可能需要记一些技术相关的笔记。在以往,可能你会把这些笔记按主题记下来,比如 React, Vue, Rust, 前端, 后端之类的分类。但在 PARA 中,你应该为你正在开发的软件创建一个 Project,无论你想记下来的技术笔记是什么分类,都放到这个 Project 当中。这样记下来的笔记才是真正有价值的,因为它真实地服务于你正在开发的项目,你在开发时可以反复在一个地方参考。

项目结束后,你可以将整个 Project 拖到 Archive, 不需要再管它。如果你认为 Project 中的一些笔记有复用的价值,就把它拖到 Areas 或 Resources 当中。Apple Notes 的拖动十分方便。但按照我的经验,一般来说直接 Archive 整个 Project 也没什么问题,因为它不是被删了,你还是能通过搜索重新找到它。这时 Archive 的笔记又会「流动」到 Project 当中。

我自己的 Areas 和 Resources 其实很少碰,基本只在 Projects 和 Archive 中活跃:

使用 PARA 的另一个好处在于,只要展开我的 Projects 目录,我能一目了然我正在做的事情。我不再需要单独的 Todo 工具,因为 Projects 就是我的 Todo, 而且 Apple Notes 也有 checklist 功能。这也是 The PARA Method 中所说的:

You will gain greater focus on what matters most: You will have greater clarity about what’s important so you can intentionally move your life into alignment with your interests and goals.

你将更加专注于最重要的事情:你会更清晰地了解什么是重要的,从而有意识地将你的生活与自身兴趣和目标协调一致。

常见问题

没有双链,如何找回笔记

善用搜索。虽然只是关键字查询,但按照我的经验来看,这就足够了。比如我在 Apple Notes 记过我常用的 API key, 我只要搜索 azure 这个词,我就能立刻找到,我甚至都不知道它被我放在哪里了:

怎么把旧的笔记迁移过来

不需要迁移。在新的工具重新开始,需要用到的时候才在旧的工具重新找回,有必要时再复制过来。反正没人要求你用新的工具就把旧的数据都删掉。而且,我相信你最后会发现,你并不怎么需要找回你的旧数据 😂 这两年我就没打开过我以前一直用的 Logseq, 也没有做任何迁移。

结论

以上的分享不一定适合所有人,但它非常适合我,我也从这套系统中得到了很大的解放。你甚至可以什么系统都不用,在同一个文件夹记下来所有东西,最后你会意识到,重要的不是把笔记放在哪里,而是感谢自己当初记了下来。这就是为什么降低记录的摩擦力是如此地重要。

PARA 是一个方法,你不一定要用 Apple Notes, 你可以在所有的工具用它。不要让工具阻碍了自己最重要的事 —— take action. 真正有用的笔记是帮助你 take action 的笔记。

P.S. 这篇文章在 Apple Notes 写成:

新 MacBook 的设置和软件

2025年2月8日 08:00

趁着国补,把手头用了 5 年的 MacBook Air M1 换成了 MacBook Pro 14 寸 M4. 顺便手动重新配置新电脑,在此记录一下每次设置新电脑时我会做的一些设置和必装的软件。

设置

把点按切换成轻点:

点按切换成轻点

我不喜欢用触摸板点按拖动来移动窗口,觉得有点费力,所以我会调整为三指拖移。旧版本的 OS X 可以直接在系统设置中调整,新版本的 macOS 竟然把它归类到辅助功能里了:

三指拖移

把 Control 键和 Caps Lock 键互换。因为我需要频繁使用 Control 键,Caps Lock 的位置是最合适的,这也是 HHKB 的默认布局:

Control 和 Caps Lock 互换

取消 Spotlight 的所有索引,因为我用 Raycast, Spotlight 的索引会浪费计算资源:

取消 Spotlight 的所有索引

软件

  • Microsoft Edge: 用了很多年的主力浏览器
  • 清歌五笔输入法: 最好用的五笔输入法
  • Raycast: 不必多说
  • Cursor: 目前主力 IDE, 也是 Cursor 长期的订阅用户
  • CleanShotX: 最好用的截图软件,除了截图还有很多好用的小功能(比如 OCR, 录屏)
  • 1Password: 密码管理
  • Warp: 主力 Terminal Emulator, 已经离不开通过 AI 写复杂的命令
  • iStat Menus: 在 Menu bar 显示系统信息,我用来实时看到网络传输速度和内存使用情况

2024: 在夜海中观望浪潮

2024年12月28日 08:00

高中时我读吴军的《浪潮之巅》,觉得很可惜,我出生太晚,错过了一个又一个的浪潮。我总是想,如果我身处这些浪潮,是否也会造就一点什么?我是不是也能创造一家了不起的企业而为人常道?

那时我才 17 岁,我在沙滩上观望浪潮,抱怨生不逢时。而现在,我 29 岁,已经在海中游泳多时。就在这几年,OpenAI 发布 ChatGPT 后,这片海似乎又卷起了一波巨大的浪潮,又有人站在了浪潮之巅,但我还没有。我已经无法再抱怨生不逢时,因为我已经在海里了。在很多个深夜,我差点就想承认,我这辈子只能是一个普通人,我太高估自己。但到了第二天,我又开始不服气,还是不能接受作为一个普通人活着,想做出伟大的产品,想做一家伟大的公司,想在世界上留下一点美妙的痕迹。

知道答案的人只有未来的我自己,所以每当这些迷茫时刻,我总会想起昨夜派对的《夜海的秘密》:

生命中所有来去 都是月亮的潮汐

只有闭上眼才能看到 夜海的秘密

你会看到有船从身旁驶去

船上站着来自未来的自己

他逆着霞光 看不清模样

如一尊塑像 带着先知般的哀伤

只是沉默望着你 一句未讲

你蓦然落泪 想一路追上

跟随他去往 那迢遥未知的远方 可是未来还未来 唯有此刻 是真实

昨夜派对的歌的歌词,就像诗一样,能给我一点疗愈。我习惯通过文学作品自我疗愈。别人问我,为什么还能保持阅读的习惯?我都会回答:如果你发现我某一段时间读特别多的书,那就是因为我这段时间过得非常不好,我需要从书中寻找答案。

2024,我读了 30 多本书。

因为想做一家伟大的公司,我读了柯林斯的《基业长青》和《卓越基因》,研究那些成功的企业是怎么走过来的。

因为想做出伟大的产品,我读了梁宁的《真需求》,lululemon 创始人的《lululemon 方法》,张小龙的《微信背后的产品观》。

其中一本叫做《做难而正确的事》(英文名是 Fall in Love with the Problem, Not he Solution) 让我印象很深刻,它不仅是一本给我打兴奋剂的创业鸡汤,它还教会了我,什么是真正的 Make something people want.

这些书让我对做产品有了另一个体会:如果我想做一个影响范围非常大的产品,我就需要做让人上瘾的「毒品」,要做满足用户「贪嗔痴」的产品。因为 PMF (product-market fit) 的最重要的指标是用户留存率。

恰好我读到了一本《玩家思维:游戏设计师的自我修养》,了解到了游戏让人沉迷的原理,大概也能运用到产品中去。

今年上半年我的朋友启师傅来佛山,我们在先行书店见了一面,期间我们聊到,做互联网产品有点厌倦,想做一些真正看得见摸得着的东西,能让用户在手上把玩,然后赞叹一句 wonderful 的东西,而不是拿着手机给别人看,说「你看我写的这个 App…」。

于是我想到 18 年我曾经卖过一段时间的程序员贴纸,那时我发现国内没有人在做,在国外买又非常贵,动辄一张几美元。那时我联系了一家质量非常好的厂家,做了一批质量很好的开源项目 logo 贴纸,卖得非常不错。更重要的是,中国的程序员终于可以在国内买到质量又好又便宜的贴纸。不过因为我还在上班,有点忙不过来,最后关掉了店铺。

后来我在杭州参加 AdventurX 的活动,趁着机会又见了多年的网友 Linmi, 他是 Notion 中文社区的负责人。我们也聊到了这件事。他鼓励我重新把这件事做下去。

回到家后,我重新认真思考了这件事。我确实应该重新捡起来卖贴纸这门生意,但不能像几年前一样只卖贴纸。我相信程序员(或者泛互联网从业者)需要的不止是贴纸,我们有我们独特的文化,我们有我们真正发自内心热爱的东西,我们乐意把它展示出来。

所以我决定把这件事用经营一个品牌的方式重新去做,贴纸只是其中一个产品。无论在后来是卖贴纸还是卖其它东西,我希望能聚集一群有相同文化认同的朋友,做出这个群体喜欢的产品。我想了很久品牌的名字,最终还是冒了一个风险,取了一个只有程序员会懂的名字 PaddingLeft, 这是一个 CSS 属性的名字。幸运的是,我居然能买到 padding-left.com 这个域名。

我花了些时间选择工厂,甚至跑到了工厂观察他们的机器,和工厂聊价格排期。终于重新上线了店铺。

贴纸卖了一段时间后,其实没有赚到多少钱。期间我一直在想下一个单品应该做什么。恰好那段时间我一直想给自己买一条项链,何不就做项链?

起初我跟一些人聊这个想法,他们都不认可做项链,认为程序员没有戴项链的习惯。这个观察其实不无道理,可是在做这个品牌的时候,我其中的一个想法是可以通过 PaddingLeft 的产品,让用户在使用我们的产品的同时能增加自己的时尚属性,摆脱大众对互联网工作者的刻板印象。而且项链可以做得非常精致,也适合送礼。

这个想法有点自大,但我认为值得尝试。

第一批项链做出来后,卖得也不错。

项链

做 PaddingLeft 的这段经历,虽然也和互联网有点关系,但后来我才慢慢意识到,我在做和做软件截然不同的东西。我对供应链、库存有了新的认识,这些是在做软件的时候不需要处理的问题。和传统行业的人打交道,沟通的方式也和在互联网公司里沟通的方式截然不同。关于这些,我想在以后可以专门再写一篇和大家分享。

在开单的喜悦过后,我又开始想,这到底是一门多大规模的生意?18 年我卖贴纸,我只是把它当作赚外快来看待,如果一个月能带来 2000 块的收入,我会觉得是不错的零花钱钱。但是现在,我是在为自己的生计赚钱,我要思考的问题变成了,从商业上来讲,这是一个值 2 万人民币的 market, 还是值 5 万,还是值 10 万?如果它只是一门值 5 万的生意,我有必要做下去吗?或者说,它有可能发展成价值 20 万规模的生意吗?它是一个可以「流动」的生意吗?

就在刚刚,又有人在店里下单买了些程序员贴纸,于是我走到工作台一张一张地放进包装袋。我边发货,边盘算这单赚了多少钱,得到的数字是 8 块。我忍不住笑了。我曾经的日薪是这一单的 100 多倍。我做的这件事情,它真的有意义吗?

没有人知道答案,我只能安慰自己,这件事总得有人做,而我适合做。我了解程序员、设计师、产品经理这些人喜欢什么,因为我就是程序员。每卖出一张贴纸,我都会给对应的开源项目捐一块钱,以现在的定价,我基本是在做慈善。现在也有很多店做程序员贴纸,但没有人这么做过,因为我做过开源,我知道开源项目的窘境,这就是文化的一部份,也是做这个品牌的意义。如果你曾经买过 PaddingLeft 的贴纸,你会发现我用的自封袋和普通的透明袋有点不同,因为我用的是环保可降解的自封袋。这对用户来说没有丝毫影响,但我挺享受这种自我感动,这也是其中的意义。


直到现在,我还不知道,我还要在海里游多久,才能游到浪潮之巅。我想起曾经的一场梦,梦到在一个饭局,张一鸣就坐我旁边,我说我会有一天像你这样的。张一鸣笑了笑,我也笑了笑,然后梦就醒了。

我的这些执着在多年后是否会成为笑话?Think different 广告中的那句「只有那些疯狂到认为自己能改变世界的人,才真正改变了世界」这句话,到底是不是真的?妈妈,你 10 年前和我说的,算命的说我 30 岁会创业成功,到底是不是真的?

AI 和写作

2024年10月9日 08:00

Sam Altman 最近有一个关于 AI 和写作的访谈,让我开始思考 AI 辅助写作这个课题。

在辅助生产代码方面,Cursor 和 GitHub Copilot 已经证明了 AI 和人类在编程方面的协作非常有效。通过代码的上下文和注释,加上人类显示声明需求,AI 能很好地完成写代码任务。

我在思考在写作的时候,是否也能有一个 Copilot 辅助人类更好地写作。

大部分人不会进行深度写作,根据二八法则,80% 的人在消费 20% 的人生产的内容。这 80% 的人,偶尔进行浅度写作,例如写社交网络的动态、写用于工作中用于信息同步的文档。这类写作,我认为 AI 可以辅助的地方非常有限,用户基本不会主动为这样的场景寻找专门的写作工具或到 ChatGPT 这样的聊天窗口专门改写润色。这样的场景将来会被系统级的 AI (如 Apple Intelligent) 解决。

有的人希望写作,但不知道应该写什么。我曾经在书店看到过一本书,叫《642件可写的小事》,如标题所言,里面有 642 个开头,可以随便选一个续写。现在也有一些这样类型的 App. 这些书和 App 乍看起来很有意思,能解决不知道写什么的问题,但用起来我发现我根本不想写,因为我对里面的话题毫无兴趣。

我认为 AI 能很好地解决这个问题,因为我们可以在 prompt 中告诉 AI 自己的爱好和关注的领域,来定制化地生成自己会感兴趣的创意写作话题。

Notion 流行后,很多笔记工具开始标榜自己是「思维的工具」(Tools for thought). 其实写作这个行为本身就是「思维的工具」。Sam Altman 在访谈中说「写作是思考的外化」(writing is externalize thinking),而且「写作是模糊想法的放大器」。应该有不少人有同样的感觉,我们每天有很多想法和灵感,我们以为我们对这些想法非常清晰,但其实如果试着把想法写下来(或说出来),才发现很多思考在头脑内部其实处于非常混沌的状态。只有通过思考的外化(交流、写作),才会发现思维的漏洞、连结零散的思维。在修补思维漏洞的过程中,混沌的想法会逐渐变得健壮 (robust). 思考和灵感就像一颗种子,它非常迷人,但在播种前,它什么也不是。写作就是播种,认知是你的土壤,它会长出你意想不到的枝叶,然后又生长出新的枝叶,这就是为什么「写作是模糊想法的放大器」。

造成在头脑中的想法非常混沌的原因,是人脑无法承受过高的「认知负荷」 (John Sweller 提出的理论) 。借助书写可以把信息扩展到外部记忆,使得人在处理复杂信息时能更好地理解和思考。

很多人害怕写作,认为写作有门槛,但我不这么认为。我认为只要会思考,就会写作;只要能和人正常沟通,就会写作。写作只有把文字变成作品被品味被评价才是一种有门槛的艺术。我们受学校教育的影响,把写作完全视作一种文学艺术,才让人对写作感到害怕。却没有人教育我们,写作是一种思维的工具,写作可以帮助我们思考。我们其实可以只为自己写作,它是没有门槛的。把写作视作和自己对话,你就会发现写作也就是那么一回事儿。和自己对话需要遣詞造句吗?不需要。需要遵循什么文章结构吗?不需要。

把写作看作是思维的工具后,我对 AI 辅助写作有了全新的思考角度。从表面看,我们似乎需要的是辅助我写作的 Copilot, 但在本质上我们需要的是辅助思考的 Copilot.

现在很多文本编辑器都有 AI 功能:自动补全、自动总结、选中文本 Ask AI, 重写、润色等等。但我对这些功能在写作中的作用非常失望,真正在写作时,这些功能都是非常 annoying 的,而这不止我一个人有这样的感受:

这些功能,完全不能称作写作辅助,它们只不过是文本处理辅助罢了。它们对写作毫无用处,甚至有反作用。它们对思考也毫无用处,无法「放大」我的思考。

当写作作为一种思维工具时,我不需要 AI 辅助我自动补全,甚至有些可以生成一个段落的文字。这不是写作,这是在制造垃圾。

到底什么样的形式是一个好的写作 Copilot, 我也没有答案,但我认为它一定不能是侵入式的。它应该在一旁默默地观察我写出来的想法,然后在合适的时候告诉我它对此的观点。它有比我多得多的知识量,可以做到:

  • 在我提出一个观点时,找出其中可能的逻辑漏洞,帮助我更完整地思考。
  • 在我提出一个观点时,找出其在学术研究中对应的名词可以解释这个观点,甚至找出对应的科学实验、论文、现实中的案例。这在非虚构类写作中十分有帮助。我最近在读 Ali Abdaal 的 Feel good productivity 一书,里面十个观点有八个都能举出一个科学实验来论证,我基本可以单方面认为 Ali 一定是在用 GPT 来辅助他写这本书的。
  • 找出我在写作风格中的缺点,比如过于冗长,信息密度过低,句子难以理解等等。

也就是说,写作除了和自己对话以外,增加了和 AI 对话的一层。它可以提供灵感、帮助做 research, 写作风格指导等等的帮助。

虽然我希望有这么一个写作 Copilot 出现,但我觉得很难做出一个这样的 Copilot 出来。它的难点在于,不同类型的写作有着截然不同的需求,如果需要匹配不同的需求,最终还是会变成一个 Chat IM 的形态。上面提到的需求,其实直接使用对话也能解决,能进一步做的无非是在文本编辑器里加上选中文字展开对话,预设一些跟写作相关的 prompt 而已。

至于 AI 是否会扼杀写作,我不这么认为。Sam Altman 在访谈中也提到了这点:当你读到很好的作品,你会想去了解作者,这个作者经历的事情,他的思考方式,慢慢地和作者形成一个连结。这是 AI 做不到的。

「代码艺术家」不会被 AI 取代

2024年8月10日 08:00

最近大量地使用 Cursor 替代了 VS Code, 开始习惯直接在编辑器里告诉 AI 我的需求,让它来代替我写出代码段。

请注意,我用了「代码段」这个词,而不是「代码」,因为我想做一个区分 —— 按照我目前的经验来看,生成式 AI 非常擅长生成一段内聚的代码,而不是一整个应用程序。

在没有 AI 生成代码前,我写代码也是这样的一个流程:

  1. 思考整个应用的架构、模块
  2. 选择适合的技术栈
  3. 开始写代码,设计目录结构、抽象
  4. 真正开始实现实现

AI 也许能为第 1 和第 2 点提出建议,但我目前不需要。第 3 点我认为对于稍微复杂一点的生产级应用, AI 还做不到把这一块也做到。可能很多人看到现在 Claude 直接能写出一个全功能的 Todo List 就惊叹 AI 要取代程序员了,我觉得真正写过一个完整的给用户使用的「应用」的朋友对此都会很淡定。

对于我来说,只有在第 4 步(实现) 的阶段才真正能杠杆 AI 的能力。我会尽可能地描述清楚我的需求,让 AI 能理解我要做的任务,让它来生成满足我的抽象的代码,或修改现有的代码。

这里我提到的描述清楚我的需求是用 AI 生成代码中最重要的一点。所谓的「需求」不仅仅是描述这个函数需要做什么事情,还需要包含这个函数应该接收什么参数,返回的是什么数据结构。

例如,我在做的一个应用,其中我需要一个上传文件到 S3 的函数。在这个需求中,如果我单纯告诉 AI它要做什么,那我很有可能得到一个可以实现功能但不适合我调用的函数,因为 AI 没有上下文去确定我可以传哪些参数给它。

![cursor 截图]../../../images/telegram-cloud-photo-size-5-6168067452672523878-y.jpg

在深度和 AI 「结对编程」后,我对于「AI 是否能取代程序员」这个问题有了更深刻的思考。

有了 AI, 我现在写代码花的精力主要是在「设计」上,例如思考这个应用的交互设计,例如整个应用的架构设计。所谓的架构设计,一部分的工作是决定这个系统里要有什么模块,一部分的工作是决定这些模块如何串联在一起。而这些设计工作恰恰是我写代码的时候最喜欢做的,对我来说,写代码就应该是一个设计的过程,设计出优雅、易用、易扩展的接口是一件很有成就感的事。这也是我当初看 Head First Design Patter 这本书时的感受。
 如果写软件变成了一个只需要花精力在设计而不是实现上的过程,那么写软件的人就是「代码艺术家」了。我觉得「代码艺术家」是不会被 AI 取代的,因为设计的起点和终点都是人类,AI 可以给你 100 个设计上的答案,但只有人类最终能感知到现实和当下的环境和信息,创造出能触动另一群人类的产品。

如果你从现在开始,开始把 AI 当作是你的员工,就像某一天你突然只需要 $20 一个月就能招无数多愿意帮你打工的人,你很快就会发现,你最终会面临两种局面:

局面1:你将手足无措,你突然发现如果你不是实现函数的那个人,你就不知道你应该做什么了。从前你沾沾自喜的手写快排,手写红黑树突然变得一文不值,无处施展。

局面2:你将如虎添翼,你突然发现你曾经有很多想法没有精力和时间去实现,现在突然有这么多廉价劳动力将不厌其烦地帮你写代码,而你要做的只是设计好整个系统的结构,把具体实现外包给 AI. 然后把产品推出市场,去碰壁,去失败,去成功。显然,AI 不能替代你去碰壁,去失败,去成功,但真正让你变得强大的不是你手写快排有多烂熟于心,而是去碰壁之后学习到的东西

AI 不会替代「代码艺术家」,因为 AI 是「代码艺术家」的喷射机

读到这里,可能有人要说,Randy, 你飘了,你开始技术虚无主义了。在这里我要申明,这篇文章我是写给有一定经验的程序员看的。对于没有什么经验的程序员,多写点代码总是好的(至少目前来看)。AI 能力的上限是由用的人的上限决定的。无论是任何行业,充分掌握领域知识后配合 AI 才是最好的做法。

就像下面这个例子,我只要说一句 add tanstack query provider 就能让 AI 帮我把 @tanstack/query 加到我的程序里。我自己会写,但我自己写可能要花一两分钟,但 AI 一下子就好了。

![cursor 截图]../../../images/telegram-cloud-photo-size-5-6165685253356765301-y.jpg

但如果你没有任何代码经验,你连 tanstack query 是什么都不知道,也不知道要放在程序的哪个地方,那用 AI 还是有点困难。

写下这篇文章是因为最近用 Cursor 有感,加上刚好看到 Daniel Nguyen 发了一篇 Software is Art, 有感而发,不吐不快。在此粗浅翻译(非 GPT),作为结尾:

I realize the reason I like building is not just because I’m a builder.

我意识到我一直喜欢创造点东西的原因不只是因为我就是个创造者.

It’s because software products are how I express my creativity.

而是因为写软件产品是我表达我的创意的一种方式

It’s like a poem to a poet, a song to a songwriter, a painting to a painter…

就像诗人的诗,歌手的歌,画家的画

Software is my art form, my medium of expression.

软件是属于我的一种艺术形式,是我表达(创造力)的媒介。

不上班的第一年

2024年5月14日 08:00

2023 年的 5 月,我离开了微软,开始了自己做产品的旅程。到现在刚好满了一年,这一年发生了不少事情,有些在 2023 年终总结里提到过,这一篇我想更详细地列出在这一年我具体做了什么、对自由职业的思考、对做产品的一些思考等等。

首先是我的产出,这一年我的产出主要是两个产品、一个播客。

两个产品

Notepal

离职后第一个认真做的产品是 Notepal, 这是一个用于把微信读书笔记同步到各个笔记应用的插件。我在这篇文章详细写过这个产品的起源和在做这个产品的时候的一些思考。我在做这个产品的时候完全没有想到,这个只卖 50 块的插件,在这一年帮我付了我一整年的房租。

EpubKit

epubkit

EpubKit 是另外一个我投入比较多的产品。这是一个把网页转成 ePub 电子书的工具。正式上线不到一个月,收获了几十个付费用户。

一个播客

刚好今年的 5 月份也是我和 GeekPlux 一起做的播客节目《代码之外》 的一周年。起初我们只是玩票性地做闲聊节目,后来因为有了听众来信的栏目,我们慢慢会讲更多职业发展方向的主题,这些主题意外地无形中对很多听众有不少的帮助。后来还邀请我刚工作就很欣赏的前辈勾股作为来信栏目的常驻嘉宾,为节目带来了很多很好的观点。今年在参加一些线下活动时,有些听众会跟我说从节目中得到了启发。从统计数字上看,我们好像的确是做了一件影响力不算小的事:

  • 小宇宙订阅数 6000+, 总播放量 11万+
  • Bilibili 粉丝 6000+,总播放量 13万+
  • YouTube 订阅数 2500+, 总播放量 3万+

在这一年,我对于做产品和生活都有了很多思考。对于不上班这件事,有人羡慕,有人好奇,刚好在这篇总结里,我想跟大家分享不上班的好处和缺点。

不上班的好处

时间自由

不上班的好处对我来说最明显的是时间自由。我是一个喜欢晚睡晚起的人,所以对我来说,准时上班是一件很难的事。不上班可以让我睡到自然醒,有充足的睡眠时间。

认识不同的人

上班的时候基本只能认识职场环境里面的同事朋友,或者在网络上交流的朋友。但是在自己做产品后,我开始认识一些同样是在做产品的朋友,和这些朋友可以聊得更深入。这些人往往对很多事情都有自己独特的思考。我从他们身上学习到非常多。我经常觉得如果我只是和以前一样在公司上班,业余写写博客和开源,我可能很难和这些朋友有共同话题,最多也只是互相点赞之交。

赤裸地直面市场

不上班后只能完全依靠自己赚钱,这代表我需要很赤裸地直面市场。

第一层赤裸,指的是脱离公司,作为一个个体,我可以给消费者提供什么他们认为值得为我付费的价值?

第二层赤裸,指的是一个产品如果脱离大公司本来就有的入口红利,我靠什么给我的产品带来自然流量?

这些都是很难的问题,但一旦开始学习,收获都是巨大的,而且都是属于自己的。在公司里最可怕的地方在于,我们很容易把公司给的平台误以为是自己的能力,很容易把流量看成是理所当然会有的。

也正因为如此,在这个过程中,我可以学习到很多以前不会主动学习的技能。

学习到更多技能

自己做产品的时候,没有公司平台给的入口,首先需要学习的就是如何做 marketing. 也是只有在自己做产品的时候,才会发现要别人发现你的产品是一件多么难的事。回想以前在阿里做业务,我们写一个营销活动页面,只要把入口放到某个栏位,基本不需要担心没有流量。

为了获客,我学会了研究 SEO, 学会了怎么做小红书,读了很多关于 marketing 的书。这让我学习了很多技术之外的知识,我觉得这些知识是终生受用的,而且它们不仅可以在互联网行业受用。

不上班的缺点

没有固定收入

不上班最大的缺点就是没有固定收入,这是很现实的问题。坦率地说,我以前买东西基本不看价格,只要觉得有价值,我就会买。没有固定收入之后,我买东西变得更加谨慎了。比如最近我很想买一台 Studio Display, 换作以前,无需多想,直接下单。但是现在,我会想我要卖多少份软件才能 cover 这台显示器,想想还是算了。

有时候我的朋友说羡慕我不用上班,我就跟他们说我这一年的收入还没有你们一个月赚得多,他们心理也就平衡了🤣。

孤独

可能有些人就是喜欢不用和别人交流,但对我来说,我是喜欢社交的,我在适当的社交中可以获取能量。不上班的时候,大部份的时间都是在家里写代码,看书,在网上和朋友聊天。有时候一整天都不需要开口说一句话。到后来我有点受不了,开始到外面的咖啡厅办公,只要能见到旁边有活人,就能有所缓解这种孤独感。

不确定性

上班有上班的不确定性要面对,不上班也有不上班的不确定性要面对。你无法确定这种生活可以维持多久,你的产品是否能卖得出去,就算卖得出去,它是否能养活自己,这些都是要面对的问题。

这些就是我体会到的不上班的一些优缺点,接下来,我想讲讲这一年在做产品的过程中我的一些思考和感受。

思考和感受

独立开发?

「独立开发」这个词在这一年非常火,用来标签像我这样自己做产品的开发者。其实我一直不称自己为「独立开发者」,因为我根本不想「独立」开发。我想做 scope 更大的事情,只是现在还没有条件。如果可以,我更愿意和两三个志同道合的人一起做产品。就像 61 的谜底科技,像少楠的 flomo.

而且自己做产品这一年,让我深刻地意识到,真正要做「独立」开发是很难的,因为没有人能擅长所有技能

没有人擅长所有技能

曾经我觉得只要我愿意去学,我就能做好。比如设计。我很注重产品的 UI/UX 设计,但我一直没有经过认真的设计学习和训练。我读了些关于 UI/UX 的书,以为就可以成为一个设计还不错的程序员。后来发现我错了,理论和实践之间原来有一条很大的鸿沟我虽然知道很多设计和用户体验的理论,但是一旦真正动手做页面,这些理论完全无法转换成实际的设计。

这是因为设计和写代码一样,是需要长期积累的。优秀的设计师可能有审美天赋,但他们一定也是每天都观察大量的设计,在自己的脑中内化了很多设计的模式(我不知道有没有专业的术语来形容),这些积累使他们可以面对一个新的需求的时候,根据自己内化的东西产生新的设计,这是我这种只读过一些理论的人无法做到的。正如会写代码的设计师,可能可以写一点能跑的代码,但缺乏多年的代码实践经验,是不可能像真正的专业程序员一样根据经验做好技术选型和想应该用什么设计模式(design pattern)的。

不过,我还是学会了在看到一些设计的时候,比以往更深入地去思考这个设计,这些元素为什么会这么摆放,颜色是怎么运用的,等等。

人的时间和精力是有限的

Notepal 和 EpubKit 同时做,让我更能体会到人的时间和精力是有限的。把时间放在一个产品 4 小时,那么另外一个产品投入的时间就永远少了 4 小时。而且上下文切换(context switch)是非常耗精力的。比如你正在修产品 A 的 bug, 这时用户报了产品 B 的 bug, 要从产品 A 跳转到产品 B 的开发,是很难一下子切换过来的。

所以不是自己一个人做产品就不需要项目管理,还是得学会充当自己的 manager 管理自己。给项目列好 roadmap, 排好需求优先级。

关于这个问题我还专门请教了图拉鼎,他告诉我要把自己当成不同的角色来用,比如规定上午作为客服,专门处理用户反馈,下午是程序员,专注写代码。这个方法也让我很受用。

自己做产品,同时要充当开发、marketing、客服、产品设计,我觉得这是「独立」开发的最大挑战。

学会专注

开发完 Notepal 后,我曾经陷入了很长时间的 burnout. 眼下赚的钱也不多,但又不知道应该做什么。期间有一些零星的 idea, 开发完后也不了了之。后来开发了第一版 EpubKit, 有了一些用户,之后又 burnout 了,因为开始觉得它做得不好,也很小众,渐渐又想放弃,想做点别的试试。

后来一些朋友「批评」我说我不够专注,我也开始反思,其实自己做的东西不算很糟糕,只是自己太着急,没有把它们都做得极致就失去耐性。经过反思,我决定好好打磨自己现有的产品,才有了现在这一版自己比较满意的 EpubKit.

乔布斯说专注不是指只做最好的,而是对其它也很好的东西 say no.

另外,缺乏专注很有可能会消耗用户对你的信任。

警惕「快速试错」

「快速试错」、「快速验证想法」是很多人做产品的信条,我相信快速验证想法是重要的,但是更重要的是交给用户的这个产品不应该是一个半成品,它最好是一个 Finished software. 也就是说,即使你不再维护这个产品,它还依旧是个可用的软件。

我曾经也「快速试错」,发布了一些产品,最终不再维护,甚至还有几个用户付费了。我对这种「试错」是愧疚的,因为这很有可能伤害支持你的用户。因此我现在反而发布新产品会更加谨慎,要把用户的感受放在第一位。

这篇文章很好地表达了这个观点。

总结

以上就是不上班的一年我对自己的一些思考的总结,希望对读到的朋友有帮助。这一年我其实算是比较幸运的,虽然收入微薄,但做产品也算是能卖出去,能解决很多人的需求。但同时我还是处于迷茫的阶段,认为自己做的产品还是小打小闹,scope 太小。我还是希望将来能做出满足更大众需求的产品,覆盖面能更广。

我的这些观点不一定对,但也能让读者感受到一个程序员脱离公司的其中一种可能性。

在 Electron 中使用 SQLite 的最好方式

2024年4月22日 08:00

上周刚刚发布了一个用 Electron 的应用 EpubKit. EpubKit 是一个把网页制作成电子书的工具。在 EpubKit 里,我需要一个数据库来存储内容,最好的选择是 SQLite.

但是,由于 Electron 有 renderer 和 main 区分开的机制,所以在 Electron 中使用 SQLite 会非常麻烦 —— SQLite 的执行要在 Main process, 但调用要在 Renderer process. 在 Electron 里,Renderer 和 Main process 之间的通信是通过 IPC (Inter-Process Communication) 实现的。也就是说,我可能需要把每一个有关数据库操作的业务逻辑单独写成一个 IPC 通信的事件,然后在 Renderer 里调用这些事件。

我想要做到的是,我在 Renderer process 中直接调用 ORM, 但实际的执行是在 Main process 中。这样一来我就不需要单独地写很多个 IPC 事件了。

例如:

万幸的是 drizzle 居然有一个 HTTP Proxy 的机制。这个机制能让你所有的 ORM 操作都流到一个地方,在这个地方你能拿到最终生成的 sql 语句,然后你可以自己决定怎么执行这个 sql 语句。

也就是说,我可以在这个 proxy 里,把 sql 语句通过 IPC 发送到 Main process, 然后在 Main process 里执行这个 sql 语句。

接下来我会简单描述一下我在 EpubKit 里是怎么做的。

编写 Schema

在你的项目里找一个地方,把 drizzle schema 写下来:

import { int, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const posts = sqliteTable('posts', {
  id: int("id").primaryKey().default(0),
  title: text("title").notNull().default(""),
})

在 Renderer 里创建一个 drizzle database 实例

根据 文档, 在创建 drizzle db 实例的时候,可以传入一个函数,这就是 proxy 的本体。我们要做的是在这个 proxy 里,拿到 ORM 最终生成的 sql 语句、执行方法、变量,然后通过 IPC 发送到 Main process.

export const database = drizzle(async (...args) => {
  try {
    // 通过 IPC 把 SQL 发送到 Main process
    const result = await window.api.execute(...args)
    return {rows: result}
  } catch (e: any) {
    console.error('Error from sqlite proxy server: ', e.response.data)
    return { rows: [] }
  }
}, {
  schema: schema
})

这里有一个 window.api.execute(), 是怎么来的呢?其实是在 preload 进程里面定义然后暴露的, 它的作用就是通过 IPC 发送 sql 语句到 Main process:

// preload.ts

const api = {
  execute: (...args) => ipcRenderer.invoke('db:execute', ...args),
}

也就是说,实际上我们以上做的事情就是,通过 proxy, 把 SQL 语句通过 Main process 里的 db:execute handler 最终执行。

Main process

在 Main process, 我们创建一个 IPC handler:

// main.ts
ipcMain.handle('db:execute', execute)

这里的 execute 就是 Main process 里最终执行 SQL 语句的函数。

import { drizzle } from 'drizzle-orm/better-sqlite3'
import Database from 'better-sqlite3'
import { migrate } from 'drizzle-orm/better-sqlite3/migrator'
import * as schema from '../renderer/src/db/schema'
import fs from 'fs'
import { app } from 'electron'
import path from 'path'

// 初始化 sqlite
const dbPath = '../databse.db'

fs.mkdirSync(path.dirname(dbPath), { recursive: true })

const sqlite = new Database(
  dbPath
)

// 创建 drizzle 实例
export const db = drizzle(sqlite, { schema })

// 这里是 execute 方法
export const execute = async (e, sqlstr, params, method) => {
  // 得到执行需要的参数后,用 better-sqlite3 执行
  const result = sqlite.prepare(sqlstr)
  const ret = result[method](...params)
  return toDrizzleResult(ret)
}

function toDrizzleResult(row: Record<string, any>)
function toDrizzleResult(rows: Record<string, any> | Array<Record<string, any>>) {
   if (!rows) {
    return []
  }
  if (Array.isArray(rows)) {
    return rows.map((row) => {
      return Object.keys(row).map((key) => row[key])
    })
  } else {
    return Object.keys(rows).map((key) => rows[key])
  }
}

在上面的代码中,我额外实现了一个 toDrizzleResult 的方法,是为了把 better-sqlite3 的返回值按照 drizzle 需要的结构返回。

到这里,你就已经可以在 Renderer process 里直接用 drizzle 了:

function App(): JSX.Element {

  const [postList, setPosts] = useState([] as any[])

  useEffect(() => {
    database.query.posts.findMany().then(result => {
      setPosts(result)
    })
  }, [])

  return (
    <div>
      <div>
        <form onSubmit={async e => {
          e.preventDefault()

          const formData = new FormData(e.target as HTMLFormElement)
          const title = formData.get('title') as string
          if (title) {
            await database.insert(posts).values({
              id: Math.floor(Math.random() * 1000),
              title
            })

            // refetch
            const result = await database.query.posts.findMany()
            setPosts(result)
          }
        }}>
          <input name="title" type="text" placeholder="title" />
          <button>add</button>
        </form>
      </div>
      {postList.map(post => {
        return (
          <div key={post.id}>
            {post.title}
          </div>
        )
      })}
    </div>
  )
}

export default App

但这时候执行,会报错。原因是我们还没有初始化数据库。我们需要在 Main process 里初始化数据库。

首先需要用 drizzle-kit 生成 migration 文件。在 drizzle.config.ts 中指定了 migration 文件的地址:

// drizzle.config.ts
import type { Config } from 'drizzle-kit'

export default {
  schema: './src/db/schema.ts',
  out: './drizzle',
  driver: 'better-sqlite'
} satisfies Config

然后写一个 runMigrations 方法,用来初始化数据库:

export const runMigrate = async () => {
  migrate(db, {
    // 在 drizzle.config.ts 里指定的路径
    migrationsFolder: path.join(__dirname, '../../drizzle')
  })
}

这个方法需要在 Main process 启动时执行的:

async function createWindow() {
  // ...

  await runMigrate()
  createWindow()

  //...
}

实例源码

你可以在 这里 找到这个示例的完整源码。

特别感谢 EGOIST 提供灵感。

读《岩田先生:任天堂传奇社长如是说》

2024年1月5日 08:00

《岩田先生:任天堂传奇社长如是说》封面

虽然我有 Switch 游戏机, 但我不是游戏的发烧友,对任天堂及其社长岩田聪更不甚了解。前些天听《半拿铁》的《任天堂往事》系列,对任天堂的发展有了一些了解,也听闻岩田聪同时是一个非常出色的程序员,所以开始对岩田聪产生了一些兴趣,于是找到了这本收集了岩田聪说过的话的书,希望能一睹这位天才程序员对管理企业和写程序有哪些独特的见解。

这本书不长,读完后我对岩田聪确实有了更多了解。首先是从他身上学到了一些管理企业的方法。

岩田聪的管理风格非常务实和「接地气」,他讲到他喜欢和员工一对一面谈:

我在与全体员工谈话的过程中,发现了许多“经过面谈才头一回意识到的事情”。就算对方是一向保持着沟通的人,也有在一对一的场合才讲得出口的话。这样说或许不太恰当,但我重新认识到:“假如不制造推心置腹的机会,人是不会敞开心扉的。”

在书的最后有宫本茂和糸井重里谈岩田先生的追忆文章,其中糸井重里回忆说:

虽然是第一次见面,但他的话语让人觉得值得信赖。岩田先生曾回忆说:“第一次见面时我也相当紧张。”但我一点也没看出来。“在已有基础上修改,还是从头做起?”这句话单从字面上看会让人觉得不够谦逊,但岩田先生完全没有居高临下的姿态,而是传递出十分看重对方自由选择的权利的感觉。怎么说呢,原本是我们请他来帮忙,但在技术问题之外,岩田先生工作方式的魅力也令我们深受感触,见面次数越多就越发信赖他。

结合我从前被管理的感受来看,这让我意识到,管理者能给被管理者足够的信任感是非常重要的,而信任感可以来自于谦逊和务实。

岩田聪还对公司的会议规定必须有一位「会议统筹」:

所谓“会议统筹”,就是让会议良性运转的人。如果会议中缺少创意,就负责添加创意;如果创意太多,导致过于发散,就负责归纳总结。简言之,就是会议的指挥。无论什么会议,都必须有一个决心“要在会议上得出答案”的统筹者。

我们在厂里工作过的都知道,很多时候会参加一些没有结论的无用会议,如果每次会议都能指派一个这样的「会议统筹」,相信大家的效率会提高很多。

从岩田聪的谈话中,我感觉岩田聪是一个非常能够洞悉到他人内心感受的人,所以在推进项目的时候,也会非常照顾同事的感受:

世界上许多改革都是运用否定现状的逻辑推行,但这样的做法会让很多人陷入不愉快。因为当下的现状正是许多人的心血、诚意、热情构成的。如果现状由不诚实的东西构成,去否定也无妨,但由诚实的产出构建的现状,不应该被否定。

也许正是这样的性格,才能让岩田聪清楚洞悉玩家的感受,从而做出改变世界的游戏。同时,也是因为他是真正有「给别人带来快乐」的强大 passion:

岩田先生发自内心地喜欢看到大家的笑容。他也将这个目标列入任天堂的经营理念。的确,他是一个希望给世界创造更多快乐的人。并且,他是一个为了实现这个目标不惜舍身奉献的人。他喜欢帮助他人,喜欢钻研各种事物,也喜欢为此而沟通交流的过程。所以说,每周一与宫本先生一起吃午饭的时间,凝聚着岩田先生所喜爱的一切。因为他们一起讨论着游戏创意,说着“我懂了”,试图给自己与玩家都带来笑容。

我一直觉得,能成大事的人,都是那些内心有一种很强大的 passion 的人。我虽然不是资深玩家,很难从游戏中感觉到快乐,但从岩田先生的谈话中,我还是为他的这种 passion 所感动。

如果你本身是一个玩家,可能会对这本书有更深刻的理解。

最后,用岩田先生的话结束这篇读后感:

在我的名片上,我是一名社长。在我的头脑中,我是一名游戏开发者。但在我心里,我是一个玩家。

On my business card,I am a corporate president.In my mind,I am a game developer.But in my heart,I am a gamer.

名刺のうえでは、わたしは社長です。頭のなかでは、わたしはゲーム開発者。しかし、こころのなかでは、わたしはゲーマーです。

读 React 18 文档有感

2024年1月4日 08:00

昨天 Sixian 提到了 React 的新版官方文档,之前一直没有去读,今天抽空读了其中 Escape Hatches 的部分,有一些收获,也有一点感想,在这里简单分享一下。

声明:我经常使用 React, 但我不是 React 的专家,我也不再是一个对技术会进行非常深入探究的人了。所以对于 React 最新的一些 API, 可能对某些人来说是老生常谈,但对我来说是新鲜的。所以本文只是简单分享一下我看到的之前不知道的一些 API.

sixian 的 Tweet

跑两次的 useEffect

开发环境 useEffect 跑两次是故意的,是为了帮助开发者在开发环境中发现你是否正确地给你的 effect 做了 teardown.

The right question isn’t “how to run an Effect once”, but “how to fix my Effect so that it works after remounting”.

如果你的代码因为 useEffect 跑两次所以出问题,很可能你用错了 useEffect.

Alt text

讨论这样的特性是否是一种傲慢对我来说意义不大,重要的是我理解了其动机。

flushSync API

React 有一个 flushSync API, 可以强制 update DOM. 在以前我们一般是把希望在 DOM 更新后才执行的代码放在一个 setTimeout 里.

Alt text

如果想重置一个 Component, 直接给它一个新的 key

如果希望某个 component 的 props 被改变的时候做一些重置,应该直接给这个 component 赋一个新的 key, 使 React 直接重建整个 DOM, 而不是用 useEffect 手动做重置工作。

其实以前我也经常这么干,比如 Modal 在关闭和打开后重置里面 Form 的值,我会直接给 Modal 一个新的 key. 一直不知道这是否是一个 best practice, 现在得到了官方认证。

Alt text

useSyncExternalStore

这是一个我不知道的 Hook, 看起来很适合用于把别的库移植到 React 时使用,而且它对 SSR 非常友好。

一些感想

很多人觉得 React 繁琐,心智负担特别大,我也这么认为。但我一直觉得,这不是 React 本身的问题,而是 JavaScript 的问题。

React 是一个特别函数式编程思维的框架,但很可惜,JavaScript 只是一个半吊子的函数式编程语言,它只是在被设计的时候学了一点 Lisp 的皮毛,也提供了一点点函数式的 API, 但它没有很多真正的函数式编程语言应该有的基本特性,才导致了我们要写额外的代码来解决一些问题。

例如,Memoization 在一些函数式编程语言里是标配,但 JavaScript 里没有,所以你需要给函数手动套一层 React.useCallback.

函数式编程语言里, Immutable 也是标配,而在 JavaScript 里,需要用 Immer 之类的第三方库。

所以这就是为什么在多年前我很看好 ReasonML (现在叫 ReScript) 这个语言,因为它本身就是真正的函数式编程语言(它是基于 OCaml 的 JavaScript 方言),你会发现,用它来写 React 是多么舒服的一件事,因为语言本身就提供了你在 JavaScript 里需要调 API 才能实现的功能。有趣的是,React 在刚开始设计的时候用的就是 OCaml.

成也 JavaScript, 败也 JavaScript.

2023 年终总结: 和自己对话

2023年12月22日 08:00

可在小宇宙收听本文音频版

变化

2023 年初,持续了 3 年的疫情封控结束了,整个社会迎来了一个转变的开端,没人知道会变好还是变更糟糕。随后 3 月,我决定离开微软,我自己也迎来了一个转变的开端,我也不知道会变好还是更糟糕。

我财务自由了吗?如果财务自由有一个绝对值,那么无论是多少,我肯定都没有达到。离职后有很多朋友问过我这个问题,现在刚好可以在博客也跟我的博客读者分享:当我在考虑不工作时,我在思考什么?

1. 如果继续现在的状态,那么 3-5 年内我会有什么不同?

这是我在考虑是否入职微软之前用的同一个方法,是我朋友教我的。当年我觉得如果不入职微软见识见识,我一定会后悔,留在原来的公司也不会有太大的变化。今天即使我已经离职了,但我很感谢我有选择微软,我的收获非常多。所以我运用同一种决策方式来思考,即使我在微软继续工作 10 年,很大可能我得到的只是 title 和薪水的不同,这和我的目标背道而驰。这也引出了我的第二层思考:

2. 我正在做的事和我的长远目标是否对齐?

过去我会担忧和焦虑我达不到目标,后来我醒悟:没有人可以控制结果,只要我正在做的事是朝向我的长远目标就可以了。继续工作显然不是。

3. 没有固定收入怎么生活?

我有一点积蓄,虽然不多。很多人存了钱,买了房子。而我用我的积蓄买一段可以不工作的时间,我觉得还是很值得的。而且我不工作也不是天天躺着什么都不做,只要朝着我的目标在努力,这也算是一笔投资。

幸福之道

离开公司后,我的心情很复杂。我觉得我一直想寻找一个答案,但实际上我连问题是什么都不知道。我想起了年轻时读的《刀锋》,应该像书中的拉里一样去寻找,于是 7 月份我去了泰国,得到了一段出乎意料的佛教哲学之旅

创造

今年的输出比我预期的要更丰富一些。

视频创作

继 2022 年的 Logseq 分享视频,今年又做出了一个超 50,000 播放量的视频《我如何做笔记》

《代码之外 Beyond Code》播客

今年终于和 GeekPlux 一起把盘算了多年的项目真正做了出来,意外地得到了很不错的反响。甚至能在线下聚会的时候听到一些我们的听众表达的感谢。

其实节目的制作形式受到了很多我喜欢的不同的播客节目,我由此也更深刻地感觉到,一个人能做出什么样的东西,很大程度上取决于其接触、输入的东西。只有吸收优秀的东西,才有机会做出优秀的东西。

这跟做产品也很像,如果一个人从来没有体验过真正优秀的产品,那就很难做出优秀的产品。所以我总是鼓励一些朋友,不要因为一个产品要花钱所以不去用它,就算只买一个月,也要去体验一下。

Randynamic Studio

离职后我就计划把我之后做的所有小工具统一到 Randynamic Studio 的名下. 很幸运,它的真正意义上的第一个产品 Notepal 算是非常成功。它没有为我赚巨额的钱,但它解决了很多人的需求,并且这些人愿意为它付费,这是我写在博客首页很多年的一个目标,在今年终于实现了。

多年来我把 Y Combinator 的 slogan 一直放在心中,有很长一段时间我每天睡醒后心里就会自动播放这句话:

Make something people want.

很幸运我朝着这一个目标又迈进了一步。

线下聚会

解除封控后,终于可以参加一些技术圈子的线下聚会了,也有机会见到一些相识多年但从未谋面的网友。

先是参加了佐玩开发者交流会,见到了很多很年轻的后辈,更惊喜的是很多是《代码之外》的听众,他们都说在节目中收获到了很多。在那一瞬间我觉得我做的很多事情都是有意义的。

然后我到杭州找了图拉鼎,见识了数字游民的聚合地「玉鸟集」。在那里还认识了非常多的独立开发者和做产品的人,大家都很有自己的想法,对自己做的事情有自己的理解,有自己的观点,自己的品味。这种类型的朋友是很难在工作的时候遇到的。

总结

2023 是我和自已对话的一年,我开始了解自己想要的是什么,了解自己的情绪,了解自己擅长的是什么,不擅长的是什么,了解自己追求的是什么,等等。在清迈,我学会了倾听内心的声音,我也意识到,在真正了解自己的情况下,做决定似乎没有那么难了。

展望

我其实很希望在 2024 年能做一些 scope 更大的事情,同时也需要找到和我有相同 passion 的人。我一直不称自己为「独立开发者」,一是我觉得我还没达到,二是这也不是我的目标。我的目标一直是两三个有同样追求的人组成一个小 team 做一个美且在商业上可行的产品。

希望自己能往目标再迈进一大步。

开发一个浏览器插件在第三天卖出 1000 元

2023年7月30日 08:00

写下这篇文章是我的插件 Notepal 发布的第三天,目前收获了几十名付费用户,在这短短几天已经有 5000 多条微信读书笔记被同步到 Readwise, flomo 或 Obsidian 中。

(28 号没有数据是因为那天出了事故,日志没有进来。)

很感谢点进这篇文章的你没有因为 1000 元是个小数目所以选择无视,这个数目确实很小,它甚至没有很多程序员坐在办公室待一天赚得多,但「有人愿意购买」的意义远比数目的大小对目前的我来说意义更大,而且我在开发和上线整个过程中学习到了不少,也实践了不少我读的一些关于 start a business 的书,我发现在亲身经历了这个过程后,再重读这些书,体会更加深刻,所以我很想在这篇文章和大家分享我学到的,以及我所采用的一些方法论。

最初的需求

我在差不多半年前因为想把微信读书的笔记同步到笔记软件 Readwise, 所以写了一个很简单的网站(Notepal 的前身),可以把微信读书 App 里复制出来的笔记,解析成自定义的格式,也可以解析成 Readwise 能实别的 csv 格式。

虽然这种方式还是有点繁琐,而且 csv 格式其实很不稳定,很容易被笔记里的一些字符导致导入失败,但在此之前我想基本没有人可以这么「自动化」地做到这件事了。

我把它发布到了 V2EX, 写了点介绍,并且代码是开源的。

但是,在当时,我隐约觉得这个需求会有人愿意买单,因为我相信绝对不止我一个微信读书和 Readwise 的共同用户有这个需求。但我当时刚好在读 Sahil Lavingia 的 The minimalist entrepreneur 这本书(在接下来的内容我会多次提起这本书),里面有一个让我感触很大的观点—— start with community, 创业从社区开始。

什么意思呢,如果你觉得你能解决一个很多人都有的需求,首先要做的不是急着做软件做产品,而是先找到这群人,在这个群体里帮助他们。

所以当我隐约认为我能解决一部分人的需求且他们有可能为此付费时,我做了一件和开发完全没有关系的事——建用户群,然后放到网站上,我希望把有这个需求的人先聚集起来,等有一天我把这个工具做得比较稳定的时候,有一个卖出去的机会。

后来加进群的一共 50 多个人,这些人其实也没怎么说过话,有些人提了一些使用问题,然后群就基本死了。

大部份的人反馈的问题都是 csv 出问题,这个问题很难解决,我觉得如果要稳定,必须通过调用微信读书的接口,拿到 json 格式的笔记,然后通过 API 同步到 readwise. 所以我一直想把这个需求用浏览器插件来解决,我在群里也提了一句「我准备写一个浏览器插件」,但是也没人理。

于是我就把开发插件的事情搁置了。

转折,冷启动

从这个工具发布一直过了半年,突然有位推友发了一条推,对我这个工具表达了感谢:

这不足以让我惊讶,最让我惊讶的是这条推的数据:113 转推6 引用373 喜欢次数237 书签。

这让我有了动力去把我曾经想实现的插件写出来,我决定先快速做一个 MVP, 只要实现在微信读书页面展示有笔记的书,并且用 Readwsie 的 API 一键同步笔记,最后展示同步到 Readwise 后的笔记。

为什么要这么做?因为我需要做一个「半冷启动」,我知道把插件打磨到可以上线并收费的工作量不算小,但我需要做一个流畅的视频,来展现这个 idea, 并且是一个真实的实现。把这颗小石头抛出来,看能引起多大的水花。

把视频发出来后,引起了不少的回复:

这时我决定要做出来一个真正值得被这些人购买的产品,解决他们的需求,让他们心甘情愿地因为产品解决的问题和体验而买单。

从冷启动到正式上线

在写正式的产品前,我问自己一个问题,做到什么程度可以发布第一个版本。我心中的答案是这样的:

  1. 为了尽快上线,只做同步到 Readwise 的功能
  2. 上线 day one 就要开始收费,可以提供免费试用,但一定要有收费入口
  3. 体验一定要最直接——填 API token -> 选书 -> 同步 -> 查看同步到 Readwise 的笔记,一气呵成
  4. 要记录一些非隐私日志,例如同步笔记的量,错误日志

尽快发布

第一点,很多人肯定会觉得,Readwise 这么小众,同时用微信读书和 Readwise 的更小众,会不会太少人用了。这是正确的判断,但是我认为我的当务之急是把产品 ship 出来,解决我能真实看到的那不到 10 个人的需求,看能不能从如此利基(niche)的圈子赚到钱,再谈扩张用户量(而且我很快在后面的版本支持了 flomo 和 obsidian)。

Day One 就要收费

第二点,有人会说,这么小众的需求,真的能赚到钱吗?我认为,可以,但看你是想赚大钱还是小钱,小众需求难赚大钱,但越小众的人越愿意付费。我已经对这个产品有了预期——我不认为这是能赚大钱的产品,我对这个产品的目标是:解决小部分人的需求,让他们为产品提供的价值付费。

为什么要赚钱?其实我大可以免费发布,我也完全不能靠这个产品吃饭。但和多年前的我不一样,我现在觉得「用户掏钱买你的产品」是验证你的产品价值最有用的方法,无论是便宜还是贵,即使是 1 块钱,就和免费完全有不同的意义。就像打德州扑克,用你真实的钱打和用游戏币打完全是两回事

既然要收费,就有两个问题:一是收多少,二是怎么收。

收多少的问题,首先有两个选择,一次性买断和订阅制。不过像这样的产品,我觉得理智的人都不会觉得适合订阅制。谁会为了一个低频需求订阅一个插件?

如果是买断,多少钱合适呢?我没有做什么调研,就拍脑袋觉得 30 块是个不高也不低的价格,而且是一次性收费。如果用户觉得好用,还是比较大概率选择购买的。

最难的问题其实是怎么收,尤其是这个产品面向的是国内的用户。众所周知,国内的付费渠道接入门槛是相当高的。可能做这个插件也就几天的事,但接入收费渠道就要几周。这是不能接受的。就像 Paul Garahm 说的:Do things that don't scale.

为此我想了很久,于是想出了一个办法。这也是在 The minimalist entrepreneur 这本书受到 Sahil Lavingia 的启发,他说 Gumroad 第一个版本是他自己每个月手动给 creator 发钱的。

我大受震撼,我想到,我这个产品,能不能卖得出还是个问题,即使能卖,也不可能卖很多,很频繁地交易,我何不像路边滩一样挂个收款码解决呢,只是我把收款码放到一个「购买页面」而已。

于是有了这个购买页面

但是,即使我能通过收款码收钱,那如何和我的插件联动,在用户付钱后解锁功能呢。我想到最传统的软件售卖方式——卖激活码,用户通过付款码值钱备注邮箱,当我收到款后,往他邮箱发送激活码,就完成了。

流程有了,但激活码怎么来?没有办法,这个还是要自己写点代码。我花了半个小时,用 Next.js + PostgreSQL 写了一个最简单的激活码生成和验证的 API service.

激活码机制也有了,但手动发激活码还是麻烦。所以我用写了一个「快捷指令」,只要填邮箱发到我的激活码 API service, 就会自动完成从创建激活码到发送邮件一整个步骤。虽然还是手动,但我的工作就变成了收到钱,运行「快捷指令」填邮箱。

读到这里,读者应该可以深刻地体会到,Paul Garahm 所说的 Do things that don't scale 是什么意思了。我觉得在做产品的时候,一定要瞄准最重要的事情——你给客户提供的价值是什么,而不要在其它地方花太多的精力,在这些地方甚至可以先手动做一些事情,在成功了之后再把他自动化,而不是一开始就自动化。

读者应该看过一个 meme 图,一个 ATM 机,其实背后是一个人手工把钱塞出来。这个图有点搞笑,但这是一个完美的 Do things don't scale 的例子,客户需要的是拿钱,用户并不关心你背后是多简单或多复杂的流程。新产品上线,最重要的是解决客户的问题,而不是怎么解决得比较优雅。很多工程师很容易陷入一种「自动化」的诱惑,想把一切都做得最自动化,然后忽略了真正在解决的是什么问题。

自动化可以做也必须做,但不是从 day one 就开始做。

用户体验

对于体验,我在上文从冷启动的视频到上线版本都强调了「查看同步到 Readwise」的笔记,很多人可能觉得这是一个可做可不做的功能,而且这是一个从技术上来说非常简单的功能。但我觉得这是整个产品最重要的 aha moment, 我要让用户能看到笔记一键就被放到了笔记软件里面的样子,而不是只是提示同步成功,让他自己去笔记软件查。这个体验,做和不做在技术上没多大区别,但对于体验来说是有天壤之别的。

记录日志

记录日志也相当重要,尤其是错误日志,在上线以后,有一些我自己的场景没有 cover 到的 case, 都通过用户反馈然后我看错误日志成功解决了。另外,行为日志也蛮重要,可以看到自己的产品有没有被使用,使用的量有多大,从而帮助自己做一些产品决策,也是一种对自己的激励。

上线,卖出去

如果是以前的我,我一定会有一种迷思,认为产品发布上线后,就等着她被传播,如果运气好,被大 v 传播,就有流量,就能变现,如果运气不好,可能就是没人有这个需求,这个产品就失败了。

但读完 The minimalist entrepreneur (我又提到这本书了),我对销售有了很不一样的理解。书里提到,大部分的产品,头 100 个付费用户是一个一个谈来的,只有用户足够多以后,才会出现口口相传的情况。而且广告是没用的(如果不是一个以流量为核心的产品)。

Eventually strangers will buy your product, but mostly because your customers are spreading the gospel of your business and product, not because they saw an ad. But it will take time to get there. It’s not something you hit on day one.

所以我这次上线没有被动地等待,而是主动出击,在互联网上搜索关键词,找到和我有一样需求的人,评论和私信他们,告诉他们我也有一样的需求,并且做了一个十分方便的插件,请他们试一试。

刚开始这样做的时候,我还是有点羞耻,觉得自己是在互联网上发布垃圾广告,但客观来说,我是作为有同样需求的人,分享我自己做出来的可以解决他们需求的工具,好像也不算垃圾广告。而且让我惊喜的是,很多人回复都很友善,并且感谢或最终购买了我做的产品。

这也让我想到,做产品,首先要想的不是怎么做,而是卖给谁。这是最重要的问题。如果连自己都不知道目标用户,又谈何 marketing 呢?

总结

一口气写了很多,从发布上线到现在其实也才三天,其中有一天还发生了一些事故,但还是给我自己上了很重要的一课,相信我分享出来的这些也能给大家一些启发。

虽然赚的不是什么大钱,但这对我来说是非常有意义的一次体验。就像我在博客的首页写的,小时候我的理想是改变世界,现在长大了,发现能做出用户愿意付费的有为用户提供价值的产品已经很不容易了。这是我第一个发布的付费产品,而且还收获了愿意付费的一些用户。我读了很多关于创业、产品、用户体验、营销的书,等这一刻已经等了很久了。

第一次听到到账 30 元的通知的那种激动,我想会是一辈子都不会忘记的。在厂里拿 30k, 代表我面试表现还不错,也能写出公司愿意付钱的代码,但卖产品拿 30 块,代表我洞悉了需求、直面了市场(这是说出来简单,但做的时候很难的事)、为付费用户解决了问题。

非常感谢这些用户,这对我来说是很大的激励。谨以此文作为我对大家的回报。

在清迈冥想学习 7 天后,我不再「追求」幸福

2023年7月3日 08:00

在清迈结束了一周的禅修学习,想把自己的体验和感悟写下来,才发现这些我感觉不可思议的体验,用文字和图片表达出来是多么的苍白。

事缘起年初意识到自己的心理健康状态不再适合继续工作,遂辞职休息。刚好看到早见小姐分享了她在巴厘岛冥想的点滴,才发现泰国清迈有寺庙提供冥想学习。于是当晚就找好了寺庙,订下去泰国的机票。

我在出发前一直在想这次远行学习到底能不能符合我的期望学习到「真正的」冥想技术。一周下来,我的感觉是这一周学习到的和体验到的远远超出我的期望。我不仅在老师的带领下练习冥想,还对佛教有了新的认识。

通往幸福的道路在哪里

我到的第一家寺庙是 Wat Umong, 中文应该译作乌蒙寺。我在这里待了五天四夜。Umong 基本是靠自己练习,没有系统的教学。这家寺庙在丛林里,所以特别贴近自然。

寺庙虽然没有强制不使用手机,但我在第一天开始就尽量不用手机了,只限制自己一些时间查看是否有重要信息,其余时间都是飞行模式,把手机当作相机用。

当身边没有任何可以让你转移注意力的介质(手机、电脑、互联网)的时候,内心就像被放了一个扩音器,一点微小的想法都会被放大和延伸。这让我真正地了解了自己内心的声音。

在离开 Umong 的前一晚,我和另一个中国人和一个俄罗斯人一起在黑夜中喝茶。这位俄罗斯朋友带了普洱和茶壶,跟我们两个中国人科普茶道。我们从 9 点聊聊到凌晨一点,聊了关于冥想的体验,我们各自的烦恼。我说当我在冥想的时候,我总是会想到未来的事,在这几天的冥想练习,我才发现原来我的内心一直纠结在我想像的未来,我一直找不到我的快乐和幸福在哪里,于是我很痛苦。

在黑夜中喝茶聊天

俄罗斯朋友(大意是)说:Don't think too much. Focus on where you are, what you have, and what you can do with what you have.

我从他的回答得到了很大的启发。我一直在寻找快乐和幸福,以为它们在前方,我需要走一些路去找到它们。但我忽略了「当下」,在我已经拥有的东西,和当下我做出来的事情中感受它们。我也终于理解了寺庙里其中一棵树上挂的一句话的含义:There is no path to happiness, happiness is the path.

there is no path to happiness, hapiness is the path

那晚我们还聊了很多,那一刻我希望时间可以过得更慢一点,可以在这样宁静的夜晚多待一下。萤火虫在我们身边飞来飞去,远处还有虫鸣,还有壁虎的叫声(我第一次听到壁虎也有叫声)。

第二天早上我们一起到寺庙的洞穴里面,那时还没有游客进来,我在洞穴里冥想了一会儿。然后俄罗斯朋友带我们去了附近的一个动物园,他说那里有一只会讲泰文的鸟。我不知道这种鸟叫什么(应该不是鹦鹉),我们听到它竟然会讲几句不同的话,还会唱一段相同的旋律。

三人一起在洞穴

临走前,俄罗斯朋友竟然送了我一个茶杯。

下午我就离开了 Wat Umong, 出发到 Wat Suan Dok.

介于哲学和信仰之间的佛教

到达 Wat Suan Dok 的 Monk chat office, 首先是我们接下来三天课程的老师 Phra K.K. 跟我们教授关于冥想和佛教的基本知识。K.K. 讲了差不多一个半小时,我学到非常多。后来在去冥想中心路上我和其它学员聊天,我们都一致认为我们学到了超出了我们预期的知识。这也让我们对接下来三天的学习很有信心。我们这一期一共有 15 个学员,来自世界各个地方,英国、美国、中国、西班牙、印度、新加坡、韩国等等。

教学内容

在冥想中心,我们被要求一切都要慢下来。走路要慢,即使敲钟集合,一定不能急着过来,必须慢慢走。吃饭的时候,需要 eating mindfully (中文应该就是「正念饮食」),慢慢地把食物送到嘴里,慢慢地咀嚼,感受食物。

这是个小小的改变,但是三天下来,我的内心状态因此有了翻天覆地的变化。远离社交网络、做事慢下来,让我得到了内心的平静。我们从小就被鞭策一切都要快,要「抓紧时间」—— 上课铃响,要赶紧跑回教室;在学校吃饭,每次都要被老师催要吃快点回宿舍休息;走在路上,明明没有很赶时间,步伐也要很快。

当我开始把步伐慢下来的时候,就发现肢体上的缓慢,会使得内心变得平静。反过来,当内心开始胡思乱想,肢体动作就会开始不自觉地变快。有好几次,我在缓慢行走时开始分神,回过神来发现自己走得越来越快。

在第二天的讨论环节,K.K. 解答了我们很多问题,正是这些讨论,让我对佛教有了全新的理解。

我以前认为佛教是一种迷信,因为身边接触到的跟佛相关的东西,无非是「求神拜佛」。现在我才知道,佛教反对迷信。佛教不解释人是如何被创造的,没有像上帝这样创世的神。佛教是教人如何摆脱痛苦的。佛教让你相信你自己,而不是相信别人,也不是相信佛。只有你自己可以帮你自己摆脱痛苦,而不是相信一个神可以帮你。只有你自己去体验过,你才能去相信。

老师说,每个人都可以顿悟,只要持续练习(冥想)。佛陀叫作 Buddha, 意思是觉醒的人(the awakened one),每个人都能是 Buddha.

佛教是介于哲学和信仰之间的东西。我被其哲学的部分深深吸引。

知名投资人 Naval 把自己的生活哲学称为「理性佛教」,这也是我今后打算不断探索的一块。我想学习佛教中对人生、痛苦的理解,形成自己的生活方向盘。

对我来说,理性佛教意味着理解佛教所倡导的内在修行,以此让自己变得更快乐、更富有、更能活在当下、更能控制自己的情绪——成为一个更好的人。

所以,我的人生哲学就包含这两个方面:一方面是进化论,进化论是约束性原则,因为它解释了关于人类的诸多问题;另一方面是佛教,佛教是关于我们每个人内心状态的精神哲学,是最古老、最经得起时间考验的哲学。我认为这两点并不矛盾,可以相辅相成,互为补充。

—— Naval

出家的佛教徒需要遵循很多戒律,因为佛教认为痛苦来源于欲望。你的欲望越多,你将拥有的痛苦就越多(The more you desire, the more you suffer)。今天你买卡西欧,明天你就想要劳力士,于是你痛苦。有一天你得到了劳力士,就会发现不过如此,你的欲望让你还想要别的,于是你痛苦。

当然我只是一个普通人,一个带点野心活着的普通人,我不会遵守严苛的戒律,但通过冥想练习,我似乎更有能力从客观的角度观察(aware of)到我此刻的冲动的来源,从而冷静地思考是否要做出下一步的行为。

智慧是一种知道个人行为的长期后果的思维能力。 —— Naval

使人直面内心的冥想

在冥想的一周里,我基本没有怎么说话。但当我在进行冥想练习时,我实则和自己的内心对话了数千次。冥想能锻炼我们对情绪的觉察能力。我在头几天的冥想练习里,头一回通过观察我走神时不自觉思考的内容,清晰地观察到我的内心世界。在第三天,我就在我的日记本中写下了一句:「我太纠结于我想象中的未来」。

我和一起学习的一些学员交流我们的冥想体会,有的人会想起很多过去的事,而我会想到很多还没发生的,我想象的事:我接下来应该做点什么?别人会如何评价我的行为?我接下来要读什么书?要学点什么?等等等等。

佛教也认为痛苦来自对过去和未来的纠结,过去的已经过去,未来的还没发生,我们拥有的只有当下,我们应该在享受当下的幸福。而我意识到,我一直在未来寻找幸福 —— 读这些书会幸福、买这些东西会幸福、写这些东西会幸福。但是,一旦真正实现,我还是觉得不幸福,因为未来已来的时候,我又从未来的未来寻找幸福在哪里。我一直忽略了感受当下。

人们总是用一生来等待开始新的生活,这是很常见的现象。等待是一种思维状态,意味着你需要未来,而不要现在;你不要你所拥有的,而要你所没有的。任何一种形式的等待,都让你无意识地在你的此时此刻创造了一种内心的冲突:你不要此时此刻,你把希望寄托于未来。丧失对当下时刻的意识,会大大降低你的生命质量。

设定目标并努力去实现目标本身并没有错,错误的是你将它看成是你对生命和对本体的感受的替代品。

—— 《当下的力量》

在这一周的冥想,我只记得就只有短暂的 2 秒钟,我仿佛真正地感受到了当下。我不再想过去,也不再想未来,我只感受到当下,听到鸟叫,虫鸣,风吹过脸上。有一瞬间,我感觉被一个不知名的气泡笼罩,在这个气泡里有很大的安全感,我感觉我在此刻是无敌的,因为过去已经过去,未来的我不再去想,当下我可以做任何事。

你还可以通过将你的注意力集中在当下这一刻,从而在思维中创造那种空白。就是全神贯注于当下的时刻。这是一件非常值得去做的事情。通过这种方式,你可以将意识从思维活动中引开,并创造一种无思维的空白。在这种空白中,你高度警惕,注意力高度集中,但是你没有在思考。这就是冥想的本质。

—— 《当下的力量》

最后

一周的时间很短暂,但我想我这辈子都会记得这一周。离开寺庙,我还是比以往更慢地做一切事情。慢慢走、慢慢吃,没有事情是那么的紧急,手机并没有那么着急去看。不必用尽一切去填满我的时间,吃饭不看手机并不会损失任何东西。保持冥想练习,保持对自身情绪的觉察力。

最后三天我只用手机在离开前和我的老师拍了张合照。K.K. 是个非常棒的老师,跟我们讲了很多佛学知识,带我们做冥想练习,在傍晚带我们在外面欣赏晚霞和自然的宁静,在大雨的清晨 5 点多带我们听着雨声和鸟叫冥想,最后一天还送给我们每人一串带上他的祝福的珠链。

他说,monks get no salary in Thailand, I’m teaching you for free. 离开前我把我身上所有现金都 donate 给了他。

我和 KK 的合照

这是他在 YouTube 上曾经接受过的采访:https://www.youtube.com/watch?v=3g7TUT1kjC8

FAQ

教学用的语言是什么?

英语。我认为高中英语成绩不太差的水平就能听懂。

在哪里可以报名?

Wat Umong 不需要提前报名,每天早上 8 点半前报到既可。

Wat Suan Dok 的 monkchat 在官网上可以预约。3 days 的每月都有一次。虽然有 2 days, 但我建议 3 days.

复读和命运

2023年6月10日 08:00

冯大辉 Fenng 发了一条 Tweet

对于各位高考过来人,如果成绩只能上二本,要不要复读?

以下是我的想法。

我当时考到的是二本,除了学费贵一点之外,我觉得都挺好的。我个人的浅见是,命运是没有人能预测的,复读和不复读是两个不同的分支。当然这说了等于没说。所以我来试试纸上谈兵一下:

我们假设复读一定能考上一本,那么我们可以把问题简单化为一个博弈:是否用人生的一年时间去换这个一本学历?

我有一个高中同学选择了复读,最后考到了比不复读更好的学校,但是在我对他的理解和我的个人认知里,他复读和不复读,并不会有很大的区别。

在我有限的经验观察里,人和人的距离,一本和二本的差距只占了非常非常小的部分,最重要的是人本身,他是否能客观地认知自己,自己的目标在哪里,想要的生活是什么,追求的东西是哪些。再以此为前提,是否能为了目标去努力地寻找资源,运用自己的主观能动性,去趋向自己的目标。然后在运气来临的时候抓住它。

就像有些人对我的评价,我「只不过是每次赶上了末班车」。我觉得这个评价很正确。我原本是 2018 年的大学毕业生,但我 2015 年就退学了。没有人知道我退学之后是好还是坏,我也不知道,但我们马后炮地回看,当时的时间点退学,让我赶上了互联网发展的「末班车」,如果我等到毕业,在这鼓浪潮开始退去的时候,我这个二本学生,不一定能混到我现在的状态,这辆「末班车」早就跑了。

我的例子不值得效仿,能不能坐上「末班车」,除了时机,还有我早就付出过的那些别人不一定看得到的努力。但我想表达的是,在做选择的时候,不能轻视了「时间」这个非常重要的因素。早一年和晚一年,会认识不同的人(这决定了人脉),会影响你身处在浪潮哪个位置,等等等等。

这个世界就是一连串随机事件的结果,它没有好坏之分,好坏都是靠自己的努力去定义的。如果这位朋友对自己的目标并不明确,那么早一年晚一年,好像也不会有什么本质上的区别,只要自己复读的一年里心理状态可以保持得很好,那复读也不是一个坏选择。

只有在「有目标 + 肯努力」的状态下,才能把人生这张彩票玩成一场能拿一手烂牌打赢的德州扑克。

我的笔记管理法

2023年5月13日 08:00

本文视频版:

作为一个程序员,我每天都会消化大量的信息。我以前总是会担心我花了这么多时间读各种各样感兴趣的内容但最后都派不上用场,或者不知道怎么找到想要的东西。所以我喜欢学习一些关于知识管理的方法论,然后结合自己的情况慢慢摸索出一套比较适合自己的笔记方法。在这个影片我就要给大家分享一下我从浏览信息到记录笔记再到输出的整个过程是怎么样的,我是怎么在我的笔记工具里整理我的笔记的。

其实与其说是在「记笔记」,我觉得更贴切的说法是我们在构建我们自己的「第二大脑」。我们本身的大脑的长处不是记东西,而是思考和创造。所以我们需要借助计算机创造一个我们的「第二大脑」,把我们见过的有价值的东西一直记住,等我们需要的时候再从里面找出来用。

当新的一天开始,信息就会不断地进入我们的大脑。如果我们想把我们接收的信息和知识好好地进行管理,我们必须先想清楚我们的信息来源到底有哪些。

信息输入

以我为例,信息来源主要来自:

  • 脑子里突然出现的想法、灵感。
  • 我关注的社交媒体的信息流。
  • 读书、听播客。

想法、灵感

对于脑子里突然出现的想法和灵感,如果我在用电脑,我会写在 Logseq 的 Journal 里;如果我在外面,我会立刻用手机写下来。我自己用的是 Drafts 这个 App, 因为我觉得它的 tag 比 Apple Notes 的要好用。但是你可以用任何自己喜欢的 App, 可以是自带的 Apple Notes, 可以是 flomo 等等。无论是什么 App, 最重要的是找一个你能点开就开始写的 App.

至于记下来之后要怎么处理它,在后面我会在讲组织笔记的方法时详细说明。现阶段你要知道的就是,你必须找一个点开就能写的工具帮助你抓住那一刹那的灵感。

关注的信息流

我每天起床洗漱完开始打开电脑后,都会开始进入我的「快速浏览」模式,这个过程的主要目的是从我固定的一些信息获取渠道快速地了解有什么事情正在发生。

比如我每天会固定浏览这几个信息来源:

  • Twitter
  • HackerNews
  • YouTube

我在 Twitter 上主要是关注了很多国内外的程序员、设计师、产品经理、独立开发者,还有像 Paul Graham, Naval 这样的神级人物。我每天可以从里面看到我关注的这些我很欣赏的人他们在关注什么事情,有什么最新的技术,有什么最新的观点,他们在读什么书等等。

另外一个是 HackerNews, 应该算得上是世界上最大的程序员社区了,在上面可以让我发现技术圈目前最被关注的事件是什么,当然还会有很多技术之外的好文章。

还有就是 YouTube, 我在 YouTube 除了关注一些娱乐的内容之外,还会关注一些关于生产效率、技术等等的一些偏严肃的内容。我只会在晚上睡前刷 YouTube, 早上一般来说不会主动打开 YouTube.

「快速浏览」的关键在于要把重点放在「发现」而不是「吸收」上面。因为前者花的时间很短,而后者会很长,最有效率的做法是,看到你感兴趣的,就把他扔在一个统一的地方,然后忘掉,去看发现下一个。等刷完你的时间线后,再开始「吸收」刚刚扔进来的一堆信息。这有点像你在 shopping, 把你想要的都放在购物车上,然后回家再把这一车的东西吸收整理。

快速浏览的流程

应该统一放在什么地方呢?我个人在不同的情况下会用不同的工具。我感兴趣的内容一般会有以下几种:

  • 新的语言、框架、库
  • 我感兴趣的文章、视频
  • 新的产品

对于我感兴趣的文章和视频,我会首先打开它们快速地略读,如果确定我有兴趣深入地读,我就会把他保存到 Readwise Reader 这个稍后读工具里。无论是文章还是视频,我在浏览器只要点一下就可以收藏。

这里要注意的是,很多人用稍后读工具,就是点一下保存之后就把页面关掉。而我会做得更多一些,我会根据这篇文章的内容打一些 tag, 这样等到将来我需要写关于某个主题的文章时,可以在 Readwise Reader 里通过标签直接找到关于这个主题的文章。

我还会在这篇文章加上注释 —— 为什么我想读这篇文章?我想从这篇文章里得到什么?我会强迫自己添加一篇稍后读的文章的时候思考这个问题,并且用十几个字简单地描述。这样当我在之后读这篇文章的时候,我可以带着我的问题去阅读,这样会更有效率。

如果看到的是新的产品,新的技术,新的开源库之类的,我会点进去快速地了解一下这个东西,如果我觉得可能在日后我会用到它,我就会把它保存到 Raindrop 这个书签管理服务。首先是给这个东西打上合适的 tag. 然后如果我觉得我需要更深入地学习这个技术,我会把它存到一个叫作 Inbox 的文件夹,我会在「消化」内容的阶段检查我的 Inbox 文件夹。

总的来说,第一个阶段就是快速地把我感兴趣的内容捕捉下来,根据不同的内容类型分别存到 Readwise Reader 和 Raindrop 里面。

Raindrop

读书笔记

我近一年最主要的读书渠道就是微信读书,我会在书里面直接划线和写想法。可惜微信读书没办法同步到 Readwise, 所以我写了个叫 NotePal 的工具帮我把微信读书的笔记转换到 Readwise 的格式,然后我会在读完一本书之后手动地同步到 Readwise.

NotePal 界面

内容消化

我一般会在晚上下班后的闲暇时间开始我的「内容消化」阶段。这个阶段主要的任务是把我在「快速浏览」时捕捉到的东西认真地消化。所谓的「消化」,其实指的是我试图从这些内容里面:

  • 学到新的东西
  • 得到新的灵感、想法
  • 得知新的工具,将来解决某些问题的时候可以搜到。

在 Readwise Reader 里,我会在读到让我有所收获的句子下面划线,然后打 tag, 有时候还会写下我的想法。我比较喜欢用 Readwise Reader 是因为他还包含了 RSS 订阅,我可以直接把它当作 RSS 阅读器读到我订阅的博客,然后直接在上面做笔记。而且如果保存了一个 YouTube 视频,它会把字幕显示出来,可以直接在字幕上划线做笔记。这些笔记会自动同步到我的 Logseq 里面。

Readwise Reader 界面

Readwise Reader 阅读视频

Readwise 自动同步到 Logseq

稍后读的内容过完了之后,我就会检查 Raindrop 的 Inbox, 如果我被某个产品或者技术启发出来了新的想法,我会直接记在 Logseq 里。

笔记组织

把东西记在笔记软件里只是第一步,更重要的一步是怎么去组织这些笔记。组织笔记的目的不是为了满足强迫症,而是尽可能地让我记下来的笔记更容易在我需要的时候被我发现。我一般是在把笔记写进 Logseq 的同时做好组织的,因为在 Logseq 组织笔记的形式无非在关键词里加上双向链接,或者打上合适的 tag.

但我后来发现如何打好 tag 是一个学问。在 Building a Second Brain 这本书里,Tiago Frante 对如何组织笔记提出了一个框架,叫 P.A.R.A. 也就是 Projects, Areas, Resources, Archives. 这个框架主张把笔记分这四种不同的类型存放。

PARA

  • Projects 指的是正在做的项目,比如正在学习的某一门课,正在开发的某个产品。
  • Areas 指的是你感兴趣的领域,比如理财、编程、职业规划、商业等等。
  • Resources 指的是在未来可能会有用途的东西,我的理解是那些你可能会用到的,将来可以立刻作为参考的东西。比如最近我会看到很多关于 Prompt Engineering 的东西,虽然这不是我的领域,但我觉得将来会有用,所以我的 Logseq 里会有 Resources/Prompt Engineering 这个页面,跟 prompt 相关的笔记都会带上这个 tag.
  • Archives 指的是你已经完成的项目。

我觉得 P.A.R.A 这个框架给了我很大的启发,我在 Logseq 里实践了这个框架,并且根据我自己的情况,我对这个框架进行了一些适用于我的改造。

  1. 我基本不需要 Projects 这个分类,因为我有用其它任务追踪工具。
  2. 同样地,我不需要 Archives.

因此我只保留 P.A.R.A 里面的 Areas 和 Resources 两个分类。

另外,在 Building a Second Brain 这本书里有提到关于物理学家费曼的一个故事。很多人问费曼是如何做到在这么多领域都能获得成就的,费曼分享了他的一个技巧:他说他会在心中记住十几个他很感兴趣的问题,即使这些问题他不会主动拿出来钻研,但当他每次看到一些新的发现,新的研究成果的时候,都会把这些研究发现去匹配他心中的那些问题,看这些新的发现能不能解决那些问题。

You have to keep a dozen of your favorite problems constantly present in your mind, although by and large they will lay in a dormant state. Every time you hear or read a new trick or a new result, test it against each of your twelve problems to see whether it helps. Every once in a while there will be a hit, and people will say, “How did he do it? He must be a genius!

读到这个故事的时候我非常受启发,我觉得的确是要把做的笔记也归纳到自己在思考的问题那里。这样日积月累,我的问题下面的笔记就会越来越多,多个笔记串起来会对我的问题更有帮助。

所以除了 Areas 和 Resources 这两个分类,我还建立了 Questions 这个分类,我把一直在困扰我的一些问题都建起了相应的页面,当我在记笔记时,如果觉得这个笔记和我的某个问题有关,就会链接过去。

Question, 如何做决策

Area

Resources, Prompt Engineering

无论是哪种组织框架,我觉得最重要的是让记下的笔记尽量容易被找到。当我对自己关注的 Areas 和 Resources 有一个大概的梳理后,我对之后记的笔记最后应该流向哪里也有了更清晰的认知。

检索输出

当我开始想要就某主题开始写作的时候,我就会打开 Typora 和 Logseq, 在 Typora 大概列出提纲,然后针对这个主题在 Logseq, Raindrop, Readwise Reader 里面检索相关的资料。

Typora

得益于双向链接,我在 Logseq 检索自己想要的东西的时候还算方便,因为只要你的双向链接和 tag 打得够好,在后期检索的时候你能看到很多不同的笔记互相关联。至于怎么在 Logseq 里面灵活地跳转,不属于这次要讲的范围。之后可能会单独做影片再讲讲。

总结

这就是我最近自己摸索出来的管理我的笔记的方法。你不一定和我用一样的工具,我觉得我想传达的最核心的观点的:列出你自己每天接收信息的来源。找出一个你认为最方便的方法把你从这些信息源读到的有价值的内容保存下来,然后想清楚它最终应该流向什么地方,可能是某个 tag, 可能是 P.A.R.A 里面其中的一个类型,或者是你自己的组织方法。当你有了自己的一套熟悉的方法论,你就会更清楚日后应该怎么找到你想要的东西。

28 岁,我还想生猛下去

2023年3月25日 08:00

今天是我的 28 岁生日。

在 2016 年的生日,我在博客写下了一篇《21 岁我想说的》,那年我进入了「大厂」,获得了世俗意义的「成功」,于是写下了这篇充满雄心壮志的文章。我觉得我离自己想要的「成功」越来越接近,我终于要用技术让别人刮目相看,用技术做点有意义的事情,帮助公司的业务 move fast. 我 13 岁就梦想的事情,在那一年成真了。

很感谢当年的自己写下了那篇文章,记录下来我的年少轻狂。就像王小波在《黄金时代》里所说的:

那一天我二十一岁,在我一生的黄金时代。我有好多奢望。我想爱,想吃,还想在一瞬间变成天上半明半暗的云。

但是直到今天我 28 岁,我才深刻地理解这段话的下半段:

后来我才知道,生活就是个缓慢受锤的过程,人一天天老下去,奢望也一天天消失,最后变得像挨了锤的牛一样。可是我过二十一岁生日时没有预见到这一点。我觉得自己会永远生猛下去,什么也锤不了我。

回想我的 18 岁,2013 年,高二。我很迷茫,课桌边上的《JavaScript 高级程序设计》已经被我翻了不知道多少次。后来某次技术大会,我有幸和译者曹力一起吃了个饭,我说我是看你翻译的书长大的。我们一笑而过。但他应该不明白这本书对我的意义有多大。

周末不能回家,我就去网吧写代码,写开源库,妄想可以在社区做出一点什么。那时我觉得没人懂我的抱负,身边的同学不知道 JavaScript 是什么,他们只知道我成绩不好,不爱学习。这真是冤枉,我比大多数人都爱学习。

我迷茫是因为我不知道我的路应该怎么走。我因为学编程耽误了课业,但我真的有机会靠编程吃饭吗?是我太幼稚、太理想主义了吗?我会不会到最后,课业和编程都做不好?

在那些迷茫的时光,读书和写作拯救了我。我一有空就去学校图书馆看书,读了很多现代作品(钱钟书,胡适,王小波,阿城,等等)。还读到了毛姆,那本《刀锋》改变了我很多。

每次语文考试我都很开心,因为可以写作文。我喜欢借题发挥,格子都不够用。我根本不在意因为离题被打低分,我想表达,我想在文字中创造美。那时的语文老师很懂我,是当时为数不多让我感受到被理解的人,我很感谢他。

但我还是迷茫,有时我宁愿可以像那些「好学生」一样,心无旁骛,家长开心,老师安心。但我做不到。

19 岁那年,2014,我高考。学校照例开「成人礼」,在大堂给大家打鸡血,奋战高考。我觉得可笑,但又觉得没资格,我只是一个连高中课程都应付不来的自以为是的可怜虫。

高三一整年我恶补了我落下了课业,我像自学编程一样自学高一高二的课本,我把整个课本一字不落地读,因为我发现很多考点都出在书本里一些很隐秘的角落。我像在做一个试验,用最有效率的方法尽量提升我的成绩。于是我买了历年高考真题,认真研究每一年的规律,哪些东西一定会考,题的难度是什么样的变化,基于这些规律去定制我的备考策略。

高考完以后,我感受到了一股自由的气息。窗外在木棉树上叫的鸟,对于还在上学的人来说,多美都和她毫无关系,而对于高考完的我来说,我就是那只鸟,我想叫就叫,我想飞就飞。

很幸运,我的备考策略算是成功了。大家都觉得我考不上本科,但我最终还是考上了一所不怎么样的本科。

我不想再回顾我的大学,我在博客说得已经够多了。但有一件事很有趣,我在博客也提到过:

这是一封 2014 年我写给未来的自己的信。当时在上大一,是上职业规划课时老师布置给我们的一个作业,写完我们就交给老师保存,他会在我们大学毕业后返还。

老师通过微信联系我说有封信在他那里,并拍了这张照片。我早已忘掉我曾写过这封信,看完后我就全记起来了。

记起来刚上大学时对未知的憧憬,记起来在教室听无聊的网页设计课,记起来退学那天给宿舍阿姨还了钥匙后坐上中巴回广州市区的时候听的那首《一路向北》。

退学后我正式加入了一家创业公司,严格来说是从退学前的 part time 最后决定了退学做 full time. 没有人给我意见,应该说没有人能给我意见。选择是困难的,因为没有人知道选择的结果一定是什么。我在那一刻意识到我是一个成年人了,不像考试时的题,人生给你出的题是没有固定答案的。选择的意义,是在选择后你做的事赋予的。

那是一段艰难又快乐的日子。

快乐是因为我觉得整个世界的大门为我敞开了,写代码从此不是我「不务正业」的事,我终于来到了我的主场。

艰难是因为我没有钱。我在珠江新城上班,在地铁沿线的番禺大石租了一个 600 块一个月的城中村房子。房子在二楼,没有光线,窗外是墙壁。自来水是有异味的,我只能买桶装水洗漱。出门上班要戴口罩,因为外面路过的都是货车,沙尘滚滚。

只要 600 块的房子,因为要押二付一,刚从学校出来,我付不起。我向老板提前出了下个月的薪水才租下。

那时我开始听《IT 公论》,播客的声音让我觉得,即使我在这昏天黑地的小房子里,我和他们一样,都在这互联网的浪潮里参与其中,我已经不是被困在学校里的人了,我要在其中大展拳脚。

拿到阿里的 offer 完全出于我的意料之外,即使我很喜欢当时的创业公司,以及两位创始人,但在这样的机会面前,我还是选择了「大厂」。

我记得当天面试了几轮,最后跟 HR 见面聊了一下期望,我说了一个数。回家的路上,觉得自己是不是开得有点高了,会不会因为开高了让我错失了这个机会?在我刚坐到家附近的地铁站,竟然通知我有 offer 了。

在之后,我开始面对别人附加给我的光环 —— 年轻、辍学、年少有为。我一点也不以此为荣,我只感到害怕。我不是年少有为,我只是笨鸟先飞了,我在别人还在读大二的时候,我就提前进入了社会。我总是想,我的同学都很聪明,等他们毕业了,也许只要一年,就能学到我提前学到的东西了。

我很享受这样的工作,因为编程就是我的生活,我享受她。当年的我甚至很奇怪,为什么竟然有人不想上班?上班写代码是我最开心的事,她给我带来了成就感,我在用我的能力创造价值。

这鼓热血,真是充满魅力。

时过境迁,那鼓热血已经花光在最该花的年纪了。热血退去,我才明白,编程是我真正想要追求的东西里最表面的一层。我在意的是,我用代码实现了什么,给用户带来了什么价值。我想用我的品味和价值观,创造一些美好的东西解决实际问题,并且做成一种可持续的商业模式,又或者创造一种商业模式。

商业是一种艺术,赚钱的方式也有千万种。我想用体面和美在这个世界上生存以及留下一点什么。

希望我自己会永远生猛下去,什么也锤不了我。

你看,迦摩罗,如果你将一粒石子投入水中,石子会沿着最短的路径沉入水底。恰如悉达多有了目标并下定决心。悉达多什么都不做,他等待、思考、斋戒。他穿行于尘世万物间正如石子飞入水底—— 不必费力,无需挣扎;他自会被指引,他任凭自己沉落。目标会指引他,因为他禁止任何干扰目标的事情进入他的灵魂。这是悉达多做沙门时学到的。愚人们称其为魔法。愚人以为此乃魔鬼所为。其实,魔鬼无所作为,魔鬼并不存在。每个人都能施展法术。每个人都能实现目标,如果他会思考、等待、斋戒。

—— 赫尔曼·黑塞《悉达多》

2022 年终总结

2023年1月9日 08:00

今年的年终总结写得有点晚,2021 年觉得自己一事无成,迟迟没有动笔。如今 2022 年也已经过去了,虽然同样觉得自己在今年一事无成,但转念又想自己应该给自己一个回顾的机会,终于还是动笔了。

琐碎的生活变化

2022 年因为工作的变化,主要都生活在苏州。苏州是一个很「慢」的城市,我算不上特别喜欢,但我很喜欢苏州的湖。我在 ByteTalk 的这期播客节目 里提到过一些我对苏州的看法。

东方之门

苏州的一些区域可以骑摩托车上路,我喜欢摩托,所以买了一辆摩托通勤,周末偶尔也会到不同的湖边溜溜车,还认识了一些摩友。

我的摩托车

意外的插曲

我从多年前开始受情绪问题的困扰,在 2021 年开始变得更严重,到了 2022 年,它变得更加凶猛。

那根一直在紧绷的弦,最终还是断了。我在年中因为焦虑导致了惊恐发作, 这是一种焦虑的躯体化症状。由于没有相关经验,发作时我误以为心脏出现了问题,于是拨打了 120. 这也是我第一次坐上救护车。那一周我住进了医院,做了身体检查,排除了器官问题。

我的情绪问题导致了我在 2021 和 2022 都没有写什么工作以外的代码,我的内心一直在希望自己放松和希望自己多做点事情两者之间不断摇摆。我曾经认为自己是一个很清楚自己想要什么,也很有目标的人,但最近两年,我越来越不知道自己在做什么,要做什么。

零碎的产出

Logseq 分享

我在一个晚上非常即兴地录了一个关于我如何使用 Logseq 的视频,没想到会有这么多的播放量,在 YouTube 上也收到了不少的感谢和鼓励。

CodeSpeedy

发布了一个我自己个人在用的 Code snippet 管理工具 CodeSpeedy. 是我第一个发布的用 Tauri 写的程序。

AMAzingTalk

因为看到 Twitter 上有不少人提供付费咨询服务,所以做了一个页面收录了一些不错的提供咨询的人。目前只是一个简单的静态网页,但我有计划把它做成一个产品。

《兰迪和他的朋友们》

我身边有不少不同领域的有意思的朋友,很想通过访谈和交流的形式把他们各自领域的哲学分享给更多人。于是我开了一个不定期更新的 podcast 《兰迪和他的朋友们》。目前只出了两期,分别是和我的健身教练聊了健身,还有和我的同事兼攀岩岩友聊了攀岩。

新的一年我还计划做一个和香港流行音乐相关的节目,感兴趣的朋友欢迎 Email 和我交流。

攀岩

今年在我的同事 sixian 的带领下接触了攀岩,我也意外地爱上了这个运动。喜欢和岩友一起交流线路的不同爬法和技巧,喜欢用出优雅的脚法的感觉,喜欢到不同的城市拜访当地的岩馆 —— 例如我和 sixian 到 上海攀岩工厂探店 (Bilibili).

攀岩

攀岩是一个力量和技巧结合的运动,我因为有力量训练的基础,让我入门这个运动非常快。但我喜欢学习和应用技巧的部分,我对攀岩的兴趣很大程度上来自于观看了 Jain Kim 的优雅脚法.

感染 Omicron

在 2022 年的尾声感染了 Omicron, 反复发烧 2 天多,咳嗽了近一周。我在开放了一周后才打了第一针科兴。我的症状比较轻,没有失去味觉和嗅觉,也没有所谓的「刀片噪」,只有轻微的扁桃体发炎类似的感觉。

最后

2023 年我就 28 岁了,有时候填表格看到年龄的一项写着 27, 会让我有些感觉陌生。我总是觉得自己距离踏出学校的那天还不是很远,在写做了 6 年程序员,我学到的 10 条经验 时我才发现自己已经工作了 6 年多了。我也偶尔看回 我 21 生日时写的博客, 很多问题在我内心缠绕:我还能做些什么?我想要的到底是什么?我的价值是什么?我接受了自己只是个普通人吗?

我没有答案。

做了 6 年程序员,我学到的 10 条经验

2022年9月20日 08:00

保持一颗解决问题的心

按照我的观察,那些在工作中用技术取胜的人们共同点都在于他们能保持一颗解决问题的心。他们可以率先想到一种更优的手段解决存在的问题(一般是效率问题)。他们不是嗅觉特别灵敏或者技术特别强,而是当他们遇到了问题,不是把它作为抱怨的话题,而是开始思考这个问题为什么没人解决、应该怎么解决,然后把它实现出来。这种心态在职场上特别稀缺。

我在创业公司的时候做一个图文排版的 App, 设计师会设计一些模板,然后交给我来实现。当时我们有很多模板,为了测试这些模板实现在不同的手机屏幕大小会有什么问题,我们要花特别多的精力。可以想象测试的数量 = 模板数量 * 屏幕尺寸的数量。后来我用 puppeteer 写了个自动生成不同屏幕和模板的截图,直接交给设计师一个一个地看。节省了大量的时间。这个事情没什么技术含量,但它解决了很重要的问题。

工作中需要解决的问题不仅仅在代码上,也有可能出现在非技术问题上。工作中我特别喜欢和非技术同事聊天,了解他们的工作。因为我常常觉得影响项目前进的原因不一定出在我们用了不适合的技术或者不够「先进」的技术。了解非技术同事的工作流程让我大有收获,我会发现他们有一些工作是可以通过写一段程序把原本的工作量做到指数级的下降,而通常非技术同事是很难察觉到的。

这样的例子特别多。有次我和一个运营同事聊天,我们当时在开发一个新闻内容的管理后台,他们常常用这个后台捞一些内容做分析。聊天的时候了解到他们有一部份的工作就是在上面按条件查询一些内容,再一条条地粘贴到 excel 里面,他说这常常要花一下午。后来我帮她做了一个一键导出成 excel 的功能。

她觉得这很不可思议,但这在技术的角度来说太简单了。我也因此了解到,对于不是做技术的人来说,他们很难察觉到哪一些事情是可以用技术解决的,所以我们不能希望他们主动地提出一个需求,只能我们作为掌握技术的人主动地去了解他们。

又一次我和我们的测试吃饭,聊到他们怎么做测试。我发现他们会用 mindmap 先梳理出来一些测试流程,然后一个个地做。但是痛点在于他们常常要手动维护一个文档列出这些 case 的测试结果,这些结果包括截屏,以及证明测试通过的请求返回信息等等。不但麻烦,还很难追踪。

于是我做了一个小 demo Web App,他们可以直接上传他们做好的 Mindmap, 通过他们的 mindmap 直接生成出来 case item,在项目的开发环境页面代码里面,只要注入这个 case id,就可以在测试之前开始记录请求日志,结束之后会上传到这个平台,这样在这个平台就能直接看到每一个 case 操作的时候的整个过程的记录。这个小 demo 后来被用于花呗的大部份前端项目,当然听说现在已经做得和我当时做的小 demo 完全不同了。

了解你的用户

我自认为自己还算是一个有那么一些产品思维的程序员,因为经常也会写一些自己的小产品。但在刚出来工作的时候,我在工作中太沉迷于技术本身。把心思都放在了诸如怎么重构,怎么改进构建速度之类的问题。我在阿里 P5 升 P6 的答辩中,我被问了一个我至今印象深刻的问题:你有了解你的用户是怎么用你在做的这个东西吗?

这个问题是我从来没有想过的,我哑口无言。可能它只是一个晋升答辩问题模板中的一个问题,但对我来说这个问题让我清醒了许多。当时我们做的是内部用的新闻内容管理后台,这个后台的用户是一些小编。我们和这些小编有一个群,但基本是用来报 bug 的。我离这些用户这么近,却从来没有了解过他们的使用感受。我想,如果我当时找他们聊一聊,可能也会有意想不到的收获。或许他们会报怨这个后台的加载速度很慢,我们就可以着手解决加载速度的问题,而不是和同事纠结在用哪种前端状态管理库这种无聊事情上。用户并不关心我们用的是 MobX 还是 Redux.

不要拿自己的尺子去度量别人

我刚出来工作犯的最大的错误之一就是拿自己的尺子去度量别人。我因为从小对编程痴迷,写程序对我来说是人生中最大的兴趣,我把几乎所有的时间都花在了技术上。当时我天真地认为所有程序员都应该像我这样,对待技术也应该有一种理想主义,我在互联网上结交的技术朋友都是这样的。所以我当时对我的同事特别苛刻,甚至对那些把写程序只当成工作的人嗤之以鼻。后来回想起来,这是非常错误的想法。每个人有每个人的追求,技术也只是多个兴趣爱好的其中一种。在当时别人的眼里我可能是个「怪人」,甚至有点「装逼」。

保持学习、be open-mind

我每天都会在 Twitter 和 Hackernews 发现很多最新的技术和技术思考,我关注了很多开源库的作者,我可以第一时间了解到他们最近在思考什么,在接触什么。这种主动接收会扩大你的眼界,让你在解决问题的时候有更广的思路。

不要只关注自己的领域。我还关注了很多写 Rust, 写 Go, 写 iOS/Android 的人。学习主要是学习技术背后解决问题的方式,这些解决问题的方式说不准也能应用到你自己的领域。

保持学习一直是和同行拉开差距最重要的一点。

想清楚,再下手写代码

我写代码的速度非常快,因为我已经花了超过十年的时间在写代码了。很多东西想实现,对我来说基本是纯粹的堆代码。导致我非常容易不经过多的思考就开始动手写。我为此吃了不少亏,常常写到一半发现一些没有想到过的问题,导致需要重新设计,重新改写。我的一位前老板很了解我,他也是个多年经验的程序员了。有一次我们在讨论一个新东西,他对我说,「不要着急,想清楚了再写」。这句话我一直记在心里。后来每次动手写代码之前,我都会把整个流程的设计先思考清楚,避免了很多不必要的重写。

敬畏用户

在写自己的一些没什么人用的开源库或者公司内部用的平台的时候,通常不需要过多思考就能把代码发布出去。到了做花呗这种用户基数庞大的产品,才意识到代码发布和以前所体验到的完全不同。

蚂蚁金服有代码发布的「三板斧」,这是从入职培训到实际工作中就会被反复提及的 must-follow rule. 「三板斧」指的是「可灰度」、「可监控」、「可回滚」。在代码发布之前,要先想想自己的代码是不是符合这三个条件。

  • 你的代码发布之后,如果出了问题,是不是可以被监控到的?
  • 你的代码是不是可以灰度发布的,而不是一下子全量被推到线上的?
  • 代码发布以后,出了问题,是不是可以回滚的?如何回滚?

在经历了用户基数如此庞大的产品开发之后,我对代码发布变得尤为审慎。我记得有次只是单纯改了某段 HTML, 但我还是盯着这个 PR diff 看了几分钟,在想这个修改会不会导致什么问题。

虽然蚂蚁的基础建设可以让这三板斧很容易实现(有成熟的发布平台进行灰度和回滚,有成熟的监控库);虽然即使遵守了三板斧,还是会有 bug. 但是这种代码发布的思维模式是好的,即使我到了别的公司,我在代码发布前还是会问自己这三个问题。

跨团队合作是利益交换

在大公司里,有时在做一个事情的时候,需要别的团队一起合作,或许是用到别的团队的接口、或许是需要别的团队开发新的接口,但这通常很难。我以前天真地以为,只要我们做的事情是有利于业务的,别的团队自然就应该一起合作。但实际上,大家更看中的是这个事情对自己的团队有什么好处。

换位思考一下,我们和别的团队合作,对于他们来说,增加了工作量,增加了风险(带来更高的 qps, 写更多的代码会导致更多的维护成本)。决定是否合作,首先取决于这是否是自上而下的要求,其次就是合作对他们的 KPI 有没有好处。

所以我学会了在游说别的团队合作的时候,首先应该想明白合作能给别人带来什么好处,而不是对事情本身夸夸其谈。这样更容易促成合作。

用别人的语言交流,会有意想不到的收获

有研究发现如果你用别人的母语和他交流,他会更容易接受你的观点,对你也会更友好。我发现这个心理同样适用在技术交流中。作为一个前端程序员,在和后端程序员商量技术方案的时候,如果可以更多地使用后端的术语,从后端的角度反推前端的想法,他会更容易接受。

我自己业余是个 full stack 程序员,所以很容易切换到别人的语境,也能从别人的角度去理解他的想法。因此沟通会更加顺畅。

理解前人写的「烂代码」

这里的「理解」不是指理解烂代码的逻辑,而是理解为什么会写成烂代码。我经常会听到同事报怨他看到的旧代码写得如何烂,但是实际上很多烂代码产生的原因不是因为技术不行,而是受限于技术的发展和业务的复杂性。随着自己写的代码越来越多,就越能理解这些「烂代码」的存在。看出来了烂代码,也不要着急去重构,这些代码很有可能藏着一些你不知道的特殊业务需求。如果你不需要碰这些代码,那就尽量别碰。

在技术和工作之间找到平衡点

在刚出来工作的前几年,我特别陶醉在把自己学到的新东西试图用在工作中。我的想法是,只有我把这个技术用到实际的工作中,我才算学习了这个技术。

其实这个想法是不对的,学习技术并不一定要求你把他用到工作中。工作就是工作,学习就是学习。工作的内容是为了业务服务的。我在创业公司工作的时候,曾经因为把一个我刚学习到的库用在业务中,因为一些我不知道的坑导致业务进度出了点问题。老板生气地说:业务不是你的试验田。

我后来遇到很多「后辈」(我竟然也开始有后辈了) 请教我说觉得自己在工作中不能运用到自己平时学习的技术,因此觉得自己技术没什么长进。我认为这种想法不太正确。

能把学习到的技术运用到自己的工作中当然是最好的,但这是可遇不可求的事。但是这不代表没有用在工作中,就等于没有真正学习到这个技术。我认为很多人对技术学习有错误的理解,对我来说,学习技术的精髓在于理解这个技术的 Why, What, How. 和能不能用到工作中没有太大的关系。

举个例子,我在刚接触到 Redux 的时候,我去学习它,除了了解它怎么用以外,我特别关心的是,Redux 的哲学是什么?是什么启发了 Redux 的作者创造了 Redux? 他和别的库有什么不同?顺着这些问题,我就会了解更多的东西,比如我发现 Redux 是受了 Elm 的启发,我就会去了解 Elm -> 了解 Functional Programming -> 了解 Immutable, 然后关注 Dan (Redux 的作者) 的 Twitter, 看他日常会分享什么,看他对自己做的这个东西的理解是什么。即使我没有把 Redux 用在工作中(事实上我从来没有用过 Redux),但我在学习这个库的时候,我学习到的不仅仅是 Redux 本身,还有它背后的更多东西。我可能很快就会忘掉 Redux 的 API, 但那又如何,那些它背后的知识才是最有价值的,是不会被忘掉的。

而工作则相当于是一个真实的场景,是在你学习新的技术的时候,帮助你进行实际思考的场景。你需要有意识地去想,这个技术如果用到我的工作中,它是否适合?它能解决什么问题?它为什么适合?它为什么不适合。当你在学习新技术的时候,结合这个技术,多思考这些问题,这才是真正的学习。

读《九宫格写作法》

2022年8月20日 08:00

九宫格写作法封面

倪爽Twitter 推荐了这本书,对于喜欢写作的我来说很吸引,花了很短时间就把这本书读完了。在这里推荐给大家。这本书主要给认为写不出来文章的人提供一些指南,书的前半部分是方法论,后半部分是写作套路(或者说写作框架)。

九宫格指的是在写作之前,从文章的中心,可以扩散出 8 个方格,填写和这个中心有关的信息,型成一个写作九宫格。九宫格的作用是在写作前迫使你先对文章中心进行思考、提出问题,然后进行填充。是一种帮助你在写作前收集信息的辅助手段。

所以通俗地讲,九宫格写作法的核心在于训练你在写作前的信息收集习惯。书中有一个比较确切的例子:如果你准备一场旅行,打算旅行过后写一篇游记。你就应该在旅行之前就画好一个九宫格,填上这篇游记你想要写所有的要点:

写作九宫格

然后在你旅行的时候,才有目标进行相关信息的采集,然后填充到九宫格里面,这样当旅行结束,你已经收集到了足够的信息,把它们整理成为一篇完整的游记。而不是到了当地漫无目的地游玩,然后回来只能追溯一下往事,已经忘了可以写一些什么,最终写出来的只不过是一些浅显的感受。

九宫格写作法实际上并不要求你只能有九个格子,你可以任意地扩张。所以这个写作方法,中心的思想就是:在写作之前,列出你对于这个写作主题的所有想要讨论的问题,然后再动笔。在列出九宫格的同时,整个文章的结构就自然而然地形成了。

九宫格写作法突出了写作前信息收集对于轻松写出一篇有价值的长文的重要性,这也是为什么作为一个有意向写作的人来说,平时做笔记那么重要。只有平时在信息输入的时候有意识地把价值输入作为笔记存到你的第二大脑(笔记工具)里,将来才可以基于平时的笔记轻松地写出一篇文章。这个过程也叫作「信息内化」。九宫格写作法辅助了你的「信息内化」能力。

这就是创作过程的核心: 在你选择你要写的东西之前,你必须下功夫研究并积累。理想情况下,你应该在创作开始之前就开始研究,这样一旦你决定了一个话题,你就有数周、数月甚至数年的丰富资料可以利用。这就是为什么你要把信息放在「第二大脑」如此重要的原因。

—— 真正的思考技术

我以前也常常觉得很难下笔,就是因为平时即使输入了很多信息,但没有把他们内化成自己的信息。陷入了「写作就是从一张白纸开始」的迷思。几年前机缘巧合下开始使用 Roam Research 并且读了 How to take smart note, 开始把平时摄取的有价值的输入记在了我的笔记工具里,通过双向链接,使我很容易在构思一篇文章的时候得到足够的素材。所以在读这本书的时候我很有共鸣,也对我的写作模式提供了一个更系统的方法论支持。

书的后半部分基本是一些写作的套路(框架),对我来说这部分意义不大。因为我从小就通过在学校的写作和平时写博客中得到了很多实践积累,对于写作的内容(例如哪些应该是文章重点、在文章中如何表达有价值的主观感受等等)我自己已经有了较多的体会。所以这部分我只进行了略读。对于缺少实践的读者来说,这部分也可以细读。

遗憾最小化框架 —— 如何做决定

2022年5月1日 08:00

对于我来说,我一直认为自己缺少做决策的能力。成年人的生活不像学生时代,所有的题目都有固定答案。所有的选择都不存在绝对的对和错,它只是在人的一生 checkout 了一个新的 branch. 我总是不知道应该如何做决定。

刚好看到了 Jeff Bezos 曾经谈到了自己是如何做决定的,他称之为 Regret Minimization Framwork (遗憾最小化框架) —— 他会想象自己到了 80 岁的时候,是否会认为不做这件事情会让自己遗憾。尽量让人生的遗憾数量最小化。即使当时的选择后来看来是错误的,但也不会后悔尝试过。

我很受启发。想起在 4 年前,我曾经问 Cycle.js 的作者 staltz 一个 问题, 我问他是否也会因为自己做的库没有像 React / Vue 那样火起来而感到气馁。他说他偶尔也会感到气馁,但他一直以来做事遵循一个 guideline:

Ask yourself: in 10 years from now, will you be proud of having done this? ... Do things that your future self will be proud, is my motto for the time being.

记得在一年前决定是否接收微软的 offer 的时候我非常犹豫,因为微软给出的 offer 比其它国内「大厂」给的少非常多。但是我回想起初中的时候,读了很多关于比尔盖茨的传记、微软的创业故事,十分向往。那时候的我没有预料到我将来有一天竟然有机会加入这家公司。也不会想到作为一个大学没有毕业的人竟然也得到了这样的机会。我也咨询了很多朋友我是否应该接受这个机会,他们有的会说其实在微软写的代码甚至没有在国内的公司那么 fancy. 但是我想,在加入了微软之后即使在后来可能发现这未必能得到我想象中的东西,但如果在很多年后回想起来我曾经放弃了这个机会,我一定会后悔没有尝试体验一下在这家公司工作。所以最后我决定接受了这个 offer.

❌
❌