!SLIDE
!TITLE Cheap Advice
- Kurt Stephens
- Enova Financial — http://enovafinancial.com
- 2011/11/14
- Slides — http://kurtstephens.com/pub/cheap_advice.slides/index.html
- Code — http://github.com/kstephens/cheap_advice
!SLIDE
!TITLE Clean Code
@
ruby
class MyClass
def foo; 42; end
end
class MyOtherClass
def bar; 43; end
end
a = MyClass.new
b = MyOtherClass.new
a.foo
b.bar
@
!SLIDE
!TITLE Add Logging
@
ruby
class MyClass
def foo
$stderr.puts “#{self}#foo => 42”
42
end
end
class MyOtherClass
def bar
$stderr.puts “#{self}#bar => 43”
43
end
end
a = MyClass.new
b = MyOtherClass.new
a.foo
b.bar
@
!SLIDE
!TITLE Add Security
@
ruby
class MyClass
def foo
raise “SecurityError” unless $roles.include?(“MyClass#foo”)
$stderr.puts “#{self}#foo => 42”
42
end
end
class MyOtherClass
def bar
raise “SecurityError” unless $roles.include?(“MyClass#bar”)
$stderr.puts “#{self}#bar => 43”
43
end
end
a = MyClass.new
b = MyOtherClass.new
$roles = [ “MyClass#foo” ]
a.foo
b.bar
@
!SLIDE
!TITLE YUCK!
@
ruby
class MyClass
def foo
- YUCK!: raise “SecurityError” unless $roles.include?(“MyClass#foo”)
- YUCK!: $stderr.puts “#{self}#foo => 42”
42
end
end
class MyOtherClass
def bar - YUCK!: raise “SecurityError” unless $roles.include?(“MyClass#bar”)
- YUCK!: $stderr.puts “#{self}#bar => 43”
43
end
end
a = MyClass.new
b = MyOtherClass.new
$roles = [ “MyClass#foo” ] # ???
a.foo
b.bar
@
!SLIDE
!TITLE Dumb and Clean, Smart and Dirty
- Real World is Smart Code.
- Dumb Code is Clean, Smart Code is Dirty.
- Get Dirt Out Of Code — (problem-domain vs. solution-domain)
- Sweep It Somewhere Else — (modularize the smart dirt)
- Don’t be Dirty All the Time — (dynamic, stateful dirt: logging, debugging, security, etc.)
!SLIDE
!TITLE Separation of Concerns
- Logging
- Security
… are not problem-domain issues.
!SLIDE
!TITLE Advice
- Commonplace in the Lisp world, (esp. Emacs).
- Advice is function that wraps another function: “before”, “after” or “around”.
- Advice can be added or removed at run-time.
!SLIDE
!TITLE Advice != Aspects
- Aspects are woven into code based on complex “codepoint” criteria at build-time (or load-time).
- Advice is applied to a more well-known constructs: applicable objects: functions, methods, etc.
- Advice are objects.
- Advice can be added and removed at run-time.
!SLIDE
!TITLE Cheap Advice
- … adds dynamic Advice to Ruby methods.
- … is applied to methods.
- … are stateful objects.
- … can be added and removed at run-time.
- … are configurable.
!SLIDE
!TITLE Logging Advice
@
ruby
- Advice
trace_advice = CheapAdvice.new(:around) do | ar, body |
ar.advice[:log] <<
"#{Time.now.iso8601(6)} " <<
“#{ar.rcvr.class} #{ar.meth} #{ar.rcvr.object_id}\n”
body.call
ar.advice[:log] <<
"#{Time.now.iso8601(6)} " <<
"#{ar.rcvr.class} #{ar.meth} #{ar.rcvr.object_id} " <<
“=> #{ar.result.inspect}\n”
end - State attached to trace_advice.
trace_advice[:log] = File.open(“trace.log”, “a+”)
@
!SLIDE
!TITLE Applying Advice
@
ruby
…
- Activate trace_advice:
trace_advice.advise!(MyClass, :foo)
trace_advice.advise!(MyOtherClass, :bar)
a.foo
b.bar
- Disable trace_advice:
trace_advice.disable!
a.foo
b.bar
@
!SLIDE
!TITLE Configuration
@
yaml
:advice:
~:
:enabled: false
:options:
:trace:
:logger:
:name: :default
@
!SLIDE
!TITLE Security Advice
You get the idea.
!SLIDE
!TITLE Example
!SLIDE
!TITLE CheapAdvice
- http://github.com/kstephens/cheap_advice
- gem install cheap_advice