forked from datawhale/whale-town-end
- 统一文件命名为snake_case格式(kebab-case snake_case) - 重构zulip模块为zulip_core,明确Core层职责 - 重构user-mgmt模块为user_mgmt,统一命名规范 - 调整模块依赖关系,优化架构分层 - 删除过时的文件和目录结构 - 更新相关文档和配置文件 本次重构涉及大量文件重命名和模块重组, 旨在建立更清晰的项目架构和统一的命名规范。
14 KiB
14 KiB
命名规范
本文档定义了项目中所有代码的命名规范,确保代码风格统一,提高可读性和可维护性。
目录
文件和文件夹命名
规则:使用下划线分隔(snake_case)
文件命名
✅ 正确示例:
- order_controller.ts
- user_service.ts
- game_gateway.ts
- player_entity.ts
- create_room_dto.ts
- database_config.ts
❌ 错误示例:
- OrderController.ts
- userService.ts
- game-gateway.ts
- playerEntity.ts
文件夹命名
✅ 正确示例:
- src/api/
- src/service/
- src/model/dto/
- src/utils/
- src/config/
- test/unit_test/
- test/integration_test/
❌ 错误示例:
- src/API/
- src/Service/
- src/model-dto/
- src/Utils/
特殊说明
- 所有文件和文件夹名使用小写字母
- 多个单词之间使用下划线
_连接 - 避免使用缩写,除非是广泛认可的缩写(如 dto、api)
变量和函数命名
规则:使用小驼峰命名(camelCase)
变量命名
✅ 正确示例:
const userName = 'Alice';
let playerScore = 100;
const roomId = '12345';
const isGameStarted = false;
const maxPlayerCount = 4;
❌ 错误示例:
const UserName = 'Alice';
const player_score = 100;
const RoomId = '12345';
const is_game_started = false;
函数命名
✅ 正确示例:
function getUserInfo() { }
async function queryUserInfo() { }
function calculateDamage() { }
function isPlayerAlive() { }
function handlePlayerMove() { }
❌ 错误示例:
function GetUserInfo() { }
function query_user_info() { }
function CalculateDamage() { }
function IsPlayerAlive() { }
命名建议
-
使用动词开头描述函数功能:
get- 获取数据(如getUserById)set- 设置数据(如setPlayerPosition)create- 创建实体(如createRoom)update- 更新数据(如updatePlayerScore)delete- 删除数据(如deleteRoom)is/has- 布尔判断(如isGameOver、hasPermission)handle- 事件处理(如handlePlayerAttack)calculate- 计算逻辑(如calculateDamage)validate- 验证逻辑(如validateInput)
-
布尔变量使用
is、has、can等前缀:const isActive = true; const hasPermission = false; const canMove = true;
类和构造函数命名
规则:使用大驼峰命名(PascalCase)
类命名
✅ 正确示例:
class UserModel { }
class OrderService { }
class GameController { }
class PlayerEntity { }
class RoomGateway { }
class DatabaseConnection { }
❌ 错误示例:
class userModel { }
class order_service { }
class gameController { }
class player_entity { }
接口命名
✅ 正确示例:
interface User { }
interface GameConfig { }
interface PlayerData { }
interface RoomOptions { }
// 或使用 I 前缀(可选)
interface IUser { }
interface IGameConfig { }
❌ 错误示例:
interface user { }
interface game_config { }
interface playerData { }
DTO 命名
✅ 正确示例:
class CreateUserDto { }
class UpdatePlayerDto { }
class JoinRoomDto { }
class GameStateDto { }
❌ 错误示例:
class createUserDto { }
class update_player_dto { }
class joinRoomDTO { }
装饰器命名
✅ 正确示例:
@Controller('users')
@Injectable()
@Module()
@Get()
// 自定义装饰器
function CustomDecorator() { }
常量命名
规则:全大写 + 下划线分隔(SCREAMING_SNAKE_CASE)
✅ 正确示例:
const PORT = 3000;
const DB_HOST = 'localhost';
const MAX_PLAYERS = 10;
const API_VERSION = 'v1';
const DEFAULT_TIMEOUT = 5000;
const GAME_STATUS_WAITING = 'waiting';
const GAME_STATUS_PLAYING = 'playing';
❌ 错误示例:
const port = 3000;
const dbHost = 'localhost';
const maxPlayers = 10;
const ApiVersion = 'v1';
const default_timeout = 5000;
枚举命名
✅ 正确示例:
enum GameStatus {
WAITING = 'waiting',
PLAYING = 'playing',
FINISHED = 'finished',
}
enum PlayerRole {
ADMIN = 'admin',
PLAYER = 'player',
SPECTATOR = 'spectator',
}
❌ 错误示例:
enum gameStatus {
waiting = 'waiting',
playing = 'playing',
}
enum PlayerRole {
admin = 'admin',
player = 'player',
}
接口路由命名
规则:全小写 + 短横线分隔(kebab-case)
✅ 正确示例:
@Get('user/get-info')
@Post('order/create-order')
@Put('player/update-position')
@Delete('room/delete-room')
@Get('game/get-state')
@Post('room/join-room')
❌ 错误示例:
@Get('user/getInfo')
@Post('order/createOrder')
@Put('player/update_position')
@Delete('room/DeleteRoom')
@Get('game/GetState')
路由结构建议
// 资源型路由
@Controller('api/players')
export class PlayerController {
@Get() // GET /api/players
@Get(':id') // GET /api/players/:id
@Post() // POST /api/players
@Put(':id') // PUT /api/players/:id
@Delete(':id') // DELETE /api/players/:id
}
// 动作型路由
@Controller('api/game')
export class GameController {
@Post('start-game') // POST /api/game/start-game
@Post('end-game') // POST /api/game/end-game
@Get('get-state') // GET /api/game/get-state
}
// 嵌套资源路由
@Controller('api/rooms')
export class RoomController {
@Post(':id/join') // POST /api/rooms/:id/join
@Post(':id/leave') // POST /api/rooms/:id/leave
@Get(':id/players') // GET /api/rooms/:id/players
}
TypeScript 特定规范
类型别名
✅ 正确示例:
type UserId = string;
type PlayerPosition = { x: number; y: number };
type GameCallback = (state: GameState) => void;
❌ 错误示例:
type userId = string;
type player_position = { x: number; y: number };
泛型参数
✅ 正确示例:
function findById<T>(id: string): T { }
class Repository<T, K> { }
interface Response<T> { }
// 使用有意义的名称
function mapArray<TInput, TOutput>(arr: TInput[]): TOutput[] { }
❌ 错误示例:
function findById<t>(id: string): t { }
class Repository<type, key> { }
装饰器参数
✅ 正确示例:
@Column({ name: 'user_name' })
@IsString({ message: 'Name must be a string' })
@ApiProperty({ description: 'User ID' })
❌ 错误示例:
@Column({ name: 'UserName' })
@IsString({ message: 'name_must_be_string' })
注释命名规范
注释标签命名
规则:使用标准JSDoc标签
✅ 正确示例:
@param userId 用户ID
@returns 用户信息
@throws NotFoundException 用户不存在时
@author moyin
@version 1.0.0
@since 2025-01-07
@lastModified 2025-01-07
❌ 错误示例:
@参数 userId 用户ID
@返回 用户信息
@异常 NotFoundException 用户不存在时
@作者 moyin
修改记录命名
规则:使用标准化的修改类型
✅ 正确示例:
- 2025-01-07: 代码规范优化 - 清理未使用的导入
- 2025-01-07: 功能新增 - 添加用户验证功能
- 2025-01-07: Bug修复 - 修复登录验证逻辑
- 2025-01-07: 性能优化 - 优化数据库查询
- 2025-01-07: 重构 - 重构用户服务架构
❌ 错误示例:
- 2025-01-07: 修改 - 改了一些代码
- 2025-01-07: 更新 - 更新了功能
- 2025-01-07: 优化 - 优化了性能
- 2025-01-07: 调整 - 调整了结构
📏 长度限制:修改记录只保留最近5次修改,保持文件头注释简洁。
注释内容命名
规则:使用清晰描述性的中文
✅ 正确示例:
/** 用户唯一标识符 */
userId: string;
/** 用户邮箱地址,用于登录和通知 */
email: string;
/** 用户状态:active-激活, inactive-未激活, banned-已封禁 */
status: UserStatus;
/**
* 验证用户登录凭据
*
* 业务逻辑:
* 1. 验证用户名或邮箱格式
* 2. 查找用户记录
* 3. 验证密码哈希值
* 4. 检查用户状态
*/
❌ 错误示例:
/** id */
userId: string;
/** 邮箱 */
email: string;
/** 状态 */
status: UserStatus;
/**
* 登录
*/
版本号命名规范
规则:使用语义化版本号
✅ 正确示例:
@version 1.0.0 // 主版本.次版本.修订版本
@version 1.2.3 // 功能更新
@version 2.0.0 // 重大更新
修改时版本递增规则:
- 代码规范优化、Bug修复 → 修订版本 +1 (1.0.0 → 1.0.1)
- 功能新增、功能修改 → 次版本 +1 (1.0.1 → 1.1.0)
- 重构、架构变更 → 主版本 +1 (1.1.0 → 2.0.0)
❌ 错误示例:
@version v1 // 缺少详细版本号
@version 1 // 格式不规范
@version latest // 不明确的版本标识
命名示例
完整的模块示例
// 文件:src/api/player_controller.ts
import { Controller, Get, Post, Body, Param } from '@nestjs/common';
import { PlayerService } from '../service/player_service';
import { CreatePlayerDto } from '../model/dto/create_player_dto';
const MAX_PLAYERS = 100;
@Controller('api/players')
export class PlayerController {
constructor(private readonly playerService: PlayerService) {}
@Get()
async getAllPlayers() {
return this.playerService.findAll();
}
@Get(':id')
async getPlayerById(@Param('id') playerId: string) {
return this.playerService.findById(playerId);
}
@Post()
async createPlayer(@Body() createPlayerDto: CreatePlayerDto) {
return this.playerService.create(createPlayerDto);
}
@Post(':id/update-position')
async updatePlayerPosition(
@Param('id') playerId: string,
@Body() body: { x: number; y: number }
) {
const { x, y } = body;
return this.playerService.updatePosition(playerId, x, y);
}
}
// 文件:src/service/player_service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { Player } from '../model/player_entity';
import { CreatePlayerDto } from '../model/dto/create_player_dto';
const DEFAULT_HEALTH = 100;
const DEFAULT_SPEED = 5;
@Injectable()
export class PlayerService {
private players: Map<string, Player> = new Map();
findAll(): Player[] {
return Array.from(this.players.values());
}
findById(playerId: string): Player {
const player = this.players.get(playerId);
if (!player) {
throw new NotFoundException(`Player with ID ${playerId} not found`);
}
return player;
}
create(createPlayerDto: CreatePlayerDto): Player {
const newPlayer: Player = {
id: this.generatePlayerId(),
name: createPlayerDto.name,
health: DEFAULT_HEALTH,
speed: DEFAULT_SPEED,
position: { x: 0, y: 0 },
isAlive: true,
createdAt: new Date(),
};
this.players.set(newPlayer.id, newPlayer);
return newPlayer;
}
updatePosition(playerId: string, x: number, y: number): Player {
const player = this.findById(playerId);
player.position = { x, y };
return player;
}
private generatePlayerId(): string {
return `player_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
private calculateDamage(attackPower: number, defense: number): number {
return Math.max(0, attackPower - defense);
}
isPlayerAlive(playerId: string): boolean {
const player = this.findById(playerId);
return player.isAlive && player.health > 0;
}
}
// 文件:src/model/player_entity.ts
export interface Player {
id: string;
name: string;
health: number;
speed: number;
position: Position;
isAlive: boolean;
createdAt: Date;
}
export interface Position {
x: number;
y: number;
}
export enum PlayerStatus {
IDLE = 'idle',
MOVING = 'moving',
ATTACKING = 'attacking',
DEAD = 'dead',
}
// 文件:src/model/dto/create_player_dto.ts
import { IsString, IsNotEmpty, MinLength, MaxLength } from 'class-validator';
export class CreatePlayerDto {
@IsString()
@IsNotEmpty()
@MinLength(3)
@MaxLength(20)
name: string;
}
检查清单
在提交代码前,请确保:
- 所有文件和文件夹使用下划线分隔命名
- 所有变量和函数使用小驼峰命名
- 所有类、接口、DTO 使用大驼峰命名
- 所有常量和枚举值使用全大写 + 下划线命名
- 所有路由使用全小写 + 短横线命名
- 函数名清晰表达其功能
- 布尔变量使用 is/has/can 前缀
- 避免使用无意义的缩写
- 注释使用标准JSDoc标签
- 修改记录使用标准化修改类型
- 版本号遵循语义化版本规范
- 修改现有文件时添加了修改记录和更新版本号
- 修改记录只保留最近5次,保持注释简洁
工具配置
ESLint 配置建议
{
"rules": {
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "variable",
"format": ["camelCase", "UPPER_CASE"]
},
{
"selector": "function",
"format": ["camelCase"]
},
{
"selector": "class",
"format": ["PascalCase"]
},
{
"selector": "interface",
"format": ["PascalCase"]
}
]
}
}
总结
遵循统一的命名规范能够:
- 提高代码可读性
- 减少团队沟通成本
- 降低代码维护难度
- 避免命名冲突
- 提升项目专业度
记住:好的命名是自解释的,不需要额外的注释。