AI-Assisted Programming: Accelerating Development with Artificial Intelligence Tools

10-11-2024 – by Gustavo Aquino · 7 min read

#ai#development

Context

I recently came across a mid-sized frontend application written in Angular 6 (yes, which reached EOL back in 2019). The task was to upgrade the project to an LTS (Long Term Support) version of Angular. As a first move, I chose to upgrade to the first available LTS version, 16.2.X. However, I'm not a frontend specialist, nor deeply familiar with the Node.js stack, and I'd need a lot of time or the support of another developer with more knowledge of the framework.

The project had 40 modules and 175 components, broken down as shown in the table below:

===============================================================================
 Language            Files        Lines         Code     Comments       Blanks
===============================================================================
 CSS                     6          334          271           20           43
 HTML                  180        11903        10206          693         1004
 JavaScript              4           78           49           19           10
 JSON                    2           22           22            0            0
 Sass                  247        12575         9431         1284         1860
 SVG                     2            4            4            0            0
 TypeScript            370        36123        27318         2904         5901
===============================================================================
 Total                 811        61039        47301         4920         8818
===============================================================================

Getting support from another developer wasn't an option, and I also couldn't spend weeks on the migration project. So I decided to try an approach I'd recently seen on some YouTube channels: experimenting with an AI Code Assist tool in the IDE. Although I normally use JetBrains IDEA and GitHub Copilot for backend projects, in this case I wanted to try something new, more focused on my goal: leaning on it to make up for my elementary frontend and Angular knowledge, working in a Driver and Navigator style of pair programming [1], alternating between moments where the AI generated code and I reviewed it, and vice versa.

Tools

For this task, I chose to try out the Cursor [2] code editor, which has native AI integration and promises a productivity boost through a number of features. Below, I highlight the ones I used, though there are other advanced ones described in the documentation [3].

  • Tab: to suggest or edit code based on an existing snippet or a description;
    • Cursor Prediction: after an edit made with Tab, Cursor predicts additional snippets that could be fixed the same way and automatically jumps to the next one with another tab ⇥;
  • Chat: to interact with the AI and understand a piece of code or ask for an implementation suggestion;
    • AI Fix in Chat: where an error caught by the linter is highlighted, and the AI opens a popup suggesting a fix;
    • Apply: to apply the AI's suggestions directly in the editor;

To use Cursor, a premium subscription is not required, although usage is limited [4]. In my case, I chose the Pro subscription to guarantee unlimited use of the completions and instant apply features.

With Cursor, node version 20.11, and the desired version of the Angular CLI installed, I got to work.

Interacting with Cursor's AI

The first thing I did was generate a new project with version 16 of the Angular CLI and compare the differences between the old project and the new one. I noticed that some files were no longer needed, like angular-cli.json, while others needed to be created or adjusted, like angular.json, tsconfig.json, tslint.json, and tsconfig.app.json. I delegated the task of fixing these files to the AI through prompts in the following format:

Update the angular-cli.json file (in context) for Angular version 16.

With the following result:

chat
Figure 1. Chatting with the AI to update the angular-cli.json file

And the changes suggested by the AI were applied directly to the target file:

chat apply
Figure 2. Result of the AI-suggested changes using the Apply feature

Once the project's base files were updated, I moved on to the dependencies. Naturally, many no longer existed, or had been renamed. So I had to manually fix a few dependencies based on searches on npm.js — for example, angular-http, which was folded into angular-common, or angular2-fontawesome, which was discontinued and replaced by @fortawesome/angular-fontawesome.

Once the dependencies were updated, and after many npm install runs, it was time to try running ng build and face the first errors.

Backend build phase

Angular projects are split into two major parts: the backend, made up of components, modules, and services; and the frontend, made up of templates, directives, pipes, and UI modules.

In five years, a lot changes, and when it comes to frontend projects, the changes were even bigger.

My approach was to run ng build to compile the backend first, and, as expected, plenty of build errors came up, especially due to the strict setting in tsconfig.json, which now required every variable to be typed. While I could have disabled that setting, I preferred to fix the typing errors in each file with the AI's help, using the features listed at the start of this article. On top of that, many dependencies had their namespaces changed, one of the main examples being the splitting up of Angular Material components, which used to live under the @angular/material namespace.

Hundreds of Tabs later, ng build finally compiled without errors, and I could move on to the frontend build phase.

Frontend build phase

Now ng serve needed to compile the frontend. Naturally, many directives had changed, like property and event binding, which needed fixing.

Here's the explanation Cursor's AI gave for an error during the event binding migration:

The change you mentioned in the Angular directive from maxlength='100' to [maxLength]='100' reflects an update in how properties are bound in Angular, especially around the use of property binding.

Explanation of the change:

  1. Property Binding:
  • Before (Angular 6): The directive used standard HTML attribute syntax, where maxlength was set as an HTML attribute with a literal value. This means the value was treated as a string.
  • Now (Angular 16): The new [maxLength]='100' syntax uses Angular's property binding. This lets the value be treated as an Angular expression, meaning you can pass variables, expressions, or dynamic values.

The advantage of having the AI provide both the fix and the explanation for the change was that I could use the Search All and Replace feature to fix all similar snippets that needed the same change at once.

Another frequent error was the lack of handling for null values when accessing object properties, which TypeScript didn't accept and needed fixing. This is a recurring problem in legacy projects, and the AI was able to fix it through Tab suggestions.

After a while, ng serve finally compiled without errors, and I was able to access the application in the browser.

Publishing the app and opening the Pull Request

With the application working, all that was left was to update the pipeline file to use a newer version of Node.js and open the Pull Request on the repository.

Here's the final result on the enhancement/bump-up-angular-16 branch:

 397 files changed, 20290 insertions(+), 19788 deletions(-)

Conclusion

The term "AI-Assisted/Guided Programming," and others like it, will become increasingly present in the day-to-day work of software engineering teams. Gartner studies predict that, by 2028, 75% of developers will use AI tools to write code [5]. This shift is already visible across the software industry; Mercado Livre, for example, already uses AI tools to support its more than 9,000 developers [6].

In this brief account, I found that, even though I wasn't deeply familiar with a specific stack, productivity on the task increased significantly. An effort that would previously have taken weeks was reduced to a few days. That said, the developer's knowledge and experience remain indispensable, since, as I showed, it's often still up to the developer to decide which approach best solves the problem. So critical thinking, judgment, and experience were essential, not replaced.

References

  1. Martin Fowler: On Pair Programming
  2. Cursor
  3. Get Started: Cursor
  4. Pricing: Cursor
  5. Gartner Says 75% of Enterprise Software Engineers Will Use AI Code Assistants by 2028
  6. Mercado Livre frees developers' minds to focus on their mission with GitHub.

Profile picture

Written by Gustavo Aquino, Master of Science, Software Engineer, and founder of Decodifique.com. You can find me on LinkedIn.