Top Banner
Clojure From the Ground Up BuildingOur First Clojurebased Microservices
43

ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

May 22, 2020

Download

Documents

dariahiddleston
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Clojure From  the  Ground  UpBuilding  Our  First  Clojure-­‐based  Microservices

Page 2: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

About  the  Speaker

John  Carnell  is  a  Senior  Cloud  Engineer  at  Interactive  Intelligence  in  Raleigh,  North  Carolina.  John  is  a  prolific  speaker  and  writer.  He  has  spoken  at  such  national  conferences  as  the  No  Fluff  Just  Stuff  Software  Symposium,  Internet  Expo  and  the  Data  Warehousing  Institute.

John  has  authored,  co-­‐authored  and  been  a  technical  reviewer  for  a  number  of  technology  books  and  industry  publications.

John  can  be  reached  at  [email protected].

Disclaimer: The  views  and  opinions  expressed  in  this  presentation  are  solely  the  opinion  of  the  presenter  and  do  not  reflect  or  represent  the  position  or  opinion  of  Interactive  Intelligence  or  any  of  its  subsidiaries.  

Page 3: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

About  Interactive  Intelligence

• Interactive  Intelligence  is  a  leading  provider  of  call  center  technologies  and  communication

• We  offer  a  wide  variety  of  software  products  and  have  two  core  product  lines:• CIC  – Traditional  on-­‐premise call  center  solution• PureCloud – Cloud-­‐based  telephony  and  communication  solution

• We  have  been  in  business  for  approximately  20  years  and  have  development  and  sales  offices  throughout  the  world,  with  the  core  software  development  being  done  in:• Indianapolis,  Indiana  -­‐ CIC• Raleigh,  North  Carlolina – PureCloud

• Our  Raleigh  has  been  around  for  about  3  years  and  has  approximately  100+  developers  located  there

Page 4: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

About  PureCloud• Cloud-­‐based  call  center  and  communication  software  solution

• Runs  primarily  in  AWS  • EC2• Dynamo• SQS• S3

• Microservices based  architecture• Every  team  is  responsible  for  their  own  services  from  beginning  to  end  and  choose  the  technology  stack  they  are  going  to  work  ands  support• Approximately  100+  REST-­‐based  Microservices written  in  Java,  Node,  Go,  Python  (and  now  Clojure)• Heavy  use  of  an  event  communication  using  Kafka

Page 5: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Why  We  Started  Looking  at  Clojure

Sometimes  Java  is  Just  So  Heavy…..      

ChugChug

Chug

I  wonder  why  my  hair  is  going  grey.

Page 6: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

What  we  were  trying  to  build:    Edge  Provisioning

Page 7: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Our  Experiences  Lets  do  a  little  walkthroughof  our  experiences.

This  is  a  no-­‐navel  gazing  zone.

Page 8: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Clojure and  REST-­‐Based  Microservice Development

Page 9: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Core  Framework  for  Microservices

Jetty  Servlet  Container

Compojure

Ring  Middleware

Request  Handler

• Strong  Servlet  Container• SSL  Support/  High  Performance

• Routing  API  • Swagger-­‐based  Interface  Definition

• HTTP  Request/Response  Abstraction• Middleware  Pipelines  

• Pure  Clojure Functions• Could  be  composed  and  tested  independently  of  the  Framework

Page 10: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Why  did  we  choose    Compojure and  Ring  framework?• I  have  worked  in  a  lot  of  development  frameworks.

• Frameworks  can  save  time,  but  when  you  first  start  using  them  its  Pure  Frickin Magic  (PFM)

• Then  you  often  discover  there  is  a  price  for  magic……

Wanted  to  started  with  a  light-­‐weight  abstraction  layer  that  our   team  could  reason  about.

Page 11: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Defining  an  Endpoint  using  Ring  and  Compojure

Page 12: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Ring  Handlers  are  Just  Functions

Page 13: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Ring  Middleware:    All  Requests  Get  Put  Through  a  Pipe

Page 14: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Custom  Middleware  is  Easy

Ring  middleware  has  let  to  some  very  elegant  solutions  to  problems.    We  solved  an  interesting  problem  in  the  Swagger  UI  with  minimal  effort  with  a  custom  middleware

Page 15: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Making  and  Parsing  REST  Calls

Page 16: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

What  Do  You  Do  With  This?{"organizationId"  organization-­‐id,                        "siteId"  site-­‐id,                        "asgId"  asg-­‐id,                        "instanceInfo"  [  {"instanceId"        (:instance-­‐id  instance1-­‐info),                                                            "privateIp"    (:instance-­‐privateip instance1-­‐info),                                                            "publicIp"      (:instance-­‐publicip instance1-­‐info),                                                            "imageId"  "ami-­‐2ca6b546",                                                            "state"  "running",                                                            "organizationId"  organization-­‐id,                                                            "edgeId"  nil},                                                      {"instanceId"  (:instance-­‐id  instance2-­‐info),                                                              "privateIp"  (:instance-­‐privateip instance2-­‐info),                                                              "publicIp"    (:instance-­‐publicip instance2-­‐info),                                                              "imageId"                "ami-­‐2ca6b546",                                                              "state"                    "running",                                                              "organizationId"  organization-­‐id,                                                              "edgeId"                  nil}]})(defn build-­‐get-­‐aws-­‐asg-­‐response    "Builds  a  mock  aws-­‐asg-­‐response  based  on  the  ASG"    [asg-­‐name  organization-­‐id  site-­‐id  instance1-­‐info  instance2-­‐info]      {:auto-­‐scaling-­‐groups        [{:tags                                                                  [{:value  organization-­‐id,                                                                      :key  "cluster",                                                                      :resource-­‐type  "auto-­‐scaling-­‐group",        :resource-­‐id                                                                      asg-­‐name,                                                                      :propagate-­‐at-­‐launch  true}                                                                    {:value  site-­‐id,                       :key  "layer",                                                                      :resource-­‐type  "auto-­‐scaling-­‐group",                                        :resource-­‐id                                                                      asg-­‐name,                                                                      :propagate-­‐at-­‐launch  true}                                                                    {:value  organization-­‐id,       :key  "organizationId",                                                                      :resource-­‐type  "auto-­‐scaling-­‐group",                                                                      :resource-­‐id                                                                      asg-­‐name,                                                                      :propagate-­‐at-­‐launch  true}                                                                    {:value  site-­‐id,                       :key  "siteId",                                                                      :resource-­‐type  "auto-­‐scaling-­‐group",                                                                      :resource-­‐id                                                                      asg-­‐name,                                                                      :propagate-­‐at-­‐launch  true}                                                                    {:value  "23",                             :key  "version",                                                                      :resource-­‐type  "auto-­‐scaling-­‐group",                                                                      :resource-­‐id                                                                      asg-­‐name,                                                                      :propagate-­‐at-­‐launch  true}],            :health-­‐check-­‐type  "EC2",            :default-­‐cooldown  600, :auto-­‐scaling-­‐group-­‐arn"arn:aws:autoscaling:us-­‐east-­‐1:490606849374:autoScalingGroup:d9d42949-­‐8227-­‐4cb6-­‐870a-­‐884c081cf0f3:autoScalingGroupName/ad1ea37c-­‐98c6-­‐49b4-­‐9b7c-­‐fd9d9565fd70-­‐49b4-­‐9b7c-­‐fd9d9565cccc-­‐ASG-­‐v23",            :availability-­‐zones   ["us-­‐east-­‐1a"  "us-­‐east-­‐1d"],            :launch-­‐configuration-­‐name                                                                  "ad1ea37c-­‐98c6-­‐49b4-­‐9b7c-­‐fd9d9565fd70-­‐49b4-­‐9b7c-­‐fd9d9565cccc-­‐LC-­‐v23",            :health-­‐check-­‐grace-­‐period  600,            :max-­‐size  2,            :desired-­‐capacity  2,            :min-­‐size  2,            :instances                                                                  [{:launch-­‐configuration-­‐name                           "ad1ea37c-­‐98c6-­‐49b4-­‐9b7c-­‐fd9d9565fd70-­‐49b4-­‐9b7c-­‐fd9d9565cccc-­‐LC-­‐v23",                                    :instance-­‐id  (:instance-­‐id  instance1-­‐info),                                                                      :health-­‐status  "Healthy",                                                   :availability-­‐zone  "us-­‐east-­‐1a",                                                                      :lifecycle-­‐state  "Pending:Wait"}                                                                    {:launch-­‐configuration-­‐name                                                                                                            "ad1ea37c-­‐98c6-­‐49b4-­‐9b7c-­‐fd9d9565fd70-­‐49b4-­‐9b7c-­‐fd9d9565cccc-­‐LC-­‐v23",                                                                      :instance-­‐id  (:instance-­‐id  instance2-­‐info),                                                                      :health-­‐status  "Healthy",                                                                      :availability-­‐zone  "us-­‐east-­‐1d",                                                                      :lifecycle-­‐state "Pending:Wait"}],            :vpczone-­‐identifier  "subnet-­‐7bfbc70f,subnet-­‐80a9d0a8",            :load-­‐balancer-­‐names  [],            :enabled-­‐metrics  [],            :created-­‐time        "2016-­‐06-­‐10T08:29:29.288-­‐04:00",            :termination-­‐policies  ["OldestInstance"],            :auto-­‐scaling-­‐group-­‐name                                                                  asg-­‐name,            :suspended-­‐processes  []}]})(defn get-­‐ec2-­‐instance-­‐data    "Mocks  out  EC2  instance  data"    [instance-­‐info]    {:reservations      [{:instances                                          [{:monitoring  {:state  "enabled"},                 :tags                                              [{:value  "opsTestService-­‐jim",  :key  "Name"}                                                {:value                                                            "ad1ea37c-­‐98c6-­‐49b4-­‐9b7c-­‐fd9d9565fd70-­‐49b4-­‐9b7c-­‐fd9d9565cccc-­‐ASG-­‐v23",                                                  :key  "aws:autoscaling:groupName"}                                                {:value  "ad1ea37c-­‐98c6-­‐49b4-­‐9b7c-­‐fd9d9565fd70",  :key  "cluster"}                                                {:value  "23",  :key  "opsTestService-­‐jim_version"}                                                {:value  "49b4-­‐9b7c-­‐fd9d9565cccc",  :key  "layer"}                                                {:value  "opsTestService-­‐jim",  :key  "role"}                                                {:value  "49b4-­‐9b7c-­‐fd9d9565cccc",  :key  "siteId"}                                                {:value  "23",  :key  "version"}                                                {:value  "ad1ea37c-­‐98c6-­‐49b4-­‐9b7c-­‐fd9d9565fd70",     :key  "organizationId"}                                                {:value  "dev",  :key  "environment"}],                                              :root-­‐device-­‐type  "ebs",                                              :private-­‐dns-­‐name  "ip-­‐172-­‐18-­‐12-­‐25.ec2.internal",                                              :hypervisor  "xen",                                              :subnet-­‐id  "subnet-­‐80a9d0a8",                                              :key-­‐name  "dev.ops",                                              :architecture  "x86_64",                                              :security-­‐groups                                              [{:group-­‐id  "sg-­‐69880d12",                                                  :group-­‐name                                                       "edge-­‐asg-­‐template-­‐InstanceSecurityGroup-­‐1VX898CQDNTXY"}],                                              :source-­‐dest-­‐check  true,                                              :root-­‐device-­‐name  "/dev/xvda",                                              :virtualization-­‐type  "hvm",                                              :product-­‐codes  [],                                              :instance-­‐type  "c3.large",                                              :ami-­‐launch-­‐index  0,                                              :image-­‐id  "ami-­‐2ca6b546",                                              :state  {:name  "running",  :code  16},                                              :state-­‐transition-­‐reason  "",                                              :network-­‐interfaces               [{:description  "",                                                  :private-­‐dns-­‐name  "ip-­‐172-­‐18-­‐12-­‐25.ec2.internal",                                                  :subnet-­‐id  "subnet-­‐80a9d0a8",                                                  :source-­‐dest-­‐check  true,                                                  :private-­‐ip-­‐addresses                                                  [{:association                                                                                              {:public-­‐dns-­‐name                                                                                                                          "ec2-­‐174-­‐129-­‐137-­‐192.compute-­‐1.amazonaws.com",                                                                                                :ip-­‐owner-­‐id  "amazon",                                                                                                :public-­‐ip (:instance-­‐publicip instance-­‐info)},                                                      :private-­‐ip-­‐address  (:instance-­‐privateip instance-­‐info),                                                      :private-­‐dns-­‐name  "ip-­‐172-­‐18-­‐12-­‐25.ec2.internal",                                                      :primary  true}],                                                  :network-­‐interface-­‐id  "eni-­‐8e0b90a8",                                                  :vpc-­‐id  "vpc-­‐ba514bd8",                                                  :mac-­‐address  "12:cc:e7:16:7c:1f",                                                  :association                                                  {:public-­‐dns-­‐name  "ec2-­‐174-­‐129-­‐137-­‐192.compute-­‐1.amazonaws.com",                                                    :ip-­‐owner-­‐id  "amazon",                                                    :public-­‐ip (:instance-­‐publicip instance-­‐info)},                                                  :status  "in-­‐use",                                                  :private-­‐ip-­‐address  (:instance-­‐privateip instance-­‐info),                                                  :owner-­‐id  "490606849374",                                                  :groups                                                  [{:group-­‐id  "sg-­‐69880d12",                                                      :group-­‐name                                                                          "edge-­‐asg-­‐template-­‐InstanceSecurityGroup-­‐1VX898CQDNTXY"}],                                                  :attachment                                                  {:status  "attached",                                                    :device-­‐index  0,                                                    :attach-­‐time  "2016-­‐06-­‐10T09:33:23.000-­‐04:00",                            :delete-­‐on-­‐termination   true,                                                    :attachment-­‐id  "eni-­‐attach-­‐781de2a2"}}],                                              :vpc-­‐id  "vpc-­‐ba514bd8",                                              :ebs-­‐optimized  false,                                              :instance-­‐id  (:instance-­‐id  instance-­‐info),                                              :iam-­‐instance-­‐profile                                              {:id  "AIPAJLCFTO5UAQFED3FXS",                                                :arn "arn:aws:iam::490606849374:instance-­‐profile/edge-­‐asg-­‐template-­‐InstanceProfile-­‐12CV1P3Z0GEKX"},                                              :public-­‐dns-­‐name  "ec2-­‐174-­‐129-­‐137-­‐192.compute-­‐1.amazonaws.com",                                              :private-­‐ip-­‐address  (:instance-­‐privateip instance-­‐info),                                              :placement                                              {:group-­‐name  "",                                                :tenancy  "default",                                                :availability-­‐zone  "us-­‐east-­‐1d"},                                              :client-­‐token                                              "cc425936-­‐57ca-­‐4963-­‐ab72-­‐bfbceb93ac0c_subnet-­‐80a9d0a8_1",                                              :public-­‐ip-­‐address  (:instance-­‐publicip instance-­‐info),                                              :launch-­‐time    "2016-­‐06-­‐10T09:33:23.000-­‐04:00",                                              :block-­‐device-­‐mappings                                              [{:device-­‐name  "/dev/xvda",                                                  :ebs {:status  "attached",                                                                              :attach-­‐time  "2016-­‐06-­‐10T09:33:24.000-­‐04:00",                                                                              :delete-­‐on-­‐termination  true,                                                                             :volume-­‐id  "vol-­‐c8db8318"}}                                                {:device-­‐name  "/dev/sdo",                                                  :ebs {:status  "attached",                                                                              :attach-­‐time  "2016-­‐06-­‐10T09:33:24.000-­‐04:00",                                                                              :delete-­‐on-­‐termination  true,                                 :volume-­‐id  "vol-­‐7bdb83ab"}}                                                {:device-­‐name  "/dev/sdp",                                                  :ebs{:status  "attached",                                                                              :attach-­‐time  "2016-­‐06-­‐10T09:33:24.000-­‐04:00",                                                 :delete-­‐on-­‐termination  true,                                                                              :volume-­‐id  "vol-­‐7cdb83ac"}}]}],          :group-­‐names  [],          :groups  [],          :owner-­‐id  "490606849374",          :reservation-­‐id  "r-­‐973dc335",          :requester-­‐id  "226008221399"}]}

Page 17: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

(ec2/describe-­‐instances        :instance-­‐ids  [instance-­‐id])

You  need  something  as  cool  as  Bond

Page 18: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Specter

Page 19: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Specter

Page 20: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Clojure:      Infrastructure  and  Middleware

I’m  a  services  developer,  I  have  people  skills!

Page 21: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Introducing  Amazonica• Amazon’s   Java  Client  uses  repeatable  idioms  

throughout    their  API

• Amazonica uses  reflection  and  the  API  to  build  a  simple  DSL  for  invoking   Amazon  APIs.

• The  documentation   on  their  website  is  complete,  but  once  you  understand  how  they  apply  reflection  its  pretty  easy  to  work  your  way  back.

Page 22: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Amazonica:    Simplify  Amazon  API  Calls

Page 23: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Amazonica:    Starting  an  Instance

Page 24: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Kafka:    High  Speed  Event  BusOur  architecture  communicates  state  changes  in  our   services  through   events

We  rely  heavily  on  Kafka  as  our  communication  bus.

Built  a  small  framework  to  register  functions   to  handle  messages.

91  lines  of  code  and  used  our  Broker  Consumer

We  pretty  much  reused  the  Java  clients

Actually  reused  the  HTTP  handler  code  I  had  written  for  the  delete  endpoint.

I  could  do  this  because  everything  maps  to  a  few  basic  types

Page 25: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Testing

Page 26: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Clojure:      The  Language

Tell  me  again  to  write  thisservice  in  Java!!!

Page 27: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Concise  Code  In  Action    

Page 28: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Conciseness  by  the  Numbers• 23  production  level  files  

• 5  of  those  files  are  swagger  definitions• Does  not  include  the  testing  code

• Largest  file  is  213  lines  of  code

• This  file  has  a  large  amount  of  text  in  it  describing  the  endpoints  

• The  next  largest  file  is  168  lines  of  code

• This  file  is  has  a  bunch  of  individual  property  and  map  definitions  in  it.

Page 29: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Functional  Example  1:    Building  a  Pairing  Token

Page 30: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Functional  Example  1:    Testing  Pairing  Tokens

Page 31: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

The  Real  Power  of  Clojure:    Simplified  Data  Structures

• Simple=General  data  structures  not  specific  types.

• Clojure focuses  on  a  using  a  few  basic  types  with  lots  of  powerful  functions.

• Java  and  other  static  languages  model  the  world  through  specific  types  that  decompose  the  world  into  self-­‐encapsulated  data  structures.

• This  type  specificity  adds  a  huge  amount  of  complexity    to  how  we  write  our  code.

Page 32: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Whoa!

{“organizationId”  :    “”,“id”:””,“label”:  “”,“version”:  “”,“dateCreated”:  “”,“dateModified”:””,“modifiedBy”:””,“modifiedByApp:””,“createdBy”:””,”state”:””,“didPoolId”:””,“text”:””,”ownerType”:””,“ownerId”:””}

{:organizationId :    “”:id:””:label:  “”:version:  “”

……}

• 601  lines  of  generated  code• 1  mapping  file• Have  to  write  custom  functions   to  

search  and  manipulate  the  data

• 1  function   (read-­‐str)  to  read  in  the  data• Returns  a  14  element  hashmap• Every  Clojure Hashmap function  will  work  

with  it.• Is  the  type  safety  Java  provides  worth  the  

complexity?

”It  is  better  to  have  100  functions  operate  on  one  data  structure  than  10  functions  on  10  data  structures.”-­‐ Alan  Perliss

Page 33: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Strong  JVM  Interoperability

Page 34: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Dude,  What  We  Learned

Page 35: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Lessons  Learned• Don’t  get  frustrated,  you  are  going  to  have  to  change  the  way  you  think  about  writing  code.    

• Use  standard  data  structures  and  be  aware  of  the  shape  of  your  data.

• Write  small  functions  

• Drive  your  exceptions  to  standard  data  structure

• Use  the  repl to  poke  at  things

• Turn  on  auto—testing.    Its  awesome  and  will  help  you  debug.

• Clojure is  a  great  programming  language  that  is  concise.    The  claims  about  less  code  are  true.

Page 36: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Whats Next• Stuart  Sierra’s  Component  API

• Move  from  Lein to  Clojure Boot

• More  core.async please

• Keep  learning  

Page 37: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Closing  Thoughts

“Clojure is  the  only  language  that  I  have  seen  where  the  longer  a  developer  is  writing  code,  the  smaller  the  code  base  gets.”

-­‐ Chris  Miller

Page 38: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Shameless  Self  Promotion

Page 39: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Thanks

Page 40: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Appendix  A:      Libraries  Used  in  Our  Microservices

Page 41: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

LibrariesProject Urls

compojure https://github.com/weavejester/compojure

Ring   https://github.com/ring-­‐clojure

specter https://github.com/nathanmarz/specter

amazonica https://github.com/mcohen01/amazonica

clj-­‐http https://github.com/dakrone/clj-­‐http

midje https://github.com/marick/Midje

lein http://leiningen.org/

boot https://github.com/boot-­‐clj/boot

slingshot https://github.com/scgilardi/slingshot

Page 42: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Appendix  B:    Good  Resources

Page 43: ClojureFrom*the*Ground*Up · About*the*Speaker John(Carnell(is(a(Senior(Cloud(Engineer(at(Interactive(Intelligence(in(Raleigh,(North(Carolina.(John(is(a(prolific(speaker(and(writer.(He

Good  Clojure Resources• Anything  Rich  Hickey  Presents

• Simple  Made  Easy• Deconstructing  the  database• ClojureMade  Simple