Microsoft.NET 企业级应用 架构设计 (上)

来源:互联网 发布:花之芬芳人生淘宝 编辑:程序博客网 时间:2024/06/07 15:03

Microsoft.NET 企业级应用 架构设计 (上)

1.今天的架构师和架构

  1. 在软件里,架构这个术语恰到好处地指代为客户构建系统
  2. 系统存在于环境之中,而环境则通过驱动一系列开发和运维的决策来影响系统的设计。
  3. 系统的使命可以通过一组需求来描述。这些需求最终推动系统架构的形成。
  4. 功能性需求定义了软件该有的功能。功能通过输入、行为、输出来描述。其主要问题在于描述期望行为。这里写图片描述
  5. 非功能性需求是指利益相关者明确提出的系统特性(可伸缩性、安全性、可访问性等)。
  6. 一般来说,非功能性需求必须和功能性需求同时确认。后者产生软件规范;前者则在实现策略上提供帮助,并在技术决策上给予启发。而在很多情况下,功能性需求也会影响系统架构的决策和相关方面,并且往后难以更改。
  7. 瀑布模型和迭代开发这里写图片描述
  8. 业务逻辑的设计有几种方案:事务脚本,表模块,领域模型,对命令和查询进行分离的领域模型,以及事件溯源等。
  9. 项目经理:负责选定方法学、安排工作、跟踪进度、回报情况,以及充当技术人员和业务人员之间的有效桥梁。
  10. 整体设计要与企业目标和需求保持一致。特别的,整体设计是由需求驱动,而不是驱动需求。

2.为成功而设计

  1. 沟通问题的根源是业务人员和开发者使用不同的词汇,使用和期待不同精度的描述。
  2. 针对代码,而不是针对写代码的人。但通过写代码的人来尝试改善代码。
  3. 持续改变时描述现代软件项目动态的有效方式。
  4. 作为一名架构师,架构和设计重构都是关键工具。架构师无法控制历史以及业务场景和现实世界的发展。架构师需要一直做出调整,避免重新构建。
  5. 去控制真实存在的复杂性,而不是创造原本没有或不该有的复杂性。

3.软件设计原则

  1. 所有编程都是维护编程,因为你很少写原创代码。只有你在最初的10分钟里键入的代码是原创的。仅此而已。
  2. SOLID:单一责任原则(SRP)、开放封闭原则(OCP)、里氏代换原则LSP、接口分离原则(ISP)、依赖反转原则(DIP)。
  3. 高内聚,低耦合。
  4. 架构师的设计应该解决手头上的问题、但也要足够通用,可以解决将来的问题和需求。
  5. 使用继承有一些安全的方式(例:只向派生类添加代码),但出来的对象图总是很难反映现实世界里德默写领域的整个模型。
  6. 单一责任原则:一个类有且只有一个改变理由。
  7. 开放封闭原则:模块应该对扩展开放,但对修改封闭。
  8. 里氏代换原则:子类应该可以替换它们的基类。(派生类不能限制基类的执行条件)。
  9. 接口分离原则:不应该使用胖接口(不应该强制客户以来于它们不用的接口)。
  10. 依赖反转原则:高级模块不应该依赖于底层模块。而这都应该依赖于抽象。
  11. 处理依赖的模式:
    1. 服务器定位模式
    2. 依赖注入模式
  12. 编码向量
    1. KISS(Keep It Simple,Stupid):不必要的复杂性对于给定的系统需求而言都是附加的逻辑。
    2. YAGNI(You Ain’t Gonna Need It):实现需求上没有提到的任何功能都是有问题的。
    3. DRY(Don’t Repeat Yourself):避免保持系统不同部分同步的麻烦。一块代码只有一个明确的实现是重构的首要目标
  13. 说,别问!
  14. 每个模式描述在我们的环境里重复出现的问题,然后描述这个问题的核心解决方案,你可以使用这个解决方案无数次,每次使用它的方式都不一样。
  15. 设计模式只是提供帮助。有一个问题,然后去把问题匹配到设计模式。理解问题,然后对它进行泛化。
  16. 模式对于解决方案来说并不是附加价值,它们的价值帮助作为架构师或开发者寻找解决方案。
  17. 重构可以总结为两点:
    1. 持续代码的编辑改善可读性和设计。
    2. 执行更加进取的结构调整,使现有代码符合特定模式。

4.编写优质软件

  1. 可测试性的原则:
    1. 控制性:测试者在多大程度上可以给正在测试的软件提供固定的输入数据。
    2. 可见性:观察正在测试的软件的当前状态以及它所产生的任何输出能力。(在方法执行后验证后置条件的事情)。
    3. 简约性:简单和及其内聚的组件非常适合测试。
  2. 软件测试会出现在各个层次。
    1. 单元测试:检查软件的单个组件是否满足功能性需求。
    2. 集成测试:检查软件是否兼容环境和基础设施以及两个或多个组件是否协同工作。
    3. 验收测试:检查完成的系统是否满足客户需求。
    using Microsoft.VisualStudio.TestTools.UnitTesting;      using MyMath.Model;      namespace MyMath.Model.Tests      {          [TestClass]          public void TestIfFactorialIsCorrect()          {              var factorial=new Factorial();              var result =factorial.Compute(5);              Assert.ArEqual(result,120);          }      }  
  1. 代码可扩展性:基于接口的设计、插件架构、状态机。
  2. 不要试图通过清洗、移动的注释来表达一段但以理解的代码。
  3. 可读性(3C规则):注释(Comment)、一致性(Consistency)、清晰性(Clarity)
  4. 代码质量衡量:可测试性、可扩展性、可读性。

5.发现领域架构

  1. 领域驱动设计:应对软件核心复杂性。
  2. 大多数情况下,三段架构(表现层、业务层、数据层)的数据模型时数据存储的关系型数据模型。这里写图片描述
  3. 表现层:负责提供用来完成任务的用户界面。
  4. 应用程序层:
    1. 系统后端的入口点(一个按钮都触发系统后端里德操作,启用一个工作流程);
    2. 编排业务逻辑,应用程序层引用领域层和基础设施层。最后,应用程序层对业务规则一无所知,不会包含任何与业务有关的状态信息。
  5. 领域层:包含了所有并非针对一个或多个用力的业务逻辑。
    1. 领域模型:领域模型的终极目标是实现统一语言和表达业务流程所需的操作。
    2. 领域服务:出于某种原因无法放入热河现有实体的领域逻辑。它是一个类,包含了一些逻辑上有关系并且操作多个领域实体的行为。通常也需要访问基础设施层执行刻度写操作。
      6.基础设施层:与使用具体技术有关的任何东西,不管是数据持久化、特定的安全API、日志记录、跟踪、缓存等。

6.变现层

设计不只是外在,还有内在

  1. 用户体验优先
    1. 关注交互
      1. 基于任务的设计(采用面向任务UI,与读写模式分离齐头并进);
      2. 目标是找到最佳的做事方式:关注交互而不是数据,持续去改善草图(用户界面通常更多地受后台尸体而不是想要的体验和客户端上实际执行的任务影响)
      3. 为每个屏幕创建一个视图模型类(一个屏幕就是一组输入),可以轻易抽象为一个类。
    2. 用户体验不是用户界面
      1. 要点:信息架构,交互设计,可视化设计,可用性审查。
      2. 一些工具:Axure、Balsamiq、UXPin、Wirify
      3. 交互:用户体验分析师现代表现层的核心,那么可用性审查就是用户体验分析的核心。
    3. 有效地体验
      1. 把交互变成视图。
      2. 把视图变成原型。
      3. 告诉客户它只是一个原型。
  2. 真实场景:
    1. 一般而言,表现层有两个主要组件组成:用户界面和表现逻辑(UI逻辑)。
    2. 用户在用户界面里做出的任何操作都会成为表现逻辑的输入。

7.神秘的业务层

  1. 用来组织业务逻辑模式
    1. 事务脚本模式(TS):鼓励你跳过任何面向对象设计。把业务组件直接映射到所需的用户操作上。它推动从人物的角度看业务逻辑(提高用户体验的关键)。
      1. 适合业务逻辑简单,最好是不大可能改变和发展的场景。
      2. TS模式并未强制使用任何类型或格式进行数据交换。
    2. 领域模型模式(DM):忠实反映业务领域,尤其是领域里的流程和数据流。
      1. 在较大的系统里采用领域模式,因为它的启动和维护成本更容易被消化。
      2. 领域模型是一组普通类,每个类忠实地表示了业务领域里德一个重要实体。
    3. 反领域模式(ADM):和领域模式类似,但实体里没有行为,只有属性。
      1. 不必把任何逻辑放在领域对象里。所有需要的逻辑都放在一组服务组件里,这些组件共同构成完整的领域逻辑。
      2. ADM是反模型,尤其是在复杂的领域里使用,并且面临大量频繁更改业务的规则。就数据驱动应用程序和CRUD系统而言,评学模型已经足够了。
  2. 把焦点从数据移到任务
    1. ASP.NET MVC 里的任务编排:任何用户界面都会转化成控制器的类上调用的方法。避免把所有编排逻辑放入控制器方法。
      1. 把控制器看做协调者:责任驱动设计(RDD)的本质是把系统特性分解成系统必须执行的多个操作。接着,每个操作对应正在设计中的一个组件(通常是一个类)。执行这个操作就变成这个组件的专门责任了。这个组件的角色取决于它所承担的责任。
      2. 连接应用程层与表现层:应用程序层和表现层之间的交接点是控制器。在ASP.NET MVC里使用功能能齐全的控制反转(IoC)模式,需要重写控制器的工厂。
      3. 连接应用程序层与数据访问层:通过依赖注入。仓储是数据访问逻辑的容器的常用名称。确保仓储类型和接口(与领域模型里德重要实体一一对应)关联到IoC
      4. 使用依赖注入连接各层是推荐解决方案,但不是唯一的。如果逻辑层部署到不同的物理层,使用HTTP接口则是常见做法。
    2. 在领域里编排任务:领域服务包含任何无法放入领域实体的逻辑。
      1. 跨实体的领域逻辑:通常包含的业务逻辑的操作牵涉多个领域实体(服务本身的取名应该反映显示操作,并且容易被利益相关者和领域专家理解)。定义成领域服务的操作大多数情况下都是无状态的(传入某些数据,然后获得默写结果)。
      2. 连接字符串在哪:领域模型里的实体应该是普通C#对象,并且与持久化无关。
        例子:Invoice类只包含日期、编号、客户、支付条款等数据,此外,还可能包含GetEstimateDataOfPayment方法,这个方法读取日期和支付条款,计算一下节假日,然后确定发货单的发货日期
        从存储读取Invoice实体的代码和把它保存到存储的代码并没有和实体本身放在一起。系统的其他组件会处理这点。这些类就是仓储。仓储式整个系统里唯一处理连接字符串的地方
    3. 跨越边界传输数据:物理层意味着需要跨越的物理边界,不管是进程边界还是机器边界。跨越边界是一个昂贵的操作。
      1. 分层架构里的数据流:途中展示了一个相对抽象的数据流。这里写图片描述
      2. 共享领域模型实体:在遵循领域模型模式的分层架构里,领域实体是罪合适的输入容器。
        1. 在各层的领域实体:认为应用程序层编排的组件和模块之中传递领域模型的类是没有问题的
        2. 为命令和查询使用单一模型的风险:这个行为本质上就是领域逻辑,而领域逻辑必须一致与业务规则保持一致,表现层代码有打破这个一致性的潜在风险。
        3. 将来扩展的可能约束:不想为了满足特定前端的需要而修改领域模型。于是,添加转梦的数据传输对象就变成最合适的做法了。
      3. 使用数据传输对象:在给定系统及其生命周期里使用单一解决方案跨越边界传输数据是很少的。
        1. 数据传输对象概论:数据传输对象专门用来在不同的物理层之间携带数据。
        2. DTO与领域实体:DTO可以把复杂的层次结构简化成简单的数据容器,只包含必要的数据。
        3. AutoMapper和适配器:在源类型和目标类型之间创建一个映射;启动映射过程,用源类型的实例里的数据填充目标类型的实例。

一个成功的业务层需要敏锐的观察和建模。


2017/12/18 10:54:17

彩蛋

  1. 向已经延迟的软件项目增加人手会使之更加延迟。
  2. 没有东西可以按时、按预算完成构建。
  3. 失败不是一个选择,而是包含在软件里面。
  4. 一个项目怎样才能拖上一年?每次托一天。
  5. 好的判断源自经验,而经验源自坏的判断。
  6. 专家就是最后一刻进来骂人的人。
  7. 看起来好得难以置信的东西很可能是假的。
  8. 发现缺陷的概率与观察人的数量和重要程度成正比。
  9. 随着系统的演进,它的复杂度会不断增加,除非着手维护并降低复杂度。
  10. 如果它没经过测试,它就是坏的。
  11. 写代码的时候应该去假设最终维护你所写的东西的人是一个有暴力倾向的精神变态者,并且知道你住哪。
  12. 真正的程序员不会为他们的代码写注释。如果代码很难写,它应该也很难懂。
  13. 一个程序员90%的错误都来自其他程序呀的数据。
  14. 软件缺陷不可能被任何人发现,除了最终用户。
  15. 本质上,所有模型都是有错的,但有些事有用的。
  16. 软件总体来说就是一个“有本事来抓我”的游戏。
  17. 正确的实施并非及其空难;但错误地实施却极其简单。
  18. 由于全球变暖,需求不会冻结了,会一直流淌。就如同那句话一样:你今天见到的需求还是昨天看到的那个吗?
  19. 所有归纳都是无效的,包括这个。
  20. 最弱的环节永远是最稳定的环节。
  21. 永不低估可以工作的软件的价值。
  22. 比一瞧不同的用户更糟糕的是自以为是的用户。
  23. 当你设计一个程序区处理所有可能的愚蠢的错误时,大自然会创建更愚蠢的用户。
  24. 构建一个即使傻瓜也能使用的系统,而且只有傻瓜才愿意使用它。
  25. 任何傻瓜都可以写出计算机能懂的代码,但好的程序员可以写出人类能懂的代码。
  26. 不要因为只是个CRUD就有权利写出垃圾。
  27. 一个可以工作的复杂系统总是从一个可以工作的简单系统进化而来的。
  28. 在软件可靠性上的投入会持续增加,直到超出错误的可能代价。
  29. 理论和时间在理论上没有,在实践上有
阅读全文
0 0
原创粉丝点击