impromptu data structures, e.g. maps when something has a name • Especially useful at ingress/egress boundaries • Match and dispatch on struct module • Avoid creating too early • Do not make unnecessary structs
Can be behaviourized for compile/refactor safety • Allows passing modules and asking them questions about how to execute generic pipelines, e.g. what are your attributes • Powerful in combination with Domain Specific Languages
variable, function names • Unless guard, or over network, avoid is_ prefix • Use ! when function may raise, but be consistent • If ! function is provided, have a non-! function that returns :ok/:error tuple
them • Think of them like herbicides for plants - can help but can take over your entire garden if left unchecked • Keep roots away from main application with wrappers • Hard to rip out after they permeate app, especially when transitively included by other dependencies
modules fit together • Use utility style modules when "leaf" functionality • Keep direction pointing down • Similar granularity layers should interact with each other • Prefer "deep modules" as in Philosophy of Software Design
to functions ASAP for debuggability • Use location: :keep • after_compile validation useful in DSLs • Disabling lexical tracker useful for preventing deadlocks • Avoid name generation • Clean up after yourself
abstractions that need to exist to solve some problem • But make sure there's a problem first • Wrong abstractions are worse than code duplication https://www.sandimetz.com/blog/2016/1/20/the-wrong- abstraction
organization https://www.theerlangelist.com/article/spawn_or_not • Should call into application logic where appropriate • Umbrellas are not for code organization (ultimately) • Both are for runtime concerns