軟體分層架構模式

軟體分層架構模式 - 基本分層

最近在重構六年前做的產品,雖然當時已經有做分層架構,但還是有很多該改進的地方。
有些命名越看越不順眼,重構期間順便整理一下分層架構;不管在何時回頭看自己做的東西,都覺得很多進步空間。
本篇介紹一下常見的軟體分層架構模式 (Software Layered Architecture Pattern),以及推薦的命名方式。

分層架構簡介

基本分層

基本分層架構模式主分為:

  • 展示層 (Presentation Layer)
    • UI 互動相關的部分
  • 業務層 (Business Layer)
    • 處理業務邏輯的部分
  • 資料層 (Data Layer)
    • 處理資料存取的部分

在 Software Architecture Patterns – O’Reilly 書中 資料層 (Data Layer) 被分為 Persistence Layer 及 Database Layer,我個人比較喜歡 Microsoft Application Architecture Guide 用 Data Layer 的命名方式。畢竟資料來源不一定是資料庫,也可能是外部的 Services。

分層架構有一個很重要的特性,就是要把每一層的職責分離,不應該跨層互動,每層之間的關係只能是上下互動。
如圖:

軟體分層架構模式 - 基本分層

服務型分層

上述的三層為了做到職責分離,只能層層互動,卻缺少了一些彈性。如果要提供 API 給外部使用,就處於比較尷尬的位置;不屬於展示層,比較偏向業務層,但業務層直接打破隔離方式供人使用也怪怪的。
所以如果是服務型 (Service-Based) 的系統,會建議多出一層:

  • 服務層 (Service Layer)
    • 負責把封閉的分層開放給外部使用。

如圖:

軟體分層架構模式 - 服務型分層

命名方式

從網路上可以找到很多不同風格的命名方式,此章節只是我整理出我喜歡的命名風格,如果還沒有命名頭緒的話可以參考看看。 我大部分時間都是在開發 ASP.NET MVC/WebAPI2 所以會以 .NET 專案 為例。

Domain Project

專案相依:不應該相依於其他專案。
專案名稱:CompanyName.ProjectName.Domain

這個專案主要是用來分離各層相依關係的,內容含如下:

建議的命名範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// DTO 範例
// Class 命名規則:不後綴 Entity。  
namespace CompanyName.ProjectName.Domain.Entities
{
  public class User {
    // ...
  }
}

// Enum 範例
// Class 命名規則:不後綴 Enum。 
namespace CompanyName.ProjectName.Domain.Enums
{
  public enum UserStatus {
    // ...
  }
}

Data Layer

專案相依:CompanyName.ProjectName.Domain
專案名稱:CompanyName.ProjectName.DataLayer

常見的命名有:UserDAL、UserEngine、UserManager、UserRepository 等。

DAL 全名 Data Access Layer,名稱應該是從 3-tier Architecture with ASP.NET 2.0 誕生出來的。

建議的命名Class 命名規則:名稱加上後綴 Manager
如果有用 Repository Pattern,就在 Class 名稱加上後綴 Repository
範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Class 命名規則:加上後綴 Manager。 
namespace CompanyName.ProjectName.DataLayer.Managers
{
  public class RedisManager : IRedisManager {
    // ...
  }
}

// Repository Pattern 範例。 
// Class 命名規則:加上後綴 Repository 
namespace CompanyName.ProjectName.DataLayer.Repositorys
{
  public class UserRepository : IUserRepository {
    // ...
  }
}

Business Layer

專案相依:CompanyName.ProjectName.Domain 及 CompanyName.ProjectName.DataLayer 專案名稱:CompanyName.ProjectName.BusinessLayer

常見的命名有:UserBLL、UserLogic 等。

BLL 全名是 Business Logic Layer,名稱出現同 DAL。

建議的命名:Class 名稱加上後綴 Logic

網路上非常多的範例適用 BLL,尤其是 ASP.NET 的範例。
但我不推用 BLL 的原因是,Class 名稱出現連續的全大寫,看久了有點不舒服,還是比較習慣 Pascal Case

範例:

1
2
3
4
5
6
namespace CompanyName.ProjectName.BusinessLayer.Logics
{
  public class UserLogic : IUserLogic {
    // ...
  }
}

Service Layer

專案相依:CompanyName.ProjectName.Domain 及 CompanyName.ProjectName.BusinessLayer

API Library

由於 Service Layer 是屬於對外開放的接口,所以我並沒有特別推薦命名方式,不要太突兀就好。
可以參考許多第三方套件的 API 命名方式,例如常見的 Newtonsoft.Json

1
var json = Newtonsoft.Json.JsonConvert.SerializeObject(new { });

JsonConvert 就沒有特別加什麼後綴,用比較直觀式的命名方式,讓使用方容易懂就好。

Web API

專案如果是 Web API,我會直接取名為 CompanyName.ProjectName.WebService
命名方式建議使用 RESTful 風格,用起來比較乾淨俐落,好處可以參考 Wiki。

前陣子有人問我:

如果把 Web API 符合 RESTful,是不就變成 Data Layer 了?

這兩個層級的職責是完全不一樣的:

  • Service Layer:提供資源給外部使用,負責轉手資料。
  • Data Layer:負責提供及存取 Business Layer 收送的資料。

但如果從另一個角度來看,對調用方來說,Web API 也是它的 Data Layer,把 Web API 符合 RESTful 只是為了讓調用方更容易使用。

Presentation Layer

專案相依:CompanyName.ProjectName.Domain 及 CompanyName.ProjectName.ServiceLayer (或 CompanyName.ProjectName.BusinessLayer ) 專案名稱:CompanyName.ProjectName.Website

以 Web 專案來說,這層是屬與 HTML、jQuery 或 Angular 這類的前端框架。
如果有用前端框架,命名方式就依照該框架建議的指南命名。

如果是純前端框架,其實根本不用相宜於任何專案,是以 Web API 作為相依關係。

範例架構

專案相依關係:

軟體分層架構模式 - 專案相依關係

檔案架構大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
CompanyName.ProjectName.Domain/         # Domain 專案
  Entities/
    User.cs
  Enums/
    UserStatus.cs
  Interfaces/                           # 分層隔離用到的介面
    Logics/
      IUserLogic.cs
    Managers/
      IRedisManager.cs
    Repositorys/
      IUserRepository.cs

CompanyName.ProjectName.DataLayer/      # Data Layer 專案
  Managers/
    RedisManager.cs
  Repositorys/
    UserRepository.cs

CompanyName.ProjectName.BusinessLayer/  # Business Layer 專案
  Logics/
    UserLogic.cs

CompanyName.ProjectName.WebService/     # Service Layer 專案
  Controllers/
    UserController.cs

CompanyName.ProjectName.Website/        # Angular 為例
  index.html                            # 起始頁面
  app/                                  # Angular 的主要目錄
    main.ts                             # bootstrap 的程式進入點

參考

Software Architecture Patterns – O’Reilly Media(推薦閱讀)
Chapter 5: Layered Application Guidelines – Microsoft Application Architecture Guide
Naming conventions DAL, BAL, and UI Layer
應用程式的分層設計 (1) – 入門範例

.NET Core全面扫盲贴

标签: .NETCore Asp.NETCore


1. 前言

.NET发行至今已经过了十四个年头。随着版本的不断迭代更新,.NET在Windows平台上的表现也是越来越好,可以说Windows平台上所有的应用类型.NET几乎都能完成。

只是成也Windows,败也Windows,这十四年来,除了部分“民间”版本,.NET一直没能在官方支持下摆脱Windows平台的局限,“开源”和“跨平台”这两个词语也是所有.NET开发者心中的痛楚。最终,.NET Core出现了,它让开发者们在官方和社区的支持走出了Windows,可以在macOS,Linux主流distributions上编写调试并部署.NET程序。

2. .NET Core 简介

2.1 .NET Core是什么

.NET Core是一个开源通用的开发框架,支持跨平台,即支持在Window,macOS,Linux等系统上的开发和部署,并且可以在硬件设备,云服务,和嵌入式/物联网方案中进行使用。.NET Core的源码放在GitHub上,由微软官方和社区共同支持。

它和传统的.NET Framework,属于“子集—超集”的关系,或者你也可以简单地认为它就是.NET Framework的跨平台版本(基于BCL的层面上看)。这是因为在当前版本中(1.0),.NET Core中的大部分核心代码都是从.NET Framework中继承重写的,包括Runtime和Libraries(如GC, JIT, 部分类型)。

吐槽:只能感谢微软《CLR via C#》不用白看呀,我之前看了得有小半年才看完

现在的.NET Core 1.0版本是一个很小的核心,APIs和工具也并不完整,但是随着.Net Core的不断完善,补充的Apis和创新也会一起整合到.NET Framework中。也就是说,.NET Core微软会同时更新.NET Framework和.NET Core,他们就像俩兄弟,共同努力致富(致谁的富?当然是.NET开发者们),实现所谓的天下大同,也就是.NET 标准2.0

这里不得不提到一个叫做.NET Standard Library概念。作为.NET平台APIs开发官方支持标准,它要求所有的.NET框架APIs都遵循向下兼容。比如说.NET Framwork 4.6支持.NET Standard Library 1.3,.NET Framwork 4.6.2框架支持.NET Standard Library 1.5,而.NET Core 1.0框架支持1.6标准。

最终展望如下:

2.2 .NET Core的组成

  • .NET Runtime
    CoreCLR。如之前所说,CoreCLR与.NET Framework的CLR并没有什么区别,进程管理,GC,JIT(RyuJIT 编译器)这些部分也都是一样的,只是针对服务器系统做了相应优化。现在CLR和CoreCLR也在进行同步更新,只是可以肯定的是,CoreCLR才是.NET的未来,CLR将作为兼容手段而存在
  • Framework Libraries,
    CoreFX。包括集合类,文件系统处理类,XML处理类,异步Task类等
  • SDK Tools 和 Language Compilers (SDK工具和编译器)
    CLI工具和Roslyn编译器。可以通过.NET Core SDK(.NET Core开发工具包)获取。
  • dotnet’app host
    用来选取并执行对应运行时,提供组件载入原则和启动.NET Core应用程序。SDK也是通过相同程序启动。

    Tips:是不是想起了MSCorEE.dll这个垫片,它同样承载着Windows平台上为.NET应用程序选择CLR版本的工作

2.3 .NET Core的特性

  • 跨平台
    可以在Windows,macOS,Linux上运行
  • 灵活的部署机制

1.Portable applications(便携式应用)
这种部署机制和传统的.NET Framework相似,只要目标平台上存在.NET Core Runtime即可。

2.Self-contained application(自宿主应用)
顾名思义,这种部署机制将应用和运行时共同打包,即便目标平台上没有安装.NET Core Runtime也能正常使用

第二种方式和.NET Native也是不一样的,仍然使用CoreCLR,而.NET Native使用CoreRT作为运行时,详细信息请见dotnet/corert

  • 命令行工具
    .NET程序所有的运行脚本都可以用命令行工具执行(cmd,bash)这里有几个常见的donnet命令
指令 帮助
dotnet new 产生新的基本 .NET 项目内容 (包含 project.json、Program.cs 以及 NuGet.config
dotnet restore 还原所参考的 NuGet 包
dotnet build 建造 .NET 项目
dotnet publish 产生可发行的 .NET 项目 (包含所属的 Runtime)
dotnet run 编译与立即运行 .NET 项目 (较适用于 exe 型项目)
dotnet repl 引导交互式的对话
dotnet pack 将项目的产出封装成 NuGet 包
  • 兼容性
    通过.NET Standard Library与.NET Framework,Xamarin,Mono兼容
  • 开源
    .NET Core从属于.NET基金会,由微软进行官方支持。使用MIT和Apache 2开源协议,文档协议遵循CC-BY

2.4 开发语言

.NET Core 1.0版本中支持的变成语言仅有C#(F#和VB暂未实现),这里还要提到一个开源的语言编译器Roslyn,它负责将代码编译成我们熟悉的IL语言,然后再借由AOT或JIT编译器编译成机器熟悉的机器语言。

3. Get Started

以下内容演示在Windows10和CentOS 7.2下的命令行生成和发布demo

3.1 Win 10

3.1.1 安装.NET Core SDK.NET Core Runtime

.NET Core SDK = 使用.NET Core开发应用.NET Core Runtime 和 SDK+CLI 工具

3.1.2 简单的运行结果

打开cmd,依次输入mkdir .project(创建目录),cd .\.project(进入目录),dotnet new(新建初始项目),dotnet restore(还原依赖),dotnet run(运行)即可运行第一个Hello World程序

3.2 CentOS 7.2(本地Hyper-V)

3.2.1 安装和运行

详情请见:.NET Core in CentOS,大致命令如下

sudo yum install libunwind libicu   #安装libunwind,libicu包

curl -sSL -o dotnet.tar.gz https://go.microsoft.com/fwlink/?LinkID=809131 #下载dotnet-dev-centos-x64.1.0.0-preview2-003121.tar文件,有时会因为网络问题下载较慢,耐心等待即可,当然也可以手动下载后放到目录下。

sudo mkdir -p /opt/dotnet && sudo tar zxf dotnet.tar.gz -C /opt/dotnet #创建目录并解压已下载文件
sudo ln -s /opt/dotnet/dotnet /usr/local/bin #将目录链接到$PATH下,否则dotnet命令无法识别

mkdir hwapp
cd hwapp

dotnet new #创建默认.NET Core应用
dotnet restore #还原依赖包
dotnet run #运行,结果将显示Hello World!

第六行命令后可使用dotnet –info查看是否链接成功,显示如下

.NET Command Line Tools (1.0.0-preview2-003121)

Product Information:
 Version:            1.0.0-preview2-003121
 Commit SHA-1 hash:  1e9d529bc5

Runtime Environment:
 OS Name:     centos
 OS Version:  7
 OS Platform: Linux
 RID:         centos.7-x64

以上步骤在.NET Core官方网站都可以找到,可以看到应用在经过简单的dotnet new, dotnet restore, dotnet run命令后就跑起来了,但是这其实是类似于开发环境中的调试运行,而且win上new的应用此时也不能直接跨平台到Linux下运行,所以我们又得提到dotnet publish命令了

3.2.2 Self-contained applications 发布

(1) 修改project.json文件

我们现在win10下按照步骤new一个新的HW控制台应用self,按照官方文档要求,我们需要用以下内容替换原来project.json文件(删除”type”: “platform”,并增加runtimes节点)

{
  "version": "1.0.0-*",
  "buildOptions": {
    "debugType": "portable",
    "emitEntryPoint": true
  },
  "dependencies": {},
  "frameworks": {
    "netcoreapp1.0": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "version": "1.0.0"
        }
      },
      "imports": "dnxcore50"
    }
  },
  "runtimes":{
   "win10-x64":{}, #win10平台
   "centos.7-x64":{} #centos7.2平台
  }
}

(2) 执行restore和publish操作

之后执行dotnet restore指令,针对平台进行还原操作。该步操作耗时较久,虽然只是两个平台,第一次也花了较长时间。紧接着进行进行dotnet publish -r centos.7-x64 -c release

dotnet publish指令详见dotnet-publish – Packs the application and all of its dependencies into a folder getting it ready for publishing

(3) 在Linux平台上运行

上述操作后,我们只需要将发布后的文件夹(bin/release/netcoreapp1.0/centos7-x64/publish,包含self.exe)上传到Linux root目录下project(新建)文件夹中, 在Shell中输入指令

修改可执行权限后,即可成功运行“Hello World”,这就是我们“Self-contained applications”方式的部署方法

4. 总结

4.1 尾声

至此,.NET Core的学习便告一段落了,以上内容简单介绍了.NET Core的组成和特性,同时也在Windows和Linux系统上通过两种不同的部署方式成功运行了示例。相比较之前的.NET Framework傻瓜式部署,.NET Core的新奇真是让我眼前一亮。接下来,我也会将.NET Core和ASP.NET Core的学习记录下来,欢迎指正。

4.2 相关学习资料

5. 参考资料