Thinking in Data

Priyatam Mudivarti

 Code manipulates data. To understand code, a learner must see the data, and see the effect of code on the data.

 

- Brett Victor

Complex?

Templates

client apis

Build Tools

Responsive Design

Events

Dom

Performance

Modules 

3rd party libs

Javascript  
event handling,  dynamic, ajax, json

 

CSS3/Less/Sass  
rules, selectors, 
responsive design

HTML5  

markup , templating, dom

Simpler

A typical full stack application has hundreds of classes, getters/setters, state, tens of thousands of lines of code

Clojure code has no classes

no global state

1/10th to 1/100th of the codebase

Clojure

in 5 mins

data

functions

(def a-vector [1 2 3 4 5])


(def a-nested-map 
  {:customer-id 1e6
   :preferences {:nickname "Bob"
                 :avatar "http://en.gravatar.com/userimage/0/0.jpg"}
                 :services {:alerts {:daily true}}})


(def complex-map 
  {[1 2] :one-two 
   [3 4] :three-four})


(def a-set 
  #{:cat :dog :bird})

Clojurescript 202: immutable data structures

;; Unlike JavaScript there is no hoisting in ClojureScript. ClojureScript has lexical scoping.

(def some-x 1)

(let [some-x 2]
  some-x)


;; functions parameters, let bindings locals, and loop locals are not mutable!

(let [fns (loop [i 0 ret []]
            (if (< i 10)
              (recur (inc i) (conj ret (fn [] i)))
              ret))]
  (map #(%) fns))

Clojurescript 202: scope


; simple function
(defn add [a b]
  (+ a b))

;; function with multiple args and default values
(defn another-function
  ([x] (defaults x :default))
  ([x y] [x y]))


;; closure

(let [a 1e3]
  (defn foo []
    (* a a))
  (defn bar []
    (+ (foo) a)))


;; higher order functions

Clojurescript 202: functions

;; list comprehension
(for [x (range 1 10)
      y (range 1 10)
      :when (and (zero? (rem x y))
                 (even? (quot x y)))]
  [x y])


;; higher order functions over sequences
(map inc [0 1 2 3 4 5 6 7 8 9])

(filter even? (range 10))

(reduce + (range 100))

(partition 2 [:a 1 :b 2 :c 3 :d 4 :e 5])

(remove odd? (range 10))

(take 5 (interleave (repeat "red") (repeat "blue")))

;; Protocols, a.k,a Interfaces
(defprotocol MyProtocol (awesome [this]))
(extend-protocol MyProtocol
  js/Date
  (awesome [_] "Having an awesome time!")
  number
  (awesome [_] "I'm an awesome number!"))

(awesome #inst "2014")
(awesome 5)

Clojurescript 202: abstractions

 

That's it.

can we build http services with these concepts?

No More framework abstractions

HTTP services in Clojure (Ring)

;; handler
(defn my-ip [request]
  {:status 200
   :headers {"Content-Type" "text/plain"}
   :body (:remote-addr request)})

;; middleware
(defn wrap-content-type [handler content-type]
  (fn [request]
    (let [response (handler request)]
      (assoc-in response [:headers "Content-Type"] content-type))))

(defn wrap-content-type [handler content-type]
  (fn [request]
    (let [response (handler request)]
      (assoc-in response [:headers "Content-Type"] content-type))))

(defn json-response [data & [status]]
  {:status (or status 200)
   :headers {"Content-Type" "application/edn"}
   :body (pr-str data)})

(def app
  (wrap-content-type my-ip "text/html"))

(defn serve [request]
  (app request))

Ring - Concepts

;; Routes

(defroutes routes
  (GET "/" [] (str "Server is running"))
  (GET "/ws" [] handle-websocket)
  (context
      "/api" []
      (GET "/languages" []
           (let [prog (get-in db/data [:languages])]
             (when prog
               (edn-response prog))))
      (GET "/languages/:id/:type" [id type]
           (let [stats (filter #(and
                                 (= (:id %) id) (= (:type %) type))
                               (get-in db/data [:stats]))]
             (when stats
               (response stats)))))))

Routes

(def app
  (->
   (handler/site router/routes)
   (wrap-json-body)
   (wrap-json-response)
   (wrap-edn-params)
   (wrap-defaults api-defaults)
   (wrap-cors
    :access-control-allow-origin #".+"
    :access-control-allow-methods [:get :post :put :delete :head]
    :access-control-allow-headers ["Content-Type" "X-Requested-With"])))

(defn -main [& _]
  (let [port (Integer. (or (System/getenv "SERVER_PORT") 8000))]
    (server/run-server app {:port port :join? false})
    (log/info "Server started and listening at port..." port)))

Server

HTTP Services

Abstract HTTP

Write idiomatic code

Run on any web server

Bare Metal

Easy to Test

Live Coding

I've written webservices in 5 languages.

 

I find Clojure to be 10x simpler

Let's talk about CSS/SASS

 

no namespaces

 

can't compose HTML and CSS in the same syntax

 

css doesn’t “talk to dom”

 

math impl is hard
 

can we pass css as functions at runtime?

 

mixins are not composable


constrained by limitations—not by choice



(defn create-minimal-grid [clazz pad]
  [[:* {:box-sizing "border-box"}]
   [clazz {:background "white"
           :margin [[0 0 pad 0]]}
    [:&:after {:content ""
               :display "table"
               :clear "both"}]
    ["[class*='col-']" {:float "left"
                        :padding-right pad }]
    [:.col-1-3 {:width "33.33%"}]
    [:.col-2-3 {:width "66.66%"}]
    [:.col-1-2 {:width "50.00%"}]
    [:.col-1-4 {:width "25.00%"}]
    [:.col-1-8 {:width "12.50%"}]
    [:.out-padding {:padding [[pad 0 pad pad pad]]}
     ["[class*='col-']:last-of-type" 
         {:padding-right pad}]]]])

A grid in a single function

(defn default-layout
  "Creates a tiled layout with n 'views' stacked on top, with a help
   view floated to the right.
   For more info see https://bulma.io/documentation/layout/tiles/"
  [help-section & views]
  [:div {:class "tile is-ancestor"}
   [:div {:class "tile is-1 is-vertical"}]
   [:div {:class "tile is-7 is-vertical is-parent"}
    (for [view views]
      ^{:key view} [:div {:class "tile is-child"}
                    view])]
   [:div {:class "tile is-2 is-parent"}
    help-section]])

Sample layout

It is better to have 100 functions operate on one data structure than to have 10 functions operate on 10 data structures

 

 

 - Alan J. Perlis

Thinking in Data

By Priyatam Mudivarti

Thinking in Data

Thinking in Data. Clojure/Cljs Web development

  • 377