I know this situation very well. When I get stuck that way I try to take different points of view on the project.
1.) User / customer point of view - use feedback
Unfortunately we are caught in our code in a way that we aren't able to see our own flaws because we use our applications the way we have coded them.
Look at how people use it and try to figure out what the most intuitive user guidance would be.
Play around with UI prototypes.
This seems to be fun, but if you find out that you would be forced to recode huge parts of your code just by changing the usage logic than it's time to start a redesign cycle.
2.) Do a functional analysis of your code and visualize it
Some IDEs and frameworks push you to e.g. mixing UI and backend code. If you let this happen you will at some day face the situation that your code base can hardly be maintained because of nebulous and hard to break dependencies. Especially mixing UI code with other code can lead to spaghetti code and redundant functionality.
Divide your code in functional blocks like e.g. database classes, communication classes, UI classes, core classes etc. and give the function blocks speaking names.
Then visualize the functionality with a graphical tool (I use a mind mapping tool) in order to find out whether your structure is logical and modular enough that you can reuse huge code blocks for different projects and you are able to replace them with newer versions without big pain.
The best way to do this in my experience is to create a document that visualizes all dependencies between your classes and their calls from your code. The result is a visualization of your interface design.
If this code map looks like a complete clusterf*** than it's time to act.
If not happened yet you should think about a suitable naming convention that represents your code structure in a way you don't have to think about how to call it and what it does.
3.) Use common approaches to quality assurance
My favorite is the FMEA. In terms of coding this means not only to analyze what went wrong in the past but also think about what could go wrong. A pretty common example is a suddenly dropped network connection. After you have done this you can classify the error conditions by consequences like data loss, crash, wrong calculation and judge the impact on the user.
If not done yet defining streamlined error and exception classes and routines can help you to keep your code clean and straight. The best way is to implement those in every new peace of code before even starting to write anything else. (Well, I'm guilty not always to follow this advice myself.)
In addition it helped me to generate and frequently update an "improvement proposal list" for my own code. (To be honest there's still a lot of code in my projects I'm definitely not proud of.)
I also try to take the time to collect and have a look at best practice code from API documentations, developer conferences or developer magazines.
Until this point there's no need to touch your code. It's simply about getting aware what's going wrong and finding a way to define how to improve your code.
Finally some tips for daily work from an old fart. Try to avoid to bite more than you can eat.
This leads to too much pressure for clean coding. You rarely get the time to do it right, but you will have to take the time to fix the flaws afterwards.
Nothing is as long-lasting as the provisional solution, but when it breaks it's often to late to fix it in time. Examples are nasty hacks or strange exceptions I used to get something to work despite e.g. a flaw in the underlying framework or OS. And then the flaw get's fixed or the new version simply drops the API…
If you are stuck and get forced to find a workaround than make comments and take notes which should be reviewed from time to time.
Normally we get better and better because of learning something new.
If you find a better way implement it as fast as you can.
Otherwise you might find yourself coding the workaround for the workaround and the exception of the exception one day.
(He who is without sin among you, let him throw the first byte at me.)