null
L'utilizzo dipende dall'applicazione / dalla lingua
In definitiva, la scelta se utilizzare o meno null
un valore applicativo valido è in gran parte determinata dall'applicazione e dal linguaggio / interfaccia / edge di programmazione.
A livello fondamentale, consiglierei di provare a usare tipi distinti se ci sono classi distinte di valori. null
potrebbe essere un'opzione se la tua interfaccia lo consente e ci sono solo due classi di una proprietà che stai tentando di rappresentare. L'omissione di una proprietà può essere un'opzione se l'interfaccia o il formato lo consentono. Un nuovo tipo aggregato (classe, oggetto, tipo di messaggio) può essere un'altra opzione.
Per il tuo esempio di stringa, se questo è nel linguaggio di programmazione, mi farei un paio di domande.
- Ho intenzione di aggiungere futuri tipi di valori? In tal caso,
Option
probabilmente sarà meglio per la progettazione dell'interfaccia.
- Quando devo convalidare le chiamate dei consumatori? Staticamente? Dinamicamente? Prima? Dopo? Affatto? Se il tuo linguaggio di programmazione lo supporta, utilizza i vantaggi della digitazione statica poiché evita la quantità di codice che devi creare per la convalida.
Option
probabilmente riempie meglio questo caso se la stringa non era nulla. Tuttavia, probabilmente dovrai comunque verificare l'input dell'utente per un null
valore stringa, quindi probabilmente rinvierei alla prima riga di domande: quanti tipi di valori fare / vorrò rappresentare.
- È
null
indicativo di un errore del programmatore nel mio linguaggio di programmazione? Sfortunatamente, null
è spesso il valore predefinito per puntatori o riferimenti non inizializzati (o non esplicitamente inizializzati) in alcune lingue. È null
accettabile un valore come valore predefinito? È sicuro come valore predefinito? A volte null
è indicativo di valori deallocati. Devo fornire ai consumatori della mia interfaccia un'indicazione di questi potenziali problemi di gestione della memoria o di inizializzazione nel loro programma? Qual è la modalità di fallimento di una tale chiamata di fronte a tali problemi? Il chiamante è nello stesso processo o thread del mio in modo che tali errori rappresentino un rischio elevato per la mia applicazione?
A seconda delle risposte a queste domande, probabilmente sarai in grado di capire se null
è giusto o meno per la tua interfaccia.
Esempio 1
- L'applicazione è fondamentale per la sicurezza
- Stai utilizzando un tipo di inizializzazione dell'heap all'avvio ed
null
è un possibile valore di stringa restituito in caso di errore nell'allocazione dello spazio per una stringa.
- C'è un potenziale che una tale stringa colpisca la tua interfaccia
Risposta: null
probabilmente non è appropriato
Motivazione: null
in questo caso viene effettivamente utilizzato per indicare due diversi tipi di valori. Il primo potrebbe essere un valore predefinito che l'utente della tua interfaccia potrebbe voler impostare. Sfortunatamente, il secondo valore è un flag per indicare che il sistema non funziona correttamente. In questi casi, probabilmente vuoi fallire nel modo più sicuro possibile (qualunque cosa ciò significhi per il tuo sistema).
Esempio 2
- Stai usando una C struct che ha un
char *
membro.
- Il tuo sistema non utilizza l'allocazione dell'heap e stai utilizzando il controllo MISRA.
- L'interfaccia accetta questa struttura come puntatore e verifica che la struttura non punti
NULL
- Il valore predefinito e sicuro del
char *
membro per la tua API può essere indicato da un singolo valore diNULL
- Dopo l'inizializzazione della struttura dell'utente, si desidera offrire all'utente la possibilità di non inizializzare esplicitamente il
char *
membro.
Risposta: NULL
può essere appropriato
Motivazione: C'è una piccola possibilità che la tua struttura passi il NULL
controllo ma non è inizializzata. Tuttavia, l'API potrebbe non essere in grado di tenerne conto a meno che non si disponga di una sorta di checksum sul valore della struttura e / o sul controllo dell'intervallo dell'indirizzo della struttura. Le linter MISRA-C possono aiutare gli utenti dell'API segnalando l'utilizzo delle strutture prima della loro inizializzazione. Tuttavia, per quanto riguarda il char *
membro, se il puntatore a struct punta a una struttura inizializzata, NULL
è il valore predefinito di un membro non specificato in un inizializzatore di struttura. Pertanto, NULL
può fungere da valore predefinito sicuro per il char *
membro struct nell'applicazione.
Se si trova su un'interfaccia di serializzazione, mi porrei le seguenti domande sull'opportunità di utilizzare null su una stringa.
- È
null
indicativo di un potenziale errore lato client? Per JSON in JavaScript, questo è probabilmente un no poiché null
non è necessariamente utilizzato come indicazione di errore di allocazione. In JavaScript, viene utilizzato come indicazione esplicita dell'assenza di un oggetto da un riferimento da impostare in modo problematico. Tuttavia, esistono parser e serializzatori non javascript che associano JSON null
al null
tipo nativo . In questo caso, ciò porta alla discussione se l' null
uso nativo sia o meno corretto per la tua particolare combinazione di lingua, parser e serializzatore.
- L'assenza esplicita di un valore di proprietà influisce più di un singolo valore di proprietà? A volte a
null
sta effettivamente indicando che hai un nuovo tipo di messaggio interamente. Potrebbe essere più pulito per i tuoi consumatori il formato di serializzazione semplicemente specificare un tipo di messaggio completamente diverso. Ciò garantisce che la loro convalida e la logica dell'applicazione possano avere una netta separazione tra le due distinzioni di messaggi fornite dalla tua interfaccia web.
Consiglio generale
null
non può essere un valore su un bordo o un'interfaccia che non lo supporta. Se stai usando qualcosa di estremamente sciolto nella tipizzazione dei valori delle proprietà (ad es. JSON), prova a spingere qualche forma di schema o convalida sul software per i consumatori (ad es. JSON Schema ) se puoi. Se si tratta di un'API del linguaggio di programmazione, convalida l'immissione dell'utente se possibile (tramite la digitazione) o il livello di rumorosità che è ragionevole in fase di esecuzione (ovvero pratica la programmazione difensiva su interfacce rivolte al consumatore). Altrettanto importante, documentare o definire il bordo in modo che non ci siano dubbi su:
- Che tipo (i) di valore accetta una determinata proprietà
- Quali intervalli di valori sono validi per una determinata proprietà.
- Come dovrebbe essere strutturato un tipo aggregato. Quali proprietà devono / dovrebbero / possono essere presenti in un tipo aggregato?
- Se si tratta di un tipo di contenitore, quanti elementi possono o devono contenere il contenitore e quali sono i tipi di valori contenuti nel contenitore?
- In quale ordine vengono restituite le proprietà o le istanze di un tipo contenitore o aggregati?
- Quali sono gli effetti collaterali dell'impostazione di valori particolari e quali sono gli effetti collaterali della lettura di tali valori?