Pages

Showing posts with label refactor. Show all posts
Showing posts with label refactor. Show all posts

Tuesday, February 11, 2020

Design Decisions

I was practising a Kata I haven't done in a while because I wanted to add a recording to the new Page I created dedicated to TDD Katas. The Kata in question was the Roman Numerals Kata (From Roman to Arabic).

After doing the Kata I ended up with this implementation:



This is fine, the solution worked but I just didn't like that those two nested loops seemed a bit of a lot of complexity. Probably not the best solution from the point of view of performance. I wanted to try something else. So I deleted that code and without deleting the tests I wrote this:



To me this seemed a bit better and probably faster. Optimisations are something that we should always postpone. Remember the saying?

Make it run, then make it nice, then make it fast.

Early optimisations can lead to unwanted over-engineering and some other problems. TDD teaches us that we need to grow our code gradually. But then how can we just refactor to something completely different than what we just got?

Once we have written all our tests and we are happy with our refactoring, the tests will act as our documentation, so even if we were to delete all the code and just leave the tests, we could recreate the code. So that is what I did initially to create that second implementation.

After observing the new implementation and compare it to the previous one, I decided to TDD to see if I could get to the code in the second implementation. I discovered that at the point where I was doing the refactoring after making the test for number 6 pass, here was the place where I could make a design decision and choose not to extract an enum and instead try something else.

This time the Kata has once more proven that TDD is not just capable of making safer code but also drive the design even when we are looking for a faster solution than the one we have.


Here the video for that Kata:
 

Monday, December 17, 2018

Java 8 Refactoring Part 5: Improving enum with a BiFunction

This is the last refactoring that Victor Rentea did in the devoxx conference in London. He used a BiFunction to be able to provide more flexibility to an Enum. A very interesting refactor.



Thursday, April 13, 2017

Implementing Strategy Design Pattern(Practical example)

In this video I show how to refactor some ugly if-else nested statements using polymorphism through the strategy design pattern.

Please note that I didn't use code coverage in this occasion, this was more of an Spike than a refactor I would say. My goal was to just show the implementation of the pattern and make a brief video. Of course if you are trying this in real software, please make sure that your code is covered by unit tests before proceeding.




Tuesday, April 11, 2017

Checking that 2 Lists have elements in common

How many times have we created loops to check if any of the elements of one list are contained among any of the elements of other list?

Lists have a contains() and also a containsAll() methods but they doesn't seem to do what we want and we end up writing spaghetti that looks like this often:

1:  boolean isSafeToEat(List<String> allergicFoods) {  
2:    for (String ingredient : getIngredients()) {  
3:      if (allergicFoods.contains(ingredient)) {  
4:        return false;  
5:      }  
6:    }  
7:    return true;  
8:  }  


Sometimes we forget that the Java API has so many useful things. Like this disjoint() method, from Collections.

1:    boolean isSafeToEat(List<String> allergicFoods) {  
2:      return Collections.disjoint(ingredients, allergicFoods);  
3:    }  

Its not Java 8 ;) its being there for a bit already, have a look at this docs:
https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#disjoint(java.util.Collection,%20java.util.Collection)

Refactor switch to Enum

Do switch statements sound good to you? 
Trust me better switch to Enum before it destroys your ears ;)



Thursday, April 6, 2017

Dealing with Hardwired dependencies part 2 - Making a design decission

In this second video, I make a design decision and I remove the temporary refactor that I did earlier.
The Seam was not a bad idea, but it was a temporary solution only until I make a decision about the design of the class.


Monday, May 27, 2013

Duplication - A bit between your teeth

I presume that pretty much everybody who has been in contact with the java programming language either in studies or professionally even for a little bit, knows that duplication is a code smell.
We all know that some consequences of duplication are: less maintainability, less readability, the code is more likely to contain bugs, performance issues... and many more.

I think there should not be need to explain what duplication is, but just in case let's write only one line to define it and also make sure that we understand it:
"Duplication is the existence of multiple copies of a single concept"


Are there any doubts until this point?...
Please go back and read once more the definition if you still are not sure about it.

So, how do we fix duplication?


But if it is so easy to understand what duplication is and also how simple it is to refactor, why do we find it all over the place, no matter what software we are looking at.

Well... there are many reasons why there is duplication all over the place:
  • sometimes we just rush to get things done and we don't care about it. 
  • maybe we think that refactoring is boring or is not profitable, so we have no patience to do it.
  • other times we think there are always more important things to do and duplication is not really affecting us.
  •  also sometimes when we want to do something about it, we just can't see it even if it is in front of us.             

 So, what do you think?... Any of this may be the reason why you are not fixing duplication?
If your reason is any of the first 3, I am sorry, but this blogpost will not be of any use to you and the best you can do is close this browser tab or surf somewhere else.

But if it is the 4th, the reason why you are not fixing the duplication, then you might find the following lines very interesting....

This is the secret why many programmers sometimes find it so difficult to deal with duplication...

There are different kinds of duplication, this are some of the most important:
  • Literal
  • Structural
  • Semantic

Literal duplication
This is a very easy to spot kind of duplication. It is basically literal values that are repeated in our code.

e.g
 public class RepeaterSpecification {  
      @Test  
      public void repeatsInput() {  
               assertThat("value",is(repeat("value")));  
      }  
      @Test  
      public void repeatsEmptyInput() {  
              assertThat("",is(repeat("")));  
      }  
     //...  
 }  

The most common way to fix this type of duplication is to create a local variable. Let's have a look at a possible refactor:

 public class RepeaterSpecification {  
      @Test  
      public void repeatsInput() {  
         String input = "value";  
         assertThat(input,is(repeat(input)));  
      }  
      @Test  
      public void repeatsEmptyInput() {  
         String input = "";  
         assertThat(input,is(repeat(input)));  
      }  
     //...  
 }  
It looks like we no longer have literal duplication. But unfortunately as you probably noticed, sometimes when fixing one type of duplication we generate another type of duplication. Keep reading to find out more...

Structural duplication
We can recognize this situation when the logic is duplicated but it operates on different data.
See this situation in the following example:

e.g
 public class RepeaterSpecification {  
      @Test  
      public void repeatsInput() {  
         String input = "value";  
         assertThat(input,is(repeat(input)));  
      }  
      @Test  
      public void repeatsEmptyInput() {  
         String input = "";  
         assertThat(input,is(repeat(input)));  
      }  
     //...  
 }  


As you can see I toke this code from the previous example. The assertThat() operation is identical, the only difference is the data that it uses. Let's have a little look at a way how to fix structural duplication:


public class RepeaterSpecification {  
      
      @Test  
      public void repeatsInput() {  
         assertThatInputIsRepeated("value");  
      }  

      @Test  
      public void repeatsEmptyInput() {  
         assertThatInputIsRepeated("");  
      }
 
      private void assertThatInputIsRepeated(String input) {  
            assertThat(input,is(repeat(input)));
      }
     //...  
 }


Now that we extracted the method that does the assertion we no longer have duplication.

Semantic duplication
This is  the situation where different code implementations represent the same functionality or concept.
The definition of semantic duplication teaches us that duplication can be invisible from the point of view of the code("The definition from the start of this post makes a way more sense now, uh? :)" ). This kind of duplication is probably one of the most difficult to spot.

e.g
public class TeamValidator {       
  
      public boolean isThereALeader(List<Members> team) {  
           Iterator<Member> iterator = team.getIterator();
           while(iterator.hasNext()) {
              Member member = iterator.next();
              String role = member.getRole();
              if(role.equals("Leader"))
                return true;
           }  
           return false;
      }  

      public boolean areThereAtLeast2NewJoiners(List<Members> team) {  
            for(Member member:team) {
                DateTime aMonthAgo = DateTime.now().minusMonths(1);
                if(member.startingDate().isAfter(aMonthAgo))
                return true; 
            }
            return false;   
      }
     //...  
 }


At first glance, when we look at the two methods in the code above we cannot really see much duplication. No matter how much we look at it, we will not see it. Semantic duplication is invisible from the implementation point of view. To spot it what we need to do is spot the behavioral anti pattern that is hidden in the code. If we think about it, basically the repetition going on is that both methods iterate one list of the same type and then apply certain criteria(Completely different implementations but one same concept).
Semantic duplication is more difficult to fix than other types of duplication and often requires a bigger refactoring effort. Here is one possible solution that helps us get rid of it using Java generics:

 public class TeamValidator {      
    public boolean isThereALeader(List<Member> team) {   
         return new LeaderVerifier<Member>().evaluate(team);  
    }   
    public boolean areThereAtLeast2NewJoiners(List<Member> team) {   
         return new NewJoinersVerifier<Member>().evaluate(team);  
    }  
 }  


 public abstract class LoopEvaluator<T> {

 public boolean evaluate(List<T> list) {
  for (T element : list) {
   if(evaluateElement(element)) {
    return true;
   }
  }
  return false;
 }
 
 public abstract boolean evaluateElement(T element);
 
}


public class LeaderVerifier<T extends Member> extends LoopEvaluator<T> {

 @Override
 public boolean evaluateElement(T element) {
  return element.getRole().equals("leader");
 } 
}



public class NewJoinersVerifier<T extends Member> extends LoopEvaluator<T> {

 private int newJoiners;
 
 @Override
 public boolean evaluate(List<T> list) { 
  this.newJoiners = 0;
  return super.evaluate(list);
 }
 
 @Override
 public boolean evaluateElement(T element) {
  DateTime aMonthAgo = DateTime.now().minusMonths(1);
  if(element.startingDate().isAfter(aMonthAgo)) 
   this.newJoiners++;
  return newJoiners == 2;
 }
}


Duplication is not a little topic at all. The 3 types of duplication I mentioned in this post are from my point of view some of the most common but there are many more. Here a link where I found where at the bottom you can find a mention to other kinds of duplication: http://blogs.agilefaqs.com/tag/code-smells/


                                                                     
 I am the spaghetti monster, You cant get rid of me!!!! Hahahaha......

Just to conclude this post, I want to say that I have the impression that duplication many times is an  underestimated code smell that undetected grows and grows and ends up transforming systems into spaghetti monsters.

Lets get rid of it while it is just a bit between your teeth! ;)







Share with your friends