Беспокойный код
    @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 в помощь)

More Related Content

PPTX
Иван Стеценко: ЯП Zephir. Панацея или лечение?
PPTX
Эффективный C++
ODP
Intelligent или сделай мне красиво
PDF
Михаил Давыдов: JavaScript. Базовые знания
PPTX
Универсальный сигнатурный анализ кода на C#, Java, PHP
PPS
Revolto de contos
PDF
PRA tools for khuyennong36.com
PPTX
Eyjafjallajökull
Иван Стеценко: ЯП Zephir. Панацея или лечение?
Эффективный C++
Intelligent или сделай мне красиво
Михаил Давыдов: JavaScript. Базовые знания
Универсальный сигнатурный анализ кода на C#, Java, PHP
Revolto de contos
PRA tools for khuyennong36.com
Eyjafjallajökull

Viewers also liked (20)

PPT
шоколад и дерево
PPT
حل معادلة باكمال مربع
PPT
Trabajo de photo filtre nº 2
PPTX
El inicio de la independencia-1
PPTX
Picnic for 24contest2 @ Cookpad
PDF
PPTX
1 číslo tsl
PDF
TIM KHOẺ VỚI DẦU OLIVE TINH KHIẾT - VUI TRẺ KHỎE.COM
PPTX
Usa経済指標0518
DOCX
中国网上零售商城品牌50强
PDF
Cirsoc 105
PDF
Termodinamika2
PDF
Praia Abrigo
PPTX
Rinnovo automatico
PPT
华惹》时代风云新书推介礼
ODP
Power derivades 2
ODS
цахим тестэ
PDF
Bertrand Russell
PDF
PDF
韓国の社会的企業から学ぶ 雇用開発のあり方
шоколад и дерево
حل معادلة باكمال مربع
Trabajo de photo filtre nº 2
El inicio de la independencia-1
Picnic for 24contest2 @ Cookpad
1 číslo tsl
TIM KHOẺ VỚI DẦU OLIVE TINH KHIẾT - VUI TRẺ KHỎE.COM
Usa経済指標0518
中国网上零售商城品牌50强
Cirsoc 105
Termodinamika2
Praia Abrigo
Rinnovo automatico
华惹》时代风云新书推介礼
Power derivades 2
цахим тестэ
Bertrand Russell
韓国の社会的企業から学ぶ 雇用開発のあり方
Ad

Similar to Worried code (20)

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

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 в помощь)

Editor's Notes