There are indeed techniques for gradually simplifying code and improving design by doing so. The general technique is known as "refactoring". Note that this term is used both informally (to mean "anything that changes how code is designed without changing what it does") and formally (to mean "following a specific refactoring discipline"). I am referring to the latter definition here.
In particular, this problem has been much studied by Martin Fowler, and his book "Refactoring: Improving the design of existing code" is one of the classic books of software engineering, and is well worth reading in this area.
The general technique that the book suggests is:
1) Write very detailed tests for the section of code you intend to refactor.
2) Make a specific SMALL change to the code. For example, inline a method, rename a class, extract some code into a new method, extract a superclass from an existing class, etc. (Fowler has detailed lists of many such small transformations in his book, along with suggestions on how/when to do them. Most of the names of existing "automatic refactoring" features such as those in Eclipse, IntelliJ, etc. were taken from those used in his book. Essentially, these are like "design patterns" but are used for modifying existing code rather than for designing it in the first place.)
3) Re-run your tests, to verify that you haven't broken anything yet.
4) Repeat until you are satisfied with the results.
Thus, large changes to the code can be made by accumulating multiple small changes, with testing between each change.
Obviously, if you are in the habit of writing and retaining detailed tests for your code in the first place (a unit test suite, regression test suite, etc.), the above process will be much easier than if you have to write the tests immediately before you start refactoring. Also, it will be much easier to do this if the part of your test suite that you are re-running between each change is capable of running quite quickly.
Note that refactoring code in this way is a DISCIPLINE. It is not the same as simply randomly going around changing code. The frequent testing during the process is essential for ensuring that any inadvertent changes that you make to the program's behavior are quickly caught, while you can still remember what you did. For this reason, it is also often a good idea to do refactoring separately from other development which adds or changes the behavior of the program, since those sorts of changes are likely to invalidate existing tests. You could, for instance, alternate phases: Add a feature, then refactor a bit, then add another feature, then refactor some more, then fix a bug, then refactor, etc.
If you are consistent in programming using these techniques to simplify your code, the overall trend of your code over time will be that it gradually becomes simpler and easier to read, rather than the reverse (which is, sadly, more common in industry).
You may also find that some of the community around the Agile and/or XP software development methodologies may be helpful as to how/when/what to refactor, since continuous refactoring in this manner is considered a required feature of many such methodologies.
I have seen many projects gradually become so crufty and complicated that nobody understood them and they eventually had to be discarded, because maintaining them eventually took more effort than rewriting them would. Refactoring is a way to avoid this problem.