Slide 1

Slide 1 text

Clojure Linters

Slide 2

Slide 2 text

Self-introduction /laʒenɔʁɛ̃k/ カマイルカ lagénorhynque (defprofile lagénorhynque :name "Kent OHASHI" :languages [Clojure Haskell Python Scala English français Deutsch русский] :interests [programming language-learning mathematics] :contributing [github.com/japan-clojurians/clojure-site-ja])

Slide 3

Slide 3 text

「Clojureをプロダクトに導⼊した話」

Slide 4

Slide 4 text

1. cljfmt: formatter 2. eastwood: linter 3. kibit: idiom checker 4. Example Usage 5. Other Tools

Slide 5

Slide 5 text

formatter cljfmt

Slide 6

Slide 6 text

What's the problem? (when something (something-else) )

Slide 7

Slide 7 text

$ lein cljfmt check (when something - (something-else) -) + (something-else))

Slide 8

Slide 8 text

What's the problem? (when something something-else)

Slide 9

Slide 9 text

$ lein cljfmt check (when something - something-else) + something-else)

Slide 10

Slide 10 text

What's the problem? (filter even? (range 1 10))

Slide 11

Slide 11 text

$ lein cljfmt check (filter even? - (range 1 10)) + (range 1 10))

Slide 12

Slide 12 text

What's the problem? (if something ala bala)

Slide 13

Slide 13 text

$ lein cljfmt check (if something - ala - bala) + ala + bala)

Slide 14

Slide 14 text

What's the problem? (or ala bala portokala)

Slide 15

Slide 15 text

$ lein cljfmt check (or - ala - bala - portokala) + ala + bala + portokala)

Slide 16

Slide 16 text

linter eastwood

Slide 17

Slide 17 text

What's the problem? (ns linting-example.eastwood-target (:use [clojure.string]))

Slide 18

Slide 18 text

$ lein eastwood src/linting_example/eastwood_target.clj:2:10: unlimited-use: Unl imited use of ([clojure.string]) in linting-example.eastwood-tar get

Slide 19

Slide 19 text

What's the problem? (if-let [x []] (conj x 42) :falsy)

Slide 20

Slide 20 text

$ lein eastwood src/linting_example/eastwood_target.clj:4:1: constant-test: Test expression is always logical true or always logical false: [] in form (if temp__5455__auto__ (clojure.core/let [x temp__5455__aut o__] (conj x 42)) :falsy)

Slide 21

Slide 21 text

What's the problem? (defn f [x] (def y (* x x)) (+ y 2))

Slide 22

Slide 22 text

$ lein eastwood src/linting_example/eastwood_target.clj:9:8: def-in-def: There i s a def of y nested inside def f

Slide 23

Slide 23 text

What's the problem? (defn g [x] "blah blah blah." (* x x))

Slide 24

Slide 24 text

$ lein eastwood src/linting_example/eastwood_target.clj:12:7: misplaced-docstrin gs: Possibly misplaced docstring, g src/linting_example/eastwood_target.clj:12:1: unused-ret-vals: C onstant value is discarded: "blah blah blah."

Slide 25

Slide 25 text

What's the problem? (defn h [str] (str "Hello, " str "!"))

Slide 26

Slide 26 text

$ lein eastwood src/linting_example/eastwood_target.clj:17:3: local-shadows-var: local: str invoked as function shadows var: #'clojure.core/str

Slide 27

Slide 27 text

idiom checker kibit

Slide 28

Slide 28 text

What's the problem? (defn add-one [x] (+ x 1))

Slide 29

Slide 29 text

$ lein kibit At src/linting_example/kibit_target.clj:4: Consider using: (inc x) instead of: (+ x 1)

Slide 30

Slide 30 text

What's the problem? (defn check-if-zero? [x] (== x 0))

Slide 31

Slide 31 text

$ lein kibit At src/linting_example/kibit_target.clj:7: Consider using: (zero? x) instead of: (== x 0)

Slide 32

Slide 32 text

What's the problem? (defn zip-with-* [xs ys] (map #(* %1 %2) xs ys))

Slide 33

Slide 33 text

$ lein kibit At src/linting_example/kibit_target.clj:null: Consider using: * instead of: #(* %1 %2)

Slide 34

Slide 34 text

What's the problem? (defn coll->vec [coll] (into [] coll))

Slide 35

Slide 35 text

$ lein kibit At src/linting_example/kibit_target.clj:13: Consider using: (vec coll) instead of: (into [] coll)

Slide 36

Slide 36 text

What's the problem? (defn flat-map [f coll] (apply concat (map f coll)))

Slide 37

Slide 37 text

$ lein kibit At src/linting_example/kibit_target.clj:16: Consider using: (mapcat f coll) instead of: (apply concat (map f coll))

Slide 38

Slide 38 text

Example Usage

Slide 39

Slide 39 text

e.g. ↓↓↓ lagenorhynque/situated-program- challenge/rest-server/project.clj :plugins [[jonase/eastwood "0.2.5"] [lein-cljfmt "0.5.7"] [lein-kibit "0.1.6"]] :aliases {"lint" ^{:doc "Execute cljfmt check, eastwood and kibit."} ["do" ["cljfmt" "check"] ["eastwood" "{:source-paths [\"src\"]}"] ["kibit"]]} lein cljfmt check && lein eastwood && lein kibit = lein do cljfmt check, eastwood , kibit = lein lint # alias as `lint`

Slide 40

Slide 40 text

$ lein lint All source files formatted correctly == Eastwood 0.2.5 Clojure 1.9.0 JVM 9.0.1 Directories scanned for source files: src test == Linting rest-server.util == == Linting rest-server.boundary.db.core == == Linting rest-server.boundary.db.group == ... == Linting rest-server.handler.venue-test == == Linting rest-server.handler.meetup-test == == Linting rest-server.handler.member-test == == Warnings: 0 (not including reflection warnings) Exceptions thrown: 0

Slide 41

Slide 41 text

Other Tools

Slide 42

Slide 42 text

dependency lein deps :tree lein-ancient

Slide 43

Slide 43 text

namespace slamhound

Slide 44

Slide 44 text

dead code Yagni

Slide 45

Slide 45 text

vulnerability lein-nvd

Slide 46

Slide 46 text

test coverage cloverage

Slide 47

Slide 47 text

misc. lein-bikeshed

Slide 48

Slide 48 text

Utilise linters for clean Clojure code!

Slide 49

Slide 49 text

Further Reading Clojure Code Quality Tools My Clojure Toolchain: Leiningen Automating Style In Clojure The state of code quality tools in Clojure clojure-style-guide