Kurt Frey
aka
NitricWare
# Learning by adding features to Spotify
23.06.2018

One of the benefits of being able to develop software is that - sometimes - you can fix bugs in programs you use or add features you need to existing software. Spotify confronted me with the second situation and made me learn a multitude of programming related stuff. I'll go over the details of this process in this article.

This article is a long read. You can scroll down to the TL;DR section in which I recap the things I learned.

In the Spotify library of a user, one can find two different kinds of tracks. The first one is the more common one: a song hosted by Spotify, with a proper ID and all sorts of other meta tags. Spotify has the right to stream these songs. The second kind of tracks are so called local tracks. Those can be seen as links - or aliases - to songs that are stored on the user's hard drive. These songs are not in Spotify's repertoire and Spotify has therefore no right to stream them or store them in the cloud. However, the Spotify Player can play them on the device they were added.

I recently switched from iTunes to Spotify and was lucky enough that all the tracks I had in my iTunes library were actually available on Spotify. So instead of adding just links to local tracks, the Spotify Player recognized the - properly tagged - MP3 files as songs available on Spotify and added the songs hosted by Spotify to my Spotify library. I was able to play all the songs I had in my iTunes Library now on all my devices using Spotify.

The music business seems to be changing a lot, because obviously the songs Spotify added to my library became unavailable on Spotify eventually and they were converted to local tracks. Meaning I could only play them on the device I used to add them in the first place. A device which was not available anymore. A short search on Spotify revealed, that the songs are still available on Spotify but not as exactly the same songs. Maybe the album has changed (from the original album to a remastered one) or the original album became unavailable and the song is now only listed as part of a Best-Of album. However, most of the tracks were still available on Spotify in on or another form.

The feature, Spotify forgot to add would be called something like "re-add the song that just got removed because it's actually stille there". I added that feature and learned a lot about JavaScript, Cascading Style Sheets, Integrated Development Environments, the Hypertext Preprocessor and Application Programming Interfaces. My software will look at a playlist of your library which you specify and registers all the local tracks. It will then perform a search for each one of those and lets you choose which one of the search result should replace the song if any.

Spoiler alert: Not everything written in this article will be new to you and not everything written in this article will be best practice. This is just a story about what I learned. Since learning is a continuous process, this is not the be-all and end-all of the things covered. It's actually far from it.

In order to be able to implement the feature I needed, I had to become familiar with the Spotify API. This already taught me the first lesson. Documentation - namely a good one - is a critical feature of every software. Spotify provides the developer with a Web API Console allowing them to try out the features of the API. Sometimes however, the examples do not match with the documentation. And sometimes the example data breaks the Web Console. Things that should not happen. Also, at some point in the documentation it is stated that the Web API can handle some tasks concerning local tracks. But there are no examples which makes the feature unaccessible. There are even multiple - unanswered - issues on GitHub about that topic, which brings me to the next thing I learned: communication with other developers using your API - or other kind of software - is crucial.

Primarily I wanted to realize the project using PHP. So I started with a new class which would handle all the API requests. Soon I discovered that using PHP for front- and backend is maybe not the best decision when it comes to data-heavy cross-site API requests. Some requests - like fetching a playlist with over 700 tracks - took more than a minute. The UI would be blocked meanwhile without any way to inform the user. So I took a closer look at JavaScript. JavaScript is - nowadays - extremely capable. It has its limitations though. At first I thought of scrapping the whole PHP approach and rewrite it all in vanilla JS. With functions like fetch() writing software that connects to an API is very easy. Even Spotify's Web API's limitation of only outputting 100 tracks per request would not impose a huge problem. One could simply write a recursive function fetch()ing all the songs. There was, however, one particular problem stopping me from writing a pure JavaScript application: Spotify's Web API requires you to send a Client Secret. I couldn't find anything on how to securely obscure this Client Secret, so I went another path. Since I already had a working PHP backend, why not connect to the backend with a JavaScript frontend? I just had to make sure, that whoever accessed my backend's endpoints identified as my own app.

During my research I found what would solve my problem: a NONCE. However, I had no time to implement this feature yet. Basically it's a token, only the Server and the client share with noone else knowing.

When I started the project, I had to make some very basic decisions. One of which was: which PHP version should I go with? I think type hinting is a great tool to improve readability of code and also to simplify code. So I decided to use PHP 7.2 as the version to use and I must say, I liked it a lot. Even so much that I really missed it in JavaScript. For a short time I even thought about switching to TypeScript but ultimately scrapped the idea because I wanted to finish the software. Maybe a version 2 would go that route.

Speaking of preprocessors... I used Sass because it makes the process of nesting classes a lot easier. Also, Sass allows to play with the design in an early state of the software. With Sass one can use variables to define a color palette, font faces and other design elements that tend to change frequently in an early state. With variables, those values change once in the document and searching for each instance of that value is a thing of the past. Design-wise I wanted to make a flat UI but once I was done with it, I felt it was kind of boring. So I considered another approach: Skeuomorphic design. Quick refresher: Do you remember iOS before iOS 7? Yes? Then you remember skeuomorphic design. I always appreciated this approach and found it quite nice. Not only because you really have to craft a skeuomorphic UI. Designing a flat button is actually not hard. Designing a button that somehow feels like pressing a button once you press it, is way harder. I decided to go the - for me - hard route. While designing the UI of the software I learned about modern CSS features like the linear-gradient().

When you look at the software over at GitHub, you might wonder "hell, this software is far from finished. It lacks proper design and the nonce is not implemented either. This brings me to my final point: I learned, that I should release early - with maybe not all features implemented - or I won't release at all. Releasing the software early as OSS also other talented and skilled developers to help the creator out. Which by the way is VERY encouraged. Open issues, fork my project and file pull requests.

Thanks for reading this post. Here's my conclusion:

Conclusion / TL;DR / Take home message

In the process of writing the software, I learned a lot about writing software in a very general term but also about language-specific topics, benefits of IDEs and how to design user interfaces.

  1. I added a huge amount of comments to my code, documenting how things are done and what the code does. This does not only help myself when I review the code later on but also contributors who want to improve my software.

  2. Knowing how paralyzing it can be when there are no responses to your questions confirmed me in my thinking that communication with other developers is a crucial tool to make your software accessible to more users.

  3. During the process of making the application I learned about new aspects of languages familiar to me. Those aspects included type hinting in PHP, adding event listeners and dispatching events in JavaScript.

  4. Writing JavaScript code without frameworks proved to be simple. Of course frameworks like jQuery simplify some tasks but is it worth all the required bandwidth?

  5. Type hinting is a great tool to improve the readability of code.

  6. Sass enables a developer to easily prototype the design of a software because of variables.

  7. Skeuomorphic design is harder (but in my opinion more beautiful when done right) and requires you to think about your design more.

  8. Release early or you might not release at all.

See also

  1. Issue #886 (spotify/web-api) - concerning the lack of documentation when it comes to local tracks
  2. A cross-post of the TL;DR section of dev.to
  3. The software on GitHub
  4. The stack overflow post which taught me about nonce