Code Smells -
know when your code stinks
Andreas Prüller
November 16, 2012
Andreas Prüller
November 16, 2012
If it stinks, change it.
Description
Identical or very similar code exists in more than one location.
Example
public class SuperNumber { private int number; public void multiplyOne(SuperNumber multiplier) { number = number * multiplier.getNumber(); recalculate(); doSuperThing(); } public void multiplyTwo(SuperNumber multiplier) { number = number * multiplier.getNumber() recalculate(); doAnotherSuperThing(); } }
What to do, if
Description
A method, function or procedure has grown too long.
Example
public class FooBar { public String reallyLongMethod(String value, String value2, String value3, int oopsAnInt, String value4, String value 5, String value6, int oopsAnotherInt, String value7, String value8, String nowItsEnough) { String result = "Thats the beginning ..."; // now do something in hundreds of lines of code ... return result; } }
What to do?
In 99,9% of the time, just use Extract Method to shorten a method.
Description
A class that has grown to large. It's likely the class has become a “god object”, it knows too much or does to much (perhaps even both).
Example
public class NoExample { /* * No example here, as the sheet isn't long enough, just think of one you have seen * in the past. I'm quite sure, you have seen one. * If you can't remember one, just imagine this class here has 3000 more lines of code, * which aren't comments. * * A good example could be the class java.net.URI. */ }
What to do?
Description
A long list of parameters make a method or function error prone and hard to read.
Example
public class FooBar { public String reallyManyParameters(String value, String value2, String value3, int oopsAnInt, String value4, String value 5, String value6, int oopsAnotherInt, String value7, String value8, String value9, long heheYouDidntExpectThat, String value10, String nowItsEnough, String notYet, String oneMoreToCome) { String result = "Thats the beginning ..."; // now do something ... return result; } }
What to do?
Important exception: In rare cases you possibly don't want create a dependency from to the called to the larger object. In this cases it's reasonable to unpack the data and provide by parameters. But be aware of the pain you will suffer in the future when doing so.
Description
A class is often changes in different ways for different reasons.
Example
In class CustomerData
you have edit three methods every time you add a new role to your rights management. Every time you change your social media integration you have to alter four other methods in the very same class.
What to do?
This case is quite simple: use Extract Class, so every class is just responsible for one of the change causes.
Description
Shotgun surgery is similar to Divergent Change but the opposite. Every time you make a change, you have to make lots of little changes in serveral clases.
Example
You make a change to class Customer
. As a result you have to adopt things in the classes SpecialCustomer
, Reciept
and Contact
which forces changes in Address
and SocialMedia
.
What to do?
Use Move Method and Move Field to collect all changes in a single class. If you can't find any good candidate class create a new one. Often you can use a Inline Class to pull all the behaviour together.
Description
A method is more interested in another class than the one it is in. It calls a load of getter methods of another class to calculate something.
Example
public class Invoice { public List<OrderItem> createOrderItemsList(Order order) { List<OrderItem> orderItems = new LinkedList<OrderItem>(); // ... some loop iterating over a list in oder orderItem.setItemCallNumber(order.getCallNumber()); orderItem.setItemOrderDate(order.getOrderDate()); orderItem.setItemPrize(order.getItemByNumber(itemNumber).getPrize); // and so on ... orderItems.add(orderItem); // ... end of the loop return orderItems; } }
What to do?
Attention: Patterns like Strategy or Visitor (from the Gang of Four) break this smell. A fundamental rule of thumb is: Put together what changes together, this includes the behaviour that references the data. If behaviour and data would be separated, the behaviour will be moved to.
Description
You see the same three or four data items together in lots of places: fields in a couple of classes, parameters in many method signatures.
What to do?
Afterwards you can look for cases of Feature Envy which possibly results in some methods wandering into your new class.
Description
No small classes for small entities exist. As a result the functionality was added to some other class.
Example
public class Customer { // some data ... private int phoneNumberPrivate; private int cellPhoneNumberPrivate; private int phoneNumberWork; private int cellPhoneNumberWork; private int creditRating; public void setPhoneNumberPrivate(int phoneNumberPrivate) { this.phoneNumberPrivate = phoneNumberPrivate; } public int getPhoneNumberPrivate() { return this.phoneNumberPrivate; } // and so on .. }
What to do?
Description
Switch Statements are the goto
of object oriented languages. They are evil, you don't need them. Really.
Example
public class Customer { public List<PaymentOption> decidePaymentOptions() { switch (creditRating) { case 1: // do something break; case 2: // do something default: // do something break; } return paymentOptions; } }
What to do?
Description
Every time you make a subclass of one class, you have to make a subclass of another one.
Example
You want to extend WVideoImpl
. To get it working you also have to extend VideoImpl
.
What to do?
Make sure that instances of one hierarchy refer to instances of the other. If you use Move Method and Move Field, the hierarchy on the referring class disappears.
Description
Classes that don't do enough to pay for themself should be eliminated. The cost of maintaining them is higher than there benefit.
Example
public class StreetName { private String streetName; public void setStreetName(String streetName) { this.streetName = streetName; } public String getStreetName() { return this.streetName; } }
What to do?
Description
Speculative generality appears when some functionality was built in because some time in the future someone might need it. If only a test class uses a method or class (and it is no helper to test some legitimate functionality) you can be rather sure you smell speculative generality.
What to do?
Description
Instance variables are only set under certain circumstances, e.g. during th execution of a complex algorithm in one method.
What to do?
Description
Imagine a client asks a object for another object. The last one is asked by the client for another one, wich again is asked for a other object. When stumbling over this you surely smell a message chain. It can manifest as a series of getThis()
methods or a sequence of temporary fields.
Example
public class InvoicePrinter { public List<InvoiceLine> getInvoiceLines(Order order) { // some code ... String productName = order.getCustomerOrder().getOrderList().get(i).getCustomerOrderItem() .getProduct().getProductName(); // some more code ... CustomerOrder customerOrder = order.getCustomerOrder(); CustomerOrderItem customerOrderItem = customerOrder.getOrderList().get(i); Product product = customerOrderItem.getProduct(); String productNumber = product.getOrderNumber(); // more code ... } }
What to do?
Description
Delegation is a nice concept. But you can take to far. If you look at an class interface and half of all methods delegates the work to one other class you have a Middle Man problem. Why not directly talking to the other class?
What to do?
Description
Classes become far too intimate and spend too much time delving in each others’private parts.
What to do?
Description
Any methods that do the same thing should have the same signatures for what they do.
Example
public class Order { public Order getOrderById(int orderId) { // do something return order; } } public class Invoice { public Invoice getInvByIdentifactionNumber(int invoiceIdentification, boolean switch) { // do something return invoice; } }
What to do?
Description
Working without libraries is nearly impossible nowadays. But the builders of libraries are not omniscient. Sometimes we miss a function we would like to be in the used library. Modifying a library is a no-go (if it is not your own).
What to do?
Description
Data classes are classes that just have field and setters for this fields, nothing else. They are dumb data holders and are almost certainly being manipulated in far too much detail by other classes.
Example
public class Beer { public String name; public int sizeInLiters; public int prize; public void setName(String name) { this.name = name; } public void setSizeInLiters(int sizeInLiters) { this.sizeInLiters = sizeInLiters; } // and so on ... }
What to do?
Description
Subclasses get to inherit the methods and data of their parents. But what if they don’t want or need what they are given? They are given all these great gifts and pick just a few to play with.
What to do?
Description
Comments itself aren't bad, they are not really a smell. But they are often used as a deodorant to cover smells (known as bad code). There is often some correlation between amount of comments and code quality: the more comments you see, the worse the code.
What to do
When you feel the need to write a comment, first try to refactor the code so that any comment becomes superfluous.