Skip to content

Instantly share code, notes, and snippets.

@sir-wabbit
Last active December 23, 2025 19:46
Show Gist options
  • Select an option

  • Save sir-wabbit/96e391c74d768a850dd430f6edceca8e to your computer and use it in GitHub Desktop.

Select an option

Save sir-wabbit/96e391c74d768a850dd430f6edceca8e to your computer and use it in GitHub Desktop.

Revisions

  1. sir-wabbit revised this gist Dec 23, 2025. 1 changed file with 19 additions and 12 deletions.
    31 changes: 19 additions & 12 deletions naming-conventions.md
    Original file line number Diff line number Diff line change
    @@ -1,26 +1,33 @@
    NOTE: "complexity" is somewhat vaguely defined here. The real distinction is whether we
    - expect an immediate return,
    - expect some non-trivial work that is a function of input size or object size
    - expect I/O-bound work

    ---

    | Name / Pattern | Intended use | I/O allowed | Typical complexity expectation | Can mutate `this` | Exceptions: allowed by default | "Expected failure" alternative |
    | ------------------------------------------ | ------------------------------------------------------------------------------ | ---------------: | ---------------------------------------------------- | ----------------: | --------------------------------------------------- | ------------------------------------------- |
    | `of(...)` | Construct from **domain parts** or a **domain identifier** (validated factory) | No | O(1) or proportional to input size (validate/lookup) | N/A | Yes (`IllegalArgumentException` / domain exception) | `ofOrNull`, `tryOf: Result<T>` |
    | `from(x)` | **Convert/extract** from another type (possibly lossy) | No | O(1)-O(n) depending on conversion | N/A | Yes (if conversion invalid) | `fromOrNull`, `tryFrom` |
    | `parse(text)` | Parse **textual representation** (format/grammar) | No | O(n) in text length | N/A | Yes (`IllegalArgumentException`, parse exception) | `parseOrNull`, `tryParse` |
    | `decode(bytes)` | Parse **binary encoding** (wire format) | No | O(n) in bytes | N/A | Yes | `decodeOrNull`, `tryDecode` |
    | `deserialize(data)` | Rehydrate object from serialized form (often structured) | No (shouldn't) | Usually O(n) | N/A | Yes | `tryDeserialize` |
    | `toX()` | **Produce** an `X` (conversion that may allocate/copy) | No | O(1) or O(n) if copying | No | Prefer no; if can fail, make it obvious | `toXOrNull`, `tryToX` |
    | `of(...)` | Construct from **domain parts** or a **domain identifier** (validated factory) | No | Small | N/A | Yes (`IllegalArgumentException` / domain exception) | `ofOrNull`, `tryOf: Result<T>` |
    | `from(x)` | **Convert/extract** from another type (possibly lossy) | No | Small | N/A | Yes (if conversion invalid) | `fromOrNull`, `tryFrom` |
    | `parse(text)` | Parse **textual representation** (format/grammar) | No | Scales with input size | N/A | Yes (`IllegalArgumentException`, parse exception) | `parseOrNull`, `tryParse` |
    | `decode(bytes)` | Parse **binary encoding** (wire format) | No | Scales with input size | N/A | Yes | `decodeOrNull`, `tryDecode` |
    | `deserialize(data)` | Rehydrate object from serialized form (often structured) | No (shouldn't) | Scales with input size | N/A | Yes | `tryDeserialize` |
    | `toX()` | **Produce** an `X` (conversion that may allocate/copy) | No | O(1)-O(n) depending on structure | No | Prefer no; if can fail, make it obvious | `toXOrNull`, `tryToX` |
    | `asX()` | **View/adapt/cast-like** reinterpretation (cheap) | No | O(1) | No | No (ideally) | `asXOrNull` |
    | `withX(...)` | Return a copy with one field changed (structural update) | No | O(1)-O(n) depending on structure | No | No (unless validating constraints) | `withXOrNull` |
    | `copy(...)` | Kotlin data-class copy semantics | No | O(1) | No | No | N/A |
    | `normalize()` (mutating) | Normalize in-place | No | Usually O(n) | Yes | Yes if invariants violated | `normalizedRememberingFailures()` no thanks |
    | `normalized()` (pure) | Return normalized copy | No | Usually O(n) | No | Same as above | `normalizedOrNull` |
    | `withX(...)` | Return a copy with one field changed (structural update) | No | O(1)-O(n) depending on structure | No | No (unless validating constraints) | `withXOrNull` |
    | `copy(...)` | Kotlin data-class copy semantics | No | O(1)-O(n) depending on structure | No | No | N/A |
    | `normalize()` (mutating) | Normalize in-place | No | Scales with the object size | Yes | Yes if invariants violated | `normalizedRememberingFailures()` no thanks |
    | `normalized()` (pure) | Return normalized copy | No | Scales with the object size | No | Same as above | `normalizedOrNull` |
    | `sort()` | In-place ordering | No | O(n log n) | Yes | No | `sorted()` |
    | `sorted()` | Return sorted copy | No | O(n log n) | No | No | N/A |
    | `applyX(...)` / `updateX(...)` | Mutating update with intent | No | O(1)-O(n) | Yes | Yes | `tryUpdateX` |
    | `applyX(...)` / `updateX(...)` | Mutating update with intent | No | O(1)-O(n) depending on structure | Yes | Yes | `tryUpdateX` |
    | `load...()` | Read from persistent storage | Yes (disk) | Unbounded / I/O-bound | Usually No | Yes (I/O exceptions, domain) | `tryLoad`, `loadOrNull` |
    | `save...()` | Write to persistent storage | Yes (disk) | Unbounded / I/O-bound | Usually No | Yes | `trySave` |
    | `fetch...()` | Network retrieval | Yes (network) | Unbounded / network-bound | No | Yes | `tryFetch: Result<T>` |
    | `send...()` / `publish...()` / `emit...()` | Outbound side effect | Yes | Unbounded / I/O-bound | No | Yes | `trySend` |
    | `now()` / `current...()` | Sample clock/system state | Yes-ish (system) | O(1) | No | Rarely | N/A |
    | `getX()` | Property-like access (no work) | No | O(1) | No | No | N/A |
    | `findX(...)` | Lookup/search (may return none) | No | O(1)-O(n) depending | No | No | returns `T?` |
    | `findX(...)` | Lookup/search (may return none) | No | O(log(n))-O(n) depending on structure | No | No | returns `T?` |
    | `requireX(...)` (guard) | Validate args (public API boundary) | No | O(1)-O(n) | No | Yes: `IllegalArgumentException` | Provide non-throwing validator |
    | `checkX(...)` (guard) | Validate invariants/state (internal) | No | O(1)-O(n) | No | Yes: `IllegalStateException` | Usually not needed |
    | `validate()` | Produce diagnostics about validity | No | O(n) | No | Prefer no | return `List<Error>` / `Validation` |
  2. sir-wabbit revised this gist Dec 23, 2025. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions naming-conventions.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    | Name / Pattern | Intended use | I/O allowed | Typical complexity expectation | Can mutate `this` | Exceptions: allowed by default | "Expected failure" alternative |
    | ------------------------------------------ | ------------------------------------------------------------------------------ | ---------------: | ---------------------------------------------------- | ----------------: | --------------------------------------------------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
    | ------------------------------------------ | ------------------------------------------------------------------------------ | ---------------: | ---------------------------------------------------- | ----------------: | --------------------------------------------------- | ------------------------------------------- |
    | `of(...)` | Construct from **domain parts** or a **domain identifier** (validated factory) | No | O(1) or proportional to input size (validate/lookup) | N/A | Yes (`IllegalArgumentException` / domain exception) | `ofOrNull`, `tryOf: Result<T>` |
    | `from(x)` | **Convert/extract** from another type (possibly lossy) | No | O(1)-O(n) depending on conversion | N/A | Yes (if conversion invalid) | `fromOrNull`, `tryFrom` |
    | `parse(text)` | Parse **textual representation** (format/grammar) | No | O(n) in text length | N/A | Yes (`IllegalArgumentException`, parse exception) | `parseOrNull`, `tryParse` |
    @@ -15,10 +15,10 @@
    | `sorted()` | Return sorted copy | No | O(n log n) | No | No | N/A |
    | `applyX(...)` / `updateX(...)` | Mutating update with intent | No | O(1)-O(n) | Yes | Yes | `tryUpdateX` |
    | `load...()` | Read from persistent storage | Yes (disk) | Unbounded / I/O-bound | Usually No | Yes (I/O exceptions, domain) | `tryLoad`, `loadOrNull` |
    | `save...()` | Write to persistent storage | Yes (disk) | Unbounded / I/O-bound | Usually No | Yes | `trySave` | |
    | `fetch...()` | Network retrieval | Yes (network) | Unbounded / network-bound | No | Yes | `tryFetch: Result<T>` | |
    | `save...()` | Write to persistent storage | Yes (disk) | Unbounded / I/O-bound | Usually No | Yes | `trySave` |
    | `fetch...()` | Network retrieval | Yes (network) | Unbounded / network-bound | No | Yes | `tryFetch: Result<T>` |
    | `send...()` / `publish...()` / `emit...()` | Outbound side effect | Yes | Unbounded / I/O-bound | No | Yes | `trySend` |
    | `now()` / `current...()` | Sample clock/system state | Yes-ish (system) | O(1) | No | Rarely | N/A | |
    | `now()` / `current...()` | Sample clock/system state | Yes-ish (system) | O(1) | No | Rarely | N/A |
    | `getX()` | Property-like access (no work) | No | O(1) | No | No | N/A |
    | `findX(...)` | Lookup/search (may return none) | No | O(1)-O(n) depending | No | No | returns `T?` |
    | `requireX(...)` (guard) | Validate args (public API boundary) | No | O(1)-O(n) | No | Yes: `IllegalArgumentException` | Provide non-throwing validator |
  3. sir-wabbit revised this gist Dec 23, 2025. 1 changed file with 23 additions and 23 deletions.
    46 changes: 23 additions & 23 deletions naming-conventions.md
    Original file line number Diff line number Diff line change
    @@ -1,27 +1,27 @@
    | Name / Pattern | Intended use | I/O allowed | Typical complexity expectation | Can mutate `this` | Exceptions: allowed by default | "Expected failure" alternative | Notes / examples |
    | Name / Pattern | Intended use | I/O allowed | Typical complexity expectation | Can mutate `this` | Exceptions: allowed by default | "Expected failure" alternative |
    | ------------------------------------------ | ------------------------------------------------------------------------------ | ---------------: | ---------------------------------------------------- | ----------------: | --------------------------------------------------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
    | `of(...)` | Construct from **domain parts** or a **domain identifier** (validated factory) | No | O(1) or proportional to input size (validate/lookup) | No | Yes (`IllegalArgumentException` / domain exception) | `ofOrNull`, `tryOf: Result<T>` | Good for "I already have the pieces." `Rgb.of(r,g,b)`, `TimeZone.of("Europe/Berlin")` |
    | `from(x)` | **Convert/extract** from another type (possibly lossy) | No | O(1)-O(n) depending on conversion | No | Yes (if conversion invalid) | `fromOrNull`, `tryFrom` | "x is already structured." `Instant.from(TemporalAccessor)` style` |
    | `parse(text)` | Parse **textual representation** (format/grammar) | No | O(n) in text length | No | Yes (`IllegalArgumentException`, parse exception) | `parseOrNull`, `tryParse` | Parsing anything. |
    | `decode(bytes)` | Parse **binary encoding** (wire format) | No | O(n) in bytes | No | Yes | `decodeOrNull`, `tryDecode` | Use for protobuf/msgpack/custom framing. Strong "this may fail" signal |
    | `deserialize(data)` | Rehydrate object from serialized form (often structured) | No (shouldn't) | Usually O(n) | No | Yes | `tryDeserialize` | Use when format isn't strictly "text parsing" but rehydration from structured data |
    | `toX()` | **Produce** an `X` (conversion that may allocate/copy) | No | O(1) or O(n) if copying | No | Prefer no; if can fail, make it obvious | `toXOrNull`, `tryToX` | `toString()` is the classic. If it can fail, don't hide it |
    | `asX()` | **View/adapt/cast-like** reinterpretation (cheap) | No | O(1) | No | No (ideally) | `asXOrNull` | Think "no real work, just a different lens." If it allocates, it shouldn't be `as` |
    | `withX(...)` | Return a copy with one field changed (structural update) | No | O(1)-O(n) depending on structure | No | No (unless validating constraints) | `withXOrNull` | For immutable types. If it can violate invariants, validate and possibly throw |
    | `copy(...)` | Kotlin data-class copy semantics | No | O(1) | No | No | N/A | Prefer using built-in `copy` over inventing ten `with...` methods |
    | `normalize()` (mutating) | Normalize in-place | No | Usually O(n) | Yes | Yes if invariants violated | `normalizedRememberingFailures()` no thanks | Pair with `normalized()` for pure version. Mutating name should be a verb |
    | `normalized()` (pure) | Return normalized copy | No | Usually O(n) | No | Same as above | `normalizedOrNull` | Pair naming makes mutation vs purity obvious |
    | `sort()` | In-place ordering | No | O(n log n) | Yes | No | `sorted()` | Kotlin precedent: `sort` mutates, `sorted` returns copy |
    | `sorted()` | Return sorted copy | No | O(n log n) | No | No | N/A | Avoid surprise side effects |
    | `applyX(...)` / `updateX(...)` | Mutating update with intent | No | O(1)-O(n) | Yes | Yes | `tryUpdateX` | Use when mutation is the point and you want it loud |
    | `load...()` | Read from persistent storage | Yes (disk) | Unbounded / I/O-bound | Usually No | Yes (I/O exceptions, domain) | `tryLoad`, `loadOrNull` | Names must admit touching the outside world |
    | `of(...)` | Construct from **domain parts** or a **domain identifier** (validated factory) | No | O(1) or proportional to input size (validate/lookup) | N/A | Yes (`IllegalArgumentException` / domain exception) | `ofOrNull`, `tryOf: Result<T>` |
    | `from(x)` | **Convert/extract** from another type (possibly lossy) | No | O(1)-O(n) depending on conversion | N/A | Yes (if conversion invalid) | `fromOrNull`, `tryFrom` |
    | `parse(text)` | Parse **textual representation** (format/grammar) | No | O(n) in text length | N/A | Yes (`IllegalArgumentException`, parse exception) | `parseOrNull`, `tryParse` |
    | `decode(bytes)` | Parse **binary encoding** (wire format) | No | O(n) in bytes | N/A | Yes | `decodeOrNull`, `tryDecode` |
    | `deserialize(data)` | Rehydrate object from serialized form (often structured) | No (shouldn't) | Usually O(n) | N/A | Yes | `tryDeserialize` |
    | `toX()` | **Produce** an `X` (conversion that may allocate/copy) | No | O(1) or O(n) if copying | No | Prefer no; if can fail, make it obvious | `toXOrNull`, `tryToX` |
    | `asX()` | **View/adapt/cast-like** reinterpretation (cheap) | No | O(1) | No | No (ideally) | `asXOrNull` |
    | `withX(...)` | Return a copy with one field changed (structural update) | No | O(1)-O(n) depending on structure | No | No (unless validating constraints) | `withXOrNull` |
    | `copy(...)` | Kotlin data-class copy semantics | No | O(1) | No | No | N/A |
    | `normalize()` (mutating) | Normalize in-place | No | Usually O(n) | Yes | Yes if invariants violated | `normalizedRememberingFailures()` no thanks |
    | `normalized()` (pure) | Return normalized copy | No | Usually O(n) | No | Same as above | `normalizedOrNull` |
    | `sort()` | In-place ordering | No | O(n log n) | Yes | No | `sorted()` |
    | `sorted()` | Return sorted copy | No | O(n log n) | No | No | N/A |
    | `applyX(...)` / `updateX(...)` | Mutating update with intent | No | O(1)-O(n) | Yes | Yes | `tryUpdateX` |
    | `load...()` | Read from persistent storage | Yes (disk) | Unbounded / I/O-bound | Usually No | Yes (I/O exceptions, domain) | `tryLoad`, `loadOrNull` |
    | `save...()` | Write to persistent storage | Yes (disk) | Unbounded / I/O-bound | Usually No | Yes | `trySave` | |
    | `fetch...()` | Network retrieval | Yes (network) | Unbounded / network-bound | No | Yes | `tryFetch: Result<T>` | |
    | `send...()` / `publish...()` / `emit...()` | Outbound side effect | Yes | Unbounded / I/O-bound | No | Yes | `trySend` | Your future self is not psychic |
    | `send...()` / `publish...()` / `emit...()` | Outbound side effect | Yes | Unbounded / I/O-bound | No | Yes | `trySend` |
    | `now()` / `current...()` | Sample clock/system state | Yes-ish (system) | O(1) | No | Rarely | N/A | |
    | `getX()` | Property-like access (no work) | No | O(1) | No | No | N/A | If it can block, parse, or do I/O, it should not be `get` |
    | `findX(...)` | Lookup/search (may return none) | No | O(1)-O(n) depending | No | No | returns `T?` | Conventional expectation: absence is normal, so use nullable |
    | `requireX(...)` (guard) | Validate args (public API boundary) | No | O(1)-O(n) | No | Yes: `IllegalArgumentException` | Provide non-throwing validator | Use Kotlin `require(...)` semantics: caller fault |
    | `checkX(...)` (guard) | Validate invariants/state (internal) | No | O(1)-O(n) | No | Yes: `IllegalStateException` | Usually not needed | If this fails in production, something is broken, not "invalid input" |
    | `validate()` | Produce diagnostics about validity | No | O(n) | No | Prefer no | return `List<Error>` / `Validation` | Better than throwing for routine invalid data |
    | `validateOrThrow()` | Validate then throw on failure | No | O(n) | No | Yes | `validate()` | Makes "throws" explicit without burying it |
    | `getX()` | Property-like access (no work) | No | O(1) | No | No | N/A |
    | `findX(...)` | Lookup/search (may return none) | No | O(1)-O(n) depending | No | No | returns `T?` |
    | `requireX(...)` (guard) | Validate args (public API boundary) | No | O(1)-O(n) | No | Yes: `IllegalArgumentException` | Provide non-throwing validator |
    | `checkX(...)` (guard) | Validate invariants/state (internal) | No | O(1)-O(n) | No | Yes: `IllegalStateException` | Usually not needed |
    | `validate()` | Produce diagnostics about validity | No | O(n) | No | Prefer no | return `List<Error>` / `Validation` |
    | `validateOrThrow()` | Validate then throw on failure | No | O(n) | No | Yes | `validate()` |
  4. sir-wabbit revised this gist Dec 23, 2025. No changes.
  5. sir-wabbit revised this gist Dec 23, 2025. 1 changed file with 18 additions and 18 deletions.
    36 changes: 18 additions & 18 deletions naming-conventions.md
    Original file line number Diff line number Diff line change
    @@ -1,27 +1,27 @@
    | Name / Pattern | Intended use | I/O allowed | Typical complexity expectation | Can mutate `this` | Exceptions: allowed by default | Expected failure alternative | Notes / examples |
    | Name / Pattern | Intended use | I/O allowed | Typical complexity expectation | Can mutate `this` | Exceptions: allowed by default | "Expected failure" alternative | Notes / examples |
    | ------------------------------------------ | ------------------------------------------------------------------------------ | ---------------: | ---------------------------------------------------- | ----------------: | --------------------------------------------------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
    | `of(...)` | Construct from **domain parts** or a **domain identifier** (validated factory) | No | O(1) or proportional to input size (validate/lookup) | No | Yes (`IllegalArgumentException` / domain exception) | `ofOrNull`, `tryOf: Result<T>` | Good for I already have the pieces. `Rgb.of(r,g,b)`, `TimeZone.of("Europe/Berlin")` |
    | `from(x)` | **Convert/extract** from another type (possibly lossy) | No | O(1)O(n) depending on conversion | No | Yes (if conversion invalid) | `fromOrNull`, `tryFrom` | x is already structured. `Instant.from(TemporalAccessor)` style; your domain: `Money.from(BigDecimal)` |
    | `parse(text)` | Parse **textual representation** (format/grammar) | No | O(n) in text length | No | Yes (`IllegalArgumentException`, parse exception) | `parseOrNull`, `tryParse` | Text is the warning label. If input is free-form user text, prefer `parseOrNull/tryParse` |
    | `decode(bytes)` | Parse **binary encoding** (wire format) | No | O(n) in bytes | No | Yes | `decodeOrNull`, `tryDecode` | Use for protobuf/msgpack/custom framing. Strong this may fail signal |
    | `deserialize(data)` | Rehydrate object from serialized form (often structured) | No (shouldnt) | Usually O(n) | No | Yes | `tryDeserialize` | Use when format isnt strictly text parsing but rehydration from structured data |
    | `toX()` | **Produce** an `X` (conversion that may allocate/copy) | No | O(1) or O(n) if copying | No | Prefer no; if can fail, make it obvious | `toXOrNull`, `tryToX` | `toString()` is the classic. If it can fail, dont hide it |
    | `asX()` | **View/adapt/cast-like** reinterpretation (cheap) | No | O(1) | No | No (ideally) | `asXOrNull` | Think no real work, just a different lens. If it allocates, it shouldnt be `as` |
    | `withX(...)` | Return a copy with one field changed (structural update) | No | O(1)O(n) depending on structure | No | No (unless validating constraints) | `withXOrNull` | For immutable types. If it can violate invariants, validate and possibly throw |
    | `of(...)` | Construct from **domain parts** or a **domain identifier** (validated factory) | No | O(1) or proportional to input size (validate/lookup) | No | Yes (`IllegalArgumentException` / domain exception) | `ofOrNull`, `tryOf: Result<T>` | Good for "I already have the pieces." `Rgb.of(r,g,b)`, `TimeZone.of("Europe/Berlin")` |
    | `from(x)` | **Convert/extract** from another type (possibly lossy) | No | O(1)-O(n) depending on conversion | No | Yes (if conversion invalid) | `fromOrNull`, `tryFrom` | "x is already structured." `Instant.from(TemporalAccessor)` style` |
    | `parse(text)` | Parse **textual representation** (format/grammar) | No | O(n) in text length | No | Yes (`IllegalArgumentException`, parse exception) | `parseOrNull`, `tryParse` | Parsing anything. |
    | `decode(bytes)` | Parse **binary encoding** (wire format) | No | O(n) in bytes | No | Yes | `decodeOrNull`, `tryDecode` | Use for protobuf/msgpack/custom framing. Strong "this may fail" signal |
    | `deserialize(data)` | Rehydrate object from serialized form (often structured) | No (shouldn't) | Usually O(n) | No | Yes | `tryDeserialize` | Use when format isn't strictly "text parsing" but rehydration from structured data |
    | `toX()` | **Produce** an `X` (conversion that may allocate/copy) | No | O(1) or O(n) if copying | No | Prefer no; if can fail, make it obvious | `toXOrNull`, `tryToX` | `toString()` is the classic. If it can fail, don't hide it |
    | `asX()` | **View/adapt/cast-like** reinterpretation (cheap) | No | O(1) | No | No (ideally) | `asXOrNull` | Think "no real work, just a different lens." If it allocates, it shouldn't be `as` |
    | `withX(...)` | Return a copy with one field changed (structural update) | No | O(1)-O(n) depending on structure | No | No (unless validating constraints) | `withXOrNull` | For immutable types. If it can violate invariants, validate and possibly throw |
    | `copy(...)` | Kotlin data-class copy semantics | No | O(1) | No | No | N/A | Prefer using built-in `copy` over inventing ten `with...` methods |
    | `normalize()` (mutating) | Normalize in-place | No | Usually O(n) | Yes | Yes if invariants violated | `normalizedRememberingFailures()` no thanks | Pair with `normalized()` for pure version. Mutating name should be a verb |
    | `normalized()` (pure) | Return normalized copy | No | Usually O(n) | No | Same as above | `normalizedOrNull` | Pair naming makes mutation vs purity obvious |
    | `sort()` | In-place ordering | No | O(n log n) | Yes | No | `sorted()` | Kotlin precedent: `sort` mutates, `sorted` returns copy |
    | `sorted()` | Return sorted copy | No | O(n log n) | No | No | N/A | Avoid surprise side effects |
    | `applyX(...)` / `updateX(...)` | Mutating update with intent | No | O(1)O(n) | Yes | Yes | `tryUpdateX` | Use when mutation is the point and you want it loud |
    | `applyX(...)` / `updateX(...)` | Mutating update with intent | No | O(1)-O(n) | Yes | Yes | `tryUpdateX` | Use when mutation is the point and you want it loud |
    | `load...()` | Read from persistent storage | Yes (disk) | Unbounded / I/O-bound | Usually No | Yes (I/O exceptions, domain) | `tryLoad`, `loadOrNull` | Names must admit touching the outside world |
    | `save...()` | Write to persistent storage | Yes (disk) | Unbounded / I/O-bound | Usually No | Yes | `trySave` | “save” implies side effects. Good |
    | `fetch...()` | Network retrieval | Yes (network) | Unbounded / network-bound | No | Yes | `tryFetch: Result<T>` | Don’t name this `getUser()` unless you enjoy lying |
    | `send...()` / `publish...()` / `emit...()` | Outbound side effect | Yes | Unbounded / I/O-bound | No | Yes | `trySend` | Make the effect explicit. Your future self is not psychic |
    | `now()` / `current...()` | Sample clock/system state | Yes-ish (system) | O(1) | No | Rarely | N/A | Non-deterministic by definition. Don’t disguise it as pure |
    | `save...()` | Write to persistent storage | Yes (disk) | Unbounded / I/O-bound | Usually No | Yes | `trySave` | |
    | `fetch...()` | Network retrieval | Yes (network) | Unbounded / network-bound | No | Yes | `tryFetch: Result<T>` | |
    | `send...()` / `publish...()` / `emit...()` | Outbound side effect | Yes | Unbounded / I/O-bound | No | Yes | `trySend` | Your future self is not psychic |
    | `now()` / `current...()` | Sample clock/system state | Yes-ish (system) | O(1) | No | Rarely | N/A | |
    | `getX()` | Property-like access (no work) | No | O(1) | No | No | N/A | If it can block, parse, or do I/O, it should not be `get` |
    | `findX(...)` | Lookup/search (may return none) | No | O(1)O(n) depending | No | No | returns `T?` | Conventional expectation: absence is normal, so use nullable |
    | `requireX(...)` (guard) | Validate args (public API boundary) | No | O(1)O(n) | No | Yes: `IllegalArgumentException` | Provide non-throwing validator | Use Kotlin `require(...)` semantics: caller fault |
    | `checkX(...)` (guard) | Validate invariants/state (internal) | No | O(1)O(n) | No | Yes: `IllegalStateException` | Usually not needed | If this fails in production, something is broken, not invalid input |
    | `findX(...)` | Lookup/search (may return none) | No | O(1)-O(n) depending | No | No | returns `T?` | Conventional expectation: absence is normal, so use nullable |
    | `requireX(...)` (guard) | Validate args (public API boundary) | No | O(1)-O(n) | No | Yes: `IllegalArgumentException` | Provide non-throwing validator | Use Kotlin `require(...)` semantics: caller fault |
    | `checkX(...)` (guard) | Validate invariants/state (internal) | No | O(1)-O(n) | No | Yes: `IllegalStateException` | Usually not needed | If this fails in production, something is broken, not "invalid input" |
    | `validate()` | Produce diagnostics about validity | No | O(n) | No | Prefer no | return `List<Error>` / `Validation` | Better than throwing for routine invalid data |
    | `validateOrThrow()` | Validate then throw on failure | No | O(n) | No | Yes | `validate()` | Makes throws explicit without burying it |
    | `validateOrThrow()` | Validate then throw on failure | No | O(n) | No | Yes | `validate()` | Makes "throws" explicit without burying it |
  6. sir-wabbit revised this gist Dec 23, 2025. 1 changed file with 0 additions and 2 deletions.
    2 changes: 0 additions & 2 deletions naming-conventions.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,3 @@
    Here. A table that turns naming into something slightly less religious.

    | Name / Pattern | Intended use | I/O allowed | Typical complexity expectation | Can mutate `this` | Exceptions: allowed by default | “Expected failure” alternative | Notes / examples |
    | ------------------------------------------ | ------------------------------------------------------------------------------ | ---------------: | ---------------------------------------------------- | ----------------: | --------------------------------------------------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
    | `of(...)` | Construct from **domain parts** or a **domain identifier** (validated factory) | No | O(1) or proportional to input size (validate/lookup) | No | Yes (`IllegalArgumentException` / domain exception) | `ofOrNull`, `tryOf: Result<T>` | Good for “I already have the pieces.” `Rgb.of(r,g,b)`, `TimeZone.of("Europe/Berlin")` |
  7. sir-wabbit created this gist Dec 23, 2025.
    29 changes: 29 additions & 0 deletions naming-conventions.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,29 @@
    Here. A table that turns naming into something slightly less religious.

    | Name / Pattern | Intended use | I/O allowed | Typical complexity expectation | Can mutate `this` | Exceptions: allowed by default | “Expected failure” alternative | Notes / examples |
    | ------------------------------------------ | ------------------------------------------------------------------------------ | ---------------: | ---------------------------------------------------- | ----------------: | --------------------------------------------------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
    | `of(...)` | Construct from **domain parts** or a **domain identifier** (validated factory) | No | O(1) or proportional to input size (validate/lookup) | No | Yes (`IllegalArgumentException` / domain exception) | `ofOrNull`, `tryOf: Result<T>` | Good for “I already have the pieces.” `Rgb.of(r,g,b)`, `TimeZone.of("Europe/Berlin")` |
    | `from(x)` | **Convert/extract** from another type (possibly lossy) | No | O(1)–O(n) depending on conversion | No | Yes (if conversion invalid) | `fromOrNull`, `tryFrom` | “x is already structured.” `Instant.from(TemporalAccessor)` style; your domain: `Money.from(BigDecimal)` |
    | `parse(text)` | Parse **textual representation** (format/grammar) | No | O(n) in text length | No | Yes (`IllegalArgumentException`, parse exception) | `parseOrNull`, `tryParse` | Text is the warning label. If input is free-form user text, prefer `parseOrNull/tryParse` |
    | `decode(bytes)` | Parse **binary encoding** (wire format) | No | O(n) in bytes | No | Yes | `decodeOrNull`, `tryDecode` | Use for protobuf/msgpack/custom framing. Strong “this may fail” signal |
    | `deserialize(data)` | Rehydrate object from serialized form (often structured) | No (shouldn’t) | Usually O(n) | No | Yes | `tryDeserialize` | Use when format isn’t strictly “text parsing” but rehydration from structured data |
    | `toX()` | **Produce** an `X` (conversion that may allocate/copy) | No | O(1) or O(n) if copying | No | Prefer no; if can fail, make it obvious | `toXOrNull`, `tryToX` | `toString()` is the classic. If it can fail, don’t hide it |
    | `asX()` | **View/adapt/cast-like** reinterpretation (cheap) | No | O(1) | No | No (ideally) | `asXOrNull` | Think “no real work, just a different lens.” If it allocates, it shouldn’t be `as` |
    | `withX(...)` | Return a copy with one field changed (structural update) | No | O(1)–O(n) depending on structure | No | No (unless validating constraints) | `withXOrNull` | For immutable types. If it can violate invariants, validate and possibly throw |
    | `copy(...)` | Kotlin data-class copy semantics | No | O(1) | No | No | N/A | Prefer using built-in `copy` over inventing ten `with...` methods |
    | `normalize()` (mutating) | Normalize in-place | No | Usually O(n) | Yes | Yes if invariants violated | `normalizedRememberingFailures()` no thanks | Pair with `normalized()` for pure version. Mutating name should be a verb |
    | `normalized()` (pure) | Return normalized copy | No | Usually O(n) | No | Same as above | `normalizedOrNull` | Pair naming makes mutation vs purity obvious |
    | `sort()` | In-place ordering | No | O(n log n) | Yes | No | `sorted()` | Kotlin precedent: `sort` mutates, `sorted` returns copy |
    | `sorted()` | Return sorted copy | No | O(n log n) | No | No | N/A | Avoid surprise side effects |
    | `applyX(...)` / `updateX(...)` | Mutating update with intent | No | O(1)–O(n) | Yes | Yes | `tryUpdateX` | Use when mutation is the point and you want it loud |
    | `load...()` | Read from persistent storage | Yes (disk) | Unbounded / I/O-bound | Usually No | Yes (I/O exceptions, domain) | `tryLoad`, `loadOrNull` | Names must admit touching the outside world |
    | `save...()` | Write to persistent storage | Yes (disk) | Unbounded / I/O-bound | Usually No | Yes | `trySave` | “save” implies side effects. Good |
    | `fetch...()` | Network retrieval | Yes (network) | Unbounded / network-bound | No | Yes | `tryFetch: Result<T>` | Don’t name this `getUser()` unless you enjoy lying |
    | `send...()` / `publish...()` / `emit...()` | Outbound side effect | Yes | Unbounded / I/O-bound | No | Yes | `trySend` | Make the effect explicit. Your future self is not psychic |
    | `now()` / `current...()` | Sample clock/system state | Yes-ish (system) | O(1) | No | Rarely | N/A | Non-deterministic by definition. Don’t disguise it as pure |
    | `getX()` | Property-like access (no work) | No | O(1) | No | No | N/A | If it can block, parse, or do I/O, it should not be `get` |
    | `findX(...)` | Lookup/search (may return none) | No | O(1)–O(n) depending | No | No | returns `T?` | Conventional expectation: absence is normal, so use nullable |
    | `requireX(...)` (guard) | Validate args (public API boundary) | No | O(1)–O(n) | No | Yes: `IllegalArgumentException` | Provide non-throwing validator | Use Kotlin `require(...)` semantics: caller fault |
    | `checkX(...)` (guard) | Validate invariants/state (internal) | No | O(1)–O(n) | No | Yes: `IllegalStateException` | Usually not needed | If this fails in production, something is broken, not “invalid input” |
    | `validate()` | Produce diagnostics about validity | No | O(n) | No | Prefer no | return `List<Error>` / `Validation` | Better than throwing for routine invalid data |
    | `validateOrThrow()` | Validate then throw on failure | No | O(n) | No | Yes | `validate()` | Makes “throws” explicit without burying it |