当前大家使用协同文档编辑工具,应该已经比较普遍了,比如飞书、Google Docs、石墨、语雀等等。在线编辑器方面,CodenPen有Collab Mode,Codesandbox已经实现了完整项目的协同。在线协同编辑代码(Collab Editing),很酷,对吧?所以,我也希望能让RunJS支持协同模式。
经过初步的调研,有两种比较可行的方案。 第一种,将RunJS编辑器由CodeMirror5升级到CodeMirror6,其已支持Collaborative Editing。第二种,将RunJS编辑器升级为Monaco Editor,并配合专门做数据协同的开源项目Yjs来实现Monaco Collab Editing.
由于CodeMirror6还不成熟,代码编辑体验不如Monaco,并且Yjs已经提供了集成Monaco的示例,最终我选择了Monaco。这部分工作已经完成。而协同编辑的部分,经过两周的技术调研,仍将持续。
为什么看似简单的协同编辑功能(人家连Monaco的示例代码都提供了),还要花这么长时间呢?这值得吗?围绕【深入研究Yjs的意义】,又引发了我更多的思考。
对于Yjs的调研,是做到可以使用就行,还是深入源码和原理,彻底弄明白才好?
最初,我是希望可用就行。把Yjs+Monaco Editor的Demo运行起来后,赶紧想办法集成到RunJS产品中,仿佛RunJS Collab Mode近在眼前。现实给了我一记重锤:协同编辑,没那么容易!
首先是持久化。Yjs示例的服务端程序,只将数据持久化到文件(y-indexeddb),而线上产品显示不能这么干。为了协作数据的实时性,我采用了Yjs提供的y-redis包(没有文档)。经过一番尝试,redis持久化搞定了。
接着是身份认证。如果不修改Yjs的开源依赖包,认证所使用的token,只能通过第一次websocket请求的url传输,也太不安全了。而websocket连接一旦建立,Client和Server端的数据全是Yjs定制版的二进制Encoding/Decoding,并且只传输文档协作数据。不支持自定义第三方数据结构。后来,只能将部分Yjs包下载下来,自己修改、打包(RunJS-Yjs),并建立私有npm仓库。这个问题算是勉强解决了吧。
然后是调试。引入了自定义的RunJS-Yjs,就得为其建立独立于项目的开发环境。难道要在这个项目里面再引入Monaco和React不成?NONONO!开源仓库的开发,并不像写为务代码,看一页面调试一个页面。Yjs的开发调试,完全依赖Unit Testing。做到这里,我又不得不将Yjs的开发、调试技术搞明白。在断点调试测试用例的过程中,又意外发现,Yjs的测试框架、加密解密算法,以及很多工具函数,也都是其作者完全自研的。不得不佩服他们的技术深度与广度!
最难的还是协作算法本身。Yjs实现了p2p的协作方式,并不是一定需要一个Sever端。只是现实业务中,总是需要有一个或多个中心化的服务器来做存储和权限控制。我最终是通过研读测试用例和源码,来试图理解算法的,结果发现效果并不好。我这才意识到,源码是理解代码实现的最佳方式,却不是理解架构和算法的好方法。架构和算法,在作者写的博客、做的访谈里面。果然,在官网的Talks and Podcast部分,我开始了解到Yjs所实现的协作模式,叫做CRDT。Yjs项目从开始到现在,已经迭代了8年之久!
OK,Yjs大牛都研发了8年的开源项目,我能在2周之内消化掉吗?显然不能。对于Yjs的学习,得从长计议。那么,对Yjs的深入了解,还要继续吗?是的。站在RunJS的角度,从长计议的技术方案,并不具备当下的价值。但是,Yjs的持续学习,让我有机会将很多并不熟悉的技术串联在一起,比如websocket、二进制数据压缩与传输、npm私仓搭建、Visual Studio断点调试NodeJS源码、CRDT的实现原理等等。这都将为下一步的Yjs甚至其他技术的学习,打好基础。
把8年长跑的Yjs看作是一个产品,也能给RunJS以启发。核心竞争力的建立,并非一朝一夕。只有坚定的信念、持续的热情和死磕的精神,才能匹配一个人人称道的产品。
而技术人的成长,只有以以目标为画布,深度为底蕴,以广度为画笔,才能画出更好的明天。
对于RunJS而言,当前有比协同编辑更实用的功能。比如团队版,只要实现成员管理和他人可共享与编辑就可能,实时协作只是锦上添花。在资源有限的创业条件下,是短期实用优先,还是长期创新优先?
对此,我并没有准确答案,只是试图做一些解读。
如果将RunJS的生命周期放在1-2年,那么商业模式是最为重要的事情。为了挣钱去做的业务,却不能挣钱,有意义吗?没有。这可能是一种更为务实的思路,也许RunJS只是一种试错产品。不行,那就换个方向。
如果将RunJS的期望放在更长的周期,比如也像Yjs一样,至少做五年。那么,暂时的用户、流量、营销,都不再是重点。我将有充足的时间来打磨产品做创新。
所以,优先级的问题,就变成了定位问题。
就像一句诗句所言:渔夫出海前并不知道鱼在哪里,可是他们还是选择了出发。当我开始做RunJS时,我也不清楚它究竟会变成什么。直到现在,我也没有找到RunJS究竟会为用户带来什么,除了那个用户,是我自己。不过没有关系,有些产品的生命力,只会在未来绽放。
只要保持RunJS的产品创新不停止,产品体验持续优化,它终将变成一个为更多用户创造价值的产品。