<audio id="audio" title="26 | 系统集成：为什么最容易出问题的是系统集成？" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/f2/3f/f22c82ef5a8da0880695259bda2e913f.mp3"></audio>

你好，我是臧萌。在上一节中我们聊了软件系统架构师。软件架构师完成了最核心的系统，但是这还远远没完。如果你想让这个系统真的运转起来，那还需要系统集成。而且在我看来，系统集成很多时候所占的时间和精力，远比系统核心要多。

那到底什么是系统集成呢？系统集成，简单来说，就是要对接、落地，验证，看到真正的成果。

## 吃上一道新菜，过程远比你想的复杂

我们拿饭店来打个比方。假设我们现在运营着一个连锁饭店，中心厨房会为每个连锁饭店配送半成品的菜品。现在我们要推出一款叫“三菌笋片烩鸡丁”的新菜品。对于新菜品来说，一开始我们要先构思，然后去小范围地验证这个菜品。如果在这个小范围内得到一致好评，那第一步就算完事了。

这时候，如果用软件系统研发的进度做对比的话，菜品研发部分，就是完成了系统架构和关键模块的编写，也就是完成了核心系统的开发。请大家试吃就是搞出一个演示给大家看，结果就是大家看着核心系统的演示，都觉得功能很棒，翘首期待能早日用上。

这是决定这个系统特色的一步，也是最有创造性的一步。但得到了大家的认可，这能算成功了吗？远远没有。这只能算是迈出了通向成功的第一步，距离成功，还差着系统集成这关键的一步呢。

回到我们的例子。我们的目的是为连锁饭店推出一道新的菜品。我们需要给连锁饭店的食客们安全快速地呈上这道新菜，才能算成功。而一个菜能在厨房做出来，和一个菜能一年能在所有饭店长期保持稳定水准，是完全两个概念，难度也是两个级别。

三菌笋片烩鸡丁这道菜，用到了三种菌菇以及笋片和鸡丁。三种菌菇可能无法保证每一个连锁店所在地都有货，可能某些菌菇即使有货，价格也波动很大，可能有的菌菇对保鲜和运输的要求比较高，弄不好就容易变质，造成食品安全问题。

饭店一旦要连锁，类似的问题就会不断地暴露出来，并且不断放大。如果类似问题处理不好，那么这个菜品就是失败的。而这个让新菜品落地的过程，类比到软件系统里，就是系统集成。

## 如何不掉进软件系统集成那些坑

那我们继续回到软件系统。软件系统在特定的场景，无其他干扰因素的理想情况下正常工作，并不代表它就可以用了。外界的很多因素，都有可能影响系统发挥出本身的功能。系统集成的过程，才是对系统的大考。

每个系统面对的情况都不一样，这里我还是用一个电商网站来举例子，给大家聊聊软件系统集成中常见的那些坑、如何尽量避免掉进坑里、以及要是你不小心掉进去的话，如何快速而优雅地爬出来。

电商网站有库存、商品展示、订单管理、退换货等等子系统。退换货子系统需要对接供货商的ERP系统。

### 系统内部集成：架构统一

所谓系统内部的集成，就是一个系统各个模块之间的集成。比如将库存记录、进出库存、库存盘点等模块等，集成为一个完整的库存系统。如果一个系统设计得过关，那么对于这种集成来说，出问题的几率还是比较小的，而且即使有问题，也容易解决。原因在于这个系统本身就是新的，是遵循着一个统一的架构设计做出来的。各个模块之间在设计之初，就已经做好了集成的准备。

这时候出现的问题，大多是因为一些实现的细节，或者是设计时没有描述清楚造成的。比如代码接口定义不统一，数据交互的格式不统一等等。我之所以说这时候还比较容易解决，就是因为新系统没有历史负担，不需要考虑兼容性等问题，所以只要大家将之前的误解消除，解决问题的工作量还是可以估算的。

这时候如果出现比较大的问题，很可能是因为模块由不同的架构师来负责，而不同的架构师之间没有充分的沟通。好的方式，应该是让一个架构师负责一个完整的模块，根据开闭原则，提供统一且简单清晰的接口，对外提供功能。

正所谓，令出多门，兵家大忌。如果很多人都可以拍板做决定，那么事情到头来很可能会乱套。即使需要不同的架构师负责，也要有一个总的架构师，提供统一的总体架构，解决架构师之间的争论。

好的，这时候我们有了一个库存模块，功能都测试过了，而且它接口简单精炼，一张A4纸就能打印出来。别的模块也纷纷告捷，大家满心欢喜地开始向前推进。

### 外部系统集成：不做假设

这时候，退换货模块需要就退货功能，跟外部ERP系统集成了。当你自信满满地问：你们的退货接口是什么，发给我看看。对方发给你一个文档，描述了退货需要提供的数据。你看完，发现需要的数据没啥特殊的，一切尽在掌握。

于是你按照要求，对接的代码就写了起来，没两天就弄好了，和对方说：你们的RESTful接口给我测试一下，我这边的数据弄好了。对方一脸问号地说，我们没有什么RESTful接口，你把数据保存成那个格式，上传到我们这个FTP就行，我们三天内处理完，然后你再去那个FTP上，下载一个叫yyyy-mm-dd-result.json的文件就可以了，很简单的。

这时候，你终于知道了什么叫做两个世界的人，在你眼里，对方重新定义了简单。同时，你也体会到了什么叫做失控。按照之前的设计，退换货是需要即时给出结果的。这种通过FTP传递数据，需要三天处理的模式，完全打破了之前的设计。且不说很多内部的功能都要重新设计重新做，对外的接口也要大改，而且还会影响所有已经和退换货模块集成好的模块。

和外部系统集成，越早确定细节越好，不要假设任何东西。任何在你看来很自然的东西，可能对方就是没有。你的系统如果对这些想当然的东西有强依赖，那么代价可能是惨重的。

这里我可以再举一个例子。如果你的系统的核心功能依赖于某个外部系统的功能，比如某个数据库功能，那你就先把这个通路确定好。比如公司购买的数据库是否有这个功能、公司的DBA是否允许我们使用这个功能、这个功能的吞吐量有多大等等。

如果在集成的时候发现，你的系统核心功能与外部系统依赖之间存在问题，这会变得非常麻烦。因为外部系统已经存在，外部系统能不能因为你的需要来做出改变，是非常不确定的。而不同的系统之间，本来就没有统一的架构，系统之间的集成点，需要在设计之初反反复复确认并验证。

### 漫漫集成路之问

下面我们来谈谈系统集成中其它常见问题。

首先就是配置。有些模块的配置非常繁琐，甚至配置比代码都麻烦。有些系统的配置需要经验的积累和专业的学习，比如Kafka，HBase，Hystrix等中间件系统。和这些模块或系统集成，代码之外的配置将是一个非常容易出问题的点，比如说，配置不合理、配置被覆盖、配置非法导致没有生效等等。

如何应对这类集成呢？我的建议是眼见为实。在你用到配置的地方，将配置用log的形式输出出来，方便用二分法确定问题。

接着是数据。其实系统集成的时候，很大一部分问题是和数据相关的。这里我给出两类常见的数据问题，一个是用户输入的数据，一个是数据交换。

对于用户输入的数据，简单来说，一个字节都不要相信。用户可以给用户名填写100k个字符、用户填写的日期可能是未来或者几百年前、用户可能输入任何数据。所以在使用用户的数据之前，要把数据全部检查一遍。还是那句话，不要做任何假设，哪怕前端已经做了数据验证，自己的系统也要保护性地验证一下数据。

至于数据交换，也是一个非常容易出问题的点。系统集成少不了数据交换，因为大家对数据schema定义的不同，数据交换往往伴随着数据格式的转换等操作。这时候，不同系统对于数据缺失、默认值、数据约束等规定的不同，可能会造成各种问题，甚至出错。数据在不同系统之间，交换还可能伴随着数据丢失等问题。

所以，外部系统给的数据，一个字节也不要相信。当和外部系统进行数据交换的时候，一定要在系统交互的边界，好好记log。要能够将数据的输入、转换、出错等各种情况都记录详细的log，方便排查问题。

## 总结

系统集成为什么这么麻烦，这么漫长，原因在于一方面，它需要给出最终的被大家认可的成果。另一方面，在现实条件中可能有各种各样，之前没有想到的问题。这些问题，都会在系统集成的时候，一一暴露出来，成为系统集成路上的拦路虎，造成无法交付成果的情况。

每当我听到有同学说：我代码写完了，这个事情可以结束了。我都会露出尴尬而不失礼貌的微笑。我不能否定这个结论，因为如果你问我还有什么事情没弄完，我也可能说不出个123来。但是我敢肯定，这位同学可能还要付出一倍甚至数倍写代码的时间，才能让这个代码真的跑起来，才能说这个事情结束了。

这个过程，就是系统集成，是我们在为自己的想当然、对需求的理解偏差、经验的欠缺、能力的不足、视野的限制、不充足的前期调研、未预料到的意外来付出的代价。功力深厚的架构师，也是一个系统集成的大师。他可以在设计阶段，根据自己的经验，尽量减少问题，降低难度。所以，能够越少地付出这个代价，越能代表自身综合能力的提升，也是代表自身价值的提升。

<img src="https://static001.geekbang.org/resource/image/b9/12/b92f2c8698d34448bf31171194fd4f12.jpg" alt="">

## 思考题

系统集成，是任何一个系统都逃不过的大考。你有过哪些关于系统集成刻骨铭心的经历呢？关于系统集成，你遇到过哪些问题，又有哪些实践经验可以分享呢？

好，今天的课程就结束了，希望可以帮助到你，也希望你在下方的留言区和我参与讨论，并把文章分享给你的朋友或者同事，一起交流一下。
