18 18:30 1996 (GMT) on tty1 - 23 years writing software in industry - Server-side/backend/infrastructure engineering, mostly - Former SRE; really care about operational ergonomics Today: - Building new backend services, test & automation in Haskell - Infrastructure and CI/CD with Nix/NixOS/Hydra - Still babysit a bloated Rails webapp Previously: trading systems and SaaS products Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 1 / 44
• Operational Debuggability Human factors review • Teaching/Learning • Managing Up • Setting Expectations Take-Aways Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 6 / 44
• between production and staging • before sharing with third-parties Security gates Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 7 / 44
telling us about the powers of the Haskell type system, when do we actually use it for great good?” –Team Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 8 / 44
{-# LANGUAGE KindSignatures #-} {-# LANGUAGE GADTs #-} -- OPTIONAL {-# LANGUAGE NoImplicitPrelude #-} -- OPTIONAL {-# LANGUAGE OverloadedStrings #-} -- OPTIONAL {-# LANGUAGE TypeApplications #-} -- OPTIONAL Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 11 / 44
Unscrubbed | Scrubbed deriving (Eq, Show) Email data Email (s :: EmailState) = MkEmail { emailAddress :: Text } deriving (Eq, Show) Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 13 / 44
Unscrubbed | Scrubbed deriving (Eq, Show) Email data Email (s :: EmailState) = MkEmail { emailAddress :: Text } deriving (Eq, Show) Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 13 / 44
:: EmailState) -- this is the kind signature! = MkEmail { emailAddress :: Text } deriving (Eq, Show) -- >>> :kind! Email Int -- <interactive>:1:7: error: -- • Expected kind ‘EmailState’, but ‘Int’ has kind ‘*’ -- • In the first argument of ‘Email’, namely ‘Int’ -- In the type ‘Email Int’ Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 16 / 44
-- this is the kind signature! = MkEmail { emailAddress :: Text } deriving (Eq, Show) -- >>> :kind! Email 'Unscrubbed -- Email 'Unscrubbed :: * -- = Email 'Unscrubbed Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 17 / 44
readEmail "[email protected]" → -- unscrubbedEmail :: Email 'Unscrubbed readEmail :: Text -> Maybe (Email 'Unscrubbed) readEmail = pure . MkEmail @'Unscrubbed -- silly version for slides → Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 19 / 44
(reflection, going back to terms): -- OPTIONAL: -- GADT can act as a witness of EmailState -- if we need to reflect at runtime data SEmailState :: EmailState -> Type where SUnscrubbed :: SEmailState 'Unscrubbed SScrubbed :: SEmailState 'Scrubbed Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 23 / 44
really need to reflect using a witness in this case. • Keep is simple, Susan (KISS) • Removed GADT witness and reflection functions and then… ”Cool, we like this just enough solution.” – Team Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 26 / 44
today: • more external integrations • more ”micro”-services • more storage & compute needs (for new categories of problems) • more runtime dependencies (monitoring, metrics, orchestration) • more deployment strategies And … Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 27 / 44
MonadIO m) => a -> m (LogMessage a) class Loggable a where formatLog :: a -> LogOutputType instance Loggable a => Loggable (LogMessage a) where formatLog (MkLogMessage t tid rid v s c e p) = ... Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 30 / 44
type Username = Text data PasswordReset = PasswordReset Username instance Loggable PasswordReset where formatLog (PasswordReset username) = ... Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 31 / 44
ingest structure. We us CEE-enhanced syslog @cee: {"time":"20190613T041811654", "tid":167, "pid":33451, "ver":"f73cfffe", "svc":"dk", "cmp":"tel", "env":"s1", "p":{"username":"someuser", "action":"password-reset"}} → → Now we can query structured logs not search for arbitrary text @severity:"error" svc:"dk" env:"prod" payload_status:[500 TO 599] → Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 32 / 44
ingest structure. We us CEE-enhanced syslog @cee: {"time":"20190613T041811654", "tid":167, "pid":33451, "ver":"f73cfffe", "svc":"dk", "cmp":"tel", "env":"s1", "p":{"username":"someuser", "action":"password-reset"}} → → Now we can query structured logs not search for arbitrary text @severity:"error" svc:"dk" env:"prod" payload_status:[500 TO 599] → Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 32 / 44
logging setup more involved (compared to Rails) • GOOD: First service work easily extracted in to a shared library for the next • GOOD: Simple type features used so far but some boilerplate • GOOD: Structured log record consistency (unlike first pass in Rails) • TODO: Trees That Grow to extend LogMessage in new ways • TODO: Type families to change output type • TODO: instance Generic a => Loggable a where ... Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 33 / 44
logging setup more involved (compared to Rails) • GOOD: First service work easily extracted in to a shared library for the next • GOOD: Simple type features used so far but some boilerplate • GOOD: Structured log record consistency (unlike first pass in Rails) • TODO: Trees That Grow to extend LogMessage in new ways • TODO: Type families to change output type • TODO: instance Generic a => Loggable a where ... Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 33 / 44
logging setup more involved (compared to Rails) • GOOD: First service work easily extracted in to a shared library for the next • GOOD: Simple type features used so far but some boilerplate • GOOD: Structured log record consistency (unlike first pass in Rails) • TODO: Trees That Grow to extend LogMessage in new ways • TODO: Type families to change output type • TODO: instance Generic a => Loggable a where ... Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 33 / 44
like feature flags EXCEPT: • they prevent access to a run-time resources like a database or cache or flaky API getKillSwitch :: ??? f => f (Either a b) gracefullyFail :: ??? f => f (a -> c) normalOps :: ??? f => f (b -> c) branch getKillSwitch gracefullyFail normalOps Look familiar? ;) Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 34 / 44
static over- and under-estimation of computation tree • under-estimation can be used to find computations that always run • over-estimation can be used to find computations that sometimes run • generate an on-call endpoint mapping to help tired brain debug at 3AM • Still a work-in-progress Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 35 / 44
static over- and under-estimation of computation tree • under-estimation can be used to find computations that always run • over-estimation can be used to find computations that sometimes run • generate an on-call endpoint mapping to help tired brain debug at 3AM • Still a work-in-progress Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 35 / 44
static over- and under-estimation of computation tree • under-estimation can be used to find computations that always run • over-estimation can be used to find computations that sometimes run • generate an on-call endpoint mapping to help tired brain debug at 3AM • Still a work-in-progress Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 35 / 44
static over- and under-estimation of computation tree • under-estimation can be used to find computations that always run • over-estimation can be used to find computations that sometimes run • generate an on-call endpoint mapping to help tired brain debug at 3AM • Still a work-in-progress Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 35 / 44
static over- and under-estimation of computation tree • under-estimation can be used to find computations that always run • over-estimation can be used to find computations that sometimes run • generate an on-call endpoint mapping to help tired brain debug at 3AM • Still a work-in-progress Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 35 / 44
static over- and under-estimation of computation tree • under-estimation can be used to find computations that always run • over-estimation can be used to find computations that sometimes run • generate an on-call endpoint mapping to help tired brain debug at 3AM • Still a work-in-progress Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 35 / 44
at teaching • ”Success” criteria often flawed or unmeasurable • Bottom-up foundational learning with top-down practical practice • Setup simple working dev envs; introduce the tools of trade • Team-level learning, not just individual Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 37 / 44
at teaching • ”Success” criteria often flawed or unmeasurable • Bottom-up foundational learning with top-down practical practice • Setup simple working dev envs; introduce the tools of trade • Team-level learning, not just individual Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 37 / 44
at teaching • ”Success” criteria often flawed or unmeasurable • Bottom-up foundational learning with top-down practical practice • Setup simple working dev envs; introduce the tools of trade • Team-level learning, not just individual Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 37 / 44
at teaching • ”Success” criteria often flawed or unmeasurable • Bottom-up foundational learning with top-down practical practice • Setup simple working dev envs; introduce the tools of trade • Team-level learning, not just individual Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 37 / 44
at teaching • ”Success” criteria often flawed or unmeasurable • Bottom-up foundational learning with top-down practical practice • Setup simple working dev envs; introduce the tools of trade • Team-level learning, not just individual Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 37 / 44
Design experiment • Document results • Share recommendations back to team • Team Discusses • Ticket cleanup for failures and successes Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 38 / 44
Propose solution to core problems • Offer PoC evidence that it satisfies a core requirement • Frame results to your audience (technical vs non-technical) • Incremental rollout, show results early, increase trust Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 39 / 44
Propose solution to core problems • Offer PoC evidence that it satisfies a core requirement • Frame results to your audience (technical vs non-technical) • Incremental rollout, show results early, increase trust Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 39 / 44
Propose solution to core problems • Offer PoC evidence that it satisfies a core requirement • Frame results to your audience (technical vs non-technical) • Incremental rollout, show results early, increase trust Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 39 / 44
Propose solution to core problems • Offer PoC evidence that it satisfies a core requirement • Frame results to your audience (technical vs non-technical) • Incremental rollout, show results early, increase trust Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 39 / 44
Propose solution to core problems • Offer PoC evidence that it satisfies a core requirement • Frame results to your audience (technical vs non-technical) • Incremental rollout, show results early, increase trust Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 39 / 44
technical peers • Your business peers • Your team By: • Be realistic • Iterative delivery • It will never be rainbows and unicorns, sorry! Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 40 / 44
technical peers • Your business peers • Your team By: • Be realistic • Iterative delivery • It will never be rainbows and unicorns, sorry! Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 40 / 44
Stay within a novelty budget • Give people new to Haskell working dev envs from day one! (Frustration budget) • Teach thinking tools over syntax • Promote team experiments and learning over time Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 41 / 44
Stay within a novelty budget • Give people new to Haskell working dev envs from day one! (Frustration budget) • Teach thinking tools over syntax • Promote team experiments and learning over time Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 41 / 44
Stay within a novelty budget • Give people new to Haskell working dev envs from day one! (Frustration budget) • Teach thinking tools over syntax • Promote team experiments and learning over time Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 41 / 44
Stay within a novelty budget • Give people new to Haskell working dev envs from day one! (Frustration budget) • Teach thinking tools over syntax • Promote team experiments and learning over time Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 41 / 44
tools vs syntax • Parametricity • Well Typed blog post from 2015 about ’Parametricity’ • Slide from talk ’Parametricity: Types Are Documentation’ • Theorems for free! • The algebra of [algebraic] data types • Algebra and Calculus of Algebraic Data Types • Abstractions of typed functional programming (aka typeclassopedia) • Typeclassopedia (Haskell wiki) • Typeclasses • Functors, Applicatives, and Monads in Pictures Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 43 / 44
development environments • Gist of an example Nix shell with GHC + hlint + hoogle + stylish-haskell devenv Susan Potter From Zero to Haskell: Lessons Learned 2019-06-15 44 / 44