普通视图

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

写给 Coral:去体验只此一次的人生

2025年7月11日 08:00

To: Coral / Aug 26, 2023
关键词:写作 / 职业选择 / 人生体验 / 直觉与理智

Hi,感谢来信!

你的邮件标题是「来自遥远的问候」,其实并不遥远。我已经从瑞士回北京了,目前一边带娃一边做产品。

我是年更博主,所以博客更新得很慢,哈哈。不过如果我认真思考这个问题,大概是因为生活中有比写文章更重要的事情,比如我最近在养娃陪娃,比如我还想再做些产品,所以写文章的事就被我搁置。我的笔记里还有不少文章草稿,只不过没有写完并发出来。

不过我还是很爱写文章,用文字来表达。所以大概再过些时间吧,说不定那时会产出更多。

很高兴我的文章能触动到你,我想这大概就是文字的力量。我最近又在读王小波的书,我总觉得,写作可以把人带到很远的地方,而这一点是程序无法匹敌的。我可以用程序做各种各样的产品,可是它们的可能性远远不如写作。用文字我们可以构造出《三体》,《黄金时代》,《Steal Like An Artist》,《Anything You Want》等等,可以打动人心,可以启迪智慧。

程序构造出来的产品,大概只能用来解决现实世界的问题,以及制造娱乐。

你说你在面大厂,这很好哇。如果有机会,去大厂体验一下,并没有什么不好。《人生不可 DP,但别永远贪心》说的是,你不必事事选眼前最优,不必步步为营。但不是叫你每次都随机选择,每次都要避开眼前最优,见着大厂我就一定不去。不是这样的。只此一次的人生,什么都值得体验。大厂也好,小厂也好,没有厂也好。都值得体验。

谢谢你的祝愿。也祝你顺利毕业,收获一个满意的 offer。当然最最重要的,尽可能多地去 follow your heart。直觉以及 gut feeling 有时候往往比理智做出的选择更有意思更「正确」,更让你不虚此行。

Best,
Hawstein

写给 Muniao:跳入生活这锅汤

2025年7月10日 08:00

To: Muniao / Sep 3, 2023
关键词:人生选择 / 英国留学 / 独立开发 / 冒险精神

认真读完了你的年终总结,点赞。我最喜欢的是倒数第二段:)可能是年岁渐长,更喜欢那种真诚的内心表达,尤其是偏形而上的哲学范畴,对人生的迷茫与思索。

你提到你老婆要去英国读书,然后你也跟着一起去英国。这和当初我和我老婆一起去瑞士挺像的。以我的三观,我肯定是很高兴你们做这样的选择的。人生短暂,多体验一点就赚到一点。换个大环境,给自己的人生加入一些不确定性以及可能性,说不定能探索出更广阔更有意思的未来。关于这个话题,我以前写过一篇相关文章叫《人生不可 DP,但别永远贪心》,你要是感兴趣可以看一看。

你说你还没想好去英国后做什么,其实这很正常的。我觉得很多事情,只有当你「跳」了进去,到了那个环境中,才会找着解决方案。当然,在还没有什么特别好的头绪时,先把目前已有的选择拿出来看一看,挑着一个开始做,也是不错的。比如,你现在已经开始做专栏做课程,那么可以继续沿着这个做。只不过,如果可以加一点约束,我觉得不如你也给自己定一点收入目标。毕竟如果你是打算全职做这个,先把物质基础搞稳了,后面想追求纯精神的东西(比如做个完全免费的好用的 to C 产品,或者搞开源),也不至于压力太大。

一旦决定自己做产品要达到「从 day one 就开始赚钱」,那么有些视角就不一样了。比如做课程,那就得稍微偏向市场需求,而不仅仅是按着自己喜爱或是擅长的来了。我当时辞职时也列了几个可做的方向,即使是做课程,我也有几个可做的内容。比如我最擅长的 Scala/Akka 生态,讲这些不仅是我擅长的,而且是我喜欢的。但我并没有去做这个课程,因为这个内容太小众了,买单的人肯定很少。如果课程做个一年半载,收入寥寥,那么想要继续走这条「独立创造者」的路,就会很难。甚至会和大部分曾经尝试过的人一样,最终回去上班。所以,最终我去做了算法课程。这并不是我偏爱的东西,但我也能讲好。所以我靠着它赚到了钱,走出了第一步。当然很重要的,也给了家属信心,相信我可以做好。

做独立产品是非常美好的,可是刚开始往往没有好的想法。自己闷起来硬想,我估计想出来的点子都不会是什么好点子。所以,要么你已经有不断在召唤你的产品想法,不然的话还是先在平时多看看海外 indie hacker 都在做些什么,然后慢慢找到感觉。

当然了,去英国后先找一家当地公司去工作一段时间也是不错的选择。一边工作再一边想自己的独立产品之路,这也更稳妥些。总之,每个选择都各有利弊,最后还是得根据你自身的情况(比如性格,对未来的态度,存款,家属的情况,等等去考虑)。

祝你和家属在英国的新旅程一切顺利。

Best,
Hawstein

写给 Shawn:不要投资,不要办公室,不组建团队

2025年7月9日 08:00

To: Shawn / Sep 15, 2023
关键词:独立创造 / 现金流 / 小型 B 端 SaaS / 公司的意志与群体性愚蠢 / 不要投资,不要办公室,不组建团队

注:这封回信是 2023 年 9 月写的,那时候说自学技术或代码,言必称 ChatGPT。还不到 2 年的时间,AI 领域又有了巨大变化。我想,身处巨变当中,凡事还是打上时间戳比较保险。因为今天的断言,很可能在明天就失效了。

// 来信片断:关于离开公司开始独立创造的契机

是否要破釜沉舟,我觉得这个是分人的。比如我吧,属于责任心比较强的人,所以一旦在一家公司工作,是比较难做到一边「摸鱼」一边搞副业的。尤其是国内的私企,本来就不是摸鱼氛围,我觉得大部分人都比较难做到一边在国内私企工作,一边做出好的商业产品。但如果有机会换到养老型外企,比如微软或谷歌,那么主业+副业的模式说不定就可行。我知道有个知名独立开发者在「苏州微软」上班,并且副业产品做得如火如茶。但这种「养老型」外企也分部门的,也就是有的部门也比较难摸鱼,所以说,全职搞自己的产品做成的机率肯定要大一些。

破釜沉舟其实也不是那么「悲壮」,也不是真的没有退路。即使我是裸辞来做自己的事情,我也是想好万一做不成之后的路的。我当时定的是半年时间内,产品要上线,且要有付费。不然我就回去找工作。

// 来信片断:好的产品想法应该怎么界定

我说的这两个原则是针对当时我刚辞职,手里什么都没有的情况下,定出来的。也就是说,我辞职了,一下子没有任何现金流收入,在这样的情况下,我最先要考虑的自然是「怎么尽快地能做出有现金流的产品」。所以就像你说的,可以做单一功能的简单产品,也可以做教程知识付费(2018 年知识付费还很火)。至于如何确保它能马上有付费,这个就是自己的判断了,也不能保证 100% 是对的。比如对于我,是因为我之前博客上有关于算法相关的 100 多篇文章,而且常年有稳定的访问流量,加上当时国内知识付费兴起,我一下子就觉得如果我出一套视频教程来讲算法,应该会有人付费。所以就这么去做了。结果证明也如我预想的一样。

一旦做出有稳定现金流收入的产品,那么就不太需要遵循这个原则了。比如我上一个产品,开发了一年,我可以投入大量的时间来做,也不用担心这段时间没有现金流收入。每个人都有不同的数字标准,就是自己定一个能接受的数字,比如每月稳定的现金流收入是 X 万元。OK,达到这个后,我就可以把赚钱的优先级调低一些,甚至去做一些哪怕不赚钱但我很喜欢的 to C 产品。

关于适合 Indie Hacker 的产品形态,我觉得是有的。既然是 Indie Hacker,说明就你一个人或者 2-4 人的小团队,因此不要去做市场太大的产品,不要做大公司看得上的产品,最适宜的产品品类我觉得就是 to small business 的产品,本身是 to B 保证了客户付费意愿更高,而 small B 保证了这个需求足够小,没有大公司或中型公司看得上。

// 来信片断:为什么是面相欧洲市场的产品

肯定是有理性客观原因存在的。那就是出海做产品的话,付费意愿高且付费能力强的,就是欧美国家。北美的话就美国和加拿大,欧洲的话也并不是说欧洲所有国家,而是欧洲那些发达国家:英法德意瑞等国。它反倒和我家属 transfer 到欧洲没太大关系。因为即使我在国内,我也会想到去考察一下欧洲对应的市场需求是否被满足。

// 来信片断:为什么是不要投资,不组建团队

对的,目前仍然是这个原则(不要投资,不要办公室,不组建团队)。我从做视频教程开始,就有投资人找我要给我投资,到后来做 SaaS 一样会有投资人想投。但是我一想到我以前待过的公司(也算是创业公司),我就发现,公司虽然不同,人也不同,但相同阶段遇到的问题很多是相似的。也就是说,你按照现在互联网这一套来搞公司,有些问题就是无法避免的,或者说大概率无法避免的。这个其实挺有意思的,我觉得可以把它称为「群体性愚蠢」,哈哈。就是,你作为单个个体,有时会觉得,公司这个决策看起来这么愚蠢,怎么还会被做出来呢?可是一旦个体处于公司当中,做决策的其实就是「公司」,可以认为公司里所有个体组成了「公司」这个超级个体,它仿佛有了新的意志,而它的每一个决策,其实就是公司里所有人合力的结果。所以自然是有可能做出让每个人都觉得不太满意的决策,包括公司的创始人。

「不要投资」我是肯定会继续坚持的,因为我选择做现金流稳定的产品,投资对我来说其实没有意义。有人会说,有了投资后就可以招人啊,做大做强啊。确实,资本的杠杆就是干这些事的。可是现在的我更愿意过一种自由的,没有来自公司的乱七八糟的问题的生活,哪怕钱赚得少一些。

「不要办公室」也会继续坚持,因为没有必要。

「不组建团队」这一点,未来可能会有变化。也就是说,未来我可能会招人,但不会招全职,而是以合同工的形式进行远程合作。我更喜欢松耦合的组织关系。可以比较容易解耦,其中的个体也会更加自由。关于团队和组织这一块,Gumroad 做了个很好的榜样。未来如果要搞团队,我大概率会参考 Gumorad。相关文章:

No Meetings, No Deadlines, No Full-Time Employees

// 来信片断:Indie Hacker 如何处理技能树问题

我觉得你提到的两个方案都行。具体看自己的偏好。找个技术合伙人一起,就会更快,你不用重新学很多技术。这一块的话,国内有个非常棒的例子,就是:少楠+白光(flomo 的创始人)。少楠擅长产品与营销这一块,白光擅长技术。他们的组合真的就属于非常棒的组合。但这个的难点在于,你得找着这样一个和你志同道合的靠谱的技术合伙人,最好就是你已经认识的前同事/同事/朋友,千万不要临时去哪里抓一个不认识的,我觉得这些都不太靠谱。合伙人选择不只是看技术,人品,责任心,包括其他性格方面的东西,都是很重要的考虑。所以,其实还挺难找的。

自学技术的话就不依赖外界,反正就在自己。而且,现在有了 ChatGPT,说实话,自学技术的难度已经很低了。尤其是,目标是做出产品,而不是去精通技术。在这一块,很多时候,知其然其实就够了。我是后端出身,现在有大量的前端代码,其实就是靠 ChatGPT 帮我写的,我只不过负责验证调优一下。

Best,
Hawstein

写给 Coral:Keep looking. Don't settle.

2025年7月7日 08:00

To: Coral / Apr 22, 2024
关键词:大厂 / 人生规划 / 自我探索 / 构建自己的游戏 / Keep looking. Don’t settle.

Hi Coral,

很高兴又收到你的来信。正好现在有空,给你快速回一封:)

首先祝贺你去了大厂,刚毕业去大厂是个很不错的选择。在那里你可以学习到职场以及专业领域里所需要的知识。你说时常想起我的文章,真的让我很高兴。文字真的很有意思,这也再一次提醒我应该多写。

与其问,三五年后是否有决心脱离这个巨大系统。不如现在就问自己,想不想脱离这样一个巨大系统,自己想要过怎么样的一种生活。然后开始为之努力或筹备。我不知道你在哪个大厂,也不知道你具体的岗位是什么,其实这些都不是很重要。更重要的可能是你得去想一想那些人生中最最基本的问题:你是怎样一个人,你想过一种怎样的生活,你想和怎样的人一起生活,你想要的那种生活在哪个国家/城市最容易达成。之类的吧。这些问题不是很容易想清楚,所以很多人到了 30 多 40 多甚至 50 多都想不清楚,反正越早想清楚越好,我觉得。

举我自己的例子,我在上学时,就非常明确,我想自己做点事情,我想构建自己的游戏(Build my own game)而不是参与到别人的游戏中。构建自己的游戏与系统,就可以自己制定规则;参与到别人的游戏或系统,就得遵守别人的规则。所以当我一边上大学,我就一边想我能做点什么呢?一边上研究生,也一边想我能做点什么呢?去第一份工作,也一边想我能做点什么呢?我觉得这个思考从未停止过,如果没有满意答案,那就继续生活。一旦有了答案,就可以做点什么(pull the trigger)。所以大家可能看到了一篇文章中的我,但那篇文章后面其实是大量的「念念不忘」与尝试。

乔布斯说过:Keep looking. Don’t settle. 我觉得这描述了很长一段时间的我,甚至现在,我也没有停止探寻。

感谢荐书和荐歌,歌已开始听,书已加入书架。

最后,也祝你工作顺利。然后把老乔的话再一次送给你:

Keep looking. Don’t settle.

Best,
Hawstein

写给 Sulhg:独立创造者的无限游戏

2025年7月6日 08:00

To: Sulhg / May 4, 2024
关键词:Indie Hacker / Micro SaaS / 辞职创业 / 不确定性 / 运气

Hi, 感谢来信!

我五一出去玩,刚回北京,正好小孩睡着了,可以坐下来给你回信。Better late than never :)

很真诚的一封来信哈,我也会很真诚地回复。

正如你所说,让我帮你分析该不该去,其实这种问题价值不大。越老就越发能感觉到,他人的建议属实大多无用,毕竟人与人之间有着无数看不到的差异(我愿称之为暗差异)。我之前听到过一种比较认可的说法,就是与其给别人建议,不如分享自己的故事,作为别人参考的一个数据点。你可以收集很多数据点,最后做出属于你自己才能做出的决策,走一条属于你自己独有的路。

// 来信片断:你当时是怎么做到那么坚定的放弃了自己平稳发展的道路的呢?

说实话,现在回过头去想想,其实应该算是我最后一家公司推了我一把。什么意思呢?就是虽然我是一直想自己出来单干搞事情,但是具体是在什么时间节点,要满足什么条件后才去做,这些我都是还没想好的。因为在当时我也没有一个说让我激动不已的事情,就像某种 calling,让我一定要把工作辞掉去做那件事。并没有。真实的情况是,当时公司内部有一些问题,资源又一直跟不上,所以我所在业务线做得就很累。在这样的情况下,慢慢地我自然就有些 burn out 和心灰意冷。所以有了决定要辞职。当时的第一计划是找家轻松点的公司工作,然后开展副业,等副业收入达到主业收入,再辞职全职自己做。但是日子一天天过去,我就觉得何必这么折中一下?既然我已经知道了自己最终要去的地方,为何不直接就去?决定就是一瞬间做出来的,剩下的就是兵来将挡水来土掩了。

// 来信片断:你当时是如何对抗脱离社会体系这一巨大的不确定性的呢?

我觉得一个很大的因素是我看到过很多很多的 Indie Hacker 成功案例。他们的生活方式,他们的工作方式,让我觉得那是一种我更想要的方式。我记得我在文章中也写到过,就是我真的是看了非常多非常多的 Indie Hacker 的故事,如数家珍我觉得一点不为过。并且我会在 Twitter 上持续跟踪他们以及他们产品的发展。现在国外好几个年收入在百万美元的 Indie Hacker,我是看着他们从几百刀的 MRR 一步一步做起来的。这些「数据点」给了我很大的信心,因为我觉得他们其实并没有比我优秀很多,既然他们可以,我应该也可以。

// 来信片断:比如,是否想过,自己万一没有成功,会被自己的后辈超越,可能还要回到公司打工?中间如果有怀疑,是如何解决的?做 Indie Hacker 后是否焦虑过?

我当然是设想过自己万一没做成,会怎么样的。我当时辞职后给老婆做了个 slides 讲了我的计划,就包含如果 6 个月内没有达到一个设定的目标,我就回去找工作。然后我觉得以自己的水平,找一份工作是没什么问题。所以如果自己做不成,就回公司打工,这个我其实是有预期的。至于会被后辈超越,我倒是没有这方面的焦虑,因为我知道现在许多比我年纪小的人,已经做出比我厉害的成就了。在 Indie Hacker 圈很常见。做 Indie Hacker 后是否焦虑过,我觉得应该是有焦虑过的。就是在产品迟迟没有起色时,或是前期开发产品投入过多时间时,这时可能就会怀疑是不是自己对产品的判断失误了。至于解决方法,我也说不好,有时是再开一条线做个新产品,有时是休息一下,继续投入开发已有产品。有时是尝试一种新的营销手段。反正就是继续「做事」,不管是做什么,反正在目前拿到的有限信息下做出判断然后去做,用行动缓解焦虑。

// 来信片断:你是否还有做一些其他项目呢?

有的。我一直在做新项目。目前手里有好几个项目了。SaaS 的好处就是边际成本会慢慢趋于 0。当软件逐渐成熟,onboarding 流程不断完善,文档也慢慢齐全。理论上到达一个状态后,这个 SaaS 基本上就不太需要我投入多少时间。而我就可以抽身继续做新产品。我觉得做 SaaS,尤其是 Indie Hacker 做 Micro SaaS,像是一场无限游戏(infinite game),可以一直玩下去。

不过就像很多人说过的,这里面是有运气成分的。我觉得这里运气有一个层面的意思是,摆在我面前有许多可以做的产品(至少对于我是这样),而我只能根据我有限的知识和信息,做出决策决定要做哪个。做这一个就成了,做那一个就失败了。这里面我们有时候会觉得,诶是我的决策好,其实不是,可能就是运气好,选对了。

但是,我觉得我们是有办法增加运气光顾自己的概率的。那就是让自己一直在这个赛道,不下牌桌,一直玩下去。许多 Indie Hacker 的路径就是,做 1 个产品失败了,2 个产品失败了,3 个产品失败了,继续做,在第 N 个产品时起飞了。如果是赌博,不下牌桌,有可能会在第 N 把赢把大的,但是后面还可能全输回去。但如果是做 SaaS,尤其是 Indie Hacker 这种 bootstrap 方式做 Micro SaaS,不下牌桌,在第 N 把做了个成功 SaaS 后,不会说在后面把钱全亏掉。bootstrapped micro saas 讲究的就是现金流,低成本,高 margin。所以,我觉得这是一个值得玩的游戏。只要我不下牌桌,那么我就有极大的可能做出个成功的产品。

没想到一口气写了这么多。就当是一个数据点,你看看。

Best,
Hawstein

写给 Sulhg:自我认知与做事的意义

2025年7月4日 08:00

To: Sulhg / Jun 8, 2024
关键词:自我认知与困惑 / 死亡思考 / 独立开发 / 现代性与分工

Hello,

原来你也在北京,后面要是时机合适,可以约着线下见一见:)

// 来信片断引用,省略。

哈哈。看这一段时,我也颇有感触。可能一年大一岁,我现在偶尔会感觉到「青春真是一段一去不复返的美好时光」。我有个朋友在大学当教授,有时候到大学找他,看到大学校园里那一张张青春稚气的面孔,真的会立马感叹自己已经不再青春,至少和他们相比是这样。现在我也有小孩了,前段时间小孩生病,奔波去医院,半夜小孩发高烧得起来喂药。体验了一把上有老下有小,家里有人生病的中年人生活:)也可能是一件件这样的事情,让我偶尔会感叹青春的美好。当然,这也有可能是一种「回忆中的总是更美好」的幻觉。

// 来信片断引用,省略。

那很好诶。我之所以会在上一封邮件反复强调「表达所带有的偏见」,是我在写东西时,常常担心给人一种「站着说话不腰疼」的感觉。由于我知道,每个人的处境和生活实践不一样,我不想把自己对世界的理解,当成一种通用建议或观点,说给别人听。生活中或网络上,我常常看到许多有人生阅历的人(其中不乏大 V 网红成功人士)喜欢言之凿凿地断言,给大众建议,仿佛他们在说着某种绝对真理。每次看到他们那样说话,我就提醒自已,千万不要和他们一样。无论那个人取得了多么大的世俗意义上的成功,我都觉得,世界之复杂与混沌,实在不是他们三言两语或是出本书,就能讲清楚的。

// 来信片断引用,省略。

同感。我的每一次回信,其实也是在自我对话。把自我的一部分投射到文字上。让自己更清晰地认知自我。我觉得,「认识自我」应该是个一生的话题,至少对我而言。我记得周迅在一次访谈中提到,她很惊讶古人说「四十不惑」,她说她 40 多了,可是还有很多困惑。当时我就很喜欢她的坦诚。其实何止 40,我看很多人活了一辈子,也还是有很多困惑,也没完全搞懂自己。只不过,到最后可能都不去想这个事罢了。

// 来信片断引用,省略。

我对这个问题没有解法。或者说我不把它当成一个问题。我觉得我是把它当成一个无法避免的事实,至少对于目前的科技来说是这样。当然了,未来不好说,我感觉未来说不定人类可能会掌握某种永生的技术。比方说全身上下所有的组织细胞都能人工提供/人工换掉,然后意识保持某种连贯性。这个有点扯远了,不管怎么样,我觉得我是赶不上那样的未来科技了。所以思考死亡,更多的就是给自己一点提醒,提醒自己人生短暂,这么短暂的一生到底应该怎么过。让自己思考宏大点的东西,有时候有助于不让自己陷入日常一件又一件的小事所带来的情绪中。

// 来信片断引用,省略。

我不太确定你说的的「奇迹」是什么?不过你提到的这两段,倒是让我想起了现代性的问题。高度分工确实容易让人丧失意义感,所以现在我看到有一小股思潮在兴起。无论是国外的 Indie Hacker 社区,还是最近又重新火起来的独立开发者。有不少个体想通过全程参与到一件事的完整环节中,并且直面市场,重新找到做事的意义。说到这一部分,我又有东西可以推荐。就是李厚辰的「翻转电台」中关于「好生活」,「做事」的那几期播客。他的播客太多了,我就不找了,你可以根据我给的关键词找一找,有空可以听一听。可以听听别人是怎么思考这个问题的。是不是能对自己有一些启发。

// 来信片断引用,省略。

感谢推荐哈。不过最近对我来说,能做的东西有点多了。所以最近我是在思考,当我可以做许多事的时候,我应该做什么。这其实也是一个自我探索的过程。因为有那么些时刻,面对自己的 10 几个产品想法,我发现没有一个能让我提起兴趣来做。人生每个阶段都有每个阶段的 struggle :)最早我没有什么产品想法,所以就不断探寻与搜索,期待能找着一个不错的想法。现在有不少产品想法记录在册,又得想,到底我要做什么。

Best,
Hawstein

写给 Sulhg:其他人也不过如此

2025年7月3日 08:00

To: Sulhg / May 25, 2024
关键词:职场晋升 / 自我认知 / 乔布斯 / 死亡思考 / AIGC 副业

Hi,下一封邮件你可以简单自我介绍一下,给我一个名字或ID,这样我好称呼你:)对了,我对你在哪个城市也感兴趣:)

从你拿 Offer 的情况,其实能看出在职场或者说找工作这一方面,你是很有竞争力的。因为目前这个环境,我看到不少人找工作确实很困难。优秀的人,其实是不需要太关心大环境的。我记得从我毕业那一年起,每年就都会有人说,今年是找工作最难的一年。可事实是,无论哪一年,都会有手里拿 10 多个 offer 的人。像你的情况也类似,大的经济环境确实是不如以前的,无论是从裁员的情况,中小企业倒闭的情况,写字楼空置的情况。甚至连我的小生意受影响的情况,我都能感知到,经济就是不如以前的。你还能拿到不少 offer,那说明你的实力是在那里的。

你说发现纠结的来源,是害怕无法掌控局面。这一点我其实相当能理解。面对未知,担心自己无法胜任。是我们这类偏谨慎型的人会考虑到的。但是我觉得我们可能得有意识地改善这一点。就是去更多地去发现这样一个事实:其他人也不过如此。关于这一点,我实在太喜欢乔布斯下面这个采访的节选了,我已经把它推荐给太多太多人了。这里我也推荐给你。

Steve Jobs Secrets of Life

Highlight: Everything around you that you call life was made up by people that were no smarter than you. And you can change it, you can influence it. You can build your own things that other people can use.

明白了「其他人也不过如此」这一点,并不会说让本来困难的事实变得简单。但是,它会极大增强我们的自信。而自信,我觉得是非常非常重要的。这不是大家喊口号里说的那种自信,而是一种,其他人也不过如此,让他们来面对这个问题,他们也可能毫无头绪,也可能要花很多时间去搞清楚怎么解决它。那么,当我一时不知道怎么处理时,我也不必过于羞愧,给我时间,我能解决的。

我先预祝你半年后完成晋升。但是,如果万一万一没晋升成功,我觉得也没有什么。真诚的,发自内心的,我觉得没有什么。Not a big deal. 晋升不成功,并不会就否定你这个人,你也不会被这样一次晋升成功与否定义。

我知道我这么说,其实是出自我所持有的世界观/人生观/价值观,每个人持有的三观不一样,所以对待同一件事,看法可能是完全不同的。但我还是觉得,人应该活得更松弛一些。我说得极端一点,人生短短不到百年,咱们死去的那天再来看这一次晋升,你会觉得有多重要呢?我觉得至少没你现在想的那样重要。

抱歉提到「死亡」,但我想,这是每个人都无法避免的终点,在 2024 年,应该是可以开诚布公地拿来讨论的。我是经常思考死亡这个话题的,这让我在做选择时,可以更多地听从内心的声音,而不是这个社会所提倡的主流观点。说到这,还有另一个我很喜欢的视频,就是乔布斯在斯坦福的毕业演讲,常听常新。

Steve Jobs Stanford Commencement Address

另外,为了避免我自己一不小心又回到某种谨小慎微/步步为营的状态,我给自己做了个图,贴在了我的电脑主屏,手机主屏,微信 banner,Twitter banner。如下:

Why so serious

关于副业,你说决定去做一些 AIGC 产生内容相关的事情,我觉得很赞,值得去探索一下。我觉得这一波 AI 浪潮是继移动互联网过后,时代又一次给我们的机会。我已经实打实地看到很多大/中/小公司,甚至个体,在 AI 这个领域,做出了有价值的产品,并收获和金钱和乐趣。我觉得浪潮来的时候,尽量还是要冲进去,做点什么,无论是什么都可。Do something.

好了,今天回信就这样。我写下的所有文字,都是基于我自己的世界观/人生观/价值观,你可能认可,也可能反对,都没问题。我自己持有一个观点,表达必然是带有偏见的。意思是,我们每个人的生活与实践不同,必然会产生独特的视角与观点。当然,有的人会与你相似,有的人会与我相似。但最终,没有两个人是完全相同的。而那些真诚地认为,自己在客观地表达的人,大概只是没有认知到世界的复杂性与自身的局限性。

最后希望你的主职工作以及 AIGC 副业一切进展顺利。

Best,
Hawstein

写给 Shen:自我探索与产品创造

2025年7月2日 08:00

To: Shen / May 27, 2024
关键词:自我探索 / 独立开发 / 产品哲学 / 自我表达 / SaaS

Hi Shen,感谢你的分享,很有意思。

你从「亚马逊电商」,到「做外包项目」,最后到现在「独立开发产品」,这个过程探索出来,其实就是一个慢慢了解自我的过程,一个自我探索过程。有的人是喜欢做亚马逊电商的,享受卖货的快乐;有的人是喜欢做外包项目的,享受实现的快乐而又不需要考虑太多产品层面的事情。显然,这些可能都不是你的热情所在,所以最后来到了自己创造自己做产品这条路。

我感觉这种实践出来的踏实感是很棒的。

我自己的话,在这方面可能比较早就想明白。所以不会去尝试做亚马逊电商或接外包项目。之前有很多外包项目找我,或者让我给公司当顾问,或者有投资人找我创业,我都婉拒了。关于这一点,我想的就是做互联网产品,做 SaaS,不拿投资,做现金流充裕的生意。没有实物的烦恼(供应商,工厂,海外仓,物流,有太多要操心的了)。所以在选择上,就给自己加了限制。

你说你现在在做一款自己也会用的产品,在我看来,这是很棒的。至少说,我觉得这是做产品的一种可行方式。关于做什么产品,各有各的说法,有的人说要做经过市场验证的产品,有的人说要做用户想要的产品(言下之意我自己用不用并不是很重要),有的人说要只做自己会用的产品。在我看来,都是可以的。不同时期,可以选择不同的策略。我做过给垂直领域用户用但我自己不用的产品,也做过自己想用而不在乎别人会不会用的产品,我觉得都可以。而艺术家 Rick Rubin 更直接,他在一个采访中这么说的:

I’m not making it for them. I’m making it for me. And it turns out that when you make something truly for yourself, you’re doing the best thing you possibly can for the audience.

最近我也在思考这个问题。我觉得对我来说,可能是分阶段,分目的,会采取不同的方式。比如说,如果我处于一个还没有任何营利产品的阶段,我最高的优先级是赚钱。那我可能会优先做用户想要的产品,因为他们想要,他们才愿意付钱。但如果赚钱已经不是第一优先级,更多的是想做自我表达,是一种艺术性地创造。那必然第一要考虑的就是自己,探索自己的内心,我在意什么,我的 obsession 是什么?我想把什么产品带到这个世界上来,让我的日常生活更加地愉快一些。无论是写字更愉快一些,记笔记更愉快一些,写代码更愉快一些,学习语言更愉快一些,都可以。一个精心设计的产品就是作者的自我表达。他通过创造一个产品,不仅表达出他认为这件事是重要的,也表达出他认为这件事应该这么做,而不是那样做。

因为你现在还有主业收入,所以不必为钱而焦虑。所以直接做一个自己需要的产品,让自己做得开心,我觉得就是一种很棒的方式了。其他的收获,都可以算是副产品。当然了,当你觉得你做的产品已经 ready,也可以充分向外传达出来。我最近看到一种说法,如果你做了一个好产品,那么营销它让更多的人能用上它,甚至是一件有德行的事。仔细想想也对的,但这包含了对自己产品的足够自信,确信它能给他人带来更好的生活。

你最后的结尾我很喜欢。你说的是持续尝试,我则表述为「让自己处于一种做事的状态」,大体上是差不多的意思。我喜欢「做事」这个词,它是一种产出与创造。最近我也一直在探索自我,想更深地了解自我。这真的不是件易事,难怪古希腊德尔菲神庙上才会刻着这样一句话(认识你自己)。渐渐地,我也想找着那些能让自己愿意投入10 年 20 年的长期的事情,而深刻地认识自己几乎就是前置条件了。不然,大概率做 1,2 年就觉得没意思了。

当然我也很是相信,人生是展开式的(unfold)。就是,我并不是在一个时间节点,想清楚了这个事,后面就能按着既定计划一直走。所以,即使在某一个时刻,我觉得自己找着了这么一件长期的事,也可能做着做着就生长出其他的可能性来了。或者自我也发生了变化。嘛,这就是人生啊。奇妙多变,不可预测。

我也祝你持续自我探索,更深入地认识自己。做出令自己满意的作品。

P.S. 如果有机会来北京,可以 ping 我。或者我有机会去广州,可以约饭。

Best,
Hawstein

写给 Melinda:比昨日更勇敢一点

2025年7月1日 08:00

To: Melinda / Sep 16, 2024
关键词:勇敢 / 系统 / 家庭 / 自由 / 死亡

Hi Melinda,感谢来信。

我常想,我们难得来人间走一趟,时间也不过百年,不妨活得大胆一些,勇敢一些。

说得直白一点,我们有一天都是要死掉的。在那个时候,如果回头看之前担心过的东西,害怕过的东西,畏首畏尾的事情,有多少是真的值得担心/害怕/畏首畏尾的呢?我想大概没多少吧。

只要不危害社会,不伤害他人,有什么想做的想说的,应该都给自己打打气,鼓励自己去试一试。

不过确实说起来容易做起来难。尤其是身处此时此刻,具体的事情和细节会被放大,大脑会全情的投入于此刻的细节中,所以很多事情就变重要起来。读书时,可能会觉得一次考试失利,天就要塌了;工作时,可能会觉得此次晋升的成败无比重要。但多年以后回过头看,往往都是云淡风轻。我以前上班时觉得无比重要的事情,在后来不上班的日子里,都觉得无足轻重。甚至在公司 A 觉得无比重要的事情,只要离开公司 A,那件事就变得一点都不重要了。

我想,大概就是因为我们是在一个又一个的系统当中,每个系统都它的价值体系,在那个系统里,我们被规训成遵守那套价值体系的人。

跳出系统,思路往往就不一样了。

不过呢,人是肯定至少要在一个系统中的。极端情况下,我可以不在任何一个学校/公司/机构,不组建家庭,逃离所有可能的系统。但是,我们也还是在一个地球上,还是生活在城市里,还在现今人类构筑的社会里。这是最后一个无法逃离的系统。那么我们就得至少遵守这个人类社会系统中的规范。所以,我肯定不能拿着刀冲到大街上捅人,也不能逆行把车开到对向车道上。// 我可以这么做,但会有很严重的后果。

除开人类社会,绝大多数人也还会在另一个系统中:家庭。当然,现在有不少年轻人不想结婚不要家庭,他自然也就更自由一分。不过我想,绝大多数人,还是组建了家庭。家庭这个系统也会有它的价值体系,有它对我们的要求。所以,当你决定要 follow your heart 去做一些事情时,就也得同时考虑一下对家庭里的成员会不会有什么影响。如果我只有一个人,那么我可以立即马上换一个国家换一个城市生活;我也可以把自己关在家里 1 个月,做一个自认为非常重要的产品。但是我有伴侣和小孩,那么我就不能这么做。

每个系统都有契约,人生也往往要折衷。

所以,勇敢就变得更加困难了。不过我想,正因如此,勇敢才更加可贵吧。学会去争取,去与自己生命中有羁绊的人协商。没办法做到无所顾忌的勇敢,那就尝试比昨日的自己勇敢一点点。

尝试去做,有不少事情应该都是能做到的。

加油,Melinda。

哈哈,我可真能写。娃醒了,我去陪娃了。

Best,
Hawstein

Indie Hacker 笔记 | 第 14 期

2020年1月8日 08:00

又到了码字的时间,这一次的心情很轻松。我想主要原因是,「AlgoCasts 每月小结」系列的完结,带来一个新系列的开始。人总是喜欢新的开始,正如新年给人以希望一样。新系列的名称定为「Indie Hacker 笔记」,由于它的前身「AlgoCasts 每月小结」已经出了 13 期,因此「Indie Hacker 笔记」就从第 14 期开始(关于新系列的命名考虑,文末会给出解释)。

AlgoCasts

距离上次小结已经过去一个多月了。这期间,终于把 AlgoCasts Plan 200 剩余的视频录完。至此,目前网站上 5 个系列共 211 个视频也就全都完结了。昨天把最后一个视频发布出去后,心情有点像来到了一个马拉松补给站。停下来喝点水,吃点东西,然后望望后面的路,想想接下来怎么跑得更好。小伙伴们也开始问我接下来的录制计划,这个在接下来几天之内应该就会发布到论坛公告上。时间过得可真快,不经意间,AlgoCasts 已经上线一年多了。而这一年多,我的工作生活模式也发生了很大的变化,遇到了不少有意思的人和事,感觉也差不多是时候写个跨度大一点的回顾了:)2020 年,我仍然会把大部分时间和精力放在 AlgoCasts 上,感谢一路陪伴与支持我的小伙伴们!除此之外,可能还会稍微分出一点时间来,开发一个小产品。这个小产品我已经构思挺久了,不过去年一直克制自己不要轻易开新坑,希望今年它能顺利面世。

德语

圣诞节后,我们把德语课的频次从一周一节提高到了一周两节。主要基于两个考虑,一个是多留点时间给我准备德语考试,二是德语老师在三月底要去维也纳进修他的语言学专业,我们想在他离开瑞士前把课程上完。到目前为止,我觉得德语学习的效果还是不错的。加之每天就生活在一个讲德语的城市,在学校里,在超市里,在车上,在路上,满目可见的都是德文,耳濡目染,进步也就快一些。我时不时会把这些生活中看到的德文拍照保存,然后再翻译学习。也经常为能看懂生活中某处出现的德文,为能听懂旁人聊天中出现的一些词汇或句子而小小高兴一下。在外买东西时,我也总是优先使用仅有的一点德语和对方交流,直到对方突然说出一个生词或是一个陌生的句子,使我露了馅,对方才会意并礼貌地切换成英语。这样有趣的例子可以说不胜枚举。零基础开始学习一样新东西的好处就是,进步是以一种可见的速度在发生的,毕竟起点太低了,越往后提升就越困难。不过关于德语学习,我还不需要考虑到「往后」这个阶段,毕竟还有段距离。

阅读

12 月看完了一本书,来自 James Clear 的《Atomic Habits》。这本书是从别人推荐书的推文回复里看到的(最近书架上至少有 4 本书是从别人的推文中挖掘出来的,我管这叫 steal from the tweets),于是在网上看了看评价后果断下单。书挺薄的,每天通勤路上看,很快就看完了。我觉得这本书写得还不错,书中倡导的「Build Your System」让我联想到福柯的「自我技术」。简言之就是,你的外在或内在系统,都可以由你精心设计,设计成适合你自己的系统,让你在这样一个系统内沿着理性为自己设定的路径前行,并且阻力尽可能小。整体上来说,我还是挺推荐去看一看这本书的。我有不少观点和书中观点一致,但如果让我写,现阶段应该没办法像作者写的那么好。关于输入和输出,我自己有一个理论,就是你永远只可能输出你所有输入的一个很小占比。所以,为了写一本还不错的书,为此要储备的知识与素材,要远多于书中所呈现的东西。当然了,输出垃圾不受这条理论约束:)

顺便提一句,关于「Build Your System」或者说「自我技术」,目前我了解到的人中,Stephen Wolfram 可以说是做到了极致。Stephen Wolfram 是计算机科学、数学、理论物理方面的著名科学家,是 Wolfram Research 的创始人,Mathematica 的首席设计师,《一种新科学》的作者。多年来,他一直在 hack his personal infrastructure。关于这些,强烈推荐阅读一下他写的长文:Seeking the Productive Life: Some Details of My Personal Infrastructure,相信你会获得一些启发。

App

最近在朋友的推荐下,开始使用一个 App 来记录时间,叫「Now Then」。一开始我对这个 App 并不抱多大预期,但在用了一小段时间之外,竟然发现意外地简单好用。如果你像我一样有记录时间的习惯,可以考虑下载来使用一下。关于记录时间这件事,最早我是从「奇特的一生」这本书看到的。这本书讲述了主人公「柳比歇夫」是如何使用他的时间统计法,对他做的事情以及花费的时间进行记录和研究的。后来我就开始探索适合自己的时间记录方式,也简单搜索过相关的辅助工具,不过都没遇到特别好用的。所以后来我干脆就用 Wunderlist + Evernote 的方式手工记录。我记录时间的方式不像「柳比歇夫」那样严苛,主要是围绕工作以及一些比较花时间的事情,碎片时间一般不记。这个不经意的习惯已经跟随我多年,目前我觉得带来的好处是,除了知道自己大量的时间花费到了哪里,对时间的敏感度也提升了。另外,在开始做一件事前,我会预估一个时间,做完后再记录下实际使用的时间,进行对比。如果这件事是需要经常反复做的,一般经过一段时间调整后,时间预估就可以达到一个比较准确的程度。

旅行

旅行方面,12 月份去了趟布达佩斯。在把所有细节都忘记后,目前我脑里关于布达佩斯的记忆就剩下:好看的建筑,好吃的美食,舒服的温泉。吃的方面,无论是食材的丰富程度还是做法的多样性,都比瑞士要高出不少。当然了,如果你是从国内出发去布达佩斯,请忽略我关于美食的那句评价。一月份还有两次出行:米兰和湾区。来瑞士后,出行变多了,所以最近还在思考以及需要解决的一个问题就是,如何在出行期间不打断我的某些 routine。所幸,我工作或生活中做的大部分事情,都不太需要依赖很「重」的外部条件。因此,大部分的事情即使在旅行中,也一样可以做。目前唯一的影响可能是我的录音设备不太方便携带,因此目前我决定出行期间就不录音,转而撰写/积累视频素材,或是做产品开发。(其实,非要携带上那台小小的 Blue Yeti 倒也不是不可以,最近我在推上还看到 Marques Brownlee 在去 CES 期间,把一整套非常专业的录音设备布置到了他入住的酒店里,为了消音,还把被子/毯子挂到了房间的墙上。虽说他是专业做这行的,但我也不禁小小感慨了一下,很多事情只要你想做,自然就会有办法。)

结语

前段时间接受了一个科技媒体采访,其中有一个问题的回答我自己还挺喜欢的,就用它作为这一期的结束语吧。问题是:工欲善其事,必先利其器。无论是工作还是生活,有什么特好的“磨刀法子”是你巴不得大家都知道的?面对这个问题,我第一反应并不是想到要分享什么「利器」,因为我发现当代社会影响我们「善其事」的首要因素,往往已经不是我们手中的「器」了,而是别的东西。以下是我的回答:

删掉抖音以及其他同类产品;把绝大多数的微信群(或者其他 IM 群)都设置成消息免打扰;所有的 App 都默认禁用通知,除非你认为这个通知重要得不能禁用;把所有的 IM App 都放到二级文件夹,或者移到首屏之外。

这个世界太嘈杂,嘈杂得想好好安静下来做一件事都特别困难。办法只有主动去关闭一些与世界的连接。相信我,这个世界大多数时候都只是在发出噪声而已,关闭一些连接的好处远远大于坏处。

完。

关于新系列的命名考虑

我受国外 Indie Hackers 影响挺大的,并且从 2018 年辞职成为一名 Indie Hacker,而我写的东西一般都围绕我的工作和生活展开,所以很自然地就想到用「Indie Hacker 笔记」这样的题目了。

为什么这个系列的名字要中英混用呢?因为至今我也没在中文世界找到 Indie Hacker 的合适对应词。Indie Hacker 直译是「独立黑客」,但中文里「黑客」的定义过于狭义了,刻板印象总会觉得「黑客」一定是和计算机或编程相关,但 Indie Hacker 覆盖的范围比这要大得多。事实上,我觉得在英文世界里,hack 这个词的泛化程度已经和中文里的「搞」有得一拼了。几乎什么都可以 hack:hack your life, hack your mind, hack your project, hack your iPhone…自然地,Hacker 的含义也就不再仅仅是一群搞计算机和写代码的人了。关于 Indie Hacker 这个词,indiehackers.com 的创始人(也是提出这个词的人)在 About 页面是这样描述的:

You’re an indie hacker if you’ve set out to make money independently. That means you’re generating revenue directly from your customers, not indirectly through an employer. Other than that, there are no requirements! Indie hackers are often solo founders, software engineers, and bootstrapped, but it’s totally okay if you have cofounders, can’t code, and have raised money.

由于实在没有合适的对应词,于是就决定保留英文原词了。另外再附上 IndieHackers 网站的一个相关讨论帖子:

[Discussion] What is an Indie Hacker?

AlgoCasts 2019 年 10 月小结

2019年11月30日 08:00

现在是瑞士时间 11 月 30 日晚上 9 点多,还有几个小时就 12 月了,踩在 11 月的尾巴上,得赶紧把我的每月小结写一写。这篇可能是「AlgoCasts X 年 Y 月小结」系列的最后一篇了,所以嘛,先来首淡淡忧伤的音乐定定基调:Flightless Bird, American Mouth。

So,是 AlgoCasts 要倒闭了么?这个倒没有,事实上 AlgoCasts 第一年的表现已经超出了我的预期,今年的营收目标也在 9 月份的时候就已经达到了。那为什么「AlgoCasts X 年 Y 月小结」要停了呢?Hmm,这个嘛,因为在这个框架下我的写(扯)作(淡)才华发挥不出来。事实上,每月围绕 AlgoCasts 写小结都让我绞尽脑汁。因为,每月围绕 AlgoCasts 做的事情其实是很简单的,就是录制算法视频。就算我一个月出 100 个视频,我觉得也没什么可写的。因为它的事件类型其实是单一的,就算我写出花来,说的也是我在做视频,对不对?嘛,自由职业者的生活就是这么朴实无华且枯燥:)因此,当我回顾过去一年写的 AlgoCasts 小结,除开做视频,我都会尽量在一个月里做点功能开发、搞点营销活动,这样写起小结来就还能扯点别的。不过最近几个月我已经不怎么做网站功能开发了,因此,我的AlgoCasts 月小结真的就要没有素材可写了。

当然,这个月我还是做了一次营销活动,非要写的话,整个 800 字,再升华一下随手谈谈人生,对我来说也不是什么难事。但我已经有点倦了。每月小结最主要是写给我自己看的,我要按我喜欢的方式来写。因此,「AlgoCasts X 年 Y 月小结」这个系列要停了,但是,一个涵盖范围更大,讨论主题更广的每月小结将就此产生。Surprise!

以后的每月小结将不会再只谈 AlgoCasts,而会是过去一个月工作/学习/生活中值得记录的内容。当然,能升华的我还会继续升华 233。毕竟生活中不只有柴米油盐,还有智人透过柴米油盐 YY 出来的哲学道理。由于 AlgoCasts 会继续占据我生活很大的一部分,因此每月小结肯定还是会有它的身影。不过,再次谈起来,我希望可以更感性一些。而不是冷冰冰的本月录了 X 个视频,修改了 Y 份简历,做了 Z 场模拟面试。听起来就很冷,缺少温度。

那么,「AlgoCasts X 年 Y 月小结」的最后一篇是不是还得守好最后一班岗,交待一下本月做的事情呢。其实上面我就已经说了:录了 X 个视频,修改了 Y 份简历,做了 Z 场模拟面试。哦,还搞了次促销活动。

你看,自由职业者的生活就是这么朴实无华且枯燥:)

完。

AlgoCasts 2019 年 9 月小结

2019年10月29日 08:00

这个月除了做视频,还去了趟土耳其,回了趟国,生了场病,做了三场模拟面试,研究了一下 Super Memo 算法。本月的小结音乐要祭出我的私人收藏:这是你想要的生活吗,来自「房东的猫」。

出行方面,按计划去了趟土耳其和中国,希望今年剩下的日子不用再长途旅行,不然今年的 OKR 就要凉凉了。你懂的,年末的日子就是留给突击用的。

本月还生了场病,本来生个小病这种事情实在不应该拿出来讲。不过讲真,每次生病对我的情绪影响都挺大的,进而影响工作和生活,而且我生病的频繁还挺高。于是我决定给自己制作年度生病日历,看看到底自己一年有多少天是在生病中渡过的。另外,我还准备锟斤拷锟斤拷录冶锟斤拷。嗯,为了避免公开立 flag 导致事情没有执行,此处就保留一下。关于立 flag 这一点,我是真的很迷信,哈哈哈。

另外,本月做了三场模拟面试。大家准备的充分程度不太一样,但整体上来讲,算法这一块还是要多练,练习到经典题目上来直接 bug free 解题就差不多了。有小伙伴模拟面试完就去某名厂真实面试,算法题要么是原题要么就是经典题的微小变体。变化有多微小呢?这么讲,微小到我觉得你可以直接叫原题。。。我常常在思考,我只提供算法教学视频可能对有些小伙伴来讲确实是不太够的,因为有的小伙伴连视频都懒得看,或者就只是看视频,而不愿意多花费一些力气去思考或总结。我学习一个东西的时候,总是希望从尽可能多的维度和方向去学习同一个东西,或者用不同的方法去学习同一个东西。虽然做起来没有说的那么容易,但这种意识总能让我学习的稍微好一些。另外我也常常会为学习的知识总结出一个属于自己的版本,我觉得这几乎是将知识内化到自己的知识体系中最好的方法了。你可能会遇到一个牛逼的老师,他可以把一个知识用极其易于理解的方式讲给你听,但归根结底那些东西还是那个老师的。他能做到的就是在那一刻,用他的方式让你理解某个知识。但只要你没有用属于你自己的方式把那个知识内化到自己的知识体系中,过不了多久,你就会把那个知识忘个精光。用属于自己的方式(或者说用自己的话,自己的书写)来阐述一个知识,远远比阐述本身的优劣性要重要得多。也就是说,你做笔记也好,写博文也好,归纳总结也好,只要是你自己思考的产物,那么这个产物对你而言,就会比任何一个牛逼老师帮你总结的要好得多。别人的解读永远是别人的,哪怕你去背下来,也还是别人的。为何不去创造一个属于你自己的版本呢?现在很多知识付费平台,为了赚钱,喊的口号都会让你以为,交点钱然后跟着他们的安排就可以躺着把知识学了。这世上真有这种好事么?当然是没有的!除了你自己,所有的人和工具,都只是提供辅助,希望大家在下次掏钱之前,能认清这一点。

对了,以上讲的道理,我觉得不限于学习,放在人生这个尺度上同样适用。人生中各个主题,只有你自己经历的,才是属于你的。

最后,本月还抽空研究了一下 Super Memo 算法,感觉非常有意思,在未来的某个产品中,也许会用得上。

你看我,又立 flag 了。

完。

AlgoCasts 2019 年 8 月小结

2019年9月28日 08:00

每月小结又拖出新高度了,看了眼 Wunderlist 和 Google Calendar,过去一个月可以概括如下:搬新家,装家具,修电器,做视频。网站方面加了个简单的 EDM 功能,大家肯定没兴趣听;做视频呢,也没什么好讲的。那就简单讲讲生活上的事情吧。本月的小结音乐来自人称西班牙版彭于晏的帅气男歌手 Álvaro Soler:「Sofía」。

过去一个月最主要的事情就是搬进了新租的房子。在瑞士,一个多月就找到房子并入住,应该算是比较快的了。我们租的是不带家具的房子,所以跑了几次宜家,才慢慢把家具买全。然后把安装家具这件事分摊到过去一个月,隔三差五安装几件,包括安装大件的家具和钻孔装灯。在国内,这些都花钱雇人搞定。但考虑到这边人工比较贵且我们对这边还没那么熟悉且德语还达不到自由交流的地步,所以就自己动手了。在瑞士,一般上一个租客走的时候会把他的家具都清理掉,包括灯(除非你和他提前商量好要保留)。所以我们刚搬进来时,客厅、走廊和几个房间的房顶上都只有几根裸露的电线=。=作为一个经常吐槽自己生活经验为 0 的人,在房顶上钻孔装灯对我来说还是比较困难的。。不过在安装了一两个灯找到感觉后,就越来越顺手,可以说是指哪钻哪,钻哪装哪。

除了自己安装家具,租来的房子里有几件电器坏掉了。于是开始了和本地 3 家公司的打交道过程,分别是 Service 7000 AG,Clean Up AG,Baumann Koelliker AG。每次预约上门修电器时,机智如我都是快速用英语介绍一下自己,希望对方知道我并不会讲德语。然而这并没有什么用,对方还是一定会用德语回答我。然后我会再显式地问一下对方,会不会讲英语。这基本上成了我在这边接打电话的基本 Pattern 了。Service 7000 公司的工作人员大多会讲英文,无论是电话里的客服,还是上门维修的师傅。烘干机是 Service 7000 上门维修的,换了一个中控板子,一次搞定。洗碗机就没那么幸运了,目前已经上门维修 3 次了,第 4 次约在国庆节后。橱柜灯目前上门维修 2 次,第 3 次也约在国庆后。它们分别由 Clean Up 公司和 Baumann Koelliker 公司负责,这两个公司的人员基本上不会讲英语。他们一般上门后,一句 Hello 打过招呼就开始干活。有什么问题也是直接用德语问我,然后我通过当时的上下文和他的肢体动作猜他在说什么,再用英文回答他。我估计对方会使用同样的方法猜我回答的是什么=。=当然,关键场合还少不了 Google 翻译,对方会把一些重要的信息在手机上用 Google 翻译后给我看。比如说,是哪个部件坏了需要换。

工作上,如果看过我上个月小结,就知道我目前是去 ETH 办公。又过了一个月的时间,目前可以说是轻车熟路了。我自己对比了一下之前在北京咖啡厅办公时的状态,整体上在大学里办公的状态比咖啡厅里还要更好一些。随着搬入新房子慢慢安顿下来,这个月视频产出的数量也慢慢恢复上来了。希望这个状态可以保持下去。

过两天就是国庆长假了,预祝大家假期快乐!

十大经典排序算法视频讲解

2019年9月16日 08:00

代码仓库

代码仓库包含了完整的代码实现和测试,其中 Java 版本是官方实现,其他语言版本来自社区贡献。对于每一种排序算法,如果有多种实现方法,都会尽量提供。另外代码仓库中还提供了完备的测试用例,以此确保实现的排序算法覆盖了每一种可能的情况。

GitHub 链接:https://github.com/HawsteinStudio/algocasts-sorting-algorithms

冒泡排序

视频链接:https://algocasts.io/series/sorting-algorithms/episodes/AEpoDvWQ

截图:

代码:

public class BubbleSort {

  private void swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
  }

  // Time: O(n^2), Space: O(1)
  public void sort(int[] arr) {
    if (arr == null || arr.length == 0) return;
    int n = arr.length;
    for (int end = n-1; end > 0; --end) {
      for (int i = 0; i < end; ++i) {
        if (arr[i] > arr[i+1]) {
          int tmp = arr[i];
          arr[i] = arr[i+1];
          arr[i+1] = tmp;
        }
      }
    }
  }

  // Time: O(n^2), Space: O(1)
  public void sortShort(int[] arr) {
    if (arr == null || arr.length == 0) return;
    int n = arr.length;
    for (int end = n-1; end > 0; --end)
      for (int i = 0; i < end; ++i)
        if (arr[i] > arr[i+1])
          swap(arr, i, i+1);
  }

  // Time: O(n^2), Space: O(1)
  public void sortEarlyReturn(int[] arr) {
    if (arr == null || arr.length == 0) return;
    int n = arr.length;
    boolean swapped;
    for (int end = n-1; end > 0; --end) {
      swapped = false;
      for (int i = 0; i < end; ++i) {
        if (arr[i] > arr[i+1]) {
          swap(arr, i, i+1);
          swapped = true;
        }
      }
      if (!swapped) return;
    }
  }

  // Time: O(n^2), Space: O(1)
  public void sortSkip(int[] arr) {
    if (arr == null || arr.length == 0) return;
    int n = arr.length;
    int newEnd;
    for (int end = n-1; end > 0;) {
      newEnd = 0;
      for (int i = 0; i < end; ++i) {
        if (arr[i] > arr[i+1]) {
          swap(arr, i, i+1);
          newEnd = i;
        }
      }
      end = newEnd;
    }
  }

}

选择排序

视频链接:https://algocasts.io/series/sorting-algorithms/episodes/Z5mzdwpd

截图:

代码:

public class SelectionSort {

  private void swap(int[] arr, int i, int j) {
    if (i == j) return;
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
  }

  // Time: O(n^2), Space: O(1)
  public void sort(int[] arr) {
    if (arr == null || arr.length == 0) return;
    int n = arr.length;
    for (int i = 0; i < n; ++i) {
      int minIdx = i;
      for (int j = i+1; j < n; ++j)
        if (arr[j] < arr[minIdx])
          minIdx = j;
      swap(arr, i, minIdx);
    }
  }

  // Time: O(n^2), Space: O(1)
  public void sortFromEnd(int[] arr) {
    if (arr == null || arr.length == 0) return;
    int n = arr.length;
    for (int i = n-1; i > 0; --i) {
      int maxIdx = i;
      for (int j = 0; j < i; ++j)
        if (arr[j] > arr[maxIdx])
          maxIdx = j;
      swap(arr, i, maxIdx);
    }
  }

}

插入排序

视频链接:https://algocasts.io/series/sorting-algorithms/episodes/dbGY9eG5

截图:

代码:

public class InsertionSort {

  // Time: O(n^2), Space: O(1)
  public void sort(int[] arr) {
    if (arr == null || arr.length == 0) return;
    for (int i = 1; i < arr.length; ++i) {
      int cur = arr[i];
      int j = i - 1;
      while (j >= 0 && arr[j] > cur) {
        arr[j+1] = arr[j];
        --j;
      }
      arr[j+1] = cur;
    }
  }

}

希尔排序

视频链接:https://algocasts.io/series/sorting-algorithms/episodes/zbmKZgWZ

截图:

代码:

public class ShellSort {

  // Time: O(n^2), Space: O(1)
  public void sort(int[] arr) {
    if (arr == null || arr.length == 0) return;
    for (int gap = arr.length>>1; gap > 0; gap >>= 1) {
      for (int i = gap; i < arr.length; ++i) {
        int cur = arr[i];
        int j = i - gap;
        while (j >= 0 && arr[j] > cur) {
          arr[j+gap] = arr[j];
          j -= gap;
        }
        arr[j+gap] = cur;
      }
    }
  }

  // Time: O(n^2), Space: O(1)
  public void insertionSort(int[] arr) {
    if (arr == null || arr.length == 0) return;
    for (int i = 1; i < arr.length; ++i) {
      int cur = arr[i];
      int j = i - 1;
      while (j >= 0 && arr[j] > cur) {
        arr[j + 1] = arr[j];
        j -= 1;
      }
      arr[j + 1] = cur;
    }
  }

}

快速排序

视频链接:https://algocasts.io/series/sorting-algorithms/episodes/kVG9Pxmg

截图:

代码:

public class QuickSort {

  private void swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
  }

  // [ ... elem < pivot ... | ... elem >= pivot ... | unprocessed elements ]
  //                          i                       j
  private int lomutoPartition(int[] arr, int low, int high) {
    int pivot = arr[high];
    int i = low;
    for (int j = low; j < high; ++j) {
      if (arr[j] < pivot) {
        swap(arr, i, j);
        ++i;
      }
    }
    swap(arr, i, high);
    return i;
  }

  // lomuto partition 的另一种实现,可以把最后的 swap 合并到循环中。
  private int lomutoPartition2(int[] arr, int low, int high) {
    int pivot = arr[high];
    int i = low;
    for (int j = low; j <= high; ++j) {
      if (arr[j] <= pivot) {
        swap(arr, i, j);
        ++i;
      }
    }
    return i-1;
  }

  private void lomutoSort(int[] arr, int low, int high) {
    if (low < high) {
      int k = lomutoPartition(arr, low, high);
      lomutoSort(arr, low, k-1);
      lomutoSort(arr, k+1, high);
    }
  }

  private int hoarePartitionDoWhile(int[] arr, int low, int high) {
    int pivot = arr[low + (high-low)/2];
    int i = low-1, j = high+1;
    while (true) {
      do {
        ++i;
      } while (arr[i] < pivot);
      do {
        --j;
      } while (arr[j] > pivot);
      if (i >= j) return j;
      swap(arr, i, j);
    }
  }

  // [ ... elem <= pivot ... | unprocessed elements | ... elem >= pivot ... ]
  //                         i                      j
  private int hoarePartition(int[] arr, int low, int high) {
    int pivot = arr[low + (high-low)/2];
    int i = low, j = high;
    while (true) {
      while (arr[i] < pivot) ++i;
      while (arr[j] > pivot) --j;
      if (i >= j) return j;
      swap(arr, i++, j--);
    }
  }

  private void hoareSort(int[] arr, int low, int high) {
    if (low < high) {
      int k = hoarePartition(arr, low, high);
      hoareSort(arr, low, k);
      hoareSort(arr, k+1, high);
    }
  }

  // Time: O(n*log(n)), Space: O(n)
  public void lomutoSort(int[] arr) {
    if (arr == null || arr.length == 0) return;
    lomutoSort(arr, 0, arr.length-1);
  }

  // Time: O(n*log(n)), Space: O(n)
  public void hoareSort(int[] arr) {
    if (arr == null || arr.length == 0) return;
    hoareSort(arr, 0, arr.length-1);
  }

}

归并排序

视频链接:https://algocasts.io/series/sorting-algorithms/episodes/M0G2k7pz

截图:

代码:

public class MergeSort {

  // sorted sub-array 1: arr[low ... mid]
  // sorted sub-array 2: arr[mid+1 ... high]
  private void merge(int[] arr, int low, int mid, int high, int[] tmp) {
    int i = low, j = mid + 1, k = 0;
    while (i <= mid && j <= high) {
      if (arr[i] <= arr[j]) tmp[k++] = arr[i++];
      else tmp[k++] = arr[j++];
    }
    while (i <= mid) tmp[k++] = arr[i++];
    while (j <= high) tmp[k++] = arr[j++];
    System.arraycopy(tmp, 0, arr, low, k);
  }

  private void mergeSort(int[] arr, int low, int high, int[] tmp) {
    if (low < high) {
      int mid = low + (high - low) / 2;
      mergeSort(arr, low, mid, tmp);
      mergeSort(arr, mid + 1, high, tmp);
      merge(arr, low, mid, high, tmp);
    }
  }

  // Time: O(n*log(n)), Space: O(n)
  public void sortRecursive(int[] arr) {
    if (arr == null || arr.length == 0) return;
    int[] tmp = new int[arr.length];
    mergeSort(arr, 0, arr.length - 1, tmp);
  }

  // Time: O(n*log(n)), Space: O(n)
  public void sortIterative(int[] arr) {
    if (arr == null || arr.length == 0) return;
    int n = arr.length;
    int[] tmp = new int[n];
    for (int len = 1; len < n; len = 2*len) {
      for (int low = 0; low < n; low += 2*len) {
        int mid = Math.min(low+len-1, n-1);
        int high = Math.min(low+2*len-1, n-1);
        merge(arr, low, mid, high, tmp);
      }
    }
  }

}

堆排序

视频链接:https://algocasts.io/series/sorting-algorithms/episodes/jwmBqnW8

截图:

代码:

public class HeapSort {

  private void swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
  }

  // Time: O(log(n))
  private void siftDown(int[] arr, int i, int end) {
    int parent = i, child = 2 * parent + 1;
    while (child <= end) {
      if (child+1 <= end && arr[child+1] > arr[child]) ++child;
      if (arr[parent] >= arr[child]) break;
      swap(arr, parent, child);
      parent = child;
      child = 2 * parent + 1;
    }
  }

  // i 从 end/2 开始即可,因为在二叉堆中,更大的 i 是没有子节点的,没必要做 siftDown
  // Time: O(n)
  // Reference:
  // * https://www.geeksforgeeks.org/time-complexity-of-building-a-heap/
  // * https://www2.cs.sfu.ca/CourseCentral/307/petra/2009/SLN_2.pdf
  private void buildMaxHeap(int[] arr, int end) {
    for (int i = end/2; i >= 0; --i) {
      siftDown(arr, i, end);
    }
  }

  // Time: O(n*log(n)), Space: O(1)
  public void sort(int[] arr) {
    if (arr == null || arr.length == 0) return;
    buildMaxHeap(arr, arr.length - 1);
    for (int end = arr.length - 1; end > 0; --end) {
      swap(arr, 0, end);
      siftDown(arr, 0, end - 1);
    }
  }

}

计数排序

视频链接:https://algocasts.io/series/sorting-algorithms/episodes/XOp19ap2

截图:

代码:

public class CountingSort {

  // indexes 最后存储的是排序后,相同数字在结果数组的开始位置,相同数字会依次向后(右)填充。
  // Time: O(n+k), Space: O(n+k)
  public void sortLeft2Right(int[] arr) {
    if (arr == null || arr.length == 0) return;
    int max = arr[0], min = arr[0];
    for (int num: arr) {
      if (num > max) max = num;
      if (num < min) min = num;
    }

    int k = max - min;
    int[] indexes = new int[k+1];
    for (int num: arr) ++indexes[num-min];

    int start = 0;
    for (int i = 0; i <= k; ++i) {
      int count = indexes[i];
      indexes[i] = start;
      start += count;
    }

    int[] tmp = new int[arr.length];
    for (int num: arr) {
      int idx = indexes[num-min];
      tmp[idx] = num;
      ++indexes[num-min];
    }
    System.arraycopy(tmp, 0, arr, 0, arr.length);
  }

  // indexes 最后存储的是排序后,相同数字在结果数组的结束位置,相同数字会依次向前(左)填充。
  // Time: O(n+k), Space: O(n+k)
  public void sortRight2Left(int[] arr) {
    if (arr == null || arr.length == 0) return;
    int max = arr[0], min = arr[0];
    for (int num: arr) {
      if (num > max) max = num;
      if (num < min) min = num;
    }

    int k = max - min;
    int[] indexes = new int[k+1];
    for (int num: arr) ++indexes[num-min];

    --indexes[0];
    for (int i = 1; i <= k; ++i)
      indexes[i] = indexes[i] + indexes[i-1];

    int[] tmp = new int[arr.length];
    for (int i = arr.length-1; i >= 0; --i) {
      int idx = indexes[arr[i]-min];
      tmp[idx] = arr[i];
      --indexes[arr[i]-min];
    }
    System.arraycopy(tmp, 0, arr, 0, arr.length);
  }

}

桶排序

视频链接:https://algocasts.io/series/sorting-algorithms/episodes/VBpL2omD

截图:

代码:

public class BucketSort {

  private void insertionSort(List<Integer> arr) {
    if (arr == null || arr.size() == 0) return;
    for (int i = 1; i < arr.size(); ++i) {
      int cur = arr.get(i);
      int j = i - 1;
      while (j >= 0 && arr.get(j) > cur) {
        arr.set(j+1, arr.get(j));
        --j;
      }
      arr.set(j+1, cur);
    }
  }

  // 每个桶的大小,由于桶内使用插入排序,因此桶的大小使用一个较小值会比较高效。
  //
  // 一般来说,当处理的数组大小在 5-15 时,使用插入排序往往会比快排或归并更高效。
  // 因此在桶排序中,我们尽量让单个桶内的元素个数是在 5-15 个之间,这样可以用插入排序高效地完成桶内排序。
  // 参考链接:https://algs4.cs.princeton.edu/23quicksort/
  // 参考段落:
  // Cutoff to insertion sort. As with mergesort,
  // it pays to switch to insertion sort for tiny arrays.
  // The optimum value of the cutoff is system-dependent,
  // but any value between 5 and 15 is likely to work well in most situations.
  private int bucketSize;

  public BucketSort(int bucketSize) {
    this.bucketSize = bucketSize;
  }

  // Time(avg): O(n+k), Time(worst): O(n^2), Space: O(n)
  public void sort(int[] arr) {
    if (arr == null || arr.length == 0) return;
    int max = arr[0], min = arr[0];
    for (int num: arr) {
      if (num > max) max = num;
      if (num < min) min = num;
    }

    int bucketCount = arr.length / bucketSize;
    List<List<Integer>> buckets = new ArrayList<>(bucketCount);
    for (int i = 0; i < bucketCount; ++i)
      buckets.add(new ArrayList<>());

    for (int num: arr) {
      int idx = (int)((num - min) / (max - min + 1.0) * bucketCount);
      buckets.get(idx).add(num);
    }

    int idx = 0;
    for (List<Integer> bucket: buckets) {
      insertionSort(bucket);
      for (int num: bucket)
        arr[idx++] = num;
    }
  }

}

基数排序

视频链接:https://algocasts.io/series/sorting-algorithms/episodes/q2m595mz

截图:

代码:

public class RadixSort {

  /**
   * @param arr  待排数组
   * @param bits 每次处理的二进制位数(可选值:1, 2, 4, 8, 16)
   * @param mask 每次移动 bits 个二进制位后,使用 mask 取出最低的 bits 位。
   */
  // b 表示每次处理的二进制位数
  // Time: O(32/b * n), Space: O(n + 2^b)
  private void sort(int[] arr, int bits, int mask) {
    if (arr == null || arr.length == 0) return;
    int n = arr.length, cnt = 32/bits;
    int[] tmp = new int[n];
    int[] indexes = new int[1<<bits];
    for (int d = 0; d < cnt; ++d) {
      for (int num: arr) {
        int idx = (num >> (bits*d)) & mask;
        ++indexes[idx];
      }

      --indexes[0];
      for (int i = 1; i < indexes.length; ++i)
        indexes[i] = indexes[i] + indexes[i-1];

      for (int i = n-1; i >= 0; --i) {
        int idx = (arr[i] >> (bits*d)) & mask;
        tmp[indexes[idx]] = arr[i];
        --indexes[idx];
      }

      Arrays.fill(indexes, 0);
      int[] t = arr;
      arr = tmp;
      tmp = t;
    }
    // handle the negative number
    // get the length of positive part
    int len = 0;
    for (; len < n; ++len)
      if (arr[len] < 0) break;

    System.arraycopy(arr, len, tmp, 0, n-len); // copy negative part to tmp
    System.arraycopy(arr, 0, tmp, n-len, len); // copy positive part to tmp
    System.arraycopy(tmp, 0, arr, 0, n); // copy back to arr
  }

  // 基数为 256,每次取 8 个二进制位作为一个部分进行处理,32 位整数需要处理 4 次。
  // 每次取出的 8 个二进制位会作为计数排序的键值,去排序原始数据。
  // 每次处理 8 个二进制位,是时间/空间上比较折衷的方法。
  // 如果一次处理 16 个二进制位,速度会稍微快一些。但需要额外的空间是 2^16 = 65536,远大于每次处理 8 个二进制位所需空间。
  // 如果一次只处理 4 个二进制位,速度则会慢很多。
  public void sort4pass(int[] arr) {
    sort(arr, 8, 0xff);
  }

  // 基数为 16,每次取 4 个二进制位作为一个部分进行处理。32 位整数需要处理 8 次。
  // 时间上比起 sort4pass 要差很多。
  public void sort8pass(int[] arr) {
    sort(arr, 4, 0x0f);
  }

  // 基数为 65536,每次取 16 个二进制位作为一个部分进行处理。32 位整数需要处理 2 次。
  // 时间上比 sort4pass 要稍微好一些,但额外要使用多得多的空间。
  public void sort2pass(int[] arr) {
    sort(arr, 16, 0xffff);
  }

  // 基数为 2,每次取 1 个二进制位作为一个部分进行处理。32 位整数需要处理 32 次。
  // 时间上比快排要差很多。
  public void sort32pass(int[] arr) {
    sort(arr, 1, 1);
  }

  // 基数为 4,每次取 2 个二进制位作为一个部分进行处理。32 位整数需要处理 16 次。
  // 我是打酱油的。
  public void sort16pass(int[] arr) {
    sort(arr, 2, 3);
  }

}

AlgoCasts 2019 年 7 月小结

2019年8月26日 08:00

AlgoCasts 的这个工作月正好是完整在瑞士度过的,坐在 ETH(苏黎世联邦理工学院) 的自习区,抬头是一位年过花甲的老教授在认真地工作,听着耳旁的「Stay Alive」,接下来我就要开始流水账式扯淡了。

苏黎世第一个月过得并不算轻松。办各种卡、看各种房,然后焦灼地等待邮递员叔叔给我们寄来各种文件/合同/银行卡和最重要的 Permit。瑞士的邮政处于相当主流的地位,各种重要的文件和卡直接就发挂号信给你,感觉这边的邮政相当于国内邮政加上各个快递公司,相当有存在感。幸运的是,虽然有些波折,但各件事情也都慢慢办妥了。包括租到一个还算满意的房子,预计 8 月底搬进去。这里我就不立什么 flag 了,希望后面的流程顺利。

换了一个环境后,我原来那套在北京运行得如丝般顺滑的 daily routine 就需要重建。考虑到瑞士这边在咖啡厅工作并不像国内那么主流,且咖啡更贵,我一开始的计划是在家单独弄一个书房来工作。但后来一个机灵想到 ETH 不就在苏黎世嘛,可以混到大学生当中工作呀。所以我找了一天探索 ETH,主要看都有哪些适合办公的地方。一番调研探索下来,ETH 比我想象的还要更适合当工作场所。除了图书馆,每一层都有自习区域,而且电脑室也是对外开放的。网络方面,我办的套餐是无限 4G 高速流量,用电脑连上手机热点后,上网体验和在家使用 Wi-Fi 几乎没有区别。这个月制作的一部分视频,就是在 ETH 连着 4G 热点上传到国内服务器的。吃的方面,ETH 食堂是对外开放的,因此午餐和晚餐我都在食堂里吃。虽然价格是学生的两倍,但其实也还是可以接受的。这么难吃的食物我都能接受了,两倍的价格有啥不能接受的 233。由于制作一个视频已经被我拆分成几个步骤,目前除了录音这一步要在家里进行,其他的都可以在 ETH 完成。经过一段时间的实践和调整,基本上在苏黎世的 daily routine 就可以确定下来了。几点起床;坐什么车,走哪一条路线;哪里有便宜好喝的咖啡;哪个区域的工作环境和 4G 信号更好并且采光合适,不会过于刺眼也不会过于昏暗;几点去食堂吃饭比较合适,人不太多,不用浪费时间在排队上;家附近超市的开门关门时间,以及卖货特点等等这些问题,都有了明确的答案。

这个月除了做视频,网站方面还把 PayJS 集成了进来,支持微信和支付宝。这个服务是去年某个小伙伴推荐给我的,我都一直把它放在 waiting list,直到最近收款异常(微信大佬表示要开始收保护费了!),于是我以迅雷不及掩耳盗铃儿响叮当之势,完成了申请、开通、接入、测试及上线。当然这方面也要大力赞一下 PayJS 的工单处理速度以及文档完善程度。截止目前为止,PayJS 的使用体验可以用两个字形容:真香。

另外,在 PayJS 回调并开通完相应套餐后,顺便让 Slack Bot 给我推送一条消息,把用户信息和购买信息发给我。这样每一笔成功交易后,都会有微信/支付宝给我发送一条交易信息外加 Slack Bot 给我发送一条套餐开通信息。嗯,这样应该比较稳妥了。

上周某一天还经历了水逆 4 连击。其中之一是在 ETH 工作时,F 键惊喜脱落,打断了我愉快的工作。在我短暂的 hot fix 后(把键帽底下倒 u 型的一个部件用力按缩小开口),虽然可以勉强使用。但我相当确信,只要我一奔放地码字或码码,它肯定还会掉下来,毕竟 F 键对我来说是极其高频的按键。另外一点,虽然我的 Apple Care 是到 2021 年,但查了一下,看起来只能在中国使用。事情发展到这一步,可以说是相当影响心情的了(如果你重度依赖你的笔记本电脑吃饭,应该能体会我的心情)。所幸!我把在家吃土好久的 HHKB 随身带来了瑞士。嗯,现在我每天背着它来 ETH 工作。确实是有点浮夸,可是没办法,自带键盘出问题了呀。我有个朋友(人称键少)爱好收集各种键盘,外出常年自带键盘。我依稀记得第一次面基见到他时,他正在咖啡厅外接着自带的机械键盘工作,当时我觉得大概除了他没人会这么做了。没想到今天我也已经习惯这么做了。人啊,有时候适应起新习惯来还真是快呵。

这个月还开始了德语学习。目前在 Anki 上自制 Deck 进行学习。Anki 会根据遗忘曲线,将学习内容在不同的时间段后召回,促使你重复学习,目前使用体验还不错。如果正好你也在学习需要记忆的知识,推荐一下这款应用。

流水账写完,如果你竟然耐心地看到了这里,那我就再推荐这个月看的两部电影吧。第一部是黑泽明的「生之欲」;第二部是「The Secret Life Of Walter Mitty」,中译名叫「白日梦想家」,名字虽然译得烂,但电影还可以。开头提到的音乐「Stay Alive」就出自这部电影,这也算是首尾呼应了吧。

完。

从一期播客说起

2025年8月13日 08:00

最近作客「捕蛇者说」,录了一期播客。万万没想到,主播 laike9m 为此还写了篇文章,叫 我最喜欢的一期《捕蛇者说》。作为一个友善的人,我觉得我也应该回应一篇文章。我愿把这种行为叫做「创造者之间的礼尚往来」。

既然决定坐下来写篇文章,那就写长一点吧。

我是一个年更博主,最新的一篇公开的文章《一个独立创造者的五年》是 2023 年 7 月发表的,然后我仿佛就从网络上消失了。这句话不是我说的,是我最近随机漫步在 w2solo Products 群里突然说了一句话,一位群友说的。他说,Hawstein 你消失两年了吧。这句话不完全对,因为我偶尔也在推特上发点什么,还发起过一次孤独开发者吃饭活动。

不过整体上来说,过去两年我在网络上确实不怎么活跃。我的主要活动在线下,在生活,在养娃,在做产品。这不仅不奇怪,甚至说这才是主流,大部分人的生活在线下,N 年也不会在网上说一句话。

那么,我怎么又突然在网络上「炸尸」并且竟然还录了一期播客呢?因为我在我的生活里卡住了。我开始怀疑我做的事情,感觉像是陷入「存在主义危机」。

觉知到这一点后,我决定停下来。脱离原来既定的轨道,做点不一样的事情。正如 2019 年的文章《人生不可 DP,但别永远贪心》中所写的,我决定给目前的生活添加一点随机扰动。我找朋友长谈,整理以前的读者来信,重读以前喜欢的书,陪太太一起看电视剧(一般情况下我不看电视剧),疯狂听播客,在社交媒体上表达自己的困惑,还有分享自己写的一些读者回信。// 也许我也该学习 61 刻意去玩玩游戏

然后 laike9m 就在推特上 dm 我,问我要不要上播客随便聊一聊。仔细想想,这种「连接」最是恰到好处。为此,在播客录制结束后,我还发了一条推:

最近处于一种不想做产品的状态,于是决定做点产品以外的事:比如找朋友聊天,整理读者来信,发推。这股强烈的表达欲,被 laike9m 捕捉到了,然后就收到他的私信,约我到播客聊天。

对于播客邀约我一般持谨慎态度。《一个独立创造者的五年》这篇文章发布后,我收到不少播客邀约,其中还有我挺喜欢的播客。但写完那篇文章后,我确实没有太多表达欲了,所以当时的播客邀约我都婉拒了。不是因为别的什么,电台很好,主播也很棒,就是那个时期的我真的没什么想说的了。

而最近表达欲溢出,正好被另一个人捕捉到,在和主播确认了对于我不想谈的内容可以不谈后,就欣然接受这次在线闲聊了。这次闲聊大概 2 小时,非常愉悦,全程 in the flow。最后是因为我这边家人在等着我去吃饭,所以我不得不下线了。不然的话,我感觉以当时的状态,应该还能再聊 2 小时。

我和 laike9m 说,最近我处于一种不想做产品而想找人聊天的阶段,不早不晚你正好就 reach out 了,这种感觉就像是缘分到了。时机正好,水到渠成,我喜欢这种感觉。

这一期播客我们没有提前准备什么,没有列提纲,也没有说固定要聊什么主题。我的心态完全是,我要去和两个朋友聊天,这一次与平时的区别就是要把这个过程录下来。

对话的过程非常享受,录出来的效果也很不错。GeekPlux 评论说「即兴的总是最好的」;孟岩则在 E10 让万物穿过自己 这一期播客中说:好的内容是生长出来的,不是计划出来的;而 Naval 则在 Conquering the Mind 中表述为:

I find that when I’m speaking, I do best when I’m not thinking about what I’m going to say and I won’t even hear what I’m going to say until it comes out of my mouth.

当然,我觉得,「即兴的总是最好的」这里的「最好」是针对参与者本人的最好。即,只与自己比。同样是即兴,我与孟岩和 Naval 可能还差了很远。

不过话说回来,当我回去听这一期播客,能发现许多不太完美的地方。因为听播客的时候,更多的理性与思考参与了进来。

录制播客时,我无法进行过多的自我审查。因为我们处于对话当中,我不能在每次说话前都停顿几分钟对要说的话进行审查。在这种多人对话情境下,自然而然地,我会想让对话流畅地进行。而想要对话流畅地进行,我几乎不能进行过多的思考,而是让本来在我脑里的东西蹦出来。因此,在播客中的表达往往是「不完美的」。录制完以后去听,往往会觉得,嗯,这个地方我可以举一个更好的例子;那个地方我可以给出一个更好的回答,等等。但正好是这种「不完美」的形式,这种想要保持对话流畅性的倾向,让所有参与者跨过「表达障碍」,进行了表达,不管表达水平是高还是低,内容是精彩还是无聊。录制播客,可以让所有参与者都完成表达。而「完成」对表达来说非常重要。

同样的内容,如果以写作作为表达方式,可能就死在「草稿箱」里了。非常惭愧,我的草稿箱里有许多这样「未完成」的表达。而「未完成的表达」在我看来,就等于没有表达。

从这一点看来,播客真是一种很好的表达方式。

话说回来,这期播客只是我脱离既定轨道后,所做尝试的其中一件,我还会继续其它探索。最后就以孟岩在 E30 让奇迹发生 这一期播客中的一句话来结束这篇文章吧:

人生是旷野,不是所有的游荡都意味着迷失。

P.S. 如果你还没听这一期播客,可以去听听 👉 小宇宙链接捕蛇者说链接

一个独立创造者的五年

2023年7月12日 08:00

时间过得真快啊,游离在这个巨大系统之外,已经 5 年了。

和以往任何一篇文章一样,写作时机并没有发生在任何一个里程碑的点上(里程碑发生时缺少写作冲动)。如果非要为这篇文章安排一个写作契机,那就是 solo 五周年了,需要糊一篇文章表示表示。

注意:本文结构松散,没有中心思想,想到哪写到哪,记得清我就多写点,记不清我就一笔带过。

考虑到有人会来杠「独立创造者」与 Indie Hacker 这个翻译问题,无奈的我只好在这做个说明。在这里,我认为「独立创造者」是 Indie Hacker 这个专有名词的一个合适意译或近义词,在这个圈子的固定语境中,比直译「独立黑客」要好。所以我就这么用了。关于这个问题,我在几年前讨论过:关于新系列的命名考虑

分岔路的起点

2018 年 6 月 11 日,是我从公司离职成为独立创造者(Indie Hacker)的日子。回首看这个决定,可以借用乔布斯在斯坦福大学演讲中的一句话来概括它:

It was pretty scary at the time, but looking back it was one of the best decisions I ever made.

离职后,我开始做 AlgoCasts,一个算法教学视频网站。我们姑且把这个时期叫做 A 时期。在 A 时期,我每天的工作就是研究算法题,写视频脚本,录音频,录视频,剪辑视频,发布视频。这项模式固定的工作,我做了 2 年,从北京的各个咖啡厅做到瑞士的苏黎世联邦理工学院。A 时期的我写过一篇阶段性总结的文章,我不想把这部分内容又重复一遍,感兴趣的话可以去读一读那篇文章:不上班的 613 天

A 时期的我,一心在做内容,也可以叫 info product。这是当时的我能找到的最好切入点,也为我赚到离职后的第一桶金。

内容产品的问题

AlgoCasts 是一个面向国内用户、一次性收费的内容产品。这里的 3 个关键词带出 3 个问题:

  • 面向国内用户:客单价较低(相对于海外用户来说。
  • 一次性收费:需要不断获取新客户,每月营收不稳定。
  • 内容产品:需要不断生产新内容。

当然,并不是说所有的面向国内用户、一次性收费的内容产品,就无法做出好营收。比如对于那些全平台有几百万粉丝或几千万粉丝的网红或大 V,写本书或是出个课程卖 99 元,一把梭可能就是几百万或几千万入账。

可惜我并不是这样的例子。我做的是独立产品,走的是小众路线,所以上面说的问题,是切切实实的问题。

而且,面向国内用户做内容产品,还有一个非常严重的问题:盗版。即使是像 AlgoCasts 如此小众的产品,我知道盗版过的就有 5 家了。当知道自己耗费心血做出来的内容,被人盗版然后贱卖,我的反应就是以后不会再做面向国内用户的产品了。

SaaS 之念念不忘

AlgoCasts 是我站在 2018 年 6 月 11 日这个时间点上,能为自己找到的最好切入点。但受到国外 Indie Hacker 社区影响,我其实一直都想做 SaaS (Software as a service)。加之上面提到的做面向国内用户、一次性收费内容产品的问题,我就越发渴望做一款面向海外用户、订阅制收费的 SaaS 产品。

这种渴望之强烈,以致于在我还没有任何产品想法的时候,就已经到处在和别人说我要出海做订阅制 SaaS 了。

A 时期,做算法教学视频之余,我花了很多时间泡在 indiehackers.com 这个网站上。这个网站上有非常多成功的独立创造者故事。我每天看着各式各样的独立创造者,做着五花八门的产品,想象着有一天自己也能做出一款服务于世界各国用户的 SaaS 产品。

在 indiehackers.com 上如果看到让我感兴趣的产品,我一般还会去 Twitter 上关注产品的创造者,去阅读他的推文和博客,全方位去了解这个产品及创造者背后的故事。有少数十分有意思的创造者,我会把他写过的所有博文都读了,上过的所有播客都听了,然后把他放到我的一个私人的 Twitter List 里,关注他每一天的动态。

就这么日复一日地看(帖子/采访/推文/博客)和听(播客),对国外的独立创造者圈,我几乎达到一种如数家珍的地步,仿佛自己也已经是其中的一员。

美国银行账户

2020 年春节的时候,我陪着老婆去美国出差。确切地说,是她去出差,我去当司机。每天把她送去公司后,我就开始做自己的事情。

忘了是哪天,工作之后我开始漫无目的地刷 YouTube,然后意外看到 @luoleiorg 做的美国银行开户攻略视频。视频做得很好,条理清晰。看完后,我想来都来了,要不去开个美国银行账户,方便以后给车加油。然后就走进酒店旁边的一家美国银行(Bank of America)支行,表示要开个账户(嗯,就是这么巧,我住的酒店旁边就是一家美国银行)。

接待我的是一个印度经理,一番交流得知我的基本情况后,印度经理表示现在不能给我开户。他说可以让我在美国的朋友给我开一个邀请函,拿着那个邀请函就可以来找他开户了。我心里一万头羊驼奔过,然后微笑着说了声谢谢,走出银行。

印度经理的拒绝让我更加想把这个美国银行账户办下来(越挫越勇说的就是我)。于是,我在 Google Map 上找出附近的美国银行支行,一脚油门开到最近的那一家。这次接待我的是一个白人小哥,一番愉快地交流后,不仅开了户,办了借记卡。小哥还问我要不要顺便办张信用卡,我拒绝了。毕竟给车加油,一张卡就够了。(此处还要感谢绍波帮我接收银行卡)

当时去办这张美国银行卡,纯粹就是想在美国给车加油时能方便一些。驱动力完全源于一个社恐不想在给车加油时和陌生人有任何交互的心理。

万万没想到,当时意外开的美国银行账户,却成为我后来做海外 SaaS,办离岸公司很重要的一步。当时走进一家 BOA 支行办卡时,我绝对想不到它未来会发挥的作用。但现在回过头去看,却非常的清晰。

You can’t connect the dots looking forward; you can only connect them looking backward.

SaaS 之必有回响

从美国出差归来,回到瑞士,短短一个月的时间,新冠就开始肆虐。我记得是 2020 年 2 月底,谷歌苏黎世宣布开始居家办公。我也告别在苏黎世联邦理工学院精心挑选出来的办公点(光线好,网络信号强),然后开始漫长的居家办公时期。

在居家办公时期,我每天主要还是做两件事:做视频和看产品(及其创造者的故事)。在这期间,我看到一个有意思的独立创造者,他做的是电商平台上的效率工具。产品本身其实中规中矩,但这个独立创造者的故事却很有意思。我阅读了他博客上大部分文章,很受启发。

当时我注意到,他做的工具只是针对北美市场的一个电商平台。于是我就想,欧洲市场是否也有电商平台需要类似的工具。经过一番调研,果真如我猜想的一样,欧洲这边的电商平台同样有类似的需求,而卖家们对工具的渴求散落在互联网各个角落。

完成调研后,我把调研结果包括当时已有的解决方案归档到我的笔记中,和所有其他产品想法一样,先让它沉淀一段时间。

这一次,我感觉到了些许微妙的不同。

不像以往的产品想法,沉淀着沉淀着就被遗忘。这一次的产品想法,随着日子的流逝而愈发强烈地侵占大脑。几个月后,我决定挥棒了(借用巴菲特的比喻,每个出现的产品想法就像一个抛向我的棒球,我可以静静地看着它们飞过,什么也不做。一旦发现一个绝佳好球,再全力挥棒。

一开始我还「理性」地分配了 60% 的时间做视频,40% 的时间做新产品。可是我很快发现,我做视频的时候,心里想的也全是新产品。后来我干脆也不装了,暂停视频的制作,所有时间全都投入到新产品的开发中。

三周后,新产品上线,包含 20 几个功能,宣发视频,使用指南,FAQ 一应俱全。

上线第一天,开始有用户。第一个试用期结束后,开始有付费用户。

我的第一款面向海外用户、订阅制收费的 SaaS 产品就这样诞生了。

而我的念念不忘,也有了第一个回响。

Stripe

三周的时间,撸了一个完整的 SaaS 产品。麻雀虽小,五脏俱全。后端服务的开发对我来说是最简单的,手握 Scala 刷刷两下就搞定。前端部分边学边做,感谢 Evan 的 Vue.js,让这部分工作也变得简单愉快。整个开发环节里,稍微比较复杂的就是支付服务的接入。毕竟是面向海外用户的产品,没法简单地放个微信/支付宝二维码就开始收款。

海外支付服务提供商有不少,在经过一番详尽的调研后,我选了 Stripe。这时候我那个为了加油而开的美国银行账户就派上用场了。由于 Stripe 不支持中国大陆,我只能在它支持的国家列表里选一个来注册。考虑到我已经有一个美国银行账户,于是决定注册 Stripe 美国账号。

注册 Stripe 美国个人账号,除了需要一个美国银行账户,还需要 SSN (Social Security Number) 或 EIN (Employer Identification Number)。SSN 我自然是没有的,但 EIN 则每个人都可以申请。更妙的是,你可以在 Fiverr 花点钱让别人帮你快速申请下来。有多快呢?我的一天就办下来了。

使用美国银行账户加上个人 EIN 顺利申请下来 Stripe 账号后,我就开始把 Stripe 集成到自己的产品中。这一块的开发者体验,也是好得不要不要的,无论是文档还是 API 设计,都相当棒!

随着产品营收的增加,Stripe 很快就发来邮件要求提供美国政府签发的文件,以进一步验证账户所有人的名字以及地址。我把办理 EIN 时 IRS 给的 147C 信件提交上去就可以了。

接下来,产品的 MRR (Monthly Recurring Revenue) 不断增长。到 2020 年 12 月,MRR 超过我上班时的工资并且增长趋势不停,我知道是时候注册一家公司了。

用了几年 Stripe,个人觉得,如果你要出海做 SaaS,支付服务商这一块,闭眼选 Stripe 就对了。当然,尽量别做高风险的业务,毕竟和钱直接相关,风控很严,Stripe 账号被封也是经常有的事。

美国公司

离岸公司有一些常见注册地,简单思索后,我决定注册一家美国公司。第一个原因是,我使用的是 Stripe 美国账号。注册美国公司后,我只需要把 Stripe 账号中的税务信息、商业信息和银行账户修改成公司的即可,无需迁移客户的订阅,非常方便。第二个原因是,注册美国公司很简单,全程可在网上进行。第三个原因,在互联网和科技行业,如果出了什么新产品或新服务,美国几乎总是第一个可以体验到的国家。第四个原因,美国公司可以做到 0 交税(在美国只报税不交税)。

注册美国公司我参考的是以下这篇文章,至于为什么没使用 Stripe Atlas 而是用了 Firstbase,文章中也有写。

https://www.indiehackers.com/post/setting-up-an-us-delaware-llc-and-bank-account-fully-remotely-as-a-non-us-citizen-resident-07a3191751

我的美国公司运营至今,每年除了报税季整理财务数据忙一下,几乎就没有其他维护负担了,非常轻量。

随手附上我在推上写的关于美国公司的报税小知识,说不定你想知道。链接:

https://twitter.com/Hawstein/status/1714157295419179120

微型公司与超级个体

公司会越来越小,个体会越来越强。这是我坚信的一种趋势。

随着科技的发展,各种基建越来越发达,越来越模块化,做事变得越来越容易。

这一点在互联网行业尤其明显。如果有一天你突然想做一个 SaaS 产品,你会发现这个过程中你需要的大部分东西都有相应的公司在提供垂直的细粒度的服务,而你基本上就只需要关注你的核心业务,其他全部可以使用第三方服务。这样一来,就极大地减少了你的工作量。

这种服务越来越垂直细化的局面极大地放大了个体的能力。在今天,你可以一个人开一家公司,不组建团队,不招聘员工,不需要办公室,做出一个完整度非常高的产品,去解决一个非常具体的问题。并且在这些第三方服务的帮助下,产品/设计/开发/市场/运营/销售各个环节一个都不落下。年利润可以做到百万甚至千万级别。这放在以前是根本不可能的,现如今不仅可能,而且成功案例越来越多。

微型公司的极致就是「一人公司」,一个人就是一家公司,个体就像传统的手艺人一样,全面参与到产品的各个环节。这正是我目前在践行的,并乐在其中。

雇人与否

产品的 MRR 稳健增长,我开始考虑是否需要雇个人来帮我处理客服相关的工作。

经过一番调研,我发现出海 SaaS 如果想雇佣非技术人员(比如客服),那么菲律宾会是一个非常好的选择。主要有两个原因:1. 人力成本低。2. 英语好。更棒的是,还有专门的公司帮你从菲律宾招到满足你要求的合同工,比如我收藏的 Shepherd。

研已经调好了,服务也选好了。但我最终没有走出「雇人」这一步。网上有张图可以很好地描述我在这件事情上的心理状态:

现阶段的我喜欢一个人自由自在做产品的感觉,我想做就做想歇就歇,但凡这个系统里多一个人,我的自由度就会被削弱一些。另外,我是一个社恐,但凡能不和人打交道就完成一件事,我就会选择不和人打交道。

以上是现阶段的我不雇人的「两个但凡」。虽然雇人的想法时不时还是会冒出来,但一想到这「两个但凡」,也就作罢了。

技术之外

Naval 说过

Learn to sell. Learn to build. If you can do both, you will be unstoppable.

我观察到不少优秀的技术人,尝试转型做独立创造者,最后不了了之,往往就是因为只会做(Build)不会卖(Sell)。

技术人嘛,做个 App 做个网站是不难的。但是要让别人花钱来买你的产品就没那么容易了。为了把自己做的产品卖出去,我做过不少事情。这些事并不是什么秘诀,网上一搜有大把的教程,甚至很多是你凭常识和直觉就知道可以这么做的。但根据我的观察,很多人连尝试一下都不愿意,或者才浅浅地试了一下发现不 work,就不愿意再做了。

下面是我为了卖产品做过的一些事情。

让朋友帮忙写好评。新产品上线,网络上关于它的讨论肯定是 0。这时候如果一个新用户到来,他能看到关于这个产品的一些好的评价,那么他安装使用你的产品的可能性是不是就增加了一点?另外,好评其实都是我精心写好的,朋友们只需要用着自己的账号粘贴上去就行。麻烦朋友好评,但不要麻烦他们费脑去帮你想那段话,这是对他们时间的尊重。

让用户写好评。一旦一个用户愿意付费,或是表现出对产品的喜爱,或是我及时完成了一次客户支持,我就会趁热打铁,让他帮忙去打个五星好评。这时候的用户一般都乐于完成这个举手之劳。

给潜在客户 DM 和邮件。你应该要知道你的潜在客户会在互联网上什么地方聚集或出现,TikTok? Twitter? Instagram? Reddit? LinkedIn? Facebook? Quora? 找到他们,如果能直接发私信,就发私信;或者能找着邮箱,就发邮件。精心准备好用于推销你产品的那条私信或邮件,并做好准备它们石沉大海,甚至收到嘲讽或劈头盖脸的批评。

在互联网上留下你的产品名字及官网链接。到 YouTube 上找到相关的视频,到 Reddit 上找到相关的帖子,到 Quora 上找到相关的问题,到 Twitter 上找到相关的讨论,到 Facebook 上找到相关的群组,留下评论和回答。尽量给出有用的信息,最后再带一嘴自己的产品。要卖,但不要那么明显。

内容营销一:写文章。写一篇图文并茂的长文,并把产品的关键词合理地放到文章当中。尽量使用短句,这样阅读起来更轻松;尽量多地使用图片,使文章看起来更丰富;行间距和段间距调大一些,给阅读留有呼吸距离。如果这些建议看起来又抽象又枯燥,那直接对照下面这篇文章,模仿这位著名光头的写作手法即可:Content Marketing - The Definitive Guide。长远来看,内容营销可以为产品带来免费的高质量的自然流量,值得投入时间。

内容营销二:做视频。和写文章类似,只不过换成了视频形式。

付费广告。这是短期内最简单有效的获客方式。我尝试过以下平台的付费广告:Google, Facebook, Instagram, Reddit,几个试验下来,最终发现对于我的产品,还是 Google Ads 最有效。在那之后,我就长期让 Google Ads 跑着,并切身地体会到 Google 赚钱有多么容易。

Affiliate Program。有偿地让用户帮你推荐,属于一种双赢方法。对于我的产品,如果一个用户推荐了一个订阅用户,那么我会把这个订阅收入的 25% 给推荐者。只要订阅者不取消订阅,推荐者就可以一直收到那 25% 的订阅费。

口碑传播。除了内容营销,口碑传播也属于卖产品的终极大杀器。我的产品有不少付费用户就是由已有的付费用户推荐而来。要让用户自发地去传播你的产品,首先你得有一个好产品,然后你要有一个好的客服。如果你的产品是惊为天人的好,那么 0 客服也能让千万人口碑传播,比如 ChatGPT。但大部分的产品都只能算是正常的好,这时候客服做得怎么样,就很大程度地影响了客户对你的产品的态度。对于我的产品,我估计大部分客户的态度都是:产品如预期般工作,但客服却是顶级的好。

另外还有一些小事不值一提,这里就不写了。比如工作之余,我会在 Instagram 上关注潜在客户,然后给他们的帖子点赞。这件事其实可以做个工具自动化来做,但由于我把它视为一种放松活动,所以一直都是手动进行。

产品想法的涌现

刚开始的时候,我不知道做什么产品。而一旦做出一个产品并成功运转起来,产品想法就不断涌现。

产品想法的第一个来源是已有产品的客户。我一直和客户保持良好的沟通,无论是问产品问题,还是报 bug,还是提建议,我都会很及时地回复。产品初期,我会在即时聊天中立即回复或者在收到邮件的 1 小时内回复。后期我会在收到邮件的 24 小时内回复。这样一来,这些客户就乐于把他们的想法告诉我。于是,我会在收件箱里收到客户请求做某些新产品的邮件。这些都是来自一线真实客户的需求,他们会清晰地描述自己遇到的问题,希望我能做个产品来帮助他们。这类需求邮件我收到不少,我会把它们都先记录到笔记中,也许未来某一天就会把它们做成产品。

产品想法的第二个来源是我自己做产品的过程中遇到的问题。一旦把围绕一个产品相关的各个环节(产品/设计/开发/市场/运营/销售)都跑一遍后,就会发现,有不少现有解决方案都不够好,而这些不够好的解决方案,就是新产品机会。

到了一个阶段,就会发现自己已经积累了不少产品想法。而且由于这些产品想法都是来自一线真实用户,它们往往是真实有效的需求,而不是自己 YY 出来的伪需求。这时候,我发现自己就到了另一个阶段,可以用 Derek Sivers 的一本书来描述:Hell Yeah or No

即,要么一个产品想法引起了我极大的兴趣,否则就不要去做它。这样有助于在很多的想法中,筛选出那个你特别想做的产品。

到了 2021 年 4 月,已有产品已经不太需要什么投入(功能,onboarding,文档都已经比较完善),于是我从那些记录的想法中,挑了一个挑战大复杂度高的,开始打造新产品。

把客户当作朋友

在做产品的时候,我有好几次遇到这样的情况:一个客户希望我开发一个功能来帮助他解决一个具体的问题。我分析后发现,如果要完美解决这个问题,需要考虑非常复杂的情况,开发时间会很长。但如果只是要解决这个客户的特定问题,就会简单很多。

以前的我一定是会选择花更长的时间去开发那个完美解决方案。但某次我突然想到以前帮助朋友或同事解决问题的场景。一个具体的朋友,遇到一个特定的问题,希望我写个程序帮他解决。这时候,我会花几天时间去开发一个软件帮他解决一个大类的问题吗?当然不会!对于我这个朋友来说,他遇到的是一个具体的特定的问题,而不是这个问题所属的泛化后的一类问题。他现在最关心的是怎么快速地解决眼前的问题,其他的如软件 UI,实现方案是否优美,他根本不会在意。想清楚这一点,我的最优做法就应该是花几分钟时间糊一个脚本,快速帮他把问题解决。

当然,做商业产品倒也不能这么潦草。只不过当我问自己,如果这个客户是我的朋友,那么我会让他等 3 周再拿到解决方案吗?还是今天就帮他把问题解决了,让他可以开心地回家吃个晚饭?

现在的我选后者。毕竟开心地吃晚饭是件很重要的事情。

具体实现上倒也不一定是丑陋的(不要一上来就想着全是写死的代码)。我的做法是把「问题域」剪枝到一个足够小的空间,既解决了当前这个客户的特定问题,又留下了一定的扩展性。这种方法尤其适合细分领域的小众产品。因为这类产品的总用户数并不多,可能也就几千个或几万个。这时候我们花费大力气开发一套完美方案就不是很必要。一来是开发时间长,二来可能维护成本也会高很多。

这些年我用这个方法做了一些产品功能,不仅客户开心,我也开心。而且你猜怎么着?我留下的那些扩展性,一个也没用上!

生意即艺术

很早我就有这种感觉,即做生意(商业)是一门艺术。在看了 Derek Sivers 的两本书后:Anything You WantYour Music and People,我更加确信这一点。

做生意和做艺术一样,你可以在各个环节发挥自己的创造力。你可以借鉴、融合别人的创意,也可以打破常规,尝试一些别人从来没试过的事情。

你可以在开发产品时,发挥创造力,打造一个独特有个性的产品;你可以在营销产品时,发挥创造力,比如写一封有趣的营销邮件(而不是套用死气沉沉的模板);你可以策划一场怪异的活动;也可以给客户送去一份意料之外的礼物。你可以和客户聊天聊成朋友,然后让他帮你推广产品;也可以给客户发 10 刀现金,让他给你一个好评。

做生意过程中的每一个环节都像一张白纸,没有任何金科玉律规定你该怎么做,你可以按你喜欢的方式去书写它。这与创造一部小说,一幅画作,一个雕塑,一首诗歌,并无本质区别。

当然,前提是你得喜欢做生意,正如你得喜欢写作,绘画,雕塑或诗歌,否则这项活动对你来说就是枯燥无味且煎熬的。

最好的时代

这是最好的时代,还是最坏的时代,取决于我们从哪个维度哪个切面去看这个时代。

就全球化 SaaS 及独立创造者而言,我觉得这是最好的时代。借助那一行行运行在全球各地机器上的代码,个体仿佛获得了阿基米德口中的杠杆,撬动了从未敢想之巨物。

代码永不眠。

我时常心怀感恩,能生在这样的时代。可以按自己喜欢的方式去创造并以此为生,我做的产品可以轻松到达世界任何一个接入了互联网的角落。而素未谋面的陌生人,用我的产品改善了他们的生活及工作质量,并回馈以金钱和感谢。其中一些客户,还和我成了朋友。

身处这样的时代,我尽量让自己不要浪费时代提供的丰富资源和机会,尝试去做点什么,去创造点什么,通过创造出的产品/作品,与这个世界产生联结,并最终与有趣的人和事相遇。

倘能做到以上这一点,大概连王小波先生都会认为我的一生是成功的。

交个朋友

王小波说,「我活在世上,无非想要明白些道理,遇见些有趣的事。倘能如我所愿,我的一生就算成功」。在这里,我想把「有趣的事」改成「有趣的人」,因为我觉得人比事有趣,而有趣的事大概率也是有趣之人所为。

当我耗费力气写这篇文章时,Roy 老师问我是不是准备卖课了?哈哈哈,据我观察,卖课确实是很多独立创造者的最终归宿,无论国内外。但我暂时没有这个想法,如果非要说有什么私心的话,那就是把自己扔出去,看看宇宙有什么回响。

Derek Sivers 在自己的网站首页留有这么一句话,

I love meeting new people, and I reply to every email, so say hello.

我很是喜欢他的做法。

那么在文章结束前,我也效仿一下吧(拒绝 IM,让我们用邮件连接

我喜欢和有趣的人交朋友,邮箱 tomhawstein@gmail.com,来 say hello 吧!

更新一:在收到几十封邮件后,我觉得有必要在这里加一条更新。如果你最终决定给我发邮件,请不要真的只写一个 Hello 就发过来=。=多少写点东西吧。你叫什么?在哪个城市?做着什么工作?有什么爱好?最近在看什么书?听什么音乐?看什么电影?有什么心得体会?如果还能分享一个关于你的小故事,那就再好不过了。

更新二:在收到一些访谈邀约邮件后,我觉得有必要再加一条更新。我最近没有接受播客或访谈邀约的计划,所以提前在这里说明一下,以防有人在邮件中问起。

题图

Credit to Hawstein

Plan 200 完结后做什么

2020年1月13日 08:00

近期 AlgoCasts 完成了网站上 5 个系列(https://algocasts.io/series),共 211 个算法视频的制作。算是一个小小的 Milestone 吧,接下来会做以下几件事情:

  • 录制 Plan 250
  • 录制专题:好玩的数据结构
  • 制作极简题解
  • 开发神秘 Chrome 插件(不要问,问就是否认三连:我不是/我没有/别瞎说啊)

录制 Plan 250

视频制作仍然会是 AlgoCasts 的主要工作,根据近期收到的反馈,接下来的算法视频中,会提高以下两类题目的录制频率:

  • 动态规划
  • 贪心

录制专题:好玩的数据结构

之所以要录制这个专题,是由于在讲解算法题目的过程中,有的算法需要用到一些高级一点的数据结构。但如果在讲解题目的视频中,花大篇幅讲某个通用数据结构,会有以下问题:

  • 喧宾夺主。(讲算法题目的视频就应该专注讲题目,数据结构是辅助工具)
  • 通用知识耦合到一个解决具体问题的视频中。

因此,我决定做个单独的专题来讲解这些好玩又好用的数据结构。

制作极简题解

如果说算法新手需要一个详尽的视频来讲解每个算法题目,那么对于已经有一定经验的小伙伴或者说基础本来就不错的小伙伴,一份类似 Cheat Sheet 的极简题解,就会是一份更加称手的学习资料或复习资料。即使对于同一个人,前期看视频讲解,后期通过 Cheat Sheet 复习,这种组合学习法,也往往会比单一学习法更加高效。

开发神秘 Chrome 插件

目前没有更多信息可以透露。不要问,问就是否认三连:我不是/我没有/别瞎说啊。

Indie Hacker 笔记 | 第 14 期

2020年1月8日 08:00

又到了码字的时间,这一次的心情很轻松。我想主要原因是,「AlgoCasts 每月小结」系列的完结,带来一个新系列的开始。人总是喜欢新的开始,正如新年给人以希望一样。新系列的名称定为「Indie Hacker 笔记」,由于它的前身「AlgoCasts 每月小结」已经出了 13 期,因此「Indie Hacker 笔记」就从第 14 期开始(关于新系列的命名考虑,文末会给出解释)。

AlgoCasts

距离上次小结已经过去一个多月了。这期间,终于把 AlgoCasts Plan 200 剩余的视频录完。至此,目前网站上 5 个系列共 211 个视频也就全都完结了。昨天把最后一个视频发布出去后,心情有点像来到了一个马拉松补给站。停下来喝点水,吃点东西,然后望望后面的路,想想接下来怎么跑得更好。小伙伴们也开始问我接下来的录制计划,这个在接下来几天之内应该就会发布到论坛公告上。时间过得可真快,不经意间,AlgoCasts 已经上线一年多了。而这一年多,我的工作生活模式也发生了很大的变化,遇到了不少有意思的人和事,感觉也差不多是时候写个跨度大一点的回顾了:)2020 年,我仍然会把大部分时间和精力放在 AlgoCasts 上,感谢一路陪伴与支持我的小伙伴们!除此之外,可能还会稍微分出一点时间来,开发一个小产品。这个小产品我已经构思挺久了,不过去年一直克制自己不要轻易开新坑,希望今年它能顺利面世。

德语

圣诞节后,我们把德语课的频次从一周一节提高到了一周两节。主要基于两个考虑,一个是多留点时间给我准备德语考试,二是德语老师在三月底要去维也纳进修他的语言学专业,我们想在他离开瑞士前把课程上完。到目前为止,我觉得德语学习的效果还是不错的。加之每天就生活在一个讲德语的城市,在学校里,在超市里,在车上,在路上,满目可见的都是德文,耳濡目染,进步也就快一些。我时不时会把这些生活中看到的德文拍照保存,然后再翻译学习。也经常为能看懂生活中某处出现的德文,为能听懂旁人聊天中出现的一些词汇或句子而小小高兴一下。在外买东西时,我也总是优先使用仅有的一点德语和对方交流,直到对方突然说出一个生词或是一个陌生的句子,使我露了馅,对方才会意并礼貌地切换成英语。这样有趣的例子可以说不胜枚举。零基础开始学习一样新东西的好处就是,进步是以一种可见的速度在发生的,毕竟起点太低了,越往后提升就越困难。不过关于德语学习,我还不需要考虑到「往后」这个阶段,毕竟还有段距离。

阅读

12 月看完了一本书,来自 James Clear 的《Atomic Habits》。这本书是从别人推荐书的推文回复里看到的(最近书架上至少有 4 本书是从别人的推文中挖掘出来的,我管这叫 steal from the tweets),于是在网上看了看评价后果断下单。书挺薄的,每天通勤路上看,很快就看完了。我觉得这本书写得还不错,书中倡导的「Build Your System」让我联想到福柯的「自我技术」。简言之就是,你的外在或内在系统,都可以由你精心设计,设计成适合你自己的系统,让你在这样一个系统内沿着理性为自己设定的路径前行,并且阻力尽可能小。整体上来说,我还是挺推荐去看一看这本书的。我有不少观点和书中观点一致,但如果让我写,现阶段应该没办法像作者写的那么好。关于输入和输出,我自己有一个理论,就是你永远只可能输出你所有输入的一个很小占比。所以,为了写一本还不错的书,为此要储备的知识与素材,要远多于书中所呈现的东西。当然了,输出垃圾不受这条理论约束:)

顺便提一句,关于「Build Your System」或者说「自我技术」,目前我了解到的人中,Stephen Wolfram 可以说是做到了极致。Stephen Wolfram 是计算机科学、数学、理论物理方面的著名科学家,是 Wolfram Research 的创始人,Mathematica 的首席设计师,《一种新科学》的作者。多年来,他一直在 hack his personal infrastructure。关于这些,强烈推荐阅读一下他写的长文:Seeking the Productive Life: Some Details of My Personal Infrastructure,相信你会获得一些启发。

App

最近在朋友的推荐下,开始使用一个 App 来记录时间,叫「Now Then」。一开始我对这个 App 并不抱多大预期,但在用了一小段时间之外,竟然发现意外地简单好用。如果你像我一样有记录时间的习惯,可以考虑下载来使用一下。关于记录时间这件事,最早我是从「奇特的一生」这本书看到的。这本书讲述了主人公「柳比歇夫」是如何使用他的时间统计法,对他做的事情以及花费的时间进行记录和研究的。后来我就开始探索适合自己的时间记录方式,也简单搜索过相关的辅助工具,不过都没遇到特别好用的。所以后来我干脆就用 Wunderlist + Evernote 的方式手工记录。我记录时间的方式不像「柳比歇夫」那样严苛,主要是围绕工作以及一些比较花时间的事情,碎片时间一般不记。这个不经意的习惯已经跟随我多年,目前我觉得带来的好处是,除了知道自己大量的时间花费到了哪里,对时间的敏感度也提升了。另外,在开始做一件事前,我会预估一个时间,做完后再记录下实际使用的时间,进行对比。如果这件事是需要经常反复做的,一般经过一段时间调整后,时间预估就可以达到一个比较准确的程度。

旅行

旅行方面,12 月份去了趟布达佩斯。在把所有细节都忘记后,目前我脑里关于布达佩斯的记忆就剩下:好看的建筑,好吃的美食,舒服的温泉。吃的方面,无论是食材的丰富程度还是做法的多样性,都比瑞士要高出不少。当然了,如果你是从国内出发去布达佩斯,请忽略我关于美食的那句评价。一月份还有两次出行:米兰和湾区。来瑞士后,出行变多了,所以最近还在思考以及需要解决的一个问题就是,如何在出行期间不打断我的某些 routine。所幸,我工作或生活中做的大部分事情,都不太需要依赖很「重」的外部条件。因此,大部分的事情即使在旅行中,也一样可以做。目前唯一的影响可能是我的录音设备不太方便携带,因此目前我决定出行期间就不录音,转而撰写/积累视频素材,或是做产品开发。(其实,非要携带上那台小小的 Blue Yeti 倒也不是不可以,最近我在推上还看到 Marques Brownlee 在去 CES 期间,把一整套非常专业的录音设备布置到了他入住的酒店里,为了消音,还把被子/毯子挂到了房间的墙上。虽说他是专业做这行的,但我也不禁小小感慨了一下,很多事情只要你想做,自然就会有办法。)

结语

前段时间接受了一个科技媒体采访,其中有一个问题的回答我自己还挺喜欢的,就用它作为这一期的结束语吧。问题是:工欲善其事,必先利其器。无论是工作还是生活,有什么特好的“磨刀法子”是你巴不得大家都知道的?面对这个问题,我第一反应并不是想到要分享什么「利器」,因为我发现当代社会影响我们「善其事」的首要因素,往往已经不是我们手中的「器」了,而是别的东西。以下是我的回答:

删掉抖音以及其他同类产品;把绝大多数的微信群(或者其他 IM 群)都设置成消息免打扰;所有的 App 都默认禁用通知,除非你认为这个通知重要得不能禁用;把所有的 IM App 都放到二级文件夹,或者移到首屏之外。

这个世界太嘈杂,嘈杂得想好好安静下来做一件事都特别困难。办法只有主动去关闭一些与世界的连接。相信我,这个世界大多数时候都只是在发出噪声而已,关闭一些连接的好处远远大于坏处。

完。

关于新系列的命名考虑

我受国外 Indie Hackers 影响挺大的,并且从 2018 年辞职成为一名 Indie Hacker,而我写的东西一般都围绕我的工作和生活展开,所以很自然地就想到用「Indie Hacker 笔记」这样的题目了。

为什么这个系列的名字要中英混用呢?因为至今我也没在中文世界找到 Indie Hacker 的合适对应词。Indie Hacker 直译是「独立黑客」,但中文里「黑客」的定义过于狭义了,刻板印象总会觉得「黑客」一定是和计算机或编程相关,但 Indie Hacker 覆盖的范围比这要大得多。事实上,我觉得在英文世界里,hack 这个词的泛化程度已经和中文里的「搞」有得一拼了。几乎什么都可以 hack:hack your life, hack your mind, hack your project, hack your iPhone…自然地,Hacker 的含义也就不再仅仅是一群搞计算机和写代码的人了。关于 Indie Hacker 这个词,indiehackers.com 的创始人(也是提出这个词的人)在 About 页面是这样描述的:

You’re an indie hacker if you’ve set out to make money independently. That means you’re generating revenue directly from your customers, not indirectly through an employer. Other than that, there are no requirements! Indie hackers are often solo founders, software engineers, and bootstrapped, but it’s totally okay if you have cofounders, can’t code, and have raised money.

由于实在没有合适的对应词,于是就决定保留英文原词了。另外再附上 IndieHackers 网站的一个相关讨论帖子:

[Discussion] What is an Indie Hacker?

❌
❌