Slide 1

Slide 1 text

E-Commerce at UnderArmour __________ Jesse Dailey [email protected] github/jldailey

Slide 2

Slide 2 text

The Caveat This presentation discusses a closed-source application owned by a publicly-traded company, so code snippets are pseudo-code and all dates, statistics, and numbers are only my best personal estimates.

Slide 3

Slide 3 text

What is this talk about? And not about?

Slide 4

Slide 4 text

Goals: for 2011 1. Act quicker, and sell more. ○ Get developers out of the way. 2. Empower authors to control Publishing. ○ Preview ○ Scheduling ○ Rollback 3. Test any thing. ○ Deeply integrated AB Testing.

Slide 5

Slide 5 text

The Plan ● Divide the existing application into three sections: ○ the "runtime", ○ "author time", ○ and the "service" layer. ● What we are showing today ○ The new runtime, a CMS designed for MongoDB. ○ The new author time UI, done in Flex.

Slide 6

Slide 6 text

MongoDB

Slide 7

Slide 7 text

Batches Publishing: ● Preview ● Scheduled Activation ● Rollback Every piece of content is associated with an integer batch number, and batches are scheduled to begin and end at certain times.

Slide 8

Slide 8 text

Batches: how-to Documents in Mongo that are batch-aware have a "batch" attribute, a single integer. To find the document with the highest active version: var doc = collection("pages").find({ ... real criteria first ..., $in: { batch: timeslice } }) .sort({ batch: -1 }) .limit(1); There is a more elegant way to use the timeslice that we will save for later, if someone asks about it in Q&A.

Slide 9

Slide 9 text

Content A tree of objects, stored in BSON documents. Every node in the tree has a "type" attribute. var page = { type: "page", body: "Hello World" }; Each "type" maps to some handler code. reducer["page"] = function(node) { return [ "",node.head, "",node.body, "" ]; } Two-phase rendering.

Slide 10

Slide 10 text

reduce: the first phase. A central recursive function, ● evaluates the handler for each node ● output accumulates output as a (larger, but simpler) tree. This is why the previous example was: return [ "string", object, "string" ]; instead of return "string" + object + "string"; At the end of reduction, it is still "turtles all the way down".

Slide 11

Slide 11 text

finalize: the second phase. Results in a single string. A second recursive function, ● joins simple elements as strings. ● invokes finalize on nodes that survived reduction. Next, an example of a node that survives to be finalized, ● { type: "region" }

Slide 12

Slide 12 text

Regions: out-of-order rendering. A region lets you: ● label a position in the output. ● each label gets a content buffer. ● during reduction, other nodes contribute to these buffers. ● during finalization, the buffer is joined. { type: page, head: ["",{ type:region, name:"css" },""] body: [ "
Hello World
", { type: region, action: "add", name: "css", content: ".demo { color: red; }" } ] }

Slide 13

Slide 13 text

"script" and "style": out-of-order function script(node) { return { type:"region", action:"add", name:"js", content: node.text } }

Slide 14

Slide 14 text

Dependencies: scripts {type: "script", src: "my-jquery-plugin.js", depends: "jquery" } {type: "script", src: "jquery-1.6.min.js", provides: "jquery" } ● reduce builds a dependency tree. ● finalize renders tree to $script (into the "js" region).

Slide 15

Slide 15 text

Dependencies: application logic { type: "anything", require: "tax-calculated" } Here, "tax-calculated" is the name of a Processor. A Processor defines two methods: ● pre() ● post() Each method is called once in any request where it is required.

Slide 16

Slide 16 text

AB Testing ● The code "homepage-test" gets sent to the mPath Learning API from Conductrics. { type: "abtest", code: "homepage-test", items: { A: { ... } B: { ... } } }

Slide 17

Slide 17 text

Programming { type: "data", key: "FOO" } { type: "each", of: [ ... ] as: { ... } } { type: "with", person: { ... } as: [ "Hello ", { type: "data", key: "PERSON.NAME"} ] } { type: "if-data" } { type: "case-data" }, etc...

Slide 18

Slide 18 text

Caching { type: "cached", key: { type: "list-join", items: [ {type:"data", key:"PARENTKEY"}, "my-key-component" ] }, content: { ... } }

Slide 19

Slide 19 text

What makes this powerful? Why bother?

Slide 20

Slide 20 text

5-minute UI video

Slide 21

Slide 21 text

Event Queue w/ Blind Locking Goal: Cluster-wide publish / subscribe event queue. Strategy: ● Capped Collection ○ maintains insertion order cheaply. ○ can't delete, just mark. ● Readers of the Queue must use "Blind Locking"

Slide 22

Slide 22 text

Blind Locking 1. Each document in the capped collection gets: ○ { lock: 'unlocked' } 2. Each Reader is assigned/generated an 8-digit token: ○ 'reader01' 3. To pop an event off the Queue safely under load: ○ Update the first 'unlocked' lock to 'reader01'. ○ Find the first document with 'reader01'.

Slide 23

Slide 23 text

Reading from an Event Queue. 1: db.event.queue.update( 2: { lock: 'unlocked' }, 3: { lock: 'reader01' }); 4: 5: doc = db.event.queue.findOne( 6: { lock: 'reader01' }); 7: 8: if( doc != null ) { 9: doc.status = invokeEventHandlers(doc); 10: doc.lock = 'finished'; 11: db.event.queue.save(doc); 12: }

Slide 24

Slide 24 text

Acknowledgements (aka Wall of Email) UnderArmour, Inc - Dev Team Brian Massey Brian "Magic" Johnston Jeff "Switzerland" Switzer Ken Valencik, Ron Wilson, and others. Twin Technologies, LLC Ben Elmore, CEO Abraham Lloyd, Solutions Exec. Conductrics, LLC Nate Weiss, CTO Jesse Dailey

Slide 25

Slide 25 text

Thank You Three Talks that inspire (and aren't on TED): 1. Bret Victor, "Inventing on Principle": ○ youtu.be/PUv66718DII 2. Jaron Lanier, "Learning by Experience & Play": ○ youtu.be/F9eFZpdSeRU 3. Alan Kay, "Normal considered Harmful": ○ youtu.be/FvmTSpJU-Xc