Code Smells Flashcards
Nil Check
A Nil Check is a type check. Failures of Nil Check violate the “tell, don’t ask” principle. Additionally to that, type checks often mask bigger problems in your source code like not using OOP and / or polymorphism when you should.
The Nil Check code smell is a case of Simulated Polymorphism.
Manual Dispatch
Manual Dispatch smell is found in source code that manually checks whether an object responds to a method before that method is called. Manual dispatch is a type of Simulated Polymorphism which leads to code that is harder to reason about, debug, and refactor.
Simulated Polymorphism
Simulated Polymorphism occurs when code uses a case statement (especially on a type field);
or code has several if statements in a row (especially if they’re comparing against the same value);
or code uses instance_of?, kind_of?, is_a?, or === to decide what type it’s working with;
or multiple conditionals in different places test the same value.
Conditional code is hard to read and understand, because the reader must hold more state in their head. When the same value is tested in multiple places throughout an application, any change to the set of possible values will require many methods and classes to change. Tests for the type of an object may indicate that the abstraction represented by that type is not completely defined (or understood).
Repeated Conditional
Repeated Conditional is a case of Simulated Polymorphism. Basically it means you are checking the same value throughout a single class and take decisions based on this.
Feature Envy
Feature Envy occurs when a code fragment references another object more often than it references itself, or when several clients do the same series of manipulations on a particular type of object.
Feature Envy reduces the code’s ability to communicate intent: code that “belongs” on one class but which is located in another can be hard to find, and may upset the “System of Names” in the host class.
Feature Envy also affects the design’s flexibility: A code fragment that is in the wrong class creates couplings that may not be natural within the application’s domain, and creates a loss of cohesion in the unwilling host class.
Feature Envy often arises because it must manipulate other objects (usually its arguments) to get them into a useful form, and one force preventing them (the arguments) doing this themselves is that the common knowledge lives outside the arguments, or the arguments are of too basic a type to justify extending that type. Therefore there must be something which ‘knows’ about the contents or purposes of the arguments. That thing would have to be more than just a basic type, because the basic types are either containers which don’t know about their contents, or they are single objects which can’t capture their relationship with their fellows of the same type. So, this thing with the extra knowledge should be reified into a class, and the utility method will most likely belong there.
Control Couple
Control coupling occurs when a method or block checks the value of a parameter in order to decide which execution path to take. The offending parameter is often called a Control Couple.
Control Coupling is a kind of duplication, because the calling method already knows which path should be taken.
Control Coupling reduces the code’s flexibility by creating a dependency between the caller and callee: any change to the possible values of the controlling parameter must be reflected on both sides of the call. A Control Couple also reveals a loss of simplicity: the called method probably has more than one responsibility, because it includes at least two different code paths.
Control Parameter
This is a “Control Couple” smell:
A simple example would be the quoted parameter in the following method:
def write(quoted) if quoted write_quoted @value else write_unquoted @value end end
Fixing those problems is out of the scope of this document but an easy solution could be to remove the write method altogether and to move the calls to write_quoted and write_unquoted to the caller of write.
Large Class
A Large Class is a class or module that has a large number of instance variables, methods or lines of code in any one piece of its specification. (That is, this smell relates to pieces of the class’s specification, not to the size of the corresponding instance of Class.)
Reek offers these checks for the smell:
- Too Many Constants
- Too Many Instance Variables
- Too Many Methods
Instance Variable Assumption
Classes should not assume that instance variables are set or present outside of the current class definition.
Good:
class Foo
def initialize
@bar = :foo
end
def foo? @bar == :foo end end Good as well:
class Foo
def foo?
bar == :foo
end
def bar @bar ||= :foo end end Bad:
class Foo
def go_foo!
@bar = :foo
end
def foo?
@bar == :foo
end
end