Qual è il valore nel nascondere i dettagli attraverso le astrazioni? Non c'è valore nella trasparenza?


30

sfondo

Non sono un grande fan dell'astrazione. Devo ammettere che si può trarre vantaggio dall'adattabilità, portabilità e riutilizzabilità delle interfacce ecc. C'è un vero vantaggio lì, e non voglio metterlo in discussione, quindi ignoriamolo.

C'è l'altro grande "vantaggio" dell'astrazione, che è nascondere la logica di implementazione e i dettagli agli utenti di questa astrazione. L'argomento è che non è necessario conoscere i dettagli e che a questo punto ci si dovrebbe concentrare sulla propria logica. Ha senso in teoria.

Tuttavia, ogni volta che gestisco grandi applicazioni aziendali, devo sempre conoscere maggiori dettagli. Diventa una seccatura enorme scavare sempre più a fondo nell'astrazione ad ogni giro solo per scoprire esattamente cosa fa qualcosa; vale a dire dover fare una "dichiarazione aperta" circa 12 volte prima di trovare la procedura memorizzata utilizzata.

Questa mentalità "nascondi i dettagli" sembra intromettersi. Desidero sempre interfacce più trasparenti e meno astrazioni. Riesco a leggere il codice sorgente di alto livello e sapere cosa fa, ma non saprò mai come lo fa, quando lo fa, è ciò che ho davvero bisogno di sapere.

Cosa sta succedendo qui? Ogni sistema su cui ho mai lavorato è stato progettato male (almeno da questa prospettiva)?

La mia filosofia

Quando sviluppo software, mi sento come se stessi cercando di seguire una filosofia che ritengo strettamente correlata alla filosofia ArchLinux :

Arch Linux mantiene le complessità intrinseche di un sistema GNU / Linux, mantenendole ben organizzate e trasparenti. Gli sviluppatori e gli utenti di Arch Linux credono che il tentativo di nascondere le complessità di un sistema si traduca in realtà in un sistema ancora più complesso, e quindi deve essere evitato.

E quindi, non cerco mai di nascondere la complessità del mio software dietro i livelli di astrazione. Cerco di abusare dell'astrazione, non di diventare schiavo di esso.

Domanda a cuore

  1. C'è un vero valore nel nascondere i dettagli?
  2. Non stiamo sacrificando la trasparenza?
  3. Questa trasparenza non è preziosa?

7
L'astrazione può essere abusata sotto forma di cattiva progettazione. Ma ciò non significa che l'astrazione in linea di principio non sia preziosa.
Bernard,

4
Penso che ci sia una buona domanda lì dentro, tuttavia, sembra molto simile a una collera contro l'astrazione. Potresti essere de-enfatizzarlo e far emergere di più la tua vera domanda.
PersonalNexus,

4
Sei sicuro di utilizzare la giusta definizione di "nascondere i dettagli"? In questo contesto, si tratta di ridurre l' accoppiamento , non di impedirti di imparare il funzionamento interno di qualcosa.
Andres F.

24
A meno che non ti piaccia programmare con un voltmetro e un oscilloscopio sulla tua scrivania, stai programmando contro nient'altro che astrazioni sopra astrazioni sopra astrazioni. C'è valore per te nel nascondere il dettaglio che in realtà stai manipolando non bit ma in realtà tensioni? Fare così sacrifica la trasparenza? Questa trasparenza è preziosa?
Eric Lippert,

8
Penso che ciò con cui hai problemi non sia l'astrazione, sono strati vuoti di indiretta che non astraggono davvero nulla. Sì, quelli si trovano spesso nei grandi sistemi aziendali e no, non sono buoni.
Michael Borgwardt,

Risposte:


47

Il motivo per nascondere i dettagli non è quello di mantenere i dettagli nascosti; è per rendere possibile modificare l'implementazione senza rompere il codice dipendente.

Immagina di avere un elenco di oggetti e ogni oggetto ha una Nameproprietà e altri dati. E molte volte, è necessario trovare un elemento nell'elenco che Namecorrisponda a una determinata stringa.

Il modo più ovvio è di scorrere ogni elemento uno per uno e verificare se Namecorrisponde alla stringa. Ma se scopri che ci vuole troppo tempo (come farebbe se avessi diverse migliaia di elementi nell'elenco), potresti volerlo sostituire con una ricerca nel dizionario degli oggetti stringa.

Ora, se tutte le tue ricerche sono state eseguite recuperando l'elenco e passandoci sopra, avrai un sacco di lavoro da fare per risolvere questo problema. È ancora più difficile se ti trovi in ​​una libreria e gli utenti di terze parti lo usano; non puoi uscire e correggere il loro codice!

Ma se avessi un FindByNamemetodo per incapsulare il processo di ricerca del nome, puoi semplicemente cambiare il modo in cui è implementato e tutto il codice che lo chiama continuerà a funzionare e ottenere molto più velocemente gratuitamente. Questo è il vero valore dell'astrazione e dell'incapsulamento.


Sono d'accordo con questo, ma non era questo il punto della domanda. Sono completamente d'accordo sul fatto che un metodo per incapsulare funzionalità specifiche sia utile, ma penso che questo non sia sempre il motivo. Ho sbagliato?
user606723,

3
@ User606723: Dovrebbe essere. Ciò non significa che sempre è . Alcune persone non capiscono il punto e accatastano più livelli su più livelli e trasformano le cose in un disastro. Questo è il motivo per cui programmatori esperti consigliano ai nuovi sviluppatori di non adottare mai una nuova tecnologia o tecnica fino a quando non la comprendono.
Mason Wheeler,

3
@ user606723: La trasparenza incoraggia l'accoppiamento stretto, quindi forse non è sempre male, ma di solito lo è.
Malfist,

3
Il problema che Mason descrive, delle persone che si accumulano su livelli in una forma di programmazione cargo-cult, è perché divento sospettoso di troppa eredità e perché la composizione dovrebbe essere favorita rispetto all'eredità. Sembra essere particolarmente un problema per i programmatori Java.
scherzare il

2
No, l'accoppiamento stretto non è sempre negativo. Spesso fa male, ma fare di tutto per evitarlo può produrre problemi anche peggiori, come la codifica software.
Mason Wheeler,

16

Ho appena finito di leggere la sezione Codice completo sull'astrazione, quindi è qui che la maggior parte di queste fonti.

Il punto di astrazione è rimuovere la necessità di chiedere "come viene implementato?". Quando chiami user.get_id(), sai che idè ciò che stai per ottenere. Se devi chiedere "come si ottiene l'ID utente?" allora probabilmente non hai bisogno di un ido get_id()restituisci qualcosa che è inaspettato ed è mal progettato.

Usi l'astrazione per permetterti di progettare:

a house with doors and windows

non design

a box with four walls,
    with 3 holes,
        two of which fit panes of glass surrounded by wood frames,
        one that fits a large plank of wood with hinges and a metal knob,
etc.

Non sto parlando di queste interfacce. Queste interfacce vanno bene. Sto parlando di enormi sistemi complessi che sono segmentati dietro molte diverse astrazioni.
user606723,

9
@ user606723 Quindi la tua domanda riguarda il design troppo complesso, piuttosto che le astrazioni
Andres F.

3
+1 per il codice completato. Descrive sia il motivo per cui l'astrazione è necessaria per la progettazione, sia perché un livello errato di astrazione ostacola la progettazione. Per portare ulteriormente il tuo esempio, se lavoro nell'ufficio di suddivisione in zone, voglio pensare alle tue case, senza confondere i dettagli. Ma se pensassi alle case come faccio io, non potresti costruirne una.
Spencer Rathbun,

questa domanda dovrebbe essere chiusa o il titolo modificato
Jake Berger,

8

C'è un vero valore nel nascondere i dettagli?

Sì. Presentando le astrazioni possiamo pensare e programmare ad un livello superiore.

Immagina di modellare sistemi fisici senza calcolo o algebra di matrice. È completamente poco pratico. Allo stesso modo, se possiamo programmare solo a livello scalare, non saremo in grado di risolvere problemi interessanti. Anche le applicazioni web relativamente semplici possono trarre grandi vantaggi da astrazioni come tag libs. È molto più facile inserire un tag che significa "campi di immissione dell'indirizzo" piuttosto che creare ripetutamente quattro campi di testo e una casella di selezione. E se decidi di espandere oltremare, puoi semplicemente modificare la definizione del tag, piuttosto che correggere ogni modulo per gestire gli indirizzi internazionali. L'uso efficace dell'astrazione è ciò che rende alcuni programmatori dieci volte più efficaci di altri.

Gli umani hanno una memoria di lavoro limitata. L'astrazione ci consente di ragionare su sistemi di grandi dimensioni.

Aren't we sacrificing transparency?

No. Se le astrazioni non vengono utilizzate, lo scopo di un componente software viene nascosto in dettagli ripetuti. Gli sviluppatori trascorrono le loro giornate guadando codice in questo modo:

for (i = 0; i < pilgrim.wives.size(); ++i) {
  wife = pilgrim.wives[i];
  for (j = 0; j < wife.sacks.size(); ++j) {
     sack = wife.sacks[i];
     for (k = 0; j < sack.cats.size(); ++j) {
        cat = sack.cats[k];
        for (m = 0; m < cat.kits.size(); ++m) {
           ++count;
        }
     }
  }
}

e pensando "oh sì, un altro loop a quattro livelli sui kit", invece di vedere

pilgrim.kits.each { ++count; }

Questa trasparenza non è preziosa?

Come hai sottolineato, c'è un costo per l'indirizzamento indiretto. Non ha senso creare livelli "per ogni evenienza". Usa l'astrazione per ridurre la duplicazione e chiarire il codice.


7

Quando le persone affermano che le astrazioni nascondono i dettagli dell'implementazione, in realtà non significano "nascondere" nel senso che rendono difficile la ricerca. Ciò che significano sono i dettagli dell'implementazione separati dall'interfaccia pubblica, per mantenere l'interfaccia semplice, concisa e gestibile. Proprio come un'auto "nasconde" la maggior parte delle sue parti vitali e offre solo un set abbastanza rudimentale di controlli per gestirle, un modulo software "nasconde" la maggior parte delle sue funzionalità nelle viscere e espone solo un numero limitato di metodi di accesso a guidarla. Immagina un'auto in cui dovevi azionare manualmente tutti gli interni del motore (e ce ne sono molti di loro), faresti fatica a tenere d'occhio il traffico e trovare la strada.

Ma mantenere l'interfaccia semplice non è solo una cosa estetica; può fare la differenza tra un progetto di successo e una Marcia della morte. Giochiamo all'avvocato del diavolo per un minuto; immaginare un progetto software senza alcuna astrazione. Se è necessario mantenere un valore, si utilizza una variabile globale. Se è necessario utilizzare la funzionalità più di una volta, è necessario copiarla e incollarla. Se sono necessarie due versioni diverse di una determinata sezione di codice, si copia e incolla, si avvolge in ifun'istruzione e si modificano entrambi i rami. Tecnicamente parlando, funziona, ma pochi mesi dopo, combatterai alcuni problemi davvero brutti:

  • Quando trovi e risolvi un bug, è probabile che esista anche in altre istanze di codice simile copiate e incollate, quindi oltre a trovare e correggere il bug, devi anche cercare altri eventi e risolverli.
  • Per trovare un bug o implementare una modifica, un programmatore di manutenzione deve essere in grado di comprendere il codice pertinente. La difficoltà nel farlo aumenta con le dimensioni della sezione di codice pertinente, ma ancora di più con il suo ambito. Mantenere una mezza dozzina di variabili nella tua testa mentre si passa mentalmente attraverso un po 'di codice è fattibile; ma se ne hai alcune centinaia, la tua produttività è gravemente compromessa (mi piace confrontare il processo di pensiero con un programma che esaurisce la RAM fisica e deve immergersi nel file di scambio: invece di leggere il codice fluentemente in una volta sola , il programmatore deve saltare avanti e indietro per cercare le cose).
  • L'ambito di un pezzo di codice influisce anche sulla dimensione della base di codice che si deve scavare per trovare il bug. Se si dispone di una funzione a dieci righe con due parametri e nessun globale, e si conoscono i valori dell'input e la riga in cui si arresta in modo anomalo, la ricerca del bug è in genere banale e spesso non richiede altro che guardare il codice. Se sono poche centinaia di linee, venti parametri, quindici globi e chiama alcune altre funzioni di natura simile, ti senti un po 'grave.
  • Senza una corretta astrazione, qualsiasi modifica può potenzialmente influire su ampie parti della base di codice, poiché praticamente tutto può dipendere dal codice da modificare. Un sintomo tipico di tali basi di codice è che si apporta una piccola modifica apparentemente innocente e una funzionalità completamente non correlata si interrompe improvvisamente. Con l'astrazione, è possibile limitare la quantità di danno che può apportare una modifica e rendere l'impatto più prevedibile. Se cambi il nome di un campo privato, hai solo un file sorgente da controllare; se si modifica il nome di una variabile globale, è necessario eseguire l'intera base di codice.

In una base di codice mal astratta, l'impatto generalmente aumenta in modo esponenziale con la dimensione della base di codice, vale a dire l'aggiunta di una quantità costante di codice aumenta lo sforzo di manutenzione di un fattore costante. A peggiorare le cose, l'aggiunta di più programmatori a un progetto non aumenta la produttività in modo lineare, ma nella migliore delle ipotesi logaritmicamente (poiché più è grande il team, maggiore è il sovraccarico per la comunicazione).


2

Penso che dovresti capire come funziona se necessario. Una volta che hai deciso che fa quello che pensavi potesse fare, allora hai la pace della mente. Non avrei mai pensato che l'obiettivo fosse nasconderlo per sempre.

Dopo aver impostato una sveglia su un orologio che ritieni possa funzionare, puoi dormire un po 'sapendo che si spegnerà al momento della correzione. Svegliarsi un'ora prima solo per guardare i secondi scorrere è uno spreco.


1
Certo, ma non mi viene spesso chiesto di cambiare il modo in cui funziona la mia sveglia o di far cambiare ad altre persone il modo in cui funziona la mia sveglia senza essere pienamente informato delle modifiche.
user606723,

1
Vedi le modifiche al codice per ogni framework che hai mai usato?
JeffO,

1
no, ma non sono state mantenute modifiche al codice per ogni framework che abbia mai usato.
user606723

3
Hai praticamente dimostrato il punto di JeffO: non sei nemmeno interessato al mantenimento delle sveglie. Se ne compri uno e inizi a usarlo senza fare una demolizione completa e un'analisi di come funziona, hai accettato che gli interni ti saranno astratti. Nulla dice che non puoi smontarlo per scoprire come funziona, ma quanto spesso lo ritieni necessario?
Blrfl,

2

Per rispondere alle tue domande in particolare:

C'è un vero valore nel nascondere i dettagli?

Sì. Come riconosci nella prima riga della tua domanda.

Non stiamo sacrificando la trasparenza?

Non proprio. Un'astrazione ben scritta faciliterà la comprensione dei dettagli, se necessario.

Questa trasparenza non è preziosa?

Sì. Le astrazioni dovrebbero essere progettate e implementate per facilitare la comprensione dei dettagli quando necessario / desiderato.


Finalmente una risposta che mi piace.
user606723

1

Direi che nascondere i dettagli è fantastico quando le cose nascoste funzionano.

Ad esempio, supponiamo di sviluppare un'interfaccia che definisce i comportamenti (ad esempio GetListItems, SendListItem), che sono due funzioni che vengono avviate dall'utente tramite un clic sul pulsante o qualcosa del genere. ORA, ogni utente può avere il proprio "ListItemStore" .. uno su Facebook, uno su myspace .. (ad esempio) .. e dire che è salvato come proprietà dell'utente / impostazione da qualche parte nell'app tramite le prefrenze dell'utente .. e dire che è possibile per gli sviluppatori di App aggiungere ulteriori ListItemStore nel corso di tempo (mybook, facepace, ecc.)

ora ci sono molti dettagli nel collegarsi a Facebook e ottenere loro gli elementi .. e ci sono altrettanti dettagli quando ci si connette a myspace .. e così via ...

ora, dopo che è stato scritto il codice iniziale di "accesso al negozio", potrebbe non essere necessario modificarlo (bene nel caso di Facebook probabilmente abbiamo bisogno di uno sviluppatore a tempo pieno per tenere il passo con le modifiche, zing ..),

quindi quando usi il codice è qualcosa del tipo:

    new ItemManager(user) //passes in user, allowing class to get all user properties
    ItemManager.GetListItems()

e ora hai i dati dell'utente da qualunque luogo li abbiano archiviati, e poiché tutto ciò di cui sono preoccupato è ottenere l'elenco degli articoli e fare qualcosa con esso, e poiché ci sono volute solo 2 righe che funzioneranno, non importa come molti altri negozi vengono aggiunti posso tornare a rispondere / pubblicare domande sullo stack ... lol ..

Quindi, tutto l'impianto idraulico per realizzarlo è "nascosto" e chi se ne frega davvero di come lo fa fintanto che ottengo l'elenco corretto degli elementi .. se si dispone di unit test, allora si può anche riposare più facilmente perché i risultati dovrebbero ' sono già stati quantificati ..


Sì, ma la parte che deve essere mantenuta non sono mai quelle due righe. Quelli sono impossibili da rovinare. È sempre il 2 °, 3 °, 4 ° livello in basso che devi cambiare. Concordo sul fatto che questo è fantastico quando si dispone di un'API di cui ci si può fidare per essere stabili , ma cosa succede se non può essere stabile solo dalla complessità della propria attività?
user606723,

1
@ user606723 se l'API non è stabile, allora è probabilmente immatura, o più probabilmente l'astrazione sbagliata
sdg

@ user606723 - È vero, e in quei casi le stesse convenzioni di denominazione dovrebbero definire una qualche forma di trasparenza che nasconde la logica / i dettagli di programmazione effettivi .. e se dovessi mai modificare la fonte attuale, ulteriori dettagli e idee dovrebbero essere espressi attraverso la denominazione informativa quindi, in sostanza, la trasparenza può essere raggiunta con una corretta denominazione fino in fondo, tuttavia, non dovremmo davvero dover scendere fino in fondo molto spesso.
hanzolo,

@sdg o perché i requisiti del sistema cambiano sempre. Perché le leggi cambiano, perché le altre API cambiano, è fuori dal nostro controllo.
user606723,

1
@ user606723 - In realtà lavoro su un sistema SaaS finanziario e vedo le insidie ​​di non avere abbastanza astrazione ad ogni ciclo di rilascio. in parte è il risultato di un design scadente, ma di solito è il risultato di spingere il codice dove non era originariamente previsto. Andare giù per la catena può essere doloroso senza quei commenti, nomi e incapsulamenti . se tutto ciò che dovevo fare era Remeasurements.GetRemeasureType (grant), e quindi reMeasure.PerformCalc (), sarebbe molto più bello che aggiungere sovraccarichi e leggere i diversi rami logici per arrivare al calcolo corretto o aggiungerne uno nuovo
hanzolo,

1

Ciò che si chiama "Nascondersi", molti vedono come una separazione di preoccupazioni (ad es. Implementazione vs. Interfaccia).

Secondo me, uno dei maggiori vantaggi dell'astrazione è quello di ridurre il disordine dei dettagli non necessari dal limitato spazio cerebrale dello sviluppatore.

Se il codice di implementazione fosse offuscato, potrei vederlo come ostacolo alla trasparenza, ma l'astrazione a mio avviso, è solo una buona organizzazione.


1

Prima di tutto, qualsiasi cosa al di là di una singola istruzione di codice macchina è essenzialmente l'astrazione: un while...dociclo è un modo simbolico coerente di rappresentare i confronti e le chiamate di indirizzo necessarie per ripetere un set di istruzioni fino a quando non viene soddisfatta una condizione. Allo stesso modo il tipo int è un'astrazione per il numero X di bit (a seconda del sistema). La programmazione si basa sull'astrazione.

Probabilmente saresti d'accordo sul fatto che quelle astrazioni primitive sono estremamente utili. Bene, così è essere in grado di costruire il tuo. OOAD e OOP sono tutto.

Supponiamo di avere un requisito in cui gli utenti vogliono essere in grado di esportare i dati da una schermata in una varietà di formati: testo delimitato, Excel e pdf. Non è utile creare un'interfaccia chiamata "Esportatore" con un metodo di esportazione (dati), in base al quale è possibile creare un DelimitedTextExporter, un ExcelExporter e un PDFExporter, ognuno dei quali sa come creare il proprio output particolare? Tutto ciò che il programma chiamante deve sapere è che può chiamare il metodo di esportazione (dati) e qualunque implementazione venga utilizzata farà il suo dovere. Inoltre, se cambiano le regole del testo delimitato, è possibile modificare DelimitedTextExporter senza dover fare confusione con ExcelExporter, eventualmente interrompendolo.

Praticamente tutti i ben noti schemi di progettazione utilizzati nella programmazione OO dipendono dall'astrazione. Consiglio di leggere i primi modelli di design di Freeman e Head First per avere un'idea migliore del perché l'astrazione sia una buona cosa


1
anche il codice della macchina è un'astrazione, ci sono processi reali, fisici, che si svolgono sotto la logica, persino l'elettronica digitale è un'astrazione su ciò che accade realmente come chiunque può fare un hash di overclock di un chip a cui può testimoniare
jk.

Troppo vero, anche se sembra più concreto a livello di istruzioni della macchina.
Matthew Flynn,

1

Penso di aver capito cosa provi per questo, e penso di avere un'opinione simile.

Ho lavorato con sviluppatori Java che trasformano 50 classi di codice in 3 classi e 3 interfacce perché è facile da capire. E non potevo sopportarlo.

La cosa era tremendamente difficile da capire, quasi impossibile da eseguire il debug e mai e poi mai necessario "cambiare l'implementazione".

D'altra parte, ho anche visto il codice in cui più oggetti condividono comportamenti simili e vengono utilizzati in un unico posto e potrebbero davvero utilizzare cicli di ordinamento / elaborazione comuni se i metodi sarebbero stati esposti attraverso un'interfaccia comune.

Quindi, IMHO, gli oggetti principali che possono essere usati in scenari simili di solito beneficiano di comportamenti comuni che dovrebbero essere accessibili attraverso l'interfaccia. Ma è praticamente tutto, astrarre cose semplici perché è giusto, o rende possibile cambiare implementazione è solo un modo per rendere il codice disordinato.

Ancora una volta, preferisco lezioni più intelligenti più lunghe rispetto a quantità esplosive di piccole classi con tutti i problemi di gestione della vita, relazioni difficili da vedere e grafici di chiamate spaghetti. Quindi alcune persone non saranno d'accordo con me.


1

Lo scopo guida di nascondersi e astrazione dovrebbe essere quello di disaccoppiare l'utente dall'implementazione in modo che possano essere modificati in modo indipendente Se il consumatore è accoppiato con i dettagli dell'implementazione, a causa di armeggiare con i suoi interni entrambi sono fusi nella pietra e diventa più difficile introdurre nuove funzionalità o algoritmi migliori in futuro.

Quando si scrive un modulo, le parti nascoste dell'implementazione ti danno l'idea di poterle modificare senza rischiare di rompere altri codici a cui non riesci a pensare.

Un altro vantaggio nel fornire interfacce opache è che riducono significativamente la superficie tra i sottosistemi. Riducendo la quantità di modi in cui possono interagire, possono diventare più prevedibili, più facili da testare e avere meno bug. Le interazioni tra i moduli aumentano anche in modo quadratico con il numero di moduli, quindi c'è un valore nel cercare di controllare questa crescita della complessità.


Detto questo, è ovviamente possibile nascondere troppo e nidificare le interfacce troppo in profondità. È compito del programmatore, in quanto essere umano intelligente, progettare il sistema in modo che sia estremamente utile minimizzando la complessità e massimizzando la manutenibilità.


0

In così tanti casi semplicemente non hai bisogno di sapere come vengono implementate le cose. Posso quasi garantire che scriverai codice così people.Where(p => p.Surname == "Smith")così tante volte al giorno eppure quasi mai penserai "come funziona Where()effettivamente questo metodo?" Semplicemente non ti interessa - sai che questo metodo è lì e che ti dà i risultati che desideri. Perché ti interesserebbe come funziona?

Questo è esattamente lo stesso per qualsiasi software interno; solo perché non è scritto da Oracle, Microsoft, ecc. non significa che dovresti andare a caccia di come è implementato. Puoi ragionevolmente aspettarti che un metodo chiamato GetAllPeopleWithSurname(string name)ti restituisca un elenco di persone che hanno quel cognome. Potrebbe scorrere su un elenco, potrebbe usare un dizionario, potrebbe fare qualcosa di completamente folle ma a te non dovrebbe interessare .

Esiste ovviamente un'eccezione a questa regola (non sarebbe una regola senza una!) E questo è se c'è un bug nel metodo. Così, nell'esempio di cui sopra, se si dispone di una lista con 3 persone in essa e si sa che uno di loro ha il cognome Smith e non vengono restituiti nella lista , allora vi preoccupate per l'attuazione di tale metodo, perché è chiaramente rotto .

L'astrazione, se eseguita correttamente, è meravigliosa perché ti permette di filtrare tutto ciò che non è utile quando devi leggerlo in un secondo momento. Non dimenticare che si trascorre molto più tempo a leggere il codice di quanto si impieghi a scriverlo, quindi l'accento deve essere posto sul rendere questo compito il più semplice possibile. Potresti anche pensare che l'astrazione significhi una gerarchia di oggetti lungo quanto il tuo braccio, ma può essere semplice come refactoring di un metodo a 100 linee in 10 metodi, ciascuno lungo 10 linee. Quindi, ciò che una volta erano 10 passaggi tutti raggruppati ora sono 10 passaggi separati che ti consentono di andare direttamente nel luogo in cui si nasconde questo fastidioso bug.


Eh, ma diciamo che sei tu quello che mantiene l'implementazione. Voglio dire, qualcuno si preoccupa dell'implementazione e quella persona sei tu. Ti capita anche di essere l'utente dell'implementazione ... I requisiti aziendali cambiano (in modi che non puoi prevedere) causando cambiamenti che sono a molti livelli. Immagino che il mio punto sia che un bug non è l'unica eccezione a quella regola.
user606723,

Il problema èPeopleFactory.People.Strategy.MakePeople.(CoutryLaw.NameRegistry.NameMaker.Make()) as People.Female
Coder,

@ user606723 Non devi preoccuparti di ogni singola riga di codice nella tua base di codice per tutto il tempo. Se c'è un bug in quell'implementazione o è stato segnalato come un bisogno di essere riscritto (perché è lento, mal scritto o altro) e lo stai riscrivendo, allora te ne importa. Altrimenti, dovrebbe essere tenuto fuori dai piedi. Forse il tuo problema è che stai cercando di possedere tutto il codice per tutto il tempo. Secondo me, dovresti semplicemente concentrarti sul codice su cui stai lavorando in un determinato momento.
Stuart Leyland-Cole,

@Coder Ovviamente questa è una forma piuttosto estrema di astrazione! All'inizio ho pensato che fosse il genere di cosa contro cui l'OP era contrario, ma leggendo il resto delle loro risposte, sembra che vedano tutte le astrazioni come cattive, cattive, cattive. Questo è il motivo per cui ho cercato di spiegare i diversi livelli di astrazione nella mia risposta.
Stuart Leyland-Cole,

0

Le astrazioni comportano il nascondimento delle informazioni. Ciò dovrebbe finire con un accoppiamento inferiore. Ciò dovrebbe comportare minori rischi nel cambiamento. Ciò dovrebbe portare a programmatori felici, non innervosirsi quando si tocca il codice.

Queste idee sono espresse attraverso tre leggi essenziali nell'architettura del software:

Legge di Simone: "Le gerarchie riducono la complessità". (Le gerarchie introducono l'astrazione)

Legge di Parna: "Solo ciò che è nascosto può essere modificato senza rischi".

Legge di Costantinopoli: programmi robusti richiedono basso accoppiamento e elevata coesione


"Le gerarchie riducono la complessità". - non necessariamente vero.
Coder

Nessuna metodologia di progettazione è deterministica. Questa legge non proviene dall'IT / CS, è formulata in un senso molto più ampio ed è anche riferita da matematica, fisici ecc. È un principio valido, ma nessuno può impedirti di creare Gerarchie senza senso.
ins0m,

0

Anch'io sono nel settore delle applicazioni enterprise e questa domanda ha attirato la mia attenzione perché ho la stessa domanda da solo. Ho avuto qualche intuizione sulla questione dell'astrazione nel corso della mia carriera finora, ma la mia intuizione non è affatto la risposta universale. Sto continuando a imparare / ascoltare nuove idee e pensieri, quindi ciò che credo ora potrebbe cambiare.

Quando stavo mantenendo un'applicazione sanitaria ampia e complessa, mi piacevi e basta, odiavo tutte le astrazioni lì. Capire dove va tutto il codice era dolore al collo. Saltare in diverse classi mi faceva venire le vertigini. Quindi mi sono detto "l'astrazione fa schifo, minimizzerò l'astrazione quando progetto cose".

Quindi, è arrivato il momento in cui ho dovuto progettare un'applicazione (un componente di servizio Web relativamente piccolo) da zero. Ricordando tutto il dolore, avevo un design piuttosto piatto del componente. Il problema è stato che, quando i requisiti sono cambiati, ho dovuto apportare modifiche in molti luoghi diversi (i requisiti erano piuttosto fluidi e non potevo farci nulla). È stato così male, praticamente ho buttato via il mio progetto iniziale e la riprogettazione con l'astrazione e le cose sono migliorate - non ho dovuto apportare modifiche in molti luoghi quando i requisiti sono cambiati più.

Ho consegnato la domanda, mi sono seduto per alcune settimane, poi mi è stato detto di iniziare a mantenere la domanda. Ero stato un po ', non ricordavo tutto, quindi ho faticato un po' a capire il mio codice e l'astrazione non mi ha aiutato.

Successivamente sono stato coinvolto in molti altri progetti diversi e ho avuto la possibilità di giocare un po 'di più con i livelli di astrazione. Quello che trovo davvero è, e questa è solo la mia opinione personale, l'astrazione aiuta molto nello sviluppo ma ha un impatto negativo quando non hai scritto il codice e stai cercando di capire tutto al livello più profondo di un'applicazione; passerai più tempo saltando in diverse classi e provando a stabilire le connessioni.

La mia sensazione è che l'astrazione sia così preziosa durante il periodo di sviluppo che vale la pena affrontare i problemi che affrontiamo come manutentori quando proviamo a capire il codice. Esistono software per risolvere i problemi aziendali, i problemi aziendali si evolvono nel tempo; quindi, il software deve evolversi nel tempo. Senza astrazione, evolvere il software è molto difficile. Si può progettare l'astrazione in modo tale che il manutentore possa navigare facilmente nella base di codice una volta che vede lo schema della struttura del codice, in modo che solo la curva di apprendimento iniziale sia frustrante.


0

Come altri hanno già detto, "nascondere i dettagli" dietro un'astrazione consente loro di essere modificati senza influire sugli utenti. Questa idea deriva da On the Criteria to Paromas to Decomposing Systems Into Modules (1972) ed è collegata all'idea di tipi di dati astratti (ADT) e alla programmazione orientata agli oggetti.

Più o meno nello stesso periodo, Un modello relazionale di dati di Codd per grandi banche dati condivise (1970) è stato motivato (vedi abstract e introduzione) volendo cambiare la rappresentazione della memoria interna dei database, senza influenzare gli utenti del database. Aveva visto i programmatori impiegare regolarmente giorni, modificando pagine di codice, per far fronte a piccole modifiche alla memoria.

Detto questo, un'astrazione non è molto utile se devi vedere cosa c'è dentro per poterla usare. Può essere molto difficile progettarlo bene. Un esempio di una buona astrazione è l'aggiunta: quando è stata l'ultima volta che hai dovuto pensare a cosa succede dentro? (ma a volte lo fai, ad esempio per overflow).

Il problema essenziale (IMHO) è che per progettare bene i moduli (nel senso di Parnas), è necessario prevedere cosa cambierà e cosa no. Prevedere il futuro è difficile, ma se hai molta esperienza con qualcosa e lo capisci chiaramente, allora puoi fare un buon lavoro di previsione. E quindi, puoi progettare un modulo (astrazione) che funzioni bene.

Tuttavia, sembra il destino di tutte le astrazioni - anche le migliori - che alla fine ci saranno cambiamenti imprevisti (e probabilmente imprevedibili) che richiedono la rottura dell'astrazione. Per ovviare a questo, alcune astrazioni hanno una via di fuga, dove puoi accedere a un livello più profondo se ne hai davvero bisogno.

Tutto questo sembra molto negativo. Ma penso che la verità sia che siamo circondati da astrazioni che funzionano così bene che non le notiamo o realizziamo cosa nascondono. Notiamo solo le scarse astrazioni, quindi ne abbiamo una visione itterica.


0

Le astrazioni sono principalmente a beneficio dei loro consumatori (ad es. Programmatori di applicazioni). I programmatori di sistema (designer) hanno più lavoro da fare per renderli belli e utili, motivo per cui un buon design di solito non è fatto dai principianti.

Forse non ti piacciono le astrazioni perché aggiungono sempre complessità? Forse i sistemi su cui hai lavorato avevano l'astrattite (uso eccessivo di astrazioni)? Non sono una panacea.

Il lavoro extra e la complessità di un'astrazione utile dovrebbero ripagare, ma è difficile saperlo con certezza. Se si considera un'astrazione come un punto di articolazione, la progettazione del software può flettersi su entrambi i lati: le implementazioni dell'astrazione possono essere modificate senza rompere il codice client e / o i nuovi clienti possono facilmente riutilizzare l'astrazione per fare nuove cose.

Si potrebbe quasi misurare il ritorno sull'investimento delle astrazioni dimostrando che sono state "flesse" nel tempo in una o entrambe le direzioni: modifiche all'implementazione relativamente indolore e nuovi clienti aggiuntivi.

Ad esempio: usando l'astrazione della classe Socket in Java, sono sicuro che il mio codice dell'applicazione da Java 1.2 funziona ancora bene in Java 7 (anche se potrebbero esserci dei cambiamenti nelle prestazioni). Da Java 1.2, ci sono stati sicuramente molti nuovi client che hanno utilizzato anche questa astrazione.

Per quanto riguarda l'infelicità con le astrazioni, se ho parlato con gli sviluppatori che hanno mantenuto il codice dietro la classe Socket, allora forse le loro vite non sono così peachy e rosee come i client che hanno usato Socket per scrivere applicazioni divertenti. Lavorare sull'implementazione di un'astrazione è sicuramente più lavoro che usarlo. Ma questo non lo rende negativo.

Per quanto riguarda la trasparenza, in una strategia di progettazione dall'alto verso il basso, la trasparenza totale comporta un cattivo design. I programmatori intelligenti tendono a trarre il massimo dalle informazioni di cui dispongono e il sistema si accoppia strettamente. Il più piccolo cambiamento di dettaglio (ad esempio, cambiando l'ordine dei byte in una struttura di dati) in un modulo potrebbe rompere qualche codice altrove, perché un programmatore intelligente ha usato queste informazioni per fare qualcosa di utile. David Parnas ha sottolineato questo problema in articoli risalenti al 1971, dove ha proposto di nascondere informazioni nei progetti.

Il tuo riferimento ad ArchLinux ha senso per me se consideri il "dentro" del sistema operativo come l'implementazione complessa dell'astrazione che sono il sistema operativo per le applicazioni che lo eseguono. Mantenerlo semplice nelle viscere dell'astrazione.


0

Risponderò alla tua domanda con una domanda; quando hai guidato al lavoro stamattina (suppongo che in effetti lo hai fatto), ti è importato esattamente come il motore ha aperto le valvole per far entrare le miscele aria-carburante e poi le ha accese? No. Non ti interessa come funziona il motore della tua auto quando guidi lungo la strada. Si cura che fa il lavoro.

Supponiamo che un giorno la tua auto non funzioni. Non si avvia, lancia una canna, si rompe una cintura, inspiegabilmente si arrabbia in quella barriera di cemento per colpa tua mentre eri impegnato a mandare messaggi. Ora hai bisogno di una macchina nuova (almeno temporaneamente). Ti interessa esattamente come funziona questa nuova auto? No. Quello che ti interessa è innanzitutto che funzioni, e in secondo luogo che puoi usare le stesse conoscenze e abilità che hai usato per guidare la tua vecchia auto per guidare quella nuova. Idealmente, ti dovrebbe sembrare che non ci siano stati cambiamenti nell'auto che stai guidando. Realisticamente, il modo in cui funziona questa nuova auto dovrebbe darti il ​​minor numero di "sorprese" possibili.

Questi principi di base sono il principio fondamentale dietro l'incapsulamento e l'astrazione. La conoscenza di come un oggetto fa ciò che fa non dovrebbe essere un requisito per usarlo per fare ciò che fa. Anche nella programmazione per computer, i dettagli dei percorsi elettrici all'interno della CPU che eseguono il programma sono astratti dietro almeno una mezza dozzina di strati di istruzioni I / O, driver, software OS e runtime. Molti ingegneri del software di grande successo scrivono codice perfettamente perfetto senza preoccuparsi dell'esatta architettura hardware, o persino della build del sistema operativo, che lo eseguiranno. Incluso me.

L'incapsulamento / occultamento delle informazioni consente alla mentalità "non importa come fa, cura solo che faccia". Il tuo oggetto dovrebbe esporre ciò che è utile per il consumatore, in modo tale che il consumatore possa facilmente consumarlo. Ora, nel mondo reale, questo non significa che un'auto non dovrebbe fornire all'utente alcuna informazione sui meccanismi interni, o che l'auto dovrebbe consentire all'utente solo le funzionalità più basilari come l'accensione, il volante, e pedali. Tutte le auto dispongono di tachimetri e indicatori di livello del carburante, contagiri, luci idiota e altri feedback. Praticamente tutte le auto hanno anche interruttori per vari sottosistemi indipendenti, come i fari, gli indicatori di direzione, la radio, la regolazione del sedile, ecc. Alcune auto consentono un input utente piuttosto esoterico, come la sensibilità del differenziale centrale a slittamento limitato. In tutti i casi, se ne conosci abbastanza, puoi aprirlo e cambiare le cose per farlo funzionare in modo leggermente diverso. Ma, nella maggior parte dei casi, forse, forse, l'utente non dovrebbe essere in grado di controllare direttamente e indipendentemente le pompe del carburante dall'interno della cabina? Forse, forse, l'utente non dovrebbe essere in grado di attivare le luci dei freni senza premere il pedale del freno?

L'astrazione permette alla "questa non è la stessa cosa, ma poiché sono entrambe XI posso usarle come farei con qualsiasi X" mentalità. Se il tuo oggetto eredita o implementa un'astrazione, i tuoi consumatori dovrebbero aspettarsi che l'implementazione produca lo stesso o simile risultato di altre implementazioni conosciute dell'astrazione. Una Toyota Camry e una Ford Fusion sono entrambe "macchine". Come tali, hanno una serie comune di funzionalità previste, come un volante. Giralo in senso antiorario, l'auto va a sinistra. Giralo in senso orario, l'auto va a destra. Puoi salire su qualsiasi auto negli Stati Uniti e aspettarti che l'auto abbia un volante e almeno due pedali, quello a destra è il pedale "auto va" e quello al centro è il pedale "auto ferma" .

Un corollario di astrazione è la "teoria del minimo stupore". Se ti mettessi al volante di una nuova auto per un giro di prova, ruotassi il volante in senso orario e l'auto girasse a sinistra, saresti piuttosto stupito a dir poco. Accuseresti il ​​rivenditore di vendere un POS e difficilmente ascolterai una delle sue ragioni per cui il nuovo comportamento è "migliore" di quello a cui sei abituato, o quanto bene questo "comportamento" è "documentato" o come " trasparente "il sistema di controllo è. Nonostante questa nuova auto e tutte le altre che hai guidato siano ancora "auto", quando guidi questa auto devi cambiare alcuni concetti fondamentali di come si suppone che un'auto debba essere guidata per guidare con successo la nuova auto. In genere è una brutta cosa, e succede solo quando c'è un vantaggio intuitivo nel nuovo paradigma. Forse l'aggiunta delle cinture di sicurezza è un buon esempio; 50 anni fa sei appena entrato e sei andato, ma ora devi allacciarti, il vantaggio intuitivo è che non passi attraverso il parabrezza o sul sedile del passeggero in caso di incidente. Anche allora, i driver hanno resistito; molti proprietari di auto tagliano le cinture di sicurezza dall'auto fino a quando non vengono approvate le leggi che impongono il loro uso.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.