Programming Production Code
 as if writing Natural Language




      Kazuya NUMATA
         @kaznum
Self-introduction
                        (Kazuya NUMATA)
  •
  •                          �


  •
  •
  •
      ���������������


  •
My favorite


•
    •
    •
Agile
Communication with team members
     including stakeholder
                &
        Iterative Testing
Behavior Driven Development
             BDD
Tools
to make BDD effective
•   RSpec (Ruby)

•   NSpec (.NET)

•   CppSpec (C++)

•   JBehave (Java)

•   instinct (Java)

•   PHPSpec (PHP)

•   and more....
Question
Question




   Have you ever experienced *Spec?


*Spec                                 ?
RSpec example:



describe "A new chess board" do

   before(:each) do
     @board = Chess::Board.new
   end

   it "should have 32 pieces" do
     @board.should have(32).pieces
   end

end
                               D. Chelimsky. The RSpec Book
                          Section 13.7 Generated Descriptions
RSpec example:



describe "A new chess board" do

   before(:each) do
     @board = Chess::Board.new
   end

   it "should have 32 pieces" do
     @board.should have(32).pieces
   end

end
                               D. Chelimsky. The RSpec Book
                          Section 13.7 Generated Descriptions
RSpec example:



$ rspec -fd board_spec.rb

(Output is...)

A new chess board
  should have 32 pieces

                       D. Chelimsky. The RSpec Book
                  Section 13.7 Generated Descriptions
It is just Natural Language!
�
The reality is that it’s hard for the Japanese.
Cucumber

(              )
Cucumber Example:


         :

         :


         "           "    "                 "
         "       "   "        Cucumber"
         "       "
             "           Cucumber"

                                                                   ( ∀ )o   sasata299's blog
                                     http://blog.livedoor.jp/sasata299/archives/51278697.html
/Spec




Before
 BDD


After    Spec    Spec
BDD
Before
 BDD


After
BDD
?
Uncle Bob

   Complex fulcrumPoint = Complex.FromRealNumber(23.0);

is generally better than

   Complex fulcrumPoint = new Complex(23.0);

Consider enforcing their use by making the corresponding constructors private.



                           (   )
by Masayoshi Son
Person
         name
                        true
                false
Ruby Example:   name   1

ex1


class Person
  attr_accessor :name
  def initialize(name = nil)
    @name = name
  end
end

shimada = Person.new(“Shimada”)
if shimada.name.split(//)[0] == “S”
  puts “Match”
end
Ruby Example: name   1

ex2


class Person
  attr_accessor :name
  def initialize(name = nil)
    @name = name
  end

  def has_a_name_that_begins_with?(expected)
    @name.split(//)[0] == expected
  end
end

shimada = Person.new(“Shimada”)
if shimada.has_a_name_that_begins_with?(“S”)
  puts “Match”
end
Ruby Example: name    1

ex3

class Person
  attr_accessor :name
  def initialize(name = nil)
    @name = name
  end

  def has_a_name_that_begins_with?(expected)
    @name.split(//)[0] == expected
  end

  def method_missing(m, *args, &block)
    if m.to_s =~ /has_(a|the)_name_(that|which)_begins_with?/
      has_a_name_that_begins_with?(args)
    else
      super
    end
  end
end

shimada = Person.new(“Shimada”)
puts “Match” if shimada.has_a_name_that_begins_with?(“S”)
puts “Match” if shimada.has_the_name_that_begins_with?(“S”)
puts “Match” if shimada.has_a_name_which_begins_with?(“S”)
puts “Match” if shimada.has_the_name_which_begins_with?(“S”)
Ruby Example: name                           1
ex4      name                                                                                     String
                                                                   has_(a|the)_(.+)_(which|that)_begins_with?
Dynamic                    setter
             undef                         Singleton Method
class Person
  def initialize(args)
    args.each do |key, value|
      self.class.send(:attr_accessor, :"#{key}") unless instance_variables.include?(:"@#{key}")
      instance_variable_set(:"@#{key}", value)
    end
  end

  def self.undef_has_a_var_which_begins_with(var)
    method_name = "has_a_#{var}_which_begins_with?"
    send("undef_method", method_name) if method_defined? method_name
  end

  def self.define_has_a_var_which_begins_with(var)
    method_name = "has_a_#{var}_which_begins_with?"
    define_method(method_name) do |expectation|
      value = instance_variable_get(:"@#{var}")
      if value.is_a?(String)
        value.split(//)[0].downcase == expectation.downcase
      else
        self.class.undef_has_a_var_which_begins_with(var)
        method_missing(method_name.to_sym)
      end
    end
  end

  def method_missing(m, *args, &block)
    if m.to_s =~ /has_(a|the)_(.+)_(which|that)_begins_with?/ &&
         instance_variables.include?(:"@#{Regexp.last_match[2]}") &&
         instance_variable_get(:"@#{Regexp.last_match[2]}").is_a?(String)
      var_name = Regexp.last_match[2]
      self.class.define_has_a_var_which_begins_with(var_name)
      send("has_a_#{var_name}_which_begins_with?".to_sym, *args, &block)
    else
      super(m, *args, &block)
    end
  end
end

#### sample #####
shimada = Person.new(:name => "Shimada", :age => 18, :sex => :half, :fuga => "bababa")
p shimada.has_a_name_which_begins_with?("S") ? "Good" : "Suck"
p shimada.has_the_name_which_begins_with?("S") ? "Good" : "Suck"
shimada.name = 5
p shimada.has_the_name_which_begins_with?("5") ? "Good" : "Suck" #=> undefined method
if air_plane.is_created_by? :bowing
    if he.is_eligible_to_get? reward
    if selected_value.is_valid?


→
    can_..., is_,
is does was did
module Kernel
  def is(expected)
    expected
  end

 alias_method :does, :is
 alias_method :was, :is
 alias_method :were, :is
 alias_method :did, :is
 # alias_method :do, :is       × do
end

is air_plane.created_by?(bowing)
does [1,2,3].include?
is he.eligible_to_get?(bonus)
does [1,2,3].include?
is "h".included_in?("hello")
is she, nancy   # ?
Conclusion & Impression

•   Spec



•

•
      •                                                                          Receiver
                                                                            Array#sort


      •            Ruby Standard Library         if obj.instance_of?(exp)   be
                                           (Is                  Object#is   Is#method_missing
           self   return...)


      •
      •
      •
thank you :)

あたかも自然言語を書くようにコーディングしてみる

  • 1.
    Programming Production Code as if writing Natural Language Kazuya NUMATA @kaznum
  • 2.
    Self-introduction (Kazuya NUMATA) • • � • • • ��������������� •
  • 3.
  • 4.
  • 5.
    Communication with teammembers including stakeholder & Iterative Testing
  • 6.
  • 7.
  • 8.
    RSpec (Ruby) • NSpec (.NET) • CppSpec (C++) • JBehave (Java) • instinct (Java) • PHPSpec (PHP) • and more....
  • 9.
  • 10.
    Question Have you ever experienced *Spec? *Spec ?
  • 11.
    RSpec example: describe "Anew chess board" do before(:each) do @board = Chess::Board.new end it "should have 32 pieces" do @board.should have(32).pieces end end D. Chelimsky. The RSpec Book Section 13.7 Generated Descriptions
  • 12.
    RSpec example: describe "Anew chess board" do before(:each) do @board = Chess::Board.new end it "should have 32 pieces" do @board.should have(32).pieces end end D. Chelimsky. The RSpec Book Section 13.7 Generated Descriptions
  • 13.
    RSpec example: $ rspec-fd board_spec.rb (Output is...) A new chess board should have 32 pieces D. Chelimsky. The RSpec Book Section 13.7 Generated Descriptions
  • 14.
    It is justNatural Language!
  • 15.
  • 16.
    The reality isthat it’s hard for the Japanese.
  • 17.
  • 18.
    Cucumber Example: : : " " " " " " " Cucumber" " " " Cucumber" ( ∀ )o sasata299's blog http://blog.livedoor.jp/sasata299/archives/51278697.html
  • 20.
  • 21.
  • 22.
  • 25.
    Uncle Bob Complex fulcrumPoint = Complex.FromRealNumber(23.0); is generally better than Complex fulcrumPoint = new Complex(23.0); Consider enforcing their use by making the corresponding constructors private. ( )
  • 26.
  • 27.
    Person name true false
  • 28.
    Ruby Example: name 1 ex1 class Person attr_accessor :name def initialize(name = nil) @name = name end end shimada = Person.new(“Shimada”) if shimada.name.split(//)[0] == “S” puts “Match” end
  • 29.
    Ruby Example: name 1 ex2 class Person attr_accessor :name def initialize(name = nil) @name = name end def has_a_name_that_begins_with?(expected) @name.split(//)[0] == expected end end shimada = Person.new(“Shimada”) if shimada.has_a_name_that_begins_with?(“S”) puts “Match” end
  • 30.
    Ruby Example: name 1 ex3 class Person attr_accessor :name def initialize(name = nil) @name = name end def has_a_name_that_begins_with?(expected) @name.split(//)[0] == expected end def method_missing(m, *args, &block) if m.to_s =~ /has_(a|the)_name_(that|which)_begins_with?/ has_a_name_that_begins_with?(args) else super end end end shimada = Person.new(“Shimada”) puts “Match” if shimada.has_a_name_that_begins_with?(“S”) puts “Match” if shimada.has_the_name_that_begins_with?(“S”) puts “Match” if shimada.has_a_name_which_begins_with?(“S”) puts “Match” if shimada.has_the_name_which_begins_with?(“S”)
  • 31.
    Ruby Example: name 1 ex4 name String has_(a|the)_(.+)_(which|that)_begins_with? Dynamic setter undef Singleton Method class Person def initialize(args) args.each do |key, value| self.class.send(:attr_accessor, :"#{key}") unless instance_variables.include?(:"@#{key}") instance_variable_set(:"@#{key}", value) end end def self.undef_has_a_var_which_begins_with(var) method_name = "has_a_#{var}_which_begins_with?" send("undef_method", method_name) if method_defined? method_name end def self.define_has_a_var_which_begins_with(var) method_name = "has_a_#{var}_which_begins_with?" define_method(method_name) do |expectation| value = instance_variable_get(:"@#{var}") if value.is_a?(String) value.split(//)[0].downcase == expectation.downcase else self.class.undef_has_a_var_which_begins_with(var) method_missing(method_name.to_sym) end end end def method_missing(m, *args, &block) if m.to_s =~ /has_(a|the)_(.+)_(which|that)_begins_with?/ && instance_variables.include?(:"@#{Regexp.last_match[2]}") && instance_variable_get(:"@#{Regexp.last_match[2]}").is_a?(String) var_name = Regexp.last_match[2] self.class.define_has_a_var_which_begins_with(var_name) send("has_a_#{var_name}_which_begins_with?".to_sym, *args, &block) else super(m, *args, &block) end end end #### sample ##### shimada = Person.new(:name => "Shimada", :age => 18, :sex => :half, :fuga => "bababa") p shimada.has_a_name_which_begins_with?("S") ? "Good" : "Suck" p shimada.has_the_name_which_begins_with?("S") ? "Good" : "Suck" shimada.name = 5 p shimada.has_the_name_which_begins_with?("5") ? "Good" : "Suck" #=> undefined method
  • 33.
    if air_plane.is_created_by? :bowing if he.is_eligible_to_get? reward if selected_value.is_valid? → can_..., is_,
  • 34.
    is does wasdid module Kernel def is(expected) expected end alias_method :does, :is alias_method :was, :is alias_method :were, :is alias_method :did, :is # alias_method :do, :is × do end is air_plane.created_by?(bowing) does [1,2,3].include? is he.eligible_to_get?(bonus) does [1,2,3].include? is "h".included_in?("hello") is she, nancy # ?
  • 35.
    Conclusion & Impression • Spec • • • Receiver Array#sort • Ruby Standard Library if obj.instance_of?(exp) be (Is Object#is Is#method_missing self return...) • • •
  • 36.