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 ...
A content management system for the rapid          creation of content-rich mobile applications.          A PhoneGap & Doj...
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 ...
If data is required for a                                                                                                 ...
Have we                                      no                         loaded the           Populate DB                  ...
{                             "name": "Audio Player",                             "audios": [{                            ...
Identify pain pointsSaturday, July 9, 2011
Saturday, July 9, 2011
/* {{^android}} */          var mediaPath = "www/media/" + toura.pages.currentId +          "/";          /* {{/android}} ...
toura.app.Has = function() {                    var device = toura.app.Config.get(device);                         return ...
//>>excludeStart(production, kwArgs.production);          if (toura.features.debugToolbar) { toura.app._Debug(); }        ...
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 w...
myComponent.set(key, val)          to change state          myComponent.on<Evt>(data)          to announce state changes  ...
Saturday, July 9, 2011
Search Input                                                            toura.app.Data.search(term)              searchInp...
dojo.declare(            toura.pageControllers.search.Search,            [ toura.pageControllers._Page ], {               ...
Sanify                         asynchronicitySaturday, July 9, 2011
old & busted          images = toura.sqlite.getMedias(id, "image");          var onGetComplete = setInterval(function() { ...
var myAsyncThing = function() {              var dfd = new dojo.Deferred();              setTimeout(function() {          ...
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.            ...
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 pi...
function nodeRoute(route, nodeId, pageState) {                   pageState = pageState || {};                         var ...
Saturday, July 9, 2011
Saturday, July 9, 2011
this.connect(this.videoList, onSelect, function(assetId) {            var video = this._videoById(assetId);            thi...
videoPlayer.set(mediaId, mediaId);                         _setMediaIdAttr : function(mediaId) {                          ...
It takes con dence to throw work away ...          When people rst start drawing, they’re often          reluctant to redo...
Saturday, July 9, 2011
http://pinboard.in/u:rmurphey/t:lessons-from-a-rewrite/                                  http://spkr8.com/t/7930          ...
Upcoming SlideShare
Loading in...5
×

Lessons from-a-rewrite-gotham

2,593

Published on

Published in: Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,593
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
13
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Lessons from-a-rewrite-gotham

  1. 1. Lessons from a rewrite Rebecca Murphey • Gotham JS • New York, New YorkSaturday, July 9, 2011
  2. 2. 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
  3. 3. 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
  4. 4. Saturday, July 9, 2011
  5. 5. 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
  6. 6. 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
  7. 7. 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
  8. 8. { "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": {
  9. 9. Identify pain pointsSaturday, July 9, 2011
  10. 10. Saturday, July 9, 2011
  11. 11. /* {{^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
  12. 12. 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
  13. 13. //>>excludeStart(production, kwArgs.production); if (toura.features.debugToolbar) { toura.app._Debug(); } //>>excludeEnd(production);Saturday, July 9, 2011
  14. 14. Develop a communication manifestoSaturday, July 9, 2011
  15. 15. 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
  16. 16. 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
  17. 17. Saturday, July 9, 2011
  18. 18. 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
  19. 19. 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
  20. 20. Sanify asynchronicitySaturday, July 9, 2011
  21. 21. 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
  22. 22. 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
  23. 23. dojo.when(fn(), win, fail) react to maybe-asynchronous things, including promisesSaturday, July 9, 2011
  24. 24. Naming things is hardSaturday, July 9, 2011
  25. 25. ere are only two hard things in Computer Science: cache invalidation and naming things. Phil KarltonSaturday, July 9, 2011
  26. 26. Saturday, July 9, 2011
  27. 27. Saturday, July 9, 2011
  28. 28. Saturday, July 9, 2011
  29. 29. Saturday, July 9, 2011
  30. 30. yellow red blueSaturday, July 9, 2011
  31. 31. Never write large appsSaturday, July 9, 2011
  32. 32. 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
  33. 33. 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
  34. 34. Saturday, July 9, 2011
  35. 35. Saturday, July 9, 2011
  36. 36. 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
  37. 37. 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
  38. 38. 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
  39. 39. Saturday, July 9, 2011
  40. 40. http://pinboard.in/u:rmurphey/t:lessons-from-a-rewrite/ http://spkr8.com/t/7930 rebeccamurphey.com • blog.rebeccamurphey.com • @rmurpheySaturday, July 9, 2011
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×