Loading Spinners With AngularJS and Spin.js

Spin.js is a tiny JavaScript library that helps you create beautiful loading spinners on every web browser up from IE6. It is highly customizable, fast, and has zero dependencies. I’m using it in my AngularJS application to display loading spinners inside my ng-views while my REST API responds with the data the view needs to render itself.

I add a viewLoading boolean to the $scope of each controller that talks to the REST API. The initial value of viewLoading is true.

angular.module(‘MyApplication’)
  .controller(‘MakesTonsOfAPICalls’, function($scope) {
    $scope.viewLoading = true;
  });

After all the API calls complete successfully, I set viewLoading to false.

angular.module(‘MyApplication’)
  .controller(‘MakesTonsOfAPICalls’, function($scope, MyLargeModel) {
    $scope.viewLoading = true;

    // Grab all MyLargeModel objects.
    MyLargeModel.get({}, function(result) {
      // Do something with the result.
      $scope.viewLoading = false;
    });
  });

If I have to make multiple calls, I use the $q service to create a promise for each of them. Each promise is resolved or rejected depending on the status code that the API call returns. I then use $q.all() to call a function when all of the promises have been resolved. This function sets viewLoading to false. I will talk more about $q in another post, but here is a rather simplistic example for now:

$q.all([promise1, promise2 ... promiseN]).then(function(data) {
  $scope.viewLoading = false;
});

I want the loading spinner to be displayed for as long as viewLoading is true, and be replaced by the actual view content as soon as viewLoading becomes false. I use a directive to do this. This is what the markup looks like:

<div ng-controller=”MakesTonsOfAPICalls”>
  <div my-loading-spinner=”viewLoading”>
    <! — actual view content goes here. →
  </div>
</div>

And this is what the directive looks like:

angular.module(‘MyApplication’)
  .directive(‘myLoadingSpinner’, function() {
    return {
      restrict: ‘A’,
      replace: true,
      transclude: true,
      scope: {
        loading: ‘=myLoadingSpinner’
      },
      templateUrl: ‘directives/templates/loading.html’,
      link: function(scope, element, attrs) {
        var spinner = new Spinner().spin();
        var loadingContainer = element.find(‘.my-loading-spinner-container’)[0];
        loadingContainer.appendChild(spinner.el);
      }
    };
  });

For this to work correctly, the Spin.js code has to be loaded before the directive code.

The directive is restricted to attributes only and replaces the original content on the page with the content from my template. I set transclude to true so I can re-insert the original content back into the page later. If you look back at the HTML for the view, you will find that the value of the myLoadingSpinner attribute is viewLoading. When Angular encounters our markup, it will create a two-way binding between the loading variable in the directive’s scope and the viewLoading variable in the parent controller’s scope. If you find this confusing, you may want to read about directives on the AngularJS website.

Before I explain the link function, take a look at the directive’s template:

<div>
  <div ng-show=”loading” class=”my-loading-spinner-container”></div>
  <div ng-hide=”loading” ng-transclude></div>
</div>

The markup is simple enough. The div with class my-loading-spinner-container is displayed when loading is true, and hidden if it is false. The second div is hidden if loading is true, and displayed if it is false. The second div also uses ng-transclude to re-include into the page the original content that was replaced by our directive.

Finally, the link function creates a new loading spinner, finds the div with the class my-loading-spinner-container, and puts the spinner inside the div. Hence, the spinner is displayed as long as loading is true, and the actual content is shown when it becomes false, which is exactly what we want.

Simulating a Slow Internet Connection

I am currently working on a single page web application written with AngularJS that communicates with a REST API written with Django and Tastypie. Since I run both the client and the server locally on my machine, every HTTP request that my AngularJS application makes receives a response from the REST API in tens of milliseconds. This is not ideal.

In the real world, Internet connections have latencies that range anywhere from a few hundred milliseconds to tens of seconds. To give my user a smooth experience even on a slow internet connection, I need to ensure that she receives appropriate feedback whenever she performs an action that requires a round-trip to the server. For example, when she navigates to a view that requires a large amount of data to be fetched from the server, my application needs to display a loading spinner of some sort on the screen to indicate progress. I cannot have the UI be completely blank for the time it takes my API to respond to the HTTP request.

Unfortunately, if I run the application locally, it becomes impossible for me to test my progress indicators. The request-response cycle completes so quickly that they are replaced by the actual content within a split second.

After searching the Internet in vain for a solution that would let me simulate a “real” Internet connection from within my browser, I wrote a Django middleware that uses time.sleep() to delay each HTTP response that my application returns by 0 to 4 seconds.

import random
import time

class SlowPony(object):
    def process_response(self, request, response):
        time.sleep(random.randint(0, 4))
        return response

Then I added this middleware to my MIDDLEWARE_CLASSES:

MIDDLEWARE_CLASSES = (
    # …
    'my_application.middleware.SlowPony',
)

I don’t like this solution. For one, this does not cause any of the requests to time out, which happens frequently on mobile Internet connections. It’s better than nothing, though.

I find it surprising and disappointing that neither Firefox nor Chrome let me simulate slow Internet connections via their developer tools. Fast, reliable, low-latency Internet connections are a rarity, especially since a large and growing number of people browse the web using mobile Internet. This situation is unlikely to change for several years in the future, and tools to test our web applications in such scenarios are either incomplete or non-existent.

An Introduction to CMake

GameDev.net recently published a four-part series on writing cross-platform build systems with CMake. The series first covers the very basics of CMake, followed by a tutorial on how to add unit-tests to your codebase using googlemock. Parts 1, 2, 3, 4. (Edit: with the release of CMake 2.8.11, a fifth part was recently added.)

I consider myself lucky that I don’t have to work with C++ code very often. It’s not that I dislike the language, it’s just that I dislike working with build systems. All build systems are terrible and, much worse, poorly documented. I can never figure out how to accomplish the simplest of tasks with any of them. CMake happens to be the least bad of all build systems I’ve had the profound displeasure of having used, and this series of tutorials is the best I’ve encountered on the use of CMake.

All About Iteration

Bob Nystrom’s two-part blog post about iteration in programming languages includes perhaps the clearest explanation of coroutines I have read so far. It begins with an exploration of how iteration is implemented in mainstream programming languages, and goes on to talk about internal and external iterators, the yield statement in C# and Python, the callstack, coroutines in Ruby (or fibers, as Ruby likes to call them) and why iteration is another way of thinking about concurrency.

Read Iteration Inside and Out and Iteration Inside and Out, Part 2.

Tastypie and Timezones

If you use Tastypie with Django’s timezone support turned on (i.e, you have USE_TZ = True in your settings.py), you will notice that Tastypie helpfully converts all dates and times in your resources to the timezone specified in your TIME_ZONE setting before returning them. If you care about internationalization, this is not the behavior you want. Tastypie encodes dates and times in the ISO8601 format by default. These dates and times have no timezone information attached to them, which means that the consumers of your API will have no idea how to correctly display them or convert them to other timezones.

This is what ISO8601 datetimes look like:

{
 "end_time": "2013–04–01T06:32:06",
 "start_time": "2013–04–01T00:30:00"
}

Both those datetimes are in the Asia/Kolkata (UTC+5:30) timezone. How can I tell? I can’t. Unless I look in my settings.py. Not cool.

There are two solutions to this problem. First, you could add this line to your settings.py:

TASTYPIE_DATETIME_FORMATTING = ‘rfc-2822’

This will cause Tastypie to format dates and times using the format specified in RFC2822. Your dates and times will now include timezone information:

{
 "end_time": "Mon, 1 Apr 2013 12:02:06 +0530",
 "start_time": "Mon, 1 Apr 2013 06:00:00 +0530"
}

The second solution, which is the solution I prefer, is simpler: use UTC everywhere on the server and let your API consumers deal with timezone conversions. Set your TIME_ZONE to ‘UTC’ and sleep easy.

If your API consumer is a web application, I highly recommend using Moment.js for all date and time operations.

WordPress: Under Siege

As I mentioned in my last post, I recently switched my website from my homegrown Django blogging app to WordPress. Before installing WordPress on my VPS, I installed it on a VM so I could test the waters before jumping in. I created an Ubuntu 12.04 VM using VirtualBox and gave it a gigabyte of RAM to work with. After I had WordPress up and running, I created some test posts and played around with various plugins and themes that I could find on the WordPress directory. I was dismayed to discover that WordPress has terrible performance out of the box, even if you disable all installed plugins. The WordPress dashboard served by my Ubuntu VM would easily take 4–5 seconds to load, and individual posts would take at least 2–3 seconds to load. I found this unacceptable, so I started searching StackOverflow and the excellent WordPress StackExchange for answers.

The two most straightforward performance optimizations that I could find were:

  1. Install a PHP opcode cache.
  2. Install a page caching plugin.

Installing an opcode cache on Ubuntu is easy:

sudo apt-get install php-apc

No extra configuration is required on Ubuntu. If you use a different distro, read the php-apc documentation on the PHP website.

Installing WP Super Cache is similarly easy and a number of excellent tutorials for setting it up are scattered around the Web. Here is a good one for Apache, and here is one for nginx. I also recommend perusing this GitHub repository that contains a complete set of configuration files for serving WordPress through nginx.

The Numbers

The numbers that follow are for a fresh install of WordPress 3.5.1 running on an Ubuntu 12.04 VM with 1GB of RAM, served by nginx 1.1.19, php-fpm 5.3.10, and backed by MySQL 5.5.29. The host OS is Mac OS X 10.8.2 running on a MacBook Pro. All testing done with Siege 2.74 hitting different pages of the WordPress website in a random order.

siege -d5 -c100 -i -f url_list.txt -t5m

Note that these numbers only reflect a general trend in WordPress performance under load. Real world page load performance depends on many factors, including network latency, page size, whether you’re using a CDN or not, the number of separate JavaScript/CSS/image files per page, etc. The following numbers only indicate how quickly WordPress can push HTML to the client.

Despite the flawed testing methodology, these numbers are useful as rough indicators of the effectiveness of opcode and page caching.

Fresh Install Without Opcode Cache or Page Cache

Transactions:               2710 hits
Availability:               100.00 %
Elapsed time:               299.47 secs
Data transferred:           9.59 MB
Response time:              8.37 secs
Transaction rate:           9.05 trans/sec
Throughput:                 0.03 MB/sec
Concurrency:                75.74
Successful transactions:    2710
Failed transactions:        0
Longest transaction:        9.58
Shortest transaction:       0.20

Fresh Install With WP Super Cache and php-apc

Transactions:              11833 hits
Availability:              100.00 %
Elapsed time:              299.70 secs
Data transferred:          23.62 MB
Response time:             0.02 secs
Transaction rate:          39.48 trans/sec
Throughput:                0.08 MB/sec
Concurrency:               0.75
Successful transactions:   11881
Failed transactions:       0
Longest transaction:       0.42
Shortest transaction:      0.00

Bonus: Numbers for ankursethi.in (this website)

This website uses the same software as my testing VM. The only difference is that it is hosted in somewhere in Germany on a Hetzner VQ12 VPS, and I’m hitting it with Siege from New Delhi in India.

Transactions:              8566 hits
Availability:              98.73 %
Elapsed time:              299.54 secs
Data transferred:          40.03 MB
Response time:             0.55 secs
Transaction rate:          28.60 trans/sec
Throughput:                0.13 MB/sec
Concurrency:               15.72
Successful transactions:   8577
Failed transactions:       110
Longest transaction:       5.39
Shortest transaction:      0.38

Closing Words

My test blog went from 39 transactions per second to 9 transactions per second with these two simple performance optimizations, and page load time went from ~8 seconds to 0.02 seconds. This page load time is for users who have not logged in or left a comment. I see a more modest 1.5–2 second load time for logged in users, which is still a 4x improvement. The concurrency number went from 75.74 to 0.75, which is a good thing in this case.

These optimizations should be enough for a majority of low to medium traffic self-hosted WordPress blogs. For more advanced optimization techniques, I recommend reading this excellent article on the New Relic blog.

Okay WordPress, You Win This Round

One of my biggest blogging crimes so far has been this: every time I get an itch to write a blog post, I start thinking of possible workflows I could use to make my writing process simpler. A few hours later, instead of the post I wanted, I have UI mockups for The Perfect Blogging App™ that will never be built. It’s a disease, I tell ya.

In the summer of 2012, though, I did finally get around to building a blogging app. I called it Can ‘O Beans, and it was nothing like my mockups. I had to write my posts using a text editor and then paste them into my app’s autogenerated admin interface — the one you get out of the box with Django. I neither added Markdown support to the app, nor a WYSIWYG editor; instead, I marked up all my posts using plain ol’ HTML, which made for a frustrating writing experience. The app didn’t even support uploading images to the server. I had envisioned a slick, AJAX-y media manager for Can O’ beans but, since it would have taken some time to build, I kept putting off hacking on it. Real life commitments kept me from improving the usability of Can ‘O Beans, and the bad usability of Can ‘O Beans prevented me from ever thinking beyond the app itself and concentrating on what mattered: writing.

Hacking on Can ‘O Beans was a lot of fun, but it was only fun for the part of my brain that enjoyed engineering puzzles. The part that wanted to just fucking write was frustrated with the whole deal.

The astute reader may now ask why I had to go and write my own blogging app when I could just have used WordPress like every other sane person. An year ago, I would have told said astute reader that WordPress was a terrible piece of software. I would have gone on to mention that it was slow and unresponsive, that it had a cluttered UI that was anathema to the creative mind, that it was insecure, that it was impossible for a sane person to customize WordPress because it was written in PHP, etc. etc.

Of course, the real reason I didn’t use WordPress was that I was a complete ass.

(The astute reader may also ask why I didn’t use one of the many static blog generators that are all the rage these days. The reason is that I prefer having a dashboard I can log into from any Internet connected computer I have access to and manage my blog from there. Also: plugins and themes.)

When faced with a problem, it’s tempting for a hacker to immediately switch to her text editor and start building something completely new. Down this path lies madness and despair, for what thou codeth, thou maintaineth, and I’ve learned this lesson well after Can ‘O Beans. More often than not, mature, well-tested, actively maintained software exists that satisfies ~99% of your needs. There are people out there who have spent years building, deploying, securing and scaling software that, with a tiny bit of customization, does everything you want it to. This was something I always knew, but I had to actually experience it for myself before I internalized it. And internalize it I did — ankursethi.in is now (proudly?) powered by WordPress. I can stop worrying about having to maintain Can ‘O Beans, and concentrate on blogging. Phew.

I still have some minor issues with the WordPress admin UI, and I still don’t like PHP and MySQL, but I’m willing to let all that slide because what WordPress lets me do is fucking write. With php-apc and WP Super Cache enabled, it performs shockingly well even on low-end servers. On my slightly-better-than-low-end Hetzner VPS, it flies.

Time to roll up my sleeves and write!

2012: Year in Review

The Good

  • Finished my four years of college. The nighmare ends at last.
  • Rediscovered my love for hip-hop music, all thanks to /r/HipHopHeads. More on this in another post.
  • Technology for the sake of technology is no fun. In the past, I wasted a lot of my time and energy on mildly interesting tools and programming languages when I could’ve been building useful software using more practical technology. 2012 was the year practicality finally beat purity.
  • Started writing software for myself. I intend to eventually polish up and release this software for public consumption.
  • Started maintaining proper information hygiene. More on this in another post.
  • Became more organized. More on this in another post.

The Bad

  • Have to take a few more exams in May before I get my degree.
  • Stopped exercising. Shameful.
  • Only read five books in the entire year. Doubly shameful.
  • Almost everyone I know is now in Bangalore while I’m stuck in Delhi.

The Ugly

  • Lost a friend to cancer.
  • Started a business, but shuttered it after a few months of work.

Highlights

  • Best movie watched: Forrest Gump
  • Best book read: Skinny Legs and All by Tom Robbins
  • Best musicians discovered: Eyedea, MF DOOM
  • Favorite albums of the year: First Born by Eyedea & Abilities, The Many Faces of Oliver Hart by Eyedea, Theatre is Evil by Amanda Palmer and the Grand Theft Orchestra
  • Favorite new programming language: Go
  • Favorite new software: Sublime Text 2, Clementine, LastPass

What Next?

  • Release one or two useful webapps into the wild.
  • Learn Go and build a webapp with it.
  • Further streamline my web development and deployment workflow.
  • Learn my technology stack better. This means learning more about the capabilities of nginx, PostgreSQL, uWSGI and of course Django and Flask.
  • Start keeping track of how I spend my time. If you can measure it, you can optimize it.
  • Start keeping track of the movies I watch, the books I read and the music I listen to.
  • Read more. Twenty-five books is an achievable goal for 2013.
  • Read less SciFi and genre fiction.
  • Exercise. I have been intending to start with the Convict Conditioning bodyweight training program for the last three months. The new year is as good an excuse as any to start having some fun!
  • Explore New Delhi more and get involved in local community events.
  • Move to Bangalore by the end of the year.
  • Super secret goal.

This was an year of many small epiphanies, and one or two big ones ones. Those deserve little mention, though, since us silly inexperienced twentysomethings have epiphanies all the fucking time.

Anyway, happy new year to everyone reading this. Make it one worth remembering!

Mobile Tweaks and Chrome Extension

I just made some changes to my website’s CSS to make it more readable on small screens. I’m not completely happy with how it looks — the header looks jarringly out of place and code samples are all messed up — but at least now you don’t have to play with your browser’s zoom settings to be able to read the text properly. Baby steps.

I also wrote a little Chrome extension for adding bookmarks to my homegrown bookmarks manager. I was pleasantly surprised at how easy it is to extend Chrome. The APIs are well-designed and well-documented, and a number of examples are available from Google’s developer website. I can see myself writing more extensions for Chrome in the future.

My bookmarks extension is nothing to write home about. It consists of the mandatory manifest.json file, four or five lines of JavaScript that open a new tab when a toolbar button is clicked, and a terrible icon I quickly designed in Photoshop. The code is on GitHub so that my friends and family can laugh at my terrible Photoshop skills.