什么是 Clean Code
Clean Code 是指简洁、清晰、易读、易维护的代码。核心原则包括:
- 可读性:代码应该像书写好的文章,易于理解。
- 可维护性:代码应该便于修改和扩展。
- 无重复:避免重复代码,提升复用性。
- 高内聚、低耦合:模块之间依赖最小,每个模块职责单一。
在项目一开始就要做好Clean code,避免屎山代码越写越多
可读性
良好的命名、注释和代码结构是实现可读性的关键。
javascript
// 不清晰的代码 神秘命名(Mysterious Name)
const d = new Date();
const n = d.getFullYear();
// 更清晰的代码
const currentYear = new Date().getFullYear();
js
// 差的命名和结构
function calc(a, b) {
return a + b;
}
// 良好的命名和结构
function calculateSum(number1, number2) {
// 将两个数字相加并返回结果
return number1 + number2;
}
无重复
重复代码(Duplicated Code)
javascript
//问题代码:
function getUserFullName(user) {
return user.firstName + ' ' + user.lastName;
}
function getAuthorFullName(author) {
return author.firstName + ' ' + author.lastName;
}
//改进代码(抽取公共方法):
function getFullName(person) {
return person.firstName + ' ' + person.lastName;
}
可维护性
代码应该便于修改和扩展。模块化设计和单一职责原则有助于提高代码的可维护性。
js
// 不易维护的代码
function processData(data) {
// 验证数据
if (!data) {
throw new Error("数据不能为空");
}
// 处理数据
const result = data.map(item => item * 2);
// 保存结果
console.log("结果已保存");
return result;
}
// 易维护的代码
function validateData(data) {
if (!data) {
throw new Error("数据不能为空");
}
}
function transformData(data) {
return data.map(item => item * 2);
}
function saveResult(result) {
console.log("结果已保存");
}
function processData(data) {
validateData(data);
const result = transformData(data);
saveResult(result);
return result;
}
高内聚、低耦合
模块之间依赖最小(低耦合),每个模块的职责单一(高内聚)。
js
// 高耦合、低内聚的例子
class UserManager {
constructor() {
this.users = [];
}
addUser(user) {
this.users.push(user);
// 直接操作数据库
database.save(user);
}
getUser(id) {
// 直接从数据库获取
return database.find(id);
}
}
// 高内聚、低耦合的例子
class UserRepository {
constructor(database) {
this.database = database;
}
save(user) {
this.database.save(user);
}
find(id) {
return this.database.find(id);
}
}
class UserManager {
constructor(userRepository) {
this.userRepository = userRepository;
this.users = [];
}
addUser(user) {
this.users.push(user);
this.userRepository.save(user);
}
getUser(id) {
return this.userRepository.find(id);
}
}
代码重构方法
重构工作是怎么执行的?
- 局部:代码片段的重构,识别坏味道 (小步迭代,日常开发)
- 广泛:架构级的重构 (专家投入,统一规划)
何时重构?
重构本应该是个渐进式的过程,不是只有伤筋动骨的改造才叫重构
不是所有软件开发过程都一定要重构,较能凸显重构价值的场景是:代码规模较大、生命周期还较长、承担了较多责任、有一个较大团队在其上工作的单一代码库。
识别坏味道
- 命名混乱?➡ 重命名变量和函数
- 代码重复?➡ 提取函数
- 逻辑复杂?➡ 拆分成小函数
- 过长参数列表?➡ 使用对象封装参数
(命名混乱)重命名变量和函数
javascript
// 问题代码:
function calc(a, b) {
let c = a * b / 100;
return c;
}
//改进代码:
function calculateDiscount(price, discountRate) {
let discountAmount = price * discountRate / 100;
return discountAmount;
}
改进点:
- 使用明确的函数名
calculateDiscount
代替calc
- 使用
price
和discountRate
代替a
和b
- 让代码可读性更高,减少理解成本
(代码重复)提取方法
javascript
// 重复代码
function calculateTotal(items) {
let total = 0;
for (let i = 0; i < items.length; i++) {
total += items[i].price * items[i].quantity;
}
return total;
}
// 改进代码
function calculateItemTotal(item) {
return item.price * item.quantity;
}
function calculateTotal(items) {
return items.reduce((sum, item) => sum + calculateItemTotal(item), 0);
}
改进点:
- 提取
calculateItemTotal
函数,使calculateTotal
逻辑更清晰 - 避免重复代码,提高可读性和复用性
(逻辑复杂)拆分成小函数
将复杂的逻辑拆分成多个小函数,每个函数负责单一任务。
js
// 逻辑复杂的代码
function processOrder(order) {
if (order.status === "pending") {
if (inventory.checkStock(order.items)) {
const total = order.items.reduce((sum, item) => sum + item.price, 0);
if (order.discountCode) {
total *= 0.9; // 10% 折扣
}
order.status = "processed";
database.save(order);
} else {
order.status = "out_of_stock";
}
}
}
// 拆分成小函数后的代码
function checkStock(items) {
return inventory.checkStock(items);
}
function calculateTotal(items, discountCode) {
let total = items.reduce((sum, item) => sum + item.price, 0);
if (discountCode) {
total *= 0.9; // 10% 折扣
}
return total;
}
function updateOrderStatus(order, status) {
order.status = status;
}
function saveOrder(order) {
database.save(order);
}
function processOrder(order) {
if (order.status === "pending") {
if (checkStock(order.items)) {
const total = calculateTotal(order.items, order.discountCode);
updateOrderStatus(order, "processed");
saveOrder(order);
} else {
updateOrderStatus(order, "out_of_stock");
}
}
}
- 原函数包含库存检查、总价计算、状态更新和订单保存等复杂逻辑。
- 重构后,每个任务被拆分到独立的小函数(如 checkStock、calculateTotal 等),使 processOrder 更简洁,逻辑更清晰。
(过长参数列表)对象封装参数
javascript
//问题代码:
function createUser(name, age, email, address, phone, gender) {
return { name, age, email, address, phone, gender };
}
// 改进代码(引入参数对象):
function createUser(userInfo) {
return { ...userInfo };
}
const user = createUser({
name: 'Alice',
age: 25,
email: '[email protected]',
address: '123 Street',
phone: '123456789',
gender: 'Female'
});
改进点:
- 使用对象作为参数,避免参数过多
- 提高函数的可扩展性和可维护性
重构工具
检测工具
- sonar 生成质量报告
IDE
vscode
实测vscode 只支持简单的 Rename symbol重命名
refactor 也只有简单的剪切方法
使用vscode重构代码不太理想
webstorm
实测非常强大,跟另外一个IDEA一样强大, 支持各个重命名,方法提取,类提取
单元与集成测试
- Jest juejin.cn/post/693023...
- vitest juejin.cn/post/740032...
- Cypress juejin.cn/post/740032...
结语
Clean Code 和代码重构是提升代码质量的重要手段。实践过程中,可以遵循以下原则:
- 保持代码清晰易懂
- 减少重复代码,提取可复用逻辑
- 合理设计参数,避免过长参数列表
- 持续优化代码,提高可维护性
推荐书籍:
- 《重构:改善既有代码的设计》
- 《代码整洁之道》