type driven development @ confitura 2014

64
Type driven development Maciek Próchniak

Upload: maciek-prochniak

Post on 29-Nov-2014

112 views

Category:

Software


1 download

DESCRIPTION

Type Driven Development @ Confitura 2014

TRANSCRIPT

Page 1: Type Driven Development @ Confitura 2014

Type driven development

Maciek Próchniak

Page 2: Type Driven Development @ Confitura 2014

Whoami?

Page 3: Type Driven Development @ Confitura 2014

Maciek Próchniak

Algebraic topologyhocolim

Group cohomology

Monads

GWT

TouKCamel

OSGi

CQRS

Scala

Page 4: Type Driven Development @ Confitura 2014

How to prevent bugs?

● Tests● Defensive programming● Tests● Contracts● Tests

Page 5: Type Driven Development @ Confitura 2014

Guerilla defensive programming

Page 6: Type Driven Development @ Confitura 2014

How to prevent bugs?

In the end, having static types is all about preventing bugs by allowing the über-smart compiler to humiliate you on a regular basis, making sure you’re doing the right thing before it’s too late.

(http://danielwestheide.com)

Page 7: Type Driven Development @ Confitura 2014

What bugs?

“Only 1% of issues in Python system are TypeErrors, AttributeErrors, NameErrors”

Page 8: Type Driven Development @ Confitura 2014

What about

● NullPointerException

● (uncaught) IOException

● ArrayOutOfBoundsException

● ItemNotFoundException

Page 9: Type Driven Development @ Confitura 2014

Typesafe stronghold

... strings and nulls shall not overcome

http://en.wikipedia.org/w

iki/File:Cit%

C3%

A9_de_C

arcassonne,_w

oman_on_w

all.jpg

Page 10: Type Driven Development @ Confitura 2014

Security layersmain/servlet

parsing

validation

business “logic”

collections, utils

io

Page 11: Type Driven Development @ Confitura 2014

Scalaz

If you are thinking about using Scalaz, stop now while you still have your sanity!

And don’t get into arguments with the people who suggest that you use it – it is pointless.

Page 12: Type Driven Development @ Confitura 2014

Equal?

long userId = 14

User user = getUser(...)

userId.equals(user)

Page 13: Type Driven Development @ Confitura 2014

Equal?

val userId : Long = 14

val user : User = getUser(...)

import scalaz.syntax.equal._

userId === user

Page 14: Type Driven Development @ Confitura 2014

Names are important

BigDecimal balance;

BigDecimal price;

balance.compareTo(price) > 0

Page 15: Type Driven Development @ Confitura 2014

Names are important

double log(double a)

double log(positiveDouble)

double log(double positive)

double log(PositiveDouble a)

Page 16: Type Driven Development @ Confitura 2014

Tagged types

@Nullable

@Email

@Valid

@Notempty

private String mail

Page 17: Type Driven Development @ Confitura 2014

Oh, really?@PUT

@Path("/fulfilment/address")

@ApiOperation(value = "Set shipping method for cart", response = CartDTO.class)

@ApiResponses(value = {

@ApiResponse(code = 400, message = "Method cannot be used due to bussines rules"),

@ApiResponse(code = 404, message = "Unknown fulfilment option"),

@ApiResponse(response = CartDTO.class, code = 200, message = "Customer cart after selecting fulfilment")})

public CartDTO setFulfillmentAddress(

@ApiParam(value = "New shipping method", required = true) @Valid AddressDTO addressDTO

) throws PricingException, FulfillmentPriceException {

Page 18: Type Driven Development @ Confitura 2014

Tagged types

Double @@ Meter

sealed trait Meter

sealed trait Liter

Page 19: Type Driven Development @ Confitura 2014

Tagged types

val length = Tag[Double,Meter](10)

val capacity = Tag[Double,Liter](10)

length : Double @@ Meter

capacity : Double @@ Liter

length + 15 : Double

Page 20: Type Driven Development @ Confitura 2014

Value classes

Page 21: Type Driven Development @ Confitura 2014

Java??public class LengthInMeters(int value) {

private final int length;

public LengthInMeters(int value) {

this.length = value;

}

public int getValue() {

return length;

}

@Override

public int hashCode() {

return 31 * length;;

}

@Override public boolean equals(Object o) {

if (o == this)

return true;

if (!(o instanceof LengthInMeters))

return false;

LengthInMeters c = (LengthInMeters) o;

return Integer.compare(c.length, length) == 0;

}

}

Page 22: Type Driven Development @ Confitura 2014

Value classes

case class CustomerId(id:String)

extends AnyVal {

def load:Customer

}

def loadFriends

(cid:CustomerId, bid:BranchId)

val cid:CustomerId = parseId(cidString)

Page 23: Type Driven Development @ Confitura 2014

Value classes

implicit class CustomerId(

val id:String) extends AnyVal {

def load:Customer

}

“12345”.load : Customer

Page 24: Type Driven Development @ Confitura 2014

What about

● NullPointerException

● (uncaught) IOException

● ArrayOutOfBoundsException

● ItemNotFoundException

Page 25: Type Driven Development @ Confitura 2014

Option[A]

val maybeResult : Option[Result]

= Option(unsafeResult)

maybeResult.map(_.name):Option[String]

maybeResult

.getOrElse(defaultResult) : Result

maybeResult.get

Page 26: Type Driven Development @ Confitura 2014

Option[String]

val str = Option(“str”)

val none = Option(null)

val none2 = Option.empty[String]

val fake = Some(null)

Page 27: Type Driven Development @ Confitura 2014

Syntax sugar IS important

val maybe = Option.empty[String]

maybe.map(_.toUpperCase)

Page 28: Type Driven Development @ Confitura 2014

Syntax sugar IS importantOptional<String> maybeName =

Optional.absent();

maybeName.transform(

new Function<String, Object>() {

@Override

public Object apply(String s) {

return s.toUpperCase();

}

});

Page 29: Type Driven Development @ Confitura 2014

Syntax sugar IS important

String maybe = null;

if (maybe != null) {

maybe = maybe.toUpperCase();

}

Page 30: Type Driven Development @ Confitura 2014

What about

● NullPointerException

● (uncaught) IOException

● ArrayOutOfBoundsException

● ItemNotFoundException

Page 31: Type Driven Development @ Confitura 2014

IO...

https://www.flickr.com/photos/oddsock/100761143/

Page 32: Type Driven Development @ Confitura 2014

Why not exceptions?

● They are invisible in the source code.● They create too many possible exit points

A better alternative is to have your functions return error values (...), no matter how verbose it might be

Joel Spolsky

Page 33: Type Driven Development @ Confitura 2014

IO[Result]val fileNameIO : IO[String] =

IO { System.getProperty("file.config") }

val config : IO[String] = for {

fileName <- fileNameIO

fileReader = new BufferedReader(

new FileReader(fileName))

line <-safeReadLn(fileReader)

} yield line

val data : String = config.unsafePerformIO

Page 34: Type Driven Development @ Confitura 2014

Security layersmain/servlet

parsing

validation

business “logic”

collections, utils

io

Page 35: Type Driven Development @ Confitura 2014

Mixing stuff

IO[State[Map, String]]

State[Map, IO[String,]]

Page 36: Type Driven Development @ Confitura 2014

Mixing stuff

https://www.flickr.com/photos/oddsock/100761143/

Page 37: Type Driven Development @ Confitura 2014

What about

● NullPointerException

● (uncaught) IOException

● ArrayOutOfBoundsException

● ItemNotFoundException

Page 38: Type Driven Development @ Confitura 2014

Empty list?

val list : List[String]

= Nil

list.head

import scalaz.NonEmptyList

val nel : NonEmptyList[String]

= NonEmptyList(“a”,List(“b”))

nel.head

Page 39: Type Driven Development @ Confitura 2014

Dependent types?

val list : List[String]

val listOfSize5 : List[String,2+3]

def sum[A,L1:Nat,L2:Nat]

(l1 : List[A,L1], l2:List[A,L2])

: List[A,L1+L2]

Page 40: Type Driven Development @ Confitura 2014

Is it a dream?

Page 41: Type Driven Development @ Confitura 2014

Path dependent types

class Family {

case class Child(name : String)

def quarell(child1 : Child,

child2 : Child) {

//blaaah

}

}

Page 42: Type Driven Development @ Confitura 2014

Path dependent types

val kowalscy = new Family()

val nowakowie = new Family()

val pawelK = kowalscy.Child("Pawel")

val pawelN = nowakowie.Child("Pawel")

kowalscy.quarell(pawelK, pawelN)

Page 43: Type Driven Development @ Confitura 2014

Path dependent types

def hide(family:Family)

(child:family.Child) {

}

Page 44: Type Driven Development @ Confitura 2014

Shapeless

"maybe it's bug in compiler, but we'll use it and assume it won't be fixed"

https://github.com/milessabin/shapeless

shapeless is an exploration of generic (aka polytypic) programming in Scala

Page 45: Type Driven Development @ Confitura 2014

Sized[Seq[A],N]

trait Sized[T, N] {

???

}

N = ???

Page 46: Type Driven Development @ Confitura 2014

Part I - numbers as types

trait Nat

class _0 extends Nat

case class Succ[P<:Nat]() extends Nat

val _2 : Succ[Succ[_0]] =

Succ(Succ(_0))

Page 47: Type Driven Development @ Confitura 2014

Sized[Seq[A],N]

type SSeq[A,M<:Nat] = Sized[Seq[A],M]

Sized("maciek","prochniak")

: SSeq[String,_2]

def sizedZip[A,B,M<:Nat]

(l1:SSeq[A,M],l2:SSeq[B,M])

: SSeq[(A,B),M] = ???

Page 48: Type Driven Development @ Confitura 2014

Part II - witness

def myFun[N<:Nat](a:SIter[String,N])

(implicit b:All[N]) {}

trait All[N<:Nat] {}

implicit object AllZero

extends All[_0]

implicit def allSucc[N<:Nat]

(implicit a:All[N])

= new All[Succ[N]] {}

Page 49: Type Driven Development @ Confitura 2014

Part II - witness

trait Even[K<:Nat] {}

implicit object Even0 extends Even[0_]

implicit def succ[K<:Nat]

(implicit n:Even[K])

:Even[Succ[Succ[K]] =

new Even[Succ[Succ[K]]{}

Page 50: Type Driven Development @ Confitura 2014

Part II - witness

def evenFun[N<:Nat]

(a:Sized[Iterable[String],N])

(implicit n:Even[N]) {}

evenFun(Sized[Seq](“a”,”b”))

//evenFun(Sized[Seq](“a”,”b”,”c))

Page 51: Type Driven Development @ Confitura 2014

Ultimate challenge...

isSum(_8 :: _4 :: HNil, _12)

//isSum(_8 :: _4 :: HNil, _10)

trait Summed[H <:HList, S<:Nat]

def isSum[L<:HList,S<:Nat](l:L,s:S)

(implicit sumProof: Summed[L,S]) {}

Page 52: Type Driven Development @ Confitura 2014

Ultimate code...

implicit object NilSummed

extends Summed[HNil, _0]

implicit def pSum

[H<:Nat,T<:HList,PS<:Nat,S<:Nat]

(implicit partial: Summed[T, PS],

sum: Sum.Aux[H, PS, S])

= new Summed[H :: T, S] {}

Page 53: Type Driven Development @ Confitura 2014

Security layersmain/servlet

parsing

validation

business “logic”

collections, utils

io

Page 54: Type Driven Development @ Confitura 2014

What about

● NullPointerException

● (uncaught) IOException

● ArrayOutOfBoundsException

● ItemNotFoundException

● (uncaught) ConstraintViolationException

Page 55: Type Driven Development @ Confitura 2014

Diagram chasing

https://www.flickr.com/photos/intvgene/370973576/in/photolist-yMkw9-7DzC2S-cFnmdQ-4zTfBU-4wuofP-5jGxP9-2auo-4eMTQm-9Napth-jrxsDZ-9cfBr2-ypFzW-7UyLLa-8tJckK-9N7DnM-5UhnaA-h82ub-4fUsNL-7vEVv7-aSj57v-5Ycmai-8sWpQY-8BPU1e-7vEVHQ-gJ3my-6bZkwr-87V3bY-dKfwc5-bpMqEM-8NLnCe-5B3jzN-9bdfAr-iSEFkV-4EEuP8-55TSMz-cee2wo-9SiXWP-8iVuse-7vB7fR-7ASTkd-6dpV1C-4j1h7w-4qB8yx-64pP5z-57gbdz-2QP4c-2Dt2iR-9N7Dc8-8nDt9B-ei86DD

Page 56: Type Driven Development @ Confitura 2014

Types as documentation

https://www.flickr.com/photos/videolux/2389320345/in/photolist-4D8TGn-41Hk4j-f5j58F-58cFd2-6jtGaU-8M9Rct-dKjTu-bFuM9p-288vk7-6MDA6U-9rpM2p-7uFTQX-by46VA-jtP7tW-d1yszw-4BxoMU-4Bt4Q8-4Bt8Eg-9qdvDe-9uQehi-9cbiDp-4Bxpz7-4BxmPL-4Bt8jZ-4Bt99T-4Bt7Nv-4Bt6Wz-4BxoCY-4Bxov7-8hqYi6-9X4XKN-4Dd9WY-9ZYLNT-27ie4m-7kJq5y-feBNUr-76WjbN-55V3TL-83eR5P-5fqy8i-4yewUt-4jgxK-7m1XhV-7hJ1yt-7ePuGr-e2x4rd-8Y9XXj-8iPy1e-795cWD-89z3Th

Page 57: Type Driven Development @ Confitura 2014

Are we there yet?

Page 59: Type Driven Development @ Confitura 2014

Do you do all this?

● IDE support

● library maturity

● verbosity

● is it worth it?

Page 60: Type Driven Development @ Confitura 2014

Generic vs concrete code

https://www.flickr.com/photos/oddsock/100761143/

Page 61: Type Driven Development @ Confitura 2014

Generic vs concrete code

Object

Collection

Controller

Domain

https://www.flickr.com/photos/oddsock/100761143/

Page 62: Type Driven Development @ Confitura 2014

Is your business logic logical?

k4j-f5j58F-58cFd2-6jtGaU-8M9Rct-dKjTu-bFuM9p-288vk7-6MDA6U-9rpM2p-7uFTQX-by46VA-jtP7tW-d1yszw-4BxoMU-4Bt4Q8-4Bt8Eg-9qdvDe-9uQehi-9cbiDp-4Bxpz7-4BxmPL-4Bt8jZ-4Bt99T-4Bt7Nv-4Bt6Wz-4BxoCY-4Bxov7-8hqYi6-9X4XKN-4Dd9WY-9ZYLNT-27ie4m-7kJq5y-feBNUr-76WjbN-55V3TL-83eR5P-5fqy8i-4yewUt-4jgxK-7m1XhV-7hJ1yt-7ePuGr-e2x4rd-8Y9XX

Page 63: Type Driven Development @ Confitura 2014

Value classes

Option

Dependent types

IOMonad

Validation

Scala Scalaz

Shapeless

Page 64: Type Driven Development @ Confitura 2014

Dziękihttp://mproch.blogspot.com

[email protected]://github.com/mproch