SlideShare ist ein Scribd-Unternehmen logo
1 von 111
Downloaden Sie, um offline zu lesen
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

Weitere ähnliche Inhalte

Was ist angesagt?

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
 
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 Codescidept
 
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 DjangoLoek 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 TutorialAnup 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 DesignVictor Rentea
 
Painless JavaScript Testing with Jest
Painless JavaScript Testing with JestPainless JavaScript Testing with Jest
Painless JavaScript Testing with JestMichał 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 JSMichael 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 BDDKonstantin Kudryashov
 
Angular Intermediate
Angular IntermediateAngular Intermediate
Angular IntermediateLinkMe Srl
 
Intro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJSIntro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJSJim Lynch
 
JavaScript - From Birth To Closure
JavaScript - From Birth To ClosureJavaScript - From Birth To Closure
JavaScript - From Birth To ClosureRobert Nyman
 
Google mock for dummies
Google mock for dummiesGoogle mock for dummies
Google mock for dummiesHarry Potter
 

Was ist angesagt? (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
 

Ähnlich wie Exception Handling: Designing Robust Software in Ruby

Ruby & Rails Error Handling
Ruby & Rails Error HandlingRuby & Rails Error Handling
Ruby & Rails Error HandlingSimon Maynard
 
Object Oriented PHP - PART-2
Object Oriented PHP - PART-2Object Oriented PHP - PART-2
Object Oriented PHP - PART-2Jalpesh 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 2thenmozhip8
 
Test First Teaching
Test First TeachingTest First Teaching
Test First TeachingSarah Allen
 
ruby on rails pitfalls
ruby on rails pitfallsruby on rails pitfalls
ruby on rails pitfallsRobbin 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 ProjectLouie Zhao
 
Speed geeking-lotusscript
Speed geeking-lotusscriptSpeed geeking-lotusscript
Speed geeking-lotusscriptBill Buchan
 
Ruby On Rails Pitfalls
Ruby On Rails PitfallsRuby On Rails Pitfalls
Ruby On Rails PitfallsRobin Lu
 
Ruby for C# Developers
Ruby for C# DevelopersRuby for C# Developers
Ruby for C# DevelopersCory Foy
 
20141210 rakuten techtalk
20141210 rakuten techtalk20141210 rakuten techtalk
20141210 rakuten techtalkHiroshi SHIBATA
 
exceptionvdffhhhccvvvv-handling-in-java.ppt
exceptionvdffhhhccvvvv-handling-in-java.pptexceptionvdffhhhccvvvv-handling-in-java.ppt
exceptionvdffhhhccvvvv-handling-in-java.pptyjrtytyuu
 
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 LaterHiraq Citra M
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everythingnoelrap
 
Monkeybars in the Manor
Monkeybars in the ManorMonkeybars in the Manor
Monkeybars in the Manormartinbtt
 
VodQA_ParallelizingCukes_AmanKing
VodQA_ParallelizingCukes_AmanKingVodQA_ParallelizingCukes_AmanKing
VodQA_ParallelizingCukes_AmanKingpoojaelkunchwar
 

Ähnlich wie 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
 

Mehr von 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 LearningWen-Tien Chang
 
淺談 Startup 公司的軟體開發流程 v2
淺談 Startup 公司的軟體開發流程 v2淺談 Startup 公司的軟體開發流程 v2
淺談 Startup 公司的軟體開發流程 v2Wen-Tien Chang
 
RSpec on Rails Tutorial
RSpec on Rails TutorialRSpec on Rails Tutorial
RSpec on Rails TutorialWen-Tien Chang
 
ALPHAhackathon: How to collaborate
ALPHAhackathon: How to collaborateALPHAhackathon: How to collaborate
ALPHAhackathon: How to collaborateWen-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.0Wen-Tien Chang
 
RubyConf Taiwan 2012 Opening & Closing
RubyConf Taiwan 2012 Opening & ClosingRubyConf Taiwan 2012 Opening & Closing
RubyConf Taiwan 2012 Opening & ClosingWen-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
 

Mehr von 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
 

Kürzlich hochgeladen

Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DaySri Ambati
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 

Kürzlich hochgeladen (20)

Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 

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