GWも終わりましたね。皆様どう過ごされましたか?
GWの延長線で、有給を取るスタッフも多く、今日はオフィスが、がらんとしています。
今回は4月にリリースされた「チャット複数枚画像送信」に関して、CTOの名人さんに突撃インタビューしました!
今回の開発の山場や工夫点、今後の改善につなげたい点など語っていただきました!
NoSchoolではエンジニア採用も積極的に行っているので、興味ある方は「話を聞きに行きたい」からご連絡くださいね!
-今回リリースした機能の内容を簡単に教えて下さい!
チャットで複数枚の画像を一度に送信・削除ができる機能です。これまでマナリンクのチャット機能では、一度に5枚まで画像を送ることはできましたが、ユーザーさんからの見た目としては5通のメッセージに1枚ずつ画像が添付されている見た目になっていました。 今回のアップデートで、1通のメッセージに5枚添付されているように見えるようになりました。 また、一度送った画像を削除したいときには、削除用のモーダルが表示されて、消したい画像を送った2〜5枚の中から選んで削除されるようになりました。
-おー!実際に画像で見せていただけますか?
もちろんです!これまでは画像を送ると1枚あたり1メッセージになっていましたが、今回のリリースで5枚までの画像を一度に送ると、以下の画像のように表示されるようになりました。
また、送った各画像をタップすると、全画面で拡大表示されるようになりました。これまでは別タブで画像が開いていました。 拡大表示された画像は、左右の矢印をクリックすることで、前後に移動できます。同時に送った5枚の画像内で移動できます。右上のバツボタンで閉じることができます。右下の保存するボタンを押すと、画像を名前を付けて保存できます。
送った画像は選択して削除できます。送った画像メッセージのゴミ箱ボタンを押すと、以下の画像のようなモーダルが出てきて、削除したい画像をチェックで選んで、削除するボタンを押すことでまとめて削除ができます。 なお、細かいですが、1枚しか画像を送っていないときは、このモーダルを介さずにいきなり削除できます。
これらの機能はReact Nativeアプリでも実装しています。画像は複数枚選択して削除するときのスクリーンショットです。
-おー!実際に画像で見るとすごい!ちなみに今回この開発を始める前に、技術的に一番ネックだと思ったことはなんですか?
既存の画像つきのメッセージはメッセージごとに1枚添付される前提でデータ構造が組まれていました。そのため、既存データの読み取りにも対応しつつ、複数枚添付できる新形式でのデータ形式に対応できるように互換性をもたせて実装できるのか、という点がネックだと感じてましたね。
-アプリ側担当したゆうきくんはどうですか?(※いきなり話を振ってみました)
え?あ、画像を複数枚送信したときの見た目の特徴として、1枚〜5枚の画像を格子状に並べつつ、最後の画像は横長に表示するというデザインがあったんですが、個人的にスタイリングが苦手なので、うまくデザインどおりに実装できるか不安でしたね...
‐今回の機能の開発を初める前と開始後に、「技術的に一番ネックだったこと」にGAPってありましたか?
ありましたね。
Webで画像を拡大表示したときに、保存するボタンを押すと画像が保存できるという機能があったんですが、これの実現が結構難しくて時間がかかりました。
保存するボタンを押すと画像が保存できる
というのは簡単そうに見えて結構奥が深いです。なぜならブラウザでは画像を右クリックして保存するのが一般的で、「プログラムが画像を保存『させる』」というのは比較的珍しいため、仕込みが必要だったからです。
ここに関する見立てが甘く、GAPが生まれました。
事前知識として、画像のUpload時にContent-Dispositionヘッダーにファイル名を指定しておくことで、画像のURLをaタグに指定したときに、クリックしただけでブラウザが自動で保存させることができるというのは知っていました。が、今回の施策では過去の画像に対しても保存するボタンを実装する必要がありました。そのため、過去にUploadされた、すなわちContent-Dispositionヘッダーを指定していなかった画像に対しても保存するボタンが動作するようにしないといけませんでした。
この点について悩んだため、そもそもContent-Dispositionヘッダー以外で保存させる機能を実装できる抜け道を調べ、あるにはあるけどマナリンクではフロントエンドのドメインと画像のドメインが異なるためCORSに引っかかり実装ができないといった部分を調べたり検証するなどを経ました。
最終的に、過去画像に対してもContent-Dispositionヘッダーを付与できるように間にプロキシとなる処理を挟むことを思いついて解決したので、よかったですね。
‐うーん。なるほど。「保存するボタンを押すと画像が保存できる」って当たり前そうなので簡単そうに見えますがそんな道のりがあったんですね...ちなみに今回の開発の山場はどんなところでしたか?
【アプリ】
複数枚送信したときの画像の1枚〜5枚の見た目ですね。 最初、1枚〜5枚の画像の配列を受け取ったあと、1度の繰り返し処理で全パターンの画像の表示を扱おうとして苦労しました。
苦心していたら、「たった5パターンしか現状は無いんだから、愚直に実装してみたらいい」というアドバイスを受けて、5パターンのそれぞれの表示サイズや形状を見直して、愚直に実装することで、要件を満たすことができた。いきなり完璧な実装を目指すのではなくて、不安なときはまず愚直に実装することが大事だと感じましたね...
【Web】
すでに前の項目でお話したんですが、画像を名前を付けて保存できる機能ですね。
あと、iOS端末×画像一覧機能で、画像を拡大表示できる機能 画像一覧機能という、過去のチャットメッセージから画像だけを一覧できる機能があるが、この機能はモーダルで画像を一覧できるため、ここからさらに画像の拡大表示を実装すると、モーダルの上にモーダルを乗せることになりiOS Safariでスクロールの動きがおかしくなったところも山場でしたね。
ここではDOMの置き方やz-indexの値を工夫することで、本機能を実装しました。
‐今回の開発機能の技術的な工夫点はどのようなところですか?
先ほどGAPの部分でお話した、「画像を名前を付けて保存できる機能」ですね。
あとは画像を複数枚、モーダルで指定して削除する機能です。
Web/アプリ共通ですが、選択された画像を保持するステートや、削除ボタンを押したときの削除処理を動かすハンドラなどを同じカスタムフックにカプセル化して、処理を見やすくしました。
‐開発中に個人として気をつけていたことや工夫した点はありますか?
ChatGPTを積極的に活用しました。
要件があまりドメイン知識の無い要件だったので、活用しやすかったと思います。要件の中から、マナリンク独自の知識やインフラ知識を問われる部分を除いて抽象化した質問を作り、プロンプトとして投げるところを工夫しました。
‐ちゃんとChatGPTを使いこなしているのがすごい!今回の機能のリリース前とリリース後に「個人」として成長した部分はありましたか?
ChatGPTを使って開発を進めるのが上手くなったと思います。(笑) また、Content-Dispositionヘッダーを中心とする、ファイル保存に関わるブラウザの挙動について詳しくなりました。
‐アプリ側を担当したゆうきくんはどうですか?(突然また話を振ってみる)
え。(また突然....)えっと... 配列操作に関しての引き出しが増えたような気がします。特に画像の表示方法に関しては、渡ってきた配列を2個ずつにsliceして表示しています。配列のメソッドに関してはある程度知っていましたが、どのように使うのかがイメージできていなかったので、それらを知れたのは個人的に成長できた部分だと思います。
‐今回リリースした機能が80%の完成度だとして、残りの20%でどのように発展していきたいかなどあれば教えてください。
なるほど。4点ほどありますね。
Content-Dispositionヘッダーを付与するためにプロキシする処理が、あまりインターネット上で前例が見当たらなかったので、何か罠があるかもしれないと思っています。なので、余裕があればレスポンスタイムやコールされた回数などを監視する仕組みも作りたかったなぁと思います。
現在Webのフロントでは、アプリのReact Nativeに合わせるためにNuxtからNextへの段階的な移行を進めていますが、工数が許せば今回の実装の段階でチャット機能をNextに移行したかったです。ただ今後チャット周りで大きな改修予定があるのでその時でいいかなと思っていて、そこまで考えると、移行を見据えた設計の工夫はもっとやりようがあったかもしれないと思っています。
また、画像の表示の際に、S3にアップロードした画像をそのまま表示しているのですが、imgixをCDNとして採用しているため、imgixを介した画像を表示するようにしたほうがネットワーク負荷が減ります。こちらも今後改善する予定です!
あと、現在React Nativeアプリにて実装中ではありますが、画像をまとめて送信したとき、ユーザーをある程度待たせることになるので、画像ごとに送信処理の進捗度を円グラフ風に重ねて表示するようにして、待っている感覚を軽減したいですね。
まあいろいろやりたいことあるので、まずは一緒に頑張ってくれるエンジニアさん募集してます!
名人さん、ゆうきくんありがとうございました!現在NoSchoolではエンジニア採用を強化中!いろいろな開発や改善をおこないながらご自身も成長していきませんか?
興味ある方、「話を聞きに行きたい」ボタンからでもいいですし、応募から直接質問いただいてもOKです!皆様の応募お待ちしております!
★現在募集中のエンジニアポジション
株式会社NoSchoolでは一緒に働く仲間を募集しています