<= Home

YAGNI and Designing For the Future

Posted about over 2 years ago

YAGNI (You aren’t going to need it)

Simply stated "Always implement things when you actually need them, never when you just foresee that you need them." There are several reasons why this is good practice.

Designing for the Future

Once an application is created, there is one thing that is for sure…the system will eventually be asked to change to meet certain new requirements by its users.

That means the future of every application is change and therefore it would make sense to write software in a way for it to evolve gracefully. But when pairing with some one new to "real" object thinking...designing for the future seemed to conflict with YAGNI.

These two aspects of programming in fact are not contradictions at all but applicable in different contexts.

The ultimate goal of OOP is to provide a system with limited "Implementation" dependencies. Meaning Class A does not depend on how class b is implemented and so on. In a system, YAGNI would manifest itself when a developer would want provide some type of feature that they feel the business will eventually need OR introduce a measure of complexity just for "when" things change drastically.

I think the simplest example would be factories for the creation of every different type in a system (I am not sure why many have such a desire to abstract a constructor) At this point YAGNI (if it were a person) would say stick to the simplest code to implement the task and do only what the users/business ask for.

But we can still designing a system for the future without requiring additional complexity by:

So what does that mean, lets take an example of Filtering an collection of object based on some criteria Lets say we have a filter class that should filter items based on its location. It can filter anything that implements IsupportLocationFiltering
interface ISupportLocationFiltering
{
  State GetState();
}


class FilterRule
{
  private readonly State TargetState;

  public IList Filter(IList itemsToFilter)
  {
     IList filteredItems = new ArrayList();
     foreach(IsupportLocatinFiltering supporter in itemsToFilter)
	if(items.GetState() == TagetState) filteredItems.Add(supporter)
     return filteredItems;
  }
}
The above FilterRule breaks encapsulation and therefore is not designed for the future. The reason being is the filter asks for the State and proceeds to compare it against the state that we want to find items from. First we are assuming that all types that implement ISupportLocationFiltering can be filtered by matching states. Maybe we match states for all objects today but tomorrow what if we introduce a new type that can support "Location Filtering" but is done by checking to see if a zip code is from the target state. We can easily accommodate this by using encapsulation without adding complexity and achieving flexibility.
interface ISupportLocationFiltering
{
  bool IsIn(State state);
}


class FilterRule
{
  private readonly State TargetState;

  public IList Filter(IList itemsToFilter)
  {
     IList filteredItems = new ArrayList();
     foreach(IsupportLocatinFiltering supporter in itemsToFilter)
	if(items.IsIn(TagetState)) filteredItems.Add(supporter)
     return filteredItems;
  }
}
Now its up to each implementation of ISupportLocationFiltering to know if it can be filtered by a state. Our Interface is much more useful then just for filtering so we can accommodate future changes by renaming it to something more useable
interface ISupportALocation
{
  bool IsIn(State state);
}