Skip to content

UX: StatusMap as IDeref container #13

@SerhiiRI

Description

@SerhiiRI

Problem

execute returns a full status-map with internal structures, errors, stats, etc. But 99% of the time users only need the resolved instruction:

;; Current — verbose
(:instruction (commando/execute reg instruction))

;; Every single call site has this pattern

The status-map is valuable as a container (errors, patching, debug) but the default UX forces everyone to unwrap it.

Solution: defrecord + IDeref

Make status-map a record type that implements IDeref. @ returns :instruction on success, throws ExceptionInfo (with full status-map as ex-data) on failure.

;; Happy path — clean, 99% of use cases
@(execute reg instruction)
;; => {"1" 1, "2" 1, "3" 1}

;; Explicit error handling — full control
(let [r (execute reg instruction)]
  (if (ok? r)
    @r
    (handle-errors (:errors r))))

;; try/catch style
(try
  @(execute reg instruction)
  (catch #?(:clj ExceptionInfo :cljs ExceptionInfo) e
    (let [{:keys [errors status]} (ex-data e)]
      ...)))

;; Patching — pass the container, deref the final result
(let [r (execute reg instruction)]
  @(execute reg changed {:previous r}))

Implementation sketch

(defrecord StatusMap [status instruction errors warnings successes stats uuid]
  #?(:clj  clojure.lang.IDeref
     :cljs IDeref)
  (#?(:clj deref :cljs -deref) [this]
    (if (= status :failed)
      (throw (ex-info "Commando execution failed" (into {} this)))
      instruction)))

Why defrecord works here

  • assoc/update/get/destructuring — all work, extra keys (:internal/*) stored in overflow map
  • No dissoc on status-map fields anywhere in the pipeline (verified)
  • Record field access (:status, :instruction) is direct Java/JS field lookup — faster than hash-map
  • CLJS has IDeref protocol — cross-platform
  • (= record plain-map) breaks, but tests compare individual keys, not entire status-maps

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions