KISS - Keep It Simple, Stupid
Definition

Over-Engineering Examples
// BAD: Over-engineered for a simple need
// "We might need to support multiple formats later"
public interface DataSerializer<T> {
byte[] serialize(T data);
T deserialize(byte[] bytes);
}
public abstract class AbstractSerializerFactory<T> {
protected abstract DataSerializer<T> createSerializer();
protected abstract void configure(SerializerConfig config);
}
public class JsonSerializerFactory<T> extends AbstractSerializerFactory<T> {
private ObjectMapper mapper;
private SerializerConfig config;
private List<SerializerPlugin> plugins;
// ... 100 more lines
}
// GOOD: Simple solution for current need
public class UserSerializer {
private final ObjectMapper mapper = new ObjectMapper();
public String toJson(User user) {
return mapper.writeValueAsString(user);
}
public User fromJson(String json) {
return mapper.readValue(json, User.class);
}
}
// When you actually need multiple formats, refactor then.
Simplicity in Code
// BAD: Clever but hard to understand
public int findMax(int[] arr) {
return Arrays.stream(arr)
.boxed()
.reduce(Integer.MIN_VALUE, (a, b) ->
a ^ ((a ^ b) & -((a - b) >>> 31)));
}
// GOOD: Clear and obvious
public int findMax(int[] arr) {
if (arr.length == 0) {
throw new IllegalArgumentException("Array is empty");
}
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
// Or even simpler:
public int findMax(int[] arr) {
return Arrays.stream(arr).max()
.orElseThrow(() -> new IllegalArgumentException("Array is empty"));
}
Architecture Simplicity

Signs of Over-Complexity

Simplicity Techniques
// Technique 1: Use clear naming instead of comments
// BAD
int d; // elapsed time in days
// GOOD
int elapsedTimeInDays;
// Technique 2: Prefer composition over complex inheritance
// BAD: Complex inheritance hierarchy
class Animal { }
class Mammal extends Animal { }
class Canine extends Mammal { }
class Dog extends Canine { }
class ServiceDog extends Dog { }
// GOOD: Flat composition
class Dog {
private final Breed breed;
private final Training training;
private final boolean isServiceAnimal;
}
// Technique 3: Early returns over nested conditions
// BAD
public String getLabel(User user) {
if (user != null) {
if (user.isActive()) {
if (user.isPremium()) {
return "Premium";
} else {
return "Standard";
}
} else {
return "Inactive";
}
} else {
return "Unknown";
}
}
// GOOD
public String getLabel(User user) {
if (user == null) return "Unknown";
if (!user.isActive()) return "Inactive";
if (user.isPremium()) return "Premium";
return "Standard";
}
// Technique 4: Extract when it clarifies, not just to reduce lines
// BAD: Extraction makes it harder to follow
public void process(Order order) {
doStep1(order);
doStep2(order);
doStep3(order);
// Have to jump to 3 methods to understand
}
// GOOD: Keep simple logic inline
public void process(Order order) {
validateOrder(order);
// Calculate totals
Money subtotal = order.getItems().stream()
.map(item -> item.getPrice().multiply(item.getQuantity()))
.reduce(Money.ZERO, Money::add);
Money tax = subtotal.multiply(TAX_RATE);
order.setTotal(subtotal.add(tax));
orderRepository.save(order);
}
KISS vs Premature Optimization

Tips & Tricks
