ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

ユニファのエンジニアの業務領域とは?

こんにちは。 ユニファのエンジニアマネージャーの田渕です。

気づけば今年も、残り二ヶ月になってしまいました! コロナの影響などもあり、ハロウィンも例年ほどにお祭り騒ぎにはならなかったので、落ち始めた気温と乾燥した空気で季節を感じています。。。

各種媒体や弊社コーポレートサイトでも掲載しているように、現在ユニファでは技術職を盛大に募集しています! 過去にも何度か採用関連のお話を書いたことがありますが、今回は「ユニファのサービス開発のエンジニアって何してるの?」の最新状況を、これまでに掲載された記事の内容と合わせて書いてみたいと思います。

参考:過去の採用関連記事 tech.unifa-e.com

一口に「サーバーサイドエンジニア」と言っても色々ある

私自身がサーバーサイドエンジニアなので、差し当たりサーバーサイドエンジニアを例にとってお話を進めます。 外部コミュニティに参加したり、あるいは同業他社に知り合い/友人が居るエンジニアの方なら、一度は感じたことがあるかもしれません。

「同じサーバーサイドエンジニアでも、会社によって仕事の内容結構違うな。」

そうなんです。 一口に「サーバーサイドエンジニア」と言っても、その仕事内容や仕事の範囲は会社規模や扱う製品、サービスによってまちまちです。 「プログラムを書くこと」が役割のケースもあれば、「要件をまとめること」「顧客と話をすること」とか「インフラ構成を考えること」「モバイルのアプリを書くこと」までもその仕事の範囲に含んでいるケースもあります。 これはエンジニアに限った話ではなく、どの職種に於いても言える話だと思います。

そしてそのことが、時々起こる「転職者と会社のミスマッチ」の原因にもなります。 それ故に、ユニファの採用活動ではそのミスマッチを防ぐため、極力応募者の方と面接の段階で業務内容や範囲、期待する役割のイメージ合わせをさせて頂くようにしています。

ユニファのエンジニアの業務範囲

かつて(と言っても5年前。。。)は正社員エンジニアが片手で数えられるほどしかいなかった弊社ですが、今では海外メンバーも合わせ多数のメンバーが参画してくれています。 昔は要件の取りまとめなども含めてエンジニアが広くやっていましたが、今はプロダクトマネージャーやディレクターが居るため、その部分はそちらのメンバーにお任せするなど、役割も少しずつ変わってきています。 そんな中で、現在のユニファのエンジニアの業務範囲ってどんな感じなんだろう?と言うことを、現時点の情報として書いてみたいと思います。

サーバーサイドエンジニア

要件はPdM、ディレクターの方々がまとめてくださるため、基本的にはその内容に沿って開発を行っていく形になります。 また、画面設計/デザインについては、必要と判断したケースではデザイナーさんに作って頂いています。 要件決めの際にはもちろん技術的な実現性の考慮も必要となってくるため、要件検討段階でなんらかの形で検討に加わっています。

前回、赤沼がご紹介した午睡チェックのケースでは、大凡の要求定義の段階でシステム的な様々な課題(5分に一回一斉にデータが飛んでくるなど)が分かってきたため、早い段階からモバイルエンジニア、サーバーサイドエンジニア、インフラエンジニアが協力してアーキテクチャ設計を行っていました。 その後、運用が始まってからも、少しずつ改良を重ね現在の構成を作っています。

tech.unifa-e.com

大きな会社ですと、各社員の役割分担がかなり細分化されているため、例えばサーバーサイドのエンジニアが一切インフラの設計には携わらないケースもあります。 一方、弊社では技術検討段階でサーバーサイドエンジニアが実際にAWSの環境でテスト用の構成を作って試してみたり、「この仕組み使いたいんだけど」とインフラエンジニアに持ち込んで相談したりと、インフラ構築面にも比較的入り込んだ形で開発を進めています。

モバイルエンジニア

要件やデザインに関してはサーバーサイドエンジニアの項目で記載した通りです。 同様に、要件検討段階でももちろん検討に加わります。 モバイルエンジニアの提案により要件が大きく変わることもあり、「ただ言われたものを作る」と言う立場ではありません。 提供しているサービスの性質上、モバイルアプリは実際に保育士さんや保護者の方が一番目にする機会が多くなります。 その使い勝手や品質によって大きく利用者の満足度が変わるため、とても重要な役割をになっています。

モバイルのアプリはiOS/Androidでそれぞれにデザインのガイドラインがあり、それが各OSのバージョンアップなどに伴い少しずつ変わっていくなど、Webとは違った状況もあります。 また、それぞれに独特の「セオリー」や「トレンド」が存在し、それに追従した形での開発が求められます。 そのため、現在弊社ではモバイルのエンジニアが主導しモバイルアプリのデザインのガイドラインの輪読会を開催しています。 これを行うことで、企画や仕様検討段階で皆が想像するアプリや各種デザインのイメージを少しでも近くしようとしています。

インフラエンジニア

弊社はAWSを利用しているため、主としてAWS内の環境構築/管理を行っています。 前述した通り、サーバーサイドやモバイルのエンジニアから「この仕組み使いたい」と持ち込まれることも多々あるので、それらの相談を受け付けつつ、最終的な構成をどうするのかと言ったあたりを決めていきます。 ログ管理や監視周り、バックアップの計画/設定など、信頼されるシステム運用に欠かすことの出来ない大切な領域について担ってもらっています。 Terraformを利用した環境構築の自動化などにも取り組んでいます。 tech.unifa-e.com 提供するサービスが増えていくに連れて、インフラエンジニアが管理するサーバーが増えてきたため、現在はサーバーサイドエンジニアと一部業務の分担を計画しているところです。

でも、棲み分けは絶対ではない。

と言う感じで、ここまで長々書いた通り、各職種ごとに一応の棲み分けは存在します。 ただ、この棲み分けも、絶対ではありません。 どう言うことかと言えば、自分の主たる職種に近い領域については「はみ出して」仕事をすることが多々あります。 会社によってはサーバーサイドエンジニアが本番のインフラ設定を直接変更するなんてことは許されないケースもありますが、そう言うことも実施しています。 また、現在は募集条件の都合上「サーバーサイドエンジニア」「iOSエンジニア」「Andoroidエンジニア」と言う職種で募集をしていますが、「サーバーサイドエンジニアだからモバイルのコードを書いてはいけない」と言うことも実はありません。 ですので、募集要項職種にぴったりとハマらないケースであっても、十分にご活躍頂ける可能性があります。

もちろん、その時の開発計画などの兼ね合いもあるため、必ずしも希望通りのことが出来る訳ではありません。 ですが、状況が許す限りはご本人の志望を汲んだ形でお仕事がお願い出来るように考えています。

We are hiring!!!

そんな感じで、ユニファでは現在技術職を絶賛募集中です! 少しでもご興味をお持ちの方は、ぜひ一歩踏み出してみてください! unifa-e.com

ルクミー午睡チェックの Well-Architected なポイント

皆様こんにちは、ユニファ CTO の赤沼です。

もう1ヶ月以上前になってしまいますが、 AWS Startup Architecture of the Year Japan 2020 で優勝したことはこのブログにも書かせていただきました。

tech.unifa-e.com

ですが実際のアーキテクチャの内容についてはほとんど書いていなかったので、今回は改めてどのような点が Well-Architected であると評価されたのか、ピッチでアピールした内容を説明させていただきたいと思います。 ピッチで使用したスライドは下記に公開していますので、よろしければご覧ください。

www.slideshare.net

ピークタイムに合わせた Auto Scaling

f:id:akanuma-hiroaki:20201030000500p:plain

iPadから送信される午睡チェックデータを受け取るサーバサイドのRailsアプリケーションはEC2インスタンス上で稼働しています。ピークタイムはある程度特定されていますので、時間指定でオートスケールし、インスタンス数を増やして負荷に対応します。午睡チェックの開発開始当初は今ほどにコンテナ関連の環境が充実していなかったり、メンバーのナレッジ等の都合でコンテナ化はしませんでしたが、アクセスパターンがある程度読めて、急激なトラフィック増加の懸念もあまりないプロダクトであれば、EC2でも十分に安定的な運用ができますので、何でもコンテナ化するのではなく、それがどれぐらいメリットがあるのか、ビジネスに貢献するのかを考えてアーキテクチャを選定するのが良いかと思います。

Redis を使用した処理順番の担保

f:id:akanuma-hiroaki:20201030001149p:plain

サーバサイドで受け取ったセンサーデータは、後述するように SQS に格納され、Worker によって DynamoDB に格納されます。その際に Worker が複数の場合には SQS からデータが取り出される順番は保証されません。ただこのプロダクトにとっては処理順番も重要ですので、サーバサイドでデータを受け取るとまず Redis(ElastiCache) に午睡チェックシートの各セルのステータスをフラグ情報として書き込みます。そして Worker が SQS からデータを取り出した際には、そのフラグ情報を確認し、期待した通りのステータスになっていれば DynamoDB に書き込むことで、処理順番を担保するようにしています。

SQSを介した非同期処理によるDynamoDBへの書き込み

f:id:akanuma-hiroaki:20201030001722p:plain

このプロダクトのアクセス特性として、5分毎に数千施設の iPad アプリから一斉に午睡チェックシートのデータが送信されてくるという点があります。それをサーバサイドで直接 DynamoDB に書き込もうとすると、 DynamoDB のスケールが間に合わない、もしくはオンデマンドキャパシティーでオートスケールが間に合ったとしても、スパイクするアクセスパターンの最大値にフィットしてしまい、利用料金が高額になってしまうということになります。そこでデータを一度 SQS に格納し、Worker が非同期で順次処理していくようにすることで、安定的に処理をしていくと共に、キャパシティー値をリーズナブルな範囲に止めておくことができています。

また、Worker は EC2 インスタンスに相乗りしているため、オートスケールによって EC2 インスタンスが増えると Worker も増えるのですが、その場合にキャパシティーの設定値を超過しないように、 ElastiCache に DynamoDB のキャパシティーの設定値を登録しておき、各 Worker は起動時に自身の情報を ElastiCache に登録すると共に、稼働中の Worker の情報とキャパシティーの設定値を取得し、キャパシティーを超えないように書き込み速度を調整するようにしています。

DLQを使用した失敗データ対応

f:id:akanuma-hiroaki:20201030002943p:plain

SQS から取り出した午睡チェックデータが正しく処理されなかった場合、10回まではリトライされますが、10回処理に失敗したデータは DLQ(Dead Letter Queue)に格納され、エンジニアに通知が来るようになっています。エンジニアは通知を受けるとそのデータの内容を確認し、対応が必要であれば対応を行います。対応が必要ないデータは4日間DLQに格納されたままになると削除されます。

Design for Failure

f:id:akanuma-hiroaki:20201030003439p:plain

プロダクトの利用中に、ネットワーク障害等で iPad アプリがサーバに接続できなくなった場合に、既に午睡チェック業務が開始されている状態であれば午睡センサーと iPad アプリ間だけで最低限の午睡チェック業務が継続可能になっています。

セルラー回線使用によるネットワーク安定性の担保

f:id:akanuma-hiroaki:20201030003718p:plain

iPad アプリからサーバへの接続は、 SORACOM Air Sim によるセルラー回線を使用しています。これによって保育園の Wi-Fi 環境の有無や安定性に左右されることなく、安定的なネットワーク接続を提供することができます。

また、サービスの導入時に保育園側で Wi-Fi 接続の設定を行うのはハードルが高い場合も多いのですが、SORACOM Air Sim をセットし、アカウント登録も済ませた状態で iPad や午睡センサーをお届けすることで、箱から出したらそのまますぐにお使いいただくことができるようになっていますので、導入に対する保育園側のハードルを下げることにも役立っています。

まとめ(そして We are hiring!!)

以上がピッチの中でアピールさせていただいた、ルクミー午睡チェックの Well-Architected なポイントになります。アーキテクチャには絶対的な正解はなく、そのプロダクトの特性や制約、ビジネスメリットを考慮して適切な選択をしていくべきですが、ご紹介した内容が参考になれば幸いです。

そしてユニファでは、より良いプロダクトを提供するためのアーキテクチャ構成に挑戦したいインフラエンジニアの方を始めとして各種ポジションを絶賛募集中ですので、興味がありましたらぜひご連絡ください!!

www.wantedly.com

「価値の押しつけ」とならないように。

f:id:unifa_tech:20201010174141p:plain こんにちは、PdM(プロダクトマネージャー)の田嶋です。

プロダクト開発において、何を置いても大切なのは、顧客に「使われる」こと。そして、そのために顧客を「よく知る」ということ。
理想を求めるばかり、最近は基本を忘れかけていました。改めて思い出すためにもこのブログを書こうと思います。

これから新規事業に取り組まれる方にとっても、「使われる」を目指すペインの超入門編として参考にして頂ければ幸いです。
※特定の参考文献はなく、様々な知識の寄せ集めのため、別の理解があればぜひ教えてください。

続きを読む

強化学習で最強の打順を求める(前編)

こんにちは。機械学習やデータ分析に加えて最近インフラ周りにも入門して修行中の浅野です。新しいことにチャレンジするのは楽しいですね。新しいことといえば機械学習の中でも強化学習についてはなかなか手をつけられていなかったので、今回はその強化学習を使って何かを作ってみたいと思います。息子が野球をやっていることもあり、「シチュエーション別の打率データから最強の打順を求める」という課題設定にします。通常は解くべき課題に対して最適な解法を選択していくのが筋ですが、今は「理解を深めるために強化学習をオリジナルの課題に使ってみたい」というのがモチベーションなので、強化学習を使うのが適切か、そもそも解けるのか、といったところはあまり気にせず探索していきたいと思います。

長くなりそうなので次のように2回に分けてまとめていく予定です。

  • 前編:打率データの作成とシミュレーション環境の構築 ← いまココ
  • 後編:強化学習モデルの学習と評価

強化学習としての大まかな問題設定

強化学習では、ある環境においてエージェントが観測した状態をもとに行動を起こし、それによって得られる報酬の累積値を最大化するような行動指針を学習していきます。今回の課題では、9人の打者のシチュエーション(アウトカウントとランナーの有無)別の打率データがあるとき、ランダムな打順からスタートしてある二人の打順を入れ替えていき、得点力がなるべく大きくなるような打順を求める、という立て付けを考えています。強化学習の枠組みに照らし合わせると、打順が状態に対応し、打順の中で1組を入れ替えることが行動にあたります。報酬については、与えられた打順で各イニングの攻撃をシミュレートし、1試合(9イニング)で得られる総得点をもとに設計していくつもりです。まだこのモデル化が良いのかどうか定かではありませんが、この前編ではそれを検証する上で必要になってくる打率データの生成と得点シミュレーション部分の作成について書いていきます。後編ではそれをもとに実際に行動モデルを強化学習によって求めます。

打率データ

f:id:unifa_tech:20201005143500j:plain
高打率タイプの打者のランナー状況毎のアクション割合(ノーアウトの場合)

上図はある打者の状況別の打率を定義したものです。ランナーがいるほうが一般に打率が高くなりますが、この打者はランナー状況によってヒット(single), 2塁打(double)、3塁打(triple)、ホームラン(homerun)、犠打(sacrifice)、アウト(out)の割合は変化しない設定です。どんな状況においても35%の確率でシングルヒットを打ち、3%の確率で2塁打、3塁打とホームランは1%ずつです。犠打は行いません。1人の打者に対してこれをアウトカウントごとに定義します。それを9人分作成します。ノーアウトかワンアウトでランナーがいれば高確率で犠打を成功させる川相タイプ、満塁になると異常に打率があがる駒田タイプ、2塁打が多い立浪タイプなど、いろんなバリエーションの選手を用意します(例えが昭和ですね)。一般にツーアウトになると投手が有利なので打率を全般に下げたりするなどの調整も自由ですし、現実のデータを利用することも可能です。今回準備した9人のラインナップは下記のような感じです。

  1. リードオフマンタイプ:ランナーがいないときの出塁率が高い
  2. 川相タイプ:犠打の成功率が高い
  3. 高打率タイプ:どんな状況でも出塁率が高い
  4. 三冠王タイプ:長打も含めてとにかく打つ
  5. 駒田タイプ:満塁に強い
  6. 立浪タイプ:2塁打が多い
  7. ランスタイプ:打率が極端に低いがホームランだけは多い
  8. 守備の人: 全体的に打率が低い
  9. ジョーカータイプ:なぜかツーアウトになると打ちまくる

試合における得点数のシミュレーション

ある打順が与えられたとき、1回の先頭打者から1人ずつ上記で定めた打率データに基づいてアクションを選び、アクションに応じてアウトカウント/ランナー/得点をアップデートし、3アウトになったらイニングを終了させる。それを9イニング繰り返すことで、その打順で1試合でどれだけ得点することができたのか計算することができます。特に実装が難しい部分はありませんが、アクションに応じてランナーを進塁させたり得点を計算したりする部分は下記のようにビット演算にすることで多少すっきりと書けるので一応例を示しておきます。

def update(self, out, runner, action):
    if action == 'out':  # アウト
        out += 1
    elif action == 'sacrifice':  # 犠打:ランナーを1つ進塁(左シフト)してアウトカウントを1つ増やす
        runner = runner << 1
        out += 1            
    elif action == 'single':  # ヒット:ランナーを1つあるいは2つ進塁して1塁走者をおく(第0ビットをたてる)
        if random.random() > 0.5:
            runner = runner << 1
        else:
            runner = runner << 2
        runner = runner | 0b0001
    elif action == 'double':  # 2塁打: ランナーを2つあるいは3つ進塁して2塁走者をおく
        if random.random() > 0.5:
            runner = runner << 2
        else:
            runner = runner << 3                
        runner = runner | 0b0010
    elif action == 'tripple':  # 3塁打: ランナーを3つ進塁して3塁走者をおく
        runner = runner << 3
        runner = runner | 0b0100
    elif action == 'homerun':  # ホームラン: ランナーを4つ進塁し第3ビットをたてる
        runner = runner << 4
        runner = runner | 0b1000

    run, runner = self.get_score(runner)  # アクションの結果入った得点を計算
        
    return out, runner, run
    
def get_score(self, runner):
    run = bin(runner & 0b1111000).count('1')  # 第3ビット以上で1がたっているビット数が得点
    runner = runner & 0b111  # 第0−2ビットに残っているのがランナー
        
    return run, runner

得点力が高い打順の例

9人で組める打順は9!= 362,880通りです。かなり時間はかかりますが全てのケースで上記の得点シミュレーションを走らせることで、どんな打順が得点力が高いのかを知ることができます。各打順で100試合分のシミュレーションを行い平均得点数を調べてみた結果、私が直感でこんな順番がよいのではないかと思った打順での平均得点は3.05点でした。また、すべての組み合わせの中で最も平均得点が高かった打順では4.03点でした(最低は1.76点)。それぞれの打順を比べてみるとこんな感じです。

私の案 (3.05点) 最高の打順 (4.03点)
1 リードオフマン 高打率
2 川相 三冠王
3 高打率 ジョーカー
4 三冠王 駒田
5 駒田 川相
6 立浪 ランス
7 ランス 守備の人
8 守備の人 立浪
9 ジョーカー リードオフマン

平均だけでなく得点の分布も比較してみましょう。水色のヒストグラムが私が考えたオーダーの得点分布で、クリーム色が最高得点の打順の分布です(茶色は両者が重なっている部分)。これを見ると確かに5点以上得点する試合の数がかなり違いますね。

f:id:unifa_tech:20201005180456j:plain
2つの打順における得点の分布
最高得点の打順を見てみると、まず、2番に強打者を置くという最近のトレンドと合致していて面白いです。また、上位に打率が高めのバッターを集め、ランナーが溜まったときにまわりやすい4番に満塁に強い駒田を入れたり、川相/ランス/守備の人と打率が低めな選手を固めることで打線が分断されるのを防ぐなど、言われてみるとそうだよなと納得させられるオーダーになっており興味深いですね。

まとめ

打率データをもとにある打順での得点数を算出するシミュレーションが完成しました。対戦相手の能力や相性、ボールカウント、走力、代打、守備力など野球において考慮できていない要素がたくさんありますが、今回は野球の正確なシミュレーション環境を構築するのが目的ではないので気にしないでおきましょう。また、全探索の結果から得点力の高い打順の例を示しましたが、打者の特徴が少しでも変わるたびにこのような計算を行うことは現実的ではないため、後編では強化学習モデルによって得点力のある打順をより効率的に求める手法に挑戦していきます。

AWS Startup Architecture of the Year Japan 2020 で優勝しました!!

f:id:akanuma-hiroaki:20200923223808j:plain

皆様こんにちは、ユニファの赤沼です。

先日プレスリリースも出させていただきましたが、9/16 に行われた AWS Startup Architecture of the Year Japan 2020 Live Finale にて、ルクミー午睡チェックのアーキテクチャについてプレゼンさせていただき、ユニファが優勝することができました!これも日々社内でサービス提供のために取り組んでいる開発、ビジネス、コーポレートの全メンバーの努力が評価されたものですし、メンタリングいただいた AWS の松田さん、岡田さんのおかげですし、何より日々保育の現場で真摯に保育に取り組まれている保育者の方々のご尽力の成果でして、本当にありがたく思っています。

今回はどういったところが評価されて受賞に至ったのか、また、事前の準備や当日の様子などについてご紹介できればと思います。

AWS Startup Architecture of the Year とは

「AWS Startup Architecture of the Year」は2018年に日本で生まれ、今年から世界規模で展開されるスタートアップのためのコンペティションで、評価の対象はビジネスを成功に導く優れた「アーキテクチャー」です。そのアーキテクチャーがいかに AWS Well-Architected Frameworkの基準に適合しているか、ビジネスにインパクトを与えているかといった点が評価の対象となります。日本、米国、インド、欧州の各地域から、優れたアーキテクチャーでビジネスをけん引しているスタートアップが選出され、11月に開催予定の世界大会(オンライン)にて世界一を決定します。

Startup Architecture of the Year Japan 2n020

aws.amazon.com

評価されたポイント

さて、今回どういったところを評価いただいたかですが、受賞時に審査員の藤本さんからいただいたコメントから、派手さはないけれどやるべきことをしっかりやっているというところを評価いただいたと思っています。

ルクミー午睡チェックでは命に関わる業務の安心・安全をサポートするというプロダクトの性質上、 Well-Architected Framework の5つの柱の中でも、特に信頼性と運用上の優秀性が求められます。信頼性という点では、DynamoDB と SQS を使ってパフォーマンスを担保している点や、 Design for Failure を考慮した DLQ の仕組み、ネットワーク障害等が発生してもローカルのみで一定の業務が継続可能にしている点等で担保しています。また、運用上の優秀性といった点では、SORACOM Air Sim を用いたセルラー回線を使うことでの安定した接続や導入時の保育園側のハードルの低減といった点で考慮しています。

一つ一つは技術的に尖っているわけではないですが、サービスの特性を考えて求められる点を総合的にしっかりカバーし、そしてこれらが実際にプロダクトの導入実績と紐づいて、事業に貢献できているというところが評価いただけたものと思っています。

メンタリング

応募後に書類選考を通って Live Finale での登壇が決まった段階で、 AWS の松田さんと岡田さんにメンタリングいただき、5分間という短い時間でどういった点を伝えるのが良いかをアドバイスしていただきました。それをもとにプレゼン資料とシナリオを作成したのですが、5分間というのは思っていたよりもとても短く、その中で事業やアーキテクチャ、ビジネスへの貢献をしっかり説明するには、スライドで表示して理解してもらうことと喋って説明することを吟味して、不要なものをできる限り削る必要がありました。そして一旦作ったもので松田さんと岡田さんにレビューいただき、ダメ出しを経てなんとか5分間で伝えるべきことをまとめることができたと思います。松田さんと岡田さんには本当に感謝です。

当日の様子

当日のプレゼンの順番は社名の五十音順ということで、六社中一番最後だったのですが、ということは一番最後まで緊張してることになるので、正直他社のプレゼンをしっかり見てる余裕はありませんでした。見てると余計に緊張しちゃうので。。

またこれは完全に自社の事情なのですが、当日 Live Finale の直前に取締役会があり、どうしても外せなかったので、岡田さんに会議室を手配いただき、Amazon目黒オフィスの会議室からリモートで取締役会に参加させてもらいました。取締役会では自分のアジェンダもあり、 Live Finale のことを考えるとそわそわしながら参加していたのですが、なんとか無事に予定時間までに取締役会も終えることができました。岡田さんには私のわがままにご対応いただき、感謝です。

朝から吐きそうに緊張してましたが、プレゼン自体もなんとか5分間に収めることができ、審査員のCTOの方々からどんなマサカリが飛んでくるかとびびっていた質疑応答も乗り越えて、やっとほっとした感じでした。

世界大会

今のところ世界大会については、11月にオンラインで開催、という以外にはまだ何も聞いていないので、プレゼン英語なのかなー、というぐらいなのですが、審査員の藤本さんや松本さんからはしっかりプレッシャーかけられたので、日本代表としてはがんばらねばと思っています。プレゼン自体は英語でもなんとかなりそうな気がしますが、質疑応答が英語でできるのか。。英語力を鍛える必要がありますね。。

まとめ

事前の準備は色々と大変でしたが、受賞できたことは本当に嬉しく、SNS等でも多くの方からお祝いの言葉をいただきました。本当にありがとうございます。また、社内のメンバーとしても自信につながるところもあると思いますし、社外に向けてのアピールになる点も大きいのではないかと思います。私自身も改めてアーキテクチャを見直して Well-Architected Framework について考えるきっかけにもなりましたし、今後より良いプロダクトを提供できるようにチャレンジしていこうというモチベーションにもつながりました。

そしてインフラエンジニアをはじめ、このチャレンジに一緒に参加してくれる方を募集してますので、興味のある方はぜひご連絡ください。一緒に保育をハックしていきましょう!!

herp.careers

Jamstackで動的サイトを作ってみる

こんにちは、サーバーサイドエンジニアの柿本です。

みなさんは Jamstack をご存知ですか??!!

先日知人が Jamstack について熱く語ってくれまして、私は「ナニソレオイシイノ?」と思って聞いていたのですが、彼があまりに熱く語るので「サゾカシオイシイニチガイナイ!」ということでいろいろ調べてみました。

「 SPA と SSR のいいとこ取り」や「動的サイトと静的サイトのいいとこ取り」といった魅力的な言葉が並ぶのですが、つまるところ、

サイトの中の静的な箇所は完全に静的ファイル化しておいて、動的な部分はAPIを叩いてよろしくやろうぜ!

ということのようです。

早速入門してみようとしたところ、 Jamstack の入門記事は主に ヘッドレス CMS や SSG (静的サイトジェネレータ)との繋ぎ込みなど 静的ファイル化部分 に主眼が置かれておりました。
動的によろしくやる方法を知りたかったので、自分でやってみることにします。

TL;DR

1クリックで Netlify にデプロイすることができます!

Deploy to Netlify

事前準備として FaunaDB のセットアップと Server secret の取得 が必要です。

デプロイ完了後に Netlify Identity の設定 が必要です。

目次

技術スタック

  • 静的サイトジェネレータ: Next.js
  • ソースコード管理: GitHub
  • ホスティング・CDN: Netlify
  • データベース: FaunaDB
  • ヘッドレスCMS: 利用なし(*動的部分をターゲットとしてるので使いません)

Jamstack の構成としては標準っぽい物を選定しました。

構想

動的サイトといえば ユーザーログインデータ保存が基本となるので、 『ユーザー登録制の掲示板サイトもどき』 を作ってみます。

ユーザーストーリー

  • ユーザーがログインできる
  • ユーザーが自分の名前でメッセージを投稿できる
  • メッセージ一覧を誰でもみれる

画面構成

/ フロントページ(メッセージ一覧)
└/ メッセージ投稿画面

非常にシンプルですね!

最終形態

f:id:unifa_tech:20200918003519g:plain
2人のユーザーによるログインから記事投稿まで

最終成果物

GitHub に公開 しました!
開発手順の詳細も README に記載してあるので、参考にしてみてください。

github.com

開発の流れ

  1. Next.js のセットアップ
  2. GitHub に push
  3. Netlify にデプロイ
  4. Netlify Identity の設定
  5. フロントコーディング
  6. FaunaDB の設定
  7. Netlify Functions コーディング

実装のポイント

フロントエンド

フロントエンドを構成するソースファイルは以下です。

dynamic-jamstack (App root)
├── pages
│   ├── index.js           // ホーム(メッセージ一覧)画面
│   └── new_message.js     // メッセージ投稿画面
├── components
│   ├── Message.js         // 1つのメッセージ表示
│   ├── MessageList.js     // メッセージを一覧で表示&データ取得処理
│   └── MessageForm.js     // メッセージ入力フォーム&データ送信
└── utils
    └── netlifyAuth.js     // Netlify Identityの認証処理

/pages/ 配下は Next.js により静的化されるページです。
デプロイ時に静的化されるため、ここに動的な処理(データ取得&描画)を記述しても想定どおりに動きません。

/components/ 配下は React コンポーネントです。
動的な処理をここに記述し、 pages のファイルで読み込むことで動的な挙動を実現できます。

Netlify Functions (API)

API のロジックは以下で構成されます。

dynamic-jamstack (App root)
└── functions
    ├── messages-create.js       // メッセージ保存
    └── messages-read-all.js     // メッセージ一覧取得

Netlify Functions の中身は AWS Lambda なので、書き方は同じです。

/messages-create はログイン済みのユーザーのみに制限する必要があり、クライアントと Functions のそれぞれで以下の対応が必要です。

クライアント - Header に Netlify Identity Widget から取得した token をセットします。

// components/MessageForm.js

  generateHeaders() {
    const headers = { "Content-Type": "application/json" }
    if (netlifyIdentity.currentUser()) {
      return netlifyIdentity.currentUser().jwt().then((token) => {
        return { ...headers, Authorization: `Bearer ${token}` }
      })
    }
    return Promise.resolve(headers)
  }

Functions - context.clientContext.user でユーザー情報を取得することができます。

// functions/messages-create.js

  const user = context.clientContext && context.clientContext.user;
  if (!user) {
    return callback(null, {
      statusCode: 401,
      body: JSON.stringify({ "error": "You must be signed in to call this function" })
    })
  }

考察

今回は "Jamstack構成で動的な処理を実装する" を目的として Next.js をベースに

  • 動的な処理を React コンポーネントで記述
  • 静的ファイル化される箇所からコンポーネントを呼び出し

として実現しました。

わかったこと

  • Jamstack 構成で動的サイトは実現可能
  • ユーザー認証は Netlify Identity で実現可能
  • ローカル(静的ファイル内)でも API 内でもユーザー情報を取得可能
  • データ保存はサーバーレスのデータストアにより実現可能

課題

1) サイトによる向き不向きがありそう

いわゆる SNS のような動的な処理がメインのサイトの場合、静的ファイル化できる部分が限られるためあまり恩恵を受けられないかもしれません。

メリットを最大化するには静的化する箇所を適切に切り出す必要がありそうです。

例えば弊社サービスのルクミーフォトの販売画面(購入する写真を保護者が選択する画面)などは、販売写真の設定がされたタイミングで静的ファイル化すればハイパフォーマンスのメリットがありそうです。

そのためには incremental build が適切に実行されるようにする、などの複雑な設定も必要になるかと思います。

2) pages 配下は静的ファイル化される、と意識してコーディングする必要がある

Next.js の仕組み上当たり前のことなのですが、ローカルの開発サーバー上でホットビルドをしているとついつい忘れてしまいます。

これは慣れの問題だとは思いますが、 Netlify にデプロイしてから「あれれ?」となることが何度かありました。(笑)

まとめ

Jamstack で動的サイトを作ることが可能なことは分かりましたが、感想としては「ちょっと無理やり感が否めない」といったところです。

とはいえ Netlify などの CDN 経由で静的ファイルを配信できることのメリットは大きいので、サイトの向き不向きは選びますが、活用していければ良いなと思いました。


ユニファでは保育をハックするエンジニアを募集中です。 一緒にスマート保育園を実現しましょう!

www.wantedly.com

Appendix

FaunaDBの設定

https://fauna.com/ からアクセスし、 Signup します。 Netlify のアカウントでも Signup できます。

任意の名前で Database を作成し、以下を設定します。

  • Collection - Name: messages
  • Index - Name: all_messages

SECURITY メニューから key を作成し、 Server secret を取得します。
Server secret は2度と表示されないので、無くさないように保管します。

Netlify Identityの設定

Netlify の dashboard の Site 一覧から対象の Site を選択します。

Identity > Enable Identity の順にクリックしてアドオンを有効化します。

Setting and usage > Registration > External providers で追加したい認証プロバイダーを選択します。

f:id:unifa_tech:20200918025325p:plain
Netlify Identity の External providers

TensorFlow Profilerを用いた学習時間の短縮

こんにちは。R&D改めデータエンジニアリングチームの宮崎です。 普段はTensorFlowを使って、Deep Learningを学習させて画像認識モデルを作ったりしています。

Deep Learningの悩みの一つとして、学習時間が数時間から数日に及び、非常に長いという点が挙げられます。 作業効率やマシンの費用を考えると、少しでも学習時間を短くしたいです。 そこで今回はTensorFlow Profilerを用いてDeep Learningの学習時間を短縮してみたいと思います。

TensorFlow Profilerとは

TensorFlow ProfilerはTensorFlowの計算時に、処理毎の所要時間などパフォーマンス情報を収集し、TensorBoard上で可視化してくれるツールです。 TensorFlow v2.2.0やv2.3.0で機能が強化され、より詳細な分析ができるようになっています。

続きを読む