Tips for high-abstraction software engineering with Cursor

Tips for high-abstraction software engineering with Cursor

High abstraction software engineering means attempting to focus almost exclusively on what the code is doing rather than how the code is working.

Some will say "This isn't engineering" and I disagree. Just as Python can still be engineering despite being a high-abstraction language, operating at a higher-level than code can still of course be engineering.

Others will say "This won't work for my project" and they'll often be right - e.g. if they're building something very complex, not known by LLMs, or they want other developers to build on top of - but I'd say most will be wrong. And even when they're right for a lot of their project they'll be wrong for other parts.

With this in mind, below are a bunch of tips for high-abstraction engineering - focused exclusively on Cursor-usage:

1) Claude is too keen to give you a solution - for some tasks, this is good, but for more complex ones and bug solving, build a mutual understanding of what's going on before acting.

2) You should probably be using Composer - your draw to using chat may be because you're thinking as a low abstraction engineer. Composer forces you to you think at a higher level.

3) Often if you go down the wrong path, it's easier to just return than try to fix afterwards.

4) Use Composer's simple version control to test different solution paths.

5) Generally, asking it to give you full context on a task or problem helps you understand you if it even understands what it's doing - often this is the problem.

6) Instead of solving a problem, often you should be asking: "Why is this a problem in the first place?"

7) Say to it: "Remember: you can use terminal commands like grep to fetch additional data." or "Query the db with terminal to understand the data format". It often forgets it has this ability.

8) Context management is the no. 1 skill of high-abstraction engineering. For example, knowing when to drop a description of a problem into a new window or continue with prior context. Experiment with this.

9) Overwhelming it with too much context can be as misleading for the model as too little context.

10) "Why is this stupid?" or "Why is this bad code?" will get you honesty from sycophantic models like Claude

11) Provocative questions help a lot for exploring issues as long as their answer isn't too deterministic: "I found the solution but it was very unintuitive, what do you imagine this could be?"

12) If you have a big chunk of context, pasting it to another window and asking it to summarise it first helps a lot with context overloading.

13) When in development mode, instead of just creating logs, you should also create rolling logs for the past 100-200 messages that you can attach as context - you can see an implementation of this here - or logs for each run in development mode.

14) If you find yourself in a loop of asking for something, copying a response from somewhere, and feeding it back to the model, try to automate/streamline this. It isn't always possible but frequently is.

15) If you're stuck, refactoring often either make the solution obvious or magically solves the problem.

16) For refactoring - especially moving large chunks of code - Cursor's apply model seems particularly bad. Asking o1 or o1 pro to just do the whole thing is often far simpler. I've had this work for >3,000 lines of code.

17) Get it to explain everything it's doing to you but be okay with the fact that you might not fully understand it the fist time. Over time, it'll tell you the same thing 5+ times and it'll click.

18) Reasoning models are smart and stupid in a different way to base model. Both have their uses.

19) Staying in flow is the most important thing in any case and reasoning models -though often smarter - are too slow for most tasks.

20) Completely reframing the problem is often useful - e.g. "What if you thought about this as a geometry problem, rather than a code one?" when dealing with a React positioning issue.

21) "There's clearly something fundamentally wrong about your approach. Take a step back."

22) "No solution please, just understand and hypothesise"

23) Ask "Can you check if you deleted anything by accident?" after each big chunk of work.

24) Get used to multi-tasking if you have complex tasks or are using reasoning models - e.g. I'm writing this while also fixing some bugs! - there's a lot of waiting and not enough to occupy your mind.

25) In general, imagine you're a 'proper' engineer in how you approach things - just at a higher level of abstraction than most software engineers - ask Claude "How would a proper engineer think about this?". This is more important than even understanding the code.

26) Give up on any level of granular understanding of the code as you generally work. It's good to understand when there's a bug or issue, but generally it brings your mind to the wrong level.

27) There's a lot of bullshit best practice in software engineering around project structure. Instead, pick a structure that makes sense to your brain for the level of understanding you're at. Refactoring is on a trajectory towards being trivial.

28) That said, often if there's an annoying bug or inefficiency, refactoring for its own sake can either fix it or make it clear.


I'll keep adding more tips here as I come up with them.