TECH PLAY

エス・エム・エス

エス・エム・エス の技術ブログ

271

介護事業者向け経営支援サービス「カイポケ」のエンジニアリングマネージャー、酒井( @_atsushisakai )です。現在、私たちは「カイポケ」のフルリニューアルプロジェクトに着手しています。今日は、このプロジェクトをご紹介します。また、プロジェクトで扱っている課題や私たちが日々取り組んでいる技術的なチャレンジについて、これからさまざまな観点の記事を deep dive してお届けしていきます。そのあたりについても簡単にご紹介します。 「カイポケ」フルリニューアルプロジェクトとは? 私たちは、介護事業所の運営に不可欠な「保険請求」の機能をはじめ、事業所経営を総合的に支援するための多くの機能を提供する業界特化型 SaaS である「カイポケ」を開発・運用しています。 「カイポケ」はサービスローンチから17年が経過し、システムの安定性・開発効率の観点で多くの課題を抱えているのが現状です。同時に、高齢化社会が進む背景もあり介護業界からのニーズは年々高まっています。そこで、今後の更なる継続的な事業成長を見越して、アーキテクチャから全てを見直すような開発プロジェクトを2021年から始動してきました。 今回、このプロジェクトについて、扱っている技術的な課題や将来の展望など、詳しい取り組み内容についてまとめたサイトを新しく立ち上げました。情報量はとても多いのですが、非常にチャレンジングで難易度が高いが故のプロジェクトの面白さが伝わる内容になっていると思います。是非一度ご覧になっていただき、興味を持っていただけると嬉しいです。 careers.bm-sms.co.jp プロジェクトの裏側を順次公開中 今後、多くの難易度の高い技術的な課題をどう解決していこうとしているかであったり、多くの人が関わる複雑で規模の大きなプロジェクトをどのように進めているかというプロセスの工夫など、さまざまな観点でフルリニューアルプロジェクトの裏側をご紹介していく予定です。 既にフロントエンドの技術選定については以下の記事でご紹介しています。 tech.bm-sms.co.jp 来週には @okazu_dm さんによる SREチームの取り組みについての記事が公開されます。さらに、今後、以下のようなテーマでコンテンツを順次公開していく予定です。(内容は変更の可能性もあるのでご了承ください。) 極めて複雑な介護費用請求金額の計算について 大規模なプロジェクトを運営するための開発プロセスについて カイポケの新しいアーキテクチャについて プロジェクトを支えるメンバーを積極採用中 最後になりますが、このフルリニューアルプロジェクトでは、まだまだ多くのエンジニアの方の協力を必要としています。先ほどご紹介したプロジェクト専用サイト内に 募集中のポジション を記載していますので、興味のある方はぜひご覧ください!また、エンジニアだけでなく、 プロダクトマネージャー ・ UI/UXデザイナー などプロジェクトに携わるポジションを全方位的に募集しています。 カジュアル面談もやっておりますので「選考に進む気持ちはまだないけどプロジェクトについては面白そうなので聞いてみたい」という方でも構いません。ご興味があれば是非お気軽にお声がけください!
はじめに エス・エム・エス BPR推進部カスタマーデータGrで、「 ナース人材バンク 」等のキャリア事業を中心に、社内のデータ活用の推進、データ基盤の開発を担当しています、橘と申します。 私達カスタマーデータGrでは、Google CloudのBigQueryを中心としたデータ基盤を構築しており、社員がデータを利用して意思決定をする業務をサポートする役割を担っています。本記事ではそのデータ基盤についてご紹介したいと思います。 カスタマーデータGrのデータ基盤について 私達が運用するデータ基盤のデータ連携アーキテクチャについて、簡単にまとめると以下の図のようになります。 エス・エム・エスのキャリア事業で活用したいデータは、AWS上に構築されたシステム、Salesforce、GoogleドライブやGoogleスプレッドシート、その他SaaS等、様々な場所に散らばっております。これらをGoogle Cloud上のストレージに収集し、利用目的に応じたデータストアへ連携し、業務への活用をする、といった構成となっています。 データ基盤のワークフローエンジン これらのデータを連携する基盤として、GCP上でApache Airflowをマネージドで提供するサービス、Cloud Composerを利用しています。Airflowでは次の図のようなワークフローをPythonで定義して運用することができます。各処理を動かすタスクを整理し、それを有向非巡回グラフで依存関係を定義し、前のデータのロードが終わったら、そのデータを加工するタスクを動かす、といったことが実現できます。 Airflowには、BigQueryやCloud Storage等のGoogle Cloud上の各サービスへ接続する機能が元々あります。その他の外部サービスへ接続する共通処理であったり、プログラムでビジネスロジックを記述する必要がある処理に関しては、Pythonを書いてこのAirflow上で動かすことができます。 3年ほど前にこのAirflowを本番環境で導入し、今では100件以上のワークフローを動かす基盤として運用しています。 BigQueryを中心としたETL基盤 BigQueryは、とにかく大量のデータを蓄積することが可能なので、Google Cloudに連携したデータのほとんどをここにロードしています。BigQueryに蓄積したデータを加工して、集計・分析用のデータマートを作成する、ELT(Extract, Load, Transform)の構成を取っています。データの加工には、SQLやJavaScript(BigQuery SQLのUDFとして利用)を主な手段として採用しています。BigQuery上のSQLであれば当然リソースはBigQueryのリソースを利用できるので、大量データを効率良く処理ができます。導入前はオンプレミス環境に構築したETLツールを用いて、サーバのリソースを割いてデータ加工の処理をしていましたが、BigQueryの導入によって、数億件のデータでも安定して高速で処理ができるようになりました。 BigQuery上のデータは、マーケターやエンジニア等のデータ利用者がSQLを実行して参照したり、Looker Studio、Googleスプレッドシート等を用いたレポートを作成して閲覧できるようにしています。 また、BigQueryのデータは集計データを蓄積するのみにとどまりません。後述するGoogle Cloud上に構築した業務Webアプリケーションが利用するCloud SQLやFirestoreに連携したり、BigQueryのリソースを用いて大量データを集計した結果を、AWSやSalesforce等の社内の別システムへの連携をしたりと、大量データを処理する業務システムとしての役割も担っています。 Looker StudioやGoogleスプレッドシートを用いたデータの活用 弊社ではエンジニア組織のみならず、全社的にグループウェアとしてGoogle Workspaceを利用しています。そのため、GoogleスプレッドシートやLooker StudioといったGoogleのサービスを用いることで、Googleアカウントとデータの閲覧権限があれば、URL一つで誰もが必要なデータにアクセスできる環境を目指しています。 Looker Studioでは、次の図のような図表やフィルタを簡単に作成して共有ができます。日々の業務で観測したいデータをまとめたダッシュボードを作成して、事業の意思決定に役立てています。参照するデータは前述のBigQuery上のデータを用いています。BigQueryやSQLの知識がなくても、GUI上で見たい指標を選んでグラフを作成したり、簡単な数式も組んだりすることができるので、データエンジニアに依存することなく、データの利用者がダッシュボードを編集できるようになりました。 Googleスプレッドシートにもまた、BigQueryに接続できるコネクタがあります。Looker Studioのようなダッシュボードではなく、慣れ親しんだ表計算を用いて集計業務をしたいケースに応えるために利用しています。従来はExcel上でマクロを組んで、複数のデータソースをまとめて処理していた業務を、BigQueryとスプレッドシートに置き換えることで、ある程度の業務の自動化が可能となりました。 また、集計や分析に必要なデータは、データ基盤に蓄積したデータのみではありません。集計したい指標の軸となる独自のマスタデータを管理して、それをBigQueryに連携するインターフェースとしてもGoogleスプレッドシートを利用しています。Googleスプレッドシートはデータ利用の入出力のインターフェースとして欠かせないものとなっています。 Cloud SQLやFirestoreを用いた業務アプリケーション BigQueryは大量データを処理したり、集計したデータを一括で閲覧したりするのに向いている一方で、RDBMSのように業務アプリケーションで用いるデータベースとしては、パフォーマンスやコストの観点で非常に不向きです。Google Cloud上にためたデータをWebアプリケーション上で活用したいといったケースにも対応する場合は、Cloud SQLやFirestoreといった別のデータストアサービスも利用しています。 Cloud SQLは、RDBMSを利用できるマネージドサービスで、蓄積したデータをWebアプリケーション上で閲覧したり編集したりするために用いています。Webアプリケーションは同じくGoogle Cloud上のApp Engineで構築しています。BigQueryは、Cloud SQLへの接続設定をすることで、BigQuery上のデータとCloud SQL上のデータをSQLで結合して利用することもできるので非常に使い勝手が良いです。 Firestoreは、構成が複雑な構造化データをシステム化するために用いたNoSQLのデータストアです。RDBMSで表現がしにくい構造のデータ、項目数が多かったりばらつきがあったりして定義が難しいデータ等を用いたアプリケーション用に利用しています。 今後の課題 さて、今回ご紹介したデータ基盤ですが、今はデータの活用を推進していくフェーズとなっております。ビジネス上の課題を解決するためにデータ基盤を利用したり、○○のデータを集計したいといった話は多数いただきます。一方でデータの利用用途が部署ごとにバラバラで、結局は集計したいデータを一元で管理できていなかったり、あるいは既存のETLツールで組んだデータ連携処理+Excel上での集計処理から抜け出すことができなかったりと課題は多数あります。 データを活用する基盤がある今、更なる活用に向けて、私達データエンジニアも事業の理解と、データ活用の推進により力を入れていく必要があると感じています。 おわりに 本記事ではエス・エム・エスのキャリア事業におけるデータ基盤についての事例をご紹介しました。 私達のデータ基盤は、ご紹介した通りGoogle Cloudの技術をフルに活用しています。パブリッククラウドの知識やデータサイエンスの知識も勿論求められますが、ある程度の基盤が開発され、実際のデータの活用を推進していくフェーズの今、データを利用する人たちの課題を理解する力、そしてどういったデータを用いれば課題解決に繋がるのかを提案できる力も必要となっています。 エス・エム・エスは新しいメンバーを募集しています。 私達のチームは、筆者のようなデータエンジニアから、元は基幹アプリケーションの開発に携わっていたエンジニア、データやドメイン知識が豊富なプロダクトオーナーなど、様々なスキルセットを持ったメンバーで構成されています。データ活用を推進するBPR推進部として一丸となって日々の業務の課題の理解と解決に取り組んでいます。 弊社の事業に携わってみたい方、興味のある方は、ぜひこちらのページものぞいてみてください。 エス・エム・エス - エンジニア採用情報
「エス・エム・エス社員に訊いてみた」第三弾として、介護事業者向け経営支援サービス「カイポケ」の事業責任者である園田さんへのインタビュー記事をお届けします。 事業責任者の役割 本日はよろしくお願いします。はじめに、園田さんの担っている「事業責任者」という役割がどんな役割なのかを教えてください。 カイポケに関わる組織のうち、プロダクトマネジメントとエンジニアリングの部署は田辺さん( @sunaot )が担当で、それ以外のセールス、マーケティング、カスタマーサクセス、事業開発といった部署を僕が担当しています。事業責任者が担っているのは、 「顧客に提供する価値を最大化するために必要なことすべて」 です。事業の方針を立てて、必要になるリソースを調達して、プロダクトを市場に投下・フィットさせていくというのが一つの流れです。代表的には、調査をして事業計画を立てたり、人を採用したり、予算を取ってきたり、ステークホルダーと対話したりといった事柄となります。 取り組む事柄には、連続的なものと非連続的なものがあります。事業上のボトルネックを特定して解消し、また次にボトルネックになったところを特定して解消し……というのを繰り返すのは連続的な部分です。また、個々の担当者がそれぞれの担当分野を見ているのに対して、横断的に見ることのできる自分が事業全体を統合するというのも役割になります。一方で、非連続なことを考える場面というのもあります。ミッションやビジョンの定義といったタイムラインの長いものを考えたり、事業を再定義するといったことも、僕が担うことの多い仕事です。 カイポケはSaaSのソフトウェアだけでなく、金融事業やICT機器のレンタル事業、M&A仲介事業といった、ソフトウェアと非ソフトウェアの事業を統合的に提供しているので、サービス全体のポートフォリオマネジメントも重要です。新規のサービスを作ることよりも、「何かの機能を無くす、事業を撤退する」という意思決定をする方が、担当者としては難しい場合がありますが、プロダクト全体の観点をもって、一定のユーザーがいる中で「削ぎ落す」という意思決定をする事は自身にしかできないので、とても大事だと思っています。 これまでのキャリア ありがとうございます。事業責任者になるまではどのようにキャリアを歩んできたのですか? 一貫して、「必要なことは全部やる」という仕事の仕方をしています。新卒で小さなベンチャー企業に就職して、2年目くらいには一つの事業の責任者という立場になったので、色々やりました。電子書籍サービスの会社だったので、配信サイトのUI/UXの改善をやったり、コンテンツを増やすために版権を取りにいく動きをしたり、市場を広げるために営業に行ったりと、その時々にボトルネックになっている部分を解消しにいく動きをしていました。その後の転職先でも同じような動きをしていましたし、エス・エム・エスのグループ会社であるエムスリーキャリアやMIMSに在籍していたときもそうです。その後いちど起業をしていた時期もありました。 カイポケに関わるようになってから なるほど、エス・エム・エスには起業を経験されたあとで戻ってきたのですよね。戻ってきてからはどのようなことをして今に至っているのですか? カイポケには10程度のプロダクトラインが有るのですが、それぞれのLTV(ライフタイムバリュー)を把握している人はいなくて、リソース投下の優先順位も曖昧な状態でした。そこで、まず各部署からデータを取得して、各プロダクトのLTVを分析しました。 各部署の長にヒアリングをしていく中で、サイロ化していて、事業全体を統合して把握している人が存在しないことを課題に感じました。そのせいなのか、データが各グループ内に閉じていてデータの形態もそれぞれ独自(Excelがあったり、CSVファイルがあったり、あるいは時系列データで持っているところがある一方でスナップショット的なデータしかないところもあったり)で、横串で分析をする事が極めて困難になっていたのです。 こういった部分の改善と並行して、ボトルネックを探索的にみていって特定するという活動をしました。ちなみに、最近ではデータの民主化がだいぶ進んできています。データの民主化については以下の記事も見てみてください。 tech.bm-sms.co.jp その後、分析対象を広げていって、事業をこうしたら良いのでは?という提案を行い、最終的には、事業の責任者になりました。 PythonやSQLを使ったデータ分析の話 データの話が出ましたが、園田さんはPythonやSQLを使ってデータ分析などをバリバリできる人だと聞きました。どういうきっかけで身に付けたんですか? 僕は、別にデータ分析を専門としているわけではないのですが、事業のために必要なことをやるというスタンスで仕事をしていく中で、やはりデータ分析という所作は必要で、以前からよく行っていました。昔はExcelとVBAでやっていたのですが、大量データを扱うことが多かったので、SQLで分析するようになりました。Pythonで前処理を行うようになったのも似たような理由です。 カイポケの事業運営の特徴 カイポケの事業運営についてお話を伺います。データの話も出ていましたが、カイポケの事業運営の特徴を教えてください。 可能な限り「勘」で動くことを避けて、調査/分析→仮説構築→仮説検証→施策実行という流れにそって運営しています。そして、分析のアプローチの一つとして、現場に身を投じて感覚的に理解することと、データ分析の2つを重視しています。 前提として、カイポケが対象とする医療介護業界は、エンタメやBtoCのようなトレンドに左右される事業という性質は薄く、一定程度はStable(安定的)なマーケットです。プロダクトを作る側が何か新機軸を打ち出すということよりも、顧客のニーズを捉えてそこにソリューションで応えていくことの方が重要だと考えています。さらに、カイポケは既に多くの顧客に利用していただいていて、データも社内に相当程度蓄積されています。そのため、意思決定をするときにデータを活用するということがフィットしていると思います。また、マーケットの性格上、中小の法人の顧客が大多数を占めていて、特定の顧客に売上の多くを依存しているわけではないということも、データ分析の重みが増す要因です。 なるほど、プロダクト開発においてデータ分析を用いるというのは近年では当たり前になってきている印象もありますが、カイポケは特にそれがフィットしているという側面があるのですね。ここまでの話では机上の分析を重んじている印象がありますが、一方で事業所訪問などもよくしていますよね。 はい、プロダクトの使われる現場に行くことから得られる肌感覚も大切にしています。介護事業所などを訪問することはやはり大事で、僕自身も率先して行きますし、メンバーにも推奨しています。カイポケに関わるメンバーは若い人が多いので、介護事業所に縁のある人が少なく、実際にプロダクトが使われる場面のイメージを持ちづらいんです。いくら分析をしても、イメージが湧かないところに対して考えることというのは的を射ていないものになりがちです。たとえば、障害児通所支援事業所を訪れてみると、カイポケを使ってもらう端末としてタブレットはあまりフィットしないということがわかります。介護事業所と違ってそこにいるのは子どもなので、職員のタブレットで遊びたがってしまうんですよね。こういったことは現場に行くとわかるので、現場に行くことは問題解決のためには非常に有益なんです。また、現場に行くとやっぱりがんばろうという気持ちにもなれて、仕事にも熱がこもってきます。営業の方であれば当然現場には行くんですが、プロダクトマネージャーやエンジニアの方というのは普段の仕事の中では現場に行く機会は意図して行わないと少ないので、例えば「事業所に訪問したい!」とチャットで投げれば営業側ですぐに設定するようにするなど、各人が現場を訪問するハードルを極力下げるようにして、どんどんメンバーには訪問してもらえるようにしています。 カイポケのプロダクト開発の特徴 プロダクト開発という観点ではカイポケにはどんな特徴があるでしょうか? 先ほど言ったことと関連するのですが、SaaSらしいプロダクト開発をしているということは言えます。「SaaSらしい」というのは、Slerのように、特定の顧客のためにカスタマイズを頑張るのではなく、顧客全体にとってのValueを考え、最大公約数的にプロダクトを作っていくということです。そのようにして作ったプロダクトの仕様から外れる部分については、顧客の業務を可能な限りシステムに寄せてもらうという思想ですね。これが有効なのは、カイポケが対象としているマーケットが、中小の顧客が圧倒的多数を占めるマーケットだからです。もちろん顧客の声というのは重要なインプットではあるのですが、営業が大口の顧客と約束してきてしまったから特殊な機能を作らないといけない、みたいなことは避けています。特定の顧客のための例外処理的なものを実装するとシステムとしても複雑になってしまいますし、多数の顧客にとって使わない機能が存在していると、プロダクトの完成度はむしろ落ちると思っています。 また、カイポケで一番大事にしているのは顧客への提供価値を最大化することで、システム開発ですべて解決しようとはしていません。顧客の課題を解決するのにシステムでの対応が一番的確な場合はもちろんシステム開発をしますが、たとえばサポートでの支援で解決するというのも選択肢のひとつとして扱っています。システムという狭義のプロダクトに限らず、セールスやカスタマーサクセス、サポートや外部の協力会社といったエコシステム全体を「プロダクト」として捉えています。これはテクノロジーで全てをスマートに解決してやろうという志向の人からすると「え〜」と思うような側面かもしれませんが、介護や医療の現場のリアルで複雑な課題に対して、「現実解で解く」という面白さもあります。システム開発ではなく問題の解決が私たちの商売というわけです。 プロダクト開発部門との関係 エンジニアとしても、言われたものをただ作るというのは避けたいし、作るなら本当に顧客にとって必要なものを作りたいので、事業全体としてそういう方針だとやりやすいですね。園田さんと、プロダクトマネージャーやエンジニアの部門との関係はどういうふうになっているのですか? プロダクトマネージャーはプロダクトに責任を負います。何かを決めるという時に、エンジニアリングリーダーシップ、プロダクトリーダーシップ、ビジネスリーダーシップという3つに分けて考えるというのを田辺さんが社内で提唱しているのですが、僕はこのうちのビジネスリーダーシップのみを権限として持つようにしています。ですから、最終的にプロダクトのHOWの部分(どうするのか、どう作るのか)については、事業責任者である僕にも「こうしろ」という権限はありません。ビジネスの観点から、こういう背景があるとか、こういう未来予測になるとか、収益上こういう形にしたいとか、「こうするのがいいと思う」という意見はもちろん言います。しかし、最終的にそれをプロダクトとしてどのように表現するかは、プロダクトリーダーシップの担い手であるプロダクトマネージャーが責任を負っていますし、技術的にどのように実現するかはエンジニアリングリーダーシップを担うエンジニアが責任を負います。ここは完全に権限が委譲されている状態です。たとえば、プロダクトマネージャーの決めたロードマップに対して僕が何かを差し込むというのはできないようになっています。 なぜそうしているかというと、何かを最終的に決める人というのを1人に決めておくことによって色々なことがスムーズにいくと考えているからです。これはプロダクト開発部門に対してだけでなく、セールスやマーケティングといった事業部門のメンバーに対してもそうで、僕は「ここはあなたに100%委譲したので僕は決められません、あなたが決めてください」とよく言っています。これは元々の僕のマネジメントスタイルで、そこと先ほどの田辺さんの言っている3つのリーダーシップの話はマッチしていたので今の組織運営はそういう形になっています。 エンジニアへのメッセージ 最後に、エンジニアに対して伝えたいことはありますか? 理想としては、エンジニアの方にも、顧客に対して価値をどう提供するかについてよりよい方法を提案してもらえると嬉しいです。もちろん最終的には実装する、ものづくりをするというのがエンジニアの職責だとは思うのですが、プロダクトマネージャーがプロダクトマネジメントトライアングルの全てを担うことはかなり難しいので、「いやそこはこう作った方が拡張性があるよ」や「そこは実装しなくていいんじゃないか」といった議論をエンジニアからもしてもらえるといいなと思います。そのためにはやはり、できれば顧客を理解してほしいなと思っています。 もちろん、エンジニアとしては、一番興味がある、やりがいを感じるのはそういう部分じゃなくて技術の部分だ、という人もいると思うので、みんながみんなそうなるとは思っていないのですが、もし顧客を理解してものづくりをするという部分にも興味を持っているエンジニアがいれば、とてもハッピーですし、そういう人にとってやりやすい環境を作る努力は惜しみません。社内でのコミュニケーションの場も用意しますし、顧客と話をする機会もアレンジします。事業所訪問のハードルを下げるというのもこういう意図でやっていることです。ですから、こういう動き方に興味がある人がいたら一緒に働けると嬉しいです。 ありがとうございました! (終)
介護事業者向け経営支援サービス「カイポケ」の開発をしている伊藤です。2019年4月に入社し、一貫してプロダクト開発部の介護レセチームでエンジニアとして活動しています。 本稿では私の所属する介護レセチームで実施している、システムの改善活動について気をつけていることや気がついたことをまとめます。 介護レセチームとは 介護レセチームは、介護事業者向け経営支援サービス「カイポケ」の介護領域の開発を担当するチームです。「カイポケを使った介護業務をノンストレスで行えるようにすることで利用者に向きあうゆとりを増やすこと」をチームのミッションに掲げ、日々カイポケの機能開発などを実施しています。 カイポケでは介護事業所の経営を支援するための様々な機能を提供していますが、コア機能の1つとして、介護事業所が収入を得るために必要となる請求業務の支援機能があります (請求業務はレセプト業務とも呼ばれ、介護レセチームの名前の由来にもなっています)。この請求業務の支援機能は、2000年から施行されている介護保険制度のルールに依存する機能です。この介護保険制度は数年ごとに「介護報酬改定」と呼ばれる見直しが実施され、様々な改正が行われます。介護報酬改定についての詳細はこちらの過去のブログをご参照ください。 tech.bm-sms.co.jp 介護報酬改定の改定内容をカイポケへ素早く反映し、ユーザへ価値を届ける必要があるため、介護レセチームでは普段からリファクタリングなどのシステム改善活動に取り組んでいます。 介護レセチームでのシステムの改善活動について システムの改善を行うにあたって、まずは一般的によいとされている知識をインプットすることから始めるのがよいと考えています。システム改善の理想的なゴールを思い描きゴールに向かって効率的に進むために、まずは知識や方法論の理解が必要で、これは大前提になると思います。余談ですが、介護レセチームは技術知識のインプットに意欲的なメンバーが多く、毎週実施しているふりかえりの中で、だいたい誰かしらが読み終えた技術書の紹介をしてくれます。 介護レセチームでは、新しい機能開発を実施する場合でもすぐに改修を実装するのではなく、リファクタリングから始めます。修正対象のモジュールにテストがない場合はまずテストコードを書き、リファクタリング対象の振る舞いを壊さないよう保護したうえでリファクタリングを実施しています。 リファクタリングを実施する上での方法論の詳細については、本稿での説明は控えますが以下の書籍が参考になると思います。 www.seshop.com このように特別なことをしているわけではないのですが、介護レセチームはこれらの改善活動を継続的に実施しています。 システムの継続的な改善活動 システムの改善は長丁場の作業になりがちです。秘孔のような改善ポイントを見つけて、そこを修正するだけで一発で理想に到達できれば理想的なのですが、なかなかそうはいきません。特にカイポケでは、前述のとおり介護報酬改定に起因する開発を実施することがあり、スケジュールの締め切りが事実上決まっていることが度々あるので、毎回改善活動を理想的なゴールまで持っていけるわけではありません。 しかし、一発で理想にたどり着けないからといって何も改善しなければ、文字通り何も改善することはできません。一発で理想にたどり着けないのならば、今回の対応で最低限どこまで改善するのかチームで認識を合わせ、少しずつ理想に近づける作業を継続的に続ける必要があります。 繰り返しになりますが、システムの改善を実施する上では効率的に改善を実施するための知識や方法論を知っておくことは大前提です (もしそれらが足りていないようなら、知識や方法論をインプットすることから始めるのがよいと思います)。しかし、継続的に改善のサイクルを回していくためには知識や方法論を知っているだけでは不十分です。システムの改善活動は、ユーザからは目に見える改善につながらない場合も多くあります。そのため、継続的に取り組むためには改善の必要性について関係者(開発チームのメンバーやプロダクトマネージャー、QAチームのメンバーなど)の間で共通認識を作り、皆の目線をあわせた上で、粘り強く継続的に取り組むことが大切です。 無力感に気づき、無力感と向きあう ある程度の規模のサービスに関わっていると、大量の課題に優先順位をつけて順番に対応していくことが多いと思いますが、介護レセチームでも各課題を評価した上で優先度順に対応を行っています。 しかし、ある時一歩下がって課題全体の消化状況を見てみると、消化できているのは緊急性が高い課題ばかりになっていることに気がつきました。反面、やればすぐに対応できる課題や重要だが緊急性の高くない課題が積み上がっている状態になっていました。 振り返ってみると、前述の通りカイポケではスケジュールの締め切りが事実上決まっていることが度々あるため、緊急性の高い課題を締め切りに間に合わせることにフォーカスすることが多く、やればすぐに対応できる課題や重要だが緊急性の高くない課題に手をつけにくい雰囲気になってしまっていたように思います。 結果として、「自分たちはこんな簡単なことにも着手できないのか……」、「サービスの将来にとって重要な課題に着手できない……」といった、もやもやとした無力感がチームに溜まった状態になっていました。 介護レセチームでは、開発メンバーとプロダクトマネージャーで課題の扱い方について対話を重ねる中で、自分たちが無力感を感じていることに気づきました。無力感に気づいてから、開発メンバーとプロダクトマネージャーの間で、「無力感を放っておくとメンバーの日々の活動に対するモチベーション維持やキャリア形成(技術/業務スキルの取得や、技術/業務スキルを活かした業務経験を得ることなど)にネガティブな影響があり、各メンバーに介護レセチームで長く生き生きと活躍してもらうことが難しくなるのでは?」という懸念について認識をすり合わせることができました。 現在では以下のように課題を扱っています。 課題の優先度を決める際には以下のように評価を行う 緊急性の高い課題の緊急度合いにも濃淡があるので、対応しなかった場合、サービスにどの程度影響があるのか個別に評価する 課題の緊急性だけでなくサービスにとっての将来的な重要性や、対応した際にチームが得られる学びや経験の多さなども評価する やればすぐに対応できる課題については、新しいメンバーが加入した時の最初のタスクにしたり、手が空いたときに着手する課題としてチームで認識を共有しておくことで消化しやすくする 無力感を認識することで緊急性以外の観点から課題を扱えるようになり、少しずつこれまで積極的に実施できていなかったサービスのデリバリー方法の改善などの改善施策にも取り組めるようになってきています。 活動をチームで粘り強く継続的に続けるには、チームメンバーが消耗せず、生き生きと活躍できる状態に近づけることも必要だと思います。そのために、無力感のような自分たちの負の感情と向きあい、どのようにそれを扱っていくのか明確にすることも重要だと感じています。 小さい歩みを続けるために ここまでシステムの改善活動は継続性が大切だと繰り返してきましたが、現実問題として、スケジュールの期限がある中である課題の対応中に思わぬ問題が見つかったり、他の緊急性の高い対応依頼が飛び込んできたりすることもあるわけで、地道な活動を日々継続的に続けるのが苦しいときもあります。 私は苦しい状況になればなるほど、関係者の間で活動の必要性についての共通認識ができていて目線が揃っているかが試されると考えています。目線の揃ったチームは苦しい状況でも皆で励ましあいながら前に進むことができ、改善がうまくいったときには皆で互いに感謝しあい、喜びあうことができます。そしてまた次の改善活動に取り組むことができるのです。 介護レセチームの改善活動はまだまだ道半ばです。私達は一緒に喜びを分かちあい、励ましあいながら改善を進めてくれる仲間を探しています。関心を持ってくださった方は、ぜひ末尾のカジュアル面談のリンクから話を聞きにきてください。 最後に、私が尊敬する元プロ野球選手のイチローさんの言葉で本稿を終わろうと思います。 小さなことでも満足感、満足することっていうのはすごく大事なことだと思うんですよね。だから、僕は今日のこの瞬間とても満足ですし、それは味わうとまた次へのやる気、モチベーションが生まれてくると僕はこれまでの経験上信じているので。これからもそうでありたいと思っています。 (出典: 国際情勢研究会『イチロー 会見全文』 /「 第1章 メジャー通算3000本安打達成会見(全文)」p.19)
こんにちは、エス・エム・エスのフロントエンドエンジニアの城内です。 前職では、ヘルスケア系のスタートアップでソフトウェアエンジニアをしていましたが、2022年8月にエス・エム・エスへ入社し、介護事業者向けの経営支援サービス「カイポケ」の改善をするチームに所属しています。 カイポケの改善を進める開発チームでは、この度フロントエンド専任チームを立ち上げました。この記事ではフロントエンドチーム立ち上げの背景や、チームの立ち上げから進めてきた技術選定について書きたいと思います。 カイポケ改善プロジェクト 介護事業者向けの経営支援サービス「カイポケ」は、4万を超える事業所で導入されている SaaS 型のサービスです。介護事業には様々なサービスの種類(ex. 居宅介護支援、通所介護支援、訪問介護支援、etc…)があり、カイポケはそれぞれのサービス種類に対応した約40のサービス・機能を提供しています。カイポケは15年以上の歴史の中で、各サービス種類への対応や法改正に合わせてシステムを拡張してきました。カイポケはモノリシックなアプリケーションとして構築されてきたので、拡張に次ぐ拡張で様々な機能が複雑に絡み合う大きなプロダクトになっています。 高齢化が進む日本社会において、介護領域では制度改正や改正に伴う現場対応など、目まぐるしい変化が起こり続けています。システムとしても、こういった介護業界の変化や数年に一度行われる法改正へ対応していくことが求められます。今のカイポケは現在の介護事業を支えるプロダクトになっていますが、長期的なタイムスパンでこれらの法改正などの要望に応えていくことを考えた場合に、より良いシステムのアーキテクチャにできないかと改善プロジェクトのチームで検討を重ねてきました。そういった背景から、システムを改修する際の修正範囲の局所化と新しいサービス種類への対応などといった拡張性の担保、生産性向上のための並列性の確保を目的にマイクロサービスアーキテクチャへ移行を進める改善プロジェクトが始まりました。 カイポケの規模では一度に全てのサービスをマイクロサービスに移行するのは現実的でないため、今回の改善プロジェクトでは特定のサービス種類に対象を絞って少しずつリリースをして、小さく早くユーザーからのフィードバックを回して確実に価値を積み上げていく方針を取ることにしました。 フロントエンドチームの発足 当初想定していた改善プロジェクトの開発チームの体制は、ドメインごとに適切な単位でマイクロサービスに切り出し、各サービスごとに同じエンジニアがバックエンド・フロントエンドを実装する形でした。しかし、カイポケのサイト全体の情報設計を再検討しユーザビリティテストを行った結果、カイポケはドメイン単位ではなく様々なユースケース単位(ex. 経営者、ケアマネージャ、サービス事業者、etc…)で利用されていることが見えてきました。さらに、ユースケース起点でシステムを分割することで情報設計の複雑さが改善されナビゲーションがシンプルになるということがわかり、ユーザーインターフェイスとなるフロントエンドについてはユースケース単位で分割する方針になりました。 この変更によってドメイン単位で分割したバックエンドとユースケース単位で分割したフロントエンドでシステムの境界が異なることになり、従来通り一つのチームでバックエンドとフロントエンドを実装するチーム構成が合わなくなってきたため、バックエンドとフロントエンドのチームを分割し、フロントエンド専任のチームが発足することになりました。 全体的なシステムの構成としては、バックエンドとフロントエンドの間には (GraphQL)を配置して疎結合にし、フロントエンドからは Gateway を通して横断的にバックエンドの API を呼び出せる構成を取っています。 フロントエンドチームはまだ発足して数ヶ月で、今はチームビルディングやフロントエンドで採用する技術選定を進めているフェーズになります。 ここからはカイポケの改善活動でフロントエンドに求められる開発の要件と技術選定について紹介します。 改善プロジェクトのフロントエンドにおける要件 現在のカイポケの UI は1000ページ以上ある大規模なプロダクトです。 昨今のフロントエンド開発では、コンポーネントを組み合わせて画面を構築する手法が一般化しましたが、カイポケの改善プロジェクトも例外ではありません。複数の画面で利用するコンポーネントは適切な単位で共通化することはもちろんですが、コンポーネント数が増えても破綻しないような一貫性と拡張性を持った設計が求められます。 また、現在のカイポケは長年の機能追加によって改修の影響範囲が見えにくくなり部分的な改修が続いた結果、全体的に統一感のない UI や少しずつ機能の違う同じようなページが増えていきました。今回の改善プロジェクトでは、ユースケースを元にフロントエンドを分解し、それぞれのユースケースに適切な UX を目指すとともに、カイポケとして一貫したユーザー体験を提供するために統一感のある UI の開発も求められています。 技術選定 言語 技術選定する上で最初に考えたのは、型を中心に据えることです。 カイポケは巨大なプロダクトであり、改善プロジェクトも長期にわたることが想定されています。小さく早くユーザーからのフィードバックを回して確実に価値を積み上げていく方針のため、継続的な改善やリファクタリング等の活動も必要になります。こういったプロジェクトでは、静的型チェックによる整合性の検査、補完やリファクタリングを中心としたエディタの支援など、TypeScript を導入することによる生産性の向上は非常に大きいものがあります。 また、バックエンドとの通信には GraphQL を採用しました。 後述する GraphQL Code Generator を利用することで API のレスポンスに型がつくのはもちろん、フロントエンドとバックエンドでスキーマ定義の合意を取ることで、フロントエンドとしてはモックサーバーを利用して開発をし、バックエンドはスキーマを返すロジックを実装するという、スキーマ駆動で独立性高く並行して開発を進められるのも今回のプロジェクトのチーム体制にマッチしていました。 UI ライブラリ・フレームワーク UI ライブラリには、コンポーネント指向で画面を構築できること、TypeScript との親和性の高さやシェアの高さから React を採用しました。 React と合わせて、規約を持ち込むことによる生産性やパフォーマンスの向上を目的にフレームワークに Next.js を採用しました。pages 以下にファイルを配置すればルーティングされる仕組みが欲しかったのと、webpack の設定を隠蔽してくれたり、zero-configuration で TypeScript に対応できたり、v11.0.0 からは ESLint の設定がデフォルトで用意されたりと、プロジェクトの足回りを整えてくれる機能が備わっているので、ユーザーへの価値提供に繋がるアプリケーションの開発に集中することができています。 また、レンダリング方法として SSR / CSR / SSG を選べるのも Next.js の大きな特徴です。今回の改善プロジェクトでは CSR 中心で実装を進めていますが、将来的に SSR に対応したいページが出てきた場合にも対応できるように技術的な選択肢を残しておきたかったのも理由の1つです。 GraphQL Gateway との通信で利用する GraphQL クライアントは、 Apollo を採用しました。 バックエンドの各マイクロサービスの GraphQL スキーマをまとめるために Apollo Federation を採用しているのでそちらとの相性もありますが、GraphQL Code Generator で Apollo の Hooks を生成できる点も大きいです。フロントエンドは .graphql を書き、GraphQL Code Generator で各マイクロサービスの GraphQL スキーマから Hooks を含んだ生成ファイルを React Component が利用する形かつ型が一貫した状態で生成する仕組みを構築することができます。 UIフレームワーク 一般的な WEB アプリケーションで共通して使用する UI パーツについては車輪の再発明を避けたかったので、UI フレームワークを導入しました。MUI や Tailwind CSS などと比較した結果、以下の理由で Chakra UI を採用しました。 デザイナーが作成していたデザインとテイストが近い 標準でモーダルやフォーム、タブなどのコンポーネントが揃っている Color や Typography などのデザイントークンのルールが整備されている アクセシビリティが考慮されている Figma が提供されている Chakra UI は Color や Typography、Spacing などデザイントークンが JavaScript のオブジェクト形式で定義されており、これらを上書きすることでアプリケーション独自のスタイルを定義できる Theme という機構を持っています。今回のプロジェクトでは、統一感のある UI を作っていくためにデザイナーと連携してデザインシステムの構築を進めていて、デザイントークンの定義にこの機構を利用しています。 Chakra UI の Theme の機構とカイポケで作りたいデザインシステムのルールがマッチしないのではないかという懸念もありましたが、プリミティブトークンとセマンティックトークンを分けて定義できたり、プリセットで定義している Color や Typography、Spacing などのバリエーションが今回のプロジェクトのデザインシステムにおいては必要十分と判断して採用を決めました。 Figma も提供されているので、Chakra UI のコンポーネントをデザイナーが作成した Figma に取り込んでもらい、Chakra UI の Props と Figma の Component Properties を一致させた形でデザインシステムを整えていただいています。こういった形でデザイナーとエンジニアでデザイントークンやコンポーネントの粒度についての認識を揃えながら、デザインシステムを育てていっています。 その他の主要ライブラリ state management: Recoil form: React Hook Form schema validator: Zod component catalog: Storybook test: Jest test library: Testing Library 今後はE2E テストや Figma で更新されたデザイントークンをフロントエンド側に自動更新する仕組みなども整備していこうと考えています。 技術顧問 ここまで書いてきた技術選定は、私を含めたフロントエンドチームのメンバーと相談して決めていますが、チームメンバーがナレッジを持っていない領域のこともあります。そういった際に相談できる場として、Japan Node.js Association 代表理事の古川陽介さん( @yosuke_furukawa )に技術顧問として参画いただいています。中長期的な視野に沿った技術選定や、プロジェクトの進め方に関するアドバイスなどをいただけるので、チームやプロジェクトにあったちょうど良い技術選定ができていると感じています。こういった技術的なサポートがある環境なので、チームメンバーも疑問点を解消しながら安心感を持ってプロジェクトを進められています。 おわりに この記事では、介護事業者向け経営支援サービス「カイポケ」を改善するフロントエンドチームの発足の背景と技術選定の一部を紹介しました。 エス・エム・エスでは開発メンバーを募集しています。カイポケの開発に興味を持ったり、チャレンジしてみたいという方がいれば、ぜひこちらも覗いてみてください。またカジュアルに話だけ聞いてみたい、といった方も大歓迎です。こちらのページよりお気軽にご連絡ください!
この記事は、「MySQL Advent Calendar 2022」の13日目の記事です。 qiita.com 株式会社エス・エム・エスでエンジニアをしている @koma_koma_d です。今回はMySQLにおけるセミジョイン最適化について調べた内容を書きます。 ※記載内容に誤りなどがある場合は筆者のTwitter宛に連絡をいただけると幸いです。 前置き この記事で書くこと この記事では、MySQLにおけるセミジョイン最適化について、サンプルテーブルを用いた実行例を示しながら、 セミジョイン最適化とは何か セミジョイン最適化はなぜ有用か セミジョイン最適化にはどのような種類があるのか どのようにクエリやテーブル定義を変えると戦略が変化するか どのような実行計画になるか どのようなオプティマイザトレースになるか などを紹介します。 執筆にあたって、Web上のリソースなどをある程度調べましたが、自分が気になった上記のような内容を網羅しているものが見当たらなかったので、誰かの役に立つかもと思って書いています。 この記事で書かないこと MySQLの公式ドキュメントを読むだけでわかること 公式ドキュメントを読むだけでわかることについては、この記事では書きません(必要に応じて公式ドキュメントから引用をする場合はあります)。 MySQL :: MySQL 8.0 リファレンスマニュアル :: 8.2.2 サブクエリー、導出テーブル、ビュー参照および共通テーブル式の最適化 MySQL :: MySQL 8.0 Reference Manual :: 8.2.2.1 Optimizing IN and EXISTS Subquery Predicates with Semijoin Transformations コードリーディングに基づいた知見 MySQLのコードはGitHubで公開されているので、コードを読むことで動作を読み解くことも可能ではありますが、筆者にはその技量まではないので今回は対象外です。 GitHub - mysql/mysql-server: MySQL Server, the world's most popular open source database, and MySQL Cluster, a real-time, open source transactional database. MySQLのバージョン間の比較 MySQLはセミジョイン最適化が導入された後も進歩を続けており、その過程でセミジョイン最適化に関連するバージョンアップも行われているようですが、それらについて細かく言及することは今回の記事ではしません。 他のRDBMSとの比較 Oracleなどの他のRDBMSにも類似した最適化があるようですが、それらとの比較は今回は対象外とします。 セミジョイン最適化概説 前置きが長くなりましたが、本題に入っていきます。今回のテーマであるセミジョイン最適化は、MySQL 5.6 からサブクエリの実行に関する最適化として導入されたものです。まず、なぜセミジョイン最適化が「最適化」たりうるのか、パフォーマンス的に嬉しいのかを説明します。 なぜセミジョイン最適化がパフォーマンス的に嬉しいのか? 本来、サブクエリはメインクエリに従属しており、サブクエリ側からはメインクエリ側のカラムを参照できます(相関サブクエリはこれを利用したもの)。サブクエリ側からメインクエリ側のカラムを参照できるということは、メインクエリ側のテーブルが先にアクセスされるということです。 しかし、セミジョイン最適化が行われると、結合(JOIN)として処理することになるので、①先にサブクエリ側のテーブルにアクセスすることが可能になります。このため、サブクエリ側のテーブルに先にアクセスした方が効率が良い場合には、パフォーマンス上のメリットを享受できる可能性があります。 『詳解MySQL 5.7』 では以下のように記載されています。 MySQL 5.6 では、 IN サブクエリを SEMIJOIN という特殊な JOIN へと変換することで、より効率的な実行計画が選択されるようになった。SEMIJOINとは、駆動表の1行に対して内部表からマッチする行が1行だけになるという特殊な結果を産むJOINである。 SEMIJOINがなぜunique_subqueryやindex_subqueryより優れているかというと、テーブルをJOINする順序を入れ替えられるからである。サブクエリ内でアクセスされるテーブルを先にアクセスするような実行計画のほうが効率的なものになるケースは少なくない。 (『詳解MySQL 5.7』p.110) www.shoeisha.co.jp 更に、セミジョイン最適化を適用したクエリは、通常の結合では必ずしも満たされていない条件である、 最終的な結果にサブクエリ側のカラムが含まれない メインクエリ側の1行に対してサブクエリ側の複数行をマッチさせない(マッチすることを考慮しなくてよい) という条件を満たすため、②通常の結合では取ることのできない処理の効率化を行うことができます。(MySQLに焦点を当てた記述ではありませんが) 『SQL実践入門』 では以下のように記載されています。 「Semi-Join」は日本語では「準結合」または「半結合」と呼ばれています。これは通常の結合の際には現れない、EXISTS述語(とIN述語)を使ったときに特有のアルゴリズムです。 このアルゴリズムの特徴は次の2つです。 機能的には、結果には駆動表となるテーブルのデータしか含まれず、しかも1行につき必ず1行しか結果が生成されない(通常の結合の場合、1対Nの結合の場合は行数が増えることがある) 内部表にマッチする行を1行でも発見した時点で残りの行の検索を打ち切れるため、通常の結合よりもパフォーマンスが良い (『SQL実践入門』p.341) gihyo.jp 以上で記載した、 ①先にサブクエリ側のテーブルにアクセスすることが可能 ②通常の結合では取ることのできない処理の効率化を行うことができる という2つの特性をどのように活かすかが、次に紹介するそれぞれのセミジョインの戦略で違ってきます。 セミジョインにはどのような「戦略」があるのか? セミジョインには、いくつかの種類があります。MySQLではそれらを「戦略(Strategy)」と表現しています。各戦略の特徴は、以下のように整理できます。 なお、表中の「重複の除去」は、先述の「メインクエリ側の1行に対してサブクエリ側の複数行をマッチさせない(マッチすることを考慮しなくてよい)」という側面に関するもので、メインクエリ側の1行がサブクエリ結果との結合によって最終的な結果の中で重複しない理由、重複させない方法を記載しています。 戦略の名称 サブクエリ側の結合キー列のINDEXの必要性 駆動表と内部表 重複の除去 Table Pullout UNIQUE制約必要 可変 UNIQUE制約により保証 LooseScan 必要 サブクエリ側が駆動表 インデックスを活用しながら結合時に実施 Materialization 不要(一時表で自動作成) 可変 サブクエリ実体化時に除去 Duplicate Weedout 不要 可変 結果を返す前に除去 FirstMatch 不要 メインクエリ側が駆動表 結合時に除去 以下、個別に補足説明を加えます。記載している内容は参考資料に依拠しているほか、サンプルテーブルを使った実行例から分かる内容を記載しています。 主な参考資料は以下の2つです。 MySQL道普請便り 第43回 MySQLの準結合(セミジョイン)について セミジョインについての親切な紹介。駆動表と内部表がどうなるかはこちらに主に依拠した。 MariaDB 10.6 [日本語] 最適化とチューニング セミジョイン副問い合わせの最適化 (MySQLではなくMariaDBですが)それぞれの戦略が図付きで解説されていてわかりやすい。 各戦略の特徴 ここからは、上で記載した表の内容を戦略ごとに補足していきます。各戦略について細かく論じていくにあたって、サンプルテーブルを用いて実際に実行計画やオプティマイザトレースを取得した結果を随時示します。実行計画やオプティマイザトレースについては、実物を示すのが最も参考になると思いましたので、厚め(実行計画は全部、オプティマイザトレースは一部抜粋)に載せましたが、記事が長くなってしまうので折りたたんでいます。展開したい場合は「▶︎詳細」となっているところをクリックしてください。 サンプルテーブルの前提 サンプルテーブルの前提条件を記載しておきます。 使用したMySQLのバージョン MySQL 8.0.21 ※現時点での最新は 8.0.31 です。たまたま調べようと思ったタイミングでローカルに入っていたのがこのバージョン( 以前個人ブログの方に書いた記事 の検証で使ったバージョンだった)だったために過ぎません。 サンプルテーブル CREATE TABLE `employee` ( `emp_id` int unsigned NOT NULL AUTO_INCREMENT, `main_floor` int unsigned DEFAULT NULL , `gender` int unsigned DEFAULT NULL , PRIMARY KEY (`emp_id`), ) ENGINE=InnoDB; CREATE TABLE `department` ( `dept_id` int unsigned NOT NULL AUTO_INCREMENT, `main_floor` int unsigned DEFAULT NULL , `dept_name` varchar ( 100 ) DEFAULT NULL , PRIMARY KEY (`dept_id`) ) ENGINE=InnoDB; データ内容(クリックで展開) employee テーブル emp_id main_floor gender 1 1 1 2 2 2 3 3 3 4 4 1 5 5 2 6 6 3 7 7 1 8 8 2 9 9 3 10 10 1 11 11 2 12 12 3 13 13 1 14 14 2 15 15 3 16 16 1 17 17 2 18 18 3 19 1 1 20 2 2 21 3 3 22 4 1 23 5 2 24 6 3 25 7 1 26 8 2 27 9 3 28 10 1 29 11 2 30 12 3 31 13 1 32 14 2 33 15 3 34 16 1 35 17 2 36 18 3 department テーブル dept_id main_floor dept_name 1 1 Finance 2 2 Legal 3 3 Human Resorces 4 4 Corporate Planning 5 5 Sales 1 6 6 Sales 2 7 7 Accounting 8 8 Development 1 9 9 Development 2 Table Pullout Table Pullout 戦略は、以下のような特徴を持ちます。 通常のJOINとして処理する 結合キーにUNIQUE制約(PRIMARY KEY含む)がある場合に利用可能 メインクエリの結果1行に対してサブクエリから0or1行しか返らないことが保証されているので、通常のJOINにして結合順序を入れ替えてもメインクエリ側の行が最終結果の中で重複することがない サンプルテーブルを用いた実行例から分かることは以下の通りです。 department 表の main_floor 列にUNIQUE制約を付与したところ選択された オプティマイザトレースの pulled_out_semijoin_tables という項目に department 表が表れている EXPLAIN ANALYZE をみると、 Remove duplicates from ... という重複除去を表す情報がない ここが後述のLooseScanとの違い SELECT * FROM employee e WHERE e.main_floor IN ( SELECT main_floor FROM department d ) 実行計画 mysql> explain select * from employee e where e.main_floor in ( select main_floor from department d ); +----+-------------+-------+------------+-------+---------------------------+---------------------------+---------+----------------------+------+----------+--------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------------------+---------------------------+---------+----------------------+------+----------+--------------------------+ | 1 | SIMPLE | d | NULL | index | department_main_floor_IDX | department_main_floor_IDX | 5 | NULL | 9 | 100.00 | Using where ; Using index | | 1 | SIMPLE | e | NULL | ref | employee_main_floor_IDX | employee_main_floor_IDX | 5 | sandbox.d.main_floor | 2 | 100.00 | NULL | +----+-------------+-------+------------+-------+---------------------------+---------------------------+---------+----------------------+------+----------+--------------------------+ 2 rows in set, 1 warning ( 0.00 sec) Note (Code 1003 ): /* select#1 */ select `sandbox`.`e`.`emp_id` AS `emp_id`,`sandbox`.`e`.`main_floor` AS `main_floor`,`sandbox`.`e`.`gender` AS `gender` from `sandbox`.`department` `d` join `sandbox`.`employee` `e` where (`sandbox`.`e`.`main_floor` = `sandbox`.`d`.`main_floor`) mysql> explain analyze select * from employee e where e.main_floor in ( select main_floor from department d )\G *************************** 1 . row *************************** EXPLAIN : -> Nested loop inner join (cost= 7.45 rows = 18 ) (actual time = 0.040 .. 0.078 rows = 18 loops= 1 ) -> Filter: (d.main_floor is not null ) (cost= 1.15 rows = 9 ) (actual time = 0.023 .. 0.026 rows = 9 loops= 1 ) -> Index scan on d using department_main_floor_IDX (cost= 1.15 rows = 9 ) (actual time = 0.022 .. 0.024 rows = 9 loops= 1 ) -> Index lookup on e using employee_main_floor_IDX (main_floor=d.main_floor) (cost= 0.52 rows = 2 ) (actual time = 0.005 .. 0.005 rows = 2 loops= 9 ) オプティマイザトレース(一部抜粋) { "steps" : [ { "join_preparation" : { "select#" : 1, "steps" : [ // 中略 { "transformations_to_nested_joins" : { "transformations" : [ "semijoin" ] , "expanded_query" : "/* select#1 */ select `e`.`emp_id` AS `emp_id`,`e`.`main_floor` AS `main_floor`,`e`.`gender` AS `gender` from `employee` `e` semi join (`department` `d`) where ((`e`.`main_floor` = `d`.`main_floor`))" } } ] } } , { "join_optimization" : { "select#" : 1, "steps" : [ // 中略 { "pulled_out_semijoin_tables" : [ { "table" : "`department` `d`" , "functionally_dependent" : true } ] } , // 中略 ] } } , { "join_explain" : { "select#" : 1, "steps" : [ ] } } ] } LooseScan LooseScan 戦略は以下のような特徴を持ちます。 サブクエリ側のテーブルの結合キーのカラムにインデックスがある場合に利用可能 ※UNIQUE制約がついていれば Table Pullout も使えることになる サブクエリ側のインデックスを重複を避けながらスキャンしていく サブクエリ側が必ず駆動表になる 重複の除去を、サブクエリのインデックスを使って実現するため サンプルテーブルを用いた実行例から分かることは以下の通りです。 department 表の main_floor 列にインデックスを追加したところ、LooseScan が候補に上がるようになった UNIQUE制約をつけると Table Pullout も利用可能になる オプティマイザトレースの final_semijoin_strategy が LooseScan 実行計画の Extra 列に LooseScan と表示 EXPLAIN ANALYZE をみると、 Remove duplicates from ... という重複除去を表す情報がある ここがTable Pullout との違いになる SELECT * FROM employee e WHERE e.main_floor IN ( SELECT main_floor FROM department d ) ※ Table Pullout と同じクエリ 実行計画 mysql> explain select * from employee e where e.main_floor in ( select main_floor from department d ); +----+-------------+-------+------------+-------+---------------------------+---------------------------+---------+----------------------+------+----------+-------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------------------+---------------------------+---------+----------------------+------+----------+-------------------------------------+ | 1 | SIMPLE | d | NULL | index | department_main_floor_IDX | department_main_floor_IDX | 5 | NULL | 9 | 100.00 | Using where ; Using index ; LooseScan | | 1 | SIMPLE | e | NULL | ref | employee_main_floor_IDX | employee_main_floor_IDX | 5 | sandbox.d.main_floor | 2 | 100.00 | NULL | +----+-------------+-------+------------+-------+---------------------------+---------------------------+---------+----------------------+------+----------+-------------------------------------+ 2 rows in set, 1 warning ( 0.00 sec) Note (Code 1003 ): /* select#1 */ select `sandbox`.`e`.`emp_id` AS `emp_id`,`sandbox`.`e`.`main_floor` AS `main_floor`,`sandbox`.`e`.`gender` AS `gender` from `sandbox`.`employee` `e` semi join (`sandbox`.`department` `d`) where (`sandbox`.`e`.`main_floor` = `sandbox`.`d`.`main_floor`) mysql> explain analyze select * from employee e where e.main_floor in ( select main_floor from department d )\G *************************** 1 . row *************************** EXPLAIN : -> Nested loop inner join (actual time = 0.109 .. 0.141 rows = 18 loops= 1 ) -> Remove duplicates from input sorted on department_main_floor_IDX (actual time = 0.091 .. 0.095 rows = 9 loops= 1 ) -> Filter: (d.main_floor is not null ) (cost= 1.15 rows = 9 ) (actual time = 0.090 .. 0.093 rows = 9 loops= 1 ) -> Index scan on d using department_main_floor_IDX (cost= 1.15 rows = 9 ) (actual time = 0.089 .. 0.091 rows = 9 loops= 1 ) -> Index lookup on e using employee_main_floor_IDX (main_floor=d.main_floor) (cost= 4.70 rows = 2 ) (actual time = 0.004 .. 0.005 rows = 2 loops= 9 ) オプティマイザトレース(一部抜粋) { "steps" : [ { "join_preparation" : { "select#" : 1, "steps" : [ // 中略 { "transformations_to_nested_joins" : { "transformations" : [ "semijoin" ] , "expanded_query" : "/* select#1 */ select `e`.`emp_id` AS `emp_id`,`e`.`main_floor` AS `main_floor`,`e`.`gender` AS `gender` from `employee` `e` semi join (`department` `d`) where ((`e`.`main_floor` = `d`.`main_floor`))" } } ] } } , { "join_optimization" : { "select#" : 1, "steps" : [ // 中略 { "considered_execution_plans" : [ { "plan_prefix" : [ ] , "table" : "`department` `d`" , "best_access_path" : { "considered_access_paths" : [ { "access_type" : "ref" , "index" : "department_main_floor_IDX" , "usable" : false , "chosen" : false } , { "rows_to_scan" : 9, "filtering_effect" : [ ] , "final_filtering_effect" : 1, "access_type" : "scan" , "resulting_rows" : 9, "cost" : 1.15, "chosen" : true } ] } , "condition_filtering_pct" : 100, "rows_for_plan" : 9, "cost_for_plan" : 1.15, "semijoin_strategy_choice" : [ { "strategy" : "MaterializeScan" , "choice" : "deferred" } ] , "rest_of_plan" : [ { "plan_prefix" : [ "`department` `d`" ] , "table" : "`employee` `e`" , "best_access_path" : { "considered_access_paths" : [ { "access_type" : "ref" , "index" : "employee_main_floor_IDX" , "rows" : 2, "cost" : 6.3, "chosen" : true } , { "rows_to_scan" : 36, "filtering_effect" : [ ] , "final_filtering_effect" : 1, "access_type" : "scan" , "using_join_cache" : true , "buffers_needed" : 1, "resulting_rows" : 36, "cost" : 32.65, "chosen" : false } ] } , "condition_filtering_pct" : 100, "rows_for_plan" : 18, "cost_for_plan" : 7.45, "semijoin_strategy_choice" : [ { "strategy" : "LooseScan" , "recalculate_access_paths_and_cost" : { "tables" : [ { "table" : "`department` `d`" , "best_access_path" : { "considered_access_paths" : [ { "access_type" : "ref" , "index" : "department_main_floor_IDX" , "usable" : false , "chosen" : false } , { "rows_to_scan" : 9, "filtering_effect" : [ ] , "final_filtering_effect" : 1, "access_type" : "scan" , "resulting_rows" : 9, "cost" : 1.15, "chosen" : true } ] } , "unknown_key_1" : { "searching_loose_scan_index" : { "indexes" : [ { "index" : "department_main_floor_IDX" , "covering_scan" : { "cost" : 0.2522, "chosen" : true } } ] } } } ] } , "cost" : 7.4522, "rows" : 2, "chosen" : true } , { "strategy" : "MaterializeScan" , "recalculate_access_paths_and_cost" : { "tables" : [ { "table" : "`employee` `e`" , "best_access_path" : { "considered_access_paths" : [ { "access_type" : "ref" , "index" : "employee_main_floor_IDX" , "rows" : 2, "cost" : 6.3, "chosen" : true } , { "rows_to_scan" : 36, "filtering_effect" : [ ] , "final_filtering_effect" : 1, "access_type" : "scan" , "using_join_cache" : true , "buffers_needed" : 1, "resulting_rows" : 36, "cost" : 32.65, "chosen" : false } ] } } ] } , "cost" : 10.25, "rows" : 2, "duplicate_tables_left" : false , "chosen" : false } , { "strategy" : "DuplicatesWeedout" , "cost" : 12.05, "rows" : 18, "duplicate_tables_left" : false , "chosen" : false } ] , "chosen" : true } ] } , { "plan_prefix" : [ ] , "table" : "`employee` `e`" , "best_access_path" : { "considered_access_paths" : [ { "access_type" : "ref" , "index" : "employee_main_floor_IDX" , "usable" : false , "chosen" : false } , { "rows_to_scan" : 36, "filtering_effect" : [ ] , "final_filtering_effect" : 1, "access_type" : "scan" , "resulting_rows" : 36, "cost" : 3.85, "chosen" : true } ] } , "condition_filtering_pct" : 100, "rows_for_plan" : 36, "cost_for_plan" : 3.85, "semijoin_strategy_choice" : [ ] , "rest_of_plan" : [ { "plan_prefix" : [ "`employee` `e`" ] , "table" : "`department` `d`" , "best_access_path" : { "considered_access_paths" : [ { "access_type" : "ref" , "index" : "department_main_floor_IDX" , "rows" : 1, "cost" : 12.6, "chosen" : true } , { "access_type" : "scan" , "chosen" : false , "cause" : "covering_index_better_than_full_scan" } ] } , "condition_filtering_pct" : 100, "rows_for_plan" : 36, "cost_for_plan" : 16.45, "semijoin_strategy_choice" : [ { "strategy" : "FirstMatch" , "recalculate_access_paths_and_cost" : { "tables" : [ ] } , "cost" : 16.45, "rows" : 36, "chosen" : true } , { "strategy" : "MaterializeLookup" , "cost" : 10.5, "rows" : 36, "duplicate_tables_left" : false , "chosen" : true } , { "strategy" : "DuplicatesWeedout" , "cost" : 24.65, "rows" : 36, "duplicate_tables_left" : false , "chosen" : false } ] , "pruned_by_cost" : true } ] } , { "final_semijoin_strategy" : "LooseScan" , // 中略 } } ] } , //中略 ] } } , { "join_explain" : { "select#" : 1, "steps" : [ ] } } ] } Materialization Materialization 戦略は以下の特徴を持ちます。 サブクエリの結果を実体化して、結合キーにインデックスを作成して重複を取り除いてからメインクエリとJOINする ※結合キーのカラムにインデックスがあれば LooseScan が使えるし、UNIQUE制約がついていれば Table Pullout が使える ただし、コスト次第で他の戦略ではなくこちらが選択されることはある たとえば、サブクエリでWhere句での絞り込みをしていて、絞り込み後に実体化する Materialization の方が、LooseScan(JOIN時に絞り込みを行う)よりもコストが低くなるケースなど 作成されたインデックスのキーが <auto_key> という形で実行計画に現れることがある メインクエリ側とサブクエリ側のどちらが駆動表、内部表となるかはコストで決まる 実体化されたサブクエリ側が内部表になる場合が MaterializeLookup 実体化されたサブクエリ側が駆動表になる場合が MaterializeScan 参考: MySQL: Query Optimizer 4.MaterializeLookup (Materialize inner tables, then setup a scan over outer correlated tables, lookup in materialized table) 5.MaterializeScan (Materialize inner tables, then setup a scan over materialized tables, perform lookup in outer tables) サンプルテーブルを用いた実行例から分かることは以下の通りです。 これまでのクエリのサブクエリにWHERE句を追加したところ選択された オプティマイザトレースの final_semijoin_strategy が MaterializeScan 今回はサブクエリ側の方が駆動表になったパターン 実行計画の select_type に MATERIALIZED と表示 SELECT * FROM employee e WHERE e.main_floor IN ( SELECT main_floor FROM department d WHERE d.dept_name LIKE ' Sales% ' ) 実行計画 mysql> Explain select * from employee e where e.main_floor in ( select main_floor from department d where d.dept_name like 'Sales%' ); +----+--------------+-------------+------------+------+-------------------------+-------------------------+---------+------------------------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+--------------+-------------+------------+------+-------------------------+-------------------------+---------+------------------------+------+----------+-------------+ | 1 | SIMPLE | <subquery2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | 100.00 | Using where | | 1 | SIMPLE | e | NULL | ref | employee_main_floor_IDX | employee_main_floor_IDX | 5 | <subquery2>.main_floor | 2 | 100.00 | NULL | | 2 | MATERIALIZED | d | NULL | ALL | NULL | NULL | NULL | NULL | 9 | 11.11 | Using where | +----+--------------+-------------+------------+------+-------------------------+-------------------------+---------+------------------------+------+----------+-------------+ 3 rows in set, 1 warning ( 0.00 sec) Note (Code 1003 ): /* select#1 */ select `sandbox`.`e`.`emp_id` AS `emp_id`,`sandbox`.`e`.`main_floor` AS `main_floor`,`sandbox`.`e`.`gender` AS `gender` from `sandbox`.`employee` `e` semi join (`sandbox`.`department` `d`) where ((`sandbox`.`e`.`main_floor` = `<subquery2>`.`main_floor`) and (`sandbox`.`d`.`dept_name` like 'Sales%' )) オプティマイザトレース(一部抜粋) { "steps" : [ { "join_preparation" : { "select#" : 1, "steps" : [ // 中略 { "transformations_to_nested_joins" : { "transformations" : [ "semijoin" ] , "expanded_query" : "/* select#1 */ select `e`.`emp_id` AS `emp_id`,`e`.`main_floor` AS `main_floor`,`e`.`gender` AS `gender` from `employee` `e` semi join (`department` `d`) where ((`d`.`dept_name` like 'Sales%') and (`e`.`main_floor` = `d`.`main_floor`))" } } ] } } , { "join_optimization" : { "select#" : 1, "steps" : [ // 中略 { "considered_execution_plans" : [ { "plan_prefix" : [ ] , "table" : "`department` `d`" , "best_access_path" : { "considered_access_paths" : [ { "rows_to_scan" : 9, "filtering_effect" : [ ] , "final_filtering_effect" : 0.1111, "access_type" : "scan" , "resulting_rows" : 1, "cost" : 1.15, "chosen" : true } ] } , "condition_filtering_pct" : 100, "rows_for_plan" : 1, "cost_for_plan" : 1.15, "semijoin_strategy_choice" : [ { "strategy" : "MaterializeScan" , "choice" : "deferred" } ] , "rest_of_plan" : [ { "plan_prefix" : [ "`department` `d`" ] , "table" : "`employee` `e`" , "best_access_path" : { "considered_access_paths" : [ { "access_type" : "ref" , "index" : "employee_main_floor_IDX" , "rows" : 2, "cost" : 0.7, "chosen" : true } , { "rows_to_scan" : 36, "filtering_effect" : [ ] , "final_filtering_effect" : 1, "access_type" : "scan" , "using_join_cache" : true , "buffers_needed" : 1, "resulting_rows" : 36, "cost" : 3.8503, "chosen" : false } ] } , "condition_filtering_pct" : 100, "rows_for_plan" : 2, "cost_for_plan" : 1.85, "semijoin_strategy_choice" : [ { "strategy" : "MaterializeScan" , "recalculate_access_paths_and_cost" : { "tables" : [ { "table" : "`employee` `e`" , "best_access_path" : { "considered_access_paths" : [ { "access_type" : "ref" , "index" : "employee_main_floor_IDX" , "rows" : 2, "cost" : 0.7, "chosen" : true } , { "rows_to_scan" : 36, "filtering_effect" : [ ] , "final_filtering_effect" : 1, "access_type" : "scan" , "using_join_cache" : true , "buffers_needed" : 1, "resulting_rows" : 36, "cost" : 3.8503, "chosen" : false } ] } } ] } , "cost" : 3.05, "rows" : 2, "duplicate_tables_left" : true , "chosen" : true } , { "strategy" : "DuplicatesWeedout" , "cost" : 3.25, "rows" : 2, "duplicate_tables_left" : false , "chosen" : false } ] , "chosen" : true } ] } , { "plan_prefix" : [ ] , "table" : "`employee` `e`" , "best_access_path" : { "considered_access_paths" : [ { "access_type" : "ref" , "index" : "employee_main_floor_IDX" , "usable" : false , "chosen" : false } , { "rows_to_scan" : 36, "filtering_effect" : [ ] , "final_filtering_effect" : 1, "access_type" : "scan" , "resulting_rows" : 36, "cost" : 3.85, "chosen" : true } ] } , "condition_filtering_pct" : 100, "rows_for_plan" : 36, "cost_for_plan" : 3.85, "semijoin_strategy_choice" : [ ] , "pruned_by_cost" : true } , { "final_semijoin_strategy" : "MaterializeScan" , // 中略 } ] } , // 中略 ] } } , { "join_explain" : { "select#" : 1, "steps" : [ ] } } ] } Duplicate Weedout Duplicate Weedout には以下の特徴があります。 JOINしてから、一時テーブルを作成して重複を取り除く メインクエリの1行に対してサブクエリの結果が複数行マッチする場合には、JOINで処理することによって重複が発生するので、それを取り除くという戦略 JOIN時にメインクエリとサブクエリのどちらが駆動表・内部表となるかはコストによって決まる(どちらともありうる) 重複の除去を最後にするので、JOINはどちらを駆動表として行ってもよいため サンプルテーブルを用いた実行例から分かることは以下の通りです。 Materialization 戦略が選択されたときのクエリをベースとして、メインクエリ側に AND で条件を足している final_semijoin_strategy が DuplicateWeedout 実行計画の Extra 列に Start temporary と End temporary と表示 EXPLAIN ANALYZE では一番上に Remove duplicate e rows using temporary table (weedout) と表示 重複の除去を一時テーブルを用いて実施している SELECT * FROM employee e WHERE e.main_floor IN ( SELECT main_floor FROM department d WHERE d.dept_name LIKE ' Sales% ' ) AND gender = 2 ; 実行計画 mysql> explain select * from employee e where e.main_floor in ( select main_floor from department d where d.dept_name like 'Sales%' ) and gender = 2 ; +----+-------------+-------+------------+------+-------------------------+-------------------------+---------+----------------------+------+----------+------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+-------------------------+-------------------------+---------+----------------------+------+----------+------------------------------+ | 1 | SIMPLE | d | NULL | ALL | NULL | NULL | NULL | NULL | 9 | 11.11 | Using where ; Start temporary | | 1 | SIMPLE | e | NULL | ref | employee_main_floor_IDX | employee_main_floor_IDX | 5 | sandbox.d.main_floor | 2 | 10.00 | Using where ; End temporary | +----+-------------+-------+------------+------+-------------------------+-------------------------+---------+----------------------+------+----------+------------------------------+ 2 rows in set, 1 warning ( 0.00 sec) Note (Code 1003 ): /* select#1 */ select `sandbox`.`e`.`emp_id` AS `emp_id`,`sandbox`.`e`.`main_floor` AS `main_floor`,`sandbox`.`e`.`gender` AS `gender` from `sandbox`.`employee` `e` semi join (`sandbox`.`department` `d`) where ((`sandbox`.`e`.`main_floor` = `sandbox`.`d`.`main_floor`) and (`sandbox`.`e`.`gender` = 2 ) and (`sandbox`.`d`.`dept_name` like 'Sales%' )) mysql> explain analyze select * from employee e where e.main_floor in ( select main_floor from department d where d.dept_name like 'Sales%' ) and gender = 2 \G *************************** 1 . row *************************** EXPLAIN : -> Remove duplicate e rows using temporary table (weedout) (cost= 1.85 rows = 0 ) (actual time = 0.051 .. 0.062 rows = 2 loops= 1 ) -> Nested loop inner join (cost= 1.85 rows = 0 ) (actual time = 0.047 .. 0.057 rows = 2 loops= 1 ) -> Filter: ((d.dept_name like 'Sales%' ) and (d.main_floor is not null )) (cost= 1.15 rows = 1 ) (actual time = 0.027 .. 0.030 rows = 2 loops= 1 ) -> Table scan on d (cost= 1.15 rows = 9 ) (actual time = 0.022 .. 0.025 rows = 9 loops= 1 ) -> Filter: (e.gender = 2 ) (cost= 0.52 rows = 0 ) (actual time = 0.011 .. 0.012 rows = 1 loops= 2 ) -> Index lookup on e using employee_main_floor_IDX (main_floor=d.main_floor) (cost= 0.52 rows = 2 ) (actual time = 0.011 .. 0.012 rows = 2 loops= 2 ) オプティマイザトレース(一部抜粋) { "steps" : [ { "join_preparation" : { "select#" : 1, "steps" : [ // 中略 { "transformations_to_nested_joins" : { "transformations" : [ "semijoin" ] , "expanded_query" : "/* select#1 */ select `e`.`emp_id` AS `emp_id`,`e`.`main_floor` AS `main_floor`,`e`.`gender` AS `gender` from `employee` `e` semi join (`department` `d`) where ((`e`.`gender` = 2) and (`d`.`dept_name` like 'Sales%') and (`e`.`main_floor` = `d`.`main_floor`))" } } ] } } , { "join_optimization" : { "select#" : 1, "steps" : [ // 中略 { "considered_execution_plans" : [ { "plan_prefix" : [ ] , "table" : "`department` `d`" , "best_access_path" : { "considered_access_paths" : [ { "rows_to_scan" : 9, "filtering_effect" : [ ] , "final_filtering_effect" : 0.1111, "access_type" : "scan" , "resulting_rows" : 1, "cost" : 1.15, "chosen" : true } ] } , "condition_filtering_pct" : 100, "rows_for_plan" : 1, "cost_for_plan" : 1.15, "semijoin_strategy_choice" : [ { "strategy" : "MaterializeScan" , "choice" : "deferred" } ] , "rest_of_plan" : [ { "plan_prefix" : [ "`department` `d`" ] , "table" : "`employee` `e`" , "best_access_path" : { "considered_access_paths" : [ { "access_type" : "ref" , "index" : "employee_main_floor_IDX" , "rows" : 2, "cost" : 0.7, "chosen" : true } , { "rows_to_scan" : 36, "filtering_effect" : [ ] , "final_filtering_effect" : 0.1, "access_type" : "scan" , "using_join_cache" : true , "buffers_needed" : 1, "resulting_rows" : 3.6, "cost" : 3.8541, "chosen" : false } ] } , "condition_filtering_pct" : 10, "rows_for_plan" : 0.2, "cost_for_plan" : 1.85, "semijoin_strategy_choice" : [ { "strategy" : "MaterializeScan" , "recalculate_access_paths_and_cost" : { "tables" : [ { "table" : "`employee` `e`" , "best_access_path" : { "considered_access_paths" : [ { "access_type" : "ref" , "index" : "employee_main_floor_IDX" , "rows" : 2, "cost" : 0.7, "chosen" : true } , { "rows_to_scan" : 36, "filtering_effect" : [ ] , "final_filtering_effect" : 0.1, "access_type" : "scan" , "using_join_cache" : true , "buffers_needed" : 1, "resulting_rows" : 3.6, "cost" : 3.8541, "chosen" : false } ] } } ] } , "cost" : 3.05, "rows" : 0.2, "duplicate_tables_left" : true , "chosen" : true } , { "strategy" : "DuplicatesWeedout" , "cost" : 2.89, "rows" : 0.2, "duplicate_tables_left" : false , "chosen" : true } ] , "chosen" : true } ] } , { "plan_prefix" : [ ] , "table" : "`employee` `e`" , "best_access_path" : { "considered_access_paths" : [ { "access_type" : "ref" , "index" : "employee_main_floor_IDX" , "usable" : false , "chosen" : false } , { "rows_to_scan" : 36, "filtering_effect" : [ ] , "final_filtering_effect" : 0.1, "access_type" : "scan" , "resulting_rows" : 3.6, "cost" : 3.85, "chosen" : true } ] } , "condition_filtering_pct" : 100, "rows_for_plan" : 3.6, "cost_for_plan" : 3.85, "semijoin_strategy_choice" : [ ] , "pruned_by_cost" : true } , { "final_semijoin_strategy" : "DuplicateWeedout" } ] } , // 中略 ] } } , { "join_execution" : { "select#" : 1, "steps" : [ ] } } ] } FirstMatch FirstMatch 戦略には以下の特徴があります。 通常のNLJ(Nested Loop Join)に似ているが、内側の(サブクエリ側の)ループを回しているときに1行でも見つかったら即座に内側のループを打ち切って外側のループの次の周回に進むことができるため効率が良い メインクエリ側が必ず駆動表になる 重複の除去を、内側のループを途中で打ち切ることによって実現しているため サンプルテーブルを用いた実行例から分かることは以下の通りです。 これまでのクエリとは違い、department表へのクエリをメインクエリとしている これまでは、サブクエリのテーブルの方が小さかったが、今回のクエリはメインクエリのテーブルの方が小さい オプティマイザトレースの final_semijoin_strategy が FirstMatch 実行計画の Extra 列に FirstMatch(department) の表示がある SELECT * FROM department WHERE department.main_floor IN ( SELECT main_floor FROM employee ); 実行計画 mysql> explain select * from department where department.main_floor in ( select main_floor from employee ); +----+-------------+------------+------------+------+-------------------------+-------------------------+---------+-------------------------------+------+----------+-------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+------------+------------+------+-------------------------+-------------------------+---------+-------------------------------+------+----------+-------------------------------------+ | 1 | SIMPLE | department | NULL | ALL | NULL | NULL | NULL | NULL | 9 | 100.00 | Using where | | 1 | SIMPLE | employee | NULL | ref | employee_main_floor_IDX | employee_main_floor_IDX | 5 | sandbox.department.main_floor | 2 | 100.00 | Using index ; FirstMatch(department) | +----+-------------+------------+------------+------+-------------------------+-------------------------+---------+-------------------------------+------+----------+-------------------------------------+ 2 rows in set, 1 warning ( 0.00 sec) Note (Code 1003 ): /* select#1 */ select `sandbox`.`department`.`dept_id` AS `dept_id`,`sandbox`.`department`.`main_floor` AS `main_floor`,`sandbox`.`department`.`dept_name` AS `dept_name` from `sandbox`.`department` semi join (`sandbox`.`employee`) where (`sandbox`.`employee`.`main_floor` = `sandbox`.`department`.`main_floor`) mysql> explain analyze select * from department where department.main_floor in ( select main_floor from employee )\G *************************** 1 . row *************************** EXPLAIN : -> Nested loop semijoin (cost= 5.20 rows = 18 ) (actual time = 0.034 .. 0.050 rows = 9 loops= 1 ) -> Filter: (department.main_floor is not null ) (cost= 1.15 rows = 9 ) (actual time = 0.022 .. 0.026 rows = 9 loops= 1 ) -> Table scan on department (cost= 1.15 rows = 9 ) (actual time = 0.022 .. 0.025 rows = 9 loops= 1 ) -> Index lookup on employee using employee_main_floor_IDX (main_floor=department.main_floor) (cost= 0.54 rows = 2 ) (actual time = 0.002 .. 0.002 rows = 1 loops= 9 ) オプティマイザトレース(一部抜粋) { "steps" : [ { "join_preparation" : { "select#" : 1, "steps" : [ // 中略 { "transformations_to_nested_joins" : { "transformations" : [ "semijoin" ] , "expanded_query" : "/* select#1 */ select `department`.`dept_id` AS `dept_id`,`department`.`main_floor` AS `main_floor`,`department`.`dept_name` AS `dept_name` from `department` semi join (`employee`) where ((`department`.`main_floor` = `employee`.`main_floor`))" } } ] } } , { "join_optimization" : { "select#" : 1, "steps" : [ // 中略 { "considered_execution_plans" : [ { "plan_prefix" : [ ] , "table" : "`department`" , "best_access_path" : { "considered_access_paths" : [ { "rows_to_scan" : 9, "filtering_effect" : [ ] , "final_filtering_effect" : 1, "access_type" : "scan" , "resulting_rows" : 9, "cost" : 1.15, "chosen" : true } ] } , "condition_filtering_pct" : 100, "rows_for_plan" : 9, "cost_for_plan" : 1.15, "semijoin_strategy_choice" : [ ] , "rest_of_plan" : [ { "plan_prefix" : [ "`department`" ] , "table" : "`employee`" , "best_access_path" : { "considered_access_paths" : [ { "access_type" : "ref" , "index" : "employee_main_floor_IDX" , "rows" : 2, "cost" : 4.0525, "chosen" : true } , { "access_type" : "scan" , "chosen" : false , "cause" : "covering_index_better_than_full_scan" } ] } , "condition_filtering_pct" : 100, "rows_for_plan" : 18, "cost_for_plan" : 5.2025, "semijoin_strategy_choice" : [ { "strategy" : "FirstMatch" , "recalculate_access_paths_and_cost" : { "tables" : [ ] } , "cost" : 5.2025, "rows" : 9, "chosen" : true } , { "strategy" : "MaterializeLookup" , "cost" : 10.5, "rows" : 9, "duplicate_tables_left" : false , "chosen" : false } , { "strategy" : "DuplicatesWeedout" , "cost" : 8.9025, "rows" : 9, "duplicate_tables_left" : false , "chosen" : false } ] , "chosen" : true } ] } , { "plan_prefix" : [ ] , "table" : "`employee`" , "best_access_path" : { "considered_access_paths" : [ { "access_type" : "ref" , "index" : "employee_main_floor_IDX" , "usable" : false , "chosen" : false } , { "rows_to_scan" : 36, "filtering_effect" : [ ] , "final_filtering_effect" : 1, "access_type" : "scan" , "resulting_rows" : 36, "cost" : 3.85, "chosen" : true } ] } , "condition_filtering_pct" : 100, "rows_for_plan" : 36, "cost_for_plan" : 3.85, "semijoin_strategy_choice" : [ { "strategy" : "MaterializeScan" , "choice" : "deferred" } ] , "pruned_by_heuristic" : true } , { "final_semijoin_strategy" : "FirstMatch" , "recalculate_access_paths_and_cost" : { "tables" : [ ] } } ] } , // 中略 ] } } , { "join_execution" : { "select#" : 1, "steps" : [ ] } } ] } 終わりに 以上、セミジョイン最適化について、個々の戦略の内容を含めて書いてきました。サンプルテーブルを用いて取得した実行計画やオプティマイザトレースはあくまで一例に過ぎず、少し条件を変えるとまた違った結果が得られるかもしれません。冒頭にも書いたように、記載している内容に誤りなどを見つけた場合は 筆者のTwitter までご一報いただけると幸いです。 参考資料 公式 5.6 8.2.1.18 サブクエリーの最適化 8.2.2.1 Optimizing Subqueries with Semijoin Transformations 8.2.2.2 Optimizing Subqueries with Materialization 8.8.5.2 切り替え可能な最適化の制御 8.0 8.2.2.1 Optimizing IN and EXISTS Subquery Predicates with Semijoin Transformations 8.9.3 オプティマイザヒント MySQL 8.0.30 Source Code Documentation その他 MySQL道普請便り 第43回 MySQLの準結合(セミジョイン)について MariaDB 10.6 [日本語] 最適化とチューニング セミジョイン副問い合わせの最適化 INとEXISTSはどちらが速いのか? MySQL のサブクエリって、ほんとに遅いの? MySQL 8.0.21 では Multi-Table Trick が必要なくなったらしい MySQL道普請便り第103回MySQL 8.0のセミジョインの変更点
介護職向け求人情報サイト「カイゴジョブ *1 」の開発をしている児玉卓也です。 弊社の プレスリリース でお知らせしているように、カイゴジョブは2022年5月にデザインリニューアルを行いました。 デザインリニューアルにはサイトのコンセプトなどはそのままで、UIなどの見た目を部分だけを変更するものから、コンセプトやユーザーシナリオというサービスの基盤となる部分から再設計し直すことがあるかと思いますが、カイゴジョブが行ったデザインリニューアルは後者の方で、カイゴジョブにおける求職者の体験をより良くするためにコンセプト・ユーザーシナリオをアップデートした上でデザインを全面的に変更しました。 全面リニューアルとなるとその影響範囲は大きく、特にプロダクトの品質を保ちつつ大規模リリースをすることは、経験された方にはわかると思いますが大変な作業となります。今回のデザインリニューアルでは40,000行、900を超えるファイル数の変更となり、我々が日々行っているリリースの数百倍くらい大きなリリースとなりました。 デザインリニューアル時のPRの変更行数 本記事では私達が大規模リリースをしなければならなかった理由を説明した後に、どのような開発手法を用いて大規模なリリースを安全に行えたかについて説明したいと思います。 デザインリニューアルの背景 環境の変化が激しく不確実性が高まる時代ではありますが、介護業界も例に漏れず変化が激しい業界です。カイゴジョブも市場の変化やユーザーニーズの変化に合わせて新機能を追加するなど求職者への価値提供を追求してきました。そのような中でビジネスモデルの変革を進めていくこととなりました。 ビジネスモデルが変わったことで求職者に期待したい行動やサイト上でのゴールも変わりました。しかし、サイト全体の体験は2019年に設計したものであったため、機能の開発をする際に既存の導線との接続であったり、体験の整合性をサイト全体と合わせるのが困難と感じることが増えてきました。 その問題を解決するためにデザインリニューアルを行い新しいビジネスモデルにそった体験を提供することとなりました。 アジャイルなビックバンリリース 前述したように今回のデザインリニューアルではサービスの基盤となるコンセプトから作り直していることもあって、画面単位、コンポーネント単位に分けてリリースをしてしまうと全体の動線の中で体験の整合性が合わなくなってしまうので、全画面の開発完了後に一斉にリリースする必要がありました。 このような大規模なリリースをしようとする際に、開発工程が完全に完了してからQAテストを行うとなると、バグが見つかったときの手戻りのコストが大きく、また、バグの度合いによってはリリース時期の延期をせざるを得ない状況となってしまいます。そのような事態になることは避けたかったので、開発工程と並行してテストを行えるようなプロセスで進めていきました。 このプロセスで開発をすすめる上で、タスクの作成方法と優先順位付けがポイントとなります。 テスト可能な単位でタスクを作成 まず、タスクの作成方法ですが、QAエンジニアによるテストの実行が可能となる単位でタスクを作成していきます。 私達の開発チームはエンジニア、デザイナー、QAエンジニアが1つのチームとなって活動しており、日々の活動の共有に加えて、チームの活動のふりかえり、さらに実装前のフェーズである要件定義なども一緒に行い、密にコミュニケーションをとるチームであることが特徴です。 デザインリニューアルのプロジェクトにおいても、普段の開発と同様に要件定義やユーザーストーリー作成のフェーズからQAエンジニアに参加してもらい、何を作らなければならないかを対話しながら具体化し、共通理解を深めながらタスクを作成し管理します。QAエンジニアは受け入れ条件を開発前から把握できるため、開発と並行してテストシナリオの作成などテスト実行に向けた準備が可能となります。 また、QAエンジニアが要件定義の場にいることで、仕様に抜け漏れがないか、不具合が入り込む余地がないかなど、QAエンジニアの観点で提案をもらうことができ、開発着手する前に不具合に気づくこともできました。 テストの優先度の高いものは早めに着手する デザインリニューアルのプロジェクトでは事業の影響度、開発コストなどの基準に加え、テスト優先度を含めて優先順位を決定し、開発・テストの取捨選択をしていきました。 基本的に事業への影響度が高いものはテストの優先度も高くなりますが、テストを効率よく進めるために以下の観点も重要視しています。 テストボリュームが多くなりそうな改修であるか 仕様が複雑そうな改修であるか テストの優先度が高いものは不確実性が高く、早期に解消しないとリリースブロックとなる可能性もあるので、優先順位付けをする中でも重要な基準となります。 副次的効果 開発・テストのサイクルを繰り返していくプロセスの副次的効果として、バグの修正が容易であることが挙げられます。というのも、開発完了からテストのフィードバックまでのリードタイムが短いため、バグ修正の際もコンテキストや実装内容の詳細の記憶を思い出す労力を多くかけずに対応できるからです。 おわりに 今回、私達は開発とテストの工程を並行するプロセスを採用し、デザインリニューアルプロジェクトを進めてきましたが、はじめからこの開発手法を確立できていたわけではありません。日々のプロセスの中で上手くいったことや課題に感じたことをチームでふりかえりながらプロセスを最適化してきました。 デザインリニューアルを終えた後もプロジェクトのふりかえりを行い、QAエンジニアが実施したシナリオテストを自動テストに落とし込んでいきたいなど課題が見つかり、今後も継続的に改善していきたいと思っています。 最後になりますが、デザインリニューアルによってカイゴジョブは求職者にとってより使いやすいサービスとなりました。しかし、求職者に提供できる価値はまだまだたくさんあると感じています。今後も求職者の圧倒的な不足という社会的な課題を解決するために、プロダクトの価値を高めていきたいと思っていますので、興味のある方はぜひお話を聞きに来てください! *1 : カイゴジョブは介護業界に特化した求人情報サイトで、2004年より展開しているサービスです。利用者はカイゴジョブのサイト上で求職者の希望に近い求人を検索し応募できることに加え、電話での求人検索や、応募手続きができます。 介護特有のこだわり条件で求人を探せることなど、介護に特化した求人情報サイトであることが特徴の1つでもあります。
はじめまして、カイゴジョブの開発をしている真下です。 皆さんは今自分が所属している会社が事業を行なっている業界に対して、興味を持っていますでしょうか。また、入社時にはどの程度興味を持っていましたか。 エス・エム・エスが事業を行う業界に対する印象 私は前職では、所謂エンターテイメントの業界でWebサービスの開発を行なっていました。当時は、この業界への強い興味があったわけではありませんが、業界全体の雰囲気が何となく面白そうだと感じて入社し、結果的には、サービスの開発自体に対して面白さを見出して働いていた思い出があります。 一方で、エス・エム・エスは「医療・介護・シニアライフ・ヘルスケア」の業界で事業を行なっておりますが、私はエス・エム・エスに入社するまでこの4つの業界での業務経験は全くありませんでした。入社する前は、これらの業界に対して元々そこまで強い興味や理解がなく、「業界に対する高度な知識や理解が必要である」という印象がありました。このような理由から、エス・エム・エスでしっかりとやっていけるのだろうかという多少の不安がありました。しかしながら、入社して約1年が経ち、これまでを振り返ると日々やりがいを感じながら楽しく業務を行ってこられたと感じております。 アンケートの実施 弊社には、例えば「クラウドベンダー」「金融」「ゲーム」といった様々な業界経験をバックグラウンドに持つエンジニアが在籍しております。 そこで、弊社のエンジニアは「医療・介護・シニアライフ・ヘルスケア」の業界に対して、どの程度興味を持ってエス・エム・エスに入社したのか気になり、アンケートを取ってみました。 アンケートでは以下の項目について回答してもらいました。 入社時、エス・エム・エスが事業を行なっている業界(医療・介護・シニアライフ・ヘルスケア)への興味はありましたか?以下の3つから回答してください。 1: とても興味があった 2: まあまあ興味があった 3: 全く興味がなかった アンケートの集計結果は以下のようになりました。 回答者のうち、入社時にはエス・エム・エスが事業を行なっている業界に対する興味を全く持っていなかった人が約3分の1を占めるという結果になりました。このアンケート結果から、弊社のエンジニアはエス・エム・エスが事業を行なっている業界以外の、別のどのようなところに興味があったのか、そして今はどのようなことに魅力ややりがいを感じているのか気になり、何人かのメンバーにインタビューしてみました。 エス・エム・エスで働く魅力 インタビューでは、以下のように様々な観点からの回答が得られました。 介護・医療などの業界に対しては元々興味がありませんでしたが、入社前に技術責任者の田辺さんから聞いた事業説明で、エス・エム・エスが事業を行なっている「医療・介護・シニアライフ・ヘルスケア」の業界そのものというよりは、その業界の中で行なっているエス・エム・エスの事業が面白そうだと感じて、入社しました。事業の面白さは入社後にも感じながら仕事をしていますが、入社後に発見した面白さとして、業務ルールの複雑さがあります。現在担当しているプロダクトには、介護保険制度が関わっていて、その制度に由来する複雑な計算ルールをシステムに落とし込む必要があります。これは難しいと感じる一方で、やりがいを感じている点でもあります。 (エンジニア) 前々職は、医療業界で事業を行う会社に所属していましたが、業界に対しては特に強い興味を持っていませんでした。そして、エス・エム・エスに対しては、なんとなく社会貢献できるイメージの会社であるという印象を持っておりました。一方で入社後には、エス・エム・エスが行なっているビジネスモデルの幅広さが面白いと感じるようになりました。例えば、現在私が担当しているカイポケはフィンテック領域に関わるような事業があったり、シニアライフ領域では食事に関する事業があったりと、「医療・介護・シニアライフ・ヘルスケア」の枠を超えて事業を行なっている印象があります。(エンジニアリングマネージャー) 前職は営業代行系の事業会社に所属しており、全く異なる業界にいました。入社前には、医療や介護の業界に対する興味ではなく、これらの業界自体の市場の拡大に興味がありました。そして、入社後に自分が担当しているサービスは、医療介護に直接関わっているというよりは、その業界で、人材紹介のビジネスモデルを行なっている構造になっています。この業界における求職者のニーズを考えるのが面白いと感じています。また、転職というライフイベントを支えるサービスのサポート戦略を考えることにやりがいを感じています。 (エンジニア) 私が現在担当している「カイゴジョブ」というサービスについても、名前から想像されるような介護サービスというよりは、むしろ求人広告サービスや業務システム開発のような要素が強く、ユーザーが使いやすい検索システムデザインを考えたり、使いやすい管理機能の開発をするといったようなことに対して面白さを感じています。 業界への関心をハードルに感じる必要はない エンジニアとして働くにあたって、自分が作るソフトウェアが使われる領域への興味を最初から持っているのはもちろん素晴らしいことです。しかし実際には、別のところに面白さややりがいを見出しているケースも多いと思いますし、今回の社内でのアンケートとインタビューでも、入社前はそこまで強く業界への関心をもっていなかった人が多かったことがわかりました。 「介護・医療・シニアライフ・ヘルスケア」と言われると「あまり身近でないな……」などと感じる人も多いかと思いますが、あまりそこをハードルに感じずに、話を聴きにきていただけるとうれしいです。
はじめに プロダクト開発部でキャリア事業のEM(エンジニアリングマネージャー)をやっている大野です。前回は、私がエンジニアリングマネジメントをするに当たってどのようなアプローチをとっているのかを紹介しました。 tech.bm-sms.co.jp 今回は、他のEMと会話している際に、「EMが取り組む施策は失敗する可能性が高いよね」という話があがり、それに対して共感できる部分もありつつ、じゃあどうすればいいのか?を考える機会になったので、まとめてみました。 EMが取り組む施策は失敗する可能性が高い? EMやそれに近しい役割を経験したことのある方なら、思い当たることがある人も多いのかなと思います。 自身の成功体験を元に組織改善しようとするが、中々変えることができない 他社のよい事例を参考に、自社での取り組みを開始したがうまく軌道に乗らない などです。 私自身も、過去こういった経験がそれなりにあり、現在でもそういった場面に出くわすことはあると感じます。 なぜそういったことが起こるのか 一概にこうだ!という理由はないと考えていて、たとえば以下のような阻害要因が経験としてはあります。 現場とEMとの温度差 現場は常に忙しく、余力がない EMとメンバーで見えているものが違い、課題として認識していない 導入時はよかったが、除々に形骸化したり廃れてしまった どうすればいいか? こういった課題を解決するために、どうすれば組織・チームが動くのかをEMは日々トライ&エラーを繰り返していく形になります。こういった答えが明確にない課題解決を繰り返していくことで、EMとしてのスキルが磨かれていくと感じています。 私自身、何かに取り組む際、最低限意識するよう心がけていることがあります。以下でそれらをご紹介します。 1. まずは情報収集 前述した阻害要因の多くは、自分の持っている情報が不足していることに起因しています。そのため、今でも1on1やエンジニア以外の職種の方と接する機会を活用し、課題感を把握するよう努めています。 2. 期待値のすり合わせ もう1つ大事なこととして、相手との期待値を合わせていくことです。 EMがやりたいことを理解してもらい、そこにメンバーも同じような期待値を持ってもらうことで、取り組みの進み方が変わってきます。 3. セカンドペンギンを意識する ビジネス用語のセカンドペンギンとは少しニュアンスが異なるのですが、勝手にそう名付けています(笑)何か新しい取り組みをする際、1人目が動いた後、2人目、3人目が続くか、同じような熱量で取り組んでくれるか、がその後に大きく影響します。 私自身、推進していく内容に合わせてファーストペンギンになることもあれば、セカンドペンギンになることもありますし、すべてメンバーに取り組んでもらうこともあります。 4. 失敗を恐れないチームづくり これは言葉のままですが、何かチャレンジしようとした際のフットワークの軽さに影響します。失敗しても問題がないことや、そもそもチャレンジを推奨するようなチームにしていくべきです。 たとえば、リファクタリングと影響範囲に伴う不具合の懸念等を天秤にかけているメンバーがいた場合には、 万一、不具合が発生してもリカバリーすればよい 合わせて自動テストを書くチャンス など、チャレンジを後押しするよう日々接することで、チーム文化として根付いていきます。このような文化を作っていくことで、EMのやろうとしていることについても「すぐにはうまくいかないかもしれないけど、チャレンジしてみよう」とフォロワーシップを発揮してくれるメンバーが増えてくるのではないかと思います。 EMの職能 上記で記載した内容は、とても重要とは思いつつも、「どういうスキルか?」と問われると一言で表すことのできない難しさがあります。 情報収集する際に、専門的な知識が必要になる場合もありますし、事業理解が必要な場面もあります。期待値を合わせていくのに、信頼関係が構築できているようなコミュニケーション能力も必要でしょう。 そういった正解が決まってないことに対して自他の強みを活かし、成果を出すのがEMで、その再現性を高めるのがEMの職能となるため、EMの職能がはっきりと定義されたものを見ないのはそういう面があるのかなと思います。 経験上、EMとしてトライ&エラーを多く経験している人ほど、上記のような自分なりのやり方の引き出しが多い印象です。 おわりに 今回は他のEMとの話をきっかけに、EMの失敗からの学びと、そこからどういった行動に結びつけて解決していけばよいかを考える機会になりました。
介護事業者向けの経営支援プラットフォーム「カイポケ」で、プロダクトマネージャー兼アーキテクトを務めている三浦です。 11月2日にオンラインで開催された、プロダクトマネージャーカンファレンス 2022(pmconf 2022)で、「日々の意思決定で使うB2Bプロダクトマネジメントサイクル」のタイトルで発表しました。 発表要旨は以下のとおりです。 プロダクトマネージャーの重要な仕事の一つに意思決定があります。ユーザー価値を生み出すために、プロダクトマネージャーはプロダクトマネジメントトライアングルそれぞれの観点から次に作るものは何か?要件は何か?作っているものはユーザー価値があるのか?など様々なイシューに対して開発チームとして日々、意志決定をしなければなりません。さらにB2Bプロダクトの場合は法令や行政、マーケット、プロダクト導入決定者の観点が加わり、プロダクトマネージャーにとって意思決定は難しいものになります。 このセッションでは、B2Bプロダクトマネジメントにおいて必要な観点が何かを整理し、どうやってプロダクトマネジメントトライアングルを使って意思決定をしていくのか実例を交えて紹介します。 (セッション内容紹介より) 2022.pmconf.jp この記事では、発表資料とともに、発表時に寄せられた質問の一部への応答・補足説明を公開します。 発表内容やカイポケの開発についてより詳しく聞いてみたいという方は、 ぜひカジュアル面談にお越しください! open.talentio.com 資料 質問への回答・補足説明 Q:複数の介護形態でペインの発生場所も異なる中で、どのように優先度をつけてきたか、これまでとこれからの話も踏まえてお聞きしたいです。 前提として、介護業界は非常に広大な市場ですので、基本的には介護業態によって市場が細分化できます。その上で、優先順位は、マーケットの大きさ、エス・エム・エスの強みがフィットするかなどの要素を掛け合わせて決めています。まずは細分化した市場を選んで、特に注意すべきペインに取り組んでいくという形です。 Q:歴史の長いプロダクトだとは思うのですが、それならではのプロダクトマネジメントの難しさはありますか? 歴史が長いので、「どうしてこういう仕様になっているのか」という仕様がわからない箇所がどうしても出てきます。カイポケは18年以上の歴史がありますので、当初のメンバーは当然ほとんど在籍していません。そうすると、仕様の「なぜ」はもはやリバースエンジニアリングで解き明かしていく感覚になります。 Q:アクセスコントロールの例で、外側のトライアングルから具体化していくのが分かりやすくていいと思ったのですが、トライアングルのバランスはどんな感じで取っていくのでしょうか まずはトライアングルの登場人物のペルソナを考えています。 開発者の市場...エンジニア 顧客(ユーザー)...介護事業、意思決定者(経営者) 行政(GTM: Go To Market)...厚労省、財務省 三者が何を考えていて、今後何をしたいのか?を意識的に考えています。その上で、例えばAという要件に対して三者が「いいよね」って言ってくれるかどうかを考えて判断しています。 Q:トリプルトライアングルを用いて意思決定するときにバーティカル SaaS ならではのアプローチってありますでしょうか?よく使うパターンがあるのかどうか気になります! 前提として、個人的にトリプルトライアングルを使うのはtoB向けがメインだと思っています。 そしてVertical SaaSになると、「ペインの深さ」だとか、「業界にいかに深く入り込めるか?」がポイントになってきますので、トリプルトライアングルの三つの角をさらに分解する、例えば顧客(ユーザー)でも「経営者、管理職、従業員」とさらにトライアングルを作って考える、といったアプローチを行っています。 Q:法令対応はドメインエキスパートのような方がいるのでしょうか?難しそうです。。 もちろんいます。介護業界からドメインエキスパートとしてお越しいただいた方もいらっしゃいますし、おなじく介護業界出身の方がPdMをしているケースもあります。 業務上の細かなやり取りや、無数に種類がある帳票などについて、どういう目的で作っていて、次の工程は何か、などを把握して開発していくには、やはりドメインエキスパートの存在は不可欠です。 Q:トリプルトライアングルの導入について、どう使えばいいかわからない?という事がありそう…つまずいたポイントなどあれば教えて下さい 外側のトライアングルから考えることは大事だと考えています。 最初は内側のトライアングルから整理していました。しかしそうすると、例えば、アクセスコントロールについて足りない観点が出てきます。カイポケの場合であれば、行政の出しているガイドラインで遵守すべき項目が定められており、これは最初から要件として取り込んでおく必要があります。 外側のトライアングル(法令)から要件を抽出していかないと「蓋を開けたら法令遵守できてないかも?」みたいなことが起こるとわかってきたので、外側からトライアングルを作り始めるようになりました。
はじめに プロダクト開発部でキャリア事業のEM(エンジニアリングマネージャー)をやっている大野です。今回は自分が見ているチームに関して、普段どういったアプローチをしているのか?という話を元に、自身のマネジメント術に関して深堀りしていきたいと思います。 一般的なEMとは? 企業におけるフェーズや組織設計で、EMが持つ役割は変わるものの、大きくはピープルマネジメントを行いつつ、プロジェクトマネジメントやテックリード、プロダクトマネジメント等組織に必要な役割を多岐に担っている形が一般的なEM像かと思います。 大野の担当範囲 私自身、前職を含めると約9年EMに近い役割を担っています。 最近だとピープルマネジメント、テックリードが主で、状況次第でプロジェクトマネジメントやプロダクトマネジメントに近い役割で動くこともあります。 マネジメントボリュームの話をすると、エンジニア30人弱をEMとしてマネジメントしており、事業としても様々な方と仕事を進めるため、ステークホルダーとしては100名超の方とお仕事させてもらっています。 よく聞く「マネジメントは多くて10名まで」という一般的な数からするとかなり多い部類になるのかなと思います。 そのため、どうやって回しているのか?と聞かれることもよくあります。 こういった背景から、今回自分の仕事術を深堀りしていくことで参考になる人も多いのでは?と思った次第です。 ピープルマネジメント編 まとめてみた結果、極力、「マネジメントコスト = 人数*時間」にならないようにしているなと自分でも理解しました。 まずは任せる メンバーと仕事を進める際、可能な限り裁量を渡すようにしています。 事業側とのコミュニケーションをどう取るか 開発におけるリファクタをどう進めるか などの裁量を渡すことで、メンバー自身が考える成長機会となり、チームの成長に結びつきます。 任せる上で大事なこととしては 狙いを伝える(裁量を譲渡すること・自分で思考する等) 失敗も経験として恐れないこと チャレンジした上でキャパオーバーするものは手伝う あたりに気をつけて伝えています。ここが認識合わせできていないと、ただの丸投げとなってしまうので気をつけないといけない部分です。 1on1よりも普段の接点を増やす これは前職で30人マネジメントすることになった際に定着したのですが、メンバーとのコミュニケーションは普段の接点を多く持つことに重きを置いています。 1on1でしか得られない高揚はもちろんあるのですが、1on1で改まって話をするより、普段の業務中に会話をしたほうが圧倒的に鮮度・頻度が増えるため、プラスになることが多いです。結果、1on1の頻度としては多いメンバーで隔週、大半のメンバーはQ単位で1回程度と一般的な1on1の頻度よりはかなり少ない形で運用しています。 リモート業務中心となり、偶発的な会話の機会が減ってしまったこともあり、業務上のコミュニケーションはSlack中心、雑談等はMTGの間のGoogle Meetでの通話等で行うことが増え、より普段の接点自体に意識を向けるようになりました。 自身もバリューを発揮する 上記のようなコミュニケーションをメンバーと取る上で重要なのは、自分が業務やエンジニアリングにおける示唆をするに値する人間であることをメンバーに知ってもらうことです。 もちろん、色々やり方はあるとは思うのですが、私自身は「背中で語る」が最も手っ取り早く効果も高いと思っています。 といっても、すべての領域で無双するような必要はなく、自身の強みをベースにチームメンバーとの関係構築を行っていくことで、エンジニアならではのスキルからくる信頼関係が構築されていきます。 テックリード編 自身の技術力 私自身、技術面に関してはそこまで尖っているわけではありません。元々、マネジメントにキャリアを歩むきっかけとしても、技術を極めていく自分が想像できなかった面もあったりします。 ただ、実際にマネジメントをやってきた結果、やはり技術力は必要だなと認識する場面は多々あります。 結果、自分としては「自チームにおいて、最も技術力が高い人と同じレベルで会話ができる」をモットーに技術面のキャッチアップを行うようにしています。 これが満たせない場合、チームでの技術的な意思決定に自分が関われず、それがビジネスに本当に必要なものなのか?の判断を間違える可能性があるからです。 メンバーの興味関心に合わせる 見る範囲が広い為、自分だけで技術面のチャレンジを行ったところで、チームには浸透しません。そのため、メンバーが今どういう部分に興味関心を持っているか、業務上どういう課題を持っているか等、メンバー個々が動機づきやすいような内容を中心に開発改善を進めることが多いです。 こういった流れ自体が定着していくことで、新たな提案にも前向きに取り組めるチーム文化ができていると感じます。チームに感謝! プロダクトマネジメント編 事業を広い視点から理解する 事業に貢献するために、事業理解の中でも「色々な視点」から事業を見ることを意識しています。 それぞれの深い部分は各担当の人に勝てないので、実際に事業面で把握するようにしているのは以下のような情報です。 大枠の事業戦略 各担当が日々追いかけているKPIとその相関 サービスを利用するペルソナ 隣のチームのHOTな話題 これらの情報をインプットとして、「事業の色々+エンジニアリング」を理解したユニークな人になるようにしています。 こうして、事業での意思決定の場で自分ならではのバリューを出すようにしています。 問題解決を進める 業務を進める上で、開発に限らず日々たくさんの問題が発生します。 私自身、どんな問題があっても必ず前に進めるというのを意識しており、これを体現していくことで周りからの信頼も勝ち取れ、更に自分に情報が集まりやすくなる好循環が生まれます。 ここで前に進めると表現したのは、必ずしも自分で解決する必要はないからです。重要なのは「大野に聞けば何かしら前に進む」と思ってもらうことなので、自分で解決してもよいですし、解決に適任な人に繋ぐこと自体にバリューがあります。 今は、メンバーにどんどん裁量を渡しているので、大野ではなくメンバーに真っ先に相談・質問が来るように関係構築を進めるよう推進しています。 また同時に、メンバーにとって困難な問題が発生した際はいつでもヘルプできるような距離感は保ちつつ、自身は比較的難易度の高い問題の解決に時間を充てられるようにしています。 おわりに 今回は、広い範囲の組織をみる上で、自分なりに行っている仕事術のような形で色々と書かせていただきました。 こういった言語化や、この記事から生まれる会話でよりEMとしても、組織としても成長していければと思います。
技術組織のマネジメント @sunaot です。エス・エム・エスで技術組織のマネージャーをしています。入社時点から技術組織全体のマネジメントを担う役割でスタートし、今年で7年が過ぎました。 「エンジニアリングマネージャー (以下、EM) の仕事とはなんですか?」と聞かれたときにその定義を答えられるでしょうか? 「1on1をすること」「メンバーの育成をすること」など、これは EM の仕事だという要素は挙げられても、全体像を言える人は中々いないのではないかと思います。そうしたときに頼りになるのは書籍ですが、EM に特化して仕事の全体像を語った書籍というのは日本語ではなかなかありませんでした *1 。 EM の仕事単体でその全体像を説明するのが難しいのにはそれなりの理由があります。この記事では、全体像を語りにくい EM の仕事というものについて、技術組織のマネジメントという視点から全体を説明し、その中で EM の果たす役割を定義するという流れで説明をしてみたいと思います。 対象となる読者の人は、 ある程度 EM としての経験があり、これからどのようによりよい EM となっていけばいいか悩んでいる人 現在 EM をしていて、より広い範囲の役割で仕事をすることが求められそうな人 です。自分で自分の仕事をつくっていく必要が出てきた人の考える土台になることを狙って書いています。 一方で、あまり対象ではないであろう人は、 これから初めての EM をするという人 です。経験をしていない人にとっては、もう少し具体的にどういう活動をすればいいのかというのをステップ・バイ・ステップで解説してくれるようなもののほうが合っていると思います *2 。 技術組織のマネジメントの要素とレイヤー それでは、技術組織のマネジメントから説明をしていきます。最初に、技術組織のマネジメントと EM の仕事の区別を説明します。 技術組織のマネジメントは、会社の技術組織全体の成功へ責任を持ち、成功のために必要な活動を設計し、実行をすることです。スコープとして技術組織という組織を対象にしています。一方、EM の仕事はスコープとしてチームを対象としています。人数としては多くて8名、最大でも15名くらいをイメージしています。 技術組織という組織が成功するためには、次のような要素が必要になります。 実現したいことと目標 体制とアプローチ アライメントと実行 組織構造 情報流通 コラボレーション 価値観と文化、モラル さらに、技術組織のマネジメントのレイヤーとしては次の3つがあります。 個人 チーム 組織 組織が、技術組織のマネジメントの要素を満たして成功をするために、各レイヤーのそれぞれで必要な活動をしていくのが、技術組織の経営です。 ここからは、それぞれの要素やレイヤーについて説明をしていきます。 技術組織のマネジメントの7要素 実現したいことと目標 これは文字通りの意味ですが、マネジメントの根幹になります。他のすべての要素のゴールでもあり、制約でもあります。その組織にとって成功とは成果とはというものを定義します。表現形式としてミッション・ビジョンや短期的にOKRのような形態をとります。 会社組織であれば、上位概念になる組織から求められることもありますし、一方でそれを鵜呑みにしないことも組織の価値になります (鵜呑みにするならサブセットになって組織固有の価値が低いため)。あとは、周辺の他の組織から求められる要求というのもあります。より広い役割の場合は社会や市場、競合他社という視点から考えることもあるでしょう。 いずれにせよ、その組織固有の価値とはなにかを考え続け、状況の変化に合わせた更新を加え続けていく仕事になります。 体制とアプローチ 実現したいことと目標、それに向けて得たい成果からスタートします。そこへ向けて必要な体制やアプローチというのは多くの選択肢の中からマネージャーと組織の能力のキャパシティの中で変わってきます。これがマネージャーを優秀な人に担ってもらうべき理由でもあります。 現在の組織能力と実現性というのは制約になりますが、基本的にはあくまで成果からの逆算で考えます。 無限の選択肢と組織能力を持っているのであれば、最善の解を選べばいいわけですが、通常マネージャーが置かれている状況はそうではありません。制約条件があり、ビジネスや開発/技術におけるセオリーがあり、その中で数少ない成功の可能性のある選択肢を選ぶ必要があります。 ビジネスや開発/技術の状況・コンテキストをどう読むのか。組織の能力や体力、マネージャー自身の得意不得意も加味して、どの選択肢に勝算を求めるのか。これはマネージャーの仕事の思考の自由度における最大の楽しみになります。 先行するのはアプローチであり、それを実現するために必要な体制を整えていくというのが基本です。体制は、採用と育成、組織づくりが支えているので実際はこれだけで一大トピックになります。 アライメントと実行 アプローチと体制から進むべき道が決まったら、今度はそれを組織的に実現していく必要があります。ここまでの内容は主に戦略と呼ばれますが、実現されない戦略は絵に描いた餅です。戦略が優れていたと評価されるためにはここから先の実現の過程が重要になります。実現の過程は地味ですが、現実の仕事で重要なのは実現とそれを支える実行です。このパートが組織が動くかの肝だと言ってもいいでしょう。ここから、それぞれについて説明します。 アライメント ここで言うアライメントは組織におけるアライメント (organizational alignment) です。実現したいことと目標に対して、組織の一人ひとりが同じゴールへ向かうように理解と意思と行動の方向をそろえ続ける活動です。アライメントという活動があるというよりは、様々な活動を通じてアライメントのとれた状態を実現していきます。たとえば、組織での方針説明会のようなものは活動の一例ですし、インセプションデッキのような活動もアライメントのための活動の一種になります。いわば、組織の照準を合わせる活動です。 実行 実行は、アライメントでそろった方向に対して進めていく過程です。現実には様々な理由で目指した方向に対して歩みを止める力が働きます。実行の過程は、個人や人と人の間に生まれる歩みを止める障害を取り除き、素早く目的地までたどり着くための活動です。戦略や方針が間違っている以前に実行をできずに物事が進まず停滞する組織というのが多く、マネージャーが新しい組織へいった場合に最初にテコ入れするのが実行の文化をつくることであるケースは多いです (一般に実現したいことやアプローチを見直すことは時間がかかるが、実行の文化をつくることは短期で成果を出しやすいため)。 実行の過程についてはマネージャーによって得意なやり方が分かれるところですが、共通する基本的な形式としては「現状把握」と「進行 (進めること)」と「進路補正 (問題の解消)」で成り立っています。たとえば、 『HIGH OUTPUT MANAGEMENT』 ではインディケーターや1on1 *3 によって現状把握をして、教育 (訓練) とモチベーションの向上やナッジングによって進行や進路補正をする手法が解説されています。実行とは、論理的には成り立っている方針に対して、実現をする過程で現れる現実とのギャップを解消しながら前へ進めていく活動です。 組織構造 組織構造は、他のマネジメント要素に対しての枠組みになります。組織の成功に向けて適した構造をとるといった形で導出されるものです。導出されるものでありながら、一度決めた枠組みは制約として働くので、継続的に狙いにあった形に変化させていく必要があります。組織上密結合にするほど、同じ目標を見ることの容易さが上がったり、日常の中での情報流通の量が増えるなどの効果が出やすいです。ただ、組織の構造によらず、狙って特定の要素を強化することは可能なので、もっとも優先したいことへ寄せて組織構造を設計して、課題が出る部分にサポートをしていったりします。特定の優れた組織構造を目指すよりも、その組織構造で過ごす中での組織のコンディションへの影響を追いかけて、主要なテーマが変わってきたら構造を見直すことが重要です。 情報流通 組織の構造ができあがったら、その中で働く人たちが仕事を主体的に進められるように必要な情報を手に入れられる状態をつくる必要があります。プッシュであれプルであれ、どこでどのような情報が手に入れられるのかという土台になる場を設計して、その場の提供をします。場は会議や定期的なイベントという実装をとることもありますし、イシューやチケット、ドキュメントのような実装をとることもあります。土台で埋まらない部分の情報について、ハブとして日常的に埋めていく活動をしたり、他の人が埋める手伝いをします。とくに組織と組織の間で情報流通が途切れることが多いので、必要な情報が相互にやりとりされるように場の設計をします。 コラボレーション コラボレーションは実行の過程で組織やチーム、個人のレベルでの相互の関係が機能するようにしていく動的な活動です。チームのレベルではチームビルディングによってコラボレーションの質と量を上げたり、個人と個人の間では協力して物事を進めるための考え方や行動に働きかけたりします。直接的にコラボレーションの機会や場をつくることもありますし、コラボレーションが活発になるような環境づくりをすることもあります。 価値観と文化、モラル 価値観や文化といったものは、会社の単位で設定されていることも多いと思います。当然それを一つの前提とするわけですが、ただ技術組織固有の価値観や文化があることが多いのと組織の状況やフェーズによって今テーマとして取り組むべきものというのが移り変わるので、意識的に扱ったほうがよいと思います。実現していくための活動としては、採用や育成、評価といったものもあれば、直接的な価値観や文化浸透のための施策、日常の一つ一つの振舞いや行動習慣に至るまであらゆるポイントで「どのような組織でありたいか」を表現していくことになります。仮に他の目的で行う組織の施策だとしても、その思考様式や表現方法は価値観や文化の表明を含むものになるため、いろいろな場面で意識をする必要があります。 技術組織のマネジメントの3レイヤー 個人 スタートは個人のレイヤーです。そもそも個人は組織のために居るわけではないので、個人が個人としてパフォーマンスを発揮できるように支援をしていくというのが一つの役割です。そして、個人は組織のために居るわけではない一方で、技術組織のマネジメントの仕事は組織の成功を実現することです。個人のレイヤーではこの個人の働きを組織の成果へつなげるための働きかけをしていきます。技術組織のマネジメントの7要素が個人のレイヤーではどのように評価できるのかを考え、個人への後押しをしたりコーチをしたりフィードバックをしたりします。 現実に個人に向き合っているときには、必ずしも組織の成果のことだけを考えるわけではありません。というよりも、目の前のマネージャーが組織の立場からしか会話をしてくれないのであれば信頼関係は築けません。個人としてのその人の立場を尊重して考えることへ100%の意識を使いながら、同時にチームや組織の視点も提供できるのがマネージャーの付加価値になります。 チーム チームは現代のサービス開発の基本単位です。そのため、技術組織のマネジメントの7要素はどれもチームのレイヤーで機能をしている必要がありますし、考えるときにもチームを主体として考えたときにどのようにそれぞれの要素を機能させるかという視点で考えることが多いです。また、一見すると個人のものに見える課題を解決するときにも、あえて「チームのレイヤーでその課題を解決するとしたら」という視点の置換をすることも多いです。個人に課題が出ているときは、その一つ上のチームのレイヤーでなにかの課題を抱えている結果であることが多いからです。 組織 組織のレイヤーで考える場合も、基本はチームを中心に考えます。物事が成し遂げられる基本単位がチームだからです。一方、チームはそれぞれに状況や成熟度合いが違います。複数のチームに対して一定の土台となる仕組みや質、成熟度合いをつくっていくには組織というレイヤーでのサポートが必要になります。チームが気持ちよく働き成果を出すことへ集中できるようにするには組織がどうあればよいかを考えていくのが組織のレイヤーです。 ここまでで、技術組織のマネジメントに必要な7つの要素と3つのレイヤーについて説明をしてきました。次回は、この要素とレイヤーに対してエンジニアリングマネージャーはどういった仕事を担っているのかを説明します。 *1 : 『エンジニアリングマネージャーのしごと』 という翻訳書が8月に出版されました。 *2 : この点、『エンジニアリングマネージャーのしごと』は期待に応えてくれる場合が多そうです。 *3 : 書籍では「ワン・オン・ワン」として紹介されています。
はじめに はじめまして。エス・エム・エスで介護事業者向け経営支援サービス「カイポケ」の開発をしている古川です。今回はエス・エム・エス内で行っていた『プロダクト・レッド・オーガニゼーション』読書会の取り組みを紹介します。 エス・エム・エスでの読書会 エス・エム・エスでは読書会が数多く行われています。チーム内で実施しているものもあれば、チームを跨いだ有志での会もあります。カイポケの開発チームは現在リモート中心で業務を行っているので、読書会もリモートで行っています。本記事でご紹介する読書会もリモートワークが主体になってから生まれた読書会です。 『プロダクト・レッド・オーガニゼーション』とは 読書会の話に入る前に、『プロダクト・レッド・オーガニゼーション』(以下、本書)について簡単に内容を紹介します。 pub.jmam.co.jp 本書はPendoの共同創業者兼CEOであるトッド・オルソン氏の著書で、原著は2020年、日本語の翻訳書は2021年10月に発売されました。本書ではプロダクトを通して顧客の獲得と維持、拡大を行う組織をプロダクト主導型組織と呼び、そのような組織がどのようにプロダクトからデータを収集し、意思決定を行っているかについて解説をしています。 私の所属するカイポケの開発チーム内で、ロードマップの作成や優先順位づけにあたって、利用データをこれまで以上に重視しようという意識が高まっていたこともあり、この書籍に興味を持ちました。 『プロダクト・レッド・オーガニゼーション』を読書会で読むことになった経緯 本記事でご紹介する読書会は、2021年4月頃から現在の形式で活動をしています。エンジニアだけでなく、プロダクトマネージャーなども参加して一緒に本を読んでいるのが特徴です。 読書会で読む本はそれぞれが候補をいくつか挙げ、最終的には参加者全員の話し合いによって決めています。明確な選定基準はないのですが、技術一辺倒の本よりも、エンジニアとプロダクトマネージャーがそれぞれの立場で読むことができ、みんなで色んな話をするきっかけになるような本を選んでいます。 そのような経緯で、これまでにこの読書会で読んできた本は以下のとおりです。 『プロダクトマネジメント』 『エリック・エヴァンスのドメイン駆動設計』 (一部) 『プロダクト・レッド・オーガニゼーション』 『プロダクトリサーチ・ルールズ』 (現在読書中) プロダクト系の読書会と銘打っているわけではないのですが、並べてみるとプロダクトに関する書籍が多いことに気づきます。 読書会の進め方 Slack上で通話をしながら行っています。進め方は以下の通りで、これを1時間ひたすら繰り返します。 読む範囲(数ページ程度)を決める それぞれが黙々と読む 読んでいる間に生まれた疑問点や感想をesaに書き出す それぞれが読み終わったところで、出てきた疑問点や感想について議論する すべて話したら次の読む範囲を決める 実際に行われた議論の例 以上のような進め方で本書を読んでいる中で、実際に行われた議論の例を紹介します。 『プロダクト・レッド・オーガニゼーション』は、さまざまな視点から幅広いプロセスについて、非常に具体的に記述しているため、「自分たちのプロダクトで考えるとどうなるだろう?」という問いが生まれやすかったです。 例えば無料トライアルの効果的な事例として、ガイド付きのセルフサービス体験が紹介されています。トライアルの中でプロダクトの価値を最大限に感じてもらうため、そこに至る準備や設定を省略し、架空のテストデータとウォークスルーのプログラムを用意することで、より短い時間で効果を感じてもらえるようになったという事例が紹介されていました。 この事例紹介を読んだあと、自分たちのプロダクトであるカイポケのトライアルについての議論が生まれました。介護サービスの提供は1ヶ月単位で行われます。そのため給付管理業務がカイポケでどこまで効率的になるのかを実感していただくためには、最低でも1ヶ月という期間が必要になります。カイポケではこの1ヶ月単位で行われる業務が円滑に行えるように設計をしています。 しかし、前述のウォークスルーの例を読んで、カイポケ内で有効性を十分に伝えられていないのではないかという疑問が生まれました。そこで、カイポケであればどのようなウォークスルーが考えられるかについて議論しました。 1ヶ月の流れを掴めるようなウォークスルーはどのようなものが考えられるのか。 そのために準備しておくデータは何か。 使い始めのユーザーがつまずきやすいポイントはどこなのか。 これらを実現するためにはどのような環境が必要か。 現状の仕組みで実現するためにはどのような設計が考えられるか。 このような論点に加えて、実際の利用状況のデータ等も参照しながら、エンジニアとプロダクトマネージャーが立場を跨いで議論することができました。 読書会を終えての感想 読書会を通じて、本書で出てくるアイデアを自分たちのプロダクトだったらどのように適用できるだろうかと考える機会が度々ありました。 また、データ分析やメトリクスに基づく意思決定の重要性が繰り返し説明されていたことも印象に残りました。業務の中でもメトリクスの整備や振り返りを進めていたところだったので背中を押してもらえたような気がします。 以下では、私の感想だけでなく、読書会の他の参加者の感想も紹介します。 プロダクトマネージャーの感想 「正しいもの」を作るためにデータを活用すること、プロダクトチームとカスタマーサクセスチームの連携、価値の無い機能は捨てるなど、全体的に取り組み始めたことや今後やりたいと思っていることに関連した内容が多く刺さる本だった。 顧客の獲得からプロダクトの改善、戦略の立案からプロダクトオプスの部分まで幅広い観点で書かれていたので、今後のガイド的に使っていけると思った。 エンジニアの感想 顧客満足度やNPSといったよく目にする指標について、それを利用する文脈・目的を含めて説明されていて、役に立った。 プロダクトを改善していくための仕組みをプロダクト自体に色々と組み込んでいくのがよいという話が多々あり、そのようなことを行おうとしていくと、システム開発の仕方にも変化が出てくるのではないかと感じた。 終わりに 現在読書会では『プロダクトリサーチ・ルールズ』を読んでいます。読書会のesaやSlackから興味を持ってもらい、新しいメンバーも加わりました。単純に参加者が増えただけでなく、カイポケではないプロダクトを担当してるエンジニアや別チームのプロダクトマネージャーが参加してくれるようになりました。 このような読書会だけでなく、エス・エム・エスでは普段からプロダクトマネージャーとエンジニアが近い距離で働いています。役割によって壁を作ることなく、共に取り組みながらより良いプロダクトを提供できるよう努力していきます。
医療・介護・ヘルスケア・シニアライフの4つの領域で高齢社会に適した情報インフラを構築している株式会社エス・エム・エスのAnalytics&Innovation推進部( 以下、A&I推進部)でデータ分析基盤開発を担当している長谷川です。 A&I推進部はエス・エム・エス社内のデータを横断的に収集し、データの分析や加工から、データに基づく施策までを行う部門で、現在は介護事業者向け経営支援サービスである「カイポケ」や、介護職向け求人情報サービスである「カイゴジョブ」のデータ分析やレコメンドシステムの開発を行っています。 エス・エム・エスは多くのサービスでAWSを採用しており、A&I推進部においてもAWSのマネージドな機能を活用してデータ分析やサービス開発を行っています。 A&I推進部とは エス・エム・エスは主に医療・介護領域を事業のドメインとしていますが、それらのうち特に介護領域は労働集約型の事業が多く、産業データ活用があまり進んでいないのが現状です。 ここ数年で介護給付費は10兆円を超え、国家予算のおよそ1/10を占めるほどにまで膨らんでいますが、日本の少子高齢化は今後も進んでゆく可能性が非常に高く、 2065年には65歳以上の高齢者が全人口の4割近くになるとも予想されています。 高齢化に伴い医療や介護の需要が増大する一方で、生産年齢人口の減少により、これらのサービスを支える医療・介護従事者の不足が深刻な課題となっています。これにより、今後質の高い医療・介護サービスの提供が難しくなると予想されます。 エス・エム・エスは、解決すべき重要な社会課題の1つとして「質の高い医療・介護サービスの提供が困難になる」という問題を捉えており、A&I推進部はその中でデータ分析を利用した介護領域への貢献を推し進めるために立ち上げられた事業部です。 横断データ分析するための環境づくり エス・エム・エスには介護・医療領域の従業者と事業所とのマッチングを業務領域とするキャリア事業部や、SaaS型の「カイポケ」など、介護・医療領域のデータが多く蓄積されていますが、個々のサービスごとにデータが分断されており、蓄積されたデータが最大限に活用されているとは言い難い状態でした。 A&I推進部はエス・エム・エスでのデータ活用を押し進めるべく、各サービスのデータを横断的に収集、安全にアクセスできる仕組みと、個人情報を匿名化したうえで配布できるデータ分析環境をAWS上に構築しました。 この仕組みはA&Iが主としてデータ分析を行いつつ、エス・エム・エスの社員が希望すれば分析環境にアクセスできる仕組みも同時に提供してきましたが、なかなか活用が進みませんでした。 「データの民主化」の誤解 データ活用が進まなかった理由として、「データ民主化」という言葉への誤解があったと思います。 我々は「事業横断でデータを集めて一元管理すること」ができ「希望すれば誰もが分析環境にアクセスできる仕組み」を提供できれば、データエンジニアやアナリスト以外の社員が自主的にデータにアクセスして分析するようになると考え、それを称して「データの民主化」と捉えていました。 しかしながらこれは完全に誤った解釈で、データの管理や環境を用意するのはあくまで手段であり、本来は「誰もが容易に集めたデータにアクセスし、分析や意思決定を行える文化を醸成すること」だったのですが、この視点が完全に抜け漏れていたのです。 データ活用が捗らなかった理由 私はエス・エム・エスに入社するまではWEBエンジニアとしてビッグデータソリューションの開発・運用に携わってきました。 そのためマーケターやアナリスト業務について深い理解を持っておらず、逆にSQLやビッグデータ基盤などの知識・経験を有していました。これが誤解を生む要因の一つでした。 SQLはWEBエンジニアのほぼ共通言語のようなものなので、欲しいデータの入ってるテーブルをいくつかJOINしてデータを集計することが当たり前でしたが、開発以外の業務ではSQLを使わないことのほうが多く、SQLクライアントに接続することの障壁が高く、さらにそのうえでSQLを書くということはかなり難しいことでした。 例えば毎日所定のフォルダにバッチ処理でDBのデータを集計したデイリーサマリを出力しているとします。 このサマリを時間別に集計したいとなった場合、バッチ処理で利用しているテーブルを特定し、集計軸を変えて正しく動くクエリを書く、ということを1からやれと言われたらエンジニアでも難しいですが、それをマーケターやアナリストが自分でやるというのはかなり難易度が高い業務になります。 また、分析そのものの難しさもデータ活用が進まなかった理由です。 分析を依頼する場合、依頼元も何をどう可視化したいのか、どこのデータを使えばやりたい分析ができるのかがわからないことのほうが大半で「時系列でマーケットシェアを出したいんです」のような依頼が来た場合、直近12か月に絞ったシェア率なのか、月次・週次は平均値なのか、その場合は移動平均なのか、などのイメージを予め固めたうえでないと可視化することは難しいです。 しかしながら、大抵の場合は「おそらくこういったデータがあれば何かが見えてくるはず」という主観的なイメージが起点となるので、手さぐり状態で可視化や分析を始め、「データを探す→抽出する→分析して可視化する」を繰り返す必要があり、A&Iの分析環境ではこのサイクルを繰り返すことに非常に多くのコストがかかっていました。 課題解決に向けて 課題が見えてきたので、分析したいことはあるが解像度を上げることが難しい事業側に対し、より高速にデータを可視化し、そのうえでそのうえで多種多様な軸で分析を繰り返すにはどうすればよいかを考えました。 A&I推進部はDWHにRedshiftを採用しているのですが、これまではRedshiftで集計したデータを一度S3に出力し、S3から各事業部のBIツールごとに異なる出力先へ出力、必要に応じてTableauなどのダッシュボード更新を手動で行っていました。 これでは最新のデータに更新するにも手動で再取り込みが必要ですし、BIツールのビジュアル更新にも時間がかかり、最新の状態でKPIを見直すことができません。 そこで、各事業部で利用しているBIツールについてはCSVデータを提供するに留め、新しい分析依頼については可視化をすべてQuickSightに集約することに方針を変更しました。 QuickSightはAWS上のマネージドサービス(S3、Athena、Redshift、RDSなど)をデータソースとしてWEBブラウザベースで可視化できるBIツールで、他のBIツールに比べても閲覧者が最大$5/月、作成者も$24/月(年間契約なら$18/月)という リーズナブルなコストで利用できるBIツール です。 QuickSightはデータソースという単位で可視化するデータを管理しており、 ほとんどのAWSのマネージドなリレーショナルデータベースに接続可能 です。 A&I推進部では事業データを集計してサマリデータを作る部分を共通バッチ化しているため、Redshiftには加工されたサマリデータの最新版が常に格納されており、QuickSightから最新のサマリデータに直接接続できるため、この仕組みを使えば可視化におけるアウトプット速度を最大化できることがわかりました。 しかしながらプロダクトとして採用するためには、A&I分析環境のルールに沿ったセキュリティ要件をクリアする必要がありました。 A&Iの分析環境はセキュリティの観点から特定のIPからのみ接続を許可しており、一般ユーザーにはAWSコンソールも開放していません。一方でQuickSightはグローバルなサービスのためAWSコンソールからログインする必要があり、アクセス元IPによる接続制限をかけることができませんでした。 これを解決するためにまずAWS SSOによるIP認証を試みたのですが、AWS SSOを通すと接続元IPがAWSのIPとなってしまい、正しい接続元IPを取得することができずこの方法も利用できませんでした。 そこでフロントにIP制限を設けたKeycloakを配置し、認証をkeycloak経由とすることで接続元IPに絞ったうえでQuickSightにアクセスする手法を採用しました。 QuickSight導入により、Redshift上の最新のデータソースに即座にアクセスしブラウザで最新のKPIを確認出来るようになりました。 またダッシュボードを見ながら「この軸を深掘りしたい」「別の軸で集計したい」という希望に対してその場で更新しその結果を共有できるようになり、一番の課題であった「多様な軸をすぐに可視化して分析」することができるようになりました。 QuickSight導入後 QuickSight導入後、可視化案件の質が大きく向上しました。 例えばコールセンターの可視化案件では、これまではダッシュボード更新の煩雑さからダッシュボードの元データをExcelで直接集計し、ダッシュボード更新が行われない問題がありましたが、今ではQuickSight上で日々のKPIを追うようになっています。 またQuickSightはSPICEというインメモリDBを利用しているためデータ集計速度が向上し、Excel集計では限界だったデータの可視化なども可能になりました。 すべてがAWSのマネージドな環境に収まった結果、今まではデータエンジニアがデータ集計し、データアナリストが可視化を行うというように、暗黙的に業務が分担されていましたが、データエンジニアがデータ集計からボード作成まで行うようになり、メンバーの業務スキルの幅が広がるという、当初想定していなかった良いフィードバックも生まれました。 昨年9月に本格導入した後、これまでに60以上の可視化を行い、うち40以上のダッシュボードが今でも活用されています。 今後の課題 QuickSight導入により分析・可視化の速度を格段に改善でき、A&I事業部と事業担当者双方が、データの解像度を揃えながら分析を繰り返すことができるようになったことは「データ民主化」の大きな一歩だといえます。 ただしこれらのダッシュボード作成はデータエンジニア、データアナリストが行うことがまだまだ多く、本来のデータ民主化である「社員誰もが独自に分析を行い、意思決定できる文化の醸成」まで及んでいません。 しかしながら今回QuickSightを導入したことで「便利そうだからやってみたい」という土壌ができ、このムードを維持しながらデータ分析に参加してもらうことが今後の課題と考えています。 また技術的には、QuickSightには異常検知や未来予測などのインサイト機能であったり、SageMakerで作成した独自モデルと統合できるなどML機能が豊富に備わっていますが、これらの機能についても十分に活用できていないため、ゆくゆくはAI機能を活用したダッシュボード開発も進めていきたいと思います。
エス・エム・エス テックブログ運営の小林と樽本です。今回の記事は 技術推進グループ長に聞いてみた・前編 「全社横断の技術アドバイザー」 の後編となります。 光宗朋宏 Tomohiro Mitsumune -技術推進グループ グループ長 Ex. DeNA 面接においてどういうことを意識されているのでしょうか? 四つ目の質問です。光宗さんはエンジニアの方の技術面接を担当されることが多いと思いますが、面接の際にどんなことを意識しているのか教えてください。 自分も面接時に、光宗さんに技術面接を担当いただいたのですが、今までの仕事について突っ込んで聞かれた覚えがあります...(笑)。 もちろん先方の経歴は事前に拝見しているのですが、「話を組み立てる能力」は特に重視しており、そこをチェックできるような面接を心がけています。 具体的には、ご自身の経歴を自由作文形式で喋っていただくようにしています。 僕がいっぱい喋ってしまうとなんだか誘導尋問のようになってしまうので、例えば「今までキャリアの中で一番大変だった仕事はなんですか?」と投げかけてみて、聞かれたことに対してどうやって話を組み立てていくのかな?という点を見ています。 エンジニアって「難しい課題に対してロジックを組んで解決するスキル」と同じくらい「組み立てたロジックを他人に説明するスキル」が大事だと僕は思っています。 なので、自分は面接中になるべく喋らないことを目標にしたりして、その辺りのスキルを見るようにしていますね。 となると、光宗さんが面接でいっぱい喋ってしまう時は候補者さんがうまく話を組み立てられなかったりで、お見送りとなってしまうパターンが多いのでしょうか? エンジニア3〜4年目のいわゆるポテンシャル枠の方に対しては、話している中でヒントを出したりすることもありますが、エンジニア15年目のベテランの方にはそれ相応の期待値があるので、そういったヒントを出すことはあまりしないですね。なので、僕がいっぱい喋ったことがお見送りの基準になるかどうかは、先方に対する期待値によって変わってきますね。 なるほど、こちらの問いかけに対するアウトプットの質でレベル感だったりを測っているのですね。 はい。これまでの面接官の経験として、一時間という時間の中で相手のことをより深く知るには「相手に多く喋ってもらう」方針は間違っていないと思っています。 面接時に意識していることとしては、「相手に多く喋ってもらうこと」ということになるんですね。 エンジニアとしてステップアップしてきた方法は? 最後の質問です。ベタですが、今までエンジニアとして働かれてきた中で、どうやって様々な壁や修羅場を乗り越えてステップアップしてきたのかというところをお聞きしたいです。 どうやってステップアップして来たかと言われると、自分で狙ってキャリアを築いてきたわけではないので偶然なところがあります。 過去に3回転職してきた中では、結局今まで自分がやってきたことの延長戦だと面白くないので「自分の手に負えないことをやりたい」とか、「明らかにレベルの高そうなところに行きたい」「ハードルがあるところに行きたい」などのマインドを持つようにしていました。そうすると壁というかチャレンジみたいなことが自然といっぱい出てくるので、それをその時々で乗り越えられるように努力してきましたね。 転職歴的なところでいうと、一社目がメーカー系で二社目が大手toCのWeb企業でした。その時の社内の風潮として、新規事業を立てたり別の会社を子会社化したりするものがありまして、その流れで新規事業として立ち上げるWebサイトの開発を希望して入ったんですね。 チームにはエンジニアが僕一人、デザイナーが一人、そしてPMとして起案者が一人いまして、起案者のやりたいこと、実現したいことをヒアリングした上で当時の競合サービスを片っ端から調べました。 人気だった他社サービスのデザインをベースにしようということになり、デザイン面はデザイナーと協力して考え、それ以外のサービスの立ち上げからは僕一人でやっていました。サーバーの知識は大学〜大学院時代に研究室のLinuxサーバーの管理者を好きでやっていたり、当時は自宅サーバーが流行っていた時代でその流行に乗っかっていたりしたので、わりかしそこら辺は得意だったので進められました。 その時エンジニア1人でやり遂げられたのは、自分が持っていた趣味嗜好と仕事がたまたまフィットしてうまくいっただけなので、狙ってやったかと言われると全く狙っていなかったです。 「手に負えないことをやりたい」と思って進んでみたら、良い方に進んだようです。なのでステップアップというか、自分を成長させるためにあえて「手に負えない」現場や環境に飛び込んできたと思います。 かなりストイックですね...。自分のできること/できないことの線引きをした上で、できないことをできるようになりたいという姿勢ですよね。 できるようになりたい、はちょっとかっこよく言い過ぎですね(笑)。 単に飽き性なんだと思います。同じことをやり続けると飽きるだけです。 大体何年くらいで飽きが来るのですか? 大体3-5年ですね。一般的なエンジニアの転職サイクルと一緒です。 なるほど...(笑)。 新規事業立ち上げのWebサイト開発を希望し入社され、そこからどのようなキャリアを進んで行ったのでしょうか? 新規事業のサービスは無事にローンチされて、社内の評判もよかったです。社内的な知名度と評価はこれがきっかけで生まれたんじゃないかなと思います。 ローンチ後の二年半くらいはそのサービスの開発と運用を諸々、サーバー監視以外は基本一人でやっていました。 その二年くらいの実績を評価してくれる人から、子会社の開発部長やらない?みたいな話をいただいて、二年以上やっていて流石にやることがなくなってきていたので、引き継ぎ資料を作って子会社に開発部長として移籍しました。 その時が初めてのマネージャー職だったのでしょうか? そうですね、初めてです。 なるほど。初めてマネージャーをご経験される中で、多くのエンジニアが悩みがちな満足のいくエンジニアリングとマネジメントの両立はできていたのでしょうか? できていたと思います。一応部長として、営業だったりデザインだったりの他部署の偉い人が集まる会議に出ていたんですが、そこで僕が喋ることは「こういうことやりたいです」でした。 結局マネジメント役でそういう場所に出ると、ある程度の裁量があるのでやりたいことを自分で決められるんですね。もちろんやりたくないこともあるんですが。 自分のやりたいことができるような流れを作っていたので、満足にエンジニアリングができていました。 ただ、忙しいっちゃ忙しかったですね...。 確かにお話を聞いているとエンジニアの数が足りていなさそうな感じはしていました。 マネジメントするエンジニアの数は4-5人と多くなかったので、マネジメントで忙しい訳ではなかったです。 タイミングとか巡り合わせもあると思うのですが、元々マネジメント志向はあったのでしょうか? 1ミリもなかったです。 ただ、その会社で働いていくうちに「この会社ではマネジメントスキルがないと、給料も上がらないしやりたいことができないな」ということはわかってきていたので、マネジメントをやりたいかやりたくないかは置いておいて、やった方が得になるなと考えました。 長い目で見ても、コードも書けてマネジメントもできる方が人として強いんじゃないかと考えてました。実際楽しくないしあまりやりたくはなかったですが、やっておいた方がいいと思ってやってましたね。 なるほど...。お話を聞く限りエンジニアリングとマネジメントの両立もできていたように思えるのですが、そのままそのマネージャ職を続けるという選択はしなかったんですか? その会社に5年いたんですけど、開発部長としてマネジメントをやるのに飽きたので転職したのが前職の大手ソーシャルゲーム企業なんです。 飽きるっていうと言葉が悪いですが、向こう3、5年同じ環境に居続けた場合と、違う環境に移動した場合で伸び幅がどれだけ違うかとか、モチベーションを保てるのか、とかが大きな理由ですね。 あとは当時の大手ソーシャルゲーム企業は、どこも有名他社と採用合戦をやり合ってて、できるエンジニアはそこら辺のどこかに行くみたいなのが風潮としてあったんですよ。なので、できるエンジニアに囲まれることで自分のレベルがどのくらいなのか客観的にわかるかな、と期待していたのも大きいですね。 やっぱりお話を聞いているとストイックなところが垣間見えるのですが、そんなことないんですかね...。 うーん、自分の実力って他人に評価してもらわないとわからない部分もあるじゃないですか。そして、同じ環境に居続けると、「どう立ち振る舞えば高い評価を得られるのか」がわかってきてしまいますし、それは評価を受ける上でフェアじゃないと思っています。それがストイックなのかはわかりません(笑)。 感覚的には、お金を稼いでる会社がネームバリューある人をいっぱい採用する環境ってメジャーリーグっぽくて、そういう憧れみたいなのもありました。 大手ソーシャルゲーム企業の時に田辺さんと一緒にお仕事されてたんでしたっけ? そうです。3年半ぐらいいて、最初の一年ぐらい田辺さんと同じチームで働いてて、仕事内容としてはエス・エム・エスにおける技術推進グループみたいなところで、僕と田辺さんは横串で開発効率改善のようなことをしていました。 前職から既に横断的にご活躍されてきたんですね。エス・エム・エスに入ってこられたのは田辺さんがエス・エム・エスに入られてからなんですか? 田辺さんがエス・エム・エスに転職してから、1年半後ぐらいに入社してます。ずっと誘われてはいましたが、少し時間が空いてますね。その時は、エス・エム・エスも一つの選択肢として考えていて、他にもいろんな会社の話を聞きつつ転職活動をしていて、最終的にエス・エム・エスに決めました。 その時はエス・エム・エス一本ではなくて、別の会社の話も聞いていたんですね。 ですね、いろんな会社の話を聞いてました。 そろそろお時間になりました。本日はありがとうございました。インタビューという名目でしたが、色々とスケールの大きい話が聞けて為になる時間を過ごさせてもらいました! キャリアの話は意図してこのキャリアに進んだわけではないので、あんまり参考にならないかもしれません。ただ、迷ったら面白そうな道を選んできたのでそれが吉と出ているかも。選択をミスっても死なないですし、売り手市場なのでなんとでもなるでしょう、という気持ちでキャリアを選択してみて良いと思います。 (完) tech.bm-sms.co.jp
9/10 に閉会をした RubyKaigi 2022 へ Shuttle Bus Sponsor として参加しました。 今年の RubyKaigi では現地参加をする人がどのくらいいるのかが読めなかったため、スポンサーブースを出すことやノベルティの配布をせず、明らかに必要があるだろう Shuttle Bus Sponsor 1 本に絞って参加をしました。 蓋を開けてみれば、スポンサーブースも大盛況で「これは我々もスポンサーブースを出せばよかった!!」と若干の後悔もしながら各社のスポンサーブース巡りを楽しみました (今年の様子を参考にして、来年はスポンサーブースの出展もしていこうと一足先に心に誓いました)。 Shuttle Bus Sponsor 1 本に絞ったのは、アイデア一発勝負よりも、明らかにニーズがあるところへビジネスをつくりに行くという社風が現れた参加の仕方だったとも思うのですが、自社のスポンサーブース出展をしていなかったため、ほとんどの方へはエス・エム・エスという会社を知ってもらう機会をつくれていません。 もし、どんな会社かわからないので話を聞いてもいいよという方がいたら、Twitter アカウント エス・エム・エス@RubyKaigi 2022 や sunaot や採用担当の fkc_hr への DM や この記事の案内ツイート への LIKE をください。LIKE をもらえた方へは連絡をするようにします。また、記事末尾からは Wantedly からのカジュアル面談の申込みも受け付けています。 「RubyKaigi の土産話をして余韻を楽しみたい」「ただ技術の話をしてみたい」「カジュアル面談で会社の話を聞いてみたい」などなど、どんな形のご興味でも大丈夫です。もちろん、現地参加はしていない方からのご連絡も歓迎です。 LIKE やご連絡お待ちしています! RubyKaigi 2022 に参加していたメンバーのブログ記事 tech.bm-sms.co.jp tech.bm-sms.co.jp tech.bm-sms.co.jp Wantedly 経由、カジュアル面談への申込み
はじめに はじめまして。2022年4月より、介護事業者向け経営支援サービス「カイポケ」のプロダクトマネージャー(以下PdM)としてエス・エム・エスに参画した小場(コバ)です。 今回は、前職で基幹系パッケージ製品開発に携わっていた私が、どのような経緯でカイポケのPdMになったかについてお話ししていこうと思います。 よろしくお願い致します。 前職の仕事について 前職では自社開発の人事統合パッケージ製品を企画する立場にあり、世間で「基幹系エンジニア」と称されるSEをしていました。 扱っていた人事統合パッケージには、人事管理(従業員の個人情報管理、配属及び移動処理、採用・退職処理、考課など)、勤怠管理(残業時間や有給取得状況の管理、シフトの作成など)、給与計算(月々の給与・賞与計算、年末調整、源泉徴収票の発行、所得税や控除項目の計算など)の機能があり、人事部や労務・給与担当者、採用担当者など多彩なステークホルダーの要望に応える必要がある製品でした。 元々は開発エンジニアであったことから、次期製品バージョンに入れ込む新機能や頻繁に発生する法改正にプロダクトとしてどのように対応・設計-実装していくかについて考える、所謂「製品企画」をメインミッションとしていました。 新しいチャレンジ(企画)をする際には、事前にその効果を検証する作業や、オフショアを含めた開発チーム内への情報連携、上司や決裁権者へ開発内容を説明する必要もあったため、必然的にチーム内で手薄だった領域のキャッチアップを行う担当になることが多くありました。 主な例としては「UI改善を行う上で必要となるコンセプトの立案」や「DBのパフォーマンスチューニング」、「AIを用いた機能の開発」、「オフショア先の管理」など多種多様なもので、製品企画と言いつつも新しいことを始める上で要員や技術スキルの調達が追いつかなかった時にはエンジニアやプログラマーとしての仕事もこなす「何でも屋(何でもやらざるを得ない屋)」のポジションにいました。 製品企画というファジーなポジションで幅広く、様々な経験をさせてもらった点は前職に感謝しております。 転職を考えたキッカケと転職の方針 30代後半に差し掛かり自身の今後のキャリアを考えた際に、以下の点に不安を感じるようになったことがキッカケです。 各々の要点に対して、お世話になった転職エージェントの方と共に方針を立て転職活動を進めました。 ①ITに関わる人間としてオンプレミスのパッケージ開発経験のみで今後大丈夫か? SaaS 型の製品や SaaS を用いたビジネスに携わる経験をすると共に、 SaaS におけるシステムのライフサイクルについて理解を深めたいと感じました。好きか嫌いか/合う合わないはやってから考えることしました。 → SaaS 型の製品・ビジネスを展開している企業を転職先のターゲットとして見据えるようにしました。 ②良くも悪くも『何でも屋』過ぎてアピールポイントが分かりにくい。 中途採用の面接において、ほぼ100%質問される自身の長所について、スペシャリストよりもゼネラリストよりのスキルセットになっていることに気づかされました。 →現状の全方位型のスキルセットを生かしつつ、重心をずらすことで特徴を出していく方向で職種を探すようにしました。 また、製品に対してより広い範囲でオーナーシップを持って活動できる職種を考慮したところ、 PdM が一番理想としている形に近い立ち位置の職種であると感じるようになりました。 ③前職の「基幹系」というビジネスドメイン色が強かったためか、同業種からのオファーが非常に多かった。 基幹系システムを取り扱う企業からドメイン知識をベースとした転職オファーが圧倒的に多く、仮にそれらの企業に転職したとしても環境や取り扱う製品を変えるだけの転職になる可能性が高い(仕事としてのミッション自体は前職と代り映えしない)と感じていました。 →基幹系以外のビジネスドメインの企業の中で、基幹系機能の知識を活かせる業務特化型ビジネス(メインの機能の他に、事業を運営する上で必要となる業務を行う基幹系機能が携わっている製品)を展開している企業をターゲットとすることとしました。 この大まかな3方針を軸として、より社会的に課題感がある領域に対して挑戦することができる企業を探すことにしました。 エス・エム・エス/カイポケとの出会い そんな中、転職エージェントから紹介された企業の1つがエス・エム・エスでした。 エス・エム・エスは少子高齢化が進む日本において、「介護事業者の経営改善とサービス品質の向上に貢献する」ことをミッションとして掲げており、「カイポケ」という SaaS プロダクトのPdM職が上記の①、②の方針を満たしていました。 同時に世界で一番少子高齢化が進む日本で、この社会課題の解決に取り組むことは仕事をする上で意義のあるものだと感じました。 カイポケは「ケアプラン作成・連携」、「実施した介護の予実管理」、「予実を基にした保険料請求の支援」機能といった介護事業者の業務を支援するプロダクトです。 また、カイポケは上記の介護事業特有の業務に関わる機能以外に、介護事業者が事業を運営するために必要となる機能(世に言うところのERPのような機能)を多数サポートしており、前職で関わっていた「給与計算」、「勤怠管理」、「シフト作成」等の経験や知識がカイポケであれば活かせるかもしれないと感じたことが決め手となりました。(上記の③の方針に該当) 現在の業務について/カイポケの開発現場について 現在は(当初の転職の方針通り)カイポケのPdM職として、給与計算や勤怠管理といった「介護以外の機能」について、今後のカイポケのあるべき姿を考え-実現する役割を担当しています。 入社の段階では肝心な介護に関する知識が0の状態であったため、オンボーディングや社内に在籍している有識者に意見を求めることで知識を補完してプロダクトを形にしていっています。 例えば、介護事業者の給与計算において、介護職員に対して介護報酬を加算して支給する制度(この制度の事を「処遇改善加算」と言う)があり、持ち合わせていた給与・労務管理の知識に介護ドメイン特有の知識を組み合わせることで、より理解が深まるという経験をすることができました。 また、入社当初はテレワーク主体でのオンボーディングに不安を感じておりましたが、上記のようなフォローもあり、違和感なく業務に入っていくことが出来たという印象です。 カイポケの開発現場の雰囲気については、転職者が多く在籍しており、私のように前職のビジネスドメインが介護ではないというメンバーの方が多いという印象です。 逆に様々なバックグラウンドを持つメンバーが揃っていることによって発生しているシナジー効果を感じると共に、多様なタイプ/働き方のスタンスのメンバーを受け入れることができるエス・エム・エスの懐の深さを感じています。 最後に 私のような基幹系エンジニア出身であっても、「介護の知識」をキャッチアップしつつ、「介護以外の領域」で手腕を振るう事ができる点は、介護事業者に対して包括的に機能提供をしているカイポケならではの魅力であると感じています。 「介護」という言葉を意識せずに、話を聞いてみると「畑違いの経験」を活かすことができる可能性や共通点など、思わぬ発見があるかもしれません。 この度は基幹系エンジニア→カイポケのPdMの話ではございましたが、現在弊社ではPdM、エンジニア、EMなどプロダクト関連職種を広く積極採用中です。 もし弊社に興味をもっていただけましたら、ぜひカジュアル面談にてコンタクトをとって頂ければと思います。 最後まで読んでいただいて、ありがとうございました。
エス・エム・エス テックブログ運営の小林と樽本です。 前回の田辺さんインタビュー に続いて、「エス・エム・エス社員に訊いてみた」第二弾は弊社の技術推進グループ長である光宗さん( @mitz )です。 光宗朋宏 Tomohiro Mitsumune -技術推進グループ グループ長 Ex. DeNA Q1.現在所属している技術推進グループの具体的な業務内容を教えてください 本日はよろしくお願いいたします。一つ目の質問として、光宗さんが現在所属している技術推進グループでは具体的にどんなことをやっているか教えてください。 現在技術推進グループというグループに所属しています。グループには四人いて、全員がバラバラの業務やタスクを行なっている状況ですね。各メンバーごとに得意な領域、例えばインフラとか、アプリケーションとかを持っていて、様々な角度から依頼が技術推進グループに来ます。依頼の内容は、各種サービスの改善や業務効率化、解決のレベルが技術的に高い課題などがあり、R&D(Research & Development)的な側面を持っています。 具体的な最近の業務だと、ハピすむというサービスのAWS寄りのインフラ周りのSRE業務を1年半くらいやっているメンバーがいたり、僕が手伝っているものだと、カイポケリニューアルのアーキテクトチーム(技術的方向性、技術選定)の話し合いに参加して知見を出し合っています。このプロダクトは、数人単位の複数チームがバラバラに仕事をしているので、ルール決めだったり方向性だったりを落穂拾い的に決めています。その中でも僕はAWS、フロントエンド周りで活動しています。 過去の業務で言うと、一つのプロダクトの機能改善よりも、もっとインパクトのあることをすることが多く、例えばカイポケのオンプレからクラウド移行時に「そもそもどう進めていけばいいか」の検討から入るPM的なこともやっていました。 他にもプロダクトを限定せず、例えばMySQLのパフォーマンスがめっちゃ落ちた時はパフォーマンスチューニングをひたすらやっていたり、サービスにNew Relicを導入して改善ポイントを指摘したり、カイゴジョブのフルリニューアルをする際にプロダクトオーナーをしたり、社内で元々あった技術的負債が多すぎたサービスのフルリニューアルを手伝ったりしています。開発リソースが少ないところの技術アドバイザー的なことをやっていたりが多かったです。 (インタビュアーがたまたま中途面接の時に光宗さんに面接を担当してもらっていたので) 入社から2年経ちましたが、社内事情を知ってから光宗さんの話を聞くと、かなり横断的に業務を行なってらっしゃるのが鮮明に想像できますね…。面接で初めてお会いした当時からフルスタックエンジニアのイメージが強いです。 開発に関係ないところで呼ばれたりもしますからね。バックオフィスとか、法務やコンプライアンスを担当する部署とか…。 どういった背景でそういう場所から呼ばれるのでしょうか? 例えば法務やコンプライアンスを担当する部署の話だと、グループ長の方から「こういうことをやりたいんだけど、エンジニア目線でどうだろうか」っていう感じでお話を受けて、「実際に手伝ってくれ」と相談された流れのまま手伝うことが多いです。インフラ周りの話が多いですね。 実際に手を動かしたものの話だと、数十を超えるサービスのプライバシーポリシーやサイト規約みたいなものって、元々はワードファイルで個別管理されていたのですが、それをGCP上で管理できるような社内システムを作ったりもしました。 バックオフィス系で軽いところだと、外部のクラウドソーシングのリソース管理をスプレッドシートでやっていたものを、スプレッドシートのイベントフッキングを使用して社内のチャットツールに連携する仕組みを作って業務効率化したりしていました。 一般的なエンジニアよりもかなり広いことをやられているのですね。全社的に困っているところにスポットで入って、改善していくみたいな…。 そうですね。エス・エム・エスに入社する前はエンジニア一人、デザイナー一人、PM一人みたいな状況で仕事をすることが多かったので、「なんでも自分でやらざるを得ない」みたいな経験を積んできましたこともありますし。 技術推進グループのメンバーも光宗さんみたいなご経験を積んでこられた方が多いのでしょうか? それぞれキャリアパスは違いますが、幅広く経験して来られた方が多いです。インフラに強いメンバーだと、toC、toBの大きな企業にいた方とか。 なるほど、異なったキャリアパスを歩みつつも、幅広い経験を持った方が多いと。 メンバーは各自バラバラに仕事されていると伺いましたが、ペアとかで一緒に仕事されることはあるのでしょうか? ペアっていうのはありませんが、定例MTGみたいなのはあって各自進捗とか状況を共有することはあります。その時に、各自の得意な領域を背景に、チームメンバーにアドバイスしたりすることはありますね。 各メンバーがそれぞれ別々の仕事を行なっていく、というのは自走力というか一人で完結できる能力をもってないと難しそうですし、皆さんきっと高い能力をお持ちなのだろうなと思いました。 そうですね、プレイヤーとして一通りはできて、何かしら得意領域がある方達ですね。 それと単に技術ができるだけではなく、技術がわからない人や、特定のレイヤーに弱いエンジニアに対してわかりやすくコミュニケーションを取る必要があるので、そういったことができないと技術推進グループのやっている仕事的には辛いものがあると思います。 わかりやすく説明するにはかなり高度なスキルが要求されますが、技術推進のメンバーはそこらへんができる人が集まっています。 Q2. 弊社に入社を決めたきっかけは? 二つ目の質問です。エス・エム・エスに入社することを決めた「決め手」みたいなのはあったのでしょうか?○○さんが在籍していたからとか...。 内部の状況は色々聞いていたのでよく知っていたのと、面接の中でCEOの後藤さんと話をする機会があって、それが決め手になったかもしれないです。面白いCEOだなという印象でした。 他の会社の話を聞いた時にも、割とCTOやCEOが出てきてくれて話をする機会が多かったのですが、その中でも面白い人だな、と思って、そこに惹かれたのが大きいですね。 前回インタビューした田辺さんも入社したきっかけに後藤さんをあげていたような記憶がありますね。具体的に後藤さんのどの辺が面白い人だったのでしょうか? CEOとしての視点だけではなく、現場感も大きく持っていて、すごく高性能なCPUを搭載している気さくな人、という点でしょうか。普通の会話の中で、「この人すごいな」と思わせるところがどこかありました。 頭の回転が早い、とかですか? 頭の回転も早いし、とてもロジカルです。いろんなことを抽象度高く話せる人ですね。そこに惹かれたところがあります。 エンジニアでグレードの高い人は確実に後藤さんの面接が入るので、「後藤さんから見たエンジニアは?」みたいな話を聞いてみても良いかもですね。 Q3.光宗さんの思う弊社の魅力は? 三つ目の質問に移ります。面接というフィルターを除いた時、エンジニアとして光宗さんが思う弊社の魅力ってどんなものがあるのでしょうか? 結構あるのですが、1つは「技術的な選定において、担当の開発チームに主導権/決定権があること」ですかね。 実際に社内でJavaだったりRubyだったりPHPだったりGoだったりいろんな言語が使われているのはそれを表していますし、魅力的だなと思えるポイントです。 2つ目は、「プロダクトに対するエンジニアの裁量権が大きい」ことですね。個々のチームの規模が小さい傾向にあるので、プロダクトを開発する上でただコードを書くだけではなく、プロダクトをどうしていくのか、という根幹部分にも関わっていくことができます。 当たり前のことを言っているようですが、これが実現できていない組織は多いです。 また、「プロダクトが社会的貢献性の高いものである」ことも魅力だと思います。 確かに、自分も常々感じています。最終的なアウトプットさえ帳尻が合えば、そこに至るプロセスは問われないですね。チームごとに使っているツールが違いますし、開発スタイルも委ねられている印象があります。 僕は前職大手ソーシャルゲーム企業だったのですが、そこだと「エンジニアはコードだけ書いていればいい風潮」がありました。それを突き詰めたい人にはいい環境だと思うのですが、エンジニアとしてビジネス、プロダクトに大きく関わっていきたい場合は弊社の方がフィットしているのかなと思います。 プライム上場企業でありながらベンチャーっぽい、というのは一つの特徴ですね。 新しい技術にチャレンジできる環境やプロダクトに対する意思決定のチャンスが魅力だということですね。 僕はそこら辺が好きなんですが、あまり自由にしすぎると会社として管理していけなくなってしまうので、最低限のルールは必要だと思っています。非常に難しい問題ですが...。 (後編 ↓ へ続く) tech.bm-sms.co.jp
🔥株式会社エス・エム・エスは、2022年9月8日(木)〜 9月10日(土)に開催される、「 RubyKaigi 2022 」にて Shuttle Bus Sponsor としてシャトルバスを運行します。 ご利用方法については RubyKaigi の Venue ページをご参照いただければと思いますが、同様の内容を下記に日本語でご案内しておきます。 rubykaigi.org 乗車方法 乗車の際、スマホで RubyKaigi 公式ページの乗車用画像や こちらの画像 をバス搭乗口にいるスタッフにご提示いただくか、「エス・エム・エス シャトルバスを利用します」「RubyKaigi シャトルバスを利用します」とお伝えください。運賃は無料です。 スマホでのシャトルバス画像表示イメージ 運行ダイヤ・乗降場所 ■ 会場行シャトルバス 「津駅臨時バス乗り場 ⇒ 三重県総合文化センターメインエントランス」のバスです。 ※全ての日程で5分〜10分間隔で順次出発します。 2022年9月8日(木) AM9:00 〜 AM10:30頃まで 2022年9月9日(金) AM8:00 〜 AM9:30頃まで 2022年9月10日(土) AM8:00 〜 AM9:30頃まで 【RubyKaigi 2022 会場行きバスの乗車場所】 津駅臨時バス乗り場 ( Google Mapでの確認はこちら 、 Street Viewで付近の様子を確認はこちら ) 津駅臨時バス乗り場地図 ■ 会場発シャトルバス 「三重県総合文化センターメインエントランス ⇒ 津駅臨時バス停」のバスです。 ※津駅臨時バス停行きは全ての日程で5分〜10分間隔で順次出発します。 ※津みなとまち港行きは最終日の1本のみの運行です。ご注意ください。 2022年9月8日(木) 【津駅行】PM17:30 〜 PM18:30頃まで 2022年9月9日(金) 【津駅行】PM17:30 〜 PM18:30頃まで 2022年9月10日(土) 【津駅行】PM17:30 〜 PM18:30頃まで 【会場から津駅臨時バス停行きバスの乗車場所】 三重県総合文化センター メインエントランス付近 ( Google Mapでの確認はこちら 、 三重県総合文化センターフロアマップはこちら ) 三重総合文化センターフロアマップ 【乗車時提示用画像 / 現地案内スタッフ】 各乗降場所には三重交通様にご協力いただき、案内スタッフを配置しています。 手持ち看板 / 乗車時提示画像 【特記事項】 実際のシャトルバスに 株式会社エス・エム・エス のデザインは施されていません。 運行の都合や交通状況によって、シャトルバスの運行間隔が前後することがあります。 座席にお忘れ物のないようご注意ください。 満席で乗車できない可能性がございます。ご了承ください。 COVID-19 など感染症リスク回避へご協力ください。 乗車中はマスク着用、飲食禁止でお願いします。 その他 本シャトルバス運行用 Twitter 基本的には前述の内容で運行させていただきますが、シャトルバスの運行情報などについてアナウンスの必要性が生じた場合にはこちらから発信いたします。 また、Rubyを活用して社会基盤となるサービスを提供している株式会社エス・エム・エスにご興味のある方は、RubyKaigi 2022 開催中、こちらのアカウントへのDMも歓迎します。 twitter.com 採用情報
エス・エム・エス テックブログ運営の熊谷です。今回の記事は sunaotに聞いてみた・前編「『言われたとおりに』が何より苦手」なプログラマーがエンジニアリング組織のトップになるまで の後編となります。 田辺順 Sunao Tanabe -技術責任者 Ex. DeNA 外資生保のSEやWebの会社のプログラマーを経験後、DeNAにて技術支援チームの立ち上げ、SET/SWETとして自動化や開発者テストの開発支援に従事。エス・エム・エスでは技術責任者として、開発組織づくりや開発基盤の整備などを進める。 Q2. 田辺さんが CTO を名乗らない理由って何かあるんですか? 田辺さんは「技術責任者」を名乗っていますが、あまり一般的な呼称ではないなと感じています。CTOを名乗らない理由は何かあるのでしょうか? 「困っていないから」というのが大きいです。名乗ると何が得られるのかがわかっておらず、明確に実務的に裁量が増えるなら、本部長になることや役員になることのほうが明らかに自分の責任において決められることが増えます。 ではそれが今欲しいかというと、そうは感じていなくて、今私が決められないことというのはほぼすべて全社に依存することか、事業と重なる部分の話が多いです。 もし仮に自分が CTO の名称なり、本部長や役員なりだったときに、相互に依存する事情を無視して物事を進めたいかというと、そんなことはないです。その場の意思決定のスピードは上がるけれど、その割り切りによって学びの機会や相互理解の機会を失うことになるからです。 ということで、自分が今必要としている範囲の裁量は持っていて、とくに困っていないからというのが理由です。 あと、個人的なところで気づいた点としては、価値観としてそもそも役職やポジションというものを欲していなかったというものがあります。今まではそういうものがなかったので、もう少し人並みに役職やポジションへの欲があるかと思っていたのですが、実際に技術組織のトップの役割をやってみて、自分が必要としているものを満たせば、役職やポジションの名称というのは本気でまったく欲していなかったということに気づきました。漫画の『昴 *1 』で「あたしは…そう。尊重されたいの。あたしがバレエをやる理由はそれ。尊重されて生きるため。」というセリフがあり、それを読んだときに自分が求めていたのもこれだなと納得したのを覚えています。根本の価値観として「自分が良い仕事をして世の中に価値を提供をする。それにあたって必要になる信頼を得られる程度の尊重がほしい」というのだけを必要としているのだと思います。自分にとって肩書きが寄与してくれるのはその尊重へ寄与する一部で、幸い今の会社は「その人がなにを言っているか。それはなぜか」ということへの関心が非常に強く、そこで中身があればあまり肩書きは重視されないため、少なくとも社内では必要性を感じていません。 入社から室長/部長ととくに職位は変わっていないけれど待遇としては変わっていっているので、その辺も自分の組織でもやりたいこと (肩書きへの依存を極力減らして、そこと関係なく能力によって評価され待遇が上がっていく) であるし、肩書きが強くなると暗黙に他の人と関わるときに発生する 権威勾配 も好ましくないし、積極的に欲しくないなーという風に思っています。 ただ、個人の話とは別に、なにかしらの理由で CTO がいる/経営層に技術職出身の人がいることを重視している人がいることは知っていて、本当にそれがうちの会社でも必要だと思えたら、積極的に CTO なりのポジションを拒否をするほどの理由もないなと思っています。 Q3. 田辺さんから見たエス・エム・エスならではの楽しさというか良さみたいなものはありますか? 戦略とビジネスがセオリーを土台にした上で、実践で具体性高く実行されていく様を見られることですね、特に事業責任者レイヤー、事業戦略レイヤーで感じます。 「そんな風に考えるんだ」「そんな物の見方するんだ」など、自分にはできないなと思う発見をする機会が多いです。その結果、過去読んだセオリーが自分のなかで腑に落ちて、自分でも使える道具になることが何度もありました。 事業の成長という形で、その実践が世のなかで結果を出せるんだという証明とセットで過程を見ていくことができ、知識だったものから使える道具と使えない道具が検証されている感覚になります。 これらの戦略やビジネスの強さというのが、特定の個人や一過性のもので作られているのではなくて、過去からの連綿とつないでいる経営の歴史のなかで意識的にそうなるように作られてきている、というのが非常に特異で面白い会社だと感じています。 「社風や文化、価値観として場をつくってきた」というのは他の会社でも見受けますが、それ以上に日常の会社運営も「戦略やビジネスの強さを会社として持ち続けられるようになること」を土台とし、 ”そうなるように会社を経営しているからそうなっている” というのはユニークな価値だなと思っています。 また、それをセオリーや仕組みだけでやろうとするのではなく、あくまで人に依存して人が優秀だと最大パフォーマンスを出せるぞという思想も持ち合わせてるため、 XP の洗礼を受けた私としては『人間性 (Humanity) / 人間がソフトウェアを開発する』に通ずる価値観を感じていました。 最後に、「相手へ誠実さを期待できて、変な気を使わずに本当にするべきことに集中しやすい」というのもならではの良さかなと思います。特に私の場合、ムダだと思うことを受け入れて粛々とやるというキャパが小さいので… Q4. 将来的に作っていきたい組織の理想像みたいなものはありますか? これまでも自分が転職をする際に、「少なからず自分にフィットする環境ってどこかにあるんじゃないか」と思って転職してきた経緯はあります。 実際どの会社も良いところはたくさんありましたが、「自分のやりたい仕事の仕方を全部できる会社」は無かった。そして 4-5 社を経てさすがに気づいたことは、自分の求めているような会社は多分ないぞ、ということです。だったらそれに近い環境を作りたいなと思ってエス・エム・エスに入社したというのがあります。 そのなかで今も残っている軸がいくつかあって、1つ目に「チーム開発大事だよね」という価値観。世の中が今ほど「チーム開発」って言い出す前に、チーム開発への思いとずっとやりたいなというのがありました。 2 つ目にプロダクト開発として見たときの「ユーザー中心設計(UCD)」で、「企画の思いつき」ではないユーザーを中心としたプロダクト開発がしたかった。 3 つ目は「ビジネスとエンジニアリングとの関係性」みたいな部分です。今までどちらか二極の会社しか経験してこなかったので、ビジネスのいいなりという開発組織も嫌だったし、逆にエンジニアがヒエラルキーのトップというのも嫌だったんですね。「僕もあなたも同僚だし、一緒に良いビジネス作って、ユーザーに価値届けたいですよね」っていうのがとにかくやりたかったんです。お互いの関係性がフラットで、気持ちよく働けていけたらいいなって当時から思っていました。 この 3 つすべてやれそうな会社が、僕の思いつく限りでは見当たりませんでした。スモールビジネスだったらいくつかあったと思うんですけれども、ちゃんと成長余地があって、かつ一定規模のインパクトを世の中に出せる会社でやりたかったんですよね。 これらの条件を全部兼ね備えている会社が僕の知る限りではなかったので、エス・エム・エスでそれを作ってしまおうというのがありました。あとは組織の話からは若干ズレますけど、 「継続性アーキテクト」という生き方 でも書いてあるとおり、ちゃんとコードを書き続けながらお金がもらえるような会社が良かった、というのもあります。 自分のポジションがまだ事業責任者から遠いポジションにいるせいか、簡単なコミュニケーションはあれど、まだ距離は遠いかなと感じる部分もあります。「俺は技術やってくぜ」っていう人はいいと思うんですけど、ビジネス側との距離をどのように縮めていけば良いか、自分のなかではまだはっきりしない部分もあります。 そこは同じく課題感を持っていて、これは採用の話とも絡むんですが、エス・エム・エスはシニア層の採用比率を多くしています。 エス・エム・エスはディレクターが何かと開発に依頼をしてくるみたいな会社ではなく、プロダクトマネージャーだったり、エンジニアとして技術とビジネス両方の話ができる人たちが事業責任者と直接喋って、「この事業戦略だったらこうしないとダメなのでは?」「こうする必要があるよね」という話を直接行なっている会社です。そのためシニアクラス程度の経験が無いと、ビジネスの話を事業責任者と上手くできないという課題があるんですね。 これらは良いことなんですが、 エス・エム・エスの事業責任者たちは、僕が今まで見てきた人と比べても、世の中で有数に優秀な人たちなんです。 戦略リテラシーも高く、まずマーケッターとして優秀だなと。反面、そのための専門知識も当たり前にあって、その人が持っている知識量とか、今どういう視点で喋っているんだろう、ということを理解しながら、適切にプロダクトの話やエンジニアリングの話に変換する能力が求められるわけです。 これらの理由から、会社としてシニアクラス層が足りないと事業スケールのボトルネックになってしまうため、ここの採用に力を入れています。 とはいえ採用だけではなく、社内での育成体制を整えていきながら事業責任者とやり取りできる人を育てていく道筋を作らないと、と思ってはいますが、まだうまく形にできていません。これらの事業戦略直結な人材を育てていくことができれば、シニア採用に頼らずとも層を厚くできますし、ジュニアやポテンシャル採用もさらにしやすくなるはずです。それによってより多くのビジネスが実現し、価値提供ができると思っています。 (完) tech.bm-sms.co.jp *1 : MOON ー昴 Solitude standing ー 1 巻 p203