CH01 概论
软件 = 程序 + 软件工程
软件架构(SoftwareArchitecture)
软件设计与实现(Software Design, Implementation and Debug)
源代码管理(Source Code Control)
配置管理(Software Configuration Management)
质量保障(Quality Assurance):一系列的工具和程序来保证程序的正确性, 这些工具流程和程序本身应该更正确
软件测试(Testing): 具体的验证过程
软件的生命周期(Software Life Cycle, SLC)
Requirement Analysis -> program Comprehension -> Software Maintenance -> Service Operation
程序(算法、 数据结构)是基本功, 但是在算法和数据结构之上, 软件工程决定了软件的质量; 商业模式决定了一个软件企业的成败。
软件开发的不同阶段
软件工程
软件工程是把系统的、 有序的、 可量化的方法应用到软件的开发、 运营和维护上的过程。
软件工程包括:
- 软件需求分析
- 软件设计
- 软件构建
- 软件测试
- 软件维护
软件的特殊性
- 复杂性
- 不可见性
- 易变性
- 服从性
- 非连续性
软件工程和计算机科学的关系
软件工程的研究目标(软件的开发、 运营和维护) 都有“人”出现, 这些“人”可以是项目需求的提供者, 可以是软件的开发人员, 还可以是软件的用户。 这一特征与其他计算机科学的子领域明显不同。
软件工程的知识领域
- Software Requirements
- Software Design
- Software Construction
- Software Testing
- Software Maintenance
- Software Contribution Management
- Software Engineering Management
- Software Engineering Process
- Software Engineering Models and Methods
- Software Quality
- Software Engineering Professional Practice
- Software Engineering Economics
- Comuting Foundations
- Mathematical Foundations
- Engineering Foundations
软件工程的目标 -- 创造足够好的软件
学习的目标:
- 研发出符合用户需求的软件说明:要通过实际的工作收集、推导、提炼需求,并在软件发布后通过实际数据验证的确满足用户的需求。需求来源于实际,而不是自己虚构出来的抑或是人云亦云的需求(如图书管理系统)。
- 通过一定的软件流程再预计的时间内发布“足够好”的软件说明:这个软件是通过全体团队成员的努力,在一个学期中逐步完成的。
- 要通过数据和其他方式展现所开发的软件是可以维护的:例如,对用户的需求有详细的分析,包括对将来这类软件发展趋势的分析;主要功能都有设计文档,源代码完整,有修改记录(版本控制),并且有 release 版本;关键模块有可以执行的单元测试、压力测试脚本,等等。对于已知的 bug 和将来的工作都有详细的记录。
CH02 个人技术和流程
单元测试
单元测试是为了某一模块功能定义尽量明确,模块内部的改变不会影响到其他模块,而且模块的的质量能得到稳定、量化的包装。
创建单元测试的主要步骤
- 设置数据
- 使用被测试类型的功能
- 比较实际结果与预期结果
单元测试最好在一开始就开始逐步嵌套在开发过程中,而不是等所有功能模块都全部整合在一起后才开始。在写技术模块的规格说明书(Specfication)的时候,要越详细越好,最好各项要求都可以表示为一个单元测试用例。
好的单元测试的标准
单元测试应该明确、快速的保证程序基本模块的正确性。
单元测试应该在最基本的功能/参数上验证程序的正确性。
从面向对象的设计原理出发,系统中最基本的功能点也应该由一个类及其方法来表现。
单元测试要测试 API 中的每一个方法及每一个参数。
单元测试必须是由最熟悉代码的人来书写。
最好在设计的时候就写好单元测试,这样单元测试九年体现 API 语义的准确性。
单元测试后,机器状态保持不变,这样才能不断地运行单元测试,得到相同的结果。如果单元程序创建了临时文件或目录,应该在结束阶段删除;如果单元测试修改了数据库,那么在结束前应该恢复数据库记录状态。
单元测试要块,一个测试的运行时间是几秒钟,而不是几分钟。
单元测试应该产生可再现、一致的结果。
一般情况下,不要用随机数来增加单元测试的真实性。
单元测试应该覆盖所测单元的所有代码路径,包括错误处理路径。
为保证代码覆盖率(Coverage),单元测试必须测试公开的和私有的方法。
单元测试应该集成到自动测试的框架中。
单元测试必须和代码一起进行版本维护。
回归测试(Regression)
Regress 的英语定义:return to worse or less developed state,也就是倒退、退化的意思。
在一个软件项目中,如果一个模块的新版本出现了问题,那么这个模块就出现了一个 Regression。
我们在开发一个模块的过程中,一旦有关的测试都通过了,我们就得到了一个功能基准线(Baseline),也可称作 Benchmark。
在新版本是要运行所有以通过的测试用例,已验证有无退化的情况发生,这个过程就是一个 “Regression Test”。
如果退化的原因是因为新功能引起的,我们应该修改 Benchmark,以便和新功能保持同步。
针对一个 Bug Fix,我们也要做 Regression Test 来保证新的代码在没有破坏其他模块的前提下修复了已知 bug。
回归测试最好要自动化,这样就能对每一次构建快速运行所有的回归测试,以尽早发现问题。
单元测试是回归测试是基础。
在一个项目的最后稳定阶段,所有人都要参加全面的测试工作,把所有之前发现并修复的 Bug 找出来,逐个验证,以保证所有已修复 bug 真正地得到了修复,这也是一个大规范的、全面的回归测试。
CH03 软件工程师的成长
个人能力的衡量和发展
衡量能力的参数:
- 由多少任务?
- 能完成到什么程度?
- 多快完成?
- 执行的过程中多少任务失败了?
初级软件工程师如何成长?
- 积累软件开发相关的知识,提升技术技能(如对具体技术的掌握,动手实践能力)。例如:对 Java、C/C++、C# 的掌握,诊断/提高性能的技术,对驱动设备程序(Device Driver)、内核调试器(Kernel Debugger)的掌握;对于某一开发平台的掌握。
- 积累问题领域的知识和经验(例如:对金融行业的了解)。
- 对通用的软件设计思想和软件工程思想的理解。在这一方面就比较虚,什么是好的软件设计思想?什么是好的软件工程思想?
- 提升职业技能(区别于技术技能)。职业技能包括:自我管理能力,表达和交流能力,团队协作能力,保质保量完成任务的执行力。
- 实际成果。绝大部分软件工程师的工作成果都是可以公开的,你参与的产品用户评价如何,市场占有率如何,对用户由多大价值?你在其中参与了哪些工作?
软件开发的工作量和质量如何衡量呢?PSP 认为由以下 4 个因素:
项目/任务有多大?说明项目的大小,一般可以用代码行数(Line Of Code)来表示;也可以用功能点(Function Point)来表示。
花了多少时间?可以用小时、天、月、年来表示;也可以用人月表示一组人所花费的时间。
质量如何?交付的代码中由多少缺陷?
交付有两个定义:
- 在代码完成时(Code Complete),交付给测试人员
- 在软件最终发布时,交付给用户可以用 bug 的数量来除以项目的大小。
是否按时交付?
平均用时少的人更优秀吗?其实我们应该从标准方差(Standard Deviation)评判一个员工的稳定性。软件项目的确需要创造性,需要一些惊喜。但是,更多的是常规的、可重复的任务。
软件领域可以分为两个方面:一方面是技艺程序的大爆发;另一方面是坚持不懈的工程工作,包括软件的改善、测试和维护等,这一方面占了 90 % - 95% 的比例。如果你能长时间稳定而按时的交付工作的结果,内部和外部的顾客就会对你的工作有信心,更喜欢与你合作。
软件工程师的职业发展
职业发展 - 考级之路
中国软件工程师的职业资格考试有:
- 计算机等级考试
- 全国计算机技术与软件专业资格考试
还有一些公司针对自己产品的职业认证项目(Certified Program)
- 微软公司有微软认证专家(Microsoft Certified Professional, MCP)
- 甲骨文公式有 Oracle 认证项目(Oracle Certification Program, OCP)
获得了相应公司和行业的认证,工程师就会更容易得到相应的工作、合作机会。
职业成长 - Steve McConnell
一个工程师对相关的软件知识的掌握程度分为如下 4 个阶段:
- 入门(Introductory)
- 熟练(Completency)
- 带头人(Leadership)
- 大师(Mastery)
工程师有职业成长级别(Professional Develepment Ladder)。麦克康纳尔把工程师分为 8 个级别(8-15),一个工程师要从一个级别升到另一个级别需要在各方面达到一定的要求。
职业成长 - 大公司版本
等级 | 要求 |
---|---|
SDE(初级软件开发工程师) | 入门。在学校里学到了一些技能,尚未在实践中欧给得到充分锻炼。 |
SDE II(中级软件开发工程师) | 独立。可以写别人交给你的任何东西,不明白是知道去问谁 |
Senior SDE(高级软件开发工程师) | 小组领导。带领着 3 - 12 名工程师,或者是他们的行政领导/技术带头人 |
Principal SDE(首席软件开发工程师) | 团队领导。带领着 10 人以上的大团队,成为影响团队成败的关键任务 |
其他更高级的职位 | 影响力扩到到整个机构,甚至工业界 |
职业成长 - 自我评估
绝大部分软件工程师都不是技术天才,将来可能都是做一般的重复性工作(CRUD),但即使是一般的工作,也需要一些核心技术和许多扩展知识:
基本需求 | 基本技术 | 扩展技术 | 进一步的扩展技术 |
---|---|---|---|
把数据放到数据库中实现CRUD的需求 | 数据库技术 | 大容量的数据库操作、并行、备份等技术 | 关系数据库模型、数据挖掘 |
有网页满足一般用户的查询需求 | 网页服务技术(ASP.NET、PHP等),数据绑定及控件 | 用户界面的设计,对不同浏览器的支持 | 跨设备、跨场景应用 |
能不断实现新的功能 | 编程语言和开发工具(Java、C#、Python) | 程序的性能分析,软件的重用,面向对象的理论等 | 能改进软件工具,或构建新的语言提高解决问题的效率 |
软件团队能按时高质量完成任务 | 每日构建、版本管理、单元测试、项目管理 | 需求分析,敏捷开发等高级软件工程的技术 | 软件团队的绩效评估、发展 |
要有一定的安全性 | 数据库安全、网站安全 | 计算机网络与数据通讯,操作系统的知识,数据加密解密 | 密码学,各种病毒工作原理 |
能满足业务需求 | 对业务领域有基本的了解 | 进一步了解业务领域知识 | 对业务领域有深入的了解,能洞察行业发展的趋势 |
很少有人能在学校里掌握这么多知识后再毕业找工作,随后把技术应用在实践中。工程师应该在实践工作中不断学习和不断成长,根据自己的情况下选择在哪个方面追求“专和精”,在哪几个方面达到“了解”的水平。
技能的反面
技能的反面是“Program Solving”- “解决问题”。举个例子:一个“不精通”的面试者给编程过程实际上就是一个“解决问题”的过程。
那么如何提过技能呢?答案很简单,通过不断的练习,把那些低层次的问题都解决了,变成不用经过大脑的自动操作,然后才有时间和精力来解决高层次的问题。