Standard di codifica Delphi![]()
ProjectOO
Ing. M.Planchestainer
https://members.tripod.com/mplank
4.PJST - Standard di codifica Delphi
Ver.1.00
Febbraio 1999
Questo documento rappresenta lo standard di codifica Delphi di ProjectOO realizzato sulla base dello standard Essedi [1].
Viene distribuito in forma gratuita, a condizione che venga citato il seguente riferimento:
M.Planchestainer Standard di codifica Delphi ver.1.00 - https://members.tripod.com/mplank, 1999
Questa pagina è disponibile anche come file Acrobat a:
Standard di codifica ver100.zip
Come utilizzare questo documento
Questo documento descrive un possibile standard di codifica da utilizzare per progetti Delphi.
Un qualsiasi progetto software non banale necessita di regole ben precise che governino il lavoro di sviluppo. Stabilire uno standard di codifica permette di generare moduli che si interfacciano meglio, programmi più leggibili, prodotti più facilmente mantenibili. Lo standard di codifica può essere adottato a livello di un solo progetto, di un gruppo di progetti, di un cliente oppure genericamente di tutti gli elaborati di una software house.
Questo standard è aggiornato alla versione 4 di Delphi, tuttavia il carattere generico della maggior parte delle informazioni riportate permette di utilizzarlo anche per release precedenti dellambiente di sviluppo.
Deve essere modificato o personalizzato per le esigenze specifiche di ogni progetto o team di sviluppo.
Questo documento si basa sullo standard di codifica del progetto ERP-Fashion di Essedi [1], il quale a sua volta si è richiamato a Inprise [4], come si evince dalla VCL, e soprattutto a Pacheco, Teixeira [2].
Come utilizzare questo documento
*Sommario
*Regole generali di formattazione del codice sorgente
*Indentazione
*Commenti
*Margini
*Coppie begin..end
*Object Pascal - Generalità
*Parentesi
*Parole riservate e parole chiave
*Procedure e funzioni
*Nomenclatura/Formattazione
*Formattazione parametri
*Nomenclatura parametri
*Ordinamento dei parametri
*Parametri costanti
*Collisione di nomi
*Variabili
*Nomenclatura e formattazione dei nomi
*Variabili locali
*Uso di variabili globali
*Tipi
*Convenzioni di capitalizzazione
*Tipi a virgola mobile
*Tipi enumerati
*Variant e OleVariant
*Tipi strutturati
*Tipi array
*Tipi Record
*Istruzioni
*Istruzione
if *Istruzione
case *Istruzione
while *Istruzione
for *Istruzioni
repeat *Istruzioni
with *Gestione strutturata delle eccezioni
*Regole generali
*Uso di try. . .finally
*Uso di try. . .except
*Uso di try except else
*Classi
*Nomenclatura/formattazione
*Campi od attributi
*Metodi
*Uso dei metodi statici
*Uso di metodi virtuali/dinamici
*Uso di metodi astratti
*Metodi di accesso alle proprietà
*Proprietà
*Nomenclatura di file
*File di progetto
*File di unit
*Clausole uses
*Sezione Interface
*Sezione Implementation
*Sezione Inizialization
*Sezione Finalization
*Nomi dei file delle form
*Nomi dei file di data module
*Nomi dei file di Remote DataModule
*Nomi dei file di report
*Unit di uso generale
*Unit dei componenti
*Intestazione delle unit
*Intestazioni di procedure/funzioni
*Form e Data module
*Nomenclatura tipo delle form
*Nomenclatura istanza delle form
*Nomenclatura tipo datamodule
*Nomenclatura istanza datamodule
*Form/datamodule autocreati
*Packages
*Uso di package runtime o design
*Standard di nomenclatura dei file
*Componenti
*Componenti definiti dallutente
*Standard di nomenclatura dei tipi
*Unit dei componenti
*Uso delle unit di registrazione
*Convenzioni di nomenclatura delle istanze dei componenti
*Prefissi dei componenti
*Tab Standard
*Tab Additional
*Tab Win32
*Tab System
*Tab Internet
*Tab Data Access
*Tab Data Controls
*Tab Decision Cube
*Tab Qreport
*Tab Qrdesign
*Tab Qrdtools
*Tab Dialogs
*Tab Win31
*Tab Samples
*Tab ActiveX
*Tab Midas
*Tab RX Controls
*Tab RX DbAware
*Tab RX Tools
*Tab Addins
*Riferimenti
*Tabella delle revisioni
*Riferimenti bibliografici
*
Regole generali di formattazione del codice sorgente
Lindentazione sarà di due spazi per livello. Non salvare i caratteri tabulazione con i file sorgente. Il motivo di questo è che i caratteri di tabulazione sono espansi con diverse larghezze per diverse impostazioni utente e per diverse utilità di gestione dei sorgenti (stampa, archiviazione, controllo versione, ecc.).
E possibile disabilitare il salvataggio dei caratteri di tabulazione disabilitando i check box "Use Tab Character" e "Optimal fill" nella pagina Editor della finestra di dialogo "Environment options" (selezionabile tramite la voce di menu Tools|Environment).
Non usare i commenti per dire quello che già dice il codice ad un programmatore Delphi. Usare i commenti per delineare gli scopi generali del codice e per spiegare i motivi di alcune scelte fatte che potrebbero non essere più chiari a distanza di un certo periodo di tempo.
In linea di massima si dovrebbe utilizzare un metodo di scrittura del codice che parta dal PDL (Program Design Language) per poi evolvere in codice sorgente (si raccomanda lapproccio di "Code Complete" [3]).
Inserire un commento ad ogni inizio di unit e ad ogni inizio di procedura, utilizzare in special modo la parte
interface delle unit per i commenti che poi genereranno la documentazione dei programmi, dunque per commenti riguardanti scopi, utilizzi, note particolari. La sezione implementation dovrebbe contenere solo commenti strettamente legati al codice, destinati a chi farà manutenzione.Ci saranno perciò tre livelli di commento. Il primo livello sarà costituito dai commenti che devono diventare parte integrante della documentazione tecnica, da estrarre automaticamente con un tool di documentazione del tipo di DelphiDoc. Il secondo livello è costituito da commenti veri e propri del codice, per essi utilizzare le parentesi graffe. Al terzo livello si trovano i brevi commenti strettamente tecnici, per essi usare le doppie barrette.
A livello due e tre si aggiungano, in linea di massima, le iniziali o lo pseudonimo del programmatore e la data del commento.
Per disabilitare porzioni di codice utilizzare sempre le parentesi graffe con a seguire la prima parentesi i caratteri --, si veda esempio (ma a questo proposito è preferibile la compilazione condizionata, ove possibile).
{** Commento che è parte integrante
della documentazione tecnica
}
{ commento normale - mp 10/02/1999 }
// commento strettamente tecnico mp
{--
Showmessage(test);
}
I margini sono posti a 80 caratteri. In generale, il codice non dovrebbe eccedere questo margine con la eccezione di finire una parola, ma questa regola è abbastanza flessibile. Dove possibile, le istruzioni che superano il margine dovrebbero essere mandate a capo dopo una virgola od un operatore. Quando una istruzione è divisa su più linee, dovrebbe essere indentata di due caratteri dalla linea di codice di partenza.
Listruzione begin dovrebbe apparire su una sua propria riga. Nellesempio seguente, la prima istruzione è errata; la seconda è corretta:
for i := 0 to maxIter do begin // scorretto
for i := 0 to maxIter do // corretto, begin separato
begin
Una eccezione a questa regola si ha quando listruzione
begin fa parte di una clausola else, ad esempio:if qualche istruzione = then
begin
. . .
end
else begin
. . .
end;
Listruzione end appare sempre da sola.
Quando listruzione begin non fa parte di una clausola else, listruzione end è sempre indentata in modo da allinearsi con il begin correlato.
Non dovrebbero esserci mai spazi bianchi tra una parentesi aperta e il carattere successivo. Analogamente, non dovrebbero mai esserci spazi bianchi tra una parentesi chiusa e il precedente carattere. Lesempio seguente illustra un modo scorretto ed uno corretto dutilizzo delle parentesi:
ChiamaProc( UnParametro ); // scorretto
ChiamaProc(UnParametro); // corretto
Non includere mai parentesi non necessarie in una istruzione. Le parentesi dovrebbero essere usate quando richiesto per raggiungere uno scopo preciso nel codice sorgente. Lesempio seguente illustra un uso scorretto ed uno corretto:
if (I = minValore) then // scorretto
if (I = minValore) or (J = maxValore) then // corretto
Parole riservate e parole chiave
Le parole riservate dellObject Pascal dovrebbero essere sempre completamente minuscole.
I nomi delle routine dovrebbero sempre iniziare con una lettera maiuscola e seguire la classica regola di "nessuno spazio, prima lettera di ogni parola maiuscola" per questioni di leggibilità. Il seguente è un esempio di nome di procedura formattato scorrettamente:
procedure questoeunnomediproceduramalformattato;
Questo invece è un esempi di un nome di procedura formattato correttamente:
procedure QuestoNomeDiProceduraEPiuLeggibile;
Alle routine dovrebbero essere sempre dati dei nomi esplicativi delle funzioni che svolgono e dovrebbero avere nomi in italiano, per poterle meglio distinguere da chiamate a funzioni e procedure di Delphi. Le routine che eseguono una azione dovrebbero avere come prima parola del nome il verbo dellazione, ad esempio:
procedure FormattaHardDisk;
La lunghezza raccomandata per un nome di routine è tra 9 e 25 caratteri, non usare nomi eccessivamente abbreviati perché rendono difficile la successiva manutenzione del codice.
Come eccezione alla regola dellitaliano le routine utilizzate per impostare valori di proprietà dovrebbero, in conformità alle regole generali usate in tutto il linguaggio, essere prefissate dalla parola Set, per esempio:
procedure SetNomeUtente;
Allo stesso modo, le routine usate per leggere valori di proprietà dovrebbero essere sempre prefissate da Get, per esempio:
function GetNomeUtente: string;
Dove possibile, i parametri formali dello stesso tipo dovrebbero essere combinati in una istruzione:
procedure TrovaPippo(Param1, Param2: Integer; Param3: String);
Tutti i nomi di parametri formali dovrebbero ricordare il loro scopo e tipicamente saranno basati sul nome dellidentificatore che è stato passato alla routine. Quando opportuno, i nomi di parametri saranno prefissati con "Un", ad esempio:
procedure StampaPippo(UnNomeUtente: string; UnaEtaUtente :Integer);
Il prefisso "Un" è una convenzione per non fare confusione quando il nome del parametro è lo stesso di una proprietà o nome di campo nella classe.
Il seguente ordinamento dei parametri formali consente una ottimizzazione del codice compilato.
I parametri più frequentemente usati (dal chiamante) dovrebbero essere ai primi posti. I parametri meno usati dovrebbero seguire i primi in un ordine da sinistra a destra.
Le liste di input dovrebbero essere prima delle liste di output in un ordine da sinistra a destra.
Piazzare i parametri generici prima dei parametri più specifici, in un ordine da sinistra a destra. Per esempio:
CreaCapitalePianeta(UnPianeta, UnContinente, UnaNazione, UnaRegione, UnaCitta);
Piazzare i parametri senza default prima, a seguire i parametri con un valore di default, in un ordine da sinistra a destra. Solitamente i parametri che forniscono dei valori di default sono quelli di uso meno frequente, quindi questa regola non dovrebbe essere di difficile attuazione. Usare questa funzionalità soprattutto quando si stanno aggiungendo nuovi parametri ad una routine, in modo da non costringere a modificare tutte le chiamate alla procedura, anche dove il nuovo parametro non interessa.
Eccezioni alla regola di ordinamento sono possibili, come nel caso dei gestori di evento, dove un parametro chiamato Sender di tipo TObject è spesso passato come primo parametro.
Quando i parametri di tipo record, array, ShortString o interfaccia non sono modificati da una routine, i parametri di quella routine dovrebbero essere dichiarati come Const. Questo consente al compilatore di generare un codice che passa i parametri non modificati nel modo più efficiente possibile.
Parametri di altro tipo possono essere opzionalmente marcati come Const se essi non sono modificati da una routine. Sebbene questo non abbia effetti sullefficienza del codice, fornisce maggiori informazioni sulluso dei parametri al chiamante della routine.
Quando si usano due unit che contengono entrambe una routine con lo stesso nome, la routine che risiede nella unit che appare per ultima nella clausola uses verrà invocata se chiamate la routine.
Per evitare questa ambiguità, prefissare sempre tali chiamate di metodi con il loro nome di unit, come nellesempio:
SysUtils.FindClose(SR);
oppure
Windows.FindClose(Handle);
Nomenclatura e formattazione dei nomi
Le variabili dovrebbero avere dei nomi mnemonici.
Alle variabili di controllo dei cicli si dovrebbero generalmente dare dei nomi come I, J, o K. E anche accettabile usare un nome più significativo, come
IndiceUtente.I nomi delle variabili booleane dovrebbero essere abbastanza descrittivi così che il loro assumere
True o False sia significativo.Le variabili locali usate allinterno delle procedure seguono le stesse convenzioni di uso e nomenclatura di tutte le altre variabili. Alle variabili temporanee verrà dato un nome di conseguenza.
Quando necessaria, linizializzazione delle variabili locali verrà fatta immediatamente dopo lentrata della routine. Le stringhe
Ansi locali sono inizializzate automaticamente come stringhe vuote, le interfacce sono inizializzate automaticamente a nil, e le variabili di tipo Variant e OleVariant sono inizializzate a Unassigned.Luso di variabili globali è scoraggiato. Comunque, esse possono essere usate se necessario. Quando questo avviene, sarebbe meglio mantenere tali variabili entro il contesto in cui sono usate. Per esempio, una variabile globale potrebbe essere globale solo entro lo scope di una singola sezione
implementation di una unit.Dati globali usati da più di una unit dovrebbero essere posti in una unit comune usata da tutti.
I dati globali potrebbero essere inizializzati con un valore direttamente nella sezione
var. Ricordare che tutti i dati globali sono automaticamente inizializzati a zero, così non si inizializzino le variabili globali con valori "vuoti", come 0, nil, , unassigned e così via. Un motivo di questo è che i dati globali inizializzati con zero non incrementano del dimensioni del file .EXE. I dati inizializzati con zero sono posti in un segmento di dati virtuale che è allocato in memoria solo al lancio dellapplicazione. Viceversa, le variabili inizializzate a codice con valori (zero o non) ingrandiscono il file .EXE e, di conseguenza, aumentano loccupazione di disco.
Convenzioni di capitalizzazione
I nomi di tipo che sono parole riservate del linguaggio dovrebbero essere completamente minuscoli. I tipi
API Win32 sono generalmente tutti maiuscoli, e si dovrebbero seguire le convenzioni usate in Windows.pas o altre unit di API. Per altri nomi di variabili, la prima lettera dovrebbe essere maiuscola, così come le altre lettere inizio di nuove parole, per chiarezza. Esempi:var
MiaStringa: string; // parola riservata
WindowHandle: HWND; // tipo API Win32
I: integer; // identificatore (System.pas)
Luso del tipo Real è scoraggiato perché esiste solo per compatibilità con vecchio codice Pascal. Usare double per bisogni generici di tipi a virgola mobile. Inoltre, il tipo double è ottimizzato dal processore ed è un tipo di formato standard IEEE. Usare extended solo quando è necessario un range maggiore di quello offerto da double. Extended è un tipo specifico Intel e non è supportato da Java. Usare single solo quando la dimensione fisica in byte della variabile è significativa (nel caso ad esempio di DLL scritte in altri linguaggi).
I nomi dei tipi enumerati dovrebbero essere significativi del loro scopo e contenuto. Il nome di tipo dovrebbe essere prefissato dal carattere T per evidenziare la sua caratteristica di tipo. Ogni componente della lista dovrebbe avere il nome prefissato da due o tre lettere minuscole che ne identificano lappartenenza, ad esempio:
TTipoCanzone = (tcRock, tcClassica, tcCountry, tcNewAge, tcHeavyMetal, tcJazz);
Istanze di un tipo enumerato dovrebbero avere lo stesso nome del tipo senza il prefisso T (TipoCanzone), a meno che non ci sia un particolare motivo per dare un nome più specifico, come CanzoniPreferite1, CanzoniPreferite2, e così via.
Luso generalizzato di questi tipi è scoraggiato, ma il loro uso risulta necessario quando il tipo di dato è noto solo a runtime, come nel caso della programmazione COM o di database. Usare OleVariant per programmazione COM come Automazione o controlli ActiveX, e usare Variant per programmazione non-COM. La ragione di questo è che il tipo Variant può contenere in modo efficiente le stringhe native Delphi, mentre OleVariant converte tutte le stringhe in stringhe OLE (stringhe WideChar) che non seguono il meccanismo del conteggio dei riferimenti, ma vengono sempre copiate.
I tipi array dovrebbero avere dei nomi significativi. Il nome di tipo deve essere prefissato da un carattere T. Se viene dichiarato un tipo puntatore ad array, deve essere prefissato dal carattere P e deve essere dichiarato subito prima dellarray, per esempio:
type
PArrayCiclico = ^TArrayCiclico
TArrayCiclico = array[1..maxElem] of Integer;
Alle istanze di array si darà lo stesso nome del tipo senza il prefisso T, a meno che non si debbano dichiarare più array dello stesso tipo.
Ai tipi record dovrebbe essere dato un nome significativo. Il nome di tipo deve essere preceduto dal carattere T. Se si dichiara un puntatore al record, deve essere prefissato dal carattere P al posto della T e deve essere dichiarato subito prima del tipo. La dichiarazione del tipo può essere opzionalmente indentata a destra, ad esempio:
Type
PImpiegato = ^TImpiegato
TImpiegato = record
NomeImpiegato: string
StipendioImpiegato: Double;
end;
ifLa clausola di più probabile esecuzione in una istruzione
if/then/else dovrebbe essere posta nella clausola then, e la clausola meno probabile nella parte else.Cercare di evitare quanto possibile
if concatenate ed usare al loro posto quando possibile istruzioni case.Non indentare comunque ad una profondità maggiore di cinque livelli. Se si verifica il caso, modificare lapproccio alla soluzione.
Non usare parentesi estranee in una istruzione
if.Se si devono verificare condizioni multiple in una istruzione
if, le condizioni dovrebbero essere sistemate da sinistra a destra, ordinate dalla meno alla più complicata come computazione. Questo per far si che il codice si avvantaggi della logica short-circuit evaluation del compilatore. Per esempio, se la Condizione1 è più veloce della Condizione2 che è più veloce della Condizione3, la istruzione if dovrebbe essere composta così:if Condizione1 and Condizione2 and Condizione3 then
Le singole possibilità allinterno di una istruzione case dovrebbero essere ordinate numericamente od alfabeticamente.
Le istruzioni dopo ogni singolo caso dovrebbero essere mantenute semplici e generalmente non eccedere le quattro o cinque righe di codice. Se lazione è più complessa, il codice dovrebbe essere posto in una propria procedura o funzione.
Luso della clausola else in una istruzione case dovrebbe essere usato solo per porre dei default o per individuare degli errori.
Le istruzioni case seguono le stesse regole di formattazione di altri costrutti riguardo ad indentazione e convenzioni di nomenclatura.
Luso della procedura Exit per uscire da un ciclo è scoraggiato; quando possibile, si dovrebbe sempre uscire dal ciclo solo con lapposita condizione.
Tutto il codice di inizializzazione per un ciclo while dovrebbe essere fatto subito prima di entrare nel ciclo e non dovrebbe essere separato da altre istruzioni non correlate.
Ogni operazione di pulizia dovrebbe essere fatta subito dopo luscita dal ciclo.
Le istruzioni for dovrebbero essere usate al posto dei while quando il codice deve essere eseguito per un numero di incrementi noto.
Le istruzioni repeat sono simili alle istruzioni while e dovrebbero seguirne le stesse regole.
Le istruzioni with dovrebbero essere usate sporadicamente e con considerevole cautela. Evitare un eccessivo uso ed evitare di usare oggetti multipli, record e così via nelle istruzioni with. Per esempio:
with Record1, Record2 do
codice simile può confondere il programmatore e portare facilmente a errori difficili da rilevare.
Le istruzioni
with seguono le stesse regole di formattazione già viste nel documento presente riguardo alle convenzioni di nomenclatura ed indentazione.
Gestione strutturata delle eccezioni
La gestione delle eccezioni dovrebbe essere usata abbondantemente sia per la correzione di errori sia per la protezione delle risorse. Questo significa che in tutti i casi in cui vengono allocate delle risorse, deve essere usato un blocco
try finally per assicurare un corretto rilascio delle risorse. Leccezione a ciò si ha quando le risorse sono allocate/liberate nella parte di initialization/finalization di una unit o nei constructor/destructor di un oggetto.Dove possibile, ogni allocazione dovrebbe essere posta entro un construtto
try. . .finally. Per esempio, il seguente codice, passibile di bug:ClasseGenerica1 := TClasseGenerica.Create;
ClasseGenerica2 := TClasseGenerica.Create;
try
{ fa qualche cosa }
finally
ClasseGenerica1.Free;
ClasseGenerica2.Free;
end;
dovrebbe essere riscritto in un modo più sicuro:
ClasseGenerica1 := TClasseGenerica.Create;
try
ClasseGenerica2 := TClasseGenerica.Create;
try
{ fa qualche cosa }
finally
ClasseGenerica1.Free;
end;
finally
ClasseGenerica2.Free;
end;
Usare try except solo quando si vuole svolgere qualche compito quando uneccezione è sollevata.
In generale, non si dovrebbe usare try. . .except semplicemente per mostrare un codice sullo schermo poiché questo verrà fatto automaticamente nel contesto dellapplicazione dalloggetto Application.
Se si vuole invocare il gestore delle eccezioni di default dopo che si è svolto qualche compito nella clausola except, usare raise per risollevare leccezione per il successivo gestore.
Evitare luso della else dopo try. . .except perché blocca tutte le eccezioni, anche quelle per cui non si era pronti.
I nomi di tipo per le classi dovrebbero rispecchiare lo scopo della classe. Il nome di tipo dovrebbe essere prefissato dal carattere T per evidenziarlo come definizione di tipo, ad esempio:
type
TCliente = class(TObject)
I nomi di istanza per le classi dovrebbero generalmente essere uguali al nome del tipo senza il prefisso T, ad esempio:
var
Cliente: TCliente;
Notare che, pur non essendo obbligatorio specificare TObject come classe padre di TCliente, sia stato comunque specificato per maggiore completezza e chiarezza del codice.
I nomi dei campi di classe seguono le stesse convenzioni degli identificatori di variabile tranne che sono prefissati dal carattere F per indicare che sono nomi di campo.
Tutti i campi dovrebbero essere privati. Campi che devono essere resi accessibili al di fuori dello scope della classe devono essere esportati tramite luso di proprietà.
Le regole di nomenclatura dei metodi sono le stesse già viste nel presente documento per le procedure e le funzioni.
Usare metodi statici quando non si vuole che un metodo sia sovrascritto dalle classi discendenti
Uso di metodi virtuali/dinamici
Usare metodi virtuali quando si può voler modificare il metodo nelle classi discendenti. I metodi dinamici dovrebbero essere usati solo nelle classi per le quali ci saranno molti discendenti (diretti o indiretti). Per esempio, una classe contenente un metodo riscritto infrequentemente e 100 classi discendenti dovrebbe essere reso dinamico per ridurre luso di memoria per le 100 classi discendenti.
I metodi astratti si usano per classi che non saranno istanziate.
Metodi di accesso alle proprietà
Tutti i metodi di accesso alle proprietà devono apparire nelle sezioni private o protected della definizione di classe.
Le convenzioni di denominazione seguono le stesse regole delle procedure e funzioni. Il metodo di accesso in lettura deve essere prefissato con la parola Get. Il metodo di accesso in scrittura deve essere prefissato con la parola Set. Il parametro per il metodo di scrittura deve avere il nome Value ed il suo tipo deve essere lo stesso del metodo che rappresenta, ad esempio:
TQualcheClasse = class(TObject)
private
FQualcheCampo: Integer;
protected
function GetQualcheCampo: Integer;
procedure SetQualcheCampo(Value: Integer);
public
property QualcheCampo: Integer read GetQualcheCampo write SetQualcheCampo;
end;
Le proprietà che servono per esporre campi privati si chiameranno come i campi che rappresentano senza la F iniziale.
I nomi di proprietà dovrebbero essere oggetti, non verbi. Le proprietà rappresentano dati; i metodi rappresentano azioni.
Le proprietà
array dovrebbero essere plurali; le proprietà normali dovrebbero essere singolari.Sebbene non richiesto, è incoraggiato almeno luso dei metodi di accesso in scrittura per le proprietà che rappresentano un campo privato.
Ai file di progetto verrà dato un nome descrittivo. Per esempio, un progetto per catalogare bug di programma protrebbe chiamarsi
CatalogoBug.dpr
. In ambiente multitier, i file di progetto degli application server avranno il nome che termina con "Server", mentre al contrario i file di progetto dei programmi client avranno il nome che termina con "Client".Per quel che riguarda i file di unit, il loro nome sarà composto essenzialmente da tre parti. Si ipotizza unarchitettura modulare dellapplicazione, dove un certo numero di unit farà parte di un cosiddetto modulo.
In base a tali considerazioni, la prima parte del nome di una unit ovvero i tre o quattro caratteri iniziali indicheranno lappartenenza della Unit ad un modulo ben preciso.
Di seguito verrà il nome esteso delloggetto o della famiglia di oggetti contenuti nella unit, oppure delle funzionalità offerte dalla unit.
Per finire ci sarà un eventuale suffisso del tipo "frm" per le form, "dm" per i datamodule, "rdm" per i remote data module. Per un elenco dei suffissi attualmente previsti vedere lappendice 1 alla fine del documento.
La clausola
uses nella sezione Interface conterrà solo le unit richieste dal codice nella sezione di interfaccia. Rimuovere ogni nome di unit estraneo che potrebbe essere stato inserito automaticamente da Delphi.La clausola
uses nella sezione Implementation conterrà solo le unit richieste dal codice nella sezione di implementazione. Rimuovere tutti i nomi di unit non necessari.La sezione
Interface conterrà solo le dichiarazioni di quei tipi, variabili, dichiarazioni forward di funzioni/procedure, ecc. che devono essere accessibili da parte di unit esterne. Tutte le altre dichiarazioni dovranno andare nella sezione Implementation.La sezione
Implementation conterrà solo tutte le dichiarazioni dei tipi, variabili, procedure/funzioni, ecc. che sono di esclusivo uso da parte della unit che le contiene.Non piazzare codice molto pesante nella sezione di inizializzazione di una unit. Questo rallenterebbe lapparizione della prima form.
Assicurarsi di aver rilasciato qualsiasi oggetto che sia stato allocato nella sezione di
Inizialization.I file delle form avranno lo stesso nome del file della unit corrispondente ma avranno estensione
.dfm.I file dei data module avranno lo stesso nome del file della unit corrispondente ma avranno estensione
.dfm.Nomi dei file di Remote DataModule
I file dei remote data module avranno lo stesso nome del file della unit corrispondente ma avranno estensione
.dfm.Da definire
Le unit di uso generale seguiranno le stesse regole di nomenclatura già definite prima, con leccezione di eventuali unit di codice recuperate da terze parti e non ridenominabili agevolmente.
Le unit dei componenti verranno poste in directory separate per distinguerle dalle unit di progetto. Non devono mai essere poste nella stessa directory. Alle unit dei componenti viene dato lo stesso nome del componente in esse definito. Per gli standard relativi alle nomenclature dei componenti definiti dallutente, vedere paragrafo relativo più avanti.
Luso di un commento di intestazione della unit è incoraggiato per tutti i file sorgenti del progetto e dei componenti. Conterrà un messaggio di copyright, a cosa serve la unit, particolari informazioni di cui potrebbe necessitare il programmatore che dovesse usare la unit, eventuali modifiche apportate nel tempo con data e nome di chi ha fatto tali modifiche. Riguardo ai commenti, si raccomanda di non segnalare cosa il codice fa, specie se questo è banale, ma il perché certi problemi sono stati risolti in un modo piuttosto che in un altro e tutte le altre informazioni che si pensa potrebbero servire a chi, a distanza di tempo, cercasse di capire non solo cosa fa la unit ma perché lo fa in un certo modo piuttosto che in un altro. Esempio di intestazione di unit:
{** Unit Pippo
© Copyright 1998 Autore
Data e versione
Questa unit serve a fare questo e quello.
Fa questo in questo modo perché nellaltro
modo non funzionava.
Per usare questa unit si raccomanda prima
di dire una preghierina.
10-11-1998 Rob: lho modificata perché non
funzionava niente.
}
Intestazioni di procedure/funzioni
Luso di un commento di intestazione di procedure/funzioni è raccomandato. Conterrà una breve indicazione delle operazioni svolte dal codice e indicazioni per chi dovesse utilizzarlo. Riguardo al contenuto di questi commenti valgono le stesse considerazioni già espresse per le intestazioni di unit.
Esempio di intestazione di procedura:
{** Procedura QuestoEQuello
© Copyright 1998 Autore
Data e versione
Questa procedura serve a fare
questo e quello.
Per richiamarla bisogna mettersi
in ginocchio sui ceci.
}
Il nome del tipo della form rispecchia in qualche modo il nome della unit che la contiene, rovesciato: i 3 o 4 caratteri che erano suffisso diventano prefisso, mentre il resto del nome rimane invariato; per cui se abbiamo una unit che si chiama BasSingoloFmr, il tipo della form sarà TfmrBasSingolo (dove Bas indica un particolare modulo dellapplicazione). Questo consente di poter avere in Delphi le unit ordinate per modulo premendo F12 (oppure dal menu: View|Units ) e le form ordinate per tipo premendo Shift+F12 (oppure dal menu: View|Forms ).
Nomenclatura istanza delle form
Le istanze delle form assumeranno lo stesso nome del loro tipo corrispondente, perdendo la T iniziale; per cui listanza di form dellesempio precedente si chiamerà FmrBasSingolo.
Il nome del tipo del datamodule rispecchia in qualche modo il nome della unit che le contiene, rovesciato: i 3 o 4 caratteri che erano suffisso diventano prefisso, mentre il resto del nome resta invariato; per cui se abbiamo una unit che si chiama BasScritturaDms, il tipo della form sarà TDmsBasScrittura. Questo per gli stessi motivi già espressi nel paragrafo relativo alla nomenclatura del tipo delle form.
Nomenclatura istanza datamodule
Anche per le istanze di datamodule valgono le stesse considerazioni fatte per le istanze di form, a cui si rimanda.
Lunica form auto creata sarà la main form a meno che non ci sia un buon motivo per fare diversamente. Tutte le altre dovranno essere rimosse dalla lista auto-create nel dialog box Project Options.
Per quel che riguarda le form modali, verrà rimossa anche la dichiarazione di variabile presente nella unit della stessa form. La parte di codice che dovrà visualizzare la form creerà una variabile locale della stessa, ne farà la visualizzazione ed al termine provvederà a distruggere la form e ad impostare a nil la variabile.
Uso di package runtime o design
I package di runtime conterranno solo le unit e i componenti richiesti da altri componenti in quel package. Le altre unit che contengono editor di proprietà o editor di componenti o altro codice utile per il design devono essere posti in un package di design. Le unit di registrazione verranno poste in un package di design.
Standard di nomenclatura dei file
I package verranno denominati secondo il seguente schema:
PREFISSOLibvv.pkg design package
PREFISSOStdvv.pkg runtime package
Dove il PREFISSO si utilizza liberamente, Lib o Std identificano il tipo di package e vv indica la versione di Delphi per cui il package è compilato.
Notare che il nome del package contiene Lib o Std per indicare se è un package di runtime o di designtime.
Componenti definiti dallutente
Standard di nomenclatura dei tipi I componenti dovrebbero essere battezzati in modo simile alle classi così come definito nella sezione apposita del presente documento, con leccezione di un PREFISSO che è il prefisso standard per i componenti da sviluppati internamente ovvero personalizzati. Unit dei componenti Ogni unit dei componenti dovrebbe contenere soltanto un componente principale. Vengono considerati come componenti principali tutti quelli che compaiono nella palette dei componenti. Ogni componente/oggetto ausiliario può risiedere nella stessa unit del componente principale. Uso delle unit di registrazioneLa procedura di registrazione dei componenti dovrebbe essere rimossa dalla unit del componente ed essere posta in una unit separata. Questa unit di registrazione dovrebbe essere usata per registrare tutti i componenti, editor di proprietà, editor dei componenti, expert, ecc.
La registrazione dei componenti dovrebbe essere fatta solo nei package di design: quindi la unit di registrazione dovrebbe essere contenuta nel package di design e non in quello di runtime.
Un nome consigliato per la unit di registrazione è:
PREFISSOxxxReg.pas
Dove PREFISSO è di libero utilizzo e xxx deve essere usato per identificare il componente che viene registrato.
Convenzioni di nomenclatura delle istanze dei componenti
I seguenti prefissi dovrebbero essere assegnati ai componenti standard che sono presenti in Delphi 4; sono stati inoltre aggiunti altri popolari componenti di terze parti.
Prefisso Componente mm TMainMenu pm TPopupMenu mmi TMainMenuItem pmi TPopupMenuItem lbl TLabel edt TEdit mem TMemo btn TButton cb TCheckBox rb TRadioButton lb TListBox cb TComboBox scb TScrollBar gb TGroupBox rg TRadioGroup pnl TPanel al TActionList ac TAction
Prefisso Componente bbtn TBitBtn sb TSpeedButton me TMaskEdit sg TStringGrid dg TDrawGrid img TImage shp TShape bvl TBevel sbx TScrollBox clb TCheckListBox spl TSplitter stx TStaticText ctb TControlBar cht TChart
Prefisso Componente tbc TTabControl pgc TPageControl il TImageList re TRichEdit tbr TTrackBar prb TProgressBar ud TUpDown hk THotKey ani TAnimate dtp TDateTimePicker mcl TMonthCalendar tv TTreeView lv TListView hdr THeaderControl stb TStatusBar tlb TToolBar clb TCoolBar psc TPageScroller
Prefisso Componente tm TTimer pb TPaintBox mp TMediaPlayer olec TOleContainer ddcc TDDEClientConv ddci TDDEClientItem ddsc TDDEServerConv ddsi TDDEServerItem
Prefisso Componente csk TClientSocket ssk TServerSocket wbd TWebDispatcher pp TPageProducer tp TQueryTabeProducer dstp TDataSetTableProducer nmdt TNMDayTime nec TNMEcho nf TNMFinger nftp TNMFtp nhttp TNMHttp nMsg TNMMsg nmsg TNMMSGServ nntp TNMNNTP npop TNMPop3 nuup TNMUUProcessor smtp TNMSMTP nst TNMStrm nsts TNMStrmServ ntm TNMTime nudp TNMUdp psk TPowerSock ngs TNMGeneralServer html THtml url TNMUrl sml TSimpleMail
Prefisso Componente ds TDataSource tbl TTable qry TQuery sp TStoredProc db TDataBase ssn TSession bm TBatchMove usql TUpdateSQL nstt TNestedTable
Prefisso Componente dbg TDbGrid dbn TDbNavigator dbt TDbText dbe TDbEdit dbm TDbMemo dbi TDbImage dblb TDbListBox dbcb TDbComboBox dbch TDbCheckBox dbrg TDbRadioGroup dbll TDbLookupListBox dblc TDbLookupComboBox dbre TDbRichEdit dbcg TDbCtrlGrid dbch TDbChart
Prefisso Componente dcb TDecisionCube dcq TDecisionQuery dcs TDecisionSource dcp TDecisionPivot dcg TDecisionGrid dcgr TDecisionGraph
Prefisso Componente qr TQuickRep qrsd TQRSubDetail qrsb TQRStringBand qrb TQRBand qrcb TQRChildBand qrg TQRGroup qrl TQRLabel qrt TQRText qre TQRExpr qrs TQRSysData qrm TQRMemo qrem TQRExprMemo qrrt TQRRichText qrdr TQRDbRichText qrsh TQRShape qri TQRImage qrdi TQRDbImage qrcr TQRCompositeReport qrp TQRPreview qrch TQRChart qrtf TQRTextFilter qrcf TQRCSVFilter qrhf TQRHTMLFilter
Prefisso Componente qrdd TReportDesignerDialog qrdp TReportPrinterDialog qrdl TQRDLoader qrd TQRepDesigner qrddq TDesignQuickReport qrdsd TQRDesignSubdetail qrdb TQRDesignBand qrdcb TQRDesignChildBand qrdg TQRDesignGroup qrdl TQRDesignLabel qrdt TQRDesignDbText qrde TQRDesignExpr qrds TQRDesignSysData qrdm TQRDesignMemo qrdsh TQRDesignShape qrdim TQRDesignImage qrddi TQRDesignDbImage qrdrt TQRDesignRichText qrddr TQRDesignDbRichText
Prefisso Componente qrdeh TQRExprHandler qrdes TEventScrollbox qrdrp TRulerPanel qrdli TLanguageInifile qrdel TEnhancedListbox
I componenti dialog box sono in realtà delle form incapsulate in un componente. Per questo motivo, essi seguiranno delle convenzioni di nomenclatura simili a quelle delle form. La definizione del tipo è già definita per il nome del componente. Il nome di istanza sarà lo stesso del nome di tipo senza il prefisso numerico, che è assegnato da Delphi. Seguono esempi:
Tipo Nome istanza TOpenDialog OpenDialog TSaveDialog SaveDialog TOpenPictureDialog OpenPictureDialog TSavePictureDialog SavePictureDialog TFontDialog FontDialog TColorDialog ColorDialog TPrintDialog PrintDialog TPrintSetupDialog PrintSetupDialog TFindDialog FindDialog TReplaceDialog ReplaceDialog
Prefisso Componente dbll TDBLookupList dblc TDBLookupCombo ts TTabSet ol TOutline tnb TTabbedNotebook nb TNoteBook hdr THeader flb TFileListBox dlb TDirectoryListBox dcb TDriveComboBox fcb TFilterComboBox
Prefisso Componente gg TGauge cg TColorGrid spb TSpinButton spe TSpinEdit dol TDirectoryOutline cal TCalendar ibea TIBEventAlerter
Prefisso Componente cfx TChartFX vsp TVSSpell f1b TF1Book vtc TVTChart grp TGraph
Prefisso Componente prv TProvider cds TClientDataSet dcom TDCOMConnection corb TCORBAConnection olee TOLEEnterpriseConnection sck TSocketConnection dprv TDatasetProvider sob TSimpleObjectBroker rms TRemoteServer mid TMidasConnection
Prefisso Componente rxce TRxComboEdit rxfe TRxFilenameEdit rxde TRxDirectoryEdit rxdt TRxDateEdit rxca TRxCalcEdit rxcu TRxCurrencyEdit rxtl TRxTextListBox rxcl TRxCheckListBox rxfc TRxFontComboBox rxcc TRxColorComboBox rxsp TRxSplitter rxsl TRxSlider rxlb TRxLabel rxck TRxClock rxai TRxAnimatedImage rxdg TRxDrawGrid rxsb TRxSpeedButton rxga TRxGIFAnimator rxsn TRxSpinButton rxse TRxSpinEdit rxsw TRxSwitch rxdi TRxDice
Prefisso Componente rxqy TRxQuery rxss TRxSQLScript rxmt TRxMemoryTable rxqbe TRxQBEQuery rxdf TRxDbFilter rxdbg TRxDbGrid rxll TRxDbLookupList rxlc TRxDbLookupCombo rxle TRxDbLookupEdit rxdd TRxDbDateEdit rxdc TRxDbCalcEdit rxdce TRxDbComboEdit rxdsl TRxDbStatusLabel rxdcb TRxDbComboBox rxdr TRxDbRichEdit rxdic TRxDbIndexCombo rxdbp TRxDbProgress rxdse TRxDbSecurity rxbdi TRxBDEItems rxdbi TRxDatabaseItems rxtbi TRxTableItems
Prefisso Componente rxpc TPicClip rxfs TFormStorage rxfp TFormPlacement rxwh TRxWindowHook rxae TAppEvents rxspb TRxSpeedBar rxclc TRxCalculator rxtm TRxTimerList rxpm TRxPageManager rxmru TMRUManager rxscp TSecretPanel rxsth TStrHolder rxtri TRxTrayIcon rxmm TRxMainMenu rxpo TRxPopupMenu rxfm TRxFolderMonitor rxcv TClipboardViewer rxgc TRxGradientCaption rxdld TRxDualListDialog rxcnv TConverter
Prefisso Componente axl TAdvExcel xls TExcel Jon TJustOne Joa TJustOneAsk Aex TAppExec Ema TEmail
Versione Autore Principale
Descrizione della versione Completata 0.92 MP, RI Beta 1 09/02/1999 0.96 MP Beta 2 revisione del codice e degli esempi 16/02/1999 0.97 MP Beta 3 adeguamento standard, revisione esempi 19/02/1999 0.98 MP Beta 4 revisione nomenclatura file 22/02/1999 0.99 MP Pre-release di test 22/02/1999 1.00 MP Prima release ufficiale 22/02/1999
Questo standard è stato ricavato da:
[1] R.Icardi Standard di codifica ESSEDI Delphi 4, Progetto ERP-Fashion Essedi Sviluppo Clienti S.r.l., 1998
[2] Pacheco, Teixeira - Delphi 4 Developers Guide SAMS, 1998
[3] S.McConnell Code Complete Microsoft Press, 1993
[4] Inprise VCL source code Inprise, 1998
© M.Planchestainer 1999