'help[] the developer talk to the computer' is pretty much the goal of most abstractions I've seen
Here’s another thought for you: are those abstractions to help the developer talk to the computer, or to communicate better with other developers, perhaps including themselves a few months later?
I'm not really sure how to elegantly get 1000 modules loosely coupled
The trick is not to wind up with 1,000 modules that need to be coupled in the first place.
Even in the largest systems, it’s rare for more than a few modules to need to communicate intimately at any given level of abstraction. Usually you can break a system down into a few top-level subsystems, maybe break those down into a few layers and divide up the major concepts within each layer, or otherwise decompose your overall system into smaller chunks.
This way even if you have a lot of intricate dependencies within a certain part of the system, hopefully you can wrap them up in some sort of higher-level module and present a relatively simple interface to the rest of the system. Even then only certain other parts of the system would depend on that interface directly. This reduces the number of immediate dependencies in your system to some vaguely logarithm-like function of the number of modules in your system and the degree to which you decompose it, rather than something approximating the square of the number of modules if you have an everything-talks-to-everything design.
(Edit: Removed any hint of mathematical notation since this is hardly a rigorous formal argument...)
Here’s another thought for you: are those abstractions to help the developer talk to the computer, or to communicate better with other developers, perhaps including themselves a few months later?
I'm not really sure how to elegantly get 1000 modules loosely coupled
The trick is not to wind up with 1,000 modules that need to be coupled in the first place.
Even in the largest systems, it’s rare for more than a few modules to need to communicate intimately at any given level of abstraction. Usually you can break a system down into a few top-level subsystems, maybe break those down into a few layers and divide up the major concepts within each layer, or otherwise decompose your overall system into smaller chunks.
This way even if you have a lot of intricate dependencies within a certain part of the system, hopefully you can wrap them up in some sort of higher-level module and present a relatively simple interface to the rest of the system. Even then only certain other parts of the system would depend on that interface directly. This reduces the number of immediate dependencies in your system to some vaguely logarithm-like function of the number of modules in your system and the degree to which you decompose it, rather than something approximating the square of the number of modules if you have an everything-talks-to-everything design.
(Edit: Removed any hint of mathematical notation since this is hardly a rigorous formal argument...)