代码过度设计,真的有意义吗?

开发 前端
Keep it simple, stupid,保持简单、愚蠢。提醒我们大多数系统,与其变得复杂,保持简单能让系统运行更好。越资深的人,越觉得这大有道理。因为大佬们见识过因为复杂而引发的各种问题。

1、过度设计有意义吗?

看着自己每次根据设计原则及模式的代码重构,虽效果不错,但也自省:如果我的每段代码都这么写,是不是过度设计?把握设计的度,需长久锤炼。行业也总结了很多原则,帮助我们把握设计的度。它们是一种思考方法、一种行为准则。

2、KISS

Keep it simple, stupid,保持简单、愚蠢。提醒我们大多数系统,与其变得复杂,保持简单能让系统运行更好。越资深的人,越觉得这大有道理。因为大佬们见识过因为复杂而引发的各种问题。堆太多功能,调整起来就很费劲:

  • • 有现成库,就不自己写
  • • 能用文本做协议,就别用二进制
  • • 方法越短小精悍越好
  • • 能把一个基本流程打通,软件就能发布,无需那么多功能(MVP)

真是吸引crud boy,但无法指导具体工作。啥叫保持简单,怎么就叫复杂?这都没标准。有人基于自己的理解给具体原则:

3、YAGNI

You aren’t gonna need it,你用不着它。如非必要,勿增功能。软件设计对抗的是需求规模:

  • • 通过努力,让软件在需求规模膨胀之后,依然能平稳发展
  • • 努力控制需求规模

很多需求不需要做。很多产品经理以为很重要的功能实际上是没什么用的。真正重要的功能大约只占20%。做了更多的功能,并不会得到更多的回报,但是,做了更多的功能,软件本身却会不断地膨胀,越难维护。

所以,在现实经常看到一些功能简单的东西不断涌现,去颠覆更复杂东西。如Word强大,但只是个写字工具,重点排版功能都用得少。而Markdown简单地让我们专注写内容,而且简单的几个排版标记在日常沟通中就完全够用。尽量可能不去做不该做的事,从源头堵住问题。

4、DRY

Don’t repeat yourself,不要重复自己。在一个系统中,每一处知识都必须有单一、明确、权威地表述。Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

即不要做cv工程师。这还远远不够,DRY针对的是你对知识和意图的复制:在两个不同地方的两样东西表达形式不同,但表达内容却可能相同。如下打印账户信息:

public void printBalance(final Account account) {
System.out.printf("Debits: %10.2f\n", account.getDebits());
System.out.printf("Credits: %10.2f\n", account.getCredits());
if (account.getFees() < 0) {
System.out.printf("Fees: %10.2f-\n", -account.getFees());
} else {
System.out.printf("Fees: %10.2f\n", account.getFees());
}

System.out.printf(" ----\n");

if (account.getBalance() < 0) {
System.out.printf("Balance: %10.2f-\n", -account.getBalance());
} else {
System.out.printf("Balance: %10.2f\n", account.getBalance());
}
}

这段隐藏一些重复。如对负数的处理显然是复制的,可通过增加一个方法消除:

String formatValue(final double value) {
String result = String.format("%10.2f", Math.abs(value));
if (value < 0) {
return result + "-";
} else {
return result + " ";
}
}

void printBalance(final Account account) {
System.out.printf("Debits: %10.2f\n", account.getDebits());
System.out.printf("Credits: %10.2f\n", account.getCredits());
System.out.printf("Fees:%s\n", formatValue(account.getFees()));
System.out.printf(" ----\n");
System.out.printf("Balance:%s\n", formatValue(account.getBalance()));
}

数字字段格式反复出现,不过,格式与我们抽取出来的方法一致,复用:

String formatValue(final double value) {
String result = String.format("%10.2f", Math.abs(value));
if (value < 0) {
return result + "-";
} else {
return result + " ";
}
}

void printBalance(final Account account) {
System.out.printf("Debits: %s\n", formatValue(account.getDebits()));
System.out.printf("Credits: %s\n", formatValue(account.getCredits()));
System.out.printf("Fees:%s\n", formatValue(account.getFees()));
System.out.printf(" ----\n");
System.out.printf("Balance:%s\n", formatValue(account.getBalance()));
}

打印格式其实也重复,如果我要在标签和金额之间加一个空格,相关的代码都要改,所以,这也是一个可以消除的重复:

String formatValue(final double value) {
String result = String.format("%10.2f", Math.abs(value));
if (value < 0) {
return result + "-";
} else {
return result + " ";
}
}

void printLine(final String label, final String value) {
System.out.printf("%-9s%s\n", label, value);
}

void reportLine(final String label, final double value) {
printLine(label + ":", formatValue(value));
}

void printBalance(final Account account) {
reportLine("Debits", account.getDebits());
reportLine("Credits", account.getCredits());
reportLine("Fees", account.getFees());
System.out.printf(" ----\n");
reportLine("Balance", account.getBalance());
}

重构后:

  • • 改金额打印格式,就去改formatValue
  • • 改标签格式,就去改reportLine

有人说这种调整粒度太小。如你这样感觉,证明你看问题的粒度太大。品味这个修改,与分离关注点和单一职责原则异曲同工:粒度要小。

DRY不局限于写代码:

  • • 注释和代码之间存在重复,可以尝试把代码写得更清晰
  • • 内部API在不同的使用者之间存在重复,可以通过中立格式进行API的定义,然后用工具生成文档、模拟 API 等等
  • • 开发人员之间做的事情存在重复,可以建立沟通机制降低重复;……

都是在试图减少重复,其实也是减少了维护成本。

5、简单设计

Simple Design,提出者Kent Beck,只包含如下规则,后3条规则是重构方向

(1)通过所有测试

保证系统能按预期工作。怎么知道系统按照预期工作,就需要有配套自动化测试,最好能TDD,最根本的还是要懂设计,否则,你的代码就是不可测。

(2)消除重复

正如DRY,你得能发现重复,就要会分离关注点

(3)表达出程序员的意图

编写有表达性的代码,这也需要你对“什么是有表达性的代码”有认识。代码要说明做什么,而不是怎么做

(4)让类和方法的数量最小化

让类和方法的数量最小化,不要过度设计,除非你已看到这必须要做个设计,比如,留下适当扩展点,否则,就不要做。能做出过度设计的前提,是已懂得各种设计,这时才需要用简单设计的标准对自己约束。所谓简单设计,对大多数人并不“简单”。

没有良好设计,代码就没有可测试的接口,TDD就无从谈起。不懂设计,重构就只是简单提取方法,改改名字,对代码的改进相当有限。

简单设计的前提是,把编程基础打牢。片面地追求敏捷实践,而忽视基本功,是舍本逐末。

责任编辑:武晓燕 来源: JavaEdge
相关推荐

2011-08-23 09:00:47

可用性五个九

2016-04-13 10:52:12

2015-04-23 16:21:23

2019-01-24 10:23:58

Web前端密码加密

2016-02-17 09:06:42

代码注释代码规范

2011-09-09 10:31:40

Xen虚拟化linux内核

2022-02-28 22:52:56

混合云工具技术

2022-07-13 17:56:09

Bug率产品经理系数

2021-03-04 13:25:22

Python面向对象代码

2021-02-19 09:45:50

Python面向对象代码

2021-04-06 11:21:50

Python面向对象代码

2014-05-04 10:06:56

数据收集

2024-04-19 11:34:10

数据中心

2020-11-03 10:50:09

代码

2013-05-20 10:09:19

过时应用迁移云计算

2020-06-04 08:05:06

物联网客户见解IOT

2016-02-17 10:01:36

编程代码注释

2014-12-24 10:03:26

融合基础设施

2022-12-12 17:42:38

人工智能预测性维护智能建筑

2021-10-28 15:02:16

OpenHarmony微纳卫星
点赞
收藏

51CTO技术栈公众号