I was watching the most recent Rich Hickey talk[0] and at the start, he talks about correctness and the difference between the internal machinery of your software (which can be finely specified) and handling the external world (which will always be messy).

Good Architecture will try to isolate the two. You got the internal logic which is either the business domain abstracted away. And you got the highly volatile part (request from frontend, new integration, new drivers, deps update,....).

If you've done that, migration/refactoring, unless it entails some unlikely core changes, will not take that long. It's just a matter of dropping that part and replacing it (like changing a car's brake pads or steering wheel). But the actual core mechanism will hardly change over the years.

To go with the thread flow: It's a stone core wrapped by clay.

[0]: https://www.youtube.com/watch?v=P5eO7BNyJao

ADDENDUM

In regards to separation, one of the best example in mind is the OpenBSD kernel code. The OS concepts are in /kern, while each architecture lives in /arch. There's an horizontal separation between machine independent code (core idea of Unix) and machine dependent code (The hardware platform). It can also be found in the various subsystem like audio (the concept of a sound card) and implementation like uaudio (usb interface) and azalia (Intel's HD Audio).