Ruby, Rails и BDD

Владимир Мельник
#kranonit S15 2013
Who am I?
Мельник Владимир
aka egoholic | egotraumatic | rubydev

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

● Расскажу что такое Ruby и почему Ruby’истам
больше дают.
● Расскажу что такое Rails и почему все его хотят.
● Расскажу что такое BDD, как BDD связан с BDSM.
Что такое Ruby?
● Объектная-ориентированность
● Выразительность и минимализм
● Динамичность и Динамическая типизация
● Широкие возможности метапрограммирования
● Развитая инфраструктура
Бла-бла-бла...
Немного истории
Юкихиро Мацумото
(Yukihiro Matsumoto) aka Matz
Юкихиро Мацумото
(Yukihiro Matsumoto) aka Matz
Основной принцип
Концентрация не на машине, но на
программисте, его продуктивности и
удовольствии от работы.
Объектная ориентированность
● Практически все есть объект.
● Нет примитивов.
1.class #=> Fixnum
3.14.class #=> Float
'string'.class #=> String
/AregexpZ/.class #=> Regexp
:symbol.class #=> Symbol
[1, 2, 3].class #=> Array
{'a' => 1, 2 => 'ololo'}.class #=> Hash
{a: 1, b: 2, c: 3}.class #=> Hash
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
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
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
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'
Множественное наследование
● Его нет
● … но оно есть
● mixins (примеси) реализуются через
модули
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
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
Выразительность и минимализм
● блоки кода,
● каждое выражение возвращает значение,
● итераторы, итераторы, итераторы
● удобные условные операторы,
● интерполяция строк,
● много сахара.
Блоки кода
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
Итераторы
[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
Динамичность и метапрограммирование
● Возможность определять и переопределять методы
и классы во время исполнения.
● Возможность перехватывать и обрабатывать
NoMethodError.
●

eval, class_eval, instance_eval, module_eval
Развитая архитектура
● Огромное количество библиотек (Gem’ов),
фреймворков и приложений.
● Централизованное хранилище gem’ов (RubyGems.
org)
● Удубный менеджер гемов (RubyGems)
● Удобный менеджер зависимостей (Bundler)
Недостатки Ruby
● Отсутствие параллельного выполнения кода в MRI
(из-за GIL).
● Сложность разработки многопоточных приложений.
● Относительно низкая производительность.
● Нет проверки типов аргументов методов и
возвращаемого значение.
● Динамичностью и метапрограмированием можно
отстрелить сразу обе ноги.
Где использутся?
● Везде
● Серьезно, везде. (NASA, Google, Github, Twitter,
LivingSocial, Basecamp, Groupon, ...)
● В основном для web
● И еще в отличных инструментах для разработчиков
и не только (Vagrant, Chef, Metasploit, Capistrano, ...)
Веб фреймворк Rails
Немного истории
Фреймворк впервые увидел свет в
2004 году.
Изначально разрабатывался
Девидом Хейнемеером Хенсоном
(David Heinemeier Hansson) aka
DHH.
Текущая версия - 4.0.
Задачи веб фреймворков
● Избавить разработчика от рутины,
● навязать архитектурные решения и соглашения,
которые авторам фреймворка кажутся верными,
● обеспечить безопасности веб приложения.
● Что-то еще?
Что есть у Rails?
● Один из самых развитых и прагматичных веб
фреймворков.
● Архитектурный паттерн MVC (Model - View Controller).
● Принцип CoC (Convention over Configuration)
● Принцип DRY (Don’t repeat yourself!)
● Один из самых безопасных веб фреймворков.
● RESTfull архитектура
MVC
Model - работа с данными,
бизнес логика.
View - логика
представления и HTML код.
Controller - обработка
запроса.
MVC - это не архитектура проекта!
● MVC - это частный случай применения принципа
SRP на высоком уровне.
● MVC позволяет сделать код проще в поддержке.
● MVC - это одно из соглашений в Rails.
Структура приложения
$ rails new my_app создает приложение MyApp.
my_app/
app/
config/
db/
lib/
log/
public/
vendor/
app/ - основное место работы
app/
assets/
controllers/
helpers/
mailers/
models/
views/

- stylesheets, javascripts, images
- контроллеры
- вспомогательный код
- генераторы писем
- модели
- макеты, шаблоны, паршиалы
Пример моделей
# 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
Пример контроллера
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
Пример вьюшки (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
Сгенерированный 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>
Мягкое введение в TDD/BDD

Behavior-Driven Development kinkier than Test-Driven
Development
RED, GREEN, REFACTOR
RED, GREEN, REFACTOR
“BDD - как BDSM, либо ты
подчиняешь, либо подчиняешься.”
(c) Владимир Мельник
Breaking News: Единственный
достоверный тест на определение
сексуальных предпочтений!
Вы используете TDD или BDD?

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

TDD

BDD
TDD

BDD

● Пишем тесты,
которые “фейлятся”.

● Пишем тесты,
которые “фейлятся”.

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

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

● Рефакторим код.

● Рефакторим код.
И в чем же разница?
TDD

BDD

● Пишем тесты,
который “фейлятся”.

● Описываем
поведение системы.

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

● Пишем код
реализующий
описанное
поведение.

● Рефакторим код.
● Рефакторим код.
BDD - это правильный TDD

● Немного другая философия.
● Другой язык.
● Больше информации.
Философия BDD
● Важно то, как система ведет себя, а не то, как
реализована функциональность.
● Проектирование в момент написания спецификаций.
● Спецификации служат документацией по коду
проекта.
● Тестирование предоставляет максимум
информации о “красных” тестах.
“Правильный программный код легко тестируемый код.”
(с) Владимир Мельник
Off topic:

“Отличный способ показаться
высокомерным и настроить против себя
людей - цитировать самого себя.”
(c) Владимир Мельник
Инструментарий TDD/BDD
для Ruby / Rails
Инструментарий TDD/BDD для
Ruby / Rails
● Test::Unit - TDD (поставляется с Ruby StdLib)
● MiniTest - TDD/BDD (поставляется с Ruby 1.9 StdLib)
● RSpec - BDD
● Cucumber - BDD
… over 9000 прочих библиотек (gem’ов)
Давайте напишем программу на
Ruby которая считает сумму
выплат по кредиту!
Ууу! На Ruby?
RED
Пишем спецификации используя
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
example а не test
Описываем сценарий использования.

CreditCalc
.calc
when amount of credit = 0
returns 0

“Когда сумма кредита равна 0, калькулятор должен
вернуть 0.”
GREEN
Когда “фичи” реализованы и
“баги” исправлены.
REFACTOR
А необходим ли рефакторинг?
● Деньги платят не за рефакторинг, но за решение
задач.
● Без рефакторинга растет технический долг.
Как правильно рефакторить?

● Мелкими шагами.
● Во время решения задачи.
● Только тот код, который касается задачи.
● Рефакторить только покрытый тестами код.
Плюсы такого подхода
● Никаких специальных задач и затраты времени на
переключение.
● Заказчик видит в списке задач только ценные
тикеты.
● Технический долг постепенно минимизируется.
● Никаких “Потом”
● Никаких авралов*
*почти правда
На самом деле я вас немного
обманул!
Дело здесь в “двустороннем” тестировании.
TDD / BDD в Ruby on Rails
Зоопарк технологий
●

guard - обработчик событий FS

●

spork / spring - прелодеры Rails приложения.

●

rspec-rails - TDD/BDD фреймворк

●

factory_girl_rails - фабрики объектов на замену фикстурам

●

database_cleaner - очистка тестовой БД

●

shoulda_matchers - специальные матчеры для Rails

●

timecop - mock для даты и времени

●

capybara - симуляция поведения пользователя

●

cucumber - BDD фреймворк (не использую)
Немного о Cucumber (огурце)
● Много од
● Мало кто использует
● Очень медленный
● Много писанины
Никакой “силы земли” в огурце нет!
Разработка приложения на Rails с нуля
● Настраиваем тестовое окружение.
● Описываем поведение используя RSpec.
● Пишем код.
● Повторяем N раз.
configure_test_environment!
while food.present? do
write_specs!
write_code! refactoring: true, bugs: false
end
Советы
● Переходите на BDD.
● Красивые спеки - красивый код.
● Быстрые тесты - хорошие тесты.
● Mocking для внешних сервисов.
● Mocking / Stubbing хороши, но в меру.
● Важно не количество спеков / тестов, а покрытие.
Спасибо за внимание.
Вопросы?
Мои контакты
● Блог: http://rubydev.ru
● Тусовка Ruby’стов: http://vk.com/rubydevclub
● Я во Вконтакте: http://vk.com/rubydev_ru
● Имэил: egotraumatic@gmail.com
● Twitter: @egotraumatic
● Skype: rubydev.ru
Читайте, пишите, спрашивайте
Именно в таком порядке!

kranonit S15 Vladimir Melnik - Ruby on Rails, BDD

  • 1.
    Ruby, Rails иBDD Владимир Мельник #kranonit S15 2013
  • 2.
  • 3.
    Мельник Владимир aka egoholic| egotraumatic | rubydev Веб разработчик, автор блога RubyDev.ru 2 года опыта коммерческой разработки на Ruby и Rails Работал в: egotraumatic@gmail.com http://rubydev.ru @egotraumatic
  • 4.
    Что я сегоднярасскажу? ● Расскажу что такое Ruby и почему Ruby’истам больше дают. ● Расскажу что такое Rails и почему все его хотят. ● Расскажу что такое BDD, как BDD связан с BDSM.
  • 5.
  • 6.
    ● Объектная-ориентированность ● Выразительностьи минимализм ● Динамичность и Динамическая типизация ● Широкие возможности метапрограммирования ● Развитая инфраструктура
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
    Основной принцип Концентрация нена машине, но на программисте, его продуктивности и удовольствии от работы.
  • 12.
    Объектная ориентированность ● Практическивсе есть объект. ● Нет примитивов. 1.class #=> Fixnum 3.14.class #=> Float 'string'.class #=> String /AregexpZ/.class #=> Regexp :symbol.class #=> Symbol [1, 2, 3].class #=> Array {'a' => 1, 2 => 'ololo'}.class #=> Hash {a: 1, b: 2, c: 3}.class #=> Hash
  • 13.
    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
  • 14.
    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
  • 15.
    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
  • 16.
    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'
  • 18.
  • 19.
    ● Его нет ●… но оно есть ● mixins (примеси) реализуются через модули
  • 20.
    module Singleton def self.extended(klass) klass.class_evaldo 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
  • 21.
    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
  • 22.
    Выразительность и минимализм ●блоки кода, ● каждое выражение возвращает значение, ● итераторы, итераторы, итераторы ● удобные условные операторы, ● интерполяция строк, ● много сахара.
  • 23.
    Блоки кода 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
  • 24.
    Итераторы [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
  • 25.
    Динамичность и метапрограммирование ●Возможность определять и переопределять методы и классы во время исполнения. ● Возможность перехватывать и обрабатывать NoMethodError. ● eval, class_eval, instance_eval, module_eval
  • 26.
    Развитая архитектура ● Огромноеколичество библиотек (Gem’ов), фреймворков и приложений. ● Централизованное хранилище gem’ов (RubyGems. org) ● Удубный менеджер гемов (RubyGems) ● Удобный менеджер зависимостей (Bundler)
  • 29.
    Недостатки Ruby ● Отсутствиепараллельного выполнения кода в MRI (из-за GIL). ● Сложность разработки многопоточных приложений. ● Относительно низкая производительность. ● Нет проверки типов аргументов методов и возвращаемого значение. ● Динамичностью и метапрограмированием можно отстрелить сразу обе ноги.
  • 30.
    Где использутся? ● Везде ●Серьезно, везде. (NASA, Google, Github, Twitter, LivingSocial, Basecamp, Groupon, ...) ● В основном для web ● И еще в отличных инструментах для разработчиков и не только (Vagrant, Chef, Metasploit, Capistrano, ...)
  • 31.
  • 32.
    Немного истории Фреймворк впервыеувидел свет в 2004 году. Изначально разрабатывался Девидом Хейнемеером Хенсоном (David Heinemeier Hansson) aka DHH. Текущая версия - 4.0.
  • 33.
    Задачи веб фреймворков ●Избавить разработчика от рутины, ● навязать архитектурные решения и соглашения, которые авторам фреймворка кажутся верными, ● обеспечить безопасности веб приложения. ● Что-то еще?
  • 34.
    Что есть уRails? ● Один из самых развитых и прагматичных веб фреймворков. ● Архитектурный паттерн MVC (Model - View Controller). ● Принцип CoC (Convention over Configuration) ● Принцип DRY (Don’t repeat yourself!) ● Один из самых безопасных веб фреймворков. ● RESTfull архитектура
  • 35.
    MVC Model - работас данными, бизнес логика. View - логика представления и HTML код. Controller - обработка запроса.
  • 36.
    MVC - этоне архитектура проекта! ● MVC - это частный случай применения принципа SRP на высоком уровне. ● MVC позволяет сделать код проще в поддержке. ● MVC - это одно из соглашений в Rails.
  • 37.
    Структура приложения $ railsnew my_app создает приложение MyApp. my_app/ app/ config/ db/ lib/ log/ public/ vendor/
  • 38.
    app/ - основноеместо работы app/ assets/ controllers/ helpers/ mailers/ models/ views/ - stylesheets, javascripts, images - контроллеры - вспомогательный код - генераторы писем - модели - макеты, шаблоны, паршиалы
  • 39.
    Пример моделей # app/models/user.rb classUser < 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
  • 40.
    Пример контроллера 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
  • 41.
    Пример вьюшки (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
  • 42.
    Сгенерированный HTML <div id="articles"> <divclass="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>
  • 43.
    Мягкое введение вTDD/BDD Behavior-Driven Development kinkier than Test-Driven Development
  • 44.
  • 45.
  • 46.
    “BDD - какBDSM, либо ты подчиняешь, либо подчиняешься.” (c) Владимир Мельник
  • 47.
    Breaking News: Единственный достоверныйтест на определение сексуальных предпочтений!
  • 48.
    Вы используете TDDили BDD? а. Да б. Нет
  • 49.
    ● TDD/BDD позволяютподчинить код, ● Их отсутствие подчиняет разработчика коду.
  • 50.
  • 51.
    TDD BDD ● Пишем тесты, которые“фейлятся”. ● Пишем тесты, которые “фейлятся”. ● Пишем код, который делает тесты “зелеными”. ● Пишем код, который делает тесты “зелеными”. ● Рефакторим код. ● Рефакторим код.
  • 52.
    И в чемже разница?
  • 53.
    TDD BDD ● Пишем тесты, который“фейлятся”. ● Описываем поведение системы. ● Пишем код, который делает тесты “зелеными”. ● Пишем код реализующий описанное поведение. ● Рефакторим код. ● Рефакторим код.
  • 54.
    BDD - этоправильный TDD ● Немного другая философия. ● Другой язык. ● Больше информации.
  • 55.
    Философия BDD ● Важното, как система ведет себя, а не то, как реализована функциональность. ● Проектирование в момент написания спецификаций. ● Спецификации служат документацией по коду проекта. ● Тестирование предоставляет максимум информации о “красных” тестах.
  • 56.
    “Правильный программный кодлегко тестируемый код.” (с) Владимир Мельник
  • 57.
    Off topic: “Отличный способпоказаться высокомерным и настроить против себя людей - цитировать самого себя.” (c) Владимир Мельник
  • 58.
  • 59.
    Инструментарий TDD/BDD для Ruby/ Rails ● Test::Unit - TDD (поставляется с Ruby StdLib) ● MiniTest - TDD/BDD (поставляется с Ruby 1.9 StdLib) ● RSpec - BDD ● Cucumber - BDD … over 9000 прочих библиотек (gem’ов)
  • 60.
    Давайте напишем программуна Ruby которая считает сумму выплат по кредиту!
  • 61.
  • 62.
  • 63.
    Пишем спецификации используя RSpec describeCreditCalc 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
  • 64.
    example а неtest Описываем сценарий использования. CreditCalc .calc when amount of credit = 0 returns 0 “Когда сумма кредита равна 0, калькулятор должен вернуть 0.”
  • 66.
  • 67.
    Когда “фичи” реализованыи “баги” исправлены.
  • 69.
  • 70.
    А необходим лирефакторинг? ● Деньги платят не за рефакторинг, но за решение задач. ● Без рефакторинга растет технический долг.
  • 71.
    Как правильно рефакторить? ●Мелкими шагами. ● Во время решения задачи. ● Только тот код, который касается задачи. ● Рефакторить только покрытый тестами код.
  • 72.
    Плюсы такого подхода ●Никаких специальных задач и затраты времени на переключение. ● Заказчик видит в списке задач только ценные тикеты. ● Технический долг постепенно минимизируется. ● Никаких “Потом” ● Никаких авралов* *почти правда
  • 73.
    На самом делея вас немного обманул! Дело здесь в “двустороннем” тестировании.
  • 74.
    TDD / BDDв Ruby on Rails
  • 75.
  • 76.
    ● guard - обработчиксобытий FS ● spork / spring - прелодеры Rails приложения. ● rspec-rails - TDD/BDD фреймворк ● factory_girl_rails - фабрики объектов на замену фикстурам ● database_cleaner - очистка тестовой БД ● shoulda_matchers - специальные матчеры для Rails ● timecop - mock для даты и времени ● capybara - симуляция поведения пользователя ● cucumber - BDD фреймворк (не использую)
  • 77.
    Немного о Cucumber(огурце) ● Много од ● Мало кто использует ● Очень медленный ● Много писанины
  • 78.
  • 79.
    Разработка приложения наRails с нуля ● Настраиваем тестовое окружение. ● Описываем поведение используя RSpec. ● Пишем код. ● Повторяем N раз.
  • 80.
  • 81.
    Советы ● Переходите наBDD. ● Красивые спеки - красивый код. ● Быстрые тесты - хорошие тесты. ● Mocking для внешних сервисов. ● Mocking / Stubbing хороши, но в меру. ● Важно не количество спеков / тестов, а покрытие.
  • 82.
  • 83.
  • 84.
    Мои контакты ● Блог:http://rubydev.ru ● Тусовка Ruby’стов: http://vk.com/rubydevclub ● Я во Вконтакте: http://vk.com/rubydev_ru ● Имэил: egotraumatic@gmail.com ● Twitter: @egotraumatic ● Skype: rubydev.ru
  • 85.