Live Fast,        Die Young,Have A Good Looking Corpse
Code Fast,       die() Early,Throw Structured Exceptions
Throw Structured Exceptions         John SJ Anderson            @genehack            03 Jan 2012
“Classic” Perl exception throwing
“Classic” Perl exception throwing•   Throw an exception with die()
“Classic” Perl exception throwing•   Throw an exception with die()•   Or Carp::croak(), Carp::confess(), etc.
“Classic” Perl exception throwing•   Throw an exception with die()•   Or Carp::croak(), Carp::confess(), etc.•   TIMTOWTDI!
“Classic” Perl exception throwing•   Throw an exception with die()•   Or Carp::croak(), Carp::confess(), etc.•   TIMTOWTDI...
“Classic” Perl exception throwing•   Throw an exception with die()•   Or Carp::croak(), Carp::confess(), etc.•   TIMTOWTDI...
“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?• Even if you have tests for the code in question, do you  really have test cover...
Wait, where’s the duplicated information?• Even if you have tests for the code in question, do you  really have test cover...
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 HandlingPatterns & Anti-Patterns
Error Handling          Patterns & Anti-Patterns• DO use exceptions instead of error flags
Error Handling          Patterns & Anti-Patterns• DO use exceptions instead of error flags• DO throw exceptions as early as...
Error Handling          Patterns & Anti-Patterns• DO use exceptions instead of error flags• DO throw exceptions as early as...
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•   Many...
Use exceptions instead of error flags•   Forget just one of those checks and you’ve got a hard to track down    bug•   Many...
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...
Web application error actions should handle exceptions 1 sub error :Private { 2   my( $self , $c , $error ) = @_; 3 4   my...
Web application error actions should handle exceptions 1 sub error :Private { 2   my( $self , $c , $error ) = @_; 3 4   my...
Further reading•   Throwable::X: common behavior for thrown exceptions    (<http://rjbs.manxome.org/rubric/entry/1860>)•  ...
Thanks for your time    this evening!
Questions?
Upcoming SlideShare
Loading in …5
×

Code Fast, die() Early, Throw Structured Exceptions

3,034 views
2,938 views

Published on

Slides from a short talk given at January 2012 DC.pm. Covers "classic" exceptions in Perl as well as some libraries to make working with exceptions easier.

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

No Downloads
Views
Total views
3,034
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
19
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
  • \n
  • \n
  • \n
  • \n
  • \n
  • Code Fast, die() Early, Throw Structured Exceptions

    1. 1. Live Fast, Die Young,Have A Good Looking Corpse
    2. 2. Code Fast, die() Early,Throw Structured Exceptions
    3. 3. Throw Structured Exceptions John SJ Anderson @genehack 03 Jan 2012
    4. 4. “Classic” Perl exception throwing
    5. 5. “Classic” Perl exception throwing• Throw an exception with die()
    6. 6. “Classic” Perl exception throwing• Throw an exception with die()• Or Carp::croak(), Carp::confess(), etc.
    7. 7. “Classic” Perl exception throwing• Throw an exception with die()• Or Carp::croak(), Carp::confess(), etc.• TIMTOWTDI!
    8. 8. “Classic” Perl exception throwing• Throw an exception with die()• Or Carp::croak(), Carp::confess(), etc.• TIMTOWTDI!• Catch an exception with eval {}
    9. 9. “Classic” Perl exception throwing• 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 }1112 sub this_might_fail {13 die "FAILED!"14 if rand() < 0.5;15 }
    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 };1415 sub this_might_fail {16 die "FAILED!"17 if rand() < 0.5;18 }
    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?• Even if you have tests for the code in question, do you really have test coverage on all your exception cases?
    29. 29. Wait, where’s the duplicated information?• Even if you have tests for the code in question, do you really have test coverage on all your exception cases?• (Almost certainly not. If you do, come write tests for $WORK_PROJECT, we need the help...)
    30. 30. So what’s the solution?
    31. 31. So what’s the solution?• die() can also take a reference as an argument
    32. 32. So what’s the solution?• die() can also take a reference as an argument• So you can die() with an object!
    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
    34. 34. 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
    35. 35. 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 ],    },);
    36. 36. 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;}
    37. 37. Exception::Class Pros
    38. 38. Exception::Class Pros• Nice declarative syntax
    39. 39. Exception::Class Pros• Nice declarative syntax• Possible to declare detailed or simple exception class hierarchies very simply
    40. 40. Exception::Class Pros• Nice declarative syntax• Possible to declare detailed or simple exception class hierarchies very simply• Supports macro definitions to make throwing particular exception types easier
    41. 41. Exception::Class Cons
    42. 42. Exception::Class Cons• Not really designed for use with Try::Tiny
    43. 43. Exception::Class Cons• Not really designed for use with Try::Tiny• Based on Class::Data::Inheritable, not Moose
    44. 44. A Moose role for structured exceptions: Throwablepackage Redirect;use Moose;with Throwable; has url => (is => ro);...then later...Redirect->throw({ url => $url });
    45. 45. Throwable Pros
    46. 46. Throwable Pros• Implemented as a Moose role, so your exception classes are just normal Moose classes that consume the role
    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.
    48. 48. 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.
    49. 49. Throwable Cons
    50. 50. Throwable Cons ?
    51. 51. Throwable Cons ? So far, I haven’t really found any.
    52. 52. Throwable Cons ? So far, I haven’t really found any.(Of course, that doesn’t mean there aren’t any...)
    53. 53. Error HandlingPatterns & Anti-Patterns
    54. 54. Error Handling Patterns & Anti-Patterns• DO use exceptions instead of error flags
    55. 55. Error Handling Patterns & Anti-Patterns• DO use exceptions instead of error flags• DO throw exceptions as early as possible
    56. 56. 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
    57. 57. 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
    58. 58. 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();1314 $c->stash({15 one => $step_one_result ,16 two => $step_two_result ,17 });18 }
    59. 59. Use exceptions instead of error flags Please please please don’t write code like this!
    60. 60. Use exceptions instead of error flags
    61. 61. Use exceptions instead of error flags• Forget just one of those checks and you’ve got a hard to track down bug
    62. 62. Use exceptions instead of error flags• Forget just one of those checks and you’ve got a hard to track down bug• Many times, $session was passed just to provide access to that error flag. Far too much information was being passed around for no reason
    63. 63. Use exceptions instead of error flags• Forget just one of those checks and you’ve got a hard to track down bug• Many times, $session was passed just to provide access to that error flag. Far too much information was being passed around for no reason• 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)
    64. 64. 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 , [ $_ ] ) };1213 $c->stash({14 one => $step_one_result ,15 two => $step_two_result ,16 });17 }
    65. 65. Throw exceptions as early as possible
    66. 66. Throw exceptions as early as possible• If you’re going to throw an exception because you didn’t get passed something, do it ASAP.
    67. 67. 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.
    68. 68. Don’t catch exceptionsexcept to handle them
    69. 69. Don’t catch exceptions except to handle them• Most of the time, your business logic code is going to throw exceptions, not catch them
    70. 70. 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.
    71. 71. 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.
    72. 72. Web application error actions should handle exceptions 1 sub error :Private { 2 my( $self , $c , $error ) = @_; 3 4 my $message = An unexpected error happened.; 5 6 # NOTE: duck typing 7 $message = $error->user_visible_message 8 if( $error->has_user_visible_message and ! $error->is_private ); 910 $c->stash({11 message => $message ,12 template => error,13 });14 }
    73. 73. Web application error actions should handle exceptions 1 sub error :Private { 2 my( $self , $c , $error ) = @_; 3 4 my $message = An unexpected error happened.; 5 6 # NOTE: duck typing 7 $message = $error->user_visible_message 8 if( $error->has_user_visible_message and ! $error->is_private ); 910 $c->stash({11 message => $message ,12 template => error,13 });14 } (again, not the best example ever...)
    74. 74. 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>)
    75. 75. Thanks for your time this evening!
    76. 76. Questions?

    ×