これでようやく満開の河津桜
伊豆河津では2月になると咲き始め、3月には終わっているはずの梅より早く咲く河津桜。梅はいつもより少し遅いくらいだが、こちらはかなり遅い印象。
ミザクラは早く花が咲く桜。実がつくのも早い。梅雨前には食べられる。
同じ日の梅。ウチで一番遅い梅。まだ蕾が多い。
「WEB+DB PRESS vol.127」(以下、wdp127)にリファクタリングの話があったので読んでみたら良かった。
https://gihyo.jp/magazine/wdpress/archive/2022/vol127
知らない単語が出てきたのでメモしておく。
□ 凝集度(cohesion)
□ 結合度(coupling)
調べてみると、語源は1979年あたりにヨードンが提唱していたらしい。
□ DRY(Don’t Repeat Yourself)
コードの最適化、なんでもDRYというルールがあるそうだ。
プログラミングしていると、同じようなコードを何度も書くとき、共通化できるのでは?と考える。あちこちに書いておくと、あとでそこに修正が生じた場合にあちこち直さなくてはならないため不便だし、処理が同じならモジュール化すべきだという考えだ。
wdp127では凝集度について、論理的凝集は避ける、ようなことが書いてある。要はフラグを使った関数内分岐を避けよ、という意味と理解した。ウチでは同じような意味で「多機能関数はダメ」というルールがある。
結合度については値は引数で渡す、ようなことが書いてある。要はグローバル変数は避けよ、という意味と理解した。ウチでは「関数の中はローカル変数だけを使う」と「グローバル的な変数にはゲッターセッターを用意して関数を介して取得する」というルールがある。ただし例外として、画面に一覧を表示する際のフォームオブジェクトはグローバル参照をしていいというルールもある。画面に表示する情報についてゲッターセッターをすべて用意するのはあまりにも面倒だ。フォームオブジェクトは名前付のルールでわかるようにしている。
ウチでは上記のほかに、
forやifの構造が3つ以上出現する場合は、さらなるモジュール化を検討せよ、という意味だ。
仕様がケース分岐しているのであればコードも分岐している、のがフツーだ。入り口から分岐させて、中に共通処理を見つけたら共通モジュール化する、のが良い。
できるだけ1行で書く、というコードはダメ。if文の中に関数を記述したり、引数に関数を記述するのはわかりやすいNGだ。デバッグする時にたとえばforループが何回回るのかは重要な要素だ。上手くいかないときは0回の場合が多い。これをデバッグするには繰り返し回数を見れば良いのだが、大体はなんかの関数の戻り値である。これをfor($i;1;myFunc())のように書いてしまうとmyFunc()の戻り値を見たくなる。$count:=myFunc()とか記述して$countの値を見ることになる。それなら最初からそういうコードにしておけば良い。
上記はソース内部の記述だが、表面的な仕様でもデバッグに便利な機能を実装しよう。あるテーブルの中身が見たいような機能は言われなくても作ってしまう。デバッグでよく使うツールであればプログラマは便利になる。そのままリリースして、ユーザに「削除して」と言われてから「隠す」ようにすればよい。
まだ語り尽くせないので、また思いついたら続きを書く。。。
「4Dアプリ開発ガイド v18対応版」を制作していたらコマンドの仕様変更に気づいたので報告する。これまでに気づいているのは次の2つ、「FORM Event」と「PAGE SETUP」。
フォームイベントコマンドの仕様が変わった。以前は次のように記述していた。
//A02_frmこのコードをv18にペーストして実行すると、次のようなエラーになる。
ランゲージリファレンスを見ると、v18では戻り値がオブジェクト型になっていた。
https://doc.4d.com/4Dv18/4D/18.4/FORM-Event.301-5233147.ja.html
v15とかv17のプロジェクトをv18に変換すると、次のようなコードに変換される。
//A02_frm「Form event」コマンドは「Form event code」に変更されて、オブジェクト型を返す「FORM Event」が新しく追加された、ということらしい。従来取得していた整数型のイベントコードは「code」というフィールドに格納されている。もともとコードしか返さなかったを、イベントのトリガーとなったオブジェクト名も返すようだ。いいかもしれない。これまでイベントハンドラはオブジェクトメソッドに書いていたが、フォームメソッドにまとめて書いて、「もしこのオブジェクト名だったら」という記述ができるようになったってことかな。
発生したcodeだけを必要とする場合はどちらのコマンドを使っても同じみたいだけど、オブジェクト型を使ってドット表記を参照する方が流行りっぽくてかっこいいかもしれない、とか色々考えて次のようにした。
//A02_frm修正ついでに一旦ローカル変数に取得するようにした。これでデバッグしやすくなる。Case文に何回も書くと、その数だけFORM Eventが実行されてしまい、気づかれるほどではないにしても性能的によろしくないので。
廃止になった。プロジェクトをv18に変換すると、次のようなコードに変換されている。
_O_PAGE SETUP
代わりのコマンドが用意されていて、SET PRINT OPTION/GET PRINT OPTION、Print settings to BLOB/BLOB to print settingsを使う、とランゲージリファレンスに書いてある。
https://doc.4d.com/4Dv18R5/4D/18-R5/o-PAGE-SETUP.301-5128159.ja.html
もともと「PAGE SETUP」は、印刷ダイアログを表示することなく、用紙とか印刷設定を前回と同様またはいつも決まった所定のセッティングで印刷したいときに使うコマンドであった。ユーザが毎回印刷設定ダイアログで設定してから印刷する場合は不要だが、印刷設定ダイアログを出さずに印刷したり、前の設定を覚えておいて欲しい場合に実装することになる。v18ではまだそのような仕様を使う状況に遭遇していないので、使うことになったらまた報告する。
庭に甘夏の木がある。3月、普通の甘夏はこれからが収穫期、だがうちのは終了した。
もう12月から黄色く色づいていた。今年は豊作と思っていたが。
1月くらいからリスがかじり出して、ヒヨドリがつついて、メジロが食べたり、風で落ちたり、どんどんなくなっていく。昨年はこれらの影響で人間は一つも食べられなかった。
リスが食べているのならもう食べられるのでは?ということで、今年は1月から風で落ちたのを食べ始めた。酸っぱい。下手に食べるとむせて大変なことになる。砂糖をかけて食べるとむせないことに気づく。昔ババアがそうやって食べていたのを思い出す。若い頃は酸っぱいものを食べても、多少むせても平気だったがこの歳になるとむせかたが半端なくて辛い。なるほど砂糖をかけて食べるとむせる心配がない。これはこれでかなり美味しい。
2月に入ると樹熟が進んで甘くなってくる。別に八朔があって、こちらは今年初収穫。2月に14個取れた。八朔は美味しいな。
八朔も甘夏も皮は砂糖で煮てジャムにする。鍋に甘夏5個分くらいの皮を千切りにして入れて、水を張って煮る。沸騰したらお湯をこぼして、また水を張って煮る。これを3回繰り返す。4回目の沸騰の後、水が皮よりも少なくなったら砂糖を入れる。350gから400gがうちのお好みかな。これで水気が半分くらいになるまで煮詰める。程々で良い。冷めていく途中で水分が減るからね。
3月14日、最後の4つを収穫。
残りはリスと鳥にやられた残骸。今年は人間も食べられたので良かったです。
以前のブログで間違いがあったので修正するとともに、印刷用フォームについて再考した。プロジェクトフォームとテーブルフォームで制御できるイベントプロパティが違うのは「テーブルのレコードセレクションを前提としたイベントがプロジェクトフォームではサポートされていない」ということだった。以前ブログを書いた時の理解が足りていなかっただけで、考えてみればプロジェクトフォームには帰属するテーブルがないから、セレクションを前提としたプロパティが設定できないのは当たり前だ。
たとえばプロジェクトフォームのプロパティには「On Printing Detail」などの印刷時に発生しそうなプロパティがない。これはPrint selectionの時に有効で、セレクションが必要なのでテーブルに帰属していることが前提になるためにテーブルフォームにしかないプロパティなのだ。
たとえば、印刷時に「文字列が多くて印字領域に収まらなかった時に文字フォントを小さくして印刷する」という技を使っているのだが、これは印字しようとしている文字列長によって適用するかしないかが異なる。「On Printing Detail」が発生した時、文字列を一度配置してみて文字列オブジェクトの矩形の長さを評価して、所定の幅に収まりきらなかったら小さいフォントサイズを再設定するという仕様だ。それで「On Printing Detail」にコードを記述することになる。この実装がプロジェクトフォームでもテーブルフォームでも動いてしまう。あれっ、と思って調べたらどちらのフォームにも「On Printing Detail」イベント(Form event = 23)が発生していたのだ。では、テーブルフォームで「On Printing Detail」チェックを外したらどうなるか。これでも「On Printing Detail」イベントは発生していた。
印刷時に使っているコマンドは次。
Print form([Z_PrintForm];”PP11_PrintList”;Form detail)
ここで印刷するフォームオブジェクトに配置されているのは配列要素またはプロセス変数でありテーブルのセレクションは無関係。
Print formではフォームプロパティのイベント「On Printing Detail」のチェックオフが無視される。Print formでForm detailを直接印刷しているため、4Dが内部的に「On Printing Detail」イベントを発生させているように見える。よく見たらPrint formの説明に書いてあった。つまり、Print formを使うということは、印刷イベント「On Printing Detail」を強制的に発生させるという意味であり、フォームのプロパティ設定は無視される、ようだ。しかしヘッダーを印刷するとき、つまりPrint formの指定領域が「Form header」でも同じイベント「On Printing Detail」が発生するのはわかりにくい。どうやら指定領域ごとに異なるイベントを発生させる必要はない、と考えているようだ。まあ実用上は問題ないかもしれない。次のコードはいずれも「On Printing Detail」が発生した。
Print form([Z_PrintForm];”PP11_PrintList”;Form header)
Print form([Z_PrintForm];”PP11_PrintList”;Form detail)
Print form([Z_PrintForm];”PP11_PrintList”;Form footer)
以前のブログは次のように補足しよう。
1)Print formを使う場合、「On Printing Detail」イベントプロパティのチェックは印刷時に影響しない。
2)配列を印刷する場合のフォームはプロジェクトフォームでもテーブルフォームでもよい。
Print formで配列を印刷する場合はセレクションが関係しないため、どちらにフォームを作っても問題はない。テーブルフォームに作ることもできるがテーブルに帰属させる必要性はない。フォームを整理するという側面からは、テーブルの内容を一覧する(配列に転送したとしても)ものはそのテーブルのフォームに作る、ことは意味があるかもしれない。
しばらくは、印刷用フォーム専用テーブル[Z_PrintForm]に印刷フォームを作成して、プロジェクトに印刷フォームがどのくらいあるかを把握できるようにしたい。フォーム名は出力するデータの元のテーブルのプレフィックスをつけて、10番代から始める。たとえば上記であれば、PPというお売りフィックスのテーブルの1番目の印刷フォーム「PP11_」をつけてフォーム名を続ける。「PP11_SiharaiIchiran」とか。
以前のブログはこちら
4D プロジェクトフォームとテーブルフォーム、イベントプロパティが違う その1