集成工作的复杂度影响了复杂系统的研发
Unix的实践无疑对软件架构有着巨大的影响,做一个事情,做到最好,一直是 Unix 风格所倡导的,但“在理想世界中,Unix程序员只愿意手工打造小巧完美的软件宝石,每个都那么小巧、那么优雅、那么完美。然而现实中很不幸的是,太多复杂问题需要复杂的解决方案。仅仅十行的程序,再优雅也无法控制喷气式客机。那儿有太多的装备、太多的通路和界面,太多不同的处理机,太多不同操作人员定义的子系统,他们甚至连基本的约定都无法统一。即使能够成功地将航空系统所有的个体软件部分做的优雅,但拼装结果很可能是一堆庞大、复杂、糟糕的代码… 喷气客机的复杂是必然的。过去有个尖锐的观点,不能为简单性而牺牲功能,因为飞机必须要能飞。正是这个事实,航空控制系统并不会产生关于复杂度的圣战----Unix程序员往往敬而远之。“(摘自《Unix编程艺术》)。
不幸的是,我们面临的往往是复杂性的系统,片面理解Unix风格分而治之往往带来更大的集成难度。为了降低集成的难度,我们往往采用巨石型的系统架构,用一个大一统的方式设计系统,仅仅在系统内部进行模块的拆分,用codebase和规范进行约束,走上了和Unix风格背道而驰的道路。当性能和可维护性压力到来后,这样的系统又不得不进行拆分:我过去常常看到,当软件系统达到 100 万行代码规模时,人们会觉得维护困难,产生了强烈的拆分念头,当达到 300 万行代码规模时,人们往往再也按耐不住拆分的欲望,当达到 500 万行代码规模时,再保守的组织也会作出拆分的决定。
软件架构中复杂的集成工作需要利用人工智能方式简化下来
回顾一下解决集成问题的历史,我们会发现较早的集成架构模式来自于 Unix,就是众所周知的管道(Pipe)模式。Pipe模式将数据传递到一个任务序列中,管道扮演着流水线的角色,数据在这里被处理然后传递到下一个步骤。管道模式作为一种最基本的方式,理论上可以解决所有集成问题,但涉及到具体问题时,就需要针对不同情况做应对,针对各种复杂的情况,可以总结出更多的模式,《企业集成模式》(EIP)一书中围绕消息集成,总结出若干集成模式,可谓是消息集成的集大成式总结。
但EIP的集成模式主要针对系统间后台服务的集成,SOA架构提出了以Portal(前端集成)、BPM(流程集成)、ESB(服务集成)、DI(数据集成)以及事件/消息集成的多层面集成体系,更加系统性的为集成工作提供指导。SOA的集成方式需要一系列的集成基础设施支持,属于一种中心化的集成方式,我们可以称之为MiddleBox的方式,在微服务架构提出后,我们会采用把集成逻辑与业务功能部署在一起的去中心化集成方式,可以称之为MiddlePipe的模式。
集成方式一路演进下来,主要是集成的手段上不断翻新,多种框架和基础设施越来越多的解决了非功能需求,例如 ESB 可以解决路由、安全、流控等问题,一定程度上减少了集成的工作量。但集成的业务复杂度还存在很多,这里我列举几个常见的问题:
(1)数据的查找问题。针对业务需求,需要使用已存在的数据和服务,但在企业环境中,系统、服务、数据众多(想象一下具有10多万服务、10多万数据标准的情况),想找到适用的服务和数据,不是一件容易的事情,一般我们都要依赖专家在这方面的知识,通过总体设计指定了数据的流向,这依赖于专家的能力,专家的能力也是慢慢积累起来的。我们需要帮助业务更快速的找到数据和服务,帮助专家快速实现积累,减少重复劳动。
(2)数据的适配问题。通过服务方式进行集成,原子服务往往需要大量的输入参数。举个例子,调用一个发短信的接口,不仅仅是收信人电话号码和短信内容,还要包括很多业务含义的参数,例如发信人的姓名、组织、发信的系统、发信的原因、发信时和客户接触的渠道(客服渠道、网点渠道、网银渠道、自助终端等等)、发信时关联的产品,这些信息是可以用来计算成本、控制次数、避免重复骚扰客户;用户名、密码、验证码、发送时间等这是用作安全验证的;优先级、发送渠道等是用来做流量控制的;流水号、全局业务ID、请求ID、请求时间等等是用来做监控的。上述信息来自与每次发短信的上下文,在实际开发期间就要做很多的赋值、转换工作,将上下文的信息传递给服务,这种转换就像下图那样,典型的面多了加水,水多了加面。我们需要根据当前上下文和服务的特征,自动的进行一些适配,避免人工的重复性劳动。