If I could give four words of instruction to an unknown intermediate-level programmer, I'd probably go with "think about dependencies more."
It's remarkably hard to keep track of what exactly you're thinking about when you're thinking about dependencies. There are at least three candidates:
- There are dependencies at the file/package/module (depending on the system you're working in) level. When your compiler (or interpreter, or whatever) complains about a circular dependency, this is the kind of dependency you start reasoning about.
- There are dependencies of objects on objects. So, when you read Architecture Patterns in Python and you read that your domain entities should be depended on and not depend on anything else, it's this kind of relation you're thinking about. But these discussions often occur at the code level, and there is also a logical level, so that:
- There are dependencies of objects on objects at the logical level. So, for example, when you make a foreign key reference in a Django model with a string instead of the Model itself, you avoid a dependency at the code level but retain it at the logical level.
There are a few immediate lessons here:
- It's easy to take yourself to be thinking about one kind of dependency and actually be thinking about another.
- If you're making a dependency graph, be sure not to graph different kinds of relationships at the same time or unwittingly make the same box refer to, e.g., both a module and a logical object.
- Devices that remove one sort of dependency might leave another sort of dependency, and the remaining dependency might be dangerous.