MacTalk By 池建强

Featured

这是池建强的个人博客,我会不定期输出一些思考,希望对读者有帮助。

我有个公众号,叫做 MacTalk。开通于2012年末,内容起于 Mac 而不止 Mac,沿用了一贯的科技与人文相结合的风格,文风有趣,又增加了一点力量。其中有我对生活的思考,对边界的探寻,有我身边的人和他们的故事,其中的一些文字还记录了这个时代的某个剪影,或某段情感。

我自己充分享受着写作与编程的乐趣,输出的文字对我意义非凡,它们能够帮助我探索、梳理和记录生活。

关注『MacTalk』请微信搜索『池建强』或是用微信扫描右边的二维码。

我的个人作品:《MacTalk·人生元编程》《MacTalk·跨越边界

文字版权属于池建强所有,付费转载,相关媒体转载请与新浪微博 @池建强 联系

十二 03

张小龙 的 22 年和微信的 8 年

今天中午看到一篇文章,张小龙22年,讲的是张小龙从做 Foxmail 一直到微信 2019 的事情,写得挺好。虽然很多东西我都知道和听过,甚至和张小龙交流过,但每次看到他和微信的故事,总是让人很激动。

张小龙从 90 年代的程序员一直到微信 2019,经历了整个互联网的发展。微信则创立八年多,成为国民产品,几乎代表了整个中国移动互联网的一个侧面。这篇文章的文末还提供了一个石墨链接,罗列了作者的参考资料,极大丰富,值得大家读读。

https://shimo.im/docs/whkrJWcykkTwYDKW

做一个好产品非常难,做个伟大的产品,简直难于上青天。谁不想把产品做大呢?很多产品规模小或者最终死掉,那都是人和组织的能力不够,没有人愿意把应用做小。张小龙在文中这么说:

「其实,任何产品如果能够做大(这个意味着它有更多的用户或者平台化),那么它一定不会放弃这样的机会。所以,我们看到很多小众的产品,是因为注定它的市场就是小众的、或者它不能做大,并不是故意想要做小,没有人愿意把应用做小。所以“小而美”会存在,有些人并没有这么多资源去做很大众化的通用的产品,它在某个领域里面去做,形态上看是小而美。

但是,如果微信我们不做成平台化、不做大,那我们就会死掉。因为你本身是个通讯工具,你必须要大,这时候大而全就是美的,否则它是病态的。并不是一定说小就美了,大就不美了,不是这样子的。」

我们做了两年产品,用户做到了百万级别,收入到了亿的规模,对比从前,进步不小,但整体上看,我们还是很小。想不想做大?当然想,但是一方面需要资源,一方面需要能力,而这些都需要时间。我们只能持续的探索,各种尝试,品味失败,偶尔体验小小的成功,然后继续艰难向前。

我们是学不了微信的,阿里、腾讯和华为的东西,都挺好,但不是我们东西,我们可以拿一点进来实验,但最终我们要拿出自己的东西。就像酿酒,你不能一直喝葡萄汁,也不能兑水,最终得是一杯美酒。

有时候做产品,真的是非常孤独。

10

有意瞄准,无意击发

MacTalk-L1000217 7:14:2018

今天的题目估计很多经历过大学军训、打过步枪的读者都不陌生。你五体投地趴在地上,怀里揣着步枪,哆哩哆嗦压上子弹,打开保险,近视眼镜和眼镜后面的眼珠都闪烁着捉摸不定的光。这时候你的教练悄悄的凑过来在你耳边低语:有意瞄准,无意击发。嗯,就这句话。

什么意思呢?射击的时候,要把你的武器、身体、注意力都指向目标,全神贯注的瞄准,至于什么时候扣动扳机,不知道,这个是无意识行为,也许是某个小小的因素,让你无意间扣动了扳机,可能是风吹草动,可能是心流涌动,子弹就射出去了,能否击中目标,也是未知之数。

最近做产品,就有这种感触。

以前听吴军老师的专栏,他说到了自己出书的事。吴军老师是个科学家、计算机工作者、投资者,也是个高产高质的作者,他写的书又多又好,还不限于某个专业领域,叫好叫座,在 IT 圈子里,可以说无出其右。不过,好的东西放一起,也有个比较。在吴军眼中,他最钟意也是花费了最多心血的两本书,一本是浪潮之巅,一本是文明之光,但受欢迎程度和销量最好的,却是数学之美和智能时代。这四本书,数学之美最随意,原本就是谷歌黑板报的连载,最后重新整理成书,反而最受欢迎。吴军老师说,每次都试图用心做到最好,但最终「无意击发」,你并不知道哪本书最受欢迎,市场和时间才是最好的验证者。

拍电影也是一样,很少人像韩寒这样,第一次拍电影就几个亿票房,拍了三部,居然一部比一比票房好,也算是奇迹。大导演姜文当年拍太阳照常升起,没人看懂,叫好不叫座。转手拍了让子弹飞,说是翻身了吧,站着把钱挣了,但是信心满满的邪不压正(2018),票房还不如让子弹飞(2010 票房冠军),八年过去了,让子弹飞了八年,但你依然不知道它是否命中了目标。

姜文这样的导演,拍电影像酿酒,每一部都想做到最好,都是自己的孩子,但在每一部电影上映之前,你永远不知道这个电影的票房和口碑会是个什么走势。但是,你必须要瞄准、击发,然后等待下一次瞄准的机会。

无论是发布极客时间的专栏和课程,还是研发极客时间的功能特征,都是这种心情,我们总想把功能、内容做到最好再给大家,但有时候必须要瞄准、击发,是骡子是马,得拉出来遛遛。

看专栏的订阅量也很有意思,有些我们非常看好的课程,并没有很大体量。有些专栏呢,当时没觉得能火,一点点长销和口碑效应起来,反而有三四万的订阅量。

以前专栏上新,大家都会做个预测,哪个能火,订阅多少,后来越来越没把握,受众不同,领域不同,时机不同,运营不同,完全难以捉摸。怎么办?有意瞄准,无意击发,努力把手头的事情做到平衡,做到最好,然后等待命运的裁决,让用户去为产品打分吧。

作家阿尔贝·加缪说的:对未来最大的慷慨,是把一切献给现在。我要说,把好的内容传递给终端用户,就是极客时间的职责,至于哪个会火,哪个最有价值,这个需要用户说了才算。

05

优秀程序员的九种素质

MacTalk-“L1010186”的副本 3:5:2019

打开这个博客,发现今年还没有一篇文章,那就写一篇吧。

上周看到一篇文章,大意是阿里云源代码泄露,涉及多少家企业云云,看起来耸人听闻,点进去发现是有企业在使用阿里云做代码托管的时候,private internal 和 public 傻傻分不清,创建仓库用了 internal,结果只要是登录用户都可以看到并 clone 这些代码。事实上,这三个设置不仅是惯例,internel 的注释也写的清清楚楚,但是挡不住程序员不看。你永远不知道一个人的水准会低到什么地步,也许这些人从来没用过 GitHub 和 GitLab 呢?

阿里云其实可以采用安全最小化原则,也就是常说的多一事不如少一事。最小化可用原则,对于操作系统来说,就是装最小化的包,没用的服务不启动,操作命令最小化,权限最小化等等。对于阿里云上的托管用户来说,internal 应该是个可有可无的功能,去掉是不是更好呢,也许值得平台方思考。

永远不要高估用户的聪明程度。

本周我们上线了一款基础课专栏《软件工程之美》,最新的文章中阐述了软件过程和软件危机:

软件是怎么被创造出来的?

首先,它们的诞生都是有人想要造一个东西。这其中的很多故事你都耳熟能详:张小龙创造微信、乔布斯创造 iOS、暴雪想做一款不一样的射击游戏……他们首先有着这样的意图,然后,他们立项做这样的产品。

每一款软件项目背后,都有很多人在参与。你无法想象微信这样复杂的 App 靠张小龙自己可以开发出来;你也不会相信 iOS 是乔布斯一个人设计出来的;像守望先锋这种游戏的背后,有成百上千的游戏策划、美术设计、程序开发人员。

从立项到第一个版本的发布,每个成功的软件都需要有计划、有步骤地进行,什么时候发布第一个版本、第一个版本有什么样的功能、什么时候发布第二个版本、第二个版本有哪些地方要改进,这些都是研发过程中需要考虑的问题。

比如,守望先锋是在 2013 年立项,他们计划做一个基于职业的 MMO 游戏,他们先花了几个月的时间做了第一个 Demo 演示,只有四个英雄和一个张地图。

然后,他们要在 2014 年的“暴雪嘉年华”发布这个游戏的试玩版,包含 12 个英雄和 4 张地图。

最终这个游戏在 2016 年 5 月正式发布了。这样从立项一步步到最终发布,历时三年,中间经过了诸多环节。

类似的例子还有微信,2010 年 11 月 20 日立项,2011 年 1 月 21 日第一版上线,当时的功能还非常简陋,只能发送文本消息和照片。之后才是一个个版本的迭代,直到你现在看到的微信。

像这种有人参与、有计划、有步骤地造一件产品,我们通常称为「工程」。

那什么是软件危机呢?有兴趣可以订阅专栏阅读。软件工程是你通向程序之巅的必经之路。

http://gk.link/a/102ij

周末读村上的书,他说自己能够持续写作和跑步,就是因为具备两个特质,一个是集中力,一个是耐力。村上写长篇的时候每天早晨集中写作四小时,他一个人坐在书桌前,没有任何打扰,将意识集中倾斜在书稿中,其他什么都不考虑。另外,没有耐力也不行。你集中写了一星期然后伸伸懒腰说,我累了,然后就休息一个月,这样是写不成长篇的。你必须每天集中写作,坚持半年,一年,甚至更长才行。

一个优秀的程序员需要什么特质呢?由此我想到之前读过的一篇文章,是 Redis 之父萨尔瓦托·桑菲利普(Salvatore Sanfilippo)写的 9 种高能程序员的特质,重新意译一下,推荐给读者:

1、高效完成子任务

从处理编程子任务上,可以看出一个程序员的短板和长处,比如实现一个函数或者一个算法。事实上,擅于使用基本的编程技能来高效完成任务的程序员,并没有人们想象的那么多。有时候,团队里有些不称职的程序员,他们甚至不知道该怎么写一个简单的排序算法。

2、合理使用自己的经验

桑菲利普认为,经验就是一系列解决方案,它们已经被证实可以用于处理一些重复性的任务。经验老道的程序员知道该如何处理各种子任务,这样不但省掉了很多设计工作,而且避免了很多设计错误,而设计错误是简洁性最大的敌人。

3、准确预测工期

花在编码上的时间不仅要看数量,也要看质量。造成注意力不集中的因素既有内部的,也有外部的。集中注意力和避免被打扰,对于提高编程效率来说是至关重要的。

4、设计权衡:用 5% 换取 90%

项目的「非根本性」目标在很大程度上导致了设计的复杂性,或者导致无法达成其他更重要的目标,因为根本性功能和非根本性功能在设计上存在竞争关系。如果意识不到这点,复杂性就会随之而来。对于设计者来说,如果项目要最大化产出,就要把精力集中在重要的事情上,并在合理的时间内完成。

5、简洁性

简洁性是成败之间最为明显的分界点,理解复杂性的产生过程有助于理解什么是简洁性。不愿意做出设计权衡和设计错误的累积是导致复杂性的两个主要因素。我在第一点里讲的 Internal 其实是提高了复杂度导致用户选择错误。

6、拒绝完美主义(为了偏袒设计而放弃生产力)

完美主义可以分为两种:一种是追求程序极致性能的工程文化,另一种是个人特质。不管是哪一种完美主义,它们都会对程序员实现快速交付造成阻碍。完美主义和对外部评判的恐惧会导致设计上的偏袒,程序员根据主观的心理因素和无关紧要的衡量参数做出设计决策,却忽略了健壮性、简洁性和及时交付。

我曾经服务过的一家公司就犯了这种错误。当然,错误不止于此。

7、理解知识理论的价值

在处理复杂任务时,具备一些理论方面的知识会对设计产生重要影响,比如数据结构方面的知识、了解计算能力的局限性和一些重要的算法。虽然程序员没有必要成为无所不知的超级专家,但是至少要知道一些问题的潜在解决方案,避免设计出复杂、缓慢、低内存效能的解决方案。

8、理解机器原理

程序的很多问题都是源于对计算机工作原理的误解,即使是使用高级语言开发的程序也不外乎如此。这种情况可能导致一个项目需要重新设计和实现,因为项目所使用的工具和算法出现了根本性的错误。

7 和 8 说的道理差不多,这也是极客时间会连续推出数学、算法、数据结构、网络协议、软件工程等课程的原因,后面还有架构设计、操作系统、编译原理等等。

9、调试技能

查找和解决 bug 经常会占用程序员大量的时间。查找引起 bug 的问题根源,在合理的步骤内修复 bug,以简单的方式编写包含较少 bug 的代码,对于程序员来说,做到这几点就可以显著提升效率。

能否运用调试技能快速解决问题是衡量一个程序员水平的重要标准。

你具备这些特质嘛?我觉得村上说的没错,程序员同时还需要集中力和耐力。

12

AgentNEO 架构简介 – Docker,Rancher 和 Kubernetes

推荐一篇文章和服务,基于 Docker、Rancher 和 Kubernetes 构建的技术架构。

前言

我和朋友常常谈起,对于做技术的我们,这是个支离破碎的世界,大到被无形的墙分割的互联网,小到林林总总残缺的工具,他们总是很难以完整的面貌真实的世界。某一天,我们也和其他同样背负着「程序员」之名的人一样,决定以「精卫填海」的精神去「修复」眼中的世界,而这一切,开始于一架优雅和精致的梯子……

简介

AgentNEO 生产环境是完全 Docker 化的,所有的服务都运行在 Docker 中。这些服务包括我们的 Web 主站,Shadowsocks 节点,还有其他很多基础服务,比如 HA Kafka、MySQL、Redis、各个服务的 Healthcheck、CI/CD 所需要的 Drone、Gitlab runner 等等。

到目前为止,AgentNEO Shadowsocks 节点,包括 VPS 和独立服务器,一共有 30 多个,分布在香港、日本、韩国、美国等地,同时和这些节点所对应的 Docker 容器数量接近 300 个。那么我们是如何做到将不同的服务启动到合适的宿主机上,并且保证通信安全和通信质量的呢?答案是 Rancher!

全新 Rancher 2.0 刚刚发布,2.0 版本的 Rancher 全面拥抱了 Kubernetes,用户可以非常方便地创建高可用的 Kubernetes 集群。

Rancher

Rancher 是一个 Docker 集群管理工具,提供了非常友好的 WebUI 去帮助用户管理容器。它通过虚拟网络加服务编排技术,实现在合适的服务中运行我们想要的容器。

集群容器编排

在 Rancher 中,有一个概念「服务」,它指的是拥有相同参数的一组容器。因此我们的 Shadowsocks 应用就可以抽象成为一个 Rancher 的「服务」。

每个服务都有自己的很多属性,其中最关键的,则是「调度规则」。

enter image description here

上图是我们一组 Shadowsocks 服务的调度规则。它的意思是,在每一台同时拥有 zone=hk-azure 和 role=ss 标签的主机上,都启动一个 Shadowsocks 进程。这样一来,我们将需要运行 Shadowsocks 服务的节点(此处为香港 Azure 数据中心的一台 VPS)打上对应的标签即可,剩下的事情 Rancher 会自动帮我们完成。更棒的是,如果以后我们需要添加一台 Shadowsocks 服务器,只用将对应标签打到新加入的节点里即可自动完成所有部署。

enter image description here

服务器标签管理,非常简单

除此之外,Rancher 还提供了很酷的容器链接图,用户可以很直观的看到目前相关容器的相互依赖。

enter image description here

AgentNEO 官网链接图,可以很清楚的看到前端负载均衡器将请求分发到两个 Rails 应用中

自研的意义

熟悉的朋友可能会知道,AgentNEO 官网没有使用 ss-panel 这个开源项目,而是基于 Ruby on Rails 自己开发的。其实除了官网,我们的 Shadowsocks 也是自己实现的。

为什么要造轮子?

首先,如果只是用开源软件简单的搭一个平台,就如同玩已经组装好的乐高,是一件特别没有意思的事,而且对于开源的重度依赖,也会在业务逻辑上遇到比较大的障碍。然后,作为一群还算有梦想程序员,还是想做一些有用的事情,来推动整个 Shadowsocks 社区的建设,而不是仅仅汲取开源社区的成果。

所以,我们在一开始做 AgentNEO 的时候,就投入了很大的研发精力,遵循 Shadowsocks 协议实现自己的 Shadowsocks,包括 AgentNEO 官网的开发,无不亲力而为。这一切都是为了更好的进行技术沉淀,将来回馈开源社区。

DevOps

关于 DevOps,维基百科的介绍如下:

DevOps(Development 和 Operations 的组合词)是一种重视「软件开发人员(Dev)」和「IT运维技术人员(Ops)」之间沟通合作的文化、运动或惯例。透过自动化“软件交付”和“架构变更”的流程,来使得构建、测试、发布软件能够更加地快捷、频繁和可靠。

在 AgentNEO,我们始终坚持的是,尽量将所有步骤都放入自动化流程中,避免人为操作。部署时只用做决策,而不用执行(是否上线是决策,而部署步骤是执行)。大大减少「人」带来的风险。得益于近几年以 Docker 为首容器技术的兴起,整个生态圈极为活跃,我们的自动化环节都有非常丰富的资源和技术支持。

在代码管理方面,我们使用 Gitlab 作为管理平台。拿官网举例,当有新的版本标签(例如 v1.4.5)被 push 到远端后,会触发自动测试以及自动构建(构建 Docker 镜像)的任务,成功后,会进入到等待上线的阶段,这个时候,运维只需要手动点击 Gitlab 中的部署按钮即可完成上线(只决策,不执行)。如果测试或者构建失败,则会自动发送邮件通知相关人员进行处理。

enter image description here

AgentNEO 官网 CI/CD Pipeline,点击 Deploy 流程中的播放按钮即可完成部署(使用 Gitlab runner 调用了 Rancher 的 API 实现)

片尾曲

做 AgentNEO 的动机,最开始是让自己有一个稳定、快速的网络。但是作为一个有梦想的程序员来说,既然做了,那么就要尽可能的在各个环节将自己平时的积累用起来,形成自己的一套最佳实践。这才是有意思的事情。


推荐他们的服务,新一代的「网络加速服务」AgentNEO:AgentNEO 网络服务

21

如何「收集」知识

MacTalk-L1000537 7:21:2018

这些年杂七杂八写了很多东西,总会有读者问,你是从哪获取到这些知识和信息的?写了六年还不够你得瑟的,怎么没完没了了?早期写东西是因为之前的十几年积累了很多素材和想法,输出到一定程度,就需要重新去收集知识和素材、学习、进化,然后再次输出。这个阶段并不是串行的,而是并行的。大家会看到,很多习惯写作和分享的人,一般都是持续输出,生命力长的作家,作品也是一本接着一本,不敢长时间的中断。停下来容易,但是重新上路,就需要更大的驱动力才行。这也是很多人无法坚持的原因。

很多人会说,知识并不重要,重要的是对知识的理解和运用,但前提是你得有这个知识库才行,如何管理自己的知识库呢?估计每个人都有自己的办法。我也有,办法虽然很土,对我来说还有些效果,分享给大家。

收集知识对我来说大概有两个阶段,开始的时候目的性极强,比如想学习 Linux,买的书和上网找的资料都是 Linux 相关的,然后进行整理和消化吸收。后来功利性没这么强了,无论是技术、文学、传记、影像,看着好就会把一些片段或入口保存自己的知识库里。当然,任何时候都有需要针对性的知识的时候,比如写推荐算法的文章,还是得去找到特定领域的资料以确保自己写的内容是相对严谨的。

读书

构建知识库就像建一座摩天大楼,开始的时候要把根基打好,结实、端正、坚韧,有人过来踹一脚,能做到不动如山。知识是金字塔,地盘越坚实,越容易构建上层建筑。如何打好基础呢,当然是读书喽,这个阶段如果东一榔头西一棒槌去追击一些知识碎片,效果反而很糟。

人们常说,买书如山倒,读书如抽丝,大意就是买的容易读来难,最终买了个收藏知识的幻觉。我对此倒是不以为然,买书肯定是好事不是坏事,但你别想着买了的书能全部读完,凡事都有转化率,买了,就有可能读,不买,那可能真的永远不会读。况且有些书是用来收藏的,有些是用来当参考手册的,有很少一部分是买了需要立刻读完的。

如何阅读一本书呢?这是个可以写本书的话题,简单来说,要对阅读进行层次划分,同一本书,因为性质和场景不同,我们可以简读,速读,精读,甚至可以用学者的方式阅读。什么是学者的方式?就是知识拆解和重新组合,安姐在她的极客时间专栏里谈到了编程语言的学习,别人去学怎么使用,她想的是语言是怎么实现的,类型系统是什么,计算能力的边界在哪。学者方式的阅读也是类似。知其然,而知其所以然。

有的人遇到看不懂的图书和文章就会觉得作者写的烂,遇到浅显解惑的内容又会认为作者肤浅,却从来不考虑自己的需求场景、阅读方式和理解问题。有的人希望快速阅读一本书,有的人希望找到好书,有的人则希望能够通读并拆解一本书。读书时要找到自己的定位。

好记性不如烂笔头

光读书当然是不够的,想学以致用,还需要用自己的方式建立人和知识的连接。我的方式就是写下来。无论是读纸书还是电子书,我都喜欢在读的过程中里写写画画。读完之后,如有必要,就会把纸书里写的文字和划线部分,电子书里的摘要和评论,全部记录下来,甚至写成一篇文章。书里有些内容特别好的,我会把原文在电脑上重新敲一边,以便随时阅读。

柯南在刻画福尔摩斯这个人物的时候,创造了记忆宫殿这个类比,其实普通人也是类似的记忆模式,写下来的过程就相当于你把某些知识放到了记忆宫殿的阁楼,阁楼多了,也就形成了宫殿和记忆图谱,用的时候自然可以按图索翼,追根溯源,最终把这些知识连接起来。

构建知识库,就像酿酒,无论原材料多好,挂着霜的原产地葡萄也好,深山老林的矿泉水也罢,最终出来的得是酒,而不是汽水。知识的发酵也是如此。

至于这些知识放哪,如何分门别类的管理,每个人处理方式都不一样。我一般用 Ulysses 写比较正式的、可能发布的东西,用 Evernote 记录碎片化的、非正式的信息。这方面很多人比我做的更好更系统,后面再说。

稍后读,而不是稍后再也不读

除了系统性的读书,我们还会从现在的付费专栏、微信公众号的文章,以前的 RSS 和博客上汲取知识,这些相对碎一点的内容,基本上都会提供收藏或者稍后读功能。大部分人看着好点击了收藏或者稍后读之后,这些知识就消失了,因为大部分人稍后也不读……直到有一天你突然发现自己有了一个一眼看不到尽头的阅读列表和堆积成山的 PDF,然后开始梦想到一个人迹罕至的森林小木屋里苦读一年以期迎头赶上 —— 对了,要是每天清晨沿着林中小溪散步时会有人带来食物并带走垃圾就更好了。围笑。

我自己把稍后读的内容分成两类,一种是当做参考消息的,收藏起来,将来能搜索到就行。另一种则是真正希望稍后读的。对于第二种,我会每天拿出固定的半小时把这些文章找出来过一遍,有价值的内容写上价值所在,做个标记放入我的知识库,读完了了的,干脆删除了事,防止信息干扰。

稍后读的工具挺多的,比如 Instapaper、Pocket、Evernote、Send to Kindle 等等,选择适合自己的就好。

因为资质平平,我在构建知识库的过程,差不多遵循的原则是日拱一卒、不期速成。现在看来,虽然学的慢,但也不是学不会,于是有了这些年的输出。

19

《程序员练级攻略》推荐必读书籍清单(上)

左耳朵耗子在极客时间开了一个专栏,写了快一年了,文章中涉及了很多计算机经典图书。我们的运营妹子整理了一部分出来,是为(上),我看了一下,大部分自己也读过,确实是好书。一并推荐给大家。

必读书籍清单链接地址:https://time.geekbang.org/column/article/10793

关于读书,我为微信读书写了个寄语,写完发现,字写得不如原来好看了,很显然是写得少的原因。以前上学时很强调练字,字写得难看了会不好意思。现在都无纸化办公了,面试很多九零后的时候,发现简历上的字写得像小学生。

这时候,一般字挺拔的,我就录取了。

微信读书寄语