阅读视图

发现新文章,点击刷新页面。
🔲 ☆

2025年年度总结

这个博客已经不知不觉变成了年更博客。不过,这是好事。

转眼间也已经是在日本生活的二年目了,和去年的剧烈变化不同,今年似乎已经开始逐渐享受这份平和带来的滋养感了。换句话说,在国内这些年积累的压力,无论是来自于房间里的大象 (zhōng gòng) 的、还是来自于工作本身的,已经释放得差不多了。

得益于更多放空大脑的时间,我一直在思考一个问题。

在 AI 已经完全成为生活的一部分的时代,如何回答人的存在性问题。

我没有傲慢到去告诉世人我解决了这个问题。但是我认为今年我凭着本能去做了大量我认为能够帮助我和这个问题共存的事情。

其中之一就是花更多时间和家人呆在一起。

今年我比较意外地发现自己是阿斯伯格,虽然我一直想要尝试否定这点,但是人无法欺骗自己。好处是这终于回答了困扰我许久的诸多问题,比如为何我既不需要也难以建立长期的“朋友”关系;似乎每次在离开一个环境以后,我都会毫无心理负担地人间蒸发,然后心安理得地享受新的人生体验。这反过来也解释了我在唯一的亲密关系中所表现出来的强烈依赖性。

既然如此,与其对抗来自于基因特殊,不如接受这一切。

当金钱不再成为最迫在眉睫的问题的时候,放下手头的工作和学习,和家人花更多的时间相处,去聊对于世界的看法,去聊对于生命的观察;走出家门,去各个冷门小众的街道,走一走,探索不同的小店和演出;亦或者什么都不做,仅仅是呆在家里各自做一些最无关紧要的琐事。

这才是这个时代无法被替代的东西。和家人还有猫咪呆在一起,真的很温暖。

其二就是对兴趣爱好的投入。

正如很多人所说,这个时代你最好拥有一些和原子有关(可触摸的物质)的技能树,而不能仅仅拥有和电子有关(信息)的技能树,后者的利维坦已经降临在人间了。

今年继续投入了相当的精力和金钱在收藏品上。

上半年主要在补全纸币的品类,但是很快就遇到了无法逾越的瓶颈,难以寸进。因此下半年开始了机制币和方孔钱的收集。得益于更多自由的时间,系统性地学习了中国和日本的制币史,也在力所能及的范围内,收集了一些比较有意思的品种;毕竟古钱只有亲自上手,才能真正理解工艺本身。这是一片异常广袤的世界,历代古钱谱众若繁星,仅是阅读《中国钱币大辞典》进行粗略的纲目入门,已耗去半载时光。往细处深究的精妙乐趣,更是言之不尽。

兴趣是滋养精神健康度最好的养料,有个说法是,一个人的兴趣就像是一座属于他自己的道场,是这个末法时代最后存在灵气的洞天。失去了兴趣爱好的人,就如同功力尽散的修士,身陨道销,已是定数。

其三就是对自身灵肉的优化

其实来到日本以后才意识到自己的身材出了多大的问题。这不仅仅是一个外表形象的问题;之前 30 年在口舌上的贪欲让我的身体已经出现了一些微妙的警告。如果说这个世界是一个硬核模式的角色扮演游戏的话,时刻关注自己的血条永远是第一要务。

世界已经展示了一个存在 AGI 拐点的未来,和毫无意义的努力和学习相比,活到那个时刻才是最有价值的投入——公园里可没有肥胖的老人,他们早就死了。

当专注力没有过度被琐事消耗的时候,同时增肌刷脂是非常简单的。一个季度刷掉 25 斤的体重,基本已经接近健康减重的速度极限;而带来的精神力和身体掌控力的提升,更是妙不可言;三大项的数值,也相对之前又有少许进步。成人的世界其实很少有确定性的非常高的东西,甚至于绝大多数人滚出第一桶金的唯一方法就是对外出售自己的确定性。而减脂,是百分之一百确定性的回报。

除了肉体的优化,今年还花了不少时间去做冥想相关的训练。当然这个就不细说了,提升松果体的 DMT 分泌量是一个非常吃天赋的东西,没什么值得分享的东西。非要说的话就是所谓的缘分了。


所以说到底,今年基本就做了一个事情,在 AI 无法染指的领域,提升自己的生命质量。
这也毫无疑问也会是我 2026 年的主要目标。

最后祝大家,丙午年身体健康。

🔲 ⭐

2024年年度总结

博客竟然整整一年没有更新了,而上一篇博文,还是 2023 年年度总结

这一年也许是这一生中最转折的一年,亦或是更加狂野的旅途开始的一年。我带着家人和两只猫,移居到了日本,继续自己在东京的职业生涯。

说实话,这次回来,少了几分陌生感,更多的其实是一种熟悉的感觉,毕竟曾经在东京生活过不短时间。在 COVID 大流行之后,这里的一切似乎也没有太多变化。过去爱去的小店,依然静静开在街角;过去爱逛的街道,仿佛尘封了六七年。

年初坐在办公室楼下大厅的咖啡馆,和现在老板第一次面对面聊天的时候,我其实还一度问自己:“在完全英语的环境下办公,真的可以吗?”。好在事实上上手以后,这事儿出乎意料的顺利。

在国内满打满算干了也快六年的 DevOps 和 Infrastructure,今年机缘巧合,以 SDE 的角色主导了一个挺有意思的项目重构。以前在一堆大部头书籍里学了不少分布式、数据结构优化、性能提升的纸面技巧,今年也算是都用上了。当然,更重要的是遇到了非常不错的同事,以我浅薄的职业经验来说,职场舒适度里“和谁一起工作”是占比最高的因素。希望来年可以继续做一些数据库和 Infra 相关的项目吧。

相比于职场,其实今年的健康管理做得非常不好。也许是去年的暴力面试消耗了太多的生命力,今年充满了摆烂的气息,整整一年都没有好好坚持运动。年初冲的高尔夫练习场会员卡,到今天为止也就去了 5 次。夏天体重虽然一度减下去 5 公斤,但是秋膘又贴回去了。

好在家属时不时会拉我去隅田川边跑个 5 公里,周末天气好会在市区进行大暴走。尽管身体指标并没有显著改善,但是也没有变糟糕。而立之年将至,真的得狠狠有氧了。

不过,得益于海外工作的 Work Life Balance,今年真的拥有了太多时间来做自己感兴趣的事情。年初开始入了明信片的坑,注册了 Postcrossing,至今为止也收发了上百张明信片;重新捡起了纸币收藏,尽管今年没有入手很多漂亮的钞券,不过花时间补了下近 15 年全球主流国家银行券的发行日志,争取明年把日本的非高价券都集齐了;开始了中古掌机的收藏,基本把任天堂从 1989 年到现在所有型号的掌机都收集齐全了,而且是箱说全对码,这算是最有成就感的一项了。

另外也是蹭了一下家属的手账坑。我自己其实一直有记录每日事项的习惯,不过之前用的都是烂本子,写完一年就丢掉。这次终于有一个很不错的手账用了。

我个人觉得对兴趣的投资还是挺重要的,毕竟这是保持心理健康最实惠的办法。而心理健康在人生路上的重要性,不亚于肉体的健康。总结的话就是,今年心理健康很用功,肉体健康很马虎。

那么最后,祝大家 2025 年身体健康!

🔲 ☆

2023年年度总结

是的这有点奇怪。为什么已经离 2023 年过去快两周了我才开始写年终总结。

其实原因并不复杂,有一句话叫做 “事以密成,语以泄败”。今年的年末年始确实是我一个非常重要的人生节点,因此我无法在那个时刻对任何不必要的人讲任何关于自己的事情,包括年度总结。

还好最近在妻子、家人和好友的支持下,一切逐渐稳定下来了。因此也算是一个合适的时间回顾一下自己的 2023 了。

去年做了什么

简而言之,去年除了做好本职的工作之外,我和妻子完成了带着宠物移居东京的计划。

我无意于过多展开关于为什么做这个决定的具体原因。如果非要说的话,2022 年的 Lockdown 让我对某些地方最后的怜悯和期待也完全消失了。

另外,就像香港投资家曹仁超先生在那个广为流传的视频里所言,个人天赋和能力其实在大势面前,和路边野狗拉的粪便没有本质的区别。而我觉得自己多少还是一个胆小如鼠的投机分子,因此还是和易于预测的环境为伍比较安心。

移居海外一直是一个热门的话题,我并不想在这样相对容易引起争议的话题上说太多暴论。每个人有每个人最适合的路径,与其向他人取经,不如重新内观一下自己。

我的移居之路本质上和在国内跳槽没有太大的区别,面试、继续面试、坚持面试,拿到 Offer 然后下签高度专门职,飞到东京入职。除了行李多了点、需要提前 225 天办理宠物的检疫手续之外,说到底,主要还是时间成本。

除了面试的准备之外,去年主要干了两件有趣的事:

  • 第一次向 Kubernetes 官方文档提了 PR。当然,对于任何开源项目,给文档提 PR 就是给刚接触的小朋友上手的,但是说实话能够有机会感受到那么好的社区氛围,每天睡觉前看一眼 dev 的邮件列表,确实也够了。如果真的想给 CNCF 的项目提交一些真正有价值的 feature PR 的话,说实话并不是一件容易的事情。可能在短期内成为一个出色的 Kubernetes 的使用者会是一个更加现实的目标。
  • 作为主要贡献者开发了一个多系统初始化项目。受限于签署的 NDA 条款,没有办法聊项目的具体内容,但是这种利用过去工作中用过的诸多工具和它们的最佳实践经验,和许多有着数十年开发经验的大佬一起头脑风暴,最后迭代出一份会被大规模使用,服务于万千游戏玩家的内部工具链,确实是一件让人难以抑制兴奋的事情。如果不是移居大业当前,我大概会在前东家长久服务。可惜人生就是这样充满不可逃避的变化。

去年吃喝玩乐了什么

去年因为非常忙碌,其实并没有太多时间专注于玩乐。除了过年的时候去北方感受了一下久违的年味之外,只出了一次远门。

秋天和妻子一起去了趟泰国,感受了一下久违的南国海滩。尽管普吉岛的沙滩和水质在整个亚洲都算不上优秀,但是和爱人一起在海边散步和休憩的浪漫,与学生时代跟着父母去浮潜胜地游玩的体验,是截然不同的。从这个角度来说,海滨的质量已经不是最重要的因素了。

也许是热带海岛去多了疏忽了,在充满热带植被覆盖的酒店居住期间,我们被携带登革热的蚊虫叮咬了,我爱人离奇地成为了今年静安区第四例登革热患者,在结束了泰国之行后的两周,我们不得不在上海的疾控中心度过。而我们在离开曼谷的前一天,刚好去过第二天发生了枪击案的暹罗广场。这段经历揉在一起看,极度的不真实。可能这也预示着人有时候还是得今朝有酒今朝醉吧。

之后又去了几趟南京和老家,主要还是以吃本地平价菜为主,顺便辱骂几句沪国离谱的物价。

有在运动吗?

还是有一点的,但是不多。

今年因为招行信用卡送了 12 次高尔夫练习场的场次,就硬着头皮买了套入门球杆去练习场丢人现眼了。但是意外地,高尔夫这东西相当的好玩。首先这东西并不是看上去那么慢条斯理,抽打开球木和长铁杆的时候,是非常暴力的。每小时能耗能破 1000 大卡的东西只能说和优雅是半毛钱关系都没有。

但是高球本身又极度追求精度和可控,这导致参与者需要用最大的爆发力打出最精确的飞行曲线。结果就导致高尔夫的练习是永无止境的,而即便到了专业级,依然会屈服于随机性的魅力之下。

因此在 12 次练习场用完之后,又去了不少次室内的练习场,虽然成年人搞运动进度肯定不如童子功,但是起码三杆洞也能稳定上果岭了。至于推杆的练习,未来有机会再说吧,不是现在要解决的问题。

至于跑步的话,倒是断断续续进行了几次,但是终归是没有维持住频率。尤其是八月份健身卡到期后,更是荒废了。希望今年可以重新振作,再次跑起来(心虚)。

2024 有展望吗?

有的吧,就是五个 “好好干”

  • 好好工作,做一个更好的工程师。
  • 好好吃饭,但是别吃的太胖了。
  • 好好打球,五杆洞稳定上果岭。
  • 好好学习,日语多讲讲。
  • 好好拉屎,不要得痔疮。

最后。祝大家,身体健康。

🔲 ☆

写好项目技术文档 - CH02. 文档标准设计

大家好,时隔两个月,我又来了。

时隔这么久一方面是最近事情比较多,已经到了并行处理的极限;一方面也是因为,文档标准总归是一个比较枯燥的话题,所以拖到了现在。

那么话不多说,我们书接上文 写好项目技术文档 - CH01. Repository 设计,接着聊聊怎么设计文档的标准和规范。

为什么要有标准?

在日常中,其实很少有人喜欢写文档;而愿意写文档的朋友,经常也会忽视如何设计文档的标准这一话题。毕竟能够愿意去持续地为公司内部项目贡献文档,已经弥足珍贵,有得是玩命糊屎山不写文档的人(当然,代码如文档是最好的状态;但是 99% 的从业者无法达到 Linux Kernel Docs 所描述的理想的状态)。

不过我倒是觉得,文档这东西是有传染性的。当你能够以一个比较高的标准去持续输出文档的时候,身边的其他人多多少少也会被你感染,潜移默化地体会到一个有规范的文档所带来的好处。

这里一个比较常见的案例就是,一个工作上的伙伴来问你一个曾经遇到过的 TroubleShooting,而你直接把相关的文档链接/复盘案例直接在 Thread 里甩给了他。原本需要冗长的 DM 或者 Thread 讨论的问题,直接被终结了。可以说,这是与人合作的过程中最爽的事情之一。

另一个场景是,组里来了一个萌新,他正在进行 Onboarding。这个时候他来向你询问一个内部工具的用法,而你粗暴地甩给了他一份事无巨细、Step-by-step、我奶奶来了都能跟着操作的文档的时候,你的潜意识会清晰的告诉你,这些文档为自己和萌新节省了无可计量的时间,这亦是另一种爽快。

如果说文档的有无带来的爽感是第一层级的话,那么文档的标准和规范,就是到达第二层级的爽感的必经之路。

当一个文档逐渐壮大,或者整个团队的文档意识开始提升之后,一定会遇到一个问题:文档的协作

不像代码,无论项目使用什么语言、版本管理工具、开发框架,总归有一系列非常成熟的开发规范和工具链可以使用。这意味着:

  • 作为下限,项目的 OWNER 可以通过一个很低的代价,确保项目代码的基本一致性。
  • 作为上限,通过 Reviewer 的严苛程度以及单元测试的高覆盖,可以让所有贡献者保持高度一致的提交风格。

而文档的协作,却更加复杂:

  • 贡献者的行文风格都大相径庭。
  • 不同语言的遣词造句规范,有很大的差异。
  • 对于长期项目,甚至会被语言本身的变迁所困扰。
  • 同义词和近义词混杂问题。

因此,文档的标准和规范的目的,就是希望在可控的范围内,尽可能地减少这些问题的出现。让多人协作的大型文档,变得更加工业化,从而实现一套囊括了文档新增和更新(以及本地化)的流水线工程,并且和上一篇 写好项目技术文档 - CH01. Repository 设计 中的文档 Repository 设计相结合,充分利用版本控制工具的优势,结合现代的 CI/CD 流水线,实现一个可跟踪、可维护、行文统一、用词标准无歧义的文档贡献系统

文档标准,分哪些部分呢?

这个分类,我更多其实是参考了 Kubernetes 官方文档以及 Jenkins 官方文档的一些内容以后,自己琢磨的。

简单来说我觉得可以分为这么四块:

  • Reference & Concepts —— 名词与概念参考表。
  • Style Conventions —— 行文/i18N 风格指南。
  • Sync Check —— 适用于多语言的 commit 同步检查。
  • Ownership —— 文档/文档分支的所有权管理。

传统意义上的文档规范,其实主要指的就是 ReferencesStyle Conventions。前者是对整个文档中出现的专业术语和概念的标准解释,从而其他贡献者撰写的时候可以用类似于 {{\}} 这样的形式进行快捷引用。

后者是对整个文档的行文风格,遣词造句的规范。举个例子,在 Kubernetes 官方中文文档中,明确描述了,不允许在翻译中使用 “您” 作为读者的指代。这就是一个很明确的行文风格的规范。

当我们说标准化的时候,到底说的是什么

相信多数的读者在阅读各种开源/商用工具的文档的时候,多少遇到过一个问题:

在不同的页面中,同一个概念或者术语,居然有不同的描述

这并不是一个罕见的问题。无论是 Kubernetes,Splunk,Jenkins 这类超级项目的文档,还是说遍布 GitHub 的各种小型开源项目的文档,都会遇到这样的问题。

举个很直接的例子,在 Kubernetes 中 control-plane 是一个非常基础的概念。然而即便是如此基础的概念,在所有中文翻译版本的页面中,其实有 控制面控制平面 两种翻译方法。从提交记录来看,这显然是一个因为早期批量翻译提交和行文风格规范没有完善所导致的问题。

因此这里也引申出了小节标题。当我们说标准化的时候,到底说的是什么?

我认为在这个场景里,标准化代表的就是精确、达意、全局统一术语词典表。这个表应当包含了当前这个项目/软件所有的专业术语和概念。如果有余力,甚至应该对这个术语词典表中的每一项,进行完整的描述和概念边界的限制。

Reference & Concepts,也就是这个术语词典表,我认为是文档规范中一切的基础,是大楼的根基,是巨树的树根。

有了这个形而上的认识,下一个问题就是,如何把 Reference & Concepts 动手做起来。其实很多时候大家都会觉得把一个 PPT 或者概念上很好的东西落地到实际的 Repository 里,很困难。但是很多时候我觉得我们是被自己束缚住了。

我很喜欢一位厨子(高寒)的说法:“按照我说的做,不要按照我做的做。”

事实上在项目文档里推进标准化也是一个道理。不要在一开始想着就和 Kubernetes 文档一样,设计一个非常成熟而夸张的目录树,用来承载多如繁星的各种概念和术语。这没有必要,因为你根本做不到,并且你的所有热情会在这个过程中燃烧殆尽:


很多时候,作为一个好的开始,一张 MarkDown 写的术语表或个 CSV 文件可能就完全够用了。你完全可以写一个检查工具,放在 CI/CD 管道中用来对文档的术语进行初步的检查。这样的工具只要稍微利用正则就很容易制作。

...namespace, 命名空间control-pane, 控制平面ingress, 入口...

文档和业务代码最大的不同是,文档更像是一种活的东西,一种随着贡献者的来来去去自由生长的东西。Reference & Concepts 作为保证其符合要求生长的最底层的规则,很多时候最大的意义在于其存在本身

如何让无数人,按一个风格说话

说实话,这个副标题让人绝望。

莫说让无数人按照同样的行文标准来说话;哪怕让我这个月和上个月用完全一样风格的说话,恐怕都不太容易。

所以这里就产生了一个问题,语言、或者说文章的标准化生产方法是什么。对了,就是车轱辘话。不管什么人说出来的车轱辘话,基本味道都是差不太多的。那么怎么说车轱辘话呢?

答案就是堆砌简单陈述句

- A 是 B- A 有 B- A 可以 B- A 用于 B- A 用 B 来 C

其中 B 和 C 这样的名词或者动词,至多再加一个简单的修饰词。这样的句子,不仅简单,而且容易理解,也容易记忆。好的文档是消除歧义的,而简单句就是消除歧义最好的办法。

但是规定是规定,人是人。所以我一直认为(当然很多人不这么觉得),文档的 Reviewer 团队对于文档长期的风格一致性,至关重要。人类其实是非常善于模仿的,甚至在自身是新参与者的情况下,会主动对集体的行为进行无意识的模仿。引申到文档文风上,历史已经存在的文档的风格,对后来的贡献者影响会非常巨大。因此有一个稳定的 Reviewer 团队的文档,往往能够在比较长的时间线上,保持了很好的风格一致性。这里可以参考 Splunk,RedHat,Microsoft 这些商业公司的文档。且不论文档内容纰漏的多少,但是它们确实相较于大量开源项目,有着更加工业化的统一文风。

另外有一个非常好的例子是 Linux Kernel Docs。你会发现在内核文档中,随处可见夸张的谩骂和对糟糕提交行为的批评。按照普适的技术文档的眼光来看,这样的文档是让人皱眉的;因为 Linus Torvalds 以及他早期的小伙伴们的个人印记实在太过于强烈。但是即便如此,由于 Linux Kernel 直至今日依然有着这颗星球上最成熟老练的维护团队,面对五万人级别的贡献者团队,仍然可以将文档和 Code as Document 理念贯彻到底。

聊到这里其实大家估计也品出来了,关于行文风格,真正的规范可能只有一条:尽量使用简单陈述句。剩下都是关于 的问题。

再缩小点范围,是一个关于 维护团队 成员稳定性的问题。他(她)/他(她)像破冰船的船头一样,带领整个项目的文档贡献者,一起向着一个方向前进,撰写一页又一页得到用户和社区认可的文档,那么这个文档的文风本身也会像一棵被妥善照料和修剪得到树木一样,长期维持一个不变的风格。

正所谓,不要尝试去教成年人如何说话,好的文档本身就是最好的老师。

而维护者要做的,就是照料好最初得种子和幼苗。

多语言,我们怎么跟踪母语言版本的修改?

几年前其实思考过这个问题,当时我觉得容易想不容易做。原理是利用 git diffgit log

多语言内容无论是放在不同分支,还是在同一个分支的不同目录内,都可以用这个方法进行跟踪,但是需要一些巧思设计。当时写了一个简单的 demo,用了一下勉强可以用。直到有一天,我看到了一个终结问题的答案:

Kubernetes i18n sync check

这个脚本稍作修改,可以迁移到几乎任何形式的文档中,用来跟踪多语言翻译的变更。无需多言,大家直接看代码就行。

没必要重复造轮子。

维护者,亦是苦行僧

聊到这里,本文也快到尾声了。我想说的最后一点,是关于维护者的话题。

正如上面提到的,行文风格的核心是维护者团队的稳定性。无论是文档刚刚开始产生的时候,还是后期有越来越多贡献者参与的阶段,稳定的维护团队是保证文档不发生锈化的核心要素。很多商业公司,甚至开源基金会的团队建设过程,都忽视了这点。

大家往往很重视项目业务代码仓库的核心团队的组建和发展,但是到了文档这个环节,由于没有直观的业务价值,往往被降级。要么是由开发团队的人员兼任,要么由团队的萌新来做。萌新连项目本身都看不明白,就要来写文档,这不是在扯淡么?

这也是为什么国内好几个规模很大的厂子,文档却一泡浆糊的原因。

说实话,我一直坚信技术文档是任何开源/商业项目的第一个门面,而不是他们的官网。FFmpegVIM 的官网一点都不酷炫,但是不影响他们成为伟大的软件。他们的文档写的都很清爽和开发者友好,对这些工具真正的用户来说,这实在是太重要了。

如果鄙人有幸,真有开源项目的创始者或者技术行业的大佬看到这篇文章,我真心希望大家,少去评几个没用的奖项,少去在官网弄一堆酷炫的合作友商和优秀客户采访;一份出色项目文档,能为项目带来巨大的潜在声誉,长期价值远远超过那些虚浮的东西。


最后祝大家,身体健康。

🔲 ☆

窜访游记:红山森林动物园

我是一个业余动物园爱好者。

南京红山森林动物园的大名,不管是不是动物园爱好者,多少都是有所耳闻的。互联网上红山和台湾市立动物园被并称为两岸双雄,那自然应当是有一些独到的东西在的。

但是去之前我比较担心的一个事情:期望会不会被拉太高了

人类便是这样,说要掀掉屋顶乘凉,便觉得开窗也不算过分了。旅游也是如此,当觉得自己要去一个屎一样的景点的时候,意外发现比想象中好得多,就会收获难忘的记忆。

去年窜访云南的时候,就有了这样的体验。但是这次出行之前,内心比较忐忑。

不过好在,红山到底是没有让我失望。

动物园本身其实千园千面,把红山拿来和亚洲的其他动物园对比,意义并不大。如果非要说为什么我觉得红山值得它一直以来受到的盛名的话,主要是一点:

红山愿意牺牲游客观看动物的体验,来提高丰容水平

红山本身并不大,難以从动物的种类和游乐设施的水平上和其他动物园竞争,因此红山曾经一度濒临倒闭。

直到红山利用社交媒体的影响力,加上本身对园区丰容出色的运营,获得了社会层面的支持,才慢慢走出了困境。

红山绝大多数的中小型园区,尤其是本土动物区和冈瓦纳区的丰容设计,似乎从一开始就没有考虑过游客的能不能看到动物的问题。

这一点,和国内大多数的动物园区别极大。这些园区内设置了大量人工或者自然的绿植,让整个区域的可见度非常差。

但是这对动物来说是非常好的,因为欧亚大陆的原生物种对于人类会本能恐惧。

人类作为盘踞地球史无前例的统治性生物,在上千个世纪的时间里屠戮了大半的陆生中大型生物。

动物园只有真正考虑过动物本身的需求,才会在游客的体验下刀,做出更偏向动物的取舍。这不是利于营收的决策,因此更加难能可贵。

在浏览过程中,其实如果眼尖一些,是能够发现动物喜欢藏在能够看到人类,又不容易被发现的隐蔽处。安全感的满足,让动物可以表现出更多自然行为,例如正常的进食、较少的刻板行为、亲子间互动。

回想过去的参观经历,这类行为的出现频率还是很稀有的。

另外,红山接近九成的园区指示牌和信息牌,都是工作人员手写手绘的。这种细节也说不出所以然好在哪里,但是国内并没有看到其他动物园,能做到类似的程度。

今天太晚了,就懒得写多了。传了些视频到油管,下面是最有溫情的一個,大家有兴趣的可以去看看。

金絲猴媽媽和幼崽的互動


最後祝大家身体健康,有空也可以去红山逛逛。

🔲 ⭐

关于 初码先生 某推中典型诡辩论部分的拆解

最近简中技术圈发生了一件不小的事情:知名技术分享者左耳朵耗子因心梗不幸去世。

说实话,我从未和耗子哥有任何交集,也未曾受益于任何他过去的分享和文章。但是,至少从绝大多数缅怀他的人口中,可以多少感受到他的人格魅力和技术能力。这是一个值得尊敬的人。

然而今天看到一位推主 初码@chumacn 发了一条推文,为了防止他之后修改,直接复制内容如下:

TweetID:1658453862561501184
虽然死者为大,但是这篇回忆文章,再次印证了我的观点,陈皓的范本,是对一线程序员无比巨大的毒害,一点不为过。

推主我对你没有任何恶意,从私人的角度看,这篇回忆文章里,有上下级的交流和学习的过程,有对一些重要事情的回忆和佐证,更有作为朋友的相互情谊,文字间温情流露,精彩人生。

但是,既然发在了公众平台,那我就真的有必要说几句了,站在程序员、技术人员、产品人员、大公司平台、大厂资本等公共利益角度,我认为你的上级陈皓,在一些大是大非上,他并没有帮助到你。反而给你做出了非常错误的示范,而你的回忆文章恰好很清晰的证明了这些问题。并且你到现在为止都没有意识到这些行为非常越界,非常错误。

我想帮助你复盘一下:

首先问一个最核心的问题,我反对陈皓、冯大辉等人,反对的到底是什么?

我反对的是:

他们作为技术KOL,自己本身不学无术,把大量精力和时间花在了社交媒体上,花在了花样繁多的新技术、新产品、新想法上。巨大的信息流涌入他们,让他们从窄而深的技术通道转向了宽但散的纷杂路口。不以为耻反以为荣,并在互联网上布道这种劳逸结合、工学一体的玩法。

这种路径犯法吗,是不被允许的吗?当然不是!但是这种是自由职业者、自媒体人士、财务自由者的娱乐技术玩法,这种玩法,不仅不适合初级程序员,更严重违背入职工作者的职业道德。

当然了,冯大辉老师的不学无术,这个已经反复证明了,无需多说,他不认错的话,水货CTO的耻辱帽子一辈子都摘不掉。

但陈皓的不学无术,则是一种更常见的、更隐蔽的,但是伤害更大的不学无术。这种不学无术总结起来就是:

没有工作上的边界意识,在自己所拿薪资的岗位上,没有真正窄向、深度的钻研自己权责范围内的事情,而是用自己的阅历、见识、想法,跨越到远超自己能力上限的地方,去指点迷津、夸夸其谈,这是一种非常隐晦的、隐藏的,但大面积存在的严重职业道德缺失的行为,不仅在程序员领域,也在产品、运营领域出现。

如果真正的想实现一个想法、平台,真正的技术职业工作者,无非两种情况,1是遵循自己的Leader的想法和架构,老老实实的写代码、做模块。2个就是自己担负着研发的重担,了解并深度认真的去评估自己的技术水平,评估自己能否基于想法去实现完整的闭环,并模拟这样的过程,做好完整的计划,带领团队逐级拆解任务,做好管理,去实现这个过程。

而陈皓,就是非常典型的,不愿意做1,所以在面试和找工作的事情,都奔着2的岗位去找、去靠,但是在2的岗位上,不具备2的能力,但是既不愿意直面现实,也不和团队说真话,做真正的评估拆解,绑着整个团队一起走向必然的失败。

这段过程,就是陈皓在阿里云的典型失败过程,也是为啥闹纠纷的主管因素。

要知道,你作为一个P7、P8、P9的程序员,你之所以能拿着3万-7万的基本工资,还能闲暇之余上网,动辄就是什么流行、我得学什么新东西、我要捣鼓什么东西,我要拿公司平台去实现我什么什么想法。

陈皓同学,你得知道,你之所以可以异想天开,那是因为你在阿里,吃着时代的红利,你的试错,是阿里在给你承担,而不是你在承担。这是互联网红利下,社会给的红利,大厂给的功利。建立在千千万万的淘宝商家血汗上的红利。公司付钱给你,不是让你去做自己的舞台,而是让你当小蚂蚁,帮助公司创造价值,一个程序员,如果连这点最基本的自知都没有,路不可能走的长。

所以对于陈皓这些违背职业道德,远超能力范围的异想天开,推主竟然觉得陈皓某些想法很感人。这也就是为什么我觉得有必要站出来说几句,真的是被带远了,带偏了。

另外怕推主有疑惑,我再补充一些信息。

因为推主也提到了,陈皓让他刷题,对他的成长帮助非常大,这是当然了,但是你得搞明白这个里面的因果关系。陈皓让你刷题,做对了的地方时:刚好他意识到了刷题对程序员是有好处的,做错了的地方是,刷题本来就是普世价值,普世价值应该发生在学习阶段、入职前,而不是占用工作时间(不用杠,忙的时候,想要坚持刷题,必然占用工作时间),而且按照陈皓、冯大辉这样的技术KOL的逻辑,上班时间,如果事情做完了,也可以去刷题。这已经是何等扭曲的职场观,首先我国的大厂里的996高薪岗位,如果HR体系管理得当,就不可能出现闲暇的上班时间,其次就算做完了,也应当在Leader的允许下,在同事的知情下去刷题,这是最基本的职业道德边界感。但是陈皓等传递给一线程序员价值观就是,我心随我欲,技术感悟的风飘到哪,我就可以做到哪,我认为这简直太卑劣了。

那么程序员是否有标准路径呢,当然是有一些的。

在学校的时候,深度学习好数据结构与算法、编译原理、数据库原理、操作系统原理、计算机网络等基础学科。

在工作的时候,老老实实的在自己公司、在代领人的框架内学习和钻研使用方法,把工作上的细节,包括业务代码设计、算法优化、代码review、自测等等等等各项工作做好。

在接到研发需求的时候,优先寻找并顺着成熟轮子开展工作,如果在得到上级和公司允许并做好充分预算和评估的情况下, 可以尝试自行或者激进的研发。

以上标准路径,其实在10多年前的互联网上,默默的布道者非常多,大家在CSDN、ITEye、博客园等地方,在某个具体的技术上、组件上,发表连载教程,而不是陈皓、冯大辉之流,以技术之名谈天说地,获得时代红利后,把自己的成功也试图强加到普通程序员头上。

在我看来,他们简直是技术圈最坏的榜样,最糟糕的示范,我不断地发声,就是希望技术回归技术,程序员,能得到真正的指导,而不是这样站在时代的风口里左右摇晃。





看完整条 Tweet 的第一反应是,2023 年怎么还会有机会看到这么经典的诡辩案例。不妨就此来盘一盘,这篇文章让人浑身不舒服的地方到底在哪里。

在开始之前,我们还是花一分钟简单复习一下诡辩论,也就是 Sophism 里最最经典的一些方法:

  • 滑坡论证,也就是所谓的蝴蝶效应。这条也是危害最大的一条
  • 从众式论证
  • 言论者个人行为推断
  • 模糊化推论,也就是强行建立无因果要素之间的关系。
  • 不恰当类比
  • 特殊推论的一般推广
  • 错误因果关系

下面直接一段段开始盘。在 我想帮助你复盘一下 前面的那三段,姑且作为推主本人的主观观点的发表,虽然也有诡辩嫌疑,但暂且跳过。

首先是第一段:

他们作为技术KOL,自己本身不学无术,把大量精力和时间花在了社交媒体上,花在了花样繁多的新技术、新产品、新想法上。巨大的信息流涌入他们,让他们从窄而深的技术通道转向了宽但散的纷杂路口。不以为耻反以为荣,并在互联网上布道这种劳逸结合、工学一体的玩法。

这段直接进行了滑坡论证,直接把这段的口风推到一个不可控的方向上去了。具体来说,因为陈皓和冯大辉在社交媒体上花了大量精力和时间,所以他们从窄而深的技术通道转向了宽但散的纷杂路口。这里的因果关系是完全没有证据的,但是作者却把这个因果关系当成了铁板钉钉的事实来推论。

同时还说到 不以为耻反以为荣,并在互联网上布道这种劳逸结合、工学一体的玩法。这句话首先对于推主的论点没有任何帮助,其次也是一个诡辩,因为这句话的前提是 他们不以为耻,但是这个前提是作者自己加上去的,等于说通过自己设定一个被推测对象的主观态度,来进行立靶子批判。

接下来是第二段:

这种路径犯法吗,是不被允许的吗?当然不是!但是这种是自由职业者、自媒体人士、财务自由者的娱乐技术玩法,这种玩法,不仅不适合初级程序员,更严重违背入职工作者的职业道德。

这里又用了几个诡辩技巧。首先是 这种路径犯法吗,是不被允许的吗?当然不是!,这里的诡辩在于,作者把自己的主观论点 这种玩法,不仅不适合初级程序员,更严重违背入职工作者的职业道德 作为了一个事实。在计算机这个行业,有无数的岗位需要有不同特质的程序员进行合作和贡献,海外几家著名的企业无一例外,数十年如一日强调 Diversity 在一个企业的发展过程中的重要性。在这样的背景下,自由职业者、自媒体人士、财务自由者的娱乐技术玩法,和计算机从业者的职业道德的冲突之间的联系,作者并没有给出任何的可信的证据来进行说明。

接下来是第三,四段,因为是对冯大辉和陈皓的纯粹人身批评,毫无内容,所以我就不多说了。

再看第五段:

没有工作上的边界意识,在自己所拿薪资的岗位上,没有真正窄向、深度的钻研自己权责范围内的事情,而是用自己的阅历、见识、想法,跨越到远超自己能力上限的地方,去指点迷津、夸夸其谈,这是一种非常隐晦的、隐藏的,但大面积存在的严重职业道德缺失的行为,不仅在程序员领域,也在产品、运营领域出现。

这段诡辩术用得比较隐晦,很多人可能并不容易第一眼看出来其中得问题。这里的诡辩在于,作者把 没有工作上的边界意识没有真正窄向、深度的钻研自己权责范围内的事情 作为了一个事实。然而糟糕的是,作者并没有给出任何的证据来证明这两个事实,而是直接把这两个事实作为了一个前提,然后在这个前提的基础上进行了推论。作为一个没有给当事人进行过长期上下游代码审核,没有给当事人进行过深入技术交流,乃至于没有进行过大量学术和技术方面得公开辩论的人,我们无法认为其拥有足够的 Credit 在这两个点上进行事实判断。

并且,作者还进一步将这两点和 严重职业道德缺失的行为 进行了联系,这里的联系也是没有任何的证据的。因为此处的 职业道德 的定义,本身就很大程度依赖度第二段中通过诡辩构建出来的定义,而基于诡辩得到的定义的二次诡辩引申,其可信度是非常低的。

然后是第六、七、八段:

如果真正的想实现一个想法、平台,真正的技术职业工作者,无非两种情况,1是遵循自己的Leader的想法和架构,老老实实的写代码、做模块。2个就是自己担负着研发的重担,了解并深度认真的去评估自己的技术水平,评估自己能否基于想法去实现完整的闭环,并模拟这样的过程,做好完整的计划,带领团队逐级拆解任务,做好管理,去实现这个过程。

而陈皓,就是非常典型的,不愿意做1,所以在面试和找工作的事情,都奔着2的岗位去找、去靠,但是在2的岗位上,不具备2的能力,但是既不愿意直面现实,也不和团队说真话,做真正的评估拆解,绑着整个团队一起走向必然的失败。

这段过程,就是陈皓在阿里云的典型失败过程,也是为啥闹纠纷的主管因素。

这里的诡辩术就用得比较明目张胆了。首先,作者把 真正的技术职业工作者 通过一定程度的从众式论证 + 言论者个人行为推断的方法,进行了片面化定义。其次,作者把 真正的技术职业工作者无非两种情况 进行了联系,这里的联系也是没有任何的证据的。

到底什么是真正的技术工作者,没有深刻和详实的讨论和证明,是几乎不可能用所谓的两种情况来进行概括的。我们往往只能用一些普世的、共同的人类良好品质,在不同的行业和领域的从业者身上进行对照和印证。比如,对于一个医生来说,我们可以用 对病人负责 来进行判断,对于一个教师来说,我们可以用 对学生负责 来进行判断,对于一个程序员来说,我们可以用 对用户负责 来进行判断。但是,这些判断的标准,都是基于对于 负责 这个词的共同理解的基础上的。而这个共同理解,是需要结合时代背景,通过大量的观察事实,来进行共同的认知和建立的。绝不可能通过一篇文章,或者一段文字,或者一个人的个人行为,来进行建立的。

第七段中其实用的诡辩术和第五段中用的诡辩术是一样的,甚至有点审美疲劳。

最后来看看九、十、十一段:

要知道,你作为一个P7、P8、P9的程序员,你之所以能拿着3万-7万的基本工资,还能闲暇之余上网,动辄就是什么流行、我得学什么新东西、我要捣鼓什么东西,我要拿公司平台去实现我什么什么想法。

陈皓同学,你得知道,你之所以可以异想天开,那是因为你在阿里,吃着时代的红利,你的试错,是阿里在给你承担,而不是你在承担。这是互联网红利下,社会给的红利,大厂给的功利。建立在千千万万的淘宝商家血汗上的红利。公司付钱给你,不是让你去做自己的舞台,而是让你当小蚂蚁,帮助公司创造价值,一个程序员,如果连这点最基本的自知都没有,路不可能走的长。

所以对于陈皓这些违背职业道德,远超能力范围的异想天开,推主竟然觉得陈皓某些想法很感人。这也就是为什么我觉得有必要站出来说几句,真的是被带远了,带偏了。

首先是陈皓本人拿着的高收入。从现代企业和被雇佣者的关系而言,企业开出来的薪酬是基于企业在雇佣和面试过程中的人才价值判断。被雇佣者本人对于这个定价本身并不存在道德和判断的责任。因此这里事实上再一次使用了模糊化推论,强行建立了一个 高收入对高收入的定价责任 的关系,然后进一步建立了 鼓捣新技术企业责任 的矛盾。

具体过程发生在第十段,直接通过上一段模糊推论的关系,进一步进行了滑坡推论和错误因果,将陈皓本人的合法劳务所得的数额,首先建立到了 阿里 这个企业的身上,然后又建立到了 千千万万的淘宝商家血汗上,最后又建立到了 公司付钱给你,不是让你去做自己的舞台,而是让你当小蚂蚁,帮助公司创造价值这条罪责上。这里只能说诡辩的技巧用得还不够熟练,一般来说在进行诡辩的时候我们要尽可能避免在较短的篇幅使用超过三种以上的诡辩技巧。

这里推主的本意较为明显,就是希望将陈皓和对普通劳动者的压迫进行关联,从而在道德层面构建起谴责和声讨的合理性,可惜技巧不够纯熟,反而使这段成为了整条推中最糟糕的表演。

然后就是最后一段,在通过上述若干条的诡辩,构建起陈浩本身违背职业道德这条没法站得住脚跟的推论后,再次进行了言论者个人行为推断,否定了所有对陈皓持支持和认可的人的道德和判断能力,最后又通过 被带远了,带偏了 这样的词语,对他们进行了一次全面的贬低和否定。

补充信息部分来来回回还是那些诡辩套路,就不赘述分析了。

最后想告诉大家,日常阅读的文章、推文,听到的发言、通告、业内的大量论文,以及自己日常脱口而出的大量发言,本身都是诡辩的聚合体。在发表内容中适当存在诡辩,本身也很常见,不值得大书特书,但是如同这条推文一般,通篇拥挤着大量雷同的诡辩技巧,确实也较为罕见。

以上,祝大家身体健康。

🔲 ☆

关于说话:不要叠加态,不要反问句

今天在网上冲浪的时候,看到有人转发了关于河森堡的一条微博,聊到了现在简中内容量子化的问题。

也就是出于一些众所周知、令人发笑的原因,目前在中文网络上发表评论最安全的方式其实就是让自己的内容进入叠加态。所谓的正着理解没什么问题,反着理解也充满了讽刺的趣味,甚至中性地理解也有一丝智慧的奇怪感觉。

我并不打算过多去描述这种现象在文化上带来的长远影响,但是我想说的是,这种做法在日常的工作中,也是极度糟糕的。甚至很多人应该有所感觉,在过去的几年中,不好好说人话这个现象,已经先行一步开始侵蚀企业的公开沟通环境了。

而这样的侵蚀,也确实在过去很多年给我和我的同事们(至少是我欣赏的那批)带来了非常糟糕的工作体验。

不知大家有没有过这样的经历。在企业招聘的过城中,经常会招来一些技术水平并不是非常匹配其职级或报酬的同事,而这类同事中往往分为两类:

  1. 在意识到自己的技能树欠缺以后,在尽可能不犯错,不发表误导建议的情况下,玩命补课
  2. 为了防止别人识别出自己的水分,打肿脸冲胖子,依赖出色的口舌把老板蒙在鼓里,最后捂不住了赶紧跑路。

事实上,我觉得企业给候选人开虚高这件事情并无问题,定级本身只是对寥寥几次的面试的一个总结反馈。无所谓对错,招聘部门和技术面试官也都不是火眼金睛。

根据观察,第一类的同事往往会在一段时间的积累后,爆发出远超公司所开报酬的生产力和效能。这种情况无疑对企业来说是非常划算的交易。

但是糟糕的是第二类人。这类人最显著的特点有两个:

  1. 绝对不承认自己不懂
  2. 将业绩的包装视作比真实结果更重要的点,并擅长叠加态说话法

这两点的持有者能在职场大行其道并不是没有道理,大家也并非懵懂刚毕业的学生,但是个人的观察来看,这种现象的根因是整个社会舆论大环境对企业的一种污染。

一个怕说错话的舆论环境,一个充斥着火药味并习惯于拉旗圈地、标签异己的简中社交圈,必然会让这样的说话习惯渗透进入企业、学校、科研机构

《左传·宣公二年》有言:人谁无过,过而能改,善莫大焉。这本是人人皆知的道理,但是现在整个舆论场已经越来越不能容忍有人发出和自己想法不同的声音。无论是客观的事实错误,还是观点上的意见分歧,都可以招致狂风骤雨一般的声讨和辱骂。

以此,进入了职场,暴露自身错误的代价也不知从什么时候开始,越来越巨大。但是通过欺骗,掩盖自己的错误的收益,也日益诱人。在模糊的中间地带,说话或者报告的时候,尽可能留足后续的扯皮空间,成为了所有职场人稔熟于心的必修课。

但是不幸的是,这些东西在计算机科学上行不通,你唯一可以期待的扯皮空间是高能的宇宙射线把你内存里的某一位打反转了,然而我们用的都是 ECC 内存,反弹你的反转。

尽管我不理解其他行业的运作方式,但是每每看到有人在计算机相关的事件上尝试用叠加态说话法的时候,一种强烈的滑稽感是难以避免的。

正如磁盘并不能因为模棱两可的描述,让 MBR 分区可以给你识别出 6 TB 的空间;数据库不会因随便乱糊的索引而减少慢查询发生的次数;某些知识不会因为说两句模棱两可的话变成可以己用的东西;靠着喊赋能对齐抓手,除了可以让 PPT 和说话者看上去更像是一个语言能力存在障碍的人之外,什么都无法实现。

计算机行业是一个逃避可耻且无效的领域。承认自己在某个领域是个菜鸟,并且多看一些相关的文档和论文,比说任何叠加态的浑话都有建设性太多太多。这也是为什么我喜欢它的原因。

除了上面说的这些以外,其实我觉得很多人也容易混淆 坦诚/直率说话冲 的边界。这里有一个很简单的例子:

  • “我认为对于 Ansible 执行结果的每一个点都进行 Molecule 测试是一个不划算的 trade-off”
  • “哪有那么多人力和开发周期给每一个 Ansible 执行结果做 Molecule 验证啊?”

两句话的内容其实差不多,但是很多时候我们更常听到的是反问的那句。而反问句往往还会伴随着上面的叠加态语言发生。往往会是:

  • 一大段滚咕噜话 + 几句反问句

没反应过来的,甚至会觉得说话者很直率。而事实上,说话者同时犯了两个破坏坦诚交谈原则的错误。而这种说话方式的长期积累的结果,就是企业跨部门合作关系的崩解。

从我这些年的习惯来说,做到坦诚说话是一件并不困难的事情,并没有什么特别的技巧。非要说的话,做好两点就够:

  1. 坦诚承认对某一点不懂,但是愿意去花时间看文档。
  2. 一律不准用反问句

不过我自己也经常犯这类错误,自勉之。希望未来更少给人带来迷惑感和不适感。

最后,祝大家身体健康,工作顺利。

🔲 ⭐

杂谈:聊聊高尔夫球杆

最近趁着招行卡送了很多练习场,就尝试着入坑玩了玩高尔夫。竟意外地发现这个被妖魔化已久的运动,还是非常有意思的。
尤其是球杆的分类,让人感觉非常有器具的美。我想,单从这点来说,理工学生应该挺容易对这个运动产生兴趣。因此花了一些时间,学习了一下球杆的分类,以及相关的一些基本的知识。这里就简单记录一下顺便写写关于这项运动祛魅的一些想法。

但是在开始之前,我必须承认目前的自己只能说新手中的新手,连入门都算不上。高尔夫本身作为对精确度器具要求极高的运动,说实话没有上万次击球的练习的话,别说下场地上果岭了,连做到稳定大力击球都不太可能。这点上和台球倒是有几分相像。

另一条想吐槽的还是国内的场地问题。诚如上海这样的城市,市中心竟也仅有寥寥数家练习场,主要还集中于古北新区这样的传统外国人聚居区。由此可见高尔夫的发展,在国内处于一个非常尴尬的状态。说好听点是还有巨大的市场可以挖掘,说难听点就是因为种种原因,压根就是畸形发展的。

说起为啥觉得这东西好玩,其实就是原始的暴力。只要你打出第一下暴力铁杆挤压击球,这种泄压感是忘不掉的。言归正传,我们来聊聊球杆。

球杆分类

高尔夫球杆粗略来说其实就分为五大类:

  • 木杆 (Wood)
  • 混合杆 (Hybrid)
  • 铁杆 (Iron)
  • 挖起杆 (Wedge)
  • 推杆 (Putter)

边看图边聊会更加直观:

木杆 Wood

一般来说,木杆分为两类,分别是开球木 Driver、球道木 Fairway Wood。

其中,Driver 往往特指 1 号木。这个木杆的特点是头部比较大,重量比较轻,主要用于开球。说实话第一次打 1 号木的时候,真的有被其重量给惊讶到。巨大的头部居然是如此的轻,仿佛空气般的存在。但是抽打的时候声音的暴力程度却远超铁杆。

而 Fairway Wood 则是 3-5 号木,主要用于球道上的开球。头部小了非常多,随之而来的也是使用上难度的陡增。有说法是,三号木是最难打好的一根杆,很多业余玩家可能从未打出过一次完美的三号木。

不过主流球杆生产商通常提供从 3 号木杆到 9 号木杆的不同型号。4 号木有时会代替 3 号木(主要调整距离),而5号木杆则是为那些喜欢在果岭上使用球道木杆而不是长铁杆的球手准备的。

更高序号的木杆往往为女士或老年人这样力量相对更小的球手准备。

一般来说,常规的业余玩家的全套杆里,也就是 3 木 9 铁套里面,木杆主要就是 #1#3#5 这三根。


混合杆 Hybrid

混合杆主要是 1990s 末期开始出现的,算是很经典的场地杆。怎么说呢,如果完全是练习场玩家,真没啥必要买 Hydrid。

混合杆借鉴了铁杆和木杆的特点,具有两者都具备的有利特征。换句话说,结合了铁杆挥杆力学和木杆更宽容的打击域。

因为长铁杆( 1 - 4 号)即使配备了现代化的杆头,也很难用。尤其是在一些深草坪或者树下这样复杂的地形,对于击球点和长球杆都有严格要求的情况下,挺多 Pro 的解决方法是用混合杆取代1-4号铁杆。

这么讲其实也印证了 Hydrid 算是高手球杆这件事。


铁杆 Iron

铁杆是高尔夫球杆中最核心的一组球杆。一般来说,铁杆分为 1-9 号,其中 1-4 号是长铁杆,5-9 号是短铁杆。


其中,7 号铁又是卖的最好的入门级铁杆。因为 7 号铁杆的特点是比较容易击中,而且击球点也比较宽松,所以也是最适合新手的一根铁杆。还有一个野鸡理由是,台湾教练们喜欢用 7 号铁杆来教新手,所以 7 号铁杆也就成了新手的标配。

Iron123456789
Loft[nb 1]14°17°20°23°26°29°33°37°41°
Lie[nb 2]59.5°60°60.5°61°61.5°62°62.5°63°64°
Length (in)[nb 3]40.039.539.038.538.037.537.036.536.0
Length (cm)10110099.197.896.595.394.092.791.4

上表里的 Loft 指的是球杆的挡板角度,也就是球杆的球面和垂直面之间的夹角。通常来说,Loft 越大,球杆的弧度就越高,球飞行的高度就会更高。可以看到编号越大,击球面弧度越高,球的飞行的高度最高。

Lie 指的是球杆的摆角,也就是球杆与地面之间的夹角。通常来说,铁杆球杆的 Lie 角度可以使得击球面和地面接触的位置找平并稳定。如果摆角不对或者不稳定,球杆与地面之间的夹角会改变,会导致球的方向和高度发生偏差。

另外就是随着摆角的增加,球杆的长度相应的变短。简单的勾股定理。

挖起杆 Wedge

又是一类下场才会用的杆。

应该说,挖起杆是铁杆 Iron 的一个子集,专门设计用于特殊救球的情况。因为挖起杆的球面角度最大,杆身最短,重量最重。这些特性可以让球员准确地打出短距离高球,从而上果岭或从柔软的地面把球救回来。

因为挖起杆带有改良后的底板,可以把嵌入或甚至被掩埋的球直接从地里打出来。楔子有多种配置,并一般分为四类:攻击杆 PW、沙坑杆 SW、间隙/进攻杆 GW/AW 和高球杆 LW。

常见的半套杆组里,往往带了一根 P 杆或者 S 杆。


推杆

很多电视剧和电影里经常出现什么反派 Boss 或者大佬在巨大办公室的模拟球道上练高尔夫,他们使用的球杆就是 Putter。

推杆杆是通过轻轻挥杆,从较短的距离将球滚入洞中的球杆。 它非常平坦,低轮廓,有一个低镂角的球头,并具有一些仅限推杆使用的特性:

  • 弯曲杆柄
  • 非圆形握把
  • 定位导杆

推杆一般用于距离杆孔非常近的地方,基本都在果岭上使用,不过少部分球场在果岭边缘和草丛也有适合推杆的点。

如果说下场打的时候有哪根杆是绝对必不可少的话,那只能是推杆。所有市售的半套杆和套杆,一定带了一根推杆。


新手怎么玩

从自己的体验和查阅信息来看,新手期下场地的必要性可能没那么高,除非钱多到烧不完或者有教练无限耐心带你打,否则只会让你怀疑自己不听话的四肢。

在练习场里把开球木、7号铁练好,有条件的话买个地毯练练推杆,就可以了。这样的话,一组入门级半套杆完全够用,而且也不会太贵。一般来说,这样的套杆价格在 1000-3000 之间,足够陪着自己练上万球了。等技术精进之后,再考虑买一套更好的杆,以及开始下场地的练习。

再说了,球杆这玩意儿,有一点一份价格一分货,二毛价格两分货,三块价格三分货的味道。更何况高尔夫入门周期非常长,普通人除非天天有空去练习场练习,否则很难在短时间内精进到可以下场地练习的程度。所以,初学的话更推荐弄一套不那么贵的半套杆,先把五类球杆的特性熟悉了再说。

我也不打算推具体品牌。低价区间国产 PGM 的套杆也不能不能玩。中间档 Taylermade,Callaway,Mizuno 的套杆在 5000 ~ 10000 这个区间,也绝对够普通玩家玩到死了。

如果真的对更上级的手感有所追求,类似于 HONMA, Titleist 这样比较顶的套杆,总归也能满足。至于定制化,那就是专业选手的领域了,不是普通人能玩的。

然后最后一点就是怎么学,高尔夫严格来说还是需要教练的运动,但是如果自己有一定的运动和人体结构知识基础,也可以自己学。这里强烈推荐油管上一些台湾和日本教练出的视频,更加适合东亚人的体态,并且讲得远比国内的教练清楚易懂。

或者换个说法,不是说国内教练水平特别差,而是国内网站上压根就没多少人在做新手入门这块的视频,基数都这么小了,还能期待有什么出色的教学视频呢?

总的来说,从上海目前的物价和消费来说,高尔夫的入门门槛还是非常低的。比什么健身卡、网球场、足球场的练习成本要低多了,而且最重要的时候一个人就能玩。宅宅时代,找人才是成本最高的事情。

希望大家天天运动,健康生活。

🔲 ⭐

TCC 数据库:开发者的噩梦,攻击者的狂欢

苹果,我完全无法理解你

前言

最近几周,我花了不少时间在 macOS 的自动化流程以及 MDM (Mobile Device Management) 的开发上。

事实上我一直以来都难以理解为什么有那么多企业选择使用 macOS 作为员工的工作电脑。

姑且可以认为多数的科技公司从业者都具备一些必要的计算机常识和命令行技能,但是 macOS 本身其实是基于 XNU 内核构建的 Darwin ,而 Darwin 本身又包含了大量来自 BSD 的特性,这些特性意味着用户在深入使用的时候,往往不得不面对一些在 BSD 和 Linux 中同名同姓却完全不同的命令,例如 mount

而更加好死不死的是,Apple 还额外贴心地从 macOS 10.11 开始加入了 SIP (System Integrity Protection),也就是著名的苹果是你的爸爸组件。

这意味着无论你是卑微的个人设备还是财大气粗的企业采购设备,都要面临你的 root 不是真正的 root 这样的糟糕体验。而更加搞笑的是,有时候 SIP 不但没有真正保护用户安全,还接二连三的爆出涉及 TCC.db 的各种权限漏洞,给黑客大开便捷之门。有时候真觉得 macOS 上开发工作流太噩梦了。

本篇我就稍微聊一聊 TCC.db 这个数据库。

TCC - Transparency, Consent, and Control

TCC.db 是 macOS 10.9 之后引入的一个数据库,用于记录用户对于各种系统服务的授权情况。系统级 TCC.db 的完整路径是 /Library/Application Support/com.apple.TCC/TCC.db。而对于每一个单独的用户,其实还有一个 TCC.db,位于 $HOME/Library/Application Support/com.apple.TCC/TCC.db

这个数据库的结构非常简单,只有 6 个表:

  • access
  • active_policy
  • expired
  • access_overrides
  • admin
  • policies

事实上这 6 个表里,在默认情况下有且只有 access 这一个表是有有效数据的。其他的表利用 sqlite3 查看的话可以发现都是空表,而 admin 表也仅有一行:

sqlite3 "./Library/Application Support/com.apple.TCC/TCC.db" "select * from access_overrides;"sqlite3 "./Library/Application Support/com.apple.TCC/TCC.db" "select * from active_policy;"sqlite3 "./Library/Application Support/com.apple.TCC/TCC.db" "select * from expired;"sqlite3 "./Library/Application Support/com.apple.TCC/TCC.db" "select * from policies;"sqlite3 "./Library/Application Support/com.apple.TCC/TCC.db" "select * from admin;"version|20

PS: 无端推测,iOS 的权限实现大概率也是基于类似的机制。

然而这一切对开发者友善的前提是,macOS 需要在 Darwin 的命令行支持或系统开发接口中,也复刻一套这样的授权机制。然而事实上是,macOS 没有做到这一点,也似乎并不打算做好这些支持。

稍微对 SIP 有所接触的人应该会很容易察觉到,苹果对于用户可以在自己的机器上可以做什么这件事情上,做了非常多的限制。在最近的几个版本的 macOS 中,对于所有系统相关的目录,无论用户本身是否是 Administrator,都仅能做只读操作;即便用户通过 sudo su 提权到 root,也无法对这些目录进行任何的写操作。

然而 macOS 就仿佛脑子神经搭错了一样,把 TCC.db 放在了一个普通用户可以进行读写的位置。这就留下隐患了。

当然,macOS 在正常情况下对 TCC.db 还是进行了许多的保护,但是在过去的几年中,这些保护可以被二十多种方法[1]绕过,TCC 提权漏洞在几乎每一个版本的 macOS 中都有出现。这些方法包括且不限于:

  • 插件注入
  • 进程注入[4]
  • /Library & $HOME 挂载 [5], [6]
  • App 行为漏洞利用
  • /usr/bin/grep 注入

这样就呈现出了一个非常怪异的状态。macOS 在每一个版本里都留下了方便攻击者的 TCC 提权方式,却对有着 Administrator 权限的用户进行了严格的命令行指令的限制。举几个例子,以下操作就必须通过往 TCC.db 中写入数据来实现:

  • 通过 /usr/bin/env 在系统后台静默更新特定用户的壁纸。
  • 通过 /bin/bash 静默禁用&启用用户的麦克风和摄像头。这条用过 OBS 的人应该不陌生。

而这些操作本身理应由 Administrator 通过命令行是可以轻松实现的。但是由于 macOS 的糟糕的权限设计,用户不得不深入到 TCC.db 里去,用各种很 Tricky 的方式来实现。

详解 access 表结构

在上面的章节里,我们查看了 TCC.db 所包含的数据表。而里面最有用的 access 表的结构大概是这么个样子:

CREATE TABLE access (    service TEXT NOT NULL,    client TEXT NOT NULL,    client_type INTEGER NOT NULL,--  allowed INTEGER NOT NULL,       -- Removed in Big Sur--  prompt_count INTEGER NOT NULL,  -- Removed in Big Sur    auth_value INTEGER NOT NULL,    -- Added in Big Sur    auth_reason INTEGER NOT NULL,   -- Added in Big Sur    auth_version INTEGER NOT NULL,  -- Added in Big Sur    csreq BLOB,    policy_id INTEGER,    -- Added in Mojave    indirect_object_identifier_type INTEGER,    indirect_object_identifier TEXT NOT NULL DEFAULT "UNUSED",    indirect_object_code_identity BLOB,    flags INTEGER,    last_modified INTEGER NOT NULL DEFAULT (CAST(strftime('%s','now') AS INTEGER)))

这样的多维结构,使得用户可以在非常细致的颗粒度上控制自己的设备。例如,你可以授权某个应用访问你的摄像头,但是不授权它访问你的麦克风;你可以授权某个应用访问你的通讯录,但是不授权它访问你的日历;你可以授权某个应用访问你的照片,但是不授权它访问你的照片库。

以下为每个字段的详细解释:

  • service: 受 TCC 管理限制的服务名。比如 kTCCServiceMicrophonekTCCServiceCamerakTCCServicePhotos 等等。完整的列表我放在本文末尾了。
  • client: 申请访问服务的应用的 Bundle Identifier 或者绝对路径(例如 com.apple.finder 或者 /usr/libexec/sshd-keygen-wrapper
  • client_type: 申请访问服务的应用的类型。0 代表 Bundle Identifier,1 代表绝对路径。
  • allowed: (本字段仅存在于 Big Sur 之前的版本) 是否允许访问(1)或者拒绝(0
  • prompt_count: (本字段仅存在于 Big Sur 之前的版本) 用户被提示的次数。如果程序在第一次被拒绝后,仍然不断地申请访问,那么这个字段就会不断地增加。
  • auth_value: (本字段仅存在于 Big Sur 以及之后的版本) 访问权限的值。0 代表拒绝,1 代表未知,2 代表允许,3 代表有限制。例如,允许应用选择照片,但是不允许它访问整个照片库。
  • auth_reason: (本字段仅存在于 Big Sur 以及之后的版本) 用于描述 auth_value 是因何理由被设置的。一个常见的值是 3,代表 用户设置。完整的列表我也放在本文末尾了。
  • auth_version: (本字段仅存在于 Big Sur 以及之后的版本) 默认为 1,也可能会随着未来的 macOS 版本而改变。
  • csreq: 二进制代码签名要求 blob 必须满足特定的格式,以便获得访问权限。这是用于防止攻击者的欺骗/冒充。我会在下一个章节描述以下如何进行这部分内容的生成和解码。这里真得感谢 Keith Johnson,即便在英文互联网上,可能也就他那条回答真正解释清楚了这个字段。可以简单理解为对 client 目标进行 csreq 处理后的 Blob 值,我会在下一节详细解释。
  • policy_id: 这个字段与 MDM(Mobile Device Management) 策略相关,carlashley/tccprofile 可以用于生成这些配置文件。
  • indirect_object_identifier: 用于指定某个服务(例如 kTCCServiceAppleEvents)的目标客户端。这个字段可以是 Bundle Identifier 或者绝对路径,就像 client 字段一样。在某些情况下,这个字段会被设置为 UNUSED
  • indirect_object_identifier_type: 用于指定 indirect_object_identifier 字段的类型。0 代表 Bundle Identifier,1 代表绝对路径。
  • indirect_object_code_identity: 和 csreq 字段一样,这个字段也是用于防止攻击者的欺骗/冒充。但是这个字段的作用于 indirect_object_identifier 字段指定的客户端。可以简单理解为对 indirect_object_identifier 目标进行 csreq 处理后的 Blob 值,我会在下一节详细解释。
  • flags: 未知作用。值总是为 0,可能与 MDM 策略一起使用。
  • last_modified: 最后一次修改的时间戳。

如果你还不知道什么是 Blob,可以参考 The BLOB and TEXT Types.

有了这些字段的详细解释,我们就可以读懂甚至构造一条 TCC.db access 语句了。当然在开始之前,我们还需要补充一个知识点,就是 csreq。利用 csreq,我们可以解码一个二进制代码签名 Blob,亦或者从零开始构造一个 Blob

关于 csreq[3]

很多人一看到要构造一个 Blob 第一反应就是慌,事实上我也是一样。

不过我们在插入数据到 TCC.db 的时候,只需要构造一个满足特定格式的、非常短的 Blob 即可。这个 Blob 的格式是由 Apple 的 libsecurity_codesigning 库定义的,源代码可以在这里找到:libsecurity_codesigning/lib/requirement.h

比较粗略的看了一下,这个头文件定义了一个叫 Requirement 的类,用于表示苹果的代码签名要求(Code Signing Requirements)。Requirement 类的成员函数包括用于验证是否合法和满足格式要求的 void validatebool validates;还有用于声明格式的 kind 函数,不过目前唯一支持的表达式的类型是 opExpr

不过实际上我们并不需要手动写 csreq 的生成 & 翻译工具,macOS 本身就自带了一个同名的命令行工具 csreq。这个工具可以用来生成 Blob,也可以用来解码符合格式要求的 Blob。这个工具一个旧版本的源代码在这里:csreq.cpp

下面主要来说说怎么用吧。就以 TCC.db 插入时最常用的一条 Blob 为例,来看看怎么用 csreq 来生成和解码这个 Blob

# Convert the hex string into a binary blob$ BLOB="FADE0C000000003000000001000000060000000200000012636F6D2E6170706C652E5465726D696E616C000000000003"$ echo "$BLOB" | xxd -r -p > terminal-csreq.bin# Ask csreq to tell us what it means$ csreq -r- -t < terminal-csreq.binidentifier "com.apple.Terminal" and anchor apple

从解码的结果来看,这条 Blob 代表了一个通过苹果官方签名的 com.apple.Terminal 对象。

那这条信息 identifier "com.apple.Terminal" and anchor apple 本身是怎么来的呢?或者说,我们应该怎么写这条原始文本,并确认其符合 Blob 的解析原文的格式要求呢?其实也很简单,使用另一个命令行工具 codesign 就可以获得任意已签名对象的 designated 字段,也就是 Blob 的合法描述原文:

$ codesign -d -r- /Applications/Utilities/Terminal.appExecutable=/Applications/Utilities/Terminal.app/Contents/MacOS/Terminaldesignated => identifier "com.apple.Terminal" and anchor apple

这里再举一个类似的例子,也就是游戏开发团队非常常用的 P4V 客户端,这玩意儿的 Blob 是:

fade0c000000009c00000001000000060000000600000006000000060000000200000010636f6d2e706572666f7263652e7034760000000f0000000e000000010000000a2a864886f763640602060000000000000000000e000000000000000a2a864886f7636406010d0000000000000000000b000000000000000a7375626a6563742e4f550000000000010000000a505959465359353453370000

我们来依样画葫芦地解码一下:

# Convert the hex string into a binary blobBLOB="fade0c000000009c00000001000000060000000600000006000000060000000200000010636f6d2e706572666f7263652e7034760000000f0000000e000000010000000a2a864886f763640602060000000000000000000e000000000000000a2a864886f7636406010d0000000000000000000b000000000000000a7375626a6563742e4f550000000000010000000a505959465359353453370000"echo "$BLOB" | xxd -r -p > p4v-csreq.bin# Ask csreq to tell us what it means$ csreq -r- -t < p4v-csreq.binidentifier "com.perforce.p4v" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = PYYFSY54S7# ask codesign what the requirement text from the application itself is$ codesign -d -r- /Applications/p4v.appExecutable=/Applications/p4v.app/Contents/MacOS/p4vdesignated => identifier "com.perforce.p4v" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = PYYFSY54S7

可以看到,就是这样简单的处理,就能获得任意对象合法的 Blob 描述原文。

那么第二个问题来了,既然可以通过 codesign 来获得 Blob 的描述原文,那么我们应该如何获得 Blob 本身呢?这个问题其实也很简单,只要把 Blob 的描述原文通过 csreq 转换成二进制格式即可。

这里我们继续用 p4v.app 为例:

# Get the requirement string from codesign$ REQ_STR=$(codesign -d -r- /Applications/p4v.app/ 2>&1 | awk -F ' => ' '/designated/{print $2}')# Convert the requirements string into it's binary representation(sadly it seems csreq requires the output to be a file; so we just throw it in /tmp)$ echo "$REQ_STR" | csreq -r- -b /tmp/csreq.bin# Convert the binary form to hex, and print it nicely for use in sqlite$ REQ_HEX=$(xxd -p /tmp/csreq.bin  | tr -d '\n')$ echo "X'$REQ_HEX'"X'fade0c000000009c00000001000000060000000600000006000000060000000200000010636f6d2e706572666f7263652e7034760000000f0000000e000000010000000a2a864886f763640602060000000000000000000e000000000000000a2a864886f7636406010d0000000000000000000b000000000000000a7375626a6563742e4f550000000000010000000a505959465359353453370000'

如你所见,刚才的 Blob 描述原文,就这样简单的获取到了。看到这一步的你,应该已经有能力自由地获得任意目标的 Blob 描述原文,并将其转换成 Blob 本身。

动手构造一条 TCC.db access 语句

既然万事具备,说再多不如动手构造一条 TCC.db 的插入语句来得记忆深刻。

这里我们以 kTCCServiceAppleEvents 服务为例,构造一个允许 /usr/bin/env 通过 AppleEvents 服务访问 /System/Library/CoreServices/System Events.appaccess 表的插入语句。

这个插入语句的作用呢,一般来说是用来帮助 osascript 命令在执行 Apple Script 的时候,强制跳过一些用户 GUI 层的确认对话框,从而达到静默执行 Login Items 的目的。在类似 JAMF Pro 这样的企业级管理软件中,有不少类似的骚操作。

好,我们开始。

  • 首先是 service 字段,这个字段的值是 kTCCServiceAppleEvents,是我们的目标服务,也就是用于跳过一些强制行的用户确认 Prompts 的服务对象。下一节为参考表
  • 然后是 client 字段,这个字段的值是 /usr/bin/env,这个是我们的目标客户端,也就是我们要让它通过 kTCCServiceAppleEvents 服务访问 /System/Applications/System Preferences.app 的客户端。这里无论是 /usr/bin/env 还是其对应的 identifier,都是可以的,所以也可以写成 com.apple.env
  • client_type 字段,如果你 client 填的是 /usr/bin/env,也就是绝对路径,那就这个字段的值是 1;如果填的是 com.apple.env,也就是 identifier,那就这个字段的值是 0
  • auth_value 字段,那肯定是允许嘛。所以这个字段的值是 2
  • auth_reason 字段,这个字段的值是 3,也就是 User Set。表示是用户自己设置的(笑)。下一节为参考表
  • auth_version 字段,默认就是 1。别问,别管。
  • csreq 字段,这个字段就是对 /usr/bin/envBlob 描述原文的二进制表示。构造方法上面一节已经说的清清楚楚了。
  • policy_id 字段,我们暂时用不到,设置为 NULL
  • indirect_object_identifier_type 也就是被访问对象的类型,这里是 0,也就是 identifier
  • indirect_object_identifier 字段,这个字段的值是 /System/Library/CoreServices/System Events.app/identifier,也就是 com.apple.systemevents
  • indirect_object_code_identity 字段,这个字段的值是 /System/Library/CoreServices/System Events.app/Blob 二进制表示。构造方法也是参考上一节。
  • flags 字段,我们暂时用不到,设置为 NULL
  • last_modified 字段,这个字段的值只要是合法的时间戳就行,我自己一般喜欢用 2022-01-01 00:00:00,也就是 1642634565

那么现在,我们的插入语句已经全部完成了,写出来就是这么个样子:

INSERT INTO access VALUES(    'kTCCServiceAppleEvents',   -- service    '/usr/bin/env',                -- client    1,                          -- client_type    2,                          -- auth_value    3,                          -- auth_reason    1-- auth_version    -- csreq    X'fade0c000000002c0000000100000006000000020000000d636f6d2e6170706c652e656e7600000000000003',    NULL,                       -- policy_id    0,                          -- indirect_object_identifier_type    'com.apple.systemevents',   -- indirect_object_identifier    -- indirect_object_code_identity    X'fade0c000000003400000001000000060000000200000016636f6d2e6170706c652e73797374656d6576656e7473000000000003',    NULL,                       -- flags    1642634565                  -- last_modified);

之后我们就可以用 sqlite3 命令行工具,或者 DB Browser for SQLite 这样的 GUI 工具,将这条语句插入到 TCC.db 中了。

然后,你就可以通过构造一个 plist 文件和 launchctl 命令,给用户加载一些 Login Items,例如更换壁纸、更换 Dock 图标、更换桌面图标等等,而不需要经过用户在 GUI 的窗口确认了。

以下为一个简单的 plist 文件示例:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict>    <key>Label</key>    <string>{{ plist_name }}</string>    <key>Program</key>    <string>{{ apple_script_path }}</string>    <key>RunAtLoad</key>    <true/></dict></plist>

吐槽:明明非常正常的设备和系统管理操作,非要被苹果弄得像是黑客入侵操作一样。真有你的,库克。

Service & Auth_Reason 参考表[2]


SERVICE List
Value Description
kTCCServiceAddressBook client would like to access your contacts.
kTCCServiceAppleEvents client wants access to control indirect_object. Allowing control will provide access to documents and data in indirect_object, and to perform actions within that app.
kTCCServiceBluetoothAlways client would like to use Bluetooth.
kTCCServiceCalendar client would like to access your calendar.
kTCCServiceCamera client would like to access the camera.
kTCCServiceContactsFull client would like to access all of your contacts information.
kTCCServiceContactsLimited client would like to access your contacts basic information.
kTCCServiceFileProviderDomain client wants to access files managed by indirect_object.
kTCCServiceFileProviderPresence Do you want to allow client to see when you are using files managed by it? It will see which applications are used to access files and whether you are actively using them. It will not see when files that are not managed by it are accessed.
kTCCServiceLocation client would like to use your current location.
kTCCServiceMediaLibrary client would like to access Apple Music, your music and video activity, and your media library.
kTCCServiceMicrophone client would like to access the microphone.
kTCCServiceMotion client Would Like to Access Your Motion & Fitness Activity.
kTCCServicePhotos client Would Like to Access Your Photos
kTCCServicePhotosAdd client Would Like to Add to your Photos
kTCCServicePrototype3Rights client Would Like Authorization to Test Service Proto3Right.
kTCCServicePrototype4Rights client Would Like Authorization to Test Service Proto4Right.
kTCCServiceReminders client would like to access your reminders.
kTCCServiceScreenCapture client would like to capture the contents of the system display.
kTCCServiceSiri Would You Like to Use client with Siri?
kTCCServiceSpeechRecognition client Would Like to Access Speech Recognition.
kTCCServiceSystemPolicyDesktopFolder client would like to access files in your Desktop folder.
kTCCServiceSystemPolicyDeveloperFiles client would like to access a file used in Software Development.
kTCCServiceSystemPolicyDocumentsFolder client would like to access files in your Documents folder.
kTCCServiceSystemPolicyDownloadsFolder client would like to access files in your Downloads folder.
kTCCServiceSystemPolicyNetworkVolumes client would like to access files on a network volume.
kTCCServiceSystemPolicyRemovableVolumes client would like to access files on a removable volume.
kTCCServiceSystemPolicySysAdminFiles client would like to administer your computer. Administration can include modifying passwords, networking, and system settings.
kTCCServiceWillow client would like to access your Home data.
kTCCServiceSystemPolicyAllFiles Full Disk Access
kTCCServiceAccessibility Allows app to control your computer
kTCCServicePostEvent Allows to send keystrokes
kTCCServiceListenEvent Input Monitoring; to monitor input from your keyboard
kTCCServiceDeveloperTool Allows app to run software locally that do not meet the system’s security policy
kTCCServiceLiverpool Related to location services
kTCCServiceUbiquity Related to iCloud
kTCCServiceShareKit Related to the share feature(presumably from iOS)(ShareKit)
kTCCServiceLinkedIn LinkedIn
kTCCServiceTwitter Twitter
kTCCServiceFacebook Facebook
kTCCServiceSinaWeibo Sina Weibo
kTCCServiceTencentWeibo Tencent Weibo

AUTH_REASON List
Value Description
1 Error
2 User Consent
3 User Set
4 System Set
5 Service Policy
6 MDM Policy
7 Override Policy
8 Missing usage string
9 Prompt Timeout
10 Preflight Unknown
11 Entitled
12 App Type Policy

相关文献

  1. 20+ ways to bypass your mac os privacy mechanisms – Csaba Fitzl
  2. A deep dive into macOS TCC.db – Keith Johnson
  3. How to get csreq of macOS application on command line? – Keith Johnson
  4. CVE-2020–9934
  5. CVE-2021-1784
  6. CVE-2021-30920
🔲 ⭐

如何合法申请一张欧盟 N26 银行信用卡用于 ChatGPT

DEPRECATED

博文内容失效警告 - 2023/06/22
根据评论区反馈,目前德国的长期居留证明已经是必须的了。因此,本文所描述的申请方式,不再可行。望周知。

前言

近期随着 ChatGPT 以及 ChatGPT API 的爆火,越来越多人需要使用 API Token 来进行开发和研究。但是很快开发者们就会发现,所有中国大陆和港澳地区发行的 MasterCard & VISA 行用卡,都会被 OpenAI 拒绝支付。我国的信用卡经过这么多年的努力,也算是成为了著名的不被信用卡。所以对于身在国内的人来说,如何安全稳定的获取一张可以使用海外 MasterCard & VISA 信用卡就成了一种刚需。

事实上很多人说可以申请一些加密货币信用卡,例如 Depay 或者 Nobepay 之类的。但是说实话这类信用卡基本都有一大堆特别蠢的硬伤:

  • 是中国人开的
  • 和 DeFi 交易密切相关
  • 开卡手续费高昂
  • 野鸡

上面任何一条单独拿出来就足够打消开卡的必要,安全性更是一塌糊涂。在目前这个时间点,笔者调研了一大圈,谨慎觉得对于开发者最好的选择可能确实就是 N26 银行的虚拟卡了。

N26 银行简介

本章节由 ChatGPT 书写 - N26 是一家来自德国的全数字化银行,成立于 2013 年,总部位于柏林。N26 的目标是重新定义银行,使它变得更加简单,透明和实用。

N26 通过其移动应用程序提供银行服务,包括:存款账户,借记卡和信用卡,转账,保险和投资产品等。其应用程序具有清晰简洁的界面,使用户可以方便地查看他们的账户余额和交易历史记录,并且提供了安全,快速和便捷的支付方式。

N26 还提供 24/7 的客户支持服务,并采用强大的安全措施来保护用户的账户。此外,N26 还与其他银行合作,以提供跨境转账和汇款服务。

当你在 N26 银行注册账户时,你可以选择三种不同的账户类型:N26 Standard,N26 You 和 N26 Metal。每种账户类型都有不同的功能和特点。

  • N26 Standard: 该账户类型是免费的,并提供基本的银行服务,包括免费的借记卡和5次免费提现。另外,该账户还提供保险服务,如手机保险和出行保险。
  • N26 You: 该账户类型需要付费,并提供更多的特殊功能,如免费提现和免费的外币交易,以及更多的保险和旅行服务。此外,N26 You账户还提供可自定义的借记卡和选择颜色。
  • N26 Metal: 该账户类型是最高端的账户类型,需要付费,但提供的特殊功能更为丰富。该账户提供无限免费提现和免费外币交易,以及更多的高级保险和旅行服务。另外,N26 Metal 账户还提供金属质感的借记卡和个性化服务。

在使用N26银行账户时,你可以通过N26移动应用程序进行转账、支付和管理账户等操作。应用程序具有直观的界面和易于使用的功能,允许用户随时随地查看账户余额和交易历史记录,并可以轻松地设置支出限额和预算等功能。此外,N26 还提供与其他银行合作的跨境转账和汇款服务,方便用户进行国际转账。

最后,N26 银行采用了强大的安全措施,保护用户的账户安全。例如,用户可以设置额外的安全密码来保护账户,每笔交易都需要确认,N26 应用程序还具有实时警报和防欺诈措施等功能。总之,N26 银行是一家以数字化为核心的现代银行,旨在提供方便,安全和高效的银行服务。

申请前准备

  • 护照
  • 一张美国的手机卡,可以是 Google Voice
  • 可以听懂土耳其口音英语的能力和正常英语口语交流能力
  • 尽可能全程保持欧洲或者北美网络环境

申请流程

本章节内容大量参考了 YouhuiMa 先生所写的 N26银行常见问题2022年版,但是由于时间有过去了大半年,有些内容有些许差异。

1. 首先打开 N26 官方网站

网站地址:N26.com。点击右上角的 Login,然后点击 Create a Account

2. 开始填写基本注册信息

Nationality 这一栏强烈推荐选择德国 Germany。因为德国在认证的时候不需要你的手机开GPS定位,只要你会一点英语或者德语,他们的简单问题你都可以完成。申请德国账户通过率高,而且因为 N26 银行总部就在德国,德国的账户服务和各种功能都是最全最新的。

自 2022 年开始,申请者如果使用中国大陆的手机号注册,往往会不成功或者接受不到验证码。而美国和香港的手机号包括虚拟号都可以顺利接受验证码。

3.填写个人信息

所有信息必须真实有效。尤其是姓名一定要和你护照上一致

笔者因为疏忽第一次注册的时候填错了姓名,直接导致浪费了一个邮箱和一个手机。因为一旦完成注册,在做完所有的认证之前,是无法登入账号管理页面的,也因为无法通过人工以外的方式删除错误的账号,会导致手机号码直接被废掉。而一个手机只能绑定一个账号,这里一定要小心再小心。

4. 填写申请N26银行账户的个人住址信息

如果要申请西班牙或者意大利的 N26 账户,你需要在当地有一个居住地址,方便接受邮寄给你的银行卡。如果你仅申请普通免费账户,N26 是不会给你寄实体卡片的,所有操作都在手机 app 上完成。因此,申请人是否真的有一个所在国家的地址就不那么重要了。在网上找一个看起来像居民住宅的地址填入就可以。比较推荐 Random German Addr

5. 填写申请人的国籍和出生/性别信息

这部分同样一定要和你的护照内容一致,如果你是中国护照或者其他国家护照,请如实填写,因为之后的视频认证需要核对的。

6. 你的工作状态相关问题

简单如实选择就可以,并不是很重要。一般来说有需要的人都填 Employment。老板们自然有合法获取全球各国信用卡的方法。主要会咨询目前雇主是哪个行业的,这个问题不重要,简单选择一个就可以,一般的码农都是 Media, technology & consulting。以及最后会询问以下你申请 N26 的用途,一般都是个人项目开发,如实选择即可。

7. 美国相关的问题

这里回答是否申请人有美国身份或者绿卡,以及询问是否有美国纳税义务。如果没有持有绿卡或者美国国籍,第一个问题选择 NO。同时也没有美国纳税的义务,第二个问题选 NO。

这里想到一个笑话,如果有一天美军和解放军还有俄罗斯军队联合起来,世界上还有什么可以阻止他们;这个时候,IRS 出*手消灭了三国联军,因为他们供应链没有缴纳足额税款。

8. 申请人税务地相关的问题

此时会询问申请人在哪个国家纳税,可以选填自己的税务号码 Tax ID,或者 Tax ID 留空也可以。不影响后续申请。

9. 设置账号的密码

密码设定推荐使用比较复杂的,至少 11 位含有数字、字母和特殊字符。如果你有推荐人,可以填写推荐号码。然后点击去下一步

10. 确认所有注册信息

确认一下所有的申请信息是否正确,然后点击同意合同条款。到这里其实网上申请就基本结束了,N26银行会立刻发Email给你,请打开你的邮箱,点击绿色确认按钮进行确认。点击开户后您的账户就完成了。


认证流程

完成申请账号只是 N26 申请过程中比较简单的一环,相对恶心的步骤是认证阶段。不过毕竟是欧盟最大的网络银行,严格一点也是情有可原。我们在完成注册后,首次登陆会提示你选择一些必要信息,以及信用卡套餐。这里我们应该选择没有任何费用的 N26 Standard 方案。之后页面中会出现以下提示,意味着之后的步骤都应该在手机 App 上完成。

在 App store 下载 N26 App后,登录你的账户,然后需要绑定你的手机,然后选择使用 Germany Resident VISA (只是一个选项,实际并不需要看)验证身份,一直点击继续直到开启视频验证。
验证的时候,你要找一个安静的地方并且网络畅通。目前 Verify Your Identity 稍微有些问题的更新,需要着重讲一下。

Verify Your Identity 视频认证的时候,可以选择德语或者英语,工作时间是德国时间早9晚5,认证专家会询问你以下几个问题:

  1. 确认姓名
  2. 确认是否本人申请(回答 Yes)
  3. 确认是否在一个安静的,没有任何其他人的环境(回答 Yes)
  4. 确认是否有任何人告诉你申请 N26 后会有报酬(回答 No)
  5. 确认并拍摄你的照片
  6. 确认并拍摄你用手张开五指从面前上下移动的片段
  7. 确认护照号码及把护照的首页在摄像头前给客服看一看
  8. 确认并拍摄护照上下移动的片段
  9. 确认并拍摄护照被手指部分遮住的片段
  10. 确认并拍摄护照号码区域的详细内容
  11. 确认并拍摄申请人念出护照号码的片段
  12. 再次发送短信到你的手机,通过 App 内进行输入确认

整个过程大约10分钟不到,之后便会提交你的认证信息到 N26 审核部门。如果在周末,你可能需要等到工作日后才会收到审核通过的状态信息;如果是工作日,应该会比较快就审核完毕。一旦视频认证成功,N26 银行账户马上就打开使用了,如果申请了实体银行卡,就会在 3 天内收到邮局寄来的银行卡。(如果本人不在欧洲,建议不要申请实体卡)。

即使开户人不在德国,通过 Email 你也会知道你的 N26 银行帐号 IBANBIC 等关键信息。之后打开你的 App 已经可以操作了。

结尾

现在,愉快地拿着你全新的欧盟 MasterCard 开始 ChatGPT API 的开发之旅吧。

🔲 ⭐

聊聊个人博客这件事(一)

今年这个夏天也算是比较正式的把自己的个人博客从 medium.com 上迁移了下来。不是说Medium这样的SaaS博客不好,更多的是对MarkDown编辑器本身的执念以及SaaS天然的对版本管理的缺陷导致的。

想了想过去几年其实都没有真的认真经营过博客,当然了,这种纯粹自我娱乐的东西,倒也并无经营的必要。但是作为一种半公开的网络日志,仅仅从自我愉悦的角度来说,亦是值得投入时间的。当自己在一个很长的时间轴里回看自己在过去的一些观点,本身也是一个很好的照见自我的修行。

写博客的过程从某种角度来说甚至有点像十数年前在QQ空间无病呻吟所得到快乐,但是前者更像是荷尔蒙追逐下的孔雀炫羽,后者更多是一个强迫自己输出的做法,虽然都存在功利性,但是方向却大不同。

无意义的文字说了这么多,还是回归主题,聊聊自己这些年在博客这件事情上玩过的和经历过的趣事,以及关于博客搭建这个事情的一些浅见。所以大概会下面的顺序来规划这些内容:


最开始尝试接触博客的时间点是比较晚的,差不多从2016年左右才开始有搞搞个人博客的规划。但是考虑到这玩意儿本质是一个00年代站长时代的玩意儿,事实上现在到底还有多少人还有兴趣去写博客或者看博客,其实大家心里都有答案。这也是我在相当长时间里并不认真打理自己的N个博客的根因。

但是进入职场以后,发现了一个相当有意思的现象。明明是对计算机和互联网最熟悉、玩的最透彻的这帮程序员,反倒是博客这种复古玩具最忠实的用户。基本上有点想法的技术工作者多少都会维护一个自己的微博,而且都喜欢Self-Host。当然一开始也想过这种潜在的鄙视链是否有点“博斯林”的味道,但是当自己亲自吃过鳖以后,才真正意识到可能确实只有Self-Host的博客才能满足定制化的各种奇怪需求。

  • 只可惜在这里摔了两次

当时刚回国,查了一圈国内比较主流的技术博客平台,查到了掘金简书,当然博客园CSDN这种平台因为过于丑陋的UI和低劣的吃相一开始就没作考虑。所以当时在掘金和简书上同步更新了一段时间,内容更是五花八门,开发心得、学习心得、部署方法,各种现在看上去幼稚而搞笑、且没有任何营养和趣味的流水线技术文。所以这次迁移博客也没打算把那些文章迁过来,徒增笑尔。但是在掘金和简书的那段时间倒是收获了一些奇怪的零花钱,就是你的文章一旦有些许的阅读量,就会有人来加你联系方式,然后请你在文章的开头添加类似于编程培训那样的广告。倒也是嗦过两口这种蚊子腿。

后来花了一些时间阅读了一下国内几家比较有影响力的博客,除了编程随想托管在了BlogSpot以外,绝大多数的个人博客都采用的自建的模式。甚至有些更有时间或者更喜欢炫技的直接做了个人站,倒也是一件趣事。只是作为一个インフラ业者,我觉得更专注文字的博客框架可能更合适自己。

所以当时脑子一热,直接在Linode上起了一台云服务器,装了WordPressTheme一套,CertBot一跑,瞬间一个博客就起来了。但是这个时候我发现了WordPress存在一个没法回避的弊端: 这东西性能其实并不是很好,而且对于文字为主的博客来说,功能太冗余庞杂了。如果你需要的是一个电商首页、产品官网或者正儿八经的论坛,WordPress都会是非常不错的选择,但是如果作为一个纯粹的个人微博框架,是会有很多问题的。这点我争取在下一篇讲讲清楚。

恰好那个时间点公司事情比较忙,也刚好看到前Boss在Medium上更新了大量的优质文章,遂想着与其在自建Blog里折腾玩乐,不如直接在SaaS上专注写作。结果我低估了没有MarkDown带来的不便。

其实对于Medium整体的印象还是非常好的,作为全球最大的几家博客平台,不但提供了非常优美的原生字体和编辑器,并且为博主的盈利化创造了很可能是最好的环境。如果你能输出大量优质英语内容的话,在Medium上实现副业超越主业绝非不可能的任务。只是,MediumIntegration上做的真的不太好,尝试过用Zapier这样的工具去把NotionGitHub的内容同步到Medium上,但是效果非常不尽人意。如果真要弄大概率是需要自己造一个轮子才能起飞的。

而且最后让我彻底抛弃Medium的一个导火索,其实是这条通知。这意味这Medium的大策略就是封闭了。

As of May 2022, Medium no longer supports setting up a custom domain for your profile page or publication.Custom domains that are already connected will still redirect to your profile page or publication. However, it is no longer possible to connect a custom domain for the first time or to change it. You can disconnect your custom domain at any time in your Settings. Please note that once you disconnect your domain, you will not be able to re-connect it.

说到Notion,之前也想过一个问题,Notion或者Evernote这样的笔记软件和博客的边界到底在哪里。这两年大约是想清楚了。博客更多情况下是经过提炼的笔记,是笔记中脱敏的、精炼后的观点。两者确实存在关联,但是绝非可以互相替代的存在。在笔记中的大量观点,经过整理和反思,最终可以反哺给博客,作为可读性更好的素材。

总之,最后思索再三,还是从Medium上迁移了下来,选择回到Linode上自建。只是这次,我启用了Hexo,并且把HexoGitHub Action完全打通,在本地的VSCode完成了 [MarkDown写作Git一键上传合并Action远程执行VM重新生成Public自动发布] 的流程。现在还剩下一个小问题要处理,就是要做一份Public静态资源的同步到阿里云上,来解决国内访问Linode资源有墙的问题,同样可以在GitHub Action做掉。

以上的详情会在聊聊个人博客这件事(三)里详细谈谈。

感谢阅读

🔲 ☆

四月的声音,在六月消逝

长达61天的上海封锁终于结束了。没人能说明白这两个月里上海经历了什么,这个国家经历了什么。如果真要说一下感受的话,可能真的只是:四年春秋,大梦一场

还记得4年前的夏天踌躇满志从成田机场飞往浦东国际机场的时刻。很难想象当时的自己对这个国家是充满了何等的信心和热切。08年开始的整整十年的经济增长期犹如一种吸引了所有人的魔药,让大量的年轻人涌入了这个能把猪都吹飞的互联网热潮。

四年过去,确是从互联网中捞得了些微的金钱。但是日益收敛的舆论环境和政策让人无法得到一丝安心。企业的不规范和上位者的低能招致了大量年轻人疲乏其中,糟糕的政治环境让所有阶层没有真正的安全感。也许在这个六月,我们也该做出下一站的决定了。

我想暂时还会是那个东边的岛国,继续前行吧。正如80年前,那群在黎明前依然前往香港的冒险家一样。

❌