Come evitare che le modifiche a un'API interna interrompano altri progetti?

8

Abbiamo 20-30 moduli / soluzioni indipendenti. Ognuno di questi ha circa 7 - 10 progetti con classi, componenti, ecc. Questi sono tutti utilizzati internamente alla nostra azienda.

Il nostro problema è quando apportiamo una modifica in un modulo, quindi dobbiamo assicurarci di aggiornare tutti gli altri moduli che stanno accedendo a questo codice. Questo è difficile da sapere perché è in diverse codebase.

Come possiamo documentare dove sono tutti gli usi esterni di un'API? O altrimenti impedire piccoli cambiamenti da rompere altri moduli?

    
posta Mathematics 17.09.2015 - 13:14
fonte

5 risposte

13

La soluzione più semplice, IMO, è avere un numero decente di test automatizzati per ciascun prodotto. Quando si aggiorna una libreria, si esegue la suite di test per ciascun prodotto. Se i test falliscono, allora saprai quali prodotti devono essere aggiornati.

    
risposta data 21.09.2015 - 15:20
fonte
5

Suggerirei di non provare a documentare questo (almeno manualmente) come se richiedeste alle persone di aggiornarlo, per cui è necessario un alto livello di accuratezza per funzionare correttamente. Ma non otterrai mai quel livello di accuratezza perché aggiungere questo tipo di documentazione non sarebbe divertente e nessuno lo farà.

Alcune migliori opzioni:

  • Avere uno script che genera un elenco utilizzabile di tutte le chiamate di metodo in tutti gli altri moduli, in base ai criteri di ricerca. Semplice, grezzo, ma probabilmente efficace.
  • Una sorta di sistema di versioni in cui non si interrompe la compatibilità con le versioni precedenti ad eccezione dei numeri di versione principali. Quindi, se cambi metodo dalla versione 2.1 alla 2.2, tutta la versione di riferimento 2.X del codice funzionerà ancora. Quando è necessario interrompere questa compatibilità, aggiornare il numero di versione principale (quindi, in questo caso, 3.0) e annunciarlo a tutti i proprietari del progetto responsabili per altri moduli. A seconda di come funziona il tuo processo di rilascio, ciò potrebbe essere semplice - o incredibilmente complicato - da implementare.
  • Avere test automatici o un processo di compilazione di elementi di configurazione in cui ogni volta che si esegue il push di un codice, una build esegue test di qualche tipo. Questo ti consentirà di identificare dove si verificano i problemi. La mia ipotesi è con ciò che stai descrivendo come problema che non hai già presente.
  • Una sorta di sistema di documentazione automatica per tutti i tuoi moduli / repository

Potresti anche considerare di rifare lentamente le API per non essere così fragili, ma mi aspetto che ciò non rientri nello scopo di ciò che puoi ottenere ragionevolmente se sei un individuo e hai 20 o più moduli su larga scala con cui lavorare.

    
risposta data 21.09.2015 - 15:25
fonte
2

Prima di tutto, un'API con usi esterni non dovrebbe cambiare.

Come menzionato da @BryanOakley, l'uso di test unitari automatizzati è molto importante e salva la vita in tali situazioni. Oltre a ciò, alcuni suggerimenti che potrebbero (o potrebbero non, secondo la situazione) aiutarti

  • Molte lingue (come Java e C #) offrono Function/Method Overriding . Lingue come Python ti offrono di passare (un numero illimitato di) argomenti e argomenti di parole chiave a una funzione:

    Java:

    public void disp(char c)
    {
         System.out.println(c);
    }
    
    public void disp(char c, int num)  
    { 
         System.out.println(c + " " + num);
    }
    
    disp("A")
    disp("A", 3)
    

    Python

    def disp(c, *args):
        if args:
            num = args[0]
            print("%s %f" % (c, num))
        else:
            print("%s" % c)
    
    disp("A")
    disp("A", 3)
    
  • Molte lingue offrono metodi public , private e protected . Puoi gestire la chiamata di funzione in una funzione public ed eseguire il lavoro in private/protected funzioni.

    In Python, non esiste una definizione pubblica / privata per metodi e funzioni, ma un underscore principale ( _ ) indica che un metodo è privato e non deve essere utilizzato esternamente. Le chiamate API esterne sono gestite da un metodo aperto al mondo esterno e tutte le attività vengono eseguite nelle cosiddette funzioni locali :

    def format_input(a, b, *args, **kwargs):
        # This function is open to anyone. so use *args and **kwargs to get
        # all possible available arguments. Do not change this function
        # definition and function parameters
        a = _evaluate_input(a)
        b  =_evaluate_input(b)
        # c is not used by all APIs and may not documented in all external
        # API docs. So chech if it was sent as a keyword argument. If yes
        # evalaute it too
        if "c" in kwargs:
            c  =_evaluate_input(kwargs.get("c"))
        _check_extra_arguments(args)
        _check_extra_keyward_arguments(kwargs)
    
    def _evaluate_input(value):
        # This is a private method thus should not be called from the
        # outside world. You can change this method and parameter structure 
        # to fit your needs and do not care for outside world since no
        # outer API should use this function directly.
        ...
    
    def _check_extra_arguments(value):
        # We will check if any extra argument is passed and handle them accordingly
        ...
    

Come ho detto, una definizione API che è (anche) utilizzata da applicazioni esterne non dovrebbe essere cambiata così spesso. Puoi cercare modi per rendere più flessibili le tue funzioni esterne, in modo da poter cambiare il funzionamento dell'API senza interrompere lo stato corrente.

    
risposta data 21.09.2015 - 16:09
fonte
1

Our problem is when we make a change in one module, we then need to make sure to update all other modules which are accessing this code. This is difficult to know because it is in different codebases.

Suggerirei che è impossibile sapere.

Sei responsabile per i componenti e le loro interfacce.
Tu sei non responsabile di tutto e di tutto ciò che potrebbe farne uso.

How can we document where all external uses of an API are? Or otherwise prevent small changes from breaking other modules?

Risposta breve? Test.

Scrivi test che esercitano le interfacce pubblicate. Riattivali ogni volta che apporti una modifica. Finché i test "Pass", non hai rotto nulla. Quando un test rompe (e lo sarà) (a) trova e risolve il problema o (b) se giustifichi il cambiamento come legittimo, quindi riscrivi il test per adattarlo.

    
risposta data 22.09.2015 - 13:17
fonte
0

Ho visto e codificato API con numeri di versione nei percorsi e / o nomi di funzioni.

In questo modo puoi avere diverse versioni dell'API disponibili: API complete e diverse versioni delle funzioni all'interno di un'API.

Ciò consente di mantenere tutte le versioni API nel codice per l'API: non è necessario modificare il codice di altre applicazioni oltre a quello per cui è stata prodotta la nuova funzionalità API.

Penso che ciò sia particolarmente importante quando si scrivono API che verranno utilizzate da applicazioni esterne alla propria organizzazione.

Ad esempio, ecco un esempio di codice per inviare un SMS utilizzando l'API di bulksms:

link

da lì è la linea:

string url = ".../submission/send_sms/2/2.0";

dove 2 e 2.0 sono numeri di versione dell'API.

Poiché questa API è destinata all'uso da parte di molti clienti di Bulk SMS, una modifica a questa API potrebbe potenzialmente interrompere molte applicazioni e far squillare il telefono di supporto.

    
risposta data 21.09.2015 - 16:56
fonte