FileMaker Script Errors, Handled.

Have you ever seen a FileMaker Script that looks like this?


If [ some condition exists // comments about the conditional can go here]
    If [some condition exists]
        If [some condition exists]
            If [some condition exists]
                If [some condition exists]
                Script Step
                Script Step
                If [some other condition exists]
                    Script Step
                    Script Step
                    If [yet another condition]
                        Script Step
                        Script Step
                        Script Step
                        Script Step
                        Script Step
                        Script Step
                        Script Step
                        If [yet another condition]
                            Script Step
                            Script Step
                            Script Step
                            Script Step
                            Script Step
                            Script Step
                            If [still another condition]
                                Script Step
                                Script Step
                                Script Step
                                Script Step
                            Else
                                Script Step
                                Script Step
                                Loop
                                    Perform Script [ "Subscript" ]
                                End Loop
                                Script Step
                                Script Step
                                Script Step
                                Script Step
                                Script Step
                                Script Step
                            End If
                        Script Step
                        Perform Script [ "Subscript with More Conditionals" ]
                        Script Step
                        Script Step
                        Script Step
                        Script Step
                    Else
                        Show Custom Dialog ["Error: something went wrong"]
                    End If
                    Script Step
                    Script Step
                    Script Step
                    Script Step
                    Script Step
                    Script Step
                    Script Step
                    Script Step
                Else If [ some condition here ]
                    Script Step
                Else
                    Show Custom Dialog ["Error: something went wrong"]
                End If
            End If

            Else
                Show Custom Dialog ["Error: something went wrong"]
            End If
        Else
            Show Custom Dialog ["Error: something went wrong"]
        End If
    Else
        Show Custom Dialog ["Error: something went wrong"]
    End If
Else
    Show Custom Dialog ["Error: something went wrong"]
End If

 

I sure have, and admittedly, I've written a few of these myself. The blocks of "If statements" are known to FileMaker developers and programmers in general, as nested conditionals, and perhaps that's because the script often ends up resembling a bird's nest.

This kind of script is usually written when a developer needs to handle complex business logic. I once wrote one of these when a client's solution needed to convert one type of service to another. There were many things that needed to be validated in order for the service to be converted. If any one of those conditions weren't met, the script had to back out of the conversion process and report an error back to the user telling them why the script couldn't be converted.

When I was done, and it worked, I was proud of myself. The client was happy, and I moved on to the next task.

A few years passed. My client's business had changed and they called me with a small change request to this particular script. Ever eager to help, I said, "of course I can do that!"

With my eyebrows furrowed, I opened my script of nested conditionals and went to work. After a few seconds of review, my eyes got a bit wider, then glassy, and at some point they may have crossed. So many ifs. Which one went with which error? It was so hard to read. Where to start making changes? Why hadn't I commented this better?  Or would comments have made it even longer and more confusing?

This script was fragile, and I was scared to break it. But there was no other way, because I had promised my client it could be done. I knew it could. I made the change. Things broke. I fixed them. Other things broke. I fixed those. After rinsing and repeating several more times, it finally it worked.

Phew! Mission accomplished. Yet I felt a bit embarrassed that I had to put my client through so many rounds of bug fixes before it worked correctly. Even with the Script Debugger, it had been difficult to find and fix bugs. Aside from that, I never wanted to write a script so fragile again! If reading and editing my own code was this difficult, this was not the way I wanted to do it. 

I tried to imagine what it would have been like if another developer had written the script. Well, I found out when I was working on a huge FileMaker solution for a large corporation that had been built by 6 or 7 developers over 15-20 years. It's next to impossible to decipher and modify another developer's nested conditionals. Not only is the script fragile, unless it was commented carefully and updated every time it was modified (how often does that happen?), you don't even have the benefit of knowing what the person was thinking when it was written.

I tilted my head to the right, contemplating how to avoid this going forward. And then I realized:

Nested conditionals are a house of cards laying on its side. The more levels you add, the more precarious it gets.

Filemaker Nested Conditionals are Like a House of Cards

Lesson learned: avoid nested conditionals for cleaner, more readable code. 

When FileMaker development gets challenging and a good reference for software best practices is needed, I often ask myself, "What would WebObjects do?" (WebObjects is an object-oriented web application framework I learned years ago. It was created by Next/Apple, so I know it's smarter than me.) WebObjects, like most smart object-oriented web application frameworks, had a way of handling errors that makes it easier to debug. One key idea from that model that could be helpful to FileMaker scripting, which is not structured as an object-oriented language, is that each script logs and returns its own errors, and identifies where the error came from. 

So here's how we do it now, as part of our larger FileMaker development framework:

  1. "Stack" conditionals instead of nesting them.
  2. Check and collect errors along the way.
  3. At the end of the script, handle the error(s).

When the above approach is employed, the script will transform from the house of cards above to a friendly neighborhood of stable, brick ranch houses which, in the FileMaker Script Workspace, looks something like this:


# Use a variable called "errorLog" (or just "error") to hold the errors. Before beginning the script, assign the errorLog variable to an error if any of the validation requirements for the task are not met. For example:

Set Variable [ $errorLog ; 
    Case ( 
        condition 1 ; "Error: can't do it because condition 1 was not met." ; 
        condition 2 ; "Error: can't do it because condition 2 was not met." ; 
        condition 3 ; "Error: can't do it because condition 3 was not met." ; 
        condition 4 ; "Error: can't do it because condition 4 was not met." ; 
        condition 5 ; "Error: can't do it because condition 5 was not met." 
    )
]

# Then, check to make sure the errorLog variable is empty before each "stacked" conditional, and append any subsequent errors to the errorLog variable.


If [ IsEmpty ( $errorLog ) and nextCondition ]

    Script Step
    Script Step
    Script Step
    Script Step
Else

    Set Variable ( $errorLog ; $errorLog & "Insert your error message here." )

EndIf

If [ IsEmpty ( $errorLog ) and nextCondition ]

    Script Step
    Script Step
    Script Step
    Script Step
    Script Step
    Script Step
Else

    Set Variable ( $errorLog ; $errorLog & "Insert your error message here." )
    
EndIf

If [ IsEmpty ( $errorLog ) and nextCondition ]

    Script Step
    Script Step
    Script Step
    Script Step
Else

    Script Step
    Script Step
    Loop
        # Perform A Subscript with Stacked Conditionals that Returns a $resultError variable if something went wrong 
        Perform Script ( "Smart Subscript with Error Result" )
        Set Variable ( $errorLog ; #Assign ( $resultError ) )
        Exit Loop If [ something is true ]
    End Loop
EndIf

If [ IsEmpty ( $errorLog ) and nextCondition ] 
    Script Step
    Script Step
    Script Step
    Script Step
    Script Step
    Script Step
End If

# If appropriate, report the error(s) captured to the user

If [ Length ( $errorLog ) ] 

    Show Custom Dialog ( "An Error Occurred" ; $errorLog )

EndIf


Exit Script [ #( "resultError" ; $errorLog ) & #( "resultSource" ; Get ( ScriptName ) ) ]

Note: The Exit Script [] script step at the end of the code snippet above uses a custom function named #, originally created by Jereme Bante, which allows multiple parameters to easily be passed into a script via FileMaker's script parameter and out of a script using FileMaker's script result. If you're intrigued, you can read more about that here: http://filemakerstandards.org/pages/viewpage.action?pageId=557462. It should also be noted that a second custom function that converts the name-value pairs in the string of # functions parameter into actual FileMaker variables. That custom function is called #Assign in the example above, and it's used to convert the script result sent by the "Exit Script" step in the subscript. If nothing in this italicized paragraph makes sense, don't worry - the point is that subscripts should send any error(s) captured in the subscript back to the calling script so the calling script can handle them appropriately. You can make that happen any way you want.
 

And There You Have It: FileMaker Script Errors, Handled.

Changing the way these complex scripts are written to a "stacked" conditional format rather than a nested conditional format has provided the following benefits:

  • "Cleaner," more readable scripts. (Less scrolling and getting lost reading the script from left to right.)
  • More easily readable comments.
  • Scripts that can withstand modification without breaking what was there.
  • Simpler debugging and easier-to-maintain code.
  • Fewer embarrassing moments with clients. 

 

That's all for this post, folks! I hope this helps somebody. If it helped you, or if you have questions, comments, or confusion, let a gal know by sending me a note through our contact us page.