SLIDE 1
Contracts in Clojure: Settling Types vs Tests @jessitron What do - - PowerPoint PPT Presentation
Contracts in Clojure: Settling Types vs Tests @jessitron What do - - PowerPoint PPT Presentation
Contracts in Clojure: Settling Types vs Tests @jessitron What do we know? How do we know it? Informal Reasoning Formal Experimental Proofs Evidence // Scala def formatReport(data: ReportData): ExcelSheet types (defn format-report
SLIDE 2
SLIDE 3
Informal Reasoning Formal Proofs Experimental Evidence
SLIDE 4
def formatReport(data: ReportData): ExcelSheet // Scala
SLIDE 5
types
SLIDE 6
SLIDE 7
(defn format-report [report-data] …) format-report
SLIDE 8
(function-name arg1 arg2)
function application
SLIDE 9
(function-name arg1 arg2) (defn function-name [param1 param2] (println "Hello QCon") (do-something-with (and param1 param2)))
function definition last expression is the result
SLIDE 10
(defn function-name [param1 param2] (println "Hello QCon") (do-something-with (and param1 param2)))
square braces make a vector
SLIDE 11
(defn format-report [report-data] …) format-report
SLIDE 12
(defn ad-performance-report [params] (-> (fetch-events params) (analyze-ad-performance params) format-report)) format-report
SLIDE 13
(defn ad-performance-report [params] (-> (fetch-events params) (analyze-ad-performance params) format-report)) fetch-events
SLIDE 14
…) (defn fetch-events [params] fetch-events
SLIDE 15
{:when 12:34:56 7/8/90 :what "show" :who "abc123"}
curly braces make a map keyword
SLIDE 16
{:when org.joda.time.DateTime :what java.lang.String :who java.lang.String} (def Event )
give a thing a name
SLIDE 17
(def Event ) {:when DateTime :what s/Str :who s/Str} (:require [schema.core :as s])
dependency
SLIDE 18
(def Event ) {:when DateTime :what Incident :who Customer} Event (def Incident s/Str) (def Customer s/Str)
SLIDE 19
[Event] (def Event ) {:when DateTime :what Incident :who Customer}
SLIDE 20
…) (defn fetch-events [params] [Event]
SLIDE 21
[Event] (:require [schema.core :as s]) …) (s/defn fetch-events [params] :- [Event]
SLIDE 22
(deftest fetch-events-test … (= (expected (fetch-events input))))
SLIDE 23
(deftest fetch-events-test … (= (expected (fetch-events input)))) (use-fixtures schema.test/validate-schemas)
SLIDE 24
(defn ad-performance-report [params] (-> (fetch-events params) (analyze-ad-performance params) format-report)) (d ) [Event] analyze-ad-performance
SLIDE 25
(defn analyze-ad-performance [events params] (-> events (group-up params) summarize add-total-row (add-headers params))) analyze-ad-performance
SLIDE 26
[Event] (defn analyze-ad-performance [events params] (-> events (group-up params) summarize add-total-row (add-headers params)))
SLIDE 27
[[Event]] [Event] (defn analyze-ad-performance [events params] (-> events (group-up params) summarize add-total-row (add-headers params)))
SLIDE 28
[[Event]] [Event] (defn analyze-ad-performance [events params] (-> events (group-up params) summarize add-total-row (add-headers params)))
SLIDE 29
[[Event] ]
SLIDE 30
[[Event] Summation]
SLIDE 31
[( one [Event] ) ( one Summation )]
SLIDE 32
[(s/one [Event] "event list") (s/one Summation "group sum")]
SLIDE 33
{:groups [[(s/one [Event] "event list") (s/one Summation "group sum")]]}
SLIDE 34
{:groups [[(s/one [Event] "event list") (s/one Summation "group sum")]] :total Totals}
SLIDE 35
{:header Headers :groups [[(s/one [Event] "event list") (s/one Summation "group sum")]] :total Totals})
SLIDE 36
(def ReportData {:header Headers :groups [[(s/one [Event] "event list") (s/one Summation "group sum")]] :total Totals})
SLIDE 37
(s/defn analyze-ad-performance :- ReportData [events :- [Event] params :- Params] (-> events (group-up params) summarize add-total-row (add-headers params)))
SLIDE 38
(s/defn analyze-ad-performance :- ReportData …)
SLIDE 39
(s/defn analyze-ad-performance :- (at-least ReportData) …)
SLIDE 40
(s/defn analyze-ad-performance :- (at-least ReportData) …) (defn at-least [map-schema] (merge map-schema {s/Any s/Any}))
SLIDE 41
What do we know?
SLIDE 42
What do we know?
data shape
SLIDE 43
What do we know?
data shape value boundaries
SLIDE 44
:title
- string
- not empty
- capitalized
Headers
SLIDE 45
(def Headers {:title (s/constrained s/Str (s/pred (complement empty?) "nonempty") (s/pred capitalized? "Title Caps")) …})
SLIDE 46
What do we know?
data shape data value boundaries relationships within values
SLIDE 47
What do we know?
data shape data value boundaries relationships within values
What could we know?
SLIDE 48
What do we know?
data shape relationships within values
What could we know?
produced types data value boundaries
SLIDE 49
(s/defn fetch-events :- [Event] [params] …) Seq[Event]
SLIDE 50
(s/defn fetch-events :- [Event] [params] …)
SLIDE 51
(st/defn fetch-events :+ (st/LazySeq Event) [params] …)
what if?
check this later
SLIDE 52
(st/defn fetch-events :+ (st/LazySeq Event) [params] …) (:require [schematron.core :as st])
SLIDE 53
(s/defn a-higher-order-function [predicate :- (s/=> Bool Event) …] …)
SLIDE 54
(st/defn a-higher-order-function [predicate :+ (st/=> Bool Event) …] …)
what if?
check this later
SLIDE 55
(s/defn a-higher-order-function :- Event [predicate :- (st/=> Bool Event) …] …)
SLIDE 56
(st/defn [A] a-higher-order-function :- A [predicate :+ (st/=> Bool A) …] …)
what if?
(a-higher-order-function Event is-happy …)
SLIDE 57
What do we know?
data shape data value boundaries relationships within values
What could we know?
produced types relationships between types relationships between values
SLIDE 58
What do we know? What could we know?
produced types relationships between types relationships between values data shape relationships within values data value boundaries
SLIDE 59
(defn group-up [events params] {:post [(as-lazy-as events %)] …))
postcondition
SLIDE 60
produced types relationships between types relationships between values data shape relationships within values data value boundaries
SLIDE 61
How do we know it?
SLIDE 62
(deftest analyze-ad-performance-test (testing "grouping of rows" (let [… result (analyze-ad-performance events {}) (is (= expected (:groups result))))))
SLIDE 63
(use-fixtures schema.test/validate-schemas) (deftest analyze-ad-performance-test (testing "grouping of rows" (let [… result (analyze-ad-performance events {}) (is (= expected (:groups result))))))
SLIDE 64
(let [… result (analyze-ad-performance events {}) (is (= expected (:groups result))))))
Input does not match schema Params Missing required key :title Missing required key :start Missing required key :end
SLIDE 65
(let [… result (analyze-ad-performance events (sc/complete {} Params) (is (= expected (:groups result))))))
"Fill in everything else with something random until it meets this schema"
SLIDE 66
{:title "YhKEzII", :start "-217863493-11-21T00:54:39.872Z"], :end "-256417656-09-30T01:08:11.904Z"]} any string any date before now any date before the start
SLIDE 67
(deftest analyze-ad-performance-test (testing "grouping of rows" (let [… result (analyze-ad-performance [events] (sample-one param-gen)) (is (= expected (:groups result)))))) (use-fixtures schema.test/validate-schemas)
SLIDE 68
1 test is an anecdote generative tests are evidence
SLIDE 69
?
SLIDE 70
?
SLIDE 71
?
Experimental Evidence
SLIDE 72
(defspec analyze-ad-performance-spec 100 (for-all [events events-gen params param-gen] (analyze-ad-performance events params)))) (use-fixtures schema.test/validate-schemas)
(s/defn analyze-ad-performance :- ReportData …)
SLIDE 73
What do we know? How do we know it? Schemas Generative Tests
SLIDE 74
SLIDE 75
SLIDE 76
B A
Contract
SLIDE 77
SLIDE 78
B A
SLIDE 79
A A
SLIDE 80
A B
SLIDE 81
A B
SLIDE 82
implementation schemas generators tests
SLIDE 83
implementation schemas tests testkit client libs gen
SLIDE 84
B A
SLIDE 85
Science!
test.check prismatic/schema Clojure
SLIDE 86
Science!
generative tests types and contracts … your language …
SLIDE 87
Science!
testkits client libraries … your services …
SLIDE 88
Informal Reasoning Formal Proofs Experimental Evidence
SLIDE 89