Conventions.md

9 May 2020

In Rails, there's generally one Right (or at least commonly-accepted) way to do things, so picking up someone else's codebase is fast. In javascript there's a huge amount of syntactic sugar [1] that makes it possible to write the same function many different ways - especially using transpilers. The minimal, opinionless nature of the React ecosystem presents even more options.

To some extent you can infer the conventions from the codebase, but I'm not a huge fan of copy-paste-modify as a way of getting things done, even if you're copy-pasting from the same codebase.

Instead, I've started documenting them explicitly in my projects. I'm not talking about things like "we use 4 spaces" or "we include a comma after the last item in the list" - those can be taught and enforced more effectively by .eslintrc. Conventions.md documents architectural patterns and tool choices, along with the reasons for them.

(The reasons are important. Documenting your reasons tends to stop a conversation being repeatedly reopened unnecessarily, but also sets up a culture of doing things because they're the right way, not because they're the way we've always done it).

For example, the first few documented decisions as we refactor Couchpile have been:

Never use default export

This allows consistent import styles - you don't have to know if something was default-export or not. We can't pick "always" so we pick "never".

So, in components, do export const MyComponent = ..., then import it as import { MyComponent } from "./MyComponent.jsx"

Connect() everything

All components that access state are connected to the store via connect(). Don't generally pass state props.

This is because we were ending up passing the same half-dozen props around everywhere; this is tidier.

In mapStateToProps, take only what you need

Don't grab the entire store, or even the entire top-level items, with things like state => {room: state.room, user: state.user}. Instead, drill down to the exact props you need, raising them to the top level, like state => {nick_name: state.user.nick_name}.

This makes it clearer what component actually depends on (useful if we need to change the store), and makes the view layer terser (since it can use shorter prop names, not having to represent the whole tree).


[1] I’ve started to refer to some of this as 'syntactic chilli'. Using it definitely makes everything cooler and more fun, but also inflicts pain on people who aren't used to it.