SectionReport フォーマットを実装した拡張版 Thinreports の公開

こんにちは、Misoca の日高(@hidakatsuya)です。

Fit Boxing は何度始めても3日坊主になります。

拡張版 Thinreports の公開

Thinreports は、オープンソース のPDF 生成ツールです。Thinreports では、Editor と呼ばれる帳票デザインツールで作成したテンプレートファイルを、RubyGems である Generator を使って読み込み、値の埋め込みなどを行って PDF を作成することができます。

Misoca でも以前から一部の PDF 生成機能で利用していましたが、昨年より、本格的に利用を進めるにあたって、不足した機能の拡張という形で SectionReport フォーマットの実装を進めてきました。

Editor 及び Generator それぞれの実装は下記リポジトリの section-report ブランチで公開し、現在も少しづつ開発を進めています。

github.com

github.com

SectionReport フォーマット

SectionReport フォーマットとは、コミュニティで提案されている Thinreports の新しいレイアウトフォーマット です。公開した拡張版 Thinreports は、この提案に基づいて実装した形です。

このレイアウトフォーマットは、

レイアウト定義時点でページの制約をなくし、出力した結果によってページを決めるレイアウトフォーマット

と、提案の中でも説明されているように、従来のフォーマットのような、ページ単位の固定なレイアウトではなく、レイアウトを「セクション」と呼ばれる単位で分割して定義し、PDF生成処理の中で、それらのセクションを組み合わせたり、カスタマイズすることによって、柔軟なレイアウトを可能にします。

f:id:hidakatsuya:20200629164435p:plain
Example: Basic Usage のレイアウト定義

主な特徴を紹介します。

セクションの高さの自動伸縮

描画した結果、テキストの内容がセクションの高さに収まらないとき、それに応じてセクション自体の高さを自動的に拡張させることができます。また、後述する StackView による自動縮小もサポートしています。詳細は Example: Section Auto Stretch を参照してください。

StackView ツール

図形やテキストを配置できる複数の領域(row)をもつ、Misoca 独自の新しいツールです。

StackView は他の図形同様、セクション内に配置することができます。その row は、動的に非表示にすることができ、その下に続く row は上に詰めて描画されます。また、row はセクション同様、自動伸縮をサポートします。StackView を使うことによって、セクション内のレイアウトを動的かつ柔軟なものにすることができます。詳細は、Example: StackView を参照してください。

その他の機能や実装状況

その他の機能や実装状況など、詳細は下記 README に記載しています。また、StackView ツールなどの Misoca 独自機能についても説明しています。

使い方

それぞれの README を参照してください。

また、いくつかの example も用意しています。各 example には、テンプレートファイルと Ruby のコード、その出力結果PDFが含まれています。こちらも参考にしてください。

なお、Editor は現時点では SectionReport フォーマット専用です。従来のフォーマットを編集することはできません。

今後について

いずれの実装もまだまだ発展途上です。Misoca としても開発を継続しつつ、近く Thinreports コミュニティに pull request を送る形で提案していきます。 そして、活発な議論のもと、より良い形での機能の提案ができればと思っています。その際は、ぜひレビューやコメントをしていただけると嬉しいです。

最後に

拡張版 Thinreports の概要と公開のお知らせを中心にご紹介しました。 今後も、この拡張版 Thinreports について、詳しい使い方や Misoca での具体的な利用例などを引き続きご紹介していきたいと思います。

宣伝

Misocaでは OSS に貢献したいエンジニアを募集しています。

www.wantedly.com

急なレスポンスタイム悪化から、オープンソースプロジェクトにPull Requestを送るまで

こんにちは、Misoca開発チームの黒曜(@kokuyouwind)です。

最近はシャニマスのイベントシナリオ感想記事をnoteにまとめたりしています。

😨 急に本番のレスポンスタイムが悪化した話

Webエンジニアにとって、「本番障害」という4文字ほど見たくないものはないでしょう。

本番障害ほどではないにしても、「急なレスポンスタイム悪化」もあまり見たくない文字列ですね。まぁ、見たくなくても向こうからやってくるんですが…

というわけで、今回は本番レスポンスが急に悪化したときの話です。いろいろ調べた結果、利用しているオープンソースプロジェクトが原因だったことがわかりPull Requestを送ったので、その流れをまとめてみたいと思います。

❗️ レスポンスタイム悪化の検知

Misocaでは監視ツールとしてMackerelを、APMツールとしてSkylightを利用しています。

本番レスポンスタイムはMackerelでアラートを設定しており、平常値から大きく悪化した場合はSlackに通知されるようになっています。

その日はリリース作業を行った直後、レスポンスタイム悪化のアラートが飛んできました。気になってSkylightを確認したところ、驚きの事態が。*1

f:id:kokuyouwind:20200609181504p:plain

リリース以降、95パーセンタイルがめちゃくちゃ悪化しとるやん!*2*3

🩹 応急処置

幸いアプリケーションが使えなくなるほどの悪化ではなかったため、落ち着いて応急処置に臨みます。

Skylightで表示する期間をリリース前とリリース後で切り替えて比べた結果、どうやらPDF生成処理にかかる時間が伸びているらしいとわかりました。

リリース内容を精査したところ、ちょうどそのタイミングでPDF生成処理に関係しそうなTTFunk gemの更新が入っていることが判明。*4

おそらくこれだろうとアタリをつけ、該当コミットを巻き戻してリリース。結果、見事にレスポンスタイムが回復しました。

f:id:kokuyouwind:20200609182842p:plain

🕵️‍♀️ 原因調査

ひとまず本番の問題は落ち着いたため、なにが原因だったのかを調査していきます。

まずはローカル環境での再現確認。以下のようなコードでベンチマークを取り、gem更新前と更新後とでPDF生成にかかる時間が増えるかを確認します。

10回繰り返しているのはActiveRecordアクセスなどPDF生成以外の要因を相対的に小さくするためです。

require 'benchmark'

Benchmark.bmbm do |x|
  x.report('generate') {
    10.times { Misoca::PDF.generate(Invoice.first) }
  }
end

結果、ttfunk 1.5.1のときと比べて、ttfunk 1.6.2.1では概ね4倍ほど遅くなることが確認できました。

本番でしか起きない問題だと調査が難しいのですが、ローカルでも再現することがわかったため調査がしやすくなりましたね。

続けてStackprofを使ってプロファイルを取り、どのような処理に時間がかかっているかを調べていきます。

require 'stackprof'

StackProf.run(mode: :cpu, out: 'tmp/stackprof-cpu-myapp.dump', raw: true) do
  10.times { Misoca::PDF.generate(Invoice.first) }
end

stackprof tmp/stackprof-cpu-myapp.dump で確認した結果、以下のようにActiveSupport::CompareWithRange#cover?が50%以上の時間を使っていることがわかりました。

==================================
  Mode: cpu(1000)
  Samples: 13617 (0.71% miss rate)
  GC: 1461 (10.73%)
==================================
     TOTAL    (pct)     SAMPLES    (pct)     FRAME
      7765  (57.0%)        7765  (57.0%)     ActiveSupport::CompareWithRange#cover?
      1138   (8.4%)        1138   (8.4%)     (marking)
      8609  (63.2%)         844   (6.2%)     TTFunk::Table::OS2.group_original_code_points_by_bit
       322   (2.4%)         322   (2.4%)     String#unpack
       322   (2.4%)         322   (2.4%)     (sweeping)
...

TTFunk::Table::OS2.group_original_code_points_by_bitもTOTALでは多くの時間を使っており、SAMPLESは少なくなっています。 このことから、TTFunk::Table::OS2.group_original_code_points_by_bitからActiveSupport::CompareWithRange#cover?を呼び出している箇所が重いのだろうと推測することができました。

実際にTTFunk::Table::OS2.group_original_code_points_by_bitのコードを確認すると、以下のようにr.cover?を繰り返し呼び出しています。

os2.file.cmap.unicode.first.code_map.each_key do |code_point|
  # find corresponding bit
  range = UNICODE_RANGES.find { |r| r.cover?(code_point) }

この処理は1.6.0で追加されたものでした。ここにパフォーマンス上の問題があるようですね。

📝 Issueを立てる

問題が把握できたため既存のIssueやPull Requestを確認しましたが、どうやらまだ報告されていないようでした。

新しいIssueを立てたいところですが、このためには最小限の再現コードを作り、ttfunk自体の問題である確証を得ておきたいところです。

PDF生成の内部処理からどのようにttfunkが呼び出されているかわからなかったため、stackprof --graphviz tmp/stackprof-cpu-myapp.dump > tmp/stackprof.dotでdotファイルを作成し、dot -T pdf -o tmp/stackprof.pdf tmp/stackprof.dotでPDF化して呼び出しグラフを見てみました。*5

f:id:kokuyouwind:20200610134938p:plain:h300

どうやら、TTFunk::Subset::Base#encodeが外部とのインターフェイスのようです。

specファイルを参考にしつつ、この処理を呼び出す再現コードを書いてみます。

require 'ttfunk'
require 'benchmark'

# English Font
file = TTFunk::File.open("DejaVuSans.ttf")
# Japanese Font
# file = TTFunk::File.open("GenShinGothic-Normal.ttf")

subset = TTFunk::Subset.for(file, :unicode)
Benchmark.bmbm { |x| x.report('encode') { 10.times { subset.encode } } }

日本語などのマルチバイト文字でしか再現しない問題かもしれないので、フォントを英字フォントと日本語フォントの2種類で確認できるようにしています。

このコードを用いて1.5.1と1.6.2.1でベンチマークを取ったところ、英字フォント・日本語フォントを問わず実に30倍程度遅くなっていることがわかりました。やはり日本語フォントのほうが長時間かかるため、英字フォントを扱う海外ではパフォーマンスの問題に気づかなかったのかもしれません。

無事ttfunkのみで再現コードを作り計測もできたため、Issueとして報告することができました。

🛠 修正Pull requestを送る

あまりに難しそうな問題であれば手出しできませんが、今回は比較的読めそうなコードだったため、自分で直せないか検討してみることにします。

問題の箇所ではos2.file.cmap.unicode.first.code_mapの各キーについてeachを呼び出し、UNICODE_RANGESの中からr.cover?(code_point)を満たすものを探し出しています。

それぞれの要素数をN,M とすると、この処理は Ο(N * M)の計算量になります。Mは200弱の固定値ですが、それでも効率の悪い計算に見えますね。

素直に思いつくのはUNICODE_RANGESを探索木にすることです。ただしUNICODE_RANGESRangeの配列のため通常の探索木ではなく区間木を使うことになります。Ruby標準でサポートされないデータ構造のため依存gemを増やすか自力で実装するかになりますが、いずれも少々大きな変更になります。オープンソースプロジェクトへのPull Requestとしては、できれば避けたいところです。

ここで発想を変えて、「UNICODE_RANGESごとに、その範囲に含まれるcode_mapキーをまとめて見つけ出す」としたらどうでしょうか。code_mapが整列していた場合、同じUNICODE_RANGESに含まれるキーは必ず固まって並ぶため、効率良く処理できそうです。またUNICODE_RANGESは互いに重複しない範囲であるため、他のUNICODE_RANGESに含まれていたものを以降の判定から除外することができます。

この方針で実装してみたところうまく動いたため、Pull Requestを出すことにしました。計算量はΟ(max(N, M))まで改善しており、ベンチマークも8倍ほど早くなっています。

💬 感想

今回は本番でパフォーマンス悪化に気づいてから原因を調査し、オープンソースプロジェクトにIssueを立ててPull Requestを送るまでの流れをまとめてみました。

定番ですがStackprofを用いたプロファイル分析は大切ですね。またみんなのコンピュータサイエンス読書会で読んだばかりの計算量やアルゴリズムの話がさっそく活かせたのも良かったです。

tech.misoca.jp

今後も利用しているオープンソースプロジェクトの問題を見つけたときは、Issueで報告して直せるものはPull Requestを出していきたいと思います。

📢 宣伝

Misocaではパフォーマンスの問題を改善したいエンジニアを募集しています。

*1:話を簡単にするために省略しましたが、実は月初の負荷にまぎれてしまい、当日はアクセス量の問題だと思っていました。翌日も数値が回復しなかったため怪しんで調査し、コード起因の問題であったことがわかりました。

*2:95パーセンタイルは、レスポンスタイムすべてを短い順に並べて95%目の値を取り出したものです。SkylightのTypical responseは中央値(50パーセンタイル)を、Problem Responseは95パーセンタイルを表示しています。

*3:グラフの縦軸は具体的なパフォーマンスの情報になってしまうため、意図的に伏せています。

*4:話を簡単にするために省略しましたが、実際には別のgemの更新に伴い、依存していたttfunkも更新されていました。原因調査の際はここの切り分けでかなり苦労しました。

*5:flamegraphでも同じようなコールスタックが見えますが、スクリーンショットで貼ったときに細かすぎて見づらいため、今回はgraphvizを使っています。

みんなのコンピュータサイエンス読書会

こんにちは、Misoca開発チームの黒曜(@kokuyouwind)です。

最近はVTuberのシャニマス実況を見て無限に時間を溶かしています。だいたい委員長のせいです。

📕 みんなのコンピュータサイエンス読書会

Misocaでは有志で集まりみんなのコンピュータサイエンスの読書会を開催しています。

みんなのコンピュータサイエンス

みんなのコンピュータサイエンス

読書会を始めたのは「単に自分が読みたかったから」という理由が大きいのですが、コンピュータサイエンス(以下CS)の知識のベースラインを揃える取り組みをしたかったという面もあります。

チームメンバーの来歴はCSの専門課程を経た人から独学でプログラミングを学んだ人まで様々です。

例えば「MySQLのクエリはインデックスが効かないと遅くなる」という知識ひとつをとっても、CSの知識があれば「インデックスが探索木になっているから、Ο(log N) と Ο(N) の差があるんだな」とイメージを持てるのに対して、計算量や探索木の知識がない場合は「とにかくインデックスが効かないとだめなのかな」という理解になってしまいかねません。このように理解の齟齬がある状況では、「どの程度のサイズのテーブルで、どのカラムにインデックスを足すべきか」といった議論がまともに成り立たなくなってしまうでしょう。

こういった問題を防ぐために、CSの基礎知識をチームで揃えるのは重要だと個人的に考えています。その点で、CSの基礎を広く平易に扱ったこの本はちょうどよい題材になったと思います。*1

🏃‍♂️ 進め方

読書会では、節ごとに誰かが音読してから掘り下げて議論する流れを取っています。これは読む速度で取り残される人が出ないようにするとともに、内容をしっかり掘り下げられるようにするためです。

掘り下げ議論では、詳細を追って参加者全員の理解を確認することに加えて、現実での応用例や自社サービスで使える箇所がないかなどもよく話しています。例えば貪欲法の節では並列テストのグループ振り分けに利用している話や、探索木の節ではMySQL InnoDBのインデックスがB+木である話などをしていました。

掘り下げの際にMiroを使ってグラフや図を描くこともあります。以下は動的計画法のボトムアップについて、グラフを描いて確認したものです。

f:id:kokuyouwind:20200526173251p:plain:w480

ツールをろくに使わずフリーハンドで描いているため汚いですが、こういった図を描きながら話すことでより理解しやすくなりました。もう少し使いこなせるようになりたいですね。

📈 進捗

年初から始めて、現在5.3節までを読み終わったところです。本全体の半分ちょっとくらいでしょうか。

かなりゆっくりしたペースですが、これはかなり掘り下げて理解を確認しながら進めていることと、参加者の都合が合わず中止になる日も多いためです。

特に基礎となる論理・確率や計算量などは理解しないまま進めてしまうと後で困りそうだったので、1章で大きく時間を割いていました。

残りもこのペースでじっくり読み進められればと思います。

📢 宣伝

MisocaではCSの基礎を固めて業務に活かしたいエンジニアを募集しています!

*1:ベースラインを揃える目的で、基本情報技術者試験などの取得を推奨する企業も多いと思います。そちらも有効な手段だと思いますがやや堅苦しくなってしまうため、個人的には読書会くらいのライトさが好みです。

IaC を意識しつつ、Redash を ECS に移行する

先日、弊社内で利用する Redash のインフラ構成を docker-compose on EC2 な環境から ECS, RDS, ElastiCache に移行し、さらに Redash を v7 から v8 にバージョンアップしました。今回はどのように移行を進めたのか、どのようにバージョンアップ作業を行ったのかを紹介します。

これまでのRedash

Redash サーバは開発合宿の成果物として社内に導入されました。当時は動作することを優先させるために、公式が提供するEC2 AMI から docker-compose を使ってコンテナ群を立ち上げるようにしていました。DBやインメモリストアといったミドルウェアも docker-compose でコンテナとして起動している状態でした。

tech.misoca.jp

その後、社内の KGI/KPI や Misoca の SLO の可視化など、利用シーンが広がり社内の重要度が高まってきていました。

tech.misoca.jp

tech.misoca.jp

そうなると、不安となるのがシステムのレガシー化です。1台の EC2 インスタンス上で全部動かしていたのでコンピューティングリソースの不足が気になりますし、Redash のバージョンアップの際も懸念材料となっていました。

というわけで、レガシーになってしまう前に Redash サーバのインフラを見直し、強く柔軟な構成に移行することにしました。

Redash の新インフラ構成

最初に触れたように、新しいインフラ構成は ECS, RDS, ElastiCache を使ったマネージドサービス中心の構成にしています。

f:id:mizukmb:20200518103208p:plain
Redash 新インフラ構成

Server サービスには Redash の画面を提供する Docker コンテナを起動するタスク定義を指定いており、このサービスにのみ ALB を経由した外部アクセスができるようにしています。Workers サービスにはクエリを実行等を行う複数のDocker コンテナを集約させたタスク定義を指定しています。

Workers サービスが起動する Docker コンテナの種類は公式のdocker-compose.ymlと同じにしています。こういう構成にしようというこだわりが無かったので公式に合わせました。後々変えていくことはありうると思います。

インフラ構成のコード化

インフラ構成のコード化 (IaC) は、今では当たり前のようになってきましたが、ここで今一度 Redash のインフラ構成のコード化によって得られる恩恵は何であるかを列挙します。

  • コードがドキュメント代わりになる
  • コードレビュー、CI/CDといったソフトウェア開発で用いられる手法がインフラでも使える

その他にも様々な恩恵・利点は確かにありますが、今回は上記2点に絞りコード化の作業を進めました。

インフラ管理には Terraform を利用しました。社内でも既に AWS リソース管理に使われており、ほぼこれ一択という感じで決定しました。もっと様々な観点から他のツールも検討するべきとは思いますが、社内向けのアプリケーションであることと、自分以外の作業者でも問題無くコードが読めること (ドキュメント代わりになる) を重視した結果、社内で広く使われているツールを採用することにしました。

Terraform のファイル構成は以下の通りです。AWS のリソース毎にファイルを切り、 provider や Terraform 自身の設定は main.tf に集約させています。

.
├── README.md
├── ecs.tf
├── elasticache.tf
├── lb.tf
├── main.tf
├── rds.tf
├── task-definitions
│   ├── redash-server.yaml.tpl
│   └── redash-workers.yaml.tpl
└── vpc.tf

ちなみに、 task-definitions の yaml ファイル群はこちらの Issue コメントを参考にして、一度 yamldecode したオブジェクトを jsonencode して読み込むといった一手間を加えています。

GitHub Actions を使ったテスト、apply の自動化

プルリクエスト時の terraform plan や master ブランチ更新時の terraform apply といった事を自動で行うために GitHub Actions を使ってこれらを実現します。HashiCorp 社の公式テンプレートがあるので、今回はこちらを利用しました。

github.com

プルリクエスト単位では fmt -> init -> validate -> plan の順番で実行し、 plan を除いた全て成功すればグリーンとしています。また、 plan の結果についてはプルリクエストのコメントに残すようにもしています。この辺の設定も tf_actions_comment: true とするだけで良いのでとっても簡単です。 master ブランチ更新時 (= PR マージ時) には上記サイクルに加えて最後に apply を実行して、実際に Terraform の定義と AWS リソースの状態を合わせるようにしています。こうすることで、 master ブランチ == AWS リソースの状態となり、常に最新の状態を確認できるドキュメントとしても十分に機能してくれます。

……と、ここまで hashicorp/terraform-github-actions の使い方等を紹介しましたが、どうやら記事執筆時点ではこのリポジトリはアーカイブ状態になっていて、今後は積極的な開発やメンテナンスが行われないようです。今後は hashicorp/setup-terraform の使用が推奨されますので、皆様もこちらを使う方が良いかと思われます。私自身使ったことは無いので紹介だけ。

github.com

作業時点では hashicorp/terraform-github-actions リポジトリもアーカイブになっていなかったので、コミット履歴等を見るに最近決まったみたいですね。設定したばかりなのにまた書き直さないといけないのか (とほほ)。

Redash v7 → v8 へのバージョンアップ

Terraform による IaC と、GitHub Actions による CI/CD のセットアップが完了し、残すは Redash アプリケーションのバージョンアップ作業のみとなりました。ここまでくれば、バージョンアップ作業は Terraform のコードをいじって PR をマージするだけで作業は完了してしまいます。

f:id:mizukmb:20200519104255p:plain
GitHub のプルリクエストを使って Redash のバージョンを上げている様子

resource aws_ecs_task_definition が持つ container_definitions で設定する image の値を変更します。 Redash の公式 Docker イメージは Docker Hub で管理されているので、そこから v8 系のタグを探して Terraform 側で設定してあげましょう。

hub.docker.com

バージョンアップのPRをマージすることで GitHub Actions から terraform apply が実行され、 AWS ECS のタスク定義とサービスを更新します。サービスは自らのタスクを入れ替えてデプロイが完了します。

NOTE: Terraform を使った AWS ECS リソースの更新について

今回、AWS ECS 周りのコード化〜自動デプロイまで全て Terraform で行いましたが、実際にやってみるといくつか気になる点が出てきました。

まずは、タスク定義のリビジョンが更新されず、最新のリビジョン番号の内容を上書きしてしまう点です。例えば前回のデプロイ内容をリビジョン番号から辿れなくなってしまう問題があります。リビジョン番号が更新されないのは resouce aws_ecs_task_definition の仕様であり、私も事前に知ってはいましたが、コード自体は Git でバージョン管理できているしロールバックするのも git revert 等やり方は色々思い付くので大丈夫だろうと思っていました。しかし、やはり AWS 上でもリビジョンは更新されてほしいという気持ちもあります。

次に、 ECS へのデプロイ戦略についてです。社内向けアプリケーションということもあり、デプロイは ECS タスク総入れ替えという結構豪快なやり方を取っていますが、ダウンタイムやロールバック方法についてよりシビアに考えるのであれば、ローリングアップデートや blue-green デプロイといった方法でデプロイができるのが好ましいでしょう。 terraform apply ではこの辺りの融通が効かず、難しい印象を受けました。 Terraform で工夫するよりも、コード管理は Terraform, デプロイは他のツールを使うといった併用の形を取っても良いと思います。

今回はデプロイについても Terraform で行うようにしましたが、こちらについては他のデプロイツールの使用も検討して良いかもしれないという個人的な学びがありました。

まとめ

弊社内で利用している Redash のインフラを ECS やその他マネージドサービスへの移行と IaC 化、そして自動デプロイを使った v8 へのバージョンアップについて紹介しました。

まだまだ詰めきれていない部分も多いですが、こちらについては少しずつ磨いていければと考えています。ひとまずは移行が完了してホッとしています。

採用

今回の作業は SRE 業務の一環として行われたものです。 SRE 職種では IaC でいい感じにやっていくことが好きな方々を募集しています。

recruit.misoca.jp

開発メンバー id:mizukmb でした。

突撃!! 隣のリモート飯 🥄

こんにちは。@kawamataRyoです。
いつもは技術に関する話題を投稿している本開発ブログですが、今回は番外編としてMisocaのリモートワーカーのお昼事情の紹介します!

Misocaのリモートワークベテラン勢はどんなリモート飯を取っているのか?
急にリモートワークが始まり毎日のお昼ご飯に悩んでる皆さんの参考になれば嬉しいです。

@torimizuno

角煮ラーメン

f:id:ba068082:20200422083526p:plain

こだわりポイント

  • 夜に炭水化物を抜くので、お昼は炭水化物メイン
  • フルリモートになり、炊飯器でつくる角煮と味玉を仕込んだので、ラーメンにトッピング
  • 有名ラーメン店の器で食べるとそれだけで美味さマシマシです (器はお土産に友人から貰いました)

@k0matatsu

焼肉(円盤状無煙カセットコンロ)

f:id:ba068082:20200422083548j:plain

こだわりポイント

イワ◯ニを信じて肉を捧げろ

@rktm

パン(完全栄養食)

f:id:ba068082:20200422083616j:plain

こだわりポイント

  • 手で半分に割ってスライスチーズとハムを盛ってレンジで1分半というスピード調理
  • なんと、洗う食器はお皿一枚!
  • 糖質少なめながら一食に必要な栄養を賄える
  • 作り始めから食べ終えて食器を洗うまで15分で終わるので昼休憩の残り時間を有意義に使える

id: eitoball

サプリメント or プロテイン

走ったら、サプリメント

f:id:ba068082:20200422083643p:plain

走っていない時は、ソイプロテイン

f:id:ba068082:20200422083711p:plain

こだわりポイント

  • 走ったら、回復が早くなる(らしい)サプリメント を飲むようにしています。ちょっと癖のある味だけど、慣れるとやみつきになります。

id: sunflat

カレーライス(自炊)

f:id:ba068082:20200422083731j:plain

こだわりポイント

  • 圧力鍋で野菜と肉を煮込んで柔らかくしている
  • 食物繊維が不足しがちなので、胚芽押麦を混ぜた麦ごはんを使っている
  • 野菜が不足しがちなので、野菜を多めにしている
  • 隠し味に、カットトマト缶とレーズンととんかつソースを入れている
  • 多めに作って冷凍したいので、じゃがいもは入れてない

@mizukmb

ホットサンド

(ホットサンドの写真が無かったので先日作ったダルゴナコーヒーの写真を代わりに載せておきます。)

f:id:ba068082:20200422083752p:plain

こだわりポイント

  • 春に行われる有名なパンの祭りでシールを集めるために買った食パンを消費するため
  • 具材は適当ですが、スライスチーズは万能選手なのでたくさんあると良いです

@kanizmb

宅配すし 🍣

f:id:ba068082:20200422084757j:plain

こだわりポイント

  • 普段は冷凍食品・コンビニ・残り物で適当にすませるのですが、元気がない時やリリース終わりのめでたい時などには宅配すしを利用します
  • 午後の眠気対策に、お昼を食べずに1時間昼寝することもわりとあります

id:ryotaway

低糖質

f:id:ba068082:20200422084821p:plain

こだわりポイント

  • 1日1食、お昼だけとってます
  • 基本的に卵・肉・チーズしか食べないのですが、たまに味噌汁が飲みたくなるのでその時は味噌汁を作ります
  • これだけだとタンパク質が足りてないので、お昼以外の時間帯にプロテインを飲みます
  • 写真はないですが、チーズをおやつとしてちょこちょこ食べます
  • 食後はコーヒーで締めます

id:yoshoku

納豆

f:id:ba068082:20200422084909j:plain

こだわりポイント

  • カラシを足してます。

@Tooka_91

冷凍パスタ + 白米 + プロテイン(牛乳割り)

f:id:ba068082:20200422084940j:plain

こだわりポイント

  • 痩せやすい体質なので、とにかく何でもいいから食べる。
  • 冷凍パスタは200円でコスパ◎。(オフィスの近くで食べたら、1000円はする。)
  • タバスコが好きなので、いっぱいかける。
  • プロテインを飲めば、野菜を摂取しなくても健康になれるらしい。

@mugi_uno

\\\ 冷 凍 食 品 ///

f:id:ba068082:20200422085001j:plain

こだわりポイント

  • 昼なんて空腹を満たせればなんでも良いんですよ!!

@nezurika

炒めもの+味付け卵+サラダ

f:id:ba068082:20200422085019j:plain

こだわりポイント

  • 下味冷凍していた鶏肉(これはマヨしょうゆにんにく)と冷凍していた切ったねぎと冷凍していたしめじを炒めたものです
  • 味付け卵は週末のリモート飲み会用に作って余ったものです
  • 基本的に、何かしらの炒めものがおかずにあれば良い
  • ご飯はいつもは解凍してラップのままお茶碗に乗せています
  • 映えなんてなく日常なんてこんなもんですよ

id: mallowlabs

スパイスカレー (自炊)

f:id:ba068082:20200422085037j:plain

こだわりポイント

  • 調理時間があまりかからない料理を作っています
  • スパイスカレーは最近ハマっていて、煮込まずに作れるのと、スパイスがあれば作れるので気に入っています
  • しかも結構おいしく作れます
  • 難点があるとすれば、常に部屋がインドの香りになることくらいです

@kosappi_

近所の肉屋のお弁当

これは日替弁当が唐揚げだったときの唐揚げです。

f:id:ba068082:20200422085112j:plain

こだわりポイント

  • お昼は基本的に完成したものを調達するスタイルです
  • 昼休みになると、妻と娘の3人でお弁当屋まで散歩します
  • 密にならないように気をつけています
  • お弁当は日替わりですが事前に電話すれば好きなメニューを作っておいてくれます(すごい!)
  • 金曜日はかならずカレーです

@kawamataRyo

プロテイン(波動拳風味) + 完全栄養食 + EAA

f:id:ba068082:20200422083209p:plain

こだわりポイント

  • 美味しい粉です。
  • 昼休みは、懸垂・腕立て・ランニング・仮眠と色々やりたいので効率よくエネルギーが取れることに注力してます
  • 元袋のジップはちゃちいので、粉を移し変えておくと毎回の開け締めのUXが向上するのでオススメ。

終わりに

いかがでしたでしょうか?お昼ごはんの参考になりましたか?
「インスタ映えの連発だわい」と思って集めたお昼ごはん画像ですが、思いの外クセが強かったです。
美味しいお昼ごはんでパワーアップして午後の業務に備えましょう!!!

採用

Misocaでは、お昼ごはんにも開発にもこだわりを持つエンジニアを募集しています。

組織構造で余力を生み出す!「遊軍」チームを作ったらこぼれタスクをどんどん消化できるようになった

はじめに

こんにちは、 @rktm です。

Misocaではプロジェクトを開発プロセスの基本としています。

recruit.misoca.jp

ですがプロジェクトの枠からこぼれるタスクが増えてきました。 それらタスクをこなすべく、1年ほど前に「遊軍」というチームを作りました。

遊軍チームは当初はお試し運用でしたが価値を継続的に出せており、今は定着しています。 その遊軍チームについて、創設の背景、運用結果について書きます。

前回のブログ記事「フロントエンドチームはじめてました」と合わせて、Misocaでの、問題を個々人の努力だけではなく、組織構造の変化によって解決する事例としてお読みいただければ幸いです。 tech.misoca.jp

遊軍創設の背景:個々人の「余裕」「余力」に頼っていてはこなせないタスクが積み上がってきた

Misocaでは、2018年末ぐらいから大規模な機能追加・改修プロジェクトが複数走り、余裕のない状態が続いていました。

サービスを運営していると、日々お客様からの要望や、マーケティング担当からのリクエスト、不具合・障害の対応、分析作業、リファクタリングなど「 重要度も大きさも緊急度も様々」なタスクが発生します。

大規模プロジェクトに追われていた結果、気づけば以下のようなタスクが山積みになっていました。

  • 重要度: 非常に高いわけではないが、無視できるほどは低くない
  • 大きさ: プロジェクト化するほどは大きくないが、一人がプロジェクトの片手間でやるには手に余るボリューム

この記事ではこれらを「こぼれタスク」と呼んでおきます。

余裕のない時に起こること1: 「このタスク誰かお願いできますか?」「…(誰も手を挙げない)」

余裕がない状態では、プロジェクトメンバーはプロジェクトの目標やゴール達成に注力するため、プロジェクト外の作業にリソースを割くことに躊躇しがちです。突発的な問い合わせや障害の対応に取り組みづらくなりました。(この時の「誰かやってくれ〜 🙏 」という無言の空気は、なかなかつらいものがあります)

ということで、個々人の余裕に頼るとこぼれタスクの消化は安定しませんでした。

余裕のない時に起こること2:「余裕ができたらやる(やらない)」

「このプロジェクトが終わって余裕ができたらやる」というタスクは、プロジェクトの終了が延びがちであり、その結果次のプロジェクトがすぐに始まるため、結果的に後回しになりがちでした。

ということで、期間で余裕を作ろうとしてもなかなかうまく回らないものです。

解決策としての遊軍チーム: 組織構造として「余力」を作る

上記を踏まえ、Misocaでは個々人に頼ることなく定常的に「余力」を生むべく、遊軍チームを創設しました。

遊軍(ゆうぐん)とは - 遊軍の読み方 Weblio辞書

①  待機していて、時機を見計らって出動し、味方を助ける部隊。遊撃隊。
②  特定の所属や任務がなく、忙しい仕事やむずかしい仕事を状況に応じてする者。 「 -記者」

遊軍が対象とするスコープは以下の通りに定義しました。

  • 不具合対応等、突発的なタスク
  • お客様サポート部門・マーケティング部門などから上がってきた要望の対応
  • プロジェクト化するほど大きくないタスク
  • タスクのボリュームは、最大でも2週間ほどで終わるもの。

遊軍とプロジェクトの対比は以下の通りです。

f:id:RKTM:20200414174057p:plain
プロジェクトと遊軍の差

遊軍を運用してどうだったか

チームの規模としては、最低2人、新メンバーの受け入れやプロジェクトの狭間のメンバーの参加などで平均すると3人程度でした。

遊軍がやってきたこと

直近でブログに公開したタスクは以下の通りです。

その他にも、

  • お客様の要望:文書の件名の最大文字数を40文字から70文字にする(簡単なように見えて、いくつかのPDFテンプレートを変更するなど意外に大変でした)
  • 軽微な修正:日付系の入力フィールドにてautocompleteをオフにする
  • CIでしばしば失敗するテストを安定させる
  • 社内メモの文字数についての調査
  • デザイナーチームのビュー変更によりテストが失敗するようになったときも、ヘルプに入って迅速にマージまで持っていけた

などを行ってきました。

(ここに書ききれないような、小さな改善、リファクタリング、他プロジェクトのレビューによる支援など、多くの「こぼれタスク」をこなしています)

遊軍チームを作って、どうだったの?

遊軍内の評価

  • 溜まっていたお客様からの要望に対応できるようになり、よりお客様によりそえるようになった
  • CIの安定化に貢献することで開発チーム全体のスピードを落とさずに済んだ
  • 後回しになりがちな仕様書のアップデートにも時間を割けるようになった(斧を研ぐ時間を確保できている)
  • 新しくジョインしたメンバーの受け入れ先として機能している

外からの遊軍の評価

プロダクトマネージャーより

「プロジェクトにするほどでもない大きさの価値を、継続的に提供できるのがとても助かっています。

遊軍はある意味「余力」と捉えられがちで、最初の頃は廃止してプロジェクトにリソースを回した方がよいのでは?という声もありましたが、守ってよかったです」

デザイナーチームより

「長期間をかけて生み出すチームとは別軸で、短期間で価値を提供できるチームが発足し、実際に価値提供の頻度もあがっていると感じています。(リリースのお知らせ数が過去最高になりました)

いつでも相談できる窓口が仕組み化されたことで、細かなデザイン改善でやりたいことが発生した時も迷うこともなく相談でき、とても助かっています。」

マーティング担当より

「未来に向けた大きな取り組みを進めつつも、日々生じる改善や新規要望への対応も止めるわけにいかない。Misocaがその両輪を回すために無くてはならない、『縁の下のスピードスター』みたいなチームです。

こちらからの要望対応だけでなく、「え、そんな改善を進めてくれていたの?」というサプライズもちょくちょくあって、『縁の下のファンタジスタ』みたいなチームでもあります。」

お客様対応(カスタマーセンター)担当より

「これまで製品ロードマップに沿った計画的なリリースが中心とならざるを得ない状況でした。

そのため日々、お客さまからいただく改善要望などがなかなか反映できない(後回し)になる状況でした。遊軍チームが出来たおかげて、順次、機能改善を中心とした要望がリリースされています。

その結果、お客さまからも感謝のコメントをいただいたり、これまであった問合せがなくなったり(問題点が解消)する効果が出ています。カスタマーセンターとしても感謝していますし、何より、お客さまにとっても目に見えて実感できる改善が継続して提供できるような体制ができたことが嬉しいです!」

おわりに

遊軍チーム創設当初の目論見通り、

  • 組織構造として余力を作ることで、
  • 余力の中で「こぼれタスク」をスムーズに処理する

ということができていると評価しています。


Misocaでは、問題を解決するにあたり、個人の意識や頑張りだけでなく、仕組みや組織の変更で対応したいと思う人を募集しています。

www.wantedly.com

フロントエンドチームはじめてました

こんにちは @mugi_uno です。 某ウイルスで不安な日々が続きますが、ひとまずうがい・手洗いをちゃんとやっています。

フロントエンドチームができてました

f:id:mugi1:20200403115327j:plain:w600
最近買ったiPadProが嬉しくて書いてしまった謎のロゴ

Misocaでは半年ほど前にフロントエンドチームを新たに立ち上げました。 自分たちなりの形でひっそりと活動を続けてきて、幾つか成果も出てきています。

なぜチームを作ったのか / 何をやってるのか といった点をご紹介したいと思います。

徐々に表面化してきたフロントエンドの課題

Misocaでは個々人が「バックエンドエンジニア」「フロントエンドエンジニア」といった肩書を持っておらず、必要に応じてバックエンドもフロントエンドも触ります。

しかし、全体的にはフロントエンド側に比重を置くのは一部のメンバーに限られており、それに伴うさまざまな課題が表面化してきました。

個々人による改善活動が厳しくなってきた

フロントエンド全般に関わるような改善作業は、気になった人が隙間時間を見つけて対応していました。

それはそれで良いことですが、ボリュームの大きいタスクでは「途中で他の作業が忙しくなって続けられなくなる」「永遠に終わる気がしない」といった状態が危惧され、なかなか手をつけづらい状態が続いていました。

誰に頼めば良いのかわからない問題

フロントエンドに注力した作業は、プロダクト・デザインなどさまざまな方面から発生しますが、受け口が存在せずに「これは一体誰に相談すれば...??」となることがありました。

属人化とスキル・知識の偏り

適宜難しい技術要素については勉強会やペアプロ・モブプロを実施していましたが、気軽に相談する口も無いため、一部のメンバーに作業が偏ることも多く、スキル・知識の共有が上手くいかない部分が出てきていました。

→「チームが必要なのでは?」

問題について色々考えてみましたが、「個々人でバラバラに対応可能なフェーズを過ぎてしまったのだろう」と予想し、何らかのチームとして対応する体制を試してみても良さそうだな、という結論に至りました。

チームを作るにあたってやったこと

小さくはじめる

そもそも「チームを作って課題を解決できる」が既に予想でしかなく、空振りに終わる可能性も考えられます。 いきなり大体的にドカンとスタートするにはリスクがあるため、まずは活動時間短め&少人数で立ち上げることにしました。

具体的には次のような形です。

  • 興味のあるメンバーを数人募る
  • プロダクトチームに所属したまま、一部の時間をチームの活動に充てる

万が一「チーム意味なかったな」となっても、スパッとやめられるのが理想と考えました。

フロントエンドチームって一体何?を定義した

チームで集まって最初にやったのは、

  • 自分たちが一体何を目的として集まっているのか
  • 何をする(しない)べきか
  • 誰のために活動するのか

といった点を話し合い、「フロントエンドチームって何?」の認識を揃えました。 (この場はチームメンバーのみではなく、PdMやデザイナーにも参加してもらいました。)

「こんなフロントエンドチームはいやだ」

場の中で、チームのアンチパターンを話し合ってみました。 結果、次のようなものが出てきました。

  • ビジネスの成長に繋がらないことばかりをやってる
  • 全体の生産性向上に繋げられていない
  • 「それはバックエンドの仕事ですから」とか言い出す
  • 「面白そうだし流行ってるから良くわからないけど○○入れようぜ!!」とか言い出す

チームとして不穏な方向に走り出してしまわないよう、あらかじめガードレールを敷設しておくようなイメージです。

ミッションは何か

そしてチームが取り組むべき課題は何なのかを定義します。

最終的には、Misoca全体が望む方向に進むためにベストな支援をしていくのが理想の形だろう、という結論に至り

Web版Misocaにおいて、皆が思い描く理想のユーザ体験を実現するための技術領域での障壁を取り払う

をミッションに定めています。

f:id:mugi1:20200403112433p:plain
esaのREADMEでいつでも読める

チーム稼働から、今までにやったこと

実際にチームが走り出して実際に達成したこととして、わかりやすいタスクとしては

  • TypeScript型定義の強化
    • 皆がコードを書いた時に、無意識に負債を生まないためにコードを堅牢化
    • noImplictAny の無効化
  • Boostrap依存の撤廃
    • Bootstrap(驚異の2.x系)へのJS依存の完全撤廃
    • ユーザー体験統一プロジェクトの支援*1

などが挙げられ、直近ではAPIのGraphQL化などが計画されています。

また、日常的にフロントエンドチームのSlack上で技術相談を受けてペアプロ・モブプロを実施することで、開発チーム全体の支援を行ったり、今までは個人で対応していたような細かい依頼もチームとしてカバーしながら消化しています。

結局チームを作ってどうだったのか

現在もまだ試行錯誤を続けていますが、ひとまず順調に回るようになっており、概ね良い効果が出てきているかなと感じています。

  • 困ったときに気軽に相談できる受け口ができた
  • 長期的な改善計画を立てて、個々人が忙しくなってもカバーできる体制ができた
  • メンバー間でスキルや知見の共有ができるようになった

従来目立っていた明らかな課題は徐々に解消されつつあります。

とはいえチームだからこそ見えてきた課題もまだまだありますので、少しずつより良い形になるように見直していければな〜と思っています。

採用

Misocaではフロントエンドエンジニアを募集しています!