Upload
gabriele-tondi
View
315
Download
0
Embed Size (px)
Citation preview
Abilitare l'agilità con il design
semplice
Mini IAD Vimercate 2017Gabriele Tondi - @racingDeveloper
public static Set<Coordinate> nextGeneration(Set<Coordinate> liveCells){ Set<Coordinate> nextGeneration = new HashSet<>();
for (Coordinate liveCell : liveCells) { Set<Coordinate> block = new HashSet<>(); for (int currentX1 = liveCell.x - 1; currentX1 <= liveCell.x + 1; currentX1++) { for (int currentY1 = liveCell.y - 1; currentY1 <= liveCell.y + 1; currentY1++) { block.add(new Coordinate(currentX1, currentY1));}}
block.remove(liveCell);
for (Coordinate currentCell : block) { int liveCellsCount = 0;
Set<Coordinate> currentBlock = new HashSet<>(); for (int currentX = currentCell.x - 1; currentX <= currentCell.x + 1; currentX++) { for (int currentY = currentCell.y - 1; currentY <= currentCell.y + 1; currentY++) { currentBlock.add(new Coordinate(currentX, currentY));}}
currentBlock.remove(currentCell); for (Coordinate coordinate : currentBlock) { if (liveCells.contains(coordinate)) { liveCellsCount++; }}
int aliveCells = liveCellsCount;
if (liveCells.contains(currentCell)) { if (aliveCells == 2 || aliveCells == 3) { nextGeneration.add(currentCell); }} else { if (aliveCells == 3) { nextGeneration.add(currentCell); }}}}
return nextGeneration;} A
public class World {
public World evolve() { Set<Cell> nextGeneration = nextGeneration = cells.stream() .map(cell -> cell .coordinate() .blockIncludeSelf()) .flatMap(coordinates -> coordinates .stream()) .map(coordinate -> evolveAt(coordinate)) .collect(toSet());
return new World(nextGeneration); }
private Cell evolveAt(Coordinate coordinate) { return cellAt(coordinate) .evolve(aliveNeighboursOf(coordinate)); }
private Cell cellAt(Coordinate coordinate) { return cells.stream() .filter(c -> c.isAt(coordinate)) .findFirst() .orElse(new DeadCell(coordinate)); }
public int aliveNeighboursOf(Coordinate c) { Set<Coordinate> block = c.block(); block.retainAll(aliveCellsCoordinates());
return block.size(); }
B
private Set<Cell> aliveCells() { return cells.stream() .filter(c -> c.isAlive()) .collect(toSet()); }
private Set<Coordinate> aliveCellsCoordinates() { return aliveCells().stream() .map(c -> c.coordinate()) .collect(toSet()); }}
public class AliveCell extends Cell { public Cell evolve(int aliveNeighboursCount){ // [...] }}
public class DeadCell extends Cell { public Cell evolve(int aliveNeighboursCount){ // [...] }}
public class Coordinate { public Set<Coordinate> block() { // [...] }
public Set<Coordinate> blockIncludeSelf(){ // [...] }}
Cosa cambia?
Struttura, ossia design.
Perché facciamo design?
Vanità?
Stile?
Arte?
NO!
Riduzione e controllo del costo del cambiamento
Cosa fareste?
tempo
cost
o ca
mbi
amen
to
Quanto ne sappiamo all'inizio?
Cosa fareste?
tempo
cost
o ca
mbi
amen
to
Quanto ne sappiamo?
design speculativo
assunzioni errateaumento costo cambiamento
per evitare di pagare un costo alto provo ad anticipare il
cambiamento
le speculazioni errate mi costano
per avere più possibilità di azzeccarci devo fare più
assunzioni!
Kent Beck spezza il ciclo a retroazione positiva
Prova a prevedere i cambiamenti ad un mese
...ad una settimana
...ad un giorno
...fino al momento stesso
4 regole del design semplice
Semplice? Il mio design è già semplice per me!
SempliceEtimologia:
lat. simplĭce(m), comp. di sem- ‘una volta’ e -plex, corradicale di plectĕre ‘intrecciare’ e plicāre ‘piegare’; propr. ‘intrecciato, piegato una sola volta’.
Definizione:
formato di un solo elemento
fonte: http://www.garzantilinguistica.it
FacileEtimologia:
lat. facĭle(m), deriv. di facĕre ‘fare’; propr. ‘che si fa, che è possibile fare’.
Definizione:
che si può fare senza difficoltà; agevole, comodo
che si ottiene con poca o senza fatica
fonte: http://www.garzantilinguistica.it
Facile è soggettivo
Semplice è oggettivo
Ci serve un metro per misurare in maniera oggettiva il design
Il design semplice:1. passa tutti i test
2. esprime l'intento
3. non contiene duplicazione
4. viene realizzato con il minor numero di elementi possibili
L'ordine conta
Il design semplice:
1. passa tutti i test
2. esprime l'intento
3. non contiene duplicazione
4. viene realizzato con il minor numero di elementi possibili
PRIORITÀ
+-
1. passa tutti i test
2. esprime l'intento
3. non contiene duplicazione
4. viene realizzato con il minor numero di elementi possibili
Devo poter verificare rapidamente i cambiamenti
Ah, quindi deve essere testabile!
1. passa tutti i test
2. esprime l'intento
3. non contiene duplicazione
4. viene realizzato con il minor numero di elementi possibili
Non è solo questione di naming (variabili, metodi privati etc)
Cos'è l'intento?
public List<Customer> selectWhereNameLike(String name)
public List<Customer> searchByName(String name)
Cos'è l'intento?
public void sendMailUsingSmtp(MailMessage message)
public void sendMessage(Message message)
Intento: cosa fa, non come lo fa!
Intento => Astrazione
Le astrazioni riducono l'accoppiamento
1. passa tutti i test
2. esprime l'intento
3. non contiene duplicazione
4. viene realizzato con il minor numero di elementi possibili
public static Set<Coordinate> nextGeneration(Set<Coordinate> liveCells){ Set<Coordinate> nextGeneration = new HashSet<>();
for (Coordinate liveCell : liveCells) { Set<Coordinate> block = new HashSet<>(); for (int currentX1 = liveCell.x - 1; currentX1 <= liveCell.x + 1; currentX1++) { for (int currentY1 = liveCell.y - 1; currentY1 <= liveCell.y + 1; currentY1++) { block.add(new Coordinate(currentX1, currentY1));}}
block.remove(liveCell);
for (Coordinate currentCell : block) { int liveCellsCount = 0;
Set<Coordinate> currentBlock = new HashSet<>(); for (int currentX = currentCell.x - 1; currentX <= currentCell.x + 1; currentX++) { for (int currentY = currentCell.y - 1; currentY <= currentCell.y + 1; currentY++) { currentBlock.add(new Coordinate(currentX, currentY));}}
currentBlock.remove(currentCell);
for (Coordinate coordinate : currentBlock) { if (liveCells.contains(coordinate)) { liveCellsCount++; }}
int aliveCells = liveCellsCount;
if (liveCells.contains(currentCell)) { if (aliveCells == 2 || aliveCells == 3) { nextGeneration.add(currentCell); }} else { if (aliveCells == 3) { nextGeneration.add(currentCell); }}}}
return nextGeneration;}
public static Set<Coordinate> nextGeneration(Set<Coordinate> liveCells){ Set<Coordinate> nextGeneration = new HashSet<>();
for (Coordinate liveCell : liveCells) { Set<Coordinate> block = new HashSet<>(); for (int currentX1 = liveCell.x - 1; currentX1 <= liveCell.x + 1; currentX1++) { for (int currentY1 = liveCell.y - 1; currentY1 <= liveCell.y + 1; currentY1++) { block.add(new Coordinate(currentX1, currentY1));}}
block.remove(liveCell);
for (Coordinate currentCell : block) { int liveCellsCount = 0;
Set<Coordinate> currentBlock = new HashSet<>(); for (int currentX = currentCell.x - 1; currentX <= currentCell.x + 1; currentX++) { for (int currentY = currentCell.y - 1; currentY <= currentCell.y + 1; currentY++) { currentBlock.add(new Coordinate(currentX, currentY));}}
currentBlock.remove(currentCell);
for (Coordinate coordinate : currentBlock) { if (liveCells.contains(coordinate)) { liveCellsCount++; }}
int aliveCells = liveCellsCount;
if (liveCells.contains(currentCell)) { if (aliveCells == 2 || aliveCells == 3) { nextGeneration.add(currentCell); }} else { if (aliveCells == 3) { nextGeneration.add(currentCell); }}}}
return nextGeneration;}
Cos'è la duplicazione?public Cell cellAt(int x, int y) { // [...]}
public Set<Cell> neighboursOf(int x, int y) { // [...]}
public bool isAliveAt(int x, int y) { // [...]}
Duplicazione di conoscenza, non di righe di codice
Riduco la duplicazione?public Cell cellAt(Coordinate coordinate) { // [...]}
public Set<Cell> neighboursOf(Coordinate coordinate) { // [...]}
public bool isAliveAt(Coordinate coordinate) { // [...]}
public class Coordinate { public int getX(); public int getY();}
Attrattore di comportamentipublic Cell cellAt(Coordinate coordinate) { // [...]}
public bool isAliveAt(Coordinate coordinate) { // [...]}
public class Coordinate { public Set<Coordinate> neighbours() { // [...] }}
Ridurre la duplicazione => Aumentare la coesione
É più importante ridurre la duplicazione o chiarire l'intento?
Le regole 2 e 3 lavorano in simbiosi
The Simple Design Dinamo (@jbrains)
1. passa tutti i test
2. esprime l'intento, non contiene duplicazione
3. viene realizzato con il minor numero di elementi possibili
Rimuoviamo il codice morto.
Facciamo emergere solo gli elementi necessari oggi
Il design è semplice se:1. posso verificarne il comportamento rapidamente
2. ha poco accoppiamento ed è molto coeso
3. è conciso
Costo del cambiamento (eXtreme Programming)
tempo
cost
o ca
mbi
amen
to
In conclusione
Per essere agili dobbiamo poter cambiare il nostro software con costi contenuti
Usiamo il design per ridurre e controllare il costo del cambiamento
Il design semplice ci indica la direzione
"Simplicity is prerequisite for reliability."Edsger W. Dijkstra
Per approfondire● K. Beck: eXtreme Programming Explained
● C. Haines: Understanding the Four Rules of Simple Designhttps://leanpub.com/4rulesofsimpledesign
● J.B.Rainsberger: Putting an age old battle to resthttp://blog.thecodewhisperer.com/permalink/putting-an-age-old-battle-to-rest
● M. Fowler: BeckDesignRuleshttps://martinfowler.com/bliki/BeckDesignRules.html
● C2 Wiki: Xp Simplicity Ruleshttp://wiki.c2.com/?XpSimplicityRules
Gabriele Tondi
@racingDeveloper [email protected]
Grazie!
Rimini, 25-27 Maggio 2017
http://www.socrates-conference.it
Domande?