2025-06-08 08:01:32
最近报名了王垠老师的 计算机科学视频班(基础班),现在学习进度已经接近尾声。因为最后一节课是选修课,我选了 Rust,而 Rust 语言本身的学习成本高,感觉不会像前几节课那样能够快速掌握并完成。不过 Rust 对我来说属于可选的进阶内容,所以并不着急结束。
前几期基础班的课程没有第八节课甚至没有第七节课,所以后两节课的内容并不影响课程本身的价值,能学到属于附加福利。我现在已经学完了前七节课,感觉收获很多。对于基础班课程内容的整体感受,我的结论是,物超所值。
对于基础班课程内容后续的学习计划,我大概列了几条:
这些目标的难度是递进的,要真实现起来需要耗费很多很多时间。所以你看,即使基础班的课程结束,但是对于其中知识的学习,还远远没有结束。基础班是一个非常好的起点,在里面学到的内容可以延展出很多有价值的东西,这个可扩展能力的价值甚至超过课程本身的价值。
基础班的知识好比非常高级的原材料,从基础班毕业就意味着拿到了这些原材料。但原材料需要经过反复打磨、锤炼、加工,才能变成更加实际可用的装备。所以我猜测有的同学学完之后感觉什么都没学到,而有的同学觉得如获至宝,能够反复加以利用并产生许多价值,大概就是这个原因吧。
我开始反思自己的职业路径是从 4 月份开始的,当时我入职了一家新的公司,做普通的钱包后端开发。
实际的工作过程中,我发现同事以比较低的效率写着比较差的代码,整体工程能力差,但是每天工作显得忙的不可开交,领导也对他委以重任,因为他们之前就认识。
这样的现象让我很难受,我很懂区块链,但是这种懂不但没有让我的职业道路变轻松,没有给我的生活带来改善,反而在新的工作中,沦为新人一样的角色被轻视。
同样的,我有很强的工程实践能力,工作效率一向很高,但是这样能将技术设计短时间落地为工程代码的能力,不但没有给我在工作中带来应有的重视,反而在前公司受到了同事极其不尊重的对待。
所以我开始反思,是不是我的技术能力不够,是不是因为我没有上过好的学校,是不是行业环境整体的问题,是不是我过往的职业道路选择错误。
而反思的产物,就是 4 月份高频率的博客更新,尝试做一些技术产品的设计、学习新技术、改变社交态度。事实证明,只要我想,就真的可以学会使用 ZK,或者做点 EVM 相关的事情。但是这些事情还不够,我应该把这种学习能力和工程能力用到更有价值的地方。
以前习惯于把学习到的技术、职业经历、观察到的行业现象都毫无保留分享出来,因为很多内容是我自己摸索出来的,观点也是自己经过学习和思考形成,所以分享出来没什么问题。
但是观点和知识是两种东西,从基础班学习到的知识包含很高价值,自然不可能分享。而对于博客后续的内容,也有必要进行反思和调整。
我在区块链方面需要补齐的知识:
2025-05-11 01:15:07
我给这个项目命名为 echoevm.com,主要目标是从最简单的堆栈操作开始,逐步实现一个完整的以太坊字节码执行环境。
为什么选择这个方向?解析下以太坊客户端的技术模块:
综合来看,我倾向于做一件侧重工程而不是学术、同时又有技术含量的事情,无论是从个人技术能力的提升,还是后续有可能带来的成果上,都要有意义。假如这个最小EVM开发出来了,是可以带来一系列成果的,后续也可以基于此延伸出很多更有价值的产品。
从 Solidity 语言到 bytecode 的转换过程,那是编译器专家干的事情,我要做的,是针对 bytecode 做执行,先从最简单的加法运算和 jump 开始,然后是 Gas 的计算、上下文环境的切换,直到能够执行全部以太坊历史交易。
这个版本增加了运行 runtime bytecode 的能力,也就是先部署合约,然后再针对部署之后的合约内容,进行调用,调用的时候可以带上一些参数,比如:
go run ./cmd/echoevm -bin ./build/Add.bin -function 'add(uint256,uint256)' -args "3,5"
这个命令的含义是,会执行 ./build/Add.bin
文件内的 bytecode,并且调用 add 函数,传入参数 3 和 5,最终程序运行结束后,会返回出计算结果 8。
实现了一个非常简单的版本,现在可以用 solc 编译一个 Add.sol 合约,然后让 echoevm 读取生成的 Add.bin
部署代码,就会输出合约部署之后的运行时代码。
在实现这个版本的过程中,学习到的东西是部署代码和运行时代码的区别。我们一般会先部署一个合约到链上,然后再对这个合约产生调用,这实际上是两个不同的操作,但又都在使用相同的 EVM 执行,EVM 并不关心输入的 bytecode 是部署还是调用,只是对不同的操作码处理方式不同。一般部署代码会同时包含 CODECOPY
和 RETURN
两个操作码,可以利用这一点来区分输入的类型。
2025-04-30 22:18:54
我给这个系统取名 zkgate.fun,主要想发挥零知识证明的特性,结合区块链做个小工具。
主要功能是实现,用户证明自己属于某一个群组,但是不需要暴露自己真实的链上身份。
目前的设想是这样,管理员首先有一个名单列表,可以是以太坊地址的数组,然后根据这个地址列表,计算出一个 Merkle Root Hash。
接着把这个 root hash 提交到智能合约上。
处于这个名单中的人,可以使用 Circom 电路的 proving key,来给自己生成一个 zk proof,随后将 zk proof 提交到智能合约上。
在智能合约上,会使用 Circom 电路生成的 verifier.sol,对收到的 zk proof 进行验证,判断用于生成 zk proof 的地址,是否在 Merkle Root Hash 中,最后将判断结果返回。
这样的话,管理员不需要公开自己的群组中有哪些地址,属于群组中的地址也不需要声明自己的身份,只需要提交零知识证明生成的 zk proof,就可以证明自己真的归属于这个群组。
我接下来会具体在技术上实现这个设计。
有一个现有的、以太坊基金会支持的、工具链和生态都已经比较成熟的 zk 协议,同样是用来做身份验证的项目,叫 Semaphore,官网是这个,可以直接在上面体验一下包含前端界面的 Demo:
在 zkgate.fun 前面两个版本的迭代中,没有选择 Semaphore 使用 EdDSA 账户体系的方案,主要是不想脱离以太坊的账户体系,也不想放弃 ECDSA,而实际上只有 EdDSA 是 zk 友好的,可以使用 Poseidon Hash 签名,zk 电路中也能对签名进行验证,不需要 “链下签名、链上 recover” 这种丑陋的实现方式。
不得不说,从个人学习的角度,虽然没几天的时间,但是我已经大概理解了 zk(工具链)的操作过程。从行业前沿的角度,我仅凭个人力量不可能做的比 Semaphore 更好。即使 zkgate.fun 进一步开发出前端界面、可视化地演示出具体的交互过程,也顶多就是 Semaphore 的这个 Demo 的样子,而且技术上没有 Semaphore 硬核。
所以 zkgate.fun 这个项目不再继续开发,域名一年后会自动到期,不再续费。
这个版本解决了验证地址所有权的问题,基本思路是让 zk 证明和地址所有权的证明分开,链下用 zk 证明地址的路径在 Merkle Root 上,链上需要用户提交用私钥对 root 的签名,并且将签名提交到链上。然后合约 recover 出签名的地址,跟 zk 电路的 prove 中包含的地址信息对比。
1. zk prove 包含地址信息 -> 链上验证 zk prove -> 得知 zk prove 中的地址信息2. 用私钥对 root 签名 -> 链上得到签名 -> recover 出签名对应的地址信息3. 判断 zk prove 中的地址 == 签名 recover 出的地址
演示代码具体改动的地方有:
到此为止,zkgate.fun 实现的功能是,群组管理员不必在链上公开自己的群组成员信息,只需要提交 Merkle Root Hash 到链上。对于群组内的成员,需要完整的成员列表,以及自己地址对应私钥签名后的信息,就可以生成 zk prove 去链上,证明自己确实是群组内的成员。
在这个过程中,使用 zk 唯一隐藏掉的信息,是群组成员的完整信息不必上链公开,只需要一个 Merkle Root Hash。而用户的地址目前无法隐藏,必须提交到链上用于验证。
首先要纠正之前设计中的一个错误的地方,就是管理员必须要公开自己群组的地址列表,否则无法根据地址列表来生成 Merkle Tree,用户也无法根据树结构,来找到自己地址所在的节点位置、生成路径证明。
其次是很高兴地说,现在跑通了一个非常初级的 Demo(smallyunet/zkgate-demo),这个 Demo 功能并不完善,甚至没有办法在电路中验证地址的所有权,但至少是一个工具链路层面的跑通。
具体实现是这样:
假如一个地址不在群组列表中,有两种情况:
那么目前这个最初级版本的 Demo,问题在于,构建 prove 使用的是明文地址,比如:
const members = [ "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC",];const proofKey = toField(members[0]);const { siblings } = await tree.find(proofKey);
这个语句的含义是在让 zk 电路判断,members[0]
是否属于 members
数组构建出来的树结构,这显然是属于的。如果想要用不属于群组的地址构建 prove,只需要替换一下 proofKey 指向的地址:
const nonMemberAddress = "0x1234567890123456789012345678901234567890";const proofKey = toField(nonMemberAddress);const { siblings } = await tree.find(proofKey);
也就是说,members 列表必须是公开的,而现在的程序只能判断一个地址在不在 members
里面,但即使 members[0]
不是我的地址,我也能用来构建一个合法的 prove。那还要 zk 干嘛?
所以下一步要解决的问题,是让用户用私钥对某个消息进行签名,然后在 zk 电路中根据签名 recover 出地址,接着判断 recover 出来的地址是否属于 members 数组。
这个过程是不是听起来简单?可实际上用 zk 电路来 recover 出一个 ECDSA 签名算法的地址,别说复杂度非常高,难度就像用乐高搭核电站一样。难怪人们都说,搞 zk 真的很掉头发。
2025-04-29 19:26:45
giveme.wtf 是我刚注册的一个域名,计划做一个 web3 打赏的小工具,类似的 web2 平台有:
与之不同的是,giveme.wtf 的个人页面上,将显示 web3 钱包的收款地址、二维码,就像 Paypal 的个人收款链接一样,并且同时支持多种链的地址格式,包括比特币、以太坊、狗狗币等,可以自由选择。
giveme.wtf 不做任何资金的中转,仅仅只是展示打赏地址这一信息,比如,访问 giveme.wtf/{username},这个页面将显示出 username 设置好的收款地址信息,包括以太坊地址文本是什么,二维码是什么。就这么简单。
当然 giveme.wtf/{username} 下,也可以设置简单的 bio,头像、域名、社交媒体等,像是一个小型的个人主页,让人知道你是谁,稍微更值得分享出去一点。
user 使用 MetaMask 钱包注册,连接钱包后可以设置 username,username 是全局唯一的,在智能合约上管理,user 需要发一笔与合约交互的交易,来将自己心仪的 username 提交到合约上。
绑定好 EVM 地址与 username 的关系后,就可以设置 profile 信息,包括头像、bio、钱包地址等。
填写信息后,前端页面将数据提交到后端,后端用 IPFS 节点保存这些数据(长期开启 Pin),同时生成 CID 信息,将 CID 返回给前端。
前端收到 CID 后,再发起一次合约交互,将 username->CID 的映射关系,写入到智能合约里。这个步骤可以和注册步骤合并,也可以拆开,因为有时候 user 只想注册,不想设置 profile。
合约上的 username->CID 是最权威的数据,前端页面将根据 giveme.wtf/{username} 中的 username,从合约中获取到 CID,再拿着 CID 去 IPFS 的网关查询出具体数据,根据数据渲染出页面。
profile 会是一些非常精简的 json 数据,数据量很小,同时为了加快网关的查询速度,可以用 Cloudflare 提供的 web3 gateway CDN。
智能合约部署在 base 上。
后期可以根据链上数据,统计出使用打赏系统的收款地址,以及收到打赏的金额总量,做个排行榜,按照 username 或者链分类,分析出一堆数据。
如果上了排行榜,username 下的 bio 可以增大曝光率。给你心目中的偶像上分吧,让他保持在榜首。
还可以增加一些 24小时榜单、PK 性质之类的排名。
同时也可以扩展到社交系统,如有打赏记录的地址可以形成关系图谱,甚至可以直接以某种 IM 工具的方式通讯、自动拉群等。
MetaMask 钱包注册的问题在于,钱包丢了怎么办,是不是就失去了对 username 的控制。这里可以设计一个恢复机制,比如允许 username 设置一个恢复地址列表,只要是这个恢复列表中的地址,都可以找回 username 的控制权,进而改变 username 对应的 CID。这个机制主要是针对钱包遗失的情况。
至于钱包被黑了怎么办,黑客岂不是能直接修改恢复地址的列表。他都已经有 username 控制权了,再改也是改成他的地址,加固他对 username 的控制权。那么有没有钱包被黑还能夺回控制权的办法?web3 里没有。
目前必须要选择一条链来部署智能合约,智能合约是数据正确性的来源。那么选择哪条链其实是个问题,因为作为 user,不一定有链上的代币作手续费。
比如选择了 base,那么 user 首先得有 ETH,其次得在 base 上有 ETH,然后才能后续的操作。光是这两步,就能劝退大多数人。
那么为了解决这个问题,后面可以考虑的方向是手续费代付,用 ERC-4337 (现在差不多凉了)的 paymaster,或者比较原始的 Meta Transaction 方式。但是又得考虑到薅羊毛的问题,代付也得付得起才行。
MVP 里的方案是,数据用 IPFS 存,但仅仅只有一个服务器。IPFS 是比较底层的文件路由协议,可以考虑在上面包一层,像 Filecoin 一样,但是不会有 Filecoin 那么复杂,因为 giveme.wtf 的数据量比较小。PoST 难用的地方就在于需要对文件做加密解密,因为文件太大又不能全量校验,但 giveme.wtf 不一样,往简单了做就行,比如验证一下 Merkle Root Hash,也就是说,后面需要在 IPFS 的基础上,加上适当的文件校验和激励机制,让更多的节点愿意存下 giveme.wtf 完整的数据,然后用一种方式来定期检查每个节点是否真的储存了完整数据,如果存了,就给一点奖励。具体奖励给什么再说。
每次前端页面都从合约上查 username->CID,交互太慢了,而且消耗节点的 rpc 资源。需要考虑链下来缓存这部分数据,比如有一个中心化的后台程序,监听合约的事件,实时拿到 username->CID 的内容,然后写入到 Cloudflare Workers KV 服务里。前端页面首先请求 Cloudflare Workers KV,如果没有内容再 fallback 到合约上查。
那么这里又涉及到一个问题,如果中心化的服务作恶,或者被黑了怎么办,username->CID 的映射关系一改,钱直接打到黑客的地址上了。
这个链下数据完整性校验的问题,其实是 Optimistic Rollup 在解决的问题,也有相对成熟的方案。然后结合 Zetachain 的跨链逻辑,可以这样设想。
首先用来缓存的链下程序,将每一个 username->CID 的数据作为子节点,构建一个 Merkle Tree,最终会得到一个 Merkle Root Hash,这个 root hash 将是校验数据完整性的凭证,把这个 root hash 定时提交到合约上,前端页面去合约上查一下这个 root hash,就可以知道从缓存里拿到的 CID 有没有被篡改。
其次链下的索引程序可以有多个,通过 TSS 协商出一个私钥,只有这个私钥,才可以向合约提交 Metkle Hash Root,并且这多个索引程序,只有 root hash 相同,才会协商成功。相当于做了多签。
最后是冷静期+挑战期,Merkle Root 提交之后,在冷静期内不生效,同时任何人都可以发起挑战,如果挑战成功,则新提交的 Root 作废,继续用旧的 Root。当然这个步骤中的挑战是很麻烦的,得考虑到怎么发起挑战,尤其是怎么挑战才算是成功这个机制。但是好在不用着急做那么复杂,这个属于后期可以优化的方向。
2025-04-12 20:33:38
有点标题党,不要太介意。我想表达的是不应该过于关注使用的工具。很简单的逻辑,只有自己工程能力不如 Cursor,才会觉得 Cursor 厉害,干什么都行。当然这句话属于比较空的废话。
事实上,Cursor 的代码补全能力没有比 GitHub Copilot 好多少,底层使用的模型是一样的,不是 Claude 就是GPT。而在工程化调教方面,Cursor 和 Copilot 都是在把一些文件作为 context,继续后面的对话。
Cursor 比 Copilot 好一点的地方在于,会自己去当前工程目录下,搜索和参考其他文件的写法,这一点确实有用,你不需要告诉他具体引用那哪些文件,他自己会不断的尝试,Copilot 这种插件是不具备这种能力的,这确实是好的一面,如果项目下存在大量可复用的代码,Cursor 可以比较好的发挥出它的能力。
但有时候又会觉得 Cursor 过度智能,它甚至会自己在你的工程下面创建新文件,而不需要经过你同意,这就导致在用 Cursor 的时候需要时刻关注,他是否改变了你预期之外的代码文件。相比之下,(GoLand 下的)Copilot 只是插件的形式,只会给出代码片段,用不用是你自己的事情。VS Code 下的 Copilot 现在和 Cursor 倒是有类似的体验了,会给你一个接受或不接受更改的选项。
所以相比来说, Cursor 和 Copilot 使用了一样的大语言模型(不会有人觉得 Cursor 自己训练了个模型出来吧),然后 Cursor 拥有更大的、项目级别的控制力,而 Copilot 像他的名字一样,只是辅助级别的能力,这是它们最大的区别。
回到模型本身,o1 是迄今为止最厉害的模型,在日常工作中深有体会,我经常用 o1 来精准定位编程中遇到的 bug,而对于相同的问题,其他模型往往给出错误或者不准确的解释,包括 o3-mini-high 和 4o。
比如,在调用智能合约的时候,原本的命令是
cast call requestPrice(string) "BTC" —-rpc-url=http://eth:8545
现在需要调用另一个函数,比原本的函数多了一个入参,我就直接复制代码写成
cast call requestPrice(string) "BTC" "USD" —-rpc-url=http://eth:8545
不知道你有没有第一时间看出问题?其实 4o 倒是给出了正确的分析,只是没有特别精准,给出了 3 种有可能的错误原因,而 o1 直接就说对了。
当然大模型之间的差异不会体现在这么微小的问题上,只是正好有印象就随便提一下,我想表达的是,从日常体验来看,o1 是最好用的模型。
我严重怀疑鼓吹 Cursor 的人,都是之前没有使用过 AI、体会过 AI 强大能力的人,在用到 Cursor 之后,才明白原来现在的生成式 AI 已经这么强大了,欣喜若狂。而当需要使用生成式 AI 的时候,他们的第一反应不是打开 ChatGPT 的聊天框或者 Gotk3 的界面,而是打开了 Cursor 的代码框,开始去聊天。
所以鼓吹 Cursor 的人,实际上是把生成式 AI 的能力,误以为是 Cursor 的能力,才因此觉得 Cursor 异常强大。
我在工作中就不止一次被强烈推荐使用 Cursor ,让我别再用 GoLand,还说出 “GoLand 就是垃圾” 这种话,Cursor 最好用什么的。
首先我一直觉得喜欢用什么编辑器是个人的选择,管这个干啥。其次如果觉得使用什么编辑器会给使用者带来鄙视链和优越感,未免有点小儿科。最后就是我喜欢用 GoLand 的理由,只有两点:1.箭头非常直观的表达了接口的实现关系。2.前进后退快捷键很好用。基于这两点,我才可以比较快速的读懂和理解代码。
也因此带来一个差异是,使用 GoLand 的人,往往更加关注代码逻辑,比如在寻找代码位置的时候,喜欢通过代码之间的跳转,例如接口的实现关系等。而使用 Cursor(VS Code)的人,更加关注项目的目录结构、文件名、文件的位置,因为 Cursor 没有提供很好的代码跳转功能,所以不得不更加依赖通过项目结构来梳理代码功能。
代码的自动补全方面,GoLand+Copilot 插件能应付日常场景,需要补全的往往是打日志之类的内容,简单用用就可以,我不太敢用 AI 写侧重逻辑的代码。
给我推荐使用 Cursor 可能还有一种心理就是,觉得我不知道怎么使用 AI,或者觉得我不知道怎么使用 Cursor (?),也挺奇怪的。我在 2023 年(ChatGPT 开始大火的那段时间)就试用了 ChatGPT,还写了《不要小瞧 ChatGPT》,而现在不论是日常工作还是生活,都在高频率使用 ChatGPT。
总的来说,我的意思是,你可以喜欢 Cursor,也可以使用 Cursor,但最好不要鼓吹 Cursor。
2025-03-25 21:45:43
前情提要,推荐王垠的两篇博客文章:
由于过往不规范的工作经历,我之前是缺少对 Code Review 的理解的。最近因为同事对这个问题情绪化的表达,我开始关注到关于 Code Review 的问题。
谷歌公开出来的 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 场景下最正确的实现方式,并且能够条理清晰地去说服别人。
如果说我从自身技术发展的角度,是不太在乎这种问题的。这个问题本质上是我们平时面试时候说的八股文,随着最近几年面试风向的转变,也越来越多的人开始逐渐达成一致、反感八股文一类的东西了。
当然追求这一类底层问题到极致的人,肯定是有技术追求的人,这并不是什么坏事,我们应该尊重任何努力以及对技术较真的人。只是技术也分很多种方面。
我算不算有技术追求的人呢?也许有时候算吧。无论是技术还是别的东西,其实我们所有人都愿意追求有趣的东西。
从过往经历来看,我关心的技术话题并且乐于出自兴趣去学习、思考的,比如:
PoW 和 PoS 的本质区别是什么,PoW 好还是 PoS 好
以太坊的 PoS 和 Cardano 的 PoS 有什么区别
PBFT 的优缺点是什么,PBFT 有哪些优化的空间
不同类型的区块链是如何处理分叉的
区块链可能有哪些有趣的应用场景
知道这些东西有用吗?没什么用,面试的时候几乎不会有人问,工作中更是用不到,就仅仅只是出于兴趣爱好去探索这些技术问题。这些问题的答案,从来也都不是现成的,网络上是搜索不到的,ChatGPT 也是没办法精准回答的,只有经过一段时间的学习,加上查阅论文资料,结合自己的亲身经历和理解,才可以形成技术观点,无论观点本身是对还是错。
因此可能出于某种思维上的惯性,我很少关心太过基础的编程类问题。这种事情因人而异,不能强求,自然也不能强迫别人因为 FYI 就去关心某些问题。
(刚说完不要 FYI,我这里就在 FYI)
《Rework》 这本书里有一个章节印象挺深,标题是 “Hire great writers”,书中的观点是,不是因为工作中需要发表什么文章、写什么报告,而是好的 writer 往往具备逻辑清晰表达问题的能力,可以帮助到工作。
回到技术问题上,现在各种形式的技术文章也都非常普遍,比如对锁的使用场景比较有心得的话,完全可以落实到文字上,输出成果形成一篇文章,分门别类的介绍锁的种类、最佳的使用场景,然后发表到各种平台上,获得成千上万人的关注,再然后如果对其他技术细节也有心得,内容逐渐丰富,直到写出了一本书,甚至有出版社看上,或者公开到网络上作为电子书开源……FYI……何必跟我较真呢。