Logo

site iconsmallyu

区块链行业的开发者。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

smallyu RSS 预览

关于 Code Review 的礼节

2025-03-25 21:45:43

前情提要,推荐王垠的两篇博客文章:

由于过往不规范的工作经历,我之前是缺少对 Code Review 的理解的。最近因为同事对这个问题情绪化的表达,我开始关注到关于 Code Review 的问题。

基本礼仪:不要用 FYI

谷歌公开出来的 Code Review 规范 《The Standard of Code Review》已经非常具有指导意义,内容很全面,包括我现在实际遇到的流程问题,也完全可以依照这个规范来消化解决。当然前提是所有团队成员事先对这个规范的内容已经达成一致,而不是假设公司的员工已经知道并且开始遵循这个规范。

关于规范(TSCR)中已经提到的流程问题、礼貌问题,这里是不需要赘述的。我关注到的是其中一个小章节《Label comment severity》,也就是对 Code Review 之后的 comment 进行重要程度的区分,并且加上前缀,让 author 可以明确知道哪些留言是必须要改的,哪些是无关紧要的。

除去必须要改的 comment 不加前缀,谷歌的规范中提到有三类前缀,这些都是指站在 Reviewer 的立场,如何去写 comment,本质上这三类前缀都不影响代码的 approve 和合并:

  • Nit (Nitpick): 你应该改,但是不改我也能接受。
  • Optional:只是建议,你自由选择改还是不改。
  • FYI (For Your Information):这个 PR 中完全不需要因此有改动,但我觉得这是一个有意思的点,后续你可以关注下。

其中第三个前缀 FYI,每当看到 For Your Information 这个短语的时候,我总是下意识的会把这个短语翻译为中国传统社会普遍流行的一句古话: “为了你好”。

相信在中国本土长大的华人,即使没有遭受过严苛古怪的家庭教育,也都能深刻理解到 “为了你好” 的威力。

为了你好,你要好好学习
为了你好,你不能打游戏
为了你好,你要考公务员
为了你好,你要早点结婚
为了你好,你必须生孩子
……

一些情况下,父母的 “为了你好” 只是他们满足自己变态控制欲望的借口,另一些情况下,有些父母发自真心的 “为了你好”,然后由于自身有限的眼光给出了不正确的建议。

总的来说,中文语境下的 “为了你好” 绝不是什么好词,如果把这种话语带到工作中,就更匪夷所思了。虽然 For Your Information 并不能直译为 “为了你好”,但是为了避免歧义,还是建议大家不要使用这样的话术。

所以,Code Review 的基本礼仪就是,不要用 FYI。

为什么 “为了你好” 往往是错的

先说结论

因为没有人可以在实际上了解另一个人。

父母真的了解自己的孩子吗?结婚多年的夫妻,真的知道对方的心思吗?审查犯人的警察,足够了解自己在调查的罪犯了吗?心理学的专家,能猜到自己女朋友早上为什么生气吗?对于每一个人,你真的了解自己吗?

所以其实可以得到这样一个和技术无关的结论,出于礼貌,我们应该尽量避免对别人说 “为了你好”。

具体事例

最近的工作中,我提交的代码包含一个简单的事件总线(Event bus)的实现,其中事件的 Publish 和 Subcribe 都用了 RW 锁来保证 map 读写的线程安全:

func (eb *EventBus) Publish(event Event) {    eb.mu.RLock()    defer eb.mu.RUnlock()    if ch, exists := eb.channels[event]; exists {        ch <- event    }}

而我得到的 CR 建议是用 Sync map 改写为:

func (eb *EventBus) Publish(event Event) {    if ch, ok := eb.channels.Load(event); ok {        // 注:这里需要类型断言        ch.(chan Event) <- event    }}

这实际上最多是一个 Nit 级别的 comment,我是不太在意的,这个事情的处理起来也非常简单。

而事实上问题在于,我听到了类似于 “为了你好” 的话,大致意思是,为了你好,你要了解清楚 RW 锁、互斥锁、Sync map 的区别,然后选择在 Event bus 场景下最正确的实现方式,并且能够条理清晰地去说服别人。

如果说我从自身技术发展的角度,是不太在乎这种问题的。这个问题本质上是我们平时面试时候说的八股文,随着最近几年面试风向的转变,也越来越多的人开始逐渐达成一致、反感八股文一类的东西了。

当然追求这一类底层问题到极致的人,肯定是有技术追求的人,这并不是什么坏事,我们应该尊重任何努力以及对技术较真的人。只是技术也分很多种方面。

我的兴趣

我算不算有技术追求的人呢?也许有时候算吧,不然也不会从 Fusionist 裸辞,放弃了比现在算上币权还要高的工资。或者说,无论是技术还是别的东西,其实我们所有人都愿意追求有趣的东西。

从过往经历来看,我关心的技术话题并且乐于出自兴趣去学习、思考的,比如:

知道这些东西有用吗?没什么用,面试的时候几乎不会有人问,工作中更是用不到,就仅仅只是出于兴趣爱好去探索这些技术问题。这些问题的答案,从来也都不是现成的,网络上是搜索不到的,ChatGPT 也是没办法精准回答的,只有经过一段时间的学习,加上查阅论文资料,结合自己的亲身经历和理解,才可以形成技术观点,无论观点本身是对还是错。

因此可能出于某种思维上的惯性,我很少关心太过基础的编程类问题。这种事情因人而异,不能强求,自然也不能强迫别人因为 FYI 就去关心某些问题。

FYI:成为好的 writer

(刚说完不要 FYI,我这里就在 FYI)

Rework》 这本书里有一个章节印象挺深,标题是 “Hire great writers”,书中的观点是,不是因为工作中需要发表什么文章、写什么报告,而是好的 writer 往往具备逻辑清晰表达问题的能力,可以帮助到工作。

回到技术问题上,现在各种形式的技术文章也都非常普遍,比如对锁的使用场景比较有心得的话,完全可以落实到文字上,输出成果形成一篇文章,分门别类的介绍锁的种类、最佳的使用场景,然后发表到各种平台上,获得成千上万人的关注,再然后如果对其他技术细节也有心得,内容逐渐丰富,直到写出了一本书,甚至有出版社看上,或者公开到网络上作为电子书开源……FYI……何必跟我较真呢。

从团队内部的混乱想到……

2025-03-22 20:23:47

首先推荐两篇王垠的博客文章:

今天回看了一遍王垠的这两篇文章,比较庆幸的是,自己在平日的工作中,很少在无意间触犯到王垠提到的这些礼节问题。

会突然想起这个话题是因为工作中的一点小事,也挺有意思。起因是我擅自 merge 了没有经过 review 的代码,我的同事就开始在群里批判我的代码,也许是他觉得不经过他 review 就合并代码的行为,伤到了他在团队中的尊严和地位。

我现在在一个 web3 项目的开发团队工作,团队总共也就四五个人,内部管理却非常混乱,这是我在之前的工作中没有遇到过的。不过说实话我之前的工作经历不太够看,没有什么参考价值,所以我总结不出什么有用的结论。

要我对比的话,现在的工作和以前的工作,工作方式上最大的区别,在于分配任务的粒度不同,或者说分配到个人头上,负责的事情大小不同。

比如我在 Onchain 工作的时候,需要开发 Solidity 合约,来支持我们的分布式文件系统对 EVM 链的兼容,那么这件事情就是我在做,有人 review,但实际上整个 合约仓库 的代码只有我一个人提交(这里不是在强调提交人数的问题),在这样的模式下,自然也就不存在现在遇到的什么代码质量之类的问题。

(Onchain 这家公司已经解散了,当时项目的代码并没有开源,现在的代码仓库是我私自备份下来的,两年过去了,应该不会有什么风险吧)

再比如我在 Fusionist 工作的时候,整个 Endurance Network 的网络是我一个人启动并维护的,没出过什么问题。主网上线的时候有一个专业的运维同事帮忙开服务器、配置 Docker 之类。

(我已经离职了说出来应该没事吧)

包括更早先的工作经历,不管是我自己还是同事,直观感受上就是每个人都会负责某一块的业务,对整体业务负责而不是对某个具体的开发任务负责,个人的职责相对明确,在负责事情的时间长度上,都是几周到几个月为单位的,所以倒是没有出现过管理混乱的情况。

现在的工作模式是不太完整的 Scrum 风格,每个任务都是两到三天的开发周期,也就是小的开发任务,这些开发任务一定程度上是不区分业务线(代码仓库)的,开发人员会随机参与到不同的事情上。每个人都是在对自己的开发任务(PR)负责,而不是整个仓库负责。这种模式下,每一个开发任务都会有不同的负责人,造成感官上是比较混乱的。

侧面来对比的话,我之前的工作,如果某个人离职,是需要做很长时间工作交接的,因为需要一段时间来让别人接手。现在的工作,如果某个人离职,其实也没啥需要交接的,最多也就两三天的任务内容。不知道是不是远程工作的缘故,让公司被迫选择这样的管理方式。

我的大老板曾经把这种工作模式上的差异,总结为中国式的管理风格和欧美式的管理风格之间的差异。

我只是个普普通通的开发人员,没有管理经验,也不懂这些管理模式什么的,并不想也没什么机会需要我去思考这些问题。只是现在有点能感受到,其实管理本身是一门学问,挺大的学问……

假如启动一个叫 Oiia Network 的以太坊 PoS 网络

2025-01-28 23:26:40

OIIA OIIA(Spining Cat)是最近很火的一只鬼畜旋转猫,对比 PoW 链上的 DOGE,OIIA 将是 PoS 链上的猫主题 memecoin。

OIIA 与 pump.fun 发行的 memecoin,以及 $Trump 之类不同的地方在于,所有代币的发行量都将通过 PoS 挖矿新增,没有任何预分配(可以验证 genesis 文件),未通过挖矿产生的代币,花钱都买不到。

网络动机

  1. 发行加密货币的最好方式
  2. Oiia 将会提供更便捷的搭建以太坊 PoS 网络的工具,进一步降低搭建以太坊 PoS 网络的难度

为什么使用者要参与

如果参与者没有相关经验,作为学习者,可以:

  1. 学习如何搭建一个完整的以太坊 PoS 网络
  2. 学习如何启动和运维一个以太坊 Validator 节点,如何质押、如何解除质押
  3. 学习如何熟练使用以太坊生态节点相关的工具
  4. 发现并解决以太坊生态工具使用上的问题,给以太坊生态做贡献

为什么不用以太坊测试网

作为以太坊网络的学习者,为什么不直接用 Sepolia 这样的测试网去用,而是选择 Oiia Network?

因为 Oiia Network 的定位是 memecoin。

网络 Spec

技术基础

使用以太坊客户端 Geth + Lighthouse 作为初始节点。只修改启动配置和 genesis 文件,不修改代码。

Chain ID 以及 Network ID

十进制:

20220915

十六进制:

0x1348BF3

初始 Validator

128 个,这个是网络启动的最小规模,会直接写入到 genesis.ssz 文件中。

初始 Faucet

由于一开始网络的参与人数会比较少,会预留 128*32 = 4096 OIIA 作为水龙头余额,放到水龙头地址中。

水龙头使用 PoW Faucet(网页挖矿)的形式来分配。

水龙头的目的是提供少量的流通金额用于网络的测试使用,以及早期愿意参与到网络中的 Validator(虽然靠水龙头很难领到 32 个 OIIA)。预留额度上,如果有 128 个 solo-staker,这个网络就算是巨大的成功了,所以认为预留 4096 个 OIIA 够用。

初始发行量

为了避免类似以太坊基金会抛售的问题,OIIA 不会预分配任何金额给开发人员或 DAO,几乎所有网络都会因为预分配受到怀疑。

以太坊的 PoS 共识没有发行量上限,所以网络的初始发行量就是 4096 个 OIIA。网络启动后的流通量全部依靠挖矿奖励来产出,就像比特币一样。

也就是说,从 Oiia Network 的 genesis 文件来看,除了 4096 个 OIIA 预留用于的空投外(创世节点的 128 个 Validator 不体现在 genesis 文件上,价值 4096 OIIA),不会再预分配任何金额给任何地址。

如何成为 Validator

由于网络初始代币发行量特别少,Faucet 上又领不到足够多的 OIIA,所以可以在社区中申请成为 Validator,社区直接从 Faceut 地址转账 32 OIIA 到申请地址。

网络启动进度

由于没有任何商业目的,网络的启动进度会比较随心所欲。

发行加密货币的最好方式

2025-01-10 00:39:12

前几天某个互联网无关行业的知名人物,在 pump.fun 上发行了一个 memecoin。然后这两天看到有人在公开频道里讨论,关于把 memecoin 迁移为公链的方案,比如保留原始地址和余额启动新链之类。

这个 memecoin 的动机很简单,就是发行者需要募集资金,因为他们从事的活动需要资金来源,也因为他们在从事的活动,这个 memecoin 已经被很多钱包屏蔽掉了。

当然我们这里不会讨论发行加密货币的动机,只会讨论发行加密货币的技术手段,并且对技术手段进行对比。

最好的方式

先说结论,发行加密货币,最可靠的技术方案是,直接使用以太坊的客户端,运行一条和以太坊 Chain ID 不同的链。

为什么不是 pump.fun

pump.fun 是一个很好的平台,提供了一键发币的能力,能保证合约的安全性,不 rug pull,没有预售,没有安全漏洞。这一点相比于自己写合约发币,要方便和安全很多,

pump.fun 最厉害的地方在于,发币即可交易,使用 bonding curve 机制来定义价格,让一个币种即使交易者很少,也可以正常交易,这是其他发币方式做不到的。

不过 pump.fun 也有问题,首先是 SOL 生态,不知道为什么 pump.fun 最初选择了 Solana 而不是 Ethereum,买家在购买新发的币种之前,要先理解和拥有 SOL 才可以继续后续的步骤。虽然 SOL 也非常知名了,但买家为什么要先知道 SOL?

其次是当币种市值在 100k 以下,这个币的交易行为就和 pump.fun 平台绑定了,不访问 pump.fun 这个网站,你就找不到可以交易的地方。如果网站没了,或者域名没了,就真的没有入口了,这对于币种的长期发展并不友好。市值到 100k 以上就会进入 Raydium,那么有多少买家理解 Raydium是什么?岂不是又依赖于一个Dex平台?

所以享受 pump.fun 提供便利的同时,就要承担 pump.fun 这个平台本身的风险,还要承受 Solana 这条链有可能出现的风险,比如,Solana 会长久存在吗?多久算久?

pump,fun 对自己的定位还挺准确的,memecoin 发行平台。

为什么不是 PoW

PoW 是最去中心化的技术形式,但是发行 PoW 链的成本太高了,不但没有现成的技术框架可以复用,需要硬核的技术,而且维护成本也很高,没有人挖矿就得自己挖,算力还不能太低。

为什么不是 Cosmos

Cosmos 生态的项目往往伴随着两个负面的关键词,BFT,联盟链,所以可以排除了。

ATOM 是一个市值仅排名 50 左右的币种,生态上有自己的垂直领域,可以说,如果不知道为什么要用,就不要用。

另外 Cosmos 的生态建设其实不好,到目前都没有一个像 Metamask 一样能连接任意 RPC 的钱包,要真用上 Cosmos 会遇到不少问题。

为什么不是 Polkdot / Avalanche

区块链行业专业的从业者,估计都没整明白、用不来这两条链,不在于它们无法理解,而是理解成本高。

而且像 Polkdot 比如 Existential Deposit 这种特性简直离谱,不明白为什么会存在。类似的未知问题还有很多,是不能轻易选择使用的。

为什么不是 Ethereum Layer 2

以太坊的 Layer 2 本身也不是发币用的,是给项目方挣协议费的,L2 是以太坊的扩展,原生代币仍然是 ETH。而且 L2 虽然技术开源也好用,但是需要中心化的运营,以及不间断提交 fault proofs 到 Layer 1,手续费得用真实的 ETH,挺贵的,如果用户少,手续费都挣不回来。

为什么不在 Ethereum 上发行 ERC-20

智能合约一般人写不明白,主要是安全漏洞风险高,即使发行方觉得合约没问题,买家也很难判断合约安不安全,识别难度很高,所以不推荐这种方式。即使合约没问题,以太坊的手续费也很贵,很不友好。

Layer 2上发行 ERC-20 呢?问题是选择哪个 L2 网络?L2 网络的手续费倒是低,但是不同网络数据又不互通,从这个角度,L2 在杀掉以太坊,至少让以太坊变得分裂,而不是在帮助以太坊。

为什么是 Ethereum

不可否认的几点事实是:

  1. 以太坊的 EVM 已经成为区块链行业最广泛认可和使用的智能合约标准
  2. 以太坊的 PoS 是除了 PoW 之外最去中心化的共识机制
  3. 以太坊的地位无法撼动,ETH Killer 也许会在某些指标上超越以太坊,但 EVM 标准这一点不会
  4. 相比于其他公链,以太坊的社区生态更加活跃,基础设施更加完善
  5. 新兴公链都在试图兼容 EVM,而不是推翻 EVM

基于这些事实,发行区块链网络最好的方式只有一种:

  • 使用以太坊客户端,修改配置文件和启动参数之后,启动一个 Layer 1 网络

从网络运行的角度,即使只使用目前版本的以太坊客户端,哪怕后续客户端不再跟随以太坊的步骤进行升级,也可以让网络长久稳定运行下去。

至于手续费,币价低手续费就便宜,所以几乎不太可能贵到手续费无法接受。

如何解决初期交易和空投问题

除了 pump.fun 平台和 PoW 链,其余的发币方式都无法解决初始阶段币种交易的问题,初期上不了 CEX 也上不了 DEX,买家怎么买,拿什么买?

唯一能想到的就是以 ICO 的方式预售,在 TGE 的时候正式启动网络。尽管这个过程中往往会产生一大堆不和谐的事件和争议,但是如果用以太坊的节点,只要把 Genesis 文件中的每一个地址都说明,网络本身就可以是大家认可并且没有问题的。

网络创世没问题之后,剩下的就交给网络自身的通胀,也不会有明显的问题,网络就能平稳运行下去了。

所有 BFT 共识的区块链都是中心化的

2025-01-05 11:57:59

首先给出一个共识机制在去中心化程度上的排名,这个排名几乎是毋庸置疑的:

PoW > PoS > DPoS > BFT

然后从处理分叉的角度,对比一下 PoS 和 BFT 的差异。

因为 BFT 算法本身决定了,所有使用 BFT 共识的链,都不会存在分叉,无论是软分叉还是硬分叉。没有分叉的链,意味着整个网络同一时刻只会有一个版本,而这个版本取决于项目发行方,哪怕项目发行方不是官方,这一版本也只能来自于某个中心化的组织。所以,使用 BFT 共识的区块链都是中心化的。

假如网络发行方对网络进行了让人无法接受的更改,会发生什么?

在 PoS 共识下,验证者可以选择旧的规则,也可以选择新的规则,这两种规则可以同时存在,直到大多数验证者达成一致,网络恢复一致。如果验证者始终无法达成一致,就会一直分叉下去。

在 BFT 共识下,验证者可以选择旧的规则,也可以选择新的规则,但是如果一方数量达到半数,网络将会停止。直到验证者线下达成一致,网络才会重新启动。

也就是说,当面临本应该分叉的情形时,BFT 会直接停机,这也是为什么 Solona 和 SUI 都出现过网络停止的原因。

到这里你就明白,这里说的中心化,是指在 BFT 网络中不会同时存在两个网络,当然使用其他共识的网络也几乎不会出现这种情况,但是容许这种情况发生。

更进一步的说明,这里说的中心化,是指 BFT 网络中如果一定比例的验证者想要让网络停止,网络就可以停止,只能通过新启动另外一个网络(其实也属于硬分叉的一种)来让网络恢复正常。

这种差异会产生什么影响?以太坊网络中,即使大多数节点已经挂掉,只要还有少数存在,网络就能够正常运行。而 BFT 网络对验证者的容错能力不到一半,如果半数验证者停掉,网络会直接瘫痪,你的所有链上资产无法继续转移。

从投资的角度,如果你打算长期持有某种代币,你觉得哪种网络更安全,更能让你的资产安全受到保障?

不过还要注意的是一点,网络的可靠性不一定来自于去中心化程度,Coinbase 的 Base 网络可靠性来自于美国政府的监管和半合规化,很多交易所和政府机构都会把钱放到 Coinbase Prime 的信托服务里,所以 Base 网络也是比较可靠的。