はじめに
先日、自分がQiitaで自信満々に発表したアプリがある。
記事を出した当時は、自信満々だった。
しかし、ある記事に目を通し、その驕りを心から嘆いた。
それは、1年近くも前のMicrosoft社の公式 learn
恥ずかしい気持ちでいっぱいだ。
なんって、クソアプリを発表してしまったんだ・・・。
これを読んでしまった猛者は、さぞ気分を害したに違いない。
善は急げ、だ。
たった今から、このクソアプリのリファクタリングを始める。
App.OnStart → App.Formulas
致命的なのはOnStart
だ。
便利だから、いつもこの枠に書き散らかしてしまう。
その結果うまれたクソコードがこちら
Set(i,1);
ClearCollect(colMenu,
Table(
{index: 1,ico:Icon.AddUser,for:"Recruiter",name:"01.採用者登録"},
{index: 2,ico:Icon.OfficeBuilding,for:"Manager",name:"02.配属登録"},
{index: 3,ico:Icon.Support,for:"Payroll",name:"03.個人情報"}
)
);
ClearCollect(colEmployee,
Table(
{index: i,
employeeNumber: "",
fullName: "",
birthDate: "",
gender: "",
address: "",
phoneNumber: "",
emailAddress: "",
departmentName: "",
position: "",
salary: "",
hireDate: "",
terminationDate: "",
healthInsuranceNumber: "",
annualLeaveDaysLeft: ""}
)
);
ClearCollect(colConfig,
Table(
{
_menu: 1,
_items: 6,
_itemsConfig: {
_itemY1: 80,
_itemY2: 130,
_itemY3: 180,
_itemY4: 230,
_itemY5: 280,
_itemY6: 330
},
_labelsConfig: {
_label1: "氏名",
_label2: "生年月日",
_label3: "性別",
_label4: "電話番号",
_label5: "メールアドレス",
_label6: "住所"
},
_labelConfig: {
x: 130,
w: 150,
h: 40
},
_inpsConfig: {
x: 280,
w: 320,
h: 40
}
},
{
_menu: 2,
_items: 3,
_itemsConfig: {
_itemY1: 80,
_itemY2: 130,
_itemY3: 180,
_itemY4: 0,
_itemY5: 0,
_itemY6: 0
},
_labelsConfig: {
_label1: "部署",
_label2: "役職",
_label3: "給与",
_label4: "",
_label5: "",
_label6: ""
},
_labelConfig: {
x: 130,
w: 150,
h: 40
},
_inpsConfig: {
x: 280,
w: 360,
h: 40
}
},
{
_menu: 3,
_items: 4,
_itemsConfig: {
_itemY1: 80,
_itemY2: 130,
_itemY3: 180,
_itemY4: 230,
_itemY5: 0,
_itemY6: 0
},
_labelsConfig: {
_label1: "社員番号",
_label2: "入社日",
_label3: "健康保険番号",
_label4: "年次有給休暇",
_label5: "",
_label6: ""
},
_labelConfig: {
x: 130,
w: 150,
h: 40
},
_inpsConfig: {
x: 280,
w: 360,
h: 40
}
}
)
);
汚すぎる。そして長い。
変数名も含めて意味が分からない。
// 何回かいているんだコレ
{
_labelConfig: {
x: 130,
w: 150,
h: 40
},
_inpsConfig: {
x: 280,
w: 360,
h: 40
}
}
まあいい。書いたくそコードの数だけ強くなれるって誰かが言っていた気がする。
無知の無知である状態は仕方ない。
ただ改善策を知った。
放置は罪。
これをApp.Formulas
に変えてみる。
App.Formulasの説明はコチラ。
App.Formulasの利点
書いての通り、名前付き関数 としてあらゆるところから呼び出せる。
カスタム コンポーネント
で実現できると思っていたが、それ以前にApp.Fomulas
で解決する課題は多そうだ。
実際に書いて、使ってみると、
- 可読性が高い
- メンテナンスし易い
- 速い
名前付き計算式は Excel の概念です。
Microsoft learnより
なんって素敵な響きだ。
Excelは私の故郷だ。故郷を考えない作り方をしてしまったというのか・・・。
おお、私よ、情けない。
原点に立ち返るのだ。
トコトンめんどくさがって、同じことは何回も書かないのだ・・・。
同じ処理は可能な限り、考えて、まとめよう。
アプリ作成が大変で効率化どころか仕事になったなんていったら本末転倒だ。
App.Formulasに変えてみた全体像
汚いところはごめんなさい🙇
// 1. よく使うカラーを定義
// - App.Theme.Colorsをメインで使う前提
ColorAppsTheme = RGBA(91, 95, 199, 1);
// 2. メニューのギャラリーを関数で設定
InitializeMenuData =
Table(
{ Index: 1, Icon: Icon.AddUser, Role: "Recruiter", MenuName: "01.採用者登録" },
{ Index: 2, Icon: Icon.OfficeBuilding, Role: "Manager", MenuName: "02.配属登録" },
{ Index: 3, Icon: Icon.Support, Role: "Payroll", MenuName: "03.個人情報" }
);
// 3. 空のレコードの挿入
InitializeEmployeeData =
Table(
{
EmployeeNumber: "",
FullName: "",
BirthDate: "",
Gender: "",
Address: "",
PhoneNumber: "",
EmailAddress: "",
DepartmentName: "",
Position: "",
Salary: "",
HireDate: "",
TerminationDate: "",
HealthInsuranceNumber: "",
AnnualLeaveDaysLeft: ""
}
);
// 4. コントロール プロパティの定義
FormStyle =
{
Control: { Height: 40 },
Inputs: { Width: 320, X: 280 },
Label: { Width: 150, X: 130 ,
Y: {
Y1: 80,
Y2: 130,
Y3: 180,
Y4: 230,
Y5: 280,
Y6: 330
}
}
};
// 5. ラベル コントロールのテキストを定義
LableTexts =
Table(
{
Index: 1,
LabelTexts:
{
Label1: "氏名",
Label2: "生年月日",
Label3: "性別",
Label4: "電話番号",
Label5: "メールアドレス",
Label6: "住所"
}
},
{
Index: 2,
LabelTexts:
{
Label1: "部署",
Label2: "役職",
Label3: "給与"
}
},
{
Index: 3,
LabelTexts:
{
Label1: "社員番号",
Label2: "入社日",
Label3: "健康保険番号",
Label4: "年次有給休暇"
}
}
);
一見大差ないように見える部分もあるが、決してそうではない。
関数は毎回呼び出される。
OnStart
というタイミングで一斉に評価をせずに済むということがポイント。
App.OnStart は、長い数式を構成する大きな原因の一つであり、間違いなくそこから始めるべきですが、唯一のケースというわけではありません。
当社の調査によると、Power Apps Studio の読み込み時間の長いアプリのほぼ全てに、256,000 文字を超える数式が少なくとも 1 つあることが分かっています。 読み込み時間が最も長い一部のアプリには、100 万文字を超える数式が含まれています。 長い数式は、大きな負担を Power Apps Studio にかけます。
耳が痛い。
OnStart
に書きまくる張本人だ。
恥ずかしくなって、私はOnStart
の中身を全部消した。
なぜOnStart
に依存するかというと、最初に静的な値
定数 的な使い方をしたくなる。
データソースをつなぐまでもないな、と思うテーブルは、Table関数
で書きたくなる。
結果的に、非常にOnStart
の数式が長くなる。
わかりきっていることだったが、見解が甘かった。
Power Appsの数式の評価は高速だ。
すぐに読み込まれることを織り込んで、関数を活用する。
改善ポイントをいくつか紹介したい。
実際の速さの差異
色のメンテナンスの関係か、そもそものアプリでも負荷が少なかったか、
わかりづらさは否めなくない
元のアプリがミスっているのか、コントロールが表示されていない・・・
1. 定数のように扱う
ColorAppsTheme = RGBA(91, 95, 199, 1);
繰り返し使うもの、色
は典型。
上記をApp.Formulas
に設定することで、Color
やFill
属性に、
ColorAppsTheme
で設定を統一することができる。
App.Formulas
は関数なので、そのコントロールが必要になるときに、式が評価される。
細かく処理がPower Appsの中で分割するので、OnStart
のタイミングで、Power Appsの処理負荷を集中させずに済む。
そのほかの色については、App.Theme
を多用している。
今回はTeams
をテーマに設定した。
App.Theme
プロパティ基軸に、色合いを決定する。
// コントロール プロパティの定義
FormStyle =
{
Control: { Height: 40 },
Inputs: { Width: 320, X: 280 },
Label: { Width: 150, X: 130 ,
Y: {
Y1: 80,
Y2: 130,
Y3: 180,
Y4: 230,
Y5: 280,
Y6: 330
}
}
};
Y1
~の部分はダサいが、コントロール
の高さ
や幅
を、レコード
に集約している。
FormStyle.Control.Height
で40
が呼び出される。
コレクションcolConfig
でダサい書き方をしていたが、
こちらのほうが圧倒的にスマートだ。
アプリの修正にかかる時間を短縮するうえでは検索と置き換えを多用するに越したことはない。
くそコードからスマートな書き方へ、気軽に変えていこう。
// 2. メニューのギャラリーを関数で設定
InitializeMenuData =
Table(
{ Index: 1, Icon: Icon.AddUser, Role: "Recruiter", MenuName: "01.採用者登録" },
{ Index: 2, Icon: Icon.OfficeBuilding, Role: "Manager", MenuName: "02.配属登録" },
{ Index: 3, Icon: Icon.Support, Role: "Payroll", MenuName: "03.個人情報" }
);
変動しないテーブル型
のデータもこのようにまとめて置ける。
ぶっちゃけギャラリー コントロールのItemsに書いておいて
やらなくて良くないかとも感じたが、App.Formula
で、列挙されているのは、保守性の観点でいい。
2. 既存の式に使う
Collection
を一から作るとき、カラム名がベタ打ちになり、式が冗長的になる。
空のレコードをCollect
で追加するにも、長ったらしい式になる。
Set(i,i + 1);
Collect(colEmployee,
Table(
{
Index: i,
EmployeeNumber: "",
FullName: "",
BirthDate: "",
Gender: "",
Address: "",
PhoneNumber: "",
EmailAddress: "",
DepartmentName: "",
Position: "",
Salary: "",
HireDate: "",
TerminationDate: "",
HealthInsuranceNumber: "",
AnnualLeaveDaysLeft: ""
}
);
);
それをApp.Formulas
であらかじめ下記を設定しておくと、
// 3. 空のレコードの挿入
InitializeEmployeeData =
Table(
{
EmployeeNumber: "",
FullName: "",
BirthDate: "",
Gender: "",
Address: "",
PhoneNumber: "",
EmailAddress: "",
DepartmentName: "",
Position: "",
Salary: "",
HireDate: "",
TerminationDate: "",
HealthInsuranceNumber: "",
AnnualLeaveDaysLeft: ""
}
);
非常に美しくなる👀✨
Set(i,i + 1);
Collect(colEmployee,
AddColumns(InitializeEmployeeData,
"Index", i
)
);
これは感動的だ・・。
特に冗長的になるTable関数
が、整理されるのは嬉しい。
LookUp 参照先として利用する
前述のテーブル型として書いておけば・・・
// 5. ラベル コントロールのテキストを定義
LableTexts =
Table(
{
Index: 1,
LabelTexts:
{
Label1: "氏名",
Label2: "生年月日",
Label3: "性別",
Label4: "電話番号",
Label5: "メールアドレス",
Label6: "住所"
}
},
{
Index: 2,
LabelTexts:
{
Label1: "部署",
Label2: "役職",
Label3: "給与"
}
},
{
Index: 3,
LabelTexts:
{
Label1: "社員番号",
Label2: "入社日",
Label3: "健康保険番号",
Label4: "年次有給休暇"
}
}
);
非常に短い式で、レコード抜き出すだけの関数で変数への格納が完了する。
Set(LabelText,LookUp(LableTexts,Index=ThisItem.Index).LabelTexts);
おわりに
クソコードをさらしたことは恥ずかしいが、これを機に書き方を見直そうと思う。
無知の無知
は確かに恥ずかしいが、無知の知
に至ったので、さらに先に進めるだろう・・・。
反省点として・・・
まずは公式を読もう!
良いPower Lifeを!