Skip to content
AgileLogics
7 min read

Best Practices for Production Wolfram Code

Prerequisites: Testing and debugging

Notebooks are ideal for exploring. Code that others rely on needs the same discipline as in any language.

Structure

  • Packages, not notebooks, for reusable code: .wl files in a paclet, with public symbols documented by ::usage messages and helpers in a private context.
  • Pure functions of their inputs — avoid global variables; use Module for locals and pass settings as options.
  • One job per function, small enough to test.
  • Options for configurable behavior, the way built-ins work:
Options[describe] = {"Digits" -> 3};
describe[data_List, OptionsPattern[]] := With[{d = OptionValue["Digits"]},
  <|"n" -> Length[data], "mean" -> N[Mean[data], d]|>]
describe[{1, 2, 3, 4}]
describe[{1, 2, 3, 4}, "Digits" -> 5]
<|n -> 4, mean -> 2.50|>
<|n -> 4, mean -> 2.5000|>

N[x, 3] gives an arbitrary-precision number with 3 digits, and the notebook shows exactly those digits.

Validate inputs

  • Use patterns and tests (_Integer?Positive, _String, {__?NumericQ}) so bad input doesn't match — then add a catch-all definition that issues a clear message and returns a Failure.
  • At boundaries (APIs, forms, scripts), convert text with Interpreter, never ToExpression.

Reliability

  • Tests for every public function, run automatically with TestReport in a script.
  • Exact where it matters, approximate where speed matters — and be explicit with N.
  • Reproducibility: seed random numbers with SeedRandom, save external data you fetched, and record $Version with results.
  • Static checks: the CodeInspector paclet (CodeInspect["file.wl"]) finds suspicious code, and CodeFormatter formats it.

Collaboration

  • Keep .wl and .wlt files in version control. Notebooks (.nb) are large expression files that diff poorly; if you keep them, clear outputs first.
  • Write documentation pages with the Documentation Tools paclet, or at least a README and usage messages.

Deployment and licensing

  • Choose where code runs: the Wolfram Cloud (APIs, forms, scheduled tasks), the Wolfram Application Server, or the Wolfram Engine inside your own service.
  • Check licensing early — the free Wolfram Engine is for development, and production use needs a license.

A final example

A small, production-style function: documented, validated, optional settings, and a failure path.

compoundValue::usage = "compoundValue[p, r, n] gives the value of principal p after n years at annual rate r.";
compoundValue::badrate = "Rate `1` should be between 0 and 1.";
compoundValue[p_?Positive, r_?NumericQ, n_Integer?NonNegative] :=
  If[0 <= r <= 1,
    Round[p (1 + r)^n, 0.01],
    Message[compoundValue::badrate, r]; Failure["BadRate", <|"Rate" -> r|>]]
compoundValue[1000, 0.05, 10]
FailureQ[Quiet[compoundValue[1000, 5, 10]]]
1628.89
True

What's next

Try the Advanced Projects, then read What You Should Know Now — and What's Next for where to go from here.