18. I enjoy dealing
with behinds
the scenes
information
Living Behind
the Curtain 6 subjects, less
than 10
minutes on each
of them
Thursday, April 21, 2011
19. DATABASE
APPLICATION
CLIENT
Thursday, April 21, 2011
20. DATABASE
APPLICATION
CLIENT
Thursday, April 21, 2011
21. DATABASE
APPLICATION
CLIENT
Thursday, April 21, 2011
22. DATABASE
APPLICATION
CLIENT
Thursday, April 21, 2011
28. Small projects Large projects have
have few people, too many people so
so it is efficient it becomes
inefficient to
individually consider
all feedback
Tyrannical Leader
Thursday, April 21, 2011
58. Sadness
Web Server
Belt
NoSQL App Code File System
Database
Thursday, April 21, 2011
59. Databases Post contains
know the encoding /
stored encoding spec declares
default
#<Encoding:ASCII-8BIT>
is usually a bug!
Thursday, April 21, 2011
60. # encoding: utf-8
name = ' '
user = User.create!(:name => name)
user.reload
user.name + name
Thursday, April 21, 2011
61. # encoding: utf-8
name = ' '
user = User.create!(:name => name)
user.reload
user.name + name
incompatible character encodings: ASCII-8BIT
and UTF-8 (Encoding::CompatibilityError)
Thursday, April 21, 2011
62. >> name = "Aaron Patterson"
>> name.encoding
=> #<Encoding:UTF-8>
>> User.create!(:name => name)
>> u = User.find :first
>> u.name.encoding
=> #<Encoding:ASCII-8BIT>
Thursday, April 21, 2011
63. >> name = "Aaron Patterson"
>> name.encoding
=> #<Encoding:UTF-8>
>> User.create!(:name => name)
>> u = User.find :first
>> u.name.encoding
=> #<Encoding:ASCII-8BIT>
Thursday, April 21, 2011
64. Ruby attempts
to convert the
binary for you
name = 'aaron patterson'
user = User.create!(:name => name)
user.reload
user.name + name
Thursday, April 21, 2011
65. Ruby attempts
to convert the
binary for you
name = 'aaron patterson'
user = User.create!(:name => name)
user.reload
user.name + name
no error
Thursday, April 21, 2011
86. INSERT INTO "sessions"
("data", "session_id")
VALUES (
'BAh7BjoIZm9vSSIIYmF6BjoGRUY=',
x'3633303337623066376536613130343132343
765623763626631616439303631')
Thursday, April 21, 2011
87. INSERT INTO "sessions"
("data", "session_id")
VALUES (
'BAh7BjoIZm9vSSIIYmF6BjoGRUY=',
x'3633303337623066376536613130343132343
765623763626631616439303631')
Thursday, April 21, 2011
88. Made a sample
program to
reproduce the
db.trace { |sql| puts sql } problem
stmt = db.prepare(
'INSERT INTO "sessions"
(session_id)
VALUES (?)')
stmt.bind_param 1, 'fuu'
stmt.execute
Thursday, April 21, 2011
89. Resulting
Query
INSERT INTO "sessions"
(session_id) VALUES ('fuu')
Thursday, April 21, 2011
92. Why did sqlite3 do
this?
Talk about column
affinity
INSERT INTO "sessions" (session_id)
VALUES (x'667575')
Thursday, April 21, 2011
93. Why is it stored as
Binary?
Thursday, April 21, 2011
94. Why is the session id
tagged binary?
Thursday, April 21, 2011
95. >> x = OpenSSL::Random.random_bytes(10)
=> "Gx93xFCxB2xCExC0xECxBBxA7W"
>> x.encoding
=> #<Encoding:ASCII-8BIT>
Thursday, April 21, 2011
96. >> y = x.unpack('H*')
=> ["4793fcb2cec0ecbba757"]
>> y.first.encoding
=> #<Encoding:ASCII-8BIT>
Thursday, April 21, 2011
97. def generate_sid
ActiveSupport::SecureRandom.hex(16)
end
Thursday, April 21, 2011
98. Should hex have tagged
it?
Should have generate_sid
tagged it?
def generate_sid
sid = ActiveSupport::SecureRandom.hex(16)
if sid.respond_to?(:encode!)
sid.encode!('UTF-8')
end
sid
end
Thursday, April 21, 2011
133. Responds to *
class Select < Struct.new(:columns)
def self.* other
other.select = new(Arel.sql('*'))
other
end
end
Thursday, April 21, 2011
134. Responds to WHERE
class From < Struct.new(:table, :conditions)
def WHERE conditions
self.conditions = conditions
Where.new(self)
end
end
Thursday, April 21, 2011
135. Responds to to_s
class Where < Struct.new(:from, :select)
def to_s
Arel::Table.engine = Arel::Sql::Engine.new(
FakeRecord::Base.new)
table = Arel::Table.new from.table
table.project(select.columns).where(
from.conditions.map { |k,v| table[k].eq v }).to_sql
end
end
Thursday, April 21, 2011
136. Bootstrap Methods
SELECT = Select
def FROM table
From.new table
end
Thursday, April 21, 2011
137. x = SELECT * FROM("users") .WHERE(:id => 10)
puts x
Thursday, April 21, 2011
155. Inside Rack
Calls each,
possibly calls
close
body.each do |chunk|
output(chunk)
end
body.close rescue nil
Thursday, April 21, 2011
156. Sample Application
class MyApp
def call(env)
# some computation
body = 'hello'
# more computation
body << ' world'
[200, { 'X-Hello' => 'World' }, [body]]
end
end
Thursday, April 21, 2011
157. Delay work until each
class FooBody
def each
yield "hello "
sleep(10) # simulate work
yield "world!"
end
end
Thursday, April 21, 2011
158. Database
connections
were lost
Problems ☹
Thursday, April 21, 2011
159. Database
connections are
managed in
middleware
Middleware
Thursday, April 21, 2011
160. "There are two hard problems
in CS: cache invalidation
and naming things"
-- Phil Karlton
Thursday, April 21, 2011
161. class DbCache < Struct.new(:app)
def call(env)
# init cache
status, headers, body = app.call(env)
# clear cache
[status, headers, body]
end
end
Thursday, April 21, 2011
162. class BodyProxy < Struct.new(:delegate)
def each
delegate.each { |x| yield x }
end
def close
delegate.close rescue nil
# clear cache
end
end
Thursday, April 21, 2011
168. Types of Middleware
Generators Rack jams these to
one API.
Filters Approach seems
naive when
examining usage
Lifecycle Handlers
Tied to
callstack
Thursday, April 21, 2011
170. Embrace The
Differences!
Thursday, April 21, 2011
171. Lifecycle Listeners
class Listener
def created(event)
end
def destroyed(event)
end
end
Thursday, April 21, 2011
172. Generators Synchronous or
Asynchronous
class Resource
def service(request, response)
10.times { |i|
response.body.write "hello #{i}"
}
response.body.close
Return value is
end ignored
end
Thursday, April 21, 2011
173. Filters
class Filter
def filter(request, response, chain)
chain.filter(request, response)
end
end
Thursday, April 21, 2011
174. Synchronous
Asynchronous
Freedom from the Callstack
Thread Safety
Thursday, April 21, 2011