SlideShare a Scribd company logo
Exception Handling:
Designing Robust Software
ihower@gmail.com
2014/9/27@RailsPacific
About me
• 張⽂文鈿 a.k.a. ihower
• http://ihower.tw
• http://twitter.com/ihower
• Instructor at ALPHA Camp
• http://alphacamp.tw
• Rails Developer since 2006
• i.e. Rails 1.1.6 era
Agenda
• Why should we care? (5min)
• Exception handling in Ruby (10min)
• Caveat and Guideline (15min)
• Failure handling strategy (15min)
I’m standing on the two
great books, thanks.
1. Why should we
care?
Feature complete
==
Production ready?
All tests pass?
Happy Path!
Time
Cost Quality
Pick Two?
abstract software
architecture to reduce
development cost
Development cost
!=
Operational cost
– Michael T. Nygard, Release It!
“Don't avoid one-time development
expenses at the cost of recurring
operational expenses.”
My confession
2. Exception handling
in Ruby
– Steve McConnell, Code Complete
“If code in one routine encounters an
unexpected condition that it doesn’t know how
to handle, it throws an exception, essentially
throwing up its hands and yelling “I don’t know
what to do about this — I sure hope somebody
else knows how to handle it!.”
– Devid A. Black, The Well-Grounded Rubyist
“Raising an exception means stopping normal
execution of the program and either dealing with
the problem that’s been encountered or exiting
the program completely.”
1. raise exception
begin	
# do something	
raise 'An error has occured.' 	
rescue => e	
puts 'I am rescued.' 	
puts e.message 	
puts e.backtrace.inspect 	
end
1/5
raise == fail
begin	
# do something	
fail 'An error has occured.' 	
rescue => e	
puts 'I am rescued.' 	
puts e.message 	
puts e.backtrace.inspect 	
end
– Jim Weirich, Rake author
“I almost always use the "fail" keyword. . .
[T]he only time I use “raise” is when I am
catching an exception and re-raising it,
because here I’m not failing, but explicitly
and purposefully raising an exception.”
“raise” method signature
!
raise(exception_class_or_object, 	
message, 	
backtrace)
raise
raise	
!
# is equivalent to:	
!
raise RuntimeError
raise(string)
raise 'An error has occured.'	
!
# is equivalent to :	
!
raise RuntimeError, "'An error has occured.'
raise(exception, string)
raise RuntimeError, 'An error has occured.'	
!
# is equivalent to :	
!
raise RuntimeError.new('An error has occured.')
backtrace
(Array of string)
raise RuntimeError, 'An error'	
!
# is equivalent to :	
!
raise RuntimeError, 'An error', caller(0)
global $! variable
!
• $!
• $ERROR_INFO
• reset to nil if the exception is rescued
2. rescue
rescue SomeError => e	
# ...	
end
2/5
rescue SomeError, SomeOtherError => e	
# ...	
end
Multiple class or module
rescue SomeError => e	
# ...	
rescue SomeOtherError => e	
# ...	
end
stacking rescue
order matters
rescue	
# ...	
end	
!
# is equivalent to:	
!
rescue StandardError	
# ...	
end
Ruby Exception Hierarchy
• Exception
• NoMemoryError
• LoadError
• SyntaxError
• StandardError -- default for rescue
• ArgumentError
• IOError
• NoMethodError
• ….
Avoid rescuing Exception
class
rescue Exception => e	
# ...	
end
rescue => error	
# ...	
end	
	
# is equivalent to:	
!
rescue StandardError => error	
# ...	
end
support * splatted
active_support/core_ext/kernel/reporting.rb
suppress(IOError, SystemCallError) do	
open("NONEXISTENT_FILE")	
end	
!
puts 'This code gets executed.'
!
def suppress(*exception_classes)	
yield	
rescue *exception_classes	
# nothing to do	
end
support * splatted (cont.)
active_support/core_ext/kernel/reporting.rb
Like case, it’s support ===
begin	
raise "Timeout while reading from socket"	
rescue errors_with_message(/socket/)	
puts "Ignoring socket error"	
end
def errors_with_message(pattern)	
m = Module.new	
m.singleton_class.instance_eval do	
define_method(:===) do |e|	
pattern === e.message	
end	
end	
m	
end
arbitrary block predicate
begin	
raise "Timeout while reading from socket"	
rescue errors_matching{|e| e.message =~ /socket/}	
puts "Ignoring socket error"	
end
def errors_matching(&block)	
m = Module.new	
m.singleton_class.instance_eval do	
define_method(:===, &block)	
end	
m	
end
– Bertrand Meyer, Object Oriented Software Construction
“In practice, the rescue clause should be a
short sequence of simple instructions designed
to bring the object back to a stable state and to
either retry the operation or terminate with
failure.”
3. ensure
begin	
# do something	
raise 'An error has occured.' 	
rescue => e	
puts 'I am rescued.' 	
ensure	
puts 'This code gets executed always.'	
end
3/5
4. retry
be careful “giving up” condition
tries = 0	
begin	
tries += 1	
puts "Trying #{tries}..."	
raise "Didn't work"	
rescue	
retry if tries < 3	
puts "I give up"	
end
4/5
5. else
begin	
yield	
rescue	
puts "Only on error"	
else	
puts "Only on success"	
ensure	
puts "Always executed"	
end
5/5
Recap
• raise
• rescue
• ensure
• retry
• else
3. Caveat and Guideline
1. Is the situation truly
unexpected?
1/6
– Dave Thomas and Andy Hunt, The Pragmatic Programmer
“ask yourself, 'Will this code still run if I
remove all the exception handlers?" If the
answer is "no", then maybe exceptions are
being used in non-exceptional
circumstances.”
User Input error?
def create	
@user = User.new params[:user]	
@user.save!	
redirect_to user_path(@user)	
rescue ActiveRecord::RecordNotSaved	
flash[:notice] = 'Unable to create user'	
render :action => :new	
end
This is bad
def create	
@user = User.new params[:user]	
if @user.save	
redirect_to user_path(@user)	
else	
flash[:notice] = 'Unable to create user'	
render :action => :new	
end	
end
Record not found?
begin	
user = User.find(params[:id)	
user.do_this	
rescue ActiveRecord::RecordNotFound	
# ???	
end
This is bad
Use Null object
user = User.find_by_id(params[:id) || NullUser.new	
user.do_this
Replace Exception with Test
def execute(command)	
command.prepare rescue nil	
command.execute	
end	
!
# =>	
!
def execute(command)	
command.prepare if command.respond_to? :prepare	
command.execute	
end
– Martin Folwer, Refactoring
“Exceptions should be used for exceptional
behaviour. They should not acts as substitute
for conditional tests. If you can reasonably
expect the caller to check the condition before
calling the operation, you should provide a test,
and the caller should use it.”
Spare Handler?
begin	
# main implementation	
rescue	
# alternative solution	
end
begin	
user = User.find(params[:id)	
rescue ActiveRecord::RecordNotFound	
user = NullUser.new	
ensure	
user.do_this	
end
This is bad
user = User.find_by_id(params[:id) || 	
NullUser.new	
!
user.do_this
2. raise during raise
begin	
raise "Error A" # this will be thrown	
rescue	
raise "Error B"	
end
2/6
Wrapped exception
!
begin	
begin	
raise "Error A"	
rescue => error	
raise MyError, "Error B"	
end	
rescue => e	
puts "Current failure: #{e.inspect}"	
puts "Original failure: #{e.original.inspect}"	
end
Wrapped exception (cont.)
class MyError < StandardError	
attr_reader :original	
def initialize(msg, original=$!)	
super(msg)	
@original = original;	
set_backtrace original.backtrace 	
end	
end
Example: Rails uses the
technique a lot
• ActionDispatch::ExceptionWrapper
• ActionControllerError::BadRequest,
ParseError,SessionRestoreError
• ActionView Template::Error
3. raise during ensure
begin	
raise "Error A"	
ensure	
raise "Error B”	
puts "Never execute"	
end
3/6
begin	
file1.open	
file2.open	
raise "Error"	
ensure	
file1.close # if there's an error	
file2.close	
end
a more complex example
begin	
r1 = Resource.new(1)	
r2 = Resource.new(2)	
	
r2.run	
r1.run 	
rescue => e	
raise "run error: #{e.message}"	
ensure	
r2.close	
r1.close 	
end
class Resource	
attr_accessor :id	
!
def initialize(id)	
self.id = id	
end	
!
def run	
puts "run #{self.id}"	
raise "run error: #{self.id}"	
end	
!
def close	
puts "close #{self.id}"	
raise "close error: #{self.id}"	
end	
end
begin	
r1 = Resource.new(1)	
r2 = Resource.new(2)	
	
r2.run 	
r1.run # raise exception!!! 	
rescue => e	
raise "run error: #{e.message}"	
ensure	
r2.close # raise exception!!! 	
r1.close # never execute! 	
end
Result
lost original r1 exception and fail to close r2
run 1
run 2
close 1
double_raise.rb:15:in `close': close error: 1 (RuntimeError)
4. Exception is your method
interface too
• For library, either you document your exception, or
you should consider no-raise library API
• return values (error code)
• provide fallback callback
4/6
5. Exception classification
module MyLibrary	
class Error < StandardError	
end	
end
5/6
exception hierarchy
example
• StandardError
• ActionControllerError
• BadRequest
• RoutingError
• ActionController::UrlGenerationError
• MethodNotAllowed
• NotImplemented
• …
smart exception
adding more information
class MyError < StandardError	
attr_accessor :code	
!
def initialize(code)	
self.code = code	
end	
end	
!
begin	
raise MyError.new(1)	
rescue => e	
puts "Error code: #{e.code}"	
end
6. Readable exceptional
code
begin	
try_something	
rescue	
begin	
try_something_else	
rescue	
# ...	
end	
end	
end
6/6
Extract it!
def foo	
try_something	
rescue	
bar	
end	
!
def bar	
try_something_else	
# ...	
rescue	
# ...	
end
Recap
• Use exception when you need
• Wrap exception when re-raising
• Avoid raising during ensure
• Exception is your method interface too
• Classify your exceptions
• Readable exceptional code
4. Failure handling
strategy
1. Exception Safety
• no guarantee
• The weak guarantee (no-leak): If an exception is raised,
the object will be left in a consistent state.
• The strong guarantee (a.k.a. commit-or-rollback, all-or-
nothing): If an exception is raised, the object will be rolled
back to its beginning state.
• The nothrow guarantee (failure transparency): No
exceptions will be raised from the method. If an exception
is raised during the execution of the method it will be
handled internally.
1/12
2. Operational errors
v.s.
programmer errors
https://www.joyent.com/developers/node/design/errors 2/12
Operational errors
• failed to connect to server
• failed to resolve hostname
• request timeout
• server returned a 500 response
• socket hang-up
• system is out of memory
Programmer errors
like typo
We can handle operational
errors
• Restore and Cleanup Resource
• Handle it directly
• Propagate
• Retry
• Crash
• Log it
But we can not handle
programmer errors
3. Robust levels
• Robustness: the ability of a system to resist change
without adapting its initial stable configuration.
• There’re four robust levels
http://en.wikipedia.org/wiki/Robustness 3/12
Level 0: Undefined
• Service: Failing implicitly or explicitly
• State: Unknown or incorrect
• Lifetime: Terminated or continued
Level 1: Error-reporting
(Failing fast)
• Service: Failing explicitly
• State: Unknown or incorrect
• Lifetime: Terminated or continued
• How-achieved:
• Propagating all unhandled exceptions, and
• Catching and reporting them in the main program
Anti-pattern:

Dummy handler (eating exceptions)
begin	
#...	
rescue => e	
nil	
end
Level 2: State-recovery
(weakly tolerant)
• Service: Failing explicitly
• State: Correct
• Lifetime: Continued
• How-achieved:
• Backward recovery
• Cleanup
require 'open-uri'	
page = "titles"	
file_name = "#{page}.html"	
web_page = open("https://pragprog.com/#{page}")	
output = File.open(file_name, "w")	
begin	
while line = web_page.gets	
output.puts line	
end	
output.close	
rescue => e	
STDERR.puts "Failed to download #{page}"	
output.close	
File.delete(file_name)	
raise	
end
Level 3: Behavior-recovery
(strongly tolerant)
• Service: Delivered
• State: Correct
• Lifetime: Continued
• How-achieved:
• retry, and/or
• design diversity, data diversity, and functional
diversity
Improve exception handling
incrementally
• Level 0 is bad
• it’s better we require all method has Level 1
• Level 2 for critical operation. e.g storage/database
operation
• Level 3 for critical feature or customer requires. it
means cost * 2 because we must have two solution
everywhere.
4. Use timeout
for any external call
begin	
Timeout::timeout(3) do	
#...	
end	
rescue Timeout::Error => e	
# ...	
end
4/12
5. retry with circuit breaker
http://martinfowler.com/bliki/CircuitBreaker.html 5/12
6. bulkheads
for external service and process
begin	
SomeExternalService.do_request	
rescue Exception => e	
logger.error "Error from External Service"	
logger.error e.message	
logger.error e.backtrace.join("n")	
end
6/12
!
7. Failure reporting
• A central log server
• Email
• exception_notification gem
• 3-party exception-reporting service
• Airbrake, Sentry New Relic…etc
7/12
8. Exception collection
class Item	
def process	
#...	
[true, result]	
rescue => e	
[false, result]	
end 	
end	
!
collections.each do |item|	
results << item.process	
end
8/12
9. caller-supplied fallback
strategy
h.fetch(:optional){ "default value" }	
h.fetch(:required){ raise "Required not found" }	
!
arr.fetch(999){ "default value" }	
arr.detect( lambda{ "default value" }) { |x| 	
x == "target" }
9/12
– Brian Kernighan and Rob Pike, The Practice of Programming
“In most cases, the caller should determine
how to handle an error, not the callee.”
def do_something(failure_policy=method(:raise))	
#...	
rescue => e	
failure_policy.call(e) 	
end	
!
do_something{ |e| puts e.message }
10. Avoid unexpected
termination
• rescue all exceptions at the outermost call stacks.
• Rails does a great job here
• developer will see all exceptions at development
mode.
• end user will not see exceptions at production
mode
10/12
11. Error code v.s. exception
• error code problems
• it mixes normal code and exception handling
• programmer can ignore error code easily
11/12
Error code problem
prepare_something # return error code	
trigger_someaction # still run
http://yosefk.com/blog/error-codes-vs-exceptions-critical-code-vs-typical-code.html
Replace Error Code with
Exception (from Refactoring)
def withdraw(amount)	
return -1 if amount > @balance	
@balance -= amount	
0	
end	
!
# =>	
!
def withdraw(amount)	
raise BalanceError.new if amount > @balance	
@balance -= amount	
end
Why does Go not have
exceptions?
• We believe that coupling exceptions to a control
structure, as in the try-catch-finally idiom, results in
convoluted code. It also tends to encourage
programmers to label too many ordinary errors, such as
failing to open a file, as exceptional. Go takes a different
approach. For plain error handling, Go's multi-value
returns make it easy to report an error without
overloading the return value. A canonical error type,
coupled with Go's other features, makes error handling
pleasant but quite different from that in other languages.
https://golang.org/doc/faq#exceptions
– Raymond Chen
“It's really hard to write good exception-based
code since you have to check every single line
of code (indeed, every sub-expression) and
think about what exceptions it might raise and
how your code will react to it.”
http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx
When use error code?
!
• In low-level code which you must know the
behavior in every possible situation
• error codes may be better
• Otherwise we have to know every exception that
can be thrown by every line in the method to
know what it will do
http://stackoverflow.com/questions/253314/exceptions-or-error-codes
12. throw/catch flow
def halt(*response)	
#....	
throw :halt, response	
end	
	
def invoke	
res = catch(:halt) { yield }	
#...	
end
12/12
Recap
!
• exception safety
• operational errors v.s. programmer errors
• robust levels
Recap (cont.)
• use timeout
• retry with circuit breaker pattern
• bulkheads
• failure reporting
• exception collection
• caller-supplied fallback strategy
• avoid unexpected termination
• error code
• throw/catch
Thanks for your
listening
QUESTIONS!
begin	
thanks!	
raise if question?	
rescue	
puts "Please ask @ihower at twitter"	
ensure	
follow(@ihower).get_slides	
applause!	
end
Reference
• 例外處理設計的逆襲
• Exceptional Ruby http://avdi.org/talks/exceptional-ruby-2011-02-04/
• Release it!
• Programming Ruby
• The Well-Grounded Rubyist, 2nd
• Refactoring
• The Pragmatic Programmer
• Code Complete 2
• https://www.joyent.com/developers/node/design/errors
• http://robots.thoughtbot.com/save-bang-your-head-active-record-will-drive-you-mad
• http://code.tutsplus.com/articles/writing-robust-web-applications-the-lost-art-of-exception-handling--net-36395
• http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx

More Related Content

What's hot

Test Driven Development With YUI Test (Ajax Experience 2008)
Test Driven Development With YUI Test (Ajax Experience 2008)Test Driven Development With YUI Test (Ajax Experience 2008)
Test Driven Development With YUI Test (Ajax Experience 2008)
Nicholas Zakas
 
Angular Unit Testing
Angular Unit TestingAngular Unit Testing
Angular Unit Testing
Alessandro Giorgetti
 
Unit testing of java script and angularjs application using Karma Jasmine Fra...
Unit testing of java script and angularjs application using Karma Jasmine Fra...Unit testing of java script and angularjs application using Karma Jasmine Fra...
Unit testing of java script and angularjs application using Karma Jasmine Fra...
Samyak Bhalerao
 
Testing untestable code - phpday
Testing untestable code - phpdayTesting untestable code - phpday
Testing untestable code - phpdayStephan Hochdörfer
 
Test in action – week 1
Test in action – week 1Test in action – week 1
Test in action – week 1Yi-Huan Chan
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Code
scidept
 
Test in action week 4
Test in action   week 4Test in action   week 4
Test in action week 4Yi-Huan Chan
 
Automated Testing in Django
Automated Testing in DjangoAutomated Testing in Django
Automated Testing in Django
Loek van Gent
 
JAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
JAVASCRIPT TDD(Test driven Development) & Qunit TutorialJAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
JAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
Anup Singh
 
The Art of Unit Testing - Towards a Testable Design
The Art of Unit Testing - Towards a Testable DesignThe Art of Unit Testing - Towards a Testable Design
The Art of Unit Testing - Towards a Testable Design
Victor Rentea
 
Painless JavaScript Testing with Jest
Painless JavaScript Testing with JestPainless JavaScript Testing with Jest
Painless JavaScript Testing with Jest
Michał Pierzchała
 
Unit-testing and E2E testing in JS
Unit-testing and E2E testing in JSUnit-testing and E2E testing in JS
Unit-testing and E2E testing in JS
Michael Haberman
 
Moving away from legacy code with BDD
Moving away from legacy code with BDDMoving away from legacy code with BDD
Moving away from legacy code with BDD
Konstantin Kudryashov
 
Angular Intermediate
Angular IntermediateAngular Intermediate
Angular Intermediate
LinkMe Srl
 
Intro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJSIntro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJS
Jim Lynch
 
JavaScript - From Birth To Closure
JavaScript - From Birth To ClosureJavaScript - From Birth To Closure
JavaScript - From Birth To Closure
Robert Nyman
 
Testing in Django
Testing in DjangoTesting in Django
Testing in Django
Kevin Harvey
 
Google mock for dummies
Google mock for dummiesGoogle mock for dummies
Google mock for dummies
Harry Potter
 

What's hot (20)

Test Driven Development With YUI Test (Ajax Experience 2008)
Test Driven Development With YUI Test (Ajax Experience 2008)Test Driven Development With YUI Test (Ajax Experience 2008)
Test Driven Development With YUI Test (Ajax Experience 2008)
 
Angular Unit Testing
Angular Unit TestingAngular Unit Testing
Angular Unit Testing
 
Unit testing of java script and angularjs application using Karma Jasmine Fra...
Unit testing of java script and angularjs application using Karma Jasmine Fra...Unit testing of java script and angularjs application using Karma Jasmine Fra...
Unit testing of java script and angularjs application using Karma Jasmine Fra...
 
Testing untestable code - phpday
Testing untestable code - phpdayTesting untestable code - phpday
Testing untestable code - phpday
 
From dot net_to_rails
From dot net_to_railsFrom dot net_to_rails
From dot net_to_rails
 
Test in action – week 1
Test in action – week 1Test in action – week 1
Test in action – week 1
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Code
 
Test in action week 4
Test in action   week 4Test in action   week 4
Test in action week 4
 
Automated Testing in Django
Automated Testing in DjangoAutomated Testing in Django
Automated Testing in Django
 
JAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
JAVASCRIPT TDD(Test driven Development) & Qunit TutorialJAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
JAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
 
slingmodels
slingmodelsslingmodels
slingmodels
 
The Art of Unit Testing - Towards a Testable Design
The Art of Unit Testing - Towards a Testable DesignThe Art of Unit Testing - Towards a Testable Design
The Art of Unit Testing - Towards a Testable Design
 
Painless JavaScript Testing with Jest
Painless JavaScript Testing with JestPainless JavaScript Testing with Jest
Painless JavaScript Testing with Jest
 
Unit-testing and E2E testing in JS
Unit-testing and E2E testing in JSUnit-testing and E2E testing in JS
Unit-testing and E2E testing in JS
 
Moving away from legacy code with BDD
Moving away from legacy code with BDDMoving away from legacy code with BDD
Moving away from legacy code with BDD
 
Angular Intermediate
Angular IntermediateAngular Intermediate
Angular Intermediate
 
Intro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJSIntro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJS
 
JavaScript - From Birth To Closure
JavaScript - From Birth To ClosureJavaScript - From Birth To Closure
JavaScript - From Birth To Closure
 
Testing in Django
Testing in DjangoTesting in Django
Testing in Django
 
Google mock for dummies
Google mock for dummiesGoogle mock for dummies
Google mock for dummies
 

Similar to Exception Handling: Designing Robust Software in Ruby

Ruby Intro {spection}
Ruby Intro {spection}Ruby Intro {spection}
Ruby Intro {spection}
Christian KAKESA
 
Ruby & Rails Error Handling
Ruby & Rails Error HandlingRuby & Rails Error Handling
Ruby & Rails Error Handling
Simon Maynard
 
Object Oriented PHP - PART-2
Object Oriented PHP - PART-2Object Oriented PHP - PART-2
Object Oriented PHP - PART-2
Jalpesh Vasa
 
exception-handling-in-java.ppt unit 2
exception-handling-in-java.ppt unit 2exception-handling-in-java.ppt unit 2
exception-handling-in-java.ppt unit 2
thenmozhip8
 
Test First Teaching
Test First TeachingTest First Teaching
Test First Teaching
Sarah Allen
 
ruby on rails pitfalls
ruby on rails pitfallsruby on rails pitfalls
ruby on rails pitfalls
Robbin Fan
 
Ruby Topic Maps Tutorial (2007-10-10)
Ruby Topic Maps Tutorial (2007-10-10)Ruby Topic Maps Tutorial (2007-10-10)
Ruby Topic Maps Tutorial (2007-10-10)
Benjamin Bock
 
Continuous Integration For Rails Project
Continuous Integration For Rails ProjectContinuous Integration For Rails Project
Continuous Integration For Rails Project
Louie Zhao
 
Speed geeking-lotusscript
Speed geeking-lotusscriptSpeed geeking-lotusscript
Speed geeking-lotusscriptBill Buchan
 
Gtg12
Gtg12Gtg12
Gtg12
Poga Po
 
Ruby On Rails Pitfalls
Ruby On Rails PitfallsRuby On Rails Pitfalls
Ruby On Rails Pitfalls
Robin Lu
 
Ruby for C# Developers
Ruby for C# DevelopersRuby for C# Developers
Ruby for C# Developers
Cory Foy
 
20141210 rakuten techtalk
20141210 rakuten techtalk20141210 rakuten techtalk
20141210 rakuten techtalk
Hiroshi SHIBATA
 
exceptionvdffhhhccvvvv-handling-in-java.ppt
exceptionvdffhhhccvvvv-handling-in-java.pptexceptionvdffhhhccvvvv-handling-in-java.ppt
exceptionvdffhhhccvvvv-handling-in-java.ppt
yjrtytyuu
 
The PHP Way Of TDD - Think First, Code Later
The PHP Way Of TDD - Think First, Code LaterThe PHP Way Of TDD - Think First, Code Later
The PHP Way Of TDD - Think First, Code Later
Hiraq Citra M
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everything
noelrap
 
Monkeybars in the Manor
Monkeybars in the ManorMonkeybars in the Manor
Monkeybars in the Manor
martinbtt
 
VodQA_Parallelizingcukes_AmanKing
VodQA_Parallelizingcukes_AmanKingVodQA_Parallelizingcukes_AmanKing
VodQA_Parallelizingcukes_AmanKing
vodQA
 

Similar to Exception Handling: Designing Robust Software in Ruby (20)

Ruby Intro {spection}
Ruby Intro {spection}Ruby Intro {spection}
Ruby Intro {spection}
 
Introduction to php exception and error management
Introduction to php  exception and error managementIntroduction to php  exception and error management
Introduction to php exception and error management
 
Ruby & Rails Error Handling
Ruby & Rails Error HandlingRuby & Rails Error Handling
Ruby & Rails Error Handling
 
Object Oriented PHP - PART-2
Object Oriented PHP - PART-2Object Oriented PHP - PART-2
Object Oriented PHP - PART-2
 
exception-handling-in-java.ppt unit 2
exception-handling-in-java.ppt unit 2exception-handling-in-java.ppt unit 2
exception-handling-in-java.ppt unit 2
 
Test First Teaching
Test First TeachingTest First Teaching
Test First Teaching
 
ruby on rails pitfalls
ruby on rails pitfallsruby on rails pitfalls
ruby on rails pitfalls
 
Ruby Topic Maps Tutorial (2007-10-10)
Ruby Topic Maps Tutorial (2007-10-10)Ruby Topic Maps Tutorial (2007-10-10)
Ruby Topic Maps Tutorial (2007-10-10)
 
Continuous Integration For Rails Project
Continuous Integration For Rails ProjectContinuous Integration For Rails Project
Continuous Integration For Rails Project
 
Speed geeking-lotusscript
Speed geeking-lotusscriptSpeed geeking-lotusscript
Speed geeking-lotusscript
 
Gtg12
Gtg12Gtg12
Gtg12
 
Ruby On Rails Pitfalls
Ruby On Rails PitfallsRuby On Rails Pitfalls
Ruby On Rails Pitfalls
 
Ruby for C# Developers
Ruby for C# DevelopersRuby for C# Developers
Ruby for C# Developers
 
The Joy Of Ruby
The Joy Of RubyThe Joy Of Ruby
The Joy Of Ruby
 
20141210 rakuten techtalk
20141210 rakuten techtalk20141210 rakuten techtalk
20141210 rakuten techtalk
 
exceptionvdffhhhccvvvv-handling-in-java.ppt
exceptionvdffhhhccvvvv-handling-in-java.pptexceptionvdffhhhccvvvv-handling-in-java.ppt
exceptionvdffhhhccvvvv-handling-in-java.ppt
 
The PHP Way Of TDD - Think First, Code Later
The PHP Way Of TDD - Think First, Code LaterThe PHP Way Of TDD - Think First, Code Later
The PHP Way Of TDD - Think First, Code Later
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everything
 
Monkeybars in the Manor
Monkeybars in the ManorMonkeybars in the Manor
Monkeybars in the Manor
 
VodQA_Parallelizingcukes_AmanKing
VodQA_Parallelizingcukes_AmanKingVodQA_Parallelizingcukes_AmanKing
VodQA_Parallelizingcukes_AmanKing
 

More from Wen-Tien Chang

⼤語⾔模型 LLM 應⽤開發入⾨
⼤語⾔模型 LLM 應⽤開發入⾨⼤語⾔模型 LLM 應⽤開發入⾨
⼤語⾔模型 LLM 應⽤開發入⾨
Wen-Tien Chang
 
Ruby Rails 老司機帶飛
Ruby Rails 老司機帶飛Ruby Rails 老司機帶飛
Ruby Rails 老司機帶飛
Wen-Tien Chang
 
A brief introduction to Machine Learning
A brief introduction to Machine LearningA brief introduction to Machine Learning
A brief introduction to Machine Learning
Wen-Tien Chang
 
淺談 Startup 公司的軟體開發流程 v2
淺談 Startup 公司的軟體開發流程 v2淺談 Startup 公司的軟體開發流程 v2
淺談 Startup 公司的軟體開發流程 v2
Wen-Tien Chang
 
RSpec on Rails Tutorial
RSpec on Rails TutorialRSpec on Rails Tutorial
RSpec on Rails Tutorial
Wen-Tien Chang
 
RSpec & TDD Tutorial
RSpec & TDD TutorialRSpec & TDD Tutorial
RSpec & TDD Tutorial
Wen-Tien Chang
 
ALPHAhackathon: How to collaborate
ALPHAhackathon: How to collaborateALPHAhackathon: How to collaborate
ALPHAhackathon: How to collaborate
Wen-Tien Chang
 
Git 版本控制系統 -- 從微觀到宏觀
Git 版本控制系統 -- 從微觀到宏觀Git 版本控制系統 -- 從微觀到宏觀
Git 版本控制系統 -- 從微觀到宏觀Wen-Tien Chang
 
從 Classes 到 Objects: 那些 OOP 教我的事
從 Classes 到 Objects: 那些 OOP 教我的事從 Classes 到 Objects: 那些 OOP 教我的事
從 Classes 到 Objects: 那些 OOP 教我的事Wen-Tien Chang
 
Yet another introduction to Git - from the bottom up
Yet another introduction to Git - from the bottom upYet another introduction to Git - from the bottom up
Yet another introduction to Git - from the bottom upWen-Tien Chang
 
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩Wen-Tien Chang
 
Ruby 程式語言綜覽簡介
Ruby 程式語言綜覽簡介Ruby 程式語言綜覽簡介
Ruby 程式語言綜覽簡介Wen-Tien Chang
 
A brief introduction to SPDY - 邁向 HTTP/2.0
A brief introduction to SPDY - 邁向 HTTP/2.0A brief introduction to SPDY - 邁向 HTTP/2.0
A brief introduction to SPDY - 邁向 HTTP/2.0
Wen-Tien Chang
 
RubyConf Taiwan 2012 Opening & Closing
RubyConf Taiwan 2012 Opening & ClosingRubyConf Taiwan 2012 Opening & Closing
RubyConf Taiwan 2012 Opening & Closing
Wen-Tien Chang
 
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean StartupWen-Tien Chang
 
那些 Functional Programming 教我的事
那些 Functional Programming 教我的事那些 Functional Programming 教我的事
那些 Functional Programming 教我的事
Wen-Tien Chang
 
RubyConf Taiwan 2011 Opening & Closing
RubyConf Taiwan 2011 Opening & ClosingRubyConf Taiwan 2011 Opening & Closing
RubyConf Taiwan 2011 Opening & ClosingWen-Tien Chang
 
RSpec 讓你愛上寫測試
RSpec 讓你愛上寫測試RSpec 讓你愛上寫測試
RSpec 讓你愛上寫測試
Wen-Tien Chang
 

More from Wen-Tien Chang (20)

⼤語⾔模型 LLM 應⽤開發入⾨
⼤語⾔模型 LLM 應⽤開發入⾨⼤語⾔模型 LLM 應⽤開發入⾨
⼤語⾔模型 LLM 應⽤開發入⾨
 
Ruby Rails 老司機帶飛
Ruby Rails 老司機帶飛Ruby Rails 老司機帶飛
Ruby Rails 老司機帶飛
 
A brief introduction to Machine Learning
A brief introduction to Machine LearningA brief introduction to Machine Learning
A brief introduction to Machine Learning
 
淺談 Startup 公司的軟體開發流程 v2
淺談 Startup 公司的軟體開發流程 v2淺談 Startup 公司的軟體開發流程 v2
淺談 Startup 公司的軟體開發流程 v2
 
RSpec on Rails Tutorial
RSpec on Rails TutorialRSpec on Rails Tutorial
RSpec on Rails Tutorial
 
RSpec & TDD Tutorial
RSpec & TDD TutorialRSpec & TDD Tutorial
RSpec & TDD Tutorial
 
ALPHAhackathon: How to collaborate
ALPHAhackathon: How to collaborateALPHAhackathon: How to collaborate
ALPHAhackathon: How to collaborate
 
Git 版本控制系統 -- 從微觀到宏觀
Git 版本控制系統 -- 從微觀到宏觀Git 版本控制系統 -- 從微觀到宏觀
Git 版本控制系統 -- 從微觀到宏觀
 
從 Classes 到 Objects: 那些 OOP 教我的事
從 Classes 到 Objects: 那些 OOP 教我的事從 Classes 到 Objects: 那些 OOP 教我的事
從 Classes 到 Objects: 那些 OOP 教我的事
 
Yet another introduction to Git - from the bottom up
Yet another introduction to Git - from the bottom upYet another introduction to Git - from the bottom up
Yet another introduction to Git - from the bottom up
 
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
 
Ruby 程式語言綜覽簡介
Ruby 程式語言綜覽簡介Ruby 程式語言綜覽簡介
Ruby 程式語言綜覽簡介
 
A brief introduction to SPDY - 邁向 HTTP/2.0
A brief introduction to SPDY - 邁向 HTTP/2.0A brief introduction to SPDY - 邁向 HTTP/2.0
A brief introduction to SPDY - 邁向 HTTP/2.0
 
RubyConf Taiwan 2012 Opening & Closing
RubyConf Taiwan 2012 Opening & ClosingRubyConf Taiwan 2012 Opening & Closing
RubyConf Taiwan 2012 Opening & Closing
 
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup
 
Git Tutorial 教學
Git Tutorial 教學Git Tutorial 教學
Git Tutorial 教學
 
那些 Functional Programming 教我的事
那些 Functional Programming 教我的事那些 Functional Programming 教我的事
那些 Functional Programming 教我的事
 
RubyConf Taiwan 2011 Opening & Closing
RubyConf Taiwan 2011 Opening & ClosingRubyConf Taiwan 2011 Opening & Closing
RubyConf Taiwan 2011 Opening & Closing
 
RSpec 讓你愛上寫測試
RSpec 讓你愛上寫測試RSpec 讓你愛上寫測試
RSpec 讓你愛上寫測試
 
Git and Github
Git and GithubGit and Github
Git and Github
 

Recently uploaded

Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
Product School
 
Generating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using SmithyGenerating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using Smithy
g2nightmarescribd
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
Elena Simperl
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
Product School
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Albert Hoitingh
 
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Product School
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
DianaGray10
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
KatiaHIMEUR1
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Inflectra
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
Paul Groth
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Tobias Schneck
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 

Recently uploaded (20)

Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
Generating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using SmithyGenerating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using Smithy
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
 
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 

Exception Handling: Designing Robust Software in Ruby

  • 1. Exception Handling: Designing Robust Software ihower@gmail.com 2014/9/27@RailsPacific
  • 2. About me • 張⽂文鈿 a.k.a. ihower • http://ihower.tw • http://twitter.com/ihower • Instructor at ALPHA Camp • http://alphacamp.tw • Rails Developer since 2006 • i.e. Rails 1.1.6 era
  • 3. Agenda • Why should we care? (5min) • Exception handling in Ruby (10min) • Caveat and Guideline (15min) • Failure handling strategy (15min)
  • 4. I’m standing on the two great books, thanks.
  • 5. 1. Why should we care?
  • 9.
  • 11. abstract software architecture to reduce development cost
  • 13. – Michael T. Nygard, Release It! “Don't avoid one-time development expenses at the cost of recurring operational expenses.”
  • 16. – Steve McConnell, Code Complete “If code in one routine encounters an unexpected condition that it doesn’t know how to handle, it throws an exception, essentially throwing up its hands and yelling “I don’t know what to do about this — I sure hope somebody else knows how to handle it!.”
  • 17. – Devid A. Black, The Well-Grounded Rubyist “Raising an exception means stopping normal execution of the program and either dealing with the problem that’s been encountered or exiting the program completely.”
  • 18. 1. raise exception begin # do something raise 'An error has occured.' rescue => e puts 'I am rescued.' puts e.message puts e.backtrace.inspect end 1/5
  • 19. raise == fail begin # do something fail 'An error has occured.' rescue => e puts 'I am rescued.' puts e.message puts e.backtrace.inspect end
  • 20. – Jim Weirich, Rake author “I almost always use the "fail" keyword. . . [T]he only time I use “raise” is when I am catching an exception and re-raising it, because here I’m not failing, but explicitly and purposefully raising an exception.”
  • 22. raise raise ! # is equivalent to: ! raise RuntimeError
  • 23. raise(string) raise 'An error has occured.' ! # is equivalent to : ! raise RuntimeError, "'An error has occured.'
  • 24. raise(exception, string) raise RuntimeError, 'An error has occured.' ! # is equivalent to : ! raise RuntimeError.new('An error has occured.')
  • 25. backtrace (Array of string) raise RuntimeError, 'An error' ! # is equivalent to : ! raise RuntimeError, 'An error', caller(0)
  • 26. global $! variable ! • $! • $ERROR_INFO • reset to nil if the exception is rescued
  • 27. 2. rescue rescue SomeError => e # ... end 2/5
  • 28. rescue SomeError, SomeOtherError => e # ... end Multiple class or module
  • 29. rescue SomeError => e # ... rescue SomeOtherError => e # ... end stacking rescue order matters
  • 30. rescue # ... end ! # is equivalent to: ! rescue StandardError # ... end
  • 31. Ruby Exception Hierarchy • Exception • NoMemoryError • LoadError • SyntaxError • StandardError -- default for rescue • ArgumentError • IOError • NoMethodError • ….
  • 32. Avoid rescuing Exception class rescue Exception => e # ... end
  • 33. rescue => error # ... end # is equivalent to: ! rescue StandardError => error # ... end
  • 34. support * splatted active_support/core_ext/kernel/reporting.rb suppress(IOError, SystemCallError) do open("NONEXISTENT_FILE") end ! puts 'This code gets executed.'
  • 35. ! def suppress(*exception_classes) yield rescue *exception_classes # nothing to do end support * splatted (cont.) active_support/core_ext/kernel/reporting.rb
  • 36. Like case, it’s support === begin raise "Timeout while reading from socket" rescue errors_with_message(/socket/) puts "Ignoring socket error" end
  • 37. def errors_with_message(pattern) m = Module.new m.singleton_class.instance_eval do define_method(:===) do |e| pattern === e.message end end m end
  • 38. arbitrary block predicate begin raise "Timeout while reading from socket" rescue errors_matching{|e| e.message =~ /socket/} puts "Ignoring socket error" end
  • 39. def errors_matching(&block) m = Module.new m.singleton_class.instance_eval do define_method(:===, &block) end m end
  • 40. – Bertrand Meyer, Object Oriented Software Construction “In practice, the rescue clause should be a short sequence of simple instructions designed to bring the object back to a stable state and to either retry the operation or terminate with failure.”
  • 41. 3. ensure begin # do something raise 'An error has occured.' rescue => e puts 'I am rescued.' ensure puts 'This code gets executed always.' end 3/5
  • 42. 4. retry be careful “giving up” condition tries = 0 begin tries += 1 puts "Trying #{tries}..." raise "Didn't work" rescue retry if tries < 3 puts "I give up" end 4/5
  • 43. 5. else begin yield rescue puts "Only on error" else puts "Only on success" ensure puts "Always executed" end 5/5
  • 44. Recap • raise • rescue • ensure • retry • else
  • 45. 3. Caveat and Guideline
  • 46. 1. Is the situation truly unexpected? 1/6
  • 47. – Dave Thomas and Andy Hunt, The Pragmatic Programmer “ask yourself, 'Will this code still run if I remove all the exception handlers?" If the answer is "no", then maybe exceptions are being used in non-exceptional circumstances.”
  • 49. def create @user = User.new params[:user] @user.save! redirect_to user_path(@user) rescue ActiveRecord::RecordNotSaved flash[:notice] = 'Unable to create user' render :action => :new end This is bad
  • 50. def create @user = User.new params[:user] if @user.save redirect_to user_path(@user) else flash[:notice] = 'Unable to create user' render :action => :new end end
  • 52. begin user = User.find(params[:id) user.do_this rescue ActiveRecord::RecordNotFound # ??? end This is bad
  • 53. Use Null object user = User.find_by_id(params[:id) || NullUser.new user.do_this
  • 54. Replace Exception with Test def execute(command) command.prepare rescue nil command.execute end ! # => ! def execute(command) command.prepare if command.respond_to? :prepare command.execute end
  • 55. – Martin Folwer, Refactoring “Exceptions should be used for exceptional behaviour. They should not acts as substitute for conditional tests. If you can reasonably expect the caller to check the condition before calling the operation, you should provide a test, and the caller should use it.”
  • 56. Spare Handler? begin # main implementation rescue # alternative solution end
  • 57. begin user = User.find(params[:id) rescue ActiveRecord::RecordNotFound user = NullUser.new ensure user.do_this end This is bad
  • 58. user = User.find_by_id(params[:id) || NullUser.new ! user.do_this
  • 59. 2. raise during raise begin raise "Error A" # this will be thrown rescue raise "Error B" end 2/6
  • 60. Wrapped exception ! begin begin raise "Error A" rescue => error raise MyError, "Error B" end rescue => e puts "Current failure: #{e.inspect}" puts "Original failure: #{e.original.inspect}" end
  • 61. Wrapped exception (cont.) class MyError < StandardError attr_reader :original def initialize(msg, original=$!) super(msg) @original = original; set_backtrace original.backtrace end end
  • 62. Example: Rails uses the technique a lot • ActionDispatch::ExceptionWrapper • ActionControllerError::BadRequest, ParseError,SessionRestoreError • ActionView Template::Error
  • 63. 3. raise during ensure begin raise "Error A" ensure raise "Error B” puts "Never execute" end 3/6
  • 65. a more complex example begin r1 = Resource.new(1) r2 = Resource.new(2) r2.run r1.run rescue => e raise "run error: #{e.message}" ensure r2.close r1.close end
  • 66. class Resource attr_accessor :id ! def initialize(id) self.id = id end ! def run puts "run #{self.id}" raise "run error: #{self.id}" end ! def close puts "close #{self.id}" raise "close error: #{self.id}" end end
  • 67. begin r1 = Resource.new(1) r2 = Resource.new(2) r2.run r1.run # raise exception!!! rescue => e raise "run error: #{e.message}" ensure r2.close # raise exception!!! r1.close # never execute! end
  • 68. Result lost original r1 exception and fail to close r2 run 1 run 2 close 1 double_raise.rb:15:in `close': close error: 1 (RuntimeError)
  • 69. 4. Exception is your method interface too • For library, either you document your exception, or you should consider no-raise library API • return values (error code) • provide fallback callback 4/6
  • 70. 5. Exception classification module MyLibrary class Error < StandardError end end 5/6
  • 71. exception hierarchy example • StandardError • ActionControllerError • BadRequest • RoutingError • ActionController::UrlGenerationError • MethodNotAllowed • NotImplemented • …
  • 72. smart exception adding more information class MyError < StandardError attr_accessor :code ! def initialize(code) self.code = code end end ! begin raise MyError.new(1) rescue => e puts "Error code: #{e.code}" end
  • 74. Extract it! def foo try_something rescue bar end ! def bar try_something_else # ... rescue # ... end
  • 75. Recap • Use exception when you need • Wrap exception when re-raising • Avoid raising during ensure • Exception is your method interface too • Classify your exceptions • Readable exceptional code
  • 77. 1. Exception Safety • no guarantee • The weak guarantee (no-leak): If an exception is raised, the object will be left in a consistent state. • The strong guarantee (a.k.a. commit-or-rollback, all-or- nothing): If an exception is raised, the object will be rolled back to its beginning state. • The nothrow guarantee (failure transparency): No exceptions will be raised from the method. If an exception is raised during the execution of the method it will be handled internally. 1/12
  • 78. 2. Operational errors v.s. programmer errors https://www.joyent.com/developers/node/design/errors 2/12
  • 79. Operational errors • failed to connect to server • failed to resolve hostname • request timeout • server returned a 500 response • socket hang-up • system is out of memory
  • 81. We can handle operational errors • Restore and Cleanup Resource • Handle it directly • Propagate • Retry • Crash • Log it
  • 82. But we can not handle programmer errors
  • 83. 3. Robust levels • Robustness: the ability of a system to resist change without adapting its initial stable configuration. • There’re four robust levels http://en.wikipedia.org/wiki/Robustness 3/12
  • 84. Level 0: Undefined • Service: Failing implicitly or explicitly • State: Unknown or incorrect • Lifetime: Terminated or continued
  • 85. Level 1: Error-reporting (Failing fast) • Service: Failing explicitly • State: Unknown or incorrect • Lifetime: Terminated or continued • How-achieved: • Propagating all unhandled exceptions, and • Catching and reporting them in the main program
  • 86. Anti-pattern:
 Dummy handler (eating exceptions) begin #... rescue => e nil end
  • 87. Level 2: State-recovery (weakly tolerant) • Service: Failing explicitly • State: Correct • Lifetime: Continued • How-achieved: • Backward recovery • Cleanup
  • 88. require 'open-uri' page = "titles" file_name = "#{page}.html" web_page = open("https://pragprog.com/#{page}") output = File.open(file_name, "w") begin while line = web_page.gets output.puts line end output.close rescue => e STDERR.puts "Failed to download #{page}" output.close File.delete(file_name) raise end
  • 89. Level 3: Behavior-recovery (strongly tolerant) • Service: Delivered • State: Correct • Lifetime: Continued • How-achieved: • retry, and/or • design diversity, data diversity, and functional diversity
  • 90. Improve exception handling incrementally • Level 0 is bad • it’s better we require all method has Level 1 • Level 2 for critical operation. e.g storage/database operation • Level 3 for critical feature or customer requires. it means cost * 2 because we must have two solution everywhere.
  • 91. 4. Use timeout for any external call begin Timeout::timeout(3) do #... end rescue Timeout::Error => e # ... end 4/12
  • 92. 5. retry with circuit breaker http://martinfowler.com/bliki/CircuitBreaker.html 5/12
  • 93. 6. bulkheads for external service and process begin SomeExternalService.do_request rescue Exception => e logger.error "Error from External Service" logger.error e.message logger.error e.backtrace.join("n") end 6/12
  • 94. ! 7. Failure reporting • A central log server • Email • exception_notification gem • 3-party exception-reporting service • Airbrake, Sentry New Relic…etc 7/12
  • 95. 8. Exception collection class Item def process #... [true, result] rescue => e [false, result] end end ! collections.each do |item| results << item.process end 8/12
  • 96. 9. caller-supplied fallback strategy h.fetch(:optional){ "default value" } h.fetch(:required){ raise "Required not found" } ! arr.fetch(999){ "default value" } arr.detect( lambda{ "default value" }) { |x| x == "target" } 9/12
  • 97. – Brian Kernighan and Rob Pike, The Practice of Programming “In most cases, the caller should determine how to handle an error, not the callee.”
  • 98. def do_something(failure_policy=method(:raise)) #... rescue => e failure_policy.call(e) end ! do_something{ |e| puts e.message }
  • 99. 10. Avoid unexpected termination • rescue all exceptions at the outermost call stacks. • Rails does a great job here • developer will see all exceptions at development mode. • end user will not see exceptions at production mode 10/12
  • 100. 11. Error code v.s. exception • error code problems • it mixes normal code and exception handling • programmer can ignore error code easily 11/12
  • 101. Error code problem prepare_something # return error code trigger_someaction # still run http://yosefk.com/blog/error-codes-vs-exceptions-critical-code-vs-typical-code.html
  • 102. Replace Error Code with Exception (from Refactoring) def withdraw(amount) return -1 if amount > @balance @balance -= amount 0 end ! # => ! def withdraw(amount) raise BalanceError.new if amount > @balance @balance -= amount end
  • 103. Why does Go not have exceptions? • We believe that coupling exceptions to a control structure, as in the try-catch-finally idiom, results in convoluted code. It also tends to encourage programmers to label too many ordinary errors, such as failing to open a file, as exceptional. Go takes a different approach. For plain error handling, Go's multi-value returns make it easy to report an error without overloading the return value. A canonical error type, coupled with Go's other features, makes error handling pleasant but quite different from that in other languages. https://golang.org/doc/faq#exceptions
  • 104. – Raymond Chen “It's really hard to write good exception-based code since you have to check every single line of code (indeed, every sub-expression) and think about what exceptions it might raise and how your code will react to it.” http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx
  • 105. When use error code? ! • In low-level code which you must know the behavior in every possible situation • error codes may be better • Otherwise we have to know every exception that can be thrown by every line in the method to know what it will do http://stackoverflow.com/questions/253314/exceptions-or-error-codes
  • 106. 12. throw/catch flow def halt(*response) #.... throw :halt, response end def invoke res = catch(:halt) { yield } #... end 12/12
  • 107. Recap ! • exception safety • operational errors v.s. programmer errors • robust levels
  • 108. Recap (cont.) • use timeout • retry with circuit breaker pattern • bulkheads • failure reporting • exception collection • caller-supplied fallback strategy • avoid unexpected termination • error code • throw/catch
  • 110. QUESTIONS! begin thanks! raise if question? rescue puts "Please ask @ihower at twitter" ensure follow(@ihower).get_slides applause! end
  • 111. Reference • 例外處理設計的逆襲 • Exceptional Ruby http://avdi.org/talks/exceptional-ruby-2011-02-04/ • Release it! • Programming Ruby • The Well-Grounded Rubyist, 2nd • Refactoring • The Pragmatic Programmer • Code Complete 2 • https://www.joyent.com/developers/node/design/errors • http://robots.thoughtbot.com/save-bang-your-head-active-record-will-drive-you-mad • http://code.tutsplus.com/articles/writing-robust-web-applications-the-lost-art-of-exception-handling--net-36395 • http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx