书海拾贝-企业级架构思想

阅读书籍中的优秀思想

<Java 应用程序架构设计>

当在一个软件系统上工作时,很重要的一点就是要理解系统的结构化架构以及设计理念.

具备复杂依赖的结构在本质上就会难以理解.清晰简洁并经过深思熟虑的依赖能够让团队很容易地掌握变化的影响。 p29

 

管理模块之间的依赖是非常必要的.面向对象设计的 SOLID 原则会帮助我们尽可能地最小化类之间的耦合并最大化类的内聚,这使得软件

能够更容易地维护和扩展.使用这些原则是有成本的.额外的抽象层会增加系统的复杂度.

如果对系统中的所有类都盲目地使用这些原则,由此导致的复杂性实际上会降低我们维护和扩展软件的能力.悖论 “伴随着灵活性会带来复杂性”

最适合使用SOLID原则的地方究竟是在哪里? 模块边界或者结合点

每个系统都会有结合点,也就是两个模块的连接点。系统中的这些结合点需要最大的灵活性和弹性。原因是变化驱动的。

组合使用SOLID原则和模块化模式,就掌握了如何设计最好的大型软件系统。

 

面向对象的范式也承诺了类似的好处,但事实证明对象的粒度太小。对于大型企业级软件。

模块是比对象更粗粒度的单元,允许我们封装复杂的设计决策。模块可能包含很多的类,

但是类之间关系的设计决策可以封装在模块中。内聚的模块会封装行为并通过定义良好的接口提供它。

 

重用需要一定的前提才能达到,那就是设计按需剪裁灵活的软件实体。通过将实体配置到特定的上下文中,才能对其重用。

垂直性的重用难度

1. 粒度, 粗粒度的模块更容易使用,而细粒度的模块具备更高的可重用性。 模块门面模式 Module facade pattern

2. 重量级 模块依赖其环境的程度. 重量级的模块依赖其操作环境,而轻量级的模块会避免这些依赖。当创建一个要运行在多种环境下

的模块时,我们需要将环境相关的依赖(如上下文依赖)从代码转移到配置中。会使模块具备更高的可重用性,但是也会更难使用,

因为模块需要针对每种环境进行部署。

 

逻辑设计会影响可扩展性,而物理设计会影响可用性和可重用性

使用模块化驱动类的设计决策。

 

模块化与面向服务架构,在本质上是相似的,某种程序上,服务设计与模块设计背后的原则是相同的,创建服务时,我们尽可能让其

时松耦合高内聚的。设计模块时也是。

互补性:模块是实现进程内重用的优秀可选方案。服务重用会跨越进程的边界。

 

服务    SOA原则和模式

模块    模块化原则和模式

包       包设计原则和模式

类       SOLID与设计模式

代码   代码质量

 

架构最困难的一个方面就是在正确的粒度等级上设计实体。

展现,处理/控制 , 领域,数据访问 粒度逐渐细粒度。

 


 

开发业务应用时,将应用拆分为三层是很常见的。

展现层负责构造和渲染用户界面。业务逻辑或领域层包含业务对象,而数据访问层封装持久化数据存储以及外部系统的访问。

在对应用进行分层时,重要的一点是将行为拆分为独立和合适粒度的模块,但是进行结构化的分层也是很重要的。如果模块结构

没有进行分层,那符合分层结构的灵活类设计就会因此打折扣。

 


 

外部配置是实现容器独立的模式,因为对依赖的配置转移到了外部的配置文件中.

 实现容器独立的最常见机制是借助依赖注入,模块的依赖是在运行时注入的。有助于模块是保持独立于容器

外部配置的不同:

外部配置用来配置模块使其能够跨上下文使用。

容器独立用来确保可以方便地跨容器.

容器独立可以确保模块能够很方便地跨运行时环境,因为将基础设施的行为与模块的行为分离开了。Spring 即是。

 

接口要远离实现她的地方,要靠近实现她的地方。


 

一个模块如果要独立部署,就不能存有对其他模块的依赖。 取决于模块重用的频繁程度。不会重用的模块不必如此细致的管理。

大多数有意义的系统中,多个内聚的模块需要互相协作并且共同工作提供业务应用的复杂行为。所以有很多方面会影响类的行为。

鉴于一定程度的耦合是必要的,协作的对象很可能分布到很多不同的模块中。

内聚模块模式。


 

消除循环依赖模式:

上移和回调 可以消除依赖。

下移会将依赖放到一个更低等级的模块中,它不能消除依赖,尽管可以用它减少模块的重量级。

如果不打算重用某个模块,依赖管理背后的驱动力就变成了可维护性。当你想要更高程度的可维护性时,选择关注可测试性。

 


 

<POSA 2 并发和网络化对象>  

高质量的并发和网络化系统的开发,尤其是那些具有严格QoS需求的系统,需要靠熟练的软件体系结构设计者和工程师的直觉和专门知识。如果不花费大量的时间通过反复实验来学习,仔细推敲和处理与平台有关的细节,要想获得并发和网络化软件技术的经验是非常困难的。  (P2)


 

1. 从源代码中重新发现模式是昂贵和耗时的,因为从实现细节中分理处基本设计决策是极其困难的。

2.如果有经验的设计者的简洁和理论没有用文字记载的话, 那么它们将随着时间的消逝而消失。因而不能帮助指导后续的软件维护和增强工作。

3.没有前期工作的指导,并发和网络化软件的开发人员将面临从头开始设计复杂系统的艰巨任务,而不能复用已成功的方案。 P3


 

《RabbitMQ in action》

为什么你会首先将应用程序设计成同步的呢?大多数情况下是因为你思考着整个任务,而非着眼于构建整体的更小的任务。

应该将各个步骤是基于功能是为分隔的应用,例如:一个专门接收请求,一个专门处理请求。

解耦处理过程(分离请求和操作)

在应用中紧密耦合的两部分中间使用RabbitMQ,之前每次只能处理一个请求而现在可以持续接收请求了。开辟了新天地。  p70


 

 消息通信能够解决的问题类型时,消息通信适用的主要领域之一是发后即忘的处理模式。

关心的是这些任务将会完成,但无需实时完成。

通常想要避免阻塞触发任务的用户。

创建了任务,放置到交换器上,并让你的应用程序返回继续工作,可能甚至都不需要通知用户任务已经完成。

匹配该模式的两种一般类型的任务:

1.批处理(batch processing) - 针对大型数据集合的工作或者转换。这种类型的任务可以构建为单一的任务请求,或者多个任务对数据集合的独立部分进行操作。

2.通知(notifications) - 对发生事件的描述。 内容可以是消息的日志,也可以是真实的报告通知给另一个程序或是管理员。


 

RabbitMQ 消息通信的强大之处在于如何将将交换器和队列进行组合。

在应用程序中,是否存在一个动作触发其他动作,然后并行运行?如果有的化,使用Topic交换器。

如果需要更多的计算力,同时又不想更改代码。可以启动更多的消费者进程。

同时RabbitMQ会负责对消息进行相应的分发.计实消费者在不同的机器上。  p92


 

有很多种方式来实现远程过程调用RPC - 譬如 UNIX RPC, REST API 和 SOAP . 这些传统的 RPC 实现方法有共同之处:那就是客户端和服务端紧密相连.

客户端直接连上服务器端,发送一个请求,然后就停下来等待服务器的应答,这种点对点性质的模式有很多好处,它使得小范围内的拓扑变得简单。但这种简单

的拓扑同时也限制了灵活性,并且当需要纵向扩展的时候,增加了复杂度。

例如:当有众多服务器时,客户端如何发现在哪台服务器上可以找到想要的服务时?

SOAP 和大多数企业RPC已经采取了复杂的补充协议和服务目录。这带来了额外复杂度和众多故障点。所有这些还都是以服务众多RPC服务器API而不会紧耦合

客户端和服务端的名义发布的。

如果服务器端彻底停止运行的化,客户端必须重新发现能提供相同服务的新的服务器。当连上服务器端之后,客户端还不得不重试API调用。

 

取代复杂目录和多种协议而使用一种协议来进行RPC通信的化会如何呢?客户端可以发起API调用,而无需关心有哪台服务器来处理,同时也不必关心服务器崩溃的情况,

那会如何呢?

通过使用MQ服务器来实现RPC就可以做到这些。

使用RabbitMQ来实现RPC时,只是简单地发布消息而已。RabbitMQ会负责使用绑定来路由消息到达合适的队列。

RPC服务器会从这些队列上消费消息。

RabbitMQ替你完成了所有这些艰难的工作:将消息路由到合适的地方,通过多台RPC服务器对RPC消息进行负载均衡,甚至当处理消息的服务器崩溃时,

将RPC消息重发到另一台。所有的这些消息都无需复杂的WS-*协议,也不需要客户端的路由功能.


AMQP 消息时单向的,RPC服务器如何才能将结果返回给原始客户端呢?由于RabbitMQ处于中间环节,RPC服务器甚至都不知道客户端调用者的身份

(除非在消息体内放入应用特定的ID)

解决方案: 使用消息来发回应答。在每个AMQP消息头里有个字段叫做 reply_to, 消息的生产者可以通过该字段来确定队列名称,并监听队列等待应答。

然后接收消息的RPC服务器能够检查reply_to字段, 并创建包含应答内容的新的消息.并以队列名称作为路由键.

如何阻止其他客户端读到应答消息。

如果你声明了没有名字的队列,RabbitMQ会为你指定一个.这个名字恰好时唯一的队列名;同时在声明的时候指定exclusive参数,确保只有你可以读取队列上的

消息。所有RPC客户端需要做的是声明临时的,排他的,匿名队列,并将该队列名称包含到RPC消息的reply_to头中,于是服务器端就知道应答消息该发往哪儿了,

我命并没有提到将应答队列绑定到交换器上,因为当RPC服务器将应答消息发布到RabbitMQ而没有指定交换器时,RabbitMQ就知道目的地时应答队列,路由键

就是队列的名称。

 

posted @ 2020-11-14 10:55  君子之行  阅读(17)  评论(0)    收藏  举报