ユニファ開発者ブログ

ユニファ株式会社システム開発部メンバーによるブログです。

ユニファ開発チームの2020年-今年は洗練の年!

あけましておめでとうございます! エンジニアの田渕です。
みなさま、どんな年末年始を過ごされましたか?

ユニファは海外エンジニアも在籍しておりますので、きっと多種多様な過ごし方が……と思って話を聞いてみると意外と「寒いし混んでるんで出かけません。」と言う返事が多く(笑) 話を聞いてみると、国によっては日本みたいに「お正月だからホテルの料金が高くなる」みたいなことがないところもあるようなのです。 確かにそうなると、わざわざ高い時期に出かけることに躊躇いが出るのは納得です。

さて、まだ今年の仕事も始まって一週間経っておりませんが、早速年始からバタバタバタ……。。。 このブログも、うっかり書き忘れそうになっていたのを思い出し書いているところです。

昨年末のUniFa Advent Calendar 2019は好評のうちに終了。 (読んでくださったみなさま、ありがとうございました!執筆したみなさま、お疲れ様でした!) 最終日25日に書いたCTO赤沼の記事が良かったと内輪で話題になりましたので、 今回はその内容を受ける形で、私の方で今年の展望を書いて行こうと思います。

<プロダクト>「スマート保育園構想」の実現に欠かせないものとは

「スマート保育園構想」とは

最近は色々な場所で、弊社のメンバーが登壇した際に「スマート保育園構想」と言う言葉を口にしていると思います。

改めて、「スマート保育園構想」とはなんなのか。

昨年3月の赤沼のインタビュー記事と、12/28(土)に放送されたBSフジの「この国の行く末2」のリンクです。

job-draft.jp

「この国の行く末2」

konokuni.jp

プロダクトが増えてきた!でもそれだけでいいの?

f:id:unifa_tech:20200109234529p:plain
スマート保育園構想
上の図は、前回のブログで書かせて頂いたRuby Biz Grandprix 2019のプレゼンテーション資料中の図です。 (この俯瞰図はうちのデザイナーが書いてくれたもので、とても好評です。)

当初は写真サービスである「ルクミーフォト」しかなかった弊社ですが、現在ではこの図に記載されていないサービスも含め、保育園・幼稚園・こども園内の業務のより広い範囲をカバー出来るようになっています。 直近では、「ルクミーシフト管理」のリリースも発表されました。

プロダクト/機能が増えていくこと自体は良いことですが、それに伴い新たに生まれてくる問題もあります。

作り手としては「システム構成・アーキテクチャの複雑化」、使い手としては「機能が多すぎて使いこなせない。」 特に後者の「機能が多すぎて使いこなせない。」と言う問題は、利用者の方々にご不便をおかけすることになるので、早急な対策が必要と考えています。

私はもともと地方出身なので、東京に来たばかりの頃は巨大なデパートの中で目的のものが探せずにとても疲れた思い出があります。自分が欲しいものだけが揃ったセレクトショップあったらなーとそんな時に思った訳ですが、弊社サービスをご利用頂く利用者の皆様にはそんなご苦労はおかけしたくない。。。

プロダクトに関しては、今年も昨年同様に新しい物をどんどん世に送り出しながら、プロダクトが増えた次の段階である

「より効率的に利用者の方がやりたいことをやれる様になるには。」

「欲しいものを、欲しいタイミングで見てもらえるには。」

を追求していくのが今年だと考えています。

<チーム>「多様性を受け入れる」ことから、より充実した環境へ

その「当たり前」は本当に「当たり前」ですか?

さて、昨年は赤沼の記事中にもあった通り、エンジニアメンバーが大きく増えた年、多様化が進んだ年でした。 開発チームの19名の新メンバー中、11名は外国籍メンバー。 年末に行った忘年会では、各国の早口言葉で盛り上がったところもあったようです。

日本では当たり前の「お正月のATMのメンテナンス」。 毎年の恒例行事ながら、日本人でも忘れてしまう人がいます。 年末に外国籍メンバーから「他の外国籍メンバーに教えてあげたほうがいいです。」と言うお話を貰って慌ててアナウンスしました。 言われてみれば、日本での年末年始が初めての方は知らなくて当然です。

こんな感じで、日常的に「当たり前」と思っていることが実は当たり前じゃない、と言う経験をしています。 そのお陰で、最近では色々なことに対して「それって当たり前なんだっけ?」と考えられる様になってきた気がしています。

これは、プロダクトを作っていく中ではとても大切な感覚であり、今後役に立っていくといいなと思っています。

去年は精一杯だったけど、今年はもう一歩先へ

昨年は様々な方々を受け入れ、実際に業務をしていくための基盤づくりの年だったと思っています。

コミュニケーションはどうやって取るのが一番いいのか?

何が必要なのか?

色々と、みんなで試行錯誤してきました。 現在では各チームでそれぞれのやり方を見つけ、臨機応変に対応してくれています。

昨年は受け入れるところで精一杯でしたが、今年は「より効率的に、充実した情報を届けるには、質の高いコミュニケーションを取るには」と言う一歩先の観点を持ち、活動していきたいと思っています。

今年もHackします!

ここまで、「今年やっていきたいこと」について書かせて頂きました。

今年は、 「昨年広げた色々な物を整理/綺麗にしてより洗練させていく年」 と考えています。

また一年間、予想していることもしていないことも含め、色々なことがあると思いますが、来年は次のステージの抱負を書けるように、一年頑張っていこうと思います。

引き続き、変わり続けるユニファで一緒に保育をHackしてくれる方を募集中です!

unifa-e.com

今年も宜しくお願いいたします!

できることもできないことも増えていく。ユニファ開発チームの2019年を振り返る

みなさまメリークリスマス、ユニファCTOの赤沼です。

UniFa Advent Calendar 2019 もついに最終日。この記事を読んでいただけているということは私もちゃんと役目を果たせたということで仕事納め気分です(まだ早い)。

さて、2019年ももうすぐ終わりですが、今年もユニファではスタートアップらしく、一年の間で色々なことがありました。その中で今回は開発に関連するトピックを雑に振り返った後で、最近思ったことを書いてみたいと思います。

プロダクトの追加・拡大

プロダクトに関連することとしては、念願の一つであったルクミーフォトのリニューアルを実施しました。2013年創業時のファーストプロダクトであるルクミーフォトは、サービスの立ち上げスピードと初期ユーザ獲得を最優先としていました。リリースから時間も経ち、サービスのフェーズも変わってくるとどんなプロダクトでもレガシーな部分に対するコストが増大していきます。ルクミーフォトも今後のサービス拡大やユーザビリティ向上のためにも今リニューアルすべきという決断のもとリニューアルを実施しました。リニューアル中は大きな機能追加等はできなくなりますので、ビジネスのメンバーからも多大な協力を得て実現することができました。

tech.unifa-e.com

tech.unifa-e.com

tech.unifa-e.com

tech.unifa-e.com

また、今までリクルートマーケティングパートナーズさんが開発・運用されていた保育園向けICTサービスである Kidsly を、弊社の販売パートナーであるフレーベル館さんを経て事業譲渡いただき、弊社での開発・運用が開始しました。すでに多くのユーザに利用いただいている大規模なサービスの移管は弊社でも初めての経験で、手探りなことも多かったのですが、無事に完了し、今後のユニファの保育園向けICTサービスの中核となっていくプロダクトが加わりました。

kidsly.jp

ルクミー午睡チェックも正式リリースから一年が経過し、弊社初のIoTサービスとしてまずは1年間運用が行えたことにホッとしています。導入数も順調に伸びていますので、今後も安心・安全を提供するプロダクトとして安定的な開発・運用を続けていきたいと思います。

unifa-e.com

開発チームのスケール&開発プロセス改善

開発チームとしても体制が大きく変わりました。今年だけでも開発チームに19名の新メンバーが加入し、今までの倍の規模になりました。また、そのうち11名は外国籍メンバーということで、一気に多国籍チーム化が進みました。開発者採用はスタートアップにとっては特に厳しい市場環境である中、これだけのメンバーに入社いただけたのは本当に嬉しい限りです。

エンジニア以外にもディレクターやデザイナーメンバーも増え、各ロールでのチーム体制や、ディレクターを中心としたプロダクト開発体制も以前より充実させることができ、スクラムを主軸としたアジャイル開発プロセスのプラクティスも積極的に導入しています。ビジネスメンバーも含めたプラクティス浸透のための取り組みもメンバーが積極的に実施してくれているので、今後さらにプロセスの改善が進めていけるのではないかと思っています。

tech.unifa-e.com

R&Dのメンバーも増員され、主に Machine Learning / Deep Learning 領域について今まで以上に幅広く取り組むことができてきました。ビジネスメンバーとも連携して、企画案についての技術的な実現可能性の検討なども行なっています。スタートアップでR&Dチームを置いているケースはあまりないと思いますが、我々が目指すスマート保育園の実現のためには欠かせないと思っています。

podcast.unifa-e.com

デザイナーも人数が増え、やっとチームと言える形になってきました。自社プロダクトのデザインはもちろん、外部向けの露出も増やしていくことができそうですし、社内全体においてのチーム作りという点でもデザインが持つ力は大きいと思っています。

podcast.unifa-e.com

ちなみに入社時から現在の規模になるまでのチームのスケールについては、今年の CTO Night & Day での登壇時にお話しさせていただき、下記の資料も公開しています。

prezi.com

技術ブランディング注力

今年多くの開発メンバーが入社してくれたということは、年始の段階でもそれだけの採用を見込んでたということで、今まで以上に外部向けの技術ブランディングに注力した年でした。以前から継続していた開発者ブログもメンバーが増えたことによって投稿数も大幅に増え、今回のような Advent Calendar が成立するまでになりました。昨年末からスタートした Podcast も不定期ながらなんとか継続し、今月で一年が経過しました。またカンファレンスのスポンサーも初めてやらせていただき、RubyKaigi や builderscon でスポンサーさせていただいた他、 RubyWorld Conference や ServerlessDays Tokyo、 プロダクトマネージャーカンファレンス等ではブースも出させていただきました。当日は登壇させていただく機会があったり、ブースにお越しいただいた方と色々とプロダクトについてお話しさせていただいたり、私たちとしても世界が広がっていく感覚を持つことができました。さらには自社単独や他社との共催での Meetup イベントも開始し、参加いただいた方の中から入社が決まった方もいました。

podcast.unifa-e.com

podcast.unifa-e.com

podcast.unifa-e.com

tech.unifa-e.com

tech.unifa-e.com

podcast.unifa-e.com

tech.unifa-e.com

tech.unifa-e.com

tech.unifa-e.com

これらの実行については準備段階から実際の運用まで、今までの規模では行うことが難しかったですが、メンバーが増え、それぞれ積極的に協力してくれたからこそのもので、開発だけではなく人事や広報等の他の部署のメンバーの協力もあったからこそ実行できたものです。その甲斐あって最近他社の方と会って話をする際に、ユニファのことを目にしたことがある方が増えてきた感触がありますし、すでに繋がっていた方からも、露出機会の多さに注目いただくことが増えました。

また、今年はユニファ開発チームから初めて海外のTech系カンファレンスに1人ではありますが参加することができました。AWS re:Invent や Google I/O、 WWDC など、海外のカンファレンスは日本のものとはスケールが違いますし、最新の技術情報のキャッチアップももちろん重要ですが、何よりテクノロジーに対しての盛り上がりを実際に体験してくるということはとても重要なことだと考えています。来年以降どうなるかはまだわかりませんが、ひとまず最初の一歩が踏み出せたという点では前進できたと思っています。

tech.unifa-e.com

できることが増えてきた。でもできないことも増えていく

ここまでは主に今年やったこと、規模が大きくなったことでできるようになったことをお話ししてきましたが、一方で、できないことも増えてきているとも感じています。規模が小さい時には、今後人数が増えてくればどんどんできることも増えていって、できないことは減ってくるイメージをしていましたが、実際に開発チームや会社全体の規模が大きくなってくると、もちろんできることが増えてきてはいるものの、今までとは違ったできないことが増えていっているという感じです。

プロダクト数や開発チーム、会社規模が拡大してくると、工数などの問題以外にも様々な力学が発生してきます。また、人が増えればやりたいことの総数も増え、指向性も多様になっていき、いずれかを選択せざるを得ないケースも増えてきます。さらにスタートアップとしては対象とする業界の情勢や自社の状況などは日々めまぐるしく変わっていきます。

こういった中では、会社も個人も自分を変えていき、向上させていく必要があります。自分が今までと同じアウトプットを出していたとしても、周りが変わっていき向上していく中では、相対的に自分達のバリューは下がっていってしまいます。

一方で、どれだけ変化する状況の中でも変えてはいけないもの、守らなくてはいけない大事なものがあるのも確かだと思っています。この、変えていくべきことと変えてはいけないことの判断は簡単ではありません。痛みを伴ってでも変えるべきことなのか、流されずに抗うべきことなのか、この判断がとても難しいと最近は感じています。経営、チーム、プロダクト、どの面を取ってもこの判断を間違えた場合、リカバリが困難になる可能性があります。

日々の 1 on 1 等でメンバーと話す中で上がってくるボトムアップでの課題、マネージャー陣から上がってくる会社組織としての改善点、経営陣と話す中で論点になる事業上の問題点など、それぞれ違った視点から、みんなもっと現状を改善したいという想いで様々な課題があげられます。意思決定をしていく立場としては、上がってきている課題は適切な内容か、自分の判断は会社の経営者として正しいのか、CTOとして開発視点から通すべきことを主張できているか、単にメンバーの要望に迎合しているだけになっていないか、他の経営陣の声に流されていないか、セクショナリズムを排除してフラットに判断できているか、こういった様々な思いが日々渦巻いています。

自分の判断が正しかったのかどうかはその瞬間にはわかりません。後になってわかるものです。そうした中で意思決定していく上で大切なのは、自分の中で芯のある結論を出せたか、これで間違っていたら仕方ないと思えるような、これならメンバーにどう思われても仕方ないと思えるような決断になっているかなのかなと思っています。なんとなくで決めてしまったものは失敗することも多いですし、その後もモヤモヤしたものが残りがちです。もちろん考え抜いた上で決定したことでも失敗することはあるのですが、その場合には自分の中で整理もつけやすく、次に向けてピボットしていける気がしています。要はそれぞれの意思決定に対して自分にも他者にも真摯に向き合って手を抜かずに考え抜けたかどうかなのだと思っています(できているとは言ってない)。

来年も保育をハックする

さて、とりとめもなく色々と書いてしまいましたが、我々ユニファ開発チームは来年も保育をハックしていきます。この「保育をハックする」というのは我ながら開発チームのマインドを一言で表していて良い感じだなぁと思っています。また、上記で色々と書いたように組織としてももっと強くしていく必要がありますので、チームをハックしていくことも必要だなと思っています。今年は技術ブランディング等で外向けの施策にも注力していましたが、来年はどちらかというとチームを強くしていくための内部的な施策に重点を置きたいなと思っていますので、保育をハックしていくためのより強いチームを作っていけたらと思っています。一緒に保育をハックしていくためにチームに加わっていただける方もまだ募集していますので、興味のある方はぜひご連絡ください。

unifa-e.com

今年の Advent Calendar の記事としてはこれが最終回となりますが、今後もいろんなところで露出していけるように頑張りたいと思います。また、一年後に2020年を振り返った時に、あの決定は正しかったと言える決定を一つでも増やせるように取り組んでいきたいと思いますので、このブログを始め、引き続きユニファをよろしくお願いします。それでは、良いお年を。

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

会社でスナックを立ち上げた話

~お品書き~

ご挨拶

あらこんばんは、私「スナック洋子」というスナックのママをやらせていただいております洋子と申します。
昼間は ディレクター 兼 QA をやっておりまして、二足の草鞋を履かせていただいております。 あ、 ディレクター 兼 QA 兼 ママ なので三足ですわねおほほ。(足は三本もない。)

すみませんちょっとつらくなってきたので、ここからはいつもの感じで書きますね。

今回は社内コミュニケーションを活性化させる場としてこういう方法もあるよーってことで紹介できたらいいなーと思っております。

ゆるい話なのに、思ったより長くなりましたすみません。

「スナック洋子」について

8月にオープンしたばかりでして、ママとしてはまだまだ駆け出しです。
「スナック洋子」は社内向けと社外向け、それぞれで開店しています。

今回は「社内向け」のお話がメインです。
(社外向けは最後にチラっとだけ話します。)

社内では月に一度、最終金曜日に開催しています。
開催場所はオフィスの一角でやっています。

やりたかったこと

社内みんなのオフな場所をつくりたい

会社もなかなか大変なフェーズなので、社内はドタバタ。もう本当にドタバタ。

そんな中、みんなにとって「気晴らしの場」でも「ただ楽しい場」でもなんでも良いのでつくりたかったという感じです。

「あー疲れたなーちょっとスナック寄って帰るかー」
「お、なんかやってる楽しそうー」

ってみんなに思ってもらえていたら大成功です。

社内コミュニケーションの活性支援

ユニファはものすごい勢いで社員が増えています。
(私が入社した4年前は15人で、今や150人以上…!10倍やばい…!)

会社の規模がおおきくなってくると一度も話したことがない!という人が出てきます。
私の体感ですが、100人を超えたくらいから発生しはじめる気がします。

部署をまたいでのコミュニケーションが減り「あそこの部署何やってんだ状態」や、「もはや正社員かパートさんか委託さんなのかがわからない状態」や「役員と一度も直接しゃべったことない状態」ですね。

それを少しでも減らすために、会話をするきっかけをつくれたらなーと思っています。

「最近何してんのー?」
「お、はじめましてー!」
「土岐でございます」←CEO

って会話が生まれていたら大成功です。

私が楽しみたい

今までの話全部忘れてもらっていいくらいここです!(笑)

ママが一番楽しまなくてどうするんですかくらいに思っています。
何事も続けるには運営している側が楽しまなきゃ続かないですよ。(仕事も同じだと思う。)

私は会社のみんなが好きなので、みんなが楽しそうにキャッキャウフフしているのを見ながらお酒が飲めればそれが私にとっての最高です。

スナックをつくる

といっても、自分でつくってないんですよねこれが(笑)

私個人的な話をしますと、私は「人と酒が好き」って理由でスナックをやるのが夢だ!ってみんなに宣言していました。
そんな中、オフィス移転をしまして、カウンターが設置されました。
これはスナックいけるのでは…!って思っていたところ、
みんながロゴをつくり、名刺をつくり、看板をつくり、勝手にスナックが出来上がりました(笑)

目的や運用ルールを決める

さて、スナック自体はみんなの力でできました。
次は運用ルールや集客です。

1. Googleドキュメントで目的・ルールを作成

叩きはスナック洋子の後援者の方が作成してくれました。(みんなで作っている感じ良いね。)
叩きを元にこんなのもあったほうがいいよねーって話をして決まった内容が以下です。

趣旨と目的

  • 趣旨(開催日と開催場所など)
  • 運営目的
  • ルール策定の目的

ルール

  • 片付けの徹底
  • 深酒の禁止
  • 残業している方への配慮
  • ボトルキープ方針(誰がどれだけ飲んでもOKなものだけキープできる)
  • 出禁ルール(年間でルール違反3回で1年間出禁)

これができたら役員や部長陣へ「本当にスナックやるよー!」って宣言と総務の了承を得てきます。

ありがたいことに、会社としてGOGOでした。
こういう活動の背中を押してくれる会社は良いなーと思いました。(いつか予算もぎとりたいと思っている。)

2. お客さまへの情報発信の場をつくる

Slackにチャンネルを作成して、お客さまへの連絡や活動報告をする場としました。

開催後にはこんな感じで報告しています。

f:id:unifa_tech:20191220180344p:plain
スナック活動報告

お客さまのお金を預かる以上、ちゃんと報告はしないとですよね。

3. お客さまの集客

全社員がいるSlackチャンネルで活動開始のご連絡をし、チャンネルへ入ってもらいました。

2回目以降も同じ感じで、全社員へ周知→チャンネル誘導→チャンネルで詳細をご連絡、という形です。

いよいよスナック開店!

開店までにやったことを箇条書きします。

  • お客さまの人数把握
  • お客さまのスケジュール登録と、目的・ルールの周知
  • 食べ物・飲み物の確保
  • 開催日が近くなったらリマインドと人数再確認

得られたもの

そりゃあもうみんなの笑顔ですよね!(なんつって)

仕事やプライベートな話から、ボードゲームやったり、そりゃもうキャッキャウフフですよ。
実際みんなの話を聞いていると、狙った部分の会話もしてくれていたりと、最高でした。
また、役員もよく遊びに来てくれるのでみんな役員とたくさん話せて楽しそうでした。

実際の効果がどれくらいあったのかはどうやって測ろうかなぁは考えていますが、
それよりもみんなが楽しんでくれていればもう大成功なのではって正直思っています。

f:id:unifa_tech:20191220183149j:plain
看板をつくった張本人
f:id:unifa_tech:20191220183209j:plain
黒服担当
f:id:unifa_tech:20191220183119j:plain
オープン初日の様子
f:id:unifa_tech:20191220183155j:plain
ロゴをつくった漁師(太刀魚を捌き中)
f:id:unifa_tech:20191220183204j:plain
ボードゲーム盛り上がり中

カイゼン

もちろん課題もあるのでそれは今後運営しながらカイゼンしていき、より良いスナックにしていきたいと思っていきます。

  • 正社員じゃない方への周知方法(チャンネルに気軽に入れないなど)
  • 他部署が何をやっているかわからない問題は解決していないので、LT大会とかやりたい
  • お酒の管理(スナック開催日の夕方から冷蔵庫がパンパンになってしまう)

CEOに大きい冷蔵庫をねだろうかと思っています。
(土岐さーーーん見てますか!?冷蔵庫欲しい!冷蔵庫冷蔵庫!!!)

まとめ

社内でスナックをオープンさせると楽しいよ!

場をつくるのはちょっとたいへんだけど、それ以上に測れない何かを得られるよ!

ということで以上です。
思っていたより長くなりました、最後まで読んでくれたあなたはもうスナック洋子のお客さまです!

ちなみに社外向けの「スナック洋子」については、採用活動の一環としてオープンしております。

  • ユニファのプロダクトを知ってもらう
  • QAチームやディレクターの働き方やプロダクト開発について、こんな感じでやってるよーの紹介

などなど、ユニファに興味があるかたはどうぞご来店ください。
(TwitterとかFacebookとか、なんとかしてママに連絡とってもらえれば日程調整して開催します!)

看板設置するだけでどこでも「スナック洋子」になるので簡単なのです(笑)

それではみなさまのご来店を心よりお待ちしております。ママより

Bloom Filterについて

こんにちは、プロダクト開発部のちょうです。最近だいぶ寒くなってきて、こたつからなかなか出られません。こたつとみかんがあれば一日いきれると思いつつ、普段自分が学んでいる内容をすこし紹介したいと思います。

今回の内容はBloom Filterです。Bloom Filterは一言でいうと、空間効率のいい確率的データ構造です。要素が集合のメンバーであるかどうかのテストに使われます(wikipediaより)。確率ですので、使えるものではないと思う人が多いかもしれないが、Bloom Filterの特徴を理解すれば問題なく利用できます。

要素が集合のメンバーであるかどうかを確認するには、一番普通の方法はHash関数を元にするHashSetというデータ構造を使います。HashSetは基本 O(1) の速さで判断できます。もちろん、Hash関数による衝突の可能性があります。最悪の場合、HashSetの内部tableのサイズを倍にする必要があります。それに、要素数が非常に多い領域では、普通のHashSetだと空間効率が悪いと予想できます。ここで、Bloom Filterの登場です。

Bloom Filterは空間効率のいいデータ構造です。なぜなら、利用するメモリー領域を倍にする必要がありません。最初から固定してもいいです。それと、Bloom Filterの要素の単位は bit です。32bitマシンでinteger型だと最大32個の要素が入れます。

Bloom Filterは複数のHash関数を利用します。一つのHash関数だと衝突による実際集合のメンバーではないのにメンバーですという結果になる可能性が高いので、複数Hash関数で可能性を減らします。

サイズは8のBloom Filterを例にします。

| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |

最初すべてのbitが0です。要素 foo を入れます。Hash関数を3つにしましょう。Hash1、Hash2とHash3。3つのHash関数の結果は2, 4と7とします。

| 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 |

foo を入れたBloom Filterです。indexが2、4と7の位置を1にセットします。次は要素 bar を入れます。3つのHash関数の結果は1, 2と3とします。

| 0 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |

同じく、indexが1、2と3の位置にセットします。

では要素をテストしましょう。要素 foo でテストすると、3つのHash関数の結果で、場所2、4と7にすべて1にセットされ、メンバーであるということになります。同じく要素 bar でテストしてもメンバーであることもわかります。

続いてメンバーではない要素をテストします。 要素 aaa にたいして、Hash関数の結果を2, 5, 7とします。index 2と7に1がセットされましたが、5がセットされないです。ゆえ、 aaa がメンバーではありません。要素 bbb にたいして、Hash関数の結果は2、3と4とします。すべての位置に1がセットされ、メンバーであるという結果になりますが、実際はメンバーではありません!

ここでわかったことは、Bloom Filterはメンバーではない要素でもメンバーであるという結果になる可能性があります。これはfalse positiveということです。こういう問題があって、Bloom Filterは使えものにならないと思う人がいるかもしれないが、Bloom Filterはメンバーではない要素をメンバーであるという結果にならない(つまり、メンバーではない結果でしたら絶対メンバーではない)です。まとめてみると、

要素 事実 テスト
foo メンバー メンバー
bar メンバー メンバー
aaa メンバーではない メンバーではない
bbb メンバーではない メンバー

要素 aaa はメンバーではないの結果なので、メンバーではないということが断言できます。逆に、メンバーであるという結果になったら、メンバーではない可能性があります。

こういう特徴を受け、Bloom Filter + DBの使い例を考えみましょう。

DBに100万のレコードがあり、サイズ200万(メモリーやく244KB)のBloom FilterをDBの前にします。毎回レコードを取得するとき、まずBloom Filterを通して、もし存在しないなら、レコードはかならず存在しないので、存在するレコードだけDBと問い合わせします。

こうすることで、Bloom Filterでいらない問い合わせを減らすことができます。Bloom Filterの確率的という特徴もカバーできます。実際、Bloom Filterを利用するシーンはほとんど、レコードは非常に多く、例えばメールボックスのSpam Filter、Bloom Filterなしだと裏側のデータソースへものすごく負荷をかかることが予想できます。

Bloom Filterの特徴を理解できると、以下のような簡単なBloom Filterが書けます。

import java.util.*

interface Hasher<K> {
    fun apply(key: K): Int
}

class SimpleStringHasher(
        private val seed: Int, 
        private val max: Int
) : Hasher<String> {
    override fun apply(key: String): Int {
        return key.fold(seed) { acc, c -> acc * seed + c.toInt() } and (max - 1)
    }
}

class SimpleBloomFilter<K>(
        private val bitSet: BitSet, 
        private val hashers: Collection<Hasher<K>>
) {
    fun mightContains(key: K): Boolean {
        return hashers.all { bitSet.get(it.apply(key)) }
    }

    fun put(key: K) {
        hashers.forEach { bitSet.set(it.apply(key)) }
    }
}

fun main() {
    val size = 2048
    val bloomFilter = SimpleBloomFilter(BitSet(size), listOf(
            SimpleStringHasher(1, size),
            SimpleStringHasher(7, size),
            SimpleStringHasher(23, size)
    ))
    for (i in 1..1000) {
        bloomFilter.put(i.toString())
    }
    println((1..2000).count { bloomFilter.mightContains(it.toString()) })
    // 1024 -> 1582
    // 2048 -> 1000
}

SimpleBloomFilterのソースコードをすこしみてみましょう。mightContainsはすべてのHash関数が計算した位置に1がセットされればtrueを返します。putはすべてのHash関数が計算した位置に1をセットします。

main関数では、サイズ2048のBloom Filterを作ってました。それと1から1000までという要素をBloom Filterに入れます。最後は1から2000までの要素でテストします。サイズは2048だと、最後はきれいに1000とカウントされますが、サイズ1024の場合は1582の結果になります。ぜひ試してください。

最後に、false positiveつまり誤判断を減らすにはサイズどれぐらいにすればいいでしょうか。その質問にたいして、Bloom Filterの論文に答えがありますが、ここで結論を出します。

Pfpをfalse positiveの確率とします。nは入れようとする要素の数です。mはBloom Filterのサイズです。

m = - (n * ln Pfp) / (ln 2) ^ 2

おまけに、Hash関数の数kも

k = (m / n) * ln 2

いかがでしょうか。すこしBloom Filterに理解していましたでしょうか。普段の開発に使わないかもしれないが、こういうものがあると覚えていただければ幸いです。

GitHub Actionsで「さくらのレンタルサーバ」にFTPしようと思ったらドツボにハマって3日3晩寝不足になった話

TL; DR

「国外IPアドレスフィルタ」をOFFにしましょう。

はじめに

みなさんこんにちは。

ユニファ初のアドベントカレンダーの12月22日を担当します。サーバーサイドエンジニアの柿本です。

知り合いに頼まれてホームページを作ることがあります。まあ本職ではないしデザインセンスの問題もあるのですが、それほどのレベルは求められないのでお小遣い稼ぎと思って作ります。
*ちなみにユニファは副業OKです!ユニファの数ある良いところのうちの一つですね。

静的サイトを作る時もソースコードをGitHubで管理しますが、ホスティングサーバーにFTPでアップして、それとは別にGitHubにpushするという二度手間をなんとかしたいと思っておりました。

GitHub Actions があるじゃないか!

GitHub Pagesを使えばpushするだけで反映されますが、サーバーサイドスクリプトが使えません。つまり、問い合わせフォームを置くのが難しくなります。

そこでGitHub Actionsの登場です。 https://github.blog/jp/wp-content/uploads/sites/2/2019/08/ActionsHero.png?w=1200

GitHub ActionsはGitHubのリポジトリにビルトインされているのでお手軽に使えるし、レンタルサーバーにFTPすればPHPも使えます。

GitHub Universe 2019で正式版リリースが発表されたばかりですね。早速使ってみます。

セットアップ

GitHub Actionsでやりたいことはたった一つ

masterブランチにpushされたら「さくらのレンタルサーバ」にFTPする

GitHub Actionsのセットアップの仕方をここにつらつらと書こうと思ったのですが、ネットで検索すればたくさん情報が出てくるので割愛します。

最終的な私の成果物はこちら↓↓↓

github.com

GitHub Actionsがいかに簡単に使えるかはご理解いただけると思います。

長い旅の始まり

FTP-Deploy-Action というFTP関係のものでは比較的人気のあるサードパーティ製のactoinsを使って実行したのですが、待てども待てども終わりません。

f:id:unifa_tech:20191219022740p:plain
20分ほど待ちましたが終わりません

lftpを直に使ってもダメでした。

f:id:unifa_tech:20191219024212p:plain
ログすら見れません 泣

curlでftpを使ってもダメでした。

f:id:unifa_tech:20191219024414p:plain
`curl: (56) response reading failed` になります

SFTPにしてみても、ダメでした。

f:id:unifa_tech:20191219023711p:plain
`Permission denied` になります

その他100通りくらい(は大袈裟ですが 汗)の手段を試しましたが、どれもダメでした!!

自分のmacでubuntu:latestをdockerで走らせて、そこからは問題なくFTPできるのですが、なぜかGitHub Actionsでは動きません。

IP制限でした

気づいてしまえば、「まあそうだよね」て話なのですが、FTPサーバーのIP制限が原因でした。 さくらのレンタルサーバはデフォルトで「国外IPアドレスフィルタ」がONになっています。 help.sakura.ad.jp

GitHubのサーバーが海外であることは想像に難くないですね。このフィルタ機能をOFFにしましょう。

f:id:unifa_tech:20191219030030p:plain
ついに成功!!

学んだこと

1晩頑張ってうまくいかなかったらテクニカルサポートに問い合せしよう。

おそらく一瞬で解決したと思います。

ユニファでは、一緒に「保育をハックする」エンジニアを募集中です!

3日3晩寝不足になっても技術が好きな人を募集中です。(寝るのも大事)

unifa-e.com

Rails + Webpacker + Vue.jsの構成でSystem Testを動かしてみる

こんにちは、Webエンジニアのほんまです。

ユニファのAdvent Calendar 2019も21日目ですね。 昨日は、弊社インフラエンジニアのすずきによるAWS Lambda Provisioned Concurrencyに関するエントリでした。 25日間、連続で記事を書き続けられるほどメンバーが集まったんだなぁと思うと、感慨深いものがあります。

それでは本題に入っていこうと思います。 先日、私が所属するチームで担当したルクミーフォトのリニューアルでの変更点を紹介しました。

tech.unifa-e.com

このエントリ内で「フロントエンドではVue.jsを使用したシングルページアプリケーション(SPA)になっている」と紹介しています。 一方、Rails 5.1からは System Test が導入されており、E2E(End To End)の画面レベルでのテストを容易に実現できるようになっています。 画面内で実行されるJavaScriptにも対応しており、この機能を使った自動テストをやってみたいなーと思っていました。

ここで1つ疑問がありました。 「Vue.jsを使ったSPAのアプリケーションも、RailsのSystem Testでテストできるのだろうか?」ということです。

今後、画面レベルでのテストも自動化していきたいと考えており、この機能がリニューアル後のルクミーフォトでも利用可能なのか、今回試してみようと思います。

続きを読む

AWS Lambda Provisioned Concurrencyをゆるく検証

もういくつ寝るとお正月ございます(適当な挨拶)。

ユニファのインフラ見ているすずきです。

ユニファのアドベントカレンダーの20日目となります。

re:Inventの時差ボケも治り快調です。

そして昨日Reproさんでre:Invent報告会で話してきました。

repro-tech.connpass.com

その後半でAWS Lambda Provisioned Concurrencyを検証した結果を話したのですが、 そのことについてブログにしようと思います。

続きを読む