Bouncy Stream Blog

First thoughts on Cursor

After the failures from the past weeks, which I experienced while trying to make ChatGPT, Claude and DeepSeek edit a simple file, I decided to check out a coding assistant. After testing Cursor / Claude 3.5 Sonnet with a sample project for the last 2 week, here are my first thoughts on its performance.

The sample project

A little bit about the project first. It's an Angular2 project with an existing structure. In it, I follow DDD principles. Meaning, the business logic is grouped in use cases, which utilize different repositories to send and receive data from a backend. The backend is a REST API. The data from repositories is assembled into models and the models are used in the components.

About my Cursor settings

I just downloaded it, installed it and used it with the default settings and Claude 3.5 Sonnet.

A thought beforehand

Perhaps too obvious, but the first consideration is - when you work with coding assistant, use version control. I've read disastrous stories from people who relied too heavily on the assistant and after a couple of iterations, their whole project was irreparable. I was more on the cautious side, and didn't give it too much freedom. I mostly limited myself to the implementation of single features.

Login and logout features

I started with adding some standard features for a frontend app, such as login and logout. Cursor mastered them well. Added proper components and routing for login and logout, called the proper endpoints etc. After the Composer was done, and I've accepted the changes, both features were working. With some help from my side, it was also able to add the authentication token to every request going out to the backend and do the error handling when the authentication has failed. The components were pretty much flawless and the styling with tailwind was decent. What it didn't do on its own, however, was to implement the logic for refreshing the token. I think the default settings of the assistant prevent it from making too many changes in too many files.

Registration feature

The next feature on my list was registration. In my sample project, the registration is very simple. It consists of a single form. It doesn't require email confirmation. On submit, the data is sent to the backend. On successful registration the user is redirected to the login page. In this feature, Cursor started to have huge problems with the architecture. A lot of prompts were needed to help it navigate the project's structure. Again, the components were absolutely no problem. Once past them, however, it failed to use the existing authentication service. Instead, it used the http client directly in the component and made a call to a non-existing registration endpoint. It completely ignored my prompts to explicitly implement a registration service, which then to use calling the underlying authentication service, which is generated by the OpenAPI code generator from the REST API schema. To make it comply, I had to specify every step of the implementation of the feature and then point it directly to the services I wanted it to use and specify the method in which the calls need to be made.

Some business use cases

After that, I continued with the implementation of some business use cases. These followed more or less the same pattern - send form data to the backend, get the results back and display them in components. The implementation required the replacing of some existing forms with new ones with dependencies between them. Some of the dependencies were already implemented, so the principles I wanted Cursor to follow were present. Here again, Cursor was not consistent. Sometimes it used event emitters to implement the dependencies, and sometimes observables. Since I wanted to avoid event emitters, I had to explicitly specify that in my prompts. As with registration, in these new business use cases I couldn't rely on the Composer to implement a whole feature while complying with the architecture. I had to write prompts for every single layer and separate prompts for connecting them.

Me having to keep a close eye on Cursor was necessary to prevent it from messing up the project, as it always implemented something. It didn't ask for clarification on my prompts. Sometimes it had trouble finding the files I was asking it to change. What startled me the most is the specification of the context in which the prompts should be executed. In some cases, I specified a single file as context in order to limit the impact on the project. This context input was overridden by the Composer, and it ended up changing a completely different file.

The verdict

My expectations were more or less confirmed. The code assistant needs to be controlled and contained. Cursor doesn't have a mind-blowing fast response time. For more complicated prompts, it can take a minute, but that's fine and justifiable. Reliability, however, is a real pain point. It doesn't work flawlessly on its own as some hyped-up users suggest in their posts. One needs to learn when and where to utilize it, in order to draw a real added value. In my case, it helped me to reduce implementation time with generating code for standard features and components. In every other case, it requires constant monitoring and adjusting.