JavaScript at SoundCloud
budapest.js, February 14, 2013
Márton Salomváry
salomvary@soundcloud.com
The Product(s)
A social sound platform for music & audio creators and consumers.
- 10 hours of music and audio uploaded every minute.
- Reaches 180 million people.
- Present on the web (+mobile), iOS, Android.
- API, platform integrations (Twitter, FB, Flipboard, etc.)
- Your app!
The company
- Launched in 2008
- Berlin (HQ), London, Sofia, and San Francisco
- 170 full-time staff, 30 nationalities, still growing
Technology
Past
- Used to be a huge Rails application.
- The whole stack went through an evolution.
- Deconstruction of the Death Star.
Technology
Future
- Smaller, independent components.
- Internal HTTP API.
- Multilingual
- Ruby
- JavaScript
- Go
- Java
- Scala
- Objective-C
- …
Technology
Repositories and files by language
Aaaand JavaScript!
The most relevant projects
-
New SoundCloud - the new frontend
-
Widget - embeddable player
-
Mobile - m.soundcloud.com
-
Deck - tool for content partners
How do we write JavaScript?
- We ❤ semicolons ;)
- We ❤ modularization.
- We ❤ MVC and Backbone.
- We ❤ writing JavaScript in JavaScript syntax.
Huh, no transpilers?
- Nope.
- But:
- The AMD syntax is ugly.
- → Generate a wrapper on the server!
The AMD wrapper
The ugly way
define(['foo', 'bar'], function(foo, bar) {
// stuff..
return { /* module definition */ };
});
The pretty way
define(function(require, exports, module) {
var foo = require('foo'),
bar = require('bar');
// stuff..
module.exports = /* module definition */;
});
CommonJS wrapper is
generated on the server
Tools
- Node.js and/or Ruby + Sprockets
- Development server (run-time rewriting)
- Build tasks
- Preprocess (JS, CSS, templates)
- Optimize
- Bundle
- JSHint with custom config
Third party libraries
- Backbone + Underscore
- Handlebars
- jQuery 1.7
- Resig's class.js
- SoundManager 2
Our libraries
- Additions to Backbone
- Mixin
- Singleton
- View
- Subview for Handlebars
Views, SubViews and Singletons
Template
<button>Play!</button>
<audio></audio>
{{ view 'views/comments' resourceId=id }}
Model and view
var Sound = Model.extend({
// model implementation
}, {
hashFn: function(attributes) {
return attributes.id;
}
});
var SoundView = View.extend({
ModelClass: Sound,
template: require('sound.hbs')
// view implementation
});
Singleton models and collections
- new Sound({id:1}) == new Sound({id:1})
- If already fetched: no need to fetch!
- Simple reference counting GC.
- View calls sound.hold() and sound.release()
Testing
- Tyrtle JS testing framework
- Nodejs and Phantomjs runners
- Sinon.js FakeXMLHTTPRequest
- Selenium browser automation (on the way)
- Jenkins CI
Exception tracking
-
Errorception.com (great for low traffic)
- Problems
- High traffic & diversity
- Smart grouping of exceptions
- Ignore by patterns
-
Google Analytics + custom events for statistical trends
The frontend
- Separete, frontend-only codebase.
- Uses the public API.
- Created by a team of 6 JS engineers.
- Took more than a year.
And btw,
we are hiring
all kinds of engineers and more!
soundcloud.com/jobs
Thanks!
Márton Salomváry
salomvary@soundcloud.com