设计模式之美
王争
前Google工程师,《数据结构与算法之美》专栏作者
立即订阅
17796 人已学习
课程目录
已更新 23 讲 / 共 100 讲
0/6登录后,你可以任选6讲全文学习。
开篇词 (1讲)
开篇词 | 一对一的设计与编码集训,让你告别没有成长的烂代码!
免费
设计模式学习导读 (3讲)
01 | 为什么说每个程序员都要尽早地学习并掌握设计模式相关知识?
02 | 从哪些维度评判代码质量的好坏?如何具备写出高质量代码的能力?
03 | 面向对象、设计原则、设计模式、编程规范、重构,这五者有何关系?
设计原则与思想:面向对象 (11讲)
04 | 理论一:当谈论面向对象的时候,我们到底在谈论什么?
05 | 理论二:封装、抽象、继承、多态分别可以解决哪些编程问题?
06 | 理论三:面向对象相比面向过程有哪些优势?面向过程真的过时了吗?
07 | 理论四:哪些代码设计看似是面向对象,实际是面向过程的?
08 | 理论五:接口vs抽象类的区别?如何用普通的类模拟抽象类和接口?
09 | 理论六:为什么基于接口而非实现编程?有必要为每个类都定义接口吗?
10 | 理论七:为何说要多用组合少用继承?如何决定该用组合还是继承?
11 | 实战一(上):业务开发常用的基于贫血模型的MVC架构违背OOP吗?
12 | 实战一(下):如何利用基于充血模型的DDD开发一个虚拟钱包系统?
13 | 实战二(上):如何对接口鉴权这样一个功能开发做面向对象分析?
14 | 实战二(下):如何利用面向对象设计和编程开发接口鉴权功能?
设计原则与思想:设计原则 (6讲)
15 | 理论一:对于单一职责原则,如何判定某个类的职责是否够“单一”?
16 | 理论二:如何做到“对扩展开放、修改关闭”?扩展和修改各指什么?
17 | 理论三:里式替换(LSP)跟多态有何区别?哪些代码违背了LSP?
18 | 理论四:接口隔离原则有哪三种应用?原则中的“接口”该如何理解?
19 | 理论五:控制反转、依赖反转、依赖注入,这三者有何区别和联系?
20 | 理论六:我为何说KISS、YAGNI原则看似简单,却经常被用错?
不定期加餐 (2讲)
加餐一 | 用一篇文章带你了解专栏中用到的所有Java语法
加餐二 | 设计模式、重构、编程规范等相关书籍推荐
设计模式之美
登录|注册

20 | 理论六:我为何说KISS、YAGNI原则看似简单,却经常被用错?

王争 2019-12-18
上几节课中,我们学习了经典的 SOLID 原则。今天,我们讲两个设计原则:KISS 原则和 YAGNI 原则。其中,KISS 原则比较经典,耳熟能详,但 YAGNI 你可能没怎么听过,不过它理解起来也不难。
理解这两个原则时候,经常会有一个共同的问题,那就是,看一眼就感觉懂了,但深究的话,又有很多细节问题不是很清楚。比如,怎么理解 KISS 原则中“简单”两个字?什么样的代码才算“简单”?怎样的代码才算“复杂”?如何才能写出“简单”的代码?YAGNI 原则跟 KISS 原则说的是一回事吗?
如果你还不能非常清晰地回答出上面这几个问题,那恭喜你,又得到了一次进步提高的机会。等你听完这节课,我相信你很自然就能回答上来了。话不多说,让我们带着这些问题,正式开始今天的学习吧!

如何理解“KISS 原则”?

KISS 原则的英文描述有好几个版本,比如下面这几个。
Keep It Simple and Stupid.
Keep It Short and Simple.
Keep It Simple and Straightforward.
不过,仔细看你就会发现,它们要表达的意思其实差不多,翻译成中文就是:尽量保持简单。
KISS 原则算是一个万金油类型的设计原则,可以应用在很多场景中。它不仅经常用来指导软件开发,还经常用来指导更加广泛的系统设计、产品设计等,比如,冰箱、建筑、iPhone 手机的设计等等。不过,咱们的专栏是讲代码设计的,所以,接下来,我还是重点讲解如何在编码开发中应用这条原则。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《设计模式之美》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(42)

  • 辣么大
    很好奇这三个方法运行效率的高低。测了一下争哥给的代码的执行效率,结果正如争哥文章说,第三个是最快的。
    方法一(正则)< 方法二 < 方法三

    正则就真的这么不堪么?效率如此之低?其实不然。

    Java中正则的最佳实践是:
    用于校验和匹配的正则表达式使用时需要预先compile,在类中写做静态变量(经常会重用),这样可以提高效率。Pattern.compile(IP_REGEXP)

    优化正则后的效率如何呢?
    方法一(正则)< 方法二 < 方法一(正则改进后)< 方法三

    测试参数设置:每个方法执行100万次。
    实验结果:
    方法一:2.057s
    方法一优化:0.296s 提前编译正则
    方法二:0.622s
    方法三:0.019s
    有兴趣的小伙伴看看代码,欢迎一起讨论!https://github.com/gdhucoder/Algorithms4/blob/master/designpattern/u20/TestPerformance.java

    参考:
    https://stackoverflow.com/questions/1720191/java-util-regex-importance-of-pattern-compile
    2019-12-18
    5
    39
  • 失火的夏天
    开发中的重复造轮子,这东西怎么说呢。我认为这句话是对公司来说的,但是对自己来说,重复造轮子是有必要的。就好比之前的数据结构和算法,那也是所有轮子都有啊,为什么还要自己写响应代码。这个问题在另一个专栏都说烂了,这里也不再赘述了。

    光说不练假把式,轮子用不用的好,自己了解的深入才知道。我们读书的时候,用数学定理去解题,也是在一些已知条件下才能用这个定理。不能上来就套定理,而是要分析是否满足使用情况。只有吃透定义和原理,才能更好的使用轮子。

    开发中也一样,我们要排查各种各样的问题,如果轮子内部出了问题,对轮子原理实现都不了解的,怎么排查问题。怎么知道用那种轮子是最好的呢。而且还会存在改造轮子的情况,轮子不满足我们特定的需求,那也是吃透了才能改的动。

    总之,轮子这东西,对公司来说,不要重复,对自己来说,要多去理解,多动手。总不希望自己就是个调包侠吧
    2019-12-18
    23
  • 李小四
    设计模式_19
    今天的内容有一些哲学味道,让我联想到奥卡姆剃刀原理:
    如无必要,勿增实体。

    用同事不懂的技术,增加了整个团队的理解成本;重复造轮子和过度优化,大多数情况下带来的便利小于增加的成本;
    不要写炫技的代码,就像杜峰(CBA广东队教练)说的:“如果没有目的,就不要运球。(因为运球就可能丢球)”,降低出错的概率是一个数学问题,它能够真实得提高软件质量。

    回到作业,同上:
    只有必须造轮子时,才要造轮子。
    那什么又是必须呢?
    - Vim如果不用KMP,恐怕就没有人用了。
    - MySql的性能(即将)已经不能满足阿里的业务量
    - 微信作为国民应用,需要解决各种弱网络下尽可能收发消息。
    ...
    2019-12-18
    1
    7
  • Ken张云忠
    你怎么看待在开发中重复造轮子这件事情?
    轮子:供上层业务应用使用的基础组件.
    造轮子:设计并实现基础组件.
    重复造轮子:重新设计实现一套新的组件.
    开发中重复造轮子:
    对于个人可以有深度度地提升对业务与技术认知的理解,还可以提升设计与动手能力,由于掌握了更多细节的知识,以后对于这类问题的排查定位及处理是有益处的.
    对于技术团队,重复造出的轮子多了日后就需要有更多的人手和精力维护各个轮子,使轮子的维护成本变高;在使用方面,团队的每个成员为了能够正确的使用轮子就需要花费精力去熟悉各个轮子的特征.
    什么时候要重复造轮子?
    新的业务场景中原来的轮子不再合用,并且改造的成本高于重新建造的成本.比如原有业务量不大对于性能要求一般时,旧轮子足够满足;但随着业务的迅猛增长,对于性能提出明确苛刻的要求,就可以考虑重新建造新轮子了.
    什么时候应该使用现成的工具类库、开源框架?
    业务发展的初中期阶段时应该使用.这个阶段业务需求一般比较通用且对性能要求也不高,这时的业务与技术的特点就是要快,快速响应业务占领市场.
    但发展到一定规模,性能成为了制约业务发展的瓶颈,拿来主义已经不能满足业务的更高要求了,就必须要动手建造适合自身业务需求的特定轮子.
    2019-12-18
    5
  • 再见孙悟空
    很早就知道 kiss 原则了,以前的理解是代码行数少,逻辑简单,不要过度设计这样就符合 kiss 原则。虽然知道这个原则,但是却没有好好在实践中注意到,导致写的代码有时候晦涩难懂,有时候层层调用,跟踪起来很繁琐。看完今天的文章,理解更深了,代码不仅是给自己看的,也是给同事看的,并且尽量不自己造轮子,使用大家普遍知道的技术或方法会比炫技好很多。
    至于另一个原则,你不需要它这个实际上做的还是不错的。
    2019-12-18
    4
  • 编程界的小学生
    我觉得如果开源类库完全能满足需求的话,那完全没必要造轮子,如果对性能有要求,比如类库太复杂,想要简单高效的,那可以造个轮子,比如我认为shiro也是spring security的轮子,他简化了很多东西,小巧灵活。还有就是觉得类库能满足需求但是相对于当前需求来讲不够可扩展,那也可以采取类库思想造一个全新的轮子来用。
    2019-12-18
    3
    3
  • 黄林晴
    对工作上重复造轮子,没有必要,因为讲究效率问题,别人不会管你实现的功能是复制粘贴的,还是自己实现的,能正常使用就ok,对于自己来说也没必要盲目造轮子,不要造大轮子,除非你觉得你造的轮子可以碾压现有的,造一些小轮子,使用别的轮子的思想和设计还是有些用处的。
    2019-12-18
    2
  • 小毅
    “不要使用同事可能不懂的技术来实现代码”这一条我觉得是可以值得商榷的~ 比如在项目中引入新技术就可能会违反这一条,我觉得关键点在于这个新技术是否值得引入?新技术是否可以在团队中得到推广?

    有时候,在code review看到不理解的新技术时,其实刚好也是可以触发讨论和学习,如果只是单纯的不去使用,很容易造成整个技术团队停滞不前。
    2019-12-18
    1
  • 下雨天
    一.什么时候要重复造轮子?
    1. 想学习轮子原理(有轮子但是不意味着你不要了解其原理)
    2. 现有轮子不满足性能需求(轮子一般会考虑大而全的容错处理和前置判断,这些对性能都有损耗)
    3. 小而简的场景(比如设计一个sdk,最好不宜过大,里面轮子太多不易三方集成)
    4.定制化需求

    二.什么时候应该使用现成的工具类库、开源框架?
    1.第一条中提到的反面情况
    2. 敏捷开发,快速迭代,需求急的场景
    3. 轮子比自己写的好,BUG少,设计好
    4. KISS原则
    2019-12-18
    1
  • Jackey
    觉得大厂才有人力来重复造轮子,但也要符合业务场景。在小公司需求都做不完的情况下重复造轮子就是浪费资源。最后,最好的造轮子情景应该是自己瞎折腾吧哈哈哈
    2019-12-19
  • 拖鞋党副长
    老师,以java为例,什么样的写法可以被称为不建议使用的过于高级的语法呢
    2019-12-19
  • Kang
    打卡
    2019-12-19
  • jaryoung
    轮子不能满足需求的时候。能满足需求的时候不需要重复造轮子,拿字符串判空来说,我们有需要每个项目都自己写一个?个人觉得没有太大必要
    2019-12-19
  • 小先生
    如果简单的拓展无法很好满足需求,可能还是自己参考轮子的设计思想,自己重复造一个比较好。

    基本上还是开发效率上的考量
    2019-12-19
  • 小先生
    那请问像正则表达式这样的东西是不是就没有用武之地?
    2019-12-19
  • Pismery
    争哥好,想请问一个问题,文中说到不要写同事可能不懂的技术实现,这该如何权衡呢;
    对于 Java 8 的 lambda 表达式,我认为这样的代码会更为直观;可是由于同事都习惯使用存储过程,Java 7 的语法糖;

    是否因为团队大部分人都不使用 lambda,就应该在项目中放弃使用呢?
    2019-12-19
  • AaronYu
    争哥的判断 IPV4 地址是否合法,不适用工具类的方法判断这种 IP 地址:172.16.254.01 为 true,实际上应该是 false。我做了一点改动:
     public boolean isValidAddressV3(String address) {
            char[] ipChars = address.toCharArray();
            int unitsCount = 0;
            int ipUnitInitValue = -1;
            boolean isUnitFirst = true;

            for(int i = 0; i < ipChars.length; i++) {
                char c = ipChars[i];
                if(c == '0' && i == 0) return false;

                if(c == '.') {
                    if(ipUnitInitValue < 0 || ipUnitInitValue > 255) return false;
                    /*if(isUnitFirst && ipUnitInitValue == 0 ) return false;
                    if(isUnitFirst) isUnitFirst = false;*/
                    ipUnitInitValue = -1;
                    unitsCount++;
                    continue;
                }
                if(c < '0' || c > '9') return false;
                if(c == '0' && i+1 < ipChars.length && ipChars[i+1] >= '0' && ipChars[i+1] <= '9') return false;
                // 如果以 0 开头后面的数字不能跟上 0 -9 之内的数字。
                if(ipUnitInitValue == -1) ipUnitInitValue = 0;
                ipUnitInitValue = ipUnitInitValue * 10 + (c - '0');
            }
            if(ipUnitInitValue < 0 || ipUnitInitValue > 255) return false;
            if(unitsCount != 3) return false;
            return true;

        }
    另外送上 leetcode 上判断 IP 地址题目一道:https://leetcode.com/problems/validate-ip-address/
    2019-12-18
  • 台风骆骆
    如果是满足业务需求的话,可以用已有的轮子,不要轻易去重复造轮子,如果已有轮子不满足需求时,是需要重复造轮子的。
    2019-12-18
  • 程斌
    一切从实际出发,很多时候编码的过程中会发现,复杂的东西越少越复杂,而简单的东西呢,越敲越简单。很多项目中简单的复杂业务问题,都是问题没想透彻,最后会发现出bug最多的,也是那部分。
    2019-12-18
  • 陈华应
    对这俩原则的理解和应用总是觉得差点意思,现在清楚了!
    2019-12-18
收起评论
42
返回
顶部