SlideShare ist ein Scribd-Unternehmen logo
1 von 69
Downloaden Sie, um offline zu lesen
Cleanliness is Next to
Domain-Specificity
Ben Scofield
Senior Developer
Viget Labs




4 November 2007
© Copyright 2007 Viget Labs, LLC – www.viget.com
Part 1: Linguistics
Part 2: Refactoring
The Ruby
Community
http://www.flickr.com/photos/jesper/1395418767/




Interdisciplinary
Linguistics
Categories
Regional Dialects
(more)

Regional
Dialects
Jargons   Cants
Pidgins and Creoles
Vocabulary
 Grammar
Real DSLs




Ruby Domain-Specific Code
ActiveRecord
RSpec
Same Grammar,
Different Vocabulary
Who Cares?
DSLs
                                                 DSL




                                                       Intimidate
                                                           and
                                                        Frighten
http://www.ïŹ‚ickr.com/photos/cwsteeds/58514985/
Write a Parser?
 No, Thanks.



            http://www.ïŹ‚ickr.com/photos/rooreynolds/243810988/
http://www.ïŹ‚ickr.com/photos/jonosd/498162310/
Change the Vocabulary
  Change the World

               Heroes on NBC - Mondays at 9 PM
API vs. Dialect
Why DSanything?
Who Are We?
http://www.oreillynet.com/onlamp/blog/2006/05/
sapirwhorf_is_not_a_klingon.html
http://tech.puredanger.com/2006/11/08/does-your-programming-
language-affect-how-you-think/
http://snakesgemscoffee.blogspot.com/2006_11_01_archive.html
http://talklikeaduck.denhaven2.com/articles/2007/06/11/sapir-
whorf
http://adams.id.au/blog/2007/10/what-is-behaviour-driven-
development/
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/75914
http://www.weiqigao.com/blog/2007/09/10/
an_interesting_experiment_sapir_whorf_hypothesis.html
http://www.ibm.com/developerworks/blogs/page/pmuellr?
tag=ruby
http://intertwingly.net/blog/2007/10/05/NOC
http://brooders.net/category/perl/
http://gilesbowkett.blogspot.com/2007/02/sapir-worf-in-
action_19.html
http://blogs.msdn.com/daveremy/archive/2005/04/06/
sapirwhorfs.aspx
http://erlangish.blogspot.com/2007/05/shape-of-your-mind.html
http://www.oreillynet.com/onlamp/blog/2006/06/
how_does_a_programming_languag.html
Linguistic Determinism
The Hopi
Linguistic Relativism
http://www.flickr.com/photos/maxhunter/79993854/




                                                   Snow
                                 qanuk                    avalanche
                                 kaneq                    blizzard
                                 kanevvluk                dusting
                                 natquik                  flurry
                                 nevluk                   frost
                                 aniu                     hail
                                 qanikcaq                 hardpack
                                 muruaneq                 igloo
                                 nutaryuk                 pingo
                                 qanisqineq               powder
                                 qengaruk                 sleet
                                 utvak                    slush
                                 navcaq                   snow
                                 pirta                    snowflake
                                 pirtuk                   snowstorm
                                 ...                      ...
Color
Perception

             http://www.flickr.com/photos/thedeplorableword/140856437/
Direction of Causality
Degree of Influence
RSpec
     
Sapir-Whorf
Testing is Too Late
Specifications
 Come First
RSpec Leads You in
the Right Direction
DSDs are Built on
Linguistic Relativism
Keep Your Head in
   the Domain
Refactoring
Tastes Vary
?
Finding a Ticket
kayak.com
What Does This Do?
Ruby? Awesome!
exit 0

  @@results.each do |r|
    if searchtype == 'h'
      puts quot;#{r.price} url=#{r.url}quot;
      puts quot;#{r.stars} #{r.name} $#{r.loprice} - $#{r.hiprice}quot;
    elsif searchtype == 'f'
      puts quot;#{r.price} url=#{r.url}quot;
      r.legs.each do |leg|
        puts quot; #{leg}quot;
      end
    end
  end

  exit(0)
  more = poll_results_file(searchtype)
  @@results.each do |r|
    puts quot;#{r.price} #{r.url}quot;
    r.legs.each do |leg|
      puts quot; #{leg}quot;
    end
  end
end




                                   Whoa.
Start at the End
I Want to:
find flights from CLT to RDU leaving today
         and returning in one week
I Want to:
find :flights, :from => :CLT, :to => :RDU,
  :leaving => Date.today, :returning => Date.today + 7
48
                                                                                               40




                      The Old Way
sid = getsession(@@token)
searchid = start_flight_search(sid, ‘n’, ‘CLT’, ‘RDU’, Date.today, nil, 1)

more = poll_results('f', sid, searchid, nil)
while more == 'true' do
  more = poll_results('f', sid, searchid, nil)
  sleep(3)
end

def poll_results(searchtype, sid, searchid, count)
  url = quot;/s#{@@sparkleinstance}/apibasic/flight?searchid=#{searchid}&apimode=1&_sid_=#{sid}quot;

  more = nil
  Net::HTTP.start(@@hostname, @@port)   do |http|
    if count
      url += quot;&c=#{count}quot;
    end
    response = http.get(url)
    body = response.body
    File.open(quot;ksearchbody.xmlquot;, quot;wquot;)   do |f|
      f.puts(body)
    end
    more = handle_results(searchtype,   body)
    if more != 'true'
      # save the body, so we can test   without doin
      # an actual search
      File.open(quot;ksearchresults.xmlquot;,   quot;wquot;) do |f|
        f.puts(body)
      end
    end
  end
  return more
end
48
                                                                                      40




   The Old Way, cont.
def handle_results(searchtype, body)
  xml = REXML::Document.new(body)
  more = xml.elements['/searchresult/morepending']
  @@lastcount = xml.elements['/searchresult/count'].text
  @@sparkleinstance = xml.elements['/searchresult/searchinstance'].text
  if more
    more = more.text
  end
  if more != 'true'
    @@results = []
    #puts quot;count=#{@@lastcount}quot;
    xml.elements.each(quot;/searchresult/trips/tripquot;) do |e|
      trip = Trip.new()
      e.each_element(quot;pricequot;) do |t|
        trip.price = t.text
        trip.url = t.attribute(quot;urlquot;)
      end
      e.each_element(quot;legsquot;) do |legs|
        legs.each_element(quot;legquot;) do |l|
          leg = Leg.new
          l.each_element do |ld|
            # extract the detail from each leg
            case
            when ld.name == 'airline': leg.airlinecode = ld.text
            #...
            end
          end
          trip.legs << leg
        end # leg in legs loop
      end # legs in trip loop
      #e.each_element(quot;/searchresult/trips/trip/pricequot;) { |p| trip.price = p.text }
      #puts quot;trip: #{trip.price}quot;
      @@results << trip
    end # each trip
  end
  return more
end
40




                       Output
session_url = quot;/k/ident/apisession?token=#{token}quot;



search_url = quot;/s/apisearch?basicmode=true&oneway=n&origin=#{origin}
&destination=#{destination}&destcode=&depart_date=#{dep_date}
&depart_time=a&return_date=#{ret_date}&return_time=a&travelers=#
{travelers}&cabin=e&action=doflights&apimode=1&_sid_=#{sid}quot;



results_url = quot;/s#{@@sparkleinstance}/apibasic/flight?searchid=#
{searchid}&apimode=1&_sid_=#{sid}quot;
40




              Expectations
class KayakTest < Test::Unit::TestCase
  def test_find_should_call_out_to_session_endpoint
    setup_mocks_for_find
    Kayak.find :flights
  end

  private
  def setup_mocks_for_find
    response = mock(:body => '<?xml version=quot;1.0quot;?>
    <ident>
      <uid>uid</uid>
      <sid>0123456789</sid>
      <token>12345</token>
      <error></error>
    </ident>')
    success = mock()
    success.expects(:get).with('/k/ident/apisession?token=12345').returns
      (response)
    Net::HTTP.expects(:start).at_least_once.yields(success)
  end
end
40




   Parsing Responses
class KayakTest < Test::Unit::TestCase
  def test_session_response_should_be_parsed_for_session_id
    setup_mocks_for_find
    Kayak.find :flights
    assert_equal '0123456789', Kayak.session_id
  end

  private
  def setup_mocks_for_find
    response = mock(:body => '<?xml version=quot;1.0quot;?>
    <ident>
      <uid>uid</uid>
      <sid>0123456789</sid>
      <token>12345</token>
      <error></error>
    </ident>')
    success = mock()
    success.expects(:get).with('/k/ident/apisession?token=12345').returns
      (response)
    Net::HTTP.expects(:start).at_least_once.yields(success)
  end
end
class Kayak




                                      First Cut
  @@session_id = nil
  @@search_id = nil
  @@search_options = {}

  TOKEN    = '12345'
  HOSTNAME = 'www.kayak.com'
  PORT     = 80

  class << self
    def session_id
      @@session_id
    end

    def method_missing(name, *args)
      @@search_options[name]
    end

    def find(type, conditions = {})
      session_id ||= initialize_session
      @@search_options[:origin]      = conditions[:from]
      @@search_options[:destination] = conditions[:to]
      @@search_options[:depart_date] = conditions[:leaving].strftime('%m/%d/%Y')  if conditions[:leaving]
      @@search_options[:leave_date] = conditions[:returning].strftime('%m/%d/%Y') if conditions[:returning]

      search_id ||= initialize_search
      self
    end

    def initialize_search
      Net::HTTP.start(HOSTNAME, PORT) do |http|
        response = http.get(quot;/s/apisearch?basicmode=true&oneway=n&destcode=&depart_time=a&...
        if body = response.body
          xml = REXML::Document.new(body)
          @@search_id = xml.elements['//searchid'].text
        end
      end
    end

    def initialize_session
      Net::HTTP.start(HOSTNAME, PORT) do |http|
        response = http.get(quot;/k/ident/apisession?token=#{TOKEN}quot;)
        if body = response.body
          xml = REXML::Document.new(body)
          @@session_id = xml.elements['//sid'].text
        end
      end
    end
  end
end
module Kayak




                          Second Cut
  TOKEN    = '12345'
  HOSTNAME = 'www.kayak.com'
  PORT     = 80

  class Flight
    attr_accessor :session, :search_id, :search_options

    def method_missing(name, *args)
      search_options[name]
    end

    def initialize(conditions = {})
      session ||= Kayak::Session.new
      self.search_options = {}
      self.search_options[:origin]        =   conditions[:from]
      self.search_options[:destination]   =   conditions[:to]
      self.search_options[:depart_date]   =   conditions[:leaving].strftime('%m/%d/%Y')   if conditions[:leaving]
      self.search_options[:return_date]   =   conditions[:returning].strftime('%m/%d/%Y') if conditions[:returning]

      Net::HTTP.start(HOSTNAME, PORT) do |http|
        response = http.get(quot;/s/apisearch?basicmode=true&oneway=n&destcode=&depart_time=a&return_date=...
        self.search_id = Kayak.retrieve(response, '//searchid')
      end
    end

    def self.find(args)
      self.new(args)
    end
  end

  class Session
    attr_accessor :session_id

    def initialize
      Net::HTTP.start(Kayak::HOSTNAME, Kayak::PORT) do |http|
        response = http.get(quot;/k/ident/apisession?token=#{Kayak::TOKEN}quot;)
        self.session_id ||= Kayak.retrieve(response, '//sid')
      end
    end
  end

  def self.find(type, *args)
    case type
      when :flights
        Kayak::Flight.find(*args)
    end
  end

  ...
I Want to:
find :flights, :from => :CLT, :to => :RDU,
  :leaving => Date.today, :returning => Date.today + 7
Third Cut


  ?
Always Room for
  Improvement
Tips
:symbol
ignore the colon
I Want to:
find :flights, :from => :CLT, :to => :RDU,
  :leaving => Date.today, :returning => Date.today + 7
Optional Parentheses
   looks like a sentence
I Want to:
find :flights, :from => :CLT, :to => :RDU,
  :leaving => Date.today, :returning => Date.today + 7
Blocks for All
In other languages, you have to specify
explicitly that a function can accept another
function as an argument. But in Ruby, any
method can be called with a block as an
implicit argument.
                                 Matz, 2003
*
arrays from anything
Optional Braces
 not that common
I Want to:
find :flights, :from => :CLT, :to => :RDU,
  :leaving => Date.today, :returning => Date.today + 7
‱ Start Modestly
‱ Stay in the Domain
‱ Get Better
56




That’s It
travel safely
Ben Scofield
   ben.scofield@viget.com
http://www.extendviget.com/
   http://www.culann.com/

 4 November 2007
 © Copyright 2007 Viget Labs, LLC – www.viget.com

Weitere Àhnliche Inhalte

Was ist angesagt?

RubyEnRails2007 - Dr Nic Williams - Keynote
RubyEnRails2007 - Dr Nic Williams - KeynoteRubyEnRails2007 - Dr Nic Williams - Keynote
RubyEnRails2007 - Dr Nic Williams - KeynoteDr Nic Williams
 
Bringing Characters to Life for Immersive Storytelling - Dioselin Gonzalez
Bringing Characters to Life for Immersive Storytelling - Dioselin GonzalezBringing Characters to Life for Immersive Storytelling - Dioselin Gonzalez
Bringing Characters to Life for Immersive Storytelling - Dioselin GonzalezWithTheBest
 
A Few of My Favorite (Python) Things
A Few of My Favorite (Python) ThingsA Few of My Favorite (Python) Things
A Few of My Favorite (Python) ThingsMichael Pirnat
 
Writing Modular Command-line Apps with App::Cmd
Writing Modular Command-line Apps with App::CmdWriting Modular Command-line Apps with App::Cmd
Writing Modular Command-line Apps with App::CmdRicardo Signes
 
(Ab)Using the MetaCPAN API for Fun and Profit
(Ab)Using the MetaCPAN API for Fun and Profit(Ab)Using the MetaCPAN API for Fun and Profit
(Ab)Using the MetaCPAN API for Fun and ProfitOlaf Alders
 
"The worst code I ever wrote"
"The worst code I ever wrote""The worst code I ever wrote"
"The worst code I ever wrote"Tomas Doran
 
Malli: inside data-driven schemas
Malli: inside data-driven schemasMalli: inside data-driven schemas
Malli: inside data-driven schemasMetosin Oy
 
Moose Best Practices
Moose Best PracticesMoose Best Practices
Moose Best PracticesAran Deltac
 
Designing with malli
Designing with malliDesigning with malli
Designing with malliMetosin Oy
 
Moose (Perl 5)
Moose (Perl 5)Moose (Perl 5)
Moose (Perl 5)xSawyer
 
TDC 2014 - JavaScript de qualidade: hoje, amanhĂŁ e sempre!
TDC 2014 - JavaScript de qualidade: hoje, amanhĂŁ e sempre!TDC 2014 - JavaScript de qualidade: hoje, amanhĂŁ e sempre!
TDC 2014 - JavaScript de qualidade: hoje, amanhĂŁ e sempre!Guilherme Carreiro
 
Naked Performance With Clojure
Naked Performance With ClojureNaked Performance With Clojure
Naked Performance With ClojureMetosin Oy
 
Reitit - Clojure/North 2019
Reitit - Clojure/North 2019Reitit - Clojure/North 2019
Reitit - Clojure/North 2019Metosin Oy
 
Command
CommandCommand
Commandgajshield
 
Your code is not a string
Your code is not a stringYour code is not a string
Your code is not a stringIngvar Stepanyan
 
Evolving Software with Moose
Evolving Software with MooseEvolving Software with Moose
Evolving Software with MooseDave Cross
 
Moose talk at FOSDEM 2011 (Perl devroom)
Moose talk at FOSDEM 2011 (Perl devroom)Moose talk at FOSDEM 2011 (Perl devroom)
Moose talk at FOSDEM 2011 (Perl devroom)xSawyer
 

Was ist angesagt? (18)

RubyEnRails2007 - Dr Nic Williams - Keynote
RubyEnRails2007 - Dr Nic Williams - KeynoteRubyEnRails2007 - Dr Nic Williams - Keynote
RubyEnRails2007 - Dr Nic Williams - Keynote
 
Bringing Characters to Life for Immersive Storytelling - Dioselin Gonzalez
Bringing Characters to Life for Immersive Storytelling - Dioselin GonzalezBringing Characters to Life for Immersive Storytelling - Dioselin Gonzalez
Bringing Characters to Life for Immersive Storytelling - Dioselin Gonzalez
 
A Few of My Favorite (Python) Things
A Few of My Favorite (Python) ThingsA Few of My Favorite (Python) Things
A Few of My Favorite (Python) Things
 
Writing Modular Command-line Apps with App::Cmd
Writing Modular Command-line Apps with App::CmdWriting Modular Command-line Apps with App::Cmd
Writing Modular Command-line Apps with App::Cmd
 
(Ab)Using the MetaCPAN API for Fun and Profit
(Ab)Using the MetaCPAN API for Fun and Profit(Ab)Using the MetaCPAN API for Fun and Profit
(Ab)Using the MetaCPAN API for Fun and Profit
 
Ruby Robots
Ruby RobotsRuby Robots
Ruby Robots
 
"The worst code I ever wrote"
"The worst code I ever wrote""The worst code I ever wrote"
"The worst code I ever wrote"
 
Malli: inside data-driven schemas
Malli: inside data-driven schemasMalli: inside data-driven schemas
Malli: inside data-driven schemas
 
Moose Best Practices
Moose Best PracticesMoose Best Practices
Moose Best Practices
 
Designing with malli
Designing with malliDesigning with malli
Designing with malli
 
Moose (Perl 5)
Moose (Perl 5)Moose (Perl 5)
Moose (Perl 5)
 
TDC 2014 - JavaScript de qualidade: hoje, amanhĂŁ e sempre!
TDC 2014 - JavaScript de qualidade: hoje, amanhĂŁ e sempre!TDC 2014 - JavaScript de qualidade: hoje, amanhĂŁ e sempre!
TDC 2014 - JavaScript de qualidade: hoje, amanhĂŁ e sempre!
 
Naked Performance With Clojure
Naked Performance With ClojureNaked Performance With Clojure
Naked Performance With Clojure
 
Reitit - Clojure/North 2019
Reitit - Clojure/North 2019Reitit - Clojure/North 2019
Reitit - Clojure/North 2019
 
Command
CommandCommand
Command
 
Your code is not a string
Your code is not a stringYour code is not a string
Your code is not a string
 
Evolving Software with Moose
Evolving Software with MooseEvolving Software with Moose
Evolving Software with Moose
 
Moose talk at FOSDEM 2011 (Perl devroom)
Moose talk at FOSDEM 2011 (Perl devroom)Moose talk at FOSDEM 2011 (Perl devroom)
Moose talk at FOSDEM 2011 (Perl devroom)
 

Ähnlich wie Cleanliness is Next to Domain-Specificity

Juggling Chainsaws: Perl and MongoDB
Juggling Chainsaws: Perl and MongoDBJuggling Chainsaws: Perl and MongoDB
Juggling Chainsaws: Perl and MongoDBDavid Golden
 
R57php 1231677414471772-2
R57php 1231677414471772-2R57php 1231677414471772-2
R57php 1231677414471772-2ady36
 
Postman On Steroids
Postman On SteroidsPostman On Steroids
Postman On SteroidsSara Tornincasa
 
Hidden treasures of Ruby
Hidden treasures of RubyHidden treasures of Ruby
Hidden treasures of RubyTom Crinson
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applicationselliando dias
 
Security Challenges in Node.js
Security Challenges in Node.jsSecurity Challenges in Node.js
Security Challenges in Node.jsWebsecurify
 
Let's build a parser!
Let's build a parser!Let's build a parser!
Let's build a parser!Boy Baukema
 
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Masahiro Nagano
 
SparkR - Play Spark Using R (20160909 HadoopCon)
SparkR - Play Spark Using R (20160909 HadoopCon)SparkR - Play Spark Using R (20160909 HadoopCon)
SparkR - Play Spark Using R (20160909 HadoopCon)wqchen
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applicationselliando dias
 
Rack Middleware
Rack MiddlewareRack Middleware
Rack MiddlewareLittleBIGRuby
 
CoffeeScript Design Patterns
CoffeeScript Design PatternsCoffeeScript Design Patterns
CoffeeScript Design PatternsTrevorBurnham
 
Interface de Voz con Rails
Interface de Voz con RailsInterface de Voz con Rails
Interface de Voz con RailsSvet Ivantchev
 
Apache Spark Workshop
Apache Spark WorkshopApache Spark Workshop
Apache Spark WorkshopMichael Spector
 
Let's play a game with blackfire player
Let's play a game with blackfire playerLet's play a game with blackfire player
Let's play a game with blackfire playerMarcin Czarnecki
 
Dealing with Legacy Perl Code - Peter Scott
Dealing with Legacy Perl Code - Peter ScottDealing with Legacy Perl Code - Peter Scott
Dealing with Legacy Perl Code - Peter ScottO'Reilly Media
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers StealBen Scofield
 
I put on my mink and wizard behat (tutorial)
I put on my mink and wizard behat (tutorial)I put on my mink and wizard behat (tutorial)
I put on my mink and wizard behat (tutorial)xsist10
 

Ähnlich wie Cleanliness is Next to Domain-Specificity (20)

Juggling Chainsaws: Perl and MongoDB
Juggling Chainsaws: Perl and MongoDBJuggling Chainsaws: Perl and MongoDB
Juggling Chainsaws: Perl and MongoDB
 
R57php 1231677414471772-2
R57php 1231677414471772-2R57php 1231677414471772-2
R57php 1231677414471772-2
 
Postman On Steroids
Postman On SteroidsPostman On Steroids
Postman On Steroids
 
Hidden treasures of Ruby
Hidden treasures of RubyHidden treasures of Ruby
Hidden treasures of Ruby
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applications
 
Sphinx on Rails
Sphinx on RailsSphinx on Rails
Sphinx on Rails
 
Security Challenges in Node.js
Security Challenges in Node.jsSecurity Challenges in Node.js
Security Challenges in Node.js
 
Let's build a parser!
Let's build a parser!Let's build a parser!
Let's build a parser!
 
Perl basics for Pentesters
Perl basics for PentestersPerl basics for Pentesters
Perl basics for Pentesters
 
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
 
SparkR - Play Spark Using R (20160909 HadoopCon)
SparkR - Play Spark Using R (20160909 HadoopCon)SparkR - Play Spark Using R (20160909 HadoopCon)
SparkR - Play Spark Using R (20160909 HadoopCon)
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applications
 
Rack Middleware
Rack MiddlewareRack Middleware
Rack Middleware
 
CoffeeScript Design Patterns
CoffeeScript Design PatternsCoffeeScript Design Patterns
CoffeeScript Design Patterns
 
Interface de Voz con Rails
Interface de Voz con RailsInterface de Voz con Rails
Interface de Voz con Rails
 
Apache Spark Workshop
Apache Spark WorkshopApache Spark Workshop
Apache Spark Workshop
 
Let's play a game with blackfire player
Let's play a game with blackfire playerLet's play a game with blackfire player
Let's play a game with blackfire player
 
Dealing with Legacy Perl Code - Peter Scott
Dealing with Legacy Perl Code - Peter ScottDealing with Legacy Perl Code - Peter Scott
Dealing with Legacy Perl Code - Peter Scott
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers Steal
 
I put on my mink and wizard behat (tutorial)
I put on my mink and wizard behat (tutorial)I put on my mink and wizard behat (tutorial)
I put on my mink and wizard behat (tutorial)
 

Mehr von Viget Labs

Building a Brand as Consumers Take Control
Building a Brand as Consumers Take ControlBuilding a Brand as Consumers Take Control
Building a Brand as Consumers Take ControlViget Labs
 
Branded Utility By Josh Chambers
Branded Utility By Josh ChambersBranded Utility By Josh Chambers
Branded Utility By Josh ChambersViget Labs
 
Make Everyone a Tester: Natural Language Acceptance Testing
Make Everyone a Tester: Natural Language Acceptance TestingMake Everyone a Tester: Natural Language Acceptance Testing
Make Everyone a Tester: Natural Language Acceptance TestingViget Labs
 
Women In Technology
Women In TechnologyWomen In Technology
Women In TechnologyViget Labs
 
9 Tips to Profitability: How Squidoo Did It
9 Tips to Profitability: How Squidoo Did It9 Tips to Profitability: How Squidoo Did It
9 Tips to Profitability: How Squidoo Did ItViget Labs
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful RailsViget Labs
 
Hows Haml?
Hows Haml?Hows Haml?
Hows Haml?Viget Labs
 
Changing Your Mindset: Getting Started With Test-Driven Development
Changing Your Mindset: Getting Started With Test-Driven DevelopmentChanging Your Mindset: Getting Started With Test-Driven Development
Changing Your Mindset: Getting Started With Test-Driven DevelopmentViget Labs
 
Dealing With Legacy PHP Applications
Dealing With Legacy PHP ApplicationsDealing With Legacy PHP Applications
Dealing With Legacy PHP ApplicationsViget Labs
 
Mockfight! FlexMock vs. Mocha
Mockfight! FlexMock vs. MochaMockfight! FlexMock vs. Mocha
Mockfight! FlexMock vs. MochaViget Labs
 
Building and Working With Static Sites in Ruby on Rails
Building and Working With Static Sites in Ruby on RailsBuilding and Working With Static Sites in Ruby on Rails
Building and Working With Static Sites in Ruby on RailsViget Labs
 

Mehr von Viget Labs (11)

Building a Brand as Consumers Take Control
Building a Brand as Consumers Take ControlBuilding a Brand as Consumers Take Control
Building a Brand as Consumers Take Control
 
Branded Utility By Josh Chambers
Branded Utility By Josh ChambersBranded Utility By Josh Chambers
Branded Utility By Josh Chambers
 
Make Everyone a Tester: Natural Language Acceptance Testing
Make Everyone a Tester: Natural Language Acceptance TestingMake Everyone a Tester: Natural Language Acceptance Testing
Make Everyone a Tester: Natural Language Acceptance Testing
 
Women In Technology
Women In TechnologyWomen In Technology
Women In Technology
 
9 Tips to Profitability: How Squidoo Did It
9 Tips to Profitability: How Squidoo Did It9 Tips to Profitability: How Squidoo Did It
9 Tips to Profitability: How Squidoo Did It
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful Rails
 
Hows Haml?
Hows Haml?Hows Haml?
Hows Haml?
 
Changing Your Mindset: Getting Started With Test-Driven Development
Changing Your Mindset: Getting Started With Test-Driven DevelopmentChanging Your Mindset: Getting Started With Test-Driven Development
Changing Your Mindset: Getting Started With Test-Driven Development
 
Dealing With Legacy PHP Applications
Dealing With Legacy PHP ApplicationsDealing With Legacy PHP Applications
Dealing With Legacy PHP Applications
 
Mockfight! FlexMock vs. Mocha
Mockfight! FlexMock vs. MochaMockfight! FlexMock vs. Mocha
Mockfight! FlexMock vs. Mocha
 
Building and Working With Static Sites in Ruby on Rails
Building and Working With Static Sites in Ruby on RailsBuilding and Working With Static Sites in Ruby on Rails
Building and Working With Static Sites in Ruby on Rails
 

KĂŒrzlich hochgeladen

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
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
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
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxnull - The Open Security Community
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraDeakin University
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
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
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024BookNet Canada
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 

KĂŒrzlich hochgeladen (20)

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
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
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
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning era
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
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
 
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
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 

Cleanliness is Next to Domain-Specificity