Slide 1

Slide 1 text

© LayerX Inc. 複雑なドメインに挑む LayerX バクラク事業部アプリチーム 酒井佑旗 〜複雑なドメインに20代として取り組むということ〜

Slide 2

Slide 2 text

⽬次 Agenda ● バクラクのドメインの難しさ ● 複雑なドメインへのアプローチ ● 20代で複雑なドメインに取り組む⾯⽩さ

Slide 3

Slide 3 text

© LayerX Inc. 3 株式会社LayerX バクラク事業部モバイルチーム 2023年6⽉インターン開始 2025年4⽉新卒⼊社 酒井佑旗 ⾃⼰紹介 FlutterKaigi2025でAI x E2Eについて話します

Slide 4

Slide 4 text

バクラクのドメインの難しさ ワークフローはなぜ難しいのか

Slide 5

Slide 5 text

5 © LayerX Inc. ● 各企業が⾃由にワークフローを設計可能 ● 故にビジネスロジックがとても複雑 ● 加えて、UX を重視した結果、クライアントサイドに ビジネスロジックが集中 バクラク申請‧経費精算とは 「経費精算や様々な稟議を⾏う SaaS」 バクラク申請‧経費精算の難しさ

Slide 6

Slide 6 text

6 © LayerX Inc. バクラク申請‧経費精算とは ● 各企業が⾃由にワークフローを設計可能 ● 故にビジネスロジックがとても複雑 ● 加えて、UX を重視した結果、クライアントサイドに ビジネスロジックが集中 「経費精算や様々な稟議を⾏う SaaS」 バクラク申請‧経費精算の難しさ → 今⽇はそのごく⼀部を話します

Slide 7

Slide 7 text

フィールドの ⼊⼒⽅法をどう表すか

Slide 8

Slide 8 text

8 © LayerX Inc. フィールドの⼊⼒⽅法をどう表すか 複雑なドメインに向き合う ● ⾦額フィールドにはさまざまな⼊⼒⽅法が存在 ○ ⼿動⼊⼒、OCRによる⾃動⼊⼒、サジェストからの ⼊⼒、変更不可の⾃動⼊⼒ ● ⼊⼒⼿段によってその後の挙動が異なる ○ システムによって固定値が⼊⼒される場合、ユー ザーは変更することができない → あなたならどのように実現しますか? ⾦額の⼊⼒を例に考えてみましょう

Slide 9

Slide 9 text

9 © LayerX Inc. 機能要件 フィールドの⼊⼒⽅法をどう表すか ⼿動⼊⼒ OCRによる⾃動⼊⼒ システムによる固定値⼊⼒ ● ⼊⼒⽅法は3種類 ○ ⼿動⼊⼒ ○ OCRによる⾃動⼊⼒ ○ システムによる固定値⼊⼒ ● ⼊⼒⽅法でテキストフィールドのデザインを変えたい ● 「システムによる固定値⼊⼒」の場合、 ユーザー⼊⼒は受け付けない ⾦額⼊⼒のサンプル

Slide 10

Slide 10 text

10 © LayerX Inc. ⼊⼒⽅法ごとのフラグを持たせる? フィールドの⼊⼒⽅法をどう表すか class PaymentAmountField extends StatelessWidget { const PaymentAmountField({ required this.amount, required this.isFilledBySystem, required this.isFilledByOCR, super.key, }); final int amount; final bool isFilledBySystem; final bool isFilledByOCR; @override Widget build(BuildContext context) { return SampleTextField( amount: amount, isFixed: isFilledBySystem, borderColor: isFilledByOCR ? Colors.grey : Colors.purple, showIcon: isFilledByOCR, ); } }

Slide 11

Slide 11 text

11 © LayerX Inc. ⼊⼒⽅法ごとのフラグを持たせる? フィールドの⼊⼒⽅法をどう表すか class PaymentAmountField extends StatelessWidget { const PaymentAmountField({ required this.amount, required this.isFilledBySystem, required this.isFilledByOCR, super.key, }); final int amount; final bool isFilledBySystem; final bool isFilledByOCR; @override Widget build(BuildContext context) { return SampleTextField( amount: amount, isFixed: isFilledBySystem, borderColor: isFilledByOCR ? Colors.grey : Colors.purple, showIcon: isFilledByOCR, ); } } ● isFilledBySystem と isFilledByOCR が ともにtrueだったら? ● ⼊⼒⽅法が増えたら? ● ⼊⼒値がamount以外を持つようになったら? ● ⼊⼒⽅法による仕様の違いがさらに複雑になった ら? ● ⼊⼒⽅法とUI仕様が密すぎない?

Slide 12

Slide 12 text

12 © LayerX Inc. ではどうする? フィールドの⼊⼒⽅法をどう表すか Sealedクラスを使おう

Slide 13

Slide 13 text

13 © LayerX Inc. Sealedとは フィールドの⼊⼒⽅法をどう表すか ● 列挙可能なサブタイプの集合を定義する ● switch によるパターンマッチングで網羅性保証される ● アプリケーション固有のドメイン状態を型レベルで表現することに使われる

Slide 14

Slide 14 text

14 © LayerX Inc. ● ⼊⼒⽅法を表すSealedクラスを定義 ● amountは抽象クラスで定義 ● ⼊⼒⽅法ごとに具象クラスを作成 ⼊⼒⽅法をSealedクラスを定義 Sealedクラスを使う sealed class InputValue { const InputValue({required this.amount}); final int amount; } class ManualValue extends InputValue { const ManualValue({required super.amount}); } class OcrCompletedValue extends InputValue { const OcrCompletedValue({required super.amount}); } class SystemFixedValue extends InputValue { const SystemFixedValue({required super.amount}); }

Slide 15

Slide 15 text

15 © LayerX Inc. UIをSealedクラスを⽤いた形に更新 Sealedクラスを使う class PaymentAmountField extends StatelessWidget { const PaymentAmountField({ required this.inputValue, super.key, }); final InputValue inputValue; @override Widget build(BuildContext context) { return SampleTextField( amount: inputValue.amount, isFixed: inputValue.isFixed, borderColor: inputValue.borderColor, showIcon: inputValue.showIcon, ); } } extension on InputValue { bool get isFixed => switch (this) { ManualValue() => false, OcrCompletedValue() => false, SystemFixedValue() => true, }; bool get showIcon => switch (this) { ManualValue() => false, OcrCompletedValue() => true, SystemFixedValue() => false, }; Color get borderColor => switch (this) { ManualValue() => Colors.blue, OcrCompletedValue() => Colors.grey, SystemFixedValue() => Colors.grey, }; } わかりやすやのためにor句は未使⽤です

Slide 16

Slide 16 text

16 © LayerX Inc. ● 型による制約で無効な状態を防ぐことができる ○ 例えば isFilledBySystem と isFilledByOCR が両方trueになることがなくなる ● ⼊⼒⽅法の表現と仕様を分離 ● 型によるパターンマッチングを使うことができるので、⼊⼒⽅法の増減に気づきやすい ○ コンパイラが指摘してくれる Sealedクラスにより得られる恩恵 Sealedクラスを使う

Slide 17

Slide 17 text

17 © LayerX Inc. これは序の⼝ フィールドの⼊⼒⽅法をどう表すか ● ユーザーによるフォームカスタマイズ ● フィールドAの⼊⼒状態により、フィールドBの表⽰‧⾮表⽰が切り替わる ● フィールドAの⼊⼒状態により、フィールドBのバリデーションが変化する ● APIによる⾮同期バリデーション ● 多くの申請種別、明細種別 ● 下書き保存、申請後の修正 他にもまだまだ強敵がいます

Slide 18

Slide 18 text

20代で複雑なドメインに 取り組む⾯⽩さ

Slide 19

Slide 19 text

19 © LayerX Inc. ● 経験豊富なテックリードやEMも「過去⼀難しい」と感じるドメイン ● 若⼿の内からこのしたドメインに挑戦できるのは⼤きな成⻑機会 ● ドメインの複雑さの裏には多くのユーザーペインが多く存在 ○ ユーザーインパクトが⼤きく、価値提供に繋がりやすい ○ LayerXではアウトカムを重視しており、チームとしてユーザー体験にフォーカスできている なぜ⾯⽩い? 20代で複雑なドメインに取り組む⾯⽩さ

Slide 20

Slide 20 text

20 © LayerX Inc. カジュアル⾯談お待ちしております もっと複雑なドメインの話、LayerXのAI活⽤ なんでもお話します!