from mess to masterpiece - jfokus 2017

Post on 13-Apr-2017

42 Views

Category:

Software

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

prepare for…

From mess to masterpiecerefactoring done right

@SvenRuppert

@SvenRuppert has been coding java since 1996

Projects in the field of: •Automobile-industry •Energy •Finance / Leasing •Space- Satellit- •Government / UN / World-bank

Where?

•Europe •Asia - from India up to Malaysia

2

Our journey todaywhat is the situation…..

3

@SvenRuppert

4

@SvenRuppertAt the time I started - 3 yrs ago

Codebase is > 13 years old no test coverage

Code Lordsnearly 15% are retired soon

over 50% are since 15 yrs in the company

the developers learned Java at this project

hiring only students

the first feeling was like ……

5

@SvenRuppertAt the time I started - 3 yrs ago

6

What is part of a refactoring ?

the teamthe source code

the processesthe project management

the knowledgebudget and time line

infrastructure

@SvenRuppert

7

What is part of a refactoring ?

the team

the source code the processes

the project managementthe knowledge

budget and time line} }team transformation

C-level transformation

infrastructure

@SvenRuppert

prepare for

Refactoring - the first stepswithout this you should not start

8

@SvenRuppert

9

@SvenRuppertfirst steps - Start Small

10

@SvenRuppertfirst steps - Think Bigger

11

@SvenRuppertfirst steps - Build a Team

12

@SvenRuppertfirst steps - build trust

prepare for

Refactoring - the way of workingstart with individual responsibility

13

@SvenRuppert

14

@SvenRuppertThe way of working

20% Time have time to play or try

start learning how to practice it ?Closed Source versus Open Source

work from everywhere at your time

we started step by step

15

@SvenRuppertwork from everywhere

16

@SvenRuppertwork from everywhere

change your environment

use Messenger like Slack avoid mailsremote meetings with zoom

remote Pair-Programmingwork async.

work at your time that is the best for you

17

@SvenRuppertwork from everywhere

work at your time that is the best for youmy „normal“ day…

working05AM to 07AMbreakfast with the family07AM to 09AMworking09AM to 12AMplaying with my son12AM to 07PMplaying with my wife 07PM to 09PMworking09PM to 11PM

and yes… I need only 6h sleep ;-)

18

@SvenRuppertwork from everywhere

work at your time that is the best for youmy „normal“ day…

working05AM to 07AMworking09AM to 12AMworking09PM to 11PM

working with Asiaworking with Europeworking with US

19

@SvenRuppertThe way of working

why you should do it?20% Time

lost in daily business

20

@SvenRuppertThe way of working

how to make it useful ?

example : POC with the team in the Mountains

for the developer

for the company

20% Time

prepare for

Refactoring - Divide your codewhat is the part you are earning money with

21

@SvenRuppert

22

@SvenRuppertClosed- versus Open Source

Analyzing the existing Code in our case : a lot of infrastructure…

..with this we are not earning money

we divided the code base

dev. environment

23

@SvenRuppertClosed- versus Open Source

we divided the

code base dev. environment

could write articles about itdiscuss at conferences

will lead to better documentation

out of company rulesfree choice of tools

higher motivation

prepare for

Refactoring - the reactionsdon´t forget the team you are working with

24

@SvenRuppert

25

@SvenRuppertThe way of working

Start Learning againfor example:

functionaladd a new Languagefocus on a new paradigm

but not everyone want to learn or better…. some are learning faster

reactive

this sometimes leads to ….. reactions….

26

@SvenRuppertThe way of working

Start Learning againthis sometimes leads to ….. reactions….

running away

27

@SvenRuppertThe way of working

Start Learning againthis sometimes leads to ….. reactions….

expecting something

28

@SvenRuppertThe way of working

Start Learning againthis sometimes leads to ….. reactions….

feeling the near end

29

@SvenRuppertThe way of working

Start Learning againthis sometimes leads to ….. reactions….

or only feeling to old

30

@SvenRuppertThe way of working

Start Learning againthis sometimes leads to ….. reactions….

you have to deal with this

if you don´t want to loose them

make them happy again

How we solved

this?

prepare for

Refactoring - Projectmanagementone size fit´s all ?

31

@SvenRuppert

32

@SvenRuppertThe way of working

we are a product company with a lot of LTS contracts

we created three streams

Consultants - play and throw awayCore Developers - collect and clean

LTS Developers - keep alive

Why ?

33

@SvenRuppertThe way of working

Consultants - play and throw awayCore Developer - collect and cleanLTS Developer - keep alive Why ?some want to learn and experimentsome need more stabil environmentssome did not want to change something

34

@SvenRuppertThe way of working

Consultants - play and throw away

Core Developer - collect and clean

LTS Developer - keep alive

Why ?some want to learn and experiment

some need more stabil environments

some did not want to change something

amount of hours paid by the customer

rated on hours the systems are stabil

fixed income - bonus based on Change Request

35

@SvenRuppertThe way of working

Consultants - play and throw away

Core Developer - collect and clean

LTS Developer - keep aliveSCRUM

Kanban

customer driven

roadmap driven

36

@SvenRuppertThe way of working

SCRUM

Kanban

Consultants

LTS - Developers

Core - Developers Core - Developers

Fire

Consultants

37

@SvenRuppertThe way of working

SCRUM

Kanban

Consultants

LTS - Developers

Core - Developers

Consultants Consultants Consultants

LTS - Developers LTS - Developers

Core - Developers Core - Developers

time based planning fixed size time slots

version based dynamic size time slots

prepare for

Refactoring - Start learning againlearn how to learn together with a team again

38

@SvenRuppert

39

@SvenRuppertKnowledge Sharing

Consultants

LTS - Developers

Core - Developers

build a source of knowledge

40

@SvenRuppertKnowledge Sharing

Consultants

LTS - Developers

Core - Developers

Hacking session

Articles / Blogs

Screencasts Refactoring SessionsPOC

41

@SvenRuppertKnowledge SharingHow to motivate your team to do it ?

explain it !!

prepare for

Refactoring - Technologieschoose your weapons

42

@SvenRuppert

43

@SvenRuppertTechnical Migrations

if you ask the consultants…to scale or change you need at least … ;-)

NoSQL

Events

Akka / Scala

ReactiveFunctional

maybe ;-)

44

@SvenRuppertTechnical Transformation

Swing Vaadin

HashMap Hazelcast - Map

JDBC - ResultSet Speedment - Streams

what is the right technology for your team? what is the right order?

Java OOP Java FRP

45

@SvenRuppertTechnical Transformation

what is the right technology for your team?

what is the right order?

reduce complexityscale

the team could work with

a lot more….

start with new modules ?start with the oldest one ?

most komplex one?… or ….

46

@SvenRuppertTechnical Transformation

on thing that would limit your speed…

time

number of versions

v1

v2stabilize

47

@SvenRuppertTechnical Transformation

on thing that would limit your speed…

time

number of versions v2stabilize

delta t compared to project lifetime

prepare for

Refactoring - Safety belt choose your weapons

48

@SvenRuppert

49

@SvenRuppertQM / QS - TDD

Do you have bugs in your code ?

since years you are

working hard on this….

no

50

@SvenRuppertQM / QS - TDD

Codebase is > 13 years old no test coverage

how to decrease complexity?

remember….

how to start?what is the right point to start?

how to increase the quality of the tests?

51

TDD with jUnit @SvenRuppert

are you using jUnit?

assume that the following would make sense.. ;-)

public class Service { public int add(int a, int b){ if(a<2){ return (a+b) * -1; } else { return a+b; } }}

How many tests

you will need ?

it depends ;-)

52

TDD with jUnit @SvenRuppert

public class Service { public int add(int a, int b){ if(a<2){ return (a+b) * -1; } else { return a+b; } }}

How many tests

you will need ?

for line 100% coverage 2

but will this be enough? maybe ;-)

how to find out, what will be enough?how to find the right tests?

it depends ;-)

53

Mutation Testing @SvenRuppert

generating the mutants and

practical TDD with Mutation Testing

running all junit testscheck the reports

write more / better tests

loop until quality target reached

54

Mutation Testing - Hello World @SvenRuppert

public class Service { public int add(int a, int b){ if (a<2) { return (a+b) * -1; } else { return a+b; } }} 100% Line Coverage… and…@Testpublic void testAdd001() throws Exception { final int add = new Service().add(0, 0); Assertions.assertThat(add).isEqualTo(0); } @Test

public void testAdd002() throws Exception { final int add = new Service().add(3, 0); Assertions.assertThat(add).isEqualTo(3); }

55

Mutation Testing - Hello World @SvenRuppert

final int add = new Service().add(0, 0); Assertions.assertThat(add).isEqualTo(0);

final int add = new Service().add(3, 0); Assertions.assertThat(add).isEqualTo(3);

56

Mutation Testing - Hello World @SvenRuppert

final int add = new Service().add(0, 0);final int add = new Service().add(3, 0);

>> Generated mutations Killed 3

57

Mutation Testing - Hello World @SvenRuppert

final int add = new Service().add(0, 0);final int add = new Service().add(3, 0);

>> Generated mutations Killed 3

58

Mutation Testing - in short words @SvenRuppert

mutation testing is an add on to normal jUnit TDD

tools are supporting it well

generating and running all tests are time consuming

but most important

will effect your project structure

59

Mutation Testing - Lesson Learned @SvenRuppert

mutation tests are often leading to

…cleaner code compared to jUnit only

60

Mutation Testing - Lesson Learned @SvenRuppert

public static final String[] discardCommonPrefix(String a, String b) { String[] ret = { a, b }; int l = a.length() < b.length() ? a.length() : b.length(); for (int i = 0; i < l; i++) { if (a.charAt(i) == b.charAt(i)) { if (i + 1 < l) { ret[0] = a.substring(i + 1); ret[1] = b.substring(i + 1); } else { if (a.length() < b.length()) { ret[0] = ""; ret[1] = b.substring(i + 1); } if (a.length() == b.length()) { ret[0] = ""; ret[1] = „"; } if (a.length() > b.length()) { ret[0] = a.substring(i + 1); ret[1] = „"; } } } else break; } return ret; }

61

Mutation Testing - Lesson Learned @SvenRuppert

public String[] discardCommonPrefix(String a, String b) { final String[] ret = new String[2]; int l; if (a.length() < b.length()) { l = a.length(); } else { l = b.length(); } int position = 0; for (; position < l; position++) { final char charA = a.charAt(position); final char charB = b.charAt(position); if (charA != charB) { break; } }

if (position >= a.length()) { ret[0] = ""; } else { ret[0] = a.substring(position); }

if (position >= b.length()) { ret[1] = ""; } else { ret[1] = b.substring(position); } return ret; }

62

Mutation Testing - Lesson Learned @SvenRuppert

Version 1 Version 2 for { if { if else { if if if } } else }

if else for { if }

if else

if else

63

Example of useless Code @SvenRuppert

Functions

how use Functions…

@SvenRuppert

Functions - Java8

65

@SvenRuppert

Functions - Java8

66

@SvenRuppert

Functions - Java8

67

@SvenRuppert

prepare for

Refactoring - Design Pattern start developing design pattern again

68

@SvenRuppert

NestedBuilder - The Beginning

69

@SvenRuppert

NestedBuilder - The Beginning

70

@SvenRuppert

Car car = Car.newBuilder() .withEngine(engine) .withWheelList(wheels) .build();

Engine engine = Engine.newBuilder().withPower(100).withType(5).build();

Wheel wheel1 = Wheel.newBuilder().withType(2).withColour(3).withSize(4).build(); Wheel wheel2 = Wheel.newBuilder().withType(2).withColour(3).withSize(4).build();Wheel wheel3 = Wheel.newBuilder().withType(2).withColour(3).withSize(4).build();

List<Wheel> wheels = new ArrayList<>(); wheels.add(wheel1); wheels.add(wheel2); wheels.add(wheel3);}

NestedBuilder - The Beginning

71

@SvenRuppert

Car car = Car.newBuilder() .withEngine(engine) .withWheelList(wheels) .build();

Engine engine = Engine.newBuilder().withPower(100).withType(5).build();

Wheel wheel1 = Wheel.newBuilder().withType(2).withColour(3).withSize(4).build(); Wheel wheel2 = Wheel.newBuilder().withType(2).withColour(3).withSize(4).build();Wheel wheel3 = Wheel.newBuilder().withType(2).withColour(3).withSize(4).build();

List<Wheel> wheels = new ArrayList<>(); wheels.add(wheel1); wheels.add(wheel2); wheels.add(wheel3);

NestedBuilder - The Beginning

72

@SvenRuppert

Car car = Car.newBuilder() .withEngine(engine) .withWheelList(wheels) .build();

Engine engine = Engine.newBuilder().withPower(100).withType(5).build();

Wheel wheel1 = Wheel.newBuilder().withType(2).withColour(3).withSize(4).build(); Wheel wheel2 = Wheel.newBuilder().withType(2).withColour(3).withSize(4).build();Wheel wheel3 = Wheel.newBuilder().withType(2).withColour(3).withSize(4).build();

//List<Wheel> wheels = new ArrayList<>();// wheels.add(wheel1);// wheels.add(wheel2);// wheels.add(wheel3);

List<Wheel> wheelList = WheelListBuilder.newBuilder() .withNewList() .addWheel(wheel1) .addWheel(wheel2) .addWheel(wheel3) .build(); //more robust if you add tests at build()

}

}

how to combine ?

List<Wheel> wheels = new ArrayList<>(); wheels.add(wheel1); wheels.add(wheel2); wheels.add(wheel3);

NestedBuilder - The Beginning

73

@SvenRuppert

Car car = Car.newBuilder() .withEngine(engine) .withWheelList(wheels) .build();

Engine engine = Engine.newBuilder().withPower(100).withType(5).build();

Wheel wheel1 = Wheel.newBuilder().withType(2).withColour(3).withSize(4).build(); Wheel wheel2 = Wheel.newBuilder().withType(2).withColour(3).withSize(4).build();Wheel wheel3 = Wheel.newBuilder().withType(2).withColour(3).withSize(4).build();List<Wheel> wheelList = WheelListBuilder.newBuilder() .withNewList() .addWheel(wheel1) .addWheel(wheel2) .addWheel(wheel3) .build();

}

}

how to combine ?

NestedBuilder - The Beginning

74

@SvenRuppert

Car car = Car.newBuilder() .withEngine(engine) .withWheelList(wheels) .build();

Engine engine = Engine.newBuilder().withPower(100).withType(5).build();

// Wheel wheel1 = Wheel.newBuilder().withType(2).withColour(3).withSize(4).build(); // Wheel wheel2 = Wheel.newBuilder().withType(2).withColour(3).withSize(4).build();// Wheel wheel3 = Wheel.newBuilder().withType(2).withColour(3).withSize(4).build();// List<Wheel> wheelList = WheelListBuilder.newBuilder() .withNewList() .addWheel(wheel1) .addWheel(wheel2) .addWheel(wheel3) .build();

List<Wheel> wheels = wheelListBuilder .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .build();

NestedBuilder - The Beginning

75

@SvenRuppert

Car car = Car.newBuilder() .withEngine(engine) .withWheelList(wheels) .build();

Engine engine = Engine.newBuilder().withPower(100).withType(5).build();

List<Wheel> wheels = wheelListBuilder .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .build();

WheelBuilder

WheelListBuilder

NestedBuilder - The Beginning

76

@SvenRuppert

Car car = Car.newBuilder() .withEngine(engine) .withWheelList(wheels) .build();

Engine engine = Engine.newBuilder().withPower(100).withType(5).build();

List<Wheel> wheels = wheelListBuilder .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .build();

now we have to combine all

Car car = Car.newBuilder() .addEngine().withPower(100).withType(5).done() .addWheels() .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .addWheel().withType(1).withSize(2).withColour(2).addWheelToList() .done() .build();

NestedBuilder - The Pattern

77

@SvenRuppert

public abstract class NestedBuilder<T, V> {

protected T parent;public abstract V build()

public <P extends NestedBuilder<T, V>> P withParentBuilder(T parent) { this.parent = parent; return (P) this;} parent will connect itself…

NestedBuilder - The Pattern

78

@SvenRuppert

public abstract class NestedBuilder<T, V> {

public T done() {

Class<?> parentClass = parent.getClass();

try { V build = this.build(); String methodname = "with" + build.getClass().getSimpleName(); Method method = parentClass.getDeclaredMethod( methodname, build.getClass()); method.invoke(parent, build);} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace();}

}

connect itself with parent

NestedBuilder - The Pattern

79

@SvenRuppert

the basic steps in short words

the Parent-Builder will hold the Child-Builderthe Parent-Builder will have a addChild - Methodthe Child-Builder will extend the NestedBuilderthe rest could be generated with a default Builder-Generator

NestedBuilder - The Pattern

80

@SvenRuppert

public class Parent { private KidA kidA; private KidB kidB; //snipp..... public static final class Builder { private KidA kidA; private KidB kidB; // to add manually private KidA.Builder builderKidA = KidA.newBuilder().withParentBuilder(this); private KidB.Builder builderKidB = KidB.newBuilder().withParentBuilder(this); public KidA.Builder addKidA() { return this.builderKidA; } public KidB.Builder addKidB() { return this.builderKidB; } //---------

connect itself with child

switch to Child-Builder

NestedBuilder - The Pattern

81

@SvenRuppert

only extends on Child-Builder

public static final class Builder extends NestedBuilder<Parent.Builder, KidA> {

NestedBuilder - The Pattern

82

@SvenRuppert

Parent build = Parent.newBuilder() .addKidA().withNote("A").done() .addKidB().withNote("B").done() .build();System.out.println("build = " + build);

and a child could be a parent in the same timeParent build = Parent.newBuilder()

.addKidA().withNote("A") .addKidB().withNote("B").done() .done()

.build(); System.out.println("build = " + build);

Refactoring example

based on Java8

@SvenRuppert

84

@SvenRuppertJava8 - Functional Interfaces - Example

typical legacy implementation

85

@SvenRuppertJava8 - Functional Interfaces - Example

typical legacy implementation

86

@SvenRuppertJava8 - Functional Interfaces - Example

87

@SvenRuppertJava8 - Functional Interfaces - Example

88

@SvenRuppertJava8 - Functional Interfaces - Example

89

@SvenRuppertJava8 - Functional Interfaces - Example

90

@SvenRuppertJava8 - Functional Interfaces - Example

91

@SvenRuppertJava8 - Functional Interfaces - Example

Sourcecode is on github

Interpreter - pre Java8

92

@SvenRuppert

Interpreter - pre Java8

93

@SvenRuppert

Interpreter - pre Java8

94

@SvenRuppert

Interpreter - pre Java8

95

@SvenRuppert

Interpreter - Java8 - Java9

96

@SvenRuppert

Interpreter - Java8 - Java9

97

@SvenRuppert

Main Idea - DataStructure to Function

Memoizing partial cache-ing ?

@SvenRuppert

full example and code http://www.functional-reactive.org/

prepare for

Refactoring - Clean your code nano refactoring on language level

99

@SvenRuppert

clean your code @SvenRuppert

delete JavaDocuse final for Attributes as much as possible

replace loops with streams

extract Functional Interfacesremove anonymous classes

use everywhere the same language level

Why ?

clean your code @SvenRuppert

delete JavaDocuse final for Attributes as much as possiblereplace loops with streamsextract Functional Interfacesremove anonymous classesuse everywhere the same language level

Why ?

know the part you want to refactor

homogeneous sources are better for machines

prepare for

Refactoring - Summary the full picture

102

@SvenRuppert

Refactoring - Summary

103

@SvenRuppert

prepare your teamchange the way of working

work on your project managementbuild your safety belt - mutation testing

divide and conquer - @Inject build design pattern againextract cross functionality - Proxy's

clean your code

prepare for

Management - Summary the full picture for the C-Level

104

@SvenRuppert

Management - Summary

105

@SvenRuppert

Now it is time to relax again ;-)

Problem solved !

Summary

106

@SvenRuppert

places to read more about it

www.functional-reactive.org

www.java-9.org

or contact me ;-) @SvenRuppert

Thank You !!!

top related