精华内容
参与话题
问答
  • 软件工程——软件设计总结

    千次阅读 2018-07-19 16:52:22
    软件设计的定义 定义:对需求分析阶段提出的系统要求,给出具体的软件设计方案,即如何去做。 软件设计的概述(1)目标:根据SRS提出的目标,设计出软件的体系结构,接口,数据结构和处理流程并撰写SDS。(2)软件的...

    一.软件设计的定义

    1. 定义:对需求分析阶段提出的系统要求,给出具体的软件设计方案,即如何去做。
    2. 软件设计的概述(1)目标:根据SRS提出的目标,设计出软件的体系结构,接口,数据结构和处理流程并撰写SDS。(2)软件的设计模型

    数据设计 ——> 体系结构设计 ——> 接口设计 ——> 过程流程

    数据设计:指内部的数据结构,数据存储(数据库或文件)

    体系结构设计:物理架构,逻辑架构

    接口设计:内部模块之间的接口,外部与人机,其他系统的接口

    过程流程:处理流程和算法,并发控制

           3.软件设计的两个阶段

    总体设计

    详细设计

    体系结构具有多样性

    (1)模块化

    高层模块 ——> 复杂问题 ——> 较小问题

    (2)模块化的重要特征:

    抽象化:抽出事物的本质特征不考虑细节

    信息隐藏:模块所包含的信息不允许其他不需要这些信息的模块访问,独立的模块间仅交流为完成系统功能必须交换的信息。

    信息隐藏的作用:提高模块的独立性,便于修改维护

    4.设计描述与建模

    (1)类图:表示系统中类及类 和类之间的关系,用于对系统的静态结构进行描述。

    (2)一个系统中通常有若干个类图:一个类图不一定包含系统中的所有类,一个类也可以出现在多个类图中。

    ​​​​​​​

    UML中属性的语法:[可见性][属性名][:类型][=初值]

    1. 类之间的关系
    1. 关联:两个类对象之间存在某种语义上的关联
    2. 聚集:聚合,表示类与类之间是整体与部分的关系
    3. 泛化:继承
    4. 依赖和细化
    1. 状态图

    是一个类对象可能经历的所有历程的模型图

    1. 包图

    UML为复杂系统建模所提供的模型元素组与管的机制。

    包 定义 个名字空 包用于定义一个名字空 间或容器(Container) ,通过包可以把类、用例、组 件等语义联系紧密元素聚集在一起,从而实现从不同 抽象层次、不同角度对系统或子系统进行建模描述, 将对包中的元素作为一个整体对待,并且控制它们的 可视性和存取。

    包的表示(1)

    包的表示(2)

    不同包中的元素可以同名,但是同一包中的模 型元素不能同名。

    包的模型元素前可以有可视性标志,其表示方法与 类中的属性和操作的可视性表示 类中的属性和操作的可视性表示一样。

    F +,对于输入该包的任何包的模型元素都可见 F

    -,对于外包不可见 F

    #,只对其子包可见

    包的联系:

    依赖,输入依赖

    输入和输出,泛化

    1. 构件图

    构件图用来描述代码构件的物理结构及各个构件之间的物理关系。

    构件的作用:

    构件是定义了良好接口的物理实现单元,它是系统中可替换的部分。每个构件体现了系统设计中特定类的实现。良好定义的构件不直接依赖于其他构件而依赖于构件所支持的接口。

     

    1. 部署图

    部署视图描述位于节点实例上的运行构件实例的安排。

     

    1. 体系结构设计

    体系结构:一个系统的高层次的组织结构,表现为系统的组件、组件之间的相互关系、组件与环境之间的相互关系以及设计和进化的原理。

     

    体系结构模式:根据软件设计开发经验总结出来,且命名的,针对某类型软件具有通用性和推广价值的设计方案某一类型软件具有通用性和推广价值的设计方案。

    UML架构:“4+1”视图

    包括4种架构:

    逻辑:软件逻辑单元(函数、类)的组成及其关系。

    MVC架构

    进程:系统运行时进程(线程)的构成及其控制。与系统性能有关。

    开发:软件物理单元(动态库、文件、可执行程序、程序包)的成组及其关系。与软件开发管理及程序员有关。

    物理:系统的网络拓扑结构系统的网络拓扑结构、硬件构成以及软件的部署方案。与系统工程师规划部署方案有 关。该架构又称为系统架构(System Arch.)

    1. 人机交互设计

    1.交互设计是关于创建新的用户体验的问题,目的 在于增强和扩充人们的工作、通信及交互方式, 使他们能够更加有效地进行日常工作和学习。

    2.设计流程

    交互设计: 生成产品原型 线框图——>视觉设计: 生成产品模型 效果图——>

    SS/HTML: 生成产品DEMO

    1. 界面设计原则

    合理组织内容

    简化表单,突出重点

    清晰的浏览线

    考虑用户场景 ,保证主流程顺畅

    选择合适的标签对齐方式

    提供必要的帮助

    智能默认

    帮助用户探索和尝试

    允许用户犯错误

    使界面符合用户的使用习惯

    减少用户在使用软件时出现错误...

    1. 界面开发

    典型事件:窗口创建、打开、关闭、销毁,以及其他界面 元素触发的事件。

    1. 业务逻辑层设计
    1. 领域模型:领域模型是对真实世界中概念类的表示,而不是软 件对象的表示。它不是用来描述软件类、软件架构领 域 有责件象 层或 职责软件对象的一组图。
    2. 领域模型用一套类图来表示,这些类没有操作。

    领域模型可以显示:领域对象或者概念类;概念类之间的关联;概念类的属性。

    1. 数据存储设计

    1.设计范围: l

    业务数据在内存中的管理组织;业务数据在外存中的存储结构。

    1. 内存数据管理与组织:

    自定义数据结构; l

    开发语言内建的数据结构:

    1. 外存数据管理组织

    存储方案:文件 VS. 数据库

    文件优缺点 :l

    安装部署不需要其他软件支持; l

    易于作为网络数据交换格式; l

    不利于数据的并发访问与共享

    数据库 l

    实现数据共享 ;减少数据的冗余度 ;数据的独立性:独立于具体应用。数据实现集中控制:数据安全性、一致性和可靠性:①安全性控制;②完整性控制:③并发控制。故障恢复:备份恢复机制。

     

     

     

     

    展开全文
  • 软件设计的总体思路

    万次阅读 2019-01-08 15:16:02
    软件设计的本质就是针对软件的需求,建立模型,通过将模型映射为软件,来解决实际问题。因此软件设计需要解决的核心问题是建立合适的模型,使得能够开发出满足用户需求的软件产品,并具有以下特性: 灵活性...

    参考博客原址:

    https://www.cnblogs.com/trendline/articles/how-to-create-design-doc.html

    软件设计的本质就是针对软件的需求,建立模型,通过将模型映射为软件,来解决实际问题。因此软件设计需要解决的核心问题是建立合适的模型,使得能够开发出满足用户需求的软件产品,并具有以下特性:

    • 灵活性(Flexibility)
    • 有效性(Efficiency)
    • 可靠性(Reliability)
    • 可理解性(Understandability)
    • 维护性(Maintainability)
    • 重用性(Reuse-ability)
    • 适应性(Adaptability)
    • 可移植性(Portability)
    • 可追踪性(Traceability)
    • 互操作性(Interoperability)

    因此,软件设计并没有一套放之四海而皆准的方法和模板,需要我们的设计开发人员在软件的设计开发过程中针对软件项目的特点进行沟通和协调,整理出对软件项目团队的行之有效的方式,进行软件的设计。并保障软件设计文档的一致性,完整性和可理解性。

     

    我们经常听到这样的话:

    • “设计文档没有用,是用来糊弄客户和管理层的文档”;
    • “用来写设计文档的时间,我的开发早就做完了”;
    • “项目紧张,没有时间做设计”;

    这些言论,并不是正确的观念,根据软件项目的实际情况,软件开发设计团队可以约定设计文档的详细程度。项目团队需要保障设计文档的完整性和一致性,在项目进度紧张的情况下,软件设计文档可以更初略一些;在项目时间充裕的情况下,相关文档可以更为详尽。但是在项目开发过程中,需要软件设计开发团队对于设计文档有共同的理解。

    设计文档分类与使用

    通常来说,作为软件项目,我们需要有这几类文档

    • 需求说明文档
    • 功能设计文档
    • 系统架构说明书
    • 模块概要设计文档
    • 模块详细设计文档

    就像我之前说到的,在某个软件团队,对于以上的文档的要求是可以完全不同的,在简单项目中,可能所有类型的文档放在一个文档中进行说明;在复杂项目中,每一类文档可能都要写几个文档;而在最极端的情况下,可能每一类文档都能装订成几册。因此,在我们软件设计和开发人员心目中需要明确的是:文档并不是我们进行设计的目标,也不是我们设计过程中额外的工作。

     

    软件设计文档是我们在软件设计开发过程中形成的,用来在软件设计开发团队内部以及与各干系人之间进行沟通的文档,这些文档记录了软件项目中的各种知识,方案的思路、以及各种决策意见。

    下面我们就软件设计开发过程中必须要完成的工作进行梳理,而我们需要注意到,这些需要完成的工作,在不同的开发流程模型的指导下可能有不同的时间要求,而我们需要关注的是在这个阶段内需要完成的工作,以及这个阶段内我们需要沟通的人员。

    需求分析

    需求分析是我们进行任何一个软件项目设计开发过程中都必须要完成的工作。

    这个工作通常与客户一起完成。在不同的项目中,这个“客户”可能来自真正的购买产品的用户,使用系统的用户,也有可能来自团队的某个人员,如产品经理等。软件设计开发团队的参与成员根据项目的不同规模,则参与的人员也有所不同。原则上,设计开发人员参与的时间点越早,对于需求的理解和把握会更好。这个阶段,通常需要软件架构师参与其中。从资源优化的角度来说,开发人员不必参与需求分析,但需要理解需求。

    需求分析的结果通常我们需要使用需求说明文档来描述,目前主流的需求描述方法包括:用户例图、用户故事等方式。这些方式有所不同的侧重,其核心思想就是描述清楚用户的使用场景。但无论采取何种方式,进行需求的描述,需求说明需要明确以下几点:

    • 所需要开发的软件系统边界
    • 系统所有的相关及使用人员角色
    • 系统关键的使用场景
    • 系统规模、性能要求以及部署方式等非功能性需求

    功能设计

    功能设计与需求分析差不多同时在开展,在很多软件项目中,对于功能设计不是特别重视。但对于某些软件项目而言,这是一个相当重要的工作。对于主要是用户界面的软件项目来说,功能设计可以看作是画出原型界面,描述使用场景,获得用户认可的过程。而对于没有界面的软件项目来说,则功能设计与需求分析的区分更为模糊。

    参与的人员与需求分析的参与人员类似,架构师更侧重于参与此类工作,并给与一些实现层面的判断和取舍。

    功能设计需要明确的核心是:

    • 系统的行为

    系统架构设计

    系统架构设计是一个非常依赖于经验的设计过程。需要根据软件项目的特定功能需求和非功能性需求进行取舍,最终获得一个满足各方要求的系统架构。系统架构的不同,将很大程度上决定系统开发和维护是否能够较为容易的适应需求变化,以及适应业务规模扩张。

    架构设计工作中,用户参与程度很低。软件开发团队中的需求人员参与程度很低,但团队中的所有核心设计和开发人员都应该参与其中,并达成一致意见。

    架构设计的主要成果,是将系统的不同视图予以呈现,并使之落实到开发中:

    • 系统开发视图及技术路线选择
    • 系统逻辑视图
    • 系统部署视图
    • 系统模块视图
    • 系统的领域模型

    在软件开发过程中,系统的架构不是一成不变的,随着设计人员和开发人员对于系统的理解不断深入,系统的架构也会发生演化。在软件项目中,架构设计是开发团队沟通的统一语言,设计文档必须要随着系统的变化进行更新,保障开发团队对于系统的理解和沟通的一致性。

    模块/子系统概要设计

    模块/子系统的概要设计,由架构师参与,核心设计和开发人员负责的方式进行。

    在概要设计工作中,我们需要在架构确定的开发路线的指导下,完成模块功能实现的关键设计工作。在概要设计阶段,需要关注于模块的核心功能和难点进行设计。这个过程中更多推荐的采用UML来进行概要设计,需要进行:

    • 模块实现机制设计
    • 模块接口设计
    • 关键类设计
    • 画出时序图
    • 交互图等。

    模块详细设计

    在瀑布式开发模型中,模块的详细设计会要求比较严格,将所有类进行详细设计。据我所知,除了一些对于系统健壮性要求非常严格的软件项目,如国防项目,金融项目还要求有详细设计文档之外。其他的项目大多采用其他方式来处理这样的工作,如自动化测试等。

    综上所述,软件设计文档作为软件开发团队的沟通、理解、知识共享的手段,具有非常重要的意义。而根据软件团队的规模,对于文档上承载的信息详细程度可以有不同程度的要求。我们软件团队对于*如何使用设计文档有一个统一的理解,并坚持更新设计文档*,这就是软件设计的最佳实践!

    软件设计所需要的知识与技能

    • UML 统一建模语言
    • 软件工程
    • 面向对象的编程 OOP
    • 操作系统
    • 数据库原理
    • 设计模式
    • 沟通能力

     

    展开全文
  • 软件设计综述

    2019-07-24 20:13:58
    1. 软件设计的任务与目标 根据《软件需求规格说明书》提出的系统目标,设计出软件系 统的体系结构、接口、数据结构和处理流程,形成软件的具体实现方案,并撰写《软件设计说明书》。 软件设计是把许多事物和问题抽象...

    1. 软件设计的任务与目标
    根据《软件需求规格说明书》提出的系统目标,设计出软件系 统的体系结构、接口、数据结构和处理流程,形成软件的具体实现方案,并撰写《软件设计说明书》。
    软件设计是把许多事物和问题抽象起来,并且抽象它们不同的层次和角度。将问题或事物分解并模块化使得解决问题变得容易,分解的越细模块数量也就越多,它的副作用就是使得设计者考虑更多的模块之间耦合度的情况。
    2. 软件体系结构的内涵与主要类型;
    软件体系结构的内涵:软件体系结构是具有一定形式的结构化元素,即构件的集合,包括处理构件、数据构件和连接构件。处理构件负责对数据进行加工,数据构件是被加工的信息,连接构件把体系结构的不同部分组合连接起来。这一定义注重区分处理构件、数据构件和连接构件,这一方法在其他的定义和方法中基本上得到保持。
    软件体系结构的主要类型:结构模型 框架模型 动态模型 过程模型 功能模型
    3. 软件设计的流程、内容与主要的技术
    设计流程:
    1.需求
    2.功能定义
    3.交互设计:生成产品原型的线框图
    4.视觉设计:生成产品模型
    5.DEMO:生成产品DEMO
    6.实现:实现产品(最终阶段)
    软件设计的内容及技术:
    软件设计的描述与建模:
    类图:类图表示系统中类及类和类之间的关系,用于对系统的静态结构进行描述。类用来表示系统中需要处理的事物;类之间的关系包括关联、依赖、泛化或打包(Package)等。类之间的关系体现在类的内部结构中,通过类的属性和操作进行反映。一个典型的系统中通有若干个类图,一个类图不一定包含系统中所有的类,一个类还可以添加到多个类图。
    图由类及类与类之间的关系组成,类与类之间通常有:
    1)关联:关联表示两个类的对象之间存在某种语义上的联系。
    2)聚集:聚集也称为聚合,关联的特例。聚集表示类与类之间的关系是整体与部分的关系。
    3)泛化(继承):UML中的泛化关系就是通常所说的继承关系,它是通用元素和具体元素之间的一种分类关系。
    4)依赖和细化。
    关联的图形符号:
    普通关联 关联的角色 限定关联 关联类
    聚合: 共享聚集 组合聚集
    泛化:
    1普通泛化
    2泛化受限: 多重继承 不相交继承 完全继承 不完全继承
    依赖和细化
    状态图:状态图是一个类对象所可能经历的所有历程的模型图。状态机由对象的各个态和连接这些状态的转换组成。
    包:(Package)是UML为复杂系统建模所提供的模型元素组织与管理的通用机制。包用于定义一个名字空包用于定义一个名字空间或容器间或容器(Container),通过包可以把类、用例、组件等语义联系紧密元素聚在一起,从而实现从不同抽象层次、不同角度对系统或子系统进行建模描述,将对包中的元素作为一个整体对待对包中的元素作为一个整体对待,并且控制它们的并且控制它们的可视性和存取。
    构件图:构件图用来描述代码构件的物理结构及各个构件之间的物理关系。代码组件可以是源代码、动态链接库、子程序、独立线程或可执行文件组件。使用构件图有助于分析和理解构件之间的相互影响程度。构件是定义了良好接口的物理实现单元,它是系统中可替换的部分。每构件体现了系统设计中特定类的实现。良好定义的构件不直接依赖于其他构件而依赖于构件所支持的接口。
    部署视图:部署视图描述位于节点实例上的运行构件实例的安排。节点是一组运行资如计算机、设备或存储器。这个视图允许评估分配结果和资源分配。
    体系结构设计:根据软件设计开发经验总结出来,且命名的,针对某一类型软件软件具有通用性和推广价值的设计方案。 UML “4+1”视图 逻辑架构 进程架构 开发架构 物理架构
    软件逻辑架构: 整体/模块化结构 分层架构 MVC架构 三层架构
    软件物理架构:
    C/S架构 :特点:信息共享;人机交互性好;系统效率高;维护升级困难;胖客户端瘦服务器;数据安全性差。
    B/S架构:安装维护便利;平台无关;交互性较差
    处理流程: 浏览器 web服务器 数据库服务器
    C/S与B/S混合架构
    软件物理架构: OMG的组件定义:系统中一种一种物理的、可部署的、可替代的部件、他封装了实现并提供一系列可用的接口。
    组件优点:
    标准化:遵循组件模型标准;
    独立性:可单独部署、不依赖于其他组件;
    可组合性:通过公开接口,可进行组合;
    平台无关系:开发语言、“OS无关”;
    关联的uml表示法
    设计模式:是一套反复被使用,多数人知晓,经过分类编目的、系统设计经验的总结
    方面控制器 用例控制器
    问题与解决: 接口层不处理系统事件 UI与领域层不好耦合设计
    低耦合概念: 耦合是对一个元素与其他元素的连接,拥有知识,依赖等关系的强烈程度的度量
    高内聚:是一个元素的责任之间的关系是否密切相关和集中的度量
    4软件设计说明书的用途和主要内容。
    用途:
    主要从软件开发(程序员)角度描述软件需要实现功能,如何划分这些功能模块,各个功能模块的关系,软件的业务流程等。设计软件结构的具体任务是将一个复杂系统按功能进行模块划分、建立模块的层次结构及调用关系、确定模块间的接口及人机界面等。数据结构设计包括数据特征的描述、确定数据的结构特性、以及数据库的设计。 此软件设计说明书是为了说明整个系统的体系架构,以及需求用例的各个功能点在架构中的体现,为系统的详细设计人员进行详细设计师的输入参考文档。
    主要内容:
    1 引言
    1.1 目的
    介绍编写本文档的目的,主要内容及读者。
    1.2 需求概述
    描述所要实现的功能和性能等。
    1.3 名词及缩略语
    列出文档中所用到的专门术语的定义和缩写词的原文。
    1.4 参考资料
    a. 项目经核准的计划任务书、合同或上级机关的批文;
    b. 项目开发计划;
    c. 需求规格说明书;
    d. 文档所引用的资料、标准和规范。列出这些资料的作者、标题、编号、发表日期、出版单位或资料来源
    2 软件概述
    介绍软件的应用场合,开发和运行的背景、设计约束等等。
    2.1 系统概况
    描述软件的主要功能,以及本模块和子系统在系统中所处的位置和作用。
    2.2 运行环境
    描述软件运行的软硬件环境。
    2.3 设计约束
    列出进行本软件开发工作的假定和约束,如所采用的语言、开发工具、开发平台、中间件、数据库、外部接口,以及遵循的编码和测试规范等。
    3 总体结构设计
    3.1 软件结构
    用框图的形式说明本系统的系统元素(各层模块、子程序、公用程序等)的划分,扼要说明每个系统元素的标识符和功能,分层次地给出各元素之间的控制与被控制关系。
    3.2 设计思想
    结合上图阐述本系统的基本设计思想和理念。
    3.3 尚未解决的问题
    说明在概要设计过程中尚未解决而设计者认为在系统完成之前必须解决的各个问题。
    4 模块设计
    在此以列表形式说明各模块的名称、功能、接口、发布形式等信息。
    4.1 模块1
    详细描述各功能模块的功能、接口及内部实现。
    4.1.1 功能描述
    可以以图表方式说明本功能区域的内部结构,与其他功能模块的详细数据接口流。
    4.1.2 接口描述
    消息、函数等
    4.1.3 数据结构描述
    本功能区域使用的数据结构。
    4.1.4 类和对象描述
    采用类图和对象图描述。
    4.1.5 处理流程
    画出模块各项功能的实现流程。
    4.1.6 编译和链接说明
    对模块的编译和链接提出要求,如静态链接、动态链接,生成obj、lib、DLL、bin、hex等。
    4.2 模块2
    ……
    5 运行设计
    以列表方式描述系统的任务、线程、进程的设置,包括类型、功能、优先级、管理方法等。
    6 功能实现流程
    以用例图、顺序图、SDL图等方式,详细描述各项功能的实现流程。
    7 系统性能分析
    列出系统关键性能指标,并且对影响系统性能的功能点进行分析。
    8 数据库及数据结构设计
    8.1 数据库及数据表
    描述所使用的数据库系统,及数据库和数据表设计。
    8.2 数据结构设计
    给出本系统内所使用的每个数据结构的名称、标识符以及它们之中每个数据项、记录、文卷和系的标识、定义、长度及它们之间的层次的或表格的相互关系。
    8.3 数据存储设计
    给出本系统内所使用的每个数据结构中的每个数据项的存储要求,访问方法、存取单位、存取的物理关系(索引、设备、存储区域)、设计考虑和保密条件。
    9 定时器设计
    列表描述所有定时器的类型、用途、范围、默认值、启动、停止、扫描、超时处理等。
    10 外部接口设计
    说明本系统同外界的所有接口的安排包括软件与硬件之间的接口、与各支持软件之间的接口、与网管之间的接口等。
    10.1 用户界面设计
    参见《UI设计说明书》。
    10.2 硬件接口
    描述需要访问的硬件接口的类型、控制方式,:如中断、寄存器等。
    10.3 软件接口
    描述与其他模块及子系统的接口。
    11 兼容性设计
    列出与前后版本,以及其他模块、系统、子系统间可能存在的兼容性问题,以及对策。
    12 系统维护设计
    12.1 安装和升级
    描述软件安装和使用方面的考虑。
    描述软件升级的方式,以及升级时的兼容性和数据迁移方面的考虑。
    12.2 系统配置
    列出系统各种配置项的内容。
    12.3 日常维护
    如果有日常维护的需要,给出具体的实现方法。
    13 系统测试设计
    从代码的静态测试,到运行时的动态测试等方面详细描述实现方法。
    14 安全和可靠设计
    14.1 系统安全

    1. 系统安全控制和物理保护措施
    2. 用户身份鉴别机制
    3. 用户对系统的访问权限和范围
      14.2 数据安全
      说明在数据库的设计中,将如何通过区分不同的访问者、不同的访问类型和不同的数据对象,进行分别对待而获得的数据库安全保密的设计考虑,如:
    4. 数据用户身份鉴别
    5. 访问时的控制策略和实现方法
    6. 数据加密方法
      14.3 可靠性设计
      14.3.1 故障模式及影响分析(FMEA)
      列表分析各种可能的故障模式,以及相应的对策。
      14.3.2 避错和容错设计
      列举所采取的避错和容错设计措施,降低系统故障概率。
      14.3.3 冗余设计
      如采取系统冗余、 数据冗余等措施。
      14.3.4 故障检测和恢复机制
      可以采用watchdog、守护进程、异常处理等机制检测系统故障,并且进行局部或全局重启动机制,恢复系统运行。
      对于数据的恢复,可以从冗余或备份数据中恢复。
      15 日志和错误处理
      15.1 日志记录机制
      用一览表的方式说明每种可能的日志(如运行日志、操作日志、故障日志)如何进行记录,记录那些内容。
      15.2 错误信息及输出机制
    展开全文
  • 软件设计概述

    万次阅读 2016-08-28 19:58:20
    软件设计是把需求转化为软件系统的最重要的环节,系统设计的优劣在根本上决定了软件系统的质量。 在此,主要阐述软件系统设计的5个核心内容:体系结构设计、用户界面设计、数据库设计、模块设计、数据结构和算法...

    from:http://blog.csdn.net/guoxiaoqian8028/article/details/24204273

    概述

    软件设计是把需求转化为软件系统的最重要的环节,系统设计的优劣在根本上决定了软件系统的质量。

    在此,主要阐述软件系统设计的5个核心内容:体系结构设计、用户界面设计、数据库设计、模块设计、数据结构和算法设计。旨在帮助开发人员搞清楚“设计什么”以及“如何设计”。

    一般把设计过程划分为两个阶段:概要设计阶段和详细设计阶段,如下所示:

    • 概要设计阶段的重点是体系结构设计。
    • 详细设计阶段的重点是用户界面设计、数据库设计、模块设计、数据结构与算法设计等。

    可根据项目的情况进行文档裁减和过程合并,如项目开发过程只有一个设计阶段和设计文档。

    体系结构

    体系结构如同人的骨架。如果某个家伙的骨架是猴子,那么无论怎样喂养和美容,这家伙始终都是猴子,不会成为人。

    由此可见,体系结构乃是系统设计的重中之重。

    目前业界比较流行的软件结构模式有C/S(客户/服务器)、B/S(BROWSE/SERVER)、层次结构(上下级层次结构、顺序相邻的层次结构、含中间件的层次结构)

    体系结构设计原则

     合适性

    即体系结构是否适合于软件的“功能性需求”和“非功能性需求”。高水平的设计师高就高在“设计出恰好满足客户需求的软件,并且使开发方和客户方获取最大的利益,而不是不惜代价设计出最先进的软件。

     结构稳定性

    详细设计阶段的工作如用户界面设计、数据库设计、模块设计、数据结构与算法设计等等,都是在体系结构确定之后开展的,而编程和测试则是更后面的工作,因此体系结构应在一定的时间内保持稳定。

    软件开发最怕的就是需求变化,但“需求会发生变化”是个无法逃避的现实。人们希望在需求发生变化时,最好只对软件做些皮皮毛毛的修改,可千万别改动软件的体系结构。如果当需求发生变化时,程序员不得不去修改软件的体系结构,那么这个软件的系统设计是失败的。

    高水平的设计师应当能够分析需求文档,判断出哪些需求是稳定不变的,哪些需求是可能变动的。于是根据那些稳定不变的需求设计体系结构,而根据那些可变的需求设计软件的“可扩展性”。

     可扩展性

    可扩展性是指软件扩展新功能的容易程度。可扩展性越好,表示软件适应“变化”的能力越强。

    可扩展性越来越重要,这是由现代软件的商业模式决定的:

    • 社会的商业越发达,需求变化就越快。需求变化必将导致修改(或者扩展)软件的功能,现代软件的规模和复杂性要比十年前的大得多(对比一下操作系统的变化就明白了),如果软件的可扩展性比较差的话,那么修改(或者扩展)功能的代价会很高。
    • 现代软件产品通常采用“增量开发模式”,开发商不断地推出软件产品的新版本,从而不断地获取增值利润。如果软件的可扩展性比较差的话,每次开发新版本的代价就会很高。虽然开发商抓住了商机,但却由于设计水平差而导致没有赚取多少利润,真是要活活气死。

     可复用性

    由经验可知,通常在一个新系统中,大部分的内容是成熟的,只有小部分内容是创新的。一般地可以相信成熟的东西总是比较可靠的(即具有高质量),而大量成熟的工作可以通过复用来快速实现(即具有高生产率)。

    可复用性是设计出来的,而不是偶然碰到的。要使体系结构具有良好的可复用性,设计师应当分析应用域的共性问题,然后设计出一种通用的体系结构模式,这样的体系结构才可以被复用。

    用 户 界 面 设 

    为了提高用户界面的易用性和美观程度,总结了十个设计原则。用于提高易用性的界面设计原则有8个:

    • 用户界面适合于软件的功能
    • 容易理解
    • 风格一致
    • 及时反馈信息
    • 出错处理
    • 适应各种用户
    • 国际化
    • 个性化

    用于提高美观程度的设计原则有:

    • 合理的布局
    • 和谐的色彩

     用户界面适合于软件的功能

    用户界面的合适性是指界面与软件功能相融洽的程度。软件的功能需要通过用户界面来展现,用户界面一定要适合于软件的功能,这是最基本的要求。界面的合适性既提倡外美内秀,又强调恰如其分。

     容易理解

    提高用户界面可理解性的一些规则如下:

    • 界面中的所有元素(如菜单、工具条等)没有错误,也不会让人误解。
    • 所有的界面元素应当提供充分而必要的提示,例如当鼠标移动到工具条上的某个图标按钮时,应当在该图标旁边出现功能提示。
    • 界面结构能够清晰地反映工作流程,以便用户按部就班地操作。
    • 对于复杂的用户界面而言,最好提供界面“向导”,及时让用户知道自己在界面结构中所处的位置。例如对于基于Web的应用软件,应该在界面上显示“当前位置”,否则用户很容易在众多的页面中迷失方向。

    ● 风格一致

    风格一致有两方面的含义:

    (1) 一个软件的用户界面中,同类的界面元素应当有相同的视感和相同的操作方式。例如命令按钮是最常见的界面元素,所有命令按钮的形状、色彩以及对鼠标的响应方式都是一致的。

    (2) 同一类型软件的用户界面应当有一定程度的相似性。例如Microsoft公司的Office家族里有Word、Excel、PowerPoint、Outlook等软件,这些软件提供的“复制、剪切、粘贴”功能的操作方式都是相同的。

     及时反馈信息

    用户进行某项操作后,如果过了一会儿(几秒钟)用户界面一点反应都没有,这将使用户感到迷茫和不安,因为他不知道是自己操作错了还是软件的原因导致死机了。所以及时反馈信息很重要,至少要让用户心里有数,知道该任务处理得怎么样了,有什么样的结果。

    例如下载一个文件,界面上应当显示“百分比”或相关数字来表示下载的进度,否则人们不知道要等待多少时间。如果某些事务处理不能提供进度等数据,那么至少要给出提示信息如“正在处理,请等待…”,最好是提供合适的动画,让用户明白软件正在干活、没有死机。

     出错处理

    在设计用户界面时必须考虑出错处理,目的是让用户不必为避免犯错误而提心吊胆、小心翼翼地操作。常见的错误处理方式有:

    • 提供对输入数据进行校验的功能。当用户输入错误的数据时,及时提醒用户改正数据。
    • 对于在某些情况下不应该使用的菜单项和命令按钮,将其“失效”(屏蔽)可以有效防止该项功能被错误地使用。例如:对于某些管理软件,不同的用户有不同的操作权限。如果低权限的用户登录到系统,那些只有高级权限用户才能使用的功能应当被屏蔽(如变成“灰色”不可操作)。
    • 提供Undo功能,用以撤销不期望的操作。
    • 执行破坏性的操作之前,应当获得用户的确认。例如用户删除一个文件时,应当弹出对话框:“真的要删除该文件吗”,当用户确认后才真正删除文件。

     合理的布局

    首先,界面的布局应当符合逻辑,最好能够与工作流程吻合。界面设计人员只有仔细地分析软件的需求,才能提取对界面布局有价值的信息。

    其次,界面的布局应当整洁(整齐清爽)。界面元素应当在水平或者垂直方向对齐,行、列的间距保持一致。窗体的尺寸要合适,各种控件不能过分拥挤也不能过分宽松。要善于利用窗体和控件的空白,以及分割用的线条。

     和谐的色彩

    用户界面是否美观,主要取决于该界面的布局和色彩搭配。实现“合理的布局”相对比较容易一些,设计和谐的色彩太困难了,因为色彩的组合千变万化,并且人们对颜色的喜好也极不相同。

    对于广大软件开发人员而言,虽然我们没有必要让普通软件的界面漂亮到Windows XP这种程度,但是掌握一些界面色彩的设计原则无疑是非常有益的。

    • 如果不是为了显示真实感的图形和图像,那么应当限制一帧屏幕的色彩数目,因为人们在观察屏幕的时候很难同时记住多种色彩。
    • 应当根据对象的重要性来选择颜色,重要的对象应当用醒目的色彩表示。
    • 使用颜色的时候应当保持一致性,例如错误提示信息用红色表示,正常信息用绿色表示,那么切勿篡用红色和绿色。
    • 在表达信息时,不要过分依赖颜色,因为有些用户是色盲或色弱。

    数据库设计

     开发与平台无关的数据库应用程序

    目前国际上应用最广泛的数据库系统有Oracle、DB2、Informix、Sybase和SQL Server。

    这些数据库系统之间的激烈竞争即有好处又有坏处。竞争的好处是使数据库系统不断发展和完善,并且避免价格垄断。竞争的最大坏处是逼迫数据库厂商不断开发出独特的功能以吸引更多的用户,所以各个数据库系统的独特功能无法形成统一标准,导致用户难以开发出与平台无关的数据库应用程序,因为用户很难抵御数据库系统独特功能的诱惑。

    读者也许会问:“结构化查询语言(SQL)难道不是数据库系统的标准吗?”

    是的,SQL是数据库系统的标准查询语言。可是数据库厂商提供了太多超出SQL标准的特色功能,使人们陷入了进退两难的境地:

    • 如果你想使程序与数据库平台无关,那么只能使用SQL,放弃各个数据库系统的独特功能。
    • 如果你超越SQL,使用了某个数据库系统的独特功能,那么这样的程序就是与平台相关的。
    • 类似问题也存在于操作系统、Web浏览器这些领域。理论上讲,只有绝对垄断才能形成绝对统一的标准,但是人们既希望打破垄断又希望有统一的标准,这种矛盾无法彻底解决,只能折衷、妥协。建议如下:
    • 如果你开发的是通用的数据库应用软件,不想让应用软件与特定的数据库系统捆绑在一起,那么你就老老实实地用SQL语言写程序。
    • 如果你开发的是行业专用的数据库应用软件,并且这个行业已经指定了数据库系统(这种局部垄断现象普遍存在),最近若干年都不会改变的话,那么你可以超越SQL使用该数据库系统的独特功能。

     数据库性能优化问题

    数据库设计的主要挑战是“高速处理大容量的数据”。如何优化数据库的性能是设计人员经常面临的问题。数据库性能优化主要有两种途径:

    • 优化表结构本身。例如对第三范式的表结构进行反规范化处理,允许表中存在冗余数据,从而减少多个表链接操作,达到提高性能的目的。
    • 优化数据库的环境参数。例如提高硬件设施,调整表的空间尽量减少数据碎片等。

    在表的物理设计阶段,设计人员应当按照第三范式设计表结构(即规范化处理)。这样做的好处是:表中没有冗余数据,表结构很清晰,将来修改或者扩充非常方便。但是按第三范式设计也存在一些缺点:产生了许多表,每个表有相对较少的列,并且这些列必须使用“主健/外健”关联起来,因此某个查询操作可能会产生复杂的表链接,导致性能降低。

    反规范化处理是指对第三范式的表进行修改,通过合并一些表,或者在表中创建冗余的列,从而减少表链接操作代价,达到提高性能的目的。要注意的是反规范化处理存在很大的负面影响:管理冗余数据很麻烦,如果冗余数据不同步的话,那么会发生数据错误这种严重的问题。

    所以,对表进行第三范式的规范化处理是第一重要的,而反规范化处理则需谨慎考虑、不宜过多使用。“规范化处理”以及“反规范化处理”不是自相矛盾之举,而是性能优化的策略。

    除了优化表结构之外,优化数据库的环境参数也能够提高数据库的性能。例如给服务器配置更快的CPU,增加内存。运行数据库是非常消耗内存的,内存对数据库性能影响比较大。由于现在市场上的内存条越来越便宜,所以为服务器配置足够多的内存恐怕是成本最低、难度最低、见效最快的性能优化方法。

    在安装数据库系统时,要为系统指定“块大小”(一次物理读写操作所设计的字节数)。在创建表时,也要为表指定一定的空间。如果“块大小”和“表空间”与实际的数据存储不匹配的话,那么会产生许多磁盘碎片,这将降低数据库物理操作的性能。

    能否有效地优化应用软件数据库的性能,主要取决于开发者对数据库系统的熟悉程度以及开发经验。

    ● 数据库安全问题

    提高软件系统的安全性应当从“管理”和“技术”两方面着手。这里仅考虑技术手段(因为安全管理超出了软件工程范畴),一般原则如下:

    • 用户只能用帐号登陆到应用软件,通过应用软件访问数据库,而没有其它途径可以操作数据库。
    • 对用户帐号的密码进行加密处理,确保在任何地方都不会出现密码的明文。

    确定每个角色对数据库表的操作权限,如创建、检索、更新、删除等。每个角色拥有刚好能够完成任务的权限,不多也不少。在应用时再为用户分配角色,则每个用户的权限等于他所兼角色的权限之和。

    模块设计

    在设计好软件的体系结构后,就已经在宏观上明确了各个模块应具有什么功能,应放在体系结构的哪个位置。我们习惯地从功能上划分模块,保持“功能独立”是模块化设计的基本原则。因为,“功能独立”的模块可以降低开发、测试、维护等阶段的代价。但是“功能独立”并不意味着模块之间保持绝对的孤立。一个系统要完成某项任务,需要各个模块相互配合才能实现,此时模块之间就要进行信息交流。

    评价模块设计优劣的三个特征因素:“信息隐藏”、“内聚与耦合”和“封闭——开放性”。

     信息隐藏

    为了尽量避免某个模块的行为去干扰同一系统中的其它模块,在设计模块时就要注意信息隐藏。应该让模块仅仅公开必须要让外界知道的内容,而隐藏其它一切内容。

    模块的信息隐藏可以通过接口设计来实现。接口是模块的外部特征,应当公开;而数据结构、算法、实现体等则是模块的内部特征,应当隐藏。一个模块仅提供有限个接口(Interface),执行模块的功能或与模块交流信息必须且只须通过调用公有接口来实现。如果模块是一个C++对象,那么该模块的公有接口就对应于对象的公有函数。如果模块是一个COM对象,那么该模块的公有接口就是COM对象的接口。一个COM对象可以有多个接口,而每个接口实质上是一些函数的集合。

     高内聚

    内聚(Cohesion)是一个模块内部各成分之间相关联程度的度量。内聚程度从低到高大致划分为低端、中段和高端,如图3-15所示。模块设计者没有必要确定内聚的精确级别,重要的是尽量争取高内聚,避免低内聚。

    顺序性内聚 功能性内聚

    时序性内聚 过程性内聚 通讯性内聚

    偶然性内聚 逻辑性内聚

    低端… 中段… 高端…

    各种内聚类型的含义如下:

    • 偶然性内聚。如果一个模块的各成分之间的关系彼此松散(几乎无关),称为偶然性内聚。
    • 逻辑性内聚。几个逻辑上相关的功能被放在同一模块中,则称为逻辑性内聚。例如一个模块读取各种不同类型外设的输入。
    • 时序性内聚。如果一个模块内的几个功能必须在同一时间内执行(如系统初始化),但这些功能只是因为时间因素关联在一起,则称为时间性内聚。
    • 过程性内聚。如果一个模块内部的处理成分是相关的,而且这些处理必须以特定的次序执行,则称为过程性内聚。
    • 通信内聚。如果一个模块的所有成分都操作同一数据集或生成同一数据集,则称为通信内聚。
    • 顺序内聚。如果模块内的某个成分的输出作为另一个成分的输入,则称为顺序内聚。
    • 功能内聚。模块的所有成分对于完成单一的功能都是必须的,则称为功能内聚。

     低耦合

    耦合(Coupling)是模块之间依赖程度的度量。内聚和耦合是密切相关的,与其它模块存在强耦合的模块通常意味着弱内聚,而强内聚的模块通常意味着与其它模块之间存在弱耦合。

    耦合的强度依赖于以下几个因素:(1)一个模块对另一个模块的函数调用数量;(2)一个模块向另一个模块传递的数据量;(3)一个模块施加到另一个模块的控制的多少;(4)模块之间接口的复杂程度。

    耦合程度从低到高大致划分为低端、中段和高端,如图3-16所示。模块设计应当争取“高内聚、低耦合”,而避免“低内聚、高耦合”。

    印记耦合 控制耦合

    公共耦合 内容耦合

    非直接耦合 数据耦合

    低端… 中段… 高端…

    各种耦合类型的含义如下:

    • 非直接耦合。模块之间没有直接的信息传递,称为非直接耦合。
    • 数据耦合。模块之间通过接口传递参数(数据),称为数据耦合。
    • 标记耦合。模块间通过接口传递内部数据结构的一部分(而不是简单的参数),称为印记(Stamp)耦合。此数据结构的变化将使相关的模块发生变化。
    • 控制耦合。模块传递信号(如开关值、标志量等)给另一个模块,接收信号的模块根据信号值调整动作,称为控制耦合。
    • 公共耦合。两个以上的模块共同引用一个全局数据项,称为公共耦合。
    • 内容耦合。当一个模块直接修改或操作另一个模块的数据,或者直接转入另一个模块时,就发生了内容耦合。

    数据结构与算法设计

    设计高效率的程序是基于良好的数据结构与算法,而不是基于编程小技巧。

    一般说来,数据结构与算法就是一类数据的表示及其相关的操作(这里算法不是指数值计算的算法)。从数据表示的观点来看,存储在数组中的一个有序整数表也是一种数据结构。算法是指对数据结构施加的一些操作,例如对一个线性表进行检索、插入、删除等操作。一个算法如果能在所要求的资源限制(Resource Constraints)范围内将问题解决好,则称这个算法是有效率(Efficient)的。例如一个资源限制可能是“用于存储数据的内存有限”,或者“允许执行每个子任务所需的时间有限”。一个算法如果比其它已知算法所需要的资源都少,这个算法也被称为是有效率的。算法的代价(Cost)是指消耗的资源量。一般说来,代价是由一个关键资源例如时间或空间来评估的。

    毋庸置疑,人们编写程序是为了解决问题。只有通过预先分析问题来确定必须达到的性能目标,才有希望挑选出正确的数据结构。有相当多的程序员忽视了这一分析过程,而直接选用某一个他们习惯使用的,但是与问题不相称的数据结构,结果设计出一个低效率的程序。如果使用简单的设计就能够达到性能目标时,选用复杂的数据结构也是没有道理的。

    人们对常用的数据结构与算法的研究已经相当透彻,可以归纳出一些设计原则:

    1) 一种数据结构与算法都有其时间、空间的开销和收益。当面临一个新的设计问题时,设计者要彻底地掌握怎样权衡时空开销和算法有效性的方法。这就需要懂得算法分析的原理,而且还需要了解所使用的物理介质的特性(例如,数据存储在磁盘上与存储在内存中,就有不同的考虑)。

    2) 开销和收益有关的是时间——空间的权衡。通常可以用更大的时间开销来换取空间的收益,反之亦然。时间——空间的权衡普遍地存在于软件开发的各个阶段中。

    3) 设计人员应该充分地了解一些常用的数据结构与算法,避免不必要的重复设计工作。

    4) 数据结构与算法为应用服务。我们必须先了解应用的需求,再寻找或设计与实际应用相匹配的数据结构。

    数据结构与算法设计的一般流程如下:

    (1)数据结构与算法有全局和局部之分,当然先设计全局的,后设计局部的(通常在模块设计时进行)。

    (2)根据问题的特征,先查找已经存在的数据结构与算法,挑选最合适的(并不一定是最先进的)。如果不存在现成的,那么自己设计。

    (3)设计并且编写代码之后,要进行测试。如果不满足性能要求,那么要进一步优化数据结构和算法。

    1  系统设计的关键

    软件设计活动的关键又是什么呢?还是让我们回到现实世界去寻找答案吧!

    在远古时期,人类只能通过徒步从一个地方到达另一个地方。后来发现马可以被驯服,通过马车能更快地从一处到达另一处。再后来,人类逐步发明了自行车、汽车和飞机,且每一次发明都使得交通效率得以大幅提高。在这里,马车、自行车、汽车和飞机都共同地为了解决交通效率问题。很显然,马车、自行车、汽车和飞机都是不同的概念,人类通过抽象发明这些概念,并通过相互学习的方式使得大家掌握其含义。如果将焦点放在交通工具上,我们会发现交通效率越高则其概念越抽象,复杂度也越高。或者说,越是抽象的概念,其所隐藏的复杂度就越高。

    从这个关于交通的例子中我们不难发现,现实世界中我们是通过转移复杂度的方式解决复杂问题的,且每一次不同的转移都伴随着抽象概念的建立,转移的复杂度越多所建立的概念就越抽象。由于复杂度被转移了后,使得一小部分人专注于被转移的复杂度(比如制造飞机),而其他绝大部分人在享用复杂度被转移所带来好处的同时不用关心被转移走的复杂度(乘飞机的人不用关心飞机的驾驶与制造)。同样的事情也发生在软件行业!不同的是软件行业“制造”的不是汽车和飞机,而是编程语言、数据库、平台和框架等。

    不难发现,软件设计的关键活动应是抽象,通过抽象建立新的概念并将部分复杂度转移到概念背后。尽管不断的抽象增加了新概念的复杂度,但也简化了所需解决问题的复杂度。显然,好的设计应是其简化的复杂度要大于因为抽象所创造的复杂度。

    2  系统设计的目标

    系统设计的目标是在保证实现用户功能和必要的性能的前提下,保证系统的质量特性达到规定的要求。

    系统的功能、性能和质量特性必须通过设计来体现,通过设计方案的选择来证明系统能够满足用户在系统功能、性能和质量特性方面的用户需求。

    3  系统设计的依据

    系统设计以需求规格说明书为输入,以产生满足功能需求和非功能需求的设计方案为输出。

    首先,待开发的软件系统必须满足功能需求。确切地讲,首先必须满足用户功能需求,即软件系统可以帮助用户(包括系统所属用户和直接使用系统的用户)解决用户希望解决的问题。

    其次,待开发的软件系统必须满足非功能需求。满足非功能需求意味着软件系统能够像用户所希望的那样解决问题,并且维护方便。这里,有三个方面的问题:

    1、对约束的满足。软件系统能够在用户给定的环境下有效运行。约束是多方面的,包括硬件环境、软件环境、社会环境(包括国家法律法规)、企业管理环境。当企业信息化进行到一定阶段时,约束对软件系统开发构成了不可逾越的障碍。

    2、软件的可用性。软件的可用性除了软件系统满足约束外,还有软件使用的方便性、可靠性、安全性等。--运行期质量

    3、软件的可维护性。软件的可维护性不仅仅是软件开发组织降低软件维护成本的要求,实际上也是用户的要求。当用户需求发生变化后,用户希望能够很快地修改软件系统而不影响对业务的处理。

    开发架构设计关注软件开发环境中软件模块的实际组织方式,即软件系统由那些程序包组成,以及它们之间的关系。程序包不仅包括要编写的源程序,而且包括直接使用的第三方SDK和现存的框架、类库,支持系统运行的操作系统或中间件。

    开发架构设计的重点考虑开发期质量,软件模块的组织有利于可扩展性、可重用性、可移植性、易理解性、易测试性等,设计中的关键技术主要体现软件开发期质量有关的设计,如设计模式的运用,框架的选择等。

    开发架构设计的主要工作是:

    确定要开发的程序包或直接利用的程序包(如函数库)之间的依赖关系。

    采用的技术,包之间采用什么技术实现连接,以保证必要的开发期质量,如有依赖关系的包之间的松耦合。

    确定采用的框架。如果实现连接的技术有对应的框架,采用框架是值得推荐的选择。

    分层模型开发架构设计的主要工具。三层架构模型把程序代码分成负责与用户交互的表现层(用户界面层)代码、负责业务处理的业务层代码、负责数据服务的数据层代码。表现层可以按用例分成若干个包,业务层可以可以按照业务逻辑独立性分成若干个包,数据层可以由若干实体对象组成。其中,业务层由领域模型细化得到。由于领域模型相对稳定,所以业务层也相对稳定。表现层受表现设备和表现方式影响,数据层受数据库系统影响,因此这两层必须满足可扩展性、可修改性等要求。

    分层架构模式为“把变化点封装起来”提供了手段。分层架构的最大优点是将整体问题局部化,把可能的变化封装到不同层中。最终将系统规划为单向依赖的分层体系,利于修改、扩展、替换。将代码分为层的好处是:层形成了开发小组的自然边界—分层的开发人员需要的技巧是不同的。表现层的开发小组要深入了解用户界面工具包的使用;数据层开发小组许傲熟悉相关的数据库、数据持久化工具或文件系统。

    采用分层和分区的描述方式能够反映直接使用的程序包或框架的用法,使开发架构更清晰


    附录美文:http://www.csdn.net/article/2015-08-18/2825486

    为了给企业提供稳定可靠且优质的服务,作为一名软件架构师,在应用的架构设计上也是费尽心思,本文作者来自“风语者客服+”的CTO黄耀华,他从自己多年的实践出发,总结了软件架构设计的一些经验,分享给大家。

    “风语者客服+”是针对中小型企业推出的客服SaaS,节约了企业自建客服系统所需的巨大成本。为了给企业提供稳定可靠且优质的服务,我们在整体架构上费尽心思。虽然不尽完美,希望借此抛砖引玉,互相切磋。

    前言

    ”Look deep into nature, and then you will understand everything better.“ -- Albert Einstein

    我国传统文化上,要做成一件事,讲究三个方面:明道,优术,取势。在软件架构设计方面而言,也是类似的道理:遵循自然规律以明确大的方向,使用优秀的实操战术,再根据实际情况落地。

    这是个快餐年代,几乎所有人都只做一件事 -“取势”。 几乎没有多少人会去理解一个Servlet的工作原理,去理解一次HTTP请求的完整流程,因为有超多框架帮你屏蔽了这里的细节。询问一个人会什么技术,回答也往往是我会Hibernate、Spring、Ibatis、会PullToRefresh组件、会使用SDWebimage。不过这些框架(Framework)其实并不是软件架构。软件架构是一所有生命力的房子,而这些框架只是大一点的板砖。

    因为笔者水平有限,这里只提一些普遍准则,也就是”正确的废话“,以飨视听。不会深入到实操战术上,比如怎么用Spring实施MVC架构,怎么使用Maven管理依赖,Redis的常用操作,怎么搭建一个负载均衡的集群,如何使用阿里巴巴的Dubbo框架进行服务化等等。如果大家有兴趣,可以自行搜索,有很多优秀的文章可供参考。

    不幸的“程序猿”和“程序媛”各有各的痛苦,幸福的程序员都是相似的。其实说幸福有点言过其实,下面就说说怎么让他们不那么痛苦。

    一. 很好的模块化支持

    “At the bottom of every person's dependency, there is always pain, Discovering the pain and healing it is an essential step in ending dependency.” --Chris Prentiss

    他们都在一个相对稳定的软件架构里编码,自己的代码不会依赖很多模块,不会因为自己微小的改动造成全局的失败。正如"1984"中的老大哥说的,Ignorance is strength(”对外界的“无知就是一种力量).  任何一个模块都不能有太强的存在感。

    曾经在一个大型互联网公司里面,任何人只要用到一个核心模块的功能,就必须依赖一个部署在某远程服务器的库,而且还有IP限制,只能把代码部署到指定网段才能运行起来。导致基本上没法在本地进行单元测试或者简单调试。这个核心库的存在感太强,就成了开发的瓶颈,严重的降低了生产力和码农的幸福程度。

    在“风语者客服+”的架构中,每个码农都可以很方便的在本地把服务启动起来,一分钟up and running,随便做一些改动就可以立竿见影的看到效果。这里要归功于几个东西:

    1. Git代码管理

    在团队作战中,每个程序员可以取下来完整的最新代码库,也可以在本地分支上尽情挥毫泼墨,而不担心影响别人的工作。也可以把本地修改先stash起来,review一下别人的代码,再unstash恢复回来。要想提高团队效率,代码仓库管理建议尽快迁移到Git上。

    2. Maven、Gradle、Cocopods等依赖管理

    Maven是一个管理依赖(Dependency)的工具,现在在Java社区应该是比较普及的,无法想象现在还有团队直接拷贝jar包来管理依赖。虽然早期没有Maven的时候,都是拷贝jar包这么过来的,碰到的问题也是显而易见的,依赖的jar包作者改了某个bug,没能及时传导到调用方。多个调用方使用不一致的jar包,导致各种奇异bug。对应的在安卓社区,使用gradle的比较多,iOS的Objective-C开发中,多采用CocoaPods。

    二. 高内聚,低耦合

    He should focus on his knitting, not trying to do everything. Do one thing well.-- Steve Jobs

    "Do one thing well"其实不算是老乔的专利,UNIX哲学和Google哲学都提倡这一点。这句话本身不完全对,比如对于一个商人,如果只会Do one thing well,那他无法在市场中存活,但是在工程师中却是万般推崇的哲学。

    我们可以期望一个人具备一百种技能,然而对一个工具只期望它把一个需求解决好解决彻底,对于实现工具的一个类,一个方法,更是如此。但是,实际经验中,我们经常看到一个5000行以上代码的类,活像一个巨人版的瑞士军刀,什么都能做,但是什么都做不好。这就是”Separation of Duty"没有做好的典范。

    在风语者”客服+“对外提供的SDK和API中,我们也提倡同样的思想,力争把App使用”客服+“SDK的门槛降到最低,每个API都能自言其一,而且API直接没有时序上的依赖关系。内部各个模块的开发,也秉承同样的责任分割原则。责任分割原则的落实,没有什么好的框架或者工具来支持。只能通过老鸟经常去做Code Review,找出存在的问题,提出重构方案,并督促菜鸟改进。

    个人一般采用的重构思路,仅作为参考,照搬后被老板批评乃至造成工伤概不负责:

    1. 把一个大的工具类,根据主题不同,拆分成若干个互不干扰的高内聚工具类;举个例子,一个万能的NetworkUtils可能可以拆成HttpUtils, FTPUtils,TelnetUtils等;
    2. 对于一个被频繁调用的类,仔细观察调用情况,如果有一些方法的被调用频率远远低于其他方法,那么需要考虑这个方法是不是应该放在这个类中;
    3. 存在A,B两个类之间的相互依赖,或者更多类的混乱依赖,那么就更要抽丝剥茧,通过合理安排类的功能来去除环形依赖;
    4. 尝试一句话说清楚一个类的功能,不要使用“和”,“以及”,“或者”等连接词;如果出现了这些连接词,就需要引起重视;

    三. 用进化拥抱变化

    “It is not the strongest or the most intelligent who will survive but those who can best manage change.” ― Leon C. Megginson

    前段时间,朋友圈疯传一篇文章 -——“架构腐化之谜”,大家都深表同感,纷纷表示对自己架构的未来的担忧。然而,说句不合时宜的话, 90%的担忧是杞人忧天,因为以现在产品更新换代的速度,90%的项目面市即意味着死亡,没等到架构腐朽,产品已经入土了。

    剩下10%里面,也许有9%会一直坚持活下去,但是不会蓬勃发展,也就是说,只要保证不出现内存泄露之类的问题,代码就会一直在几台小服务器上运行下去,哪怕后面没有人维护也没关系。只有1%的产品,会日新月异的更新迭代,最终成长为巨无霸,或者巨无霸的生态下的一个环节。这个言论看似悲观,却是对现实最好的妥协。

    谬用一下泰戈尔的名言:“不是槌的打击,而是水的载歌载舞,使鹅卵石臻于完美”, 不是闭门造车的架构,而是不断拥抱变化的需求,才使得架构臻于完美。

    假如在早期就纠结于架构的完美性,而延迟产品的交付,是非常得不偿失的。只有生存下来,才有机会。再根据市场变化,不断优化架构,从而延长软件的生命周期。那么,假如撞大运,真的成了这1%,怎样做才能算是拥抱变化?

    首先,请参考本文第一点和第二点。如果这两点基本功没有练好,那么谈架构的进化就和还没有通关十八罗汉的新手就想练成九阴真经是一个道理。

    在设计之初,初步考虑系统的Scalability(可伸缩性)

    下面在第四点会详细阐述。

    内部的各个模块尽量做到可插拔

    一方面是接口和实现的分离,可以随着需求的变化更换实现;另一方面,尽量把功能服务化,成为微服务,并且可以监控到服务的互相调用情况,当某个服务老化,可以逐步废弃或使用新的服务取代之。这一点上,阿里巴巴的Dubbo框架是一个不错的选择。

    尽量采用优秀的框架,站在巨人的肩膀上

    例如在Web层面,我们使用Twitter的Bootstrap前端框架来实现响应式Web编程,提高生产效率的同时减少了为解决各种设备适配问题的投入。当然,这就需要设计师配合,按照Bootstrap规范来设计页面,减少一些个性化设计。

    最后,考虑系统的Resilience(弹性,也叫耐受性)

    俗一点说,就是变成一只打不死的小强,代码中尽量提前预判可能遇到的各种情形。经常看到代码里面有一堆的if(){}判断语句,我就问作者,“你考虑过else{}吗?”一般回答都是,“这绝对只有if,不会有else的”,可如果真的遇到else怎么办?千年虫问题就是这么诞生的。可能很多新同学还不知道什么是千年虫问题,简单地说,就是当年的码农,为了省一点内存空间,只用了2位数来表达年份,比如int year = 98; 表达1998年。我猜码农当时的心态也是,“就我这代码,还能活到2000年,搞笑吧?”

    程序员们平时可以多扩大自己的脑洞,想想有哪些else情况自己没有处理,而且可以轻易处理的。比如服务器挂了,那么App端是不是也要跟着crash,还是给出友好一点的提示,或者更友好一点,使用本地缓存。

    四. 设计可扩展,但不要过度设计

    it's better to have infinite scalability and not need it, than to need infinite scalability and not have it--@littleidea 网友

    无限的扩展能力是一种奢望,但是起码不能让扩展能力成为0。试想一下,你辛辛苦苦为老板开发了一个网站,过了一个月,网站超负荷了,老板说,“小A啊,之前2台服务器花了我5万块,预计流量马上要翻倍了,再给你5万块,帮我扛过去啊。”结果你发现,问题不是线性增加服务器就能解决的,原来的程序没有做分层(Web,Business Logic, Data Access等),导致加服务器也只能把所有层的代码全搬到新的服务器,虽然只是Business Logic的计算有压力,却要浪费老板很多服务器。更糟糕的是,因为程序里面用到了文件系统和操作系统命令,不好做负载均衡。

    这里有一些准则供参考:

    1. 代码分层是必须的,层次明朗以后,当哪个层次的负载较重,想办法对该层次进行优化或者扩容即可;
    2. 保持核心服务是无状态的,所谓无状态就是没有和请求相关的数据依赖;
    3. 尽可能的选用已被验证的广泛采用的成熟基础架构;
    4. 充分利用Zookeeper等集群管理工具,来对服务进行管理;

    风语者“客服+”中,把业务相关的代码内部组装为风语者ServiceBox,使用阿里巴巴的Dubbo服务进行注册管理。当负载增加时,可以迅速在运维层面增加服务节点,以提供更高的服务能力,从而保证客户的优质体验。


    展开全文
  • 软件设计方案

    千次阅读 2018-10-19 18:38:28
    软件设计方案 1 引 言 1.1 编写目的 阐明编写本设计方案说明书的目的,指明读者对象。 1.2 项目背景 包括:a.本项目的委托单位、研制单位和主管部门;b.该软件系统与其它系统的关系。 1.3 定 义 列出本...
  • 2019年5月真题答案,csdn小任老师真题讲
  • ''' 2019.5.19 ''' 1 程序计数器:pc用于存放下一条指令所在单元的地址的地方 地址寄存器:用于保存当前cpu所访问的内存单元的地址 ...指令译码器:从内存中取出一条指令经数据总线发送到指令寄存器 ...
  • 软件设计的七大原则

    千次阅读 2018-12-15 22:07:45
    七大设计原则 开闭原则 依赖导倒置原则 单一职责原则 接口隔离原则 迪米特原则 里氏替换原则 合成复用原则 设计模式-创建型模式 工厂方法模式 抽象工厂模式 建造者模式 单例模式 原型模式 设计模式-...
  • 软件架构设计---软件架构概述

    万次阅读 2018-09-17 21:25:54
    像学写文章一样,在学会字、词、句之后,就应上升到段落,就应追求文章的“布局谋篇”,这就是架构。通俗地讲,软件架构设计就是软件系统的“布局谋篇”。... 软件设计人员学习软件架构知识旨在站在...
  • 软件设计是什么?

    万次阅读 2018-06-10 23:25:32
    软件设计的意义(架构的意义) 关于软件设计的问题 软件设计的特点 软件设计时一系列创造活动,是借助编程语言以简单和优雅的方式表达并解决现实需求的一门科学和艺术。 - 软件设计是一门技术 数据结构,...
  • 软件设计之总体设计

    万次阅读 2018-03-25 10:22:52
    软件的需求分析阶段知道系统要“做什么”,而软件设计阶段我们明白的是“怎么做”。软件的设计分为:总体设计&&详细设计设计基本原理:总体设计的任务和过程总体设计分为:面向数据,面向功能,面向...
  • 2019软件设计师考试要点

    万次阅读 多人点赞 2019-03-18 22:43:12
    软件设计师笔记 一、计算机系统基础知识 1.CPU 的功能:程序控制、操作控制、时间控制、数据处理。 2.计算机系统组成示意图: 指令寄存器 程序计数器 地址寄存器 指令译码器 3.数据表示:原码、反码、补码、移码。...
  • 软考软件设计师考试总结(2018上半年)

    万次阅读 多人点赞 2018-05-28 01:29:26
    前段时间一直进行着软件编码的工作,应当是时候告一段落了。理论推动实践,实践反过来推动理论的理解。 与物质和意识的关系一样。 * 世界是物质的,物质决定意识; * 意识反过来影响物质,也就是物质的主观...
  • 软件设计师中级攻略

    千次阅读 2019-08-12 22:49:29
    说到软件设计师简称软考 , 还是有很多争议,不知道考下来的作用在于何处. 在此,我先声明一下我的观点吧 我是大三下学期用了接近两个月的时间复习的, 课本细看一遍, 然后选择题一定要多刷, 还有大题, 大题的类型一般是...
  • 软考—软件设计师(软件工程基础知识)

    千次阅读 多人点赞 2018-10-17 17:27:03
    1. 软件生存周期 同任何事物一样,一个...通常,软件生存周期包括可行性分析与项目开发计划、需求分析、设计(概要设计和详细设计)、编码、测试、维护等活动,可以将这些活动以适当的方式分配到不同的阶段去完...
  • 软件设计师考试详细介绍(最全)

    万次阅读 多人点赞 2018-01-14 14:02:03
    软件设计师考试属于全国计算机技术与软件专业技术资格考试(即软考)中的一个中级考试。通过本考试的合格人员能根据软件开发项目管理和软件工程的要求,按照系统总体设计规格说明书进行软件设计;能够编写程序设计...
  • 最新软件设计师知识点分析(思维导图)

    万次阅读 多人点赞 2018-04-22 19:20:12
    大家好,作为一个考取软件设计师的过来人,今天我给大家分享一下关于软件设计师考题的复习经验 1、多做多分析多总结近年来习题(达到看到题就知道考点是什么怎么解) 2、知道怎么在题中怎么找答案 3、梳理各知识...
  • 2018软考软件设计师大纲

    万次阅读 多人点赞 2018-03-13 23:05:48
    注:2018年上半年考试软件设计师大纲为2009年版新版大纲。参考资料为2016年版修编教材。大约考试时间为5月26日。考试说明1.考试目标 通过本考试的合格人员能根据软件开发项目管理和软件工程的要求,按照系统总体...
  • 2018年上半年软件设计师试题参考答案

    万次阅读 多人点赞 2018-07-09 21:10:45
    2018上半年软件设计师上午试题参考答案 基础知识 A.O(lgn) B.O(n) C.O(nlgn)D.O(n²) A.4 B.5 C.6 D.7 2018上半年软件设计师下午试题参考答案 ...
  • 软考 软件设计师 历年真题含答案(2004-2017史上最全)
  • 【视频课程动态更新,付费学员可随时免费学习新内容,配套资料免费赠送,直至通过考试】本视频教程详细讲解了近软考软件设计师下午考试真题,对每一道题都进行了重点的讲解,并点出了相关的考察点。对于一些发散的...
  • 软考之---软件设计师考试经验与笔记分享

    千次阅读 多人点赞 2018-12-16 19:28:52
    所涉及的课程更是包含基础医学概论、临床医学概论、流行病学、管理学原理、运筹学、卫生事业管理学、信息组织学、管理信息系统、医院信息系统、信息系统分析与设计、VB语言、C语言、数据结构...
  • 软考(软件设计师)注意事项(攻略)

    千次阅读 多人点赞 2014-11-27 17:00:24
    软件专业的朋友都会去参加软考,我在这里就叙述一下软考(特指软件设计师)的注意事项。 l 关于复习时间的安排  1. 对于大学专业就是计算机科学与技术(软件工程方向)的学生,只要平常的专业课学科绩良好,...
  • 历年真题软件设计师下午考试题汇分析与技巧

    万次阅读 多人点赞 2014-12-27 13:25:40
    软件设计师级别的试题题型基本固定:第一题为结构化分析与设计,主要考查数据流图DFD的绘制, 第二题为数据库分析与设计,主要考查ER图的绘制以及ER图与关系模式的映射, 第三题为面向对象分析与设计,主要考查对...
  • 软件设计师习题笔记-重点习题四

    千次阅读 2018-10-14 00:08:57
    1.在程序运行过程中,CPU需要将指令从内存中取出并加以分析和执行。CPU依据(指令周期的不同阶段)来区分在内存中以二进制编码形式存放的指令和数据。 解析: 本题查计算机系统基础知识。 指令周期是执行一条指令所...
  • 2019上半年软件设计师考试大纲

    千次阅读 多人点赞 2019-03-28 20:57:34
    软件设计师的试题主要分为上、下午两个部分。上午主要是选择题(75题75分),下午为6道大题(6题75分 其中五/六题为选择Java&C++ )。 上午题目较为繁杂,涵盖了计算机组成原理、编译原理、计算机操作系统、计算机...
  • 2017年上半年(5月份)软考 软件设计师上午真题及答案解析,全网最清晰,答案最正确的真题资料。小任老师出品,必属精品。
  • 软件设计师2019考试大纲

    千次阅读 2019-03-24 15:23:39
    2019年上半年考试软件设计师大纲为新版大纲。参考资料为《软件设计师教程》年版修编教材。 大约考试时间为5月26日。 考试说明 1.考试目标 通过本考试的合格人员能根据软件开发项目管理和软件工程的要求,按照系统...
  • 软件设计师大纲

    千次阅读 2005-01-18 10:07:00
    (4)掌握操作系统、程序设计语言的基础知识,了解编译程序的基本知识; (5)熟练掌握常用数据结构和常用算法; (6)熟悉数据库、网络和多媒体的基础知识; (7)掌握C程序设计语言,以及C++、Java、Visual Bas
  • 2019.11软考软件设计师归来心得体会及复习备考指南

    千次阅读 多人点赞 2019-11-13 16:24:46
    文末有我整理的2019软件设计师考点思维脑图,以及备考资料大全分享 上周六(11.09)参加了软考软件设计师的考试,考试分上午场和下午场。总的来说题型比较常规,但是作为战五渣的我还是很担心能否过线????。(个人...

空空如也

1 2 3 4 5 ... 20
收藏数 1,409,767
精华内容 563,906
关键字:

软件设计