会社初のフロントエンドエンジニア

北嶋初音氏(以下、北嶋):では、「Vue.js + TypeScriptによる新規サービス開発の振り返り」と題して、UI開発課の北嶋初音が発表を始めたいと思います。

まず軽く自己紹介します。名前は北嶋初音と言います。経歴ですが、2016年の4月からWeb系のITベンチャーに新卒入社しまして、Webエンジニアとしての経験を積みました。次は自社サービスを作っている会社で働きたいという気持ちがあったので、転職活動を始めて、今年の1月からラクスに中途入社しました。

前職ではバックエンドもフロントエンドも触る、いわゆる普通のWebエンジニアみたいな感じだったのですが、ラクスに入社してからはフロントエンドエンジニアをやっています。会社としてラクス初のフロントエンドエンジニアということで、そこそこプレッシャーがかかるような環境ですが、そんな感じで働いています。

ラクスに入社してからは、主に新規サービスである「楽楽勤怠」の機能開発を担当しています。またほかにも、社内のフロントエンド組織のベースづくりとして、フロントエンドエンジニアの育成プランを考えたり、実際に新卒の教育を行ったりしています。

新規サービスである「楽楽勤怠」は、画像に「勤怠管理の“面倒くさい”から解放します!」と書いてあるとおり、toB向けの勤怠管理Webアプリです。

画像を見るとわかると思うのですが、PCとスマホ版があって、この両方のブラウザから使えるように対応するのがけっこう大変でした。去年の10月からスタートしたプロジェクトで、開発の期間はちょうど1年間ぐらいですね。ちょうど今月頭に無事リリースしまして、今後も新規機能を続々追加する予定です。

本日話すことですが、「楽楽勤怠」の開発初期からリリースまで関わった、私なりの振り返りというか、よかったところやつらかったところについてお話ししたいと思っています。開発体制と利用技術の2つの軸からお話しして、最後に今後の開発について触れたいと思っています。

「楽楽勤怠」の開発体制

では、まず開発体制についてお話ししたいと思います。「楽楽勤怠」では、フロントエンドの開発にSingle Page Application、SPAを採用していまして、フロントエンドとバックエンドを完全に分けて開発しています。

具体的には、下の図にありますが、バックエンドはWeb APIを作成することに注力して、フロントエンドはそのAPIをAjaxで呼び出してレスポンスのところをゴニョゴニョといじって画面表示したり、APIを呼び出して情報を更新したりという感じでやっています。

全体の開発体制は、以下の画像のようになっています。プロダクトマネージャー(PdM)が1人いて、UIデザイナーが2人。右側の黒い枠がエンジニアですが、フロントエンド(FE)が4人、バックエンド(BE)が6人という体制で開発しています。これは現在の開発体制ですが、初期には本当にフロントエンドエンジニアが1人だったり。今はだいぶ人が増えてこうなったという感じです。

この特徴としては、先ほども言いましたが、フロントエンドとバックエンドを完全に分けて開発している部分です。

次に開発のフローについてですが、まずはプロダクトマネージャーが要件仕様書を作成します。これを受けて、Webデザイナーがデザインを作成し、バックエンドエンジニアはAPI仕様書を作成します。これらの要件定義書とデザインとAPI仕様書、この3つを受けて、フロントエンドエンジニアは画面の開発をスタート。それと並行して、バックエンドエンジニアはAPIを実装していく感じでやっています。

特徴としては、フロントエンドとバックエンドが、並行で開発しているという部分ですね。APIは、はじめはAPI仕様書でインターフェースだけ共有しておいて、フロントエンドのほうでJSONのモックサーバーを立てて、それを利用して開発しています。バックエンドエンジニアは、APIを実装後につなぎ込みを行っていました。

開発体制でよかった点

この開発体制でよかった点は、SPAを使ったことで、最小限のデータやりとりでOKなので、スムーズなUI/UXを実現できる部分です。

Web APIを採用したのは、SPAと相性がよかったり、フロントエンドのモダンなフレームワークを利用しやすかったり、そういう部分がよかったと思っています。「楽楽勤怠」では、後々お話ししますが、Vue.jsを採用しています。

また、再利用できる点がすごくよかったかなと思っていて、PCだとかスマホで同じ機能を実装するということが多々あったのですが、そのときも同じAPIを呼べばいいという部分は、非常に実装で助かった部分でした。

バックエンドとフロントエンドを分けた開発のよかったところは、やっぱりそれぞれの作業に集中できるというところです。

フロントエンド的には、デザインの再現だとか画面の表示・動作に注力できますし、APIについては、中身を知らなくてもインターフェースだけ把握しておけばOKというところがすごく助かりました。あと、バックエンドとフロントエンドが並行で開発できるので、やっぱり開発が早くて、工数削減にもなりました。

開発体制でつらかった点

逆につらかった点は、主に開発フローのところですが、フロントエンドが、さっき言った3つの資料ですね、要件仕様書とデザインとAPI仕様書、このすべて見ておく必要があって、けっこう変更に気づけないときがありました。

今後の対応として、それをウォッチできる仕組みを作っておく必要があるかなと思っています。現状は、変更者が忘れないようにチャットツールなどで通知するしかないのですが、今後はチャットに自動投稿する仕組みを作ったりするような変更があった場合に、そのあたりについて考えていけたらいいかなと思っています。

次のつらかった点ですが、デザインだけでは細かい挙動を読み取れないので、さきほどの3つの資料を見比べて、「動作はこうなるんじゃないかな?」というのを、フロントエンド側で想像して作らないといけないところがありました。そうなると、実装者以外の人は動作の正当性がわからなくて、レビューのときにこの動きで正しいかがそもそもわからず、レビューできないという問題がありました。

対応としては、「このボタンを押したときにこういう動きをするのが正しいよね」という細かい動作について記載した画面仕様書を作っていこうと思っています。これは、実際に実装前にデザイナーや要件定義者のレビューを挟んで、「この動きで作ります」ということと、それに対して「正しいよね」というところを決めて、それから実装に着手していこうかと思っています。

もう1つ、フロントエンドがAPI仕様書を参考にモックを作らなきゃいけないところがけっこうつらくて、ローカルで各自JSONサーバーを立てて対応していましたが、正常系・異常系の全パターンを網羅する必要があったり、あとAPI変更があったときに、出戻りがけっこう多かったりという問題がありました。

これに対して今考えているのが、バックエンドのAPI仕様書がOpenAPIで書かれていて、その機能にモックというものがあるらしいので、定義ファイルからモックサーバーを立てられないかなと考えて、調査しているところです。

ここまでが開発体制についてですね。次に利用技術についてお話ししたいと思います。

「楽楽勤怠」フロントエンドの技術スタック

フロントエンドでは、Vue CLIでプロジェクトを作成していて、導入している技術は以下のおりです。TypeScript、SCSS、Vuex、Vue Router、Vuetify。あと、ESLintやPrettierを入れています。そんなに変なのは入れていないですね。定番というような感じです。

そもそも、なぜVueを選定したのかという部分ですが、これは直接自分が選定したわけではないので、理由を選定した方に聞いた話なのですが、Vueだと使える人が多いという理由だったようです。確かに学習のハードルも低いし、日本語の情報・ドキュメントが充実しているので、そういう側面で技術を選ぶのも、選択肢としてはありなのかなと個人的には思いました。

この利用技術でよかった点は、まずVue.jsについてはコンポーネント化がやっぱりすごく助かりましたね。ここに書いている基底コンポーネントは、ボタンなどいろいろな画面で使うコンポーネントなのですが、これについては、1回作ってしまえば再利用できるので、開発が進めば進初期むほど実装スピードが上がるのを実感できました。

しかも、PC版でもスマホ版でも、別のスタイルを当てちゃえば、そのまま使えるというのもすごくよかったですね。あとはscopedなCSS記述ができたことも、すごく助かりました。やっぱりグローバルに影響を与えるCSSとかが多くなってくると、どんどん管理できなくなってくるので、ここもすごくよかった点ですね。

あと、コンポーネントがデザインのアトミックデザインと相性がいいので、けっこうデザイナーとのやりとりがやりやすかったかなと感じています。これらによって、高度なUI/UXの表現が可能になったと思っています。

TypeScriptのよかった点・苦労した点

次にTypeScript。これはやっぱり、型指定で安全な開発が行えるという点がすごくよかったです。また、エディタで補完機能が効くので、すごく開発スピードが上がったと思っています。

あと、これは個人的に一番助かったところなんですけど、ドキュメントとして機能するので、(スライドの)下の例はメソッドに型の指定がある例なのですが、getItemというメソッドは「idというnumber型のものを引数に受けて、Itemという型のものを返す。見つからなかったら、たぶんundefinedが返ってくるのかな」というのが、なんとなく想像できるので、コメントはあんまりしなくてもいいのがすごく助かりました。

逆につらかった点は、TypeScriptに関しては、よく言われるのですが、Vue.jsとの相性の悪さがありまして、Vue.jsとの型の衝突がけっこうあって、「どっちで書くか?」みたいなのもありました。

あとは、開発初期は全然ルールを決めていなかったので、anyや、この「!」マークで、型指定からけっこう逃げてしまっている箇所が多いのが、今すごく問題になっています。これに関しては、既存の箇所から徐々に指定していくしかないかなと思っていて、最終的にはlintで弾けたらなと思っています。

先ほどもありましたが、API仕様書の変更に気づかないと、型の定義がAPIとズレてしまって、けっこう気づかないうちに表示が正しくされなかったりするので、このあたりの対応として、API仕様書の定義ファイルからTypeScriptの型を生成する仕組みを導入しようかと考えています。

あとTypeScriptは、enumの機能の利用が推奨されていないので、これに対してはUnion Types + as constという機能に置き換えることで対応したりしました。

VuexとVue Router

次にVuexについて。これもルールをあんまりしっかり決めていなかったので、Storeでもつべきでない値をいくつか持ってしまっていました。Vuexはグローバルな値なので、最小限にすべきかなと思っていて。今後はどんどんローカル変数のほうに移行していこうかなと考えています。

あとバグであったのが、ほかの画面でfetchした情報がクリアされていなくて、別の画面で同じ情報を利用してしまい、影響を与えてしまった部分がありました。

今までは、その画面で利用したmoduleをその画面から遷移する前にクリアしていたのですが、今後はその画面で利用するmoduleを画面に入ってきた時にクリアしてから、画面の表示を行うようにしようと思っています。つまり、moduleのクリアはその画面の役割にしていこうと考えています。

次にVue Routerですが、けっこう履歴の管理が大変で、「この遷移したときはhistoryに積むのか?」「このときは積まないのか?」みたいなのを、実装者がその場で考えてたりとかするので、ここでも「これで正しいのか?」がわからないという問題があったので、これも画面仕様書というふうに「この場合は積む」とか「この場合は積まない」というのを記載していこうかなと思っています。

あとバグであったのが、URLのparamを直接参照していると、画面を高速で移動させていて、前の画面で叩いているAPIにidを渡しているときに、次の画面のparamのidを使ってAPIを叩いているという問題があったりして、それでバグが発生したりしていましたね。なので、それもローカル変数に代入して、そこから利用するように対応していこうかと思っています。

パフォーマンスの向上

けっこうつらかった点ばかりなのですが、パフォーマンスですね。SPAでよく言われるのですが、初期表示のパフォーマンスがやっぱり悪かったです。特にテーブルを使っている画面や、複数のAPIを利用している画面で要素数がすごく膨大になってくる場所がすごく重かったりしました。

この対応としては、要素の描画をテーブルなら、最初に5行目まで表示して、段階的に次の10行目まで表示して、というようにだんだんと表示していくことで、初期表示のパフォーマンスをよくしたりして回避していました。

あとは、先ほど言った基底コンポーネントですね。いろいろな画面で使うコンポーネントですが、この機能がどんどんリッチになっていくと、どんどんパフォーマンスが劣化していく問題がありまして。

現状、基底コンポーネントは、Vuetifyをラップしたものを使っていますが、Vuetifyを使っている方はわかると思うのですが、もともとの機能が大量に入っているので、使っていない機能のほうが多かったりして、だんだんそれをオリジナルのものに置き換えて、余計な機能を削っていきたいと考えています。

テスト環境の整備

次のつらかった点なのですが、テストコードがないというところで、これは工数的に書く余裕がなかったから書かなかったのですが、やっぱりリファクタリング時などにデグレの発生が検知できない問題がありまして、今後はテストを入れていきたいと話しています。

テスト環境はJestを入れようかなと思っています。あと、自動テストも入れたいなと思っています。CIを使って、例えばマージリクエストだとか出したタイミングで、自動テストが走るようにしたいと思っています。

また、テストがなかったので、やっぱりテストを意識したコーディングになっていないという問題があって、Vueファイルがロジックを持ちすぎている問題があります。これに関しては、helperのファイルにロジックを移行して、Vueファイルではそれをインポートして使うだけにしていこうかなと思っています。

あとはVue3.0への移行。これのComposition APIが、ロジックを抜き出すところにつながってくるので、移行したいなぁと。ドメイン駆動の思想も、ロジックを抜き出すところが共通していると思うので、これも入れようかなとか、いろいろ考えているところです。

これからの開発をどうしていくか

最後に、これからの開発をどうしていくかについて話していこうと思います。

「振り返り作業」と書いてあるのですが、フロントエンドチームでリリースまでの開発の振り返りを行いました。これはけっこうやってよかったなと思っています。先ほど挙げたような「つらかった点」は振り返りで出たもので、本当はもう40件ぐらいあったのですが、一部を抜粋して載せました。

振り返り作業は、各々がスプレッドシートに改善したい項目を記載していって、この下の画像にある「H」が「High」ですね。重要度と緊急度の2軸で「High」「Middle」「Low」で評価しまして、今後は緊急度のHighから対応していこうと考えています。

新規機能の開発と振り返り作業で出た改善タスク、これを並行で進めていこうかなと思っています。もちろん優先度は新規開発が高めで、それが終わって余った時間で、改善タスクをやっていこうと思っています。

フロントエンドの新規機能の開発は、コンポーネント化することによって楽になってくると想定していまして、バックエンドよりは工数が小さくなるはずなので前倒しで進めていって、その分、改善タスクのほうを対応して、開発しやすい環境を整えていこうかなと思っています。

すごく駆け足になってしまいましたが、発表内容は以上でして、最後宣伝になってしまいますが、ラクスでは定期的にこういうミートアップや勉強会を開催していますので、どんどん参加してもらえるとうれしいです。フロントエンドエンジニアも絶賛募集中ですので、興味ある方はちょっと見てみてください。

発表は以上です。ご清聴ありがとうございました。

質疑応答

藤澤貴之氏(以下、藤澤):北嶋さん、ありがとうございました。

池田智裕氏(以下、池田):ありがとうございました。まず、複数の質問があったのですが、モックサーバーのテスト環境と本番の切り替えをどのように実現されていたのでしょうかと。

北嶋:基本的には手元で動かすときは切り替えるようにしていました。なので、ローカルでモックサーバーを立ち上げていたので、手元で動かすときだけAPIの叩き先を変えていました。

池田:設定ファイルかなにかでちょっと変えるみたいな感じですかね。

北嶋:はい。そうですね。一部だけモックサーバーみたいにもできるようにしていて。

池田:一部だけもできるんですね。

北嶋:はい、実際につながっている部分は、本番の環境と同じようなAPIの検証環境みたいなものがあって、そこにつなぎ込んでおいて、一部は手元でURLだけ変えてモックサーバーにつなぎ込むというふうにしていました。

藤澤:質問の回答としては、手動で書き換えていましたということになりますか?

北嶋:そうですね。

藤澤:それは「開発中モード」や「プロダクションモード」みたいなものを設定ファイルでバチンっと替えたりとか、そういう感じだったりするんですか? それとも……。

北嶋:モックサーバーに関しては、そこでは切り替えていないですね。

藤澤:それは本当に開発中だけだからみたいな感じで?

北嶋:開発中だけだからですね。

藤澤:なるほど。

北嶋:ビルドの設定とかは、それで切り替えたりはしていますね。本番用とかで。

池田:ありがとうございます。ちょっと今ちょうどチャットのほうに「モックサーバーでなにかライブラリなどを使っていれば知りたいです」というような質問が。

北嶋:ライブラリは特に使っていないですね。JSONサーバーは利用してますけど。

藤澤:ライブラリというか、ツールでしょうか。

北嶋:そうですね。

池田:あと、ちょっと回答しにくいかもしれないですが、「フロントエンドとバックエンドを分けて開発スピードが上がったというのは、なにか比較対象があったのでしょうか?」と。

北嶋:初めから分けていたので、確かに比較対象はないですね。

藤澤:でも、実際わりと短期間でリリースできたっていう。

池田:そうですね。ものすごい短期間で。これは新規サービスになるんですけれども、ちょっと弊社の中では信じられないぐらいのスピードでどんどん機能を開発していったという意味では、すごいスピードと言えるかもしれません。数値では出せないんですけれども。

藤澤:技術的な要素だけじゃなくてマネジメント要素も当然あるとは思うんだけれども、今回の体制はかなりよかったというような評価を社内では受けていますね。

池田:ちょっと毛色は違うんですが、社会人1年目で、ちょっと技術的な質問ではないのですが、「なぜ自社開発のある企業を探していたのですか?」と。自己紹介のときの話ですね。

北嶋:前職は、わりとお客さんありきというか、ほぼほぼお客さんが仕様を決めて、そのまんまそれに忠実に作ることが重要だったのですが、自分はわりとそこじゃなくて、自分でも「こうしたらいいんじゃないか?」という提案がしたかったので、それで自社サービスだったら実現できるんじゃないかなと思って、転職活動をしたという感じですかね。

池田:実際どうですか? 転職してみて。

北嶋:かなり裁量はありますね。自分から情報をつかんで、提案もどんどんしていかないといけない状態ではありますね。

池田:ありがとうございます。あと、ちょっと質問ではないんですが、「ConfluenceとSlackをつなげればよかったのに」と。なんかConfluenceというのはWiki的なもので、そこを変えればSlackとつなぎこんでなんかタスク化とかチャットをつなぐことができるようなので、ぜひ弊社で取り入れてみたいですね。

藤澤:ところで今、設計ドキュメントってどういうふうに管理していますか? ナレッジの共有とか。

北嶋:API 仕様書で言えば、GitLabに。

藤澤:ああ、GitLabのWikiを使ってやっている感じで。

北嶋:そうです。Wikiというよりは、Swaggerで書かれていて、GitLab上で見れるようになってますね。

池田:北嶋さん、ありがとうございました。