作者归档:白宦成

关于白宦成

独立开发者, 自由职业者, 写作者

2022 年 3 月月度总结

2022 年 3 月月度总结

TL;DR

三月可以说是一个比较悲催的月份了。因为疫情的来袭,整个三月几乎没怎么出门,大部分时候都是在家里躺尸。

疫情之下,没有人能够好过,不过希望我在 4 月能够有所收获。把3 月份拖欠的事情给干了。这样四月份至少看起来还算有所收获。

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

KR1:投资收益达到 20000 元

三月份开始使用有知有行记录自己的投资情况。后续可以通过有知有行来分享自己的投资记录。

但因为三月份中概股的一波大跌,我的美股也受到不少的影响,好在我自己的仓位并不重。所以其实还好。只是说没啥收益,但也没亏多少。

KR2 :单篇稿费突破 6000 元

本月开始又开始写一些少数派的稿子,但约稿没啥变化。今年还需要多写文章,才能提升自己的稿费。

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

今年支出和收入的对比预期

目前总支出还在预算内,但局部的支出确实有所变化,比如我自己在使用的一些软件类产品发生了更新,所以不得不跟着续费。

三月份的交易数据也不少,有 88 笔花钱的地方,还是需要节省!

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

本月此 KR 无进展。

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

KR1:前往 6 个城市旅行

三月因为疫情的原因,哪都没去成,可惜了,一个美好的春天。

KR2:进行 20 次文娱活动

三月没有进行任何文娱活动,四月加油!

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

本月买了一个小米众筹的智能窗帘设备,奈何王老师不让装,就没弄成。

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

KR1:写 15 篇书评

三月读了好几本书,但都没有写书评,记得 TODO 里,本月写吧。

KR2:输出关于加密货币的 Newsletter 12 封

Crypto 相关的 Newsletter 还是没有发,但是我自己的「产品重构计划」确实还在迭代中,希望四月份能发 2 篇 Newsletter。

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

计划中要完成的三本图书已经停掉了一本。另外两本还要继续加油。

主要还是自己的精力不足吧,持续的拖下去也不是一件好事。

在项目中使用  Dead Simple LESS CSS Watch Compiler 来自动生成 css 文件

在项目中使用 Dead Simple LESS CSS Watch Compiler 来自动生成 css 文件

最近在写一个 WordPress 主题来帮助我完成从 WordPress 到微信公众号的实现。在这个过程中,我需要借助于一些 CSS 的超集,来帮助我完成样式的编写。考虑到 SCSS 的 C++ 依赖问题,我选择了 Less 来完成。但如果直接使用 lessc 的话,主要面临的问题在于无法检测文件更新,这样对于需要实时查看效果的我来说,是比较麻烦的。所以我选择使用 Dead Simple LESS CSS Watch Compiler 来完成自动监控文件变化并刷新的功能。

教程

安装

执行 npm 命令来安装 Dead Simple LESS CSS Watch Compiler

yarn global add less less-watch-compiler 

安装完成后,你就可以执行命令来监听文件的变化。

配置

这里为了方便,我在 WordPress 插件目录中初始化了 npm, 因此,可以非常方便的借助于 npm script 来完成命令的配置。

通过配置了单独的 Build 命令,实现了执行 npm run build 就会自动监听 less 文件夹下的文件,并转换成对应的 css 文件,放置在 css 目录中。

{
  "private": true,
  "scripts": {
    "build": "less-watch-compiler ./less ./css"
  },
  "devDependencies": {
    "less": "^4.1.2",
    "less-watch-compiler": "^1.16.3"
  }
}

其他

如果你需要对 less 运行有更多配置的诉求,还可以创建一个 less-watch-compiler.config.json 来配置具体的执行目录。不过我对于这部分没有要求,就直接整个目录来进行配置了。

{
    "watchFolder": "<input_folder>",   
    "outputFolder": "<output_folder>",
    "mainFile": "<main-file>",   
    "includeHidden": false,
    "sourceMap": false,
    "plugins": "plugin1,plugin2",
    "lessArgs": "option1=1,option2=2",
    "runOnce": false,
    "enableJs": true
}

总结

SCSS 因为 node-scss 的编译问题被各种吐槽,虽然换成了 dart-scss ,但历史的阴影还在。选择了 less 后,通过一些配置,可以让我自己的开发变得更加简单。何乐而不为?

你不做的那些事情,造就了你的样子

你不做的那些事情,造就了你的样子

在这个一切事物都十分充裕的时代,我们可以做几乎所有事情。但换个角度来看,我们所做的那么多、那么繁杂的事情,也让我们变得面目模糊,无法被看清。

我常常因生命短暂而感到遗憾,终我一生,难以看完所有我想看的图书、学习我想学习的知识,体验我想体验的生活。但另一方面,我也深刻的明白,正是这种有限的选择,让我们专注当下、专注自我,专注于做好每一件事,每一件小事。

对于每一个人来说,我们在做的那些事情十分重要,如雕塑一般,在做的事情形成基石,为我们打好了基础。而那些我们不做的事情,塑造了我们的样子,剥去我们身上的无用之物,仅留有用之身。

用好传感器带来的产品价值

用好传感器带来的产品价值

昨天在宜家买了个钟表,仔细研究后发现,这个产品的设计非常的有意思,完美的表现出在已有设备加,加入一些小巧的传感器,从而实现一个非常有意思的产品。这也是我觉得当下,我们的互联网产品、软件产品、硬件产品在设计方面所缺乏的。

我买的产品是宜家的 LÖTTORP 洛托普,我买了个百搭的白色表。

初次看到这个表,其实有点其貌不扬,常规的显示屏和四个莫名其妙的 Icon。

正面

背面倒是不错,只有电池仓和两个按钮,十分的简洁。

这个表设计的有意思的点在于他在内部嵌入了一个传感器,通过这个传感器来感知钟表此时的方向,从而实现控制展示不同的功能。通过这样的方式,来实现了在一个钟表当中,集成了多个钟表的能力。

下面的视频,是我自己录制的视频,可以帮助你直观的看到这个设备的操作方式。

配置 Vercel 优化大文件缓存性能

配置 Vercel 优化大文件缓存性能

Excalidraw 是一个非常好用的手绘风格的绘图工具,我给自己部署了一个版本来降低自己写作配图的难度。如果你感兴趣,可以访问 draw.ixiqin.com 体验我自己维护的版本。

白宦成

在配置 Vercel 的中文字体以后出现了一个很大的问题:中文字体文件巨大。因为和英文只有 26 个字母不同,中文想要让常见文字都要放在其中,则需要一个巨大的字库来支持不同文字的展示。也因此使得中文字体远大于英文字体。即使不同的文件类型会有优化,但近 100 倍的文件大小差距还是会让整个应用加载速度极慢。

不过,好在字体是一个相对稳定的文件, 不会经常变化,因此我们可以借助浏览器和 HTTP 协议中设计的缓存能力来优化体验。通过对较大的字体文件进行持久缓存,来确保非第一次加载后的使用体验。

Cache-Control

 Cache-Control 通用消息头字段,被用于在http请求和响应中,通过指定指令来实现缓存机制。缓存指令是单向的,这意味着在请求中设置的指令,不一定被包含在响应中。

想要实现对于文件的缓存控制,少不了使用 Cache Control 头来进行控制。以我为例,我为这些字体配置的 Cache Control 的值为 public, max-age=31536000, immutable,这意味着:

  1. 我的字体文件可以被人任意对象缓存(public):这样 Vercel 的 CDN、用户的浏览器都会帮助我将字体文件进行缓存,提升访问的体验。
  2. 我的字体文件要缓存 365 天(max-age=31536000):我的字体文件可以缓存一年(实际上更长都无所谓,因为字体不会经常变化)
  3. 不主动发起校验请求(immutable):如果浏览器支持,则在读到 immutable ,不会再向服务器发起校验请求头(比如 If-None-MatchIf-Modified-Since)。关于这个属性,可以参考 https://datatracker.ietf.org/doc/html/rfc8246

经过上述的配置,在标准的浏览器中,当他们处理到我的字体文件时,就会将字体文件进行缓存,留存至本地,并在用户显式清理缓存之前,始终使用缓存中的字体文件来进行加载,从减少需要从服务器端加载的文件的数量,提升网站的访问体验。

在 Vercel 中配置

在 Vercel 中如果需要控制不同的文件的 Header,则需要修改项目根目录下的 vercel.json 文件,在其中配置 headers ,匹配要处理的文件,并设置特定的 Header。

{
  "public": true,
  "headers": [
    {
      "source": "/(.*).(ttf|otf|woff2)",
      "headers": [
        {
          "key": "Cache-Control",
          "value": "public, max-age=31536000, immutable"
        }
      ]
    }
  ]
}

具体代码可以参考:https://github.com/bestony/excalidraw/commit/50e48fd054ccb5fe6e8fe302d135e8f643ed20eb

为 Excalidraw 添加中文手写字体

为 Excalidraw 添加中文手写字体

Excalidraw 是一个非常好用的手绘风格的绘图工具,我给自己部署了一个版本来降低自己写作配图的难度。如果你感兴趣,可以访问 draw.ixiqin.com 体验我自己维护的版本。

白宦成

我在使用 Excalidraw 时,最大的的问题就是没有中文的手写字体,这也是促使我自建的一个重要的原因。

效果

中文手写字体我选择的是 小赖字体 ,小赖字体可以免费商用,对于我这样的用途来说,更加的安全。

原理

实现的原理并不复杂,在页面中引入对应的字体文件,并为对应的字体设置对应的 Font Family 即可。

添加字体

在 Excalidraw 中添加字体,需要在 public 目录中加入你的字体文件,并在 public/fonts.css 中添加对应的字体引入,这样后续你的应用中就可以使用对应的字体来进行绘图。

需要注意的事,这里的 Font-Family 的值不要瞎填,后续会用到。

@font-face {  
	font-family: "XiaolaiSC";  
	src: url("XiaolaiSC-Regular.ttf");  
	font-display: swap;
}

此外,为了让浏览器可以提前加载字体,还可以在 public/index.html 中添加如下代码来实现预加载。

<link rel="preload" href="XiaolaiSC-Regular.ttf" as="font" type="font/ttf" crossorigin="anonymous" />

添加常量

在 Excalidraw 中,组件使用的字体被定义在 src/constants.ts 中的 FONT_FAMILY 常量中,你需要在其中添加相应的 Font。这里就会用到你刚刚填写的 Font Family

export const FONT_FAMILY = {
    Virgil: 1,
    Helvetica: 2,
    Cascadia: 3,
    XiaolaiSC: 4, // 这一行是新增的
};

在控制台上添加对应的调用

当你完成了这些基本的配置后,最后就简单了,只需要在 src/actions/actionProperties.tsx 中的 actionChangeFontFamily 中添加对应的 value 即可实现新字体的引入。

{
    value: FONT_FAMILY.XiaolaiSC,
    text: "小赖字体",
    icon: <FontFamilyLaiIcon theme={appState.theme} />,
},

参考代码:https://github.com/bestony/excalidraw/commit/f308dc32a958e4cb4fb4658cd9a5c9a19ad6d683

不要内部创业,内部创业只会让你不幸

不要内部创业,内部创业只会让你不幸

作为公司内的员工,你可能会被激励员工的“内部创业”所打动。但你要知道的是,你可以做内部创新、可以在螺狮壳里造道场,切不可在其中投入你的感情和心力。

这里的矛盾在于,你使用公司的资源做内部创业,你所有的产出,其实是归属一公司所有的。你可以用公司内部创业的路子去做所有你不那么看重的事情。但如果你真的看重一件事,且愿意为之付出极大的心力、劳力,那么一定要跳出来自己做。

跳出来,还有生的可能,留在企业内部,一定会死。

原因很简单,随着业务的高速发展、团队的扩大,创始人提供的价值会越来越少,慢慢跟不上自己的团队的迭代。这个时候公司有几个选择:

  1. 换一个负责人,你出局,不给你任何补偿,但业务可以更好的活下去
  2. 不换负责人,让你继续做,但可能业务慢慢挂掉。
  3. 换负责人,并给你一些赔偿:别想了,你以为是自己创业的么?公司怎么可能给你补偿。

这种变化,如果不是你心爱的产品还好,但如果是你心心念念的产品,一次就够你万念俱灰了。

既然都是风险,干嘛不出来做呢?

从另外一个角度来看,因为你是「内部创业」,那么你就必须遵循企业的大规范。如果企业的战略有调整,作为企业战略当中的一份子,你的业务必须被砍掉的时候,你应当如何自处?自然是跟随企业的战略调整,不然还能怎么办?

最后的结论你会发现,还是自己出来干最省心。

为什么我选择放弃生财有术?

为什么我选择放弃生财有术?

今天,我想和你聊聊我从 2020 年开始加入生财有术,到 2021 年续费,再到 2022 年决定停止续费的心路历程。

心路历程

怀疑期(加入生财有术前)

在 2020 年之前,我其实是对生财有术不感冒的。和大多数人一样,我的理解是「既然有赚钱的事情,你为什么不留着自己做,而要分享出来」。

这也是生财有术在很长一个周期上在面对的外界的指责。

认可期(加入生财有术之后)

加入生财有术源自于一个契机,我朋友圈的老朋友,工程师,技术总监 —— 朱鹏飞同学在朋友圈发了生财有术的推广,于是乎我想了想,基于对他的信任,加入了生财有术。

我的目的也非常明确:我自己是一个工程师,是一个创造者。我擅长的是创造一个东西,而不是把一个东西推广的更好。生财有术中的经验贴可以帮助我看到别人是怎么思考同一个问题的,可以为我补充更多的信息。

于是乎,我在生财有术开始疯狂的了解信息,还参与了深圳和北京的活动,还因为一次轻享,获得了一颗龙珠,加入了龙珠群。

生财有术提供了我想要的信息,帮助我理解了不一样的世界,看到了不一样的选择。

在这个阶段,我也领悟出为什么有的人愿意分享自己的心得给别人,总的来说,其实是「我知道这个东西能赚钱,但是这个钱太少了,我懒得做,顺手发给你也行」

基于这个思路,我还启发了一个人做了保罗 · 格雷厄姆的中文站点

反思期(现在)

但到了 2022 年,我为什么开始选择离开?其实核心点在于我意识到,生财有术提供的价值对于我来说,开始逐渐发生了变化。以及价格的上涨对于我来说,意味着 ROI 不符合预期。

一方面,生财有术开始从提供信息,到提供更加丰富的活动和交互转变。虽然依然会有提供信息,但对于我来说,活动所带来的溢价对我没什么价值,我并不太需要持续参与一个活动。

另一方面,得益于知识星球的机制,即使我不再续费,我依然可以看到之前我买的内容。现有的 3000 多篇精华我都没看完,完全不着急续费。

从这个角度来看,知识星球真的不错。

不适合我,那适合谁?

在写这篇文章的时候,我也在想,既然不适合我了,那适合谁?毕竟,生财有术是一个社群,不可能适合所有人。

先说说为什么不适合我:我自己是有一些明确的标签的「工程师」、「创作者」,本身有在做个人品牌影响力方面的事情。对于我来说,我需要的是补充信息,丰富自己的品牌。当现有的信息已经无法处理的情况下,那么我完全没必要马上获得更多的新信息来满足自己 FOMO 的情绪。我需要的不是去发展更多的横向业务,而是让自己在纵向业务上发展的尽可能好。所以短时间来看,生财有术并不能提供我所需要的东西。

再说说适合谁:

  • 拥有自己业务的老板:我在生财有术的龙珠群里,里面有不少专家达人,如果你加入龙珠群,完全可以在其中达成一些合作,促进更好的业务的发展。
  • 没有自己形态的普通人:除了老板,绝大多数人是普通人,普通人的坏处是没什么特点,但好处是也有塑造的机会,而 2022 年生财有术会有不少的训练营和大航海、小航海,正适合普通人先抓住一个机会上车。

总结

唠唠叨叨这么多,总体来说,就是一句话 —— 不匹配了。但不匹配我,不意味着不匹配你,如果说上面我描述的这些你觉得符合你的诉求,那生财有术依然是一个符合你预期的社群。

如果看了这么多,你觉得生财有术适合你,那就大胆扫码加入吧!

关注用户的长期价值,而不是短期价值

关注用户的长期价值,而不是短期价值

在进行互联网产品设计时,常常会说,「我们要关注用户价值」,但似乎落实到现实中,大家都默认选择了一个更短时间的价值 —— 用户走过我的摊位,我要产生多大的交易额?用户访问了我的网站,给我产生了多少的收入?

多年「羊毛出在狗身上」的免费互联网模式,让我们下意识以为,我们只有「羊毛出在狗身上」才能够赚钱,我们不得不从流量大潮中分流出一部分,经过过滤,再将其回归到流量的大潮里。

这个思维有一个最大的问题是:我们提供给用户的价值是短暂的,是会停止的。但实际上,一个用户可能是会持续的使用你的产品的,在这个过程中,你是完全有可能在一个更长的周期产生出更大的价值。

不过这里也有一些问题在于,为什么过去的产品不会太过于关注这个问题?一方面是品牌建设并非绝大多数产品会考虑到的,甚至很多产品直到产品火了,才开始关注到品牌建设。另一方面是更长期的模式需要损失短期的收益,对于企业和产品来说,能否扛到看到长期收益是个问题。

不过,对于独立开发者而言,完全可以猥琐发育,直到看到产品的长期价值。

关于「竞争」,给年轻人的一些建议

关于「竞争」,给年轻人的一些建议

很抱歉,虽然我年纪稍长,对于很多人来说,都还是一个小朋友,但依然要用一个非常老气横秋的口气来和你讨论关于「竞争」这个话题。因为有太多的人来问我关于竞争的问题。我不得不选择将我的观点和建议整理成一篇文章,以减少我重复介绍自己观点的次数。

竞争中的软门槛与硬门槛

在竞争中,常常被大部分人忽略的是,竞争并非是静态的。实际上,由于竞争中存在的软门槛和硬门槛的不同,使得竞争往往是动态的。

竞争中最常见到的是硬门槛,也是我们一般而言,给到新人的建议 —— 你必须去做某些事情,不然你就会付出极大的代价。比如,最常见的是,我们给到每一个年轻人的建议是你应该读完本科。如果你是专科,那就努力专升本。或者想办法走成人高考,获得一个本科的文凭。

应聘中的软门槛和硬门槛

硬门槛的意义在于它真的可能在关键问题上,阻止你进行下一步。比如说,对于航天科技的核心工程师来说,相关专业的文凭就是硬门槛,如果没有对应的文凭,相关的企业和单位是不敢录用你的,因为你完全可能为航天事业埋下后患。

除了硬门槛,被很多人忽视的就是软门槛,以及,很多人会把软门槛认知为硬门槛。和硬门槛不同,软门槛不会成为你能够完成某个职位工作的阻拦,但软门槛会成为别人筛选你时的重要标准。在你求职时,你有没有某个证书、你有没有某个认证,都只是你求职过程中的软门槛。不要将软门槛看作是硬门槛。硬门槛是用来筛掉不适合的 60% 的人的,而软门槛则是用来选出想要的 20 % 的人。剩下的 20% 的人,就是那些符合了硬门槛,但无法跨过软门槛的人。

竞争是全方位的,但也是局部的

对于绝大多数的人来说,面对的竞争往往都是全方位的。你并没有什么异于常人的特点,你和你的竞争者并没有什么不同。这个时候,你们并没有太大的差距。但倘若你拥有一个和其他人不同的优势, 这个优势就会成为提升你综合评分而获得选中的重要因素。

大家都相同的时候,你的竞争优势会帮你获得最终的成功

绝大多数的时候,竞争即会看你的所有竞争条件,希望尽可能选择一个足够好的候选人。另一方面,如果你在某些点上特别的突出,就能够让你自己成为被选中的佼佼者。

如果你的某个技能超出统一领域的其他人一个数量级的水平,那么即使你的其他能力不够强,依然可以获得青睐。但作为普通人的我们,应当有这样的自知之明,是否是这样的人。

数量级的差距可以让你获得青睐

高学历带来的不一定是竞争优势,也可能是竞争劣势

对于一般来说,我们都认为高学历带来的是更大的竞争优势。但是,高学历也会为你的选择来到沉没成本。这些沉没成本会让我们失去一些可能性和选择。

当然,失去的可能性未必是坏事,也可能是一件好事。但作为选择的人来说,确实会有可能担心庙小容不下大佛而不愿意选择,将你从当前的选择中踢出。换句话说,高学历意味着某些事情,你再也做不了了。

移除 Excalidraw 右上角的 Plus 连接

移除 Excalidraw 右上角的 Plus 连接

Excalidraw 是一个非常好用的手绘风格的绘图工具,我给自己部署了一个版本来降低自己写作配图的难度。如果你感兴趣,可以访问 draw.ixiqin.com 体验我自己维护的版本。

白宦成

Excalidraw 在右上角加入了他们的 Plus 版本服务的连接。不过我是自己使用,所以就不需要这样的导流连接,因此,可以通过修改 src/excalidraw-app/index.tsx 文件,将其中的代码进行替换,即可实现移除 Plus Link

原版

const PlusLinkJSX = (
  <p style={{ direction: "ltr", unicodeBidi: "embed" }}>
    Introducing Excalidraw+
    <br />
    <a
      href="https://plus.excalidraw.com/plus?utm_source=excalidraw&utm_medium=banner&utm_campaign=launch"
      target="_blank"
      rel="noreferrer"
    >
      Try out now!
    </a>
  </p>
);

移除后

const PlusLinkJSX = <></>;
自定义 Excalidraw 的字体大小

自定义 Excalidraw 的字体大小

Excalidraw 是一个非常好用的手绘风格的绘图工具,我给自己部署了一个版本来降低自己写作配图的难度。如果你感兴趣,可以访问 draw.ixiqin.com 体验我自己维护的版本。

白宦成

Excalidraw 默认的字体整体比较小,对于我来说,习惯将图画的大一些,这样在不同的设备上,都可以方便的看清楚图片的内容。

修改 S、M、L、XL 对应的字体大小

Excalidraw 将字体大小的变化定义在 src/actions/actionProperties.tsx 当中,因此,你需要修改不同按钮具体的字体,则需要修改这里的配置。

字体大小修改工具

将下方代码中的 options 中 value 修改为你需要的值,即可实现不同的字体大小。

export const actionChangeFontSize = register({
  name: "changeFontSize",
  perform: (elements, appState, value) => {
    return changeFontSize(elements, appState, () => value, value);
  },
  PanelComponent: ({ elements, appState, updateData }) => (
    <fieldset>
      <legend>{t("labels.fontSize")}</legend>
      <ButtonIconSelect
        group="font-size"
        options={[
          {
            value: 20,
            text: t("labels.small"),
            icon: <FontSizeSmallIcon theme={appState.theme} />,
            testId: "fontSize-small",
          },
          {
            value: 28,
            text: t("labels.medium"),
            icon: <FontSizeMediumIcon theme={appState.theme} />,
            testId: "fontSize-medium",
          },
          {
            value: 36,
            text: t("labels.large"),
            icon: <FontSizeLargeIcon theme={appState.theme} />,
            testId: "fontSize-large",
          },
          {
            value: 50,
            text: t("labels.veryLarge"),
            icon: <FontSizeExtraLargeIcon theme={appState.theme} />,
            testId: "fontSize-veryLarge",
          },
        ]}
        value={getFormValue(
          elements,
          appState,
          (element) => {
            if (isTextElement(element)) {
              return element.fontSize;
            }
            const boundTextElement = getBoundTextElement(element);
            if (boundTextElement) {
              return boundTextElement.fontSize;
            }
            return null;
          },
          appState.currentItemFontSize || DEFAULT_FONT_SIZE,
        )}
        onChange={(value) => updateData(value)}
      />
    </fieldset>
  ),
});

修改默认字体大小

默认字体的大小被定义在 src/constants.ts,你可以修改其中的 DEFAULT_FONT_SIZE 来实现控制默认情况下的字体大小。

export const DEFAULT_FONT_SIZE = 28;

参考代码:https://github.com/bestony/excalidraw/commit/78d2d103b40c48bdccbecd7deb85f1fd0d6b4d2f

https://github.com/bestony/excalidraw/commit/14bca18aa6395280cfda15202beaf56dc966a401