RubyKaigi Takeout 2021 にてプラチナスポンサーでの協賛をします!

RubyKaigi Takeout 2021 いよいよ来週開催ですね。 grooves(グルーヴス)でエンジニアリングマネージャーを担当している吉永です。RubyKaigi Takeout 2021のスポンサーができて嬉しいよ!という記事を書きましたのでご覧ください。

グルーヴスは今回めでたくプラチナスポンサーとして協賛することになりました。私たちは「はたらくヒトと、未来を拓く」というコーポレートビジョンを実現するために、Forkwell(フォークウェル)、Crowd Agent(クラウドエージェント)という2つのサービスをより良くしていこうと開発に取り組んでいます。どちらのサービスもRubyで開発され、長く会社の成長を支えてきました。Rubyがなければグルーヴスはなかった、と言っても過言ではないですね。今回はプラチナスポンサーとして協賛させていただくことで、Rubyへの感謝の気持ちを表現できたことを大変嬉しく思います。

また、スポンサーさせていただくことで、会社のブランディング向上や絶賛募集中のエンジニア採用活動に良い影響がでると良いな、と思っています。今回はプラチナスポンサーということでスポンサー特典の15秒のPR動画を頑張って制作いたしました。用意してくれた弊社のデザイン戦略室のメンバーに大感謝です。良い出来栄えになっているのでイベントに参加された方はぜひご覧ください。

スポンサー特典として、今回はスポンサーチケットを十分な枚数いただくことができました。こういったイベントは日頃Rubyを使って開発しているエンジニアにとって、新しい刺激を得られるまたとないチャンスですので、フル活用させていただく予定です。今回、正社員には業務としてイベントに参加してよく、特にレポート提出の義務も課さず、楽しんでらっしゃい、と送り出しています。残ったチケットは、業務委託として弊社の開発にご協力いただいている方に使っていただくことにしました。

コロナの影響で、このようなイベントの開催も難しい状況が続いています。RubyKaigi Takeout 2021が盛況に終わり、来年また新しい形で開催され、また今回のようにコミュニティをサポートする立場として関われることを願っております。

最後になりますが、弊社ではエンジニアを大絶賛募集しています。興味を持っていただいた方は、ぜひ弊社の求人をご覧いただけると幸いです。

それではRubyKaigi Takeout 2021でお会いいたしましょう!

デザイナーとエンジニアの共通言語を得る輪読会のお話

はじめに

こんにちは、Forkwell 開発チームの tbaba です。最近は暑くなってきたのでドラムを叩くと汗が吹き出てむぎ茶を飲む手が止まりません。

今日は今年の2月くらいからずっと取り組んでいる、「デザイナーとの輪読会」についてお話しようと思います。
弊社には「デザイン戦略室」というチームがありまして、社内のプロダクトやビジュアル、広告のデザインからブランドエクスペリエンスの向上など、様々な制作を横断的に受け持っています。もちろん Forkwell や Crowd Agent などのウェブアプリケーション開発にも関わっております。
そんな彼らが行っている輪読会に、エンジニアである自分が入って何をやっているのか、どんな効果があるのか、をご紹介します。

どうして輪読会をやろうと思ったのか

元々は、デザイナーやカスタマーサクセスチームのみなさんが始めました。
「プロダクトを作っていく上で、エンジニアと会話する際に単語の説明をされてから会話が始まる(「Pumaが・・・あっ、Railsアプリケーションを動かしてるWebアプリサーバーなんですけど・・・」みたいな)、という無駄が発生する」ようなケースも多く、本質的な会話に至るまでに時間がかかることがあったようです。
そこで、エンジニアとの共通言語を増やして、コミュニケーションを取りやすくしたい!という気持ちから、サーバーやWebアプリケーションなどの知識を得るための輪読会を開始した、とのことです。

どうして絡みに行こうと思ったのか

最初はすっごく軽い気持ちで入っていきました。
というのも、元々自分が2020年秋頃から、ゆるゆるとLinuxそのものの再学習を進めておりまして、得た知識を復習したいという気持ちがありました。その目的に対して、輪読会で発言をするというのはとても効率の良い復習方法だと考えたのです。

また、自分の中で今期のテーマとして、「そうやって学習した知識を周りに広めていく」というものがありました。
やっぱり知識は得たなら広めていったほうが自分にとっても周りにとっても良い事だらけです。自分以外に出来る人が増えればそれだけ、チームが成長しますし、周りにとっても出来ることが増えるのはメリットです。

そんなわけで知識を広めていくのに良い機会だと感じたので、「俺も入る〜」とカジュアルに手を上げてみたところ、何やら歓迎されたので、するっと入っていきました。

f:id:harakirisoul:20210707123642j:plain
するっと参加が決まったときのメンションがこちらです。

どんな感じで進行しているの?

基本は事前に対象となる箇所を読んで来て、気になったところについて議論をする、というよくある輪読会の形式です。
少し通常のものと違うのが、「 tbaba がオブザーバーとして参加している」という点です。
何をやっているかというと、

  • 読んできてよく分からなかった点をオブザーバーに聞く
  • オブザーバーはこれに対し、「自社ではこうなっている」という風に回答する

ということをやっています。

なぜこの形式を採用しているかというと、元々の目的が「開発者との共通言語を得て、コミュニケーションを取りやすくするため」だからです。

例えば単にサーバーと言っても、「Web サーバー」「アプリケーションサーバー」「メールサーバー」などなど、多岐にわたります。また、「IP アドレスとは」「IPv4 と IPv6 って何が違うの?」という疑問もあるでしょう。

このあたりを、「Forkwell ではこう言う構成になっていて」「Crowd Agent はこういう風になっていて」という説明をはさみつつ説明していっています。自社プロダクトがどうなっているのかを伝えることで、より具体的な理解につながるのです。

何が変わったのか

単なる輪読会に開発者のオブザーバーを入れることでどうなったのか?これが気になるところだと思います。
というわけでアンケートを取ってみました。
まずは「輪読会の理解度」についてです。

f:id:harakirisoul:20210707123017p:plain
輪読会の理解度はどのくらい増したか

参加者が少ないのと、社内のアンケートのため、公正とは言いづらいかも知れませんが、概ね高評価でした。以下のようなコメントも寄せられており、デザイナーが独自に輪読会を行うよりも効率良く学習を進められたのではないかと思います。

  • 具体例を交えて説明していただいているので、イメージしやすくなった。
  • Crowd Agent や Forkwell では実際どのようにサーバーが構築されているのか、実例を聞くことができたので、自分ごと化しやすかったです。
  • 実務につなげていただいたり、実際の開発エンジニアが理解・関わる範囲を教えていただけるので、理解度が上がりました!

一方で、「開発者とのやり取りがやりやすくなったか」という質問も投げかけてみました。結果はこちら。

f:id:harakirisoul:20210707123103p:plain
開発とのやり取りはやりやすくなったか

真ん中(よくわからない)から、右側(やりやすくなった)のあたりに留まっています。
これについては、まだサーバーのお話、つまりアプリケーション開発そのものよりも低レイヤーの話に終始しているためと思われます。今後アプリケーション開発についての輪読会が開催されれば、こちらも数値が変わってくるのではないかと思います。
個別のコメントとしては、好意的なものを頂いています。

  • 「エンジニアのみなさんの意見や質問内容を理解した上でやりとりができ、進めやすかった」
  • 「リファインメント(バックログを整えるミーティング)でのエンジニア同士の会話などに壁を感じにくくなった」

また、今後何を勉強したいかという話についてもアンケートを取ってみたところ、「ウェブアプリケーション」と「データベース」という2つが票を集めていました。やはり、ウェブアプリケーションのプロトタイプを作っていたり、データ集計・分析をしたりする際のことを考えると、この2つの優先度は高くなるのでしょう。

また、変わった点としてとても大きなものがありました。それは、「質問できる」という点です。
自分が加わるまではデザイナーやカスタマーサクセスと言った、普段エンジニアリングそのものには関わらないメンバーのみで輪読会をしていました。そのため、少し込み入った話が出てくると、誰も答えることができず、疑問解消しにくかったのです。
そこにエンジニアが入ってくることで、疑問を疑問のまま残さないで、輪読会の時間内にしっかりと解消することができるようになりました。これが、デザイナーがエンジニアリングを学ぶ輪読会を行う際に、エンジニアが同席する最大のメリットと言えると思います。

もちろん、エンジニアにとっても悪い話ではありません。人に説明するということは、自分がちゃんと理解していなくてはいけません。つまり、復習の機会になります。それに、デザイナーと一緒に学ぶということはそれだけコミュニケーションを多く取るということでもあります。そうやって一緒に学んだ時間は、きっとその後のコミュニケーションにプラスに働くことでしょう。

最後に少し別の話ですが、前半でも書いたように、今年の自分の中のテーマとして「学習した知識を周りに広めていく」というのがありました。これが少しでも広まっていくのがアンケート結果からも実感できたのが、かなり嬉しかったです。

まとめ

世の中のデザイナーの皆様の中には、エンジニアとコミュニケーションをして作る時に、「こいつ何言ってんだ」と思うときがある、という方もいらっしゃることでしょう。
しかし、それは今回の自分たちのように、一緒に学ぶ場を作ったり、歩み寄ったりすることで解消できることがとても多いと思います。
何か困ったことがあったらエンジニアに相談してほしいし、エンジニアも困りごとはデザイナーに相談するような信頼関係を持つことと、お互いがお互いの専門領域について多少なりとも知識を持つことで、円滑にお仕事を行っていけるような関係が持てると、かなり強いチームになれるのではないでしょうか。

正直そんなに深く考えないで始めた取り組みですが、今では「やってよかったし今後も続けたいなぁ」と考えております。

# そういえば、デザイナーがエンジニアに教える輪読会があっても良いかも知れませんね。

最後に

そんな grooves 社では現在、一緒に働いてくれるエンジニアを募集しています。

jobs.forkwell.com

jobs.forkwell.com

もし興味があれば、ぜひ一度ビデオ通話などでお話しをさせてください。

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の求人からエントリーいただけると幸いです。