As people are usually very quick to point out, one of the benefits of software is that it is supposed to be easy and relatively cheap to change compared to hardware. This is especially important when your realize late that you got something fundamentally wrong. Do the same with hardware, and you lose a million dollars, so as you've said, you use your simulators etc, and you test the bazinga out of it. This I think is where the paradigm fails somewhat when you shift to software.
Get into the average software developer's head, and what you have is a very busy person with an incredibly tight deadline. His manager is saying that it's ok to leave a few bugs because you can always fix it later. Tests are often an afterthought, but even in a test-driven scenario, the tests are kept minimal and the code written to the minimum of the tests, and often shortcuts are taken so that many of the boundary cases might be missed. The system may be thoroughly unit tested yet is rarely tested rigorously as a whole, and just as rarely stress tested to any great degree. Add to this that you write software from scratch, and there is little opportunity to simulate the software before you commit to writing it, primarily because we rarely write software from the same sort of fine-grained building blocks that you would find in hardware. Taken from this perspective - which I don't believe is too far fetched an example - the software is not tested to the same high degree that hardware would be, because realistically it can't be, and to attempt to do so would not be seent to be very cost effective.
Back to the OP's question. Could you define a system of building blocks from which to derive all of your software? Possibly. Would it be very cost effective? Probably not, because by the time you get around to developing a robust enough system of components, tests, and other paraphernalia to support this ideal system of programming, you would find that your competition would have already beaten you to the market, and even worse, from the average programmer's perspective you would probably find a "cookie-cutter" style of programming system to be very limiting and more likely very boring. I personally work on an API, where the bulk of the module code has been refined and standardized so completely, that all I do now is generate a code template and fill in the blanks. Most of my time can be spent writing simple connector code, and getting the modules out the door as fast as possible. It's seriously mind-numbing. There is very little opportunity to do more than just code the same sorts of things over and over, so when another project opportunity comes along, I jump at the chance to be able to do ANYTHING else.
So how can you get to deliver high quality and well factored software, and yet actually enjoy yourself doing it? I believe this comes down to your choice of tools and methodology. For me the answer has been to employ the use of a good BDD API, because it has allowed me to create very easy to read, yet highly granular code. I can build a suite of tests out of a minimal number of reusable methods, and describe my tests in the language of the specifications. In this way, I come close to a more component-ized development approach, except for the fact that I am responsible for designing and checking the building blocks. Additionally, the test output pinpoints the exact part of the test where the failure occurs, so that I don't have to guess whether the failures are in the setup or the assertion. This means I spend more of my time focused on solving problems instead of chasing them, my time is used more efficiently, I get more work done more quickly, and I can move on to other interesting tasks more quickly.
Tuning your methodology also helps. I'm a big advocate for applying lean development principals, and combining them with many of the other techniques and principals that the Agile movement has been banging-on about for many years now. Having eliminated most of the wasteful practices that I used to find so frustrating has helped a great deal to make development a more enjoyable activity. I'm still left with the issue that sometimes - but hopefully not too often - bugs will appear in my code, however I now find myself with more time, and even more incentive to spend more time writing more robust tests, and aiming for 100% test coverage. Even better, it feels really great to see all of those green lights appear at the end of my day, and be able to provide a complete - automatically generated - test report to give to my boss at the end of the day.