La Coding Guidelines specifica le regole che devono essere applicate per scrivere il codice rispettando determinati criteri di sintassi e di forma.
La Naming Guidelines rappresenta un sottoinsieme della Coding Guidelines e si focalizza nel descrivere le linee guida sulla nomenclatura dei membri(classi, interfacce, ...)
La necessità di avere delle regole comuni sulle modalità di scrittura del codice non è una novità introdotta con i nuovi linguaggi del Framework .Net.
Per esempio la Notazione Ungherese è stata ed è ancora oggi una delle pratiche più conosciute dalle comunità di sviluppatori.
Con l'introduzione del Framework .Net, Microsoft ha ideato una nuova modalità di nomenclatura del codice, più adatta ai nuovi linguaggi(completamente object-oriented) e più adatta ai nuovi tools di sviluppo(supporto avanzato intellisense).
Queste regole non devono essere considerate le linee guida da utilizzarsi per la stesura di codice in generale, ma dovrebbero essere applicate in questi casi :
per qualsiasi membro pubblicamente esposto (publicy exposed identifiers)
in generale per tutte quelle parti di codice che sono documentate
L’obiettivo è quello di fornire alla comunità di sviluppatori un unica modalità di pubblicazione delle parti pubbliche di componenti e librerie in modo da garantirne la consistenza con il resto del Framework .Net.
Naming Convention
Si definiscono Pascal Cased i nomi che hanno le iniziali maiuscole (es. RegisterClientScriptCallBack)
Sono Camel Cased i nome che hanno l’iniziale della prima parola minuscola e le iniziali delle rimanenti parole maiuscole (es. httpContext )
Le linee guida da applicare sono :
Tutti i tipi e membri pubblici devono essere Pascal Cased (i membri “protected” fanno parte dei membri pubblici)
class MyClass {
public string ClassName { ... }
protected string GetClassName() { ... }
}
I parametri devono essere Camel Cased
public void LoadData(int objectId) { ... }
Gli acronimi sono gestiti All Cased se di 2 caratteri, Pascal Cased altrimenti
public int ID;
public string Html;
Non è permesso l’utilizzo della Notazione Ungherese
int iObjectId;
string strText;
Identifiers
Nella definizione dei nomi di metodi, eventi e proprietà con modificatori di accesso public, protected o internal :
Non usare gli underscores (_)
Non usare parole tutte maiuscole o tutte minuscole
Non usare la Notazione Ungherese
Usare i nomi al plurale per metodi e proprietà che ritornano collections o array
public MemberCollection GetMembers();
public Member GetMember()
Utilizzare il prefisso "Is", "Has" o "Can" nel caso di metodi che restituiscono un boolean
public boolean IsMemberOfTeam();
public boolean HasRows();
public boolean CanWrite();
Identificatori dei controlli visuali
Per denominare i controlli nei WebForm delle applicazioni ASP.NET e nei WinForm delle applicazioni Windows conviene utilizzare una notazione come quella ungherese oppure no?
Se si quale notazione usare?
Personalmente adotto una notazione ungherese ossia aggiungo un prefisso di 3 caratteri in minuscolo, in alcuni casi i caratteri sono 4, trovo questa notazione conveniente per i soli controlli visuali privati, qualora per qualche ragione fossero pubblici preferisco usare le convensioni nella class library (ossia un nome in Pascal Case). Quindi lblFirstName e non LblFirstName o FirstName -- LucaMinudel [2005-12-19]
Anch'io uso la notazione ungherese per i controlli visuali privati, così come Luca. Il pregio più evidente è sicuramente quello di avere una certa immediatezza nell'individuare il tipo di controllo che si sta usando. E' anche vero che se durante lo sviluppo ci si accorge che quel controllo non va più bene (ad esempio una textbox deve diventare una combobox), diventa leggermente difficoltoso adeguare il codice (anche se un "replace in current document" è provvidenziale). -- FabioCozzolino [2005-12-19]
Sono d'accordo per il discorso dei controlli dichiarati come privati, ma molto spesso sono definiti protetti, quindi bisognerebbe seguire la sintassi Pascal Case. Detto questo una convenzione non è una legge e quindi può anche accettare delle piccole deroghe. Però aggiungerei un ulteriore elemento di pensiero, cioè spostare l'attenzione del prefisso dal controllo alla sua funzione (statico, in sola lettura, in sola scrittura o in lettura e scrittura). Ciò slegherebbe la proprietà/il campo dalla natura del controllo lasciando la libertà di poterlo cambiare (vedi InfoPath) -- PierreGreborio [2005-12-19]
Pierre quando dici "spostare l'attenzione del prefisso dal controllo alla sua funzione" penso possa essere una utile astrazione per aiutare il programmatore e per facilitare l'impatto della sostituzione come dice Fabio. Essendo patito x le astrazioni ho applicato questa tecnica (nomi astratti slegati dal tipo in questo caso ad esempio TextBox o Label) e non ho ottenuto i due benefici (astrazione x il programmatore e sostituzione più facile) che credevo quando l'ho applicato ad oggetti del framework (cioè che stannno ad un livello di astrazione di implementazione e non del dominio applicativo) perchè come programmatore alla fine mi è stato di maggior aiuto conoscere esattamente il tipo dell'oggetto che sto usando e l'astrazione diventa quindi d'impaccio, se devo sostituire l'oggetto ho ancora più bisogno di conoscere il tipo per garantire che il cambiamento non causi bug. Un esempio pratico che probabilmente hai già affrontato, creando per WSE uno UserToken e relativo manager x gestire autenticazione Form ho provato in entrambi i modi e introducendo l'astrazione il codice era decisamente meno chiaro -- LucaMinudel [2005-12-19]
Io seguo la linea di Pierre. Perchè per i controlli ha senso la notazione ungherese e per i tipi base non si ha questa esigenza? In fondo, la funzione del prefisso è quella di identificare il tipo del membro. Io una variabile chiamata strFirstName faccio fatica a immaginarla. -- GianlucaCarucci [2005-12-19]
"Perchè per i controlli ha senso la notazione ungherese e per i tipi base non si ha questa esigenza?" solitamente per un tipo base, il tipo deriva "automaticamente" dalla semantica del tipo (es. nomeCliente è una stringa) mentre una stessa informazione può essere rappresentata con controlli diverse. -- LucaMinudel [2005-12-19]
"il tipo deriva "automaticamente" dalla semantica del tipo" non è sempre così, anzi in c++ ad esempio non lo è mai. nomeCliente potrebbe essere un tipo std::string, un BSTR, un CHAR*, un WCHAR* ... Ovvio, net semplifica (e risolve) questo caso specifico, ma l'ambiguità c'è ancora, ad esempio, nel caso delle collezioni (ArrayList, Dictionary, Stack). Quando leggo il codice conoscere il tipo del membro dal nome non aumenta il livello informativo del codice stesso (IMHO) -- GianlucaCarucci [2005-12-20]
Io uso la convenzione ProvaTextBox, ProvaLabel, ProvaDataGrid, etc... -- LorenzoBarbieri [2005-12-19]
"Perchè per i controlli ha senso la notazione ungherese e per i tipi base non si ha questa esigenza?" La notazione ungherese ti lega strettamente ad un tipo, una pratica deleteria, a mio parere, se usata in proprietà esposte (intendo tutte le non private). Personalmente evito il più possibile di esporre i controlli direttamente, di conseguenza l'applicazione della notazione ungherese mi comporta pochi problemi e diversi vantaggi soprattutto in termini di leggibilità del codice. I problemi (eventuali) si amplificano quando il controllo è protected, ma non credo che spostare la logica sulla funzione sia la soluzione, poichè le difficoltà si possono presentare anche quando decido di cambiare la funzione del controllo. La convenzione ProvaTextBox, ecc... proposta da Lorenzo la utilizzo per dichiarare i nomi delle classi derivate, dove aggiungo come suffisso il nome, o parte di esso, della classe base. -- FabioCozzolino [2005-12-20]
"vantaggi soprattutto in termini di leggibilità del codice" <provocazione>Non è che il fatto di sentire il bisogno di aggiungere un prefisso per il tipo è sintomo di non saper trovare un nome abbastanza esplicativo?</provocazione> -- GianlucaCarucci [2005-12-19]
La convenzione utilizzata da Lorenzo va per la maggiore all'estero (a quanto pare, vedi http://weblogs.asp.net/pgreborio/archive/2005/12/19/433517.aspx). Solitamente la uso per estendere i controlli e non per nominare i campi o le proprietà. Comunque, mi accorgo sempre di più che la convenzione converge nella lista che stiamo stilando anche se in chiara contraddizione con le guidelines ufficiali, che ripeto, non sono oro colato Però sono importanti soprattutto per il lavoro in team, dove se non usi una convenzione (almeno azienale) rischi di creare codice inmanutenibile. -- PierreGreborio [2005-12-20]
Uno dei motivi che spinge l'uso dei prefissi (o suffissi) nei controlli è la distinzione di essi anche nel caso in cui fanno riferimento allo stesso dato. Mi spiego meglio: se ho un web form per l'inserimento dei dati avrò sicuramente una label ed una textbox per l'inserimento del nome dell'utente. Come le chiamo? Una possibile risposta è: lblFirstName e txtFirstName. Probabilmente non è l'unica soluzione, forse neanche la migliore, ma è quella a cui siamo arrivati (io e i miei colleghi) dopo diverse valutazioni... -- FabioCozzolino [2005-12-20]
// errato
public class CPersona {...}
// corretto
public class Persona {...}
Usare il prefisso “I” per i nomi delle interfacce
public interface IPersona {...}
Utilizzare un nome composto per le classi derivate, aggiungendo come suffisso il nome, o parte del nome, della classe base
public class PersoneCollection : CollectionBase {...}
public class CustomEventArgs : EventArgs {...}
public class CustomException : Exception {...}
Le classi non hanno bisogno di essere identificate da un prefisso in quanto rappresentano la struttura di default di ogni applicazione realizzata con il .Net Framework.
Per le interfacce è invece necessario utilizzare il prefisso “I” in modo da distinguerle dalle classi.
E’ molto importante definire con accortezza anche i nomi che si vogliono assegnare ai membri pubblici di una classe che sarà esposta ed utilizzata da altri sviluppatori :
Usare nomi che abbiano un significato, che siano “parlanti”
Guardare se esistono nomi già utilizzati e conosciuti per quello che vogliamo descrivere
MyCollection.Count vs MyCollection.NumberOfElements
(la proprietà Count è usata in framework diversi ed
è facilmente riconoscibile dallo sviluppatore, non
occore un nome nuovo,in questo esempio NumberOfElements
per specificare il concetto)
Lorenzo Barbieri è Senior Consultant in ""ObjectWay"" (http://www.objectway.it), ha pluriennale esperienza nella realizzazione di progetti basati su architetture Microsoft. Laureato in Ingegneria Informatica al Politecnico di Milano, oggi si occupa dell'implementazione di soluzioni basate su Microsoft .NET e Windows Server System. E' Microsoft Certified Trainer, MCSD e MCDBA, autore di numerosi articoli per le principali riviste IT e speaker in corsi e conferenze in Italia e all'estero. '''Dal gennaio 2006 è Microsoft MVP nella categoria Windows - Virtual Machines'''