拓展阅读
Devops-02-Jpom 简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件
项目管理平台-01-jira 入门介绍 缺陷跟踪管理系统,为针对缺陷管理、任务追踪和项目管理的商业性应用软件
项目管理平台-01-Phabricator 入门介绍 一套集成的强大工具,帮助公司构建更高质量的软件
软件设计
软件设计是指在实现或修改软件系统之前,构思该软件系统如何工作的过程。
软件设计也指设计过程的直接结果,即关于软件如何工作的概念,包括设计文档和未记录的概念。
软件设计通常由最终系统的目标驱动,涉及问题解决和规划——包括高层次的软件架构设计以及低层次的组件和算法设计。
在瀑布开发过程中,软件设计是跟随需求规范之后、编码之前的活动。
一般过程
设计过程使设计师能够在软件系统实现之前,对其各个方面进行建模。
创造力、过去的经验、对“好”软件的理解以及对质量的承诺是成功设计的关键因素。然而,设计过程并不总是一个简单的程序。
软件设计模型可以与建筑设计图纸进行比较。高层次的设计图纸代表了房屋的整体(例如,房屋的三维效果图),而低层次的设计图纸则提供了构建每个细节的指导(例如,管道布局)。类似地,软件设计模型提供了对拟议软件解决方案的多种视角。
价值
软件设计文档可能会被审查或呈现,以便在编码之前调整约束、规范甚至需求。
在对程序化模拟或原型进行审查后,可能会进行重新设计。
虽然在编码过程中也可以进行软件设计,而无需计划或需求分析,但对于更复杂的项目而言,这种方式则较为不可行。编码前的独立设计使得跨学科的设计师和主题专家(SMEs)能够与程序员协作,以生产既有用又技术上合理的软件。
需求分析
软件设计的一个组成部分是软件需求分析(SRA)。SRA是软件开发过程中的一个环节,列出了软件工程中使用的规格说明。
分析的输出是待解决的更小问题。与之相对,设计更侧重于系统的能力,因此,对于同一问题可以存在多个设计方案。根据不同的环境,设计常常有所不同,无论是采用可靠的框架,还是实现适合的设计模式。
Artifacts 工件
设计过程可能包括生成如流程图、用例、伪代码、统一建模语言(UML)模型及其他基础建模概念等工件。
对于以用户为中心的软件,设计过程可能涉及用户体验设计,并生成故事板,帮助确定这些规范。
有时,设计过程的输出是设计文档。
设计原则
基本的设计原则帮助软件工程师在设计过程中进行导航。
Davis[4] 提出了一个软件设计的原则集,并在以下列表中对其进行了调整和扩展:
-
避免“隧道视野”
设计过程不应受“隧道视野”的限制。一个好的设计师应考虑多种方法,根据问题需求和可用资源对每种方法进行判断。 -
设计应可追溯到分析模型
由于设计模型中的单个元素往往可以追溯到多个需求,因此必须有一种方法来追踪需求如何通过设计模型得到满足。 -
避免重复发明轮子
系统是由一组设计模式构建的,其中许多设计模式可能已经被遇到过。设计时应选择这些现有的设计模式,而非重新发明。时间宝贵,资源有限;设计时间应投资于通过集成现有的模式来表示(真正的新)想法(如果适用的话)。 -
设计应最小化软件与现实问题之间的智力距离
也就是说,软件设计的结构应尽可能模仿问题领域的结构。 -
设计应表现出一致性与集成性
如果设计是统一的,那么它看起来完全是连贯的。为了实现这一目标,在设计工作开始之前,设计团队应定义风格和格式的规则。如果设计是集成的,那么在定义设计组件之间的接口时应谨慎。 -
设计应结构化以适应变化
下文中讨论的设计概念使得设计能够达到这一原则。 -
设计应能够平稳退化,即使遇到异常数据、事件或操作条件
设计良好的软件永远不应该“崩溃”;它应设计成能够适应异常情况,并且如果必须终止处理,应该优雅地终止。 -
设计与编码是两个不同的过程
即使为程序组件创建了详细的过程设计,设计模型的抽象层级也要高于源代码。在编码层面上做出的唯一设计决策应当解决那些能够实现过程设计的小细节。 -
设计应在创建过程中评估质量,而非事后评估
设计过程中的各种设计概念和度量方法能够帮助设计师在开发过程中持续评估设计质量。 -
设计应进行审查,以最小化概念性(语义)错误
在设计审查时,往往有一种倾向过度关注细节,忽略了整体设计。设计团队应确保设计的主要概念元素(如遗漏、不明确、不一致)已经得到解决,之后再关注设计模型的语法问题。
设计概念
设计概念为设计师提供了一个基础,从中可以应用更复杂的方法。
以下是一些已发展出的设计概念:
-
抽象(Abstraction)
抽象是通过减少概念或可观察现象的信息内容来进行概括的过程或结果,通常仅保留对特定目的相关的信息。它是表示本质特征而不包括背景细节或解释的行为。 -
精炼(Refinement)
精炼是阐述过程的过程。通过分解宏观功能描述,逐步开发出一个层次结构,直到达到编程语言语句。在每一步中,一个或多个程序指令被分解为更详细的指令。抽象和精炼是互补的概念。 -
模块化(Modularity)
软件架构被分解为称为模块的组件。 -
软件架构(Software Architecture)
软件架构指的是软件的整体结构,以及该结构如何为系统提供概念上的一致性。良好的软件架构能有效地回报项目的预期成果,例如在性能、质量、时间表和成本方面。 -
控制层次(Control Hierarchy)
程序结构表示程序组件的组织,并暗示了控制的层次结构。 -
结构分割(Structural Partitioning)
程序结构可以水平和垂直地进行分割。水平分割定义了每个主要程序功能的模块化层次结构分支;垂直分割建议控制和工作应在程序结构中自上而下分布。 -
数据结构(Data Structure)
数据结构是表示数据中各个元素之间逻辑关系的方式。 -
软件过程(Software Procedure)
专注于单个模块的处理过程。 -
信息隐藏(Information Hiding)
模块应当被指定和设计,使得模块内部的信息对其他不需要这些信息的模块不可访问。
在他的面向对象模型中,Grady Booch提到抽象、封装、模块化和层次结构是基本的软件设计原则[5]。
有时使用首字母缩略词PHAME(Hierarchy, Abstraction, Modularisation, and Encapsulation的原则)来指代这四个基本原则[6]。
设计考虑因素
在设计软件时,有许多方面需要考虑。
每个考虑因素的重要性应当反映出软件创建的目标和期望。以下是一些常见的设计考虑因素:
-
兼容性(Compatibility)
软件能够与其他为与某产品互操作而设计的产品一起工作。例如,软件可能与其旧版本向后兼容。 -
可扩展性(Extensibility)
可以在不对基础架构进行重大更改的情况下向软件添加新功能。 -
模块化(Modularity)
所产生的软件由明确定义的独立组件组成,从而提高可维护性。组件可以在集成之前单独实现和测试,这有助于在软件开发项目中分配工作。 -
容错性(Fault-tolerance)
软件能够抵抗并从组件故障中恢复。 -
可维护性(Maintainability)
衡量修复缺陷或功能修改的难易程度。高可维护性通常源于模块化和可扩展性。 -
可靠性(Reliability / Durability)
软件能够在规定的条件下,在指定的时间段内执行所要求的功能。 -
可重用性(Reusability)
能够将现有软件的某些或全部方面在其他项目中使用,且无需做大量修改。 -
健壮性(Robustness)
软件能够在压力下运行,或者容忍不可预测或无效的输入。例如,软件可以设计得具有对低内存情况的韧性。 -
安全性(Security)
软件能够抵御和抵抗恶意行为和影响。 -
可用性(Usability)
软件的用户界面必须适合其目标用户群体。必须为参数选择默认值,这些默认值应该对大多数用户来说是合理的选择[7]。 -
性能(Performance)
软件能够在一个用户可接受的时间框架内完成任务,并且不会占用过多内存。 -
可移植性(Portability)
软件应该能够在不同条件和环境中使用。 -
可伸缩性(Scalability)
软件能够很好地适应增加的数据、功能或用户数量。根据Marc Brooker的说法:“一个系统在负载增加的过程中,边际成本几乎是恒定的,那么它就是可伸缩的。”无服务器技术符合这一定义,但需要考虑总拥有成本,而不仅仅是基础设施成本[8]。
建模语言
建模语言可以用来表达信息、知识或系统,使用一组一致的规则定义的结构来描述。
这些规则用于解释结构内的各个组件。建模语言可以是图形化的或文本化的。
以下是一些用于软件设计的图形化建模语言的例子:
-
架构描述语言(Architecture Description Language, ADL)
用于描述和表示软件系统的软件架构。 -
业务流程建模符号(Business Process Modeling Notation, BPMN)
一种过程建模语言,用于描述业务流程。 -
EXPRESS 和 EXPRESS-G (ISO 10303-11)
一种国际标准的通用数据建模语言。 -
扩展企业建模语言(Extended Enterprise Modeling Language, EEML)
通常用于跨多个层次的业务过程建模。 -
流程图(Flowcharts)
算法或其他逐步过程的示意图。 -
基本建模概念(Fundamental Modeling Concepts, FMC)
用于软件密集型系统的建模语言。 - IDEF(Integrated DEFinition)
一类建模语言,最著名的包括:- IDEF0 用于功能建模
- IDEF1X 用于信息建模
- IDEF5 用于建模本体论
-
Jackson结构化编程(Jackson Structured Programming, JSP)
基于数据流结构与程序结构之间的对应关系的结构化编程方法。 -
LePUS3
一种面向对象的视觉设计描述语言和形式化规格语言,主要用于建模大型面向对象程序(如Java、C++、C#)和设计模式。 -
统一建模语言(Unified Modeling Language, UML)
一种通用建模语言,用于描述软件的结构和行为。它具有图形符号,并允许通过Profile进行扩展。 -
Alloy(规格语言)
一种通用规格语言,用于表达软件系统中的复杂结构约束和行为。它基于一阶关系逻辑提供简洁的语言基础。 -
系统建模语言(Systems Modeling Language, SysML)
一种用于系统工程的新通用建模语言。 - 面向服务建模框架(Service-oriented Modeling Framework, SOMF)
用于面向服务架构建模的框架[9]。
这些语言的使用可以帮助开发人员和设计师更清晰地表达系统的结构、行为以及相关的业务逻辑,便于沟通和开发过程中的各个环节协作。
设计模式
软件设计师可能会识别出一些设计方面,这些问题可能已经被其他人解决过。一个描述常见问题解决方案的模板或模式被称为设计模式。复用这些模式可以提高软件开发的速度。[10]
代码即设计
在某些情况下,源代码本身可以被视为程序的设计。软件设计的难点在于,源代码不仅仅是一个结果,它也代表着设计的本身。在某种程度上,“软件设计”指的是设计的设计。Edsger W. Dijkstra将这种语义层次的分层称为计算机编程的“根本创新”,[11]而Donald Knuth则通过他编写TeX的经验来描述试图在实现之前设计程序的徒劳性:
“如果我只是指定了TEX,而没有完全参与其初期实现,它将会完全失败。实现过程不断地引发了我未预见到的问题,并且对原始规范如何改进产生了新的见解。”[12]
这表明,软件设计不仅是事先的规划,而是在实现过程中不断反思和调整的过程。通过在实践中迭代,设计师能够发现并解决问题,从而改进最初的设计方案。
参考资料
https://zh.wikipedia.org/wiki/%E8%BD%AF%E4%BB%B6%E8%AE%BE%E8%AE%A1