Managing errors the right way in Scala

46
2014-10-{23,24} Managing errors the right way in Scala François ARMAND CTO - Normation [email protected]

description

A presentation of how to managing errors in Scala, getting all the current way of doing it one by one: exception, Option, Either, Try, Box. All these solutions have major drowback, so we end-up using a solution with a clean theorical background: scalaz.Validation and scalaz.\/. But as that last solution is a little raw, I explain how to add syntactic sugar to get nice error logic on top of \/: building a nice generic Fail type with message and root cause, sugar to stack messages, display them, get root cause, etc. Code is available on Github: https://github.com/fanf/scalaio_2014

Transcript of Managing errors the right way in Scala

Page 1: Managing errors the right way in Scala

2014-10-{23,24}

Managing errors the right way in Scala

François ARMANDCTO - Normation

[email protected]

Page 2: Managing errors the right way in Scala

Say hello !

[email protected] / @fanf42

François ARMAND

Co-founder & CTO Lead-dev

Discovered Scala in 2006

Full time Scala since 2009 And yes, I'm trying to start a side

business in cloning

OSS convinced

Page 3: Managing errors the right way in Scala

What's about ?

The primary duty of an exception handler is to get the error out of the lap of the programmer and into the surprised face of the user. Provided you keep this cardinal rule in mind, you can't go far wrong.

        — Verity Stob

Managing errors so that both futur developpers, ops and users are happy is what differentiate hacking toys projects to building softwares

        — Myself

Page 4: Managing errors the right way in Scala

What's about ?

Sharing the (hard) learned lessons about managing errors in Scala in

our 5 years trip with Rudder

Page 5: Managing errors the right way in Scala

What's about ?

IT infratructure open source automation

+ compliance management

http://www.rudder-project.org

Compliance AgentsServer

Scala web applicationStarted in 2009By ex-java dev

Page 6: Managing errors the right way in Scala

Errors ? What's an error ?

■ Who MUST care ? ■ Who MUST handle the problem ?

Something didn't worked as it should

Page 7: Managing errors the right way in Scala

Errors classical classification

▣ Pop culture(1) say :

▣ Technical Errors

■ When your containing universe fails□ Ex : « oups, the underlying OS just ran out of memory »

□ OutOfMemroy Errors, Threads killed, VM crashes...

■ Logical / modeling error□ « no, you really can't access item #42 of that array of size 2 »

■ Systems in relation with yours failed□ Ex : « hello Database ? Helloooooo ? »

□ Mostly I/O errors : connection errors, bad permession on FS...

▣ Business Errors

■ The one the user want to know about

■ Ex : « oups, I can't withdraw $1M from your empty account, because, well, you know »

[1] http://programmer.97things.oreilly.com/wiki/index.php/Distinguish_Business_Exceptions_from_Technical

Page 8: Managing errors the right way in Scala

Errors classical classification

▣ Pop culture(1) say : It's complicated :

▣ Technical Errors

■ When your containing universe fails□ Ex : « oups, the underlying OS just ran out of memory »

□ OutOfMemroy Errors, Threads killed, VM crashes...

■ Logical / modeling error□ « no, you really can't access item #42 of that array of size 2 »

■ Systems in relation with yours failed□ Ex : « hello Database ? Helloooooo ? »

□ Mostly I/O errors : connection errors, bad permession on FS...

▣ Business Errors

■ The one the user want to know about

■ Ex : « oups, I can't withdraw $1M from your empty account, because, well, you know »

That's th

e end of

the univers

e, don't

care

(ops w

ill awake)

[1] http://programmer.97things.oreilly.com/wiki/index.php/Distinguish_Business_Exceptions_from_Technical

Page 9: Managing errors the right way in Scala

Errors classical classification

▣ Pop culture(1) say : It's complicated :

▣ Technical Errors

■ When your containing universe fails□ Ex : « oups, the underlying OS just ran out of memory »

□ OutOfMemroy Errors, Threads killed, VM crashes...

■ Logical / modeling error□ « no, you really can't access item #42 of that array of size 2 »

■ Systems in relation with yours failed□ Ex : « hello Database ? Helloooooo ? »

□ Mostly I/O errors : connection errors, bad permession on FS...

▣ Business Errors

■ The one the user want to know about

■ Ex : « oups, I can't withdraw $1M from your empty account, because, well, you know »

That should

be

modeled in

data ty

pe

[1] http://programmer.97things.oreilly.com/wiki/index.php/Distinguish_Business_Exceptions_from_Technical

That's th

e end of

the univers

e, don't

care

(ops w

ill awake)

Page 10: Managing errors the right way in Scala

Errors classical classification

▣ Pop culture(1) say : It's complicated :

▣ Technical Errors

■ When your containing universe fails□ Ex : « oups, the underlying OS just ran out of memory »

□ OutOfMemroy Errors, Threads killed, VM crashes...

■ Logical / modeling error□ « no, you really can't access item #42 of that array of size 2 »

■ Systems in relation with yours failed□ Ex : « hello Database ? Helloooooo ? »

□ Mostly I/O errors : connection errors, bad permession on FS...

▣ Business Errors

■ The one the user want to know about

■ Ex : « oups, I can't withdraw $1M from your empty account, because, well, you know »

Always t

he business

of som

ebody :

dev, ops,

final u

ser

[1] http://programmer.97things.oreilly.com/wiki/index.php/Distinguish_Business_Exceptions_from_Technical

That should

be

modeled in

data ty

pe

That's th

e end of

the univers

e, don't

care

(ops w

ill awake)

Page 11: Managing errors the right way in Scala

Errors classical classification

▣ Pop culture(1) say : It's complicated :

▣ Technical Errors

■ When your containing universe fails□ Ex : « oups, the underlying OS just ran out of memory »

□ OutOfMemroy Errors, Threads killed, VM crashes...

■ Logical / modeling error□ « no, you really can't access item #42 of that array of size 2 »

■ Systems in relation with yours failed□ Ex : « hello Database ? Helloooooo ? »

□ Mostly I/O errors : connection errors, bad permession on FS...

▣ Business Errors

■ The one the user want to know about

■ Ex : « oups, I can't withdraw $1M from your empty account, because, well, you know »

Always t

he business

of som

ebody :

dev, ops,

final u

ser

[1] http://programmer.97things.oreilly.com/wiki/index.php/Distinguish_Business_Exceptions_from_Technical

That should

be

modeled in

data ty

pe

That's th

e end of

the univers

e, don't

care

(ops w

ill awake)

Page 12: Managing errors the right way in Scala

So, what was our trip in error management land ?

Page 13: Managing errors the right way in Scala

Origins : the dark age of Java Exceptions

▣ Using Java Exception

■ Worst : Business and Technical Exception, enterprisy style

Page 14: Managing errors the right way in Scala

Origins : the dark age of Java Exceptions

▣ Death by one thousand different GoTos

▣ Can't reason about part of the code

■ Hard to understand

■ Hard to compose

■ Hard to refactor

■ Hard to reuse

▣ Exception are the incarnation of side effect

Error management must be referentially transparent

Problems ?

Page 15: Managing errors the right way in Scala

Origins : the dark age of Java Exceptions

▣ Dilution of responsability

■ Nobody ever manage exception in a systematic way

■ Idem in language with error code (C, Python, Go...)

▣ Human being are not very disciplined

■ That why we automate things

Problems ?

Page 16: Managing errors the right way in Scala

Origins : the dark age of Java Exceptions

▣ Human being are not very disciplined

▣ But hey ! Compilers DO ARE very disciplined

▣ Crazy idea:

■ Force the user to take care of failure to reach success values

■ Use a data type denoting Error Or Success

▣ Nice side effects:

■ Clear identification function that could fail in return type

■ Errors as value enable referential transparency

Model faillible code with Algebraic Data Type

Problems ?

Page 17: Managing errors the right way in Scala

Origins : the dark age of Java Exceptions

Exception: far better tools exists (in Scala)

Page 18: Managing errors the right way in Scala

Option to the rescue (really?)

▣ Functionnal programming 101 : use option

■ Option[+A]

□ None

□ Some[+A](x: A)

Need a rich failure type

Page 19: Managing errors the right way in Scala

Option – just to denote missing things

Option : good data type. Not for error.

Its semantic is « MISSING ITEM »

Page 20: Managing errors the right way in Scala

Either to the rescue (ok, still no)

▣ Functionnal programming 101, page 2 : use disjunction

Either[L,R]  : Left[L] : failure and Right[R] : success

But....

Page 21: Managing errors the right way in Scala

Either to the rescue (ok, still no)

▣ Functionnal programming 101, page 2 : use disjunction

Either[L,R]  : Left[L] : failure and Right[R] : success

???Ticket #SI-5793, close won't fix

No boilerplate !

Page 22: Managing errors the right way in Scala

Either – for the boilerplate lovers

Either (Scala stdlib): not tailored for errors

Page 23: Managing errors the right way in Scala

Nice try

▣ Try[A] – essentially an Either[Throwable, A]

■ Nice on paper (not used in real life)

□ Even with theoric hole (see « Try and monad laws »)

■ But really ? Everything is an exception ?

Need a rich failure type

Page 24: Managing errors the right way in Scala

Try – when all your errors are exception

Try: NOT ALL errors are exceptions

Oh, and what could go wrong with ignoring theory ?

Page 25: Managing errors the right way in Scala

A Lift gift in a Box

▣ Lift, that new web framework (2009 style)

▣ Box[T] : data structure with 3 cases :

■ Full[+A](value: A) extends Box[A]□ a success that hold your item of type T

■ EmptyBox extends Box[Nothing] (abstract)

□ Empty : no results (None for Option) extends EmptyBox

□ Failure(msg: String, exception: Box[Throwable]

, chain: Box[Failure]) extends EmptyBox

Page 26: Managing errors the right way in Scala

A Lift gift in a Box

Page 27: Managing errors the right way in Scala

A Lift gift in a Box – with error tooling !

Page 28: Managing errors the right way in Scala

A Lift gift in a Box – with error tooling !

Tooling and error lexical field helps

Page 29: Managing errors the right way in Scala

A Lift gift in a Box – with error tooling !

But....

Page 30: Managing errors the right way in Scala

So bad it was offered by Pandora

▣ getUser(User("fanf42")) === Empty.

■ What do you thing it means ?

■ Depending of the dev, the refactorer, the tests, it's an error without message.

■ Or a missing item.

▣ In Rudder, the most surprising error where due to Empty

■ Surprise is a bad thing: Empty is forbidden.

■ Object DB { def getUser(id : UserId) : Box[Option[User]] }

Must be Unambiguious

Page 31: Managing errors the right way in Scala

(Pandora) Box might have been good

Box: good tooling, too much ambiguity

Page 32: Managing errors the right way in Scala

Finally, let's go shopping ?

So, no error management framework ?

Page 33: Managing errors the right way in Scala

Desirable properties of error management

Must be Unambiguious

Error management must be referentially transparent

Need a rich failure type

No boilerplate !

Tooling and error lexical field helps

Model faillible code with Algebraic Data Type

Page 34: Managing errors the right way in Scala

It's a kind of magic

▣ You know what ? People worked on theory about that. ■ Theory-backed model free you mind : you know it WILL work. It's proved

■ http://typelevel.org/blog/2014/02/21/error-handling.html

■ http://stackoverflow.com/questions/12307965/method-parameters-validation-in-scala-with-for-comprehension-and-monads/12309023#12309023

Page 35: Managing errors the right way in Scala

Independant Errors Dependant Errors

▣ Form validation

▣ Accumulate them

▣ « best-effort »

▣ List of I/O actions

▣ Chain them

▣ Stop early

Theory says

Scalaz.Validation(applicative functor)

Scalaz.\/(monad)

Page 36: Managing errors the right way in Scala

Independant Errors

▣ Form validation

▣ Accumulate them

▣ « best-effort »

Theory says

Scalaz.Validation(applicative functor)

Page 37: Managing errors the right way in Scala

Scalaz.Validation – accumulating errrors

▣ It's an applicative functor : no for-comprehension

Page 38: Managing errors the right way in Scala

Dependant Errors

▣ List of I/O actions

▣ Chain them

▣ Stop early

Theory says

Scalaz.\/(monad)

Page 39: Managing errors the right way in Scala

Scalaz disjunction – a sane Either

Page 40: Managing errors the right way in Scala

So, no shopping after all ?

▣ Validation is great for applicative style failure.

■ It's more generic / less powerful

■ In fact only used in very specific cases

▣ \/ is great for general error management

■ Toward monadic application

▣ But...

Page 41: Managing errors the right way in Scala

Tooling on top of \/ (and Validation)

▣ Nothing in \/ is in the semantic domain of errors.

▣ And it's desirable to have :

■ One default generic Failure data structure

■ With tooling (message, root cause, etc)

■ À la Box.

▣ Some leads to follow :

■ Design your own Failure with sugar to add messages / Throwable

■ User library extension with implicit to add more sugar

What follows are JUST ideas and example

Page 42: Managing errors the right way in Scala

Tooling on top of \/ (and Validation)

A dedicated Fail data type

Page 43: Managing errors the right way in Scala

Tooling on top of \/ (and Validation)

A dedicated Error data type

Page 44: Managing errors the right way in Scala

Tooling on top of \/ (and Validation)

Page 45: Managing errors the right way in Scala

Tooling on top of \/ (and Validation)

Page 46: Managing errors the right way in Scala

2014-10-{23,24}

Questions ?

[email protected] / @fanf42

François ARMAND

Code available on GitHub : https://github.com/fanf/scalaio_2014