如何做好软件系统的架构设计
对于外包业务类型的项目,软件架构设计的目的不同于产品类型的项目。这里我们主要讨论外包业务类型项目的软件架构设计的目的。1.提供大规模开发的基础和规范,提供可复用的资产。软件系统的大规模开发必须有一定的基础,遵循一定的规范,这不仅是软件工程本身的要求,也是客户的要求。在架构设计过程中,可以对一些公共部分进行抽象,形成公共类和工具类,从而达到重用的目的。2.在一定程度上缩短项目周期,利用软件架构提供的框架或可复用组件,缩短项目开发周期。3、降低开发和维护的成本,大量的复用和抽象,可以提取一些开发人员不必关心的通用部分,让开发人员可以只专注于业务逻辑的实现,从而减少大量的工作量,提高开发效率。4、提高产品质量,好的软件架构设计是产品质量的保证,尤其是对于客户经常提出的非功能性需求的满足。软件架构设计的原则软件架构设计必须遵循以下原则:1,满足功能需求和非功能需求。这是一个软件系统最基本的要求,也是架构设计应该遵循的最基本的原则。2.实用原则,就像每一个软件系统交付给用户解决用户问题时都必须实用一样,架构设计也必须实用,否则就是“高来高去”或者“过度设计”。3.满足复用的要求,最大程度提高开发人员的工作效率。软件架构设计的几种观点我们在讨论架构设计应该做什么的时候,或者在架构设计评审的会议上,经常会问各种各样的问题,比如开发人员应该如何记录日志,如何控制事务。如何才能提高我们开发人员的工作效率,即在单位时间内更好的质量完成更多的功能?如何满足客户的非功能性需求?如何让生产环境中的平台管理者更好的维护系统?以上问题实际上是软件系统中不同的涉众从不同的角度提出来的。要回答这些问题,我们必须从不同的角度来看待软件架构设计的工作。1.从逻辑架构的角度,站在系统用户的角度考虑问题,设计的软件架构能够满足业务逻辑的需求,处理日益复杂的业务逻辑需求。2.从开发架构的角度,站在系统开发者的角度考虑问题。设计的架构要易于理解、开发和单元测试,开发人员最好用最少的代码行完成功能开发。3.从运行架构的角度,考虑到系统运行时的质量要求,尤其是关注系统的非功能性要求,客户往往要求我们系统的功能屏幕最长响应时间不超过4秒,能够满足2000个用户同时在线使用,系统资源基于角色的安全控制。4.从物理架构的角度,关注系统安装部署的环境,如IBM HTTP Server+WebSphere Application Server+DB2、WebLogic+Oracle,这些都是最流行的企业应用服务解决方案。5.从数据架构来看,我们今天开发的各种系统,比如MIS、ERP、SAP,基本上都是对各种数据进行操作,把一堆不是很好理解的数据展现给用户,自动处理各种数据的操作,所以数据的持久性很重要。1.分析需求,理解业务模型(或领域建模),并选择关键用例。软件需求可以分为用户角度和开发者角度,从用户角度也可以分为功能性需求和非功能性需求。我们必须从不同的角度和层次全面理解和分析需求,理解业务模型。实践表明,经常被我们忽略的非功能性需求,往往会导致整个项目的失败。理解业务需求的最佳方式是领域建模。领域建模和需求分析经常交替进行。领域建模主要有以下三个功能:◆探索复杂问题,理清领域知识。马丁·福勒(Martin Fowler)曾说过,他的面向对象方法最大的优点是有助于解决更复杂的问题。领域建模本身作为一种辅助思考的工具,帮助我们始终将注意力保持在最重要的业务概念及其关系上,从而能够持续深入系统地分析和理解需求。领域建模往往是一个从模糊到清晰,从碎片到系统的过程。◆确定功能范围,影响扩展性。任何模型都是现实世界中程序的抽象。这种抽象会忽略一些东西,比如对象的属性,对象之间的关系,而这些忽略往往是有目的的,决定了函数的范围。该模型揭示了各种功能背后的结构。如果说定义函数相当于“拍照”,那么领域建模相当于“做透视”,更关注问题领域的内部结构,相当于把问题领域抽象到一定程度。好的领域模型不仅能很好地支持现有功能,还能在一定程度上支持未来可能出现的新需求,体现出良好的可扩展性。◆提供沟通基础,促进有效沟通。领域建模通常使用UML图作为表示方式,这为我们的交流提供了方便。当然,有时候文字在描述某些领域的问题时可能更合适、更灵活。在我们公司实际的软件开发过程中,领域建模往往缺少这个环节,这可能是在以后的工作中需要进一步完善的地方。虽然我们总是期望架构师能够完全掌握需求,但是由于时间和精力的限制,摆在我们面前的现实是架构师没有时间深入分析所有的需求,所以我们的策略是“把好钢用在刀刃上”,也就是把大部分的时间和精力花在确定架构最重要的关键需求上。在选择关键需求时,需要注意的是,高优先级的需求往往是从用户的角度来看的,可能不是真正的关键需求。在《RUP从业者指南》一书中,它告诉我们如何确定关键的功能需求。a .作为应用程序的核心或实现系统主界面的功能b .必须实现的功能,即如果这些功能没有实现,开发的软件就失去了价值c .覆盖了系统架构的某些方面但没有被其他重要用例覆盖的功能。2.从不同的角度考虑软件架构的所有方面。软件架构设计必须考虑方方面面,根据前期工作建立的领域模型、关键需求和系统约束进行设计,从系统用户、开发人员、系统管理员、部署管理员和数据管理员的角度分析和解决问题。例如,如果我们的运行架构采用集群模式,我们必须小心缓存和会话的使用。如果我们的业务逻辑要求我们操作多个数据库,我们应该考虑支持两阶段事务提交。只有考虑到所有这些方面,这样的架构设计才是完整的。至于每个视图中我们应该设计的细节,其实是关系到整个项目的流程定义的。比如我们有一个专门的活动安排数据库概要设计,在架构设计的过程中可以只关注更高层的数据库特征和数据库之间的关系,在后续的相关活动中可以设计每个表的数据字典,但是如果没有这个活动,我们会细化每个表的每个字段和表之间的关系。3.解决技术关键问题和困惑在软件架构设计的过程中,我们经常需要攻克一些技术关键问题和困惑,这是一项需要扎实的理论知识和丰富的实践经验的工作。例如,如何提高整个系统的性能?如何导出极其复杂的“中国式报表”(一般比西方国家出的报表复杂很多,很多开源的BI框架也不能完全解决问题)?当你遇到一个确实很难的问题,可以去百度或者谷歌,咨询公司的资深技术人员或者专家,或者召开一个小规模的技术研讨会,尝试通过头脑风暴的方式寻找答案,从而提高工作效率。4.召开架构设计评审会议,接受同行评审。建筑设计评审是极其重要的一部分。我曾在《七种武器》中形容为离别钩,因为同事在会上可能会问很多问题或意见,很多意见很尖锐,所以一定要虚心接受,做好记录。俗话说,“良药苦口利于病,忠言逆耳利于行”。在审查会议之前,我们必须完成大量的准备工作。最好准备一份简明的电子简报,列出最重要的问题,这样在进行评审会议时,就不会漫无目的。我们会在会前把这些材料发给与会者,请他们花时间先了解一下。在会议进行的时候,要学会控制会议的进度,提高会议的效率。5.在关键用例的设计架构上实现功能,以验证架构。架构设计的验证也是一项非常重要的工作,验证技术有很多。在我们公司,通常使用样本的形式,即XP中的迭代0和RUP中的切片。这样做的好处是可以从实际产品的角度有效地验证架构是否满足需求,与废弃的原型验证技术相比可以节约成本。这个样本绝不是我们在解决架构设计中的问题时用来做实验的一些代码的拼凑,而是一个完整的可交付代码和满足架构设计的相关文档以及实现一个关键用例的一系列规范。同时,这个样本可以作为你讲解或者训练架构时的教材,也可以作为开发者使用这个架构进行开发的蓝本,甚至只需要简单的修改就可以复制粘贴。6.交付给客户进行审查。这个环节可能很多公司都不存在,因为他们的软件架构不一定需要客户审核,但是对于我们这样的服务公司来说最重要的是客户的尊重。实施软件架构设计的活动,就是让客户理解并接受你的架构设计方案,同时客户也会起到帮助你验证架构的作用。通常我们的架构被客户认可后,就可以进入大规模开发。在交付客户评审时,评审可能通常以会议的形式进行,所以我们可以参考评审会议中的良好做法并召开会议,这里就不赘述了。软件架构设计常见误区及解决方案1,架构设计往往“高大上”。所谓高到不能再高,其实就是我们的架构设计只停留在模型阶段,但绝不是第一个样本方案。2.架构设计在某些方面经常被过度设计。为了一些根本不会发生的变化,进行了一系列复杂的设计。这样的设计称为过度设计,往往会带来资源的浪费,增加开发的工作量或难度。虽然要考虑系统的扩展性和可维护性,但也不能过度设计。有时候你可能无法判断哪些设计是过度设计。这时候你可以请你的PM从整个项目的高度来帮你做决定。3.架构不是一个框架,也不是几个框架或者技术的简单组合。框架本身有一个架构。框架一般是针对某个方面或领域的半成品,具有良好的复用性和扩展性。我们可以用一句经典的话来概括:框架是软件,架构不是软件,框架是一种特殊的软件。在我们的工作中,我们可以通过抽象许多可重用的工具类、公共类和基本类来形成一些可重用的框架。4.建筑设计绝不是展示新技术的平台。合适的技术是对项目有益的技术,必须考虑开发人员和维护人员的能力。作为架构师,我们更应该关注如何平衡业务需求、编织操作(主要指团队合作)和技术之间的关系,而不是只关注那些技术细节。5.架构设计的成功决定了系统的质量。因为糟糕的架构设计,交付的系统bug太多,无法满足客户的非功能性需求,项目取消的案例时有发生。建筑设计不是建筑师一个人的事,也不是几天就能完成的。它必须是架构师大量辛勤工作的结果,其成败往往与组织、主管和项目经理的支持密切相关。关于建筑设计的一些通用技巧:1和层法则。这里的层是指逻辑层,而不是物理层。目前,大多数企业应用系统分为三层,即表示层、领域层和数据层。在划分每一个层次时,主要可以考虑以下几个方面:a、每一个层次都是相对独立的部分,可以作为一个整体使用,不需要了解其他层次;b、尽量减少层级之间的依赖,即减少耦合;c、某一层可以有一定程度的替代,对其他层没有太大的影响;d、等级制度不能封闭一切。如果将字段添加到用户界面,数据字段将被添加到域层,相应的字段将被添加到数据层。同时,层数过多可能会对性能产生一定的影响。2.包之间没有循环依赖。通常情况下,会先将包分成不同的逻辑层,然后根据该层的包下的功能。避免房间之间的循环依赖是一个通用规则,这样的规则必然有其存在的价值和理由。主要原因有:a、循环依赖会使分层失去意义;b、循环依赖会带来很多潜在的风险,比如嵌套事务的现象(JavaEE标准不支持)。我遇到过这样的问题。在项目中,事务被放在业务逻辑层进行统一控制。但是由于开发者在架构上忽略了这个原则,在持久层中调用了表示层的公共类,导致了嵌套事务的现象。3.设计模式的应用。在很多人心目中,提供设计模式等同于GOF的设计模式。其实设计模式是一个广义的概念,比如需求模式、领域模式、反模式等等。模式实际上是一种工具,是过去人们解决某一类问题的经验总结,所以我们可以在设计活动中应用各种设计模式,但是在应用这些模式之前一定要把问题分析清楚,否则可能会出现“牛头不对马嘴”的现象。成功的项目总有相似之处,失败的项目有各自的失败之处。好的软件架构设计一定是成功项目的相似之处。我们没有做好软件架构设计的原因是什么?