2. softwaretester.blog | Benjamin Bischoff
Law of Two Feet
• If this is not for you, please don’t stay!
• I mean it!
• Really!
3. softwaretester.blog | Benjamin Bischoff
About me
• Benjamin Bischoff
• Test Automation Engineer @ trivago N.V.
• 23 years in IT
• Last 8 years in testing
4. softwaretester.blog | Benjamin Bischoff
I wrote a book
• “Writing API Tests with Karate”
• Available since 05/2023
• Packt Publishing
5. softwaretester.blog | Benjamin Bischoff
I wrote a book
• “Writing API Tests with Karate”
• Available since 05/2023
• Packt Publishing
7. softwaretester.blog | Benjamin Bischoff
Smelly Code
Smelly code, smelly code
How are they treating you?
Smelly code, smelly code
It’s not your fault.
10. softwaretester.blog | Benjamin Bischoff
–Martin Fowler
„A code smell is a surface indication that usually
corresponds to a deeper problem in the system.“
11. softwaretester.blog | Benjamin Bischoff
Why should you care?
• Communication
Speak a common language
• A step towards better code
Clean code principles and design patterns
• Less technical debt
Clean code principles and design patterns
• Testability
Testable code is maintainable code!
12. softwaretester.blog | Benjamin Bischoff
TAXONOMY OF
CODE SMELLS
Mika V. Mäntylä & Casper Lassenius,
Helsinki University of Technology
13. softwaretester.blog | Benjamin Bischoff
TAXONOMY OF
CODE SMELLS
Mika V. Mäntylä & Casper Lassenius,
Helsinki University of Technology
15. softwaretester.blog | Benjamin Bischoff
Classi
fi
cation
Bloaters
Long Method
Large Class
Primitive
Obsession
Long Parameter
List
Data Clumps
OOP
Abusers
Switch Statements
Temporary
Field
Refused
Bequest
Alternative classes
with di
ff
erent
Interfaces
Change
Preventers
Divergent Change
Shotgun Surgery
Parallel Inheritance
Hierarchy
Dispensables
Lazy Class
Data Class
Duplicate Code
Dead Code
Speculative
Generality
Couplers
Feature Envy
Inappropriate
Intimacy
Message Chains
Middleman
17. softwaretester.blog | Benjamin Bischoff
public class WebShop {
private final List<Customer> customers = new ArrayList<>();
public String saveCustomer(final Customer customer) {
customers.add(customer);
return String.format(
"We have a new customer called %",
customer.name());
}
}
Bloaters Long Method
A method that does
too much
18. softwaretester.blog | Benjamin Bischoff
public class WebShop {
private final List<Customer> customers = new ArrayList<>();
public String saveCustomer(final Customer customer) {
customers.add(customer);
return String.format(
"We have a new customer called %",
customer.name());
}
}
Bloaters Long Method
A method that does
too much
19. softwaretester.blog | Benjamin Bischoff
public class WebShop {
private final List<Customer> customers = new ArrayList<>();
public String saveCustomer(final Customer customer) {
customers.add(customer);
return String.format(
"We have a new customer called %",
customer.name());
}
}
Bloaters Long Method
A method that does
too much
20. softwaretester.blog | Benjamin Bischoff
public class WebShop {
private final List<Customer> customers = new ArrayList<>();
public String saveCustomer(final Customer customer) {
customers.add(customer);
return String.format(
"We have a new customer called %",
customer.name());
}
}
Bloaters Long Method
A method that does
too much
21. softwaretester.blog | Benjamin Bischoff
public class WebShop {
private final List<Customer> customers = new ArrayList<>();
public String saveCustomer(final Customer customer) {
customers.add(customer);
return String.format(
"We have a new customer called %",
customer.name());
}
}
Bloaters Long Method
A method that does
too much
22. softwaretester.blog | Benjamin Bischoff
public class ShoppingCart {
public void addProduct(final Product product) {}
public void removeProduct(final Product product) {}
public void checkOut() {}
public void enterVoucherCode() {}
public void contactSupport() {}
}
Bloaters Large Class
A class that does too
much
23. softwaretester.blog | Benjamin Bischoff
public class ShoppingCart {
public void addProduct(final Product product) {}
public void removeProduct(final Product product) {}
public void checkOut() {}
public void enterVoucherCode() {}
public void contactSupport() {}
}
Bloaters Large Class
A class that does too
much
24. softwaretester.blog | Benjamin Bischoff
public class ShoppingCart {
public void addProduct(final Product product) {}
public void removeProduct(final Product product) {}
public void checkOut() {}
public void enterVoucherCode() {}
public void contactSupport() {}
}
Bloaters Large Class
A class that does too
much
25. softwaretester.blog | Benjamin Bischoff
public class ShoppingCart {
public void addProduct(final Product product) {}
public void removeProduct(final Product product) {}
public void checkOut() {}
public void enterVoucherCode() {}
public void contactSupport() {}
}
Bloaters Large Class
A class that does too
much
26. softwaretester.blog | Benjamin Bischoff
public class ShoppingCart {
public void addProduct(final Product product) {}
public void removeProduct(final Product product) {}
public void checkOut() {}
public void enterVoucherCode() {}
public void contactSupport() {}
}
Bloaters Large Class
A class that does too
much
27. softwaretester.blog | Benjamin Bischoff
record Customer(
String name,
int age,
String street,
String city,
int zipCode,
String country
) {
}
Bloaters Primitive Obsession
Favouring primitive
data types
28. softwaretester.blog | Benjamin Bischoff
record Customer(
String name,
int age,
String street,
String city,
int zipCode,
String country
) {
}
Bloaters Primitive Obsession
Favouring primitive
data types
29. softwaretester.blog | Benjamin Bischoff
record Customer(
String name,
int age,
String street,
String city,
int zipCode,
String country
) {
}
Bloaters Primitive Obsession
Favouring primitive
data types
30. softwaretester.blog | Benjamin Bischoff
public class CadTool {
public static void main(String[] args) {
int result =
CadTool.calculateResult(13, false, true, -1, null);
}
public static int calculateResult(final int baseValue,
final boolean isMetric,
final boolean is2D,
final int offset,
final Integer height) {
return 0; // some calculation
}
}
Bloaters Long Parameter List
Too many method
parameters
31. softwaretester.blog | Benjamin Bischoff
public class CadTool {
public static void main(String[] args) {
int result =
CadTool.calculateResult(13, false, true, -1, null);
}
public static int calculateResult(final int baseValue,
final boolean isMetric,
final boolean is2D,
final int offset,
final Integer height) {
return 0; // some calculation
}
}
Bloaters Long Parameter List
Too many method
parameters
32. softwaretester.blog | Benjamin Bischoff
public class CadTool {
public static void main(String[] args) {
int result =
CadTool.calculateResult(13, false, true, -1, null);
}
public static int calculateResult(final int baseValue,
final boolean isMetric,
final boolean is2D,
final int offset,
final Integer height) {
return 0; // some calculation
}
}
Bloaters Long Parameter List
Too many method
parameters
33. softwaretester.blog | Benjamin Bischoff
public class CadTool {
public static void main(String[] args) {
int result =
CadTool.calculateResult(13, false, true, -1, null);
}
public static int calculateResult(final int baseValue,
final boolean isMetric,
final boolean is2D,
final int offset,
final Integer height) {
return 0; // some calculation
}
}
Bloaters Long Parameter List
Too many method
parameters
34. softwaretester.blog | Benjamin Bischoff
public class CadTool {
public static void main(String[] args) {
int result =
CadTool.calculateResult(13, false, true, -1, null);
}
public static int calculateResult(final int baseValue,
final boolean isMetric,
final boolean is2D,
final int offset,
final Integer height) {
return 0; // some calculation
}
}
Bloaters Long Parameter List
Too many method
parameters
35. softwaretester.blog | Benjamin Bischoff
record Customer(
String lastName,
String firstName,
String middleName,
String salutation,
String streetAddress,
String city,
String state,
String country,
boolean isEmployed,
boolean isHomeOwner
) {
}
Bloaters Data Clumps
Grouping unrelated
data
36. softwaretester.blog | Benjamin Bischoff
record Customer(
String lastName,
String firstName,
String middleName,
String salutation,
String streetAddress,
String city,
String state,
String country,
boolean isEmployed,
boolean isHomeOwner
) {
}
Bloaters Data Clumps
Grouping unrelated
data
37. softwaretester.blog | Benjamin Bischoff
record Customer(
String lastName,
String firstName,
String middleName,
String salutation,
String streetAddress,
String city,
String state,
String country,
boolean isEmployed,
boolean isHomeOwner
) {
}
Bloaters Data Clumps
Grouping unrelated
data
38. softwaretester.blog | Benjamin Bischoff
record Customer(
String lastName,
String firstName,
String middleName,
String salutation,
String streetAddress,
String city,
String state,
String country,
boolean isEmployed,
boolean isHomeOwner
) {
}
Bloaters Data Clumps
Grouping unrelated
data
39. softwaretester.blog | Benjamin Bischoff
record Customer(
String lastName,
String firstName,
String middleName,
String salutation,
String streetAddress,
String city,
String state,
String country,
boolean isEmployed,
boolean isHomeOwner
) {
}
Bloaters Data Clumps
Grouping unrelated
data
40. softwaretester.blog | Benjamin Bischoff
record Customer(
String lastName,
String firstName,
String middleName,
String salutation,
String streetAddress,
String city,
String state,
String country,
boolean isEmployed,
boolean isHomeOwner
) {
}
Bloaters Data Clumps
Grouping unrelated
data
41. softwaretester.blog | Benjamin Bischoff
record Customer(
String lastName,
String firstName,
String middleName,
String salutation,
String streetAddress,
String city,
String state,
String country,
boolean isEmployed,
boolean isHomeOwner
) {
}
Bloaters Data Clumps
Grouping unrelated
data
43. softwaretester.blog | Benjamin Bischoff
public class Vehicles {
public int numberOfWheels(final String vehicle)
throws Exception {
return switch (vehicle) {
case "car" -> 4;
case "boat" -> 0;
case "bike" -> 2;
case "bicycle" -> 2;
default -> throw new Exception("Unknown");
};
}
}
OOP Abusers Switch Statements
Branching out too
much
44. softwaretester.blog | Benjamin Bischoff
public class Vehicles {
public int numberOfWheels(final String vehicle)
throws Exception {
return switch (vehicle) {
case "car" -> 4;
case "boat" -> 0;
case "bike" -> 2;
case "bicycle" -> 2;
default -> throw new Exception("Unknown");
};
}
}
OOP Abusers Switch Statements
Branching out too
much
45. softwaretester.blog | Benjamin Bischoff
public class Vehicles {
public int numberOfWheels(final String vehicle)
throws Exception {
return switch (vehicle) {
case "car" -> 4;
case "boat" -> 0;
case "bike" -> 2;
case "bicycle" -> 2;
default -> throw new Exception("Unknown");
};
}
}
OOP Abusers Switch Statements
Branching out too
much
46. softwaretester.blog | Benjamin Bischoff
public class Vehicles {
public int numberOfWheels(final String vehicle)
throws Exception {
return switch (vehicle) {
case "car" -> 4;
case "boat" -> 0;
case "bike" -> 2;
case "bicycle" -> 2;
default -> throw new Exception("Unknown");
};
}
}
OOP Abusers Switch Statements
Branching out too
much
47. softwaretester.blog | Benjamin Bischoff
public class Vehicles {
public int numberOfWheels(final String vehicle)
throws Exception {
return switch (vehicle) {
case "car" -> 4;
case "boat" -> 0;
case "bike" -> 2;
case "bicycle" -> 2;
default -> throw new Exception("Unknown");
};
}
}
OOP Abusers Switch Statements
Branching out too
much
48. softwaretester.blog | Benjamin Bischoff
public class Rectangle {
private float sideA;
private float sideB;
public void setSideA(float sideA) {
this.sideA = sideA;
}
public void setSideB(float sideB) {
this.sideB = sideB;
}
public double getAreaSize() {
return sideA * sideB;
}
}
OOP Abusers Temporary Field
Fields that are only
used once
49. softwaretester.blog | Benjamin Bischoff
public class Rectangle {
private float sideA;
private float sideB;
public void setSideA(float sideA) {
this.sideA = sideA;
}
public void setSideB(float sideB) {
this.sideB = sideB;
}
public double getAreaSize() {
return sideA * sideB;
}
}
OOP Abusers Temporary Field
Fields that are only
used once
50. softwaretester.blog | Benjamin Bischoff
public class Rectangle {
private float sideA;
private float sideB;
public void setSideA(float sideA) {
this.sideA = sideA;
}
public void setSideB(float sideB) {
this.sideB = sideB;
}
public double getAreaSize() {
return sideA * sideB;
}
}
OOP Abusers Temporary Field
Fields that are only
used once
51. softwaretester.blog | Benjamin Bischoff
public class Rectangle {
private float sideA;
private float sideB;
public void setSideA(float sideA) {
this.sideA = sideA;
}
public void setSideB(float sideB) {
this.sideB = sideB;
}
public double getAreaSize() {
return sideA * sideB;
}
}
OOP Abusers Temporary Field
Fields that are only
used once
52. softwaretester.blog | Benjamin Bischoff
public class Rectangle {
private float sideA;
private float sideB;
public void setSideA(float sideA) {
this.sideA = sideA;
}
public void setSideB(float sideB) {
this.sideB = sideB;
}
public double getAreaSize() {
return sideA * sideB;
}
}
OOP Abusers Temporary Field
Fields that are only
used once
53. softwaretester.blog | Benjamin Bischoff
public class Rectangle {
private float sideA;
private float sideB;
public void setSideA(float sideA) {
this.sideA = sideA;
}
public void setSideB(float sideB) {
this.sideB = sideB;
}
public double getAreaSize() {
return sideA * sideB;
}
}
OOP Abusers Temporary Field
Fields that are only
used once
54. softwaretester.blog | Benjamin Bischoff
public class Rectangle {
private float sideA;
private float sideB;
public void setSideA(float sideA) {
this.sideA = sideA;
}
public void setSideB(float sideB) {
this.sideB = sideB;
}
public double getAreaSize() {
return sideA * sideB;
}
}
OOP Abusers Temporary Field
Fields that are only
used once
55. softwaretester.blog | Benjamin Bischoff
public class Animals {
interface Animal { void speak(); }
static class Dog implements Animal {
@Override
public void speak() {
System.out.println("Woof");
}
}
static class Fish implements Animal {
@Override
public void speak() {
}
}
}
OOP Abusers Refused Bequest
Passing unneeded
behaviour to classes
56. softwaretester.blog | Benjamin Bischoff
public class Animals {
interface Animal { void speak(); }
static class Dog implements Animal {
@Override
public void speak() {
System.out.println("Woof");
}
}
static class Fish implements Animal {
@Override
public void speak() {
}
}
}
OOP Abusers Refused Bequest
Passing unneeded
behaviour to classes
57. softwaretester.blog | Benjamin Bischoff
public class Animals {
interface Animal { void speak(); }
static class Dog implements Animal {
@Override
public void speak() {
System.out.println("Woof");
}
}
static class Fish implements Animal {
@Override
public void speak() {
}
}
}
OOP Abusers Refused Bequest
Passing unneeded
behaviour to classes
58. softwaretester.blog | Benjamin Bischoff
public class Animals {
interface Animal { void speak(); }
static class Dog implements Animal {
@Override
public void speak() {
System.out.println("Woof");
}
}
static class Fish implements Animal {
@Override
public void speak() {
}
}
}
OOP Abusers Refused Bequest
Passing unneeded
behaviour to classes
59. softwaretester.blog | Benjamin Bischoff
public class Animals {
interface Animal { void speak(); }
static class Dog implements Animal {
@Override
public void speak() {
System.out.println("Woof");
}
}
static class Fish implements Animal {
@Override
public void speak() {
}
}
}
OOP Abusers Refused Bequest
Passing unneeded
behaviour to classes
60. softwaretester.blog | Benjamin Bischoff
public class Animals {
interface Animal { void speak(); }
static class Dog implements Animal {
@Override
public void speak() {
System.out.println("Woof");
}
}
static class Fish implements Animal {
@Override
public void speak() {
}
}
}
OOP Abusers Refused Bequest
Passing unneeded
behaviour to classes
61. softwaretester.blog | Benjamin Bischoff
public class Animals {
interface Animal { void speak(); }
static class Dog implements Animal {
@Override
public void speak() {
System.out.println("Woof");
}
}
static class Fish implements Animal {
@Override
public void speak() {
}
}
}
OOP Abusers Refused Bequest
Passing unneeded
behaviour to classes
62. softwaretester.blog | Benjamin Bischoff
public class Shapes {
record Circle(float radius) {
public double getAreaSize() {
return radius * radius * Math.PI;
}
}
record Rectangle(float a, float b) {
public double getSurfaceSize() {
return a * b;
}
}
}
OOP Abusers Different Interfaces
Confusing naming of
similar functions
63. softwaretester.blog | Benjamin Bischoff
public class Shapes {
record Circle(float radius) {
public double getAreaSize() {
return radius * radius * Math.PI;
}
}
record Rectangle(float a, float b) {
public double getSurfaceSize() {
return a * b;
}
}
}
OOP Abusers Different Interfaces
Confusing naming of
similar functions
64. softwaretester.blog | Benjamin Bischoff
public class Shapes {
record Circle(float radius) {
public double getAreaSize() {
return radius * radius * Math.PI;
}
}
record Rectangle(float a, float b) {
public double getSurfaceSize() {
return a * b;
}
}
}
OOP Abusers Different Interfaces
Confusing naming of
similar functions
65. softwaretester.blog | Benjamin Bischoff
public class Shapes {
record Circle(float radius) {
public double getAreaSize() {
return radius * radius * Math.PI;
}
}
record Rectangle(float a, float b) {
public double getSurfaceSize() {
return a * b;
}
}
}
OOP Abusers Different Interfaces
Confusing naming of
similar functions
66. softwaretester.blog | Benjamin Bischoff
public class Shapes {
record Circle(float radius) {
public double getAreaSize() {
return radius * radius * Math.PI;
}
}
record Rectangle(float a, float b) {
public double getSurfaceSize() {
return a * b;
}
}
}
OOP Abusers Different Interfaces
Confusing naming of
similar functions
68. softwaretester.blog | Benjamin Bischoff
public class AnimalInformation {
public static String getLatinName(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return "Equus caballus";
return "";
}
public static int getNumberOfLegs(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return 4;
return -1;
}
}
Change Preventers Divergent Change
Changes across
methods
69. softwaretester.blog | Benjamin Bischoff
public class AnimalInformation {
public static String getLatinName(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return "Equus caballus";
return "";
}
public static int getNumberOfLegs(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return 4;
return -1;
}
}
Change Preventers Divergent Change
Changes across
methods
70. softwaretester.blog | Benjamin Bischoff
public class AnimalInformation {
public static String getLatinName(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return "Equus caballus";
return "";
}
public static int getNumberOfLegs(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return 4;
return -1;
}
}
Change Preventers Divergent Change
Changes across
methods
71. softwaretester.blog | Benjamin Bischoff
public class AnimalInformation {
public static String getLatinName(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return "Equus caballus";
return "";
}
public static int getNumberOfLegs(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return 4;
return -1;
}
}
Change Preventers Divergent Change
Changes across
methods
72. softwaretester.blog | Benjamin Bischoff
public class AnimalInformation {
public static String getLatinName(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return "Equus caballus";
return "";
}
public static int getNumberOfLegs(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return 4;
return -1;
}
}
Change Preventers Divergent Change
Changes across
methods
73. softwaretester.blog | Benjamin Bischoff
public class Classification {
public static String getLatinName(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return "Equus caballus";
return "";
}
}
public class BodyParts {
public static int getNumberOfLegs(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return 4;
return -1;
}
}
Change Preventers Shotgun Surgery
Changes across
classes
74. softwaretester.blog | Benjamin Bischoff
public class Classification {
public static String getLatinName(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return "Equus caballus";
return "";
}
}
public class BodyParts {
public static int getNumberOfLegs(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return 4;
return -1;
}
}
Change Preventers Shotgun Surgery
Changes across
classes
75. softwaretester.blog | Benjamin Bischoff
public class Classification {
public static String getLatinName(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return "Equus caballus";
return "";
}
}
public class BodyParts {
public static int getNumberOfLegs(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return 4;
return -1;
}
}
Change Preventers Shotgun Surgery
Changes across
classes
76. softwaretester.blog | Benjamin Bischoff
public class Classification {
public static String getLatinName(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return "Equus caballus";
return "";
}
}
public class BodyParts {
public static int getNumberOfLegs(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return 4;
return -1;
}
}
Change Preventers Shotgun Surgery
Changes across
classes
77. softwaretester.blog | Benjamin Bischoff
public class Classification {
public static String getLatinName(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return "Equus caballus";
return "";
}
}
public class BodyParts {
public static int getNumberOfLegs(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return 4;
return -1;
}
}
Change Preventers Shotgun Surgery
Changes across
classes
78. softwaretester.blog | Benjamin Bischoff
public class Classification {
public static String getLatinName(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return "Equus caballus";
return "";
}
}
public class BodyParts {
public static int getNumberOfLegs(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return 4;
return -1;
}
}
Change Preventers Shotgun Surgery
Changes across
classes
79. softwaretester.blog | Benjamin Bischoff
public class Classification {
public static String getLatinName(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return "Equus caballus";
return "";
}
}
public class BodyParts {
public static int getNumberOfLegs(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return 4;
return -1;
}
}
Change Preventers Shotgun Surgery
Changes across
classes
80. softwaretester.blog | Benjamin Bischoff
public class Classification {
public static String getLatinName(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return "Equus caballus";
return "";
}
}
public class BodyParts {
public static int getNumberOfLegs(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return 4;
return -1;
}
}
Change Preventers Shotgun Surgery
Changes across
classes
81. softwaretester.blog | Benjamin Bischoff
public class Classification {
public static String getLatinName(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return "Equus caballus";
return "";
}
}
public class BodyParts {
public static int getNumberOfLegs(final String animal) {
if (animal.equalsIgnoreCase("horse"))
return 4;
return -1;
}
}
Change Preventers Shotgun Surgery
Changes across
classes
82. softwaretester.blog | Benjamin Bischoff
public class Birds {
private static class Bird {}
private static class Egg {}
private static class Sparrow extends Bird {
private SparrowEgg layEgg() {
return new SparrowEgg();
}
}
private static class SparrowEgg extends Egg {
}
}
Change Preventers Parallel Hierarchy
Implementing
parallel interfaces
83. softwaretester.blog | Benjamin Bischoff
public class Birds {
private static class Bird {}
private static class Egg {}
private static class Sparrow extends Bird {
private SparrowEgg layEgg() {
return new SparrowEgg();
}
}
private static class SparrowEgg extends Egg {
}
}
Change Preventers Parallel Hierarchy
Implementing
parallel interfaces
84. softwaretester.blog | Benjamin Bischoff
public class Birds {
private static class Bird {}
private static class Egg {}
private static class Sparrow extends Bird {
private SparrowEgg layEgg() {
return new SparrowEgg();
}
}
private static class SparrowEgg extends Egg {
}
}
Change Preventers Parallel Hierarchy
Implementing
parallel interfaces
85. softwaretester.blog | Benjamin Bischoff
public class Birds {
private static class Bird {}
private static class Egg {}
private static class Sparrow extends Bird {
private SparrowEgg layEgg() {
return new SparrowEgg();
}
}
private static class SparrowEgg extends Egg {
}
}
Change Preventers Parallel Hierarchy
Implementing
parallel interfaces
86. softwaretester.blog | Benjamin Bischoff
public class Birds {
private static class Bird {}
private static class Egg {}
private static class Sparrow extends Bird {
private SparrowEgg layEgg() {
return new SparrowEgg();
}
}
private static class SparrowEgg extends Egg {
}
}
Change Preventers Parallel Hierarchy
Implementing
parallel interfaces
87. softwaretester.blog | Benjamin Bischoff
public class Birds {
private static class Bird {}
private static class Egg {}
private static class Sparrow extends Bird {
private SparrowEgg layEgg() {
return new SparrowEgg();
}
}
private static class SparrowEgg extends Egg {
}
}
Change Preventers Parallel Hierarchy
Implementing
parallel interfaces
88. softwaretester.blog | Benjamin Bischoff
public class Birds {
private static class Bird {}
private static class Egg {}
private static class Sparrow extends Bird {
private SparrowEgg layEgg() {
return new SparrowEgg();
}
}
private static class SparrowEgg extends Egg {
}
}
Change Preventers Parallel Hierarchy
Implementing
parallel interfaces
89. softwaretester.blog | Benjamin Bischoff
public class Birds {
private static class Bird {}
private static class Egg {}
private static class Sparrow extends Bird {
private SparrowEgg layEgg() {
return new SparrowEgg();
}
}
private static class SparrowEgg extends Egg {
}
}
Change Preventers Parallel Hierarchy
Implementing
parallel interfaces
90. softwaretester.blog | Benjamin Bischoff
public class Birds {
private static class Bird {}
private static class Egg {}
private static class Sparrow extends Bird {
private SparrowEgg layEgg() {
return new SparrowEgg();
}
}
private static class SparrowEgg extends Egg {
}
}
Change Preventers Parallel Hierarchy
Implementing
parallel interfaces
91. softwaretester.blog | Benjamin Bischoff
public class Birds {
private static class Bird {}
private static class Egg {}
private static class Sparrow extends Bird {
private SparrowEgg layEgg() {
return new SparrowEgg();
}
}
private static class SparrowEgg extends Egg {
}
}
Change Preventers Parallel Hierarchy
Implementing
parallel interfaces
92. softwaretester.blog | Benjamin Bischoff
public class Birds {
private static class Bird {}
private static class Egg {}
private static class Sparrow extends Bird {
private SparrowEgg layEgg() {
return new SparrowEgg();
}
}
private static class SparrowEgg extends Egg {
}
}
Change Preventers Parallel Hierarchy
Implementing
parallel interfaces
94. softwaretester.blog | Benjamin Bischoff
public class WebShopCheckOut {
public static void checkOut(final ShoppingCart cart) {
// Some implementation
}
}
record ShoppingCart(Product... products) {
}
record Product(String id) {
}
Dispensables Lazy Class
A class with a single
method
95. softwaretester.blog | Benjamin Bischoff
public class WebShopCheckOut {
public static void checkOut(final ShoppingCart cart) {
// Some implementation
}
}
record ShoppingCart(Product... products) {
}
record Product(String id) {
}
Dispensables Lazy Class
A class with a single
method
96. softwaretester.blog | Benjamin Bischoff
public class WebShopCheckOut {
public static void checkOut(final ShoppingCart cart) {
// Some implementation
}
}
record ShoppingCart(Product... products) {
}
record Product(String id) {
}
Dispensables Lazy Class
A class with a single
method
97. softwaretester.blog | Benjamin Bischoff
public class WebShopCheckOut {
public static void checkOut(final ShoppingCart cart) {
// Some implementation
}
}
record ShoppingCart(Product... products) {
}
record Product(String id) {
}
Dispensables Lazy Class
A class with a single
method
98. softwaretester.blog | Benjamin Bischoff
public class WebShopCheckOut {
public static void checkOut(final ShoppingCart cart) {
// Some implementation
}
}
record ShoppingCart(Product... products) {
}
record Product(String id) {
}
Dispensables Lazy Class
A class with a single
method
99. softwaretester.blog | Benjamin Bischoff
public class DataClass {
record Rectangle(int sideA, int sideB) {
}
public static void main(String[] args) {
Rectangle rectangle = new Rectangle(5, 20);
int rectangleArea = rectangle.sideA * rectangle.sideB;
}
}
Dispensables Data Class
Class holding data
but not its own logic
100. softwaretester.blog | Benjamin Bischoff
public class DataClass {
record Rectangle(int sideA, int sideB) {
}
public static void main(String[] args) {
Rectangle rectangle = new Rectangle(5, 20);
int rectangleArea = rectangle.sideA * rectangle.sideB;
}
}
Dispensables Data Class
Class holding data
but not its own logic
101. softwaretester.blog | Benjamin Bischoff
public class DataClass {
record Rectangle(int sideA, int sideB) {
}
public static void main(String[] args) {
Rectangle rectangle = new Rectangle(5, 20);
int rectangleArea = rectangle.sideA * rectangle.sideB;
}
}
Dispensables Data Class
Class holding data
but not its own logic
102. softwaretester.blog | Benjamin Bischoff
public class DataClass {
record Rectangle(int sideA, int sideB) {
}
public static void main(String[] args) {
Rectangle rectangle = new Rectangle(5, 20);
int rectangleArea = rectangle.sideA * rectangle.sideB;
}
}
Dispensables Data Class
Class holding data
but not its own logic
103. softwaretester.blog | Benjamin Bischoff
public class DataClass {
record Rectangle(int sideA, int sideB) {
}
public static void main(String[] args) {
Rectangle rectangle = new Rectangle(5, 20);
int rectangleArea = rectangle.sideA * rectangle.sideB;
}
}
Dispensables Data Class
Class holding data
but not its own logic
104. softwaretester.blog | Benjamin Bischoff
public class DataClass {
record Rectangle(int sideA, int sideB) {
}
public static void main(String[] args) {
Rectangle rectangle = new Rectangle(5, 20);
int rectangleArea = rectangle.sideA * rectangle.sideB;
}
}
Dispensables Data Class
Class holding data
but not its own logic
105. softwaretester.blog | Benjamin Bischoff
public class DataClass {
record Rectangle(int sideA, int sideB) {
}
public static void main(String[] args) {
Rectangle rectangle = new Rectangle(5, 20);
int rectangleArea = rectangle.sideA * rectangle.sideB;
}
}
Dispensables Data Class
Class holding data
but not its own logic
106. softwaretester.blog | Benjamin Bischoff
public class Customers {
private List<Customer> customers;
public void addCustomer(Customer customer) {
customers.add(customer);
customers.forEach(System.out::println);
}
public void removeCustomer(Customer customer) {
customers.remove(customer);
customers.forEach(System.out::println);
}
}
Dispensables Duplicate Code
The same code
multiple times
107. softwaretester.blog | Benjamin Bischoff
public class Customers {
private List<Customer> customers;
public void addCustomer(Customer customer) {
customers.add(customer);
customers.forEach(System.out::println);
}
public void removeCustomer(Customer customer) {
customers.remove(customer);
customers.forEach(System.out::println);
}
}
Dispensables Duplicate Code
The same code
multiple times
108. softwaretester.blog | Benjamin Bischoff
public class Customers {
private List<Customer> customers;
public void addCustomer(Customer customer) {
customers.add(customer);
customers.forEach(System.out::println);
}
public void removeCustomer(Customer customer) {
customers.remove(customer);
customers.forEach(System.out::println);
}
}
Dispensables Duplicate Code
The same code
multiple times
109. softwaretester.blog | Benjamin Bischoff
public class Customers {
private List<Customer> customers;
public void addCustomer(Customer customer) {
customers.add(customer);
customers.forEach(System.out::println);
}
public void removeCustomer(Customer customer) {
customers.remove(customer);
customers.forEach(System.out::println);
}
}
Dispensables Duplicate Code
The same code
multiple times
110. softwaretester.blog | Benjamin Bischoff
public class Customers {
private List<Customer> customers;
public void addCustomer(Customer customer) {
customers.add(customer);
customers.forEach(System.out::println);
}
public void removeCustomer(Customer customer) {
customers.remove(customer);
customers.forEach(System.out::println);
}
}
Dispensables Duplicate Code
The same code
multiple times
111. softwaretester.blog | Benjamin Bischoff
public class DeadCode {
public static void main(String[] args) {
System.out.println("Pi = " + Math.PI);
}
private double getPi() {
return 3.141592;
System.out.println("Returning Pi");
}
}
Dispensables Dead Code
Code that cannot be
reached
112. softwaretester.blog | Benjamin Bischoff
public class DeadCode {
public static void main(String[] args) {
System.out.println("Pi = " + Math.PI);
}
private double getPi() {
return 3.141592;
System.out.println("Returning Pi");
}
}
Dispensables Dead Code
Code that cannot be
reached
113. softwaretester.blog | Benjamin Bischoff
public class DeadCode {
public static void main(String[] args) {
System.out.println("Pi = " + Math.PI);
}
private double getPi() {
return 3.141592;
System.out.println("Returning Pi");
}
}
Dispensables Dead Code
Code that cannot be
reached
114. softwaretester.blog | Benjamin Bischoff
public class DeadCode {
public static void main(String[] args) {
System.out.println("Pi = " + Math.PI);
}
private double getPi() {
return 3.141592;
System.out.println("Returning Pi");
}
}
Dispensables Dead Code
Code that cannot be
reached
115. softwaretester.blog | Benjamin Bischoff
public class DeadCode {
public static void main(String[] args) {
System.out.println("Pi = " + Math.PI);
}
private double getPi() {
return 3.141592;
System.out.println("Returning Pi");
}
}
Dispensables Dead Code
Code that cannot be
reached
116. softwaretester.blog | Benjamin Bischoff
public class DeadCode {
public static void main(String[] args) {
System.out.println("Pi = " + Math.PI);
}
private double getPi() {
return 3.141592;
System.out.println("Returning Pi");
}
}
Dispensables Dead Code
Code that cannot be
reached
117. softwaretester.blog | Benjamin Bischoff
public class DeadCode {
public static void main(String[] args) {
System.out.println("Pi = " + Math.PI);
}
private double getPi() {
return 3.141592;
System.out.println("Returning Pi");
}
}
Dispensables Dead Code
Code that cannot be
reached
118. softwaretester.blog | Benjamin Bischoff
public class LaserPrinter implements Printer {
@Override
public void print(final String textToPrint) {
// Implementation
}
@Override
public void turnOnOrOff() {
//Implementation
}
}
interface Printer {
void print(String textToPrint);
void turnOnOrOff();
}
Dispensables Speculative Generality
Premature future-
proo
fi
ng
119. softwaretester.blog | Benjamin Bischoff
public class LaserPrinter implements Printer {
@Override
public void print(final String textToPrint) {
// Implementation
}
@Override
public void turnOnOrOff() {
//Implementation
}
}
interface Printer {
void print(String textToPrint);
void turnOnOrOff();
}
Dispensables Speculative Generality
Premature future-
proo
fi
ng
120. softwaretester.blog | Benjamin Bischoff
public class LaserPrinter implements Printer {
@Override
public void print(final String textToPrint) {
// Implementation
}
@Override
public void turnOnOrOff() {
//Implementation
}
}
interface Printer {
void print(String textToPrint);
void turnOnOrOff();
}
Dispensables Speculative Generality
Premature future-
proo
fi
ng
121. softwaretester.blog | Benjamin Bischoff
public class LaserPrinter implements Printer {
@Override
public void print(final String textToPrint) {
// Implementation
}
@Override
public void turnOnOrOff() {
//Implementation
}
}
interface Printer {
void print(String textToPrint);
void turnOnOrOff();
}
Dispensables Speculative Generality
Premature future-
proo
fi
ng
122. softwaretester.blog | Benjamin Bischoff
public class LaserPrinter implements Printer {
@Override
public void print(final String textToPrint) {
// Implementation
}
@Override
public void turnOnOrOff() {
//Implementation
}
}
interface Printer {
void print(String textToPrint);
void turnOnOrOff();
}
Dispensables Speculative Generality
Premature future-
proo
fi
ng
123. softwaretester.blog | Benjamin Bischoff
public class LaserPrinter implements Printer {
@Override
public void print(final String textToPrint) {
// Implementation
}
@Override
public void turnOnOrOff() {
//Implementation
}
}
interface Printer {
void print(String textToPrint);
void turnOnOrOff();
}
Dispensables Speculative Generality
Premature future-
proo
fi
ng
124. softwaretester.blog | Benjamin Bischoff
public class LaserPrinter implements Printer {
@Override
public void print(final String textToPrint) {
// Implementation
}
@Override
public void turnOnOrOff() {
//Implementation
}
}
interface Printer {
void print(String textToPrint);
void turnOnOrOff();
}
Dispensables Speculative Generality
Premature future-
proo
fi
ng
126. softwaretester.blog | Benjamin Bischoff
public class UsersAndAddresses {
record User(Address address) {
public String getAddressString() {
return
address.street() + ", "
+ address.city() + ", "
+ address.country();
}
}
record Address(String street, String city, String country) { }
}
Couplers Feature Envy
Class implementing
features of another
127. softwaretester.blog | Benjamin Bischoff
public class UsersAndAddresses {
record User(Address address) {
public String getAddressString() {
return
address.street() + ", "
+ address.city() + ", "
+ address.country();
}
}
record Address(String street, String city, String country) { }
}
Couplers Feature Envy
Class implementing
features of another
128. softwaretester.blog | Benjamin Bischoff
public class UsersAndAddresses {
record User(Address address) {
public String getAddressString() {
return
address.street() + ", "
+ address.city() + ", "
+ address.country();
}
}
record Address(String street, String city, String country) { }
}
Couplers Feature Envy
Class implementing
features of another
129. softwaretester.blog | Benjamin Bischoff
public class UsersAndAddresses {
record User(Address address) {
public String getAddressString() {
return
address.street() + ", "
+ address.city() + ", "
+ address.country();
}
}
record Address(String street, String city, String country) { }
}
Couplers Feature Envy
Class implementing
features of another
130. softwaretester.blog | Benjamin Bischoff
public class UsersAndAddresses {
record User(Address address) {
public String getAddressString() {
return
address.street() + ", "
+ address.city() + ", "
+ address.country();
}
}
record Address(String street, String city, String country) { }
}
Couplers Feature Envy
Class implementing
features of another
131. softwaretester.blog | Benjamin Bischoff
public class Book {
private final String title;
private Author author;
public Book(String title) { this.title = title;}
public void setAuthor(Author author) { this.author = author; }
}
public class Author {
private final String name;
private Book book;
public Author(String name) { this.name = name; }
public void setBook(Book book) { this.book = book; }
}
Couplers Inappropriate Intimacy
Classes knowing
each other too well
132. softwaretester.blog | Benjamin Bischoff
public class Book {
private final String title;
private Author author;
public Book(String title) { this.title = title;}
public void setAuthor(Author author) { this.author = author; }
}
public class Author {
private final String name;
private Book book;
public Author(String name) { this.name = name; }
public void setBook(Book book) { this.book = book; }
}
Couplers Inappropriate Intimacy
Classes knowing
each other too well
133. softwaretester.blog | Benjamin Bischoff
public class Book {
private final String title;
private Author author;
public Book(String title) { this.title = title;}
public void setAuthor(Author author) { this.author = author; }
}
public class Author {
private final String name;
private Book book;
public Author(String name) { this.name = name; }
public void setBook(Book book) { this.book = book; }
}
Couplers Inappropriate Intimacy
Classes knowing
each other too well
134. softwaretester.blog | Benjamin Bischoff
public class Book {
private final String title;
private Author author;
public Book(String title) { this.title = title;}
public void setAuthor(Author author) { this.author = author; }
}
public class Author {
private final String name;
private Book book;
public Author(String name) { this.name = name; }
public void setBook(Book book) { this.book = book; }
}
Couplers Inappropriate Intimacy
Classes knowing
each other too well
135. softwaretester.blog | Benjamin Bischoff
public class Book {
private final String title;
private Author author;
public Book(String title) { this.title = title;}
public void setAuthor(Author author) { this.author = author; }
}
public class Author {
private final String name;
private Book book;
public Author(String name) { this.name = name; }
public void setBook(Book book) { this.book = book; }
}
Couplers Inappropriate Intimacy
Classes knowing
each other too well
136. softwaretester.blog | Benjamin Bischoff
public class Book {
private final String title;
private Author author;
public Book(String title) { this.title = title;}
public void setAuthor(Author author) { this.author = author; }
}
public class Author {
private final String name;
private Book book;
public Author(String name) { this.name = name; }
public void setBook(Book book) { this.book = book; }
}
Couplers Inappropriate Intimacy
Classes knowing
each other too well
137. softwaretester.blog | Benjamin Bischoff
public class Book {
private final String title;
private Author author;
public Book(String title) { this.title = title;}
public void setAuthor(Author author) { this.author = author; }
}
public class Author {
private final String name;
private Book book;
public Author(String name) { this.name = name; }
public void setBook(Book book) { this.book = book; }
}
Couplers Inappropriate Intimacy
Classes knowing
each other too well
138. softwaretester.blog | Benjamin Bischoff
public class Book {
private final String title;
private Author author;
public Book(String title) { this.title = title;}
public void setAuthor(Author author) { this.author = author; }
}
public class Author {
private final String name;
private Book book;
public Author(String name) { this.name = name; }
public void setBook(Book book) { this.book = book; }
}
Couplers Inappropriate Intimacy
Classes knowing
each other too well
139. softwaretester.blog | Benjamin Bischoff
public class Book {
private final String title;
private Author author;
public Book(String title) { this.title = title;}
public void setAuthor(Author author) { this.author = author; }
}
public class Author {
private final String name;
private Book book;
public Author(String name) { this.name = name; }
public void setBook(Book book) { this.book = book; }
}
Couplers Inappropriate Intimacy
Classes knowing
each other too well
140. softwaretester.blog | Benjamin Bischoff
public class Storehouse {
public static void main(String[] args) {
List<Product> products = List.of(
new Product("Cheese", "Tasty cheese"));
List<Shelf> shelves = List.of(new Shelf(products));
String description =
shelves.get(0).products().get(0).description();
}
record Shelf(List<Product> products) { }
record Product(String name, String description) { }
}
Couplers Message Chains
Returning objects
that return objects…
141. softwaretester.blog | Benjamin Bischoff
public class Storehouse {
public static void main(String[] args) {
List<Product> products = List.of(
new Product("Cheese", "Tasty cheese"));
List<Shelf> shelves = List.of(new Shelf(products));
String description =
shelves.get(0).products().get(0).description();
}
record Shelf(List<Product> products) { }
record Product(String name, String description) { }
}
Couplers Message Chains
Returning objects
that return objects…
142. softwaretester.blog | Benjamin Bischoff
public class Storehouse {
public static void main(String[] args) {
List<Product> products = List.of(
new Product("Cheese", "Tasty cheese"));
List<Shelf> shelves = List.of(new Shelf(products));
String description =
shelves.get(0).products().get(0).description();
}
record Shelf(List<Product> products) { }
record Product(String name, String description) { }
}
Couplers Message Chains
Returning objects
that return objects…
143. softwaretester.blog | Benjamin Bischoff
public record Customer(String name, Address address) {
public String getCity() {
return address.city();
}
public String getStreet() {
return address.street();
}
record Address(String street, String city) { }
}
Dispensables Middle Man
Class accessing
another one on its
behalf
144. softwaretester.blog | Benjamin Bischoff
public record Customer(String name, Address address) {
public String getCity() {
return address.city();
}
public String getStreet() {
return address.street();
}
record Address(String street, String city) { }
}
Dispensables Middle Man
Class accessing
another one on its
behalf
145. softwaretester.blog | Benjamin Bischoff
public record Customer(String name, Address address) {
public String getCity() {
return address.city();
}
public String getStreet() {
return address.street();
}
record Address(String street, String city) { }
}
Dispensables Middle Man
Class accessing
another one on its
behalf
146. softwaretester.blog | Benjamin Bischoff
public record Customer(String name, Address address) {
public String getCity() {
return address.city();
}
public String getStreet() {
return address.street();
}
record Address(String street, String city) { }
}
Dispensables Middle Man
Class accessing
another one on its
behalf
147. softwaretester.blog | Benjamin Bischoff
public record Customer(String name, Address address) {
public String getCity() {
return address.city();
}
public String getStreet() {
return address.street();
}
record Address(String street, String city) { }
}
Dispensables Middle Man
Class accessing
another one on its
behalf
148. softwaretester.blog | Benjamin Bischoff
Classi
fi
cation
Bloaters
OOP
Abusers
Change
Preventers
Dispensables Couplers
Long Method
Large Class
Primitive
Obsession
Long Parameter
List
Data Clumps
Switch Statements
Temporary
Field
Refused
Bequest
Alternative classes
with di
ff
erent
Interfaces
Divergent Change
Shotgun Surgery
Parallel Inheritance
Hierarchy
Lazy Class
Data Class
Duplicate Code
Dead Code
Speculative
Generality
Feature Envy
Inappropriate
Intimacy
Message Chains
Middleman
159. softwaretester.blog | Benjamin Bischoff
Smelly Code
Smelly code, smelly code
How are they treating you?
Smelly code, smelly code
It’s not your fault.