软件设计 (架构) 往往在项目开发中起到非常关键性的作用, 至少它是能够工作。良好的软件设计包含了:灵活性、可伸缩性、可行性、可复用性、安全性,通过该一系列的定义, 使我们影响到了软件功能的设计和特征。
(一)、什么是过度设计
过度设计一词在英文中称为“over design”,over 意思是太多,design 意思是设计、构思, 通过教科书上面的解释, 意味着你设计的或构思的太多了, 即为过度设计。
什么是过度设计?设计出来的系统比恰到好处要复杂或臃肿的多, 过度的封装、继承、接口或是大量的无用配置方法, 其实就是用户需要一把杀鸡的刀, 而你却设计出了杀牛刀或是电锯。
过度设计通常来自于开发者将问题过于复杂化或是前瞻性欠缺。
在我们日常所犯的错误中, 大部分是来自于前者, 至于后者的欠缺, 需要一定的项目经验和洞察力来支撑, 能够合理的预判和考虑需求会哪个方向发展。
在前者, 问题复杂化会引入大量额外的代价, 如成本上升,系统缺陷增大、提升维护成本、降低系统性能。而高性能和可维护性都是系统的隐性需求, 如果这些也没实现好, 那就可能属于设计错误。
但是从客观角度来看, 能够进行过度设计的,多半设计能力高于设计不足的, 过度的设计改回来的成本也比设计不足的改过去的成本低的多, 在此需要更多地去权衡“ 利与弊 ”。
(二)、过度设计案例
以系统充值为例, 最初你设计的系统只需要一个支付宝功能, 你的数据库设计如下:
id primary key int // 主键
user_id int// 充值用户
status int //- 1 充值失败,0 充值中,1 充值成功
order_no string // 第三方支付系统订单号
amount decimal // 金额
但是没过多久, 你的系统需要接入另一个支付系统 - 微信, 需要区分用户是通过微信还是支付宝充值的, 于是你的数据库设计便成了以下模样
id primary key int // 主键
user_id int// 充值用户
status int //- 1 充值失败,0 充值中,1 充值成功
order_no string // 第三方支付系统订单号
platform string // 第三方交易平台
amount decimal // 金额
但是你想了下, 感觉可能以后需要接入银联支付, 需要记录是哪张银行卡支付的, 然后你又想了下, 既然已经接入了银联支付, 那顺便就再完善以下, 支持国际支付, 如美元充值, 港币充值, 然后需要记录上当地充值的汇率及当地支付时间, 最终你花了一天的时间, 将数据库改成了这样
id primary key int // 主键
user_id int// 充值用户
status int //- 1 充值失败,0 充值中,1 充值成功
order_no string // 第三方支付系统订单号
platform string // 第三方交易平台
amount decimal // 金额
currency string // 货币:CNY USD HKD
bank_id int // 银行卡 ID
rate decimal // 充值汇率
local_pay_time // 当地支付时间
完成基本设计后, 你花了 4 周的时间完成编码和测试, 最终交付了上去, 然而系统的初衷只是需要简单区分的是微信充值或支付宝充值, 而因过度设计带来的额外成本和缺陷是非常巨大的, 为此我们需要尽力让自己做的恰到好处并且避免过度设计。
(三、)如何避免过度设计?
避免过度设计的最佳方法就是“不要设计的太远”, 未了解实际未来, 就做出了各种预设和判断, 为系统增加了额外的负担。
正如 scrum(敏捷开发)所倡导的 Evolutionary Design(演进式设计), 将每一次的重构和迭代都映射和更新到最新的设计中来,从而最大限度的满足系统的功能性需求和非功能性需求。
当你手里握着一把锤子时, 不要把所有看到的, 都当成钉子。