forked from datawhale/whale-town-end
- 重新组织docs目录结构,按功能模块分类 - 新增deployment和development目录 - 更新API文档结构 - 添加客户端README文档 - 移除过时的文档文件
528 lines
11 KiB
Markdown
528 lines
11 KiB
Markdown
# 命名规范
|
||
|
||
本文档定义了项目中所有代码的命名规范,确保代码风格统一,提高可读性和可维护性。
|
||
|
||
## 目录
|
||
|
||
- [文件和文件夹命名](#文件和文件夹命名)
|
||
- [变量和函数命名](#变量和函数命名)
|
||
- [类和构造函数命名](#类和构造函数命名)
|
||
- [常量命名](#常量命名)
|
||
- [接口路由命名](#接口路由命名)
|
||
- [TypeScript 特定规范](#typescript-特定规范)
|
||
- [命名示例](#命名示例)
|
||
|
||
## 文件和文件夹命名
|
||
|
||
**规则:使用下划线分隔(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)**
|
||
|
||
### 变量命名
|
||
|
||
```typescript
|
||
✅ 正确示例:
|
||
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;
|
||
```
|
||
|
||
### 函数命名
|
||
|
||
```typescript
|
||
✅ 正确示例:
|
||
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` 等前缀:
|
||
```typescript
|
||
const isActive = true;
|
||
const hasPermission = false;
|
||
const canMove = true;
|
||
```
|
||
|
||
## 类和构造函数命名
|
||
|
||
**规则:使用大驼峰命名(PascalCase)**
|
||
|
||
### 类命名
|
||
|
||
```typescript
|
||
✅ 正确示例:
|
||
class UserModel { }
|
||
class OrderService { }
|
||
class GameController { }
|
||
class PlayerEntity { }
|
||
class RoomGateway { }
|
||
class DatabaseConnection { }
|
||
|
||
❌ 错误示例:
|
||
class userModel { }
|
||
class order_service { }
|
||
class gameController { }
|
||
class player_entity { }
|
||
```
|
||
|
||
### 接口命名
|
||
|
||
```typescript
|
||
✅ 正确示例:
|
||
interface User { }
|
||
interface GameConfig { }
|
||
interface PlayerData { }
|
||
interface RoomOptions { }
|
||
|
||
// 或使用 I 前缀(可选)
|
||
interface IUser { }
|
||
interface IGameConfig { }
|
||
|
||
❌ 错误示例:
|
||
interface user { }
|
||
interface game_config { }
|
||
interface playerData { }
|
||
```
|
||
|
||
### DTO 命名
|
||
|
||
```typescript
|
||
✅ 正确示例:
|
||
class CreateUserDto { }
|
||
class UpdatePlayerDto { }
|
||
class JoinRoomDto { }
|
||
class GameStateDto { }
|
||
|
||
❌ 错误示例:
|
||
class createUserDto { }
|
||
class update_player_dto { }
|
||
class joinRoomDTO { }
|
||
```
|
||
|
||
### 装饰器命名
|
||
|
||
```typescript
|
||
✅ 正确示例:
|
||
@Controller('users')
|
||
@Injectable()
|
||
@Module()
|
||
@Get()
|
||
|
||
// 自定义装饰器
|
||
function CustomDecorator() { }
|
||
```
|
||
|
||
## 常量命名
|
||
|
||
**规则:全大写 + 下划线分隔(SCREAMING_SNAKE_CASE)**
|
||
|
||
```typescript
|
||
✅ 正确示例:
|
||
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;
|
||
```
|
||
|
||
### 枚举命名
|
||
|
||
```typescript
|
||
✅ 正确示例:
|
||
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)**
|
||
|
||
```typescript
|
||
✅ 正确示例:
|
||
@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')
|
||
```
|
||
|
||
### 路由结构建议
|
||
|
||
```typescript
|
||
// 资源型路由
|
||
@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 特定规范
|
||
|
||
### 类型别名
|
||
|
||
```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 };
|
||
```
|
||
|
||
### 泛型参数
|
||
|
||
```typescript
|
||
✅ 正确示例:
|
||
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> { }
|
||
```
|
||
|
||
### 装饰器参数
|
||
|
||
```typescript
|
||
✅ 正确示例:
|
||
@Column({ name: 'user_name' })
|
||
@IsString({ message: 'Name must be a string' })
|
||
@ApiProperty({ description: 'User ID' })
|
||
|
||
❌ 错误示例:
|
||
@Column({ name: 'UserName' })
|
||
@IsString({ message: 'name_must_be_string' })
|
||
```
|
||
|
||
## 命名示例
|
||
|
||
### 完整的模块示例
|
||
|
||
```typescript
|
||
// 文件: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);
|
||
}
|
||
}
|
||
```
|
||
|
||
```typescript
|
||
// 文件: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;
|
||
}
|
||
}
|
||
```
|
||
|
||
```typescript
|
||
// 文件: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',
|
||
}
|
||
```
|
||
|
||
```typescript
|
||
// 文件: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 前缀
|
||
- [ ] 避免使用无意义的缩写
|
||
|
||
## 工具配置
|
||
|
||
### ESLint 配置建议
|
||
|
||
```json
|
||
{
|
||
"rules": {
|
||
"@typescript-eslint/naming-convention": [
|
||
"error",
|
||
{
|
||
"selector": "variable",
|
||
"format": ["camelCase", "UPPER_CASE"]
|
||
},
|
||
{
|
||
"selector": "function",
|
||
"format": ["camelCase"]
|
||
},
|
||
{
|
||
"selector": "class",
|
||
"format": ["PascalCase"]
|
||
},
|
||
{
|
||
"selector": "interface",
|
||
"format": ["PascalCase"]
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
## 总结
|
||
|
||
遵循统一的命名规范能够:
|
||
|
||
- 提高代码可读性
|
||
- 减少团队沟通成本
|
||
- 降低代码维护难度
|
||
- 避免命名冲突
|
||
- 提升项目专业度
|
||
|
||
记住:**好的命名是自解释的,不需要额外的注释。**
|