{Make an onion}

Refactoring techniques to turn your Clojure code into an onion

WORK IN PROGRESS

  • Proposal by Jeffrey Palermo
  • Software layers like an onion
  • Layers can only talk to deeper layers
  • Infra,I/O, UI, Tests form outer layer

Onion?!?

Refactoring Techniques

Separate calculations from side-effects

Flatten deep call trees

Declarative queries

Declarative effects

Separate calculations from side-effects

(defn update-customer-email [customer-id new-email]
  (let [customer (-> (db/load-customer customer-id)      ;; I/O
                     (assoc :email (str/trim new-email))];; calculation
      (db/save-customer customer)))                      ;; I/O
# PRESENTING CODE

How to test this?

(deftest test-update-customer-email []
  (with-redefs [db/load-customer (constantly {:name "Han Solo" :email "han@solo.net"})
                db/save-customer #(is (= "han.solo@rebels.net" (:email %1))]
              (update-customer-email "id" "han.solo@rebels.net"))))
             
             

Not a good test. It can't treat `update-customer-email` as a black-box and needs to understand what to re-define.

If `update-customer-email` uses a different `db` fn, the test will break.

Code

By Jochen Bedersdorfer

Code

  • 102