Julia Code Standards
Julia Code Standards
Standard: Senior Principal Computational Scientist + PhD researcher quality
1. Reproducibility
Random.seed!(YYYYMMDD)called ONCE at top (YYYYMMDD format) ONCE CHOOSING A SEED DO NOT CHANGE IT AGAIN- All dependencies loaded at top via
usingorimport - All paths relative to the script working directory using
joinpath() - Rely on the Makefile to make directories
2. Function Design
snake_casefor functions and variables,CamelCasefor types and modules- Verb-noun pattern (e.g.,
run_simulation,generate_dgp,compute_effect) - Triple-quoted docstrings with signature, arguments, and return type
- Default parameters for all tuning values, no magic numbers
- Return
NamedTupleor customstruct(not bare tuples)
3. Domain Correctness
- Verify estimator/simulation implementations match paper formulas (
latex/manuscript.tex) - Check known package bugs
- Be aware of Float64 precision differences vs R
4. Output Paths & Data Persistence
Task-group scripts usually run from code/[task_group]/, so paths are
relative to that working directory. In the standard layout, define
output_root once and write into the main subdirectories under the repo-root
output/ directory:
output_root = joinpath("..", "..", "output")
# Figures
savefig(joinpath(output_root, "figures", "my_plot.pdf"))
# Tables / data
CSV.write(joinpath(output_root, "tables", "my_results.csv"), df)
# Inline numbers for manuscript
open(joinpath(output_root, "numbers", "my_estimate.txt"), "w") do io
println(io, "\\newcommand{\\myEstimate}{2.31}")
end
Heavy computations saved to disk; downstream scripts load pre-computed data.
Prefer JLD2 for Julia-native objects. Use CSV for model output. When saving parameterized results, include parameter values in filenames (ASCII only, strip hats).
5. Common Pitfalls
| Pitfall | Impact | Prevention |
|---|---|---|
| Global variables in hot loops | Severe performance regression | Pass as arguments or use const |
| Abstract-typed struct fields | Type instability, slow dispatch | Always annotate fields with concrete types |
1:length(x) instead of eachindex(x) |
Off-by-one risk with OffsetArrays | Use eachindex(x) or axes(x, dim) |
| Unfused broadcasts | Allocates intermediates | Use @. macro |
Missing @views on slices |
Allocates copies | Wrap in @views |
| Hardcoded paths | Breaks on other machines | Use joinpath() with relative paths |
6. Line Length
Standard: Keep lines <= 92 characters (Julia community convention). Mathematical formulas may exceed 92 chars under the same conditions as R.
7. Type Stability & Performance
- Run
@code_warntypeon hot functions during development - Struct fields must have concrete types (no
Any, no abstract types) - Use
constfor module-level constants - Use
@viewsto avoid allocating array slices in loops - Pre-allocate output arrays when size is known
8. Broadcasting & Fusion
- Prefer
@.macro for multi-operation broadcast expressions - Use
map/reduce/ comprehensions for non-broadcastable transforms - Avoid allocating intermediate arrays where fused broadcasts suffice
9. Code Quality Checklist
[ ] Dependencies loaded at top via using/import
[ ] Random.seed!() once at top
[ ] Clean header block with purpose, inputs, outputs, and assumptions
[ ] All paths relative via joinpath() from the script working directory
[ ] Functions documented (triple-quoted docstrings)
[ ] One operation per line; long calls split by argument where readable
[ ] Descriptive snake_case names for values/functions and CamelCase types
[ ] JLD2: every computed object saved
[ ] Comments explain WHY not WHAT
[ ] Struct fields have concrete types
[ ] Hot loops use @views and pre-allocation
[ ] Broadcasts fused with @. where applicable