Most modern typed languages support encoding this information in the type of the variable, so that the compiler catches it, instead of in the variable name. Alexis King wrote a blog post about it that reached the front page a few days ago.
<a href="https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/" rel="nofollow">https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va...</a>
Just looking at the safe/unsafe string example I wonder if another usable approach would be to ditch plain strings and instead use thin wrappers like UnsafeString and SafeString and a bunch of operations on them. But not assignment, for instance.<p>There wouldn't be much need to care about whether the code looks wrong or not (welll with regards to safe vs unsafe string:), because the compiler would do it for you (or runtime I guess, depending on which laguage it gets implemented in). I think all the examples Joel writes (the ones 'xxx is always ok' and 'xxx is not ok') are covered by it. It does mean you need a Write which only takes SafeString I guess, and it probably doesn't mean you can still do something wrong, but it should be much harder.
Another way to solve the escaping problem is by some kind of interpolation mechanism that takes care of escaping on its own: like JSX or template literals in JavaScript (although you have to remember to tag the latter), or prepared statements in SQL. Why fix a coding convention when you can fix the language?
In a previous job, I wrote an autotrader which by now I believe will have handled hundreds of millions of pounds in untyped Python 2. Certainly tens of millions.<p>There were a number of approaches I used. This is a few years back now, so apologies if anything is unclear.<p>You can fake a type system to some extent in py2 by using methods and copious 'isinstance' checking.<p>For example, Money<EUR> + Money<GBP> can be made illegal by overloading addition operators. Strings which require some sort of meaning can be given classes and functions which use them can use isinstance and friends to perform runtime type checks.<p>Another is indeed the use of 'raw_whatever' and 'whatever' in identifiers, what I now know to be "apps hungarian" notation. 'raw_whatever' would have a similar definition to Joel's unsafe user input. It might come from an API of some sorts that you don't truly "trust".<p>Similarly, that sort of variable naming approach applied to function parameters. Passing a 'dog_id' to a 'cat_id' function _may_, in certain cases, be possible if both were flat strings (and not objects that could be isinstance checked), but I favoured a variable naming approach (along with calling functions by keyword argument) that would result in this at least being visible after problems came up (e.g. you'd see myfn(dog_id=cat_id) and feel an urge to hold your nose).<p>There were tons of these sorts of things all over the codebase, tests, etc, and the system outperformed the previous ones by a significant margin. My understanding is that it still hasn't suffered any significant losses; only some minor API issues that were outside of our control.<p>Super fun project. Nowadays I'd just use a typed language for it and interface with the py2 stuff via an API. Or at least make use of mypy. But that autotrader was what the company needed at the time.<p>Details are in my bio if anyone has further interest.
I used to hate code linters. Now, when collaborating with others, I set an aggressive one.<p>They make wrong code look wrong, literally.<p>Of course, it does not catch all wrong code examples, but at least some most glaring examples that otherwise would need manual inspection.
The checker framework (<a href="https://checkerframework.org/" rel="nofollow">https://checkerframework.org/</a>) can make the compiler understand about stuff like this without introducing additional types in Java.<p>I have never tried it myself, maybe someone with experience can chime in?
WRT exceptions I'm curious what his thoughts are on the go way of handling them (just return an exception, don't throw)? Clearly this article was written pre-go.
Most people commenting here seem to be missing Joel's point that the Hungarian notation makes it possible to read the code without having to continually search elsewhere for information about what it means. I'm pretty sure that he would be all in favour of declaring sub-types in languages that support it but an awful lot don't or don't make it convenient.
Nice. It's the most lucid explanation I've seen of what Hungarian notation really is, what it can do, and how different it is from sticking "ul" in front of every unsigned long variable.