I agree with the power of holding a program in one's head, but I also consider this a (the?) serious bottleneck in the software engineering.
I hope we discover a scalable alternative to holding a program in one's head. It doesn't need to be as good as holding a program in one's head, it just needs to approximate it.
(Edit: see also Design Beyond Human Abilities by Richard P. Gabriel.)
We have - it's called an API. The way to work on big programs, too big to hold in your head all at once, is to break them into a bunch of little programs, each of which does something you can hide behind a simple interface. Then you hold all of the library in your head at once, and possibly repeat the same process.
The complexity comes in that this really does just approximate holding the whole program in your head, and sometimes you find the API is not adequate to what you want to do. Then you're back to square one, except with a codebase that by definition is too big to hold in your head.
It's also the primary driver behind the principles of object oriented programming - but those are almost dirty words these days. Somehow OO tried and failed in many ways to solve this problem, but I think it gets too little credit for at least having its heart in the right place.
I think OO was a first (and pretty good) stab at the problem. The primary goal was recursion, so having things be self-similar, and Alan's insight was to make the small things look like the big things (lots of little computers interacting), rather than making the big things look like the small things (everything is a function,...)
Back in 1972, we obviously didn't have a lot of "big things" (e.g. large distributed systems) to look at, so instead analogies and intuition were used. Considering, the results are not too shabby, IMHO.
Nowadays we have the Interwebs, a huge distributed system that appears to work most of the time, and so one might ask if we can apply the same principle and get newer and possibly better results: if we want self-similarity, should our computations internally look like the web?
We also have lots of experience with the systems we've built, and things like the Patterns books that tell us where our means of capturing common behavior fall short (if it's a pattern, it's repetitive; if it's repetitive, I should have been able to factor out the common parts).
So I am not sure "failed" is the right way to describe it. As another poster pointed out, we are now capable of building much larger systems than before, and OO seems to be largely responsible for that.
Another perspective is that Smalltalk (again) was never intended to be something final, but rather a basis for obsoleting itself, so describing OO as failed seems akin to calling the first stage of a Saturn V a failure because it didn't get to the moon.
Where I do see a failure is that we entered an age of stagnation, and rather than see OO as a first stage to build even better things on top of, we pretty much stopped. And in that sense, I guess OO did fail, because the second and third stages that were supposed to get us to the moon didn't really get built.
Even more powerful approach is minimalistic design with objects placed where they belong, to achieve harmony. Design, that among other things, minimizes a number of objects required to hold in one's head.
Personally I call it a design with good Feng Shui :) When things and objects are in their right locations, and in harmony, one don't have to remember where they are! One can just remember the harmony and find them in their places.
That's precisely why Python is so damn good, by the way.
I would argue TDD is a workaround which allows you to do meaningful work in a team context without holding a complete program in one's head.
It gets everyone to put their thoughts about what the program should do in one place. Every time you run the test suite, you are outsourcing to the test suite the task of running through your mental model of the program and thinking "what did I break".
The limitation of TDD is that it blocks rapid iteration in what the program should do. When you load the entire model of the program into your head, requirements change at the speed of thought. With TDD, they change at the speed of a lot of reading and typing.
>>> "The limitation of TDD is that it blocks rapid iteration in what the program should do. When you load the entire model of the program into your head, requirements change at the speed of thought. With TDD, they change at the speed of a lot of reading and typing."
I agree 1000% percent with that. You articulated very well what I see as the single biggest drawback of TDD.
It's as if you're still working with clay, but you put metal around it every 2 seconds, so you lose the benefit of working with clay.
TDD done correctly should allow the validation of "speed of thought" changes. It happens to me often that ideas spawned between my ears break functionality in the actual application if the application is complex. It doesn't mean that the idea was invalid, tests simply illuminate what else needs to be changed if you'd like to go forward with the change.
I hope we discover a scalable alternative to holding a program in one's head. It doesn't need to be as good as holding a program in one's head, it just needs to approximate it.
(Edit: see also Design Beyond Human Abilities by Richard P. Gabriel.)