この記事は Safie Engineers' Blog! Advent Calendar 5日目の記事です。
自己紹介
こんにちは。セーフィー株式会社 開発本部所属の佐々木 大翔(ささき ひろと)と申します。今回は、我々が行った2024年度新卒エンジニア研修における、フロントエンド開発についてお話ししたいと思います。
エンジニア研修と開発したプロダクトについて
セーフィーでは全体研修後、約3ヶ月のエンジニア研修があり、エンジニアとしての基礎を学びつつ、社内課題を解決するプロダクトを開発しました。課題選定から開発言語、体制まで全て自分たちで決める形式で、私たちは「isai connect」を開発しました。これは、他部署の方とランチに行くと会社がランチ代を負担してくれる「異才ランチ」制度をより活用し、活発化を図るためのプロダクトです。詳しくは以下の記事でご覧ください。
- 新卒研修の紹介とチーム開発前にやったこと
- 2024年新卒エンジニア研修-アジャイル開発編
- 2024年新卒エンジニア研修-isai connectについて
- 2024年新卒エンジニア研修-isai connect開発のアウトプット_サーバーサイド
- 2024年新卒エンジニア研修-フロントエンド開発編 ←本記事
- 2024年新卒エンジニア研修-インフラ構築編
- 2024年新卒エンジニア研修-isai connect開発のアウトプット_デバイス編
- 2024年新卒エンジニア研修-新卒研修の成果発表とその後
活動内容
今回のフロントエンド開発で行ったことは以下の通りです。
- 画面定義
- 実装
- テストコード実装
以上の工程について、それぞれ説明していきます。
画面定義
ここでは、Figmaを用いてアプリ内のページ遷移や各ページのレイアウト、UI・UXデザインを定義した画面仕様書の作成を行いました。 フロントエンド開発の担当者は決まっていたものの、画面仕様書を作成した際にはチームメンバー全員で確認を行うなどして、チーム内できちんと合意をとった上で画面定義を行いました。 また、我々の開発はアジャイル開発をベースにしていたので、スプリントごとに画面定義を行いました。アジャイル開発についてはこちらの記事をご覧ください。
画面実装
制作した画面仕様書をもとに、コーディングを行いました。
使用技術
今回の実装で使用したものは、以下の通りとなっております。
- プログラミング言語・・・TypeScript
- フレームワーク・・・React
- ビルドツール・・・Vite
- UIライブラリ・・・Material UI
- コード整形関連ツール・・・ESlint, Prettier
基本的に、ドキュメント量が豊富であり、サポートが現在も継続的に行われているツールを採用しました。また、実際にセーフィーで活用されている言語やツールを用いることで、配属後の学習コストを下げる狙いもありました。
工夫した点
Figmaで定義したフォントサイズやコンポーネントが画面上に反映されやすくなるよう、Figmaの設定に忠実に倣って、Material UIのコンポーネントのテーマを定義しました。 例えば、上の画像に定義されている黄色の「デフォルトボタン」では、ColorにSecondary、VariantにContainedが定義されています。
この設定をコード上では以下のように定義しました。これによりコンポーネントに”color=’Secondary’”、”variant=’contained’”というような形で変数を指定するだけで、この黄色のボタンをFigmaの定義通りに表現することができます。
components: { MuiButton: { variants: [ { props: { size: "small" }, style: { fontSize: 10 } }, { props: { size: "medium" }, style: { fontSize: 16 } }, { props: { size: "large" }, style: { fontSize: 24 } } ] } }
palette: { text: { primary: "#333" }, primary: { main: "#FFAD36", contrastText: "#fff" }, secondary: { main: "#2981C0", contrastText: "#fff" }, error: { main: "#D02F48", contrastText: "#fff" }, shadow: { main: SHADOW_COLOR }, disable: { main: "#757575" } }
テストコード実装
テスト方針
ページごとに単体テストコードを実装しました。 アプリ内のあるページを実装した人が、テストコードも合わせて実装するという方針で進めました。 今回のテストコード実装では
- 主に画面に情報がきちんと表示されているか
- ユーザーの操作をテスト内で模擬し、正しい振る舞いが画面上でできているか
といった、ユーザー目線に近い観点でテストコードを実装しました。
テストツール
テストコード実装の際に使用したツールは以下の通りです。
- Jest
- testing-library/react
気をつけたこと・学んだこと
きちんとテストコードを書いたり、チーム内でテスト方針を考えたりすること自体初めてだったので、とても学びが多い部分だったと感じております。 APIとの通信が絡む処理については、サービスの共通モックをあらかじめ作ることで、テストコード実装者によって、API処理周りの処理の書き方にばらつきが出ないようにしました。 学んだこととしては、テストコード実装初心者だった我々にとって、Jestやtesting-library/reactで提供されている関数や概念を理解するのに苦労しました。この仕組みはどのように使われ、なぜ必要なのかを一つずつ学んでいきました。 実際に私たちが実装したテストコードの一例をお見せします。
test("slackにURLを送信するテスト", async () => { renderDOM("register") const emailInput = screen.getByLabelText(/メールアドレス/) const registerButton = screen.getByRole("button", { name: /登録/ }) // 入力 await userEvent.type(emailInput, "test@example.com") // 登録実行 await userEvent.click(registerButton) await waitFor(() => { expect(screen.getByText(/まだ登録は完了していません!/)).toBeInTheDocument() }) }) test("slackにURLを送信するエラー", async () => { mockRejectedValueOnce(userService, "sendPasswordRegisterNotification") renderDOM("register") const emailInput = screen.getByLabelText(/メールアドレス/) const registerButton = screen.getByRole("button", { name: /登録/ }) await userEvent.type(emailInput, "test@example.com") await userEvent.click(registerButton) await waitFor(() => { expect(screen.getByText(/登録できませんでした。再度試してください。/)).toBeInTheDocument() }) })
こちらのコードはランチ相手が決定し、Slackに招待を送る部分の処理のテストコードです。正常系でテストを行った後に、異常系やレアケースもきちんとテストするようにしました。 何をテストし、どのような期待値が求められるのかをきちんとコード内で明文化することを意識しました。このコードに関して言うと、ユーザーのタイプ操作やクリック操作は非同期処理になるため、適切にawaitを仕込む必要性がありました。また、ユーザー操作の結果を受けて実行される処理に関しても、ユーザー操作の非同期処理を待ってから処理が走るように設定しなければなりませんでした。この設定を怠ると、非同期処理の部分だけ適切に実行されずに空回りし、望まないテスト結果につながってしまいます。
試行錯誤した部分
上述のように、フロントエンド開発といってもいろいろな工程があります。 特にこの中で一番試行錯誤した点を上げるとすれば、UI・UXデザインだと感じております。 「ユーザーが直感的に使えて、ストレスを感じさせないようなページ遷移、UIデザイン、誘導を行うにはどうすればいいのか」 このテーマを常に意識しながら画面定義を行っていたのですが、毎回スプリントレビューで上司の方々からご指摘をいただいておりました。 主にいただいていたご指摘としては、
- 同じ確認を何度もさせているので、ユーザーにとってストレス
- ボタンを押した後の結果が推測できない
- パーツの配置、サイズにどんなコンセプトがあるのかが考慮されていない
などがありました。
改善例
トップ画面の改善
トップ画面からランダムマッチングを選択した際、もともとは以下のような画面レイアウトと遷移を定義していました。
こちらの画面遷移についてご説明します。まず、左側にあるトップ画面に「異才を探す」という黄色いボタンがあります。このボタンをクリックすることで、真ん中に表示されている画面に遷移します。左側にある「ランダムに異才をさがす」というボタンを押すことで、画像右側にある確認画面へと遷移します。 しかし、これでは「異才を探す」という選択を、ユーザーに3回もさせてしまうことになり、明らかに冗長な工程だとわかります。 そこで、操作回数を減らしつつ、ユーザーが操作内容を直感で推測できるように改良したものが、以下の画像になります。
マッチング方法の選択作業をページ一つにまとめ、ボタンを押せばどのような処理が走るのかが一目でわかるような見た目にしました。 また、上二つのボタンと下の「部署を選んで」ボタンにも工夫した点があります。上二つのボタンは、押下後にすぐにマッチングが走る仕組みです。人数は異なりますが、「すぐにマッチングが走る」というコンセプトが一致しているため、ボタンのサイズや形状を統一させています。対して、下の「部署を選んで」ボタンは、ボタン押下後に部署の選択画面に遷移するため、すぐにマッチングが走るというわけではありません。このようにコンセプトが上の二つのボタンとは異なるため、形状とサイズに違いを持たせました。
プログレスバーの追加
ユーザーが実際にマッチングを行い、マッチングが終わった後の結果表示からSlackへのメッセージ送信完了への画面遷移に関しても、改善前は以下のように定義していました。
「トップ画面の改善」の節でお見せした改善前の画面遷移と合わせて見てみます。私たち開発側からすれば、この遷移で問題ないように見えてしまいますが、この状態でリリースされたアプリを初めて触るユーザーは違います。この画面遷移のままだと、ユーザーが何かボタンを押した後の結果が、実際に遷移されてからでないとわかりません。 この問題を解決するために導入したのが、画面上部に表示するプログレスバーです。プログレスバーを導入することで、ある操作をした後にどういう状態になるのかが一目でわかるようになりました。
アプリのフロントエンド開発をしてみて
私たちは常日頃からアプリケーションを利用しています。しかし、いざユーザー視点でアプリを作るとなると、日ごろからアプリを利用している身であるにもかかわらず、考えが及ばなかったり、意思決定に時間がかかったりする場面がたくさんありました。フロントエンド開発に今後も携わる身として、ユーザーにストレスを与えず、直感で機能・場所・状態を即座に推測できるようなUI/UXデザインができるように、日々精進していきたいと思います。私たちが開発したアプリを通じて、部署の垣根を超えたコミュニケーションが、社内でより活発になれば幸いです。 最後までご覧いただきありがとうございました。