Visual Basic

Develop a Coupling Strategy

Nonspecified code can often suffer problems caused by tight coupling. Because nonspecified code doesn't form part of a major unit, programmers often pay less attention to its interaction with other parts of the application. Where possible, you should pass parameters into procedures rather than use module-level variables. Input parameters that won't need to be changed should always be declared by value (ByVal) rather than the default, by reference (ByRef). Many programmers choose the by reference method simply because it saves typing.

Another common excuse for using ByRef is the argument of speed: passing by reference is a few milliseconds faster than passing by value because Visual Basic has to create a copy of the variable when it's passed by value. But the consequence of misusing ByRef can be severe in terms of debugging time. Imagine a seldom-used application configuration variable that gets inadvertently changed by another procedure. You might not detect the error until someone uses the configuration function several times-maybe even long after you've written the code. Now imagine trying to trace the cause of the problem! As a rule, always pass parameters by value unless you explicitly want changes to be passed back to the caller.

The purposes of passing parameters to a procedure rather than using module-level variables are to make it obvious to anyone not familiar with the code exactly what external dependencies are being used, and to allow the procedure to be rewritten or reused more easily. A good practice is to document procedure parameters in a header box. A header box is simply a series of comments at the beginning of a procedure that explain the purpose of the procedure. Any external dependencies should also be documented here. Often programmers do not reuse functionality simply because the parameters or dependencies are unclear or not easy to understand. Imagine a procedure that accepts an array containing 20 data items. If the procedure is dependent on all 20 data items being present, other programmers might find it difficult to use unless it is well documented.

Passing parameters to procedures allows you to create code that is loosely coupled and therefore potentially reusable. The following code fragment shows a would-be reusable procedure that is too tightly coupled to the form it's in to be reused anywhere else in that application, let alone in another application:

Sub SearchForFile(ByVal isFile As String)
      ' Disable all buttons.
      cmdClose.Enabled = False
      cmdView.Enabled = False
      ' Process
      .
      .
      .
      labStatus = "File " & isFile
      .
      .
      .

The procedure is rewritten here in a more reusable way:

Sub cmdProcess_Click()
      Dim ctlDisableArray(0 To 1) As Control
      Dim sFile                   As String
      sFile = filename
      ctlDisableArray(0) = cmdClose
      ctlDisableArray(1) = cmdView
      Call SearchForFile(sFile, ctlDisableArray(), labStatus)
      .
      .
      .
  End Sub
  Sub SearchForFile(ByVal isFile As String, _
      Optional ctlDisable() As Control, _
      Optional labUpdate As Label)
      Dim nIndex   As Integer
      ' Disable all buttons if any are specified.
      If Not IsMissing(ctlDisable) Then
          For nIndex = LBound(ctlDisable) To UBound(ctlDisable)
              ctlDisable(nIndex).Enabled = False
          Next nIndex
      End If
      ' Process
      .
      .
      .
      If Not IsMissing(labUpdate) Then
          labUpdate = "File " & isFile
      End If
      .
      .
      .

Now the procedure is totally decoupled and can be called from anywhere in the application.