微信号:infoqchina

介绍:有内容的技术社区媒体

中小研发团队架构实践之如何统一公司所有应用分层?

2017-10-15 09:00 张辉清
作者|张辉清
编辑|小智
社区里不是缺少架构图,而是缺少确实可参考的架构落地实践。大公司的架构看上去总是不明觉厉,但真要借鉴时却往往无从下手。也许,中小型研发团队的架构实践才是可供复制的?本文是张辉清专栏——《中小研发团队架构实践》的第三篇,今天我们来聊聊如何统一公司所有应用分层。
系列文章附录

以下文章点击标题即可阅读

写在前面

应用分层这件事情看起来很简单,但每个程序员都有自己的一套,哪怕是初学者。如何让一家公司的几百个应用采用统一的分层结构,并得到大部分程序员的认同,这可不是件简单的事情。有两个问题与大家一起探讨:

  1. 服务的调用代码你觉得放到哪一层好呢?A 表现层;B 业务逻辑层;C 数据层;D 公共层。

  2. 如何组织好 VO(View Object 视图对象)、BO(Business Object 业务对象)、DO(Data Object 数据对象)、DTO(Data Transfer Object 数据传输对象) 呢?

不同的人会有不同的答案,所以要统一公司应用分层,以减少开发维护学习成本。统一应用分层要可大可小、简单易用、支持多种场景,我们采用 IPO 方式:I 是 Input、O 是 Output、P 是 Process,一进一出一处理。应用系统的本质是机器,是处理设备,一进一出一处理。

IPO 原理图

统一逻辑架构

统一应用分层的逻辑架构图

职责说明:



  • 文件夹分层法:应用分层采用文件夹方式的优点是可大可小、简单易用、统一规范,可以包括 5 个项目,也可以包括 50 个项目,以满足所有业务应用的多种不同场景;

  • 调用规约:在开发过程中,需要遵循分层架构的约束,禁止跨层次的调用;

  • 下层为上层服务:以用户为中心,以目标为导向。上层(业务逻辑层)需要什么,下层(数据访问层)提供什么,而不是下层(数据访问层)有什么,就向上层(业务逻辑层)提供什么;

  • 实体层规约:DO 是数据表对象,不是数据访问层对象,不是只能给数据访问层使用;DTO 是网络传输对象,不是表现层对象,不是只能给表现层使用;BO 是内存计算逻辑对象,不是业务逻辑层对象,不是只能给业务逻辑层使用 。如果仅限定在本层访问,则导致单个应用内大量没有价值的对象转换。以用户为中心来设计实体类,可以减少无价值重复对象和无用转换;

  • U 型访问:下行时表现层是 Input,业务逻辑层是 Process,数据访问层是 Output。上行时数据访问层是 Input,业务逻辑层是 Process,  表现层就 Output。

具体规范说明

接下来将借用由本文提供下载的 TripOrderService、TripSellerMVCSite 这两个 Demo 来进行具体规范的说明,以下是截图:

项目名称的命名规则

项目名称的命名规则是:{产品线英文名全称}.{子系统英文名全称 + 应用名}.{项目职责英文名全称},如:Trip.Seller.Business。

业务逻辑层的项目规范

规范说明:

  1. 项目名的命名规则:{产品线英文名全称}.{子系统英文名全称 + 应用名}.Business,如上图的 Trip.Order.Business。

  2. 类名以 Logic 结尾,如上图的 OrderLogic.cs。

数据操作项目规范

规范说明:

  1. 各数据操作项目名根据使用什么数据库进行分类,然后以 DB 为结尾,具体命名规则是:{产品线英文名全称}.{子系统英文名全称 + 应用名}.{使用什么数据库}DB,如上图的 Trip.Seller.MSSQLDB。

  2. 如果涉及到多个数据库访问的,那么数据操作项目下的类文件需要按数据库名称(以 DB 为结尾)创建文件夹分开,如上图的 TripOrderDB 文件夹。

  3. 建议在应用中使用 SQL 语句,不使用存储过程。在数据库中不新增存储过程,但旧的存储过程可以继续使用和修改。

  4. 分页建议使用数据库(如 SQLServer)的最新特性进行分页,并将每个分页 SQL 直接写到应用中。

实体类项目规范
数据对象 DO 规范

规范说明:

  1. DO 项目名的命名规则:{产品线英文名全称}.{子系统英文名全称 + 应用名}.Entity,如上图的 Trip.Seller.Entity;

  2. 如果涉及到多个数据库访问的,那么需要按数据库名称(以 DB 为结尾)创建文件夹分开,如上图的 TripOrderDB 文件夹;

  3. 表名 +Entity 结尾,如上图的 OrderEntity.cs;

  4. DO 是数据表对象,供单表 CURD 操作。对于多表查询请求对象和返回对象,可定义新对象或使用现有对象(DTO/BO)来完成。

业务对象 BO 规范

BO 实体类名以 Model 为结尾:

数据传输对象 DTO 规范

规范说明:

  1. DTO 项目名的命名规则:{产品线英文名全称}.{子系统英文名全称 + 应用名}.DTO,如上图的 Trip.Order.DTO。

  2. 请求参数 DTO 实体类、响应 DTO 实体类存放规范以及其命名规则:

    • 请求参数 DTO 实体类放在 Request 文件夹下,且命名规则为:以 Request 结尾,如上图的 SearchOrderRequest.cs。

    • 响应 DTO 实体类放在 Response 文件夹下,且命名规则为:以 Response 结尾,如上图的 SearchOrderResponse.cs。

    • 如果请求参数 DTO 实体类或响应 DTO 实体类的属性中有对象或枚举,那么这些对象所属的类、枚举放在 DTO 项目的 Common 文件夹下。

  3. 如果请求参数 DTO 实体类、响应 DTO 实体类有基类要继承,那么建议为基类取名为 RequestBase.cs、ResponseBase.cs。且这些基类直接放在 DTO 项目的 Common 文件夹下。

视图对象 VO 规范

规范说明:

  1. VO 项目名的命名规则:{产品线英文名全称}.{子系统英文名全称 + 应用名}.ViewModel,如上图的 Trip.Seller.ViewModel。

  2. 各 VO 实体类,我们用 Controller 名作为文件夹名进行分开,如上图的 Order 文件夹。

  3. VO 实体类名的命名建议:

    • 请求参数 VO 实体类以 Input/Form/Query 结尾,如上图的 SearchOrderInput.cs。

    • 响应 VO 实体类以 Output/List/Result 结尾,如上图的 SearchOrderOutput.cs。

数据库连接配置规范

规范说明:

  1. 数据库连接的配置必须读写分离。

  2. 数据库连接字符串建议加密处理。

  3. 数据库连接配置名的命名规则:{以 DB 为结尾的数据库名称}_ 读写类型,如:TripOrderDB_SELECT、TripOrderDB_INSERT。

配置文件方面的规范

规范说明:

  1. 所有配置文件(除 Web.config 文件外)都必须放到 Config 文件夹下。

  2. 所有配置文件(除 Web.config 文件外)按不同环境区分开,具体命名规则是:{功能模块英文名}.{环境英文简称名}.config,其中本地环境的英文简称名是 Dev,测试环境的英文简称名是 Test,正式环境的英文简称名是 Prod,如上图的 AppSetting.Dev.config。

  3. 保持 Web.config 配置文件的干净,只留环境设置节点。

静态资源文件方面的规范

规范说明:

  1. 公共的静态资源文件(css、js、image 等)放在另外的静态站点中,统一由前端进行开发和维护。一般,css 文件放在 css 文件夹下,js 文件放在 js 文件夹下,image 图片文件放在 img 文件夹下。

  2. 与某项业务有关的 js 文件可以放到各自业务项目的表现层 PresentationLayer 下,以方便开发人员调试,js 文件可放在项目的 js 文件夹下。

  3. 静态资源文件必须使用版本号管理,以防更新后由于客户端浏览器缓存而导致站点使用的依然是旧版本的静态资源文件:

<script src="~/js/order.js?v=@AppSetting.StaticFileVersion"></script>

写在最后
问题回答
问:服务的调用代码应该放到哪一层呢?

A 表现层、B 业务逻辑层 、C 数据层、D 公共层。

答: 我们的规范是统一放到数据资源访问层即 C。上层提供服务,下层调用服务,中间处理业务逻辑。

问:如何组织好 VO(View Object 视图对象)、BO(Business Object 业务对象)、DO(Data Object 数据对象)、DTO(Data Transfer Object 数据传输对象) 呢?

答: 通常有两种做法,限定访问范围和不限定访问范围,可根据需要选择或折中。我们使用后者,将 EntityLayer 作为通用对象放到左侧,具体可参考实体层规约:“DO 是数据表对象,不是数据访问层对象,不是只能给数据访问层使用;DTO 是网络传输对象,不是表现层对象,不是只能给表现层使用;BO 是内存计算逻辑对象,不是业务逻辑层对象,不是只能给业务逻辑层使用 。如果仅限定在本层访问,则导致单个应用内大量没有价值的对象转换。以用户为中心来设计实体类,可以减少无价值重复对象和无用转换。”

问:应用分层范例代码在编写时需要注意些什么?

答: 应用分层范例代码要想写好,非常不容易,需要注意三点:

  1. 应用分层范例的主要价值是明确层的职责和交互,每个层要干什么,哪些要干,哪些不要干,以及层与层之间交互;

  2. 减少通用帮助类的编写,如果每一个应用中都有这些类,这在架构层面上是有问题。在我们几百个线上应用中,也是如此:没有分页帮助类、数据库帮助类、缓存帮助类、MQ 帮助类,没有日志帮助类,没有 AOP 帮助类。业务应用的重点是为业务服务,每一个应用都是特别的,大都需要定制,极少有通用的代码,如果有,那应该是框架或组件;

  3. 少即可多。应用的场景特别多,参考人员多,时间长,所以只能做大家都认同的规范、正确的事情,要减少有争议的代码范例,否则一个错误将会放大百倍,一个争议的规范将会很落地。

Demo 下载

LayerDemo 下载地址:

https://github.com/das2017/LayerDemo

大新闻,倒计时 2 天!

作者介绍

张辉清,10 多年的 IT 老兵,曾携程架构师、古大集团首席架构师、中青易游 CTO,主导过两家公司的技术架构升级改造工作。现关注是架构与工程效率,技术与业务的匹配与融合,技术价值与创新。

今日荐文

点击下方图片即可阅读

为什么 Python 发展得如此之快?


 
InfoQ 更多文章 Q新闻丨grpc-java 1.7.0 发布;GitHub发布2017年度数据报告;阿里云发布多款产品,降价 为什么Python发展得如此之快? 当技术为组织所累时怎么办?将你的组织架构旋转90度! 许式伟:我与Go语言的这十年 月活超美国人口十分之一,各大科技巨头纷纷布局,智能音箱背后有何门道?
猜您喜欢 如何打造公司级公共前端团队 29 个你必须知道的 Linux 命令 被“妖魔化”的数据分析 MapReduce 原理与 Python 实践 去大公司,还是小公司?