SlideShare a Scribd company logo
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!

•   Catch an exception with eval {}
“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 $@
“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 here
10   }
11
12   sub this_might_fail {
13     die "FAILED!"
14       if rand() < 0.5;
15   }
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 false value
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.
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 dealing with complexities
  around $@
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).
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!
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 here
13   };
14
15   sub this_might_fail {
16     die "FAILED!"
17       if rand() < 0.5;
18   }
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.
Problems with
  “semi-modern” Perl exceptions



• If $@ is a string, you’re depending on duplicated
  information, which will break.
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 error
12      }
13      elsif( $_ =~ /another error/ ) {
14        # handle another error
15      }
16      else { # not sure what the problem is, just give up
17        confess( $_ );
18      }
19   };
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 error
12      }
13      elsif( $_ =~ /another error/ ) {
14        # handle another error
15      }
16      else { # not sure what the problem is, just give up
17        confess( $_ );
18      }
19   };
Wait, where’s the duplicated information?

•   As soon as somebody “fixes” the string in some die()
    somewhere, you’ve potentially broken exception
    handling
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
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?
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...)
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 means you can cram all sorts of useful information into your
    exceptions
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
A framework for structured exceptions:
         Exception::Class
use Exception::Class (
    'MyException',
 
    'AnotherException' => { isa => 'MyException' },
 
    'YetAnotherException' => {
        isa         => 'AnotherException',
        description => 'These exceptions are related to IPC'
    },
 
    'ExceptionWithFields' => {
        isa    => 'YetAnotherException',
        fields => [ 'grandiosity', 'quixotic' ],
    },
);
A framework for structured exceptions:
        Exception::Class
# try
eval { MyException->throw( error => 'I feel funny.' ) };
 
my $e; 
# catch
if ( $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;
}
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 simply
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
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:
             Throwable
package Redirect;
use Moose;
with 'Throwable';
 
has url => (is => 'ro');


...then later...



Redirect->throw({ url => $url });
Throwable Pros
Throwable Pros
•   Implemented as a Moose role, so your exception
    classes are just normal Moose classes that consume
    the role
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.
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.
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 any...)
Error Handling
Patterns & 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 possible
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
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
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();
10
11   my $step_two_result = $c->model('BusinessLogic')->do_step_two( $step_one_result, $session );
12   $c->detach( 'error' ) if $session->has_error();
13
14   $c->stash({
15     one => $step_one_result ,
16     two => $step_two_result ,
17   });
18 }
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 times, $session was passed just to provide access to that
    error flag. Far too much information was being passed around for
    no reason
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)
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
13   $c->stash({
14     one => $step_one_result ,
15     two => $step_two_result ,
16   });
17 }
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 something, do it ASAP.
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.
Don’t catch exceptions
except to handle them
Don’t catch exceptions
     except to handle them
• Most of the time, your business logic code is going to
  throw exceptions, not catch them
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
      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.
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 );
 9
10   $c->stash({
11       message => $message ,
12       template => 'error',
13   });
14 }
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 );
 9
10   $c->stash({
11       message => $message ,
12       template => 'error',
13   });
14 }


                  (again, not the best example ever...)
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>)
Thanks for your time
    this evening!
Questions?

More Related Content

KEY
Code Fast, Die Young, Throw Structured Exceptions
PDF
Code with Style - PyOhio
PPTX
Understanding Prototypal Inheritance
PDF
P6 OO vs Moose (&Moo)
PDF
JavaScript Primer
KEY
Pontificating quantification
PDF
Moose workshop
PPT
Ruby & Rails Error Handling
Code Fast, Die Young, Throw Structured Exceptions
Code with Style - PyOhio
Understanding Prototypal Inheritance
P6 OO vs Moose (&Moo)
JavaScript Primer
Pontificating quantification
Moose workshop
Ruby & Rails Error Handling

Viewers also liked (16)

PPT
Криокомплекс
PPTX
Keith hopper-product-market-fit
PPT
正向積極成功學
PPTX
Сектор_НИТ_отдела_Технического_творчества_МГДД(Ю)Т
PPT
Social media strategies for dr. pfahl class, 8 13
PPTX
Hidden gluteninthankgivingmeal
PDF
Managing risk in challenging economic times
PPT
АВтоматизированный Расчет Операционных РАзмеров
PDF
Mi primer dibujo
PDF
5 Things Everyone Should Know about Low-Calorie Sweeteners
PDF
מצגת כיתה ט
PDF
Curation Nation
PPT
Система передачи субмиллиметровых биологических сигналов
PDF
Ipsos MORI Scotland Opinion Monitor - Lockerbie - October 2011
PDF
Apresentando ideias com Prezi
PDF
Innovations New World Order
Криокомплекс
Keith hopper-product-market-fit
正向積極成功學
Сектор_НИТ_отдела_Технического_творчества_МГДД(Ю)Т
Social media strategies for dr. pfahl class, 8 13
Hidden gluteninthankgivingmeal
Managing risk in challenging economic times
АВтоматизированный Расчет Операционных РАзмеров
Mi primer dibujo
5 Things Everyone Should Know about Low-Calorie Sweeteners
מצגת כיתה ט
Curation Nation
Система передачи субмиллиметровых биологических сигналов
Ipsos MORI Scotland Opinion Monitor - Lockerbie - October 2011
Apresentando ideias com Prezi
Innovations New World Order
Ad

Similar to Code Fast, die() Early, Throw Structured Exceptions (20)

ODP
Perl exceptions lightning talk
PPTX
Corinna-2023.pptx
PDF
Perl Sucks - and what to do about it
PDF
Catch Me If You Can: Sugary Exception Handling in Perl
ODP
Exception Handling in Perl
PDF
Php exceptions
PDF
Exception Handling: Designing Robust Software in Ruby
PPTX
Exceptions in Java
PPT
Standard exceptions
PDF
Elegant Ways of Handling PHP Errors and Exceptions
PDF
Exceptions in PHP
PDF
Perl Critic In Depth
PDF
Introduction to Writing Readable and Maintainable Perl (YAPC::EU 2011 Version)
PPT
Exception handling
PDF
Introduction to writing readable and maintainable Perl
PPTX
Exception handling
PDF
Working Effectively With Legacy Perl Code
PPT
Exceptions in Ruby - Tips and Tricks
PDF
Getting testy with Perl
PPTX
Lecture 3.1.1 Try Throw Catch.pptx
Perl exceptions lightning talk
Corinna-2023.pptx
Perl Sucks - and what to do about it
Catch Me If You Can: Sugary Exception Handling in Perl
Exception Handling in Perl
Php exceptions
Exception Handling: Designing Robust Software in Ruby
Exceptions in Java
Standard exceptions
Elegant Ways of Handling PHP Errors and Exceptions
Exceptions in PHP
Perl Critic In Depth
Introduction to Writing Readable and Maintainable Perl (YAPC::EU 2011 Version)
Exception handling
Introduction to writing readable and maintainable Perl
Exception handling
Working Effectively With Legacy Perl Code
Exceptions in Ruby - Tips and Tricks
Getting testy with Perl
Lecture 3.1.1 Try Throw Catch.pptx
Ad

More from John Anderson (20)

PDF
#speakerlife
PDF
Introduction to Git (even for non-developers)
PDF
Logs are-magic-devfestweekend2018
PDF
Logs Are Magic: Why Git Workflows and Commit Structure Should Matter To You
PDF
A static site generator should be your next language learning project
PDF
Do you want to be right or do you want to WIN?
PDF
An Introduction to Git (even for non-developers)
PDF
You got chocolate in my peanut butter! .NET on Mac & Linux
PDF
A static site generator should be your next language learning project
PDF
Old Dogs & New Tricks: What's New with Perl5 This Century
PDF
Introduction to Git (even for non-developers!)
PDF
Introduction to Git for Non-Developers
PDF
A Modest Introduction To Swift
PDF
A static site generator should be your next language learning project
PDF
Logs Are Magic: Why Git Workflows and Commit Structure Should Matter To You
PDF
JSON Web Tokens Will Improve Your Life
PDF
Old Dogs & New Tricks: What's New With Perl5 This Century
PDF
A Modest Introduction to Swift
PDF
Logs Are Magic: Why Git Workflows and Commit Structure Should Matter To You
PDF
Friends Don't Let Friends Browse Unencrypted: Running a VPN for friends and f...
#speakerlife
Introduction to Git (even for non-developers)
Logs are-magic-devfestweekend2018
Logs Are Magic: Why Git Workflows and Commit Structure Should Matter To You
A static site generator should be your next language learning project
Do you want to be right or do you want to WIN?
An Introduction to Git (even for non-developers)
You got chocolate in my peanut butter! .NET on Mac & Linux
A static site generator should be your next language learning project
Old Dogs & New Tricks: What's New with Perl5 This Century
Introduction to Git (even for non-developers!)
Introduction to Git for Non-Developers
A Modest Introduction To Swift
A static site generator should be your next language learning project
Logs Are Magic: Why Git Workflows and Commit Structure Should Matter To You
JSON Web Tokens Will Improve Your Life
Old Dogs & New Tricks: What's New With Perl5 This Century
A Modest Introduction to Swift
Logs Are Magic: Why Git Workflows and Commit Structure Should Matter To You
Friends Don't Let Friends Browse Unencrypted: Running a VPN for friends and f...

Recently uploaded (20)

PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Approach and Philosophy of On baking technology
PDF
Spectral efficient network and resource selection model in 5G networks
PPTX
Cloud computing and distributed systems.
PDF
Review of recent advances in non-invasive hemoglobin estimation
PPTX
Machine Learning_overview_presentation.pptx
PPTX
Spectroscopy.pptx food analysis technology
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
Encapsulation theory and applications.pdf
PPTX
MYSQL Presentation for SQL database connectivity
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PPTX
A Presentation on Artificial Intelligence
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
The Rise and Fall of 3GPP – Time for a Sabbatical?
Dropbox Q2 2025 Financial Results & Investor Presentation
Approach and Philosophy of On baking technology
Spectral efficient network and resource selection model in 5G networks
Cloud computing and distributed systems.
Review of recent advances in non-invasive hemoglobin estimation
Machine Learning_overview_presentation.pptx
Spectroscopy.pptx food analysis technology
Network Security Unit 5.pdf for BCA BBA.
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Encapsulation theory and applications.pdf
MYSQL Presentation for SQL database connectivity
20250228 LYD VKU AI Blended-Learning.pptx
“AI and Expert System Decision Support & Business Intelligence Systems”
MIND Revenue Release Quarter 2 2025 Press Release
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
A Presentation on Artificial Intelligence
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf

Code Fast, die() Early, Throw Structured Exceptions

  • 1. Live Fast, Die Young, Have A Good Looking Corpse
  • 2. Code Fast, die() Early, Throw Structured Exceptions
  • 3. Throw Structured Exceptions John SJ Anderson @genehack 03 Jan 2012
  • 5. “Classic” Perl exception throwing • Throw an exception with die()
  • 6. “Classic” Perl exception throwing • Throw an exception with die() • Or Carp::croak(), Carp::confess(), etc.
  • 7. “Classic” Perl exception throwing • Throw an exception with die() • Or Carp::croak(), Carp::confess(), etc. • TIMTOWTDI!
  • 8. “Classic” Perl exception throwing • Throw an exception with die() • Or Carp::croak(), Carp::confess(), etc. • TIMTOWTDI! • Catch an exception with eval {}
  • 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. “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 here 10 } 11 12 sub this_might_fail { 13 die "FAILED!" 14 if rand() < 0.5; 15 }
  • 11. Problems with “classic” Perl exceptions
  • 12. Problems with “classic” Perl exceptions • $@ can get clobbered
  • 13. Problems with “classic” Perl exceptions • $@ can get clobbered • $@ can get clobbered by code you don’t own
  • 14. Problems with “classic” Perl exceptions • $@ can get clobbered • $@ can get clobbered by code you don’t own • $@ might be a false value
  • 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.
  • 17. Use Try::Tiny for “semi-modern” Perl exceptions • Provides try{}/catch{}/finally{} blocks
  • 18. Use Try::Tiny for “semi-modern” Perl exceptions • Provides try{}/catch{}/finally{} blocks • Handles details of properly dealing with complexities around $@
  • 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. 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. 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 here 13 }; 14 15 sub this_might_fail { 16 die "FAILED!" 17 if rand() < 0.5; 18 }
  • 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. Problems with “semi-modern” Perl exceptions • If $@ is a string, you’re depending on duplicated information, which will break.
  • 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 error 12 } 13 elsif( $_ =~ /another error/ ) { 14 # handle another error 15 } 16 else { # not sure what the problem is, just give up 17 confess( $_ ); 18 } 19 };
  • 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 error 12 } 13 elsif( $_ =~ /another error/ ) { 14 # handle another error 15 } 16 else { # not sure what the problem is, just give up 17 confess( $_ ); 18 } 19 };
  • 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. 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. 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. 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. So what’s the solution?
  • 31. So what’s the solution? • die() can also take a reference as an argument
  • 32. So what’s the solution? • die() can also take a reference as an argument • So you can die() with an object!
  • 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. 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. A framework for structured exceptions: Exception::Class use Exception::Class (     'MyException',       'AnotherException' => { isa => 'MyException' },       'YetAnotherException' => {         isa         => 'AnotherException',         description => 'These exceptions are related to IPC'     },       'ExceptionWithFields' => {         isa    => 'YetAnotherException',         fields => [ 'grandiosity', 'quixotic' ],     }, );
  • 36. A framework for structured exceptions: Exception::Class # try eval { MyException->throw( error => 'I feel funny.' ) };   my $e;  # catch if ( $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; }
  • 38. Exception::Class Pros • Nice declarative syntax
  • 39. Exception::Class Pros • Nice declarative syntax • Possible to declare detailed or simple exception class hierarchies very simply
  • 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
  • 42. Exception::Class Cons • Not really designed for use with Try::Tiny
  • 43. Exception::Class Cons • Not really designed for use with Try::Tiny • Based on Class::Data::Inheritable, not Moose
  • 44. A Moose role for structured exceptions: Throwable package Redirect; use Moose; with 'Throwable';   has url => (is => 'ro'); ...then later... Redirect->throw({ url => $url });
  • 46. Throwable Pros • Implemented as a Moose role, so your exception classes are just normal Moose classes that consume the role
  • 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. 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.
  • 51. Throwable Cons ? So far, I haven’t really found any.
  • 52. Throwable Cons ? So far, I haven’t really found any. (Of course, that doesn’t mean there aren’t any...)
  • 53. Error Handling Patterns & Anti-Patterns
  • 54. Error Handling Patterns & Anti-Patterns • DO use exceptions instead of error flags
  • 55. Error Handling Patterns & Anti-Patterns • DO use exceptions instead of error flags • DO throw exceptions as early as possible
  • 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. 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. 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(); 10 11 my $step_two_result = $c->model('BusinessLogic')->do_step_two( $step_one_result, $session ); 12 $c->detach( 'error' ) if $session->has_error(); 13 14 $c->stash({ 15 one => $step_one_result , 16 two => $step_two_result , 17 }); 18 }
  • 59. Use exceptions instead of error flags Please please please don’t write code like this!
  • 60. Use exceptions instead of error flags
  • 61. Use exceptions instead of error flags • Forget just one of those checks and you’ve got a hard to track down bug
  • 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. 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. 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 13 $c->stash({ 14 one => $step_one_result , 15 two => $step_two_result , 16 }); 17 }
  • 65. Throw exceptions as early as possible
  • 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. 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.
  • 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. 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. 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. 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 ); 9 10 $c->stash({ 11 message => $message , 12 template => 'error', 13 }); 14 }
  • 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 ); 9 10 $c->stash({ 11 message => $message , 12 template => 'error', 13 }); 14 } (again, not the best example ever...)
  • 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. Thanks for your time this evening!

Editor's Notes