Non so dove provenga l'affermazione secondo cui "non esegue e spesso non è possibile eseguire un'analisi statica". La prima parte dell'asserzione è chiaramente sbagliata. Il secondo dipende da cosa intendi per "spesso". Direi piuttosto che spesso , esegue analisi statiche e raramente fallisce. Nelle normali applicazioni aziendali, raramente diventa molto più vicino a mai .
Quindi ecco qui, il primo vantaggio:
Vantaggio 1: analisi statica
Le asserzioni ordinarie e il controllo degli argomenti hanno uno svantaggio: vengono posticipate fino all'esecuzione del codice. D'altra parte, i contratti di codice si manifestano ad un livello molto più precoce, sia nella fase di codifica che durante la compilazione dell'applicazione. Prima si rileva un errore, meno costoso è ripararlo.
Vantaggio 2: sorta 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)
indica 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 che newPrice = 0
lanci un ArgumentOutOfRangeException
, ma non ha mai modificato la documentazione corrispondente. Data la correlazione tra i contratti di codice e il codice stesso, non hai il problema di documentazione non sincronizzato.
Il tipo di documentazione fornita dai contratti di codice è anche prezioso in un modo che spesso i commenti XML non spiegano bene i valori accettabili. Quante volte mi sono chiesto se null
o string.Empty
o \r\n
è un valore autorizzato per un metodo, e i commenti XML non hanno funzionato!
In conclusione, senza contratti di codice, molte parti di codice sono così:
I'll accept some values but not others, but you'll have to guess or read the documentation, if any. Actually, don't read the documentation: it's outdated. Simply loop through all values and you'll see the ones which make me throw exceptions. You also have to guess the range of values which may be returned, because even if I would tell a bit more to you about them, it may not be true, given the hundreds of changes made to me for the last years.
Con i contratti di codice diventa:
The title argument can be a non-null string with a length of 0..500. The integer which follows is a positive value, which can be zero only when the string is empty. Finally, I'll return a IDefinition
object, never 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();
...
}
In che modo, utilizzando solo le asserzioni e le eccezioni, puoi garantire che CommitChanges
possa essere chiamato solo quando PendingChanges
non è vuoto? Come garantiresti che PendingChanges
non sia mai null
?
Benefit 4: applica i risultati di un metodo
Infine, il quarto vantaggio consiste nel riuscire a Contract.Ensure
dei risultati. Cosa succede se, quando si scrive un metodo che restituisce un 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
s diventa un incubo di manutenzione per questo.
Considera i contratti di codice non solo come un mezzo di correttezza del codice, ma un modo più rigoroso di scrivere codice. In modo simile, una persona che ha utilizzato esclusivamente linguaggi dinamici può chiedere perché vorresti imporre tipi a livello linguistico, mentre puoi fare la stessa cosa nelle asserzioni quando necessario. Puoi farlo, ma la digitazione statica è più facile da usare, meno soggetta a errori rispetto a una serie di asserzioni e autodocumentazione.
La differenza tra digitazione dinamica e tipizzazione statica è estremamente vicina alla differenza tra programmazione ordinaria e programmazione per contratto.