Plataforma Eclipse
Reglas de compromiso de API
Versión 0.15 - Última revisión a las 12:00 del 30 de mayo de 2001
Estas son las reglas de compromiso para los clientes de la API de la
plataforma Eclipse (y otros componentes).
Qué significa ser una API
La plataforma Eclipse define elementos API para que los utilicen sus clientes,
en especial los proveedores de servicios de Internet (ISV) que escriben
conectores. Estos conectores pueden a su vez definir elementos API para sus
clientes, y así sucesivamente. Los elementos API son la expresión pública:
transportan una especificación de lo que se supone que harán y de cómo está
previsto que deben utilizarse. Los elementos API están soportados: el equipo de
la plataforma Eclipse solucionará los errores de implementación allí donde se
produzca una desviación del comportamiento especificado. Como suele asociarse
un alto coste a los cambios sustanciales de las API, el equipo de la plataforma
Eclipse intentará asimismo desarrollar elegantemente los elementos API en los
sucesivos releases principales.
Cómo distinguir entre las API y las no API
Por su propia naturaleza, los elementos API están documentados y tienen una
especificación, al contrario de lo que ocurre con los elementos no API, que son
detalles de implementación interna por regla general sin documentación
publicada ni especificaciones. Así pues, si no puede encontrarse la documentación de algo, es un buen indicador de que no es API.
Para intentar una distinción más clara, observemos que la base de código de
la plataforma está separado en paquetes de API y de no API, con todos los
elementos API convenientemente declarados en los paquetes de API designados.
-
Paquete de API: paquete Java que contiene al menos una clase API o una
interfaz API. Los nombres de los paquetes de API están anunciados en la
documentación de ese componente; donde sea viable, el resto de los paquetes
que solo contengan detalles de implementación muestran "internal" en el
nombre del paquete. Los nombres de los paquetes de API pueden aparecer
legítimamente en el código cliente. Los nombres válidos para la plataforma Eclipse son:
-
org.eclipse.foo.*: por ejemplo, org.eclipse.swt.widgets,
org.eclipse.ui o org.eclipse.core.runtime.
-
org.eclipse.foo.internal.*: no API; paquetes de implementación internos.
-
org.eclipse.foo.examples.*: no API; son ejemplos.
-
org.eclipse.foo.tests.*: no API; son suites de pruebas.
-
Clase o interfaz de API: clase o interfaz public de un paquete
de API, o un miembro de clase o interfaz public o protected
declarado en alguna otra clase o interfaz de API, o heredero de
ella.
Los nombres de las clases e interfaces de API pueden aparecer
legítimamente en el código cliente.
-
Método o constructor de API: método o constructor public o
protected declarado en una clase o interfaz de API, o heredero de
ella. Los nombres de los métodos de API pueden aparecer legítimamente en el
código cliente.
-
Campo de API: campo public o protected declarado en
una clase o interfaz de API, o heredero de ella. Los nombres de los campos de
API pueden aparecer legítimamente en el código cliente.
El resto se consideran detalles de implementación interna y está fuera de los
límites de todos los clientes. El código de cliente legítimo nunca debe hacer
referencia a los nombres de los elementos no API (ni siquiera utilizando el
reflejo Java). En algunos casos, se utilizan las reglas de accesibilidad a
nombres del lenguaje Java para anular las referencias no permitidas.
Sin
embargo, en muchos casos esto es sencillamente imposible. La observación de
esta sencilla regla evita por completo el problema:
-
Limítese a las API documentadas oficialmente. Solo debe hacer referencia
a los paquetes que estén documentados en el Javadoc de las API
publicadas del componente.
No haga nunca referencia a un paquete que
pertenezca a otro componente que muestre "internal" en su nombre, pues estos
jamás son API. No haga nunca referencia a un paquete para el que no exista un
Javadoc de las API publicadas; estos tampoco son API.
Reglas generales
La especificación de los elementos API se generan a partir de los comentarios
de Javadoc existentes en el código fuente Java del elemento. Para algunos tipos
de elementos, la especificación tiene forma de contrato. Por ejemplo, en el
caso de los métodos, el contrato es entre dos partes, el que llama al método y
el que lo implementa. La regla fundamental es:
-
Respetar todos los contratos. Los contratos se describen en el Javadoc
publicado para los elementos API que esté utilizando.
El término "debe", cuando se utiliza en un contrato de API, significa que es
incumbencia de la parte el asegurar que la condición se cumplirá; cualquier
incumplimiento será considerado un error de programación con consecuencias
no especificadas (y quizás imprevisibles).
-
Hay que respetar el término "debe". Preste especial atención a las
condiciones donde se utilice el término "debe".
Otras reglas de sentido común:
-
No se base en los comportamientos accidentales. El comportamiento
accidental es el que se observa mediante la experimentación o la práctica, sin estar
garantizado por ninguna especificación de la API.
-
No trate el valor nulo como objeto. Nulo significa más que la ausencia
de un objeto.
Presuponga que todo es no nulo, a menos que la especificación
de API diga lo contrario.
-
No intente hacer trampas con el reflejo Java. Utilizar el reflejo
Java para burlar la comprobación del compilador Java no le aporta ningún
beneficio. No hay ningún contrato de API adicional para los usos del reflejo;
este tan solo aumenta la probabilidad de confiar en un comportamiento
no especificado y en los detalles de la implementación interna.
-
Utilice sus propios paquetes. No declare código en un paquete que
pertenezca a otro componente. Declare siempre su propio código en sus propios
paquetes.
Llamar a los métodos de API públicos
Para la mayoría de los clientes, la parte general de las API de Eclipse tiene
el formato de métodos públicos en las interfaces o clases de API,
proporcionados para que el cliente los llame en el momento oportuno.
-
Asegurar las precondiciones. Asegúrese que se cumplan las precondiciones
del método de API antes de llamar al método. Y a la inversa, el llamador puede
presuponer con seguridad que las postcondiciones del método se habrán logrado
inmediatamente después de la devolución de la llamada.
-
Parámetros nulos. No pase un valor nulo como parámetro a un método de
API, a menos que la documentación del parámetro indique explícitamente que
permite los nulos. Este quizás sea el error de programación que se da con más frecuencia.
-
Llamadores restringidos. No llame a un método de API cuya documentación
indique que solo está disponible para determinados llamadores, a menos que
usted sea uno de ellos. En algunas situaciones, los métodos tienen que formar
parte de la API pública para beneficiar cierta clase de llamadores (a menudo
internos); el hecho de llamar a uno de estos métodos en un momento inadecuado
tiene consecuencias no especificadas (y quizás imprevisibles).
-
Métodos para depuración. No llame a un método de API en el que se indique
"solo a efectos de depuración". Por ejemplo, la mayoría de los métodos
toString() se encuentran en esta categoría.
-
Captura de parámetros. No pase como parámetro una matriz, colección u
otro objeto mutable a un método de API ni modifique luego el objeto
pasado. Ello solo sirve para provocar problemas.
Crear instancias de clases API de la plataforma
No todas las clases de API concretas están pensadas para que cualquier persona
cree instancias de ellas.
Las clases de API están sujetas a un contrato de
creación de instancias, que indica los términos bajo los que puede crearse una
instancia. El contrato puede asimismo cubrir cosas como las responsabilidades
de inicialización residual (por ejemplo, configurar una determinada propiedad
antes de que la instancia esté plenamente activa) y las responsabilidades
asociadas al ciclo de vida (por ejemplo, llamar a dispose() para
liberar los recursos del sistema operativo colgados por la instancia). Las
clases diseñadas para que los clientes creen instancias de ellas están
explícitamente marcadas en los comentarios de clases del Javadoc (con frases de
tipo "Los clientes pueden crear instancias").
-
Creadores de instancias restringidos. No cree instancias de una clase de
API cuya documentación indique que solo está disponible para determinados
terceros, a menos que usted sea uno de ellos.
En algunos casos, las clases
tienen que formar parte de la API pública para beneficio de determinados
terceros (a menudo internos); crear una instancia de una de esas clases de
manera incorrecta tendrá consecuencias no especificadas (y quizás
imprevisibles).
Crear subclases de las clases de API de la plataforma
Únicamente un subconjunto de las clases de API están diseñadas para permitir la
creación de subclases. Las clases de API están sujetas a un contrato que indica
los términos bajo los cuales pueden declararse subclases. Este contrato también
cubre las responsabilidades de inicialización y de ciclo de vida. Las clases
diseñadas para que los clientes creen subclases están marcadas explícitamente
en los comentarios de las clases del Javadoc (con frases de tipo "Los clientes pueden
crear subclases").
-
Creadores de subclases restringidos. No cree subclases de una clase de
API que no esté pensada para que se creen subclases de ella. Trate estas clases
como si estuvieran declaradas como finales. (A estas clases se las llama a
veces finales flexibles).
Llamar a métodos de API protegidos
Por lo general, está permitido llamar a los métodos públicos y protegidos
heredados desde dentro de una subclase; no obstante, para ello se suele
necesitar más precaución que cuando se llama a los métodos públicos desde fuera de
la jerarquía.
Alterar temporalmente los métodos de API
Únicamente un subconjunto de los métodos de API públicos y protegidos están
diseñados para permitir su alteración temporal. Cada método de API posee un
contrato de subclase que indica los términos bajo los que una subclase lo
puede alterar temporalmente. Por omisión, no está permitida la alteración
temporal.
Es importante comprobar el contrato de subclase de la implementación
del método real que se vaya a alterar temporalmente; los términos de los
contratos de subclase no se pasan automáticamente cuando el método se altera
temporalmente.
-
No alterar temporalmente un método de API público o protegido, a menos que
ello esté explícitamente permitido. Salvo que se indique lo contrario,
trate todos los métodos como si se hubieran declarado como
finales. (A estos métodos se les llama a veces finales flexibles).
Si la clase
de alteración temporal permitida es:
"implement": el método abstracto declarado en la subclase debe estar
implementado por una subclase concreta.
"extend": el método declarado en la subclase debe invocar el método
de la superclase (exactamente una vez).
"re-implement": el método declarado en la subclase no debe invocar
el método de la superclase.
"override": el método declarado en la subclase es libre de invocar
el método de la superclase si lo considera oportuno.
-
Asegurar las postcondiciones. Asegúrese de que, en el momento del
retorno, la implementación cumple las postcondiciones que se hayan especificado
para el método de API.
-
Comprobar proactivamente las precondiciones. No dé por sentado que las
precondiciones especificadas para el método de API se hayan cumplido
necesariamente en el momento de la entrada. Aunque la implementación del método
esté en su derecho de no comprobar las precondiciones especificadas, suele ser
una buena idea comprobarlas (cuando sea viable y razonablemente económico) para
que avise ante llamadores incorrectos.
-
Resultado nulo. No devuelva el valor nulo como resultado de un método de
API a menos que la documentación indique explícitamente (en la interfaz o en la
superclase que lo especifica) que el resultado permite el valor nulo.
-
Devuelva copias. Como resultado de un método de API, no devuelva una
matriz, colección u otro objeto mutable que sea irreemplazable. Devuelva
siempre una copia para evitar los problemas ocasionados por los llamadores que
podrían modificar el objeto.
Implementar interfaces de API de plataforma
Solo un subconjunto de las interfaces API están diseñadas para permitir su
implementación por los clientes. Las interfaces API tienen un contrato que
indica los términos bajo los cuales se pueden implementar. Las interfaces
diseñadas para implementarse por los clientes están marcadas explícitamente en
los comentarios de las clases del Javadoc (con frases de tipo "Implementable
por clientes"). Un cliente puede declarar una subinterfaz de una interfaz API
única y exclusivamente si le está permitido implementarla.
-
Implementadores restringidos. No implemente una interfaz API cuya
documentación indique que solo está disponible para ciertas personas, a menos
que usted sea una de ellas. En muchos casos, las interfaces se utilizan para
ocultar a la vista los detalles de la implementación interna.
Implementar métodos de API públicos
Vea el apartado "Alterar temporalmente los métodos de API".
Acceder a los campos de las clases y las interfaces de API
Los clientes pueden leer los campos de API, la mayoría de los cuales son
finales. Ciertos objetos de estructura semejante pueden tener campos públicos
no finales, que los clientes pueden leer y en los que pueden escribir, a menos
que se indique lo contrario.
-
Campos nulos. No establezca como nulo un campo de API a menos que esté
explícitamente permitido.
Convertir temporalmente objetos de un tipo de API conocido
Un objeto de un tipo de API conocido solo se puede convertir temporalmente
(cast) a un tipo de API diferente (o convertir condicionalmente con el método
instanceof) si ello está permitido explícitamente en la API.
-
La conversión temporal (cast) y el método instanceof. No utilice las
expresiones instanceof y cast para aumentar lo que se conoce acerca de un
objeto más allá de lo soportado por la API.
Su uso inadecuado pone al
descubierto detalles de implementación accidental no garantizados por la API.
Y, por supuesto, nunca es apropiado convertir temporalmente cualquier objeto a
una clase o interfaz no API.
No cumplir las reglas
Transgredir las reglas, consciente o inconscientemente, trae
consecuencias. Sería más fácil para todos los implicados que existiese una
policía de API que pudiera detenerle por infringir las reglas. Sin embargo,
este no es el caso.
En su mayor parte, la API opera conforme a un sistema
basado en el respeto, por lo que cada cliente es responsable de conocer las
reglas y aceptarlas.
Los contratos de los elementos API delimitan el comportamiento soportado y
sostenido. A medida que la plataforma Eclipse madura y evoluciona, serán los
contratos de API quienes guíen el desarrollo de esta evolución. Fuera de estos
contratos, no hay nada que esté soportado y todo está sujeto a cambios sin
previo aviso y en cualquier momento (incluso entre releases o entre plataformas
de sistemas operativos diferentes). El código cliente que sobrepase las reglas
anteriores puede fallar en versiones diferentes y niveles de parcheado de la
plataforma; o cuando se ejecute en distintos sistemas operativos subyacentes; o
cuando se ejecute con una combinación distinta de conectores corresidentes; o
cuando se ejecute con otra perspectiva del entorno de trabajo; y así
sucesivamente. En efecto, a nadie le interesa en especial especular exactamente
cómo puede verse afectado por una determinada transgresión. Las personas que
opten por hacer caso omiso de las reglas no podrán decir que no se les
advirtió. No podrán esperar mucho más que un cordial "Ya se lo dije".
Por otro lado, el código de los conectores de clientes que se rige por las
reglas anteriores debe continuar funcionando en las diferentes versiones y
niveles de parcheado de la plataforma, en los distintos sistemas operativos
subyacentes, y debe coexistir pacíficamente con los otros conectores. Si todo
el mundo cumple las reglas, la plataforma Eclipse proporcionará una base
estable y soportada en la que construir nuevos y excitantes productos.
