学习DDD的时候,作为开发更关心它技术层面的东西,尤其体现在DDD的分包方式、编码技巧等方面。

我们不禁发问,用了DDD的分包,就是实践落地了DDD了么?

不卖关子,直接说答案,并不是。

用了DDD的分包,只能说满足了DDD的形,并没有抓住DDD的神。DDD的神是什么,归根到底还是面向对象,领域建模。所谓的各种分包方式本质上还是为了满足DDD面向对象的本质,方便开发者进行代码编写而提供的一种”战术设计”工具.

要深入讨论这个问题,我们需要花一点时间来学习讨论一下DDD中常见的几种分包。

Read More

软件开发领域中,软件复杂度是一个由来已久的话题,从软件的诞生到成熟再到消亡,或多或少总会伴随着软件复杂度的讨论。

我们不禁发问,软件复杂度究竟从何而来?

谈到软件复杂度,有三个话题不得不提及,他们分别是软件规模,软件结构,以及业务的变化。

首先是 软件规模,它涉及到软件本身的代码量,迭代时长以及迭代的次数/数量,以及该软件经手的开发者数量等。这几个要素都会对软件规模造成显著影响,可以回想一下自己接手别人祖传代码时那种忐忑不安、小心翼翼的心态,生怕因为自己的失误导致出现bug甚至背锅的情况;并且代码规模越大,业务逻辑越冗长,这种心态就越发强烈。

Read More

今日的后端开发,我们常常听到大家提到“领域驱动设计”、“DDD”等名词,听起来感觉很高端,自己也忍不住想了解,但是又不知从何下手。

不慌,我们这个系列的意义就在于用浅显易懂又不是深度的叙述手法,为大家全方位的介绍普及DDD领域驱动设计的知识,并最终落地到自己的项目中。

那么,我们直接进入正题,领域驱动设计(接下来为叙述方便,用DDD代指)到底是什么?

Read More

随着业务发展,软件本身也需要不断进行迭代以适应业务变换。

我们可以说,软件存在的价值就是映射真实世界,解决业务问题,从而创造更多价值,为大众提供更加便利的服务。

面对复杂业务场景,我们往往通过不断增加业务分支,对原有的冰山一样的代码逻辑进行小心翼翼的修改,生怕因为自己的修改导致全局出现不可挽回的损失。

这种不断迭代的历史遗留代码,几十年前的《人月神话》已经下过一次定义–“焦油坑”。

我们也常常调侃,自己不是在写代码,而是在Ctrl C / V, 在代码的“shit mountain”山不断进行着业务逻辑的搬运,并时刻祈祷系统别出异常,从而成为背锅的那个人。

这种现实是否能够通过一定的方式/方法/技巧改善甚至说这种类型问题能否改善呢?

Read More

日常开发中,对于遗留系统代码逻辑的改造,通常不会粗暴地采用停机更新方式直接迁移到新业务逻辑,往往需要通过灰度方式逐步迁移到新逻辑,最后再把老业务逻辑下线。

这个过程中就涉及到新老业务逻辑并存的问题,而这个问题是需要研发同学去通过工具、编码、配置等方式实现灰度策略,制定灰度计划,并付诸实施,保障系统能够平稳地从老业务逻辑迁移至新业务逻辑。

通常情况下,如果是http接口灰度,我们可以利用网关的特性,如nginx自身的能力,根据cookie中传递的唯一标识进行百分比分流,通过免开发的方式进行灰度。

但在实际开发中,我们面对的系统不仅仅是网关类系统,大部分情况下,分布式系统开发场景下面对的是RPC类接口或者异步消息逻辑,对于这类型代码逻辑的灰度就需要研发同学通过编码方式,细粒度的进行灰度。

本文中,我们就后者展开代码级别的讨论和分享,向读者介绍笔者在日常开发中,面对接口级别的灰度场景是如何通过编码实现具体的灰度策略的,本文权当抛砖引玉,为读者全景展示​后端研发套路之灰度场景下的瑞士军刀具体是如何使用的。在今后的开发工作中如果你遇到类似场景,可以参考笔者思路,开发适合自己业务的灰度套路。

Read More

在之前的一篇文章 手写JDK组件之阻塞队列BlockedQueue 中 ,我们模仿Java的ArrayBlockingQueue实现了一个阻塞队列。并通过该案例对阻塞队列的实现机制有了一个初步的认识。

实际上,Java中的阻塞队列用处还是比较广泛的,尤其是当我们不需要使用复杂的分布式消息队列,只是想要基于生产者-消费者模型,解耦业务逻辑,那么我们就可以借助内存队列实现。

这类型业务场景往往具备以下特点:

  • 消息发送量不多
  • 消息的安全性不高,可以容忍丢失
  • 不需要保证HA
  • 不需要提供完备的failover机制

举个例子,比如说当订单下单成功后我们想发送一个站内信,通知商户或者用户下单成功,仅仅作为一个提醒。类似这种场景,我们就可以借助内存队列实现。

基于我们刚提出的这个场景,编写一个demo进行验证。

Read More

笔者在两年前写过一篇RestTemplate使用相关的文章,地址: springboot中使用RestTemplate调用web服务小结

文章写作时SpringBoot版本尚在1.x徘徊,随着SpringBoot版本升级,有些用法在2.x版本中已经不适用。恰逢最近又用到了RestTemplate进行HTTP接口对接,
因此写作本文对最新的使用方法进行小结,方便后续参考,也希望能够帮到读者更好的使用RestTemplate在2.x的SpringBoot中进行HTTP接口的调用。

对于Get方式请求,2.x与1.x是兼容的,因此可以直接阅读上文中提到的链接,本文就不再重复赘述。

Read More

本文我们重点讲解一下Stream中收集器Collector的主要使用方式。

收集器

收集器(Collector)的作用为:将流中元素累积成一个结果作用于终端操作collect()上

关于收集器,我们主要关注:

collect()(操作实现Collector接口的集合)、

Collector(接口)

Collectors(工具类)

日常开发中,我们使用最多的是预定义收集器功能(Collectors)

它的作用主要是:

将流元素规约和汇总为一个值

将流元素分组

将流元素分区

Read More

Fork me on GitHub