什么时候该提前做扩展性设计?我只看三种情况

36 阅读5分钟

扩展性设计该不该提前做,判断依据不是你能不能预测未来,而是你是否真正熟悉和理解对应的业务领域。

我先从自己做过的一个行业说起。

连锁行业里的确定性

我在连锁店行业待了蛮久,知道这个行业里,一定有一个事情是必须做的:

就是需要对接大量的外部系统。

我给你列一下,我对接过的:

  • 金蝶;
  • 绝配物流;
  • 旺店通;
  • 各种发票平台;
  • 各种物流配送平台;
  • 快递物流100;
  • 合思;
  • 北森;
  • 钉钉;
  • 门店巡检系统;
  • 。。。。。。

太多了。而且几乎每个项目,都会新增以前没接过的系统。

因此在后来,我都会在项目一开始就设计一个统一的外部系统接入网关。每接入一个新的外部系统,只需要新写一个策略实现类,在配置中心增加一份配置,系统根据配置选择对应的实现。新增系统不用改已有代码,已有系统的修改也不影响其他对接方。这时候提前做扩展设计,不是过度设计,而是在表达这个行业真实的业务模型。

绝对不是因为我喜欢设计模式,也不是因为我要遵守开闭原则。而是因为在这个行业待久了,我非常确定:外部系统对接不是可能发生,而是一定发生。对我来说,这已经不是未来需求,而是业务模型的一部分。

这里有一个关键的区别。我在做这个设计的时候,不是在猜「以后可能需要对接某个系统」,而是在表达「这个行业一定会对接多个外部系统」这个事实。猜和确定,完全不是一回事。

如果连锁店业务是唯一一个有这种确定性的领域,这个观点的说服力当然是不够的。但实际上,很多行业都有类似的规律。

不只是连锁店行业,其他行业也一样

支付系统就是另一个例子。在国内做过互联网电商业务的都知道,第一版可能只上线微信支付。但后面通常还会接支付宝等支付渠道。这不是在猜未来,而是整个行业已经证明:支付本身就是一个多渠道系统。第一版只接微信支付,是因为排期,不是因为只需要微信支付。支付的多渠道业务模型已经完整存在,只是代码分阶段交付而已。

营销活动也是。电商行业的促销天然就是多类型的:满减、折扣、赠品、秒杀、拼团、预售。没有哪个电商系统会只做一种营销活动。第一版可能只上线满减,但营销活动的扩展性从第一天就该考虑到。

支付、营销、外部系统对接,这几个领域有一个共同点:它们不是未来可能发生变化的地方,而是天然就具有多种实现的地方。提前设计扩展点完全没问题。

那么,怎么判断一个领域是否具有这种确定性?我从自己的项目经验里总结了三个方面。

确定性从哪里来

行业规律

有些业务天然就是可扩展的。支付渠道、营销活动、消息通知、审批流、风控规则,这些领域经过无数项目验证,本身就是多实现、多规则、多渠道的。你不需要预测未来,只需要看这个行业里其他系统是怎么做的。

产品规划

有时候,虽然代码还没开发,但产品路线已经非常明确。下个月接支付宝,两个月后接Apple Pay,三个月后支持海外支付。这种情况下,提前抽象也是合理的,因为需求已经确定,只是开发时间还没到。

历史变化

还有一种情况。某段代码已经连续修改了很多次。营销规则最开始只有一个if,后来两个,再后来十几个。这时候再继续堆if else已经不合适了,策略模式、责任链模式就会顺其自然地出现。这种抽象不是为了未来,而是为了今天已经存在的问题。

确定性来源典型场景判断依据是否值得提前设计
行业规律支付渠道、营销活动、消息通知该领域的其他系统是否都实现了多实现
产品规划近期待接入的渠道或功能路线图是否明确到排期
历史变化同一逻辑反复修改的代码是否已经因为同类需求改过多次

这张表可以当作一个判断工具。遇到一个设计决策时,先问自己:这种变化属于哪一种?如果三种都沾不上边,那这个扩展性设计可能就建立在猜测上。

建立在猜测上的扩展

面向对象设计原则里有一个很少有人注意到的隐含假设:我们提前写接口、写抽象、写设计模式,是因为我们假设自己知道未来系统会如何变化。但大多数时候,我们并不知道。

支付值得提前抽象和扩展,是因为整个行业已经证明它一定会扩展。但如果只是一个程序员觉得「以后可能支持海外」「以后可能支持AI」「以后可能支持多租户」,那就是另一回事了。行业规律有证据支撑,个人想象没有。

好的抽象和扩展应该能被解释清楚。如果你解释不了,那它就不应该留在代码里。

小结

扩展性设计的依据,不是未来会不会变化,而是你是否有足够的业务知识,确信这种变化一定会发生。当你足够了解一个行业时,你做的就不是在提前设计未来,而是在忠实地表达这个行业本身的规律。

**设计模式解决的是代码问题,而领域知识决定的是哪里应该使用设计模式。**后者比前者重要得多。