Ci sono degli svantaggi significativi a seconda delle astrazioni?


9

Stavo leggendo questo wiki sul principio delle astrazioni stabili (SAP) .

Il SAP afferma che più stabile è un pacchetto, più astratto dovrebbe essere. Ciò implica che se un pacchetto è meno stabile (più probabilità di cambiare), dovrebbe essere più concreto. Quello che non capisco davvero è perché questo dovrebbe essere il caso. Sicuramente in tutti i casi, indipendentemente dalla stabilità, dovremmo dipendere da astrazioni e nascondere l'attuazione concreta?


Prova a utilizzare un componente con cui ti senti a tuo agio, non usando le astrazioni che fornisce, ma facendo tutto in dettaglio a un livello inferiore a quello a cui sei abituato. Ciò ti darà una buona impressione dei vantaggi e degli svantaggi dell'astrazione.
Kilian Foth,

2
Hai letto l'articolo collegato e / o il libro su cui si basa l'articolo?
Jörg W Mittag,

1
+1 Buona domanda, soprattutto perché non credo che il rapporto tra stabilità e astrazione sia immediatamente intuitivo. La pagina 11 di questo articolo aiuta, il suo esempio del caso astratto ha senso, ma forse qualcuno può scrivere un esempio più chiaro del caso concreto. Richiesta di decollo.
Mike,

Quale dominio problematico hai a che fare con queste astrazioni? Come osservato in C2: "Nel modellare domini del mondo reale - il mondo di clienti, impiegati, fatture, distinte materiali, prodotti, SKU, buste paga, ecc. - le astrazioni stabili possono essere difficili da trovare. Domini computazionali - il mondo di pile, code, funzioni, alberi, processi, thread, widget grafici, report, moduli, ecc. - hanno molte più probabilità di essere stabili ". e "In alcuni settori, è difficile trovare astrazioni stabili". Senza sapere quale problema stai cercando di risolvere con SAP, è difficile darti una buona risposta.

@ JörgWMittag e Mike - Sì, ho letto l'articolo. Sento solo che manca una spiegazione del perché "i pacchetti instabili dovrebbero essere concreti". A pagina 13 di detto articolo mostra un grafico ma non spiega in modo troppo dettagliato perché (1,1) sul grafico dovrebbe essere evitato? L'idea che fondamentalmente instabile significhi dipendenze meno afferenti e perché non è necessario usare l'astrazione? Se è così ... non è una buona pratica usare l'astrazione comunque, nel caso in cui la stabilità cambi con i cambiamenti dei requisiti ..
SteveCallender

Risposte:


7

Pensa ai tuoi pacchetti come a un'API, per prendere l'esempio dal documento, prendere le definizioni Readercon string Reader.Read()e Writercon void Writer.Write(string)come l'API astratta.

È quindi possibile creare una classe Copycon un metodo Copier.Copy(Reader, Writer)e l'implementazione Writer.Write(Reader.Read())e forse alcuni controlli di integrità.

Ora, fate implementazioni concrete, ad esempio FileReader, FileWriter, KeyboardReadere DownloadThingsFromTheInternetReader.

Cosa succede se si desidera modificare l'implementazione di FileReader? Nessun problema, basta cambiare la classe e ricompilare.

E se vuoi cambiare la definizione della tua astrazione Reader? Spiacenti, non si può semplicemente cambiare la situazione, ma si avrà anche cambiare Copier, FileReader, KeyboardReadere DownloadThingsFromTheInternetReader.

Questa è la logica alla base del principio di astrazione stabile: rendere le concrezioni meno stabili delle astrazioni.


1
Sono d'accordo con tutto ciò che dici, ma credo che la definizione degli autori di stabilità e la tua differisca. Trattate la stabilità come necessità di cambiare, l'autore afferma che "la stabilità non è una misura della probabilità che un modulo cambi, ma piuttosto una misura della difficoltà nel cambiare un modulo". Quindi la mia domanda è più: perché è utile che i pacchetti che sono facilmente cambiati siano più concreti piuttosto che astratti?
SteveCallender,

1
@SteveCallender È una sottile differenza: la definizione dell'autore di "stabilità" è ciò che la maggior parte delle persone chiama "necessità di stabilità". Quanto più i moduli dipendono da un modulo, tanto più "stabile" deve essere un modulo.
Residuum,

6

A causa di YAGNI .

Se al momento hai una sola implementazione di una cosa , perché preoccuparsi di un livello extra e inutile? Porterà solo a complessità inutili. Ancora peggio, a volte fornisci un'astrazione pensando al giorno in cui arriverà una seconda implementazione ... e questo giorno non accade mai. Che spreco di lavoro!

Penso anche che la vera domanda da porsi non sia "Devo dipendere da astrazioni?" ma piuttosto "Ho bisogno di modularità?". E la modularità non è sempre necessaria, vedi sotto.

Nell'azienda in cui lavoro, alcuni dei software che sviluppo sono fortemente legati ad alcuni dispositivi hardware con cui devono comunicare. Questi dispositivi sono sviluppati per raggiungere obiettivi molto specifici e sono tutt'altro che modulari. :-) Una volta che il primo dispositivo prodotto esce dalla fabbrica e viene installato da qualche parte, sia il firmware che l'hardware non possono mai cambiare, mai .

Quindi, posso essere sicuro che alcune parti del software non si evolveranno mai. Queste parti non devono dipendere da astrazioni poiché esiste solo un'implementazione e questa non cambierà mai. Dichiarare astrazioni su queste parti di codice confonderà solo tutti e richiederà più tempo (senza produrre alcun valore).


1
Tendo ad essere d'accordo con YAGNI, ma mi chiedo il tuo esempio. Non ripeti mai alcun codice nei diversi dispositivi? Trovo difficile credere che non ci sia un codice comune tra i dispositivi della stessa azienda. Inoltre, come piacciono ai client quando non si correggono i bug nel loro firmware? Stai dicendo che non ci sono mai bug, mai ? Se hai lo stesso codice che è difettoso in 4 implementazioni diverse, devi correggere il bug 4 volte se non si trova in un modulo comune.
Fuhrmanator,

1
Il codice comune di @Fuhrmanator è diverso dalle astrazioni. Codice comune può significare solo un metodo di supporto o una libreria - non sono necessarie astrazioni.
Eilon,

@Fuhrmanator Naturalmente abbiamo un codice comune nelle biblioteche, ma come ha detto Eilon, non tutto dipende dalle astrazioni (alcune parti invece lo fanno). Non ho mai detto che non ci siano mai bug, ho detto che non possono essere corretti (per motivi che esulano dall'ambito della domanda del PO).
Scoperto l'

@Eilon il mio commento riguardava la modularità non è sempre necessaria (non astrazioni).
Fuhrmanator,

@Spotted Nessun problema di non essere in grado di patchare. È solo un esempio piuttosto specifico e non tipico della maggior parte dei software.
Fuhrmanator,

6

Penso che tu sia forse confuso dalla parola stabile scelta da Robert Martin. Ecco dove penso che inizi la confusione:

Ciò implica che se un pacchetto è meno stabile (più probabilità di cambiare), dovrebbe essere più concreto.

Se leggi l' articolo originale , vedrai (sottolineatura mia):

La definizione classica della parola stabilità è: "Non facilmente spostabile". Questa è la definizione che useremo in questo articolo. Cioè, la stabilità non è una misura della probabilità che un modulo cambi; piuttosto è una misura della difficoltà nel cambiare un modulo .

Chiaramente, i moduli che sono più difficili da cambiare, saranno meno volatili. Più difficile è il modulo da cambiare, vale a dire più è stabile, meno volatile sarà.

Ho sempre lottato con la scelta dell'autore della parola stabile , poiché io (come te) tendo a pensare all'aspetto "verosimiglianza" della stabilità, cioè è improbabile che cambi . La difficoltà implica che cambiando quel modulo si romperanno molti altri moduli, e sarà molto lavoro per riparare il codice.

Martin usa anche le parole indipendente e responsabile , che per me trasmettono molto più significato. Nel suo seminario di formazione, ha usato una metafora sui genitori dei bambini che crescono e su come dovrebbero essere "responsabili", perché i loro figli dipendono da loro. Divorzio, disoccupazione, incarcerazione, ecc. Sono grandi esempi del mondo reale dell'impatto negativo che il cambiamento dei genitori avrà sui bambini. Pertanto, i genitori dovrebbero essere "stabili" a beneficio dei loro figli. A proposito, questa metafora di bambini / genitori non è necessariamente correlata all'eredità in OOP!

Quindi, seguendo lo spirito di "responsabile", ho escogitato significati alternativi per difficili da cambiare (o non dovrebbero cambiare ):

  • Obbligatorio: significa che altre classi dipendono da questa classe, quindi non dovrebbe cambiare.
  • Beholden - ibid.
  • Vincolato: gli obblighi di questa classe limitano la sua facilità nel cambiare.

Quindi, inserendo queste definizioni nell'istruzione

più stabile è un pacchetto, più astratto dovrebbe essere

  • più un pacchetto è obbligatorio , più dovrebbe essere astratto
  • più vedo un pacchetto, più astratto dovrebbe essere
  • più un pacchetto è limitato , più astratto dovrebbe essere

Citiamo il principio delle astrazioni stabili (SAP), enfatizzando le parole confuse stabile / instabile:

I pacchetti che sono al massimo stabili dovrebbero essere al massimo astratti. I pacchetti instabili dovrebbero essere concreti. L'astrattezza di un pacchetto dovrebbe essere proporzionale alla sua stabilità .

Chiarirlo senza queste parole confuse:

I pacchetti che sono fissati al massimo ad altre parti del sistema dovrebbero essere al massimo astratti. I pacchetti che possono cambiare senza difficoltà dovrebbero essere concreti. L'astrattezza di un pacchetto dovrebbe essere proporzionale alla difficoltà di modifica .

TL; DR

Il titolo della tua domanda chiede:

Ci sono degli svantaggi significativi a seconda delle astrazioni?

Penso che se crei correttamente le astrazioni (ad esempio, esistono perché molto codice dipende da esse), allora non ci sono svantaggi significativi.


0

Ciò implica che se un pacchetto è meno stabile (più probabilità di cambiare), dovrebbe essere più concreto. Quello che non capisco davvero è perché questo dovrebbe essere il caso.

Le astrazioni sono cose che sono difficili da cambiare nel software perché tutto dipende da esse. Se il tuo pacchetto cambierà spesso e fornirà astrazioni, le persone che dipendono da esso saranno costrette a riscrivere una grande quantità del loro codice quando cambi qualcosa. Ma se il tuo pacchetto instabile fornisce alcune implementazioni concrete, il codice molto meno dovrà essere riscritto dopo le modifiche.

Quindi, se il tuo pacchetto cambierà spesso, dovrebbe fornire meglio calcestruzzi, non astrazioni. Altrimenti ... chi diavolo lo userà? ;)


0

Tieni presente la metrica di stabilità di Martin e cosa intende per "stabilità":

Instability = Ce / (Ca+Ce)

O:

Instability = Outgoing / (Incoming+Outgoing)

Cioè, un pacchetto è considerato completamente instabile se tutte le sue dipendenze sono in uscita: usa altre cose, ma nulla lo usa. In quel caso, ha senso solo che quella cosa sia concreta. Sarà anche il tipo di codice più semplice da modificare poiché nient'altro lo utilizza e quindi nient'altro può rompersi se quel codice viene modificato.

Nel frattempo, quando hai lo scenario opposto di completa "stabilità" con un pacchetto usato da una o più cose ma non usa nulla da solo, come un pacchetto centrale usato dal software, è quando Martin dice che dovrebbe essere astratto. Ciò è anche rafforzato dalla parte DIP di SOLI (D), il principio di inversione di dipendenza, che afferma sostanzialmente che le dipendenze dovrebbero fluire uniformemente verso le astrazioni sia per il codice basso che per quello di alto livello.

Cioè, le dipendenze dovrebbero fluire uniformemente verso la "stabilità" e, più precisamente, le dipendenze dovrebbero fluire verso pacchetti con più dipendenze in entrata rispetto alle dipendenze in uscita e, inoltre, le dipendenze dovrebbero fluire verso le astrazioni. L'essenza della logica alla base di ciò è che le astrazioni forniscono spazio per sostituire un sottotipo con un altro, offrendo quel grado di flessibilità per le parti in calcestruzzo che implementano l'interfaccia per cambiare senza spezzare le dipendenze in entrata in quella interfaccia astratta.

Ci sono degli svantaggi significativi a seconda delle astrazioni?

Bene, in realtà non sono d'accordo con Martin qui per il mio dominio, e qui ho bisogno di introdurre una nuova definizione di "stabilità" come in "mancanza di ragioni per cambiare". In quel caso direi che le dipendenze dovrebbero fluire verso la stabilità, ma le interfacce astratte non aiutano se le interfacce astratte sono instabili (secondo la mia definizione di "instabile", come soggetto a ripetute modifiche, non a quelle di Martin). Se gli sviluppatori non riescono a ottenere le astrazioni corrette e i clienti cambiano ripetutamente idea in modo da rendere astratti i tentativi di modellare il software incompleto o inefficace, allora non beneficiamo più della maggiore flessibilità delle interfacce astratte per proteggere il sistema da cambiamenti a cascata che dipendono dalla dipendenza . Nel mio caso personale ho trovato motori ECS, come quelli trovati nei giochi AAA,più concreti : verso i dati grezzi, ma tali dati sono altamente stabili (come in ", è improbabile che debbano mai essere cambiati"). Ho trovato spesso la probabilità che qualcosa che richieda cambiamenti futuri sia una metrica più utile del rapporto tra accoppiamenti efferenti e totali nel guidare le decisioni SE.

Quindi altererei un po 'il DIP e direi semplicemente che "le dipendenze dovrebbero fluire verso componenti che hanno la più bassa probabilità di richiedere ulteriori modifiche", indipendentemente dal fatto che tali componenti siano interfacce astratte o dati grezzi. Tutto ciò che conta per me è la probabilità che possano richiedere modifiche dirette alla progettazione. Le astrazioni sono utili in questo contesto di stabilità solo se qualcosa, essendo astratto, riduce tale probabilità.

Per molti contesti questo potrebbe essere il caso di ingegneri e clienti decenti che anticipano le esigenze del software in anticipo e progettano astrazioni stabili (come in, immutabili), mentre quelle astrazioni offrono loro tutto il respiro di cui hanno bisogno per scambiare implementazioni concrete. Ma in alcuni domini, le astrazioni potrebbero essere instabili e inclini a essere inadeguate, mentre i dati richiesti dal motore potrebbero essere molto più facili da anticipare e rendere stabili in anticipo. Quindi, in quei casi, può effettivamente essere più vantaggioso dal punto di vista della manutenibilità (la facilità di cambiare ed estendere il sistema) affinché le dipendenze fluiscano verso i dati piuttosto che verso le astrazioni. In un ECS, le parti più instabili (come nelle parti più frequentemente modificate) sono in genere le funzionalità che risiedono nei sistemi (PhysicsSystem, ad esempio), mentre le parti più stabili (come nella probabilità meno probabile che vengano modificate) sono i componenti costituiti solo da dati non MotionComponentelaborati ( ad esempio) utilizzati da tutti i sistemi.

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.