2010-06-21 17 views
7

Estamos utilizando una biblioteca proporcionada por otra persona. Últimamente debido a cambios en esa biblioteca nuestro proyecto tiene 500 errores. Al migrar a la nueva biblioteca descubrimos que solo 15 API están fallando y 500 errores son repetitivos (ocurrencias múltiples de esos 15 errores, ya que las mismas llamadas se utilizan tantas veces).¿Es este un uso excesivo de la abstracción?

Por lo tanto, para la migración propuse la creación de otra clase contenedora interna estática, que envuelve esas llamadas a la API de la biblioteca. Porque si la biblioteca volviera a cambiar tendremos menos código para cambiar y, por lo tanto, el código se volverá más fácil de mantener en el futuro. Y también al envolver las llamadas, evitamos los errores humanos (o los usos involuntarios (sobrecargados) de la API).

Pero algunas personas aquí, no ven el sentido de tener otra clase contenedora, que creen que es totalmente innecesaria. Su único argumento es que, como la mayoría de los cambios de API son solo una línea, siempre podemos cambiarlos usando CTRL + H (Buscar y reemplazar). Y también dicen que esta abstracción adicional que estoy sugiriendo, quita la legibilidad (ya que oculta la llamada API real detrás de otro nombre de método (aunque significativo)) para el codificador/lector.

¿Cuál es el mejor enfoque aquí? ¿Me equivoco con mis sugerencias?

+0

Esto no es una mala idea. No dejes que los nay-sayers te depriman. Si insisten en eliminar esta abstracción, la próxima vez * ellos * pueden ser los que arreglen los más de 500 problemas de compilación de bibliotecas. – FrustratedWithFormsDesigner

+3

Y, utilizando Buscar/Reemplazar en toda la solución garantiza horas de diversión para todo el equipo. – SWeko

+1

SWeko: Creo que aquí hay una broma que me falta. ¿Hay una situación en la que un hallazgo/reemplazo global podría causar "horas" de esfuerzo por más que la persona que realiza el hallazgo/reemplazo? – Ken

Respuesta

8

Es una práctica relativamente común envolver API y bibliotecas inestables con envoltorios personalizados. Un uso común, por ejemplo, es traducir las excepciones de esa biblioteca a su nomenclatura de excepciones.

Más generalmente estos envoltorios son conocidos como un Adaptador, aunque los Adaptadores (IMHO) están más destinados a proporcionar la funcionalidad necesaria por un lado mientras oculta el "idioma" exacto del otro lado, no porque el otro lado sea inestable.

Sin embargo, usted mencionó el uso de la estática. En general, no soy un gran admirador de su uso. En mi humilde opinión, es mejor tener una interfaz que represente la funcionalidad que necesita, y luego tener subtipos de esa interfaz, cuando uno de estos subtipos utiliza la biblioteca de terceros. La ventaja de esto es que un día puede cambiarse a otro proveedor sin cambiar todas las llamadas en su sistema.

De cualquier manera, por lo general, estás en la pista correcta. En mi humilde opinión, cualquier persona que crea que CTRL-H es una herramienta de refactorización válida está pidiendo problemas. ¿Están al menos usando getters y setters (Donde corresponda) en su código?

Además, la parte de legibilidad no está clara para mí. Un adaptador con un nombre legible es tan bueno como una API original con un nombre legible.

+0

Sí, incluso yo estaba confundido con la parte de legibilidad. Pero eso es lo que dijeron :). Probablemente están sugiriendo que la llamada API oculto en otro contenedor podría no hacer que el lector tenga conocimiento de la sintaxis/uso de la API o algo así. –

+0

@Chandan: ¿Por qué el lector debe conocer la sintaxis/uso de la API subyacente? El punto es que quieres minimizar el acoplamiento en la API subyacente – Uri

+0

@Chandan: tiendo a equivocarme por el lado de demasiada abstracción en general: desconfío de cualquier biblioteca que no sea "estándar" (es decir, no de la confiabilidad de un establecer un proyecto de apache). También soy un loco para la usabilidad API así que a menudo escribo mis propios adaptadores. – Uri

12

Esto es realmente conocido como el patrón Adapter, y ha creado específicamente con su problema exacto en mente ....

adaptador se utiliza específicamente para NO agregar funcionalidad, sólo para adaptar una interfaz de un API a una interfaz esperada por la persona que llama. Las interfaces son solo una práctica herramienta OO para implementar la función de adaptadores de una manera consistente y manejable, el patrón en sí mismo básicamente describe cómo resolver un problema.

+2

... ¡y es una buena idea! –

+0

Supongo que el adaptador está destinado a hacer algunos ajustes (es decir, agregar lógica, etc.) con la funcionalidad de terceros existente. Solo estoy envolviendo una llamada a una API de un tercero. ¿Sería aún elegible para ser llamado Adaptador? (ya que tampoco estoy definiendo interfaces). –

+0

Editado la respuesta. – SWeko

1

Difícil de decir sin conocer su código, pero siento que una fachada/adaptador es una buena forma de separar las llamadas de API de su propio código. No llegaría tan lejos para decir que es necesario, pero es más claro.

2

Si una API está cambiando, una envoltura es la única forma de protegerse. Si te has decidido por una API que está cambiando, tienes grandes riesgos para tu proyecto. Mitigar esos riesgos con un contenedor también le permite protegerse si quiere cambiar a otra biblioteca.

Para implementar la envoltura, tiene que hacer la envoltura y hacer su búsqueda y reemplazarla.

De cualquier manera, todavía tiene que tocar todas sus llamadas debido al cambio inicial de la API, por lo que no veo que la pequeña inversión adicional sea un problema.

0

Depende de qué está haciendo la API y si agregar otra capa realmente agrega aislamiento/encapsulado o si simplemente está agregando otra capa de indirección. Si un cambio en la API requerirá un cambio en la interfaz pública de su contenedor, simplemente se interpondrá en el camino.

Una capa de envoltura es más adecuada cuando puede exponer la funcionalidad a un nivel de abstracción que tenga sentido para su aplicación, ocultando la flexibilidad API que no necesita y estandarizando cómo accede a la funcionalidad que necesita. Esto también puede implicar el uso de nombres de funciones y parámetros más específicos para su dominio problemático, lo que puede reducir la dificultad conceptual de comprender cómo se integra la API en su aplicación.

Cuestiones relacionadas