When I started coding, I just hacked stuff out any which way. This code was hard to extend, because it had no structure.<p>When I arrived at university, I tried to use all the "appropriate" design patterns and software engineering techniques. This code was hard to extend, because it had 60 separate extension points, all of which were in the wrong place (and none of which had ever been used).<p>When I arrived at my first internship, I killed a project or two though grotesque over-engineering.<p>Today, I'm just happy if the code is simple, readable, and does one thing well, and if it has enough unit tests to prevent bit rot. If I add an extra layer of abstraction, I do it because it makes the code simpler, or because it eliminates duplication.