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.
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.
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;
}
}
}
WordDictionary
class, using its data and operations frequently. This suggests that the method might be better suited within WordDictionary
itself.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.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
.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 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.
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:
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.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.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.
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.
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:
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.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.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
.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._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.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 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:
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:
Remember, though, that it’s best for human developers to review and verify ChatGPT’s suggestions.
Although ChatGPT helps enhance code quality and address technical debt, it does have some limitations:
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:
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.
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