Files
whale-town-front/docs/02-开发规范/开发哲学与最佳实践.md
moyin 1ff677b3b2 docs: 重新组织文档结构,按开发阶段分类
新的目录结构:
  01-项目入门/     # 新人必读,项目基础
  02-开发规范/     # 编码标准和规范
  03-技术实现/     # 具体开发指导
  04-高级开发/     # 进阶开发技巧
  05-部署运维/     # 发布和部署
  06-功能模块/     # 特定功能文档

 新增导航文档:
- docs/README.md - 完整的文档导航和使用指南
- 各目录下的README.md - 分类说明和使用指导

 优化效果:
- 开发者可以按阶段快速定位需要的文档
- 新人有清晰的学习路径
- 不同角色有针对性的文档推荐
- 提供了问题导向的快速查找功能
2025-12-31 18:02:16 +08:00

406 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 开发哲学与最佳实践
本文档阐述了WhaleTown项目的开发哲学和编程最佳实践旨在指导团队创造高质量、可维护的代码。
## 🧘 开发哲学
### 核心理念
- **用户体验至上** - 每个功能都要考虑用户感受
- **代码即文档** - 代码应该自解释,清晰易懂
- **简洁胜于复杂** - 优先选择简单直接的解决方案
- **质量重于速度** - 宁可慢一点,也要做对
### 设计原则
#### 1. 流畅体验 (Juice or Death)
每个用户交互都必须有视觉反馈和动画效果:
```gdscript
# ✅ 正确为UI交互添加动画
func show_dialog() -> void:
dialog.modulate.a = 0.0
dialog.scale = Vector2(0.8, 0.8)
dialog.visible = true
var tween = create_tween()
tween.parallel().tween_property(dialog, "modulate:a", 1.0, 0.3)
tween.parallel().tween_property(dialog, "scale", Vector2.ONE, 0.3)
tween.set_ease(Tween.EASE_OUT)
tween.set_trans(Tween.TRANS_BACK)
# ❌ 错误:没有动画的生硬切换
func show_dialog() -> void:
dialog.visible = true # 突然出现,体验差
```
#### 2. 零魔法数字 (Zero Magic Numbers)
所有数值都应该有明确的含义和来源:
```gdscript
# ✅ 正确:使用导出变量或配置文件
@export var move_speed: float = 200.0
@export var jump_height: float = 400.0
@export var health_max: int = 100
# 或从配置文件加载
const CONFIG_PATH = "res://data/player_config.json"
var config_data: Dictionary
func _ready() -> void:
config_data = load_config(CONFIG_PATH)
move_speed = config_data.get("move_speed", 200.0)
# ❌ 错误:硬编码的魔法数字
func _physics_process(delta: float) -> void:
velocity.x = input_direction.x * 200 # 200是什么
if position.y > 1000: # 1000代表什么
respawn()
```
#### 3. 函数单一职责
每个函数只做一件事,做好一件事:
```gdscript
# ✅ 正确:职责分离
func handle_player_input() -> void:
var input_direction = get_input_direction()
apply_movement(input_direction)
check_interaction_input()
func get_input_direction() -> Vector2:
return Input.get_vector("move_left", "move_right", "move_up", "move_down")
func apply_movement(direction: Vector2) -> void:
velocity = direction * move_speed
move_and_slide()
func check_interaction_input() -> void:
if Input.is_action_just_pressed("interact"):
try_interact()
# ❌ 错误:一个函数做太多事
func handle_everything() -> void:
# 处理输入
var direction = Input.get_vector("move_left", "move_right", "move_up", "move_down")
# 处理移动
velocity = direction * move_speed
move_and_slide()
# 处理交互
if Input.is_action_just_pressed("interact"):
# 检查交互对象
var interactables = get_nearby_interactables()
# 执行交互
for obj in interactables:
obj.interact()
# 更新UI
update_health_bar()
# 播放音效
play_footstep_sound()
```
#### 4. 隐藏复杂性
复杂的逻辑应该被封装,对外提供简洁的接口:
```gdscript
# ✅ 正确:封装复杂逻辑
class_name NetworkManager
func login(username: String, password: String, callback: Callable) -> int:
return _make_request("POST", "/auth/login", {
"username": username,
"password": password
}, callback)
func _make_request(method: String, endpoint: String, data: Dictionary, callback: Callable) -> int:
# 复杂的网络请求逻辑被隐藏
var request = HTTPRequest.new()
var request_id = _generate_request_id()
# 设置请求头、处理认证、错误重试等复杂逻辑
_setup_request_headers(request)
_handle_authentication(request)
_setup_retry_logic(request, callback)
return request_id
# 使用时非常简洁
func _on_login_button_pressed() -> void:
NetworkManager.login(username_input.text, password_input.text, _on_login_response)
```
## 📋 编码最佳实践
### 1. 类型安全
始终使用严格的类型声明:
```gdscript
# ✅ 正确:明确的类型声明
var player_health: int = 100
var move_speed: float = 200.0
var player_name: String = "Player"
var inventory_items: Array[Item] = []
var config_data: Dictionary = {}
func calculate_damage(base_damage: int, multiplier: float) -> int:
return int(base_damage * multiplier)
# ❌ 错误:缺少类型信息
var health = 100 # 类型不明确
var speed = 200 # 可能是int也可能是float
func calculate_damage(base, mult): # 参数类型不明确
return base * mult # 返回类型不明确
```
### 2. 错误处理
主动处理可能的错误情况:
```gdscript
# ✅ 正确:完善的错误处理
func load_save_file(file_path: String) -> Dictionary:
if not FileAccess.file_exists(file_path):
push_warning("存档文件不存在: " + file_path)
return {}
var file = FileAccess.open(file_path, FileAccess.READ)
if file == null:
push_error("无法打开存档文件: " + file_path)
return {}
var json_string = file.get_as_text()
file.close()
if json_string.is_empty():
push_warning("存档文件为空: " + file_path)
return {}
var json = JSON.new()
var parse_result = json.parse(json_string)
if parse_result != OK:
push_error("存档文件JSON格式错误: " + file_path)
return {}
return json.data
# ❌ 错误:没有错误处理
func load_save_file(file_path: String) -> Dictionary:
var file = FileAccess.open(file_path, FileAccess.READ)
var json_string = file.get_as_text()
file.close()
var json = JSON.new()
json.parse(json_string)
return json.data # 任何步骤出错都会崩溃
```
### 3. 资源管理
及时释放不需要的资源:
```gdscript
# ✅ 正确:资源管理
class_name AudioManager
var audio_players: Array[AudioStreamPlayer] = []
var max_concurrent_sounds: int = 10
func play_sound(sound: AudioStream, volume: float = 0.0) -> void:
# 清理已完成的音频播放器
_cleanup_finished_players()
# 限制并发音频数量
if audio_players.size() >= max_concurrent_sounds:
_stop_oldest_player()
var player = AudioStreamPlayer.new()
add_child(player)
player.stream = sound
player.volume_db = volume
player.finished.connect(_on_audio_finished.bind(player))
player.play()
audio_players.append(player)
func _cleanup_finished_players() -> void:
audio_players = audio_players.filter(func(player): return player.playing)
func _on_audio_finished(player: AudioStreamPlayer) -> void:
audio_players.erase(player)
player.queue_free()
```
### 4. 性能优化
编写高效的代码:
```gdscript
# ✅ 正确:性能优化的代码
class_name EnemyManager
var enemies: Array[Enemy] = []
var update_timer: float = 0.0
const UPDATE_INTERVAL: float = 0.1 # 每100ms更新一次
func _process(delta: float) -> void:
update_timer += delta
if update_timer >= UPDATE_INTERVAL:
_update_enemies(update_timer)
update_timer = 0.0
func _update_enemies(delta_time: float) -> void:
# 只更新屏幕附近的敌人
var camera_pos = get_viewport().get_camera_2d().global_position
var screen_size = get_viewport().get_visible_rect().size
for enemy in enemies:
if _is_enemy_near_screen(enemy, camera_pos, screen_size):
enemy.update_ai(delta_time)
func _is_enemy_near_screen(enemy: Enemy, camera_pos: Vector2, screen_size: Vector2) -> bool:
var distance = enemy.global_position.distance_to(camera_pos)
var max_distance = screen_size.length() * 0.6 # 屏幕对角线的60%
return distance <= max_distance
# ❌ 错误:性能问题
func _process(delta: float) -> void:
# 每帧更新所有敌人,无论是否可见
for enemy in enemies:
enemy.update_ai(delta) # 可能有数百个敌人
# 每帧进行复杂计算
var path = enemy.find_path_to_player()
enemy.follow_path(path)
```
## 🎯 代码审查标准
### 审查清单
在提交代码前,请检查以下项目:
#### 功能性
- [ ] 代码实现了预期功能
- [ ] 处理了边界情况和错误情况
- [ ] 添加了必要的测试用例
#### 可读性
- [ ] 变量和函数名称清晰明确
- [ ] 代码结构逻辑清晰
- [ ] 添加了必要的注释
#### 性能
- [ ] 避免了不必要的计算
- [ ] 正确管理了资源生命周期
- [ ] 使用了合适的数据结构
#### 规范性
- [ ] 遵循了项目命名规范
- [ ] 使用了正确的类型声明
- [ ] 符合架构设计原则
### 代码示例评分
#### 优秀代码示例 (A级)
```gdscript
extends CharacterBody2D
class_name Player
## 玩家角色控制器
##
## 负责处理玩家输入、移动和基础交互
## 使用事件系统与其他组件通信
@export_group("Movement")
@export var move_speed: float = 200.0
@export var acceleration: float = 1000.0
@export var friction: float = 800.0
@export_group("Interaction")
@export var interaction_range: float = 50.0
@onready var sprite: Sprite2D = %Sprite2D
@onready var animation_player: AnimationPlayer = %AnimationPlayer
@onready var interaction_area: Area2D = %InteractionArea
var _current_interactable: Interactable = null
func _ready() -> void:
_setup_interaction_area()
_connect_signals()
func _physics_process(delta: float) -> void:
_handle_movement(delta)
func _input(event: InputEvent) -> void:
if event.is_action_pressed("interact"):
_try_interact()
func _handle_movement(delta: float) -> void:
var input_direction := _get_movement_input()
_apply_movement(input_direction, delta)
_update_animation(input_direction)
func _get_movement_input() -> Vector2:
return Input.get_vector("move_left", "move_right", "move_up", "move_down")
func _apply_movement(direction: Vector2, delta: float) -> void:
if direction != Vector2.ZERO:
velocity = velocity.move_toward(direction * move_speed, acceleration * delta)
else:
velocity = velocity.move_toward(Vector2.ZERO, friction * delta)
move_and_slide()
func _update_animation(direction: Vector2) -> void:
if direction.length() > 0.1:
animation_player.play("walk")
sprite.flip_h = direction.x < 0
else:
animation_player.play("idle")
```
#### 需要改进的代码 (C级)
```gdscript
extends CharacterBody2D
var speed = 200
var player
var enemies = []
func _ready():
player = self
func _process(delta):
var dir = Vector2()
if Input.is_action_pressed("ui_left"):
dir.x -= 1
if Input.is_action_pressed("ui_right"):
dir.x += 1
if Input.is_action_pressed("ui_up"):
dir.y -= 1
if Input.is_action_pressed("ui_down"):
dir.y += 1
velocity = dir * speed
move_and_slide()
for enemy in enemies:
if position.distance_to(enemy.position) < 100:
print("near enemy")
```
## 🚀 持续改进
### 重构指导原则
1. **小步快跑** - 每次只重构一小部分
2. **测试保护** - 重构前确保有测试覆盖
3. **功能不变** - 重构不改变外部行为
4. **逐步优化** - 持续改进代码质量
### 技术债务管理
```gdscript
# 使用TODO注释标记技术债务
# TODO: 重构这个函数,职责过多
# FIXME: 这里有性能问题,需要优化
# HACK: 临时解决方案,需要找到更好的方法
# NOTE: 这里的逻辑比较复杂,需要详细注释
```
---
**记住:优秀的代码不仅能工作,更要易于理解、维护和扩展。追求代码质量是每个开发者的责任!**