As time goes on in the life of a software project, the codebase grows and complexity increases. This along with hacky bug fixes, tacked on functionality and quick improvements can turn a project into a large multi-functional, inter-meshed mess.
Needles to say this makes feature tracking, versioning, bug isolation and maintenance difficult and limits code reuse potential. While it is best if planning and good design practices protect a project from growing into such a state, the need for rapid development is sometimes more pressing than the need to get design details perfect.
Despite the perfectionist in me making me shudder at the thought of imperfect design, I am slowly coming around to the idea that a product with a flawed design that functions and which customers are happy with, is better than a product that is internally perfect but never delivered. Iterative development and a quick release cycle really are the way to go. Learnings gleaned during one iteration can quickly go into the next.
Just don’t forget to track the areas of code that need improvement so that they *do* get reviewed in future releases. Keep chipping away, keep improving. With time your codebase will make you happy again.
I struggle a lot with putting stuff out that isn’t beautiful on the inside. Something that’s helped me a lot is learning how to create things that are internally simple, even when solving complex problems (and in realising that a lot of the tools / techniques that are popular to make programming “easier” these days actually make things more complex). This talk is a great intro on the topic if you want to learn: http://www.infoq.com/presentations/Simple-Made-Easy