Che cos'è "astrazione prematura"?


10

Ho sentito la frase che viene lanciata in giro e per me gli argomenti sembrano completamente pazzi (mi dispiace se sto facendo impazzire qui, non è mia intenzione), generalmente va qualcosa del tipo di:

Non vuoi creare un'astrazione prima di sapere qual è il caso generale, altrimenti (1) potresti mettere cose nelle tue astrazioni che non appartengono o (2) omettere cose di importanza.

(1) A me sembra che il programmatore non sia abbastanza pragmatico, hanno ipotizzato che nel programma finale esistessero cose che non lo fanno, quindi stanno lavorando con un livello di astrazione basso, il problema non è astrazione prematura, è concrezione prematura.

(2) Omettere cose importanti è una cosa, è del tutto possibile che qualcosa sia omesso dalle specifiche che in seguito si rivelano importanti, la soluzione a questo non è quella di inventare la tua concrezione e sprecare risorse quando ti scopri indovinato, è per ottenere maggiori informazioni dal client.

Dovremmo sempre lavorare dalle astrazioni fino alle concrezioni poiché questo è il modo più pragmatico di fare le cose, e non viceversa.

Se non lo facciamo, rischiamo di fraintendere i clienti e creare cose che devono essere cambiate, ma se costruiamo solo le astrazioni che i clienti hanno definito nella loro lingua, non corriamo mai questo rischio (almeno in nessun luogo vicino come probabile uno scatto nel buio con un po 'di concrezione), sì, è possibile che i clienti cambino idea sui dettagli, ma le astrazioni che hanno usato per comunicare in origine ciò che vogliono tendono ad essere ancora valide.

Ecco un esempio, supponiamo che un cliente desideri che tu crei un robot di insacco di oggetti:

public abstract class BaggingRobot() {
    private Collection<Item> items;

    public abstract void bag(Item item);
}

Stiamo costruendo qualcosa dalle astrazioni utilizzate dal cliente senza entrare nel dettaglio con cose che non conosciamo. Questo è estremamente flessibile, ho visto questo essere chiamato "astrazione prematura" quando in realtà sarebbe più prematuro ipotizzare l'implementazione del bagging, diciamo dopo aver discusso con il cliente che vogliono che più di un articolo venga insaccato in una volta . Per aggiornare la mia classe tutto ciò di cui ho bisogno è cambiare la firma, ma per qualcuno che ha iniziato dal basso verso l'alto potrebbe comportare una revisione del sistema di grandi dimensioni.

L'astrazione prematura non esiste, ma solo la concrezione prematura. Cosa c'è di sbagliato in questa affermazione? Dov'è il difetto nel mio ragionamento? Grazie.


1
L'opposto dell'astrazione prematura è YAGNI - You Ain't Gonna Need It, che secondo me è quasi sempre sbagliato. Quasi. L'ho visto accadere, ma è raro. Sono principalmente d'accordo con quello che stai dicendo qui.
user1118321

Risposte:


19

Almeno secondo me, l'astrazione prematura è abbastanza comune, ed è stata particolarmente così precoce nella storia di OOP.

Almeno da quello che ho visto, il problema principale che è emerso è stato che le persone leggevano gli esempi tipici di gerarchie orientate agli oggetti. Gli è stato detto molto su come rendere tutto pronto per affrontare i futuri cambiamenti che potrebbero sorgere (anche se non c'erano motivi particolarmente validi per credere che lo avrebbero fatto). Un altro tema comune a molti articoli per un po 'era quello dell'ornitorinco, che sfidava semplici regole su "i mammiferi sono tutti così" o "gli uccelli sono tutti così".

Di conseguenza, abbiamo finito con il codice che in realtà aveva solo bisogno di gestire, per esempio, i registri dei dipendenti, ma sono stati accuratamente scritti per essere pronti se hai mai assunto un aracnide o forse un crostaceo.


Quindi l'astrazione prematura non è l'atto di astrarre, è l'atto di astrarre oltre il livello di astrazione delle specifiche. Questo ha molto più senso, e ho potuto vedere che stava realmente accadendo. Immagino di dover solo chiarire ai miei colleghi che sto lavorando al livello di astrazione delineato dal mio manager.
James,

1
@James: può anche significare astrarre "troppo" a causa delle specifiche della versione 1.0, dal momento che ritieni di conoscere un nuovo requisito nelle specifiche di una versione successiva, quindi implementa già v1.0 in un modo più generale di necessario. Qualcosa, è bello immaginare cosa potrebbe accadere in una versione successiva, ma c'è anche un certo rischio di ingegnerizzazione eccessiva.
Doc Brown,

@DocBrown La chiamerei concrezione prematura. L'atto di astrazione è rimuovere le informazioni, non aggiungerle. Se stai aggiungendo all'astrazione più di quanto sia necessario, allora stai assumendo qualcosa sui livelli più bassi di astrazione. Vorrei fare una distinzione tra i due come penso che chiamare "astrazione" non abbia molto senso in quanto la definizione di astrazione è "il processo di estrazione dell'essenza sottostante" dove la concrezione è "caratterizzata o appartenente all'esperienza immediata di cose o eventi reali ".
James,

6

È importante ricordare che l'astrazione è un mezzo per raggiungere un fine. Usi l'astrazione per uniformare il comportamento nel tuo programma e rendi semplice l'aggiunta di nuove classi nei casi in cui ti aspetteresti di aggiungere nuove classi, ma solo quando l'astrazione è necessaria proprio in quel momento.

Non aggiungerei l'astrazione semplicemente perché potresti averne bisogno (senza una vera base per pensare che dovrai aggiungere nuove lezioni in futuro). Una metafora corretta qui potrebbe essere idraulica. Spero che accetti che un tubo a 6 direzioni che permetta all'acqua di fluire su / giù, est / ovest, nord / sud sarebbe il tipo più flessibile di tubo che potresti avere. Potresti teoricamente usare un tubo a 6 direzioni ovunque sia richiesto un tubo e bloccare le direzioni non necessarie, giusto?

Se hai provato a risolvere un problema con una perdita sotto il lavandino e hai scoperto che tutte le sezioni del tubo erano pezzi di tubo a 6 direzioni, ti consigliamo di strappare i capelli frustrati dal ragazzo che lo ha progettato in quel modo. Non solo non sai dove si trova il problema, ma sarebbe quasi sicuramente più semplice iniziare da zero fatto in modo corretto.

Naturalmente la codifica non è idraulica, ma la metafora è ancora valida. L'astrazione è come usare quei pezzi di tubo a 6 direzioni. Usali quando credi sinceramente che un giorno nel prossimo futuro dovrai collegare i tubi da tutte e 6 le direzioni. Altrimenti l'astrazione è semplicemente una complicazione, non molto diversa dall'uso di un modello in cui nessuno è richiesto o dall'uso di una classe divina che tenta di fare tutto. Se non viene utilizzato e probabilmente non verrà mai utilizzato, alla fine si aggiunge una classe aggiuntiva per nulla.

Certo, l'arte di scrivere programmi è concettualmente molto astratta. Vale semplicemente la pena ricordare che le astrazioni non esistono per il bene di essere un'astrazione ma perché sono pratiche in qualche modo reale. Se senti il ​​bisogno di usare l'astrazione, così sia, ma non chiedermi di controllare il tuo impianto idraulico in seguito. ;)


Sembri un po ' class-centrico ... Anche se ci sono molte classi, l'astrazione non si limita a essere usata / a beneficiarne.
Deduplicatore

1
@Deduplicator Abbastanza giusto, ma questo non cambia il mio punto. Se si utilizza l'astrazione, dovrebbe essere immediatamente vantaggioso o dovrebbe essere un cambiamento pianificato nel prossimo futuro. Non importa che ci riferiamo alle lezioni o alla programmazione funzionale.
Neil

3

Quando ho saputo dell'analisi e della progettazione orientate agli oggetti, molti anni fa, abbiamo iniziato con una semplice descrizione inglese del sistema di cui il cliente aveva bisogno.

Guardando attraverso quello, qualsiasi sostantivo (o frase di sostantivo) sarebbe considerato come una possibile classe. Qualsiasi verbo (o frase verbale) sarebbe un potenziale metodo per le classi. Quindi "robot insaccatore" potrebbe essere una classe BaggingRobot. "Apri un sacchetto" potrebbe diventare un metodo OpenBag.

Dopo alcune iterazioni, questo si trasformerebbe in un diagramma di classe.

A questo punto, non ci sono classi astratte. Il cliente non vuole un concetto astratto di robot insaccamento. Vogliono un robot che metta le cose in borsa. Tutte le classi sono concrete e hanno una serie di metodi.

Le classi astratte vengono introdotte solo quando diventa chiaro che:

  • Esistono diverse classi simili che potrebbero formare una gerarchia.
  • In realtà condividono qualcosa in comune, in modo che una classe base svolga uno scopo utile.

Per me, "l'astrazione prematura" presuppone che qualcuno BaggingRobot debba ereditare da alcuni BaseRobote, peggio ancora, cercare di sviluppare una serie di metodi BaseRobotprima ancora di sapere cosa è comune a tutti i robot.


L'astrazione non è sinonimo di classi astratte. Un'interfaccia è un'astrazione. Sto parlando di astrazioni in generale, non solo di classi astratte. Forse avrei potuto renderlo più chiaro usando un'interfaccia. Se sviluppi il tuo sistema sullo stesso livello di astrazione del tuo client, probabilmente sarà il caso di finire con alcune classi astratte che devono essere estese dal momento che il linguaggio è naturalmente astratto. Lavorare più in basso di questo è ciò che chiamo "concrezione prematura" in cui si assume ingenuamente che le idee dei clienti su come funzionerà il sistema, sono le stesse della tua.
James,

Un oggetto BaggingRobot che mette gli oggetti Item in oggetti Bag è già un'astrazione di un vero robot di insaccamento che mette le cose in sacchetti.
user253751

1

Sembra un po 'come se volessi risolvere un problema che non esiste ancora e che non hai buone ragioni per presumere che accada, a meno che tu non creda semplicemente che il cliente abbia torto in ciò che sta richiedendo. In tal caso, consiglierei più comunicazione sull'implementazione di una soluzione ipotetica, astratta o meno. Mentre potrebbe sembrare innocuo schiaffeggiare semplicemente "astratto" sulla definizione della classe e sentirti al sicuro sapendo che puoi estenderlo in seguito, potresti scoprire che non ne hai mai bisogno, o potresti trovarti ad estenderlo in modi che complicano eccessivamente il design la linea, astraggendo le cose sbagliate.

Seguendo il tuo esempio, immagini che sia il robot stesso , gli oggetti da insaccare o il metodo di insaccamento che cambierà lungo la linea?

L'astrazione prematura significa davvero che non hai buoni motivi per eseguire l'astrazione e poiché le astrazioni sono tutt'altro che libere in molte lingue, potresti incorrere in spese generali senza giustificazione.

Modifica Per rispondere ad alcuni punti dell'OP nei commenti, lo sto aggiornando per chiarire e rispondere in un modo che non richiede una lunga catena di commenti mentre si affrontano i punti (1) e (2) in modo più specifico.

(1) A me sembra che il programmatore non sia abbastanza pragmatico, hanno ipotizzato che nel programma finale esistessero cose che non lo fanno, quindi stanno lavorando con un livello di astrazione basso, il problema non è astrazione prematura, è concrezione prematura.

(Enfasi mia). Supponendo che esistano cose nel programma finale che non è esattamente quello che vedo nel tuo esempio. Il cliente ha chiesto un robot per l'insacco degli oggetti. Questa è una richiesta molto specifica, anche se piuttosto vaga nella sua lingua. Il cliente desidera un robot che trasporta oggetti, in modo da produrre un paio di oggetti

public class Item {
/* Relevant item attributes as specified by customer */
}
public class BaggingRobot {
  private Collection<Item> items;

  public void bag(Item item);
}

Il tuo modello è semplice e preciso, segue i requisiti stabiliti dal cliente senza aggiungere complessità alla soluzione e senza dare per scontato che il cliente desiderasse più di quanto richiesto. Se, quando presentato, chiariscono la necessità per il robot di avere meccanismi di insaccamento intercambiabili, solo allora hai abbastanza informazioni per giustificare la creazione di un'interfaccia o un altro metodo di astrazione, poiché ora puoi puntare a un valore specifico che viene aggiunto a il sistema attraverso l'astrazione.

Al contrario, se inizi con l'astrazione dal puro pragmatismo, o passi il tempo a creare un'interfaccia separata e ad implementarla in una concrezione, oppure a creare una classe astratta, o qualunque tipo di astrazione ti piaccia. Se dovesse poi risultare che il cliente è soddisfatto di ciò e non è necessaria alcuna ulteriore estensione, è stato inutilmente speso tempo e risorse e / o introdotto costi generali e complessità nel sistema senza alcun guadagno.

Per quanto riguarda (2), concordo sul fatto che omettere le cose importanti non è di per sé un segno distintivo di astrazione prematura. Astrazione o no, puoi omettere qualcosa di importante e, a meno che non sia trovato molto al di sotto della linea di una catena di astrazione, non sarà più difficile o più facile risolverlo in entrambi i modi.

Invece , interpreterei questo nel senso che qualsiasi astrazione corre il rischio di offuscare il tuo modello di dominio. L'astrazione errata può rendere molto difficile ragionare su un sistema, poiché si stanno creando relazioni che possono influenzare drasticamente l'ulteriore crescita del modello di dominio e la comprensione del dominio. Corri il rischio di omettere informazioni non importanti sulla cosa che viene sottratta , ma sul sistema nel suo insieme , portando il tuo modello nella tana del coniglio sbagliata.


"Sembra un po 'come se volessi risolvere un problema che non esiste ancora e che non hai buone ragioni per presumere che accada, a meno che tu non creda semplicemente che il cliente abbia torto in quello che sta richiedendo." - Questo non è affatto quello che ho detto, in realtà ho chiarito che stavo solo costruendo sulla base delle parole usate dal cliente. È l'atto di non voler fare ciò che mi ha spinto a usare le astrazioni.
James,

"Vorrei raccomandare più comunicazione sull'implementazione di una soluzione di ipotesi" - Intendi come ho suggerito? Per citare ciò che ho detto in OP "la soluzione a questo non è quella di trovare la tua concrezione e sprecare risorse quando scopri che hai indovinato, è ottenere maggiori informazioni dal cliente".
James,

"Mentre può sembrare innocuo schiaffeggiare semplicemente" astratto "sulla definizione della classe e sentirsi al sicuro sapendo che puoi estenderlo in seguito" - Quando dico "astrazione" intendo "astrazione" non intendo "parola chiave astratta". Le interfacce potrebbero essere astrazioni, le astrazioni sono logiche sfocate, ecco di cosa parla l'intero post. Il cliente sta comunicando in termini di astrazioni, quindi dovremmo programmare in termini astratti fino a quando non sapremo di più sul dominio.
James,

1
"potresti scoprire di non averne mai bisogno" - Non ha alcun senso. Un cliente dice "Voglio un robot che trasporta oggetti", crei un'astrazione che soddisfi questi criteri. Tutte le ulteriori informazioni che riceverai dal cliente saranno informazioni dettagliate su come vogliono che venga eseguito il bagging. Questo non ha invalidato la tua astrazione, il cliente non cambia improvvisamente idea su un'idea chiave dietro ciò che stanno acquistando. Il robot sta ancora impacchettando gli oggetti. L'astrazione che hai creato verrà comunque applicata.
James,

"o potresti trovarti ad estenderlo in modi che complicano eccessivamente il design lungo la linea, astraggendo le cose sbagliate." ... Hai letto onestamente quello che ho detto o solo il titolo? Sul serio? Leggi i punti (1) e (2)
James,
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.