Convenzioni per la programmazione in Visual Basic


Note: questo articolo è stato tratto da
MSDN - Visual Basic Programming Conventions from Microsoft Consulting Services
Tradotto e riadattato in alcune parti.
Non è quindi da intendersi come documentazione ufficiale.

1. Convenzioni sui nomi.

1.1 Obiettivi
Per aiutare i programmatori (specialmente in progetti di gruppo) standardizza e decodifica la struttura e la logica di un'applicazione.

Per essere precisi, completi, leggibili, semplici da ricordare e non ambigui.

Per essere coerenti con le convenzioni di altri linguaggi (most importantly the Visual Basic™ Programmer's Guide and standard Microsoft® Windows™ Hungarian C)

Per essere efficienti dal dimensionamento di una stringa alla visuale dell'intero progetto fino alla definizione di nomi complessi per tutti gli oggetti.

Per definire il minimo indispensabile per ottenere tutto questo. 

1.2 Convenzioni
1.2.1 Option Explicit
"Option Explicit" deve sempre essere usato per forzare la dichiarazione delle variabili ed è un buon ausilio al loro commento.
Il tempo perso cercando di trovare i bugs causati da digitazioni (aUserNameTmp vs. sUserNameTmp vs. sUserNameTemp) supera notevolmente il tempo necessario per una Dim.

1.2.2 Denominazione dei Controlli
La tavola seguente definisce il nostro standard dei prefissi per i controlli.

Tavola 1. Standard Prefissi per i nomi dei controlli

Prefix
Control Type Description

ani
Animation button

bed
Pen Bedit 

cbo
Combobox e dropdown Listbox

chk
Checkbox

clp
Picture Clip

cmd
Command Button

com
Communications 

ctr
Control (Usato dentro le procedure quando il tipo di controllo specifico è sconosciuto)

db
ODBC Database

dir
Dir List Box

dlg
Visual Basic Pro Common Dialog

drv
Drive List Box

ds
ODBC Dynaset

fil
File List Box

frm
Form

fra
Frame

gau
Gauge

gpb
Group Push Button

grd
Grid

hed
Pen Hedit

hsb
Horizontal Scroll Bar

img
Image

ink
Pen Ink

key
Keyboard key status

lbl
Label

lin
Line

lst
Listbox

mpm
MAPI Message

mps
MAPI Session

mci
MCI

mnu
Menu

opt
Option Button

ole
Ole Client

pic
Picture

pnl
3d Panel

shp
Shape

spn
Spin Control

txt
Text/Edit Box

tmr
Timer

vsb
Vertical Scroll Bar


1.3 Note per il Prefisso dei Controlli

1.3.1 Menu
Dato che i menu possono essere numerosi, la denominazione dei menu richiede un po' più di attenzione. I prefissi dei menu continuano oltre l'iniziale "mnu" aggiungendo un ulteriore lettera maiuscola per ogni livello di nidificamento, con il nome del menu derivato dalla stessa caption alla fine.
Quando c'è ambiguità causata da duplicazione di caratteri, come un menu con un Main con la stessa iniziale, ad es: Format e File, verrà usata una lettera minuscola addizionale per differenziarli.

Esempi: 

Struttura del menu 
Nome del menu 


Help.Contents
mnuHContents

File.Open
mnuFiOpen

Format.Character
mnuFoCharacter

File.Send.Fax 
mnuFSFax

File.Send.Email
mnuFSEmail

In questo modo tutti i membri di un gruppo di menu saranno elencati vicini gli uni agli altri.
Questo è un sistema molto efficiente di trovare un particolare menu, specie se ve ne sono molti.

Per ridurre il numero di menu elencati un eccessivo sparpagliamento del codice è possibile definire un array di menu per tutte le voci dello stesso livello.
In questo caso la denominazione segue le stesse regole di cui sopra omettendo però la parte finale del nome.
Gli indici verranno identificati da costanti con prefisso "MNU_" e il relativo codice sarà gestito nell'evento click tramite una Select.

Esempi: 

Struttura del menu 
Nome del menu 


Help.Contents 
mnuH(MNU_CONTENTS) 

File.Open 
mnuFi(MNU_OPEN) 

Format.Character 
mnuFo(MNU_CHARACTER) 

File.Send.Fax 
mnuFS(MNU_FAX) 

File.Send.Email 
mnuFS(MNU_EMAIL) 


1.3.2 Altri controlli
Per i controlli non elencati sopra viene lasciato al buon senso del programmatore trovare un prefisso univoco che identifichi la classe.

1.3.3 Denominazione di variabili e routine
Il nome di variabili e funzioni ha la seguente struttura: 
<prefisso><corpo><qualificatore><suffiso>

Il prefisso descrive l'uso e lo scopo di una variabile come in iRecordNext e sNameFirst.
ll qualificatore denota uno standard di derivazione di una variabile o funzione come in iRecordNext e sNameFirst.
Il suffisso è l'opzionale carattere che identifica il tipo ($, %, #, e così via).

Il prefisso per le funzioni pubbliche dovrebbe identificare, a differenza di quanto avviene per le variabili, il modulo di provenienza seguendo le stesse regole per il suffisso dei controlli.

Es: Modulo Graphics.bas -> Function DrawLine --> Function grpDrawLine

E' consigliato l'uso del descrittore As Tipo nella dichiarazione, anzichè il carattere di tipo.
Le variabili devono sempre essere tipizzate anche se dichiarate Variant.
L'uso del tipo Variant sarà discusso più avanti.

Prefissi 

La tavola seguente definisce i prefissi delle variabili che sono basati sul C ungherese.
Questi dovrebbero essere usati universalmente, persino con le variabili tipizzate. 

Tavola 2. Prefissi per i nomi di variabili 

Prefisso 
Descrizione del tipo di variabile 

b 
Boolean 

c 
Currency - 64 bits (vb type = @) 

d 
Double - 64 bit signed quantity (vb type = #) 

db 
Database 

ds 
Dynaset 

dt 
Date+Time 

f 
Float/Single - 32 bit signed floating point (vb type = !) 

h 
Handle (vb type = &) 

i 
Index (vb type = %, &) *NDO* riconducibile a "l" 

l 
Long - 32 bit signed quantity (vb type = &) 

n 
Integer (sizeless, counter) (vb type = %) *NDO* riconducibile a "l"

s 
String (vb type = $) 

u 
Unsigned - 16 bit unsigned quantity (must use &) *NDO* riconducibile a "l"

ul 
Unsigned Long - 32 bit unsigned quantity (must use #) *NDO* riconducibile a "l" se la quantità lo permette

v 
Variant (big and ugly to discourage use and make sure it gets the reader's attention) 

w 
Word - 16 bit signed quantity (vb type = %) *NDO* riconducibile a "i"

a 
Array 

t
User defined type 

y
Byte 

Il metodo ungarico è utile in Visual Basic in quanto il nome da solo non dà informazioni sufficienti sullo scopo di una variabile e del suo contenuto.
Per esempio, iSend (che probabilmente è un contatore per i messaggi spediti), bSend (che probabilmente è un flag che indica il successo dell'ultima operazione di invio), e hSend (che probabilmente è un handle per un oggetto) suggeriscono molto concisamente qualcosa di differente. Questa informazione è persa quando il nome è semplicemente Send

Corpo 

Il corpo di un nome di variabile o routine dovrebbe usare lettere maiuscole e minuscole in modo da descrivere il loro scopo. Nomi di funzioni dovrebbero inoltre iniziare con un verbo come in InitNameArray o CloseDialog.

Per termini lunghi o usati frequentemente, abbreviazioni (come Init, Num, Tbl, Cnt e Grp per Number, Table, Count, e Group) sono suggerite per mantenere il nome della funzione il ragionevolmente corto.
Quando queste abbreviazioni sono usate DEVONO essere usate coerentemente in tutto il progetto: passare casualmente da "Cnt" a "Count" all'interno dello stesso progetto produce frustrazione negli sviluppatori.

Qualificatori

Spesso vengono usate variabili e relative routines per gestire e manipolare oggetti comuni.
In questi casi può essere veramente d'aiuto standardizzare i qualificatori. Benchè mettere il qualificatore dopo il corpo può suonare male (come in sGetNameFirst, sGetNameLast anzichè sGetFirstName e sGetLastName), questa pratica aiuterà ad ordinare e a tenere raggruppati nell'editor di VB le funzioni rendendo anche più semplice la comprensione della struttura dell'applicazione

La tavola seguente definisce i qualificatori più comunemente usati e il loro significato.

Tavola 3. Qualificatori comuni

Qualificatore 
Descrizione (a seconda del corpo) 


First
primo elemento di un set. 

Last
ultimo elemento di un set. 

Next
prossimo elemento in un set. 

Prev
elemento precedente in un set. 

Cur
elemento corrente di un set. 

Min
valore minimo in un set. 

Max
valore massimo in un set. 

Save
Usato per salvare un valore che sarà ripristinato in seguito. 

Tmp
Una variabile temporanea con scopo fortemente localizzato. 

Src
Sorgente (Source). 

Dst
Destinazione (Destination). Spesso usata insieme a Source. 


1.3.4 Denominazione di Constanti
Il nome di una costante deve essere scritto in MAIUSCOLO con un underscores ("_") tra le parole.

Un eventuale prefisso che denota lo scopo di una costante deve essere anteposto al nome sempre in maiuscolo e separato dal nome da un underscore

Esempi: 
WM_CLICK 
Window Message, con valore per "Click" 

NEW_LINE 
New Line character string 


1.3.5 Tipi di dato Variant
Con la sola eccezione elencata sotto i tipi Variant NON dovrebbero essere usati.
Quando è necessaria una conversione di tipo le variabili Variant probabilmente offrono una performance leggermente migliore rispetto alle funzioni di conversione esplicita (val(), str$(), and the like), ma questo non è sufficiente per giustificare l'ambiguità e la trascuratezza generale del codice

Esempi:

vnt1 = "10.01" : vnt2 = 11 : vnt3 = "11" : vnt4 = "x4"
vntResult = vnt1 + vnt2 ' Does vntResult = 21.01 or 10.0111?
vntResult = vnt2 + vnt1 ' Does vntResult = 21.01 or 1110.01?
vntResult = vnt1 + vnt3 ' Does vntResult = 21.01 or 10.0111?
vntResult = vnt3 + vnt1 ' Does vntResult = 21.01 or 1110.01?
vntResult = vnt2 + vnt4 ' Does vntResult = 11x4 or ERROR?
vntResult = vnt3 + vnt4 ' Does vntResult = 11x4 or ERROR?
Additionally, the type conversion routines assist in documenting implementation details, which make reading, debugging, and maintaining code more straightforward.

Esempio:

(iVar1 = 5 + val(sVar2) 'usa questo
vntVar1 = 5 + vntVar2  'non questo!

Eccezione

Raramente è necessaria (specie lavorando con database, message, DDE, o OLE), una funzione generica che può ricevere dati di qualsiasi tipo.

Esempio:

Sub ConvertNulls(rvntOrg As Variant, rvntSub As Variant)
    If rvntOrg = Null, replace the Null with rvntSub
    If IsNull(rvntOrg) Then rvntOrg = rvntSub
End Sub

2. Commenti
Tutte le procedure devono iniziare con una breve descrizione delle caratteristiche funzionali.
Questa descrizione NON deve dire come è implementata la routine, poichè questo può variare nel tempo portando a perdite di tempo nel rivedere i commenti e soprattutto a commenti erronei
Il codice stesso e ogni eventuale suo commento descriverà l'implementazione.
I parametri devono essere descritti se (a) sono di dubbia interpretazione (questo non dovrebbe mai accadere) (b) richiedono dei valori specifici per il funzionamento della funzione (c) il valore viene modificato all'interno della routine (questo dovrebbe accadere solo se il parametro modificato è un valore di ritorno richiesto: nessuna funzione deve prendersi la libertà di modificare il valore dei parametri che non devono restituire un valore)

Ogni variabile di dubbia utilità deve essere commentata.

I nomi di variabili, funzioni, controlli e quant'altro deve essere chiaro a sufficienza.

Note: la Project window descrive solo i files nel progetto, quindi tutti i files esterni (come INI, DB ecc...) dovrebbero essere descritti. 

3. Formattazione del Codice
I blocchi di indentazione (tab) devono essere di quattro spazi. 

Il commento alla funzione dovrebbe essere indentato di una tabulazione.
Il primo statement della funzione dovrebbe partire indentato di un tab, e un tab per ogni linea di codice all'interno del blocco. 

Function iFindUser (rasUserList() as String, rsTargetUser as String) as Integer 
    
        ' Search UserList and if found, return index of first occurrence of TargetUser, 
            ' else return -1
        Dim i as Integer 'loop counter
        Dim bFound as Integer 'target found flag
        iFindUser = -1
        i = 0
        While i <= Ubound(rasUserList) and Not bFound
                If rasUserList(i) = rsTargetUser Then 
                        bFound = True
                        iFindUser = i
                End If
        Wend
End Function

Variabili e costanti devono risiedere nella sezione "Dichiarazioni" raggruppare per scopo/utilità. 
Tutte le dichiarazioni globali dovrebbero risiedere in un modulo comune. 
Le dichiarazioni delle variabili e costanti dovrebbero seguire il seguente ordine: 
public const 
public enum 
public type 

private const 
private enum 
private type

public 
private / dim 
Declare


4. Operatori
Usare SEMPRE "&" quando si concatenano stringhe e "+" lavorando con valori numerici.
L'uso del solo "+" può portare a problemi lavorando con due variabili (specie con i variant).
Per esempio: 
vntVar1 = "10.01"
vntVar2 = 11
vntResult = vntVar1 + vntVar2 'vntResult = 21.01 
vntResult = vntVar1 & vntVar2 'vntResult = 10.0111

5. Scope
Le variabili vanno sempre definite con il più piccolo scope possibile.
Variabili globali possono creare enormi e complessi stati di macchina e rendere incomprensibile la logica di un'applicazione.
Inoltre rendono il riuso e il mantenimento del codice molto più complesso.
Se vengono usate variabili globali vanno tenute raggruppate per funzionalità e commentate bene.

Con l'eccezione di variabili globali che non dovrebbero essere passate, le funzioni DEVONO lavorare SOLO con ciò che gli è stato passato.
Variabili globali che devono essere passate alle funzioni devono essere commentate adeguatamente.

Segmenta la logica dell'applicazione in blocchi il più possibile.
Questo aiuterà a suddividere la complessità dell'applicazione e a minimizzare il suo run-time everhead.


Per tutti i Sistemi Operativi