Reactを使うならRecoilも学べば良いと思うって話

こんにちは、 tbaba です。元々 Rubyist として入社していますが、ここ2〜3年はフロントエンド力の向上にも力を注いでおります。

突然ですが、React で状態を管理する時に何を使っていますか?クラスコンポーネントにしてクラスに状態をもたせている、Redux を使って管理している、React Hooks で管理している、などなど色々な選択肢があるかと思います。

そんな中で自分たちのチームは、現在社内向けのアプリケーションにおいて、フロントエンド開発をする際に Recoil という状態管理ライブラリを使うことが多いです。そこで、今日は「なんでそれ使うの」「何が便利なの」みたいな話ができれば良いなと思います。
先に言っておくと、自分のスキルセットとしては「 TypeScript を利用した開発2年目」「React を利用した開発3年目」「基本は Ruby on Rails が得意なバックエンドエンジニア」です。なので React の状態管理について理解の浅い点があるかもしれませんが、ご了承ください。

なぜ Recoil を使うのか

端的に言うと、Redux を使うことに疲れたからです。

Redux は React コンポーネントの状態 (state) を上手く管理するためのフレームワークです。元はデータの状態変化の流れを一本化しようというアーキテクチャの派生としてリリースされて、今では React アプリケーションの状態管理のデファクトスタンダードと言っても過言ではないくらい、様々なプロダクトで利用されていることと思います。

しかし、後述しますが Redux は大きなアプリケーションを作る際には更新処理などを整理してわかりやすく配置することができますが、その特性上複雑であったり、パッと見では理解しづらいところがあります。僕自身、Redux は書けるといえば書けるけど、あまり書きたくないな、と感じてしまいます。特に、よくある「マルチページアプリケーションの画面の一部を React 化する」と言った小規模な開発では使いたくないというのが本音です。

そんな時に React Hooks や Recoil を使うと、驚くほどシンプルにコードを書くことが出来ます。以下、その理由を書いていきます。

理由その1: 状態の持ち方が楽

例えば Recoil では、とある状態を持つときに以下のように設定します。

import React from "react";
import { atom, MutableSnapshot, RecoilRoot, useRecoilValue } from "recoil";

// Todo の id をインクリメントするやつ
let id = 0;
function getId() {
  return id++;
}

// Todo の型
type Todo = {
  id: number;
  content: string;
  isCompleted: boolean;
};

// Todo の状態の定義
const todosState = atom<Todo[]>({
  key: "state/todos",
  default: [],
});

const Todos = () => {
  const todos = useRecoilValue(todosState);

  const contents = todos.map((todo) => (
    <div key={`todo-${todo.id}`}>{todo.content}</div>
  ));
  return <>{contents}</>;
};

// 初期値のセット
const initialize = ({ set }: MutableSnapshot) => {
  set(todosState, [
    {
      id: getId(),
      content: "ご飯を買ってくる",
      isCompleted: false,
    },
    {
      id: getId(),
      content: "手を洗う",
      isCompleted: false,
    },
  ]);
};

export default function () {
  return (
    <RecoilRoot initializeState={initialize}>
      <Todos />
    </RecoilRoot>
  );
}

# RecoilRoot を置いて、その中で Recoil の関数を呼び出すようにしましょう、とかの基本的なことについては、公式ドキュメントを参考にしていただけると分かりやすいと思います。

keyatom を状態を示す一意の値、 default はデフォルト値です。
つまり、デフォルト値を自由に設定できるのが大変便利な上、 TypeScript で型を指定してあげることで、型保証も簡単に出来ます。

同じことを Redux を利用すると、「 reducer を作って」「 store を作って」「 connect して」など、色々とやることが多いですよね。そういうのはキレイさっぱりスキップできます。
状態の更新ですら、Redux なら「 action を作って」「 import して」「 dispatch に食わせて」「 connect して」といった風にしなきゃいけないところ、Recoil だと「 useSetRecoilState を呼び出す」で終わりです。

理由その2: 初期化がすごく分かりやすい

Redux や Hooks などでも初期化はできます。しかし、そのために Provider に store を食わせたり、そのために初期値のオブジェクトをデフォルト値のオブジェクトと手動でマージしたりとやることが多い印象です。 いちいち reducer 作ったりして大掛かりになるのも面倒くさいですね。

ところが、 Recoil はそれすら簡単です。

import React from ‘react’;
import { RecoilRoot, todosState } from ‘recoil’;
import { Todo } from ‘./models’;
import { todosState } from ‘./modules’;

const initialize = ({ todos }: Todo[]) => ({ set }: MutableSnapshot) => {
  set(todosState, todos);
};

export default function (props) {
  return (
    <RecoilRoot initializeState={initialize(props)}>
      <Todos />
    </RecoilRoot>
  );
}

このように App というルートコンポーネントが持っている初期値を、 RecoilRoot が持つ initializeState に食わせるだけで良いのです。その中では set という関数が使えるため、 atom と初期値を渡してあげればそれだけで状態として保持してくれます。
もちろん、 initializeState 関数の中で非同期で取得し、それを set に渡すことも可能です。

非同期の場合は atom 直ではなく selector を使って状態をセットすることも可能なのですが、それはまた別のときにでも。
そういえば、Redux などでは非同期処理のためにミドルウェアを入れたりしますね。 Recoil の場合は最初から対応しているため、特殊なミドルウェアの導入などは必要ありません。閑話休題。

理由その3: 余計なところで状態を読み込まなくて済む

状態管理、面倒くさいですよね。分かります。いろいろ継ぎ足していったらものすごい大きなオブジェクトが完成して、しかもそれがどっか更新するたびに全部更新されるみたいなことが起こりえます。更新したいのはほんの一部なのに!と思うことがありますね。
Redux だと、大きな reducer を作ってあげたり、複数の reducer を combineReducers を使って名前空間が区切られている一つのオブジェクトにする、といった風に、少し工夫してあげる必要があります。が、それを理解するのはしんどいです。React Hooks の Context API で頑張る、でも良いのですが、結局複数の Context を管理する必要があって煩雑でした。

それに対して Recoil は簡単です。それぞれの状態を atom が持っているので、「Aの状態を知りたかったらAの atom を見に行けば解決!」という風にスッキリさせることが可能なのです。

const todosState = atom<Todo[]>({
  key: 'state/todos',
  default: [],
});

const loadingState = atom<boolean>({
  key: 'state/loading',
  default: false,
});

function ComponentA
  const todos = useRecoilValue(todosState);
  const loading = useRecoilValue(loadingState);

  return (
    <>
      {loading ? <div>Now loading</div> : todos.map((todo) => <div>{todo.content}</div>)}
    </>
  );
}

function ComponentB
  // loadingState は見る必要がないので省いて問題がない
  // ここの todosState は、 ComponentA で見ているものと同じものを見ていることになる
  const todos = useRecoilValue(todosState);

  return <>{todos.map((todo) => <div><input type="checkbox" checked={todo.isCompleted} />ステータス</div>)}</>;
}

値を参照したいだけなら useRecoilValue 、参照と代入をしたければ useRecoilState 、代入のみしたければ useSetRecoilState を利用しましょう。

このように、Recoil は一つのオブジェクトに状態を集約させたり、複数の Context を管理したりする必要がありません。 RecoilRoot コンポーネントの中であれば、自由に呼び出すことができる*1ので、とても便利なのではないでしょうか。

まとめ

以上のように、 Recoil はコンパクトで、状態を管理しやすく、Hooks に慣れていれば使うときにもあまり悩まない大変便利な状態管理ライブラリです。基本コンセプトが「コンポーネント間で共有される状態 (atom) 」と「関数 (selector) 」で、それよりも複雑なことはやろうと思えばできるし用意もある、でも基本この2つでどうにかなるよ、というものなのです。
加えて TypeScript との親和性も非常に高く、ここ最近の Redux に心をやられているという方には大変おすすめとなっております。

ただ、気をつけたほうが良いこともあるので、こちらに書いておきます。

実はまだメジャーリリースがない

この記事を書いている 2021/05/31 現在、最新バージョンが 0.3.1 となっています。つまりまだ大変活発に実装が進んでいる、枯れていないライブラリです。そんな状況なので、いつ API が変わってしまうかもわかりません。
加えて、 description には Recoil is an experimental state management library for React apps. とあります。 experimental です。実験的なライブラリなので、無くなる可能性も考慮しながら作る必要があります。もし無くなってしまったっ場合は自分で保守するという強い意志を持ちましょう。

シンプルで自由度が高いがゆえに気をつけたい

atom を利用することで、シンプルに状態を作ることができるのはここまでで理解していただけたかと思います。
しかし、それゆえにぽんぽん自由に状態を突っ込んでいくと、結局のところ「何がどういう風にデータとして入っているのか」「どう更新処理を入れればよいのか」が分かりづらくなってしまうのは間違いありません。
そういう状態になってしまうのを避けるため、可能な限り型を使って安全に入出力値を定義してあげるのをオススメします。
selector などを使って非同期に処理を行う際も同様です。

とりあえず社内のアプリから、いかがですか?

いきなり本番環境に投入するの怖いとかがあるのでしたら、社内で使うようなちょっとした便利アプリなんかに Recoil を導入してみるのはいかがでしょうか?
触っていて面白いですし、これまでそこそこちゃんと設計してやらなきゃいけなかった React の状態管理がサクサク進むというアハ体験を感じることができますよ!

人を探しています

そんな弊社ですが、実は開発チームを技術面からリードしてくれるようなエンジニアを募集しています。
2つのプロダクトとチームがあって、どちらかに入ってもりもりと開発を進めたり、技術的な検証やアドバイスをしてくれる、そんな方を探しているところです。
もしご興味があれば一度、以下の求人から「話を聞きたい」などでコンタクトを取っていただけると幸いです。
(ちなみに tbaba は採用にも関わっており、もし選考に進んでいただけるとなればご挨拶する機会もあるかと思います。その時はぜひお喋りしましょう)

jobs.forkwell.com

jobs.forkwell.com

*1:実装の中身は React Hooks なので、呼び出しの制約は Hooks に準じるのだけ注意です。

リモートワークでも存在感を出すために

はじめに

こんにちは!Crowd Agent 開発チームのmktakuyaです。昨年11月に株式会社groovesに入社し、6名程度のスクラムチームにて主にサーバサイドの開発を担当しています。また、スクラム外でのタスクとしてカスタマーサクセス推進のためのKPI設定やSlackの無駄カスタムレスポンス量産などに従事しています。

f:id:mktakuyax:20210317230338p:plain

無駄カスタムレスポンスの一例

弊社の開発チームメンバーは、北は北海道、南は宮古島まで全国各地に散らばっております。2020年は新型コロナウイルス感染症対策をきっかけとして全国的にリモートワークが広まりましたが、弊社ではその5年前、2015年からリモートワークを本格的に導入してきました。

リモートワークでも存在感を出すために

場所に縛られず自分好みの環境で仕事が出来るリモートワークですが、一方で何も工夫しなかった場合、オフィスワークに比べて他メンバーとのコミュニケーションの総量が減り、社内での存在感を発揮しにくくなるという問題もあります。

オフィスで机を並べて仕事をしていたときにはあった、たまたま廊下ですれ違ったときに生まれる「こないだリリースされた○○機能、めっちゃ評判良かったよ!」「先日の○○の件、一応解決したもののまだこんな問題があるみたいで……。」といった何気ない会話。これらはリモートワーク環境下ではなかなか生まれません。もちろん仕事で必要な会話ならテキストベースなりMTG組むなりで話すべきですが、そこまででもないちょっとした会話からより良いフィードバックが生まれたり、知らず識らずのうちに存在感を発揮できていたものです。

今回はそんなリモートワークの中でも存在感を出し、社内の各ステークホルダーにとって頼れるエンジニアになるため気をつけていることを書いていければと思っています。

Slack キーワード通知を活用する

Slackには、事前にキーワードを設定しておいてそれに引っかかる投稿を通知してくれる機能があります*1。自分の名前やハンドルネームはもちろん、最近リリースした機能についてもキーワードを設定しておくと良いかもしれません。

f:id:mktakuyax:20210329121923p:plain

筆者の通知キーワード一覧

もちろん何かあったらメンションしてもらうのが一番ですが、そこに至る前の軽い問題意識の状態からWatchしておくことによって発見できることもありそうです。あとは、自分達が作った機能がどんな使われ方をしているのかはエンジニアなら把握しておきたいですよね。

ある程度キーワードで絞ってWatchしておくと、実際に相談が来た時に「あぁ、あの話ですよね!」という打ち返しをすることが出来ます。背景説明のコストを省きより本質的な議論に時間を割くことが出来るので、仕事の質も上がりますよね。また、単に名前を呼ばれた時に反応しておくと文字通り存在感を出すことができそうです。

問い合わせ対応のその後をremindでフォローアップする

コードを黙々と書くだけが開発チームの仕事ではありません。その代表例として、各チームからの問い合わせ対応があります。オンサイトでもリモートでも、大体の問い合わせとその対応はチャットベースで行われるかと思います。

オフィスであれば廊下ですれ違った際に「昨日の○○の件、あの後どうなった!?」と自然なフォローアップが可能です。そこから「実はまた別の小さな問題があって……」という話になるかもしれないし、無事に解決してお礼など言われたらそれはそれで嬉しいものです。

が、リモートワークだとそうもいきません。対応が終わり自分の手を離れた問題のことは普通は忘れてしまいますし、廊下ですれ違うなどを通じて思い出すきっかけもありません。

僕の場合は、一度対応が終わった問い合わせのメッセージに対してremindを設定し、後日(ものによって翌日にしたり、「1週間くらい様子見ましょうか」と言ったなら1週間などいろいろ)また通知が来るようにしています。Slackのメッセージにリマインダを設定する方法はこちらをご確認ください。

slack.com

後日のフォローアップをすることで、その対応が良かったのかどうかを確認することが出来ますし、新たな問題があればそれに早く気づくことが出来ます。何も問題が無かった場合でも感謝され良い気持ちになることが出来ますよね。 

対外的なやりとりのタスクを買って出る

問い合わせ対応とも似ている話ですが、対外的なやりとりを必要とする仕事はテキストベース・口頭問わず積極的に取りにいくようにしています。開発チームからBizのみなさんにお願いする事柄を伝えることだったり、なにか決め事をするのにエンジニアのアサインが必要と言われていることだったり、あるいは社外の方とのMTGだったりです。

あまりやりすぎるとコードを書く時間が減ってしまうのでツラいですが、何もやらないと開発チームが「チケットを投げてしばらくすると動くソフトウェアが出来ている謎の組織」になってしまいかねません。

どこかで決まったことに沿って実装をするだけでなく、自ら何かが決まる場に出向くようにすると、存在感を発揮できるだけでなく、開発者の立場から意思決定プロセスに貢献することが出来たり、普段とは違うコンテキストで会話することによって事業を進めるための視点が得られるようになったりします。

リフレクションで感謝の気持ちを伝える

弊社では、その日の業務を振り返り次へつなげる内省の機会を作るため、業務終了時にリフレクションを投稿するようにしています。

これは最近はじめたことなのですが、みなさんのリフレクションを読んでemoji reactionをつけるようにしています。また、MTGや問い合わせ対応等でお世話になった方には、スレッドにて感謝の言葉を書くようにしています。

問い合わせ対応フォローアップの項目でも書きましたが、リモートワーク・テキストベースメインでの仕事をしていると、ちょっとした会話をするチャンスがなかなかありません。かつ、「わざわざ別チームのチャンネルに登場してまで言わなくてもいいか」という気持ちになってしまうところもあります。

そういうときは、リフレクションを書くときに本日のGood Job欄*2で感謝の気持ちを述べたり、その人のスレッドまで行ってお礼を言ったりなどをしています。

f:id:mktakuyax:20210329135355p:plain

リフレクションチャンネルでのやり取りの一例

おわりに

というわけで、リモートワークでも存在感を出すために僕が気をつけていることのうちのいくつかを書き出してみました。

ここまで書いたようなことをやった甲斐もあってか、2020年度下期のMVPを受賞することが出来ました。組織の垣根を超えコラボレーションをすることが出来たからとのことでしたが、これはここまで書いていたようなことを実施出来たからなのかなぁと思っています。

一方で、ここに書いてあることを厳密に全部やると、コード書く時間がなくなるなぁとも思います。月並みな意見ですが要はバランスで、自分の仕事のどこか一部分を改善したいなと思ったタイミングで参考にしていただければ嬉しいなと思っています。

リモートワークで存在感を出せずに悩んでいるエンジニアの方がいらっしゃいましたら、参考にしていただけると幸いです。

 

株式会社groovesでは、求人データベースの「Crowd Agent」と成長し続けるエンジニアを支援するサービス「Forkwell」を開発・運用しています。

どちらのサービスも、リモートワークでプロダクトの価値を高めて頂けるエンジニアを積極採用しています。エントリーお待ちしています!

jobs.forkwell.com

jobs.forkwell.com

*1:Slack 通知を設定する | Slack

*2:弊社のリフレクションのフォーマットにある、誰かへのGood Jobを伝えるコーナー

PM3年目にして気づいた「プロダクトマネジメント3つの基本」

こんにちは、プロダクトマネージャー(以下、PM)の一柳です。 groovesでは Crowd Agent(クラウドエージェント) というtoB向けSaaSサービスを担当しています。

私は今年でPMキャリア3年目の駆け出し(?)PMなのですが、これまでの2年間を振り返って感じた「プロダクトマネジメントの基本」を3つのポイントに絞ってお伝えします。

ポイント1: PMはドキュメンテーションがとても大事

アジャイル開発を採用している開発現場におけるドキュメンテーションへの誤解として「アジャイル開発だから、ドキュメント不要なのでは?」というものがあります。(最近は流石に減ってきた気もしますが・・・)

またドキュメント不要論としては「どうせ仕様変更に対して追従できなくなるのだからドキュメント作っても無駄」というものもありますね。

ソフトウェアエンジニアとして開発に従事しているとどうしても「ドキュメントを書くよりコードを書いたほうが早い!コードこそが生きたドキュメントだ!」と感じることが多いですし、実装フェーズにおいてはその見解が正であることが多いと思います。

ただPMが関わる要件定義フェーズにおいては、ドキュメントに十分な情報が残されていないと、とても困ることになります。 通常、要件定義フェーズにおいてPMはPRD(Product Requirements Document)と呼ばれる文書を作ることが一つのマイルストーンとなります。

PRDをざっくり説明すると、プロダクト(または機能)を作る理由や、評価方法を記載したドキュメントです。

PRDがいい加減な内容の場合「開発チームが実装した成果物(Output)が事業成果(Outcome)につながらない」ということが発生します。

せっかく貴重な開発工数をかけて開発していくわけなので、どのような狙いがある機能で、その狙いが達成できたか否かをどう評価するのかぐらいは分かっている状態で開発していきたいですよね。

また、PM視点からすると他にもPRDをしっかりと記載したほうがいい理由が2点あります。

1点目は合意形成コストが削減できること。

プロダクト施策の実施には、プロダクトチームだけでなくセールスチームやカスタマーサクセスチームなど多くのステークホルダーとの合意形成が必要です。 各ステークホルダーが論理的に納得できている状態を作るために各種調整を行うのがPMのしごとの1つですが、口頭で確認、納得したとしても人はいずれ忘れてしまいます。

というわけでなんども同じ説明、説得をしてもしょうがないので、合意事項とそのロジックは全てPRDに記載して読めばわかる状態を作るのが合理的です。

2点目は施策評価についての保険をかけることが出来ること。

PRDが立派であれば施策が成功するわけではないですが、PRDがしょぼいとだいたい失敗します。

ですので、実施施策のマイルストーンとしてPRDをレビューすると手酷い失敗を防ぐ効果があると考えています。

またPMの人事評価という面でも、PRDをOutput評価の1つとして見てもらえると自身でコントロール可能な評価項目が増えるので安心して働けますね。 (究極PMへの評価はプロダクトの成功指標と連動すると思いますが、プロダクトのフェーズや特性によってはそれだけで評価する/されるのは難しい場合もあるため。)

ポイント2: 施策の基盤は「KPIとユーザーニーズ」

ドキュメンテーションの話の延長となりますが、PRDを作成する時点でKPIとユーザーニーズが両方が明らかになっていない状態で施策を実施するのは非常に危険だな感じています。

この2つが押さえられていない場合、施策の振り返りが困難です。何がどう成功 / 失敗したのか要因分析ができなず、学びが得られない。その結果として学習サイクルが回らずにプロダクトの成長が止まってしまいます。

恥ずかしい話、昨年の私はKPIとユーザーニーズそれぞれ片方だけでも分かっていればいいのでは?と勘違いしていたのですがどちらか片方だけでは説明ができないことが多すぎて大変苦労しました…。

KPIは設定されているがユーザーニーズを理解していないパターン

このパターンの場合

  • ユーザーニーズが分からないので、定量データの変化の解釈を間違えやすい。
  • ユーザーニーズを無視したKPI向上施策はevilになりやすい。

という罠にハマります。

evilな施策例としては下記のようなケースが想定できます。

記事ページのPVをKPIとして、これを向上させたいというシーン。

→ 一覧表示画面で重要情報を隠し、記事へのアクセスを誘導する施策を実施する。

→ ユーザー視点では記事ページにいかないと情報確認ができず利便性が下がっているがPVは向上する。

ユーザーニーズを理解しているがKPIが設定されていないパターン

KPIがなくて困るケースは単純で、施策評価ができないことです。 せっかくユーザーが喜ぶ機能をリリースしても、定量的に評価できなければ意味がないですよね。

また単に定量データが分かるというだけではなく、事業上のゴールと紐づくKPI として設定されている指標が存在することが大事です。 事業ゴールとの因果関係を説明できない指標が向上したとしても、事業の方向性とマッチしているのか確認できなので単にプロダクトの独りよがりになってしまいます。

既存のKPIがイケてないので、良いKPIを探索、再設定するという行為は有りえますが新しいKPIを設定し、指標の確からしさを検証するのはなかなかに大変なので施策実施前に済ませておきたいです。

ポイント3: プロダクトマネジメントは「チーム」で実現する

もともと弊社ではPMが1名でプロダクトマネジメントの全てのタスクを実施する体制だったのですが、どうにもこうにも1人でタスクを回せる分量じゃない!辛い!ということで、2020年4月よりプロダクトマネジメントチームを組成し、チームでタスクをこなす体制となりました。

スタートアップの初期段階ではPM + デザイナー + エンジニア数名といったミニマムチームで回すことも多いかと思いますが、ある程度プロダクト規模が大きくなり関連する組織の規模も増えるとPM1名だけで全てのタスクをこなすのは難しくなってきます。(残業時間がエグいことに…)

PMは、開発チーム、マーケチーム、営業チームetc...といった事業を構成する各組織をつなぎ合わせていく動きが求められますので、組織規模が大きくなるほど調整・交渉範囲がひろくなり、一人ではカバーできない領域がでてしまいます。

いかに効率的にプロダクトマネジメントを行うか、ということを考えた際に取れる選択肢は以下の3つと考えます。

  • 問題を抽象化して捉え直す
  • 調査コストを支払い学習する
  • 必要なスキルを備えた人をチームに迎える

問題を抽象化して捉え直す

日々PMが対処する様々な問題を全てイチから調査・検証・判断していくのはとてもコストが高いです。

対応していく問題を一段抽象化することで、対処しなければ行けない問題や、解放の選択肢がシンプル化して対応コストが下げることができます。

調査コストを支払い学習する

例えばマーケや開発に関する用語やセオリーが分からない、社内の誰もドメイン知識を持っていないといった場合、問題に着手するまえに調査段階を踏んで学習するフェーズを設けましょう。 前提となる知識がない状態で問題に取り掛かっても無駄にコストがかかったり、失敗/手戻りのリスクが高くなります。

必要なスキルを備えた人をチームに迎える

ドメインエキスパート、UXリサーチャー、テクニカルディレクター、マーケター…とにかく自分が持っていない専門知識を持っている人間をPMチームに迎えて一緒に問題解決していきます。 同じチームで働くことでPM自身も足りない知識が補われていくので、前段の学習効果も期待できます。

もしいま1人でプロダクトマネジメントすることにつらみを抱えている方がいましたら、自身のスキルと、事業・プロダクトフェーズによって求められているスキルの差分を確認し、足りないスキルを補うようにチームビルディングしていくことをオススメします。

おわりに

この記事ではPM3年目の筆者が自身の業務を振り返った際に気づいた「プロダクトマネジメントの基本」を記載しました。 まだまだPMの深淵に触れたばかりで力不足を感じる場面も多いですが、ドキュメンテーション、KPIとユーザーニーズ、チームによる協業の3本柱を外さずにプロダクトマネジメントに邁進していきます。

もし私達と一緒に働くことに興味がございましたら、お気軽にカジュアル面談へご応募ください。

https://jobs.forkwell.com/grooves/jobs/5467

https://jobs.forkwell.com/grooves/jobs/7805

Heroku Review Appsで「使える」レビュー環境構築

こんにちは。grooves エンジニアの福井(@bary822)です。普段はCrowd Agentを開発しています。

今回はCrowd Agentのリリースフローが抱えていたボトルネックををHeroku Review Appsを使って解決した方法をご紹介します。

似たような課題をお持ちの方に解決のヒントを与えることができればと思いながらこの記事を書いています。

リリースフローのボトルネック

Crowd Agentではスクラム開発を採用しています。

スクラムでは開発者はPO(Product Owner)が定義する受け入れ条件を満たす機能を実装することを期待されていますが、Crowd Agentでは「POデモ」と呼ばれる受け入れチェックによりこれが正しく実現されていることを担保しています。

f:id:grooves:20200915175947j:plain

実はここにボトルネックが存在します。それはStagingが1つしかないことです。

複数の機能開発が並行して進んだ場合、POデモも機能毎に実行する必要がありますが、一度に使えるStaging環境は1つのみです。既にStagingが使われていた場合、他の開発者はPOデモが終わるのを待たなければなりません。

f:id:grooves:20200915175830j:plain

また、POが多忙でPOデモに使うことの出来る時間が限られていることもあり、デモが終わる度にStagingにデプロイし直すことも現実的ではありませんでした。

作って壊せる検証環境

このボトルネックを解消するためにHeroku Review Appsを利用することにしました。

ご存知の方も多いかと思いますのでここではHeroku Review Appsについての詳細を書きませんが、いわゆる「作って壊せる検証環境」を構築できるものです。

GitHubとHerokuを連携させることにより、Pull Requestが作成/更新されたイベントをHerokuに通知し、予め定義したフローに沿って自動的にアプリケーションがデプロイされることができます。

Heroku Review Appsを導入することでStagingの空き待ち時間を無くし、同時に複数の機能をPOデモできる環境を構築することに成功しました。

f:id:grooves:20200915175836j:plain

これによりボトルネックは解消され、開発された機能がスムーズに本番環境にリリースされる状態をつくることができました。

と、ここまで流暢に書いてきましたが、実はこれが実現されるまでにはいくつもの困難がありました。

独自サブ-サブドメイン使えない問題

Herokuではデプロイされたアプリケーションに自動的にドメインが付与されます。例えば、crowd-agent.herokuapp.com のようなものです。 Heroku Review Appsでは、サブドメイン部(crowd-agentに当たる部分)を任意の値に変更することができますが、サブ-サブドメイン部(*.crowd-agent)は指定することができません。

Crowd Agentではユーザーの属性によってログイン後のドメインを分けていたため、サブ-サブドメイン部を任意の値にコントロールし、同じアプリケーションにルーティングさせる必要がありました。

f:id:grooves:20200915175843j:plain

公式ドキュメントを読み進めていくと、どうやら独自ドメインを使うと解決できることがわかりました。

*.herokuapp.comは内部的に*.herokudns.comというドメインへのCNAMEレコードをもっているため、同様に独自ドメインからもCNAMEレコードを作成して紐付けるというものです。 確かに独自ドメインであればサブ-サブドメインのレコードも自由に設定することができます。

f:id:grooves:20200915175850j:plain

これはHerokuの設定ファイルである app.jsonpostdeployエントリにDNS登録作業を行なうスクリプト実行コマンドを指定することでデプロイ語に自動的にすることができます。

app.json

"postdeploy": "bin/rails heroku:review_apps_setup"

lib/tasks/heroku.rake

aws_client = Aws::Route53::Client.new(access_key_id: AWS_ACCESS_KEY, secret_access_key: AWS_SECRET_ACCESS_KEY)
heroku_client = PlatformAPI.connect_oauth(HEROKU_API_TOKEN)

hostname = "pr-#{heroku_app_name}.crowd-agent-review.com"

 domains = [nil, :admin, :agent, :company].map do |subdomain|
   hostname_with_subdomain = subdomain.present? ? [subdomain, hostname].join('.') : hostname

   # Heroku上にドメインを作成
   heroku_client.domain.create(heroku_app_name, hostname: hostname_with_subdomain)
   heroku_cname = heroku_client.domain.info(heroku_app_name, hostname_with_subdomain)['cname']

   # Route53用の設定を定義
   config = {
     hosted_zone_id: '/hostedzone/XXXXXXXX, # crowd-agent-review.com
     change_batch: {
       changes: [
         action: 'CREATE',
         resource_record_set: {
           name: hostname_with_subdomain, type: 'CNAME', ttl: 3600, resource_records: [{ value: heroku_cname }]
         }
        ],
        comment: "Review environment host for branch #{branch}"
      }
    }

    # Route53にレコードを作成
    aws_client.change_resource_record_sets(config)

    [subdomain || 'root', hostname_with_subdomain]
 end

 hash = {}
 domains.each { |item| hash[:"APP_#{item[0].upcase}_DOMAIN"] = item[1] }

 # Herokuにドメインを登録
 heroku_client.config_var.update(heroku_app_name, **hash)

 puts "App is successfully built!"

動作が遅すぎて使い物にならない問題

無事にドメインが設定され、ようやくブラウザから操作できるようになったReview Appsですが、実はあまり活用されていませんでした。なぜなら動作が遅すぎて全く使い物にならなかったからです。

どのくらい遅かったかと言うと、レンダリングするまでに30秒近くかかるページもあるほどでした。これでは開発者もPOも使ってくれません。

どこにボトルネックがあるかは明確でした。App - DB間のレイテンシです。

初期構成では実装コストを下げるために、Staging環境で利用しているDBをReview Appと共有していました。 しかし、Heroku上のAppはUS(Virginia)リージョンに、Staging DBはTokyoリージョンに配置されています。

動作が遅くなっていた原因は、この通信に大きなレイテンシが発生していることでした。

一旦整理すると、初期構成の全体像は以下のようになります。

f:id:grooves:20200915180014j:plain

HerokuのAppがVirginiaリージョンに配置されていることは以下のコマンドで確認しました。

# Herokuの認証情報はあらかじめexportしておく
$ curl -n -X GET https://api.heroku.com/regions/us -H "Accept: application/vnd.heroku+json; version=3"
{
  "country":"United States",
  "created_at":"2012-11-21T20:44:16Z",
  "description":"United States",
  "id":"59accabd-516d-4f0e-83e6-6e37577XXXX",
  "locale":"Virginia",
  "name":"us",
  "private_capable":false,
  "provider":{
    "name":"amazon-web-services",
    "region":"us-east-1"
  },
  "updated_at":"2016-08-09T22:03:28Z"
}

これを解決するために、まずはAppをTokyoリージョンに移せないか検討しましたが、コスト(お金)の面から難しいことがわかりました。

Review AppsをUS以外のリージョンで使うためには、Private Spacesという有料の機能を使う必要があります。今回の場合、レイテンシ解消で得られる恩恵は$1000/月(2020年9月現在)という価格を下回っていると判断し、導入を見送ることにしました。

この代替案として、DBをUS(Virginia)リージョンに移すことを検討しました。 Staging DBを共有するのではなく、全Review Appsで共通の専用DBをVirgniaリージョンに設置するというものです。

f:id:grooves:20200915180018j:plain

これによりレイテンシは改善され、ページがレンダリングされる時間は1/10まで短縮されました!

また毎デプロイ後、自動的にDBのテーブルセットアップやテスト用データの作成を行なうようにしました。これでデプロイ後すぐにPOデモを依頼することが可能になりました。

app.json

"postdeploy": "bin/rails heroku:review_apps_setup && bin/rails db:migrate db:seed"

まとめ

今回はHeroku Review Appsを使ったリリースフロー上のボトルネック解消方法、また導入時に私達が直面した問題とその解決方法の一例も併せてご紹介しました。

現在Heroku Review Appsは開発からリリースまでのリードタイムを減少させる有効なツールとして、私達の開発になくてはならない存在となっています。

個人的には開発チームを支援するツールの導入・作成は大好物なので、このタスクに携わることができて大変嬉しく思っています。

最後に、Crowd Agent開発チームではアプリ開発に強みを持つエンジニアとインフラ技術に強みを持つエンジニアを募集しています。

開発メンバーは全員フルリモート勤務となりますので、都市部以外にお住まいの方、また都市部から地方への移住を検討している方からの応募も大歓迎です!

みなさまのエントリーお待ちしています!

jobs.forkwell.com

jobs.forkwell.com

grooves のオンボーディング(開発チーム編)

こんにちは!grooves の開発チームでエンジニアリングマネージャーをしている吉永です。

ひさしぶりの開発ブログ更新ですが、今回は grooves の開発チームのオンボーディングプロセスをご紹介します。タイトルに「開発チーム編」と銘打っているのは、grooves のオープン社内報にて、ほぼ同時期に採用していたデザイナーのオンボーディングの様子をご紹介しているからです。よろしければ是非そちらもご一読いただけると幸いです。

前提

ここでのオンボーディングとは、新たに採用した人材を職場に配置し、組織の一員として定着させ、戦力化させるまでの一連の受け入れプロセスのことを指しています。 良いエンジニアを採用するのは一苦労ですが、オンボーディングでつまづいてしまうと、採用の苦労も報われなくなってしまいます。私たちは、採用とオンボーディングを地続きで考えるようにしています。

今年はコロナウイルスというイレギュラーな事態が発生し、採用やオンボーディングにも大きな影響がありました。具体的には、そのプロセスのほとんどを、オンラインで完結しなければならなくなりました。もともと grooves の開発チームはフルリモートでの環境を整えていましたが、採用面接や入社直後はオフィスに出社して実施していたため、全てオンラインで実施するということは新たなチャレンジとなりました。

この前提を踏まえて、実際にオンボーディングで取り組んでいることをいくつか紹介します。

オンボーディングのゴール

grooves ではスクラム開発を採用しています。オンボーディングのゴールは、

「スクラムの開発チームのメンバーとして、成果に貢献できる状態」

を目指すようにしています。期日は入社時点のスキル次第で微調整します。「2つ先のスプリントからスクラムに加わってみましょう」といった具合ですね。プロダクトオーナーも、いつから戦力化するか考慮して少し先のスプリント計画を立てています。 このゴールから逆算してオンボーディングのプログラムを組み立てていきます。

入社直後〜入社後二週間

会社、事業、プロダクト、チームを知り、自分のことを知ってもらうための期間です。

  • 自己紹介のページを書いてもらう
  • 会社のルールを知る研修
  • 事業を理解し、各部署の役割を知る研修
  • オンラインランチ・歓迎会

このような全社共通のメニューを行いつつ、開発チーム固有のメニューとして以下のようなことを行っています。

  • 課題図書( Team Geek や SCRUM BOOT CAMP THE BOOK など)を読む
  • スクラムについての研修
  • プロダクトについての研修
  • チームメンバーとのデイリー1on1
  • 今月頑張ったことと、来月頑張りたいことを共有する場(お互いを知る会)に参加

メンバーとの1on1や、お互いを知る会への参加は、メンバーそれぞれがどういう価値観を持っているのか、相互理解を深めることができる取り組みです。こういったことを行いながら開発環境を整え、プロダクトのコードを読み進めてもらっています。

入社二週間〜入社後二ヶ月

スクラムに加わるための準備期間です。いきなりスクラムのメンバーに加えてしまうと、見積もりや計画が不安定になってしまいます。新入社員の方には、スプリントバックログとは別の開発を担当してもらうことで、スクラム開発の見通しを維持しつつ、開発に慣れてもらいます。

  • 開発チームは、プロダクトの理解度を高める助けになりそうな開発項目を、バックログからピックアップし、着手可能な状態にする
  • 新入社員の方は開発に着手し、見積もり(ストーリーポイント)のイメージをつかんでもらう。
  • チームのレビューを通す前に、スクラムマスターが事前レビューを行い、Pull Request の基準を知ってもらう。

このような準備期間を経て、いよいよスクラムチームのメンバーとして開発に携わってもらうことになります。

スクラム開発へ

準備期間の中で、ドメイン知識や、スクラム開発のフローについては一定理解した状態が実現できています。しかし、いざスクラムチームに入ってみると勝手が違ったり、スプリントゴール達成のプレッシャーに晒されたりと、ギャップを感じる部分はあるようです。以下は最近入社した方から実際にいただいた意見です。

  • 実際やってみると、実作業をする上で十分なコードの理解ができていなかった
  • スクラムのイベントの目的を、十分理解できていなかった
  • チームメンバーに、どこまで頼っていいかわからなかった
  • 見積もりの感覚がチームと合わないことがある

オンボーディングの内容を見直して、こういったギャップをひとつひとつ取り除いていきたい、と考えています。

リモートで働くチームが大切にしていること

私たちのチームは、リモートを前提として設計されています。チームで円滑にコミュニケーションし、協業するために大切にしていることがいくつかあります。

  • Do
    • HRT(Humility 謙虚、Respect 尊敬、Trust 信頼)を大事に
    • アウトプットし、アウトプットを可視化する
    • ドキュメントに残す
    • 自分の意見をはっきりと発信する
    • リモートで働く利点を最大化する
    • チームとしての成果を意識する
  • Don’t
    • チャットでの即応答などは求めない
    • チームに遠慮はしない
    • ローカル(オフライン)の環境をリモートで再現しようとしない

オンボーディングの時点からこれらを身に付けてもらうように、スクラムイベントの会議や1on1などの場を使い、意識し行動を促すようにしています。

以上です。

最後にgrooves ではソフトウェアエンジニアを絶賛募集中です。興味を持っていただけたら是非こちらのForkwellの求人からエントリーいただけると幸いです。

イベント当日にパネリストが来れない!急遽リモート先から登壇してもらった方法

こんにちは。株式会社grooves Forkwell事業部の赤川です。

つい先日、私たちが主催したイベントでちょっとしたハプニングがありました。
そのイベントのコンテンツに、福岡から東京に飛行機で来て頂くまつもとりーさんによるパネルディスカッションがあったのですが、イベント当日の朝に急遽東京に行けなくなってしまった、という連絡がありました。
過去に、リモートでの登壇発表は何度か見たことがありましたが、リモートでのパネルディスカッションは見たことがありません。
その時点でのイベント参加登録者数は90名を超えていました。
主催者である私としては、直ちに、中止にするか、実行するか、実行するならどうやるのか、を判断する必要がありました。

本日は、このシチュエーションを Zoom を使ったリモートパネルディスカッションによって乗り切った経験をご紹介します。
同じ環境を用意すれば、誰でもリモートでのパネルディスカッションを成立させることができますので、

  • 私と同じシチュエーションに遭遇するかもしれない方
  • 遠隔地の登壇者による双方向性のイベントを企画している方
  • 2会場以上での同時イベントを企画している方

にお役に立てていただければ幸いです。

目次

  • 実際に使った機材の構成図と解説
  • 最小限の機材での構成図
  • 準備時のチェックリスト
  • おわりに

実際に使った機材の構成図

f:id:redribabarn:20181011190304p:plain

実際のイベント模様

f:id:redribabarn:20181011140207p:plain

  • 自分たちでも驚くほど、スムーズなコミュニケーションができました。
  • 参加者アンケートの結果は、中継に関する不満が一切なく、イベントの満足度も満足以上が90%以上となりました。よかった!

構成図の解説

Zoom がおすすめな理由

  • Zoom を用いると、一つのパソコンで、画面共有とカメラ中継の両方を行うことができ、会場の雰囲気とスライドを同時に伝えることが可能です。
  • ただし有料会員でないと40分で中継が終了してしまいます。リモートワークする際に Zoom マジ最高なので会社に頼むなどして有料会員になっておくといいでしょう。
  • Hangouts 等を用いる場合は、スライド共有用のパソコンと会場中継用のパソコン(またはスマートフォン)を用意すると良いでしょう(設定は後述)

クリアな音声を届けよう

  • 会場の音声をリモート登壇者へ届けるために、会場スピーカーの近くに会場音声用マイクを置きました(Bluetooth のマイクだと設置位置の自由度が高くて良いです。私のおすすめは Jabra SPEAK 510 です)。
    • 会場音声用マイクがスピーカーに近いほど、参加者と同じ情報を同じ品質でリモート登壇者が聞ける状態になります。
    • マイクの音声をラインで取れたらベターでしたがその設備はありませんでした。
  • リモート登壇者の音声は、プロジェクター・ミキサーを通じ、会場のスピーカーから流しました。
    • このときのボリュームが、会場マイクからのボリュームと同じになるように揃えました。
    • プロジェクターからラインでミキサーにつなげない場合は以下の選択もあります。
      • パソコンから音声ジャックを通して、直接ミキサーにつなぐ方法(スマートフォンのZoomアプリからミキサーにつないでもOKです)。
      • パソコンから出る音を登壇者マイクで拾う方法(これはできれば避けたい)。
  • リモート登壇者には、ヘッドセットを使ってもらいました。
    • 会場側が受け取る音声がクリアになります。音声は大事です。

会場の雰囲気をリモート登壇者に伝えよう

  • 会場の様子を中継するためのカメラを用意しました。
    • これにより、登壇者が会場のフィードバックを得ながら進行できるようになり、自分も参加している感、当事者意識を感じることができます。
    • 相手からのフィードバックがないと、声が届いているのか不安になるのは、リモートあるあるですよね。

リモート登壇者の表情を会場に伝えよう

  • Zoom だと画面共有時にも常にリモート登壇者の表情が画面に出せるので、より一体感がでます。
  • プロジェクターへの投影方法はミラーリングを用いました。
    • ミラーリングを用いると、リモート登壇者を窓枠から表示する設定が少し簡単になります。
    • ファシリテーターがスクリーンを見ながらコントロールする必要がなくなるため、進行がスムーズになります。

通信トラブルに備えよう

  • Zoom を中継するパソコンはなるべく有線LANを用いるとよいです。
    • 参加者が無線LANを利用すると通信速度が落ちる可能性があります。
  • 今回の会場は有線がなかったので、無線が不安定な場合に備えて、映像中継を切り、音声のみを配信することも想定していました。
    • 映像中継を切った場合にも発表できるよう、事前にスライドを共有してもらい、会場側でスライドを手送りできるようにしていました。

反省点

  • 音が反響する会場だったので、リモート登壇者が少し聞こえにくかったようです。
  • 通常の会場より、タイムキーパーによる意思疎通が難しかったです。
    • チャットを活用して時間を連絡できたらよかったかもしれません。
  • こればっかりは仕方がないのですが、懇親会を楽しみにしていた方には申し訳なかったです。
    • リモート中継を決定した時点で、すぐにその旨を connpass を通じて参加者へ送信しましたが、それに気づけない方もいらっしゃったので他の方法も模索したいです。

最小限の機材での構成図

f:id:redribabarn:20181011190319p:plain

プチ解説

  • Zoom から出た音声を登壇者マイクで無理やり拾う方法です。
  • 会場の音声、映像はスマートフォンで中継します。
    • その際、スマートフォンから音声が出ないようにしておきます。
  • この構成の場合、Zoom ではなく、Hangouts や Appear.in でも大丈夫です(品質は Zoom が一番だと思います)。

この方法のデメリット

  • リモート登壇者が受け取る音声がクリアではなくなります。
  • リモート登壇者が、自分の話した声が自分にかえってきてしまうので、話しにくくなります。
  • 機材の相性や通信状況によっては、ハウリングが起こりうる設定です。必ずテストしてください。

こんな方法も…

f:id:redribabarn:20181011191933p:plain

準備時のチェックリスト

上記の方法をいつでも実行できるように、イベント前に確認しておくべきことをリスト化しました。

  • 模式図にある機材は揃っているか?
  • パソコンから出る音声(リモート登壇者の声)を会場から流すことができるか?その方法は?
  • 登壇者用マイクの本数は?(大きな会場だと2本以上ないと難しい)
  • 登壇者用マイクの音声を、ミキサーからラインで出力することができるか?
    • その際、登壇者のパソコン位置につなぐための十分な長さのケーブルはあるか?
  • 中継用のパソコンを有線LANにつなぐことは可能か?
    • その際、登壇者のパソコン位置につなぐための十分な長さのケーブルはあるか?
  • 登壇者の発表資料を事前に中継パソコンに収集しているか?

おわりに

今回のイベントは、エンジニアの方々にアウトプットの重要性を伝えることがテーマのイベントでした。
その中で、登壇者のkwappaさんが、自分の仕事の具体的な経験を抽象化し、一般化して社会みんなが使えるようにアウトプットするとよい、という発表をされておりました
それはいい!と思ったので、早速、自分のイベントでのトラブル経験をアウトプットしてみました。

参考になりましたら、ツイート、はてぶなどをお願いします。
また、赤川のこれまでのアウトプットはこちらにまとまっていますので、興味ある方はぜひご覧ください。

本当に良いエンジニアはいないのか?企業が採用に苦戦する本質とは

こんにちは。grooves にて Forkwell の事業責任者を務めている、赤川と申します。

この数ヶ月、 grooves では全事業部で積極的にエンジニアの採用活動を行ってきました。
当初は応募獲得に苦戦するだろうと思っていたのですが、結果は真逆で、あまりにも魅力的な方ばかりから応募いただけるので、採用に迷うことのほうが多いという結果になりました。

結果的に当初の予定より人員計画を増やすことになったのですが、それでもこの人と働きたいと思った方全員を採用できる状況ではなく、私たちとしてもぜひ一緒に働きたいと思っている方で、grooves を第一志望です、と言ってくれる方に対して採用枠の充足を理由にお断りしなければならないのは、非常に辛いことでした。

世の中には素晴らしいエンジニアがたくさんいるということを、改めて認識しています。

一方で、grooves が運営する Forkwell の元には、良いエンジニアが採用できないので支援してほしいという連絡が毎日届いています。
どの会社も、採用にはかなり苦戦していらっしゃるようです。

この差はなんなのでしょうか。

市場にはこんなに良いエンジニアがいるのに、どうして採用できない企業がこんなにいるのでしょうか。

私の意見は、魅力的なエンジニアに選ばれる企業が圧倒的に少ない、です。

選ばれないのは、差別化できるほどの魅力が足りないから

求人票を作る際に、STPを採用することは有効な手段の一つです。

STPとは、
適切な切り口で市場やユーザーを細かく分類して(セグメンテーション)、
分類した市場の中で狙う層を絞って(ターゲティング)、
その層に刺さる魅力で差別化する(ポジショニング)、
というマーケティングの基本的な考え方です。

STPを使うことで、自分たちの個性に合った方に自社を選んでもらいやすくできるのですが、そもそもポジショニングできるだけの魅力がないことが、多くの企業の課題になっているように思います。

この魅力づくりがないまま、採用ステップに進むから苦戦するのです。

魅力が足りない企業ほど、魅せ方にこだわりがち

魅力がある企業であれば、それを100%伝えることができれば、解決です。

Forkwell はエンジニアが選ぶべきかどうか正しく判断できるよう、なるべく詳しく求人に掲載していただくよう取り組んでいます。
しかし、10の魅力を10で表現することはできても、2の魅力を10に見せることはできません。

多くの採用広告では、このレートが100%からずれてしまうので、不幸が起きていると考えます。
このレートは、100%がいいのです。
50%であれば、まだ自分たちの会社が採用できないだけで済むのですが、150%にしてしまうと、入社した方が確実に不幸になります。これだけは絶対に避けなければなりません。

grooves はどうしているか?

結局、自社の魅力を底上げすることが一番です。

当たり前の給与

正直、大手企業やメガベンチャーと比較すると、届いていません。
それでも、事業の成長に伴って社員の給与は毎年平均10%で上がってきており、2018年は念願の賞与を導入することもできました(とはいえ、まだ年1ヶ月分を給与に上乗せできるレベルですが)。
ユーザーに価値を提供できれば会社が儲かる。会社が儲かった分はちゃんと社員に還元される。だからもっとユーザーに価値を届けようと頑張れる。そういうサイクルを目指して少しずつ積み上げてきました。もちろん、大手企業と並ぶには、高い生産性を実現しながら、よりユーザーに価値を届ける必要があることも理解しています。

最も大事なビジョン

私たちが何を目指したいのか、ぶれないビジョンを掲げています。
わざわざ大企業を断ってまで grooves に挑戦したいと思えるほど価値あるものを掲げなければいけません(少なくとも私はそう信じています)。
また、お飾りのビジョンには何の意味もありませんから、自ら実践する必要があります。groovesでは、 ワークシフトインフラを創るというビジョンに便乗して(ダジャレじゃないです)、様々な試みをしてきました。年初に話題にしていただいた記事もその1つです。

tech.grooves.com

他にも、フレックスやリモートワークは当たり前として、最近ではタイでのワーケーションにチャレンジする社員まで現れました。

www.wantedly.com

サービスがビジョンに沿っていることは大前提として、私たち自身でビジョンを体現することも、ビジョンの形骸化を防ぐために必要だと思っています。

チームの理想に近づける努力

ビジョンの中で働き方への取り組みを書きましたが、それだけではなく、チームとして理想の開発文化を作りあげていくということも大事です。

エンジニア自身が、「こんな組織にしたい」を言語化し、それに向けてどんな取り組みをしているのか発信していく。それに共感した人が集まり、理想とする開発環境ができていく。
その結果として、見積もりはみんなでする、テストを書く、PRをマージするにはプロジェクトで決められた人数以上のレビューが必要、ドキュメントを残す、gem などのライブラリは常に最新版を使うといったチームにとって当たり前の文化ができてきました。

Rails 5 リリース日に Forkwell を Rails 5にアップグレードしたのも、話題作りの意図もありますが、社内をエンジニアにとって刺激的な環境にすることで、働くこと自体も楽しんでもらいたいと思ったからです。

魅力が整ったら採用へ

こういった取り組みをした上で、エンジニアであれば Forkwell や開発ブログを通じて、ビジネスサイドであれば Wantedly などを通じて、伝達率100%を意識して発信しています。

grooves では、今年の2月から3月までに Forkwell Scout を使って20通のスカウトを送り、9名の素晴らしいエンジニアと面談することができました。スパムのようにスカウトを送らなくとも、良い出会いを作ることはできるのです。

現実的にはビジネスである以上、何かをする前に全てが揃うということはないので、今ある手持ちの魅力だけで戦うことにはなるのですが、魅力づくりに手を付けなければジリ貧が続くことを意識して改善を続けています。

まとめ

記事タイトルの「本当に良いエンジニアはいないのか?」という問に対しては、明確に「いる」とこたえます。
良いエンジニアに選ばれる企業が少ない、というのが私の見解です。

それを踏まえて、

  • 自社の魅力をあげよう
  • 伝達率を100%にしよう

という主張を行い、そのために grooves が行っているアプローチを書きました。

本記事が皆さんのよりよいエンジニア採用のきっかけになれば幸いです。

採用に苦戦しているポジションも

実はいま、最も採用に苦労しているのがデザインも好きなフロントエンドエンジニアです。
もし grooves に興味をお持ちいただけるようでしたら、ぜひ以下のリンク先からエントリーしてください。

jobs.forkwell.com