├── .github
└── FUNDING.yml
├── LICENSE
└── README.md
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | custom: ['https://www.buymeacoffee.com/todar']
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Robert Todar
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # VBA Style Guide()
2 |
3 |
4 |
5 | *A mostly reasonable approach to VBA.*
6 |
7 | > Note: I will be adding to it as I can!
8 |
9 | ## Table of Contents
10 |
11 | 1. [Naming Conventions](#naming-conventions)
12 | 1. [Variables](#variables)
13 | 1. [Functions](#functions)
14 | 1. [Comments](#comments)
15 | 1. [Performance](#performance)
16 | 1. [Design](#design)
17 |
18 | ## Naming Conventions
19 |
20 |
21 | - [1.1](#single--letter--names) Avoid single letter names. Be descriptive with your naming.
22 |
23 | ```vb
24 | ' bad
25 | Public Function Q ()
26 | Dim i as Long
27 | ' ...
28 | End Function
29 |
30 | ' good
31 | Public Function QueryMySQL ()
32 | Dim recordIndex as Long
33 | ' ...
34 | End Function
35 | ```
36 |
37 |
38 | - [1.2](#pascal--case) Use PascalCase as the default naming convention for anything global.
39 | ```vb
40 | ' good
41 | Public Function GreetUser ()
42 | ' ...
43 | End Function
44 | ```
45 |
46 |
47 | - [1.3](#camel--case) Use camelCase for parameters and local variables and functions.
48 |
49 | > [Microsofts convention](https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/program-structure/naming-conventions) is **PascalCase** for everything. The most important thing is to be consistent in whatever convention you use.
50 | ```vb
51 | ' good
52 | Private Function sayName (ByVal name as string)
53 | ' ...
54 | End Function
55 | ```
56 |
57 |
58 | - [1.4](#underscore--case) Do not use underscore case.
59 |
60 | > Why? VBA uses underscores for pointing out events and implementation. In fact, you can't implement another class if the other class has any public methods or properties with an underscore in the name otherwise you will get the error [Bad interface for Implements: method has underscore in name](https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/bad-interface-for-implements-method-has-underscore-in-name).
61 | ```vb
62 | ' bad
63 | Dim first_name as String
64 |
65 | ' good
66 | Dim firstName as String
67 | ```
68 |
69 |
70 | - [1.5](#system--hungarian) Do not use Systems Hungarian.
71 |
72 | > Why? These are useless prefixes that serve no purpose and can obscure the variables name.
73 | ```vb
74 | ' very bad
75 | Dim strString as String
76 | Dim oRange as Range
77 |
78 | ' bad
79 | Dim sName as String
80 | Dim rngData as Range
81 | Dim iCount as Integer
82 |
83 | ' good
84 | Dim firstName as String
85 | Dim queryData as Range
86 | Dim rowIndex as Integer
87 | ```
88 |
89 |
90 | - [1.6](#abbreviations) Do not use abbreviations.
91 | ```vb
92 | ' bad
93 | Public Function GetWin()
94 | ' ...
95 | End Function
96 |
97 | ' good
98 | Public Function GetWindow()
99 | ' ...
100 | End Function
101 | ```
102 |
103 |
104 | - [1.7](#descriptive--names) Be descriptive and use easily readable identifier names. Programming is more about reading code!
105 | ```vb
106 | ' very bad
107 | Dim x As Boolean
108 |
109 | ' bad
110 | Dim scrollableX As Boolean
111 |
112 | ' good
113 | Dim canScrollHorizontally As Boolean
114 | ```
115 |
116 | **[⬆ back to top](#table-of-contents)**
117 |
118 | ## Variables
119 |
120 |
121 | - [2.1](#declare-variables-where-used") Declare and assign variables next to where they are going to be used, but place them in a reasonable place.
122 |
123 | > Why? This makes maintaining the code much easier. When you have a wall of declarations at the top of a procedure it is difficult to modify and refactor if needed. Also, you have to scroll up and down to see if a variable is used or not.
124 | ```vb
125 | ' bad
126 | Private Sub someMethod(ByVal path As String)
127 | Dim fileSystem As Object
128 | Dim folder As Object
129 | Dim files As Object
130 | Dim file As Object
131 |
132 | Set FSO = CreateObject("Scripting.FileSystemObject")
133 | Set folder = FSO.GetFolder(path)
134 | Set files = folder.Files
135 |
136 | For Each file In files
137 | '...
138 | Next
139 | End Sub
140 |
141 | ' good
142 | Private Sub someMethod(ByVal path As String)
143 | Dim FSO As Object
144 | Set FSO = CreateObject("Scripting.FileSystemObject")
145 |
146 | Dim folder As Object
147 | Set folder = FSO.GetFolder(path)
148 |
149 | Dim files As Object
150 | Set files = folder.Files
151 |
152 | Dim file As Object
153 | For Each file In files
154 | '...
155 | Next
156 | End Sub
157 | ```
158 |
159 |
160 | - [2.2](#keep-variables-local) Prefer to keep variables local using the `Private` keyword. We want to avoid polluting the global namespace. Captain Planet warned us of that.
161 | ```vb
162 | ' bad
163 | Public Const FileName as string = "C:\"
164 |
165 | ' good
166 | Private Const fileName as string = "C:\"
167 | ```
168 |
169 |
170 | - [2.3](#no-unused-variables) Disallow unused variables.
171 |
172 | > Why? Variables that are declared and not used anywhere in the code are most likely an error due to incomplete refactoring. Such variables take up space in the code and can lead to confusion by readers.
173 |
174 | ```vb
175 | ' bad
176 | Dim someUnusedVariable as String
177 |
178 | ' good
179 | Dim message as string
180 | message = "I will be used!"
181 | Msgbox Messgae
182 | ```
183 |
184 |
185 | - [2.4](#use-option-explicit) Use [`Option Explicit`](https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/option-explicit-statement) to ensure all variables are explicitly declared.
186 |
187 | ```vb
188 | ' good
189 | Option Explicit
190 |
191 | Sub doSomething()
192 | x = 1 ' Compile error: Variable not defined
193 | End Sub
194 | ```
195 |
196 |
197 | - [2.5](#no-one-line-declarations) Use one `Dim` declaration per variable or assignment.
198 |
199 | > Why? It's easier to read and debug going back. It also prevents variables from accidentally being declared as Variants.
200 |
201 | ```vb
202 | ' very bad
203 | Dim lastRow, lastColumn As Long ' lastRow is a Variant, NOT a long
204 |
205 | ' bad
206 | Dim lastRow As Long, lastColumn As Long
207 |
208 | ' good
209 | Dim lastRow As Long
210 | Dim lastColumn As Long
211 | ```
212 |
213 |
214 | - [2.6](#decalare-variable-types) Declare all variable types explicitly.
215 |
216 | ```vb
217 | ' bad
218 | Dim row
219 | Dim name
220 | Dim cell
221 |
222 | ' good
223 | Dim row As Long
224 | Dim name As String
225 | Dim cell As Range
226 | ```
227 |
228 | **[⬆ back to top](#table-of-contents)**
229 |
230 | ## Functions
231 |
232 |
233 | - [3.1](#functions--mutate-params") Prefer `ByVal` for parameters.
234 |
235 | > Why? Reassigning and mutating parameters can lead to unexpected behavior and errors. `ByRef` is very helpful at times, but the general rule is to default to `ByVal`.
236 |
237 | ```vb
238 | ' bad
239 | Private Function doSomething(name As String) As String
240 |
241 | ' ok
242 | Private Function doSomething(ByRef outName As String) As Boolean
243 |
244 | ' good
245 | Private Function doSomething(ByVal name As String) As String
246 | ```
247 |
248 |
249 | ## Comments
250 |
251 |
252 | - [4.1](#description-header-comment) Above the function should be a simple description of what the function does. Keep it simple.
253 | ```vb
254 | ' Adds new element(s) to an array (at the end) and returns the new array length.
255 | Function PushToArray(ByRef SourceArray As Variant, ParamArray Element() As Variant) As Long
256 | '...
257 | End Function
258 | ```
259 |
260 |
261 |
262 | - [4.2](#doc--comment) Just above the function is where I will put important details. This could be the author, library references, notes, Ect. I've styled this to be similar to [JSDoc documentation](https://devdocs.io/jsdoc/).
263 |
264 | > I've decided to make this the same as JSDoc because there is no reason to recreate the wheel. This is a very known way of documenting and has plenty of documentation and examples already out there. This will keep your code consitent and easy for anyone to understand what is going on.
265 |
266 | ```vb
267 | '/**
268 | ' * Adds new element(s) to an array (at the end) and returns the new array length.
269 | ' * @author Robert Todar
270 | ' * @param {Array} SourceArray - can be either 1 or 2 dimensional array.
271 | ' * @param {...Variant} Element - Are the elements to be added.
272 | ' * @ref No Library references needed =)
273 | ' */
274 | Function PushToArray(ByRef SourceArray As Variant, ParamArray Element() As Variant) As Long
275 | '...
276 | End Function
277 | ```
278 |
279 |
280 | - [4.3](#descriptive--comment) Notes should be clear and full sentences. Explain anything that doesn't immediately make sense from the code.
281 | ```vb
282 | ' Need to check to make sure there are records to pull from.
283 | If rs.BOF Or rs.EOF Then
284 | Exit Function
285 | End If
286 | ```
287 |
288 |
289 | - [4.4](#comment-newline) Add a newline above a comment when the previous code is on same indention level. Otherwise, don't have a line break.
290 | ```vb
291 | ' bad
292 | Private Sub doSomething()
293 |
294 | ' Different indention from line above, no need for newline above.
295 | Application.ScreenUpdating = False
296 | ' Same indention as previous code, must add a newline above to make it easy to read.
297 | Application.ScreenUpdating = True
298 | End Sub
299 |
300 | ' ok
301 | Private Sub doSomething()
302 | ' Different indention from line above, no new line.
303 | Application.ScreenUpdating = False
304 |
305 | ' Same indention as previous code, add a newline above.
306 | Application.ScreenUpdating = True
307 | End Sub
308 | ```
309 |
310 |
311 | - [4.5](#actionitems) Prefixing your comments with `FIXME` or `TODO` helps other developers quickly understand if you’re pointing out a problem that needs to be revisited, or if you’re suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are `FIXME: -- need to figure this out` or `TODO: -- need to implement`.
312 |
313 | **[⬆ back to top](#table-of-contents)**
314 |
315 | ## Performance
316 |
317 |
318 | - [5.1](#avoid-using-select) Avoid using `Select` in Excel. See this [Stackoverflow Post](https://stackoverflow.com/q/10714251/8309643).
319 |
320 | > Why? It slows down code and also can cause runtime errors. `Select` should only be used for visual reasons such as the users next task is doing something in that specific cell.
321 |
322 | ```vb
323 | ' bad
324 | Range("A1").Select
325 | ActiveCell.Value = "Darth Vader"
326 |
327 | ' ok
328 | Dim cell As Range
329 | Set cell = ActiveSheet.ActiveCell
330 | cell.Value = "Lando Calrissian"
331 |
332 | ' good
333 | With Workbooks("Star Wars").Worksheets("Characters").Range("Hero")
334 | .Value = "Luke Skywalker"
335 | End With
336 | ```
337 |
338 | **[⬆ back to top](#table-of-contents)**
339 |
340 | ## Design
341 |
342 | - Functions should be small and do only a single action (think lego blocks).
343 | - Functions should be pure — meaning they should not mutate outside state and always return the same value when given the same inputs.
344 | - Anytime there is a section of code that is separated by a giant comment block, ask yourself if this needs to get extracted into it's own function.
345 |
346 | **[⬆ back to top](#table-of-contents)**
347 |
--------------------------------------------------------------------------------