支撑子域是为了项目成功必须要处理的问题,但由于没有现成、成熟的解决方案,必须要定制,费时费力。 如果能恰当地识别支撑子域的边界,形成'可复用'的'解决方案',就可以将其从支撑子域简化为通用子域,降低成本和风险 。 不就是个短信验证嘛,有这么复杂吗? 前几天安全专家马伟发布了《不就是个短信登录API嘛,有这么复杂吗?》,文章从“新增手机号和短信验证码登录”简单的一句话需求最终演变为 故事卡-274 作为用户,我可以通过手机号和短信验证码登录,以便于我更方便的登录。 安全验收标准:
实际上,根据我的经验,还可以再加一些验收条件
一个小小的需求可以衍生出如此之多的验收条件,而且其中不少是非功能性的(不容易识别的、不容易实现的),以至于有同学感叹: 厉害,短信验证这个事,如果有人做成整套解决方案直接调用就好了,就像keycloak一样。 运用子域进行战略设计 那么短信验证是否能成为'整套解决方案'呢,我们可以使用领域驱动设计中子域分类的框架来分析: 核心子域:它是一个唯一的、定义明确的领域模型,你要在这里进行战略投资,并在一个明确的限界上下文中投入大量资源去精心打磨通用语言。它是组织中最重要的项目,因为这将是你与其他竞争者的区别所在。正是因为你的组织无法在所有领域都出类拔萃,所以你必须把核心域打造成组织的核心竞争力。做出这样的决定需要对核心域进行深入地学习与理解,而这需要承诺、协作与试验。这是组织最需要在软件中倾斜其投资的方向。 支撑子域:这类建模方式提倡的是“定制开发”,因为找不到现成的解决方案。你对它的投入无论如何也达不到与核心域相同的程度。你也许会考虑使用外包的方式实现此类限界上下文,以避免因错误的认为其具有战略意义而进行巨额的投资。这类软件模型仍旧非常重要,核心域的成功离不开它。 通用子域:通用子域的解决方案可以采购现成的,也可以采用外包的方式,亦或是由内部团队实现,但我们不用为其分配与核心域同样优质的研发资源,甚至都不如支撑子域。请注意不要把通用子域误认为是核心域。你并不希望对其投资过甚。当讨论一个正在实施DDD的项目时,我们最有可能讨论的是核心域。 ——《DDD精粹:运用子域进行战略设计》Vaughn Vernon 可以发现:
我认为短信验证就是一个好例子,短信验证自身没有独立的价值,但没有它,某些重要的功能会缺乏保护。但目前只能找到发送短信的SDK,而缺乏对于'发送-验证'这个相对标准化的问题域的支持。 解决方案的形态是什么样的 在微服务的大潮下,如果想要复用短信验证的能力,最先想到的是开发一个短信验证服务,开放API给Consumer验证手机号码或是短信登录,名字我都想好了,叫 (sms-otp 服务) 如果我是甲方IT部门,可能就这么做了,找到一个软件集成商实现 作为数字化转型服务厂商,ThoughtWorks的想法会再进一步,是否还有更通用的方法? ThoughtWorks可能需要为很多客户交付短信验证服务,并且出于专业要求,我们并不会把为A客户定制的代码复制到B家使用,这时候一个开箱即用的微服务是最佳选择吗? 如果还有其他的“通用”需求呢?例如支付宝支付、微信登录呢,微服务的数量就开始膨胀了。在一些项目中,部分客户的IT基础设施比较滞后,这类项目未必适合以微服务启动。那有没有更灵活的方案,既可以在单体应用中开箱即用,又可以按需扩展为独立服务呢? 如果存在不确定性,不妨做个MVP 提到开箱即用,近几年在Java业界最火的就是 我们针对短信验证推出了自定义的 Spring Boot Starter,大名。 通过starter,既可以将解决方案'嵌入'单体应用,也可以快速启动新的微服务。 以下是一个简单的接入示例,为项目添加Starter: compile group: 'com.github.hippoom:sms-verification-starter:${latestVersion}' # 如果需要使用开箱即用的Redis验证码存储 compile 'org.springframework.data:spring-data-redis:2.1.2.RELEASE' # 如果需要使用开箱即用的Aliyun短信服务 compile('com.aliyun:aliyun-java-sdk-core:4.0.6') compile('com.aliyun:aliyun-java-sdk-dysmsapi:1.1.0') 为应用注入配置项:
启动应用,并请求验证码: >curl -H 'Content-Type: application/json' -XPOST ${host}:${port}/api/sms/verification/code -d '{'mobile': '${your mobile}'}' 在收到验证短信后,尝试验证:
在Response中可以得到一个JWT,前端应用将该JWT提交给Consumer应用,Consumer应用使用私钥对应的公钥即可验证该手机号码实现业务目标(如登录或保存验证过的手机号码)。 一些自问自答 如果是Starter的话,如何灵活定制呢? 既然这些Starter都是解决支撑/通用子域的问题,那么其领域规则、业务流程是比较固定、不易变化的。需要灵活定制的部分其实是技术实现,使用端口和适配器架构可以将这两部分隔离开,使用适配器扩展/变更技术解决方案。举个例子: 大名的端口和适配器架构 各个出口端口(右侧橙色板块的Port)作为扩展点,定制的Driven Adapter通过Spring注入。 为什么要绑定技术栈?非Java技术栈怎么办? 可以使用该Starter快速搭建一个微服务。。。 有没有前端的开箱即用方案 ? 还没有,我不是前端专家,但我猜测前端的开箱即用方案可以做成类似于 Ant Design 或 Element UI 但更专用的组件? 总结
花絮计算机科学中最难的两个问题,一个是分布式系统中的缓存系统,另一个则是起名字,为了避免第二个问题,我们决定以各个城市的著名景点周边道路作为项目代号。
|
|