SlideShare ist ein Scribd-Unternehmen logo
1 von 24
Downloaden Sie, um offline zu lesen
Elegant error-handling
for a more civilised age
IN/Clojure'18
Varun Sharma | @var_united
About me
Software engineer at SAP Concur
Website: varunited.github.io
Twitter: @var_united
About talk
Discuss some of my learnings and experiences with error-
handling.
Motivation for cutting loose from some common Clojure
idioms.
Demo app
Blogging service: https://github.com/varunited/demo-blog
Save a new
Blog post
Error-Handling by
Convention
(defn save-story [request owner-id]
(if (= (content-type? request) "application/json")
(let [payload (->> request
req/read-json-body
(validate-new-story-map owner-id))]
(if (contains? payload :tag)
(border/err-handler payload)
(let [service-response (service/save-story
(util/clean-uuid owner-id) payload)]
(if (contains? service-response :tag)
(border/err-handler service-response)
(res/json-response
{:status 201 :data service-response})))))
(border/err-handler
{:tag :bad-input
:message "Expected content-type: application/json"})))
Web Validations
Content-Type:application-
json
Valid? Input JSON
service/save-story
201 Return story-id
(defn valid-email-id? [email-id]
(re-matches #".+@.+..+" email-id))
(defn save-story [owner-id {:keys [email-id] :as new-story}]
(if-not (valid-email-id? email-id)
{:tag :bad-input
:message "Invalid email-id"}
(try
(let [story-id (util/clean-uuid)]
(do (db/save-story owner-id story-id new-story)
{:story-id story-id}))
(catch SQLException e
(throw (ex-info "Unable to save new story"
{:owner-id owner-id}))))))
Service errors & DB call
Valid? Input data
Insert data in DB
The Problems with the Convention
Spaghetti code does not scale
Refactoring becomes harder
Code is difficult to maintain
Lack of referential transparency
Exception-based error handling accentuates imperativeness
which makes the code brittle and hard to reason about
Composability is compromised when exceptions are thrown
What about exception handling?
"The Magical Number Seven, Plus or Minus
Two"
- George Miller
(defn save-story [request owner-id]
(if (= (content-type? request) "application/json")
(let [payload (->> request
req/read-json-body
(validate-new-story-map owner-id))]
(if (contains? payload :tag)
(err-handler payload)
(let [service-response (service/save-story
(util/clean-uuid owner-id)
payload)]
(if (contains? service-response :tag)
(err-handler service-response)
(res/json-response
{:status 201 :data service-response})))))
(err-handler
{:tag :bad-input
:message "Expected content-type: application/json"})))
Error-handling vs Business logic
(defn save-story
[owner-id {:keys [email-id] :as new-story}]
(if (not (valid-email-id? email-id))
{:tag :bad-input :message "Invalid email-id"}
(let [story-id (util/clean-uuid)]
(do (db/save-story owner-id story-id new-story)
{:story-id story-id}))
(catch SQLException e
(throw (ex-info "Unable to save new story" {}))))))
How Can We Do Better?
A Mechanism:
To represent each unit of computation either a success or a
failure
Operation
Failure/Success
To decouple the result of 'if' and 'when' from 'then' or 'else'
Expressing Success and Failure
Source code (promenade): https://github.com/kumarshantanu/promenade
Failure may be expressed as (prom/fail failure), for example:
(ns demo-blog.web
(:require
[promenade.core :as prom]))
(prom/fail {:error "Story not found"
:type :not-found})
Any regular value that is not a Failure is considered Success.
REPL Output
#promenade.internal.Failure
{:failure {:error "Story not found",
:type :not-found}}
Handling Success and Failure Outcomes
Here either->> is a thread-last macro acting on the result of the previous step
A non-vector expression (list-stories) is treated as a success-handler, which is
invoked if the previous step was a success
A failure-handler is specified in a vector form: [failure-handler success-
handler] (failure->resp), which is invoked if list-stories was a failure
(prom/either->> owner-id
list-stories
[failure->resp respond-200])
Extending the chain
(prom/either->> owner-id
validate-input
list-stories
[failure->resp respond-200])
(prom/either->> owner-id
validate-input
list-stories
kebab->camel
[failure->resp respond-200])
Valid? Input JSON
Case conversion
Similarly we can chain together operations using macros: either-> & either-as->
(defn m-save-story [request owner-id]
(prom/either->>
(v/m-validate-content-type request "application/json")
v/m-read-json-body-as-map
(m-validate-new-story-input owner-id)
(service/m-save-story (util/clean-uuid owner-id))
[border/failure->resp border/respond-201]))
Web Validations
(defn m-validate-new-story-input
[owner-id {:keys [heading content email-id] :as story-map}]
(if (and
(s/valid? ::owner-id owner-id)
(s/valid? story-spec {::heading heading
::content content
::email-id email-id}))
story-map
(prom/fail {:error "Bad input"
:source :web
:type :bad-input})))
(defn m-save-story [owner-id {:keys [email-id] :as new-story}]
(if-not (valid-email-id? email-id)
(prom/fail {:error "Invalid email-id"
:source :service
:type :bad-input})
(try
(let [story-id (util/clean-uuid)]
(do (db/save-story owner-id story-id new-story)
{:story-id story-id}))
(catch SQLException e
(prom/fail {:error "Unable to save new story"
:source :execution
:type :unavailable})))))
Service Errors
Error-handling vs Business logic
(defn m-validate-new-story-input
[owner-id {:keys [heading
content
email-id] :as story-map}]
(if (and
(s/valid? ::owner-id owner-id)
(s/valid? story-spec {::heading heading
::content content
::email-id email-id}))
story-map
(prom/fail {:error "Bad input"
:source :web
:type :bad-input})))
(defn m-save-story [request owner-id]
(prom/either->> (v/m-validate-content-type request "application/json")
v/m-read-json-body-as-map
camel->kebab
(m-validate-new-story-input owner-id)
(service/m-save-story (util/clean-uuid owner-id))
kebab->camel
[border/failure->resp border/respond-201]))
Conclusions
References:
Sample app : https://github.com/varunited/demo-blog
Libraries:
Promenade: https://github.com/kumarshantanu/promenade
Ringbelt: https://github.com/kumarshantanu/ringbelt
Exception free error handling in Clojure:
https://adambard.com/blog/introducing-failjure
Thank You!

Weitere ähnliche Inhalte

Was ist angesagt?

Extending Ajax Events for all mankind
Extending Ajax Events for all mankindExtending Ajax Events for all mankind
Extending Ajax Events for all mankindKyle Simpson
 
Effective C++/WinRT for UWP and Win32
Effective C++/WinRT for UWP and Win32Effective C++/WinRT for UWP and Win32
Effective C++/WinRT for UWP and Win32Windows Developer
 
Send, pass, get variables with php, form, html & java script code
Send, pass, get variables with php, form, html & java script codeSend, pass, get variables with php, form, html & java script code
Send, pass, get variables with php, form, html & java script codeNoushadur Shoukhin
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Codescidept
 
End-to-end web-testing in ruby ecosystem
End-to-end web-testing in ruby ecosystemEnd-to-end web-testing in ruby ecosystem
End-to-end web-testing in ruby ecosystemAlex Mikitenko
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Michelangelo van Dam
 
Some tips to improve developer experience with Symfony
Some tips to improve developer experience with SymfonySome tips to improve developer experience with Symfony
Some tips to improve developer experience with Symfonytyomo4ka
 
Laravel Design Patterns
Laravel Design PatternsLaravel Design Patterns
Laravel Design PatternsBobby Bouwmann
 
Desenvolvendo APIs usando Rails - Guru SC 2012
Desenvolvendo APIs usando Rails - Guru SC 2012Desenvolvendo APIs usando Rails - Guru SC 2012
Desenvolvendo APIs usando Rails - Guru SC 2012Rafael Felix da Silva
 
Php Unit With Zend Framework Zendcon09
Php Unit With Zend Framework   Zendcon09Php Unit With Zend Framework   Zendcon09
Php Unit With Zend Framework Zendcon09Michelangelo van Dam
 

Was ist angesagt? (12)

Extending Ajax Events for all mankind
Extending Ajax Events for all mankindExtending Ajax Events for all mankind
Extending Ajax Events for all mankind
 
Effective C++/WinRT for UWP and Win32
Effective C++/WinRT for UWP and Win32Effective C++/WinRT for UWP and Win32
Effective C++/WinRT for UWP and Win32
 
Send, pass, get variables with php, form, html & java script code
Send, pass, get variables with php, form, html & java script codeSend, pass, get variables with php, form, html & java script code
Send, pass, get variables with php, form, html & java script code
 
wp-n00b.php
wp-n00b.phpwp-n00b.php
wp-n00b.php
 
scope or not?
scope or not?scope or not?
scope or not?
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Code
 
End-to-end web-testing in ruby ecosystem
End-to-end web-testing in ruby ecosystemEnd-to-end web-testing in ruby ecosystem
End-to-end web-testing in ruby ecosystem
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
 
Some tips to improve developer experience with Symfony
Some tips to improve developer experience with SymfonySome tips to improve developer experience with Symfony
Some tips to improve developer experience with Symfony
 
Laravel Design Patterns
Laravel Design PatternsLaravel Design Patterns
Laravel Design Patterns
 
Desenvolvendo APIs usando Rails - Guru SC 2012
Desenvolvendo APIs usando Rails - Guru SC 2012Desenvolvendo APIs usando Rails - Guru SC 2012
Desenvolvendo APIs usando Rails - Guru SC 2012
 
Php Unit With Zend Framework Zendcon09
Php Unit With Zend Framework   Zendcon09Php Unit With Zend Framework   Zendcon09
Php Unit With Zend Framework Zendcon09
 

Ähnlich wie Elegant Error-Handling for a More Civilized Age

Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsFrancois Zaninotto
 
Camunda BPM 7.2: Tasklist and Javascript Forms SDK (English)
Camunda BPM 7.2: Tasklist and Javascript Forms SDK (English)Camunda BPM 7.2: Tasklist and Javascript Forms SDK (English)
Camunda BPM 7.2: Tasklist and Javascript Forms SDK (English)camunda services GmbH
 
Design Summit - Rails 4 Migration - Aaron Patterson
Design Summit - Rails 4 Migration - Aaron PattersonDesign Summit - Rails 4 Migration - Aaron Patterson
Design Summit - Rails 4 Migration - Aaron PattersonManageIQ
 
And the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportAnd the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportBen Scofield
 
How to write not breakable unit tests
How to write not breakable unit testsHow to write not breakable unit tests
How to write not breakable unit testsRafal Ksiazek
 
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...Coupa Software
 
Reactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaReactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaHermann Hueck
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js frameworkBen Lin
 
Roman Schejbal: From Madness To Reason
Roman Schejbal: From Madness To ReasonRoman Schejbal: From Madness To Reason
Roman Schejbal: From Madness To ReasonDevelcz
 
Re-Design with Elixir/OTP
Re-Design with Elixir/OTPRe-Design with Elixir/OTP
Re-Design with Elixir/OTPMustafa TURAN
 
Introduction to Javascript
Introduction to JavascriptIntroduction to Javascript
Introduction to Javascriptambuj pathak
 
If love is_blind_-_tiffany
If love is_blind_-_tiffanyIf love is_blind_-_tiffany
If love is_blind_-_tiffanytenka
 
Curso Symfony - Clase 4
Curso Symfony - Clase 4Curso Symfony - Clase 4
Curso Symfony - Clase 4Javier Eguiluz
 
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2Rob Tweed
 
WordPress Plugin development
WordPress Plugin developmentWordPress Plugin development
WordPress Plugin developmentMostafa Soufi
 
Performance and Scalability Testing with Python and Multi-Mechanize
Performance and Scalability Testing with Python and Multi-MechanizePerformance and Scalability Testing with Python and Multi-Mechanize
Performance and Scalability Testing with Python and Multi-Mechanizecoreygoldberg
 

Ähnlich wie Elegant Error-Handling for a More Civilized Age (20)

Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 
Camunda BPM 7.2: Tasklist and Javascript Forms SDK (English)
Camunda BPM 7.2: Tasklist and Javascript Forms SDK (English)Camunda BPM 7.2: Tasklist and Javascript Forms SDK (English)
Camunda BPM 7.2: Tasklist and Javascript Forms SDK (English)
 
Laravel tips-2019-04
Laravel tips-2019-04Laravel tips-2019-04
Laravel tips-2019-04
 
Design Summit - Rails 4 Migration - Aaron Patterson
Design Summit - Rails 4 Migration - Aaron PattersonDesign Summit - Rails 4 Migration - Aaron Patterson
Design Summit - Rails 4 Migration - Aaron Patterson
 
And the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportAnd the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack Support
 
How to write not breakable unit tests
How to write not breakable unit testsHow to write not breakable unit tests
How to write not breakable unit tests
 
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
 
Reactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaReactive Access to MongoDB from Scala
Reactive Access to MongoDB from Scala
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js framework
 
Django Vs Rails
Django Vs RailsDjango Vs Rails
Django Vs Rails
 
A First Date With Scala
A First Date With ScalaA First Date With Scala
A First Date With Scala
 
Roman Schejbal: From Madness To Reason
Roman Schejbal: From Madness To ReasonRoman Schejbal: From Madness To Reason
Roman Schejbal: From Madness To Reason
 
Re-Design with Elixir/OTP
Re-Design with Elixir/OTPRe-Design with Elixir/OTP
Re-Design with Elixir/OTP
 
Introduction to Javascript
Introduction to JavascriptIntroduction to Javascript
Introduction to Javascript
 
Web-First Design Patterns
Web-First Design PatternsWeb-First Design Patterns
Web-First Design Patterns
 
If love is_blind_-_tiffany
If love is_blind_-_tiffanyIf love is_blind_-_tiffany
If love is_blind_-_tiffany
 
Curso Symfony - Clase 4
Curso Symfony - Clase 4Curso Symfony - Clase 4
Curso Symfony - Clase 4
 
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2
 
WordPress Plugin development
WordPress Plugin developmentWordPress Plugin development
WordPress Plugin development
 
Performance and Scalability Testing with Python and Multi-Mechanize
Performance and Scalability Testing with Python and Multi-MechanizePerformance and Scalability Testing with Python and Multi-Mechanize
Performance and Scalability Testing with Python and Multi-Mechanize
 

Kürzlich hochgeladen

VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyviewmasabamasaba
 
tonesoftg
tonesoftgtonesoftg
tonesoftglanshi9
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionOnePlan Solutions
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in sowetomasabamasaba
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech studentsHimanshiGarg82
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park masabamasaba
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...masabamasaba
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfkalichargn70th171
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...masabamasaba
 
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...Shane Coughlan
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Hararemasabamasaba
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Bert Jan Schrijver
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 

Kürzlich hochgeladen (20)

VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 

Elegant Error-Handling for a More Civilized Age

  • 1. Elegant error-handling for a more civilised age IN/Clojure'18 Varun Sharma | @var_united
  • 2. About me Software engineer at SAP Concur Website: varunited.github.io Twitter: @var_united
  • 3. About talk Discuss some of my learnings and experiences with error- handling. Motivation for cutting loose from some common Clojure idioms.
  • 4. Demo app Blogging service: https://github.com/varunited/demo-blog
  • 7. (defn save-story [request owner-id] (if (= (content-type? request) "application/json") (let [payload (->> request req/read-json-body (validate-new-story-map owner-id))] (if (contains? payload :tag) (border/err-handler payload) (let [service-response (service/save-story (util/clean-uuid owner-id) payload)] (if (contains? service-response :tag) (border/err-handler service-response) (res/json-response {:status 201 :data service-response}))))) (border/err-handler {:tag :bad-input :message "Expected content-type: application/json"}))) Web Validations Content-Type:application- json Valid? Input JSON service/save-story 201 Return story-id
  • 8. (defn valid-email-id? [email-id] (re-matches #".+@.+..+" email-id)) (defn save-story [owner-id {:keys [email-id] :as new-story}] (if-not (valid-email-id? email-id) {:tag :bad-input :message "Invalid email-id"} (try (let [story-id (util/clean-uuid)] (do (db/save-story owner-id story-id new-story) {:story-id story-id})) (catch SQLException e (throw (ex-info "Unable to save new story" {:owner-id owner-id})))))) Service errors & DB call Valid? Input data Insert data in DB
  • 9. The Problems with the Convention Spaghetti code does not scale Refactoring becomes harder Code is difficult to maintain
  • 10. Lack of referential transparency Exception-based error handling accentuates imperativeness which makes the code brittle and hard to reason about Composability is compromised when exceptions are thrown What about exception handling?
  • 11. "The Magical Number Seven, Plus or Minus Two" - George Miller
  • 12. (defn save-story [request owner-id] (if (= (content-type? request) "application/json") (let [payload (->> request req/read-json-body (validate-new-story-map owner-id))] (if (contains? payload :tag) (err-handler payload) (let [service-response (service/save-story (util/clean-uuid owner-id) payload)] (if (contains? service-response :tag) (err-handler service-response) (res/json-response {:status 201 :data service-response}))))) (err-handler {:tag :bad-input :message "Expected content-type: application/json"}))) Error-handling vs Business logic
  • 13. (defn save-story [owner-id {:keys [email-id] :as new-story}] (if (not (valid-email-id? email-id)) {:tag :bad-input :message "Invalid email-id"} (let [story-id (util/clean-uuid)] (do (db/save-story owner-id story-id new-story) {:story-id story-id})) (catch SQLException e (throw (ex-info "Unable to save new story" {}))))))
  • 14. How Can We Do Better?
  • 15. A Mechanism: To represent each unit of computation either a success or a failure Operation Failure/Success To decouple the result of 'if' and 'when' from 'then' or 'else'
  • 16. Expressing Success and Failure Source code (promenade): https://github.com/kumarshantanu/promenade Failure may be expressed as (prom/fail failure), for example: (ns demo-blog.web (:require [promenade.core :as prom])) (prom/fail {:error "Story not found" :type :not-found}) Any regular value that is not a Failure is considered Success. REPL Output #promenade.internal.Failure {:failure {:error "Story not found", :type :not-found}}
  • 17. Handling Success and Failure Outcomes Here either->> is a thread-last macro acting on the result of the previous step A non-vector expression (list-stories) is treated as a success-handler, which is invoked if the previous step was a success A failure-handler is specified in a vector form: [failure-handler success- handler] (failure->resp), which is invoked if list-stories was a failure (prom/either->> owner-id list-stories [failure->resp respond-200])
  • 18. Extending the chain (prom/either->> owner-id validate-input list-stories [failure->resp respond-200]) (prom/either->> owner-id validate-input list-stories kebab->camel [failure->resp respond-200]) Valid? Input JSON Case conversion Similarly we can chain together operations using macros: either-> & either-as->
  • 19. (defn m-save-story [request owner-id] (prom/either->> (v/m-validate-content-type request "application/json") v/m-read-json-body-as-map (m-validate-new-story-input owner-id) (service/m-save-story (util/clean-uuid owner-id)) [border/failure->resp border/respond-201])) Web Validations (defn m-validate-new-story-input [owner-id {:keys [heading content email-id] :as story-map}] (if (and (s/valid? ::owner-id owner-id) (s/valid? story-spec {::heading heading ::content content ::email-id email-id})) story-map (prom/fail {:error "Bad input" :source :web :type :bad-input})))
  • 20. (defn m-save-story [owner-id {:keys [email-id] :as new-story}] (if-not (valid-email-id? email-id) (prom/fail {:error "Invalid email-id" :source :service :type :bad-input}) (try (let [story-id (util/clean-uuid)] (do (db/save-story owner-id story-id new-story) {:story-id story-id})) (catch SQLException e (prom/fail {:error "Unable to save new story" :source :execution :type :unavailable}))))) Service Errors
  • 21. Error-handling vs Business logic (defn m-validate-new-story-input [owner-id {:keys [heading content email-id] :as story-map}] (if (and (s/valid? ::owner-id owner-id) (s/valid? story-spec {::heading heading ::content content ::email-id email-id})) story-map (prom/fail {:error "Bad input" :source :web :type :bad-input}))) (defn m-save-story [request owner-id] (prom/either->> (v/m-validate-content-type request "application/json") v/m-read-json-body-as-map camel->kebab (m-validate-new-story-input owner-id) (service/m-save-story (util/clean-uuid owner-id)) kebab->camel [border/failure->resp border/respond-201]))
  • 23. References: Sample app : https://github.com/varunited/demo-blog Libraries: Promenade: https://github.com/kumarshantanu/promenade Ringbelt: https://github.com/kumarshantanu/ringbelt Exception free error handling in Clojure: https://adambard.com/blog/introducing-failjure