Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Production modes #70

Open
vemv opened this issue Jun 13, 2019 · 0 comments
Open

Production modes #70

vemv opened this issue Jun 13, 2019 · 0 comments
Labels

Comments

@vemv
Copy link
Contributor

vemv commented Jun 13, 2019

Context

Generally it is recommended to disable instrumentations/preconditions in production systems:

  • It results in slower performance
  • It can result in an unfriendly UX
    • UIs shouldn't break due to a spec failure
    • Particularly when specs might be more strict than necessary

However:

  • one shouldn't lose their benefits altogether in production
    • We can catch bugs before the user is impacted at all
  • Not all production systems are latency-critical
    • e.g. async message processors (background jobs, Kafka handlers, etc)

Task

Implement two 'spec directives':

^::speced/always

Marks a defn/etc to be always check!ed, disregarding *assert* .

^::speced/warn

Instructs all defns/defprotocols, etc to observe *assert*as per usual. However a non-throwing checking will still be performed. If this checking fails, the report will be printlned against speced/*warn* (analog to *out* and *err*).

Consumers could bind speced/*warn* to arbitrary adapters, e.g. Timbre, Rollbar, etc.

Acceptance criteria

  • I can selectively attach the flags to whichever defns/defprotocols/... I please
  • always and warn compose well
  • I can attach the flags in any likely position, avoiding silent no-ops:
    • (^here speced/defn ^here-too foo ^and-here [args] ....)
  • Typos in flags are caught.
  • individual arguments can have their own flags
    • these always take precedence over the surrounding defn's flag (if any)
  • check! can also be flagged
    • foralways would be a no-op, however serves as documentation (else I have to write a comment: ;; this (check!) is enabled in production too, do not wrap in (assert))

Examples

;; A simple case:
(speced/defn ^::speced/always foo [^::age age]
  )

;; This case is equivalent to the previous one:
(speced/defn foo [^::speced/always ^::age age]
  )

;; This case is different. Only `age` will be unconditionally checked
(speced/defn foo [^::speced/always ^::age age, ^::temperature temperature]
  )

(speced/defn foo [^::speced/always age] ;; illegal flag, because there's no spec to check
  )

;; `let` and other constructs get analog rules and syntax
(speced/let [^::speced/always ^::age age (compute-age ...)])
(^::speced/always speced/let [^::age age (compute-age ...)])
(speced/let ^::speced/always [^::age age (compute-age ...)])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant