--构建之法随笔,范飞龙,TL;DR,原文在知乎首发:具体而微
每年,我们家都会花很多时间在阅读上,今年也不例外。第一周我们就去图书馆把去年底借的书还掉,顺便找寻一些各自想看的书。我本来借了3本跟学习有关的书要看,但是想起年前计划过要重读《构建之法》这本软件工程的书,于是就花了两个晚上重读了一遍。写下这篇随笔记录下一些横向的思考,从理解的便利性上考虑,涉及到专业术语的地方会做适当的简要说明。
(零)目录
《构建之法》第2版共17章,我看书有一个习惯会反复去翻阅目录。把目录列出来,根据自己的理解做分类,便于按图索骥。第2版全书一共17章,涵盖了软件开发中的各个方面,这些章节在我看来是一个阶梯式的格局,概述的内容主要理清软件工程学科的内涵外延、提出一些针对全书而言是基石的模型和概念。而针对其他章节,按我的理解可以大致拆分如下:
个人部分:
2.个人技术和流程
3.软件工程师的成长
结对部分:
4.两人合作
团队部分:
5.团队和流程
6.敏捷流程
7.MSF
软件开发完整环节部分:
8.需求分析
9.项目经理
10.典型用户和场景
11.软件设计和实现
12.用户体验
13.软件测试
14.质量保证
15.稳定和发布阶段
创新和小队管理部分:
16.IT行业的创新
17.人、绩效和职业道德
后文涉及内容大都从这些章节中延伸出来。
(一)地图
我发现,重新读一遍,又再次看到许多漏掉的片段。我是一个程序员,我知道再复杂的代码,如果是自己写的,那么想要找到一处具体的细节都是相对容易的;而如果不是自己写的,读别人的代码是需要很多技巧和投入许多精力去深挖才能做到同样的了如指掌,正如市面上诸多的源码剖析书籍所展现的一样。
《构建之法》正是软件工程领域的这样一本看似复杂的书,我想书中所展现的从个人软件开发技能、结对编程到团队开发;从需求分析、用户画像、设计实现到用户体验;从测试和QA到稳定和发布;从“创新的迷思”到绩效的理性分析以至于职业道德的拆解;这些软件工程环环相扣的组合拳,作者是最熟练理解和运用的。而我们读者,则可以顺着书中所强调的做中学的理念在阅读、思考和实践中去做深入的挖掘。而基本目标,从狭义上来说,正如书中开篇所提,理解和掌握软件工程的知识和方法,并做出有实际用户的软件,通过文档和代码展示了软件的可持续开发的价值。这是一个具体明确的小目标,看上去似乎并不大,但这正是重要的,如果我们能把第一个小目标做好,再迭代100次,可能比我们做了100次雷同的事情结果要好。
软件开发中存在各种隐喻,例如《程序员修炼之道--从小工到专家》这本书,就提到各种隐喻。有:“提供选择,不要找各种蹩脚的借口”,“不要容忍破窗户”(破窗效应),“做变化的催化剂”...等等,这样的书籍有利于我们在欣赏隐喻的过程中提高我们的段位,然而我们人是容易忘记的,100个隐喻我们能记住3条常用的并运用到极致就非常不错了,缺失的地方在哪里呢?我们也读过《重构--改善既有代码的设计》,也认真阅读和实践《Clean Code》的理念,设计模式从套路的学习到抛弃,编码规范的排斥到遵守到入乡随俗,语言书籍从Primer,到Advance到The Good Parts。这些,都是重要的组成部分,然而它们远不是全部。
我们要看到大地图!看到大地图是一个正常的逻辑,但又不正常。程序员有时会过于陷入细节而太Geek,我们的成长经历就是不断地在自己的细节迷思与大地图需求之间博弈的过程。这一切的根源,在于: 软件=程序+软件工程,我是在构建之法这本书里第一次明确地看到这样一个公式,这是重要的,我们有了一个地图。而更大的地图是:软件公司=软件+商业模式,也在这本书里第一次看到。理解了大地图,可以把那些碎片的部分放在合适的位置,例如哪些是软件工程师个人成长的部分?哪些是与人协作的部分?哪些是与团队协作的部分?哪些强调了技术制胜的策略,哪些又强调了流程的必要,哪些强调了人剑合一的高效,哪些又说明了分工的必然和规律性。确实,许多时候一个人手里有一把锤子,看什么都是钉子,而这并没错,只是我们不断地在寻找更合适的锤子而已。当然,有的高手不强调全面,只强调特色锤子。只是,我们看到的时候要理解那不并不是全部,甚至只是一小点。
小节注释:
“迷思”一词起源于希腊语单词μθο(mythos),是英语单词Myth的音译,又意译为神话、幻想、故事、虚构的人或事,指通过口口相传流传于世的十分古老的传说和故事,泛指人类无法以科学方法验证的领域或现象,强调其非科学、属幻想的,无法结合现实的主观价值,《构建之法》第16章:IT行业里的创新 第一节讨论创新的迷思。
(二)说理
有一辆火车行驶在苏格兰的土地上。上面有一个天文学家,一个物理学家。当然还有一个数学家。这时,天文学家突然看到苏格兰的草地上有一只黑羊在吃草。他大叫:看呀,苏格兰的羊是黑的!物理学家说,“不对,你应该说,在苏格兰,有一只黑色的羊”。这时,数学家笑了笑说,“你们这么说都不合适。应该说:在苏格兰,至少存在这么一只羊,它的一侧是黑色的”。这个故事说的是逻辑。
为什么我要提到逻辑呢?因为从工作开始,我们就开始了与队友协作,在团队中协作,在软件开发工作中,同时伴随的就是对于小组、团队、组织、流程、产品、开发、测试等等的各种迷思。有时候,我们会听到一些似是而非的关于个人在这些不同群组、不同流程里的定位的观点和看法,例如常见的开发和产品、开发和测试、个人与团队的各种矛盾的关系,还有诸如“我有一个想法,就差一个程序员”,“你这是事后诸葛亮,马后炮”等等,网络上也常见各路高手从一个角度写的文章,大家都在强调自己认可的那方面理念,有的人几十年如一日专注于编程语言,有的人一路偏好通过程序解决问题,有的人反复尝试各种产品套路,有的人强调精英在高效团队中的作用,有的人强调良好战术的重要,有的人认为年龄是技术的制约,有的人则认为年龄代表技术的沉淀,而路人粉丝们总是冲到下面一路点赞或者反对。
好的方法一定是符合逻辑的,这是我看过王鼎钧《讲理》这本书的感受。讲理,学习的不只是写论说文的各个侧面,更是学习如何看别人的文章的文法,一个文章,立了是非标题,我们就要它给出靠谱的证据,如果有好的故事,可以感受故事的吸引力和比喻之妙,但也要明白故事毕竟只是故事,并不是证据,所谓充分不必要。如果用了诗句和子曰,我们就要问权威是否真的说过以及权威是否过时了。如果有反问,我们也要判断反问的主体是事实还是判断,区分事实和判断,我们才能做情绪的主人。如果有倒彩,看其是否轻薄,毕竟倒彩也是充分非必要。欣赏是非标题下的写景,明知它是铺垫和吸引,如此才能正经欣赏文字的同时不失理性。
而《构建之法》这本书在讲理方面很合逻辑。首先,在很多环节里,作者都注重集合的使用,例如,在讨论“两人合作”的时候,对评论人的层次的分类:{行为和后果,习惯和动机,本质和固有属性};在“需求分析”里对需求做分类:{必要需求,辅助需求},对功能分类:{杀手功能,外围功能};在“人、绩效和职业道德”里分析团队成员在做事方面投入的分类:P={P1:做事的,P2:不做事的,P3:不让别人做事的,P4:做假事的,P5:假装做事的};在“软件设计与实现”中“开发阶段的日常管理”里对BUG的分类:{已修复的BUG,不能重现的BUG,这个产品就是这样设计的不是BUG,不是BUG没有能力修复将来也不打算修复,这个BUG的确应该修复但是没有资源在这个版本修复推到下一个版本}...,我们看到在软件工程中处处体现着分类的作用。
在分类之后,可以使用优先级排序,例如对任务的优先级,可以使用坐标分析法等等,这就给软件工程上处理人与人、处理流程带来了理性分析的地方。例如我们对功能和需求两个维度建立四象坐标系之后,我们可以针对不同的象限采取不同的策略;再比如根据任务的{重要,不重要}和{紧急,不紧急}两种维度,我们可以有节奏有先后做事。此外,作者设计了许多独特的情景对话,通过虚拟软件公司的人物对话之间的断言、质疑、释疑,将方法和知识徐徐展开。这需要读者对应地慢读,因为慢读之下,我们会发现对话的逻辑性,而一旦逻辑的主线出来,实践上应该怎样更合理,便自然分明。
(三)招数
"The difference between theory and practice tends to be very small in theory, but in practice it is very large indeed. " -- Anonymous
我们在实际工作中由于分工的原因,以及每个具体工作所需卷入精力的原因,许多工程师会觉的自己所做的工作是单一,具体和明确的,并不需要那么多复杂的框框条条。正如许多人看过软件工程的理论,常见的感想是:“这些不错,但是离我的工作好像有点远”。另外一种类型是一些高手说:“这些都是套路,我们并不希望把日常工作的流程搞成这样”。这也是一个常见的迷思,即有效的流程是必要的,但流于形式和无效率的流程则是一种对人和事的不必要约束。
实际上我能理解这两种回复的合理性。一方面,在许多公司里程序员的分工是必要的,有时我们会几个月甚至一两年专注于特定领域的程序开发工作。小公司和大公司对开发周期的需求也不同,几个人的团队和几十人的团队也不同。有的人会认为那些全局性的工程方法不是我的事情。另一方面,许多高手都是经验主义的精英。经验与直觉足以让他们有自己的一套方式和方法去构建。
正如那个“苏格兰草地上的一侧黑羊”。软件开发的团队模式有不同的模式,正如书中“团队与流程”一章对软件开发团队模式的分类,有主治医师模式,有明星模式,甚至有交响乐模式,还有新手的一窝蜂模式等等,成员的素质高低会导致各种模式都有成功或失败的可能性。成功了,就会形成一种经验主义和选择偏好。而,任何一种偏好,都是一种偏见。因此,会有许多人排斥流程、排斥分工、排斥管理,而选择交由高素质成员的自发组织、自发协作、自发管理以及通过洞察力得到的设计来取得过程的成功。
我在这点上也思考了许多。软件工程的许多方法形式在逻辑上并不明显具有充分必要性,否则,只要大家照着这种形式去做,岂非一定能够成功?项目的成功,在构建之法1.2节讨论不同类型项目时有不同的定义,但殊途同归,最重要的是“Build To Win:以在市场上赢得用户为目标而构建的软件”。但这个问题在所有强调方法的地方都会适用,例如在火热的育儿界,我们有什么方法是万能的吗?没有。软件工程界更是如此,《人月神话》这本讲述IBM公司System 360家族和OS 360中项目管理经验的书中,作者Brooks提出了“没有银弹”这个概念,这也被许多软件工程师经常挂在嘴边,所谓的没有银弹是指没有任何一项技术或方法可以能让软件工程的生产力在十年内提高十倍。
但没有银弹并不是说那些方法毫无用处,没有银弹在我理解指代的是每个方法和技术都有其局限,每个方法都有其适用的假设条件。在理解了方法的下限之后,我们再针对一个一个具体环节,一个一个具体方法功能上的讨论、理解和使用,这是具体和重要的。而这也是工程角度擅长的,我们希望解决问题,那就要有可操作的解决问题的招数。有招数至少比一窝蜂模式强,有效利用招数又比流于形式的招数强,理解招数的内涵则是拾级而上的进阶。《构建之法》正是在那些看似技止于尔的地方,针对环节和招数的上限和下限做了足够好的分析、说理、比喻、举例、聚焦和发散。单一的方法和工具有上限和下限,从而我们更需要有章法的去做好组合,让方法、工具、人在约束条件下达到最优,为构建赢得市场的软件服务,而这些都是具体而微小的。
形式做的爽了,有可能会流于形式。这就切中了另一个重要的问题,招数是为解决问题服务的,而解决问题的核心是人。所以,前提是人的动机是有效解决问题,做出好的东西。理解这点,可以重点阅读MSF(Microsoft Solution Framework)这一章,MSF有一个9点的基本原则,其中我最喜欢的有:
● 为共同的远景而工作
● 充分授权和信任
● 各司其职,为项目共同负责
为什么单独挑出这三点呢?因为这和此处讨论的形式有关。形式是死的,人是活的。当人的主观意愿是为了解决问题,人去理解形式的优缺点,能做到扬长避短,让形式发挥其适当的作用,那么形式就和内涵是契合的,此时我认为是最佳的。反之,如果形式和内涵相违背,那么,形式的作用会打折扣,或者起的是负面作用。
招数的使用上,也有新手和老手之分,这就需要反复的练习,也就是唯手熟尔。还有一个重要的点在于善于使用工具。例如,下面这些招数都属于需要反复练习的:
● 做需求分析和立项的NABCD(Need,Approach,Benefit,Competitors,Delivery)。
● 做任务分解的WSB(Work Structural BreakDown),配合思维导图。
● 做尸体解剖的事后诸葛亮分析(Postmortem),马后炮其实是有用的。
(四)增量
先定一个小目标,设置一个里程碑,然后持续迭代,在里程碑结束后进入下一个里程碑。构建之法书中体现了这个重要的过程,特别是“敏捷流程”的内涵。年初和年末的时候,我们常常会看到很多人为自己设定了很长的todo list(当然更多的人是走一步看一步的随缘流派),而往往许多todo list最后变成了undo list。究其原因,一个重要的原因在于目标定的不具体,或者说不符合SMART原则,因此会不敢下手。这是说个人,而在团队上,则会体现在里程碑周期的控制失效上。
越是大的目标,越容易做不到,越是长的周期越容易延期和失控。这也是所谓保持敏捷,预期和适应变化。通过设置可操作性强的小目标,通过设置短周期的里程碑。我们可以上来就上手做,短平快的要么成功要么失败。成功我们就有更多的信心增量改进,失败则给出必要的改进反馈。
增量的一个前提是完整执行大地图上的所有环节,每个环节都要做到位。具体环节如果不做到位,那么它的质量就下降,环节的质量下降,会导致整体质量的下降,到最后事后诸葛亮分析起来,有的人会说是形式和流程害了他们。回顾下公式:软件的质量=程序的质量+软件工程的质量。
构建之法的章节布局是按个人、结对、团队(团队的内部由通过介绍瀑布、讨论敏捷,到MSF的柔和)的模式来的,环节大致是按软件开发的生命周期。这个线性模式本身似乎是显然的,但我观察有许多人实际上并没有有效建立起这种增量的模式。比如可能在个人上投入太多,或者因为结对的不显性而忽略之,又或者在团队上只是粗糙使用瀑布或者不重视敏捷的内涵。我想把理论消化掉的过程,都属于构建之法开篇提到的大马哈鱼巡回游的模型,这个模型用来比喻软件工程师进入软件公司从改BUG、维护一些小模块…,绕了一圈到成为骨干后才能独立设计新项目的过程,事实上我们从事任何一项行业,都有这种类似的过程。
小节注释:
Alpha:指集成了主要功能的第一个试用版本。在这个版本中有些小功能并未实现。事实上很多软件的Alpha版本只是在内部使用。
Beta:功能基本完备,稳定性较Alpha版本高,用户可以有Beta1,Beta2,Beta3…
--《构建之法》第15章“稳定和发布阶段”
(五)检查
《构建之法》有单独的两章分别介绍“瀑布模式”和“敏捷流程”(Agile),其中瀑布模式狭义上指按部就班执行需求分析、设计、实现、测试、发布的流程,瀑布模型衍生出了一些变种模型,例如让相邻两个环节更加紧密的“生鱼片模型”。
而敏捷流程强调短周期的里程碑,每个里程碑开始都把要解决的问题拆分成一个个卡片,一个里程碑叫做一个敏捷冲刺过程。形式上,每日会有一个站立会议简单碰一下前一天完成的任务,遇到的问题以及当天要做的事情等,完成任务和解决问题中的重要步骤要及时有序小结。在敏捷冲刺期间,组队的(叫做敏捷大师)要适当拒绝不在计划内的任务,保证本次队列的完成度。在里程碑开始的时候,以图形化的方式展现了剩余的工作量(y轴)与时间(x轴)的关系,形成一个工作量随着时间消逝的“燃尽图”曲线,而在实际开发过程中记录真实的完成情况,实际的曲线和预期的曲线之间的差距即可以衡量估计的准确度,也可以衡量整体的进度。
构建之法里也提到戴明环,或者叫PDCA循环,又叫质量环,是管理学中的一个通用模型,最早由休哈特于1930年构想,后来被美国质量管理专家戴明博士在1950年再度挖掘出来,PDCA是英语单词Plan(计划)、Do(执行)、Check(检查)和Action(纠正)的第一个字母的缩写。
这三种模式都强调检查的作用。有时和一些中小学老师交流,意识到在软件开发中貌似新鲜的所谓单元测试,其实我们从小到大在学校里的考试都是这样做的,从每周的单元测试到期中期末的里程碑测试。有效的知识学习和使用,都伴随着测试的过程。而结果也是明显的,并非每个走过这套流程的效果都一样。究其原因,还是质量。
以中学生为例,一次单元测试,大部分人只看结果加上老师的讲解了事,在这个过程中,存在的一种现象是对已经做对的不再重视,而对做错的只是了解下表面原因就丢弃。这样实在可惜,那么应该需要的是什么呢?复审。有效的学习也总是伴随着复审,通过复审,我们深入去理解测试所表征出来的问题背后的原因,把可重复操作的1,2,3步骤写下来。软件工程理论上也是重视复审的,但实际上我们总是好了伤疤忘了疼。说到这里,我所理解的构建之法里体现出的那种强调具体的事情要做到位的意识,是值得重视的。实际上,复审是一个再普通不过的方法,但人是惰性的,我们在生活、工作中有太多时候随随便便就放弃了改进的机会,只因为我们随随便便做了复审,比如说团队的Leader认真写了复审的邮件,但成员可能只是收过来回复已阅,并未付出同等深入的思考。
回到软件工程,短周期的里程碑结束,我们需要具体科学地去做事后诸葛亮分析,并在下一个里程碑里跟踪增量改进。有检查和没检查是两个效果,这需要协作者在意识上重视并参与,参与就表征这事我有份,我检查了它并改进了它,是构建者而不仅仅是阅读者。
(六)延迟
我们几乎总是估计失败。但我们还是要估计,让粗略估计逐渐变的准确。所有写过迭代算法的人,应该对预估-矫正的做法不陌生。在个人软件开发中使用PSP(Personal software process)对分析、设计、实现、测试的时间做估计并事后统计;在团队开发中PM(Project Manager, Product Manager 或者 Programmer Manager)对各种风险做分类估计并采用分类应对策略。这都需要反复的通过预估-矫正机制去锻炼我们的粗略估计能力,这样我们才能更好的拥抱敏捷,预期变化(不是期望)。
正如构建之法写到的:
“一个成熟的软件工程师应该能够降低任务交付时间的标准方差。如果你能长时间稳定而按时地交付工作的结果,内部和外部的顾客就会对你的工作有信心,更喜欢与你合作。”
构建之法里还提到了一个估计时间的经验公式:
实际时间花费主要取决于两个因素,对某件事的估计时间X,以及他做过类似开发工作的次数N,则实际耗时大概是:Y=X±X÷N
有敏锐意识的工程师,应该对延迟敏感,捕捉软件开发中的关键延迟点,并采取有效手段规避。然而这并非易事,一个人在某件事情上很有经验,估计比较准确,当他去做另一件事的时候,并不能轻易地迁移在之前那件事上的经验,从而达到同样的估计准确度。迁移并非不可能,如果上面的估计公式是有效的,我们可以反复在做一件新事情时尝试利用已有的经验去估计和逼近,当N足够多的时候,Y就会足够准确。问题是,我们是否有足够的自律去训练自己的估计能力?
(七)版本
源代码需要版本化管理。构建之法强调做中学,在软件开发过程中,一个最直接的工具就是版本管理工具。时下最流行的版本管理工具就是git,在git的使用上,有各种工具可以选择,有的人选择纯命令行工具,有的人选择各种平台上的GUI工具。到底哪种更好呢?我想用构建之法里的一段话来表达我的看法:
“那怎么提高技能呢?答案很简单,通过不断的练习,把那些低层次的问题都解决了,变成不用经过大脑的自动操作,然后才有时间和脑力来解决较高层次的问题。”
版本管理工具是软件工程师日常开发天天使用的,工程师要做到日常开发的添加、提交、同步、以及项目版本上的分支管理和维护。一个流畅开发的团队应该把它作为一个低层次问题,通过练习达到不用经过大脑的自动操作,这样团队才会聚焦在较高层次的任务达成和问题解决上。
当然,任何事情都有一定的代价,也并非任何一个看似“低层”的问题都是人人都能做到熟练的。这又体现了我们要从小的事情做起,通过一个又一个小问题的解决,从而在整体上拉开好坏优劣的差距的必要。有时候,道理是明显的,差别还只是在行动上。
工具提供的灵活性,有时候是一把双刃剑。例如像Git这样的版本工具,在分支管理策略选择上的不同有时就会对团队开发的效率产生不同的影响。
例如常见的Github 协作工作流:Understanding the GitHub Flow,
以及常见的Git工作流:A successful Git branching model
而在Software Enginerring At Google这篇文章中,我们会看到Google的工程师倾向于选择尽量减少分支来规避潜在的合并问题:
“Almost all development occurs at the “head” of the repository , not on branches. This helps identify integration problems early and minimizes the amount of merging work needed. It also makes it much easier and faster to push out security fixes.”
版本管理里面还有一个常见的问题是,多久提交一次,什么时候提交,对于这个问题,下面的这篇文章光看标题就能给人启发:
Commit Often, Perfect Later, Publish Once: Git Best Practices
构建之法里有一个魔方的故事,具体的故事细节此处不展开,可以看这里:技能的反面-魔方和模仿。通过魔方的故事,我们可以看到围绕玩魔方和卖魔方这件事上,就有不同的进阶版本,我想软件工程技能与内涵的学习和理解上,也存在不同的版本。
(八)平衡
Keep Balance! 这又是一个说起来容易,做起来需要技巧的事情。事物总是非线性的,但我们思考的时候却总是容易幼稚地以线性的眼光去看待。最简单的非线性模型,我认为是这样一个公式:Y=X*(1-X)。我们要求得这样一个公式的极值点,需要的是寻找X的最佳平衡点。放在软件工程里,取代线性思考方式的,是这样的一些事情:
例如,一个团队建立,团队成员和团队Leader之间就有这样一种双向视角:
● 如果你是组员,你是否在理解自身职责的基础上理解Leader的职责
● 如果你是Leader,你是否在理解自身职责的基础上理解组员的职责
例如,团队确立共同的目标,建立充分授权和信任的意识,同样存在双向视角:
● 如果你是组员,你理解团队的目标和个人的目标之间的差异么,怎样取得共识?
● 如果你是组长,你理解团队的目标和每个组员目标之间的差异么,怎样最大化共识?
● 如果你是组员,你会在理解了共识的基础上和组长及其他组员充分信任么?
● 如果你是组长,你会在理解了共识的基础上和每个组员建立充分信任么?
● 如果你是组长,你理解每个人内心真正的意愿并充分授权和分解任务么?
例如,在考虑绩效的时候,不同的人理解的不同:
● 如果你是组员,你理解贡献分平均分配和非平均分配的区别么?绩效的目的是什么?
● 如果你是组长,你理解贡献分平均分配和非平均分配的区别么?绩效的目的是什么?
例如,在做一个涉及他人的改动时,不同权责需要采用不同的模式:
● 请求模式:你好,我能改动这个么?
● 通知模式:xxx,我改了这个,你要更新下。
每个人的精力都是有限的,当我们把精力投入在一个方面,必然会在另一个方面吃紧。《构建之法》里有一个对成员在团队里投入程度不同的刻画:猪、鸡和鹦鹉
“一个人可以同时做很多事, 这些事情对每个人的轻重缓急各不相同, 有些事情只能业余帮一些忙, 这无可厚非。 加入一个团队时要弄清楚自己在团队中投入的级别是什么, 别人的期望值是什么. 不要拿着卖白菜的钱, 操那卖白粉的心 - 太不值得。 人可以在 n 个地方做鸡, 或者 n*m 个地方做鹦鹉, 但不可能在两个地方同时做猪, 这太难了!”
在管理学里面有一个典型的模型是唐僧师徒四人,每个人也都代表不同投入、技能、贡献度的角色,常常会提的一个问题是:如果徒弟三人只留一个人,你会留谁?当然这是极度简化的模型,事实上每个角色都会有不只一个人。
在角色之间,常常会有情绪卷入问题。特别是一个角色在做一件事的过程中,被需要修复的BUG、紧急添加的Feature、临时乱入的会议等等打断的时候,被打断往往会导致情绪上的对抗,内在的原因可能是预期的结果和实际结果不一致导致的,这也是需要平衡的地方。
对于个人来说,平衡自己在不同角色上的付出,同时理解其他角色的付出,调度自己的多角色,在许多时候需要良好的角色管理意识。
(九)规模
计算机的一大类问题就是输入输出问题,根据能处理的输入数据的规模大小,程序设计和实现会有不同的策略。是否一开始就要考虑规模比较大的数据处理?未必。从能处理小规模数据的程序开始迭代,在迭代中让程序逐步能解决和处理更大规模的数据。这是一个开发策略上的伸缩性问题。
在软件的功能设计中,也会有伸缩性问题:
● 基本功能
● 扩展功能
● 高级功能
而在软件工程师个人的成长方面,也有伸缩性问题,软件工程师在成长中一开始会投入很大心力在程序这一端,例如编程语言的学习,算法的学习,设计模式的学习,抽象和复用方面的学习,调试能力的学习,构架的学习。进而在成长中会考虑与单人协作的方式,与多人协作的方式。在任务数上会从同时处理一件事到同时处理N件事。这个过程中,逐渐必须解新的问题:问题规模变大了,原来的处理方式是否还能流畅运行?有的时候会遇见各种危机,每次危机都同时是一次机遇。
同样在Google 工程师写的这篇文章:Software Enginerring At Google 里,Google工程师在Code Review这件事上的做法包括: 一个模块由至少2-3个人共同负责,模块代码改动后会发给模块拥有者或者非模块拥有者做Code Review,每个人也可以主动去给别人的模块做Code Review。那么一个显然的问题是如果Code Review做的很慢,岂不是整体进度会被减缓?此处文章里推荐的做法是简单的小的改动可以发给相对较少的能力要求不是那么高的成员,复杂的大的改动则可以发给经验丰富的效率高的成员做Review,也或者你可以同时发给N个人,只要有些人比较快的回复review即可,…,方法是很多的,比较特别的是这里体现出的对问题规模变动引起的复杂性的认识和应对策略。
在问题的输入规模变大(输入有可能是需求)的时候,问题开始变的繁杂,所以我们需要适应繁杂问题的工程方法。如果把问题的规模变大作为一种变化,我们就应该预期规模的变大,在需求分析、构架设计、实现上及时响应可能的变化。
(十)尾巴
许多年前,我就听到一种说法:“完整的看完一本书比看了10本没都没看完重要”,这让我想起了最后一里路的问题。工程师常常在完成“80%”之后,就放松下来,以为完成了一切。而实际上最后20%的事情要做完整,有时在时间上要耗去整体的80%。最后的20%这个尾巴的部分,体现的是后劲、耐力以及对事物完整性的认识。
但是,另外一种观点是:只有20%是重要的,其他80%都不是重点。也就是俗称的二八原则。二八原则在挑重点方面是重要的,在工具的使用中也是重要的。如果你是用户,你会优先关注那20%最重要的部分。但是,如果你是个构建者,也许最核心的设计就20%,但是要把软件完整迭代出来,则需要关注那80%在设计上也许不是核心,但在实现上是必要的部分上。《构建之法》强调一个重要的目标:做有人用的软件,比如从10个真实的用户开始。从这10个真实用户里通过洞察和科学分析提取出真实需求,通过有效的设计解决用户的痛点,比别人家做的更好或者颠覆别人家,把足够好的软件做出来,并递到真实用户手里。在这样一个过程中,去关注每个环节的尾巴部分,把被忽视的20%尾巴做到位,这是竞争力的一部分,有时,也会是创新的一种路径。
许多软件工程的学生,在实践做中学的过程中,就会在这点上做的不足,这可能是由于学生项目带有“作业截止日期”到了就完了的原因。但“软件开发不是闭卷考”,真实的软件开发,关注那20%的尾巴,每个环节的尾巴收集起来,做完整,是重要的一环。
(N)实践
理解对于我们每个人而言和爱一样重要。这不是一件可以指派给别人做的事。我们不会让风流浪子替我们去爱。也不要让科学家替我们去理解。--阿贝尔·雅卡尔,《科学之险》,1985
一种错误想法是认为学习者可以自行组织自己的理解。表面上看,传递模式体现了那句著名谚语中的智慧:“在打铁中成为铁匠。”实际上,学习者并没有真的在“打铁”,大多数时候,他是看着老师打造一个部件,他所接收的是已经打造好的东西,这个东西对他的用处以后才会体现出来,甚至永远不会体现出来。描述想法、解决矛盾,进行所有这些有意义炼制活动的是老师而不是学习者。老师在备课过程中把他认为过难的只是砍掉,把能够证明他所要传达的信息的论据收集起来,从而完成意义的炼制。他为了促进学习者的学习,在无意中让学习者失去了学习中最具有教学意义的方面之一。《学习的本质》P18
《社会心理学精要》这本书里谈到人在社会中,基于个体内在和外在,个体私下和公开;个体为中心还是群体为中心,内群和外群;个体的积极和消极、刷脸与被刷脸,等等这些方面都存在着复杂的多还少补式的调节与反馈作用,核心目标是维护个体的自尊、安全、稳定可预期的社会自我定位。
我们掌握工程的方法要通过在实践中设定优化目标,在反复的实践中消化和建构知识、方法。特别是软件工程这样一门实践性很强的学科。实践有两种:一种是在工作环境中反复运用所学,另一种是将自己所掌握和理解的知识和方法用以分析别人的案例。
这两种方式我都有实践。第一种自然不用说,在工作中我会逐渐去对比自己所在环境下对应那些概念、逻辑的日常事件。这是一个过程性的体验,将虚化的名词、概念跟日常工作的小事件建立连接、印证、改进是做中学的一种方式。第二种,我在过去两年里实际的参与过《构建之法》线上线下结合的教学里的线上助教/评论环节。实际上有更多的工程师在业余时间做这件事。这种方式中,通过参与大量学生软件工程教学环节的评论,评分和建议分析,我们不但巩固自身的知识和方法,也让学校的学生和比他们水平高(也有可能反过来)的经验丰富的软件工程师之间建立一种近距离互动式学习环境,教师也在这个过程中协作推动课程设计的立体化。
回到主题,掌握和理解原理,在自己的领地里运用软件工程的知识和方法做出一流的软件,持续去优化这个目标。当然,你的产品未必是软件。