Como fazer boas libs?
Flávio Juvenal
Vinta Software
www.vinta.com.br
● Dia 16: Estrutura de dados e collections em Python -
André Ericson (Sala Sambaqui 3)
● Dia 17: Definindo um Boilerplate Customizável usando
Django, React e Bootstrap - Lais Varejão (Sala Sambaqui 3)
Outras talks da Vinta na PyBR 12
Como fazer boas libs APIs?
Não vamos abordar
● Estrutura de projeto
● Distribuição
● Licença de uso
● Semantic Versioning
● Code-style
● Continuous Integration
● Coverage
● etc...
API
"Um conjunto de definições de subrotinas, protocolos e
ferramentas para construir software e aplicações."
https://en.wikipedia.org/wiki/Application_programming_inter
face
Sua API é uma UI
Sua API é uma UI
10 Usability Heuristics for User Interface Design
https://www.nngroup.com/articles/ten-usability-heuristics/
Sua API é uma UI
● Visibility of system status
● Match between system and the real world
● User control and freedom
● Consistency and standards
● Recognition rather than recall
● Flexibility and efficiency of use
● Aesthetic and minimalist design
● Error prevention
● Help users recognize, diagnose, and recover from errors
● Help and documentation
Sua API é uma UI
Hmm… bonito… mas abstrato demais...
Máximas como esta são difíceis de aplicar e avaliar.
Precisamos de princípios mais práticos!
Consistência
- Com ou sem underscore?
gettype VS get_class (PHP)
- objeto + verbo ou verbo + objeto?
str_shuffle VS recode_string (PHP)
Consistência na prática: nomenclatura
- Abreviações
activatePreviousWindows VS fetchPrev (Qt < 4)
bin2hex VS strtolower (PHP)
Consistência na prática: nomenclatura
- Ordem dos argumentos?
datetime.datetime(year, month, day, hour=0,
minute=0, second=0, microsecond=0, tzinfo=None)
datetime.timedelta(days=0, seconds=0,
microseconds=0, milliseconds=0, minutes=0,
hours=0, weeks=0)
Consistência na prática: ordem
- Significado de vazio: None, False, [], '', 0
- Use o mais adequado. Cuidado com significados
obscuros:
>>> import datetime
>>> bool(datetime.date(datetime.MINYEAR, 1, 1))
True
>>> bool(datetime.time(0)) # Python < 3.5
False
Consistência na prática: semântica
[ ] A API exige que o usuário volte
constantemente para documentação para saber como
faz algo?
[ ] Existe consistência na nomenclatura (ordem
dos termos, abreviações, plurais, etc)?
[ ] Existe consistência na ordem dos argumentos?
[ ] Existe consistência no que significa vazio?
Aumentar a consistência
Verbosidade
Zen of Python
Flat is better than nested.
Sparse is better than dense.
Readability counts.
[ ] A API exige que você copie e cole muito
código para fazer algo comum? Se sim, faça
funções mais gerais (mas mantenha as mais
específicas para não perder composability).
Exemplo:
Reduzir a verbosidade
import urllib.request
gh_url = 'https://api.github.com/user'
password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
password_mgr.add_password(None, gh_url, 'user', 'pswd')
handler = urllib.request.HTTPBasicAuthHandler(password_mgr)
opener = urllib.request.build_opener(handler)
opener.open(gh_url)
Reduzir a verbosidade
Reduzir a verbosidade
import requests
session = requests.Session()
session.auth = ('user', 'pswd')
session.get('https://api.github.com/user')
[ ] É possível usar um tipo padrão adequado ao
invés de um novo tipo customizado da API?
urllib.request.HTTPPasswordMgrWithDefaultRealm VS tuple
Reduzir a verbosidade
[ ] A API tem valores defaults sãos?
// Aff...
history.pushState(null, "", "https://vinta.com.br");
// Por que não é?
history.pushState("https://vinta.com.br");
Reduzir a verbosidade
Principle of Least Astonishment
Principle of Least Astonishment
Previna que seu cliente da API fale WAT.
http://programmers.stackexchange.com/questions/187457/
what-is-the-principle-of-least-astonishment
JavaScript < ES5
>>> parseInt('010')
>>> 8
Se o valor vier de um input do usuário, lascou…
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects
/parseInt#ECMAScript_5_removes_octal_interpretation
Principle of Least Astonishment
Python
>>> int('010')
>>> 10
Principle of Least Astonishment
JavaScript
>>> new Date(2016, 1, 1)
Mon Feb 01 2016 00:00:00 GMT-0300 (BRT)
Principle of Least Astonishment
Python
>>> datetime.datetime(2016, 1, 1).isoformat()
'2016-01-01T00:00:00'
Principle of Least Astonishment
[ ] PLA funcional: O comportamento padrão faz o
que o usuário realmente espera? Testar com
usuários reais!
Garantir o Principle of Least Astonishment
Em Python, "assimetria de comportamentos deve se refletir
em assimetria de formas":
numbers.sort() VS sorted(numbers)
.append() VS +
Evitar misturar retornos com side-effects:
http://stackoverflow.com/questions/13062423/is-making-in-place-operations-ret
urn-the-object-a-bad-idea
Principle of Least Astonishment
Cuidado com falsa simetria:
QStatusBar::message(text, msecs) (Qt 3)
QStatusBar::setMessage(text, msecs)
QStatusBar::showMessage(text, msecs) (Qt 4)
Principle of Least Astonishment
[ ] PLA não-funcional: O comportamento padrão
está de acordo com as expectativas de
performance, efeitos colaterais, safety,
segurança, etc?
Garantir o Principle of Least Astonishment
Abstrações
vazadas
"Abstração: uma simplificação de algo muito mais complicado
que está acontecendo por debaixo dos panos"
Joel Spolsky em
http://www.joelonsoftware.com/articles/LeakyAbstractions.h
tml
Abstrações
from collections import Counter
c = Counter(['eggs', 'ham', 'eggs'])
print(c)
>>> Counter({'eggs': 2, 'ham': 1})
Abstrações
sorted([2,3,1])
>>> [1, 2, 3]
Abstrações
PS: Mas só porque está acontecendo debaixo dos panos, não
deve ser completamente invisível. O como às vezes precisa
estar evidente.
Mais sobre isso a seguir...
Law of Leaky Abstractions
O problema é que "Todas abstrações não-triviais são
vazadas".
Esta é a "The Law of Leaky Abstractions".
Ou seja, detalhes da implementação vazam.
Law of Leaky Abstractions
O que causa vazamentos?
Quando tentamos garantir algo impossível ou não-natural.
Law of Leaky Abstractions
APIs RPC que tentam igualar chamadas remotas a chamadas
locais.
guido_profile = Facebook.get_profile('guido')
guido_profile.set_name("Benevolent Dictator For Life")
Law of Leaky Abstractions
REST não abstrai a
dualidade cliente-servidor.
Pelo contrário, abraça ela.
Por exemplo com o
Conditional PUT:
Law of Leaky Abstractions
[ ] Existe algo que a API está tentando abstrair
e não devia?
Minimizar vazamentos das abstrações em APIs
Completude
Outro problema das abstrações é quando elas não são
completas, são restritas.
O cliente precisará estender a abstração com mais
funcionalidades, mudar partes de funcionalidades existentes
ou compor a abstração com outras.
Completude e extensibilidade
Completude e extensibilidade
"O maior objetivo de uma API deve ser eliminar a
descontinuidade de integração."
Casey Muratori em:
https://mollyrocket.com/casey/stream_0028.html
ORM count
ORM annotate com
F object
ORM com
annotate e
custom
Aggregate
ORM annotate
com F object e
Func
O cliente precisará estender a abstração com mais
funcionalidades, mudar partes de funcionalidades existentes
ou compor a abstração com outras.
Não tem problema a API não ser completa, mas ela deve ser
extensível, flexível e "composable".
Completude e extensibilidade
Retenção
Um dos vilões da extensibilidade se chama retenção.
Retenção ocorre quando a API sequestra ou encapsula um
recurso e impede seu uso direto.
Retenção
- retenção para ser + extensível
[ ] Ofereça a opção de deixar um recurso interno
aberto/alocado mesmo depois de ter terminado de
usá-lo.
[ ] Dê acesso (mesmo que com _) a recursos que o
cliente pode precisar.
[ ] Retorne objetos que o cliente pode precisar.
[ ] Ao fazer Inversion of Control ou chamar
callbacks, passe tudo que a função do cliente
pode precisar.
Exemplo a seguir:
- retenção para ser + extensível
Encapsulamento,
sim ou não?
Além de mais retenção, encapsulamento total resulta em menos
flexibilidade. Quem quiser mudar o comportamento interno vai
conseguir de um jeito ou de outro (monkey-patching, reflection,
etc)… então pra que esconder tanto?
"For a Pythonista, encapsulation is not the inability of seeing
internals of classes, but the possibility of avoiding to look at it"
http://stackoverflow.com/questions/7456807/python-name-mangl
ing
Encapsulamento total para que?
Encapsulamento total para que?
- encapsulamento para ser + extensível
[ ] A API permite a modificação ou remoção de
comportamentos sem que o usuário tenha que
reescrever o código interno dela? Permita
sobrescrita para evitar reescrita!
Exemplo dropzone.js:
- encapsulamento para ter + composability
[ ] Aceite recursos oferecidos pelo cliente caso
eles sejam similares aos seus (aproveite
duck-typing).
[ ] Ofereça a opção de aceitar um recurso externo
previamente aberto/alocado.
[ ] Se for necessário fazer muitos mock.patch,
então está faltando Inversion of
Control/Dependecy Injection para ser mais
flexível. Faça mais DI.
Exemplo:
- encapsulamento para ter + composability
- encapsulamento para ter + composability
@patch('my.project.trading.get_enriched_trade_data', lambda: TEST_TRADE_DATA)
@patch('my.project.subledger.get_subledger_data', get_test_subledger_data)
@patch('my.project.metadata.get_subledger_codes', return_value=TEST_CODES)
@patch('my.project.reports.store_report')
def test_build_report(self, store_report):
build_report()
store_report.assert_called_with(EXPECTED_REPORT)
http://mauveweb.co.uk/posts/2014/09/every-mock-patch-is-a-little-smell.html
Mais
níveis
de abstração
Se os três pontos
de integração
forem da mesma
lib, já muito!
Mas o ideal é
sempre mais
+ níveis de abstração para ter + composability
[ ] A API provê vários níveis de abstração, do
mais abstrato ao mais específico/customizável/
baixo-nível?
[ ] Na API, você deixou "o simples fácil, o
complexo possível e o errado impossível"?
Exemplo a seguir:
+ níveis de abstração para ter + composability
@app.task
def add(x, y):
return x + y
class AdderTask(Task):
rate_limit = '100/h'
def run(self, x, y):
return x + y
+ níveis de abstração para ter + composability
Granular!
Não-granular!
[ ] Tem "and" no nome da função? A função muda o
estado de vários objetos? A função tem mais de um
interesse (concern)? Se sim, quebre a função
maior fazendo ela chamar funções menores.
Exemplo a seguir:
+ granularidade para ter + composability e + extensibilidade
● Não forçar o usuário a especificar o que é óbvio ou
frequente.
● Mas também não esconder o que é importante e muitos
podem querer mudar.
● Quanto mais níveis de abstração a API tiver, mais a API
vai acertar os níveis que os clientes precisam.
Acertar o nível de abstração
Pythonic
● Prefira @property a métodos
import urllib.request
r = urllib.request.urlopen('http://python.org/')
r.getcode()
import requests
r = requests.get('http://python.org/')
r.status_code
Pythonic
● Use Context managers para objetos com life-cycle
f = open('file.txt')
contents = f.read()
f.close()
with open('file.txt') as f:
contents = f.read()
Pythonic
● Defina __repr__
>>> requests.get('http://httpbin.org/status/200')
<Response [200]>
>>> Github().gists()
<TapiocaClientExecutor object
'https://api.github.com/gists'>
Pythonic
Pythonic
● Operator overloading
● Decorators
● Generators
● asyncio
● etc...
"Design Patterns are missing language features"
Exemplo: strategy pattern < high order functions
● Documentação!!!!!!!!!!
○ Mostrar quick-start com poucas linhas para fazer o
básico
○ Top-down: primeiro pensar em o que a API deve fazer,
documentar isso, e só depois implementar
○ Exemplos hands-on, com casos de uso (exemplo:
python-social-auth)
○ Documentar erros comuns, depois proteger a API
contra eles (se estiver falando muito "note" ou
"careful", mude sua API)
Também é importante
● Visibilidade de contexto: cuidado com interfaces modais
● Exceções
○ Vários tipos
○ Mensagens de erro
○ Fail-fast, especialmente em operações sequenciais
○ "Errors should never pass silently. Unless explicitly
silenced."
● Safety (não é segurança!)
● Imutabilidade
● Discoverability
● etc...
Também é importante
● Slides disponíveis em:
http://bit.ly/pybr12-vinta
● Twitter: @flaviojuvenal
Dúvidas?
● Designing and Evaluating Reusable Components
● The Little Manual of API Design
● API Design Tips
● API Design
● What Makes Software Good?
● What makes a good software library?
● Bumper-Sticker API Design
● Ten Good Rules for Bad APIs
Referências
Referências
● What guidelines should I follow while designing a library?
● API: Design Matters
● How to Design a Good API and Why it Matters
● API Design Principles - Qt Wiki
● PHP: a fractal of bad design
● Why frameworks are evil
● Multiple levels of abstraction
● The Law of Leaky Abstractions
Referências
● On DRY and the cost of wrongful abstractions
● The Wrong Abstraction
● Separation of concerns
● Command–query separation
● PEP 8

Como fazer boas libs

  • 1.
    Como fazer boaslibs? Flávio Juvenal Vinta Software www.vinta.com.br
  • 4.
    ● Dia 16:Estrutura de dados e collections em Python - André Ericson (Sala Sambaqui 3) ● Dia 17: Definindo um Boilerplate Customizável usando Django, React e Bootstrap - Lais Varejão (Sala Sambaqui 3) Outras talks da Vinta na PyBR 12
  • 5.
    Como fazer boaslibs APIs?
  • 6.
    Não vamos abordar ●Estrutura de projeto ● Distribuição ● Licença de uso ● Semantic Versioning ● Code-style ● Continuous Integration ● Coverage ● etc...
  • 7.
    API "Um conjunto dedefinições de subrotinas, protocolos e ferramentas para construir software e aplicações." https://en.wikipedia.org/wiki/Application_programming_inter face
  • 8.
    Sua API éuma UI
  • 10.
    Sua API éuma UI 10 Usability Heuristics for User Interface Design https://www.nngroup.com/articles/ten-usability-heuristics/
  • 11.
    Sua API éuma UI ● Visibility of system status ● Match between system and the real world ● User control and freedom ● Consistency and standards ● Recognition rather than recall ● Flexibility and efficiency of use ● Aesthetic and minimalist design ● Error prevention ● Help users recognize, diagnose, and recover from errors ● Help and documentation
  • 12.
    Sua API éuma UI Hmm… bonito… mas abstrato demais... Máximas como esta são difíceis de aplicar e avaliar. Precisamos de princípios mais práticos!
  • 13.
  • 14.
    - Com ousem underscore? gettype VS get_class (PHP) - objeto + verbo ou verbo + objeto? str_shuffle VS recode_string (PHP) Consistência na prática: nomenclatura
  • 15.
    - Abreviações activatePreviousWindows VSfetchPrev (Qt < 4) bin2hex VS strtolower (PHP) Consistência na prática: nomenclatura
  • 16.
    - Ordem dosargumentos? datetime.datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None) datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0) Consistência na prática: ordem
  • 17.
    - Significado devazio: None, False, [], '', 0 - Use o mais adequado. Cuidado com significados obscuros: >>> import datetime >>> bool(datetime.date(datetime.MINYEAR, 1, 1)) True >>> bool(datetime.time(0)) # Python < 3.5 False Consistência na prática: semântica
  • 18.
    [ ] AAPI exige que o usuário volte constantemente para documentação para saber como faz algo? [ ] Existe consistência na nomenclatura (ordem dos termos, abreviações, plurais, etc)? [ ] Existe consistência na ordem dos argumentos? [ ] Existe consistência no que significa vazio? Aumentar a consistência
  • 19.
  • 20.
    Zen of Python Flatis better than nested. Sparse is better than dense. Readability counts.
  • 21.
    [ ] AAPI exige que você copie e cole muito código para fazer algo comum? Se sim, faça funções mais gerais (mas mantenha as mais específicas para não perder composability). Exemplo: Reduzir a verbosidade
  • 22.
    import urllib.request gh_url ='https://api.github.com/user' password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm() password_mgr.add_password(None, gh_url, 'user', 'pswd') handler = urllib.request.HTTPBasicAuthHandler(password_mgr) opener = urllib.request.build_opener(handler) opener.open(gh_url) Reduzir a verbosidade
  • 23.
    Reduzir a verbosidade importrequests session = requests.Session() session.auth = ('user', 'pswd') session.get('https://api.github.com/user')
  • 24.
    [ ] Épossível usar um tipo padrão adequado ao invés de um novo tipo customizado da API? urllib.request.HTTPPasswordMgrWithDefaultRealm VS tuple Reduzir a verbosidade
  • 25.
    [ ] AAPI tem valores defaults sãos? // Aff... history.pushState(null, "", "https://vinta.com.br"); // Por que não é? history.pushState("https://vinta.com.br"); Reduzir a verbosidade
  • 26.
    Principle of LeastAstonishment
  • 27.
    Principle of LeastAstonishment Previna que seu cliente da API fale WAT. http://programmers.stackexchange.com/questions/187457/ what-is-the-principle-of-least-astonishment
  • 28.
    JavaScript < ES5 >>>parseInt('010') >>> 8 Se o valor vier de um input do usuário, lascou… https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects /parseInt#ECMAScript_5_removes_octal_interpretation Principle of Least Astonishment
  • 29.
  • 30.
    JavaScript >>> new Date(2016,1, 1) Mon Feb 01 2016 00:00:00 GMT-0300 (BRT) Principle of Least Astonishment
  • 31.
    Python >>> datetime.datetime(2016, 1,1).isoformat() '2016-01-01T00:00:00' Principle of Least Astonishment
  • 32.
    [ ] PLAfuncional: O comportamento padrão faz o que o usuário realmente espera? Testar com usuários reais! Garantir o Principle of Least Astonishment
  • 33.
    Em Python, "assimetriade comportamentos deve se refletir em assimetria de formas": numbers.sort() VS sorted(numbers) .append() VS + Evitar misturar retornos com side-effects: http://stackoverflow.com/questions/13062423/is-making-in-place-operations-ret urn-the-object-a-bad-idea Principle of Least Astonishment
  • 34.
    Cuidado com falsasimetria: QStatusBar::message(text, msecs) (Qt 3) QStatusBar::setMessage(text, msecs) QStatusBar::showMessage(text, msecs) (Qt 4) Principle of Least Astonishment
  • 35.
    [ ] PLAnão-funcional: O comportamento padrão está de acordo com as expectativas de performance, efeitos colaterais, safety, segurança, etc? Garantir o Principle of Least Astonishment
  • 36.
  • 37.
    "Abstração: uma simplificaçãode algo muito mais complicado que está acontecendo por debaixo dos panos" Joel Spolsky em http://www.joelonsoftware.com/articles/LeakyAbstractions.h tml Abstrações
  • 38.
    from collections importCounter c = Counter(['eggs', 'ham', 'eggs']) print(c) >>> Counter({'eggs': 2, 'ham': 1}) Abstrações
  • 39.
  • 40.
    PS: Mas sóporque está acontecendo debaixo dos panos, não deve ser completamente invisível. O como às vezes precisa estar evidente. Mais sobre isso a seguir... Law of Leaky Abstractions
  • 41.
    O problema éque "Todas abstrações não-triviais são vazadas". Esta é a "The Law of Leaky Abstractions". Ou seja, detalhes da implementação vazam. Law of Leaky Abstractions
  • 42.
    O que causavazamentos? Quando tentamos garantir algo impossível ou não-natural. Law of Leaky Abstractions
  • 43.
    APIs RPC quetentam igualar chamadas remotas a chamadas locais. guido_profile = Facebook.get_profile('guido') guido_profile.set_name("Benevolent Dictator For Life") Law of Leaky Abstractions
  • 44.
    REST não abstraia dualidade cliente-servidor. Pelo contrário, abraça ela. Por exemplo com o Conditional PUT: Law of Leaky Abstractions
  • 45.
    [ ] Existealgo que a API está tentando abstrair e não devia? Minimizar vazamentos das abstrações em APIs
  • 46.
  • 47.
    Outro problema dasabstrações é quando elas não são completas, são restritas. O cliente precisará estender a abstração com mais funcionalidades, mudar partes de funcionalidades existentes ou compor a abstração com outras. Completude e extensibilidade
  • 48.
    Completude e extensibilidade "Omaior objetivo de uma API deve ser eliminar a descontinuidade de integração." Casey Muratori em: https://mollyrocket.com/casey/stream_0028.html
  • 51.
    ORM count ORM annotatecom F object ORM com annotate e custom Aggregate ORM annotate com F object e Func
  • 54.
    O cliente precisaráestender a abstração com mais funcionalidades, mudar partes de funcionalidades existentes ou compor a abstração com outras. Não tem problema a API não ser completa, mas ela deve ser extensível, flexível e "composable". Completude e extensibilidade
  • 55.
  • 56.
    Um dos vilõesda extensibilidade se chama retenção. Retenção ocorre quando a API sequestra ou encapsula um recurso e impede seu uso direto. Retenção
  • 57.
    - retenção paraser + extensível [ ] Ofereça a opção de deixar um recurso interno aberto/alocado mesmo depois de ter terminado de usá-lo. [ ] Dê acesso (mesmo que com _) a recursos que o cliente pode precisar.
  • 58.
    [ ] Retorneobjetos que o cliente pode precisar. [ ] Ao fazer Inversion of Control ou chamar callbacks, passe tudo que a função do cliente pode precisar. Exemplo a seguir: - retenção para ser + extensível
  • 61.
  • 62.
    Além de maisretenção, encapsulamento total resulta em menos flexibilidade. Quem quiser mudar o comportamento interno vai conseguir de um jeito ou de outro (monkey-patching, reflection, etc)… então pra que esconder tanto? "For a Pythonista, encapsulation is not the inability of seeing internals of classes, but the possibility of avoiding to look at it" http://stackoverflow.com/questions/7456807/python-name-mangl ing Encapsulamento total para que?
  • 63.
  • 64.
    - encapsulamento paraser + extensível [ ] A API permite a modificação ou remoção de comportamentos sem que o usuário tenha que reescrever o código interno dela? Permita sobrescrita para evitar reescrita! Exemplo dropzone.js:
  • 66.
    - encapsulamento parater + composability [ ] Aceite recursos oferecidos pelo cliente caso eles sejam similares aos seus (aproveite duck-typing). [ ] Ofereça a opção de aceitar um recurso externo previamente aberto/alocado.
  • 67.
    [ ] Sefor necessário fazer muitos mock.patch, então está faltando Inversion of Control/Dependecy Injection para ser mais flexível. Faça mais DI. Exemplo: - encapsulamento para ter + composability
  • 68.
    - encapsulamento parater + composability @patch('my.project.trading.get_enriched_trade_data', lambda: TEST_TRADE_DATA) @patch('my.project.subledger.get_subledger_data', get_test_subledger_data) @patch('my.project.metadata.get_subledger_codes', return_value=TEST_CODES) @patch('my.project.reports.store_report') def test_build_report(self, store_report): build_report() store_report.assert_called_with(EXPECTED_REPORT) http://mauveweb.co.uk/posts/2014/09/every-mock-patch-is-a-little-smell.html
  • 69.
  • 70.
  • 71.
  • 72.
    Se os trêspontos de integração forem da mesma lib, já muito!
  • 73.
    Mas o idealé sempre mais
  • 74.
    + níveis deabstração para ter + composability [ ] A API provê vários níveis de abstração, do mais abstrato ao mais específico/customizável/ baixo-nível? [ ] Na API, você deixou "o simples fácil, o complexo possível e o errado impossível"? Exemplo a seguir:
  • 75.
    + níveis deabstração para ter + composability @app.task def add(x, y): return x + y
  • 76.
    class AdderTask(Task): rate_limit ='100/h' def run(self, x, y): return x + y + níveis de abstração para ter + composability
  • 77.
  • 78.
  • 79.
    [ ] Tem"and" no nome da função? A função muda o estado de vários objetos? A função tem mais de um interesse (concern)? Se sim, quebre a função maior fazendo ela chamar funções menores. Exemplo a seguir: + granularidade para ter + composability e + extensibilidade
  • 81.
    ● Não forçaro usuário a especificar o que é óbvio ou frequente. ● Mas também não esconder o que é importante e muitos podem querer mudar. ● Quanto mais níveis de abstração a API tiver, mais a API vai acertar os níveis que os clientes precisam. Acertar o nível de abstração
  • 82.
  • 83.
    ● Prefira @propertya métodos import urllib.request r = urllib.request.urlopen('http://python.org/') r.getcode() import requests r = requests.get('http://python.org/') r.status_code Pythonic
  • 84.
    ● Use Contextmanagers para objetos com life-cycle f = open('file.txt') contents = f.read() f.close() with open('file.txt') as f: contents = f.read() Pythonic
  • 85.
    ● Defina __repr__ >>>requests.get('http://httpbin.org/status/200') <Response [200]> >>> Github().gists() <TapiocaClientExecutor object 'https://api.github.com/gists'> Pythonic
  • 86.
    Pythonic ● Operator overloading ●Decorators ● Generators ● asyncio ● etc... "Design Patterns are missing language features" Exemplo: strategy pattern < high order functions
  • 87.
    ● Documentação!!!!!!!!!! ○ Mostrarquick-start com poucas linhas para fazer o básico ○ Top-down: primeiro pensar em o que a API deve fazer, documentar isso, e só depois implementar ○ Exemplos hands-on, com casos de uso (exemplo: python-social-auth) ○ Documentar erros comuns, depois proteger a API contra eles (se estiver falando muito "note" ou "careful", mude sua API) Também é importante
  • 88.
    ● Visibilidade decontexto: cuidado com interfaces modais ● Exceções ○ Vários tipos ○ Mensagens de erro ○ Fail-fast, especialmente em operações sequenciais ○ "Errors should never pass silently. Unless explicitly silenced." ● Safety (não é segurança!) ● Imutabilidade ● Discoverability ● etc... Também é importante
  • 89.
    ● Slides disponíveisem: http://bit.ly/pybr12-vinta ● Twitter: @flaviojuvenal Dúvidas?
  • 90.
    ● Designing andEvaluating Reusable Components ● The Little Manual of API Design ● API Design Tips ● API Design ● What Makes Software Good? ● What makes a good software library? ● Bumper-Sticker API Design ● Ten Good Rules for Bad APIs Referências
  • 91.
    Referências ● What guidelinesshould I follow while designing a library? ● API: Design Matters ● How to Design a Good API and Why it Matters ● API Design Principles - Qt Wiki ● PHP: a fractal of bad design ● Why frameworks are evil ● Multiple levels of abstraction ● The Law of Leaky Abstractions
  • 92.
    Referências ● On DRYand the cost of wrongful abstractions ● The Wrong Abstraction ● Separation of concerns ● Command–query separation ● PEP 8