Understanding our code with tests, schemas, and types

Please download to get full document.

View again

All materials on our website are shared by users. If you have any questions about copyright issues, please report us to resolve them. We are always happy to assist you.
 8
 
  The team at Oracle in Bristol has grown rapidly, and is working on a quickly changing codebase. As the team has learned more and added features, the code hasn't always evolved to reflect the changes in their domain knowledge. For newer team members, and those who haven't worked on a given piece of code for a while, it's sometimes difficult to understand the structures flowing through the functions. In Clojure, associative structures are often gradually built up as they are passed between functions, and it's difficult to know what they might contain at any point without tracing them through these functions. Mark will describe the team's experiences of using tests, Prismatic Schema, and core.typed in an attempt to alleviate this problem. This is a talk I gave at Clojure Exchange 2015 at Skills Matter in London (https://skillsmatter.com/conferences/6861-clojure-exchange-2015)
Related documents
Share
Transcript
  • 1. Understanding our code with tests, schemas, and types Mark Godfrey @msgodf
  • 2. The problem
  • 3. (ns please-understand-me …) (defn my-function [its-complicated] …)
  • 4. ๏ Why do I need to understand the code? ๏ Why the problem exists ๏ Examples of things that might help ๏ Some other ideas ๏ Conclusion
  • 5. Why do I need to understand the code?
  • 6. To use it
  • 7. To change it
  • 8. To review it
  • 9. Why does this problem - understanding the function interface - exist?
  • 10. What things might we find in the codebase that could help?
  • 11. The code
  • 12. (defn my-function “I take a map like this: {:name ‘Sebastian’ :age ‘27’} and return the year of birth.” [its-complicated] …)) (ns please-understand-me “You might understand me better with a docstring” …)
  • 13. (defn my-function “I take a map like this: {:name ‘Sebastian’ :age ‘27’} and return the year of birth.” [its-complicated] (:age its-complicated)) (ns please-understand-me “You might understand me better with a docstring” …)
  • 14. (defn my-function [{:keys [name age] :as its- complicated}] …) (ns please-understand-me …)
  • 15. (defrecord Person [name age]) (defn my-function [its-complicated] …) (ns please-understand-me …)
  • 16. (defrecord Person [name age]) (defn my-function [its-complicated] (->YearOfBirth (:age its-complicated)) (ns please-understand-me …)
  • 17. (defprotocol Summarizable (my-function [its-complicated)) (defrecord Person [name age] Summarizable (my-function [its-complicated] … )) (ns please-understand-me …)
  • 18. (defn my-function [^Person its-complicated] …) (ns please-understand-me …)
  • 19. Tests
  • 20. (deftest verify-me (is (= (my-function {:name “Derek” :age 28}) 28))) (ns please-understand-me-test (:require [clojure.test :refer [deftest is]]) …)
  • 21. And less likely…
  • 22. Documentation
  • 23. Schemas
  • 24. (def Person {:name s/Str :age s/Int}) (s/defn my-function :- s/Int [its-complicated :- Person] …)) (ns please-understand-me (:require [schema.core :as s]) …)
  • 25. (s/defrecord Person [name :- s/Str age :- s/Int]) (s/defn my-function :- s/Int [its-complicated :- Person] …)) (ns please-understand-me (:require [schema.core :as s]) …)
  • 26. (def Person {:name (s/maybe schema/Str) :age (s/either s/Int (s/eq :dont-ask)) :occupation (s/protocol Job}) (s/defn my-function :- s/Int [its-complicated :- Person] …)) (ns please-understand-me (:require [schema.core :as s]) …)
  • 27. Types
  • 28. (t/defalias Person {:name String :age Integer}) (t/defn my-function [its-complicated :- Person] :- Integer …)) (ns please-understand-me (:require [clojure.core.typed :as t]) …)
  • 29. (t/defalias Person {:name String :age Integer}) (t/ann my-function [its-complicated :- Person] :- Integer)) (ns please-understand-me.types (:require [clojure.core.typed :as t]) …)
  • 30. Are types really an option in Clojure?
  • 31. Type Error (core.clj:66:3) Function my-function could not be applied to arguments: Domains: (typed/HMap :mandatory {:name String, :age Integer} :optional {:occupation (typed/U nil None)}) Arguments: (typed/HMap :mandatory {:name String, :age Integer} :optional {:occupation (typed/U nil None) Ranges: String with expected type: Integer in: (my-function {:name “Derek”, :age 28}) Type Checker: Found 1 error Found errors $ lein typed check
  • 32. (t/ann ^:no-check clojure.tools.logging/*logger-factory* clojure.tools.logging.impl/LoggerFactory) (t/defalias LogLevel (t/U ':trace ':debug ':info ':warn ':error ':fatal)) (t/ann ^:no-check clojure.tools.logging/log* [clojure.tools.logging.impl/Logger LogLevel (t/U nil Throwable) String -> nil]) (t/ann-protocol clojure.tools.logging.impl/Logger enabled? (t/IFn [clojure.tools.logging.impl/Logger typed/Kw -> typed/Bool]) write! (t/IFn [clojure.tools.logging.impl/Logger typed/Kw Throwable String -> nil])) (t/ann-protocol clojure.tools.logging.impl/LoggerFactory name (t/IFn [clojure.tools.logging.impl/LoggerFactory -> String]) get-logger (t/IFn [clojure.tools.logging.impl/LoggerFactory typed/Any -> clojure.tools.logging.impl/Logger])) (ns please-understand-me (:require [clojure.core.typed :as t] [clojure.tools.logging :as log]) …)
  • 33. Other Tools
  • 34. The REPL, or interactive evaluation
  • 35. Tracing/debugging
  • 36. Schemas and generative testing
  • 37. (defspec describe-my-function 1000 (tc/forall [person (sg/generate Person)] (is (pos? (my-function person))))) (ns please-understand-me-test (:require [clojure.test.check :as tc] [clojure.test.check.clojure-test :refer [defspec] [schema.experimental.generators :as sg]) …)
  • 38. (def Birthdate {:year s/Int :month s/Int :day s/Int}) (s/defn mock-helper :- Birthdate [its-complicated :- Person] (sg/generate Birthdate) …)) (ns please-understand-me (:require [schema.core :as s] [schema.experimental.generators :as sg]) …)
  • 39. Conclusion
  • 40. “Your ‘reliability’ tools (testing, refactoring, type systems) don’t care if program is simple or not”
  • 41. But they can help you understand your code
  • 42. See also • Jessica Kerr - Contracts asTypes • Schema for Clojure(Script) Data Shape Declaration and Validation • Stuart Sierra -Thinking in Data • Rich Hickey - Simplicity Matters
  • Related Search
    Similar documents
    View more
    We Need Your Support
    Thank you for visiting our website and your interest in our free products and services. We are nonprofit website to share and download documents. To the running of this website, we need your help to support us.

    Thanks to everyone for your continued support.

    No, Thanks