Upgrade to Pro — share decks privately, control downloads, hide ads and more …

kranonit_S15E01_Ruby_Rails_BDD.pdf

 kranonit_S15E01_Ruby_Rails_BDD.pdf

Introduction to Ruby/Rails/BDD

Volodymyr Melnyk

October 19, 2013
Tweet

More Decks by Volodymyr Melnyk

Other Decks in Programming

Transcript

  1. Мельник Владимир aka egoholic | egotraumatic | rubydev Веб разработчик,

    автор блога RubyDev.ru 2 года опыта коммерческой разработки на Ruby и Rails Работал в: [email protected] http://rubydev.ru @egotraumatic
  2. Что я сегодня расскажу? • Расскажу что такое Ruby и

    почему Ruby’истам больше дают. • Расскажу что такое Rails и почему все его хотят. • Расскажу что такое BDD, как BDD связан с BDSM.
  3. • Объектная-ориентированность • Выразительность и минимализм • Динамичность и Динамическая

    типизация • Широкие возможности метапрограммирования • Развитая инфраструктура
  4. Объектная ориентированность • Практически все есть объект. • Нет примитивов.

    1.class #=> Fixnum 3.14.class #=> Float 'string'.class #=> String /\Aregexp\Z/.class #=> Regexp :symbol.class #=> Symbol [1, 2, 3].class #=> Array {'a' => 1, 2 => 'ololo'}.class #=> Hash {a: 1, b: 2, c: 3}.class #=> Hash
  5. class Integer def leap_year? (self % 4 == 0 &&

    self % 100 != 0) || self % 400 == 0 end def year days = 0 current_year = Time.now.year self.times do |n| days += (current_year + n + 1).leap_year? ? 366 : 365 end return 3600 * 24 * days end alias years year end
  6. 2013.leap_year? #=> false 5.years #=> 157766400 Time.now #=> 2013-10-08 16:03:20

    +0300 Time.now.class #=> Time Time.now + 10.years #=> 2023-10-08 16:03:29 +0300
  7. class User def initialize(name, last_name, email) @name = name @last_name

    = last_name @email = email end end user = User.new('Bill', 'Clinton', '[email protected]') user.class #=> User user.name # raises NoMethodError
  8. class President < User attr_reader :name, :last_name, :email, :elected_at, :on_period

    def initialize(name, last_name, email, elected_at, on_period) super(name, last_name, email) @elected_at = elected_at @on_period = on_period end end President.ancestors #=> [President, User, Object, Kernel, BasicObject] president = President.new('Bill', 'Clinton', '[email protected]', Time.new(1993, 1, 20), 4.years) president.name #=> 'Bill'
  9. • Его нет • … но оно есть • mixins

    (примеси) реализуются через модули
  10. module Singleton def self.extended(klass) klass.class_eval do extend ClassMethods include InstanceMethods

    end end module ClassMethods def new(*args) @instance = super(*args) unless @instance return @instance end end module InstanceMethods def singleton?; true end end end
  11. class User def initialize(name, last_name) @name = name @last_name =

    last_name end end User.new('Bill', 'Clinton').object_id #=> 7939460 User.new('Bill', 'Clinton').object_id #=> 7874780 User.extend Singleton User.new('Bill', 'Clinton').object_id #=> 7767300 User.new('Bill', 'Clinton').object_id #=> 7767300
  12. Выразительность и минимализм • блоки кода, • каждое выражение возвращает

    значение, • итераторы, итераторы, итераторы • удобные условные операторы, • интерполяция строк, • много сахара.
  13. Блоки кода def do_something; yield 100 end def do_something(&block); block.call

    100 end def do_somethind # Проверка наличия блока yield 100 if block_given? end do_something { |n| n.to_s(2) } #=> "1100100" do_something do |n| n ** 2 end #=> 10000
  14. Итераторы [1, 2, 3, 4, 5].inject(0) { |sum, n| sum

    += n } #=> 15 [1, 2, 3, 4, 5].select { |n| n % 2 == 0 } #=> [2, 4] {a: 1, b: 2}.each { |k, v| puts "#{k} -> #{v}" } # a -> 1 # b -> 2 3.times { |t| puts t } # 0 # 1 # 2 [2, 4, 6].all? { |n| n.even? } #=> true
  15. Динамичность и метапрограммирование • Возможность определять и переопределять методы и

    классы во время исполнения. • Возможность перехватывать и обрабатывать NoMethodError. • eval, class_eval, instance_eval, module_eval
  16. Развитая архитектура • Огромное количество библиотек (Gem’ов), фреймворков и приложений.

    • Централизованное хранилище gem’ов (RubyGems. org) • Удубный менеджер гемов (RubyGems) • Удобный менеджер зависимостей (Bundler)
  17. Недостатки Ruby • Отсутствие параллельного выполнения кода в MRI (из-за

    GIL). • Сложность разработки многопоточных приложений. • Относительно низкая производительность. • Нет проверки типов аргументов методов и возвращаемого значение. • Динамичностью и метапрограмированием можно отстрелить сразу обе ноги.
  18. Где использутся? • Везде • Серьезно, везде. (NASA, Google, Github,

    Twitter, LivingSocial, Basecamp, Groupon, ...) • В основном для web • И еще в отличных инструментах для разработчиков и не только (Vagrant, Chef, Metasploit, Capistrano, ...)
  19. Немного истории Фреймворк впервые увидел свет в 2004 году. Изначально

    разрабатывался Девидом Хейнемеером Хенсоном (David Heinemeier Hansson) aka DHH. Текущая версия - 4.0.
  20. Задачи веб фреймворков • Избавить разработчика от рутины, • навязать

    архитектурные решения и соглашения, которые авторам фреймворка кажутся верными, • обеспечить безопасности веб приложения. • Что-то еще?
  21. Что есть у Rails? • Один из самых развитых и

    прагматичных веб фреймворков. • Архитектурный паттерн MVC (Model - View - Controller). • Принцип CoC (Convention over Configuration) • Принцип DRY (Don’t repeat yourself!) • Один из самых безопасных веб фреймворков. • RESTfull архитектура
  22. MVC Model - работа с данными, бизнес логика. View -

    логика представления и HTML код. Controller - обработка запроса.
  23. MVC - это не архитектура проекта! • MVC - это

    частный случай применения принципа SRP на высоком уровне. • MVC позволяет сделать код проще в поддержке. • MVC - это одно из соглашений в Rails.
  24. app/ - основное место работы app/ assets/ - stylesheets, javascripts,

    images controllers/ - контроллеры helpers/ - вспомогательный код mailers/ - генераторы писем models/ - модели views/ - макеты, шаблоны, паршиалы
  25. Пример моделей # app/models/user.rb class User < ActiveRecord::Base has_many :articles,

    foreign_key: :author_id has_many :comments, foreign_key: :commenter_id end # app/models/article.rb class Article < ActiveRecord::Base belongs_to :author, class_name: 'User' has_many :comments, as: :commentable, dependent: :destroy end # app/models/comment.rb class Comment < ActiveRecord::Base belongs_to :commenter, class_name: 'User' belongs_to :commentable, polymorphic: true end
  26. Пример контроллера class ApplicationController < ActionController::Base protect_from_forgery with: :exception end

    class ArticlesController < ApplicationController # http://localhost:3000/articles def index @articles = Article.order('published_at DESC') .includes(:author) end # http://localhost:3000/articles/:id def show @article = Article.find(params[:id]) @comments = @article.comments end end
  27. Пример вьюшки (HAML) #articles - @articles.each do |article| .article{id: "article_#{article.id}"}

    .a-title= article.title .a-published_at= article.published_at .a-content= article.content .a-author authored by: link_to article.author.name, article.author
  28. Сгенерированный HTML <div id="articles"> <div class="article" id="article_2"> <div class="a-title">Article 2

    Title</div> <div class="a-published-at">2013-09-28</div> <div class="a-content">Article 2 Content</div> <div class="a-author"> authored by: <a href="/users/1">Bill Clinton</a> </div> </div> <div class="article", id="article_1"> <!-- ... --> </div> </div>
  29. TDD • Пишем тесты, которые “фейлятся”. • Пишем код, который

    делает тесты “зелеными”. • Рефакторим код. BDD • Пишем тесты, которые “фейлятся”. • Пишем код, который делает тесты “зелеными”. • Рефакторим код.
  30. TDD • Пишем тесты, который “фейлятся”. • Пишем код, который

    делает тесты “зелеными”. • Рефакторим код. BDD • Описываем поведение системы. • Пишем код реализующий описанное поведение. • Рефакторим код.
  31. BDD - это правильный TDD • Немного другая философия. •

    Другой язык. • Больше информации.
  32. Философия BDD • Важно то, как система ведет себя, а

    не то, как реализована функциональность. • Проектирование в момент написания спецификаций. • Спецификации служат документацией по коду проекта. • Тестирование предоставляет максимум информации о “красных” тестах.
  33. Off topic: “Отличный способ показаться высокомерным и настроить против себя

    людей - цитировать самого себя.” (c) Владимир Мельник
  34. • Test::Unit - TDD (поставляется с Ruby StdLib) • MiniTest

    - TDD/BDD (поставляется с Ruby 1.9 StdLib) • RSpec - BDD • Cucumber - BDD … over 9000 прочих библиотек (gem’ов) Инструментарий TDD/BDD для Ruby / Rails
  35. RED

  36. Пишем спецификации используя RSpec describe CreditCalc do describe '.calc' do

    context 'when amount = 0' do let :args do {amount: 0, percent: 22, period: 10} end it ‘returns 0’ do expect(described_class.calc(args)).to be_zero end end #... #... end
  37. CreditCalc .calc when amount of credit = 0 returns 0

    example а не test Описываем сценарий использования. “Когда сумма кредита равна 0, калькулятор должен вернуть 0.”
  38. А необходим ли рефакторинг? • Деньги платят не за рефакторинг,

    но за решение задач. • Без рефакторинга растет технический долг.
  39. Как правильно рефакторить? • Мелкими шагами. • Во время решения

    задачи. • Только тот код, который касается задачи. • Рефакторить только покрытый тестами код.
  40. Плюсы такого подхода • Никаких специальных задач и затраты времени

    на переключение. • Заказчик видит в списке задач только ценные тикеты. • Технический долг постепенно минимизируется. • Никаких “Потом” • Никаких авралов* *почти правда
  41. На самом деле я вас немного обманул! Дело здесь в

    “двустороннем” тестировании.
  42. • guard - обработчик событий FS • spork / spring

    - прелодеры Rails приложения. • rspec-rails - TDD/BDD фреймворк • factory_girl_rails - фабрики объектов на замену фикстурам • database_cleaner - очистка тестовой БД • shoulda_matchers - специальные матчеры для Rails • timecop - mock для даты и времени • capybara - симуляция поведения пользователя • cucumber - BDD фреймворк (не использую)
  43. Немного о Cucumber (огурце) • Много од • Мало кто

    использует • Очень медленный • Много писанины
  44. Разработка приложения на Rails с нуля • Настраиваем тестовое окружение.

    • Описываем поведение используя RSpec. • Пишем код. • Повторяем N раз.
  45. Советы • Переходите на BDD. • Красивые спеки - красивый

    код. • Быстрые тесты - хорошие тесты. • Mocking для внешних сервисов. • Mocking / Stubbing хороши, но в меру. • Важно не количество спеков / тестов, а покрытие.
  46. Мои контакты • Блог: http://rubydev.ru • Тусовка Ruby’стов: http://vk.com/rubydevclub •

    Я во Вконтакте: http://vk.com/rubydev_ru • Имэил: [email protected] • Twitter: @egotraumatic • Skype: rubydev.ru