unified-message(统一消息平台),为业务系统提供了标准的消息发送功能

  • 支持发送短信、邮件、企业微信等消息,可以扩展支持其它的消息类型
  • 可以通过手机号、邮件、企业微信用户名直接发送, 可以直接通过用户名发送短信等

项目地址

gitee: https://gitee.com/wei772/unified-message

github: https://github.com/wei772/unified-message

使用方法

  • 运行项目

  • 调用发送消息接口

curl --location --request POST "http://localhost:8080/api/message/send" ^
--header "Content-Type: application/json" ^
--data-raw "{ \"channelName\":\"wecom\", \"content\":\"测试\", \"recipients\":[\"LiWei\"]}"

包结构和主要类介绍

  • domain包

    • 包含Message相关领域类
  • repository包
    • 访问数据存储相关类
    • 使用MongoDb存储数据
  • client包
    • 访问第三方服务
    • 使用原始feign访问第三方web接口
  • command包
    • 对应用户用例的实现
    • 使用标准的Command接口
  • controller包
    • 对外提供web接口访问
  • sender包
    • 实现发送Message相关类

整洁架构

来源 Robert C. Martin 的《架构整洁之道》,详情查看第22章 整洁架构

  • 业务实体,业务核心包含应用的业务对象

    • 包含domain包
  • 用例,通常包含特定应用场景的业务逻辑

    • 包含command包
  • 接口适配器,软件的接口适配器层中通常是一组数据转换器,它们负责将数据从对用例和业务实体而言最方便操作的格式,转化成外部系统(譬如数据库以及Web)最方便操作的格式。

    通常这一层的代码也会负责将数据从对业务实体与用例而言最方便操作的格式,转化为对所采用的持久性框架(譬如数据库)最方便的格式。

    • 包含 client 部分抽象和具体类,访问外部接口的网关
    • 包含 repository 的抽象类,比如MessageRepository,是一种数据库网关
    • 包含controller包,对外提供Web接口。接收和返回Web请求数据
  • 框架与驱动程序,最外层的模型一般是由数据库、Web 框架等组成的。

    • 包含client包下的实现类,比如Feign使用BlacktelSendService生成的请求类,对应外部接口
    • repository实现相关代码,比如MongoMessageRepository,对应数据库访问。
    • 包含Tomcat Web容器和Spring MVC等框架细节

测试驱动开发

本项目使用测试驱动开发的方法开发

复杂类的默认态与运行态

复杂类一般会依赖外部环境,在代码中体系依赖外部接口。这些外部接口可能也会依赖其它复杂对象。

在Java中IoC框架存在就是用来创建这些复杂类,使用起来十分方便

但是这样创建的类确难以进行单元测试

  • 单元测试不应该依赖任何复杂框架,太过笨重,也太过复杂
  • 严重影响单元测试的速度

为了兼容单元测试和实际运行的两种情况,我将类分成默认态与运行态的方式。这样保持了类的测试性,又保证了类的功能性

  • 使用默认构造函数生成默认状态,用于单元测试

    • 默认的实现可以依赖外部,也可以基于Mock依赖,主要看外部调用是否方便、稳定、代价是否合理,比如发送短信代价有点高必须Mock
  • 还有一个由main函数进行组装的,比如基于Spring IoC,用于运行环境的状态
    • 使用@Autowired注解指定构造函数,实现该功能

效果与感受

  • 流畅的组织所有开发活动的技术,测试驱动开发这种先写测试再开发的方式很流畅。

    • 不要绞尽脑汁再脑中、用文字还有图去思考设计,这种方法浪费时间,想象力也无法有效发挥。
    • 也不会一上来就编码,编写难以执行代码,代码基本没有设计,想到哪写到哪。
    • 使用单元测试可以持续重构,一直保持设计和编码变得更好的

测试驱动开发本质

下面一些经典数据的一些论述,涉及到测试驱动开发本质

《测试驱动开发 (Kent Beck) 》当中有几段话让我印象深刻,体现了这种方法的核心作用

  • 而我从书本上学到的却恰好相反:“编码为今天,设计为明天。”而测试驱动开发看起来已经彻底推翻了这一论点: **“为明天编码,为今天设计。”

    ** 。
  • 测试(Test)--自动、具体、切实的测试。按一个键就可以让测试运行。具有讽刺意味的是测试驱动开发不是一种测试技术(Cunningham

    Koan)。 它是一种分析技术、设计技术,更是一种组织所有开发活动的技术

《敏捷整洁之道:回归本源》关于复式记账的论述

  • 会计师们在1000年前发明了一条法则,并将其称为复式记账。每笔交易会写入账本两次:在一组账户中记一笔贷项,然后相应地在另一组账户中记为借项。

    这些账户最终汇总到收支平衡表文件中,用总资产减去总负债和权益。差额必须为零。如果不为零,肯定就出错了
  • 复式记账与TDD这两种纪律是等效的。它们都具有相同的功用:在极其重要的文档中避免错误,确保每个符号都正确。

    尽管编程对社会来说已经必不可少,

    但我们还没有用法律强制实施 TDD。可是,既然编写糟糕的软件已经造成了生命财产损失,立法还会远吗?

测试驱动开发步骤

首先编写任务清单,一般包含设计想法、要实现用例、重构任务等等,将TODO的事情要一个简单的文档记录,整个过程比较随意,有价值的想法就记录下来,完成之后将对应的任务划上删除线。

然后是具体编写过程

  1. 从任务清单中挑选任务,针对任务编写不通过的单元测试,包括无法编译和运行错误的用例
  2. 使单元测试运行通过
  3. 重构现有代码,使设计更佳。

每次写代码都重复这3个步骤,直到没有需要完成的任务。

其它测试经验

  • 单元测试相关代码也很重要

    • Mock代码挺重要,好的Mock代码能够尽可能模拟真实情况,减少gap
    • 执行单元测试的代码的重要性也不言而喻,是测试驱动开发的开始。
  • Disabled的单元测试

    • 基本都是运行代价比较大或者不稳定的的测试,通常是面向外部依赖。
    • 默认不执行测试,可以单独去执行的测试
  • 在单元测试注释记录异常

    • 在单元测试注释里记录曾经遇过的异常,以及分析还有解决方案,感觉很有趣。
    • 能记录一下曾经遇到过什么问题,并且怎么解决了,既有成就感,又可以有经验的积累和传播
  • 单元测试不能替代验收测试

    • 单元测试通过不保证基本功能正常
    • 但是能极大简化验收测试,一般是因为环境、IoC依赖等出现问题
    • 可以考虑用spring-test进行简单的验收测试

unified-message(统一消息平台)开源项目介绍的更多相关文章

  1. .NET平台开源项目速览(13)机器学习组件Accord.NET框架功能介绍

    Accord.NET Framework是在AForge.NET项目的基础上封装和进一步开发而来.因为AForge.NET更注重与一些底层和广度,而Accord.NET Framework更注重与机器 ...

  2. .NET平台开源项目速览(9)软件序列号生成组件SoftwareProtector介绍与使用

    在文章:这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧!(第二辑)中,给大家初步介绍了一下Software Protector序列号生成组件.今天就通过一篇简单的文章来预览一下其强大的功 ...

  3. .NET平台开源项目速览(6)FluentValidation验证组件介绍与入门(一)

    在文章:这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧!(第二辑)中,给大家初步介绍了一下FluentValidation验证组件.那里只是概述了一下,并没有对其使用和强大功能做深入研究 ...

  4. NET平台开源项目速览(6)FluentValidation验证组件介绍与入门(转载)

    原文地址:http://www.cnblogs.com/asxinyu/p/dotnet_Opensource_project_FluentValidation_1.html 阅读目录 1.基本介绍 ...

  5. .NET平台开源项目速览(1)SharpConfig配置文件读写组件

    在.NET平台日常开发中,读取配置文件是一个很常见的需求.以前都是使用System.Configuration.ConfigurationSettings来操作,这个说实话,搞起来比较费劲.不知道大家 ...

  6. .NET平台开源项目速览(12)哈希算法集合类库HashLib

    .NET的System.Security.Cryptography命名空间本身是提供加密服务,散列函数,对称与非对称加密算法等功能.实际上,大部分情况下已经满足了需求,而且.NET实现的都是目前国际上 ...

  7. .NET平台开源项目速览(10)FluentValidation验证组件深入使用(二)

    在上一篇文章:.NET平台开源项目速览(6)FluentValidation验证组件介绍与入门(一) 中,给大家初步介绍了一下FluentValidation验证组件的使用情况.文章从构建间的验证器开 ...

  8. .NET平台开源项目速览(2)Compare .NET Objects对象比较组件

    .NET平台开源项目速览今天介绍一款小巧强大的对象比较组件.可以更详细的获取2个对象的差别,并记录具体差别,比较过程和要求可以灵活配置. .NET开源目录:[目录]本博客其他.NET开源项目文章目录 ...

  9. .NET平台开源项目速览(17)FluentConsole让你的控制台酷起来

    从该系列的第一篇文章 .NET平台开源项目速览(1)SharpConfig配置文件读写组件 开始,不知不觉已经到第17篇了.每一次我们都是介绍一个小巧甚至微不足道的.NET平台的开源软件,或者学习,或 ...

  10. .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验

    不知不觉,“.NET平台开源项目速览“系列文章已经15篇了,每一篇都非常受欢迎,可能技术水平不高,但足够入门了.虽然工作很忙,但还是会抽空把自己知道的,已经平时遇到的好的开源项目分享出来.今天就给大家 ...

随机推荐

  1. [异常笔记] zookeeper集群启动异常:Error contacting service. It is probably not running.

    報錯信息 zookeeper服務已經啓動,但是狀態是Error contacting service. It is probably not running. 2021-02-23 21:00:41, ...

  2. 题解:CF559B Equivalent Strings

    CF559B Equivalent Strings 题解 题目描述 吐槽一下,题目翻译有歧义. 思路分析 你会发现,当你需要判断字符串 \(a,b\) 是否等价时,如果长度为偶数,需要继续判断字符串 ...

  3. 内网 BitTorrent 下载环境搭建——基于 Transmission

    背景 前段时间为公司的产品增加了磁力链.种子下载的能力,测试时发现网上搜到的热门种子,有时好用,有时不好用,不好用主要表现在:没速度.速度慢.速度不稳定.下载一部分后没速度等,严重拖累了测试工作.为此 ...

  4. JavaScript 编写的迷你 Lisp 解释器

    感谢@李欲纯 的热心翻译.如果其他朋友也有不错的原创或译文,可以尝试推荐给伯乐在线.] Little Lisp是一个解释器,支持函数调用.lambda表达式. 变量绑定(let).数字.字符串.几个库 ...

  5. 鸿蒙ArkUI-X已更新适配API13啦

    ArkUI-X 5.0.1 Release版配套OpenHarmony 5.0.1 Rlease,API 13,新增适配部分API 13接口支持跨平台:框架能力进一步完善,支持Android应用非压缩 ...

  6. PythonDay1Base

    PythonDay1Base 变量 即python运行过程中可以发生改变的量,如同数学中的未知数X,将一个确定的量赋值给变量. 变量定义原则 由英文大小写,数字以及下划线_组成 不能以数字开头 不能以 ...

  7. MySQL底层概述—10.InnoDB锁机制

    大纲 1.锁概述 2.锁分类 3.锁实战之全局锁 4.锁实战之表级锁(偏读) 5.锁实战之行级锁(偏写)-行级锁升级表级锁 6.锁实战之行级锁(偏写)-间隙锁 7.锁实战之行级锁(偏写)-临键锁 8. ...

  8. vue使用docxtemplater导出word

    安装 // 安装 docxtemplater npm install docxtemplater pizzip --save // 安装 jszip-utils npm install jszip-u ...

  9. uni-app小程序(快手、抖音)getCurrentPages使用坑位记录

    前情 uni-app是我比较喜欢的跨平台框架,它能开发小程序/H5/APP(安卓/iOS),重要的是对前端开发友好,自带的IDE让开发体验也挺棒的,公司项目就是主推uni-app. 坑位 最近在做一个 ...

  10. JavaScript 的 Mixin 问题

    JavaScript 从 ES6 开始支持 class 了, 如何在现在的 class 上实现 mixin 呢? 很多人推荐这种搞法 Object.assign(MyClass.prototype, ...