projeto de api - tdc 2014 - floripa - trilha arquitetura - 18/05/2014
DESCRIPTION
O Projeto (Design) de APIs é algo que todo programador deveria saber, afinal de contas, inevitavelmente todos escrevem programas que se comunicam com outros programas, sejam seus próprios programas ou de terceiros. Muitas vezes, integrar seu código ao de uma API pode ser algo terrível e complicado ou uma experiência simples prazerosa. Mas o que faz uma API ser simples e fácil de usar? O que de fato é uma API e quando devemos criar uma? Como desenvolvemos uma API? Basta usar Padrões de Projeto, DDD, TDD, etc? Esperamos responder essas e outras questões sobre o projeto de API e apresentar exemplos relacionados a um projeto open source real, como o JRimum.TRANSCRIPT
Projeto de API
Gilmar P. S. Leitão @gilmatryx
¡ Aprendendo § Definições e conceitos
¡ Programando § Iniciando um projeto de API § Princípios de projeto § Projeto de classes
¡ Integrando
¡ APRENDENDO
¡ Web (SOAP, REST, etc) ¡ SO (Unix, Windows, etc) ¡ Linguagens de Programação (C++, Java, etc) ¡ Protocolos (Java – RMI à IIOP)
É uma coleção de: § Funções, Classes, Tipos de Dados § Eventos, Protocolos, Arquivos, etc.
Onde temos um sistema Que se comunica Com outro Através dessas Coleções
É uma coleção de: • Funções, Classes, Tipos de Dados • Eventos, Protocolos, Arquivos, etc.
Onde temos um sistema Que se comunica Com outro Através dessas Coleções
Biblioteca, Componente, Framework, Sistema Operacional, Recurso na Web, Etc.
¡ Application Programming Interface
Se você programa, então você provavelmente trabalha com módulos ou pelo menos deveria. Bons programas são modulares e cada módulo deve ter uma API. Pensar em termos de API melhora a qualidade do código.
Uma API pode ser um dos maiores tesouros de uma empresa. Clientes investem ao integrar uma API.
"A key lesson here is that API is not just a documented class. And, APIs don't just happen; they are a big investment." Erich Gamma.
¡ Clientes investem: comprando, escrevendo e aprendendo
¡ APIs promovem a reutilização e reduz custos ¡ O custo em parar de usar uma API pode ser proibitivo ¡ APIs públicas de sucesso captam clientes
APIs também podem ser um dos maiores débitos de uma empresa. Podem resultar em intermináveis chamadas ao suporte.
”Public APIs like diamonds, are forever. You have one chance to get it right So give it your best." Joshua Bloch.
Intuitiva
¡ Fácil de aprender ¡ Fácil de usar, mesmo sem documentação ¡ Difícil de usar incorretamente ¡ Fácil de estender ¡ Fácil de ler e manter o código que a usa ¡ Focada em um propósito ¡ Poderosa o bastante para atender os requisitos ¡ Apropriada e direcionada a um público ¡ Bem documentada (exemplar)
¡ PROGRAMANDO
¡ Iniciando um projeto de API ¡ Princípios de projeto ¡ Projeto de classes
1) Liste os requisitos 2) Valide-‐os escrevendo casos de uso 3) Escreva código para cada caso de uso
Faça tudo sob a perspectiva do usuário da API
Envolva mais pessoas o quanto possível nesse processo
¡ Escreva-‐os em não mais do que uma página § Quanto menor melhor (estamos começando) § Fácil de compartilhar e modificar
¡ Valide-‐os em caso de uso R: Deveríamos ter um programa para gerar boletos do Bradesco e salvar o código de barras no banco de dados para controlar a cobrança. Caso de Uso: Gerar boleto para banco Bradesco Caso: Obter código de barras do boleto gerado C: Salvar boleto gerado em PDF
¡ Codifique o mais cedo possível ¡ Comece sem realmente implementar Caso de Uso: Gerar boleto para banco Bradesco
✓ Perspectiva do usuário public static void main.. { Boleto boleto = new Boleto(Banco.Bradesco); }
✓ Perspectiva Implementação
class Boleto{ private String codigoDeBarras; ... }
Melhor do que começar a implementar cedo é começar com TDD mesmo para rascunho ¡ Ajuda manter visível apenas o que interessa ¡ Gera exemplos de uso sempre atualizados ¡ Direciona o design ¡ Evita implementar casos que seriam descartados
¡ Evita surpresas desagradáveis
Além de usar TDD no desenvolvimento da API escreva testes para o código que utiliza a API de fato Muitas dependências, métodos complicados e outros mal cheiros podem ser identificados e levar o design à uma nova direção
Golden Rule of API Design ”It’s not enough to write tests for an API you develop; you have to write unit tests for code that uses your API. When you follow this rule, you learn firsthand the hurdles that your users will have to overcome when they try to test their code independently.” Michael Feathers, (97 Things Every Programmer Should Know)
Caso de Uso: Gerar boleto para banco Bradesco public void deveGerarBoletoBradescoCorretamenteNaMinhaAplicacao(){
Boleto boletoEsperado = mock(Boleto.class); BoletoViewer boletoViewer = mock(BoletoViewer .class); when(boletoViewer .getBoleto()).thenReturn(boletoEsperado); MeuGeradorDeBoleto geradorDeBoleto = new MeuGeradorDeBoleto(boletoViewer ); Boleto boletoGerado = geradorDeBoleto.gereBoletoCom(dadosDoMeuUsuario);
assertThat(boletoGerado, equalTo(boletoEsperado));
}
Codifique cedo e frequentemente ¡ Comece antes de fato implementar (TDD) ¡ Escreva testes de código que usa API ¡ Escreva exemplos na medida que progride
§ Lembre-‐se uma API boa é exemplar § Exemplos bons tornam API fácil de entender § Exemplos ruins disseminam o mal uso, geram bugs, perguntas em fóruns e + problemas
Seja realista e mantenha o foco no propósito
¡ Muitos dos projetos de APIs são restritivos § Não tente agradar a todos
§ Tente desagradar a todos igualmente
Tente pensar antecipadamente, mas..
¡ Espere por cometer erros § Em poucos anos de uso da API eles surgirão
§ Espere por evoluir a API
¡ Iniciando um projeto de API ¡ Princípios de projeto ¡ Projeto de classes
API deve fazer o que se propõe a fazer e deve fazer bem ¡ Siga o princípio de responsabilidade única ¡ Tente manter tudo o mais simples possível ¡ A funcionalidade deve ser fácil de explicar
§ Se está difícil nomear, algo pode estar errado § Bons nomes guiam o desenvolvimento § Estar suscetível a divisão ou fusão de módulos
API deve ser o mais simples possível, mas não simplória ¡ Deve satisfazer os requisitos ¡ Os conceitos extraídos são o mais importante ¡ Procure uma boa proporção de poder/massa ¡ A massa conceitual é mais importante que a estrutural
API deve ser tão pequena quanto possível, mas não a menor Na dúvida, deixe de fora ¡ Funcionalidades, classes, métodos, etc ¡ Sempre pode-‐se adicionar, mas não remover ¡ Quanto mais coisa, mais difícil de se aprender ¡ Quanto mais coisa, mais pode dar errado
Nomes são especiais porque eles compõem o vocabulário da API Escolha nomes pronunciáveis e memoráveis ¡ Bons nomes surgem do domínio do problema
§ São familiares, intuitivos e com significado ¡ Bons nomes são auto explicativos
§ Evite abreviações
Não me faça pensar O código deve ser lido como uma prosa
Caso de Uso: Gerar boleto para banco Bradesco
Boleto boleto = Cobranca.gere() .para(Banco.Bradesco) .com(vencimentoAtual) .com(valorAtual) .boleto();
! Código que usa objetos da API jrimum.org/bopepo
Seja Consistente ¡ Mesma palavra = significa mesma coisa ¡ Busque simetria e consistência
§ Faça a mesma coisa do mesmo jeito § Por toda API, plataforma, ambiente, etc § Inconsistência aparece por que você mudou de ideia com o tempo
§ Faça revisões de código para manter tudo alinhado com o time
Coisas similares devem se parecer com coisas similares Caso de Uso: Gerar boleto para banco Bradesco BoletoViewer boleto = new BoletoViewer(dados) .comTemplate(arquivoPersonalizado) .gerePdf(); Caso de Uso: Gerar guia de arrecadação e recebimento banco BB GuiaViewer guia = new GuiaViewer(dados) .comTemplate(arquivoPersonalizado) .gerePdf();
Minimize o acesso a tudo ¡ Tudo deve ter o mínimo privilégio de acesso
§ Promove o ocultamento de informação § Classes e membros devem ter acesso privado sempre que possível
§ Classes públicas não devem ter membros públicos, com exceção de constantes
A implementação é um detalhe ¡ Detalhes de implementação tem impacto
§ Confundem usuários § Dificultam o entendimento
¡ Saiba identificá-‐los § Parâmetros para otimização, formato de dados (file, connection, etc), dependência de outras APIs
¡ Não deixe vazarem pela API § Exceções, formatos de dados, etc
Documente cedo, frequentemente e sempre ¡ Documente todo parâmetro, método, construtor, classe, interface e exceção
¡ Mantenha sempre atualizada ¡ “O que?” e “Como?” devem estão sempre presentes
¡ “Porque” também explicando decisões tomadas, padrões adotados, etc
Documente para cada situação específica ¡ Documentação de referência
§ Javadoc e similares ¡ Tutorias
§ Como começar rapidamente e fazer algo de valor § O que posso fazer em 2 minutos § Como gerar um boleto personalizado
¡ Guia do programador § Introdução, glossário, conceitos, padrões, etc
Sua API deve ser sinérgica em relação a Plataforma ¡ Faça o que é usual e convencionado
§ Siga as convenções de nomes § Imite os bons padrões das APIs da linguagem
¡ Conheça bem a plataforma e a linguagem § Funcionalidades amigáveis devem ser utilizadas: generics, varargs, enums, default arguments
¡ Também conheça armadilhas e ciladas § Finalizers, permgen, garbage collector, etc
Lembre-‐se que decisões no projeto poderão afetar a performance ¡ Decisões ruins podem limitar a performance § Fazendo um tipo mutável ou imutável § Usando uma implementação no lugar de uma interface
§ Oferecendo um construtor no lugar de um factory method
Lembre-‐se que decisões no projeto poderão afetar a performance ¡ Decisões ruins podem limitar a performance § Fazendo um tipo mutável ou imutável § Usando uma implementação no lugar de uma interface
§ Oferecendo um construtor no lugar de um factory method
¡ Iniciando um projeto de API ¡ Princípios de projeto ¡ Projeto de classes
Quando criar um tipo? ¡ Quando existir um comportamento específico e que um tipo existente não suporte
¡ Quando é um conceito chave no domínio Ex: CEP, CPF, CodigoDeBarras, Pagador, Boleto, ..
Tipos de domínio são melhores do que strings ”String é uma estrutura de dados rigorosa e exige muita duplicação de processo em qualquer lugar para o qual seja passada. É um veículo perfeito para ocultar informações" “The string is a stark data structure and everywhere it is passed there is much duplication of process. It is a perfect vehicle for hiding information.”
Alan Perlis.
Transforme objetos de domínio em Objetos de Valor (Tiny Types or Value Object DDD) ¡ Projete-‐os imutáveis a menos que tenha uma boa razão para o contrário
Ex: CEP, CPF, CodigoDeBarras, Boleto, ..
Minimize a Mutabilidade ¡ Classes devem ser imutáveis, a não ser que haja uma boa razão para fazer o contrário § Vantagens: simples, thread-‐safe, reutilizável § Desvantagens: determina um objeto para cada valor
¡ Se mutável, manter o espaço de estados pequeno e bem definido § Deixe claro quando é legal chamar qual método.
Bom: LocalDate, Duration, Instant Ruim: Date, Calendar
Subclasse somente onde faz sentido ¡ Extensão implica em substituição (Liskov)
§ Estenda somente quando o relacionamento "é um" existe § Do contrário, use composição
¡ Classes públicas não devem estender outras classes públicas apenas por facilidades de implementação
Bom: Set extends Collection Ruim: Properties extends Hashtable Stack extends Vector
Projete e documente para herança senão a proíba ¡ Herança viola o princípio de encapsulamento
§ A subclasse é suscetível aos detalhes da implementação da superclasse
¡ Se você permitir a extensão, documente a auto-‐utilização § Como os métodos utilizam um outro?
¡ Política conservativa: todas as classes concretas são final
Bom: AbstractSet, AbstractMap Ruim: Muitas classes concretas em libs J2SE
¡ Integrando
Um servidor de integração contínua é tão dispensável quanto um sistema de controle de versões ¡ Integração contínua
§ Garante que o código continua funcionando após cada alteração
§ Proporciona aos participantes do projeto a visibilidade do estado atual do projeto
✔✖