KISS 原则和 YAGNI原则

设计模式专栏:http://t.csdnimg.cn/3a25S

目录

1.引言

2.代码并非行数越少越简单

3.代码复杂不一定违反 KISS 原则

4.如何写出满足 KISS 原则的代码

5.YAGNI原则和 KISS 原则的区别


1.引言

        KISS原则的英文描述有3种版本:Keep It Simple and Supid、 keep It Short and Simple、Keep It Simple and Straightforward。其实,它们要表达的意思差不多,即“尽量保持简单”。

        KISS原则是一个“万金油”一样的设计原则,可以应用在诸多场合。它不仅经常用来指导软件开发,还经常用来指导系统设计、产品设计等,如冰箱、建筑和手机的设计等,本书讲解的是代码设计,因此,接下来,我们重点讲解如何在程序开发中应用KISS 原则。

        我们知道,代码的可读性和可维护性是衡量代码质量的两个重要标准。而KISS原则就是保持代码可读和可维护的重要手段。代码足够简单,也就意味着容易读懂,bug比较难影藏,即便出现 bug,修复也比较简单。

        不过,KISS原则只是告诉我们,要保持代码“简单”,但并没有讲什么样的代码才算得上“简单”,更没有给出明确的方法来指导如何开发“简单”的代码。因此,KISS 原则虽然简单但不太容易落地。

2.代码并非行数越少越简单

        在下面的示例代码中,我们使用3种方式实现同一功能:检查输入的字符串ipAddress是否是合法的P地址。一个合法的P地址由4个数字组成,并且通过“.”进行分隔。每个数字的取值范围是 0~255(第一个数字比较特殊,不允许为0)。对比下面3段代码,读者认为哪一段代码符合KISS 原则呢?

//第一种实现方式:使用正则表达式
public boolean isValidIpAddressVl(String ipAddress)
{if(StringUtils.isBlank(ipAddress)){return false;}String regex = "^(1\\d{2)|2[0-4]\\d125[0-5]|[1-9]\\dl[1-9])\\."+"(1\\d(2}12[0-4]\\d|25[0-5]|[1-9]\\dl\\d)\\."+"(1\\d{2)12[0-4]\\d125[0-5]1[1-9]\\dl\\d)\\."+"(1\\d{2)12[0-4]\\d125[0-5]1[1-9]\\dl\\d)$";return ipAddress.matches(regex);
}//第二种实现方式:使用现成的工具类
Public boolean isValidIpAddressV2(String ipAddress)
{    if (Stringutils.isBlank(ipAddress))return false;String[] ipUtits = StringUtils.split(ipAddress,'.');if(ipUnits.length!=4){return false;}for(int i=0;i<4;++i){int ipUnitIntValue;try{            ipUnitIntValue = Integer.parseInt(ipUnits[i]);catch(NumberFormatException e){return false;}it (ipUnitIntValue <0 || ipUnitIntValue > 255){return false;}if(i == 0 && ipUnitIntValue== 0){return false;}}return false;
}//第三种实现方式:不使用任何工具类
public boolean isValidIpAddressV3(String ipAddress)
{char[] ipChars = ipAddress.toCharArray();int length = ipChars.length;int ipUnitIntValue = -l;boolean isFirstUnit = true;int unitsCount=0;for(int i=0;i<length;++i){char c = ipChars[i];if(c==''){if(ipUnitIntValue < 0 || ipUnitIntValue > 255) return false; if(isFirstUnit  && ipUnitIntValue ==0)return false;if(isFirstUnit )isFirstUnit = false;ipUnitIntValue=-l;unitsCount++;continue;}if (c < '0' || c >'9'){return false;if(ipUnitIntValue=-1)ipUnitIntValue =0;ipUnitIntValue=ipUnitIntValue*10+(c-'0');}if (ipUnitIntValue<0 && ipUnitIntValue >255)return false;if(unitsCount !=3)return false;return true;
}

        第一种实现方式利用正则表达式,3行代码就解决了问题。第一种实现方式的代码行数最少,那么是否符合KISS原则呢?答案是否定的。虽然第一种实现方式的代码行数最少,看似简单,但使用了比较复杂的正则表达式,而想要写出完全没有bug的正则表达式是很有挑战性的。对于不熟悉正则表达式的人,看懂并维护含有正则表达式的代码是比较困难的。基于正则表达式的实现方式导致代码的可读性和可维护性变差,因此,从KISS原则的设计初衷(提代码的可读性和可维护性)来看,这种实现方式并不符合 KISS原则。

        第二种实现方式使用StringUtils类和 Integer 类提供的一些现成的工具函数来处理IP地址字符串。第三种实现方式不使用任何工具函数,而是通过逐一处理IP地址中的字符来判断是否合法。从代码行数上来说,第二种实现方式和第三种实现方式的代码行数差不多。但第三种实现方式比第二种实现方式更有难度,更容易产生bug。从可读性来说,第二种实现式的代码逻辑更清晰、更好理解。相比来说,第二种实现方式更“简单”,符合KISS 原则。 虽然第三种实现方式稍微复杂,但其性能要比第二种实现方式高一些。从性能的角度说,选择第三种实现方式是不是更好呢?在回答这个问题之前,我们先解释一下为什么第三种实现方式的性能更高一些。一般来说,工具类的功能是通用和全面的,因此,在代码实现面、需要兼容和处理更多的情况、执行效率就会受到影响。而第三种实现方式,完全是自己操作底层字符,只针对IP地址这一种输入格式,没有其他不必要的处理逻辑,因此,在执行率方面,这种类似定制化的处理代码肯定比通用的工具类高。

        尽管第三种实现方式的性能更高,但我们还是倾向于选择第二种实现方式,因为第三种实现方式上实际是过度优化。除非isValidIpAddress函数是影响系统性能的瓶颈代码,否则,这样优化的投入产出比并不高,反而增加了代码实现的难度、牺牲了代码的可读性,而性能上的提升并不明显。

3.代码复杂不一定违反 KISS 原则

        上文我们提到,代码并非行数越少越简单,因为还要考虑逻辑复杂度、实现难度和代码的可读性等。如果一段代码的逻辑复杂、实现难度大、可读性也不太好,是不是一定违反KISS原则呢?在回答这个问题之前,我们先来看下面这段代码(来自《数据结5之美》中 KMP 算法的代码实现)。

//P算法:a、b分别是主串和模式串,n、m分别是主串和模式串的长度
public static int kmp(char[]a, int n, char[]b, int m){int[] next= getNexts(b,m);int j= 0;for(int i=0;i<n; ++i){while(j>0 && a[i] != b[j]){j=next[j-1]+ 1;}if(a[i]== b[j]){++j;}if(j==m){return i-m +l;}}return -l;
}
private static int[] getNexts(char[]b, int m){int[] next = new int[m];next[0]=-1;int k=-1;for(int i=1;i<m; ++i){while(k!=-1 && b[k +1]!=b[i]){k= next[k];}if (b[k + 1] == b[i]){++k;}next[i] = k;}return next;
}  

        上面这段代码逻辑复杂、实现难度大和可读性差,但它并不违反KIS原则,KMP算法以高效著称,当需要处理长文本字符串匹配问题(如几百MB大小的文本内容的匹配),或者字符串匹配是某个产品的核心功能(如Vim、Word等文本编辑中的文本查找),抑或字符串匹配算法是系统性能瓶颈时,我们就应该选择KMP算法。而KMP算法本身具有逻辑复杂、实现难度大和可读性差特点,因此,使用复杂的算法解决复杂的问题,并不违反KISS原则。

        不过,平时的项目开发涉及的字符串匹配问题大多针对较小的文本,在这种情况下,直接调用编程语言提高的现成的字符串匹配函数即可。如果是KMP算法实现较小文本的字符串匹配,就违反KISS原则了。也就是说,对于同一段代码,在某个应用场景下满足KISS原则,换一个应用场景后可能就不满足 KISS 原则了。

4.如何写出满足 KISS 原则的代码

        关于如何写出满足 KISS 原则的代码,前面已经讲了一些方法,这里总结一下。

        1)慎重使用过于复杂的技术来实现代码,如复杂的正则表达式、编程语言中过于高级的语法等。

        2)不要“重复造轮子”,首先考虑使用已有类库。根据作者的经验,如果自己实现类库那么产生 bug 的概率更高,维护成本也更高。

        3)不要过度优化。尽量避免使用一些“奇技淫巧”(如使用位运算代替算术运算、使用复杂的条件语句代替 if-else 等)来优化代码。

5.YAGNI原则和 KISS 原则的区别

        当YAGNI(You Ain’t Gonna Need It)原则用在软件开发时,其含义是: 不要去设计当前用不到的功能;不要去编写当前用不到的代码。实际上,这条原则的核心思想是:不要过度设计。和 KISS 原则一样,YAGNI原则也称得上“万金油”一样的设计原则。

        例如,某系统暂时只使用 Redis来存储配置信息,以后可能会用到ZooKeeper。根据 YAGNI原则,在未用到ZooKeeper之前,我们没必要提前编写这部分代码。当然,这并不是说就不需要考虑代码的扩展性了。我们还是有必要预留扩展点,在需要引入ZooKeeper时,能够在不改太多代码的情况下完成扩展。

        又如,不要在项目中提前引入不需要依赖的开发包。Java程序员经常使用Maven或Grade 管理项目依赖的类库,我们发现,有些程序员为了避免开发中类库的缺失而频繁地修改Maven或 Gradle 配置文件,提前向项目里引入大量常用的类库。实际上,这种做法违反YAGNI原则。

        从刚才的分析可以看出,YAGNI原则与KISS原则并非一回事。KISS原则讲的是“如何做(尽量保持简单),而 YAGNI原则讲的是“要不要做”(当前不需要的,就不要做)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/805821.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenHarmony开发技术:【国际化】实例

国际化 如今越来的越多的应用都走向了海外&#xff0c;应用走向海外需要支持不同国家的语言&#xff0c;这就意味着应用资源文件需要支持不同语言环境下的显示。本节就介绍一下设备语言环境变更后&#xff0c;如何让应用支持多语言。 应用支持多语言 ArkUI开发框架对多语言的…

Autowired和Resource的关系?

相同点 对于下面的代码来说&#xff0c;如果是Spring容器的话&#xff0c;两个注解的功能基本是等价的&#xff0c;他们都可以将bean注入到对应的field中 Autowired private Bean beanA; Resource private Bean beanB; 不同点 byName和byType匹配顺序不同 Autowired在获取…

TypeScript—详解、小案例(配合源代码)

简介&#xff1a;TypeScript是微软开发的 JavaScript 的超集&#xff0c;TypeScript兼容JavaScript&#xff0c;可以载入JavaScript代码然后运行。TypeScript与JavaScript相比进步的地方 包括&#xff1a;加入注释&#xff0c;让编译器理解所支持的对象和函数&#xff0c;编译器…

Web路径专题

文章目录 1.资源定位1.前置条件上下文路径设置 2.上下文路径介绍重点说明 3.资源定位方式资源路径 上下文路径 资源位置a.html定位C.java定位 4.浏览器和服务器解析的区别1.浏览器解析/&#xff08;地址变化&#xff09;2.服务器解析/&#xff08;地址不变&#xff09; 5.带/…

备份工具--kopia

kopia 备份测试 安装minio wget https://dl.min.io/server/minio/release/linux-amd64/minio 创建目录 mkdir -p /data/myapp/minio mkdir -p /data/minidata 配置启动 cat start_minio.sh nohup /data/myapp/minio/minio server --console-address :“9090” /data/minidata…

数据流重定向

数据流重定向 标准输入 0 标准输出 1 标准错误输出 2 输出 > 标准输出 1>标准错误输出 2>标准输出标准错误输出 2>&1 或 &> 输入 < 标准输入 0<eof输入 cat > catfile <<“eof” 双向重定向 tee [command] | tee -a [file] [comma…

Spring和Spring MVC和MyBatis面试题

面试题1&#xff1a;请简述Spring、Spring MVC和MyBatis在整合开发中的作用&#xff1f; 答案&#xff1a; Spring&#xff1a;是一个轻量级的控制反转&#xff08;IoC&#xff09;和面向切面&#xff08;AOP&#xff09;的容器框架。它提供了强大的依赖注入功能&#xff0c;…

git学习 1

打开自己想要存放git仓库的文件夹&#xff0c;右键打开git bush&#xff0c;用git init命令建立仓库 用 ls -a(表示全都要看&#xff0c;包括隐藏的)可以看到git仓库 也可以用 git clone 接github链接&#xff08;点code选项里面会给链接&#xff0c;结尾是git的那个&#xf…

程序员开发指南-- reference

01. 项目介绍 为开发人员分享快速参考备忘清单【速查表】 GitHub - jaywcjlove/reference: 为开发人员分享快速参考备忘清单(速查表) 02. 部署Quick Reference网站 docker pull wcjiang/reference docker run --name reference --rm -d -p 9667:3000 wcjiang/reference:lat…

阿里云ACK k8s集群迁移

1、创建k8s集群 阿里云ACK创建 2、创建所需的第三方插件 ACK ingress创建 3、导出原有ACK集群配置 包含deployment、service、ingress、PersistentVolumeClaim 执行命令 kubectl get deployment,service,secret,ingress,PersistentVolumeClaim -n <namespace_name> -o y…

OpenHarmony南向开发实例:【智能可燃气体检测系统】

样例简介 本项目是基于BearPi套件开发的智能可燃气体检测Demo&#xff0c;该系统内主要由小熊派单板套件和和MQ5可燃气体检测传感器组成。 智能可燃气体检测系统可以通过云和手机建立连接&#xff0c;可以在手机上控制感应的阈值&#xff0c;传感器感知到的可燃气体浓度超过阈…

【ISO体系认证】云服务信息安全管理体系,一起来看看吧!

云服务信息安全管理体系&#xff08;简称“CSISMS”&#xff09;&#xff0c;以ISO/IEC 27017:2015为认证依据。ISO/IEC 27017标准是建立在ISO/IEC 27001信息安全管理体系框架和ISO/IEC 27002作为最佳实践控制设置的坚实基础之上&#xff0c;通过ISO/IEC 27017标准认证&#xf…

C++ | Leetcode C++题解之第12题整数转罗马数字

题目&#xff1a; 题解&#xff1a; const string thousands[] {"", "M", "MM", "MMM"}; const string hundreds[] {"", "C", "CC", "CCC", "CD", "D", "DC&qu…

azkaban的写法

先创建一个.job文件和一个.sql文件 sql语法写到一个test名字的文件里&#xff0c;之后job写法如下&#xff1a; typecommand commandhive -f test6.sql 一定要严格写&#xff0c;不管是字母还是空格&#xff0c;单引号中就是sql文件的名字 然后将它们一块打包&#xff0c;启动…

ubuntu系统逻辑卷Logical Volume扩容根分区

Linux LVM详解 https://blog.csdn.net/qq_35745940/article/details/119054949 https://blog.csdn.net/weixin_41891696/article/details/118805670 https://blog.51cto.com/woyaoxuelinux/1870299 LVM&#xff08;Logical Volume Manager&#xff09;逻辑卷管理&#xff0c…

Go语言开发小技巧易错点100例(十四)

往期回顾&#xff1a; Go语言开发小技巧&易错点100例&#xff08;一&#xff09;Go语言开发小技巧&易错点100例&#xff08;二&#xff09;Go语言开发小技巧&易错点100例&#xff08;三&#xff09;Go语言开发小技巧&易错点100例&#xff08;四&#xff09;Go…

贪心算法|452.用最少数量的箭引爆气球

力扣题目链接 class Solution { private:static bool cmp(const vector<int>& a, const vector<int>& b) {return a[0] < b[0];} public:int findMinArrowShots(vector<vector<int>>& points) {if (points.size() 0) return 0;sort(p…

rk3588开发板上安装ssh服务

目的&#xff1a;实现远程访问和控制&#xff0c;其他主机远程控制rk3588 方法及操作步骤&#xff1a; 1&#xff09;安装&#xff1a;sudo apt install openssh-server 2&#xff09; 查看运行状态 sudo systemctl status ssh 其它主机远程连接该开发板的ip和端口22即可

urwid,一个好用的 Python 库!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个好用的 Python 库 - urwid。 Github地址&#xff1a;https://github.com/urwid/urwid Urwid 是一个功能强大的 Python 库&#xff0c;用于创建基于文本的用户界面&#xf…

[23年蓝桥杯H题] 合并石子

问题描述 在桌面从左至右横向摆放着 N 堆石子。每一堆石子都有着相同的颜色&#xff0c;颜 色可能是颜色 0 &#xff0c;颜色 1 或者颜色 2 中的其中一种。 现在要对石子进行合并&#xff0c;规定每次只能选择位置相邻并且颜色相同的两堆 石子进行合并。合并后新堆的相对位置保…