We were really excited to announce our extensibility support for VS Code at the Connect(); //2015 event on Wednesday 18th November. We’ve been working on this for a number of months now and it’s great to see the large number of extensions that have been created in the month since the announcement. In this blog post, I’d like to talk about some of the interesting (and perhaps surprising) things we did while working on extensibility.
My role on the VS Code team is to help design the overall user experience that a developer has while using VS Code. The main way I do that is by observing people using the product. I watch what they do, see the problems they have, learn how they expect the product to work and generally try to get into the head of a developer using VS Code. I use the insights gained from these observations to identify ways we can improve the product, new experiences we should add, or things that we should change or consider removing.
In general, when people think about user experience, they often think about the user interface that a user works with in order to have a particular experience with a product. It’s the most visible contributor to the overall experience that somebody has.
But the UI only contributes to a subset of the complete experience. For a developer, the programming language and APIs that they use contribute significantly to the user experience that they have while writing code. If an API is complex and hard to understand the user is unlikely to have a great experience using that API. No matter how good the editor is that they use to write code against that API, they’ll be less likely to have a great experience if the API is overly complex.
We wanted to make sure that the complete experience of building extensions for VS Code was as good as it could be. We didn’t just want to make it easy to scaffold an extension with yeoman or to publish an extension to our marketplace, we wanted to make the extensibility API easy to learn, navigate and use.
Early on in the process of building the extensibility API we began a weekly series of UX research studies. In these studies, we focused on understanding the impact that particular design decisions we were making in the API had on the overall user experience. Each week we would ask around five developers to work with the latest build of our API and perform a set of specific coding tasks. We would ask them to talk out loud while working, to tell us what they were thinking about, how they were feeling, what they expected to do. We watched them while they worked, taking note of the things that they tried, the difficulties they ran into and how successful they were on each task.
Every week we had a specific area of the API that we wanted to focus on and learn about. The team would be designing a specific API and needed more insight about what users expected, or how they would react to some design. Because we set these sessions up to run every week, it was never more than a few days before the team could get that real feedback from users that would unblock them.
For example, one week we spent a lot of time focusing on how to enable extension builders to write an extension that would modify the content of the currently active editor. We learned that initially, many developers will expect that they can manipulate the content of the editor similarly to the way that they manipulate strings. For example, they expect:
One of our challenges with this API though was how to design it such that it makes clear to the developer that an edit can fail if the content of the editor changes while they try to make their edit. We explored different ways to communicate that edits should be built up and then applied in a transactional manner.
By watching developers use different versions of the API and talking to them about their experience with each version, we learned which of the different designs we were considering would likely work the best. Insights we learned from this study led us to ship the API we have today:
In the code sample above, we have provided an editBuilder which allows developers to wrap up all of the edits inside a callback. The developers in our study suggested that this was a better way to communicate that a set of edits need to be built up and applied in one transaction, as opposed to a series of separate edits that they had initially thought would be possible. Although there is more code to write, the underlying concepts are made explicit in this API.
Another week we wanted to learn about how to structure the overall API. Should it be a very flat API with most methods exposed at the root of the API but named in such a way that similar APIs are clustered together? For example:
Or should it be more hierarchical, with namespaces that collect together sets of related APIs? For example, in the snippet below the showInformationMessage and setStatusBarMessage APIs are underneath the Shell namespace:
By watching developers work on some coding tasks in each of these two different conditions we could see which style caused least difficulties for users and which they would prefer to work with. The overwhelming preference was for an API that is more hierarchical in nature (the second option above) and that does not have a large collection of methods exposed at the root.
It was really important for us to design the APIs based on an understanding of how other developers will use the API. Of course, we would use the APIs ourselves as we designed the API and use our experience to identify ways to improve the API. But the understanding we have of how the API works means that we can’t see it from the perspective of somebody who doesn’t have that background. What we consider simple and straightforward might not be considered so simple by a developer who wasn’t intimately familiar with how the API is implemented. Getting that outsider perspective on the API was vital to helping us build a great API.
As the weeks progressed, and more of the complete end to end experience was built, we became more aware of issues using the API that weren’t caused by the API but the VS Code UI. For example, when using intellisense to explore and learn the API, users weren’t able to read the complete signature of an API or any doc comments for each API as our UI was clipping the text if it was too long to fit inside the intellisense UI. This obviously makes it a little difficult to learn how to use the API. We hope to be able to address these issues soon as this will definitely improve the overall experience of using the API. Studying the complete experience a developer has leads to insights about both the design of the API and the design of the UI.
One of the great things about doing UX research studies on APIs is that it is easy to create a prototype. You simply need the public interface of the API in order to get a better understanding of how people will use your API. The API doesn’t have to be implemented – watching how people discover the namespaces, classes and methods that the API exposes, how they interpret the purpose of each object in the API, how they expect things to work can provide huge insights very early on in the process of designing and building an API.
So yes, we spent many hours watching people write code against undocumented and incomplete APIs. It was fascinating and provided many insights that we would not have been able to get otherwise. To everybody who participated in those studies (see the list below), some of whom participated in more than one study, we want to thank you enormously. We know that at times it wasn’t easy – coding against undocumented APIs never is. But your efforts and feedback helped us and will continue to help every developer that chooses to build a VS Code extension. Thank you!
Steven Clarke
UX Researcher, Visual Studio Code
Thanks to Samuel Boswell, Thiago Jedi Abreu, Joaquin Jares, Michael Louwrens, Matias Quaranta, David Wambugu, Drew White, Richard Ashwell, Andreas Pardeike, Jon Fritzler, Alan Hamlett, Abiola Ibrahim, Krzysztof Cieślak, Andrei Zubov, Scott Addie, David Driscoll, Chad Botha, Joel Bennett and Pascal Laurin for all their help.