美文网首页持续集成今日看点程序员
学生团队的前后端分离及持续交付探索历程

学生团队的前后端分离及持续交付探索历程

作者: LuckyJing | 来源:发表于2016-12-11 21:32 被阅读419次

    原文链接: http://www.luckyjing.com/posts/front-end/arch-explore.html

    回顾大学四年,在学院课程大作业范围内的项目,并没有一次印象深刻的团队开发经历,往往都是三两程序员一聚,便草草开始了。在阿里云实习的几个月里,相比代码本身,学到的最多的便是人力资源的合理利用,工具的效率辅助,年已至末,最后一次大作业,将自己在实习过程中积累的经验运用起来,指定合理规范的项目开发流程,平稳地推进项目的开发,不会让项目边界越来越大以至于收不住边界,特地做此记录分享给大家。

    背景

    项目背景

    本次的项目是一个在线购物商城系统,这个词相信大家已经耳熟能详了,具体细节不必多说,分为三个子系统Customer,Owner,Administrator,需要将项目分为三个阶段,Release1,2,3,采用原型开发模式,每个版本给出一个可供交付的产品,总结来说,项目性质为无复杂功能点,但业务量繁多

    成员介绍

    团队成员共有20人,其中开发同学共10位,前端同学4位,后端同学6位。首先进行技术调研,和在公司不同,在公司大家技术栈其实差不多,在学校则不是,最终得出结果,前端熟悉React同学1位,其余3位熟悉jQuery,后端同学全部熟悉SSH框架,为保证后端的统一,后端技术栈不作调整,但前端因考虑到自动化构建的工具的接入, 以及用jQuery前期成本小,后期成本大,难以维护的现状,故全部采用React技术栈,并对不熟悉的同学进行一次集体培训以及后续答疑解惑。

    前期准备

    三个子系统之间其实前端关联度不大,可以认为是三个独立的系统,对于前端而言,React全家桶搭建起来并不容易,涉及到代码目录的规定,Webpack的配置等等,故前端由我做出基层的脚手架,实现业务同学可以直接写业务,无需关系构件流程的目的,对于后端而言,不同数据之间是共享的,故由一名主力后端同学负责数据库的设计与构建,并且搭建好基础后端目录,其他同学在此基础上进行业务层面的开发。

    项目构建历程

    基础结构预览

    在看过上面这个图以后,项目的整个轮廓已经清晰,为了实现以上架构,我们需要定一些小小目标:

    1. 前后端采用分离模式开发,通过一份提前给出的API文档进行协商,数据则通过以json作为基础格式的接口进行交互。
    2. 打造一个Mock服务器,实现API文档已给出,但后端接口还没有写好的时候,前端通过模拟接口可以透明地请求接口了。(注:透明的意思即Mock服务器可以拦截前端的所有请求,达到和真实线上服务调用接口一样的效果)
    3. 动静资源分离,我们只有一台服务器,是很实惠阿里云学生机,所以前后端数据都要放在这台机器上,前端静态资源存储在nginx服务器下,后端服务放在tomcat/webapps目录下,因为为单页应用,后端只需要在那份index.html里引入前端静态资源就可以了(直接写入绝对路径),最终访问的时候,服务器能够辨别是请求静态资源还是后端服务器,也就是俗称的动静分离
    4. 快速部署,部署的时候如何轻松,快捷,避免配置各种环境,要配也是一个人配,不能让开发同学苦恼。

    下面我们来一步步实现。

    前端

    简述

    1. 前后端分离开发,所以路由要放到前端,用React-Router
    2. 前端要自动化构建,用Webpack
    3. React+Redux配置其实挺麻烦的,如果能写好模板,然后自动生成就好了,用redux-cli
    4. mock2easy作为mock服务器。

    基础目录结构

    在项目开发前,我提前将项目的脚手架提前搭建好,项目的大概目录如下所示:

    ├── README.md  
    ├── blueprints  # 这就是上述第三点的模板,大家可以去github上搜 redux-cli  
    ├── build # 构建后的文件  
    ├── dev.js # 类似webpack-dev-server 加入了mock的服务  
    ├── package.json  
    ├── src  
    └── webpack.config.js  
    

    自动化构建命令

    使用Webpack提前写好配置文件,不管webpack.config.js里有多少步骤,最终呈现出来的只有build目录下那几个打包好的文件,将相关命令写到package.json中,前端同学只需执行一个命令就可以启动服务了。

      "scripts": {
        "dev": "node dev.js",
        "pub": "NODE_ENV=production webpack && git add . && git commit -m':grin:发布新功能' && git push origin master"
    }
    

    mock服务

    mock服务器什么原理,一张图给大家展示一下。

    解释一下,webpack-dev-server简单点就是一个express的服务器,那么如果我们直接用它的话,直接访问/ajax/test.json肯定是跑不起来的,因为这个接口404啊,所以我们要想实现如下目标:既能拥有webpack-dev-server独特的热刷新功能,还可以当请求后缀为xxx.json的时候,去请求一个mock服务器去拿数据然后返回,我们这个mock服务使用的是mock2easy,大家可以去GitHub上搜搜看,一切皆透明,于是我们的dev.js配置如下所示:

    // 先实现一个webpack-dev-server
    var app = connect();
    var compiler = webpack(config);
    app.use(require("webpack-dev-middleware")(compiler, config.devServer));
    app.use(require("webpack-hot-middleware")(compiler));
    // 核心代码 之 mock服务就是一个中间件
    app.use(function(req,res,next){
        if (req.url.indexOf('.json') == -1) {
          return next();
        }
        // 发现是接口请求,然后去请求mock服务器,然后把数据返回
        var _req = http.request(options, function (_res) {
          var data = '';
          _res.on('data', function (chunk) {
            data += chunk;
          });
          _res.on('end', function () {
            res.setHeader('Content-Type', 'application/json; charset=utf-8');
            res.end(data);
          });
        });
    });
    app.listen(config.devServer.port, function () {
      console.log('开发环境已经启动: http://127.0.0.1:' + port);
    });
    // 启动mock服务器
    require('mock2easynew')(options, function (app) {
      app.listen(options.port, function () {
        console.log('mock服务器已经启动,地址:http://localhost:' + options.port);
      });
    });
    

    优化

    • 开发时,React,Redux就不用被抽离出来了,当然代码也不用压缩了,一切以快为主。
    • 发布时,将React,Redux这些库抽离出来,这样打包出来文件会小,库文件我们可以用免费的CDN进行引入。
    <script src="//cdn.bootcss.com/react/15.4.0/react.min.js"></script>
    <script src="//cdn.bootcss.com/react/15.4.0/react-dom.min.js"></script>
    <script src="//cdn.bootcss.com/redux/3.6.0/redux.min.js"></script>
    

    实现以上优化,我们需要在我们的webpack.config.js中加入如下逻辑,即需要拥有区分开发环境的能力。

    //  区别环境
    var debug = process.env.NODE_ENV !== 'production';
    // 第三方资源
    var externals = {
      "react": 'React',
      "react-dom": "ReactDOM",
      'redux': 'Redux'
    };
    var config = {
      externals: debug ? {} : externals,
    }
    

    经过以上步骤之后,我们的前端开发环境已经搭建好了,开发同学只要先去填写一些mock的API,然后就可以在前端直接访问到了,所以剩下的只需要和后端进行约定下接口名称就可以了。

    # step1
    前后端约定API名称为:/ajax/profile.json
    # step2
    前端(假设是3005端口)在mock服务器(假设是8005端口)添加这个接口 && 后端正常工作...
    # step3
    访问localhost:3005/ajax/profile.json 成功拿到数据
    # step4
    前端代码里直接书写 $.ajax('/ajax/profile.json') 即可
    

    后端简介

    1. 后端基本上尽可能也要自动化,快捷化,所以使用maven去进行项目的构建,达到拥有一份源代码便可四处运行的目的。
    2. 使用postman让后端同学进行接口的测试。

    服务器部署实战

    到目前为止,前后端同学都可以在各自本地进行业务开发了,而且相互不耦合,以一份API文档为准便可以开发,接下来要讨论的就是构建的事情了,我们要达到的目的是:前端打包好后的静态资源可以自动部署到服务器上,后端代码推到仓库后,会自动进行maven构建,打war包,并自动上传到服务器上,重启tomcat服务器

    为了实现以上目的,项目采用阿里云code进行代码管理,与此同时,使用阿里云CRP服务实现上述持续化,描述如下:

    1. CRP服务检测指定的远程仓库master分支是否有更新
    2. 如果有更新,则执行一段脚本(由用户输入,往往为一些构建命令)
    3. 用户指定需要上传的文件(往往是第二步骤的产出)
    4. 用户指定需要上传到的服务器以及路径
    5. 用户指定上传结束后需要执行的一段脚本(往往为一些部署前的命令,比如移动静态资源到指定目录,或关闭tomcat,解压缩包,重启tomcat)

    还需要对nginx做一下简单配置,实现动静分离。

    # 由nginx处理静态页面
    location ~ .*\.(gif|jpg|png|bmp|swf)$
    {
      expires 30d;   #使用expires缓存模块,缓存到客户端30天
    }
    location ~ .*\.(html|jsp|js|css)?$
    {
      expires 1d;
    }
    # 其余请求全部转到tomcat
    location ~ .*$ {
      proxy_pass http://127.0.0.1:8080;
    }
    

    我们集成后的效果如下,当集成完毕后,可以通知测试同学进行及时测试,提前暴露出问题,保证项目的稳步前进。

    总结

    全程构建系统的过程中,一直遵循的守则是自动化越高越好(redux-cli,maven,持续交付),细节屏蔽的越高越好(执行命令写到package.json里),将部署步骤和开发步骤相互隔离,开发同学只需要专注业务的开发即可,这样便可以三个子系统同时前进,开发同学可以有更多的时间去考虑代码本身的质量。

    能够让我们放心去构建整个系统的基础,屏蔽底层的不同,多亏了在背后运行的Docker服务,本次项目中的尝鲜体验已经感受到了好处,将Docker纳入项目的部署环境,往往会带来惊喜。

    路还长,保持新鲜感,不断去构造更加完善的自动化系统。

    相关文章

      网友评论

      • loszer:楼上说的好,大学能做成这样,可以去公司无缝衔接上班了,哎,我就tm的孤军奋战过来的
      • 陈家不二少:可以,其实学校做项目能做到这样…已经可以进企业上班了…

      本文标题:学生团队的前后端分离及持续交付探索历程

      本文链接:https://www.haomeiwen.com/subject/odwpmttx.html