理想とする技術組織

こんにちは、kotamatです。 開発メンバーも15人を超えてきて、開発ラインも複数走っている状況となってきました。 それぞれの開発ラインにおいて、上長となる開発責任者やマネージャーが要件やスケジュールを決めていくため、それぞれの開発ラインが独立駆動で走っていってしまうということが発生してきました。 そういった中で、SCOUTERという会社に所属している開発メンバーとして立ち戻る物が必要となってきました。

SCOUTERでは、会社全体のミッション・バリューがありますが、開発者としてのまとまりを作るためには、抽象度を落としてより具体的にする必要があるため、開発組織として目指す像を定義しました。

今回は各定義の紹介と、内在する意図を紹介します。

f:id:kotamat:20190105195228p:plain
理想の開発組織

開発組織として目指す像

パートナー意識を持った相互依存型自律組織

シンプルに言うと「頼り頼られる組織」「背中を任せられる仲間」

エンジニアやデザイナー、PO、PMと、開発に関わる人は一人ではプロダクトを作ることができません。 それぞれ専門性を持った人が集まり、それぞれの特性を活かしながら開発を行うのがプロダクト開発です。 誰が何が得意なのか、苦手なのかを相互に認識した上で、自主的に穴埋めできるような高度なやり取りがプロダクト開発には求められており、そういう体制を構築できればスケールできる強い技術組織になると思っています。 また、開発に用いられる専門性は日進月歩でもあるため現状に満足せず、得意な領域に関してもより高度なレベルを常に目指す組織を目指していきます。

開発組織のバリュー

バリューに関しては、SCOUTERのバリューに照らし合わせています。

なぜ会社のバリューに相対させるものを作成したのかというと、

  • 開発組織としてのバリューを当該対象者の評価に組み込まないと運用されない未来が待っている
  • 一人の非評価者に一人の評価者という構造で評価を行っている
  • 既存の評価では、バリューの達成度合いを評価している

という背景があり、現行の評価にスムーズに組み込むためには既存の評価に対応させる必要があったためです。

副次的な効果として、相対させることによって、営業やCSのメンバーにとっても、開発組織が行っている行動がどのように会社の規範に紐付いているのかというところが理解可能な形になるため、全社的に同じ方向に向かっているということが感じ取れるようになります。

バリューの設定方法は以上です。 これから具体的にそれぞれのバリューを紹介させてもらいます。

1. 個々のプレゼンスが組織のプレゼンスとなる

対応するバリュー

f:id:kotamat:20190105195306p:plain
ROCK

正解は探すものではなく、創り出すもの 立場や結果を恐れず、自らの正しさを証明するまで闘い続けよう

コアとなる考え

  • 自分の得意を社内外問わず発信し続けることで個のプレゼンスを上げていく
  • 苦手なところは自責意識を持ちながらも他の人に認識してもらい助けてもらう
  • 得意なところは互いに高め合う

解説

前述の通り、開発に関わるメンバーの専門性の相互作用によってプロダクトは作られていきます。 また、同じ職種でも人によって得意な領域や不得意な領域は別れており、プロダクトのフェーズや施策開発のフェーズによって求められるレベル感も異なっていきます。

そういった中でそれぞれのメンバーが自分が得意な領域を他者に認識させ、発揮することによってその人の存在意義を発揮でき、その領域を任せられるようになります。

また、現在の開発のエコシステムに置いて、社外への発信は非常に重要視されてきています。 各個人の得意を向上する過程を社外に発信することによって、その過程そのものが本人のブランディング戦略の一つの要素となり、唯一無二となる個々のプレゼンスが形成されます。

そうしていくと、様々なシチュエーションにSCOUTERのメンバーが露出するようになり、会社としてのプレゼンスが上がっていくと考えています。

得意な領域が個々にあるということは、不得意な領域もあるということになります。 不得意な領域も認識し合うことによって、その領域は誰か他の人のヘルプを得ることもでき、背中を預けられる関係となると考えています。

2. 自分史上最高のプルリクを出す

対応するバリュー

f:id:kotamat:20190105195337p:plain
JAZZ

絶えず時間が流れ、状況は変わり続けている 型に嵌らない、その瞬間の最高パフォーマンスを追い求めよう

コアとなる考え

  • プルリクというのは、自分の成果物を他人に評価、受け入れてもらうためのものとする。
  • プロダクトやその他環境に応じて求められる評価は変わってくるが、その場における自己最高のものを作ることによってパフォーマンスを最大化していく

解説

キーワードは「比較対象が自分」というところではありながら「その環境におけるベストをアウトプットする」という点です。

スクラム開発ではよくもちいられている「トレードオフスライダー」や「Doneの定義」にもありますが、事業のフェーズやステークホルダーの関係性など様々な要因によって、求められるアウトプットにおける重要視されるポイントが変わってきます

自分が置かれている環境下でベストはなにかを認識し、過去の自分の経験も融合して一番いいものをアウトプットとするということを行っていけば、不確実性の高い領域においても、次第に良いものになっていく環境となり、強いプロダクトが作られていくと考えています。

3. 好奇心を持って体系化する

対応するバリュー

f:id:kotamat:20190105195401p:plain
PROGRESSIVE

誰もやっていないことに、誰も気付いていない価値がある 誰も実現したことのないことへの挑戦を喜び讃えよう

コアとなる考え

  • 日進月歩のWeb業界において、常に新しい技術や手法を取り入れていくことが求められている。
  • 新しいことを取り入れるだけではなく、それを体系化し再現性のある形に昇華させるまでをチャレンジとし、唯一無二の価値を創造する。

解説

日進月歩のWeb開発業界において、専門性の向上は常に行う必要があります。 そういった中で、常に最新の情報や技術に対してアンテナを張り続ける事によって、今どういうのがモダンなのかというのを判断できるようにする必要があります。

ここで注意しなければならないのは、新しいものを取り入れるというのはとてもいいのですが、よくあるのがとりいれたままにすることです。 新規プロダクト、新規施策においては、新しい概念を入れるのはたやすいですが、それだけではそれほど価値はありません。それを体系化しノウハウ化して他のプロダクトや社外の人もつかえるようにしていくことによって他者にとって価値のあるチャレンジとなります。

また、体系化を行うプロセスは唯一無二となるため、それを社外に発信し、個のプレゼンスとしていくことで、チャレンジをすることの対価を何倍も得られるようになります。

まとめ

SCOUTERの開発組織の目指す像とバリューについて紹介させていただきました。

バリューを設定する際には、バリューに沿う行動を行うことが

  • 当該メンバーのスキルアップに繋がり
  • 強い組織を作る要素となり
  • 会社の価値観に沿う

ようにすることで、組織と個人がWinWinの関係になるようなものとなるかと思います。

今回設定したものはまだベータ版であり、今後運用していく中でブラッシュアップされていくかと思いますが、明文化することでクリアになったので、10-20名規模になってきたら導入を検討されるといいのかなと思います。

最後に

SCOUTERでは、Laravue勉強会やNuxtMeetup、本技術ブログなど社外に発信する場があり、上記バリューを発揮する環境は整っているかと思います。

こういったバリューに共感する方、開発者として圧倒的に成長していきたい方は、一度お話させていただければと思います。 下記リンクから応募していただいてもいいですし、kotamatにDMを送っていただいても構いません。

www.wantedly.com

www.wantedly.com

www.wantedly.com

新規事業を最速で立ち上げる開発のノウハウ

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

現在、弊社では back check という新規事業の立ち上げを行っています。

backcheck.jp

note.mu

この記事では、その新規事業を最速で立ち上げるために僕が行ったフロントエンド開発のノウハウを書いていきたいと思います。 あと、PMとしてどうしたかみたいなことも少し書けたらなと。

新規プロダクトで求められること

具体的なノウハウを話す前に、新規プロダクトで求められることを整理します。

バグが少ないこと

これは、新規プロダクトに限った話しではありませんが、新規プロダクトはまだコアファンもおらず、致命的なバグや小さなバグの積み重ねで顧客が離れていきます。

そして、スピードは保ったまま進めたいのでバグが少ない方が良いでしょう。

少人数で仮設検証を回すこと

まだ儲かるかどうかもわからないので、経営者からしたら新規プロダクトは投資になります。 ですので、ここではなるべく人件費をかけずに少人数で仮説検証をしていきこのプロダクトはいけると判断できるラインにすばやくもっていく必要があります。

少人数で進めるのは人件費の面だけではなく、意思決定フローが楽になるというメリットもあります。

最速でのコア機能の開発

これは、仮設検証にも含まれますが、コア機能を早く作ってユーザーに触ってもらう必要があります。 当たり前ではありますが、コア機能ができあがらないといつまで立ってもリリースはできません。 なにかをリリースするということを当たり前に考えているエンジニアは多いですが、実はリリースは当たり前のことではありません。出戻りなどでいつまで立ってもリリースができなかったり、コア機能が定まらずあれもこれも必要と開発に時間がかかったりなど様々な理由でリリースができなかったということがあります。 なので、新規プロダクトにアサインされたPMは正しくコア機能を定めスケジュールを組む必要があります。

新規プロダクトあるある

次に新規プロダクトあるあるを話します。 これらは最速で進める上で割とある大きな壁にです。これらを認識して進めているかどうかではスピードもメンタル的にも全然違います。

度重なるデザインの変更

これは、経営者次第ではありますが、デザインの変更は割とよくある話しです。 これを仕方ないこととして受け入れるか、いやいやその差し込みはおかしいとデザイン変更を後回しにするかどうかはPM次第ですが、僕は基本的に意味のあるデザインの変更は受け入れるようにしています。(さすがにイケてないとかそういうよくわからないやつは対応しません)

仕様変更の可能性大

仕様変更は開発を進めているとどうしても起こる可能性があります。 画面を触ったらこうした方がいいなど、事前に防げそうな問題から経営上の都合など理由は様々ですが割とあるあるです。

ここまでを踏まえ、爆速で進めないといけないが手が止まる要因があるのはわかっていただけたかなと思います。 新規プロダクトにおいて愚直に作っていたら時間がいくら合っても正直足りません。

では、どうすれば良いのか。 作り直す前提で捨てやすく運用のしやすいコードで開発をする必要があります。

作り直す前提で開発を進めるためのコツ

ディレクトリ構成をしっかりと考える

ディレクトリ構成は開発のキモになってくるのでしっかりと設計しましょう。 ここで事故るとどんどん開発がしづらくコードを読むのも大変になっていきます。

back check では Nuxt.js を使っているので大枠のディレクト構成は Nuxt.js にまかせて、細かいところだけルール化しました。

カラーは変数で定義する

カラーは一箇所で管理したら楽なのと、無駄なカラーが増えることを防げます。 デザイナーには始めにカラースキームを定義してもらい、それを scss ではじめに定義します。

back check では、src/assets/config 配下に colorの変数用のファイルを作成し、nuxt-sass-resources-loader を利用しどこからでも定義した変数を使えるようにしています。

Component はなるべく最小単位で作成する

Component を最小単位で作成すると言うと、すぐ Atomic Design でやるぞってなりがちですが、Atomic Design は気をつけてほしい点がいくつかあります。

  1. デザイナーがちゃんと Atomic Design を意識してデザインをしている
  2. Component 設計のレベル感がチームであまり変わらない。

これらの前提がない場合は Atomic Design の導入はやめたほうが良いでしょう。 あと、Atomic Design のルールに沿ってしまうと作り直しがめんどくさくなる背景もあります。 では、どうやって Component の粒度を揃えるのか?幸い、back check チームではあまり Component 設計のレベル感が変わらなかったので気になるところはPRで指摘するぐらいで良かったので個人に任せています。

実装を進め共通処理がでてきたら Mixins 化する

Mixins 化も安易にやっていくと気づいたらカオスになっていたというのがあるので、なるべく Mixins 化をしないようにはしていますが、確実にこの処理は共通で今後も使っていくのが見えたら Mixins 化しています。 back check では form 周りが結構同じような処理だったので抽象化してから Mixins 化しています。

同じ Style はまとめて外に出す

Vue.js / Nuxt.js では Scoped CSS によって CSS を気軽に閉じ込められるので結構 Style がカオスになっている現場が多いです。 同じ Style がでてきたら src/assets/ 配下にscssファイルとして追い出し、必要なところで import するようにし page/component で書く Style をなるべくそこに必要なものだけにするほうが良いでしょう。

再利用性を考えるのは最低限

Component 指向での開発が当たり前になってから、再利用性の高い Component 設計を求められがちです。 もちろん大事なのはそうなのですが、新規プロダクトにおいてここに時間をかけるのはデメリットのほうがでかいです。 理由は単純にどうせ使い回さないからです。他にもあるのですが、とりあえず再利用性を考えるのは最低限にしときましょう。

これらを実行すると割と作り直しがしやすいプロジェクトができます。 back check チームでは、3度のデザインリニューアルと3種類のユーザー画面を二ヶ月でほぼ作りきりました。

最後に、PM として取り組んだことを書いていきます。

チームが開発しやすい環境作り

back check チームでは、週1でMTGを開きそこで歪があがったらその歪を解決するためのルール(仕組み)を作っています。 今後 Join されるメンバーのためのドキュメント作成や、命名のルールなど様々な仕組みを作りました。 なるべくメンバーには自分の思ったことを発散してもらうようにしており、それが必要だと判断したら解決し、なるべくストレスフリーでできるように進めています。

爆速で開発するために作り直しやすいコードで開発するのも大事ですが、そのためにはメンバーがやりやすい環境を作ってあげることが大事なので back check チームでは DX を上げるためにできる限りのことはしてあげようと思っています。

まとめ

  • 新規プロダクトはスピード感を求められるが、不確定要素が多い
  • 不確定要素に振り回されないために作り直しやすく作っていく必要がある
  • 最速でかつ良いものを作るにはチームメンバーが健常がどうかに目を向ける

ここまで色々と紹介しましたが、これはあくまで新規プロダクトにおける話しです。(新機能開発でも割と当てはまる部分はある)

フェーズが変わったらもちろんこの辺も変わるのを忘れないでください。

最後に

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

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

www.wantedly.com

www.wantedly.com

www.wantedly.com

Nuxt.js+Contentful+NetlifyでサーバーレスなSPAサイトを作成する

こんにちは!
株式会社SCOUTER開発部フロントエンドエンジニアの佐藤(@r_sato1201)です

先日、社内でプログラミング歴が浅い社員対象の、初学者LT大会というものが開催されました。 LT大会の様子は後日このブログにて公開されると思いますが、 今回はそのLT大会で私が作成したものを、使った技術の紹介も含めて紹介したいと思います。
主にNuxtとNetlifyについて紹介します。

作成物

休日に活動しているバンドのHPを作成しました。

f:id:ryonnsui1201:20181224165412p:plain
bokunofuneHP

技術構成

Nuxt + Contentful + Netlify

この構成を選んだ理由は大きく2点あります。

HPの更新を誰でも更新できるようにしたかった

バンドHPでは主に、ライブ情報や発売したCDなどの情報を定期的に更新する必要があります。 その更新を、私以外のバンドメンバーでも更新できるようにしたかった為、CMS化することを考えました。 その中で、ContentfulはAPIファーストでコンテンツの作成・管理を簡単にできるので選択しました。

サーバーを自前で用意・運用したくなかった

上記の通りなのですが、サーバーを自前で運用するのはコストもかかりますし、知見もなかったので 静的サイトホスティングサービスであるNetlifyを選択しました。 GitHubリポジトリからwebhookを受け取ると自動でリポジトリをビルドやデプロイしてくれるので非常に便利なサービスです。

1.Nuxtでサイトの作成

Nuxtプロジェクト作成

yarn create nuxt-app <プロジェクト名>

まずは上記コマンドでNuxtプロジェクトを作成します。

layoutの作成

各ページ共通であるヘッダー、フッターをレイアウトテンプレートに記述しました。

default.vue

<template>
  <div>
    <Header/>
    <nuxt/>
    <Footer/>
  </div>

</template>

<script>
import Header from '~/components/item/Header.vue'
import Footer from '~/components/item/Footer.vue'

export default {
  components: {
    Header,
    Footer,
  },
}
</script>

ヘッダー、フッター部分のコードは割愛します。

Contentfulの設定

Contentfulについて

Nuxtでプロジェクトを作り、外見をつくったら次はContentfulの設定です。 Contentfulはコンテンツを管理するためのREST APIを提供してくれます。 f:id:ryonnsui1201:20181225115721p:plain

Contentfulの概念は上図のようになっています。 各々をイメージで説明すると

Space:コンテンツを管理する単位
ContentModel:データベースのテーブル定義のようなもので、テーブルのカラム定義を設定する場所
Entry:ContentModelに定義したテーブルのデータ
となります。
Spaceの作成→ContentModelの作成→Entryの作成という順序でコンテンツを作成します。
次に、Contentfulを呼び出す用のプラグインcontentful.jsを作成します

contentful.js

const contentful = require('contentful')

const config = {
  space: process.env.CTF_SPACE_ID,
  accessToken: process.env.CTF_CDA_ACCESS_TOKEN,
}

module.exports = {
  createClient() {
    return contentful.createClient(config)
  },
}

次に、Contentfulと接続するためのAPI keyを取得し、接続設定を以下のように.envに記述します

.env

CTF_SPACE_ID="Your Space ID"
CTF_CDA_ACCESS_TOKEN="Your Access Token"
CTF_BLOG_POST_TYPE_ID="Your Post Type ID"

nuxt.config.jsにて先程.envに記述した内容をenvプロパティにて呼び出します。

nuxt.config.js

const config = require('./.contentful.json')

module.exports = {
  // ...
  env: {
    CTF_SPACE_ID: config.CTF_SPACE_ID,
    CTF_CDA_ACCESS_TOKEN: config.CTF_CDA_ACCESS_TOKEN,
    CTF_BLOG_POST_TYPE_ID: config.CTF_BLOG_POST_TYPE_ID
  }
  // ...
}

最後に、Vueファイルを記述し記事を取得します。 asyncData内でContentfulから記事情報を取得し、Liveコンポーネントに渡しています。
※Vueファイルは分かりやすくするため、簡略化しています

pages/live/index.vue

<template>
  <div class="container">
      <live
        v-for="post in posts"
        :key="post.fields.slug"
        :image="post.fields.image"
        :title="post.fields.title"
        :place="post.fields.place"
        :fee="post.fields.fee"
      />
  </div>
</template>

<script>
import Live from '~/components/Live'
import { createClient } from '~/plugins/contentful'

const client = createClient()
export default {
  transition: 'slide-left',
  components: {
    Live,
  },
 asyncData({ env }) {
    return client
      .getEntries({
        content_type: env.CTF_BLOG_POST_TYPE_ID,
        order: '-fields.date',
      })
      .then(entries => {
        return {
          posts: entries.items,
        }
      })
      .catch(console.error)
  },
}
</script>



components/Live.vue

<template>
      <div class="live-card">
        <div class="live-card_image">
          <img :src="image.fields.file.url">
        </div>
        <div class="live-card_contents">
          <p class="live-card_title">{{ title }}</p>
          <p class="live-card_place">{{ place }}</p>
          <p class="live-card_fee">{{ fee }}</p>
        </div>
      </div>
</template>
<script>
export default {
  props: {
    image: {
      type: Object,
    },
    title: {
      type: String,
    },
    place: {
      type: String,
    },
    fee: {
      type: String,
    },
  }
}

これでContentfulの設定は完了しました。

※詳しくは、Contentful公式ドキュメントに詳しく書かれているので参照して下さい。

Netlifyの設定

Netlify Formsについて

Netlifyを選んだ理由として、サーバーレスで実装できる以外にもフォームが簡単に実装できることが挙げられます。
HTMLの

タグの属性にnetlifyと追加で記述することで、そのフォームが動きます。 以下は公式ドキュメントの例です。

<form name="contact" method="POST" data-netlify="true">
  <p>
    <label>Your Name: <input type="text" name="name" /></label>   
  </p>
  <p>
    <label>Your Email: <input type="email" name="email" /></label>
  </p>
  <p>
    <label>Your Role: <select name="role[]" multiple>
      <option value="leader">Leader</option>
      <option value="follower">Follower</option>
    </select></label>
  </p>
  <p>
    <label>Message: <textarea name="message"></textarea></label>
  </p>
  <p>
    <button type="submit">Send</button>
  </p>
</form>

上記のように記述するだけで、NetlifyのFromページ上で送られた情報が確認できます。

サイトの作成

最後にNetlifyの設定について書きたいと思います。 「New Site From Git」を押下するとリポジトリ選択画面に移動するので、Nuxtプロジェクトをプッシュしたリポジトリを選択してください。 f:id:ryonnsui1201:20181224224147p:plain

次に、デプロイするブランチを選択して下さい。 基本的にはmasterでいいと思います。 f:id:ryonnsui1201:20181224225549p:plain

デプロイブランチを選択したら、ビルドの設定を行います。 今回は、Nuxtから静的サイトジェネレートするので nuxt generateと記述をします。
nuxt generateによってdistディレクトリが生成されるので、Publish Directoryにはdistと記述します。

f:id:ryonnsui1201:20181224230147p:plain

環境変数の設定

最後に環境変数の設定です。
.envに設定したContentfulのSpace ID,Access Token,Post Type IDを設定する必要があるので設定します。 f:id:ryonnsui1201:20181224232042p:plain

サイトの公開

以上までで、設定は完了です。 Netlify上で、「Deploy Site」をクリックすることでサイトが公開されます。

まとめ

Nuxt+Contentful+Netlifyという構成で簡単にSPAサイトを作成することができました。 初学者でも非常に簡単に作成できるので非常にオススメの構成です。

今後は、現在作成途中のバンドHPを最後まで作り切ると共に Contentful,Netlifyで出来ることに関してもっと理解を深めていきたいと考えています。

さいごに

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

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

www.wantedly.com

www.wantedly.com

www.wantedly.com

リリース品質、どうやって守っていますか?

こんにちは!

株式会社SCOUTERの鍬(@kuwausk)です。

SCOUTERの開発組織について書きます。

この1年間で僕が所属するチームのエンジニアが2名→6名に増えているのですが、 その中で、「どうプロダクトの品質を守ってきたか、これから守っていくか」をまとめてみようと思います。

開発チームが10名前後の規模感の組織で、プロダクト品質に責任を持っている方が、メインターゲットです。

目次

目次は以下の通りです。よろしくお願いします!

  • これまでの属人的な守り方について
  • スクラムをやってみた
  • SCOUTERのリリース品質チェックリスト、公開します!
  • スクラムを入れてみて思うこと

これまでの属人的な守り方について

自分もエンジニアとして開発していたので、仕様設計から実装〜動作確認〜リリースまで、"センス"で品質を守っていました。 リリース直前の動作確認で細かい修正を行うこともありましたが、その度に自分自身の品質レベルが上げていきました。

自分自身が砦になることで、品質を維持して安定リリースすることは出来るようになったのですが、メンバーが4人・5人に増えてくると、

  • 同じ品質レベルを共有する手段がない(属人的なので)
  • チームメンバーの品質レベルが成長しない
  • 自分がPO/PMとして本来やるべき仕事を一層求められる

という課題が顕在化しました。

「自分が離れると問題が発生しちゃうから!」というのは、一見求められている存在なようで宜しいのですが、裏返すとスケール出来ていない証明でもあります。

そして、チームをスケール出来ない、自分が成長できていない、というのはスタートアップ的には死です。。

スクラムをやってみた

チームをスケールさせるにあたり、SCOUTERではスクラムを取り入れました。

スクラムでは、「始めにゴールを決めて、ゴールまでの完成物(インクリメント)を分割して、スプリントでDoneを満たす完成物(インクリメント)をなるべく多く出そう!」ということをやっています。

僕たちは、完成物(インクリメント)を

  • 前スプリントの完成物と、今回スプリントの完成物の差分
  • すべてが正常に動くように十分にテストされたものである
  • Doneの定義を満たすものである
  • スプリントの終了時には、新しいインクリメントが「完成」している状態である

と定義しています。

「Doneの定義」は、リリースによって事業数値が伸びるかどうかを保証するものではありません。が、「サービス提供者として提供可能な品質である」ことを保証するものです。

種明かしになりますが、本記事のタイトルである「リリース品質、どうやって守っていますか?」に対するアンサーは、「Doneの定義で守っています」ということになります。

プロダクトバックログアイテム(PBI)やインクリメントの「完成」を決めるときには、全員がその「完成(Done)」の意味を理解しておかなければいけない。スクラムチームによってその意味は大きく異なるかもしれないが、作業の完了についてメンバーが共通の理解を持ち、透明性を確保しなければいけない。これは、スクラムチームの『「完成(Done)」の定義』と呼ばれ、プロダクトインクリメントの作業が完了したかどうかの評価に使われる。開発チームは、スプリントごとにプロダクトインクリメントを届ける。インクリメントは実際に利用可能なものであり、プロダクトオーナーがすぐにリリースすることもできる。インクリメントの「完成」の定義に関して、開発組織の慣例・標準・ガイドラインが存在する場合は、スクラムチームは最低でもそれを守らなければいけない。( スクラムガイド - Scrum Guidesより抜粋)

SCOUTERのリリース品質チェックリスト、公開します!

ここで、今実際にチームで運用している「Doneの定義」を公開してみようと思います。

「こんな当たり前な内容を書かないと守れないのか」とか「1週間で満たすには結構厳しい条件だな」など色々思われるかもしれませんが、これが今の僕たちの品質そのものです。

WF

  • 必要なページが全て揃っている
  • ページ内で必要な要素が揃っている
  • ページごとに各要素の重要度を分類する

デザイン

  • ユーザーストーリーを満たすフィーチャーがデザインされている
  • 技術的な実現可能性の検討結果がesaに記録されている
  • スタイルガイドの更新について検討結果がesaに記録されている
  • 操作可能なオブジェクトの動的な挙動がある場合、それがesaに記述されている
  • 操作可能なオブジェクトに対してhover,action,focusなどのデザインが網羅されている
  • アニメーション・トランジションが発生するオブジェクトについて、挙動がesaで明確化されている
  • 書き出しが必要な素材について、2倍の解像度でzeplinからダウンロード可能になっている
  • 素数が0件のパターンがデザインで網羅されている
  • 素数が多い場合のパターン(スクロール・ページネーション・展開など)がデザインで網羅されている
  • 文字コンテンツの字数が多い場合の取扱がデザインで網羅されている

仕様/設計

  • ユースケースを満たすエンドポイントが全て定義されている
  • エンドポイントに対してAPISPECが作成されている
  • デザインで扱っている項目を満たすDBスキーマが定義されている
  • esaにDB仕様書が作成されている
  • 現行仕様への影響が洗い出されている(現行仕様を変更する場合)
    • 影響箇所、対応方法がesaに記載されている
    • テストのチェックリストがesaに作成されている

実装

  • APISPECとAPIのレスポンスが同じ形になっている
  • ユーザーストーリーで定義されたアクションを実行することができる
  • デザイナーのUIチェックが通っている
  • CI、レビューが通っている
  • リリース手順が用意されている

ブラウザテスト(ステージング環境)

  • ユーザーストーリーで定義されたアクションを実行できる(IEを除く)
  • 現行仕様への影響箇所のテストのチェックリストを全て満たしている

振り返り

  • ストーリーポイントについて、予定pt,完了ptが記録されている
  • ストーリーポイントについて、3週間の平均(velocity)が記録されている

スプリントプランニング

  • タスクが一覧化されている
  • インクリメントごとにタスクが分割されている
  • 分割したインクリメントを完成させる順番が決まっている
  • タスクの見積が完了している(2点見積でも可)
  • 見積結果を元にインクリメントの調整が終わっている
  • 調整後のインクリメントが定義されている
  • わかっているAPIの一覧が書き出されている
  • 影響範囲がページ単位で明確化されている

※スプリントプランニングは、スプリントの始めに行うミーティングです image.png (559.8 kB) (参考) 1週間のスプリントにおける開発フロー

Doneの定義についてのチームのルール

補足になりますが、Doneの定義について、チームで以下のルールを設けています。

  • Doneの定義は、スプリントの合間に更新しても良い
  • Doneの定義は、開発チーム全員で満たすように頑張る。責任者を明確に定めない
  • Doneの定義は、スプリント振り返りのmtgで発案し、合意すれば更新できる
  • Doneの定義は、チームの習熟度によって追加され、定義が厳しくなるものである

スクラムを入れてみて思うこと

エンジニアやデザイナ出身で、職能のあるPO/PMは特に、"自分が出来る仕事" "簡単にバリューを出せる仕事" で手を動かしてしまいがちです。

けれども、PO/PMには、プロダクトを成功に導くという大事な役割があります。 僕自身は最近POとして、

  • 開発ロードマップの更新(プロダクトバックログの可視化・並び替え)
  • 完成物(インクリメント)の確認、開発チームへのフィードバック
  • ユーザーインタビュー(企画した機能についてインサイトを探す)
  • ユーザビリティ検証
  • 数値分析(SQLを書く、振り返り、ログが足りないところのDB設計と実装)
  • リリース準備(マーケチームやCSチームとの連動など)
  • 大きな障害が発生した時のディレクション

などを行っていますが、"設計や実装をしている場合ではない"と、半年前の自分に教えてあげたいです。。

開発チームの人数が増えたりプロダクトがMVPリリースの時期を超えたりすると、PO/PMに求められる仕事は、実装や設計やリリース期限を守ることではなくなると思っています。開発チームと相互に助けあって、集合体としての力を最大化すれば、人間ひとりでは出来ないようなアウトプットを創造することができます。

プロダクトを成功させられるように、開発チームとPOがそれぞれの役割を最大限果たせるように、引き続き取り組んでいきたいと思います。

最後に

Doneの定義に「テストが通っていること」を追加してくれるリードエンジニア、募集しています!

www.wantedly.com

www.wantedly.com

デザイナーさんも大募集中です! www.wantedly.com

【Vue.js】Vue.Draggableを使って躓いたところ

こんにちは株式会社SCOUTERでフロントエンドエンジニアをしているhirokinishizawaです。

以前機能開発でドラッグアンドドロップを行えるようにするという開発を行いました。そこでVue.Draggableを使用することになったのですが躓いたところがあったのでメモとして残していければと思います。

成果物 f:id:hiroki-nishizawa:20181218112555p:plain

ドキュメント github.com

インストール

yarn add vuedraggable
又は
npm i -S vuedraggable

構成

実際の機能とは少し違うのですが近い感じの構成で簡単に作成してみました。

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

<template>
  <div class="conteiner">
    <div 
      v-for="(list, key) in lists" 
      :key="key" 
      class="lists">
      <div class="list-wrapper">
        <draggable 
          :options="{group:'group', animation: 150}" 
          class="draggable"
          @start="draggableStart"
          @end="drag=draggableEnd">
          <div 
            v-for="item in list" 
            :key="item.id"
            class="list" >
            {{ item.name }}
          </div>
        </draggable>
      </div>
    </div>
  </div>
</template>

<script>
import draggable from 'vuedraggable'

export default {
  components: {
    draggable
  },
  data() {
    return {
      lists: [
        [{ name: 'aaa', id: 1 }, { name: 'bbb', id: 2 }, { name: 'ccc', id: 3 }],
        [{ name: 'ddd', id: 4 }, { name: 'eee', id: 5 }, { name: 'fff', id: 6 }],
        [{ name: 'ggg', id: 7 }, { name: 'hhh', id: 8 }, { name: 'iii', id: 9 }],
        [{ name: 'jjj', id: 10 }, { name: 'kkk', id: 11 }, { name: 'lll', id: 12 }]
      ]
    }
  }
  methods: {
      draggableEnd(event) {
          console.log(event)
      }
  }
}
</script>

躓いたところ

画像のように今回いくつかの列に別れて縦移動のみではなく横移動もできるようにしました。 ドキュメントを読めば縦横のドラッグアンドドロップをできるようにするのはとても簡単に出来るかと思います。今回保存移動後にデータベースに移動先、順番を保存をしなければいけなくサーバーサイドに渡すものとして横移動をした際に`移動前の列,移動先の列`が必要で、この情報をどこからとってくるのかで躓きました。

解決策

Vue.DraggableはSortableというライブラリを拡張したもので、Sortableのイベントを使えます。イベントの種類はこちらに書いてありますがstart, add, remove, update, end, choose, sort, filter, cloneがあり、今回使用するのはendイベントになります。

イベントの中身をconsoleで吐き出すと以下のようなデータが吐き出され f:id:hiroki-nishizawa:20181218094115p:plain

from(移動前),to(移動先)があるので次に

draggableEnd(event) {
      console.log(event.from)
      console.log(event.to)
}

f:id:hiroki-nishizawa:20181218100540p:plain f:id:hiroki-nishizawa:20181218100553p:plain

としたところhtmlが返ってきました。

先程も言ったように列の情報がほしいのですが、3列目と4列目を区化するものがなく仕方なく、

<draggable 
          :options="{group:'group', animation: 150}" 
          class="draggable"
          @start="draggableStart"
          @end="drag=draggableEnd"
          :data-column-id="key">

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

data-column-idを持たせることでevent.to.data-column-idで移動先の列と移動前の列の差分を取ることができました。

他にいいやり方が合ったかもしれないですが分からなかったのでわかる方いたら教えていただきたいです!

最後に

エンジニア、デザイナーの採用を行っております!

デザイナー、エンジニアの皆さん興味のある方はご応募お願いします!

www.wantedly.com

www.wantedly.com

www.wantedly.com

PHPConにて話した「PHPを使う理由」の解説

PHPConにて話した「PHPを使う理由」の解説

こんにちは、 kotamat です。 2018-12-15 PHPカンファレンス2018にて、スポンサリングさせていただきました!

phpcon.php.gr.jp

f:id:kotamat:20181217110906j:plain

f:id:kotamat:20181217111129j:plain
お配りしていたチラシ 結構目立っていたようです

プラチナスポンサーをさせてもらったので、「PHPを選ぶ理由」というタイトルでスポンサーセッションさせていただきました。

本記事は発表内容を簡単に解説します。

軽くまとめると

  • 入社したタイミングで、言語含めた技術の再検討を行った。
  • 採用難易度、市場性、習熟度などを総合的に判断してLaravel Vue.jsを採択した。
  • 情報発信を通じてポジション形成を行った。
  • PHPが苦手なものは技術で解決していく。
  • どうしても無理なところは他言語を使う前提でアプリケーションを構築していく。

採用難易度という概念について

人によるとは思いますが、ある程度習熟度のあるエンジニアは、新しい技術を触れ続けるという観点で、一見合理的に見える技術選定を行った後、採用に苦労するというパターンがいくつか見受けられてきました。 toCサービスやDev向けツールのサービスを行っている会社であれば、認知形成にそれほど苦労はしないですが、弊社のようなtoBに近く、あまり採用者が触れるサービスではないものになってくると、認知形成が難しく、認知形成できている採用競合に負けてしまうという事象が発生してしまいます。

もちろんサービスの方向性として、業界を変革するような新しいアプローチで課題を解決しているという自負はあるので、詳しくサービス説明をした方からは「面白いサービスやっているんですね。」という反応はあるのですが、その手前に「話を聞いてもらう機会を作る」という前提が必要であり、大変な売り手市場のエンジニア採用においては、そこがネックとなるパターンが多いです。

しばらく売り手市場は継続するはずであり、ここでの意思決定は今後の事業成長に大きく関わってくるということが自明であったため、採用難易度を将来見据えて検討いたしました。

認知形成の手法に関して

昨今のサービス構築には、OSレベルからフロントエンドまで、全てにおいてOSSが関わっています。

そういった環境下において、オープンに情報を共有するというのが結果エコシステムを形成し、自分たちにもメリットが有る形になるという文化が形成されております。ブログでの技術発信や勉強会などがその発信の場の一つとなっており、弊社はそういったものを主催したり、別の勉強会で発表するなど行ってきました。

情報発信するにあたって、マーケティング的な視点が必要と考え、どういったポジションを構築するのかということを考えたときに、LaravelやVue.jsでの独立したコミュニティはすでに存在していたのですが、それぞれをマージしたLaravueというものはポジションを形成している人や団体は存在していなかったため、そこに注力して情報発信を行ってきました。

その結果累計1000名規模の、それなりの認知の形成までは来ることができ、「Laravel + Vue.jsの会社ですよね!」というお声をいただくことが増えてきました。

PHPの得意なところ、苦手なところ

PHPは得意なところとして、エンジニア市場における言語習熟割合が高い言語であり、Webアプリケーションを構築する上では、及第点を出せる言語だと思っております。

逆に、高トラフィックを捌くことや、マルチスレッドでの高速化、FaaS系のサポート、機械学習など依存パッケージに伴う解決できる手法の限定などにおいては苦手だと思っており、その領域は1. PHP外のミドルウェアとの連携で頑張る 2. 他言語との連携を行う というエンジニアリングで解決できるのではと考えております。

今回は静的チェックに関して解決方法を紹介させてもらいました。クラウドのCI環境を整備することで擬似的に静的チェックでそこそこの品質担保ができるようになります。

他言語にまたがる前提で、gRPCやGraphQLなどのIDLをもちいたり、APIスペックの自動生成などでインターフェースレイヤーの品質担保をする必要があり、弊社では、LaravelのPHPUnitを拡張したテスト機能をもちい、APIスペックの自動生成を行っております。

まとめ

サーバーサイドの言語には、昨今様々な技術が取り入れられており、PHP以外にも選択肢が増えてきている状況かなと思います。 一つの言語にこだわらず、バランス感覚をもって技術選定をしていくのが今後求められるのかなと思っております。

最後に

SCOUTERではエンジニアの採用を行っております!

デザイナー、エンジニアの皆さん興味のある方はご応募お願いします!

www.wantedly.com

www.wantedly.com

www.wantedly.com

Vue on Laravelというモノリスを解体してNuxtへ移行しました!

こんにちは、株式会社SCOUTERの開発部の小平(@ryotakodaira )です。

f:id:ryotakodaira:20181212011618p:plain 以前Twitterにてこのようなツイートをして、Nuxt移行の記事を書くと宣言してしまっていたので、書く書く詐欺で終わらないように今回の開発の背景などを含めて記事にしてみました。

弊社では、SARDINEという法人向けの業務管理ツールを提供していますが、そのアプリケーションはLaravelがベースにあり、その中でVueを使う構成で運用されていました。

今回、そのようなLaravelに依存しているVueアプリケーションからフロントエンドのみを切り出す形でLaravel API+Nuxtアプリケーションに置き換えを行いました。

この記事では、なぜNuxtに移行したのかや、その時に少し躓いた点について記していこうと思います。

なぜフロントを切り出す選択をしたのか

今回リニューアルをしたアプリケーションはリリースから1年6ヶ月程が経過しており、当然のことながら同期間立て続けにシステムの追加開発/運用を続けてきました。

当初は立ち上げから間もないサービスということもあり、スピード重視での開発体制であったため、アプリケーション構成も最小構成のLaravel(bladeテンプレート)の中でVueを使う構成で開発を進めていました。

機能追加を繰り返しコードベースの量が増えたり開発に関わるメンバーが増えたことによって以下のような問題が顕在化してきました。

ページ読み込みにかかる時間が長いことによるユーザビリティの低下

  • 前述の通り、Laravel(bladeテンプレート)の中でVueを使う構成で作られていた
  • そのためクライアント側のルーティングをLaravel(PHP)が握っている構成でアプリケーション自体が構築されておりvue-routerなども使用していなかったため、ページ遷移のたびに「JS/CSSファイルのダウンロード→Vueインスタンスの初期化」が行われてしまっていた

採用要件を高めてしまっている

  • バックエンド、フロントのコードが完全に分離出来ていないため、LaravelとVueの両方に理解がないと1つの機能開発を行うことが出来ない状態になっていた
  • 仮に両方出来たとしてもバックエンド、フロントのそれぞれの責務範囲がはっきりしていなかったためキャッチアップにも時間がかかってしまう

開発効率の低下

  • はるか昔に導入した化石のようなパッケージ群の影響範囲が分からず毎回影響範囲を調査する必要があった
  • ESLintやPretterを入れていなかったためコードスタイルが無法地帯
  • モノリシックな構成になっているためバックエンド、フロントの両方を気にかけて開発を行わないとならない
  • コードが増えるにつれてjavascriptのビルドの時間が長くなり開発中の待ち時間が増加(laravel-mix)

ということでそれらを一気に解決するために、フロントを切り出す開発に踏み切りました。

移行時に気をつけたこと

VuexStoreの設計

  • NuxtのSPAモードで開発するので、今までとは違ってページ遷移するたびにStoreが初期化されない(元々はページ遷移でどうせ初期化されるからちゃんとやってなかったw)
    • ページ遷移してもStoreは引き継がれるため遷移先の挙動に影響を及ぼさないように調整
  • コンポーネント内にdataプロパティーとして状態を持っている場合、ページ遷移でコンポーネントが破棄されると当然dataプロパティーも破棄されるので同じページに戻ってきた時に再度リクエストが走り、無駄が生じてしまう可能性がある
    • Vuexをフル活用しグローバルに状態を持つように変更して該当ページに再流入してきた時はAPIにリクエストを送らずにVuexからデータを降ろしてくるように処理を修正する

移行時に躓いたこと

驚くべきことにNuxtへの移行に大きな問題には遭遇しませんでしたが、 唯一少し躓いたところがありましたので、その部分の説明をします。

this.$router.pushの仕様

this.$router.push('hoge', {
  query: {
    params: ['foo', 'bar']
  }
})

Nuxtで上記のようにルーティングのプッシュを行うと、デフォルトでは http://example.com?params=foo&params=bar のようなURLになります。

ただ、このクエリーパラメータのフォーマット形式だと弊社のサービスにとっては問題が有りました。

Nuxtのページコンポーネントで受け取った query のオブジェクトが意図した形では無いという問題でした。

// http://example.com?params=foo&params=bar

query = {
  params: ['foo', 'bar']
}

// http://example.com?params=foo

query = {
  params: 'foo'
}

👆配列で欲しいが文字列になってしまう

要件としてはparamsが一つだったとしてもパースした結果は配列として受け取りたいので、nuxt.config.jsに以下のような記述を追加してvue-routerを拡張して解決しました。

query-stringというnpmパッケージを通すことによってクエリパラメーターのフォーマットを指定できるのでその方法を採用しました。

ちなみにquery-stringを通すとURLは http://example.com?params[]=foo&params[]=bar のようになります。

module.exports = {
  router: {
    parseQuery(query) {
      return require('query-string').parse(query, {
        arrayFormat: 'bracket',
      })
    },
    stringifyQuery(params) {
      if (Object.keys(params).length === 0) {
        return ''
      }
      const query = require('query-string').stringify(params, {
        arrayFormat: 'bracket',
      })
      return `?${query}`
    },
  },
}

まとめ

VueをNuxtへの移行は今回が初めてでしたが、移行中は大きな問題は特に発生せずNuxtはまさにかゆいところに手が届くという言葉がふさわしいなと実感しました。

弊社と同じような課題を抱えている開発チームにはぜひ取り組んでみて欲しいと思います!

今回のNuxtへの移行にはエンジニアメンバー4人で3週間かかりましたが、顕在化していた問題は無事解決されたため、リターンとしては十分で合ったと思います。

ただ、Nuxtへ移行する前のLaravel(bladeテンプレート)の中でVueを使う構成のアプリケーションが他にも存在しているためタイミングを見てそちらもNuxtに移行していきます。

次は2回目なのでもっと早く終わると信じて。

さいごに

SCOUTER社の開発チームの取り組みを紹介させていただきました! サービスが成長していくにあたって、これからもメンバーを増やしていきたいと思っています。

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

www.wantedly.com

www.wantedly.com

www.wantedly.com