Si consiglia di lasciare che i client di interfaccia modellano l'interfaccia?

3

Diciamo che ho un'interfaccia:

 public interface IAccountStoreManager
{
    bool IsUserMemberOfAny(string username, string[] groups, out string[] containingGroups);
}

La firma del metodo di IsUserMemberOfAny era influenzata dalla mia osservazione che la classe client avrebbe controllato l'appartenenza di un utente a più gruppi. Ad esempio, potrebbe essere che per verificare se un account utente è quello di un supervisore, sarebbero membri di uno dei gruppi Admins1 o Admins2.

Se dovessi pensare a questo metodo senza considerare che ci sarebbe più di un gruppo per controllare l'appartenenza, potrei aver progettato un metodo come questo:

bool IsUserMemberOf(string username, string group);

e si è conclusa con un ciclo contenente una chiamata all'implementazione del metodo. Questo ciclo potrebbe essere costoso se l'implementazione dovesse interagire con un Account Store come Active Directory, ad esempio, dove avremmo qualcosa di simile:

using (PrincipalContext adPrincipalContext = new PrincipalContext(ContextType.Domain, ldapSettingsConfig.DomainController, ldapSettingsConfig.Username, ldapSettingsConfig.Password))
        {
            using (PrincipalSearcher ps = new PrincipalSearcher())
            {
               //code here
            }
        }

Quindi la mia domanda è: cosa si consiglia per quanto riguarda l'effetto dell'implementazione e le classi dei clienti sulla progettazione di un'interfaccia? È consigliabile lasciare che l'implementazione modellino l'astrazione (interfaccia) in questo modo?

    
posta 3m3sd1 22.12.2016 - 14:27
fonte

5 risposte

6

Assolutamente. Un'interfaccia è progettata per essere utilizzata, quindi i modelli di utilizzo previsti dovrebbero sicuramente modellare l'interfaccia. Questo è il motivo per cui il design dell'API viene talvolta descritto come qualcosa di artistico, e i fattori umani e il pubblico previsto dovrebbero essere presi in considerazione.

Le interfacce non dovrebbero esporre dettagli di implementazione, ma i vincoli dettati dall'implementazione sottostante dovrebbero essere espressi nell'API in modo tale da scoraggiare gli usi problematici. Altrimenti si crea un'astrazione che perde.

    
risposta data 22.12.2016 - 14:53
fonte
3

Le astrazioni spezzate vengono create tutte le volte in cui vengono create senza pensare all'implementazione. Basta guardare i moduli Web ASP.NET. Microsoft ha avuto una grande idea per nascondere molti dei brutti dettagli di sviluppo web, ma chiunque volesse creare siti decenti ha capito subito che dovevi capire a fondo HTTP, cache, gestione dello stato, javascript, ecc. E hai finito per combattere contro web forma l'astrazione, piuttosto che utilizzarla come progettata.

Lavoravo con un architetto che avrebbe sempre detto "questo è un dettaglio di implementazione" ogni volta che metteremo in discussione la progettazione di qualcosa e forniamo un esempio di come potrebbe non funzionare. A lui non importava. Il suo design era la cosa più importante e non come avrebbe dovuto essere usato. Questo è un errore assoluto da pensare in questo modo e può avere conseguenze negative a lungo termine.

Ho imparato nel corso degli anni a pensare in termini concreti prima, e poi a ritroso in una serie di interfacce che riassumono i dettagli. Pensa all'implementazione degli oggetti in primo piano e non dopo che la magica scatola nera è stata creata. E non lasciarti coinvolgere nell'affrontare ogni eventualità e creare componenti ingombranti che sono stati progettati per fare molto più di quello che erano originariamente intesi a fare. Mantieni la semplicità e pensa sempre a come verrà utilizzato un oggetto.

    
risposta data 22.12.2016 - 16:33
fonte
2

Sono d'accordo con le risposte di JacquesB e Telastyn, anche se ho pensato di aggiungere alla discussione:

La considerazione principale per fornire un'interfaccia dovrebbe essere l'uso previsto. Il nostro compito è fornire ai nostri clienti (anche se siamo solo noi) un'astrazione utilizzabile e completa.

Se l'astrazione non è completa, scopriamo che i nostri clienti devono fare la differenza; spesso significa fare il giro dell'astrazione fornita a un livello inferiore, fare cose che dipendono dall'implementazione specifica e creare un accoppiamento più stretto di quello che vorremmo vedere.

Sebbene non sia necessariamente la chiave in questa situazione, il ciclo di esempio che stai mostrando non offre intrinsecamente atomicità. Con i sistemi asincroni che abbiamo oggi, è un dato che le informazioni, una volta interrogate e trasmesse, possono essere stantie, ma è molto meglio se le informazioni fornite sono almeno una singola istantanea autoconsistente nel tempo piuttosto che una serie di risposte potenzialmente da diversi punti nel tempo.

Non posso dire di essere un fan dell'uso di stringhe per rappresentare utenti e gruppi. Idealmente questi concetti sarebbero entità di prima classe, ad es. in Java ogni classe per sicurezza dei tipi.

Anche se non possiamo davvero capire da questo piccolo frammento, probabilmente mi aspetterei un'enumerazione più orientata al ruolo piuttosto che gruppi e gruppi contenenti. Sembra che i client debbano continuare a lavorare per determinare se l'utente ha privilegi speciali.

    
risposta data 22.12.2016 - 16:34
fonte
0

Is it recommended to let the implementation shape the abstraction (interface) in such a way?

No, l'implementazione non dovrebbe influenzare l'interfaccia, che è per definizione un'astrazione che perde. D'altra parte, le interfacce dovrebbero essere facili da usare: dovrebbero fornire ciò che i consumatori desiderano.

Ma questo è il lato ideale delle cose. Dal punto di vista pragmatico, di tanto in tanto si imbattono in questo genere di cose in cui fornire l'astrazione inconsistente o fare ciò che i consumatori vogliono intuitivamente significa che sei costretto a implementare le cose in un modo che rende il codice inutilizzabile a causa delle prestazioni / scalabilità / robustezza / sicurezza / motivi etc.

Questo è uno di quei casi comuni in cui inizi con le linee guida, finché la realtà non ti costringe a scendere a compromessi.

    
risposta data 22.12.2016 - 14:55
fonte
0

Is it recommended to let interface clients shape the interface?

Secondo i principi dell'inversione della segregazione e dell'inversione delle dipendenze (I e D in SOLID) il client (modulo di alto livello) dovrebbe definire le interfacce delle sue dipendenze (moduli di basso livello).

Questo significa che devi prima creare il client insieme alle interfacce più adatte alle sue esigenze. Quindi queste interfacce dovrebbero essere implementate come librerie esterne.

Ovviamente dovresti essere pragmatico e se l'interfaccia "ideale" è troppo complessa per l'implementazione dovrebbe essere cambiata. Ma dovresti sapere chiaramente che questo è contrario alle buone pratiche e viene fatto per una ragione.

    
risposta data 22.12.2016 - 16:42
fonte

Leggi altre domande sui tag