Plataforma Eclipse
Regras de compromisso da API
Versão 0.15 - Revista pela última vez às 12:00 de 30 de Maio, 2001
Estas são as regras de compromisso para clientes da API da plataforma Eclipse (e outros componentes).
O que significa ser uma API
A plataforma Eclipse define elementos da API para uso dos clientes, nomeadamente os fornecedores de servidores de internet (ISV) que escrevem plug-ins. Esses plug-ins podem, por sua vez, definir elementos da API para os respectivos clientes, e assim em diante. Os elementos da API são a expressão pública: contêm uma especificação sobre o que é suposto fazerem e sobre o modo como se destinam a ser utilizados. Os elementos da API são suportados: a equipa da plataforma Eclipse irá corrigir os problemas de implementação onde existir um desvio do comportamento especificado. Uma vez que, muitas vezes, está associado um custo elevado a alterações substanciais na API, a equipa da plataforma Eclipse irá também tentar desenvolver os elementos da API elegantemente através de sucessivas edições principais.
Como distinguir as API e as não API
Pela sua própria natureza, os elementos da API estão documentados e têm uma especificação, em contraste com os elementos que não sejam da API, que são detalhes de implementação internos, normalmente sem documentação ou especificações publicadas. Por isso, se não conseguir encontrar documentação para alguma coisa, isso é um bom indicador de que o elemento não é de uma API.
Para sermos mais exactos, a base do código para a plataforma está separados em pacotes de API e pacotes não de API, com todos os elementos da API declarados em pacotes da API designados.
-
Pacote da API - um pacote Java que contém, pelo menos, uma classe da API ou um pacote da API. Os nomes dos pacotes da API estão publicados na documentação para esse componente; onde seja viável, todos os outros pacotes que contêm apenas detalhes da implementação têm "internal" no nome do pacote. Os nomes dos pacotes da API podem aparecer legitimamente no modo cliente. Os nomes válidos para a plataforma Eclipse são:
-
org.eclipse.foo.* - por exemplo, org.eclipse.swt.widgets, org.eclipse.ui ou org.eclipse.core.runtime
-
org.eclipse.foo.internal.* - não API; pacotes de implementação interna
-
org.eclipse.foo.examples.* - não API; são exemplos
-
org.eclipse.foo.tests.* - não API; são conjuntos de testes
-
Classe ou interface da API - uma classe ou interface pública num pacote da API ou um membro de classe ou interface pública ou protegida declarado em ou herdado por, outra classe ou interface da API.
Os nomes das classes e interfaces da API podem aparecer legitimamente no código de cliente.
-
Método ou construtor da API - um método ou construtor público ou protegido declarado em, ou herdado por, uma classe ou interface da API. Os nomes dos métodos da API podem aparecer legitimamente no código de cliente.
-
Campo da API - um campo público ou protegido declarado em, ou herdado por, uma classe ou interface da API. Os nomes dos campos da API podem aparecer legitimamente no código de cliente.
Tudo o resto é considerado como detalhes da implementação interna e fora dos limites de todos os clientes. O código de cliente legítimo numa deve referenciar os nomes de elementos que não sejam da API (nem utilizando a duplicação Java). Em alguns casos, as regras de acessibilidade de nome da linguagem Java são utilizadas para anular as referências ilegais.
No entanto, existem muitos casos onde isto simplesmente não é possível. Cumprir esta regra simples evita o problema:
-
Limite-se às APIs documentadas oficialmente. Apenas os pacotes de referência que estão documentados no Javadoc da API publicado para o componente.
Nunca faça referência a um pacote que pertença a outro componente que tenha "internal" no nome, estes nunca são da API. Nunca fazer referência a um pacote para o qual não existe nenhum Javadoc da API publicado, estes também não são da API.
Regras gerais
A especificação de elementos da API é gerada a partir de comentários no Javadoc no código de origem Java dos elementos. Para alguns tipos de elementos, a especificação está sob a forma de contrato. Por exemplo, no caso dos métodos, o contrato é entre duas partes, quem chama o método e quem implementa o método. A regra fundamental é:
-
Honrar todos os contratos. Os contratos estão descritos no Javadoc publicado para os elementos da API que está a utilizar.
O termo "tem de", quando utilizado num contrato da API, significa que é da incumbência dessa parte assegurar que a condição é sempre cumprida; qualquer falha seria considerada como erro de programação com consequências não especificadas (e talvez imprevisíveis).
-
Deve honrar o termo "tem de". Tenha especial atenção às condições onde o termo "tem de" é utilizado.
Outras regras do senso comum:
-
Não confie nos comportamentos acidentais. Os comportamentos acidentais são observados através da experiência ou na prática, mas não são garantidos por nenhuma das especificações da API.
-
Não trate o valor nulo como um objecto. O objecto nulo é algo mais do a falta de um objecto.
Parta do princípio que tudo é não nulo, a não ser que a especificação da API diga o contrário.
-
Não tente enganar com uma duplicação Java. Utilizar a duplicação Java para enganar a verificação do compilador Java não traz nenhum benefício. Não existem contratos adicionais da API para utilizar na duplicação; a duplicação aumenta simplesmente a possibilidade de confiar num comportamento não especificado e detalhes da implementação interna.
-
Utilize os seus próprios pacotes. Não declare o código num pacote que pertença a outro componente. Declare sempre o código nos pacotes que lhe pertencem.
Chamar métodos da API públicos
Para a maior parte dos clientes, a parte geral da API de Eclipse assume o formato de métodos públicos em interfaces ou classes da API, fornecidos para o cliente chamar quando for apropriado.
-
Assegure as pré-condições. Assegure que as pré-condições do método da API são cumpridas antes de chamar o método. Inversamente, o chamador pode pressupor com segurança que as pós-condições do método foram cumpridas de imediato após o retorno da chamada.
-
Parâmetros nulos. Não passe o valor nulo como um parâmetro para um método da API, a não ser que o parâmetro esteja expressamente documentado como permitindo o valor nulo. Este é talvez o erro de programação mais frequente.
-
Chamadores restritos. Não chame um método da API que esteja documentado como disponível apenas para determinados chamadores, a não ser que seja um deles. Em algumas situações, os métodos devem fazer parte da API pública para benefício de uma determinada classe de chamadores (muitas vezes internos); chamar um destes métodos no momento errado tem consequências não especificadas (e talvez imprevisíveis).
-
Métodos para depuração. Não chame um método da API identificado como "apenas para fins de depuração". Por exemplo, a maior parte dos métodos toString() encontram-se nesta categoria.
-
Captura de parâmetros. Não transmitir um conjunto, recolha ou qualquer outro
objecto mutável como um parâmetro para um método da API e para, em seguida,
modificar o objecto que foi transmitido. Isto serve apenas para causar problemas.
Criar instâncias de classes da API da plataforma
Nem todas as classes da API concretas se destinam a que qualquer pessoa crie instâncias.
As classes da API têm um contrato de criação de instâncias que indica os termos sob os quais as instâncias podem ser criadas. O contrato pode ainda incluir coisas como responsabilidade residuais de criação de instâncias (por exemplo, configurar uma determinada propriedade antes da instância estar totalmente activa) e responsabilidade de ciclo de vida associadas (por exemplo, chamar dispose() para libertar recursos do sistema operativo capturados pela instância). As classes que se destinam à criação de instâncias por parte dos clientes estão sinalizadas, de modo explícito, no comentário de classe do Javadoc (com palavras como "Clientes podem criar instâncias.").
-
Criadores de instâncias restritos. Não crie instâncias numa classe da API que esteja documentada como disponível apenas para determinados terceiros, a não ser que seja um deles.
Em algumas situações, as classes devem fazer parte da API pública para benefício de um determinada terceira parte (muitas vezes interno); criar instâncias numa dessas classes incorrectamente tem consequências não especificadas (e talvez imprevisíveis).
Criar sub-classes das classes da API da plataforma
Apenas um sub-conjunto das classes da API se destina a permitir a criação de uma sub-classe. As classes da API têm um contrato de sub-classe que indica os termos sob os quais as sub-classes podem ser declaradas. Este contrato inclui também as responsabilidades de iniciação e responsabilidades de ciclo de vida. As classes que se destinam a permitir a criação de sub-classes por parte de clientes estão sinalizadas, de modo explícito, no comentário de classe do Javadoc (como palavras como "Clientes podem criar sub-classes.").
-
Criadores de sub-classes restritos. Não cria uma sub-classe de uma classe da API que não se destine a permitir a criação de sub-classes. Trate essas classes como se tivessem sido declaradas como finais. (São por vezes referidas como classes finais flexíveis.)
Chamar métodos da API protegidos
Chamar método protegidos e privadas herdados a partir de uma sub-classe é, geralmente, permitido; no entanto, muitas vezes, isso requer mais cuidado para chamar correctamente, do que seria necessário para chamar métodos a partir do exterior da hierarquia.
Substituir métodos da API
Apenas um sub-conjunto dos métodos da API públicos e protegidos se destina a ser substituído. Cada método da API tem um contrato de sub-classe que indica os termos sob os quais uma sub-classe o pode substituir. Por predefinição, a substituição não é permitida.
É importante verificar o contrato de sub-classe na implementação do método real
que está a ser substituída; os termos dos contratos de sub-classes não são
transmitidos automaticamente quando o método é substituído.
-
Não substitua um método da API público ou protegido, a não ser que seja explicitamente permitido. A não ser que se indique o contrário, trate todos os métodos como se tivessem sido todos declarados como finais. (São por vezes referidas como métodos finais flexíveis.) Se o tipo de substituição permitida for:
- "implement" - o método abstracto declarado na sub-classe tem de ser implementado por uma sub-classe concreta.
- "extend" - o método declarado na sub-classe tem de invocar o método na super-classe (exactamente uma vez).
- "re-implement" - o método declara na sub-classe não pode invocar o método na super-classe.
- "override" - o método declara na sub-classe é livre para invocar o método na super-classe como achar adequado.
-
Assegurar pós-condições.Assegure que quaisquer pós-condições especificadas para o método da API são cumpridas pela implementação após o retorno.
-
Verificar pró-activamente as pré-condições. Não parta do princípio que as pré-condições especificadas para o método da API foram necessariamente cumpridas à entrada. Embora a implementação de método esteja dentro dos seus direitos de não verificar as pré-condições especificadas, é boa ideia verificar as pré-condições (quando for viável e razoavelmente pouco dispendioso), para permitir avisar sobre a existências de chamadores incorrectos.
-
Resultado nulo. Não devolva o valor nulo como um resultado do método da API, a não ser que o resultado esteja explicitamente documentado (ao especificar a interface ou super-classe) como permitindo um valor nulo.
-
Devolver cópias. Não devolva um conjunto, recolha ou qualquer outro objecto mutável insubstituível como resultado de um método da API. Devolve sempre uma cópia para evitar problemas com os chamadores que podem modificar o objecto.
Implementar interfaces da API da plataforma
Apenas um sub-conjunto das interfaces da API se destina a ser implementado pelos clientes. As interfaces da API têm um contrato que indica os termos sob os quais devem ser implementadas. As interfaces que se destinam a ser implementadas pelos clientes estão sinalizadas, de modo explícito, no comentário de classe do Javadoc (com palavras como "Clientes podem implementar."). Um cliente pode declarar uma sub-interface de uma interface da API se, e apenas se, for permitido implementá-la.
-
Implementadores restritos. Não implemente uma interface da API que esteja documentada como disponível apenas para determinados terceiros, a não ser que seja um deles. Em muitas situações, as interfaces são utilizadas para ocultar os detalhes da implementação interna da visualização.
Implementar métodos da API públicos
Consultar "Substituir métodos da API".
Aceder a campos nas classes e interfaces da API
Os clientes podem ler os campos da API, a maior parte do quais são campos finais. Determinados objectos semelhantes a estruturas podem ter campos públicos não finais, que os clientes podem ler e gravar, a não ser que se indique o contrário.
-
Campos nulos. Não defina um campo da API como nulo, a não ser que seja explicitamente permitido.
Converter temporariamente objectos de um tipo de API conhecido
Um objecto de um tipo de API conhecido pode apenas ser convertido temporariamente para um tipo de API diferente (ou convertido condicionalmente utilizando instanceof), se isso for explicitamente permitido na API.
-
Converter temporariamente e método instanceof. Não utilize as expressões instanceof e cast para aumentar o que se sabe sobre um objecto para além do que a API suporta.
O uso inadequado expõe detalhes de implementação acidentais que não são garantidos pela API.
E, claro, converter temporariamente um objecto para uma classe ou interface que não seja da API é sempre algo inadequado.
Não seguir as regras
Quer o faça com conhecimento ou inadvertidamente, estas são as consequências por transgredir as regras. Pode ser mais fácil para todos os envolvidos, se existisse uma política da API que o prendesse por quebrar as regras. No entanto, não é esse o caso.
Na generalidade, a conformidade da API opera como um sistema de honra, sendo cada cliente responsável por conhecer as regras e respeitá-las.
Os contratos dos elementos da API delimitam o comportamento que é suportado e sustentado. À medida que a plataforma Eclipse progride e evolui, serão os contratos da API a guiar o utilizador sobre o modo como essa evolução acontece. Fora destes contratos, tudo o resto não será suportado e está sujeito a alterações, sem aviso prévio e a qualquer altura (mesmo a meio das edições ou entre plataformas de sistemas operativos diferentes). O código de cliente que se sobreponha às regras anteriores poderá falhar em diferentes versões e níveis de correcções da plataforma; ou quando executado em diferentes sistemas operativos subjacentes; ou quando executado com uma mistura diferente de plug-ins co-residentes; ou ainda quando executado com uma perspectiva de ambiente de trabalho diferente e assim em diante. De facto, ninguém se interessa muito pela especulação exacta do modo como qualquer transgressão específica poderá afectar o utilizador. Os utilizadores que optarem por ignorar as regras não poderão dizer que não foram avisados. E não devem esperar mais do que uma resposta cordial do género "Nós avisámos".
Por outro lado, o código do plug-in de cliente que sobrevive através das regras anteriores deverá continuar a funcionar através das diferentes versões e níveis de correcções da plataforma, através de diferentes sistemas operativos subjacentes e deverá co-existir de modo pacífico com os outros plug-ins. Se todos os utilizadores cumprirem as regras, a plataforma Eclipse irá proporcionar uma base estável e suportada no qual poderá construir novos e excitantes produtos.