SlideShare une entreprise Scribd logo
1  sur  69
Télécharger pour lire hors ligne
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

Contenu connexe

Tendances

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
 

Tendances (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)
 

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

Similaire à 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)
 

Plus 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
 

Plus 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
 

Dernier

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
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
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
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 

Dernier (20)

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
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
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
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
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
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 

Cleanliness is Next to Domain-Specificity