Use UTF-8 everywhere you can.
UTF-8 is:* the most backwards compatible (can be passed through many tools intended for ASCII-only with a few limitations – including avoiding composed latin glyphs)
* most likely to give an appropriate result if the end-user incorrectly interprets it
* the most space efficient encoding (on average)
* avoids endianness problems
* de-facto encoding for most Mac and Linux C APIs
* verifiable with a high degree of accuracy (unlike many other encodings which can't be verified at all)
Specifically:
* If you have to pick an encoding, always try to use UTF-8 unless you're only storing text to pass into an API which requires something different.
* The Winapi (aka Win32) is the only commonly used API that regularly requires something other than UTF-8 (the Windows Unicode APIs use UTF-16 – not UCS-2 as indicated in the Spolsky article). Windows' UTF-16 requirement a pain for platform independence -- be careful. However, you should still aim to use UTF-8 for all text files on Windows and only use UTF-16 for the Windows API calls (never use the locale specific non-Unicode encodings).
* There are a few language+environment combinations that literally can't open Unicode filenames. These include MinGW C++ which has no platform independent way of opening file streams with unicode filenames. You need to fall back to C _wfopen and UTF-16 to open files correctly.
Note: you don't always have to choose the encoding. e.g. the Mac class NSString or the C# String class use UTF-16 internally, you don't normally need to care what they do internally since any time you access the internal characters, you specify the desired encoding. You should usually extract characters in UTF-8.