最近在教一名学生封装 2D 可视化渲染引擎的时候,无意间了解到了他一个的想法:
我们封装的这个东西,别人已经有非常成熟的实现了,为什么还要自己重新封装一遍?如果面试官问这个问题,我都不知道应该怎么回答。
通过进一步聊天我的感受是,他觉得重复造轮子在我们行业里其实是一件不那么光彩的事情,他一直以来听到的都是不要重复造轮子。
很显然,确实在我们行业有很多人会旗帜鲜明的反对重复造轮子,这句话影响也是非常大的,我们会发现很多人在面对新需求的时候,常常脑袋里的第一反应就是:有没有什么库能直接帮我搞定这个需求。
但是我的观点却恰好刚刚相反,我觉得作为程序员,在能力范围之内,一定要尝试去造几个轮子。哪怕刚开始因为能力不足造轮子困难,或者造出来的东西不好用。
说一下我的理由。
一、找轮子花费的时间也不少
其实我们会花大量的时间在找轮子上。
这件事情我比较有体会,因为我以前经常干这个事情。这里面最痛苦的事情是当你找到一个轮子之后,到底好用不好用其实你自己也不知道,然后用了一半之后发现不完全是自己想要的,有的功能实现不了。
然后你就只能重新找。
有可能要反复几次之后才能找到完全符合当前需求的东西。但是也有可能找不到,最后只能妥协需求,实现一个大概差不多的东西。
虽然最终也交差了,但毕竟给同事留下了一个不好的形象。甚至会直接影响自己的升职加薪和年终绩效。
二、别人造的轮子并不完全符合心意
最近有幸能有机会参与到 openInula 技术方案的探讨会议中去,在几位华为、腾讯大佬的讨论过程中我也学习到了很多东西。
在设计一个东西的过程中,我能很明显感受到的一个现象就是,每个人都有自己的技术偏好。哪怕是在设计一个小小的语法上,大家也会有不一样的喜好。
就拿我自己来说,我并不喜欢 React 语法里 useState 用数组来解构,每次看到几个的数组解构堆在一起我就觉得浑身不舒服。
const [loading, setLoading] = useState(true)
const [param, setParam] = useState('')
const [list, setList] = useState([])
const [error, setError] = useState('')
所以我在使用 React 的过程中,做得最多的事情就是想办法把这些 state 藏起来,用自定义 hook 重新封装,并一定要改成对象解构的语法来使用。
const {
loading,
setParam,
list = [],
error
} = useFetch(searchApi)
又比如有的人觉得 solid.js 非常惊艳,是他理想中的样子。但是我还是觉得 solid.js 的语法比 React 更让我无法接受。
const [count, setCount] = createSignal(0);
一方面是因为沿用了 React 的数组解构,另外一方面是因为返回的 count,他不是一个值,而是一个获取值的方法。
因此我们使用的时候必须这样用。
count()
但同时,他又可以是一个值,例如我们这样用的时候。
setCount(count => count + 1)
这违背了我一直严格遵守的语义化和单一性,所以我主观上不接受这样的语法设计。
包括 solid.js 在 props 的处理上,为了确保修改之后的 props 具备响应性,不得不新增了两个语法,mergeProps splitProps,这也是我不愿意接受的语法设计。
这种偏好其实非常主观,但是确实是每个人都会或多或少有这样的怪癖,会觉得别人的语法写起来不舒服。
三、不完全符合需求
有的时候一个优秀的轮子你对他赞不绝口,然后用了半年之后,突然来了个需求,它满足不了。贼难受。
于是很多程序员这个时候又不知道咋跟产品经理沟通,他会犯一个经典的职场错误:直截了当的告诉产品这个事情他做不了,甚至有的人会更夸张,还会解释说这个需求我用的组件库不支持所以我做不了。
这种沟通方式最大的问题,就是在跟同事暴露你技术能力不行。你可以用别的任何理由去拒绝这个需求,但理由一定不能是我实现不了这个需求。
如果一年中,你有 2 次出现这种情况,你就会发现你的年终绩效会受到很大的影响。一年两次这样的频率其实非常低,真实情况可能远不止两次。但是即使只是两次,别人也会觉得你能力有问题。
所以别人的轮子往往会限制我们,哪怕他满足了你 99% 的需求,如果突然来了一个需求满足不了,就会让你很难受,直接面临职场危机。
四、遇到 BUG 难以修复
有很多轮子是不得不用别人的。然后就经常遇到的一个问题就是,如果在特定场景之下遇到一个 bug,轮子作者也不会马上帮你把这个 bug 给修复了。
你提的 issue 可能轮子作者隔了半年才反应过来可能会修复你这个问题。
有的时候修复这个 bug 也非常不容易。因为你特定场景的 bug,作者要复现可能比较困难,甚至会因为沟通问题,比如你提供的信息、版本、环境不充分,而导致作者根本就复现不了,导致最终也改不了你这个问题。
这个时候是最难受的。
所以我以前经常 fork 别人的轮子,然后去把他的源码给改了,改个名字重新上传到 npm 上,当成自己的轮子用。这样虽然勉强解决了问题,但其实也并不是一个好的方案,因为后续的版本就开始完全分道扬镳了,后续所有的改动都要你自己动手操作了。慢慢的也走上了造轮子的道路。
五、场景不匹配
有的时候我们会发现别人的轮子跟我想要的场景不太匹配。
例如我需要一个图表库,我希望他能在网页上跑,又希望他能在小程序上跑,还希望在 React Native 上也能跑。这样对我来说,项目的维护成本是最低的。
实际上如果是我自己写的轮子的话,我要做的兼容成本非常低。但是这种特定的需求可能别的轮子就不会专门帮你做这个事情。
于是我们就不得不在不同的平台使用不同的轮子。难受的是,如果遇到定制化 UI,有的轮子支持得就不那么好,就会出现一个诡异的现象,明明能在 web 上做得非常好的功能,在 RN 上就搞得缺点意思,给人一种很古怪的感觉。
六、自己造的轮子,可以更轻量
成熟的开源项目往往会考虑更多的因素,因此你常常会发现许多开源项目的源码读起来非常痛苦,各种条件判断特别多。原因就是成熟的开源项目他需要兼顾更多的场景和需求。
但是在你的项目中,有可能不需要考虑那么多。
这样我们自己造的轮子其实是可以更轻量,更简单。例如我自己封装的一个状态管理器 mozz,只有 10 多行代码,在特定的场景下结合我自己的项目架构思路,用了 5 年了也没出什么问题,非常舒适。
所以我一直以来,对别的 React 生态中的状态管理并不是很关注,因为他们内部到底是怎么实现的,具体的优缺点是什么,是否是我的项目所必要的我大概心里也有数。
在我公众号文章里,前面介绍了几种封装状态管理器的思路「半成品」,其实就覆盖了好几种状态管理的实现原理,例如基于 reducer 和 useSyncExternalStore 的 zustand,基于 Atom 的 Jotai,只是在最终实现上,语法设计上会有所不同。
七、提高技术竞争力
最最主要的原因是,造轮子能提高我们的个人技术能力。能造轮子的人,技术能力肯定是要比不能造轮子的人更强。
实际上很多人会觉得造轮子可能比较浪费时间。其实恰恰相反,这东西是可以不断累积的。工作时间长了之后,你就会发现你需要亲自造的轮子会越来越少。
然后到了后期,很多时候都是出了一个新框架,新平台,你需要自己动手去做迁移和重写。就比如这次鸿蒙开发起来了之后,我们的交流群里面就有几个大佬在着手把以前自己写的轮子重新在 arkUI 上写一篇,花的时间也不是很多。
当然前期受限于技术能力和工作时间,造轮子会比较困难,甚至有的人会觉得无从下手。
那么我们有几个方式可以走,首先就是先从简单的轮子开始,例如在我职业生涯的早期,我自己写了一个专门操作 cookie 的库。
或者搞一个更简单的,写一个专门用来创建 css3 动画的 JS 库。
然后慢慢的逐渐深入,写一个拖拽库,或者写一个动画库,写一个轮播图库。
这些都是比较简单就能做到,不需要太高昂的学习成本。只是很多人内心深处觉得这些事情根本没必要,完全是在浪费时间而已。
打个小广告:你也可以直接付费找我学习从零开始基于 canvas 打造一个 2D 可视化渲染引擎,费用 2000 元,助你快速提高技术能力,在面试时手握利器,不用为项目亮点而担心。
八、直接和薪资,绩效挂钩
有人不知道年终总结怎么写,自己一年下来都在写页面,好像对团队也没什么特别的贡献,想涨工资又不好意思找老板提。
想要晋升也不知道用什么去谈。
我其实都没怎么遇到过这种烦恼,因为每年都有产出和贡献。这就是经常自己造轮子的一个非常大的好处。
因为实际上团队内部有自己的技术沉淀这件事情本身就是非常重要的。因此你总会发现一些好的团队总是非常热衷于自己造轮子,然后你还会发现很多人会嘲讽这种现象。
对于这种嘲讽我们完全不需要理会,一方面是他们并不理解团队技术沉淀的重要性,别人的技术终究是别人的,不管是从团队角度或者从个人角度出发,尽可能少的受限于他人,本身就是我们应该追求的目标之一。
另外一方面是因为你拿到手上的是真金白银,那些嘲讽的人又不会给你发钱。
九、总结
总之在能力范围之内,尝试自己造轮子是我比较推崇的观点。他的好处我有切身的体会。你也有机会认识更多的大佬,能更轻松的找到工作等等。
但是一定要操作得当,不要因为造轮子而导致任务总是 delay,一个好的方式就是把造轮子的事情上升到公司层面的需求,而不是自己私下悄悄搞,这样的话就不用担心任务 delay 这个事情了,你也有充足的时间和正当的理由来做这个事情。
当然这样做也有坏处,就是以后你造的轮子就是属于公司了,所以我当年这样做虽然可以大量利用上班时间来通过造轮子提高自己的技术能力,但也导致了很多东西不能开源出来,属于是有利有弊吧,自己权衡就好。