Clojure, the Good Parts
rasterize.io
Clojure, the Good Parts
1–10 of 96 posts
Re: Clojure, the Good Parts
#2Otherwise, lots of great points. One other thing I will say about Schema (https://github.com/plumatic/schema): while it's a lifesaver in a lot of ways, its mere existence really does expose some of Clojure's deficiencies when it comes to the type system (or lack thereof). I'm probably in the minority in the Clojure world but I really wish that it had better static typing and a more sophisticated type system sometimes. I've mostly made my peace with it but once in a while I look longingly at ML-family languages from afar...
Re: Clojure, the Good Parts
#3Pretty good list that I mostly agree with. I think the only point of contention I may have is with using timbre--having tried it in the past, I found it didn't do much that clojure.tools.logging couldn't do for most use-cases, and added configuration complexity while not sparing me the trouble of dealing with logback XML configs and whatnot--Java logging seems to rears its ugly head no matter what you do, especially…
I agree knowledge of how Java logging works is still useful, but I'm not willing to be part of the problem anymore :-)
Agreed on Schema, and how it illustrates deficiencies in the type system. I still want core.typed, or something like it, but it's too immature for production use.
Re: Clojure, the Good Parts
#4* before you decide to use Component, take a look at Mount and see which one suits you better (I settled on mount for both Clojure and ClojureScript and I'm happy so far),
* use Timbre: yes. Definitely. In fact, pretty much anything by Peter Taoussanis will be a good choice (for example, Sente is a wonderful tool for writing client+server apps). If you use Timbre in a mixed Clojure+ClojureScript application, consider sending logging from client-side to server side via Sente. I did and it's fantastic to be able to log something in ClojureScript code and have it appear in your server logs. Just don't overdo it, or you'll be flooded with logs.
* avoid lein plugins: yes, in general. But I still use one, lein-git-version, which names output artifacts using `git describe --tags` and places a version.txt file in resources/. This is difficult to do in any other way.
Re: Clojure, the Good Parts
#5If your doing a new language, you should look into it.
Re: Clojure, the Good Parts
#6Pretty good list that I mostly agree with. I think the only point of contention I may have is with using timbre--having tried it in the past, I found it didn't do much that clojure.tools.logging couldn't do for most use-cases, and added configuration complexity while not sparing me the trouble of dealing with logback XML configs and whatnot--Java logging seems to rears its ugly head no matter what you do, especially…
I'd personally add the potentially controvertial "prefer transducers to lazy sequences." Lazy seq laziness is a big source of errors for newbies, and even for old hands since 1.7 Iterable-backed lazy seqs have surprising chunked realization behavior. Transducers take a bit more up-front effort to gain familiarity, but then yield fewer surprises.
Re: Clojure, the Good Parts
#7Pretty good list that I mostly agree with. I think the only point of contention I may have is with using timbre--having tried it in the past, I found it didn't do much that clojure.tools.logging couldn't do for most use-cases, and added configuration complexity while not sparing me the trouble of dealing with logback XML configs and whatnot--Java logging seems to rears its ugly head no matter what you do, especially…
Author here. I agree, Timbre is new, and has some rough edges, but in my projects, I've found them worth putting up with. In my current project (18k LoClojure), I think the only serious dependency I have that uses j.u.logging or SLF4J is Datomic. Timbre has an interop library that will pipe java logs through timbre. I agree knowledge of how Java logging works is still useful, but I'm not willing to be part of the pro…
Yeah, the post you folks put out on core.typed last fall (https://circleci.com/blog/why-were-no-longer-using-core-type...) was certainly disappointing but not unexpected...I'm curious to see if Jaunt goes anywhere at this point too: https://www.arrdem.com/2016/02/22/clojarr_-_a_friendly_cloju...
Anyways, thanks for the piece!
Re: Clojure, the Good Parts
#8Global atoms provide a good way to confine state into a single place. In my applications they serve as a in-memory database while everything persistent is written to disk in the form of a log (kafka, file append, you name it).
Agents provide a good way to serialise events akin to a transactor. Not every problem requires the parallelism or the concurrency gained by smearing it out into a nondeterministic pile of communicating processes that is a nightmare to test. In those cases having determinism and centralised state is a godsend. I see them as the atoms bigger brother.
In cases where you need some concurrency or parallelism futures are fine. They provide a simpler interface and can even be canceled as first class citizens, unlike CSProcesses which potentially linger around indefinitely without having a first class handle to kill them or see their status.
Core.async is heavily overused. If your application doesn't contain a multitude of moving parts that all need to execute concurrently I wouldn't touch it with a ten feet pole. The go macro is a clojure to continuation passing style compiler, and don't get me wrong it's a marvel of engineering, but it's also a sausage machine that makes code impossible to debug. The fact that processes aren't first class citizens makes it impossible to build erlang style resilient systems, and creates tons of zombie processes when using figwheel. People immediately grab it when building cljs applications even though a log/queue would give them much more reliable performance guarantees, much better debug-ability and better tool compatibility. (Re-Frame for example ditched core.async for their own queue implementation.) (If somebody is sharing that sentiment and looking for a kafka style log for cljs, I wrote one and it's been used in production for a while :) https://gitlab.com/j-pb/franz)
Last but not least, transducers make it onto my list of things to avoid. I'm not sure if they or core.async are clojures million dollar mistake. They are incredibly complex, even brought the spawn of the devil, volatile, into the language. Just for a bit of speedup and core.async integration.
Re: Clojure, the Good Parts
#9Solid advice (I've been writing Clojure for the last 6 years or so and I agree with pretty much everything). I would like to add, however: * before you decide to use Component, take a look at Mount and see which one suits you better (I settled on mount for both Clojure and ClojureScript and I'm happy so far), * use Timbre: yes. Definitely. In fact, pretty much anything by Peter Taoussanis will be a good choice (for e…
But we do take a tip or two from stuartsierra's "Reloadable" work flow (which he based Component on), specifically that there should be no global state, and all dependencies should be passed into functions that need them as a parameter.
In our case, we call it `env` since it's the "environment" that a function runs in or can affect, and contains things like the database connection, email service, etc.
Some of these are records which implement a protocol, so that you can have e.g. LiveEmailService in production and MemoryEmailService in development or while running tests.
All in all, I like and have used some of Stuart's ideas, but not necessarily Component itself. There's strong mindshare for it in the Clojure community right now, and it's tempting to look at it as The Solution™ for almost everyone's use-cases because of that. And the ideas it has are good, but that doesn't always mean it's the best solution for each person.
Re: Clojure, the Good Parts
#10I've recently moved from Component to Mount. It is less powerful but just a vast syntactic overhead reduction.
Absolutely avoid metadata. The worst thing ever is using it like how Reagent does in ClojureScript where it actually provides important program semantics. This is a Terrifically Bad Idea.
Schema is wonderful. Schema is terrible. It is nothing resembling a replacement for static types. The more you use it the more obviously it is deficient for such things.
Absolutely just use Clojure.Test. I don't even understand why this is a question. What is up with cutesy testing APIs?