OOBootcamp 回顾与总结

OOBootcamp,全称是Object-oriented Bootcamp,就是面向对象训练营的意思,在12月份和1月份,我们整个项目组一些senior一些的同事一起接受了OOBootcamp的培训,有这个培训呢,还多亏了训杰找骏总争取到了这个机会,Tech leader做得好,关心组员的技术成长,哈哈。讲师是袁慎建老师,intellij 的快捷键玩的出神入化,技术实力没得说,又会说话还又会写文章,关键是人还长得特别帅,这就让人有点嫉妒了,附上他的地址,欢迎大家前去骚扰.

前些天这次OOBootcamp圆满结束,完结撒花。领到了一张小奖状


image.png

当然还有一些附带的训战计划,是需要在实际项目中去落实所学到的知识。所以之后还会有一些在实际项目中实践这次学到的知识之后的感悟,好,废话不多说了,下面就来回顾总结一下这次的OOBootcamp.

这次OOBootcamp, 主要分了三大块的内容,一个是SOLID原则, Simple Design原则,贫血充血模型,二是TDD, 三是重构,主要用了Parking Lot 这个编程实例来给我们做练习,学以致用,先用例子实现一遍,再之后在真实项目中再操练一遍,几板斧下来,保准你映像深刻,又有自己的体悟。

SOLID 原则 (面向对象的基石)

SOLID原则,我自己就不多现丑了,附上一篇袁老师的博文,供大家参考,虽然主要讲的是里氏替换原则,但是其他原则附带也有讲,网上一搜索也是一大把。我下面就讲一下我在OOBootcamp结束后对SOLID原则的理解,就不会讲很多细节了。

先复制一波袁老师的一段文字
SOLID由五大原则构成:

  1. Single Responsibility Principle【单一职责原则】
  2. Open Close Principle【开闭原则】
  3. Liskov Substitution Principle【里氏替换原则】
  4. Interface Segregation Principle【接口隔离原则】
  5. Dependency Inversion Principle【依赖倒置原则】
    并且请记住一句话,所有的原则其实都是为开闭原则服务的

注:袁老师说,你们知道了这几个原则后,就把它忘掉,不过,我可能还没到这种无招胜有招的境界,所以需要详细记录一下

1. 单一职责原则

我理解的单一职责原则很简单, 就是一个类,或者一个方法,它就只做一件事情,当然这句话说了等于没说,你可能会说我知道单一职责是什么意思,但还是不会啊。对,我也不会,没人敢说他会。因为单一职责的难点就在于这个一件事,到底是怎么个一件事,或者说怎么分。大到组装一台车,小到造一个螺丝钉,它都是一件事。怎么分?

其实这是一个很难的问题,这个问题是没有一个标准的答案的,它跟你的业务相关,跟你具体的实践相关。不是一个精准的度量而是一个感官度量。唯有以面向对象的方式多多练习,才能找到那个感觉。以我的感受来说,当你觉得你找出的那一件事情,分无可分,不存在二义性,那么我认为这就是单一职责的一件事。

2. 开闭原则

开闭原则的定义是对扩展开放,对修改关闭。这个真的咋一看云里雾里,要理解这个原则,我觉得我们首先得把这句话的作用域缩小一点,就针对java 面向对象来说,其实应该说的是,扩展功能可以增加新的类,但应该尽量避免修改已有的类。其实还是有点不好理解哈,也不知道怎么做,我觉得这时候可以去看下设计模式,全部的设计模式都遵循了开闭原则,简直是最好的开闭原则示范。

3. 里氏替换原则

墙裂推荐袁老师的这篇博文 让里氏替换原则为你效力,写得很好,简直写到我心坎里去了。

我这里就只说说里氏替换原则的定义,任何基类可以出现的地方,子类一定可以出现,如果你覆写了父类的方法,那么其实你是违背里氏替换原则的。至于为什么,都在袁老师的博文里,欢迎大家去围观,哈哈。

4. 接口隔离原则

接口隔离原则的定义是 客户端不应该依赖它不需要的接口;类间的依赖关系应该建立在最小的接口上
这个原则,看定义就很好理解了,其实我认为它是对单一职责的一种补充,因为如果你单一职责做的非常好,那么你其实会很少碰到违背接口隔离的情况的,反之,如果真的出现了,那么一定是你单一职责做的还是不够好。

5. 依赖倒置原则

这个原则的定义 是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了耦合

这个其实也是有点绕的,面向抽象编程怎么就降低了耦合呢?其实我觉得还是很好理解的,比如你吃一个苹果,如果写实现,你写一个苹果类就完事儿了,但是如果面向抽象你需要定义一个苹果接口,然后我吃这个接口就好,不关心是什么苹果,然后再写苹果的实现,但是后面还有需求,说要吃一个美国的苹果,因为美国苹果又大又圆,面向实现的做法是,我改一下我的那个苹果类改成美国苹果就完了,面向抽象的做法是,我在写一个类,美国苹果类实现苹果接口,其实对比两种方式,你就能知道谁好谁坏。

Simple Design(简单设计)

简单设计原则 我还是推荐大家去读袁老师的文章 简单设计落地三板斧 其中链接了 简单设计的价值观和 简单设计原则,哈哈,都是他写的,十分高产。

简单设计原则在我看来核心就是 保持简单。对于程序开发来说,就是保持程序简单,不要去过度设计,我们写程序的时候常常会不由自主的为未来去考虑,比如一个好的程序员,他会有这样个习惯,他不会单单只完成自己手上的工作,他会去思考未来会有什么需求进来,于是这些思考会常常体现在代码上,形成过度设计。而如果你认同敏捷价值观,那么这其实并不是一个好的习惯,因为你思考的需求,其实有时候并不会实际产生,于是代码凭空复杂了很多,并且有一部分还是无用代码。

Simple Design 就是需要你去认同这样的价值观 保持程序简单,不要过度设计,你的程序实现应该是刚刚好满足你现有的需求的。

那么怎么去落地Simple Design呢?请看袁老师讲的Simple Design落地三板斧。TDD, 重构,clean code, 哈哈
培训的时候映像比较深的是这样一幅图


img

这个是说的在实践简单设计过程中,当面临冲突时,我们如何取舍,最重要的是通过所有测试,其次是消除重复和解释意图,优先级最低的是减少元素,当有冲突时,优先级越高的我们越应该关注。

贫血充血模型

期间由训杰给我们分享了贫血和充血模型,现在一般Java 项目多数都会采用spring全家桶,而spring所推崇的mvc结构是一种典型的贫血模型,于是迅杰给我们分享了贫血模型和充血模型的区别(好处和坏处),以及充血模型的架构应该是怎么样的

不了解贫血模型和充血模型的, 可以看看这篇文章 贫血模型与充血模型的对比

以下是摘抄自上面那篇文章

贫血模型的好处是:
1、每个贫血对象职责单一,所以模块解藕程度很高,有利于错误的隔离。
2、非常重要的是,这种模型非常适合于软件外包和大规模软件团队的协作。每个编程个体只需要负责单一职责的小对象模块编写,不会互相影响。

贫血模型的坏处是:
1、由于对象状态和行为分离,所以一个完整的业务逻辑的描述不能够在一个类当中完成,而是一组互相协作的类共同完成的。因此可复用的颗粒度比较 小,代码量膨胀的很厉害,最重要的是业务逻辑的描述能力比较差,一个稍微复杂的业务逻辑,就需要太多类和太多代码去表达(针对我们假定的这个简单的工时管 理系统的业务逻辑实现,ruby使用了50行代码,但Java至少要上千行代码)。
2、对象协作依赖于外部容器的组装,因此裸写代码是不可能的了,必须借助于外部的IoC容器。

对于Ruby来说,更加适合充血模型。因为ruby语言的表达能力非常强大,现在用ruby做企业应用的DSL是一个很热门的领域,DSL说白了就是用来描述某个行业业务逻辑的专用语言。

充血模型的好处是:
1、对象自洽程度很高,表达能力很强,因此非常适合于复杂的企业业务逻辑的实现,以及可复用程度比较高。
2、不必依赖外部容器的组装,所以RoR没有IoC的概念。

充血模型的坏处是:
1、对象高度自洽的结果是不利于大规模团队分工协作。一个编程个体至少要完成一个完整业务逻辑的功能。对于单个完整业务逻辑,无法再细分下去了。
2、随着业务逻辑的变动,领域模型可能会处于比较频繁的变动状态中,领域模型不够稳定也会带来web层代码频繁变动。

TDD

上面的理论讲完了之后,就是实践了,用TDD 这个工具来实现一个比较经典的题目ParkingLot Management,在回顾TDD之前我要先回顾一下Tasking 思维管理工具

Tasking

Tasking 是一种思维管理工具, 它要求你对于一个比较复杂的问题,列出它的每一个完整子路径,这样进行Task分解之后,复杂的问题就变成了一个个简单的容易实现的子问题了

Tasking 的经典格式是 Given When Then 格式,一个典型停车小弟的需求Tasking分解的例子是

Given: 我管理一个停车场,停车场有空位
When: 用户委托我停一辆车
Then: 停车成功

可以看到,Tasking要求你分解出的Task要尽量的简单并且可测试

一个错误的例子是

Given: 我管理N个停车场,停车场N个空位
When: 用户委托我停N辆车
Then: 停车成功

这个Task其实是很难去测试的,N是多少?测试里面你难道要穷举吗?怎么穷举?

TDD

TDD 测试驱动开发,是极限编程列出的12个团队实践之一,是其中重要的组成部分,TDD的具体理论和一些实践,在网上都有,我这里只讲我练写TDD的感受,首先 TDD 是一个工具,是工具就有适用场景的,也就是说,不是所有的软件开发过程都适合使用TDD,其次它是由三个单词组成

  1. Task Driven Development
  2. Test Driven Development
  3. Test Driven Design

三个词中都出现了Driven,所以,TDD的核心其实是那三个D, 而且从2,3两个词可以看出,TDD是必须Test First的

其实在课程开始之前,我对TDD的理解很粗浅,仅仅限于先写测试后写实现(当然,其实这样理解也没什么毛病),在实践中也几乎没有去实践,我们总是习惯于先写实现,写完之后再回过头来补测试. 其实有时候就会有一种想法,觉得测试是一个可有可无的东西,你写了更好,没写程序也不会出啥大的问题。就像是客户要求我们测试覆盖率90%以上,写测试就是为了完成客户的需求。

但是,TDD要求你重视测试,测试是一等公民, 你得先写测试再去写实现,你的测试得能表现你的业务,让别人一看你的测试,就知道你的业务是啥,这就倒了过来,变成了实现是小儿子,哈哈

因为在TDD看来,好的能完整表现业务的测试,至少不会让你漏了边边角角,而且这样写下来,理想情况下,测试的覆盖率应该是百分之一百的. 你会对你写的代码无比有信心,因为在需求范围内,你可以宣称你写的代码是百分之百的满足需求。

课程开始的时候,我们对TDD要求的 Test First是什么,是很明确的,就是先写测试后写实现,Task Driven Development 这个也是比较好理解的,但是后两个确难到我们了,测试怎么去驱动开发,怎么去驱动你的设计,你的设计是测试驱动出来的吗?以至于我们花了两节课的时间去讨论这些问题。下面我附上,我们讨论的结论

  1. 我们写测试之前,脑海里是有提前设计的,没有提前设计,你测试都写不了更不用说写实现。
  2. 测试并不能驱动你的设计,只会让你发现坏的设计(坏的设计测试很难写)

下面是我们TDD的实践步骤:

  1. 跟客户确认当前阶段需求,确认到什么程度呢?你觉得你能开始列Task了的时候,之后随时保持与客户的紧密沟通,需求有任何问题找客户沟通

  2. 选择视角(就是选择看待问题的视角,比如是用户视角还是停车场管理员视角),运用Tasking思维管理工具 列Task,Task是以业务场景为单位的,每一个Task都是要有交付价值,何为交付价值,就是客户拿来能用的功能(能跑起来的程序), 代码写了一半,跑都跑不起来的,没有任何价值. 先列简单场景的Task 后列复杂场景的.

  3. 根据Task列表,从前到后一个一个的实现,由于我们是采取Pair的编程方式,所以是一个人写测试,然后另一人写实现,之后轮换
    提前设计注意点:

    1. 写Task之前,是要有提前设计的
    2. 提前设计必须根据你当前已经做完和正要做的Task做提前设计,禁止根据全部的Task做提前设计
      写测试的注意点:
    3. 测试必须能表现你当前Task的业务
    4. 抽象关系可以体现在测试里
      写实现的注意点:
    5. 实现的代码是基于你的提前设计的 (不要做重复的无用功)
    6. 实现的代码要刚刚好满足你的业务,何为刚刚好?就是删除任意一行你的代码,你的测试就会挂掉, 反之,就不是刚刚好
    7. 看到不爽的代码就重构,什么是不爽的代码?请看 clean code 这本书
  4. 全部Task完成之后就是向客户交付产品了,由于我们的客户是袁老师,所以给他review了代码,保证所有的测试是绿的

TDD 这个东西,如果你单看字面,不去实践,是无法领会它的精髓的,我觉得初学者如果要去实践TDD, 可以不用去考虑它的后两个单词,只看Test First,先实践一下Test First, 然后再慢慢去加上后两个Driven,最终你会达到那种得心应手的境界,当然还可能是放弃,哈哈

据说如果熟练使用了TDD, 开发效率会比不使用TDD提升很多,这个我暂时也还没体会到,看来是实践的少了,之后会找机会多实践TDD

重构

重构我就不多介绍了(要介绍也只能贴贴各种代码示例),请大家移步 重构 这本书

我就只说说我的感受

  1. 当你看到不爽的点的时候,你就要重构你的代码
  2. 不爽的点应该是违背团队的代码约定的,而不是违背你自己的小癖好
  3. 最好通读一遍 clean code, 这样你说别人代码不好的时候也不至于词穷(可以指着书本骂他)
  4. 光看重构这本书,其实没多大用处,你看过就会忘,你必须结合它来一场说写就写的实践, clean code也一样
  5. clean code, 重构这两本书,请常备在桌面上,说不准啥时候就会用到,无论是指着书本骂人,还是适当的装一下逼

总结

OOBootcamp 培训给我的进步还是很大的,以前我虽说是用着面向对象的语言,确写着云里雾里,而这次培训下来,结合理论和实践,我深刻理解了面相对象的基本原则,简单设计原则,以及Tasking TDD等做法,而且也使我对敏捷有了更深刻的认知,确实是犹如醍醐灌顶,受用无穷。我相信这些知识最终也能带着我飞得更高。

你可能感兴趣的:(OOBootcamp 回顾与总结)