SlideShare una empresa de Scribd logo
1 de 69
Descargar para leer sin conexión
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.flickr.com/photos/cwsteeds/58514985/
Write a Parser?
 No, Thanks.



            http://www.flickr.com/photos/rooreynolds/243810988/
http://www.flickr.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

Más contenido relacionado

La actualidad más candente

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
 
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
 

La actualidad más candente (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)
 

Similar a 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
 
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
 
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
 
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
 

Similar a 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)
 

Más de 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
 
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
 

Más de 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
 

Último

CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
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
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
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
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 

Último (20)

CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
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
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
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
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 

Cleanliness is Next to Domain-Specificity