极客时间已完结课程限时免费阅读

答疑解惑 | 如何在实际工作中推行新观念?

答疑解惑 | 如何在实际工作中推行新观念?-极客时间

答疑解惑 | 如何在实际工作中推行新观念?

讲述:郑晔

时长11:02大小10.12M

你好,我是郑晔。
在整个专栏的最后一个大模块"综合运用"中,我们把前面学到的各种原则和知识穿插在一起应用在了不同的场景中。在这个模块的答疑中,我们也综合汇总一次,把整个专栏中出现的一些有趣却还没有来得及讨论的问题放在一起。

问题 1:想要推行 DDD,阻力很大怎么办?

段启超 同学提到
想在公司内推行 DDD,阻力真的很大,首先是很多人对 DDD 没概念,需要一定的学习成本,二是团队间相互隔离,沟通成本很高,起码的通用语言都很难达成。
段启超同学提到的这个问题是一个非常典型的问题,而且,这个问题并不仅仅局限于 DDD。你在一个地方看到了一些好东西:技术、实践,或是想法,然后想把它运用在自己的项目中,希望项目越做越好,越来越顺利。但在实际情况中,想在一个组织内推广一些不一样的东西,都会面临层层阻力。
我在《40 | 我们应该如何保持竞争力?》中提到了一个学习模型,你只要在学习区不断地练习新技能,很快就可以超越同侪。其中的原因是,大部分人只习惯待在舒适区,在舒适区的人能力上的进步非常有限。也因为在舒适区实在太舒适了,走出舒适区会让人产生焦虑,所以,人的内心是惧怕改变的。
你有良好的愿望,驱动你自己去改变是一件可控的事,有愿意和你一起改变的人是一件幸运的事,但你指望所有人一下子和你走上同一条道路,这是一件几乎不可能的事,即便你是很高层的领导,让所有人与你保持一致也不现实。
我曾经在一个大公司做过敏捷咨询,这还是由他们顶层领导推动的敏捷转型,但依然是困难重重。那些习惯于待在自己舒适区的人总会找到各种神奇的理由告诉你,他们的情况有多么特殊,这些最佳实践在他们那里是不适用的。
我们放弃了吗?并没有。我们的做法是,找一个团队来做试点。
换句话说,我们找到了几个愿意改变的人,把这些最佳实践应用在他们的项目上。在这种情况下,大家的目标是一致的,就是希望让这个项目得到改善。所以,大家自然会想尽一切办法,克服遇到的困难。比如,我们当时的切入点是持续集成。
他们的代码都在老旧的 ClearCase 上,每个人修改文件要先去竞争文件锁,特别不利于小步提交,所以,我们推动着将 ClearCase 改成了稍微进步一点的 Subversion。(好吧,你能听出来这是一个有些年头的故事。)
代码是用 C 语言编写的,在他们的代码规模下,编译时间会很长。于是,我们决定搭建一个分布式构建系统,这需要有很多台电脑。不过,他们的硬件是严格管控的,申请电脑是很困难的,虽然花了很大的力气,但最终我们做到了。
以往团队都是几天甚至几周才提交一次代码,我们先将代码提交的要求限定在每人每天至少提交一次,为此,我们专门坐下来与团队成员一起分解任务,将他们理解的大任务拆分成一个一个的小任务。
……
想做事,只需要一个理由就够了,不想做,理由有一万个。劝那些不想改变的人改变是异常耗时而且收效甚微。最好的办法是,找到愿意和你一起改变的人,做一件具体的事。
我们并没有劝说谁去听从我们的想法,只是在一个一个地解决问题。我们花了很长时间,最终建立起了持续集成,看到大屏幕上的绿色标识,我颇为感动。原本只需要一两天搭建的持续集成,在一个复杂组织中,它要花费那么长时间,这也是我从未经历过的。
当我们把这件事做成之后,其他团队看到了效果,开始纷纷效仿。于是,原本复杂的各种规定也开始纷纷松绑,比如,他们再也不需要为申请电脑发愁了。至于之前质疑我们的人,因为看到了成效,他们的关注点就成了怎么把事能做成。
后来我听说,他们在组织内部专门建立了一个持续集成中心,为各个团队提供了公共的构建资源,提升了整体的效率。
Linus Torvalds 曾经说过:“Talk is cheap. Show me the code. ”讲道理很容易,但也难以让人真正的信服。同样,做事很难,但成果摆在那里,让人不得不信服。
在英文中对这种行为有一个说法叫“Lead by Example”,通常用来形容团队领导以身作则的行事风格。当你寻求改变时,无论你的角色是什么,你都需要扮演好领导者的角色,“Lead by Example”送给你!

问题 2:测试怎么写?

andyXH 同学提到
目前对于 TDD 还是处于理解状态,不知道如何真正的在项目工程中使用。因为项目工程往往还有很多其他调用,如 rpc,数据库服务,第三方服务,不知道在这个过程如何处理。期待老师在之后文章中讲解。
梦倚栏杆 同学提到
从数据库或者第三方 api 查询类内容需要写测试吗?这种测试怎么写呢?如果不需要写,会发现大量展示类系统不需要写测试了,感觉怪怪的。
闷骚程序员 同学提到
假设我要测试的函数是一个关于 tcp 的网络发送函数,我想问一下,老师在写类似这样功能的单元测试是怎么实现的?
TimFruit 同学提到
问个问题,一般 web 服务依赖数据库,这部分如何做好单元测试?如果去掉数据库,很难测试相应的 sql 语句。
大家看到了,这是一类非常典型的问题。一般来说,如果写的测试是一些业务逻辑的测试,大多数人还知道怎么测,一旦涉及到外部系统、数据库,很多人就不知道该怎么办了。
我们先来回答一个问题,你要测外部系统的什么?
你当然会说,我的整个系统都依赖于外部系统,没有了它,我的系统根本运行不起来,不能完成工作啊!但是,我的问题是你要测的是什么?
我知道很多人一想到外部系统,第一反应是:“我的整段代码都是依赖于外部系统的,因为外部系统不好测,所以,我这段代码都没法测了。”如果你是这样想的,说明你的代码将对外部系统的依赖在业务代码中散播开了,这是一种严重的耦合。外部系统对你来说,应该只是一个接口。
我在《13 | 先写测试,就是测试驱动开发吗?》中说过,想写好测试,先要站在可测试的角度思考。假设我同意你关于外部系统不好测的观点,那应该做的是尽量把能测的部分测好。将对外部系统的依赖控制在一个小的范围内。
一个好的做法就是设计一个接口,让业务代码依赖于这个接口,而第三方依赖都放在这个接口的一个具体实现中。我在《34 | 你的代码是怎么变混乱的?》中提到了 SOLID 原则,这种做法就是 接口隔离原则(ISP)的体现。
如果你能够站在系统集成的角度思考,这个部分就是系统与系统之间的集成点。我在《37 | 先做好 DDD 再谈微服务吧,那只是一种部署形式》提到了 DDD。在 DDD 的战略设计中,有一个概念叫上下文映射图(Context Map),在不同上下文中集成最常见的一种模式是防腐层(Anti-Corruption Layer,ACL)。
很多系统在实现时就是缺少了防腐层,造成的结果就是系统耦合极其严重。因为外部服务的任何修改都会造成自己的代码跟着大幅度变动,更极端的情况是,我见过一个网关系统在自己的业务逻辑中直接依赖于第三方服务传过来的 JSON 对象,造成内存资源的极大浪费,网关本身极其不稳定。
至此,你知道了,如果有任何外部系统,都要设计防腐层,用接口做隔离。这样,才能保证你的业务代码是可测的。如果外部系统真的不好测,这种做法将大幅度降低不可测的比例,尽可能提高测试覆盖率。
我们前面的假设是,外部系统不好测,但真的不好测吗?
作为 Moco 这个模拟服务器的作者,我肯定是不会同意这个说法。如果你的系统依赖的外部系统是最常见的 REST 服务,那 Moco 就是给这种场景准备的。我给你看一个最简单的例子,这是 Moco 中最简单的用法:
@Test
public void should_response_as_expected() throws Exception {
HttpServer server = httpServer(12306);
server.response("foo");
running(server, new Runnable() {
@Override
public void run() throws IOException {
Content content = Request.Get("http://localhost:12306").execute().returnContent();
assertThat(content.asString(), is("foo"));
}
});
}
在这个例子里,你设置外部服务的行为,让它按照你的需求返回特定的内容,然后,运行你的服务去访问这个外部服务,它和你访问真实服务效果是一样的。而且,通过 Moco,你还可以模拟出一些真实服务不可能给你做出的效果,比如,连接超时。
这里给出的是一个用 Java 编写的例子。如果你采用的是其他语言,也可以使用 Moco 的 Standalone 模式,用 JSON 配置出一个模拟服务器。
对于数据库的测试,如果你采用的是 Spring Framework,它就提供了一套完整的方案,比如:你可以在运行测试时插入一些数据,然后,在测试执行完毕之后,回滚回去,保证测试的可重复性。
事实上,它对测试的支持已经非常强大了,远不止于数据库。如果你采用的是 Spring Boot,对测试的支持就更加完整了,但基础还是 Spring Framework 提供的。如果用到真实的数据库,最好是一套独立的本地数据库,保证环境的可控。
对于外部服务的测试,简言之,能模拟的就模拟,能本地的就本地。如果你的服务没有现成的工具支持,也许就是一个打造新工具的好时机。
总结一下。关于外部系统的测试,你可以先通过接口隔离开来,然后,通过模拟服务或本地可控的方式进行测试。
好,今天的答疑就到这里,你对这些问题有什么看法呢?欢迎在留言区写下你的想法。
感谢阅读,如果你觉得这篇文章对你有帮助的话,也欢迎把它分享给你的朋友。
分享给需要的人,Ta购买本课程,你将得20
生成海报并分享

赞 16

提建议

上一篇
40 | 我们应该如何保持竞争力?
下一篇
划重点 | “综合运用”主题内容的全盘回顾
unpreview
 写留言

精选留言(14)

  • 西西弗与卡夫卡
    2019-04-19
    找团队进行试点,这个很重要。最近我们在推行信息化,一种方法是从上往下强推,我们采用的是第二种,主要从下往上推动,即让大家觉得方便工作高效。从下往上,许多团队就会观望,先找团队试点,改善他们流程提升效率,看到失效,其他部门也就容易攻克了

    作者回复: 如果从组织转型的角度,确实需要从上开始,但必须有一个试点先落地,否则就是,上面有呼吁,下面没响应。

    15
  • 孤星可
    2019-04-19
    回答一下 mybatis 的测试问题 我建议直接看源码 4w行 其中2w是测试代码

    作者回复: 很好的补充

    8
  • 大力
    2019-04-21
    Talk is cheap. Show me the example.🤓

    作者回复: 我也很想讨论更多细节,篇幅有限,唉!

    7
  • desmond
    2019-04-19
    技术推广,不要先推广最难的部分,先推广能让对方感到最明显好处的部分。 取得对方的信任,是友好沟通的基础。

    作者回复: 非常赞同这个角度!

    6
  • J.M.Liu
    2019-04-20
    追了快一个月,终于赶在专栏结束前追上大家了,郑老师好呀,同学们好呀,很高兴见到你们。不过马上就又要分别了,真有一丝不舍

    作者回复: 欢迎加入,学到知识是最重要的。

    4
  • 研发
    2022-03-01
    专栏截止目前出现的书单 《人月神话》 《Rapid Development》/《快速软件开发》 《精益创业》 《从一到无穷大》 《卓有成效的管理者》 《设计模式》 《Succeeding with Agile》 《解析极限编程》 《测试驱动开发》 《User Stories Applied》和《Agile Estimating and Planning》 《高效能人士的七个习惯》 《三体》 《大富翁》 《通信的数学原理》 《程序设计实践》 《圣斗士星矢》 《五分钟商学院》 《实现模式》 《计算机程序设计艺术》 《重构:改善既有代码的设计》 《持续交付》/《持续交付 2.0》 《敏捷软件开发:原则、实践与模式》 《架构整洁之道》 《淘宝技术这十年》 《领域驱动设计》 《实现领域驱动设计》 《领域驱动设计精粹》 《修改代码的艺术》 《C 程序设计语言》《程序设计实践》《Unix 编程环境》 《人类简史》 《未来简史》
    展开
    共 1 条评论
    4
  • 宝宝太喜欢极客时间了
    2019-04-19
    老师,有没有对mybatis单元测试写的好的开源项目或者博客之类的推荐个

    作者回复: 对于 Java 的话,我通常采用的是 Spring 的方法,测试之后回滚,没有专门针对 MyBatis 进行过处理。

    2
  • ifelse
    2022-05-02
    关于外部系统的测试,你可以先通过接口隔离开来,然后,通过模拟服务或本地可控的方式进行测试。--记下来
  • aoe
    2021-12-01
    读完后突然解决了这几天困扰的问题,通过MQ调用其他服务和定时任务怎么写单元测试?单元测试解决不了,集成测试可以。
  • 独孤九剑
    2021-10-14
    “子域”对标“中台”,“限界上下文”对标“微服务”,微服务之间交互主要有3种方式:REST API接口,RPC调用,MQ。
  • Sic Pavis
    2020-12-02
    防腐层这个深有体会,直接依赖外部对象,一旦外部更新结构,对服务来说就是灾难性的。 关于外部依赖怎么做单测,文章已经讲过,数据库如果想测试sql查询逻辑,我这边目前是用的h2内存数据库,麻烦点在于需要在两个地方维护表结构,而且部分MySQL语法可能不兼容。单测启动时创建一个和正常环境结构相同的数据库,然后可以随意操作数据,单测结束数据也会跟着销毁。
    展开

    作者回复: 一种隔离是数据库,一种隔离是业务接口。

  • 丁丁历险记
    2019-11-19
    lead by example 2 测试数据库,还是没分解到位。 用好isp 原则。 防腐层。 3 能测是开发的前续条件。 实在不行,造工具
  • helloworld
    2019-05-14
    依赖第三方系统时增加一个防腐层的做法感觉非常好!对于依赖第三方系统的代码测试能模拟第三方的就弄模拟

    作者回复: 在《程序员的测试课》里,我详细讲解了怎么做。

  • enjoylearning
    2019-04-21
    依赖第三方的采用适配器模式即可。