Retty Tech Blog

実名口コミグルメサービスRettyのエンジニアによるTech Blogです。プロダクト開発にまつわるナレッジをアウトプットして、世の中がHappyになっていくようなコンテンツを発信します。

サマーインターン ユーザーアイコンのマイクロサービスと店舗詳細のOGP生成を実装しました!

こんにちは、エンジニアサマーインターンねこチームです。

今回のインターンでは、ねこチームは次の開発を行いました。

  • ユーザーのアイコンを配信するマイクロサービス
  • 店舗詳細ページのOGPを配信するマイクロサービス

この記事では、Rettyのサマーインターンの開発の進め方と、上記の開発の概要とそこで学んだことを紹介していきたいと思います。

開発の流れ

朝10:30にディスコードで集合し、その日のタスクを確認して開発に着手、あとは休憩を挟みつつ19:30頃になったら明日のタスクを確認して解散。といった感じで三週間勤務しました。 チームは社員のメンターさんが1人、インターン生が4人の計5人チームで、全てモブプログラミングで行いました。 モブプロで進めるメリットとして、他の人に指摘する/してもらうことで、慣れない技術に対してキャッチアップする機会が増え、足並みを揃えて技術習得するのに効率が良いと感じました。

KPT で振り返り

週の最後には、チームの動きについて振り返りをしました。
KPT とは、Keep, Problem, Try の略語です。つまり、「何ができたのか」「何ができなかったのか」「次どうするか」ということをそれぞれ整理してみんなで考えよう、といった感じです。
チームの動きを改善する場、にもなりつつ、メンバーたちが雑談をする場にもなって、色んな点で良い取り組みだったと思います。

f:id:rettydev:20210909162437p:plain
KPTの様子

ユーザーアイコンサービス

開発背景

Rettyでは、複数のSNSと連携してアカウントが作成できますが、アイコン画像のハンドリングに下記の課題がありました。

  • 連携するSNSが増加し、各SNSからのアイコン画像の取得方法が複雑化
  • 画像のURLがSNS側で変更され、リンク切れ
  • イコン画像の取得時にアクセストークンが必要になるというSNS側の仕様変更への追従

などの課題があって、これらのユーザーアイコンの複雑な対応を請け負うマイクロサービスを作りたいという話になり、ねこさんチームが開発を担当する運びとなりました。

今回のインターンではまず足掛かりとして、クライアントから/id/:id のようにユーザーIDをパスパラメータに指定すると、DBからアイコンURLを取得して、画像を引っ張ってきて返すプロキシのようなエンドポイントを実装するところまでを行いました。

実装概要

言語はGo、フレームワークは軽量なものをということでEchoを使用しました。

具体的な処理としては、ユーザーアイコンサービスは

  • DBからユーザーのアイコンURLを取得
  • HTTPクライアントとして、外部のSNSに画像を取りにいく
  • 画像をレスポンスとして返す

という流れです。

実装自体は非常にシンプルですが、長期的な運用を想定して、今回のインターンでは、CleanArchitectureを意識して、丁寧に設計&開発を行うことに重きを置きました。

CleanArchitectureとは、ソフトウェアの設計に関する考え方で、下記の円の図が有名ですが、端的にいうと「依存性を一方向にしよう」という考え方です。

The Clean Architectureの説明図

引用 Robert C. Martin, The Clean Architecture., https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

今回の実装では、まず、重要な要素であるEntitiesを

  • ユーザー情報
  • ユーザーアイコン(URLなど)

としました。このように決めた理由は、まずリクエスト元のユーザー情報が必要ということと、リクエストされたユーザーアイコンという2つのドメインオブジェクトに分けることができると考えたからです。

また、

  • データ取得をする処理では、MySQLクライアントやgRPCクライアントなどのデータアクセスのクライアントを抽象化
  • ユースケースでは、データ取得を行う構造体を抽象化

などの設計を意識しました。上記のように依存性が中から外に向かう場合は、 依存性逆転の法則に従い、インターフェースを用いて抽象化して、依存性を一方向にしました。

依存性を方向を統一すると、内側の処理が外側の詳細を気にしなくて良くなります。 例えば、「外部からユーザーの情報を取得する」ような処理をする場合に、それがMySQLなのか、マイクロサービスにgRPCで取りに行っているのかなどは、処理を呼び出す側は何にも考える必要がありません。 それこそMySQLからマイクロサービスに置き換わるような場合や、テストでスタブに置き換える場合など、そのまま取り替えることができるし、データリソース特有のロジック(論理削除やテーブルごとに接続先を変えるなど)を変更する場合に、このレイヤーだけ修正すればよくなり、内側に対して副作用がない設計にすることができます。

店舗詳細ページOGP 

実装背景

サマーインターンのもう1つのチームいぬさんチームがOGPのマイクロサービスの土台を作ってくれていました。 ねこさんチームはそこに店舗詳細ページのOGPを生成する機能の追加の開発を行いました。

元々の店舗詳細ページのOGPは、

  • 選択される写真のロジックがブラックボックス
  • 多少リサイズはされているが画像をそのまま表示

画像サイズや見た目としてOGPとして相応しくはないものでした。

そこで今回の開発では、「アイキャッチ」や「イメージ」を重要視し、1枚写真をトリミングするシンプルなOGP生成をしました。

具体的には、下のように元画像のアスペクト比によって、画像をトリミングします。

  • 800:630より縦長の場合、左右をトリミングし、余白を白抜き
  • 800:630より横長で、1200:630より縦長の場合、上下をトリミング
  • 1200:630より横長の場合、左右をトリミング

f:id:rettydev:20210909160249p:plainf:id:rettydev:20210909160252p:plain
OGPのトリミング

実装概要

言語とフレームワークには、同じくGo/Echoを使用しました。 OGPの生成には、以下の2つの実装方法が考えられましたが、HTML/CSSを用いてシンプルにスタイリングしたいという理由から前者を採用しました

OGPの生成(スタイリング)では、画像のアスペクト比に応じて、3種類の異なるHTMLテンプレートを適用して、トリミングします。 ねこさんチームでは、この「アスペクト比に応じて、適用するHTMLテンプレートを差し替える」という処理をどこに書こうかという議論が白熱しました。

実装の選択肢としては、次の2つがあがりました。

  • 画像を取得するタイミングでアスペクト比から適用するテンプレート情報を画像情報オブジェクトに含めて戻り値として返して、HTMLを生成するタイミングでテンプレートを選択する
  • 画像を取得するタイミングでは画像の縦横の幅を画像情報オブジェクトに含めて、HTMLを生成するタイミングでアスペクト比に応じて適用するテンプレートを選択する

f:id:rettydev:20210909110414p:plain
処理フロー

前者に従ってオブジェクトに適用するテンプレートをEnumなどでプロパティに持たせれば、便利なオブジェクトとなりそうですが、 「アスペクト比がいくつの時はこのテンプレート」というView側の知識が、本来データを取得処理のみをすべき処理の中に混在してしまいます。 また、CleanArchitectureの考え方に従うと、外側のレイヤーであるViewに依存したデータアクセスの処理をするべきではないという理由により、後者の方針に従い、実装しました。

学びや感想

今回、実際に使われるマイクロサービスや機能の開発をすることができ、

  • デザイナーやプランナーなどとコミュニケーション
  • 保守性を意識した技術選定や設計
  • 納期や実際に使われることを意識した現場の開発

など、普段経験することができない貴重な経験をすることができました。

また、3週間という短い期間で

  • Go言語
  • マイクロサービス
  • CleanArchitectureなどの設計技術
  • gRPC
  • 自動テスト

などの様々な技術に触れ学ぶことができました。 特にCleanArchitectureなどの保守性を意識した開発は、普段の個人開発や大学でのプログラミングではあまり扱うことがなく、現場のエンジニアからレビューがもらえるありがたい環境でした。 また、インターン生同士でも、たくさん議論して、設計技術を磨くことができました。 インターンは終わりますが、まだまだ、理解や経験が足りないことを実感していく毎日なので、今後とも、今回学んだことを足掛かりに学んでいきたいと思います。

最後に、メンターの神さんをはじめ、最高の環境を提供していただいたRettyの皆さんありがとうございました。