推荐 「湾区日报广告投放」: 来湾区日报介绍你的产品。面向全球华人 makers,针对科技圈进步青年。湾区日报广告全面改版,多种形式可灵活挑选。

湾区日报是如何运作的?

2017/07/02 · 浏览量 47125 · 全部博文

Updated July 1, 2017:这篇文章第一版是2015年5月份写的,现在看来有点“过时”了。所以我决定每隔一段时间把这篇文章更新一次。


湾区日报是什么?

湾区日报是一个在旧金山工作的工程师运营的个人博客。该博客每天挑选5篇他主观认为高质量的文章,针对每篇文章拟一个中文标题写几句简单评论,通过10个渠道(网站iOS appAndroid app微博微信TwitterChrome 浏览器推送Facebook邮件订阅RSS)推荐给读者们。

写这篇文章的“我”就是这个工程师。湾区日报不是一个公司,也不是一个创业项目。只是我的一个 side project。从 2014年8月6日发第一期以后,运营至今。

看上去很简单,对吧?我一开始做的时候也觉得很简单,很没技术含量,任何有高中文凭具有简单电脑知识的人都能运营这种博客。但为什么同一道命题作文,每个人写的内容不一样,有人能写离题有人能写满分作文?为什么大家都会写字,有人“竟然”能成为作家并靠写字为生?

每天的内容是如何发出的?

我在每天利用零散时间发现新文章,然后直觉认为是好文章的就收藏在Pocket 里。发现新文章的渠道很多,排名不分先后:Hacker NewsMediumQuora,我订阅的很多博客的RSS,各种社交网络上看到的文章,头脑中突然对某个主题感兴趣临时搜来的文章,与同事交谈中得知的文章等。这篇博文列出了湾区日报文章的主要来源

我也利用白天的各种零散时间读一两篇文章。但一般都是晚上回家吃完晚饭后,再开始用完整的时间专心读。每天读的文章数量不一定,有时候一天读20几篇,勉强挑出5篇;有时候一天读了5篇,但都觉得很不错,就不读其他的了。这个过程一般要花1到3个钟头。

我一般用 iPad 读文章,然后多任务打开 Slack,在里面跟我的小机器人(wanqu-ops)对话,有点像程序员工作的时候敲命令行一样。我会告诉小机器人,这是一篇文章的链接,然后它会自动提取文章的标题,url的slug,图片等信息,最后插入到后台数据库;每5篇文章自动生成新的一期,自动生成当天的日期(北京时间)以及当天的期号(比如第502期)。总之,我只要把链接扔给这个小机器人,它就能帮我做这些繁琐的事情了 --一个普通网站的小编会怎么做?会用CMS,然后一项一项手动输入,这个过程不会花太多时间,可能每天十几分钟吧;但我实在太懒了,连每天花这十几分钟都不舍得。

下一步要写简评。我也是跟小机器人对话,比如 “wq post 2672 title 这是一篇好文章” ,就是告诉它:我要把编号 2672 的文章标题改成 “这是一篇好文章”。同理,可以录入文章简评等内容。下图是我在 iPad 上读文章然后用 Slack 写简评: 

 

凑足5篇文章后,我最后给小机器人下达命令:把这期的内容发出。然后它就自动把内容更新到网站,消息推送给 iOS app 与 Android app 的用户,自动发布到微博TwitterFacebook等社交平台。

总之,手动操作的部分主要是读文章与写简评。剩下的繁琐的操作,都是由程序自动完成的。同一道命题作文,程序员的写法是和普通网站小编不一样的;不同程序员的写法也会不同。

背后的技术

我为湾区日报这个 side project 写了一些代码。由于只是 side project,我对它的期望不高,力求用最简单的做法,花最少的时间,用最“快糙猛”的方法实现我想要的功能。

网站与后台架构

2014年8月份,湾区日报只是处于”闹着玩”的阶段,没有严肃要做的意思。所以那个时期的湾区日报网站只是一些静态网页,用 Pelican 生成的。

之后的网站换成了 Wordpress。换了几个不同的主题。甚至还花了些钱买了 Product Hunt 的主题。

到了2015年3月份的某个周末,我也不知道哪根筋接错了,就宅在家里一天,从头写了现在的这个网站。主要用 Python/Django,Celery,RabbitMQ,Postgres 以及 Redis 搭建的。

为什么用Django?为什么能在一天做一个网站?很简单,我在过去两三年(2013~2015)自己写了大大小小10几个 Web App,都是写着玩的 side project,都是用 Django/Postgres 搭建的,只是一个套路而已。将自己以前写的代码复制粘贴,当然可以很快拼凑一个网站出来了。况且,第一版的网站远比现在大家看到的这个网站简单得多;现在这个版本的网站是经过1年多时间不断改进的成果。

所有网站基本都能简化成这个架构:Web App,Datastore,Async Worker,Task Queue,以及 Scheduler。其中,Web App就是跑网站代码接受用户的访问请求,所有耗时间的 task(比如发邮件,发微博,数据统计等)都扔到 Task Queue上,然后 Async Worker 从 Task Queue 抓 task 过来离线处理;而 Scheduler 就是定时跑程序,很多网站直接用的 Cron。

对于湾区日报,Web App 就是 Django App,用 uwsgi 跑N个进程,用 supervisord 来管理进程,前面挂一个 nginx 当 load balancer。Database用的是 PostgresRedis  —  其中,大部分需要永久存储的数据都在Postgres中,而Redis存的是文章的访问数与一些只需保留一两天的数据。Task Queue是用 RabbitMQ。Scheduler用的是 Celery Beat。而Async Worker是 Celery。下图是湾区日报后台简单的架构: 

湾区日报的所有这些后台的大大小小20几个进程是跑在3台 DigitalOcean 的虚拟机上。按照访问量的增长速度,这样的架构估计至少可以支撑到 2020 年 -- 大家整天在科技媒体上看到每天动辄几百万几千万访问量,可能都忘了世界上大部分的网站其实访问量都非常非常少的吧。当然,我在这3台虚拟机上也跑了其他的 side project,也不算浪费计算资源。我自己还有一些简单的小项目放在Bluehost上,与别人共享主机(没有root权限),就是图个便宜(每月低于$5)。

iOS App

2015年5月份的时候,用了一个周末写了 iOS App。完完全全用 Swift 写的,很不错的体验。前面说了,这只是一个 side project,所以期望不高,我是可以厚着脸皮上线质量低劣的一个周末写的 app 的,反正也没什么人用,以后慢慢改进就是了。

后台的 Api 也是 Django App(抽象出一些通用的内部 api 与网站共用),也是跑了 个 uwsgi 进程然后用 nginx 做 load balancer。

在开发第一版 App 的那个周末,除了完成基本的功能(浏览文章)外,还加入:

  • Crash report(用 Crashlytics),第一时间通知我用户的 app crash 了,方便我调试;
  • Google Anlytics,监测用户使用 app 的情况,比如多少人在线,哪个页面比较多人访问,哪个按钮比较多人点击等;
  • Appirater,提醒那些使用了几次 App 的用户去 App Store 给个好评;
  • PSUpdateApp,提醒用户有新版本了,快及时更新。

这些都只是套路而已。尽管不是 iOS 开发人员,但至少要有这么一个意识。上线一个产品,最基本的东西都要有:收集 metrics,收集 crash 的信息,更新提醒等 --开始做 app 之前有跟同事打听了一下应该用哪些工具,少走了不少弯路。详见这篇博文:两天四夜上线一个 App

经过1年多(2015~2016)陆陆续续的改进,iOS app 也支持了夜间模式3D touch离线收藏夹与 Spotlight 搜索,加入微支付精选文章合集Universal links记住文章上次阅读位置首页加入 Infinite ScrolliCloud 同步收藏夹等功能。

Android App

2017年4月初开始动工,4月底上线。Android app 是用 React Native 写的,现在只实现了 iOS app 的功能的子集,还有很长的路要走。

React Native 学起来很容易,我也是今年以来刚学的。以后如果 Android app 的功能赶上了 iOS app,就可以只用 React Native 开发两个平台的 app 了。但由于历史原因,现在 Android 与 iOS app 是两个代码库、两个不同的语言(Javascript 与 Swift)。得尊重现实啊,一步一步来。

Android app 目前只放在了 Play Store 上,国内的读者如果不会翻墙、不会使用 Play Store 的话就没法下载了。尽管如此,Android app 的下载量的增长速度比 iOS app 当初刚上线时(2015年6月)要快不少,或许现在湾区日报的读者数量是当时的好几倍了、而且湾区日报读者大多会翻墙。

发布系统

湾区日报这个博客有很多推送的渠道。现代博客与10年前的博客不同:10年前的博客就是一个网站,而现代的博客形式多样,同一份内容会以不同的形式通过不同的渠道出现在读者面前。

前面介绍到我用 Slack 与机器人对话。这机器人就是 Hubot -- 它解析我发出的命令,然后调用我在 Django App 里提供的 REST api 发布文章;当文章的状态由 pending 变成 published后,将触发一些 Celery tasks;每个 task 负责一个渠道的发布任务,比如一个task发布到微博,一个task发布到reddit等。

微博:调用微博 api 发布。凡是微博的帖子底部有 “来自 湾区日报BayArea” 字样的,都是由发布系统自动发布的。 

 

微信:理论上,成为认证用户后,可以调用 api 自动发消息给订阅者们。但我没有成为认证用户,只能手动发布。Hubot会生成每期需要发布的文字,我只要复制粘贴就能发出消息了。对于微信,我基本是放弃了,完全不上心;因为湾区日报这种分享链接的模式很不适合在微信这种平台做。

Twitter:调用 Twitter 的 api 发布。Twitter 的 api 做得不错。

Facebook:调用 Facebook 的 Graph API 发布。

Reddit:调用 Reddit 的 api 发布的。难道有中文用户上 Reddit?我不确定。我只是把 Reddit 当作一种 SEO 的手段而已。

邮件订阅:用 MailChimp 自动读取 RSS,每天定时自动发布。

iOS App 推送:没什么好说的,就是 APNS。每隔2个钟头,会有一个 Celery Beat 的 job 清理掉那些已经失效的 device token(比如有用户关掉了 push notification 或者已经把湾区日报的 app 卸载了);这就是为什么打开消息推送的用户数字有时候会变小。定期清除失效的 device token 可以避免浪费服务器计算资源白白发送无效的 push notification。

Android App 推送:使用 Firebase Cloud Messaging (FCM),国内的读者可能没法收到推送的消息。我尽力了。

RSS:老旧的,但仍然很有用的 RSS。你会很惊讶,现在很多线上媒体不提供 RSS订阅。

Chrome 浏览器推送:我是根据 Google 的官方文档做的。Chrome 是访问湾区日报网站用的最多的浏览器,占了 50% 左右,所以先实现了 Chrome 上的消息推送。接下来是桌面 Safari 占了 10%、Firefox 占了 4%,最后是可以忽略不计的 IE 以及其他杂牌浏览器。

为了避免同一篇文章在短时间内不小心被多次发到以上渠道,我会针对每篇文章生成一个 uuid 存到 Redis 里;每次修改文章简评的时候,会查一下这个 uuid 是否存在,如果不存在,就推送到以上渠道;反之就不推送。

很多读者注意到了,湾区日报在各个社交媒体上不断炒冷饭,重复发布几个月前发过的文章。我在 FAQ 里有详细说明原因。简单说,半年后,湾区日报的读者数量翻倍,将有一半的读者没有读过我以前推荐过的文章,“旧”的文章对他们而言是“新”的。

怎么炒冷饭呢?每天推荐新文章时,我会判断这篇文章是不是 evergreen content,半年后来看是否依然适用;如果是的话,我就把该文章扔到一个队列中(存在 Postgres 里);然后 Celery Beat 每个钟头会有一定概率(不同时段的概率不同)从队列里取出文章发到微博,Twitter,Facebook等社交媒体上,比如这条微博。队列里的这些旧文我会定期清理;有的文章真的发了好几次了,老读者们是在看腻了或者已经不再适用了(比如关于Apple Watch即将发布的相关文章;现在Apple Watch已经发布了,就不能再发这类文章),那就得从队列里删除。

湾区论坛 / 读者讨论

以前湾区日报网站用 Disqus 让读者留言。我最近不用 Discus 了,换成了 Discourse。因为我不想让湾区日报网站的内容变得太杂,所以最好能弄个地方让我发一些五篇文章以外的东西(如推荐 Podcast、讨论一些时效性强的新闻)。正好 Discourse 用来搭论坛,还能挂到湾区日报网站做评论系统,一举两得。于是,湾区论坛就诞生了:wanqu.io

Discourse 代码是开源的。我开了一台新的 DigitalOcean 的 $20 的服务器来跑 Discourse,按照文档搭设,一路很顺利。然后我写了个脚本,调用 Discourse api 为之前湾区日报推荐过的每篇文章生成一个湾区论坛的帖子,然后再湾区日报网站的文章页面下挂上 Discourse 的 js 代码片段,这样就能让读者评论了。

数据统计

如果你经常使用湾区日报的 iOS appAndroid app 或者网站,你就会发现我竟然公开了湾区日报的运营数字:访问量,app下载量,app打开消息推送的用户数,app的付费用户数等。下图告诉你在哪里可以找到湾区日报的各种运营数据: 

 

湾区日报毕竟不是一个公司,我也不跟任何人合作,所以我说的算。我觉得中文的互联网上能找到运营网站的实战案例很少。一个对互联网感兴趣的人,当然希望能看到一个真实的运营案例以及真实的数据,作为一个学习材料 -- 有点像教科书上的案例分析。

这些数据分别从 App Annie 的 api,Google Analytics 的 api,以及我自己的后台数据库去抓去。Celery Beat 每小时开启一个 job 更新一下这些数据。

对于湾区日报的 iOS App,我最关心的数字是有多少用户开启了 push notification;只有开启了 push notification,用户才能及时得知当天的湾区日报的更新。每当有一个新用户开启了 push notification 或付费了,我的 Slack 就得到通知。下图是我 Apple Watch 上来自 Slack 的通知,告诉我此刻有一个新用户下载了 App 并且打开了 push notification: 

 

关于 Slack 与 Hubot,详见这篇博文:湾区日报的第一个“员工”:Slack/Hubot

湾区日报分享的每篇文章都有一个访问量的统计,这个统计数字是存在 Redis 上,这比存在 Postgres 上每次访问都要写数据库的 cost 要小得多;存在 Redis 上即使失去了1小时的数据也无所谓,这个统计数字不是那么 critical。

一般每个湾区日报网站的链接后面都有一个 query parameter,方便我在 Google Analytics 的实时监控里一看看出用户是通过什么途径访问了网站的。比如 wanqu.co/cost?s=social 里的 s=social 表示这是通过社交类的线上服务进来的,而 wanqu.co/cost?s=footer 则是表示这是通过网页底部直接点链接进来的。这样做一点都不科学,但由于湾区日报只是一个小 project,我只要知道个大概、心中有数就行了,不用那么精确。

除了通过 query parameter 外,我还用 Google Analytics 的 api 跟踪某些我感兴趣的 event(网站与 iOS app 都有),这样我可以知道大概哪个按钮被点击了多次、用户大概是有怎样的访问路径。如下是在 Google Analytics 上看到的 iOS app 的用户点击事件:

 

所以湾区日报也是有做一些很简单粗暴的伪 data science 的:)

搜索功能

网站与 iOS app 上都可以关键词搜索往期的文章。我原来想用 ElasticSearch 来做一下,但想着要多管理一个ElasticSearch就不爽,这样就多了一个 failure point,运维上可能得多花点时间,不划算。

后来受到这篇文章的启发,用一个晚上的时间直接利用 Postgres 做全文索引,并实现了网站与 app 的搜索功能,真是快糙猛的做法。

广告运营

光靠情怀与热情去做湾区日报是没法长久的,毕竟我只是一个普通人,也会有懈怠、厌倦的时候。所以为了鼓励我继续长久做下去,为了湾区日报能可持续发展,我尝试引入赞助商广告、增加一点收入,但愿这种经济上的刺激能让我这个普通人坚持运营下去。

广告形式主要是文字与图片,都是 html,很简单。

支付用的是 Stripe,但只支持刷信用卡;有时也用 PayPal。但国内的广告商一般都没法刷卡,只好用银行转账。

跟踪广告的表现(浏览量、点击量)我是直接写到 Redis 里,然后每 1 个小时自动更新报表。这是一份真实的广告报表

与广告商的沟通主要是通过电子邮件或者微信(wanqu_w)。

详见这篇博文:这半年来运营湾区日报的广告业务的体会

运维

我一般每几个星期发布一次新版本的 app。每次的更新其实很有限。我每星期一般只能花不到一小时来写 app 的代码。

网站后台代码的更新主要通过 Slack。仍然是与小机器人对话:“wq deploy”。它就会 checkout 网站的 git repo 的最新 master branch,然后重启相关进程。我用 symlink 做了版本控制,所以如果发现严重的bug,要 rollback 到前一个版本的话,只需要切换一下 symlink,几秒钟的事情。

发布代码变得轻松愉快,且充满自信,这就鼓励了开发人员(我)勇于尝试各种新奇的 idea,勇于快速迭代,快速部署小更新。所以湾区日报一直在进化。湾区日报的今天没有比昨天好多少,但这个季度肯定比上个季度改进了不少。

监控网站是否挂了,我用的是 Pingdom;如果网站挂了,我会收到短信提醒。监控服务器各种计算资源的使用情况,我用的是 Datadog(2014年去开 Dockercon 的时候,在他们摊位聊了很久,才知道有这么个东西)--理论上,monitoring 与 alerting 都可以自己用开源软件搭建,但是,湾区日报只是一个 side project 而已,有现成可以凑活着用的SaaS方案,就不必花时间自己做了;而且自己做的肯定不如人家专业的。用 Datadog 可以方便地看到不同 endpoint 在特定时间段内的请求次数以及latency。详情请见:湾区日报是如何监控系统的健康情况的

 

网站域名的 DNS 管理,我用 CloudFlare。使用 CloudFlare 还有其他的好处,比如它帮我挡住了不少恶意请求,帮我缓存了各种静态文件。

客服

每天都有读者来信。当然,大部分的问题都能在 FAQ 里得到解答。但也有很多来信给了我很多鼓励,知道你们从湾区日报推荐的文章里学到了东西得到了成长,我真的很高兴。

微博与微信上的读者来信,大部分都能得到关键词匹配的自动回复,算是缓解了我手动回复的压力。而花时间去写 FAQ 页面则省去了回复大部分邮件的时间。

我会阅读发到 hi@wanqu.co 的每封邮件的,大部分来信都很正能量,谢谢你们。但我实在没有时间一一回复,请见谅。我很希望一天能有48小时,这样可以多做一些事。有一些邮件我默认是不回复的,比如邮件里用到“你们”,“贵公司”之类字眼的,比如以公司名义发信要进行“内容合作”与“商业推广”的,这些人显然没有做好功课。很多人会惯性思维地认为湾区日报是一个多人创业团队运营,以盈利为目的,追求点击量的媒体,所以来信内容是会基于这样的假设的。我没办法控制别人的想法,这些也都是 distraction,我有限的时间只能花在每天5篇文章上,仅此而已。若有得罪之处,请多包涵。

代码管理与新功能的开发

湾区日报有3个 git repo(网站后台,iOS app,以及运维相关的脚本),都放在 Bitbucket 上,不对外公开。使用 Bitbucket 而不用 GitHub 的原因是为了省钱;如果要在 GitHub 上使用 private repo,得交钱;而 Bitbucket 我个人用的话,可以有无限数量的 private repo。

我比较倾向于 commit 小段代码,出问题了也可以比较小粒度地 revert。一般一个 commit 包含的代码量不多于 100 行。很显而易见的代码修改我直接在 master branch 上操作,然后直接 push master;比较 tricky 的代码修改我会建立一个新的 branch,然后给自己发 pull request,自己 review 一遍自己写的代码。

我经常上线没有写完的代码,然后 wrap 在 feature switch 里面。我这种小破 project 大部分的方案都是土办法,不用太学术派不用太杀鸡用牛刀,意思一下就行了。所以一个 feature switch 其实就是 Postgres 里的一个表格里的一行。湾区日报99.999%的workload是 read-only 的,所以网站上很多页面其实都是缓存在内存然后走CDN的,数据库访问不会太 crazy。

顺便提一下,有一些年轻的读者(学生或者刚工作不久的年轻人)发邮件过来逼我开源湾区日报的代码,让我有点哭笑不得。详见 FAQ 第18条

开发环境

我用家里的 iMac 写代码。Mac OS X 下运行虚拟机 Vagrant + VirtualBox。虚拟机里跑的是 Ubuntu,与 production 里用的操作系统一样。然后通过 Vagrant 的 synced folders 在 Mac OS X 与虚拟机之间共享代码的文件夹。在 Mac OS X 上用 PyCharm 写代码,利用 PyCharm 里的 Vagrant 的支持,在虚拟机里跑服务器。

数据备份

有一个每天自动执行一次的 job 把所有数据 dump 出来,压缩一下,按日期命名,最后上传到某个地方。上传到哪里呢?任何提供API的云存储服务都行(Dropbox、Box之类的)。

对于 PostgreSQL 里的数据,我用 Django 的 dumpdata 命令把所有数据 dump 成一个 json file,然后 gzip 一下。

对于 Redis 里的数据,直接 gzip 一下 disk 上的 dump.rdb

详情见这篇博文:湾区日报是如何备份数据库的?

运营成本与收入

湾区日报网站的这个页面 wanqu.co/cost 会更新每个月的运营成本。最近这个月的运营成本是 $739.22。其中 $139.22 是花在租服务器、买域名、各种 SaaS 的费用,而剩下的 $600 是人工成本。

$600 的人工成本是如何计算出来的?我每天花在湾区日报的时间是 1~3 小时,周末有时候可以腾出半天时间写代码、更新 iOS app。就当每天平均工作 2 个小时吧,乘以加州最低时薪 $10,再乘以 30 天一个月;所以每个月人工成本 $600。

湾区日报是有一些收入的,但整体来讲是亏本经营。收入来源主要有四个:

1,来自 Google Adsense (网站)、 Google AdMob (iOS app)以及 Amazon Affiliate 的收入。这部分收入几乎可以忽略不计。每个月大概就 $50 左右吧。

2,来自 iOS app 内购的收入。App 内购的定价相当于请我喝半杯咖啡;这个价钱说多也多,说少也少,因人而异了。让我很欣慰的是,下载了 app 的人里,有 7.4% 的人愿意掏钱请我喝这半杯咖啡:)

3,来自赞助商的广告。这是最新开辟的收入手段,不是每天都有赞助商的,所以收入还不是很稳定,大概每月几百到一千多不等。

创业公司需要养一帮人,要发全职的工资,要租办公室,还要做营销,相当烧钱。而湾区日报是小 side project,业余时间做就行了,运营起来不会花太多钱。所以湾区日报一时半会儿是不会因为钱的问题而倒闭的:)

4,来自读者的捐款,主要是通过 PayPalPatreon

处理负面情绪

当然,任何人、任何事、任何一句话、任何作品都不可能让世界上每个人都一致认可的。任何有微博帐号的公司、组织、小有名气的人,必然要接受网友讽刺、辱骂的。湾区日报的传播变广了后,也偶尔会有无理挑衅、攻击的声音;我脸皮还算厚,平常心对待,专注于每天推荐的5篇文章就是了。

如果你做的东西没有任何批评的声音,如果没有人嫉妒眼红,如果没人模仿抄袭盗版,那么你做的东西要嘛没意思,要嘛知名度还太低。

总结

如果把这篇文章给2014年8月6日的我看,我肯定不会做湾区日报这个 side project 了,太花时间了 -- 竟然要做网站,要做发布系统,要学 Swift 然后写 iOS app,还要每周发布 app 新版本,还要管理好几个发布渠道,还要做客服回邮件,还要每天花1到3个钟头读文章写简评。

幸亏写这篇文章的时候,大部分困难的工作已经完成了。这就是互联网时代的产品迭代,是一个循序渐进的过程,是个人与产品共同成长的过程。你不能期望一夜成功 -- 其实,你也可以一夜成功,只是这一夜发生在第1000天甚至第3600天。

运营湾区日报是没什么经济上的回报的,尽管有一些广告收入与app内购的收入,但与投入的时间(再乘以一个哪怕是实习生的时薪)相比,相当微不足道。之所以我还能继续做下去,是看中知识的积累与个人的成长。这些运营经验以及从每天5篇文章里学到的东西,是完全可以运用到我其他的项目上的。就算最后真的什么都没做成,也是一段美好的回忆。临死的时候,回顾一生,至少我还能说,我做过一个叫湾区日报的博客,每天有那么几万个读者(我也是读者之一),我们每天都在进步。这就够了。

有 impact 的东西,未必是有技术含量的。

如果湾区日报让世界上某个角落的陌生人拓宽了视野,甚至是得到启发进而更热爱工作、热爱生活,我觉得这就算有 impact 了。至少我对这个世界还是有点用处的。


欢迎下载使用湾区日报 for iOS湾区日报 for Android,或在网站上看看往期文章

如果你觉得湾区日报对你的成长有所帮助,你想在经济上支持我一下,可以考虑在 Patreon 上每个月捐 $1


我读过的好书、 用过的好工具推荐:
Sponsor