the only size limit is the block size, in other words you can inject a garbage data a little less than 1 MB in one transaction's output to the bitcoin blockchain. 20 byte (which is actually 40+OP_RETURN+push-byte size) is the standard rule that the bitcoin nodes are enforcing to reduce the chances of abuse. there is also transaction fees that will prevent such shenanigans to some extent.
the thing is that bitcoin is a payment system so it's "ledger" should only have to store payment data not arbitrary messages hence the "The best practice is don't."
Yeah I should have been more clear in that. By best practice I really meant in terms of encrypting and encoding to ensure the data is stored in a secure manner. In what manner is the 20 byte rule enforced? On a per transaction basis, the use case I am targeting would be somewhere around 1 to 2kb tops. But there may be anywhere between a few to a few hundred transactions per user.