【プロマネ】プロジェクトの「測る化」の実践

はじめに

開発グループPMO(プロジェクトマネジメントオフィス)の大嶋です。

過去10年近くのプロジェクトマネージャー(PM)的な役割を経て、下期からウィルゲート開発グループを横断的に見るPMOとしてゼネラルマネージャー(以下GM)を補佐する形で組織戦略の立案遂行や開発本部の運営、採用活動などを主なミッションとしています。実はこのブログ自体もそういった役割の一環として、よりよい形に変えていくことを意識しています(笑)

ウィルゲートは大きくコンテンツマーケティング事業とメディア事業があり、それぞれの事業の中でも大小複数の開発プロジェクトが並行で進んでいます。1週間~1ヶ月くらいで終わるものが大半ですが、中には半年からそれ以上の規模で動いているものもあります。

今回は、大きめのプロジェクトを対象としてコンディションを客観的な視点で見て必要に応じた打ち手に繋げるために、GMより託された『変化に強い計画・問題発見の技術 プロジェクトの「測る化」』の書籍を参考に行った取り組みをご紹介します。

変化に強い計画・問題発見の技術 プロジェクトの「測る化」

変化に強い計画・問題発見の技術 プロジェクトの「測る化」

 

 

プロジェクトの何を「測る化」するか

ビジネスにおいて「見える化」というワードは、トヨタ自動車が浸透させたものとして有名だと思います。ウィルゲートでも、主に開発プロジェクトの「見える化」はカンバン方式でタスク管理するツールを活用して行われてきています。

tech.willgate.co.jp

今回は「測る化」ということで、一歩進んでプロジェクトにおいて見えづらい指標を定量化する試みになります。
書籍に則ると、定量化するべきものは以下の「QCD+S」が対象になります。

  • Quality ・・・品質
  • Cost ・・・コスト
  • Delivery ・・・納期
  • Scope ・・・スコープ

この中でもスコープは普段なかなか見えづらいですし、ウィルゲートの開発プロジェクトにおいても進行途中で開発要件が変わることは少なくないので、特に注目して「測る化」をしていきました。
余談ですが、開発スコープが変わることはややもするとネガティブな捉え方もされがちかと思いますが、中長期のプロジェクトであるほど時間の経過とともに周辺の状況も変わっていくものなので、一定の変化はあるべきものと捉えて普段から計画や目標設定をしています。

どのように「測る化」したか

  • スコープについて
    まず最も注目したと述べた「スコープ」に関しては、ファンクションポイントを算出することで「測る化」としました。ファンクションポイントの考え方自体は1979年に提唱されているそうですがウィルゲートではほとんど初めての試みとなったので、Web上の情報を参考に算出方法をみんなで学んで実践しました。
    チームによってはスクラム開発手法に則りストーリーポイントを見積として使用しているところもありますが、今回はプロジェクト横断的に実践するために書籍も参考にファンクションポイントを使用しています。

    FP 法のイメージをつかむ - あしのあしあと

  • コストについて
    コストの「測る化」についてはこれまでも会計処理のために、毎月開発に掛けた工数(時間)をもとにして算出していたのでそれを転用しました。
    基本的にはエンジニア1名あたりの単価×人数となり、そこにそれぞれのプロジェクトへの稼働比率(100%専任なのか、2つを50%ずつなのかなど)を加味して算出しています。
  • 品質について
    品質についてはサービスで起きた障害事案は開発組織全体で統括的に管理しているんですが、プロジェクトが完了してしばらく経たないと評価できないものになります。従って今回はプロジェクトによって管理方法が異なることを理解した上で、リリースまでのテスト工程で検出したバグや、変更依頼の件数を障害管理表からカウントして使用することにしました。
  • 納期について
    今回は完了したプロジェクトを扱ったので、進捗状況の測定は対象としませんでした。
    代わりに、どのくらいのアウトプットしたのかを「測る化」するべく、カンバンのチケット数と、コード量を計測することにしました。
    コード量の測定は、以下のようにgit logコマンドをリポジトリ(ブランチ)別に、プロジェクトの期間(--since,--until)を指定して実行する形で行いました。
    ただしそれだけだとフレームワークや外部ライブラリのコード量もカウントされてしまうので、該当する箇所のディレクトリまで指定したコマンドを合わせて実行してその分を差し引く形にすることで、実際に記載したコード量だけをカウントするようにしました。

    # コード行数をカウント(全行数,追加行数,削除行数,総更新行数)
    git log --numstat --pretty="%H" --no-merges --since= <sincedate> --until= <untildate> --author="" <branch> <directory> | awk 'NF==3 {plus+=$1; minus+=$2} END {printf("%d,+%d,-%d,%d", plus-minus, plus, minus, plus+minus)}'> output.csv
    # コミット回数をカウント
    git log --pretty=oneline --no-merges --since= <sincedate> --until= <untildate> --author="" <branch> <directory> | wc -l | awk '{printf "," $1}'>> output.csv
    # ファイル数をカウント
    git ls-files  | wc -l | awk '{printf "," $1}'>> output.csv 
    

 

「測る化」した結果

「QCD+S」の軸で3プロジェクトの「計る化」を行って以下のような数値がまとまりました。

f:id:oshima106:20180309192213p:plain

こうして得られた数字に対して、それぞれの指標を掛け合わせた係数を算出することでプロジェクトのコンディションを定量的に評価する基準値としていけるのではないか、と考えています。

f:id:oshima106:20180309193425p:plain

気をつけたこと

  • はじめに自分でやってみる
    こういった取り組みをする上で、現場のプロジェクトリーダーの協力は不可欠でした。
    開発業務に専念したい現場になるべく負荷を掛けずに実現するために、PMOである自身が先行して小規模なプロジェクトを対象に取り組んでみて成功イメージを作ることで、分担して現場にお願いするところとそうでないところを切り分けることができました。
  • 正確性の追求よりも早期実現を重視
    いわゆるスモールスタートというわけでもないですが、まず運用をはじめてそこから改善していければいいと考えて取り組みました。例えば今回初めて取り組んだファンクションポイントの計測では、完璧を求めて粒度を細かくしたり複数名でチェックして正確さを担保するといったことは避けて、「1時間で行える範囲で算出する」という取り決めで簡易的に行いました。コード量についても同様で、厳密に全てのライブラリ部分を除外したカウントするようなことはせず、おおよその規模感を出すことを優先しました。
  • 異なるサービスのプロジェクト間での横比較は行わない
    「測る化」をして数値が「見える化」されると、どうしてもそれを比較したくなってしまいます。
    しかし、プロジェクトごとのシステムを構成する言語・フレームワークミドルウェアだけでなく、関連する事業のステージやステークホルダー、サービスの特性も異なるので、横比較してもほとんど意味がないと考えています。従って比較は同じ事業/サービスや、時間軸で連続性のあるプロジェクト同士でのみ行うものとしました。(例えば、一連のプロジェクトのフェーズ1とフェーズ2で比較するなど)
    これまでのプロジェクトを遡って「測る化」は行っていないので今は比較対象がなく、今回を起点にして今後の比較基準に活用できればと考えています。

まとめ

簡単ですが、プロジェクトの「測る化」を実践してみた事例のご紹介でした。
書籍にならうともっと緻密に、様々な切り口での「測る化」の観点がありましたが、あくまで目的としてはプロジェクトのコンディション把握と改善であり、さらにはいかに価値のある開発を行うかということを忘れずに今後も継続していければと思っています。

新卒での1年間を振り返ってみて

昨年の4月に新卒で入社したエンジニアの吉田です。入社してあっという間に1年が経とうとしています。
入社前と入社後で感じた違いをまとめていきたいと思います。

入社の経緯

学生時代は専門学校で、Webデザインの勉強をしていて、Webサイトの企画からデザイン、実装までの技術を学んでいました。授業では、上流工程を学ぶことが多く、実装はフロントエンドの実装がメインでした。
授業外の活動で、2年連続で技能五輪Webデザイン職種に出場しました。技能五輪に出場したことで、授業ではほとんど勉強していない、サーバーサイドの技術を学びました。
企画からデザイン、サーバーサイドからフロントエンドまでの技術を競うので、Webに関わる技術に一通り触れることができました。
最初はフロントエンドエンジニアを目指していましたが、技能五輪でサーバーサイドの技術にも触れたことで、サーバーもフロントも楽しいと思い、どちらも挑戦することができる会社で働きたいと思っていました。
ウィルゲートを決めた理由としては、メディアの企画を行う部署と、開発サイドの距離が近く、話し合いながら実装しているのが良いなと感じ入社をしました。企画などの上流工程を学んでいたので、そちらにも興味があり、どちらにも関われるチャンスがあるというのがすごく魅力的に感じました。

普段の業務

普段の業務では、Millyの機能開発と運用保守を行なっています。サーバーサイドもフロントエンドも同じくらいの割合で開発を行っています。

Millyはウィルゲートで運営している、子育てを行なっている母親向けのメディアです。

millymilly.jp

学生時代との違い

学生時代は、1人での開発か、デザイナーと2人での開発で、自分がわかれば良い実装で、ローカル環境で開発していくというスタイルで開発を行っていました。しかし、入社すると複数のエンジニアでのチーム開発になり、サーバーが与えられ、新しいツールを使い、実装の規約が決まっていて、と全く違う環境での開発でした。技術面では技能五輪を経験したこともあり、なんとかついていけたのですが、環境面の違いに最初はかなり戸惑いました。

Git

学生時代ではGitを使ってのチーム開発を行ったことがありませんでした。軽く触ったものの、必要性を全く感じず使わずに作業を行っていました。なので入社した時は、ブランチ?コミット?プッシュ?という状況だったので、Gitの仕組みや操作を覚えるのに苦労しました。ブランチの仕組みを理解できず、別のブランチにプッシュしてしまったり、ミスをしながら作業していました。
そんな私でしたが、Gitを使っていくうちに仕組みが理解できてきたのと、社内でGitの勉強会があり徐々に理解することができました。

コーディング規約

cssのクラスの命名規則や、余白の取り方まで規約として決まっており、規約を守って実装していくというのに慣れるのも時間がかかりました。規約を読んだり、プルリクにコメントをもらったり、他の人のプルリクを見たりしながら規約を学んでいました。
規約通りの開発に慣れてくると、他の人が作った部分を読むことができるようになり、技術の理解も深めることができました。
最初は、覚えて実装していくのが大変だなと感じていましたが、規約を守っていれば保守性が高いソースコードにすることができました。

サーバー

ウィルゲートの開発環境は、1人1台の専用の仮想サーバ環境が整備されていてそこで開発を行っていきます。これまではローカルでの開発だったので、ターミナルでsshで繋いで...と、コマンドを覚えるのに苦労しました。コマンドはよく使うものについては覚えてきて操作することがきるようになりました。
さらに、鍵認証の仕組みも分からず、毎回パスワード入力を行っていたのですが、最近、鍵認証で入れるようにしたら簡単にサーバーに入れるようになり、感動しました。

ツール

フロントエンドの実装を行っていく際に、Zeplinというアプリを使用してデザインからHTML・CSSに落とし込んでいきます。余白の取り方や、カラーコードなどが簡単に確認できるのでPhotoshopで余白やカラーコードを確認するのに比べて何倍も早く実装することができました。
学生の頃に知りたかったです。

まとめ

チームで開発することに慣れてきた1年でした。知らないことばかりで入りましたが、先輩方にたくさん教えていただき成長することができました。
gitや規約など学生時代から挑戦しておけばよかったかなと感じています。そこの知識を得るための時間を技術の習得の時間にあてられたらと思ってしまいます。
下半期では、テストコードやDocker、Vue.jsといった技術に挑戦する機会をもらえたので、技術面でも新しいことに挑戦していきたいです。

Laravel で Amazon DynamoDB を利用するための実装 tips 集

ウィルゲートで開発を行っている岡田 (okashoi) です。

私の所属するソリューションチームでは web コンサルティングのためのシステムの開発を行っています。

現在開発中のプロダクトにおいて Amazon DynamoDB (以下、DynamoDB)を利用しており、 Laravel で DynamoDB を利用する際の実装上の tips が貯まってきたので紹介していきたいと思います。

DynamoDB 概要

DynamoDB は KVS と ドキュメント指向データベースの両方の特徴を併せ持ったデータベースサービスです。

概要は以下の通りです。

用途

  • 基本的には KVS のような使い方
  • 加えて、あらかじめ決めておいたカラムでの範囲検索ができる

メリット

  • レスポンスが安定して速い(KVS の利点)
  • 柔軟・スキーマレス(ドキュメント指向データベースの利点)
  • アプリケーション側だけ考えれば良い(フルマネージド)
  • ストレージに上限がない
  • 自動的にスケールさせることができる

デメリット

  • 決められた方法での検索しか出来ない
  • 特性を把握しないとうまくスケールしてくれない
  • トランザクションはない

より詳しい話については他の多くの方が資料や記事を公開しているのでそちらに譲ります。

以下、 tips を紹介していきます。

ORM には laravel-dynamodb を利用

Laravel といえば Active Record パターンの実装である Eloquent ORM を特徴として挙げる方も多いでしょう。

この Eloquent ORM とほぼ同様のインターフェースを、DynamoDB 用に提供しているのが baopham/laravel-dynamodb です。

github.com

packagist での人気(Installs, Stars)などから、私たちのプロダクトではこの laravel-dynamodb を利用することにしました。

例として DynamoDB 上に Movies というテーブルがある場合、以下のようなモデルを定義しておくことで App\Models\Movie::create() でレコードを作成したり、 App\Models\Movie::find()App\Models\Movie::get() を使ってデータの取得が行うことが出来ます。

<?php

namespace App\Models;

use Baopham\DynamoDb\DynamoDbModel as Model;

class Movie extends Model
{
    protected $table = 'Movies';

    protected $primaryKey = 'year';

    protected $compositeKey = ['year', 'title'];

    public $timestamps = false;

    protected $fillable = [
        'year',
        'title',
        'info',
    ];
}

Model の使い方としては以下を押さえておくと良いと思います。

  • 基本的に Eloquent Model と互換がある(Eloquent Model を継承しているため)
    • できるからと言って何でもかんでもやるのはよくない
  • $fillable なども記述する必要がある
    • デフォルトで $incrementing = false の上書きだけされている
  • テーブルの Key を明記する必要がある(Hash Key 名前が id の場合は $primaryKey は省略可)
<?php

    // Hash Key のみの場合
    protected $primaryKey = 'hash_key'

    // Hash Key + Range Key の場合
    protected $primaryKey = 'hash_key';
    protected $compositeKey = ['hashKey', 'rangeKey'];
  • Index(GSI, LSI)についても明記する必要がある
<?php

    // GSI , LSI ともに $dynamoDbIndexKeys に書く
    protected $dynamoDbIndexKeys = [
        'index_1_name' => [
            'hash' => 'index_1_hash_key_name',
        ],
        'index_2_name' => [
            'hash' => 'index_2_hash_key_name',
            'range' => 'index_2_range_key_name',
        ],
    ];

より詳しい使い方は README を読みましょう。

ちなみに、Model 内部の実装はこちらです。

laravel-dynamodb/DynamoDbModel.php at master · baopham/laravel-dynamodb · GitHub

使っているときに迷ったり、疑問に思ったりしたら実装を読んでみるのも良いでしょう。

マイグレーションRDBMS と区別しない

以前 Qiita にも投稿したのですが、RDBMS 用のマイグレーションと同じ場所に DynamoDB のマイグレーションも書いています。

qiita.com

理由も Qiita に書いた通りで「DynamoDB のテーブル管理のために特別なオペレーションを増やしたくない」に尽きます。

具体的には以下のようなコードになります。

<?php

use Illuminate\Database\Migrations\Migration;
use BaoPham\DynamoDb\DynamoDbClientService;

class CreateDynamodbGaTrafficRecordsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        // テスト時には DynamoDB を利用しない
        if (app()->environment('testing')) {
            return;
        }

        $params = [
            'TableName' => $this->getTableName('Movies'),
            'KeySchema' => [
                [
                    'AttributeName' => 'year',
                    'KeyType' => 'HASH',
                ],
                [
                    'AttributeName' => 'title',
                    'KeyType' => 'RANGE',
                ],
            ],
            'AttributeDefinitions' => [
                [
                    'AttributeName' => 'year',
                    'AttributeType' => 'N'
                ],
                [
                    'AttributeName' => 'title',
                    'AttributeType' => 'S'
                ],
            ],
            // キャパシティユニットは仮の値を入れておくだけ
            'ProvisionedThroughput' => [
                'ReadCapacityUnits' => 5,
                'WriteCapacityUnits' => 5,
            ],
        ];

        resolve(DynamoDbClientService::class)->getClient()->createTable($params);
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        // テスト時には DynamoDB を利用しない
        if (app()->environment('testing')) {
            return;
        }

        $params = [
            'TableName' => $this->getTableName('Movies'),
        ];

        resolve(DynamoDbClientService::class)->getClient()->deleteTable($params);
    }

    /**
     * 環境ごとのテーブル名を取得
     *
     * @param string $tableBaseName
     * @return string テーブル名
     */
    protected function getTableName(string $tableBaseName): string
    {
        // 環境名を Suffix として追加する(理由は後述)
        return studly_case($tableBaseName) . studly_case(app()->environment());
    }
}

コード中のコメントにも記載したとおり、キャパシティユニット(以下、CU)に関しては、テーブル作成時は仮の値(最小の 5 とか)を入れておき、あとから管理コンソール上で値を更新するようにしています。

CU は環境(本番/ステージングなど)によって変わるうえに、運用の中で変化していく値でもあるため、マイグレーションで管理する必要性が薄いことが理由です。

また、マイグレーションに関しては他のパッケージの利用も検討しましたが、それぞれ以下の理由で採用を見送っています。

環境をまたいでテーブル名を一意にする方法

運用に際して「テーブル名は本番環境・ステージング環境をまたいでを一意にしなければならない」という問題に後から気が付きました*1

これについてはテーブル名の suffix として環境名(APP_ENV の値)を付与することで解決しました。

今まで Movies という名前のテーブルだったのであれば、本番環境なら MoviesProduction に、ステージング環境なら MoviesStaging に、といった具合です。

先述のマイグレーションgetTableName() メソッドが登場したのはこのためです。

Model が参照するテーブルも環境ごとに変える必要もあるわけですが、これは getTable() メソッドをオーバーライドすることで解決しました。

<?php

namespace App\Models;

use Baopham\DynamoDb\DynamoDbModel as Model;

class Movie extends Model
{
    // (略)

    /**
     * テーブル名を取得
     * 環境ごとの suffix を付ける
     *
     * @return string
     */
    public function getTable(): string
    {
        $baseTableName = parent::getTable();
        return $baseTableName . studly_case(app()->environment());
    }
}

複数の Model で DynamoDB を使うのであればこの getTable() は Trait に切り出してしまうのが良いでしょう。

APP_ENV が衝突する複数の環境が存在する場合は、各々の事情に合わせて一意になる suffix を付けてあげましょう。

その他細かな tips など

find() は強い整合性での Read しかできない

Qiita に書いてあります。

qiita.com

Range Key での BETWEEN 条件を指定する際は where($rangeKeyName, 'range', [$min, $max]) を使う

こちらも Qiita に書いてあります。

qiita.com

バッチ処理などのリアルタイム性を求められない Read/Write を大量に行うときには retry() と併用する

Laravel のグローバルヘルパ retry() と併せて使うことで「CU 超過していたら 1 秒待ってもう一回リクエスト」というロジックをシンプルに書くことができます。

<?php

$movies = collect([]);
foreach ($conditions as $condition) {
    // キャパシティユニット超過の場合、再リクエスト(ウェイト1秒)
    $tmpMovies = retry(2, function () use ($condition) {
        return App\Models\Movies::where('year', $condition['year'])
            ->where('title', $condition['title'])
            ->get();
    }, 1000);

    $movies = $movies->concat($tmpMovies);
}

// $movies を用いた処理
// :

このような書き方は、大量に読み書きをする必要がある代わりに、リアルタイム性が求められないバッチ処理において活用する方法があります。

CU を低めに設定してあると、そのCUをいっぱい使い切る速さで読み書きの処理が進みます*2

実際に試した場合の様子がこちらです。

f:id:okashoi:20180227154331p:plain

21:00~00:00 の間、消費 CU がプロビジョニング済み CU 付近に張り付いているのがわかります。

なお、一時的にプロビジョニング済みの CU を越えているのは、過去300秒分は未使用の CU を持ち越せる(バーストキャパシティ)ためです。

この方法は、同じテーブル(または GSI)に対して並列で読み書きが動いているとうまくいかないかもしれません。

おわりに

以上、 Laravel で DynamoDB を利用する際の実装上の tips でした。

今後もこのような tips ・ノウハウは貯まっていくと思うので、DynamoDB に限らず紹介していこうと思います!

*1:本番環境とステージング環境でリージョンが異っていれば問題ない

*2:ただし、1回の読み書きで超過してしまうくらい低い CU では動きませんが

【スライドあり】勉強会「【PHP事例】プロダクトをレガシーにしないために闘う現場のリアル」を開催しました!

こんにちは。ウィルゲートで開発を行っている池添です。

先日、2月16日に「【PHP事例】プロダクトをレガシーにしないために闘う現場のリアル」という勉強会をウィルゲートのオフィスを使って開催させていただきました!

connpass.com

今回の勉強会は、ランサーズさん、うるるさんと合同で発表させていただき、各社のプロダクトをレガシーにしないための取り組みを発表してもらいました。

ウィルゲートからは私が「PHP5.3からPHP7.0へバージョンアップの裏側」というテーマで発表させていただきました。

speakerdeck.com

勉強会中の様子

開始直前の様子 f:id:zoe302:20180222144411j:plain

株式会社ウィルゲート f:id:zoe302:20180222142250j:plain

株式会社うるる f:id:zoe302:20180222142528j:plain

ランサーズ株式会社 f:id:zoe302:20180222142808j:plain f:id:zoe302:20180222143548j:plain

懇親会・LT中 f:id:zoe302:20180222150510j:plain f:id:zoe302:20180222145436j:plain

感想

各社プロダクトの規模も長さも違いますが、プロダクトの成長を止めないためにレガシーにさせないようにしたいという思いは一緒でした。

サービスの規模や特徴によって一部を先に載せ替えたり、いったん機能開発を止めてでもバージョンアップをしたりと、バージョンアップのための具体的な進め方は違いましが、できるところから少しずつ進める、より多くの人の助けを得ながら進める、という点は共通していました。

ウィルゲートでは今後も、勉強会やイベントを開催していきますので、今後もお楽しみに。

社内ネットワーク大改革! オフィス全面フリーアドレスまでの道のり

はじめまして、インフラチームの内田です。主に社内ネットワークを担当しています。
ウィルゲートは2017年5月にオフィスを移転し、スペースの有効活用とコミュニケーションの活性化を目的に「フリーアドレス」を導入しました。
この時に行った大幅な社内ネットワークの変更事例についてご紹介します。
同じ事例などでお困りの際、少しでも参考になれば幸いです。

 

移転前のネットワーク状況

プロバイダ数最大6つ!

移転前にはプロバイダを最大で6つ契約しており、このうち2つが固定IP用、残りの4つが社員や来客者用の回線として利用していました。
帯域を考慮して部署ごとに回線を分けてインターネットへ接続を行っていたため回線契約がこんなに多くなってしまい、
なかにはマンションタイプなどの業務用途ではない物もあったために通信速度にも差がありました。

そして組織変更や異動等に合わせて社内の席替えを行う時、机や人の配置状況によっては床下の配線をたびたび直すことがあるので、
席替えにあわせて床のカーペットやブロックを剥がしてLANケーブルの配線をやり直すなど、作業的には結構な負担になっていたのを覚えています。

有線LANと無線LAN

社内ではファイルサーバやプリンタ等の共有物も含め、もともとは全て有線LANでネットワークに接続されていました。
そこに「来客者もインターネット接続できる環境が欲しい」という要望があがり、ゲスト用の無線LANが後から追加されることに。

その際に来客者セグメントを分割し、来客者が社内ファイルサーバ等にアクセスできないように制限するなど、セキュリティを担保しつつ、
認証方式もWPA2-PSKという一般的なID/Password認証を採用し、定期的にパスワードを変更する運用を行っていました。

しかし社内にノートPCの利用者が増えてきて無線LANのニーズが高まり、いつしか「普段は無線LAN、ファイルサーバなどに用がある時は有線LANに接続」のような使われ方が普及し始めていました。

 

オフィス移転に向けて

移転後のネットワーク要件

大きく分けて3つの要件が挙がりました。

  • フリーアドレスを導入、全面的に無線化。
  • 通信速度は移転前と同じ程度の速度を維持、業務に支障のないように。
  • ファイルサーバ等へのアクセスは社員のみ可、ゲストはインターネットのみ利用可。

フリーアドレス、通信速度に関しては要件に応えられるアクセスポイントや回線を用意すれば良い話なのでそれほど難しい話ではありません。
ですが、3つ目のアクセス制限は有線LANと無線LANで用途を分けていたから容易に実現できていたものの、無線LANのみの場合オフィスビルの外にも電波が飛ぶため物理的な制限は出来ません。
どのようにして社員と社員以外を区分するのか考える必要がありました。

 

フリーアドレスに向けて思ったこと

正直なところ、全面的にネットワークを目視できない物に変えていくのは恐怖でした。
今までネットワークの不具合が起きた時にどこが悪いのか物理的に確認できて分かりやすかったのですが、無線ではそうは行きません。

しかし床下配線などの作業から解放されるとともに、何よりも自分の手で社内ネットワークを再構築出来るという所にモチベーションが上がりました。
またオフィス移転自体が滅多にあることではないのでいい機会と捉え、さらにプロバイダの見直しやネットワーク上の問題点を解消させたいと考えました。

 

社内NW構成変更

1. プロバイダ見直し

とりあえず6回線もあるプロバイダを見直すところからはじめました。
基本的には今までと同じように社員用・ゲスト用の2回線に限定し、それ以外は廃止。
加えて社員用の回線は可能な限り広い帯域の物を用意し、通信速度の低下を避けるため2GBの回線を用意しました。

また移転後は全面的に無線化されるため、オフィス内外の電波干渉についても考慮しました。
ネットワークが不安定になることを回避するため、社員用は5Ghz、ゲスト用は2.4Ghzと棲み分けさせます。

2. マルチSSIDとVLANで社員用・ゲスト用を分割

移転後は社員用・ゲスト用ともに無線LANとなるため、何らかの形で明確に分けておく必要がありました。
しかし社員用・ゲスト用毎にアクセスポイントを用意すると台数が2倍になり、管理コストが跳ね上がります。

そこで1つのアクセスポイントに2つのSSIDを割り当てるマルチSSIDを採用し、VLANによって仮想的にセグメントを分割。
さらにL3スイッチとルータで、VLAN毎に利用する回線を分けるように設定しました。

3. PoEを活用、アクセスポイントを天井に

移転前はコンセントから電源を確保してアクセスポイントを窓際等に設置していましたが、知らないうちにLANケーブルやコンセントを抜かれていた事もありました。
そこで移転後はアクセスポイントを天井に設置、オフィス内全体に無線が行き届くような場所に設置。
電源についてはLANケーブルを通じて給電できるPoE対応のアクセスポイントとハブを用意することで解決しました。

 

f:id:uchida-yuya:20180221161011j:plain

このように(人の手の届かない)天井に設置しています。
アクセスポイントには天井裏から伸びているLANケーブルが1本だけ繋がっており、PoEで電力を供給しています。

4. ルータ・PoEハブ・アクセスポイントのメーカーを統一

もともとルータはYAMAHA製品を使用しており、アクセスポイントには当初はBUFFALO製品を検討していました。
しかし機器の選定を続けていくうちに、ルータ・PoEハブ・アクセスポイントを同じYAMAHA製品で統一するとGUI上でアクセスポイントの設定や管理を行えることが分かりました。
かなり使えそうな手応えがあったため統一します。
実際使ってみた感想としてはかなり便利で、視覚的に社内ネットワークを管理出来るようになっています。

5. 無線の認証方式・WPA2-EAPでActiveDirectoryと連携

移転前は無線LANの認証方式にはWPA2-PSKを利用していました。
しかしそれはゲスト用の回線だったからこその運用なので、社員用のネットワークが無線となるとパスワード漏れの危険性が上がります。
退職者が出たらその都度パスワードの変更が必要となる等、管理上の問題が多数見つかったのでWPA2-PSKは廃止。

それでは何を認証情報に使おうかと考えた末に、社員のアカウントや端末を全て管理しているActiveDirectoryを利用出来ないかと考え、
アカウント情報と証明書のセットで認証を行うWPA2-EAPという方式を採用しました。

まずActiveDirectoryに認証サーバ(RADIUS)の役割を追加し、グループポリシーによって証明書を各端末に配布するように設定しました。
これによって、管理下の端末及びアカウントには配布された証明書を使用して認証を行い、社員用の無線LANに接続出来る状態が実現できます。
逆に、社内で管理されていない端末には証明書が配布されないので社員用の無線LANに接続が出来ません。
また退職者などActiveDirectory上にアカウントが無い場合も認証が通らず、社員用の無線LANに接続出来ないようになりました。
無線LANでもかなり強固なセキュリティ体制をつくる事が出来ました。

6. SPOFの解消、L3スイッチの冗長化

移転前はルータとL3スイッチは共に1台ずつしかなく、このどちらかが壊れた時点で社内のネットワークが停止する状態となっていました。
いわゆるSPOF(単一障害点)です。

このリスクを避けるため、まずはL3スイッチの冗長化から行うことにしました。
L3スイッチを2台新たに用意してVRRP設定によって冗長化を実現、1台が壊れたとしてもネットワークが停止する事態は発生しなくなります。

f:id:uchida-yuya:20180221161007p:plain

現在のネットワーク構成を簡単に図解したものがこちらになります。

L3スイッチについては冗長化出来ましたが、残念ながら時間の都合上ルータの冗長化は後日に見送られることになりました。

 

いざオフィス移転

移転完了、想定通りの挙動 と思いきや・・・

オフィス移転そのものは問題なく完了しました。
今回始めて導入したマルチSSID及びVLANも想定通りに稼働、社員用とゲスト用でネットワーク及び回線も分かれていました。
WPA2-EAPも順調で、社員は社員用ネットワークに接続できており、ゲストは社員用ネットワークに接続できていない状態でした。
想定していたとおりに動いてくれたので、とりあえず一安心したのを覚えています。

一安心していたのですが、直後に通信速度が極端に遅いという問題が発生しました。
しかし調査開始とともにすぐさま原因は判明、アクセスポイントのファームウェアが最新の物ではありませんでした。
ルータ等のファームウェアは更新しておいたのですがアクセスポイントだけすっかり忘れていました・・・更新したら無事直りました。

今度は瞬断が頻発

通信速度は改善されたのですが、今度はネットワークから瞬断されるクライアントが多数発生。
ログをチェックすると「PMKcacheの有効期限が300秒で切れました」というメッセージが頻発しており、アクセスポイントとクライアント間の接続が5分間隔程度で切断されていることが確認できました。
PMKcacheとは一度認証に成功したことをアクセスポイントにキャッシュとして持たせておき、有効期限内の再接続時に認証を省略させる機能です。
アクセスポイントの設定ではキャッシュの有効期限を12時間としているのですが一向に反映されません。

ひとまずメーカーに問い合わせしたものの、有効な回答を得られませんでした。
そこで認証サーバでキャッシュの有効期限をデフォルトから12時間に修正したところ、アクセスポイントにも設定が反映されて瞬断が起きることはなくなりました。

なお、後日メーカーからファームウェアに存在していたバグだったと回答を頂き、後に解消されたファームウェアが配布されていました。

またも瞬断が頻発、今度は何が悪いのか

5分間隔で瞬断される事象は解消されたにも関わらず、場所によっては変わらず瞬断されてネットが途切れるという人が発生していました。
もう一度ログを良く見てみるとDFSという単語が頻出しており、その直後にチャネルが強制変更されていることが分かりました。
DFSとは気象レーダーなどの電波と干渉してしまった際にチャネルを強制的に変更する機能です。
どうやら5GhzのW53,W56帯域は気象レーダーと競合してしまう帯域らしく、そこでチャネルが変わり切断されていたことが分かりました。

5Ghzの無線LANは通信速度の低下を避けるために5GhzはW52・W53・W56の帯域を利用して広いチャネル幅を確保していましたが、これが返って仇になったようです。
W53,W56帯域はチャネルが変更の度に瞬断されてしまうので、アクセスポイントの帯域をW52の中だけに変更。
かつオフィス内でチャネルの競合が起きないようにW52内でうまく再設定した所、瞬断騒動は収まりました。

現在は落ち着いて稼働中、ようやく一段落

色々と問題は起きてしまいましたが、現在では安定して稼働しています。
やはり有線LANから無線LANへと移行する上で原因追求の難易度や慣れてない作業などが多数ありましたが、それでも色々勉強になりました。
特に無線に関する技術や知識を多く学べました。

またフリーアドレスのおかげでオフィス内の配線はほぼなくなり、回線の数だけあったONUの数を減らすこともできたりオフィス内のどこに行ってもネットワークに接続できるようになったりと、いい感じに構築できたかなと実感しております。
まだルータの冗長化が残ってるので、準備ができ次第取り掛かりたいと思います。

「Comfortable development / 2.0」チーム目標に対する取り組み

 こんにちは。サグーワークス開発チームの横道です。

 

弊社では毎年半期に一回、チーム目標設定をしていて

その目標に対して色々取り組んできたので複数回に分けて紹介したいと思います。

 

f:id:m_yokomichi:20180215185907j:plain

目標自体はチームメンバー全員で決めており

この半年で取り組んでいきたいことや、変えていきたいことをブレストで出しあい

みんなの意見をまとめて目標にしています。

 

そこで決まった2017年度下半期(9月~3月)の目標が

タイトルに記載している「Comfortable development / 2.0」でした

 f:id:m_yokomichi:20180215185924j:plain

 

目標の意味は

サグーワークスがリリースされてから5年経ち

デザインリニューアルや市場の変化に対応するための機能拡張を重ねるうちに開発しづらい箇所や使われなくなった箇所が残っていたりしています。

全体的に見直して開発を取り巻く環境を今より1段階上げて

開発をより快適にすることで開発速度を向上させようとなりました。

 

-----------------------------------------------------

Comfortable:快適な・居心地の良い

Development:開発

2.0:バージョン2.0

=快適な開発環境にバージョンアップする

-----------------------------------------------------

 

この目標に向けてやってきた取り組みを

少しずつ記事にしていくのでお楽しみに!

【スライドあり】勉強会「【PHP7 実践編】事例で学ぶ CakePHP と Laravel の徹底比較」を開催しました

こんにちは。ウィルゲートで開発を行っている岡田です。

先日、1月25日に「【PHP7 実践編】事例で学ぶ CakePHP と Laravel の徹底比較」というタイトルの勉強会を開催いたしました。

同じ内容の勉強会を昨年の9月にも開催しており、スライドも公開したところ好意的な反応を多くいただいたので、再講演させていただくことになったのが今回の背景です。

www.slideshare.net

※スライドのタイトルは昨年に開催したときのものです。SlideShare は後からスライドを更新できないのを初めて知りました。。。

スライドだけでも内容が分かるように作ったつもりなので、具体的な内容はスライドを見ていただければ、と思います。

このスライドで伝えたかったことは最後の1枚にまとまっています。

f:id:okashoi:20180126143814p:plain

こういった特徴を把握したうえで、サービスやチームに合わせた選択をしていけるといいですね!

ウィルゲートでは今後も様々な勉強会・イベントを開催していく予定なので、今後もお楽しみに!