# FileMaker Fail Early

**URL:** <https://the.fmsoup.org/t/filemaker-fail-early/4128>\
**Category:** Floating Topics\
**Created:** [May 18, 2024, 4:22pm UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128 "2024-05-18T16:22:05Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![tonywhitelive](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/tonywhitelive/32/208_2.png) [@tonywhitelive](https://the.fmsoup.org/u/tonywhitelive)\
**Post date:** [May 18, 2024, 4:22pm UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/1 "2024-05-18T16:22:05Z")

</div>

There is a principal in software design called "Fail Early”, "Fail Fast", or "Fail Early, Fail Fast”. For this post, I am going to use the term “FileMaker Fail Early” to share some thoughts about how this principal applies to FileMaker software development...

Let us look at the common use case where a user clicks a Button on a Layout that runs a Script. For the Script to succeed, there might be a number of conditions that must be true, for example, there might be:

- Object Names that the Script references
- Fields that must be empty (or not empty)
- Related records that must be present (or not present)
- Required Plugin(s) (with versions)
- Feel free to add your favorites below
- Users privileges. // thanks @harvest
- Hidden errors that show up when you commit record // thanks @mrwatson-de
- Share points are mounted // new, from yours truly

A “FileMaker Fail Early” strategy lets us keep our Script as simple as possible by failing (dare I say Halt Script'ing) before we change state...

1. Layout
2. Window(s)
3. Found Set
4. Etc.

…and then needing to "clean up".

We are polishing and updating our “FileMaker Fail Early” Scripts. Below is one:

 ![image](https://canada1.discourse-cdn.com/flex030/uploads/fmsoup/original/2X/8/8e5018e795ef73fc4c9af170592f0ada5f81eff1.png)

1. Which of the 3 lines do you prefer: 8, 9, or 10?
2. What do you think of the Script name?
3. Other thoughts?

Considering that we put this Script in almost every File, how would you comment?

- Comment each section in the script in-line
- Single line comment at the top
- Let the Script name be the comment
- Link to a web page that documents all the “ **FileMaker Fail Early** ” Scripts
- Other?

This post is, in part, a followup on this presentation  
DIGFM: Code Review, ♫ It's Getting Better All the Time ♬ (5/9/2024)  
[https://www.youtube.com/watch?v=oPZ\_sJHVHVM&t=2288s](https://www.youtube.com/watch?v=oPZ_sJHVHVM&t=2288s)

The goal of the presentation was to show some good code and some bad code...easy to do if you [don't] think about it 😉

"Failure is an option” — unless you are watching a movie

---

<div class="post-metadata">

**Author:** ![tonywhitelive](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/tonywhitelive/32/208_2.png) [@tonywhitelive](https://the.fmsoup.org/u/tonywhitelive)\
**Post date:** [May 18, 2024, 5:02pm UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/2 "2024-05-18T17:02:18Z")

</div>

Here is an example of how the above Script might be called:

 ![image](https://canada1.discourse-cdn.com/flex030/uploads/fmsoup/original/2X/a/ab535f660763ceb3c86fa82de318bb187e555e30.png)

---

<div class="post-metadata">

**Author:** ![mrwatson-de](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/mrwatson-de/32/351_2.png) [@mrwatson-de](https://the.fmsoup.org/u/mrwatson-de)\
**Post date:** [May 18, 2024, 10:32pm UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/3 "2024-05-18T22:32:41Z")

</div>

Fail early is a great philosophy!

It's MUCH better to fail in the hands of the developers than the customers! Support time is gold!

You, of course, can say HALT SCRIPT! In some cases it is a much more desirable result than the consequences of NOT halting!

For example, we have a FAIL FAST & halt early script to create a record. It checks to see if it failed - which happens if somebody had locked the table by working live on the schema - and retries for a short time and then gives up and halts the script.

Although this is an unpleasant outcome for the user - and the data - it is by far a lesser evil than the new record step quietly failing and the rest of the script continuing to work on some random record, whatever was currently in focus before the script started!

---

<div class="post-metadata">

**Author:** ![Malcolm](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/malcolm/32/196_2.png) [@Malcolm](https://the.fmsoup.org/u/Malcolm)\
**Post date:** [May 19, 2024, 7:23am UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/4 "2024-05-19T07:23:02Z")

</div>

if the script is going everywhere, or being used a lot, then that construction would be better placed into a custom function, no?

Calling LayoutObjectExists( objectName ) seems easier than writing all that code many times over.

---

<div class="post-metadata">

**Author:** ![tonywhitelive](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/tonywhitelive/32/208_2.png) [@tonywhitelive](https://the.fmsoup.org/u/tonywhitelive)\
**Post date:** [May 19, 2024, 3:29pm UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/5 "2024-05-19T15:29:31Z")

</div>

Thanks for your thoughts...

A single Script per File that is called from many Scripts is a good architecture (IMO).

A script is needed to Show a Custom Dialog and sometimes to perform a subscript. A single Script does it all.

I would say that a Custom Function is not called for in this case because:

- A single Script per File is already "Don't Repeat Yourself" (DRY)
- Using a Custom Function would introduce a dependency and thereby reduce portability.
- We would have 2 code objects (Script + CF) instead of one (Script) = more complex
- There is not much complexity to encapsulate, especial after we remove at least 2 lines as noted above.

Here are some thoughts on Custom Functions from the same presentation:

DIGFM: Code Review, ♫ It's Getting Better All the Time ♬ (5/9/2024)  
[https://www.youtube.com/watch?v=oPZ\_sJHVHVM&t=6247s](https://www.youtube.com/watch?v=oPZ_sJHVHVM&t=6247s)

---

<div class="post-metadata">

**Author:** ![planteg](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/planteg/32/627_2.png) [@planteg](https://the.fmsoup.org/u/planteg)\
**Post date:** [May 19, 2024, 8:50pm UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/6 "2024-05-19T20:50:32Z")

</div>

Thank you all for that discussion,

this topic is of great interest. I never heard of "fail early" before, but that make a lot of sense !

---

<div class="post-metadata">

**Author:** ![harvest](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/harvest/32/231_2.png) [@harvest](https://the.fmsoup.org/u/harvest)\
**Post date:** [May 20, 2024, 5:56pm UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/7 "2024-05-20T17:56:16Z")

</div>

Hi Tony,

while I hadn't put a name to it I try to follow similar patterns for scripting.

I try to cover as much as possible of the pre-checking routines before touching anything like changing the layout, entering fields etc. too.

First is always a check for the users privileges.

Second is a part of the scriptparameter that already covers prechecks if the button calling the scipt is pushed like looking for related records needed.

Third is looking for an error message coming from a previous run of the triggered script that got initiated by unsucessfully entering data that failed plausibility checks and the likes

In case or CRUD scripts I go for the deletion part next asking the user to again state his intention and than turn data ( and related data ) invalid

...so getting the low hanging fruit first and of course give as much meaningful response messages as possible to the user.

and by the way I would opt for line 8 because I like the longer approach that will help anybody taking my programming at some point in the future to better understanding and it gives me more opportunities maybe not in this case but in more complicated scenarios

best  
Holger

---

<div class="post-metadata">

**Author:** ![tonywhitelive](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/tonywhitelive/32/208_2.png) [@tonywhitelive](https://the.fmsoup.org/u/tonywhitelive)\
**Post date:** [May 20, 2024, 7:05pm UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/8 "2024-05-20T19:05:32Z")

</div>

Thank you for your thoughtful answers.

> [@harvest](#):
>
> First is always a check for the users privileges.

Good catch, we do that too.

> [@harvest](#):
>
> Third is looking for an error message coming from a previous run of the triggered script that got initiated by unsucessfully entering data that failed plausibility checks and the likes

We sometimes commit the record to bring forward any errors lurking in uncommitted changes from previous actions that are not related to the Script we are about to run.

> [@harvest](#):
>
> In case or CRUD scripts I go for the deletion part next asking the user to again state his intention and than turn data ( and related data ) invalid

Cool.

> [@harvest](#):
>
> and by the way I would opt for line 8 because I like the longer approach that will help anybody taking my programming at some point in the future to better understanding and it gives me more opportunities maybe not in this case but in more complicated scenarios

Thank you for voting and providing a reason for your vote!

---

<div class="post-metadata">

**Author:** ![bdbd](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/bdbd/32/620_2.png) [@bdbd](https://the.fmsoup.org/u/bdbd)\
**Post date:** [May 20, 2024, 9:15pm UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/9 "2024-05-20T21:15:14Z")

</div>

Just about every script we create at D-Cogit goes through these steps:

- Initialization;
- Validation;
- Script logic;
- Cleanup;
- Return.

The "fail early" principal would be handled in the validation step. That said, we don't use a set strategy during validation. Each script has its own needs, therefore validation is specific to each script. Of course we use core scripts and custom functions to handle repetitive routines.

We also do our best to use the MVC (model-view-controller) design pattern. We have scripts for layouts / menus (view), for business logic (controller) and for data (model). The "fail early" strategy is not always possible because some error-checking is limited to specific domains (model, view or controller).

Lastly, our script code is structured such that execution always starts at the start of the code and always ends at the end of the code. Exiting anywhere else is prohibited. Halting is prohibited because it can have unintended consequences in MVC.

Hope this helps!

---

<div class="post-metadata">

**Author:** ![tonywhitelive](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/tonywhitelive/32/208_2.png) [@tonywhitelive](https://the.fmsoup.org/u/tonywhitelive)\
**Post date:** [May 23, 2024, 4:28pm UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/10 "2024-05-23T16:28:07Z")

</div>

Updated the original post to add 3 conditions to check early:

- Users privileges. // thanks @harvest
- Hidden errors that show up when you commit record // thanks @mrwatson-de
- Share points are mounted // added by me...better late than never!

---

<div class="post-metadata">

**Author:** ![mrwatson-de](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/mrwatson-de/32/351_2.png) [@mrwatson-de](https://the.fmsoup.org/u/mrwatson-de)\
**Post date:** [May 24, 2024, 4:47pm UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/11 "2024-05-24T16:47:11Z")

</div>

More fail fast tactics:

- my fail first programming ethic is **catch early**!

So early, in fact, that I never allow some bugs to even get into the database, specifically:

- we use Mac + MBS plugin and fmSyntaxColorizer to catch steps at the coding stage. Before the script is even run.

- the most important feature is MBS variable checking which highlights all variables which are used but not defined

- fmSyntaxColorizer also highlights interactive steps (with dialog, pause or with halt), so that you notice more easily and quickly that you've forgotten to turn of an `Enter Find Mode` pause or similar.

Another technique I use to fail fast by catching quickly is to avoid long `if` blocks with an `else` block off the page.

If the error handling is a few lines to just log an error, show a dialog maybe with an exit or halt, I prefer to put the error handling **first** , and the longer ' normal' part of the process in the Else block.

Like this, when you see the else block, you can still see the If condition on the page and thus know instantly when the else block is performed/what it is for.

If you program the other way round - preferring to have the main flow first and the edge cases / error handling last (which does have its merits) this can - _particularly_ if you have (lots of) nested `if`s - lead to a string of else-error blocks and way disconnected from their branching logic.

Such code can quickly lead to errors like this:

```auto
If A ok
  If B ok
    # do stuff
    # do stuff
    # do stuff
    # do stuff
    # do stuff
    # do stuff
    # do stuff
    # do more stuff
    # do more stuff
    # do more stuff
    # do more stuff
    # do more stuff
    # do more stuff
    # do more stuff
    # do more stuff
    # do more stuff
    # do more stuff
    # do more stuff
    # do even more stuff
    # do more stuff
    # do more stuff
    # do more stuff
    # do even more stuff
    # do more stuff
    # do more stuff
    # do more stuff
    # do even more stuff
    # do more stuff
    # do more stuff
    # do more stuff
    # do even more stuff
  else
    Error A
  End if
else
  Error B
End if

```

The other disadvantage of this structure is that the errors are in _reverse order_ , when programmed like this correctly - which is illogical, hard to check when scrolling up and down and checking indentation level - and a really unnecessary brain strain!

The other way round is `MUCH` easier to read, code and to see (I.e. catch/ avoid) errors AND can mostly be flattened into a single simple If Else If Switch construct:

```auto
If A NOT ok
    Error A
else If B NOT ok
  Error B
else
    # Ready to go …
    # do stuff
    # do stuff
    # do stuff
    # do stuff
End If

```

If there is no clean up code, it is also possible to code this as **guard clauses** , which exit the script before you have started.

```auto
If A NOT ok
    Error A
    Exit Script 
else If B NOT ok
  Error B
    Exit Script 
End If

# Ready to go …
# do stuff…

```

Or the even more compact version (my fav)

```auto
Set Variable [$errMsg ; List (
  Case ( not A ok ; "Error A" ) ;
  Case ( not B ok ; "Error B" ) ;
  …
  )) ]
If [ not IsEmpty ( $errMsg )
    Exit Script [$errMsg]
End if

# Ready to go …
# do stuff…

```

I also use fmLogAnalyser to catch pasting errors logged in the FileMaker import.log file before they go unnoticed!

Conclusion:

- Fail fast by catching the errors at coding time!
- Don't let the bugs in! // = Google my presentation on this topic (Rome? Dotfmp? Somewhere😂)

---

<div class="post-metadata">

**Author:** ![rivet](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/rivet/32/1727_2.png) [@rivet](https://the.fmsoup.org/u/rivet)\
**Post date:** [May 25, 2024, 12:40am UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/12 "2024-05-25T00:40:47Z")

</div>

I have a two-line error check at various points that will exit right at fail point

```auto
	Loop

		…
		Set Variable [$error ; Value: Case( Get( LastError ) > 0; JSONSetElement( ""; [ "code"; Get( LastError ); JSONNumber]; ["message"; "foo"; JSONString] ) ) ] 
		Exit Loop If [JSONGetElement ( $error ; "code" ) > 0] 

		…
		Set…
		Exit…

		Exit Loop If [True] 
	End Loop

# clean-up
If [JSONGetElement ( $error ; "code" ) > 0] 
	
	Revert Record/Request [With dialog: Off] //error
	Set Variable [$result ; Value: JSONSetElement ( "" ; ["error" ; $error ; JSONObject] ; ["data" ; "{}" ; JSONObject] ) ] 

Else
	
	Commit Records/Requests [With dialog: Off] //success 
	Set Variable [$result ; Value: JSONSetElement ( "" ; ["error.code" ; 0 ; JSONNumber] ; ["error.message" ; "success" ; JSONString] ; ["data" ; "{}" ; JSONObject] ) ] 
	 
End If

Exit Script [Text Result: $result] 

```

---

<div class="post-metadata">

**Author:** ![jwilling](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/jwilling/32/256_2.png) [@jwilling](https://the.fmsoup.org/u/jwilling)\
**Post date:** [May 26, 2024, 6:14pm UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/13 "2024-05-26T18:14:29Z")

</div>

This is the way!

And if you encapsulate that error authoring/detecting logic, you can even do:

```bash
Loop
    …
    Exit Loop If [Let ( $error = Error.Last ( "foo" ) ; Error.IsError ( $error ) )]

    // I actually go further and allow the CF to magically populate $error, and avoid that boilerplate, but magic is controversial.
    …
    Exit Loop If [Error.CheckLast ( "foo" )] // sets $error and returns true if is error

    Exit Loop If [True]
End Loop

If [ Error.IsError ( $error )
    // handle error
End If

// Bubble it up!
Exit Script [JSONSetElement ( "{}" ; "error" ; $error ; JSONObject )]

```

---

<div class="post-metadata">

**Author:** ![tonywhitelive](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/tonywhitelive/32/208_2.png) [@tonywhitelive](https://the.fmsoup.org/u/tonywhitelive)\
**Post date:** [June 25, 2024, 4:06pm UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/14 "2024-06-25T16:06:17Z")

</div>

Here is Script that we call as many times as needed to check that a field is NOT empty. For example, it takes 10 lines in the calling script to check 10 fields and get field specific feedback (keeps the calling script short and easy to read).

This one is part of a suite that can check for Empty, Not Empty, = 0, \> 0, etc., etc.

 ![image](https://canada1.discourse-cdn.com/flex030/uploads/fmsoup/original/2X/8/8597c8cbe3bb7dfa90ea6f6549e968eacd910c92.png)

---

<div class="post-metadata">

**Author:** ![tonywhitelive](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/tonywhitelive/32/208_2.png) [@tonywhitelive](https://the.fmsoup.org/u/tonywhitelive)\
**Post date:** [October 26, 2024, 11:17pm UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/15 "2024-10-26T23:17:01Z")

</div>

I DRAFT'ed a vRev of the Sub-Script that I use to "Fail Early" when a field IsEmpty.

The goals for this vRev where:

- Use FM 16 JSON Functions to simplify the code
- Add an optional Go to Object {GTO} feature. We considered adding optional Go to Layout and/or Run Script and decided that would be too much and not needed most of the time.
- Simplify and make as readable as possible the passing of the ( field\_ref, {custom\_message}, and {object\_name} ).

Below is the DRAFT Sub-Script: "\_If [field] IsEmpty, {message}, {GTO}, Halt\_P"

- Since this Script will be used in many system and many Files, we might move most of the comments to a more central location
- We are using a Custom Function: @field\_msg\_obj ( field\_ref ; message\_custom ; optional\_objectName ) // to simplify and make as readable as possible the passing of the parameter to Script:\_If [field] IsEmpty, {message}, {GTO}, Halt\_P

1/4: Script:\_If [field] IsEmpty, {message}, {GTO}, Halt\_P

 ![image](https://canada1.discourse-cdn.com/flex030/uploads/fmsoup/original/2X/f/ff066972a50b0512b52406c1bce4768874d1dafd.png)

2/4: Custom Function: @field\_msg\_obj ( field\_ref ; message\_custom ; optional\_objectName )

 ![image](https://canada1.discourse-cdn.com/flex030/uploads/fmsoup/original/2X/d/d7569289ccda416024106e9a0b75f0269015942f.png)

3/4: Example calling Script

 ![image](https://canada1.discourse-cdn.com/flex030/uploads/fmsoup/original/2X/6/6c5e8c0af5cb3e76e7c34d732dbc4d1afbd74295.png)

4/4: We are testing the use of the InFocus State to turn the background from white to light blue:  
To blue or not to blue, that is the question. Thoughts?

 ![image](https://canada1.discourse-cdn.com/flex030/uploads/fmsoup/original/2X/b/b12c681521e70533710e9b06965ca6088983965f.jpeg)

Feedback welcome.

---

<div class="post-metadata">

**Author:** ![tonywhitelive](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/tonywhitelive/32/208_2.png) [@tonywhitelive](https://the.fmsoup.org/u/tonywhitelive)\
**Post date:** [December 25, 2024, 6:10pm UTC](https://the.fmsoup.org/t/filemaker-fail-early/4128/16 "2024-12-25T18:10:02Z")

</div>

Feedback welcome.

 ![image](https://canada1.discourse-cdn.com/flex030/uploads/fmsoup/original/2X/b/b478e652846029aec83f27c3a6e6f9172160f2f3.jpeg)

**# \_If [field] IsEmpty, Go to Layout, Go to Object, then Halt\_P in file Contact (fms.twdesigns dot com)**

// 2024-12-25 by twdesigns dot com - TW:  
// Script is called with a Parameter built using a Custom Function: @FLOM ( GetFieldName ( Contact::Terms ) ; 168 ; "f.Terms--Contact" ; "Enter Terms" )  
// Custom Function: @FLOM ( field\_ref ; layout\_ID ; object\_name ; custom\_message )

Set Variable [$json ; Value: Get ( ScriptParameter )]  
Set Variable [$field.TO\_FN ; Value: JSONGetElement ( $json ; "field\_ref" )]  
Set Variable [$layout\_ID ; Value: JSONGetElement ( $json ; "layout\_ID" )]  
Set Variable [$object\_name ; Value: JSONGetElement ( $json ; "object\_name" )]  
Set Variable [$message.custom ; Value: JSONGetElement ( $json ; "custom\_message" )]

// value.index.ci ( a\_list ; a\_value ) // [FileMaker Custom Function: value.index.ci ( a\_list ; a\_value )](https://www.briandunning.com/cf/2342)  
// Set Variable [$layout\_number ; Value: value.index.ci ( LayoutIDs ( "" ) ; $layout\_id )]  
Set Variable [$layout\_number ; Value: // replace for portability: value.index.ci ( a\_list ; a\_value ) Let ( [ ~list.padded = ¶ & LayoutIDs ( "" ) & ¶ ; ~value.padded = ¶ & $layout\_id & ¶ ; ~position = Position ( ~list.padded ; ~value.padded ; 1 ; 1 ) ; ~list.padded.left = Left ( ~list.p…]  
Go to Layout [$layout\_number ; Animation: None]

Go to Object [Object Name: $object\_name]  
// Go to Object does cause a Drop-down List. Neither does the next 2 lines.

Set Variable [$field.contents ; Value: GetField ( $field.TO\_FN )]  
If [IsEmpty ( $field.contents )]  
If [IsEmpty ( $message.custom )]  
Set Variable [$field.TO\_FN\_as\_List ; Value: Substitute ( $field.TO\_FN ; "::" ; "¶" )]  
Set Variable [$field.FN ; Value: GetValue ( $field.TO\_FN\_as\_List ; 2 )]  
Set Variable [$message ; Value: "Field [" & $field.FN & "] can NOT be Empty." ]  
Else  
Set Variable [$message ; Value: $message.custom]  
End If

// The internet says that Emoji support is based on the operating system  
// ⚠AKA 'Warning' was approved as part of Unicode 4.0 in 2003,  
// under the name "Warning Sign" and added to Emoji 1.0 in 2015.

Show Custom Dialog ["⚠" ; $message]  
// 1 = OK  
Halt Script  
End If

```auto
Happy Holidays
```
