工程经验 - 小组管理初级指南

管理工作也算工程经验吧?一个人的力量是有限的,在有限的时间节点要完成大工程,就需要协作多人一起完成

一、前言

我的 timeline 如下:

  • 2020/7:毕业。我负责业务后端研发工作,ToB & ToG 产品
  • 2022/2 ~ 至今:直属组长离职。由我接手组长的工作,带领业务后端组相关研发工作

工作期间,最多的时候我有带 5 个人进行版本开发。本文分享近两年来我当小组长的一些管理经验

二、整体工作

在担任技术研发组长期间,我有以下工作内容,接下来将会围绕如何做好以下工作做相关分享,一些详细的管理流程和模板请看附录章节:

  • 设计方案:快速提供可靠的整体设计方案和交付时间
  • 分配任务:拆分大任务为子任务,并分配给组内或外的同事
  • 评审工作:检查组内同事的代码、设计方案和调研结果
  • 流程把控:预测和把控项目风险,组织晨会同步进度并推进核心问题排查
  • 外部对接:撰写接口文档、组织会议并推进外部合作
  • 面试招人:招聘适合的候选人进行版本研发工作

三、设计方案

3.1 给出交付时间

我的工作中,研发常以定制化项目 or 版本研发两种形式展开,有大概如下研发流程:

  • 前端沟通
  • 技术预研
  • 需求评审
  • 概要设计
  • 概要设计评审
  • 编码

在产品初步同步完需求后,需要研发给出交付时间,然后再进行立项。这里存在一个悖论:在不知道具体情况的情况下给出交付时间

早期我的做法是先做完全部的设计方案,进行概要设计评审,然后进行任务拆分和估时,给出交付时间。现在,集团组织流程改革,在需求评审通过阶段就要求研发给出整体交付时间

因此,无论如何都需要在梳理设计后给出初步工作量,才能依据此给出估时。现在的做法与早期的区别在于设计粒度的不同,后者会带来更多问题。因此,在任务估时时,需要预留一些 buffer 来抵御未知风险。

3.2 如何做好设计

我的工作中,设计工作分成两类,业务类设计是占大部分的:

  • 业务类设计
  • 组件类设计

设计方案是将设计落为文档的过程,我们有设计方案模板,内容较多,评审时关注如下要点:

  • 数据库设计
  • 模块结构设计
  • 功能接口流程设计
  • 局限性说明
  • 其他组的协作问题说明

对于业务研发的设计,我的做法:

  • 从数据库设计开始:梳理支撑业务功能的出表、字段、E-R 关系
  • 下一步完善整体结构:需要画一个图,内容包括不局限于中间件、服务、服务内模块、调用协议、关键端口、业务调用链路说明
  • 做好功能接口流程设计:主要涉及页面上的按钮、列表和编辑操作,每个都可以视为需要获取或更改数据的接口。接口流程包括具体的业务接口逻辑,涵盖了if-else逻辑、CRUD操作、错误处理、响应等流程。通常我会从新建和编辑接口开始设计,因为查询类接口通常比较简单。
  • 局限性说明:由于依赖某些组件、某些中间件的设计,存在某些性能局限、功能局限的说明
  • 其他组的协作问题说明:需要说明其他组需要做的工作,例如运维组的环境注入、组件组提供服务接口、前端组的路由更新等

对于组件类的设计, 我的做法:

  • 性能满足前提,从开发语言开始:一般选择使用自己最熟悉的语言,例如代理这种,我会使用 Spring Cloud Gateway 做,比在 OpenResty 写 Lua 更方便,更好调试
  • 选择生态更好的组件:拿代理举例,Zuul 是 SCG 的友商,但后者的生态更新、更大;又比如 OAuth2 组件,Ory Hydra 将比 keycloak 更大
  • 组件接口需要满足性能:有时也会做提供给业务方调用的组件接口,性能提升从三个方面考虑,并行异步缓存,一般我使用缓存,最简单;另一方面我也会考虑性能高的 RPC 协议调用,例如使用 gRPC 作为组件调用协议

四、分配任务

4.1 提高人力利用率

工作中,我使用过两种项目 & 任务 & 缺陷管理工具,一种是禅道,另一种是 JIRA。在我有限的工作经历中,我意识到一个很重要的问题:工作中你期望拥有的是什么任务都能干的强大人力,但实际上给你的人力,没有最弱,只有更弱。正常逻辑也该是如此,毕竟如果一线的组长不是组里最强的,那还有什么资格当组长?

每个人适合的任务类型不同,这个需要在分配任务前就确定。可以通过不同的任务类型去试探出这个人力适合做什么工作

  • 技术调研
  • 新业务研发编码
  • 旧业务适配编码
  • 版本 BUG 排查
  • 测试验证

拿我的在某次版本开发举例:

  • 人力 A:工作两年,能力一般,对已有项目比较熟悉,适合旧业务适配编码 & 新业务研发编码
  • 人力 B:工作一年,能力一般,适合新业务研发编码 & 版本 BUG 排查
  • 人力 C:工作三年,能力很差,适合做一些耗时的版本 BUG 的解决方案测试验证(这位同事后面转岗干测试,最后被优化了)
  • 人力 D:实习生,基础非常好,但不懂业务,适合做技术调研 & 新业务研发编码
  • 人力 E:工作九年,能力不错,技术调研 & 新业务研发编码 & 旧业务适配编码 & 版本 BUG 排查都能干,设计方案也能帮忙做;解决方案的测试验证这种工作对他来说属于浪费资源

我会给人力三次机会完成任务,如果同一难度类型的任务失败超过三次,说明此人力不适合。作为组长需要帮人力兜底和指导,如果发现人执行过程有问题,指导之下,最后磕磕绊绊也能完成,那还是可以继续安排其做这种任务

人力的利用率问题,任务分配是主观影响因素,还有客观影响因素是人力本身能力,如果人力能力不足,其实只能发挥 0.7 个人力的作用。实力不够,加班来凑

4.2 任务拆分

工作中我负责大部分设计方案任务,完成设计方案后,再丢给底下的人力做编码。这期间,也会拆分小部分设计任务让其他人参与到这个流程

对于任务拆分,首先还是得理解业务需求,再按照服务-模块这个粒度做大拆分,比如

  • 服务 D-数据-数据权限
  • 服务 D-用户-用户认证
  • 服务 D-实验-代码运行
  • 服务 P-数据-代理适配
  • 服务 R-资源-资源消耗
  • 服务 O-代理-location 入口

按照服务-模块拆分成一个个任务后,就可以拆分出细粒度的子任务,一般子任务按照 1 ~ 5 个接口的工作量是适合的,子任务描述也需要写明白具体的工作内容

一般我会将拆分出来的任务 Draft 写到 wiki,并 @ 每个人,到上面进行下一步工作:估时

4.3 估时

完成“需求-任务(服务-模块)-子任务(接口集合)”的划分后,各人力进行估时,之后召开估时评审会。对于不合理的估时或需要更多时间的人力,要求重新估时。估时计算按接口数量,需要观察并总结小组的平均实力,这样估时才能有参考

从我当了两年多组长工作经历来看我的小组,我们一天工作 8 工时则有如下实力:

  • 设计:3.5 接口/人天
  • 编码:编码 + 自测,2 接口/人天
  • 联调:9 接口/人天

基本上我是按照这样的公式来给出我的整体排期和估时,当然接口 or 子任务有难有易,具体的子任务时间可以调整

题外话,从我的经验来看,按照这种公式给出排期后,往往领导会觉得研发小组实力不够,于是被打回,小组不得不按照”每天工作 10 小时 or 9 小时“估算,从而并给出更短的估时

作为组长,也可以预留 buffer,如果有机会的话,就要想办法在自己的任务估时或者 code review 多估一点。这里预留的 buffer,是自己管理的,而不是给底下的人用的。如果有问题还能 workaround 兜底

估时确定后,任务 Draft 完成,就可以在 JIRA 上建立任务了

  • 组长:作为组长,需要在 JIRA 上建立出任务
  • 人力:作为人力,需要在 JIRA 上建立出任务的子任务

五、评审工作

5.1 设计方案评审

我的工作中,设计方案评审主要有两大类:组内 & 组外

组内设计方案评审:组内人员完成设计方案后,会进行组内评审。我关注设计是否满足需求,是否有遗漏设计;除此之外,会往性能提升方向考虑,例如缓存设计、循环调用获取单一结果改成单次返回批量结果调用、去除冗余逻辑等。不过就业务设计来说,数据表和表字段的设计非常大程度上决定了业务功能接口的实现复杂度。一定要做好数据库设计。组内设计方案评审通过后,一般会产出一些需要调整的问题,让其完成调整后,进行产线评审

组外设计方案评审:在评审会上,关注与自己有协作的设计,核对设计是否符合预期,如有偏差则提出讨论确定解决方案。

5.2 代码评审

代码评审俗称 code review。组内人力完成编码和自测后,进行代码评审。所有组内成员参与,屏幕投影,对比设计方案和代码,逐步讲解编码实现,确保与设计方案一致

对于代码评审:

  • 重点关注:如上所述,是否有按照设计方案实现,往往人力对于复杂逻辑会有遗漏

  • 优化关注:关注代码实现是否有更好的写法,优化内容,如果时间紧张不改也罢

    • 语义化注释

    • 更短更准确的字段命名

    • 值对象传递只读,不写

    • 日志打印带上足够的业务信息

    • 解决 sonarlint 的质量问题 major 以及以上级别问题

    • 通过工具类、面向对象的一些概念,让代码更加面向对象语义化

虽然现在做的都是面向对象开发,但大多数人写的时候挺面向过程的。我认为近年提出的概念, DDD 就是某种程度上的面向对象的终点了。但 DDD 非常复杂,其中的一些聚合、防腐,都是可以借鉴设计的,还有例如单一函数职责之类的设计原则也可参考。使用一些工具类也可以帮助我们实现更加面向对象的语义

使用工具类,让代码更加面向对象

// 面向过程
if (desc.length() < 0 || desc.length() > 128) { 

}

// 面向对象
if (!ComparableUtils.is(desc.length()).between(0, 128)) {

}

使用 stream 编程,让代码更简洁

// stream 遍历比 Map Entry 更复杂
field2RuleMap.forEach((k, v) -> {
    fieldIds.add(FieldId.newBuilder().setName(k).build());
    fieldList.add(k);
});

使用函数式编程,让代码更简洁

// 抽象流程,如果发现两个接口流程一样,只有某个环节的处理异同,可以考虑抽象这个环节处理为不同的函数
BiConsumer<Integer, Integer> teamMergeOperate;
BiConsumer<Integer, Integer> teamMergeExceptionCleanOperate;

if (Objects.equals(condition.getAgree(), TrueFalseEnum.TRUE_VALUE)) {
    // 【同意】
    teamMergeOperate = this::competitionTeamMergeAgree;
    teamMergeExceptionCleanOperate = this::competitionTeamMergeOperateAgreeExceptionClean;
} else {
    // 【拒绝】
    teamMergeOperate = this::competitionTeamMergeDisagree;
    teamMergeExceptionCleanOperate = this::competitionTeamMergeOperateDisagreeExceptionClean;
}

teamMergeOperateByFunction(
        teamMergeOperate,
        teamMergeExceptionCleanOperate
);

5.3 调研评审

调研任务,一般会有几种:产品功能调研、BUG 解决方案调研、新功能的技术调研

对于产品功能调研,确保与需求契合,进行多方调研,包括国内外公司产品、GitHub、Gitee。需要有分析、对比和结论

BUG 解决方案调研,渠道包括国内外博客、CSDN、简书、官方文档、StackOverflow 和 GitHub 的 Issue 列表。不过注意,大多数普通人力一般也只会在 CSDN 和 StackOverflow 上找解决方案,不具备参与到社区的讨论和分析的能力

新功能的技术调研,展示可运行的 demo,确保满足功能需求,并进行多方分析、对比和结论

六、流程把控

6.1 例会制度

每天工作开始前,召开两个晨例会,会议控制在半小时,第一个例会是组长例会,拉开 JIRA 同步进度是否正常进行,同步项目的问题以及风险;第二个是组内例会,拉开 JIRA 同步进度,未完成的任务是否加班能完成 or 需要延期,任务执行过程中的问题以及其他问题推进情况

6.2 专项小组

工作中偶尔会有一些疑难问题,根本不知道是在哪一端触发的,但这种疑难问题可能又是亟需解决的,此时可以从各组拉出人,并安排其进行相应的排查任务,例如 A 组写脚本在 A 服务压测;B 组压测 B 服务;C 组提供 CI 支持等。紧急的疑难问题有结果及时同步就好了,尽快解决

七、外部对接

7.1 接口文档

外部对接一般分成两种:

  • 作为组件,提供功能
  • 作为平台,集成组件

工作中,我有三次都是作为平台角色,有一次是作为组件角色。角色不同,对接工作的侧重点和职责也不同。篇幅有限,暂不做扩展讨论

外部对接的接口文档,集团和产线现在没有明确的方案,我一般采用采用以下 excel 模板,命名时 会用使用 _年月日时间戳 来命令

excel 文件第一个 sheet 是接口

接口 编号 接口 中文名 提供方 调用方 实现状态 调用频次说明 同步/异步 功能描述 入参格式和样例 返回值格式和样例 补充说明

excel 文件第二个 sheet 是变更日志

日期 更新内容

7.2 会议纪要文档

除了外部接口文档,还要做好每一次的对外同步的会议纪要

  • 主题
  • 参与人
  • 会议主题:材料
  • 会议问题简要
  • 关键决议
  • 行动项(任务、截止日期、执行人)

7.3 外部交付产物跟踪文档

提供一个文档,梳理外部需要交付的内容,以及是否完成和交付

模块 功能 状态 预计工时 完成或预计完成日期 描述(存在问题)

7.4 推进外部合作的沟通方式

有时外部合作的进度推进地很慢,例如我曾经有个平台产线由于项目多,他们给予我们的支持就很慢,此时有以下两种做法:

  • 每日群里同步进展:拉对接群,并在群里拉上各自的 +1 + 2 级领导,群里每天下班前,每日同步问题进展,以及 @ 到对应的负责人,并告知还未交付,如果有延期风险及时说明
  • 每两天询问进展:按照两天的频率打负责人的电话,询问交付产物进展,让其尽快做完,并在晨会同步上报相关进展

八、面试招人

8.1 简历筛选

组长离职后,我作为一面面试官为后端组招聘新人,候选人工作经验在 3 至 9 年不等。大约持续了半年

在简历筛选时,首先由 HR 筛选,然后由我进行二次筛选。我关注工作经历、稳定性、技术水平和学历。如果有在大厂工作的经历,则说明已经经历了一轮筛选;我更倾向于寻找长期合作的候选人,而技术水平在纸面上很难区分

8.2 面试侧重点

我个人不会在面试中考察算法题。算法题除了数据结构题,对于业务工程上来说,应用还蛮少的

我喜欢考察场景设计题,所以初期面试,我会将工程中一些难的场景抽象出来,再去考察

例如考察并发编程,我会举例团队申请的合并业务场景:

  • 用户 A 创建了一个团队 A
  • 用户 B 发出了加入团队 A 的申请
  • 用户 A1 打开 Chrome 登录用户 A 账号,看到用户 B 的申请记录
  • 用户 A2 打开手机登录用户 A 账号,看到用户 B 的申请记录
  • 用户 A1 同意 用户 B 的申请记录
  • 用户 A2 拒绝 用户 B 的申请记录
  • 同意申请和拒绝申请是两个接口,这个操作过程,是否有并发问题?如果有应该如何解决,你可以获取到 用户 id、团队 id

我并不会在面试中直接考察其背诵并发知识点,而是会看能否解决实际问题

后期公司的面试组是出了一道排错题,以 PDF 的方式让候选人做,时间给 20 分钟,如果通过的话,再面试,如果面试不通过,也不需要再问了,这也算提高面试效率的一种方式

8.3 面试考察点

面试前,我也在思考我需要的人选是什么,我需要一名 Java 技术专家,为此我置定了一下需求表,我会按照如下需求考察,满足越多越好

能力目标 考察点 考察原因 考察题
写出好的代码 1、数据结构与算法;2、设计模式;3、函数式编程;4、面向对象思想与设计原则;5、Java 基础 了解常用的数据结构与算法、设计模式、函数式编程,才能在写代码时想到最好、最合适的方案,写出高质量的代码;不过设计模式一般也不大常用,可能其他三项知识比较能带来直观的效果;具备扎实的 Java 基础,对注解、反射、JVM、方法执行、集合容器、接口、抽象类、并发编程特性有着自己的、正确的理解
能够独立负责版本业务需求 1、面向对象 UML 分析与设计;2、数据库设计;3、SQL;4、基础工具能力;5、测试基础能力;6、docker & k8s 虚拟化技术 做一个版本开发涉及:需求分析、方案设计、评审 review、编码、自测、联调、测试、发版。1、UML & 数据库设计:业务方案设计其中要分析需求,抽象出表和表的 E-R 图关系很重要。以及能正确建立索引;剩下的可能具备时序图、类图能力,如果知道实现、关联、聚合、组合、依赖等关系之类的更好。2、SQL 能力:对数据库的了解,一个复杂查询能给出 SQL 做法或者代码做法;3、数据库设计:当然数据库的基础知识还是得要具备的,事务、数据库的乐观锁和悲观锁的设计,事务隔离级别之类的;4、基础工具能力:具备 git 能力,怎么用 git 的,git 的各种常用命令怎么用,idea 调试能力,日常是怎么调试的,是否具备抓包分析的能力;5、测试能力,怎么自测的,单测的了解,mock 技术有没有了解;6、虚拟化技术:具备 docker 的常用基本知识和操作
能够设计与写出复杂的基础组件和代码 1、并发编程能力;2、分布式系统的常见问题与解决方案以及基本的实现原理;3、计算机网络;4、操作系统原理;5、NIO 编程能力 做好复杂的组件,往往需要一定的并发编程能力,对常见分布式系统面临的问题有所了解,并且知道有哪些常见的解决方案;1、并发编程能力:乐观锁、悲观锁在编程语言的提供的方案,适用的场景,线程安全的容器;2、分布式系统的常见问题:限流、缓存、锁、事务、异步、负载均衡、网关、服务注册发现、海量数据处理(存储、流转发、计算);3、计算机网络:对 tcp 和 udp 的协议特点有一定了解,了解 TCP/IP 协议栈下如何更好地去设计方案;4、操作系统:操作系统的进程编程提供的一些解决方案,常见的错误排查 linux 命令;5、NIO 能力,目前我也不大了解
具备足够的发展与合作潜力 1、技术敏感性,新技术优缺点,趋势的理解;2、历史经历分析的性格 & 沟通特点 1、云原生的需求,GraalVM、协程、ZGC 低停顿 GC、响应式编程,GraphSQL;2、历史经历:抗压能力、沟通能力、专注力

附录

研发流程

我们的产线执行的研发流程如下:

  • 前端沟通:市场前端,像销售,完成客户洽谈,会与产品同步对齐相关项目 or 客户需求
  • 技术预研:产品会形成初步的方案,对于不确定 or 复杂需求,产品会与研发同步,并让其做相关方案的技术预研。这个过程可能根据调研的结果,影响最后的产品的需求
  • 需求评审:产品将初步的方案细化或,做成需求文档,并与产线各组同步产品需求
  • 概要设计:完成需求评审后,各组开始根据需求做概要设计(数据库设计、功能流程设计、模块结构设计、缓存设计、接口设计… )
  • 概要设计评审:完成概要设计后,研发需要召集参与本次项目研发的人员,进行概要设计同步和评审,让各组知道自己的工作,同时各组需要评估设计的可行性
  • 编码:研发对着概要设计进行编码。最简单的一个环节
  • 编码评审:研发进行代码 review
  • 联调:部署到研发环境,进行各组联调
  • 冒烟测试:联调结束,部署到测试环境,进行冒烟测试
  • 一轮测试:一轮测试,此轮解的 BUG 的解决会在二轮解
  • 二轮测试:二轮测试,验证一轮测试的 BUG,如果新发现了重要、危险 BUG,打回二轮,重新解完后,再此验收这些问题
  • 三轮测试:理论上此轮的 BUG 不解决,验证核心流程用例,,如果新发现了重要、危险 BUG,打回二轮,重新解完后,再走流程
  • 产品验收:产品验证功能解决
  • 发版:发布版本

总结的面试题

曾经总结过以下面试题,用于面试候选人

  • JVM

    • JVM 的作用是什么?现在这个时代 JVM 有必要存在么?Java 对此做的决策是什么?
    • 垃圾回收器常说低停顿和高吞吐量,如何理解这两个特点?
    • 了解 JVM 的知识,对你来说有什么帮助?为什么去了解 JVM 的知识?
  • 面向对象

    • 面向对象和面向过程区别是什么,举例谈谈你的理解
  • 注解

    • 聊聊你对注解的理解,并讲讲它的使用场景是啥?
  • IO 流

    • 我们常用的是输入流和输出流,有个场景是我如果想边写边读,有什么好的想法?有没有更好的数据结构解决此问题?JDK 对应的实现是什么?那么阻塞,如何做超时呢?
    • 讲述一下,你所理解的 IO 场景和 CPU 计算场景是啥?
  • 并发编程

    • 对于并发编程,做过什么场景?从中归纳出解决并发问题,核心是什么?
    • 做并发编程,保证线程安全,了解过哪些方案?
    • volatile 这个是作用了解过么?为什么需要这个关键字?频繁使用会有问题?从其中可以得出什么编码注意点?
    • 线程池用过么?你是如何确定最佳的参数配置的?
    • 进程 & 线程有了解么?为什么需要这个东西?什么时候选择进程与线程?协程呢?什么时候选择协程?哪种场景选择进程编程?
    • 并发场景题:QQ 群可以同意加入 QQ 群申请,用户可以登录手机端、电脑端对同一条申请进行点击同步或者拒绝,此时有没有并发问题?如果有,你可以知道用户 id、qq 群 id,对于 同意和拒绝 这两个接口,代码怎么写,能解决这个问题?
  • 计算机基础

    • 你是如何序列化的?常见的序列化协议有了解么?
    • 反射的性能和实例化的性能有了解过么?用它可以比较方便地做什么事情?
    • 值传递和引用传递了解过么?java 是什么传递?如何在 java 传递函数?
    • java 有哪些缺点?
    • map 有用过么?什么场景用这个?线程不安全?有哪些线程安全的替代方案?你会如何做测试证明新方案是线程安全的?
    • 链表和数组了解过?链表插入性能优秀?但查询不如数组,有了解过比链表更好的方案么?有什么代价?
  • 数据库

    • 事务有了解过么?为什么需要事务?
    • 事务与存储数据,如何进行回滚?
  • 网络

    • HTTP 和 TCP 的关系是什么?HTTP 1.1 有什么问题了解过么?有什么解决方案? HTTP 2 的问题了解过么,如何解决?
    • 如何本地调试?本地把服务跑起来,前端是如何将数据传递到后端的,可以结合网络、物理设备、操作系统,网络协议讲一下这期间的过程么?
    • 文件上传的原理了解过么,数据是如何从用户端的磁盘到服务器后端磁盘的,从数据 IO 读取、数据在 HTTP 报文如何传递 两个方面讲述一下?
    • TCP 三次握手四次挥手有了解过么?知道有没有手段可以在工程中调整这个过程?
    • 有没有 tcpdump 抓包过?
  • 运维排查

    • 部署在 k8s ?如何排查 java ?如何看日志?
    • 多节点部署服务的时候,存储是怎么同步的?存储在本地的日志呢?
  • Git

    • git 用过么?你是如何解决冲突的?
    • reset 和 revert 有了解过么?
  • 分布式

    • 负载均衡有了解过么?服务端负载均衡和客户端负载均衡有什么区别?
    • 限流场景题:限流有了解过么?如果有,业务服务,计算服务。计算服务最多只能提交五个最大提交,你怎么满足此需求?

项目排期表

近期一个版本的排期实例如下

任务类型 负责人 07-21 07-25 08-03 08-04 08-10 08-24 08-25 09-05 09-08 09-22 09-25 10-08 10-09 10-10
需求 @产品 需求评审
设计-概要设计方案 @研发 概要设计-开始 概要设计-评审
设计-系统测试方案 @测试 测试方案-评审
设计-测试用例评审 @测试 测试用例-评审
设计-系统构建方案 @运维 构建方案-评审
开发&单元测试&部署 @研发 编码-开始 编码-完成
集成联调 @研发 联调-开始 联调-结束
提测 @研发 提测邮件
一轮测试 @测试 一轮-开始 一轮-结束
二轮测试 @测试 二轮-开始 二轮-结束
三轮测试 @测试 三轮
产品验收 @产品 验收
售后验证 @测试
发版 @产品

项目风险报告表

提出人 风险分类(管理、技术、客户、团队) 风险内容 风险级别(低、中、高) 管理措施 责任部门/人 提出时间 解决时间 解决方案 原因分析