back to top

Accorgimenti per la scrittura di codice efficiente in C#

Nella scrittura del codice delle proprie applicazioni uno sviluppatore dovrebbe sempre seguire standard di codifica e convenzioni, al fine di implementare algoritmi efficienti ed eventualmente comprensibili anche ad altri sviluppatori. Per questo motivo, nel presente articolo, vedremo alcuni semplici accorgimenti per la scrittura di codice efficiente in C#.

Partiamo da un semplice esempio, un programmino che scorre i numeri da 1 a 1000. Scorrendo i numeri per ogni multiplo di 3 restituisce il messaggio โ€˜Multiplo di 3โ€™, per ogni multiplo di 5 restituisce โ€˜Multiplo di 5โ€™ e per ogni multiplo di entrambi restituisce โ€˜Multiplo di 3 Multiplo di 5โ€™. Se non si verifica alcuna delle tre condizioni viene restituito semplicemente il numero corrente.

Pubblicitร 

Una possibile implementazione del metodo รจ la seguente

public void Test()
{
  for (int i = 1; i < 1001; i++)
  {
    if (i % 3 == 0 && i % 5 == 0)
    {
      Console.WriteLine("Multiplo di 3 Multiplo di 5");
    }
    else if (i % 3 == 0)
    {
      Console.WriteLine("Multiplo di 3");
    }
    else if (i % 5 == 0)
    {
      Console.WriteLine("Multiplo di 5");
    }
    else
    {
      Console.WriteLine(i);
    }
  }
}

Ovviamente il metodo fa quello che ci siamo prefissati ma potremmo scrivere il tutto nel modo seguente

public void Test2()
{
  for (int i = 1; i <= 1000; i++)
  {
    string output = "";

    if (i % 3 == 0) { output = "Multiplo di 3"; }
    if (i % 5 == 0) { output = output + " Multiplo di 5"; }
    if (output == "") { output = i.ToString(); }
    Console.WriteLine(output);
  }
}

Vi sembrano abbastanza comprensibili?

Uno dei problemi fondamentali della programmazione รจ dare il giusto (nel senso di comprensibile ed appropriato) nome agli elementi che compongono le applicazioni. Uno sviluppatore tipicamente si trova a dover dare un nome a proprietร , metodi, classi, file, progetti e tante altre cose. Pur essendo unโ€™attivitร  che richiede del tempo, si dovrebbe sempre dedicare il giusto tempo ad essa perchรฉ utilizzare i nomi giusti rende il codice piรน leggibile e comprensibile.

Lo stesso risultato dei due esempi precedenti possiamo ottenerlo scrivendo il seguente codice

public void EseguiTest()
{
  for (int numero = 1; numero <= 1000; numero++)
  {
    var output = Test3(numero);
    Console.WriteLine(output);
  }
}

private static string Test3(int numero)
{
  string output = string.Empty;

  if (numero % 3 == 0)
  {
    output = "Multiplo di 3";
  }
  if (numero % 5 == 0)
  {
    output += " Multiplo di 5";
  }
  if (string.IsNullOrEmpty(output))
  {
    output = numero.ToString();
  }
  return output;
}

Eโ€™ piรน comprensibile dei due casi precedenti?

Il codice prima di tutto deve essere scritto per le persone (intese come altri programmatori) e solo dopo per le macchine. Un codice leggibile non richiede molto tempo per essere compreso, al contrario di un codice poco chiaro. Spesso gli sviluppatori programmano senza tenere conto che il proprio codice potrร  essere letto da altri per vari motivi: per correggere un errore, per effettuare modifiche, per provare ad utilizzarne parte in un progetto simile, ecc.

A parte queste motivazioni, scrivere codice leggibile serve anche in primis a chi lo scrive. Coloro che lavorano in realtร  in cui ogni una o due settimane si passa allโ€™implementazione di un progetto nuovo saprร  che dopo un certo periodo di tempo i dettagli dei progetti precedenti fisiologicamente vengono in parte dimenticati.

Quindi quando si riprende un vecchio progetto trovarsi di fronte ad un codice confuso e poco leggibile farร  soltanto perdere tempo prezioso, perchรฉ ci costringerร  a ricostruire cosa fa quel codice. Al contrario un codice ben scritto (e ben commentato aggiungo) ci richiederร  uno sforzo iniziale, ma ci permetterร  di ricordare facilmente tutti i dettagli dello stesso, aumentando anche la nostra produttivitร .

Ma come si puรฒ valutare la leggibilitร  di un codice? Il primo consiglio che vi do รจ leggere il codice scritto da altri sviluppatori e capire cosa รจ chiaro e cosa non lo รจ in esso. Le cose che vi sembrano piรน comprensibili provate ad applicarle al vostro modo di scrivere codice, quelle poco chiare no. Chiaramente poi รจ necessaria una certa esperienza per migliorare in questo ambito, nessuno sviluppatore con esperienza scrive lo stesso codice che scriveva allโ€™inizio della sua carriera.

Esistono anche alcuni tool che permettono di valutare la leggibilitร  del codice e tra questi citiamo:

  • FxCop: strumento che effettua unโ€™analisi statica del codice .NET e consente vari tipi di valutazioni.
  • StyleCop: progetto open source che analizza il codice sorgente C# forzando una serie di regole di stile e consistenza. Esso puรฒ essere utilizzato anche allโ€™interno di Visual Studio.
  • JetBrains ReSharper: strumento di produttivitร  che migliora molto lโ€™esperienza di programmazione in Visual Studio, mettendo a disposizione tantissime utili funzionalitร .

Passiamo adesso alle convenzioni, termine con cui si designa un insieme di linee guida relative ad un linguaggio di programmazione. Esse riguardano indentazione, commenti, dichiarazioni, istruzioni, assegnazione dei nomi, principi di programmazione, ecc. Agli sviluppatori รจ fortemente raccomandato seguire tali linee guida per migliorare la leggibilitร  del proprio codice e quindi facilitare la manutenzione del software.

Tra le varie convenzioni una molto importante รจ quella relativa allโ€™utilizzo delle lettere maiuscole nellโ€™assegnazione dei nomi agli elementi (si parla di capitalization, da capital letter ovvero lettera maiuscola). Una proprietร , una variabile, il nome di un metodo o di una classe dovrebbero essere scelti tenendo conto di alcune convenzioni.

In particolare si parla di Pascal Casing e Camel Casing. Nel primo caso la in un identificatore la prima lettera in assoluto e la prima lettera di ogni parola concatenata sono maiuscole, nel secondo caso la prima lettera in assoluto รจ minuscola e la prima lettera di ogni parola concatenata รจ maiuscola. Microsoft consiglia lโ€™utilizzo del Camel per i parametri e le variabili locali e del Pascal per classi, eventi, metodi, proprietร , ecc.

Vediamo alcuni accorgimenti su capitalization e altro:

Utilizzare il Pascal per gli identificatori di classi e nomi di metodi

public class Dipendenti
{
  public void EstraiDipendenti()
  {
    //...
  }
  public void CalcolaCostoDipendenti()
  {
    //...
  }
}

Utilizzare il Camel per gli argomenti di un metodo e come identificatori di variabili locali

public class CategorieDipendenti
{
  public void Salva(CategorieDipendenti categoriaDipendente)
  {
    string codiceAzienda;
    // ...
  }
}  

Non utilizzare abbreviazioni

//Consigliato
CategorieDipendenti categoriaDipendente;

//Sconsigliato
CategorieDipendenti catDip;

Non utilizzare il trattino basso (underscore) negli identificatori

//Consigliato
CategorieDipendenti categoriaDipendente;

//Sconsigliato
CategorieDipendenti categoria_Dipendente;

Dichiarare tutte le variabili allโ€™inizio di una classe, con le variabili statiche prima di tutte le altre

public class Dipendenti
{
  public static string Cognome;
  public static string Nome;

  public string Sesso { get; set; }
  public DateTime DataAssunzione { get; set; }

  public Dipendenti()
  {
    // ...
  }
}

Utilizzare nomi al singolare per gli enum e non utilizzare il suffisso โ€˜Enumโ€™

//Consigliato
public enum Ruolo
{
  Operaio,
  Amministrativo,
  Dirigente
}

//Sconsigliato
public enum Ruoli
{
  Operaio,
  Amministrativo,
  Dirigente
}

//Sconsigliato
public enum RuoloEnum
{
  Operaio,
  Amministrativo,
  Dirigente
}

Le convenzioni comportano diversi vantaggi, in particolare stabilendo dallโ€™inizio le regole per la definizione degli identificatori รจ possibile concentrarsi su aspetti funzionali piรน importanti del codice.

Un altro consiglio per la scrittura di codice leggibile ed efficiente riguarda le dimensioni delle classi. Spesso infatti capita di vedere (o implementare) classi veramente molto estese. Questo non va bene perchรฉ classi di questo tipo cercano di effettuare troppe cose diverse. Un principio molto importante (principio di singola responsabilitร ) sostiene che ogni classe dovrebbe avere una singola responsabilitร  e tale responsabilitร  dovrebbe essere incapsulata nella classe.

Un esempio su questo aspetto che circola in rete รจ il seguente:

Si consideri un modulo che compila e stampa un report. Tale modulo puรฒ cambiare per due motivi. In primo luogo il contenuto del report puรฒ cambiare. In secondo luogo il formato del report puรฒ cambiare. Queste due cose cambiano per cause molto diverse: uno sostanziale e uno estetico. Il principio di singola responsabilitร  afferma che questi due aspetti del problema sono in realtร  due responsabilitร  distinte e dovrebbero quindi essere descritte in classi o moduli separati. Sarebbe cattiva progettazione accoppiare due cose che cambiano, per motivi diversi in momenti diversi. Se vi รจ un cambiamento nel processo di compilazione del report, ci saranno maggiori probabilitร  che il codice per la stampa fallisca se si trova nella stessa classe.

Quindi in sintesi se una classe ha piรน di una responsabilitร , queste risultano legate tra di loro e la modifica di un elemento relativo ad una delle responsabilitร  potrebbe avere conseguenze sul funzionamento di altre responsabilitร , che invece dovrebbero essere indipendenti dalla prima.

Altro aspetto da considerare nella scrittura del codice sono i commenti. Questi sono spesso molto importanti per la comprensione del codice ma non bisogna abusarne. Bisognerebbe, ad esempio, evitare commenti su singoli metodi o piccole classi perchรฉ in questi casi il nome del metodo o della classe dovrebbero giร  avere un significato ben preciso se scelti bene e non dovrebbero necessitare di commenti.

Questo non significa che i commenti non siano importanti ma รจ consigliabile scriverli a livello di applicazione complessiva non a livello dei singoli metodi. Un codice troppo commentato probabilmente รจ un cattivo codice perchรฉ necessita di troppe spiegazioni per essere comprensibile da altri.

Passiamo adesso ai metodi. La maggior parte di sviluppatori con esperienza raccomanda che la lunghezza di un metodo non dovrebbe mai superare le 20-25 linee di codice. Quindi quando un metodo supera questo limite o necessita di troppi commenti per essere compreso รจ il momento di chiedersi se non sia meglio suddividerlo in piรน parti.

Visual Studio mette a disposizione una utile funzionalitร  denominata โ€˜Extract Methodโ€™ che consente di selezionare una porzione di codice ed inglobarla in un metodo esterno a quello in cui si trovava

Altro aspetto da considerare รจ che quando si opera su metodi molto lunghi e complessi tenere traccia di tutte le variabili locali puรฒ essere complicato e dispendioso in termini temporali.

Anche il numero di parametri รจ importante. Quando in un metodo si arrivano ad inserire troppi parametri bisogna valutare se non sia meglio creare una classe che mette tutti questi parametri assieme e poi passare come parametro del metodo unโ€™istanza di tale classe

//Sconsigliato
public void Spedizione(string nomeDestinatario,string cittaDestinatario, 
string statoDestinatario,string codicePostaleDestinatario, 
string telefonoDestinatario)
{
}

//Consigliato
public void Spedizione(Destinatario destinatario)
{
}  

Nel caso precedente abbiamo sostituito cinque parametri con un solo parametro corrispondente ad una classe che contiene cinque proprietร  corrispondenti ai parametri del primo metodo.

Spesso mentre scriviamo codice riscontriamo dei warning ma siccome non sono bloccanti nella quasi totalitร  dei casi essi finiscono per essere ignorati. Un caso tipico รจ la dichiarazione di una variabile che poi non viene utilizzata allโ€™interno del codice

Eโ€™ consigliabile rimuovere dal codice oltre agli errori anche i warning e per essere in qualche modo โ€˜costrettiโ€™ a farlo รจ possibile impostare Visual Studio in modo da bloccare la compilazione del nostro codice anche se sono presenti solo warning.

Basta accedere alle proprietร  del progetto e selezionare la scheda Build

In questa scheda รจ presente una sezione denominata โ€˜Treat warnings as errorsโ€™ con il valore predefinito None. Tutto quello che dobbiamo fare รจ impostare il valore All e quello che in precedenza ci compariva come warning comparirร  come errore

Nel presente articolo abbiamo analizzato alcuni semplici ma efficaci accorgimenti per rendere il nostro codice piรน efficiente e leggibile. Ovviamente รจ possibile adottare tanti altri accorgimenti che vanno in questa direzione e che probabilmente saranno oggetto di futuri articoli, ma mettere in pratica quelli che abbiamo qui descritto rappresenta un primo ed importante passo verso la scrittura di codice leggibile ed efficiente.

Altri contenuti interessanti

Pubblicitร 

Leggi anche...

Vibe Coding: cosโ€™รจ, come funziona e quali sono i migliori strumenti AI per programmare

Immagina di poter scrivere software senza dover digitare una...

I migliori libri per imparare a programmare in Python

Imparare a programmare in Python รจ un passo fondamentale...

Il file manifest.json: cosโ€™รจ e a cosa serve

Il file manifest.json รจ un componente chiave nelle applicazioni web moderne,...

Java: cosโ€™รจ e a cosa serve lโ€™operatore modulo (%)

In Java, l'operatore modulo รจ rappresentato dal simbolo "%"...

Radice quadrata in C: vediamo come calcolarla in diversi modi

La radice quadrata รจ un'operazione matematica piuttosto comune (in...

Sperimentare la sequenza di Collatz in C++

Vediamo come verificare la congettura di Collatz con C++....
Pubblicitร