The “conventional commit” format advocates prefixing commit messages with keywords to give both humans and machines a quick idea of what’s affected:
41e7be2 feat: notify user on new messages
f3b33ab build: enable caching to decrease build times
7501fb2 fix(api): detect invalid query parameter
f5baa4d docs: typo
06e851a perf(ui): optimize loading time
The keyword mostly answers the question: “How does this modify existing code?” It fixes or refactors it, enhances its performance, or adds a new feature on top. Sometimes, however, it answers the question: “What area does this affect?” It affects the build process or the docs. Yet other times, it answers both questions by adding a parenthesized “scope”: it’s a fix to the api; it’s a performance enhancement to the (ui).
And if you’re fixing a doc? Improving the build’s performance?
Having to stop and think in these loaded, non-orthogonal terms, to come up with only moderately descriptive descriptions, feels like too high of a cost for the benefit.
Fortunately, a few extra keystrokes are all that’s need to lower the burden on the writer and boost the value for the reader.
A great question one can ask about a change is: “What quality of the system does this directly improve?” [1] A change to the front end might improve usability; one to the back end, observability; another to the docs, understandability.
The book Building Evolutionary Architectures has a long list of these “-ilities”:
You can use them to better describe, and think about, changes.
What qualities matter to your team and project? Pick a few, e.g.: functionality, usability, devability [2], stability, and security.
What quality does a change influence? That’s the first dimension:
what? | ||
---|---|---|
“notify user on new messages” | makes the application more useful | func |
“enable caching to decrease build times” | makes the system easier to develop | dev |
“detect invalid query parameter” | makes the system more stable | stab |
How does the change improve the quality? That’s the second dimension:
how? | ||
---|---|---|
“notify user on new messages” | adds something that wasn’t there before | feat |
“enable caching to decrease build times” | makes something better | enh |
“detect invalid query parameter” | makes something right | fix |
And the original example becomes:
- 41e7be2 feat: notify user on new messages
+ 41e7be2 usab,feat: notify user on new messages
- f3b33ab build: enable caching to decrease build times
+ f3b33ab dev,enh: enable caching to decrease build times
- 7501fb2 fix(api): detect invalid query parameter
+ 7501fb2 stab,fix(api): detect invalid query parameter
- f5baa4d docs: typo
+ f5baa4d dev,fix: typo
- 06e851a perf(ui): optimize loading time
+ 06e851a usab,enh(ui): optimize loading time
This strategy is surprisingly quick to pick up, generates informative descriptions, and gently nudges one to focus on the fundamental question:
What value does this change deliver?
“Directly” because everything, eventually, aims at improving end-user functionality, business profitability, and similar bottom lines, so those aren’t good descriptors at a local level. ↩︎
Think of devability as of usability for developers: a mixture of code understandability, debuggability, and tool ergonomy. ↩︎