项目管理系统自研之路

2022-12-05 12:15:32 浏览数 (1)

背景

我司的项目管理比较乱,核心数据存在了外部购买的系统上"teambition",比如项目排期、测试用例、bug等数据。PMO同学在做数据统计的时候,先要从teambition倒出一份原始数据,再按照PMO约定的规则计算人效,计算的效率极低。

项目管理系统主要目的最开始是为了解决提高PMO手动出人效的效率,核心是计算产研人员效能。

当时PMO计算人效的公式是内部协商出来的: 1、当研发阶段的时候,开发人效 1 2、当测试阶段的时候,开发人效 0.5、测试人效 1 3、当前上线阶段,开发人效 0.5、测试人效 1 等等还有一些公式。

基于上面的痛点,我们决定开发一条可视化项目管理平台,直观展示研发效能数据。

实现方案

1、经过调研在teambition中,如果达成pmo的效果,需要给teambition提需求,经过沟通比较难实现。

2、自研项目管理系统,通过同步teambition把数据存储到研项目管理系统,把计算人效逻辑封装到后端服务中。

自研系统好处: 1)、锻炼后端开发技术 2)、PMO、产品、研发共建系统,拉起目标 3)、向上管理工具

自研系统缺点: 1)、产品缺乏架构设计 2)、项目质量一般 3)、服务架构单一

业务架构

如下图是当时PMO计得产品原型图,包含从项目管理角度出发覆盖研发效能到质量分报告,涉及功能模块比较全。

首页图表

需求维度

质量分报告

如下图是,思维导图梳理的产品架构:

开发架构

前端

参考vue admin平台,隐藏不需要代码即可,开箱即用。

代码语言:javascript复制
https://github.com/PanJiaChen/vue-element-admin

依赖如下库

代码语言:javascript复制
vue2.x、axios、echarts、element-ui、stylus等库

后端

后端系统主要使用django全家桶开发,类库比较多、并且ORM功能强大、部署方便。

代码语言:javascript复制
django全家桶、 mysql 、redis 、request 、gunicorn等库

经过几个迭代以后,代码越来越多,所有功能模块都写到一个服务上,变得越来越重。应该考虑微服务架构解耦代码问题。

定时任务

1、jenkins

jenkins主要做同步数据脚本使用,配置灵活方便。

2、apscheduler

apscheduler库,为了实现内部方法做定时任务使用。

登录

接入公司的单点sso登录

每个公司为了统一账号密码登录控制,都会由运维部门统一认证后,才能登录各个子系统。目的在于安全、统一管理账号密码。

下图是单点登录的首页,支持账号密码登录或者扫描二维码登录。

接入后,登录后可以拿到姓名、岗位等信息,方便后续权限管理模块开发。

接单点登录系统,一般需要和单点登录系统注册,注册后会把给clientid和clientsecret两个参数,为了安全性考虑。

需要在前端启动首页的时候,如果没有登录就去访问登录首页。

在router.beforeEach函数中,从cookie中获取token,如果没有token跳转到登录页面。

代码语言:javascript复制
var hasToken = getCookie('token')
  var myDate = new Date()
  const logs = {}
  const newDate = formatDate(myDate, 'yyyy-M-d h:m:s')
  logs.username = hasToken
  logs.content = newDate   ' '   hasToken   ' '   '登录'
  logs.type = "logs"
  createLogs(logs).then(res => {
  })
  if (hasToken) {
    if (to.path === '/login') {
      next({ path: '/' })
      NProgress.done()
    } else {
      const hasPerms = store.getters.perms && store.getters.perms.length > 0
      if (hasPerms) {
        next()
      } else {
        try { 
          const { perms } = await store.dispatch('user/getInfo')
          const accessRoutes = await store.dispatch('permission/generateRoutes', perms)
          router.addRoutes(accessRoutes)
          history record
          next({ ...to, replace: true })
        } catch (error) {
          NProgress.done()
        }
      }
    }

登陆页面的逻辑,首页会判断是有code,没有的话调用接口获取code,code参数通过前端页面拦截获取,所以这样是很安全的.拿到code再去换token,最后获取用户信息的接口携带token参数,跳转到首页。

代码语言:javascript复制
mounted() {
this.getTokenByCode()
},
created() {
this.goSSO()
},

goSSO() {
  if (!this.code) {
    var sso_url =
      'https://sso.xxxx.com/oauth/authorize/?client_id='  
      client_id  
      '&redirect_uri='  
      redirect_uri  
      '&response_type=code'
    // console.log("sso_url is "   sso_url);
    window.location.href = sso_url
  }
},

getTokenByCode() {
  if (this.code) {
    // SSO登录回调
    const params = {
      code: this.code,
      client_id: client_id,
      client_secret: constclient_secret,
      grant_type: 'authorization_code',
      redirect_uri: redirect_uri
    }
    // console.log(params);
    const axiospost = axios.create({
      timeout: 500000,
      headers: { 'Content-Type': 'multipart/form-data' },
      withCredentials: true
    })
    const formData = new FormData()
    for (const k in params) {
      formData.append(k, params[k])
    }
    axiospost.post(tokenURL, formData).then(res => {)
      const access_token = res.data['access_token']
      this.getTokenByUserName(access_token)
    })
  }
},
    getTokenByUserName(access_token) {
      console.log('getTokenByUserName')
      const axiospost = axios.create({
        timeout: 500000,
        headers: {
          'Content-Type': 'multipart/form-data',
          Authorization: 'Bearer '   access_token
        },
        withCredentials: true
      })
      axiospost.get(infoURL, null).then(res => {
        const username = res.data['name'])
        if (username) {
          setCookie('userName', username, 7)
          this.$router.push('/dashboard')
        } else {
          this.$router.push('/login')
        }
      })
    }

共享登录状态

内部有很多系统都接入了单点登陆系统,为了能登陆一次系统后,再登陆其他系统就不需要再登陆,需要共享登陆状态。

如果设置cookie的话,把cookie种在根域下就可以,这样就通过cookie完成了共享登录状态。

代码语言:javascript复制
export function setCookie(cname, cvalue, exdays) {
  var d = new Date()
  d.setTime(d.getTime()   (exdays * 24 * 60 * 60 * 1000))
  var expires = 'expires='   d.toUTCString()
  document.cookie = cname   '='   cvalue   '; '   expires   ';'   'domain=.xxxx.com;'
}

首页

数据来源

由于我们和"teambition"第三方公司签约到很久,需求数据、bug、测试用例都存在了 "teambition"平台。所以需要使用对接"teambition"的api完成数据同步。

teambition接口鉴权这款还是比较复杂的,首先有管理员账号并且生成对应的token。

使用jwt对参数进行编码解码等一系列操作生成token,放在请求的header中。

代码语言:javascript复制
def get_token():
    """
    生成token
    :return:
    """
    payload = {}
    iat = math.floor(int(time.time()) / 3600 * 3600)
    payload['iat'] = iat
    payload['_appId'] = appId

    headers = {
        "alg": "xxx",
        "typ": "JWT"
    }
    token = jwt.encode(payload, appSecret, headers=headers).decode('utf-8')
    return token

teambition的官方接口文档,如果对接第三方系统,没有好的接口文档,开发的过程中会很痛苦。

代码语言:javascript复制
https://open.teambition.com/help

查询任务,只需要把task id传过去就行了。

还支持tql查询,扩展性比较强。

增量同步

因为增量同步可以减少同步时间,但是可能会存在同步数据存在误差。

主要有几个原因,需要保持新增、删除、变更的数据一样,这样就需要同步脚本有大量的逻辑判断。所以写完脚本,需要测试各种场景保障数据的一致性。

全量同步

这种用法比较少,暴力做法就是删库重新同步。

webhook方式同步

当"teambition"的数据发生变化,主动给我们服务发送请求告知数据变化。这种可以满足数据实时更新,但是需要服务端有逻辑判断。

数据管理

迭代填报

迭代填报主要是从"teambition"同步过来数据,这里只做展示,一般不会手动改数据。

人事管理

人事管理对接了"薪人薪事"系统,可以拿到人员状态。

请假管理

请假管理需要手动填报,具体因为很多人请假不走"薪人薪事"系统,每周五时候pmo手动同级。

需求管理

需求管理也是同步"teambition"空间的数据,需求有几种流转状态,当状态变更时候需要记录。

数据展示

业务线人效统计

从业务线唯独可以清晰的知道,每个业务线的数据。

按职能人效统计

因为我们公司前端在业务线干活,但是隶属统一前端leader管理,职能人效可以发现谁不忙就让谁补其他人得需求开发。

人员饱和度看板

人员饱和度主要是想细化到每人身上,关注每个人得产出。

项目投入统计

App发版日历

App发版日历主要想看本次发版的需求,共涉及多少个需求。

PMO项目人员统计

人事数据统计

周报分析统计

项目总结统计

项目管理甘特图

项目各阶段周期

系统设置

当时有个OKR是,想看看我们得系统使用率,所以做了埋点数据统计。

权限管理

权限管理是通过vue的动态路由实现和并且结合自定义指令控制按钮权限。

菜单控制

项目迭代的心得

1、每次版本开发前,PMO会做立项会。

2、每次版本发布前,PMO会做产品发布会。

3、内部系统一样做好技术文档沉淀。

4、项目完成后做复盘。

5、测试环境和线上环境隔离。

6、内部系统一样提bug,标明优先级。

落地效果

有几点用: 1、老板的确很喜欢这种系统。

2、通过数字化、图表化,反映研发效能。

3、产品也喜欢看谁有排期。

不好的点: 1、开发很diss这个系统,也能明白。

2、有一定的维持成本。

总结

研发效能开发会是未来趋势,大厂都开始自研内部效能系统了并且开始商业化了,为啥大家不计成本开始做研发效能呢,我觉得可能有几点思考:

1、随着自动化测试体系搭建,需要有一套流水线串联自动化测试。

2、需求迭代过程产生的数据需要被存储归档。

3、项目过程和结果需要被度量。

4、通过效能平台打通各个内部系统,串联研发流程。

回到项目管理系统本身,在小公司可能测开就去完成了,但是是否能成一个比较好得产品还是比较难,在大厂会是研发效能去当一个产品迭代开发,服务整体研发团队.从另外一个角度来开,QA应该从这个研发效能去看问题,这样才能看到更多团队内得问题。

0 人点赞