首页 存档 技术 查看内容

10个现代软件开发过度设计上的错误

2018-3-30 13:00 |来自: 互联网 332 0

摘要:   有些事情总是会增加的:两颗星星之间的距离,宇宙中的熵值,还有客户对软件需求!很多杂志都说不要过度设计,但是并没说为什么,这里列举了十条清楚的观点。 重要提醒: 以下的一些观点像“不要滥用泛型”常常被 ...

  有些事情总是会增加的:两颗星星之间的距离,宇宙中的熵值,还有客户对软件需求!很多杂志都说不要过度设计,但是并没说为什么,这里列举了十条清楚的观点。

重要提醒: 以下的一些观点像“不要滥用泛型”常常被误解为“不要使用泛型”,“不要创造不必要的包装类”被认为“不要用包装类”等等。我仅仅是在讨论过度设计而不是在讨论要如何养成好的代码风格。

  1. 工程师比客户更聪明

  工程师通常认为自己是最聪明的因为万物都是他们创造的。这是使我们过度设计的第一个错误。如果我们计划100件事情,商人通常会提出我们从来没想过的第101事情。如果我们解决了1000个问题,他们将会反馈10,000个问题。我们以为所有都在我们的掌控之下,然而实际上我们连我们具体的方面都不知道。

  我们以为所有都在我们的掌控之下,然而实际上我们连我们具体的方面都不知道。

  在我15年的开发生涯中,我从未看到一个客户减少软件功能的需求,他们的想法通常会偏离原来的初衷,对于客户这是可以理解的,这也不是客户的错。

TL;DR客户总是对的。

  Tip: 如果你没有时间读本文的一下部分,这一点其实已经足够了。


  2. 业务功能是可以重用的

  当客户提出越来越多的功能需求(这是我们都知道将会发生的)我们通常做出这样的反应:

  我们试着尽可能地分组和概括逻辑。这就是为什么大多数MVC模型的系统到最后就剩下臃肿的模型或者臃肿的控制器。但是正如我们早已知道的,客户的需求只会增加,不会减少。

  所以替代的,我们应该这样反应:

  在系统中,共享功能的重用和抽象往往随着时间的推移而趋于稳定。当功能增多的时候系统会保持稳定或者会相对的轻量。如果不这么做的话,系统很可能由于太过臃肿而崩溃。(更可能会被重写).

  举例: 我们为以前的客户建立了一个用户配置文件系统。起初我们认为功能需求与以前的很相似的,所以采用了重用的CRUD(增加(Create)、读取查询(Retrieve)、更新(Update)和删除(Delete))控制器。但是到最后却产生13种不同的开始流程初始的连接,首次注册的信息填写,编辑信息等等,这使得重用的组件根本起不了作用。相似的,顺序视图和顺序编辑流与实际的排序流本质上是不同的.。

  在水平划分业务功能的时候先试着垂直的划分。在各种情况下考虑隔离服务,基于中继的服务,特定于语言的模块等等。这也对从一个功能转换到另一个功能十分方便。否则的话当系统的一部分发生改变的时候将会系统将会变得很复杂。

TL;DR功能的隔离好于功能间的组合

  Tip: 在你写的代码中找一个面向外部的功能(Endpoint/Page/Job等)看看其他人要理解多少个选择语句?


  3. 一切都是通用的

  (有时候这一点与前一点可以结合,但是它仍可以应用于独立的项目)

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

  • 查询数据库? 通用的Query

  • 传递参数? 通用的Params

  • 创建参数? 通用的Builder

  • 映射返回值? 通用的Data Mapper

  • 处理用户请求? 通用的 Request

  • 执行整个事件? 通用的 Executor

  • 等等

  有点工程师就是这样,不解决业务上出现的问题而要浪费时间去寻找一个完美的抽象类,答案是非常简单的。

  什么是完美的抽象类?

  设计总是为了解决不断变化的现实世界的需求。因此即使我们奇迹般的找了一个完美的抽象类,它仍然有一个有效期的标签 #1The House wins in the end. 今天最好的设计其实是不设计,这有一篇震惊的文章 写容易被删除的代码,而不是可拓展的.

TL;DR复制比错误的抽象更好

  相反的,复制有时是正确的抽象。当我们看到系统的某些部分具有相似的代码,一个好的抽象就出现了 复制暴露了许多的使用情况并使得界限更加清晰。

  Tip: 在服务间共用的抽象有时会导致 微型服务最终变成分散的大石柱.


  4. 表面的封装

这是在整篇文章中最困难的一个观点。提醒一下我们正在讨论过度设计。

  在使用额外的库之前希先封装它,不幸的是大多数我们写的封装类都是非常表面的,我们在提供功能性和创建一个好的封装类之间徘徊,所以大多数我们写的封装类都与底层库十分相似(有些情况下是1:1的镜像关系,而有时候以10倍的功耗来完成原始库中1/10的功能)如果我们在不久对底层库进行改动,这个库的封装类到后来也不得不更改。有时我们也将业务逻辑融入到封装类中,使它既不是一个好的封装类也不是一个好的业务代码,而是处于在两者之间的层次。

  这是2016. 外部库和我们的客户都有很大的提升。开源库十分流行的,它们被十分厉害的人专门所编写,有着高质量,可测试的代码。有更加清晰,可测试,更高效的API,允许我们去按照初始化组装(Instrument)实现的步骤去构建。

TL;DR封装是一个异常,而不一个规范,不要给一个好的库进行封装。

  Tip: 创建一个模糊的封装可不是开玩笑的。封装一个库的想法来源于可配置这一想法,并将配置过后的具体实现隐藏起来。


  5. 使用质量检测工具

  盲目使用高质量代码的规范(像把所有的变量改为 “private final”,为所有的类写一个借口, 等等) 并没有把代码变得更好

  查看 企业级编程 (or Hello World). 它有大量的代码。在微观层次中每一个类都遵循SOLID原则,使用各种设计模式(工厂模式,建造者模式,策略模式等)以及编程技巧(泛型,枚举等),从CQM工具中它们都获得了很高的代码质量评分。

TL;DR总是后退一步来宏观的看待问题

  相反的,自动化CQM工具擅长于跟踪测试覆盖率,而并不能告诉我们是否我们正在测试一个正确的东西。一个基准工具能够跟踪性能表现,但是它不能告诉我们程序是否是并行执行的还是顺序执行的。只有人才能解决这些问题。

  5.1. 划分层次

  我们采取简洁,紧密的动作来把程序划分为10或20个层次,它们之中的任何一个层都离不开整体而独立存在。这是由于我们想要遵循“测试代码”或“单一责任原则”的概念。

  在过去这由继承来实现 A extends B extends C extends D

  总共有200层

  现在人们做着相似的事情,让每一个类都有一个接口来继承同时把它注入到下一层中,就是为了SOLID原则。

  2016年采用SOLID原则的层次 (没有写出处的必要, 图片由Keynote制作)

  SOLID原则的提出是为了防止继承和其他OOP概念被滥用,而大多数开发人员都不知道这些概念是哪或为什么来的,仅仅是错误的遵照。

TL;DR原则是为了转变观念,不是要像工具一样盲目的使用。

  学习一种不同的语言然后尝试以一种不同的思维去做事。这一才会成为一个更好的开发者。这些概念在新的语言当中可能根本不起作用 我们不应该以遵循某种原则的名义来分割某个清晰的设计


  6. 过度使用

过度使用泛型. 现在一个简单的 “HelloWorldPrinter” 都会变成 “HelloWorldPrinter

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部