• 在软件开发的各种书籍和资料中,也应当有类似美国独立时的《常识》的文本来告诉大家,道理原来是这样的。

  • 托马斯*潘恩的《常识》:北美应该独立,且不需要国王。

  • 本书:应当重视软件的维护成本,追求简单清晰的设计

前言:

  • 好程序员和差程序员的区别在于理解能力。

  • 本书帮助各位程序员,以适用于各种编程语言,各种项目的广阔视角来理解软件开发。软件开发的科学规律,说明为什么有些开发方法有效,另一些无效。

  • 这些规则也会指引你在日常工作中做出开发决策,帮助你的团队进行高质量的交流,最终制定出合理的计划。

  • 帮助你深入理解软件工程师某些行为的原因。

引言:

  • 微软的Windows2000还在开发时,有史以来规模最大的软件,包含3000W行代码,2亿字,是不列颠百科全书字数的5倍

  • 程序是抽象的,非常难处理

  • 编程把复杂问题化解为简单问题的劳动,否则,达到某种复杂程度,没人理解。

  • 程序中复杂的部分必须以某种简单方式组织起来,这样,不需要神那样强大的思维。

  • 这就是编程所要用到的艺术和才能--化繁为简。

  • 能跑通,符合老板,客户需求就好。

  • 其他程序员继续添加复杂性

  • 喷气式飞机差不多也有这么复杂,但造价不同,百万--几十亿美元,而软件50-100美元,没有人有足够的时间和资源,在几乎无限复杂的系统里找到所有的问题。

  • 有时,大量的代码也可以带来简单,只不过增加了阅读和编写的工作量而已。提供了化解复杂性所必须的简短注释。

  • 先进的技术只会让事情更简单,只是一开始你得学习,所以整个过程没那么简单。

程序究竟是什么?

1)给计算机的一系列指令

2)计算机依据指令进行的操作

  • 第一种定义是程序员写程序时所用的

  • 第二种是使用程序的普通用户所用的

  • 程序员面对的是字母和符号,用户看到的是最终结果--计算机执行的操作。

  • 所以,计算机程序其实是这两者的混合体:程序员的指令,计算机执行的操作。

  • 除软件开发之外,没有任何领域的指令和结果联系得这么紧密。比如设计房子,建筑师给出指令,也就是蓝图。经过很多人的手,很长时间,才执行,才建起房子。房子是大家所有人解读建筑师指令的结果。

  • 相反,写程序时,计算机绝对服从命令,没有其他人,结果的质量完全取决于机器的质量,我们想法的质量,代码的质量。三个因素当中,代码的质量是软件工程要面对的重要问题。大多数内容在讨论怎样改善你交给机器的指令的结构和质量。

  • 为了改进结果,提高代码质量是最重要的问题,需要掌握提高代码质量的科学方法。

缺失的科学:

  • 为某种创造性活动而制订,但尚未实施的计划。例句:确定了桥梁的设计

  • 业已存在的创造物所遵循的计划,如:那座桥的设计相当不错

  • 程序代码结构

  • 速度重要,容易阅读重要

  • 为满足需求,选择哪种编程语言

  • 公司的机构怎样

  • 什么时候召开团队会议

  • 程序员工作时间如何安排

  • 程序员绩效如何考核

  • 这些决策与软件本身无关,只与组织有关。有些失败是由于管理。但不是本书主题,本书关注的是,如何为你的软件制订合理的技术决策。

  • 与架构有关的技术决策,以及开发系统中的技术决策,都可以归到“软件设计”的范畴里

  • 什么是设计?

  • 动词:为创造性活动制订计划。比如,工程师本月会设计一座桥梁,下个月建造它。

  • 名词:

  • 动词时,计划活动,关心的事,代码结构,所用技术,制订技术决策,通常我们只是在脑子里做这些决定,有时候会把它写下来或画出来。

  • 上一步的结果是软件的设计,名词,可能是落实下来的文档,也可能是我们脑中的若干决定。

  • 已经存在的设计,它的结构,或它所遵循的计划。无设计的,完整的设计,之间存在着广阔的灰色地带,比如部分的设计,若干矛盾的设计,接近完成的设计等等。一些刻意而为的糟糕设计甚至比无设计还要差劲。

  • 软件设计的科学就是为软件做计划,制定决策的科学,这些决定:

  • 与下列问题无关:

程序员也是设计师:

  • 在软件项目中,首席程序员负责设计程序的总体架构;高级程序员负责大的模块;普通程序员设计自己的那一小块,甚至只是某个文件的一部分。一行代码,也包含设计的因素。

  • 身为设计师,必须时时愿意聆听建议和反馈。但是考虑了所有这些后,任何决策都必须由单独的个人而不是一群人来做出。

  • 如果你是推翻决策的那个人,要教育别人。为什么新决策比原来好。让他们学习,如果从来也不学习,还是做出成堆的糟糕决策,这种人应该清理出团队。

软件设计的科学:

  • 科学必须包含汇总而来的知识。必须包含事实而不是意见,且这些事实必须汇总起来。比如集结成书。

  • 这些知识必须具有某种结构。知识必须能分类,其中的各个部分必须能够依据重要性之类的指标,妥善建立起与其他部分的联系。

  • 科学必须包含一般性的事实或者基本的规则。

  • 科学必须告诉你在现实世界中如何做一些事情。它必须能够应用到工作或生活中。

  • 通常,科学是经由科学方法来发现或证明的。科学方法必须观察现实世界,提炼出关于现实世界的理论,通过验证理论,而且这些实验必须是可重复的。这样才能说明理论是普适的真理,而不仅仅是巧合或者特例。

  • 一门学问要成为科学,必须符合下列标准:

  • 软件领域,已经有了知识,有了结构,但忽略了最重要的部分:清楚表述出来的规则law。规则是恒常不变的事实,一旦掌握了它们,人就不会犯错。

  • 不但要知道怎么做是正确的,而是为什么这么做,判断正确和错误的标准在哪里。

软件设计的基础规则是什么?

  • 书中列出了关于软件开发的若干定义,事实,规则,定律,它们的着眼点大多在于软件设计。Definition,Fact,Rule,Law区别?

  • Definition定义告诉你事物是什么,应当如何使用。

  • 事实是关于事物的真实陈述。每一点真实的信息都是事实。

  • 条例是给你的确切建议,它包含某些具体的信息,用于制定决策。但是,条例并不能帮你绝对地预测未来,也不能帮你发现其他真理。它们通常会告诉你是否需要采取某些行动。

  • 规则是永远为真的事实,它涵盖了很多领域的知识。它们帮你发现其他重要的真理,帮你预测未来要发生的事情。

  • 若是你以为你这些都知道了,你这么想的时候应该问问自己:

  • 我是否知道,某些特定的说法是否经过了证实

  • 我是否清楚它的重要性

  • 我是否可以向其他人清楚讲解,让对方彻底明白

  • 我是否明白,在软件开发领域中,它与其他部分知识的关系如何

  • 区分某些说法到底是科学,或者仅仅是想法的集合。

  • 软件设计可以成为科学。咨询顾问要把软件设计新方法拿出去换钱。

  • 软件设计是有章(规则)可循的,它们可以被认识,可以被理解。规则是永恒不变的,是基本的事实,而且确实可行。

  • 检验这些规则,能否想到关于软件开发的,使用范围更广或者更基础,更深入的普适真理。真实基本的定律或规则。

之前为什么不存在软件设计科学?

  • 今天计算机来源于数学家的设计,它最初纯粹是一种抽象的设备,数学家想用机器来代替人脑来解决数学问题。计算机科学正是对信息处理所做的数学研究。

  • 不过,最早计算机是有计算机科学家指挥下,由经验丰富的电子工程师制造出来的。

  • @人月神话:项目延迟的情况下,增加更多的程序员,只能加剧延迟。对编程及软件开发管理的观察相当有价值。

  • 之后涌现出了大量的软件开发方法:Rational统一过程,能力成熟度模型,敏捷软件开发,等等。它们是管理软件开发复杂性的手段,无一标榜自己是科学。

  • 现状:方法众多,真正的科学却缺席。

  • 软件管理的科学告诉我们的是,如何为程序员分派工作,如何制定发布计划,如何估量任务所需的时间,诸如此类。这是一门显学,上述的各种方法强调的正是这一点。在这个领域中,存在着彼此矛盾却各有道理的观点,这说明软件管理的基本规律尚未被认识。不过,大家已经关注到了这个问题。

  • 但软件设计的科学在现实的编程中,却没有什么人关注。动手写代码吧!

  • 本书要讲的并不是计算机科学,那属于数学研究。本书提供的是“实际干活的程序员”所需科学的入门部分---在任何语言中编写程序时都应当遵循的若干基础定律和规则。这种科学与物理和化学一样可靠,它告诉你如何编写程序。

  • 软件设计的变化太逗了,无法用简单,基础的规则来描述,这是一种说法。还有人说,理解物理世界是不可能的,因为世界是神创造的,但神是不可知的。可是我们确实已经发现了物理世界的规律。

  • 所以,除非你相信计算机是不可知的,否则,软件设计的科学是必然会存在的。

  • 也有人说,编程纯粹是一门艺术,服从于程序员的个人爱好。这么说有点道理,在科学应用的任何领域,都存在着不少艺术的成分,但是他们背后必然有科学存在。只可惜,一片空白。

  • 其实,软件复杂性的主要根源在于缺乏科学。如果程序员有科学指导,知道该如何开发简单的软件,就不会有这么多的复杂性问题,也不需要运用令人发狂的过程来管理这些复杂性。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

$软件设计的推动力

  • 在编写程序时,我们应当知道自己为什么要编程,最终目标时什么。

  • 其实,全部软件都有一个相同的目标:帮助其他人。(这个目标比任何规则都重要)

  • 具体软件有具体目标。有些软件是帮助特定人群的。服务于动植物,真正目的,还是帮助人类。

  • 即使是程序库,也是为程序员服务,而不是为计算机。

  • 帮助的定义:(让人)能更容易地做某事;帮忙;协助。特指完成部分工作,减轻或者分担工作量。

  • 你可以帮很多忙,做规划,制订食谱等,想干什么取决于你。

  • 赚钱,或炫耀智商,都是狭隘的帮助,是偏离目标的。无可厚非。

  • 任何情况下,你所赚的钱都直接维系于你的软件能为他人提供多少帮助。事实上,决定软件公司收入的两个主要因素基本就是组织水平(包括行政,管理,推广,销售等方面),以及软件对他人的帮助。

  • 一个人写出优秀软件的潜力,完全取决于他在多大程度上理解了“帮助其他人”的思想。

  • 总的来说,在做与软件有关的决策时,指导法则就是判断能提升什么样的帮助,请记住,帮助有很多种,帮大忙,帮小忙,帮很多人,帮少数人。

  • 各项需求也可以照这个标准排出先后顺序,哪项需求能为人们提供最大的帮助,就应当赋予最高的优先级。关于需求的优先级,还有很多可以补充,但在评估开发和维护软件系统的建议时,“它能给用户帮多少忙”绝对是一个重要而且基础的问题。

  • 这样思考,有助于澄清功能描述或实现方式中的模糊之处。上面关于快捷键的描述说明,它的响应必须很快,因为快捷键的价值就在这里。

  • 这样思考,有助于团队确认功能的价值。有些人可能不喜欢快捷键,但是每个人都应该认同上面关于其价值的解释。可能想出更好的办法。如果问题的答案可以引出更好的想法,就应该去实现。问题的答案告诉我们的是真实的需求,而不是用户以为的需求。

  • 这样思考,某些功能会凸显出更重要的价值。这有助于项目领导分配优先级。

  • 退一万步说,如果编辑器因为堆叠了过多功能而臃肿,可以根据这些答案决定删减哪些功能。

  • 真实应用:如何才能把软件的目标落实到真正的项目中去呢?先决定软件的目的,要简单,不妨先定位“帮助程序员编辑文本”。若具体目标尚存分歧,且从最简单的形式开始吧。

  • 目标定了,来看需要完成的功能。针对每一条功能,我们都要问自己,“这个功能怎么样帮助程序员编辑文本呢?”。检查过一遍之后,对剩下的每个需求,要写下一个短句作为答案。如果写下来显得多余,只要保证自己明白这一点就好了。

  • 之所以要这样问自己,是因为还存在其他有价值的理由:

  • 我们还需要列一张bug清单,方便检查和反思:这个bug如何影响程序员编辑文本,有时候答案很明显,那不需要写。

  • 要把软件的目标落实到真正的工作中,还有很多办法,这里只给出了几个例子。

【软件设计科学的目标】

  • 了解了软件设计的目标之后,就可以确定软件设计的科学的基本方向了。

  • 目标是:确保软件能够提供尽可能多的帮助。

  • 第二个目标是:确保软件能持续提供尽可能多的帮助。

  • 在今天,编写和维护有帮助的软件的主要障碍在于设计和编程。如果软件很难开发或修改,程序员的主要精力就花在让软件能用上,而没有精力去帮助用户。如果系统易于修改,程序员就会有更多的余力去帮助用户,不必费心于编程细节。同样道理,软件的维护难度越低,程序员确保软件能持续提供帮助的难度也越低。

  • 第三个目标:设计程序员能尽可能简单地开发和维护的软件系统,这样的系统才能为用户提供尽可能多的帮助,而且能持续提供尽可能多的帮助。

  • 第一个和第二个目标的指引是非常重要的。推动实现第三个目标的,就是确保软件现在能提供帮助,将来仍然能帮助。

  • 第三个目标很重要,否则就没法完成前两个目标。所以应该不会冲突。


第四章 未来

  • 软件设计师面对的主要问题是:在设计软件时,应该做怎样的决定?面对的众多可能,哪一个才是最好的。不要绝对好坏,而是哪些更好,是个排序问题,我们要做的是从所有可能中选出最好的决定。比如,眼前功能100项,但我们的人力只能够完成2项。应该选哪2项呢?

  • 软件设计的方程式:上面的问题,还包括软件设计的本质中的如有问题,都可以用下面的方程式来解答: D = V/E, expense

  • 其中,D表示这个变化的合意程度(可取程度)。我们对此项工作的需求有多么迫切?

  • V表示它的价值,几何?对用户多少用,当然还有很对其他方法来判断其价值。

  • E表示完成这个变化的成本,也就是完成它需要付出的代价。

  • 这个等式的意思是:任何一点改变,其合意程度与其价值成正比,与所付出的成本成反比。是否应当维持不变?价值何在,要花什么成本?

4.1.1 价值

  • 这个变化能带给人多大帮助

  • 价值最简单的定义是:

  • 所有最需要帮助的人里面,最重要的是你的用户。不过,为了赚更多钱而开发某些功能,也是一种形式的价值,对你来说有价值,其实,创造价值的方式有很多种。上面只是举两个例子。

  • 要准确衡量某点变化所创造的价值,有时候是很难得。比如软件帮人减肥,怎么精确衡量帮人减肥的价值?

  • 判断每一点可能的变化的价值,基本的依据是开发人员的开发经验,还包括对用户做恰当的研究,找到对他们帮主最大的工作。

1,价值可能性和潜在价值

  • 多少用户(占多大比例)会从此项工作中受益?

  • 此功能对用户有价值的可能性有多大?或者换个说法:此功能发挥价值的频率有多高?

  • 在它发挥价值的时候,它能发挥出多大的价值?

  • 价值由两部分组成:可能价值(这个变化有多大可能帮到用户),潜在价值(这个变化在对用户提供帮助的时候,将为用户提供多大的帮助)

  • 举例来说,某个功能可以延长人的寿命,可能性很低,但仍然非常有用。

  • 所以,在判断价值时,你应该考虑:

2,平衡危害

  • 有些改变在带来帮助的同时也会带来麻烦。如果你的程序展示广告,提供资金VS觉得烦。

  • 权衡改变的价值,需要衡量它可能造成的危害,并权衡利弊。

3,赢得用户的价值

  • 如果某个功能找不到用户,就不存在实际的价值。可能用户找不到或者很难使用,或者根本帮不上任何人。在将来它们可能有价值,但目前没有。

  • 这也意味着,大多数情况下,为了确保你的软件有价值,就必须真正发布它。如果某个变化花费的时间太长,最后可能就没有任何价值,因为它不能及时发布,无法给人提供切实的帮助。评估发布计划是非常重要的。

4.1.2 成本

  • 比起价值,成本更容易量化一点。通常,你可以计算“需要多少个人工作多少小时”。

  • 尽管成本可以量化,落实起来却相当复杂,甚至是不可能的。有些变化包含隐形成本,难于预测,比如花在修正开发某项功能造成的bug上的时间久很难预测。

  • 不过,经验丰富的可以不需要知道确切数值的情况下,根据可能成本来预测。

  • 预测某个变化的成本时,重要的是要考虑牵涉到的所有投入,而不仅仅是编程的时间。研究,沟通,思考,花多少时间。简单说,与这个变化有关的每一点时间,都是成本的一部分。

4.1.3 维护

  • 目前,这个方程式很简单,但忽略了一个重要的因素--时间。完成,并要维护。

  • 比如,报税软件,每年新规定公布后要维护。即使暂时看不到长期的维护成本,即使维护成本只是你下一年必须再做一次测试,维护成本依然存在。

  • 还必须考虑现在价值和未来价值。修改现有的系统时,受益的是现在的用户,但是它也可能帮助到未来的用户,甚至影响未来用户的数目,进而影响到现有系统究竟总共能帮助到多少人。

  • 有些功能的价值会随时间变化,贬值或增值。

  • 成本包括实现成本和维护成本,价值也包括当前价值和未来价值。用方程式来表示就是:E=Ei+Em, V=Vn + Vf

4.1.4 完整的方程式

  • 考虑所有因素,完整的方程式就是: D = (Vn + Vf)/ (Ei + Em)

  • 用文字说明就是:改变的合意程度(可行性),正比于软件当前价值与未来价值之和,反比于实现成本和维护成本之和。

4.1.5 化简方程式

  • 未来价值和维护成本都取决于时间,如果把这个方程式应用到现实中,随着时间的改变,会出现非常有意思的现象。为说明这个问题,假设价值和成本都可以用金钱来衡量。带来或需要投入多少钱。D = ($10000 + $1000/天)/($1000  + $100/天),随着时间的流逝,最开始说的当前价值和维护成本看来就微不足道了。

  • 变成了D = Vf / Em

  • 几乎所有软件设计决策都完全忽略了未来价值与维护成本的对比。有时候当前价值和实现成本足够大,始终在决策中占有决定性地位,但这种情况很少见。长期受益和维护成本才是真正需要考虑的,与之相比,当前价值和实现成本变得无足轻重。

4.1.6 你需要什么,不需要什么

  • 避免某项工作维护成本最终大大超过未来的收益。

  • 可以用微积分,把这个方程式理解为一个具有极限的无穷数列,而不是某个静态的方程式。

  • 只要维护成本的增长速度比价值快,就会遇到麻烦。

  • 理想的解决方案,也即保证成功的唯一途径——就是这样设计你的系统:保证维护成本随时间降低,最终降到零(或者尽可能接近零)。只要你能做到这点,就无所谓未来收益是大还是小,总之你不需要关心。

  • 能带来更高未来价值的改变仍然是更可取的,不过,只要每项决策的维护成本都会随时间降低到接近于零,未来你就不会陷入危险的境地。

  • 只要未来收益超过维护成本,也是值得做的。

  • 相比降低实现成本,降低维护成本更加重要。(也许实现上花很高成本,做相当多的设计和规划)

  • 维护成本从哪里来?怎样设计系统,才能保证维护成本会随时间推移而降低?要对未来做更细致的检查。

4.2 设计的质量

  • 如今,要写出一款能帮助某个人的软件,实在是太容易了。但是,要写出能帮助几百万人,而且是在未来几十年里持续提供这种帮助的软件,则要难的多。那么,编程中的大部分精力应该花在哪里?大多数人什么时候使用这款软件?现在,还是未来的几十年?

  • 答案是,相比现在,将来有多得多的编程工作要做,也有更多的用户要帮助。在未来,你的软件必须保持竞争力,才能继续存在,同时,维护成本和用户数量也会增加。

  • 于是,得到这条规律:设计的质量好坏,正比于该系统在未来能持续帮他人时间的长度。

  • 如果你的软件只能在未来几小时内提供帮助,就不需要花太多的功夫去设计。

  • 不要把自己禁锢在某种工作定势里,要保持灵活;不要做任何以后无法改变的决策;在设计时要慎重,慎重,再慎重。

4.3 不可预测的结果

  • 未来的某些事情,是我们所不知道。

  • 设计软件时最应该关注的是未来,不过,关于任何工程,都有一点极为重要:

  • 软件设计也是如此。程序员犯的最常见也是最严重的错误,就是在其实不知道未来的时候去预测未来。

  • 比如1985年程序员写了一个修复软盘错误的程序,他预期是“人们会一直使用软盘”,但现在没用了。

  • 预测短期未来是可能的,但长期未来基本是未知的。但相比短期,长期的未来对我们来说更重要,因为我们的设计决策会在未来更长的时间里产生更大的影响。

  • 如果完全不考虑未来,只根据当前已知的确切信息确定所有设计决策,那就百分百安全了。

  • 在进行决策时,未来才是最重要的事情。但在进行决策时,考虑未来的变数和尝试预测未来,是有区别的。

  • 有些决策不用预测未来,不需要知道确切的未来。同样道理,在软件设计时,可以根据已知的信息做某些决策,目的是为了创造更好的未来(提升价值,降低维护成本),而不必预测未来究竟会发生什么具体的事情。

  • 也有少量例外,有时候你确切知道未来短期内会发生什么,便可以据此决策。如果这么做,必须对未来有相当的把握。无论你多聪明,肯定没有简单的办法准确预测长期未来。

  • 简单来说,CD诞生于1979年,最初设想是取代磁带,成为最主要的听音媒质。出现DVD到计算机的兼容CD/DVD的驱动器,以及CD-ROM以50倍速读取CD出先什么问题,谁会想到。

  • 正因如此,任何工程,包括软件开发,都有指导原则。重要的是要记住,存在着未来。

  • 某条特定的规则和条例在未来会以什么样的方式帮助你也无法预测,但它确实能帮上忙,而且你会欣然乐意把它们应用在工作中。


第 5 章 变化

  • 程序存在的时间越久,它的某个部分需要变化的可能性就越高。

  • 未来有些东西是我们不知道也不可能知道的,但可以确定的一点,随着时间的流逝,软件所处的环境会变化。没有东西可以永恒不变。

  • 也就是说,软件必须随环境变化而变化,才能适应所处的环境。

  • 于是,我们得到了变化定律: law of change

  • 未来是无穷无尽的,所以可以百分百地肯定,最终,程序的每个部分都必须变化。

  • 哪些部分会发生变化,为什么变化很难预测。

  • 可能你的程序是为4轮轿车写的,可未来每个人都开着18个轮的大卡车;可能你的程序是写给高中生的,但是高中教育的质量差到没有学生懂你的程序。

  • 关键不需预测变化,应保证尽可能合理的灵活性。应付变化。

5.1 真实世界中程序的变化

  • 看一份关于真正的程序随时间流逝而变化的数据吧,某个程序数百个文件,4个样本的变化详情。

文件1 文件2 文件3 文件4
分析时长
初始行数
未变化行数
当前行数
增长数
变化次数
新增行数
删除行数
修改行数
总变化行数
变化率 1.6x 8.9x 13x 36x
  • 行数,包含文件的每一行:代码,注释,文档,空行。未变化的行几乎都是注释,文档,空行。

  • 观察变化率可以发现,修改文件的工作量比最初写文件时的还要大。当然,行数这个指标不能准确反映工作量,但是它可以体现一般趋势。

  • 总变化行数通常比当前行数要大。改的多,不是新增代码。

  • 关于这些数字,还可以做其他许多有趣的分析。鼓励探究这些数据,或分析自己项目里的类似指标。

  • 若是有全部修改历史,回顾修改的每次,和最初写这个文件相比,能预测到这些变化,或减轻后期的工作量。尝试理解每次修改,看是否能从中得到一些关于软件开发的新收获。

5.2 软件设计的三大误区

  • 1,编写不必要的代码

  • 2,代码难以修改

  • 3,过分追求通用

  • 为了适应变化定律,软件设计师常常会掉进误区。其中有3个误区最常见,按照其发生频率逐一列出来:

5.2.1 编写不必要的代码

  • 如今,软件设计中有一条常见的规则,叫做“你不会需要它”(You Ain't Gonna Need It),或者简称YAGNI。

  • 不要编写不是必需的代码,并且要删除没有用到的代码。

  • 如果真的需要,你随时可以恢复回来。

  • 有些人相信自己可以抗拒变化定律,保留暂时用不到的代码,现在就编写一些今后才会需要的代码。

5.2.2 代码难以修改

  • 1,对未来做太多假设

  • 2,不仔细设计就编写代码

  • 软件项目的一大杀手就是所谓的“僵化设计”(rigid design)。

  • 僵化设计有两大原因:

  • 医院的错误在于试图预测未来,花了1年时间来写系统实现细节文档。

  • 更好的办法是每次只确定一个或者少数几个需求,然后立刻让开发人员实现它。在开发过程中,用户可以扮演开发人员的较色,反复进行沟通。上次确定的功能实现并发布后,就可以继续处理其他的功能。这样最终得到的系统是设计良好的,完全满足用户需求的。

  • Status字段,记录当前任务的进度,No Work Done, In Progress, On Hold, Complete.

  • 类似的部分分得很散,没有注释,没有逻辑,每次要修改时,除了阅读整个文件外别无他法。

  • 避免僵化设计,就应当做到:设计程序时,应当根据你现在确切知道的需求,而不是你认为未来会出现的需求。

  • 保持每次改变的幅度都很小,设计的难度也会很小。

5.2.3 过分追求通用

  • 既然代码将来要修改是一个事实,有些开发人员给出的应对方案就是:做一个足够通用的办法,保证可以适应未来任何可能的形式。

  • 我们称这种做法为过度工程,overengineering。

  • Engineer,意思是设计和构造。

  • 问题:1,都不够满足未来需求,2,无法满足具体的需求,3,写很多不需要的代码

  • 在追求通用时,应当选择正确的事情,选择正确的方法,这是成功的软件设计的基础。

  • 仅仅根据目前确知的需求来考虑通用。

5.3 渐进式开发及设计

  • 有个办法可从根本上避免这三大误区,就是渐进式开发和设计,它要求按照特定顺序,一点一点地设计和构建系统。

  • 这个方法的精妙之处就在于,它是根据实现的顺序来决策的。总的来说,在其中的每个阶段,下一步都只做最容易的事情。

  • 先选加法,因为是最简单的运算,其次选择减法,因为从逻辑上说,它与加法只有很小的差异。也可以选择乘法,是把加法执行很多次。不选除法,从加法到除法的步子距离太远了。最后一步,从乘法到除法。

  • 有些时候,你甚至需要把某个单独的功能拆分为一系列小的,简单的逻辑步骤,然后才可以很方便地实现。

  • 混合了两种做法,一种叫渐进开发,一种叫渐进设计。渐进开发是一种通过小步骤构建整个系统的办法。先实现,在修改设计,再实现,再修改设计。

  • 渐进开发和设计并不是唯一有效的软件开发方法,但是它无疑可以避免之前列出的三大误区。


第6章 缺陷与设计

  • 没有哪个程序员可以不犯错误,最优秀的程序员,在状态最好的时候,每写1000行代码也会犯一个错误。

  • 不变得:写的代码越多,引入的缺陷就越多。

  • 缺陷概率定律:在程序中新增缺陷的可能性与代码修改量成正比。

  • 错误妨碍了我们帮助他人的目标,应当避免。修复缺陷也是维护工作的一种,所以新增缺陷还会抬高维护成本。

  • 小的变化 = 更少的缺陷 = 更少的维护

  • 有时候,该规则也会被非正式地表述为:如果不新加代码,也不修改代码,就不会产生新缺陷。

  • 这规律似乎与“变化定律”相矛盾。

  • 所以,最好的设计,就是能适应外界尽可能多的变化,而软件自身的变化要尽可能少。

6.1  如果这不是问题

  • 永远不要“修正”任何东西,除非它真的有问题,而且有证据表明问题确实存在。

  • 可能用户没弄清楚到底要干什么。

  • 最有名的错误就是:提前优化

  • 在你的程序中,真正需要关注速度的部分,应该局限于你可以证明的,真正让用户体会到有性能问题的那些部分。对程序的其他部分,最主要关心的还是灵活和简洁,而不是速度。

6.2 避免重复

  • 理想情况下,任何系统里的任何信息,都应当只存在一次。

  • 比如用户界面上的东西,若是硬编码,要改很多地方。

  • 对代码段也同样适用。我们不应该复制粘贴代码段,相反,应该使用各种编程技巧来处理,让各处的代码可以“使用” use,“调用” call,“包含” include已有的其他代码。

  • 一个强有力的理由,就是缺陷概率定律。重用,引入错误少。


第7章 简洁

  • Law of Simplicity

  • 软件任何一部分的维护难度,反比于该部分的简洁程度。

  • 不关心系统的,只关心部分的,因为程序足够复杂,没有人可以一次性全面理解它,大家都只能分部分逐步了解。

  • 由大模块构成的系统,质量要差得多。

7.1 简洁与软件设计方程式

7.2 简洁是相对的

  • 注释,头一次看这些代码?

  • 应用场合(上下文)也是非常重要的。有时候,某个应用场合中看来复杂的东西,换个应用场合就会变简单。比如马路上广告牌标注大量解释文字。

  • 我们做的每一件事都会有目标受众,每个应用场合通常都存在诸多限制。

7.3 简洁到什么程度

  • 简单到傻子也能懂。

7.4 保持一致

  • 各个地方规则一致

  • 一旦你理解了某种复杂性,就不必再进行重复劳动。

7.5 可读性

  • 代码可读性主要取决于字母和符号之间的空白排布。

  • 空白太多不必要,因为很难发现事物之间的联系。太少难分解。

  • 代码到底应该留出怎样的空白,硬性的直接的规则, 唯一的规则是:代码之间留出的空白应当保持一致规范,空白应当能有助于读者理解代码的结构。

  • 空白排布:下面的代码很难看懂,因为空白太少了,几乎没有提供关于代码结构的信息。

  • 同样的代码,空白太多了,也难理解代码的结构。

  • 一般来说,如果某段代码有很多bug,又难以阅读,那么首先要做的是让它更容易阅读,然后bug在哪里才能看得更清楚。

7.5.1 命名

  • 理想的名字:名字应该足够长,能够完整表达其意义或描述其功能,但不能太长,以免影响阅读。

  • 同时考虑使用频率,若频率长就要短些。

7.5.2 注释

  • 如果你的代码实在不能更简单,才应该写注释来说明。

  • 保证代码的可读性是非常重要的,而且它往往是通往优秀设计之路上应当走出的第一步。

7.6 简洁离不开设计

  • 如果设计师不倾注经历,系统就会逐渐变成杂乱庞大的怪物。

  • 有些人缺乏足够的经验来理解最终的复杂局面。

  • 解决重大缺陷为你赢得很多赞誉,但是避免缺陷发生,嗯,没人会注意到。


第 8 章 复杂性

  • 1,扩展软件的用途

  • 2,新增程序员,《人月神话》,设定合适岗位,适应新人,学会沟通等。少量精干比众多平庸好。

  • 3,做无谓的改变

  • 4,困于糟糕的技术

  • 5,理解错误,确保自己完全理解所用的系统和工具

  • 6,糟糕的设计或不做设计,没有为变化做计划。

  • 7,重新发明轮子,

  • 很多问题的根源都在复杂性,比如工期,别人完成的快,需求变换多等。

  • 复杂性会叠加的,而且不是简单的线性叠加。

  • 原有10项功能,再加1项,不是10%。因为要协调,所以需要多时间。

  • 除了新增功能,其他一些做法也会增加复杂性:

8.1 复杂性与软件的用途

8.2 糟糕的技术

  • 可以通过三个因素来判断技术是否糟糕:生存潜力,互通性,对品质的重视

  • 有人维护,发布,解决问题,有生态圈

  • 切换到其他技术是否容易

  • 是否变得更好

  • 上面这些指引只负责帮你排除掉糟糕的选择,剩下的则取决于你自己的研究,需求,计划。

  • 开发人员可能对自己所用的技术有独特的热情。为了避免触犯这类用户,我们还是不提具体的技术为佳。

8.3 复杂性及错误的解决方案

  • 如果某件事情变得非常复杂,也就意味绝不是表面的复杂那么简单,而是设计出了问题。深层次的基本错误。

  • 真正要解决的问题是什么?

8.4 复杂问题

  • 在解决复杂问题时遇到了麻烦,那么用简单易懂的问题自把它写在纸上,或者画出来。

  • 有些最优秀的程序设计就是在纸上完成的,真的。把它输入到计算机里只是次要的细节。

  • 大多数麻烦的设计问题,都可以用在纸上画图或写出来的办法找到答案。

8.5 应对复杂性

  • 如果系统中某个部分太过复杂,有个好办法来解决:把它分解成几个独立的小部分,逐步重新设计。每次修改足够小,可以放心动手。

  • 不能专门花很长时间来重新设计,停止开发新功能。要适应变化,从用户角度出发来调试和改进。

  • 一点点修改,分步骤做,每一步都是一个项目,遇见文件修改就改。

8.5.1 把某个部分变简单

  • 学习设计模式和设计方法

  • 学习软件工程师普遍使用的工具

  • 掌握多门编程语言,熟悉多种不同的类库

  • 软件设计的工具和技巧只能锦上添花,帮助你找到更好的答案。

8.5.2 不可解决的复杂性

  • 屏蔽这种复杂性,在程序外面妥善包装上一层,让其他程序员更容易使用和理解。

8.6 推倒重来

  • 重来,几乎就是设计师承认失败,等于说:"我们设计不出可维护的系统,所以只能重来"

  • 摩天大楼,就不用重写


第 9 章 测试

  • 测试法则Law of Testing告诉我们:你对软件行为的了解程度,等于你真正测试它的程度。

  • 软件最后一次测试时间距离现在越近,继续正常运行的可能性就越大。在越多的环境里测试过。

  • 测试的程度,包括多少个方面曾测试过,上一次测试是多久前,在多少不同的环境下进行过测试。

  • 除非亲自测试过,否则你不知道软件是否能正常运行。

  • 针对每项测试,你必须问一个非常具体的问题,得到一个非常具体的答案。知道预期的行为。

  • 测试要和事实相符合。

  • 修改了软件的某个部分,这部分是否能正常工作就成了未知数,就必须重新测试。

  • 编写许多自动化测试来测试所写的每一段代码。

  • 网上有许多资料讲解如何编写自动化测试以及测试的一般原理,也出版过很多相关书籍。

  • 测试领域的资料丰富详尽,值得学习。

  • 测试法则只负责解释为什么需要测试,什么时候需要测试,以及测试真正能提供什么信息。

附录 A 软件设计的规则

附录B 事实,规则,条例,定义

图形社区: ituring.com.cn

读书笔记 - 简约之美:软件设计之道相关推荐

  1. 《简约之美-软件设计之道》- 笔记

    简约之美-软件设计之道 软件设计的推动力 软件设计的目标:全部软件都有⼀个共同的⽬标:帮助他⼈:让⼈更加容易的做某事:协助,减轻或分担⼯作量.⽽不是只是以赚钱为⽬的. 软件设计科学的⽬标 确保软件能够 ...

  2. 浅读《简约之美-软件设计之道》

    浅读<简约之美-软件设计之道>     大家好,我是Lampard~     这个周末阅读了一本程序设计相关的书籍<简约之美-软件设计之道>,它原著是<The Scien ...

  3. [读书笔记]编程之美(三)

    [读书笔记]编程之美(三) 3.1字符串移位包含的问题 问题:给定两个字符串s1和s2,要求判定s2是否能够被s1做循环移位(rotate)得到的字符串包含.例如,给定s1=AABCD和s2=CDAA ...

  4. 开天眼,顿悟软件设计之道

    本文摘自http://tech.it168.com/j/n/2007-07-10/200707101017099_3.shtml 开天眼,顿悟软件设计之道   <script type=&quo ...

  5. 《Computer Graphics with OpenGL》计算机图形学读书笔记 02——计算机图形学软件

    这里是<Computer Graphics with OpenGL>英文原版第四版的读书笔记,预计每一章写一篇读书笔记.本篇为第二章,简要介绍计算机图形学的相关软件.图形学相关软件可分为两 ...

  6. [置顶] 软件设计之道_读书纪要.doc

    本系列的文档都是我读书后的个人纪要,如想了解更多相关内容,请购买正版物.对应的图书可以从我的个人图书列表里找寻:个人毕业后图书列表 1.  每个写代码的人都是设计师,团队里每个人都有责任保证自己的代码 ...

  7. 软件工程读书笔记(四)——软件工程师的成长

    昨天依靠一罐红牛撑了一天,在零点到来前五分钟commit了最终代码.脑袋昏沉地走出实验室,去肥西路的蒸小皖吃了一碗牛肉面,在凌晨一点之前,把自己扔到了床上,当然少不了敲开宿舍楼下的门的时候宿管阿姨的一 ...

  8. 信息系统项目管理师自学笔记(八)——软件设计

    2.4 软件设计 从工程管理角度来看,软件设计可分为概要设计和详细设计两个阶段. 概要设计也称为高层设计,即将软件需求转化为数据结构和软件的系统结构.概要设计主要包括设计软件的结构.确定系统由哪些模块 ...

  9. 软件工程学习笔记——第六章 软件设计方法

    目录 第一章 概述 第二章 过程和活动 第三章 软件过程模型 第四章 问题定义和可行性研究方法 第五章 需求分析方法-1 第五章 需求分析方法-2 第六章 软件设计方法 第七章 软件实施与测试方法 第 ...

  10. 软件工程学习笔记(四)软件设计

    软件设计概述 软件设计的基本特征:目标,形态,内容 从技术角度考虑,软件设计主要包括4方面内容: 系统结构设计:确定软件系统的结构,即软件系统的组成,以及各组成成分(子系统或模块)之间的相互关系 接口 ...

最新文章

  1. 整体关闭screen(转)
  2. mac 用户 文件夹 权限_这可能是 Mac 共享文件最详细的教程了
  3. CRM_ORGMAN_CHECK_OW
  4. ubuntu安装QT4的方法
  5. react学习(49)--参数判定
  6. F#学习之路(2) 深刻理解函数(上)
  7. CompletableFuture详解~设置任务结果
  8. c++ 使用nacos_为什么选用Nacos?虎牙直播微服务改造实践
  9. 大数据数据可视化设计原则_数据可视化设计的8顶帽子
  10. 股票点买3.0交易系统接口设计思路
  11. K进制 nyoj882
  12. 计算机输入设备和输出设备怎么区分,输入设备和输出设备的区别
  13. Python实现大文本文件分割成多个小文件
  14. 从零搭建SSR+VUE框架(附源码)
  15. python海龟作图好看图案_Python中的高级turtle(海龟)作图
  16. Java设计原则之单一职责原则、开闭原则、里氏代换原则
  17. 设计一个智能客服系统
  18. 野人参多少钱一斤?走进野人参高价格背后的秘密
  19. vue_云点播TCPlayer
  20. CVPR2022: Oriented RepPoints论文模型实践(用dota数据集)

热门文章

  1. Graphpad prism 使用教程汇总(更新)
  2. Delphi10.4.2关于Android设备调试
  3. 【无机纳米材料科研制图——OriginLab 0204】Origin细胞存活率柱状图绘制
  4. Pytorch 报错 Python int too large to convert to C long
  5. RK3399基于ubuntu文件系统的audio调试
  6. 【信号处理】脉搏信号处理系统含Matlab源码
  7. Matlab聚类分析(Kmeans)
  8. 利用Wireshark分析UDP数据包
  9. adb 驱动安装说明文档
  10. H3CSE培训阶段1