作为一个程序员,我每天都在和代码打交道。写新代码是一件快乐的事,但维护旧代码,尤其是别人写的烂代码,就是一件痛苦的事了。

我相信每个程序员都有过这样的经历:接手一个老项目,打开代码一看,变量名不知所云,函数动辄几百行,注释少得可怜,重复代码到处都是。想加一个新功能,不知道从哪里下手;想修一个bug,改了一处又坏了另一处。

这种时候,重构就成了唯一的出路。但重构是一件费时费力的事情,需要仔细阅读代码、理解逻辑、设计新的结构,然后一步步修改。一个几千行的模块,重构可能需要好几天。

但自从我开始用Claude 3.5 Sonnet之后,代码重构的效率提升了不止一倍。以前需要几天的重构工作,现在几个小时就能完成,而且质量还更高。

这篇文章,就来分享一下我用Claude 3.5 Sonnet做代码重构的实战经验,从提示词设计到重构流程,聊聊AI如何帮助我们写出更优雅、更易维护的代码。

为什么需要代码重构

在讲具体方法之前,先说说为什么需要代码重构。

代码重构,就是在不改变外部行为的前提下,改善代码的内部结构。它的目的,是让代码更容易理解、更容易维护、更容易扩展。

很多程序员觉得重构是浪费时间,觉得代码能跑就行。但实际上,烂代码的维护成本是非常高的。有研究表明,程序员花在阅读和理解代码上的时间,占了工作时间的60%以上。如果代码写得很烂,理解起来就更费劲,维护成本就更高。

烂代码的典型特征有:

  • 变量名和函数名不清晰,看不懂是干什么的
  • 函数太长,一个函数做了太多事情
  • 重复代码多,同样的逻辑在多个地方出现
  • 注释少或者注释过时
  • 嵌套太深,if里面套if,套了好几层
  • 魔法数字和字符串到处都是
  • 耦合度高,改一个地方要动很多文件
  • 没有单元测试,不敢随便改

这些问题,会让代码越来越难维护。到最后,加一个小功能都要小心翼翼,修一个bug都要冒很大的风险。

重构的目的,就是解决这些问题,让代码重新变得健康。

Claude 3.5 Sonnet在代码重构中的优势

Claude 3.5 Sonnet在代码重构方面,有几个明显的优势。

第一个优势,是理解能力强。Claude 3.5 Sonnet能很好地理解代码的逻辑和意图,即使代码写得很烂,它也能大致看懂代码在做什么。这是重构的基础,看不懂代码就没法重构。

第二个优势,是知识面广。Claude 3.5 Sonnet学习了海量的代码,了解各种设计模式、最佳实践和编码规范。它能根据代码的情况,给出合理的重构建议,应用合适的设计模式。

第三个优势,是不知疲倦。重构是一件枯燥的事情,人做久了会累,会出错。但AI不会,它可以一遍又一遍地分析和修改代码,保持稳定的质量。

第四个优势,是速度快。人重构一个函数可能需要十几分钟,AI只需要几秒钟。虽然AI的输出需要人工审核,但整体速度还是快了很多。

当然,Claude 3.5 Sonnet也不是万能的。它有时候会理解错代码的意图,有时候会引入新的bug,有时候会过度设计。所以,用AI重构代码,不能完全依赖它,需要人工的审核和把控。

重构前的准备

在用Claude 3.5 Sonnet重构代码之前,需要做一些准备工作。

第一步,是确保代码有版本控制。重构可能会引入bug,所以一定要用Git等版本控制工具,在重构前提交一个干净的版本。这样,如果重构出了问题,可以随时回滚。

第二步,是确保代码有测试。重构的原则是不改变外部行为,所以需要有测试来验证重构后的代码和原来的代码行为一致。如果没有测试,可以先写一些单元测试或者集成测试,作为重构的安全网。

第三步,是了解代码的整体结构。在重构之前,先花一些时间阅读代码,了解代码的整体结构、主要模块、数据流和依赖关系。这样,在重构的时候,才能有一个全局的视角,不会陷入局部优化。

第四步,是确定重构的范围。不要一上来就重构整个项目,那样风险太大。可以先从一个模块、一个类或者一个函数开始,逐步扩大范围。

做好这些准备之后,就可以开始用Claude 3.5 Sonnet进行重构了。

提示词设计:让AI理解你的需求

用Claude 3.5 Sonnet重构代码,最关键的是提示词的设计。一个好的提示词,能让AI准确理解你的需求,给出高质量的重构结果;一个差的提示词,可能会让AI理解偏差,给出不相关甚至错误的结果。

我总结了一个代码重构的提示词模板,包含以下几个部分:

第一部分,是角色设定。告诉AI它是谁,应该以什么身份来重构代码。比如:"你是一个资深的软件架构师,有十年以上的开发经验,精通代码重构和设计模式。"

第二部分,是任务描述。清楚地告诉AI你要做什么。比如:"请重构下面的代码,提高代码的可读性和可维护性。"

第三部分,是重构要求。列出你对重构的具体要求。比如:

  • 保持代码的外部行为不变
  • 使用有意义的变量名和函数名
  • 将长函数拆分成小函数,每个函数只做一件事
  • 消除重复代码
  • 减少嵌套层级
  • 添加必要的注释
  • 应用合适的设计模式
  • 遵循特定的编码规范(比如PEP 8、Google Style等)

第四部分,是输出格式。告诉AI你希望它怎么输出。比如:"请先分析代码存在的问题,然后给出重构后的代码,最后解释重构的思路和改动点。"

第五部分,是代码本身。把要重构的代码贴在最后。

一个完整的提示词示例:

你是一个资深的Python开发工程师,有十年以上的开发经验,精通代码重构和设计模式。

请重构下面的Python代码,提高代码的可读性和可维护性。

重构要求:
1. 保持代码的外部行为不变,不要改变功能
2. 使用有意义的变量名和函数名,不要用拼音或缩写
3. 将长函数拆分成小函数,每个函数不超过50行
4. 消除重复代码,提取公共逻辑
5. 减少嵌套层级,使用提前返回(early return)
6. 添加必要的注释和文档字符串
7. 遵循PEP 8编码规范
8. 如果合适,可以应用设计模式,但不要过度设计

请按以下格式输出:
1. 代码问题分析:列出代码存在的主要问题
2. 重构后的代码:完整的重构后代码
3. 重构说明:解释主要的改动点和原因

代码如下:
[在这里贴代码]

这个提示词模板,我用了很多次,效果都不错。当然,你可以根据具体的需求,调整要求和格式。

重构实战:一个烂函数的改造

下面,我用一个实际的例子,来演示一下如何用Claude 3.5 Sonnet重构代码。

假设我们有这样一个函数,用来处理用户的订单:

def process_order(data, user):
    if user is None:
        return None
    if data is None:
        return None
    if 'items' not in data:
        return None
    if len(data['items']) == 0:
        return None
    total = 0
    for item in data['items']:
        if 'price' in item and 'quantity' in item:
            if item['price'] > 0 and item['quantity'] > 0:
                total += item['price'] * item['quantity']
    if total <= 0:
        return None
    if 'discount' in data:
        if data['discount'] > 0 and data['discount'] < 1:
            total = total * (1 - data['discount'])
    if user['vip']:
        total = total * 0.9
    if total > 1000:
        total = total - 100
    order = {}
    order['user_id'] = user['id']
    order['items'] = data['items']
    order['total'] = total
    order['status'] = 'pending'
    order['created_at'] = datetime.now()
    db.session.add(order)
    db.session.commit()
    return order

这个函数,有很多问题:

  • 函数太长,做了太多事情
  • 嵌套太深,if里面套if
  • 没有注释,看不懂逻辑
  • 魔法数字(0.9、1000、100)
  • 校验逻辑和业务逻辑混在一起
  • 直接操作数据库,没有抽象

我把这个函数和提示词一起发给Claude 3.5 Sonnet,它给出了这样的重构结果:

问题分析:

  1. 函数职责过多,包含参数校验、价格计算、折扣计算、订单创建、数据库保存等多个职责
  2. 嵌套层级过深,多个if嵌套,可读性差
  3. 缺少注释和文档字符串
  4. 存在魔法数字(VIP折扣0.9、满减门槛1000、满减金额100)
  5. 参数校验逻辑分散,可以统一处理
  6. 直接操作数据库,耦合度高

重构后的代码:

VIP_DISCOUNT_RATE = 0.9
FREE_SHIPPING_THRESHOLD = 1000
FREE_SHIPPING_AMOUNT = 100

def process_order(order_data, user):
    """
    处理用户订单,计算价格并创建订单记录。
    
    Args:
        order_data: 订单数据,包含商品列表和折扣信息
        user: 用户信息
        
    Returns:
        创建的订单对象,如果参数无效则返回None
    """
    if not _is_valid_order_data(order_data) or not user:
        return None
        
    subtotal = _calculate_subtotal(order_data['items'])
    if subtotal <= 0:
        return None
        
    total = _calculate_final_price(subtotal, order_data, user)
    return _create_order(user, order_data['items'], total)

def _is_valid_order_data(order_data):
    """校验订单数据是否有效。"""
    return (
        order_data is not None
        and 'items' in order_data
        and len(order_data['items']) > 0
    )

def _calculate_subtotal(items):
    """计算商品小计金额。"""
    subtotal = 0
    for item in items:
        price = item.get('price', 0)
        quantity = item.get('quantity', 0)
        if price > 0 and quantity > 0:
            subtotal += price * quantity
    return subtotal

def _calculate_final_price(subtotal, order_data, user):
    """计算最终价格,应用折扣和优惠。"""
    total = subtotal
    
    # 应用订单折扣
    discount = order_data.get('discount', 0)
    if 0 < discount < 1:
        total *= (1 - discount)
        
    # 应用VIP折扣
    if user.get('vip', False):
        total *= VIP_DISCOUNT_RATE
        
    # 应用满减优惠
    if total > FREE_SHIPPING_THRESHOLD:
        total -= FREE_SHIPPING_AMOUNT
        
    return total

def _create_order(user, items, total):
    """创建订单记录并保存到数据库。"""
    order = {
        'user_id': user['id'],
        'items': items,
        'total': total,
        'status': 'pending',
        'created_at': datetime.now()
    }
    db.session.add(order)
    db.session.commit()
    return order

重构说明:

  1. 将原函数拆分成了5个小函数,每个函数只做一件事
  2. 用提前返回替代了深层嵌套,提高了可读性
  3. 提取了魔法数字为常量
  4. 添加了文档字符串和注释
  5. 分离了参数校验、价格计算和订单创建的逻辑
  6. 用dict.get()替代了in判断,简化了代码

这个重构结果,质量非常高。代码结构清晰,每个函数职责单一,可读性和可维护性都大大提升了。而且,外部行为完全没有改变。

当然,这只是一个简单的例子。在实际项目中,代码可能更复杂,重构的难度也更大。但方法是一样的:设计好提示词,让AI分析和重构,然后人工审核和调整。

重构的流程和技巧

根据我的经验,用Claude 3.5 Sonnet重构代码,可以遵循以下流程。

第一步,从小处开始。不要一上来就重构整个文件或整个模块。先从一个函数开始,让AI重构,看看效果。如果效果好,再逐步扩大范围。

第二步,分步骤重构。对于复杂的代码,可以分多步进行重构。比如,第一步先修改变量名和函数名,第二步拆分长函数,第三步消除重复代码,第四步应用设计模式。每一步都让AI做一件事,这样更容易控制质量。

第三步,人工审核每一步。AI的输出不是完美的,每一步重构之后,都要仔细审核代码,确保逻辑正确,没有引入bug。特别是涉及到边界条件和异常处理的地方,要重点检查。

第四步,运行测试。每一步重构之后,都要运行测试,确保代码的行为没有改变。如果没有测试,可以手动验证关键功能。

第五步,迭代优化。第一次重构的结果可能不够好,可以让AI继续优化。比如,你可以说"这个函数还是有点长,请再拆分一下",或者"这里可以用策略模式来优化,请修改一下"。通过多轮迭代,让代码越来越优雅。

除了这个流程,还有几个小技巧:

技巧一,给AI足够的上下文。如果代码依赖了其他模块,要把相关的代码也发给AI,或者告诉AI相关的接口定义。这样AI才能更好地理解代码,给出更合理的重构方案。

技巧二,明确编码规范。如果团队有特定的编码规范,要在提示词中告诉AI,比如"遵循Google Java Style"或者"使用ESLint的airbnb配置"。这样重构后的代码才能符合团队的规范。

技巧三,控制重构的幅度。告诉AI不要改变代码的外部行为,不要改变接口,不要引入新的依赖。这样可以降低重构的风险。

技巧四,让AI解释重构思路。让AI在输出代码的同时,解释重构的思路和改动点。这样你可以更好地理解AI的改动,也更容易发现问题。

常见问题和注意事项

用Claude 3.5 Sonnet重构代码,也会遇到一些问题。这里列出几个常见的问题和注意事项。

第一个问题,是AI会改变代码的行为。虽然我们在提示词中要求保持外部行为不变,但AI有时候还是会无意中改变一些细节。比如,它可能会改变异常处理的方式,或者改变边界条件的处理。所以,一定要有测试来验证,并且人工仔细审核。

第二个问题,是AI会过度设计。有时候,AI会为了应用设计模式而应用设计模式,把简单的问题复杂化。比如,一个只有两个分支的逻辑,它可能会用策略模式来重构,结果代码反而更复杂了。这时候,需要人工判断,告诉AI不要过度设计。

第三个问题,是AI会遗漏一些细节。对于复杂的代码,AI可能会遗漏一些边界条件或者特殊处理。比如,它可能会忘记处理某个异常,或者忽略某个特殊的输入。这时候,需要人工补充和修正。

第四个问题,是AI不了解项目的上下文。AI只能看到你发给它的代码,它不了解项目的整体架构、业务逻辑和历史原因。所以,它的重构建议可能在局部是好的,但在全局来看可能不合适。这时候,需要你从全局的角度来判断和调整。

第五个问题,是安全和隐私。如果代码中包含敏感信息(比如密钥、密码、用户数据),不要直接发给AI。可以先把敏感信息替换成占位符,再发给AI。

写在最后

用Claude 3.5 Sonnet做代码重构,是我今年发现的最实用的AI应用之一。它大大提高了重构的效率,让我有更多的时间去做更有价值的事情。

但我想说的是,AI只是一个工具,它不能代替程序员的思考和判断。重构的核心,不是把代码丢给AI,让它改一改就完事了。重构的核心,是理解代码、发现问题、设计更好的结构,然后一步步实现。AI可以帮我们做一些机械性的工作,但最终的决策和质量把控,还是要靠人。

所以,在用AI重构代码的时候,不要完全依赖它。要把它当作一个助手,一个能力很强但需要你指导和审核的助手。你告诉它方向,它帮你执行,你再检查和调整。这样,才能既提高效率,又保证质量。

希望这篇文章,能帮你更好地用Claude 3.5 Sonnet来重构代码,让你的代码从烂代码变成优雅代码。

愿每个程序员,都能写出优雅、易维护的代码,都能享受编程的乐趣。