Don't Repeat Yourself o DRY és un principi important en el desenvolupament de programari. Aquesta publicació us mostrarà com aplicar-la a la configuració d'Apache APISIX.
"No et repeteixis" (DRY) és un principi de desenvolupament de programari dirigit a reduir la repetició d'informació que és probable que canviï, substituint-la per abstraccions que tinguin menys probabilitats de canviar o utilitzant la normalització de dades que evita la redundància en primer lloc. .
La idea principal de DRY és que si et repeteixes i la informació canvia, hauràs d'actualitzar la informació canviada en diversos llocs. No només és un esforç addicional; hi ha la possibilitat que t'oblidis i tinguis informació diferent en diferents llocs. DRY brilla en la correcció d'errors.
Imagineu un fragment de codi que conté un error. Imagineu ara que heu duplicat el fragment en dos llocs diferents. Ara, heu de solucionar l'error en aquests dos llocs, i aquesta és la part fàcil; el difícil de saber sobre la duplicació en primer lloc.
Hi ha una gran probabilitat que la persona que duplica i la que arregla siguin diferents. Si el fragment s'havia refactoritzat per compartir-lo i cridar-lo des dels dos llocs, només cal que arregleu l'error en aquest lloc.
La majoria de la gent associa DRY amb el codi. Tanmateix, podria ser més limitant i contrari a la idea original.
El principi ha estat formulat per Andy Hunt i Dave Thomas al seu llibre The Pragmatic Programmer. Ho apliquen de manera bastant àmplia per incloure esquemes de bases de dades, plans de prova, el sistema de compilació, fins i tot documentació.
Els sistemes de configuració de so permeten DRY o fins i tot ho fomenten.
Apache APISIX ofereix una configuració DRY en dos llocs.
En un context de comerç electrònic, el vostre viatge de principiant per definir una ruta a Apache APISIX probablement comenci de la següent manera:
routes: - id: 1 name: Catalog uri: /products* upstream: nodes: "catalog:8080": 1
Si esteu familiaritzat amb APISIX, hem definit una ruta al catàleg sota l'URI /products
. Tanmateix, hi ha un problema: probablement voleu que els possibles clients naveguin pel catàleg, però voleu evitar que la gent creï, suprimeixi o actualitzi productes. Tanmateix, la ruta coincideix amb tots els mètodes HTTP per defecte.
Hauríem de permetre que només els usuaris autenticats gestionin el catàleg perquè tothom pugui navegar-hi lliurement. Per implementar aquest enfocament, hem de 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
és el connector més senzill per a això
Hem solucionat el problema de seguretat de la manera més senzilla possible: copiant i enganxant. En fer-ho, vam duplicar la secció upstream
. Si necessitem canviar la topologia, per exemple , afegint o eliminant nodes, ho hem de fer en dos llocs. Derrota el principi DRY.
En escenaris del món real, especialment quan involucren contenidors, no implementareu l' upstream
enumerant nodes
. En lloc d'això, hauríeu d'implementar un descobriment de serveis dinàmics per adaptar-se als canvis de topologia. No obstant això, el punt continua sent quan necessiteu canviar la configuració o la implementació del descobriment del servei. Per tant, el meu punt s'aplica igualment als nodes i al descobriment de serveis.
Juntament amb l'abstracció de ruta , APISIX ofereix una abstracció Upstream per implementar DRY. Podem reescriure el fragment anterior així:
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 passa alguna cosa a la topologia, haurem d'actualitzar el canvi només en l'únic Upstream .
Tingueu en compte que definir l'element incrustat upstream
i fer-ne referència amb upstream_id
s'exclouen mútuament .
Una altra àrea on APISIX us pot ajudar a assecar la vostra configuració amb l'abstracció del connector . APISIX implementa la majoria de les funcions, si no totes, mitjançant connectors
Implementem versions basades en camins a la nostra API. Hem de reescriure l'URL abans de reenviar-lo.
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
abans de reenviar
Igual que amb upstream
anterior, la secció plugins
està duplicada. També podem tenir en compte la configuració del connector en un objecte de configuració del connector dedicat. El fragment següent té el mateix efecte que l'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
Els lectors astuts podrien haver notat que em falta part de la configuració: la auth-key
ha desaparegut misteriosament! De fet, el vaig treure per claredat.
A diferència de upstream
i upstream_id
, plugins
i plugin_config_id
no s'exclouen mútuament . Podem solucionar el problema només afegint el plugin
que falta:
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
D'aquesta manera, podeu moure la configuració compartida a un objecte plugin_config
i mantenir-ne un de específic al lloc on s'aplica. Però, què passa si el mateix connector amb configuracions diferents s'utilitza a plugin_config
i directament a la route
? La documentació és bastant clara al respecte:
Consumer
>Consumer Group
>Route
>Plugin Config
>Service
En resum, la configuració plugin
en una route
anul·la la configuració del plugin_config_id
. També ens permet proporcionar la variable apikey
per al connector key-auth
en un consumer
i només establir-la en una ruta. APISIX trobarà i utilitzarà la clau per a cada consumer
!
DRY no es tracta només de codi; es tracta de la gestió de dades en general. La configuració és dades i, per tant, cau sota aquest paraigua general.
APISIX ofereix dues opcions DRY: una per upstream
- upstream_id
, i una per plugin
- plugin_config_id
. Les aigües amunt són exclusives; els connectors permeten anul·lar.
Tots dos mecanismes haurien d'ajudar-vos a assecar la vostra configuració i fer-la més fàcil de mantenir a llarg termini.
Per anar més enllà:
Publicat originalment a A Java Geek l'1 de setembre de 2024