5 ms·
Clojure was one of the first languages I picked up when I started coding and I really enjoyed using it. The instarepl in Light Table was a huge boon for learnin
by muraiki 11y ago
Clojure was one of the first languages I picked up when I started coding and I really enjoyed using it. The instarepl in Light Table was a huge boon for learning and helped to offset the infamous Clojure stack traces of doom. :) However, I'd be very much interested in hearing more from people who have gone from Java, C#, or another statically typed language to Clojure, particularly in regards to designing, maintaining, and refactoring large codebases.
I don't mean to turn this into yet another static vs dynamic flamewar. I'm just very interested in the patterns that professional Clojure programmers use to help manage this complexity. I know that code in Clojure is normally structured very differently than one would find in a more imperative or OO language, whether dynamic or static. I also realize there are things available, such as Prismatic Schema and Typed Clojure, to assist with these problems.
Really, I'd love to come back to Clojure but the problems I run into in my day job often have me thinking, "types would have made this so much easier." :( As a result, I haven't given Clojure the time to really delve deeply into it. As someone with limited time to try out whole new languages, I'd love to be convinced to go further!
- evanspa 11y agoSo I worked exclusively in the statically typed (and imperative / OO) world for the first 10 years of my professional career. Several years ago I decided to learn functional programming. I started with Scheme and moved to Clojure. I really enjoy Clojure; it's a real joy coding in it using Emacs with paredit (or smartparens). I wrote a REST API using Clojure; the code also has to interact with a Postgres database. This is for a side project, but it's not a trivial code base. I definitely miss Java/Eclipse style refactoring (right-click, rename, and EVERYTHING is properly updated). Can't do that in Clojure. Also, I find that I have to write more unit tests with Clojure in order to make up for the fact the compiler can't help me. Not that I wouldn't write tests in Java; but I find I have to write more in Clojure to keep the codebase manageable. So again, for me, I use unit testing to make up for the fact I don't have the compiler helping me as much.
- puredanger 11y agoThe Cursive IntelliJ IDE for Clojure does allow you to rename everything in this manner (even keywords used across your codebase). Others may as well, not sure.
- Hupriene 11y agoclj-refactor is coming along quite nicely... https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-rename-symbol https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-r...
- dkersten 11y agoProperty-based/generative testing should, at least hypothetically, reduce the amount of tests you need to write.
- evanriley 11y agoDo you have any books/resources that you recommend to learn Clojure?
- puredanger 11y agoLots of good links here: http://clojure.org/community/resources http://clojure.org/community/resources
- muraiki 11y agoI strongly recommend http://www.braveclojure.com/ http://www.braveclojure.com/
- kirang1989 11y agoSecond this. Definitely a good beginner's book.
- sova 11y agoClojure is amazing. Definitely start lurking in the Clojure IRC channel, I learned a lot just reading other peoples' questions and answers in there. There is a great book, The Joy of Clojure. Highly recommend it. For specific projects there is also a bigger book, it's more of a reference (like if you wanted to make a website using Ring) called Clojure Programming (it's got a Dodo on the cover and a purple bar).
- retrogradeorbit 11y agoThe Joy of Clojure is the best book on Clojure I have read (and I've read about 5 of the main ones), but its certainly not a beginners book. Read Joy of Clojure when you want to deep dive into the detail and the really powerful aspects of the language. For people who have been using Clojure for a while, I highly recommend reading it.
- sova 11y agoI think it is a suitable starting resource for any experienced coder. Also, just to add to the thought, if one navigates to infoq one can see Rich Hickey's talks and in it he describes not only a philosophy of an anciently-refreshed-language (lisp a la clojure beauty), but he also talks of some beautiful principles in general. For example, he mentions how when we talk about a River or a Stream, we are not really talking about an object, because there is no section you can block off and say "hey this is the river" due to it changing moment by moment. Yet, for convenience we use the conventional term "river" and it's understood. He also has this one line "the great thing about a hammock is that you can lay in one with your eyes closed and no one will bother you because they think you're sleeping." He totally helped me wake up to the way a coder can really live a fulfilling life, and how the organization/ideation/creation of a digital experience ("application") can happen (and in fact, happens better) away from the computer. Without distraction, with your own balance, it's much easier to focus ones mind. He's truly a great learner and teacher and watching even one talk by him would do anyone interested in Clojure, or the philosophy of coding (if I may call it so) much good.
- anthonybsd 11y ago>Really, I'd love to come back to Clojure but the problems I run into in my day job often have me thinking, "types would have made this so much easier." I've gone back and forth on this one during the course of my career. My first professional language was Borland Delphi (strongly typed), then C (weakly typed), then Perl (dynamic), then Java (mostly strongly typed), Scala (very strongly typed) and now I'm slowly trying to adopt Clojure at my place of work. Out of all those the worst kind of code I've ever come across was in Perl, so for awhile I've blamed the lack of typing as a contributing factor to this. However. Most of the Python code I've seen since around 2001 has been fairly clean looking so that can't just be dynamic typing that was to blame. I suspect Perl's woes had more to do with the "there is more than one way to do it philosophy" as opposed to types. There's just no such thing as idiomatic Perl. In fact I'm seeing some of this in some Scala code. There are nearly-religious level wars around what constitutes idiomatic Scala way of doing things. I've seen completely insane spaghetti-style Scala classes, especially those that dealt with XML code and DSLs. So far, it seems that Clojure in Java ecosystem is more like Python than like Perl. I.e. only one way of doing things that is fairly clear from the onset.
- muraiki 11y agoThanks for your response. Most of my professional work is in Perl, except for frontend stuff in JS, although we are increasingly using Go for more things. I'm lucky in that our Perl codebase is very well structured and clean, despite having parts up to 20 years old. It relies very little on objects, generally passing around hashes of information. For error handling we even use something akin to the Either type, instead of using exceptions. But yeah, you could go into another Perl codebase and see a completely different story. I guess that I really lucked out! Anyway, when I walked into this Perl codebase I generally didn't feel too far away from Clojure in terms of its basic setup, creating lots of small functions that accept and produce basic data structures. But where I do feel pain is in safely refactoring that code, getting insight into where things are used, and understanding what might happen to be in this plain old hash being passed around. It's at this point that I miss having good tooling, in the sense of the tooling I've experienced in Go or Scala. The only dynamic language I've used with comparable tooling is Smalltalk, but unfortunately that's not really viable professionally at this time. :( I've heard good things about Cursive Clojure, so perhaps I should give it a try and see what fancy features it has.
- retrogradeorbit 11y agoThe way I approach it is to make use of the Design By Contract features Clojure took from Eiffel. I almost never want to restrict an input to a function to a specific type or interface. I want it to conform to some kind of contract. So you build the :pre clause to reflect what kind of input you want. Sometimes I add a :post clause to ensure the function has performed correctly. What does annoy me though (and you can see it clearly reflected in the survey respondents putting such a weight on better error messages) is the way assertions don't give me a traceback (or file name and line number of the assertion). http://blog.fogus.me/2009/12/21/clojures-pre-and-post/ http://blog.fogus.me/2009/12/21/clojures-pre-and-post/
- hellofunk 11y agoRuntime assertions (like the :pre clause) are the only way to really do this in a dynamic language, but they are merely a band-aid, and suffer these problems: 1) You have to actually write the assertion/:pre all the time, which is not a trivial step in my opinion. A basic type system just removes this chore altogether. Writing these little assertions really breaks the wonderful flow of elegance. 2) Any errors are only caught with a specific input that would violate the assertion; some inputs might pass, and others not. Therefore, you may not know there is a possible bug that will crash your app or lead to unexpected behavior, even if it runs fine for a long time. 3) You have to keep flipping the assertions switch on and off as you move from testing to deployment, or, just leave them on and suffer the runtime overhead of their checking everything all the time. 4) You will typically write more unit tests to make-up for the tests a type system does for you.
- wotbrew 11y agoI find naming discipline very important in reducing type uncertainty. If I call something 'user' I better be referring to the same thing every time, at least within a single namespace, package or library. As one thing gets more specific, it gets a more specific name. Like a map representing the database record for a user would get `user-record`. For aggregates or abstract things, Its ok to use `m` and `coll` if referring to any map, or any collection. `n` if referring to any number, and so on. But having conventional names like `user-coll` for a collection of users, or `user-set` for a set makes a big difference. It all comes down to reducing the number of things names can mean and therefore improving the likelyhood of your brain inferring the type of an argument, or what a function says it will return. This is something I have gotten better at as I have grown as a Clojure programmer (previously only worked in static languages like C#/F#/Haskell/C etc). I used to just take or return the exact structure I needed without thinking if it was transient or anonymous. I now make sure I can name everything a function takes, and returns. Use constructor functions to reify new domains and name them (nouns), or document them with Prismatic schemas. Hopefully that's not too hand-wavy.