softwaretester.blog | Benjamin Bischoff
TestCon Europe 2023
Identifying Code Smells
softwaretester.blog | Benjamin Bischoff
Law of Two Feet
• If this is not for you, please don’t stay!
• I mean it!
• Really!
softwaretester.blog | Benjamin Bischoff
About me
• Benjamin Bischoff
• Test Automation Engineer @ trivago N.V.
• 23 years in IT
• Last 8 years in testing
softwaretester.blog | Benjamin Bischoff
I wrote a book
• “Writing API Tests with Karate”
• Available since 05/2023
• Packt Publishing
softwaretester.blog | Benjamin Bischoff
I wrote a book
• “Writing API Tests with Karate”
• Available since 05/2023
• Packt Publishing
softwaretester.blog | Benjamin Bischoff
Disclaimer
• This is only about identi
fi
cation
• Lots of code
• All Java
softwaretester.blog | Benjamin Bischoff
Smelly Code
Smelly code, smelly code
How are they treating you?
Smelly code, smelly code
It’s not your fault.
softwaretester.blog | Benjamin Bischoff
The term
softwaretester.blog | Benjamin Bischoff
The term
softwaretester.blog | Benjamin Bischoff
–Martin Fowler
„A code smell is a surface indication that usually
corresponds to a deeper problem in the system.“
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!
softwaretester.blog | Benjamin Bischoff
TAXONOMY OF
CODE SMELLS
Mika V. Mäntylä & Casper Lassenius,
Helsinki University of Technology
softwaretester.blog | Benjamin Bischoff
TAXONOMY OF
CODE SMELLS
Mika V. Mäntylä & Casper Lassenius,
Helsinki University of Technology
softwaretester.blog | Benjamin Bischoff
Classi
fi
cation
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
softwaretester.blog | Benjamin Bischoff
Bloaters
Too large to handle.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
softwaretester.blog | Benjamin Bischoff
OOP Abusers
Missing object-oriented design possibilities.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
softwaretester.blog | Benjamin Bischoff
Change Preventers
Hindering further development.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
softwaretester.blog | Benjamin Bischoff
Dispensables
Unnecessary things that can be removed.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
softwaretester.blog | Benjamin Bischoff
Couplers
Too much or too little coupling.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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…
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…
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…
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
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
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
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
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
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
softwaretester.blog | Benjamin Bischoff
Example Code
github.com/bischoffdev/code-smells
softwaretester.blog | Benjamin Bischoff
When to tackle code smells?
softwaretester.blog | Benjamin Bischoff
Broken window
Long-term effects of un
fi
xed
code.
softwaretester.blog | Benjamin Bischoff
YAGNI
Wasting time with future
requirements.
softwaretester.blog | Benjamin Bischoff
Campground Rule
Later never comes…
softwaretester.blog | Benjamin Bischoff
Code Reviews
Point out smells before it is too
late!
softwaretester.blog | Benjamin Bischoff
More information
softwaretester.blog | Benjamin Bischoff
Refactoring catalog
refactoring.com/catalog
softwaretester.blog | Benjamin Bischoff
Refactoring Guru
refactoring.guru/refactoring
softwaretester.blog | Benjamin Bischoff
Marcel Jerzyk
luzkan.github.io/smells/
softwaretester.blog | Benjamin Bischoff
Smelly Code
Smelly code, smelly code
How are they treating you?
Smelly code, smelly code
It’s not your fault.
softwaretester.blog | Benjamin Bischoff
Thank you!
softwaretester.blog | Benjamin Bischoff
Thank you!

Identifying Code Smells

  • 1.
    softwaretester.blog | BenjaminBischoff TestCon Europe 2023 Identifying Code Smells
  • 2.
    softwaretester.blog | BenjaminBischoff Law of Two Feet • If this is not for you, please don’t stay! • I mean it! • Really!
  • 3.
    softwaretester.blog | BenjaminBischoff About me • Benjamin Bischoff • Test Automation Engineer @ trivago N.V. • 23 years in IT • Last 8 years in testing
  • 4.
    softwaretester.blog | BenjaminBischoff I wrote a book • “Writing API Tests with Karate” • Available since 05/2023 • Packt Publishing
  • 5.
    softwaretester.blog | BenjaminBischoff I wrote a book • “Writing API Tests with Karate” • Available since 05/2023 • Packt Publishing
  • 6.
    softwaretester.blog | BenjaminBischoff Disclaimer • This is only about identi fi cation • Lots of code • All Java
  • 7.
    softwaretester.blog | BenjaminBischoff Smelly Code Smelly code, smelly code How are they treating you? Smelly code, smelly code It’s not your fault.
  • 8.
  • 9.
  • 10.
    softwaretester.blog | BenjaminBischoff –Martin Fowler „A code smell is a surface indication that usually corresponds to a deeper problem in the system.“
  • 11.
    softwaretester.blog | BenjaminBischoff 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 | BenjaminBischoff TAXONOMY OF CODE SMELLS Mika V. Mäntylä & Casper Lassenius, Helsinki University of Technology
  • 13.
    softwaretester.blog | BenjaminBischoff TAXONOMY OF CODE SMELLS Mika V. Mäntylä & Casper Lassenius, Helsinki University of Technology
  • 14.
    softwaretester.blog | BenjaminBischoff Classi fi cation
  • 15.
    softwaretester.blog | BenjaminBischoff 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
  • 16.
    softwaretester.blog | BenjaminBischoff Bloaters Too large to handle.
  • 17.
    softwaretester.blog | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff record Customer( String name, int age, String street, String city, int zipCode, String country ) { } Bloaters Primitive Obsession Favouring primitive data types
  • 28.
    softwaretester.blog | BenjaminBischoff record Customer( String name, int age, String street, String city, int zipCode, String country ) { } Bloaters Primitive Obsession Favouring primitive data types
  • 29.
    softwaretester.blog | BenjaminBischoff record Customer( String name, int age, String street, String city, int zipCode, String country ) { } Bloaters Primitive Obsession Favouring primitive data types
  • 30.
    softwaretester.blog | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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
  • 42.
    softwaretester.blog | BenjaminBischoff OOP Abusers Missing object-oriented design possibilities.
  • 43.
    softwaretester.blog | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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
  • 67.
    softwaretester.blog | BenjaminBischoff Change Preventers Hindering further development.
  • 68.
    softwaretester.blog | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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
  • 93.
    softwaretester.blog | BenjaminBischoff Dispensables Unnecessary things that can be removed.
  • 94.
    softwaretester.blog | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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
  • 125.
    softwaretester.blog | BenjaminBischoff Couplers Too much or too little coupling.
  • 126.
    softwaretester.blog | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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 | BenjaminBischoff 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
  • 149.
    softwaretester.blog | BenjaminBischoff Example Code github.com/bischoffdev/code-smells
  • 150.
    softwaretester.blog | BenjaminBischoff When to tackle code smells?
  • 151.
    softwaretester.blog | BenjaminBischoff Broken window Long-term effects of un fi xed code.
  • 152.
    softwaretester.blog | BenjaminBischoff YAGNI Wasting time with future requirements.
  • 153.
    softwaretester.blog | BenjaminBischoff Campground Rule Later never comes…
  • 154.
    softwaretester.blog | BenjaminBischoff Code Reviews Point out smells before it is too late!
  • 155.
    softwaretester.blog | BenjaminBischoff More information
  • 156.
    softwaretester.blog | BenjaminBischoff Refactoring catalog refactoring.com/catalog
  • 157.
    softwaretester.blog | BenjaminBischoff Refactoring Guru refactoring.guru/refactoring
  • 158.
    softwaretester.blog | BenjaminBischoff Marcel Jerzyk luzkan.github.io/smells/
  • 159.
    softwaretester.blog | BenjaminBischoff Smelly Code Smelly code, smelly code How are they treating you? Smelly code, smelly code It’s not your fault.
  • 160.
    softwaretester.blog | BenjaminBischoff Thank you!
  • 161.
    softwaretester.blog | BenjaminBischoff Thank you!