Contracts in Clojure: Settling Types vs Tests @jessitron What do - - PowerPoint PPT Presentation

contracts in clojure
SMART_READER_LITE
LIVE PREVIEW

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-1
SLIDE 1

Contracts in Clojure:

Settling Types vs Tests

@jessitron

slide-2
SLIDE 2

What do we know? How do we know it?

slide-3
SLIDE 3

Informal Reasoning Formal Proofs Experimental Evidence

slide-4
SLIDE 4

def formatReport(data: ReportData): ExcelSheet // Scala

slide-5
SLIDE 5

types

slide-6
SLIDE 6
slide-7
SLIDE 7

(defn format-report [report-data] …) format-report

slide-8
SLIDE 8

(function-name arg1 arg2)

function application

slide-9
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
SLIDE 10

(defn function-name [param1 param2] (println "Hello QCon") (do-something-with (and param1 param2)))

square braces make a vector

slide-11
SLIDE 11

(defn format-report [report-data] …) format-report

slide-12
SLIDE 12

(defn ad-performance-report [params] (-> (fetch-events params) (analyze-ad-performance params) format-report)) format-report

slide-13
SLIDE 13

(defn ad-performance-report [params] (-> (fetch-events params) (analyze-ad-performance params) format-report)) fetch-events

slide-14
SLIDE 14

…) (defn fetch-events [params] fetch-events

slide-15
SLIDE 15

{:when 12:34:56 7/8/90 :what "show" :who "abc123"}

curly braces make a map keyword

slide-16
SLIDE 16

{:when org.joda.time.DateTime :what java.lang.String :who java.lang.String} (def Event )

give a thing a name

slide-17
SLIDE 17

(def Event ) {:when DateTime :what s/Str :who s/Str} (:require [schema.core :as s])

dependency

slide-18
SLIDE 18

(def Event ) {:when DateTime :what Incident :who Customer} Event (def Incident s/Str) (def Customer s/Str)

slide-19
SLIDE 19

[Event] (def Event ) {:when DateTime :what Incident :who Customer}

slide-20
SLIDE 20

…) (defn fetch-events [params] [Event]

slide-21
SLIDE 21

[Event] (:require [schema.core :as s]) …) (s/defn fetch-events [params] :- [Event]

slide-22
SLIDE 22

(deftest fetch-events-test … (= (expected (fetch-events input))))

slide-23
SLIDE 23

(deftest fetch-events-test … (= (expected (fetch-events input)))) (use-fixtures schema.test/validate-schemas)

slide-24
SLIDE 24

(defn ad-performance-report [params] (-> (fetch-events params) (analyze-ad-performance params) format-report)) (d ) [Event] analyze-ad-performance

slide-25
SLIDE 25

(defn analyze-ad-performance [events params] (-> events (group-up params) summarize add-total-row (add-headers params))) analyze-ad-performance

slide-26
SLIDE 26

[Event] (defn analyze-ad-performance [events params] (-> events (group-up params) summarize add-total-row (add-headers params)))

slide-27
SLIDE 27

[[Event]] [Event] (defn analyze-ad-performance [events params] (-> events (group-up params) summarize add-total-row (add-headers params)))

slide-28
SLIDE 28

[[Event]] [Event] (defn analyze-ad-performance [events params] (-> events (group-up params) summarize add-total-row (add-headers params)))

slide-29
SLIDE 29

[[Event] ]

slide-30
SLIDE 30

[[Event] Summation]

slide-31
SLIDE 31

[( one [Event] ) ( one Summation )]

slide-32
SLIDE 32

[(s/one [Event] "event list") (s/one Summation "group sum")]

slide-33
SLIDE 33

{:groups [[(s/one [Event] "event list") (s/one Summation "group sum")]]}

slide-34
SLIDE 34

{:groups [[(s/one [Event] "event list") (s/one Summation "group sum")]] :total Totals}

slide-35
SLIDE 35

{:header Headers :groups [[(s/one [Event] "event list") (s/one Summation "group sum")]] :total Totals})

slide-36
SLIDE 36

(def ReportData {:header Headers :groups [[(s/one [Event] "event list") (s/one Summation "group sum")]] :total Totals})

slide-37
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
SLIDE 38

(s/defn analyze-ad-performance :- ReportData …)

slide-39
SLIDE 39

(s/defn analyze-ad-performance :- (at-least ReportData) …)

slide-40
SLIDE 40

(s/defn analyze-ad-performance :- (at-least ReportData) …) (defn at-least [map-schema] (merge map-schema {s/Any s/Any}))

slide-41
SLIDE 41

What do we know?

slide-42
SLIDE 42

What do we know?

data shape

slide-43
SLIDE 43

What do we know?

data shape value boundaries

slide-44
SLIDE 44

:title

  • string
  • not empty
  • capitalized

Headers

slide-45
SLIDE 45

(def Headers {:title (s/constrained s/Str (s/pred (complement empty?) "nonempty") (s/pred capitalized? "Title Caps")) …})

slide-46
SLIDE 46

What do we know?

data shape data value boundaries relationships within values

slide-47
SLIDE 47

What do we know?

data shape data value boundaries relationships within values

What could we know?

slide-48
SLIDE 48

What do we know?

data shape relationships within values

What could we know?

produced types data value boundaries

slide-49
SLIDE 49

(s/defn fetch-events :- [Event] [params] …) Seq[Event]

slide-50
SLIDE 50

(s/defn fetch-events :- [Event] [params] …)

slide-51
SLIDE 51

(st/defn fetch-events :+ (st/LazySeq Event) [params] …)

what if?

check this later

slide-52
SLIDE 52

(st/defn fetch-events :+ (st/LazySeq Event) [params] …) (:require [schematron.core :as st])

slide-53
SLIDE 53

(s/defn a-higher-order-function [predicate :- (s/=> Bool Event) …] …)

slide-54
SLIDE 54

(st/defn a-higher-order-function [predicate :+ (st/=> Bool Event) …] …)

what if?

check this later

slide-55
SLIDE 55

(s/defn a-higher-order-function :- Event [predicate :- (st/=> Bool Event) …] …)

slide-56
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
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
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
SLIDE 59

(defn group-up [events params] {:post [(as-lazy-as events %)] …))

postcondition

slide-60
SLIDE 60

produced types relationships between types relationships between values data shape relationships within values data value boundaries

slide-61
SLIDE 61

How do we know it?

slide-62
SLIDE 62

(deftest analyze-ad-performance-test (testing "grouping of rows" (let [… result (analyze-ad-performance events {}) (is (= expected (:groups result))))))

slide-63
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
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
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
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
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
SLIDE 68

1 test is an anecdote generative tests are evidence

slide-69
SLIDE 69

?

slide-70
SLIDE 70

?

slide-71
SLIDE 71

?

Experimental Evidence

slide-72
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
SLIDE 73

What do we know? How do we know it? Schemas Generative Tests

slide-74
SLIDE 74
slide-75
SLIDE 75
slide-76
SLIDE 76

B A

Contract

slide-77
SLIDE 77
slide-78
SLIDE 78

B A

slide-79
SLIDE 79

A A

slide-80
SLIDE 80

A B

slide-81
SLIDE 81

A B

slide-82
SLIDE 82

implementation schemas generators tests

slide-83
SLIDE 83

implementation schemas tests testkit client libs gen

slide-84
SLIDE 84

B A

slide-85
SLIDE 85

Science!

test.check prismatic/schema Clojure

slide-86
SLIDE 86

Science!

generative tests types and contracts … your language …

slide-87
SLIDE 87

Science!

testkits client libraries … your services …

slide-88
SLIDE 88

Informal Reasoning Formal Proofs Experimental Evidence

slide-89
SLIDE 89

@jessitron

blog.jessitron.com

https://github.com/jessitron/contracts-as-types-examples

examples resources

https://github.com/Prismatic/schema http://hintjens.com/blog:85 The End of Software Versions http://david-mcneil.com/post/114783282473/extending- prismatic-schema-to-higher-order https://github.com/jessitron/schematron http://dl.acm.org/citation.cfm?id=2661156 Static typing and productivity: Stefik & Hanenberg 2014