When designing systems or software there are many considerations to weigh, and more often than not you have to start building before you know most of them.
Regardless, I try to keep these ideas floating around my mind while programming
As a developer, I believe in innovation after convention, that is, cleverness is costly unless necessary and convention is built on the success of an ecosystem.
As an engineer, I believe in creating tools that solve problems created by conventions that have outlived their scope of innovation in an ever-growing ecosystem.
Knowing when to wear which hat is one of the many keys to building successful software.
It's really all just about maintainability, this is the highest cost of code, but means very different things depending on the team, environment, stack, timeline, etc.
These are general, language agnostic ideas that are once again, highly depend on the context.
The developer is the only necessary resource for software. This is obviously hyperbole, but the principle holds; write code to be read, not executed.
Small changes and quick iteration is the way forward, and to that effect code should be read like a book, it should tell a story at a glance, and, to extend the metaphor, if the developer has to go to a different library to checkout a different book just to get to the next page the development process will stutter. Definitions should be as much as possible, layed out in order of use;
main (or equivalent) should be at the top of the page, and the first function it uses should be defined directly below, in this fashion the story will unfold organically.
"The idea is that another programmer (including your future self) can glance down a single column and understand the expected flow of the code."
- Mat Ryer
It's not about increasing the developer's cognitive capactity, it's about removing cognitive load from inappropriate sources; it's the same reason you shouldn't text and drive, it's not that you aren't capable of doing it, you're just worse at it when you do.
There is a difference between simplicity of syntax and simplicity of logic. If a developer has a hard time following the logic of a program, its too complex, if a developer has a hard time reading a line of code, they need to go to the docs. There is of course a balance here, we've all seen some comically convoluted oneliners that are absolutely unreadable, but that has more to do with the readability of a program, when I refer to simplicity I mean that of logic. I like the advice of the Golang Memory Model
"... If you must read the rest of this document to understand the behavior of your program, you are being too clever.
Don't be clever."
You never know what is on the horizon for a project, and you never know what will become of the technology you are using, whether it be new product requirements that call for a more suitable framework, or the organization that maintains a piece of your stack changes its terms of service or even discontinues their product altogether, good software is built on reusable, blind components flexible enough to swap implementation detail without rewriting your entire codebase. This approach keeps development and transitions sane and downtime to a minimum when surprises come, which they inevitably will.
However, this is all in a perfect world where everything is as simple as it sounds, which it's not, and it isn't. I think the idea that your database or framework isn't a part of your business logic is a bit naive. No matter how perfectly abstracted your code, changing the stack you've built on for years is never going to be a simple plug-and-play. There is only every unexpected everything.
I think the core of the idea of modular/abstracted code is really trying to get at easier testing, simpler refactoring, and quicker additions/removals. Good abstraction is about fewer abstractions and well designed contracts.
Not really just on design, but all his articles on Ardan Labs' Blog are excellent