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

Viewers also liked (16)

PPT
Криокомплекс
kulibin
 
PPTX
Keith hopper-product-market-fit
hopperomatic
 
PPT
正向積極成功學
yourwater
 
PPTX
Сектор_НИТ_отдела_Технического_творчества_МГДД(Ю)Т
Ivan Dementiev
 
PPT
Social media strategies for dr. pfahl class, 8 13
Game Day Communications
 
PPTX
Hidden gluteninthankgivingmeal
Glutagest
 
PDF
Managing risk in challenging economic times
The Economist Media Businesses
 
PPT
АВтоматизированный Расчет Операционных РАзмеров
kulibin
 
PDF
Mi primer dibujo
Johanna Marcatoma
 
PDF
5 Things Everyone Should Know about Low-Calorie Sweeteners
Food Insight
 
PDF
מצגת כיתה ט
guest27a22b
 
PDF
Curation Nation
Social Media Club
 
PPT
Система передачи субмиллиметровых биологических сигналов
kulibin
 
PDF
Ipsos MORI Scotland Opinion Monitor - Lockerbie - October 2011
Ipsos UK
 
PDF
Apresentando ideias com Prezi
Marcio Okabe
 
PDF
Innovations New World Order
Strategy&, a member of the PwC network
 
Криокомплекс
kulibin
 
Keith hopper-product-market-fit
hopperomatic
 
正向積極成功學
yourwater
 
Сектор_НИТ_отдела_Технического_творчества_МГДД(Ю)Т
Ivan Dementiev
 
Social media strategies for dr. pfahl class, 8 13
Game Day Communications
 
Hidden gluteninthankgivingmeal
Glutagest
 
Managing risk in challenging economic times
The Economist Media Businesses
 
АВтоматизированный Расчет Операционных РАзмеров
kulibin
 
Mi primer dibujo
Johanna Marcatoma
 
5 Things Everyone Should Know about Low-Calorie Sweeteners
Food Insight
 
מצגת כיתה ט
guest27a22b
 
Curation Nation
Social Media Club
 
Система передачи субмиллиметровых биологических сигналов
kulibin
 
Ipsos MORI Scotland Opinion Monitor - Lockerbie - October 2011
Ipsos UK
 
Apresentando ideias com Prezi
Marcio Okabe
 
Innovations New World Order
Strategy&, a member of the PwC network
 

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

ODP
Perl exceptions lightning talk
Peter Edwards
 
PPTX
Corinna-2023.pptx
Curtis Poe
 
PDF
Perl Sucks - and what to do about it
2shortplanks
 
PDF
Catch Me If You Can: Sugary Exception Handling in Perl
Ash Berlin
 
ODP
Exception Handling in Perl
Ian Kluft
 
PDF
Php exceptions
Damian Sromek
 
PDF
Exception Handling: Designing Robust Software in Ruby
Wen-Tien Chang
 
PPTX
Exceptions in Java
Vadym Lotar
 
PPT
Standard exceptions
Mohamad Al_hsan
 
PDF
Elegant Ways of Handling PHP Errors and Exceptions
ZendCon
 
PDF
Exceptions in PHP
JanTvrdik
 
PDF
Perl Critic In Depth
Jeffrey Ryan Thalhammer
 
PDF
Introduction to Writing Readable and Maintainable Perl (YAPC::EU 2011 Version)
Alex Balhatchet
 
PPT
Exception handling
zindadili
 
PDF
Introduction to writing readable and maintainable Perl
Alex Balhatchet
 
PPTX
Exception handling
Abhishek Pachisia
 
PDF
Working Effectively With Legacy Perl Code
erikmsp
 
PPT
Exceptions in Ruby - Tips and Tricks
Dimelo R&D Team
 
PDF
Getting testy with Perl
Workhorse Computing
 
PPTX
Lecture 3.1.1 Try Throw Catch.pptx
sunilsoni446112
 
Perl exceptions lightning talk
Peter Edwards
 
Corinna-2023.pptx
Curtis Poe
 
Perl Sucks - and what to do about it
2shortplanks
 
Catch Me If You Can: Sugary Exception Handling in Perl
Ash Berlin
 
Exception Handling in Perl
Ian Kluft
 
Php exceptions
Damian Sromek
 
Exception Handling: Designing Robust Software in Ruby
Wen-Tien Chang
 
Exceptions in Java
Vadym Lotar
 
Standard exceptions
Mohamad Al_hsan
 
Elegant Ways of Handling PHP Errors and Exceptions
ZendCon
 
Exceptions in PHP
JanTvrdik
 
Perl Critic In Depth
Jeffrey Ryan Thalhammer
 
Introduction to Writing Readable and Maintainable Perl (YAPC::EU 2011 Version)
Alex Balhatchet
 
Exception handling
zindadili
 
Introduction to writing readable and maintainable Perl
Alex Balhatchet
 
Exception handling
Abhishek Pachisia
 
Working Effectively With Legacy Perl Code
erikmsp
 
Exceptions in Ruby - Tips and Tricks
Dimelo R&D Team
 
Getting testy with Perl
Workhorse Computing
 
Lecture 3.1.1 Try Throw Catch.pptx
sunilsoni446112
 
Ad

More from John Anderson (20)

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

Recently uploaded (20)

PDF
July Patch Tuesday
Ivanti
 
PDF
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
PDF
Blockchain Transactions Explained For Everyone
CIFDAQ
 
PDF
Fl Studio 24.2.2 Build 4597 Crack for Windows Free Download 2025
faizk77g
 
PDF
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
PDF
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
PDF
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
PPTX
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
PPTX
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
PDF
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
PDF
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
PDF
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
PPTX
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
PDF
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
PPTX
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
PDF
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
PDF
Exolore The Essential AI Tools in 2025.pdf
Srinivasan M
 
PPTX
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
PPTX
OpenID AuthZEN - Analyst Briefing July 2025
David Brossard
 
PPTX
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
July Patch Tuesday
Ivanti
 
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
Blockchain Transactions Explained For Everyone
CIFDAQ
 
Fl Studio 24.2.2 Build 4597 Crack for Windows Free Download 2025
faizk77g
 
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
Exolore The Essential AI Tools in 2025.pdf
Srinivasan M
 
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
OpenID AuthZEN - Analyst Briefing July 2025
David Brossard
 
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 

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