+ All Categories
Home > Software > FP is coming... le 19/05/2016

FP is coming... le 19/05/2016

Date post: 14-Apr-2017
Category:
Upload: loic-knuchel
View: 217 times
Download: 0 times
Share this document with a friend
98
FP is coming... @loicknuchel
Transcript
Page 3: FP is coming... le 19/05/2016
Page 6: FP is coming... le 19/05/2016

Front-end

Page 7: FP is coming... le 19/05/2016
Page 8: FP is coming... le 19/05/2016
Page 9: FP is coming... le 19/05/2016
Page 10: FP is coming... le 19/05/2016
Page 11: FP is coming... le 19/05/2016
Page 12: FP is coming... le 19/05/2016
Page 13: FP is coming... le 19/05/2016

Fonctions pures

Immutabilité

Page 14: FP is coming... le 19/05/2016

Fonctions pures

ImmutabilitéModifier une variable ?

Accès BDD ?

Logs ? Exceptions ?

CRUD ?

Page 15: FP is coming... le 19/05/2016

Do not fear FP

Page 16: FP is coming... le 19/05/2016

Au fait, c’est quoi la programmation fonctionnelle ?“La programmation fonctionnelle est un paradigme de programmation qui considère le calcul en tant qu'évaluation de fonctions mathématiques.” Wikipedia

Page 17: FP is coming... le 19/05/2016

Au fait, c’est quoi la programmation fonctionnelle ?“La programmation fonctionnelle est un paradigme de programmation qui considère le calcul en tant qu'évaluation de fonctions mathématiques.” Wikipedia

“La programmation fonctionnelle est un style de programmation qui met l’accent sur les fonctions qui ne dépendent pas de l’état du programme.” Functionnal programming in scala

Page 18: FP is coming... le 19/05/2016

Au fait, c’est quoi la programmation fonctionnelle ?“La programmation fonctionnelle est un paradigme de programmation qui considère le calcul en tant qu'évaluation de fonctions mathématiques.” Wikipedia

“La programmation fonctionnelle est un style de programmation qui met l’accent sur les fonctions qui ne dépendent pas de l’état du programme.” Functionnal programming in scala

“La programmation fonctionnelle permet de coder de manière plus productive et plus modulaire, avec moins de bugs.” Moi

Page 19: FP is coming... le 19/05/2016
Page 20: FP is coming... le 19/05/2016

Transformer un tableau

function toUpperCase(list){ var ret = []; for(var i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } return ret;}

var names = ['Finn', 'Rey', 'Poe'];

console.log(toUpperCase(names));// ['FINN', 'REY', 'POE']

public List<String> toUpperCase(List<String> list) { List<String> ret = new ArrayList<>(); for(String item : list){ ret.add(item.toUpperCase()); } return ret;}

List<String> names = Arrays.asList("Finn", "Rey", "Poe");

System.out.println(Arrays.toString(toUpperCase(names).toArray()));// [FINN, REY, POE]

Page 21: FP is coming... le 19/05/2016

Transformer un tableau

function toUpperCase(list){ return list.map(function(item){ return item.toUpperCase(); });}

var names = ['Finn', 'Rey', 'Poe'];

console.log(toUpperCase(names));// ['FINN', 'REY', 'POE']

def toUpperCase(list: List[String]): List[String] = list.map(item => item.toUpperCase)

val names = List("Finn", "Rey", "Poe")

println(toUpperCase(names))// List(FINN, REY, POE)

Page 22: FP is coming... le 19/05/2016

Transformer un tableau

function toUpperCase(list){ return list.map(function(item){ return item.toUpperCase(); });}

var names = ['Finn', 'Rey', 'Poe'];

console.log(toUpperCase(names));// ['FINN', 'REY', 'POE']

def toUpperCase(list: List[String]): List[String] = list.map(_.toUpperCase)

val names = List("Finn", "Rey", "Poe")

println(toUpperCase(names))// List(FINN, REY, POE)

Page 23: FP is coming... le 19/05/2016

Créer son .map()

Array.prototype.map = function(callback){ var array = this; var result = []; for(var i=0; i<array.length; i++){ result[i] = callback(array[i]); } return result;};

Page 24: FP is coming... le 19/05/2016

Séparation technique / métier

Array.prototype.map = function(callback){ var array = this; var result = []; for(var i=0; i<array.length; i++){ result[i] = callback(array[i]); } return result;};

list.map(function(item){ return item.toUpperCase();});

Page 25: FP is coming... le 19/05/2016

Séparation technique / métier

Array.prototype.map = function(callback){ var array = this; var result = []; for(var i=0; i<array.length; i++){ result[i] = callback(array[i]); } return result;};

list.map(function(item){ return item.toUpperCase();});

GénériqueHaut niveau d’abstraction

Un maximum de libraires externe

Page 26: FP is coming... le 19/05/2016

Séparation technique / métier

Array.prototype.map = function(callback){ var array = this; var result = []; for(var i=0; i<array.length; i++){ result[i] = callback(array[i]); } return result;};

list.map(function(item){ return item.toUpperCase();});

GénériqueHaut niveau d’abstraction

Un maximum de libraires externe

Concis / ExpressifFocalisé sur le domaine

Un minimum de libraires externe

Page 27: FP is coming... le 19/05/2016

Architecture Hexagonale

Page 28: FP is coming... le 19/05/2016

Manipuler des donnéesvar data = [{ id: '123', actions: [ {name: 'sendPicture', pictures: [ {path: '123/1.jpg', deleted: true, sync: false}, {path: '123/2.jpg', deleted: false, sync: true}, ]}, {name: 'sendPicture', pictures: [ {path: '123/3.jpg', deleted: false, sync: true}, {path: '123/4.jpg', deleted: false, sync: true} ]}, {name: 'sendPicture', pictures: [ {path: '123/5.jpg', deleted: true, sync: false}, {path: '123/6.jpg', deleted: false, sync: false} ]} ]}, { id: '456', actions: [ {name: 'sendPicture', pictures: [ {path: '456/1.jpg', deleted: false, sync: true}, {path: '456/2.jpg', deleted: false, sync: true}, ]}, {name: 'sendPicture', pictures: [ {path: '123/3.jpg', deleted: true, sync: false}, {path: '123/4.jpg', deleted: true, sync: false} ]} ]}];

function doSomething(items, id){ var pictures = []; for (var i=0; i<items.length; i++) { var item = items[i]; if (item.id === id) { for (var j=0; j<item.actions.length; j++) { var action = item.actions[j]; if (action.name === 'sendPicture') { for (var k=0; k<action.pictures.length; k++) { var picture = action.pictures[k]; if (!picture.deleted) { pictures.push(picture); } } } } } } return pictures;}

Page 29: FP is coming... le 19/05/2016

function getPictures(items, id){ var pictures = []; for (var i=0; i<items.length; i++) { var item = items[i]; if (item.id === id) { for (var j=0; j<item.actions.length; j++) { var action = item.actions[j]; if (action.name === 'sendPicture') { for (var k=0; k<action.pictures.length; k++) { var picture = action.pictures[k]; if (!picture.deleted) { pictures.push(picture); } } } } } } return pictures;}

Manipuler des donnéespublic List<Picture> getPictures(List<Item> items, String id) { List<Picture> pictures = new ArrayList<>(); for (Item item : items) { if (item.getId() == id) { for (Action action : item.getActions()) { if (action.getName() == "sendPicture") { for (Picture picture : action.getPictures()) { if (!picture.getDeleted()) { pictures.add(picture); } } } } } } return pictures;}

Page 30: FP is coming... le 19/05/2016

function getPictures(items, id){ var pictures = []; for (var i=0; i<items.length; i++) { var item = items[i]; if (item.id === id) { for (var j=0; j<item.actions.length; j++) { var action = item.actions[j]; if (action.name === 'sendPicture') { for (var k=0; k<action.pictures.length; k++) { var picture = action.pictures[k]; if (!picture.deleted) { pictures.push(picture); } } } } } } return pictures;}

Manipuler des donnéespublic List<Picture> getPictures(List<Item> items, String id) { List<Picture> pictures = new ArrayList<>(); for (Item item : items) { if (item.getId() == id) { for (Action action : item.getActions()) { if (action.getName() == "sendPicture") { for (Picture picture : action.getPictures()) { if (!picture.getDeleted()) { pictures.add(picture); } } } } } } return pictures;}

Duplication !Duplication !

Page 31: FP is coming... le 19/05/2016

function getPictures(items, id){ var pictures = []; for (var i=0; i<items.length; i++) { var item = items[i]; if (item.id === id) { for (var j=0; j<item.actions.length; j++) { var action = item.actions[j]; if (action.name === 'sendPicture') { for (var k=0; k<action.pictures.length; k++) { var picture = action.pictures[k]; if (!picture.deleted) { pictures.push(picture); } } } } } } return pictures;}

Manipuler des donnéespublic List<Picture> getPictures(List<Item> items, String id) { List<Picture> pictures = new ArrayList<>(); for (Item item : items) { if (item.getId() == id) { for (Action action : item.getActions()) { if (action.getName() == "sendPicture") { for (Picture picture : action.getPictures()) { if (!picture.getDeleted()) { pictures.add(picture); } } } } } } return pictures;}

Find item by idFilter actions by nameFilter pictures not deleted

Page 32: FP is coming... le 19/05/2016

function getPictures(items, id){ var pictures = []; for (var i=0; i<items.length; i++) { var item = items[i]; if (item.id === id) { for (var j=0; j<item.actions.length; j++) { var action = item.actions[j]; if (action.name === 'sendPicture') { for (var k=0; k<action.pictures.length; k++) { var picture = action.pictures[k]; if (!picture.deleted) { pictures.push(picture); } } } } } } return pictures;}

Manipuler des donnéespublic List<Picture> getPictures(List<Item> items, String id) { List<Picture> pictures = new ArrayList<>(); for (Item item : items) { if (item.getId() == id) { for (Action action : item.getActions()) { if (action.getName() == "sendPicture") { for (Picture picture : action.getPictures()) { if (!picture.getDeleted()) { pictures.add(picture); } } } } } } return pictures;}

Find item by idFilter actions by nameFilter pictures not deleted

Level up your abstraction !

Page 33: FP is coming... le 19/05/2016

Manipuler des données// Finds the 1st elt of the sequence satisfying a predicate, if anydef find[A](p: (A) => Boolean): Option[A]

// Selects all elts of this collection which satisfy a predicatedef filter[A](p: (A) => Boolean): List[A]

// Builds a new list by applying a function to all elements of the listdef map[A, B](f: (A) => B): List[B]

// Applies a binary operator to all elts of this listdef reduce[A, B](f: (B, A) => B, b: B): B

Page 34: FP is coming... le 19/05/2016

Manipuler des donnéesfunction getPictures(items, id){ return items .find(function(item){ return item.id === id; }).actions .filter(function(action){ return action.name === 'sendPicture'; }) .map(function(action){ return action.pictures; }) .reduce(function(a, b){ return a.concat(b); }, []) .filter(function(picture){ return !picture.deleted; });}

def getPictures(items: List[Item], id: String): List[Picture] = items .find(_.id == id) .map(_.actions).getOrElse(List()) .filter(_.name == "sendPicture") .flatMap(_.pictures) .filter(!_.deleted)

Page 35: FP is coming... le 19/05/2016
Page 36: FP is coming... le 19/05/2016

public List<Picture> getPictures(List<Item> items, String id) { List<Picture> pictures = new ArrayList<>(); for (Item item : items) { if (item.getId() == id) { for (Action action : item.getActions()) { if (action.getName() == "sendPicture") { for (Picture picture : action.getPictures()) { if (!picture.getDeleted()) { pictures.add(picture); } } } } } } return pictures;}

def getPictures(items: List[Item], id: String): List[Picture] = items .find(_.id == id) .map(_.actions).getOrElse(List()) .filter(_.name == "sendPicture") .flatMap(_.pictures) .filter(!_.deleted)

Manipuler des donnéesfunction getPictures(items, id){ var pictures = []; for(var i=0; i<items.length; i++){ var item = items[i]; if(item.id === id){ for(var j=0; j<item.actions.length; j++){ var action = item.actions[j]; if(action.name === 'sendPicture'){ for(var k=0; k<action.pictures.length; k++){ var picture = action.pictures[k]; if(!picture.deleted){ pictures.push(picture); } } } } } } return pictures;}

function getPictures(items, id){ return items .find(function(item){ return item.id === id; }).actions .filter(function(action){ return action.name === 'sendPicture'; }) .map(function(action){ return action.pictures; }) .reduce(function(a, b){ return a.concat(b); }, []) .filter(function(picture){ return !picture.deleted; });}

Safe ?

Page 37: FP is coming... le 19/05/2016

public List<Picture> getPictures(List<Item> items, String id) { List<Picture> pictures = new ArrayList<>(); for (Item item : items) { if (item.getId() == id) { for (Action action : item.getActions()) { if (action.getName() == "sendPicture") { for (Picture picture : action.getPictures()) { if (!picture.getDeleted()) { pictures.add(picture); } } } } } } return pictures;}

def getPictures(items: List[Item], id: String): List[Picture] = items .find(_.id == id) .map(_.actions).getOrElse(List()) .filter(_.name == "sendPicture") .flatMap(_.pictures) .filter(!_.deleted)

Manipuler des donnéesfunction getPictures(items, id){ var pictures = []; for(var i=0; i<items.length; i++){ var item = items[i]; if(item.id === id){ for(var j=0; j<item.actions.length; j++){ var action = item.actions[j]; if(action.name === 'sendPicture'){ for(var k=0; k<action.pictures.length; k++){ var picture = action.pictures[k]; if(!picture.deleted){ pictures.push(picture); } } } } } } return pictures;}

function getPictures(items, id){ return items .find(function(item){ return item.id === id; }).actions .filter(function(action){ return action.name === 'sendPicture'; }) .map(function(action){ return action.pictures; }) .reduce(function(a, b){ return a.concat(b); }, []) .filter(function(picture){ return !picture.deleted; });}

Cannot read property 'xxx' of

undefined x 6 !!!

Page 38: FP is coming... le 19/05/2016

public List<Picture> getPictures(List<Item> items, String id) { List<Picture> pictures = new ArrayList<>(); for (Item item : items) { if (item.getId() == id) { for (Action action : item.getActions()) { if (action.getName() == "sendPicture") { for (Picture picture : action.getPictures()) { if (!picture.getDeleted()) { pictures.add(picture); } } } } } } return pictures;}

def getPictures(items: List[Item], id: String): List[Picture] = items .find(_.id == id) .map(_.actions).getOrElse(List()) .filter(_.name == "sendPicture") .flatMap(_.pictures) .filter(!_.deleted)

Manipuler des donnéesfunction getPictures(items, id){ var pictures = []; for(var i=0; i<items.length; i++){ var item = items[i]; if(item.id === id){ for(var j=0; j<item.actions.length; j++){ var action = item.actions[j]; if(action.name === 'sendPicture'){ for(var k=0; k<action.pictures.length; k++){ var picture = action.pictures[k]; if(!picture.deleted){ pictures.push(picture); } } } } } } return pictures;}

function getPictures(items, id){ return items .find(function(item){ return item.id === id; }).actions .filter(function(action){ return action.name === 'sendPicture'; }) .map(function(action){ return action.pictures; }) .reduce(function(a, b){ return a.concat(b); }, []) .filter(function(picture){ return !picture.deleted; });}

Cannot read property 'xxx' of

undefined x 6 !!!

Page 39: FP is coming... le 19/05/2016

public List<Picture> getPictures(List<Item> items, String id) { List<Picture> pictures = new ArrayList<>(); for (Item item : items) { if (item.getId() == id) { for (Action action : item.getActions()) { if (action.getName() == "sendPicture") { for (Picture picture : action.getPictures()) { if (!picture.getDeleted()) { pictures.add(picture); } } } } } } return pictures;}

def getPictures(items: List[Item], id: String): List[Picture] = items .find(_.id == id) .map(_.actions).getOrElse(List()) .filter(_.name == "sendPicture") .flatMap(_.pictures) .filter(!_.deleted)

Manipuler des donnéesfunction getPictures(items, id){ var pictures = []; for(var i=0; i<items.length; i++){ var item = items[i]; if(item.id === id){ for(var j=0; j<item.actions.length; j++){ var action = item.actions[j]; if(action.name === 'sendPicture'){ for(var k=0; k<action.pictures.length; k++){ var picture = action.pictures[k]; if(!picture.deleted){ pictures.push(picture); } } } } } } return pictures;}

function getPictures(items, id){ return items .find(function(item){ return item.id === id; }).actions .filter(function(action){ return action.name === 'sendPicture'; }) .map(function(action){ return action.pictures; }) .reduce(function(a, b){ return a.concat(b); }, []) .filter(function(picture){ return !picture.deleted; });}

Cannot read property 'xxx' of

undefined x 6 !!!java.lang.NullPointerException x 6 !!!

Page 40: FP is coming... le 19/05/2016

public List<Picture> getPictures(List<Item> items, String id) { List<Picture> pictures = new ArrayList<>(); for (Item item : items) { if (item.getId() == id) { for (Action action : item.getActions()) { if (action.getName() == "sendPicture") { for (Picture picture : action.getPictures()) { if (!picture.getDeleted()) { pictures.add(picture); } } } } } } return pictures;}

def getPictures(items: List[Item], id: String): List[Picture] = items .find(_.id == id) .map(_.actions).getOrElse(List()) .filter(_.name == "sendPicture") .flatMap(_.pictures) .filter(!_.deleted)

Manipuler des donnéesfunction getPictures(items, id){ var pictures = []; for(var i=0; i<items.length; i++){ var item = items[i]; if(item.id === id){ for(var j=0; j<item.actions.length; j++){ var action = item.actions[j]; if(action.name === 'sendPicture'){ for(var k=0; k<action.pictures.length; k++){ var picture = action.pictures[k]; if(!picture.deleted){ pictures.push(picture); } } } } } } return pictures;}

function getPictures(items, id){ return items .find(function(item){ return item.id === id; }).actions .filter(function(action){ return action.name === 'sendPicture'; }) .map(function(action){ return action.pictures; }) .reduce(function(a, b){ return a.concat(b); }, []) .filter(function(picture){ return !picture.deleted; });}

Cannot read property 'xxx' of

undefined x 6 !!!java.lang.NullPointerException x 6 !!!

Safe code \o/

Page 41: FP is coming... le 19/05/2016

Java “Safe”public List<Picture> getPictures(List<Item> items, String id) { List<Picture> pictures = new ArrayList<>(); if (items != null) { for (Item item : items) { if (item != null && item.getId() == id && item.getActions() != null) { for (Action action : item.getActions()) { if (action != null && action.getName() == "sendPicture" && action.getPictures() != null) { for (Picture picture : action.getPictures()) { if (picture != null && !picture.getDeleted()) { pictures.add(picture); } } } } } } } return pictures;}

def getPictures(items: List[Item], id: String): List[Picture] = items .find(_.id == id) .map(_.actions).getOrElse(List()) .filter(_.name == "sendPicture") .flatMap(_.pictures) .filter(!_.deleted)

Page 42: FP is coming... le 19/05/2016

Option

Page 43: FP is coming... le 19/05/2016

Le problèmefunction getName(user) { return user.name;}

Page 44: FP is coming... le 19/05/2016

Le problèmefunction getName(user) { return user.name;}

public String getName(User user) { return user.getName();}

Page 45: FP is coming... le 19/05/2016

Le problèmefunction getName(user) { return user.name;}

public String getName(User user) { return user.getName();}

def getUser(user: User): String = user.name

Page 46: FP is coming... le 19/05/2016

Le problèmefunction getName(user) { return user.name;}

getName();// Cannot read property 'name' of undefined

public String getName(User user) { return user.getName();}

getName(null);// java.lang.NullPointerException

def getUser(user: User): String = user.name

// no null (used) in scala !

Page 47: FP is coming... le 19/05/2016

Le problèmefunction getName(user) { return user.name;}

getName();// Cannot read property 'name' of undefined

getName(localStorage.getItem('user'));// ERROR ???

public String getName(User user) { return user.getName();}

getName(null);// java.lang.NullPointerException

getName(getUser());// ERROR ???

def getUser(user: User): String = user.name

// no null (used) in scala !

Page 48: FP is coming... le 19/05/2016

Le problèmefunction getName(user) { return user.name;}

getName();// Cannot read property 'name' of undefined

getName(localStorage.getItem('user'));// ERROR ???

function getName(user) { return user ? user.name : '';}function getName(user) { return (user || {}).name;}

public String getName(User user) { return user.getName();}

getName(null);// java.lang.NullPointerException

getName(getUser());// ERROR ???

public String getName(User user) { if(user != null){ return user.getName(); } else { return ""; }}

def getUser(user: User): String = user.name

// no null (used) in scala !

Page 49: FP is coming... le 19/05/2016

Option

Page 50: FP is coming... le 19/05/2016

Le problèmefunction getName(user) { return user.name;}

getName();// Cannot read property 'name' of undefined

getName(localStorage.getItem('user'));// ERROR ???

function getName(user) { return user ? user.name : '';}

function getName(user) { return (user || {}).name;}

public String getName(User user) { return user.getName();}

getName(null);// java.lang.NullPointerException

getName(getUser());// ERROR ???

public String getName(User user) { if(user != null){ return user.getName(); } else { return ""; }}

def getUser(user: User): String = user.name

// no null (used) in scala !

def getUser(user: Option[User]): Option[String] = user.map(_.name)

def getUser(user: Option[User]): String = user.map(_.name).getOrElse("")

Page 51: FP is coming... le 19/05/2016

List.map() vs Option.map()

Page 52: FP is coming... le 19/05/2016

Monad

Page 53: FP is coming... le 19/05/2016

Monad

● Wrapper (context) M[A]

● Fonction map def map[B](f: A => B): M[B]

● Fonction flatMap def flatMap[B](f: A => M[B]): M[B]

Page 54: FP is coming... le 19/05/2016

Monad

● List

● Option

● Future

● Try

● ...

Page 55: FP is coming... le 19/05/2016

Basics

Page 56: FP is coming... le 19/05/2016

Typage fort

Page 57: FP is coming... le 19/05/2016

Typage fort

● Filet de sécurité pour garantir la cohérence du programme

Page 58: FP is coming... le 19/05/2016

Typage fort

● Filet de sécurité pour garantir la cohérence du programme

● Documentation pour le développeur

Page 59: FP is coming... le 19/05/2016

Typage fort

● Filet de sécurité pour garantir la cohérence du programme

● Documentation pour le développeur

● Implémentent certains concepts

Page 60: FP is coming... le 19/05/2016

Typage fort

● Filet de sécurité pour garantir la cohérence du programme

● Documentation pour le développeur

● Implémentent certains concepts

● null => Option

Page 61: FP is coming... le 19/05/2016

Typage fort

● Filet de sécurité pour garantir la cohérence du programme

● Documentation pour le développeur

● Implémentent certains concepts

● null => Option● exception => Either / Try

Page 62: FP is coming... le 19/05/2016

Typage fort

● Filet de sécurité pour garantir la cohérence du programme

● Documentation pour le développeur

● Implémentent certains concepts

● null => Option● exception => Either / Try● async => Future● ...

Page 63: FP is coming... le 19/05/2016

Typage fort

● Filet de sécurité pour garantir la cohérence du programme

● Documentation pour le développeur

● Implémentent certains concepts

● Type Driven Development

Page 64: FP is coming... le 19/05/2016

Type all the things !!!case class Contact(

firstName: String, middleInitial: String, lastName: String,

emailAddress: String, isEmailVerified: Boolean

)

Page 65: FP is coming... le 19/05/2016

Type all the things !!!case class Contact(

firstName: String, middleInitial: String, lastName: String,

emailAddress: String, isEmailVerified: Boolean

)

Optionnel ?

Page 66: FP is coming... le 19/05/2016

Type all the things !!!case class Contact(

firstName: String, middleInitial: String, lastName: String,

emailAddress: String, isEmailVerified: Boolean

)

Optionnel ?Contrainte ?

Page 67: FP is coming... le 19/05/2016

Type all the things !!!case class Contact(

firstName: String, middleInitial: String, lastName: String,

emailAddress: String, isEmailVerified: Boolean

)

Optionnel ?Contrainte ?

Lien ?

Page 68: FP is coming... le 19/05/2016

Type all the things !!!case class Contact(

firstName: String, middleInitial: String, lastName: String,

emailAddress: String, isEmailVerified: Boolean

)

Optionnel ?Contrainte ?

Lien ?

Logique métier ?

Page 69: FP is coming... le 19/05/2016

Type all the things !!!case class Contact(

firstName: String, middleInitial: String, lastName: String,

emailAddress: String, isEmailVerified: Boolean

)

case class Contact( name: PersonalName, email: EmailAddress)

Optionnel ?Contrainte ?

Lien ?

Logique métier ?

Page 70: FP is coming... le 19/05/2016

Type all the things !!!case class Contact(

firstName: String, middleInitial: String, lastName: String,

emailAddress: String, isEmailVerified: Boolean

)

case class Contact( name: PersonalName, email: EmailAddress)

case class PersonalName( firstName: String_50, middleInitial: Option[String_1], lastName: String_50)

sealed trait EmailAddresscase class VerifiedEmail(value: Email) extends EmailAddresscase class UnverifiedEmail(value: Email) extends EmailAddress

Optionnel ?Contrainte ?

Lien ?

Logique métier ?

Page 71: FP is coming... le 19/05/2016

Type all the things !!!case class Contact(

firstName: String, middleInitial: String, lastName: String,

emailAddress: String, isEmailVerified: Boolean

)

case class Contact( name: PersonalName, email: EmailAddress)

case class PersonalName( firstName: String_50, middleInitial: Option[String_1], lastName: String_50)

sealed trait EmailAddresscase class VerifiedEmail(value: Email) extends EmailAddresscase class UnverifiedEmail(value: Email) extends EmailAddress

case class String_1(value: String) { require(value.length <= 1, s"String_1 should be <= 1 (actual: $value)") override def toString: String = value}case class String_50(value: String) { require(value.length <= 50, s"String_50 should be <= 50 (actual: $value)") override def toString: String = value}case class Email(value: String) { require(value.contains("@"), s"Email should contain '@' (actual: $value)") override def toString: String = value}

Optionnel ?Contrainte ?

Lien ?

Logique métier ?

Page 72: FP is coming... le 19/05/2016

Stateless

Page 73: FP is coming... le 19/05/2016

Stateless

Passer toute les données nécessaires à chaque fois

Page 74: FP is coming... le 19/05/2016

Stateless

Passer toute les données nécessaires à chaque fois

● Testabilité

Page 75: FP is coming... le 19/05/2016

Stateless

Passer toute les données nécessaires à chaque fois

● Testabilité

● Plus facile à comprendre

Page 76: FP is coming... le 19/05/2016

Immutabilité

Page 77: FP is coming... le 19/05/2016

Immutabilité

Page 78: FP is coming... le 19/05/2016

Immutabilité

● Scalabilité / Multithreading

Page 79: FP is coming... le 19/05/2016

Immutabilité

● Scalabilité / Multithreading

● Meilleur nommage

Page 80: FP is coming... le 19/05/2016

Immutabilité

● Scalabilité / Multithreading

● Meilleur nommage

● Séparation données / calculs

Types et Fonctions plutôt que Classes :

● Entity● Value Object● Service

Page 81: FP is coming... le 19/05/2016

Immutabilité

● Scalabilité / Multithreading

● Meilleur nommage

● Séparation données / calculs

Types et Fonctions plutôt que Classes :

● Entity● Value Object● Service

case class Person( firstName: String, lastName: String) { val fullName = Person.fullName(this)}object Person { def fullName(p: Person): String = p.firstName+" "+p.lastName}

Page 82: FP is coming... le 19/05/2016

No side effectEffet de bord: lancer une exception, faire un appel (bdd, http, fichier…), récupérer la date actuelle,

modifier un paramètre, accéder à une variable “globale”, afficher un log...

Page 83: FP is coming... le 19/05/2016

No side effect

Page 84: FP is coming... le 19/05/2016

No side effect

● Fonctions plus faciles à comprendre et à composer

● Possibilité de construire des choses complexes à partir d’éléments simples

● Local reasoning

Page 85: FP is coming... le 19/05/2016

● Lancer une exception ?

No side effect

Page 86: FP is coming... le 19/05/2016

● Lancer une exception ?

No side effect

Renvoyer un Type d’erreur :

● Option[A] : un type ou pas● Try[A] : un type ou un Throwable● Either[A, B] : un type ou un autre● Validation[A, Seq[ValidationError]] : un type ou une liste d’erreur

Page 87: FP is coming... le 19/05/2016

● Lancer une exception ?● Accès à une base de données ?

No side effect

Page 88: FP is coming... le 19/05/2016

● Lancer une exception ?● Accès à une base de données ?

No side effect

Effet de bord fait :● en “bordure du système”● idéalement par une librairie● représenté par un type (Future, IO…)

Ex : def getDBUser(id: UserId): Future[Option[User]] = ???

Page 89: FP is coming... le 19/05/2016

● Lancer une exception ?● Accès à une base de données ?● Afficher un log ?

No side effect

Page 90: FP is coming... le 19/05/2016

● Lancer une exception ?● Accès à une base de données ?● Afficher un log ?

No side effect

On peut éventuellement se permettre un peu de liberté...

Page 91: FP is coming... le 19/05/2016

Architecture Hexagonale

strict FPsoft FP

Page 92: FP is coming... le 19/05/2016

“Easy to learn/write”vs

“Easy to maintain”

Page 93: FP is coming... le 19/05/2016
Page 94: FP is coming... le 19/05/2016

DDD

Hexagonal architecture

Event Storming

Property based testing

Event Sourcing

Clean code

TDDBDD

Craftsmanship

Living Documentation

CQRS

Page 95: FP is coming... le 19/05/2016

Take away

● Paramètre de fonction plutôt que donnée globale (même de classe)

● Créer des objets plutôt que de les modifier (immutable)

● Option plutôt que ‘null’

● Either/Try plutôt qu’une exception

● Collection API / recursivité plutôt que boucles for/while

● Eviter les ‘if’ autant que possible

● Séparation métier / technique

Page 96: FP is coming... le 19/05/2016

Recommended