…Componentize and compartmentalize your system with the expectation that some day you’ll need to replace each part.
Additionally, avoid the anti-pattern of adopting pre-mature frameworks, especially low-level frameworks that define how the code is written and structured. Once that framework is proved to be not working or need to be replaced for other reasons, it makes refactoring much harder and may lead to rewrite eventually.
In terms of code structure, consider things in the following order: native language features > libraries > frameworks.
If you need to use a framework, make sure to use it only for what it is meant be used for (for example, things like dependency injection), and keep the rest of the code organized as framework independent as possible. It would be much easier to replace it with better options without dramatic rewrite.