株式会社ROXX ✕ ドラッカー風エクササイズ

はじめに

こんにちは株式会社ROXXのhirokinishizawaです。

いきなりですが現在SARDINE開発チームの体制はこの様になっています。

f:id:hiroki-nishizawa:20190730191203p:plain

もともと3月から開発チームは2チームあったのですが人数も少なかったというのもありスクラムマスターというロールはいませんでした。両チーム人数も増えてきて6月からスクラムマスターを入れるということになりました。

スクラムマスターになってから1ヶ月程たって、メンバー間やチーム間で価値観や期待することに対して疑問も上がってきたので「ドラッカー風エクササイズ」を行いました。

ドラッカー風エクササイズとは

ドラッカー風エクササイズはアジャイルサムライという本にある、チームにおける期待をすり合わせるための手法です。たった4つの質問を通じて、お互いの考えや価値観、期待のすり合わせを行います。

  • 自分は何が得意なのか?
  • 自分はどういうふうに仕事をするか?
  • 自分が大切に思う価値は何か?
  • チームメンバーは自分にどんな成果を期待していると思うか?

たった4つの質問と書きましたが回答する側は結構考える内容になっていると思います。

自分が得意なことは結構出てくるイメージですが、大切に思う価値やチームメンバーからどんな期待をされているかはすぐに出てこない人も多いかと思います。

株式会社ROXX ✕ ドラッカー風エクササイズ

スクラムチーム全体でのチームビルディングということもあり、今回は少しカスタマイズをして各チーム内と、ロール間という2パートを用意しました。

チーム内

以下の質問でチーム内での期待することを各々チームで認識をあわせました。

  1. 自分が大切に思う価値は何か
  2. 自分がどうやって貢献していくつもりか
  3. 他のメンバーに期待していることは何か

f:id:hiroki-nishizawa:20190801145522j:plain

各々発表する時間をとってメンバー間での期待すり合わせを行ってもらいました。「他のメンバーから期待されていたことを見て新しい発見があったか」や「メンバー間での大切にしていることの違い」など見てもらいます。

ロール間

以下の質問で各ロールに期待することを全体で認識をあわせました。

  1. 自分たちのロールが大切にする価値は何か
  2. 自分たちのロールが期待されていることは何か
  3. 他のロールに期待していることは何か

f:id:hiroki-nishizawa:20190801145553j:plain

ロール間で期待のすり合わせを行った理由はスクラムマスターの役割はなんなのかという話があがったためパートを用意しました。

スクラムチームの成熟度によってスクラムマスターの役割も変わっていくため、現段階でチームでどのような期待をされているのか。また「PO→スクラムマスター」「各開発チーム→スクラムマスター」だけではなく、「PO→各開発チーム」「各開発チーム→PO」も行うことで、チーム間で差分があるのかを改めて認識できました。

まとめ

今回はスクラムチーム全体でやりましたが、チーム毎にチームの成熟度は違うため、チームのフェーズによってカスタマイズを行っていくのが良いと思います。

新しいメンバーが入ってきた時などチームビルディングとしてドラッカー風エクササイズは有効なので、みなさんもぜひ試してみてください!

さいごに

チームが成長していくにあたり、これからもメンバーを増やしてもっと生産性の高いチームにしていきたいと思っています。

新規事業や既存事業の拡大も考えているため自分の力で事業を成長させたいエンジニアを絶賛募集中です!

興味のある方は下記からご応募いただくか、弊社CTO:kotamatまでご連絡ください!!

www.wantedly.com

www.wantedly.com

LaravelでIP制限機能の実装

はじめに

こんにちは、株式会社ROXXの開発責任者の小平(@ryotakodaira )です。 業務では、SARDINEという人材紹介会社向けの業務管理システムを開発・運用をしています。

規模の大きい人材紹介会社がSARDINEを利用するにあたって、システムの利用時に 自社のIPからのみアクセスを許可 したいという開発案件が発生したため、備忘録的に開発としてどのような対応を行ったのかを残そうと思います。

準備

今回の開発で達成したいこととしては、

「システムの利用時に 自社のIPからのみアクセスを許可 したい」となっており、

ユーザー毎に自社のIPアドレスを設定できるようにすることでした。

当然ですが、認証を先に済ませないとどのIPアドレスを許可するかの判断をシステム側で行うことができないため、認証済みのリクエストが来たときに必ずIP制限の評価が走るミドルウェアを実装することとしました。

早速、ミドルウェアを作っていきます。

Laravelのartisanコマンドでミドルウェアクラスのファイルを作ることができるので、そちらを利用します。

$ php artisan make:middleware CustomIpLimitation

ミドルウェアの実装

<?php

namespace App\Http\Middleware;

use App\Entities\User;
use Closure;
use Symfony\Component\HttpFoundation\IpUtils;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

/**
 * Class CustomIpLimitation
 * @package App\Http\Middleware
 */
class CustomIpLimitation
{
    /**
     * @var array
     */
    // ①
    const ACCEPTED_IPS_GROUP_BY_USER = [
        // user_id => ['127.0.0.1/0', '127.0.0.1/1']
        1 => [
            '127.1.1.1/32',
            '127.2.2.2/32',
        ],
    ];

    /**
     * @see https://ip-ranges.amazonaws.com/ip-ranges.json
     */
    // ②
    const CF_IPS = [
        // CloudFrontのIPレンジ
        '13.124.199.0/24',
    ];

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // ③
        if (!app()->runningUnitTests() && !app()->environment('production')) {
            return $next($request);
        }

        /** @var User $user */
        $user = $request->user();

        // ④
        $allowedIps = $this->allowedIps4AuthenticatedUser($user->id);

        // ⑤
        if (empty($allowedIps)) {
            return $next($request);
        }

        // ⑥
        $request::setTrustedProxies(
            [$request->server->get('REMOTE_ADDR')] + self::CF_IPS,
            $request::HEADER_X_FORWARDED_AWS_ELB
        );
        $clientIp = $request->ip();

        // ⑦
        if (!IpUtils::checkIp($clientIp, $allowedIps)) {
            throw new AccessDeniedHttpException('IPNotAllowed');
        }

        // ⑧
        return $next($request);
    }

    /**
     * @param int $userId
     * @return array
     */
    protected function allowedIps4AuthenticatedUser(int $userId): array
    {
        return self::ACCEPTED_IPS_GROUP_BY_USER[$userId] ?? [];
    }
}

実装内容について順を追って説明していきます。

ACCEPTED_IPS_GROUP_BY_USER という定数に、 IP制限を設定するユーザーIDをkey、許可したいIPアドレスの配列をvalue 、とした配列を定義します。

本来はこれらの情報は何らかのデータベースで永続化し、都度データベースからデータを引いてくるべきですが、本投稿では定数に定義する形で進めます。

CF_IPS という定数に、CloudFrontのIPレンジを設定しています。

弊社のサービスはCloudFrontを使用しているため後々の処理でCFのIPレンジが必要となります。

こちらも本来は定数として定義するのではなく、都度、以下のURLを参照するなどをして最新のIPレンジを取得するようにした方が良いでしょう。

https://ip-ranges.amazonaws.com/ip-ranges.json

(体感ですが、CFのIPレンジは1,2週間に1度くらいのペースでアップデートがかかります。)

こちらはあってもなくてもどちらでも良いですが、開発中にIP制限に引っかかってしまい非常に面倒だったため、開発中はこの機能を無視するようにしています。

phpunit実行時, 本番環境以外では機能を無視するようにしています。

で定義したIPリスト( ACCEPTED_IPS_GROUP_BY_USER )をクライアントからリクエストを送信したユーザーIDで検索して、そのユーザーIDに対してIP制限が設定されていた場合は、許可するIPアドレスの配列を返却しています。

で取得した許可するIPアドレスの配列が空の場合は、IP制限を設定していないものとみなしそのままミドルウェアの処理を抜けます。

クライアントのIPアドレスを取得する前に setTrustedProxies を行い、サービス提供者が直接管理しているリバースプロキシのリストをセットします。

セットすべきリバースプロキシの内容はサービスのインフラ構成により異なってきますが、弊社のサービスの場合は CF -> ALB -> EC2 となっているため、

self::CF_IPS で最初に定義したCFのIPレンジを取り、 $request->server->get('REMOTE_ADDR') で直前(ALB)のIPレンジを取ってそれらをセットしています。 ここは完全にインフラ構成に依存していますが、そのことを最初は考慮できていなかったため割と躓いたポイントです。

その後、 $request->ip() で正確なクライアントIPアドレスを取得することができます。

クライアントのIPアドレスが許可されたIPアドレスの範囲内にあるかを検証しています。

SymfonySymfony\Component\HttpFoundation\IpUtils::checkIp メソッドを使えば一発で評価することができます。

許可されたIPアドレスの範囲内になかった場合はその時点でエラーをクライアントに対して返却しています。

クライアントのIPアドレスが許可されたIPアドレスの範囲内であれば、正常とみなしミドルウェアを抜けて終了となります。

後は app/Http/Kernel.php などで今回作成したミドルウェアを通るように設定してあげれば完了です。

最後に

事業・サービスが成長していくにあたって、これからもメンバーを増やしていきたいと思っています。

新規事業や既存事業の拡大も考えているため自分の力で事業を成長させたいエンジニアを絶賛募集中です!

興味のある方は下記からご応募いただくか、@ryotakodairaにご連絡ください!!

www.wantedly.com

www.wantedly.com

Nuxt.js の context をおさらいする

こんにちは、 ROXX の匠平@show60です。

Nuxt.js の context は色々な機能を内包してくれているためそれとなく使えている感覚でしたが、そもそも中身どうなってんの?と気になったので調べてみることにしました。

そもそも context とは

JavaScript では this という呼び名の context ですが、直訳すると 文脈、脈絡、前後関係 という意味となります。

日常では曖昧な使い方をされてしまうため一層理解に戸惑いますが、 MdN では outside of any function (どの関数の外側にもある) と説明されています。

Global context

In the global execution context (outside of any function), this refers to the global object whether in strict mode or not.

this - JavaScript | MDN

global object とありますが、つまるところグローバルで定義したオブジェクトであり、文脈という言葉を使うとすれば、「すでに定義したという文脈があるんだよー。知っておいてね。」という解釈になるでしょうか。

Nuxt.js の context

Nuxt.js の公式ドキュメントには context で使用可能なキーのリストが載っています。

API: コンテキスト - Nuxt.js

このリストを見ていくと、例えば routefrom といったものは Vue Router Route のインスタンスの型をとっています。 Nuxt.js のアプリ内の適当な箇所で context を呼び出し、 console.log(route) を行ってみると以下のような内容が表示されます。

{
  fullPath: "xxx",
  hash: "",
  params: {},
  path: "xxx",
  query: {}
  ...
}

これは Vue Router のルートオブジェクトプロパティがそのまま含まれているということが分かります。

API Reference | Vue Router

つまり context にはVue Router が定義してあり、 route などの名前で呼び出すことによってどこでも使えますよ、というのが context です。

上記のドキュメント内のキーのリストに app という項目が含まれているのですが、 NuxtAppOptions の型を持っていると説明してあります。

これはどのように使うのでしょうか。

Nuxt.js の context の app

物は試しで、 context の app を呼び出したところで console.log(app) してみましょう。

{
  $axios: ƒ wrap(),
  beforeCreate: ƒ beforeCreate()
  components: {NuxtLoading: {}}
  computed: {isOffline: ƒ}
  context: {isStatic: false, isDev: true, isHMR: true, app: {}, store: Store, …}
  ...
  store: Store {_committing: false, _actions: {}, _actionSubscribers: 
Array(0), _mutations: {}, _wrappedGetters: {}, …}
  watch: {nuxt.err: "errorChanged"}
}

コンポーネント内で使用するオブジェクトなども並んでいます。

この中の context を開いて見てみると、先程の routefrom も存在しており内容も同一となっています。

この context 内の app について、先程のリスト内では すべてのプラグインを含むルートの Vue インスタンス と説明されています。つまり、 app には Vue RouterVue Store など context に含まれるオブジェクトがすべて参照できるというわけです。

context の定義

念のために Nuxt.js の Github 上でコードも確認してみましょう。

GitHub - nuxt/nuxt.js: The Vue.js Framework

Nuxt.js の package/vue-app/template/index.js 、 58 行目あたりに async function createApp とあります。この処理内で const app = { してある箇所があり、どうやらここで app を定義しているようですね。

async function createApp(ssrContext) {
  const router = await createRouter(ssrContext)
  ...
  const app = {
    router,
    <% if (store) { %>store,<%  } %>
    nuxt: {
      defaultTransition,
      transitions: [ defaultTransition ],
      setTransitions(transitions) {...},
      err: null,
      dateErr: null,
      error(err) {...}
    },
    ...App
  }
  ...
  await setContext(app, {
    route,
    next,
    ...
  })

router はここで注入されているようです。setContext で context を定義しているようですのでこちらも見てみましょう。

nuxt.js/utils.js at dev · nuxt/nuxt.js · GitHub

export async function setContext(app, context) {
  // If context not defined, create it
  if (!app.context) {
    app.context = {
      isStatic: process.static,
      isDev: <%= isDev %>,
      isHMR: false,
      app,
      <%= (store ? 'store: app.store,' : '') %>
      payload: context.payload,
      error: context.error,
      base: '<%= router.base %>',
      env: <%= JSON.stringify(env) %><%= isTest ? '// eslint-disable-line' : '' %>
    }
    ...
  }
  ...
  app.context.params = app.context.route.params || {}
  app.context.query = app.context.route.query || {}
}

index.js が起動し、そこで context の中身を諸々注入していることが分かりました。この app がどこでも参照できる状態にあることで各コンポーネントから context 内のオブジェクトを扱うことができるわけですね。

実務では storeerror あたりを使うことが多いでしょうか。ページから store に保管してあるデータを参照したり、 API へのリクエストが失敗したときのエラーハンドリングを行うため自ずと頻度が上がります。

プラグインの注入

新たに context にプラグインを注入したい場合は、上記の Nuxt.js の utils をわざわざ編集するのではなく plugins ディレクトリと nuxt.config.js に記述するだけです。

プラグイン - Nuxt.js

プラグインではないですが、 app にテキストを入れて表示してみたいと思います。

plugins/sample.js

export default ({ app }) => {
  app.sample = 'sample'
}

nuxt.config.js

plugins: [
  '~/plugins/sample'
]

npm installyarn 等をして config.js を再読み込みすると、先程の console.log(app) の結果に sample が追加され、テキストが表示されました。

f:id:show-hei:20190729132411p:plain
plugins/sample の注入

とても簡単に扱えるようにしてくれてますね。

まとめ

外部プラグインは context だけでなく Vue インスタンスに注入しても使用することができます。

どちらもコンポーネント内で呼び出すことができるのですが、どちらの使用を選択するべきかについて、また改めて調べてみたいと思います。

最後に、私たち ROXX では一緒に開発を進めていただける仲間を募集しています。 ご興味お持ちいただいた方はぜひご応募ください!

www.wantedly.com

www.wantedly.com

Frontend de KANPAI! で登壇してきました

こんにちは、株式会社ROXXの石岡 将明( @masaakikunsan )です。

7月19日の Frontend de KANPAI! #7 - Going on 令和 で登壇させていただきました。

今回は、登壇した話について、ブログを書いていこうかなと思います。

登壇でのテーマ

今回は Going on 令和 というテーマがありました。 内容としては令和でも Frontend やっていきみたいなのを考えていましたが、Frontend を普段からやっている人や、ある程度スキルのある人達は勝手に成長していくので今回は令和から Frontend やっていきたい人に向けての発表にしようと思いました。

なのでゴールとしては、下記としました。

  • これからフロントエンドを始めたい、伸ばしていきたい人の背中を押す
  • フロントエンドエンジニアとしてのキャリアを悩んでる人の手助けができる

実際のスライド

下記が実際のスライドです。

slides.com

タイトルは 令和から始める Frontend としました。

アジェンダは、下記です。

  • これまでのフロントエンド
  • ここ数年のフロントエンド
  • これからのフロントエンド

スライド内では、僕のキャリア的な話を書いております。 ここでは、僕が3年ぐらいでこんな感じのことをやっているって話をしました。

詳しくは、スライドを見ていただきたいのですが、全体的にこれから始める人はこうしたほうがいいんじゃない?という話 + 僕が3年で普通に働けているのでみんな普通に1年本気でやればやっていきできるよっていった感じの発表になりました。

f:id:masaakikunsan:20190726135017j:plain

フロカンについて

フロカンでは、LT 枠はなく運営が登壇依頼をしその人達 + DeNA の社員が登壇する形になっています。 それもあり、毎回発表のクオリティはかなり高いものになっています。

また、スタッフもやりたくてやってるんだろうなぁといった感じが強く、ものすごく雰囲気が良いです。(あとコミュ力が高いと感じた)

今後も参加していこうと思っていますし、弊社イベントでも取り入れられることはかなりあるかなぁと。

また、登壇させてもらえるように日々頑張っていきをします。

さいごに

現在、株式会社ROXX では、エンジニア、デザイナーの募集をしております。

興味のある方は、是非下記からご応募お願い致します!

www.wantedly.com

SARDINE開発チームを支えるツールたち

こんにちは。2019年7月1日からジョインしました です。 入社当日に 株式会社ROXXへ社名変更 するというリリース作業に立ち会うレアイベントを経験できてラッキーでした。

この記事では SARDINE をどのように開発しているのか、SARDINEの開発チームを支えるWEBサービスやツールを紹介します。

SARDINE

開発体制

開発体制ではスクラム手法を取り入れています。月曜日に始まり金曜日まで、毎週1週間のスプリントです。 金曜日はスプリントレビューと振り返りや次スプリントのプランニング、ときには意識合わせのワークショップなどを行い1日が終わるので開発する時間は月曜日から木曜日までの4日間です。 スプリント期間が短いこと、しっかりプランニングを行うことで1週間の予測が立てやすいので、メリハリをつけた活動ができています。 トレードオフスライダーは納期と品質は毎スプリント一定を保つ、スコープで実装を調整するよう意識しています。

スクラムマスターの hirokinisizawaスクラムマスターの話 、またCTOの kotamat技術組織の話 として記事を公開していますのでそちらもご覧ください。

Jira

スプリントの管理には Jira をフル活用しています。たとえば朝会ではスクラムボードで今日やることの確認をします。スプリント中に発生した課題は随時バックログへ追加して必要に応じてスプリント中に対応したり次スプリントに回したりの判断をしやすくします。

秘匿性が高い情報も含まれているため黒塗りが多くなってしまいました...イメージだけでもご確認いただければ幸いです。

Jiraのスクラムボード ほぼ真っ黒でごめんなさい

チームのコミュニケーション・情報の共有や蓄積

リモートで作業しているメンバーも多数いるのでコミュニケーションは密にとるようにしています。

Google Meet, Discord

朝会では Google Meet を利用して会話しています。 Google Meetで画面共有をおこなってJiraのスクラムボードを全員で参照したり各自困っているコミットなどを共有して全員で認識を合わせられるように心がけています。 また、チームメンバーの顔や状況をわかりやすくするために外部カメラを繋いだり声が聞き取りやすいように外部スピーカーを使っています。

モニター上部に設置したカメラ

かんたんに声をかけたり話しかけたりしたい場合には Discord も使っていますね。

Slack

テキストコミュニケーションには Slack を利用しています。 Slackは開発メンバーに限らずROXXの全メンバーが活用しています。 出社退社時の打刻はスラッシュコマンドで行いますし、全社周知事項の案内、お客様からのお問い合わせ速報など様々な内容が通知されます。

ただし開発用のチャンネルだけでもが多岐にわたるので慣れないと追うのが大変でした。 このへんは課題があるなと感じています。

esa

esa もROXXの全メンバーが活用しています。 開発環境の構築手順、ステージング環境のアクセス方法などなどとりあえずesaを探せば情報に辿りつけるようになっています。

development and deploy

画面デザインの設計には Figma を、ソースコードの管理には GitHub を、 CIに Travis CI を利用しています。 サービスのインフラに AWS を利用しておりAPIサーバーはEC2、データベースはRDS、静的サイトの配信にはS3 + CloudFrontを利用しています。 静的サイトでもランディングページなどの一部のサイトには Netlify を利用しています。

イメージ

ここまで出てきたツールを画像にまとめるとこのような図になります。

SARDINEの開発ワークフローまとめ

ほかにも

ほかにもスプリントレビューやミーティングで利用する50インチ程度の大きなディスプレイが開発チームエリア近くに配置されています。 またディスプレイも申請せずとも1人1枚以上配給されます。私のチームでは27インチ程度のモニターを2枚利用しています。

...以上のように、SARDINEサービスの運営開発をより円滑に行うために様々なツールを用いています。

SARDINEの開発体制がみなさんにイメージが伝われば幸いです。

最後に

株式会社ROXXでは一緒にSARDINEの開発に携わってくれるメンバーを、また新規サービスの back check にもメンバーを随時募集しています。 この記事を読んでROXXに興味を持ってくれた方はぜひご応募ください。  

www.wantedly.com

LaraVue勉強会 #10 開催しました!

こんにちは、株式会社ROXXの佐藤( @r_sato1201 )です。

先日、Laravue勉強会#10を開催いたしました。
はやいもので、今回でなんと10回目。 今回もたくさんの方に参加して頂き、非常に有意義な勉強会となりました。
その模様を報告させて頂きたいと思います。

laravue.connpass.com

会場

今回は、heyさんのオフィスをお借りしました。開放感のあるとてもきれいなオフィスでした。

f:id:ryonnsui1201:20190721002315j:plain

発表内容

スポンサー枠も含め、6名の方に発表していただきました。
すべて紹介するのは冗長なので、私が気になった発表を紹介させていただきます!

Storybookを用いたVue.js共通コンポーネント開発との戦い (@howdyさん)

f:id:ryonnsui1201:20190721003110j:plain

トップバッターはスポンサー枠の@howdyさん。
storybookを使った共通コンポーネント集を使う際の苦悩、戦いについて話していただきました。
予期せぬUI崩れに気づくために、REG-SUITという画像回帰テストを行ってくれるツールの話など、とても興味深かったです。

speakerdeck.com

Vuex-ORMの紹介 (@Yasshieeeeさん)

f:id:ryonnsui1201:20190722113816j:plain

VuexをDBとして使い、ORMライクなアクセスをすることができるVuex-ORMについてご紹介いただきました。
ノーマライズしてくれるので、複雑にネストされたデータ構造を持っているとき便利そうです。

www.slideshare.net

Laravel + AWSでCI/CDしてみた話 (@mjimaさん)

f:id:ryonnsui1201:20190721020257j:plain

AWSのCodePipelineでLaravelプロジェクトをCI/CDする話をしてくださいました。
AWSCodeBuild内のビルドの流れなど、詳しく知ることができました。

slides.com

Laravelのイベントディスカバリー (@niisan-tokyoさん)

f:id:ryonnsui1201:20190721020318j:plain

弊社からは、@niisan-tokyoさんにLaravel5.8.9から実装されたイベントディスカバリについて発表していただきました。
5.8.9以前だと、イベント・リスナーが増えるたびにEventServiceProviderが膨らんでいくが、イベントディスカバリを使うとリスナー側のhandlerに指定されているイベントの型宣言を読んで、その型のイベントのリスナーに自動で登録してくれるというお話でした。
非常に便利ですし、興味深い話でした。

qiita.com

PHPUnit + openapi-validator で「スキーマが正、実装が追従」にする (@kon_shouさん)

f:id:ryonnsui1201:20190721020345j:plain

スキーマが正、実装が追従となるようPHPUnitで、APIスキーマと異なるレスポンスを返したら、落ちるテストを書く話をしてくださいました。
OpenApiでAPIに関するインターフェース定義のyamlを吐き出し、openapi-validatorでそのyamlPHPUnitに取りこむ、という方法で実現していました。

qiita.com

懇親会

f:id:ryonnsui1201:20190721020218j:plain

発表後は、heyさんが提供してくれた美味しいケータリングを囲み懇親会をしました!
多くの方に残っていただき、会場の使用時間ギリギリまで親交を深めていただきました。

まとめ

今回は、Laravel,Vueの発表が半々でまさに「LaraVue勉強会」を体現する勉強会になったと思います。

次回の開催は未定です。詳細が決まり次第connpass上で告知いたします!

最後に

ROXX社では一緒に頑張ってくれる方を募集しております。 デザイナー、エンジニアの皆さん興味のある方はご応募お願いします!

www.wantedly.com

www.wantedly.com

www.wantedly.com  

スクラムマスターとして失敗したと思った2つのこと

こんばんは今年の3月から3ヶ月だけですがPOをやり今月からスクラムマスターをやることになりましたhirokinishizawaです。

スクラムマスターになってから1ヶ月がたつので本記事で振り返りつつ、スクラムマスターになってから失敗したなと思ったことを話していければと思います。

はじめに

SARDINEの開発チームは2軸でやっています。その中で1チームだけ10月頃からスクラムを導入し始めました。

当時自分はスクラムを導入した方のチームに所属しており、3月からもう一つのチームがスクラムを導入するタイミングで3ヶ月だけですがPOをやりました。そして今月6月から現在そのチームでスクラムマスターをやっています。

スクラムチームのそれぞれの役割

  • PO(プロダクトオーナー): 開発チームから生み出されるプロダクトの価値を最大化すること
  • 開発チーム: 開発チームの開発効率を最適化すること
  • スクラムマスター: スクラムの促進と支援をし目的を実現する確率を最大化すること

スクラムマスターの責任

スクラムマスターはスプリントを円滑に進めることに責任を持ちます。

その中には

  • 開発チームが行ったスプリント計画の障害になるものを取り除く
  • 次のスプリントをよくするために気づきやコミュニケーションを促す
  • プロダクトオーナーのプロダクトバックログの作成や並び替えを支援する
  • プロダクトオーナーと開発チームの会話を促す

などまだまだありますが基本的になにかを決定をするのではなくあくまでサポートする動きをしてスプリントを円滑に進めるように動きます。

スクラムマスターになってからの失敗談

POをやっていたときはなるべく要件から仕様までやってプランニング(見積もり)readyの状態をつくるようにしていました。なるべくというのはどうしてもバックログの調査や整理などが間に合っていなく、必要なときはタスクを作っていて開発チームがプランニングをするために障害がなくなることに注力してしまっていました。

その状態のままスクラムマスターになって失敗したなと思ったことを書いていこうかと思います。

POから要件を受け取りプランニングreadyの状態にする

POをやっていた時はゆくゆく仕様なども開発チームに降ろすようにしなければいけないと思っていました。ですがスクラムも始まったばかりだったので基本的にはプランニングの時に見積もりが出来る状態を意識してやっていました。そんな状態のままスクラムマスターになり、POから降ってきた要件を見積もりが出来る状態までタスク分解をやったことにより

  • プランニングがただポイントをつけるだけの作業になってしまっていた
  • スクラムマスターで閉じてしまっているため質問がないと共有出来ていないことがあり共通認識があわなかった

のような状態になってしまった。

開発チームの中継役になってしまう

実際にスクラムマスターとしてサポートするというのがどういうことなのか深く理解できていませんでした。最初はサポートとしてタスクの管理やアサイン、スプリント内であった開発チームの不安要素などを吸い上げPOに確認を自分が行っていました。ですがそれを続けたらPOと開発チームの中継になりコミュニケーションをスクラムマスターを通すというルールになっていきそうだったためやめました。基本的に開発チームがPOやステークホルダーとコミュニケーションを取っては行けないというルールはありません。

現在はスプリント内で上がった不安要素や技術課題などの優先順位をつけるためにPOとのコミュニケーションを促すようにしています。

まとめ

スクラムマスターの最終目的としてスクラムチーム にスクラムマスターってもういらないよね? というチームにしなければいけないと思っています。なのでスクラムマスターが見積もりが出来る状態までやるのはやりすぎに入ってしまいます。

見積もりするために何を準備すればいいのではないか、またどのように解決すればいいのではないか。というのように決定・命令はせずスクラムチームに気づきを促すサポートをしていくのがスクラムマスターなのではないかと思います。

まだまだ未熟なので間違っているところなどご指摘いただけると幸いです!8/7~8/9の間CSM行ってまいります!

最後に

で8/7~8/9でCSMを受けに行ってくるので終わったらいろんな人が書いていますが自分もブログを書きたいと思います!

現在、株式会社SCOUTERでは、エンジニア、デザイナーの募集をしております。

興味のある方は、是非下記からご応募お願い致します!

www.wantedly.com

www.wantedly.com

www.wantedly.com