5 ms·
We've used Clojure in production for years. 1. "Has clojure.spec worked out in terms finding bugs during refactoring/maintenance and general QA?" - Spec worked
by badsavage 8y ago
We've used Clojure in production for years.
1. "Has clojure.spec worked out in terms finding bugs during refactoring/maintenance and general QA?" - Spec worked out as a much more useful library than we expected. You could describe any data structures with it, then validate, generate, regenerate it. I think spec is a must have for any Clojure programmer from 2018.
2. "Do you make use of the Lispy-ness"
Macros are super useful sometimes, but in general we try to avoid them, because we prefer to solve everything with just pure functions.
Homoiconicity and the "code is data" aspect are must haves in any programming language after you realised their power.
3. "is it generally an anti-pattern to use these language features in daily development?" macros are feel like cheating sometimes, and we fear the consequences, but homiconicity is useful for us on a daily basis.
4. "Do you wish you had static types?" We prefer to create our own "types" up to complex data structures. A built-in type system seems like a downgrade from here.
5. "I often have the feeling that I'm not smart enough to use Lisp." I think you are just scared from the unknown, Clojure is an alien technology compared to most of the currently popular languages.
Any kids could learn programming in Clojure due to its simplicity and the REPL driven workflow. Its an interactive experience and very likeable.
- pvinis 8y agoCan you elaborate a bit on your own "types"? I am very interested and intrigued.
- badsavage 8y agoYes, I could show you a simple example: Let's create our own 78 digits long string type: (def hex-digit (set "0123456789")) (defn hex-digit? [x] (contains? hex-digit x)) (defn hex-str? [s] (every? hex-digit? (seq s))) (s/def ::hash (s/and hex-str? #(= (count %) 78))) ::hash is now registered, now we go to the REPL: (s/valid? ::hash "23179372") ;;=> false (s/valid? ::hash "nope93721907914920047210715459933122004671648400678953445710500236944435987060") ;;=> false (s/valid? ::hash "231793721907914920047210715459933122004671648400678953445710500236944435987060") ;;=> true That's cool, but we want to generate too: (defn hex-str-gen [n] (let [digit (g/elements hex-digit)] (g/fmap clojure.string/join (g/vector digit n)))) (s/def ::hash (s/with-gen (s/and hex-str? #(= (count %) 78)) #(hex-str-gen 78))) We extended our ::hash spec with a generator function, so we can do this now: (g/generate (s/gen ::hash)) ;;=> "310584715385467847758653938894742415543975445356609397864862925839413265904779" (+ Pro tip: you could spec functions too) Learn more about spec here: https://clojure.org/guides/spec https://clojure.org/guides/spec
- cube2222 8y agoCould you describe examples of using homoiconicity daily?
- badsavage 8y ago90% of our codebase is in databases. Less than 10% belongs to namespaces and being compiled after you boot up the system. This is not a conventional way at all. It would be really hard to explain properly, but I have a simple example for you: The REPL It means: Read -> Eval -> Print -> Loop and is a very basic and common thing that relies on homoiconicity, haha
- Naomarik 8y ago90% of codebase in database? I've never heard of this before. I'm extremely curious, could you explain more? What are the tradeoffs and why did you guys go with this approach for the problem you're solving?