Progettazione dell'API: approccio concreto o astratto - best practice?

23

Quando si discutono le API tra i sistemi (a livello di business) ci sono spesso due punti di vista diversi nel nostro team: alcune persone preferiscono un approccio astratto più - diciamo - generico , altro ancora approccio "concreto".

Esempio: la progettazione di una semplice API "ricerca persone". la versione concreta sarebbe

 searchPerson(String name, boolean soundEx,
              String firstName, boolean soundEx,
              String dateOfBirth)

Le persone a favore della versione concreta dicono:

  • l'API è auto-documentante
  • è facile da capire
  • è facile da convalidare (compilatore o come servizio web: convalida dello schema)
  • BACIO

L'altro gruppo di persone nel nostro team direbbe "Questo è solo un elenco di criteri di ricerca"

searchPerson(List<SearchCriteria> criteria)

con

SearchCritera {
  String parameter,
  String value,
  Map<String, String> options
}

con la possibilità di creare "parametri" di un certo tipo di enumerazione.

I sostenitori dicono:

  • senza modificare la (dichiarazione di) dell'API, l'implementazione può cambiare, ad es. aggiungendo più criteri o più opzioni. Anche senza sincronizzare tale modifica al momento della distribuzione.
  • la documentazione è necessaria anche con la variante concreta
  • la convalida dello schema è sopravvalutata, spesso è necessario convalidare ulteriormente, lo schema non può gestire tutti i casi
  • abbiamo già una API simile con un altro sistema: riutilizzare

Il contro-argomento è

  • molta documentazione su parametri validi e combinazioni di parametri validi
  • maggiore sforzo di comunicazione perché è più difficile da comprendere per gli altri team

Ci sono delle buone pratiche? Letteratura?

    
posta erik 11.09.2013 - 22:46
fonte

10 risposte

17

Dipende da quanti campi stai parlando e da come vengono utilizzati. Il calcestruzzo è preferibile per query altamente strutturate con solo pochi campi, ma se l'interrogazione tende ad essere molto libera, l'approccio concreto diventa rapidamente ingombrante con più di tre o quattro campi.

D'altra parte, è molto difficile mantenere pura un'API generica. Se fai una semplice ricerca dei nomi in molti posti, alla fine qualcuno si stancherà di ripetere le stesse cinque righe di codice e lo avvolgeranno in una funzione. Tale API invariabilmente si evolve in un ibrido di una query generica insieme a involucri di cemento per le query più comunemente utilizzate. E non vedo niente di sbagliato in questo. Ti dà il meglio di entrambi i mondi.

    
risposta data 11.09.2013 - 23:39
fonte
7

Progettare una buona API è un'arte. Una buona API è apprezzata anche dopo che il tempo passa. A mio avviso, non ci dovrebbe essere alcun pregiudizio generale sulla linea astratto-concreto. Alcuni parametri possono essere concreti come i giorni della settimana, alcuni richiedono di essere progettati per l'estensibilità (ed è piuttosto stupido renderli concreti, ad esempio parte dei nomi di funzioni), l'ennesimo può andare anche oltre e per avere un'elegante L'API one deve fornire callback o anche un linguaggio specifico del dominio aiuterà a combattere la complessità.

Ci sono raramente cose nuove che accadono sotto la Luna. Dai un'occhiata alla tecnica precedente, in particolare agli standard e ai formati stabiliti (ad esempio, molte cose possono essere modellate dopo i feed, le descrizioni degli eventi sono state elaborate in ical / vcal). Rendi la tua API facilmente additiva, dove le entità frequenti e onnipresenti sono concrete e le estensioni previste sono dizionari. Esistono anche alcuni modelli consolidati per affrontare situazioni specifiche. Ad esempio, la gestione della richiesta HTTP (e simili) può essere modellata nell'API con gli oggetti Request e Response.

Prima di progettare API, fai un brainstorming su aspetti, inclusi quelli, che non saranno inclusi, ma devi essere consapevole di ciò. Esempi di questo sono linguaggio, direzione della scrittura, codifica, locale, informazioni sul fuso orario e simili. Presta attenzione ai luoghi in cui possono apparire i multipli: usa la lista, non il singolo valore per loro. Ad esempio, se stai definendo l'API per il sistema di videochat, la tua API sarà molto più utile, se assumi N partecipanti, non solo due (anche se le tue specifiche al momento sono tali).

A volte, essere astratti aiuta a ridurre drasticamente la complessità: anche se si progetta una calcolatrice per aggiungere solo 3 + 4, 2 + 2 e 7 + 6, potrebbe essere molto più semplice implementare X + Y (con limiti tecnicamente fattibili su X e Y e includi ADD (X, Y) nella tua API invece di ADD_3_4 (), ADD_2_2 (), ...

Tutto sommato, scegliere in un modo o nell'altro è solo un dettaglio tecnico. La tua documentazione dovrebbe descrivere casi di utilizzo frequente in modo concreto.

Qualunque cosa tu faccia sul lato della struttura dati, fornisci un campo per una versione API.

Per riassumere, l'API dovrebbe ridurre al minimo la complessità quando si ha a che fare con il software. Per apprezzare l'API, il livello di complessità esposta dovrebbe essere adeguato. La decisione sulla forma dell'API dipende molto dalla stabilità del dominio del problema. Quindi, ci dovrebbe essere qualche stima su quale direzione il software e la sua API cresceranno, perché queste informazioni possono influenzare l'equazione per complessità. Inoltre, l'API desing è lì per le persone a capire. Se ci sono buone tradizioni nell'area della tecnologia del software in cui ti trovi, cerca di non deviare molto da loro, poiché ciò aiuterà a capire. Prendi in considerazione per chi scrivi. Gli utenti più esperti apprezzeranno la generalità e la flessibilità, mentre quelli con meno esperienza potrebbero essere più a loro agio con i concreti. Tuttavia, ci si prende cura della maggior parte degli utenti API lì, cioè quelli tra principianti ed esperti.

Per quanto riguarda la letteratura, potrei raccomandare "Beautiful Code", i principali programmatori spiegano come pensano Andy Oram, Greg Wilson, poiché penso che la bellezza riguardi la percezione dell'ottimalità nascosta (e dell'idoneità per qualche scopo).

    
risposta data 12.09.2013 - 05:53
fonte
1

La mia preferenza personale è di essere astratto, ma le politiche della mia azienda mi bloccano in modo concreto. Questa è la fine del dibattito per me:)

Hai fatto un buon lavoro elencando pro e contro per entrambi gli approcci, e se continui a scavare troverai molti argomenti a favore di entrambe le parti. Finché l'architettura della tua API è sviluppata correttamente, ovvero hai pensato a come verrà utilizzata oggi e come potrebbe evolversi e crescere in futuro, allora dovresti andare bene in ogni caso.

Ecco due segnalibri che ho avuto con punti di vista opposti:

Come favorire le classi astratte

Favorire le interfacce

Chiediti: "L'API soddisfa i miei requisiti di business? Ho criteri ben definiti per il successo? Può scalare?". Sembrano pratiche best practice davvero semplici da seguire, ma onestamente sono molto più importanti del concreto rispetto al generico.

    
risposta data 11.09.2013 - 23:17
fonte
1

Non direi che un'API astratta è necessariamente più difficile da convalidare. Se i parametri dei criteri sono abbastanza semplici e hanno poche dipendenze tra loro, non fa molta differenza se si passano i parametri separatamente o in un array. Hai ancora bisogno di convalidarli tutti. Ma ciò dipende dal design dei parametri dei criteri e degli oggetti stessi.

Se l'API è abbastanza complessa, avere metodi concreti non è un'opzione. Ad un certo punto probabilmente finirai con entrambi i metodi con molti parametri o troppi metodi semplici che non copriranno tutti i casi d'uso richiesti. Per quanto riguarda la mia esperienza personale nella progettazione di API che consumano, è meglio avere più metodi generici a livello di API e implementare specifici wrapper obbligatori a livello di applicazione.

    
risposta data 12.09.2013 - 08:36
fonte
1

L'argomento del cambiamento deve essere ignorato con YAGNI. Fondamentalmente, a meno che tu non abbia almeno 3 diversi casi d'uso che usano l'API generica in modo diverso, è molto probabile che tu la progetta in modo che non debba cambiare quando si presenta il prossimo caso d'uso (e quando ne hai l'uso) casi, ovviamente hai bisogno dell'interfaccia generica, periodo). Quindi non tentare di essere pronto per il cambiamento.

La modifica non deve essere sincronizzata per la distribuzione in entrambi i casi. Quando si generalizza l'interfaccia in un secondo momento, è sempre possibile fornire un'interfaccia più specifica per la compatibilità con le versioni precedenti. Ma in pratica qualsiasi implementazione avrà così tante modifiche che la sincronizzerete comunque, in modo da non dover testare gli stati intermedi. Non lo vedrei neanche come argomento.

Per quanto riguarda la documentazione, entrambe le soluzioni possono essere facili da usare e ovvie. Ma rappresenta una discussione importante. Implementa l'interfaccia in modo che sia facile da usare nei tuoi casi reali. A volte specifiche possono essere migliori e talvolta generiche.

    
risposta data 12.09.2013 - 09:26
fonte
1

Preferirei l'approccio dell'interfaccia astratta. Mettere una query a quei tipi di servizio (di ricerca) è un problema comune e probabilmente si verificherà nuovamente. Inoltre, è possibile trovare più candidati di servizio adatti a riutilizzare un'interfaccia più generale. Per essere in grado di fornire un'interfaccia comune coerente per tali servizi, non enumererei i parametri di query attualmente identificati nella definizione dell'interfaccia.

Come già sottolineato in precedenza, mi piace l'opportunità di modificare o estendere l'implementazione senza modificare l'interfaccia. L'aggiunta di un altro criterio di ricerca non deve riflettersi nella definizione del servizio.

Anche se non si tratta di progettare interfacce ben definite, concise ed espresse, sarà sempre necessario fornire ulteriore documentazione. L'aggiunta dell'ambito di definizione per criteri di ricerca validi non è un tale onere.

    
risposta data 12.09.2013 - 13:00
fonte
1

Il miglior riassunto che abbia mai visto è la scala di Rusty, ora chiamata Rusty's API Design manifesto . Posso solo raccomandare caldamente quello. Per completezza, cito il riassunto della scala dal primo link (il migliore in alto, il peggiore in basso):

Buone API

  • È impossibile sbagliare.
  • Il compilatore / linker non ti permetterà di sbagliare.
  • Il compilatore ti avviserà se ti sbagli.
  • L'uso ovvio è (probabilmente) quello corretto.
  • Il nome ti dice come usarlo.
  • Fallo bene o si interromperà sempre in fase di esecuzione.
  • Segui le convenzioni comuni e avrai ragione.
  • Leggi la documentazione e avrai capito bene.
  • Leggi l'implementazione e avrai capito bene.
  • Leggi il thread corretto della mailing list e avrai capito bene.

API non valide

  • Leggi il thread della mailing list e ti sbagli.
  • Leggi l'implementazione e ti sbagli.
  • Leggi la documentazione e ti sbagli.
  • Segui le convenzioni comuni e ti sbaglierai.
  • Fallo bene e a volte si romperà in fase di runtime.
  • Il nome ti dice come non usarlo.
  • L'uso ovvio è sbagliato.
  • Il compilatore avviserà se hai capito bene.
  • Il compilatore / linker non ti permetterà di farlo bene.
  • È impossibile avere ragione.

Entrambe le pagine dei dettagli qui e qui viene fornito con una discussione approfondita di ogni punto. È davvero una lettura obbligata per i progettisti dell'API. Grazie Rusty, se mai lo leggerai.

    
risposta data 04.10.2013 - 21:25
fonte
0

In parole semplici:

  • L'approccio astratto ha il vantaggio di consentire di costruire metodi concreti attorno ad esso.
  • Il contrario non è vero
risposta data 12.09.2013 - 14:04
fonte
0

Se estendi l'idea SearchCriteria un po ', può darti flessibilità come la creazione di AND , OR etc. criteri. Se hai bisogno di tale funzionalità, questo sarebbe l'approccio migliore.

Altrimenti, progettalo per usabilità. Rendi l'API facile per le persone che lo usano. Se hai alcune funzioni di base che sono necessarie spesso (come cercare una persona con il suo nome), forniscile direttamente. Se gli utenti avanzati hanno bisogno di ricerche avanzate, possono comunque utilizzare SearchCriteria .

    
risposta data 12.09.2013 - 14:30
fonte
0

Che cosa sta facendo il codice dietro l'API? Se è qualcosa di flessibile, allora un'API flessibile è buona. Se il codice dietro l'API è molto specifico, mettere una faccia flessibile su di esso significa solo che gli utenti dell'API saranno frustrati e infastiditi da tutte le cose che l'API finge sia possibile, ma che in realtà non possono essere realizzate.

Per esempio, per la tua persona sono richiesti tutti e tre i campi? Se è così allora la lista dei criteri è cattiva perché consente una moltitudine di usi che semplicemente non funzionano. In caso contrario, richiedere all'utente di specificare input non richiesti è errato. Quanto è probabile che la ricerca per indirizzo venga aggiunta in V2? L'interfaccia flessibile facilita l'aggiunta di quella flessibile.

Non tutti i sistemi devono essere estremamente flessibili, cercando di fare di tutto ciò che è Architettura Astronauting. Un arco flessibile spara frecce. Una spada flessibile è utile come un pollo di gomma.

    
risposta data 04.10.2013 - 23:02
fonte

Leggi altre domande sui tag