"And unit tests are not critical. If there’s no unit test the customer isn’t going to complain about that.” By all means, ship. Do what you gotta do. But a code base that doesn't have tests cannot safely be refactored. This technical debt must eventually be paid by the product owner in cash and the code's maintainers in sanity.
I disagree with your statement that a codebase without tests cannot safely be refactored. I've been refactoring code for 20+ years, the overwhelming majority of time without any automated tests, and I'd say offhand 99% of the time it causes no bugs, and in the occasional case where it does cause a bug (because I am imperfect and sometimes make mistakes), I almost always soon find it during the same coding session and…
It's nice to hear someone with experience from before the "Unit Test is compulsory" explosion. Programmers should always test their work, but testing comes in much more of a diverse range than mere Unit Tests.
There are plenty of cases where Unit Testing is 'embarrasingly'[1] appropriate. These pin-up applications blinds Testing advocates to the fact that Unit Tests are often inferior to other methods or simply not possible.
An example where completely automated tests are impossible is PDF generation. One cannnot 'Unit Test' this. One has to build a framework to take test data, create less than 100 pdfs, and then a human has to eyeball it. Humans cannot eyeball more than 100 images and perceive subtle errors. Less than 100 output images means this cannot exercise every codepath of even simple applications.
Often I was working on a part of the Render Pipeline which was not currently exercised by the existing test. Do I create a whole new test suite to generate test images for each branch condition? If it is important, yes, I created a new end-to-end test. But if it was not, then I addapted some existing test input and used my best judgement and my knoweldge of the internal state. This test did not last beyond my short-term memory, and my own set of eyeballs. If a problem occured later, I would recreate the test from memory.
This is still TDD, but it is so much less straight-jacket than requiring Automated-testing. The tests are 'thrown away' effectively. But the tested code remains. I would also say that the coder knowing which portions to test is superior in many cases.
--------------
[1] Similar to :: http://en.wikipedia.org/wiki/Embarrassingly_parallel . Network stacks, account balances, Frameworks are all embarrasingly unit-testable