When you start something new, you soak up guidelines — rules that guide, lines to not cross — to find your way. You make progress by following the always do this and avoiding the never do that. With experience comes the realisation that there are exceptions to these rules. With expertise comes the realisation that these are not exceptions, but highly context-dependent rules. The always do this and never do that you’ve relied on give way to it depends. Former certainties dissolve into a sea of possibilities. Context and dependency on context are hard to see, but they are critical to thinking and to code.
The creation of software is an exercise in knowledge acquisition and retention, and there are limits to what we know and what we can know, and limits to what can be stated and tested, but seeing software as knowledge structure has important consequences. All too often, assumptions about code dependencies and execution, remain unstated and unexplored, hidden behind not-quite-right mental models and weak formalisms for reasoning. Ask any developer to draw up the dependencies in their current system and, after a few boxes and lines, they’ll likely run dry, having barely sketched the tip of the tip of the iceberg. Most dependencies are out of sight and out of mind. Mentions of technology and third-party code are vague (versions and vendors completely overlooked), risk implications are unacknowledged (from left-pad to Heartbleed), the roles of developers and organisations and the real world are considered a mildly inconvenient abstraction.
This is software development. This is water. This is dependency.