Use refs and STM when several in-process identities must change together, and keep each dosync transaction small, pure, and focused on one invariant.
Refs are Clojure’s coordinated state references. They are useful when several independent identities must change as one logical unit.
For Java engineers, refs are closer to database transaction thinking than lock thinking. You express the state transition inside dosync; Clojure’s software transactional memory (STM) gives the transaction a consistent view and commits the changes together.
1(def checking (ref 100M))
2(def savings (ref 50M))
3
4(dosync
5 (alter checking - 10M)
6 (alter savings + 10M))
The practical rule is the same throughout this section: keep transactions pure. Do not put I/O, randomness, email, logging side effects, or Java object mutation inside work Clojure may retry.