原文:http://blog.qiniu.com/archives/1048
谢孟军:大家好,我是谢孟军,我是beego作者。今天我来讲一下beego的设计理念和API开发,大家有听过beego的吗?有用beego在自己项目里面做吗?OK,今天的大纲就大概讲一下是这样,首先我要讲一下什么是beego,然后讲一下beego的设计理念,里面有很多的模块,每一个模块怎么样设计的,可能会牵涉到一些GO设计的东西,然后讲一下插件化的东西,最后讲一下API的开发。我个人比较看好Go在API方面应用的开发,当然Go用来开发Web也是OK的,但是没有用PHP开发那么方便,但是开发API的话GO是有很多天生的优势,所以到时候我会讲一下,最后我会用一个最近开发的一键式的开发工具,大家现在有很多的数据库,老板说要基于这个数据库做一个API,文档什么都要有,我先前因为在上一家公司做这个东西,因为公司数据库表有200多个,让我做我就要写的疯掉了,所以我就写了这个自动化的工具,可以从数据库自动的生成所有的API加文档,而且你还可以自动的生成对应的SDK。比如说PHP应该怎么调用你的API,因为它那一整套的生态系统已经全部有了,这就是选择swagger的原因,所以就可以一键式的全部生成基于你数据库表的API应用加文档。
什么是beego?beego是我进盛大的时候开始做的。当初我最主要的想法是要用Go做一个类似Python的框架,当开始的时候你会发现所有的方法其实跟Python是一样的,当初差不多就5个文件,然后我说一个框架也写好了很方便。刚开始我就是很简单核心的东西,后面随着我做的东西越来越多、越来越多,所以我就做了很多的模块,是有很多丰富模块的框架,但是现在还是保持着很少的核心,通过不断的增加模块、不断的增加一些库。
第二个因为基于这样的设计所以是很松偶合的框架,很多的东西都是模块化、插件,都是很容易去组装起来的。第三个是文档比较丰富,因为我知道很多人开源都是扔一个东西出来,但是后面都是很多文档都没跟上。因为这个是我以前做PHP的时候,那个时候就有很大的经验,就是说你文档跟不上你的用户就会有很多的抱怨问题、很多的反馈,你就不能跟用户很好的互动,而且又会遇到很多问题,如果文档跟不上你的框架、你的开源产品就没办法很快获得用户的认同,第四个是RESTFUL的设计,后来我看了很多路由的方式,最近又自己写了一个基于多叉树的路由,我是觉得现在市场上有很多路由库,例如httprouter号称性能最好,但是你去用它的功能就是一般的功能,我是觉得beego的路由是现在市场上路由支持最好的,同时性能也是佼佼者。接下来就是强大的Namespace,它可以实现你所有独立的东西,可以把你的代码全部独立成一个模块,把模块里面的路由命名成一个Namespace,这样你想什么时候增加前缀都很容易,很方便的进行扩展。接着是自动化的API文档,这是我最近才开发,最后就是beego框架除了一个框架之外还有另外一个工具叫Bee工具,Bee能够迅速的帮你创建一个项目的结构,现在我又增加了一个功能,而且可以基于数据库自动的给你生成所有的东西,你只要命名好输入就可以了,基本上80%的逻辑代码都会帮你完成,你只要核心的逻辑稍微自己再修改一下就OK。
beego现在已经有很多的用户在用,这边是很多的厂商,最近腾讯穿越火线的游戏现在后端有一部分也是用beego在做。淘宝和游戏公司都有,他们内部用的东西还是挺多,盛大我以前用beego做了很多开发的东西,zalora是我在新加坡的公司,beego就是用来开发mobile API应用的。
接下来开始讲一下beego的设计理念,主要是参考了Unix的设计理念,它有几个点:第一个是模块化、第二个是分离、第三个是组合。Unix的思想是你要把所有的事情都弄成一件简单的事情,把这件简单的事情做好,同时分离是引擎的分离,这个在Go里面特别重要,我后面会讲到。我们设计的时候GO里面最好的功能就是interface,而且对你测试案例的时候特别有用,最近就是不断在迭代开发当中,我越来越觉得interface设计的重要性。当一个应用开发完成的时候,但是整个程序会依赖很多的东西,例如数据库、搜索引擎等各种系统,如果你设计好了interface,那么就很容易的mock数据,这样对于整个的应用的测试用例特别有用。第三个是组合,把这些简单的事情组合成一个东西,到了重要的是less is more,Go可能更极致一点,少即是指数级的多。
beego的设计理念就是乐高的概念,大家有玩过乐高吗?乐高是很简单的小小片,可以组成一些部件,这个部件就是所谓beego里面会弄成一个一个的模块,最后大家可以把它做成一个很大型的系统,基于这些小的模块做一个大的系统,这就是我所有的理念,就是组合、分离。beego设计的理念跟前面一样,就是简单的内核,我还是一直保持了先前的设计风格,就是很简单的内核然后丰富的模块就是做了很多的模块,当然我学习其他很多成功的框架,Flask、Rails、sinatra,我们会参考它的ORM系统,rails里面我会参考他的I18N的库,只要是好的东西像PHP里面一些框架的设计, 只要好的系统我们就去学习他。然后就是提供强大的开发工具,Bee工具是我自己在实战当中总结出来的工具,开发中有可能就会碰到很多的问题,所以我很想自动化这些越到的问题,所以开发了这个工具。插件化设计是能够让我们的程序动态的扩展,最后是Fast、Fast、Fast第一个是我们要做的东西一定要让用户学习的快、开发效率快、运行效率快,所以这边写了三个。
接下来我简单的演示一下beego的快速入门。这个命令是安装Bee工具,装好之后Bee new mygo。这是我所在gopath的目录,如果要创建一个目录就ECUG就可以了,这样的话会帮你生成一个目录,我们就可以进入到ECUG了,已经帮你自动的生成了很多东西,如果要运行的话就Bee Run就可以了,就自动帮你监控所有目录下的文件,只要一修改就可以帮你编译,你就可以在浏览器里面看到这个东西。这个是beego的默认应用的页面,这个beego的默认页面是一个用户最近贡献给我们,人家前端写的比较好帮我们改成这样,很漂亮。
beego主要的模块现在有这些模块,就是cache、config、Context、httplib,Logs、Orm,sessions,toolbox,validation这些模块都是独立的,就是说不管你做什么应用假如说拿这个来说,你可以直接拿这个Logs去应用,beego框架不强制你用什么东西。Go里面有一个库有很多独立的库,beego我为什么没有把这些东西全部分离出去,因为很多给我提建议,我应该创建一个新的repo,这样大家可以重新用,但是这样的话我就没办法保证每一个版本出去的时候系统的稳定性和兼容性,我要保证每一个版本的稳定性,假如说我现在光光升级了Httplibs,假如说我现在依赖于Context的,那我升级了这个,那我还要不要升级beego呢?所以我要保证每一个整体的东西都是稳定的,但是独立的模块用户可以直接去用。
Cache设计这就是我参考了Go里面的database/sql设计,就是interface的分离。我现在支持Get、Put、Delete、Incr,这些所有的东西我定义了一个interface有这些方法,然后Memcache也一样,这样就保证网友来不断的贡献。这个是独立的应用,就是说我beego的其他东西都不用,那就是可以Cache.NewCache,然后这些都可以用了。Config的设计现在支持Ini、json、Xml、yaml,Config的应用也是这样,假如说你用Config的包,那我简单的就可以Config.NewConfig,然后就是你配置的文件,你就可以获取一个对象,这个对象返回的是一个interface,你就可以用它的方法来进行操作。Context的设计是这样,在request和response的基础之上写了一些很方便的函数,把它变成了Input、Output,我只是写了一些好的方法。Output也是一样,我直接输入一个Json就可以省去了很多的方法,因为这边没有多引擎的说法,用的话就直接这样用,就是分的很清。一个是Input进来的数据流,另外一个是我要输出的数据流。你说Input里面要获取用户输入的IP这些东西就去Input里面找,那就有很多的方式和方法让你获得这些数据,Output就是我要输出的东西。
Httpliibs是用来模拟客户端请求,现在支持Https、Debug还有超时支持文件的上传,这些就很方便。这个是简单的例子,假如说我要请求这个get的请求,那就是HttpBin.ORG,我要Post的数据就先Httpliibs.Post。Logs和前面的设计是一样的,就是支持interface引擎的分离,Logs现在支持四种引擎,我支持Cosole、CONN就是网络,还有File和Smtp,比如说我碰到一个红色警报我就需要发到我的邮箱里面报警给我,因为我这个设计的时候除了interface和引擎的分离之外,同时支持输出到这四个里面,因为我用了channel的方式。每个引擎就订阅日志信息,每个引擎可以收到相应的日志信息,每个引擎又有不同的等级,我要搜到什么样的等级就是类似这样的。File就是支持你按天分、按大小分、保存多少天、保存多少条数这些东西都可以,就是很容易应用的东西性能也很高,因为你可以自己根据应用来自定义。
类似这样用就是Logs.NewLogger,然后Setlogger就是说我要Set哪些引擎进去,这个是我可以把你调用Logger文件的行数给输出来,这样我就可以分析到你调的Logger的行数和文件,这样的话就有利于你定位那个是哪个文件包出来的,这些是基本的操作,就是Logger不同等级的操作。
大家可以看到,我这边最后写一个Time Sleep,如果我直接结束掉了可能这一条就没有输出,你实际应用的时候需要考虑安全的关闭,我在beego里面已经帮你考虑了,我会去判断那里面是不是已经等于零了,如果不等于零还会输出,直到你的Logs全部输出为止,当然你独立应用的时候还要注意一下这个问题。
ORM的设计,目前支持的数据库是MySQL、POstgreSQL和Shlite3。ORM的特性第一是支持链式的API、支持数据关系,这是我们最引以为豪的,因为我们刚开始做的时候是beedb,其实支持了很多的数据库和引擎,基本上是MSSQL、Oracle这些引擎全都支持了,但是有一个问题是只是支持单表的,如果关联了另一个表那是不支持的。所以我那时候就开始考虑,因为我以前做PHP的时候,我们写的应用就是关联数据库很简单,我觉得关联这个是很大的需求,所以我一定要重新写、重新搞,所以我们开始设计ORM的东西,刘鹏帮我们写了很多ORM的代码,他现在应该去七牛了 。
Struct我们就支持和Table一对一,简单的Crud的类型,你定义好直接在里面帮你把东西创建到你的数据库表,自动的关联创建,可以直接使用Rawsql,有时候你很复杂关联的东西就可以自己去写、自己去运行,但是返回来我们有很多的函数可以用到Struct,这些代码都是有完整的测试代码,就是我们只要github一递交,在drone那边全部的CI就会自动运行。
CRUD我们看一个例子,我们这边定义了一个User的结构体,ID、Birthday、Age、Name,我们首先要把它注册好,因为我们第一步就是说我们会扫描整个的Struct把它缓存起来,本身Go里面也不允许这你个结构体动态创建,所以我们就让你注册一下,我们就知道你这个结构体是在哪里的,你的字段都已经OK了,先前我们有做过一个ORM的测试,beegoORM测试的性能最好,我觉得最大的原因就是我们用了缓存的机制。第二个是RegisterDataBase,假如说你有三个数据连接你就可以注册三个,你需要哪一个的时候就切换到哪一个去用。默认是一个default,这个就是你数据库的连接地址。
这是我们简单的连接应用,User就是先建一个,然后你再更新就读取然后再接着就是删除,很多例子我们的文档里面都有,我可以说这个文档是有但是不够详细,很多人都反馈这个问题,我们下一步很多的文档都会更详细、说的更明白一点,当然我新加坡有一个同事现在也在写一本书,因为以前是做前端的东西,现在也想学beego,他现在把很多学习的步骤给记录下来,但是我也会指导他一些,这本书里面什么都会介绍,因为有一整套的方案,就是API怎么设计、JS怎么调API、用户权限怎么弄、数据设计的时候怎么弄,因为他是比较有典型性的例子,他现在对beego文档属于知道了的级别,但是真正做出项目来整个过程要记录下来,这样的话希望对很多的用户是有用的。
Sessios的设计跟前面的设计是一样,就是interface和引擎的分离。我刚开始其实只是Cookie、File,后面的引擎是网友贡献的。如果你要独立使用的话,有很多人经常会搞混,就是说beego里面用其实你不需要这样用,因为beego里面这些已经会帮你定义,如果你不用beego的逻辑,因为现在Go没有session模块,那beego的模块很多人就拿去独立用,比如说你有一个应用但是你想用beego的模块,那你独立应用的话就初始化一个让他操作就可以了,后面是你要用的引擎和配置文件。简单应用的话就是你每个request进来然后就SessionStart,我刚开始做的时候我是读了PHP的原码,所以我就是用Go重新写了一遍C。一个老外说你这个是多此一举,说PHP本身不是很安全,因为Go里面已经是很随机的数,我又在随机数上加上了时间进行了加密的操作,他觉得这样反而会增加不安全性,但是我又不能说服他这个为什么没有安全性,他也不能说服我这个是不安全的,后来我又把这个问题发到Go的群组里面,有一个安全专家说你这样的话不一定有安全性,但是会有潜在的安全性,你增加了稳定参数,所以你还不如直接用rand,代码就变得很简单,因为Go里面已经实现了所有随机的功能,如果用的话就是GetSession(key),然后就可以操作这个东西。beego里面还有一个强大的工具叫Toolbox,toolbox是一个网友给我提的一个建议,说你在beego里面是不是能够加入一些管理工具,healthcheck就是我一个应用起来之后我应用里面的数据库连接是不是正常,其他应用的程序和逻辑是不是符合我的需求,然后一个Profile就是当我运行的时候我可以在线的时候看我的CPUprofile,还有一些东西我在线的看,Statistics是达达,他是厦门那边做神仙道的主程,他统计的时候就跟我说你可以把这个东西加到你的里面,我看了一下设计的东西我觉得不错,用户请求的每一条数据最小的花费时间、最大的花费时间、每个人的平均时间,特别是你设计API的时候,我今天请求了1万次,平均我最小的一次是100毫秒,最大的一次300毫秒,平均可能是150,那300为什么会高,那你就可以对你的性能有一个分析。
这个是Toolbox的后台,我刚开始做只是做了命令行的东西,出来的时候是文本Txt类型。后来说新加坡的同事是做前端的,他帮我把所有的东西都做了美化,你就可以看得到请求了哪些东西,然后最小时间是花费了多少这样。可以在线运行的时候直接进行这些性能的分析,这些特别有用,当你一个程序遇到性能问题的时候,你的Cpuprofile对你调优特别有效,建议大家都去用一下。这里可以看得到你现在程序里面路由的设置,你的配置文件怎么设的是设了多少,这些都可以在这里看得到。这个模块虽然集成到beego里面了,你也可以用到你自己的程序里面去,因为里面的很多函数都是很方便的,因为这些都是模块化设计。
最后就是validation的设计,我们定义一个结构体然后V,然后Required这些配置的规则你就可以进行判断。这是其中一种方式,还有一种方式是把配置文件写在tag里面,然后模块开发计划,接下来要做三个东西,第一个是Testing,其实我一直在思考怎么样更好的做好这个事,因为Testing分两块,一种是白盒测试还有一种是黑盒测试,还有一种是基于函数的测试,那我接下来第一步可能做的是基于结果的测试,我只是根据你应用里面的路由可以帮你自动的生成所有逻辑化的的东西。第二个是blueprint,因为Go里面的RPC的功能很强大了,我就想我在模块化和模块化之间通过RPC的方式来做。Zero-downtime我打算独立做成一个模块。
beego里面有很多的插件,最近做了这三个,后面两个是用户做的。一个是Apiauth,亚马逊里面有一个验证,就是你有一个AppID然后再你本机把要请求的东西进行加密,这个是你做之前引入怎么用Plugins的东西,然后就插件化插入一个东西。这个是BeforeRouter就是在路由之前进行验证,大家可以看到这边的文档,这个就是ippid,你要允许用户用的appid和appkey,如果我开发一个app是提供给很多的商家用。还有另外一个函数,它里面就是你可以自己去指定APPid和appkey的映射关系,你可以来源于你的数据库、来源于你其他的配置文件,你就有很多个都可以支持,因为里面只是一个验证的过程。这个是AUTH的插件,你可以简单的加上这一句就可以实现你的Basicauth的功能了,用户只有输入用户名才能登陆这个网页。你可以用cors的插件,你在beforeRouter前面设定哪些域名可以访问这是很容易的测试,这些文档都可以看得到,我就写的很详细。gorelic是国外的应用,我在新加坡的时候我们用的很多,国外人有一个思路,就是人家一个产品做的好他们就拼命去用,而且就即使收钱也会用,就是相互之间的依靠关系很好。假如说你公司产品做的很好我用你产品,假如说我公司产品用的很好你用我的产品,他们的生态环境我觉得比国内好很多。这是一个性能监控的软件,你可以在这个里面去监控你的内存使用量有多少、CPU使用量有多少它可以全部的帮你接入进去。那Pongo是一个模板引擎,现在用的人挺多,有一个用户贡献了一个插件就可以在beego里面实现去调用支持这个Pongo的模板引擎。
我接下来要做这三个事情,第一个是auth2,是auth的插件。第二个是RBAC、第三个是ACL。Utils库现在除了这些刚才所谓的模块化和插件的功能之外,我还有一个库,就是方便其他开发的库,包括验证码、发送邮件、测试、Slice,比如说交集和比较都有,然后File判断文件是不是存在和文件的属性,Pagination就是分页操作应用。总结一下,beego的设计理念就是一个组合框架,就是我有很多的设计模块,然后beego的核心应用就是基于这些之上,其实beego有一个很好的设计是你装beego的时候,其他的组件是一个都不会依赖的,就是你用什么你装什么。第二个是高度的松耦合,第三个是Interface和negine的分离,我现在写代码都是先定Interface然后再写其他的代码,因为Interface实在太好用了,Interface定义完之后你很容易的去实现扩展这些东西,太方便了。第四是模块丰富,beego已经很多的产品在线上跑,而且都是很高性能的应用。第四个是插件设计,可以很容易的动态扩展系统。
接下来是讲一下API开发,我们API开发因为移动互联网大家知道发展的非常迅速,但是你看到移动互联网企业里面,他们基本上是API的模式,所以说我们后端程序员为什么吃香?因为我们任何一个时代我们后端的程序员,都是不管前端怎么变,我们后端应用的东西都得我们来做。API现在也变得越来越重要了,就是很多人都是先开发API再开发别的,像我如果开发一个app的话那我首先是先开发API,然后先定一个文档再基于这个东西来做,即使在网页端用这些东西来渲染后端定义一个API,这样就很容易扩展。API开发我觉得需要关注几个点,第一个是RestFul的方式,然后文档太重要了,特别是你人多了之后大家协同合作的时候,你如果没有文档那简直是效率极低,如果你找不到一个东西但是我又不知道返回是什么、请求参数是什么这些东西都是一个问题。第三个是效率,我们都希望自己开发的API可以抗高并发,能够轻松达到2-3w的并发。第四个是维护,假如说公司我走了公司的人是不是有人能够维护,第五个是部署,我觉得应用方便部署很重要,当然现在有了docker之后部署就更方便了。这些我觉得beego和Go的结合都很好的解决了这几个问题,第一因为beego就是支持天然支持的,第二个是文档我会给大家演示如何自动化的文档,第三个是效率,因为beego就是可以秒杀很多的动态语言。第四个因为beego的结构化很清晰就很容易维护,beego为什么会有自动化文档?因为有很多注释,然后基于这些注释我来自动的生成文档,为什么有了注释就容易维护呢?我们都知道有注释的代码大家看了这个东西逻辑就很清楚,我函数的处理逻辑是怎么样子的。最后部署的话Go编译之后就是一个二进制文件,扔到系统就部署完毕了。
【[ECUG专题回顾]《BEEGO设计理念与API开发》-谢孟军 (BEEGO作者、GO WEB编程作者)】 下面是DemoTime,我给大家看一下,我现在的数据库里面有两张表,一张是Customers表,一张是Orders表,现在我要做一个API的应用,我怎么做呢?大家看到,我现在只要做一个命名就OK,Bee这个是工具,API就是要创建一个API,这个Bcloud是我创建的应用名字,你可以换任何的名字但是这两个是固定的,Conn是我要去连接的数据库,现在我要连接数据库就是本机的,这个连接的地址就是Go里面一个连接的格式。这个是我要去连接的点,本机是3306然后Test这个数据库我点一下他就给我生成了这个就是自动化生成所有的代码,它所有的代码都生成了,然后我刚刚输入的连接地址它也会帮我自动生成,还有路由、ORM的东西都会引入,这个我们可以看一下这边生成了两个Model,数据我们数据库里面的资料是一一对应的,就是会把你数据库里面所有的东西都反射过来,Order也是一一对应,然后这些东西都是会自动引入,你看Add、get、getall这些方法是全部写好了的,大家可以看一下所有的函数,我们可以看一下这些方法全部已经帮你写好了,我们看一下运行的效果。大家可以看看我就运行了一条命令我就完成了所有API的工作,从数据库到API所有的东西都有,这里网络有问题我没办法下载包,所以我先前已经下好了我这边直接拷过来,不然会自动去下,Swagger是HTML的东西,这样的话我就把它拷过来,我们可以看一下,当大家不知道命令怎么用的时候,大家可以用一下Bee Help,如果我自己下的话他就会自己去下,我昨天试了一下,在这边它不能下,我不知道为什么。大家可以看到刚才在这个里面大家可以看到有很多的注释,这些beego会分析所有的东西来生成文档,然后会自动生成文档,我们看一下,它已经运行起来了,大家可以看到这个就是我们生成的文档,beego Test API,这是API的描述,再下面就是Customed,然后你可以再点一下可以看到这可以传一个Body,然后返回的信息是什么,我可以创建一个东西过去,这边是获取,我放一个1这样大家可以看得到,就可以直接进你就测试你所有的API,可以把这个东西丢给你调用API的人,说我的API就是这样子的,他就可以完全知道应该怎么样操作。这个是获取,我可以拷过来这个,我把它改一下,ID其实可以删掉,因为它会自动搜索,因为POST相当于创建一个,我放过去他给我的返回是会返回2,我们来看一下数据库里是不是已经有了,在这边就已经插入进去了,然后我可以修改也可以获取,我就不一一演示了。这是GET所有的东西,PUT是去修改,Delete这个你点一下其实也是所有的类似的操作,这样就一个命令可以把我数据库两张表全部生成了一个应用,调我的API文档,我所有的东西都做好了,但是还有很多个性化的应用东西我没有所有的数据库类型都测试过,但是我在我们公司200、300张表上面都测试过,所以那些上面的性能和功能上我都测试过,很多的类型我也都测试上。基本上就是这样,这是我们社区,大家可以有问题可以在上面提问,有Golang的、有beego的大家都可以去上面交流,这是我们的QQ群、这是我们的微信群大家有兴趣可以去沟通一下
推荐阅读
- 【golang】leetcode中级-字母异位词分组&无重复字符的最长子串
- 彻底理解Golang Map
- kratos线上开源年会它来啦~
- 深入浅出 Golang 资源嵌入方案(go-bindata篇)
- 深入浅出 Golang 资源嵌入方案(前篇)
- golang 经典案例总结
- Go实战 | 基于有向无环图的并发执行流的实现
- Golang 数组和切片
- Go JSON编码与解码()
- golang map基础知识