フリーランスでソフトウェアエンジニアをしているTatsunoriです。
プライベートではReact Nativeをメインに個人開発でアプリを作っています。
作ったもの
家族向けの写真共有アプリ「ファミリーフォト(仮)」を開発しました。
イメージとしては家族限定版の「みてね」です。
現在はTestFlightで家族のみに配布しています。
解決したかった課題
このアプリは以下の課題を解決する目的で作成しました。
1. 写真のバックアップ
2. 写真の共有
3. 技術的な勉強
なぜ作ったか(背景)
3年ほど前に結婚し、夫婦で外出の際に写真を撮ることが増えました。
(昨年には子どもも生まれ、更に写真を撮る機会が増えました)
今後増えて行く写真の保存場所を考えた時に、
自分1人だけなら外付けのハードディスクに保存すればいいですが、せっかく撮った思い出なので家族で共有して定期的に見返したい。
ただ、単純にアプリを開いて表示するだけでは能動的なアクションが必要となり、毎日アプリを開いて写真を眺めるのはハードルが高くなります。
そこでスマフォのウィジェットにランダムで写真を表示すれば、能動的なアクションは必要なく、
またランダム性によって思いもよらない写真に出会うことができると考えました。
別の方法として「みてね」に子どもの写真以外もアップし、家族以外(祖父母等)を除外して公開するという方法も考えましたが、以下の理由で自分で開発することにしました。
1. 営利企業が運営している以上、収益の関係でサービスが終了する恐れ
2. サービス終了時にアップした写真のダウンロードができなくなる恐れ
3. サービス終了時に保存した写真をすべてダウンロードする必要がある
4. AWSやバックエンドの勉強のため
アーキテクチャ

フロントエンド
– React Native
バックエンド
– CakePHP
– Mysql
インフラ
– CloudFront
– S3
– API Gateway
– Lambda
– Xserver
主な役割
CakePHP
Xserver上に配置し、アプリのAPIとして使用しています。
– DBサーバー(mysql)への操作
– S3のURLをCloudFrontのURLに変換
– アプリからS3に直接画像をアップするためのURLを発行
LambdaとAPI Gateway
S3に保存している写真はオリジナル画像含め3種類あります。
1. オリジナルサイズ(アップされた画像サイズそのまま)
2. 一覧表示、アプリのウィジェットで表示するためのスモールサイズ(300\*300)
3. 詳細画面で表示するミディアムサイズ(幅800)
2.のスモールサイズは1.のオリジナルサイズがS3に保存されたことをトリガーに、Lambdaを使って300\*300にリサイズしたものをリサイズ用のバケットに保存しています。
3.のミディアムサイズは以下の条件で動的に取得しています。
1. CloudFrontにキャッシュがあればそれを使用
2. 1.が無ければS3から取得
3. 2.が404ならAPI Gatewayを経由し、Lambdaを使って幅800のミディアムサイズを生成したものをレスポンス。またリサイズ用のバケットに保存(次回からは2.でS3の画像をレスポンスする)
技術選定理由
アプリ(React Native)
総合的な理由でネイティブ(swift, java, kotlin)で開発するのがベストと思っていましたが、以下の理由でReact Nativeを選択しました。
1. Xcode、Android StudioよりVsCodeが軽量で、ホットリードやライブラリ等のフロントエンドのエコシステムが充実している環境面
2. 自分のWeb知識を多少なり活用できる知識面
3. クロスプラットフォーム開発できる
4. 公式ドキュメント含め情報が豊富
初期バージョンはSwiftUIで開発していましたが、1.の理由もありReact Nativeにリプレースしました。
バックエンド(CakePHP)
仕事でも使用したことがあり慣れていることが理由です。
Xserverを使用しているのは、ブログ記事をXserver上で運営しており手頃に使用できるからです。AWSを使用しているなら将来的にはEC2を使用してもいいかなと思っています。
AWS(S3, CloudFront, Lambda, API Gateway)
写真の保存先としてS3を選択したのは、数十年先を考えた時にAWSが無くなっている可能性が1番低いと考えたからです。
CloudFrontは写真をキャッシュすることで表示速度を上げるため。
スモールサイズとミディアムサイズを作成するにあたってS3やCloudFrontとの連携のしやすさを考えてLambda、API Gatewayを採用しました。
苦労した点(技術的に)
初期バージョンではオリジナルサイズをCakePHP経由でスモールサイズにリサイズしてS3に保存していました。
この方法だとネットワーク負荷や画像容量の問題で1枚ずつしかアップロードできないため改善が必要でした。
Lambdaに関しては知見がなかったため、やりたいことが実現できるか調査からスタートし、
設定から切り替えまで対応するのに時間がかかり大変でした。
工夫した点
詳細画面で表示するミディアムサイズの写真をどれくらいのサイズにするのがベストか。
表示速度を早くするにはオリジナルサイズをアップロードする際にミディアムサイズもS3に保存しておくのがベストですが、状況を見ながら柔軟にサイズを変更したいのと、S3に保存する写真が増えて請求額が上がるのは困る。(個人で運用しているので、できるだけ金額は抑えたい…)
そこでミディアムサイズはオンデマンドでリサイズする方法にしました。
こうすれば後からサイズも変更可能で、リサイズした写真もライフサイクルで削除すれば無駄な容量は抑えられるためです。
ただし、リサイズ済みの写真がS3に保存されていない場合、Lambda実行で表示速度が遅くなるのは今度後の課題ですね。
結果 / 学び
あまりAWSを触ったことがなかったのでLambdaやAPI Gatewayといった便利なものがあることは勉強になりました。
今後やりたいこと
– UI/UXの改善
– 動画対応
– ストア公開

コメント