Esposizione della rappresentazione dei dati

1

Mi piacerebbe sapere come viene esposta la rappresentazione dei dati nella diapositiva 7 di nascondere le informazioni :

  • La modifica di una rappresentazione di dati esposti si propaga su tutto il codice che accede direttamente a tale rappresentazione

    • Forse il miglior esempio dell'impatto che questo può avere è il problema dell'anno 2000
    • I software legacy per applicazioni diverse come controllo delle centrali nucleari, controllo del traffico aereo, finanza e militari sono stati codificati utilizzando le rappresentazioni dei dati esposti
    • Per garantire che il software funzioni correttamente, ogni 2000 postazione che utilizza la rappresentazione della data deve essere modificata per memorizzare anni utilizzando 4 cifre anziché 2
    • Il costo di questa conversione è stato stimato in miliardi di dollari!
  • La rappresentazione dei dati esposti porta a modificare la propagazione ... influisce sui costi di manutenzione ... un grosso problema

Mi piacerebbe anche sapere se nascondere informazioni significa "nascondere i dati usando identificatori di visibilità (pubblici, privati)" o se significhi "nascondere la rappresentazione dei dati". In realtà, la rappresentazione dei dati significa? Qualcuno potrebbe aiutarmi? / p>     

posta justin 28.11.2014 - 07:57
fonte

3 risposte

3

Quando parliamo di un sistema (o di un modulo, o classe, o struttura), ci sono due rappresentazioni di dati: interni ed esterni (non voglio chiamarli pubblici e privati per non mescolarne il significato con OOP ). L'esterno è una rappresentazione che viene utilizzata da ogni singola cosa che utilizza un sistema. C'è il rischio che cambiare questa rappresentazione esterna richieda il cambiamento di ogni cosa che dipende da questa rappresentazione. Raramente hai il pieno controllo di tutte queste cose. D'altro canto, la rappresentazione interna si trova in un unico posto e vi si accede tramite un insieme controllato di funzioni (non confondere con la funzione nel linguaggio di programmazione). Quando questa rappresentazione cambia, solo quelle funzioni devono cambiare. Quindi il cambiamento è molto più facile (e quindi più economico) per la rappresentazione interna rispetto alla rappresentazione esterna.

Il problema Y2K è stato causato da un semplice fatto: che la rappresentazione interna era anche esterna. Ogni singolo pezzo di codice si basava su un fatto, quell'anno è rappresentato da 2 cifre e che prima di quelle c'è sempre 19. Se, invece, c'era una chiara separazione, allora la rappresentazione interna userebbe le due cifre, ma la esterno sarebbe l'anno intero (tutte e 4 le cifre). Ciò significherebbe che solo la cosa che deve cambiare sarebbe la rappresentazione interna e la funzione che converte la rappresentazione interna in esterna (e in un altro modo).

    
risposta data 28.11.2014 - 14:12
fonte
2

Vorrei iniziare rispondendo alle tue domande:

  • La rappresentazione dei dati è il tipo di archiviazione dei dati e il significato dei possibili valori di tali dati. Ad esempio, un valore booleano può essere memorizzato come un singolo bit, dove il bit essendo 1 significa verità e 0 significa falsità.

  • La rappresentazione dei dati viene esposta creando qualcosa con un tipo (variabile, membro della classe) visibile all'esterno.

  • Nascondere informazioni significa usare costrutti di linguaggio per impedire che il funzionamento interno di un modulo sia visibile ad altro codice. "Funzionamento interno" può significare tutto ciò che fa sì che il modulo torni, come il fatto che esista un dato, la sua rappresentazione e come vengono determinati i valori (memorizzati, calcolati o entrambi).

Ecco un esempio pratico che dovrebbe rispondere alla domanda che penso tu stia davvero chiedendo in base ad alcuni dei tuoi commenti:

Supponiamo che tu stia sviluppando un'applicazione che ha bisogno di una classe per rappresentare una data. Ti viene in mente qualcosa che non fa nessuno sforzo per nascondere le informazioni, dove tutti i membri sono pubblici e non ci sono metodi per manipolarli:

class Date {    // Irrelevant parts left out for brevity
      ...
    public int month;  // Month of year, 1 = January
      ...
}

Il tuo team continua a scrivere molte migliaia di righe di codice che utilizzano Date , che presuppongono che il primo mese dell'anno, gennaio, sia rappresentato dal valore 1 e raggiunga direttamente la struttura per accedervi:

Date foo;
  ...
foo.month = 1;  // January
  ...

Un giorno, qualcuno scopre che una funzione critica sarebbe molto più efficiente se ha dato mesi a base zero ( 0 per gennaio, 1 per febbraio, ecc.) invece di dover fare l'aritmetica per produrne una ogni volta che legge o scrive il month membro di Date . La direzione decide il business case per fare il cambiamento è buono e dice di farlo accadere.

La funzione critica viene riscritta per utilizzare mesi a base zero, il che significa che ogni altra riga di codice nell'applicazione che si occupa di mesi è ora interrotta perché non utilizza i valori corretti. Può essere compilato perché il valore è ancora un numero intero, ma non utilizza più i valori corretti. Quello che era gennaio ( 1 ) ora è febbraio e quello che era dicembre ( 12 ) non è più un valore valido perché i mesi a base zero terminano a 11 .

(Questo esempio è un po 'forzato, perché le buone pratiche imporranno che la classe definisca le costanti per valori ben noti come Date.MONTH_JANUARY , ma abbiate con me. Il principio si applica ancora.)

Correggere il codice danneggiato ti dà molto da fare:

  • Identifica ogni uso di Date nell'applicazione intera
  • Verifica ciascuno di questi usi per determinare se fa o meno supposizioni sul valore del membro month
  • Cambia quelli che fanno per usare le nuove regole
  • Ricontrolla tutto
  • Mettiti in ginocchio e prega che non ti sia mancato nulla

I costi di questo sforzo possono essere enormi in termini di manodopera per effettuare e testare le modifiche e i rischi per l'azienda se un errore (o la correzione di uno) si tradurrebbe in mancati guadagni.

Se il Date era stato sviluppato utilizzando l'occultamento delle informazioni in primo luogo, ci sarebbero modi per manipolare il mese che sono indipendenti dal modo in cui sono memorizzati:

class Date {
      ...
    private int month;  // Month of year, 1 = January
      ...
    // These methods operate on the month as a 1-based value and
    // are the ones all of the existing code uses.
    void set_month(int new_month) { month = new_month; }
    int  get_month() { return month; }
}

Apportare la modifica all'archiviazione basata su zero rende la tua lista di cose da fare molto più piacevole e molto meno rischiosa:

  • Riscrivi il membro month per indicare che ora è a base zero
  • Modifica set_month() e get_month() per eseguire l'aritmetica da convertire in / da uno a zero in base a come in / out
  • Verifica i metodi modificati per la correttezza
  • Aggiungi e verifica i metodi per eseguire operazioni basate su zero su month in modo che la nuova versione della funzione critica possa utilizzarli

La classe ora appare così:

class Date {
      ...
    private int month;  // Month of year, 0 = January
      ...
    // These methods operate on the month as a 1-based value and
    // are the ones all of the existing code uses.
    void set_month(int new_month) { month = new_month - 1; }
    int  get_month() { return month + 1; }

    // New methods that operate on the month as a 0-based value
    void set_month_zero(int new_month) { month = new_month; }
    int  get_month_zero() { return month; }
}

La chiave qui è, ancora una volta, che nulla al di fuori della classe sa nulla su come il mese è memorizzato o anche se è memorizzato del tutto. Tutto ciò che vedono sono due metodi chiamati set_month() e get_month() che devono essere utilizzati per memorizzare o recuperare il valore basato su uno. Finché le nuove implementazioni di questi metodi possono essere dimostrate come si comportano come sempre, non è necessario toccare le migliaia di righe di codice che le utilizzano. La funzione critica può utilizzare i nuovi metodi set_month_zero() e get_month_zero() per eseguire una manipolazione a base zero del mese.

    
risposta data 29.11.2014 - 17:35
fonte
1

Come? Bene, rendendolo pubblico e scrivibile.

La rappresentazione dei dati in questo caso è un valore int per ogni componente Date, ma noterai che questa non è una scelta particolarmente appropriata - i numeri dei giorni non vanno da -2.147.483.648 a 2.147.483.647, vanno da Da 1 a 31. Il punto non è tanto mantenere un segreto dai client API che il numero del giorno è memorizzato come un "int" ma per impedirgli di invocare il rappresentativo completo potenza di int durante la manipolazione di Date .

Con i campi pubblici, ogni utente della classe ha tanto potere sui valori quanto lo scrittore della classe: il potere assoluto. In particolare, possono impostare valori privi di senso (es. DayOfMonth = 50) o valori che sono di per sé fini ma in conflitto con altri valori (dayOfMonth = 31, month = 2), o valori che sono ancora più sottilmente errati (dayOfMonth = 29, month = 2, anno = 2001). Questo tipo di restrizione dei possibili valori e combinazioni di valori è esattamente ciò per cui la classe è idealmente adatta, ma può fare il suo lavoro solo se nessun altro ha lo stesso potere. Ecco perché è una buona idea avere un metodo advanceDay() invece dei campi pubblicamente scrivibili.

    
risposta data 28.11.2014 - 10:18
fonte

Leggi altre domande sui tag