Upgrade to Pro — share decks privately, control downloads, hide ads and more …

22歳になる長寿サービスのUI刷新 ~密結合システムからViewを分離した苦労話

Rakus_Dev
September 06, 2023
2.8k

22歳になる長寿サービスのUI刷新 ~密結合システムからViewを分離した苦労話

ロジックの中にHTMLが記載されているシステムを想像してください。
このシステムのUI改修、皆さんならどう進めますか?

当社のメール管理プロダクト「メールディーラー」はリリースから22年。
刷新前のプロダクトコードはビューロジックとビジネスロジックが密結合…とても改修できそうには思えませんでした。

コア機能の改修なのでもちろんクリティカルな不具合は許されません。
どのようにしてデグレを起こさずにUI刷新を進めたのか、メールディーラー開発チームの1年半の戦いをお話します。

Rakus_Dev

September 06, 2023
Tweet

More Decks by Rakus_Dev

Transcript

  1. #RAKUSMeetup 自己紹介 • 名前:小西 佑 • 所属:株式会社ラクス • 業務:メールディーラー開発 •

    趣味:ゲーム ◦ ゲームを絡めてプログラムの学習をすることも ◦ (ほぼ欲しいものリストばかり・・・) 2
  2. #RAKUSMeetup 6 刷新内容 • UIのデザイン・画面構成の変更 ◦ 費用対効果の観点から「ユーザがよく使う機能」のみを対象とする ◦ CSSのみではなく、他(HTML、JavaScript等)の修正も必要である •

    UIの刷新によるユーザへのインパクトが大きいため、旧画面をし ばらく残すことになった ◦ 旧画面のロジックを残しつつ、新UIのコードを実装する
  3. #RAKUSMeetup 9 理由 • 以下のような問題がある ◦ 機能が多く、コードも複雑なため、手動のテストだけで「旧画面と同機能で あること」を担保することが難しい ◦ 自動テストがない

    ▪ 作成するにしても、ビューロジックとビジネスロジックが混在しているため、   細かい仕様の確認が難しい ➢ コア機能の改修なのでクリティカルな不具合は許されない
  4. #RAKUSMeetup 分離作業内容 14 • 作業概要 1. 旧画面のコードから機能一覧を作成する 2. IDEの機能を使用して、共通利用するロジックをメソッドに切 り出す

    3. 切り出したメソッドのユニットテストを作成する 4. ビューロジックとビジネスロジックを分割する
  5. #RAKUSMeetup 16 $isEdit = $_REQUEST['mode'] === 'edit'; if ($isEdit) {

      if ($_REQUEST['input'] === 'radio') {     print "<input type='radio' id='male' name='gender' value='0'>男";     print "<input type='radio' id='female' name='gender' value='1'>女";   } else {     print "<input type='text' id='input' name='text' value=''>";   } } if ($isEdit) {   $js = "alert('edit');"; } else {   $js = "alert('view');"; } print "<script>{$js}</script>"; if ($isEdit) {   $sum = 0;   foreach ($_REQUEST['count'] as $count) {     $sum += $count;   } } print "<p>{$count}</p>";
  6. #RAKUSMeetup 分離作業内容 4. ビューロジックとビジネスロジックを分割する ◦ 手順 ➀ 旧画面のコードをそのままLaravelへ移植 ➁ HTML作成のコードをコメントアウト

    ➂ 機能一覧に従って、新UIを実装 ➃ ③で作成した機能のActionクラスの自動テストを作成・実施 ▪ 想定通りレスポンスパラメータが送信されているかを確認 ➄ 不要なコードを削除(コメントアウトしたコードなど) ➅ 機能一覧を使って、受入テストを実施(最終確認) 参照:フレームワークが存在しない時代からのレガシープロダクトを、Laravelに”載せる”実装戦略 21
  7. #RAKUSMeetup 23 $isEdit = $_REQUEST['mode'] === 'edit'; if ($isEdit) {

      if ($_REQUEST['input'] === 'radio') {     print "<input type='radio' id='male' name='gender' value='0'>男";     print "<input type='radio' id='female' name='gender' value='1'>女";   } else {     print "<input type='text' id='input' name='text' value=''>";   } } if ($isEdit) {   $js = "alert('edit');"; } else {   $js = "alert('view');"; } print "<script>{$js}</script>"; if ($isEdit) {   $sum = 0;   foreach ($_REQUEST['count'] as $count) {     $sum += $count;   } } print "<p>{$count}</p>"; Javascript PHP HTML
  8. #RAKUSMeetup 24 <script @if($isEdit === 'edit') @if($input === 'radio') <input

    type='radio' id='male' name='gender' value='0'>男 <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" ></script> <p>{{$count}}</p> const vm = { mounted() { if (params.isEdit) { alert('edit') } else { alert('view') } } } export default vm; ビューロジック page_a.js page_a.blade.php
  9. #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
  10. #RAKUSMeetup 苦労した話 • 機能一覧を作るのがしんどかった ◦ 3000行超えのコード x 4機能分 を読んだ ◦

    条件分岐が多かったり、不明な処理があり、どういう機能なのかを理解する のが大変だった ◦ 作成した機能一覧が実装時に役にたったので、作ってよかった 31