# 编码规范

统一的编码规范是保证代码质量和可维护性的基础。本文档适用于所有 DarkM 项目参与者。


# 📚 参考标准


# 🔖 后端编码规范(C#)

# 1. 命名规范

# 1.1 命名风格

元素 风格 示例
命名空间 Pascal DarkM.Lib.Data
类/结构 Pascal UserEntity, UserService
接口 Pascal + I 前缀 IUserService, IRepository
方法 Pascal GetUserById, CreateAsync
属性 Pascal UserName, CreateTime
字段 Camel + _ 前缀 _userRepository, _logger
参数 Camel userId, userName
局部变量 Camel userList, totalCount
常量 Pascal MaxRetryCount, DefaultPageSize
枚举类型 Pascal UserStatus, OrderType
枚举值 Pascal Active, Inactive, Pending

# 1.2 命名最佳实践

// ✅ 推荐
public class UserEntity : EntityBase
{
    private readonly IUserRepository _userRepository;
    
    public string UserName { get; set; }
    
    public UserStatus Status { get; set; }
    
    public const int MaxUserNameLength = 50;
}

// ❌ 不推荐
public class user_entity
{
    private IUserRepository UserRepository;  // 字段应该用_前缀
    
    public string userName { get; set; }     // 属性应该 Pascal 命名
    
    public const int maxUserNameLength = 50; // 常量应该 Pascal 命名
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 1.3 命名原则

  1. 可读性优先ScreenXScreenHorizontally 更易读
  2. 避免缩写:除非广泛接受(如 HTML、URL、ID)
  3. 使用复数:命名空间使用复数 System.Collections
  4. 避免关键字冲突:不使用 C# 关键字作为标识符
  5. 语义清晰userListlist 更明确

# 2. 代码组织

# 2.1 文件结构

// 1. using 语句(按命名空间分组)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using DarkM.Lib.Data.Abstractions;
using DarkM.Lib.Utils.Core.Result;

// 2. 命名空间声明
namespace DarkM.Module.User.Application
{
    // 3. 类定义
    /// <summary>
    /// 用户应用服务
    /// </summary>
    public class UserService : IUserService
    {
        // 4. 私有字段
        private readonly IUserRepository _userRepository;
        private readonly ILogger _logger;

        // 5. 构造函数
        public UserService(IUserRepository userRepository, ILogger logger)
        {
            _userRepository = userRepository;
            _logger = logger;
        }

        // 6. 公共方法
        public async Task<IResultModel> GetUserById(Guid id)
        {
            // 方法实现
        }

        // 7. 私有方法
        private void ValidateUser(UserEntity user)
        {
            // 方法实现
        }

        // 8. 内部类
        private class UserCache
        {
            // 类实现
        }
    }
}
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

# 2.2 空行使用

// ✅ 推荐:适当使用空行增强可读性
public class UserService
{
    private readonly IUserRepository _userRepository;
    private readonly ILogger _logger;

    public UserService(IUserRepository userRepository, ILogger logger)
    {
        _userRepository = userRepository;
        _logger = logger;
    }

    public async Task<IResultModel> GetUserById(Guid id)
    {
        var user = await _userRepository.GetAsync(id);
        
        if (user == null)
            return ResultModel.Failed("用户不存在");
        
        return ResultModel.Success(user);
    }

    private void ValidateUser(UserEntity user)
    {
        Check.NotNull(user.Name, nameof(user.Name));
    }
}
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

# 3. 注释规范

# 3.1 XML 文档注释

/// <summary>
/// 用户应用服务
/// </summary>
public class UserService : IUserService
{
    /// <summary>
    /// 根据 ID 获取用户
    /// </summary>
    /// <param name="id">用户 ID</param>
    /// <returns>用户信息</returns>
    public async Task<IResultModel> GetUserById(Guid id)
    {
        // 实现
    }

    /// <summary>
    /// 创建用户
    /// </summary>
    /// <param name="model">用户信息</param>
    /// <returns>创建结果</returns>
    /// <exception cref="ArgumentNullException">当用户名为空时抛出</exception>
    public async Task<IResultModel> CreateUser(UserAddModel model)
    {
        // 实现
    }
}
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

# 3.2 代码注释

// ✅ 推荐:解释为什么这样做
// 使用事务确保数据一致性
using var uow = _unitOfWorkManager.Begin();
try
{
    await _userDbSet.InsertAsync(user);
    await _logDbSet.InsertAsync(log);
    uow.Commit();
}
catch
{
    uow.Rollback();
    throw;
}

// ❌ 不推荐:解释做了什么(代码已经很清楚了)
// 设置用户名称
user.Name = "张三";
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 4. 异常处理

# 4.1 使用 Check 进行参数验证

public async Task<IResultModel> CreateUser(UserAddModel model)
{
    // ✅ 推荐
    Check.NotNull(model, nameof(model), "用户信息不能为空");
    Check.NotNull(model.UserName, nameof(model.UserName), "用户名不能为空");
    
    // ❌ 不推荐
    if (model == null)
        throw new ArgumentNullException(nameof(model));
}
1
2
3
4
5
6
7
8
9
10

# 4.2 异常捕获

// ✅ 推荐:捕获特定异常
try
{
    await _userRepository.AddAsync(user);
}
catch (DbUpdateException ex)
{
    _logger.LogError(ex, "数据库更新失败");
    return ResultModel.Failed("数据库操作失败");
}

// ❌ 不推荐:捕获所有异常
try
{
    await _userRepository.AddAsync(user);
}
catch (Exception)
{
    // 空的 catch 块
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 5. 异步编程

# 5.1 异步方法命名

// ✅ 推荐:异步方法以 Async 结尾
public Task<UserEntity> GetUserByIdAsync(Guid id);
public Task<List<UserEntity>> GetAllUsersAsync();

// ❌ 不推荐
public Task<UserEntity> GetUserById(Guid id);
1
2
3
4
5
6

# 5.2 异步最佳实践

// ✅ 推荐
public async Task<IResultModel> GetUserAsync(Guid id)
{
    var user = await _userRepository.GetAsync(id);
    return ResultModel.Success(user);
}

// ❌ 不推荐:async void(除了事件处理程序)
public async void GetUserAsync(Guid id) { }

// ❌ 不推荐:Task.Result(可能导致死锁)
var user = _userRepository.GetAsync(id).Result;
1
2
3
4
5
6
7
8
9
10
11
12

# 6. LINQ 使用

// ✅ 推荐:链式调用
var activeUsers = _userRepository.Find()
    .Where(u => u.Status == UserStatus.Active)
    .OrderBy(u => u.CreateTime)
    .Take(10)
    .ToList();

// ✅ 推荐:查询表达式
var query = from u in _userRepository.Find()
            where u.Status == UserStatus.Active
            orderby u.CreateTime descending
            select u;

// ❌ 不推荐:多次遍历
var users = _userRepository.Find().ToList();
var activeUsers = users.Where(u => u.Status == UserStatus.Active);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 🎨 前端编码规范(Vue.js)

# 1. 目录结构

src/
├── api/                    # API 接口
│   ├── modules/           # 模块接口
│   │   ├── user.js
│   │   └── order.js
│   └── index.js
├── views/                 # 页面组件
│   ├── user/
│   │   ├── list.vue
│   │   └── edit.vue
│   └── order/
├── components/            # 公共组件
│   ├── NmTable/
│   └── NmForm/
├── utils/                 # 工具函数
│   ├── request.js
│   └── validate.js
├── store/                 # Vuex 状态管理
│   ├── modules/
│   └── index.js
├── router/                # 路由配置
│   └── index.js
├── styles/                # 全局样式
│   ├── variables.scss
│   └── mixins.scss
└── App.vue
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

# 2. 命名规范

# 2.1 文件和目录

类型 风格 示例
组件文件 Pascal UserList.vue, NmTable.vue
页面目录 camel user/, orderManage/
API 文件 camel user.js, orderApi.js
工具函数 camel validate.js, utils.js
样式文件 camel variables.scss

# 2.2 组件命名

// ✅ 推荐:多单词组件名
export default {
  name: 'UserList',
  // ...
}

// ❌ 不推荐:单单词组件名
export default {
  name: 'List',  // 可能与 HTML 标签冲突
  // ...
}
1
2
3
4
5
6
7
8
9
10
11

# 2.3 DarkM.UI 组件别名规则

使用 DarkM.UI 组件时,支持驼峰格式连字符格式两种写法,系统推荐使用连字符格式

<template>
  <!-- 两种写法都支持 -->
  <NmButton type="primary">按钮</NmButton>
  <nm-button type="primary">按钮</nm-button> <!-- ✅ 推荐:连字符格式 -->
  
  <NmDatePicker />
  <nm-date-picker /> <!-- ✅ 推荐 -->
  
  <NmFormDialog />
  <nm-form-dialog /> <!-- ✅ 推荐 -->
</template>
1
2
3
4
5
6
7
8
9
10
11

转换规则:驼峰命名的大写字母前添加 - 并转小写

  • NmButtonnm-button
  • NmDatePickernm-date-picker
  • NmFormDialognm-form-dialog

# 3. 代码规范

# 3.1 组件结构

<template>
  <div class="user-list">
    <nm-table :data="list" :columns="columns">
      <!-- 自定义列 -->
    </nm-table>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'

export default {
  name: 'UserList',
  
  // 组件选项顺序
  components: { NmTable },
  props: { },
  data() {
    return {
      list: [],
      columns: []
    }
  },
  computed: {
    ...mapGetters(['userId'])
  },
  watch: { },
  created() { },
  mounted() { },
  methods: {
    async fetchList() {
      const res = await this.$api.user.getList()
      this.list = res.data
    }
  }
}
</script>

<style lang="scss" scoped>
.user-list {
  padding: 20px;
}
</style>
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
32
33
34
35
36
37
38
39
40
41
42
43

# 3.2 Props 定义

// ✅ 推荐:完整定义
export default {
  props: {
    userId: {
      type: String,
      required: true,
      validator: value => value.length > 0
    },
    status: {
      type: Number,
      default: 0,
      validator: value => [0, 1, 2].includes(value)
    }
  }
}

// ❌ 不推荐:简写
export default {
  props: ['userId', 'status']
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 4. 异步操作

// ✅ 推荐:async/await
export default {
  methods: {
    async fetchUser(id) {
      try {
        const res = await this.$api.user.getById(id)
        this.user = res.data
      } catch (error) {
        this.$message.error('获取用户失败')
      }
    }
  }
}

// ❌ 不推荐:Promise 链
export default {
  methods: {
    fetchUser(id) {
      this.$api.user.getById(id)
        .then(res => {
          this.user = res.data
        })
        .catch(error => {
          this.$message.error('获取用户失败')
        })
    }
  }
}
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

# 5. 状态管理

// store/modules/user.js
export default {
  namespaced: true,
  
  state: {
    userInfo: null,
    token: ''
  },
  
  mutations: {
    SET_USER_INFO(state, info) {
      state.userInfo = info
    },
    SET_TOKEN(state, token) {
      state.token = token
    }
  },
  
  actions: {
    async login({ commit }, credentials) {
      const res = await loginApi(credentials)
      commit('SET_TOKEN', res.data.token)
      commit('SET_USER_INFO', res.data.userInfo)
    }
  },
  
  getters: {
    userId: state => state.userInfo?.id,
    userName: state => state.userInfo?.name
  }
}
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

# 📝 代码审查清单

# 后端检查项

  • [ ] 命名符合 Pascal/Camel 规范
  • [ ] 所有公共方法有 XML 注释
  • [ ] 使用异步方法处理 I/O 操作
  • [ ] 异常处理适当,不吞掉异常
  • [ ] 使用 Check 进行参数验证
  • [ ] 数据库操作使用事务
  • [ ] 避免 N+1 查询问题
  • [ ] 日志记录完整

# 前端检查项

  • [ ] 组件使用多单词命名
  • [ ] Props 有完整定义和验证
  • [ ] 使用 async/await 处理异步
  • [ ] 组件职责单一
  • [ ] 避免直接修改 props
  • [ ] 使用 Vuex 管理全局状态
  • [ ] 样式使用 scoped
  • [ ] 响应式设计考虑移动端

# 🔗 相关文档


最后更新: 2022-08-07