2 Years of Real World FP at REA

160
2 Years of Real World FP at REA @KenScambler Scala Developer at λ

Transcript of 2 Years of Real World FP at REA

Page 1: 2 Years of Real World FP at REA

2 Years of Real World FP at REA@KenScambler

Scala Developer at

λ

Page 2: 2 Years of Real World FP at REA

Me14 years

5 years

5 years

when possible

when bored

when forced

Page 3: 2 Years of Real World FP at REA

@

Jul 13 Jan 14 Jul 14 Jan 15

- 3 teams- 17 codebases- 43K LOC

Page 4: 2 Years of Real World FP at REA

Why Functional Programming?

Page 5: 2 Years of Real World FP at REA

Compelling, tangible software engineering benefits

Page 6: 2 Years of Real World FP at REA

Modularity

Abstraction

Composability

Page 7: 2 Years of Real World FP at REA

Modular, abstract, composable programs

are simple programs

Page 8: 2 Years of Real World FP at REA

Modularity

Page 9: 2 Years of Real World FP at REA

Can you reason about something in isolation?

Page 10: 2 Years of Real World FP at REA

Or do you need to fit everything in your head at once?

Page 11: 2 Years of Real World FP at REA

A

B C K

Is the cost of replacing Bwith K just writing K?

Page 12: 2 Years of Real World FP at REA

A

B CK

Is the cost of replacing Bwith K just writing K?

Page 13: 2 Years of Real World FP at REA

AK

B CK

K

…or rewriting half the program?

glue

glue

Page 14: 2 Years of Real World FP at REA

A pure function is just input output; no side effects

You can tell what it does without Looking at surrounding context.

Page 15: 2 Years of Real World FP at REA

Consider: Let’s parse a string like “Richmond, VIC 3121”

def parseLocation(str: String): Location = {val parts = str.split(“,”)val secondStr = parts(1)val parts2 = secondStr.split(“ “)Location(

parts(0), parts2(0), parts(1).toInt)}

Page 16: 2 Years of Real World FP at REA

Could be null

Possible errors: 1

def parseLocation(str: String): Location = {val parts = str.split(“,”)val secondStr = parts(1)val parts2 = secondStr.split(“ “)Location(

parts(0), parts2(0), parts(1).toInt)}

Page 17: 2 Years of Real World FP at REA

def parseLocation(str: String): Location = {val parts = str.split(“,”)val secondStr = parts(1)val parts2 = secondStr.split(“ “)Location(

parts(0), parts2(0), parts(1).toInt)}

Might not have enough elements

Possible errors: 2

Page 18: 2 Years of Real World FP at REA

def parseLocation(str: String): Location = {val parts = str.split(“,”)val secondStr = parts(1)val parts2 = secondStr.split(“ “)Location(

parts(0), parts2(0), parts(1).toInt)}

Might not have enough elements

Possible errors: 3

Page 19: 2 Years of Real World FP at REA

def parseLocation(str: String): Location = {val parts = str.split(“,”)val secondStr = parts(1)val parts2 = secondStr.split(“ “)Location(

parts(0), parts2(0), parts(1).toInt)}

Might not have enough elements

Possible errors: 4

Page 20: 2 Years of Real World FP at REA

def parseLocation(str: String): Location = {val parts = str.split(“,”)val secondStr = parts(1)val parts2 = secondStr.split(“ “)Location(

parts(0), parts2(0), parts(1).toInt)}

Might not have enough elements

Possible errors: 5

Page 21: 2 Years of Real World FP at REA

def parseLocation(str: String): Location = {val parts = str.split(“,”)val secondStr = parts(1)val parts2 = secondStr.split(“ “)Location(

parts(0), parts2(0), parts(1).toInt)}

Might not be an int

Possible errors: 6

Page 22: 2 Years of Real World FP at REA

def doSomethingElse(): Unit = {// ...Do other stuffparseLocation(“Melbourne, VIC 3000”)

}

Possible errors: 6 + 3 = 9

63

Page 23: 2 Years of Real World FP at REA

def anotherThing(): Unit = {// ...Do even more stuffdoSomethingElse()

}

Possible errors: 9 + 4 = 13

49

Page 24: 2 Years of Real World FP at REA

Code inherits all the errors and side-effects of code it calls.

Local reasoning becomes impossible; modularity is lost.

Page 25: 2 Years of Real World FP at REA

def parseLocation(str: String): Option[Location] = {

val parts = str.split(”,")for {

locality <- parts.optGet(0)theRestStr <- parts.optGet(1)theRest = theRestStr.split(" ")subdivision <- theRest.optGet(0)postcodeStr <- theRest.optGet(1)postcode <- postcodeStr.optToInt

} yieldLocation(locality, subdivision, postcode)

}

Possible errors: 0

Page 26: 2 Years of Real World FP at REA

All possibilities have been elevated into the type system

Local reasoning is possible!

Local reasoning is possible about things that call it, etc…

Page 27: 2 Years of Real World FP at REA

Abstraction

Page 28: 2 Years of Real World FP at REA

Know as little as you need

Page 29: 2 Years of Real World FP at REA

Know as little as you need

Produce as little as you can

Page 30: 2 Years of Real World FP at REA

def sumInts(list: List[Int]): Int = {

var result = 0for (x <- list) {

result = result + x}return result

}

Page 31: 2 Years of Real World FP at REA

def flatten[A](list: List[List[A]]): List[A] = {

var result = List()for (x <- list) {

result = result ++ x}return result

}

Page 32: 2 Years of Real World FP at REA

def all[A](list: List[Boolean]): Boolean = {

var result = truefor (x <- list) {

result = result && x}return result

}

Page 33: 2 Years of Real World FP at REA

def sumInts(list: List[Int]): Int = {

var result = 0for (x <- list) {

result = result + x}return result

}

Page 34: 2 Years of Real World FP at REA

def flatten[A](list: List[List[A]]): List[A] = {

var result = List()for (x <- list) {

result = result ++ x}return result

}

Page 35: 2 Years of Real World FP at REA

def all[A](list: List[Boolean]): Boolean = {

var result = truefor (x <- list) {

result = result && x}return result

}

Page 36: 2 Years of Real World FP at REA

trait Monoid[M] {def zero: Mdef append(m1: M, m2: M): M

}

Extract the essence!

Page 37: 2 Years of Real World FP at REA

def fold[M](list: List[M])(implicit m: Monoid[M]): M

= {

var result = m.zerofor (x <- list) {

result = m.append(result,x)}result

}

Page 38: 2 Years of Real World FP at REA

def fold[M](list: List[M])(implicit m: Monoid[M]): M

= list.foldLeft(m.zero)(m.append)

Page 39: 2 Years of Real World FP at REA

fold(List(1, 2, 3, 4)) 10

fold(List(List("a", "b"), List("c"))) List("a", "b", "c")

fold(List(true, true, false, true)) false

Page 40: 2 Years of Real World FP at REA

Abstraction is always a good thing!

Less repetition More reuse

Less decay, because code can’tgrow tumours around unnecessary detail

Page 41: 2 Years of Real World FP at REA

Composability

Page 42: 2 Years of Real World FP at REA

Functions compose.

A => B B => C

C => D D => E

Page 43: 2 Years of Real World FP at REA

A => E

Functions compose.

Page 44: 2 Years of Real World FP at REA

Sideways too.

A => E

X => Y

Page 45: 2 Years of Real World FP at REA

(A,X) => (E,Y)

Sideways too.

Page 46: 2 Years of Real World FP at REA

This works in the large, as well as the small!

Entire systems can be composable like functions…. without side effects

Page 47: 2 Years of Real World FP at REA

Truly composablesystems can accrue more and more stuff without getting more complex!

Page 48: 2 Years of Real World FP at REA

Simplicity

• Modularity – Reason locally

• Abstraction – say only what you need, hide

everything you don’t

• Composability – scale without accruing complexity

Page 49: 2 Years of Real World FP at REA

The human process

Page 50: 2 Years of Real World FP at REA

Technical excellence isn’t enough!

Software development is a human process

Coffee Tea

Quiet time

GSD

PoniesReconsider!

Page 51: 2 Years of Real World FP at REA
Page 52: 2 Years of Real World FP at REA
Page 53: 2 Years of Real World FP at REA
Page 54: 2 Years of Real World FP at REA
Page 55: 2 Years of Real World FP at REA

Xi’an offshore team

Team

Team

Team

Team

Page 56: 2 Years of Real World FP at REA

Xi’an offshore team

• Many teams are partly based in Xi’an.

• They’re very good, but…

• Communication is hard!

• It works, but requires great investment of time and

money

Page 57: 2 Years of Real World FP at REA

Bottom-up tech decisions

Page 58: 2 Years of Real World FP at REA
Page 59: 2 Years of Real World FP at REA
Page 60: 2 Years of Real World FP at REA
Page 61: 2 Years of Real World FP at REA
Page 62: 2 Years of Real World FP at REA
Page 63: 2 Years of Real World FP at REA
Page 64: 2 Years of Real World FP at REA
Page 65: 2 Years of Real World FP at REA
Page 66: 2 Years of Real World FP at REA
Page 67: 2 Years of Real World FP at REA
Page 68: 2 Years of Real World FP at REA

GET /foo/bar

PUT

{"mode":

"banana"}

POST {"partyTime": "5:00"}GET /buzz/5/

Page 69: 2 Years of Real World FP at REA

ArchitectMountain

Page 70: 2 Years of Real World FP at REA

ArchitectMountain

Page 71: 2 Years of Real World FP at REA

ArchitectMountain

Page 72: 2 Years of Real World FP at REA

ArchitectMountain

Just needs more Agile

Don’t forget your

velocity

More meetings, but littler

NONo no no no no no no

no no no no no no no

no no no no no no no

no no no no no no no

no no no no not like

this. Wake up it’s a

school day

Page 73: 2 Years of Real World FP at REA

Bottom-up tech decisions

You have to win

Page 74: 2 Years of Real World FP at REA

Bottom-up tech decisions

You have to win

Page 75: 2 Years of Real World FP at REA

Bottom-up tech decisions

You have to win

Page 76: 2 Years of Real World FP at REA

Software Paleontology

Everyone’s got a history…

Page 77: 2 Years of Real World FP at REA

Scriptozoic era1995 – 2010Mostly Perl

Page 78: 2 Years of Real World FP at REA

Monolithocene epoch2010 – 2012Ruby, Java

Scriptozoic era1995 – 2010Mostly Perl

Page 79: 2 Years of Real World FP at REA

AWS

Monolithocene epoch2010 – 2012Ruby, Java

Scriptozoic era1995 – 2010Mostly Perl

Microservices2012 –Ruby, Scala, JS

Page 80: 2 Years of Real World FP at REA

Adoption

Page 81: 2 Years of Real World FP at REA

June, 2013

Page 82: 2 Years of Real World FP at REA
Page 83: 2 Years of Real World FP at REA
Page 84: 2 Years of Real World FP at REA
Page 85: 2 Years of Real World FP at REA

λ

Page 86: 2 Years of Real World FP at REA
Page 87: 2 Years of Real World FP at REA

λ

λ

Page 88: 2 Years of Real World FP at REA

λ

λ

λ

Page 89: 2 Years of Real World FP at REA

λ

λ

λ

Page 90: 2 Years of Real World FP at REA

λ

λ

Page 91: 2 Years of Real World FP at REA

λ

λ

Page 92: 2 Years of Real World FP at REA

λ

Page 93: 2 Years of Real World FP at REA

Language choiceObject Oriented

Powerful static types

Functional

JVM

Page 94: 2 Years of Real World FP at REA

Object Oriented

Powerful static types

Functional

JVM

Page 95: 2 Years of Real World FP at REA

Functional

JVM

Page 96: 2 Years of Real World FP at REA

Functional

JVM

Page 97: 2 Years of Real World FP at REA

Functional

JVM

Page 98: 2 Years of Real World FP at REA

Functional

JVM

Page 99: 2 Years of Real World FP at REA

Whatever works for you!

Page 100: 2 Years of Real World FP at REA

The journey

Page 101: 2 Years of Real World FP at REA

Jul 13 Jan 14

1

Page 102: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Play2

Play2

6K

Squeryl / Play2

Constructors

Type API#1

Page 103: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Play2

Play2

6K

Squeryl / Play2

Constructors

Type API

• Mentor• Code reviews

Learning Investment

#1

Page 104: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Play2

Play2

6K

Squeryl / Play2

Constructors

Type API

• Mentor• Code reviews

Learning Investment Report cardLearning curve

Technical result

Productivity

Sentiment

Steep but ok

OK; slight dip

Great; but FWs too heavy

#1

Page 105: 2 Years of Real World FP at REA

Jul 13 Jan 14

1 2

Some infrastructure

Page 106: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Play2

Argonaut

3K

Squeryl / Play2

Constructors

Type API#2

Page 107: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Play2

Argonaut

3K

Squeryl / Play2

Constructors

Type API

• Almost noneLearning Investment

#2

Page 108: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Play2

Argonaut

3K

Squeryl / Play2

Constructors

Type API

• Almost noneLearning Investment Report card

Learning curve

Technical result

Productivity

Sentiment

Learning?

Meh

Needed rework; OK in the end

#2

!!!

Page 109: 2 Years of Real World FP at REA

Lesson #1

New tech, mindset requires investment in learning

Invest in your people!

Page 110: 2 Years of Real World FP at REA

λ

Page 111: 2 Years of Real World FP at REA

Another team!

λ

Page 112: 2 Years of Real World FP at REA

“We’ll have some of that!”

λ

Page 113: 2 Years of Real World FP at REA

Jul 13 Jan 14

1 2

46

5

New team; new ideas!

3

Page 114: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Unfinagled

Argonaut

2K, 3K, 4K, 1K

Slick

Constructors

Type Web app, libs, API x 2

• 2 x MentorLearning Investment Report card

Learning curve

Technical result

Productivity

Sentiment

Not bad

Great

Great

#3,4,5,6

Page 115: 2 Years of Real World FP at REA

Jul 13 Jan 14

1 2

46

5

3

7

Theft & innovation

Jul 14

Page 116: 2 Years of Real World FP at REA

Lesson #2

Having multiple teams is great, because you can steal from each other

Page 117: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Unfinagled

Argonaut

4K

Slick

Monad Transformers

Type API#7

Page 118: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Unfinagled

Argonaut

4K

Slick

Monad Transformers

Type API

• 2 x MentorLearning Investment

#7

Page 119: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Unfinagled

Argonaut

4K

Slick

Monad Transformers

Type API

• 2 x MentorLearning Investment Report card

Learning curve

Technical result

Productivity

Sentiment

Vertical

Great

Great

#7

Page 120: 2 Years of Real World FP at REA

Monad Transformers

Good technical benefits, but…

Only 2 people could understand the code

Experienced engineers felt totally helpless

Learning curve way too steep

Page 121: 2 Years of Real World FP at REA

Devops

All-rounders

Gurus

Page 122: 2 Years of Real World FP at REA

All-rounders

Gurus

JS / CSS / HTML

Page 123: 2 Years of Real World FP at REA

AWS

All-rounders

Gurus

Page 124: 2 Years of Real World FP at REA

Scala (originally!)

Gurus

Page 125: 2 Years of Real World FP at REA

All-rounders

Scala (now)

Gurus

• Smooth learning curve is utterly essential

• We need more all-rounders

• We can’t leave people behind

Page 126: 2 Years of Real World FP at REA

Lesson #3Familiar, but technically unsound concepts have limited value.

However… if we can’t make a concept learnable, then we can’t use it.

Page 127: 2 Years of Real World FP at REA

λ

A Ruby team considers its options…

Page 128: 2 Years of Real World FP at REA

λ

Page 129: 2 Years of Real World FP at REA

λ

Page 130: 2 Years of Real World FP at REA

Jul 13 Jan 14

1 2

46

5

3

7

A 3rd team dips its toe in the water

8

Jul 14

Page 131: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Play2

Play2

2K

Anorm

Constructors

Type Web app#8

Page 132: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Play2

Play2

2K

Anorm

Constructors

Type Web app

• Trial and error• Code Katas

Learning Investment

#8

Page 133: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Play2

Play2

2K

Anorm

Constructors

Type Web app

• Trial and error• Code Katas

Learning Investment Report cardLearning curve

Technical result

Productivity

Sentiment

Steep

Meh

OK

#8

Page 134: 2 Years of Real World FP at REA

Lesson #4

It’s really hard learning from scratch

Be prepared for pain up front

Page 135: 2 Years of Real World FP at REA

λ

Page 136: 2 Years of Real World FP at REA

Jul 13 Jan 14

1 2

46

5

3

7

Latest iteration

8

Jul 14 Jan 15

17

Page 137: 2 Years of Real World FP at REA

Design trends

Inheritance/mixins Static functions

Page 138: 2 Years of Real World FP at REA

Design trends

Inheritance/mixins Static functions

Partial functions Total functions

Page 139: 2 Years of Real World FP at REA

Design trends

Inheritance/mixins Static functions

Partial functions Total functions

Exceptions Sum types

Page 140: 2 Years of Real World FP at REA

Design trends

Inheritance/mixins Static functions

Partial functions Total functions

Strings/primitives Wrapper types

Exceptions Sum types

Page 141: 2 Years of Real World FP at REA

FP Guild

Every Thursday, in work hours

7 – 12 people each week

Reading, exercises, talks, live coding

Page 142: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Unfiltered

Argonaut

3K

Slick

Free Monads

Type API#17

Page 143: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Unfiltered

Argonaut

3K

Slick

Free Monads

Type API

• 2 x Mentors• Pull Requests• Code reviews• Pairing• FP Guild

Learning Investment

#17

Page 144: 2 Years of Real World FP at REA

LOC

Web

JSON

DB

Dep Inj

Unfiltered

Argonaut

3K

Slick

Free Monads

Type API

• 2 x Mentors• Pull Requests• Code reviews• Pairing• FP Guild

Learning Investment Report cardLearning curve

Technical result

Productivity

Sentiment

Smooth

Great

Brilliant

#17

Page 145: 2 Years of Real World FP at REA

Pure coreRoutes Controllers Logic Script

Interpreter

Actual DB

“Authenticate”“Use config”“Get from DB”“Update DB”“Log result”

Web Framework

Server

App runtime

Page 146: 2 Years of Real World FP at REA

Pure coreRoutes Controllers Logic Script

Pure Interpreter

Pure tests

Input

Output

Assert

“Authenticate”“Use config”“Get from DB”“Update DB”“Log result”

Page 147: 2 Years of Real World FP at REA

Pure core

Interpreter

Actual DB

Web Framework

Server

App runtimeWafer thinE2E tests

Input

Output

Assert

Page 148: 2 Years of Real World FP at REA

object SearchController {

def getList(uid: UserId): Script[Response]= {

for {searches <- getSearches(uid)cfg <- getConfigresults <- addLinks(searches, cfg)

} yield Ok ~> Response(result.toJson)}

}

Page 149: 2 Years of Real World FP at REA

Learning curve:

Page 150: 2 Years of Real World FP at REA

Learning curve:

Smooooth

Page 151: 2 Years of Real World FP at REA

Mocks

Page 152: 2 Years of Real World FP at REA

Stubs

Page 153: 2 Years of Real World FP at REA

Flaky pretend servers

just to check

a response code

Page 154: 2 Years of Real World FP at REA

Flaky tests

that take

30 min to run

Page 155: 2 Years of Real World FP at REA

Side effects

everywhere

Page 156: 2 Years of Real World FP at REA

Exceptions

Page 157: 2 Years of Real World FP at REA

Intrusive

DI frameworks

Page 158: 2 Years of Real World FP at REA

You shouldn’t be dealing with all that complexity and crap!

Most business software isn’t rocket science.

Page 159: 2 Years of Real World FP at REA

There is a better way

FP is a tall tree

But there is so much low hanging fruit!

Page 160: 2 Years of Real World FP at REA

Thank you!