< 构建之法 -- 现代软件工程 > 读书笔记
构建之法
一本不错的软件工程教材,实际从事过软件开发后再读,很多东西就是日常的工作行为规范,本书没有大段大段的概念定义,而是用对话、场景和例子来介绍,读起来也很有趣。
印象比较深的点:
- 如何来衡量、证明一个软件工程师的能力?用数据、结果来展示
- “黄金点”游戏,创新有时候只需要比别人多走一步
- 敏捷方法的实用性,可能是“霍桑效应”导致的
- 学会估计工作量很重要
前言
关于学习:
- 知识体系是构建出来的,不是接收到的。
- 人的认知模型改变得非常缓慢。
- 提问能帮助构建知识体系。
- 身心投入是学习的关键。
ch1 概论
程序 = 数据结构 + 算法
软件 = 程序 + 软件工程
软件企业 = 软件 + 商业模式
软件开发的不同阶段:
玩具阶段 → 业余爱好阶段 → 探索阶段 → 成熟的产业阶段
软件工程是把系统的、有序的、可量化的方法应用到软件的开发、运营和维护上的过程。
ch2 个人技术和流程
PSP(Personal Software Process)。
如何让自己负责的模块功能定义尽量明确,模块内部的改变不会影响其他模块,而且模块的质量能得到稳定的、量化的保证?-- 单元测试。
好的单元测试的标准:
- 在最基本的功能/参数上验证程序的正确性
- 单元测试必须由最熟悉代码的人(程序的作者来写)
- 单元测试过后,机器的状态保持不变
- 单元测试要快(一个测试的运行时间是几秒钟,而不是几分钟)
- 单元测试应该产生可重复、一致的结果
- 独立性——单元测试的运行/通过/失败不依赖于别的测试,可以人为构造数据,以保持单元测试的独立性
- 单元测试应该覆盖所有代码路径
- 单元测试应该集成到自动测试的框架中
- 单元测试必须和产品代码一起保存和维护
回归测试:
- 验证新的代码的确改正了缺陷
- 同时验证新的代码有没有破坏模块的现有功能,有没有Regression
个人开发流程,以 PSP 2.1 为例:
- 计划:估计这个任务需要多长时间
- 开发:需求分析,设计文档,设计评审,代码规范,具体设计,具体编码,代码评审,测试
- 报告:记录用时,测试报告,计算工作量,总结,提出改进计划
“开发” 不仅仅是写代码。
ch3 软件工程师的成长
一个问题:软件工程师如何衡量和证明自己的能力?类比篮球运动员,用数据展示是最直观的。
初级软件工程师的成长包括以下几种:
- 积累软件开发相关的知识,提升技术技能(如对具体技术的掌握,动手能力)。例如:对JAVA、C/C++、C#的掌握,诊断/提高效能的技术,对设备驱动程序、内核调试器的掌握,对于某一开发平台的掌握
- 积累问题领域的知识和经验(例如对医疗或金融行业的了解)
- 对通用的软件设计思想和软件工程思想的理解
- 提升职业技能(区别于技术技能),包括:自我管理的能力、表达交流的能力、与人合作的能力、按质按量完成任务的执行力
- 实际成果——最重要的评价标准
ch4 两人合作
函数的设计:只做一件事,而且要做好。
结对编程:
- 驾驶员:控制键盘输入
- 领航员:起到领航、提醒的作用
结对编程对人的心智、道德修养有较高的要求。
结对编程好处:
- 在开发层次,可以提供更好的设计质量和代码质量,两人合作解决问题的能力更强。
- 对开发人员,带来更多的信心,高质量的产出带来更高的满足感。
- 企业管理层次上,有效地交流,相互学习和传递经验,分享知识,取得更高的投入产出比。
Code Review:
除了提前发现错误之外,还能够传授、分享知识和经验。
可以记录一个“我常犯的错误”列表。
ch5 团队和流程
常见软件团队模式:
- 主治医师模式
- 明星模式
- 社区模式
- 业余剧团模式
- 秘密团队
- 特工团队
- 交响乐团模式
- 爵士乐模式
- 功能团队模式
- 官僚模式
常见开发流程:
- 写了再改模式
- 瀑布模型:开发过程是通过设计一系列阶段顺序展开的,从系统需求分析开始直到产品发布和维护,每个阶段都会产生循环反馈,因此,如果有信息未被覆盖或者发现了问题,那么最好 “返回”上一个阶段并进行适当的修改,项目开发进程从一个阶段“流动”到下一个阶段,这也是瀑布模型名称的由来。
- 瀑布模型的变形:生鱼片模型(各个相邻模块像生鱼片那样部分重叠)以及大瀑布带着小瀑布(各个子系统统一到最后进行系统测试)
ch6 敏捷流程
敏捷开发原则:
- 尽早并持续地交付有价值的软件以满足顾客需求
- 敏捷流程欢迎需求的变化,并利用这些变化来提高用户的竞争优势
- 经常发布可用的软件,发布间隔可以从几周到几个月,能短则短
- 业务人员和开发人员在项目开发过程中应该每天共同工作
- 以有进取心的人为项目核心,充分支持信任他们
- 无论团队内外,面对面的交流始终是最有效的沟通方式
- 可用的软件是衡量项目进展的主要指标
- 敏捷流程应能保持可持续的发展。领导、团队和用户应该能按照目前的步调持续合作下去
- 只有不断关注技术和设计,才能越来越敏捷
- 保持简明——尽可能简化工作量的技艺
- 只有能自我管理的团队才能创造优秀的架构、需求和设计
- 时时总结如何提高团队效率并付诸行动
敏捷流程概述:
- 找出完成产品需要做的事情
- 决定当前的冲刺(Sprint)需要解决的事情
- 冲刺(冲刺期间每天开每日例会)
- 得到软件的一个增量版本并发布
每日立会(站立会议):
要追踪任务完成的时间。
敏捷方法为什么有效,可能是“霍桑效应”。
霍桑效应(Hawthorne Effect):当人们在意识到自己正在被关注或者观察的时候,会刻意去改变一些行为或者是言语表达的效应。
敏捷不是万能的,它只是帮助你更早知道你是否能如期完成任务,仅此而已。
学会估算工作量,这需要不断练习。
ch7 MSF
微软公司中关于软件开发的思想和宣言有一个方法论——微软解决方案框架(Microsoft Solution Framework,MSF),也就是微软推荐的软件开发方法。
- 推动信息共享与沟通(Foster open communications)
- 为共同的远景而工作(Work toward a shared vision)
- 充分授权和信任(Empower team members)
- 各司其职,对项目共同负责(Establish clear accountability and shared responsibility)
- 交付增量的价值(Deliver incremental value)
- 保持敏捷,预期和适应变化(Stay agile, expect and adapt change)
- 投资质量(Invest in quality)
- 学习所有的经验(Learn from all experiences)
- 与顾客合作(Partner with internal and external customers)
ch8 需求分析
软件需求
- 获取和引导需求:软件团队需要找到软件的利益相关者,了解和挖掘他们对软件的需求,引导他们表达出对软件的需求;需求还可以来自各种管理机构;需求不仅来自外界,还可以来自软件企业本身;需求还可以来自技术团队本身;有些需求的目的是要更好地了解用户的行为和需求。
- 分析和定义需求
- 验证需求
- 在软件产品的生命周期中管理需求
竞争性需求分析的框架 -- NABCD模型
- N(Need,需求)
- A(Approach,做法)
- B(Benefit,好处)
- C(Competitors,竞争)
- D(Delivery,推广)
功能的定位和优先级
我们以一个英汉词典软件为例子来说明。
- 杀手功能:OCR文字识别技术,可以在屏幕上取词解释,拥有独家权威词典,等等
- 外围功能:良好的界面设计,在各个平台上都能运行
- 必要需求:单词短语释义的准确性(如果达不到这一点,用户就不会来使用)
- 辅助需求:可以做各种皮肤(这也许能让一些用户更喜欢这个软件,但不是决定因素)
分而治之(Work Breakdown Structure): 通常从最终的产品开始,一层一层往下,把大型交付件(Deliverable)分割为小型、具体的交付件。这样的分割可以持续下去,直到WBS的使用者(开发团队、接收方)达到共识。从数据结构方面来看,WBS分割的结果是一棵树。所有子节点都最终有一个根节点。每个节点描述的是要交付的产品或文档,而不是开发团队的努力或花费(各个叶节点的成本可以作为次节点的属性展现出来)。
ch9 项目经理
软件团队里除了能写代码、测试代码和画图做设计的成员,还有一类角色,不做上面这些事情但也很重要,我们叫他们项目经理 —— PM
PM 的 M 就是Manager,但是P有这几种:Product Manager、Project Manager、Program Manager,在不同的行业和公司,他们的作用各不相同。接下来介绍的是项目经理——Program Manager
- Product Manager:产品经理——正确地做产品
- Project Manager:项目经理——正确地做流程
- Program Manager:微软的职位名称
PM 的能力要求和任务:
- 观察、理解和快速学习能力——PM要能够在一个新的领域中很快上手
- 分析管理能力
- 一定的专业能力
- 自省的能力
ch10 典型用户和典型场景
我们首先要定义用户的角色。正如戏剧中有正面和反面的角色,软件系统中也有受欢迎的和不受欢迎的典型用户。
- 受欢迎的典型用户——指那些按设计者的期望使用系统的用户,如“网站的购物者”
- 不受欢迎的典型用户——指那些有不正当目的的用户,如在一个房地产业主论坛中滥发房屋中介广告的用户——这些用户也许在别的系统中(如房屋中介论坛)是受欢迎的
典型用户只是我们的设想,还要和这些典型用户的代表交流,理解用户,理解他们的工作方式和需要。然后再修改,细化典型用户
有了典型用户之后,我们还得决定每一个典型用户的目标——他/她使用系统想要达到什么目的。对于每一个目标,列出达到目标所必须经历的过程,这就是场景,也可以叫故事。注意,有些场景描述了成功的结果,有些场景描述了失败的结果。用户和系统有成百上千种可能的交互情况,写场景时要有针对性。
怎么写场景:
- 首先针对每一个场景,设计一个场景入口(描述场景如何开始)
- 接着描述典型用户在这个场景中所处的内部和外部环境(内部环境指心理因素等)
- 然后给场景划分优先级,按优先级排序写场景
如何区分场景:
- 找到这个场景的特殊之处,对于共同的流程可以一笔带过,重点描述场景中特殊的因素
- 把场景组织成一个故事,这样就能把一个完整的用户与系统交互的流程记录下来,以后进行产品演示或验收都可以以此为基础
使用用例(Use Case):
- 标题:描述这个用例要达到的目标
- 角色(Actor):和软件系统交互的角色,例如用户,其他实体,甚至时间(在描述一些和时间相关的场景时有用)
- 主要成功场景(Main Success Scenario):一系列步骤描述角色是怎样和系统交互,从而达到目标的
- 步骤(Step):描述每一步的交互(例如一套正常的ATM取款流程)
- 扩展场景(Extension):描述一些扩展的交互,例如一些意外情况(例如取款时账户余额不足)
规格说明书(Spec):
- 软件功能说明书(Functional Spec),主要用来说明软件的外部功能和用户的交互情况(把软件当作一个黑盒子)
- 软件技术说明书(Technical Spec),又叫设计文档(Design Doc),主要用来说明软件内部的设计规范(把软件当作一个透明的箱子)
ch11 软件设计与实现
从 Spec 到实现,注意沟通,不要闭门造车。
ch12 用户体验
- 用户的第一印象
- 从用户的角度考虑问题
- 软件服务始终都要记住用户的选择(长期的使用只会使软件更好用)
- 短期刺激 长期影响
- 不让用户犯简单的错误
- 注重用户体验和质量
- 情感设计
ch13 软件测试
名词解释:
- Bug :软件的缺陷
- Test Case :测试用例。测试用例描述了一个完整的测试过程,包括测试环境、输入、期望的结果等
- Test Suite :测试用例集。即一组相关的测试用例
测试方法:
- 黑箱:指的是设计测试的过程中,把软件系统当做一个“黑箱”,无法了解或使用系统的内部结构及知识。一个更准确的说法是行为测试设计,即从软件的行为,而不是从内部结构出发来设计测试
- 白箱:指的是在设计测试的过程中,设计者可以“看到”软件系统的内部结构,并使用软件的内部结构及知识来选择测试数据及具体的测试方法。
Ad hoc Test:exploratory test,探索式、随机进行的测试。Ad hoc 原意是特定的、一次性的。
ch14 质量保障
软件(质量) = 程序(质量) + 软件工程(质量)
软件质量的保障工作:软件团队为了让软件达到事先定义的质量标准而进行的所有活动,包括测试工作。
ch15 稳定和发布阶段
设计变更(DCR, Design Change Request)。
发布之后:项目回顾(Postmortem)
有什么历史经验教训?如果重来一遍,我们会做什么改进?
ch16 IT 行业的创新
介绍关于创新的一些迷思。
创新不是灵光乍现的产物。
不是所有人都喜欢创新。
好的想法不一定带来好的创新。
创新者可能会摔得更惨。
创新不需要成为某个领域的专家。
技术创新不一定是最关键的。
黄金点游戏:
N个同学(N通常大于10),每人写一个0~100之间的有理数 (不包括0或100),交给裁判,裁判算出所有数字的平均值,然后乘以0.618(所谓黄金分割常数),得到G值。提交的数字最靠近G(取绝对值)的同学得到N分,离G最远的同学得到-2分,其他同学得0分。
玩了几天以后,大家发现了一些很有意思的现象,比如黄金点在逐渐地往下移动。
你会想, 如果大家随机报数的话, 0-100 的平均数是50, 50 * 0.618 = 31. 那我就来个 31。
但是其他人也不是傻子, 他们肯定也想到了这一点。如果大家都选 31 附近的数, 那我得选 31*0.618 = 19;
但是这些人肯定也想到了这一点, 那我要选 19 * 0.618 = 12… 然后 12 * 0.618 = 8 …
最后干脆选 0.0001 好了!
0.0001 是正确答案么? 这取决于参与游戏的所有成员。
赢者通吃
这个游戏规定第一名得到全部的分数, 第二名(不管多接近)到倒数第二名都是 0 分,最后一名还要倒扣分。软件行业就是一个赢者通吃的坏境, 最后一名还要把自己的身家倒贴进去。
螳臂当车
在游戏中, 经常有一两个同学逆历史潮流, 提交一个 99.999 之类的分数。但是从大趋势来看, 这些捣乱分子对大局影响不大。我经常看到几个同学面带微笑小声商量,一起提交几个最高分来搅局,但是G-number 还是由大多数人决定。另外不是所有口头同意搅局的同学最后都“守约” 提交了大数字… 这也是“囚徒的困境”的一种。
只先一步
参加游戏的人都是在top N 的大学生, 或者IT 从业人员, 数学足够好, 都是聪明人。我把题目公布之后, 一些人马上就说– 这肯定收敛到0啦! 他们交上来一个 (0.00001 ) 的答案 (提交的数字必须大于 0 )。遗憾的是, 一起玩游戏的人其他人不这么想。 一个小团体, 或者一个小社会的社会共识 (consensus) 从来不是最激进的, 每个个体发出自己看似随机的声音, 它的进步是缓慢的, 有时还倒退一下。 如果只看微博上的发言, 你会觉得德先生和赛先生早已是国人的共识; 如果只参加最前沿的科技沙龙, 你会觉得明天大家都会用人体嵌入智能芯片同时会同步电子书邮件微博微信SNS再加GPS再有云计算,你如果不推出相应产品就会被淘汰… 但是社会作为一个整体还没有进步得这么快。
ch17 人、绩效和职业道德
RASCI模型
- R:Responsible,负责把具体事情做好
- A:Accountable,对任务负全责,有批准的权利
- S:Support,对任务提供支持,辅助任务的完成
- C:Consulted,咨询,拥有完成项目所需的信息或能力的角色
- I:Informed,知会者,应该事后及时通知结果的角色
职业道德是工作的基本原则,为了短期利益违反职业道德是得不偿失的。