Slide 1

Slide 1 text

FINDING PATTERNS MARCO ROGERS @polotek Yammer in FRONT-END JS

Slide 2

Slide 2 text

FINDING PATTERNS "When it comes down to it, everybody is building variants of the same MVCish framework. We should be talking about the shared patterns." ! - Me

Slide 3

Slide 3 text

FINDING PATTERNS • Common (Basic MVCish) • Advanced (Better abstractions, integrated) • Emerging (New app capabilities)

Slide 4

Slide 4 text

! ! COMMON PATTERNS

Slide 5

Slide 5 text

COMMON PATTERNS • Models • Views • Routing/Controllers • RESTful API access

Slide 6

Slide 6 text

MODELS • Objects representing your data • Data properties that are read/write • Persist data to the server (usually) • Event listeners that fire when data changes

Slide 7

Slide 7 text

MODELS: BACKBONE.JS var thread = new Backbone.Model({ ! id: 100,! latest_reply_at: '2014-05-28T17:36:05.707Z'! }); ! ! thread.get(‘id’) === 100;! ! thread.on(‘change:latest_reply_at’, function() {! /* Do Stuff */! });! ! thread.set(‘latest_reply_at’, (new Date).toISOString());

Slide 8

Slide 8 text

MODELS: YAM.JS var thread = yam.model.Thread.create({ ! id: 100, ! latest_reply_at: '2014-05-28T17:36:05.707Z'! });! ! thread.id === 100;! ! thread.hook(‘onUpdate’, function(oldData, newData) {! /* Do Stuff */! });! ! thread.update({! latest_reply_at: (new Date).toISOString()! });

Slide 9

Slide 9 text

MODELS: ANGULAR feedApp.controller('ThreadViewCtrl', function ($scope) { ! $scope.thread = { ! id: 100, ! latest_reply_at: '2014-05-28T17:36:05.707Z' ! }; ! ! $scope.thread.id === 100;! ! $scope.$watch(‘thread.latest_reply_at’, function(old, new) { ! /* Do Stuff */ ! }); ! ! $scope.thread.latest_reply_at = (new Date).toISOString();! });

Slide 10

Slide 10 text

MODELS • Objects representing your data • Data properties that are read/write • Event listeners that fire when data changes • Persist data to the server (usually)

Slide 11

Slide 11 text

! ! ADVANCED PATTERNS

Slide 12

Slide 12 text

ADVANCED PATTERNS • Nested Views • Complex Rendering • Model Relationships • Local Data Caching • Data-binding (two-way)

Slide 13

Slide 13 text

VIEWS • Render some markup to the DOM • Respond to user input from the DOM • Update the DOM based on some changes

Slide 14

Slide 14 text

NESTED VIEWS • Organize views into a parent-child tree • Parents recursively render children • The tree has a shared lifecycle

Slide 15

Slide 15 text

NESTED VIEWS: YAM.JS ThreadListItem ThreadStarter MessageListItem

Slide 16

Slide 16 text

NESTED VIEWS: YAM.JS ThreadListItem = Backbone.Component.extend({! _addThreadStarter: function () {! this.threadStarter = new ThreadStarter(message, {...});! this.prepend(this.threadStarter);! });! ! _addReplyListItem: function (reply) {! this.replyListItem = new MessageListItem(reply, {…});! this.append(this.replyListItem); ! });! });! ! var threadList = new ThreadListItem();! threadList.render();

Slide 17

Slide 17 text

NESTED VIEWS: MARIONETTE.JS MessageListItem = Backbone.Marionette.ItemView.extend({});! ! ThreadListItem = Backbone.Marionette.CompositeView.extend({! itemView: MessageListItem! });! ! var threadList = new ThreadListItem({! model: someModel,! collection: someCollection! });! ! threadList.render();

Slide 18

Slide 18 text

NESTED VIEWS: EMBER.JS App.MessageListItem = Ember.Component.extend({…});! !
! {{thread-starter}}!
    ! {#each reply in threadReplies}}! {{message-list-item reply=reply}}! {{/each}}!
!

Slide 19

Slide 19 text

! ! EMERGING PATTERNS

Slide 20

Slide 20 text

EMERGING PATTERNS • Custom components (Polymer, React) • Real-time updates (Socket.IO, Pusher) • Real-time sync (Firebase, Meteor) • Persistent offline cache (hood.ie) • Device capabilities (e.g. camera, location)

Slide 21

Slide 21 text

REAL-TIME UPDATES • Subscribe to real-time updates from the server • Dispatch updates to the model layer • Register to receive events with new model data

Slide 22

Slide 22 text

REAL-TIME: ANGULAR var ItemListController = function($scope, $http, Pusher) {! $scope.items = [];! ! var retrieveItems = function () {! $http.get('/api/items').success(function (items) {! $scope.items = items;! });! };! ! Pusher.subscribe('items', 'updated', function (item) {! $scope.items.push(item);! });! ! retrieveItems();! http://blog.pusher.com/making-angular-js-realtime-with-pusher/

Slide 23

Slide 23 text

REAL-TIME: EMBER.JS Discourse.TopicController = Discourse.ObjectController.extend(..., {! subscribe: function() {! var topicController = this;! var bus = Discourse.MessageBus;! ! bus.subscribe("/topic/" + this.get('id'), function(data) {! // Add the new post into the stream! topicController.get(‘postStream')! .triggerNewPostInStream(data.id);! });! }! } http://balinterdi.com/2014/01/14/how-real-time-updates-work-in- discourse.html

Slide 24

Slide 24 text

REAL-TIME: YAM.JS // FeedModel! yam.model.define('yam.model.Feed', function () {! this.clientize(‘yam.client.RealtimeFeedClient’);! ! // DataClient! yam.ctor(‘yam.client.BaseRealtimeClient’, {! connectToRealtime: function(params) {! yam.client.bayeux.subscribe({! id: this.getUrl(),! url: this.getRealtimeUrl(),! onData: _.bind(this.onRealtimeData, this)! });! }! });

Slide 25

Slide 25 text

REAL-TIME: YAM.JS var feedModel = yam.model.Feed.create(…);! ! // Listen for events! feedModel.hook(‘onThreadUpdate’, function(thread) {! // Could be from an ajax request, could be real-time! // We usually don’t care! });

Slide 26

Slide 26 text

REAL-TIME: METEOR Messages = new Meteor.Collection(‘messages’);! ! var query = Messages.find();! query.observeChanges({! added: function (id, message) { /* Do stuff */ },! removed: function () { /* Do stuff */ }! });

Slide 27

Slide 27 text

REAL-TIME: METEOR ! {#each messages}!
  • {{body}}
  • ! {/each}! ! ! Template.messageList.messages = function () {! return Messages.find();! };

    Slide 28

    Slide 28 text

    FINDING PATTERNS "I'm more interested in optimizing a person's understanding of problems than their understanding of solutions.” ! - Kris Gale

    Slide 29

    Slide 29 text

    THANKS. MARCO ROGERS @polotek Yammer