2019年11月15日星期五

Early Reader 2020 调整

我在 Patreon 上开放 Early Reader 这一档有一年多了,感谢大家长期的支持,让我来聊聊这一年的通过经营 Patreon 学到的东西吧。

Early Reader 这一档每个月收 $1 的费用,对应的好处是提前一周阅读我最新发布的文章。(事实上我推迟了文章在其它平台发布的时间,同时在 Patreon 上设置了解锁时间。)在这一年内我获得了 9 位朋友的支持,现在仍然活跃的有 5 位。

我觉得 Early Reader 这一档并没有达到我原来的预期。我原本设想这一档能够通过足够低的价格获得尽可能多的读者支持,但实际上没有足够多的人愿意为「提前一周」这个福利而付费。我在跟 Joma 聊天时他提醒了我一件事情,「你不应该根据『你需要付出多少』来定价,而要根据『别人能获得多少』来定价,提前一周阅读对读者来说其实不值钱」。我觉得这个视角是对的,所以我准备对 Early Reader 这一档作出调整。

我从读者的角度来思考什么有价值,我觉得主要是两方面吧:

  1. 获得我不对外公开的独家内容。
  2. 能够真正的激励我创作更多的内容。

为此我新开了两档,分别叫做 Coffee Supporter ($5) 和 Sushi Supporter ($30)。这两档的价格比原来的更高,但请我吃饭(尤其是吃寿司)这件事情确确实实能够激励我干活。我有一个猜想,很透明地分享一下吧:如果我的读者觉得他们给我的是看得着摸得到的实物(食物),那会比原来虚无地付 $1 但不知道这 $1 有什么具体含义更乐意付费。(你们可以在评论区告诉我这个猜想对不对。)

此外我会开始做不对外公开的独家内容,专门给付费读者看。一开始主要还是文章,之后我会探索音频和视频。这些内容如果是长篇的话,我可能会免费发布其中一部分在公开的博客上,但不会发布全部。

最后说一下现在 Patreon 上的 Early Reader 这一档会如何迁移。我现在已经对新读者关闭了这一档,并且计划在 2020 年 1 月完全终止这一档,那意味着如果你到时候仍然使用这一档的话 Patreon 就会把你的付费订阅取消掉。如果你愿意升级到 Coffee Supporter 或 Sushi Supporter 的话,你可以在那之前进行升级。升级后会保留原有的福利,同时获得上述新增福利(不对外公开的独家内容)。

如果你是在我 Patreon 以外的博客上看到这篇文章,欢迎来 Patreon 付费支持我。如果你觉得美元付费对你来说并不方便,请在评论区留言告诉我,我正在努力开通支持人民币支付的对应版本。

Career Coaching 2020 新价格

我的 Career Coaching 将在 2020 年初开放更多名额,同时进行年度价格调整。新学生的价格为每小时 $300。2019 年内或更早加入的学生将能继续获得优惠,优惠价将在 2020 年 1 月统一调整到每小时 $200。

对于已经在 Patreon 上进行付费的现有学生,我会在 12 月开放新的一档 $200 的服务,请你们把自己的帐号从现在的 $100 或 $150 一档调整到 $200 一档,然后我会在 1 月删除 $100 和 $150 这两档。(我到时候会发消息逐一通知你们。)

对于等待新名额的学生,我将会在 12 月放出 $300 这一档。如果你 12 月就在 Patreon 上加入的话,系统会在 1 月头扣钱,我会在 12 月跟你约好 1 月份开始的 bi-weekly 30 minutes 1:1。

2019年11月12日星期二

《牛油果烤面包》满月回顾(Part 3 - 统计数据)

Apple Podcasts Connect

上一篇文章里我讲述了《牛油果烤面包》的录音和剪辑过程,接下来我们看看听众订阅和收听的数据如何。


我在第一篇文章里面提到我们用 Anchor 把播客自动发布到多个平台,同时我们手动发布到喜马拉雅和企鹅 FM。如果我们要看数据,我们就必须一个一个平台地看。

  • Anchor:Anchor 提供「播放数」和估算的「听众数」,同时提供听众的国家、播放平台和设备分布。Anchor 会统计每一集每一天的播放次数。(参考截图
  • Apple Podcasts:Apple Podcasts Connect 不提供「订阅数」只提供「设备数」,所以无法知道有多少人订阅了。Apple 强调的是总收听时间,我们在过去的 60 天内有 96 个小时的收听时间,这样就可以推算出来每台设备 85 分钟的收听时间。此外这 96 个小时里 84% 来自于订阅听众,但这还是无法推算出订阅数。具体到每一集,Apple 同样提供设备数和总收听时间,同时提供节目内的留存率,也就是用户听到第几分钟第几秒钟就流失了。(参考截图:1 2
  • Spotify:Spotify 提供「播放次数」、「播放超过 60 秒次数」、「听众数」和「订阅数」。后面两个都是根据 Spotify 注册用户进行计算的,所以不存在多次在不同设备播放导致的重复计算。我们现在有 153 个订阅用户,但每期节目只有不到 20 次播放,意味着 Spotify 的用户经常订阅但不收听。Spotify 为每一集提供留存率,以及听众的性别和年龄分布。(参考截图)
  • Google Podcasts:Google Podcasts 本身并不提供任何的数据,只要 RSS 被 Google 抓取了就会显示在 Google Podcasts 里。有意思的是,Google Play Music Podcast Portal 可以认领 podcasts,但我认领后还没能看到任何数据,不知道这个产品现在到底是否还活着,还是因为不会有人在 Google Play Music 里面听 podcasts。暂时来说,我们无法从 Google 获得任何数据。
  • Castbox:Castbox Creator Studio 提供节目的订阅数、播放数和每一集的播放次数。(此外,因为 Castbox 提供了评论系统,所以作为管理员可以管理用户评论。)
  • Breaker:Breaker 自动收录第三方的 RSS,对于不是在 Breaker 上创建的 podcasts 无法认领也无法获取数据。
  • Overcast:Overcast 自动收录 Apple Podcasts 已经收录的 RSS,并且不提供认领。有意思的是,Overcast 在抓取 RSS 时通过 user agent 来上报订阅数,但由于我们使用 Anchor 提供 RSS 所以无法截获 user agent 获取订阅数。
  • Pocket Casts:Pocket Casts 接受 podcasts 提交,但不提供认领和数据。
  • RadioPublic:RadioPublic 自身不提供任何的数据分析,但可以使用 Google Analytics 收集数据。不过只有付费用户才能使用这项功能,所以我并不知道 RadioPublic 会向 Google Analytics 汇报什么数据。
  • Stitcher:Stitcher Partners 提供播放数、播放时间和听完率。
  • 喜马拉雅:喜马拉雅提供「订阅数」和「播放数」,以及每周新增听众的留存率。喜马拉雅不提供节目内的「留存率」但提供「跳出率」,虽然本质上是一样的数据但呈现出来的曲线就完全不一样的。(「跳出率」是「留存率」的倒数。)此外喜马拉雅提供听众的省份、城市和性别分布。

总结一下:这些平台提供的数据各不一样,有些平台基本上不提供什么数据。这就导致我们无法轻易地整合数据,分析听众喜好,然后优化将来的节目。现阶段我们能做的是,尽量把用户带往几个提供数据分析的平台,然后依靠这几个大平台的数据做决策。

长远来说,我觉得我们可以做自己的平台入口,让用户可以直接在我们自己的网站上播放甚至是订阅,这样我们就可以自己收集一部分的统计数据了。当然,如果用户喜欢用其它平台的 app 进行订阅和播放我们依然无法收集到那部分的数据,但至少我们能收集多少是多少吧,这对我们优化选题和节目内容很重要。


说完数据之后,我们接下来可以说说选题。如果你想知道我们是如何进行选题的,欢迎通过邮件RSS/Atom 订阅我的博客,保证你不会错过下一次关于选题的文章。

2019年11月9日星期六

追踪短地址的小工具:Trace URL

我写了一个追踪短地址的小工具,输入任何短地址(或普通带重定向的地址),它就能找到原地址显示给你看。我把它叫做 Trace URL,欢迎大家来使用。这是一个 PWA (Progressive Web App),所以 Android 用户可以把它添加到首屏,添加后就可以把短地址「分享」给 Trace URL 进行追踪。

这个项目是完全开源的,不过源代码分布在多个 GitHub 项目当中。traceurl-web 包含了 PWA 客户端代码。这个项目使用 Create React App 创建,然后使用 Material UI 做样式模板,最后手工编辑了一堆 metadata 使它成为一个好用的 PWA。在这里我分享一个比较小众的 PWA 知识吧,也就是如何让 PWA 接受来自 Android 分享的数据,这需要在 manifest.json 里面添加一个叫做 share_target 的信息,例如说:

{
  "share_target": {
    "action": "/",
    "method": "GET",
    "enctype": "application/x-www-form-urlencoded",
    "params": {
      "title": "title",
      "text": "text",
      "url": "url"
    }
  }
}

添加 share_target 信息后,只要 PWA 被添加到首屏,它就能成为 Android 系统的分享目标。需要注意的是,Chrome for Android 有个已知的 bug,分享地址时会把地址传输给 text 参数而非 url 参数。所以在处理传入参数时我们需要同时看 texturl,哪个有值就处理哪个。

这个 PWA 背后实际调用的 API 在 traceurl-api 项目里。这个 API 其实只是对 traceurl 库做了个简单的封装,这个库才是真正负责跟踪短地址的。这样层层封装只是为了好玩,让我能够尝试一些新技术,学习新知识。例如说,traceurl 其实是一个 package,我原本把它发布到 NPM Registry 了,后来 GitHub 发布测试版的 GitHub Package Registry 时我就试用了一下,把 traceurl 发布到那里去然后在 traceurl-api 里面引用。这就让我理解到了到底为什么 GitHub 要做自己的 Registry。(到底是为什么?我另外写一篇文章解释。)

这次就先说这么多吧,大家记得来试用一下 Trace URL 哦,好用的话记得添加到 Android 首屏哦!下次我再写文章讲述 GitHub Package Registry,感兴趣的话请记得通过邮件RSS/Atom 订阅本博客。

2019年10月18日星期五

Career Coaching 小组交流群

我在做 career coaching 的过程中听到了大家的建议,希望能建立小组帮助目标一致的学生沟通。在我的学生当中,有两个主流的目标群体,为此我专门在我的 Discord 服务器上开了两个 channel 用作交流:

  • 第一个是求职小组(#students-job-seeking),主要针对想要找 Software Engineer 职位的在校学生,有计划换工作的 Software Engineer 也可以加入讨论。这个小组主要用来讨论笔试题目、面试题目、公司招聘流程、寻求内部推荐、了解公司口碑和职位信息等。
  • 第二个是职业成长小组(#students-career-growth),主要针对在职 Software Engineer 提升技能和探索新领域,同时也可以用作交换各大公司的职场经验。我预期这个小组的话题更宽广一些,包括一些类似 case study 的个人经历讨论。

如果你还没有加入我的 Discord 服务器,请使用邀请连接 加入。(如果你不想使用 Discord,欢迎通过评论推荐别的平台。)只要你是我的 Patreon 上的学生,你应该会自动获得对应的权限,保证你能够进入这两个小组。如果你在 Patreon 外跟我 ad-hoc 约时间,你可以在加入我的 Discord 服务器后告诉我你的用户名,我可以手动把你添加进去。

《牛油果烤面包》满月回顾(Part 2 - 录音剪辑)

我们继续回顾一下录制播客《牛油果烤面包》过程中学习到的东西。在上一篇文章里我说了一下使用 Anchor、喜马拉雅和企鹅 FM 作为平台发布的经验,这次我们说说录音和剪辑的过程。


我们录音使用的是一支 Sony 录音笔,这是我看着 TheWireCutter 的推荐买的。为什么选择录音笔?这跟我选择 Anchor 作为第一个发布平台的原则是一致的,就是找投入成本最低最快能起步的方式先把节目做起来,如果节目做得好,听众越来越多,我们可以投入更多把节目做得更好,否则我们停掉节目损失也不大。

一个人录音的话其实很方便,直接用手机连接麦克风录就可以了。这其实也是 Anchor 推荐的办法,Anchor 说很多个人播客都是一个人躲在棉被下面录音的,因为棉被可以隔音。不过我们有两位主持人,一个麦克风无论是连接手机还是电脑都不能解决问题,但要两个麦克风一起录的话就需要特殊设备支持。用电脑录的话,可以用 mixer,把多路麦克风输入合并到一起再输入给电脑。后来我发现原来录音笔也是有内置支持多路输入的,例如这个价格是上述 Sony 录音笔四五倍的 Zoom H6

我们现在使用双声道的 Sony 录音笔,两个主持人一起录通常没什么问题,大家坐在桌子的两旁,录音笔放中间。只要录音笔离两个人的举例相当,大家保持相当的音量说话,录出来的效果也不错。当我们开始邀请嘉宾时,事情就变得有点复杂了。要让三个人到录音笔的举例一致比较难,我们往往是把位置安排好后先试录一段,然后再听一听感觉效果没问题了再正式开始录。


录音之后的剪辑我用 Audacity,免费开源的好工具。我在剪辑方面不是很有经验,往往就是看看哪里有废话就剪哪里。我们在录音过程中有时候聊着聊着就把话题给聊死了,于是我们会停下来讨论一下接下来聊什么,这样的部分就会被完全删掉。除此之外,我们还有很多「嗯」、「啊」之类的 fillers,也就是想不到说什么时会无意识说的字,在合理的情况下这些也会被删掉。在内容剪辑好之后,我们会在录音前后加上 intro 和 outro 的音乐,然后调节一下整个节目的音量大小。

这项工作说起来简单,实际上做起来非常耗时。之前剪辑都是另外一位主持人斯图亚特做的,后来我听说 Acquired 这个两位 VC 做的播客使用网上专业的剪辑服务,每周节省数个小时的剪辑时间,于是就产生了类似的想法。很可惜他们使用的服务仅支持英语播客,不适用于我们的中文节目。为此我在 Twitter 上问我的 followers 有没有人愿意收费帮我们剪辑,最终找到了 @icewlb 来跟我们合作,帮我们完成剪辑这一项艰巨的任务。


这次文章就写到这里,下次我们来聊聊我们节目的用户收听数据如何,根据这些数据我们会如何安排接下来的节目。如果你想要看我们的数据,欢迎通过邮件RSS/Atom 订阅我的播客,保证不会错过下一篇文章。

2019年10月17日星期四

《牛油果烤面包》满月回顾(Part 1 - 发布平台)

我们做《牛油果烤面包》这个播客满一个月了,总结一下这个月以来的经验吧。

我在之前的文章里面说到为什么我选择使用 Anchor 这个平台来发布播客,因为它像是播客业界的 YouTube,能够让你免费并且迅速地起步。这对于我们这个不知道能不能做起来的播客来说很重要,因为我们当时还不知道会坚持做多久,所以前期投资越低越好。


用 Anchor 发布我们后发现的第一个问题就是中国国内不能访问。这其实很要命,因为我们做这个节目的一个初衷是为了让国内的听众更好地了解美国加州和湾区,如果国内不能访问的话这一个目标就实现不了。我第一时间尝试研究 Anchor 支持的第三方平台有没有能在国内收听的,例如说 Spotify。我发现 Spotify 的收费用户是能在国内收听的,但因为 Spotify 没有正式在国内提供服务,所以能注册到的帐号必然是其它国家的帐号,不付费就不能「漫游」到中国使用。(我暂时还没有找到一个能让国内用户正常订阅和下载 Anchor 节目的方案。)

在我紧张地想办法解决 Anchor 不能访问的问题时,我们的另外一位主持斯图亚特直接注册了一个喜马拉雅的帐号来解决问题。这需要他进行身份证验证,这还需要我们接下来持续维护两个帐号同步发布,不过为了能让国内的听众正常收听到我们的节目,这也是值得的。

这个问题看起来解决了,但后来我在网上搜索了一下国内播客平台的市场份额,发现没有最新的数据但几年前的数据表明喜马拉雅并没有完全占据这个市场,企鹅 FM 和荔枝 FM 也占据了不小的市场份额。于是斯图亚特又去注册了一个企鹅 FM 的帐号在那边同步发布。


我们遇到的第二个问题是如何修改已发布内容。博客文章发布后要修改很简单,编辑文本就可以了。播客的话,我们可以在本地编辑音频文件,但平台是否支持上传覆盖呢?

Anchor 在这方面是很容易的,编辑一集节目时除了可以修改文本信息,还有一个编辑音频的功能。编辑环境跟发布前的创作环境一样,可以随意切割音频文件,然后重新排列多段音频顺序,或者是插入听众留言和过渡音效。因为我们不使用 Anchor 的编辑环境,所以我们把本地编辑好的新文件上传就好了。

喜马拉雅的这个功能找了很久才找到。在编辑某一集节目的界面里只能修改文本信息,不能重新上传音频。最终我在研究专辑编辑时找到了这个功能——在专辑的节目列表里,可以选择任何一集节目然后重新上传音频文件。当然作为一个国内的平台,上传当然不仅仅是上传,先审后发是必须的,不过审阅超级快(不知道是不是用算法侦测出我们只是微调了音频)。

至于企鹅 FM,因为我们比较晚才登陆,所以没试过需要发布后编辑的,仍然不确定它是否支持发布后编辑……


在这篇文章里我就先说这么多,我会在下一篇文章中聊聊我们录音和剪辑的经验。最后送上我们这一个月里除首发外热度最好的一集,里面讲述了我们两位主持人移民美国的体验。

2019年10月10日星期四

《Secrets of Sand Hill Road》书摘(Part - 1)

我最近读完了《Secrets of Sand Hill Road: Venture Capital and How to Get It》,觉得这本书对于 VC 及其运作方式的解释很清晰。如果你想要创业但还没有跟 VC 打交道的经验,这是一本非常好的入门书。如果你只是好奇 VC 和创业者之间的合作和博弈,那也不妨读一读。以下是我读完这本书以后我觉得有意思值得摘录的点。

VC 是什么?

  • 在你无法通过其它更传统的金融手段(例如债券)获得资金时,VC 是一种获取资金的手段。但在选择 VC 之前,你必须先先思考一下哪种获取资金的手段更适合你。
  • 债券还是股权?债券是要偿还的,所以更适合于那些短期内能够产生利润的公司。股权则没有这方面的限制,但你就不能够保持对公司的 100% 控制权了。
  • VC 作为一种资产类别来说,其回报中位数并不比 S&P 500 好多少,只有顶级 VC 能产生超额回报。研究表明,能够产生超额回报的 VC 会持续产生超额回报,因此品牌效应明显。
  • VC 的品牌效应会覆盖到创业公司:被顶级 VC 投资的创业公司,更可能是这一领域的顶级公司,更有可能吸引顶级人才,更有可能吸引到顶级 VC 投资下一轮。
  • VC 的投资结果分布:约 50% 是亏本的,甚至血本无归;约 20% 到 30% 能产生几倍(不到 10 倍)的回报;约 10% 能产生 10 倍甚至 100 倍回报。VC 只在乎增加 10 倍或以上回报的概率,10 倍以下和亏本无区别。

VC 如何选择投资?

  • VC 主要考虑三个类别:人、产品、市场
    • Founder-Market Fit:有什么特定技能、背景或经历导致创始团队想要做这个 idea?
    • 基本问题:对于同一个 idea,为什么选择押注在这个团队上,而不是等待另外一个更适合做这个 idea 的团队出现?(背后的逻辑:一家 VC 投资一家公司就是认定这家公司能够赢得这个市场,投资这家公司的机会成本就是将来不能再投资这家公司在这个市场的竞争对手。)
    • 创始人的领导力:他们能否围绕公司使命说一个很动听的故事,吸引优秀人才加入,吸引顾客购买,并且为将来的融资吸引其它投资人。
    • 「You have to be partly delusional to start a company given the prospects of success and the need to keep pushing forward in the wake of the constant stream of doubters.」
  • 产品
    • 假设产品在寻找 product-market fit 时会改变许多次,如同探索迷宫一样探索 idea 的流程比实际的产品 idea 能更好地预测创始人的成功。
    • 维生素和阿司匹林:如果你忘记吃维生素,你不会放下手上的活赶回家吃。如果你觉得头痛,无论如何你都会想弄一片阿司匹林来吃。VC 喜欢投资阿司匹林一样的产品。
  • 市场规模
    • 如果 VC 投资到一个不成规模的市场里,就算公司表现优异,股票价值也不会太高。因为 VC 需要 10 倍或以上的回报,所以不能投不成规模的市场。
    • 平庸的团队能在伟大的市场里获得成功,优秀的团队在不好的市场里总会失败。

LP 是什么?

  • VC 靠 LP 的投资来生存。LP 需要 VC 维跑赢市场指数来维持他们的投资组合。
  • 常见的 LP 类型:大学的捐赠基金、慈善基金会、企业和政府退休金、超高净值家庭的财富管理公司、国有财富基金、保险公司、小额基金组合而成的基金。
  • LP 的三大投资类别:grwoth assets(公开股票、私募股权、对冲基金)、inflation hedges(房地产、商品、自然资源)、delationary hedges(债券、现金)。
  • 大学的捐赠基金需要向学校提供稳定的资金来源,Yale 是这些基金的典范。Yale 基金有一半放在非流动性资产里。为了保证学校的正常运作,Yale 基金需要每年从非流动性的 VC 投资里获得 18% 的回报。这个对回报的需求驱使 VC 把投资转化为利润,投资的公司要么上市要么出售。
  • 创业者必须有对 VC 基金周期的敏感性,知道投资自己的基金处于周期的哪里。(大多数 VC 基金的生命周期都是十年。)如果你在基金的第三、四年拿钱,这个基金有充裕的时间和可用资本跟你共同成长。
  • VC 的基金一般都会预留一定的资本,用来追加更晚轮次的投资给之前这个基金投资过的公司。你从一个基金首次获得投资的时间越晚,这个基金就越有可能没留下足够的预留资本继续投资你将来的轮次。
  • 在预留资本不足时,VC 可以用第二个基金追加更晚轮次的投资,但这比从同一个基金出资要难。因为第二个基金有不同的一组 LP,可能会导致跟第一个基金产生利益冲突。

书摘的第一部分就写到这里,下一篇从「LP 如何和 VC 组队」开始继续写。想要关注这个系列的话,欢迎通过邮件RSS/Atom 订阅。

2019年9月24日星期二

如何让 MailChimp 订阅对话框在点击时弹出

问题描述

我的博客提供 MailChimp 订阅,大家点击订阅链接后需要转跳到 MailChimp 的页面输入 email。MailChimp 官方提供直接嵌入在网页内的订阅对话框,我希望读者在博客上点击订阅链接后直接打开对话框,让订阅流程变得更顺畅,这样可能能够提高订阅率。(为了保持兼容性,如果读者在 RSS 阅读器或邮件内点击订阅链接,则还是正常打开订阅页面。)

问题在于 MailChimp 官方不提供订阅对话框通过点击触发的选项。对话框的触发条件只有简单的几种:页面加载后弹出、用户滚动到页面底部时弹出……(可能 MailChimp 是设计给非程序员用的,所以不提供任何需要写点代码才能完成的整合,只提供包装好简单易用的方案。)为此,我需要修改 MailChimp 官方提供的对话框嵌入代码,使得它能在订阅链接点击时触发。

解决方案

MailChimp 提供的嵌入代码包含两个 <script> 标签。第一个 <script> 标签不需要做改动,第二个 <script> 标签需要把内含的代码需要嵌入到一个函数中去,然后就可以在链接的点击事件里通过调用这个函数触发订阅对话框了。以下是参考代码:

在上述代码中,我没有改动第一个<script> 标签,第二个<script> 标签里面有一个函数,第三个 <script> 标签对页面上的订阅链接添加点击事件响应函数并在那里调用第二个 <script> 标签里定义的函数。

第二个 <script> 标签里定义的函数,包含了 MailChimp 官方提供的代码中的 window.dojoRequire(...) 这一行。如果你要使用我的代码,你必须把这一行替换成 MailChimp 给你的同一行代码,然后才会显示你的对话框而不是我的对话框。

在这一行前面,我插入了两行代码用来删除 MailChimp 会插入的两个 cookie:一个是在用户关闭对话框后加入,另一个是在用户订阅后加入。只要有这两个 cookie 中的一个,对话框就不再显示。这对页面打开就触发的订阅对话框来说是合理的,谁也不希望每次打开页面都会看到对话框弹出。但如果用户主动点击链接,则应该总是打开对话框。为此我们要删除上述两个 cookie,保证对话框总是能打开。

第三个 <script> 标签是针对我的博客定制的,并不适用于其它人。我在我的博客页面内寻找所有指向我 MailChimp 订阅页面的链接,然后绑定这些链接的点击事件。用户点击链接的话,就调用第二给 <script> 标签内的函数,打开对话框,同时取消正常链接点击带来的页面转跳。

如果你想测试一下这项功能,请点击邮件订阅链接。如果你是在博客上阅读本文的话,应该会看到对话框。对话框打开后,记得输入 email 然后订阅哦!

2019年9月14日星期六

Career Coaching 名额报满

Career Coaching 名额报满

我从 2018 年 4 月开始用 Patreon,一开始就设立了两档服务,包括 $100 一个小时的 career coaching 服务。我在 2018 年 6 月有了第一个学生,接下来花了一年多的时间,到 2019 年 9 月才把我的五个学生名额招满。我在 9 月 10 日晚上发了一条 tweet,说我又开了五个新的名额,只是打折少了,价格提高到 $150 一个小时。(我在知乎上也发了同一条消息。)

完全出乎我意料之外的是,在短短的 24 个小时之内,这五个名额就被报满了!这真的是让我非常的震惊,因为上一批的五个名额花了一年多才被报满,就算用户增长存在加速度,也应该要花好几个月才会被报满啊。我完全没有预料到用户增长的加速度会如何巨大!

超级感谢大家对我 career coaching 项目的支持,尤其是学生们对我的支持,这包括想报名但这次没有抢到名额的学生们。没有大家的支持,就没有这个项目的快速成长。在这个项目上,我有机会接触到大家在 career 不同阶段遇到的问题,然后尝试为跟大家一起解决这些问题,这其实是非常有意思。

接下来我会花一段时间来观察迅速增加无名学生对我时间开销的影响,然后再决定是否能够开放更多名额以及开放多少名额。如果你想报名但没抢到名额,欢迎你到 Patreon 上来 follow 我,保证我开放新名额是你能够第一时间获取到资讯。此外,通过邮件RSS/Atom 订阅我的博客也能收到消息。

2019年9月13日星期五

博客文章阅读分析

最近在和朋友研究做什么样的 podcast(纯音频)节目内容合适,于是分析了一下自己曾经写过的内容哪些比较热门。以下是对我博客园文章的分析,之所以用博客园,是因为那里的人气最旺,所以统计数字更可靠。


首先我们看一下阅读数量的前十:

我们可以粗略看看这返影读者的什么倾向:首先,读者都比较关心跟自己职业发展相关的话题,所以面试和职业发展路线的文章能够排到前面,擦边相关的英语也正好能上榜。其实,读者对大公司比较好奇,所以头四篇都是讲不同公司面试风格和体验的。最后,科普型的技术内容也偶尔能吸引大量阅读。


接下来我们再看看评论数量的前十:

这跟阅读数量的前十有 40% 的重合,意味着这两者存在一定的相关性。从标题上来看,能够刺激用户评论的往往是具备争议性的话题:要么我直接抛出一个非常逆主流的观点,要么我提一个宽广的问题。这两者都能很好地刺激读者通过评论发表他们自己的观点,前者会带出主流观点来和我争论,后者会给每个人空间来陈述他们独有的经历。总的来说,其实很多读者是有自己的观点的,文章更多是设立一个巨大的舞台,让读者觉得自己的观点是相关的,于是上来展现自己的观点。


综上所述,要吸引读者阅读和评论,内容最好能覆盖到以下一个或多个要素:

  • 跟读者职业发展相关
  • 满足读者对行业(尤其是大公司)的好奇心
  • 科普型的信息
  • 逆主流(contrarian)的观点
  • 广阔的话题

这会成为接下来我们研究 podcast 节目方向的依据。如果你好奇我们在做什么 podcast,或想在我们发布后第一时间知道,欢迎通过邮件RSS/Atom 订阅我的博客。

2019年9月12日星期四

《牛油果烤面包》播客开播!

我跟朋友做了一个播客,名叫《牛油果烤面包》。我们两个主持人都是湾区科技行业工作者,我们喜欢在一起聊聊现在的行业趋势,于是我们开了一个播客跟大家一起聊。

我们的第一期节目趁着 Apple Special Event 发布,聊聊我们对 Apple 新品的看法,顺便蹭个热点。以下是我们这一期节目,欢迎直接点击收听。如果你喜欢的话,请记得订阅哦,我们下周就会发布第二期节目。

如果你使用 Spotify,也可以在 Spotify 内收听,这样会更方便你订阅及在通勤时收听。如果你使用其它 podcast apps,你可以直接通过《牛油果烤面包》的 RSS 进行订阅,主流的 podcast apps 都支持手工添加 RSS 进行订阅。(此时此刻,我们的节目还不能在各大 podcast 平台内搜索到,因为这些平台的发布和审核需要时间。)


说一下我们这个《牛油果烤面包》这个节目背后的故事吧,首先说说这个名字是怎么来的。我们昨天刚刚录制了第一期节目其实不是原计划的第一期话题,而是我突发选择的 Apple Special Event 蹭热点节目。我们在吃早餐时还没定下来名字,于是我朋友就说:「既然要讲 Apple,我们就学习 Apple 当初命名的方式来为我们的节目命名吧。你刚才点了什么?」我刚刚点了一个 advocado toast,于是我们就有了《牛油果烤面包》这样的名字。

我们在订好名字之后,我就决定要搞一个 advocado toast 的封面。我有两个想法,一个是拍一张 advocado toast 的照片,另一个是画一个 advocado toast 样子的图标。碰巧我今天冰箱里还真有 advocado,于是我决定早餐就做一份 advocado toast 然后拍下来,这就成了我们现在封面照片。如果你要问照片里的 advocado toast 去哪里了,我会指着我的肚子说「在这里」。

为了做这个节目,我们之前做了一些研究,考察哪个播客平台更好。因为我们不确定这个节目能做多大,只是想要低成本地快速启动,所以我们选择了最近刚刚被 Spotify 收购了的 Anchor。我自己比较喜欢 Anchor 的理念:现在的云存储价格已经如此之低,每个月收你 $10 甚至更多来帮你存储和发布音频文件其实很不合理,因为这个价格远超出实际的成本,所以应该提供一个免费平台给大家发布播客,然后再通过广告或其它方式进行营收和分成。

说起来 Anchor 这个平台有点像是专门为 podcast 打造的 YouTube,首先为大家提供免费的工具和存储空间,鼓励大家创造内容,然后等大家有流量后再盈利和分成。跟 YouTube 起步时不一样的是,podcast 市场已经有非常多固定的玩法,例如主流的 podcast apps 都有自己的内容平台,你自己默默发布一个新的节目别人都不会收录自然也就没有听众。Anchor 为了解决这个问题,提供自动发布到各个平台的功能。这个功能好不好用暂时还不知道,因为各个平台都要独立审核新节目,尽管 Anchor 已经把我的节目推给这些平台了,但现在还没有审核结果也不知道是否会出问题。(由于此时此刻除 Spotify 外各大平台还没有收录我们的节目,所以还是要麻烦大家手动订阅 RSS。)

Anchor 的坏处是不支持团队播客,也就是说不能几个个人帐号共同管理一个节目。Anchor 必须是一个帐号就一个节目,为此我们专门注册了一个共用的帐号来管理这个节目。如果我们以后要开更多节目的话,我们必须注册更多帐号。(希望到后 Anchor 已经支持一个帐号管理多个节目。)

当然我们先不管那么多啦,任何项目要上马都要趁着初期有势头赶紧上,希望我们能够趁着第一期节目把我们录制、编辑和发布的流程定下来,之后我们就可以重复这个流程可持续地发布节目了。等节目做得越来越好,听众越来越多了,再想办法优化流程,到时候再重新评估 Anchor 是不是最适合的平台吧。


虽然我们的节目发布在 Anchor 上,也有自己的 RSS。但我也不介意在自己的博客 RSS 上带上同样的音频内容,希望这样能让更多人接触到这期节目,希望更多人因此而选择在自己常用的 podcast app 内订阅我们的节目。如果你想要订阅我的博客本身,你可以选择通过邮件RSS/Atom 进行订阅。

2019年9月9日星期一

Echo Auto 试用体验

Echo Auto 暂时还不完全公开售卖,需要向 Amazon 申请邀请,被选中后才能购买。我 2018 年 9 月申请的,等待了差不多一年,上个月终于收到邀请了。Echo Auto 零售价为 $50,我们这种早期用户可以半价购买。

Echo Auto 的安装非常简单。它提供了夹住空调出风口的架子,其作用跟同类型的手机架差不多,直接插进空调出风口夹住就行。架子通过磁贴吸住 Android Auto,然后接上 Micro-USB 的电源就能启动了。(Echo Auto 附送上述架子、Micro-USB 电源线和一个双 USB 的车载电源。)

Echo Auto 启动后就可以跟手机上的 Alexa app进行配对了。我在这个流程中折腾了两次,第三次才搞好了。第一次,是搜了很久也没搜到 Echo Auto 这个设备。第二次,连上后 Echo Auto 会调用你的手机播放一个欢迎的音乐,这个音乐应该通过蓝牙在车载音响中播放出来,Echo Auto 听到后就能计算播放声音的延迟。因为当时我车载音响的音量不大,Echo Auto 没听清,就卡住了。第三次,我把音响调到最大,把自己吓了一跳,但终于配对通过了。

配对后 Echo Auto 会出现在 Alexa app 的 Echo 设备列表上,有意思的是 Echo Auto 被分类到「附件」那里去了,而不认为只一个独立的 Echo 设备。在使用了一段时间后,我才明白到为什么这样分类。

Echo Auto 试用体验

在汽车启动后,Echo Auto 会启动并自动通过蓝牙连接手机,之后就可以如同操作其它 Echo 设备一样用「Alexa」唤醒它并进行语音对话。跟 CarPlay 和 Android Auto 类似,这些语音对话其实都是在手机上进行处理的,需要使用网络时也都是使用手机的网络,所以本质上 Echo Auto 只是一个更好的麦克风:第一,它可以在你的手机没打开 Alexa app 的时候通过「Alexa」来唤醒;第二,它比手机的麦克风更适用于收听来自车内的语音命令。

Echo Auto 接收到指令后,后台实际处理的还是 Alexa app,本质上跟打开 Alexa app 然后进入语音界面再发布命令没有区别,但省去了上述手动步骤。在对着 Echo Auto 呼叫「Alexa」后,手机前台的 Google Maps 可以继续导航,手机后台的 Music app 可以继续播放音乐,Alexa app 会降低音乐的音量以便收听指令并播放回复。Echo Auto 的优势就在于这两个地方:第一,不需要用点击屏幕,增加驾驶安全;第二,不影响手机上正在运作的 app。


我在使用了几周之后,发现 Echo Auto 拥有一些比其它 Echo 设备要好的使用场景,但使用频率还是不够频繁。

第一类使用场景是「出门后才想起来忘记要做的事情」,例如说「灯都关了吗?」或者是「让 Roomba 吸尘吧」。这些事情可以对应的 app 来做,不过有 Echo Auto 后我喊一句就可以了,不需要在屏幕上操作。

第二类使用场景是控制音乐、podcast 和 audiobook 的播放。因为我的车没有 CarPlay 或 Android Auto,所以我通常要在开车前在手机上选好播什么。有了 Echo Auto 之后我就可以喊它来帮我了。这意味着 Echo Auto 跟 CarPlay 和 Android Auto 是直接竞争关系,如果我换一辆新车,我就不需要 Echo Auto 了。(现在也有在老车上加装 CarPlay 和 Android Auto 的模块,但价格比 Echo Auto 贵很多。)

第三类使用场景是控制导航,准确来说是查找新的导航目标。Echo Auto 可以让 Alexa app 去搜索一个新的地点,然后在 Google Maps 里面打开这个地点,但我还是需要点一下才能开始导航到这个地点。我不能使用 Echo Auto 来调整当前的导航,例如帮我在路线上搜索一个加油站,这还是要用 Google Maps 内置的 Assistant 来完成。

综上所述,Echo Auto 如果 $25 卖给那些没有 CarPlay 和 Android Auto 的车主,我觉得还是值得的。($50 就有点贵了。)现在有一个几年的窗口给 Echo Auto 发展,如果找不到跟 CarPlay 和 Android Auto 竞争的突破口,等新车都装上了 CarPlay 和 Android Auto,那 Echo Auto 就没有存在的意义了。


如果你对同类的科技产品感兴趣的话,欢迎通过邮件RSS/Atom 订阅我的博客。如果你想支持我写作的话,欢迎到 Patreon 付费,每个月 $1 就能让你提前阅读我的文章。

2019年9月7日星期六

推送的四种类型:中断、提醒、任务、垃圾

iOS push notification

一年之前我曾经在英文博客发表了一篇《Divide Notifications into Interrupt, Reminder and Backlog》,现在我觉得可以补充一下并翻译为中文版。我实际需要解决的问题是信息过载,尤其是手机上各种应用推送而来的信息。很多这些推送信息其实并不需要我实时处理,但如果它们展现的方式都如此类似的话,我就会习惯性地实时处理它们,例如说看看不重要的邮件和 Facebook 更新,结果浪费很多时间。

为了解决这个问题,我把所有的推送系统化地划分为 4 个类型:

  • 中断:我不能错过这种类型的推送,看到后可能会中断我手头上正在做的事情。这种类型的推送应该是极其罕见的。举例:关键人物发送给我的消息。
  • 提醒:在恰当的时机(例如恰当的时间和恰当的地点)提醒我做某件事情。举例:日历和待办事项的提醒。
  • 任务:可以积压的任务,不需要立即处理,甚至长时间不处理也不会有问题。举例:Facebook 内提醒和绝大多数 Gmail 的邮件。
  • 垃圾:广告之类的垃圾信息,最好完全不要出现。举例:国内应用很常见的各种活动和推广信息。

因为在 iOS 里面只能针对 app 来设置推送,所以不可能对所有的推送进行完美的分类,只可能针对 app 来做分类。我的目标是让这 4 类推送的体验产生明显地有所差别,使得我能习惯性地针对不同的推送做不同的事情:

  • 中断:iPhone 和 Apple Watch 上有声音,静音情况下有震动,未处理的话可以在应用图标上显示未读数量。
  • 提醒:iPhone 和 Apple Watch 上有声音,提醒时需要提供「snooze」按钮让我推延这个提醒。
  • 任务:iPhone 上没有声音,静音情况下不震动,不在 Apple Watch 上出现,不在应用图标上显示未读数量。
  • 垃圾:禁用推送,不显示未读数量。

做了这样的设置后,我能够减少我浪费在手机上的时间。

很多推送由于没有声音没有震动而不再可能获得我的实时关注,只有在我闲下来的时候我才会去看有什么。这对于我的一对一面谈非常有帮助,我不再会因为推送而分神,我可以专心跟别人聊完了,再回头看我收到了什么推送。如果我在一对一面谈过程中知道有新的推送,就算我不看,我也会分神去想一下这可能是什么推送,那对方的体验就很不好了。

这些同送同时由于关闭了未读数量,我不会再浪费时间去查那些有未读数量的应用,只有我真的觉得有需要从应用里面获取信息时我才会去打开它,否则我就忙别的事情去了。举例来说,我不再会因为 Facebook 或 Gmail 上显示的数字而想要打开应用,因为这个数字消失了,心里就变得平静很多。

以上是我应对信息过载的方案,如果你有不一样的方案,或者遇到了类似但又不完全一样的问题,欢迎在评论区进行讨论。如果你喜欢我写的文章,欢迎你在 Patreon 上付费支持我。如果你对我的博客感兴趣的话,欢迎通过邮件RSS/Atom 进行订阅。

2019年9月5日星期四

薅 Amazon No-Rush 羊毛

首先让我来简单介绍一下 Amazon No-Rush 是如何操作的,然后再介绍如何薅羊毛。

假设你在 Amazon 购买的商品符合免费当天、一天或两天送达,在结帐时 Amazon 会让你选择送达速度。你可以选择上述免费快速送达,但你也可以选择一个叫做 No-Rush 的选项,意思是主动放弃免费快速送达,改为需要一周时间的慢速送达。为了鼓励大家使用慢速送达,No-Rush 的选项伴随着奖励机制。只要你选择了 No-Rush,在商品发货时你可以得到对应的奖励,例如 $1 的数字商品(Kindle 书、电影等)折扣或 $5 Prime Now 折扣等。(具体你能得到哪种奖励,你需要在结帐流程时看看,每个人能得到的类型不一样。)

如果你要在 Amazon 购买多件商品,并且:

  1. 在结帐时 Amazon 显示这些商品能一起送,也就是一个 package 而不是分开多个 package。
  2. 其中至少一件商品就算单独购买也能符合免费快速送达。

这时候你可以一件一件商品分开结帐,除了上述那一件商品外其它商品都选择 No-Rush。这时候你会在 Amazon 产生多张订单,然而 Amazon 系统内部会对此进行优化,把所有的订单合并到一个 package 内,降低 Amazon 的送货成本。这个 package 内有一个商品需要快速送达,所以整个 package 会被快速送达,但你能得到其它商品的 No-Rush 奖励。

举个例子,假设你要买三件商品,它们都符合「超过 $35 就能 Free Prime Same-Day Delivery」,它们的价格分别是 $35、$25、$10。如果你可以使用 Free Prime Same-Day Delivery 购买 $35 那一件,然后剩下两件分作两张 No-Rush 的订单处理,这三件商品还是会在同一个 package 里面同一天送达,但你能赚到两个 No-Rush 奖励。

如果你对我的博客感兴趣的话,欢迎通过邮件RSS/Atom 进行订阅。如果你对这个话题有什么问题或者观点的话,欢迎对本文发表评论。

2019年8月30日星期五

2019 年邀请链接(referral links)

一年时间过去了,又到了无心工作只想玩乐的夏季。跟去年一样,针对我用过且觉得好用的服务,我提供它们的 referral link,如果你使用它们注册的话,你和我都能获得到一些好处。我会简单介绍每项服务是做什么的以及为何我觉得好用,你可以看看是否符合自己需要。

我今年推荐的服务包括:

  1. Robinhood
  2. American Express Platinum Card
  3. Stitch Fix
  4. Wealthfront

以下是它们的详细介绍。

Robinhood

Robinhood 是一个免费交易股票的平台,跟其它老牌股票交易平台最大的不同就是完全没有手续费!(此前以低手续费著称的 Charles Schwab 每笔交易收 $4.95 的手续费。)这也正是我喜欢它的地方。

我主要的投资手段是基金,股票只是拿来练手的,所以只放了几千块钱在 Robinhood 里面。我不希望手续费影响我是否做一笔交易,同时我的单子不会大到能够完全无视交易费,所以我选择使用 Robinhood。

如果你使用我的邀请链接的话:

  • 你得到的好处:免费获得一股随机的股票,价值在 $2.50 到 $200 之间
  • 我得到的好处:免费获得一股随机的股票。累积总额达到 $500 后我将不能再获得免费股票。

邀请链接:http://chen.cat/robinhood-invite

American Express Platinum Card

Amex 白金卡的好处:

  • 酒店和机票 5 倍积分。(酒店必须在 Amex Travel 上订,机票必须在 Amex Travel 或航空公司官网订。)
  • 免费使用机场贵宾室,包括 Amex 自己的贵宾室及任何接受 Priority Pass 的贵宾室,且可以免费携带两名亲友。
  • 每年送 $200 用于航空公司小额消费。(不能用于机票,只能用于各种服务消费或各式各样的 fee。)
  • 每年送 $200 用于 Uber 及 Uber Eats,每个月 $15,十二月额外多 $20。
  • 每年送 $100 用于 Saks Fifth Avenue,上半年下半年各 $50。
  • 每五年送 $100 用于 Global Entry 或 $85 用于 TSA Pre-Check。

Amex 白金卡的坏处也很明显,就是 $550 的年费。不过我们算一下,如果上述免费赠送的金额都花光的话,这 $550 差不多也就回来了。之后如果多出差多旅游的话,机场贵宾室和 5 倍积分都是额外的好处。

如果你使用我的邀请链接的话:

  • 你得到的好处:没有。
  • 我得到的好处:在你成功申请信用卡后,我能获得 $100。

邀请链接:https://chen.cat/american-express-invite (这个邀请链接会显示所有的 Amex 卡,打开后你需要手动选择白金卡,或者是其它你想要申请的卡。)

Stitch Fix

Stitch Fix 是一个帮你搭配衣服的服务。注册时它会让你填写众多衣服尺码和喜好的信息,多到简直让人想要放弃注册。然后它会根据这些信息帮你挑选 5 件单品并邮寄给你。(在它帮你挑选前,你可以留言说明一下有没有什么你特别想要的。)

在收到包裹后,你可以试穿然后决定 5 件中哪些你想要留下哪些你想要退回去。如果你 5 件都要了,全单 7.5 折;如果你 5 件都不要,你需要给 $20 的最低消费;否则你只需要对你要的那几件买单。(Stitch Fix 有一项服务叫做 Style Pass,一次性给 $50,购买一整年的服务。在这一年里,每个包裹不再有 $20 的最低消费,全年一次性的 $50 最低消费可以在任意多个包裹里抵消掉。)

我今年买了 Style Pass,然后选择了让他们每个月给我寄一个包裹。有时候包裹里没有任何一件是我想要的,但也没所谓,最重要是节省了我去逛街买衣服的时间,我在家里试穿就可以了。这是我喜欢 Stitch Fix 的原因。

如果你使用我的邀请链接的话:

  • 你得到的好处:$25,用于首次消费。
  • 我得到的好处:$25,用于下次消费。

邀请链接:http://chen.cat/catchen-stitchfix-invite

Wealthfront

Wealthfront 提供投资账户和储蓄账户两种功能:

  • 投资账户是一个 robo adviser,你把钱放进去,它帮你管理 portfolio,买进股票、债券等 ETF (Exchange-Traded Fund)。具体回报率跟你选择的风险等级相关,风险系数越高股票占 portfolio 的比例越大。
  • 储蓄账户也就是 savings account,提供超高的利率(此时此刻 APR 是 2.32%)。必须至少投入 $5000 注册投资帐号后才能使用储蓄帐号。

Wealthfront 的投资帐号有管理费但储蓄帐号没有。投资帐号中的资产头 $10k 是免管理费的,之后是每年 0.25%。也就是说,如果有 $20k 资产在里面,头 $10k 免费然后之后的 $10k 每年收 $25($10k * 0.25%),然后分摊到 12 个月来收,每个月 $2 多。

我用 Wealthfront 的原因是它储蓄帐号的利率足够高(虽然此时此刻不是市面上最高的)。考虑到现在股市可能在高位,我个人并没有把太多钱存放在投资帐号里,现在更多的是把闲钱放到储蓄帐号里。如果哪一天股市大跌,我就可以在 Wealthfront 里面迅速把储蓄帐号的钱挪进投资帐号,趁低买入。

如果你使用我的邀请链接的话:

  • 你得到的好处:免管理费资产额度增加 $5k,也就是说注册帐号就有 $15k 免管理费资产额度。
  • 我得到的好处:免管理费资产额度增加 $5k。

邀请链接:http://chen.cat/wealthfront-invite

最后,如果你对我的博客感兴趣的话,欢迎通过邮件RSS/Atom 进行订阅。如果你对这个话题有什么问题或者观点的话,欢迎对本文发表评论。

2019年6月14日星期五

使用 AppleScript 批量发送带附件的邮件

最近某人要代表学校批量发送邮件欢迎新生,而且有几个特殊的要求:

  1. 邮件必须每个人独立发一封,因为给每个人的邮件要正确的称呼这个人的名字。因此邮件必须批量发送,而不能够以 bcc 的形式一封邮件发给所有人。
  2. 邮件需要带上附件。
  3. 邮件没办法提供「退订」链接。这导致我们不能够使用 MailChimp,因为 MailChimp 根据法律要求邮件列表必须提供退订链接。

为此我想到了用 AppleScript 来控制 Mac 上的 Mail 来批量发送邮件。搜索一番后,写出如下的 AppleScript 来:

在这个 AppleScript 里,我通过 theRecipients 提供一个姓名及邮件的列表,然后打开系统对话框选择一个用作附件的邮件,接着利用循环逐一发送邮件。代码里面最 tricky 的一行是 delay 1,如果没有这一行代码附件会添加失败,但邮件文本会被发送出去。我也无法解释为什么会这样子,使用 delay 1 是我从网上搜索回来的解决方案,如果你知道为什么要这样做,请在评论告诉我。

最后,现在 AppleScript 的文档实在难找。例如说我想找 Mail 支持的所有 AppleScript 操作现在已经找不到了,Apple 网站上一些原有的 AppleScript 文档链接已经失效。现在能做的也就是看着别人过去留下的 AppleScript 自己慢慢摸索。如果你有更好的 AppleScript 文档,请在评论分享一下。

2019年6月5日星期三

Patreon 付费读者交流群

如果你是我的 Patreon 付费读者,你现在可以加入付费读者专属的 Discord 交流群。加入办法很简单:首先,如果你还没有 Discord 帐号的话可以先注册一个;然后,你可以在 Patreon 的 App 设置页关联你的 Discord 帐号。接下来 Patreon 会自动利用 Discord bot 把你添加到我的 Discord 服务器及对应的付费读者专属群。(这是此功能的 Patreon 官方帮助。)

如果你还不是我的付费读者,你可以使用邀请连接加入我的 Discord 服务器。相对于非付费读者来说,付费读者享受以下两项福利:

  1. 付费读者能够加入到我服务器上的 #early-reader 群,我会在上面跟大家讨论任何跟我文章相关的问题。
  2. 付费读者拥有高亮的用户名,在我服务器上的开放群拥有更高的可识别度。

如果你现在还不是我的付费读者,欢迎通过我的 Patreon 成为付费读者。现在付费读者有两档:

  • Early Reader: 每个月 $1,能够比其它人提前一个星期读到我发布的文章。如果你喜欢我写的文章,这是支持我写作的最佳途径。
  • Career Coaching: 每个月 $100,我每两周跟你面谈 30 分钟(面对面或视频),对你的职业成长进行辅导。如果你是从事互联网和科技相关的工作,或者你计划毕业后从事相关工作,我们可以试着聊一下看看我对你的职业成长是否能够提供帮助。

最后,如果你是非美国用户,觉得 Patreon 付费不方便(例如说不接受你的信用卡或你没有美元信用卡),请在评论留言告诉我,我会想办法提供其它付费方式。感谢大家对我一直以来的支持!

2019年4月19日星期五

如何重置 macOS 的蓝牙模块

问题现象

我买了新的 Bose QC35 II 主动降噪耳机,买的原因是我老的 QC25 不支持蓝牙且磨损到一定程度了。新耳机到手后,跟 iPhone 配对没问题,但跟我的一台 MacBook Pro 就是无论如何也配对不上。通过跟另外一台 MacBook Pro 配对,证明问题发生在这台 MacBook Pro,而 Bose QC35 本身没问题。

无法配对的具体现象是,在 macOS 设置的蓝牙面板中无论如何也搜索不到 Bose QC35。(而且也搜索不到周边的其他蓝牙设备。但 Apple 自己的蓝牙键盘鼠标之前能正常配对,因为那是通过 Lightning 线配对的。)我尝试过重启 macOS,但依然搜索不到任何蓝牙设备。

解决方案

解决方案就是重置 macOS 的蓝牙。我搜索后发现,老的 macOS(准确来说还是 Mac OS X)需要删除 Bluetooth.plist 来重置,新的 macOS 已经不用那么麻烦。同时按住 Shift 和 Option,然后点击菜单栏上的蓝牙图标,这时候下拉菜单就会显示更多信息,包括一个「Debug」子菜单。打开「Debug」子菜单,然后选择「Reset the Bluetooth module」,并且确认真的要重置,最后重启 macOS,问题就解决了。之后我能在蓝牙面板中搜索到 Bose QC35,配对后播放音乐没有任何问题。

2019年2月26日星期二

把我的个人网站推倒重来(Part 8 - Sitemap)

为了让 Google 更好地发现和索引我的网站,我会使用 Google Search Console 提交 Sitemap。Sitemap 本质上是一个 XML 文件,描述网站包含的网页信息,帮助 Google 了解网站上都有哪些网页,以及这些网页的重要程度和更新频率。(Google 会参考这些信息,但我们不能通过 Sitemap 直接控制 Google 爬虫或排名。)我上一版的个人网站就包含了 Sitemap,所以重新新版本时也会把 Sitemap 加上。

上一个版本的 Sitemap 是我手工维护的 XML 文件,既然新版本的网站使用 Harp 进行编译,我希望 Sitemap 的 XML 文件也是编译时自动生成的。Harp 要使用模板生成 XML 文件很简单,把文件的后缀写成 .jade.xml 就可以了,Harp 从文件名可以推断出这个文件需要使用 Jade 模板来编译,结果保存为 XML 文件。我希望这个文件尽可能不需要手工维护,最好自己根据语言和页面的组合生成所有有效页面的链接。

每一个有效页面背后都有一个同路径的 .jade 文件,例如说 /en/resume 背后存在对应的 /en/resume.jade,这个文件会生成 /en/resume.html,然后 Netlify 会美化 URL 删掉不必要的 .html 后缀。如果我需要找出所有的有效页面,其中一个方法就是遍历项目目录,找出所有这些 .jade 文件,然后把它们的路径映射过去。因为遍历所有目录需要用到递归,我就写了一个 mixin 来做这个事情,原因是 Jade 里面的 mixin 类似于函数,可以自己调用自己从而实现递归。

mixin tree(current, path)
  for value, key in current
    if key === '_contents'
      for file in value
        if /\.html$/.test(file) && !/^\d{3}\.html$/.test(file)
          url
            loc
              | https://catchen.me#{path}#{file.replace(/(index)?\.html$/, '')}
            changefreq
              | hourly
            priority
              if path === '/' && file === 'index.html'
                | 1.0
              else
                | #{public._data[file.replace(/\.html$/, '')].priority}
    else if !/^[._]/.test(key)
      mixin tree(value, path + key + '/')

这个 mixin 接收两个参数,第一个是代表当前目录的对象,第二个是当前目录所在路径。在递归的入口,我会调用 mixin tree(public, '/'),把代表根目录的 public 对象和对应的路径字符串 '/' 传进去,然后这个 mixin 就会遍历所有子目录把所有编译后的 .html 文件找出来。它找到的每一个 .html 文件都会被添加到 Sitemap 里面。

这个 mixin 在把 .html 文件映射为 URL 时,它还做了以下的特殊处理:

  1. 删除 .html 后缀,因为 Netlify 在美化 URL 时也会进行这个操作。如果我们在浏览器中打开 https://catchen.me/zh/resume.html,Netlify 会返回 301 重定向到 https://catchen.me/zh/resume,保证用户看到的是不包含 .html 的路径。
  2. 删除 index 默认文件名,因为 https://catchen.me/zh/index.htmlhttps://catchen.me/zh/ 等价,同样会被 URL 美化删除。
  3. 过滤掉 404.html 等状态码特殊页面,因为这个页面是专门给 Netlify 返回对应状态码时使用的,不应该被索引。

最终的 sitemap.jade.xml 其实并不复杂,记得加上 doctype xmlurlset(xmlns="http://www.sitemaps.org/schemas/sitemap/0.9") 这类必要的元素就行了。编译后立即可以发布到 Netlify,然后在 Google Search Console 进行手工添加 Sitemap。数天后 Google Search Console 就会显示这个 Sitemap 已经被抓取了,然后还能看到 Sitemap 中页面的抓取情况。

这有可能是这个系列的最后一篇文章了,将来如果我对我的个人网站继续有更新,我会继续写这个系列。如果你对我的博客感兴趣的话,欢迎通过邮件RSS/Atom 进行订阅。如果你对这个话题有什么问题或者观点的话,欢迎对本文发表评论。

2019年1月17日星期四

把我的个人网站推倒重来(Part 7 - Google Analytics & Facebook Pixel)

网站上线之后,我自然关心访客的数量和来源,于是我决定加上 Google Analytics。同时纯粹出于好奇,我把 Facebook Pixel 也加上了。

Google Analytics 和 Facebook Pixel 都需要插入 JavaScript 到每一个页面上,因此把代码加到 _layout.jade 是最合适的,因为这是所有页面共享的模板。

Google Analytics

在 Google Analytics 创建好「property」后,复制 Google Analytics 生成的代码到 _layout.jade 其实就完事了。(Google 把独立的每一个网站和 app 叫做「property」,这样使得一个 Google 帐号可以管理多个网站和 app。)

因为我想知道我的网站是否有 JavaScript 出错,所以我特意通过 window.onerrorwindow.onunhandledrejection 事件把错误信息上报到 Google Analytics。如果 Google Analytics 在创建 property 时选择的是网站而不是 app,默认是不会有报告显示 exception 事件的。这时候我们需要手工在 Google Analytics 添加一份自定义报告,然后选择显示 exception 事件,并把 exception message 展示出来。这样我就能看到是否存在 JavaScript 错误,以及具体在哪个页面发生什么错误了。

Facebook Pixel

Facebook Pixel 跟 Google Analytics 类似,在 Facebook 上配置后然后复制粘贴代码就可以了。需要注意的是,一个 Facebook 广告帐号只能创建一个 Pixel,不像 Google Analytics 那样可以创建多个 property。如果需要跟踪多个网站,那就需要创建多个广告帐号,或者一个 Pixel 用不同的事件来跟踪不同的网站。

在配置好 Facebook Pixel 并运行一段事件后,我发现 Facebook Pixel 并不能提供 Google Analytics 那样复杂的分析功能,更多是为了跟踪广告效果和生成广告受众群体。例如说,如果我在我的博客上使用 Facebook Pixel,然后我就能生成一个访问我博客的受众群体,然后在 Facebook 上面向这些受众投放广告让他们来赞我的专页。除此之外,我没有去深入研究 Facebook Pixel 还能做什么别的事情。(如果你知道 Facebook Pixel 还能做什么别的事情,欢迎在评论区讨论。)

搞掂 Google Analytics 和 Facebook Pixel 后,我还想做的是支持 Sitemaps 好让 Google 抓取所有页面。如果你对此感兴趣的话,欢迎通过邮件RSS/Atom 订阅我的博客,关注接下来的文章。