|Perl: the Markov chain saw|
I think there is a counterpoint to this argument. If you look at the history of software projects that went bad, the most consistent reason for failure is that they tried too hard to make things perfect. To cover all the bases. To be all things to all people. To encapsulate everything. To control everything. To handle every contingency, edge case and possibility.
As a freind of mine once put regarding a project that cost close to a billion dollars and ultimately went nowhere... "Designed to death!".
The art of software (design/code/maintanence) is as much about what to leave out, what not to handle, what not to encapsulate, and what not to fix, refine or refactor, as it is about doing those things.
I agree with your first point. Make it work. But I do not think that you gave it enough emphasis (despite putting it first) nor enough importance. It is better to produce something that does something--even if it does it wrong--than to produce nothing at all.
More is learnt from making a mistake and correcting it than from trying to avoid the mistake in the first place. Intellectual 'what-ifs' and 'maybes' are interesting games to play, but ultimately less productive than "It does"' or "It doesn't."s.
Like the proverbial picture, one line of code is worth 1000 words. Even if the result is that the line of code is thrown away, the the learning (experience) from having written and tried it is invaluable.
The earlier mistakes, mis-assumptions and bad design are found, the earlier they can be rectified and the less their effect upon the project enddate.
And the quickest and most relaible way to find mistakes is to make them.
Unnecessary security is more than just unecessary--it is a drain on resources, both when coding the program, and when using it.
Designing in reusability, before there is an application for reuse, besides being a waste of effort if the code is never reused, frequently leads to design and coding descisions that only serve the purpose of the assumed reusability.
These decisions are often non-optimal for both the original application, and when a real application for reuse comes along, non-optimal for that too.
Better to code the solution to the problem at hand, and redesign/refactor for reuse, only once the nature of the reuse is known and can be factored into the design.
To do otherwise places constraints and costs that rarely (IME) ever produce payback.