Data, the Ultimate Abstraction

Miikka Koskinen

2017-10-25

about me

Professional Clojure user since 2013.

metosin_blue_horizontal.png

"data structures as interfaces"

Programming with concrete data, like EDN or JSON.

Hiccup

HTML rendering library by James Reeves in 2009.

(defn example-page [title]
  (h/html5
   [:head
    [:title title]]
   [:body
    [:div.container
     [:h1 title]
     [:p "Hello world!"]]]))

concrete data, not abstract

Like this:

{:shape/kind     :circle
 :shape/color    :red
 :shape/position [3 3]
 :shape/radius   5}

Not like this:

public class Circle extends Shape {
   public Color color;
   public Point position;
   public double radius;

   public Circle(Color startColor, Point startPoint,
                 double startRadius {
     color = startColor;
     position = startPosition;
     radius = startRadius;
   }

   public void setColor(Color newColor) {
     color = newColor;
   }

   // ... you get the idea ...
}

Not even like this:

data Shape
    = Circle { color :: Color
             , position :: Point
             , radius :: Double }
    | Rectangle { ... }
    | ...

What can you program with?

  1. macros
  2. functions
  3. data

compojure

Routing library created by James Reeves in 2009.

(defroutes app
  (context "/products"
    (GET "/" []                    (products/list))
    (GET "/:pid" [pid :<< as-uuid] (products/get pid))
    (GET "/search" [q]             (products/search q)) 
    (POST "/" {body :body}         (products/new body))
    (route/not-found "<h1>Page not found</h1>"))

ataraxy

Routing library created by James Reeves in 2016.

{"/products"
 {[:get]                [:products/list]
  [:get "/" pid]        [:products/get ^uuid pid]
  [:get "/search" #{q}] [:products/search q]
  [:post {body :body}]  [:products/new body]}}

(defroutes app
  (context "/products"
    (GET "/" []                    (products/list))
    (GET "/:pid" [pid :<< as-uuid] (products/get pid))
    (GET "/search" [q]             (products/search q)) 
    (POST "/" {body :body}         (products/new body))
    (route/not-found "<h1>Page not found</h1>"))
{"/products"
 {[:get]                [:products/list]
  [:get "/" pid]        [:products/get ^uuid pid]
  [:get "/search" #{q}] [:products/search q]
  [:post {body :body}]  [:products/new body]}}

language-oriented programming

When you encounter a problem, solve it by creating a language where it's easy to solve.

code-is-data.jpeg

code-is-data-ann.jpeg

benefits

You already know how to work with data!

  • how to generate it
  • how to merge it
  • how to put it in a file
  • how to send it over wire

benefits

Instead of having a compiler for your macro language, you can have multiple interpreters for your data language.

downsides

Can be slow.

downsides

IDEs won't support your little language (out of the box).

re-frame

(rf/reg-event-db
  ::input-changed
  (fn [db [_ value]]
     (assoc db :input-value value)))

[:input {:type "text"
         :on-change #(rf/dispatch [::input-changed %])}]

downsides

Beware of implementing a general-purpose programming language!

Why is this a Clojure thing?

EDN is rich enough and easy to work with!

Consider: JSON vs. EDN vs. XML

Integrant

{:adapter/jetty {:port 8080, :handler #ig/ref :handler/greet}
 :handler/greet {:name "Alice",
                 :birthday #inst "1987-10-25T00:00Z"}}
{ 
  "adapter/jetty": {
    "port": 8080,
    "handler": ["ig/ref", "handler/greet"]
  }, 
  "handler/greet": {
    "name": "Alice",
    "birthday": "1987-10-25T00:00Z"
  }
}

What about tooling?

There's a controversial library for creating a parser for your little language…

clojure.spec

Seriously, check out s/conform.

hylje.png

http://miikka.me/slides/data-the-ultimate/

follow me on twitter: @arcatan

See also…

Photo credit: Kenneth Dellaquila. CC-BY-NC. Cropped.