š Last updated: October 21, 2025
ā Welcome to The Coder Cafe! Today, we discuss a fundamental idea to software design: focusing on product ideas and not the strict requirements. Get cozy, grab a coffee, and letās begin!
In Premature Abstractions, we discussed how building premature abstractions or designing with speculative future needs in mind can often be a waste of time. In this post, I want to introduce a principle to help us find a better balance between over-engineering and over-applying the YAGNI principle.
The main idea is that writing code that is aligned with the fundamental concepts of our productĀ can make it more adaptable to future changes. Letās discuss a concrete example.
Imagine we work at Starbucks as a software engineer, crafting their first online ordering system. Hereās a simple Java interface that we could start with:
interface Delivery {
public void deliverCoffee(List<Coffee> coffees);
}This approach works well initially. Yet, what if Starbucks decides to add food alongside coffee as part of the deliveries?
One way to accommodate this change is to modify our existing interface by adding a new method:
interface Delivery {
public void deliverCoffee(List<Coffee> coffees);
public void deliverCoffeeAndFood(List<Coffee> coffees, List<Food> foods); // New method
}Yet, as our requirement grows (ordering teas, juices, mugs, etc.), we might find ourselves adding more and more methods to this interface. This can quickly become cumbersome and lead to a codebase that becomes hard to maintain.
Perhaps the issue was to create this initial deliverCoffee method. This method was based on a specific requirement we received: delivering coffee. Thus, letās create one method for that!
Instead, we can focus on the product idea itself. What does Starbucks want to achieve? Handling deliveries. So, instead of our initial deliverCoffee method, letās replace it with a more generic deliver function, taking a DeliveryList argument:
interface Delivery {
public void deliver(DeliveryList items);
}
class DeliveryList {
private List<Coffee> coffees;
// Other items can be added as needed
}In this approach, DeliveryList isĀ a domain object: an object that represents a common idea in our domain. By focusing on the idea of delivery rather than a specific requirement, we create a design that is more adaptable to future changes.
While YAGNI tells us to avoid building what we donāt need, it shouldnāt force us to ignore what we already know. Modeling the core concepts of the business (e.g., a delivery) isnāt speculation. Using domain objects can be a practical way to find the balance between premature thinking and YAGNI, creating foundations that will be more naturally resilient to future changes.
Resources
More From the Programming Category
ā¤ļø If you enjoyed this post, please hit the like button.





