Tenendo i dati mutabili in un'unica posizione

6

Dato una proprietà mutable , generalmente ha senso tenere / archiviare quella proprietà in un unico posto . Quando i dati devono essere modificati, devi solo aggiornare un singolo campo e puoi evitare completamente i bug in cui i diversi campi non vengono sincronizzati.

Un esempio estremamente semplice potrebbe essere:

L'approccio "giusto":

class Owner {
    String name;
}

class Dog {
    Owner owner;

    String getOwnersName() {
        return owner.name;
    }
}

L'approccio "sbagliato":

class Owner {
    String name;
}

class Dog {
    Owner owner;
    String ownerName;

    String getOwnersName() {
        return ownerName;
    }
}

L'esperienza mi ha insegnato che raramente è una buona idea rompere questa regola. Il rischio di introduzione di bug e il maggiore sforzo richiesto per comprendere il codice quasi sempre superano qualsiasi vantaggio.

La mia domanda è, c'è un nome per questa regola / principio?

Punti bonus per il collegamento a articoli / blog / ecc. che rendono chiaramente l'argomento per questo. Doppi punti bonus per contro-argomenti!

    
posta vaughandroid 16.01.2013 - 15:38
fonte

3 risposte

7

Si chiama Single Source of Truth . Per quanto riguarda le contro-argomentazioni, l'articolo evidenzia il suo principale svantaggio, che è il ridimensionamento delle difficoltà. Tuttavia, anche in sistemi distribuiti di grandi dimensioni, si desidera avere un'unica fonte di verità localmente.

    
risposta data 16.01.2013 - 16:34
fonte
3

Questo è un aspetto di Non ripeterti , e probabilmente il singolo meta-principio più importante di programmazione per computer.

    
risposta data 16.01.2013 - 15:52
fonte
3

Le persone del database lo chiamano Normalizzazione . I buoni progetti di sistema tendono a iniziare solo con dati normalizzati e fanno solo eccezioni, se necessario.

Un contro-esempio non menzionato nell'articolo di normalizzazione è la programmazione concorrente. Quando due o più processi accedono allo stesso pezzo di dati mutabili, ci sono tutti i tipi di problemi in cui il processo A inizia una lettura, quindi il processo B esegue una scrittura, quale valore processa A letto? Quello vecchio o quello nuovo? Se i tuoi dati sono un oggetto complesso, A può ottenere un puntatore a un nuovo oggetto, ma non inizializzato e iniziare a usarlo prima che sia completamente creato.

Quando devi condividere dati mutabili tra i processi, spesso è meglio rendere copie difensive dei tuoi dati. In questo modo process A può garantire completamente che il processo B legga un valore corretto, completamente inizializzato e che il processo B non possa quindi modificare accidentalmente o intenzionalmente il valore dei dati di A (o viceversa).

Questa è la ragione per cui Java ha la convenzione di usare quei fastidiosi metodi get / set. Se esponi un campo con un get / set, successivamente scopri un problema in cui un client della tua classe sta cambiando il comportamento sottostante della tua classe in un modo non sicuro, quindi senza modificare l'interfaccia della tua classe puoi:

  • Rendi immutabili i dati sottostanti
  • Restituisce una copia difensiva dal metodo get ()
  • Aggiungi la sincronizzazione ai metodi get / set

I dati immutabili sono la soluzione più semplice e affidabile quando è pratico progettare la classe in modo che i dati in essa contenuti non cambino. Se l'oggetto ha un piccolo ingombro di memoria e non verrà creato così tante volte da riempire la memoria con piccole copie di se stesso, allora una copia difensiva è probabilmente più efficiente della sincronizzazione. Se l'oggetto sottostante è costoso da creare, ha un ingombro di memoria di grandi dimensioni, o deve essere creato così tante volte da riempire la memoria rapidamente, quindi la sincronizzazione potrebbe essere migliore delle copie difensive.

Linguaggi più recenti come Ruby e Scala generano metodi get / set impliciti per te in modo tale che sembra che tu stia accedendo direttamente ai campi, ma puoi in seguito sovrascrivere i metodi get / set predefiniti come descritto sopra. I linguaggi funzionali come Scala, Clojure o Haskell presuppongono che tutti i dati siano immutabili, a meno che non si specifichi diversamente.

Anche all'interno di un singolo processo è molto semplice passare myObject a diversi metodi o usarlo su diverse pagine di codice all'interno della stessa procedura e in un posto si imposta myObject.color = BLUE e da qualche altra parte myObject.color = RED e ogni posto si aspetta che myObject mantenga il suo colore. È facile fare questo tipo di errore di programmazione ogni volta che il codice diventa abbastanza complicato.

    
risposta data 16.01.2013 - 16:10
fonte

Leggi altre domande sui tag