Functional programming, UX, tech
Twitter • GitHub • LinkedIn • RSS
My book, Functional Programming in Scala, uses Scala as a vehicle for teaching FP. Read what people are saying about it.
Unison: a friendly programming language from the future
unison.cloud: the worldwide elastic computer (coming soon)
Type systems and UX: an example
CSS is unnecessary
Names and the little details of an API matter. I’m going to pick on one small example I came across recently. In unagi-chan, a very fast lock-free queue implementation, we have the following API:
newChan :: IO (InChan a, OutChan a)
Here’s me:
Huh, okay, they split the queue into separate read and write access. Geez, was that really necessary? If I wanted to partially apply readChan
or tryReadChan
and pass around an IO a
or IO (Maybe a)
, I could do that, you know. Now if I need both read and write access, you’ve forced me to pass around a pair… ugly. But okay, okay, fine, I can deal with this, this thing’s supposed to be screaming fast, I can put up with a few admittedly subjective API warts, and honestly I’m being pretty ungrateful that the people wrote this nice code and made it freely available.
Two minutes later: a type error when trying to read from an InChan
. Wait, what? Let me re-check hackage docs here… WAT? readChan
takes an OutChan
??
readChan :: OutChan a -> IO a
WTF!!?! What kind of idiot would—oh, wait, maybe that does make sense. I’m probably just being dense here. Calm down, Paul. Let’s think about this, do you read from the InChan
or the OutChan
? Obviously I should read from the InChan
… but AHA! From the perspective of the producer, the InChan
IS the OutChan
. But from the perspective of the consumer, it’s the reverse! This is so fucking confusing! What the hell was I even doing? I’ve forgotten by now…
(After a moment of realization). You know, it’s completely arbitrary whether the InChan
is from the perspective of a queue writer or a queue reader, so these names are just confusing as hell. Calling these two types WootChan
and Woot2Chan
would have been MORE INFORMATIVE, since it would not have tempted me to start writing code based on my assumed understanding of the meaning of In
and Out
without checking the type signatures!
Not to mention, while I’m trashing this code, who decided to call those functions readChan
and writeChan
? Where exactly are we writing to / reading from? Is this a stack or a queue? How about enqueue
and dequeue
, which is more appropriately suggestive of what’s happening?
Five minutes later, I’d settled on this: if you really insist on splitting up the queue into two types, how about these names:
newQueue :: IO (Enqueue a, Dequeue a)
enqueue :: Enqueue a -> a -> IO ()
dequeue :: Dequeue a -> IO a
Now THIS is the sort of API I like. I can use it without switching on random parts of my brain that have nothing to do with what I’m trying to accomplish.
Summary:
Also see this section of design for experts; accomodate beginners.
comments powered by Disqus