SlideShare ist ein Scribd-Unternehmen logo
1 von 40
Downloaden Sie, um offline zu lesen
Lessons from a rewrite
                 Rebecca Murphey • Gotham JS • New York, New York




Saturday, 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 Spolsky




Saturday, 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 Brooks




Saturday, July 9, 2011
If data is required for a
                                                                                                                  route, such as node data
                                                                                                                  or the user's 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, it's 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 Controller's
           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 rewriting
Saturday, 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
                       version



Saturday, 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 points
Saturday, 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
                         manifesto




Saturday, 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 Stefanov


Saturday, 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 interest


Saturday, 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
                                              Display




Saturday, 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
                         asynchronicity

Saturday, 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 promises




Saturday, July 9, 2011
Naming things is hard
Saturday, July 9, 2011
ere are only two hard things in
            Computer Science: cache invalidation
            and naming things.
                                            Phil Karlton




Saturday, July 9, 2011
Saturday, July 9, 2011
Saturday, July 9, 2011
Saturday, July 9, 2011
Saturday, July 9, 2011
yellow
                          red
                          blue
Saturday, July 9, 2011
Never write large apps




Saturday, 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 Meyer




Saturday, 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 Graham




Saturday, 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 • @rmurphey




Saturday, July 9, 2011

Weitere ähnliche Inhalte

Ähnlich wie Lessons from-a-rewrite-gotham

ScrapeXpress-Standalone-solution
ScrapeXpress-Standalone-solutionScrapeXpress-Standalone-solution
ScrapeXpress-Standalone-solution
Andy Yang
 
Spatial Data Integrator - Software Presentation and Use Cases
Spatial Data Integrator - Software Presentation and Use CasesSpatial Data Integrator - Software Presentation and Use Cases
Spatial Data Integrator - Software Presentation and Use Cases
mathieuraj
 

Ähnlich wie Lessons from-a-rewrite-gotham (20)

Lessons from a Rewrite
Lessons from a RewriteLessons from a Rewrite
Lessons from a Rewrite
 
NASA Facilities GIS
NASA Facilities GISNASA Facilities GIS
NASA Facilities GIS
 
Data Sharing Between Child and Parent Components in AngularJS
Data Sharing Between Child and Parent Components in AngularJSData Sharing Between Child and Parent Components in AngularJS
Data Sharing Between Child and Parent Components in AngularJS
 
CSSDP Presentation April 09
CSSDP Presentation April 09CSSDP Presentation April 09
CSSDP Presentation April 09
 
CSSDP Presentation April 09
CSSDP Presentation April 09CSSDP Presentation April 09
CSSDP Presentation April 09
 
Web Server-based Distributed Machine Socialization System
Web Server-based Distributed Machine Socialization System Web Server-based Distributed Machine Socialization System
Web Server-based Distributed Machine Socialization System
 
Asp.net control
Asp.net controlAsp.net control
Asp.net control
 
Parallelminds.asp.net with sp
Parallelminds.asp.net with spParallelminds.asp.net with sp
Parallelminds.asp.net with sp
 
Getting started with react &amp; redux
Getting started with react &amp; reduxGetting started with react &amp; redux
Getting started with react &amp; redux
 
ScrapeXpress-Standalone-solution
ScrapeXpress-Standalone-solutionScrapeXpress-Standalone-solution
ScrapeXpress-Standalone-solution
 
React - The JavaScript Library for User Interfaces
React - The JavaScript Library for User InterfacesReact - The JavaScript Library for User Interfaces
React - The JavaScript Library for User Interfaces
 
15 asp.net session22
15 asp.net session2215 asp.net session22
15 asp.net session22
 
Component based User Interface Rendering with State Caching Between Routes
Component based User Interface Rendering with State Caching Between RoutesComponent based User Interface Rendering with State Caching Between Routes
Component based User Interface Rendering with State Caching Between Routes
 
Synopsis
SynopsisSynopsis
Synopsis
 
Spatial Data Integrator - Software Presentation and Use Cases
Spatial Data Integrator - Software Presentation and Use CasesSpatial Data Integrator - Software Presentation and Use Cases
Spatial Data Integrator - Software Presentation and Use Cases
 
Reactjs
Reactjs Reactjs
Reactjs
 
Full-Stack Observability for IoT Event Stream Data Processing at Penske
Full-Stack Observability for IoT Event Stream Data Processing at PenskeFull-Stack Observability for IoT Event Stream Data Processing at Penske
Full-Stack Observability for IoT Event Stream Data Processing at Penske
 
Automatic Web Service Composition For SaaS Business Intelligence
Automatic Web Service Composition For SaaS Business IntelligenceAutomatic Web Service Composition For SaaS Business Intelligence
Automatic Web Service Composition For SaaS Business Intelligence
 
Next.js - ReactPlayIO.pptx
Next.js - ReactPlayIO.pptxNext.js - ReactPlayIO.pptx
Next.js - ReactPlayIO.pptx
 
DashMash: a Mashup Environment for End User Development
DashMash: a Mashup Environment for End User DevelopmentDashMash: a Mashup Environment for End User Development
DashMash: a Mashup Environment for End User Development
 

Mehr von Rebecca Murphey

Getting Started with Mulberry
Getting Started with MulberryGetting Started with Mulberry
Getting Started with Mulberry
Rebecca Murphey
 
Cleaner, Leaner, Meaner: Refactoring your jQuery
Cleaner, Leaner, Meaner: Refactoring your jQueryCleaner, Leaner, Meaner: Refactoring your jQuery
Cleaner, Leaner, Meaner: Refactoring your jQuery
Rebecca Murphey
 
Delivering a Responsive UI
Delivering a Responsive UIDelivering a Responsive UI
Delivering a Responsive UI
Rebecca Murphey
 

Mehr von Rebecca Murphey (9)

Beyond the DOM: Sane Structure for JS Apps
Beyond the DOM: Sane Structure for JS AppsBeyond the DOM: Sane Structure for JS Apps
Beyond the DOM: Sane Structure for JS Apps
 
BVJS
BVJSBVJS
BVJS
 
Getting Started with Mulberry
Getting Started with MulberryGetting Started with Mulberry
Getting Started with Mulberry
 
Cleaner, Leaner, Meaner: Refactoring your jQuery
Cleaner, Leaner, Meaner: Refactoring your jQueryCleaner, Leaner, Meaner: Refactoring your jQuery
Cleaner, Leaner, Meaner: Refactoring your jQuery
 
Functionality Focused Code Organization
Functionality Focused Code OrganizationFunctionality Focused Code Organization
Functionality Focused Code Organization
 
The jQuery Divide
The jQuery DivideThe jQuery Divide
The jQuery Divide
 
Delivering a Responsive UI
Delivering a Responsive UIDelivering a Responsive UI
Delivering a Responsive UI
 
Using Objects to Organize your jQuery Code
Using Objects to Organize your jQuery CodeUsing Objects to Organize your jQuery Code
Using Objects to Organize your jQuery Code
 
Jquery Fundamentals
Jquery FundamentalsJquery Fundamentals
Jquery Fundamentals
 

Kürzlich hochgeladen

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 

Kürzlich hochgeladen (20)

DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 

Lessons from-a-rewrite-gotham

  • 1. Lessons from a rewrite Rebecca Murphey • Gotham JS • New York, New York Saturday, July 9, 2011
  • 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 Spolsky Saturday, July 9, 2011
  • 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
  • 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 Brooks Saturday, July 9, 2011
  • 6. If data is required for a route, such as node data or the user's 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, it's 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 Controller's 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 rewriting Saturday, July 9, 2011
  • 7. Have we no loaded the Populate DB bundled with bundled data data? yes no Is the remote dfd.resolve() reachable? Get the remote version Saturday, July 9, 2011
  • 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": {
  • 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. 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. //>>excludeStart('production', kwArgs.production); if (toura.features.debugToolbar) { toura.app._Debug(); } //>>excludeEnd('production'); Saturday, July 9, 2011
  • 14. Develop a communication manifesto Saturday, July 9, 2011
  • 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 Stefanov Saturday, July 9, 2011
  • 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 interest Saturday, July 9, 2011
  • 18. Search Input toura.app.Data.search(term) searchInputInstance.onSearch(term) Search Page Controller Application Data searchResults.set('results', resultSet) return resultSet Search Results Display Saturday, July 9, 2011
  • 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. Sanify asynchronicity Saturday, July 9, 2011
  • 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. 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. dojo.when(fn(), win, fail) react to maybe-asynchronous things, including promises Saturday, July 9, 2011
  • 24. Naming things is hard Saturday, July 9, 2011
  • 25. ere are only two hard things in Computer Science: cache invalidation and naming things. Phil Karlton Saturday, July 9, 2011
  • 30. yellow red blue Saturday, July 9, 2011
  • 31. Never write large apps Saturday, July 9, 2011
  • 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 Meyer Saturday, July 9, 2011
  • 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
  • 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. 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. 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 Graham Saturday, July 9, 2011
  • 40. http://pinboard.in/u:rmurphey/t:lessons-from-a-rewrite/ http://spkr8.com/t/7930 rebeccamurphey.com • blog.rebeccamurphey.com • @rmurphey Saturday, July 9, 2011