Newbe.Claptrap 项目周报 1,第一周代码写了一点。但主要还是考虑理论可行性。

第一次接触本框架的读者,可以先点击此处阅读本框架相关的基础理论和工作原理。

周报是啥?

成功的开源作品,离不开社区贡献者的积极参与。作为一个新启动的轮子项目,项目联合创始人【月落】有交代:

“我知道你代码能力也不怎么样,你就把你的想法每周的交代清楚。让他人看到项目的价值。等待越来越多的人发现项目价值所在的时候,自然就会给予更多的关注,甚至于参与的项目的开发当中。所以你要每周都写一下周报。周报最好侧重于讲解项目的概念,以及通过项目如何解决实际问题。当然也可以包含一些关于项目如何设计的内容,但要注意适度,通常大家不会太注意项目怎么实现。而更关注项目带来的价值。记住:只有产生了价值,项目才会成功。”

于是笔者就只能每周写一下周报,勉强维持生活这样子。

轮有轮样

新轮要有新轮的样子,“项目开张篇” 中介绍了本框架相关的基础理论和工作原理。鉴于相关的理论内容对于刚刚接触的读者较为生疏,因此本节将前文最为关键的内容罗列如下以激发读者的回忆。

Actor 特性一:Actor 的状态是通过外部调用 Actor 而改变的。

Actor 特性一补 1:Actor 的状态不与外部进行共享。

Actor 特性一补 2:外部可以读取 Actor 状态。

Actor 特性二:Actor 是 “单线程” 工作的,每次只能处理一个请求。

Actor 特性二补 1:并发读取状态可以不是 “单线程”。

框架定义的 Actor 类型——Claptrap:通过事件模式,产生事件并通过事件改变自身状态的 Actor。

框架定义的 Actor 类型——Minion:与 Claptrap 对比,Minion 不产生事件而是读取对应 Claptrap 的事件来改变自身的状态。允许存在多个 Minion 对应一个 Claptrap。

通过 Claptrap 和 Minion 配合完成 “转账” 业务。

月落大佬名言警句 1:世界上本也不存在 “银弹”。一套框架解决不了所有问题。
月落大佬名言警句 2:业务复杂度是不会因为系统设计变化而减少的,它只是从一个地方转移到了另外的地方。

还没轮影,先用轮跑

现在我们拥有了 Claptrap 和 Minion 的概念。接下来,结合一些业务场景,实验一下框架能否应对各种各样的业务需求。

再美的技术手段无法应对现实的需求与变化,那也只能技术花瓶。——刚刚学完赛博坦 XII 量子计算机指令集的月落

业务场景

这是一个简单的电商系统:

  1. 只卖一种绿色的水晶,为了方便描述,将这个商品命名为 “原谅水晶”。
  2. 用户可以使用自己账号中的余额购买原谅水晶。余额是通过外部支付系统充值进来的。充值部分,暂时不是业务场景需要考虑的。
  3. 每个用户还有一个积分,很巧,这个积分的图标也是绿色的,因此,将这个积分命名为 “原谅积分”。
  4. 原谅积分的获取方式有很多,例如:用户注册;邀请其他用户注册;被邀请用户进行了消费,邀请者也可以获得;原谅即挖矿;现实中获得了原谅;等等其他的一些方式,这部分可能需要配合后续的活动持续增加获得方式。
  5. 原谅积分可以在进行购买原谅水晶时,抵扣一部分需要支付的金额。
  6. 原谅积分在未来很可能有其他的用途。
  7. 购买原谅水晶的支付方式未来很可能不止余额和原谅积分两种。

以上就是对于这个电商系统的一部分需求描述。需求未来肯定是会变化的。

要素察觉

电商系统,最为主要的业务场景自然是和商品的交易有关的业务场景。不论其他的需求场景多么的复杂,交易相关的业务场景必然是首当其冲需要分析解决的。

那么首先,我们将 “用户确认购买原谅水晶” 这个场景用简单的语言描述一下程序需要执行的业务内容:

  1. 需要检查用户的余额是否足够
  2. 假如用户选择了积分抵扣,需要检查用户的积分是否足够
  3. 需要检查库存是否足够
  4. 需要扣减用户的余额
  5. 需要扣减库存
  6. 假如用户选择了积分抵扣,需要扣减用户的积分

如果采用直接操作数据表的方式实现以上六个要点,对于绝大部分开发者来说应该是十分简单的。开启一个数据库事务,至少具备行级锁,将数据进行检查和更新,便可以完成这个业务。那么现在使用本框架进行实现,根据
“业务复杂度不减少” 的基本事实,也同样需要实现以上六个要点。

未卜先知

首先,在不太讨论依据的前提下,笔者围绕上文提到的一些主体概念,设计了以下这些 Claptrap:

概念 英文命名 缩写 代表颜色
原谅水晶 SKU S ■■■■■
原谅积分 UserPoint P ■■■■■
用户余额 UserBalance B ■■■■■

依轱辘画轮

按照前篇的 “转账” 业务场景的流程设计,此处采用相同的方式设计一下购买的逻辑。如下图所示:

分析一下这个设计方案:

依照业务逻辑的顺序,完成了库存检查、库存扣减、余额检查、余额扣减、积分检查、积分扣减的业务步骤。

注意 Client 和 Claptrap S 之间的调用线的存在时间,只有在一开始的时候,也就是说,客户端仅需要稍作等待,便可以得到响应。

Claptrap S 将事件推送给 Minion S 之后便可以继续响应新的请求。确保了多个用户进行并发购买商品即确保了商品不会超卖,也确保了响应事件足够短。

整个业务逻辑的入口是 S、这样可以确保用户在锁定库存的前提下进行支付,避免了用户付了钱没有办法买到商品的情况。

基于形状上的原因,这种设计方案被命名为 “链形设计(Chain-Like Design)”

一样的材料,不一样的轮子

也存在另外一种设计方案。如下图所示:

分析一下这个设计方案:

引入了一个新的 Claptrap W(What a amazing that I get a forgiven-crystal)作为业务的入口,这个 Claptrap W 通过调用其他的 Claptrap 实现这个业务过程。

相比与上节的设计方案,Minion S、P、B 都不再参与业务的流转控制,因为这些业务的流转控制已经由 Claptrap W 进行控制。

并且由于 Minion W 的存在,这个设计方案也可以将部分的调用交由 Minion 来进行,所以这个方案也可以是以下两种形式。

基于形状上的原因,这种设计方案被命名为 “树形设计(Tree-Like Design)”

那么此处就出现了选择,既然有出现了选择,那么此处就使用《月老板的软件开发小妙招三十二则》中记载的 “WhyNot 对比分析法” 来决定使用哪种设计方案:

选项 为什么不? 为什么!不!
链形设计   业务流转过程的控制通过
Minion 相连接,这是一种紧耦合的设计。这相当于 Minion 和 Claptrap
这次操作业务的上下文。一个明显的问题:客户是否选择了积分支付,这个逻辑,要么在 Minion B 中判断,要么在 Claptrap P
中判断,但不论哪种方式其实都不合理。
这样的设计在应对流程失败的时候,会特别难以处理。例如在最后一步客户如果积分不足,那么可能就需要逐步回滚,这可能会非常困难。
树形设计 这种设计,把业务的核心流程控制内容集中的一对相关的 Claptrap W 和 Minion W 中。这是一种高内聚的表现。
基于这种设计方案,很容易基于 Claptrap S、P、B 构建出更加复杂的过程。

其实读者很容易发现,对于这个选择的 WhyNot 对比分析表,其实是一边倒的。这里明显就是要选择树形设计。

《月老板软件开发小妙招三十二则》,是月落大佬在日常开发过程当中对软件开发过程用到的一些小方法的收集和归纳。这些方法大多不是新发明的内容。月落大佬只是将这些方法收集在一起,为了启示后来者,在分析判断一些问题的时候,用一些小方法有时就能让事情变得有条理一些。除了
“WhyNot 对比分析法” 之外,还有较为知名的 “5W1H 需求描述法”;非常简单的“CheckList
备忘录”;被广泛提及的“艾森豪威尔法则” 等。

WhyNot
对比分析法,简单来说就是要讲选择多个主体进行并排对比,分别列举 “应该选择它”
和“不应该选择它”的理由,然后进行综合判断进而做出决定的方法。它特别适用于多人对某一选择争执不休时采用的方法,通过表格的形式分别记录陈述的理由,确保了不缺不漏有理有据。在方法上的基础,还衍生出了
“理由权重计量”、“人员话语权计量” 等其他的一些变种。此方法与 “优劣对比法”、“异同对比法” 等对比法,以及
“概率选择法”、“经验选择法” 等选择法有一定的联系与区别。此方法的命名据说是月落大佬首创,是一个语法梗。在中文当中,可以采用 “为什么不?”
这样的反问句来表示选择一个对象的理由,可以用 “为什么!不!” 这个的祈使句来表示不选择一个对象的理由。 WhyNot 其实就是对 “为什么不”
四个字的直译。

好轮子外观也好看

初见 WhyNot 对比分析法的读者可能会有疑问:难道就没有选择链形设计的理由?

需要解释的是, WhyNot 对比分析法是对固定场景的分析法,因此如果场景变了,分析的结果也会变。也就是说,在某些特定的场景下,链形设计有其必要性

那么在解释之前,我们采用另外的方法来解读链形设计与树形设计:

  • 将 Claptrap 和对应的 Minion 合并
  • 用 “因为… 所以…” 的句式来代替图形中的实线调用

那么结合上图的链形设计就可以表述为:

  • 因为 S,所以 B
  • 因为 B,所以 P

展开的语义可以是:

  • 因为购买而扣除了库存,所以进一步扣减余额
  • 因为购买而扣减了余额,所以要进一步扣减积分

上图树形设计就可以表述为:

  • 因为 W,所以 S
  • 因为 W,所以 B
  • 因为 W,所以 P

展开的语义可以是:

  • 因为购买,所以扣减了库存
  • 因为购买,所以扣减了余额
  • 因为购买,所以扣减了积分

即使笔者这里解释的不太清楚,但是读者仍然可以观察 “因为购买而扣减了余额,所以要进一步扣减积分” 这句其实不太合理,这两者在业务上其实不应该有明显的前因后果。

这其实也是链形设计在这个场景下不能适用的原因:如果两者的调用关系没有明显的前因后果,而将两者设计为前后调用的链形关系。那么很可能得到的是不合理的设计。

那么反过来说:如果要应用链形设计。两者之间必须存在合理的前因后果。

不过,在需求分析过程中,当前可能必然存在的前因后果,过后可能就已经不太合理。业务场景的多变和需求的不完全稳定,导致了事实上,采用树形设计能够应对更多的问题。

读者可以尝试对上文业务场景中剩余的几点需求进行一下设计。

另外,读者可以重新思考一下开张篇中所采用的 “转账” 场景的设计,采用树形设计是否更为妥当。

其实就是新轮子

在开张篇中,我们将 Actor 模式与 CRUD 模式进行了简单异同点比较。而现在还存在另外一类比较常提到的设计方案,就是 “领域驱动设计”。

领域驱动设计的概念此处不多做介绍,对此内容比较陌生的读者可以参看微软 MVP 汤雪华老师的文章《领域驱动设计之领域模型》

那么,当读者理解了领域驱动设计之后,再结合本篇前面提到的 Claptrap W、S、P、B。或许 Claptrap S、P、B 就是聚合根?或许 Claptrap W 就是应用服务?笔者认为 Actor 模式其实是对领域驱动设计的一种进一步发挥:

  • 领域驱动设计没有在设计模型内考虑业务并发,而 Actor 模式作为一套并发编程模型其实就弥补了这部分的缺失。
  • 绝大多数(笔者所知到的)领域驱动框架仍然采用了
    “从仓储还原聚合根,操作完毕后保存” 的一般过程。而以 Orleans 为例的 Actor 框架会将已经激活的 Actor
    在内存中保留一段时间,也就是说,聚合根可以在内存中不断的修改,而不需要重复的从仓储中还原。

总的来说,读者可以沿用领域驱动设计的思路建模,然后尝试将原有的聚合根和应用服务设计为 Actor ,从理论上尝试一下自己所熟悉的领域,能否采用 Actor 进行实现。或许读者可以从中发现一些不一样的体验。

不过,本框架由于采用了 Actor 模式和事件溯源模式,因此设计方法与领域驱动模型相比有所继承又不完全相同,还有一些其他需要注意的内容,会在后续整理出相应的文章。

结篇

本篇希望通过一个业务场景的设计,让读者了解到如何采用本框架的理论概念来实现业务。其中包含有一些作者的臆造词,因此可能需要花费读者更多的时间进行理解。

由于作者的工作经验有限,缺乏丰富的行业领域知识,因此对于框架的设计理念是否符合特定行业特性的问题无法给出准确的判断,还需要读者多加思考。若有任何需要协助的问题,欢迎联系本项目组。

欢迎对此感兴趣的朋友关注项目,参与项目。

以下是一些与项目有关的链接,欢迎读者查看:

.Net Actor 服务端开发框架,Newbe.Claptrap 项目周报 1 - 还没轮影,先用轮跑的更多相关文章

  1. Newbe.Claptrap - 一套以 “事件溯源” 和“Actor 模式”作为基本理论的服务端开发框架

    本文是关于 Newbe.Claptrap 项目主体内容的介绍,读者可以通过这篇文章,大体了解项目内容. 轮子源于需求 随着互联网应用的蓬勃发展,相关的技术理论和实现手段也在被不断创造出来.诸如 “云原 ...

  2. Vue+koa2开发一款全栈小程序(5.服务端环境搭建和项目初始化)

    1.微信公众平台小程序关联腾讯云 腾讯云的开发环境是给免费的一个后台,但是只能够用于开发,如果用于生产是需要花钱的,我们先用开发环境吧 1.用小程序开发邮箱账号登录微信公众平台 2.[设置]→[开发者 ...

  3. 服务端挂了,客户端的 TCP 连接还在吗?

    作者:小林coding 计算机八股文网站:https://xiaolincoding.com 大家好,我是小林. 如果「服务端挂掉」指的是「服务端进程崩溃」,服务端的进程在发生崩溃的时候,内核会发送 ...

  4. 轻松应对并发问题,Newbe.Claptrap 框架中 State 和 Event 应该如何理解?

    Newbe.Claptrap 框架中 State 和 Event 应该如何理解?最近整理了一下项目的术语表.今天就谈谈什么是 Event 和 State. Newbe.Claptrap 是一个用于轻松 ...

  5. Newbe.Claptrap 框架如何实现多级生命周期控制?

    Newbe.Claptrap 框架如何实现多级生命周期控制?最近整理了一下项目的术语表.今天就谈谈什么是 Claptrap Lifetime Scope. 特别感谢 kotone 为本文提供的校对建议 ...

  6. Newbe.Claptrap 框架如何实现 Claptrap 的多样性?

    Newbe.Claptrap 框架如何实现 Claptrap 的多样性?最近整理了一下项目的术语表.今天就谈谈什么是 Claptrap Design 和 Claptrap Factory. 特别感谢  ...

  7. Newbe.Claptrap 框架入门,第一步 —— 创建项目,实现简易购物车

    让我们来实现一个简单的 “电商购物车” 需求来了解一下如何使用 Newbe.Claptrap 进行开发. 业务需求 实现一个简单的 “电商购物车” 需求,这里实现几个简单的业务: 获取当前购物车中的商 ...

  8. 十万同时在线用户,需要多少内存?——Newbe.Claptrap 框架水平扩展实验

    Newbe.Claptrap 项目是笔者正在构建以反应式.Actor模式和事件溯源为理论基础的一套服务端开发框架.本篇我们将来了解一下框架在水平扩展方面的能力. 前情提要 时隔许久,今日我们再次见面. ...

  9. 谈反应式编程在服务端中的应用,数据库操作优化,提速 Upsert

    反应式编程在客户端编程当中的应用相当广泛,而当前在服务端中的应用相对被提及较少.本篇将介绍如何在服务端编程中应用响应时编程来改进数据库操作的性能. 开篇就是结论 接续上一篇<谈反应式编程在服务端 ...

随机推荐

  1. MySQL常用功能语句分类总结

    C(创建型功能) 创建数据库:CREATE DATABASE 创建用户:CREATE USER 用户名@主机 IDENTIFIED BY 密码; -- 如果想让该用户可以从任意远程主机登陆,可以使用通 ...

  2. 实现EventHandler的监测

    的监测", "category":"", "tags":"", "publish":&qu ...

  3. [翻译]NUnit---RequiredAddin and RequiresMTA Attributes(十六)

    RequiredAddinAttribute (NUnit 2.5) RequiredAddin特性用于提示一个程序集需要特殊的插件才能保证功能正常.如果没有安装插件,整个程序集会被标记为未运行. N ...

  4. [javascript]IIFE立即执行的函数表达式

    近况:最近一直忙着找实习没有更新,不过学习还是在继续的.最近在写Node.js又稍带把javascript的角落知识捡了一遍,过半个月打算去看看python和一些CSS深层的书和博客.工作找的还好,拿 ...

  5. Nginx an upstream response is buffered to a temporary file

    1.错误日志:warn:an upstream response is buffered to a temporary file 解决办法:增加fastcgi_buffers 8 4K;     fa ...

  6. 使用DbTableColumnWeb项目简要

    项目说明 环境:Vs2013 .Net4.5 MVC5 主要功能:直观编辑表字段说明:生成表对应的实体类:生成数据库表文档说明: 初衷:在开发过程中,经常会遇到同事询问表字段含义.手动编写表对应的实体 ...

  7. MaxScript调用DotNet时命名空间的问题

    Fn GetSpecialFolder argEnumName = (DotNetClass "System.Environment").GetFolderPath (Execut ...

  8. Unity实现一个morpher/blendShape

    using UnityEngine; using System.Collections; [RequireComponent (typeof (MeshFilter))] public class B ...

  9. CF特征码遍历

    HOOK_游戏代码 8B 00 8B 08 8B 91 A8 00 00 00 地址-15 4E5E954E5EA 44E5E95DIRECT 从733E00开始搜 6B 00 94 51 6C 地址 ...

  10. Django + DRF + Elasticsearch 实现搜索功能

    django使用haystack来调用Elasticsearch搜索引擎  如何使用django来调用Elasticsearch实现全文的搜索 Haystack为Django提供了模块化的搜索.它的特 ...