简单的 ID 生成器设计

关于在分布式系统里如何生成各种 ID 的问题,对于小的业务来说一直是件麻烦的事情。

小业务注定不像大厂的服务一样,有超多的服务器,很多的开发者组合,所以方案要求简单,并不太高的性能。

ID 要求

  • 唯一性
  • 保护业务隐私(不能透漏有多少用户数)
  • 数值型(更少占用空间)
  • 单向增长,精确有序 (写入性能保证)

常见的方式是有两种:

  • 中心式发号器
  • 单机发号规则

中心式发号器需要额外的服务,增加了成本,一旦发号器出了问题,会影响业务。

单机发号,在号码的规则中,约定一定的位数属于某台单独的机器,也需要在机器上执行一定的配置。

这两种对于小企业小业务来讲,都不方便。

用户 ID 的方案

该方案仅使用数据库,搞一个 Cron 进程,不断的维护一个表的 ID 队列,等待业务去消费。

简单的说,做一个小的业务规则。不断的向数据库中生成一些等待使用的 ID,然后业务在用时,从数据库中查最小可用的 ID,做为本次的实例的 ID 即可。

> 流程

用户 ID 从 3000001 开始,从 ID 中选最后一条记录,然后随机 (0-9 间)选一个数值用作跳跃值,然后加在最后一个 ID 上,生成一个新 ID,写入表中。

通过 Cron 进程,在用户表中,维护 1000 个这样的未消费 ID 队列(小时级别的调度就可以了)。

每次有新用户注册,就取最小一个未消费的 ID 值。然后更新状态到待消费。

等用户填写完信息后,将该值变成正常用户状态。

状态值

  • unspent
  • pending
  • normal
  • disable

其中 unspent/pending 这两个就是为了 ID 生成器所专门设计。

- 好处

好处是,简单啊,哪怕有多个服务,也不用关心 ID 的问题,解决了分布式的麻烦。

通过数据库的解决方案,成本较小。实施简单。

订单 ID 的方案

订单和用户不同的是,定单可以使用大长度数值。

不同于普通 ID,定单还有额外的要求:

  • 可以快速分析出有用信息 (在定单中加入时间内容)

- 关于 uint64

uint64 是定单所使用的 ID 值生成范围:

uint64 取值范围:0 - 18446744073709551615

去掉第一个 1 后,可以拆解为如下字段:

1
8446 7440 7370 9551 615

- 符合 uint64 的设计

基于这样的要求,将时间作为定单上的信息,时间天然是自增长的。

1
2020 0210 1212 1455 123
  • 2020 0210 - 日期
  • 1212 1455 - 时间(厘秒单位)中午 12 点 12 分 14 秒 55 厘秒
  • 123 - 随机数

当然也可以把前面的 20 去掉,毕竟一个系统存活几十年的概率几乎为零。

1
2020 0210 1212 1455 123

这样可以在时间精度上进行加长,并且在随机数上进行加长,可以根据实际情况来做调整

1
2002101212 14550 123

在一个小型定单系统里,在厘秒的时间段内+三位随机数,重复的概率非常低(没有做过大型测试),但理论上非常可行。

总结

ID 生成器有很多很好的方案,像 Twitter 的 Snowflake,大型项目非常推荐,但对于小项目来说,一个可行的方案不仅是速度,可行性,还有非常重要的成本。

这个方案,是实践下来一个很不错的方案。

NAS 清洁小记

春节期间,把手机,相机里的照片统一整理了次,放进了 NAS,做了一年的收尾。

这款 716+II 是 16 年末买的,也已经服役三年之久了,这三年来机器本身从没出过问题,使用上也带来了不少的便捷性。堪称近几年买过最省心好用的产品。性价比这回事不是很重要,省心比较重要。

简单的回顾下这几年的使用情况吧

- 省心好用到不记得TA的存在

  • 买回来就放在一个角落里,然后有年夏天小区总是断电,于是配了个电源。
  • 硬盘有过一次坏道,在质保期内,换了块新的。

其它就没了

- 群晖卖的是软件

这句话是对的,Synology 的配套软件才是最好用的,像 DS Photos,DS Video 装在 Apple TV 上,可以方便的看照片,电影。后来出的 Synology 系列主要面向团体用户,像 Driver,Moments。Driver 是我最常用的。在多机之间同步,重要文档几乎都放在这上面了。

几年来也总结了一套成熟可信的同步方案。

- 电源

好像这个世上除了 Apple 外,其它商家都不会做电源,弄一个大的外置电源,好丑也不方便。虽然你不会动它,但就是不好看。

- Wi-Fi

没有 Wi-Fi 就让他的摆放位置很受限制,只能放在路由器的边上。

- 备份问题

现在只有两个盘位,做备份吧,就只剩下一个盘的容量了,又不够用。

没有备份总觉得不踏实。

关于备份,有想过换一个 918+,或者额外加一个 5 盘位的拓展,但都没实施,毕竟也没那么强需求,而且现在东西换代太快了。

清理

把机器搬出来,机身上全是灰,没有做防尘处理,就简单的摆在一个架子上。

这里还找不到钥匙了,左下角硬盘的孔位是要用钥匙旋转开锁的,但实在找不到了,后来用螺丝刀慢慢打开的。

拆下风扇,做个清理。灰真大 😓

原配 2G 的内存,这次的原意是加两根大内存

拆机后发现,只有一个内存插槽,并且手里要换的内存也是 2G 单条。尴尬。只能当是清洁了。

软件开发周期

▎为什么要有周期

生命周期的每一个周期都有确定的任务,并产生一定规格的文档(资料),提交给下一个周期作为继续工作的依据。按照软件的生命周期,软件的开发不再只单单强调“编码”,而是概括了软件开发的全过程。

  • 周期带来明确,让每个人知道当下在何时、何地、要做何事。
  • 周期带来秩序,让所有人知道如何分工。
  • 周期带来简化,软件工程太复杂,只有把工程分解为小周期可理解可完成的
  • 周期带来成就,开发者可以很快看到成果,而不是一味的编码
  • 周期带来减损,短周期可以让需求者迅速做反应,而不是等整个流程结束后才知道产品和需求不对应

▎周期中包括

  • Propose(Requirement) | 提案(需求)
  • Development | 开发
  • Integration + Testing | 集成和测试
  • Release | 发布

在周期中,有很多规范可以参考,像 Agile/SCRUM,这也是整个工作期间,用过的最多的一种开发方式。

SCRUM 中定义了需求的标准,优先级的制定,开发的一些方式,集成和测试的建议,这套体系比较复杂,有机会再细讲。但好的体系学习成本高,背后的收益也大,可以在团队中树立标准的沟通语言,构建共同的认知体系,降低总成本。

另一个要提到的点是在周期中技术的应用,软件开发不仅是在开发软件,更多的是在利用现在工具整合流程,提升效能。有时,技术的采用就是标准的采用。


▎常见软件开发周期

  • 两周

以上是我见过主流的开发周期。

> Annual | 年

以年为单位的,主要是一些大型软件,以开发语言,操作系统为主。

开发语言 Node.js / Java / Python 等
操作系统 macOS / Ubuntu 等

这种系统的特点就是庞大,且有着明确的发布日期,需求的来源也有着明确的标准。

> Monthly | 月

一些偏传统的公司会采用一种发布列车的方式,每月定制发布时间。如果一个功能能在发布列车启动前做好准备,就可以上车。

总体来说,月还是偏少见的。

> Biweekly/Weekly | 双周/单周

从 MS/EF,双周一直是比较推荐的,原因是一个标准周期里的项目有点多:需求及评审,开发,集成,测试,发布,回顾。放在单周中,会挤压开发时间,让开发者疲于应对。

单周应用于一些特殊时刻,需要产品尽快上线,有种做一点上一点的感觉。


▎实践

> 角色:

  • Product | 产品
  • Designer | 设计
  • Developer | 开发
  • Tester | 测试

> 流程图

这是我在上家公司所实施的流程,图中表示了不同的周期,不同的角色,在一个时间线里,分别要做的事务。

在每个生命周期里,流程是有严格的依赖的关系,产品先行,设计其实,然后是开发,测试,直至发布。

产品是建议先行最少一个迭代的,设计要在下一个迭代开始前,准备好大量的稿件,不要等开发阶段开始后还在等设计。

开发和测试同行,其次是集成和测试同步进行。

在开发期间,同时处理线上的一些问题。


▎举例

年度 | Python Annual Release Cycle

Python 于 2019 年末宣布使用 12 个月的发布周期,委员会认为有一个一致的时间表会对社区有所帮助:

  • 开发者能制定自己的工作计划
  • 社区知道何时参与测试,提供反馈

https://lwn.net/Articles/803679
https://www.python.org/dev/peps/pep-0602


▎REF::

https://en.wikipedia.org/wiki/Systems_development_life_cycle
https://en.wikipedia.org/wiki/Software_release_life_cycle
https://stackify.com/what-is-sdlc

Windows 10 那些事

自从用了 Macinotosh 后,已经好多年没有在操作系统上纠结了,最近配了一台 NUC,顺带体验了下 Windows 10,发现一些有意思的事。

▎版本

不管愿不愿接受,Windows 10 会是该系列最终的版本了。也就是不会再有 11 了。

原因也很悲惨,Win 10 是单机操作系统的顶峰了,这个市场的机会已经没了。微软的重心也到了云和服务上。就连这个操作系统部门都被合并到了云业务部门。Office 现在出售的方式也主要是订阅了,Office 365。

无论你有多爱它,都要接受这个事实。

即然不会有新的操作系统,那 Windows 10 代表的就不再是版本了,而是一种品牌。版本则由另外的数字来代表。

微软使用了一种全新的命名方式,Windows 10 19H1 是微软于 2019 年春季推出的一个版本(H 是德文 Halbjahr 缩写,译为 6 个月)连起来 H1 就是年度上半年,所以 19H1 即 2019 年上半年发布版本。

这是 Windows 发布的一个版本的信息

- 更新

最近爆发了很多 Windows 升级的问题,作为在微软工作过的开发者,特别能理解。

一款在战略上不再是顶级的产品,资源配置上肯定会下降不少。在流程上也会为了这种配置做简化,像测试的简化。

回想过去,那些优秀的人才在帮 Windows 不停的付出,找到各种问题,代价就是高额的支出。

当然了,这里没有对和错,公司做出的决策,都会由公司来承受最终的代价。


▎Settings 设置

这个面板是面镜子,通过它可以看到很多。

Settings 像是个未完工的产品,很多时候,依然要去控制面板里找到一些设置的地方。

新闻上也有很多微软致力于迁移的文章,但,Windows 产品已是明日黄花,所以这种迁移十有八九都不会再发生了。就像一个城市,在最高点时开始建新城,随后没落了,整个新旧城的结构就这样保留了下来。

这也又一步印证了,属于我们童年、中年的那个时代过去了。


▎内核

Windows 10 有个很有意思的点,看起来它像一个双内核的系统。就是设置和控制面板。

在 Settings 中的 Region 中可以设置 Country 和 Format,但这对于一些旧的软件来并不起作用(银行 APP)。

而在控制面板的 Region Settings 中,可以单独设置 System local,并启用 Unicode UTF-8 为世界语言支持。

通过这个,可以发现,Windows 10 在对待 APP 是有两个内核(暂时这么称呼)来处理的。

对比 macOS 15.12 在 32/64 位的一刀切,Windows 承受了太多的过去。


▎32 位

WoW64(Windows on Windows 64)应该是 Win7 时开始提供的一个功能,即提供一个虚拟技术,让 32 位的应用程序正常地运行在 64 位的 Windows 中。

我在微软时还测过这类的功能,转眼间十年过去了,这项技术依然在为各种软件提供服务,也就是国内市场上目前依然是 32 位软件的居多。像银行,税务等。

能理解,32 能用,还搞啥 64,万一用户是个 32 位的旧系统。

看,这就是 Windows 文化,从来都是能用即可。没有棱角。


▎DevBox

作为一名开发者,Windows 能用吗?

在使用的这几天来看,并不行。

- 专业的 Termial

Windows 没有专业的 Terminal,这一点就不行,开发者大量的工作,都是在命令行里进行完成的。没有专业的命令行,生产效率完全无法根上。

- *nix 内核

虽然 Windows 也能方便安装各种开发软件,但没有 *nix 的内核,好多东西都无法参与,但好在现在 WSL 做的还可以。

Windows 的 FS 不支持 Soft link,我的个人习惯是把很多配置做成可同步 Sync 的,真正的文件在 Dropbox 中,而目录下用的都只是 link。

但 Windows 不支持。


▎AppData

Linux 系统习惯把用户的应用数据存放在 ~/.xxx 目录下。

Windows 现在也有一个 AppData,但不得不说,Roaming,Local,LocalLow,这几者的关系,实在让人费解。


▎其它

如果您不是从事音视频编辑、软件开发,Windows 是一款真心不错的产品。目前还没有其它系统能代替它的地位。

肺炎时期的日记

这是一个我个人完全不擅长的领域,所以开头怎么写,我也不知道。

> 流水账

年初四,按网友的说法,今天是接着不动。

上海的雨已经连续下了一周了,每日都是湿冷,好久没有运动的身体显的很臃肿。

回忘这艰难的假期,漫长如过了一个世纪,但细数起来,也不过才一周而已。

上周初,公司聚餐时,大家还在聊武汉是不是有瞒报,然后假期初还去了次迪斯尼,满城中口罩数量已经多了起来,但还是充满着热情和忙碌的。

疫情来的太快,没有一点防备,都来不及做准备,大家就各被按在了家中。

而居家的时间如蜗牛般的离去,微博朋友圈变成了疫情播报地,每天看的谈的都是疫情的进展,这一过就是多天。

> 回忘 Sars

那时,我还在读高中,那时都是在校住宿的,整个非典期间都是封校,关于外面,只有一些新闻联播可以看,并没有太多的感触和记忆。

封校期间,父亲给我送过一次东西,大约有香蕉和板蓝根,见不到人,只能放在门卫处,然后经过消毒去领取。

这次病毒期间,听母亲讲了很多那时的事,像回乡的人被堵,其实和今日何其相仿。

我们已经战胜过一次,我们终将会战胜这一次。

但这些苦难一定要加在这个民族身上吗,从某个角度来讲,是的,像吃野味,迷信,这些行为,如果不能有效去除,这些疾病会一直像噩梦伴随。

> 封城记

23 号凌晨忽然发布公告,上午 10 点封城。自小,这是第一次见过封城的行为,而随即上演的是大逃离。

河南位邻湖北正北,这次是被重点表扬的省份,因全省尽封路,禁止人员流动,外来人口报备。

这些让我想到战时的情景,而这次正是一场没有硝烟的战争,对象是一种新兴传染病病毒。

但城市并不生产物资,封城的后续就是城市供应链的打断,各种紧缺会出现。所以还是建议大家稍囤积点备灾物资。但依然希望不会,毕竟中国不仅是一个大国,还是一个生产强国。

> 责任人

武汉在这次重大事故中的各种决策都非常糟糕。

像今日最火的一张图,如果我能回到一个月前,内容是:一个月前香港对武汉病毒非常重视,而回复都是香港阴谋论。

从瞒报,人大会,万家宴,到春晚。真可谓步步凌乱。

从物资储备丰富到当天的医务人员联名求助;从凌晨封城禁令到执行 8 小时空白期,从禁止城市通行影响医务人员到调度私车服务公务职员;

更为悲痛的是早期暴露问题的医生还被依法办理了。。。

> 人,真实的人

官方数字都很冰冷,无论是多少人感染多少人离去,都没有真切感。

但人的故事,都很悲伤。

微博上那些短短的文字,记录着一个个家庭的悲惨去离。

最美逆行者的图文渲染着人们的激情。

好像苦难又一次成为这个民族的武器,但大苦很快会忘记,而个人家庭的记忆永远无法抹去。

在这场灾难里,对人的关怀上,我们的表现并不好。

武汉人像过街老鼠,酒店不准入住,甚至看到无处收留的例子。加油站不准加油,鄂A 不敢上路。

他们说,武汉人不是病毒,只是倒霉版的你。

今天对武汉人的刻薄,改日在另一件事上,刻薄的对象就是自己。

> 这个时代

网络带来的信息洪流并没有让人们变得更睿智,相反,躲在看不见的另一处充满着阴暗和毒辣。

人们已无法分辨真实和虚假,也没有能力认真和同情。

这个事情,只能告诫自己,遇到陌生的事情,不要轻易站队,多读专业文献书刊,人生漫漫,学无止境。

最后,信仰科学!

A Little Architecture 【译】

by Robert C. Martin (Uncle Bob)
https://blog.cleancoder.com/uncle-bob/2016/01/04/ALittleArchitecture.html
@04 January 2016

译者注:这是很久前看到的一篇关于架构师的文章,出自 Bob 大叔,这篇文章曾被我分享给了好多人,好多不知什么是架构师的人,我不确定他们有看。但我确定我很认可这其中的道理:什么是架构师要关注的,不是数据库,不是库,也不是服务器,是业务及一些顶级的设计原则。
在当下,顶级的架构变成了云设计师专属,而中低层则是数据库直连的时代,再次把这篇文章翻译出来,给那些有志的开发者,关注哪些方能成就自己,勿做井底之蛙。



我想成为一名软件架构师。

这对于一个年轻的开发者来说是一个很好的目标。

我想要带团队做重要决策,包括数据库,框架和服务器以及其它一切。

恩,这样听起来,你并不是想成为一名架构师。

我当然想成为架构师,要在团队里做重大决策的那种。

但你刚才并没有指哪任何重要决策,你说的都是不想干的事项。

什么意思?数据库难道不是重要决策?你不知道我们花了多少钱在这上面?

可能很多,但,数据库不属于重要决策。

怎么能这么讲?数据库简直就是整个系统的内核了!它是整个数据的归集,排序,索引和访问的地方。没有它就没有整个系统。

数据库只是一个 IO 设施。它是提供了一些功能来做数据的排序、查询及报表,但这都只是系统架构的辅助。

辅助??这种解释太不可理喻了。

没错,就只是辅助。系统的业务规则可能会使用到这样那样的一些工具,但工具本身不是业务所固有的。也就是说,如果需要,你可以替换这些工具,但业务规则不会变。

恩,但我依然需要数据库来记录这些数据。

那是你的问题!

什么意思?

你认为业务规则依赖于你的数据库工具。但不是的,最少好的架构不应该有这样的依赖关系。

搞笑,如果不用这些必须的工具, 那我如何创建业务规则。

我并没有说不用这些工具,我是说不应该依赖于它们。业务规则应该不知道你用的是哪种具体的数据库。

如何让业务规则使用工具但不去了解工具?

你搞反了依赖。你的数据库依赖于业务。你需要明确业务不依赖于数据库。

胡扯。

正相反,我在讲计算机架构语言。这是一种依赖反转原则。低级策略应该依赖于高级策略。

更胡扯!高级策略(我想你是指业务)调用低级策略(这里指数据库)。所以是高级依赖于低级,就像呼叫者依赖于被呼者。路人皆知。

在运行时,这样讲是对的。但在编译时,我们希望的是依赖反转。高层级代码不应该直接标明低层级代码。

得了吧!不可能调用一个方法但又不提及它。

当然可以,这就是面向对象技术在做的事。

面向对象是指创建直接世界的对象。它是把数据和方法放在一起的内聚对象。它是把代码按直观的结构进行的一种组织。

谁给你讲的?

每个人都是这样理解的,绝对正确。

恩恩。使用面象对象原则你可以在不提及一个方法时来调用它。

你知道如何在一个面向对象设计中,对象间如何发送消息吗?

当然。

那你应该知道消息的发送者不知道接收者的类型吧。

这个取决于语言,在 Java 中,发送者要知道接收者的 Base type,在 Ruby 中,也要确定接收者能处理发送者所发送的消息。

是的。但这两种示例中,发送者都不知道具体的接收都类型。

恩,是的。

因此,发送方可以执行接收方的函数,而不需要指明接收方的确切类型。

我知道,但发送方依然依赖于接收方。

在运行时,是的。但在编译时,发送方的代码没有指明,或依赖于接收方的相关代码。事实上,代码层面,接收方依赖于发送方。

什么!发送方依然依赖于发送的 class。

来点代码吧。先看看 sender

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package sender;

public class Sender {
private Receiver receiver;

public Sender(Receiver r) {
receiver = r;
}

public void doSomething() {
receiver.receiveThis();
}

public interface Receiver {
void receiveThis();
}
}

这是 receiver

1
2
3
4
5
6
7
8
9
package receiver;

import sender.Sender;

public class SpecificReceiver implements Sender.Receiver {
public void receiveThis() {
//do something interesting.
}
}

注意了!receiver 依赖于 sender。还要注意 SpecificReceiver 依赖于 Sender。另外还要注意 senderreceiver 一无所知。

你这作弊了。你在 sender 的类里引用了 receiver 的接口。

你开始懂了。

懂什么?

架构原则。当然发送者有它的接口,接收者必须要实现该接口。

这表示我必须使用嵌入对象,然后。。。

嵌套对象只是一种达到目的的方法,这里是其它的。

等下。这些东西怎么使用数据库,回到讨论的起点。

那看更多的代码。首先看个简单的业务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package businessRules;

import entities.Something;

public class BusinessRule {
private BusinessRuleGateway gateway;

public BusinessRule(BusinessRuleGateway gateway) {
this.gateway = gateway;
}

public void execute(String id) {
gateway.startTransaction();
Something thing = gateway.getSomething(id);
thing.makeChanges();
gateway.saveSomething(thing);
gateway.endTransaction();
}
}

That business rule doesn’t do much.
这个业务倒是很简单。

It’s just an example. You’d likely have many classes like this, implementing lots of different business rules.
这只是个示例,你可以多弄点类,实现更多的业务。

OK, so what’s that Gateway thingy?
恩,Gateway 是个啥?

It supplies all the data access methods used by the business rule. It’s implemented as follows:
它提供了业务所需的数据访问方法。它的实现如下:

1
2
3
4
5
6
7
8
9
10
package businessRules;

import entities.Something;

public interface BusinessRuleGateway {
Something getSomething(String id);
void startTransaction();
void saveSomething(Something thing);
void endTransaction();
}

注意哦,这个包名是 businessRules

恩,那 Something 呢?

这里描述了一个简单的业务对象。我把它放到 entities 的包里。

1
2
3
4
5
6
7
package entities;

public class Something {
public void makeChanges() {
//...
}
}

这里是 BusinessRuleGateway 的最终实现。这个类知道真实的数据库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package database;

import businessRules.BusinessRuleGateway;
import entities.Something;

public class MySqlBusinessRuleGateway implements BusinessRuleGateway {
public Something getSomething(String id) {
// use MySql to get a thing.
}

public void startTransaction() {
// start MySql transaction
}

public void saveSomething(Something thing) {
// save thing in MySql
}

public void endTransaction() {
// end MySql transaction
}
}

再次注意,在运行时业务方法调用数据库,但在编译时,database 包提及并依赖于 businessRules 包。

恩恩,我想我有点懂了。你在用一个多态来对业务隐藏数据库实现。但你依然对业务提供了数据库的接口。

不,不完全是。我们并没有尝试为业务提供所有的数据库。相反,我们只为业务创建了所需要的接口。这些接口的实现方来调用相应的数据库。

恩,但如果所有的业务需要所有的工具,然后你就不得不把所有的工具写在 gateway 的接口里。

看来你还是不大明白。

明白什么?这对我来说已经很清除了。

每个业务都为自己的数据访问定义单独的接口。

等等?

这叫接口分离原则。每个个业务类将只使用数据库数据的一部分。所以每个业务都提供一个接口去访问该部分数据。

这不就意味着要有一堆的接口,并且有一堆的类来调用其它的数据库类。

这才算开窍吗。

但这不乱吗,又浪费时间!为啥这样干啊?

你想又清晰,又省时间。

这简直是为了代码而代码。

相反,相对于那些不相关的决策,这才是最后要的架构。

这啥意思?

还记得你开始时说要成为一名软件架构师?你想做那些真正的重要的决策?

是啊,我是想这样啊。

在这些决策间,你想的是确定使用哪些数据库,哪些服务器,哪些框架。

恩,然后你说这不是重要的决策,这是不相关的。

是的,对架构师而言,重要决策,不包括使用什么样的数据库,服务器和框架。

但你总要先决定这些吧!

不,你不用。事实上,你更希望在开发周期更迟些时再做这些决定,这样你可以有更多信息。
有时,架构师早早的决定上个数据库,最后发现搞个文件写写就够了。
有时,架构师早早的上了个 Web 服务器,最后发现团队想要的只是一个 socker 接口。
有时,架构师早早的选定了一个框架,最后发现框架提供了一堆没用的功能,还增加了一堆有的没的限制。
可幸的是,团队架构师有一种方法论,可以将这些决策推迟到有足够的信息时再来做。
可幸的是,架构师将团队从速度慢、资源匮乏的 IO 设备和框架中隔离出来,使得团队能够创建快速、轻量级的测试环境
祝福那些架构师关心真正重要的事情的团队,并推迟那些不重要的事情。

胡扯。不知所云。

如果你还没有进入管理层,也许十年后你可以的。

版本规则介绍

▎认识版本号

这是 Windows 10 的版本号,相信在每日的使用与升级中,大家都有所目睹。


▎为什么需要版本

> 1. 对于软件工程,简单的说,因为有依赖。

现代软件工程,是模块和依赖构建,越大的规模,涉及的包越多,而依赖包会有如下更新情况:

在软件开发过程中,会有三种常见升级情况:

  • 修复问题,没有加新功能
  • 加入新功能,不影响当前功能
  • 大的变动,和现有版本不兼容

如果没有一些规则,对每个依赖库的升级,就会变成一种灾难。

所以我们需要一种约定、规范,来实现依赖之间的合作,升级,及让开发者能清晰的识别。

> 2. 另一种情况是,信息确认

通常人们说升级了一个新版本,用户需要来通过这个值确定是不是已经升到了最新。
其实,当用户在遇到问题时,客服、开发者需要知道用户的问题是出现在哪个版本下的。

从上可见,这种需求更多的适用于没有软件工程中库的依赖的顶级 APP。


▎常用版本格式

以上是当下最常见的两种通用版本格式,适用于主流应用,库及一些模块。


> SemVer | 语义化版本 2.0.0

版本格式:主版本号.次版本号.修订号,例如 1.9.15

版本号递增规则如下:

  • 主版本号:当你做了不兼容的 API 修改,
  • 次版本号:当你做了向下兼容的功能性新增,
  • 修订号:当你做了向下兼容的问题修正。

先行版本号及版本编译元数据可以加到“主版本号.次版本号.修订号”的后面,作为延伸。

该规范对于依赖库,非常实用。它可以通过通用的规范来做 Bug Fix 级别升级,或进行 Feature 级别的更新,事实也是如此。

- Bundler 实例

这里用 Ruby Gemfile 的管理器 Bundler 来举例:

1
2
3
4
gem 'nokogiri'
gem 'rails', '3.0.0.beta3'
gem 'rack', '>=1.0'
gem 'thin', '~>1.1'
  • = 指定版本 3.0.0,表示仅限制于该版本
  • >= 如字面意思,大于等于该版本都可升级
  • ~> 2.0 是指可以升级所有的功能更新 [‘>= 2.0’, ‘< 3.0’]
  • ~> 2.2.0 是指问题修复升级 [‘>= 2.2.0’, ‘< 2.3.0’]

- 最佳实践

在项目

  • 0.1.0 - Init 项目初始化
  • 0.2.0 - 加入了新的功能
  • 1.0.0 - 版本正式上线
  • 1.0.1 - Bug 修复
  • 2.0.0 - 重构了新的 API,与 1.x 不兼容

> ChronVer | 日期式版本 2019.05.19

Chronologic Versioning “日期版本”,软件版本按照年月日编排。

版本格式:A.B.C.D (Year.Month.Day.Change)

因为用户在使用场景上更在意的是版本的发布时间,语义化版本号对用户认知有一定的门槛。

如果是同一天发布多次,版本号如何定呢?

虽然官网讲了很多案例,但这种版本方式非常不适用在软件依赖包中,因为日期是没有功能的规则的。


> 对比

综上,SemVer 语义化版本适用于所有的情况。包括各种开源代码库,二进制包,终端应用产品。

在上家公司,让人印象最深的一个解释,PR 在给客户介绍产品时,指着下面的版本号,讲道,知道这个 6 代表着什么吗,代表着公司人的努力印迹,在几年的时间不断迭代,这已经是第六代产品了,那种自豪感,非常强烈。

SemVer 用在终端应用上的一个常见问题就是,在很长一个时间内,版本会一直维护在 1.xx.xx 上。

ChronVer 日期版本,更多适用于和用户产品相关的末端应用,像各种客户端,在场景上,使用者都是各行业者,在技术上它不被其它产品依赖。


▎错误示范

> 对 Docker 的吐槽

  • Docker Desktop 2.2.0.0
  • Engine 19.03.5
  • Compose v1.25.2
  • Notary 0.6.1
  • Kubernetes v1.15.5

天那,这都是什么样的版本命名呀。

Desktop 是一款面向用户的 UI APP,比较适合的方式是 ChronVer,用 SemVer 也合适,但这里用了四个字段来表示,不知最后一个代表什么。

而 Engine 更像是一个库,它被上面的 Desktop 依赖,这就表示它需要被知道是哪种类别的更新,更适合的版本方式是 SemVer。

Compose 和 Kubernetes 前面又加了个 v。

> 对 Golang 的吐槽

Golang 在 2018 2019 年最大的变化就是加入了 Go Module,那么来看看它是如何使用的吧:

1
2
3
4
5
6
7
require (
github.com/BurntSushi/toml v0.3.1
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/gin-gonic/gin v1.5.0
}

Go Module 起源于 8012 年,在此之前有各种语言作为参考,但很遗憾,依赖设计出这么丑陋的模块依赖。

  • 依赖配置不是由开发者指定,而是代码分析生成
  • 依赖中大量的库没有版本号,Go 默认使用 Git 日期和 Commit Sha1
  • 间接依赖也在配置中?这就不懂了,不是有 go.sum 吗。

做好一门语言,最难的部分就在于依赖库管理,但这不应该是 Go 的借口,毕竟不是单片机时代。


▎ REF::

解锁新年

今年是个暖冬,去年的此时,还下了一场小雪,而今年一切都平静了很多。临近年底,人却得了感冒,各种发炎,喉咙像冒了火,一直咳嗽,病怏怏的弄了好几天,吃药也不见效果。

时间飞逝,新年的倒计时还是如约而致,都想用一些特别的方式来致敬新的一天,当然对于自己来说,其实可选的也就是跑步了。临近的这两年也都有报名,但种种原因,空气质量、气温过低,熬夜等等原因,都让自己没能战胜被窝。而今年又恰逢生病。

朋友都建议感冒放弃,但对于我,这个起跑的意义似乎又大了一些,不止是一场跑步,而是一个态度,一种对待未来,对待难题的态度。于是乎,没有选择就是最好的结果。

定好了 5:20 的闹钟,相对于上海的比赛,会发现每次外地的比赛会有更多的休息时间,因为会住附近的酒店,酒店会有早餐,等等。

为了御寒,翻出来好久不穿的长裤,准备了 3 件跑步的短袖,又准备了一件外套。加了一件薄款的羽绒服,出门时用。

最后一个交易日,市场行情也琢磨不定,没再多花心思。

> 赛事

6 点上海的冬日,还是挺冷的,走在高架上,城市的建筑笼罩在淡淡的黑色中,房顶镶着金红色的边,一切都这般的美。南京路上的彩灯应该是通宵的,回想在它乡的傍晚,不禁感叹了上海这个不夜之城。

存包,预热,等开赛,哦,忘记说了,这次的迎新赛事是静安区举办的,从静安寺出发,过石门一路、上海站到前闸北公园。静安一直都很高大上,这次,终于有机会用另一种方式看看这个区域。

在存包里,没有脱掉里面的跑步外套,于是穿着有史最厚的衣服,开始漫漫征途,不知是不是冷的原因,耳机一直有种要掉的感觉,于是取了下来拿在手里。

南京路的灯光在晨光中漫漫暗了下去,随即转入其它的道路。边上的建筑也开始从金碧辉煌变得普通起来,陆续开始有民宅,街上的行人也开始多了。

大约过了 4 公里,才隐约感觉身上开始起热,这是多冷的天呀。

边上跑了一位静安公安的帅哥,一路上就见他和周边的警察打招呼,像是在自己的主场。

可能是不用担心散热问题,一路跑下来感觉很轻松,没有因为劳累而采用跟随策略,也很放空,所以全程很舒服的一个状态就差不多结束了。

赛事的最后一公里,是穿越一个隧道,下坡时那种感觉真的健步如飞,而平时所有的隧道都是开车经过的,跑起来的距离感明显不同。在后面的爬坡路段,因为临近终点,所以也是满速向前的,感觉心率都 180 了。

解锁城市

我很喜欢用脚步去丈量城市,这样的速度能让人看到更多,这样的疲惫更让人印象深刻。

随车开过的地方,总像两个场景,人在车里,而城市在车外。

生活需要感悟,用的是慢速度。

> 祝语新年

拿到奖牌,拍了两张照,到附近的咖啡厅休息,临窗的位置刚好有阳光晒进来,照在身上,暖暖的,一杯太妃的甜唤醒一年的美好。

我是个定了计划会想尽千方百计去完成的人,这也是为什么会在意新年第一天的计划。

保持好节奏,新的一年,接着干!全力冲梦想!

2019 回顾 - 我的设备

2019 又要结束了,回望这一年真的是经历颇多,感触也不少。想写一些东西来记录下,但又不知如何下笔。打开电脑,盒上电脑,换台电脑,反复间,好像一个轮回,于是想找一些简单的话题先开始写写。

作为一个数码爱好者,就从身边的设备写起吧。

> 显示器

年初时心痒痒,一心想入手点东西,思来想去,还是换个显示器吧,当时在公司,两台 U2518 来回接线的体验一点都不好,就定来下这次买显示器,指标上一定要支持 USB Type-C,这样一根线可以充电、传数据、接显示器。选了好久,甚至做了张表单,最后才定了 U3218Q(从官方通过 QQ 下单的感觉很复古),主要参数:

  • 32寸
  • 4K
  • USB Type-C (内建 DP1.4,PD 60W,USB 3.0)

32 寸大屏配上窄边框的视觉效果非常好,4K 的分辨率显的字有点小。但常用的工作模式依然是 4K,把编辑器的字体放大点就好,也偶尔也尝试在 3360x1890 下。字体大小会更舒服一些,但会有缩放产生的模糊。

最近需要聚焦的工作,全新尝试 1920x1080,没想到效果非常的好,一来显示面积小了,就不会去打开一些多余的软件摆在可视区域,减少了视觉噪音。二来,这就是标准的 HiDPI,清晰度非常的高,视觉上带来了全新体验。

如果是 6K/7K,打开 HiDPI 便是极好。

年中 Apple 预告了 Pro Display XDR。这简直就是爱情的模样了。直到价格出来 :(。
如果 DELL 能出这么一款,就用 LCD 普通面板,价格在 1W 多,该多好呢。

> 电脑

18 年底入了台 15 MacBook Pro 中配,16G 内存加升 512 SSD,一切正常,表面上贴满了标志,经常连笔记本键盘使用,整机非常新。

这个机器的键盘依然是蝶式,有好几个朋友的同款都已经维修过了。

因为太过正常,所以没什么感觉,就是最近经常出差,带上这么重的一东西,肩膀有点受不了。即使是换了双肩包后。

公司的一台 DIY PC,因办公地点原因,现在家使用,了解了下 UEFI 并安装好最新的 macOS Catalina 后,这台 Hackintosh 成了现在的办公主力。

毕竟 32G 内存,i7-8900K 的配置做什么都不在话下,速度带来的幸福感提升还是很明显的。

要说问题吗,就是这么大的机箱,在房价的面前显的有点昂贵。

用完黑苹果后,也有考虑过 NUC,但还是等它出了 USB-C 供电版本后再说吧。

当然如果 iMac 出一款 32 寸屏幕的话,那便是极香的。毕竟是一直想再入一台 iMac 的,直到 3218 用过后再也回不到 27 的屏了。

> 键盘鼠标

从日本带了几把 Filco Minila Air,留下了 Brown 和 Black,但 Black 实在太重了,出掉后,又跑秋叶原入了一把双模 87 Brown,当然还是大F。

论手感 Minila 真的很赞,很紧致,87 有点旷的感觉。同样的茶轴,有两种不一样的感觉。

但蓝牙 3 的品质真的是头疼,现在 87 是用有线连接使用,Minila 则在包里随我征战各方。

Magic Mouse 1 已经用了大约 7 年了,算是长情,虽然一直会断开重联,但也没想过要换掉,就一直在包里随用随取。

她的灵魂在于上面那个触摸板。

G903 陪了我一年,电池已经不怎么行了。但优雅的造型和清晰的指向,清脆的点击,都深得我心。

当下这款有个 Bug,按键会失灵,官方会换新,这就是我的期待。

> 手机

今年入手了一台小米 9SE,主力机器依然是 iPhone X。

入米九的原因主要是公司的华为测试机太难用了,而 iPhone 不支持 NFC,这对于上下班刷门卡来说,太不方便了,同时还有夜景的需求。9SE 的大小和 iPhone X 一致,叠放时比较方便拿。

iPhone X 表现依然超凡,外形上也很漂亮,像件实用的艺术品,一直在服务着,从没掉过链子,这一点小米就完全不行,在稍差点的环境中,简直就是个 Bug。

iPhone 11 在店里感受了下,说实话,真心没感动。更像是疲劳期,对新的东西也没什么更高的期待。

iPad Pro 今年的使用率稍微高一点点,主要是各种画图,也就是那支笔。经常拿出来画一些架构图,流程图之类,或做一些速记。

> 手表

Apple Watch 4 好像是今年买的。一直带着,设定好了指标,坚持完成着,几乎没有间断。

常和朋友开玩笑说:一直以为自己保持身材的秘方只是贫穷,后来看到 Apple Activity 记录时,才发现还是有很多的努力的。

> HomePod

记不清是什么时间入的了,在香港广场,带着她坐 71 路回的家。

使用频率还可以。满意度很高,虽然偶尔也会断线,但相对于之前的那款水晶音箱来说,这连接便捷性,连接品质和音质都让人很满意。

安安静静的放在书房的桌面,你用她时,她都在,无论从哪个设备连接,都很快,很少出问题,简直就是完美了,除非哪天想不开,叫了声 Hey Siri。

> AirPods

AirPods 2 是刚出的第二天在香港广场入的。这款产品是今年所有产品里使用率最高的了,几乎每天都带在耳朵上。

起初担心跑步会掉,还用个头巾包住,后来各种长跑、马拉松,耳机都是必备了。

音质不做评论,不专业。但苹果对蓝牙的把控,真的是绝世高手,蓝牙耳机玩过很多,但 AirPods 这种多机共联,而且如此稳定,快捷的,也只能是苹果了。

不便的话,就是调节音量了。

AirPods Pro 去南京东小试了下,有点想吐,是中号的耳塞,Apple 说有马达通风来保证耳道压强,但自己从小就不喜欢入耳式。

> 小结

这些设备早已超出自身的范畴了,她们带来各种功能、便利性的同时,也在影响着生活的方式。

安静时,找个沿江的 Bar,听着音乐,发发呆,做些有创造性的工作,亦或写写人生感悟。傍晚时分,用新的夜景模式去拍拍城市的灯光。

2020 生活还会继续,而这些设备也会继续安静的服务着生活。