CODE SMELLS
O QUE É UM
CODE SMELL?
LEONARDO BERNARDELLI
@lbenardelli
•Long Method
•Large Class
•Primitive Obsession
•Long Parameter List
•Data Clumps
•Switch Statements
•Temporary Field
•Refused Bequest
•Alternative Classes with Different Interfaces
•Divergent Change
•Shotgun Surgery
•Parallel Inheritance Hierarchies
•Comments
•Duplicate Code
•Lazy Class
•Data Class
•Dead Code
•Speculative Generality
•Feature Envy
•Inappropriate Intimacy
•Message Chains
•Middle Man
•Incomplete Library Class
BLOATERS
OO ABUSERS
CHANGE PREVENTERS
DISPENSABLES
COUPLERS
RefactoringPara todo existe uma receita
CODE SMELL
que explica como resolver o problema
http://www.industriallogic.com/wp-content/uploads/2005/09/smellstorefactorings.pdf
class OrdersReport
def initialize(orders, start_date, end_date)
@orders = orders
@start_date = start_date
@end_date = end_date
end
def total_sales_within_date_range
orders_within_range =
@orders.select { |order| order.placed_at >= @start_date &&
order.placed_at <= @end_date }
orders_within_range.
map(&:amount).inject { |sum, amount| amount + sum }
end
end
class Order < OpenStruct
end
class OrdersReport
def initialize(orders, start_date, end_date)
@orders = orders
@start_date = start_date
@end_date = end_date
end
def total_sales_within_date_range
orders_within_range.
map(&:amount).inject { |sum, amount| amount + sum }
end
private
def orders_within_range
@orders.select { |order| order.placed_at >= @start_date &&
order.placed_at <= @end_date }
end
end
class Order < OpenStruct
end
class OrdersReport
def initialize(orders, start_date, end_date)
@orders = orders
@start_date = start_date
@end_date = end_date
end
def total_sales_within_date_range
orders_within_range.
map(&:amount).inject { |sum, amount| amount + sum }
end
private
def orders_within_range
@orders.select { |order| order.placed_between?(@start_date, @end_date) }
end
end
class Order < OpenStruct
def placed_between?(start_date, end_date)
placed_at >= start_date && placed_at <= end_date
end
end
class OrdersReport
def initialize(orders, date_range)
@orders = orders
@date_range = date_range
end
def total_sales_within_date_range
orders_within_range.
map(&:amount).inject { |sum, amount| amount + sum }
end
private
def orders_within_range
@orders.select { |order| order.placed_between?(@date_range) }
end
end
class DateRange < Struct.new(:start_date, :end_date)
end
class Order < OpenStruct
def placed_between?(date_range)
placed_at >= date_range.start_date && placed_at <= date_range.end_date
end
end
class OrdersReport
def initialize(orders, date_range)
@orders = orders
@date_range = date_range
end
def total_sales_within_date_range
orders_within_range.
map(&:amount).inject { |sum, amount| amount + sum }
end
private
def orders_within_range
@orders.select { |order| order.placed_between?(@date_range) }
end
end
class DateRange < Struct.new(:start_date, :end_date)
def include?(date)
(start_date..end_date).cover?(date)
end
end
class Order < OpenStruct
def placed_between?(date_range)
date_range.include?(placed_at)
end
end
Foo Sale
Sale
where
.where(date: range)
Persistence
where
List
a List
a List
sum
.sum('cost')
Colaboradores Imediatos
Foo
DateRange
LIST
Sale
#where
I KNOW MY COLLABORATORS COLLABORATORS
SPECULATIVE GENERALITYDEPENDENCY INJECTION
É FODA!
99 bottles of beer on the wall, 99 bottles of beer.
Take one down and pass it around, 98 bottles of beer on the wall.
98 bottles of beer on the wall, 98 bottles of beer.
Take one down and pass it around, 97 bottles of beer on the wall.
97 bottles of beer on the wall, 97 bottles of beer.
Take one down and pass it around, 96 bottles of beer on the wall.
…
2 bottles of beer on the wall, 2 bottles of beer.
Take one down and pass it around, 1 bottle of beer on the wall.
1 bottle of beer on the wall, 1 bottle of beer.
Take one down and pass it around, no more bottles of beer on the wall.
No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.
A satisfactory modular decomposition technique must satisfy one more requirement: It should yield
modules that are both open and closed.
• A module will be said to be open if it is available for extension. For example, it should be possible to add
fields to the data structures it contains, or new elements to the set of functions it performs.
• A module will be said to be closed if is available for use by other modules. This assumes that the module
has been given a well-defined, stable description (the interface in the sense of information hiding). In the
case of a programming language module, a closed module is one that may be compiled and stored in a
library, for others to use. In the case of a design or specification module, closing a module simply means
having it approved by management, adding it to the project's official repository of accepted software
items (often called the project baseline), and publishing its interface for the benefit of other module
designers.
Robert C. Martin
SOLID
OBRIGADO!

Code smells

  • 1.
  • 2.
    O QUE ÉUM CODE SMELL?
  • 3.
  • 5.
    •Long Method •Large Class •PrimitiveObsession •Long Parameter List •Data Clumps •Switch Statements •Temporary Field •Refused Bequest •Alternative Classes with Different Interfaces •Divergent Change •Shotgun Surgery •Parallel Inheritance Hierarchies •Comments •Duplicate Code •Lazy Class •Data Class •Dead Code •Speculative Generality •Feature Envy •Inappropriate Intimacy •Message Chains •Middle Man •Incomplete Library Class BLOATERS OO ABUSERS CHANGE PREVENTERS DISPENSABLES COUPLERS
  • 6.
    RefactoringPara todo existeuma receita CODE SMELL que explica como resolver o problema
  • 8.
  • 9.
    class OrdersReport def initialize(orders,start_date, end_date) @orders = orders @start_date = start_date @end_date = end_date end def total_sales_within_date_range orders_within_range = @orders.select { |order| order.placed_at >= @start_date && order.placed_at <= @end_date } orders_within_range. map(&:amount).inject { |sum, amount| amount + sum } end end class Order < OpenStruct end
  • 10.
    class OrdersReport def initialize(orders,start_date, end_date) @orders = orders @start_date = start_date @end_date = end_date end def total_sales_within_date_range orders_within_range. map(&:amount).inject { |sum, amount| amount + sum } end private def orders_within_range @orders.select { |order| order.placed_at >= @start_date && order.placed_at <= @end_date } end end class Order < OpenStruct end
  • 11.
    class OrdersReport def initialize(orders,start_date, end_date) @orders = orders @start_date = start_date @end_date = end_date end def total_sales_within_date_range orders_within_range. map(&:amount).inject { |sum, amount| amount + sum } end private def orders_within_range @orders.select { |order| order.placed_between?(@start_date, @end_date) } end end class Order < OpenStruct def placed_between?(start_date, end_date) placed_at >= start_date && placed_at <= end_date end end
  • 12.
    class OrdersReport def initialize(orders,date_range) @orders = orders @date_range = date_range end def total_sales_within_date_range orders_within_range. map(&:amount).inject { |sum, amount| amount + sum } end private def orders_within_range @orders.select { |order| order.placed_between?(@date_range) } end end class DateRange < Struct.new(:start_date, :end_date) end class Order < OpenStruct def placed_between?(date_range) placed_at >= date_range.start_date && placed_at <= date_range.end_date end end
  • 13.
    class OrdersReport def initialize(orders,date_range) @orders = orders @date_range = date_range end def total_sales_within_date_range orders_within_range. map(&:amount).inject { |sum, amount| amount + sum } end private def orders_within_range @orders.select { |order| order.placed_between?(@date_range) } end end class DateRange < Struct.new(:start_date, :end_date) def include?(date) (start_date..end_date).cover?(date) end end class Order < OpenStruct def placed_between?(date_range) date_range.include?(placed_at) end end
  • 15.
  • 16.
  • 18.
  • 19.
    99 bottles ofbeer on the wall, 99 bottles of beer. Take one down and pass it around, 98 bottles of beer on the wall. 98 bottles of beer on the wall, 98 bottles of beer. Take one down and pass it around, 97 bottles of beer on the wall. 97 bottles of beer on the wall, 97 bottles of beer. Take one down and pass it around, 96 bottles of beer on the wall. … 2 bottles of beer on the wall, 2 bottles of beer. Take one down and pass it around, 1 bottle of beer on the wall. 1 bottle of beer on the wall, 1 bottle of beer. Take one down and pass it around, no more bottles of beer on the wall. No more bottles of beer on the wall, no more bottles of beer. Go to the store and buy some more, 99 bottles of beer on the wall.
  • 21.
    A satisfactory modulardecomposition technique must satisfy one more requirement: It should yield modules that are both open and closed. • A module will be said to be open if it is available for extension. For example, it should be possible to add fields to the data structures it contains, or new elements to the set of functions it performs. • A module will be said to be closed if is available for use by other modules. This assumes that the module has been given a well-defined, stable description (the interface in the sense of information hiding). In the case of a programming language module, a closed module is one that may be compiled and stored in a library, for others to use. In the case of a design or specification module, closing a module simply means having it approved by management, adding it to the project's official repository of accepted software items (often called the project baseline), and publishing its interface for the benefit of other module designers. Robert C. Martin SOLID
  • 37.