内容简介:This guide is aimed to the developer who’s interested in Clojure and want to install it and start using it right away.It will cover the installation of Clojure, some of the build tools and how they work, the configuration of an editor, of the REPL and a sm
This guide is aimed to the developer who’s interested in Clojure and want to install it and start using it right away.
It will cover the installation of Clojure, some of the build tools and how they work, the configuration of an editor, of the REPL and a small hello world demonstrating how things like build, and test works.
If you’re new to Clojure, at the end of this guide you should be able to start your project.
Table of contents
- Playing with the REPL from your IDE
- Clojure 101 in 5 minutes
- Project specific steps
- Where to go from here?
Installing
Java
First you’ll need to make sure that Java is installed on your computer, you can run a Terminal and run the following command to check if it’s already installed:
java -version
You’ll need at least Java 8, but you can install Java 11, Java 12 or even Java 13.
If you don’t have Java, or want to upgrade it you can either go download it directly from the Oracle website, or you can use Adopt OpenJDK and select the version that you wish to install.
Once you installed or upgraded java run again java -version
in your terminal to check that it’s been correctly installed, for example this is a sample output after having downloaded and installed Java 11 (here in Ubuntu via Windows SubLinux) :
$ java -version openjdk version "11.0.5" 2019-10-15 OpenJDK Runtime Environment (build 11.0.5+10-post-Ubuntu-0ubuntu1.118.04) OpenJDK 64-Bit Server VM (build 11.0.5+10-post-Ubuntu-0ubuntu1.118.04, mixed mode, sharing)
Clojure Tooling
There are different Clojure tools that you can use to build your project.
- Clojure CLI + tools.deps
- Leiningen
- Boot
You can use the one you want.
Hey I’m new to Clojure and you want me to make a choice? Seriously?
I agree with you, humble imaginary visitor.
In this guide I will cover tools.deps , and we’ll also install Leiningen so that you have it on your system when you need to, and because I’ve never used Boot myself even if I’ve heard good things about it, you can try it if you want.
From my point of view you should start with tools.deps because I feel like the community is really invested in it right now, and they are building some cool stuff .
Nevertheless it helps knowing how Leiningen works because you’ll find a lot of projects using it. But for your project just stick with one of the alternative, don’t try to mix the two.
Edit:I’ve just found this article What are the clojure tools which goes into more details regarding how the Clojure CLI & tools.deps actually work, so read it later if you need to know more about it.
MacOS
You can install Clojure using homebrew :
First update your brew, then install Clojure CLI, and verify that it works:
$ brew update $ brew install clojure/tools/clojure $ clj Clojure 1.10.1 user=> (println "Hello, world!") Hello, world! nil user=>
With these 3 commands you have Clojure CLI + tools.deps already installed.
Now let’s install Leiningen, you just need to download the lein script make it executable and put it somewhere on your disk.
I personally install all my dev tools in ~/dev/tools/
, but you can install it wherever you want like in /usr/local/bin/
, for example
$ curl https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein > lein $ sudo mv lein /usr/local/bin/lein $ sudo chmod +x /usr/local/bin/lein $ lein version Leiningen 2.9.1 on Java 11.0.5 OpenJDK 64-Bit Server VM
Linux + Windows
On WindowsI personally use the Windows Sub Linux (WSL), I chose the Ubuntu distribution but you can take anyone you prefer, then open your Ubuntu terminal and follow the steps.
You can install Clojure by downloading an installer from the clojure.org website
$ curl -O https://download.clojure.org/install/linux-install-1.10.1.536.sh $ chmod +x linux-install-1.10.1.536.sh $ sudo ./linux-install-1.10.1.536.sh $ clj Clojure 1.10.1 user=> (println "Hello, world!") Hello, world! nil user=>
Now you have Clojure CLI + tools.deps installed correctly.
To install Leiningen, you’ll do the same as on Mac OS X
$ curl https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein > lein $ sudo mv lein /usr/local/bin/lein $ sudo chmod +x /usr/local/bin/lein $ lein version Leiningen 2.9.1 on Java 11.0.5 OpenJDK 64-Bit Server VM
IDE
Now that Clojure is installed, let’s write some code using your IDE and the REPL integration.
Obviously I cannot explain how every IDE / text editor works with Clojure, I’m not a Emacs or Atom user, I do use mainly IntelliJ, but I’ve used VSCode extensively also.
As with the Linux distribution, you can chose to use the editor you like most, like Emacs, or Vim + fireplace, or Sublime or any other you can find.
This is why I will cover both IntelliJ and VSCode in this guide.
IntelliJ + Cursive
Since I’m from the Java world, I’m used to IntelliJ and the Cursive plugin for Clojure development.
If you don’t have IntelliJ installed, just grab a version, the community version is free and works fine with Cursive, otherwise just follow the steps for VS Code below.
Run the installer then run IntelliJ.
Type Shift Shift
then type Plugins
then Enter
or you can go to File > Settings... > Plugins
.
In the Plugins window type Cursive
and then install it, finally restart the IDE, you’ll be good to go for the next section.
VSCode + Calva
Regarding VSCode, you can use the Calva plugin, to install it you just run VSCode and the go to the Extension market place, search for Calva
and then install it, you’re good to go.
Playing with the REPL from your IDE
The Clojure REPL is fantastic , and I urge you to make it part of your work-flow right from the beginning.
If you want a demo of how the REPL can help you write your code when you know how to use it (and it’s quick to get going), just take a look at What makes a good REPL? from Valentin Waeselynck .
Note: for this part I will cover opening a project based on tools.deps, but the IDE support opening Leiningen projects also, and it doesn’t affect the REPL in any way.
There are two ways to work with the REPL, either you run a REPL from the command line, and then you attach your IDE to it, or you run a REPL directly from your IDE.
I usually chose the first solution using nREPL and then attach my Cursive within IntelliJ to it. We’ll see both solutions for both of the IDE and how we can do some trivial things with the REPL to get you going.
In order to have the same little project to test from both IDE, let’s just create a simple file named deps.edn
and put the following content in it.
{:paths ["resources" "src"] :deps {org.clojure/clojure {:mvn/version "1.10.1"} nrepl/nrepl {:mvn/version "0.5.3"}}}
Then create a simple file named src/playground.clj
with the following content:
(ns playground) (+ 40 2)
Ok, we’re good to go.
IntelliJ + Cursive
Importing this project in IntelliJ
Just go through File > Open
and select the directory where you’re working, then open as a New Project.
IntelliJ will open a new window with your project.
Now let’s see how to use the REPL from within IntelliJ.
Run a REPL from your IDE
Click the Add Configuration… button next to the green hammer.
Then click the + button and chose Clojure REPL > Local
, in the new Run/Debug Configurations window name it Local REPL and click OK.
Now instead of the Add Configurations button, select Local REPL and click run.
You can evaluate Clojure from the text editor in the bottom right (where I wrote (println "Hello, world!")
then press Enter
.
You can also directly evaluate forms from your editing, for example place your cursor at the end of (+ 40 2)
and press Alt + Shift + P
.
For example type a new Clojure code (map inc [0 1 2 3])
put your cursor at the end, then press Alt + Shift + P
it will send it for evaluation into the REPL, which will respond with => (1 2 3 4)
.
Now in the text editor in the bottom right, type (map inc *1)
then press Enter
, it will output => (2 3 4 5)
. Because in the REPL, *1
means the last evaluated result.
Cursive let’s you load a file to the REPL ( Alt + Shift + L
), synchronize the files to the REPL ( Alt + Shift + M
), switch the REPL to the current namespace you’re editing ( Alt + Shift + R
).
I’ll let you play with the different options that you can find in the Tools > REPL
menu.
Attach to a running REPL
In order to attach to a REPL you must have one running elsewhere, if you followed the section above, stop the REPL by clicking the red square.
Now in a terminal go to the directory where your code is located then type the following.
$ clj -m nrepl.cmdline nREPL server started on port 63812 on host localhost - nrepl://localhost:63812
Take a look at the port on which nREPL is running, for me it was 63812
.
In IntelliJ, click the Add Configuration… button next to the green hammer.
Then click the + button and chose Clojure REPL > Remote
, in the new Run/Debug Configurations window name it Remote REPL , select nREPL then type localhost
for the host and 63456
for the ** port**, finally click OK.
Now instead of the Add Configurations button, select Remote REPL and click run.
As for the previous section you can evaluate into the remote REPL as if it was running locally. A remote REPL has advantages, you could imagine that you connect to a running REPL in production and check what’s going on live.
VSCode + Calva
Importing this project in VSCode
In VSCode, just go to Open > Folder
, select the folder where your code is located and click OK.
Run a REPL from your IDE
Right click in the editor and select Jack-in or Connect to REPL Server
Select Start a REPL server and connect (a.k.a Jack-in) , then select Clojure CLI .
Like Cursive in IntelliJ, it will display a REPL on the right side of your IDE, where you can evaluate Clojure forms.
You can select a form using Ctrl + Alt + C, Ctrl + S
, and evaluate it using Ctrl + Alt + C V
, the result is directly appended next to your form in your IDE.
Calvahas plenty of shortcuts like loading the current file in the REPL ( Ctrl + Alt + C Enter
), load the current namespace in the REPL ( Ctrl + Alt + C, Ctrl + Alt + N
).
I’ve lost my finger muscle memory regarding the default shortcuts on Calva, but I think they can be customized to your need (I’m more of a Cursive guy).
If you want to disconnect from the REPL, just right click then select Disconnect from the REPL server .
Attach to a running REPL
Right click in the editor and select Jack-in or Connect to REPL Server
This time select Connect to a running REPL server in your project then Clojure CLI then type localhost:63812
if your previous REPL is still running, otherwise run it again and get the actual nREPL port.
Accept by pressing Enter
and you’re good to go (see the green text saying REPL connected. ).
All right you’re now ready to rock!
Clojure 101 in 5 minutes
Tables | Cool |
---|---|
Numbers | Integers, doubles, floats, fractions |
String | "foo" |
Character | \A |
Keyword | :foo |
List | '(1 2 3) |
Vector | [1 2 3] |
Map | {:name "Alex" :age 35} |
Sets | #{1 2 3} |
Regexp | #"\d+" |
Variable | (def foo 123) |
Function | clojure (defn add [a b] (+ a b) |
Anonymous function | (fn [a b] (+ a b)) |
Also more concise | #(+ %1 %2) |
Java | JavaScript | Clojure | |
---|---|---|---|
String | "foo" |
"foo" or 'foo' |
"foo" |
Boolean | true , false |
true , false |
true , false |
Nothing | null |
null |
nil |
Keywords | Nope | Nope | :name |
Numbers | 1 |
1 |
1 |
Decimals | 1.2 |
1.2 |
1.2 |
Comments | //comment |
//comment |
; comment |
Regexp | "\\d+" |
/\d/ |
#"\d+" |
Arrays/Vectors | new int[] {1, 2, 3} |
[1, 2, 3] |
[1 2 3] |
Maps | Map.of("one", 1, "two", 2) |
{one: 1, two: 2} |
{:one 1 :two 2} |
Sets | Set.of(1, 2, 3) |
new Set(1, 2, 3) |
#{1 2 3} |
Functions | int sum(int x, int y) { return x + y; } |
function sum(x, y) { return x + y; } |
(defn sum [x y] (+ x y)) |
Shorthand | sum = (x, y) -> x + y; |
const sum = (x, y) => x + y; |
(def sum #(+ %1 %2)) |
Function call | sum(1, 2) |
sum(1, 2) |
(sum 1 2) |
Project specific steps
I want to build my project
Note: for this example I just created an src
folder, but you’ll often see src/main/clojure
deriving from Maven standard directory layout, in such a case you just need to change the path in deps.edn
.
Let’s say you have written a super program which SHOUT the text you’re giving to it.
(ns playground (:require [clojure.string :as str]) (:gen-class)) (defn shout [text] (as-> (seq text) $ (interpose \ $) (concat $ (repeat 3 \!)) (apply str $) (str/upper-case $))) (defn -main [& args] (->> args (map shout) (apply str) println))
You can run it with the clj
utility:
$ clj -m playground "Clojure is fun" C L O J U R E I S F U N!!!
But we’d like to build this to a fat JAR (some call them uber JAR also). A fat JAR is a Java Archive (a zip) containing all the needed dependencies so that you just have to call the java
executable on it to execute the code it contains.
We call them Jean-Michel at work since years, because of Jean-Michel Jarre . Hey, t’as buildé le Jean-Michel ?
There are multiple tools which can do it in Clojure land, but we’ll be using uberdeps by Nikita Tonsky, one of the Clojure community that you should definitely follow, but you’ll see more at the end of this article.
Modify your deps.edn
file to add uberdeps :
{:paths ["resources" "src"] :deps {org.clojure/clojure {:mvn/version "1.10.1"} nrepl/nrepl {:mvn/version "0.5.3"}} :aliases {:fatjar {:extra-deps {uberdeps {:mvn/version "0.1.10"}} :main-opts ["-m" "uberdeps.uberjar" "--target" "target/shout-0.1.jar"]}}}
Essentially we’re just adding an alias named fatjar that needs an extra dependency uberdeps
and which command line to run is clj -m uberdeps.uberjar --target target/shout-0.1.jar
.
In order to run an alias you have to use clj -A{alias-name}
, so just do it like this, and then run the JAR:
$ clj -Afatjar Downloading: uberdeps/uberdeps/0.1.10/uberdeps-0.1.10.pom from https://repo.clojars.org/ Downloading: org/clojure/tools.deps.alpha/0.8.677/tools.deps.alpha-0.8.677.pom from https://repo1.maven.org/maven2/ ... [uberdeps] Packaging target/shout-0.1.jar... + resources/** + src/** + nrepl/nrepl 0.5.3 . nrepl/bencode 1.0.0 + org.clojure/clojure 1.10.1 . org.clojure/core.specs.alpha 0.2.44 . org.clojure/spec.alpha 0.2.176 [uberdeps] Packaged target/shout-0.1.jar in 572 ms $ java -cp target/shout-0.1.jar clojure.main -m playground "Clojure is fun" C L O J U R E I S F U N!!!
Working as expected, now you can just send your JAR to anyone having Java 8+ installed, and they can use it. How cool!
And tests? Everyone say tests are great and all
Like for the fat JAR, just add an alias to your deps.edn
so that we can use kaocha from lambdaisland (one more to follow) as a test runner.
{:paths ["resources" "src"] :deps {org.clojure/clojure {:mvn/version "1.10.1"} nrepl/nrepl {:mvn/version "0.5.3"}} :aliases {:test {:extra-paths ["test"] :extra-deps {lambdaisland/kaocha {:mvn/version "1.0-612"}} :main-opts ["-m" "kaocha.runner"]} :fatjar {:extra-deps {uberdeps {:mvn/version "0.1.10"}} :main-opts ["-m" "uberdeps.uberjar" "--target" "target/shout-0.1.jar"]}}}
Now just create a test
directory, and add a file named playground_test.clj
write a simple test:
(ns playground-test (:require [clojure.test :refer :all] [playground :refer :all])) (deftest shouting (is (= "H E L L O!!!" (shout "hello"))))
Note that the file is named playground_test with an underscore but the namespace is named playground-test with a dash .
Then run kaocha with clj
and your newly created test
alias.
$ clj -Atest [(.)] 1 tests, 1 assertions, 0 failures.
Great we have created a powerful test, and we can now ensure our program works before building it and send it to friends!
I’m a beginner, I make mistake, is there something to help me?
You can use a linter. In Clojure there are plenty of options, but the most recent is clj-kondo by Michiel Borkent (one more to follow).
You can install the binary, or use it directly from your deps.edn
, this is what I will cover below, but don’t hesitate to read the README of clj-kondo.
{:paths ["resources" "src"] :deps {org.clojure/clojure {:mvn/version "1.10.1"} nrepl/nrepl {:mvn/version "0.5.3"}} :aliases {:test {:extra-paths ["test"] :extra-deps {lambdaisland/kaocha {:mvn/version "1.0-612"}} :main-opts ["-m" "kaocha.runner"]} :fatjar {:extra-deps {uberdeps {:mvn/version "0.1.10"}} :main-opts ["-m" "uberdeps.uberjar" "--target" "target/shout-0.1.jar"]} :kondo {:extra-deps {clj-kondo {:mvn/version "RELEASE"}} :main-opts ["-m" "clj-kondo.main"]}}}
For the purpose of the article, modify the playground.clj
to add an unused binding:
(ns playground (:require [clojure.string :as str]) (:gen-class)) ; ... (defn -main [& args] (let [foo "foo bar"] (->> args (map shout) (apply str) println)))
Then run clj-kondo:
$ clj -Akondo src/playground.clj:13:9: warning: unused binding foo linting took 60ms, errors: 0, warnings: 1
You’ll notice that clj-kondo took 60ms to execute, but it took more than that to execute clojure and everything related, that’s why clj-kondo can also be installed as a native binary.
Let’s install it, and run it to see that the execution is instant .
$ bash <(curl -s https://raw.githubusercontent.com/borkdude/clj-kondo/master/script/install-clj-kondo) $ clj-kondo --lint src src/playground.clj:13:9: warning: unused binding foo linting took 9ms, errors: 0, warnings: 1
That seems about very usable directly from your IDE, you can achieve this by following the great guide on the clj-kondo GitHub wiki.
Is there any way my code looks the same everywhere?
Sure use a code formatter, they are built-in your IDE, in IntelliJ I belive it’s Ctrl + Alt + L
(or Menu > Code > Reformat code
), but maybe you want to reformat the code in a git pre-hook?
For this you can use cljfmt
by weavejester (again someone to follow).
Modify your deps.edn
and add both a fmt-fix
and fmt-check
aliases:
{:paths ["resources" "src"] :deps {org.clojure/clojure {:mvn/version "1.10.1"} nrepl/nrepl {:mvn/version "0.5.3"}} :aliases {:test {:extra-paths ["test"] :extra-deps {lambdaisland/kaocha {:mvn/version "1.0-612"}} :main-opts ["-m" "kaocha.runner"]} :fatjar {:extra-deps {uberdeps {:mvn/version "0.1.10"}} :main-opts ["-m" "uberdeps.uberjar" "--target" "target/shout-0.1.jar"]} :kondo {:extra-deps {clj-kondo {:mvn/version "RELEASE"}} :main-opts ["-m" "clj-kondo.main" "--lint" "src"]} :fmt-fix {:extra-deps {com.jameslaverack/cljfmt-runner {:git/url "https://github.com/JamesLaverack/cljfmt-runner" :sha "97960e9a6464935534b5a6bab529e063d0027128"}} :main-opts ["-m" "cljfmt-runner.fix"]} :fmt-check {:extra-deps {com.jameslaverack/cljfmt-runner {:git/url "https://github.com/JamesLaverack/cljfmt-runner" :sha "97960e9a6464935534b5a6bab529e063d0027128"}} :main-opts ["-m" "cljfmt-runner.check"]}}}
Now modify the playground.clj
to make it look weird on purpose.
(ns playground (:require [clojure.string :as str]) (:gen-class)) (defn shout [text] (as-> (seq text) $ (interpose \ $) (concat $ (repeat 3 \!)) (apply str $) (str/upper-case $))) (defn -main [& args] (let [foo "foo bar"] (->> args (map shout) (apply str) println)))
And run cljfmt
:
$ clj -Afmt-check src/playground.clj has incorrect formatting --- a/mnt/c/temp/starter/src/playground.clj +++ b/mnt/c/temp/starter/src/playground.clj @@ -4,14 +4,14 @@ (defn shout [text] (as-> (seq text) $ - (interpose \ $) + (interpose \ $) (concat $ (repeat 3 \!)) - (apply str $) - (str/upper-case $))) + (apply str $) + (str/upper-case $))) (defn -main [& args] - (let [foo "foo bar"] + (let [foo "foo bar"] (->> args - (map shout) + (map shout) (apply str) - println))) + println))) No such file: project.clj
Pretty neat, now ask cljfmt to fix it:
$ clj -Afmt-fix src/playground.clj Reformatting src/playground.clj
Done, your code looks like normal again:
(ns playground (:require [clojure.string :as str]) (:gen-class)) (defn shout [text] (as-> (seq text) $ (interpose \ $) (concat $ (repeat 3 \!)) (apply str $) (str/upper-case $))) (defn -main [& args] (let [foo "foo bar"] (->> args (map shout) (apply str) println)))
This is using cljfmt-runner for deeper integration with tools.deps.
Clojure core library is so full of awesome bits, sometimes I forget them
Of course Clojure comes with batteries included, really included, even in years you’ll discover some gems, but for a starter you can lean on kibit which will inspect your code and propose you some ways you can improve it with built-in function you forgot existed.
Modify your playground.clj
to look like this:
(ns playground (:require [clojure.string :as str]) (:gen-class)) (defn handle-empty [s] (if (nil? s) (seq "Please talk to me") s)) (defn shout [text] (as-> (seq text) $ (handle-empty $) (interpose \ $) (concat $ (repeat 3 \!)) (apply str $) (str/upper-case $))) (defn -main [& args] (->> (or args [""]) (map shout) (apply str) println))
Test it still works:
$ clj -m playground "Hello" H E L L O!!! $ clj -m playground "" P L E A S E T A L K T O M E!!! $ clj -m playground P L E A S E T A L K T O M E!!!
You can also add a test to your playground_test.clj
(ns playground-test (:require [clojure.test :refer :all] [playground :refer :all])) (deftest shouting (is (= "H E L L O!!!" (shout "hello")))) (deftest shouting-empty (let [expected "P L E A S E T A L K T O M E!!!"] (is (= expected (shout nil))) (is (= expected (shout "")))))
Then run the tests:
$ clj -Atest [(...)] 2 tests, 3 assertions, 0 failures.
Ok let’s get back to kibit .
Add it to your deps.edn
like this:
{:paths ["resources" "src"] :deps {org.clojure/clojure {:mvn/version "1.10.1"} nrepl/nrepl {:mvn/version "0.5.3"}} :aliases {:test {:extra-paths ["test"] :extra-deps {lambdaisland/kaocha {:mvn/version "1.0-612"}} :main-opts ["-m" "kaocha.runner"]} :fatjar {:extra-deps {uberdeps {:mvn/version "0.1.10"}} :main-opts ["-m" "uberdeps.uberjar" "--target" "target/shout-0.1.jar"]} :kondo {:extra-deps {clj-kondo {:mvn/version "RELEASE"}} :main-opts ["-m" "clj-kondo.main" "--lint" "src"]} :fmt-fix {:extra-deps {com.jameslaverack/cljfmt-runner {:git/url "https://github.com/JamesLaverack/cljfmt-runner" :sha "97960e9a6464935534b5a6bab529e063d0027128"}} :main-opts ["-m" "cljfmt-runner.fix"]} :fmt-check {:extra-deps {com.jameslaverack/cljfmt-runner {:git/url "https://github.com/JamesLaverack/cljfmt-runner" :sha "97960e9a6464935534b5a6bab529e063d0027128"}} :main-opts ["-m" "cljfmt-runner.check"]} :kibit {:extra-deps {tvaughan/kibit-runner {:mvn/version "0.1.0"}} :main-opts ["-m" "kibit-runner.cmdline"]}}}
And run kibit
$ clj -Akibit At ./src/playground.clj:15: Consider using: (clojure.string/join $) instead of: (apply str $)
Kibitcan also report the changes to be made in Markdown
$ clj -Akibit -- --reporter markdown ---- ##### `./src/playground.clj:15` Consider using: ```clojure (clojure.string/join $) ``` instead of: ```clojure (apply str $) ```
And you can ask it to replace with what it thinks best alone (add --interactive
for an interactive terminal session)
$ clj -Akibit -- --replace Replacing (apply str $) with (clojure.string/join $) in ./src/playground.clj:15
Now your code looks like this
(ns playground (:require [clojure.string :as str]) (:gen-class)) (defn handle-empty [s] (if (nil? s) (seq "Please talk to me") s)) (defn shout [text] (as-> (seq text) $ (handle-empty $) (interpose \ $) (concat $ (repeat 3 \!)) (clojure.string/join $) (str/upper-case $))) (defn -main [& args] (->> (or args []) (map shout) (apply str) println))
Awesome, isn’t it?
Where to go from here?
Now that your IDE is configured and you have some tooling ready to rock some code, how do you start your Clojure journey?
I’ll link to you some website and tutorials to read, and also people to follow.
Websites
- Clojure Distilled : Awesome introduction to the language, a must read if you start, by yogthos.
- Clojure for the Brave and True : Learn the ultimate language and become a better developper
- Clojure from the ground up : Deep introduction by Aphyr
- Clojure Collections : Courses on Clojure collections by Eric Normand
- Clojure by example : A cool website also
- Clojuredocs : the obligatory website to find functions
- The Clojure Toolbox
- Rich Hickey fan club : every time I watch one of his talks I feel like someone has gone in and organized my brain
- So much more, I can’t list them all…
Social
- r/Clojure : The Clojure sub-reddit
- Clojurians : A Slack channel
- #Clojurians also on Discord
Conferences
- Clojure/north
- :clojureD
- IN/Clojure
- ClojuTRE
- Clojure/conj
Follow
- Arne Brasseur - @plexus
- Chris Houser - @chrishouser
- Christophe Grand - @cgrand
- David Nolen - @swannodette
- Derek Troy-West - @_d_t_w
- Dmitri Sotnikov - @yogthos
- Eric Normand - @ericnormand
- James Reeves - @weavejester
- Kyle Kingsbury - @aphyr
- Lambda Island - @lambdaisland
- Michael Fogus - @fogus
- Nikita Tonsky - @nikitonsky
- Peter Taoussanis - @ptaoussanis
- Planet Clojure - @planetclojure
- Russ Olsen - @russolsen
- Val Waeselynck - @val_waeselynck
- You can also follow me, I’m not in the same league but I tweet regularly about Clojure - @algrison
- and a lot of others of course…
Last word
Clojure is awesome, there’s even love letters written to it, the community is fantastic, the projects are of great quality.
I’ve been doing Clojure for around 6 years, that’s my favorite language, it made me learn a lot, and changed how I program in other languages (my primary language at work being Java).
I hope you’ll enjoy your Clojure journey, this is just the beginning ❤
Until next time!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。