Whenever I write a piece of functionality from scratch, it's a good and robust code.
We all think that at this point. We're seldom right.
But often times my assumptions about how the code should work evolve over time. After I reflect those changes in the code, the whole system suddenly loses its quality.
Well no. It never had quality. If it had you'd have been able to change your assumptions easily. Quality is more then satisfying today's requirements.
It seems to me that the best approach is to drop the old code and write a new one from scratch with new assumptions in mind. But from obvious constraints in time I wanna learn how to keep the code quality high while heavily changing it.
If you simply can't write flexible code then a rewrite is the best. Certainly better then half mutated code that is still trying to satisfy requirements that no longer exist.
Question: Are there any techniques or books that could help me develop this skill?
From the development point of view this is agile. Waterfall doesn't react well to lots of unplanned and emergent changes. Right now agile is the best we have for this.
From a coding point of view the best principle for this is single responsibility. Each module should have only one, preferably unique, reason to change. Make your decisions in one place. Don't spread them around. Follow that from the start and change won't be so traumatic.
I see how code review is a good tool to uncover issues in code and I agree. But I'm interested in preventing those issues from happening in the first place and developing the skill to do that on my own without involving other team members.
Code review is mainly a check that your code is readable. Definitely worth while but it won't guaranty everything. Others may check your design and implementation but don't lean on that.
PS: Please don't confuse this with refactoring, which is meant to change the code, while keeping the behavior the same. In my case when the requirements to the code change, it's obviously not refactoring and involves changing the behavior.
True. Refactoring changes design. You need transformations to satisfy new requirements. Guess what? Refactoring allows you to change old designs that didn't anticipate a need to accommodate change into ones that do. Once you have that you're ready to write new unit tests that reflect your new needs and can make them pass.
We don't recommend books here but this answer has enough buzz words in it that you should be able to find some now.