A manifesto by Oliver Russell, posted on 2023-02-23.
Or CTRL-click or META-click or whatever.
- Being able to CMD-click through code >> any other theoretical concerns.
- CMD-clickability is the opposite of indirection - how does this function work? CMD-click it.
- Non-CMD-clickable codebases are filled with non-meaningful abstractions and tend to be longer.
- Static analysis tooling should be easy to write.
- Stack traces should correspond with the structure of the code.
-
Higher order functions break the golden property, use them as a last resort.
def do_something(data, f: Callable[...]): f(data) # I can't CMD-click f
-
Trad Object Orientated code tends to break the golden property (this makes sense as objects are closures), use it as a last resort.
def do_something(a: Animal): a.meow() # I can't CMD-click meow
This case it is ambiguous as
meow()
could be on anyCat
,Lion
,Tiger
... 8. Use enum-like information to distinguish between otherwise similar data.class Cat(Animal): ... # bad a = Animal(kind=AnimalKind.CAT, ...) # good
-
Serializable enum-like discriminants in data can be trivially plonked into databases, regurgitated via JSON, etc.
-
Choose behaviour based on data, not class hierarchies:
def do_something(data): if data.kind == Kind.A: g(data) # I can CMD-click g
-
Say arbitrarily complicated things about data, rather than be constrained by inflexible heirarchies.
class Cat(Animal, FourLegged): ... # bad def has_even_number_of_legs(a: AnimalKind) -> bool # good
-
Strong typing aids CMD-clickability, this property of typing is more valuable than correctness.
- Microservices in and of themselves are not bad, however:
- Construct your codebase such that CMD-clicking across a service boundary is as easy as within a service.
- Typecheck service boundaries as you would any other code.
- Use correlation ids and a Datadog-like tool to make cross-service stack traces comprehensible for debugging production.
-
Where you might have to fall back on grepping - make it easy, use full literals:
@app.route(PREFIX + "/v1/add") # bad @app.route("/payments/inbound/v1/add") # good
-
Good code expresses the smallest possible state space the program could operate in - YAGNI.
def do_something(data, f: Callable[...]): # f could be anything - big state space f(data) def do_something(data, kind: Kind): # we enumerate the specific things we can do - small state space if kind == Kind.A: g(data) ...
-
Lean in on language features, don't introduce unnecessary abstractions.
- There exists deep library code where we want to allow consumers to do anything (extensibility). In application development, this is the exception - you have control over the whole codebase, the code by its nature is extensible.
- Ignore this manifesto sooner than code anything outright barbarous.