Recentemente, desenvolvi minha própria API e, com esse interesse investido em design de API, fiquei muito interessado em saber como posso melhorar meu design de API.
Um aspecto que surgiu algumas vezes é (não pelos usuários da minha API, mas na minha observação de discussão sobre o tópico): deve-se saber apenas olhando o código que chama a API do que está fazendo .
Por exemplo, veja esta discussão no GitHub para o repositório de discurso , é algo como:
foo.update_pinned(true, true);
Apenas olhando o código (sem saber os nomes dos parâmetros, a documentação etc.), não se pode adivinhar o que vai fazer - o que significa o segundo argumento? A melhoria sugerida é ter algo como:
foo.pin()
foo.unpin()
foo.pin_globally()
E isso esclarece as coisas (o segundo argumento foi sobre se deve ou não ser globalmente, suponho), e concordo que, neste caso, o posterior certamente seria uma melhoria.
No entanto, acredito que possa haver casos em que métodos para definir um estado diferente, mas logicamente relacionado, seriam melhor expostos como uma chamada de método, em vez de separados, mesmo que você não saiba o que está fazendo apenas observando o código . (Portanto, você teria que procurar nos nomes dos parâmetros e na documentação para descobrir - o que pessoalmente eu sempre faria, independentemente de não estar familiarizado com uma API).
Por exemplo, eu exponho um método SetVisibility(bool, string, bool)
em um FalconPeer e reconheço apenas olhando a linha:
falconPeer.SetVisibility(true, "aerw3", true);
Você não teria ideia do que está fazendo. Ele está configurando três valores diferentes que controlam a "visibilidade" do falconPeer
no sentido lógico: aceitar solicitações de associação, apenas com senha e responder a solicitações de descoberta. Dividir isso em três chamadas de método pode levar um usuário da API a definir um aspecto da "visibilidade", esquecendo-se de definir os outros que eu os forço a pensar, expondo apenas o método único para definir todos os aspectos da "visibilidade" . Além disso, quando o usuário deseja alterar um aspecto, quase sempre desejará alterar outro aspecto e agora pode fazê-lo em uma chamada.
setSize(10, 20)
não é tão legível quanto setSize(width=10, height=20)
ou random(distribution='gaussian', mean=0.5, deviation=1)
. Em idiomas com parâmetros nomeados impostos, os booleanos podem transmitir exatamente a mesma quantidade de informações que o uso de enumerações / constantes nomeadas, para que possam ser boas nas APIs.
update
método:foo.update(pinned=true, globally=true)
. Ou:foo.update_pinned(true, globally=true)
. Portanto, a resposta para sua pergunta também deve levar em consideração os recursos do idioma, porque uma boa API para o idioma X pode não ser boa para o idioma Y e vice-versa.