はじめに
Node-REDの読みやすいフローを目指して、Tipsをまとめました。
機会があればイベントとかでも発表したいな。
フロー書いてたら、ごちゃーってなってスパゲッティフローになることありませんか?
動いてるからいいやーってそのままにして、数ヶ月後に改造しようとしたときになんだこれは!!ってなったことありませんか?
他の人が書いたフローをちょちょっと改造して、楽勝!と思っていたら、フローがどこで何してるかわからなくて困ったことありませんか?
私はあります!!
そんな困った事にならないように、自分のため、みんなのためにわかりやすいフローを書きたい!
そんな気持ちから、書き始めました。
かなり自己流な部分もあるので、こんなやり方もあるよ!とかこっちの方がいいよ!とかあれば、ぜひ教えてください!
■名前付け
ノードの名前
名前を設定すると何をしているのか、わかりやすくなります。
処理名や何をしている(したい)かを書く。
以下のようなメリットもあります。
- debugノード:デバッグ画面でノードIDが名前になる
- Linkノード:リンク先、元のノードIDが名前になる
コメントノード
処理のまとまりをコメントノードで示すとわかりやすい。
仕様をMarkdownで記入すれば「情報」サイドパネルに表示されます。
■構造化
ノードの流れ
選択したノードを一気に整列したい場合は、メニューの配置機能も便利です。
functionノードでコネクター
複数の処理が合流するときにワイヤーを遠くに何本も接続すると、ワイヤーが多くてわかりにくくなります。
そこで、何も処理しないfunctionノードをコネクターにするとワイヤーを1本にまとめられて、見た目がスッキリします。
ノードの繋ぎ変えも1本で済んで便利!
Linkノードで処理を分割する
以下のような場合はLinkノードを使用すると見た目がスッキリします。
また、どこへ接続しているかをコメントノードを付けるとわかりやすくなります。
- 複数の処理から、または、複数の処理へ接続
- 遠くへの接続
サブフローで処理を分割する
DRY原則(Don't Repeat Yourself)
1つの処理にまとめられる。
msg変数でパラメータを渡して汎用化できる。
以下のような場合に有効
- 複数箇所で呼ばれる処理
- 似たような処理をいくつも書く
switchノード
- 名前をつける。「〇〇判定」「閾値超過?」
- boolの判定は上をtrueにすることが多いです。(文脈による)
■functionノード
コードを書かずにプログラムできるのがNode-REDの特徴の1つですが、JavaScriptを書けるならfunctionノードを適材適所で活用できると思います。
functionノードで処理をまとめる
changeノードやswitchノード等を複数使用して、ちょっとした処理を書くことも多いと思いますが、何してるかまで見えなくてもいい場合、functionノードにまとめるのもいいかもしれません。
ノード数が少なくなりフローがシンプルになることで、重要なビジネスロジックに集中できます!
- こんな時に使える
- 細々とした見えなくてもいい処理
- 1つのまとまった処理
- こんな時は向いてないかも
- 保守する人がJavaScriptを使えない
functionノードの処理を分割する
functionノード便利!!!全部functionノードでやっちゃおう!!
ってすると、数百行の何してるかわからないfunctionノードができて詰む。
みたいな事もありますね。
1つのfunctionにはノード名で表せる1つの仕事をさせるようにしましょう。
フローを見て「何がしたいのかがわかる」、「伝えたいことが伝わる」のが重要だと思います。
functionの出力先の定数化
出力を増やした時、
1つ目の出力はreturn msg;
2つ目はreturn [null, msg];
3つ目はreturn [null, null, msg];
ってと書きますが、これが読みにくい。
- 何個目に出力しているか数えないといけない
- 出力先の一括変更ができない
なので、これを定数化したい。
改善前
if(isHoge){
return msg;
}else if(isHuga){
return [null, msg];
}else if(isPiyo){
return [null, null, msg];
}else{
return msg;
}
改善後
nullの配列を作って最後にmsgをつなげています。
// アウトプット
const OUT_HOGE = 0;
const OUT_HUGA = 1;
const OUT_PIYO = 2;
if(isHoge){
return Array(OUT_HOGE).fill(null).concat(msg);
}else if(isHuga){
return Array(OUT_HUGA).fill(null).concat(msg);
}else if(isPiyo){
return Array(OUT_PIYO).fill(null).concat(msg);
}else{
return Array(OUT_HOGE).fill(null).concat(msg);
}
■その他tips
グローバルな関数
Node-RED TIPS:functionノード間で関数を共有する方法
をよく使っています。
Node-REDのバージョンアップで、今はモジュールをインポートできるようになっている?
(functionノードのモジュール機能まだ使ったことがない。。。)
いいやり方があったら教えてください。
msg汚染問題
msg変数にプロパティが増えていく問題。
後で使うので、payloadをmsg.hogeにバックアップして、デバッグ用にmsg.hugaにこれを保存して・・・
デバッグログで確認すると、うわー。見たい情報どこだよ!!必要な情報はどれ??ってよくなります。
こんな時は、以下のような対策をよく使います。
- msgに保存せずにfunctionノード内のローカル変数にする
- フロー変数、グローバル変数にする。(長いフローの一部でしか使わない場合)
- 使用しなくなったら、すぐに削除
- Changeノードで「値の削除」
- functionノードで
- プロパティ指定で削除:
delete msg.hoge;
- 全部削除 msgの初期化:
msg = {};
- 一部残す:
- プロパティ指定で削除:
const newMsg = {};
newMsg.payloag = msg.payloag;
newMsg.data = msg.data;
msg = newMsg;
return msg;
デバッグTips
追記:サイドバーの「コンテキストデータ」からも確認できますね。
参考
以下の記事も参考になります。
他にもいい記事、ドキュメントあればコメントで教えてください。
さいごに
弊社(ユニロボット)では、フローの開発、Node-REDの改造、独自ノードの開発等を行なっています。
絶賛エンジニアを募集中です!他にもいろんなレイヤーの開発があります。
我こそは!!という方は、弊社採用ページをご覧ください!