Eu conheço essa situação muito bem. Quando fico assim, tento ter pontos de vista diferentes no projeto.
1.) Ponto de vista do usuário / cliente - use feedback
Infelizmente, estamos presos em nosso código de uma maneira que não conseguimos ver nossas próprias falhas, porque usamos nossos aplicativos da maneira que os codificamos. Veja como as pessoas o usam e tente descobrir qual seria a orientação mais intuitiva para o usuário. Brinque com protótipos de interface do usuário. Parece divertido, mas se você descobrir que seria forçado a recodificar grandes partes do seu código apenas alterando a lógica de uso, é hora de iniciar um ciclo de reprojeto.
2.) Faça uma análise funcional do seu código e visualize-o
Alguns IDEs e estruturas pressionam você para, por exemplo, misturar código da interface do usuário e back-end. Se você deixar isso acontecer, algum dia enfrentará a situação em que sua base de código dificilmente poderá ser mantida por causa de dependências nebulosas e difíceis de quebrar. Especialmente, misturar o código da interface do usuário com outro código pode levar ao código de espaguete e funcionalidade redundante. Divida seu código em blocos funcionais, como, por exemplo, classes de banco de dados, classes de comunicação, classes de interface do usuário, classes principais, etc. e forneça os nomes dos blocos de funções. Em seguida, visualize a funcionalidade com uma ferramenta gráfica (eu uso uma ferramenta de mapeamento mental) para descobrir se sua estrutura é lógica e modular o suficiente para que você possa reutilizar grandes blocos de código em diferentes projetos e possa substituí-los por versões mais novas sem grande dor.
A melhor maneira de fazer isso na minha experiência é criar um documento que visualize todas as dependências entre suas classes e as chamadas do código. O resultado é uma visualização do seu design de interface. Se esse mapa de código parecer um clusterf *** completo, é hora de agir. Se ainda não aconteceu, você deve pensar em uma convenção de nomenclatura adequada que represente sua estrutura de código de uma maneira que você não precise pensar em como chamá-la e o que ela faz.
3.) Use abordagens comuns para garantia de qualidade
O meu favorito é o FMEA. Em termos de codificação, isso significa não apenas analisar o que deu errado no passado, mas também pensar no que poderia dar errado. Um exemplo bastante comum é uma conexão de rede que caiu repentinamente. Depois de fazer isso, você pode classificar as condições de erro por consequências como perda de dados, falha, cálculo incorreto e avaliar o impacto no usuário. Se ainda não tiver sido definido, a definição de classes e rotinas simplificadas de erro e exceção pode ajudá-lo a manter seu código limpo e direto. A melhor maneira é implementá-los em cada nova paz de código antes mesmo de começar a escrever qualquer outra coisa. (Bem, sou culpado nem sempre de seguir esse conselho.)
Além disso, me ajudou a gerar e atualizar com freqüência uma "lista de propostas de melhoria" para meu próprio código. (Para ser sincero, ainda há muito código em meus projetos dos quais não tenho orgulho.) Também tento dedicar um tempo para coletar e dar uma olhada no código de práticas recomendadas de documentações da API, conferências de desenvolvedores ou revistas de desenvolvedores.
Até este ponto, não há necessidade de tocar no seu código. É simplesmente conhecer o que está acontecendo de errado e encontrar uma maneira de definir como melhorar seu código.
Finalmente, algumas dicas para o trabalho diário de um peido velho. Tente evitar morder mais do que você pode comer. Isso leva a muita pressão para uma codificação limpa. Você raramente tem tempo para fazer o que é certo, mas terá que reservar um tempo para corrigir as falhas posteriormente.
Nada é tão duradouro quanto a solução provisória, mas quando se rompe, muitas vezes é tarde para consertá-lo a tempo. Exemplos são hackers desagradáveis ou exceções estranhas que eu costumava fazer com que algo funcionasse, apesar de, por exemplo, uma falha na estrutura ou no sistema operacional subjacente. E então a falha é corrigida ou a nova versão simplesmente elimina a API ...
Se você estiver parado e forçado a encontrar uma solução alternativa, faça comentários e faça anotações que devem ser revisadas periodicamente. Normalmente ficamos cada vez melhores por aprender algo novo. Se você encontrar uma maneira melhor de implementá-lo o mais rápido possível. Caso contrário, você poderá codificar a solução alternativa para a solução alternativa e a exceção da exceção em um dia. (Aquele que está sem pecado entre vós, que me dê o primeiro byte.)