Life without Objects (w/ Clojure)

 
( life w/o objects )
( oop → functional  design )
( with clojure )
 
 
(Osvaldas Grigas | )@ogrigas
(oop hangover)
Life without Objects (w/ Clojure)
type systems
"hybrid" languages
(design)
(monolithic design)
(modular design)
(design process)
Before A er
(oo design)
Noun-oriented
Verb-oriented
(nouns)
CustomerDAO
CustomerService
CustomerController
(verbs)
RegisterCustomer
PromoteCustomerToVIP
RenderCustomerProfilePage
Domain-driven Design?
 
"As a teller, I want to transfer funds between accounts."
(oo design principles)
Single Responsibility
Interface Segregation
Dependency Inversion
(single responsibility)
public class ZipDownloadService { 
    List<File> downloadAndExtract(String location) { 
        ... 
    }
}
public class FileDownloader { 
    List<File> downloadFiles(String location) { 
        ... 
    }
}
public class ZipExtractor { 
    File extractZip(File archive) { 
        ... 
    }
}
Or ... just functions
(defn download­files [location] 
  (...)) 
(defn extract­zip [archive] 
  (...))
(clojure)
in a nutshell
(clojure)
in a nutshell
 calculate(5,2,9)
(clojure)
in a nutshell
(calculate 5,2,9)
(clojure)
in a nutshell
(calculate 5 2 9)
(function definition)
(defn calculate [a b c] 
  (+ a (* b c)))
(interface segregation)
public class ProductCatalog 
{ 
    public void Save(Product product) 
    {
        ... 
    }
    public Product FindById(int productId) 
    {
        ... 
    }
}
public class ProductSaver 
{ 
    public void Save(Product product) 
    {
        ... 
    }
}
public class ProductFinder 
{ 
    public Product FindById(int id) 
    {
        ... 
    }
}
Somethin' ain't right
public class ProductRepository 
{ 
    public void Save(Product product) 
    {
        ... 
    }
}
public class ProductQuery 
{ 
    public Product FindById(int id) 
    {
        ... 
    }
}
Feelin' good now
Or ... just functions
(defn save­product [product] 
  (...)) 
(defn find­product­by­id [id] 
  (...))
Applying OO design principles
o en leads to
functional design
(what's missing)
(what's missing)
Code organization
Inheritance
Encapsulation
Composition
Polymorphism
State management
(code organization)
(ns my.product.repository) 
(defn save [product] 
  (...)) 
(defn find­by­id [id] 
  (...))
(ns my.other.namespace 
  (:require [my.product.repository :as product­repo])) 
(product­repo/find­by­id 42)
(inheritance)
 
(inheritance)
just don't
(encapsulation)
(encapsulation)
Data is not an object
 
(encapsulation)
Data is not an object
Data is immutable
(html [:body 
        [:h1 "Employees"] 
        [:ul 
        (for [person employees] 
          [:li 
            [:h2 (:name person)] 
            [:p (:email person)]])]])
(defn handle [request] 
  {:status 200 
   :headers {"Content­Type" "application/json" 
             "X­Custom­Header" "12345"} 
   :body (json/generate­string 
           {:name "John Wick" 
            :age 42 
            :email "john@wick.name" 
            :hobbies ["guns" "dogs" "judo"]})})
append-child array-map assoc associative? assoc-in bean bigdec bigint biginteger bit-and bit-and-not bit-clear
bit-flip bit-not bit-or bit-set bit-shi -le bit-shi -right bit-test bit-xor blank? branch? butlast byte capitalize cat
char char? char-escape-string char-name-string children coll? compare concat conj cons contains? count
counted? cycle dec dec' decimal? dedupe dense-int-set diff difference disj dissoc distinct distinct? double
down drop drop-last drop-while edit eduction empty empty? end? enumeration-seq escape even? every?
false? ffirst file-seq filter filterv find find-keyword first flatten float float? fnext for format frequencies gensym
get get-in group-by hash-map hash-set identical? inc inc' index insert-child insert-le insert-right int integer?
interleave interpose intersection int-map into into-array int-set iterate iterator-seq join keep keep-indexed key
keys keyword keyword? last lazy-cat lazy-seq le le most le s line-seq list list? list* long lower-case make-
node map map? mapcat map-indexed map-invert mapv max max-key merge merge-with min min-key mod
neg? next nfirst nil? nnext node not not= not-any? not-empty not-every? nth nthnext nthrest num number?
odd? partition partition-all partition-by path peek pmap pop pos? postwalk postwalk-demo postwalk-replace
prev prewalk prewalk-demo prewalk-replace priority-map project quot rand rand-int rand-nth random-sample
range ratio? rational? rationalize reduce reduce-kv reductions re-find re-groups rem re-matcher re-matches
remove rename rename-keys re-pattern repeat repeatedly replace replace-first re-quote-replacement re-seq
rest resultset-seq reverse reversible? right rightmost rights root rseq rsubseq second select select-keys seq
seq? seque sequence sequential? seq-zip set set? short shuffle some some? sort sort-by sorted? sorted-map
sorted-map-by sorted-set sorted-set-by split split-at split-lines split-with str string? subs subseq subset?
subvec superset? symbol symbol? take take-last take-nth take-while to-array-2d transduce tree-seq trim triml
trim-newline trimr true? unchecked-add unchecked-dec unchecked-inc unchecked-multiply unchecked-
negate unchecked-subtract union unsigned-bit-shi -right up update update-in upper-case val vals vec vector
vector? vector-of vector-zip walk when-first xml-seq xml-zip zero? zipmap
(composition)
Life without Objects (w/ Clojure)
(dependency inversion)
Good for decoupling
Good for isolated testing
(oo dependencies)
public class ProfilePage { 
    String render(Repository repo, int customerId) { 
        return toHtml(repo.loadProfile(customerId)); 
    }
}
Repository repo = new SqlRepository(); 
ProfilePage page = new ProfilePage();
String html = page.render(repo, customerId);
(fp dependencies)
(defn render­page [repository­fn customer­id] 
  (to­html (repository­fn customer­id)))
(defn load­from­sql [customer­id] 
  (...))
(render­page load­from­sql customer­id)
(basic fp polymorphism)
All functions implement the "Strategy" pattern
(oo composition)
Repository repo = new SqlRepository(); 
ProfilePage page = new ProfilePage(repo);
page.render(customerId);
(function closure)
(defn inject [f arg1] 
  (fn [arg2] (f arg1 arg2)))
(def render­from­db 
  (inject render­page load­from­sql))
(render­from­db customer­id)
(partial application)
(def render­from­db 
  (partial render­page load­from­sql))
(render­from­db customer­id)
"Object is a collection of partially-applied functions."
( J.B. Rainsberger )
(structural patterns)
Adapter
Decorator
...
("adapter" pattern)
(defn to­view­model [profile] (...)) 
(render­page (comp to­view­model load­from­sql) id)
("decorator" pattern)
(defn traceable [f] 
  (fn [& args] 
    (log/trace "Called with params:" args) 
    (apply f args)))
(render­page (traceable load­from­sql) id)
(polymorphism)
Life without Objects (w/ Clojure)
(oo polymorphism)
"Subtype Polymorphism"
(dispatch on the type of first argument)
public interface JsonObj { 
    String toJson(); 
}
public class JsonString implements JsonObj { 
    private final String value; 
    public JsonString(String value) { 
        this.value = value; 
    }
    public String toJson() { 
        return """ + value + """; 
    }
}
public class JsonList implements JsonObj { 
    private final List<JsonObj> items; 
    public JsonString(JsonObj... items) { 
        this.items = asList(items); 
    }
    public String toJson() { 
        return "[" + items.stream() 
            .map(item ­> item.toJson()) 
            .collect(joining(",")) + "]"; 
    }
}
JsonObj obj = new JsonList( 
    new JsonString("a"), 
    new JsonList( 
        new JsonString("b"), 
        new JsonString("c") 
    ), 
    new JsonString("d") 
); 
System.out.println(obj.toJson()); 
// ["a",["b","c"],"d"]
(limitations)
Subtyping is coupled to implementation
 
 
(limitations)
Subtyping is coupled to implementation
... cannot extend existing types
 
(limitations)
Subtyping is coupled to implementation
... cannot extend existing types
... need wrapper classes
Too constraining!
(clojure protocols)
dispatch on the type of first argument
(defprotocol Json 
  (to­json [this]))
(extend­type String Json 
  (to­json [this] 
    (str """ this """)))
(extend­type List Json 
  (to­json [this] 
    (str "[" (str/join "," (map to­json this)) "]")))
(extend­type nil Json 
  (to­json [this] 
    "null"))
(to­json ["a" ["b" "c"] nil "d"]) 
;;=> ["a",["b","c"],null,"d"]
Why stop there?
(clojure multimethods)
dispatch on anything!
(defmulti greet :country) 
(defmethod greet "PL" [person] 
  (println "Dzień dobry," (:name person))) 
(defmethod greet "FR" [person] 
  (println "Bonjour," (:name person) "!")) 
(defmethod greet :default [person] 
  (println "Hello," (:name person)))
(greet {:name "Jacques" :country "FR"}) 
;;=> Bonjour, Jacques !
(state management)
State Machine / Business Process / Entity
"Class" as a namespace
(def Account 
  {'deposit  (fn [state amount] 
               (update state :balance + amount)) 
   'withdraw (fn [state amount] 
               (if (< amount (state :balance)) 
                 (update state :balance ­ amount) 
                 state))})
(def state0 {:balance 0})
(def state1 ((Account 'deposit)  state0 100)) 
(def state2 ((Account 'withdraw) state1 30)) 
(def state3 ((Account 'withdraw) state2 20))
Partially apply state with "constructor"
(defn new­object [clazz initial­state] 
  .......... 
    .......... 
      ..........)
(def acc (new­object Account {:balance 0})) 
(acc 'deposit 100) 
(acc 'withdraw 30) 
(acc 'withdraw 20)
Partially apply state with "constructor"
(defn new­object [clazz initial­state] 
  (let [state­ref (atom initial­state)] 
    .......... 
      ..........))
(def acc (new­object Account {:balance 0})) 
(acc 'deposit 100) 
(acc 'withdraw 30) 
(acc 'withdraw 20)
Partially apply state with "constructor"
(defn new­object [clazz initial­state] 
  (let [state­ref (atom initial­state)] 
    (fn [method & args] 
      ..........)))
(def acc (new­object Account {:balance 0})) 
(acc 'deposit 100) 
(acc 'withdraw 30) 
(acc 'withdraw 20)
Partially apply state with "constructor"
(defn new­object [clazz initial­state] 
  (let [state­ref (atom initial­state)] 
    (fn [method & args] 
      (apply swap! state­ref (clazz method) args))))
(def acc (new­object Account {:balance 0})) 
(acc 'deposit 100) 
(acc 'withdraw 30) 
(acc 'withdraw 20)
(the takeaway)
Eierlegende Wollmilchsau
(the takeaway)
Object
(google "Clojure Made Simple")
(questions? "Osvaldas Grigas" @ogrigas)
1 of 84

More Related Content

Viewers also liked(9)

Programuotojo karjeros mitaiProgramuotojo karjeros mitai
Programuotojo karjeros mitai
Osvaldas Grigas664 views
Evolution of MacrosEvolution of Macros
Evolution of Macros
Osvaldas Grigas480 views
Name StuffName Stuff
Name Stuff
Osvaldas Grigas778 views
SimplicitySimplicity
Simplicity
Osvaldas Grigas634 views
Framework-less ApplicationsFramework-less Applications
Framework-less Applications
Osvaldas Grigas529 views
SimplicitySimplicity
Simplicity
Agile Lietuva711 views
Chinese marketChinese market
Chinese market
Osvaldas Ciuksys427 views

Similar to Life without Objects (w/ Clojure)(20)

Pune Clojure Course OutlinePune Clojure Course Outline
Pune Clojure Course Outline
Baishampayan Ghose686 views
Introductionto fp with groovyIntroductionto fp with groovy
Introductionto fp with groovy
Isuru Samaraweera201 views
Spark training-in-bangaloreSpark training-in-bangalore
Spark training-in-bangalore
Kelly Technologies285 views
Hadoop trainingin bangaloreHadoop trainingin bangalore
Hadoop trainingin bangalore
appaji intelhunt719 views
R for Pythonistas (PyData NYC 2017)R for Pythonistas (PyData NYC 2017)
R for Pythonistas (PyData NYC 2017)
Christopher Roach776 views
Introduction To ScalaIntroduction To Scala
Introduction To Scala
Peter Maas1.6K views
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
Dmitry Buzdin3.5K views
Contracts in-clojure-peteContracts in-clojure-pete
Contracts in-clojure-pete
jessitron3.4K views
JavaScript Foundations Day1JavaScript Foundations Day1
JavaScript Foundations Day1
Troy Miles677 views
Groovy unleashed Groovy unleashed
Groovy unleashed
Isuru Samaraweera404 views
Introduction to RIntroduction to R
Introduction to R
agnonchik282 views
Advance Scala - Oleg MürkAdvance Scala - Oleg Mürk
Advance Scala - Oleg Mürk
Planet OS1.3K views
LibrettoLibretto
Libretto
Ilya Kazakov426 views

Recently uploaded(20)

The Research Portal of Catalonia: Growing more (information) & more (services)The Research Portal of Catalonia: Growing more (information) & more (services)
The Research Portal of Catalonia: Growing more (information) & more (services)
CSUC - Consorci de Serveis Universitaris de Catalunya51 views
Green Leaf Consulting: Capabilities DeckGreen Leaf Consulting: Capabilities Deck
Green Leaf Consulting: Capabilities Deck
GreenLeafConsulting170 views

Life without Objects (w/ Clojure)