Skip to content

Commit 94c9a47

Browse files
committed
tune up
1 parent c2881b0 commit 94c9a47

File tree

1 file changed

+23
-40
lines changed

1 file changed

+23
-40
lines changed

copy/entries/five-point-haskell-1.md

Lines changed: 23 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -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

4141
Think about the stereotype of a "brilliant programmer" that an inexperienced
4242
programmer 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
5656
need to upgrade your mental awareness and your context window. You just need to
5757
be 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
6868
eventually 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
117117
newtype SiteId = SiteId String
118118
newtype 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

141121
And now such a mis-call will never compile! Congratulations!
@@ -153,7 +133,7 @@ instance FromJSON SiteId where
153133
SiteId <$> (v .: "id")
154134

155135
instance ToJSON SiteId where
156-
toJSON (SiteId x) = object [ "type" .= "Site", id" .= x ]
136+
toJSON (SiteId x) = object [ "type" .= "Site", "id" .= x ]
157137

158138
instance FromJSON AppId where
159139
parseJSON = withObject "Id" $ \v ->
@@ -163,7 +143,7 @@ instance FromJSON AppId where
163143
AppId <$> (v .: "id")
164144

165145
instance ToJSON AppId where
166-
toJSON (AppId x) = object [ "type" .= "App", id" .= x ]
146+
toJSON (AppId x) = object [ "type" .= "App", "id" .= x ]
167147
```
168148

169149
However, luckily, because we're in Haskell, it's easy to get the best of both
@@ -179,6 +159,7 @@ data App
179159
type SiteId = Id Site
180160
type AppId = Id App
181161

162+
-- using Typeable for demonstration purposes
182163
instance 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!
200181
Phantom types gives us a _lot_ of low-hanging fruits to preventing inadvertent
201182
bad 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

337318
It 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

342323
It's called the billion dollar mistake, but it's definitely arguable that the
343324
cumulative damage has been much higher. High-profile incidents include
@@ -467,10 +448,10 @@ getUser conn uid = do
467448
```
468449

469450
It _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

475456
Don't assume that these inconsequential slip-ups won't happen; assume that it's
476457
only 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
652635
processAll :: 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
715698
addressed here exists both in LLMs and humans: the limited "context window" and
716699
attention. Humans might be barely able to keep a dozen things in our heads,
717700
LLMs 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
719702
window (be it biological or mechanical), the less crowded our context windows
720703
will be, and the more productive we will be.
721704

0 commit comments

Comments
 (0)