系统要求

C/S架构的单体桌面应用,可以满足客户个性化需求,易于升级和维护。相比于一代Winform,界面要求美观,控件丰富可定制。

解决方案

依托.Net6开发平台,采用模块化思想设计(即分而治之的策略),每个模块采用DDD分层设计。前端选用WPF + Prism 框架,后端选用ABP + EF框架,数据库选择SQL Server。

业务拆分

核心领域:包含用户管理、客户管理、表具管理、方案管理、抄表管理

通用领域:包含权限、菜单、个人中心、参数配置、审计日志、数据字典

支撑领域:包含数据查询、统计报表、消息管理、STS安全、工单、自动升级

业务建模

通过业务拆分,水务领域已经被划分为若干子领域(即模块)。每个模块可以看成是一个限界上下文,在此边界内可以进一步拆分更细粒度的单元(我们把最小的业务单元叫做聚合)。一个模块也可能只有一个聚合,如:数据字典。

先拿简单的用户管理来说,用户(User)、角色(Role)、组织(Organization)三者关系紧密、彼此协作。一个用户可以拥有多个角色,一个组织可以拥有多个用户,因此可以归属到用户界限上下文,它们既是实体又是聚合根。

再拿复杂一点的客户管理来说,客户可分为预付费和后付费两种。对于预付费客户来说,可以按量或按金额购水。对于后付费客户来说,每月会生成一笔月账单,客户需要及时充值,否则就会欠费。因此,在客户这个业务边界内,可以确定客户(Customer)、客户类型(CustomerType)、交易记录(Transactions)、月账单(MonthlyBilling)等领域对象。其中水费的计算是一个非常复杂的业务逻辑,涉及到阶梯价格、附加费、债务、当月历史售水交易等多个领域实体,所以需要借助领域服务来完成这笔交易。

系统设计

系统设计包含两部分:全局设计局部设计

全局设计是从框架角度来进行整体设计。系统框图如下:

虚线框部分为笔者设计的Lapis.Framework框架,文件组织结构如下:

其中,Laison.Lapis.XXX文件夹代表基础业务模块(Laison.Lapis.Shared除外),如:审计日志、消息管理等,每个模块就是一个独立的C#解决方案。Laison.Lapis是一个底层类库,封装各种通用基础功能,供上层调用。Laison.Lapis.Shared称之为共享模块,用于封装和业务无关,可以被业务模块共享使用的功能,如: 抽象基类、接口、虚方法等。因为是单体应用设计,所以模块之间少不了相互引用的关系。模块划分越多,引用关系也会变得越复杂。

局部设计是从业务角度来进行模块设计,每个模块按照DDD来分层:基础设施层、领域层、应用层和表现层。下面是用户管理模块(Laison.Lapis.Identity)的分层设计:

Laison.Lapis.Identity.UI:表现层,包含前端页面、控件和一些UI逻辑。
     Laison.Lapis.Identity.Application.Contracts:应用接口层,负责定义应用接口和DTO。
     Laison.Lapis.Identity.Application:应用层,用于实现应用接口,包含各种应用逻辑。
     Laison.Lapis.Identity.Domain:领域层,负责业务逻辑处理,包含实体、值对象、仓储接口等领域模型。
     Laison.Lapis.Identity.Domain.Shared:领域共享层,包含了一些枚举和常量的定义,可供其它任意层调用。
     Laison.Lapis.Identity.EntityFramework:实体框架层(EF),包含实体的映射配置和仓储的实现。
     Laison.Lapis.Identity.HttpApi.Host 和 Laison.Lapis.Identity.Shell:即宿主和壳,分别用来启动前/后端应用程序。

在ABP框架的世界里,每一分层就是一个模块单元,它是代码层面的模块,而Identity是业务层面的模块,后者包含前者,最终以DLL的形式来呈现。

系统如何运行

每个模块负责自己的业务功能,各司其职,又彼此依赖。模块划分越细,内聚性越强,代码的复用性就越高。 当系统要完整运行所有功能时,只需要像搭积木一样,把各个模块进行组装就行,做到即插即用。为了方便代码复用和管理,笔者采用Nuget包的形式将业务模块引入到项目中使用,这在开发初期似乎没有什么问题。

但随着系统不断迭代,模块数量也再随之增长。假设1个模块会生成6个DLL(采用DDD分层),那么20个模块就会有120个DLL,听上去有点吓人。每次模块发生变化,就要重新打包、发布、升级120个Nuget包,这显然不符合常理(非常耗时)。后来笔者采取了一种折中的处理方式:将通用稳定性强的模块保留在Lapis.Framework中,把易于变化的模块下沉到项目中管理,这样就能避免之前的尴尬,但却牺牲了模块代码的复用性。项目最终代码结构如下:

个性化定制

企业个性化功能定制是一个普遍而又绕不开的话题,假如能用一套代码把所有客户的需求全部覆盖,当然是最理想的状态(现实几乎不可能,除非通用标准化)。所以笔者从设计一开始就是围绕如何提高代码的复用,将差异化分散到项目中的思路来展开,这也是采用模块化设计的初衷。至于个性化如何来实施?根据笔者已知的做法有以下两种:1. 通过版本管理开分支的方式,2. 简单粗暴,每个项目都单独复制一套标准版,然后在上面做定制化修改。 除此之外,笔者似乎没有想到更好的办法。至于选择哪一种,就要根据项目实际情况来考量。

结束语

无论是模块化设计还是DDD,都是强调从业务领域角度出发,根据业务的发展,合理划分业务边界,采用分治策略,降低业务和软件开发的复杂度,持续调整现有架构,以保持架构和代码的生命力。 因此,世界上并不存在一劳永逸的架构,软件设计本身就是一个平衡取舍的过程,只有合适的才是最好的,这也许就是架构设计的魅力所在吧!如果你有好的建议或不同想法,欢迎评论区留言。

二代水务系统架构设计分享——DDD+个性化的更多相关文章

  1. 万级TPS亿级流水-中台账户系统架构设计

    万级TPS亿级流水-中台账户系统架构设计 标签:高并发 万级TPS 亿级流水 账户系统 背景 业务模型 应用层设计 数据层设计 日切对账 背景 我们需要给所有前台业务提供统一的账户系统,用来支撑所有前 ...

  2. 基于Struts2,Spring4,Hibernate4框架的系统架构设计与示例系统实现

    笔者在大学中迷迷糊糊地度过了四年的光景,心中有那么一点目标,但总感觉找不到发力的方向. 在四年间,尝试写过代码结构糟糕,没有意义的课程设计,尝试捣鼓过Android开发,尝试探索过软件工程在实际开发中 ...

  3. 新零售SaaS架构:多租户系统架构设计

    什么是多租户? 多租户是SaaS领域的特有产物,在SaaS服务中,租户是指使用SaaS系统的客户,租户不同于用户,例如,B端SaaS产品,用户可能是某个组织下的员工,但整个企业组织是SaaS系统的租户 ...

  4. PetShop的系统架构设计

    <解剖PetShop>系列 一.PetShop的系统架构设计 http://www.cnblogs.com/wayfarer/archive/2007/03/23/375382.html ...

  5. petshop4.0 具体解释之中的一个(系统架构设计)

    前言:PetShop是一个范例,微软用它来展示.Net企业系统开发的能力.业界有很多.Net与J2EE之争,很多数据是从微软的PetShop和Sun的PetStore而来.这样的争论不可避免带有浓厚的 ...

  6. NET ERP系统架构设计

    解析大型.NET ERP系统架构设计 Framework+ Application 设计模式 我对大型系统的理解,从数量上面来讲,源代码超过百万行以上,系统有超过300个以上的功能,从质量上来讲系统应 ...

  7. Unity3D手游开发日记(2) - 技能系统架构设计

    我想把技能做的比较牛逼,所以项目一开始我就在思考,是否需要一个灵活自由的技能系统架构设计,传统的技能设计,做法都是填excel表,技能需要什么,都填表里,很死板,比如有的技能只需要1个特效,有的要10 ...

  8. 图数据库 Nebula Graph 的数据模型和系统架构设计

    Nebula Graph:一个开源的分布式图数据库.作为唯一能够存储万亿个带属性的节点和边的在线图数据库,Nebula Graph 不仅能够在高并发场景下满足毫秒级的低时延查询要求,而且能够提供极高的 ...

  9. 5G 融合计费系统架构设计与实现(一)

    5G 融合计费系统架构设计与实现(一) 随着5G商用临近,5G的各个子系统也在加紧研发调试,本人有兴全程参与5G中的融合计费系统(CCS)的设计.开发.联调工作.接下来将用几篇文章介绍我们在CCS实现 ...

  10. [转]【转】大型高性能ASP.NET系统架构设计

    大型高性能ASP.NET系统架构设计 大型动态应用系统平台主要是针对于大流量.高并发网站建立的底层系统架构.大型网站的运行需要一个可靠.安全.可扩展.易维护的应用系统平台做为支撑,以保证网站应用的平稳 ...

随机推荐

  1. 【HTML-CSS】div中加入icon后input标签占用不满问题

    做登录表单时遇到了一个宽度控制不好的问题,放入图标后,input框总是无法正确的填满剩余空间(尺寸过大/过小) 原因是input元素和父元素div宽度都写死的问题 把父元素的高度删除,宽度改成max- ...

  2. 2021-09-09:企鹅厂活动发文化衫,文化衫有很多种,企鹅们都穿文化衫。采访中,企鹅会说还有多少企鹅跟他穿一种文化衫。有些企鹅没被采访到,将这些回答放在answers数组里,返回活动中企鹅的最少数

    2021-09-09:企鹅厂活动发文化衫,文化衫有很多种,企鹅们都穿文化衫.采访中,企鹅会说还有多少企鹅跟他穿一种文化衫.有些企鹅没被采访到,将这些回答放在answers数组里,返回活动中企鹅的最少数 ...

  3. flask之数据模型flask-sqlalchemy

    一.安装数据库连接依赖包 pip install flask-sqlalchemy pip install pymysql 二.项目配置 app/__init__.py from flask_sqla ...

  4. yaml的读写

    yaml文件的读写是真的快,也很简单.代码如下:from ruamel.yaml import YAMLimport os # 读取yaml配置文件def read_yaml(yaml_path): ...

  5. 手把手实践丨基于STM32+华为云设计的智慧烟感系统

    摘要:当前基于STM32和华为云,设计了一种智慧烟感系统,该系统可以检测烟雾,同时将检测到的数据上传到云端进行处理和分析. 本文分享自华为云社区<基于STM32+华为云设计的智慧烟感系统> ...

  6. P1585 魔法阵 题解

    题意: 题目传送门 可以看做一个人手中有一些宝石,并将宝石分成两组,一组的编号为 1 至 n×m/2,二组为 n×m/2+1 至 n×m+1.当两组两个宝石编号相差为 n×m/2 为一对.现在要遍历一 ...

  7. Solon 成为信通院可信开源社区、可信开源项目

    自2021年9月17日成立以来,可信开源社区共同体共有五批新成员加入.在4月21日"OSCAR开源生态建设论坛"上,可信开源社区共同体又迎来2位正式成员和6位预备成员,Solon ...

  8. 前端Vue自定义导航栏菜单 定制左侧导航菜单按钮 中部logo图标 右侧导航菜单按钮

    前端Vue自定义导航栏菜单 定制左侧导航菜单按钮 中部logo图标 右侧导航菜单按钮, 下载完整代码请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin? ...

  9. Java使用数组存储成绩,输出成绩列表,总分,平均分

    代码如下: public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out. ...

  10. Blazor前后端框架Known-V1.2.2

    V1.2.2 Known是基于C#和Blazor开发的前后端分离快速开发框架,开箱即用,跨平台,一处代码,多处运行. 概述 基于C#和Blazor实现的快速开发框架,前后端分离,开箱即用. 跨平台,单 ...