Type Driven Development @ Confitura 2014
-
Upload
maciek-prochniak -
Category
Software
-
view
112 -
download
1
description
Transcript of Type Driven Development @ Confitura 2014
![Page 1: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/1.jpg)
Type driven development
Maciek Próchniak
![Page 2: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/2.jpg)
Whoami?
![Page 3: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/3.jpg)
Maciek Próchniak
Algebraic topologyhocolim
Group cohomology
Monads
GWT
TouKCamel
OSGi
CQRS
Scala
![Page 4: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/4.jpg)
How to prevent bugs?
● Tests● Defensive programming● Tests● Contracts● Tests
![Page 5: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/5.jpg)
Guerilla defensive programming
![Page 6: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/6.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/7.jpg)
What bugs?
“Only 1% of issues in Python system are TypeErrors, AttributeErrors, NameErrors”
![Page 8: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/8.jpg)
What about
● NullPointerException
● (uncaught) IOException
● ArrayOutOfBoundsException
● ItemNotFoundException
![Page 9: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/9.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/10.jpg)
Security layersmain/servlet
parsing
validation
business “logic”
collections, utils
io
![Page 11: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/11.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/12.jpg)
Equal?
long userId = 14
User user = getUser(...)
userId.equals(user)
![Page 13: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/13.jpg)
Equal?
val userId : Long = 14
val user : User = getUser(...)
import scalaz.syntax.equal._
userId === user
![Page 14: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/14.jpg)
Names are important
BigDecimal balance;
BigDecimal price;
balance.compareTo(price) > 0
![Page 15: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/15.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/16.jpg)
Tagged types
@Nullable
@Valid
@Notempty
private String mail
![Page 17: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/17.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/18.jpg)
Tagged types
Double @@ Meter
sealed trait Meter
sealed trait Liter
![Page 19: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/19.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/20.jpg)
Value classes
![Page 21: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/21.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/22.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/23.jpg)
Value classes
implicit class CustomerId(
val id:String) extends AnyVal {
def load:Customer
}
“12345”.load : Customer
![Page 24: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/24.jpg)
What about
● NullPointerException
● (uncaught) IOException
● ArrayOutOfBoundsException
● ItemNotFoundException
![Page 25: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/25.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/26.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/27.jpg)
Syntax sugar IS important
val maybe = Option.empty[String]
maybe.map(_.toUpperCase)
![Page 28: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/28.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/29.jpg)
Syntax sugar IS important
String maybe = null;
if (maybe != null) {
maybe = maybe.toUpperCase();
}
![Page 30: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/30.jpg)
What about
● NullPointerException
● (uncaught) IOException
● ArrayOutOfBoundsException
● ItemNotFoundException
![Page 31: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/31.jpg)
IO...
https://www.flickr.com/photos/oddsock/100761143/
![Page 32: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/32.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/33.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/34.jpg)
Security layersmain/servlet
parsing
validation
business “logic”
collections, utils
io
![Page 35: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/35.jpg)
Mixing stuff
IO[State[Map, String]]
State[Map, IO[String,]]
![Page 36: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/36.jpg)
Mixing stuff
https://www.flickr.com/photos/oddsock/100761143/
![Page 37: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/37.jpg)
What about
● NullPointerException
● (uncaught) IOException
● ArrayOutOfBoundsException
● ItemNotFoundException
![Page 38: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/38.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/39.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/40.jpg)
Is it a dream?
![Page 41: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/41.jpg)
Path dependent types
class Family {
case class Child(name : String)
def quarell(child1 : Child,
child2 : Child) {
//blaaah
}
}
![Page 42: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/42.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/43.jpg)
Path dependent types
def hide(family:Family)
(child:family.Child) {
}
![Page 44: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/44.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/45.jpg)
Sized[Seq[A],N]
trait Sized[T, N] {
???
}
N = ???
![Page 46: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/46.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/47.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/48.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/49.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/50.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/51.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/52.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/53.jpg)
Security layersmain/servlet
parsing
validation
business “logic”
collections, utils
io
![Page 54: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/54.jpg)
What about
● NullPointerException
● (uncaught) IOException
● ArrayOutOfBoundsException
● ItemNotFoundException
● (uncaught) ConstraintViolationException
![Page 55: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/55.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/56.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/57.jpg)
Are we there yet?
![Page 58: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/58.jpg)
Do you do all this?
https://www.flickr.com/photos/drgaz/277221424/in/photolist-quQgJ-5KKwCZ
![Page 59: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/59.jpg)
Do you do all this?
● IDE support
● library maturity
● verbosity
● is it worth it?
![Page 60: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/60.jpg)
Generic vs concrete code
https://www.flickr.com/photos/oddsock/100761143/
![Page 61: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/61.jpg)
Generic vs concrete code
Object
Collection
Controller
Domain
https://www.flickr.com/photos/oddsock/100761143/
![Page 62: Type Driven Development @ Confitura 2014](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/62.jpg)
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](https://reader034.fdocuments.us/reader034/viewer/2022052617/547d99a6b37959a22b8b527f/html5/thumbnails/63.jpg)
Value classes
Option
Dependent types
IOMonad
Validation
Scala Scalaz
Shapeless