Slide 1

Slide 1 text

#RAKUSMeetup ©2023 RAKUS Co., Ltd. 22歳になる長寿サービスの UI刷新 ~密結合システムからViewを分離した苦労話~

Slide 2

Slide 2 text

#RAKUSMeetup 自己紹介 ● 名前:小西 佑 ● 所属:株式会社ラクス ● 業務:メールディーラー開発 ● 趣味:ゲーム ○ ゲームを絡めてプログラムの学習をすることも ○ (ほぼ欲しいものリストばかり・・・) 2

Slide 3

Slide 3 text

#RAKUSMeetup 製品紹介 ● メール共有・管理システム ● 2001年にリリースされた弊社最古参のサービス(今年で22年) 3

Slide 4

Slide 4 text

#RAKUSMeetup 4 メールディーラーのUIがい けてないじゃん だから、イマドキの デザインにしようよ 企画の人

Slide 5

Slide 5 text

#RAKUSMeetup メールディーラーのUIを刷新することに なった 5

Slide 6

Slide 6 text

#RAKUSMeetup 6 刷新内容 ● UIのデザイン・画面構成の変更 ○ 費用対効果の観点から「ユーザがよく使う機能」のみを対象とする ○ CSSのみではなく、他(HTML、JavaScript等)の修正も必要である ● UIの刷新によるユーザへのインパクトが大きいため、旧画面をし ばらく残すことになった ○ 旧画面のロジックを残しつつ、新UIのコードを実装する

Slide 7

Slide 7 text

#RAKUSMeetup 7 まじで? 開発者

Slide 8

Slide 8 text

#RAKUSMeetup 現状無理 8

Slide 9

Slide 9 text

#RAKUSMeetup 9 理由 ● 以下のような問題がある ○ 機能が多く、コードも複雑なため、手動のテストだけで「旧画面と同機能で あること」を担保することが難しい ○ 自動テストがない ■ 作成するにしても、ビューロジックとビジネスロジックが混在しているため、   細かい仕様の確認が難しい ➢ コア機能の改修なのでクリティカルな不具合は許されない

Slide 10

Slide 10 text

#RAKUSMeetup どうすれば・・・ 10

Slide 11

Slide 11 text

#RAKUSMeetup 自動テストの作成が難しいのは ビューロジックとビジネスロジックが 混在しているため・・・ 11

Slide 12

Slide 12 text

#RAKUSMeetup そうだ!! 12

Slide 13

Slide 13 text

#RAKUSMeetup ビューロジックとビジネスロジック を分離しよう 13

Slide 14

Slide 14 text

#RAKUSMeetup 分離作業内容 14 ● 作業概要 1. 旧画面のコードから機能一覧を作成する 2. IDEの機能を使用して、共通利用するロジックをメソッドに切 り出す 3. 切り出したメソッドのユニットテストを作成する 4. ビューロジックとビジネスロジックを分割する

Slide 15

Slide 15 text

#RAKUSMeetup 分離作業内容 15 1. 旧画面のコードから機能一覧を作成する ● 用途 ○ 実装・手動テストで使用する ● 目的 ○ 機能落ちや、想定外の不具合を防ぐため

Slide 16

Slide 16 text

#RAKUSMeetup 16 $isEdit = $_REQUEST['mode'] === 'edit'; if ($isEdit) {   if ($_REQUEST['input'] === 'radio') {     print "男";     print "女";   } else {     print "";   } } if ($isEdit) {   $js = "alert('edit');"; } else {   $js = "alert('view');"; } print "{$js}"; if ($isEdit) {   $sum = 0;   foreach ($_REQUEST['count'] as $count) {     $sum += $count;   } } print "

{$count}

";

Slide 17

Slide 17 text

#RAKUSMeetup 17 サンプルコードで機能一覧を 作成すると・・・

Slide 18

Slide 18 text

#RAKUSMeetup 18 実装時に使用する コードを読み、その処理を 記載する

Slide 19

Slide 19 text

#RAKUSMeetup 分離作業内容 2. IDEの機能を使用して、共通利用するロジックをメソッドに切 り出す 3. 切り出したメソッドのユニットテストを作成する ○ 新UIの実装時に、切り出した箇所の修正が必要になった場合に、動作 を担保できるようになった ➢ 旧画面のロジックを「テスト可能な状態」にすることができた 19

Slide 20

Slide 20 text

#RAKUSMeetup 分離作業内容 4. ビューロジックとビジネスロジックを分割する ○ フレームワークを導入して、テンプレートエンジンに渡すように変更 ○ Laravel/Vue.jsを導入 ■ フロント:Vue.jsとblade ■ バックエンド:LaravelでADR実装 20

Slide 21

Slide 21 text

#RAKUSMeetup 分離作業内容 4. ビューロジックとビジネスロジックを分割する ○ 手順 ➀ 旧画面のコードをそのままLaravelへ移植 ➁ HTML作成のコードをコメントアウト ➂ 機能一覧に従って、新UIを実装 ➃ ③で作成した機能のActionクラスの自動テストを作成・実施 ■ 想定通りレスポンスパラメータが送信されているかを確認 ➄ 不要なコードを削除(コメントアウトしたコードなど) ➅ 機能一覧を使って、受入テストを実施(最終確認) 参照:フレームワークが存在しない時代からのレガシープロダクトを、Laravelに”載せる”実装戦略 21

Slide 22

Slide 22 text

#RAKUSMeetup 22 ビューロジックとビジネスロジック に分解すると・・・

Slide 23

Slide 23 text

#RAKUSMeetup 23 $isEdit = $_REQUEST['mode'] === 'edit'; if ($isEdit) {   if ($_REQUEST['input'] === 'radio') {     print "男";     print "女";   } else {     print "";   } } if ($isEdit) {   $js = "alert('edit');"; } else {   $js = "alert('view');"; } print "{$js}"; if ($isEdit) {   $sum = 0;   foreach ($_REQUEST['count'] as $count) {     $sum += $count;   } } print "

{$count}

"; Javascript PHP HTML

Slide 24

Slide 24 text

#RAKUSMeetup 24 男 <input type='radio' id='female' name='gender' value='1'>女 @else <input type='text' id='input' name='text' value=''> @endif @endif <script src="/js/page_a.js" >

{{$count}}

const vm = { mounted() { if (params.isEdit) { alert('edit') } else { alert('view') } } } export default vm; ビューロジック page_a.js page_a.blade.php

Slide 25

Slide 25 text

#RAKUSMeetup 25 class PageAAction { protected $Domain; protected $Responder; public function __construct(Domain $Domain, Responder $Responder) { $this->Domain = $Domain; $this->Responder = $Responder; } public function __invoke(Request $request): Response { return $this->Responder->response($request, $this->Domain->get($request)); } } class PageAResponder { protected $response; protected $view; public function __construct(Response $response, ViewFactory $view) { $this->response = $response; $this->view = $view; } public function response(Request $request, $data): Response { $isEdit = $request->get('mode') === 'edit'; if ($isEdit) {    $sum = 0;    foreach ($request->get('count') as $count) {      $sum += $count;    } } $this->response->setContent( $this->view->make('page_a', [ 'isEdit' => ($isEdit) ? 'edit' : 'view', 'input' => $request->get('input'), 'count' => $sum, ]) ); return $this->response; } } ビジネスロジック PageAAction.php PageAResponder.php

Slide 26

Slide 26 text

#RAKUSMeetup 結果・・・ 26

Slide 27

Slide 27 text

#RAKUSMeetup 27 BEFORE

Slide 28

Slide 28 text

#RAKUSMeetup 28 AFTER

Slide 29

Slide 29 text

#RAKUSMeetup ビジネスロジックとビューロジックを 分離したことでUIを 新しくすることができた 29

Slide 30

Slide 30 text

#RAKUSMeetup 今回の結果 30 ● ビジネスロジックの自動テストを作成したので、今後の追加実装 や改修がしやすくなった ● クリティカルな不具合が少なかった ● 新UIへの移行の手法が確立できたので、他の機能でも活用でき る

Slide 31

Slide 31 text

#RAKUSMeetup 苦労した話 ● 機能一覧を作るのがしんどかった ○ 3000行超えのコード x 4機能分 を読んだ ○ 条件分岐が多かったり、不明な処理があり、どういう機能なのかを理解する のが大変だった ○ 作成した機能一覧が実装時に役にたったので、作ってよかった 31

Slide 32

Slide 32 text

#RAKUSMeetup 苦労した話 ● 旧画面のロジックを移植した際に、変数のスコープが変化した た め、バグが発生した ○ グローバル変数を、Responderクラス内に移植したため、ローカル変数に 変化した ➢ その変数をglobalで呼び出している箇所の値が変化した ○ リリース前に見つかってよかった 32

Slide 33

Slide 33 text

#RAKUSMeetup 今後の展望 ● 今回の刷新で対象外だった画面を新UIに改修 ● 今回改修したロジックのリファクタリング ○ ADR実装に沿った実装にする ■ 現状、旧画面から移植したビジネスロジックはすべてResponderにある ➢ デグレ防止のために旧画面のロジックをそのまま移植したため ➢ 複雑なコードはほぼそのままの状態 ■ これを適切な箇所に実装する 33

Slide 34

Slide 34 text

#RAKUSMeetup 結論 34

Slide 35

Slide 35 text

#RAKUSMeetup ビュー・ビジネスロジック分離はいい 35

Slide 36

Slide 36 text

#RAKUSMeetup ご清聴ありがとうございました 36