SlideShare une entreprise Scribd logo
1  sur  134
Ruby
Plus Rails
Plus Your Application
Minus Rails
Brian Guthrie
bguthrie@thoughtworks.com
http://twitter.com/bguthrie
The
Last
Ten
Percent
Brian Guthrie
bguthrie@thoughtworks.com
http://twitter.com/bguthrie
How to do complex things in Ruby
      (without shooting yourself in the foot)

                      2010
How to do simple things in Ruby
          (with care and craft)

                 2011
the last

10%
So what’s hard about this?
(Is it time to go check out the talk in the other room? That guy seems cool.)
Nothing!
Every good talk needs a rant
not complex
There’s an army of programmers
      looking for Rails bugs
Your code? Just you.
Craft is even more important.
not
cookie
cutter
Most Ruby programmers are Rails programmers first
Learning what Rails doesn’t do
is as important as learning what it does
For those craftspeople here:
        Thank you
Gaps in Rails:
Where’s the problem?
“
Prior to Rails 3.0, if a plugin or gem
developer wanted to have an object
interact with Action Pack helpers, it was
required to either copy chunks of code
from Rails, or monkey patch entire
helpers to make them handle objects that
did not exactly conform to the Active
Record interface. This would result in
code duplication and fragile applications
that broke on upgrades.
                  - ActiveModel README
Rails 2




Active      Active          Action          Action
Record     Resource         Mailer           Pack



      Active
                                     Railties
     Support
Presentation   Logic   Data
Presentation        Logic   Data


form_for @user do
Presentation                   Logic                 Data


form_for @user do   @user = User.find(params[:id])
Presentation                   Logic                 Data


form_for @user do   @user = User.find(params[:id])
Presentation                   Logic                 Data


form_for @user do   @user = User.find(params[:id])
Presentation                     Logic                    Data


form_for @user do     @user = User.find(params[:id])




                    @fb_user = FbUser.find(params[:id])
Presentation                       Logic                    Data


 form_for @user do       @user = User.find(params[:id])




form_for @fb_user do   @fb_user = FbUser.find(params[:id])
• Domain models that aren’t database tables
• Importing and transforming data
• Web service clients
• Presenter objects

         (not a comprehensive list)
Rails 2




Active      Active          Action          Action
Record     Resource         Mailer           Pack



      Active
                                     Railties
     Support
Rails 3


         Active
         Model
Active         Active          Action          Action
Record        Resource         Mailer           Pack



      Active
                                        Railties
     Support
Active
          gem 'active_model'
 Model




 Active   gem 'active_support',
Support     :require => false
the principles
   Simplicity
   Testability
   Abstractability
   Community
the principles
Code      Simplicity
          Testability
          Abstractability
          Community
S   Single responsibility principle
    An object should have only a single responsibility.



O   Open/closed principle
    Software entities … should be open for extension, but closed for modification.



L
    Liskov substitution principle
    Objects in a program should be replaceable with instances of their subtypes without altering
    the correctness of that program.



I   Dependency inversion principle
    Depend upon Abstractions. Do not depend upon concretions.



D   Interface segregation principle
    Many client specific interfaces are better than one general purpose interface.
S   Single responsibility principle
    An object should have only a single responsibility.



O   Open/closed principle
    Software entities … should be open for extension, but closed for modification.



L
    Liskov substitution principle
    Objects in a program should be replaceable with instances of their subtypes without altering
    the correctness of that program.



I   Dependency inversion principle
    Depend upon Abstractions. Do not depend upon concretions.



D   Interface segregation principle
    Many client specific interfaces are better than one general purpose interface.
SD Card Principles
S   Single responsibility principle
    An object should have only a single responsibility.



O   Open/closed principle
    Software entities … should be open for extension, but closed for modification.



L
    Liskov substitution principle
    Objects in a program should be replaceable with instances of their subtypes without altering
    the correctness of that program.



I   Dependency inversion principle
    Depend upon Abstractions. Do not depend upon concretions.



D   Interface segregation principle
    Many client specific interfaces are better than one general purpose interface.
S
     Single responsibility principle




     An object should have only a single responsibility.




O
              Open/closed principle




              Software entities … should be open for extension, but closed for modification.




L
       Liskov substitution principle




       Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.




 I
              Dependency inversion principle




              Depend upon Abstractions. Do not depend upon concretions.




D
           Interface segregation principle




           Many client specific interfaces are better than one general purpose interface.




Mini SD Card Principles
the principles
                  Simplicity
                  Testability
Architecture      Abstractability
                  Community
Idiomaticity
Idiom (plural idioms)
 1. A manner of speaking, a way of expressing oneself.
 2. An artistic style (for example, in art, architecture, or
    music); an instance of such a style.
 3. An expression peculiar to or characteristic of a
    particular language, especially when the meaning is
    illogical or separate from the meanings of its
    component words.
 4. (linguistics) A communicative system under study,
    which could be called either a dialect or a language,
    when its status as a language or dialect is irrelevant.
 5. (programming) A programming construct or
    phraseology generally held to be the most efficient,
    elegant or effective means to achieve a particular
    result or behavior.

              http://en.wiktionary.org/wiki/idiom
Idiomaticity
Idiom (plural idioms)
 1. A manner of speaking, a way of expressing oneself.
 2. An artistic style (for example, in art, architecture, or
    music); an instance of such a style.
 3. An expression peculiar to or characteristic of a
    particular language, especially when the meaning is
    illogical or separate from the meanings of its
    component words.
 4. (linguistics) A communicative system under study,
    which could be called either a dialect or a language,
    when its status as a language or dialect is irrelevant.
 5. (programming) A programming construct or
    phraseology generally held to be the most efficient,
    elegant or effective means to achieve a particular
    result or behavior.

              http://en.wiktionary.org/wiki/idiom
Some of the best Ruby programmers have
  gone against commonly-accepted style
Keep it simple when you can
Break the rules when you must
 (or when it sounds like fun)
The best* Ruby code is clean, simple, and follows
             community idioms.




                  * Easiest to maintain.
the recipe
Build an object
Test that object
Expose a familiar API
Mmm... Masala Ruby
the recipe
Build an object
Test that object
Expose a familiar API
Antipattern: Bad Modeling
Dosa Tracker
(I smell a startup opportunity)
CSV File
name,city,address,district,review,dosa types
Sukh Sagar,Chennai,2nd Ave,Anna Nagar,plain|paper|masala|mysore masala|rava
Sri Sai Sagar,Bangalore,"5th Cross, 18th Main Road, HAL 2nd
Stage",Indiranagar,plain|paper|masala|rava masala|mysore masala|coconut
Columns
name,city,address,district,review,dosa types
Sukh Sagar,Chennai,2nd Ave,Anna Nagar,plain|paper|masala|mysore masala|rava
Sri Sai Sagar,Bangalore,"5th Cross, 18th Main Road, HAL 2nd
Stage",Indiranagar,plain|paper|masala|rava masala|mysore masala|coconut
Data
name,city,address,district,review,dosa types
Sukh Sagar,Chennai,2nd Ave,Anna Nagar,plain|paper|masala|mysore masala|rava
Sri Sai Sagar,Bangalore,"5th Cross, 18th Main Road, HAL 2nd
Stage",Indiranagar,plain|paper|masala|rava masala|mysore masala|coconut
ETL
CSV
      (extract, transform, load)
Hand-written SQL




CSV
Slight improvement




                        CSV
CSV
                       Mapper


 module ABunchOfSuperAwesomeDataTransformationMethods

   def some_conversion_that_wont_make_sense_six_months_from_now(inputs)
   end

 end
Active
               Support




                CSV                   Active
CSV                                   Record
               Mapper


      module DosaTracker
        class DosaStandMapper

          def initialize(inputs={})
          end

          def to_model # Output
          end

        end
      end
module DosaTracker
  class DosaStandMapper

    def initialize(inputs={})
      @inputs = inputs
    end

    def location
      [ @inputs["city"], @inputs["address"], @inputs["landmark"] ].join(", ")
    end

  end
end
require 'spec_helper'

describe DosaTracker::DosaStandMapper do

  context "#location" do
    it "should include the city and address" do
      DosaTracker::DosaStandMapper.new(
        'city' => 'Chennai',
        'address' => '2nd Avenue, Anna Nagar'
      ).location.should match("Chennai, 2nd Avenue, Anna Nagar")
    end
  end

end
context "#rating" do
  [
    [ "pretty good", 4 ],
    [ "bad", 1 ],
    [ "okay", 3 ],
    [ "awesome", 5 ],
    [ "meh", 2 ]
  ].each do |review, rating|

    it "should match a review of '#{review}' to a rating of #{rating} stars" do
      DosaTracker::DosaStandMapper.new(
        'review' => "it was sort of #{review}"
      ).rating.should == rating
    end

  end
end
def rating
  case @inputs["review"]
  when /bad/; 1
  when /meh/; 2
  when /okay/; 3
  when /pretty good/; 4
  when /awesome/; 5
  end
end
Tip

Keep objects testable by reducing internal dependencies.
                     Each method tested individually.
context ".build" do

    EXAMPLE_CSV = <<-CSV
name,city,address,district,review,dosa types
Sukh Sagar,Chennai,2nd Ave,Anna Nagar,plain|paper|masala|mysore masala|rava
Sri Sai Sagar,Bangalore,"5th Cross, 18th Main Road, HAL 2nd Stage",Indiranagar,plain|
paper|masala|rava masala|mysore masala|coconut
CSV

    it "should instantiate an array of mappers based on the file it's given" do
      csv_file = Rails.root.join("test", "tmp.csv")
      csv_file.open("w") { |io| io << EXAMPLE_CSV }

      mappers = DosaTracker::DosaStandMapper.build(csv_file.open)
      mappers.size.should == 2
      mappers[0].name.should == 'Sukh Sagar'
    end
  end
def self.build(io)
  CSV.read(io, :headers => :first_row).map do |row|
    self.new(row.to_hash)
  end
end
Tip

Initializers are dumb, factory methods are smart.
             Follow Rails factory patterns where appropriate.
Factory method
Factory method   Initializer
context "#dosa_types" do
  it "map a single dosa type to a list with a single item" do
    DosaTracker::DosaStandMapper.new(
      'dosa types' => 'rava'
    ).dosa_types.should == [ DosaType.new(:name => "rava") ]
  end

  it "map pipe-delimited dosa types to a list of multiple types" do
    DosaTracker::DosaStandMapper.new(
      'dosa types' => 'rava|masala|paper|butter'
    ).dosa_types.should == [
      DosaType.new(:name => "rava"),
      DosaType.new(:name => "masala"),
      DosaType.new(:name => "paper"),
      DosaType.new(:name => "butter")
    ]
  end
end


def dosa_types
  @inputs["dosa types"].split("|").map do |name|
    DosaType.new(:name => name)
  end
end
Tip

Don't stub in the class you’re testing.
          It’s a smell. Reduce dependencies instead.
context "#to_model" do
  it "should expose a model object with the newly-populated data" do
    DosaTracker::DosaStandMapper.new(
      'name' => 'Sukh Sagar',
      'city' => 'Chennai',
      'address' => '2nd Avenue, Anna Nagar',
      'review' => 'Pretty good',
      'dosa types' => 'plain|paper|masala|mysore masala|rava'
    ).to_model.location.should match("Chennai, 2nd Avenue, Anna Nagar")
  end
end
class DosaStand < ActiveRecord::Base
  # Domain logic here
end

module DosaTracker
  class DosaStandMapper
    def to_attributes
      {
        name: self.name,
        rating: self.rating,
        location: self.location,
        dosa_types: self.dosa_types
      }
    end

    def to_model
      DosaStand.new(self.to_attributes)
    end
  end
end
Tip

Abstract when you've got a pattern.
              But not before.
Tip

When you've abstracted a pattern, make it a gem.
           This is how good ideas are born.You don’t have to release it.
Antipattern:Too much view logic
http://www.flickr.com/photos/donpezzano/3496645152/


                                                     Active
                                                     Model
http://www.flickr.com/photos/donpezzano/3496645152/


                                                      Active
                                                      Model
                                                     No integration
                                                     dependencies
http://www.flickr.com/photos/donpezzano/3496645152/


                                                      Active
                                                      Model
                                                     No integration
                                                     dependencies

                                                     Mix and match
http://www.flickr.com/photos/donpezzano/3496645152/


                                                       Active
                                                       Model
                                                      No integration
                                                      dependencies

                                                      Mix and match

                                                     Quack like a duck
http://www.flickr.com/photos/donpezzano/3496645152/


                                                       Active
                                                       Model
                                                      No integration
                                                      dependencies

                                                      Mix and match

                                                     Quack like a duck

                                                     Keep it consistent
autoload   :AttributeMethods
autoload   :BlockValidator, 'active_model/validator'
autoload   :Callbacks
autoload   :Conversion
autoload   :DeprecatedErrorMethods
autoload   :Dirty
autoload   :EachValidator, 'active_model/validator'
autoload   :Errors
autoload   :Lint
autoload   :MassAssignmentSecurity
autoload   :Name, 'active_model/naming'
autoload   :Naming
autoload   :Observer, 'active_model/observing'
autoload   :Observing
autoload   :Serialization
autoload   :TestCase
autoload   :Translation
autoload   :Validations
autoload   :Validator
Mix and match to suit your needs
class DosaSearchController < ApplicationController

  def new
    @search = DosaSearch.new
  end

  def show
    @search = DosaSearch.new(params[:search])
    @results = @search.results
  end

end
describe DosaSearch do
  include Test::Unit::Assertions
  include ActiveModel::Lint::Tests

  def model
    subject
  end

  ActiveModel::Lint::Tests.public_instance_methods.map{|m| m.to_s}.grep(/^test/).each do |m|
    example m.gsub('_',' ') do
      send m
    end
  end
end
class DosaSearch
  include ActiveModel::Conversion

  def initialize(attrs={})
    @attributes = attrs
  end

  def persisted?
    false
  end
end
Tip

If you accept attributes, mass-assign.
            It’s simple and straightforward.
context "attributes" do
  it "should assign city" do
    DosaSearch.new(:city => "Chennai").city.should == "Chennai"
  end
end

context "validations" do
  it "should not be valid if a city is not specified" do
    DosaSearch.new.should have(1).error_on(:city)
  end

  it "should be valid if it has a city" do
    DosaSearch.new(:city => "Mysore").should be_valid
  end
end
class DosaSearch
  include ActiveModel::Conversion
  include ActiveModel::Validations

  attr_reader :attributes
  attr_accessor :city

  validates_presence_of :city

  def initialize(attrs={})
    @attributes = attrs

    @attributes.each do |key, value|
      send "#{key}=", value
    end
  end

  def persisted?
    false
  end
end
class DosaSearchController < ApplicationController

  def new
    @search = DosaSearch.new
  end

  def show
    @search = DosaSearch.new(params[:search])
    @results = @search.results
  end

end
Antipattern: Slavish Adherence
       (with zombies)
The Uncanny Valley
class Person
  include Validatable
  validates_presence_of :name
  attr_accessor :name
end
class Person
  include Validatable
  validates_presence_of :name, :times => 1
  attr_accessor :name
end
class MortgageApplication
  include Validatable
  validates_presence_of :ssn, :groups => [:saving, :underwriting]
  validates_presence_of :name, :groups => :underwriting
  attr_accessor :name, :ssn
end
class MortgageApplication
  include Validatable
  validates_presence_of :ssn, :groups => [:saving, :underwriting]
  validates_presence_of :name, :groups => :underwriting
  attr_accessor :name, :ssn
end

>> application = MortgageApplication.new
>> application.ssn = 377990118
>> application.valid_for_saving?
=> true
application.valid_for_underwriting?
=> false
Validations! Everywhere!
http://www.flickr.com/photos/rodolphoreis/5253294758/

          [your library here]
Validations was a great gem.
    It solved a real need.
Database
.establish_connection
ActiveRecord




Database
.establish_connection
ActiveRecord
                        Validatable




Database
.establish_connection
ActiveRecord
                                Validatable




Database
.establish_connection




                        [your library here]
Post-Rails?




http://www.flickr.com/photos/vogelium/2105821119
Rails isn’t going anywhere
What is Ruby on Rails anyway?
What is Ruby on Rails anyway?
          Routing?
What is Ruby on Rails anyway?
          Routing?
         Requires?
What is Ruby on Rails anyway?
          Routing?
         Requires?
   A set of conventions?
Post-Rails:
use individual pieces without being tied to the whole
ActiveRecord anywhere
    First-class Sinatra
Unintrusive ActiveSupport
More generally, code is now more portable
Rails 3


         Active
         Model
Active         Active          Action          Action
Record        Resource         Mailer           Pack



      Active
                                        Railties
     Support
Sinatra


         Active
         Model
Active                      Action
Record                      Mailer



      Active
     Support
What happens when stuff gets modular
How to learn Ruby
How to learn Ruby
    (secret)
“Dude, this is RubyConf. How many people here do you
        really think don’t already know Ruby?”
1
Read Ruby Code
1a
Read good Ruby Code
2
Write Ruby Code
2a
Write Ruby Code
 (without Rails)
3
Structure your libraries like gems
   Run an internal gem server
         Release a gem!
Robots do what every other robot does
Robots do what every other robot does




      Don’t be a robot!
Brian Guthrie
bguthrie@thoughtworks.com
http://twitter.com/bguthrie

questions?


                              http://www.flickr.com/photos/jonnya/4212907371/

Contenu connexe

En vedette

What's our Status?
What's our Status?What's our Status?
What's our Status?Dirk Haun
 
Html5 web sockets - Brad Drysdale - London Web 2011-10-20
Html5 web sockets - Brad Drysdale - London Web 2011-10-20Html5 web sockets - Brad Drysdale - London Web 2011-10-20
Html5 web sockets - Brad Drysdale - London Web 2011-10-20Nathan O'Hanlon
 
On Shrink It and Pink It: Designing Experiences for Women
On Shrink It and Pink It: Designing Experiences for WomenOn Shrink It and Pink It: Designing Experiences for Women
On Shrink It and Pink It: Designing Experiences for WomenJessica Ivins
 
Advanced Ruby Idioms So Clean You Can Eat Off Of Them
Advanced Ruby Idioms So Clean You Can Eat Off Of ThemAdvanced Ruby Idioms So Clean You Can Eat Off Of Them
Advanced Ruby Idioms So Clean You Can Eat Off Of ThemBrian Guthrie
 
Lispmeetup48 cl-online-learningによる文書分類
Lispmeetup48 cl-online-learningによる文書分類Lispmeetup48 cl-online-learningによる文書分類
Lispmeetup48 cl-online-learningによる文書分類Satoshi imai
 
Building a Responsive Web Design Process
Building a Responsive Web Design ProcessBuilding a Responsive Web Design Process
Building a Responsive Web Design ProcessLydia Whitehead
 
Let's Sketchnote — MidwestUX 2012
Let's Sketchnote — MidwestUX 2012Let's Sketchnote — MidwestUX 2012
Let's Sketchnote — MidwestUX 2012Veronica Erb
 
Design Swoon - Visual Trends & WordPress
Design Swoon - Visual Trends  & WordPressDesign Swoon - Visual Trends  & WordPress
Design Swoon - Visual Trends & WordPressSara Cannon
 
Body Language The Hidden Language
Body Language The Hidden LanguageBody Language The Hidden Language
Body Language The Hidden LanguageBrad Nunnally
 

En vedette (10)

What's our Status?
What's our Status?What's our Status?
What's our Status?
 
Html5 web sockets - Brad Drysdale - London Web 2011-10-20
Html5 web sockets - Brad Drysdale - London Web 2011-10-20Html5 web sockets - Brad Drysdale - London Web 2011-10-20
Html5 web sockets - Brad Drysdale - London Web 2011-10-20
 
On Shrink It and Pink It: Designing Experiences for Women
On Shrink It and Pink It: Designing Experiences for WomenOn Shrink It and Pink It: Designing Experiences for Women
On Shrink It and Pink It: Designing Experiences for Women
 
Advanced Ruby Idioms So Clean You Can Eat Off Of Them
Advanced Ruby Idioms So Clean You Can Eat Off Of ThemAdvanced Ruby Idioms So Clean You Can Eat Off Of Them
Advanced Ruby Idioms So Clean You Can Eat Off Of Them
 
Lispmeetup48 cl-online-learningによる文書分類
Lispmeetup48 cl-online-learningによる文書分類Lispmeetup48 cl-online-learningによる文書分類
Lispmeetup48 cl-online-learningによる文書分類
 
Building a Responsive Web Design Process
Building a Responsive Web Design ProcessBuilding a Responsive Web Design Process
Building a Responsive Web Design Process
 
Let's Sketchnote — MidwestUX 2012
Let's Sketchnote — MidwestUX 2012Let's Sketchnote — MidwestUX 2012
Let's Sketchnote — MidwestUX 2012
 
Community at Scale
Community at ScaleCommunity at Scale
Community at Scale
 
Design Swoon - Visual Trends & WordPress
Design Swoon - Visual Trends  & WordPressDesign Swoon - Visual Trends  & WordPress
Design Swoon - Visual Trends & WordPress
 
Body Language The Hidden Language
Body Language The Hidden LanguageBody Language The Hidden Language
Body Language The Hidden Language
 

Dernier

Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesZilliz
 

Dernier (20)

Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector Databases
 

Ruby Plus Rails Plus Your Application Minus Rails

  • 1. Ruby Plus Rails Plus Your Application Minus Rails Brian Guthrie bguthrie@thoughtworks.com http://twitter.com/bguthrie
  • 3. How to do complex things in Ruby (without shooting yourself in the foot) 2010
  • 4. How to do simple things in Ruby (with care and craft) 2011
  • 6.
  • 7.
  • 8.
  • 9. So what’s hard about this? (Is it time to go check out the talk in the other room? That guy seems cool.)
  • 11. Every good talk needs a rant
  • 12.
  • 14. There’s an army of programmers looking for Rails bugs
  • 16. Craft is even more important.
  • 18. Most Ruby programmers are Rails programmers first
  • 19. Learning what Rails doesn’t do is as important as learning what it does
  • 20. For those craftspeople here: Thank you
  • 21.
  • 22. Gaps in Rails: Where’s the problem?
  • 23. “ Prior to Rails 3.0, if a plugin or gem developer wanted to have an object interact with Action Pack helpers, it was required to either copy chunks of code from Rails, or monkey patch entire helpers to make them handle objects that did not exactly conform to the Active Record interface. This would result in code duplication and fragile applications that broke on upgrades. - ActiveModel README
  • 24. Rails 2 Active Active Action Action Record Resource Mailer Pack Active Railties Support
  • 25. Presentation Logic Data
  • 26. Presentation Logic Data form_for @user do
  • 27. Presentation Logic Data form_for @user do @user = User.find(params[:id])
  • 28. Presentation Logic Data form_for @user do @user = User.find(params[:id])
  • 29. Presentation Logic Data form_for @user do @user = User.find(params[:id])
  • 30. Presentation Logic Data form_for @user do @user = User.find(params[:id]) @fb_user = FbUser.find(params[:id])
  • 31. Presentation Logic Data form_for @user do @user = User.find(params[:id]) form_for @fb_user do @fb_user = FbUser.find(params[:id])
  • 32. • Domain models that aren’t database tables • Importing and transforming data • Web service clients • Presenter objects (not a comprehensive list)
  • 33. Rails 2 Active Active Action Action Record Resource Mailer Pack Active Railties Support
  • 34. Rails 3 Active Model Active Active Action Action Record Resource Mailer Pack Active Railties Support
  • 35. Active gem 'active_model' Model Active gem 'active_support', Support :require => false
  • 36. the principles Simplicity Testability Abstractability Community
  • 37. the principles Code Simplicity Testability Abstractability Community
  • 38. S Single responsibility principle An object should have only a single responsibility. O Open/closed principle Software entities … should be open for extension, but closed for modification. L Liskov substitution principle Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program. I Dependency inversion principle Depend upon Abstractions. Do not depend upon concretions. D Interface segregation principle Many client specific interfaces are better than one general purpose interface.
  • 39. S Single responsibility principle An object should have only a single responsibility. O Open/closed principle Software entities … should be open for extension, but closed for modification. L Liskov substitution principle Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program. I Dependency inversion principle Depend upon Abstractions. Do not depend upon concretions. D Interface segregation principle Many client specific interfaces are better than one general purpose interface.
  • 41. S Single responsibility principle An object should have only a single responsibility. O Open/closed principle Software entities … should be open for extension, but closed for modification. L Liskov substitution principle Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program. I Dependency inversion principle Depend upon Abstractions. Do not depend upon concretions. D Interface segregation principle Many client specific interfaces are better than one general purpose interface.
  • 42. S Single responsibility principle An object should have only a single responsibility. O Open/closed principle Software entities … should be open for extension, but closed for modification. L Liskov substitution principle Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program. I Dependency inversion principle Depend upon Abstractions. Do not depend upon concretions. D Interface segregation principle Many client specific interfaces are better than one general purpose interface. Mini SD Card Principles
  • 43. the principles Simplicity Testability Architecture Abstractability Community
  • 44. Idiomaticity Idiom (plural idioms) 1. A manner of speaking, a way of expressing oneself. 2. An artistic style (for example, in art, architecture, or music); an instance of such a style. 3. An expression peculiar to or characteristic of a particular language, especially when the meaning is illogical or separate from the meanings of its component words. 4. (linguistics) A communicative system under study, which could be called either a dialect or a language, when its status as a language or dialect is irrelevant. 5. (programming) A programming construct or phraseology generally held to be the most efficient, elegant or effective means to achieve a particular result or behavior. http://en.wiktionary.org/wiki/idiom
  • 45. Idiomaticity Idiom (plural idioms) 1. A manner of speaking, a way of expressing oneself. 2. An artistic style (for example, in art, architecture, or music); an instance of such a style. 3. An expression peculiar to or characteristic of a particular language, especially when the meaning is illogical or separate from the meanings of its component words. 4. (linguistics) A communicative system under study, which could be called either a dialect or a language, when its status as a language or dialect is irrelevant. 5. (programming) A programming construct or phraseology generally held to be the most efficient, elegant or effective means to achieve a particular result or behavior. http://en.wiktionary.org/wiki/idiom
  • 46. Some of the best Ruby programmers have gone against commonly-accepted style
  • 47. Keep it simple when you can Break the rules when you must (or when it sounds like fun)
  • 48. The best* Ruby code is clean, simple, and follows community idioms. * Easiest to maintain.
  • 49. the recipe Build an object Test that object Expose a familiar API
  • 51. the recipe Build an object Test that object Expose a familiar API
  • 53. Dosa Tracker (I smell a startup opportunity)
  • 54. CSV File name,city,address,district,review,dosa types Sukh Sagar,Chennai,2nd Ave,Anna Nagar,plain|paper|masala|mysore masala|rava Sri Sai Sagar,Bangalore,"5th Cross, 18th Main Road, HAL 2nd Stage",Indiranagar,plain|paper|masala|rava masala|mysore masala|coconut
  • 55. Columns name,city,address,district,review,dosa types Sukh Sagar,Chennai,2nd Ave,Anna Nagar,plain|paper|masala|mysore masala|rava Sri Sai Sagar,Bangalore,"5th Cross, 18th Main Road, HAL 2nd Stage",Indiranagar,plain|paper|masala|rava masala|mysore masala|coconut
  • 56. Data name,city,address,district,review,dosa types Sukh Sagar,Chennai,2nd Ave,Anna Nagar,plain|paper|masala|mysore masala|rava Sri Sai Sagar,Bangalore,"5th Cross, 18th Main Road, HAL 2nd Stage",Indiranagar,plain|paper|masala|rava masala|mysore masala|coconut
  • 57. ETL CSV (extract, transform, load)
  • 59. Slight improvement CSV CSV Mapper module ABunchOfSuperAwesomeDataTransformationMethods def some_conversion_that_wont_make_sense_six_months_from_now(inputs) end end
  • 60. Active Support CSV Active CSV Record Mapper module DosaTracker class DosaStandMapper def initialize(inputs={}) end def to_model # Output end end end
  • 61. module DosaTracker class DosaStandMapper def initialize(inputs={}) @inputs = inputs end def location [ @inputs["city"], @inputs["address"], @inputs["landmark"] ].join(", ") end end end
  • 62. require 'spec_helper' describe DosaTracker::DosaStandMapper do context "#location" do it "should include the city and address" do DosaTracker::DosaStandMapper.new( 'city' => 'Chennai', 'address' => '2nd Avenue, Anna Nagar' ).location.should match("Chennai, 2nd Avenue, Anna Nagar") end end end
  • 63. context "#rating" do [ [ "pretty good", 4 ], [ "bad", 1 ], [ "okay", 3 ], [ "awesome", 5 ], [ "meh", 2 ] ].each do |review, rating| it "should match a review of '#{review}' to a rating of #{rating} stars" do DosaTracker::DosaStandMapper.new( 'review' => "it was sort of #{review}" ).rating.should == rating end end end
  • 64. def rating case @inputs["review"] when /bad/; 1 when /meh/; 2 when /okay/; 3 when /pretty good/; 4 when /awesome/; 5 end end
  • 65. Tip Keep objects testable by reducing internal dependencies. Each method tested individually.
  • 66. context ".build" do EXAMPLE_CSV = <<-CSV name,city,address,district,review,dosa types Sukh Sagar,Chennai,2nd Ave,Anna Nagar,plain|paper|masala|mysore masala|rava Sri Sai Sagar,Bangalore,"5th Cross, 18th Main Road, HAL 2nd Stage",Indiranagar,plain| paper|masala|rava masala|mysore masala|coconut CSV it "should instantiate an array of mappers based on the file it's given" do csv_file = Rails.root.join("test", "tmp.csv") csv_file.open("w") { |io| io << EXAMPLE_CSV } mappers = DosaTracker::DosaStandMapper.build(csv_file.open) mappers.size.should == 2 mappers[0].name.should == 'Sukh Sagar' end end
  • 67. def self.build(io) CSV.read(io, :headers => :first_row).map do |row| self.new(row.to_hash) end end
  • 68. Tip Initializers are dumb, factory methods are smart. Follow Rails factory patterns where appropriate.
  • 69.
  • 71. Factory method Initializer
  • 72. context "#dosa_types" do it "map a single dosa type to a list with a single item" do DosaTracker::DosaStandMapper.new( 'dosa types' => 'rava' ).dosa_types.should == [ DosaType.new(:name => "rava") ] end it "map pipe-delimited dosa types to a list of multiple types" do DosaTracker::DosaStandMapper.new( 'dosa types' => 'rava|masala|paper|butter' ).dosa_types.should == [ DosaType.new(:name => "rava"), DosaType.new(:name => "masala"), DosaType.new(:name => "paper"), DosaType.new(:name => "butter") ] end end def dosa_types @inputs["dosa types"].split("|").map do |name| DosaType.new(:name => name) end end
  • 73. Tip Don't stub in the class you’re testing. It’s a smell. Reduce dependencies instead.
  • 74. context "#to_model" do it "should expose a model object with the newly-populated data" do DosaTracker::DosaStandMapper.new( 'name' => 'Sukh Sagar', 'city' => 'Chennai', 'address' => '2nd Avenue, Anna Nagar', 'review' => 'Pretty good', 'dosa types' => 'plain|paper|masala|mysore masala|rava' ).to_model.location.should match("Chennai, 2nd Avenue, Anna Nagar") end end
  • 75. class DosaStand < ActiveRecord::Base # Domain logic here end module DosaTracker class DosaStandMapper def to_attributes { name: self.name, rating: self.rating, location: self.location, dosa_types: self.dosa_types } end def to_model DosaStand.new(self.to_attributes) end end end
  • 76. Tip Abstract when you've got a pattern. But not before.
  • 77. Tip When you've abstracted a pattern, make it a gem. This is how good ideas are born.You don’t have to release it.
  • 80. http://www.flickr.com/photos/donpezzano/3496645152/ Active Model No integration dependencies
  • 81. http://www.flickr.com/photos/donpezzano/3496645152/ Active Model No integration dependencies Mix and match
  • 82. http://www.flickr.com/photos/donpezzano/3496645152/ Active Model No integration dependencies Mix and match Quack like a duck
  • 83. http://www.flickr.com/photos/donpezzano/3496645152/ Active Model No integration dependencies Mix and match Quack like a duck Keep it consistent
  • 84. autoload :AttributeMethods autoload :BlockValidator, 'active_model/validator' autoload :Callbacks autoload :Conversion autoload :DeprecatedErrorMethods autoload :Dirty autoload :EachValidator, 'active_model/validator' autoload :Errors autoload :Lint autoload :MassAssignmentSecurity autoload :Name, 'active_model/naming' autoload :Naming autoload :Observer, 'active_model/observing' autoload :Observing autoload :Serialization autoload :TestCase autoload :Translation autoload :Validations autoload :Validator
  • 85. Mix and match to suit your needs
  • 86. class DosaSearchController < ApplicationController def new @search = DosaSearch.new end def show @search = DosaSearch.new(params[:search]) @results = @search.results end end
  • 87. describe DosaSearch do include Test::Unit::Assertions include ActiveModel::Lint::Tests def model subject end ActiveModel::Lint::Tests.public_instance_methods.map{|m| m.to_s}.grep(/^test/).each do |m| example m.gsub('_',' ') do send m end end end
  • 88. class DosaSearch include ActiveModel::Conversion def initialize(attrs={}) @attributes = attrs end def persisted? false end end
  • 89. Tip If you accept attributes, mass-assign. It’s simple and straightforward.
  • 90. context "attributes" do it "should assign city" do DosaSearch.new(:city => "Chennai").city.should == "Chennai" end end context "validations" do it "should not be valid if a city is not specified" do DosaSearch.new.should have(1).error_on(:city) end it "should be valid if it has a city" do DosaSearch.new(:city => "Mysore").should be_valid end end
  • 91. class DosaSearch include ActiveModel::Conversion include ActiveModel::Validations attr_reader :attributes attr_accessor :city validates_presence_of :city def initialize(attrs={}) @attributes = attrs @attributes.each do |key, value| send "#{key}=", value end end def persisted? false end end
  • 92. class DosaSearchController < ApplicationController def new @search = DosaSearch.new end def show @search = DosaSearch.new(params[:search]) @results = @search.results end end
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100. class Person include Validatable validates_presence_of :name attr_accessor :name end
  • 101. class Person include Validatable validates_presence_of :name, :times => 1 attr_accessor :name end
  • 102. class MortgageApplication include Validatable validates_presence_of :ssn, :groups => [:saving, :underwriting] validates_presence_of :name, :groups => :underwriting attr_accessor :name, :ssn end
  • 103. class MortgageApplication include Validatable validates_presence_of :ssn, :groups => [:saving, :underwriting] validates_presence_of :name, :groups => :underwriting attr_accessor :name, :ssn end >> application = MortgageApplication.new >> application.ssn = 377990118 >> application.valid_for_saving? => true application.valid_for_underwriting? => false
  • 106. Validations was a great gem. It solved a real need.
  • 107.
  • 110. ActiveRecord Validatable Database .establish_connection
  • 111. ActiveRecord Validatable Database .establish_connection [your library here]
  • 113. Rails isn’t going anywhere
  • 114. What is Ruby on Rails anyway?
  • 115. What is Ruby on Rails anyway? Routing?
  • 116. What is Ruby on Rails anyway? Routing? Requires?
  • 117. What is Ruby on Rails anyway? Routing? Requires? A set of conventions?
  • 118. Post-Rails: use individual pieces without being tied to the whole
  • 119. ActiveRecord anywhere First-class Sinatra Unintrusive ActiveSupport
  • 120. More generally, code is now more portable
  • 121. Rails 3 Active Model Active Active Action Action Record Resource Mailer Pack Active Railties Support
  • 122. Sinatra Active Model Active Action Record Mailer Active Support
  • 123. What happens when stuff gets modular
  • 124. How to learn Ruby
  • 125. How to learn Ruby (secret)
  • 126. “Dude, this is RubyConf. How many people here do you really think don’t already know Ruby?”
  • 130. 2a Write Ruby Code (without Rails)
  • 131. 3 Structure your libraries like gems Run an internal gem server Release a gem!
  • 132. Robots do what every other robot does
  • 133. Robots do what every other robot does Don’t be a robot!
  • 134. Brian Guthrie bguthrie@thoughtworks.com http://twitter.com/bguthrie questions? http://www.flickr.com/photos/jonnya/4212907371/

Notes de l'éditeur

  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
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n
  68. \n
  69. \n
  70. \n
  71. \n
  72. \n
  73. \n
  74. \n
  75. \n
  76. \n
  77. \n
  78. Hero of Rails 3\n
  79. Hero of Rails 3\n
  80. Hero of Rails 3\n
  81. Hero of Rails 3\n
  82. \n
  83. \n
  84. \n
  85. \n
  86. \n
  87. \n
  88. \n
  89. \n
  90. \n
  91. \n
  92. Masahiro Mori - 1970\n
  93. Masahiro Mori in 1970\n
  94. Masahiro Mori in 1970\n
  95. \n
  96. \n
  97. \n
  98. \n
  99. \n
  100. \n
  101. \n
  102. \n
  103. \n
  104. \n
  105. \n
  106. \n
  107. \n
  108. \n
  109. \n
  110. \n
  111. \n
  112. \n
  113. \n
  114. \n
  115. \n
  116. \n
  117. \n
  118. \n
  119. \n
  120. \n
  121. \n
  122. \n
  123. \n
  124. \n
  125. \n
  126. \n
  127. \n
  128. \n
  129. \n