Customer Reliability Engineer の発展的な職務領域についての覚書

Customer Reliability Engineering とは

現在の自分は B2B SaaS の技術サポートを提供するチームの中で Customer Reliability Engineer (CRE)として働いている。

Customer Reliability Engineering は 2016 年に Google が提唱し始めた職務領域で、Google 社内で蓄積した Site Reliability Engineering のノウハウを Google Cloud ユーザーのアプリケーション(サイト)にも適用してコミットしていこうというアプローチだ。つまり、Google が提唱する CRE は Customer('s Site) Reliability Engineering のようなものと言える。

そのミッションは、 Drive Customer Anxiety -> 0 のように表現されていて、Reliability と Anxiety の関係は Anxiety = 1 / Reliability であると書かれている。その理念に共感したフォロワー企業は日本でも多数生まれ、例えば Mixi, Hatena, Soracom, Mercari などが CRE と名前のつく部署を立ち上げている。

一方で、その職務領域は各企業ごとに異なっており、技術サポートチームを CRE チームとして名前を変えたものや、セールスエンジニアに由来を持つものなど、当初の Google が実践してきた職務領域の枠に囚われず、試行錯誤を進めている。

各オペレーションへの SRE の方法論の応用可能性

SRE の職務に関しては O'Reilly の書籍 Site Reliability Engineering に詳細がまとまっているが、Kazunori さんのこの「ソフトウェアエンジニアが作った運用チームとしての SRE」という言葉がわかりやすい。

SaaS を成功させるためには、さまざまな要素を担当するチームが必要で、それぞれに日々のオペレーションがある。SRE は DevOps というインターフェイスの実装であるように語られているが、そこから考えを進めて DevOps 以外の Ops である ProductOps、CustomerSuccessOps、SupportOps などの SaaS を提供する上では欠かせないファンクションにおけるオペレーションにも、それぞれにその精神性や方法論が横展開できるかもしれない。

既にそれぞれの Ops ロールの必要性は認められポジションとして存在するとは思うが、その技術職として可能性がこのような文脈で語られるのはみたことがなかった(もちろん既に高度に実践している企業もあるとは思う)。そこで、発展的に CRE にそのロールの一部を担わせることができるのではないかと思っている。

Embedded CRE

各オペレーションの具体的な業務は、例えば ProductOps なら製品の利用状況の開発へのフィードバック、CustomerSuccessOps ならカスタマーヘルスダッシュボードの構築や Churn / 売上予測、SupportOps ならサポートツールの開発やスループットの改善などが考えらられる。

これらの業務はカスタマーサクセスマネージャー、プロダクトマネージャー、カスタマーサポートが片手間で(もしくは専属のポジションとして)行う、それか社内で他業務を主としているエンジニアやデータサイエンティストなどに依頼ベースで実施しているところが多いのではないかと思う。その職務を「ソフトウェアエンジニアがなる運用ロールとしての CRE」に担わせることで、それらの業務をさらにドライブさせることができるのではないかと考えている。実際に上記の業務にはエンジニアリング的な素養は大きく活きると思う。

SRE が開発チームに Embedded されるように、CRE がプロダクトチーム、カスタマーサクセスチーム、サポートチームに Embedded され、業務を遂行するような形でも良いかもしれない。なぜなら、業務改善には業務理解が不可欠だからだ。そこはソフトウェアエンジニアリングを知っている SRE との違いであり、難しさかもしれない。更に Embedded SRE との違いは、Embedded される先のチームが基本的には組織的にエンジニアリングチームの外にあると考えられるため、組織的運用的には Embedded しにくいというところがある。

まとめ

この記事では CRE の業務の発展性について考えてみた。このアイディアは自分自身がサポートチームに所属する CRE としてプロダクトチーム、カスタマーサクセスチーム、サポートチームのオペレーションの改善業務を行っているところから着想を得ている(実際には Data Engineer 的な仕事が多いので Embedded Data Engineer と評しても良いのかもしれない)。このようなロールは組織構造や職務の切り方などによってはもちろん他のロールで代替可能なものだが、組織によってはその構成の選択肢の一つとして有効なのではないかと考えている。

データ系エンジニアの職種の違い

はじめに

自分は Martin Kleppmann が言うデータ指向アプリケーションやそれを実現する周辺の技術領域が好きで、業務としてそのような領域のエンジニアリングを引き続きやっていけたらなと思っています。 世の中には関連する職種の求人が多々ありますが、同じ名前のロールでも職務内容がコンテキストによって異なることが多かったりします。 ここではそれぞれの職種の違いについて自分の観点からまとめます。

1. データエンジニア

求人を眺めていると、データエンジニアは企業によって割と役割がぶれるので分けて説明します。

1-1. 小さめの事業会社のデータエンジニア

まずは、小さめの事業会社のデータ分析基盤の構築・運用をするロールです。 ここでは ETL 処理の実装・運用のほかに、各種ツールを使ったデータ基盤の構築・運用知識やクラウド上のアプリケーション構築の知識などが求められることが多いです。 さらには、データ分析業務や機械学習アプリケーションの構築もそこに含まれる場合もあります。

1-2. 大きめの事業会社のデータエンジニア

一方、例えば保険系や金融系なんかの大きめのトラディショナルな企業ではより職責が狭くなって、複雑な ETL 処理をコード化したり、そのトラブルシュートをしたりするような職種であることが多いです(以前 Apple もデータエンジニアの求人を出していましたが、話を聞いたところそんなそんな感じでした)。 このような企業では小さめの事業会社で求められる能力とは異なり、インフラやツールセットの知識よりも ETL の実装そのものに比重が置かれます。

1-3. コンサル企業のデータエンジニア

さらに、コンサルサービスを提供する企業でもデータエンジニアの求人を募集していることがあります。 上記二つのケースがインハウスの社内システムに関するロールである一方、こちらはお客様のデータ処理基盤の面倒をみるロールとなります。 上記のプロダクト向かいのロールと違い、お客様向かいになるので、求められる能力は技術知識以外にもお客様と関係性を維持しながらプロジェクトを運用していく能力が求められます。

2. ソフトウェアエンジニア(データプラットフォーム、MLOps)

こちらは、自社のデータ処理関連プラットフォームをソフトウェアエンジニアとして開発していくロールです。 社内外向けのサービスを開発するロールとなり、バリバリにコードを書く能力が求められます。 (現職のスマートニュースも自分が入社したころはデータエンジニアとして求人をしていましたが、現在はこちらの肩書きで募集しています) MLOps エンジニアとなる場合は、特徴量エンジニアリングなどではデータ処理基盤と重なる部分はありますが、効率的なトレーニングやサービングなどの機械学習ドメインに関する知見が特に重視されるでしょう。

4. ソリューションアーキテクト(データ処理関連プロダクト)、ビックデータコンサルタント

テックベンダーかコンサル企業で、ソリューションかコンサルサービスを提供し顧客サポートをするロールとなります。 コンサル企業のデータエンジニアと同様に、顧客向かいのロールで、技術的知見以外の能力が求められます。

5. データアーキテクト

そんなにポジションが存在する職種ではなく、データアーキテクトは企業によって役割は異なることが多いです。 基本的にはインハウスのシステムのデータ設計やプロジェクトリードなんかが主な業務だと思います(ドメイン知識が必要なことが多い)。 一方で、ソリューションアーキテクト的なロールであることもあります。

6. SRE

インフラ知識のあるエンジニアは、SRE としても働いて良いかもしれません。データエンジニアのロールを用意せず、SRE やインフラエンジニアがデータ基盤をインフラの一部として面倒を見るようなステージの企業は多いと思います。 この場合、データ基盤技術領域以外の SRE 的なインフラ的な知見が求められます。

まとめ

上記にあげたものの他にも、Analytics Engineer や Database Reliability Engineer、Data Reliability Engineer だったり、企業ごとに独自の役割を付与してロールにしていることがあります。 これは、この問題領域におけるロールが比較的新しく、それぞれの組織の運用の形に合わせて手探りで役割を与えていることによるものでしょう。

キャリア面に関しては、データエンジニアを続けていくと、将来その先はどうなるだろうかという話はあります。 IC でいることに飽きてマネージメントに挑戦したくなった場合、データエンジニアはわりと条件が厳しい印象があります。 BigQuery 含むマネージドサービスの勃興で企業規模に対して必要なインハウスのエンジニア数が少なくて済むようになっており、小さな企業ではマネージャーを置くまでチーム規模を大きくする必要がないからです。 一方、事業規模が大きくなりデータエンジニアが多めに必要な事業体を選ぶとなると、小さな事業体とは必要とされる能力も異なってきて、ゲームが変わってきます。

DX 文脈もあり、関連技術の重要性は増すでしょう。キャリアの方向性を考えるためにも、市場でどんなロール・能力が求められているか、自分はどの方向性に向かいたいかを継続的に確認していくことは重要かと思います。

2019年買って良かったものと今欲しいもの

2019年買って良かった物

基本的に必要にかられないと買い物はしないが(書籍は除く)、今年に買って良かった物を紹介する。

第5位 BRAUNのハンドブレンダー

みじん切りとか楽にしたりスムージーとかしたいねとずっと話していたが、踏み切れず先延ばしにしていたところ、妻が義弟から誕生日のプレゼントとしていただいた(買ったものじゃなかった)。 牛乳とバナナなどで手軽に健康的な気持ちになれるのが良い。

第4位 GREGORYのCOVERT MISSION DAY

5年使っていた普段使い用のリュックのチャックが壊れてしまったので、良さそうな物をインターネットで調べて、ちょうど会社の前にあった GREGORY で購入した。 22L あってそこそこ何でも入るし、ポケットやスリーブも使いやすく、背負った時のフィット感も良い。 しいて言えば、背面がメッシュじゃないのでちょっと蒸れるかも。 www.gregory.jp

第3位 THE BODY SHOPのインディアンナイトジャスミン ボディクリーム

妻の買い物ついでに物色していたところ、香りが良かったので購入した。その際に店員さんには「男性が好まれるんですよねー」ってコメントされたが、どんな相関があるのか謎。香りが好きで気に入って使っている。

www.the-body-shop.co.jp

第2位 机と椅子

引っ越す前は狭めの1DKに二人暮らししていて、フリーランスの妻には仕事部屋がなかった。 簡素な折りたたみ机(毎日しまう)と椅子で仕事をしていて、非常に辛そうだった。 少し広めの部屋に引っ越し、やっと机と椅子が置けて仕事が捗っているようで本当に良かった。 椅子はニトリのこれ

www.nitori-net.jp

あと、引っ越し時、ダイニング用のテーブルと椅子も購入する必要があり、椅子は質感が気に入って一目惚れした下記のものにさせてもらった(本当はそんなお金かける気もなかったが、直感に従ってしまった)。

https://www.idc-otsuka.jp/item/item2.php?id=dchair377www.idc-otsuka.jp

第1位 マンション

部屋のグレードが上がり、持ち家か賃貸か論争も気にならなくなり、不動産や税金の知識がつき、35年のローンを背負った。 まだ引っ越して1ヶ月だけれど、あれだけ悩んで買っただけあって非常に満足している。 あと、風呂場にミストサウナがついており、購入時はあまり期待していなかったが、使ってみて非常に気に入った。水風呂を張れば簡易交代浴できそう。

2019年の今現在欲しい物

第3位 AirPods Pro

欲しい。けど、なくても問題ない。

第2位 Switchとリングフィットアドベンチャーとフィットボクシング

運動をゲーミフィケーションされたい。どれくらい続くかな。

第1位 海外リゾートホテルコンドミニアム

欲しい。

ja.sekaiproperty.com

聴いているPodcastの番組

通勤時間が徒歩+電車で片道30分超くらいで、その道すがらPodcastを聴いています。コンテンツはTechニュースが主で、英語のリスニングも兼ねていて、稀にshadowingもしたりします。以下に、聴いているPodcastを紹介します。その他におすすめの番組あれば教えてください。

日本語編

Rebuild

定番ですが、好きです。個人的にはNさん回が好きで、その他ゲーム回は割とスキップしたりします。家で流していたら妻がよく登場するゲストを識別できるようになりました。

www.listennotes.com

バイリンガルニュース

これも定番。話題になっている社会問題からScienceのニッチなニュースまで幅広く知れます。取り上げるテーマがユニークなので好きです。

www.listennotes.com

Misreading Chat

CSの論文をざっくばらんに紹介してくれていて、とても勉強になります。

www.listennotes.com

英語編

TechCrunch

TechCrunch の Podcast です。短くてわかりやすいのが良いです。

www.listennotes.com

Software Engineering Daily

特定の技術領域に特化した話が聞けて勉強になります。ホストの Jeff 氏の英語も聞き取りやすくて良いです。

www.listennotes.com

Modern CTO with Joel Beasley

有名企業の CTO / VPoE をゲストに生い立ちから技術の話まで聞けて面白いです。英語も聞き取りやすいです。

www.listennotes.com

Data Engineering Podcast

Data Engineering に特化した Podcast。テーマは面白いですが、ホストの方の英語が抑揚なくやや聞き取りにくいです。

www.listennotes.com

This Week in Startups

日本でも翻訳されているエンジェル投資家の著者であるジェイソン・カラカニス氏の配信しているPodcast 。投資家視点の話が聞けて面白いです。

www.listennotes.com

a16z Podcast

Andreessen Horowitz が配信している Podcast。たまに聞きます。

www.listennotes.com

16 Minutes News by a16z

Andreessen Horowitz が配信している Podcast だけれどニュースに特化したもの。数ヶ月に始まったものですが、こっちのが a16z Podcast より短いし聞きやすいです。

www.listennotes.com

Equity

TechCrunch の VC が配信している Podcast。たまに聞きます。

www.listennotes.com

(翻訳) データエンジニアリングの未来

訳者まえがき

原著者の Chris Riccomini の許可を得て以下の記事を翻訳・公開しました。

riccomini.name

下記より記事翻訳本文です。

データエンジニアリングの未来

https://riccomini.name/assets/images/2019-07-29-future-data-engineering/mathilda-khoo-HLA3TAFQuQs-unsplash.jpg

私は最近、近頃のデータエンジニアリングがこれまで来た道について、また、この分野の仕事の将来について考えてきました。考えのほとんどは、私たちのチームが WePay で実践していることを背景にしています。その一方、以下に述べる考えは普遍的で、共有する価値があるものと思っています。

データエンジニアリングの仕事は、組織におけるデータの移動と処理を支援することです。これには、一般的に、データパイプラインとデータウェアハウスという2つの異なるシステムが必要です。データパイプラインはデータの移動を担当し、データウェアハウスはデータの処理を担当します。これは、やや過度に単純化しています。バッチ処理とストリーム処理では、抽出(extraction)とロード(loading)の間で変換(transformation)を行うことにより、パイプライン自体で処理を行うことはできます。近年の データウェアハウスには、多くのストレージおよび処理システム(Flink、Spark、Presto、Hive、BigQuery、Redshiftなど)と、データカタログ、ジョブスケジューラなどの補助システムが含まれています。しかし、それでもこのパラダイムは意味のあるものと思います。

業界では、これらのシステムの構築および管理方法の変革が進んでいます。特に、今後数年間で変化が予期される、4つの分野があります。

  • 適時性(Timeliness): バッチからリアルタイムへ
  • 接続性(Connectivity): one:one、特注のインテグレーションから many:many へ
  • 集中化(Centralization): 集中管理からセルフサービスツールへ
  • 自動化(Automation): 手動管理から自動化ツールへ

バッチからリアルタイムへ

データパイプラインとデータ処理の両方は、これまではバッチベースでした。データはバッチETLスナップショットでシステム間転送が行われ、ジョブスケジューラ(Airflow、Oozie、Azkaban、Luigi)によって定期的に処理されていました。

最近は、リアルタイムデータパイプラインとリアルタイムデータ処理システムへ移行しつつあります。 Debezium などの変更データキャプチャシステムと、Kafkaの堅牢なコネクタエコシステムにより、リアルタイムのデータパイプラインが可能になりました。ストリーム処理は、過去5年間でルネッサンスを迎え、リアルタイムのデータ処理システムは現在追いきれないほど多くなっています。これら要因により、つまり、入力(抽出)、処理(変換)、および出力(読み込み)がすべてリアルタイムで行われることを意味します。

現在のトレードオフは、コストと複雑さのようです。企業がデータウェアハウスを立ち上げており、4〜6週間ですぐに効果が必要な場合、リアルタイムパイプラインをセットアップするのは大きな負担になります。バッチの作成と実行は依然として簡単です。リアルタイム領域のツールが成熟し続け、クラウドホスティングが成長するにつれて、これは今後数年間で変わると私は予想しています。

接続性

上流のデータソースをデータウェアハウスに接続することは、システム間の1to1接続ごとにまったく新しい特注のインテグレーションを追加することを意味していました。Jay Krepsの重要な投稿、The Log: What every software engineer should know about real-time data’s unifying abstraction は、これをよく説明しています。

https://riccomini.name/assets/images/2019-07-29-future-data-engineering/datapipeline_complex.png

複雑なデータパイプライン

この投稿は、データ統合の将来についても詳しく説明しています。これは2013年に書かれたもので、そこで予想され提案されているものの多くが現在に実を結び始めています。 ConfluentKafka Connect、およびコネクタエコシステムが作られたことで、既存の Kafka データパイプラインに接続できる実行可能なコネクタが数多く生まれました。

このアーキテクチャのアプローチは定着していくでしょう。入力を出力から、またそれらを変換から切り離することは、データパイプラインにメトカーフの法則を効き始めることを意味します。そこでは、新しいシステムをパイプラインに追加することは、以前よりも安価でより価値があります。

上記のパラグラフはかなり Kafka 中心主義的であるとは思いますが、このアプローチにおいてはリアルタイムは必ずしも必要ありません(そうなっていくとは思いますが)。たとえば Airflow では、現在 GoogleCloudStorageHook、BigQueryHook、1to1のオペレーターであるGoogleCloudStorageToBigQueryOperator があります。出力から入力を完全に解きほぐし、一般的な形式のステージング領域が存在すると、バッチベースのETLの改善にも大いに役立ちます。

このパターンにより、よりきめ細かいデータシステムを採用することもできます。パイプラインに新しいシステムを接続するのが安価になると、エコシステムに新しい特殊なシステムを追加する価値がそのコストを上回ります。その結果、グラフデータベース、リアルタイムOLAPシステム、検索インデックスなど、ニッチなデータ処理システムの使用が増えることが期待されます。また、新しいシステムをパイプラインに接続し、それがニーズに合わないことを確認することが以前よりもはるかに安価になるため、このパターンはより多くの実験を可能にします(これは今年の初めの記事ですでに取り上げたテーマです, Kafka is your escape hatch)。

クラウドもまた、接続性の一連の作業に興味深い妙案を加えてくれています。データ統合の作業を、AWSコンソールのチェックボックスにするという夢はまだ実現していません。各クラウドプロバイダーで、すべてのシステムはすぐに完全に統合されることはないでしょう。ポイントアンドクリックUIでのクラウドプロバイダー間を完全統合するというアイディアは、さらに遠そうです。最後に、クラウドおよび非クラウド(またはサードパーティがホストする)システムを統合するには、依然として作業が必要です。

これらの理由から、Stitchなどのクラウドベースのサードパーティソリューションは引き続き価値があると思います。また、これは、上記で説明したリアルタイムのKafkaアーキテクチャが、構築して運用する余裕があるとすれば、最も成熟したソリューションになることを意味します。

自動化と非中央集権化

リストの最後の2つの項目、自動化と集中化は、かなり密接に関連しています。ほとんどの組織には、データパイプラインとデータウェアハウスを管理する単一のデータエンジニアリングチームやデータウェアハウジングチームがいます。これらのチームにリクエストが届くと、次の2つの基準でリクエストを評価する必要があります。

  • 技術的に可能か: What can we do (technical)
  • ポリシー的に可能か: What may we do (policy)

私の経験では、中央集権化されたチームは通常、ある程度の自動化を行いますが、技術的な自動化に主に焦点を合わせます。これは、エンジニアリングチームの操舵室にあるため、当然です。この種の作業は、通常、運用上のトイルを自動化することを意味します。新しいコネクタの追加、監視またはデータ品質チェックの設定、新しいデータベースまたはテーブルの作成、許可の付与などの作業です。

ただし、データエンジニアリングがまだ自動化していないもうひとつのタイプのトイルがあります。ポリシーのトイルです。この種の面倒な作業には、誰がどのデータにアクセスできるか、どのくらいの期間データを保持するか、どのデータシステムにどのような機密データを格納することを許すか、どの地域のデータが存在するかについての決定が含まれます。通常、データエンジニアリングは、これらの質問に対する回答を最終的に決定するチームではありませんが、回答を見つける際に連絡役またはドライバーとして行動しなければならないことがよくあります。これは通常、セキュリティ、コンプライアンス、法律など、組織の他のチームを介して要望をナビゲートすることを意味します。

GDPRCCPAなどの規制により、すでにこの種の作業は重要です。従来のソフトウェア企業の枠を超え、ヘルスや金融などの分野において技術の継続的な拡大に対する政府の規制を追加する場合(Why Software Is Eating the World 参照)、ポリシーのトイルを自動化することの重要性が増すことは避けられないでしょう。

ポリシーの自動化には、成熟度の低いデータエコシステムでは通常無視されている分野に焦点を当てる必要があります。 LyftAmundsenApache RangerGoogleデータカタログなどのツールを採用する必要があるでしょう。監査、DLP、機密データの検出、保持期間の強制、アクセス制御管理などのポリシーの実施は、すべて完全に自動化する必要があります。

自動化が技術分野とポリシー分野の両方で成熟するにつれて、必然的に次のような質問が生まれます。なぜ、単一のチームで管理する必要があるのでしょう? ツールがポリシーガイドラインを実行し、データパイプラインを自動化するならば、組織のそれぞれのチームがデータパイプラインとデータウェアハウスを直接管理できるようにするのはどうでしょうか?

データパイプラインにおいては非中央集権化とは、技術的およびポリシーガイドラインに(自動的に実施される)準拠している場合、チームが既存のデータパイプラインに接続することを決定できることを意味します。データウェアハウスにおいては、チームは必要に応じてデータベース、データセット、データマート、およびデータレイクを作成できます(一部は既に存在しています)。これにより、多くの複雑性、混乱、および重複が発生します。そのため、ツール(上記に挙げたツールなど)が非中央集権化にとって非常に重要な前提条件となります。

非中央集権化のトピックは、Zhamak Dehghaniの投稿 How to Move Beyond a Monolithic Data Lake to a Distributed Data Mesh で詳細に説明されています。ぜひお読みください。より複雑なデータエコシステムを管理するために認知的負荷が生まれてしまうため、唯一のスケーラブルで効率的な方法は、自動化と非中央集権化だと思います。これは、ある意味では、アプリケーション層で過去10年間に見られたCI / CDおよびモノリスからマイクロサービスへの移行のように見えます。

結び

これらを踏まえて、私は楽観的です。まだやるべきことがあり、たくさんの機会があります。これらの要求を満たすために、組織内でデータエンジニアリングが拡大することを期待しています。オープンソースコミュニティは拡大を続け、新しいプロジェクトとスタートアップが生まれます。これらのすべてが、組織全体の大幅な効率向上につながり、より厳密なデータ管理の実践につながるはずです。

JMX metrics exposed in Presto version 302

Summary

Presto provides JMX metrics to monitor its system but there is few description in the document what metrics we can use, so I checked it.

Monitoring · prestosql/presto Wiki · GitHub

I used CLI tool jmxterm to get the information.

Commands

$ echo domains | java -jar jmxterm-1.0.0-uber.jar -l localhost:8086 -n > domains.txt
$ sed -i "s/^/beans -d /g" domains.txt
$ cat domains.txt | java -jar jmxterm-1.0.0-uber.jar -l localhost:8086 -n > beans.txt
$ cat beans.txt | awk -F: '{print "info -d " $1 " -b " $2}' | java -jar jmxterm-1.0.0-uber.jar -l localhost:8086 -n > info.txt 2>&1

Results

domains

[ec2-user@ip-10-0-101-241 ~]$ cat domains.txt
JMImplementation
com.amazonaws.management
com.sun.management
io.airlift.discovery.client
io.airlift.discovery.store
io.airlift.event.client
io.airlift.http.client
io.airlift.http.server
io.airlift.jmx
io.airlift.log
io.airlift.node
io.airlift.stats
java.lang
java.nio
java.util.logging
org.eclipse.jetty.http2.server
org.eclipse.jetty.io
org.eclipse.jetty.jmx
org.eclipse.jetty.server
org.eclipse.jetty.server.handler
org.eclipse.jetty.server.handler.gzip
org.eclipse.jetty.servlet
org.eclipse.jetty.util.thread
org.eclipse.jetty.util.thread.strategy
presto.execution
presto.execution.executor
presto.execution.resourceGroups
presto.execution.scheduler
presto.failureDetector
presto.memory
presto.metadata
presto.operator.index
presto.plugin.hive
presto.plugin.hive.metastore
presto.plugin.hive.metastore.thrift
presto.plugin.hive.s3
presto.security
presto.server
presto.server.remotetask
presto.spiller
presto.sql.gen
presto.sql.planner.iterative
presto.sql.planner.optimizations
sun.nio.ch

beans

[ec2-user@ip-10-0-101-241 ~]$ cat beans.txt
JMImplementation:type=MBeanServerDelegate
com.amazonaws.management:type=AwsSdkMetrics
com.amazonaws.management:type=AwsSdkMetrics/1
com.sun.management:type=DiagnosticCommand
com.sun.management:type=HotSpotDiagnostic
io.airlift.discovery.client:name=Announcer
io.airlift.discovery.client:name=ServiceInventory
io.airlift.discovery.store:name=dynamic,type=DistributedStore
io.airlift.discovery.store:name=dynamic,type=HttpRemoteStore
io.airlift.discovery.store:name=dynamic,type=Replicator
io.airlift.event.client:name=EventClient
io.airlift.http.client:name=ForDiscoveryClient,type=HttpClient
io.airlift.http.client:name=ForDynamicStore,type=HttpClient
io.airlift.http.client:name=ForEventClient,type=HttpClient
io.airlift.http.client:name=ForExchange,type=HttpClient
io.airlift.http.client:name=ForFailureDetector,type=HttpClient
io.airlift.http.client:name=ForMemoryManager,type=HttpClient
io.airlift.http.client:name=ForNodeManager,type=HttpClient
io.airlift.http.client:name=ForScheduler,type=HttpClient
io.airlift.http.client:name=ForWorkerInfo,type=HttpClient
io.airlift.http.server:context=HTTP/1.1|h2c@183fc2fa,id=0,type=httpserverchannellistener
io.airlift.http.server:id=0,type=classpathresourcehandler
io.airlift.http.server:id=0,type=statsrecordinghandler
io.airlift.http.server:id=1,type=classpathresourcehandler
io.airlift.http.server:name=HttpServer
io.airlift.http.server:name=RequestStats
io.airlift.jmx:name=StackTraceMBean
io.airlift.log:name=Logging
io.airlift.node:name=NodeInfo
io.airlift.stats:name=PauseMeter
java.lang:name=Code Cache,type=MemoryPool
java.lang:name=CodeCacheManager,type=MemoryManager
java.lang:name=Compressed Class Space,type=MemoryPool
java.lang:name=G1 Eden Space,type=MemoryPool
java.lang:name=G1 Old Gen,type=MemoryPool
java.lang:name=G1 Old Generation,type=GarbageCollector
java.lang:name=G1 Survivor Space,type=MemoryPool
java.lang:name=G1 Young Generation,type=GarbageCollector
java.lang:name=Metaspace Manager,type=MemoryManager
java.lang:name=Metaspace,type=MemoryPool
java.lang:type=ClassLoading
java.lang:type=Compilation
java.lang:type=Memory
java.lang:type=OperatingSystem
java.lang:type=Runtime
java.lang:type=Threading
java.nio:name=direct,type=BufferPool
java.nio:name=mapped,type=BufferPool
java.util.logging:type=Logging
org.eclipse.jetty.http2.server:context=HTTP/1.1|h2c@183fc2fa,id=0,type=abstracthttp2serverconnectionfactory$http2sessioncontainer
org.eclipse.jetty.http2.server:context=HTTP/1.1|h2c@183fc2fa,id=0,type=http2cserverconnectionfactory
org.eclipse.jetty.io:context=HTTP/1.1|h2c@183fc2fa,id=0,type=arraybytebufferpool
org.eclipse.jetty.io:context=HTTP/1.1|h2c@183fc2fa,id=0,type=connectionstatistics
org.eclipse.jetty.io:context=HTTP/1.1|h2c@183fc2fa,id=0,type=managedselector
org.eclipse.jetty.io:context=HTTP/1.1|h2c@183fc2fa,id=0,type=managedselector$selectorproducer
org.eclipse.jetty.io:context=HTTP/1.1|h2c@183fc2fa,id=1,type=managedselector
org.eclipse.jetty.io:context=HTTP/1.1|h2c@183fc2fa,id=1,type=managedselector$selectorproducer
org.eclipse.jetty.io:context=HTTP/1.1|h2c@183fc2fa,id=2,type=managedselector
org.eclipse.jetty.io:context=HTTP/1.1|h2c@183fc2fa,id=2,type=managedselector$selectorproducer
org.eclipse.jetty.io:context=HTTP/1.1|h2c@183fc2fa,id=3,type=managedselector
org.eclipse.jetty.io:context=HTTP/1.1|h2c@183fc2fa,id=3,type=managedselector$selectorproducer
org.eclipse.jetty.jmx:id=0,type=mbeancontainer
org.eclipse.jetty.server:context=HTTP/1.1|h2c@183fc2fa,id=0,type=abstractconnector$acceptor
org.eclipse.jetty.server:context=HTTP/1.1|h2c@183fc2fa,id=0,type=httpconfiguration
org.eclipse.jetty.server:context=HTTP/1.1|h2c@183fc2fa,id=0,type=httpconnectionfactory
org.eclipse.jetty.server:context=HTTP/1.1|h2c@183fc2fa,id=0,type=serverconnector
org.eclipse.jetty.server:context=HTTP/1.1|h2c@183fc2fa,id=0,type=serverconnector$serverconnectormanager
org.eclipse.jetty.server:id=0,type=server
org.eclipse.jetty.server.handler:id=0,type=errorhandler
org.eclipse.jetty.server.handler:id=0,type=handlercollection
org.eclipse.jetty.server.handler:id=0,type=handlerlist
org.eclipse.jetty.server.handler:id=0,type=requestloghandler
org.eclipse.jetty.server.handler:id=0,type=statisticshandler
org.eclipse.jetty.server.handler.gzip:context="ROOT@@http",id=0,type=gziphandler
org.eclipse.jetty.server.handler.gzip:id=0,type=gziphandler
org.eclipse.jetty.server.handler.gzip:id=1,type=gziphandler
org.eclipse.jetty.servlet:context="ROOT@@http",id=0,type=servletcontexthandler
org.eclipse.jetty.servlet:context="ROOT@@http",id=0,type=servlethandler
org.eclipse.jetty.util.thread:context=HTTP/1.1|h2c@183fc2fa,id=0,type=scheduledexecutorscheduler
org.eclipse.jetty.util.thread:id=0,type=queuedthreadpool
org.eclipse.jetty.util.thread:id=0,type=reservedthreadexecutor
org.eclipse.jetty.util.thread.strategy:context=HTTP/1.1|h2c@183fc2fa,id=0,type=eatwhatyoukill
org.eclipse.jetty.util.thread.strategy:context=HTTP/1.1|h2c@183fc2fa,id=1,type=eatwhatyoukill
org.eclipse.jetty.util.thread.strategy:context=HTTP/1.1|h2c@183fc2fa,id=2,type=eatwhatyoukill
org.eclipse.jetty.util.thread.strategy:context=HTTP/1.1|h2c@183fc2fa,id=3,type=eatwhatyoukill
presto.execution:name=QueryExecution
presto.execution:name=QueryManager
presto.execution:name=RemoteTaskFactory
presto.execution:name=TaskManager
presto.execution.executor:name=MultilevelSplitQueue
presto.execution.executor:name=TaskExecutor
presto.execution.resourceGroups:name=InternalResourceGroupManager
presto.execution.resourceGroups:name=chartio,type=InternalResourceGroup
presto.execution.resourceGroups:name=user,type=InternalResourceGroup
presto.execution.scheduler:name=NodeScheduler
presto.execution.scheduler:name=SplitSchedulerStats
presto.execution.scheduler:segment=all
presto.execution.scheduler:segment=machine
presto.failureDetector:name=HeartbeatFailureDetector
presto.memory:name=ClusterMemoryManager
presto.memory:name=general,type=ClusterMemoryPool
presto.memory:name=general,type=MemoryPool
presto.memory:name=reserved,type=ClusterMemoryPool
presto.memory:name=reserved,type=MemoryPool
presto.metadata:name=DiscoveryNodeManager
presto.operator.index:name=IndexJoinLookupStats
presto.plugin.hive:name=hive,type=FileFormatDataSourceStats
presto.plugin.hive:name=hive,type=HiveSplitManager
presto.plugin.hive:name=hive,type=HiveWriterStats
presto.plugin.hive:name=hive,type=NamenodeStats
presto.plugin.hive:name=hive,type=OrcFileWriterFactory
presto.plugin.hive:name=hive_ad,type=FileFormatDataSourceStats
presto.plugin.hive:name=hive_ad,type=HiveSplitManager
presto.plugin.hive:name=hive_ad,type=HiveWriterStats
presto.plugin.hive:name=hive_ad,type=NamenodeStats
presto.plugin.hive:name=hive_ad,type=OrcFileWriterFactory
presto.plugin.hive.metastore:name=hive,type=CachingHiveMetastore
presto.plugin.hive.metastore:name=hive_ad,type=CachingHiveMetastore
presto.plugin.hive.metastore.thrift:name=hive,type=ThriftHiveMetastore
presto.plugin.hive.metastore.thrift:name=hive_ad,type=ThriftHiveMetastore
presto.plugin.hive.s3:name=hive,type=PrestoS3FileSystem
presto.plugin.hive.s3:name=hive_ad,type=PrestoS3FileSystem
presto.security:name=AccessControlManager
presto.server:name=AsyncHttpExecutionMBean
presto.server:name=ExchangeExecutionMBean
presto.server:name=StatementHttpExecutionMBean
presto.server:name=TaskExecutorResource
presto.server:name=TaskResource
presto.server.remotetask:name=RemoteTaskStats
presto.spiller:name=SpillerFactory
presto.sql.gen:name=ExpressionCompiler
presto.sql.gen:name=JoinCompiler
presto.sql.gen:name=JoinFilterFunctionCompiler
presto.sql.gen:name=OrderingCompiler
presto.sql.gen:name=PageFunctionCompiler
presto.sql.planner.iterative:name=IterativeOptimizer,rule=AddExchangesBelowExchangePartialAggregationGroupId
presto.sql.planner.iterative:name=IterativeOptimizer,rule=AddExchangesBelowProjectionPartialAggregationGroupId
presto.sql.planner.iterative:name=IterativeOptimizer,rule=AddIntermediateAggregations
presto.sql.planner.iterative:name=IterativeOptimizer,rule=AggregationExpressionRewrite
presto.sql.planner.iterative:name=IterativeOptimizer,rule=ApplyExpressionRewrite
presto.sql.planner.iterative:name=IterativeOptimizer,rule=CheckNoPlanNodeMatchesRule
presto.sql.planner.iterative:name=IterativeOptimizer,rule=CreatePartialTopN
presto.sql.planner.iterative:name=IterativeOptimizer,rule=DetermineJoinDistributionType
presto.sql.planner.iterative:name=IterativeOptimizer,rule=EliminateCrossJoins
presto.sql.planner.iterative:name=IterativeOptimizer,rule=EvaluateZeroLimit
presto.sql.planner.iterative:name=IterativeOptimizer,rule=EvaluateZeroSample
presto.sql.planner.iterative:name=IterativeOptimizer,rule=ExtractSpatialInnerJoin
presto.sql.planner.iterative:name=IterativeOptimizer,rule=ExtractSpatialLeftJoin
presto.sql.planner.iterative:name=IterativeOptimizer,rule=FilterExpressionRewrite
presto.sql.planner.iterative:name=IterativeOptimizer,rule=ImplementBernoulliSampleAsFilter
presto.sql.planner.iterative:name=IterativeOptimizer,rule=ImplementFilteredAggregations
presto.sql.planner.iterative:name=IterativeOptimizer,rule=InlineProjections
presto.sql.planner.iterative:name=IterativeOptimizer,rule=JoinExpressionRewrite
presto.sql.planner.iterative:name=IterativeOptimizer,rule=MergeAdjacentWindowsOverProjects
presto.sql.planner.iterative:name=IterativeOptimizer,rule=MergeFilters
presto.sql.planner.iterative:name=IterativeOptimizer,rule=MergeLimitWithDistinct
presto.sql.planner.iterative:name=IterativeOptimizer,rule=MergeLimitWithSort
presto.sql.planner.iterative:name=IterativeOptimizer,rule=MergeLimitWithTopN
presto.sql.planner.iterative:name=IterativeOptimizer,rule=MergeLimits
presto.sql.planner.iterative:name=IterativeOptimizer,rule=MultipleDistinctAggregationToMarkDistinct
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PickTableLayoutForPredicate
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PickTableLayoutWithoutPredicate
presto.sql.planner.iterative:name=IterativeOptimizer,rule=ProjectExpressionRewrite
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneAggregationColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneAggregationSourceColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneCountAggregationOverScalar
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneCrossJoinColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneFilterColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneIndexSourceColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneJoinChildrenColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneJoinColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneLimitColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneMarkDistinctColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneOrderByInAggregation
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneOutputColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneProjectColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneSemiJoinColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneSemiJoinFilteringSourceColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneTableScanColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneTopNColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneValuesColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PruneWindowColumns
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PushAggregationThroughOuterJoin
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PushLimitThroughMarkDistinct
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PushLimitThroughProject
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PushLimitThroughSemiJoin
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PushPartialAggregationThroughExchange
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PushPartialAggregationThroughJoin
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PushProjectionThroughExchange
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PushProjectionThroughUnion
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PushRemoteExchangeThroughAssignUniqueId
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PushTableWriteThroughUnion
presto.sql.planner.iterative:name=IterativeOptimizer,rule=PushTopNThroughUnion
presto.sql.planner.iterative:name=IterativeOptimizer,rule=RemoveEmptyDelete
presto.sql.planner.iterative:name=IterativeOptimizer,rule=RemoveFullSample
presto.sql.planner.iterative:name=IterativeOptimizer,rule=RemoveRedundantIdentityProjections
presto.sql.planner.iterative:name=IterativeOptimizer,rule=RemoveTrivialFilters
presto.sql.planner.iterative:name=IterativeOptimizer,rule=RemoveUnreferencedScalarApplyNodes
presto.sql.planner.iterative:name=IterativeOptimizer,rule=RemoveUnreferencedScalarLateralNodes
presto.sql.planner.iterative:name=IterativeOptimizer,rule=ReorderJoins
presto.sql.planner.iterative:name=IterativeOptimizer,rule=RewriteSpatialPartitioningAggregation
presto.sql.planner.iterative:name=IterativeOptimizer,rule=SimplifyCountOverConstant
presto.sql.planner.iterative:name=IterativeOptimizer,rule=SingleDistinctAggregationToGroupBy
presto.sql.planner.iterative:name=IterativeOptimizer,rule=SwapAdjacentWindowsBySpecifications
presto.sql.planner.iterative:name=IterativeOptimizer,rule=TransformCorrelatedInPredicateToJoin
presto.sql.planner.iterative:name=IterativeOptimizer,rule=TransformCorrelatedLateralJoinToJoin
presto.sql.planner.iterative:name=IterativeOptimizer,rule=TransformCorrelatedScalarAggregationToJoin
presto.sql.planner.iterative:name=IterativeOptimizer,rule=TransformCorrelatedScalarSubquery
presto.sql.planner.iterative:name=IterativeOptimizer,rule=TransformCorrelatedSingleRowSubqueryToProject
presto.sql.planner.iterative:name=IterativeOptimizer,rule=TransformExistsApplyToLateralNode
presto.sql.planner.iterative:name=IterativeOptimizer,rule=TransformUncorrelatedInPredicateSubqueryToSemiJoin
presto.sql.planner.iterative:name=IterativeOptimizer,rule=TransformUncorrelatedLateralToJoin
presto.sql.planner.iterative:name=IterativeOptimizer,rule=ValuesExpressionRewrite
presto.sql.planner.optimizations:name=PlanOptimizer,optimizer=AddExchanges
presto.sql.planner.optimizations:name=PlanOptimizer,optimizer=PredicatePushDown
sun.nio.ch:context=HTTP/1.1|h2c@183fc2fa,id=0,type=serversocketchannelimpl

bean info

[ec2-user@ip-10-0-101-241 ~]$ cat info.txt
Welcome to JMX terminal. Type "help" for available commands.
#mbean = JMImplementation:type=MBeanServerDelegate
#class name = javax.management.MBeanServerDelegate
# attributes
  %0   - ImplementationName (java.lang.String, r)
  %1   - ImplementationVendor (java.lang.String, r)
  %2   - ImplementationVersion (java.lang.String, r)
  %3   - MBeanServerId (java.lang.String, r)
  %4   - SpecificationName (java.lang.String, r)
  %5   - SpecificationVendor (java.lang.String, r)
  %6   - SpecificationVersion (java.lang.String, r)
#there's no operations
# notifications
  %0   - javax.management.MBeanServerNotification(JMX.mbean.unregistered,JMX.mbean.registered)
#mbean = com.amazonaws.management:type=AwsSdkMetrics
#class name = com.amazonaws.metrics.MetricAdmin
# attributes
  %0   - CredentialFile (java.lang.String, rw)
  %1   - HostMetricName (java.lang.String, rw)
  %2   - JvmMetricName (java.lang.String, rw)
  %3   - MachineMetricsExcluded (boolean, rw)
  %4   - MetricNameSpace (java.lang.String, rw)
  %5   - MetricQueueSize (java.lang.Integer, rw)
  %6   - MetricsEnabled (boolean, r)
  %7   - PerHostMetricsIncluded (boolean, rw)
  %8   - QueuePollTimeoutMilli (java.lang.Integer, rw)
  %9   - Region (java.lang.String, rw)
  %10  - RequestMetricCollector (java.lang.String, r)
  %11  - ServiceMetricCollector (java.lang.String, r)
  %12  - SingleMetricNamespace (boolean, rw)
# operations
  %0   - void disableMetrics()
  %1   - boolean enableDefaultMetrics()
(以下省略)

ベン・ホロウィッツの「HARD THINGS」を読んだ

最近、組織的な動きによって問題の解決が可能かを考える場面がたまにあるので、何かヒントになることでもないかと思い、前から読んでみたかった本書を読んだ。

HARD THINGS

HARD THINGS

良かったところを以下に述べる。

CEOの苦闘の話

前半の苦難が詰まったエピソードを読んだ後に、CEOの苦難が語られ始める。 特に下記のフレーズ。他の文書と違ってやたら詩的でぐっとくる。

苦闘とは、そもそもなぜ会社を始めたのだろうと思うこと。苦闘とは、あなたはなぜ辞めないのかと聞かれ、その答えを自分もわからないこと。苦闘とは、社員があなたはウソをついていると思い、あなたも彼らがたぶん正しいと思うこと。

苦闘とは、料理の味がわからなくなること。苦闘とは、自分自身がCEOであるべきだと思えないこと。苦闘とは、自分の能力を超えた状況だとわかっていながら、代わりが誰もいないこと。苦闘とは、全員があなたをろくでなしだと思っているのに、誰もあなたをクビにしないこと。苦闘とは、自信喪失が自己嫌悪に変わること。苦闘とは、苦しい話ばかり聞こえて、会話していても相手の声が聞こえないこと。苦闘とは、痛みが消えてほしいと思う時。苦闘とは、不幸である。苦闘とは、気晴らしのために休暇をとって、前より落ち込んでしまうこと。苦闘とは、多くの人たちに囲まれていながら孤独なこと。苦闘は無慈悲である。

苦闘とは、破られた約束と壊れた夢がいっぱいの地。苦闘とは冷汗である。苦闘とは、はらわたが煮えくり返りすぎて血を吐きそうになること。苦闘は失敗ではないが、失敗を起こさせる。特にあなたが弱っているときにはそうだ。弱っているときは必ず。

採用周りの話

今の勤めている会社は100-200人くらいの規模の会社で、そんなに小さくはないが大きくもない会社で、日々採用面接を担当している。 候補者の職歴はスタートアップから大企業から様々で、面接をするたびにこの人は果たしてこの会社でやっていけるだろうかと考えている。 本書は基本的には「幹部」の人事について言及していたが、一般社員にもある程度当てはまるように感じ、とても参考になった。

「大企業の幹部が小さな会社で成功できない理由」のセクション

大企業から小さな会社の転職の場合、

  • ペースのミスマッチ: 「大企業の有能な幹部の多くは、四半期に新しいプロジェクトが3つあったら、多すぎると言うだろう」
  • スキルのミスマッチ: 「大企業を動かしていくには、新たに組織をつくり上げるのとはまったく異なるスキルが必要だ」

のようなミスマッチがあり、そして、そのような採用の失敗を防ぐには、

  • 面接段階でどうしようもないミスマッチを察知する
  • 面接と同じくらい融和を大切にする

が大切だと書かれている。

ミスマッチの検知

下記のような質問をすると良い、と言っており参考になる。

  • 質問: 仕事に就いて最初の一ヶ月に何をしますか?
    • 勉強という答えを強調しすぎる人には要注意だ
    • 候補者が、割り込み駆動型である兆候を見逃してはならない。小さな会社では、割り込みはいつまでたってもやってこないからだ。CEOが無理だと思うくらい新規プロジェクトを持ってくる候補者を探そう。
  • 質問: 新しい仕事は、あなたの今の仕事とどう違いますか?
    • 仕事の違いを自覚しているrかどうかに注目すること
    • 過去の体験の大部分を今すぐ応用できると思い込んでいる候補者は要注意だ
  • 質問: なぜ小さな会社に入ろうと思いましたか?
    • ストックオプションが主要な動機でないかに注意せよ。ゼロの1パーセントはゼロだ。
    • 大きな会社と小さな会社でもっとも大きく違うのは、経営している時間と、創造している時間の長さだ。

入社したら積極的に溶け込ませる

  • 創造を強いる
    • 毎月、毎週、あるいは毎日でも目標を与えて、すぐに結果が出せることを確認する。
  • 「理解」をしているか確認する
    • コンテキストを持たない幹部は、スタートアップでは価値を持たない。
    • できるだけ早く、必要な情報を与えること。何も質問がなければ解雇を検討すべきだ。30日経っても状況を把握できていないと感じたら、間違いなく解雇すべきだ
  • 社員と接触させる

その他の人事の話

下記のセクションも良かった。

  • 人を正しく解雇する方法
  • 幹部を解雇する準備
  • 親友を降格させるとき
  • 友達の会社から採用してもよいか

人間の感情を認めた上で、人事判断を行う際にどう振る舞うのが良いのかを経験を元に描かれていて良い。 このような人事がどのようなダイナミズムで発生するかが面白かった。

「幹部の採用 - 未経験の仕事でも適任者を見つける」のセクション

幹部の採用のためのステップは下記の通りと書かれている。

  1. 自分が欲しいものを知る
  2. 適性を見極めるプロセスを実行する
  3. 孤独な決断を下す

人の採用を行うに際して陥りやすい罠として、「典型的な人物を探してしまう」という項目が挙げられており、最近の自分の判断を省みながら読んだ。 結成したての少数チームのメンバーの採用にとっても、大事な考え方だなと感じた。

もし私が典型的な人物を探していたら、マーク・クラニーを雇うことも、今あなたがこれを読んでいることもなかっただろう。この誤ったアプローチは、セールス責任者にプラトンイデア(真実の姿)を求めることと同じだ。まず、理想的なセールス担当幹部のイメージを描き、次に現実世界の候補者を自分のモデルと一致させようと試みる。これは良くない方法だ。第一に、あなたが雇おうとしているのは、架空の会社で働く概念上の幹部ではない。自分の会社の今この瞬間にとって、正しい人物を雇わなくてはならない。2010年のオラクルのセールストップは、1989年なら失敗していた可能性が高い。アップルのエンジニアリング担当副社長は、フォースクエアにとっては完全に誤った人選かもしれない。重要なのは詳細さと明確さだ。第二に、CEOが描く空想モデルは、ほぼ確実に間違っている。CEOがこのモデルをつくった根拠は何だろうか。最後に、そんな曖昧な基準を面接チームに教え込むことはあり得ないほど困難である。その結果、全員が何か違うものを求めることになる。

目標管理の話

「社員がマネージャーを誤解するとき」のセクション

このセクションでは、数字を重視するあまり間違ったインセンティブを与えてしまい失敗していた事例が書かれていた。

促進する対象には、定量化できるものとできないものがある。定量的な目標についてばかり報告して、定性的な目標を無視していけば、定性的な目標は達成できない-たとえそれがもっと重要な目標であったとしても。純粋に数字だけによるマネジメントは、筋通りに色を塗るぬり絵キットのようなもの-あれはアマチュア専用だ。

と言っている。これは、最近のトレンドの一部の OKR による目標管理に反対になる意見のように見える。 (参考: https://satoshihirose.hateblo.jp/entry/2019/01/05/153343

文章中には見落とされがちな定性的な目標として

  • 対ライバルの勝率は、上がっていたか下がっていたか?
  • 顧客満足度は、上がっていたか下がっていたか?
  • わが社のエンジニアたちは、この製品をどう思っていたのか?

を例としてあげられていたが、社員や顧客に対するサーベイによりこれらの項目を定量化することはOKRの中では普通に行われているように思う。

カルチャーの話

罵倒語

著者のベン・ホロウィッツは罵倒語を良く使うらしく、社内でそれを使うことの是非についても書かれてあった。 部下からその点を問題提起され、ベンは下記のように整理したらしい

  • テクノロジー企業では罵倒語を不快に感じる社員もいるが、不快に感じない社員もいる。
  • もし罵り言葉を禁止したら、罵り言葉を使っている社員は「この会社は古臭い」と思い、辞めてしまうかもしれない。
  • 罵り言葉を続けると、それを不快に感じる社員の一部は辞めてしまうかもしれない。
  • なんといっても私が最大の違反者なのだから、私の判断に偏りが入り込むのは避けられない

この罵倒語を使っている会社はクールである、といった風潮を感じたことはないが、当時のアメリカではそのような風潮はあったのだろうか(今も?)(もしくは、エグゼクティブの界隈ではあったのかもしれない)。 その問題提起に対して、ベンは社員を集めて下記のように言い渡したらしい。印象的な場面なので長いけれど引用する。

「当社における罵倒語の頻繁な使用が一部の社員を不快にしているという問題があると知った。罵倒語の使用頻度のナンバーワンとして、私自身の振る舞いを反省したが、同時に当社全体の問題としても考えてみた。私の考えではふたつの選択肢がある。(a)罵倒語の使用を禁じる、(b)罵倒語の使用を受け入れる-だ。このふたつの中間の選択肢というのは、理論的にはともかく現実的ではない。『罵倒語の使用を最小限に留める』などという対策は実効性がない。前にもの述べたことだが、世界で最優秀の人材を惹きつけられなければ、われわれは勝利できない。テクノロジー業界ではほとんど全員が罵倒語の使用を受け入れている。

そこで、罵倒語の使用を禁じることで生じる人材の損失は、受け入れることによって生じる損失を上回ると予想される。以上の理由で当社は、罵倒語の使用を受け入れる。ただし、いかなる場合でも、セクシャル・ハラスメント、その他の不当な目的で罵倒語を使ってはならない。罵倒語を使うかどうかにかかわらず、かかる行為が許されないのはもちろんだ。(略)」

その日以後、罵倒語に対する苦情は後を断った。それにこの方針によって会社を辞めた人間も出なかったようだ。ここで強調したいのは、組織で問題が生じたときに、必ずしも解決策は必要なく、単に事柄を明確化するだけで良い場合もあるという点だ。脅迫やセクハラにならない限り罵倒語の使用はオーケーだということをはっきりさせただけで、問題は消滅した。ともかく、この方針の結果、職場環境の快適さは維持され、辞職率は低いままにとどまり、苦情はなくなった。つまり、この方針は正しかったということになる。

最近の心理的安全をケアする風潮からするとにわかには信じられない言説だ。 (参考: 「暴言を吐かれた人は処理能力が61%、創造性58%落ちる」暴言が#職場 にもたらす悪影響 https://togetter.com/li/1201526

もしくは、単に私がスタートアップもしくは「戦時の企業」に向いていないだけなのかもしれない。 少なくとも個人的には頻繁に罵倒語やリスペクトに欠ける発言を頻繁に目にするような状況は、退職を検討するひとつの理由になるのではと感じている。

「優秀な人材が最悪の社員になる場合」のセクション

企業が大きくなるにつれて、円滑なコミュニケーションはどんどん難しくなっていく。 それにつれて優秀な人材が悩みのタネとなるという話も興味深かった。

ある種の人々はコミュニケーションのスタイルがあまりに好戦的なので、誰も口を利きたがらなくなる。誰かがマーケティングの話題に触れるたびにマーケティング担当副社長が飛び出してきて怒鳴りまくるようだったら、誰もマーケティングの話をしなくなる。会議にこういう根性曲がりがいると誰も口を開こうとしなくなる。その結果、会社幹部の間での意思疎通に大きな障害が生じ、やがて会社全体にその悪影響が出る。念のために付け加えておくが、問題の社員が一方で極め付けに頭がいい場合のみ、こうした破壊的な影響が広がる。そうでなければ、その社員が誰を攻撃しようと気にする者はない。ケガが大きくなるのは大きな犬に噛まれたときだ。もし幹部スタッフに大きな犬がいる場合は、その犬をどこかに追い払うしかない。

偉大なフットボール・コーチも同様のことに言及していると引用し、その影響をコントロールすることを肝に銘じるよう締めている。

「ひとりがバスに遅れれば、チーム全員が待っていなければならない。うんと遅れれば、チームは試合に間に合わなくなってしまう。だからそんなヤツは許しておくわけにはいかない。バスには出発しなければならない時刻がある。そうは言っても、時にはあまり役に立つので、バスを遅らせるのもやむを得ないような選手もいる。しかしそれはよほどの選手に限る」 (略) 時として会社にはデニス・ロッドマンのようにあまりに貢献が巨大なので、何をしても許容せざるを得ないような社員が存在することがある。だがその場合、CEOはその社員の悪影響が会社のほかの社員にひろがらないように自ら措置を講じなければならない。「社会全体でもデニス・ロッドマンはめったにいない」ことを肝に銘じておくべきだ。

1on1の話

1on1とは書いていなかったが、社員との個人面談の大事さについても言及している。 社員の方が個人面談の主役だと前置きしつつ、意見を引き出すのに役に立つ質問の例として下記のものをあげている。

  • われわれがやり方を改善するとしたらどんな点をどうすればよいと思う?
  • われわれの組織で最大の問題は何だとおもう?またその理由は?
  • この職場で働く上で一番不愉快な点は?
  • この会社で一番頑張って貢献しているのは誰だと思う?誰を一番尊敬する?
  • きみが私だとしたら、どんな改革をしたい?
  • われわれの製品で一番気に入らない点は?
  • われわれがチャンスを逃しているとしたら、それはどんな点だろう?
  • われわれが本来やっていなければならないのに、やっていないのはどんなことだろう?
  • この会社で働くのは楽しい?

まとめ

紹介しなかったどの章も興味深く、組織で働く上で折に触れて読み返したいと思えるような本だった。