软件架构是软件工程一个很重要的分支,随着软件规模的扩大和软件寿命的延长,软件架构也越发重要。就像建筑领域,盖一个狗窝不需要进行分析与设计,但是如果是要盖一座万人体育场或者摩天大楼,那一定会离不开设计师。软件工程与之同理,好的架构能够决定软件的成败。软件架构不只是简单的分层或者划分模块,它包括更多的内容,例如需求确认、系统分解、架构风格的选择(最简单的如B/S还是C/S)、技术选型(Java还是.net,Oracle还是MySQL、Windows还是Linux等)、物理架构设计、数据架构设计、逻辑架构设计等等,通常架构师还要参与包设计、核心模块设计以及类设计等概要设计和详细设计工作。正因为软件架构设计涉及的内容相当多,因此需要考虑的因素也很多。

软件架构设计需要考虑的问题包括需求、成本、进度、团队人员的素质等等,我觉得首先应该考虑的是需求。俗话说:需求进、架构出。如果没有深入分析需求,往往难以得到好的架构,在分析需求时除了功能需求外,还要考虑一些非功能需求,包括是否要与第三方系统兼容、是否要考虑到数据迁移、是否要考虑到平台的多样性等等,非功能需要中很多因素也会影响到架构,例如安全性、性能等等,因此好的架构师应该尽量多参与需求分析,听听客户的想法,需求是影响架构最大的因素,架构风格的选择、技术选型等都与需求息息相关。除此之外,成本、进度以及人员素质等对架构的影响也很大,因此在架构设计的时候也需要充分考虑。没有完美的设计方案,无论是SAAM还是ATAM等架构评估方法,其实都是一种折中的方法,无法使每一个因素都达到最优,所以我们要全盘考虑,具体问题具体分析,找出当前应用最合适的一种设计方案。因为软件本身的复杂性,拿出一套完整、合理、面面俱到的架构设计方案并不是件简单的事情。

对于如何做好架构设计,Sunny个人建议如下:

  • 深入理解需求:错误的需求必定导致错误的架构,因此一定要深入理解需求,作为架构师,一个很重要的职责是进一步确认和细化需求,例如了解当前系统是否需要和别的系统交互,通过什么接口来交互,在交互的时候数据如何发送和接收等等,了解得越细致对于架构设计帮助越大,因此,一定要做好需求工作。架构师应该积极参与需求获取,需要对需求分析人员的需求分析过程进行必要的指导,一定要参与需求评审和《软件需求规格说明书》的确认工作,及时了解需求的变更,参与需求变更的评估和讨论,并验证和审查需求和架构的一致性。

  • 全面考虑非功能因素(质量属性):很多软件项目的失败并不是因为功能的缺失或者错误,而是因为一些非功能因素考虑不周全,例如服务器的性能、最多容许的并发用户数、安全性等等【2013年年初国内某知名化妆品网站就因为对系统负载考虑不够,导致在三周年庆大促销时服务器宕机,“为自己代言”的老大微博年薪百万聘架构师,】。作为一名好的架构师,应该认识到当前系统最重要、最核心的质量属性是哪些,例如有些项目的核心是安全性,此时可能需要牺牲性能来提高安全性,这就需要和客户进行交流,做一些平衡,通盘考虑。可能还要专门就安全性来做专门的设计,例如在我曾经参与过的项目中,光一个安全性就需要做好几个层次的设计,有代码级的、数据库级的、功能级的、系统级、网络级的,但性能是肯定会要下降的。因此,在进行架构设计时要学会取舍,当然取舍的前提是已得到客户的认可。优秀的架构师会引导客户接受合理的架构方案,以确保系统能够真正投入使用。

  • 构造合理的系统模型:建筑设计师都擅长绘图,同样作为一门工程学科,软件工程也需要绘制一些图,越大的项目需要的图越多,要求也越严格。这些图又可以称为模型,好的架构设计一定要有一套完整、合理的模型,包括数据模型(概念数据模型、逻辑数据模型和物理数据模型),结构模型(类图、包图、组件图和部署图等),动态模型(状态图、活动图和顺序图等)等,要熟练使用UML等技术来构造系统模型,这些图形也有助于进一步理解和验证架构的合理性,例如使用类图描述系统的类结构、使用包图描述系统的分层结构、使用组件图描述系统物理文件的联系以及与第三方库之间的交互、使用状态图描述核心业务对象的状态及其转换、使用活动图描述核心业务流程等等。在现代软件开发中,越来越多的软件公司都意识到建模的重要性,我也给一些软件公司做过UML建模技术的培训,发现很多公司在学完UML之后就能够将这些技术很好地用于实际的项目开发,特别是软件架构的设计,这与之前直接根据需求文档写代码,越写越盲目,最后还可能出现项目失败的情况相比,已经有了很大的改善。

  • 提高架构的稳定性和可扩展性:好的架构应该是稳定而又易于扩展的,因此在进行架构设计时要充分考虑这些因素,使用设计模式的目的实际上就是在一定程度上来保持架构的稳定性和可扩展性。合理使用设计模式,可以在提高代码质量的同时提升软件架构设计的质量。在架构设计中使用设计模式时,也需要充分理解需求,才能正确选择和使用设计模式。大部分设计模式都提供了抽象层,目的是让系统更易于扩展。通常的做法是要学会分析出系统的扩展点,对于一些可变的扩展点,需要提供一个稳定的抽象层,然后通过具体层来实现具体的业务功能。比如:如果在需求分析和架构设计时发现某个业务功能将来可能会进行改进,例如加密算法,此时可以提供一个抽象的加密类,而将具体的加密类作为其子类,所有的依赖和关联都基于抽象加密类,引入配置文件,将具体加密类类名存储在配置文件中,然后利用反射和注入的方式将具体加密类对象提供给其他业务类使用。当需要更换加密算法时,只需增加一个新的具体加密类并修改配置文件即可,原有设计方案和代码都无须进行修改,系统符合开闭原则,具有良好的可扩展性,这就是策略模式的一个应用。对于需求分析和架构设计中的一些具体问题,有些设计模式已经提供了很好的解决方案,例如当你需要经常调用一些第三方接口时可以考虑使用适配器模式,当你需要为多个外部子接口提供一个一致的入口时可以使用外观模式,等等。每一个设计模式都相当于“三十六计”中的一计,一不小心就在你的项目开发中用上了,当你遇到此类问题时就可以游刃有余地解决,这就是设计模式的魅力所在吧。如果你的项目涉及到更多底层的东西,例如事件处理、缓存服务、类工厂、消息队列等等,特别是你要开发的是一个API或者框架,那么所涉及到的设计模式就更多了,大家有兴趣可以看看《应用框架的设计与实现-.net平台》和《软件框架设计的艺术》这两本书,里面就提到了不少设计模式在框架设计中的应用。虽然框架不等于架构,但是框架的架构设计需要更加灵活,想想谁会去用那些僵硬固化、不易于扩展的框架呢?有效地使用设计模式会提高架构设计的质量,解决在架构设计中遇到的一些困难。因此,Sunny认为对于一名优秀的架构师而言,软件需求(需求工程)、软件质量属性、UML、设计模式等知识都是必须要具备的。

文章最后,Sunny友情提醒:好的架构师一定要学会如何与客户和领导沟通交流,可以读一读《软件架构师的12项修炼》(12 Essential Skills for Software Architects)一书,看看一名优秀的软件架构师(普通开发人员也一样)应该具备的一些非技术性的软技能,例如如何沟通、如何协商等等,说不定对你会有所帮助。

【作者:刘伟 http://blog.csdn.net/lovelion

Sunny谈软件架构的更多相关文章

  1. 从软件开发到 AI 领域工程师:模型训练篇

    前言 4 月热播的韩剧<王国>,不知道大家有没有看?我一集不落地看完了.王子元子出生时,正逢宫内僵尸作乱,元子也被咬了一口,但是由于大脑神经元尚未形成,寄生虫无法控制神经元,所以医女在做了 ...

  2. [小北De编程手记] : Lesson 05 玩转 xUnit.Net 之 从Assert谈UT框架实践

    这一篇,本文会介绍一下基本的断言概念,但重点会放在企业级单元测试的相关功能上面.下面来跟大家分享一下xUnit.Net的断言,主要涉及到以下内容: 关于断言的概念 xUnit.Net常用的断言 关于单 ...

  3. Java程序员从笨鸟到菜鸟之(五十一)细谈Hibernate(二)开发第一个hibernate基本详解

    在上篇博客中,我们介绍了<hibernate基本概念和体系结构>,也对hibernate框架有了一个初步的了解,本文我将向大家简单介绍Hibernate的核心API调用库,并讲解一下它的基 ...

  4. 从决策树学习谈到贝叶斯分类算法、EM、HMM --别人的,拷来看看

    从决策树学习谈到贝叶斯分类算法.EM.HMM     引言 最近在面试中,除了基础 &  算法 & 项目之外,经常被问到或被要求介绍和描述下自己所知道的几种分类或聚类算法(当然,这完全 ...

  5. 从决策树学习谈到贝叶斯分类算法、EM、HMM

    从决策树学习谈到贝叶斯分类算法.EM.HMM                (Machine Learning & Recommend Search交流新群:172114338) 引言 log ...

  6. SoC嵌入式软件架构设计II:没有MMU的CPU虚拟内存管理的设计和实现方法

    大多数的程序代码是必要的时,它可以被加载到内存中运行.手术后,可直接丢弃或覆盖其它代码. 我们PC然在同一时间大量的应用,地址空间差点儿能够整个线性地址空间(除了部分留给操作系统或者预留它用).能够觉 ...

  7. SoC嵌入式软件架构设计II:否MMU的CPU虚拟内存管理的设计与实现方法

    大多数的程序代码是必要的时,它可以被加载到内存中运行.手术后,可直接丢弃或覆盖其他代码.我们PC然在同一时间大量的应用,能够整个线性地址空间(除了部分留给操作系统或者预留它用),能够觉得每一个应用程序 ...

  8. 【C#系列】浅谈委托和委托

    本篇文章更适合具有一定开发经验,一定功底,且对底层代码有所研究的朋友!!! 本篇文章主要采用理论和代码实例相结合方法来论述委托和事件,涉及到一些边界技术,如软件架构的OCP原则(开-闭原则), 软件架 ...

  9. 【WebApi系列】浅谈HTTP

    [01]浅谈HTTP在WebApi开发中的运用 [02]聊聊WebApi体系结构 [03]详解WebApi如何传递参数 [04]详解WebApi测试和PostMan [05]浅谈WebApi Core ...

随机推荐

  1. java对象的内存布局(二):利用sun.misc.Unsafe获取类字段的偏移地址和读取字段的值

    在上一篇文章中.我们列出了计算java对象大小的几个结论以及jol工具的使用,jol工具的源代码有兴趣的能够去看下.如今我们利用JDK中的sun.misc.Unsafe来计算下字段的偏移地址,一则验证 ...

  2. 如何在Github Pages搭建自己写的页面?

    教程一大堆,却没有几个能看懂的,问题一:90%的都在讲解如何搭建博客,和我想要将自己的网页部署到上面还是有点区别的.问题二:所有的教程都用到了Git,而我只知道Git是一个开源的分布式版本控制系统.完 ...

  3. html系列教程--header head iframe img

    <head> 标签 用于定义文档的头部,它是所有头部元素的容器.<head> 中的元素可以引用脚本.指示浏览器在哪里找到样式表.提供元信息 head的描述信息包括<bas ...

  4. OCI_INVALID_HANDLE 什么原因

    查看oci.dll应用版本和服务器版本是否一致

  5. Openlayers 自定义控件

    OpenLayers.Control.YourControl = OpenLayers.Class(OpenLayers.Control, { // may private properties he ...

  6. poj1284--原根的性质

    关于原根,在百度百科上有着详细的介绍,此题主要考查原根的两个性质 1.只有奇素数才有原根. 2.一个数的原根个数为其欧拉函数的欧拉函数. 综合以上特点,可得到,我们设输入数为n,那么输出结果就为n-1 ...

  7. C++ 类中指向函数的指针 以及 类模板

    C++类中总是出现诸如下面的情况 这是一篇深入浅出讲解函数指针的文章,值得参考! http://blog.csdn.net/lishuhuakai/article/details/18276477 关 ...

  8. JVM学习之常见溢出类型

    Java堆 所有对象的实例分配都在Java堆上分配内存,堆大小由-Xmx和-Xms来调节,sample如下所示: public class HeapOOM { static class OOMObje ...

  9. Facebook 调试工具Stetho配置入门

    I decided to spend a few hours on Stetho.Stetho is a sophisticated debug bridge for Android applicat ...

  10. Android 通知栏系列....

    转:http://blog.csdn.net/vipzjyno1/article/details/25248021 在android的应用层中,涉及到很多应用框架,例如:Service框架,Activ ...