1. Lessons from a rewrite
Rebecca Murphey • TXJS 2011 • Austin, Texas
Saturday, June 11, 2011
2. Rewrite projects are ... tempting because they
always look easier than they actually are.
If you want to survive a software rewrite,
don’t throw away your existing software ...
Write the code in such a way that it co-exists
with your existing software, perhaps as an
optional add-on that you can sell.
James Shore
Saturday, June 11, 2011
3. 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, June 11, 2011
4. Until you are able to prove that you have a
viable market ... you shouldn’t be sinking a lot
of time and money into implementation.
Assuming you are [competent], you should be
able to ... take on quite a bit of technical
debt to build throwaway proof-of-concept
versions of your product.
Obie Fernandez
Saturday, June 11, 2011
5. 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, June 11, 2011
6. For the human makers of things,
the incompleteness and
inconsistencies of our ideas
become clear only during
implementation.
Fred Brooks
Saturday, June 11, 2011
7. 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, June 11, 2011
12. 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.
Saturday, June 11, 2011
13. 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, June 11, 2011
21. page controllers set up components and
broker communication between them
ui components receive and render data;
announce and react to user interaction
app components manage app data and state
Saturday, June 11, 2011
31. myComponent.set()
to change state
myComponent.on<Evt>()
to announce state changes
myComponent.connect()
to listen for events & methods
myComponent.subscribe()
to react to published topics
dojo.publish()
to announce occurrences of app-wide interest
Saturday, June 11, 2011
32. Facilitating
development
Saturday, June 11, 2011
37. /**
* This file generates built dojo and toura files for
* use in production.
*/
dependencies = {
/*
* tell dojo to strip out ie-specific hacks
*/
webkitMobile : true,
/*
* this is a production build -- non-production code should be stripped
*/
production : true,
/*
* the name of the release and where to put it,
* relative to dojo-release-X.X.X-src/util/buildscripts/.
*/
releaseName : 'production',
/*
* strip all calls to console.log automatically
*/
stripConsole : 'all',
/*
* clean the existing release directory, then create a new release
Saturday, June 11, 2011 */
38. dojo.provide('toura.app.Phonegap.network');
toura.app.Phonegap.network = function(pg, device) {
var n = navigator;
return {
isReachable : function(domain) {
console.log('toura.app.Phonegap.network::isReachable()');
var dfd = new dojo.Deferred();
if (n && n.network && n.network.isReachable) {
console.log('using phonegap network');
n.network.isReachable(
domain || 'aws.amazon.com',
function(r) {
dfd.resolve(r !== NetworkStatus.NOT_REACHABLE);
},
function() {
console.log('failure on network is reachable');
dfd.resolve(false);
}
);
} else {
// resolve false if PhoneGap is present;
// network is not indeed reachable
if (pg) {
dfd.resolve(false);
Saturday, June 11, 2011
} else {
52. Feature: A User can view a node with the Video1 template and play each video
Scenario: Videos1: Setup
When I am on the home node
And I click "Plain Node"
And I click "Video Player"
Then I should see a Video Player
And I should see an Asset List
And I should see a Child Nodes list
And I should see "movie_for_demo" in the asset list
Scenario: Videos1: Controlling the video player from the asset list
When I am on the home node
And I click "Plain Node"
And I click "Video Player"
And I click "movie_for_demo" in the asset list
Then "video-29" should be selected in the asset list
And I should see "videos-29" in the video player
Scenario: Navigating to a specific video
When I am on the home node
And I go to the URL "#/node/node-372/videos/video-29"
Then I should see "videos-29" in the video player
And "video-29" should be selected in the asset list
Saturday, June 11, 2011
53. expect(c.queryInput).toBeDefined();
expect(c.i18n_placeholderText).toBeTruthy();
});
});
it("should provide an API for setting the search term", function() {
c = C();
c.set('searchTerm', term);
expect(c.queryInput.value).toBe(term);
});
it("should announce searches when the form is submitted with a term", function() {
var submitHandler;
toura.app.UI.hasTouch = false;
c = C();
c.set('searchTerm', term);
spyOn(c, 'search');
submitHandler = getEventHandlers(c, 'submit', c.searchForm)[0];
submitHandler(fakeEventObj);
expect(c.search).toHaveBeenCalledWith(term);
});
it("should not announce searches if the form is submitted with no term", function() {
var submitHandler;
toura.app.UI.hasTouch = false;
c = C();
c.set('searchTerm', '');
spyOn(c, 'search');
Saturday, June 11, 2011 submitHandler = getEventHandlers(c, 'submit', c.searchForm)[0];
54. 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, June 11, 2011