从beego谈起,畅聊Go的优雅与高效
今天和大家一起分享的主要题目就是从beego开源谈起,然后畅聊Go里面的优雅和高效。先和大家分享一下我做beego的初衷还有设计思路。
首先和大家介绍一下我自己,我是beego的作者,也写了一本书叫《Go Web编程》。我还是Go官方中国区社区负责人,现在也发起了一个Go基金会,主要做Go到校园、企业等推广工作。在2017年的时候,我们举办了第一届Go Hackathon,效果非常好,孵化出很多项目。
我在盛大创新院的时候开始写 beego 框架,到现差不多六七年了。如今 beego 已经逐步成为很受欢迎的一个框架,到今天达到了22.2K star。beego也在国内外很多公司中,被开始应用到实际场景及自己的业务中。对此我感到非常荣幸。
今天和大家一起分享四点:
1. 我为什么开发beego,这个是最早的框架的思路来源
2. beego设计思路
3. 开源
4. Go的发展路径
设计初衷
最早从2000年起,我开始写PHP,一直写到毕业之后。后来在企业,就发现PHP其实在性能方面有一些局限性。
我记得很清楚,在百事通的时候,我们用PHP做了很多应用,有应用很火,因为面向儿童,所以一下就会有十几万的并发。那我们如何去优化那个性能?我记得连续熬夜三、四天一直在优化这个东西。用C写的话,还经常遇到内存溢出等问题。我从百事通离职之后去了盛大创新院,那时候开始写CDN,但CDN在应用性能方面遇到了更大的问题。
之后,我就开始想如何解决性能问题。我在盛大接触了Go语言,就想用来解决一些性能的问题。我第一个做的是大文件分发系统。那时候流行桌游,一个就很大,300多个机房,要把文件分发下去,遇到的问题很大。
我们最早那套系统也是用C++加PHP来写的,原来写PHP也写惯了,怎样用MVC之类的。所以这个时候就开始积累了一些我们自己原来思路里面的小框架。所以我们最初设计beego的初衷是去解决性能的问题,就是在PHP写的程序里面性能的问题,同时也去解决C++里面编译时间太长的问题,所以就在正式项目中开始应用了。
在这个过程当中,因为我对python这些东西还比较熟悉,然后那时候有一个很不错的框架,叫Tornado。当初好像是Facebook他们开源出来的,在各方面的性能都非常好,所以我一开始写beego的时候大多思路都来源于此。
设计思路
我们可以看到Tornado最早的时候程序是这么写。就是有handler,每一个handler里面有一个application,进来每一个handler里面又有一个路由,然后在每一个handel里面,又一个restful的这个结构。所以我最早的beego,非常简单,估计就20个文件,把整套程序给实现了出来。可以跟大家一起看一下,Tornado最初的程序就是这样。
我基于Tornado整理了处理的流程,算是一个用户,然后怎样从路由解析分为静态文件和动态路由?静态文件是静态的一套逻辑,动态路由、过滤器,怎样动态注册的这个结构体?然后initial初始化,然后prepare,再次到restful的那些函数体,再到是不是要渲染,然后直接到分离器那,这样一套从接收请求到最后渲染出来返回的这个过程。
所以,从最初版到现在为止其实一样,beego保持了这种一样的风格,即怎样注册路由,然后路由注册为之后到control这个过程,再怎样做restful的整个设计逻辑。这里可以溯源,大家可以看一下beego最早的代码。其实我们应该是这个领域里面做的最早的一个框架,后面有很多框架都参考了beego的设计思路,后来一代一代衍生出来。
整体来说的话,借鉴自Tornado,设计思路包含下面这几点:
1. 模块化
beego里面看上去好像很庞大,但实际用过就会知道里面都是一个个独立的模块。
2. 分离
我觉得这个是Go里面最优雅和设计精妙的一个地方——interface和inpermanentation的分离。在beego里面,包括我最初设计那个cache模块的时候都会有,比如定义interface,后面的inpermanentation就是会有好多种,然后就很容易去实现。这个开源后,有很多贡献者会在这个基础上实现这个东西,其实Go里面的Interface设计就是类似思路。
3. 组合
即我们如何把一个个模块组合起来,使之可以快速开发应用。因为,我觉得如果要快速开发应用,这些东西必不可少。放在别的地方其实只是多引入了几个模块而已,放在一个地方也没有什么差别。
4. 少即是多
这很难,但在设计beego的过程中,我们需要去平衡。
所以我在beego的整体思路之前,其实希望有一个乐高的模式,所有的模块都可以小模块化,然后可以拼出来一个大的应用。beego在设计的时候主要会为了两类应用,一类是API应用,一类是web,如此我可以快速开发一些web应用。
所以我在设计beego的时候,主要参考了这些东西:
第一,简单的内核,路由进来之后怎样路由到control里面去,里面可能有一些contact的处理,然后直接输出,这就是一个简单的内核。
第二,丰富的模块,我知道其实最早的时候,Go刚刚出来的时候,什么sension都没有。所以beego其实给Go社区带来了丰富的插件库。后来很多人把beego的东西迁移到其他的框架里,我觉得这其实给社区起到了一个很好的带动作用,这就是开源的力量。
第三,我也是在做这个beego的过程中学到很多其它框架,借鉴优势。其实最早我做beego的时候,根本就没有某个概念,只能自己去模拟出来这些东西。
第四,提供强大的开发工具这是beego的首创,比如B框架、热启动。因为我自己在开发项目,会遇到各种各样的这些问题,所以我要给开发者提供一个非常强大的开发工具,大家如果用过那个beego,可以从数据库里反向读出来,自动生成代码。
第五,插件化设计,即如何让beego快速调用插件,比如过滤器怎么插进来,就是作为beego插件化的一个设计思路。
整体上,我希望为开发者来设计出速度更快、性能更快、内核更简单的框架。
基于此,beego做了一个微内核,把路由器做了。路由器做完后,因为结合了control的思路,就是restful。然后就实现了很多其它模块,包含config、contact等,这些模块差不多十个,接下来会跟大家一起分享我的设计思路。
模块设计思路
在这个log的日志模块中,我设计了一个interface,然后又设计了一个register用来快速实现这个interface。我现在只要实现这四个函数,就可以实现任一形式的log。当然log就可以写信息,然后去调用这个log,至于我要存到哪里,只要通过实现interface,我就可以去实现这些信息。
大家可以看一下log的实践,这个是SMTP,我可以直接发邮件出来。所以我实现了这四个函数,于是我已经实现了这个log的interface。但最关键在于因为你会Init,那Go里面会有这个Init,直接register这个东西进来就好了,然后调用的时候,我只要调用这个SMMTP的employmentation,就可以直接去调用这个SMTP,只要用这个就会发到邮件。
beego大有优势的地方。
这个是beego filter的设计工程,有四个插入点。就是说四个地方所执行的,就是上面那个流程,里面可能会有几个流程比如before static 、before router、before excutenavator,然后finish,在这些不同的位置插入路由的位置,然后还有context,这样就可以非常容易阻断任何东西。
所以像这样的一个函数,Filter User,就可以在注册进去的位置,比如,去判断这个用户是不是已经登录了,那如果他没登陆,那就直接跳转到log in的地方,是不是有检测的登录。
目前beego的插件很多,我只是列出来了在beego已经有的。其实第三方各种应用很多,比如说像微信,SDK。在beego的官方里面,下载下来就可以用。
我接下来介绍一下B工具,用这个B的工具就可以快速地去做很多的东西,比如B的api就可以创建一个。beego的API application,然后B的fix,然后就可以把老版本迁移过来。beego的dlv可以去调试。dockerize可以产生一个dockerfile,然后generate,让你去产生一些深层源码。beego pack可以把这个代码弄成一个文件,直接可以部署。
beego run会用到比较多的东西,我在本地开发的时候就beego run起来,之后只要你有个源码。因为你经常会在改代码,beego run会监测你这个目录,下面你这个Go的文件,要有变更,就会自己做,就把这个程序给杀掉,然后边run,一边自动编译,编译完之后把它运行起来就是这样一个过程。
B server就是我们经常有一个静态目录,我快速打出一个服务来。这个是我原来在开发的时候遇到过这样一个问题:别人发给我一些静态的东西,说检查一下,看看是不是可以,因为CS加载的问题、路径的问题不能显示出来。所以用B server就可以快速地渲染出来出来这个东西。
所以大家可以看到,我在设计这个B的时候,都是从开发者的角度。比如我有些control要自己经常去写,其实就是复制,我们可以自动化去生成这些东西,所以我就写了这个B工具。
开源之路
那接下来就是开源之路。在国内我觉得大家做开源,有些时候做的不是很好,是因为我们只是开源代码,不是教别人开源代码怎么用。这是我们很多时候做的不够好的地方,我做beego其实也是因为我在大学时候的那段经历,我做PHP开源的时候也没有做文档,但是后来就发现好多用户其实不是很懂这些东西,所以文档是一个非常重要的东西,所以我在做beego的时候,很详细地写了中英文档,有详细的设计思路。
我觉得这是开源过程当中非常重要的一部分,我们去做开源,不仅仅是开源一个代码,我们其实是要开源我们的整个思路,开源我们这个社区的东西,让更多的人参与进来,让更多的人学会这个东西。我们现在很多人喜欢在QQ上问,当然这些问题可以快速的得到答复,但是你不可能24小时都回复。所以文档都很重要。
我觉得做开源要做到:
第一,持之以恒。我从12年开始到现在差不多七、八年了,一直在做这个东西,没有逼迫,没有利益,只是自己的兴趣爱好,但是这个很难。特别是像我现在创业之后,时间很少,但是我周末还是会抽出一些时间来改进。
第二,持续付出。需要为beego投入时间。
第三,强大内心。因为开源,会有人说你好,也有人说你不好,有人觉得这个是一堆垃圾,有人会觉得这个东西挺适合我。所以在这个过程中就需要自己的心理非常强大。
第四,心态开放。如果一个新框架是好的,那我们就应该去学习、使用。beego里面很多插件和模块,大家觉得好,那很多人会拿去用,我觉得这就是一个生态逐渐发展起来的过程,用开放的心态让Go和beego变得更好。
很多知名企业拿beego做了一些项目,这个我觉得很欣慰。因为beego有几个特点:
1. 容易上手;
2. 文本文档相对齐全;
3. 很多python或者PHP转过来人去用beego那一套东西,上手非常快,因为思路很接近。
beego总结
所以最后总结一下beego,我自己觉得是一个组合框架,很多的模块,它是松耦合的一种方式。第二,就是interface和angel分离,容易扩展的一个方式。第三,模块非常丰富,product ready。最后,我们是插件设计,可以动态地去扩展这个系统。
Go发展路径
最近大家可以看得到被吐槽最多的三大点,一个是L的过程,一个是泛型,第三个就是第三方依赖,我现在看到前两块已经解决的差不多了,说起L,大家可以看到,1.13发布之后它增加了很多新的包。第三方包的管理,Go Modul从这个1.13开始,其实已经很好的解决了这个依赖问题,当然这个里面还有一些bug另说。
至于泛型,最近我看到他们在社区里面其实已经有一个方案,而且已经开始在做这个东西,我估计在1.14到1.15之间会出来一个最初的原型,就是contract的一个模式。这个模式我上次看了一下,基本能够做到一定程度上的泛型,而且这个设计思路我觉得很优雅,就是和现在这个interface的定义类型有点类似,同时对我们的学习成本和使用来说会比较容易接受。