Whenipress | Part 1 - How to create great software

Last updated 03/07/2020

Why did I create a JavaScript package for key bindings, and what is the key to great software?

If you've never heard of whenipress, here is a link: https://github.com/lukeraymonddowning/whenipress.

In future articles, I'll dive into how to make the most of whenipress. But in this article, I wanted to answer the 'why', not the 'how'. There are many developers in the world who really want to start creating open source packages but have no idea what to create. Others feel they're not good enough to create them. Still others think that they don't have time to maintain them.

If you're one of those people, hopefully this article will help you to realise that anybody can create great open source packages.

Stage 1: Inspiration

The best packages are inspired. They could be inspired by your own findings. They could be inspired by another package. They could be inspired by a comment somebody else has made. The latter was the case for whenipress.

Whilst browsing a subreddit, I saw a question that caught my attention: "Is it possible to create keybindings for key combinations in JavaScript?" That seems like a fair question, no? If you want to add keyboard shortcuts to your webapp, you'd need this functionality. If you were creating a JS game, you'd need this functionality. If you're creating custom JS components, accessibility requires you to have this functionality.

The top answer made me sad: "Yes its possible. You just need to track and record all keys pressed on a keydown listener and stop tracking them on a keyup listener. Then you'll need to compare your keys being pressed to the keys you want pressed."

I'm not saying that it is difficult to create this functionality. What I am saying is that nobody who is not required to put keybindings into their application is going to bother to put the effort in to do this, because we all have better things to do.

The result, sadly, is that most applications on the web have little to no support for the keyboard. That just isn't proper. So it was time to do something about it.

Stage 2: Unique Selling Point

Believe it or not, I'm not the first person to think this. There are packages out there that will do this already. Primarily: Mousetrap. Mousetrap is a brilliant package. It has over 10,000 stars on Github. It would be easy to look at Moustrap and reason that there is no point to building another package that performs as similar task.

Just stop and think about that though. If everybody thought that way, the world would be a very different place. Monopolies would be the norm, not the exception. Many of the tools we use everyday as developers came about thanks to people who realised that there was possible a better way of doing something that had already been done before.

But how can I compete against something as popular as Mousetrap? Simple: I need a Unique Selling Point. I need something that makes my product clever, or unique, or interesting. Interesting enough that people are willing to give it a try. In the case of whenipress, my USP was the syntax.

Stage 3: Creating the perfect syntax

The name whenipress came from my scratch file. If you don't know what a scratch file is, its basically a file that you intend to dispose of that allows you mess about in. I use them all the time for deciding on my public API. Here's my little secret: write out your flow in full English. For whenipress, it would look something like this:

When I press a, b and c, then do something.

When I press a, b and c, then do something once.

When I press a, b, and c twice in rapid succession, then do something.

I really feel like this is key to a successful API. Anybody can read these sentences and understand what they do. Now all we have to do is turn them into functions and expressions.

Stage 4: The test suite

You can only get so far in software without tests. I decided to go the TDD route on this package, and there was one place in particular where it paid off in dividends.

From the outset, my mind had jumped to JS Promises. The word then had appeared in all of my sentences, so naturally, Promises seemed like a good fit. There are a couple of important lessons here. Most of you would already be able to tell me that you can only resolve a Promise once. I'd overlooked that completely. Does that make me a bad developer? No. Just because you forget something, or do something wrong, or don't know something, it doesn't make you a bad developer.

I did actually get pretty far with promises. That was until I wrote a test that did two key presses. All of a sudden, the problem jumped out to slap me in the face. Thankfully, I had a test suite. I could rewire everything and, so long as the tests passed, I was still golden. The refactor probably took 20 minutes.

If I hadn't had a test suite, this would have been an overwhelming test. I would probably have started from scratch for fear of breaking something. In all honesty, I might never have shipped it at all.

Stage 5: Try it out

So, after working on this for a while, I had something like this:

whenipress('a', 'b', 'c').twiceInRapidSuccession().then(e => alert('do something'))

This reads beautifully. But the focus has been lost. Our eyes are drawn to the twiceInRapidSuccession method rather than the then method. I sat and thought on this for a while. I needed it to be clear, but concise. In the end it was obvious:

whenipress('a', 'b', 'c').twiceRapidly().then(e => alert('do something'))

Much better. But does it really matter? If you want people to love what you've made, yes. Every key stroke is important. Every word used or omitted is a case for or against your package. Never underestimate the power of language, especially in programming.

Try out what you've made, and then change it until you feel its perfect.

Stage 6: Get somebody else to try it out

I'm not talking about another programmer here. I'm talking about a non-developer. Not a technophobe, not an idiot, but somebody who knows the bare minimum, if anything, about programming. In my case, its my wife.

I ask her to look over an example of my package and tell me what it does. This is the public API I'm talking about here, not the low level code. Your low level code cannot help but have complexity, but your public API should abstract that complexity away.

If my wife comes back with an "I don't know", I know I have more work to do. However, if she can give me a basic idea of what it does, I know I've got something golden.

Try it. I think you'll find it super useful when developing.


So, a wrap-up. Hopefully, you've learned something by reading this article. If you take anything away from it, let it be this: It is a fairly simple task to tell a computer what to do. The art comes in doing it in such a way that a human can understand what you've asked the computer to do.

And if you can master that, you'll create packages that people use, love and cherish.