&yet Blog

● posted by Peter Saint-Andre

Way back in 2008, my friend Jack Moffitt wrote a blog post entitled XMPP Is Better With BOSH. In those ancient days of long polling, BOSH was the state of the art for sending XMPP traffic over an HTTP transport because we needed something like the Comet model for bidirectional communication over HTTP. Even at the time, we knew it was an ugly and temporary hack to send multiple HTTP request-response pairs via long polling, but we didn’t have anything better.

Since then, bidirectional communication between web browser and web service has come a long way, thanks to WebSocket. Nowadays, you start with an HTTP connection but use the HTTP UPGRADE method to bootstrap directly into a long-lived bidirectional session (for this reason, WebSocket has been likened to “TCP for the web”). WebSocket has its warts too, but compared to BOSH it significantly reduces the overhead of maintaining HTTP-based connections for XMPP. Even better, it has become a truly standard foundation for building real-time web apps, with support in all the modern languages and frameworks for web development.

The benefits of communicating XMPP over WebSocket encompass and extend the ones that Jack enumerated years ago for BOSH:

  • Greater resilience in the face of unreliable networks — here WebSocket does pretty much what BOSH and other “Comet” approaches did 10 years ago, but in a more network-friendly way by removing the need for long-polling.
  • The ability to recover from data loss — the BOSH model of recovering from network outages and communication glitches was generalized with the XMPP stream management extension, this can be used with XMPP over WebSocket, too.
  • Compression for free — well, it turns out that the free compression we got by sending XMPP over HTTP wasn’t so free after all (cf. the CRIME and BREACH attacks), but there’s a native compression scheme for WebSocket which so far appears to avoid the security problems that emerged with application-layer compression in HTTP.
  • Firewall friendliness — in this case WebSocket isn’t quite as network-agnostic as BOSH, since it’s known that some mobile networks especially prevent WebSocket from working well (usually because they don’t handle the HTTP UPGRADE mechanism very well). Hopefully that will improve over time, but in the meantime we can always fall back to BOSH if needed.

Thanks in large measure to the dedication of yeti Lance Stout and key contributions from Jack as well as Eric Cestari, the XMPP over WebSocket spec has just been published as RFC 7395. This technology is a big factor in our long-term efforts to help XMPP love the web, and we’re already using it extensively in the next generation of Talky, in stanza.io, and more generally in the Otalk platform we’re building as a more open foundation for realtime communications.

● posted by Henrik Joreteg

There’s a bit of a kerfuffle right now in Angular.js land because, lo and behold, the 2.0 release contains drastic differences and there isn’t really an upgrade path.

If you want to upgrade you’ll likely need to completely re-write your app!

The structural updates they’re proposing all sound like good improvements, but if you built a large app on 1.x and want to upgrade it doesn’t really seem like you’ll be able to use much of your code.

Losing your religion

Ok, so what should you do? Pick another framework?

As developers we seem to have a tendency to get really religious about frameworks. We invest a bunch of time learning a tool and then hold onto it tightly.

But, it doesn’t really buy us anything to be religious about tools. Simply converting to another big framework doesn’t protect us from a similar situation in the future, does it?

Why don’t we anticipate that things will change from the start?

Change is the only constant. How can we optimize for change?

Well, how do we deal with change in other large systems?

By not building large systems, but instead composing many small, independent things into a large system.

As it turns out, we’ve gotten to the point where clientside JavaScript apps are large systems!

Refactoring, rewriting, and rebuilding from scratch is expensive. Buying into a single framework is risky. On the other hand, not leveraging anybody else’s efforts and solved problems is wasteful and painful. So what do we do?

The biggest takeaway I’ve had from building stuff with Node for the last four years is to build your code as small, focused, re-usable modules.

This type of architecture lets us change a leaky faucet without having to burn the whole building down.

We can apply these same approaches in our clientside apps. This means we can mix and match and install solutions to the specific problems that we’re facing.

We’re doing that with Ampersand.js. But I’ll let you in on a little secret:

Ampersand isn’t actually a thing–it’s a bunch of little things.

The only reason we gave it a shared name is so we can talk about is as a thing. But it’s really a loose collection of a bunch of optional modules. In fact, we call it “Ampersand.js”. But good luck finding a file to use by that name, it doesn’t exist!

If you want something to model and fetch data from your API, but then use React for your views, go for it. Just use ampersand-rest-collection and ampersand-model

Need something smart to manage state while tracking touch events in your multi-touch library? Use ampersand-state by itself.

Just need something to manage clientside routing? Use the router.

And we don’t just mix it with our own modules, we grab all sorts of other useful stuff from npm. We keep a small collection of a our favorites on the tools site, but that’s just like a bookmark directory. There are a whole slew of tools available for clientside apps on npm.

Tools like Angular and Ember require that you go “all in”.

As a leader on a dev team, I personally consider it too risky to invest our team’s energy in learning the intricacies of a particular framework; I want our team to learn how to solve problems in JavaScript by combining the right tools for the job.
At the end of day, tools are just tools. Find and use what works best for you and your team. I just urge you to consider architectures that mitigate risk of marriage to a particular framework.

No two apps are the same, so we optimize for change. It’s the only constant.

References and further reading

We’d love to help

If you’re looking for help moving from an “all in” toolkit like Angular to a completely composable approach, optimized for change, let’s talk. &yet provides advanced JS training and consulting to teams all over the world.

See our client Glenn Scott’s recent Node Road talk as a good example of how we work to make JavaScript apps maintainable and fun to work on, while capable of evolving over the long run.


P.S. I’d love to hear your feedback on twitter @HenrikJoreteg

edited 10/29/2014 23:45pm: The first version of this post was excessively critical of Angular. Angular is incredibly popular and growing like crazy. It’s a brilliant, powerful framework that makes it easy to get started and really empowers developers. I disagree with some of the technical choices that have been made in the project, but that doesn’t negate the fact is there are some really awesome people working on Angular. I respect them and their work very much. The engineering chops and dedication required to build a framework like Angular is inspiring. I was given frank feedback about the harshness of the original version of this post and I’d like to genuinely apologize to the Angular team.

● posted by Julie Horvath

Our general approach to consulting at &yet goes something like this: If we have a knack for something and we think it can help make you better at what you do, help your team eliminate risk, or move more confidently down the right path, we should do it. Starting today, we’re offering 3 new WebRTC consulting packages.

In addition to building products and open source software, our team has offered consulting services as long as we’ve been a company. But now we’ve started focusing in on how to better package the skills and expertise our community (that’s you!) needs.

After reaching out to and talking with teams actively working with WebRTC, we’re hearing a lot of the same questions that need answering. Questions like:

  • What open source tools are out there and where should we go to get started with them?
  • How do we configure TURN/STUN servers so our WebRTC service can work consistently across firewalls?
  • What is the best way to go about implementing WebRTC on iOS?
  • How can we ensure we’re providing a secure and private service? (Including HIPAA-compliance)
  • Is it possible to build and scale a WebRTC service on our own infrastructure?
  • How can we scale beyond a couple people in a group conversation?
  • How could we add chat or whiteboarding alongside our video solution?
  • How would we create a massive broadcast live video service?

Whether you’re looking for advice from WebRTC experts who have been there, done that OR you want to team up with a well-rounded, resourceful consultancy to help drive a new chat or video feature or product forward, you’ll find what you need with our team.

Here’s our new WebRTC consulting packages, available starting today:

  • The Starter Discussion: We’ll tackle the tip of iceberg with you. Our WebRTC experts will provide high-level feedback and recommendations to your team. Read more about the Starter Discussion here.

  • The Perfect Fit: If you’re running up against a WebRTC wall, having likely met the same wall in our collective pasts, we can help your team navigate its way to safety and success. We’ll deliver and document plans and recommendations for your team with the option of custom feature development and design. Read more about the Perfect Fit here.

  • The Monthly Retainer: A high-touch approach to keeping &yet on-board. We’ll lead weekly standups, deliver thorough code reviews and spec documentation and planning, and train your team on deploying and maintaining your new project. Oh! And this package includes a full week of design consulting, too. Read more about the Monthly Retainer here.

If you’re looking for a little less or a little more, we can create a package to fit your needs. Just get in touch.

● posted by Adam Brault

For the past year and a half, it’s been our pleasure and privilege to serve CAA, an agency representing many of the most successful professionals in film, television, music, sports, and theater.

Glenn Scott leads the team there. Over the past few years, they’ve transitioned their IT to building custom applications in Node. We’re proud to say we’ve been able to partner with Glenn’s great team at CAA, playing a key role in their work during that time.

Recently, Glenn gave a nice presentation as part of Joyent’s Node on the Road series. In it, he described the way CAA builds applications.

Glenn talks about the challenge of maintenance in traditional IT and how building Node and JS web apps make that much less painful.

His keys:

  1. Create a platform where it’s easy to create many small apps, where the mean time to business value is measured in days and weeks.
  2. Make it fun and glamorous to add features to shipped products.
  3. Make it easy to keep products modern, giving each layer an evolution pattern that allows parallel and independent updating of components.

Node and Ampersand‘s mutual modularity make all these good things possible.

For more, check out Glenn’s talk.

● posted by Jenna & Speegle

What is Talky?

Jenna and Speegle explain it all.

With apologies to Clarissa. #sorrynotsorry

But wait, there’s more!

Want to be the first to know when Talky 2 is ready? (And also get a bi-weekly dispatch of stuff we’re learning and doing at &yet?) Join our community! We can’t be &yet without &you.

● posted by Adam Brault

We’ve been hard at work on the next generation of Talky for months and we’re getting close.

We think Talky 2 is going to help make group meetings better and simpler.

What’s new in Talky 2?

  • HD video group conversations with 25+ people
  • text chat
  • audio-only modes
  • low-bandwidth modes
  • dramatically improved UX

…and more.

Why we care

As a distributed team, there are very few conversations we have that don’t involve a Talky session.

It’s as core to our work as any other piece of software in our belt, so we’re motivated to make it the best we possibly can.

In fact, we’re so eager to solve this problem that we’ve pointed our entire focus as a company into this area.

We’re proud of the team working on Talky 2.

Karolina Szczur and Philip Roberts are creating an all-new interface we think you’ll enjoy.

Meanwhile, Lance Stout, Philipp Hancke, and Peter Saint-Andre (in collaboration with the Jitsi team among others) are pushing forward some tried-and-true approaches and forging new Internet standards for group video conversations.

Fritzy, Hjon, and our friends at Steamclock have put a lot of effort into creating tools that will enable us to add these features over time to our native iOS app.

And Bear and Marcus Stong have created an operational foundation for rapidly building and scaling communication and collaboration applications, which we can run for you or help you run on your own hardware. (If you’re interested, we’d love to talk.)

Talky and Otalk

With Talky, we aren’t just building a product.

We’re massively investing energy into open-source technology that will empower modern communication and collaboration apps to be built with open technologies, including tools that will make it easier to build native WebRTC applications for iOS, Android, Windows, Mac, and Linux.

Otalk provides the foundation for Talky. It’s a suite of completely open and standards-based tools for making modern communication a delightful user and developer experience—and it’s all open sourced.

Creating these technologies represents a mammoth undertaking. Otalk is nothing less than the culmination of everything our team members have learned from building and scaling realtime systems since the 90s, combined with everything we’ve learned in the last five years about building realtime apps for web and mobile.

Talky 2 will be the first software we’ve released built entirely on top of Otalk.

Why are we doing this Otalk thing?

As firm proponents of the Open Web, we naturally believe in the power of Open Communication.

There are Really Big Things™ that the Open Web makes more possible than any previous human invention. Things like democracy, equality, freedom, and distribution of power.

The Web is rapidly evolving. More and more of our experience on the web rely on extremely advanced technologies—the majority of which are closed silos.

It’s nearly impossible to build a quality communication app without either a deep understanding of a huge swath of tech or by leveraging one of a small handful of private services—let alone doing it in an open and interoperable way. That’s not good enough.

Alan Kay famously said, “The best way to predict the future is to invent it.”

At &yet, we’re more than a little concerned that the trend of the web is toward consolidation of power and oligarchy.

We’re not opposed to business in general (we are one); we simply believe there’s a better future waiting to be invented and we’re not afraid to try.

Join us

Want to be the first to know when Talky 2 is ready and stay up to date on Otalk? Want to give us input and feedback to help guide features? Join our community! We can’t be &yet without &you.

● posted by Henrik Joreteg

TodoMVC is a neat project with a simple idea: to build the same application with a whole slew of different frameworks so we can compare how they solve the same problems.

The project’s maintainers asked me to contribute an example in Ampersand.js, so that’s what we did.

There are a few aspects of the implementation that I thought were worth writing up.

First, some highlights

  1. filesize: Total filesize of all the JS assets required for the app only 24kb(minified/gzipped) which, for comparison, is smaller than jQuery by itself. By comparison the Ember.js version is 165kb and that’s without including compiled templates.

  2. super efficient DOM updating: Nothing is re-rendered to the DOM just because the underlying model changed. Only state changes that result in a different outcome touch the DOM at all, and when we do need to update the DOM because of a state change, it’s done using specific DOM methods such as .setAttribute, .innerText, .classList.add, etc. and generally not with .innerHTML. This matters because innerHTML is slower, because it requires the browser to parse HTML. The point is that after the initial render, it does the absolute minimum number of DOM updates required, and does them as efficiently as possible.

  3. good code hygiene: Maintainable, readable code. All state stored in models, zero state stored in the DOM. Fully valid HTML (I’m looking at you, Angular). Call me old school, but behavior is in JS, styles is in CSS, and structure is in HTML.

  4. fully template language agnostic: We’re using jade here, but it really doesn’t matter because the bindings are all handled outside of the templating, as we’ll see later. You could easily use the template language of your choice, or even plain HTML strings.

Ok, now let’s get into some more of the details.

Persisting todos to localStorage

The TodoMVC project’s app spec specifies:

Your app should dynamically persist the todos to localStorage. If the framework has capabilities for persisting data (i.e. Backbone.sync), use that, otherwise use vanilla localStorage. If possible, use the keys id, title, completed for each item. Make sure to use this format for the localStorage name: todos-[framework]. Editing mode should not be persisted.

This is ridiculously easy in Ampersand. This could be done this as a mixin, so we could use the “backbone-esque” .save() methods on the models. But given how straightforward this use case is, it’s simpler to just do it directly. We simply create two methods.

One to write the data to localStorage:

writeToLocalStorage: function () {
  localStorage[STORAGE_KEY] = JSON.stringify(this);
}

One to retrieve it:

readFromLocalStorage: function () {
  var existingData = localStorage[STORAGE_KEY];
  if (existingData) {
    this.set(JSON.parse(existingData));
  }
}

You’ll notice we’re just passing this to JSON.stringify. This works because ampersand collection has a toJSON() method and the spec for the browser’s built-in JSON interface states that it will look for and call a toJSON method on the object passed in, if present. So rather than doing JSON.stringify(this.toJSON()), we can just do JSON.stringify(this). Ampersand collection’s toJSON is simply an alias to serialize which loops through the models it contains and calls each of their serialize methods and returns them all as a serializable array.

So far we’ve just created the methods and not actually used them, so how do we wire that up?

Well, given how simple the app requirements are in this case: “save everything when stuff changes,” we can just have the collection watch itself and persist when it changes. Then our models don’t even have to know or care how they get persisted, the collection will watch itself, and whenever we add/remove or change something it’ll re-save itself. This keeps our logic nicely encapsulated into the collection whose responsibility it is to deal with models. Makes sense, right?

Turns out, that’s quite easy too. Inside our collection’s initialize method, we’ll do as follows. See line comments below:

initialize: function () {
  // Attempt to read from localStorage right away
  // this also adds them to the collection
  this.readFromLocalStorage();

  // We put a slight debounce on this since it could possibly
  // be called in rapid succession. We're using a small npm package
  // called 'debounce' for this: 
  // https://www.npmjs.org/package/debounce
  this.writeToLocalStorage = debounce(this.writeToLocalStorage, 100);

  // We listen for changes to the collection
  // and persist on change
  this.on('all', this.writeToLocalStorage, this);
}

Syncing between multiple open tabs

Even though it’s not specified in the spec, we went ahead and handled the case where you’ve got the app open in multiple tabs in the same browser. In most of the other implementations, this case isn’t covered, but it feels like it should be. Turns out, this is quite simple as well.

We simply add the following line to our initialize method in our collection, which listens for storage events from the window:

window.addEventListener('storage', this.handleStorageEvent.bind(this));

The corresponding handler inside our collection looks like this:

handleStorageEvent: function (event) {
  if (event.key === STORAGE_KEY) {
    this.readFromLocalStorage();
  }
}

The event argument passed to our storage event handler will includes a key property which we can use to determine which localStorage value changed. These storage events don’t fire in the tab that caused them, and they only fire in other tabs if the data is actually different. This seems perfect for our case. So we simply check to see if the change was to the key we’re storing to, run readFromLocalStorage, and we’re good.

That’s it! Here’s the final collection code.

note: It’s worth noting that the app spec for TodoMVC is a bit contrived (understandably). If you’re going to use localStorage in a real app you should beware that it is shared by all open tabs of your app, as well as the fact that your data schema may change in a future version. To address these issues, consider namespacing your localStorage keys with a version number to avoid conflicts. While all these problems can be solved, in most production cases you probably shouldn’t treat localStorage as anything other than an somewhat untrustworthy cache. If it uses it to store something important and the user clears their browser data, it’s all gone. Also, you can’t always trust that you’ll get valid JSON back, so a try/catch would probably be wise as well.

Session properties for editing state

If you paid close attention, you noticed the TodoMVC application spec also says we shouldn’t persist the editing state of a todo. This refers to the fact that you can double-click a task to put it into edit mode.

One thing that’s a bit unique in Ampersand is its use of what we call “session properties” to store things like the editing state.

If you look at the other examples, both Ember and Backbone only reference the “editing” state in the view code or the view controller; there’s no reference to it in the models. Compare that to our todo model:

var State = require('ampersand-state');


module.exports = State.extend({
  // These properties get persisted to localStorage
  // because they'll be included when serializing
  props: {
    title: {
      type: 'string',
      default: ''
    },
    completed: {
      type: 'boolean',
      default: false
    }
  },

  // session properties are *identical* to `props`
  // *except* that they're not included when serializing.
  session: {
    // here we declare that editing state, just like
    // the properties above.
    editing: {
      type: 'boolean',
      default: false
    }
  },

  // This is just a convenience method that just
  // gives our view a simple method to call when 
  // it wants to trash a todo.
  destroy: function () {
    if (this.collection) {
      this.collection.remove(this);
    }
  }
});

You might be thinking, WHAT!? You’re storing view state in the models?!

Yes. Well… sort of.

If you think about it, is it really view state? I’d argue it’s “application state,” or really “session state” that’s very clearly tied to that particular model instance.

Conceptually, at least to me, it’s clear that it’s actually a state of the model. The view is not in “editing” mode; the model is.

How the view or the rest of the app deals with that information is irrelevant. The fact is, when a user edits a todo, they have put that particular todo into an editing state. That has nothing to do with a particular view of that model.

This distinction becomes even more apparent if your app needs to do something else based on that state information, such as disabling application-wide keyboard shortcuts, or applying a class to the todo-list container element when it’s in edit mode.

Even if you disagree with that, what about readability? Let’s say you’re working with a team on this app, where can they go to see all the state we’re storing related to a single todo?

In the Backbone.js example the model code reads like this:

app.Todo = Backbone.Model.extend({
  // Default attributes for the todo
  // and ensure that each todo created has `title` and `completed` keys.
  defaults: {
    title: ',
    completed: false
  },

  // Toggle the `completed` state of this todo item.
  toggle: function () {
    this.save({
      completed: !this.get('completed')
    });
  }
});

and in Ember:

Todos.Todo = DS.Model.extend({
  title: DS.attr('string'),
  isCompleted: DS.attr('boolean')
});

Neither of these give any indication that we also care about whether a model is in editing mode or not. We’d have to dig into the view to see that. In an app this simple, it’s not a big deal. In a big app this kind of thing gets problematic very quickly.

It feels so much clearer to see all the types of state related to that model in a single place.

Using a subcollection to get filtered views of the todos

The spec says we should have 3 different view modes for our todos:

  1. All todos
  2. Remaining todos
  3. Completed todos

There are a few different ways we could go about this. We’ve got our trusty ampersand-collection-view which will take a collection and render a view for each item in the collection. It also takes care of adding and removing items if the collection changes, as well as cleaning up event handlers if the parent view is destroyed.

That collection view is included in ampersand-view and is exposed as a simple method: renderCollection.

One way to accomplish what’s being asked in the spec would be to create three different collections and shuffle todos around between collections based on their completed state. But that feels a bit weird. Because we really only have one item type. We could also have a single base collection and request a new filtered list of todos from that collection each time any of them changes, which is how the Backbone.js implementation does it. But that would mean that it’s no longer just a rendered collection. Instead we’d have to re-render a view for each todo in the matching set, which doesn’t feel very clean or efficient.

It seems cleaner/easier to just have a single todos collection and then render a “filtered view,” if you will. Ideally, we’d just be able to set a mode of that filtered view and have it add/remove as necessary.

So we want something that behaves like a normal collection, but which is really just a subset of that collection.

Then we could still just call renderCollection once, using that subcollection.

Then if we change the filtering rules of the subcollection things would Just Work™. In ampersand we’ve got just such a thing in ampersand-subcollection.

If you give it collection to use as a base and a set of rules like filters, a max length, or its own sorting order, then it pretends to be a “real” collection. It has a models array of its current models, a length property, its own comparator, and it will fire events like add/remove/change/sort as the underlying data in the base collection changes, but it will fire those events based on its own defined filters and rules.

So, let’s use that. In this case we just need a single subcollection, so we’ll just create it and attach it to the collection as part of its initialize method:

var Collection = require('ampersand-collection');
var SubCollection = require('ampersand-subcollection');
var Todo = require('./todo');


module.exports = Collection.extend({
  model: Todo,
  initialize: function () {
    ...
    // This is what we'll actually render
    // it's a subcollection of the whole todo collection
    // that we'll add/remove filters to accordingly.
    this.subset = new SubCollection(this);
    ...
  },
  ...
}

Now, rather than just rendering our collection, in our main view we’ll render the subcollection instead:

this.renderCollection(app.me.todos.subset, TodoView, this.queryByHook('todo-container'));

We’ll talk about model structure in just a minute, but for now let’s just realize that app.model.todos is our todos collection and app.model.todos.subset was the subcollection we just created above.

The TodoView is the constructor (a.k.a. view class) for the view we want to use to render the items in the collection and this.queryByHook('todo-container') will return the DOM element we want to render these into. If you’re curious about queryByHook, see this explanation of why we use data-hook.

So, now we can just re-configure that subcollection and it will fire add/remove events for changes based on those filters and our collection renderer will update accordingly.

There are three valid states for the view mode we’re in. It can be "active", "completed", or "all". So now we create a simple helper method on the collection that configures it based on the mode:

setMode: function (mode) {
  if (mode === 'all') {
    this.subset.clearFilters();
  } else {
    this.subset.configure({
      where: {
        completed: mode === 'completed'
      }
    }, true);
  }
}

So where does that mode come from? Let’s look at our model structure.

Modeling state

In Ampersand a common pattern is to create a me model to represent state for the user of the app. If the user is logged in and has a username or other attributes, we’d store them as props on the me model. In this app, there’s no persisted me properties, but we do still have a user of the app we want to model and that user has a set of todos that belong to them. So we’ll create that as a collection property on the me object like so:

var State = require('ampersand-state');
var Todos = require('./todos');


module.exports = State.extend({
  ...
  collections: {
    todos: Todos
  },
  ...  
});

Things that otherwise represent “session state” or other cached data related to the user can be attached to the me model as session properties as we described above.

Something like the mode we described above fits into that category.

Ideally, we should be able to simply change the mode on the me model and everything else should just happen.

And, since we’re using ampersand-state, we can change the entire mode of the app with a simple assignment, as follows:

app.me.mode = 'all';

Go ahead and open a console on the app page and try setting it to various things. Note that it will only let you set it to a valid value. If you try doing: app.me.mode = 'garbage' you’ll get this error:

type error

This type of defensive programming is hugely helpful for catching errors in other parts of your app.

This works because we’ve defined mode as a session property on our me model like this:

mode: {
  type: 'string',
  values: [
    'all',
    'completed',
    'active'
  ],
  default: 'all'
}

It’s readable and behaves as you’d expect.

Calculating various lengths/totals

The app spec states we must show counts of “items left” and “items completed,” plus we have to be able to know if there aren’t any items at all in the collection so we can hide the header and footer.

This means we need to track 3 different calculated totals at all times.

Ultimately if this is state we care about, we want them to be easily readable as part of a model definition. Since we have a me model that contains the mode and has a child collection of todos, it makes sense for it to care about and track those totals. So we’ll create session properties for all of those totals too.

In the me model’s initialize we can listen to events in our collection that we know will affect these totals, and then we have a single method handleTodosUpdate that calculates and sets those totals.

The totals are quite easy; we check todos.length for totalCount, loop through once to calculate how many items are completed for completedCount, then use simple arithmetic for activeCount.

Just for clarity, we also then set a boolean value for whether all of them are completed or not. This is because the spec states that if you go through and check all the items in the list, that the “check all” checkbox at the top should also check itself. Tracking that state as a separate boolean makes it nice and clear.

So, now our me models looks something like this:

...
initialize: function () {
  // Listen to changes to the todos collection that will
  // affect lengths we want to calculate.
  this.listenTo(this.todos, 'change:completed change:title add remove', this.handleTodosUpdate);

  // We also want to calculate these values once on init
  this.handleTodosUpdate();
  ...
},
// Define our session properties
session: {
  activeCount: {
    type: 'number',
    default: 0
  },
  completedCount: {
    type: 'number',
    default: 0
  },
  totalCount:{
    type: 'number',
    default: 0
  },
  allCompleted: {
    type: 'boolean',
    default: false
  },
  mode: {
    type: 'string',
    values: [
      'all',
      'completed',
      'active'
    ],
    default: 'all'
  }
},
// Calculate and set various lengths we're
// tracking. We set them as session properties
// so they're easy to listen to and bind to DOM
// where needed.
handleTodosUpdate: function () {
  var completed = 0;
  var todos = this.todos;
  todos.each(function (todo) {
    if (todo.completed) {
      completed++;
    }
  });
  // Here we set all our session properties
  this.set({
    completedCount: completed,
    activeCount: todos.length - completed,
    totalCount: todos.length,
    allCompleted: todos.length === completed
  });
},
...

At this point we have all the state we want to track for the entire app. None of it is mixed into any of the view logic. We’ve got an entire completely de-coupled data layer that tracks all state for the app.

You can see the me model in its entirety as currently deployed on github.

Routing

Once we’ve done all of this state management, the router becomes super simple.

We’ve already created a mode flag on the me that actually controls everything.

So all we have to do is set the proper mode based on the URL, which we can do like so:


var Router = require('ampersand-router');


module.exports = Router.extend({
  routes: {
    // this matches all urls
    '*filter': 'setFilter'
  },
  setFilter: function (arg) {
    // if we passed one, set it
    // if not set it to "all"
    app.me.mode = arg || 'all';
  }
});

Views

At this point it’s really all a matter of wiring things up to the views. The views contain very little actual logic. They simply declare how things should be rendered, what data should be bound where, and turn user actions into changes in our state layer.

For this app, the index.html file contains the layout HTML already. So the main view is just going to attach itself to the <body> tag as you can see in our app.js file, below. We simply hand it the existing document.body and never call render() because it’s already there.

var MainView = require('./views/main');
var Me = require('./models/me');
var Router = require('./router');


window.app = {
  init: function () {
    // Model representing state for
    // user using the app. Calling it
    // 'me' is a bit of convention but
    // it's basically 'app state'.
    this.me = new Me();

    // Our main view
    this.view = new MainView({
      el: document.body,
      model: this.me
    });

    // Create and fire up the router
    this.router = new Router();
    this.router.history.start();
  }

};

window.app.init();

The views in this particular app handle all bindings declaratively as described by the bindings property of the views. It might feel a tad verbose, but it’s also very precise. This way you, as the developer, can decide whether you want to just render things into the template on first render, or whether you want to bind things. It’s also useful for publishing re-usable views. Because you don’t have to include any templating library as part of your re-usable views.

Templates and views are easily the most debate-inducing portion of modern JS apps, but the main point is that Ampersand.js gives you an agnostic way of doing data binding that’s there if you want it, but completely gets out of your way if you’d rather use something like Handlebars or React to handle your view layer.

That’s the whole point of the modular architecture of Ampersand.js: optimize for flexibility, install only what you want to use.

For a full reference of all the data binding types you can use, see the reference documentation.

Below are the declarative bindings from the main view with comments describing what each does.

Note that model in this case is the me model. So model.totalCount, for example, is referencing the me.totalCount session property discussed above. If you really prefer tracking state in your view code, it’s easy to do so. Simply add a props or session properties just like you would in a model, and everything still works.

It’s worth noting that with the way we’ve declared bindings in the app they still work if you replaced this.el, or if this.model was changed or didn’t exist at the time of first render. They would still be set and updated accordingly.

Many times in real apps, these binding declarations are simpler than this example, but on the plus side it serves as a good demo of the types of bindings that are available. Here’s the data binding section from our js/views/main.js view:


...

bindings: {
  // Toggles visibility of main and footer
  // based on truthiness of totalCount.
  // Since zero is falsy it won't show if
  // total is zero.
  'model.totalCount': {
    // this is the binding type
    type: 'toggle',
    // this is just a CSS selector
    selector: '#main, #footer'
  },
  // This is how you do multiple bindings
  // to a single property. Just pass an 
  // array of bindings.
  'model.completedCount': [
    // Hides the clear-completed span
    // when there are no completed items
    {
      type: 'toggle',
      // "hook" here is shortcut for 
      // selector: '[data-hook=clear-completed]'
      hook: 'clear-completed'
    },
    // Inserts completed count as text
    // into the span
    {
      type: 'text',
      hook: 'completed-count'
    }
  ],
  // This is an HTML string that we made
  // as a derived (a.k.a. computed) property
  // of the `me` model. This was done this way
  // for simplicity because the target HTML
  // looks like this: 
  // "<strong>5</strong> items left"
  // where "items" has to be correctly pluralized
  // since it's not just text, but not really
  // a bunch of nested HTML it was easier to just
  // bind this as `innerHTML`.
  'model.itemsLeftHtml': {
    type: 'innerHTML',
    hook: 'todo-count'
  },
  // This adds the 'selected' class to the right
  // element in the footer
  'model.mode': {
    type: 'switchClass',
    name: 'selected',
    cases: {
      'all': '[data-hook=all-mode]',
      'active': '[data-hook=active-mode]',
      'completed': '[data-hook=completed-mode]',
    }
  },
  // Bind 'checked' state of `mark-all`
  // checkbox at the top
  'model.allCompleted': {
    type: 'booleanAttribute',
    name: 'checked',
    hook: 'mark-all'
  }
},
...

A few closing thoughts

I’m excited that we were asked to contribute an example to TodoMVC. Big thanks to Luke Karrys, Philip Roberts and Gar for their help/feedback on building the app and to Sindre Sordhus, Addy Osmani, and Pascal Hartig for their hard work on the TodoMVC project, as it’s quite useful for comparing available tools.

If you have any feedback ping me, @HenrikJoreteg on twitter or any of the other core contributors for that matter. You can also jump into the #&yet IRC channel on freenode and tell us what you think. We’re always working to improve.

We think we’ve created something that strikes a good balance between flexibility, expressiveness, readability, and power, and we’re thrilled about the fast adoption and massive community contribution we’ve seen in just a few short months since releasing Ampersand.js.

I’ll be speaking about frameworks in Brighton at FullFrontal in a few weeks, and then about Ampersand.js at BackboneConf in December. Hope to see you then.

If you like the philosophy and approaches described here, you might also enjoy my book, Human JavaScript. If you want Ampersand.js training for your team get in touch with our training coordinator.

See you on the Interwebz! <3

● posted by Peter Saint-Andre

Two of our core values on the &yet team are curiosity and generosity. That’s why you’ll so often find my yeti colleagues at the forefront of various open-source projects, and also sharing their knowledge at technology and design conferences around the world.

An outstanding example is the work that Philip Roberts has done to understand how JavaScript really works within the browser, and to explain what he has discovered in a talk entitled “What the Heck is the Event Loop, Anyway?” (delivered at both ScotlandJS and JSConf EU in recent months).

If you’d like to know more about the inner workings of JavaScript, I highly recommend that you spend 30 minutes watching this video - it is fascinating and educational and entertaining all at the same time. (Because another yeti value is humility, you won’t find Philip boasting about this talk, but I have no such reservations because it is seriously great stuff.)

What the Heck is the Event Loop, Anyway?

● posted by Adam Brault

&yet has long been a wandering band of souls—like a mix of the A-Team and the Island of Misfit Toys from Rudolph the Red-Nosed Reindeer.

Over five years, one thing that’s been a constant for &yet is realtime. We’ve worked our way through many technologies—some ancient, some nascent, and many of our own. We’ve stayed focused on the users of those technologies—end users and developers.

Our path forward has become clearer and more focused than it’s ever been. Some of the terrific people we’ve added to our team this last year have had tremendous influence on honing our focus.

We know the type of company we aspire to be: people first, and always determined to make things better for humans on all sides of our work.

We know the type of experiences we aim to create: friendly, user-focused, and simple.

We know the types of problems we want to solve: we want to empower realtime software and the teams who build it, and we want to create a huge wake of open source that helps make communication technologies as open and accessible as the web itself.

We have a clearer sense of focus than we’ve ever had. But for us, there’s one missing component.

You.

In order for us to get where we want to go, we need you. The communities we are part of have shaped &yet in instrumental ways.

Blog posts are great, but they’re not enough. We don’t believe in blog post comments—we believe in conversations.

We want to invite our community to be a more intimate part of what we’re doing here, and we want to use email as a way to share the things we’re working on and learning and wondering about.

To that end, we are launching &you, a mailing list with bi-weekly dispatches covering all the things &yet does and has learned, and we want you to be part of it. Your aspirations, your questions, your problems, your frustrations, your wishes, your hopes. What do you need? How can we help?

We’ll get into more of that as we go, but first, we need your name and email address to get the ball rolling.

Join us. We need you!