Notes
Slide Show
Outline
1
 
2
Steve Yen
  • TrimPath
    • Num Sum
  • Escalate
  • KIVA
3
Fast Changing Topic
  • What
  • Why
  • How you can do it yourself
4
Web Apps Without The Web
5
Web Apps Without The Web
  • Modern web browser
  • No installs
  • No security dialogs
  • Standards
  • Ajax / dhtml / html / css
6
Web Apps Without The Web
  • Occasionally offline
  • Occasionally connected
  • Airplane is boarding
  • Train in a tunnel
  • Wifi is “secured”
  • Evdo hiccups
7
Easily Add Without The Web
  • Already (re)learning DHTML, Ajax…
  • Add just a little bit more…
  • Only a few more tricks…


8
Why
  • Get more dates
  • Make more money
  • Look like a hero


9
Recurring Dream
  • Alpha geeks
10
Ray Ozzie
  • Notes
  • Groove
11
Adam Bosworth
  • Alchemy
  • Blog
12
Demo
13
Without The Web Is Easy!
  • Use the TrimPath Junction framework
  • Or, do it yourself / write your own
  • As easy as Ajax
14
100 Ajax frameworks?
  • Everyone has one, maybe even you
  • Starts so simple
  • 15 line wrapper around XMLHttpRequest


  • What about for going occasionally offline?
15
What Else Do You Need
  • …to go occasionally offline
16
Persistence
  • Client side data cache
  • That can work offline
17
Persistence Technique 1
  • Modern browsers keep dhtml DOM tree intact during a File | Save Page As
  • Keep your data in the DOM tree
    • myHiddenDataDiv.innerHTML = bigString
  • Whenever user saves the HTML page, you’re ok
  • User must explicitly File | Save Page As
18
Persistence Technique 2
  • Flash 8 Storage
  • Flash to JavaScript bridge
  • Seamless!
  • Except, when you hit quantum level of storage usage, Flash pops up a warning


    • (+1 Brad Neuberg)
19
Persistence Technique 3
  • Internet Explorer’isms
  • IE persistence
  • IE offline data


  • Future is already here
  • And in the case of Internet Explorer is already widely distributed
20
Persistence Examples
  • DOM Page Saving Technique
    • TiddlyWiki & friends
    • Num Sum
    • Next Action


  • Flash Storage Technique
    • AMASS demos
    • Tiwywiki / AFLAX
      • http://ajaxian.com/archives/take-it-with-you-wiki
    • ideaShrub
21
What else do you need?
  • Persistence (yes)
  • Synchronization
22
Synchronization
  • Data / record level semantics
  • Tracking deltas
  • Change requests, not changes
  • INSERTs only
  • Unique ID gen
  • Or, just punt
    • Wiki semantics
23
What else do you need?
  • Persistence (yes)
  • Synchronization (yes)
  • Client side API
24
Client Programming Model
  • Visual Basic Style
    • No
  • Rails Style
    • Yes
    • Write Once Run Anywhere
25
SQL Everywhere
  • SQL on the server
  • SQL on the client
  • Aside: Firefox future
    • Derby?
    • SQLite?
26
TrimPath Junction
  • MVC Framework for JavaScript
    • Rails-like API with client-side SQL
  • Designed for WORA
    • Write once, run anywhere (client or server)
    • Server runs Rhino
  • Designed for >1 storage provider
    • DOM Page, Flash or other (Derby, SQLite)
    • MySQL when running on server
27
Building your own Junction
  • What are the core tricks?
28
Born from a question
  • How powerful is JavaScript?
29
JavaScript ~= Lisp
  • Thank you, Douglas Crockford
  • Thank you, Brendan Eich


30
eval and with
31
JavaScript’s with keyword
  • JavaScript’s dynamic scoping
  • Change the scope chain at runtime
32
with (obj) { … }
  • x = 123;
  • alert(x);
  • obj = { ‘x’: ‘joel’ }
  • alert(x);
  • with (obj) {
    • alert(x);
    • obj[‘x’] = ‘spolsky’;
    • alert(x);
  • }
33
Why care about with?
  • Domain specific mini languages are easy


  • JSP
  • SQL
  • Obj-Relational mapping
  • Spreadsheet formulas
  • Prolog
  • Scheme
  • Ruby
  • Layout constraints
  • Synchronization constraints
34
JST Template Engine
  • JST == JavaScript Templates


  • <h1>Welcome Back!
  •          ${Customer.name}</h1>


  • Loops, macros, modifiers, minify
  • Smarty, Freemarker
35
JST Compilation
  • Hand rolled parser
  • Generate JavaScript function string
    • with (context) {
      • out.push(“<h1>Welcome Back! ”)
      • out.push(Customer.name)
      • out.push(“</h1>”)
    • }
  • Eval and return it
36
JST Processing
  • resultStr = template.process(context)
  • someDiv.innerHTML = resultStr


  • JST Engine -- 397 LoC
37
JST Parsing Via Regexp
  • JST-R
38
TrimQuery SQL Engine
  • RegExps to transform SQL to TQL
    • SELECT(Emp.name, Emp.salary,
      • FROM(Emp, Dept),
      • ORDER_BY(Emp.name))
  • Eval the TQL (it’s just JavaScript)
  • Emp and Dept are JavaScript objects that represent the table schema.
  • schema = {
    • Emp: { …bunch-o-column-definitions… },
    • Dept: { …more-column-definitions… }
  • }
39
TrimQuery AST
  • with (TQL_KEYWORDS) {
    • with (schema) {
      • SELECT(Emp.name, Emp.salary,
        • FROM(Emp, Dept),
        • ORDER_BY(Emp.name))
    • }
  • }
40
TrimQuery JOIN driver
  • with (data_tables) {
    • crossJoinTuple = {}
    • for (i = 0; i < Emp.length; i++) {
    • crossJoinTuple.Emp = Emp[i];
    • for (j = 0; j < Dept.length; j++) {
    • crossJoinTuple.Dept = Dept[j]
    • if (whereClause(crossJoinTuple))
    •     addToResultSet(crossJoinTuple)
    • }
    • }
  • }
41
TrimQuery where clause
  • with (crossJoinTuple) {
    • if (Emp.salary > 100 &&
    •     Emp.dept_id == Dept.id)
    •     return true;
    • return false;
  • }
42
TrimQuery stats
  • CROSS & LEFT OUTER JOINs
  • TABLE & COLUMN aliases
  • WHERE, ORDER BY
  • GROUP BY, HAVING
  • Aggregates


  • SQL engine in 668 LoC
43
Model View Controller API
  • Clone or port the Rails API
  • Into JavaScript
  • Leverages Rails goodness
  • Lazy approach


  • TrimPath Junction -- 1244 LoC
44
Model
  • Milestone = function() { }
  • with (modelFor('Milestone')) {
    • belongsTo('Creator', { modelName : 'Person' });
    • belongsTo('Domain', { modelName : 'Org' });
    • belongsTo('Project');
    • belongsTo('Assignee', { modelName : 'Person' });
    • hasMany('Messages');
    • hasMany('TodoLists');
  • }
45
Model
  • Milestone.findRecentByProject =
  • function(projectId, date) {
    • return Milestone.findAll(
      • “Milestone.projectId = ?” +
      • “ AND Milestone.createdAt > ?”,
      • [ projectId, date ]);
  • }
46
Controller
  • MilestoneController = function() {
    • this.index = function(req, res) {
      • res.milestones = Milestone.findAll();
    • }
    • this.show = function(req, res) {
      • res.milestone = Milestone.find(req['objId']);
    • }
    • …
  • }
47
How does WORA work?
  • Write Once Run Anywhere
48
WORA Depends On Layout
  • When running on the server
    • Junction uses layout name just like Rails
  • When running on the client
    • Junction uses the layout name to…
    • O = document.getElementById(layoutName)
    • O.innerHTML = resultOfJSTRender
    • Somewhat like HAJAX
49
Issues
50
Data Scalability
  • DOM page storage limits
  • TrimPath Junction written to support pluggable persistence engines
    • AMASS
    • AFLAX
51
Synchronization
  • Sync issues are hard
  • Solutions
  • Data / record level synchronization
  • Send deltas
  • Change requests, not changes
52
Versioning
  • Ancient schemas
53
Just a few 1000+ lines of code
  • Build your own!
  • Do it better!
54
Future Already Here
  • Exists on Brad Neuberg’s laptop
  • Which is not widely distributed yet
55
Thank You!