Spotting Feature Envy and Refactoring

I was following Aki’s on the SoCraTes2014 conference last week about Legacy Code and Refactoring. In the session a piece of real-world code was shown that contained one of most common code smells in LegacyCode: Feature Envy.

Martin Fowler describes this smell as “a method that seems more interested in a class other than the one it is in. The most common focus of the envy is the data.”

This code smell causes two very similar problems in a code base:

Duplication of rules related to their data throughout the code base.

Spreading domain concepts throughout the whole code-base.

A simple example can show this problem with DateTime is wide-spread in many PHP projects. We often see code such as the following computation to create a range of dates for a reporting function:

<?php function calculateReport ( DateTime $start , $days ) { if ( $days < 0 ) { throw new InvalidArgumentException ( $days ); } $endDate = clone $start ; $endDate -> modify ( '+' . $days . ' day' ); // calculation code here }

This is a really simple example for Feature Envy: The computation and validation of creating an end date some days in the future of a start date can easily be duplicated throughout the whole code base and implements business rules that belong to the class DateTime itself:

<?php class DateTime { // ... other methods public function getDateDaysInFuture ( $days ) { if ( $days < 0 ) { throw new InvalidArgumentException ( $days ); } $endDate = clone $this ; $endDate -> modify ( '+' . $days . ' day' ); return $endDate ; } } function calculateReport ( DateTime $start , $days ) { $endDate = $start -> getDateDaysInFuture ( $days ); // calculation code here. }

(Note: You cant extend the builtin DateTime this way and need to subclass).

This is a great way to improve your code base massively and achieve what Object-Oriented and Domain-Driven Design is about: Modelling concepts of the domain by encapsulating data and behavior.

Learning to spot this kind of Feature Envy is a very good way to incrementally improve your legacy code base towards better models. I find it very interesting that the focus on fixing technical code-smells duplication and feature envy actually leads to a better domain model. As a side effect it massively deemphasizes DDD building blocks like Entity or Value Object, which in my opinion are a big cause for confusion. Testability increases as well, because data objects with behavior are much simpler to setup for testing.

That is why I recommend learning about Feature Envy. For me it is a very simple approach to find improvements.