SCOUTER社でデータ可視化が定着するまで

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

自分の担当している事業では、metabaseというBIツールを使用して数値管理・可視化をしています。 そこで今回は事業全体にBIツールを用いた数値管理を定着させるまでの話を書いていきます。

BIツールとは簡単にいうとサービスのDBなどに蓄積されているデータを可視化するためのツールです。

BIツールの「BI」とは、「ビジネス・インテリジェンス(Business Intelligence)」を意味します。ビジネス・インテリジェンスとは、企業が日々蓄積されていく膨大なデータを分析し、その分析結果を経営意思決定に活用することをいいます。 このBIを助けるシステムを総称したものを「BIツール」と呼びます。 *1

metabase導入前

導入前は、サービス内の主要KPIを確認するものはほぼ存在せず、どうしようもない状態でした。。。

そんな状態でも当然、事業部のメンバーから数値を出力する依頼が来る訳ですが、その都度SQLを書いて出力結果のCSVを渡していたり、クレンジングされたデータが無かったので毎回クレンジング用のクエリを追加していましたw

なぜmetabaseを選択したのか

BIツールはかなり多くのサービスがあり、OSSのものからサブスクリプションモデルで高価なものまで幅広いのが現状となっています。 OSSのBIツールもいくつかありますがその中でもmetabaseを選択した理由は主に以下の3点となります。

親しみやすさ

f:id:ryotakodaira:20190117114813p:plain

上の画像を見ていただければわかると思いますが、metabaseのユーザーインターフェイスはかなりシンプルでわかりやすく作られています。

データが可視化できれば見た目はどうでもいいだろと思うかもしれませんが、「親しみやすさ」はかなり重要だったと考えています。

エンジニアのみが使うものなら見た目を度外視していてもある程度は我慢できる?かと思いますが、触る時間が長いのは常に数値確認を行う事業部のビジネス職のメンバーだからです。

実際、数値が可視化されていてもそれが見にくい場合は時間が経つに連れて見られにくくなってしまうため、選定時に「親しみやすさ」(見た目)は重要視して比較していました。

扱いやすさ

metabaseにはダッシュボードという複数のグラフを1画面に並べて表示すること出来ますが、画像のようにセルの範囲内でグラフの大きさを自由に変更することが出来ます。

ダッシュボードの中でも大きく表示したい重要なグラフや参考程度の情報のグラフが混在することがありますが、グラフの大きさで分類する事ができます。

f:id:ryotakodaira:20190117114708p:plain

また、クエリビルダーのような機能が搭載されており、SQLを書かずにグラフを表示することが出来ます。

複雑な条件には対応出来ないものの1テーブルの中のデータを可視化するくらいであれば一瞬で作ることが出来ます。

これならエンジニア以外のメンバーでもグラフを作成することができるためSQLに触れるきっかけを作ることもでき、多方向で効果を発揮します。

f:id:ryotakodaira:20190117114745p:plain

導入コスト

metabaseはOSSのプロジェクトとして開発されているため無料で使うことが出来ます。

当初からサクッと環境を作って運用まで持っていきたいという思いがあったため、OSSのプロジェクトであるmetabaseは適していました。

また、dockerイメージが用意されているためサーバー上にmetabaseを構築するのは普段インフラを触っていないエンジニアでも簡単にできるようになっています。 なので短期間で導入までたどり着くことができました。

最近では大体のOSSのBIツールはdockerイメージが用意されている印象です。

導入後に気をつけたこと

BIツールを導入したのはいいけど、使われるのは最初の1ヶ月で直ぐに忘れ去られてしまうという事態は以外と多いのではないかと思います。

しかし、BIツールは事業にとって非常に重要なものであり、無いと意思決定を間違いかねません。

僕も以前にそのような失敗をしていますが、今回は同じ失敗を繰り返さずメンバーに親しまれるツールにするために実行したことを上げます。

事業目標数値を常に可視化する

metabaseを使って数値やグラフを見るタイミングは大きく2つあると考えています。

  1. 標数値/中間指標の確認
  2. 実績の原因分析

特に 1 目標数値/中間指標の確認 に関してはほぼ毎日行います。そのため、metabaseで可視化することによって強制的にmetabaseに触れる機会を増やしています。

追加して、metabaseのグラフを全員が見ることができるため "AさんとBさんの集計結果が違った" などの事態の発生を防ぐこともできるようになっています。

クレンジング済みのデータを用意する

データクレンジングとは、データベースに保存されているデータの中から、重複や誤記、表記の揺れなどを探し出し、削除や修正、正規化などを行い、データの品質を高めること。 *2

グラフの作成依頼は直ぐにそのグラフを確認したい場合に飛んで来ることがほとんどです。素早くそれらの依頼に対応するために、よく使われるデータについては常にクレンジング済みのものを用意するようにしました。

依頼者からすると見たいときにデータを見れないことが一番のストレスとなるため、そうならないようクレンジング後のデータの整備にはかなりの力を割きました。

クレンジングすることによってデータが扱いやすくなっているため、素早く求められているデータの出力が可能になったり元々のデータ構造を完全に理解していなくてもクエリを書くことができるようになりました。

弊社では、Laravelのデイリーバッチ処理でクレンジング後のデータをMySQLに格納する形で運用されています。

データ量を考慮しても今のところは前述の運用で間に合っていますが、今後さらなるスケールをした場合は違った運用方法に乗り換えるべきなのではないかという所感です。

まとめ

このようにして、BIツール(metabase)で数値を確認し、数値振り返りを行うことができるところまで作りあげることが出来ました。 今まで数字を見ていなかったメンバーや開発チームも数値で振り返ることができるようになったことが今回の一番の収穫だろうと感じています。

これからBIツールを導入するという方はぜひ試してもらえたらと思います!

今回はデータソースとしてMySQLのみに対応させていましたが、社内ではGoogleAnalyticsなども使っているため今後は他のデータソースの可視化も出来たらと考えています。

さいごに

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

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

www.wantedly.com

www.wantedly.com

www.wantedly.com

Laradockを使ったLaravel開発環境構築のやさしい解説

こんにちは!

今月からSCOUTER開発部でフロントエンドエンジニアをしている匠平@show60です。

弊社開発部では主にVue.jsとLaravelを使って開発をしています。

私も日頃はVue.jsを使ったフロントエンドの開発を担当させてもらっていますが、あわせてLaravelの学習も始めました。

さっそく開発環境の構築を始めたのですが、知らないことだらけのなかなか大変な作業で、新年から涙しそうでした。

これからLaravelを始めようという方が悲しみに暮れないよう、Laravel開発環境構築をやさしくやさしく解説したいと思います。

サマリ

  • マイグレートしてデータベースを作るまでを解説
  • 起きるかもしれないエラーにも言及

開発環境について

  • MacBook Air
  • Git
  • Laradock

Laradockとは

公式ウェブサイトには、Laravel(PHP)のプロジェクトをDocker上で動作させるためのワンダフルな環境とあります。

A full PHP development environment for Docker. Includes pre-packaged Docker Images, all pre-configured to provide a wonderful PHP development environment. Laradock is well known in the Laravel community, as the project started with single focus on running Laravel projects on Docker. [Laradock official] (https://laradock.io)

Laravelプロジェクトの開発環境はいくつもありますが、今回はこのワンダフルなLaradockを使って環境構築を行っていきます。

Laradockを使う上で、最低限知っておきたい基礎知識

きちんとした解説はもっと詳しい方へ譲るとして、開発環境を整える上で最低限理解しておきたいこと、また理解しておけばよかったと思ったことです。

なぜ仮想環境が必要なのか

Laravelの実行にはいくつものプログラムやライブラリが必要になります。例えばPHP, nginx, MySQLやミドルウェアなどです。

ある特定の環境でしか動かないプログラムなどに対応するために、1つのPC上に複数の環境を用意する必要がありますが、1つのOS上には1つの環境しか用意できないため、仮想のOS環境を用意する必要があります。

Docker、コンテナとは

Dockerはコンテナ型と呼ばれる仮想環境の1つです。仮想環境は他にホスト型、ハイパーバイザー型があります。

Dockerはコンテナという区画を複数提供することで、ある区画ではPHPアプリケーションを、別の区画ではMySQLを実行するというように隔離された実行環境を実現します。 隔離されている各区画(コンテナ)同士は、TCPという通信プロトコルで接続されます。

Laradockの導入

Laradockのダウンロード

ホームディレクトリにLaradockをダウンロードするために、ディレクトリを作成します。名前は任意で、ここでは「laravel_study」という名前にしました。

ダウンロードが完了したら、laradockに移動して.envファイルを作成します。

// laravel_studyディレクトリに移動
$ cd laravel_study

// GitからLaradockをダウンロード
laravel_study $ git clone https://github.com/Laradock/laradock.git

// ダウンロードができたらlaradockに移動
$ cd laradock

// env-exampleをコピペして.envファイルを作成
laradock $ cp env-example .env

このあとにMySQLをダウンロードしますが、先にバージョンを指定してあげます。

指定しない場合、latest(最新)バージョンをダウンロードします。投稿時点で最新バージョンである8系からはユーザー認証方式が違っており、私はここでかなり詰まってしまいました。

よんどころない理由がなければ、5.7を指定しましょう。

作成した.envファイルをテイストエディタで開いて、MYSQL_VERSIONを修正し保存します。

// "MYSQL_VERSION=latest" を以下のように変更
MYSQL_VERSION=5.7

コンテナの初期化

下記のように、nginx, MySQL, workspaceやphpMyAdminなど開発に必要なプログラムを指定してダウンロードします。これらが各コンテナで実行されることになります。 初めてダウンロードする際には20分ほど時間がかかります。

$ docker-compose up -d nginx mysql workspace phpmyadmin

各プログラム名の横にある進捗が"... done"となれば完了です。

http://localhostにアクセスすると404 Not Foundと表示されます。一見失敗に見えますが、ページにはnginxと表示されており、すでにコンテナ上でプログラムが実行されていることが分かります。

「docker-compose up ...」というコマンドは、これらのプログラムを実行する際に入力します。初回のみダウンロードに時間を要しますが、次回以降はほとんど待たずに実行します。

Laravelアプリケーションファイルの準備

Laravelプロジェクトは先ほどダウンロードしたworkspaceコンテナで実行されます。

workspaceにログインし、ここでは「sample」という名前でLaravelアプリケーションファイルを作成しました。その際にLaravelのバージョン5.5系を指定しています。なお、Laravelアプリケーションファイル名を「Laravel」にしてしまうとエラーが出るようなのでご注意ください。 Laravelのダウンロードには5〜10分ほど時間がかかります。

// wordspaceコンテナにログイン
$ docker-compose exec --user=laradock workspace bash

// ログインすると"/var/www$" というディレクトリに入ります
// workspace上でLaravelアプリケーションファイルを作成します
$ composer create-project laravel/laravel sample --prefer-dist "5.5.*"

// "Application key [base64:****] set successfully." となれば完了
// workspaceコンテナからログアウト
$ exit

workspaceコンテナで新たに「sample」という名前のアプリケーションファイルを作成できました。ここにLaradockがアクセスできるよう、Laradockディレクトリの.envファイルを修正します。先ほど.env-exampleをコピペして作ったものです。 Pathsの項目にあるAPP_CODE_PATH_HOST=../sampleと追記します。

### Paths #################################################

# Point to the path of your applications code on your host
APP_CODE_PATH_HOST=../sample

dockerを再起動します。.envファイルを修正した際には再起動が必要です。

# dockerを停止
$ docker-compose stop

# dokcerを再起動
# ここではnginx と MySQLだけ指定しています
$ docker-compose up -d nginx mysql

Laravelのアプリケーションファイルとそのパスを設定できたのでLaravelのページを開いてみましょう。 再度ブラウザでhttp://localhostにアクセスすると、無事Laravelのアプリケーションが起動していることが確認できます。

マイグレーションしてテーブルを作成する

MySQLにユーザー情報を登録できるテーブルを作成します。マイグレーションという機能を使うことで、テーブルの新規作成や実行を簡単に行うことができます。 マイグレーションに必要なファイルはすでに用意されているのでそちらを使います。

sample/
  └ database/
    ├ factories/
    ├ migrations/
    │  ├ 2014_10_12_000000_create_users_table.php
    │  └ 2014_10_12_000000_create_password_resets.php
    └ seeds/

マイグレーションファイルはテーブルの設計図のようなものです。今回は編集は加えずに、そのままマイグレーションを実行します。

// sampleディレクトリに移動
$ cd
$ cd laravel_study/sample

// マイグレーションの実行
$ php artisan migrate
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table
Migrating: 2014_10_12_000000_create_password_resets_table
Migrated: 2014_10_12_000000_create_password_resets_table

// マイグレーション完了

これでMySQLに新しいテーブルが作成されました。

マイグレーションの際に出たエラー

マイグレーションの段階で何度もエラーに遭遇し、その度に悲しい思いをしてきました。

一部ですが、実際に出たエラーとその対処法を紹介します。

SQLSTATE[HY000] [1045] Access denied for user 'ユーザー名'@'ホスト名' (using password: [YES/NO])

MySQLにログインできないよ、というエラーです。

using passwordYESの場合はユーザー設定の間違い、NOの場合はログインのパスワードの間違いが原因です。

私の場合はYESとなっており、ユーザー名が違っていました。Laradocksampleのそれぞれのディレクトリの.envファイル内のDB_USERNAMEのパラメータを合わせる必要があります。sampleディレクトリ側の.envファイルを編集、保存し、dockerを再起動することで解消しました。

"SQLSTATE[HY000] [2002] Connection refused

MySQLが起動していないよ、というエラー。

docker-compose up -d nginx mysqlで立ち上げましょう。

ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/tmp/mysql.sock’ (2)

  • MySQLに接続する通信プロトコルは、TCP通信とソケット通信の2種類ある。
  • localhostがsocket使いたがるので、TCPに変更(127.0.0.1)する必要あり

MySQLから作成したテーブルを確認

先ほど作成したテーブルを確認できたら完了です。

// MySQLに接続
// DB_DATABASEは.envファイル内の名前と同じ
$ mysql --host=localhost --user=[MySQLのユーザー名] --password=secret [DB_DATABASE]

// テーブルを表示
$mysql> show tables from [DB_DATABASE]

最後に

私と同じように初めてLaravelに触れる方に、少しでもこの記事がお役に立てれば幸いです。

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

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

www.wantedly.com

www.wantedly.com

www.wantedly.com

理想とする技術組織

こんにちは、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