Live Fast,         Die Young,Leave A Good Looking Corpse
Code Fast,       die() Early,Throw Structured Exceptions
Throw Structured Exceptions    John SJ Anderson / @genehack / dc.pm        YAPC::NA 2012 ~ Madison WI
“Classic” Perl exceptions
“Classic” Perl exceptions•   Throw an exception with die()
“Classic” Perl exceptions•   Throw an exception with die()•   Or Carp::croak(), Carp::confess(), etc.
“Classic” Perl exceptions•   Throw an exception with die()•   Or Carp::croak(), Carp::confess(), etc.•   TIMTOWTDI!
“Classic” Perl exceptions•   Throw an exception with die()•   Or Carp::croak(), Carp::confess(), etc.•   TIMTOWTDI!•   Cat...
“Classic” Perl exceptions•   Throw an exception with die()•   Or Carp::croak(), Carp::confess(), etc.•   TIMTOWTDI!•   Cat...
“Classic” Perl exception throwing 1   #! /usr/bin/perl 2 3   use strict; 4   use warnings; 5 6   eval { my $result = this_...
Problems with “classic” Perl exceptions
Problems with “classic” Perl exceptions•   $@ can get clobbered
Problems with “classic” Perl exceptions• $@ can get clobbered• $@ can get clobbered by code you don’t own
Problems with “classic” Perl exceptions• $@ can get clobbered• $@ can get clobbered by code you don’t own• $@ might be a f...
Problems with “classic” Perl exceptions• $@ can get clobbered• $@ can get clobbered by code you don’t own• $@ might be a f...
Use Try::Tiny for“semi-modern” Perl exceptions
Use Try::Tiny for  “semi-modern” Perl exceptions• Provides try{}/catch{}/finally{} blocks
Use Try::Tiny for  “semi-modern” Perl exceptions• Provides try{}/catch{}/finally{} blocks• Handles details of properly dea...
Use Try::Tiny for  “semi-modern” Perl exceptions• Provides try{}/catch{}/finally{} blocks• Handles details of properly dea...
Use Try::Tiny for  “semi-modern” Perl exceptions• Provides try{}/catch{}/finally{} blocks• Handles details of properly dea...
Use Try::Tiny for      “semi-modern” Perl exceptions 1   #! /usr/bin/perl 2 3   use strict; 4   use warnings; 5 6   use Tr...
Problems with  “semi-modern” Perl exceptions• $@ can get clobbered• $@ can get clobbered by code you don’t own• $@ might b...
Problems with  “semi-modern” Perl exceptions• If $@ is a string, you’re depending on duplicated  information, which will b...
Wait, where’s the duplicated information? 1   my $answer; 2   try { 3      # any of these might throw an exception 4      ...
Wait, where’s the duplicated information? 1   my $answer; 2   try { 3      # any of these might throw an exception 4      ...
Wait, where’s the duplicated information?•   As soon as somebody “fixes” the string in some die()    somewhere, you’ve pote...
Wait, where’s the duplicated information?•   As soon as somebody “fixes” the string in some die()    somewhere, you’ve pote...
Wait, where’s the duplicated information?•   As soon as somebody “fixes” the string in some die()    somewhere, you’ve pote...
So what’s the solution?
So what’s the solution?•   die() can also take a reference as an argument
So what’s the solution?•   die() can also take a reference as an argument•   So you can die() with an object!
So what’s the solution?•   die() can also take a reference as an argument•   So you can die() with an object!•   Which mea...
So what’s the solution?•   die() can also take a reference as an argument•   So you can die() with an object!•   Which mea...
A framework for structured exceptions:         Exception::Classuse Exception::Class (    MyException,     AnotherException...
A framework for structured exceptions:        Exception::Class# tryeval { MyException->throw( error => I feel funny. ) }; ...
Exception::Class Pros
Exception::Class Pros• Nice declarative syntax
Exception::Class Pros• Nice declarative syntax• Possible to declare detailed or simple exception class  hierarchies very s...
Exception::Class Pros• Nice declarative syntax• Possible to declare detailed or simple exception class    hierarchies very...
Exception::Class Cons
Exception::Class Cons•   Not really designed for use with Try::Tiny
Exception::Class Cons•   Not really designed for use with Try::Tiny•   Based on Class::Data::Inheritable, not Moose
A Moose role for structured exceptions:             Throwablepackage Redirect;use Moose;with Throwable; has url => (is => ...
Throwable Pros
Throwable Pros•   Implemented as a Moose role, so your exception    classes are just normal Moose classes that consume    ...
Throwable Pros•   Implemented as a Moose role, so your exception    classes are just normal Moose classes that consume    ...
Throwable Pros•   Implemented as a Moose role, so your exception    classes are just normal Moose classes that consume    ...
Throwable Cons
Throwable Cons      ?
Throwable Cons               ? So far, I haven’t really found any.
Throwable Cons                      ?        So far, I haven’t really found any.(Of course, that doesn’t mean there aren’t...
Error Handling          Patterns & Anti-Patterns• DO use exceptions instead of error flags• DO throw exceptions as early as...
Use exceptions instead of error flags 1 sub some_catalyst_action :Local { 2   my( $self , $c ) = @_; 3   my $session = get_...
Use exceptions instead of error flags   Please please please don’t write code like this!
Use exceptions instead of error flags
Use exceptions instead of error flags•   Forget just one of those checks and you’ve got a hard to track    down bug
Use exceptions instead of error flags•   Forget just one of those checks and you’ve got a hard to track    down bug•   $ses...
Use exceptions instead of error flags•   Forget just one of those checks and you’ve got a hard to track    down bug•   $ses...
Use exceptions instead of error flags 1 sub some_catalyst_action :Local { 2   my( $self , $c ) = @_; 3 4   try { 5     my $...
Throw exceptions as early as         possible
Throw exceptions as early as         possible• If you’re going to throw an exception because you  didn’t get passed someth...
Throw exceptions as early as         possible• If you’re going to throw an exception because you  didn’t get passed someth...
Don’t catch exceptionsexcept to handle them
Don’t catch exceptions     except to handle them• Most of the time, your business logic code is going to  throw exceptions...
Don’t catch exceptions     except to handle them• Most of the time, your business logic code is going to  throw exceptions...
Don’t catch exceptions      except to handle them• Most of the time, your business logic code is going to    throw excepti...
Further reading•   Throwable::X: common behavior for thrown exceptions    (<http://rjbs.manxome.org/rubric/entry/1860>)•  ...
Thanks!Questions?
Further reading•   Throwable::X: common behavior for thrown exceptions    (<http://rjbs.manxome.org/rubric/entry/1860>)•  ...
Upcoming SlideShare
Loading in …5
×

Code Fast, Die Young, Throw Structured Exceptions

1,943 views

Published on

Published in: Technology, Sports
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,943
On SlideShare
0
From Embeds
0
Number of Embeds
9
Actions
Shares
0
Downloads
9
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Code Fast, Die Young, Throw Structured Exceptions

    1. 1. Live Fast, Die Young,Leave A Good Looking Corpse
    2. 2. Code Fast, die() Early,Throw Structured Exceptions
    3. 3. Throw Structured Exceptions John SJ Anderson / @genehack / dc.pm YAPC::NA 2012 ~ Madison WI
    4. 4. “Classic” Perl exceptions
    5. 5. “Classic” Perl exceptions• Throw an exception with die()
    6. 6. “Classic” Perl exceptions• Throw an exception with die()• Or Carp::croak(), Carp::confess(), etc.
    7. 7. “Classic” Perl exceptions• Throw an exception with die()• Or Carp::croak(), Carp::confess(), etc.• TIMTOWTDI!
    8. 8. “Classic” Perl exceptions• Throw an exception with die()• Or Carp::croak(), Carp::confess(), etc.• TIMTOWTDI!• Catch an exception with eval {}
    9. 9. “Classic” Perl exceptions• Throw an exception with die()• Or Carp::croak(), Carp::confess(), etc.• TIMTOWTDI!• Catch an exception with eval {}• Handle an exception by looking at $@
    10. 10. “Classic” Perl exception throwing 1 #! /usr/bin/perl 2 3 use strict; 4 use warnings; 5 6 eval { my $result = this_might_fail() }; 7 8 if( $@ ) { 9 # handle the error here10 }
    11. 11. Problems with “classic” Perl exceptions
    12. 12. Problems with “classic” Perl exceptions• $@ can get clobbered
    13. 13. Problems with “classic” Perl exceptions• $@ can get clobbered• $@ can get clobbered by code you don’t own
    14. 14. Problems with “classic” Perl exceptions• $@ can get clobbered• $@ can get clobbered by code you don’t own• $@ might be a false value
    15. 15. Problems with “classic” Perl exceptions• $@ can get clobbered• $@ can get clobbered by code you don’t own• $@ might be a false value• If $@ is a string, you’re depending on duplicated information, which will break.
    16. 16. Use Try::Tiny for“semi-modern” Perl exceptions
    17. 17. Use Try::Tiny for “semi-modern” Perl exceptions• Provides try{}/catch{}/finally{} blocks
    18. 18. Use Try::Tiny for “semi-modern” Perl exceptions• Provides try{}/catch{}/finally{} blocks• Handles details of properly dealing with complexities around $@
    19. 19. Use Try::Tiny for “semi-modern” Perl exceptions• Provides try{}/catch{}/finally{} blocks• Handles details of properly dealing with complexities around $@• Lightweight and generally Just Works(tm).
    20. 20. Use Try::Tiny for “semi-modern” Perl exceptions• Provides try{}/catch{}/finally{} blocks• Handles details of properly dealing with complexities around $@• Lightweight and generally Just Works(tm).• N.b.: you have to end try{}/catch{} with a semicolon. Don’t forget this!
    21. 21. Use Try::Tiny for “semi-modern” Perl exceptions 1 #! /usr/bin/perl 2 3 use strict; 4 use warnings; 5 6 use Try::Tiny; 7 8 try { 9 my $result = this_might_fail();10 }11 catch {12 # handle the error here13 };
    22. 22. Problems with “semi-modern” Perl exceptions• $@ can get clobbered• $@ can get clobbered by code you don’t own• $@ might be a false value• If $@ is a string, you’re depending on duplicated information, which will break.
    23. 23. Problems with “semi-modern” Perl exceptions• If $@ is a string, you’re depending on duplicated information, which will break.
    24. 24. Wait, where’s the duplicated information? 1 my $answer; 2 try { 3 # any of these might throw an exception 4 my $this = this_might_fail(); 5 my $that = something_else_might_fail(); 6 $answer = combine_them( $this , $that ); 7 } 8 catch { 9 # our error is in $_10 if( $_ =~ /some error/ ) {11 # handle some error12 }13 elsif( $_ =~ /another error/ ) {14 # handle another error15 }16 else { # not sure what the problem is, just give up17 confess( $_ );18 }19 };
    25. 25. Wait, where’s the duplicated information? 1 my $answer; 2 try { 3 # any of these might throw an exception 4 my $this = this_might_fail(); 5 my $that = something_else_might_fail(); 6 $answer = combine_them( $this , $that ); 7 } 8 catch { 9 # our error is in $_10 if( $_ =~ /some error/ ) {11 # handle some error12 }13 elsif( $_ =~ /another error/ ) {14 # handle another error15 }16 else { # not sure what the problem is, just give up17 confess( $_ );18 }19 };
    26. 26. Wait, where’s the duplicated information?• As soon as somebody “fixes” the string in some die() somewhere, you’ve potentially broken exception handling
    27. 27. Wait, where’s the duplicated information?• As soon as somebody “fixes” the string in some die() somewhere, you’ve potentially broken exception handling• And you can’t even easily tell where, because it’s probably in a regexp that doesn’t look at all like the changed string
    28. 28. Wait, where’s the duplicated information?• As soon as somebody “fixes” the string in some die() somewhere, you’ve potentially broken exception handling• And you can’t even easily tell where, because it’s probably in a regexp that doesn’t look at all like the changed string• Even if you have tests for the code in question, do you really have test coverage on all your exception cases?
    29. 29. So what’s the solution?
    30. 30. So what’s the solution?• die() can also take a reference as an argument
    31. 31. So what’s the solution?• die() can also take a reference as an argument• So you can die() with an object!
    32. 32. So what’s the solution?• die() can also take a reference as an argument• So you can die() with an object!• Which means you can cram all sorts of useful information into your exceptions
    33. 33. So what’s the solution?• die() can also take a reference as an argument• So you can die() with an object!• Which means you can cram all sorts of useful information into your exceptions• And more importantly, handle them in a structured fashion that’s much less brittle than string comparisons
    34. 34. A framework for structured exceptions: Exception::Classuse Exception::Class (    MyException,     AnotherException => { isa => MyException },     YetAnotherException => {        isa         => AnotherException,        description => These exceptions are related to IPC    },     ExceptionWithFields => {        isa    => YetAnotherException,        fields => [ grandiosity, quixotic ],    },);
    35. 35. A framework for structured exceptions: Exception::Class# tryeval { MyException->throw( error => I feel funny. ) }; my $e; # catchif ( $e = Exception::Class->caught(MyException) ) {    warn $e->error, "n", $e->trace->as_string, "n";    warn join , $e->euid, $e->egid, $e->uid, $e->gid, $e->pid;    exit;}elsif ( $e = Exception::Class->caught(ExceptionWithFields) ) {    $e->quixotic ? do_something_wacky() : do_something_sane();}else {    $e = Exception::Class->caught();    ref $e ? $e->rethrow : die $e;}
    36. 36. Exception::Class Pros
    37. 37. Exception::Class Pros• Nice declarative syntax
    38. 38. Exception::Class Pros• Nice declarative syntax• Possible to declare detailed or simple exception class hierarchies very simply
    39. 39. Exception::Class Pros• Nice declarative syntax• Possible to declare detailed or simple exception class hierarchies very simply• Supports aliasing to make throwing particular exception types easier
    40. 40. Exception::Class Cons
    41. 41. Exception::Class Cons• Not really designed for use with Try::Tiny
    42. 42. Exception::Class Cons• Not really designed for use with Try::Tiny• Based on Class::Data::Inheritable, not Moose
    43. 43. A Moose role for structured exceptions: Throwablepackage Redirect;use Moose;with Throwable; has url => (is => ro);...then later...Redirect->throw({ url => $url });
    44. 44. Throwable Pros
    45. 45. Throwable Pros• Implemented as a Moose role, so your exception classes are just normal Moose classes that consume the role
    46. 46. Throwable Pros• Implemented as a Moose role, so your exception classes are just normal Moose classes that consume the role• So you get the usual Moose-y good stuff around attributes and methods and such.
    47. 47. Throwable Pros• Implemented as a Moose role, so your exception classes are just normal Moose classes that consume the role• So you get the usual Moose-y good stuff around attributes and methods and such.• Comes with a grab-bag of typical exception behaviors (in Throwable::X), like stack traces, printf-ish messages, etc.
    48. 48. Throwable Cons
    49. 49. Throwable Cons ?
    50. 50. Throwable Cons ? So far, I haven’t really found any.
    51. 51. Throwable Cons ? So far, I haven’t really found any.(Of course, that doesn’t mean there aren’t any...)
    52. 52. Error Handling Patterns & Anti-Patterns• DO use exceptions instead of error flags• DO throw exceptions as early as possible• DON’T catch exceptions unless you’re going to handle them – just let them propagate upwards• DO design your web application-level error actions to handle your business logic-level exceptions
    53. 53. Use exceptions instead of error flags 1 sub some_catalyst_action :Local { 2 my( $self , $c ) = @_; 3 my $session = get_huge_session_object( $c->session ); 4 5 my $validated_params = validate_request_params( $c->request->params ) 6 or $c->detach( error ); 7 8 my $step_one_result = $c->model(BusinessLogic)->do_step_one( $session , $validated_params ); 9 $c->detach( error ) if $session->has_error();1011 my $step_two_result = $c->model(BusinessLogic)->do_step_two( $step_one_result, $session );12 $c->detach( error ) if $session->has_error();13 }
    54. 54. Use exceptions instead of error flags Please please please don’t write code like this!
    55. 55. Use exceptions instead of error flags
    56. 56. Use exceptions instead of error flags• Forget just one of those checks and you’ve got a hard to track down bug
    57. 57. Use exceptions instead of error flags• Forget just one of those checks and you’ve got a hard to track down bug• $session is being passed just to provide access to that error flag.
    58. 58. Use exceptions instead of error flags• Forget just one of those checks and you’ve got a hard to track down bug• $session is being passed just to provide access to that error flag.• The error action gets no real info about what the problem was, or it tries to pull it from $session itself (which has its own problems)
    59. 59. Use exceptions instead of error flags 1 sub some_catalyst_action :Local { 2 my( $self , $c ) = @_; 3 4 try { 5 my $validated_params = validate_request_params( $c->request->params ) 6 7 my $step_one_result = $c->model(BusinessLogic)->do_step_one( $session , $validated_params ); 8 9 my $step_two_result = $c->model(BusinessLogic)->do_step_two( $step_one_result, $session );10 }11 catch { $c->detach( error , [ $_ ] ) };12 }
    60. 60. Throw exceptions as early as possible
    61. 61. Throw exceptions as early as possible• If you’re going to throw an exception because you didn’t get passed something, do it ASAP.
    62. 62. Throw exceptions as early as possible• If you’re going to throw an exception because you didn’t get passed something, do it ASAP.• In general, the quicker you can die(), the better – because it reduces the amount of code that might contain the bug.
    63. 63. Don’t catch exceptionsexcept to handle them
    64. 64. Don’t catch exceptions except to handle them• Most of the time, your business logic code is going to throw exceptions, not catch them
    65. 65. Don’t catch exceptions except to handle them• Most of the time, your business logic code is going to throw exceptions, not catch them• If you do catch an exception, you should be trying to fix the problem.
    66. 66. Don’t catch exceptions except to handle them• Most of the time, your business logic code is going to throw exceptions, not catch them• If you do catch an exception, you should be trying to fix the problem.• Don’t catch exceptions just to munge them or log them and re-throw them. Munge them or log them before you throw them.
    67. 67. Further reading• Throwable::X: common behavior for thrown exceptions (<http://rjbs.manxome.org/rubric/entry/1860>)• Exceptionally Extensible Exceptions (<http://advent.rjbs.manxome.org/2010/2010-12-03.html>)• Structured Data and Knowing versus Guessing (<http://www.modernperlbooks.com/mt/2010/10/structured-data-and-knowing-versus-guessing.html>)
    68. 68. Thanks!Questions?
    69. 69. Further reading• Throwable::X: common behavior for thrown exceptions (<http://rjbs.manxome.org/rubric/entry/1860>)• Exceptionally Extensible Exceptions (<http://advent.rjbs.manxome.org/2010/2010-12-03.html>)• Structured Data and Knowing versus Guessing (<http://www.modernperlbooks.com/mt/2010/10/structured-data-and-knowing-versus-guessing.html>)

    ×