• Home
  • コーポレートブログ Geniee’s BLOG
コーポレートブログ

Geniee’s BLOG

ジーニーは最先端の広告テクノロジーで
顧客の収益を最大化します。

こんにちは、R&D本部 18卒エンジニアの鈴木です。
経営システム情報開発部でリーダーをしています。
今回はタイトルの通り、リーダー業務について紹介しようと思います。
(経営システム情報開発部 鈴木望 2018年新卒でジーニーに入社。早稲田大学理工学部出身)

Contents

1 普段の業務紹介
2 メンバーとリーダーの違いとは
3 これからリーダーになる人へ

1 普段の業務紹介

開発業務
私の所属する経営情報システム開発部では、主に社内の各プロダクトを統合する業務管理ハブの開発を行っています。それに伴い社内の工数削減につながる業務を担うことが多いです。直近の業務だと、財務会計システムのオンプレミスソフトウェアからクラウドSaaSへの移行などを行っていました。
リーダーとは言っても、開発業務自体はメンバーと特に違いはありません。組織運営などがある分、実際に手を動かす時間は減ります。

プロジェクト管理
開発業務の中には、数日で終わるものから要件定義含めて数年かかるものがあります。
開発業務の箇所で紹介した財務会計システムの移行なども全体で1年ほどかかった大きなものでした。
小さな開発でもスケジュールを決めることは必要ですが、プロジェクトが大きくなればなるほどスケジュールの管理が重要になってきます。
また、プロジェクトの中のタスクを持ちつつも、プロジェクト全体の進捗にも意識を向けてPL(※1)のフォローをする必要があります。そのためには、各メンバーのタスク内容を把握して適切にフォローを行えるようにした上で、全体的にプロジェクトを俯瞰できることも重要になります。

組織運営
組織運営と言っても色々あるとは思いますが、今回は「チーム」運営に絞って話そうと思います。その中でも効果がすぐに期待できる会議運営とそれに付随した当事者意識の促進に関して話そうと思います。

各チームで定例的に開催している会議体はいくつかあると思いますが、会議自体に対しての改善を行っていく姿勢を少なくともリーダーは持つ必要があります。つまり自チームの運営に関して当事者としての意識をより強く持つ必要があるということです。また、チームメンバーに対しても当事者としての意識をより強く持たせるように促す必要があります。

今は在宅勤務をしている方も多いと思いますが、その中で当事者としての意識の有無がより顕著に出てきていると思います。例えば、会議に参加しているが裏で別の作業をしていて発言をしない、あるいは会議には参加しているが終始受け身になっているなどです。
前者に関しての問題点は、会議の進行中に別作業をしているので、会議の進行自体に対して何も意識を向けられないこと、また自分が会議に参加している理由を考えて提案を行うところまで行動にできないことです。後者に関しての問題点は、課題感を正確に把握してフィードバックを行うことができないことです。

会議で当事者意識を持ってもらうために、私は例えば、会議の中で、発言のない人に意見を聞いてみる、あるいはタスクを持ってもらうなどして積極的に関わらざるをえない状況を作っています。また全員でフィードバックの会(※2)を設けてチームメンバーに対してお互いに改善のためのフィードバックを与えるようにしたことで、それぞれがチームメンバーをちゃんと意識して業務を行えるようになったと思います。また、それによって意見を出す敷居が下がり、積極的に話し合いが行えるようになったと感じています。

このように、現状の課題を洗い出し、適切なアクションを考えチームに落とし込むことも業務の一つになると思います。

(※1)プロジェクトリーダーのこと。今回は比較的大きなプロジェクトだったので、プロジェクトに関わる各チームで一人ずつ割り当て、担当する各チームのプロジェクト作業を管理する役割を担ってもらいました。
(※2)お互いのメンバーに関して、改善のためのフィードバックを与える会。開発に関わる業務だけでなく、会議進行やslackでのメッセージの送り方など幅広くフィードバックを与えています。

2 メンバーとリーダーの違いとは

視座と価値の出し方
一般的に言われていることだと思いますが、メンバーとリーダーの違いとして視座の違いがあるかと思います。自分の動きだけではなく、メンバー全体の動き、延いてはチームの動きも考える必要があるからです。

リーダーとして動く中で意識していることは、メンバーとマネージャーの間になぜリーダーというポジションがあるのかということです。また、マネージャーや部長と動きの方向性がずれていないかということです。

メンバー全体の動きという点で一例をあげます。
メンバー全体の開発の進捗を、音頭を取ってスケジュール管理していくというのは、一つの重要な役割になるかと思います。メンバー一人ひとりの開発タスクの確認まで細かいことはマネージャーが行う必要はなくリーダーが行い、まとめたものをマネージャーに報告すればいいからです。マネージャーの資源はより上位の組織運営などに使われるべきです。

次に、チームの動きに関して一例をあげます。
チームの動きを考えていく姿勢は確かに重要なものです。しかし、同じ方向を向いていなければリーダー以下のチームの動きとしてはうまくいっているように見えても、より広いグループや部という視点から見ると混乱を招いているだけです。

このように、リーダーとしての動き方の前提になるのは、マネージャーや部長と同じ方向性を持った上で、メンバーとマネージャーの間のブリッジになることです。そのためにもマネージャーとは密にコミュニケーションをとって業務を行っていくことが重要です。
その上で、「どのように」「どれくらいの速さで」チームを取りまとめて動いていけるか、また、「どれくらい」マネージャーや部長の手からメンバーの細かいタスクへの意識を手放せられるかが、リーダーとしての価値の出し方になると思います。

3 これからリーダーになる人へ

いかがでしたか。
これからリーダーになる方や、リーダーではあるがメンバーとの違いを意識できていない方はこの機会に一度、なぜメンバーとマネージャーの間にリーダーという役職があるのか振り返ってみてはいかがでしょうか。これからの働き方のヒントが浮かび上がってくるのではないでしょうか。

一緒に働く仲間募集中!
【ジーニーのリクルートサイトはこちら】
https://geniee.co.jp/recruit/

こんにちは、R&D本部 20卒エンジニアの高橋です。
今回はタイトルの通り、GENIEEで行われた20卒エンジニア研修について、受講者という視点から振り返ってみたいと思います。

※ GENIEEにおけるエンジニア研修は “bootcamp” と呼ばれており、実施年度と共に表現します。(例 : 2020年度のbootcamp → bootcamp2020)
また、ビジネスを含む新卒全体に対する研修もbootcampの前に別途実施されます。

CONTENTS

1 新卒エンジニア研修「bootcamp」概要
2 研修内容
3 アンケートサマリ〜受講者から見る bootcamp2020〜
・評判のよかった研修について
・フルリモート実施について よかった点、課題点
4 来年度に向けて

1 新卒エンジニア研修「bootcamp」概要

例年、bootcampは1ヶ月半程度の期間で実施されており、GENIEEで使用されている技術を中心に、業務に最低限必要となる技術について学びます。また、具体的な研修内容やスケジュールについては、状況に合わせて毎年調整されています。
bootcamp2020は、個別研修が4月中旬から5月中旬頃、チーム研修が5月下旬から6月上旬頃、というスケジュールで実施されました。
また、新型コロナウイルスの影響が考慮され、bootcamp初のフルリモートでの実施となりました。

2 研修内容

bootcamp2020で実際に行われた主な研修内容について簡単にご紹介していきたいと思います。
【Git研修】
Gitの基礎的な知識と使い方を知り、コード管理の基礎を学びます。
【UNIXコマンド基礎研修】
よく使うUNIXコマンドを知り、状況に応じた使い分け方、調べ方を学びます。
【プロダクトマネジメント研修 】
プロダクト開発の一連の考え方を知り、プロダクトマネージャーの役割について学びます。
【ネットワークと仮想技術研修】
仮想化技術の基礎知識から、代表技術の一つであるDockerの仕組みと使い方について学びます。
また、コンテナ間の接続を通して、ネットワーク構築について学びます。
【MySQL研修】
データベースの基礎からその使い方、注意点など、業務に最低限必要となるデータベースに関する知識を学びます。
また、テーブル設計やレプリケーションなど、データベース設計の基礎知識を学びます。
【CSS研修】
CSSの位置付けとその用途を知り、その調べ方と試し方を学びます。
【LEMP研修】
Webアプリケーションの基礎から構築までを学びます。
※ LEMP; Linux, Engine-X(nginx), MySQL(or MariaDB), PHP(or Python) の頭文字を取ったもの
【アルゴリズムとデータ構造研修】
基本的なアルゴリズムとデータ構造を知り、計算量の感覚を学びます。
【JavaScript研修】
JavaScriptの基礎的な知識から、Next.js, React といった、ライブラリやフレームワークについて学びます。
また、サーバサイドである Node.js や、JavaScriptの拡張言語であるTypeScriptについて学びます。
【Python研修】
Pythonの基本的な構文とライブラリについて学びます。
【デバッグ研修】
デバッグの基本的な考え方や当たりの付け方を知り、デバッグ全体の流れを学びます。
【Go研修】
Go言語の基本的な構文やテストの書き方について学びます。
また、Go言語における非同期処理やプロファイラについても学びます。
【クラウド研修】
クラウドの基礎知識や、GENIEEで活用されているサービスの基本的な使い方について学びます。
【サーバー作成研修】
サーバーの基礎知識から構築までを、実際の作成をしながら学びます。
【開発ルール研修】
GENIEEにおける開発ルールを知り、実際の業務における開発の流れを学びます。
【セキュリティ研修】
セキュリティの基礎と重要性を理解し、開発で注意すべき点について学びます。
【テスト研修】
開発におけるテストの重要性とテストの種類などを知り、目的に応じたテストの仕方を学びます。
【コードレビュー研修】
コードレビューの意義と注意点を理解し、開発におけるレビューの仕方を学びます。
【Git研修(応用編)】
Gitにおけるcommit操作やブランチモデルといった、より高度なGitについての知識を学びます。
【チーム開発研修】
実際にチームに分かれ、チーム開発の流れを開発を通して学びます。

3 受講者から見る bootcamp2020

ここからは、研修後にbootcamp2020運営の方々が取ってくださった20卒エンジニアに対するアンケートの回答を元に、受講者視点から振り返ってみたいと思います。

評判の良かった研修について
各自で3つほど良かったと思う研修を選んでもらい、その理由とともに回答を集めた結果が以下になります。

また、上位3位(3位はタイなので4つ) の講義について、いくつかの詳細な回答とともにご紹介します。
【Go研修】
「Goの使い方から、低レイヤーを扱う処理についても実装する機会があったのが良かったです」
「初めてGoを触ったのですが、Goを好きになれるような研修でした」
【JavaScript研修】
「充実したドキュメントにしたがって進めていくことで、JavaScript, TypeScript, Reactのことなどフロントに関する知識を沢山仕入れることができました」
「モダンなサーバーサイド開発を学べて嬉しかったです。RESTAPI・ページネーション・セキュリティ認証などWeb開発において必要な技術を学ぶことができました」
【ネットワークと仮想技術研修】
「今まで Docker やデータベースに触る機会があまりなかったのですが、研修以降 Docker コンテナを作って作業するのは当たり前になりました」
「ネットワーク的な知識も勉強できたのが良かったです。研修序盤にあったことでその後の研修でも環境構築に利用できました」
【サーバ作成研修】
「ソケットを通してバイト列を送受信する仕組みを作ることで、同時に個人的に学んでいたHTTPの理解が進みました」
「作業時間に余裕があったので、設計にこだわることができました。また、他人の成果物を読んで、他の人がどういうアプローチをしたのか探ることができたのも良かったです」

フルリモート実施について
フルリモートという実施形式に対しての意見についてもご紹介したいと思います。こちらについては、各自良かった点と課題点を自由回答するアンケート形式でした。

リモート研修 良かった点
まずは、良かった点についてです。良かった点については、それぞれ異なる視点の意見が多く見られました。以下に簡単にまとめたものをご紹介します。

【環境要因による効率化】
周りに人が居ないことで、集中力を保つことができたり、自分のペースで自由に進めることができた。
【通勤時間分の有効活用】
通勤時間がないことで、その時間を有効に使うことができた。
【リモート開発の練習】
実際のリモートでの開発や、文字ベースでのコミュニケーションの取り方の練習になった。

リモート研修 課題点
次に、課題点についてです。課題点については、挙がった意見のほとんどがコミュニケーションに関するものでした。以下に簡単にまとめたものをご紹介します。

【コミュニケーションの難航】
同期間のコミュニケーションが取りにくく、関係構築に時間がかかった。
また、細々としたものなど、質問自体がし難いと感じた。

4 来年度に向けて

bootcamp2021は、筆者を含めた20卒エンジニアが主体となって運営をすることになり、実施に向けた準備を着々と進めています。bootcamp2020での良かった点はしっかり踏襲した上で、一部研修での課題難易度調整および説明不足の解消や、フルリモート研修におけるコミュニケーションの更なる促進など、反省点はしっかり活かし、より良い研修を目指していきたいと思います。

一緒に働く仲間募集中!
【ジーニーのリクルートサイトはこちら】
https://geniee.co.jp/recruit/

はじめまして。
昨年10月に入社した新卒エンジニアの鈴木です。現在情報システムグループで社内SEをやっています。
今回は社内SEとしてこの半年間やってきたことを振り返って行こうと思います。
(情報システムチーム 鈴木悠太 2020新卒でジーニーに入社。慶應義塾大学理工学部出身)

Contents

1 社内SEって?
2 直面した問題① 管理すべきものが多い!
3 GASとSlack Incoming Webhookで自動通知飛ばしてみた。
4 直面した問題② タスクがめちゃくちゃ多い!
5 Jira Core導入
6 さいごに

1 社内SEって?

社内SEの主な仕事は以下の3つです。
・社内のIT問合せ対応
・社内の資産管理・調達
・アカウントの管理・設定
社内のITコンシェルジュのような存在をイメージしていただければ分かりやすいかと思います。
一口に「問合せ」と言っても内容が非常に多岐にわたるので最初は仕事を覚えることに必死でした。
具体的にはPCやアダプタの貸出・交換対応やVPN設定、メーリングリストのメンバー管理など、一つひとつ列挙していくとキリがありません。
社内SEは社内全部署がお客様です。円滑なコミュニケーションや他部署への理解が求められます。コミュ障を自負する理系インキャの私でもコミュ力はついてきたかなと思います。
とにかく聞かれたことには適切な応答ができるように日々粛々と業務をこなしています。

2 直面した問題① 管理すべきものが多い!

社内SEが管理するものは非常に多いです。
・PC
・モバイル端末
・周辺機器
・各種アカウント
例えばgithubアカウントの登録やVPN接続などの申請はスプレッドシートで受け付けているのですが、社内SEはこれらのシートを毎日逐一チェックする必要があります。面倒くさがり屋の私としてはこのチェック作業は煩わしい事限り無しでした。

3 GASとSlack Incoming Webhookで自動通知飛ばしてみた。
チェックは人が行うものだからミスや発見遅れが生じる可能性があるよねってことで申請シートに記入されたらslackへ通知が行くような仕組みを作りました。
スプレッドシートとGAS(Google Apps Script)は非常に相性が良いです。シートの情報を自由自在に取得できます。

このようにシートの記入列にユーザ名が記入されたらセルの内容を取得してslackに通知を飛ばしています。(本記事ではサンプルコードを見易くするため、一部マジックナンバーをそのまま記載しています)

Webhook URLはここから取得できます。
以上の工程を経てSlackチャンネルに通知が飛んでくるようになりました

簡単な仕掛けではありますが2つの効果を生み出すことができました。やったぜ。
・毎日シートをチェックする時間をゼロに
・チェック漏れがなくなった
エンジニアブログっぽい感じにしたかったのでコードとか入れて格好つけました。普段はもっと泥臭いことやってます。現在は機器管理台帳と格闘中です。

4 直面した問題② タスクがめちゃくちゃ多い!

これには困りました。
社内SEの仕事に抜け・漏れは許されません。毎日様々な依頼や申請を捌きながら機器管理や入退社の定常業務をこなしていく必要があります。そのためにはタスクを正確に管理し、チームメンバー間でも進捗や課題を共有認識として持っておく必要があります。
スピード感を持ちながらもヒューマンエラーを限りなくゼロにしていく努力が求められるわけです。
現在社内のIT問合せは「情シス依頼」という形でSlackコマンドとGoogleフォームから受け付けています。

この仕組み自体は非常に便利でよくできています。しかしスプレッドシートでのタスク管理に難がありました。
・ひとつの依頼内容を1行で表現しているので横に長く見辛い
・タスクのステータス管理が難しい
・そもそもR&DではタスクをJiraで管理している

5 Jira Core導入

こういったタスク管理状況を改善すべくJira Coreというビジネス・運用チーム向けのタスク管理ツールを導入しました。
Jira Coreの特徴は以下の通り。
・カンバンボードでのタスク管理
・カレンダーによる期日の管理
・詳細画面があるのでタスクの全容が見えやすい
・サマリ・統計レポート機能
・UIがイケてるぜ
イケてます。Dopeです。
どのように情シス依頼タスクをJira Coreに反映させたかをかいつまんで説明していこうと思います。
はじめに浮上した問題はSlackコマンドとGoogleフォームの両方から依頼を受け付けていることでした。依頼があれば直接Jira Coreに反映させようとしたのですが全く違う窓口が2つあったのでこれは困難だということになりました。
こういった経緯で管理用のスプレッドシートに記入された内容を取得してJira Coreに飛ばすことに。

ここでもGASを使ってスプレッドシートに記入された依頼内容が自動的にJira Coreへ送られる仕組みを作りました。便利ですねGAS。スプレッドシートからもJira Core側のタスク状況を参照できるようにリンクも挿入しておきました。
スプレッドシートの内容取得は以下のように最終行から未タスク化依頼を探索して取得しています。

次にJira REST APIを叩きました。


先ほどスプレッドシートから取得した情報をJira Coreのフィールド情報として反映されます。

結果としてタスクの全容が非常に分かりやすくJira Core上で表示されるようになりました。とても分かりやすいですね。細長いスプレッドシートの行を凝視する苦行から解放されたわけです。

Jira Coreとスプレッドシートの連携によってタスクが分かりやすく表示され、ストレス無く管理をしながら仕事が進むようになりました。
社内SEが抱える多種多様なタスクを整理することは非常に大切です。ジーニー社員の皆さんが抱える問題を解消していくためにもミスなく迅速な対応を心がけています。

6 さいごに

ジーニーに入社してからこれまでの半年間はあっという間でした。毎日様々な小さいタスクに対応して、その積み重ねの日々だったと思います。
地味で目立たない仕事も多いですが社員の声をダイレクトに聞くことができるのでやりがいも大きいです。これからもジーニー全社員がストレスなく快適に仕事していけるよう努力していこうと思います。
最後にありきたりなことを言うと入社当初なにもできなかった私を助けてくれた情報システムチームメンバーには感謝しています。先輩からのアドバイスやレビューを通して私もなんとか今に至っています。隣人を大切にするカルチャーがジーニーの良いところです。

一緒に働く仲間募集中!
【ジーニーのリクルートサイトはこちら】
https://geniee.co.jp/recruit/

11期上半期、「GENIEE DSP」は機械学習を活用した自動入札機能の正式提供を開始しました。企画から半年、驚異的なスピードでの機能リリースを成功させたエンジニア二人に、開発の裏話とチームでの取り組みを聞きました。

R&D本部 マネージャー代理 内木 正隆
「大規模なデータを使い様々な開発ができそう」と感じたことが、入社の決め手に。
R&D本部 リーダー 遠藤 悠平
「広告事業はデータ分析を実践的にできそうで面白そうだった」という思いでジーニーへ。

チームのミッションを教えてください。

遠藤  担当プロダクトの指標、広告配信の指標であるCVとCPAを最適化することです。

自動入札開発チームは、上半期MVT(Most Valuable Team)を受賞しました。成果について、改めて説明をお願いします。

内木 機械学習の予測を用いて入札の価格づけを自動的に行う「自動入札機能」をジーニーとして初めて開発しました。今まで人手に頼っていた広告運用作業を部分的に自動化することで、工数削減と広告パフォーマンスの改善を実現できました。
遠藤 私達が入社する前から、DSPにこの機能を組み込むことはジーニーにとって悲願でした。しかしお客様にも納得していただけて、かつ運用チームの要望を実現するのは、技術的に難しいものでした。

かなりスピード感のある開発だったそうですが、なぜ短期間で成果を上げることができたのでしょうか。

内木 自動入札機能自体は企画から半年でリリースできたのですが、周辺の開発も含めると丸3年かかってようやくできたものなんです。第一弾としてCTR(クリック率)予測機能を開発し、その後プロトタイプであるCVR(コンバージョン率)予測機能をリリースしました。
遠藤 リリース後、もっとこういう機能があったらいいのではと二人で話し合い、他機能をいくつか追加した「自動入札」の企画を私が上げたのが4月です。
内木 PMとCTOが開発の大枠の方向性を決め、主に遠藤さんがアイディアの取りまとめや要件定義、スケジュール設定を行っています。
遠藤 チームは各々が専門的な知識を持っているので、企画についてミーティングやテキストで議論し、プロジェクトに関わるチームみんなで形を作っています。配信チームのメンバーには、非常に技術的に難しいところを実現してもらいました。私たちの作ったモデルが実際に機能するかどうかは配信にかかっています。1億、10億といったリクエストを捌けるような配信構成を取り、実装できたのは配信チームのおかげです。

プロジェクトが計画通り進まない時、どのようにして課題を解決し、進めていますか。

内木 プロダクト開発は積み重ねです。使えるものが一度でできることは滅多にありません。予測の精度は赤字に直結します。予測する範囲等のチューニングを繰り返し、チームを跨いだ話し合いと改善を何度も重ねました。計画通り進まないことの方がむしろ多いです。今回企画から半年、初回リリースでパフォーマンスを出せたことの方が驚きです。

数年来開発を積み重ね、一つひとつ技術を積み重ね、メンバーの皆さんが一体となって進めてきたことが、結実したのですね。

遠藤 そうですね。自チームだけでは解決しない課題も多いですし、他チームとのコミュニケーションがずれていてうまくいかない時もあります。実装に至るまでは多くの過程を経るので、周辺の知識や解決策を多く知り、積み上げていくことが成功につながると思います。それを乗り越えてうまくいった時は、やはり嬉しいですね。この時のためにやっていると言っても過言ではないです。

※役職・職務は取材時のものです

大学生活につまずいていた2年生の3月、1本の広告に出会ったことで、道は拓かれました。
文系学部出身の僕が、アドテク企業のジーニーでエンジニアになった今、同じように悩む後輩たちに伝えたいこと。
(R&D本部 東哲志 2020年新卒でジーニーに入社。東京大学経済学部出身)

Contents

・なぜエンジニアになろうと思ったか
・3ヶ月でアプリをリリース
・経済学部での経験もエンジニアの仕事に生きる
・GENIEEでの仕事

なぜエンジニアになろうと思ったか

きっかけはFacebookの広告。「4時間でマリオ風ゲームを作ってみよう」というプログラミング無料体験会の宣伝でした。経済学部に進学が決まり、専門科目の基礎を一通りやったところで、自分にはこの学部は向いていないなと思っていた時で、何かやってみたいと思っていたところだったので、秒で飛びつき、気付いたら申し込み完了していました。大学2年の3月これがエンジニアライフの始まりです!
実際の体験会ではUnityを用いて避けゲー(オブジェクトを左右に移動させて障害物を避けながらゴールを目指すゲーム)を作りました。

画面上を移動させる主人公や障害物、ゴールなどは、Unity上に予め用意されているオブジェクト(球とか立方体)をドラッグ&ドロップで、Scene上に配置するだけでできてしまいます。なので、実際にプログラミングした内容としては、「主人公が一定のスピードでX座標上を移動する。右左のキーの入力を受けてY座標を移動する」という至ってシンプルな内容です。
プログラミングを初めてつまずく最初の難関は、大量の「気にしてはいけない」コードです。Unityで言えば以下のような初期コードが以下のような物で、初めての人にとっては意味不明な概念が大量に出てきます。

(void?,public,class?,MonoBehaviour?)
しかし、そういった細かいことが気にならないたちで、 Start(){} のなかに書いた内容が再生ボタンを押した際に1度だけ実行され、Update(){} のなかに書いた内容が1秒間に60回[^1]処理されるといった説明を自然と受け入れ、オブジェクトが意図通りに動くのを眺めてめっちゃ楽しい!となったわけです。

[^1]: 1秒間に何回処理されるかは実際には端末に依存するが、そんなことは初心者にとってはどうでもいい。

プログラミングを始めて3ヶ月でゲームアプリをリリース

そんな訳で、体験会後に誘われるままGeekSalonというプログラミングスクールで3ヶ月間のUnityコースに取り組むことになりました。目標はなんとアプリリリース!
作ったのはピンポンダッシュ風のアプリです。連打するタイプのゲームで、ロジック部分は簡単でしたが、ゲーム中に出てくる3Dのオブジェクトやキャラを、MagicaVoxelというアプリを用いて一から作ったり、Admobを使ってアプリ内広告を出したりといった点まで作り込みました。
かなり熱中していて大学の授業中でもずーっと作業を進めていたりしていて、メンターの方に色々と手伝ってもらいつつ無事AppleStoreとGooglePlayにリリースすることができました![^2] [^3]
スクールを卒業した後はエンジニアインターンに誘われ、長期インターン[^4]を始めました。3ヶ月間のプログラミング漬け生活は本当に楽しくて、エンジニアは天職だと確信していたので迷いはなく、そのまま大学3年の後期の休学を決めるまで時間はかかりませんでした。

[^2]: アプリ名を「ピンポンダッシュ」で出そうとして、Appleに「反社会的な行為を助長するアプリは受け入れられない」とRejectを食らってしまい、名前とキャラだけ変えてゴーストダッシュという謎のアプリを生み出してしまった。
[^3]: 広告収入より、AppleDeveloppersへの登録料(年間¥12,000)の方が高くついてしまうので、現在はAppStoreには公開されていない。
[^4]: 大学3年の夏からGeekSalonを運営していた株式会社Scovilleという会社で長期インターンをさせてもらっていた。

経済学部の経験もエンジニアの仕事に生きる

元々、経済学部が自分には向いていないと感じていた部分もあり、インターンにのめり込んでるうちにだんだんと大学の方が辛くなってしまっていました。半年単位で休学・復学・休学を繰り返し、辛くて本気で退学も視野に入れていのですが、このまま逃げるように辞めてしまうのもちょっと嫌だなと思うところがあったので、最終的に腹を括って、インターンは継続しつつ復学もしました。[^5]
ただ、卒業を目指すからにはきちんとということで、
・授業はきちんと出席、課題はきちっと提出
・試験勉強もちゃんとして余裕を持って単位をとる
といった基本的なことを目標に、経済学部での勉強をやり切りました。また幸いにして、他学部での講義も単位取得が可能であったため、コンピュータアーキテクチャ、オペレーティングシステム、ネットワーク基礎などの理・工学部の単位も修了しました。大学の最後の一年間は、エンジニアとして文系未経験の弱点をそのままにせず、経済の勉強も思いっきりできたのが良かったです。
文系未経験からエンジニアになれたとしてもその後が大変なイメージがあるかも知れません。実際の情報系出身の人に比べたらコンピュータ系の基礎理解はやっぱり弱くて、そういう点では苦労することがあります。
しかし、仕事をする上ではいろいろな分野のことを知っていることは間違いなく強みになります。実際、エンジニアの仕事はプログラムを書くばかりではなく、事業の方針を見て何を作るかを考えたり、エンジニアの人的リソースの分配などの戦略の部分を決めたりと、ビジネス側と協力する部分も非常に重要です。そういった話し合いや決定の背景を理解するのに、経済学部で学んだ土台がとても生きていると感じます。

[^5]: 親に大学だけは絶対出たほうが良いと言われたのもある。

GENIEEでの仕事

R&D本部 アドプラットフォーム開発部 DOOHグループのフロントチームに所属しています。DOOHというのはDigital Out of Homeの略で、屋外のデジタル広告を指しています。
[YUNIKA VISION (新宿)]

主な業務内容は、このようなサイネージへ広告を配信するためのプラットフォーム開発です。、フロントエンドの開発ではTypeScript+React+Next.jsと、流行りの技術スタックを使っており、どれも初めて触る技術だったのですが、最近ではだいぶ慣れてスムーズに開発を進められるようになってきました。また、チームに囚われず、いろんな技術に挑戦できる環境で、時にはフロントだけでなくバックエンドAPIの開発、配信やレポートのバッチ、インフラ設定なども担当しています。

現在の目標はフロントチームのリーダーになることです。チームでの開発を通してシステム全体の構成や、仕様はだいぶ把握できてきたので、今度はフロントエンドの技術をさらに極めて、技術的にもリードできる頼れるエンジニアになりたいと思います!

一緒に働く仲間募集中!
【ジーニーのリクルートサイトはこちら】
https://geniee.co.jp/recruit/

Date
Author
エンジニアの視点から、様々な技術、サービス開発秘話、イベントをご紹介していきます。 ジーニーエンジニアチーム
Tag

2020年の大ヒットドラマ「半沢直樹」。
ジーニーは、シリーズの幕開けとなる「ロスジェネの逆襲」編の主要な舞台として撮影協力しました。現場の様子や撮影風景をご紹介します。

画像1 こちらは普段のGENIEEラウンジ正面の様子です。

画像2 Spiral社長室設営中…美術さんが魔法をかけている最中です。

画像3 IT企業「東京スパイラル」瀬名洋介社長のデスク。このコートハンガー、実はジーニー代表の工藤が普段ジャケットをかけているものなんです。

画像4 Spiral共同経営者2人のデスク。ジーニーラウンジのインテリアと美術さん持ち込みのインテリアが、全く違和感なく調和しています。

画像5 ストーリーの中で重要な役割を果たす時計とホワイトボード。

画像6 Spiralのポスターは全部で3種類。もちろんオリジナルです。

画像7 大きいモニターに映っているのはオリジナルアニメーションです。モニターの電源はオフ。画面にはそれらしい「紙」が貼ってありました。遠目にはわかりませんね。

#画像8 ちょっとニヒルな笑いが印象的な青いウサギ、その名も「スパイラビット」。公式グッズもTBSショップに売っています。(買いました)

今期、本格始動した「ブランドマネジメント事業」はジーニーの社会的な認知を高めるために始まりました。
今回ご紹介した「半沢直樹」のほか、今年は日本テレビ「35歳の少女」、テレビ朝日「相棒19」、また多数のテレビ等CMにも撮影協力させていただいています。来年もどうぞご注目ください。

1.導入 はじめに
 1.自己紹介、コロナについて
 2.目的
 3 開催方法 使用したツールの紹介
    (ZOOM、コメントスクリーン)
2.コンテンツ紹介/リポート
 1.マネージャーからの挨拶
 2.内定者紹介(学生自己紹介、内定者サマリー)
 3.ゲームの紹介(クイズ、絵しりとり、景品)
 4.オフィスツアー
 5.先輩社員との懇親会
3.まとめ(アンケート結果)

 

▼はじめに

1.自己紹介、新型コロナウイルスについて

こんにちは、ジーニー新卒採用担当の岡本です。

今回は8月7日に行われた21卒内定者懇親会の様子をお届けいたします!

まず私の自己紹介ですが、新卒採用を担当している岡本と申します。

20新卒で今年の4月に入社しておりまして、おうち時間は料理をして過ごすことが多く

最近のマイブームは水ナスの浅漬け作りです!

さて、新卒採用担当となって、初めて採用に関わった内定者の皆さんが一堂に集まるこの内定者懇親会を楽しみにしていました。

がしかし、今年世界中で流行しているコロナウイルスの影響を内定者懇親会も受けました。内定者懇親会の準備を進めていた7月上旬からコロナウイルスの再流行が始まり、1日に200人以上の新規感染者が出ている状況でした。

そのため、ジーニーでは内定者の皆さんの安全を最優先に考え、ジーニー史上初完全オンラインで内定者懇親会を実施することにしました!

オンラインと決まったら前向きに、オンライン上でも楽しんでもらえるようなコンテンツを全力で考えました。

2.内定者懇親会開催の目的

今回は開催目的を以下のように決め、準備を進めました。

1.内定者同士の仲を深めてもらうこと

2.先輩社員との仲を深めてもらうこと

3.ジーニーのことを知ってもらうこと

 

3.導入ツール

今回は配信ツールとしてZoomを使いました。

しかしオンラインってどうしてもコミュニケーションが一方通行になりがちですよね。。それじゃ内定者の皆さんが楽しめないじゃないか!ということで、、、ZoomのみならずComment Screenというツールを導入しました。

Comment Screenはリアルタイムで参加者がコメントをすることができ、ニコ動のようにコメントが流れる、そんなツールです。

テクノロジーの力ってすごいですね!無料のツールなので大人数のZoom飲み会でもお勧めですよ。

実際の様子がこちら

このツールのおかげで、終始和気あいあいとした雰囲気で進められたと思います。

 

▼コンテンツ紹介

1.マネージャーからの挨拶

最初に人事部マネージャーの水野より、このような状況下でも内定者の皆さんを1人もかけることなく、受け入れる準備を進めていることをお話ししました。

コロナにより内定取り消しなどの不安もあるかと思いますが、ジーニーでは責任をもって採用をし、皆さんと一緒に働くことを楽しみにしています!

2.内定者自己紹介

今回はオンラインということもあり、事前に内定者の皆さんにスライドを作ってもらって自己紹介をしてもらいました!皆さん、思った以上にしっかりスライドを作ってくれました。

創意工夫あふれる自己紹介に加え、皆さんがComment Screenで合いの手を入れてくれたのでとても盛り上がりました。


このコロナ自粛期間にハマったことを聞いたところ、どうぶつの森や筋トレを始めた人などが多かったです!

ちなみに今年の内定者のサマリーはこちらです。

今年の特徴として地方の大学出身者が多い点が挙げられます!説明会や面接を全てオンライン化した関係で、地方の皆さんにもジーニーのことを知ってもらう機会を多く持てたのかなあと考えています。僕自身地方出身でもあり、地元が近い内定者の方もいるのでとても嬉しいです!

3.ゲーム

みんな大好きゲームの時間です。今回は、オンラインでも盛り上がる2種類のゲームを用意いたしました!

1つ目は ジーニークイズ!

シンプルでアイスブレイクにはもってこいのコンテンツですよね。今回はジーニーにまつわるクイズを用意し、一番早く答えた方には豪華景品をプレゼント!

こんなクイズを出題しました。

この他に5問ほど出題しました。ちなにこの問題の答えは「プロポーズ」です。

エンジニアがウィキペディアで速攻で調べて回答したり、逆にネットにない情報で苦戦したりと白熱したクイズ大会になりました!ちなみに豪華景品は某有名コーヒーチェーンのギフトカードでした。中には2問正解を出し、二枚獲得したそんなツワモノもいました。

2つ目のゲームはオンライン絵しりとり!

画力とチームワークが試され、お互いのことを知り、仲を深めるのにもってこいのコンテンツです。Zoomのホワイトボード機能を使い、オンライン上で行います。最初の単語が「ジ」でスタートし、最後の文字が「二」で終えることが出来れば大成功です!

こんな感じで作品を完成させてくれました。皆さんわかりますか?

絵しりとりは全4チーム成功という素晴らしい結果でした!また4チーム中3チームが偶然にも「かに」で終わらせていました。「かに」へいかに簡単に繋ぐかがこのゲームの攻略ポイントだったと言えるでしょう。

ちなみに今回は某高級アイスのギフトカードを全員にプレゼントしました。(うらやましい)

4.オンラインオフィスツアー

オフィスの雰囲気を見たい!という内定者の皆さんの声からオンラインの壁を超えて実現したコンテンツです!

ジーニーのオフィスは実はあの絶賛放送中の人気ドラマ「半沢直樹」の撮影にもわれたおしゃれオフィスです。(シリーズ2 1話~4話で使われました)おしゃれなオフィスで働けるだけでモチベーションが1.5倍増しになりますよね。

高性能カメラを使い、私岡本がドラマで使われた箇所を中心に回りました。(ほぼ半沢直樹ロケ地ツアーです)

実際のオフィスの様子がこちらです!弊社ラウンジがドラマに登場するベンチャー企業の社長室として使われていました。

このラウンジは社員が自由に使うことができ、気分を変えて仕事をしたい時や、少し休憩したいときに使います。

またジーニー執務室内には半沢直樹の特大ポスターが貼ってあります!私も毎週見ていたのですが、ドラマを見ながら勝手に親近感をもっています(笑)

オフィスツアーはまるでVRのようだという感想もあり、リアルにオフィスを感じてもらえたようでした。

5.懇親会

最後のコンテンツとして、もう一段階グッと仲を深めてもらうべく懇親の時間を用意しました。

また今回はオンラインでも皆さんに繋がりを感じてもらおうと、オリジナルクッキーとタンブラーを製作し、内定者の皆さんに事前にお送りいたしました。

その写真がこちら

ジーニーのロゴが入ったイケてるデザインに仕上がりました!

そして先輩社員も交えて記念撮影です。

 

2回に分けて懇親会を行いました。

1回目が先輩社員を交えた懇親です。若手を中心に20名ほどの社員が参加しました!

先輩社員も懇親会で内定者の皆さんとお話しできるのを楽しみにしていました。

1人暮らしにお勧めの最寄り駅や業務内容のリアルな話等ざっくばらんに話せたようでした。

2回目は内定者同士の懇親です。人事も先輩も抜きで内定者の皆さんだけでお話ししてもらいました。地元トークに華を咲かせたり、エンジニアは好きな言語の話をしたりなどなどお互いのバックグラウンドなども知る時間になったようでした。

 

▼まとめ

懇親会後、内定者の皆さんにアンケートを実施いたしました。

満足度の結果はこちら

 

なんと5段階(5が満足度高い)の回答で満足度5と4しかない驚異の結果となりました!

平均満足度も4.6とオンラインにも関わらず大変満足してもらえたようで、企画した人事部一同大喜びでした!

自由回答で頂いた感想がこちらです。

「絵しりとりは団結して頑張った感じがあり楽しかった」

「先輩社員の方に一人暮らしについてのアドバイスをいただけた点がよかった」

「ゲームがプレゼント付きなので楽しかった」

「スライドにコメントが流れる機能が良かった」

「エンジニア職とビジネス職が多様な発表をしていて面白かった」

 

内定者同士お互いを知ることができ、仲を深めることができた懇親会となって運営側としても良かったです!

 

今回の懇親会はオンライン開催ということで、目的である内定者同士の仲を深めることができるか少し不安な部分もありました。

しかし、内定者の皆さんが使い慣れていないツールも簡単に使いこなし前向きに会に参加してくれたことが会の成功に繋がったと思います。そのような頼もしい内定者の皆さんと一緒に働けるのが今から楽しみです!

 

ジーニーでは22卒も積極的に新卒採用を進めていきます。みなさんのご応募どしどしお待ちしております! 

 

こちらのリンクからジーニーの採用情報や現場社員インタビュー記事なども読めますのでぜひぜひ読んでみて下さい!

https://geniee.co.jp/recruit/

 

Date
Author
社風やジーニーでの働き方などをご紹介していきます。 ジーニー人事チーム

ClickHouseのテーブル構成を考え直してみた


今回が二度目の投稿になります。ClickHouse Meetup TokyoでジーニーのLT(Lightning Talk)を担当しました、R&D本部 元 基盤技術開発部の犬伏です。(現所属はマーケティングテクノロジー開発部)

記事その1: 「ClickHouse Meetup Tokyo」イベントレポート

記事その2: 「ClickHouse Meetup Tokyo」エンジニアレポート

LT担当者の視点からイベントを振り返りました。

今回の記事:「ClickHouseのテーブル構成を考え直してみた」

Meetupの後、過去に弊社で作成した構成をどのように修正したかを概説します。


目次

  • はじめに
  • 2017年に本ブログで紹介した内容の振り返り
    • 紹介した構造の説明
    • 紹介した構造の問題点
  • 新規に構築した構造の決定過程
    • 複数あり得たPARTITION構造
    • 頻出クエリ抽出
    • 性能評価の結果
    • 性能評価結果についての考察
  • 新規に構築した構造の詳細
  • 新規に構築した構造への移行手順
  • おわりに
  • おまけ
    • text_logについて

はじめに

昨年の ClickHouse Meetup からはだいぶ時間が経ってしまいました。部署異動に伴う業務のキャッチアップ、研修やBootcampなどが重なり、3月中としていた本記事の公開がとても遅れてしまい、申し訳ありませんでした。

前回の記事の公表後、ClickHouseのドキュメントに日本語版が(多くがまだ機械翻訳ではありますが)できたり、Changelogが整備されたり、昨年のMeetup内容にも触れたQiitaに記事が投稿されるなど、じわじわと日本でも広がりを見せているかと思われます。(ほんまか?)

2017年に弊社ブログで紹介した内容の振り返り

紹介した構造の説明

まずは、過去に弊社で作成した構成がどのようなものであったかを振り返ります。

テーブル構造:

  • 1日単位のデータを保持する日毎テーブル ( records_YYYYMMDD = SummingMergeTree(…) ) を作る
  • 1日単位のテーブルをまとめた全期間テーブル ( merge_recordes = Merge(…, ‘^records_[0-9]{8}$’) ) を作る

集計値の更新:

  1. 定期的に一時的な日毎テーブル( tmp_records_YYYYMMDD = SummingMergeTree(…) )を作り、ここへINSERTして新しい日毎テーブルを構築
  2. 新しい日毎テーブルの数値の妥当性を検証し、怪しければ警告を発して中断
  3. RENAME TABLEにより対象の日毎テーブルを差し替える

紹介した構造の問題点

弊社では現在、この構造にレプリケーションを加えた構造のクラスター「V2」と、これにさらにシャーディングを追加してデータ量も増やしたクラスター「V3」の2つのClickHouseクラスターがあります。

V2、V3それぞれの場合について、どのような問題が、どの程度の深刻度で存在していたかを説明します。

  • P1. 全期間テーブルへのクエリは大量の資源を消費し、かつ時間もかかる
    • 全期間テーブルは、V2ではマージテーブル、V3では分散テーブルのマージテーブルという構成であるが、それぞれが性質の異なった問題を生じる。
    • マージテーブル(V2): マージテーブルは内部的にはマッチするテーブル全てに対してクエリを発行する。例えば3年分のデータがDBに入っていれば、内部的には1000を超えるクエリが発行される。マージテーブルへのクエリの結果はこれらすべての内部クエリに対する結果を得るまで返されないので、最悪ケースに引っ張られてトータルでは時間もかかってしまう。特に日付横断的でフルスキャンに近いようなクエリの実行ではメモリ不足に陥ってしまう場合がある。
    • マージテーブル+分散テーブル(V3): マージテーブルの配下に分散テーブルが存在する場合、上記に加えてもっと厄介な問題が発生する。ClickHouseでは分散テーブルへのクエリに対しては他のシャードからデータを取得する必要があるが、マージテーブルによって N 個の内部クエリが発生した後、さらにシャードの数 S に対し、 S-1 個のコネクションが生成され、これと同じ数のクエリが外部シャードに対して発行される。デフォルト値は 1024 ( 根拠はこちら ) なので、年単位のデータを入れていけばすぐに限界が訪れる。また、 ClickHouse v19.7.3.9 時点ではこのようなクエリを投入すると再起動以外では ( KILL QUERY でも ) 停止できないクエリが生じてしまうという問題があった。 ( 注: 実験は行っていないが、この問題はこの修正で解消しているかもしれない。 )
  • P2. 大量の Replicated テーブルは ZooKeeper XID を高速に消費し XID overflow エラーを頻発させる
    • Replicated テーブルは、毎分ZooKeeperに対してリクエストを行うが、リクエストの度に順序一貫性を保つための XID をインクリメントする。これは符号付き32bit整数であるが、これは数千のテーブルに対しては一週間持つか持たないかという程度の猶予であり、また XID overflow となった場合、一時的にではあるが ZooKeeper とのセッションが断絶する。これは次のような問題を生じている
      • 一時期はより重篤な不具合があり、一部のテーブルが readonly になってしまうという状況もあったが、 ClickHouse v19.7.3.9 では改善されている。
      • また DROP TABLE などがアトミックな処理になっておらず、途中のZooKeeperリクエストが失敗すると中途半端な状態で放置される場合があったが、こちらも改善される見込みである。
    • このように、セッション断絶による致命的な不具合は既に修正されているものの、当時のバージョンにおいては INSERT や CREATE TABLE が中途半端に失敗することはあまり好ましい状況とは言えないため、弊社ではやむなく clickhouse-server を定期的に再起動し XID をリセットすることで対処しているが、これもやはり一時的とは言え部分的には可用性・耐障害性が低下しているため、望ましくない。
  • P3. RENAME TABLE の操作が遅延する場合がある
    • 置き換え対象のテーブルに対して実行中のSELECTがあると、ロックが解除されるまで実行されない。そのため、時間のかかるクエリがロックを開放しなければ、データの反映が遅延してしまう状況がある。
    • RENAME TABLE によってデータを更新するのは「V2」のみであるため、この問題については本記事では扱わない。

P1. によるメモリ消費は、仮に1日分のデータを集計するクエリであっても、インデックス ( 詳細はこちら ) が効かないような条件を指定すれば、その列はすべてメモリ上に展開されるため、全期間分の条件列がメモリ上に展開され、大きなメモリ消費に繋がります。 ( これは日付範囲で絞っているつもりのクエリでも、書き方が良くなければ同じ状況が発生します。これについては後述します。 )

単にこの問題に対処するだけであれば、1日分の結果を得る場合に限り、全期間テーブルではなく日毎テーブルを参照すれば良いのですが、期間が1日ではなく1週間や1月といった単位になってしまうと対応できなくなる他 ( 注: merge table function を使うことでこの問題には対処できるが、この機能を使うためには、 readonly=2 以上の権限が必要となる。この権限を持っていると、 max_memory_usage の変更など、管理者側が望まない設定変更も行うことができてしまうため、望ましくない。 ) 、「V3」では時間軸が一次元ではない(後述します)ために、この対策も良い解決策とはなりませんでした。

また P2. によるサーバー再起動は、タイミングを制御して行っているためクラスター全体としての可用性は保っているもの、再起動の時間帯にはそのサーバーで実行中のクエリが失敗してしまうため、クエリ単位では失敗してしまう確率を上げてしまっていました。

そこで、クラスターの安定性を向上させるとともに、あわよくば応答速度も高速化しようという目的で、抜本的にテーブルの構成を変更することとなりました。

新規に構築した構造の決定過程

新規にテーブル構造を設計するにあたり、これまで登場していなかったパーティションという概念が必要になるので、先にこれを説明します。

次に、 Partitioning key をどのように選択したかを順を追って説明します。Partitioning key は通常データの取り回し方から決定されるもので、ClickHouseでは月単位でのパーティショニングが推奨されていると言えるでしょう (注: 明言されているドキュメントがあったか定かではないが、想定する最大のパーティション数が1000-10000とされているほか、多くの例示において toYYYYMM が用いられている) 。

しかし私たちは、とある理由でパフォーマンス上の問題も考慮する必要がありました。この経緯や詳細については「複数あり得たPARTITION構造」で述べます。

次に私たちは、最終的なテーブル構造を選定するため、実際によく叩かれているクエリを集め、それらの典型的な集計期間を定めて、それぞれの構造に対してパフォーマンス計測を行いました。この手順の詳細及び結果、考察については「頻出クエリ抽出」及び「性能評価の結果」、「性能評価結果についての考察」で述べます。

複数あり得たPARTITION構造

私たちのClickHouseテーブルには、キーとなる日時 DateTime 型のカラムが2つあります。やや込み入った内容になるので、一旦進みたい方は、「統一時刻」と「現地時刻」という意味の違う2種類の日付が必要になった、とご理解ください。

★☆★ 込み入った説明ここから ★☆★

前提知識:

  1. ClickHouseの DateTime 型は時刻をUNIXタイムスタンプで保持する。
  2. UNIXタイムスタンプにはタイムゾーン情報は含まれない。UNIXタイムスタンプとタイムゾーンの組み合わせで、はじめて「ある国・地域のタイムゾーンでの時刻」を表現できる。

一つは正当なUNIXタイムスタンプを記録するカラムで、従ってすべての行が同じタイムゾーンで記録されるものです ( 説明のため「統一時刻」と呼びます ) 。

もう一つがトリッキーで、海外での配信成果の集計をその国・地域でのタイムゾーンに沿って行うために、「タイムゾーンをUTCとして取得すると現地での時刻を得られるUNIXタイムスタンプ」を記録するカラムです ( 説明のため「現地時刻」と呼びます ) 。例えば日本時間 (JST, UTC+9) であれば、通常のUNIXタイムスタンプに9時間分、 32400 (秒) を加えたものを記録します。こうしておくことで、UTCとして取得したときに、9時間進んだ時刻を取得できます。 ( 注: 本当は行ごとにタイムゾーン情報を保持できれば最も望ましかったのですが、そういった機能はなかった上、たとえあったとしても「現地時刻」の取得で計算が必要になるため、「統一時刻」と同等のクエリ性能を発揮しにくいため、 DateTime 型で2種類の時刻を保持するのが最も高速に要求を実現できると判断され、このような構成となりました。 )

★☆★ 込み入った説明ここまで ★☆★

私たちは日本時間での時間 (hour) 単位で集計してデータベースへの投入を行っていたため、再集計のことだけを考えれば、日本時間での日単位でパーティショニングしてしまえばよいのですが、その後に行われるバッチ類のSELECTクエリでは各国・地域のタイムゾーンでの日単位で行っているものも多く、これらについては日本時間での日単位でのパーティショニングのみであると、パーティションの中からは該当するものを発見できなくなり、すべてのパーティションのインデックスを参照しに行くことになってしまいます。

このオーバーヘッドがどの程度かを見積もるため、私たちは日本時間の日単位のみのパーティショニングと、日本時間の日単位と現地時間の日単位の組による二次元 (注: 見た目上は二次元ではあるものの、日本時間と現地時間の差分は一定の範囲に限定されているので、パーティション数の増え方は線形オーダーです。) のパーティショニングの両方を試そうと考えました。

頻出クエリ抽出

さて、パフォーマンステストのためには妥当なベンチマークが必要です。しかしこのベンチマークの用意は当初想定した以上に厄介なものでした。

クエリをいくつか用意すれば良い、と漠然と考えていましたが、実際にどういうクエリが速いと嬉しいかとなると、単純に全件取ってくるとか、特定の1列だけを取得してくるとか、集約単位 (group by) の細かさはどうするかとか、自由度が高すぎてわからなくなってしまいました。

そこで、実際に使われているクエリを16個程度 (注: 数は勘で決めた) 集め、それらの結果がどの程度改善するかを見ることでベンチマークとする、という方針を立て、クエリを集め始めました。このテーブルを使っているチームに「こういうクエリを使っているとか、こういうクエリが早くなると嬉しいとか、教えてください」と呼びかけ、協力を求めました。

しかしここでも課題が生じました。エンジニアに質問するとたいていバッチ処理のためのクエリが返ってきますが、実際に飛んできているクエリを見てみると、ビジネス側の社員も社内のRedashを経由してそれなりの数のクエリを投げていることがわかりました。こういったクエリもできるだけベンチマークに組み込みたくなりました。

そして最終的には、クエリログ (注: 公式ドキュメント: https://clickhouse.tech/docs/en/operations/system-tables/query_log/) からよく飛んできている、あるいは資源を多く消費しているクエリを集めることにしました。

しかし、クエリを集めると言っても、通常テンプレートとなるクエリが存在し、実際に投入されるクエリはその中の文字列や IN 節の括弧内、数値など、様々な部分が変化します。この部分を同じに扱ってやらないと同じクエリとみなすことができず、回数のカウントが漏れてしまいます。そこで私たちは次のようなクエリを作り、これを調査しました。

SELECT
    replaceRegexpAll(
        replaceRegexpAll(
            replaceRegexpAll(
                replaceRegexpAll(
                    replaceRegexpAll(query, '(--.*?)?\n', ''),  -- コメント・改行除去
                    '\\s+', ' '),                               -- 連続する空白文字を同一視
                '\\s*\\d+\\s*', '0'),                           -- 数を同一視
            '0(,0)*', ' 0 '),                                   -- 数・数列を同一視
        '\'.*?\'', '\'\'') AS query_template,                   -- 文字列を同一視
    any(query) as query_sample,
    count(*) AS execution_count
FROM
    system.query_log
WHERE
    is_initial_query                -- ユーザーが直接投入したクエリを対象とする
    AND
    NOT match(query, '.*INSERT.*')  -- INSERTクエリは除外する (INSERT ... SELECT は使っていない)
GROUP BY
    query_template
ORDER BY
    execution_count DESC
LIMIT 64
FORMAT Vertical

replaceRegexpAll によって、実際に実行されたクエリをそのテンプレートのようなものに変換して、この数を数えることで実行回数を調べました。

実際にはこのあと、バッチかヒトかを推測するためや使われなくなった古いクエリを除外するためにクエリの実行周期を調べたり、実行時間やメモリ消費量などの指標も加えて取得するようにするなども行いましたが、割愛します。

性能評価の結果

性能評価にあたって、テーブル構造以外に一つ注視すべき設定項目がありました。分散テーブルのマージテーブルに対しては ClickHouse v19.7.3.9 時点では誤った結果が返却されるため使えなかった、 distributed_aggregation_memory_efficient (注: 公式ドキュメント: https://clickhouse.tech/docs/en/sql-reference/statements/select/group-by/#select-group-by-in-external-memory) という設定項目です。(長いので、以下 DAME と略します。)

分散テーブルのマージテーブルという構成をやめ、パーティションを使うことにした結果、この設定項目も使えるようになったので、これを有効化した場合にそれぞれの構造でどの程度パフォーマンスが向上するかも加えて評価することにしました。

よって性能評価は以下の5種類の比較となりました。

  1. base(旧構成)
  2. single(新構成、日本時間のみのパーティショニング)
  3. single_DAME(新構成、日本時間のみのパーティショニング + DAME )
  4. twin(新構成、二次元のパーティショニング)
  5. twin_DAME(新構成、二次元のパーティショニング + DAME )

また、集めたクエリは以下の13個となりました。

  • No.3(頻度3位、現地時間で細かい単位で集約する、大量の行を返す重いクエリ)
  • No.5(頻度5位、現地時間で細かい単位で集約するが、結果行数は少ないクエリ)
  • No.7(頻度7位、現地時間で細かい単位で集約する、大量の行を返す重いクエリ)
  • No.8(頻度8位、日本時間で「直近24時間」を粗い単位で集約する軽いはずのクエリ)
  • No.9(頻度9位、日本時間で「直近28日間」を粗い単位で集約するちょい重いクエリ)
  • No.100(人間がたまに叩く、重いが速いと嬉しいクエリその0)
  • No.110(人間がたまに叩く、重いが速いと嬉しいクエリその1)
  • No.19(頻度19位、日本時間で、決められた4時間の間隔のデータを無差別に合計する監視用クエリ)
    • このクエリでは、旧構造についてのみ、日本時間での1日分のデータのみを集約していることを利用して、全期間テーブルではなくその日の日毎テーブルを直接参照するという最適化を行っている。
    • またこのクエリでは PREWHERE での最適化が行われておらず、インデックスで範囲を絞れないようになっていたため、実質的に意味のないベンチマークとなってしまった。
    • しかしながら、No.919にて最適化されたものの結果も得ているのでこちらを信用すれば良い。(呼び出し箇所は後で書き換えました。)
  • No.29(頻度29位、日本時間で、1ヶ月間のデータを荒い単位で集約するクエリ)
  • No.903(頻度3位を筆者が最適化したもの)
  • No.905(頻度5位を筆者が最適化したもの)
  • No.907(頻度7位を筆者が最適化したもの)
  • No.919(頻度19位を筆者が最適化したもの)

ベンチマークの計測方法は次のとおりです:

  • それぞれのテーブル構造に対して、若いナンバーから順に一つずつ実行していきます。これを9回繰り返します。
  • 他のクエリと重複する範囲をSELECTするなどによって有利不利が生じないよう、最初の2回の結果は捨てます。(注: この間に、データがOSによってキャッシュされることを期待します。)
  • その後の7回から、「最速値」及び「期待される値」を計算します。「期待される値」には、7回のうち遅い2回を除いた5回の平均を使います。(注: クラスターそれぞれの計算資源やネットワークなどを再現することが難しかったため、本番環境上でベンチマークを実行した都合上、運悪く他の重いクエリと同時に動作した場合に不利になってしまうのを回避しようという意図です。)
  • 実行エラー(すべてメモリ制限超過と確認済み)になった実行の実行時間及びメモリ消費量は、例外処理が面倒だったのでそれぞれ 999,999 ms , 999,999,999,999 Byte に設定しました。
  • パフォーマンス計測の際には、クラスター上でのクエリの実行についてのみ興味があるため、 FORMAT Null を指定することで結果を捨てています。
  • 結果の集計では、実行時間やメモリ消費量の統計をあとから楽に計算できるように、それぞれのクエリの先頭に定型コメントを付与した上で、あとからまとめてクエリログを参照しました。このようにしたことで、集計の計算も含めてクエリログに対するクエリ内で完結させることができました。

ベンチマーク結果は次のとおりです:

  • 左側は、大雑把に緑色が最良、薄いグレーが次点(1.2倍以内)、赤が最悪、白はその他です。中央のグラフは左側の対数プロット、右側のグラフは最良を1としたときの相対値です。
  • 上から、最速実行時間、期待実行時間、最小メモリ消費量、期待メモリ消費量です。

テーブル構造のSELECT性能比較

性能評価結果についての考察

実行速度上は、全体的に twin_DAME が多くの最善を叩き出しており、最速を逃した6つのうち4つはDAMEでないほうに僅差で負けているのみで、残った7番は全体的に僅差であり、19番はもともと勝ち目のない比較を行っているため考慮する必要がありません。

次にメモリ消費ですが、横並びから19番、905番、919番にてやや twin 系が多くのメモリを消費する傾向が見て取れます。

このことから、テーブル構造としては二次元の構造を採用することとしました。

ここからは蛇足ですが、No.3の旧構造では結局全ての実行がメモリエラーで落ちてしまいました。一応本番で何度かは成功しているはずのクエリなので、定常的なメモリ負荷があったのかもしれません。

またNo.3からNo.9までは無視できない確率で(少なくとも9回に1回以上は)メモリ不足で失敗してしまうことがありましたが、クエリを書き直すことである程度症状は緩和できています。(それでもNo.905では8倍近く時間を使ってしまっていますが…)

新規に構築した構造の詳細

ということで、旧来の「分散テーブルのマージテーブル」という構造は、「パーティション付きのReplicatedSummingMergeTree」という構造に置き換えられることになりました。

DDL上は、日毎テーブルの名前から日付部分を取り去って全期間テーブルのように改め、以下の Partitioning key の指定を加えるのみです。しかし、私たちの場合は後述する移行手順のために、直接古いマージテーブルを上書きすることはせず、別に新しい名前で新しいテーブルを作り、それのみを含むマージテーブルを新しく作って古いマージテーブルと差し替える ( RENAME TABLE ) という方法を取りました。

この部分をマージテーブルではなくビューテーブルを使うことも検討しましたが、 PREWHERE が使えなくなるなどマージテーブルの場合と比べて互換性を維持できなかったために棄却されました。

結局、マージテーブルの部分がパーティションに変化しただけであるため、基本的には旧来の全期間テーブル向けにかかれているクエリであれば書き換えなく動作します。(書き換えることでさらに速くなる可能性はありますが…)

CREATE TABLE our_database.shard_reports ON CLUSTER our_cluster
ENGINE = ReplicatedSummingMergeTree(...)
-- ここから
PARTITION BY (
    toYYYYMMDD(現地時刻みたいな日時カラム, 'UTC'),
    toYYYYMMDD(普通の日時カラム, 'Asia/Tokyo')
)
-- ここまで
ORDER BY ...

新規に構築した構造への移行手順

ディスク容量に余裕があったので、新しい構造でテーブルを作り、そこへINSERTの速度をプロダクトに影響が出ない範囲に抑えつつデータを流し込むことで基本的には対応できました。

しかし、ある程度時間のたった範囲のデータについては既に確定しているので特に考慮することなく入れ直すだけで済みますが、直近のデータは常に古いテーブルのほうへ流入してくるので対応にやや苦慮しました。

また、参照しているクエリをすべて把握しているわけでもなかったため、ユーザーからは同じテーブル名のデータが差し替わることが期待されました。

そのため、一度古いテーブルへのデータの流入を止め、直近分のデータを新しいテーブルに入れてから、互換性のためにマージテーブルを差し替え、その後新しいテーブルに向けてデータの流入を再開する必要がありました。この手順を時系列で表すと次のようになります。

概略 詳細・遷移条件
A: 確認用の数値を取得 D, G あたりで確認するため、過去分の各列の合計等を取得

(直近分は B のあとに行うが、過去分は分量が多く実行に時間がかかってしまうので、先に行っておくとよい)

B: Flinkを停止 Flinkを停止し、ClickHouseへのデータ流入を止める。

【ClickHouseへの流入が止まったら goto C】

C: バッチを停止 本当は長時間かかる可能性があるクエリは全部止めたいところ、 E 向けの布石
D: 直近データ移行 すべてのreplicaについてreplicationが完了していることを確認したのち、直近分のデータを旧テーブルから新テーブルにINSERT

【数値の一致を見たら goto E】

E: 全期間テーブル置き換え RENAME TABLE によって行う

【入れ替え完了が確認されたら goto F】

F: Flinkを再開 新しいテーブルの方にINSERTするように変更するのを忘れない(忘れるとだいぶ面倒なことに)
G: みまもる 大丈夫そうならCで止めたバッチを戻す

様子がおかしかったら臨機応変に対応

テーブル構造更新の手順

この手順により、実際には無事「臨機応変に頑張る」ことなく移行を完了することができました。

おわりに

今回は、2017年に弊社ブログで紹介した内容を振り返り、そこで紹介されていたClickHouseのテーブルについて構造上の課題を指摘し、これをより良い構造で再構築した過程を、順を追って説明しました。

特にメモリ使用量やクエリの応答速度で悩まれている方は、パーティションを用いた構造に修正されることをおすすめします。

もし「次回」があれば、ClickHouseクラスターのバージョンアップ( v19.7.3.9 to v19.16.14.65)についての記事になるかと思います。

おまけ

text_log について

text_log は ClickHouse v19.14 以降で使える機能で、 /var/log/clickhouse-server/clickhouse-server.log に出ていたClickHouseのログをデータベース上のテーブルにも保存することができます。

特に、「何時頃のこういうエラーログ」という条件さえわかっていればすばやくログにアクセスできる、どういうエラーがどういうタイミングで発生しているのかの調査など、テーブルとして存在していることによる恩恵は大きいと感じました。

ただし、 system.query_log と同様にストレージ容量を食いつぶす可能性もあるので、パーティショニングや容量の監視は常に行う必要があります。

公式ドキュメント: https://clickhouse.tech/docs/en/operations/system-tables/text_log/

設定の書き方等参考PR: https://github.com/ClickHouse/ClickHouse/pull/6164/files

Date
Author
エンジニアの視点から、様々な技術、サービス開発秘話、イベントをご紹介していきます。 ジーニーエンジニアチーム
Tag

ジーニーは、2020シーズンから東京ヴェルディクラブとマーケティングパートナーシップ契約を結びました。アドテクノロジー、マーケティングテクノロジー分野で事業を拡大するジーニーが東京ヴェルディクラブとパートナー契約を結んだ経緯、今後の展望について、両社代表を始めとする参加者同士が熱く語り合いました。

対談参加者
【一般社団法人東京ヴェルディクラブ】
・eスポーツ選手 YUKI様
・フットサル選手 山田ラファエルユウゴ様
・理事長 森本 譲二様
【株式会社ジーニー】
・代表取締役社長 工藤智昭
・マーケティングテクノロジー事業本部コマーシャル営業部部長 石井賢

――今回、パートナーシップを結ぶに至った経緯をお聞かせいただけますか。

ジーニー代表取締役社長・工藤智昭(以下、工藤):子どもの頃からのサッカーファンで、特にヴェルディは一番好きなチームだったので、今回のご縁をとても嬉しく思います。今回ヴェルディさんのスポンサーをさせていただこうと思った理由が2つあります。まず我々はBtoBの企業様相手に取引をしており、もっともっと我々の事業を広く知ってもらいたいという思いを持っています。まずは、スポーツ界を牽引する東京ヴェルディのファンの方々、スポーツのファンの方々を起点にしたいと思ったからです。2つ目の理由は社会貢献、ビジネスで収益を作るだけではなく、スポーツなどの支援していきたいと考えました。

ジーニー 代表取締役社長 工藤智昭

世界で共に戦うパートナーに
一般社団法人東京ヴェルディクラブ理事長・森本 譲二氏(以下、森本氏):ヴェルディファミリー、サッカーチームも含めたヴェルディ全体でジーニーさんと共に世界に向けて進んでいきたいと思います。
ヴェルディは、25年前のJリーグ創成期にはカズ(三浦知良)、ラモス(瑠偉)北澤(豪)を擁し、日本代表イコールヴェルディという輝かしい時代がありましたが、2010年頃に厳しい経営難に陥りました。そのタイミングで現社長の羽生英之を迎えました。当時Jリーグの事務局長だった彼が東京ヴェルディの社長に就任し、今日に至っています。

一般社団法人東京ヴェルディクラブ 理事長 森本 譲二様

工藤:2010年がヴェルディ様の節目だったのですね。当社も、2010年創業です。日本発の世界的なテクノロジー企業を作ろうという思いで起業しました。

森本氏:ご縁を感じますね。その後10年の間、東京ヴェルディは踊り場に留まり、J2におります。私が経営に参画させていただいた2018年、J1参入プレーオフ決定戦でジュビロ磐田と対戦したのですが、惜しくも負けてしまいました。

この頃から、東京ヴェルディはサッカー以外でも日本でチャレンジしています。今、野球チーム、バスケットボールチーム、ハンドボールチーム、陸上競技チームなど延べ18のクラブチームがあります。ヴェルディの名の下に様々なチームが集まり、この2年で、東京から世界を目指していくんだ、というチームの集合体に成長してきました。

工藤:我々も世界を目指しています。設立3年目から海外展開を開始し、現在ではシンガポール、ベトナム、タイ、インドネシアのアジア4カ国に進出しています。マーケティング・業績の改善をするソフトウェアを提供し、アジア中の企業の成長に貢献しています。

森本氏:創業間もない頃から世界を目指して拠点を構えていらっしゃるのは、とても勉強になります。ジャンル・活躍の場所を広げる過程で我々が痛感したのは、良くも悪くも我々はスポーツ村、スポーツビジネスの中で、国内で仲間を集めてきたということです。
eスポーツチーム中心に、世界にプロモーションするにはどうしてもIT、マーケティングテクノロジーが不可欠です。しかしなかなか有効な手立てが見当たりませんでした。そんな時、ジーニーさんの「世界に、日本から本気で挑戦する」というメッセージに強く感銘を受けました。

スポーツ×ビジネス×ITの融合で世界を目指す

森本氏:スポーツやテクノロジーは、これからボーダレスに、世界を超えて挑戦していかなければならない。世界に挑んでいくヴェルディのパートナーに、パートナー以上の存在にぜひなっていただきたい、そう思い、まずフットサルチーム、eスポーツチームのビジネスパートナーになっていただきたいとお願いに上がりました。

工藤:私はこの10年、高い志を持って会社を経営する、そしてお客様や会社で働く社員を含めた周りの人を全部幸せにしたいと考え、挑戦し続けてきました。ビジネスとのバランスを取りながら、人々の幸せをつくり、我が社が世の中から必要とされる存在であり続けたい。高い志をもつヴェルディ様とも、共に成長し、チャレンジをできるパートナーでありたいと思っています。

森本氏:ありがとうございます。日本のスポーツ界は、スポンサーシップは契約することがゴールになってしまうことも多いんですが、私たちは深いコミュニケーション、パートナーシップを築いていける関係でありたいと思っています。
我々がいかにジーニーさんに対してお役に立てるのか。ジーニーさんがヴェルディと組むことで、宣伝効果もそうですし、既に拠点を持っておられるアジアから世界に打って出るひとつの起爆剤として、お役に立てればと思っております。

ビジネスとスポーツの知見を共有し、両社のパワーを拡大につなげる

ーー具体的に、どのような取り組みをしていくのでしょうか。

ジーニー・石井賢(以下、石井):既に、マーケティング事業領域では取り組みが進みつつあります。ファン拡大、認知向上などのマーケティング施策に加えて、我々がサービス開発・販売しているCRMなどの顧客管理ツールを活用していただき、ヴェルディファンの方との関係強化の一助となればと思っています。メルマガ配信、ヴェルディさんが力を入れているスクール事業での生徒様の管理などが挙げられます。
単にツールを使うだけでなく、ビジネスを拡大していくための包括的な取り組みとして知見をお互いに共有し、両社のパワーを拡大していければと思っています。
ヴェルディさんはサッカーのイメージが強いですが、18ものクラブチームをお持ちですし、今回協業するeスポーツやフットサルはこれからどんどん伸びていくと思いますので、協力させていただければと思っております。

ジーニー マーケティングテクノロジー事業本部コマーシャル営業部部長 石井賢

ーー今日はeスポーツで活躍されている山田選手とフットサルのYUKI選手にもお越しいただいています。今後ジーニーとパートナーとして関わっていくにあたり、今後の目標やジーニーに期待することを教えてください。

フットサル・山田ラファエルユウゴ選手:私は選手として活動しながら、フットサルスクールでユースチームの子どもたちへの指導もしています。チーム全体のレベルアップが図れるようにしっかり頑張りますので、ご支援いただければと思います。

フットサル 山田ラファエルユウゴ選手

eスポーツ・YUKI選手:少し自己紹介をさせていただきますと、普段は半導体の専門商社でビジネスマンとして働いていまして、競技者としても活動しています。その中で今、YouTubeチャンネルに力を入れております。
現在ゲームのプレイ動画を主にYouTubeに上げているのですが、チャンネルの登録者のほとんどが実際のプレイヤーです。今後、ファン層拡大のためにビジネスマンの方や上の世代の方々をどうやって取り込んでいくかが私自身の課題のひとつです。
ゲームに限らず、普段の仕事や競技前後の様子も含め、魅力を発進していきたいと思っており、SNSマーケティングの知見、ジーニーさんのツールなどを最大限活用させていただきたいです。いちビジネスマンとしても今回のパートナーシップは非常に興味があるところです。

eスポーツ YUKI選手

キーワードは「多様性」。世界を広げることでお互いに強くなれる

ーー最後に、工藤さん、森本さんから今回のパートナーシップについての展望をお聞かせください。

工藤:我々の持っている技術・ノウハウを最大限に活かし東京ヴェルディさんに貢献したいです。またインドネシア、ベトナムをはじめとしたアジアでも大きなビジネスをしていますので、東京ヴェルディさんのファンをアジア中で増やしていきたいと思っています。

森本様:キーワードは多様性だと思います。ジーニーさんとご縁をいただいてYUKI選手、山田選手も共に語り合う。このことは、ヴェルディにとってものすごくいいことだと思います。ビジネス界と関わることで我々も刺激を受けてよりよく成長できますし、サッカーだけではなく、様々な種目が加わることでヴェルディは強くなると思っています。
ジーニーさんが持つ、テクノロジーの技術をぜひ我々も使わせていただき、両社の資産を築いていきたい。ジーニーさんが持っておられる高い志を我々も共に目指し、世界と戦っていくだけの目標と文化に並ばせていただきたいと思っています。

工藤:力強いお言葉をありがとうございます。これから、ぜひ共に頑張っていきましょう。

こんにちは、R&D本部基盤技術開発部の内木です。

私は現在ジーニーで主にGenieeDSPの入札部分のロジック実装などを行っています。今回はDSPの入札ロジックに欠かせないCTR(Click Through Rate)予測について、またそれを支えるデータ分析・処理環境についてご紹介します。

CTR予測とは

DSPは広告主に広告を出す機会を提供するプラットフォームです。広告主は費用を使って様々なメディアに広告を出すことで、商品購入など何らかの効果を目指します。弊社を含め多くのDSP事業者では以下で決まるCTRを予測することがDSPにとって重要な機能の一つとなっています。

CTR <- (広告が表示されて、クリックされた回数) / (広告が表示された回数)

CTRを予測するには、どのメディアに出すかはもちろんですが、メディアの中での広告の位置、出される広告コンテンツの内容、広告を見ているユーザーの特性・OS情報など、多様な情報を考慮する必要があります。より良いCTR予測を行うには日々変わる広告パフォーマンスの傾向を考慮した予測モデルで日々改善・修正していく必要があります。
ジーニーの広告表示回数は約800億/月の規模です。この規模のログを様々な軸でデータの傾向を頻繁に確認するために、弊社ではデータ処理・分析環境を整備しています。

データ処理・分析環境

ジーニーではCTR予測モデルをはじめとして、大規模なデータ処理・分析の一部をGCP上で行っています。GCPでデータを処理する大きな理由の一つとして、BigQueryが自由に使えることが挙げられます。

BigQueryでは数TBのデータでも基本的な集計処理なら早くて数秒、ウインドウ関数やJavascriptで記述できるUDFをはじめとした負荷のかかるデータ処理でも多くの場合数分もすれば結果が返ってきます。本番環境でこのような負荷のかかる処理が本当に必要かは慎重に考える必要がありますが、こういった環境はアドホックな処理・調査の効率や頻度などデータ全体に対して大きく影響してきます。

CTR予測モデル作成をBigQuery上で完結させることはできませんが、機械学習には欠かせないデータの前処理・調査で使われています。今のアーキテクチャでは前処理されたデータはGCS(Google Cloud Storage)を通してGCE(Google Compute Engine)に送られ、予測モデルの学習を経て作成されたモデルは再度GCSを通して広告の配信サーバーに渡され、日々新しい予測モデルが更新されていきます。

終わりに

今回はCTRについての説明やBigQueryをはじめとしたデータ処理基盤など、弊社のデータ分析の一例を説明させていただきました。
ジーニーではデータ基盤の運用方法から機械学習などを利用したプロダクトのロジック改善方法に到るまで、データ活用をより盛んにしていくため開発環境をまだまだ改善していきたいと考えています。今回ご紹介した内容に興味を持っていただければ幸いです。

Date
Author
エンジニアの視点から、様々な技術、サービス開発秘話、イベントをご紹介していきます。 ジーニーエンジニアチーム
Tag
Back to top