おいしい健康 開発者ブログ

株式会社おいしい健康で働くエンジニア・デザイナーが社内の様子をお伝えします。

おいしい健康オフィス紹介

こんにちは。おいしい健康エンジニアアルバイトの伊藤です。

おいしい健康ではiOSアプリを開発しています。

今回は社内の様子をお伝えしますと書いてあるのに様子を伝えてるのがペアプログラミングを導入して分かったことしか書かれていないということに気づいたのでオフィス紹介をしたいと思います。

弊社のオフィスはザ・パークレックス小網町第2ビル 4階 にあります。

東京メトロ東西線 茅場町駅7番出口より徒歩5分

東京メトロ半蔵門線 水天宮前駅8番出口より徒歩5分

という便利な場所にあり近くには飲食店がたくさん並んでいます。

ここがおいしい健康の入り口です。

f:id:oishi-kenko:20190508151705j:plain 中に入るとオフィスエリアが広がっていています。

ディスプレイは誰でも自由に使うことができ、仕切りがないので広々と使えます。

f:id:oishi-kenko:20190501152634j:plain

左手には打ち合わせスペースがあります。ここではミーティングや面接などを行っています。

f:id:oishi-kenko:20190501150406j:plain

本棚にはプログラミングの技術書や病態やダイエットなどのヘルスケア系の本が並んでいています。

本棚の本は借りることができるので電車の中や自宅などで読むことができます。

弊社は書籍購入補助制度があり好きな本を購入することができます。

オフィスにはキッチンが面していて、誰でも自由に使うことができます。

自分でお昼ご飯を作ったり、管理栄養士が試作レシピを作っているので、試食することもできます。

f:id:oishi-kenko:20190501150454j:plain

最後に集中エリアです。

f:id:oishi-kenko:20190508185853j:plain いかがだったでしょうか?

以上、オフィス紹介でした!

AndroidStudioのテンプレートを活用する

こんにちは、おいしい健康の真崎です。

おいしい健康ではAndroidアプリの開発を行っています。

日々、Android開発を行っていて、開発効率を上げるために、テンプレートを作成した話を紹介します。

弊社では以下のような構成で開発を行っています。

  • MVVM
  • DataBinding
  • DIとしてKoin

そのため、既存の テンプレートであるFragment ( with ViewModel )を利用していました。しかし、既存のテンプレートでは以下の作業が発生してしまいます。

  • Databinding対応のための書き換え
  • DIとしてKoinを使う書き換え

この手間が毎回発生していたので、もっと楽にできる方法はないかと調べいたところ、Android Studioのテンプレートをカスタムする方法にたどり着きました。

Android Studio のテンプレートとは

developer.android.com

Android Studio では、Android の設計と開発におけるベストプラクティスに基づいたコード テンプレートが用意されているため、適切な道筋に沿って美しく機能的なアプリを作成することができます。

Android Studio のテンプレートカスタマイズについて

Mac の場合は以下のパスにテンプレートがおいてあります。

cd /Applications/Android\ Studio.app/Contents/plugins/android/lib/templates/other/

今回はFragment ( with ViewModel )のテンプレートをカスタマイズするので、適当なディレクトリ名でコピーします。

cp -r ViewModelFragment MyViewModelFragment

中身を見てみると以下のような構成になっています。

% tree
.
├── globals.xml.ftl
├── recipe.xml.ftl
├── root
│   ├── res
│   │   └── layout
│   │       └── blank_fragment.xml.ftl
│   └── src
│       └── app_package
│           ├── BlankFragment.java.ftl
│           ├── BlankFragment.kt.ftl
│           ├── BlankViewModel.java.ftl
│           └── BlankViewModel.kt.ftl
├── template.xml
└── template_blank_fragment.png

テンプレートを記述方法としてFreeMarkerが使われているようです。

freemarker.apache.org

書き換えたファイルとしては以下のようなことを作業しました。

  • template.xml の name を書き換えて自分のテンプレートの名前を決定します。
  • BlankViewModel.kt.ftl, BlankFragment.kt.ftl, blank_fragment.xml.ftl を Databinding + Koin に対応した形に書き換えました(弊社ではkotlinを使っているので、java側のテンプレートは書き換えず削除してしまってます。

結果

テンプレートを作成したことにより、あらたな画面を作っていくときにすぐその画面の実装作業に映ることができるようになったので、開発効率は上がったと感じています。

以上です

1行の変更でWebサービスの速度を5倍にした話

こんにちは。おいしい健康エンジニアの近藤です。

おいしい健康では、iOS、Web(API / フロントエンド)、インフラ、SEOなど幅広く担当しています。 今回は掲題の通り、たった一行の変更でおいしい健康のWebサイトのパフォーマンスを大きく改善することが出来ましたので、ご紹介させていただきます。

PageSpeed Insightsとは

皆さんは、PageSpeed Insightsはご存知でしょうか?

PageSpeed Insightsとは、Googleが提供しているWebサイトのパフォーマンス(速度)を測定するためのツールです。 無料で利用することができ、改善事項なども細かく提示してくれますので、利用したことが無い方は、ぜひ一度お試しください。

developers.google.com

おいしい健康の速度スコア

お恥ずかしながら、おいしい健康のPageSpeed Insightsの速度スコアはとても低くなっていました。

私の方で https://oishi-kenko.com/ に対して、実行した結果は以下の通りです。

f:id:oishi-kenko:20190411154056p:plain

100点満点で、0〜49が遅いという評価のため、おいしい健康の11というスコアはとても遅いという位置づけでしょうか。

ただし、この速度スコアには少しカラクリがあり、モバイルのパフォーマンスについては、3G回線利用時の通信速度をベースとしたスコアとなっています。

そのため、4G回線を利用している場合は、おいしい健康の表示にそこまで遅いとは感じないはずです。 日本では、現在は4G回線が主流で、2020年には、NTTドコモKDDIソフトバンク楽天モバイルで、5Gの商用通信サービスが開始される見込みとの報道もありました。

しかし、日本以外ではまだ3G回線以下の速度の地域も多いことや、ページ読み込み速度はSEOの指標の一つになっていることもあり、可能であれば速度改善をしたいところです。

速度スコアの改善項目

PageSpeed Insightsで主に以下の項目が指摘されていました。

No 改善できる項目 短縮できる時間(推定)
1 レンダリングを妨げるリソースの除外 7.93s
2 テキスト圧縮の有効化 7.05s
3 キー リクエストのプリロード 6.12s
4 オフスクリーン画像の遅延読み込み 3.75s
5 次世代フォーマットでの画像の配信 1.95s
6 使用していない CSS の遅延読み込み 1.8s
7 効率的な画像フォーマット 0.9s

多くの改善項目がありますが、前述の通り、モバイルの速度スコアは3G回線利用時の通信速度がベースとなっており、通信容量の影響を非常に多く受けます。 そこで、通信容量の削減を行うことで、全体的に表示速度を改善できるのではないかという仮説を立て、先ずは、テキスト圧縮の有効化を実施することにしました。

テキスト圧縮の有効化

おいしい健康では、 AWS の S3 に CSS や JS などのアセットを配置し、CloudFront経由で配信しています。 今回はこれがgzipで圧縮されていなかったため、PageSpeed Insightsで改善項目として挙がっていました。

CloudFrontで配信しているファイルの圧縮は非常に簡単です。

docs.aws.amazon.com

おいしい健康では、Cfdefというgemを使い、CloudFrontの設定内容をDSLとして管理しているため、今回の対応内容としてはDSLの変更のみです。

実際の変更内容は以下の通りです。

-    compress false
+    compress true

タイトルの通り、diffは1行だけですね。

改善後の速度スコア

気になる改善後の速度スコアはこちらです。

タイトル通り、1行の変更で速度スコアが11から58と、ほぼ5倍になりました。

さいごに

この記事では、テキスト圧縮の有効化の対応内容をご紹介させていただきましたが、これ以外にもいくつか比較的簡単に改善できる項目もあるため、 皆さんも一度確認してみてはいかがでしょうか。

今回は以上です。

git commitする前にktlintでフォーマットチェックをかける

こんにちは。おいしい健康エンジニアの小林です。

昨年12月に入社しまして、Androidアプリの開発をしています。おいしい健康ではAndroidアプリをKotlinで開発しておりフォーマッターにはktlintを使用しています。

ktlintとは

Android公式のスタイルガイドに基づいてコードチェックをしてくれるKotlin用のlinterです。自動でフォーマットしてくれる機能も用意されています。

ktlint.github.io

ktlintはGradleプラグインが提供されているためAndroidプロジェクトへの導入が簡単です。

おいしい健康ではPullRequestのコードに対してCircle CI上でktlintを走らせるようにしています。

レビュワーの労力を、コードフォーマットのレビュー(本質的ではないこと)に使いたくないで非常に便利です。

Push前にもlintしたい

コードフォーマットの修正漏れがあっても気づけるようにCircle CI上でktlintを実行しているのですが、

  • ほぼ毎回Push後にフォーマットの修正漏れに気づく。
  • ./gradlew ktlintFormatかけてまたPush!
  • あ、ビルド渋滞が……
  • 修正漏れ分のビルド中止をするの面倒。
  • push前にフォーマットかけていれば、ビルドを無駄に走らせなくてもよかったのに。

と言った点から、ローカルでも自動チェックしたいなと考えました。 ./gradlew ktlint って叩けばチェック可能なんですが、コード書く度に手動で叩きたくないので(叩くの忘れるので)、何かをトリガーに自動化したいです。

Commit前にlintする

Command Line版のktlintに用意されてました。

$ ktlint --install-git-pre-commit-hook

と実行すると自動でpre-commitファイルが作成されます。

すでにpre-commitを使用している場合は、

git diff --name-only --cached --relative | grep '\.kt[s"]\?$' | xargs ktlint --relative .
if [ $? -ne 0 ]; then exit 1; fi

を追記すれば良さそうです。(ktlint --install-git-pre-commit-hookで生成された中身です。)

Commitすると以下のようにktlintが自動でチェックしてくれます。

$ git commit
app/src/main/java/com/example/MainActivity.kt:8:27: Missing spacing before "{"
app/src/main/java/com/example/MainActivity.kt:10:1: Unexpected indentation (1) (it should be 8) (cannot be auto-corrected)

これでローカルでフォーマットの修正漏れに気づくことができますね。

Android Studioで使う

Gitをコマンドで実行している場合は特別意識せずにgit commitすればktlintが走ってくれます。

Android StudioGUI上でGit Commitしている場合は、 Commit Changes の Run Git hooks オプションをオンにしてあげればOKです。

Android StudioのRun Git hooks
Run Git hooksをオンにする

Ktlintのコードチェックに失敗すると、以下のような目に悪いアラートが表示されるので、フォーマット忘れに一目で気づくことができますね。

ktlintの実行結果
ktlintの実行結果

これで修正忘れにプッシュ後気づくこともなくなり、Commit分のコード自体も綺麗になります。

今回は以上です。

BigQueryで協調フィルタリングを使って使用食材が似たレシピを探す話

こんにちは。おいしい健康エンジニアの花井です。

今年の8月に入社しまして、iOS(クライアント)、API(サーバーサイド)、データ分析など幅広くやっています。 言語で言うと、Ruby(Ruby on Rails), Swift, Pythonですね。

今回は、食材が似たレシピを探す話、と題しておいしい健康のデータ分析の話をします。

概要

おいしい健康で最も人気がある下記レシピに対して、使用食材が似ているレシピを探します。 oishi-kenko.com BigQueryはクエリを気軽に実行して試行錯誤できるので最適化問題のソルバーとしてとても優秀です!

おいしい健康のデータ分析まわり

f:id:oishi-kenko:20181109142033p:plain

おいしい健康ではデータウェアハウスとしてBigQueryを使っています。

BigQueryへのデータコピーには、WebやアプリのログではFluentd, データベースに保存しているレシピや食品成分表等のデータではEmbulkを使っています。

データ可視化にはGoogle Data Studio*1を使っており、レポートやダッシュボードをサクッと作り社内会議で共有しています。 Google Data Studioでは表現できない複雑な図表を作成するときはGoogle Colaboratory*2を使っています。

使用食材が似ているレシピを探す

レシピには食材・調理手順・調理器具など様々な要素がありますが、今回は食材のみ着目します。

定義

食材(Ingredient)の集合を {I = (i_1, i_2, \cdots, i_n)}, レシピ(Recipe)の集合を {R = (r_1, r_2, \cdots, r_m)}と表記します。

レシピ {r_i}に対する食材 {j}の使用量を {w_{r_i,j}}と定義し、 レシピ {r_i}に対する食材使用率ベクトル {v_{r_i}}を次のように定義します。

\begin{align} \vec{v_{r_i}} = \frac{1}{\sum_{k=1}^n w_{r_i,k}} (w_{r_i,1}, w_{r_i,2}, \cdots, w_{r_i,n}) \end{align}

今回のデータ分析では食品成分表*3を利用し、調味料等を除外して食材の使用量を算出しています。

クエリでは、次のように実装できます。

協調フィルタリング

協調フィルタリングは、ユーザ間やアイテム間の類似性に基づいて推薦アイテムを決定する推薦アルゴリズムです。今回は類似性の指標としてコサイン類似度を採用し、設計します。

レシピ {r_i, r_j}に対するコサイン類似度 {s_{r_i r_j}}を次のように定義します。

\begin{align} s_{r_i r_j}= \frac{\sum_{k=1}^n v_{r_i,k} v_{r_j,k}}{\sqrt{\sum_{k=1}^n v_{r_i,k}^2} \sqrt{\sum_{k=1}^n v_{r_j,k}^2}} \end{align}

具体例を見てみましょう。

f:id:oishi-kenko:20181112185426p:plain

食材の集合 {I = (i_1, i_2, \cdots, i_n)}に対してそれぞれのレシピで使用してる食材は数種類なので、食材使用率ベクトルのほとんどの成分はゼロです。例にあげている2つのレシピに対する使用食材の成分だけ取り出すると次のようになります。

f:id:oishi-kenko:20181113114048p:plain

大雑把に言えば、この2つの図形がどのくらい一致するか、という指標がコサイン類似度です。 ベクトル同士の成す角度の近さを表現しており、1に近づくほど似ている、0に近づくほど似ていない、となります。

この例ではコサイン類似度は0.94958となり、よく似ていると判断できます。

まとめると、使用食材が似たレシピを探す話は、あるレシピ  {r_i}に対してコサイン類似度  {s_{r_i r_j}}が最大となるようなレシピ {r_j}を求める最適化問題となります。

\begin{align} arg\max_{r_j \in R} s_{r_i r_j} \end{align}

今回は、この最適化問題のソルバーとしてBigQueryを使い、総当たり*4で求めます。

BigQueryのメリット

Python等でも実装できますが、BigQueryはこんなメリットがあります。

  • 標準SQLが使えるので学習コストが安く、エンジニア間のコミュニケーションが容易。
  • メンテナンスコストも安い
  • 実行速度がとても速いため総当たりで解ける
  • Google製品と簡単に連携できて、結果出力やデータビジュアリゼーションの実行環境の構築コストが安い

コード

いよいよ実装に入ります。 BigQueryでは協調フィルタリングを次のようにシンプルに実装できます。

類似度1位を見てみよう

実は、コサイン類似度が最も大きいレシピはコサイン類似度で例を出したものでした。 oishi-kenko.com

しかし....

このレシピが最も似ているレシピだと納得できるでしょうか。

コサイン類似度が0.94958ですが、似ていると判断できるでしょうか。

「落とし揚げ」のレシピにはレタスも玉ねぎも生姜も食材に含まれていないです。

もう1度、食材使用率ベクトルを見てください。 f:id:oishi-kenko:20181113114048p:plain

豆腐と鶏ひき肉が多く含まれているレシピが選ばれていることが分かります。

つまり、食材使用率の低い食材が無視されてしまっています。

少量の食材でもレシピに含まれてほしいですね。

そこで、定義を変更します。

ingredient.total_gram / SUM(total_gram) OVER(PARTITION BY ingredient.recipe_id) AS gram_per_recipe

食材使用率に1を足し、下駄を履かせます。

少量の食材も考慮されるようにします。

1 + ingredient.total_gram / SUM(total_gram) OVER(PARTITION BY ingredient.recipe_id) AS gram_per_recipe

1位の結果を見てみましょう。 oishi-kenko.com コサイン類似度は0.80864です。

食材使用率ベクトルはこのようになりました。 f:id:oishi-kenko:20181113113904p:plain

5つの食材が被っているレシピが選ばれました。

レシピ類似度のデータビジュアリゼーション

以下はおまけです。 レシピ間の類似度ネットワーク*5を可視化してみます。

可視化対象

すべてのレシピ間を図示してしまうと辺だらけのネットワークになってしまうので、コサイン類似度が0.7以上のレシピ間を可視化します。

頂点 {V} : レシピ集合  {R = (r_1, r_2, \cdots, r_m)}

 {E} : { {(r_i, r_j) | s_{r_i r_j} \geqq 0.7 for \forall r_i, r_j \in R}}

データ取り出し

BigQueryのコンソール画面でGoogleスプレッドシートへ出力できる機能があるのですが、行数が多すぎるため使えません。 そんなときは、Google Colaboratoryが便利です。 下記のようにCSVファイルを簡単に取得できます。

可視化したネットワーク

ネットワーク可視化ソフトウェアプラットフォームCytoscape*6が便利です。

以下のフィルターを適用しました。

  • 頂点の次数*7が大きいほど大きくする描画する
  • 頂点の次数が大きいほど赤く、小さいほど青く描画する

巨大なネットワークと複数の小規模ネットワークができました。

f:id:oishi-kenko:20181112182528p:plain f:id:oishi-kenko:20181112182529p:plain

いくつかクラスターがあり、その中にハブとなるようなレシピが存在していることが分かります。

今回は可視化しただけですが、レシピのネットワーク構造を研究してサービスに活かせそうですね。

*1:https://datastudio.google.com/overview

*2:https://colab.research.google.com/

*3:おいしい健康では食品やレシピの栄養価は、主に文部科学省から食品の栄養価が書かれた一覧表(日本食品標準食品成分表 2015年版(七訂))を用いて算出しています。

*4:力まかせ探索、しらみつぶし探索とも言います

*5:数学用語ではグラフといいます。グラフG, 頂点集合V, 辺集合EのときG=(V,E)と表記します。この記事ではグラフではなくネットワークと書くことにします。

*6:バージョン3.7.0 https://cytoscape.org/

*7:頂点から出ている辺の数

Probot で GitHub の PullRequest のレビューアサイン, ブランチ削除を自動化する

Probot ご存知でしょうか!?

今回は、GitHub に便利な自動化ツールを追加できる Probot を弊社事例とともにお伝えしていきます。

Probot is 何

Probot は GitHub apps を Node.js により作れるフレームワークです。

probot.github.io

GitHubを使っているときに、「あぁ。。これ自動でなんとかしたい」と思うことはないでしょうか。

  • PullRequest(以下、PR) をマージしたら、ブランチを毎回手動で消すのめんどい
  • レビュワーを自動でアサインしてほしい
  • 最低一人に approve をしてもらわないと、マージできないルールで運用しているので、approve がないPRはマージボタンを無効にしたい

こういったことを実現するために自分で GitHub apps を書いたり、 APIでなんとかしようとしたりも出来ますが、そこまで時間的コストをかけられない。という方々も多いハズ。

Probot は GitHub Apps の開発フレームワークを提供していますが、更に Probot で開発された GitHub Apps の一覧も公開してくれており、既に公開されている GitHub Apps を使うことで、上記の様な願いはすぐに叶えられるようになっています 😇

おすすめ GitHub Apps by Probot

ここからは、弊社でも使っている便利な GitHub Apps をご紹介します。

Auto Assign

probot.github.io

PR を出すたびに指定した GitHub ユーザーの中から何名かをランダムに選択しレビューワーへのリクエストを飛ばす GitHub App です。

おいしい健康では、(ほぼ)すべてのPRを必ず他のエンジニアがコードレビューをします。

コードレビューでは、プログラムが設計通りにかけているかを始め、より良い解決方法はないか。などを中心にやり取りが行われます。在籍期間が長くなればなるほど、コードレビューを活発に行える一方で、新しく入ってきたばかりの人は、書かれたコードの前後背景がわからなかったり、コメントするポイントがわからなかったりして、レビューに参加しにくいことも珍しくありません。

そこで、この Auto Assign の登場です。

レビュワーはランダムに割り当てられるため、誰もが均等にレビューをする機会を得ることになります。

前後背景の知識を持っている人は、コードに考慮漏れがないかなどを中心に。 前後背景の知識を持っていない人は、今後前後背景の知識を蓄えられるように。この Auto Assign は役立っています。 もちろん、前後背景を知らない人たちばかりがアサインされてしまい、ちょっと不安だな。と思うときには、手動で新たにレビューワーを追加するなどの対応は必要になってきます。

なんにせよ、この GitHub Apps を入れてから、レビューが活発になったのは確かです。

Delete merged branch

probot.github.io

PR をマージしたら、マージ済みのブランチを自動で消してくれる GitHub App です。 マージ後のブランチは基本的に用済みであり、トラブルがあれば Restore もできるため、消してしまうのが弊社の通常運用になっています。

この GitHub App を導入するまでは定期的に消し忘れているものをチェックしたり、あまり消す習慣のない人にはリマインドを送ったりと、地味に手間な運用が行われていました。

すごく簡易な機能だけの GitHub App ですが、めちゃくちゃ役立っています。

おわりに

今回は便利 GitHub Apps の紹介がメインとなりましたが、自分で作るのもとても簡単なようです。(私はまだ作っていない) Probot を用いた自作 GitHub App の良い事例がでてきましたら、またお知らせします。

ペアプログラミングを導入して分かったこと

こんにちは。おいしい健康エンジニアの近藤です。

WWDC2018で他のエンジニアと情報交換させていただいた中で、他社ではペアプログラミングを導入して開発速度が2倍に上がったというお話を聞き、おいしい健康でも少しずつペアプログラミングを導入しています。今回はペアプログラミングを導入してみて分かったペアプログラミングのメリット、デメリットを紹介いたします。

f:id:oishi-kenko:20180817173215j:plain ※画像はペアプロの相方が出社するまでの間の場所取りとして活躍している人形です。

おいしい健康でのペアプログラミングのやり方

おいしい健康では、複雑なモデル周りの設計をするときや、比較的難易度の高いアプリの画面を実装するときに、ペアプログラミングをしながら最初に実装方針を決めています。
また、最近では、毎日エンジニア同士でランダムにペアを決めて、ペア同士は必ず隣に座るという運用も始めました。これによってフリーアドレスでもエンジニア同士で気軽に相談できるようにしました。こちらはペアプログラミングに限らず、テディベア効果も狙ったものになります。

ペアプログラミングのメリット

設計や実装のスピードが格段に上がる

ペアプログラミング中は途中で集中力が途切れたり、Slackを見たりする暇がなく、強制的にプログラミングが進むため、格段にスピードが上がります。

レビューによる手戻りが少ない

最初にペアプログラミングで実装方針を決めているため、大きな手戻りが発生することがありません。レビューでは細かい修正点だけを見ていけばよく、レビュー時間の短縮にも繋がります。

知識の底上げ、新メンバーのフォローアップ

新メンバーが新しく開発に入るタイミングでペアプログラミングをすることで、最初に詰まりやすいポイントに対してすぐにフォローすることができ、エンジニア全体の知識の底上げにも繋がります。

ペアプログラミングのデメリット

ナビゲータ役のエンジニアへの負担

弊社のペアプログラミングでは主にベテランエンジニアがナビゲータ、新メンバーがドライバーとして行っていることが多いため、ベテランエンジニアに負担が行ってしまうことがあります。こちらはペアプログラミングを続けていくことによって、エンジニア全体の知識が平準化されることで徐々にナビゲータ役のエンジニアが増えていけば解決されるかも知れません。

ペア席が取りづらい

おいしい健康ではフリーアドレスを導入しているため、外部ディスプレイ席を隣同士で2台確保しづらい場合があります。またフリーアドレスのメリットも少し薄れてしまいます。

単純作業の場合には向かない

比較的難易度の高い設計や実装の場合はペアプログラミングが効果を発揮しますが、ただ手を動かすだけの単純作業の場合は、一人で作業をした方が効率が良い場合があります。

さいごに

いくつかデメリットもありましたが、全体的にはペアプログラミングを導入したあとの方が実装スピードも上がり、エンジニア全体の知識の底上げにも繋がり良かったと思います。 開発速度が2倍とまでは行きませんでしたが、開発効率や品質向上の施策の一つとしてはオススメです。