@@ -35,8 +35,8 @@ Haskell is perfectly primed to make living with it as frictionless as possible.
3535> compiler, use types to guard against errors, and free yourself to only
3636> mentally track the actual important things.
3737
38- Mix-ups Will Happen
39- -------------------
38+ Mix-ups Are Inevitable
39+ ----------------------
4040
4141Think about the stereotype of a "brilliant programmer" that an inexperienced
4242programmer has in their mind --- someone who can hold every detail of a complex
@@ -56,15 +56,15 @@ This is the myth of the hero programmer. Did you have a bug? Well, you just
5656need to upgrade your mental awareness and your context window. You just need to
5757be better and better at keeping more in your mind.
5858
59- Admittedly, actually _ addressing_ these issues in most languages requires a lot
60- of overhead and clunkiness. But luckily we're in Haskell!
59+ Actually _ addressing_ these issues in most languages requires a lot of overhead
60+ and clunkiness. But luckily we're in Haskell!
6161
6262### ID Mix-ups
6363
64- The [ 2022 Atlassian Outage] [ atlassian ] , fundamentally , was the result of
65- passing the wrong type of ID. The operators were intended to pass _ App_ IDs,
66- but instead passed _ Site_ IDs, and the errors cascaded from there. It goes
67- without saying that if you have a bunch of "naked" IDs, then mixing them up is
64+ The [ 2022 Atlassian Outage] [ atlassian ] , in some part , was the result of passing
65+ the wrong type of ID. The operators were intended to pass _ App_ IDs, but
66+ instead passed _ Site_ IDs, and the errors cascaded from there. It goes without
67+ saying that if you have a bunch of "naked" IDs, then mixing them up is
6868eventually going to backfire on you.
6969
7070[ atlassian ] : https://www.atlassian.com/blog/atlassian-engineering/post-incident-review-april-2022-outage
@@ -116,26 +116,6 @@ accidentally using the wrong ID is a compile error:
116116``` haskell
117117newtype SiteId = SiteId String
118118newtype AppId = AppId String
119-
120- instance ToJSON SiteId where
121- toJSON (SiteId x) = object [ " type" .= " Site" , id " .= x ]
122-
123- instance FromJSON SiteId where
124- parseJSON = withObject " Id " $ \v ->
125- tag <- v .: " type "
126- unless (tag == " Site " ) $
127- fail " Parsed wrong type of ID ! "
128- SiteId <$> (v .: " id " )
129-
130- instance ToJSON AppId where
131- toJSON (AppId x) = object [ " type " .= " App " , id" .= x ]
132-
133- instance FromJSON AppId where
134- parseJSON = withObject " Id" $ \ v ->
135- tag <- v .: " type"
136- unless (tag == " App" ) $
137- fail " Parsed wrong type of ID!"
138- AppId <$> (v .: " id" )
139119```
140120
141121And now such a mis- call will never compile! Congratulations !
@@ -153,7 +133,7 @@ instance FromJSON SiteId where
153133 SiteId <$> (v .: " id" )
154134
155135instance ToJSON SiteId where
156- toJSON (SiteId x) = object [ " type" .= " Site" , id " .= x ]
136+ toJSON (SiteId x) = object [ " type" .= " Site" , " id" .= x ]
157137
158138instance FromJSON AppId where
159139 parseJSON = withObject " Id" $ \ v ->
@@ -163,7 +143,7 @@ instance FromJSON AppId where
163143 AppId <$> (v .: " id" )
164144
165145instance ToJSON AppId where
166- toJSON (AppId x) = object [ " type " .= " App " , id" .= x ]
146+ toJSON (AppId x) = object [ " type" .= " App" , " id" .= x ]
167147```
168148
169149However, luckily, because we're in Haskell, it's easy to get the best of both
@@ -179,6 +159,7 @@ data App
179159type SiteId = Id Site
180160type AppId = Id App
181161
162+ -- using Typeable for demonstration purposes
182163instance Typeable a => ToJSON (Id a ) where
183164 toJSON (Id x) = object
184165 [ " type" .= show (typeRep @ a )
@@ -200,8 +181,8 @@ Type safety doesn't necessarily mean inflexibility!
200181Phantom types gives us a _ lot_ of low-hanging fruits to preventing inadvertent
201182bad usages.
202183
203- The [ 2017 DigitalOcean outage] [ digitalocean ] outage, for example,
204- fundamentally was about the wrong environment credentials being used.
184+ The [ 2017 DigitalOcean outage] [ digitalocean ] outage, for example, partially
185+ about the wrong environment credentials being used.
205186
206187[ digitalocean ] : https://www.theregister.com/2017/04/11/database_deletion_downed_digital_ocean_last_week/
207188
@@ -335,9 +316,9 @@ There are examples:
335316 sometimes ` -999 ` might actually be a valid value!
336317
337318It should be evident that these are just accidents and ticking time-bombs
338- waiting to happen. All it takes is for some caller to forget to handle the
339- sentinel value, or to falsely assume that the sentinel value is impossible to
340- occur in any situation.
319+ waiting to happen. Some caller just needs to forget to handle the sentinel
320+ value, or to falsely assume that the sentinel value is impossible to occur in
321+ any situation.
341322
342323It's called the billion dollar mistake, but it's definitely arguable that the
343324cumulative damage has been much higher. High-profile incidents include
@@ -467,10 +448,10 @@ getUser conn uid = do
467448```
468449
469450It _ should_ be fine as long as you only ever use ` saveUser ` and ` getUser ` ...and
470- nobody else has access to the database. But, all it takes is for someone to
471- hook up a custom connector, or do some manual modifications, and the ` users `
472- table will now have an invalid username, bypassing Haskell. And because of
473- that, ` getUser ` can return an invalid string!
451+ nobody else has access to the database. But, if someone hooks up a custom
452+ connector, or does some manual modifications, then the ` users ` table will now
453+ have an invalid username, bypassing Haskell. And because of that, ` getUser ` can
454+ return an invalid string!
474455
475456Don't assume that these inconsequential slip-ups won't happen; assume that it's
476457only a matter of time.
@@ -648,6 +629,8 @@ that all of them _eventually_ happen.
648629[ resourcet ] : https://hackage.haskell.org/package/resourcet
649630
650631``` haskell
632+ import qualified Data.Map as M
633+
651634-- | Returns set of usernames to close
652635processAll :: Map Username Handle -> IO (Set Username )
653636
@@ -715,7 +698,7 @@ I don't have too much to say here, except that the fundamental issue being
715698addressed here exists both in LLMs and humans: the limited "context window" and
716699attention. Humans might be barely able to keep a dozen things in our heads,
717700LLMs might be able to keep a dozen dozen things, but it will still be
718- fundamentally finite. So, the more we can move concerns out of our context
701+ ultimately finite. So, the more we can move concerns out of our context
719702window (be it biological or mechanical), the less crowded our context windows
720703will be, and the more productive we will be.
721704
0 commit comments