Tools That Teach Poor Habits

"It is practically impossible to teach good programming style to students that have had prior exposure to BASIC; as potential programmers they are mentally mutilated beyond hope of regeneration." -- EwDijkstra

Certain tools or influences cause poor habits to build up. These habits may serve well enough when using the tool in its intended domain, but can be harmful when the user of the tool is introduced to new circumstances - such as larger projects with more programmers, long tail-end maintenance cycles, or stricter correctness or security requirements.

Programmers, being lazy (LazinessImpatienceHubris), will tend to achieve the easiest solution to any given problem - not always the simplest solution, but rather the one that takes the least immediate effort and doesn't involve breaking other code. 'DoTheSimplestThingThatCouldPossiblyWork' embraces this particular pattern of behavior (but is often tempered with RefactorMercilessly - which requires taking the TimeToMakeItSimple).

Thus, tools can be said to 'teach poor habits' when they make 'easier' those solutions that are more difficult to later maintain, extend, debug, verify, grok, secure, refactor, optimize, etc. Now this isn't especially grievous if there are no better known solutions for a particular problem, and it also isn't an issue if the tool is not intended to solve the particular problem at hand.

But if the tool makes it difficult to utilize DesignPatterns that have in practice proven to possess better properties for later maintenance, extension, et al., then programmers will learn to make do with the less maintainable solution - it will be GoodEnough (at least immediately), so the programmers will use it and move on. In large projects with many programmers or long maintenance cycles, this has the consequence of the source slowly building cruft that is difficult to maintain, just as difficult to refactor, quite difficult to grok or extend, and buried under layers of similar code in such a manner that nobody is really certain how a change at one place will affect everything else; one begins to experience the TwentyEightyRule commonly associated with LegacyCode, and it becomes tempting to RewriteFromScratch?.

So, for tools to avoid teaching bad habits, they need to provide features that make 'easier' the more maintainable, grokkable, verifiable, et al. solutions. Some 'tools' of the programmer's trade include libraries, frameworks, standard message protocols, standard file formats, IntegratedDevelopmentEnvironments, SoftwareConfigurationManagement, paradigms, methodologies, DesignPatterns, and (of course) ProgrammingLanguages. Below, I'll focusing on ProgrammingLanguages (as a didactic example).

ProgrammingLanguages can avoid teaching bad habits by offering KeyLanguageFeatures that support common DesignPatterns for their target domain (See AreDesignPatternsMissingLanguageFeatures). They can also do it by lowering the barriers for extending the programming language to add new DesignPatterns (See MutableLanguage and ExtensibleProgrammingLanguage for the more extreme examples, but even having procedures, objects, generics, etc. qualifies here).

Finally, and far more controversially, is the BondageAndDiscipline approach: ProgrammingLanguages can raise a barrier by intentionally making more difficult those solutions that the language-designers have deemed to be less maintainable, grokkable, verifiable, optimizable, et al.; this ultimately results in the allegedly better solutions being 'easier', but only because the other solutions were made more difficult. Integrating automatic use of TypeSystems or removing 'GoTo' from the language would generally qualify as an example of this BondageAndDiscipline approach. This is controversial for two reasons: First, it implies that the LanguageDesigners know better - it might even be true, but nobody likes having that shoved in their faces. Second, people that have already learned 'poor habits' from prior tools will enter this language and be frustrated by it: they'll need to change their own behaviors in order to use the language (and 'bad habits' are notoriously difficult to break), or they'll need to change the language to support their habits (BadCodeCanBeWrittenInAnyLanguage). However, despite the controversy behind it and the potential for circumvention by a determined programmer, the BondageAndDiscipline approach does, in practice, achieve the purpose of the language designers in encouraging use of whatever the designer considered the more appropriate approach to solving problems, especially when combined with the lowering of barriers for the proposed 'correct' approaches and DesignPatterns.

Some languages that (allegedly) teach poor habits include BasicLanguage (VbTeachesBadHabits), PerlLanguage (ThereIsMoreThanOneWayToDoIt has been accused of encouraging YouShouldDoItEveryWhichWay, which results in code more difficult to grok or maintain for new programmers), MutableLanguage and OperatorOverloading (for the same reason as PerlLanguage), use of GoTos vs. StructuredProgramming (accusations of SpaghettiCode), etc. Actually, for just about any feature or language you can find on this wiki, you'll find someone else accusing it of being bad - often for the very same reasons that the other people call it a feature. I wish to avoid discussion regarding truth or fallacy behind these accusations in this section; there are dedicated pages for each.

Regarding banning goto in BondageAndDiscipline languages: Standard Pascal, a BondageAndDiscipline language, didn't ban the use of GoTo, but forced one to use numbers as labels (most likely to discourage people from using text labels all over the code as control structures, and to encourage goto's only for error code exits (number labels) or special situations). However, when goto label's are used the descriptive text labels can be really handy and these numbered labels can be annoying. Linus had a statement about this on a mailing list, once upon a time (re: his hatred for pascal and the usefulness of text labels vs numbers).

One way to allow GoTo but to discourage it, is to disable it by default (SecureByDefault?) and only allow GoTo when a compiler switch is enabled. An example in Qomp and FPC is the {$GOTO ON} directive, or the command line switches. This allows one to use nice local goto's when justified or reasonable (GoodUseOfGoto).

I would suggest that CheckedExceptions of the ManifestTyping sort are among the ToolsThatTeachPoorHabits. Related: CheckedExceptionsAreOfDubiousValue, JavaExceptionsAreParticularlyEvil. LazinessImpatienceHubris suggests that the easiest, fastest way to errors go away will be the one that is favored. For CheckedExceptions, that means smashing them at the place the compiler complains. Since these are exceptions, and thus aren't part of the HappyPath, the silent error-creep issues that arise from smashing these exceptions, probably will go unnoticed and uncorrected for years.

Where's the Proof?

One common (and very reasonable) objection to methodologies, adherence to paradigms, and especially BondageAndDiscipline approaches is the lack of highly statistical, objective, independently verified 'proof' behind the design decisions intended to teach 'better' habits. Without proof, one cannot readily justify raising a barrier to a particular feature - e.g. deciding to not add GoTo to a language GeneralPurposeProgrammingLanguage, or requiring static type verification.

Anecdotes, especially in large supply, provide ample evidence that a problem has been observed; even vociferous GoTo adherents won't deny that SpaghettiCode is both possible and exists in practice. But anecdotes don't say that a problem will occur - they only indicate what can occur, and those same GoTo adherents will argue that the problem won't happen to them; they've got 'experience'. A well organized GoTo project can be just as verifiable and maintainable and grokkable as any StructuredProgramming project - perhaps (given the 'well organized' criterion on the former) even more so.

For the designers, the answer is that hard evidence is impossible to obtain in practice. Due to the combinatorial explosion in how systems interrelate, it will cost far more than going to the moon and back several times to properly compare tools against one another, especially when one needs a 'clean slate' against which to test - an impossible thing to obtain for human programmers. It isn't as though you can teach pigeons to maintain programs with long tail-end maintenance cycles.

Attempting to obtain 'guaranteed' automatic features is easier to handle; e.g. one deductively cannot allow pointer arithmetic if one's goal is to guarantee language safety ('safety' = no operations have undefined consequences). One can also remove GoTo to support termination, or require static typing to support safety. But, even if these reasons account for many of the core design decisions for a language, this class of deductive feature still accounts for a relatively small subset of all tool design decisions. It certainly doesn't affect decisions that, for example, name language primitives, favor choice of '=>' vs. '->' in a syntax, or distinguish the JavaSwing and JavaAwt frameworks.

Thus, designers are stuck basing most of their decisions off of UserStories, anecdotes, experience, observed DesignPatterns, and logical reasoning backed more by models and mathematics and limited abduction than statistical observations over reality. Some of these observations do involve those over programmers; a designer can always reasonably assume that (a) in any open system some programmers aren't trustworthy, (b) some programmers don't know what they're doing, (b.ii) on any large or long-term project, it is very rare that all programmers know what they are doing or exactly how a change affects emergent behavior of the code, (c) programmers that never make typographical, copy-and-paste, and logic-errors are so rare as to be almost unheard of (d) rarely do programmers or users know exactly what they want - perfect foresight doesn't exist, etc.. These aren't issues of 'psychology'; they're simply observed reality.

These sorts of observations can reasonably shape and justify design decisions, even though they aren't proven with hard, undeniable, statistical, clean-slate laboratory proofs. Designers must deal with the fact that there will rarely be absolute proofs to support their design decisions in practice; often, the best they can do is learn from the new anecdotes and UserStories about what should maybe be done better next time around.

Books that advocate some hype or current technology can also teach poor habits. It doesn't help that the people who use the books are usually those who lack the experience and skill to judge for themselves. Anything written in a book is usually taken as absolute truth, even if it is pure garbage.

See also: SapirWhorfHypothesis, CobolCausesBrainDamage

EditText of this page (last edited May 19, 2009) or FindPage with title or text search