A recent discussion about introducing typeclasses to F# resulted in this comment:
Adding type-level programming of any kind can lead to communities where the most empowered programmers are those with deep expertise in certain kinds of highly abstract mathematics (e.g. category theory). Programmers uninterested in this kind of thing are disempowered. I don’t want F# to be the kind of language where the most empowered person in the discord chat is the category theorist.
– Don Syme, designer of F#
Don brings up a fascinating question when it comes to language and API design: what kind of user do you most want to empower?
In gaming, MOBA (multiplayer online battle arena) players have a mental framework for describing just what kind of player is empowered by different characters. This framework describes all characters in terms of two statistics: their skill floor and their skill ceiling.
A character’s skill floor is the minimum level of skill needed to be effective with a character. A character’s skill ceiling is the level at which getting more skillful doesn’t really bring much benefit.
Consider a character whose abilities are mostly single button press, area of effect (AoE). These are hard to miss and don’t require much coordination. This character has a low skill floor because a player with relatively low skill can still be effective with it. It also has a low skill ceiling since an experienced player isn’t going to be that much better than a newer one.
Now contrast with a character whose abilities require skillshots and precisely timed combos. This character has a high skill floor because the character is hard to play for newer players. It also has a high skill ceiling because players with higher skill can get a lot more value out of the character.
Finally, it’s interesting to think about a character’s range. Characters with a narrow range (e.g. both low skill floor and low skill ceiling) are usually designed for a particular player type. Characters with a broader range are designed to be useful to players with a more diverse levels of skill.
This mental model isn’t just useful when thinking about the design of MOBA characters. It can be used to analyse games as a whole. Going beyond that, we can use it to think about our own API designs.
In the F# example above, introducing typeclasses would raise the skill ceiling. Experienced devs (and category theorists in particular) now get more value out of their skill. However, introducing the feature will also raise the skill floor. This means the language will be less accessible to developers with less experience.
The changes in these two boundaries won’t always move in tandem. A feature that raises the skill ceiling slightly might move up the skill floor by a lot, resulting in a narrower range than before. Narrow ranges aren’t necessarily bad per-se but they should definitely be centered on your core audience.
All new features impose a cost on your API. Not just to develop or maintain, but on your design as a whole by shifting the skill floor and ceiling boundaries. Most commonly, new features will make it harder for inexperienced users to use your product or tool.
Consider a command-line tool like
tar. It provides many flags to customize its
behavior. This makes it a more powerful tool, but it also makes it notorious
for no one being able to remember how to use it.
Designing a tool with broad range, one that has both a low skill floor and a high skill ceiling is incredibly difficult, sometimes even impossible. Moving one boundary usually also moves the other in some way.
Don asks a great question: “who should my design focus on empowering?”. A good design targets a particular audience. A system designed for beginners will often be quite different from a system designed for experts.
In F#’s case, it looks like Don wants to focus on empowering users more in the middle of the skill range. This means passing on a useful advanced feature that would disempower his core audience.