SlideShare una empresa de Scribd logo
1 de 116
Descargar para leer sin conexión
Poetic APIs     by Erik Rose


 “A poet is, before anything else, a person
 who is passionately in love with language.”
              —W. H. Auden
Poetic APIs     by Erik Rose

   programmer
     ^
 “A poet is, before anything else, a person
 who is passionately in love with language.”
              —W. H. Auden
“Language is the best way of getting ideas
from one head into another without surgery.”
               —Mark Twain
“Oh! Everything has a name!”
“The window became a different thing by
    having a symbol attached to it.”
Inventing
   Language
 “Any fool can write code that a computer can understand.
Good programmers write code that humans can understand.”
                     —Martin Fowler
req = urllib2.Request(gh_url)
password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(
    None, 'https://api.github.com', 'user', 'pass')
auth_manager = urllib2.HTTPBasicAuthHandler(password_manager)
opener = urllib2.build_opener(auth_manager)
urllib2.install_opener(opener)
handler = urllib2.urlopen(req)
print handler.getcode()
req = urllib2.Request(gh_url)
password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(
    None, 'https://api.github.com', 'user', 'pass')
auth_manager = urllib2.HTTPBasicAuthHandler(password_manager)
opener = urllib2.build_opener(auth_manager)
urllib2.install_opener(opener)
handler = urllib2.urlopen(req)
print handler.getcode()




r = requests.get('https://api.github.com', auth=('user', 'pass'))
print r.status_code
Don’t Be An
Architecture
 Astronaut
“It’s hard to make predictions, especially about the future.”
                 —Robert Storm Petersen
The best libraries are extracted, not invented.
def terminal_codes(self, stream):
    capabilities = ['bold', 'sc', 'rc', 'sgr0', 'el']
    if hasattr(stream, 'fileno') and isatty(stream.fileno()):
        # Explicit args make setupterm() work even when -s is passed:
        setupterm(None, stream.fileno()) # so things like tigetstr() work
        codes = dict((x, tigetstr(x)) for x in capabilities)
        cup = tigetstr('cup')
        codes['cup'] = lambda line, column: tparm(cup, line, column)
    else:
        # If you're crazy enough to pipe this to a file or something,
        # don't output terminal codes:
        codes = defaultdict(lambda: '', cup=lambda line, column: '')
    return codes

...
self._codes = terminal_codes(stdout)
...

class AtLine(object):
    def __enter__(self):
        """Save position and move to progress bar, col 1."""
        self.stream.write(self._codes['sc']) # save position
        self.stream.write(self._codes['cup'](self.line, 0))

    def __exit__(self, type, value, tb):
        self.stream.write(self._codes['rc']) # restore position

...
print self._codes['bold'] + results + self._codes['sgr0']
Tasks
Tasks
Print some text with formatting.
Tasks
      Print some text with formatting.
Print some text at a location, then snap back.
Language Constructs
Language Constructs
Functions, arguments, keyword arguments
Language Constructs
Functions, arguments, keyword arguments
              Decorators
Language Constructs
Functions, arguments, keyword arguments
              Decorators
           Context managers
Language Constructs
   Functions, arguments, keyword arguments
                   Decorators
               Context managers
Classes (really more of an implementation detail)
Language Constructs
         Functions, arguments, keyword arguments
                         Decorators
                     Context managers
      Classes (really more of an implementation detail)


                          å
Patterns, Protocols, Interfaces, and Conventions
Language Constructs
         Functions, arguments, keyword arguments
                         Decorators
                     Context managers
      Classes (really more of an implementation detail)


                          å
Patterns, Protocols, Interfaces, and Conventions
                        Sequences
Language Constructs
         Functions, arguments, keyword arguments
                         Decorators
                     Context managers
      Classes (really more of an implementation detail)


                          å
Patterns, Protocols, Interfaces, and Conventions
                        Sequences
                         Iterators
Language Constructs
         Functions, arguments, keyword arguments
                         Decorators
                     Context managers
      Classes (really more of an implementation detail)


                          å
Patterns, Protocols, Interfaces, and Conventions
                        Sequences
                         Iterators
                        Mappings
Consistency
  “Think like a wise man, but communicate
       in the language of the people.”
           —William Butler Yeats
get(key, default)

    is better than
fetch(default, key)
Tasks
Print some text at a location, then snap back.
      Print some text with formatting.
Tasks
        Print some text at a location, then snap back.
              Print some text with formatting.



print_at('Hello world', 10, 2)

with location(10, 2):
    print 'Hello world'
    for thing in range(10):
        print thing
Tasks
        Print some text at a location, then snap back.
              Print some text with formatting.



print_formatted('Hello world', 'red', 'bold')
print color('Hello world', 'red', 'bold')
print color('<red><bold>Hello world</bold></red>')
print red(bold('Hello') + 'world')

print codes['red'] + codes['bold'] + 
      'Hello world' + codes['normal']

print '{t.red}Hi{t.bold}Mom{t.normal}'.format(t=terminal)
print terminal.red_bold + 'Hello world' + terminal.normal
Tasks
        Print some text at a location, then snap back.
              Print some text with formatting.



print_formatted('Hello world', 'red', 'bold')
print color('Hello world', 'red', 'bold')
print color('<red><bold>Hello world</bold></red>')
print red(bold('Hello') + 'world')

print codes['red'] + codes['bold'] + 
      'Hello world' + codes['normal']

print '{t.red}Hi{t.bold}Mom{t.normal}'.format(t=terminal)
print terminal.red_bold + 'Hello world' + terminal.normal
Tasks
        Print some text at a location, then snap back.
              Print some text with formatting.



print_formatted('Hello world', 'red', 'bold')
print color('Hello world', 'red', 'bold')
print color('<red><bold>Hello world</bold></red>')
print red(bold('Hello') + 'world')

print codes['red'] + codes['bold'] + 
      'Hello world' + codes['normal']

print '{t.red}Hi{t.bold}Mom{t.normal}'.format(t=terminal)
print terminal.red_bold + 'Hello world' + terminal.normal
Tasks
        Print some text at a location, then snap back.
              Print some text with formatting.



print_formatted('Hello world', 'red', 'bold')
print color('Hello world', 'red', 'bold')
print color('<red><bold>Hello world</bold></red>')
print red(bold('Hello') + 'world')

print codes['red'] + codes['bold'] + 
      'Hello world' + codes['normal']

print '{t.red}Hi{t.bold}Mom{t.normal}'.format(t=terminal)
print terminal.red_bold + 'Hello world' + terminal.normal
from blessings import Terminal

t = Terminal()

print t.red_bold + 'Hello world' + t.normal
print t.red_on_white + 'Hello world' + t.normal
print t.underline_red_on_green + 'Hello world' + t.normal
from blessings import Terminal

t = Terminal()

print t.red_bold + 'Hello world' + t.normal
print t.red_on_white + 'Hello world' + t.normal
print t.underline_red_on_green + 'Hello world' + t.normal




Article.objects.filter(tag__in=['color_red', 'color_blue'])
Article.objects.filter(tag__contains='color')
Consistency
   warning signs
Consistency  warning signs
  Frequent references to your docs or source
Consistency  warning signs
  Frequent references to your docs or source
         Feeling syntactically clever
Brevity
“The finest language is mostly made up
    of simple, unimposing words.”
             —George Eliot
from blessings import Terminal
term = Terminal()

print term.bold + 'I am bold!' + term.normal
from blessings import Terminal
term = Terminal()

print term.bold + 'I am bold!' + term.normal

print term.bold('I am bold!')
from blessings import Terminal
term = Terminal()

print term.bold + 'I am bold!' + term.normal

print term.bold('I am bold!')

print '{t.bold}Very {t.red}emphasized{t.normal}'.format(t=term)
Brevity
 warning signs
Brevity  warning signs
Copying and pasting when writing against your API
Brevity  warning signs
Copying and pasting when writing against your API
  Typing something irrelevant while grumbling
  “Why can’t it just assume the obvious thing?”
Composability
 “Perfection is achieved not when there is nothing left to add
         but when there is nothing left to take away.”
                 —Antoine de Saint-Exupery
print_formatted('Hello world', 'red', 'bold')
print_formatted('Hello world', 'red', 'bold')

print_formatted('Hello world', 'red', 'bold', out=some_file)
print_formatted('Hello world', 'red', 'bold')

print_formatted('Hello world', 'red', 'bold', out=some_file)

print formatted('Hello world', 'red', 'bold')
Composabilty
    warning signs
Composabilty
     warning signs
   Classes with lots of state
Composabilty
                                        warning signs
                                     Classes with lots of state
class ElasticSearch(object):
    """
    An object which manages connections to elasticsearch and acts as a
    go-between for API calls to it"""

   def index(self, index, doc_type, doc, id=None, force_insert=False,
             query_params=None):
       """Put a typed JSON document into a specific index to make it
       searchable."""

   def search(self, query, **kwargs):
       """Execute a search query against one or more indices and get back search
       hits."""

   def more_like_this(self, index, doc_type, id, mlt_fields, body='', query_params=None):
       """Execute a "more like this" search query against one or more fields and
       get back search hits."""

    . . .
Composabilty
                                         warning signs
                                     Classes with lots of state
class ElasticSearch(object):
    """
                               class PenaltyBox(object):
    An object which manages connections to elasticsearch and acts as a
                                   """A thread-safe bucket of servers (or other things) that may have
    go-between for API calls to it"""
                                   downtime."""
    def index(self, index, doc_type, doc, id=None, force_insert=False,
              query_params=None): def get(self):
        """Put a typed JSON document into a specific index server and a bool indicating whether it was from the
                                       """Return a random to make it
        searchable."""                 dead list."""

    def search(self, query, **kwargs): mark_dead(self, server):
                                   def
        """Execute a search query against one or more indices and get won't search
                                       """Guarantee that this server back be returned again until a period of
        hits."""                       time has passed, unless all servers are dead."""

    def more_like_this(self, index, def mark_live(self, server):
                                     doc_type, id, mlt_fields, body='', query_params=None):
        """Execute a "more like this" search query against one or dead list to and live one."""
                                        """Move a server from the more fields the
        get back search hits."""

    . . .
Composabilty
       warning signs
    Classes with lots of state
   Deep inheritance hierarchies
Composabilty
         warning signs
      Classes with lots of state
     Deep inheritance hierarchies
   Violations of the Law of Demeter
Composabilty
         warning signs
      Classes with lots of state
     Deep inheritance hierarchies
   Violations of the Law of Demeter
           Mocking in tests
Composabilty
                    warning signs
                 Classes with lots of state
                Deep inheritance hierarchies
              Violations of the Law of Demeter
                      Mocking in tests

print_formatted('Hello world', 'red', 'bold')
Composabilty
                    warning signs
                 Classes with lots of state
                Deep inheritance hierarchies
              Violations of the Law of Demeter
                      Mocking in tests

print_formatted('Hello world', 'red', 'bold')

print formatted('Hello world', 'red', 'bold')
Composabilty
         warning signs
      Classes with lots of state
     Deep inheritance hierarchies
   Violations of the Law of Demeter
           Mocking in tests
               Options
Plain Data
 “All the great things are simple, and many
   can be expressed in a single word…”
          —Sir Winston Churchill
✚
✚
✚   ✚
✚         ✚
RawConfigParser.parse(string)
✚         ✚
RawConfigParser.parse(string)

charming_parser.parse(file_contents('some_file.ini'))
class Node(dict):
    """A wrapper around a native Reflect.parse dict
    providing some convenience methods and some caching
    of expensive computations"""
class Node(dict):
    """A wrapper around a native Reflect.parse dict
    providing some convenience methods and some caching
    of expensive computations"""

   def walk_up(self):
       """Yield each node from here to the root of the
       tree, starting with myself."""
       node = self
       while node:
           yield node
           node = node.get('_parent')
class Node(dict):
    """A wrapper around a native Reflect.parse dict
    providing some convenience methods and some caching
    of expensive computations"""

   def walk_up(self):
       """Yield each node from here to the root of the
       tree, starting with myself."""
       node = self
       while node:
           yield node
           node = node.get('_parent')

   def nearest_scope_holder(self):
       """Return the nearest node that can have its own
       scope, potentially including myself.

       This will be either a FunctionDeclaration or a
       Program (for now).

       """
       return first(n for n in self.walk_up() if
                    n['type'] in ['FunctionDeclaration',
                                  'Program'])
Plain Data
   warning signs
Plain Data         warning signs

Users immediately transforming your output to another format
Plain Data         warning signs

Users immediately transforming your output to another format
       Instantiating one object just to pass it to another
Grooviness
“The bad teacher’s words fall on his pupils like harsh rain;
          the good teacher’s, as gently as dew.”
                 —Talmud: Ta’anith 7b
Grooviness
  Groove   Wall
Avoid nonsense representations.
Avoid nonsense representations.
{
    "bool" : {
        "must" : {
            "term" : { "user" : "fred" }
        },
        "must_not" : {
            "range" : {
                "age" : { "from" : 12, "to" : 21 }
            }
        },
        "minimum_number_should_match" : 1,
        "boost" : 1.0
    }
}
Avoid nonsense representations.
{
    "bool" : {
        "must" : {
            "term" : { "user" : "fred" }
        },
        "must_not" : {
            "range" : {
                "age" : { "from" : 12, "to" : 21 }
            }
        },
        "minimum_number_should_match" : 1,
        "boost" : 1.0
    }
}

                                       frob*ator AND snork
Old pyelasticsearch
def search(self, q=None, body=None, indexes=None, doc_types=None):
    """Execute an elasticsearch query, and return the results."""
Old pyelasticsearch
def search(self, q=None, body=None, indexes=None, doc_types=None):
    """Execute an elasticsearch query, and return the results."""

search(q='frob*ator AND snork', body={'some': 'query'})
Old pyelasticsearch
def search(self, q=None, body=None, indexes=None, doc_types=None):
    """Execute an elasticsearch query, and return the results."""

search(q='frob*ator AND snork', body={'some': 'query'})
search()
Old pyelasticsearch
def search(self, q=None, body=None, indexes=None, doc_types=None):
    """Execute an elasticsearch query, and return the results."""

search(q='frob*ator AND snork', body={'some': 'query'})
search()
✚
Old pyelasticsearch
def search(self, q=None, body=None, indexes=None, doc_types=None):
    """Execute an elasticsearch query, and return the results."""

search(q='frob*ator AND snork', body={'some': 'query'})
search()
✚
                    New pyelasticsearch
def search(self, query, indexes=None, doc_types=None):
    """Execute an elasticsearch query, and return the results."""
Old pyelasticsearch
def search(self, q=None, body=None, indexes=None, doc_types=None):
    """Execute an elasticsearch query, and return the results."""

search(q='frob*ator AND snork', body={'some': 'query'})
search()
✚
                    New pyelasticsearch
def search(self, query, indexes=None, doc_types=None):
    """Execute an elasticsearch query, and return the results."""




                        Fail shallowly.
Resource acquisition is initialization.
Resource acquisition is initialization.
class PoppableBalloon(object):
    """A balloon you can pop"""

   def __init__(self):
       self.air = 0

   def fill(self, how_much):
       self.air = how_much
Resource acquisition is initialization.
class PoppableBalloon(object):
    """A balloon you can pop"""

   def __init__(self):
       self.air = 0

   def fill(self, how_much):
       self.air = how_much




class PoppableBalloon(object):
    """A balloon you can pop"""

   def __init__(self, initial_fill):
       self.air = initial_fill

   def fill(self, how_much):
       self.air = how_much
Compelling examples
Compelling examples
Grooviness
   warning signs
Grooviness
         warning signs
  Nonsense states or representations
Grooviness
         warning signs
  Nonsense states or representations
       Invariants that aren’t
Grooviness
         warning signs
  Nonsense states or representations
       Invariants that aren’t
  Users unclear where to get started
Grooviness
         warning signs
  Nonsense states or representations
       Invariants that aren’t
  Users unclear where to get started
  Long, complicated documentation
Safety
“I wish it was easier to hurt myself.”
           —Nobody, ever
Safety
Groove   Wall
update things set frob=2 where frob=1;
update things set frob=2 where frob=1;

update things set frob=2;
update things set frob=2 where frob=1;

update things set frob=2;

update things set frob=2 all;
update things set frob=2 where frob=1;

update things set frob=2;

update things set frob=2 all;




rm *.pyc
update things set frob=2 where frob=1;

update things set frob=2;

update things set frob=2 all;




rm *.pyc
rm *
update things set frob=2 where frob=1;

update things set frob=2;

update things set frob=2 all;




rm *.pyc
rm *
rm -f *
def delete(self, index, doc_type, id=None):
    """Delete a typed JSON document from a specific
    index based on its id."""
def delete(self, index, doc_type, id=None):
    """Delete a typed JSON document from a specific
    index based on its id."""
def delete(self, index, doc_type, id=None):
    """Delete a typed JSON document from a specific
    index based on its id."""




def delete(self, index, doc_type, id):
    """Delete a typed JSON document from a specific
    index based on its id."""

def delete_all(self, index, doc_type):
    """Delete all documents of the given doctype from
    an index."""
Error reporting: exceptions are typically safer.
Safety
 warning signs
Safetywarning signs

Surprisingly few—people will blame themselves.
non-astronautics
                     consistency
      brevity
                   composability
 plain data
                   grooviness
     safety
non-astronautics         consistency
brevity                composability




plain data               grooviness
              safety
non-astronautics                     consistency
brevity                            composability

   Elegance?
          “It is the ineffable will of Bob.”
                  —Old Thrashbarg
plain data                               grooviness
                    safety
Preflight
Architecture Astronautics               ✖ Instantiating one object just to pass
✖ Inventing rather than extracting        it to another

Consistency                             Composability
✖ Frequent references to your docs or   ✖   Classes with lots of state
  source                                ✖   Deep inheritance hierarchies
✖ Feeling syntactically clever          ✖   Violations of the Law of Demeter
                                        ✖   Mocking in tests
Brevity                                 ✖   Bolted-on options
✖ Copying and pasting when writing
  against your API                      Grooviness
✖ Grumbling about having to hand-       ✖   Nonsense states
  hold the API                          ✖   Invariants that aren’t
                                        ✖   No clear introductory path
Plain Data
                                        ✖   Long, tricky documentation
✖ Users immediately transforming
  your output to another format         Safety
                                        ✖ Ease of hurting self or others
Thank You
    twitter: ErikRose
  www.grinchcentral.com
    erik@mozilla.com

Más contenido relacionado

La actualidad más candente (14)

Moose (Perl 5)
Moose (Perl 5)Moose (Perl 5)
Moose (Perl 5)
 
Ruby_Basic
Ruby_BasicRuby_Basic
Ruby_Basic
 
Introduction to Moose
Introduction to MooseIntroduction to Moose
Introduction to Moose
 
Moose Best Practices
Moose Best PracticesMoose Best Practices
Moose Best Practices
 
OO Perl with Moose
OO Perl with MooseOO Perl with Moose
OO Perl with Moose
 
Hw1 rubycalisthenics
Hw1 rubycalisthenicsHw1 rubycalisthenics
Hw1 rubycalisthenics
 
Introduction To Moose
Introduction To MooseIntroduction To Moose
Introduction To Moose
 
The Art Of Readable Code
The Art Of Readable CodeThe Art Of Readable Code
The Art Of Readable Code
 
Natural Language Toolkit (NLTK), Basics
Natural Language Toolkit (NLTK), Basics Natural Language Toolkit (NLTK), Basics
Natural Language Toolkit (NLTK), Basics
 
PHP Classes and OOPS Concept
PHP Classes and OOPS ConceptPHP Classes and OOPS Concept
PHP Classes and OOPS Concept
 
10 classes
10 classes10 classes
10 classes
 
Elixir for rubysts
Elixir for rubystsElixir for rubysts
Elixir for rubysts
 
Beauty and/or elegance in functional programming
Beauty and/or elegance in functional programmingBeauty and/or elegance in functional programming
Beauty and/or elegance in functional programming
 
React.js Basics - ConvergeSE 2015
React.js Basics - ConvergeSE 2015React.js Basics - ConvergeSE 2015
React.js Basics - ConvergeSE 2015
 

Similar a Poetic APIs: How to design expressive yet practical APIs

Tools for the Toolmakers
Tools for the ToolmakersTools for the Toolmakers
Tools for the ToolmakersCaleb Callaway
 
Basics of Python programming (part 2)
Basics of Python programming (part 2)Basics of Python programming (part 2)
Basics of Python programming (part 2)Pedro Rodrigues
 
Ruby 1.9.3 Basic Introduction
Ruby 1.9.3 Basic IntroductionRuby 1.9.3 Basic Introduction
Ruby 1.9.3 Basic IntroductionPrabu D
 
WordPress Plugin Localization
WordPress Plugin LocalizationWordPress Plugin Localization
WordPress Plugin LocalizationRonald Huereca
 
Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...
Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...
Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...Eelco Visser
 
Workshop presentation hands on r programming
Workshop presentation hands on r programmingWorkshop presentation hands on r programming
Workshop presentation hands on r programmingNimrita Koul
 
Crystal presentation in NY
Crystal presentation in NYCrystal presentation in NY
Crystal presentation in NYCrystal Language
 
Ruby -the wheel Technology
Ruby -the wheel TechnologyRuby -the wheel Technology
Ruby -the wheel Technologyppparthpatel123
 
An Intro to Python in 30 minutes
An Intro to Python in 30 minutesAn Intro to Python in 30 minutes
An Intro to Python in 30 minutesSumit Raj
 
PuppetConf 2017: Puppet Tasks: Taming ssh in a "for" loop- Alex Dreyer, Puppet
PuppetConf 2017: Puppet Tasks: Taming ssh in a "for" loop- Alex Dreyer, PuppetPuppetConf 2017: Puppet Tasks: Taming ssh in a "for" loop- Alex Dreyer, Puppet
PuppetConf 2017: Puppet Tasks: Taming ssh in a "for" loop- Alex Dreyer, PuppetPuppet
 

Similar a Poetic APIs: How to design expressive yet practical APIs (20)

An introduction to Ruby
An introduction to RubyAn introduction to Ruby
An introduction to Ruby
 
Python basic
Python basicPython basic
Python basic
 
Rails by example
Rails by exampleRails by example
Rails by example
 
Tools for the Toolmakers
Tools for the ToolmakersTools for the Toolmakers
Tools for the Toolmakers
 
python.pdf
python.pdfpython.pdf
python.pdf
 
Basics of Python programming (part 2)
Basics of Python programming (part 2)Basics of Python programming (part 2)
Basics of Python programming (part 2)
 
Ruby 1.9.3 Basic Introduction
Ruby 1.9.3 Basic IntroductionRuby 1.9.3 Basic Introduction
Ruby 1.9.3 Basic Introduction
 
WordPress Plugin Localization
WordPress Plugin LocalizationWordPress Plugin Localization
WordPress Plugin Localization
 
Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...
Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...
Model-Driven Software Development - Pretty-Printing, Editor Services, Term Re...
 
ppt
pptppt
ppt
 
ppt
pptppt
ppt
 
Workshop presentation hands on r programming
Workshop presentation hands on r programmingWorkshop presentation hands on r programming
Workshop presentation hands on r programming
 
Crystal presentation in NY
Crystal presentation in NYCrystal presentation in NY
Crystal presentation in NY
 
Ruby -the wheel Technology
Ruby -the wheel TechnologyRuby -the wheel Technology
Ruby -the wheel Technology
 
Effective Object Oriented Design in Cpp
Effective Object Oriented Design in CppEffective Object Oriented Design in Cpp
Effective Object Oriented Design in Cpp
 
C#
C#C#
C#
 
DSL in scala
DSL in scalaDSL in scala
DSL in scala
 
An Intro to Python in 30 minutes
An Intro to Python in 30 minutesAn Intro to Python in 30 minutes
An Intro to Python in 30 minutes
 
Term Rewriting
Term RewritingTerm Rewriting
Term Rewriting
 
PuppetConf 2017: Puppet Tasks: Taming ssh in a "for" loop- Alex Dreyer, Puppet
PuppetConf 2017: Puppet Tasks: Taming ssh in a "for" loop- Alex Dreyer, PuppetPuppetConf 2017: Puppet Tasks: Taming ssh in a "for" loop- Alex Dreyer, Puppet
PuppetConf 2017: Puppet Tasks: Taming ssh in a "for" loop- Alex Dreyer, Puppet
 

Más de Erik Rose

Fathom Overview and Future, San Francisco 2018
Fathom Overview and Future, San Francisco 2018Fathom Overview and Future, San Francisco 2018
Fathom Overview and Future, San Francisco 2018Erik Rose
 
What happens when firefox crashes?
What happens when firefox crashes?What happens when firefox crashes?
What happens when firefox crashes?Erik Rose
 
Es part 2 pdf no build
Es part 2 pdf no buildEs part 2 pdf no build
Es part 2 pdf no buildErik Rose
 
Fluid, Fluent APIs
Fluid, Fluent APIsFluid, Fluent APIs
Fluid, Fluent APIsErik Rose
 
Django’s nasal passage
Django’s nasal passageDjango’s nasal passage
Django’s nasal passageErik Rose
 
WebLion Hosting: Leveraging Laziness, Impatience, and Hubris
WebLion Hosting: Leveraging Laziness, Impatience, and HubrisWebLion Hosting: Leveraging Laziness, Impatience, and Hubris
WebLion Hosting: Leveraging Laziness, Impatience, and HubrisErik Rose
 
WebLion Hosting Lightning Talk
WebLion Hosting Lightning TalkWebLion Hosting Lightning Talk
WebLion Hosting Lightning TalkErik Rose
 
Protecting Plone from the Big, Bad Internet
Protecting Plone from the Big, Bad InternetProtecting Plone from the Big, Bad Internet
Protecting Plone from the Big, Bad InternetErik Rose
 

Más de Erik Rose (9)

Fathom Overview and Future, San Francisco 2018
Fathom Overview and Future, San Francisco 2018Fathom Overview and Future, San Francisco 2018
Fathom Overview and Future, San Francisco 2018
 
What happens when firefox crashes?
What happens when firefox crashes?What happens when firefox crashes?
What happens when firefox crashes?
 
Es part 2 pdf no build
Es part 2 pdf no buildEs part 2 pdf no build
Es part 2 pdf no build
 
Fluid, Fluent APIs
Fluid, Fluent APIsFluid, Fluent APIs
Fluid, Fluent APIs
 
Django’s nasal passage
Django’s nasal passageDjango’s nasal passage
Django’s nasal passage
 
Stackful
StackfulStackful
Stackful
 
WebLion Hosting: Leveraging Laziness, Impatience, and Hubris
WebLion Hosting: Leveraging Laziness, Impatience, and HubrisWebLion Hosting: Leveraging Laziness, Impatience, and Hubris
WebLion Hosting: Leveraging Laziness, Impatience, and Hubris
 
WebLion Hosting Lightning Talk
WebLion Hosting Lightning TalkWebLion Hosting Lightning Talk
WebLion Hosting Lightning Talk
 
Protecting Plone from the Big, Bad Internet
Protecting Plone from the Big, Bad InternetProtecting Plone from the Big, Bad Internet
Protecting Plone from the Big, Bad Internet
 

Último

Spain Vs Italy 20 players confirmed for Spain's Euro 2024 squad, and three po...
Spain Vs Italy 20 players confirmed for Spain's Euro 2024 squad, and three po...Spain Vs Italy 20 players confirmed for Spain's Euro 2024 squad, and three po...
Spain Vs Italy 20 players confirmed for Spain's Euro 2024 squad, and three po...World Wide Tickets And Hospitality
 
Croatia vs Albania Clash of Euro Cup 2024 Squad Preparations and Euro Cup Dre...
Croatia vs Albania Clash of Euro Cup 2024 Squad Preparations and Euro Cup Dre...Croatia vs Albania Clash of Euro Cup 2024 Squad Preparations and Euro Cup Dre...
Croatia vs Albania Clash of Euro Cup 2024 Squad Preparations and Euro Cup Dre...Eticketing.co
 
ALL NFL NETWORK CONTACTS- April 29, 2024
ALL NFL NETWORK CONTACTS- April 29, 2024ALL NFL NETWORK CONTACTS- April 29, 2024
ALL NFL NETWORK CONTACTS- April 29, 2024Brian Slack
 
08448380779 Call Girls In Lajpat Nagar Women Seeking Men
08448380779 Call Girls In Lajpat Nagar Women Seeking Men08448380779 Call Girls In Lajpat Nagar Women Seeking Men
08448380779 Call Girls In Lajpat Nagar Women Seeking MenDelhi Call girls
 
Jankipuram / Call Girls Lucknow | Whatsapp No 🫗 8923113531 🎳 VIP Escorts Serv...
Jankipuram / Call Girls Lucknow | Whatsapp No 🫗 8923113531 🎳 VIP Escorts Serv...Jankipuram / Call Girls Lucknow | Whatsapp No 🫗 8923113531 🎳 VIP Escorts Serv...
Jankipuram / Call Girls Lucknow | Whatsapp No 🫗 8923113531 🎳 VIP Escorts Serv...gurkirankumar98700
 
Chennai Call Girls Anna Nagar Phone 🍆 8250192130 👅 celebrity escorts service
Chennai Call Girls Anna Nagar Phone 🍆 8250192130 👅 celebrity escorts serviceChennai Call Girls Anna Nagar Phone 🍆 8250192130 👅 celebrity escorts service
Chennai Call Girls Anna Nagar Phone 🍆 8250192130 👅 celebrity escorts servicevipmodelshub1
 
JORNADA 5 LIGA MURO 2024INSUGURACION.pdf
JORNADA 5 LIGA MURO 2024INSUGURACION.pdfJORNADA 5 LIGA MURO 2024INSUGURACION.pdf
JORNADA 5 LIGA MURO 2024INSUGURACION.pdfArturo Pacheco Alvarez
 
Plan d'orientations stratégiques rugby féminin
Plan d'orientations stratégiques rugby fémininPlan d'orientations stratégiques rugby féminin
Plan d'orientations stratégiques rugby fémininThibaut TATRY
 
Tableaux 9ème étape circuit fédéral 2024
Tableaux 9ème étape circuit fédéral 2024Tableaux 9ème étape circuit fédéral 2024
Tableaux 9ème étape circuit fédéral 2024HechemLaameri
 
VIP Kolkata Call Girl Liluah 👉 8250192130 Available With Room
VIP Kolkata Call Girl Liluah 👉 8250192130  Available With RoomVIP Kolkata Call Girl Liluah 👉 8250192130  Available With Room
VIP Kolkata Call Girl Liluah 👉 8250192130 Available With Roomdivyansh0kumar0
 
Atlanta Dream Exec Dan Gadd on Driving Fan Engagement and Growth, Serving the...
Atlanta Dream Exec Dan Gadd on Driving Fan Engagement and Growth, Serving the...Atlanta Dream Exec Dan Gadd on Driving Fan Engagement and Growth, Serving the...
Atlanta Dream Exec Dan Gadd on Driving Fan Engagement and Growth, Serving the...Neil Horowitz
 
( Sports training) All topic (MCQs).pptx
( Sports training) All topic (MCQs).pptx( Sports training) All topic (MCQs).pptx
( Sports training) All topic (MCQs).pptxParshotamGupta1
 
JORNADA 4 LIGA MURO 2024TUXTEPEC1234.pdf
JORNADA 4 LIGA MURO 2024TUXTEPEC1234.pdfJORNADA 4 LIGA MURO 2024TUXTEPEC1234.pdf
JORNADA 4 LIGA MURO 2024TUXTEPEC1234.pdfArturo Pacheco Alvarez
 
🔝|97111༒99012🔝 Call Girls In {Delhi} Cr Park ₹5.5k Cash Payment With Room De...
🔝|97111༒99012🔝 Call Girls In  {Delhi} Cr Park ₹5.5k Cash Payment With Room De...🔝|97111༒99012🔝 Call Girls In  {Delhi} Cr Park ₹5.5k Cash Payment With Room De...
🔝|97111༒99012🔝 Call Girls In {Delhi} Cr Park ₹5.5k Cash Payment With Room De...Diya Sharma
 
大学学位办理《原版美国USD学位证书》圣地亚哥大学毕业证制作成绩单修改
大学学位办理《原版美国USD学位证书》圣地亚哥大学毕业证制作成绩单修改大学学位办理《原版美国USD学位证书》圣地亚哥大学毕业证制作成绩单修改
大学学位办理《原版美国USD学位证书》圣地亚哥大学毕业证制作成绩单修改atducpo
 
ppt on Myself, Occupation and my Interest
ppt on Myself, Occupation and my Interestppt on Myself, Occupation and my Interest
ppt on Myself, Occupation and my InterestNagaissenValaydum
 

Último (20)

Spain Vs Italy 20 players confirmed for Spain's Euro 2024 squad, and three po...
Spain Vs Italy 20 players confirmed for Spain's Euro 2024 squad, and three po...Spain Vs Italy 20 players confirmed for Spain's Euro 2024 squad, and three po...
Spain Vs Italy 20 players confirmed for Spain's Euro 2024 squad, and three po...
 
Croatia vs Albania Clash of Euro Cup 2024 Squad Preparations and Euro Cup Dre...
Croatia vs Albania Clash of Euro Cup 2024 Squad Preparations and Euro Cup Dre...Croatia vs Albania Clash of Euro Cup 2024 Squad Preparations and Euro Cup Dre...
Croatia vs Albania Clash of Euro Cup 2024 Squad Preparations and Euro Cup Dre...
 
ALL NFL NETWORK CONTACTS- April 29, 2024
ALL NFL NETWORK CONTACTS- April 29, 2024ALL NFL NETWORK CONTACTS- April 29, 2024
ALL NFL NETWORK CONTACTS- April 29, 2024
 
08448380779 Call Girls In Lajpat Nagar Women Seeking Men
08448380779 Call Girls In Lajpat Nagar Women Seeking Men08448380779 Call Girls In Lajpat Nagar Women Seeking Men
08448380779 Call Girls In Lajpat Nagar Women Seeking Men
 
Jankipuram / Call Girls Lucknow | Whatsapp No 🫗 8923113531 🎳 VIP Escorts Serv...
Jankipuram / Call Girls Lucknow | Whatsapp No 🫗 8923113531 🎳 VIP Escorts Serv...Jankipuram / Call Girls Lucknow | Whatsapp No 🫗 8923113531 🎳 VIP Escorts Serv...
Jankipuram / Call Girls Lucknow | Whatsapp No 🫗 8923113531 🎳 VIP Escorts Serv...
 
Chennai Call Girls Anna Nagar Phone 🍆 8250192130 👅 celebrity escorts service
Chennai Call Girls Anna Nagar Phone 🍆 8250192130 👅 celebrity escorts serviceChennai Call Girls Anna Nagar Phone 🍆 8250192130 👅 celebrity escorts service
Chennai Call Girls Anna Nagar Phone 🍆 8250192130 👅 celebrity escorts service
 
Call Girls In Vasundhara 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SERVICE
Call Girls In Vasundhara 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SERVICECall Girls In Vasundhara 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SERVICE
Call Girls In Vasundhara 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SERVICE
 
JORNADA 5 LIGA MURO 2024INSUGURACION.pdf
JORNADA 5 LIGA MURO 2024INSUGURACION.pdfJORNADA 5 LIGA MURO 2024INSUGURACION.pdf
JORNADA 5 LIGA MURO 2024INSUGURACION.pdf
 
Plan d'orientations stratégiques rugby féminin
Plan d'orientations stratégiques rugby fémininPlan d'orientations stratégiques rugby féminin
Plan d'orientations stratégiques rugby féminin
 
Tableaux 9ème étape circuit fédéral 2024
Tableaux 9ème étape circuit fédéral 2024Tableaux 9ème étape circuit fédéral 2024
Tableaux 9ème étape circuit fédéral 2024
 
Call Girls Service Noida Extension @9999965857 Delhi 🫦 No Advance VVIP 🍎 SER...
Call Girls Service Noida Extension @9999965857 Delhi 🫦 No Advance  VVIP 🍎 SER...Call Girls Service Noida Extension @9999965857 Delhi 🫦 No Advance  VVIP 🍎 SER...
Call Girls Service Noida Extension @9999965857 Delhi 🫦 No Advance VVIP 🍎 SER...
 
VIP Kolkata Call Girl Liluah 👉 8250192130 Available With Room
VIP Kolkata Call Girl Liluah 👉 8250192130  Available With RoomVIP Kolkata Call Girl Liluah 👉 8250192130  Available With Room
VIP Kolkata Call Girl Liluah 👉 8250192130 Available With Room
 
Atlanta Dream Exec Dan Gadd on Driving Fan Engagement and Growth, Serving the...
Atlanta Dream Exec Dan Gadd on Driving Fan Engagement and Growth, Serving the...Atlanta Dream Exec Dan Gadd on Driving Fan Engagement and Growth, Serving the...
Atlanta Dream Exec Dan Gadd on Driving Fan Engagement and Growth, Serving the...
 
Call Girls 🫤 Paharganj ➡️ 9999965857 ➡️ Delhi 🫦 Russian Escorts FULL ENJOY
Call Girls 🫤 Paharganj ➡️ 9999965857  ➡️ Delhi 🫦  Russian Escorts FULL ENJOYCall Girls 🫤 Paharganj ➡️ 9999965857  ➡️ Delhi 🫦  Russian Escorts FULL ENJOY
Call Girls 🫤 Paharganj ➡️ 9999965857 ➡️ Delhi 🫦 Russian Escorts FULL ENJOY
 
Call Girls 🫤 Malviya Nagar ➡️ 9999965857 ➡️ Delhi 🫦 Russian Escorts FULL ENJOY
Call Girls 🫤 Malviya Nagar ➡️ 9999965857  ➡️ Delhi 🫦  Russian Escorts FULL ENJOYCall Girls 🫤 Malviya Nagar ➡️ 9999965857  ➡️ Delhi 🫦  Russian Escorts FULL ENJOY
Call Girls 🫤 Malviya Nagar ➡️ 9999965857 ➡️ Delhi 🫦 Russian Escorts FULL ENJOY
 
( Sports training) All topic (MCQs).pptx
( Sports training) All topic (MCQs).pptx( Sports training) All topic (MCQs).pptx
( Sports training) All topic (MCQs).pptx
 
JORNADA 4 LIGA MURO 2024TUXTEPEC1234.pdf
JORNADA 4 LIGA MURO 2024TUXTEPEC1234.pdfJORNADA 4 LIGA MURO 2024TUXTEPEC1234.pdf
JORNADA 4 LIGA MURO 2024TUXTEPEC1234.pdf
 
🔝|97111༒99012🔝 Call Girls In {Delhi} Cr Park ₹5.5k Cash Payment With Room De...
🔝|97111༒99012🔝 Call Girls In  {Delhi} Cr Park ₹5.5k Cash Payment With Room De...🔝|97111༒99012🔝 Call Girls In  {Delhi} Cr Park ₹5.5k Cash Payment With Room De...
🔝|97111༒99012🔝 Call Girls In {Delhi} Cr Park ₹5.5k Cash Payment With Room De...
 
大学学位办理《原版美国USD学位证书》圣地亚哥大学毕业证制作成绩单修改
大学学位办理《原版美国USD学位证书》圣地亚哥大学毕业证制作成绩单修改大学学位办理《原版美国USD学位证书》圣地亚哥大学毕业证制作成绩单修改
大学学位办理《原版美国USD学位证书》圣地亚哥大学毕业证制作成绩单修改
 
ppt on Myself, Occupation and my Interest
ppt on Myself, Occupation and my Interestppt on Myself, Occupation and my Interest
ppt on Myself, Occupation and my Interest
 

Poetic APIs: How to design expressive yet practical APIs

  • 1. Poetic APIs by Erik Rose “A poet is, before anything else, a person who is passionately in love with language.” —W. H. Auden
  • 2. Poetic APIs by Erik Rose programmer ^ “A poet is, before anything else, a person who is passionately in love with language.” —W. H. Auden
  • 3. “Language is the best way of getting ideas from one head into another without surgery.” —Mark Twain
  • 4.
  • 6. “The window became a different thing by having a symbol attached to it.”
  • 7. Inventing Language “Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” —Martin Fowler
  • 8. req = urllib2.Request(gh_url) password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm() password_manager.add_password( None, 'https://api.github.com', 'user', 'pass') auth_manager = urllib2.HTTPBasicAuthHandler(password_manager) opener = urllib2.build_opener(auth_manager) urllib2.install_opener(opener) handler = urllib2.urlopen(req) print handler.getcode()
  • 9. req = urllib2.Request(gh_url) password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm() password_manager.add_password( None, 'https://api.github.com', 'user', 'pass') auth_manager = urllib2.HTTPBasicAuthHandler(password_manager) opener = urllib2.build_opener(auth_manager) urllib2.install_opener(opener) handler = urllib2.urlopen(req) print handler.getcode() r = requests.get('https://api.github.com', auth=('user', 'pass')) print r.status_code
  • 10. Don’t Be An Architecture Astronaut “It’s hard to make predictions, especially about the future.” —Robert Storm Petersen
  • 11.
  • 12. The best libraries are extracted, not invented.
  • 13.
  • 14.
  • 15. def terminal_codes(self, stream): capabilities = ['bold', 'sc', 'rc', 'sgr0', 'el'] if hasattr(stream, 'fileno') and isatty(stream.fileno()): # Explicit args make setupterm() work even when -s is passed: setupterm(None, stream.fileno()) # so things like tigetstr() work codes = dict((x, tigetstr(x)) for x in capabilities) cup = tigetstr('cup') codes['cup'] = lambda line, column: tparm(cup, line, column) else: # If you're crazy enough to pipe this to a file or something, # don't output terminal codes: codes = defaultdict(lambda: '', cup=lambda line, column: '') return codes ... self._codes = terminal_codes(stdout) ... class AtLine(object): def __enter__(self): """Save position and move to progress bar, col 1.""" self.stream.write(self._codes['sc']) # save position self.stream.write(self._codes['cup'](self.line, 0)) def __exit__(self, type, value, tb): self.stream.write(self._codes['rc']) # restore position ... print self._codes['bold'] + results + self._codes['sgr0']
  • 16. Tasks
  • 17. Tasks Print some text with formatting.
  • 18. Tasks Print some text with formatting. Print some text at a location, then snap back.
  • 21. Language Constructs Functions, arguments, keyword arguments Decorators
  • 22. Language Constructs Functions, arguments, keyword arguments Decorators Context managers
  • 23. Language Constructs Functions, arguments, keyword arguments Decorators Context managers Classes (really more of an implementation detail)
  • 24. Language Constructs Functions, arguments, keyword arguments Decorators Context managers Classes (really more of an implementation detail) å Patterns, Protocols, Interfaces, and Conventions
  • 25. Language Constructs Functions, arguments, keyword arguments Decorators Context managers Classes (really more of an implementation detail) å Patterns, Protocols, Interfaces, and Conventions Sequences
  • 26. Language Constructs Functions, arguments, keyword arguments Decorators Context managers Classes (really more of an implementation detail) å Patterns, Protocols, Interfaces, and Conventions Sequences Iterators
  • 27. Language Constructs Functions, arguments, keyword arguments Decorators Context managers Classes (really more of an implementation detail) å Patterns, Protocols, Interfaces, and Conventions Sequences Iterators Mappings
  • 28. Consistency “Think like a wise man, but communicate in the language of the people.” —William Butler Yeats
  • 29.
  • 30. get(key, default) is better than fetch(default, key)
  • 31. Tasks Print some text at a location, then snap back. Print some text with formatting.
  • 32. Tasks Print some text at a location, then snap back. Print some text with formatting. print_at('Hello world', 10, 2) with location(10, 2): print 'Hello world' for thing in range(10): print thing
  • 33. Tasks Print some text at a location, then snap back. Print some text with formatting. print_formatted('Hello world', 'red', 'bold') print color('Hello world', 'red', 'bold') print color('<red><bold>Hello world</bold></red>') print red(bold('Hello') + 'world') print codes['red'] + codes['bold'] + 'Hello world' + codes['normal'] print '{t.red}Hi{t.bold}Mom{t.normal}'.format(t=terminal) print terminal.red_bold + 'Hello world' + terminal.normal
  • 34. Tasks Print some text at a location, then snap back. Print some text with formatting. print_formatted('Hello world', 'red', 'bold') print color('Hello world', 'red', 'bold') print color('<red><bold>Hello world</bold></red>') print red(bold('Hello') + 'world') print codes['red'] + codes['bold'] + 'Hello world' + codes['normal'] print '{t.red}Hi{t.bold}Mom{t.normal}'.format(t=terminal) print terminal.red_bold + 'Hello world' + terminal.normal
  • 35. Tasks Print some text at a location, then snap back. Print some text with formatting. print_formatted('Hello world', 'red', 'bold') print color('Hello world', 'red', 'bold') print color('<red><bold>Hello world</bold></red>') print red(bold('Hello') + 'world') print codes['red'] + codes['bold'] + 'Hello world' + codes['normal'] print '{t.red}Hi{t.bold}Mom{t.normal}'.format(t=terminal) print terminal.red_bold + 'Hello world' + terminal.normal
  • 36. Tasks Print some text at a location, then snap back. Print some text with formatting. print_formatted('Hello world', 'red', 'bold') print color('Hello world', 'red', 'bold') print color('<red><bold>Hello world</bold></red>') print red(bold('Hello') + 'world') print codes['red'] + codes['bold'] + 'Hello world' + codes['normal'] print '{t.red}Hi{t.bold}Mom{t.normal}'.format(t=terminal) print terminal.red_bold + 'Hello world' + terminal.normal
  • 37. from blessings import Terminal t = Terminal() print t.red_bold + 'Hello world' + t.normal print t.red_on_white + 'Hello world' + t.normal print t.underline_red_on_green + 'Hello world' + t.normal
  • 38. from blessings import Terminal t = Terminal() print t.red_bold + 'Hello world' + t.normal print t.red_on_white + 'Hello world' + t.normal print t.underline_red_on_green + 'Hello world' + t.normal Article.objects.filter(tag__in=['color_red', 'color_blue']) Article.objects.filter(tag__contains='color')
  • 39. Consistency warning signs
  • 40. Consistency warning signs Frequent references to your docs or source
  • 41. Consistency warning signs Frequent references to your docs or source Feeling syntactically clever
  • 42. Brevity “The finest language is mostly made up of simple, unimposing words.” —George Eliot
  • 43. from blessings import Terminal term = Terminal() print term.bold + 'I am bold!' + term.normal
  • 44. from blessings import Terminal term = Terminal() print term.bold + 'I am bold!' + term.normal print term.bold('I am bold!')
  • 45. from blessings import Terminal term = Terminal() print term.bold + 'I am bold!' + term.normal print term.bold('I am bold!') print '{t.bold}Very {t.red}emphasized{t.normal}'.format(t=term)
  • 47. Brevity warning signs Copying and pasting when writing against your API
  • 48. Brevity warning signs Copying and pasting when writing against your API Typing something irrelevant while grumbling “Why can’t it just assume the obvious thing?”
  • 49. Composability “Perfection is achieved not when there is nothing left to add but when there is nothing left to take away.” —Antoine de Saint-Exupery
  • 50.
  • 52. print_formatted('Hello world', 'red', 'bold') print_formatted('Hello world', 'red', 'bold', out=some_file)
  • 53. print_formatted('Hello world', 'red', 'bold') print_formatted('Hello world', 'red', 'bold', out=some_file) print formatted('Hello world', 'red', 'bold')
  • 54. Composabilty warning signs
  • 55. Composabilty warning signs Classes with lots of state
  • 56. Composabilty warning signs Classes with lots of state class ElasticSearch(object): """ An object which manages connections to elasticsearch and acts as a go-between for API calls to it""" def index(self, index, doc_type, doc, id=None, force_insert=False, query_params=None): """Put a typed JSON document into a specific index to make it searchable.""" def search(self, query, **kwargs): """Execute a search query against one or more indices and get back search hits.""" def more_like_this(self, index, doc_type, id, mlt_fields, body='', query_params=None): """Execute a "more like this" search query against one or more fields and get back search hits.""" . . .
  • 57. Composabilty warning signs Classes with lots of state class ElasticSearch(object): """ class PenaltyBox(object): An object which manages connections to elasticsearch and acts as a """A thread-safe bucket of servers (or other things) that may have go-between for API calls to it""" downtime.""" def index(self, index, doc_type, doc, id=None, force_insert=False, query_params=None): def get(self): """Put a typed JSON document into a specific index server and a bool indicating whether it was from the """Return a random to make it searchable.""" dead list.""" def search(self, query, **kwargs): mark_dead(self, server): def """Execute a search query against one or more indices and get won't search """Guarantee that this server back be returned again until a period of hits.""" time has passed, unless all servers are dead.""" def more_like_this(self, index, def mark_live(self, server): doc_type, id, mlt_fields, body='', query_params=None): """Execute a "more like this" search query against one or dead list to and live one.""" """Move a server from the more fields the get back search hits.""" . . .
  • 58. Composabilty warning signs Classes with lots of state Deep inheritance hierarchies
  • 59. Composabilty warning signs Classes with lots of state Deep inheritance hierarchies Violations of the Law of Demeter
  • 60. Composabilty warning signs Classes with lots of state Deep inheritance hierarchies Violations of the Law of Demeter Mocking in tests
  • 61. Composabilty warning signs Classes with lots of state Deep inheritance hierarchies Violations of the Law of Demeter Mocking in tests print_formatted('Hello world', 'red', 'bold')
  • 62. Composabilty warning signs Classes with lots of state Deep inheritance hierarchies Violations of the Law of Demeter Mocking in tests print_formatted('Hello world', 'red', 'bold') print formatted('Hello world', 'red', 'bold')
  • 63. Composabilty warning signs Classes with lots of state Deep inheritance hierarchies Violations of the Law of Demeter Mocking in tests Options
  • 64. Plain Data “All the great things are simple, and many can be expressed in a single word…” —Sir Winston Churchill
  • 65.
  • 66.
  • 67.
  • 68.
  • 69. ✚ RawConfigParser.parse(string)
  • 70. ✚ RawConfigParser.parse(string) charming_parser.parse(file_contents('some_file.ini'))
  • 71. class Node(dict): """A wrapper around a native Reflect.parse dict providing some convenience methods and some caching of expensive computations"""
  • 72. class Node(dict): """A wrapper around a native Reflect.parse dict providing some convenience methods and some caching of expensive computations""" def walk_up(self): """Yield each node from here to the root of the tree, starting with myself.""" node = self while node: yield node node = node.get('_parent')
  • 73. class Node(dict): """A wrapper around a native Reflect.parse dict providing some convenience methods and some caching of expensive computations""" def walk_up(self): """Yield each node from here to the root of the tree, starting with myself.""" node = self while node: yield node node = node.get('_parent') def nearest_scope_holder(self): """Return the nearest node that can have its own scope, potentially including myself. This will be either a FunctionDeclaration or a Program (for now). """ return first(n for n in self.walk_up() if n['type'] in ['FunctionDeclaration', 'Program'])
  • 74. Plain Data warning signs
  • 75. Plain Data warning signs Users immediately transforming your output to another format
  • 76. Plain Data warning signs Users immediately transforming your output to another format Instantiating one object just to pass it to another
  • 77. Grooviness “The bad teacher’s words fall on his pupils like harsh rain; the good teacher’s, as gently as dew.” —Talmud: Ta’anith 7b
  • 80. Avoid nonsense representations. { "bool" : { "must" : { "term" : { "user" : "fred" } }, "must_not" : { "range" : { "age" : { "from" : 12, "to" : 21 } } }, "minimum_number_should_match" : 1, "boost" : 1.0 } }
  • 81. Avoid nonsense representations. { "bool" : { "must" : { "term" : { "user" : "fred" } }, "must_not" : { "range" : { "age" : { "from" : 12, "to" : 21 } } }, "minimum_number_should_match" : 1, "boost" : 1.0 } } frob*ator AND snork
  • 82. Old pyelasticsearch def search(self, q=None, body=None, indexes=None, doc_types=None): """Execute an elasticsearch query, and return the results."""
  • 83. Old pyelasticsearch def search(self, q=None, body=None, indexes=None, doc_types=None): """Execute an elasticsearch query, and return the results.""" search(q='frob*ator AND snork', body={'some': 'query'})
  • 84. Old pyelasticsearch def search(self, q=None, body=None, indexes=None, doc_types=None): """Execute an elasticsearch query, and return the results.""" search(q='frob*ator AND snork', body={'some': 'query'}) search()
  • 85. Old pyelasticsearch def search(self, q=None, body=None, indexes=None, doc_types=None): """Execute an elasticsearch query, and return the results.""" search(q='frob*ator AND snork', body={'some': 'query'}) search() ✚
  • 86. Old pyelasticsearch def search(self, q=None, body=None, indexes=None, doc_types=None): """Execute an elasticsearch query, and return the results.""" search(q='frob*ator AND snork', body={'some': 'query'}) search() ✚ New pyelasticsearch def search(self, query, indexes=None, doc_types=None): """Execute an elasticsearch query, and return the results."""
  • 87. Old pyelasticsearch def search(self, q=None, body=None, indexes=None, doc_types=None): """Execute an elasticsearch query, and return the results.""" search(q='frob*ator AND snork', body={'some': 'query'}) search() ✚ New pyelasticsearch def search(self, query, indexes=None, doc_types=None): """Execute an elasticsearch query, and return the results.""" Fail shallowly.
  • 88. Resource acquisition is initialization.
  • 89. Resource acquisition is initialization. class PoppableBalloon(object): """A balloon you can pop""" def __init__(self): self.air = 0 def fill(self, how_much): self.air = how_much
  • 90. Resource acquisition is initialization. class PoppableBalloon(object): """A balloon you can pop""" def __init__(self): self.air = 0 def fill(self, how_much): self.air = how_much class PoppableBalloon(object): """A balloon you can pop""" def __init__(self, initial_fill): self.air = initial_fill def fill(self, how_much): self.air = how_much
  • 93. Grooviness warning signs
  • 94. Grooviness warning signs Nonsense states or representations
  • 95. Grooviness warning signs Nonsense states or representations Invariants that aren’t
  • 96. Grooviness warning signs Nonsense states or representations Invariants that aren’t Users unclear where to get started
  • 97. Grooviness warning signs Nonsense states or representations Invariants that aren’t Users unclear where to get started Long, complicated documentation
  • 98. Safety “I wish it was easier to hurt myself.” —Nobody, ever
  • 100. update things set frob=2 where frob=1;
  • 101. update things set frob=2 where frob=1; update things set frob=2;
  • 102. update things set frob=2 where frob=1; update things set frob=2; update things set frob=2 all;
  • 103. update things set frob=2 where frob=1; update things set frob=2; update things set frob=2 all; rm *.pyc
  • 104. update things set frob=2 where frob=1; update things set frob=2; update things set frob=2 all; rm *.pyc rm *
  • 105. update things set frob=2 where frob=1; update things set frob=2; update things set frob=2 all; rm *.pyc rm * rm -f *
  • 106. def delete(self, index, doc_type, id=None): """Delete a typed JSON document from a specific index based on its id."""
  • 107. def delete(self, index, doc_type, id=None): """Delete a typed JSON document from a specific index based on its id."""
  • 108. def delete(self, index, doc_type, id=None): """Delete a typed JSON document from a specific index based on its id.""" def delete(self, index, doc_type, id): """Delete a typed JSON document from a specific index based on its id.""" def delete_all(self, index, doc_type): """Delete all documents of the given doctype from an index."""
  • 109. Error reporting: exceptions are typically safer.
  • 112. non-astronautics consistency brevity composability plain data grooviness safety
  • 113. non-astronautics consistency brevity composability plain data grooviness safety
  • 114. non-astronautics consistency brevity composability Elegance? “It is the ineffable will of Bob.” —Old Thrashbarg plain data grooviness safety
  • 115. Preflight Architecture Astronautics ✖ Instantiating one object just to pass ✖ Inventing rather than extracting it to another Consistency Composability ✖ Frequent references to your docs or ✖ Classes with lots of state source ✖ Deep inheritance hierarchies ✖ Feeling syntactically clever ✖ Violations of the Law of Demeter ✖ Mocking in tests Brevity ✖ Bolted-on options ✖ Copying and pasting when writing against your API Grooviness ✖ Grumbling about having to hand- ✖ Nonsense states hold the API ✖ Invariants that aren’t ✖ No clear introductory path Plain Data ✖ Long, tricky documentation ✖ Users immediately transforming your output to another format Safety ✖ Ease of hurting self or others
  • 116. Thank You twitter: ErikRose www.grinchcentral.com erik@mozilla.com