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

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 definidce 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 and dropdown Listbox

chk

Checkbox

clp

Picture Clip

cmd

Command Button

com

Communications

ctr

Control (Used within procs when the specific type is unknown)

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

* Nota del traduttore *

Ulteriori estensioni verranno aggiunte man mano.

 

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.

* Nota del traduttore *

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_OPEN)

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.
[snap da parte dell'organizzatore]

1.3.3 Denominazione di variabili e routine

* Nota del traduttore *

La convenzione per la denominazione delle funzioni era descritta in modo analogo a quella usata per le variabili.
Le funzioni useranno ora una convenzione differente.

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).

* Nota del traduttore *

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

* Nota del traduttore *

Corretta per la ver. 32bit di VB

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 or 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 scope fortemente localizzato.

Src

Sorgente (Source).

Dst

Destinazione (Destination). Spesso usata insieme a Source.

1.3.4 Denominazione di Constanti

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 trascuranza 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.

Example:

(iVar1 = 5 + val(sVar2)     'use this
vntVar1 = 5 + vntVar2       'not this!

Eccezione

Raramente è necessaria (specie lavorando con databases, messages, 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

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

4. Operatori

vntVar1 = "10.01"
vntVar2 = 11
vntResult = vntVar1 + vntVar2  'vntResult = 21.01 
vntResult = vntVar1 & vntVar2  'vntResult = 10.0111

5. Scope