代码如屎山~~~如何让它成为“艺术”,改造成人见人爱的代码???

职场   2024-11-26 11:28   福建  

有时候看别人的项目的代码或者自己以前写的代码,总感觉如屎山一样,一点都不清爽干净~~~

干净代码要的是简洁、清晰且易于维护,它遵循一定的规范和实践,避免了复杂性和冗余。

干净代码风格是一致的,例如缩进、命名风格(驼峰命名或下划线命名)、括号位置等。

干净代码的重要性在于它提高了开发效率,减少了错误,并确保了代码库能够长期得到有效维护和更新。

尽管对干净代码的理解存在主观性,但遵循通用的编码约定可以帮助我们写出更好的代码。


1、使用有意义的变量、函数和类的名字

避免 x 或 temp 这样的通用变量名,而使用 userAge 或 tempFilePath:

不推荐的通用变量名:

// 不明确的变量名,不清楚变量的用途let x = 10;let temp = "example.txt";

推荐的描述性变量名:

// 明确的变量名,一目了然变量的用途let userAge = 10; // 表示用户的年龄let tempFilePath = "example.txt"; // 表示临时文件的路径

2、注释只解释“为什么”

避免在代码中写“显而易见”的注释,注释应当说明设计决策和背景,而不是解释代码做了什么。

避免的“显而易见”的注释:

// 将数组中的每个元素乘以2let doubledArray = array.map(item => item * 2);

在这个例子中,注释直接解释了代码的行为,这是显而易见的,因为从map函数和乘法操作就可以直接看出意图。

更有价值的注释:

// 根据用户的权限等级调整定价策略// 如果用户是VIP,则应用额外的折扣let finalPrice = calculatePriceWithDiscount(basePrice, user.isVIP);

另一个例子:

// 检查用户是否已登录if (user.isLoggedIn) {  // 用户已登录,允许访问受保护的资源  allowAccessToProtectedResource();} else {  // 用户未登录,重定向到登录页面  redirectToLogin();}

这里的注释解释了代码块的意图和设计决策,而不是简单地重述代码做了什么。

更好的做法:

// 为了避免未来代码修改时忘记更新注释,最好让代码本身尽可能清晰// 并且只在必要时添加注释function applyVipDiscount(price) {  return price * 0.9; // VIP用户享受10%的折扣}
// 检查用户是否有权访问受保护的资源// 这个检查包括了用户登录状态和权限等级的验证if (userHasAccess(user)) { allowAccessToProtectedResource();} else { redirectToLogin();}
  • applyVipDiscount 函数的注释解释了折扣的逻辑,这是未来可能需要了解的信息,尤其是如果折扣逻辑发生变化时。

  • userHasAccess 函数则封装了登录状态和权限等级的检查,减少了重复代码和注释,使得代码更加清晰。


3、代码风格一致

代码风格一致,遵循团队的代码规范,例如缩进、命名风格(驼峰命名或下划线命名)、括号位置等。

缩进和空格:

// 正确的缩进和空格使用function calculateSum(a, b) {  let sum = a + b;  return sum;}
// 错误的缩进和空格使用function calculateProduct(a, b){let product= a * b;return product;}

驼峰命名(CamelCase):

// 使用驼峰命名的变量和函数let userFirstName;let userLastName;function getFullName() {  return userFirstName + ' ' + userLastName;}

下划线命名(snake_case):

// 使用下划线命名的变量和函数let user_first_name;let user_last_name;function get_full_name() {  return user_first_name + ' ' + user_last_name;}

团队应该选择一种命名风格,并在整个项目中一致地使用它。


4、简洁性与清晰性

简洁性有助于提高代码的可读性和可维护性,但同样重要的是确保代码清晰易懂。

简洁但不清晰:

const countVowels = s => (s.match(/[aeiou]/gi) || []).length;

这行代码虽然简洁,但对不熟悉正则表达式的开发者来说,可能不清楚它的作用。

晰但较长:

function countVowels(s) {  const vowelRegex = /[aeiou]/gi; // 定义一个正则表达式匹配元音  const matches = s.match(vowelRegex) || []; // 使用正则表达式找到所有匹配项  return matches.length; // 返回匹配项的数量}

这个函数虽然代码行数更多,但它清晰地展示了每一步的操作,使得其他开发者即使不熟悉正则表达式,也能理解代码的意图和功能。

通过这两个例子,我们可以看到,虽然简洁的代码节省空间,但清晰的代码更容易被理解和维护。

在编程中,我们需要在代码的简洁性和清晰性之间找到平衡。


5、代码可复用

代码可复用可以提高开发效率、减少错误、节省时间和资源。

通过复现有代码,开发人员可以节省时间和精力,提升代码质量和一致性,减少引入错误的风险。

可复用码还使得软件架构更加模块化和可扩展,从而在维护和更新代码库时更加容易。

不可复用的代码:

// 不可重用的代码,重复逻辑function sendWelcomeEmail(user) {  const welcomeMessage = `Welcome, ${user.name}!`;  sendEmail(user.email, "Welcome", welcomeMessage);}
function sendGoodbyeEmail(user) { const goodbyeMessage = `Goodbye, ${user.name}!`; sendEmail(user.email, "Goodbye", goodbyeMessage);}

在这个例子中,sendWelcomeEmail 和 sendGoodbyeEmail 函数执行相似的任务,但包含了复用的逻辑,这降低了代码的可复用性。

可复用的代码:

// 可重用的代码,提取公共逻辑function sendEmailToUser(user, subject, message) {  sendEmail(user.email, subject, message);}
// 使用可重用的函数function sendWelcomeEmail(user) { const welcomeMessage = `Welcome, ${user.name}!`; sendEmailToUser(user, "Welcome", welcomeMessage);}
function sendGoodbyeEmail(user) { const goodbyeMessage = `Goodbye, ${user.name}!`; sendEmailToUser(user, "Goodbye", goodbyeMessage);}

在这个例子中,我们提取了发送电子邮件的公共逻辑到 sendEmailToUser 函数中,这样它就可以被 sendWelcomeEmail 和 sendGoodbyeEmail 函数复用。


6、单一职责原则 (SRP)

每个函数或类只负责一个任务,避免“万能函数”或“上帝类”。

// 不好function processOrder(order) {  validateOrder(order);  saveOrderToDatabase(order);  sendOrderNotification(order);}
// 好function validateOrder(order) { /*...*/ }function saveOrder(order) { /*...*/ }function sendNotification(order/*...*/ }

7、模块化 

模块化是编写清晰代码的关键概念,它涉及将大型复杂代码分解成更小、更易管理的模块或函数,便于理解、测试和维护。

模块化优势:

  • 可重用性:模块可以在应用的不同部分或其他应用中重用,节省开发时间和精力。

  • 封装性:模块隐藏函数或对象的内部细节,只暴露必要的接口,减少代码耦合,提升代码质量。

  • 可扩展性:将大型代码分解成小模块,方便添加或移除功能,不影响整个代码库。

// 无模块化function calculatePrice(quantity, price, tax) {  let subtotal = quantity * price;  let total = subtotal + (subtotal * tax);  return total;}
// 有模块化function calculateSubtotal(quantity, price) { return quantity * price;}
function calculateTotal(subtotal, tax) { return subtotal + (subtotal * tax);}

8、错误处理

正确的错误处理能够防止程序意外崩溃,并提供有用的调试信息。

不好的处理方式是仅仅记录错误而不进行适当响应。

不好的错误处理方式:

try {    result = divide(x, y);} catch (error) {    console.error("An error occurred"); // 仅仅记录了一个通用的错误信息,没有具体说明问题}

好的错误处理方式:

try {    result = divide(x, y);} catch (error) {    if (error instanceof ZeroDivisionError) {        console.error("Division by zero error:", error.message); // 指出了具体的错误类型和信息    } else if (error instanceof ValueError) {        console.error("Invalid input:", error.message); // 提供了错误输入的具体信息    } else {        console.error("An unexpected error occurred:", error.message); // 处理其他未预期的错误    }}

9、测试

编写单元测试可以确保代码的正确性,并在重构时提供信心。

测试驱动开发(TDD)迫使开发者预先考虑各种情况和预期行为,从而编写出更清晰的代码。

使用 JavaScript 和 Jest 测试框架的单元测试:

// 测试加法函数的正确性test('addition works correctly', () => {    expect(add(2, 3)).toBe(5); // 测试正常的加法    expect(add(-1, 1)).toBe(0); // 测试负数和正数相加    expect(add(0, 0)).toBe(0); // 测试零值相加});

10、文件夹结构 

选择良好的文件夹结构是编写清晰代码的重要组成部分。

良好的项目结构帮助开发者轻松查找和修改代码,降低代码复杂性,提高项目的可扩展性和可维护性。

不好的目录结构:

my-app/├── App.js├── index.js├── components/│   ├── Button.js│   ├── Card.js│   └── Navbar.js├── containers/│   ├── Home.js│   ├── Login.js│   └── Profile.js├── pages/│   ├── Home.js│   ├── Login.js│   └── Profile.js└── utilities/    ├── api.js    └── helpers.js

好的目录结构:

my-app/├── src/│   ├── components/│   │   ├── Button/│   │   │   ├── Button.js│   │   │   └── index.js│   ├── pages/│   │   ├── Home/│   │   │   ├── Home.js│   │   │   └── index.js│   ├── utils/│   │   ├── api.js│   │   └── helpers.js│   ├── App.js│   └── index.js└── public/    ├── index.html    └── favicon.ico

虽然规范很多,但如果项目在稳定运行的时候,千万切记不要随便改动,稳定大于一切,不然改动史就会成为血泪史~~~


菜鸟教程
学的不仅是技术,更是梦想!
 最新文章