JoeCao.github.io icon indicating copy to clipboard operation
JoeCao.github.io copied to clipboard

多研究些架构,少谈些框架(4)-- 架构师是技术的使用者而不是信徒

Open JoeCao opened this issue 7 years ago • 11 comments

多研究些架构,少谈些框架(1) -- 论微服务架构的核心概念 多研究些架构,少谈些框架(2)-- 微服务和充血模型 多研究些架构,少谈些框架(3)-- 事件驱动架构 多研究些架构,少谈些框架(4)-- 架构师是技术的使用者而不是信徒

多研究些架构,少谈些主义(4)-- 架构师是技术的使用者而不是信徒

2017-6-9 曹祖鹏

架构师是技术的使用者而不是信徒

我承认我是标题党, 为什么要写这篇充满争议的文章?目前架构师这个职位特别火热,程序员的目标都是成为一个令人尊敬的架构师。但是我们真的理解架构师应该做些什么?很多人把架构师和框架师等同起来,认为研究框架多的才是架构师
下面说的情况请勿对号入座。

  • 盲目的追新: 技术人员的喜好往往是什么技术流行就追什么技术。现在的技术发展快,前后端不断涌现各种框架,我们恨不得把这些框架都用在自己的项目里才行,要不然怎么好意思和别人打招呼啊。 我亲身经历,有个技术人员一定要把原来单元测试框架的xml初始数据改为json,他的原话是”json看的更舒服”,但是改完后,我们的单元测试反而难落地了,原因是原来的单元测试框架有个工具是可以将表中的数据自动生成xml的,而改成json后,我们必须手写json数据了。 他的喜好不包括给大家更好用的工具。

  • 按技术站队,以结果反推: 很多人把手段当成了目的,成为了框架的信徒。用了Java开发,你的设计就一定是面向对象的?用了Spring boot就是微服务了吗?这些荒唐的事情却在技术圈不断发生,技术人员甚至会按照语言、框架形成不同的圈子,各种技术圈互相鄙视,互相踩,真相此时无法越辩越明,反而把技术方向带歪了。

技术要和实际场景结合

架构师也要深入了解掌握技术,但是更多的是了解技术的优劣和使用场景,而不是简单的生搬硬套。以现在流行的微服务架构来说,Netflix使用RESTful接口作为通讯,我们是不是要把公司的用了n年的基于TCP的RPC换成RESTful接口,因为根据Netflix的实践,RESTful可以更好的解耦、更强的伸缩性等优点,还能支持多种语言开发,互通性好。但是我们需要对RESTful彻底的理解清楚:

  • RESTful接口不简单是是http+json,Richardson成熟度模型中哪个层级更合适我们的内网API通讯,HATEOAS是否需要?
  • RESTful的核心是资源,如何在微服务中抽象资源概念,如何将基于过程的RPC调用平滑的迁移到RESTful上?
  • 多语言开发是快,但是后续维护如何找到稳定的Go、Scala、xxx语言程序员来源?
    以上的问题应该是架构师在考虑引入新技术的时候的重点,其中对技术优劣和架构思路是核心

版权说明

本文采用 CC BY 3.0 CN协议 进行许可。 可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。

关注我

微信公众号 qrcode_for_8

JoeCao avatar Jun 12 '17 09:06 JoeCao

其实很多时候想拿最新的技术或思想来练手而已。只是私下写个DEMO神马的,体会不到具体技术合适的应用场景的。

hc24 avatar Sep 20 '17 09:09 hc24

@JoeCao 想再请求一个问题: 假设前端有个页面表单,其功能为用户注册并为用户新增一个车辆信息(由于单纯用户注册表单会过于简单,所以加了个车辆表单),提交到apigetaway的时候,是由apigetaway分别调用用户微服的注册接口和车辆添加接口呢,还是在用户中心新增一个注册用户并添加车辆接口。 为什么会有这个疑问是因为车辆表中会依赖于用户表的user_id,假设分开调用微服,可能会存在用户已注册成功,但是车辆添加失败的情况,此时前端不知道该如何处理。 望解答。

sndwow avatar Feb 06 '18 07:02 sndwow

@sndwow 你这个问题已经隐含的将领域BC划分为两个,一个是用户,一个是车辆。划分的依据是什么?是两个业务本身关联就少,是松耦合。但是问题中,又将两个领域紧密的放到了一个页面中,制造一个分布式事务的场景。实际上这个问题本身就是冲突的,既然业务上有必要紧密同时增加,为啥要在两个领域中?这就涉及到DDD的一个领域划分问题,绝对不是按照表来划分的。而是按照你的业务场景来划分的,划分的过程可以参考Event Storming,你做完了,很可能发现这两个表应该在一个领域中,一个微服务中。Event Stroming 是非常好的一种手段。如果有兴趣可以参考 https://github.com/JoeCao/qbike 这个项目。从业务流程入手来划分领域,最终实现代码的例子。

JoeCao avatar Feb 06 '18 08:02 JoeCao

@JoeCao 目前这2个表是放在了一个微服中。没表述清楚,添加用户接口和车辆接口是处于同一个微服中的2个接口(目前没有完全按照rest风格),假设页面表单将用户和车辆信息同时提交到apigetaway,目前处理的逻辑是先调用用户接口注册用户(返回user_id),再将user_id与表单中的车辆信息调用车辆接口注册。所以出现上面所述的可能2个接口其中一个处理失败,照成数据不一致。 假设将上述2个接口合并在一起组成一个微服接口,可以利用微服自身的关系数据库的事物达到预期要求,但是感觉又像是微服是面向前端页面开发接口。 目前感到比较困惑的是,到底微服的接口是应该写得通用些,还是针对前端开发。因为前端不止有web,还有app,每个端可能都有此类的表单,但是表单项是不一样,比如app端需要填写的表单项很少。如果每个端都写一个微服,那么开发工作量就很大,且冗余。

sndwow avatar Feb 06 '18 09:02 sndwow

@JoeCao 实际业务中,也存在多个微服的资源放在同一个页面表单提交到api的情况。

sndwow avatar Feb 06 '18 09:02 sndwow

微服务还是基于领域的,你说的针对前端开发的是BFF(backend for frontend)的范畴。 BFF的作用,看这篇 https://github.com/JoeCao/JoeCao.github.io/issues/2 。 具体业务还是要分析场景,特别是Create、Update、Delete之类改变多个领域状态的操作,我是不太建议。一旦出现这种情况,很可能是我们领域划分有问题。

JoeCao avatar Feb 06 '18 09:02 JoeCao

@JoeCao BFF篇幅里也有这种情况

以商品中心为例:一个大的商品中心服务可以被拆为类目、商品、价格、库存四个微服务

例如商品,在前端后台管理中,针对商品进行Create、Update,可能会涉及商品价格、名称、库存等,这也是会改变多个微服的数据状态。

sndwow avatar Feb 06 '18 11:02 sndwow

@sndwow 我们拆分商品中心为四个服务,是因为在业务上他们的编辑的场景是分开的,商品是基础数据的编辑是商城运营角色配置。价格涉及到营销策略、级别价格,由营销团队去配置的。库存是库管、采购角色共同管理的,这个场景更独立。如果你们的商品的基础信息、价格、库存是一个场景下都编辑了,角色也一样,说明价格和库存的管理流程不是那么复杂,只是商品的一个附属属性而已,那么建议你就直接合在一个服务里面,不需要拆开。还是那句话,按照业务场景、流程去划分你的服务边界。

JoeCao avatar Feb 07 '18 01:02 JoeCao

@JoeCao 举个实例来说,用户与车辆目前在一个微服中。app、erp端都存在用户注册的需求,而app由于可操作空间小,用户注册与车辆添加的ui是分离的,而erp是pc端,用户注册与车辆添加是处于同一个页面表单。 目前有2个解决方法: 1、为app和erp端分别开发2个注册用户接口,而erp端的用户注册接口允许接收车辆信息并添加。 2、只写一个用户注册接口和一个车辆添加接口,erp端的apigateway调用完用户接口后,根据返回的用户id再次请求车辆添加接口。

第一种方法可以有效的根据不同的端接收不同的参数,也就是说已经是BFF开发范畴,相当于每个页面都需要为其开发一个专用的微服接口,apigateway只是做了数据转发。 第二种方法可以复用用户注册接口,不同的业务可组合调用接口,但是不能保证原子性。

想请求下有什么好的解决方案。

sndwow avatar Feb 07 '18 06:02 sndwow

@sndwow 这个需要了解一下详细的业务流程。在看到底是不是设计的问题。 详细情况你发邮件给我吧。 我提供一个思路, 1、如果这个用户和车辆是强绑定的,一个人必须有0...n的车辆,修改车辆信息等于修改用户的相关信息。那么这个场景下人是聚合根,车辆是属于人的值对象。我的设计甚至会将车辆的数据内联到用户表中,都不会用附加的外键子表。 那么你的新增用户的接口,就应该包含将聚合根和对应值对象一并加入数据库的逻辑。所以这个事务的一致性就在这个接口保证了。bff不需要调两次不同的接口。 2、如果用户和车辆是松耦合的,有业务场景可以让用户在后续添加完善车辆信息,并且车辆信息也有什么是否保险到期、年检没过、违章信息的相关可变化的属性。那么用户和车辆就是松耦合的两个不同的聚合根。那么两个聚合根,我们就不合适用强制的事务来保证一致性,而是采用最终一致性。 那么你说的在注册的时候,需要同时加两个信息,我认为这是一个比较奇怪的需求,请和产品经理讨论一下。当然为了方便客户操作也可以做,原子性不用考虑太多,毕竟网络错误之类的几率很少,而且如果在第二个车辆信息添加接口调用失败的情况下,这个新增用户应该是成功的,可以提示用户,“在后续的操作中,请至xxx菜单完善您的车辆信息”,我相信这样做,产品经理也是可以接受的。

JoeCao avatar Feb 08 '18 02:02 JoeCao

@JoeCao 感谢解答! 场景正如思路2所述,目前采用了该方法来解决。 在您的文档中解开了许多疑惑,再次感谢。

sndwow avatar Feb 08 '18 07:02 sndwow