前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 ChatGPT 提高代码质量并减少技术债

使用 ChatGPT 提高代码质量并减少技术债

作者头像
一个正经的测试
发布2024-01-27 14:22:16
2340
发布2024-01-27 14:22:16
举报
文章被收录于专栏:一个正经的测试

前言

OpenAI 的 ChatGPT 是一种先进的人工智能语言模型,因其能够解释人类编写的文本并生成书面散文和编程代码的响应而脱颖而出。此功能使 ChatGPT 成为多方面的软件开发工具,有助于确保代码质量并避免技术债务。

软件设计模式的先驱者、《敏捷宣言》的 17 位原始签署者之一 Kent Beck 和软件工程师、面向对象设计和分析专家 Martin Fowler 为可能表明设计的模式创造了术语“代码气味”缺陷。这些缺陷不是 bug,而是可能导致这些缺陷或阻碍开发的因素,这对 Beck 和 Fowler 的极限编程实践提出了挑战。代码异味会产生技术债务——选择需要未来返工的快速、简单的解决方案而不是现在花精力寻找更有效的解决方案的隐性成本。

ChatGPT 使开发人员能够解决代码质量问题并有效管理技术债务。它有助于生成和完成代码、发现代码异味并提出修复建议、重构以及丰富代码文档。

本教程演示如何使用 ChatGPT 提高代码质量,包括识别代码异味和重构代码。然后,它检查了 ChatGPT 的局限性和软件开发的最佳实践。

使用 ChatGPT 识别代码异味

ChatGPT 可帮助您查找 .NET 代码库中的代码异味。尽管您可以使用任何语言,但本教程使用 C#。

要识别代码异味,首先要准备代码。提取相关代码片段并确保它们格式正确且易于阅读。当您将代码分解为更小的块并为 AI 提供足够的上下文来理解代码时,ChatGPT 效果最佳。

接下来,提交清晰简洁的提示。例如,您可以要求 ChatGPT 识别代码片段中的代码味道,或者检查您的代码是否遵循特定的 SOLID 面向对象设计原则。SOLID 是一个缩写词,代表五个关键的面向对象设计原则:单一责任、开闭设计、里氏替换、接口隔离和依赖倒置。

然后,分析 ChatGPT 的响应。但请注意,它的反馈并不完美,如以下示例所示。因此,请始终根据您作为开发人员的判断来确定要实施哪些建议。

例子

ChatGPT 提示:请分析以下 C# 代码并识别其中存在的任何潜在代码。

代码语言:javascript
复制
private void ComputeGloom(WordDictionary wordDictionary, 
                           List<string> gloom) 
{ 
    wordDictionary._gloomScore = 0; 
    for (int i = 0; i < gloom.Count; i++) 
    { 
        if (wordDictionary.GloomWordsContain(gloom[i])) 
        { 
            int val; } 
            wordDictionary.GloomWords.TryGetValue(gloom[i], out val); 
            wordDictionary._gloomScore += val; 
        } }   
    }
  • Feature Envy:这个方法似乎对类更感兴趣WordDictionary,经常使用它的数据和操作。这表明该方法可能更适合WordDictionary其本身。
  • 不适当的亲密/违反封装:该方法直接操作wordDictionary._gloomScore似乎是私有字段。该方法应该尊重对象的封装,并且不应该直接访问其字段。相反,使用方法来操纵它们。
  • 冗余代码:GloomWordsContain检查和TryGetValue操作是冗余的。该TryGetValue方法本身可用于检查键是否存在并获取值。的使用gloom[i]也可以替换为foreach
  • 错误的 API:该方法修改作为参数 ( ) 传入的对象的状态wordDictionary,这可能是该方法的用户所不希望的。更改传递给方法的对象的状态通常是一个坏主意。

ChatGPT 的回应有效地指出了,指出函数 ComputeGloom 似乎更多地与 WordDictionary 类相关,而不是与它自己的类相关。当一个方法对一个类而不是它自己的类更感兴趣时,就会发生特征嫉妒。它通常表明您应该将该方法的职责放在它的类中。ChatGPT 还可以检测不适当的亲密关系或封装破坏、冗余代码以及可能的 API 不足。

最终的代码可能是误报。糟糕的 API 建议可能是错误的,因为该方法的用户希望应用程序以某种方式返回计算出的暗度。方法类型为 void 表明了这种期望。

使用 ChatGPT 重构代码

ChatGPT 提示:呈现给定代码的重构版本,以解决任何检测到的代码异味或问题。提供所有所做修改的全面摘要,包括解释为什么重构后的代码比原始版本有所改进。

代码语言:javascript
复制

private void ComputeGloom(WordDictionary wordDictionary, 
                           List<string> gloom) 
{ 
    wordDictionary._gloomScore = 0; 
    for (int i = 0; i < gloom.Count; i++) 
    { 
        if (wordDictionary.GloomWordsContain(gloom[i])) 
        { 
            int val; 
            wordDictionary.GloomWords.TryGetValue(gloom[i], out val); 
            wordDictionary._gloomScore += val; 
        } 
    } 
}
代码语言:javascript
复制
public class WordDictionary 
{ 
  public Dictionary<string, int> GloomWords { get; private set; } 
  public int GloomScore { get; private set; } 

  public WordDictionary (Dictionary<string, int> gloomWords) 
  { 

    GloomWords gloomWords ?? new Dictionary<string, int>(); 
    GloomScore = 0; 
  } 

  public void ComputeGloom(List<string> gloom) 
  { 
    GloomScore = 0; 

    foreach (var word in gloom) 
    { 
      if (GloomWords.TryGetValue(word, out int val)) 
      { 
        GloomScore += val; 
      } 
    } 
  } 
}

下面是一些变化的总结以及背后的原因:

  • 使 WordDictionary. _ looomScore 成为带有私有 setter 的公共属性:
  • 这使得从类外部读取 GloomScore 变得更加容易,同时仍然可以防止外部代码直接更改它。这确保了数据的完整性。
  • 不需要直接访问 wordDictionary 实例:
  • ComputeGoom 方法现在是 WordDictionary 类中的一个实例方法。这在概念上更有意义,因为它是在 WordDictionary 实例上执行的操作。
  • 合并 GloomWords 包含和 GloomWords 试试价值:
  • Dictionary 的 TryGetValue 方法既检查键,又一次检索值。这可以避免需要两个字典访问,从而提高效率。
  • 使用 foreach 而不是 for:
  • 这使得代码更清晰、更易读。在这种情况下,不需要手动管理索引变量,因为除了访问元素之外,我们不会使用它做任何事情。
  • 将 GloomScore 的初始设置移动到构造函数:
  • 这样可以确保 WordDictionary 的每个实例都有一个初始的 GloomScore 为 O,而不需要显式调用 ComputeGoom。
  • 重构后的代码更清晰、更有效,数据封装和可读性也得到了改进。WordDictionary 类现在有一个明确的职责,它的公共接口只公开必要的信息。

在 C# 中采用 ChatGPT 的最佳实践

遵守行业公认的软件开发最佳实践至关重要。这些准则增强了软件的可读性、可维护性和可扩展性,确保代码保持健壮且不易出现错误。

ChatGPT 可以分析您的代码,识别偏离最佳实践的区域,并提出改进建议。本节探讨 ChatGPT 如何帮助您在 C# 代码库中实现 SOLID 面向对象的设计原则,包括接口隔离原则 (ISP)。ISP 规定客户端不应被迫依赖他们不使用的接口。

例子

ChatGPT 提示:您能否分析此代码并指出可以改进的地方?是否有任何最佳实践、设计原则或约定似乎缺失或未得到适当实施?

代码语言:javascript
复制
public interface IDictionaryOperations 
{ 
    void ComputeGloom(List<string> gloom); 
    int GetGloomScore(); 
    void AddWord(string word, int score); 
    void RemoveWord(string word); 
} 

public class WordDictionary : IDictionaryOperations 
{ 
    private int _gloomScore; 
    private Dictionary<string, int> _gloomWords; 

    public WordDictionary(Dictionary<string, int> gloomWords) 
    { 
        _gloomWords = gloomWords; 
        _gloomScore = 0; 
    } 

    public void ComputeGloom(List<string> gloom) 
    { 
        _gloomScore = 0; 
        foreach (var word in gloom) 
        { 
            if (_gloomWords.TryGetValue(word, out int val)) 
            { 
                _gloomScore += val; 
            } 
        } 
    } 
    public int GetGloomScore() 
    { 
        return _gloomScore; 
    } 

    public void AddWord(string word, int score) 
    { 
        // Not needed for this class but necessary because of the interface 
        throw new NotImplementedException(); 
    } 

    public void RemoveWord(string word) 
    { 
        // Not needed for this class but necessary because of the interface 
        throw new NotImplementedException(); 
    } 
}   

这是回应:

这段代码有几点需要讨论:

  • 接口隔离原则 (ISP):这是 SOLID 原则之一。它指出任何客户端都不应被迫依赖于他们不使用的接口。在这里,WordDictionary实现IDictionaryOperations但不需要AddWord方法RemoveWord,如注释中所示。因此,该代码违反了 ISP。如果这些方法并不与所有实现 的类相关IDictionaryOperations,那么最好将此接口分成两个:一个用于计算和检索 gloom 分数,另一个用于操作字典。
  • NotImplementedException 用法:实现接口然后为不想使用的方法抛出 NotImplemented 异常是一种不好的做法。如果您发现某些方法不适用于您的类,您可以重新考虑您的类和接口设计(请参阅上面有关 ISP 的观点),而不是抛出异常。
  • 访问修饰符和封装:类WordDictionary依赖于Dictionary<string, int>。此依赖项通过其构造函数传递,并且可以从类外部访问。您可能需要重新考虑这一点,以将数据完全封装在您的类中。如果绝对有必要从外部提供它,那么请考虑进行深层复制以避免可变数据的潜在问题。
  • 命名约定:ComputeGloom并且GetGloomScore可以有更好的名称来表明它们的作用。方法应该是动词或动词短语,并且应该清楚地传达其效果。例如,ComputeGloomScore会比ComputeGloom、 和GetGloomScore could更好RetrieveGloomScore
  • 潜在的不一致:该方法会在每次调用时ComputeGloom重置并重新计算。如果对和 的调用之间_gloomScore存在潜在变化的可能性,则可能会导致意外的行为。为了避免这种情况,请考虑在gloomWords 更改之内或当时重新计算分数。_gloomWordsComputeGloomGetGloomScoreGetGloomScore
  • 不变性:该字段_gloomScore是可变的。您可以考虑将其设为基于 的计算属性_gloomWords,这将使您的类对状态操作和潜在错误更加稳健。
  • 测试和可维护性:根据当前的设计,由于内部状态的变化,类可能很难进行单元测试。考虑到可测试性进行设计可以产生更清晰、更易于维护的代码。

ChatGPT 确定该代码违反了接口隔离原则 (ISP)。它建议将 IDictionaryOperations 接口拆分为更细粒度的接口,使类能够仅实现相关方法。ChatGPT 还指出了其他问题,例如 NotImplementedException 的误用、数据封装不足、方法命名不明确以及潜在的状态不一致。

将 ChatGPT 集成到开发流程中

将 ChatGPT 集成到 C#/.NET 开发流程中可以提高工作效率和代码质量。为了增强开发过程,您可以利用强大的工具(例如 GitHub 的 Copilot 和 CodeGPT)来帮助完成以下任务:

  • 代码生成——利用这些扩展,开发人员可以轻松生成样板 C#/.NET 代码。通过简单地描述高级功能,扩展可以创建类、接口和方法,从而节省开发时间并保持整个代码库的一致性。
  • 代码建议- GitHub Copilot 和 CodeGPT 等工具可以建议改进的编码实践。您可以通过突出显示您的代码,直接要求这些扩展生成优化且高效的代码建议。
  • 文档帮助——这些由 AI 驱动的扩展可以帮助为 C# 方法、属性和类编写 XML 注释,从而确保代码库有良好的文档记录。
  • 代码审查- 您可以使用这些扩展来检查代码是否遵守既定的编码约定,例如命名和缩进。这些工具可确保符合最佳实践,并确保您正确使用异步/等待模式匹配等 C# 功能。
  • 结对编程——GitHub Copilot 和 CodeGPT 还提供实时代码建议和示例代码片段,增强结对编程体验。这些工具甚至可以通过建议潜在问题来帮助调试代码。
  • 测试和调试——利用这些工具可以帮助使用 NUnit 或 xUnit 等流行的测试框架编写单元测试,并且它们可以建议潜在的边缘情况或测试场景。

ChatGPT Whisper API 使您能够在 C#/.NET 开发流程中以编程方式使用 AI,从而提高生产力和代码质量。

实施这些最佳实践以将 ChatGPT 成功集成到您的 C#/.NET 开发流程中:

  • 确定使用领域——选择开发过程中 ChatGPT 可以增加价值的部分。
  • 集成工具——通过IDE插件和扩展将ChatGPT整合到日常工具中。
  • 根据您的特定需求进行定制- 在各个代码库上微调 ChatGPT,以符合您组织的独特编码风格和业务逻辑。
  • 培训团队— 举办培训课程以确保您的开发团队有效地使用 ChatGPT。
  • 持续评估和调整— 定期评估 ChatGPT 集成的影响并根据反馈进行调整。
  • 逐步扩展——在成功的初步实施后,在整个开发过程中扩展 ChatGPT 的使用。

但请记住,人类开发人员最好查看并验证 ChatGPT 的建议。

结论

如果有效且谨慎地使用,ChatGPT 可以帮助您提高代码质量并最大程度地减少技术债务。它有助于识别代码异味,并简化各种编程语言的重构。然而,它的局限性不应被忽视:最好使用 ChatGPT 来获取建议和想法,但不要用它来执行政策。

这种人工智能驱动的方法彻底改变了软件开发,提高了效率和创新,从而使代码更简洁并降低了技术债务。立即开始尝试使用 ChatGPT 来改变您的编码实践。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-01-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一个正经的测试 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用 ChatGPT 识别代码异味
    • 例子
    • 使用 ChatGPT 重构代码
    • 在 C# 中采用 ChatGPT 的最佳实践
      • 例子
      • 将 ChatGPT 集成到开发流程中
      • 结论
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档