以3个思考问题为核心的思考框架
- Where are we?(我们现在在哪?) 现状
- Where are we going?(我们要到哪儿去?)目标
- How can we get there?(我们如何到达那里?)实现路径
整个工作法以4个思考原则展开讨论
以终为始,确定好真实目标
- 遇到事情倒着想,首先描述要做的事情,包括背景和意义,然后先写用户使用文档,最后再写代码。
- DOD (Definition of Done,完成的定义)-做任何事情,先定义完成标准,可以固化到流程,是一种有效协作方式
- 检查项清单
- 梳理依赖,确定边界,用“用户故事”描述需求,定义验收标准(正常流程和异常流程)
- 交付物不是代码,是可工作的软件,如何做好集成?
- 最小可行产品 MVP(Minimum Viable Product),默认所有的需求都不做,知道弄清楚为什么这么做。
- 《精益创业》
- 精益创业的方法论里,提出“开发(build)-测量(measure)-认知(learn)”这样一个反馈循环。就是说,当你有了一个新的想法(idea)时,就把想法开发成产品(code)投入市场,然后,收集数据(data)获取反馈,看看前面的想法是不是靠谱。
- 得到的结果无非是两种:好想法继续加强,不靠谱的想法丢掉算了。不管是哪种结果,你都会产生新的想法,再进入到下一个循环里。在这个反馈循环中,你所获得的认知是最重要的,因为它是经过验证的。在精益创业中,这也是一个很重要的概念:经过验证的认知(Validated Learning)。
- 扩大自己工作的上下文,在更高的维度思考问题。
- 不同角色工作真正的差异在于上下文的差异。在一个局部上下文难以解决的问题,换到另外一个上下文甚至是可以不解决的。所以说无论单点有多努力也只是局部优化,很难达到最优的效果。
- 想把工作做好,就需要不断扩大自己工作的上下文,多了解一下别人的工作逻辑是什么样的,认识软件开发的全生命周期。
- 在动手做一件事之前,先推演一番。
- 问一下自己,我的工作是不是可以用数字衡量。大数据时代,可视化的价值,定义好测量工作的有效性指标
迭代考虑项
任务分解,找到实施路径
- 动手做一项工作之前,首先进行任务分解。
- 最佳实践称之为测试金字塔,它强调的重点是,越底层的测试应该写得越多。只有按照测试金字塔的方式写测试,持续集成才能更好地发挥作用。
- 多写单元测试。
- TDD测试驱动开发已经是行业中的优秀实践,学习测试驱动开发的第一步是,记住测试驱动开发的节奏:红——绿——重构。把测试放在前面,还带来了视角的转变,要编写可测的代码。
- 将任务拆小,越小越好。
- 按照完整实现一个需求的顺序去安排分解出来的任务。
- 测试一定要写断言。
- 一段旅程(A-TRIP)
- 怎么样的测试算是好的测试呢?有人做了一个总结 A-TRIP,这是五个单词的缩写,分别是
- Automatic,自动化;
- Thorough,全面的;
- Repeatable,可重复的;
- Independent,独立的;
- Professional,专业的。
- 绝大多数问题都是由于分解的粒度太大造成的,少有因为粒度太小而出问题的。
- 想要管理好需求,先把需求拆小。
- 评价用户故事有一个“ INVEST 原则”,这是六个单词的缩写,分别是:
- Independent,独立的。一个用户故事应该完成一个独立的功能,尽可能不依赖于其它用户故事,因为彼此依赖的用户故事会让管理优先级、预估工作量都变得更加困难。如果真的有依赖,一种好的做法是,将依赖部分拆出来,重新调整。
- Negotiable,可协商的。有事大家商量是一起工作的前提,我们无法保证所有的细节都能100%落实到用户故事里,这个时候最好的办法是大家商量。它也是满足其它评判标准的前提,就像前面提到的,一个用户故事不独立,需要分解,这也需要大家一起商量的。
- Valuable,有价值的。一个用户故事都应该有其自身价值,这一项应该最容易理解,没有价值的事不做。但正如我们一直在说的那样,做任何一个事情之前,先问问价值所在。
- Estimatable,可估算的。我们会利用用户故事估算的结果安排后续的工作计划。不能估算的用户故事,要么是因为有很多不确定的因素,要么是因为需求还是太大,这样的故事还没有到一个能开发的状态,还需要产品经理进一步分析。
- Small,小。步子大了,不行。不能在一定时间内完成的用户故事只应该有一个结果,拆分。小的用户故事才方便调度,才好安排工作。
- Testable,可测试的。不能测试谁知道你做得对不对。这个是我们在前面已经强调过的内容,也就是验收标准,你得知道怎样才算是工作完成。
- 按照时间管理的理念,重要且紧急的事情要立即做。重要但不紧急的事情应该是我们重点投入精力的地方。紧急但不重要的事情,可以委托别人做。不重要不紧急的事情,尽量少做。
- 需求分解之后,最重要的是,排列需求的优先级。
- 需求分解成一个个小块,其实也分解了原本合一的上下文。如果想要有效地管理需求,尤其是确定事情的重要程度,一种方式是找回丢失的上下文。如果我们自己无法判断上下文,一种好的办法是,引入外部更大的上下文。
- 我们要做的是验证一个想法的可行性,甚至不是为了开发一个软件,开发软件只是一种验证手段。
- 不是一个模块做得有多完整,而一条用户路径是否通畅。
- 做好产品开发,最可行的方式是采用 最小可行产品(Minimum Viable Product,MVP)。
- 最小可行产品就是“刚刚好”满足客户需求的产品。
沟通反馈,解决与人打交道出现的问题
- 通过沟通反馈,不断升级自己的编解码能力。
- 用业务的语言写代码。
- 站会。之所以采用站会的方式,就是要控制时间。在站会上每个人说什么,我给了你一个建议的格式:
- 我昨天做了什么?
- 我今天打算做什么?
- 我在过程中遇到了什么问题,需要请求帮助。
- 多面对面沟通,少开会。
- 人的大脑更擅长处理图像。
- 多尝试用可视化的方式进行沟通。
- 雷达图、流程图、UML 等。
- 看板。看板把工作分成了几个不同的阶段,在看板上对应不同的列,然后,每个任务作为一张卡贴在上面。每完成一张卡,就把这张卡挪到下一个阶段。
- 做好持续集成的关键在于,快速反馈。
- 定期复盘,找准问题根因,不断改善。
- 多走近用户,聆听用户声音,做对用户有价值的产品。
- 能用尽可能小的时间颗粒度来安排自己的工作。
- 在工作中要拓展自己的上下文,将自己放在更大的范围、平台上去思考问题,主动发掘问题关键点,在面对不同职能人员间沟通时,多运用“以终为始”模块中的知识尝试解决分歧,达成共识。
- 一旦有困难,尽早暴露问题,寻求帮助。
- 多输出,让知识更有结构。
- 金字塔原理。
- 持续集成的价值在于,它是一条主线,可以将诸多实践贯穿起来。
- 做好持续集成的关键是,快速反馈。
- 重构,本质上就是一个“微操作”的实践。你需要把做的代码调整分解成若干可以单独进行的“重构”小动作,然后,一步一步完成它。
- 函数式编程已然成为时代的主流。
自动化,解决与机器打交道出现的问题
- 学习自动化,先要知道哪些东西不要自动化,尽最大的努力不做浪费时间的事。一方面,我们要从需求上规避那些没必要做的事;另一方面,我们也从自身防止 NIH 综合症(Not Invented Here Syndrome),争取做一个懒惰的程序员。
- NIH 是什么意思?就是有人特别看不上别人做的东西,非要自己做出一套来,原因只是因为那个东西不是我做的,可能存在各种问题。
- 不懂软件设计,只会被各种层出不穷的工具和框架淘汰。
- 将你的工作过程自动化。
- 有体系地学习运维知识。
- DevOps 是将开发(Development)和运维(Operations)组合在了一起。
- 持续交付,是一种让软件随时处于可以部署到生产环境的能力。让软件具备部署到生产环境的能力,这里面有两个关键点:验证发布包和部署。
- 验证发布包,不仅是功能上的验证,还包括与环境结合在一起的验证。所以,通常会用几个不同的环境验证,每一个环境都是一个单独的阶段,一个阶段不通过,是不能进入下一阶段的,这种按照不同阶段组织构建的方式,称之为构建流水线(Build Pipeline)。
- 今天定义交付,不再是一个发布包,而是一个可以部署的镜像。
- BDD(Behavior Driven Development)用业务的视角描述测试用例。
- 将验收测试自动化。
- 按照设计原则而不是设计模式重构代码,先有设计模式,再有设计模式。
- Robert Martin 提出的面向对象设计原则:SOLID,这其实是五个设计原则的缩写,分别是
- 单一职责原则(Single responsibility principle,SRP)
- 开放封闭原则(Open–closed principle,OCP)
- Liskov 替换原则(Liskov substitution principle,LSP)
- 接口隔离原则(Interface segregation principle,ISP)
- 依赖倒置原则(Dependency inversion principle,DIP)
- 把函数写短。
- 人们擅长解决的是小问题,大问题怎么办?拆小了就好。
- 分层架构,实际上,就是一种在设计上的分解。
- 构建好你的领域模型(Domain Model),指的是服务层。领域模型中一个重要的组成部分:领域对象。领域对象中不应只包含数据访问,也就是常说的 getter 和 setter,还应该有业务逻辑。
- 你的领域层只依赖于你的领域对象,第三方发过来的内容先做一次转换,转换成你的领域对象。这种做法称为防腐层。
- 领域驱动设计(Domain Driven Design,DDD)
- 领域特定语言(Domain Specific Language,DSL)
- 用简单技术解决问题,直到问题变复杂。
- 领域驱动设计(Domain Driven Design,DDD)是 Eric Evans 提出的从系统分析到软件建模的一套方法论。它要解决什么问题呢?就是将业务概念和业务规则转换成软件系统中概念和规则,从而降低或隐藏业务复杂性,使系统具有更好的扩展性,以应对复杂多变的现实业务问题。
- DDD 到底讲了什么呢?它把你的思考起点,从技术的角度拉到了业务上。
- DDD 分为战略设计(Strategic Design)和战术设计(Tactical Design)。
- 战略设计是高层设计,它帮我们将系统切分成不同的领域,并处理不同领域的关系。
- 战术设计,通常是指在一个领域内,在技术层面上如何组织好不同的领域对象。
- 学习领域驱动设计。
- 看到差距之后,我唯一能做的,就是自己下来偷偷练习。幸好,无论是快捷键也好,重构也罢,都是可以单独练习的。花上一段时间就可以提高到一定的水平。
- 入职新公司,了解的优先级是业务,技术(技术栈,技术架构,功能模块),团队运作(协作方式)。
- 了解一个项目,从大图景开始。大多数程序员习惯的工作方式,往往是从细节入手,很难建立起一个完整的图景,常常是“只见树木不见森林”,而我的方式则是从大到小、由外而内,将要了解的内容层层分解,有了大图景之后,很容易知道自己做的事情到底在整体上处于什么样的位置。
- 先尝试重构你的代码,尽可能在已有代码上做小步调整,不要走到大规模改造的路上,因为重构的成本是最低的。
- 如果你的“小模块”是一个系统,那就部署新老两套系统,在前面的流量入口做控制,逐步把流量从老系统转到新系统上去;如果“小模块”只在代码层面,那就要有一段分发的代码,根据参数将流程转到不同的代码上去,然后,根据开发的进展,逐步减少对老代码的调用,一直到完全不依赖于老代码。
- 要想代码腐化的速度不那么快,一定要在软件设计上多下功夫。一方面,建立好领域模型,另一方面,寻找行业对于系统构建的最新理解。
- 改造遗留系统,一个关键点就是,不要回到老路上。
- 只要产品还在发展,系统改造就是不可避免的。改造遗留系统,前提条件是要弄清楚现状,知道系统为什么要改造,是架构有问题,还是领域模型混乱,只有知道根因,才可能有的放矢地进行改造。
- 改造遗留系统,我给你几个建议:
- 构建测试防护网,保证新老模块功能一致;
- 分成小块,逐步替换;
- 构建好领域模型;
- 寻找行业中关于系统构建的最新理解。
- 小步改造遗留系统,不要回到老路上。
- IT 行业在国内的大发展也就最近20多年的事,行业里很少有走过完整职业生涯的程序员。也正是因为如此,我们经常会产生了各种焦虑:
- 我刚刚入行时,有人问,程序员能做到30岁吗?
- 我快30岁时,有人问,35岁还能做程序员吗?
- 我35岁时,讨论变成了40岁的程序员该怎么办。
-
有了“一专”,“多能”才是有意义的,否则,就是低水平重复,而这正是很多人职业生涯不见起色的真正原因。
-
这里的“专”不是熟练,而是深入。你可能是个有着10年丰富经验的程序员,但实际上只不过是重复了10年解决同样难度的问题而已,这根本就不算深入,也就没有做到真正意义上的“一专”。
-
当你有了“一专”,拓展“多能”,就会拥有更宽广的职业道路。比如,我拥有了深厚的技术功底,通晓怎么做软件:
- 如果还能够带着其他人一起做好,就成了技术领导者。
- 如果能够分享技术的理解,就有机会成为培训师。
- 如果能够在实战中帮助别人解决问题,就可以成为咨询师。
-
反过来,当你有了“多能”,也可以拓宽你的视野,帮你认清自己的“一专”怎样更好地发挥价值,而不是狭隘地认为自己有了技术,就已经天下尽在掌握了。视野窄,缺乏大局观,也成为了许多程序员再进一步的阻碍。
-
既然要朝着行业中的专家方向努力,那你就得知道行业中的专家是什么样。我的一个建议是,向行业中的大师学习。读这些大师写的书的一个好处在于,你的视野会打开,不会把目标放在“用别人已经打造好的工具做一个特定的需求”,虽然这可能是你的必经之路,但那只是沿途的风景,而不是目标。
-
怎么才能让自己的水平不断提高呢?找一个好问题去解决,解决了一个好的问题能够让你的水平快速得到提升。什么是好问题?就是比你当前能力略高一点的问题,比如:
- 如果你还什么都不会,那有一份编程的工作就好。
- 如果你已经能够写好普通的代码,就应该尝试去编写程序库。
- 如果实现一个具体功能都没问题了,那就去做设计,让程序有更好的组织。
- 如果你已经能完成一个普通的系统设计,那就应该去设计业务量更大的系统。
- 最内层是舒适区(Comfort Zone),置身其中会让人感觉良好,但也会因为没有挑战,成长甚微,你可以把它理解成做你最熟悉的事情。
- 最外层是恐慌区(Panic Zone),这是压力极大的地方,完全超出了你的能力范围,你在其中只会感到无比的焦虑。
- 中间的是学习区(Learning Zone),事情有难度,又刚好是你努力一下可以完成的,这才是成长最快的区域。
- IT 行业依然是一个非常有前景的行业,但想在这条路上走好,需要我们成为 “T ”型人才,也就是“一专多能”。一专多能的前提是“一专”,让自己成为某个方面的专家。这个专家要放在行业的标准去看,这才能降低因为一个公司的波动而造成的影响。
- 成为行业专家,要向行业的大师学习,给自己定下一个高的目标,然后是脚踏实地,找适合自己的问题去解决,让自己一直在学习区成长。
- 在学习区工作和成长。
- 外部系统对你来说,应该只是一个接口。
- 能模拟的就模拟,能本地的就本地。
- 关于外部系统的测试,你可以先通过接口隔离开来,然后,通过模拟服务或本地可控的方式进行测试。
- 所谓的算法优化,其实就是尽可能利用已知的信息,少做不必要的事。
- 我在这个专栏真正探讨的主题是,有效工作。
- 有效工作,需要我们把力量聚焦到正确的地方,做本质复杂度(Essential Complexity)的事情,少做无意义的事情。
- 怎么才能有效工作呢?小结一下就是:
- 拓展自己的上下文,看到真正的目标,更好地对准靶子,比如,多了解用户,才不至于做错了方向;站在公司的层面上,才知道哪个任务优先级更高;站在行业的角度,而不局限于只在公司内成为高手,等等。
- 去掉不必要的内容,减少浪费,比如,花时间分析需求,不做非必要的功能;花时间做好领域设计,别围着特定技术打转;花时间做好自动化,把精力集中在编码上,等等。
- 要想有效工作,有两点非常重要。一方面,意识上要注意自己工作中无效的部分。这就像一个开关,拨过去就好了。另一方面,要构建自己关于软件开发的知识体系,这是要花时间积累的。