10x程序员工作法——任务分解

任务分解:

找到实现路径 ‼️学习经验,收集错误/痛点/风险点

将大目标拆分成可执行任务序列。

检验标准:是否清晰知道如何行动。知道自己下一步要做什么,优先级-应对插入打断,需要哪些资源,有什么风险-什么时候能消除这部分不确定性,制定可完成的计划时间表。

:小 ✅可以随时停下来 try粒度在1~3个番茄之间

:分而治之

开发:feature -> user story -> task

#随着软件开发,软件变更成本在逐步增加

测试金字塔:

:越是底层越多测试

:多写单元测试

在本地运行单元测试和集成测试,在持续集成服务器上运行系统测试

mvc结构的工程,c层的单元测试要实际的去调用m层吗?需要和数据库里的数据做比对和验证吗?如果不用,c层的单元测试应该验证或测试哪些内容呢?

作者回复: 在单元测试里,M 的接口是可以用 Mock 的,这才算是单元测试。涉及到数据库,就变成了集成测试。

测试驱动开发TDD(Test Driven Development/Design)

❗️≠ 测试先行开发(先写测试后可代码)。区别在于重构。

思维上的转变:编写可测的代码

开发守则:

尽量不写 static 方法。

除非它不涉及任何状态&&行为简单,如可以抽象出来做库函数的程度。

if 第三方的static,将其封装

主分支开发模型是一种更好的开发分支模型

极限编程:

思想:把好的实践推向极限

实践:TDD、持续集成、结对编程、现场客户……

最佳实践是,基于主分支的模型。大家都在同一个分支上进行开发

一个是在已用线上产品的时候,我们通常会有一条release分支。这样当有线上bug出现的时候,我们能在release分支上快速修复 + 上线。

另外一个是,在规律性的迭代上线时,难免会遇到有story没有完成(开发或者测试),此时,就得使用feature toggle 或者 revert代码了。

最后是当在做一个很明显上线前不可能完成的大feature的时候,一般我们会启另一条分支来开发。此时会定时从主分支merge代码,因为有些改动可能会影响已用的业务

主分支开发模型 遭遇 多个功能同时开发:

Feature Toggle:通过开关,决定哪个功能对外是可用的。//应该是一个非常临时的存在。除非在遗留系统上工作,功能要跨越很长周期。

[]https://martinfowler.com/articles/feature-toggles.html

[]https://www.infoq.cn/article/function-switch-realize-better-continuous-implementations

Branch by Abstraction:在动手改造前,先提取出来一个抽象,把原先的实现变成这个抽象的一个实现。改造的过程就是提供这个抽象的一个新实现。

✅在一个分支上进行

❎对设计能力有一定要求。对很多团队来说,这是一个挑战。

写出思路、需要用到的知识点,api等,写出各个小任务,然后对应写出关键代码段。

开发实践中注意:

数据库迁移别忘记

把需求分解到具体的方法和目标:

领域对象,这里就是用户

数据访问层,在不同的项目里面叫法不一,有人从J2EE年代继承下来叫DAO(数据访问对象,Data Access Obejct),有人跟着Mybatis 叫 mapper,我现在更倾向于使用领域驱动设计的术语,叫 repository

服务层,提供对外的应用服务,完成业务处理

资源层,提供API接口,包括外部请求的合法性检查

考虑分布式服务器

访问控制:

调整依赖关系,按需求的完整实现来写,而非一个一个类

根据现状制定改进路径,不要想着一步到位

分解不了解的技术任务:

做一次技术spike,先将它变成熟悉的技术 #⚠️发散

    0.  通过各种渠道(新闻网站、技术blog、上级安排……)对要使用的技术有感性的认识,知道他是干啥的。

快速完成教程上的例子 (4-5h)

确定这项技术在项目中应用场景和我们的关注点。

//‼️spike没有那么多时间通读文档!!!要针对最重要的场景选出几个最需要的功能。

‼️要找准关注点。比如,采用新的缓存中间件是为了提高性能,那关注点就是性能,采用新的消息队列是为了提升吞吐,那关注点就是吞吐。我们选用一项新技术总是有自己的一些假设,但这些假设真的成立吗?这是我们需要验证的

验证想法,决定是否采纳这项技术。

‼️‼️假如确定使用,丢弃原型重新设计‼️‼️

怎么把新技术用在自己的项目中?

思考这个问题重点要放在“自己的项目”而不是新技术。

不要混淆目标与现状:

【目标】应该怎么做

【现状】正在怎么做

‼️忙是不去思考改进的借口。假如不忙了,你知道该怎么改进吗??!

以测试为例:

业务代码100%测试覆盖

任务分解:

与人沟通:

与团队达成共识

将最佳实践及背后的逻辑与之沟通,讲清Why,触发动机

自动化:

把测试覆盖率检查加入工程,得到现有的测试覆盖率

将测试覆盖率加入持续集成,设定当前测试覆盖率为初始值。测试覆盖率不达标,不许提交代码。

每周将测试覆盖率调高,比如:5%或10%,直到测试覆盖率达到100%

需求管理:

‼️口头不算,全部文件邮件确认,存档。

区分优先级,尽可能把精力放在重要的事情上。 站在老板面前讲道理

//艾森豪威尔矩阵(Eisenhower Matrix)

告诉老板:我资源有限,需要将这两个需求排个序,看哪个更重要。我的上下文有限,需要你帮我判断一下

老板会和你说这起两个需求的起源:

扩展盈利的需求是竞争对手都已经有了客户也问这边要,再不做会影响客户关系,尤其是新财年快到了,下个阶段的合同会受到影响。

而另外的新业务是某天一个高端聚会上得到的新启发,想尝试一下,他也不确定这个想法能带来多少收益,就让产品部门试一下

可视化团队四象限:

为了适当减少每次argue需求优先级带来的沟通成本,还可以把当前团队正在面对的四象限公示出来,让大家都能看到团队路线图,让提需求的人(产品经理更需要)看看自己的需求在哪个象限,什么优先级,有时候他们自己就明白了

需求分解:

一般用户故事经两次拆分,先是业务,再是估算时拆小它。

用户登录是一个master story,可以拆分成第三方验证,邮箱地址验证,登录验证码……

好的细分需求的衡量标准:INVEST原则

Independent 独立性:一个用户故事完成一个独立的功能,如果有依赖,将该部分拆出来,重新调整 //2019/4/28 其实依赖那里没有看懂,抽出来不还是要依赖吗?是开发依赖还是业务依赖

Negotiable 可协商性:主动提问理清需求

需求管理中印象最深的是刚进入开发行业时的一段经历。当时要显现某种单据,单据本身还嵌套子单据,原始需求是单据按层次显示,但某变量等于某个值时,某层次的单据就隐藏,但它的再下一层子单据需要显示。解决方案简单可以理解成页面要用递归方式才能正确显示。当时一心想显示自己牛鼻,因为无法用通常的页面模版机制,就自己写工具递归生成页面代码,看起来代码很巧妙,但别人难以维护。后来有段小插曲,若干年后项目移交到另外一个研发中心时,还需要有人专门去讲这段代码,否则接手人很难理解。再说回到之前,开发完后有一次和业务分析员再次聊起,说这个很不好实现但我啃下来了等等,他说那可以不用隐藏,显示空白层也可以,真如果这样实现就简单多了,也好理解多了。事不大,但在职业生涯里印象深刻。需求不光是拆解,更可以讨论后寻找简单解决方案,而不是用自以为牛鼻的代码实现。以更合理的成本实现需求交付价值,这其实是用户故事里Negotiable的意义所在

Valuable 有价值的:

这个功能不做,用户会怎样?有没有什么替代方案。

Estimatable 可估算的:

假如不能估算,要么因为还有很多不确定因素,要么因为需求还是太大,都没到可开发的状态。

❗️How:分解好用户故事之后从中挑出最简单的作为基准,其他任务清单和它相比的复杂度给个估计。

假如大家估算差异过大,是因为对需求的理解出现了巨大的差异。

Small 小:小才方便调度和安排工作

Testable 可测试的

面对不确定的产品:最小可行产品(Minimum Viable Product,MVP)

❗️最小的代价:

:能不做就不做,能简化就简化

‼️我们要做的是验证一个想法的可行性,甚至不是为了开发一个软件,不要把解决方案当作问题。

想做物联网相关项目:

做产品文档,让销售拿给用户看。➜ 验证已有设备进行物联网改造的需求确实存在。额外收获:知道客户能接受的价格区间

用原型工具做界面和产品交互,用户可以实际体验➜根据用户真实反馈,调整产品设计

整理反馈,决定哪些可以真正开发出来,进入开发阶段

可行的路径:

:可行不是模块多么完整,而是用户路径是否畅通

:P2P项目(个人对个人互联网借贷平台),项目方希望尽快上线:

#当时间有限时,我们需要学会找到一条可行的路径,在完整用户体验和完整系统之间,找到一个平衡。

业务模型:贷款方贷款之后,一次性拿到所有的钱,然后用等额本息的方式每个月还款,最后一个月剩多少钱一次性全还了。

第一次上线,1个月后➜只做最基本的还是不够时间➜第一版只包含贷款能力

两周一迭代,一个半月后上线了每期等额本息还款。

基础上慢慢叠加,但用户发现不了,它的视角始终是个完整的平台

总的来说,小步快跑。先弄清客户想要什么,整理后再用自己的语言复述一遍,后面拿着原型+业务交互给客户确认,同时把自己的设计理念植入进去和客户探讨,有些点对方之前也没有想清楚,尤其是实现方面需要专业的软件意见去参考,而我们再从探讨中更新自己的认知,如此往复几次,大方向上就不会有偏差,后面在实施过程中再局部调整。尤其是对于不确定性很高或者从零开始的工作,这是个可操作的方式。

测试:

阶段:

前置准备:准备依赖 e.g:组件(使用mock隔离)、参数

❗️执行:一般就一行代码的调用

断言:我们的预期,就是这段代码执行出来怎么算是对的 //不只是assert,mock框架的verify

清理: 释放资源 //利用好现有的测试基础设施(比如,JUnit 的 Rule),遵循好测试规范的话,很多情况下,这个部分就会省掉了。

A-TRIP:

Automatic,自动化:尽可能交给机器,人工参与越少越好。

Thorough,全面的:

写代码前:考虑各种场景:正常的、异常的、各种边界条件

代码写好后:看测试是否覆盖了所有的代码和所有的分支

if在补测试,让测试覆盖率逐步提升是个好方法

Repeatable,可重复的:

反复运行结果应相同

测试本身不依赖于任何不再控制下的环境:

外部依赖➜模拟服务 Moco:模拟外部HTTP服务

依赖数据库➜测试完后回滚数据库 SpringBoot@Transactional

CI的数据库是共用的,没有本地的那份初始化数据集

➜保持数据库干净,用测试时用初始化脚本准备数据

➜如果测的场景比较复杂,比如要测多个事务的交互结果,还可以引入Docker,将依赖的数据库及初始化数据做成Docker的image,测试代码就更加简单,并且可以重复运行了,只要CI支持Docker即可

测试代码中尽量避免与数据库打交道,测试更关注领域与业务,往往爆雷更多的是resource和service,模型的变化往往牵动着表结构的变化,与其两头兼顾不如多聚焦模型,我常用的做法是用例配合若干小文件(数据忠实于模型),保证库操作临门一脚前所有环节都是正确的,同时方便适应变化。一旦出现异常,也比较容易定位是否是数据库操作引发的问题。(此点基于工作中发现项目型程序员大多是先急于把表结构定义出来,好像不这么做写代码就不踏实) //2019/4/27 虽然没太看懂

Independent,独立的:测试不相互依赖 

if多个测试有相同的准备和清理➜use setup & teardown 

Professional,专业的:按代码的标准维护

比如:良好的命名,把函数写小,要重构,甚至要抽象出测试的基础库, Web 测试中常见的 PageObject 模式

简单到一目了然,不需要证明它的正确性

一个测试做很多事。出现了几个不同的方法的调用 ➜拆分成几个测试

没有断言 Hmm……

复杂 出现判断/循环语句➜判断 拆分 每个测试覆盖一种场景 | 循环 测试等价类->用少量数据

你可能感兴趣的:(10x程序员工作法——任务分解)