> 3. Functions should have extensibility, put the required parameters as parameters and always include an “options” at the end. Each function can have defaults that you can extend, which means you need a deep-extend method:
counter-point: why not write functions that take the arguments they need? if they need more arguments later, why not add them later?
> 4. When in doubt whether to do convention A or B, take a bit more time to do C which can handle both, and add the convention in a config. You never know when someone may need something else!
counter-point: why try to anticipate future needs? maybe it won't happen. maybe it'll be something you totally don't expect. you should write code that's easy to understand and change, so it can react to future requirements. you should not write code that's bloated with unnecessary features, because it slows down your future ability to iterate.
> 5. Similar to 4, if you can have an extra indirection, add it. So you can let others hook into “before” and “after” hooks at any point. Use events instead of functions.
have you ever tried to figure out how a piece of functionality is implemented, only to go chasing it across 10 files because of indirection? have you ever had a piece of code that runs, but you don't know why it's running because you can't tell which things are firing what events? have you ever had to ask the question, "what happens when i execute this function", but been unable to answer because of hooks/observers that are not directly connected to that function?
my counter-point: use the barest minimum of functionality you actually need. stick with functions and maintain linear control flow with minimal side effects.
> 6. In fact try to have event driven architecture rather than futzing around with mutating data. The easiest way to sync is to maintain a linear total order for events.
if you have to mutate data, you should mutate data? not sure how events save you.
> 7. Think about how lookups will proceed and partition everything by those keys. Sometimes you need to have duplicate tables and keep a sync from a “primary” table to a “secodary” one in the app layer. Doing this allows you to do sharding or even go serverless peer-to-peer later!
wow! serverless peer-to-peer! i can't wait to re-write my app, i'm sure my customers will love the new architecture! /s -- on a serious note, while distributed sync is sometimes required (for instance, state kept in the JS front-end app that is a copy of the DB-preserved state on the backend), keeping them in sync can be a nightmare, and you should avoid this at all costs if possible.
> 8. Security: more checks are better than less. Pile on private keys, bearer tokens (api or cookie), and so on. Use a device keychain
in my experience, 80% of all bugs are security bugs (that number may be as low as 20% if you use the OPs advice to increase your bug count). while security is important, you should avoid "[piling] it on", and instead be thoughtful about it. separate authentication (accomplished with keys/tokens/etc...) from authorization (accomplished through checks of the identity at points of functionality).