• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Lessons from-a-rewrite-gotham

Lessons from-a-rewrite-gotham






Total Views
Views on SlideShare
Embed Views



7 Embeds 440

http://coderwall.com 394
http://lanyrd.com 27
http://paper.li 10
https://twitter.com 5
http://twitter.com 2
url_unknown 1
http://lanyrd.net 1



Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
Post Comment
Edit your comment

    Lessons from-a-rewrite-gotham Lessons from-a-rewrite-gotham Presentation Transcript

    • Lessons from a rewrite Rebecca Murphey • Gotham JS • New York, New YorkSaturday, July 9, 2011
    • ere’s a subtle reason that programmers always want to throw away the code and start over. e reason is that they think the old code is a mess. ... e reason that they think the old code is a mess is because of a cardinal, fundamental law of programming: It’s harder to read code than to write it. Joel SpolskySaturday, July 9, 2011
    • A content management system for the rapid creation of content-rich mobile applications. A PhoneGap & Dojo system that consumes the output of the CMS to generate the application.Saturday, July 9, 2011
    • Saturday, July 9, 2011
    • Where a new system concept or new technology is used, one has to build a system to throw away, for even the best planning is not so omniscient as to get it right the rst time. Hence plan to throw one away; you will, anyhow. Fred BrooksSaturday, July 9, 2011
    • If data is required for a route, such as node data or the users favorites, the route requests the data prior to creating the page. Data Page Controller Component Component Page Controller Component Component Component Component When the app is booted from a "cold" state (that URL Change Router Page Factory is, its not fast-app- Page controllers are responsible for Components are responsible for Once components are placed on the switched), it goes receiving data from the Page Factory. Once receiving and rendering data and page, the Page Controller brokers through a bootstrapping The Router detects a The Route asks the page the page controller receives that data, it reacting to user interaction. communication between components. Route determines which components to display in process. This process change in the URL, looks factory to generate a page for a matching route in controller. If the page its postMixInProperties method and sets up Components whose content can change Components announce events either by ensures the application "placements," which define the components during a single page view should expose publishing a topic (for events that may toura.app.Routes, and controller is for a node, the is working with the that will be placed on the page and the data an API using setters (i.e. have app-wide significance) or by calling parses any additional Page Factory figures out most recent data, and parameters out of the URL which template (Audios, that needs to be passed to them. The _setContentAttr) that allows Page a method (such as onClick). Page also sets up various (such as the node ID, Images, etc.) the node actual instantiation and placement of Controllers to update their content. Controllers can subscribe to these application-wide Device Storage asset type, etc.). uses. The page factory components is handled in the postCreate topics or connect to these method calls creates an instance of the method of toura.pageControllers._Page, Alternately, a component can define an (much like connecting to events). This functionality, including page controller and hands which is inherited by all Page Controllers. attributeMap object that specifies how happens in the Page Controllers the Router, UI, Page the component should react when a postCreate method. the created instance back Factory, Data Store, to the Route. property is set. and several others. Once these pieces are in place, the app Remote triggers a URL change to the home node, and the process outlined here begins. Every time the user goes UI to a new page, we check the age of the local data; if it is more than 8 hours old, we see whether we need to do an over-the-air update. Browser Page Container Old Page Controller New Page Controller Component Component Component Component Component Component The Route asks toura.app.UI to place the Page Controller in the UI; in turn, toura.app.UI sets the content attribute of the Page Container. If there is already a page on screen, the Page Container handles the animation between the pages, and calls the destroy method of the old page, which results in the proper teardown of the old page and its components. Understand what you’re rewritingSaturday, July 9, 2011
    • Have we no loaded the Populate DB bundled with bundled data data? yes no Is the remote dfd.resolve() reachable? Get the remote versionSaturday, July 9, 2011
    • { "name": "Audio Player", "audios": [{ "audio": { "_reference": "audio-23" }, "caption": { "_reference": "text-asset-64" } }], "parent": { "_reference": "node-365" }, "page_controller": "Audios1", "id": "node-369", "sharing_text": null, "sharing_url": null, "images": [{ "caption": { "_reference": "text-asset-60" }, "image": { "_reference": "image-174" } }, { "caption": { "_reference": "text-asset-61" }, "image": { "_reference": "image-182" } }, {Saturday, July 9, 2011 "image": {
    • Identify pain pointsSaturday, July 9, 2011
    • Saturday, July 9, 2011
    • /* {{^android}} */ var mediaPath = "www/media/" + toura.pages.currentId + "/"; /* {{/android}} */ /* {{#android}} */ var mediaPath = [Toura.getTouraPath(), toura.pages.currentId].join("/"); /* {{/android}} */ var imagesList = [], dimensionsList = [], namesList = [], thumbsList = []; var pos = -1, count = 0; /* {{#android}} */ var pos = 0, count = 0; /* {{/android}} */Saturday, July 9, 2011
    • toura.app.Has = function() { var device = toura.app.Config.get(device); return { cssBackgroundContain : function() { return !( device.os === android && device.version === 2-1 ); }, html5Player : function() { return device.os !== android; }, iScrollZoom : function() { return device.os !== android; } }; };Saturday, July 9, 2011
    • //>>excludeStart(production, kwArgs.production); if (toura.features.debugToolbar) { toura.app._Debug(); } //>>excludeEnd(production);Saturday, July 9, 2011
    • Develop a communication manifestoSaturday, July 9, 2011
    • Writing to be read means writing code ... with the idea that someone else will read it. is fact alone will make you edit and think of better ways to solve the problem you have at hand. Stoyan StefanovSaturday, July 9, 2011
    • myComponent.set(key, val) to change state myComponent.on<Evt>(data) to announce state changes myComponent.connect(evt, handler) to listen for events & methods myComponent.subscribe(topic) to react to published topics dojo.publish(topic, data) to announce occurrences of app-wide interestSaturday, July 9, 2011
    • Saturday, July 9, 2011
    • Search Input toura.app.Data.search(term) searchInputInstance.onSearch(term) Search Page Controller Application Data searchResults.set(results, resultSet) return resultSet Search Results DisplaySaturday, July 9, 2011
    • dojo.declare( toura.pageControllers.search.Search, [ toura.pageControllers._Page ], { // ... postCreate : function() { // ... this.connect(this.searchInput, onSearch, _handleSearch); }, _handleSearch : function(term) { if (term === this.lastSearchTerm) { return; } this.searchResults.set(results, toura.app.Data.search(term)); }, // ... });Saturday, July 9, 2011
    • Sanify asynchronicitySaturday, July 9, 2011
    • old & busted images = toura.sqlite.getMedias(id, "image"); var onGetComplete = setInterval(function() { if (images.incomplete) return; clearInterval(onGetComplete); showImagesHelper(images.objs, choice) }, 10); new hotness toura.app.Data.get(id, image).then(showImages, showImagesFail);Saturday, July 9, 2011
    • var myAsyncThing = function() { var dfd = new dojo.Deferred(); setTimeout(function() { dfd.resolve(hello); }, 1000); return dfd.promise; }; myAsyncThing().then(function(result){ console.log(result); });Saturday, July 9, 2011
    • dojo.when(fn(), win, fail) react to maybe-asynchronous things, including promisesSaturday, July 9, 2011
    • Naming things is hardSaturday, July 9, 2011
    • ere are only two hard things in Computer Science: cache invalidation and naming things. Phil KarltonSaturday, July 9, 2011
    • Saturday, July 9, 2011
    • Saturday, July 9, 2011
    • Saturday, July 9, 2011
    • Saturday, July 9, 2011
    • yellow red blueSaturday, July 9, 2011
    • Never write large appsSaturday, July 9, 2011
    • e secret to building large apps is never build large apps. Break up your applications into small pieces. en, assemble those testable, bite-sized pieces into your big application. Justin MeyerSaturday, July 9, 2011
    • function nodeRoute(route, nodeId, pageState) { pageState = pageState || {}; var nodeModel = toura.app.Data.getModel(nodeId), page = toura.app.UI.getCurrentPage(); if (!page || !page.node || nodeId !== page.node.id) { page = toura.app.PageFactory.createPage(node, nodeModel); page.init(pageState); toura.app.UI.showPage(page, nodeModel); } else { page.init(pageState); } // record node pageview if it is node-only if (nodeId && !pageState.assetType) { dojo.publish(/node/view, [ route.hash ]); } return true; }Saturday, July 9, 2011
    • Saturday, July 9, 2011
    • Saturday, July 9, 2011
    • this.connect(this.videoList, onSelect, function(assetId) { var video = this._videoById(assetId); this.videoCaption.set(content, video.caption || ); this.videoPlayer.play(assetId); });Saturday, July 9, 2011
    • videoPlayer.set(mediaId, mediaId); _setMediaIdAttr : function(mediaId) { var media = this.media = this.mediasCache[mediaId]; if (this.useHtml5Player && !this.player) { this._queuedMedia = media; return; } this._queuedMedia = null; if (this.player) { this.player.src = media.url; } },Saturday, July 9, 2011
    • It takes con dence to throw work away ... When people rst start drawing, they’re often reluctant to redo parts that aren’t right ... they convince themselves that the drawing is not that bad, really — in fact, maybe they meant it to look that way. Paul GrahamSaturday, July 9, 2011
    • Saturday, July 9, 2011
    • http://pinboard.in/u:rmurphey/t:lessons-from-a-rewrite/ http://spkr8.com/t/7930 rebeccamurphey.com • blog.rebeccamurphey.com • @rmurpheySaturday, July 9, 2011