AI and the Future of Coding

A review of Cursor AI Code Editor

Jonathan Fulton
Jonathan’s Musings
9 min readMay 12, 2024

--

The future of coding looks quite bright

ChatGPT ushered in a new era of coding. No longer did one have to hope Stackoverflow had the answer to a coding question. Instead, one could merely prompt ChatGPT to give the answer to questions and get a response back within seconds. It was a game changer for me and our team at Eppo, particularly when we were dealing with unfamiliar domains.

Cursor AI Code Editor is a game changer almost as big as ChatGPT. It’s ChatGPT that knows your codebase. There are several ways of interacting with Cursor to turbocharge your development experience.

  1. Copilot++. As the name implies, Cursor offers an improved version of GitHub Copilot that suggests multi-line edits in addition to the more traditional new code suggestions that standard Copilot provides.
  2. Codebase Chat (Command + L with Codebase). This allows you to “chat” with your codebase and ask questions. Cursor intelligently pulls in files into the conversation context and then ChatGPT responds appropriately. This can be super helpful for navigating parts of the codebase you’re unfamiliar with.
  3. Codebase Chat for code generation (Command + L with Codebase and correct prompting). Very similar to the normal codebase chat where you can ask Cursor questions about your code, you can also chat with Cursor and prompt it to generate new code for you. This can be extremely powerful especially if your change needs to span multiple files.
  4. New code generation (Command + K). Prompt Cursor to generate new code for you in the current file. You can tag files or documentation to provide the context necessary for Cursor to do your bidding.
  5. Code editing (Highlight, Command + K). You can highlight a section of code and prompt Cursor to make edits. Again, you can tag files or documentation to provide the right context
  6. Code questions (Highlight, Command + L). You can highlight a section of code and prompt Cursor with questions about it, with or without codebase context. This is very helpful if you’re trying to understand what a few lines of code or function actually do.

I’m going to skip a deep dive on Copilot++ because it’s hard to capture in the moment. I’ll provide examples for the other four ways of interacting with Cursor below.

2. Codebase Chat

Codebase chat was the initial “aha” moment I had with Cursor. A customer data scientist asked a question in our engineering Slack channel what the operator was for an undocumented part of our public metric sync API, which allows companies to sync hundreds or thousands of metrics with our system by passing in a single JSON file. Needless to say, that API is pretty complicated. And I’d never looked at the metric sync code before. However since I was new to Cursor, I figured I would test its skills. Woah, was I blown away! Specifically, I asked

For the metric API sync, when filtering by a fact property, what’s the operator you pass into the API for not equals?

The client had tried “not in” and “not equals” but couldn’t get either to work. Cursor specifically came back and showed the correct operator was “not_equals”

Before Cursor, it would’ve taken me at least 5 minutes of tracing code to get to this answer. With Cursor, it took less than 30 seconds.

Another relatively straight forward example. I wanted to figure out where we define global lift for ratio metrics. A simple query

Where is global lift for ratio metrics defined?

comes back immediately with the specific function where we compute global lift.

Ok, cool, so Cursor can handle questions that are relatively simple and have straight forward answers. Can it handle something a bit more challenging?

I came across the following in a Datadog trace while investigating Eppo web app performance:

Many, many database query spans all looking up the same data warehouse connection info

I figured out from Datadog that this was happening when loading “diagnostics” for an experiment. While I relatively easily identified where we were resolving the diagnostics (we use GraphQL), I couldn’t figure out where the queries for the warehouse info were coming from. So I decided to see if Cursor could help. I had the query from Datadog and I knew we were loading diagnostics so I asked Cursor

Where might this query come from in the context of loading diagnostics?
{Insert query here}

The response it provided was pretty unbelievable. It pointed to the exact place in the code where diagnostics fetched the warehouse info. I had to poke around a bit to figure out the resolve fields that were triggering it but Cursor had basically solved my problem and saved me an hour of poking around the code.

I was totally blown away by this response

3. Codebase Chat for code generation (Command + L with Codebase and correct prompting)

This one is extremely powerful. Right now Cursor doesn’t support multi-file code generation via it’s Command + K functionality but you can “trick” it to generate code for multiple files that you can copy/paste into the correct locations.

Here’s one of my favorite examples. I was trying to figure out how to implement rate limiting for our public API using simple decorators and a guard for our Nest.js controller. Here’s what I prompted:

Is there a way to do rate limiting with a decorator? I’d like the route and API key as the rate limiting identifier. Would like to be able to specify the rate limiting window in the decorator

And look what came back! A complete solution!

It showed (1) The decorator, (2) The rate limiting interceptor, and (3) The application of the decorator. Beautiful!

I didn’t copy / paste this exactly but it was pretty close. More to come on this specific example below when discussing Cursor’s Command + K new code generation functionality.

4. New code generation (Command + K)

Cursor is great at producing new code from scratch within a particular file, especially when you provide the right context by including files or documentation with the @ sign.

Continuing on rate limiting, when actually writing the core code logic, I used the new code generation functionality. I created the appropriate guard file and prompted

Write a rate limiter guard based on API key hash, method, and path. Use Redis.

And here’s what it produced!

Another time I need to generate a bar chart showing total run times by step for our experiment pipeline. We used Recharts but I didn’t really feel like reading the documentation to produce the correct code. So I prompted Cursor instead:

Please generate a stacked bar chart using @Recharts

The @ here is critical. I actually pulled in context from the Recharts documentation, which is available to Cursor. Here’s what it produced:

That saved me probably an hour of digging through the Recharts documentation to get all the attributes correct. And the chart it produced looked great! It even chose reasonable colors for all the categories.

Another somewhat complicated example from a math perspective was the code to compute the global lift for a ratio metric. Approximate prompt was

Write a function to compute the global lift for ratio metrics

The response was fantastic. While I double checked the math, it did it correctly.

Yet another example was a prompt to generate an HTML table given a data input. Something to the effect of

Please generate an HTML table with the columns from the provided data.

And here’s what it cooked up.

Now, I shouldn’t have been using raw HTML but that brings me to the next section.

5. Code editing (Highlight, Command + K)

Cursor is great at editing existing code. All you have to do is highlight some code you want to modify, prompt Cursor, and then either accept or reject the changes with Command + Y/N.

I received very good feedback on the PR above to use the DataTable.tsx component instead of raw HTML (I’m mostly a backend dev so didn’t know it existed). So I highlighted the 100 lines of HTML and prompted:

Please convert this to use the @DataTable.tsx component

This time I’m pulling in the context for a particular file, namely the one for the DataTable component. 30 seconds later I had a working table using the DataTable component instead of raw HTML. Absolutely unbelievable!

And here’s what the DataTable display looks like:

6. Code questions (Highlight, Command + L)

Another great part about Cursor is the ability to easily pull code into the codebase chat functionality. You highlight the code, press Command + L, and you can easily ask questions about it.

Here’s one of the first times I used this functionality when browsing some config settings in our codebase. First, I highlighted the schedulableWindowISOIntervals setting and prompted

What does this setting do?

I even asked a follow on question:

What happens if the interval doesn’t span the entire day?

Received a great answer to both of these.

Another example. I was debugging why the default pagination in our public API wasn’t being applied when no pagination parameters were passed in. The code looked right, I just couldn’t figure it out. So I decided to give Cursor a shot. I highlighted the appropriate code and prompted:

For some reason the default limit isn’t being applied in some cases. How could that happen?

Correctly, Cursor figured out that the problem was we were explicitly checking null, when the parameter might be undefined. BOOM! That was it.

A final really cool example. We had some problematic code that pulled all experiments into memory to count them. I wanted to fix it by counting them in SQL so I highlighted the offending code and prompted Cursor:

Is there a way to make this more efficient by pushing the counts into queries instead of pulling all experiments into memory?

And sure enough, Cursor came up with the appropriate TypeORM query that we needed to resolve the problem.

Conclusion

And that’s a wrap! I hope you enjoyed me walking you through some very concrete examples of how Cursor has revolutionized the way we’re searching, writing, and debugging code here at Eppo. Cursor has defined the way AI and software engineers are going to interact for the foreseeable future. You should hop on the bandwagon!

--

--

Jonathan Fulton
Jonathan’s Musings

Engineering at Eppo. Formerly SVP Product & Engineering at Storyblocks, McKinsey consultant, software engineer at APT. Catholic, husband, father of three.