Thursday, August 22, 2013

Communication at Khan Academy: Open By Default

I've only been at Khan Academy a few weeks now, and I'm still learning how they (we) work as a company and what makes their (our) culture tick. But, there's one thing that I can't help but notice: our communication is open by default.

I don't know how much of the openness was a conscious effort and how much was coincidence, but at this point, it's a definite part of the culture now. Here's where I've seen it:

  • Public Wiki: Khan has a Google Sites wiki, and it is actually openly viewable to anyone. Newly created pages are public by default, but can be made organization-restricted if it contains secret information. I almost thought it was a mistake at first, an accident, but it's very much on purpose. Khan works with many external volunteers, and it makes it easier if we can easily expose documentation about best practices and processes on the same wiki that we use for employees. There's a fine line between "internal" and "external" at Khan, and that blurriness is reflected in their communication.
  • Email Transparency: Khan is following Stripe's suit by trying out "email transparency", where everyone is encouraged to CC a "-blackhole" list on every email, so that anyone can find conversations later, but people can ignore the bulk of conversations (everything in the "Blackhole" filter, which we set up on our first day). So far, it's worked great for me - I've never regretted CCing blackhole, and I've also benefitted from responses by people who've found the email in the blackhole. At first, I was a little creeped out by what I saw in the blackhole, I thought "Am I really supposed to see this?" but now it's like, "Yep, we all share everything, that's how we roll." The email transparency is both a way of increasing openness and making it clear that Khan prioritizes openness in all aspects.
  • HipChat: After all that about email transparency: Khan doesn't do much human communication over email. Emails are largely for announcements and automated emails (like from Phabricator). The majority of day-to-day communication happens in HipChat, an IRC-like app. The engineering room has been my go-to room for getting started in the codebase in the last few weeks - whenever I have a question, whoever happens to be around will respond. The computer science room is filled with conversations about current projects and it's how we iterate quickly in development. When someone is working on a new feature, they'll post a screenshot of the WIP, voice any UI concerns, we'll give feedback, designers will post back mock ideas, and the cycle continues. We sometimes have 1-on-1 conversations too, but we try to funnel most conversations into the rooms, so that anyone can search through them later. Now, HipChat can also be quite distracting, so it's not a perfect solution. But then again, what is? (Besides Wave! :-)
  • Open Office: The Khan office is built in this big large space, with a few meeting rooms around the perimeter, then rows of desks, and the main meeting area is smack dab in the center of the room, with no walls. All of the all-hands and dev stand up meetings happen in that meeting area, so it's pretty hard to miss them, and anyone can pull their chair over and listen in. I think this is just an architectural artifact of the space, but the majority of meeting rooms have no ceilings, so there's not a lot of opportunity for keeping secrets. The usual objection to an open office is the high distractibility that can come from the conversations, but the office is eerily quiet for most of the day - and I think that's because all of those conversations are actually happening on HipChat. It's better that they happen on HipChat than in the physical space, since remote employees can chime in, and it's easier for others to chime out if they want to.

All in all, I'm loving how all of our communication is open by default, and it makes me feel good that I'm in an organization where everybody wants everyone to know what's going on and has built that into the culture. I'd love to hear from you about how your company culture ticks in the comments.

Monday, August 12, 2013

Why Do I Speak at Conferences?

When I worked at Google as a Developer Advocate, it was actually part of my job description to speak at conferences, since our goal was to increase the number of developers using the Google APIs and speaking at conferences was one way to achieve that goal. Since speaking was just an assumed part of the job, I never thought very deeply about *why* I spoke. I just thought about which conferences would have the greatest reach and sent out my trip reports after.

Now that I'm no longer in developer relations, it's not an official part of my job description to speak. Despite that, I still get invited to speak and I ended up speaking at 14 conferences and meetups over the last year. I'm lucky to work for companies that support and even encourage me to accept speaking opportunities, and they trust my judgement in deciding how often to speak and which conferences to speak at. Since I am now basically speaking of my own accord, I find myself thinking more deeply about why it is exactly that I speak. I don’t want to speak just because that’s what I’ve always done. I want to understand what it is that I get out of speaking and what I enjoy about conferences, so that I say "yes" to conferences with some degree of confidence in the future. Here goes!


What I Get of Speaking

It gives me a moment to step back and reflect. In my year at Coursera, I worked on many projects, and I would often work on multiple at once or jump directly from one to the other. When I had to put together a talk for a conference, it would force me to take a moment to stop working and just think, asking myself questions like “What is it that I’ve learnt that I think is worth sharing? What have I liked or disliked about the technology we picked?”

I think it’s really important to give a balanced perspective on a topic, and it’s easy for you to convince yourself that you’re doing everything the right way when you’re in moment, so I *need* that forcing function to make sure that I am actually considering all the angles. This is true as much about our approaches to frontend development (which I reflected on in the “Frontend Architectures” talk) and our approaches to social learning (which I reflected on in the “Social learning” talk at I/O).

It gives me a new way to share knowledge I’ve accumulated. When I learn things, I have this burning desire to share what I’ve learnt. I hate thinking that there might be someone out there who might benefit from what I’ve learnt, and me knowing that I’m hoarding that information. If my goal is to reach all those possible people that might benefit, then blogging has the most potential, but speaking has its own benefits. You can share that knowledge in a more interactive way, immediately see how attendees respond, and have fun telling a bit of a story along the way. If the talk is videotaped, then that can reach more people after the event’s over (I rarely ever watch videos of talks myself, but hey, some people prefer that format!).

It’s also not much work to turn a talk into a blog post or a series of posts, and you can focus the posts based on what the audience reacted most to. For example, my localStorage talk became a 2-part article series on Dr. Dobbs, and my “Frontend” talk, that was originally given to an audience of 30 or so, became a blog post with 30,000+ views.

I have to strike a balance between learning new knowledge and sharing what I’ve learnt, of course, and that’s been a struggle for me in an engineering role, but I think I found a good mix of coding, blogging, and speaking this year.

It gives me a way to learn new knowledge from many developers at once. After I give a talk on a particular technology, that gives developers in the audience an opportunity to come up and tell me about their experience with that technology, and often share different solutions from what I shared. I often find out about new tools and techniques this way, and I’ll share the ideas with my colleagues after. We don’t always have the time or resources to try them out, but I always appreciate knowing about new possibilities.

Like all the other attendees, I also get to learn from the presentations of the other speakers. I’ll often write down what my favorite talks were, and send out an email afterwards to colleagues or write up a blog post with a list of my favorites and links to slides.

It gives me an opportunity to meet the amazing developers of the tools I use. We used many open-source frameworks and libraries at Coursera, and conferences love to have the authors of those tools as speakers. Those developers are like our celebrities in the tech world, and hey, even if they’re not the best speakers, it’s like “whoah, the creator of X is speaking!” They often have unique insights because they know what the tool started as when they invented it in their mind, they’ve seen it grown, and they know where they want it to go. They’re also experts on the tool, and the person most likely to be able to answer your burning questions about how to use it.

Now, I could meet those developers as a mere attendee of the conference too, but I find it much easier to meet them as a speaker. Speakers have more inter-networking opportunities, like the speakers dinners, the flights, the walks back to the speakers hotel, the hand-offs between talks. At Webstock, I even found myself accidentally in the same post-conference vacation spot as the keynote speaker Ze Frank, and we wandered around the New Zealand bush together for a few days. Thanks to speaking at conferences, there are so many amazing developers that I’ve had the honor of having long conversations with, and those experiences are invaluable.


How I Decide Where to Speak

Since I’m in the fortunate position of being invited to speak more than I think I probably should, then I must look at each speaking opportunity and decide for myself whether to say yes. It’s incredibly flattering to be invited to speak - the little girl inside me squeals, “you like me! you reallly like me!” when I get those emails - so I really have to force myself to not reply with my gut reaction of “yes, of course!”.

Here are some of the questions I ask myself about the conference:

  • Location: Have I ever been to the location? Will it be good weather at the location? If it’s a foreign city, is it safe for me to wander around? If it’s not safe, will there be locals willing and eager to escort me, or will I be hiding out in my hotel? Do I know anyone else in that location that I want an excuse to visit, anyway? I love traveling and seeing the innards of different cultures, so if I am picking a conference because of it’s location, I want to know that I will actually get to experience that location fully.
  • Distance: How long of a flight is it? Will it be non-stop or be a horribly annoying 3-stop ordeal which could possibly get delayed? How jetlagged will I be? I’ve been invited to conferences in incredibly exotic locales, but then I stick “SFO -> XXX” in kayak.com, see the kind of itinerary I’d have to take to get there, and decide it’s just not worth it. If I was going to turn the conference into a longer vacation with a friend, then sure, it might be worth it to spend so much time traveling, but not if its just me.
  • Timing: Is it during the week or weekend? If its during the week, will I miss our weekly team meetings, show & tells, all hands, or any interesting tech talks? Will it be in the middle of any big launches? If you can’t guess, I prefer weekend conferences, where I don’t feel like I have to sacrifice missing out on things at work.
  • Topics: Does the conference cover a lot of topics that I’m interested in? I’m often invited to more general software conferences, and though I appreciate getting to see topics from way outside my niche, I come away with much less immediately applicable knowledge. On the other hand, sometimes I take advantage of not caring as much about other topics, because it means that I know I can create my slides at the conference itself and not worry about missing anything.
  • My Topic: Will I get to talk about a topic that I’m truly interested in now? Will it be a new presentation or will I recycle an old presentation? I’ve been asked to speak about mobile a few times this year, which I can understand because it’s a hot topic, but I haven’t done PhoneGap in more than a year, so I could not deliver a talk on mobile with confidence. The technology scene changes rapidly in our industry, so if I’m talking about a technology, I better have used that damn recently. As for new versus recycled presentations, I sometimes feel like I don’t have the time to put together a new talk, or that I don’t have any new topic that I’m burning to talk about it, so I’ll only agree to speak if I can recycle a previous talk. I try to be transparent about that, so that the organizers know that it’s not entirely new content.
  • Organizers: Is it organized by a corporation or is it community run? I’ve found that I’ve most enjoyed the conferences that are put together by communities. They tend to care the most about really making it a great experience for both attendees and speakers, and they’ll often go to care to give you a more local experience. The conferences also have a different feel to them - there’s this vibe of “we’re all in this together” that pervades everything, and that’s a great environment for a speaker.
  • Sponsorship: Will the conference pay my way? Most conferences require some sort of travel, and if they do, I will only speak if they’re able to pay for the hotel and flight. Sure, Coursera probably would have been happy to pay for 1 or 2 conferences last year, but they’re a startup, and I don’t think its reasonable to expect them to afford more than that for a single engineer, and conference organizers work hard to get sponsors so that they *can* pay for speakers that need it. And I will ask for it. :-)

I don’t have a scientific way to ask all those questions about a particular conference. As much as I wish I could just stick it all into a formula and get a discrete answer out, I don’t think it’s possible or reasonable. Conferences are experiences, and anything can happen at them, and it’s hard to predict the things you’ll learn or the people you’ll meet that will have the greatest effect on you later. I can ask these questions to try to approximate an answer, and try and reassure myself that I’ve made the right decision, but in the end, it is only an approximation.


What about you?

If you're someone who speaks at conferences, I'd love to hear about what you get out of it and how you decide which conferences to go to. If you're not someone who speaks at conferences yet, then I encourage you to try it out. Start small if you'd like, like with internal demos, lightning talks, local meetups, and work your way up. Find a topic you're passionate about and share your knowledge. I guarantee there's something that you know that other people want to know too.Maybe you'll find you love speaking — I literally feel a surge of adrenalin kick in 5 minutes into every talk the lasts for hours after — or maybe you'll decide it's not your thing. But, hey, it's worth finding out. Report back once you find out!

Tuesday, August 6, 2013

My Next Adventure: Khan Academy CS

To quote my Twitter profile, I "learn, create, teach, and repeat." Well, since I do most of my learning in the space of computer science, that's where I do most of my creating and teaching too.

In middle school, one of my first web pages was titled "HTML iz FuN!" and gave gory details of using the <font> tag to create rainbow colored text. In high school, I helped my dad with his "Saturday Java Academy", where we tricked my friends into spending their weekends learning Java. That's also where I first got asked out - with a Java applet - and of course, I couldn't say no to an object-oriented solicitation. In college, I ran workshops on graphics, 3d scripting, and web programming, the kind of programming that made me love CS, but that we never had time for in our pointer-laden intro classes. At Google, I got to teach developers how to use the Maps API, and as it turns out, there are few things more fun in life than making maps. Nowadays, I get out my teaching urges in GirlDevelopIt web development workshops.

I looked back on all that recently and realized that I've spent many hours of my life teaching programming and thinking about how to teach programming. What order should topics go in? How can students figure out what level they're in? When should students pair, and when should they go at it alone? What exercise will help a student learn a topic and challenge them, but not to the point of giving? In an in-person workshop, what's the allocation of lecture time vs. exercise time? Online, how can you provide hints without making it too easy? Should a student's first language be the most practical or the most newbie-friendly? What language features trip a student up the most?

I find these all to be fascinating questions, and I decided I want to spend more of my day thinking about them - so I found a place where I could do that. Starting this week, I'll be spending my days at Khan Academy, working with John Resig on the Computer Science curriculum that he kick-started last year. I'll be both an engineer, coding up the pieces to make it a great interface to learn, and I'll be a content creator, putting together tutorials and exercises. I also hope to visit schools that are using the curriculum and watch how they incorporate it into classrooms. In this role, I'll be learning how to create tools that teach the next generation about programming, and man, I'm excited.

I know that many before us have thought about how to make programming easier to learn, and I'm looking forward to learning from them. I've started reading related research papers, watching talks, and building up an Amazon wishlist of books on programming and early education. If you have any suggestions to add to those lists, let me know. I've also started to find out about the feedback that Khan has received on the existing curriculum framework, and well, I better finish this blog post soon so I can get started on addressing that feedback.

If you've ever read one of the great blog posts by Ben Kamens or forked one of their open source repos, then you know they have a great culture of sharing and openness - one that I look forward to contributing to. Stay tuned!

Friday, August 2, 2013

JavaScript UI Library Design

Preamble: This write-up is inspired by the talk I gave at BackboneConf 2013.

For the last year, I worked as a frontend engineer at Coursera. We constantly found ourselves needing UI widgets to decorate our interfaces, like modals, popups, tooltips, uploaders. You know, the same widgets that 99% of websites need, plus a few niche widgets.

We wanted to use the same UI widget libraries both in the legacy global-variables-roam-free codebase and the shiny-requirified-backboney codebase. We started with what most developers start with, jQuery plugins, but then we ended up coming up with our own way of architecting UI plugins to meet our particular constraints and satisfy our particular desires.


On jQuery Plugins

Now, don't get me wrong; I'm forever grateful for jQuery and its plugins ecosystem. John Resig released jQuery in 2006 with a plugin mechanism from day 1, and the first third-party jQuery plugin came out only a few weeks later. A year later, the community launched the plugin repository, further encouraging developers to create and share their plugins. They also launched jQuery UI soon after, which gave developer more of an architecture and base for UI plugin development. jQuery plugins became the defacto standard for UI library development and thanks to jQuery encouraging developers to share their creations, there are now thousands of plugins for developers to pick from.

But, that doesn't mean that jQuery plugins are perfect. To begin with, many jQuery plugins lack an architecture or vary wildly in their internal architecture. The original jQuery plugin "architecture" was as simple as attaching a method to $.fn and processing the passed in element. jQuery UI eventually introduced a generic widget factory with more of an architecture, and developers like Addy Osmani wrotes articles on best practices for plugin design. But it's hard to know how many plugins actually follow those best practices, particularly the older ones, and from a purely anecdotal perspective, I've gone through the source of enough plugins to suspect that the majority do not. Now, the internal architecture wouldn't matter if plugins were just blackboxes that did what you wanted them to do. But, they're not - they are chunks of JS code that your code depends on, code that you will likely find yourself debugging and patching to better suit your needs. If they follow a set of best practices and standard architecture,then they're more likely to work well and be easier for developers to dive into.

Besides that, jQuery plugins are inherently dependent on jQuery. Yes, most websites use jQuery these days (including all of Coursera), but it'd be better if there was a standard way to write UI libraries that did not depend on any libraries, and the UI library would only bring the libraries in that it truly needed. Plus, some of the best plugins are dependent on jQuery UI, since it includes the widget factory and offers features like draggable/sortable, and jQuery UI is a heavy addition to an app that isn't otherwise using it. It's also often difficult to use the jQuery UI JS without the CSS and its subsequent look & feel.


Rethinking UI Libraries

After trying to write some custom Coursera UI widgets as jQuery plugins, we decided that it might be more useful for us to start over and figure out how to architect our UI libraries for everything that we wanted out of them. We wanted many of the things that developers want in jQuery plugins, like customization and events, but we also wanted zero dependencies, AMD-compatibility, designer-friendly declarative usage, and more. As an example, I'll step through the creation of a library that emulates <marquee> functionality, because, seriously, there are so many times in life that I need a marquee.


The Basic Marquee Library

We'll start off with the basic library. The library user will write this HTML:

<div id="marquee-me">Yo Wassssup!</div>

And write this JavaScript:

var marquee = new Marquee(document.getElementById("marquee-me"));
window.setTimeout(function() { marquee.stop(); }, 5000);

The code that makes it work is in this JSBin. I've used standard OO JS to create a Marquee object, setInterval to start the element moving via CSS positioning, and clearInterval in the stop method.


Hidden Private Functionality

As I learned from my many years on the Google Maps API, developers using a JS API *will* find every single possible un-documented method and use them in their production code, and they'll get mad once that method stops working. After that experience, my approach now with libraries and APIs is that you should try to keep everything private until absolutely necessary; until developers are groveling at your doorstep for the functionality and you feel confident enough that you can test and maintain that functionality. Hiding functionality isn't as crucial for internal libraries, but I still think it's a useful to make it clear which methods a library author originally intended to be used by the outside.

In the original code, library users could easily call marquee.moveItMoveIt(), a method that I intended to be private (I'd never expose such a silly name!), so I want to restrict that. In the new code, I've wrapped everything in a MarqueeModule that includes a _private object with the moveItMoveIt method as a member as well as the Marquee object which now only has the stop method. Then MarqueeModule returns the Marquee object, and window.Marquee is set to that return value. There's no way now for library authors to access _private, since that's a local variable that was never exposed or returned.


Idempotent Constructor

We developers are forgetful. Okay, at least I am, and I want to make sure that if I call a constructor twice on the same element, I only really construct the UI component once. That way, I don't have to worry about checking everywhere that a UI component may have been constructed and I can just call it again for good measure. This is the fancy concept known as "idempotence".

In the previous code, if a library user called Marquee twice on #marquee-me and tried to stop() it, the marquee would go on forever and ever, because it started two setInterval's. Now, we wouldn't want that.

In the new code, I've added a private getOrMakeMarquee method that checks if there's already a Marquee object associated with the element, returns that if so, and constructs a new one if not.


Customization and Defaults

When a developer can customize their usage of a UI library by just specifying a few options, it gives them a way to change the library without having to go into the code or write their own. That's why many popular libraries boast many options (just see the Select2 demo page for an example). Of course, more options means more to maintain and test, so we don't want to add options just because, we want to add them because we have some inkling of how usage will vary of the library.

For Marquee, we might realize that library users will want to vary the distance and direction:

var marquee = new Marquee(document.getElementById("marquee-me"), 
    {direction: 'forwards', distance: 100});

They also might want to re-specify options later, and have the library pick up the new options:

var marquee2 = new Marquee(document.getElementById("marquee-me"), 
       {direction: 'backwards', distance: 1});

To support options in the new code, I added a defaults object at the top that clearly documents every option, its default value, and its possible values. I then added the customizeMarquee method that merges the passed in options with the default values, and I call that both from the constructor and the getOrMakeMarquee method.


Declarative Customization

The Coursera designers like to work in HTML and CSS to craft the interfaces, and they even have Github accounts and local servers running on their machines to make it possible for them to actually check out branches, tweak HTML, and send changes for review. They're not quite at the stage yet of JS, and given the non-linearity of our JS, it's not so easy to poke around for newbies, so the frontend engineers try to make it possible for them to edit as many things about the look and feel as possible in HTML and CSS alone. That means that when it comes to UI libraries, they should be able to customize the widgets without diving into the JS. And hey, as it turns out, developers like being able to customize in the HTML as well.

For example, for the Marquee library, it should be possible to use data attributes to customize it like so:

<div id="marquee-me" 
     data-marquee-direction="backwards" 
     data-marquee-distance="5">
     Yo Wassssup!
</div>

To support that in the new code, I modified the customizeMarquee method to check the data attributes for each option, and use that if none were specified in the JS.


Declarative Construction

Why should developers and designers have to use JS to initialize a UI widget at all? We could just have them add a specific data attribute that indicates an element should be transformed, and as long as the page included the JavaScript, we'd transform all the matching elements.

For the Marquee library, we could add an attribute like data-marquee:

<div id="marquee-me" 
     data-marquee
     data-marquee-direction="backwards" 
     data-marquee-distance="5">
     Yo Wassssup!
</div>

To support that in the new code, I added a new method called start to the public object. That method takes in an element, searches for any elements with the data-marquee attribute, and calls getOrMakeMarquee on them. We call that method on document.body when the library is loaded, so it can pick up anything that exists already. If we're using this library in a Backbone app where we often construct the HTML after the fact, then we'll still need to call that method on the view element once everything's rendered. Theoretically, we could use Mutation Observers to find out about DOM changes that introduce new data-marquee elements, but that's a new and not widely supported browser feature.


Observable

Another way to let developers customize their use of a library is to let them specify callback functions to happen at particular times in the lifecycle of a UI widget. Many libraries still do this via options, letting developers specify things like an onClick callback. That approach isn't the best, though, since it means only one callback can be assigned, and it clutters up the options hash. The preferred approach is to let developers add event listeners to the widget for whatever event they're interested in. Just like with options, events should be tested for and maintained, so we only want to fire those events that we are prepared to support.

In the Marquee library, we might realize we want library users to find out when the marquee reverses direction, like so:

var marquee = new Marquee(document.getElementById('marquee-me'));
marquee.on('reverse', function() {
  document.getElementById('marquee-me').innerHTML = marquee.direction;
});

To support that in the new code, I added an EventTarget object (copied from this article). and made the Marquee object extend it. Then I can call this.fire('reverse') at the appropriate time.


AMD-Compatible

At Coursera, there are some codebases that use RequireJS to manage dependencies, and some codebases that just shove everything into the global namespace and hope for the best. Not that I'm advocating for the latter, but hey, I bet there a lot of codebases out there that do that, especially smaller ones. We want our UI libraries to work equally well in each codebase, and not have to use separate copies for each.

In an AMD environment, we should be able to use Marquee like so:

define("lib/marquee", function(Marquee) {
  var marquee =  new Marquee(document.getElementById('marquee-me'));
});

To support that in the new code, we added a conditional at the end which checks if define is defined in the AMD way, and if so, it wraps the module in define. If not, then it attaches it to window.Marquee like before.


Declared Dependencies

Most UI libraries will indeed depend on additional libraries - and that's understandable. The code in a UI library should be focused on the unique functionality of that library, not on re-inventing the code of libraries past. So we want a way to bring in those dependencies that works in both the AMD and non-AMD environments.

For the Marquee library, I would likely bring in jQuery for my DOM manipulation and data attributes, as my current code is nowhere near being cross-browser compatible. You can see that in this code; all I do is change the define block at the end and pass the $ to MarqueeModule at the top.

I would also use LucidJS for the event emission, as it's a great little library that's easy to mix-in to an object in a non-obtrusive way. You can see that in this code.

Many of the Coursera UI libraries also bring in Underscore for data manipulation, extend to process options, debounce, and some bring in Q for promises.


Testable

As I've mentioned in many of the above points, we should have tests for all publicly exposed functionality, options, and events. In fact, we should probably test UI libraries even more than our normal application JS, because we will be using these libraries multiple times, and it is more likely that a developer from another part of the codebase will accidentally "abuse" library, using it in a way that the author never expected. If there are tests for the library, then it's easy to add regression tests for the new and interesting ways that the libraries gets used, or add a test that ensures it can't get used that way.

For the Marquee library, I wrote a small suite of 7 tests that check construction, options, declarative usage, and events. That suite is built on Mocha and Chai, but the tests could just as easily be written in QUnit, Buster, or Jasmine. The typical Coursera testing stack is Mocha and Chai with JSDom, so that the UI library tests can be quickly run outside of a browser environment as well.

I did run into a problem testing Marquee that I also ran into with Coursera libraries: now that we've hidden the private functionality, how can we test them? We don't usually care about calling them directly (though there are cases where testing that could be useful), but there are times when it would be useful if we could use Sinon to stub out private functions and simply verify that they were called during the execution of a public function. There are various posts like this one the discuss testing private functions in JS, and I don't think there's one technique that's clearly the best yet.


Documented

Developers should not have to read through a library's code to understand how to use it. Even if you've written the most beautifully usable code in the world (at this point, I will remind you how most parents think their babies are beautiful, when in fact they're screaming trolls). At the minimum, add a comment at the top which shows an example of using the library, both the HTML and the JS needed. If you want users of the library to appreciate you even more, add more examples of advanced configuration, write up an explanation of why the library exists and what future work remains, and point to examples of real world usage of the codebase. Remember, you want your colleague to look over at you with an adoring look on their face, not a begrudged glare.

For the Marquee library, I added a readme with a short history and usage examples.

Remember: when in doubt, document.


Real World Examples

Now that we've walked through the Marquee library together, I've shown you many of the design patterns that power the Coursera UI libraries. You might be wondering what these look like in a "real library", as you likely suspect that the Coursera designers never let me get away with Marquee-ing everything. You'd be right...so here are some actual Coursera UI libraries.


ReadMe

The ReadMe library displays a banner at the top of a page, which will be displayed until a particular date or until users close it a certain number of times. The Coursera frontend lead built this after constantly wanting banners like this to announce new functionality to students and admins, and it's now in heavy use.

To use this library, we'd write HTML like this - notice how we can stick data-readme-close on any element to tell the library that clicking it should close the banner:

<div data-readme="watchlist-announcement" data-readme-show-count="1" data-readme-show-until-closed="data-readme-show-until-closed" data-readme-show-expires="Jun 15, 2013" class="hide readme">  We now give students the ability to "watch" classes they're interested in, which replaces the need for TBA sessions.
  <a href="https://class.coursera.org/mooc/forum/thread?thread_id=472" target="_blank" data-readme-close="data-readme-close">Read more here.</a>  <div data-readme-close="data-readme-close" class="readme-close-icon"><span class="icon-remove"></span></div></div>

Then we'd call ReadMe on the element:

new Readme(this.$('.readme'));

You can see the full code here.


Modals

Like any proper webapp, Coursera uses a lot of modals. The modals library was built as a replacement for the Bootstrap modals library (which didn't do enough) and the fancybox library (which did too much and was heavy), so it was designed to let developers use the Bootstrap CSS if desired, but not force it.

To use it with Bootstrap CSS, we'd write HTML like so:

<div data-modal-overlay-class="coursera-overlay-dark" class="modal coursera-course-selfstudy-modal hide"> 
   <div class="modal-header"><h2>What is "self study"?</h2></div>
   <div class="modal-body"><p>Self-Study bla bla bla....</p></div>
   <div class="modal-footer"><button data-modal-close class="btn btn-primary">OK, I got it!</button></div>
</div>

We could then trigger it via an HTML anchor:

<a data-modal=".coursera-course-selfstudy-modal" role="button">?</a>

Or we could programmatically open it:

Modal(this.$('.coursera-course-self-study-modal')).open();

You can see the full code here. The start function is a bit more interesting in the Modals library, because there should only ever be one Modal open at once, so it takes care of closing previous modals and enforcing the singleton nature of this UI widget.


PopUps

The Popups library is similar to the Bootstrap popovers library, a UI component that pops up next to an anchor, and remains there until the user moves away. Coursera uses it for dropdown menus, hover cards, and more.

To use it, we'd write HTML like this for the anchor. Yes, it's a lot of HTML, and that's because we need our UI to be accessible, so we must add the appropriate ARIA attributes that signal both that the anchor is a button and that it is associated with an expanded menu.

<li class="course-topbar-nav-list-item"
    tabindex="0" role="button" aria-haspopup="true"
    aria-expanded="false" aria-owns="course-topbar-aboutus"
    data-popup="#course-topbar-aboutus"
    data-popup-bind-open="mouseenter" data-popup-direction="se">
    <a>About <i class="icon-caret-down"></i></a>
</li>

We'd write this HTML for the actual popup content - no ARIA required here, as the library itself adds what's necessary. We wrote the ARIA roles manually in the anchor HTML, as we don't necessarily run the JS until the anchor is interacted with, and it needs to be accessible from the beginning.

<div id="course-topbar-aboutus" class="course-topbar-sublist">
    <a class="course-topbar-sublist-item" href="/about/jobs">Jobs</a>
    <a class="course-topbar-sublist-item" href="/about/team">Team</a>
</div>

You can see the full code here. A few things to notice: 1) it documents the accessibility requirements clearly, 2) it enforces that only one popup is open at once, like modals, 3) if the specified activation event is mouseenter but the current browser is a touch device, it uses click instead.


And Many More

Those are some of the most frequently used UI libraries at Coursera, but as you can imagine, there are many more: a custom A/B testing framework, a media uploader using Transloadit as a backend, a rich text area with Markdown and HTML support, tooltips, calendar date picker, affix, draggable, sortable, etc. They vary in how much they adhere to the design patterns I've laid out here, but going forward, the frontend lead tries to enforce them in reviews of new libraries and backport them to old libraries. It's important that new developers that join the engineering team are presented with a consistent architecture, because they'll naturally follow that architecture when building new libraries.


Wrapping It Up

You might be looking at everything I just showed and thinking, "wait, couldn't we do all that with jQuery plugins?" I bet that you could, and I bet there are jQuery plugins out there that do all of that and more. We just went down the route of starting from scratch to see what we'd end up with at the end, given our particular constraints and desires, and I'm sharing what we came up with. I encourage you to share your own best practices for UI library design in the comments, or try out some of the ideas here in your own projects and report back.

Thursday, August 1, 2013

The JavaScript Rap

Last year, I gave a talk at EverywhereJS called "JS in the front, REST in the back" about our frontend-heavy architecture and the advantages of it. I thought that the title had a nice rhyme to it and that it almost seemed like to start of a rap, and I always like an excuse to sing and dance in my talks, so I started an EtherPad with one stanza in it, and asked Twitter to take it from there.

I discovered that my Twitter followers are all rhymers at heart, and they should probably all just give up coding and spend their time penning mad rhymes. But, actually, they're also JS ninjas: their rhymes mentioned the most obscure of JS features and the new ES6 hotness. Since the etherpad gets "vandalized" a lot, I've decided to snippet it here for posterity. If any of you actually record yourself rapping this whole thing (or country singing it, that's cool too), please let me know. It would make my day/life.

Update: I dared Adam Sontag to deliver the rap as the closing for BackboneConf, and he got through a whole 40% of it. Check out the video here. Best conference closing ever.

Update 2: You can now listen to JavaScript speaking the rap. Amazing. Better than I could ever do it.

Give me the Mic
Crockford and Eich
From Netscape to Node
It’s been quite a hike
 
JS in the front, REST in the back
Ain’t it time you changed your stack?
Server-side rendering? That’s just whack
Once you go Backbone, you never go back
 
Unobtrusive set us free
It all blew up with jQuery
Now it’s MVC with TDD
Ain’t got time for PHP
 
Onclick to Require was such a ride
With GitHub code ain't got no where to hide
my lack of globals is a point of pride
I’m hitting my stride on the client-side
 
Stop testing IE 6, it’s a trap!
Been crap since way back, everybody knows that
Standards make dev such a snap
And don’t get me started on space vs. tab. [mic drop]
 
Use Grunt, watch it automate on a dime
Don’t waste no coding time
AMD will make you feel cool
Loose Coupling so you won’t look like a fool
 
Just sit right back hear the tale
Brendan’s gonna make, we cannot fail
We ain’t got three hours, it’ll take ten days
Born from scheme and self in a lispy haze.
 
And amp, semicolon, the rhymes, I got plenty
I got the space encoded, fool it’s percent twenty
my var’s locked in closure, that’s dope
Ain’t no bleedin or leakin’ since I’m in the right scope.
 
Yo, JS is /the/ form,
where I code like a storm
Free from spaghetti!
Fierce like the Serengeti
If that bug’s hard to track
console’s got your back
 
Code it DRY, code it right
Browser, server, world; its all in sight
Use the remote debugger
Like there ain't no other
 
You code in JS, but you mixing the types
And always forget the syntax for “splice”
To type “double equal” is like rolling the dice
And you scared to death … of prototypes
 
It’s time to stand up and get some respect
Just go to ECMA and read the fucking spec
Unpuzzle, unlock it, uncode and decrypt
And gain yourself power of true JavaScript
 
You add number to string and string to array
Divide it by object (you know it’s ok)
The prototype chain you can see through the code…
It was a great journey from Netscape to Node.
 
`eval` is evil and `with` is whack
F*ck classes — you can have ’em back
This is the generation of floating math
No tail calls in this giant stack
 
Var i, math dot pie in the sky
Fly tries to catch zero size
arrays with new prototypes are lies
disguised as wise overrides
prefix with java, ecma, mocha, and live
script all day and all night
microsize your JS lines
but don’t self minify
above all else, yo, f*ck static types
 
Go async and then you’ll never look
(this line will run before the last’s call)
back. Stop waiting for some slow IO
and start using four cores in your MacBook Pro.
fat arrow lambda, func’d the funky
close over this, ya JavaScript junkie
comma abuse, ASI hack
truth-y compare, you'll wanna redact
Bask in the glow, open/close brace
of any indent, Insignificant whitespace
`arguments` array? It isn’t that hard
You ain’t gotta call Captain Picard
 
My macros are sweet, my models aren’t fat
My build script’s complete, unit test — all that
Controllers are trim, view models fine
E.C.M.A. - TC-39b
 
functional code, is what I’m rockin’
dot foreach and map, reduce ain’t lockin’
those mutable props, makin’ me sneeze
I think I’m allergic, object dot freeze
 
while cache clonin’, weakMap for me
gimme some has-Own-Prop-er-ty
awaiting for no one, renaming a file
async is alright, actor callback style
 
Google Go code-gen, in fat reams
Don’t need no types, or agile teams
Slingin’ that node, gimme pipes, gimme streams
Gimme that Harmony, of our dreams
 
My code is lean, it ain’t all swollen
I love my braces and my semicolons
It’s ok now, don’t you be tight-lipped
it’s ok to say you hate CoffeeScript!
 
It was all a dream 
I used to code vanilla JS on the scene 
Now I got Backbone and Zepto all up in the IDE
JS is blowin’ up like I thought it would 
New frameworks, but same language in the hood.
And it’s all good.
So if you don’t know, now you know, coders. Uh.
 
Hey yo server siders clogging up the rear
Stop making it complex, I’m starting to tear
try the frontend, that’s where it’s at
Power to the coders, got nothin’ to catch