《构建之法》邹欣pdf:https://pan.baidu.com/s/1Z7cTtVBqxbVcU3vsyynysQ 提取码:dusr
章1.概论
软件=程序+软件工程
写程序练习数据结构/算法,用新的语言尝试以下“hello world”->用JavaScrip、ASP.NET、Ruby写写网站->钻研新技术,应用新技术在软件行业创新->银行软件系统,互联网搜索行业,淘宝、Windows操作系统
软件工程是什么
软件工程是把系统的、有序的、可量化的方法应用到软件的开发、运营和维护上 的过程
软件的特殊性
软件的各种形式:
- 系统软件:操作系统、设备驱动程序、工具软件等
- 应用软件:用户使用它们来完成工作,从管理核电厂到写文章,或者是通信、 游、浏览网页、播放视频等
- 恶意软件:软件病毒等软件
软件开发过程中有什么特别的难题?
- 复杂性(Complexity):软件的各个模块之间有各种显性或隐性的依赖关系,随着系统的成长和 模块的增多,这些关系的数量往往以几何级数的速度增长
- 不可见性(Invisibility):工程师是“看”不到自己的源代码如 何具体地在用户的机器上被执行的。商用软件出现了错误,工程师可以看到程序 在出错的一瞬间留下的一些痕迹(错误代号、大致的目标代码位置、错误信 息),但是几乎无法完整重现到底程序出现了什么问题
- 易变性(Changeability):正确地修改软件是一件很困难的事情。
- 服从性(Conformity):软件总是要运行在硬件上面,它要服从系统中其他组成部分的 要求,它还要服从用户的要求、行业系统的要求
- 非连续性(Discontinuity):有时输入上很小的变化,会引起输出上极大的变化
软件的这些本质特性让“做一个好软件”变得很难,同时也让软件工程有它独特的挑战和魅力
软件工程与计算机科学的关系
工程:创造性地运用科学原理,设计和实现建筑、机器、装置或生产过程;或者是在实践中使用一个或多个上述实体;或者是实现这些实体的过
托尼·霍尔(Tony Hoare)比较计算机科学和软件工程不同的侧重点:
计算机科学 软件工程 发现和研究长期的、客观的真理 短期的实际结果(具体的软件会过时) 理想化的 对各种因素的折衷 确定性,完美,通用性 对不确定性和风险的管理,足够好,具体的应用 各个学科独立深入研究,做出成果 关注和应用各个相关学科的知识,解决问题 理论的统一 百花齐放的实践方法 强调原创性 最好的、成熟的实践方法 形式化,追求简明的公示 在实践中建立起来的灵感和直觉 正确性 可靠性
软件工程的目标--创造“足够好”的软件
好软件--没有缺陷(Bug) | 软件工程--把软件中的Bug都消灭掉的过程
用户满意度:用户使用时发现了很多Bug,影响了用户使用软件的效率。
可靠性:某个软件经常会崩溃,某个操作系统会时不时死机。
软件流程的质量:软件团队和开发流程的问题太多,导致团队成员无法互相协 作,按时交付软件。这也可以说是软件团队的Bug。
可维护性:某个软件太难维护了,按下葫芦起了瓢,修复了一个问题,另一个问 题又出来了。也没有足够的文档,维护人员表示需要更多的资金和时间来维护这 个软件
章2.个人技术和流程
单元测试
如何能让自己负 责的模块功能定义尽量明确,模块内部的改变不会影响其他模块,而且模块的质 量能得到稳定的、量化的保证?单元测试就是一个很有效的解决方案。
因为可将程序的功能分为可作为单个单元 测试的独立可测试行为,所以它叫做单元测试
只要你编写了一个函数或其他应用程序代码块,就可以创建单元测试用于验证对应于输入数据的标准、边界和不正确情况的代码的行为,而且用于检查代码所做的任何显式或隐式假设
用VSTS (Visual Studio Team System) 写单元测试
简单例子
新建一个控制台程序ConsoleApp2,在Program.cs添加如下类:
public class CheckingAccount { public double m_balance; string name; public CheckingAccount(string name,double balance) { this.name = name; m_balance = balance; } public void Withdraw(double amount) { if (m_balance >= amount) { m_balance -= amount; } else { throw new ArgumentException(nameof(amount), "Withdrawal exceeds balance!"); } } }
右击Withdraw方法点击创建单元测试
在生成的CheckingAccountTests.cs中添加测试方法
[TestMethod()] public void Withdraw_ValidAmount_ChangesBalance() { double currentBalance = 10.0; double withdrawal = 1.0; double expected = 9.0; var account = new CheckingAccount("hhq", currentBalance); account.Withdraw(withdrawal); Assert.AreEqual(expected, account.m_balance); }
打开测试资源管理器,选择相应方法进行测试
更多内容
Visual Studio文档单元测试:https://docs.microsoft.com/zh-cn/visualstudio/test/getting-started-with-unit-testing?view=vs-2019
好的单元测试的标准
单元测试应该准确、快速地保证程序基本模块的正确性,单元测试应该在最基本的功能/参 数上验证程序的正确性。单元测试应该测试程序中最基本的单元—如在 C++/C#/Java中的类,在此基础上,可以测试一些系统中最基本的功能点(这些 功能点由几个基本类组成)
回归测试
在单元测试的基础上,我们就能够建立关于这一模块的回归测试(Regression Test)
在软件项目中,如果一个模块或功能以前是正常工作 的,但是在一个新的构建中出了问题,那么这个模块就出现了一个“退步”(Regression),从正常工作的稳定状态退化到不正常工作的不稳定状态。在 一个模块的功能逐步完成的同时,与此功能有关的测试用例也同样在完善中。一 旦有关的测试用例通过,我们就得到了此模块的功能基准线(Baseline),一个模块的所有单元测试就是这个模块最初的Baseline,一个 模块的所有单元测试就是这个模块最初的Baseline。工程师们应该在新版本上运行所有 已通过的测试用例,以验证有没有“退化”情况发生,这个过程就是一 个“Regression Test”。
效能分析工具
个人开发流程
PSP(Personal Software Process)
PSP有如下特点:
- 不局限于某一种软件技术(如编程语言),而是着眼于软件开发的流程,这 样,开发不同应用的软件工程师可以互相比较。
- 不依赖于考试,而主要靠工程师自己收集数据,然后分析,提高
- 在小型、初创的团队中,很难找到高质量的项目需求,这意味着给程序员的输 入质量不高。在这种情况下,程序员的输出(程序/软件)往往质量也不高, 然而这并不能全部由程序员负责
- PSP依赖于数据
- 需要工程师输入数据,记录工程师的各项活动,这本身就需要不小的时间代价
- 如果数据不准确或有遗失,怎么办?让工程师编造一些?
- 如果一些数据不利于工程师本人(例如:花很多时间修改缺陷),我们怎么能 保证工程师愿意如实地记录这些数据呢?
- PSP的目的是记录工程师如何实现需求的效率,而不是记录顾客对产品的满意度
软件工程师的任务清单:
PSP2.1 计划 开发
- 估计这个任务需要多少时间
记录用时 测试报告 计算工作量 事后总结 提出过程改进计划
- 分析需求
- 生成设计文档
- 设计复审(和同事审核设计文档)
- 代码规范(为目前的开发制定合适的规范)
- 具体设计
- 具体编码
- 代码复审
- 测试(包括自测,修改代码,提交修改)
章3.软件工程师的成长
个人能力的衡量与发展
软件系统的绝大部分模块都是由个人开发或维护的。在 软件工程的术语中,我们把这些单个的成员叫做Individ-ual Contributor(IC)。 IC在团队中的流程是怎么样的呢?以开发人员为例,流程如下:
- 通过交流、实验、快速原型等方法,理解问题、需求或任务
- 提出多种解决办法并估计工作量
- 其中包括寻找以前的解决方案,因为很多工作是重复性的
- 与相关角色交流解决问题的提案,决定一个可行的方案
- 执行,把想法变成实际中能工作的代码,同时验证方案的可行性和其他特性 (例如程序的效能等)
- 和团队的其他角色合作,在测试环境中测试实现方案,修复缺陷(Bug)。如 果此方案有严重的问题,那么就考虑其他方案
- 在解决方案发布出去之后,对结果负责每个人的工作质量直接影响最终软件的 质量
什么样的数据能说明一个软件工程师的技术和能力呢?衡量能力有哪 些参数?没有量化的指标,就谈不上衡量和比较。我们还是看看搬砖的伙计们, 关于工作量,他们:
- 有多少块砖?
- 要搬多远?他们也有简单的指标衡量工作质量。
- 多快搬完?
- 搬的过程中损坏了多少块砖?
初级软件工程师如何成长?
- 积累软件开发相关的知识,提升技术技能(如对具体技术的掌握,动手能 力)。例如:对Java、C/C++、C#的掌握,诊断/提高效能的技术,对设备驱动程序(Device Driver)、内核调试器(Kernel Debugger)的掌握;对于某一开发平台的掌握
- 积累问题领域的知识和经验(例如:对医疗或金融行业的了解)。第一点和第二点都可以在很多简历上都可以看到,也可以比较容易地检测出来。随着经验的 增长,一个工程师可以掌握更广泛、更深入的技术和问题领域的知识。
- 对通用的软件设计思想和软件工程思想的理解。这一方面就比较虚,什么是好的软件设计思想?什么是好的软件工程思想?一个工程师开了博客,转发了很多别人的文章,这算有思想么?另一个工程师坚持做任何设计都要画UML图,这算有思想么?
- 提升职业技能(区别于技术技能)。职业技能包括:自我管理的能力,表达和交流的能力,与人合作的能力,按质按量完成任务的执行力,这些能力在IT行业和其他行业都很重要
- 实际成果。绝大部分软件工程师的工作成果都是可以公开的,你参与的产品用 户评价如何,市场占有率如何,对用户有多大价值?你在其中起了什么作用?
软件工程师的职业发展
就软件工程师这个职业而言,有很多证明 个人能力的办法和模型,下面简单介绍几种
职业发展----考级之路
在中国,软件工程师的职业资格考试有:
- 计算机等级考试和全国计算机技术与软件专业技术资格考试
此类考级的好处:国家认证,有一定的权威性和通用性;任何人都可以参与
局限性:以答题/评分为主要考试形式,没有面对面的口试;考试中每个人单独行动,不能考量团队合作能力;要考虑到通用性和稳定性,考题内容相对滞后于工业界的发展,部分内容相当滞后
很多公司也提供了针对自己产品的职业认证项目,如:
- 微软公司有微软认证专家(Microsoft Certi-fied Professional,MCP)
- 甲骨文公司有Oracle认证项目(Oracle Certi-fication Program,OCP)
国内也有机构和学校探索各种能力和认证考试服务,如:
- 中国计算机协会计算机职业资格认证考试:http://cspro.ccf.org.cn
- 有以浙江大学计算机学院为首开发的计算机程序设计能力考试:http://pat.zju.edu.cn/
职业成长----Steve McConnell
一个软件工程师需要具备一定的知识和能力:
知识:迈克康奈尔把相关的软件知识分为十大知识领域
能力:一个工程师对这些知识的掌握分为如下四个阶段
入门(Introductory);
熟练(Competency);
带头人(Leadership);
大师(Mastery)
迈克康奈 尔把工程师分为8个级别(8—15),一个工程师要从一个级别升到另一个级别, 需要在各方面达到一定的要求。例如,要达到12级,工程师必须在三个知识领域 达到“带头人”水平。例如要到达“工程管理(知识领域)的熟练(能力)”水平,工 程师必须要做到以下几点:
- 阅读:4—6个经典文献的深入分析和阅读
- 工作经验:要参与并完成6个具体的项目
- 课程:要参加3个专门的课程有些级别
职业成长----大公司版本
微软公司的软件工程师职业等级:
等级 要求 SDE(初级软件开发工程师) 入门。在学校里学到了一些技能 SEE II(中级软件开发工程师) 独立。可以写别人交给你的任何东西,不明白时知道去问谁 Senior SDE(高级软件开发工程师) 小组领导。影响着3~12名工程师,或者是它们的行政领导;或者是它们的技术带头人 Principal SDE(首席软件开发工程师) 团队领导。影响着10人以上的一个大团队,成为影响团队成败的关键人物 更高的职位有:
Partner SDE
Distinguished Engineer
Technical Fellow影响力扩大到整个机构,甚至工业界 职业成长----自我评估
并不是每个软件工程师都有强烈的愿望或机遇去做最先进、最创新、最有风险的项目。绝大部分软件工程师都不是技术天才,但即使是一般的工程师,做一般的信息系统,就是业界说的“CRUD”(Cre-ate/Retrieve/Update/Delete,增删改查)数据库系统,也需要一些核心技术和许多扩展的知识:
基本需求 基本技术 扩展技术 进一步的扩展技术 把数据放到数据库中满足增删改查的需求 数据库技术(关系数据库的基本原理和操作) 大容量的数据库操作、并行、备份等技术 关系数据库模型,数据挖掘,商业智能 有网页满足一般用户的查询需求 网页服务技术(ASP.NET、PHP等),数据绑定及控件 用户界面的设计,对不同浏览器的支持 用户心理,用户交互的原则在不同设备和不同场景下的应用 能不断实现新的功能 编程语言和开发工具(Java、C#、Python) 程序的效能分析,软件的重用,面向对象的理论等 能改进软件工具,或构建新的语言提高解决问题的效率 软件团队能按时高质量完成任务 每日构建,版本管理,单元测试,项目管理 需求分析,敏捷开发等高级软件工程的技术 软件团队的绩效评估,团队的发展 要有一定的安全性 数据安全、网站的安全 计算机网络与数据通讯,操作系统的知识,数据加密解密 密码学,各种病毒工作原理 能满足业务的需求 对业务领域有基本的了解 进一步了解业务领域知识 对业务领域有深入了解,能洞察行业发展的趋势
很少有人能在学校里掌握这么多知识后才毕业找工作,随后把技术运用在实践中。工程师应该在实际工作中不断学习和不断成长,根据自己的情况选择在哪个方面追求“专和精”,在哪几个方面达到“知道就好”的水平
技能的反面
巴克斯顿说技能的反面是“Problem Solving”—“解决问题“
一个例子:
一个IT专业的大学生来面试,简历上写“技 能:精通Visual Studio C#编程”。于是面试官请他用Visual Studio IDE写一段程 序。一个“不精通”的面试者的编程过程实际上就是一个“解决问题”的过程。例如:
嗯,怎么开始一个C#的命令行程序呢? 定义数组是怎么弄的?是“int [] arr”还是“int arr[]”,还是ArrayList, 还是Array。哦,我平时都是上网查的。哦,我不知道还有MSDN网站。 嗯,为什么编译没过呢,哦,这里少一个分号。 嗯,怎么设断点?怎么定义命令行参数?额,
我要查一查……你发现他把时间都花在“解决(低层次)问题”上了,你想考察的“算法技能”、“C#程序设计技能”都无暇顾及。注意,这是在他认为非常精通的编程工具和编程语言中出现这样的问题。你要这样的员工么?那怎么提高技能呢?答案很简单,通过不断的练习,把那些低层次的问题都解决了,变成不用经过大脑的自动操作,然后才有时间和脑力来解决较高层次的问题