This repository has been archived by the owner on May 14, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathslideshow.html
278 lines (238 loc) · 7.72 KB
/
slideshow.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
<!DOCTYPE html>
<html>
<head>
<title>Clojure</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<style type="text/css">
@import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz);
@import url(https://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic);
@import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic);
body { font-family: 'Droid Serif'; }
h1, h2, h3 {
font-family: 'Yanone Kaffeesatz';
font-weight: normal;
}
.remark-code, .remark-inline-code { font-family: 'Ubuntu Mono'; }
</style>
</head>
<body>
<textarea id="source">
class: center, middle
# Hacking In Clojure
### Farmlogs Backend Team
---
# Brief Intro to Clojure/Lisp
* Normally, you call functions this way
```python
foo(1, 3, 4)
```
* Now, move that leftmost parenthesis a little _more_ to the left:
```clojure
(foo 1 2 3) ; that wasn't so hard!
```
* Anything of that form is called an "s-expression":
```clojure
(whatever-you-are-doing arg1 arg2 ...) ; those dots are not valid clojure
```
In lisps, (almost) everything is an s-expression...
(continued on next slide)
---
# S-Expression Examples
* Defining things
```clojure
(def message "Hello World")
(defn sum [x y]
(+ x y))
```
* Control "statements" (expressions)
```clojure
(if (predicate? item)
(do-something item)
(do-something-else item))
(case item
"foo" (do-foo item)
"bar" (do-bar item)
(do-default item))
```
That's it!
---
# How to Server in Clojure: Ring
* From the [Github Page](/~https://github.com/ring-clojure/ring)
> Ring is a Clojure web applications library inspired by Python's WSGI
and Ruby's Rack
* A Ring application is just a clojure function:
```clojure
(defn app [request]
{:status 200
:headers {"Content-Type" "text/html"}
:body "Hello World"})
```
* To run the app, you plug the function into a magic java
server adapter which handles the actual requesting and responsing
* Very simple, and (as we'll soon see), *very* powerful
---
# First, Higher Order Functions
* Any function that takes another function as an argument and/or
returns a function as its result:
```clojure
(def filter-then-count (comp count filter))
; just like in math f(g(x)), count(filter(...))
(filter-then-count neg? [-3 -2 -1 1 2 3]) ; => 3
(def add-two (partial sum 2)) ; we defined "sum" earlier
(add-two 5) ; => 7
```
* The most well-known examples are the classic collection processing
functions: `map`, `filter`, `reduce` etc.
```clojure
(map inc [1 2 3]) ; => (2 3 4)
(filter pos? [-8 -2 1 9 3]) ; => (1 9 3)
(reduce + [1 2 3]) ; => 6
```
---
# Chaining Together Functions
Let's say we had a collection of fields, and wanted to find the total
rainfall of all fields in Michigan
```clojure
(def michigan? (comp (partial = "MI") :state))
(->> fields
(filter michigan?) ; keep only field in Michigan
(map :rainfall) ; grab the :rainfall value from each
(reduce +)) ; add all of the values together
```
`->>` is a macro, which we'll cover in a bit. For now you can just
think of it as another part of Clojure syntax.
If you want an example you can use in your repl, try
```clojure
(->> (range -5 5) ; generate set of numbers with negative numbers
(filter pos?) ; only keep positive numbers
(map inc) ; increment them all by one
(reduce +)) ; add it all together
```
---
# Back to Ring: Middleware
Remember our simple app?
```clojure
(defn app [request]
{:status 200
:headers {"Content-Type" "text/html"}
:body "Hello World"})
```
"Hello World" is pretty sensitive info, so we should authenticate
every request:
```clojure
(defn wrap-authentication [handler]
(fn [request]
(if (= "super-secret-session-id" (get-cookie "session" request))
(handler request)
{:status 403 :body "You're not allowed!"})))
```
Now, we can build a new secure app from our old app simply by calling
the wrapper function
```clojure
(def secure-app (wrap-authentication app)) ; hooray for higher-order functions!
```
---
# More Middleware
Since middleware are just functions, and most real apps use a lot of
middleware, you can chain them together like anything else:
```clojure
(defn app [request] ...)
(def better-app
(->> app
(wrap-authentication) ; our middleware from before
(wrap-json-response) ; auto-convert a non-ring map to json
(wrap-cookies) ; convert cookies to an easy-to-use format
(wrap-gzip))) ; handle gzip requests
```
---
# Obligatory Lisp Macro Slide(s)
Lisps have a proud tradition of utilizing the power of _macros_, which
you can think of as "functions" (not technically functions) that
manipulate code at compile time instead of data at runtime.
Macros are incredibily useful for modifying language syntax:
```clojure
(defn arbitrary-arithmetic [x y z]
(/ (* 2 y) (+ z (- x y))))
; using the "$=" macro from http://incanter.org
(defn arbitrary-arithmetic [x y z]
($=
(2 * y) / (z + x - y)))
```
as well as things like setting up and tearing down test data:
```clojure
(with-data [person [person-model]
pet [pet-model {:person person}]]
(do-test-stuff person pet))
```
---
# Writing Real Web Apps with Macros
For most web apps that aren't toy examples, you can use Compojure, a
set of macros for defining routes in a sane, high-level way:
```clojure
(defroutes app
(GET "/" [] "Hello World")
(POST "/data" request
(post-some-data request))
(GET "/data/:id" [id]
(get-some-data id)))
```
`defroutes`, `GET` and `POST` all compile down to something like this:
```clojure
(defn app [request]
(if (and (= (:uri request) "/")
(= (:request-method request) :get))
{:status 200 :body "Hello World"}
(if (and (= (:uri request) "/data")
(= (:request-method request) :post))
(post-some-data request)
...)))
```
Much easier than writing all of that out by hand!
---
# Testing Clojure Apps
Testing is important.
By default, all Clojure applications have access to a nice set of
macros in `clojure.test`
```clojure
(deftest security-policy
(testing "authorized requests are allowed"
(let [response (secure-app authed-request)]
(is (= 200 (:status good-response)))
(is (= "Hello World" (:body good-response)))))
(testing "unauthorized requests are not allowed"
(let [bad-response (secure-app bad-request)]
(is (= 403 (:status bad-response)))
(is (= "You're not allowed!" (:body bad-response))))))
```
Because `testing` and `is` are both macros, when the test fails, it
can tell you exactly what code failed, not just whatever was passed
into a comparison function.
---
# Extra Credit
We've only just scratched the surface of the wonderful world of
Clojure, if you want to learn more, you should check out:
* [Clojure for the Brave and True](http://www.braveclojure.com/), a
great book that covers nearly all important language concepts and
features
* [4Clojure](https://www.4clojure.com/), an interactive set of
problems to solve in clojure
* [Try Clojure](http://www.tryclj.com/) has an interactive tour mode
* [Clojure Koans](http://clojurekoans.com/) a set of problems similar
to 4Clojure that you run on your local machine, so you can learn
about Clojure's excellent tooling while you're at it.
* [Simple Made
Easy](http://www.infoq.com/presentations/Simple-Made-Easy) by Rich
Hickey, creator of Clojure (or any of his talks, really)
* [ClojureScript](/~https://github.com/clojure/clojurescript), Clojure
that runs on top of JavaScript instead of the JVM
---
class: center, middle
# Questions?
</textarea>
<script src="https://gnab.github.io/remark/downloads/remark-latest.min.js" type="text/javascript">
</script>
<script type="text/javascript">
var slideshow = remark.create();
</script>
</body>
</html>