Gestisce la compatibilità con le versioni precedenti delle modifiche API

1

Ho un'API che mi consente di comunicare con un dispositivo. Il protocollo di comunicazione è memorizzato in un file JSON. Elenca gli eventi che il dispositivo può sollevare, le funzioni, il formato dei frame, ecc.

Ma questo file JSON cambia spesso e ho bisogno di mantenere la mia API retrocompatibile con tutti i file JSON.

Ho immaginato delle soluzioni (sto usando Python):

  1. Usa decoratori sulle mie funzioni (@ api_1, @ api_2 ...) ma sarà troppo pesante quando arriverò api 5 o più

  2. Crea una cartella per ogni modifica dell'API

    1. / API
      1. API_1
        1. frame_translation.py ...
      2. API_2
        1. frame_translation.py ...
  3. Un modello di strategia?

La seconda soluzione sembra già migliore della prima, ma probabilmente non la migliore.

Come lo faresti?

    
posta PyNico 01.09.2016 - 21:06
fonte

3 risposte

2

Dato il tuo approccio attuale, la modifica del protocollo di comunicazione non dovrebbe portare a cambiamenti API: poiché il protocollo di comunicazione è memorizzato in un file JSON, la struttura API rimane la stessa per tutti i dispositivi non appena il loro protocollo di comunicazione può efficacemente essere descritto attraverso JSON.

Quando comunichi con un determinato dispositivo, il chiamante dell'API deve semplicemente specificare la versione del protocollo di comunicazione, specificando il JSON o utilizzando un ID e / o una versione attuale del dispositivo, se consente all'API di trovare il corrispondente JSON.

Quando in realtà dovrai modificare la versione dell'API se i dispositivi più recenti utilizzano funzionalità non supportate dall'API precedente, indipendentemente da come modifichi un determinato JSON.

Come confronto, guarda come funziona lo standard USB: tu (per fortuna) non devi aggiornare il tuo sistema operativo ogni volta che viene rilasciato un nuovo dispositivo USB; ciò che è necessario, tuttavia, è installare i driver dei dispositivi che indicano al sistema operativo come comunicare con un dispositivo - questo è simile ai file JSON. Tuttavia, USB 2 è stato sostituito da USB 3 per fornire maggiore velocità e molti altri miglioramenti, cosa che non sarebbe possibile semplicemente aggiungendo un driver.

    
risposta data 01.09.2016 - 21:31
fonte
2

Questa è una variante del versioning semantico (che dovresti anche leggere):

  1. Stabilire un numero di versione per l'API, con numeri principali e secondari separati. Includilo esplicitamente nel file JSON e (se possibile) nell'handshake del protocollo. Inizia dalla versione 1.0 (major.minor).
  2. Quando modifichi un'API compatibile con le versioni precedenti, incrementa il numero secondario.
  3. Quando si modifica un'API incompatibile all'indietro, incrementa il numero maggiore e reimposta il numero minore su 0.
  4. Quando si stabilisce una connessione, se i numeri maggiori non corrispondono, si fallisce l'handshake o si ricorre a una versione precedente del codice, se disponibile.
  5. Non apportare modifiche non reversibili all'indietro (o affatto).

Non conosco i dettagli della tua API, ma qui ci sono alcuni esempi di modifiche compatibili con le versioni precedenti:

  • Presentazione di un nuovo tipo di messaggio. *
  • Aggiunta di un campo facoltativo a un messaggio esistente, con il comportamento predefinito (quando il campo non viene fornito) identico al comportamento precedente.
  • Indebolimento di una precondizione.
  • Rafforzamento di una post-prenotazione.
  • Contrassegnare un tipo di messaggio come deprecato, senza rimuoverlo o alterarlo.

Ecco alcuni esempi di modifiche incompatibili:

  • Rimozione di un tipo di messaggio.
  • Rimozione di un campo da un tipo di messaggio.
  • Aggiunta di un campo obbligatorio a un tipo di messaggio.
  • Modifica del comportamento di un messaggio in un modo che l'altro lato dell'API potrebbe ragionevolmente notare (ad esempio, l'introduzione di un livello di memorizzazione nella cache va bene, restituire risultati diversi non lo è).
  • Rafforzamento di una precondizione.
  • Indebolimento di una post-condizione.

Tecnicamente, non hai proprio bisogno del numero minore. Potresti semplicemente affidarti al controllo della versione per tenere traccia di queste informazioni. Ma i numeri di versione sono più intuitivi degli hash di commit e potresti voler eseguire il rilevamento delle funzioni con il numero minore.

Se non si interrompe la compatibilità con le versioni precedenti, non è necessario nemmeno il numero maggiore. Ma è una buona idea averlo nel caso in cui sia necessario fare un cambio di rottura. Tali cambiamenti dovrebbero essere rari.

D'altra parte, se la tua API non è ancora stata pubblicata e non hai alcun codice cliente che potrebbe essere influenzato dall'incompatibilità con le versioni precedenti, puoi iniziare il numero maggiore a zero invece di uno, per indicare che l'API è provvisorio. Quindi puoi semplicemente apportare le modifiche incompatibili all'indietro che ti piacciono senza toccare il numero maggiore e quando sei pronto per "passare all'oro", vai alla versione 1.0.

* Se è possibile che il destinatario del messaggio sia più vecchio del mittente, è necessario assicurarsi che sia il mittente sia il destinatario siano in grado di gestire il caso in cui il destinatario non riconosce un messaggio o un particolare campo del messaggio . Nelle tipiche API Web server-client, questo è raramente un problema, ma per le API dell'hardware la situazione potrebbe essere molto diversa. È possibile che tu debba considerare questo come un cambio di rottura, il che rende molto più difficile seguire alcuni di questi consigli.

    
risposta data 03.09.2016 - 02:26
fonte
2

In alcuni casi, le strutture devono essere condivise su più sistemi che eseguono versioni di programmi diverse. Avere più strutture dati per abbinare ogni versione del programma (come suggerito sopra) è una soluzione, ma può anche introdurre più problemi come la clonazione dei dati e l'amp; sincronizzazione, spazio aggiuntivo, manutenzione e ampli aggiunti complessità a seconda della soluzione.

Un'altra soluzione è combinare tutte le versioni dei dati in una struttura comune e modificare ciascuna versione del programma per elaborare solo le informazioni che capisce e ignorare il resto. Il meme o il protocollo di versioning sono tutti gli elementi di dati all'interno della struttura dati che sono sconosciuti sono considerati dati relativi a funzioni in versioni superiori e non necessari per questa versione del programma (dati ignorati). Esempi di seguito ..

Tutti i dati della nuova versione devono essere aggiunti alla fine di una struttura dati. Ad esempio v1.0 elabora solo i primi 10 byte. v1.1 elabora i primi 20 byte. v1.3 elabora i primi 40 byte. Questo metodo garantisce che i primi 10 byte necessari al programma v1.0 non vengano mai modificati, in modo che v1.0 sia programmato per analizzare i primi 10 byte e ignorare il resto. Se il primo 10 byte è un ID che v1.3 deve essere 20 byte, non 10, il nuovo ID 20 byte può essere aggiunto come esempio.

Implementa GML linguaggio di markup generale. Il protocollo HTML utilizza questo metodo per offrire la stessa pagina Web a tutte le versioni del browser HTML. Ogni browser è programmato per elaborarlo, ha funzioni di supporto per e ignora i tag.

Un altro approccio è implementare gli indici nella struttura condivisa per ogni dato di versione. È simile al metodo Append sopra ma utilizza indici di [offset, lunghezza] per individuare il segmento di versione dei dati. Tutte le versioni del programma comprendono l'indicizzazione e la utilizzano per individuare i dati necessari. per ridurre la duplicazione dei dati, un elemento di dati si trova solo nel segmento di versione che lo ha introdotto, cioè una nuova versione del programma non ha bisogno di cambiare il modo in cui viene ottenuto un campo versione precedente, in particolare il metodo di codice in v1.0 che estrae un file id è invariato nel codice v1.4 e il file_id è ancora estratto dal segmento di dati v1.0.

    
risposta data 07.09.2016 - 04:09
fonte