Access JumpStart 2.0 | Blog

A Rapid Development Framework for Microsoft Access

The title is a line from an episode of Uncle Bob’s clean code video series. He advocates refactoring until you get down to 3 lines of code per function and make sure every function is doing one thing and is clearly named. At least that’s what I got out of it. I like his approach on this. So part of Test Driven Development in the coding to make the test pass phase is to do whatever is simplest and easiest to get the test to pass. Well, maybe with some caveats, although I’m not sure what they are right at the moment, but I’ll let you know as I think of them.

So, what did I write that I want to refactor? This:

Private Sub FormToAudit_BeforeUpdate(Cancel As Integer)
    Dim OldValue As Variant, NewValue As Variant, AddChange As Boolean
    OldValue = FormToAudit.TestText.OldValue
    NewValue = FormToAudit.TestText.Value
    
    If IsNull(OldValue) And Not IsNull(NewValue) Then
        AddChange = True
    ElseIf Not IsNull(OldValue) And IsNull(NewValue) Then
        AddChange = True
    ElseIf IsNull(OldValue) And IsNull(NewValue) Then
        AddChange = False
    Else
        If FormToAudit.TestText.OldValue <> FormToAudit.TestText.Value Then
            AddChange = True
        End If
    End If
    If AddChange Then
        pListOfChanges.Add FormToAudit.TestText.Value
    End If
End Sub

I don’t like this giant if else set of structures I added to this function. So what can I do? How about extracting the boolean tests to some functions…

Private Sub FormToAudit_BeforeUpdate(Cancel As Integer)
    If FieldChanged(FormToAudit.TestText) Then pListOfChanges.Add FormToAudit.TestText.Value
End Sub

Private Function FieldChanged(Field As Access.Control) As Boolean
    Dim OldValue As Variant, NewValue As Variant, retVal As Boolean
    OldValue = Field.OldValue
    NewValue = Field.Value
    If IsNull(OldValue) And Not IsNull(NewValue) Then
        retVal = True
    ElseIf Not IsNull(OldValue) And IsNull(NewValue) Then
        retVal = True
    ElseIf IsNull(OldValue) And IsNull(NewValue) Then
        retVal = False
    Else
        If FormToAudit.TestText.OldValue <> FormToAudit.TestText.Value Then
            retVal = True
        End If
    End If
    FieldChanged = retVal
End Function

Ok, so the original BeforeUpdate module is now SUPER clean. It checks the function FieldChanged, passing the field and it looks much nicer. I’ve now moved most of the code into it’s own function. Before continuing to refactor, let’s make sure I didn’t break anything by running the tests:

Yay, so I think I can make the new function FieldChanged much cleaner as well. Let’s see:

Private Function FieldChanged(Field As Access.Control) As Boolean
    Dim retVal As Boolean
    If OnlyOneFieldIsNull(Field.OldValue, Field.Value) Then
        retVal = True
    ElseIf IsNull(Field.OldValue) And IsNull(Field.Value) Then
        retVal = False
    Else
        If Field.OldValue <> Field.Value Then
            retVal = True
        End If
    End If
    FieldChanged = retVal
End Function

Private Function OnlyOneFieldIsNull(OldValue As Variant, NewValue As Variant) As Boolean
    Dim retVal As Boolean
    retVal = (IsNull(OldValue) = True And IsNull(NewValue) = False) Or (IsNull(OldValue) = False And IsNull(NewValue) = True)
    OnlyOneFieldIsNull = retVal
End Function

Well, it’s getting better, but I need to do more. Tomorrow… Thanks for joining me!