Improving code quality and reducing technical debt with ChatGPT

OpenAI’s ChatGPT, an advanced AI language model, stands out for its ability to interpret human-written text and generate responses in both written prose and programming code. This feature makes ChatGPT a multifaceted software development tool to help ensure code quality and avoid technical debt.

Kent Beck, a pioneer of software design patterns and one of 17 original signatories of the Agile Manifesto, and Martin Fowler, a software engineer and specialist in object-oriented design and analysis, coined the term code “smell” for patterns that may indicate design defects. These defects aren’t bugs but, rather, are things that could cause them or impede development—something that posed a challenge to Beck and Fowler’s practice of extreme programming. Code smells generate technical debt—the hidden cost of choosing quick, simple solutions that require future rework rather than spending effort now on a more effective solution.

ChatGPT empowers developers to tackle code quality issues and manage technical debt effectively. It helps generate and complete code, spot and recommend fixes for code smells, refactor, and enrich code documentation.

This tutorial demonstrates how to use ChatGPT to improve code quality, including identifying code smells and refactoring code. It then examines ChatGPT’s limitations and best practices for software development.

Identifying code smells with ChatGPT

ChatGPT helps you find code smells in a .NET codebase. Though you can use any language, this tutorial uses C#.

To identify code smells, first, prepare your code. Extract the relevant code snippets and ensure they’re correctly formatted and easily readable. ChatGPT works best when you break your code into smaller chunks and give the AI enough context to understand the code.

Next, submit a clear and concise prompt. For instance, you could ask ChatGPT to identify code smells in the snippet or check if your code follows a particular SOLID object-oriented design principle. SOLID is an acronym that stands for five key object-oriented design principles: single responsibility, open-closed design, Liskov substitution, interface segregation, and dependency inversion.

Then, analyze ChatGPT’s response. Note, though, that its feedback isn’t perfect, as the following example demonstrates. So always use your judgment as a developer to determine which suggestions to implement.

Example

ChatGPT prompt: Please analyze the following piece of C# code and identify any potential code smells present within it.


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: This method seems to be more interested in the WordDictionary class, using its data and operations frequently. This suggests that the method might be better suited within WordDictionary itself.
  • Inappropriate Intimacy/Breach of Encapsulation: The method directly manipulates wordDictionary._gloomScore which seems to be a private field. The method should respect the object's encapsulation and should not directly access its fields. Instead, use methods to manipulate them.
  • Redundant Code: GloomWordsContain check and TryGetValue operation is redundant. The TryGetValue method itself can be used to check whether the key exists and get the value. The use of gloom[i] can also be replaced with foreach.
  • Bad API: The method modifies the state of an object passed in as a parameter (wordDictionary), which might not be expected by users of this method. It is generally a bad idea to change the state of an object passed to a method.

ChatGPT’s response effectively pinpoints feature envy, noting that the function ComputeGloom appears more engaged with the WordDictionary class than its own class. Feature envy occurs when a method appears more interested in a class other than its own. It often indicates that you should place the method’s responsibilities within the class that it “envies.” ChatGPT also detects inappropriate intimacy or breach of encapsulation, redundant code, and possibly an inadequate API.

The final code smell might be a false positive. The bad API suggestion could be wrong since the method’s user expects the application to return the calculated gloom somehow. The method type being void indicates this expectation.

Refactoring code using ChatGPT

Refactoring restructures existing code without changing functionality to improve its readability, maintainability, and overall quality. ChatGPT can suggest refactoring techniques to optimize your code. When given the previous sample code, ChatGPT suggests the following refactoring methods.

Example

ChatGPT prompt: Present the refactored version of the given code to address any detected code smells or issues. Provide a comprehensive summary of all the modifications made, including an explanation of why the resulting refactored code is an improvement over the original version.


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;
}
}
}

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;
}
}
}
}

Here's the summary of changes and the reasons behind them:

  • Make WordDictionary._gloomScore a public property with a private setter:
    This makes it easier to read the GloomScore from outside the class, while still preventing external code from changing it directly. This ensures data integrity.
  • Remove the need for direct access to wordDictionary instance:
    The ComputeGloom method is now an instance method within the WordDictionary class. This makes more sense conceptually, as it's an operation performed on a WordDictionary instance.
  • Merge GloomWords Contain and Gloom Words.TryGetValue:
    The TryGetValue method of a dictionary both checks for the key and retrieves the value in one go. This prevents the need for two dictionary accesses, thereby improving efficiency.
  • Use 'foreach' instead of 'for':
    This makes the code cleaner and more readable. There's no need to manually manage an index variable in this case, as we're not using it for anything other than accessing elements.
  • Move initial setting of GloomScore to constructor:
    This ensures that every instance of WordDictionary has an initial GloomScore of O without requiring an explicit call to ComputeGloom.
  • The refactored code is cleaner and more efficient, with improved data encapsulation and readability. The WordDictionary class now has a clear responsibility, and its public interface only exposes necessary information.

Asking ChatGPT to explain the refactoring helps deepen your understanding of how to restructure code. Then, you can apply the same techniques in the future, minimizing the need to address code smells.

Adopting best practices with ChatGPT in C#

It’s vital to adhere to industry-accepted best practices for software development. These guidelines enhance the software’s readability, maintainability, and scalability, ensuring the code remains robust and less prone to bugs.

ChatGPT can analyze your code, identify areas where it deviates from best practices, and suggest improvements. This section explores how ChatGPT can help you implement SOLID object-oriented design principles in your C# codebase, including the Interface Segregation Principle (ISP). The ISP states that clients shouldn’t be forced to depend on interfaces they don’t use.

Example

ChatGPT prompt: Could you analyze this code and point out areas where it could potentially be improved? Are there any best practices, design principles, or conventions that seem to be missing or have not been appropriately implemented?


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();
}
}

Here’s the response:

There are a few points to discuss in this code:

  • Interface Segregation Principle (ISP): This is one of the SOLID principles. It states that no client should be forced to depend on interfaces they do not use. Here, WordDictionary implements IDictionaryOperations but does not need AddWord and RemoveWord methods, as shown in the comments. Therefore, this code violates the ISP. If these methods aren't relevant for all classes implementing IDictionaryOperations, it might be better to split this interface into two: one for computing and retrieving the gloom score, and another for manipulating the dictionary.
  • NotImplementedException usage: It's a bad practice to implement an interface and then throw a NotImplemented Exception for the methods you don't want to use. Instead of throwing an exception, if you find that some of the methods don't apply to your class, you might reconsider your class and interface design (see the point about ISP above).
  • Access Modifiers and Encapsulation: Class WordDictionary has a dependency on Dictionary<string, int>. This dependency is passed through its constructor and can be accessed from outside of the class. You might want to reconsider this to fully encapsulate the data within your class. If it's absolutely necessary for it to be supplied externally, then consider making a deep copy to avoid potential problems with mutable data.
  • Naming Convention: ComputeGloom and GetGloomScore could have better names to indicate what they do. Methods should be verbs or verb phrases, and they should clearly communicate their effects. For example, ComputeGloomScore would be better than ComputeGloom, and GetGloomScore could be RetrieveGloomScore.
  • Potential Inconsistency: The method ComputeGloom resets and then recalculates _gloomScore each time it is called. If there's a possibility of the underlying _gloomWords changing between calls to ComputeGloom and GetGloomScore, it may result in unexpected behavior. To avoid this, consider recalculating the score within GetGloomScore or at the moment gloomWords changes.
  • Immutability: The field _gloomScore is mutable. You could consider making it a computed property, based on _gloomWords, which would make your class more robust against state manipulation and potential bugs.
  • Testing and Maintainability: With the current design, the class could be difficult to unit test due to the internal state changes. Designing with testability in mind could lead to clearer, more maintainable code.

ChatGPT identifies that the code violates the Interface Segregation Principle (ISP). It recommends splitting the IDictionaryOperations interface into more granular interfaces, enabling classes to implement only the relevant methods. ChatGPT also points out other concerns, such as misuse of NotImplementedException, insufficient data encapsulation, ambiguous method naming, and potential state inconsistency.

Integrating ChatGPT into the development process

Integrating ChatGPT into your C#/.NET development process can enhance productivity and code quality. To augment the development process, you can leverage powerful tools, such as GitHub’s Copilot and CodeGPT, to help with the following tasks:

  • Code generation — Utilizing these extensions, developers can effortlessly generate boilerplate C#/.NET code. By simply describing the high-level functionality, the extensions create classes, interfaces, and methods, thereby saving development time and maintaining consistency across the codebase.
  • Code suggestions — Tools like GitHub Copilot and CodeGPT can suggest improved coding practices. You can directly ask these extensions to generate optimized and efficient code suggestions by highlighting your code.
  • Documentation assistance — These AI-powered extensions can aid in writing XML comments for C# methods, properties, and classes, ensuring a well-documented codebase.
  • Code reviews — You can use these extensions to check code adherence to established coding conventions, such as naming and indentation. The tools ensure compliance with best practices and ensure you’re correctly using C# features like async/await pattern matching.
  • Pair programming — GitHub Copilot and CodeGPT also offer real-time code suggestions and sample code snippets, enhancing the pair programming experience. These tools even help debug code by suggesting potential issues.
  • Testing and debugging — Leveraging these tools can assist in writing unit tests using popular testing frameworks like NUnit or xUnit, and they can suggest potential edge cases or test scenarios.

The ChatGPT Whisper API enables you to programmatically use the AI within your C#/.NET development processes, enhancing productivity and code quality.

Implement these best practices to integrate ChatGPT into your C#/.NET development process successfully:

  • Identify use areas — Select parts of the development process where ChatGPT can add value.
  • Integrate tools — Incorporate ChatGPT into daily tools through IDE plugins and extensions.
  • Customize it to your specific needs — Fine-tune ChatGPT on individual codebases to align with your organization’s unique coding styles and business logic.
  • Train the team — Run training sessions to ensure your development team effectively uses ChatGPT.
  • Continuously assess and adjust — Regularly evaluate the ChatGPT integration’s impact and adjust based on feedback.
  • Scale gradually — After successful initial implementation, expand ChatGPT use across the development process.

Remember, though, that it’s best for human developers to review and verify ChatGPT’s suggestions.

Limitations and best practices

Although ChatGPT helps enhance code quality and address technical debt, it does have some limitations:

  • It may produce false positives or negatives, recommending unnecessary changes or missing required ones, so assess its suggestions critically.
  • ChatGPT may not grasp complex domain-specific requirements or proprietary coding practices. So, pair this tool with domain expertise that offers additional context and knowledge that the AI might lack.
  • It needs a comprehensive understanding of the entire codebase to avoid missing broader issues like architectural defects or inefficiencies. It’s best to combine ChatGPT with a robust code review process to ensure you don’t overlook these broader considerations.
  • ChatGPT may only partially consider nonfunctional requirements such as performance, security, usability, and scalability, as its focus is primarily on code structure and syntax. Integrate ChatGPT with other testing and optimization tools to address these concerns fully.
  • It may introduce privacy concerns. Software engineers in enterprises should be careful not to leak sensitive data by using ChatGPT. Always check your company’s policies before using AI-based tools, ensuring compliance with data privacy and security standards.

Despite these shortcomings, ChatGPT helps spot code smells, propose refactoring options, and promote best practices. This AI tool can supplement—not substitute—experienced developers’ expertise and judgment. Below are some best practices for using ChatGPT in development:

  • Use ChatGPT for creating boilerplate code — Quickly generate standard parts of your application, reducing human error and repetitive tasks, saving significant development time.
  • Use ChatGPT to create code structures that you have to fill in later — Make your development more organized and reduce the cognitive load associated with architecting from scratch, improving overall code quality.
  • Use ChatGPT to explain code generated by open source or third-party dependencies — Simplify the understanding of complex code structures, making it easier to integrate, customize, or debug external libraries and dependencies in your project.
  • Use ChatGPT to generate documentation and unit test cases from legacy code — You can facilitate the proper testing coverage and improved maintainability through accurate and up-to-date documentation.
  • Use ChatGPT to generate code that you can understand and then write it yourself — This not only helps beginners learn coding best practices, but also aids experienced developers in exploring alternative coding strategies.

Conclusion

When used effectively and cautiously, ChatGPT can help you enhance code quality and minimize technical debt. It helps identify code smells, and streamline refactoring across various programming languages. However, its limitations shouldn’t go unnoticed: It’s best to use ChatGPT for getting suggestions and ideas—but don’t yet use it for enforcing policies.

This AI-driven approach revolutionizes software development, improving efficiency and innovation, leading to cleaner code and lower technical debt. Start experimenting with ChatGPT today to transform your coding practices.

Was this article helpful?

Related Articles

Write For Us

Write for Site24x7 is a special writing program that supports writers who create content for Site24x7 "Learn" portal. Get paid for your writing.

Write For Us

Write for Site24x7 is a special writing program that supports writers who create content for Site24x7 “Learn” portal. Get paid for your writing.

Apply Now
Write For Us