[技术/领域] 最佳实践
适用对象:初级/中级/高级开发者
更新日期:2025-01-20
维护人:[团队名称]
文档目的
本文档总结了 [技术/领域] 的最佳实践,帮助团队:
- 统一编码规范
- 避免常见陷阱
- 提升代码质量
- 提高开发效率
一、编码规范
1.1 命名规范
| 类型 | 规范 | 示例 | 说明 |
|---|---|---|---|
| 变量 | camelCase | userName, isActive | 使用驼峰命名 |
| 常量 | UPPER_SNAKE_CASE | MAX_SIZE, API_URL | 全大写下划线 |
| 类名 | PascalCase | UserService, DataModel | 首字母大写驼峰 |
| 函数 | camelCase | getUserData, handleClick | 动词开头,驼峰命名 |
| 私有成员 | _camelCase | _privateMethod | 下划线前缀 |
| 文件名 | kebab-case | user-service.js | 小写短横线分隔 |
示例:
javascript
1// 推荐2const MAX_RETRY_COUNT = 3;3const userName = 'John';4class UserService {}5function getUserById(id) {}67// 不推荐8const max_retry_count = 3; // 常量应全大写9const UserName = 'John'; // 变量不应大写开头10class userService {} // 类名应大写开头11function get_user_by_id() {} // 函数应驼峰命名1.2 注释规范
函数注释:
javascript
1/**2 * 根据用户ID获取用户信息3 * 4 * @param {number} userId - 用户ID5 * @param {Object} options - 可选配置项6 * @param {boolean} options.includeDetails - 是否包含详细信息7 * @returns {Promise<User>} 用户对象8 * @throws {NotFoundError} 当用户不存在时9 * 10 * @example11 * const user = await getUserById(123, { includeDetails: true });12 */13async function getUserById(userId, options = {}) {14 // 实现代码15}复杂逻辑注释:
javascript
1// 推荐:解释"为什么"而不是"是什么"2// 使用二分查找提升大数组的查找性能3const index = binarySearch(arr, target);45// 不推荐:陈述代码本身6// 调用binarySearch函数7const index = binarySearch(arr, target);1.3 代码格式
javascript
1// 推荐:清晰的代码结构2function processUserData(users) {3 if (!users || !Array.isArray(users)) {4 throw new Error('Invalid users array');5 }6 7 return users8 .filter(user => user.isActive)9 .map(user => ({10 id: user.id,11 name: user.name,12 email: user.email13 }))14 .sort((a, b) => a.name.localeCompare(b.name));15}1617// 不推荐:混乱的代码格式18function processUserData(users){19if(!users||!Array.isArray(users))throw new Error('Invalid users array');20return users.filter(user=>user.isActive).map(user=>({id:user.id,name:user.name,email:user.email})).sort((a,b)=>a.name.localeCompare(b.name));}二、设计原则
2.1 SOLID原则
| 原则 | 说明 | 示例 |
|---|---|---|
| S - 单一职责 | 一个类只负责一件事 | UserService只处理用户相关逻辑 |
| O - 开放封闭 | 对扩展开放,对修改封闭 | 使用策略模式扩展功能 |
| L - 里氏替换 | 子类可以替换父类 | 子类不改变父类行为 |
| I - 接口隔离 | 接口应该小而专一 | 拆分大接口为多个小接口 |
| D - 依赖倒置 | 依赖抽象而非具体实现 | 依赖接口而非具体类 |
单一职责示例:
javascript
1// 不推荐:职责混乱2class User {3 constructor(name, email) {4 this.name = name;5 this.email = email;6 }7 8 save() {9 // 保存到数据库10 }11 12 sendEmail(message) {13 // 发送邮件14 }15 16 generateReport() {17 // 生成报表18 }19}2021// 推荐:职责分离22class User {23 constructor(name, email) {24 this.name = name;25 this.email = email;26 }27}2829class UserRepository {30 save(user) {31 // 保存到数据库32 }33}3435class EmailService {36 send(user, message) {37 // 发送邮件38 }39}4041class ReportService {42 generateUserReport(user) {43 // 生成报表44 }45}2.2 DRY原则(Don't Repeat Yourself)
javascript
1// 不推荐:重复代码2function validateEmail(email) {3 const regex = /^\S+@\S+\.\S+$/;4 return regex.test(email);5}67function validateUsername(username) {8 const regex = /^[a-zA-Z0-9_]{3,20}$/;9 return regex.test(username);10}1112// 推荐:提取公共逻辑13function validateWithRegex(value, regex) {14 return regex.test(value);15}1617const EMAIL_REGEX = /^\S+@\S+\.\S+$/;18const USERNAME_REGEX = /^[a-zA-Z0-9_]{3,20}$/;1920const validateEmail = (email) => validateWithRegex(email, EMAIL_REGEX);21const validateUsername = (username) => validateWithRegex(username, USERNAME_REGEX);三、性能优化
3.1 前端性能优化
| 优化项 | 技术方案 | 提升效果 | 优先级 |
|---|---|---|---|
| 资源加载 | 懒加载、预加载 | 50%+ | 高 |
| 代码分割 | Code Splitting | 40%+ | 高 |
| 图片优化 | WebP、压缩 | 60%+ | 高 |
| 缓存策略 | Service Worker | 80%+ | 中 |
| 虚拟滚动 | 大列表优化 | 90%+ | 中 |
| 防抖节流 | 减少函数调用 | 30%+ | 低 |
懒加载示例:
javascript
1// 推荐:路由懒加载2const UserDashboard = () => import('./components/UserDashboard');34const routes = [5 {6 path: '/dashboard',7 component: UserDashboard // 仅在访问时加载8 }9];1011// 推荐:图片懒加载12<img 13 src="placeholder.jpg" 14 data-src="actual-image.jpg" 15 loading="lazy" 16 alt="Image"17/>3.2 后端性能优化
数据库优化:
sql
1-- 不推荐:未使用索引2SELECT * FROM users WHERE email = 'test@example.com';34-- 推荐:添加索引5CREATE INDEX idx_users_email ON users(email);6SELECT id, name, email FROM users WHERE email = 'test@example.com';缓存策略:
javascript
1// 推荐:多级缓存2class UserService {3 constructor() {4 this.cache = new Map(); // 内存缓存5 this.redis = new Redis(); // Redis缓存6 }7 8 async getUser(id) {9 // 1. 检查内存缓存10 if (this.cache.has(id)) {11 return this.cache.get(id);12 }13 14 // 2. 检查Redis缓存15 const cached = await this.redis.get(`user:${id}`);16 if (cached) {17 const user = JSON.parse(cached);18 this.cache.set(id, user);19 return user;20 }21 22 // 3. 查询数据库23 const user = await this.db.findById(id);24 25 // 4. 更新缓存26 await this.redis.setex(`user:${id}`, 3600, JSON.stringify(user));27 this.cache.set(id, user);28 29 return user;30 }31}四、安全最佳实践
4.1 输入验证
javascript
1// 危险:不安全的做法:未验证输入2app.post('/api/users', (req, res) => {3 const user = req.body;4 db.insert(user); // 可能导致SQL注入5});67// 安全:推荐做法:严格验证8const Joi = require('joi');910const userSchema = Joi.object({11 username: Joi.string().alphanum().min(3).max(30).required(),12 email: Joi.string().email().required(),13 password: Joi.string().min(8).required()14});1516app.post('/api/users', async (req, res) => {17 try {18 const value = await userSchema.validateAsync(req.body);19 // 处理已验证的数据20 } catch (error) {21 res.status(400).json({ error: error.message });22 }23});4.2 密码处理
javascript
1// 危险:不安全的做法:明文存储密码2const user = {3 username: 'john',4 password: '123456' // 明文密码5};67// 安全:推荐做法:加密存储8const bcrypt = require('bcrypt');910async function hashPassword(password) {11 const salt = await bcrypt.genSalt(10);12 return await bcrypt.hash(password, salt);13}1415const user = {16 username: 'john',17 password: await hashPassword('123456')18};4.3 XSS防护
javascript
1// 危险:不安全的做法:直接插入HTML2element.innerHTML = userInput;34// 安全:推荐做法:转义HTML5function escapeHtml(text) {6 const map = {7 '&': '&',8 '<': '<',9 '>': '>',10 '"': '"',11 "'": '''12 };13 return text.replace(/[&<>"']/g, m => map[m]);14}1516element.textContent = escapeHtml(userInput);五、错误处理
5.1 统一错误处理
javascript
1// 推荐:统一错误类2class ApplicationError extends Error {3 constructor(message, statusCode = 500, data = {}) {4 super(message);5 this.name = this.constructor.name;6 this.statusCode = statusCode;7 this.data = data;8 Error.captureStackTrace(this, this.constructor);9 }10}1112class ValidationError extends ApplicationError {13 constructor(message, data) {14 super(message, 400, data);15 }16}1718class NotFoundError extends ApplicationError {19 constructor(message) {20 super(message, 404);21 }22}2324// 使用25throw new ValidationError('Invalid email format', { field: 'email' });5.2 错误边界
javascript
1// React错误边界2class ErrorBoundary extends React.Component {3 constructor(props) {4 super(props);5 this.state = { hasError: false, error: null };6 }78 static getDerivedStateFromError(error) {9 return { hasError: true, error };10 }1112 componentDidCatch(error, errorInfo) {13 // 记录错误到日志服务14 logErrorToService(error, errorInfo);15 }1617 render() {18 if (this.state.hasError) {19 return <ErrorFallback error={this.state.error} />;20 }2122 return this.props.children;23 }24}六、测试最佳实践
6.1 单元测试
javascript
1// 推荐:清晰的测试结构2describe('UserService', () => {3 describe('getUserById', () => {4 it('should return user when user exists', async () => {5 // Arrange6 const userId = 123;7 const expectedUser = { id: 123, name: 'John' };8 mockDB.findById.mockResolvedValue(expectedUser);9 10 // Act11 const result = await userService.getUserById(userId);12 13 // Assert14 expect(result).toEqual(expectedUser);15 expect(mockDB.findById).toHaveBeenCalledWith(userId);16 });17 18 it('should throw NotFoundError when user does not exist', async () => {19 // Arrange20 mockDB.findById.mockResolvedValue(null);21 22 // Act & Assert23 await expect(userService.getUserById(999))24 .rejects25 .toThrow(NotFoundError);26 });27 });28});6.2 测试覆盖率目标
| 代码类型 | 覆盖率目标 | 说明 |
|---|---|---|
| 核心业务逻辑 | 90%+ | 必须有充分测试 |
| 工具函数 | 95%+ | 应该有完整测试 |
| UI组件 | 70%+ | 重点测试交互逻辑 |
| 配置代码 | 60%+ | 基本测试即可 |
七、代码审查清单
7.1 提交前检查
- 代码符合团队规范
- 添加了必要的注释
- 更新了相关文档
- 编写了单元测试
- 测试用例全部通过
- 没有console.log等调试代码
- 处理了所有TODO
- 检查了安全隐患
7.2 Code Review要点
功能性:
- 代码是否实现了预期功能?
- 边界条件是否处理?
- 错误处理是否完善?
可读性:
- 命名是否清晰?
- 逻辑是否易懂?
- 是否需要注释?
性能:
- 是否有性能问题?
- 是否有不必要的计算?
- 是否可以优化?
八、Git最佳实践
8.1 提交信息规范
bash
1# 推荐:清晰的提交信息2feat: 添加用户导出功能3fix: 修复登录页面样式问题4docs: 更新API文档5refactor: 重构用户服务代码6test: 添加用户服务单元测试7chore: 更新依赖版本89# 不推荐:模糊的提交信息10update code11fix bug12changes8.2 分支策略
九、文档最佳实践
9.1 README模板
markdown
1# 项目名称23简短描述项目功能45## 功能特性67- 功能18- 功能29- 功能31011## 快速开始1213### 安装14\`\`\`bash15npm install16\`\`\`1718### 运行19\`\`\`bash20npm start21\`\`\`2223## 文档2425详细文档请查看 [文档站点](https://docs.example.com)2627## 贡献指南2829请查看 [CONTRIBUTING.md](./CONTRIBUTING.md)3031## 许可证3233MIT十、常见反模式
10.1 避免的做法
| 反模式 | 问题 | 正确做法 |
|---|---|---|
| 上帝类 | 一个类承担太多职责 | 拆分为多个小类 |
| 意大利面代码 | 逻辑混乱,难以维护 | 使用清晰的结构 |
| 魔法数字 | 硬编码的数字 | 定义为常量 |
| 过早优化 | 在需要前就优化 | 先保证正确性 |
| 重复代码 | 相同逻辑多处出现 | 提取为公共函数 |
| 过度设计 | 添加不需要的抽象 | 保持简单 |
总结
核心原则
- 简单优于复杂:保持代码简洁明了
- 可读性第一:代码是写给人看的
- 持续改进:不断学习和优化
- 团队协作:遵循团队规范
- 质量保证:测试和代码审查
评论