敏捷开发修炼之道

敏捷开发就是在一个高度协作的环境中,不断地使用反馈进行自我调整和完善.

态度决定一切

做事, 追求结果:

  • 以结果为导向, 一切的工作都围绕”把事情做成”. 有问题解决问题, 不允许相互指责, 批判错误而不批判人
  • 如果一个成员一再做伤害团队的事情, 无疑显示了他的不专业, 不专业的人无法帮助团队前进
  • 当团队中大部分都不专业, 并且没有工作目标, 及早离开

戒骄戒躁,步步为营

  • 改代码之前, 要先理解代码. 同样, 要理解团队的开发方法和开发过程, 遵从统一的开发方式
  • 警惕”破窗效应”, 一次的妥协, 在不理解的基础上对代码进行类似+1-1的快速修复, 就一定会有下一次
  • 重视单元测试, 好的单元测试, 会是代码极佳的说明文档

    对事不对人

  • 可以不用直接指出队友方案中的错误或不足, 转而以描述问题场景, 询问解决方法来替代. 可能业务场景有特殊性, 并不见得是错误
  • 一致对外, 对内多包容. 每个人都会有好的创新想法, 也会萌生愚蠢的馊主意. 要引导团队变得更开放, 禁止组内有挖苦/挤兑的情况存在
  • 没有绝对完美的方案, 兼收并蓄, 努力在当前场景下优点最多缺点最少的方案上让大家达成一致.

排除万难, 勇往直前

  • 每当发现代码有问题或者不够简洁, 都需要立马进行重构/优化, 不是自己负责的代码, 也应该大胆提出来. 只要方向是正确的, 勇往直前
  • 提出观点, 应当具有理论依据, 否则没有说服力
  • 遇到缺乏背景知识的抉择者, 要以对方能听懂的方式去沟通. 目的是为了让论点有说服力

学无止境

跟踪变化

  • 迭代和增量式学习
    • 高频次
    • 最好每次只涉及1个点
  • 多看好书(技术/非技术均可)
  • 机会总是给有准备的人

对团队投资

  • 一个学习型的团队才是好团队
  • 让团队中的每个成员分享他们擅长的技能, 带动其他成员赶上
  • 能提高其他团队成员的人, 应该得到重用
  • 坚持分享, 成就感和关注度能够督促每个成员学习

懂得丢弃

  • 既有的习惯与思维应该用来帮助理解与解决问题
  • 当学习新知识时, 要有开放心态, 不能生搬硬套

刨根问底

  • 在找到真正的原因前, 不要停止问为什么
  • 要想清楚提问的理由, 问到点子上

保持开发节奏

  • 尽量让自己的代码可以在一天结束时, 执行完测试用例然后提交到仓库. 让自己每天都是新的开始
  • 保持固定的迭代周期, 在迭代周期内执行明确且合理的开发任务, 保持节奏

交付符合预期的软件

需求负责人决定

  • 把影响系统使用或系统行为的问题上报给负责人, 由负责人决定, 只需提供选项

设计只到战略层面

  • 重视战略设计, 战术设计留给开发人员
  • 好的设计是正确的, 不是精确的
  • 设计只需要到调用关系, 可以使用类图或系统交互图来描述
  • 开发过程中, 意识到新问题, 不停地调整设计与代码

合理使用技术

  • 警惕”简历驱动设计”
  • 技术方案的花费不应该高于解决的问题
  • 不需要开发容易下载到的东西, 代码写的越少, 维护的工作就越少
  • 每一门技术都有优点和缺点, 使用时要清楚利弊, 根据需要选择技术

保持可以发布

  • 代码提交前必须自测通过
  • 代码提交前必须合并远端最新代码

持续集成

  • 尽早集成, 频繁集成, 才能尽早发现问题, 降低风险

自动化部署

  • 尽早使用容器, 实现统一的运行环境

不停演示, 不停接收反馈

  • 需求总有不确定性, 越早得到反馈, 越早修正错误
  • 有缺陷或不稳定的功能, 不要拿来演示

短迭代, 增量发布

  • 迭代开发: 在小且重复的周期内, 完成分析/设计/实现/测试和获得反馈
  • 注意迭代周期与任务量的匹配
  • 相邻迭代中间可以安排时间做总结/维护性工作

敏捷反馈

代码的保护神

  • 单元测试, 用单测验证结果, 验证变量
  • 可以保留一些只为单测而写的方法

度量真实的进度

  • 舍弃计算工作量完成百分比, 应该评估剩余任务的工作量
  • 每次都将实际工作量与评估工作量做对比, 不断修正评估方法, 让评估越来越准确
  • 用待办事项排列剩余任务和任务优先级

持续集成

  • 区分环境进行持续集成, 避免环境不同导致的问题
  • 持续集成需要有失败告警机制

倾听用户的声音

  • 用户的抱怨背后隐藏着真正的问题
  • 用户是最终的使用者, 从用户出发, 理解用户的行为习惯

敏捷编码

代码要清晰地表达意图

  • 代码清晰度优先级高于执行效率
  • 想要读简洁易懂的代码, 要先做到自己的代码简洁易懂
  • 代码改动流程: 读懂代码->确定改动点->修改并测试

用代码沟通

  • 保留类/方法的JavaDoc注释, 尽量避免方法体内的注释
  • 写简明扼要的注释
  • 让代码能够自解释
    • 正确命名变量/方法
    • 清晰分离逻辑
    • 简洁表达逻辑

动态评估取舍

  • 没有完美的解决方案, 只有相对最合适的解决方案
  • 评估投入产出比, 不为10%的收益付出90%的努力
  • 过早的优化是万恶之源
  • 要因地制宜地设计方案, 不可生搬硬套

增量式编程

  • 编程过程中不停调整, 持续做细小而有用的事
  • 番茄工作法
  • 测试代码也需要经常调整或重构

保持简单

  • 警惕过分设计
  • 开发可以工作的, 最简单的解决方案
  • 不要过于追求简洁, 防止矫枉过正

高内聚

  • 让类的功能尽量集中, 让组件尽量小

方法区分查询和命令

  • 将方法分为命令与查询两种类型
    • 查询不应该改变对象的可见状态
    • 命令改变对象状态, 可以有返回值

里式替换原则

  • 里氏替换原则: 子类可以自由替换父类
  • 继承的最佳实践之一:代理模式/装饰模式
  • 不能进行里式替换, 就采用依赖/聚合的方式
  • 通过替换代码类扩展系统

敏捷调试

工作日志

  • 每日工作日志汇总每日问题的解决方法, 学到的知识点
  • 每周分别汇总知识点和问题集

高效调试

  • 如果依赖的第三方没有准备好, 可以先用mock本地调. 同理, 往小可以引申到代码层级调试; 往大可以引申到多服务调用调试

抛出所有异常

  • 注意, 代码层级间如果抛出的是检测异常,则需要处理, 不应向上抛, 增加层级耦合. 如果不能处理, 最好的方式是包装成运行时异常或者当前层级所定义异常抛出
  • 影响业务流程的地方才抛出异常
  • 抛出的异常要有实际意义, 比如抛出一个NullPointerException其实没有意义

异常信息应准确

  • 抛异常应该伴随着日志记录, 最好有主键信息方便问题定位
  • 异常的错误信息要有实际意义, 能指出问题直接原因, 不能空泛

敏捷协作

定期安排站会

  • 每人2分钟左右, 全程10-15分钟
  • 小团队可以每周1~2次
  • 上班后半小时~一小时内开始站会
  • 会议内容
    • 昨天的成果
    • 今天的工作计划
    • 面临的问题
  • 如果是大于1天的工作量, 成果和工作计划必须明确
  • 根据会议总结进度, 调整任务, 摊开大饼
  • 会上不讨论问题细节, 可以会后再召开小规模会议讨论
  • 通过会议, 达到问题集思广益, 激励团队成员前进的目的
  • 如果有人觉得站会浪费时间, 那是没有形成真正的团队意识

架构师必须写代码

  • 新系统的设计者必须亲自参与实现
  • 不理解细节, 就不可能做出好的设计
  • 战略层次(总的架构)不允许单独设计, 战术层次(具体问题)如果是单独设计, 最好有评审
  • 鼓励程序员参与设计

代码集体所有制

  • 实行模块轮换制, 定期开发人员负责不同的模块
  • 实行模块owner制度, owner对模块负全部责任
  • 所有人都可以往不同的模块提交代码, owner负责评审
  • 特殊模块可以让专家驻留, 对其开放其他模块代码
  • 如果不能实行轮换制, 那一定是高精尖项目

成为指导者

  • 费曼学习法
  • 通过别人的提问发现不同的角度. 如果不能回答, 就要继续学习增加
  • 形式多样, 可以是讨论问题, 可以是博客分享
  • 过程是分享自己的知识/经验和体会, 目的是提高自身与队友的能力, 进而提升团队实力
  • 讲得多的主题就记录成笔记, 进而可以据此写出博客, 甚至是书

指导者的工作法则

  • 在告知答案前, 鼓励/引导大家思考如何解决问题
  • 尝试用问题来回答问题
  • 如果过了限定时限, 还是没有进展, 直接告知答案, 再给解释
  • 如果一个成员拒绝尝试自己寻找答案, 甚至不想听答案的解释. 那他是拒绝进步的, 这类人不适合留在团队

代码管理

  • 合并到公共分支的代码, 必须过编译过单测
  • 主干分支的代码合并需要给模块owner review
  • 差异不意味着不好, 除非能让代码变好, 否则不要批判别人的代码

及时公布进度

  • 不同的受众, 关心的进度粒度不同, 要做好区分
  • 每日站会评估进度, 一日一次比较好, 紧急的可以一日两次
  • 当工作量/问题的原因导致进度受阻或者需要延期, 要及时处理, 方式有如下:
    • 及时寻找资源(人/开源工具)解决, 能解决尽量解决
    • 不能解决的问题, 抛给上层, 让上层决策