nubank/state-flow

Uncaught exceptions are really hard debug

caioaao opened this issue · 3 comments

When an uncaught exception is thrown, all we get is the flow where it happened. Consider this flow and its execution output: https://gist.github.com/caioaao/0505aef68992f5bd6da88aba3e27a6f8

We don't have the step where it happened like we do with failed assertions. Instead we just have the flow name. This is specially hard when we have more complex flows that uses the faulty function more than once. Sub flows help mitigate this issue, but not completely solve it.

Yes, I think addressing this would help a lot with the opaqueness of state-flow stacktraces

#35 / #51 do this for test failures, to some extent, but not exceptions.

I'm trying to figure out how to get line info for arbitrary steps in a flow. Here is what I have sketched but need to spend some more time with it, because I don't know if I'm on the right track

(defmacro flow
  "Defines a flow"
  {:style/indent :defn}
  [description & flows]
  (when-not (string-expr? description)
     (throw (IllegalArgumentException. "The first argument to flow must be a description string")))
  (let [flow-meta     (meta &form)
        flows'        (or flows `[(m/return nil)])
        subflow-lines (map (fn [f] `(push-meta "" ~(meta f)))
                           flows')
        ;; add line meta info before each step in a flow body
        flows''       (interleave subflow-lines
                                  flows'
                                  (repeat `pop-meta))]
    `(m/do-let
      (push-meta ~description ~flow-meta)
      [ret# (m/do-let ~@flows'')]
      pop-meta
      (m/return ret#))))

We don't have the step where it happened like we do with failed assertions. Instead we just have the flow name.

The stack trace in the gist points directly to the problem, which is an NPE caused on line 6. I find that much more precise and useful than "line 13", from where the step was invoked.