Kompatybilność naprzód
Czym jest kompatybilność naprzód
Kompatybilność naprzód to zdolność systemu do prawidłowej pracy z nowszymi klientami lub danymi niż te, dla których został pierwotnie zaprojektowany. Prostsze: stary serwer nie pęka, gdy przychodzi do niego nowy klient; stary konsument nie upada, gdy napotyka nową wiadomość.
Naprzód różni się od kompatybilności wstecznej (kiedy nowy system obsługuje starych klientów) w kierunku odpowiedzialności: projektujemy protokoły i klientów w taki sposób, aby „przetrwać” przyszłe rozszerzenia bez całkowitej modernizacji całego ekosystemu.
Podstawowe zasady
1. Tolerancyjny czytelnik i tolerancyjny pisarz
Czytelnik ignoruje nieznane pola/nagłówki i pozwala na nowe wartości enum z prawidłowym odchyleniem.
Writer nie wysyła niczego, co serwer nie zadeklarował wprost jako obsługiwane (możliwości).
2. Negocjacje w sprawie zdolności
Wyraźna wymiana możliwości (funkcje/wersje/typy mediów) na etapie uścisku dłoni. Klient dostosowuje swoje zachowanie do odpowiedzi serwera.
3. Domyślna degradacja
Nowe funkcje są uważane za opcjonalne: jeśli serwer/konsument ich nie obsługuje, skrypt nadal zakończy się przydatnym minimum (MGC).
4. Stabilny rdzeń (MGC)
Minimalna umowa gwarancyjna nie ulega zmianie; innowacje żyją jako rozszerzenia.
5. Umowy o błąd w ramach protokołu
Przewidywalne kody/przyczyny („funkcja nie obsługiwana”, „nieznany typ nośnika”) pozwalają klientowi automatycznie wrócić do obsługiwanego trybu.
6. Wersje bez niespodzianek
Główne linie oddzielone; niewielkie rozszerzenia nie wymagają uaktualnienia serwera/konsumenta.
Gdzie to ma znaczenie
Publiczne API z długotrwałymi integracjami (partnerzy, SDK w aplikacjach mobilnych).
Platformy imprez z wieloma niezależnymi konsumentami.
Klienci mobilni, którzy aktualizują się wolniej niż backend.
Krawędź/IoT, gdzie część floty urządzenia rzadko miga.
Wzory implementacji według stylu
REST/HTTP
Negocjacje:- 'Akceptuj '/typy nośników z parametrami (' application/vnd. przykład. kolejność + json; v = 1; profil = ryzyko ").
- "Preferuj: include =... "dla opcjonalnych bloków.
- Tytuł 'X-Capabilities: risk_score,item_details_v2'.
- Wysyła żądanie w formacie podstawowym, rozszerzenia - tylko wtedy, gdy serwer ma potwierdzoną funkcję (poprzez OPCJE/desc/lead endpoint).
- Gdy '415/406/501' jest automatycznie zwijane z powrotem do obsługiwanego formatu/metody.
- Odpowiedź serwera: nieznane parametry - ignoruj; dozwolone są dodatkowe pola; stabilny format błędu ("type/code/detail/trace _ id').
gRPC/Protobuf
Stabilne usługi: nowe metody/pola - dodatek; stary serwer po cichu ignoruje nieznane pola żądania.
Odkrycie funkcji: Metoda 'BlackCapabilities ()' zwraca listy funkcji/limitów. Klient nie wywołuje metody v2, chyba że serwer ją zadeklaruje.
Streaming: ustawić kolejność minimalnego zestawu wiadomości; zaznaczyć nowe „ramki” z rozszerzeń/typów, które stary klient ignoruje.
GraphQL
Przyjazne do przodu: na serwerze pojawiają się nowe pola/typy - starzy klienci po prostu ich nie żądają.
Domysły są zabronione: klient musi zachować system (introspekcja/kodogen) i nie wysyłać nieznanych dyrektyw/zmiennych.
Degradacja: jeśli serwer nie zna dyrektywy niestandardowej/funkcji, klient buduje żądanie bez niej.
Imprezy (Kafka/NATS/Pulsar, Avro/JSON/Proto)
Kompatybilność systemu w rejestrze: starzy konsumenci mogą odczytywać wiadomości napisane przez nowy system.
Domyślne pola addytywne: nowi producenci nie łamią starych konsumentów.
Rdzeń vs Wzbogacony: jądro pozostaje takie same, nowe informacje są publikowane w '.enriched' lub jako opcjonalne pola.
Praktyki projektowe
1. Minimalna umowa o zamówienie (MGC)
Operacja powinna mieć „wąską szyję”, którą wszystkie serwery będą obsługiwać przez wiele lat.
2. Flagi funkcji na poziomie kontraktu
Opisz funkcje jako funkcje nazwane: 'risk _ score', 'pricing _ v2', 'strong _ idempotence'. Klient wyraźnie je zawiera.
3. Wyraźne kody błędów dla „nie obsługiwane”
HTTP: '501 Not Implemented', '415 Unsupported Media Type', деталкна 'problem + json'.
gRPC: „UNIMPLEMENTED ”/„ FAILED _ PRECONDITION”.
Zdarzenia: trasa w DLQ z 'reason = unsupported _ feature'.
4. Nie polegaj na zamówieniu/kompletnych listach
Klient musi być gotowy na nowe wartości enum, brak nowych pól i „dodatkowe” właściwości.
5. Stabilne identyfikatory i formaty
Nie zmieniaj formatu ID/partycjonowania klawiszy w linii - to pęka do przodu po stronie czytników.
6. Dokumentacja „do odczytu maszynowego”
Deskryptory hosta: OpenAPI/AsyncAPI/Proto deskryptory/GraphQL SDL. Klienci mogą zweryfikować wsparcie dla tej funkcji.
Testowanie zgodności naprzód
Schema-diff w trybie FORWARD/FULL: nowy schemat zwaliduje starego konsumenta/serwera.
Testy kontraktów klienckich: Nowy klient jest wykonywany na starym serwerze z funkcjami włączonymi/wyłączonymi.
Złote żądania: zestaw „nowych” żądań jest uruchamiany przez „stary” serwer; spodziewana degradacja bez błędów krytycznych.
Chaos/latency: check timeout/retray - nowy klient musi prawidłowo przetrwać najgorsze SLA starego serwera.
Canary: niektórzy nowi klienci współpracują z poprzednią wersją serwera - zbieramy telemetrię błędów/degradacji.
Obserwowalność i wskaźniki operacyjne
Odsetek żądań/wiadomości z nieoprocentowanymi funkcjami i ich automatycznymi rolkami.
Dystrybucja według wersji klienta (User-Agent/metadane/claims).
"UNIMPLEMENTED/501/415Pomiary i trasy w DLQ z" unsupported _ feature ".
Czas degradacji: p95/p99 dla odpowiedzi MGC vs „rozszerzonej”.
Tryby kompatybilności w rejestrze schematu
NAPRZÓD: nowy wpis jest kompatybilny ze starym czytnikiem (domyślne są potrzebne, opcjonalność).
PEŁEN: DO PRZODU, DO TYŁU; wygodne dla zamówień publicznych.
Zalecenie: dla wydarzeń - BACKWARD dla producenta i FORWARD dla konsumenta (za pośrednictwem czytnika tolerancyjnego), dla zewnętrznych API - FULL.
Przykłady
REST (możliwości + degradacja)
1. Klient robi 'GET/meta/capabilities' → '{„risk _ score”: false,' price_v2": true} '.
2. Na „POST/zlecenia” wysyła pola bazowe; 'risk _ score' nie żąda, ponieważ serwer nie może tego zrobić.
3. Jeśli przypadkowo wysłano opcję „Prefer: include = risk _ score”, serwer odpowiada 200 bez pola „risk _ score” (lub „Preference-Applied: none”) - klient nie rozbija się.
gRPC (odkrycie)
Lista/funkcja zwróconej metody 'BlackCapabilities ()'. Klient nie wywołuje 'CaptureV2', jeśli nie jest obecny - zamiast tego używa 'Capture' i lokalnie konwertuje wejście do obsługiwanego widoku.
Wydarzenia (FORWARD w rejestrze)
Producent dodał pole „risk _ score” (nieważne z domyślnym). Stary konsument go ignoruje; jego logika używa tylko stabilnych pól jądra.
Antypattery
Twardy klient: filtruje odpowiedź przez pola białej listy i spada na nieznanej nieruchomości.
Funkcje Implicit: Klient zaczyna wysyłać nowy parametr bez sprawdzania możliwości.
Zmiana identyfikatora/kluczowych formatów w linii → stare serwery/konsumenci nie rozumieją już nowych żądań/wiadomości.
Hardwired założenia o pełnej liście enum (przełącznik bez domyślnego).
Rejestrowanie jako kontrola przepływu: ciągi błędów parsowania zamiast kodów kontraktowych.
Lista kontrolna implementacji
- zdefiniowane MGC; nowe funkcje są oznaczone jako opcjonalne.
- Opisano i wdrożono negocjacje dotyczące zdolności (punkt końcowy/metadane/uścisk dłoni).
- Klienci ignorują nieznane pola i prawidłowo obsługują nowe enum (fallback).
- Kontrakty na błędy przechwytują „nie obsługiwane” przewidywalnie (HTTP/gRPC/Event).
- Rejestr schematu jest ustawiony na FORWARD/FULL dla odpowiednich artefaktów.
- Autotests: schema-diff (FORWARD), client vs. Old server contract tests, canary.
- Metryki: wersja klienta, awaria funkcji, szybkość degradacji, p95 MGC.
- Dokumentacja/SDK publikują listę cech i przykładów degradacji.
NAJCZĘŚCIEJ ZADAWANE PYTANIA
Czym się różni od wstecznych w praktyce?
Wstecz: nowy serwer nie łamie starych klientów. Do przodu: stary serwer nie zrywa z nowymi klientami (lub stary konsument z nowych wiadomości). Idealnie, osiągasz pełnię.
Czy zawsze muszę wprowadzać możliwości?
Jeśli oczekujesz aktywnej ewolucji bez synchronicznych zwolnień, tak. To tańsze niż trzymanie dziesiątek głównych linii.
A co z ochroną?
Nowe funkcje powinny wymagać oddzielnych zakresów/roszczeń. Jeśli serwer ich nie obsługuje, klient nie powinien zmniejszać bezpieczeństwa, ale powinien zrezygnować z funkcji.
Czy możliwe jest „odgadnięcie” wsparcia przez wersję serwera?
Niepożądane. Lepiej zapytać wprost (możliwości) lub spojrzeć na rodzaj/schemat mediów.
Razem
Dalsza interoperacyjność to dyscyplina negocjacji i bezpieczna degradacja. Stabilny rdzeń, negocjacje z możliwościami, dodatkowe rozszerzenia i przewidywalne błędy pozwalają nowym klientom i danym dogadać się ze starymi serwerami i konsumentami - bez masowych wydań i nocnych migracji.