Ottimizzazione del codice

Ultima modifica: 28-05-2016

Si legge in alcune guide che quello a cui dobbiamo tendere nel compilare il codice è la dimensione e la velocità dell'applicativo che stiamo realizzando.

Molto spesso, tuttavia non si possono ottenere entrambe le cose e bisogna scendere a compromessi: scegliere tra la dimensione del file e la velocità di esecuzione.

Attenzione:

è ovvio che quando il codice è breve e gli elementi da calcolare o da elaborare sono pochi il problema non sussiste: qualsiasi soluzione è buona. Ma quando il codice è abbondante ed altrettanto numerosi sono gli elementi da elaborare occorre operare delle scelte.

Velocità di esecuzione

A volte usando dei semplici accorgimenti possiamo migliorare la scrittura e l'esecuzione del nostro codice. Quel che viene scritto qui di seguito vuole essere, se ci riesco, solo una guida per impostare alla meglio il nostro modo di scrivere del codice a prescindere che lo scriviamo per noi o per terze persone.

Blocchi di istruzioni

Cercare di evitare di scrivere blocchi di istruzioni in procedure (Sub) al di fuori dell'istruzione For ... Next se questo esegue molti cicli.

Certamente l'esecuzione del codice con le impostazioni date nel riquadro 1 risulta più veloce di quello impostato come nel riquadroi 2 che richiama le istruzioni che sono nel riquadro 3

riquadro1 riquadro2 riquadro 3
Private Sub UserForm_Activate()
For i = 1 To 10000
' qui il blocco di istruzioni
Next
End Sub
Private Sub UserForm_Activate()
For i = 1 To 10
FaiQualcosa   'viene richiesta l'esecuzione della routine FaiQualcosa
Next
End Sub
Sub FaiQualcosa()
' qui il blocco di istruzioni
End Sub

Istruzioni in un ciclo For ... Next

Altro metodo per velocizzare l'esecuzione di blocchi di istruzioni messe in cicli è quello di stabilire dove scrivere determinate istruzioni, ma questa è anche una norma dettata dalla semplice logica oltre che dalle norme sulla velocizzazione dell'esecuzione del codice.

Vediamo la procedura istruita nei riquadri 4 e 5.

Dobbiamo esaminare un certo numero di celle e controllare se sono dello stesso colore della cella A1

Osservando, infatti, il costrutto presentato nel riquadro 4 notiamo che la istruzione evidenziata in rosso occupa una posizione non corretta in quanto continuando a leggere la proprietà della cella "A1" in ciascuno dei cicli For ... Next non facciamo altro che rallentare l'esecuzione delle istruzioni. Questa lettura viene eseguita 200 x 50 volte.

Più corretto sembra il costrutto del riquadro 5. Qui infatti la lettura della proprietà della cella "A1" avviene una sola volta, al di fuori delle istruzioni For ... Next ed i successivi confronti sortiscono senz'altro lo stesso effetto ma con un notevole risparmio di tempo.

riquadro4 riquadro5

Sub provaletturacolore()
For i = 1 To 200
For b = 1 To 50
A = Range("A1").Interior.ColorIndex
If Cells(i, b).Interior.ColorIndex = A Then
Cells(i, b) = "Stesso colore della A1"
End If
Next
Next
End Sub

Sub provaletturacolore()
A = Range("A1").Interior.ColorIndex
For i = 1 To 200
For b = 1 To 50
If Cells(i, b).Interior.ColorIndex = A Then
Cells(i, b) = "Stesso colore della A1"
End If
Next
Next
End Sub

Viceversa, se la proprietà o il contenuto di una determinata cella ha una qualche possibilità di cambiare durante l'esecuzione della routine, sarebbe allora lecito, anzi obbligatorio, adottare la forma usata nel riquadro 4 come nell'esempio dell'ordinamento proposto nel riquadro 6:

riquadro6

For I = 1 To NumMax - 1
B = Cells(I, 1) ' Errato
For A = I + 1 To NumMax
B = Cells(I, 1) ' Esatto perché il valore nella cella indicata potrebbe variare durante il ciclo
If Cells(A, 1) > B Then
Numero = Cells(I, 1)
Cells(I, 1) = Cells(A, 1)
Cells(A, 1) = Numero
End If
Next
Next

Variabili o Oggetti

Quando è possibile è consigliabile lavorare con una variabile a cui si assegna un valore di una qualsiasi proprietà di un oggetto anziché lavorare direttamente sull'oggetto stesso.

Infatti nel riquadro 4 avremmo potuto scrivere anche:

riquadro6

For I = 1 To NumMax - 1
For A = I + 1 To NumMax
If Cells(A, 1) > Cells(I, 1) Then
Numero = Cells(I, 1)
Cells(I, 1) = Cells(A, 1)
Cells(A, 1) = Numero
End If
Next
Next

ma lavorare su una variabile risulta senz'altro più veloce.

B = Cells(I, 1)

If Cells(A, 1) > B Then

Quando gli elementi da elaborare sono numerosi non possiamo ovviamente usare semplici variabili ma sarà il caso di far ricorso alle Matrici.

Specificare il tipo di variabili

Anche se l'uso di variabili di tipo Variant è molto più comodo da gestire da parte del programmatore tuttavia, dove il fattore tempo è critico, è preferibile usare variabili di tipo appropriato per non affaticare inutilmente il VBA.

A tal proposito ci viene incontro l'istruzione Dim per dichiarare le variabili con il proprio tipo.

Dim A As Long

Attenzione:

quando si dichiarano più variabili è facile incorrere in un errore di logica molto frequente come in questo caso:

Dim A, X, Y As Long

le variabili A - X, dopo una tale dichiarazione, risultano ancora di tipo Variant mentre la sola variabile Y viene dichiarata Long.

Per ottenere che tutte le variabili siano di tipo Long bisogna dichiararle singolarmente come tali:

Dim A As Long, X As Long, Y As Long

Dimensione del file

Ove possibile occorre curare anche questo aspetto: se il codice da scrivere è particolarmente corposo, occorre cercare se ci sono dei passaggi o delle istruzioni superflue o ripetute.

Istruzioni che evocano degli eventi

Evitare ripetizioni di codice

In alcune circostanze alcune istruzioni si rivelano inutili, se non dannose.

Quando una istruzione scatena un evento legato a un altro controllo che esegue alcune istruzioni, è inutile scrivere dopo tale istruzione quelle già usate nella routine di evento del controllo evocato.

Ma facciamo un esempio altrimenti non riesco a farmi capire.

In una UserForm come questa vogliamo che, premendo uno dei quattro pulsanti adibiti alla navigazione, o facendo la scelta direttamente dalla comboBox, vengano visualizzati: il Nome dell'elemento nella ComboBox, il codice e le altre voci relative all'elemento scelto nelle apposite caselle di testo.

Non sto ora a spiegare anche le tecniche usate per rintracciare le coordinate degli elementi e perché fra le tante io prediligo (almeno per il momento) quella che userò qui di seguito. Se ne parlerà a tempo debito.

Per ogni controllo ci verrebbe da scrivere qualcosa del genere:


Private Sub ComboBox1_Change()
' la reazione della ComboBox ai cambiamenti subiti
If ComboBox1.ListIndex = -1 Then Exit Sub
Riga = ComboBox1.ListIndex + 4 ' rintraccio la coordinata di riga
Cells(Riga, 1).Select ' queste le istruzioni da compiersi
TextBox1.Text = Cells(Riga, 1)
TextBox2.Text = Cells(Riga, 6)
TextBox3.Text = Cells(Riga, 11) * -1

End Sub


Private Sub CommandButton3_Click()
' PRIMO
' modifico la ListIndex della ComboBox provocandone l'attivazione

ComboBox1.ListIndex = 0
Riga = ComboBox1.ListIndex + 4 ' rintraccio la coordinata di riga
Cells(Riga, 1).Select ' queste le istruzioni da compiersi
TextBox1.Text = Cells(Riga, 1)
TextBox2.Text = Cells(Riga, 6)
TextBox3.Text = Cells(Riga, 11) * -1

End Sub


Private Sub CommandButton4_Click()
' ULTIMO
' modifico la ListIndex della ComboBox provocandone l'attivazione

ComboBox1.ListIndex = ComboBox1.ListCount - 1
Riga = ComboBox1.ListIndex + 4 ' rintraccio la coordinata di riga
Cells(Riga, 1).Select ' queste le istruzioni da compiersi
TextBox1.Text = Cells(Riga, 1)
TextBox2.Text = Cells(Riga, 6)
TextBox3.Text = Cells(Riga, 11) * -1

End Sub


Private Sub Image1_Click()
' GIU
If ComboBox1.ListIndex < ComboBox1.ListCount - 1 Then
' modifico la ListIndex della ComboBox provocandone l'attivazione
ComboBox1.ListIndex = ComboBox1.ListIndex + 1
End If
Riga = ComboBox1.ListIndex + 4 ' rintraccio la coordinata di riga
Cells(Riga, 1).Select ' queste le istruzioni da compiersi
TextBox1.Text = Cells(Riga, 1)
TextBox2.Text = Cells(Riga, 6)
TextBox3.Text = Cells(Riga, 11) * -1

End Sub


Private Sub Image2_Click()
' SU
If ComboBox1.ListIndex > 0 Then
' modifico la ListIndex della ComboBox provocandone l'attivazione
ComboBox1.ListIndex = ComboBox1.ListIndex - 1
End If
Riga = ComboBox1.ListIndex + 4 ' rintraccio la coordinata di riga
Cells(Riga, 1).Select ' queste le istruzioni da compiersi
TextBox1.Text = Cells(Riga, 1)
TextBox2.Text = Cells(Riga, 6)
TextBox3.Text = Cells(Riga, 11) * -1

End Sub

Ma, come già evidenziato nei frammenti di codice evidenziati in rosso non è necessario, anzi è da evitare, scrivere tutto quel codice in abbinamento ai controlli adibiti alla navigazione perché è sufficiente che questi modifichino lo stato della ComboBox per attivarla e far compiere a questa tutte quelle istruzioni.

Ridurre ulteriormente il codice

Alcune volte capita di progettare applicativi abbastanza complessi ed articolati. Utilizziamo molte procedure e molte UserForm e capita che molti blocchi di istruzioni vengano più volte ripetuti.

In questi casi è possibile, anzi consigliabile, sempre compatibilmente col discorso fatto nel paragrafo Blocchi di istruzioni, invece di scrivere più volte lo stesso blocco di istruzioni, metterlo in una procedura a parte e quando serve basta semplicemente richiamare la procedura che contiene il blocco di istruzioni.

In questo esempio ogni volta che dobbiamo leggere o scrivere in un determinato settore del foglio, dobbiamo individuarne le coordinate. Questa azione viene eseguita in più parti cel codice. Allora, dove serve, ricorriamo alla routine DeterminaSettore

Private Sub CommandButton1_Click()
DeterminaSettore
UserForm1.Show
End Sub


Sub DeterminaSettore()
Prima1 = 4
Riga = Prima1
While Cells(Riga, 1) <> ""
Riga = Riga + 1
Wend
URiga1 = Riga
NumArt = URiga1 - Prima1
End Sub

In questa Sub viene individuata l'area di lavoro e vengono inizializzate le variabili che serviranno in seguito per spostarsi nell'archivio a partire dalla prima riga (Prima1) all'ultima (URiga1) e in base al numero di righe contate si determina anche il numero di articoli presenti in archivio.

Ovviamente, a chiusura di tutto quanto il discorso, c'è da puntualizzare che non c'è una regola precisa per prendere una o l'altra soluzione. Tutto va fatto secondo una logica personale e soggettiva. Ove c'è da scegliere se è meglio optare per una economia di spazio (quindi di peso del file) o di tempo spetta sempre a noi ponderare bene i due aspetti.

Quanto è stato detto finora serve solo a farci riflettere che sia che il codice da scrivere è molto limitato, sia che è lungo ed articolato, importante è solo avere le idee chiare e serve come spunto per abituarci, in ogni caso, ad affinare la nostra tecnica di programmazione.

 

 

Buon lavoro!