《病人家属,请来一下》书摘

d2b5ca33bd970f64a6301fa75ae2eb22 40
d2b5ca33bd970f64a6301fa75ae2eb22 40

生命,就是由一系列意外组成 ——与一名癌症病人女儿的书信往来

  • 正是因为有了这样的时间和空间的限制,每一天的鸟语花香才显得弥足珍贵。
  • 选择大教授仍然是一个稳妥的做法。也许你认为看诊一分钟要解决的是自己心中的疑问,但对教授来说,是要决定治疗方案的,任何无关的信息都会拖延他下判断的时间,作为门诊医生,他并不希望和你展开聊天。高等级的医院里,下面的医生执行医疗方案是没有什么问题的,这一点不需要过于担心。
  • 医生的说法也许有不同,这也是合理的,这说明目前你父亲的状态,治疗的选择很多,没有一个确定的最优解,这本身就是生命的奇妙之处。

第一章 医疗信息篇 明确思路,谋求共识

  • 大量数据表明,厨房油烟也许才是女性患肺癌的重要原因

第五节 别总让医生管理你,你也要管理好医生

  • 有时候你也不得不承认,即使程序是正义的,民主也必定是无能且低效的。

第二章 心态篇 癌症没有想象中那么可怕

  • 谁出钱,谁知情。

第五节 人是种需要集体支持的社会动物

  • 千万不要小看这种感觉。当人在对“生存”本身没有安全感的时候,要获得内心充盈、自如的状态,是非常难的

第二节 女婿经济学:癌症病人家庭如何决定花多少钱看病?

  • 女婿和媳妇没有本质区别,也和男女无关,关键是这个家庭当中谁能够获得大多数家庭成员的信任,进行合理的决策

第三节 医生总让我选择治疗方案,太纠结了怎么办

  • 人总是在出现不如意结果的时候开始质疑自己当初的选择,但你问问自己,当时做的选择是不是基于当时的情况的最优解。如果是的话,要努力放过自己。
  • 开个家庭会议。叫上负担家庭收入主要来源的人、对家庭的债务和风险负主要责任的人、药费的主要提供者、家里话语权最大的大家长,坐在一起开一次家庭会议。你不妨用这样一个公式来帮助你判断。用药程度=药物效果-并发症-价格-家庭负债例如这个药物 100%有效,就是 100 分;并发症的发生率是 10%,就是 10 分;价格是每年 20 万,要用 2 年,那就是 40 分;家庭负债是 80 万,就是 80 分;用药程度=100-10-40-80=-30 分。低于 0 分,意味着从你们家庭长期发展的角度考虑,眼下这个矛盾也许不适合投资这么一大笔钱解决。会议的召开和结果,都要和其他家庭成员同步。

第五节 买对保险不踩坑,你才能逆风翻盘

  • 所以我一直认为,代理人是短期内不能完全被互联网取代的存在,他不只是一个中介,他更应该是一个优质的法律顾问

《武汉女孩阿念日记》书摘

d2b5ca33bd970f64a6301fa75ae2eb22 39

在 2023 年,奥密克戎疫情袭来,我国疫情防控从之前的严防严控调整为逐步放开的时刻,这本书值得你去读一读,去感受一下 2020 年初武汉人民的绝望和痛苦。时至今日,我们所遭遇的病毒可能和当时已经完全不同,但我们依然需要珍惜身边的人,为自己身边的人做好准备,应对疫情。

白宦成
d2b5ca33bd970f64a6301fa75ae2eb22 39

来到火神山,见到外婆 2月19日 星期三

  • 新冠肺炎是一个让人孤独的疾病,把每个人的路分开。走着走着你会发现,旁边是没有别人的,只有你在踽踽独行,前方可能有野兽,可能有泥泞,而你没有地图和向导,一切都需要自己去摸索
  • 我一直觉得,“骄纵”必是先有“纵”而后才“骄”,而过分“懂事”除去个人修养,有一部分原因是自卑,担心自己不那么被在乎,所以往往主动向后退一步,选择对生活妥协。

“你要是照顾不好外婆,我对你不客气” 2月21日 星期五

  • 不知道其他人是否也有像外婆这样倔强又不会撒娇的长辈,喜欢用责怪去表达关心。大概亲人总是这样,好话总要反着说,我们需要抛开情绪的因素,体会对方说话的本心。

回家之后

  • 以前好朋友对我说过一句话,成年人应有的礼貌,是把自己的伤口舔好再出来见人。大概像某种昆虫吧,难过的时候把痛苦织成茧,包裹着自己,待有朝一日恢复后,再优雅地破茧而出以新形象见人。

35 岁问题,只与你的竞争力有关

man and woman sitting on bench

时常会在各种论坛看到一些关于 35 岁裁员的话题,大家都很恐慌自己会在 35 岁被裁员。

但说实话,这个事情其实没有那么复杂,你是否 35 岁被裁员,只与你的竞争力有关

当然, 不同的人和环境竞争力和年龄的相关性是有区别的:

以绝大多数人感知到 35 岁裁员的消费互联网为例:消费互联网主要需要的是快速迭代的能力和对于用户行为、用户需求的感知,这里需要的更多是随机应变的能力,自然也就更多需要加班、卷。当然,你也可以通过一些别的手段来增强自己的竞争力 —— 比如质量、效果。并不是快就是绝对的好,快但是在错误的方向蒙眼狂奔,也是一种悲哀。

而对于传统的To B 的行业软件领域,虽然可能增长没有那么快,但由于需求明确、变化少,更多是自己在行业当中的经验的产品化,则不需要那么快的迭代速度 —— 毕竟你的用户不会迭代那么快。在这样的行业当中,你待的时间越久,积累的行业 Know How 越多,自然竞争力也就越强。

选择一个适合你的领域,提升自己在领域的竞争力,才是无惧 35 岁裁员的唯一手段。

一个支持 ES3 环境的 querystring

text

相比于使用 Uniapp / Taro 之类的,我其实更喜欢使用小程序的原生来进行开发。主要是减少中间商赚差价,性能损耗更少一些。当然,也少了不少好用的体验 —— 比如随便引入 NPM 包,好在是现在的小程序开发者工具也提供了 NPM 构建的能力,所以一些基本的使用是没有问题的。

不过,小程序本身环境的特殊性,我在使用 NPM 包的时候还是会有一些谨慎的 —— 要选择尽可能小的、不受平台依赖的包,来缩小小程序的包。所以当我发现一个可以在小程序中使用的包的时候,我就会将其写下来, 以备不时之需。

在涉及到 Web 开发时,一个比较常见的场景是构建 HTTP 中的 QueryString,以便在发送 GET 请求时传递参数。但自己手拼参数还是比较痛苦的,所以用一些 package ,可以有效的提升开发的体验。

TL;DR

你可以在小程序环境中使用 <a href="https://www.npmjs.com/package/querystring-es3">querystring-es3</a> 来进行 querystring 的构建,包的体积不大,可以达到比较好的效果。

const { encode } = require('querystring-es3')

encode({
  page:1,
  pageSize: 10
})
// return 'page=1&pageSize=10'
Code language: JavaScript (javascript)

为什么不是 qs

querystring 的处理包当中,比较出名的除了 node 内置的 querystring 之外,应该就是 qs 了,但实际在使用过程中,小程序的静态分析依赖了 qs,导致开发者使用时要么关闭提醒,要么换包。考虑到我还是希望使用小程序的静态分析,所以就只能替换包了。

待解决问题

  • 实际上我使用 querystring-es3 主要是看到他写的 ES3 compat,但可能其实我可以直接用 query-string ? 需要验证一下。

用小米电视看电影,感觉挺好

flat screen TV

去年买了小米的电视,但一直都闲置在那里,没怎么看。毕竟对于我来说,电脑是一个更加高频度使用的设备,完全没有怎么看过电视。

但过去一年里,没有什么文娱活动,更多都是刷抖音,刷信息流,时间被大量的消耗。在跨年的时候,突发奇想,我是不是可以把电视抱到卧室,在睡前看看电影啥的,毕竟我一直想看电影,但说实话,疫情的原因,让人不太敢和别人在一个密闭空间待两个小时。

说干就干,我把电视抱到卧室,开始用小米电视看电影。

4d2dbe4e85752e901e7446f4570ff4ea
临时搭的架子来看电视

配置好之后,两三天里,我看了好几部之前想看,但没有看的电影 —— 《十万个冷笑话》、《坏蛋联盟》、《小黄人大眼萌 2 :神偷奶爸前传》。

目前我觉得比较好的有:

  1. 我买了小米的电视会员,可以免费看很多电影,这个我很喜欢。虽然部分的影片是需要付费的,但绝大多数是可以免费看。
  2. 更新的很快:小米的影视库资料还行,我想看到的基本都有

不太好的点

  1. 之前我买电视的时候,没怎么花钱,甚至还不如我在用的显示器贵,所以画质很一般、也很容易卡。后续买电视还是要买个更好的品质的。
  2. 无线的网络不太行:毕竟租房,不太好接线,所以看高清的视频就会容易卡,以后自己买房的时候,还是要接网线。

结合小米的广告的尿性,我感觉后续我的最好的方案是一个比较好的传统电视 + 一个电视盒子,这样体验会好点。 Apple TV 买起来!

学会用巧劲,做选择

d2b5ca33bd970f64a6301fa75ae2eb22 3

如果说,一个人最重要的是什么,那便是判断力。有了判断力,做事便有了轻重缓急,有了不同的资源调配。

d2b5ca33bd970f64a6301fa75ae2eb22 3

大部分人终其一生,不做选择,而是随大流,别人做什么,我也做什么。这样带来的结果是终其一生,如浮萍跟随时代和他人的步伐,飘摇不定。

想要摆脱这种不确定性,拥抱确定性,则需要学会做出选择,做那些重要的事情,达成自己的目标。

技术文章格式

MacBook Pro near white open book

在查看一些技术文章的时候,看到一个不错的技术文章的范式,记录一下,这样后续我的技术文章也可以写的更有价值一些,而不仅仅是一个笔记。

以下内容为对应的范式和我的批注。

结构

  1. 简要的 Intro:介绍你在做什么、遇到了什么问题。
  2. tl;dr :总有人不想看长文,对他们友好一些
  3. 目标 + 结果:明确目标既可以帮你明确写作的目标,也可以框定问题的范围
  4. Shortcuts taken :可以快速带走的 intro,也可以理解为是 tldr 的内容
  5. 发现问题、解决问题的过程
  6. 结果
  7. 待解决的问题:在这个过程中你可能会有很多的新问题,可以记录下来,以后慢慢研究

2022 年 12 月月度总结

summary

今年的最后一个月,到了尘埃落定的时刻,也到了一年的总结时刻。今年的一年,是毫无收获,躺平的一年。。。

Objective 1:持续获取现金流,并构建未来收益的现金牛

KR1:投资收益达到 20000 元

12月市场开始回暖,我的基金也开始回暖。终于算是回归了本金。今年的投资收益非常的惨淡,一方面有市场的因素,另一方面,我认为我的 KR 本身有问题。这个到年终总结再讨论吧。

KR2 :单篇稿费突破 6000 元

无变化

KR3 :达成年度预算,支出不超预算

没出门, 也就没超预算。不过这个月有一些紧急支出(指阳了以后,买了大量的储备物资,现在还没吃完。。)

KR4 :构建软件类现金牛业务,预期产生收益 10000 元人民币

暂无进展

Objective 2:提升生活基础设施,构建未来生活好基础

KR1:前往 6 个城市旅行

这个月没有出去玩。。

KR2:进行 20 次文娱活动

没有进行文娱活动。

KR3:借助智能化设备,缩减在家务相关事务上耗费的时间

这个月没有啥变化。

Objective 3 :开拓视野,打造多元行业人才

KR1:写 15 篇书评

暂无进展

KR2:输出关于 API 的 Newsletter 12 封

12月份起草了两篇文章的大纲,但没有写成正式的文章。

KR3 :完成计划中的三本图书的写作

暂无进展。

几个 Swagger UI 的替代品

black and silver laptop computer

Swagger 算是 Code 2 Doc 的默认选项了,各种语言都提供了生成工具,此外官方还提供了一套方便使用的默认 GUI。

d2b5ca33bd970f64a6301fa75ae2eb22 36

不过,Swagger UI 本身其实并不够好用,所以社区就会提供一些 Swagger UI 的替代品,方便大家使用。

ReDoc

ReDoc 是一个前端的开源项目,在 Github 上拥有超过 1W + 的 Star。对我来说,我觉得他最好的点是左中右三栏模式,左侧切换 API,中间查看 API 详情,右侧查看接口调用的 Sample,比 Swagger 官方的 UI 瀑布式的要舒服。

d2b5ca33bd970f64a6301fa75ae2eb22 37

Angular Swagger UI

Angular Swagger UI 同样是一个开源的项目,界面简洁明了,虽然是瀑布式布局,但由于在界面上更加简洁,所以同样可以在同样的屏幕中,获取到更多的信息。

d2b5ca33bd970f64a6301fa75ae2eb22 38

使用 Taro 的一些小配置

text

我自己在使用 Taro 开发小程序的时候,一定会开启的两个配置:

1. 开启压缩

Taro 在预览模式生成的文档比较大,对于小程序的预览来说,不是很友好,所以开发的时候,我经常会打开压缩,以便于在小程序开发者工具进行预览。

修改也比较简单,只需要在你的 package.json 当中加入对应的环境变量 NODE_ENV=production 来支持即可。

diff 见下

d2b5ca33bd970f64a6301fa75ae2eb22 34

2. 开启 webpack 持久化缓存

Taro 可以开启 webpack 的持久化缓存,以便加速 webpack 的构建速度,因此我也会开启这个配置,以提升构建的速度。

d2b5ca33bd970f64a6301fa75ae2eb22 35

《小镇金融学》书摘

d2b5ca33bd970f64a6301fa75ae2eb22 33

Comments

这本书总体和之前看到过什么小岛经济学之类的风格很像,虚构一个环境,并在这个环境中演绎金融学,可以读一读,对于我们所熟悉的金融机构有一些了解。内容总体来说比较薄。

第1章 画中蓬莱

  • 请不要憎恨贪婪与恐惧,恐惧和贪婪是金融市场的永动机,波动的成因无一不是贪婪和恐惧。金融市场以贪婪而始、以恐惧而终,在繁荣与萧条中往复循环。金融市场的魅力恰恰就在于此,没有波动的市场又有什么意义呢

远方即财富

  • 贸易是人类历史上所有重大创新的原动力,有分工才会有贸易,有专业化才会有贸易,贸易确实没有创造什么,但贸易本身就是一种重大的创新。商品从一个人手中流转到另一个人手中,就是因为自己创造不出来(或者创造不划算)。

银钱之行,故曰“银行”

  • “模糊面纱”原则又称“无知之幕”,只有当缔约各方都对未来无知状态时制定的游戏规则才合乎公平。在小镇的故事里,没有人知道未来会是怎样的,只有以最公平的手段保护和惩罚所有人才能确保自己最大限度得到保护,虽然结果不一定公平,但过程肯定公正。

第3章 金融的本性

  • 供给会自行创造需求,这是萨伊定律的结论。

卿本佳人:房地产的金融属性

  • 看着若有所思的轩辕启恒,长孙东阳长叹了一声:“三生三世枕上书,可对现世来说还是那句话,最重要的永远是当下,这才是‘理性’本质,才是俗人的本心。”
  • 一般来说,只要一种商品可以短时间内暴涨(学名“做多”),就具备了最基本的金融属性。在这里我们暂时不考虑暴跌的情况,在金融理论中确实有个名词叫“做空”,也就是赌价格下跌。微观层面确实有人通过“做空”盈利,危机爆发也是因为有人故意“做空”,但这些都是建立在已经有人“做多”(赌价格上涨)的基础上。实际上,宏观层面的“做空”是一个伪概念,打压价格不可能吸引全民投身炒作,毕竟绝大多数人都通过价格上涨才能获利

第5章 走出洪荒

  • 商业银行最基本的原理非常简单,便宜借储户的钱,以更高的价格借给贷款者,金钱高买低卖的商业版本罢了

回不去的从前

  • 通常情况下买房的资金杠杆比率为1∶3—1∶5,也就是说,房价只需要上涨10%,投资者就能赚取30—50%的收益。同样的资金量投入,杠杆可以成倍扩大收益率,当然,也会成倍扩大损失。投资者没有不贪婪的,这是人的本性之一,所以,房地产将永远是投机者的天堂,昨天是,今天是,明天也是

盛衰循环的辩论

  • 经济繁荣的根本原因是大创新,不是货币扩张;同理,经济萧条的根本原因是创新带来的刺激衰减,不是货币收缩,从繁荣到危机不过是将整个过程以金融的方式记录下来罢了。
  • 改变世界的创新在当代经济学中被称为“毁灭型创新”,所谓“毁灭”必定是开天辟地,以新产业毁灭旧产业。新产业必然创造巨大的利润,并对应融资方式的改变,也就是金融革命配合产业革命。金融革命一旦出现,人们便能轻易获得资金,其后模仿者蜂拥而至,投资新产业、投资新产品……“毁灭型创新”注定改变了人类社会生活,工业革命、电气革命、信息技术无不如此。
  • 任何一次“毁灭型创新”都有相似的历程,创新开始的时候会生产奢侈品,随着创新延续成本逐渐降低,普及到草根大众的时候,创新使命就基本结束了

投资银行:人类第二次资金大融合

  • 只有能赚钱的技术才是真正的好技术,也只有实现商业化才能普惠于万众生灵
  • 在金融市场上,如果大家都这么认为,那这件事就一定会发生,这就是所谓的“预期自我强化”
  • 人类第二次资金大融合实现了产业链中的资金流动,造就了投资银行,也对美国经济转型与发展起到了巨大的推动作用。当时投资银行主导的并购中,目标企业拥有互补性资源,注重研发和创新,着力整合各方资源。一旦在大部分行业完成了上下游企业并购,美国工业结构便出现了永久性的变化,国民经济集中化程度空前提高,伴随而来的则是规模效益和垄断利润

再造辉煌

  • 一切的关键,是创新。一次“毁灭型创新”代表着出现一个新的产业,新的产业又代表着形成一个全新的利益格局、一个创新者主导的利益格局。打破一个旧世界,建设一个新世界!旧有利益格局一旦被打破,创新者就会成为新世界的主宰。在创新的路径中,银钱业始终为创新提供了充足的燃料——钱,资本从一个天才转向另一个天才,从一个产业转向另一个产业。只要能在经济分工中掌握最核心的创新,就一定能找到世界上最强大的资金,资金每日梦想着寻找更高的报酬

开发者文档的三种内容层次:字典、概览和教程

APILetter

不知道,你有没有关注过开发者文档的信息结构。下图是 Google Docs 的 API 文档。

89ug0i

在菜单中 Google Docs 提供了 Home、Guides、Reference、Samples、Support。你有没有想过,这些内容为什么如何设计?在我看来,这是开发者文档内容的三种层次。

第一层:解决有没有的问题

典型代表:API Reference

绝大多数开放平台也好,To Developer 产品也罢,首先要解决的问题是让开发者知道我有什么样的能力。而最简单、最直接最高效的方式,便是 API Reference。

各大产品在进行对外开放时,首先准备的便是一套 API Reference。在 API Reference 当中,你可以看到开发者应该如何调用一个 API;某个 API 的入参是什么、出参是什么;如果出现了失败,应该如何处理这些错误。

当一个 API Reference 为开发者提供了简洁、明确、易懂的文档内容之后,开发者基本就可以准备开始进入开发流程了。

Opinionated Notes:RESTFul API 的 API Reference 理论上不应该存在多层级的资源关系。

优秀的 API Reference 参考:

第二层:解决怎么用的问题

典型代表:API Overview、单个业务领域的 API Guides & API Tutorial

作为开放平台,当完成了 API Reference 之后,便算是及格了。但及格不应该是目标,目标应当是卓越。抵达卓越,则需要更多内容的帮助。

API Reference 回答了「能用什么」的问题,但没有解决「如何使用 API」的问题,特别是复杂的业务场景下,同一个业务内可能会需要多个不同的资源来进行 API 的操作,这个时候,如何使用这些资源,并将这些资源包装、关联起来,就成为极具业务属性的 Know How 知识。

举个例子来说,以服务端 OpenAPI 为例,日历的资源就涉及到用户、日历、日程、会议室、参会人、权限管控等多个不同的资源,如何串联这些 API 才能达成你的业务目标,就成为一个非常重要的说明。对于日历的能力熟悉的开发者可能很快就可以找到调通的方式,但对于不够熟悉的,这些 API 之间的串联,可能需要他花费一天,甚至一周的时间才能真正理解背后的含义。如果想要降低开发者调通过个 API 的时间,那么介绍这些不同 API 之间的关系,其在业务系统之中的含义就尤为重要。

如果你对于服务端的 API 感触不深,那么客户端的 API 可能会让你感受更加深刻,以微信小程序的中的蓝牙设备开发为例,如果你作为一个从未开发过蓝牙能力的开发者,看到了蓝牙提供的这一系列 API,只怕马上头皮发麻,需要每一个都看一遍才能理解其含义和价值;在蓝牙这件事上阻塞个半周一周也是常态。

d2b5ca33bd970f64a6301fa75ae2eb22 31

一个好的 API Guide / Tutorial 可以有效的降低开发者在调试这些 API 过程中所耗费的时间。当然,微信也意识到了这个问题,提供了一套非常好的 API 说明

优秀的 Tutorials 参考

第三层:解决场景化使用的问题

典型案例:Code Sample,Demo App,场景化的使用教程

API Tutorials 可以解决的是面向场景化的单个领域的内容。它帮助开发者很好的解决了一个领域内的产品能力的串联。但在实际的业务场景当中,开发者面对的不是已经拆解到 API 粒度的任务,而是面向场景设计的不同问题。对于开发者来说,把场景拆分成 X 个 API 并没那么容易(特别是如果经验不足的时候),因此,一套标准的 Code Sample ,甚至是 Demo App ,都可以帮助开发者快速解决面向场景化的问题。它可能涉及到了客户端、服务端,或者是面向了多个不同的领域。这些内容帮助开发者可以快速 landing。

以飞书开放平台为例,飞书开放平台在开发教程里提供了多个领域、不同方向的场景化教程(虽然还不够多,远远不够),帮助开发者快速完成某个特定领域的功能的开发。

d2b5ca33bd970f64a6301fa75ae2eb22 32

这些内容可能未必能完全满足开发者的需求,但确实可以给开发者一定的借鉴意义,帮助开发者理解整个业务流程和对应场景下的具体的实现,帮助开发者快速完成业务需求。

第三层之后,应该是什么?

前面三层解决了有什么、怎么用的问题,而在整个应用的生命周期当中,怎么用并不是终极问题。下一步需要解决的是如何用好的问题。不过这个问题不在本次阐述的内容当中,所以我们留一个悬念,下次再说。

 衡量 API 设计质量的指标 — TTFC/TTFHW

APILetter

任何一个开放平台类产品,要解决的问题都是如何在现有的平台能力之上,开放一些能力给到第三方开发者,帮助第三方开发者开发应用,拓展体验,如果我们可以降低开发者在完成开放能力接入所需的时间,我们就可以让开发者有更多的时间去构建属于自己的业务逻辑,拓展平台之上的应用生态和开发者体验。

API 的设计质量、文档质量和错误处理信息的质量可以非常明显的影响到 API 的使用体验。但这些体验却很难通过我们在软件工程领域所使用的各种性能指标来衡量。我们可以通过一些专业的、对于 API 有判断能力的人来完成对于 API 质量的评估和优化的引导,但这件事并不利于持续发展和长期迭代。我们需要一个靠谱的指标,来引导我们持续性的、规模化的进行 API 本身的优化和迭代。

上图为 readme.com 提供的 TTFC 介绍

在这个问题上,Slack 给出了自己的答案 —— Time to First Hello World(TTFHW), API 服务提供商 readme.com 则提出了一个类似的概念 Time to First Call(TTFC)。

TTFC/TTFHW 为什么是一个好的指标?

在 TTFC 之前,我相信你或多或少都试过对自己的 API 进行统计和分析。你可能会基于技术工程指标来判断 API 的好与坏;进一步则会通过一些反馈的能力来完成(比如划词反馈、点赞点踩反馈)数据的收集和进一步的分析,你可能会将这些数据进行加权分析,从而得出一个质量评分,用于判断一个 API 的好与坏。

表面上来看,他可以帮助你发现你的 API 当中的不好的点,你可以基于开发者的反馈来快速对 API 当中的一些问题来进行修复,从而提升开发者的开发体验。但这个指标的一个缺点是:它是一个负向反馈的指标。作为 API 的提供者,你拿到这些反馈的时候,它可能已经早已影响了你的大多数开发者,甚至早已令你的开发者十分不快而你却从不知道。不仅如此,如果你的开发者们并不喜欢反馈,你的 API 的问题可能永远都不会暴露出来。

TTFC/TTFHW 如其名所述,记录的是一个开发者第一次调用所需要时长,你可以根据你自己的需要,来设定开发者行为的起点。而终点,则是开发者成功发起一次调用。

相比于需要开发者主动反馈所进行的数据收集,TTFC/TTFHW 的指标不需要开发者做什么,我们可以通过一些技术手段来完成这些信息的收集,从而在第一天开始收集数据。你不需要等自己的 API 有很多开发者之后才能开始进行数据的收集和反馈,只要设计合适的埋点,从 Day 1 就可以获取数据,并基于数据来分析指标和下一步优化的方案。

如何建设 TTFC/TTFHW

TTFC 和 TTFHW 的指标在实际的建设过程中并不容易。其中最大的问题是如何将开发者的行为和实际的调用进行关联。如果你的 API 在前端就可以发生调用,且能够在前端直接调用,还算是简单,可以通过简单的前端埋点来完成数据的建设,并配合开发者在网站上行为的埋点,来分析出具体的 TTFC / TTFHW。

而对于一些服务端的 API,则需要花费更多的心力来建立这些数据,你可能需要将开发者在网站上的行为和其对应的在 API 上的行为进行串联,从而形成一个完整的开发者图景。在最理想的情况下,你的统计系统和你的 API 网关系统上是可以打通的,你可以非常简单的将开发者在网站上的行为与发生在 API 网关系统上的行为进行串联,从而形成一整个从开发者进入网站到开发者了解 API 设计再到开发者真实发生 API 调用当中来完成。

不过,这件事在某些支持以应用身份来调用 API 的开放平台当中来说,就是比较困难的了。因为发生调用的最小单位是应用,而不是某一个人。但也并非绝对无解,你同样可以基于某些指标来圈选一部分开发者,并将这些开发者和实际网关当中产生调用的接口进行串联分析,得出开发者的实际的调用时长。

如何使用 TTFC / TTFHW

当你通过艰辛的数据埋点、数据收集、数据入仓之后,便可以进行数据分析,使用这些数据了。这里分享两个使用这些数据的思路,供你参考。

TTFC/TTFHW 的数据可以从整体数据视角和局部数据视角查看。

当你作为整体数据来查看时,你所拿到的是一个开发者完成整体调用所需的时长。你可以基于开发者的行为,来计算出开发者的 TTFC 所需的时长,和他进入到转化漏斗当中下一步所需的时间,并分析不同时长人群在实际转化率上的差异值,对比这些差异值,并得出判断和下一步的 Action ,优化你的 API 产品的实际体验,提升产品转化率。

上图为 moesif 提供的 TTFC 转化分析图表

当你作为局部数据来查看时,你可以将 TTFC/TTFHW 拆分成若干个不同的阶段,比如网站访问、查找文档、了解鉴权信息、阅读 API 文档、实际发生调用等多个阶段,并对这几个部分的耗时进行分析,从而得出一些定向优化的 Action ,来优化整个网站和 API 的质量,帮助开发者降低调用所需耗费的时长。

建设 TTFC / TTFHW 数据指标的一些建议

在建设 TTFC / TTFHW 的过程中,如果你遇到了困难,不妨试试如下的方式:

  1. 为你的服务端 API 提供一套在线的调试工具,从而让开发者可以在看文档的时候直接调用接口,测试效果。
  2. 如果你的 API 支持以开发者的身份调用,可以试着使用 OAuth 协议,让开发者在看文档的时候直接授权发起调用,并在调用成功之后给出相应的代码的生成。

一个可互动(Interactive)的文档,可以帮助你有效的降低 TTFC/TTFHW。

当然,除了产品本身的优化,你还可以试着提供更多的开发者教程、示例代码,来降低开发者调用你所提供的 API 的难度,优化开发者的体验。

为什么开放平台大多选择了 RESTful 风格?

APILetter

大型互联网平台会提供一些开放平台,并提供一定的开放能力,帮助开发者基于自己的平台进行二次开发,拓展平台之上的应用生态。而在这些开放平台当中,最常见的便是采用 RESTful 风格的开放平台,比如 GitHubMicrosoftGoogleTwitterStackOverflow

如果说用一个偷懒的想法,那我们可以得出一个结论 —— RESTful 一定做对了什么,不然不会这么多平台都愿意选择它。

考虑到我们的 Newsletter 是一个面向开发者、To Dev 业务的产品经理的邮件,就不再详细介绍 RESTful 是什么,如果你感兴趣,可以去看看 Fielding R T. Architectural styles and the design of network-based software architectures[M]. University of California, Irvine, 2000 这篇论文。国内的技术劳模阮一峰老师也有一篇文章阐述 RESTful 架构:理解RESTful架构

如果用一句话来描述 RESTful 风格做对了什么?我想它应该是「RESTful 风格的 API 通过将方法抽象回资源,面向资源提供操作的方式,简化了 API 的设计,减少使用 API 所需要的上下文,用最简单的方法为我们提供了各种各样不同的操作的可能。」

举个🌰

个简单的对比的理解,以创建一篇博客文章为例,我们所熟悉的 Internal API (应用内部的 API,没有特定的风格)和 RESTful API 的区别如下:

Internal API 下的创建文章

POST /create-post

{
  "title":"xxx",
  "content":"xxx"
}

RESTful API 下的创建文章

POST /posts

{
  "title":"xxx",
  "content":"xxx"
}

看起来,好像也没什么不同,啊哈?那我们再看看根据 ID 获取文章的区别:

Internal API 下的根据 ID 获取文章

POST /get-post-by-id

{
  "id":123
}

RESTful API 下的根据 ID 获取文章

GET /posts/123

{
}

看获取文章,似乎有那么点意思了,显然,我们所习惯使用的 Internal API 比 RESTFul API 的风格的路径更长,也更喜欢用 POST。当然,这也完全可以接受。我们可以再举个例子,既然有根据 ID 获取文章,是不是还可以根据标题来获取文章:

Internal API 下的根据标题获取文章

POST /get-post-by-title

{
  "title":"xxx"
}

RESTful API 下的根据标题获取文章

GET /posts/?title=xxx

{}

你可以看到, 在 Internal API 当中,我们为了提供获取标题的方式,不得不又写了一个新的路径,一个新的方法,来实现类似的功能。而在 RESTful 当中,我们只是在创建文章的路径当中,提供了一个不同的 Query Param,来完成查询。

实际上,如果我们的文章提供了不同的参数,我们又要针对这个文章提供各种不同类型的搜索条件(相信你肯定在各种中后台管理系统当中看到各种各样的筛选器),在 RESTful API 当中,你只需要在同一个路径上叠加不同的 Query Param 即可,而在传统的 Internal API 当中,你可能需要设计不同的方法来实现。

为开发者省时间的 RESTful 风格

RESTful 风格的 API 不再面向具体的操作来设计,而是将具体的操作抽象为不同的资源和对应的资源的操作,来降低开发者实际在使用这些 API 的成本。

在 RESTful 风格下,一个开发者唯一知道的,便是资源的命名,剩下的便都是交给 RESTful 风格的规范来完成的。

  • 如果开发者知道对应的资源是叫 User,那么他就知道获取所有用户使用 GET /users,获取某个用户就是 GET /users/ID,创建用户就是 POST /users,删除一个用户使用DELETE /users/ID。
  • 类似的,如果他需要操作邮件的对象,则是把 URL 当中的 users 替换为emails,仅此而已。

开发者不需要每次打开文档去猜测 API 到底是 camelCase 、snake_case、PascalCase 还是 kebab-case,也无需猜测每个 API 应该使用什么 HTTP 方法发出请求,开发者只需要遵循 RESTful 规范去请求接口即可。

为平台方省设计的 RESTful 风格

对于服务提供来说,RESTFul 风格也提供了简化设计的可能。举个例子来说,假设我们有一个相对比较复杂的用户数据,如果开发者不能很好的抽象,带来的可能是一系列复杂的接口,让我们的维护成本疯狂提升。随着数据结构本身的复杂,要实现、维护的接口的数量也在不断的增多,需要投入的人力也不断的变多。

举个例子来说,假设我们的平台上有一个 User 对象,他的结构如下面的 JSON 所示:

{
  "id":1, // ID
  "name":"张三", // 姓名
  "nick_name":"小张", // 昵称
  "former_name":"张老三", // 曾用名
  "login":"zhangsan2022", // slug
  "i18n_names": {
     "en":"Sam Zhang" // 英文名
  },
  "blog":"http://example.com" //个人博客
}

由于使用开放平台的用户可能在开放平台上有各种各样不同的用法和操作,所以我们可能需要为用户提供一系列的方法,来帮助用户实现不同目的下的数据查询。你可能不得不提供一系列的 API:

  • GetUserById
  • GetUserByName
  • GetUserByNickName
  • GetUserByFormerName
  • GetUserByLogin
  • GetUserByBlog

而同样的问题,放在 RESTful API 当中,只需要一个 /users? 就可以完成了,剩下的便是在 Query Param 当中去叠加各种不同的判断规则,简单但直接。对于一个开放平台来说, RESTful 风格将过去可能需要用 N 个方法才能实现的方式收拢成一个方法,大大降低了持续维护的成本。

不严谨的的 RESTful 风格

说了那么多 RESTFul 风格的好处,也来说一说 RESTful 风格的坏处。

  1. 没有明确的规范,只有一个指导思想:RESTful 风格的提出者 Roy Thomas Fielding 在自己的博士论文Fielding R T. Architectural styles and the design of network-based software architectures[M]. University of California, Irvine, 2000.当中提出了 RESTful 风格的设计,但并未详细的指明具体的设计细节,所以对于实际落实到工业生产环境过程中,往往会衍生出不同的风格,比如 Google 的 RESTful API 规范和 Microsoft 的 RESTful API 规范就并不相同。他 2008 年写的一篇文章轻描淡写的说自己当时没写细则是因为没时间了。但论文发表了 8 年时间,也没见写第二篇论文解释细则。。。
  2. 对于资源的抽象要求非常高,很容易抽象错:RESTful 风格看起来是否简单,面向资源设计是个人就行。但落实到实际应用场景中,就没这么容易了。
    1. 一个最容易引发讨论的点便是:如何表现出数据结构之间的关系?常见的做法是在路径里展示出关系,比如用户的文章是 /users/1/posts ,但在 Roy 2008 年的文章《REST APIs Must be hypertext-drivern》当中给出的答案是,应该抽象出一个更高层的资源来完成这个筛选,路径中不应该包含关系。
    2. 另一个容易引发讨论的点是批量操作:你如何设定一个批量操作?比如批量创建用户,或者是批量发送消息?你可能会单独设计出一个 /message/batch_send 的方法,但在 Roy 2008 年的文章《REST APIs Must be hypertext-drivern》当中给出的答案是,你应该设计一个全新的资源抽象,来确保整个 API 架构是稳定、一致的。

选择 RESTful 风格,归根还是省钱

RESTFul 风格的好处和坏处都很明显 —— 好处是他提供了简化的实现,统一的表现,最小惊讶原则的落实,让开发者只需要知道资源的信息,便可以进行具体的操作,而无需担心众多的 API 存在各种不同的设计风格和设计实现。开发者需要自行编写 SDK 来完成各种不同的操作。毕竟,RESTful 本身就是基础的 HTTP 操作。

而作为一个已经提出了 20 余年的 API 设计风格,RESTful 已经拥有了丰富的开发者共识(大部分开发者可能不熟悉 RESTful API ,但看到了,大多能猜到是 RESTful 风格,也能用起来 RESTful 风格的 API )、抽象也更统一(RESTful 虽然没定义特别多细节,但一些基础的逻辑也是定义了的,比如 URL 里不能包含动词),对于开放平台这样需要大规模的和外部开发者交互的平台来说,无疑是成本更低的。

评语

RESTful 风格有着其明确的优势,但同样,他的劣势(定义不明确、抽象要求高)使得大部分我们所见的的 RESTful 风格都不那么 RESTful(也并没有人能定义谁更 RESTful),更重要的是,RESTful 的使用体验,并不一定真的就比 Internal API 更好。很多时候,它只是一种无奈的选择。

而未来,能够提供更加丰富的组合能力的 GraphQL ,可能是一个选择。不过,想要做好 GraphQL,你要先做好基础的 RESTful 资源抽象,才好在真正进入 GraphQL 的时代,快速发展。

下一轮增长在哪里?

growth

回顾 2022 ,我们看到了经济的不断在下行(不只是国内的经济下行,国外的经济也没好到哪里去,美股也在跌)。

一方面,我们可以将其归因为疫情 —— 疫情的出现使得国际之间的交流变得困难,开始出现了逆国际化的潮流,大家开始只为本国的产品消费。

另一方面,我们也应该关注到,这一次的下行,很有可能是创新的缺失 —— 任何创新都有其增值周期,上一次的创新的增长,来自于互联网。千禧年代,我们遭受了千年虫的冲击,但也带来了一波互联网发展。而这一波发展持续了 20 年,我们也得到了 20 年的高速增长。

如今互联网已经难以提供新的增长点了 —— 能够联网的已经都连的差不多了(物联网、车联网)、能够上网的人也都上的差不多了(现在的小朋友们可能都不一定会玩电脑,但一定会玩手机、iPad)。

互联网已经没有什么太多的增长点了。我们的经济,也就自然而然的进入萧条的时期。想要让我们的生活重回一个高速增长的时代,需要一个新的增长点。

我不知道这个增长点在哪里。不过,我们唯一能做的,便是积累那些能够跨越周期,穿越牛熊的能力 —— 写作、演讲、学习、创新的能力,永不过时。

该来的新冠阳性,还是来了

病毒
d2b5ca33bd970f64a6301fa75ae2eb22 30
抗原阳性

终究,我还是感染了新冠病毒阳性。

前奏

我的感染并不是一个孤例,女朋友先我一步感染新冠病毒阳性,我感染时她已经阳性反应一天有余。不过也合理,毕竟我们的这种生活环境,无法做到绝对意义上的隔离,就算人隔离了,猫也会到处溜达,我的感染,不过是早晚问题。

回顾我们两个人的生活方式 —— 深居简出,一切采购物品全靠网购。我们的暴露点不多,仔细想想,大概率是我们下楼取快递时,快递点的工作人员未戴口罩,将病毒传递给了我们,导致我们最终感染新冠病毒。

预备

不过,既然已经感染,倒是也没有什么必要去追责,没有意义。于我而言,最重要的是让自己快速恢复。得益于山姆会员店和 JD 的 211 限时达,我成功的采购了一批必备物资

  • 足量的速食食品:方便面、牛肉卷、鸡蛋、番茄、橙子;
  • 足量的电解质水:买了两箱宝矿力

以及之前因为骨折,粒粒姐送给我的一瓶布洛芬(还有 400 多粒,救急了!)。

考虑到我之前已经完成了三针疫苗的接种,甚至我的第三针就是在 12 月初接种的,我应该是问题不大,准备好这些物资,就开始准备硬扛新冠病毒了。

病程

可能是得益于疫苗 / 病毒毒力下降 / 个人身体素质还凑合,我的新冠病程并不长,第一天头晕难受;第二天继续头晕睡了一天;第三天体温恢复正常,但嗓子开始吞刀片;第四天体温和嗓子差不多都恢复了;第五天就一切正常了。

不到一周,我的身体恢复的差不多,病程中是几乎没有什么影响。

愈后

虽然新冠病毒对我来说,并不是很痛的病,但说实话,依然令人担心。在新冠病毒感染康复之后,我的身体虽然几乎没有影响,但依然不敢运动(毕竟有心肌炎的各种先例),但也没感觉哪里有不舒服。

倒是后续我喝了一杯咖啡,才发现新冠病毒的厉害 —— 以往咖啡对我来说,几乎是没有太多的效果,我一天能喝个六七杯美式。然而康复之后,一杯美式,让我一个下午都心慌慌,不敢再喝咖啡。

直到康复后的两周,我才算是能够喝一些咖啡了。

总结

新冠病毒从我的个人体验来说,还可以接受(毕竟是已经毒性减缓了很多轮的奥密克戎了),但依然不是一个好受的病,不是简单的躺着休息就可以的。而更重要的是,奥密克戎将长存的事情,令我们每个人忧心忡忡。

今天的我可以抵抗奥密克戎,明天、明年、后年的我,是否还能抵抗的住新的变种?这是个问题。

天津日常

d2b5ca33bd970f64a6301fa75ae2eb22 28

以下是我来天津以后拍的一些照片~

我住的位置是在河北区靠河的位置,租了一个高层,视野非常好,夕阳的时候可以看到红桥区的灯光点点

d2b5ca33bd970f64a6301fa75ae2eb22 28
夕阳

随着天气渐冷,旁边的河也开始上冻了,可以看到有人时不时的在上面行走。

d2b5ca33bd970f64a6301fa75ae2eb22 29
冰上行走

后来,禁不住诱惑,我也自己下去冰上走了走,很爽。北方孩子的快乐。

ab66cdf92040a36cee4dbe79bf9b2c42
结结实实的冰

不过,我因为体重比较大,还是不太敢在冰上行走,看到远处滑冰的人,还是挺羡慕的。

c4e988080bd4f3d8d65e0c197390b495
滑冰的人

当然,有滑冰的人,也少不了钓鱼的人

9d913cbfb1085759c1fd5b53a5162621
凿冰钓鱼

广度优先探店和深度优先探店

cooked dish on gray bowl

来到天津以后,我和女朋友开始了新一轮的探店,之前熟悉的店铺已经没有了,只能逐渐去探索新的好吃的、好玩的。在探索的过程中,我发现女朋友和我一个很大的不同:我们俩采用完全不同的算法来探店。

我用的是深度优先的算法来进行探店操作,具体的表现是我会在大众点评上发现一些看起来还不错的店铺,然后去试试看。如果发现这家店还不错,那么在下一次我想要外食的时候,就会继续选择这家店,直到我认为这家店中我感兴趣的东西已经的体验完了,则会结束对这家店的体验,转而体验下一家店。再次来这家店,可能就是日后和朋友一起去,不会再专门去体验。

女朋友则喜欢广度优先的算法来进行探店操作,具体的表现是我们会不断尝试新的店铺,期间如果发现了好吃的店铺,也不会再去,而是留着以后想去了再去。

对于我来说,我觉得深度优先可以让我深度的体验某一家店(特别是很多店铺如果不是在你的常驻地),广度优先的话,在你吃不了多少东西的前提下,你很有可能错过那些你感兴趣的菜。不过,广度优先对于一个全新的环境来说,也是一个不错的策略(比如旅游)。