[OCaml] High Intensity Training Online
Table of Contents
OCaml implementation
Source of truth
- `.mli` files are the specification and outrank tests.
- If an interface and a test disagree, fix the test.
- Changing an interface is a deliberate design decision — raise it, don't drift into it.
Style
- Modern, idiomatic OCaml. Favour the principle of least surprise: a reader should not need to learn a local idiom to follow the code.
- Prefer readable, shallow code. A flat sequence a reader can follow top to bottom beats a deeply nested tower of `match` arms.
- Reach for `let*` when it flattens nested cases — chained `result` or `result Lwt.t` plumbing where each step short-circuits on error. Used this way, a bind improves flow and cuts indentation. - A single `match` is clearer than a monad; don't reach for one reflexively. - Two or three cascading `match ... with Error _ -> ... | Ok x -> ...` steps are the signal to switch to `let*`.
- Abstract types with smart constructors for anything carrying an invariant.
- Use `result` for expected, recoverable failure. - This includes converting untrusted external data and domain feedback a caller can present or recover from. - Each module defines its own errors; no shared catch-all error type or `string` errors.
- Raise a module-specific exception for a violated authored-plan precondition after validation. - Do not use exceptions for normal domain outcomes or recorded deviations.
- Prefer closed variants — they keep `match` exhaustiveness working for you.
- Total functions where practical; make partiality visible in the type.
Layering
Three libraries, dependencies pointing inward only:
- `hito.core` — pure domain. No framework, database, or serialization dependencies. Ever.
- `hito.app` — `Repository` port, `Service`, adapters. Knows nothing of Dream.
- `hito.web` — Dream application. The only place Dream and dream-html appear.
Rules:
- Ports are module types; adapters implement them.
- Persistence identity is assigned in `hito.app`, not in the core.