Upgrade to Pro — share decks privately, control downloads, hide ads and more …

MongoNYC 2012: E-Commerce at UnderArmour, Inc.

D8fc2580cfaca035f666d9e4ee79a7f7?s=47 mongodb
May 29, 2012

MongoNYC 2012: E-Commerce at UnderArmour, Inc.

MongoNYC 2012: E-Commerce at UnderArmour, Inc, Jesse Dailey, Twin Technologies. Using MongoDB at UnderArmour, in 9 months from concept to launch, we built an e-commerce platform that within weeks of launch was handling millions of dollars a day in sales; replacing a huge portion of a large MSSQL+J2EE stack, in what is considered a "home run" by the technical team, the content teams, and management. Here's how we did it using an innovative CMS we built for MongoDB.



May 29, 2012


  1. E-Commerce at UnderArmour __________ Jesse Dailey jesse.dailey@gmail.com github/jldailey

  2. 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.
  3. What is this talk about? And not about?

  4. 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.
  5. 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.
  6. MongoDB

  7. 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.
  8. 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.
  9. 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 [ "<html><head>",node.head, "</head><body>",node.body, "</body></html>" ]; } Two-phase rendering.
  10. 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".
  11. 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" }
  12. 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: ["<style>",{ type:region, name:"css" },"</style>"] body: [ "<div class='demo'>Hello World</div>", { type: region, action: "add", name: "css", content: ".demo { color: red; }" } ] }
  13. "script" and "style": out-of-order function script(node) { return { type:"region",

    action:"add", name:"js", content: node.text } }
  14. 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).
  15. 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.
  16. AB Testing • The code "homepage-test" gets sent to the

    mPath Learning API from Conductrics. { type: "abtest", code: "homepage-test", items: { A: { ... } B: { ... } } }
  17. 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...
  18. Caching { type: "cached", key: { type: "list-join", items: [

    {type:"data", key:"PARENTKEY"}, "my-key-component" ] }, content: { ... } }
  19. What makes this powerful? Why bother?

  20. 5-minute UI video

  21. 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"
  22. 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'.
  23. 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: }
  24. Acknowledgements (aka Wall of Email) UnderArmour, Inc - Dev Team

    Brian Massey <bmassey@underarmour.com> Brian "Magic" Johnston <bjohnston@underarmour.com> Jeff "Switzerland" Switzer <jswitzer@underarmour.com> Ken Valencik, Ron Wilson, and others. Twin Technologies, LLC Ben Elmore, CEO <ben@twintechs.com> Abraham Lloyd, Solutions Exec. <abe@twintechs.com> Conductrics, LLC Nate Weiss, CTO <nate@conductrics.com> Jesse Dailey <jesse@conductrics.com>
  25. 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