聊一聊过度设计!

简介: 新手程序员在做设计时,因为缺乏经验,很容易写出欠设计的代码,但有一些经验的程序员,尤其是在刚学习过设计模式之后,很容易写出过度设计的代码,而这种代码比新手程序员的代码更可怕,过度设计的代码不仅写出来时的成本很高,后续维护的成本也高。因为相对于毫无设计的代码,过度设计的代码有比较高的理解成本。说这么多,到底什么是过度设计?

@

  新手程序员在做设计时,因为缺乏经验,很容易写出欠设计的代码,但有一些经验的程序员,尤其是在刚学习过设计模式之后,很容易写出过度设计的代码,而这种代码比新手程序员的代码更可怕,过度设计的代码不仅写出来时的成本很高,后续维护的成本也高。因为相对于毫无设计的代码,过度设计的代码有比较高的理解成本。说这么多,到底什么是过度设计?

什么是过度设计?

  为了解释清楚,我这里用个类比,假如你想拧一颗螺丝,正常的解决方案是找一把螺丝刀,这很合理对吧。 但是有些人就想:“我就要一个不止能拧螺丝的工具,我想要一个可以干各种事的工具!”,于是就花大价钱搞了把瑞士军刀。在你解决“拧螺丝”问题的时候,重心早已从解决问题转变为搞一个工具,这就是过度设计。

网络异常,图片无法展示
|
  再举个更技术的例子,假设你出去面试,面试官让你写一个程序,可以实现两个数的加减乘除,方法出入参都给你提供好了 int calc(int x, int y, char op),普通程序员可能会写出以下实现。

   publicintcalc(int x, int y, char op) {
       if (op == '+') {
           return x + y;
       } elseif (op == '-') {
           return x - y;
       } elseif (op == '*') {
           return x * y;
       } else {
           return x / y;
       }
   }

  而高级程序员会运用设计模式,写出这样的代码:

publicinterfaceStrategy {
   intcalc(int x, int y);
}

publicclassAddStrategyimplementsStrategy{
   @Override
   publicintcalc(int x, int y) {
       return x + y;
   }
}

publicclassMinusStrategyimplementsStrategy{
   @Override
   publicintcalc(int x, int y) {
       return x - y;
   }
}
/**
* 其他实现  
*/

publicclassMain {
   publicintcalc(int x, int y, char op) {
       Strategy add = new AddStrategy();
       Strategy minux = new MinusStrategy();
       Strategy multi = new MultiStrategy();
       Strategy div = new  DivStrategy();
       if (op == '+') {
           return add.calc(x, y);
       } elseif (op == '-') {
           return minux.calc(x, y);
       } elseif (op == '*') {
           return multi.calc(x, y);
       } else {
           return div.calc(x, y);
       }
   }
}

  策略模式好处在于将计算(calc)和具体的实现(strategy)拆分,后续如果修改具体实现,也不需要改动计算的逻辑,而且之后也可以加各种新的计算,比如求模、次幂……,扩展性明显增强,很是牛x。 但光从代码量来看,复杂度也明显增加。回到我们原始的需求上来看,如果我们只是需要实现两个整数的加减乘除,这明显过度设计了。

过度设计的坏处

  个人总结过度设计有两大坏处,首先就是前期的设计和开发的成本问题。过度设计的方案,首先设计的过程就需要投入额外的时间成本,其次越复杂的方案实现成本也就越高、耗时越长,如果是在快速迭代的业务中,这些可能都会决定到业务的生死。其次即便是代码正常上线后,其复杂度也会导致后期的维护成本高,比如当你想将这些代码交接给别人时,别人也需要付出额外的学习成本。

  如果成本问题你都可以接受,接下来这个问题可能影响更大,那就是过度设计可能会影响到代码的灵活性,这点听起来和做设计的目的有些矛盾,做设计不就是为了提升代码的灵活性和扩展性吗!实际上很多过度设计的方案搞错了扩展点,导致该灵活的地方不灵活,不该灵活的地方瞎灵活。在机器学习领域,有个术语叫做“过拟合”,指的是算法模型在测试数据上表现完美,但在更广泛的数据上表现非常差,模式缺少通用性。 过度设计也会出现类似的现象,就是缺少通用性,在面对稍有差异的需求上时可能就需要伤筋动骨级别的改造了。

如何避免过度设计

  既然过度设计有着成本高和欠灵活的问题,那如何避免过度设计呢!我这里总结了几个方法,希望可以帮到大家。

充分理解问题本身

  在设计的过程中,要确保充分理解了真正的问题是什么,明确真正的需求是什么,这样才可以避免做出错误的设计。

保持简单

  过度设计毫无例外都是复杂的设计,很多时候未来有诸多的不确定性,如果过早的针对某个不确定的问题做出方案,很可能就白做了,等遇到真正问题的时候再去解决问题就行。

小步快跑

  不要一开始就想着做出完美的方案,很多时候优秀的方案不是设计出来的,而是逐渐演变出来的,一点点优化已有的设计方案比一开始就设计出一个完美的方案容易得多。

征求其他人的意见

  如果你不确定自己的方案是不是过度设计了,可以咨询下其他人的,尤其是比较资深的人,交叉验证可以快速让你确认问题。

总结

  其实在业务的快速迭代之下,很难判定当前的设计是欠设计还是过度设计,你当前设计了一个简单的方案,未来可能无法适应更复杂的业务需求,但如果你当前设计了一个复杂的方案,有可能会浪费时间……。 在面对类似这种不确定性的时候,我个人还是比较推崇大道至简的哲学,当前用最简单的方案,等需要复杂性扩展的时候再去重构代码。

目录
相关文章
|
6月前
|
缓存
代码优化与过度设计:寻找平衡的艺术
作为开发人员,我们常常会面临一个棘手的问题,即如何在代码优化和过度设计之间找到平衡点?因为我们都希望通过优化代码来提升程序性能,但实际情况是稍有不慎就可能陷入过度设计的泥潭,让代码变得难以理解和维护,反而适得其反。在实际开发中,我们应该如何在这两者之间找到平衡呢?那么本文就来简单分享一些经验和方法,从而帮助我们避免陷入这种困境泥潭中。
101 3
代码优化与过度设计:寻找平衡的艺术
|
3月前
|
架构师 NoSQL 中间件
挑战架构师极限:分布式锁的四种实现方式,优劣对比让你一目了然!
【8月更文挑战第29天】在2024年软考架构师考试中,掌握分布式锁的实现方法极其重要。本文详细介绍了基于数据库、Redis及ZooKeeper三种常见分布式锁方案。数据库锁简单易懂但性能低;Redis锁性能优越且支持自动续期,但需引入中间件;ZooKeeper锁可靠性高,适用于分布式环境,但实现复杂。通过对比各方案优缺点,帮助考生更好地应对考试,选择最适合业务场景的分布式锁策略。
232 0
|
6月前
|
设计模式 IDE Java
谈谈过度设计:因噎废食的陷阱
本文探讨了设计模式在软件开发中的应用和争议,指出设计模式虽有助于应对软件复杂性,但在互联网快速迭代的背景下,可能会导致过度设计,增加理解和修改成本。文章分析了设计模式的缺陷,如开闭原则可能导致不易修改,最小知识原则可能导致理解困难。同时,文章强调了设计模式的重要性,指出它们可以提高代码的可理解性和模块的可维护性,并提出了通过函数式设计模式进行优化的示例。作者认为,设计模式需要随着业务演进而不断演进,同时提倡使用可调试的模块和模式演进来促进系统的成长性。文章最后提醒读者,要根据实际情况选择是否使用设计模式,避免因噎废食。
|
存储 SQL Kubernetes
面向K8s设计误区
K8s 取其精华去其糟粕,是我们程序员应该做的事情。
2899 12
面向K8s设计误区
想学习UI设计,但是审美能力很差怎么办?
最近很多学员问我,说自己审美能力差,还能不能学习UI设计。针对这个问题我就来和大家一起探讨一下,如何提升自己的审美能力。 其实审美,并不是天生就有的,审美全是后天培养的,不管是设计,还是其他的一些事情,对于美与丑,都是后天的学习与指导产生的,也就是说这都是从小就开始养成的,从小就开始培养的,就跟小时候大人教我们那些事物是好的,那些事物是坏的,是一样的道理。
1038 0
|
UED
为什么有些设计初衷很好,结果却很糟糕
本文讲的是为什么有些设计初衷很好,结果却很糟糕,刚刚,在她意识到自己已经买了机票之后,她又打开另一个标签页,预定这次旅行的酒店房间,又租了一辆车。随后返回到美国航空的标签页获取她的确认编号,同时记录在她的日历上。
1398 0