Slide 1

Slide 1 text

Ruby, Rails и BDD Владимир Мельник #kranonit S15 2013

Slide 2

Slide 2 text

Who am I?

Slide 3

Slide 3 text

Мельник Владимир aka egoholic | egotraumatic | rubydev Веб разработчик, автор блога RubyDev.ru 2 года опыта коммерческой разработки на Ruby и Rails Работал в: egotraumatic@gmail.com http://rubydev.ru @egotraumatic

Slide 4

Slide 4 text

Что я сегодня расскажу? ● Расскажу что такое Ruby и почему Ruby’истам больше дают. ● Расскажу что такое Rails и почему все его хотят. ● Расскажу что такое BDD, как BDD связан с BDSM.

Slide 5

Slide 5 text

Что такое Ruby?

Slide 6

Slide 6 text

● Объектная-ориентированность ● Выразительность и минимализм ● Динамичность и Динамическая типизация ● Широкие возможности метапрограммирования ● Развитая инфраструктура

Slide 7

Slide 7 text

Бла-бла-бла...

Slide 8

Slide 8 text

Немного истории

Slide 9

Slide 9 text

Юкихиро Мацумото (Yukihiro Matsumoto) aka Matz

Slide 10

Slide 10 text

Юкихиро Мацумото (Yukihiro Matsumoto) aka Matz

Slide 11

Slide 11 text

Основной принцип Концентрация не на машине, но на программисте, его продуктивности и удовольствии от работы.

Slide 12

Slide 12 text

Объектная ориентированность ● Практически все есть объект. ● Нет примитивов. 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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

class User def initialize(name, last_name, email) @name = name @last_name = last_name @email = email end end user = User.new('Bill', 'Clinton', 'bclinton@whitehouse.gov') user.class #=> User user.name # raises NoMethodError

Slide 16

Slide 16 text

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', 'bclinton@whitehouse.gov', Time.new(1993, 1, 20), 4.years) president.name #=> 'Bill'

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

Множественное наследование

Slide 19

Slide 19 text

● Его нет ● … но оно есть ● mixins (примеси) реализуются через модули

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

Выразительность и минимализм ● блоки кода, ● каждое выражение возвращает значение, ● итераторы, итераторы, итераторы ● удобные условные операторы, ● интерполяция строк, ● много сахара.

Slide 23

Slide 23 text

Блоки кода 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

Slide 24

Slide 24 text

Итераторы [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

Slide 25

Slide 25 text

Динамичность и метапрограммирование ● Возможность определять и переопределять методы и классы во время исполнения. ● Возможность перехватывать и обрабатывать NoMethodError. ● eval, class_eval, instance_eval, module_eval

Slide 26

Slide 26 text

Развитая архитектура ● Огромное количество библиотек (Gem’ов), фреймворков и приложений. ● Централизованное хранилище gem’ов (RubyGems. org) ● Удубный менеджер гемов (RubyGems) ● Удобный менеджер зависимостей (Bundler)

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

Недостатки Ruby ● Отсутствие параллельного выполнения кода в MRI (из-за GIL). ● Сложность разработки многопоточных приложений. ● Относительно низкая производительность. ● Нет проверки типов аргументов методов и возвращаемого значение. ● Динамичностью и метапрограмированием можно отстрелить сразу обе ноги.

Slide 30

Slide 30 text

Где использутся? ● Везде ● Серьезно, везде. (NASA, Google, Github, Twitter, LivingSocial, Basecamp, Groupon, ...) ● В основном для web ● И еще в отличных инструментах для разработчиков и не только (Vagrant, Chef, Metasploit, Capistrano, ...)

Slide 31

Slide 31 text

Веб фреймворк Rails

Slide 32

Slide 32 text

Немного истории Фреймворк впервые увидел свет в 2004 году. Изначально разрабатывался Девидом Хейнемеером Хенсоном (David Heinemeier Hansson) aka DHH. Текущая версия - 4.0.

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

MVC Model - работа с данными, бизнес логика. View - логика представления и HTML код. Controller - обработка запроса.

Slide 36

Slide 36 text

MVC - это не архитектура проекта! ● MVC - это частный случай применения принципа SRP на высоком уровне. ● MVC позволяет сделать код проще в поддержке. ● MVC - это одно из соглашений в Rails.

Slide 37

Slide 37 text

Структура приложения $ rails new my_app создает приложение MyApp. my_app/ app/ config/ db/ lib/ log/ public/ vendor/

Slide 38

Slide 38 text

app/ - основное место работы app/ assets/ - stylesheets, javascripts, images controllers/ - контроллеры helpers/ - вспомогательный код mailers/ - генераторы писем models/ - модели views/ - макеты, шаблоны, паршиалы

Slide 39

Slide 39 text

Пример моделей # 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

Slide 40

Slide 40 text

Пример контроллера 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

Slide 41

Slide 41 text

Пример вьюшки (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

Slide 42

Slide 42 text

Сгенерированный HTML
Article 2 Title
2013-09-28
Article 2 Content
authored by: Bill Clinton

Slide 43

Slide 43 text

Мягкое введение в TDD/BDD Behavior-Driven Development kinkier than Test-Driven Development

Slide 44

Slide 44 text

RED, GREEN, REFACTOR

Slide 45

Slide 45 text

RED, GREEN, REFACTOR

Slide 46

Slide 46 text

“BDD - как BDSM, либо ты подчиняешь, либо подчиняешься.” (c) Владимир Мельник

Slide 47

Slide 47 text

Breaking News: Единственный достоверный тест на определение сексуальных предпочтений!

Slide 48

Slide 48 text

Вы используете TDD или BDD? а. Да б. Нет

Slide 49

Slide 49 text

● TDD/BDD позволяют подчинить код, ● Их отсутствие подчиняет разработчика коду.

Slide 50

Slide 50 text

Test-Driven vs Behavior-Driven TDD BDD

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

И в чем же разница?

Slide 53

Slide 53 text

TDD ● Пишем тесты, который “фейлятся”. ● Пишем код, который делает тесты “зелеными”. ● Рефакторим код. BDD ● Описываем поведение системы. ● Пишем код реализующий описанное поведение. ● Рефакторим код.

Slide 54

Slide 54 text

BDD - это правильный TDD ● Немного другая философия. ● Другой язык. ● Больше информации.

Slide 55

Slide 55 text

Философия BDD ● Важно то, как система ведет себя, а не то, как реализована функциональность. ● Проектирование в момент написания спецификаций. ● Спецификации служат документацией по коду проекта. ● Тестирование предоставляет максимум информации о “красных” тестах.

Slide 56

Slide 56 text

“Правильный программный код - легко тестируемый код.” (с) Владимир Мельник

Slide 57

Slide 57 text

Off topic: “Отличный способ показаться высокомерным и настроить против себя людей - цитировать самого себя.” (c) Владимир Мельник

Slide 58

Slide 58 text

Инструментарий TDD/BDD для Ruby / Rails

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

Давайте напишем программу на Ruby которая считает сумму выплат по кредиту!

Slide 61

Slide 61 text

Ууу! На Ruby?

Slide 62

Slide 62 text

RED

Slide 63

Slide 63 text

Пишем спецификации используя 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

Slide 64

Slide 64 text

CreditCalc .calc when amount of credit = 0 returns 0 example а не test Описываем сценарий использования. “Когда сумма кредита равна 0, калькулятор должен вернуть 0.”

Slide 65

Slide 65 text

No content

Slide 66

Slide 66 text

GREEN

Slide 67

Slide 67 text

Когда “фичи” реализованы и “баги” исправлены.

Slide 68

Slide 68 text

No content

Slide 69

Slide 69 text

REFACTOR

Slide 70

Slide 70 text

А необходим ли рефакторинг? ● Деньги платят не за рефакторинг, но за решение задач. ● Без рефакторинга растет технический долг.

Slide 71

Slide 71 text

Как правильно рефакторить? ● Мелкими шагами. ● Во время решения задачи. ● Только тот код, который касается задачи. ● Рефакторить только покрытый тестами код.

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

На самом деле я вас немного обманул! Дело здесь в “двустороннем” тестировании.

Slide 74

Slide 74 text

TDD / BDD в Ruby on Rails

Slide 75

Slide 75 text

Зоопарк технологий

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

Немного о Cucumber (огурце) ● Много од ● Мало кто использует ● Очень медленный ● Много писанины

Slide 78

Slide 78 text

Никакой “силы земли” в огурце нет!

Slide 79

Slide 79 text

Разработка приложения на Rails с нуля ● Настраиваем тестовое окружение. ● Описываем поведение используя RSpec. ● Пишем код. ● Повторяем N раз.

Slide 80

Slide 80 text

configure_test_environment! while food.present? do write_specs! write_code! refactoring: true, bugs: false end

Slide 81

Slide 81 text

Советы ● Переходите на BDD. ● Красивые спеки - красивый код. ● Быстрые тесты - хорошие тесты. ● Mocking для внешних сервисов. ● Mocking / Stubbing хороши, но в меру. ● Важно не количество спеков / тестов, а покрытие.

Slide 82

Slide 82 text

Спасибо за внимание.

Slide 83

Slide 83 text

Вопросы?

Slide 84

Slide 84 text

Мои контакты ● Блог: http://rubydev.ru ● Тусовка Ruby’стов: http://vk.com/rubydevclub ● Я во Вконтакте: http://vk.com/rubydev_ru ● Имэил: egotraumatic@gmail.com ● Twitter: @egotraumatic ● Skype: rubydev.ru

Slide 85

Slide 85 text

Читайте, пишите, спрашивайте Именно в таком порядке!