The wearther blog

New release!

Wearther 1.1.0 is just released on the iTunes App Store!. Wearther now has female items, so no more excuses from the ladies for not using wearther ;)

This release also includes some UI improvement and bugfixes. Below is the more detailed release notes:

  • Female Items

Wearther optimizer also considered that female has less metabolic rate than male[1] in general. Therefore the clothing combinations will tend to be a little bit warmer compared to male's

  • Optimizer is tweaked to give better clothing combinations
  • Switched min and max temperature position
  • Fixed default unit not correctly loading for first time users
  • Improved loading screen and error screen
  • No more install screen for wearther webapp if the page is visited using Safari on an iPhone. Thanks to the new minimal-ui tag

We are also considering of opening our own wearther API (Application Programming Interface) for third party developers. If you are a developer, or know any developer that would be interested in using wearther service to develop custom product, click here to sign up. We'll let you know when the API is available as soon as possible

Node.js + Backbone = wearther

I would like to share how wearther code is achitected. Hopefully this post will be useful for your own projects.

Wearther is built on top of Backbone for the front-end and Node.js as its backend. The backend stuff is pretty simple, just a small webserver that handles different routes, requests external API calls and the optimizer to calculate clothing combinations. I want to focus on the front-end side of things instead.

First off, I decided to separate each component to a separate module and store it in their own separate directories. So we left with the following directory structure:

modules/
  |-combinations/
  | |-collections/
  | | |-combinations.js
  | |-models/
  | | |-combination.js
  | |-views/
  | | |-combination.js
  | | |-combinations.js
  | |-Combinations.js
  |-listings/
  | |-...
  | |-Listings.js
  |-location/
  | |-...
  | |-Location.js
  |-router/
  | |-Router.js
  |-settings/
  | |-Settings.js
  |-temperature/
  | |-...
  | |-Temperature.js
Util.js
WeartherApp.js

WeartherApp.js is the main file where it listens to events and deal with them accordingly. It's also the point of entry for the entire app.

Originally each module can communicate to each other directly but I soon realized that it's not going to be pretty once I start to add more modules in the future. Eventually it will be a very tightly coupled app. So I decided to look for alternative pattern and soon discovered Mediator[1][2] pattern.

A quick note: mediator pattern allows the app to be loosely coupled by not a letting modules to communicate to each other directly. This is achieved by passing the mediator object around. Something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var mediator = {
  subscribe: function(channel, fn) {
    // store the function into the channel
  },
  publish: function(channel) {
    // notify the channel
  }
};

function Module1(mediator) {
  function doSomething() {
    // do stuff

    // let mediator knows we're finished
    mediator.publish('module1:done');
  }
}

function Module2(mediator) {
  mediator.subscribe('module1:done', function() {
    // module 1 is done, do something here
  });
}

I like mediator pattern approach but I'm still not entirely satisfied. I don't like the idea of passing the mediator object around (in this case WeartherApp) to each module. I don't like the extra parameter in my function constructors so I came up with mediator-like convention: a slightly modified Event Aggregator pattern (note that I mentioned convention, because it is very easy to mess things up if I'm not following my own convention).

The idea is very simple. Each module can broadcast and listen to message, but they are not allowed to directly communicate with other module. Every communication is handled by the main object (WeartherApp). To achieve this, all modules inherited Backbone.Event class so it can call trigger method.

WeartherApp then load all the modules and listens to the broadcast messages and react accordingly

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
*Location.js*
function getLocation() {
  // obtain location
  var location = readGeolocation();
  this.trigger('location:locationUpdated', location);
}

*Temperature.js*
function getTemperature(location) {
  // do ajax call to server
  var temp = $.ajax(...)
  this.trigger('temperature:temperature', temp);
}

*Combination.js*
function calculateCombinations(temp) {
  var combinations = $.ajax(...)
  this.trigger('combination:combination', combinations);
}

*WeartherApp.js*
locations.on('location:locationUpdated', function(newlocation) {
  temperature.getTemperature(newlocation);
});

temperature.on('temperature:temperature', function(newtemp) {
  combinations.calculateCombinations(newtemp);
});

// start the app
location.getLocation();

What I like about this convention is that I don't have to pass around the main object (mediator), instead each module simply broadcast its own message without any dependency to the main object. The obvious downside is that it is possible for each module to talk with each other. That's why by using the convention, the module should not listen to any message at all. It can only broadast and it's up to the main object to handle them.

Another reason why I like this is that the inner module implementation can be as convoluted as you wish without affecting other module. For example in Combination module, the implementation (models, collections, views) can interact with each other (model can notify collection and vice-versa) while the main module container is the one wrapping them all up and broadcast message to the main object whenever required.

I hope you find this post useful. Let me know what you think :)

- Ronald

Why mobile web application sucks

Originally I started wearther as a mobile web application - webapp out of the curiousity of the web technology. I was just started learning JavaScript and was so inspired by Forecast.io (try visiting Forecast.io using an iPhone). To average users, they wouldn't even notice that Forecast.io is not a native app!

As soon as I started working on wearther mobile web application, I noticed some serious problems and limitations (note that problems 1-4 are iOS specific problems):

  1. Bookmarklet freezes! This one is a huge issue for me, when opening bookmarklet on iOS, there are times where it just froze and simply won't respond to anything. Turning screen off doesn't work, the same goes with pressing home button (although Siri is still active) [1] [2] [3]. I started noticing this on iOS 6 and was hoping that this will be fixed on iOS 7. Unfortunately that's not the case. In fact, iOS 7 introduces severe bookmarklet problems [4] [5]!

  2. No multitasking. This irks me and Enrico the most. Often when checking the weather we got distracted by new email or tweets, so we simply switch app. Upon switching back to wearther, we have to start all over again from the beginning (obtaining location/temperature/combinations).

  3. Updating the webapp is a pain. Sometimes you have to delete the old shortcut and re-add it again (if you made a significant change on the <head> tag)

  4. Location permission expires. I haven't fully confirm this but after some time wearther will lose permission to use geolocation. The only solution was to recreate the bookmarklet. This is a big no-no.

  5. Compatibility issues. It's getting better everyday but one big issue I faced was running wearther on Samsung Galaxy S3 was border-radius style was not respected. Best part is, it's Samsung Galaxy S3-specific bug.

I admit I was very slow to decide to move on to native iOS, but it's better late than never. Switching to native iOS opens up a huge possibilities for the upcoming features. I'm really excited and looking forward to it!

- Ronald