In my experience this is the only safe thing to do when you don't fully understand the system and cannot reason about it in a precise way. You create well defined abstractions over the messy parts, verify the abstractions, and write lots of tests. Eventually you can start deleting code. Although nobody ever ends up deleting code because they skip the "well defined" part and end up adding more indirection, afraid to delete code.
The only real way to tame complexity is to reason about it with precise, mathematically-defined abstractions. You can't invent Paxos using boxes and arrows on a white-board and prove the minimum quorum required without showing your work. Fortunately we have languages and systems that can automate a lot of the effort in checking our work as long as we can express it in formal language.
The other problem with this is that learning how to use these tools and techniques requires a lot of effort that isn't highly valued or rewarded in industry. Most businesses are fine with the trade off of errors and mistakes down the line if they're first to market. Ship it now, fix it later. We do a reasonably good job of preventing enough obvious errors with our tooling and processes. We can have software that obviously has no errors or software that has no obvious errors. Time and again we chose the latter because the former is too difficult and doesn't reward us with money now.