Claris FileMaker Pro で置換リスト変数を用いて複数フィールド内容のメンテナンスを「汎用的」にする

# はじめに
## 前置き
* 本記事は [Qiita Advent Calendar 2023](https://qiita.com/advent-calendar/2023) の [FileMaker Advent Calendar 2023](https://qiita.com/advent-calendar/2023/filemaker)  22 日目記事です。

https://qiita.com/advent-calendar/2023

https://qiita.com/advent-calendar/2023/filemaker

* また、[Claris FileMaker Pro で置換リスト変数を用いて複数フィールド内容のメンテナンス（+ちょっと ChatGPT を使う）](https://qiita.com/Hi_Noguchi/items/fb4f1af179126403c84a) という記事の続編となります。

https://qiita.com/Hi_Noguchi/items/fb4f1af179126403c84a

## 対象読者
* [Claris FileMaker](https://www.claris.com/ja/) ユーザ
* 複数のフィールドにおいて、複数の文字列を置換するようなメンテナンスが必要になる方
* 愚直に長いスクリプトステップを書きたくない方
* 「汎用的」とは？　など考えたい方

## FileMaker とは？
https://www.claris.com/ja/

> モダンで幅広い業務に対応できる拡張性の高いカスタム App を作成

することが可能なもの、とのことです。

## FileMaker 動作環境
* FileMaker Pro 20.x.x
  * 19 以前でも動作するはずです

## 自己紹介
* 株式会社きみよりで代表をしています 野口啓之 / Hiroyuki Noguchi / Hi-Noguchi です
    * IT を中心とした DX コンサル／顧問などやっております
    * FileMaker については、内製化支援・トレーニングや 1on1 でのペアプロなど対応しています

https://kimi-yori.co.jp/

## 前編記事でやったこと
前編記事のおさらいとして、以下のことを実現しました。

- 複数のフィールドに対して、それぞれの内容に不正な値がある場合、置換処理をおこなう

この際に、愚直に処理を書いていくと、長々としたスクリプトとなってしまいます。
よって、以下のような工夫を凝らして作成しました。

- 置換リスト変数を用意し、リスト行数分だけループ処理をおこなう
- モジュール処理用のスクリプトを切り分けて、汎用的に呼び出せるようにする

## 本記事でやること
本記事では、上記よりもさらに一歩踏み込んで汎用的なつくりにすることを目指します。
[前編記事での具体的な箇所はこちら](https://qiita.com/Hi_Noguchi/items/fb4f1af179126403c84a#address_for_shipping-%E3%81%B8%E3%81%AE%E5%AF%BE%E5%BF%9C
) です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/f4473260-901e-1293-5c6e-0f825e88de8e.png)

> 処理全体をコピーします！

ジャネーヨ！　って話ですよね。はい、ごもっともでございます。
本記事は、その仮想ツッコミを受けてのリファクタリングが主な目的となります。

# 汎用的にするべき箇所を特定
ではまず、全体を眺めて、どこを汎用化できそうか考えます。
逆に言うと、どこが汎用化できないか、つまり、固有の箇所なのか、ということを特定しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/9ff05739-4f97-4da0-565e-c36a807f85be.png)

まず `18` 行目で `フィールドへ移動` がありますが、ここは固有の箇所になりそうですね。
ここに移動することによって `$target_table_name` `$target_field_name` の値を取得しています。

あとは `40` 行目の `フィールド設定` や `42` 行目の `フィールド内容の全置換` でしょうか。
`フィールド設定` は `フィールドを名前で設定` で動的に指定できそうです。
また `フィールド内容の全置換` は `ターゲットフィールドの指定` をおこなわずに、その手前で該当フィールドに移動しておけば処理実行できますね。
手前で `フィールドへ移動` すること前提なら、`フィールドを名前で設定` も使わずにやれそうです。

……それならそもそも 27 行目で `フィールドを名前で設定` するためにモジュール用スクリプト作って指定しているけれど、そんなことする必要ないじゃん！　`フィールドへ移動` で `ターゲットフィールドの指定` をおこなわなければいいじゃん！　というツッコミが入りそうです。
まあそうなんですよ、ぶっちゃけ。
前回はこういうやり方がありますぜーというご紹介でしたもので。

あとは、「フィールドにカーソルが入っていることが前提」みたいな作りがやや危ないというのはあります。
ただ、今回はそのあたりのリスクを背負って、綱渡りにギリギリな作りをあえてしてみる、という方針でリファクタリングしていくことにしましょう。

全体として見ると `フィールドへ移動` 以外は全部共通化できてしまいそうですね。
ではその方向性でやってみましょう。

# リファクタリング_1
まず、この範囲を切り出します。
`モジュール` という名前を使うには不適切なほどの大きな処理ですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/296c197c-4cf8-a420-515e-25c6987b887f.png)

まあ、今回は気にしないでやっちまいましょう。
` - モジュール_メンテナンス実処理` という名前のスクリプトを作成して、切り分けます。

まず超絶雑にやるとこんな感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/efc4faf1-20b1-d0eb-68f3-dd98182defcf.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/79ec4886-6114-5924-31c7-36c8d04d4d51.png)

あまりに雑すぎるので、さすがに冒頭でのエラー処理を少し入れておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/e7670c16-658d-4b86-4a54-247fa262350b.png)

このようにして、呼び出される経路を特定させるのと、フィールドが取得できていない場合のエラー処理を入れておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/fd2584ef-5350-099c-0b41-97f0b30d8739.png)

呼び出し元でも引数を渡すようにしてあげましょう。
あとは以下の `ターゲットフィールドの指定` を外してあげればヨシです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/121ee164-2e1c-c589-24da-eca645732e4d.png)

それから最後に、メンテナンスのリストも実処理の方に移してしまいましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/f36ff51e-715a-ee05-d962-9a77880dc950.png)


# 出来上がり？
出来上がりです！　短くなりました！
今後、対象フィールドが増えた場合には、四行だけ追加すれば大丈夫です。

……本当でしょうか。

## `メンテナンス` スクリプト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/16539c1f-7e70-38db-8b75-a8f083c32c2a.png)


## ` - モジュール_メンテナンス実処理` スクリプト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/b975263a-0070-908b-4900-4c80669e1131.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/888717a2-0810-c83e-7dd0-39a8ea24d929.png)

:::note warn
上の方のキャプチャ画像では、上記キャプチャ画像 `38` 行目の `新規レコード/検索条件` が抜けているのですが、ここ重要です！
:::

# 動作確認_1
以下のようなレコードがあったとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/1bc270c5-8487-0180-b787-d214029b425f.png)

スクリプト実行！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/f9c2ee94-c95d-475b-780d-9206dd8cb2b6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/5abba150-c1ce-976f-b69a-11e4973916f1.png)

ちゃんと二つのフィールドにおいて引っかかってくれました。
ただ、これで実行しても変換されません！
どうしてでしょうか？

……それは `検索実行` によってカーソルがフィールドから外れてしまうからなのです！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/271f3e0b-4583-942d-1f3b-b63ba2eb97a9.png)

ここ。それはそう。

# リファクタリング_2
そもそも、現状だと `検索モードに切り替え` してから、検索実行をせずに `スクリプト実行` で別スクリプトに移ってしまって、その中で検索実行をしているらしいぞ……という感じで推測しなければならず、コンテクスト依存度がとても高くて可読性が悪いなーとは思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/990f55cc-317f-4346-053d-4fd0f36c70da.png)

なので、別解として、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/2641c2b5-2203-4107-76ca-603db2387562.png)

- ここの選択部分を一つ目のモジュールとして切り出してスクリプト実行させる。
- `検索実行` と `$target_count` 変数の格納までは、呼び出し元のスクリプトでおこなわせる。
- そこから先の以下の箇所については、二つ目のモジュールとして切り出してスクリプト実行させる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/630d48e6-f3c8-0e1c-ec5b-d931ef1d9fa5.png)

というようにする方が、全体としての可読性は上がると思いますし、これでちゃんと動くようになります。
`モジュール` という名付けにも適したものになりますし。

:::note warn
仮に先ほどのコードで動いていたとしても、短さだけを追求した設計というのは、往々にして作った本人（当時）以外の人には読みにくくなりがちです。
作った本人（未来）ですら読みにくくなります。

多少は長くなったり冗長な記述になったりしても、可読性を重視したつくりにする方をオススメしたいところです。
:::

モジュールを二つに分割するとして、都道府県のリスト変数をどうするのか、という問題がありますね。
これについては JSON にして引数で持ち回すというやり方が一つあります。
ただ今回、そこまでの仕様改修を大掛かりにするのが面倒なので、手っ取り早くグローバル変数に押し込むようにしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/93c9327c-4c0a-7e28-0038-c64a1f5158d9.png)

あわせて各所の指定もローカル変数からグローバル変数に変えておきます。
計算式内も忘れずに。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/3c6806e4-9add-b0b8-e0d2-aed5cf0103aa.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/71cfd154-9f37-a11a-0482-22578d7a9ab8.png)

テーブル名やフィールド名も引数で受け渡しするようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/695aafd5-a5d9-2caf-0b16-16addce4c9c6.png)

モジュールは ` - モジュール_メンテナンス検索設定` ` - モジュール_メンテナンス置換処理` という名前で分けました。

# 出来上がり！
さて、これで今度こそ出来上がりです。
ちょっと呼び出し元の処理が長くなりましたね。
まあこのくらいはいたしかたなし。

## `メンテナンス` スクリプト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/8ca95454-abe9-514f-8f0c-bf917cd123ef.png)

## ` - モジュール_メンテナンス検索設定` スクリプト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/d9382c45-2030-3c99-a4d8-cd2044731277.png)

## ` - モジュール_メンテナンス置換処理` スクリプト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/7e8e153b-c21a-df57-8538-62c8bac1266b.png)


# 動作確認
一応、動作確認だけしておきましょうか。
またまた以下のようなレコードがあったとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/1bc270c5-8487-0180-b787-d214029b425f.png)

スクリプト実行！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/f9c2ee94-c95d-475b-780d-9206dd8cb2b6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/5abba150-c1ce-976f-b69a-11e4973916f1.png)

ちゃんと二つのフィールドにおいて引っかかってくれました。
そして置換処理を実行したところ、二回目のメンテナンス実行時には引っかからないようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/de324c8f-abb4-8493-ab2d-2154177cd115.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/6df912c3-a66b-82a2-7fe3-553f60fcec7c.png)

正常に処理完了しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/82711cf4-377b-d816-7767-dcd8545ab6c4.png)

お疲れ様でした！🎉

# 後書き
## 雑感
- この題材を通じて、「汎用的」とは何か？　可読性を向上させるとはどういうことか？　など、少し体験していただけたかなと思います。
- コードを書いていると、あるいは読んでいると、本当にさまざまな実装方法があるものだと感じられるものですよね。短さと読みやすさというのは、トレードオフの関係になりがちなところがありますが、この記事なんかが考えるきっかけになったら嬉しいです！😀

## PR
- FileMaker についてお困りのことがありましたら気軽にお声がけください🙌

https://kimi-yori.co.jp/

- `FileMake Casual` という Discord サーバも主催していますので、お気兼ねなくご参加ください！
  - https://discord.com/invite/PWWcYK8 ( 招待リンク )

https://discord.com/invite/PWWcYK8