I decided to jump into the deep end of the pool and complete two projects using Cursor with it’s default AI setup.
The first project is a C++ embedded device. The second is a sophisticated Django-based UI front end for a hardware device (so, python interacting with hardware and various JS libraries handling most of the front end). For context, I have decades of experience in software and software-driven-hardware development across a range of domains, frameworks, languages, etc.
So far I am deeper into the Django project than the C++ embedded project.
It’s interesting.
I had already hand-coded a conceptual version of the UI just to play with UI and interaction ideas. I handed this to Cursor as well as a very detailed specification for the entire project, including directory structure, libraries, where to use what and why, etc. In other words, exactly what I would provide a contractor or company if I were to outsource this project. I also told it to take a first stab at the front end based on the hand-coded version I plopped into a temporary project directory.
And then I channeled Jean-Luc Picard and said “Engage!”.
The first iteration took a few minutes. It was surprisingly functional and complete. Yet, of course, it had problems. For example, it failed to separate various screens into separate independent Django apps. It failed to separate the one big beautiful CSS and JS files into independent app-specific CSS and JS files. In general, it ignored separation of concerns and just made it all work. This is the kind of thing you might expect from a junior programmer/fresh grad who, after doing this, would get called into the office for a conversation.
Achieving separation of concerns and other undesirable cross-pollination of code took some effort. LLM’s don’t really understand anything. They simulate understanding very well, but, at the end of the day, they do not. They tend to get stuck and make dumb mistakes because of it. No context. No understanding.
The process to get to something that is now close to a release candidate entailed an interesting combination of manual editing and “molding” of the code base with short, precise and scope-limited instructions for Cursor. For my workflow, I am finding that limiting what I ask AI to do delivers better results. Go too wide and it can be in a range between unpredictable and frustrating.
Speaking of frustrations, one of the most mind-numbing things it does every so often is also in a range, between completely destroying prior work or selectively eliminating or modifying functionality that used to work. This is why limiting the scope, for me, has been a much better path. If I tell it to do something in app A, there’s a reasonable probability that it isn’t going to mess with and damage the work done in app B.
I pretty much commit before every single request. Git is your friend here. I’ve had to git reset --hard HEAD a bunch of times. No big deal if you have this in your workflow. It can be hilarious and frustrating.
One simple case was when I asked it to implement layered canvas elements to double-buffer graphics output to a div to improve graphics rendering (eliminate blinking, etc.). Instead of changing a few lines of code it created half a dozen new files, completely rewrote the rendering code, added another half dozen test files that were completely unnecessary and even decided to test and see if Django and all the dependencies (which have not changed for days) were installed correctly… git reset --hard HEAD
These issues mean that regression testing (of the right kind) becomes far more important in this workflow, because, on every iteration, you have no idea what functionality may have been altered, damaged or nuked. It will also go nuts and do things you never asked it to do.
For example, I was in the process of redoing the UI for one of the apps. For some reason it decided it was a good idea to change the UI for one of the other apps, remove all controls and replace them with controls it thought (hallucinated?) were appropriate or relevant (which wasn’t even remotely the case). And, no, I did not ask it to touch anything other than the app we were working on.
Note: For those not familiar with Django, think of an app as a page with mostly self-contained functionality. Apps (pages) can share data with each other through various means, but, for the most part, the idea is that they are designed as independent units that can be plucked out of a project and plugged into another (in theory).
The other thing I’ve been doing is using ChatGPT and Cursor simultaneously. While Cursor is working I work with ChatGPT on the browser to plan the next steps, evaluate options (libraries, implementation, etc.) and even create quick stand-alone single file HTML tests I can run without having to plug into the Django project to test ideas. I like this very much. It works well for me. It allows me to explore ideas and options in the context of an ChatGPT project and test things without the potential to confuse Cursor. I have been trying to limit Cursor to being a programmer, rather than having long exploratory conversations.
Based on this experience, one thing is very clear to me: If you don’t know what you are doing, you are screwed.
While the OpenAI demo where they have GPT5 develop a French language teaching app is cute, I cannot see people who don’t know how to code producing anything that would be safe to bet the farm on. The code can be great and it can also be horrific. It can be well designed and it can be something that would cause you to fail your final exams in a basic software engineering course. There’s great variability and you have to get your hands in there, understand and edit code by hand as part of the process.
Overall, I do like what I am seeing. It’s another tool and you have to learn how to use it correctly. Anyone who has done non-trivial projects in Django knows that there’s a lot of busy boilerplate typing that is just a pain in the ■■■. With Cursor, that evaporates and you can focus on where the real value lies: The problem you are trying to solve.
One of the things I’ve been doing it is to tell it not to change code and explain what it would do as a result of my instructions. I like this. I can evaluate before changes and not have to deal with potentially massive pollution of the code base or adverse effects. The deeper I am into the project, the greater the possibilities of it making changes that will cause a severe setback and unknown unknowns in functionality, algorithmic correctness, etc.
I have not played with the different models yet. It’s in Auto. Based on what I’ve read in this forum I am tempted to disable GPT5 and experience Claude. I might try that today.
I jump into the embedded C++ project next week. I’ve already done some of it, but I’m in that mental space 100% next week. Looking forward to new discoveries.
The other reality is simple: This is the worse this will ever be. And it is already pretty good.
Tips, pointers, advise and criticism are very much welcome. Thanks in advance.