Non so da dove provenga l'affermazione secondo cui "non è e spesso non può eseguire un'analisi statica". La prima parte dell'asserzione è chiaramente sbagliata. Il secondo dipende da cosa intendi per "spesso". Preferirei dire che spesso esegue analisi statiche e raramente fallisce. Nell'applicazione aziendale ordinaria, raramente diventa molto più vicino a mai .
Quindi ecco che arriva, il primo vantaggio:
Vantaggio 1: analisi statica
Le asserzioni ordinarie e il controllo degli argomenti presentano uno svantaggio: vengono posticipati fino all'esecuzione del codice. D'altro canto, i contratti di codice si manifestano a un livello molto precedente, sia durante la fase di codifica sia durante la compilazione dell'applicazione. Prima si rileva un errore, meno costoso è risolverlo.
Vantaggio 2: una specie di documentazione sempre aggiornata
I contratti di codice forniscono anche una sorta di documentazione che è sempre aggiornata. Se il commento XML del metodo SetProductPrice(int newPrice)
dice che newPrice
dovrebbe essere superiore o uguale a zero, potresti sperare che la documentazione sia aggiornata, ma potresti anche scoprire che qualcuno ha cambiato il metodo in modo da newPrice = 0
lanciare un ArgumentOutOfRangeException
, ma non ha mai cambiato la documentazione corrispondente. Data la correlazione tra i contratti di codice e il codice stesso, non si ha il problema della documentazione non sincronizzata.
Anche il tipo di documentazione fornita dai contratti di codice è prezioso in un modo che spesso i commenti XML non spiegano bene i valori accettabili. Quante volte mi chiedevo se null
o string.Empty
o \r\n
è un valore autorizzato per un metodo, e i commenti XML sono rimasti in silenzio su questo!
In conclusione, senza contratti di codice, molti pezzi di codice sono così:
Accetterò alcuni valori ma non altri, ma dovrai indovinare o leggere la documentazione, se presente. In realtà, non leggere la documentazione: è obsoleta. Basta scorrere tutti i valori e vedrai quelli che mi fanno generare eccezioni. Devi anche indovinare l'intervallo di valori che possono essere restituiti, perché anche se ti dico un po 'di più su di loro, potrebbe non essere vero, date le centinaia di modifiche apportate a me negli ultimi anni.
Con i contratti di codice, diventa:
L'argomento title può essere una stringa non nulla con una lunghezza di 0..500. L'intero che segue è un valore positivo, che può essere zero solo quando la stringa è vuota. Infine, restituirò un IDefinition
oggetto, mai null.
Vantaggio 3: contratti di interfacce
Un terzo vantaggio è che i contratti di codice potenziano le interfacce. Diciamo che hai qualcosa del tipo:
public interface ICommittable
{
public ICollection<AtomicChange> PendingChanges { get; }
public void CommitChanges();
...
}
Come garantiresti che, usando solo asserzioni ed eccezioni, CommitChanges
possa essere chiamato solo quando PendingChanges
non è vuoto? Come garantiresti che PendingChanges
non lo sia mai null
?
Vantaggio 4: applicare i risultati di un metodo
Infine, il quarto vantaggio è essere in grado di ottenere Contract.Ensure
i risultati. Cosa succede se, quando si scrive un metodo che restituisce un numero intero, voglio essere sicuro che il valore non sia mai inferiore o uguale a zero? Di cui cinque anni dopo, dopo aver subito molti cambiamenti da molti sviluppatori? Non appena un metodo ha più punti di ritorno, Assert
diventa un incubo per la manutenzione.
Considera i contratti di codice non solo come mezzo di correttezza del tuo codice, ma un modo più rigoroso per scrivere il codice. Allo stesso modo, una persona che ha usato linguaggi esclusivamente dinamici potrebbe chiedersi perché dovresti applicare i tipi a livello linguistico, mentre puoi fare la stessa cosa in asserzioni quando necessario. Puoi, ma la digitazione statica è più facile da usare, meno soggetta a errori rispetto a una serie di affermazioni e autodocumentazione.
La differenza tra la tipizzazione dinamica e la tipizzazione statica è estremamente vicina alla differenza tra la programmazione ordinaria e la programmazione per contratto.