SlideShare una empresa de Scribd logo
1 de 22
Беспокойный код
    @SergeyMoiseev
О себе


• Девелопер с 1998 года.
• Писал индустриальные системы на PHP.
• Теперь на RoR.
Как определить
        неофита?

• Толстые контроллеры
• Беспокойство
• Желание “работать” с предельными
  условиями
Самый простой
   способ?
  def   foobar
    x   = self.bar
    x   = nil if x == 0
    y   = foo

    return x || y
  end
Return

• Самый неочевидный оператор для
  новичков
• Функция его наиболее отличается от
  таковой в других языках
return для flow-control
    def foobar
      if foo?
        if bar?
           #do something
           return 42
        else
           #do something
        end
      else
        #do something
      end
    end
if || unless
           if !params[:query].blank?




if !something                  unless something
unless?

• Как ни странно, это единственное для
  чего он нужен.
• Читать логику объединенную and/or при
  этом применяя к ней ! сложно.
• У него нет elsunless (нельзя сказать, что
  это минус).
If/else vs. unless
def possible_parents
  if self.new_record?
    Category.first_level
  else
    Category.first_level.where('id != ?', self.id)
  end
end

                                 vs.

   scope :not_given, lambda{|id| where('id != ?', id)}

   def possible_parents
     Category.first_level
     Category.first_level.not_given(self.id) unless self.new_record?
   end
Виды беспокойства

• Боязнь пользователя (глупого или
  злонамерянного).
• Боязнь предельных условий.
• Боязнь языка. Недостаток времени для
  экспериментов.
• Иллюзия контроля.
Боязнь пользователя
          Код из контроллера в админке
@role = Role.find params[:id]
redirect_to role_index_path and return unless @role


  Программист боится неправильного параметра.
 При этом он забывает о том, что find выбрасывает
                   exception.
Боязнь предельных
             условий
session[:foo] = params[:foo].blank? ? nil :
params[:foo].to_i


                         VS.

session[:foo] = params[:foo] ? params[:foo] : nil
Боязнь языка
scope :with_state, lambda {|state| where('state = ?',
state.to_s)}
scope :ready_for_start, with_state(:foo)
scope :ready_for_close, where('state IN(?)',
[:foo, :bar])


     “А вдруг он не приведет символ к строке?”

scope :with_states, lambda {|s| where("state in
(#{s.map{|e| "'#{e.to_s}'"}.join(',')})")}
Иллюзия контроля
def self.find_for_facebook_oauth(access_token,
signed_in_resource=nil)
  data = access_token['extra']['user_hash']
  if user = User.find_by_email(data["email"])
    user
  else # Create a user with a stub password.
    user = User.create do |record|
      record.email = data['email']
      record.password = Devise.friendly_token[0,20]
      record.registration_source = 1
      record.skip_confirmation!
    end
  end
end
Ослепление
          беспокойством

def self.to_rtf(codes)
  buffer = ""
  codes.each {|code| buffer << code.value << "n"}
  buffer
end
Ослепление
            беспокойством 2
def self.to_rtf(codes)
  codes.inject("") {|code, buffer| buffer << code.value << "n"}
end



                    Это был рефакторинг
Ослепление
   беспокойством 3
   def self.to_rtf(codes)
     codes.map(&:value).join("n")
   end

А это то, что на самом деле было нужно.
Знай свои
              инструменты
before_filter :guests_only!

def guests_only!
  redirect_to root_url and return if user_signed_in?
end

                 Зачем тут return?
Разгадка
• Программист не знает, как работает
  before_filter.
• Он беспокоится, что код контроллера
  будет выполняться после редиректа в
  фильтре.
• От своего беспокойства он забывает как
  о том, что нужно возвращать false, так и о
  том, что после редиректа это уже лишнее.
Более простое
       объяснение

• Код был перенесен в фильтр из экшена.
• Программисту просто не хочется его
  переписывать, потому как кажется, что
  этот возврат нужен (возвращаемся к
  исходному объяснению).
Metaprogramming to
          the recsue
if permission.can?
  can permission.action.to_sym, subject
else
  cannot permission.action.to_sym, subject
end


                    vs.
     method = permission.can? ? :can : :cannot
     send method, permission.action.to_sym, subject
Способы борьбы


• Знание языка
• Критический взгляд на свой код
• Let it fail (hoptoad в помощь)

Más contenido relacionado

Similar a Worried code

Программирование как способ выражения мыслей.
Программирование как способ выражения мыслей. Программирование как способ выражения мыслей.
Программирование как способ выражения мыслей. Levon Avakyan
 
Alexander Dymo - IT-клуб Николаева - April 2011 - Ruby: Beaty and the Beast
Alexander Dymo - IT-клуб Николаева - April 2011 - Ruby: Beaty and the BeastAlexander Dymo - IT-клуб Николаева - April 2011 - Ruby: Beaty and the Beast
Alexander Dymo - IT-клуб Николаева - April 2011 - Ruby: Beaty and the BeastAlexander Dymo
 
Теории и практики функционального программирования.
Теории и практики функционального программирования.Теории и практики функционального программирования.
Теории и практики функционального программирования.Dev2Dev
 
Теории и практики фунционального программирования - GDG D2D
Теории и практики фунционального программирования - GDG D2DТеории и практики фунционального программирования - GDG D2D
Теории и практики фунционального программирования - GDG D2D0xffAA
 
Grail - CodeFest'2015
Grail - CodeFest'2015Grail - CodeFest'2015
Grail - CodeFest'2015Igor Khrol
 
Grail: шаги для ваших Python-тестов
Grail: шаги для ваших Python-тестовGrail: шаги для ваших Python-тестов
Grail: шаги для ваших Python-тестовCodeFest
 
Павел Павлов - Scala для профессионалов - Joker 2013
Павел Павлов - Scala для профессионалов - Joker 2013Павел Павлов - Scala для профессионалов - Joker 2013
Павел Павлов - Scala для профессионалов - Joker 2013ScalaNsk
 
Algorithms and programming lecture in ru
Algorithms and programming lecture in ruAlgorithms and programming lecture in ru
Algorithms and programming lecture in russuser0562f1
 
Алгоритмизация и программирование С/С++
Алгоритмизация и  программирование С/С++Алгоритмизация и  программирование С/С++
Алгоритмизация и программирование С/С++ssuser0562f1
 
Демонизированный PHP - before it was cool
Демонизированный PHP - before it was coolДемонизированный PHP - before it was cool
Демонизированный PHP - before it was coolAndrey Tokarchuk
 
functional patterns - dotnetconf'11
functional patterns - dotnetconf'11functional patterns - dotnetconf'11
functional patterns - dotnetconf'110xffAA
 
Андрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кодаАндрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кодаSergey Platonov
 
Лекция 1. Начало.
Лекция 1. Начало.Лекция 1. Начало.
Лекция 1. Начало.Roman Brovko
 
2015-03-07 03 Сергей Александрович. 50 оттенков красного
2015-03-07 03 Сергей Александрович. 50 оттенков красного2015-03-07 03 Сергей Александрович. 50 оттенков красного
2015-03-07 03 Сергей Александрович. 50 оттенков красногоОмские ИТ-субботники
 
Лекция 6. Классы 1.
Лекция 6. Классы 1.Лекция 6. Классы 1.
Лекция 6. Классы 1.Roman Brovko
 

Similar a Worried code (20)

About Python
About PythonAbout Python
About Python
 
Enter: legacy code
Enter: legacy codeEnter: legacy code
Enter: legacy code
 
Программирование как способ выражения мыслей.
Программирование как способ выражения мыслей. Программирование как способ выражения мыслей.
Программирование как способ выражения мыслей.
 
Alexander Dymo - IT-клуб Николаева - April 2011 - Ruby: Beaty and the Beast
Alexander Dymo - IT-клуб Николаева - April 2011 - Ruby: Beaty and the BeastAlexander Dymo - IT-клуб Николаева - April 2011 - Ruby: Beaty and the Beast
Alexander Dymo - IT-клуб Николаева - April 2011 - Ruby: Beaty and the Beast
 
Теории и практики функционального программирования.
Теории и практики функционального программирования.Теории и практики функционального программирования.
Теории и практики функционального программирования.
 
Теории и практики фунционального программирования - GDG D2D
Теории и практики фунционального программирования - GDG D2DТеории и практики фунционального программирования - GDG D2D
Теории и практики фунционального программирования - GDG D2D
 
Grail - CodeFest'2015
Grail - CodeFest'2015Grail - CodeFest'2015
Grail - CodeFest'2015
 
Grail: шаги для ваших Python-тестов
Grail: шаги для ваших Python-тестовGrail: шаги для ваших Python-тестов
Grail: шаги для ваших Python-тестов
 
Павел Павлов - Scala для профессионалов - Joker 2013
Павел Павлов - Scala для профессионалов - Joker 2013Павел Павлов - Scala для профессионалов - Joker 2013
Павел Павлов - Scala для профессионалов - Joker 2013
 
Algorithms and programming lecture in ru
Algorithms and programming lecture in ruAlgorithms and programming lecture in ru
Algorithms and programming lecture in ru
 
Алгоритмизация и программирование С/С++
Алгоритмизация и  программирование С/С++Алгоритмизация и  программирование С/С++
Алгоритмизация и программирование С/С++
 
Ruby exceptions
Ruby exceptionsRuby exceptions
Ruby exceptions
 
Демонизированный PHP - before it was cool
Демонизированный PHP - before it was coolДемонизированный PHP - before it was cool
Демонизированный PHP - before it was cool
 
functional patterns - dotnetconf'11
functional patterns - dotnetconf'11functional patterns - dotnetconf'11
functional patterns - dotnetconf'11
 
Андрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кодаАндрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кода
 
Лекция 1. Начало.
Лекция 1. Начало.Лекция 1. Начало.
Лекция 1. Начало.
 
2015-03-07 03 Сергей Александрович. 50 оттенков красного
2015-03-07 03 Сергей Александрович. 50 оттенков красного2015-03-07 03 Сергей Александрович. 50 оттенков красного
2015-03-07 03 Сергей Александрович. 50 оттенков красного
 
50 оттенков красного
50 оттенков красного50 оттенков красного
50 оттенков красного
 
Лекция 6. Классы 1.
Лекция 6. Классы 1.Лекция 6. Классы 1.
Лекция 6. Классы 1.
 
запахи кода
запахи кодазапахи кода
запахи кода
 

Worried code

  • 2. О себе • Девелопер с 1998 года. • Писал индустриальные системы на PHP. • Теперь на RoR.
  • 3. Как определить неофита? • Толстые контроллеры • Беспокойство • Желание “работать” с предельными условиями
  • 4. Самый простой способ? def foobar x = self.bar x = nil if x == 0 y = foo return x || y end
  • 5. Return • Самый неочевидный оператор для новичков • Функция его наиболее отличается от таковой в других языках
  • 6. return для flow-control def foobar if foo? if bar? #do something return 42 else #do something end else #do something end end
  • 7. if || unless if !params[:query].blank? if !something unless something
  • 8. unless? • Как ни странно, это единственное для чего он нужен. • Читать логику объединенную and/or при этом применяя к ней ! сложно. • У него нет elsunless (нельзя сказать, что это минус).
  • 9. If/else vs. unless def possible_parents if self.new_record? Category.first_level else Category.first_level.where('id != ?', self.id) end end vs. scope :not_given, lambda{|id| where('id != ?', id)} def possible_parents Category.first_level Category.first_level.not_given(self.id) unless self.new_record? end
  • 10. Виды беспокойства • Боязнь пользователя (глупого или злонамерянного). • Боязнь предельных условий. • Боязнь языка. Недостаток времени для экспериментов. • Иллюзия контроля.
  • 11. Боязнь пользователя Код из контроллера в админке @role = Role.find params[:id] redirect_to role_index_path and return unless @role Программист боится неправильного параметра. При этом он забывает о том, что find выбрасывает exception.
  • 12. Боязнь предельных условий session[:foo] = params[:foo].blank? ? nil : params[:foo].to_i VS. session[:foo] = params[:foo] ? params[:foo] : nil
  • 13. Боязнь языка scope :with_state, lambda {|state| where('state = ?', state.to_s)} scope :ready_for_start, with_state(:foo) scope :ready_for_close, where('state IN(?)', [:foo, :bar]) “А вдруг он не приведет символ к строке?” scope :with_states, lambda {|s| where("state in (#{s.map{|e| "'#{e.to_s}'"}.join(',')})")}
  • 14. Иллюзия контроля def self.find_for_facebook_oauth(access_token, signed_in_resource=nil) data = access_token['extra']['user_hash'] if user = User.find_by_email(data["email"]) user else # Create a user with a stub password. user = User.create do |record| record.email = data['email'] record.password = Devise.friendly_token[0,20] record.registration_source = 1 record.skip_confirmation! end end end
  • 15. Ослепление беспокойством def self.to_rtf(codes) buffer = "" codes.each {|code| buffer << code.value << "n"} buffer end
  • 16. Ослепление беспокойством 2 def self.to_rtf(codes) codes.inject("") {|code, buffer| buffer << code.value << "n"} end Это был рефакторинг
  • 17. Ослепление беспокойством 3 def self.to_rtf(codes) codes.map(&:value).join("n") end А это то, что на самом деле было нужно.
  • 18. Знай свои инструменты before_filter :guests_only! def guests_only! redirect_to root_url and return if user_signed_in? end Зачем тут return?
  • 19. Разгадка • Программист не знает, как работает before_filter. • Он беспокоится, что код контроллера будет выполняться после редиректа в фильтре. • От своего беспокойства он забывает как о том, что нужно возвращать false, так и о том, что после редиректа это уже лишнее.
  • 20. Более простое объяснение • Код был перенесен в фильтр из экшена. • Программисту просто не хочется его переписывать, потому как кажется, что этот возврат нужен (возвращаемся к исходному объяснению).
  • 21. Metaprogramming to the recsue if permission.can? can permission.action.to_sym, subject else cannot permission.action.to_sym, subject end vs. method = permission.can? ? :can : :cannot send method, permission.action.to_sym, subject
  • 22. Способы борьбы • Знание языка • Критический взгляд на свой код • Let it fail (hoptoad в помощь)

Notas del editor

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n