Related notes: Flat structures, Serialisation formats.
When writing a system consisting of multiple software components, it is too easy to get stuck with a particular technology: a language, if it's monolithic or heavily relies on a language-specific library; a message bus/queue if the architecture is service-oriented; a DB engine and structure if it's just a bunch of programs using DB directly; and weird non-standard conventions for things like logging and configurations tend to arise.
In dealing with that, KISS and Unix philosophy seem to be rather helpful, along with the aim to keep the components as independent and unattached to each other as possible. Basically, writing them with minimal assumptions about the system they'll be used in, sticking to standards whenever they are defined, etc.
Yet it becomes rather tricky when it comes to interaction between components: when integrating a program into a system, it should exchange data with others somehow. I've used serialization (mostly JSON, primarily because it's common nowadays) + stdin/stdout for that (well, also environment variables where that made sense), but JSON on input is not that handy for scripting, cron jobs, manual invocation, and not the most common way to tell a program what to do: for that, there are command-line arguments, which solve the other listed issues as well, and perhaps DSVs, which are quite similar.
Well, mostly: there's usually better support for JSON in high-level languages, allowing to derive printers and parsers directly from types (e.g., with Aeson in Haskell), while for command-line arguments there usually are just parsing libraries. In an attempt to fix the latter, I wrote the coalpit library, which derives command-line option parsers along with printers and usage messages, and is suitable for DSV printing and parsing.
Standard input/output/error are not always suitable, but are fairly easy to replace with UNIX domain sockets (or network sockets) and logging when needed.