10 个当代软件开发中的Over-Engineering症状

来自:米么信息科技
时间:2016-08-04 10:25:35
分享:
米么信息 米么信息 米么信息
10 个当代软件开发中的Over-Engineering症状,在自然系统中,通用的逻辑和抽象概念会随着时间逐渐趋于稳定。在功能变得更广泛的情况下,他们要么停留在扁平的状态,要么慢慢沉没。否则的话,系统的体积就会变得过大,导致各种错误的出现,在这种情况下,你就要对系统进行彻底的重写了。

没有什么东西的总量是在一直增加的:星体间的距离、宇宙中的平均信息量,还有该死的商业需求。很多文章都说Over-Engineering是个不好的东西,但是它们却没说如何避免Over-Engineering。

1. 工程比商业更重要

工程师们都觉得自己是世界上最聪明的人,因为我们能够开发出新的东西。这样的错觉总是会让我们Over-Engineering。但是事实上,如果我们做了100个计划,商业总是能提出我们没有想到的第101个计划。如果我们解决了1000个问题,商业会再给我们提出1万个新问题。我们觉得自己能掌控一切——但是实际上,对于未来会发生什么,我们完全没有任何头绪。 

在我15年的编程生涯里,我从未见过商业要求“交汇”的情况,它们只会分岔,这是商业的天性,并不是商业人士的错。 

2. 可重复使用的商业功能

当商业给我们提出越来越多的功能要求时,我们有的时候会这样反应: 

 

我们会尽可能的进行归类,并且生成其中的逻辑。正是出于这个原因,MVC才会最终变成Fat Model或是Fat Controller。但是我们刚刚提到了,商业要求只会分岔,不会交汇。因此,我们的反应应该是这样的:

  

在自然系统中,通用的逻辑和抽象概念会随着时间逐渐趋于稳定。在功能变得更广泛的情况下,他们要么停留在扁平的状态,要么慢慢沉没。否则的话,系统的体积就会变得过大,导致各种错误的出现,在这种情况下,你就要对系统进行彻底的重写了。 

例如,我们曾经给一个客户创建了用户资料系统。刚开始的时候,我们使用了CRUD控制器,以及通用的功能设计,因为我们觉得所有人的注册过程都是相似的。但是结果我们发现,用户有13种注册流程,这让我们使用的方法难以为继。 

3. 所有东西都是通用的


  • 想要连接数据库?写一个通用Adapter吧

  • 对那个数据库进行Query?写一个通用的Query

  • 要传递一些参数?通用参数

  • 要架构参数?通用Builder

  • 对反应进行Map? 通用Data Mapper

  • 处理用户请求? 通用Request

  • 执行整个系统? 通用Executor

有的时候工程师会对此过于着迷。我们会忘记解决商业问题,而是将是将浪费在寻找完美的抽象概念上


我们在设计的时候,总是要试图满足真实世界中不断变化的各种要求。因此,即使我们真的遇上了奇迹,摘到了完美的抽象画概念,它也会有不再适用的那一天,因为真实世界的要求变了。 

4. 过于粗浅的Wrapper


在使用每一个外部库之前,我们都会把它包裹起来。不幸的是,我们所使用的大多数wrapper都非常粗浅。我们在投递功能性和编写好的wrapper之间挣扎。我们的wrapper大多数情况下都与当前的库紧密结合。如果我们在未来改变了所使用的库,它所对应的wrapper也必须要改变。有的时候我们还会把业务逻辑也放在这个wrapper内,这样导致我们即无法得到好的wrapper,也无法得到好的业务解决方案,而是介乎两者之间的某种粘性层。 

现在已经是2016年了,外部库和客户端都已经得到了快速的发展。OSS库就很好,它有着很高的质量,一些优秀的人写了很好的数据库。它们大多数都有着清晰、可测试的API,让我们可以使用一种标准的Initialize — Instrument — Implement模式。 

5. 将特性当做工具使用


盲目的使用特性概念(例如将所有变量变成“private final”、为所有类编写界面等)并不能让代码变得更好。 

去看看Enterprise FizzBuzz吧。它有着体量极大的代码。在微层面上,每一个类都遵循了SOLID原色,使用了各种各样的优秀设计模式和变成技巧。它在CQM工具中获得了极高的代码质量评分。 

5.1. 三明治层


我们来简要说明一下,创建一个结合紧密的反应,并且将其拆分为10或20个三明治曾,每一个单独的层面都需要整体架构来运行。

在过去,我们需要一个连锁反应来实现。A导致B导致C导致D……  

 

而现在,我们还是在用这种方式,只不错我们给一个类都添加了界面/执行,然后将其注入下一个层面,因为我们现在有了SOLID。

 

但是SOLID这样的概念导致了连锁反应和其他OOP概念的滥用。大多数工程师都不知道这些概念是怎么来的,只是在不断的使用。 

6. Adopter依赖综合征


在发现了Generics之后,现在,就连一个简单的“HelloWorldPrinter”都变成了“HelloWorldPrinter<String,Writer>”。

在数据类型如此明显的情况下,我们并不需要使用Generics。

在发现了策略模式后,连“if”条件都变成了一种策略。

为什么?

学会了DSL之后,我们在哪里都在使用DSL。

在用过Mocks之后,我们就对每一个对象进行模拟。

Metaprogramming真好用,我要在任何地方都使用。

这样做并不好。

7. <X>–ity


  • 可配置性

  • 安全性

  • 可扩展性

  • 可维护性

  • 可延伸性

 

实例1:我们来做一个可延展的CMS吧,负责商务的同事可以轻松的添加新的领域。

结果:负责商务的同事从来就没用过。当他们必须要添加新领域的时候,他们也会找来一名开发人员帮他们完成。也许我们需要的只是一个简单的开发者指导。 


实例2:我们来设计一个拥有可配置性的大型数据库层面吧。我们应该拥有只用一个Magic文件就可以切换数据库的能力。

结果:近10年来,我只见过一家公司用过这样的功能。而在切换数据库的时候,那个Maigc文件并没有发挥什么作用。 

实例3:我们来打造一个OAuth系统吧,让软件更具安全性。

结果:如果真的有人要黑我们的系统,他们不会经过OAuth层面,他们随便找一个其他曾的漏洞就黑进来了。

 

8. 内部“发明”


刚开始的时候你会感觉不错。但是今年之后,你的发明就会成为通用资源。例如:

  • 内部库(HTTP, mini ORM/ODM, Caching, Config等)

  • 内部框架(CMS, Event Streaming, Concurrency, Background Jobs, etc)

  • In-house tools (Buildchains, Deployment tools等)

9. 跟随现状


当某个东西按照某种特定方式部署完成之后,所有人都会在其基础上进行开发。没有人会质疑这种现状。只要代码能够工作,我们就默认这种方式为“正确的方式”。 

有的时候现有的方式并不是最简洁的方式,有的东西完全是可以去除的。 

 

10. 糟糕的自我评估


很多次我都见过非常优秀的团队做出糟糕的软件。在看到他们的代码库的时候,我们不禁在想:“怎么回事?这真实那个团队/人做的吗?”

优秀的质量不仅需要技巧,还需要时间。一个优秀的开发者总是会高估自己的能力,给自己定了不切合实际的开发截止日期,导致最终软件呈现的质量让所有人失望。

过分的自信在项目刚刚开始之前就会毁掉产品的最终质量。


米么信息 米么信息 米么信息
分享文章至