SlideShare una empresa de Scribd logo
1 de 56
Descargar para leer sin conexión
Inside
Data-driven
Schemas
Tommi Reiman
29.2.2019
ClojureD
malli
Chapter 1:
Expectations
• Data-oriented - represent entities and their relationships as data.
• Data-driven - create DSLs in data structures and write interpreters for
them
Clojure <3 Data
https:!"clojureverse.org/t/clojure-a-pragmatic-data-driven-language/4565/5Eric Normand
It’s just data!
;; restaurant
{:name "Lie Mi"
:tags #{:street :vietnamese}
:stars 4.3
:address {:street "Hämeenkatu 14"
:city “Tampere"}}
It’s just data!
{:type :restaurant
:name "Lie Mi"
:tags #{:street :vietnamese}
:stars 4.3
:address {:street "Hämeenkatu 14"
:city “Tampere"}}
It’s just data!
{:type :customers.1234/restaurant
:name "Lie Mi"
:tags #{:street :vietnamese}
:stars 4.3
:address {:street "Hämeenkatu 14"
:city “Tampere"}}
It’s just data!
{:mydomain/type :mydomain.types/restaurant
:mydomain.restaurant/name "Lie Mi"
:mydomain.restaurant/tags #$:street :vietnamese}
:mydomain.restaurant/stars 4.3
:mydomain.restaurant/address {:mydomain.address/street "Hämeenkatu 14"
:mydomain.address/city "Tampere"}}
It’s just data!
{:type :restaurant
:name "Lie Mi"
:tags #{:street :vietnamese}
:stars 4.3
:address {:street "Hämeenkatu 14”
:city "Tampere"}}
It’s just data!
(-> {:type :restaurant
:name "Lie Mi"
:tags #{:street :vietnamese}
:stars 4.3
:address {:street "Hämeenkatu 14"
:city "Tampere"}})
(select-keys [:name :tags :address]))
(assoc-in [:address :zip] 33100))
;{:name "Lie Mi"
; :tags #{:vietnamese :street}
; :address {:street "Hämeenkatu 14"
; :city "Tampere"
; :zip 33100}}
https:!"devrant.com/rants/2192467/on-category-theory
Types, Schemas and Specs
Malcolm 16:45
Awesome!
Awesome!
Awesome!
One tool for everything?
Expectations
We are building dynamic multi-tenant systems where data-
models should be data too: they should drive the runtime value
transformations, forms and processes.We should be able to edit
the models at runtime, persist them and load them back from
database and over the wire, for both Clojure and ClojureScript.
Think of JSON Schema, but for EDN and Clojure/Script.
If you have expectations (of others) that aren't
being met, those expectations are your own
responsibility.You are responsible for your own
needs. If you want things, make them.
- Rich Hickey
https:!"gist.github.com/richhickey/1563cddea1002958f96e7ba9519972d9
Chapter 2:
DIY
The Idea
• Schemas as data (hiccup, reagent, internal.*, reitit)
• Take the best parts of Plumatic Schema, clojure.spec & JSON Schema
• Programming with Schemas, first class meta-data
• Focus on Developer Experience
• Small core, extendable
• Create a Prototype, experiment, have fun
Malli
/ˈmɑlːi/, [ˈmɑlːi]
Syntax (Schema AST)
[:vector {:min 0, :max 10} int?]
type %& [type ?properties & children]
{:type :vector
:properties {:min 0, :max 10}
:children [int?]}
Schemas
int?
[:= 43]
[:tuple double? double?]
[:and int? [:> 18]]
[:map
[:x int?]
[:y int?]]
AST '( (resolve) '( IntoSchema opts '( Schema
Validation
(require '[malli.core :as m])
(m/validate int? 1)
; => true
(m/validate int? "kikka")
; => false
(m/validate [:maybe keyword?] nil)
; => true
(m/validate [:vector int?] [1 2 3])
; => true
Complex Schema
(def CompositeMap
[:and
[:map {:closed true}
[:x pos-int?]
[:y pos-int?]]
[:fn {:error/message "x )* y"}
(fn [{:keys [x y]}] (> x y))]])
(m/validate CompositeMap {:x 3, :y 2})
; '( true
(m/validate CompositeMap {:x 1, :y 2})
; '( false
Complex Schema
(def CompositeMap
[:and
[:map {:closed true}
[:x pos-int?]
[:y pos-int?]]
[:fn {:error/message "x )* y"}
'(fn [{:keys [x y]}] (> x y))]])
(m/validate CompositeMap {:x 3, :y 2})
; '( true
(m/validate CompositeMap {:x 1, :y 2})
; '( falseMichiel Borkent
Forms
(def CompositeMap
[:and
[:map {:closed true}
[:x pos-int?]
[:y pos-int?]]
[:fn {:error/message "x )* y"}
'(fn [{:keys [x y]}] (> x y))]])
(m/form CompositeMap)
;[:and
; [:map {:closed true}
; [:x pos-int?]
; [:y pos-int?]]
; [:fn {:error/message "x )* y"}
; (fn [{:keys [x y]}] (> x y))]]
• Works on all of JVM, ClojureScript & GraalVM
Durable Schemas
Michiel Borkent
(require '[malli.edn :as edn])
(+, CompositeMap
(edn/write-string)
(edn/read-string)
(m/validate {:x 3, :y 2}))
; '( true
• Inspired by clojure.spec
Explaining Data
(m/explain CompositeMap {:x -1, :y -2, :EXTRA true})
;{:schema …,
; :value {:x -1, :y -2, :EXTRA true},
; :errors [{:path [1 2 1], :in [:x], :schema pos-int?, :value -1}
; {:path [1 3 1], :in [:y], :schema pos-int?, :value -2}
; {:path [1], :in [:EXTRA], :schema …, :type :malli.core/extra-key}]}
AlexRich
Errors for Humans
(require '[malli.error :as me])
(+, CompositeMap
(m/explain {:x -3, :y -2, :EXTRA true})
(me/humanize))
;{:x ["should be positive int"]
; :y ["should be positive int"]
; :EXTRA ["disallowed key"]
; :malli/error ["x )* y"]}
Alexander Kiel
GeneratingValues
(require '[malli.generator :as mg])
(mg/generate keyword?)
; '( :?
(mg/generate [:enum "a" "b" "c"] {:seed 42})
; '( "a"
(mg/generate
[:re #"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9-.]+.[a-zA-Z]{2,63}$"]
{:seed 42, :size 10})
; '( "CaR@MavCk70OHiX.yZ"
GeneratingValues
(mg/generate
[:and {:gen/elements ["kikka" "kukka" "kakka"]} string?])
; '( "kikka"
(mg/generate
[:and {:gen/fmap '(partial str "kikka_")} string?]
{:seed 10, :size 10})
/0 '( "kikka_WT3K0yax2"
(require '[clojure.test.check.generators :as gen])
(mg/generate
[:sequential {:gen/gen (gen/list gen/neg-int)} int?]
{:size 42, :seed 42})
; '( (-37 -13 -13 -24 -20 -11 -34 -40 -22 0 -10)
Gary Frederics
Inferring Schemas
(def lie-mi
{:type :restaurant
:name "Lie Mi"
:tags #$:street :vietnamese}
:stars 4.3
:address {:street "Hämeenkatu 14"
:city "Tampere"}})
(def wanha-tappi
{:type :restaurant
:name "Wanha Tappi"
:tags #$:burgers :beer}
:address {:street "Jokipohjantie 18"
:city "Tampere"}})
Stathis Sideris
(require '[malli.provider :as mp])
(def Restaurant
(mp/provide [lie-mi wanha-tappi]))
Restaurant
;[:map
; [:type keyword?]
; [:name string?]
; [:tags [:set keyword?]]
; [:stars {:optional true} double?]
; [:address
; [:map
; [:street string?]
; [:city string?]]]]
Programming with Schemas
(require '[malli.util :as mu])
(+, [:map
[:a int?]
[:b string?]
[:c [:map
[:d int?]
[:e keyword?]]]]
(mu/closed-schema)
(mu/select-keys [:a :c])
(mu/update-in [:c] mu/dissoc :e))
;[:map {:closed true}
; [:a int?]
; [:c [:map {:closed true}
; [:d int?]]]]
Metosin
Walking over Schemas
• Generic schema walking using theVisitor-pattern (CLJ-2251)
• To JSON Schema, Swagger2, Map-syntax etc.
(require '[malli.json-schema :as json-schema])
(json-schema/transform
[:map {:title "a map"}
[:x int?]
[:y {:optional true} inst?]])
;{:type "object"
; :title "a map"
; :properties {:x {:type "integer", :format "int64"}
; :y {:type "string", :format "date-time"}
; :required [:x]}
Walking over Schemas
(defn closed-schema
"Closes recursively all :map schemas by adding `{:closed true}`
property, unless schema explicitely open with `{:closed false}`"
([schema]
(closed-schema schema nil))
([schema options]
(m/accept
schema
(m/schema-visitor
(fn [schema]
(if (-open-map? schema options)
(update-properties schema c/assoc :closed true)
schema))))))
• Open Schemas to embrace growth (and typing errors)
• Closed Schemas and Spell Checking to the rescue?
Spell Checking
(def nante-eck
{:type :restaurant
:name "Nante-Eck"
:tags #$:traditional :vegan}
:starz 4.2
:address {:streez "Unter den Linden 35"
:city "Berlin"}})
Restaurant
;[:map
; [:type keyword?]
; [:name string?]
; [:tags [:set keyword?]]
; [:stars {:optional true} double?]
; [:address
; [:map
; [:street string?]
; [:city string?]]]]
Spell Checking
(+, Restaurant
(m/explain nante-eck)
(me/humanize))
; {:address {:street ["missing required key"]}}
(+, Restaurant
(mu/closed-schema)
(m/explain nante-eck)
(me/humanize))
;{:address {:street ["missing required key"]
; :streez ["disallowed key"]}
; :starz ["disallowed key"]}
(+, Restaurant
(mu/closed-schema)
(m/explain nante-eck)
(me/with-spell-checking)
(me/humanize))
;{:address {:streez ["should be spelled :street"]}
; :starz ["should be spelled :stars"]}
Bruce Hauman
• Fully re-written engine, built with interceptors
• Encode and decode chains with enter & leave phases
• Json, string, strip-extra-keys & default-value-transformer
• Schemas can define transformation via properties
• Fast
ValueTransformers
(m/decode int? "42" (mt/string-transformer))
; '( 42
(m/encode int? 42 (mt/string-transformer))
; '( ”42”
(require '[malli.transform :as mt])
(def json-transformer
(mt/transformer
(mt/strip-extra-keys-transformer)
(mt/json-transformer)
(mt/default-value-transformer)))
(def json+,Restaurant
(m/decoder Restaurant json-transformer))
(json+,Restaurant
{:type "restaurant"
:DARK "ORKO"
:name "Mustafas Gemüse Kebab"
:tags ["kebab" "yoghurt"]
:address {:street "Mehringdamm 32"
:EXTRA "KEY"
:city "Berlin"}})
;{:type :restaurant,
; :name "Mustafas Gemüse Kebab",
; :tags #$:kebab :yoghurt},
; :address {:street "Mehringdamm 32"
; :city "Berlin"}}
(require '[criterium.core :as cc])
/0 1.8µs
(cc/quick-bench
(+, json
(update :type keyword)
(update :tags (comp set (partial map keyword)))
(select-keys [:type :name :tags :address])
(update :address select-keys [:street :city])))
/0 1.9µs
(cc/quick-bench (json+,Restaurant json))
(def json+,Order
(m/decoder
[:map
[:id int?]
[:tags string?]
[:address
[:map
[:street string?]
[:zip string?]
[:country string?]]]]
(mt/json-transformer)))
json+,Order
; '( #object[clojure.core$identity]
(require '[criterium.core :as cc])
/0 1.8µs
(cc/quick-bench
(+, json
(update :type keyword)
(update :tags (comp set (partial map keyword)))
(select-keys [:type :name :tags :address])
(update :address select-keys [:street :city])))
/0 1.9µs
(cc/quick-bench (json+,Restaurant json))
(def json+,Order
(m/decoder
[:map
[:id int?]
[:tags [:vector string?]]
[:address
[:map
[:street string?]
[:zip string?]
[:country string?]]]]
(mt/json-transformer)))
json+,Order
; '( #object[clojure.core$identity]
(require '[criterium.core :as cc])
/0 1.8µs
(cc/quick-bench
(+, json
(update :type keyword)
(update :tags (comp set (partial map keyword)))
(select-keys [:type :name :tags :address])
(update :address select-keys [:street :city])))
/0 1.9µs
(cc/quick-bench (json+,Restaurant json))
(def json+,Order
(m/decoder
[:map
[:id int?]
[:tags [:vector string?]]
[:address
[:map
[:street string?]
[:zip string?]
[:country string?]]]]
(mt/json-transformer)))
json+,Order
; '( #object[clojure.core$identity]
Chapter 3:
The Future
• reitit-malli coercion module, since 0.4.0
• Orders of magnitude faster coercion than with reitit-spec
• Small example application: https://github.com/metosin/reitit/tree/
master/examples/ring-malli-swagger
• A new module & configuration system?
reitit + malli
• … and custom Schemas to inline external stuff, maybe like:
Schema providers (F#)
(m/validate
[:json-schema
{:type "object"
:properties {:x {:type "integer", :format "int64"}
:y {:type "integer", :format "int64"}}
:required [:x]}]
{:x 1, :y 2})
; => true
• Have generated forms in four decades, just one more time ;)
• Good companion for FSMs and rule engines, rapid prototyping
• https://www.youtube.com/watch?v=IekPZpfbdaI
• https://github.com/domino-clj + malli
Generating UIs
Dmitri Carmen Nikola
Schema '( UI %& Schema UI-Schema '( UI
• Inspired by expound, backed by metosin/virhe
Errors for Developers
Ben Brinkerhoff
• malli-powered code checking: https://github.com/teknql/aave
• Add support schematized defn and fn
• Emit clj-kondo type annotations
• Schemas for Schemas AST
• Test utilities
MoreTooling
Ryan Schukler
Michiel Borkent
• Pre-alpha, still experimenting, but core is 90% code complete
• Was public announcement by the community long time ago
• Many active contributors and some users too
• Big thanks to all people and libraries for source of innovation
• Goal to get official release out in a month or two
• Learned a lot, has been fun to develop
Current Status
• Understand and manage your expectations
• Clojure is awesome tool for building data-driven systems
• Malli is a fresh new schema library for Clojure/Script, try it out
• If you’re interested in type and schema systems, consider contributing
• https://github.com/metosin/malli
• #malli on slack
Takeaways
Questions?
Tommi Reiman
tommi@metosin.fi
@ikitommi
https://www.github.com/metosin/malli
malli.io
Multi-Schemas
(def MultiSchema
[:multi {:dispatch :type}
[:sized [:map
[:type [12 :sized]]
[:size int?]]]
[:human [:map
[:type [12 :human]]
[:name string?]]]])
(m/validate MultiSchema {:type :sized, :size 10})
; '( true
(m/validate MultiSchema {:type :human, :name “Tiina"})
; '( true
Multi-Schemas
(def MultiSchema
[:multi {:dispatch 'first}
[:sized [:tuple [12 :sized] [:map [:size int?]]]]
[:human [:tuple [12 :human] [:map [:name string?]]]]])
(m/validate MultiSchema [:sized {:size 10}])
; '( true
(m/validate MultiSchema [:human {:name "Tiina"}])
; '( true

Más contenido relacionado

La actualidad más candente

Idiomatic Kotlin
Idiomatic KotlinIdiomatic Kotlin
Idiomatic Kotlinintelliyole
 
Type script - advanced usage and practices
Type script  - advanced usage and practicesType script  - advanced usage and practices
Type script - advanced usage and practicesIwan van der Kleijn
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016Manoj Kumar
 
Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017Roman Elizarov
 
Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017Sunghyouk Bae
 
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Scott Wlaschin
 
The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)Scott Wlaschin
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Scott Wlaschin
 
Jpa 잘 (하는 척) 하기
Jpa 잘 (하는 척) 하기Jpa 잘 (하는 척) 하기
Jpa 잘 (하는 척) 하기경원 이
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Scott Wlaschin
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기Arawn Park
 
Trends and future of C++: Evolving a systems language for performance - by Bj...
Trends and future of C++: Evolving a systems language for performance - by Bj...Trends and future of C++: Evolving a systems language for performance - by Bj...
Trends and future of C++: Evolving a systems language for performance - by Bj...devstonez
 
Purely Functional Data Structures in Scala
Purely Functional Data Structures in ScalaPurely Functional Data Structures in Scala
Purely Functional Data Structures in ScalaVladimir Kostyukov
 
JavaScript: Variables and Functions
JavaScript: Variables and FunctionsJavaScript: Variables and Functions
JavaScript: Variables and FunctionsJussi Pohjolainen
 
A Brief Intro to Scala
A Brief Intro to ScalaA Brief Intro to Scala
A Brief Intro to ScalaTim Underwood
 
[112]rest에서 graph ql과 relay로 갈아타기 이정우
[112]rest에서 graph ql과 relay로 갈아타기 이정우[112]rest에서 graph ql과 relay로 갈아타기 이정우
[112]rest에서 graph ql과 relay로 갈아타기 이정우NAVER D2
 
HTML Dasar : #5 Heading
HTML Dasar : #5 HeadingHTML Dasar : #5 Heading
HTML Dasar : #5 HeadingSandhika Galih
 

La actualidad más candente (20)

Idiomatic Kotlin
Idiomatic KotlinIdiomatic Kotlin
Idiomatic Kotlin
 
Type script - advanced usage and practices
Type script  - advanced usage and practicesType script  - advanced usage and practices
Type script - advanced usage and practices
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016
 
Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017
 
Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017
 
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
 
Functions in javascript
Functions in javascriptFunctions in javascript
Functions in javascript
 
The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)
 
Jpa 잘 (하는 척) 하기
Jpa 잘 (하는 척) 하기Jpa 잘 (하는 척) 하기
Jpa 잘 (하는 척) 하기
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
 
Trends and future of C++: Evolving a systems language for performance - by Bj...
Trends and future of C++: Evolving a systems language for performance - by Bj...Trends and future of C++: Evolving a systems language for performance - by Bj...
Trends and future of C++: Evolving a systems language for performance - by Bj...
 
Purely Functional Data Structures in Scala
Purely Functional Data Structures in ScalaPurely Functional Data Structures in Scala
Purely Functional Data Structures in Scala
 
JavaScript: Variables and Functions
JavaScript: Variables and FunctionsJavaScript: Variables and Functions
JavaScript: Variables and Functions
 
XSLT. Basic.
XSLT. Basic.XSLT. Basic.
XSLT. Basic.
 
A Brief Intro to Scala
A Brief Intro to ScalaA Brief Intro to Scala
A Brief Intro to Scala
 
[112]rest에서 graph ql과 relay로 갈아타기 이정우
[112]rest에서 graph ql과 relay로 갈아타기 이정우[112]rest에서 graph ql과 relay로 갈아타기 이정우
[112]rest에서 graph ql과 relay로 갈아타기 이정우
 
Full Text Search In PostgreSQL
Full Text Search In PostgreSQLFull Text Search In PostgreSQL
Full Text Search In PostgreSQL
 
HTML Dasar : #5 Heading
HTML Dasar : #5 HeadingHTML Dasar : #5 Heading
HTML Dasar : #5 Heading
 

Similar a Malli: inside data-driven schemas

Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?osfameron
 
Slaying the Dragon: Implementing a Programming Language in Ruby
Slaying the Dragon: Implementing a Programming Language in RubySlaying the Dragon: Implementing a Programming Language in Ruby
Slaying the Dragon: Implementing a Programming Language in RubyJason Yeo Jie Shun
 
ELK Stack - Turn boring logfiles into sexy dashboard
ELK Stack - Turn boring logfiles into sexy dashboardELK Stack - Turn boring logfiles into sexy dashboard
ELK Stack - Turn boring logfiles into sexy dashboardGeorg Sorst
 
Let's build a parser!
Let's build a parser!Let's build a parser!
Let's build a parser!Boy Baukema
 
A Rusty introduction to Apache Arrow and how it applies to a time series dat...
A Rusty introduction to Apache Arrow and how it applies to a  time series dat...A Rusty introduction to Apache Arrow and how it applies to a  time series dat...
A Rusty introduction to Apache Arrow and how it applies to a time series dat...Andrew Lamb
 
What you forgot from your Computer Science Degree
What you forgot from your Computer Science DegreeWhat you forgot from your Computer Science Degree
What you forgot from your Computer Science DegreeStephen Darlington
 
A miało być tak... bez wycieków
A miało być tak... bez wyciekówA miało być tak... bez wycieków
A miało być tak... bez wyciekówKonrad Kokosa
 
Patterns for slick database applications
Patterns for slick database applicationsPatterns for slick database applications
Patterns for slick database applicationsSkills Matter
 
MongoDB Analytics
MongoDB AnalyticsMongoDB Analytics
MongoDB Analyticsdatablend
 
Ruby Language - A quick tour
Ruby Language - A quick tourRuby Language - A quick tour
Ruby Language - A quick touraztack
 
WTF Oriented Programming, com Fabio Akita
WTF Oriented Programming, com Fabio AkitaWTF Oriented Programming, com Fabio Akita
WTF Oriented Programming, com Fabio AkitaiMasters
 
Complex Values
Complex ValuesComplex Values
Complex ValuesESUG
 
Extreme Swift
Extreme SwiftExtreme Swift
Extreme SwiftMovel
 
Dublin Ireland Spark Meetup October 15, 2015
Dublin Ireland Spark Meetup October 15, 2015Dublin Ireland Spark Meetup October 15, 2015
Dublin Ireland Spark Meetup October 15, 2015eddiebaggott
 
Elasticsearch intro output
Elasticsearch intro outputElasticsearch intro output
Elasticsearch intro outputTom Chen
 
Scalding big ADta
Scalding big ADtaScalding big ADta
Scalding big ADtab0ris_1
 
RDataMining slides-r-programming
RDataMining slides-r-programmingRDataMining slides-r-programming
RDataMining slides-r-programmingYanchang Zhao
 

Similar a Malli: inside data-driven schemas (20)

Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?
 
Slaying the Dragon: Implementing a Programming Language in Ruby
Slaying the Dragon: Implementing a Programming Language in RubySlaying the Dragon: Implementing a Programming Language in Ruby
Slaying the Dragon: Implementing a Programming Language in Ruby
 
R Language
R LanguageR Language
R Language
 
ELK Stack - Turn boring logfiles into sexy dashboard
ELK Stack - Turn boring logfiles into sexy dashboardELK Stack - Turn boring logfiles into sexy dashboard
ELK Stack - Turn boring logfiles into sexy dashboard
 
Let's build a parser!
Let's build a parser!Let's build a parser!
Let's build a parser!
 
ES6 is Nigh
ES6 is NighES6 is Nigh
ES6 is Nigh
 
A Rusty introduction to Apache Arrow and how it applies to a time series dat...
A Rusty introduction to Apache Arrow and how it applies to a  time series dat...A Rusty introduction to Apache Arrow and how it applies to a  time series dat...
A Rusty introduction to Apache Arrow and how it applies to a time series dat...
 
What you forgot from your Computer Science Degree
What you forgot from your Computer Science DegreeWhat you forgot from your Computer Science Degree
What you forgot from your Computer Science Degree
 
A miało być tak... bez wycieków
A miało być tak... bez wyciekówA miało być tak... bez wycieków
A miało być tak... bez wycieków
 
R programming language
R programming languageR programming language
R programming language
 
Patterns for slick database applications
Patterns for slick database applicationsPatterns for slick database applications
Patterns for slick database applications
 
MongoDB Analytics
MongoDB AnalyticsMongoDB Analytics
MongoDB Analytics
 
Ruby Language - A quick tour
Ruby Language - A quick tourRuby Language - A quick tour
Ruby Language - A quick tour
 
WTF Oriented Programming, com Fabio Akita
WTF Oriented Programming, com Fabio AkitaWTF Oriented Programming, com Fabio Akita
WTF Oriented Programming, com Fabio Akita
 
Complex Values
Complex ValuesComplex Values
Complex Values
 
Extreme Swift
Extreme SwiftExtreme Swift
Extreme Swift
 
Dublin Ireland Spark Meetup October 15, 2015
Dublin Ireland Spark Meetup October 15, 2015Dublin Ireland Spark Meetup October 15, 2015
Dublin Ireland Spark Meetup October 15, 2015
 
Elasticsearch intro output
Elasticsearch intro outputElasticsearch intro output
Elasticsearch intro output
 
Scalding big ADta
Scalding big ADtaScalding big ADta
Scalding big ADta
 
RDataMining slides-r-programming
RDataMining slides-r-programmingRDataMining slides-r-programming
RDataMining slides-r-programming
 

Más de Metosin Oy

Navigating container technology for enhanced security by Niklas Saari
Navigating container technology for enhanced security by Niklas SaariNavigating container technology for enhanced security by Niklas Saari
Navigating container technology for enhanced security by Niklas SaariMetosin Oy
 
Where is Technical Debt?
Where is Technical Debt?Where is Technical Debt?
Where is Technical Debt?Metosin Oy
 
Creating an experimental GraphQL formatter using Clojure, Instaparse, and Gra...
Creating an experimental GraphQL formatter using Clojure, Instaparse, and Gra...Creating an experimental GraphQL formatter using Clojure, Instaparse, and Gra...
Creating an experimental GraphQL formatter using Clojure, Instaparse, and Gra...Metosin Oy
 
Serverless Clojure and ML prototyping: an experience report
Serverless Clojure and ML prototyping: an experience reportServerless Clojure and ML prototyping: an experience report
Serverless Clojure and ML prototyping: an experience reportMetosin Oy
 
Naked Performance With Clojure
Naked Performance With ClojureNaked Performance With Clojure
Naked Performance With ClojureMetosin Oy
 
Fun with errors? - Clojure Finland Meetup 26.3.2019 Tampere
Fun with errors? - Clojure Finland Meetup 26.3.2019 TampereFun with errors? - Clojure Finland Meetup 26.3.2019 Tampere
Fun with errors? - Clojure Finland Meetup 26.3.2019 TampereMetosin Oy
 
Clojutre Real Life (2012 ClojuTRE Retro Edition)
Clojutre Real Life (2012 ClojuTRE Retro Edition)Clojutre Real Life (2012 ClojuTRE Retro Edition)
Clojutre Real Life (2012 ClojuTRE Retro Edition)Metosin Oy
 
The Ancient Art of Data-Driven - reitit, the library -
The Ancient Art of Data-Driven - reitit, the library - The Ancient Art of Data-Driven - reitit, the library -
The Ancient Art of Data-Driven - reitit, the library - Metosin Oy
 
Craft Beer & Clojure
Craft Beer & ClojureCraft Beer & Clojure
Craft Beer & ClojureMetosin Oy
 
Performance and Abstractions
Performance and AbstractionsPerformance and Abstractions
Performance and AbstractionsMetosin Oy
 
ClojuTRE2016 Opening slides
ClojuTRE2016 Opening slidesClojuTRE2016 Opening slides
ClojuTRE2016 Opening slidesMetosin Oy
 
Schema tools-and-trics-and-quick-intro-to-clojure-spec-22.6.2016
Schema tools-and-trics-and-quick-intro-to-clojure-spec-22.6.2016Schema tools-and-trics-and-quick-intro-to-clojure-spec-22.6.2016
Schema tools-and-trics-and-quick-intro-to-clojure-spec-22.6.2016Metosin Oy
 
ClojuTRE - a (very) brief history
ClojuTRE - a (very) brief historyClojuTRE - a (very) brief history
ClojuTRE - a (very) brief historyMetosin Oy
 
Wieldy remote apis with Kekkonen - ClojureD 2016
Wieldy remote apis with Kekkonen - ClojureD 2016Wieldy remote apis with Kekkonen - ClojureD 2016
Wieldy remote apis with Kekkonen - ClojureD 2016Metosin Oy
 
ClojuTRE2015: Kekkonen - making your Clojure web APIs more awesome
ClojuTRE2015: Kekkonen - making your Clojure web APIs more awesomeClojuTRE2015: Kekkonen - making your Clojure web APIs more awesome
ClojuTRE2015: Kekkonen - making your Clojure web APIs more awesomeMetosin Oy
 
Clojure in real life 17.10.2014
Clojure in real life 17.10.2014Clojure in real life 17.10.2014
Clojure in real life 17.10.2014Metosin Oy
 
Euroclojure2014: Schema & Swagger - making your Clojure web APIs more awesome
Euroclojure2014: Schema & Swagger - making your Clojure web APIs more awesomeEuroclojure2014: Schema & Swagger - making your Clojure web APIs more awesome
Euroclojure2014: Schema & Swagger - making your Clojure web APIs more awesomeMetosin Oy
 
Swaggered web apis in Clojure
Swaggered web apis in ClojureSwaggered web apis in Clojure
Swaggered web apis in ClojureMetosin Oy
 

Más de Metosin Oy (18)

Navigating container technology for enhanced security by Niklas Saari
Navigating container technology for enhanced security by Niklas SaariNavigating container technology for enhanced security by Niklas Saari
Navigating container technology for enhanced security by Niklas Saari
 
Where is Technical Debt?
Where is Technical Debt?Where is Technical Debt?
Where is Technical Debt?
 
Creating an experimental GraphQL formatter using Clojure, Instaparse, and Gra...
Creating an experimental GraphQL formatter using Clojure, Instaparse, and Gra...Creating an experimental GraphQL formatter using Clojure, Instaparse, and Gra...
Creating an experimental GraphQL formatter using Clojure, Instaparse, and Gra...
 
Serverless Clojure and ML prototyping: an experience report
Serverless Clojure and ML prototyping: an experience reportServerless Clojure and ML prototyping: an experience report
Serverless Clojure and ML prototyping: an experience report
 
Naked Performance With Clojure
Naked Performance With ClojureNaked Performance With Clojure
Naked Performance With Clojure
 
Fun with errors? - Clojure Finland Meetup 26.3.2019 Tampere
Fun with errors? - Clojure Finland Meetup 26.3.2019 TampereFun with errors? - Clojure Finland Meetup 26.3.2019 Tampere
Fun with errors? - Clojure Finland Meetup 26.3.2019 Tampere
 
Clojutre Real Life (2012 ClojuTRE Retro Edition)
Clojutre Real Life (2012 ClojuTRE Retro Edition)Clojutre Real Life (2012 ClojuTRE Retro Edition)
Clojutre Real Life (2012 ClojuTRE Retro Edition)
 
The Ancient Art of Data-Driven - reitit, the library -
The Ancient Art of Data-Driven - reitit, the library - The Ancient Art of Data-Driven - reitit, the library -
The Ancient Art of Data-Driven - reitit, the library -
 
Craft Beer & Clojure
Craft Beer & ClojureCraft Beer & Clojure
Craft Beer & Clojure
 
Performance and Abstractions
Performance and AbstractionsPerformance and Abstractions
Performance and Abstractions
 
ClojuTRE2016 Opening slides
ClojuTRE2016 Opening slidesClojuTRE2016 Opening slides
ClojuTRE2016 Opening slides
 
Schema tools-and-trics-and-quick-intro-to-clojure-spec-22.6.2016
Schema tools-and-trics-and-quick-intro-to-clojure-spec-22.6.2016Schema tools-and-trics-and-quick-intro-to-clojure-spec-22.6.2016
Schema tools-and-trics-and-quick-intro-to-clojure-spec-22.6.2016
 
ClojuTRE - a (very) brief history
ClojuTRE - a (very) brief historyClojuTRE - a (very) brief history
ClojuTRE - a (very) brief history
 
Wieldy remote apis with Kekkonen - ClojureD 2016
Wieldy remote apis with Kekkonen - ClojureD 2016Wieldy remote apis with Kekkonen - ClojureD 2016
Wieldy remote apis with Kekkonen - ClojureD 2016
 
ClojuTRE2015: Kekkonen - making your Clojure web APIs more awesome
ClojuTRE2015: Kekkonen - making your Clojure web APIs more awesomeClojuTRE2015: Kekkonen - making your Clojure web APIs more awesome
ClojuTRE2015: Kekkonen - making your Clojure web APIs more awesome
 
Clojure in real life 17.10.2014
Clojure in real life 17.10.2014Clojure in real life 17.10.2014
Clojure in real life 17.10.2014
 
Euroclojure2014: Schema & Swagger - making your Clojure web APIs more awesome
Euroclojure2014: Schema & Swagger - making your Clojure web APIs more awesomeEuroclojure2014: Schema & Swagger - making your Clojure web APIs more awesome
Euroclojure2014: Schema & Swagger - making your Clojure web APIs more awesome
 
Swaggered web apis in Clojure
Swaggered web apis in ClojureSwaggered web apis in Clojure
Swaggered web apis in Clojure
 

Último

CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistandanishmna97
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Victor Rentea
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Angeliki Cooney
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...apidays
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...apidays
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdfSandro Moreira
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024The Digital Insurer
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Zilliz
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Jeffrey Haguewood
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxRustici Software
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontologyjohnbeverley2021
 

Último (20)

CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 

Malli: inside data-driven schemas

  • 1.
  • 3.
  • 4.
  • 6. • Data-oriented - represent entities and their relationships as data. • Data-driven - create DSLs in data structures and write interpreters for them Clojure <3 Data https:!"clojureverse.org/t/clojure-a-pragmatic-data-driven-language/4565/5Eric Normand
  • 7.
  • 8. It’s just data! ;; restaurant {:name "Lie Mi" :tags #{:street :vietnamese} :stars 4.3 :address {:street "Hämeenkatu 14" :city “Tampere"}}
  • 9. It’s just data! {:type :restaurant :name "Lie Mi" :tags #{:street :vietnamese} :stars 4.3 :address {:street "Hämeenkatu 14" :city “Tampere"}}
  • 10. It’s just data! {:type :customers.1234/restaurant :name "Lie Mi" :tags #{:street :vietnamese} :stars 4.3 :address {:street "Hämeenkatu 14" :city “Tampere"}}
  • 11. It’s just data! {:mydomain/type :mydomain.types/restaurant :mydomain.restaurant/name "Lie Mi" :mydomain.restaurant/tags #$:street :vietnamese} :mydomain.restaurant/stars 4.3 :mydomain.restaurant/address {:mydomain.address/street "Hämeenkatu 14" :mydomain.address/city "Tampere"}}
  • 12. It’s just data! {:type :restaurant :name "Lie Mi" :tags #{:street :vietnamese} :stars 4.3 :address {:street "Hämeenkatu 14” :city "Tampere"}}
  • 13. It’s just data! (-> {:type :restaurant :name "Lie Mi" :tags #{:street :vietnamese} :stars 4.3 :address {:street "Hämeenkatu 14" :city "Tampere"}}) (select-keys [:name :tags :address])) (assoc-in [:address :zip] 33100)) ;{:name "Lie Mi" ; :tags #{:vietnamese :street} ; :address {:street "Hämeenkatu 14" ; :city "Tampere" ; :zip 33100}}
  • 15. Types, Schemas and Specs Malcolm 16:45 Awesome! Awesome! Awesome!
  • 16. One tool for everything?
  • 17. Expectations We are building dynamic multi-tenant systems where data- models should be data too: they should drive the runtime value transformations, forms and processes.We should be able to edit the models at runtime, persist them and load them back from database and over the wire, for both Clojure and ClojureScript. Think of JSON Schema, but for EDN and Clojure/Script.
  • 18. If you have expectations (of others) that aren't being met, those expectations are your own responsibility.You are responsible for your own needs. If you want things, make them. - Rich Hickey https:!"gist.github.com/richhickey/1563cddea1002958f96e7ba9519972d9
  • 20. The Idea • Schemas as data (hiccup, reagent, internal.*, reitit) • Take the best parts of Plumatic Schema, clojure.spec & JSON Schema • Programming with Schemas, first class meta-data • Focus on Developer Experience • Small core, extendable • Create a Prototype, experiment, have fun
  • 22. Syntax (Schema AST) [:vector {:min 0, :max 10} int?] type %& [type ?properties & children] {:type :vector :properties {:min 0, :max 10} :children [int?]}
  • 23. Schemas int? [:= 43] [:tuple double? double?] [:and int? [:> 18]] [:map [:x int?] [:y int?]] AST '( (resolve) '( IntoSchema opts '( Schema
  • 24. Validation (require '[malli.core :as m]) (m/validate int? 1) ; => true (m/validate int? "kikka") ; => false (m/validate [:maybe keyword?] nil) ; => true (m/validate [:vector int?] [1 2 3]) ; => true
  • 25. Complex Schema (def CompositeMap [:and [:map {:closed true} [:x pos-int?] [:y pos-int?]] [:fn {:error/message "x )* y"} (fn [{:keys [x y]}] (> x y))]]) (m/validate CompositeMap {:x 3, :y 2}) ; '( true (m/validate CompositeMap {:x 1, :y 2}) ; '( false
  • 26. Complex Schema (def CompositeMap [:and [:map {:closed true} [:x pos-int?] [:y pos-int?]] [:fn {:error/message "x )* y"} '(fn [{:keys [x y]}] (> x y))]]) (m/validate CompositeMap {:x 3, :y 2}) ; '( true (m/validate CompositeMap {:x 1, :y 2}) ; '( falseMichiel Borkent
  • 27. Forms (def CompositeMap [:and [:map {:closed true} [:x pos-int?] [:y pos-int?]] [:fn {:error/message "x )* y"} '(fn [{:keys [x y]}] (> x y))]]) (m/form CompositeMap) ;[:and ; [:map {:closed true} ; [:x pos-int?] ; [:y pos-int?]] ; [:fn {:error/message "x )* y"} ; (fn [{:keys [x y]}] (> x y))]]
  • 28. • Works on all of JVM, ClojureScript & GraalVM Durable Schemas Michiel Borkent (require '[malli.edn :as edn]) (+, CompositeMap (edn/write-string) (edn/read-string) (m/validate {:x 3, :y 2})) ; '( true
  • 29. • Inspired by clojure.spec Explaining Data (m/explain CompositeMap {:x -1, :y -2, :EXTRA true}) ;{:schema …, ; :value {:x -1, :y -2, :EXTRA true}, ; :errors [{:path [1 2 1], :in [:x], :schema pos-int?, :value -1} ; {:path [1 3 1], :in [:y], :schema pos-int?, :value -2} ; {:path [1], :in [:EXTRA], :schema …, :type :malli.core/extra-key}]} AlexRich
  • 30. Errors for Humans (require '[malli.error :as me]) (+, CompositeMap (m/explain {:x -3, :y -2, :EXTRA true}) (me/humanize)) ;{:x ["should be positive int"] ; :y ["should be positive int"] ; :EXTRA ["disallowed key"] ; :malli/error ["x )* y"]} Alexander Kiel
  • 31. GeneratingValues (require '[malli.generator :as mg]) (mg/generate keyword?) ; '( :? (mg/generate [:enum "a" "b" "c"] {:seed 42}) ; '( "a" (mg/generate [:re #"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9-.]+.[a-zA-Z]{2,63}$"] {:seed 42, :size 10}) ; '( "CaR@MavCk70OHiX.yZ"
  • 32. GeneratingValues (mg/generate [:and {:gen/elements ["kikka" "kukka" "kakka"]} string?]) ; '( "kikka" (mg/generate [:and {:gen/fmap '(partial str "kikka_")} string?] {:seed 10, :size 10}) /0 '( "kikka_WT3K0yax2" (require '[clojure.test.check.generators :as gen]) (mg/generate [:sequential {:gen/gen (gen/list gen/neg-int)} int?] {:size 42, :seed 42}) ; '( (-37 -13 -13 -24 -20 -11 -34 -40 -22 0 -10) Gary Frederics
  • 33. Inferring Schemas (def lie-mi {:type :restaurant :name "Lie Mi" :tags #$:street :vietnamese} :stars 4.3 :address {:street "Hämeenkatu 14" :city "Tampere"}}) (def wanha-tappi {:type :restaurant :name "Wanha Tappi" :tags #$:burgers :beer} :address {:street "Jokipohjantie 18" :city "Tampere"}}) Stathis Sideris (require '[malli.provider :as mp]) (def Restaurant (mp/provide [lie-mi wanha-tappi])) Restaurant ;[:map ; [:type keyword?] ; [:name string?] ; [:tags [:set keyword?]] ; [:stars {:optional true} double?] ; [:address ; [:map ; [:street string?] ; [:city string?]]]]
  • 34. Programming with Schemas (require '[malli.util :as mu]) (+, [:map [:a int?] [:b string?] [:c [:map [:d int?] [:e keyword?]]]] (mu/closed-schema) (mu/select-keys [:a :c]) (mu/update-in [:c] mu/dissoc :e)) ;[:map {:closed true} ; [:a int?] ; [:c [:map {:closed true} ; [:d int?]]]] Metosin
  • 35. Walking over Schemas • Generic schema walking using theVisitor-pattern (CLJ-2251) • To JSON Schema, Swagger2, Map-syntax etc. (require '[malli.json-schema :as json-schema]) (json-schema/transform [:map {:title "a map"} [:x int?] [:y {:optional true} inst?]]) ;{:type "object" ; :title "a map" ; :properties {:x {:type "integer", :format "int64"} ; :y {:type "string", :format "date-time"} ; :required [:x]}
  • 36. Walking over Schemas (defn closed-schema "Closes recursively all :map schemas by adding `{:closed true}` property, unless schema explicitely open with `{:closed false}`" ([schema] (closed-schema schema nil)) ([schema options] (m/accept schema (m/schema-visitor (fn [schema] (if (-open-map? schema options) (update-properties schema c/assoc :closed true) schema))))))
  • 37.
  • 38. • Open Schemas to embrace growth (and typing errors) • Closed Schemas and Spell Checking to the rescue? Spell Checking (def nante-eck {:type :restaurant :name "Nante-Eck" :tags #$:traditional :vegan} :starz 4.2 :address {:streez "Unter den Linden 35" :city "Berlin"}}) Restaurant ;[:map ; [:type keyword?] ; [:name string?] ; [:tags [:set keyword?]] ; [:stars {:optional true} double?] ; [:address ; [:map ; [:street string?] ; [:city string?]]]]
  • 39. Spell Checking (+, Restaurant (m/explain nante-eck) (me/humanize)) ; {:address {:street ["missing required key"]}} (+, Restaurant (mu/closed-schema) (m/explain nante-eck) (me/humanize)) ;{:address {:street ["missing required key"] ; :streez ["disallowed key"]} ; :starz ["disallowed key"]} (+, Restaurant (mu/closed-schema) (m/explain nante-eck) (me/with-spell-checking) (me/humanize)) ;{:address {:streez ["should be spelled :street"]} ; :starz ["should be spelled :stars"]} Bruce Hauman
  • 40. • Fully re-written engine, built with interceptors • Encode and decode chains with enter & leave phases • Json, string, strip-extra-keys & default-value-transformer • Schemas can define transformation via properties • Fast ValueTransformers (m/decode int? "42" (mt/string-transformer)) ; '( 42 (m/encode int? 42 (mt/string-transformer)) ; '( ”42”
  • 41. (require '[malli.transform :as mt]) (def json-transformer (mt/transformer (mt/strip-extra-keys-transformer) (mt/json-transformer) (mt/default-value-transformer))) (def json+,Restaurant (m/decoder Restaurant json-transformer)) (json+,Restaurant {:type "restaurant" :DARK "ORKO" :name "Mustafas Gemüse Kebab" :tags ["kebab" "yoghurt"] :address {:street "Mehringdamm 32" :EXTRA "KEY" :city "Berlin"}}) ;{:type :restaurant, ; :name "Mustafas Gemüse Kebab", ; :tags #$:kebab :yoghurt}, ; :address {:street "Mehringdamm 32" ; :city "Berlin"}}
  • 42. (require '[criterium.core :as cc]) /0 1.8µs (cc/quick-bench (+, json (update :type keyword) (update :tags (comp set (partial map keyword))) (select-keys [:type :name :tags :address]) (update :address select-keys [:street :city]))) /0 1.9µs (cc/quick-bench (json+,Restaurant json)) (def json+,Order (m/decoder [:map [:id int?] [:tags string?] [:address [:map [:street string?] [:zip string?] [:country string?]]]] (mt/json-transformer))) json+,Order ; '( #object[clojure.core$identity]
  • 43. (require '[criterium.core :as cc]) /0 1.8µs (cc/quick-bench (+, json (update :type keyword) (update :tags (comp set (partial map keyword))) (select-keys [:type :name :tags :address]) (update :address select-keys [:street :city]))) /0 1.9µs (cc/quick-bench (json+,Restaurant json)) (def json+,Order (m/decoder [:map [:id int?] [:tags [:vector string?]] [:address [:map [:street string?] [:zip string?] [:country string?]]]] (mt/json-transformer))) json+,Order ; '( #object[clojure.core$identity]
  • 44. (require '[criterium.core :as cc]) /0 1.8µs (cc/quick-bench (+, json (update :type keyword) (update :tags (comp set (partial map keyword))) (select-keys [:type :name :tags :address]) (update :address select-keys [:street :city]))) /0 1.9µs (cc/quick-bench (json+,Restaurant json)) (def json+,Order (m/decoder [:map [:id int?] [:tags [:vector string?]] [:address [:map [:street string?] [:zip string?] [:country string?]]]] (mt/json-transformer))) json+,Order ; '( #object[clojure.core$identity]
  • 46. • reitit-malli coercion module, since 0.4.0 • Orders of magnitude faster coercion than with reitit-spec • Small example application: https://github.com/metosin/reitit/tree/ master/examples/ring-malli-swagger • A new module & configuration system? reitit + malli
  • 47. • … and custom Schemas to inline external stuff, maybe like: Schema providers (F#) (m/validate [:json-schema {:type "object" :properties {:x {:type "integer", :format "int64"} :y {:type "integer", :format "int64"}} :required [:x]}] {:x 1, :y 2}) ; => true
  • 48. • Have generated forms in four decades, just one more time ;) • Good companion for FSMs and rule engines, rapid prototyping • https://www.youtube.com/watch?v=IekPZpfbdaI • https://github.com/domino-clj + malli Generating UIs Dmitri Carmen Nikola Schema '( UI %& Schema UI-Schema '( UI
  • 49. • Inspired by expound, backed by metosin/virhe Errors for Developers Ben Brinkerhoff
  • 50. • malli-powered code checking: https://github.com/teknql/aave • Add support schematized defn and fn • Emit clj-kondo type annotations • Schemas for Schemas AST • Test utilities MoreTooling Ryan Schukler Michiel Borkent
  • 51.
  • 52. • Pre-alpha, still experimenting, but core is 90% code complete • Was public announcement by the community long time ago • Many active contributors and some users too • Big thanks to all people and libraries for source of innovation • Goal to get official release out in a month or two • Learned a lot, has been fun to develop Current Status
  • 53. • Understand and manage your expectations • Clojure is awesome tool for building data-driven systems • Malli is a fresh new schema library for Clojure/Script, try it out • If you’re interested in type and schema systems, consider contributing • https://github.com/metosin/malli • #malli on slack Takeaways
  • 55. Multi-Schemas (def MultiSchema [:multi {:dispatch :type} [:sized [:map [:type [12 :sized]] [:size int?]]] [:human [:map [:type [12 :human]] [:name string?]]]]) (m/validate MultiSchema {:type :sized, :size 10}) ; '( true (m/validate MultiSchema {:type :human, :name “Tiina"}) ; '( true
  • 56. Multi-Schemas (def MultiSchema [:multi {:dispatch 'first} [:sized [:tuple [12 :sized] [:map [:size int?]]]] [:human [:tuple [12 :human] [:map [:name string?]]]]]) (m/validate MultiSchema [:sized {:size 10}]) ; '( true (m/validate MultiSchema [:human {:name "Tiina"}]) ; '( true