作为创业公司很重要的一个环节就是在有限的时间和资源下把产品需求落地为产品,也就是研发和项目管理,毫无疑问,这个阶段的主角是开发人员,那作为一个PM,把做项目管理的过程也当成做产品的过程的话,是不是应该多思考下怎么面向开发人员来优化整个研发过程和项目管理流程。本文就是我们如何通过优化开发环境搭建,代码管理,需求生命周期管理,开发任务分配和追踪,项目整体进度管理来提高研发过程中开发人员效率,通过持续集成和交付让开发中的问题更早暴露,通过合理的测试反馈工具让开发人员最快定位和解决问题。 一点前提条件和背景 印象中很多关于产品和开发为了进度撕逼的段子,其实作为一个开发转的产品,对这两块都有所了解,就我的看法是研发效率不止是研发人员本身的技术能力和工作效率,而是整个研发过程和项目管理流程的效率,但我自己理解的高效的研发和项目管理有两个前提: 公司内各团队有个大家认同的沟通协作方式:因为所有的流程和工具都是为人所用的,只有团队有主动性去沟通协作才能提高效率,这也是我这个系列第一篇写“异地创业团队如何做团队沟通协作”的原因。 尽量清晰的需求定义:产品经理的任务就是让研发团队开发正确的任务,我所碰到的开发延期或者交付失败很多时候就是由于自己对需求的认识不够,开发中过多需求的变更造成的,一个表达清楚,考虑完善的需求定义才能保证下面的研发和管理是不是在做无用功,所以本系列的第二篇是“聊聊针对异地团队的需求协作和原型、设计的评审” 说到创业团队的研发和项目管理的实践,就逃不开先要说一下我们研发和项目管理中的工具作为背景: 即时交流和协作:Slack,这个我在“异地创业团队如何做团队沟通协作”里重点谈到过,鉴于它的开放性,已经基本连接了我们用到的文件管理,设计评审,持续集成,测试分发,BugReport等一系列工具。 代码管理:GitGitlab,在VPN环境内自己搭建Git和Gitlab一定程度上保证了代码的安全性,不过维护和备份都是个会耗费精力的问题,对没有专业运维的创业团队推荐直接Github托管。 项目管理:Redmine,老实说Redmine一直都不是项目管理上的最佳方案,专业级的有JIRA,轻量的有Asana、Tower等很多,我们就是已经习惯了,有一套Githooks在上面,并没有什么动力去换。 持续集成:Jenkins,虽然Java的坑也很大,维护起来也不时被坑,不过功能和插件确实齐全,搭起来也不易,有兴趣的可以尝试TravisCI或者GitlabCI。 最后切入正题了,本篇涵盖的是我们在研发过程和项目管理流程,以及当中在DevOps上做的一些努力去优化开发人员的体验,就试着从各个环节总结一下,因为不同团队的研发流程和项目管理都不一样,各位看官可以挑有兴趣的来看: 研发环境的搭建:包括如何kickoff新开发者,如何搭建日常开发环境 代码的管理:包括源码管理,CodeReview和组织公共库 需求在研发中的生命周期管理:包括功能需求清单,功能需求定义和其中的开发任务项分配和状态管理 项目进度的管理:包括如何通过Redmine有效的执行敏捷开发 研发阶段的产品测试和反馈:包括在产品测试和反馈中的一些经验和工具分享 持续集成和持续发布:包括如何针对Web,Android和iOS分别搭建持续集成和发布 一、研发环境的搭建 如何让团队新的开发者尽快上手 对新的开发人员,一般都会有开账号,装系统,配环境,跑代码这些过程,我自己发现每次都低估这些工作的耗时,以前就发现有时候不小心就一两天过去了还没跑起来代码,一两周还没搞清楚目前产品的功能,我总结了两点加快这个进度的方法: 1。加快能让代码跑起来的速度 有很多可以加速的环节,一个比较重要的就是自动构建代码,就是指开发人员checkout代码后通过简单的构建脚本就能完成代码依赖安装,代码编译,单元测试运行,也就是我们常说的跑起来。以Web为例,可以通过npm的脚本完成npm依赖的安装,然后用gulp完成代码的构建和运行,这也是持续集成的基础。 2。对产品功能需求和目前进度的了解 在背景的里说的保持一个尽量清晰的需求定义的一个用途就在这,新的开发人员可以通过浏览产品的需求文档来了解产品功能,我们的做法是在Redmine上把“系统功能汇总(含已排期未完成功能)”作为一个CustomQuery,将所有功能的PRD列出来,有两种视图可以选择,一个就是下图这样按照产品线,能看到每个产品线的功能: 另一个视图就是按照功能完成的时间来归类,可以知道以前每个版本都做了什么功能,未来有什么功能正在排期中: 如何方便开发人员进行日常开发调试 目前对于Web开发来说,一般构建的过程中代码都会进行混淆、合并、CDN地址替换、CSSSprite生成等等操作,造成在Dev服务器上调试很不方便,我们采取的解决方法是在web的Gulp构建流程中分不同的BuildTarget,本地调试使用未混淆的代码加本地搭建的Python环境,连接Dev数据库,方便Web开发人员本地调试。 二、代码管理 首先最重要的就是代码必须用源码管理工具,我们一直用的Git。代码的查看和管理都在Gitlab上,可以查看代码,codereview,合并分支,打版本tag之类的,不过Gitlab对开发者不是必须要用的,所有这些操作都能用gitcommand解决的事情,有两点我觉得需要关注的: 1。怎么让开发人员高效的使用第三方库 项目开发的过程中去抽象公共组件,使用第三方库或开发工具都可以提高开发效率,但需要做好模块和版本管理,有时候碰到一个开发人员引入了一个不合理的依赖,或者学习成本陡峭的组件,每个参与开发人员都要增加学习成本。这个一般都是根据不同的技术栈有相应的一套工具可以使用,我们自己在Web、Python、iOS、Android上面都有自己习惯的选择,需要加新的组件或者替换正在使用的都可以一起讨论之后加入,以免发生重复或者后期的分歧。我们主要考虑的点有下面这些。 2。如何做新功能开发的代码管理 只要多人开发,而且多功能并行开发都避免不了要考虑如何管理代码,一般有FeatureToggle和GitBranching两种,目前我们根据自己的需求定义了一个Gitbrancingmodel,对于复杂的新功能建立featurebranch来开发: 虽然我个人更喜欢FeatureToggle的方式,不过实践起来需要的模板开发和构建方式上的配合,不如GitBranching对开发来说上手更简单一些,暂时就没有更换,建议看一下BaiduFEX的去考虑自己适合哪一种。 三、需求在研发中的生命周期管理 对于开发人员来说,开发工作一般是围绕着具体的功能需求进行的,而背景中提到过的“清晰的需求定义”就是研发的主要输入,由负责的PM来主导需求(UserStory)的状态更新,本节以一个功能需求(UserStory)为例,先上一个时序图来说明单个功能在研发中的生命周期是什么样的: 从功能需求(UserStory)的时间线上可以看出来其分为下面几个状态: PM创建后协作编写需求文档(New)需求确认(Confirmed)开发中(InProgress)待测试(Waitfortest)已完成,可以上线(Finished)完成,可以关闭(Closed) 可以划分为需求确认,需求开发,需求测试和上线三个阶段: 1。需求确认 对于需求文档的编写和确认,不同团队方式不一样,我在前一篇《“聊聊针对异地团队的需求协作和原型、设计的评审”》聊了如何通过怎么协作完成清晰的需求定义,我的理解是包括功能需求的前置条件和后置条件,用户流程和规则,完整的产品交互原型,评审确认的设计稿。下图为在Redmine上定义的一个功能需求(UserStory) 2。需求开发 在需求定义清晰后,开发前需要整个开发团队的参与确认任务的分配。任务分配的原则就是将功能需求对应的任务按树形结构分解,敏捷开发里的学名就是“WorkBreakdownStructure(WBS)”,保证其中每个任务都是可以开发,并且是可以测试的。下图就是一个功能需求对应的任务的实例: 具体到其中一个单独的任务项(Task),里面会有它所属的功能需求(UserStory),当前的状态,优先级,任务指派的开发者,任务所属的产品线(Web,iOS,android),一个简单的任务描述的,所属的milestone,预计开发时间和结束时间,任务当前的状态和进度等等。如下图所给的就是一个Task的实例: 从上文中“需求在研发中的生命周期”的时序图上可以看出其对应的任务的生命周期是如何管理的,包括前端和后台之间的任务协作是如何完成的,简单来总结的话Task有下面几种状态: 新建开发中待代码复查(目前仅juniordeveloper需要被codereview)待测试反馈完成(可以上线)关闭(上线以后可以关闭) 开发人员主要负责的就是开发的同时更新自己任务的状态,看起来状态蛮多,如果开发需要每次登录redmine来改也确实蛮累,在实践的过程中我们引入了一下优化的方法: 为Redmine自定义一些Githooks来更新状态。通过自定义git提交语法,让Git提交能自动更新在Redmine相应的issue上,既节省了更新状态的时间,又能保持一个干净的gitlogs。下面是我们定义的Git提交语法: 〔component〕Abc:(IssueId)Message(IssueStatus) 〔component〕就是任务所属的模块,比如〔ios〕,〔android〕,〔backend〕,〔web〕,这和Jenkins的BuildJob绑定,当有相应模块的代码提交就会触发相应部分的持续集成和交付。 Abc就是操作的Action是什么,比如Add,Mod(ify),Ref(actoring),Fix,Rem(ove)andRea(dability),用来让代码提交信息的目的看起来比较清晰。 (IssueId)就是对应的Task的Id是什么,为了将changelog和task绑定在一起。提交以后就会自动更新Redmine的Task: Server端接口文档自动生成。在需求定义里可以将规则和逻辑写的很清楚,但在前端和服务端协作开发的过程中,如果服务端没有文档可能会经常被前端打断,询问接口具体参数的名称或参数类型,也是比较烦的事情,可以考虑用DocumentationGenerator在代码中添加注释来自动生成文档,我们使用的“Sphinx”作为Python的文档生成工具,用Python的推荐使用。 开发中的持续集成和交付。这个后面会专门来讲如何操作,具体的意义就是开发人员提交代码之后在Dev服务器上进行自动构建和发布,这样一方面每次提交都做Lint检查,有单元测试的做单元测试,降低代码最后集成的时候出现问题的风险,另一方面让PM可以尽早的接触到成品,尽早进行反馈。 2。需求测试和上线 当单个功能需求下面对应的所有任务都开发完成后,由PM进行测试和反馈,在确认与PRD一致后可以由PM更新为“待测试(Waitfortest)”。这里“待测试(Waitfortest)”的意义就是该功能需求可以在发布到测试服务器(TestServer),由业务团队及测试用户参与测试。当测试没有问题后,如果是Web功能则根据上线计划上线到ProductionS如果是NativeApp,则按照版本计划,可能需要固定时间发布或者等待几个功能完成后一起发布。 由于这里讲的是单个功能需求的研发周期,而测试和上线更多是在整个项目这个Scope上来讨论,所以针对测试和上线的部分在后面持续集成和发布的部分会来细说。 四、项目进度的管理 顺着上面的思路,当你有单个需求研发的流程后,整个项目的管理就是管理所有的需求,安排优先级和迭代计划,然后对所有需求进行同样的研发流程管理。敏捷开发里把一个迭代周期称为一个Sprint,每个Sprint做一次产品发布,然后回顾Sprint内的问题,规划下一个Sprint的开发任务,如下图: 我们的实践不完全是Scrum,但比较接近,我们的迭代周期为一周,保证每周至少都往Production上做一次同步。项目的进度管理在Scrum的实践里其实就是在它的三个Meeting时完成的: SprintPlanningMeeting:从整个产品的ProductBacklogs里一起规划出下一个Sprint要完成的功能,可能对应着很多团队的需求评审会 DailyStandupMeeting:在一个Sprint里每天和开发人员一起回顾昨天的开发进度,讨论碰到的问题和确认当天的工作计划,其实对应着为开发人员诟病的项目日报 SprintReviewMeeting:在一个Sprint结束回顾项目进度,问题和下一个Sprint的计划,一般对应着PM要做的项目周报 在产品体验的优化中有个理论就是在所有直接接触用户的‘Touchpoint’上进行体验优化,其实我个人觉得这三个Meeting就是项目进度管理里的Touchpoint,在这三个Meeting上PM会和开发人员或者ProductOwner进行接触,如果这里体验不好就会影响项目的管理。其实我们总结的优化方案也比较简单,就是通过项目管理工具Redmine去实现的功能需求和开发任务的“看板”: SprintPlanningMeeting 平时积累下的需求我会建立一个FutureMilstone来存放,这样在PlanningMeeting上可以直接以这些作为ProductBacklogs,作为产品以后可以去做的内容,这些需求可以按照功能模块来组织,然后在SprintPlanningMeeting上一起规划出下一个Sprint要完成的功能: DailyStandupMeeting 每日的站立会议是粒度最细的会议了,就是追踪每个人每天的任务情况,在这里我们在Redmine上建立一个叫“本周需要完成的任务(开发人员)”的CustomQuery,将这个Sprint里的任务按照不同类别(网站,后台管理,iOS或者Android)来归类,作为我们的看板: 对于开发人员,只需要按照前面提到的提交代码来更新任务状态,完全不需要额外的工作就可以汇报自己每天的进度。每天早上一上班,所有的开发人员聚在一起,按照不同的类别一个个过任务项,同步昨天完成的任务,确定今天的任务,有疑问的就在早会解决。 SprintReviewMeeting 对于项目进度Review来说,Scrum的看板管理是将任务项按照状态来分类,这样能更清晰的看出来哪些已经完成,哪些还没有开始,可以通过变换CustomQuery来实现: 不过SprintReviewMeeting一般就不只是研发团队参与,为了辅助相关的业务人员和测试用户一起来Review,我们通过在Redmine上建立一个叫“本周已经完成的任务(业务人员)”的CustomQuery准备上线的功能,里面是这个Sprint已经完成的功能,将已经完成功能的按照来归类,PM可以按照这个来测试已经完成的功能,全部完成测试提交到测试服务器以后,相关的业务人员和测试用户也可以按照这些任务来试用,节省一下每次都要介绍更新了什么的时间: 五、研发阶段的产品测试和反馈 产品发布到测试渠道后的反馈 当产品发布到测试渠道就是希望在正式发布前得到业务团队或内测用户的反馈,对比开发人员的测试反馈,业务人员和测试用户的反馈一般都比较抽象,就是问题描述不具体,环境上下文不清晰,没有复现流程,解决这些问题最好借助反馈辅助工具: 移动端的Bug反馈工具目前我们使用BugTags,目前只用在Test版本上,可以让测试人员通过截图标记的方式描述反馈内容,发送时候也会附上环境和App日志,能节省不少对于反馈的处理时间。不过这个是显式的反馈收集工具,需要测试用户主动提交,如果需要隐式的反馈收集可以考虑AppSee,我自己没有试用过,但一些测评都表示可以记录用户行为的视频,统计界面点击热图和漏斗分析,不过收费比较高,有机会可以尝试下。 移动端的录屏工具的话可以选Lookback,其实是个用研的工具,功能就是语言录屏面部摄像,目前还在Beta期间,免费试用,可以Mac直接连接录屏后发送到它的网站,也可以在它的本地目录里找到。 Web端的Bug反馈工具目前只有截屏报bug,我目前没有找到类似BugTags的可以显式标记问题的反馈工具,曾经在《HowGoogleTestSoftware》里面看到Google曾经开源的Chrome插件工具BITE,有各种web上bug记录和复现的黑科技,不过在GoogleCode上一副年久失修的样子,我没有勇气去尝试,如果有知道其他类似合适的可以推荐一下。 Web的线上用户追踪的话,我们目前使用了Mouseflow,它可以记录用户的行为,然后在它的网站上通过iframe你的网站帮你复现出来,虽然不是100精准,但可以观察一些用户的行为。 产品发布前的测试用例表 我自己的经验是每次发布前的测试都需要产品经理亲自来做,一方面确认发布功能的正确性,另一方面重新走一遍用户流程,确认产品目标可以达到。测试的方法比较笨,暂时就是通过GoogleSheet维护一张测试用例的表,如果是移动端就每个版本维护一个测试用例表,开发版测试时会把表格分享给所有开发人员,每个人都可以遍历测试用例提交自己发现的问题。测试用例表的结构为: 一级目录,二级目录,三级目录,用例名称,优先级,前置条件,执行方式,操作步骤,预期结果,测试状态,测试备注,是否自动测试覆盖 六、持续集成和持续发布 前几年有一段为海外客户做移动产品设计开发和咨询的经历,这里面一个重要的痛点就是不停发测试版给客户,征求意见和反馈,但对于移动app来讲之前每次打包都需要打断开发人员,等待编译,改文件名加版本号,上传等一系列繁琐的过程,然后还经常因为客户没有装最新版而造成沟通时间的浪费,所以早期我们就开始着手建立持续集成和持续发布体系来避免这些问题。 我理解的一个完善的持续集成应该包括代码提交后的构建部署测试发布几个阶段,可以看‘TheProductManagers’GuidetoContinuousDeliveryandDevOps’上这个图来理解: 自动构建 在上文Redmine的Githooks提到过githooks在持续集成中的作用,其实就是当GitCommitMessage出现相应的模块,就会在代码提交成功后能在持续集成服务端(CIServer)触发相应的Server,Web,iOS或android端的自动构建,这是持续集成的基础。 这里面有个针对开发这边的优化就是尽量缩短自动构建的时间消耗,我们的Web编译就是个反例,优化前有10来分钟的时间,现在稳定在3分钟,还有优化空间: 持续部署 部署分为客户端部署和服务端部署两种,就是构建以后要把可运行的代码发布到相应的服务器和手机端。 持续测试 这部分在服务端和每种客户端都分为单元测试和集成测试,理论上来说能在持续集成的过程中执行测试,是对产品质量极大的提升,不过对团队的规模和时间要求比较高,一般还是按自己的实际情况来。 自我检讨来说我们客户端的单元测试这块做的比较少,自动化集成测试的话每个项目都只对主要流程做一下覆盖,这也是个从Linkedin早期开发流程里看到的经验,可以通过分析用户行为得到主要用户流程,然后先自动化测试这些流程。早期在Android开发的时候实践过,通过JenkinsSpoonRobotium可以在CI上跑多种不同的Android设备来对主要流程截图,实现多设备的测试,在CI的效果是这样的: 虽然效果确实不错,可以在持续集成阶段发现在什么版本或者分辨率下出现问题,但用Robotium测试写起来还比较麻烦,后来我在Github上fork过一些优化测试的方法进行优化,但如果不是非常长期维护的产品还是慎用吧。 持续交付 持续集成后的持续发布是我们主要需要解决的痛点,发布的对象分别是给开发和测试人员的Dev版,给内测用户的Test版和给最终线上用户的Production版,发布的渠道又分为Web端和Mobile端,需要分别来考虑,一个涵盖上面所有的情况项目的Jenkins大概是这样的: 在之前Gitflow的图上有展示到,我们将发布的dev,test和production分为三个不同的服务器: 对于Dev服务器就是由Githooks来触发,每次代码提交都会更新Redmine对应的Task,然后Redmine发邮件给这个Task的Watchers,同时触发CI集成新版本到Dev上。 对于Test服务器就是当有新功能测试完成,准备上线的时候,就先同步到Test服务器上,通知内测用户下载测试,相当于Staging服务器。 对于Production的正常的流程就是当SprintReviewMeeting之后,按照确认要上线的功能进行发布。这里我有个习惯就是发布的时候在CI上检查一下发布对应的redminetasks,避免有不该被同步的内容。 需要注意的就是,Web的持续交付相对来讲比较简单和成熟,但Android端和iOS端处理起来都比较麻烦,首先就是对于Production版本,都不能直接发布到AppStore或者国内的一堆Android市场,能在CI上做的就是build好production以后自动在Git上打版本tag。然后对于Test版本的分发,可以考虑使用Testflight或者国内的蒲公英,绑定到CI上,可以集成好以后直接发布上去,然后通过Slack建立测试用户Channel,自动发送通知消息,收到通知可以直接点击下载安装。 后记 关于团队沟通,需求协作和项目管理三块的总结终于写完了,很久没码文字了,写出来感觉蛮生硬,很多地方没有说清楚,不过水平确实也就这样了。写的过程中还是想到不少现在的方法里面有缺陷的地方,正好给自己一个ToDoList,以后去优化。