Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Building Do on Heroku
Search
Austin Bales
March 15, 2012
Programming
730
7
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Building Do on Heroku
Gopal Patel (@nixme) presents "Building Do on Heroku"
Austin Bales
March 15, 2012
More Decks by Austin Bales
See All by Austin Bales
Design Minded Development
austin
8
540
UI Encapsulation with Handlebars and Sass
austin
5
1.1k
Building Awesome Products at Do.com
austin
2
220
Other Decks in Programming
See All in Programming
R8 の設定見直しでアプリサイズ削減
andpad
0
190
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
1
350
re:Inventに行く前に知っておきたい現地参加のノウハウ
nokomoro3
0
390
AI主導のプログラミング学習アプリを作ってみた
econanringo
0
120
見えないものを探る要求要件定義に必要な基本的思考 / invisible-requirement-thinking
minodriven
15
8k
mrbgem 三角測量 開発
ogom
0
220
WebRTC映像をAirPlayに対応させる挑戦.pdf
monolithic_adam
0
350
Turning Architecture into Unit Tests in the AI Era (NSSpain XIV)
steliosf
PRO
1
130
複雑なUIコンポーネントとの ⻑い付き合い⽅:波及するバグからテスト戦略を経て、安全な再設計へ
mixplace
0
260
[ハンズオン]AIへの指示だけで「五目並べ」を作ってみよう
satoshi256kbyte
1
360
Compiling a real-world CLI tool to native with Static Hermes
tmikov2023
0
100
Agents on Rails - Rails at Scale 2026
irinanazarova
0
350
Featured
See All Featured
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
840
Testing 201, or: Great Expectations
jmmastey
46
8.3k
Designing Experiences People Love
moore
143
24k
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
520
The Invisible Side of Design
smashingmag
301
52k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.8k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
The World Runs on Bad Software
bkeepers
PRO
72
12k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
300
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
Mind Mapping
helmedeiros
1
400
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.6k
Transcript
Building Do on Heroku
Gopal Patel, Director of Engineering
[email protected]
• @nixme github.com/nixme
Social Productivity Everywhere “ ”
None
None
SINGLE PAGE
SINGLE PAGE MOBILE FIRST
SINGLE PAGE MOBILE FIRST MANY CLIENTS
↑ ↓ RUBY Heroku Postgres, New Relic, Logplex… ADD-ONS iOS
Android Desktop Widgets CoffeeScript + Backbone.js WEB APPS NATIVE CLIENTS CUSTOM UI FRAMEWORK
API First BEST PRACTICE
API First BEST PRACTICE
Build Platform API First BEST PRACTICE
Build Platform Separation of concerns. Modularity. API First BEST PRACTICE
Build Platform Separation of concerns. Modularity. Constraints lead to guided
design API First BEST PRACTICE
Build Platform Separation of concerns. Modularity. Constraints lead to guided
design Speak HTTP API First BEST PRACTICE
None
def hello puts 'Hello World!' end hello # => Hello
World
class Note include SoftDelete def initialize(title = 'Untitled') @id =
Sequence.next_id @title = title @body = 'Enter your note...' end def print puts "#{@id}: #{@title} - #{@body}" end end
None
VIEW MODEL CONTROLLER BROWSER ↑ ↓ ↑ ↓ ROUTER ↑
↓ ↑ ↓
JSON MODEL CONTROLLER BROWSER ↑ ↓ ↑ ↓ ROUTER ↑
↓ ↑ ↓
Notes Controller RUBY DEMO
The New Age of JS BIG MOVES
None
$('.name').bind('change', function(event) { $.ajax({ type: "PUT", url: "/names/" + $(event.target).attr('context_id'),
data: { value: $(event.target).attr('data-value') }, success: function(response) { statusIcon = $('.name + .status'); statusIcon.show(); setTimeout(function() { statusIcon.hide(); }, 5000); }, error: function(response) { console.log(response); $('.name').attr('disabled', true); } }); }); $('.name_delete').click(function(event) { event.preventDefault(); id = $(event.target).attr('context_id'); if (confirm('Are you sure?')) { $.ajax({ type: "DELETE", url: "/names/" + id, success: function(response) { $(".row-" + id).remove(); $(".row-" + (id + 1)).focus(); },
None
Backbone.Events binds and triggers
Backbone.Events binds and triggers Backbone.Router front-end routing, pushState
Backbone.Events binds and triggers Backbone.Router front-end routing, pushState Backbone.View controllers
for your UI
Backbone.Events binds and triggers Backbone.Router front-end routing, pushState Backbone.View controllers
for your UI Backbone.Model domain objects
Backbone.Events binds and triggers Backbone.Router front-end routing, pushState Backbone.View controllers
for your UI Backbone.Model domain objects Backbone.Collection model sets
var object = {}; _.extend(object, Backbone.Events); object.on("alert", function(msg) { alert("Triggered
" + msg); }); object.trigger("alert", "an event"); Backbone.Events
var Note = Backbone.Model.extend({ initialize: function() {…}, coordinates: function() {…},
}); var note = new Note({ title: "Today's Dinner", body: … }); note.on("error", function(model, error) {…}); note.save(); Backbone.Model
var DocumentRow = Backbone.View.extend({ tagName: "li", className: "document-row", events: {
"click .icon": "open", "click .button.edit": "openEditDialog", "click .button.delete": "destroy" }, render: function() {…} }); Backbone.View
Do’s Router COFFEESCRIPT DEMO
Ember Knockout Spine
None
None
None
number = 42 flag = true greeting = 'world' var
flag, greeting, number; number = 42; flag = true; greeting = 'world';
square = (x) -> x * x cube = (x)
-> x * square x @customer = new Customer $('.cart').on 'click', (event) => @customer.buy event.target var cube, square, _this = this; square = function(x) { return x * x; }; cube = function(x) { return x * square(x); }; this.customer = new Customer; $('.cart').on('click', function(event) { return _this.customer.buy(event.target); });
kids = brother: name: "Max" age: 11 sister: name: "Ida"
age: 9 var kids; kids = { brother: { name: "Max", age: 11 }, sister: { name: "Ida", age: 9 } };
for own view, element of views $(element).remove() view.removed = true
var element, view, __hasProp = Object.prototype.hasOwnProperty; for (view in views) { if (!__hasProp.call(views, view)) continue; element = views[view]; $(element).remove(); view.removed = true; }
coffeescript.org
coffeescript.org sass-lang.com
None
None
BUNDLE (Sprockets) ↓ MINIFY (UglifyJS) COMPRESSION (GZIP) git push ↓
↓
BUNDLE (Sprockets) ↓ MINIFY (UglifyJS) COMPRESSION (GZIP) git push ↓
↓ ↑ ↓ → CLOUDFRONT ↑ ↓
web: unicorn -p $PORT -c ./config/unicorn.rb worker: rake resque:work QUEUE=notifications,...
workerprovisioning: rake resque:work QUEUE=provisioning,... scheduler: rake resque:scheduler VERBOSE=true Procfile
BACKUPS • FORKING • FOLLOWING
None
CONTINUOUS INTEGRATION AUTOMATED TESTING
CONTINUOUS DEPLOYMENT
CONTINUOUS DEPLOYMENT FEATURE FLAGS if Do.Flags.check ‘recurrence’ # Recurring Tasks
Code
Design HOW WE DO
Design HOW WE DO User Experience is #1
Design HOW WE DO User Experience is #1 Engineering +
Design = Like
Design HOW WE DO User Experience is #1 Engineering +
Design = Like Design is a process / conversation
Design HOW WE DO User Experience is #1 Engineering +
Design = Like Design is a process / conversation We work together. Everyone commits.
WHAT WAS THIS TALK ABOUT? API First Expressive Languages Modern
Browsers Continuous Deployment
WHAT WAS THIS TALK ABOUT? API First Expressive Languages Modern
Browsers Continuous Deployment Loosely-coupled Code Tightly-coupled Team
do.com
THE PANEL Manav Monga Product Guy. @xmanav Bing Yang Product
Guy. @bsbox David Yung Developer. @azethoth Austin Bales Designer. @arbales http://pris.ma/9M