Don't Repeat Yourself of DRY is een belangrijk principe in softwareontwikkeling. Deze post laat zien hoe je het toepast op Apache APISIX-configuratie.
"Don't repeat yourself" (DRY) is een principe van softwareontwikkeling dat gericht is op het verminderen van de herhaling van informatie die waarschijnlijk zal veranderen, door deze te vervangen door abstracties die minder waarschijnlijk veranderen, of door gebruik te maken van datanormalisatie om redundantie in de eerste plaats te voorkomen.
Het hoofdidee achter DRY is dat als je jezelf herhaalt en de informatie verandert, je de gewijzigde informatie op meerdere plekken moet updaten. Het kost niet alleen extra moeite; er is een kans dat je het vergeet en dat je op verschillende plekken andere informatie hebt. DRY blinkt uit in het oplossen van bugs.
Stel je een codefragment voor dat een bug bevat. Stel je nu voor dat je het fragment op twee verschillende plekken hebt gedupliceerd. Nu moet je de bug op deze twee plekken oplossen, en dat is het makkelijke gedeelte; het moeilijke is om in de eerste plaats te weten dat er sprake is van duplicatie.
Er is een grote kans dat de persoon die dupliceert en degene die repareert verschillend zijn. Als het fragment was gerefactored om deelbaar te zijn en in plaats daarvan vanaf de twee plekken was aangeroepen, hoef je de bug alleen op deze ene plek te repareren.
De meeste mensen associëren DRY met code. Het zou echter beperkender en tegenstrijdiger kunnen zijn met het oorspronkelijke idee.
Het principe is geformuleerd door Andy Hunt en Dave Thomas in hun boek The Pragmatic Programmer. Ze passen het vrij breed toe, inclusief databaseschema's, testplannen, het bouwsysteem en zelfs documentatie.
Geluidsconfiguratiesystemen staan DROOG toe of moedigen het zelfs aan.
Apache APISIX biedt DRY-configuratie op twee plaatsen.
In een e-commercecontext begint uw beginnersreis om een route op Apache APISIX te definiëren waarschijnlijk als volgt:
routes: - id: 1 name: Catalog uri: /products* upstream: nodes: "catalog:8080": 1
Als u bekend bent met APISIX, hebben we een route naar de catalogus gedefinieerd onder de /products
URI. Er is echter een probleem: u wilt waarschijnlijk dat potentiële klanten door de catalogus bladeren, maar u wilt voorkomen dat mensen producten maken, verwijderen of updaten. Toch komt de route standaard overeen met elke HTTP-methode.
We zouden alleen geauthenticeerde gebruikers de catalogus moeten laten beheren, zodat iedereen er vrij doorheen kan bladeren. Om deze aanpak te implementeren, moeten we de route in tweeën splitsen:
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
is de eenvoudigste plugin hiervoor
We hebben het beveiligingsprobleem op de eenvoudigste manier opgelost: door kopiëren en plakken. Daarmee hebben we de upstream
sectie gedupliceerd. Als we de topologie moeten wijzigen, bijvoorbeeld door knooppunten toe te voegen of te verwijderen, moeten we dat op twee plaatsen doen. Het verslaat het DRY-principe.
In real-world scenario's, met name wanneer ze containers betreffen, zou u de upstream
niet implementeren door nodes
op te sommen. U zou in plaats daarvan een dynamische service discovery moeten implementeren om topologiewijzigingen te accommoderen. Het punt blijft echter staan wanneer u de service discovery-configuratie of -implementatie moet wijzigen. Daarom is mijn punt evenzeer van toepassing op nodes als op service discovery.
Samen met de Route- abstractie biedt APISIX een Upstream- abstractie om DRY te implementeren. We kunnen het bovenstaande fragment als volgt herschrijven:
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
Als er iets in de topologie gebeurt, moeten we de wijziging alleen in de enkele Upstream bijwerken.
Houd er rekening mee dat het definiëren van de upstream
embedded en het ernaar verwijzen met upstream_id
elkaar uitsluiten .
Een ander gebied waar APISIX u kan helpen uw configuratie te DROGEN met de Plugin- abstractie. APISIX implementeert de meeste functies, zo niet alle, via plugins
Laten we path-based versioning implementeren op onze API. We moeten de URL herschrijven voordat we deze doorsturen.
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
voorvoegsel voordat u doorstuurt
Net als bij upstream
hierboven, is de plugins
sectie gedupliceerd. We kunnen de plugin configuratie ook factoriseren in een dedicated Plugin Config object. Het volgende fragment heeft hetzelfde effect als het fragment hierboven:
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
Oplettende lezers hebben misschien opgemerkt dat ik een deel van de configuratie mis: de auth-key
is op mysterieuze wijze verdwenen! Ik heb hem inderdaad verwijderd voor de duidelijkheid.
In tegenstelling tot upstream
en upstream_id
, zijn plugins
en plugin_config_id
niet wederzijds exclusief . We kunnen het probleem oplossen door gewoon de ontbrekende plugin
toe te voegen:
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
Op deze manier kunt u de gedeelde configuratie verplaatsen naar een plugin_config
object en een specifieke behouden op de plaats waar deze van toepassing is. Maar wat als dezelfde plugin met verschillende configuraties wordt gebruikt in de plugin_config
en direct in de route
? De documentatie is er vrij duidelijk over:
Consumer
>Consumer Group
>Route
>Plugin Config
>Service
Kortom, de plugin
in een route
overruled de configuratie in de plugin_config_id
. Het stelt ons ook in staat om de apikey
variabele voor de key-auth
plugin in een consumer
te verstrekken en deze alleen in een route in te stellen. APISIX vindt en gebruikt de sleutel voor elke consumer
!
DRY gaat niet alleen over code; het gaat over datamanagement in het algemeen. Configuratie is data en valt dus onder deze algemene paraplu.
APISIX biedt twee DRY-opties: één voor upstream
- upstream_id
, en één voor plugin
- plugin_config_id
. Upstreams zijn exclusief; plugins staan overruling toe.
Beide mechanismen helpen u bij het DROGEN van uw configuratie en maken deze op de lange termijn beter onderhoudbaar.
Om verder te gaan:
Oorspronkelijk gepubliceerd op A Java Geek op 1 september 2024