If my project is using "person" maps with the shape {:firstName :lastName :address}
, and I want to change that shape to {:name {:firstName :lastName} :address}
, what can I do to help ensure that I've made the corresponding changes everywhere these objects are used?
In Java, it's straightforward as anywhere I still have person.firstName would issue a compile error. In Clojure I might not even get a runtime error, but just bad data saved to the server. I assume it's not possible to guarantee correctness, but what is there other than fine-toothed-combs?
Clojure has libraries that provide data definition and validation. For example, you could use https://github.com/Prismatic/schema
Regarding the difficulty of compile-time vs. runtime errors...well, that issue is not unique to Clojure. To quote John Carmack: "The challenge of lisp is getting your program to run, the challenge of Haskell is getting it to compile."
I agree with @noahlz - if you want to be really sure then, you'll have to use a library like the one he's suggested. Large refactoring with maps can be a problem, it's true.
Having said that, you could slightly improve your chances in your case if you used a Record with its constructor function to create your person
(and still retain the good things about maps):
(defrecord Person [name address])
;; Okay. No problem
(def scott (->Person {:firstname "Scott" :lastname "Lowe"}
"23 Hope Street, Edinburgh"))
;; But then...
(def scott (->Person "Scott"
"Lowe"
"23 Hope Street, Edinburgh"))
;; Boom!
ArityException Wrong number of args (3) passed to: user/eval990/->Person--1005
Now this example catches the issue at runtime, and it will obviously only help in some simple cases. But static analysis tools will also pick up on this bug at development time (for example: Clojure plugins like Cursive available for IntelliJ).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With