We use Campfire chat here as it means we can work asynchronously. I can drop in and ask a question or share a link, and James can pop in later and read all the updates when he’s ready. No meetings. No one-line emails filling up our inboxes.
Hubot
We also use Hubot. Hubot is a chatbot, originally developed by Github, that joins you in your chatroom and can carry out certain vitally important tasks, by listening for commands.
The brilliant thing about using Hubot to carry out actions for you (rather than, for example, doing them yourself in the terminal) is that these commands get added to the chat history of the room, like any other discussion. This means that when someone makes a change that they want the team to know about (e.g. when they deploy code), they can carry out the task via Hubot and everyone will see it (and the result), instead of them having to send a separate communication. And because Campfire has mobile apps, anything you can do at your computer, you can do on the go. Nice.
Tasks!
Once we started using Hubot, one of the first things we wanted was a way for Hubot to store and manage tasks for us. So we wrote a script to do it.
Now, instead of James saying:
[James] We need some business cards
He can write:
[James] hubot add task Get some business cards made
And Hubot will store the task.
Later, I will enter the room, read up on the latest developments. I will see the task has been added, and maybe ask to see a list of all the tasks:
[Basil] hubot list tasks
Hubot will respond:
[Hubot] #1: Get some business cards made
#2: Order an Arduino
After I’ve done a task I can delete it:
[Basil] hubot delete #1
[Hubot] Task deleted: Get some business cards made
That’s it. It’s very simple, and is obviously not suitable for large project task lists, but for the odd tasks that used to come up in the room and which were then (maybe) transcribed into a separate Google Doc that we would never check, we now have this script operating in the same place that we usually discuss work.
If you use Campfire and Hubot, feel free to grab the code and use it. We’re trying to keep it very simple, but if there’s an improvement you’d like to make, by all means fork it and send us a pull request.
Over the past few years there has been a surge in the number of client-side JavaScript frameworks. Currently, Backbone gets a lot of the attention, and rightly so, it's a great framework. In this post though, I want to demonstrate a use case where I believe SproutCore 2 excels — building interactive web apps.
Let's start by describing what I mean when I say 'interactive' web apps. I'm talking about applications where user interaction repeatedly causes lots of elements to be updated, where multiple different elements interact and change the state of each other, and where keeping track of all the necessary view updates becomes a pain.
The reason that SproutCore excels in this use case is because of the way it handles view updates. When any data changes, it is the responsibility of the framework to update the views and it does this automatically. I find that this encourages a real data driven approach to building apps — you take care of updating the data and the framework takes care of updating the views.
SproutCore achieves this view magic by utilising the concept of bindings.
Bindings
Bindings are a way of keeping data synchronised. Simply put, when two properties are bound together, they are connected; a change to either one of the properties will automatically be reflected in the other. While this method of data synchronisation is not present in JavaScript by default, SproutCore introduces it with its object model.
SproutCore introduces a new base object SC.Object which includes a number of new features such as bindings. The example below shows two SC.Objects that have a bound property.
varApp=SC.Application.create()App.mr=SC.Object.create({name:'Mr X',maritalStatus:'Married'})App.mrs=SC.Object.create({name:'Mrs X',// This is how bindings are created in SproutCore,// pass the property name suffixed with 'Binding'// and a string that references the property you // are binding tomaritalStatusBinding:'App.mr.maritalStatus'})App.mrs.get('maritalStatus')// => Married// The property has been synced App.mr.set('maritalStatus','Single')// Set Mr to singleApp.mrs.get('maritalStatus')// => Single// The property has been synced again
The example shows how you can bind properties together and in effect build relationships between objects. Building relationships using bindings in an incredibly useful way to propagate data changes throughout your application.
SproutCore view system
The SproutCore view system is a good demonstration of the power of bindings. Each view has a binding to an underlying data object (which in turn can have bindings to other objects). The binding means that whenever the underlying data changes, the view automatically updates to reflect the change.
When you build an application using the SproutCore view system, the responsibility for triggering view updates is moved up to the framework level. I find that this encourages a data driven approach to building applications.
Data driven applications
The example below is taken from our vehicle tracking product, Sensor. It shows a summary of the movement of a vehicle for a particular day.
In this demo, there are three main sections:
A graphical representation of the speed of the vehicle throughout the day.
A textual list of the journeys and stops that the vehicle made.
A map showing each of the journeys and stops on the map.
Each of these sections is a different view of the same underlying data stored in the client side data model. The data model is essentially just a list of the journeys and stops that the vehicle has made.
Each of the three views in the demo are independent and have no knowledge of one another. However, if you mouse over the demo, you'll see that whenever a journey is highlighted in one representation, it is highlighted in the other two representations.
This state synchronisation is achieved because each of these views have bindings to the same underlying data and we use the interaction events to trigger changes in this data. Whenever the data changes, each of the views are updated.
For example, when an hovering over an item in the textual journey list, we set the hover property to true on the corresponding journey object.
Sensor.Views.JourneyListItem=SC.View.extend({mouseEnter:function(){// Get the journey object associated with the // view and set it's hover propertythis.get('journey').set('hover',true);},mouseEnter:function(){this.get('journey').set('hover',false);}//... Rest of the view code omitted})
The textual journey list does not need to know about the speed graph view or the map view. The speed graph and the map have bindings to the same underlying journey object that the textual view is manipulating. Whenever the journey object is changed, all the views update. The result is three views that appear to all interact with each other but, in fact, are each just responding to the underlying object they are bound to.
Using this technique, adding a new interacting view of the data is trivial. You can just create a new view, bind it to the same object and it will automatically interact with the other views, highlighting the correct journeys on hover.
Live updates
In Sensor all of our screens update live as the vehicles are being driven. We use websockets to stream the live updates to the browser where the underlying data is updated. As this live data is streamed in, all of the views update accordingly — the paths on the map update in real time, the speed graph updates and new journeys are added to the list.
Developing in SproutCore takes away the need to update and re-render views, and the focus shifts entirely to managing and updating the client side data model. This is why I call it a data driven approach to building applications.