01 软件工程基础

Posted on Wed, 25 Dec 2024 16:54:20 +0800 by LiangMingJian


1.软件工程概述

1.1 软件的生命周期

  • 软件是计算机程序、规程、相关文档和数据的集合。
  • 软件的生命周期分为以下内容:
    • 可行性分析与项目开发计划:产物:可行性分析报告和项目计划书。
    • 需求分析:产物:软件需求说明书。
    • 软件设计:产物:概要设计说明书,详细设计说明书。
    • 软件编码:产物:可实际运行的代码
    • 软件测试:产物:软件评测报告
    • 软件维护:运维阶段是信息系统生命周期中,花钱最多、延续时间最长的活动。
  • 在一些模型中,软件的生命周期也可以分为以下内容:
    • 软件定义阶段:可行性分析与项目开发计划,需求分析。
    • 软件开发阶段:软件设计,软件编码,软件测试。
    • 软件维护阶段:软件维护。

1.2 软件工程

  • 软件工程是指以工程化的思想和方法,来解决软件生命周期内问题的一系列工程活动。
  • 软件工程是为了解决软件危机而提出的一系列工程活动。
  • 软件工程的目标是提高软件生产率,提高软件质量,降低软件成本。
  • 软件工程的特性是复杂性、不可见性、可变性、一致性。
  • 软件工程的三要素是过程、方法和工具。
  • 软件工程的基本原则是模块化,抽象,信息掩蔽。

2.需求分析

2.1 需求分析的内容

  • 需求分析是软件定义阶段的一项重要工作。在软件定义阶段,需要完成如问题定义,需求分析,可行性分析,项目计划制定,验收计划制定的任务。
  • 需求分析需要跟用户交流,清楚要做什么样的系统,为了完成什么功能,建立目标系统的雏形。确定系统必须完成哪些工作,对目标系统提出完整、准确、清晰、具体的要求。
  • 产出【软件功能规格说明书】,说明书需要确定用户对软件的需求,作到明确、无歧义,不涉及具体实现方法。
  • 产出【可行性报告】,说明项目的可行性。

2.2 可行性报告

  • 经济可行性(投入,产出)
  • 技术可行性(开发风险,资源可行性)
  • 操作可行性(用户是否认可)
  • 法律可行性
  • 时间可行性

2.3 需求的层次

  • 业务需求:企业或者用户对于软件要实现的目标的要求,是这个系统最高的需求层次目标,确定了系统开发的范围。
  • 用户需求:用户的具体目标,或者说是用户要求系统必须要完成的任务。
  • 系统需求:从系统角度,来说明软件的需求,包括以下内容:
    • 功能需求:所开发的软件必须具备什么样的功能。
    • 非功能需求:是指产品必须具备的属性或品质,如可靠性、性能、响应时间、容错性和扩展性等。
    • 设计约束:也称为限制条件、补充规约,这通常是对解决方案的一些约束说明。

2.4 需求的特征

  • 完整性:每一项需求都必须将所要实现的功能描述清楚,使设计人员获得设计和实现这些功能所需的必要信息。
  • 正确性:每一项需求都必须准确地陈述其要开发的功能。(只有用户代表才能确定需求的正确性)
  • 可验证性:检查每一项需求是否能通过测试用例或其它验证方法。
  • 可行性:每一项需求都必须是在已知的系统或环境内可以实现的。(建立数学模型,进行仿真)
  • 必要性:每项需求都是编写文档的根源,每项需求都唔那个回溯到具体用户。(用户需求,跟踪矩阵,WishList)
  • 无歧义性:对所有的需求,读者只能有一个明确统一的解释。(形式化的语言、图、表)

2.5 需求分析方法

  • 功能分解方法:将新系统作为多功能模块的组合,各功能可分解为若干子功能及接口,子功能能继续分解。
  • 结构化分析方法:以自顶向下,逐步求精为基点,以数据流图,数据字典,结构化语言,判定表,判定树等图形表达为主要手段,强调开发方法的结构合理性和系统的结构合理性的软件分析方法。
  • 信息建模方法:从数据角度对现实世界建立模型。此方法的核心概念是实体和关系,基本工具是 E-R 图,其基本要素由实体、属性和联系构成。该方法的基本策略是从现实中找出实体,然后再用属性进行描述。
  • 面向对象的分析方法:识别问题域内的对象,分析它们之间的关系,并建立对象模型、动态模型和功能模型三类模型。考虑类或对象、结构与连接、继承和封装、消息通信等内容。

2.6 需求分析工具

  • 数据流图
  • 数据字典
  • 判定表
  • 判定树

3.软件设计

3.1 概要设计

3.1.1 概要设计的内容

  • 概要设计的目的是将软件系统需求转换为未来系统的总体设计。
  • 概要设计的重点是清楚总体实现方案,确定软件系统的总体布局,各个子模块的功能和模块间的关系,模块与外部系统的关系。
  • 概要设计需要完成以下内容:
    • 设计软件系统的总体结构,软件体系结构。
    • 将系统按功能划分模块,并确定每个模块功能,但不涉及模块内的设计。
    • 确定模块间的调用关系。
    • 确定模块间的信息传递。
    • 一小部分的数据整体结构和数据库设计。
    • 需要评审软件体系结构。
  • 概要设计的输出是分层数据流图、结构图、数据字典以及相应的文字说明等。

3.1.2 概要设计的原则

  • 原则一:价值为王,不应该开发任何当前不使用的功能。因为这些占用开发成本的功能,可能根本没有人用。而且不仅仅是开发成本打了水漂,你还要不断投入维护成本,来保证这些无人使用的功能可以正常运行。
  • 原则二:以终为始,在做事之前,先想想结果是什么样子的,这个结果是否能达到最初的目标。
  • 原则三:分治原则,做架构时不要想着一次性把所有的功能都做好,要拥抱 MVP(Minimal Viable Product),最小可运行版本。先让程序完成最基本功能上线,根据反馈调整和决定下一步的迭代。迭代着去做事情,敏捷开发的思路。对于每个功能点,创建里程碑,然后去迭代。
  • 原则四:服务自治,在系统设计时,要考虑服务上线后,对于问题要自感知、自修复、自优化、自运维及自安全。
  • 原则五:拥抱变化,重视架构扩展性和可运维性。无状态的系统的是可扩展的和直接的。任何时候都要考虑这一点,不要搞个不可扩展的,有状态的东西出来。否则,一旦需要改变,成本很高。
  • 原则六:简单即正义,保持每件事情都尽可能的简单。用最简单的解决方案来解决问题。
  • 原则七:尽量自动化,人力成本既慢又贵,还有经常不断的人工失误。如果不能降低人力成本,反而需要更多的人,那么这个架构设计一定是失败的。
  • 原则八:依赖最简,依赖原则是去除依赖、弱化依赖、控制依赖。多一个依赖多一分风险。能不依赖则不依赖,能异步弱依赖不要同步强依赖。实在不能弱依赖的,比如必须要调用加密存储来获取数据库的密码,不然无法连接数据库,可以控制获取密码在服务启动时进行。
  • 原则九:不作不死,尽可能的做较少的功能。当有疑问的时候,就不要去做,甚至干掉。很多功能从来不会被使用。最多留个扩展点就够了。等到有人提出再说(除非是影响核心流程,否则就等到需要的时候再去做)。
  • 原则十:容灾容错,如果一件事情有可能发生则在生产环境中一定会发生,架构中要做好容错设计。
  • 原则十一:用成熟的技术,更多地使用主流大多数公司实际在用的技术栈。

3.2 详细设计(过程设计)

3.2.1 详细设计的内容

  • 详细设计的目的是依据概要设计阶段的分解,设计每个模块内的算法和流程。
  • 详细设计的本质是对系统中的模块进行设计。
  • 详细设计需要完成以下内容:
    • 信息代码设计:信息在系统中如何进行管理。
    • 输入/输出设计:模块要接收的数据的数量、类型等。
    • 处理过程设计:模块要实现特定的功能,算法,具体的步骤是怎样的。
    • 用户界面设计
    • 算法设计
    • 数据结构和数据库物理结构设计
  • 详细设计的输出是模块的流程图、状态图、局部变量及相应的文字说明等。

3.2.2 详细设计的原则

  • 一个软件系统是由各个子系统构成的,子系统是由各个模块组成的。
  • 模块设计的原则就是模块独立,每个模块完成一个相对的特定子功能、并且与其他模块之间的联系简单。
  • 模块间应具有高内聚,低耦合的特性。
  • 模块间的连接只能存在上下级关系,不能有同级间横向联系。
  • 整个系统呈现树状结构,不允许网状结构或交叉调用关系。
  • 所有模块必须严格分类编码并建立归档文件。

3.2.3 模块的耦合性

  • 耦合性是程序结构中各模块间相互关联的度量,它取决于各模块间接口的复杂程序,调用模块的方式。
  • 耦合如下可分为七级,从低至高,耦合应越低越好 。
  • 非直接耦合:两模块间彼此无任何交互,没有直接关系。
  • 数据耦合:两模块间仅通过数据参数交换信息。
  • 标记耦合:两模块间通过参数表传递记录信息,这个记录信息包含着复合数据结构,含有若干数据项。
  • 控制耦合:两模块间传递的参数中含有控制信息。
  • 外部耦合:两模块间共同访问一个全局简单变量,而不是全局数据结构。
  • 公共耦合:指模块间存在着公共数据区、全局数据结构、可共享的文件。
  • 内容耦合:一个模块需要使用另一模块内部的数据或控制信息的路径。包括以下情况:一个模块直接访问另一个模块;两个模块由一部分代码重叠;一个模块有多个入口。

3.2.4 模块的内聚性

  • 内聚是一个模块内部各成分相关联的度量,标志一个模块内各元素彼此结合的紧密程度。内聚,只看模块内这些元素(比如,写了两段代码,第1段处理1,第2段处理2)与模块功能之间的关系。
  • 内聚如下可分为七级,从低至高,内聚应越高越好 。
  • 偶然内聚:一个模块的各成分之间毫无关系,这些成分之间的关系松散,实际上没有联系。
  • 逻辑内聚:几个逻辑上相关的功能被放在同一模块中,则称为逻辑内聚。如一个模块读取各种不同类型外设的输入。尽管逻辑内聚比偶然内聚合理一些,但逻辑内聚的模块各成分在功能上并无关系,即使局部功能的修改有时也会影响全局,因此这类模块的修改也比较困难。简单的讲,逻辑内聚指的是模块内有多个功能代码,依据模块获得的参数来判定执行那个功能
  • 时间内聚:一个模块完成的功能必须在同一时间内执行(如系统初始化),但这些功能只是因为时间因素关联在一起而不是因为功能关联。
  • 过程内聚:构件或者操作允许在调用前面的构件或操作之后,马上调用后面的构件或操作,且使两者之间没有数据进行传递,模块完成多个需要按一定的步骤一次完成的功能。
  • 通信内聚(信息内聚):一个模块的所有成分都操作同一数据集或生成同一数据集。
  • 顺序内聚:模块内部的各部分,前一个部分处理的输出作为另一个部分的输入。
  • 功能内聚:模块的所有成分对于完成单一的功能都是必须的,是最理想的内聚。

3.3 软件设计原则

  • 分解协调原则:将系统划分成很多个小的模块,分解出来的模块共同协调完成特定的功能。
  • 自顶而下原则:将系统看做一个整体,根据系统工程的思想,自顶向下逐层进行设计。
  • 信息隐蔽原则:把一些比较机密的信息封装在模块内,给用户看到的只是输入和输出的信息,隐蔽数据的处理逻辑。
  • 抽象原则:把具体的对象、行为、特征,进行分类总结后一步一步抽象成类、或者更高层的对象。
  • 一致性原则:设计的理念、逻辑结构、操作交互以及视觉形象等内容要保持一致。
  • 明确性原则:设计的描述要明确,不能出现歧义。
  • 模块的扇入系数要合理:扇入大,说明这个模块的通用性强,直接调用该模块的上级模块多,重复利用的机会高。
  • 模块的扇出系数要合理:扇出大,说明这个模块的复杂度高,直接调用的下级模块多,需要控制和协调过多的下级模块。
  • 模块的规模适当:软考中的参考值是代码不超过 500 行。

3.4 软件设计工具

4.软件编码

4.1 软件编码的内容

  • 软件编码就是根据需求和设计规范将设计好的软件,使用编程语言转化为计算机可执行的程序。
  • 程序的质量取决于软件设计的质量,程序设计语言的特性以及编码途径。
  • 软件编码的目标是在给定成本、进程的前提下,开发出具有效性、可靠性、可维护性、可适应性、可移植性并满足用户需要的软件产品。

4.2 程序编码的原则

  • 可读性:代码应该易于阅读和理解,使用有意义的变量名、函数名和注释,遵循一致的代码风格和命名规范。
  • 简洁性:代码应该尽量简洁,避免冗余和重复的代码。使用合适的数据结构和算法,避免过度设计。
  • 可维护性:代码应该易于维护和修改,遵循模块化的设计原则,将功能划分为独立的模块或函数,避免代码耦合。
  • 可靠性:代码应该具有稳定性和可靠性,处理边界条件和异常情况,进行错误处理和异常处理。
  • 可扩展性:代码应该易于扩展和修改,具有良好的架构和设计,遵循开闭原则,允许在不修改现有代码的情况下添加新功能。
  • 性能效率:代码应该具有高效的执行性能,避免不必要的计算和内存消耗,优化关键路径和瓶颈代码。
  • 安全性:代码应该具有安全性,避免安全漏洞和攻击,进行输入验证和数据加密等安全措施。
  • 可测试性:代码应该易于测试,具有良好的单元测试和集成测试覆盖率,使用合适的测试框架和工具。
  • 可复用性:代码应该具有可复用性,避免重复编写相似的代码,使用函数、类、模块等封装可复用的功能。

5.软件测试

  • 软件测试是通过手工或自动化的手段来运行或测定某个软件产品系统的过程,目的在于检测软件产品是否满足规定的需求。

6.软件维护

6.0 可维护性的内容

  • 可理解性:理解、改正、改动、改进软件的难易程度。
  • 可测试性:测试和诊断软件错误的难易程度。
  • 可修改性:修改软件的难易程度。

6.1 维护的类型

  • 正确性(更正性)维护:更正交付后发现的错误。
  • 适应性维护:是软件产品能够在变化后或变化中的环境中继续使用。已经发生变化。
  • 完善性维护:改进交付后产品性能和可维护性。
  • 预防性维护:在软件产品的潜在错误成为实际错误前,检测并进行更正。还没有发生变化。

6.2 可维护性复审

  • 在完成了每项维护工作之后,都应该对软件维护本身进行仔细认真的复审。
  • 在软件再次交付使用之前,对软件配置进行严格的复审,则可大大减少问题。
  • 在需求/系统分析阶段的复审过程中,应该对将来要改进的部分和可能会修改的部分加以注意并指明;应该讨论软件的可移植性问题,并且考虑可能影响软件维护的系统界面。
  • 在系统设计阶段的复审过程中,应该从容易修改、模块化和功能独立的目标出发,评价软件的结构和过程,对将来可能修改的部分预作准备。
  • 在系统实施阶段的复审期间,代码复审应该强调编码风格和内部说明文档这两个影响可维护性的因素。

6.3 重构

  • 系统发展到一定阶段后,使用重构的方式,不改变系统的外部功能,只对内部的结构进行重新的整理。
  • 通过重构,不断的调整系统的结构,使系统对于需求的变更始终具有较强的适应能力。
  • 重构可以降低项目的耦合度,使项目更加模块化,有利于项目的开发效率和后期的维护。
  • 重构是对框架的一种维护。