from mess to masterpiece - jfokus 2017
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 !!!