El principio "No te repitas" o "DRY" es importante en el desarrollo de software. En esta publicación, le mostraremos cómo aplicarlo a la configuración de Apache APISIX.
"No te repitas" (DRY) es un principio de desarrollo de software cuyo objetivo es reducir la repetición de información que es probable que cambie, reemplazándola con abstracciones que tienen menos probabilidades de cambiar o utilizando la normalización de datos que evita la redundancia en primer lugar.
La idea principal detrás de DRY es que si repites lo mismo y la información cambia, entonces debes actualizar la información modificada en varios lugares. No solo implica un esfuerzo adicional; existe la posibilidad de que te olvides de ello y tengas información diferente en diferentes lugares. DRY se destaca en la corrección de errores.
Imagine un fragmento de código que contiene un error. Imagine que ha duplicado el fragmento en dos lugares diferentes. Ahora, debe corregir el error en esos dos lugares, y esa es la parte fácil; lo difícil es saber que existe la duplicación en primer lugar.
Existe una gran posibilidad de que la persona que duplica y la que corrige sean diferentes. Si el fragmento se hubiera refactorizado para que se pueda compartir y se lo haya llamado desde los dos lugares, solo necesita corregir el error en este lugar.
La mayoría de las personas asocian DRY con el código. Sin embargo, podría ser más limitante y contrario a la idea original.
El principio fue formulado por Andy Hunt y Dave Thomas en su libro The Pragmatic Programmer. Lo aplican de manera bastante amplia para incluir esquemas de bases de datos, planes de prueba, el sistema de compilación e incluso la documentación.
Los sistemas de configuración de sonido permiten el DRY o incluso lo fomentan.
Apache APISIX ofrece configuración DRY en dos lugares.
En un contexto de comercio electrónico, su viaje de principiante para definir una ruta en Apache APISIX probablemente comience de la siguiente manera:
routes: - id: 1 name: Catalog uri: /products* upstream: nodes: "catalog:8080": 1
Si está familiarizado con APISIX, definimos una ruta al catálogo bajo el URI /products
. Sin embargo, hay un problema: probablemente desee que los posibles clientes exploren el catálogo, pero desea evitar que las personas creen, eliminen o actualicen productos. Sin embargo, la ruta coincide con todos los métodos HTTP de forma predeterminada.
Deberíamos permitir que sólo los usuarios autenticados administren el catálogo para que todos puedan navegar libremente por él. Para implementar este enfoque, necesitamos dividir la ruta en dos:
routes: - id: 1 name: Read the catalogue methods: [ "GET", "HEAD" ] #1 uri: /products* upstream: #2 nodes: "catalog:8080": 1 - id: 1 name: Read the catalogue methods: [ "PUT", "POST", "PATCH", "DELETE" ] #3 uri: /products* plugins: key-auth: ~ #4 upstream: #2 nodes: "catalog:8080": 1
key-auth
es el complemento más simple para esto
Hemos solucionado el problema de seguridad de la forma más sencilla posible: copiando y pegando. Al hacerlo, duplicamos la sección upstream
. Si necesitamos cambiar la topología, por ejemplo , añadiendo o quitando nodos, debemos hacerlo en dos lugares. Esto anula el principio DRY.
En situaciones del mundo real, especialmente cuando involucran contenedores, no implementarías el upstream
mediante la lista nodes
. En su lugar, deberías implementar un descubrimiento de servicios dinámico para adaptarlo a los cambios de topología. Sin embargo, el punto sigue siendo válido cuando necesitas cambiar la configuración o implementación del descubrimiento de servicios. Por lo tanto, mi punto se aplica por igual a los nodos y al descubrimiento de servicios.
Junto con la abstracción de ruta , APISIX ofrece una abstracción de flujo ascendente para implementar DRY. Podemos reescribir el fragmento anterior de la siguiente manera:
upstreams: - id: 1 #1 name: Catalog nodes: "catalog:8080": 1 routes: - id: 1 name: Read the catalogue methods: [ "GET", "HEAD" ] uri: /products* upstream_id: 1 #2 - id: 1 name: Read the catalogue methods: [ "PUT", "POST", "PATCH", "DELETE" ] uri: /products* upstream_id: 1 #2 plugins: key-auth: ~
1
Si algo sucede en la topología, debemos actualizar el cambio solo en el Upstream único.
Tenga en cuenta que definir el incrustado upstream
y hacer referencia al mismo con upstream_id
son mutuamente excluyentes .
Otra área en la que APISIX puede ayudarle a secar su configuración es la abstracción de complementos . APISIX implementa la mayoría de las funciones, si no todas, a través de complementos
Implementemos el control de versiones basado en rutas en nuestra API. Necesitamos reescribir la URL antes de reenviarla.
routes: - id: 1 name: Read the catalogue methods: [ "GET", "HEAD" ] uri: /v1/products* upstream_id: 1 plugins: proxy-rewrite: regex_uri: [ "/v1(.*)", "$1" ] #1 - id: 1 name: Read the catalogue methods: [ "PUT", "POST", "PATCH", "DELETE" ] uri: /v1/products* upstream_id: 1 plugins: proxy-rewrite: regex_uri: [ "/v1(.*)", "$1" ] #1
/v1
antes de reenviar
Al igual que en upstream
anterior, la sección plugins
está duplicada. También podemos incluir la configuración del complemento en un objeto Plugin Config dedicado. El siguiente fragmento tiene el mismo efecto que el anterior:
plugin_configs: - id: 1 #1 plugins: proxy-rewrite: regex_uri: [ "/v1(.*)", "$1" ] routes: - id: 1 name: Read the catalogue methods: [ "GET", "HEAD" ] uri: /v1/products* upstream_id: 1 plugin_config_id: 1 #2 - id: 1 name: Read the catalogue methods: [ "PUT", "POST", "PATCH", "DELETE" ] uri: /v1/products* upstream_id: 1 plugin_config_id: 1 #2
Los lectores astutos pueden haber notado que me falta parte de la configuración: ¡la auth-key
desapareció misteriosamente! De hecho, la eliminé para mayor claridad.
A diferencia de upstream
y upstream_id
, plugins
y plugin_config_id
no son mutuamente excluyentes . Podemos solucionar el problema simplemente agregando el plugin
faltante:
routes: - id: 1 name: Read the catalogue methods: [ "GET", "HEAD" ] uri: /v1/products* upstream_id: 1 plugin_config_id: 1 - id: 1 name: Read the catalogue methods: [ "PUT", "POST", "PATCH", "DELETE" ] uri: /v1/products* upstream_id: 1 plugin_config_id: 1 plugins: key-auth: ~ #1
De esta manera, puedes mover la configuración compartida a un objeto plugin_config
y mantener una específica en el lugar al que se aplica. Pero, ¿qué pasa si se utiliza el mismo complemento con diferentes configuraciones en el plugin_config
y directamente en la route
? La documentación es bastante clara al respecto:
Consumer
>Consumer Group
>Route
>Plugin Config
>Service
En resumen, la configuración plugin
en una route
prevalece sobre la configuración en plugin_config_id
. También nos permite proporcionar la variable apikey
para el complemento key-auth
en un consumer
y solo configurarlo en una ruta. ¡APISIX encontrará y usará la clave para cada consumer
!
DRY no solo se trata de código, sino de gestión de datos en general. La configuración son datos y, por lo tanto, se incluye en este ámbito general.
APISIX ofrece dos opciones DRY: una para upstream
- upstream_id
y otra para plugin
- plugin_config_id
. Los upstream son exclusivos; los plugins permiten la anulación.
Ambos mecanismos deberían ayudarle a secar su configuración y hacerla más fácil de mantener a largo plazo.
Para ir más allá:
Publicado originalmente en A Java Geek el 1 de septiembre de 2024