NABC模型:
1) N (Need 需求)
2) A (Approach 做法)
3) B (Benefit 好处)
4) C (Competitors 竞争)
Provide “what’s in it for me” for stakeholders 对利益相关人要讲清楚能得到什么
Relative Advantage (创新和目前的应用相比, 有什么相对的优势)
Compatibility (创新和目前的应用是否兼容)
Complexity (避免过度地描述复杂的技术)
Observability & Trialability (能让别人看到/实验创新的结果么
First Mover, First Mover Advantage (FMA)
Second Mover, Second Mover Advantage (SMA)
软件工程包括了开发,运营, 维护软件的过程中有很多技术, 做法, 习惯, 和思想。软件工程把这些相关的技术和过程统一到一个体系中, 叫 “软件开发流程”,软件开发流程的目的是为了提高软件开发, 运营, 维护的效率;以及用户满意度, 可靠性,和软件的可维护性。
IC 在团队中的流程是怎么样的呢? 我们以开发人员为例:
• 理解问题或任务
• 提出多种解决办法并估计工作量
• 其中包括寻找以前的解决方案,因为很多工作是重复性的 – 例如实现某些类似的web页面。
• 与相关角色交流解决问题的提案, 决定最终方案
• 执行, 把想法变成实际中能工作的代码
• 修复缺陷, 对结果负责
VSTS效能分析工具:
选择两种分析方法:
(1) 抽样(Sampling)
(2) 代码注入(Instrumentation)
抽样就是当程序运行时,Visual Studio时不时看一看这个程序运行在哪一个函数内,并记录下来,程序结束后,Visual Studio就会得出一个关于程序运行时间分布的大致的印象。这种方法的优点是不需要改动程序,运行较快,可以很快地找到瓶颈。但是不能得出精确的数据,代码中的调用关系(CallTree)也不能准确表示。
另一方面,代码注入就是将检测的代码加入到每一个函数中,这样程序的一举一动都被记录在案,程序的各个效能数据都可以被精准地测量。这一方法的缺点是程序的运行时间会大大加长,还会产生很大的数据文件,数据分析的时间也相应增加。同时,注入的代码也影响了程序真实的运行情况(这有点像量子物理学中的“测试的光线干扰了测试物体本身”的现象)。
我们一般的做法是,先用抽样的方法找到效能瓶颈所在,然后对特定的模块用代码注入的方法进行详细分析。
解释单元测试的结构:
从上面这个例子可以看到创建单元测试函数的主要步骤:
(1)设置数据(一个假想的正确的E-mail地址);
(2)使用被测试类型的功能(用E-mail地址来创建一个User类的实体);
(3)比较实际结果和预期的结果(Assert.IsTrue(target != null);)。
单元测试:
单元测试应该产生可重复、一致的结果
独立性,单元测试的运行/通过/失败不依赖于别的测试,可以人为构造数据,以保持单元测试的独立性。
单元测试应该覆盖所有代码路径,包括错误处理路径,为了保证单元测试的代码覆盖率,单元测试必须测试公开的和私有的函数/方法
单元测试应该集成到自动测试的框架中
单元测试必须和产品代码一起保存和维护。
回归测试:
(1)验证新的代码的确把缺陷改正了。
(2)同时要验证新的代码没有把模块的现有功能破坏,没有Regression
最外层: 行为和后果
中间层: 习惯和动机
最内层: 本质和基本属性
1.类
(1)使用类来封装面向对象的概念和多态(Polymorphism)。
(2)避免传递类型实体的值,应该用指针传递。换句话说,对于简单的数据类型,没有必要用类来实现。
(3)对于有显式的构造和析构函数,不要建立全局的实体,因为你不知道它们在何时创建和消除。
(4)只有在必要的时候,才使用“类”。
2.Class vs. Struct
如果只是数据的封装,用Struct即可。
3.公共/保护/私有成员Public、Private和Protected
按照这样的次序来说明类中的成员:public、protected、private
4.数据成员
(1)数据类型的成员用m_name说明。
(2)不要使用公共的数据成员,要用inline访问函数,这样可同时兼顾封装和效率。
5.虚函数Virtual Functions
(1)使用虚函数来实现多态(Polymorphism)。
(2)只有在非常必要的时候,才使用虚函数。
(3)如果一个类型要实现多态,在基类(Base Class)中的析构函数应该是虚函数。
6.构造函数Constructors
(1)不要在构造函数中做复杂的操作,简单初始化所有数据成员即可。
(2)构造函数不应该返回错误(事实上也无法返回)。把可能出错的操作放到HrInit()或FInit()中。
7.析构函数
(1)把所有的清理工作都放在析构函数中。如果有些资源在析构函数之前就释放了,记住要重置这些成员为0或NULL。
(2)析构函数也不应该出错。
8.New和Delete
(1)如果可能,实现自己的New/Delete,这样可以方便地加上自己的跟踪和管理机制。自己的New/Delete可以包装系统提供的New/Delete。
(2)检查New的返回值。New不一定都成功。
(3)释放指针时不用检查NULL。
9.运算符(Operators)
(1)在理想状态下,我们定义的类不需要自定义操作符。只有当操作符的确需要时。
(2)运算符不要做标准语义之外的任何动作。例如,“==”的判断不能改变被比较实体的状态。
(3)运算符的实现必须非常有效率,如果有复杂的操作,应定义一个单独的函数。
(4)当你拿不定主意的时候,用成员函数,不要用运算符。
10.异常(Exceptions)
(1)异常是在“异乎寻常”的情况下出现的,它的设置和处理都要花费“异乎寻常”的开销,所以不要用异常作为逻辑控制来处理程序的主要流程。
(2)了解异常及处理异常的花销,在C++语言中,这是不可忽视的开销。
(3)当使用异常时,要注意在什么地方清理数据。
(4)异常不能跨过DLL或进程的边界来传递信息,所以异常不是万能的。
11.类型继承(Class Inheritance)
(1)当有必要的时候,才使用类型继承。
(2)用Const标注只读的参数(参数指向的数据是只读的,而不是参数本身)。
(3)用Const标注不改变数据的函数。
代码复审:
1.概要部分
(1)代码能符合需求和规格说明么?
(2)代码设计是否有周全的考虑?
(3)代码可读性如何?
(4)代码容易维护么?
(5)代码的每一行都执行并检查过了吗?
2.设计规范部分
(1)设计是否遵从已知的设计模式或项目中常用的模式?
(2)有没有硬编码或字符串/数字等存在?
(3)代码有没有依赖于某一平台,是否会影响将来的移植(如Win32到Win64)?
(4)开发者新写的代码能否用已有的Library/SDK/Framework中的功能实现?在本项目中是否存在类似的功能可以调用而不用全部重新实现?
(5)有没有无用的代码可以清除?(很多人想保留尽可能多的代码,因为以后可能会用上,这样导致程序文件中有很多注释掉的代码,这些代码都可以删除,因为源代码控制已经保存了原来的老代码。)
3.代码规范部分
(1)修改的部分符合代码标准和风格么(详细条文略)?
4.具体代码部分
(1)有没有对错误进行处理?对于调用的外部函数,是否检查了返回值或处理了异常?
(2)参数传递有无错误,字符串的长度是字节的长度还是字符(可能是单/双字节)的长度,是以0开始计数还是以1开始计数?
(3)边界条件是如何处理的?Switch语句的Default是如何处理的?循环有没有可能出现死循环?
(4)有没有使用断言(Assert)来保证我们认为不变的条件真的满足?
(5)对资源的利用,是在哪里申请,在哪里释放的?有没有可能导致资源泄露(内存、文件、各种GUI资源、数据库访问的连接,等等)?有没有可能优化?
(6)数据结构中是否有无用的元素?
5.效能
(1)代码的效能(Performance)如何?最坏的情况是怎样的?
(2)代码中,特别是循环中是否有明显可优化的部分(C++中反复创建类,C#中 string 的操作是否能用StringBuilder 来优化)?
(3)对于系统和网络调用是否会超时?如何处理?
6.可读性
代码可读性如何?有没有足够的注释?
7.可测试性
代码是否需要更新或创建新的单元测试?
还可以有针对特定领域开发(如数据库、网页、多线程等)的核查表。
复杂的合作模式:
R: Responsible, 负责把具体事情做好。
A: Accountable, 对任务负全责, 有批准的权力
S: Support, 对任务提供支持, 辅助任务的完成
C: Consulted, 咨询, 拥有完成项目所需的信息或能力的角色。
I: Informed, 知会者, 应该事后及时通知结果的角色。
绩效管理:
完成任务维度,团队贡献维度
敏捷开发流程:
敏捷开发原则:
尽早并持续地交付有价值的软件以满足顾客需求。
敏捷流程欢迎需求的变化, 并利用这种变化来提高用户的竞争优势。
经常发布可用的软件,发布间隔可以从几周到几个月,能短则短
业务人员和开发人员在项目开发过程中应该每天共同工作。
以有进取心的人为项目核心,充分支持信任他们
无论团队内外,面对面的交流始终是最有效的沟通方式
可用的软件是衡量项目进展的主要指标
敏捷流程应能保持可持续的发展。 领导, 团队和用户应该能按照目前步调持续合作下去
只有不断关注技术和设计才能越来越敏捷.
保持简明 - 尽可能简化工作量的技艺 - 极为重要。英文说 maximizing the amount of work not done. 我的理解是 - 任何还没有明确的工作都会花不可知的时间,因此要 maximize, 不要把那些还没有做的工作和正在做的工作混起来。
只有能自我管理的团队才能创造优秀的架构, 需求和设计.
时时总结如何提高团队效率, 并付诸行动
敏捷Scrum和Sprint的开发流程:
第一步: 找出完成产品需要做的事情 – Product Backlog
产品负责人主导大家对于这个Backlog 进行 增/删/改 的工作
第二步: 决定当前的冲刺需要解决的事情 – Sprint Backlog.
任务被进一步细化了,被分解为以小时为单位。如果一个任务的估计时间太长 (例如 超过16个小时),那么它就应该被进一步分解。 冲刺订单上的任务不会被分派,而是由团队成员签名认领他们喜爱的任务。 团队成员能主导任务的估计和分配, 他们的能动性得到较大的发挥。
第三步: 冲刺 (Sprint).
在冲刺阶段, 外部人士不能直接打扰团队成员。 一切对交流只能通过SCRUM MASTER 来完成。 这一措施较好地平衡了 “交流”和 “集中注意力”的矛盾
第四步: 得到软件的一个增量版本,然后在此基础上又进一步计划增量的新功能和改进
MSF:
MSF八个基本原则:
1)推动信息共享与沟通(Foster open communications)
(2)为共同的远景而工作(Work toward a shared vision)
(3)充分授权和信任(Empower team members)
(4)各司其职,对项目共同负责(Establish clear accountability and shared responsibility)
(5)重视商业价值(Focus on delivering business value)
(6)保持敏捷,预期变化(Stay agile, expect change)
(7)投资质量(Invest in quality)
(8)学习所有的经验(Learn from all experiences)
MSF团队模型:
MSF过程模型:
Postmortem
现代软件工程 项目Postmortem 模板
邹欣
现代软件工程 课件
2011
设想和目标
1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述?
2. 是否有充足的时间来做计划?
3. 团队在计划阶段是如何解决同事们对于计划的不同意见的?
如果历史重来一遍, 我们会做什么改进?
计划
1. 你原计划的工作是否最后都做完了? 如果有没做完的,为什么?
2. 有没有发现你做了一些事后看来没必要或没多大价值的事?
3. 是否每一项任务都有清楚定义和衡量的交付件?
4. 是否项目的整个过程都按照计划进行?
5. 在计划中有没有留下缓冲区,缓冲区有作用么?
6. 将来的计划会做什么修改?(例如:缓冲区的定义,加班)
如果历史重来一遍, 我们会做什么改进?
资源
1. 我们有足够的资源来完成各项任务么?
2. 各项任务所需的时间和其他资源是如何估计的,精度如何?
3. 用户测试的时间,人力和软件/硬件资源是否足够?
4. 你有没有感到你做的事情可以让别人来做(更有效率)?
如果历史重来一遍, 我们会做什么改进?
变更管理
1. 每个相关的员工都及时知道了变更的消息?
2. 我们采用了什么办法决定“推迟”和“必须实现”的功能?
3. 项目的出口条件 (Exit Criteria – 什么叫 “做好了”)有清晰的定义么?
4. 对于可能的变更是否能制定应急计划?
5. 员工是否能够有效地处理意料之外的工作请求?
如果历史重来一遍, 我们会做什么改进?
设计/实现
1. 设计工作在什么时候,由谁来完成的?是合适的时间,合适的人么?
2. 设计工作有没有碰到模棱两可的情况,团队是如何解决的?
3. 团队是否运用单元测试(unit test),测试驱动的开发(TDD)、UML, 或者其他工具来帮助设计和实现?这些工具有效么?
4. 什么功能产生的Bug最多,为什么?
5. 代码复审 (Code Review)是如何进行的,是否严格执行了代码规范?
如果历史重来一遍, 我们会做什么改进?
测试/发布
1. 团队是否有一个测试计划?为什么没有?
2. 是否进行了正式的验收测试?
3. 团队是否有测试工具来帮助测试?
4. 团队是如何测量并跟踪软件的效能的?从软件实际运行的结果来看,这些测试工作有用么?应该有哪些改进?
5. 在发布的过程中发现了哪些意外问题?
如果历史重来一遍, 我们会做什么改进?
PM的任务:
带领团队形成团队的目标/远景, 把抽象的目标转化为可执行的, 具体的, 优美的设计。
管理软件的具体功能的生命周期 (需求/设想/设计/实现/测试/修改/发布/升级/迁移/淘汰)。
创建并维护软件的功能说明书 (specification), 让它成为开发/测试的及时准确的指导, 而不是障碍。
代表客户和用户的利益, 主动收集用户反馈, 预期用户新的需求。 协调并决定各种需求的优先级。
分析并带领其他成员形成对缺陷/变更需求的一致意见, 并确保实施。
带领其他成员确保项目保持 功能/时间/资源 的合理平衡, 跟踪项目进展, 确保团队发布让客户满意的软件。
收集团队项目管理和软件工程的各种数据, 客观地分析项目实施过程中的优缺点, 推动项目成员持续改进, 从而提振士气。
DEV的工作:
理解问题或任务
• 提出多种解决办法并估计工作量
• 其中包括寻找以前的解决方案,因为很多工作是重复性的 – 例如实现某些类似的web页面。
• 与相关角色交流解决问题的提案, 决定最终方案
• 执行, 把想法变成实际中能工作的代码
• 修复缺陷, 对结果负责
、、、一个软件工程师在接到一个任务之后应该怎么做:
PSP2.1 |
|
Planning
Development
Record Time Spent Test Report Size Measurement Postmortem Process Improvement Plan |
计划
开发
记录时间花费 测试报告 计算工作量 事后总结 提出过程改进计划 |
QA: 运用各种手段, 在软件工程的各个阶段确保软件的质量能帮助软件团队实现目标。
Test (测试) : 特指验证代码的行为是否符合功能规格说明书 (spec) 的规定。
Bug可以分为这三个组成部分:症状(Symptom)、程序错误(Fault)、根本原因(Root cause)。
(1)Symptom:即从用户的角度看,软件出了什么问题。
例如,在输入(3 2 1 1)的时候,程序错误退出。
(2)Fault:即从代码的角度看,代码的什么错误导致了软件的问题。
例如,代码在输入为某种情况下访问了非法的内存地址——0X0000000C。
(3)Root Cause:错误根源,即导致代码错误的根本原因。
例如,代码对于id1==id2的情况没有做正确判断,从而引用了未赋初值的变量,产生了以上的情况。
测试设计有两类方法:Black box(黑箱)、White box(白箱):
黑箱:在设计测试的过程中,把软件系统当作一个“黑箱”,无法了解或使用系统的内部结构及知识。一个更准确的说法是“Behavioral Test Design”,从软件的行为,而不是内部结构出发来设计测试。
白箱:在设计测试的过程中,设计者可以“看到”软件系统的内部结构,并且使用软件的内部知识来指导测试数据及方法的选择。“白箱”并不是一个精确的说法,因为把箱子涂成白色,同样也看不见箱子里的东西。有人建议用“玻璃箱”来表示。
测试分类:
1, 功能测试:
表7-1 功能测试分类
测试名称 |
测试内容 |
Unit Test |
单元测试——在最低的功能/参数上验证程序的正确性 |
Functional Test |
功能测试——验证模块的功能 |
Integration Test |
集成测试——验证几个互相有依赖关系的模块的功能 |
Scenario Test |
场景测试——验证几个模块是否能够完成一个用户场景 |
测试名称 |
测试内容 |
System Test |
系统测试——对于整个系统功能的测试 |
Alpha/Beta Test |
外部软件测试人员(Alpha/Beta测试员)在实际用户环境中对软件进行全面的测试 |
2, 非功能测试:
非功能测试
测试名称 |
测试内容 |
Stress/load test |
测试软件在负载情况下能否正常工作 |
Performance test |
测试软件的效能 |
Accessibility test |
可访问性测试——测试软件是否向残疾用户提供足够的辅助功能 |
Localization/Globalization Test |
本地化/全球化测试 |
Compatibility Test |
兼容性测试 |
Configuration Test |
配置测试——测试软件在各种配置下能否正常工作 |
Usability Test |
易用性测试——测试软件是否好用 |
Security Test |
软件安全性测试 |
典型用户:
(1)名字(越自然越好)。
(2)年龄(不同年龄和收入的用户有不同的需求)。
(3)收入。
(4)代表的用户在市场上的比例和重要性(比例大不等同于重要性高,如付费的用户比例较少,但是影响大,所以更重要)。
(5)使用这个软件的典型场景。
(6)使用本软件/服务的环境。
(7)生活/工作情况。
(8)知识层次和能力(教育程度,对电脑、万维网的熟悉程度)。
(9)用户的动机、目的和困难(困难 = 需要解决的问题)。
(10)用户的偏好。
场景:
对每一个场景,设计一个场景入口(描述场景如何开始)。
描述典型用户在这个场景中所处的内部和外部环境(内部环境指心理因素等)。
给场景划分优先级,就按优先级排序。
任务:举例:
(1)UI层。子任务为:界面设计,货物资料处理,文件上传处理,编辑控件等。
(2)逻辑层。子任务为:用户输入字段合法性处理,上传图像逻辑和缩略图处理,资料保存逻辑等。
(3)数据库。子任务为:资料读取的存储过程,图像的索引建立和维护等。
在计划阶段,我们就要制定测试计划(Test Plan),特别是测试总纲。然后还要写测试设计规格说明书 (TDS)、测试用例(Test Case)、程序错误报告(Bug Report)和测试报告(Test Report)。