计算机概论 - 软件工程 Software engineering

软件工程是计算机科学的一门分支,目的是寻找能引导大型且复杂软件系统开发的原则,开发这样的系统所要面的问题比撰写小型程序大得多,比如开发一个大型系统需要多人一起合作很长的时间,在期间所提出的系统需求也可能会随时调整,并且合作的人员也会有所改变,因此软件工程包含人员与专案的管理,不过这个议题比较像是商业管理领域,本章只着重在计算机科学议题上。

img

软件工程学

在工程学中由於他是个非常完善的领域,所以会有许多之前就发展好的工程方法可以用来处理问题,但软件开发的特性与工程领域有着基本的不同,其中一项差异是从预先建置好的通用元件来建构系统的能力,当要建构一个复杂的设备时,传统的工程领域长久以来都使用现成的元件作为基本构建,比如要设计一部新车,设计师不需要设计新的引擎或变速箱只要使用那些已经设计好的零件,但在软件工程来说这个部分相当落後,过去设计的软件元件都属於订制款所以很难让别人使用,使得复杂的软件系统通常都是从头开始设计。

另一个软件工程与其他工程的差异是缺乏用来评估软件特性的评量法 (metrics),比如要估算软件开发的成本,若想要估算计画中的产品复杂度就缺乏可靠的软件复杂度评估法,同样的评估软件的品质也是一个大挑战。

因此软件工程的研究分为两个层次进行,有些研究者(实务派)发展能够立即应用的开发技术,而其他研究者(理论派)则寻找新的原理或理论,不论那个派系都急需新的进展,软件错误已经发展成会造成严重灾害的程度了,比如误认错的目标为攻击目标或让银行损失个几百万等等。

不过情况也不是非常悲观,电脑科技对於软件发展也产生了所谓的电脑辅助软件工程 (computer-aided software engineering, CASE) 让软件开发程序变得更有效率,有些工具是专门为了软件工程设计的比如说有种名为整合开发环境 (integrated development environment, IDE) 的系统结合了软件发展的工具(编辑器, 编译器或除错工具等等) 成为单一整合工具。

大型系统开发的挑战之一是需要集合众人之力,而团体合作进行一个大型专案的个阶段都需要各种不同的技能,使得程序设计师可以单独撰写程序以降低每个人所负责的任务与复杂性,事实上是因为大型软件系统非常复杂所以要将其分割程序多小型的元件好让每个小元件可让每个程序设计师完全掌控。

软件生命周期

软件工程中最重要的概念就是软件的生命周期。

整体周期

一但软件完成後他就会进入使用与被维护的循环,这个循环会在软件的使用期间不断的重复,许多工厂所制造的产品也有这种循环,不过两这的差异在於其他产品的维护阶段往往是修理的过程,但软件维护阶段包含更正更新,实际上软件维护阶段是因为发现错误或因为软件因应应用上的改变而需要进行调整,或是在上次改版的改变造成其他方面出了问题。

img

无论什麽原因造成软件需要进入维护阶段都会需要安排一个人力去研究其程序码或相关文件,直到了解该程序并找到问题所在,但即使软件设计良好且文件也清楚的情况下,要了解其他人的程序码也是个不容易的工作,因此多数软件工程的研究都专注於软件生命周期的发展阶段希望藉此提高程序效益。

传统软件开发阶段

传统软件开发的生命周期主要步骤是软件需求分析, 设计, 实作测试

img

软件需求分析

软件生命周期始於软件需求分析,目的是明确定界定软件的服务项目,并指明这个服务的任何条件(时间限制, 安全性等等),其分析包含从相关人士 (stakeholder)取得重要意见,软件需求分析的过程包含收集与分析软件使用者的需求与软件专案相关人士进行软件期望, 需求, 成本与可行性之间平衡的协商并最後发展出明确的指名软件必须具备的特徵和服务,这些需求应记录在软件需求规格书 (software requirements specification) 的文件中。

从软件开发这的角度来说软件需求规格书应该定义软件开发的明确目标,然而规格书中恨少会有明确的目标,事实上多数软件工程领域的实务派认为沟通不良与软件需求的变动是成本超支与软件延迟交付的主要原因。

设计

软件需求分析对软件产品进行描述,而设计则是对该软件的建构提出规划,所以说需求分析是找出要解决的问题而设计是开发出问题的解法,软件系统的内部结构是在设计阶段中建立的,设计阶段的结果代表软件系统的结构有清楚的描述。

实作

实作包含程序的撰写资档的产生以及资料库的开发,在实作阶段可以看出软件分析师 (softwaren analyst)程序设计师 (programmer) 任务上的区别,软件分析师参与了软件整个开发过程但会比较注重在需求分析与设计阶段,而软件设计师则主要参与实作阶段。

测试

在整个开发过程的每个步骤中都需要进行准确的测试,测试是确保软件品质的必要程序之一,而确保软件品质是整个软件生命周期的目标,因此许多软件工程师认为测试不该再视为软件开发的一项单独步骤,而是应该融入其他步骤中,因此软件开发程序应该是软件需求分析与确认 (requirements analysis and confirmation), 设计与验证 (design and validation) 以及实作与测试 (implementation and testing)

软件工程方法论

早期软件工程法坚持以严格且循序的方式来执行分析, 设计, 实作与测试,因此软件工程师坚持在开始设计之前必须先完成整个软件需求规格,同样的在开始实作钱也要先完成设计,这种开发模式称为瀑布模式 (waterfall model),因为开发过程只允许按照一种方式进行。

最近软件工程开始有了改变,出现了一种称为渐进模式 (incremental model) 的开发模式,这种模式认为软件可以逐步构建出来,最初所完成的软件是一个有限功能的简化版本,一旦这个版本经过测试并由部分使用者评估过就会以渐进的方式加上其他功能并在进行测试直到系统全部完。

另一种不走瀑布模式的方式称为反覆模式 (iterative model),这种模式实际上有时候等於渐进模式,但两者的差异在於渐进模式会『拓展』每个初步版本使得系统规模逐渐增大,而反覆模式则是『精炼』每个初步版本,实务上渐进模式会包含反覆测试而反覆模式可能会逐步的加入新功能。

反覆模式法的一个重要实例是统一软件开发过程 (rational unified process, RUP),RUP 的广泛使用导致了另一种非营利版本的发展,这种版本称为统一软件 (unified process) 并提供非商业模式的免费版。

渐进模式和反覆模式有时候会利用软件开发往原型化 (prototyping) 的趋势来进行系统建置与评估,原型化指的是非完整版的系统,这个系统称为原型,在渐进模式中这个原型会逐渐演进为完整的终极版,这个过程称为演进式原型化 (evolutionary prototyping),而在反覆模式中圆形可能被舍弃使最终设计有新的实作,这种方式称为丢弃式原型化 (throwaway prototyping),属於丢弃式原型化的例子之一是快速原型化 (rqpid prototyping),这种方式能够在软件开发的早期阶段快速地建构出预想中的系统简单版,其目的并非一个能运作的产品而是作为一种说明工具以用来在软件开发过程中对相关人士阐述系统特性。

在电脑爱好者之间有一种使用多年的方法,称为开放原始码发展法 (open-source development),是渐进模式与反宽魔是非正式的典型模式。透过这种方法产生了现今许多免费软件,其中着名的例子就是 Linux,软件开放原始码的开发过程为: 由一个程序设计师撰写该软件的初始版本然後将程序码与相关文件放到网路上,之後这个软件可以供他人下载使用,因为其他人也可以获得这个软件的原始码与文件,所以可以对他进行修改以符合他们自己的需求过更正使用上发现的错误与问题,然後由开发者将这些更改发布在新的版本中。

与瀑布模式最大相迳庭的方式称为敏捷法 (agile method),这是众多方法所集合而成的模式,此模式对软件需求改变进行快速反应并且不重视眼镜的需求分析和设计,简而言之敏捷法举有高度弹性与瀑布式有强烈的对比。

模组化

若要修改软件,程序设计师必需要了解该程序或相关部分的程序码,要了解大型软件系统程序码几乎是非常困难的情况,尤其是软件没有模组化 (modularity),所谓的模组化是将软件划分为适当大小的单元,一般称为模组 (module),每一个模组都负责软件某部分的功能。

耦合

模组化可以让程序划分为适当大小的单元,因此对程设的修改就只需要针对少数几个模组即可,让程序设计师可以专注於程序的某个部分而不用了解整个系统的程序,不过这也要基於这个模组的修改不影响到其他模组的前提下,因此当要设计模组化系统时应尽力设计出独立的模组,要尽量避免模组之间的连结亦即模组之间的耦合 (couping) 要尽量的少,软件系统中不同模组之间的耦合程度可以看出这个软件系统的复杂度。

模组之间的耦合有几种不同的形式,其中一种是控制耦合 (control coupling),当某个模组使用到同一个资料项则其中一个模组对资料的异动可能会影响到另一个且资料本身的格式异动会同时影响到两个模组。

两个函数之间的耦合有两种不同的形式,其中一种是由某个函数将资料传给另一个函数,这种耦合在结构图中是以箭头表示,两个函数之间的箭头会标示所传送的资料而箭头方向代表资料传送的方向。

img

物件导向式程序设计的好处之一是他本质上就能让物件之间的资料耦合发生率降到最低,因为物件中的方法一般都会包含物件内部资料的操作,由於不需要将在物件内部资料传送给其他物件使得物件之间的资料耦合可以减少到最低。

相较於以参数传传送资料的形式,也有资料会以全域资料 (global data) 的形式让模组共用,全域资料可以让系统中所有模组直接取用,使用全域资料要非常小心,因为有人修改到某个全域资料的话会很难发现其他模组的更改状况进而导致意想不到的错误出现。

内聚

与最小化耦合等同重要的就是最大化模组之间的内部连结这种连结称为内聚 (cohesion),用来表示内部的连结换句话说内句是模组内部元素的相关性,如果有模组需要修改它内部的结构,可能会造成整体程序上的混淆或出意料之外的错误,因此除了要降低模组之间的耦合之外也要提高模组的内聚。

比较弱的内聚称为逻辑内聚 (logical cohesion),这种内聚是由模组内部的元素做都执行类似的操作所形成,而比较强的内聚称为功能内聚 (functional cohesion) 亦即模组内的所有元件都只专注在单一操作,在命令式设计中可以将子任务分中到其他模组以增强功能内聚,而在物件导向程序中肘个物件通常只有逻辑内聚,因为物件内的方法通常会执行不相关的操作,唯一共通的连结是这些方法的操作都由同一个物件执行。

软件设计师应该要尽力的让物件中的每个方法都具有功能内聚,也就是将物件本身只有逻辑内聚而他内部的每个方法应该只执行一个功能内聚的任务。

img

资料隐藏

模组设计的要法之一是掌握资讯隐藏 (information hiding)的概念,它是指将资讯局限於软件系统的某个特定区域中,这个隐藏的资料可以包含资料、资料型别、编码法、模组的内部组成结构、程序单元的逻辑以及任何与模组内部特性相关的其他要素。

资讯隐藏的目的是避免模组的运作与其他模组产称生不必要的相依性或影响,不然可能会影响到其他正常工作的模组或被错误的模组影响到,要注意的是资讯隐藏有两种意义,一种是作为设计目的另一种是作为实作目的,模组的设计应该使其它模组不需要去存去其内部资源,并且模组的实作应该加强其界限,前者的例子就是要最大化内聚以及最小化耦合,而後者的例子包含使用区域变数资料封装以及使用定义完善的控制结构

元件

上面有提到软件工程的领域中缺乏预先订制好的构建已建立出大型软件系统,不过软件的模组化让这个问题得以实现,因为物件导向的物件可以构成完整的程序并且具备清楚的介面让个物件可以彼此沟通,不过虽然物件和类别可以作为软件工程所需要的构建但不代表他们是完美的,其中一个问题是他们只能提供相对小型的构建,物件实际上只是元件 (component) 的特例,元件具有更一般化的概念是软件中可重复使用的单元,实际上大多数元件都是基於物件导向程序法并且有一个以上的物件且都可以独立完成某项工作。

交易工具

本章会介绍一些软件开发中分析与设计阶段会用到的塑模法符号法

版本控制: 版本中系统现在已经是大多数软件工程的一部分,透过网页和网路的版本控制系统可提供一致的机制来追踪程序码的修改,让多人开发合作编写某个大型系统时可以更好的维护与开发,常见的版本控制工具有 Git, Subversion, Mercuurial 等等,版本控制可以精确追踪是谁在何时做了哪些更改,且可以回朔原始码到较早期的版本用於修改不当更改造成的错误或影响。

老朋友

资料流程图 (dataflow diagram) 是研究资料流向所取得的资讯的表现,箭头代表资料的路径,椭圆代表资料处理的位置点而矩形代表资料的来与和储存。

img

资料流程图不仅能在设计阶段辅助辨认程序,在分析阶段尝试理解整个系统时也有很大的用处,建构资料流程图可以加强客户与软件工程师之间的沟通。

另一种长年被使用的工具是资料字典 (data dictionary),这是用来储存整个软件系统中所用到的资料项目资讯,这个资讯里面有资料的名称, 资料的有效构成元素 (资料只能是数字还是字母?数值的值域等等), 资料的储存位置以及资料使用在系统的什麽地方

建构资料字典的目的之一是强化软件工程师与相关人士的沟通,因为资料字典可以在分析阶段中帮忙确认一些问题而不用在设计或实作阶段才发现,他的另一个目的是为了建立系统的一致性。

统一塑模语言

资料流程图和资料字典是在物件导向出现前就存在的软件工程工具,都是基於命令式程序法所发展出来的,而现代的工具称为统一塑模语言 (Unified Modeling Language, UML),主要是随着物件导向盛行而发展的,其中一个工具称为使用案例图 (use case diagram),他以一个大矩形来表示系统并描绘系统与使用者之间互动关系,这些互动称为使用案例 (use case) 并以椭圆来表示使用案例,而系统使用者也称为行动者 (actor) 会以火柴人表示,

img

使用案例图是从外部检视软件洗桶架构,UML 也提供许多工具以描述系统内部的物件导向架构设计,其中一种称为类别图 (class diagram),这是一种表示类别结构和类别之间的关系符号表示法,类别关系在 UML 的术语中称为关联性 (association)

img

以上面的图来说,通常会以矩形表示 Class 并且以线条表示关联性,关联性线条不一定会有文字,除了指名类别之间的关联性之外类别图也能表达这些关联性的数量,换句话说类别图可以指名有多少个类别的实例与另一个类别的实例具有关联性,关联性的数量只会有三种形式 一对一关系, 一对多关系, 多对多关系

  • 一对一关系 (one-to-one relationshop): 如病人与病房的关系,每个病人只能使用一个单人房,且每个单人房只能提供给一个病人使用。
  • 一对多关系 (one-to-many relationshop): 如医生与病人的关系,一个医生可以照顾多名病患但每个病人只能让一位医生负责照顾。
  • 多对多关系 (many-to-many relationshop): 如每个病人可以照顾许多病人而每个病人也可以谘询不同医生。

img

类别图代表静态的程序设计特性,但不代表执行时事件发生的顺系,为了表达这种动态的特性 UML 提供许多不同的图形表示法,这种表示法称为互动图 (interaction diagram),互动图之一是顺序图 (sequence diagram),他会画出执行某项动作所涉及到的个体之间的沟通,他们都以矩形表示个体并有虚线向下延伸,每个矩形与其虚线称为生命线 (life line),每个个体之间个沟通已箭头表示并连结彼此的生命线,其中会用文字标示请求的动作,这些箭头按照时间顺序从上而下看而顺序图会被一个大矩形包围这个矩形称为框架 (frame)

img

设计模式

设计模式 (design pattern) 是软件设计中一种预先开发好的模式,用来解决经常出现的问题,比如转接器模式 (Adapter pattern) 所提供的方法可以用来解决使用预先订制好的模组来建构软件时会发生的问题,简单来说如果有个模组可以用来解决目前手中的问题,但这个模组没有与目前应用程序相容的介面,这时就可以使用转接器模式将这个模组包在另一个模组里面,这样就能被应用程序使用。

品质保证

软件故障、成本超支和开发逾时等问题会在开发软件系统中不断的发生,这些问题都需要有方法来改善软件的品质控制,本章将会介绍这个议题以及过去的一些成果。

软件测试

现今大多数软件是以测试来进行验证,但除非我们可以测试到所有可能发生的状况不然即使是做简单的程序依然会有错误发生,因此测试所有可能性几乎是不可能的任务。

白箱测试 (glass-box testing)

基於帕雷托法则与基础路径测试的方法都需要了解软件内部的组成,因此这两种方法被归类在白箱测试 (glass-box testing) 中,亦即软件测试者需要了解软件内部结构并根据对软件的了解来进行测试。

帕雷托法则 (Pareto principle)

不过软件工程师发展出其他测试的方法能够以有限个数的测试提高发现错误的机率,其中一种方式是基於软件错误倾向再一起,亦即经验告诉我们在大型系统中有少部分模组比较容易发生问题,藉由找出这些模组且充分测试这些模组就可以找到系统中大部分的问题与错误,这样要比全面的测试所有模组来的有效率,这种方式就是帕雷托法则 (Pareto principle) 的实例之一,只要在关键区域多付出一些心力其效就可以快速增加。

基础路径测试 (basis path testing)

另一种方法称为基础路径测试 (basis path testing),这是用来确保软件中每个指令至少都能执行到一次,这种方式使用数学中的图轮法,虽然不能保证每种状况都会被测试到但可以确保软件中每一条陈述在测试过程中都会至少被执行到一次。

黑箱测试 (black-box testing)

这种测试会在不了解软件内部组成的情况下进行,简而言之黑箱测试是从使用者角度出发,在黑箱测试中测试者并不会考量软件是如何运行的,仅在意软件是否能正确且即时的执行。

边界值分析 (boundary value analysis)

这是黑箱测试的方式之一,这种方式会包含一组指定范围的资料,这些资料称为等价类 (equivalence class),软件以相同方式来执行这些资料人後再以接近边界值的资料来测试软件, 举例来说如果某软件的输入值有特定的范围那麽就应该要使用这个范围的最大值与最小值来测试软件,或着若是某软件负责协调多项作业那麽就应该要以最多可能的运作项目才测试软件,若软件在这些测试项目中都能正常执行那麽软件也应该能够在所有项目中正常执行。

beta 测试 (beta testing)

将软件的前期版本给一群有兴趣的使用者进行测试,目的是在软件的最终版本还未稳固并上市之前可以知道软件在实际应用上的状况,如果测试是由开发端进行测试的话则称为alpha 测试 (alphq testing),beta 测试的好处远大於传通的错误寻找法,从一般用户反馈的意见来修改软件以达成调整行销策略的目的。

文件

如果使用这无法知道软件该怎麽使用或维护那麽这个软件就没有用处,所以文件算是软件套件很重要的一部分,软件文件有三个主要的方向分别对应文件的三种类别: 使用者文件, 系统文件技术文件

使用者文件 (user documentation)

使用者文件 (user documentation) 其目的是说明软件的特色使用方式,以应用层面的术语撰写让使用者阅读的,好的使用者文件通常结合了设计完善的使用者介面,可以增加软件的销售量。

系统文件 (system docummentation)

系统文件 (system docummentation) 其目的是描述软件内部的组成以利於软件在日後的维护,系统文件的主要内容是系统所有的程序码,其中这些程序码必须要易於阅读,这也是为什麽现代软件会使用高阶语言并使用注释以及使用模组化设计的原因。

系统文件的另一个要素是设计文件的纪录,该纪录包含软件需求规格书以及这些规格设计的过程,在软件的维护中这些资讯非常有用,因为他说明了这些软件是如何设计的。

技术文件 (technical documentation)

技术文件 (technical documentation) 其目的在说明如何安装与维护软件(如调整软件运作参数、安装更新以及回报错误等等)。

软件所有权与责任

法律上赋予软件所有权的范畴归类於智慧财产权法 (intellectual property),着作权与专利权的目的在於让产品的开发者可以在公开产品的同时取得所有权的保障,因此产品的开发者都会在相关产品上加上所有权的声明,包含需求规格书、设计文件、程序码、测试规划以及最终产品的显眼处,版权声明会清楚的指名所有权,此外开发者权益会在软件授权书 (software license) 上以法律用语正式的陈述,软件授权书是软件产品所有权人与使用者之间的法律协议,赋予使用这某些权限来使用该产品而不需要转让其智慧财产权给使用者,这个协议会详细的说明双方的权益与义务。

专利法是为了让发明者可以从发明中获取利润,为了取得专利发明者需要证明该发明是新颖、有用且与其他发明者之发明无相似之处的,专利权年限一般是专利提申请後的 20 年。

Reference


<<:  16. STM32-I²C EEPROM DataSheet

>>:  调查、证据和取证(Investigation, Evidence, and Forensics)

响应式设计

元件自动侦测改变外观 现在网页应用程序越来越朝向「mobile first」设计,代表网站都要能支援...

Day 1 - 课程大纲

大家好,我高中生 姜义新 本次课程大纲 在本次的it帮铁人竞赛,我将会以swift及SwitchUI...

欸! 我觉得自动化测试的架构应该长这样,测试应该这样写。

最近目前我的公司要做新的专案, 所以藉此需要一个新的专案来做自动化测试, 所以开始在思考一个好的自动...

【Day3】前端React +Antd 的环境(Docker化)建立 (上)

1.前端的建立过程(上): 我是在本机电脑运行起来本地版本 Container 的静态前端 Serv...

[区块链&DAPP介绍 Day9] Solidity 教学 - control flow

本日来介绍一下 solidity 的控制流程。 学任何语言基本上都需要条件判断式,那就稍微简单介绍一...