投稿者「adachin」のアーカイブ

Lancers Tech Nightの取り組みとは!?

adachin|2019年12月03日
イベント/登壇

ランサーズ Advent Calendar 2019 3日目の記事となります。

SREチームの@adachin0817です。最近はTerraformやったりAWS Fargateに挑戦してます。あっという間に2019年も終わりですね。皆様は今年の目標など達成できましたでしょうか!私はリバウンドしてしまったので来年は気合い入れて別人になろうと思います。さてさて今回は「Lancers Tech Night」という社内エンジニアイベントついてご紹介できていなかったので、雰囲気や取り組みについてブログできればと思います。

Lancers Tech Nightとは

ランサーズをテックカンパニーにしたいため、お昼は「Lunchers(ランチャーズ)」という外部のエンジニアさんをお呼びしてLTしながらランチを食べるというイベントを定期的に行っています。(以下アーカイブを参考に)

https://engineer.blog.lancers.jp/category/event/lunchers/

また、「Lancers Tech Night(ランサーズ テック ナイト)」では不定期で社内のエンジニアをランダムで選び、金曜日にLT大会を実施しています。目的としては以下の3つになります。

  • ランサーズをテックカンパニーにするため
  • エンジニア同士のコミュニケーション活性化
  • 技術のシェアにより技術力アップ

前回の様子(2019/07/12)

技術的なお話から、マネジメントまで内容は幅広く、普段業務では見れない姿を見ることができました。
そして先月行われたLancers Tech Night #2についてレポートもしてきましたので以下ご覧になってみてください!
※一部資料は公開していないものもありますのでご了承ください


Lancers Tech Night #2

reactとreduxを使った簡単なアプリ作りました
@Kakki0310

構成について紹介
・TypeScript
・jsしか使ってない
・mainのコンポーネントは管理画面全体の部分
・reduxまで表示させる
・実際にpostを作るには
・formをreactの形式を使っている
・投稿ボタンと2つのフォームがある
・post.jsでそれぞれの関数を定義して、どういうアクションが行われたのかを組み込める
・delete postは投稿を削除している。
・この形はランサーズでも使われている
・reactはCakePHPのctpファイルの表側のようなイメージ
・reduxは裏側の処理をしているイメージ

増税対応開発の教訓
@吉本くん

技術よりも個人の反省点
・日付が考慮されていない
・税率はconfig設定
・増税対応って?
・税を扱うクラスを作成
・日付を元に税率を算出
・税率、日付はprivate
・これにより呼び出し元の全差し替えができる

起こったこと
・対応漏れによる不具合
・振込手数料のタイミング、表示上の金額ずれ
・仕様による不具合など

原因
・ロジックの分散
・規模が大きい
・手数料の計算メソッドの分散
・漏れが発生する、テストしにくい
・既存に継ぎ足し
・既存メソッドに振る舞いを追加
・個別最適
・複雑テスト漏れ
計画変更
・複数のマイルストーンごとに異なる税率
・後片付け漏れ
・差し替え対応引数なしでも動作するnull許容
・日付必須でも $date = null
・一つのズレで一日コミュニケーションしながら進めるので気をつけないといけない

学んだこと
・システム全体において、結合テストしたがエラーの見逃し
・コードで保証ができることをしないといけない
・既存に追加する形でも考えて作り直さないといけない
・未使用変数がバグに繋がっているなどを学んだ

最近やっていること
・PHPによるデザインパターンをやりなおしている
・クラス、依存関係
・Clean Architecture
・SOLID原則
・DI依存関係の逆転
・一方向の依存性

やってみたいこと
・クリーンアーキテクチャ実践 Go
・マイクロサービス
・フロントアーキテクチャ Flux

ドメイン駆動開発の手法をかじった上でLでざパターンについて考える
@manamin0521m

導入
・増田論
・DDDのイベントもある
・メリット
・どのようにロジックが書いてあるか明確
・影響範囲を特定のドメインオブジェクトやパッケージに閉じ込めやすくなる
・三層の記述が完結でわかりやすくなる
・View Controller Model

ドメインとは
・概念である
・概念はオブジェクトの集合体である
・レンタル料金の計算
・before ビジネスルールが見えない
・after classが増える
・流れが見やすい

詳細
・業務の関心事をヒト・モノ・コトいう3分類に分ける
・業務の関心事にドメインを切る
・画面やデータベースの都合からは独立して、業務ロジックを整理
・良くないコードだと?
・判定のロジックが複数のclassに重複してしまう
・1つ変更するのに全部変えないといけない
・画面やデータベースの影響範囲が大きくなる
・バグなどが起きるので、テストが必要

Lデザインパターン(Lancersデザインパターン)
・肥大化したモデルの責務を分けるため
・コードを実務のサービス文言にしている

詳しく
・細かくオブジェクトを作ると、条件分岐や前提条件をコントローラーで書かなくてよくなる
・役割は入出力のみに集中できる
・一方、現状だとテーブルとオブジェクトが一対一のものがほとんどで、各テーブルを細かく区切ったり
・テーブル同士をまとめるという作用が強くなっている

発展
・DDD化するには
・値オブジェクト (Value)
・コレクションオブジェクト(配列)
・区分オブジェクト(条件分岐)

まとめ
・設計に時間がかかるけど

・拡張しやすく、ミスが起こりにくい
・詳しい人が土台を整えてからじゃないと取り掛かるのが難しいけど
・ドメインオブジェクトが増えてくるとやりやすくなりそう
・既存の大量のコードと両立させるのが難しいけど
・コアなドメインから少しずつやっていくと良さそう

僕が作りたい世界と現状の問題点
@0xb5951

方向性
・どうやって体をなくしていくか
・最近の熱い話
・この世界めんどくさい
・やりたいことはいっぱいある
・時間が足りない
・寿命を延ばしたい
・強いタンパク質を作る
・ペインは解決されない

Human Augmentation
・ハードウェアで実現する
・ソフトウェアで実現する
・体の機能を切り出す
・思考パターン、声、目、手など
・切り出した機能にスパイスをかける
・他人の思考パターンと混ぜてみる
・喉の発生域を超えた領域での声
・人間にフィードバックする
・体を空間に溶かす
・瞬間移動もできる

熱い例
・HADO
・ARスポーツ
・ゴーストエンジニアリング
・IOA
・テクノロジーやメディアは人間の体の拡張である
・マーシャル・マクルーハン
・問題はかなり多い
・ゴーストをどう管理できるか
・広義での精神体
・攻殻機動隊に近い

自分の形をどうやって保つか
・サルトル
・実在は本質に先立つ
・ソフトウェアの重さをどうやってなくすか
・物理的な依存点が存在する

ER図について実際に考えて作ってみる
@sayanet

マリオーカートのER図について考える
・ランチをER図おもしろい取り組み
・エンティティロード湿布
・ランサーズのER図考えるの面白そう
・人によってやり方は違う
・必要な要素をピックアップ
・マリオーカートのランキングを取りたい
・ホワイトボードでやるといい
・不要なものを削除する
・ビデオ屋だとどんなER図が作れるのかみんなで考えてみよう

社内LANで学ぶネットワーク / 将棋のAIの歴史
@yakitori009

社内LAN MAPの共有
・各ポートのタグVLAN割り当て
・経路制御(ルーティング)

MAC(Media Access Control address)アドレスとは
・ネットワーク機器のハードウェアに一意に割り当てられる物理アドレス
・OSI参照モデルの第二層(データリンク層)にあたる

サブネットマスクの仕組み
・IPアドレスからネットワークアドレスを取得するときに使う

プライベートIPアドレスとは
・企業ネットワークに存在する端末が自由に使用できるIPアドレスのこと

コンピュータ将棋の登場と進化
・1980年代 初心者
・1990年代前半 12~14級
・1990年代後半 アマチュア初段
・2000年代 アマチュア2段以上
・各ボードゲームの局面数と強さ
・計算量の削減
・枝切り
・選択的探索手法
・開発者の棋力が反映される

Bonanzaの登場
・DeepBlueのチェスアルゴリズムの論文を将棋に応用
・プロ棋士と初対局(2007年)
・渡辺 竜王の勝利
・Bonanza亜種の登場(2009年)
・Bonanza作者の保木さんがOSSを公開
・ボンクラーズ
・Ponanza

まとめ
・コンピュータ将棋の強さ
・疲れない、間違えない、うっかりしたミスがない
・恐れない、緊張しない

まとめ

長くなりましたが、いかがだったでしょうか!?ランサーズエンジニアの環境や雰囲気など少しでも伝われば幸いです。技術力を高めたいエンジニアが弊社にはたくさんいますし、学びたいと思う方には最高かと思います。今後は他社さんを巻き込んでLT大会などもやっていければと思いますし、少しでもランサーズで働いてみたいと思ったエンジニアさん、ぜひ下記のWantedlyから話を聞いてみませんか!?

8年間お疲れ様でした!社内サーバーをAWSに移行したお話

adachin|2019年09月20日
AWS

みなさんお久しぶりです。SREのadachin0817です。
今回は歴史あるランサーズの社内サーバーをAWSに2ヶ月ですべて移行することができました。

どのような取り組みとどのように運用しているのか、
サーバー触っているエンジニアさんは気になるところだと思うので公開します!

ランサーズ開発環境の歴史

2011年から開発環境がラックサーバーで動いており、VMware ESXiで仮想サーバー構築して検証していたようです。
歴史を感じる…

そこから数年経って、Dockerとなり、現在の開発環境になるわけですが、
この数年で、色んなエンジニアが稼働しているVMにバッチや、
その他ツール等運用していくことで誰が管理しているか分からず、技術的負債や属人化が見えるようになっていきました。

クラウドに移行するメリットとデメリット

以下、移行することのメリットとデメリットを記載してみました。

・年に一回ゴールデンウィーク中に実施される法定停電時のサーバー停止、および起動作業が要らなくなる
・技術的負債をなくせる/整理できる
・運用コスト削減/サーバー電気代0円へ
・SREチームが管理することで属人化がなくなる
・AWSのコストが上がる

では現時点で動いているもので必要なサーバーを洗い出してみました。

・バッチ5つ(シェルスクリプト/PHP)
・社内DNSサーバー
・dev X 10台(新機能確認用コンテナ)
・弥生会計
・社内ツール 1つ(Rails)

バッチ

バッチは本番で運用しているサーバーがあるので、5つを移行するだけでしたが、
シェルスクリプト内でC言語でコンパイルしているものがあったりしてなかなか手強かったのを思い出します。

社内DNSサーバー

こちらはRoute53にすべて移行しました。登録するレコードが多く、
aws-cliで一気に登録すると楽なので、以下にサンプルを貼りますので参考にしてみてください。

・53.json

{
  "Comment" : "",
  "Changes" : [
    {"Action":"CREATE","ResourceRecordSet":{"Name":"dev0.xxxxxx.jp","Type":"A","AliasTarget":{"HostedZoneId":"xxxxxxxxxxxx","DNSName":"dualstack.rproxy-xxxxxxxx.ap-northeast-1.elb.amazonaws.com","EvaluateTargetHealth":false}}},
    {"Action":"CREATE","ResourceRecordSet":{"Name":"dev1.xxxxxx.jp","Type":"A","AliasTarget":{"HostedZoneId":"xxxxxxxxxxxx","DNSName":"dualstack.rproxy-xxxxxxxx.ap-northeast-1.elb.amazonaws.com","EvaluateTargetHealth":false}}},
    {"Action":"CREATE","ResourceRecordSet":{"Name":"dev2.xxxxxx.jp","Type":"A","AliasTarget":{"HostedZoneId":"xxxxxxxxxxxx","DNSName":"dualstack.rproxy-xxxxxxxx.ap-northeast-1.elb.amazonaws.com","EvaluateTargetHealth":false}}},
    {"Action":"CREATE","ResourceRecordSet":{"Name":"dev3.xxxxxx.jp","Type":"A","AliasTarget":{"HostedZoneId":"xxxxxxxxxxxx","DNSName":"dualstack.rproxy-xxxxxxxx.ap-northeast-1.elb.amazonaws.com","EvaluateTargetHealth":false}}},
    {"Action":"CREATE","ResourceRecordSet":{"Name":"dev4.xxxxxx.jp","Type":"A","AliasTarget":{"HostedZoneId":"xxxxxxxxxxxx","DNSName":"dualstack.rproxy-xxxxxxxx.ap-northeast-1.elb.amazonaws.com","EvaluateTargetHealth":false}}},
    {"Action":"CREATE","ResourceRecordSet":{"Name":"dev5.xxxxxx.jp","Type":"A","AliasTarget":{"HostedZoneId":"xxxxxxxxxxxx","DNSName":"dualstack.rproxy-xxxxxxxx.ap-northeast-1.elb.amazonaws.com","EvaluateTargetHealth":false}}},
    {"Action":"CREATE","ResourceRecordSet":{"Name":"dev6.xxxxxx.jp","Type":"A","AliasTarget":{"HostedZoneId":"xxxxxxxxxxxx","DNSName":"dualstack.rproxy-xxxxxxxx.ap-northeast-1.elb.amazonaws.com","EvaluateTargetHealth":false}}},
 
    {"Action":"CREATE","ResourceRecordSet":{"Name":"dev0-hoge.xxxxxx.jp","Type":"A","AliasTarget":{"HostedZoneId":"xxxxxxxxxxxx","DNSName":"dualstack.rproxy-xxxxxxxx.ap-northeast-1.elb.amazonaws.com","EvaluateTargetHealth":false}}},
    {"Action":"CREATE","ResourceRecordSet":{"Name":"dev1-hoge.xxxxxx.jp","Type":"A","AliasTarget":{"HostedZoneId":"xxxxxxxxxxxx","DNSName":"dualstack.rproxy-xxxxxxxx.ap-northeast-1.elb.amazonaws.com","EvaluateTargetHealth":false}}},
    {"Action":"CREATE","ResourceRecordSet":{"Name":"dev2-hoge.xxxxxx.jp","Type":"A","AliasTarget":{"HostedZoneId":"xxxxxxxxxxxx","DNSName":"dualstack.rproxy-xxxxxxxx.ap-northeast-1.elb.amazonaws.com","EvaluateTargetHealth":false}}},
    {"Action":"CREATE","ResourceRecordSet":{"Name":"dev3-hoge.xxxxxx.jp","Type":"A","AliasTarget":{"HostedZoneId":"xxxxxxxxxxxx","DNSName":"dualstack.rproxy-xxxxxxxx.ap-northeast-1.elb.amazonaws.com","EvaluateTargetHealth":false}}},
    {"Action":"CREATE","ResourceRecordSet":{"Name":"dev4-hoge.xxxxxx.jp","Type":"A","AliasTarget":{"HostedZoneId":"xxxxxxxxxxxx","DNSName":"dualstack.rproxy-xxxxxxxx.ap-northeast-1.elb.amazonaws.com","EvaluateTargetHealth":false}}},
    {"Action":"CREATE","ResourceRecordSet":{"Name":"dev5-hoge.xxxxxx.jp","Type":"A","AliasTarget":{"HostedZoneId":"xxxxxxxxxxxx","DNSName":"dualstack.rproxy-xxxxxxxx.ap-northeast-1.elb.amazonaws.com","EvaluateTargetHealth":false}}},
    {"Action":"CREATE","ResourceRecordSet":{"Name":"dev6-hoge.xxxxxx.jp","Type":"A","AliasTarget":{"HostedZoneId":"xxxxxxxxxxxx","DNSName":"dualstack.rproxy-xxxxxxxx.ap-northeast-1.elb.amazonaws.com","EvaluateTargetHealth":false}}},
   ]
}

・run

$ jq . 53.json
$ aws route53 change-resource-record-sets --hosted-zone-id xxxxxxxx --change-batch file://53.json --profile aws
{
    "ChangeInfo": {
        "Id": "/change/xxxxxxxxxxxx",
        "Status": "PENDING",
        "SubmittedAt": "2019-05-07xxxxxxxxxxxxxxxx",
        "Comment": ""
    }
}

dev X (10台)/弥生会計

dev X(10台)に関しては、社内でエンジニア以外でも確認できるランサーズの検証用環境となります。
ローカルの開発環境との差異をなくすため、EC2上にdockerをインストールして構築しました。
ALBでは各ドメインごとにリスナールールを使用してリクエストをターゲットにルーティングしています。

また、インスタンスが立ち上がっているとコストがかかるため、CloudWatch Eventsで深夜に止めて、
Slack上で個人で使いたいときに予約して起動するようAPI Gateway、Lambda、Slack commandを利用して工夫してみました。
LambdaはNode.jsで書いたので参考にしてみてください。(以下画像より)

弥生会計はEC2上にWindows Server 2019をインストールしてリモートデスクトップを利用して運用しています。
バージョン16から19へのバージョンアップにつまずきましたが、
サポートに問い合わせして、無事移行することができました。
その他社内ツールで利用しているサーバーはAnsible化していなかったので一から作りました。

・確認
/ec2 dev1 status
・起動
/ec2 dev1 start
・停止
/ec2 dev1 stop

・index.js

'use strict';

const AWS = require('aws-sdk');
var targetId = '';

// EC2 インスタンスのステータスを確認
function statusEC2Instance(region, instanceId) {
    const ec2 = new AWS.EC2({ region: region });
    const params = {
        InstanceIds: [instanceId],
        DryRun: false
    };
    return new Promise((resolve, reject) => {
        ec2.describeInstances(params, (err, data) => {
            if (err) reject(err);
            else    resolve(data.Reservations[0].Instances[0].State.Name);
        }); 
    });
}

// EC2 インスタンスを起動
function startEC2Instance(region, instanceId) {
    const ec2 = new AWS.EC2({ region: region });
    const params = {
        InstanceIds: [instanceId],
        DryRun: false,
    };
    return new Promise((resolve, reject) => {
        ec2.startInstances(params, (err, data) => {
            if (err) reject(err);
            else     resolve(data.StartingInstances[0].CurrentState.Name);
        }); 
    });
}


// EC2 インスタンスを停止
function stopEC2Instance(region, instanceId) {
    const ec2 = new AWS.EC2({ region: region });
    const params = {
        InstanceIds: [instanceId],
        DryRun: false,
    };
    return new Promise((resolve, reject) => {
        ec2.stopInstances(params, (err, data) => {
            if (err) reject(err);
            else     resolve(data.StoppingInstances[0].CurrentState.Name);
        }); 
    });
}

// 関数指定してインスタンスを制御
function executeControl(ec2Function) {
    var result = '';
    const a = ec2Function(process.env.EC2_REGION, targetId)
        .then(data => {
            result = data;
        }).catch(err => {
            result = { result: 'hoge', data: err };
        });
    return Promise.all([a]).then(() => result );
}

function getSuccessfulResponse(message, result) {
    return {
        "attachments": [
            {
                "color": "#32cd32",
                "title": 'Success',
                "text": message,
            },
            {
                "title": 'Result',
                "text": '```' + result + '```',
            },
        ],
    };
}

function getErrorResponse(message) {
    return {
        "response_type": "ephemeral",
        "attachments": [
            {
                "color": "#ff0000",
                "title": 'Error',
                "text": message,
            },
        ],
    };
}

# インスタンスIDの指定
exports.handler = (event, context, callback) => {
    if (!event.token || event.token !== process.env.SLASH_COMMAND_TOKEN)
        callback(null, getErrorResponse('Invalid token'));
    if (!event.text)
        callback(null, getErrorResponse('Parameter missing'));

    var target = event.text.split(' ')[0];
    switch (target) {
        case 'dev1':
            targetId = 'i-xxxxxxxxxxxx';
            break;
        case 'dev2':
            targetId = 'i-xxxxxxxxxxxx';
            break;
    }
    
    if (event.text.match(/start/)) {
        executeControl(startEC2Instance).then(result => { callback(null, getSuccessfulResponse(target + ' Starting...', result)); });
    } else if (event.text.match(/stop/)) {
        executeControl(stopEC2Instance).then(result => { callback(null, getSuccessfulResponse(target + ' Stopping...', result)); });
    } else if (event.text.match(/status/)) {
        executeControl(statusEC2Instance).then(result => { callback(null, getSuccessfulResponse(target + ' Get status...', result)); });
    } else {
        callback(null, getErrorResponse('Unknown parameters'));
    }
};

まとめ

8年も動いていた社内サーバーの電源を無事にシャットダウンすることができました。
このラックサーバーのおかげでランサーズの一部を担っているかと思うとなかなか感動的です。

社内でサーバーを運用することはコスト削減になりますが、メンテナンスが大変なのと、
オンプレであればハードウェア障害は避けられず、運用に伴う専門性が問われるため 、
クラウドに移行して誰でも運用できるような検証環境を実現できたので、
なかなか達成感がありました!

読んでいただきありがとうございました。
また会いましょう!! See you next time!!

Vuls祭り#5でLTしてきました

adachin|2019年06月18日
SRE

こんにちわ。皆さんお元気ですか!!!
SREのあだちん(@adachin0817)です。

毎年Vuls祭りが行われるのですが、今回始めて運営チームの委員長をやらせていただきました!
今回は令和一発目のVuls祭り#5でLTしてきましてので、スライドぜひご覧ください!

connpass

https://vuls-jp.connpass.com/event/131960/

約100名

近くの方が遊びに来ていただきました!!

特に好評だったのが「まい泉のハンバーガー」
私は5個食べましたよ👍

WordPressの脆弱性を
Vulsで検知できるように!

アジェンダ

  • 自己紹介
  • ランサーズで運用しているWordpressとVuls
  • 近年の脆弱性数と推移
  • Vuls x WordPress
  • インストール方法
  • スキャンとレポート方法
  • Vuls開発環境のご紹介
  • ハンズオン
  • まとめ

まとめ

  • 脆弱性を放って置くと..
  • セキュリティ対応は敏感に!

  • WordPress脆弱性対応している方は見逃すことなし!
  • Vulsのバリューがさらに上がった↑
  • API叩きまくるとエラーが出る→有料にしましょう


それではまた来年のVuls祭りでお会いしましょう!!!バルス!!

感謝を贈り合うツール「nas!」を開発したインターン生の今後のビジョンとは

adachin|2019年03月06日
インタビュー

<プロフィール>
水島啓太/みずしまけいた @0xb5951
高専生として電子制御科を学び、電子回路やロボットなどの機械に興味を持つ。
2018年10月にCREチームのインターン生として入社。また2019年4月に新入社員としてもジョイン。
感謝を贈り合うツール「nas!」の開発者でもあり、
直近ではWordpressサーバのPHP7へバージョンアップもやりぬいた期待の新人。

できる言語:Python/Solidity/C/JavaScript/PHP
ハマっているゲームは「スマブラ」
4月からのメンターはあだちんさん


高専で今後の将来について不安があった

・高専ではどんなことを勉強していましたか?

もともと高専では電子制御科にいて、電子回路やロボットなどを中心に機械を学んでいました。自分自身、手動で行うものは全て自動化するタイプで、例えば手が感じたら信号を送って動作すれば、障害者のための環境創りもできるのではないかと思うんです。そして、5年間勉強して自分は何がつくれるのか?と考えた時に、勉強してもモノ作りができなかった自分に苛立ちを感じました。大学進学を考えましたけど、社会に出て、モノづくりを経験したほうが成長できると思ったんです。そこで、ビジネス知識と技術力の2つを学べるランサーズのインターンに目を光らせたわけです。


インターンをしてみて

・実際にインターンを経験してみてどう感じましたか?

インターンではCREチームに所属し、依頼フォームの日付をドラムロールからカレンダーに開発するところから始まりました。CREチームではバグ修正など日々ランサーさんから困っているところをサポートするのがメインとなります。まさにランサーズ自体の構成なども理解するのにピッタリな部署でもあります。

まず明確によかったところは「雰囲気が良い」「フラットである」この二択です。CRE、SREチームはじめ、教え合う環境がありコミュニケーションを頻繁に行っていること。もちろんすべてを教えてもらうというわけでなく、先輩方が「どうすればいいと思う?」と自分自身が考えさせられるという教育方法に感銘を受けました。また、巻き取りすぎず、任せてくれるといったチャレンジも大企業ではあまりないことだと感じます。


感謝を贈り合うツール「nas!」を作ったきっかけ

「nas!」とは
Slackで感謝コメントを送った際と、そのコメントにnas!スタンプを押す際に加算されるツール。また、毎月一番nas!を送られた人が表彰されるイベントにもなった。

・サクッと開発して驚きましたが「nas!」の工夫したところ、大変だったところは?

Slackで簡単に感謝の気持ちを贈り合うものをつくりたいよね!じゃあやりましょう!というフラットさから始まりました。ちょうどチャットでのコミュニケーションを活性化するチャンスだったのです。

https://qiita.com/odrum428/items/183934ee0f7e93b2f3ea?p

構成としてはAWS Lambda+API Gateway+DynamoDBを使い、 管理画面はRedashを使って集計などを可視化しています。特に難しかったことといえば、DynamoDBの設計が初めてだったので、なかなか思うように進みませんでした。

しかし、結局自分で考えて自己解決してしまうという力を身に着けていきました。工夫したところはSlackには3秒のタイムアウトがあるんですよ。並列処理を含めてユーザにはエラーが出ないようにしたところですね。

今後のnas!はもっとファジーにしていきたいです。例えば、ゲーム制をつけて自分の貯めたnas!をガチャで回したりなど。まだ社内では90人程度しか使われていないので、もっと仕掛けや仕組みを考えてバージョンアップしていきたいです


新卒になり、今後成し遂げたいこと

・5年後、10年後、どんなエンジニアになりたいですか?

実は3年後、大学に行こうと考えています。世間の論文を見るとたくさんの問題を抱えたまま解決していないのが現状です。そこを自分が解決し、問題提議をして社会実装するのが今後の夢です。生きる=働くといったことはマストなので、ランサーズでの技術的課題をこなしていき、的確な判断をしていきながら、新技術の検証などを用いてランサーズの技術をシェアしていく存在になりたいです。また、ランサーズのエンジニアとして働きながら大学へ行く、新しい働き方を創りたいなと思っています。

ランサーズのインターンにマッチしている人は「帰ってもコードを書いている」「フットワークが軽い」といった人が向いていると思います。成長できる環境がたくさんあります。ぜひビジネス力と技術力をあげたい学生さん、一緒に働き方改革をしましょう!

[AWSでWordPressのスケールアウト]PHPカンファレンス仙台2019に参戦してきた!

adachin|2019年01月27日
SRE

SREのあだちんです!!

というわけで!!

PHPカンファレンス仙台2019にて、弊社SREチームリーダー金澤さんが登壇するので、初!仙台に行ってきました!!その様子と登壇内容を簡単に解説&ブログしていきます。

SESSION

https://phpcon-sendai.net/2019/

弊社ランサーズではWordpressをAWSで運用しています。1台のインスタンスにいくつものメディアが可動しているのですが、スケールアウトのノウハウやHTTPS化、セキュリティ対策など合わせてご紹介できればと思います!

ちなみにエンジニアブログでもご紹介されているのでぜひ参考にしてみてください。

https://bit.ly/2K3Z0r4

1/25 13:00~

https://twitter.com/adachin0817/status/1088648085536858112

まずは恒例のエントランスでの写真撮影から!
お昼は会社近くの磯丸水産でランチ!!安いのでおすすめです!
(って新幹線で駅弁食べないのかい!!)🚅

https://tabelog.com/tokyo/A1303/A130301/13208791/

1/25 14:25~

隣でざわさんはひたすらスライドを修正しまくっていましたが、
私もこのブログを書いていました。平日ということもあり、車内はガラガラ 。非常にのどかです。🗻そして、

採用広報にずんだもちのお土産を要求される👀ちなみに自分は食べたことがない😋

1/25 16:04~

仙台到着!!雪がぱらつき、なんとも風情がある街!
そして我々は前前夜祭へ向かいます。

からの!!!前夜祭!!

 

オミカレCTOそーだいさんに遭遇!!!
地元仙台出身のエンジニアさんも集まり、金澤さんと同い年の方もいたのは偶然すぎる!
2次会は行かず、金澤さん実家へ泊まりに行きました(どんだけ仲いいのよ!)

そーだいさんのリアクションがあまりにも面白すぎて思わずリツイート。
後ろの「食べたらやみつきだ」が似合う。

1/26 08:00~

朝から大雪!!凍結!!危うく転ぶところだった。。

朝ごはんはオシャンティーカフェで最後のスライド確認!

現地に到着!!

 

1/26 10:25~
「AWSでWordPressのスケールアウト」

では、簡単に解説していこうと思います!!

ランサーズのWordpressサーバの構成はPHP7.2、PHP-FPM、Nginx、Aurora MySQL5.7、GIthub、自前のdeployシステムでリリースしております。今回は自前でプラグインを作成している、大量アクセスで捌けない!などスケールアウトによる運用が今回ターゲットとなります。

スケールアウトの課題としては、DBが2つ以上のサーバに分離してしまう、ファイルのアップロードができない、管理画面からプラグインをアップロードできない、wp-cronがサーバの数だけ実行されてしまう、アクセスログが分散されてしまう恐れがあります。

ここで、スケールアウトの準備をしましょう。まずはVPCを構築し、Public Subnetを切ります。そしてEIPを付与します。

そしてRoute53でALBのエンドポイントとAレコードAliasで設定をします。

先程のPublic SubnetにALBを配置し、Private Subnetを設定します。そしてWordpressサーバをPublic Subnetに移動します。ALBのメリットとしてはACMによる無料でSSLの証明書が取得可能。セキュリティ向上、HTTP2、SSL Terminationをサポートします。

DBはまずPrivate Subnetを作成していきましょう。RDSのメリットとしてはリードレプリカの追加が簡単で、スケールアウトが楽なところ。自動バックアップやポイントリカバリ機能もあります。Auroraのメリットはリードレプリカが15台まで作成可能で、レプリカ遅延が低く、Readerエンドポイントも提供されています。なので、リードレプリカ追加時の負荷分散が楽なところと、haproxyなどインストールしなくても済みます。デメリットとしてはInnoDBのみサポートしており、MyISAMしか対応していないプラグインもあるので注意してほしいところです。

アップロードディレクトリの分離はS3バケットを用意し、wp-contents/uploads以下のファイルを格納します。プラグインはWP offload Media Liteを使って画像をS3にアップロードします。

プラグイン導入後、SQLでINSERT文をwp_postmetaテーブルにデータを追加していきます。必要に応じてURLの修正をしなければならないので、mysqldumpでエキスポートして修正するのが楽でしょう。

ログの集約はtd-agentでS3に集約していますが、今後CloudWatch Logsの方が学習コストが低いので導入しやすいと思われます。

管理画面専用サーバを構築することで、/wp-admin、/wp-login.phpをIP制限したり、cron実行、deploy処理を行えます。

プラグイン追加とアップデートは上記のようにgit pullをansibleで実行しています。

冗長構成するのであれば2つ以上のAZにAppとDBを分散すれば、AZレベルの障害でも対応できるようになります。

以上!

@for__3 さんツイートありがとうございます!!!

待ちに待ったランチ!!

仙台と言えば「牛タン!」
我々は善次郎さんでたらふくいただきました。
にしても小林さんのビールジョッキ大はデカイ。そして飲みきった!!

まとめ

実際に仙台のエンジニアさんと交流できたのは熱かったです!!
そして強いエンジニアさんとも人脈掴めたのはいい経験でした。
個人的に仙台へはまた行きたいと思います。
他の登壇者については私個人のブログで紹介したいと思います!!
↓書きました。

[2019/01/26]PHPカンファレンス仙台2019に行ってきた!

😋

<掲載情報>「成長できる」ではなく「成長しやすい」が職場選びの秘訣。ランサーズで活躍する元起業家に聞いたファーストキャリアの選び方(co-mediaより)

adachin|2019年01月22日
インタビュー

学生の視野を広げるメディアco-mediaにて、18新卒エンジニア森泉のインタビューが掲載されました!

「成長できる環境選びのコツ」「未経験からエンジニアとして自走するまで」など紹介しておりますので、ぜひご覧ください!

▼「成長できる」ではなく「成長しやすい」が職場選びの秘訣。ランサーズで活躍する元起業家に聞いたファーストキャリアの選び方

https://www.co-media.jp/article/23842

「コードを書きたい」フルスタックエンジニアの苦悩と目指すものとは

adachin|2019年01月15日
インタビュー

<プロフィール>
長島 和馬/ながしー(ながしま かずま) LPF事業部

某大規模なメディアサービスを5年間勤め、MovableType, WordPressで8つのメディアを運用し、AjaxなどのJavaScript実装、マークアップ、CMS組み込み、プラグイン開発などを行う。

その後サーバーサイドエンジニアになり、Go言語によるAPI開発、PHP, React, ReduxによるCMS開発、PHP, Node,js, Express, Reactによるフロントシステム開発を行う。

そしてシステムの品質を高めるべくSREを経験し、AWS環境におけるインフラの構築、コード化(Terraform, Ansible, CloudFormation)CIの導入(CircleCI, CodePipeline)、テストの自動化、ボトルネックの調査、改修マイクロサービスアーキテクチャの設計・検証などを行う。

ランサーズのSRE 安達(あだちん)と新卒時代の同期でもあり、2019/01/06にジョイン。


6年前の新卒時代

新卒のころはいわゆる常駐といえるSES企業で、フロント周りを担当していました。6年前のころの自分を思い出すとモノづくりが好きで、一番成果として感じるのはフロントだったんですね。むしろサーバーサイドはとっつきにくいイメージで。そこからがエンジニアとして歩む第一スタートだったと思います。

当時はもくもくとコードを書いて、技術を身に着けようと必死でしたが、もっと幅広く学べる環境はないのかと思い、転職を決意しました。


フロント、サーバーサイド、SRE、あらゆる技術を経験

転職先ではフロントエンジニアとして入社しました。メディアは10個。MTやWordpressを運用しており、自分でもできるのかという不安との戦いでした。当時はディレクターもいなかったですし、案件化するところから始めて、効果測定も行い、その半年後、私の上司が退職をして、開発が私一人になったんです。

これからどうしよう。

毎日精神的に辛くなったのを今でも思い出しますね。しかも当時のあだ名は「CTO」なんてことも笑。 そこで培ったのは「自己解決する力」。誰にも教わらないって苦痛でした。Masterコミットでしたし、レビューもない。結局のところ、やりきるしかなかったんですね。

次第に会社のフェーズが変わり、サーバーサイドにも挑戦していきました。また、エンジニアでスペシャリストの方も入り、心理的安全性も保たれていきました。

そこで、PHP, React, Redux,Goなどを使ってシステム開発を行っていきました。そしてSREにも挑戦し、下から上まで経験をしてきました。しかし、5年も経ち、自分はどの技術に特化しているのかわからなくなってきたんですね。中途半端なエンジニアにはなりたくないなと。


ランサーズに入社するきっかけ

そこで新卒時代の同期だったランサーズのSRE 安達(あだちん)が声をかけてくれたんです。「5年経ったけどまた一緒にやらない?ランサーズ盛り上げようよ!」って。彼は新卒時代のころと相変わらずのあだちんだなと笑。

圧倒的に変化していたのは本業もこなし、副業も行っていること。

当時一番仲がよかったので、彼の実家で勉強会やったり、技術共有してあれから数年。また一緒に切磋琢磨しあって成長できる。こんなにも楽しいことないと思いました。

また、ランサーズというサービスはだいぶ前から知っていました。エンジニアの神庭さん土屋さんも知り合いで、勉強会でも参加するほど。2年前くらいからランサーズに転職したいなと感じていました。

自分でも働き方を変えていきたいし、地方で自然を堪能しながら仕事ができる当たり前を作りたい。

何よりもランサーズのエンジニアはブランディング力と技術力の高さに自分も仲間に入りたい気持ちでいっぱいでした。ここなら圧倒的に成長を感じれる。

そこで気づいたんです。自分はフルスタックエンジニアではなく、コードをガリガリ書いたり、DBを設計したり、サーバーサイドエンジニアとして活躍していきたい。プログラミングを誰よりも早く書けるようなスピード感溢れるエンジニアになりたいと。


身内でもランサーズを知ってもらえるように

まだ入社したばかりですが、いい人ばかりで感銘を受けました。前職では得られない、いい刺激で裁量労働制なので自由にやらせてもらっている環境にも出会えてよかったと感じています。

今後は多角的な視野で学び、ランサーズを使って副業やエンジニアとしてのブランディングを向上させて、身内でもランサーズを使えば新しい働き方を作れるよとさらに言われるようにサービスを愛し、改善していきたいです。

ランサーズの分析基盤(capybara)と運用について紹介

adachin|2018年12月02日
BigQuery

さあて!!Lancers(ランサーズ) Advent Calendar 2018 がついに始まりました。1日目は @numanomanuさん「誰も教えてくれない、サービスを終了する技術〜 SPA で作ったサービスを閉じる時にやるべきこと 〜」

SREの@adachin0817 が担当します。

ランサーズでは2018年今年から分析基盤を創り上げていきました。今回は今流行りの分析基盤をどのように運用しているか、どのような技術を使っているのか簡単にご紹介できればと思います。

ランサーズ分析基盤の始まり

もともと@g0dgardenさんが設計を考えて、私が5月にジョインして引き継ぎをしました。

capybara(カピバラ)!!

カピバラといえば草を大量に食べて蓄えている印象からデータ分析に近い存在なので決まったそうです(ロゴとか真面目に作りたい)

SRE本の中にも分析基盤によるログの可視化は該当するので、私にとってはちょうどいいタイミングとチャレンジできるといったところですね!まずはシステム構成図と各チームでの役割について書いていきます。

システム構成図

各チームでの役割

・Redash

これは割愛したいところですが、弊社ではGoogleアカウントでログインでき、DBはRDSで管理しています。従って、間違えてData Sourcesの登録を削除して、クエリを全て消えても元に戻せるようになっています。またRedashは常に最新のバージョンを保つよう運用しています。工夫していることは @waldo0515さんが作成した以下より、Redash自体のモニタリング!時間帯別に実行している時間、重いクエリ、BigQueryのユーザ別コストを可視化しています。

・td-agent/Athena

アプリケーションログtd-agentでログサーバに集計し、S3に同期しています。また、Athenaへのアクセスログを同期する方法としては以下のように工夫をしています。

  • アクセスログをLTSV形式にする⇛アクセスログを解析しやすく, 項目追加など変化に強い形になるため
  • S3へ保存するログファイルをtdでJSONにする
  • S3バケットのディレクトリ設計。HIVE形式にする⇛全ファイルを探索すると、その分課金されてしまうため必要な分のみ
  • パーティションを認識させる

これ実現することで、毎回サーバに入ってawkからの加工などがなくなり、運用コストが下がりました。

・embulk/Digdag/BigQuery

BigQueryembulkを使って、S3やRDSのデータを日々Digdag(ワークフローエンジン/ジョブスケジューラ)を使って同期しています。エラー等出たら、slackで通知が来て、以下Digdagコンソールからポチっと押すだけで再同期されるのも手軽です。

BigQueryは仮想テーブルを作成するviewという機能があるので、分析用に加工されたtableでさらに加工することが可能です。また上記にもある各チームでの役割で、アプリ側/Dev開発チームがtdの設定をして、SREチームがDigdagや、embulkの設定をしています。そうすることでスムーズに依頼と作業が進められているのもメリットSREチーム全員が対応できるよう回しています。またBigQueryはスキャンしたデータ容量によって重量課金する仕組みなので、下手にメンバーがしくじらないよう、アカウント作成時に以下のスライドで共有もしています。RedashではTotal MByte Processed Limitの設定をしているため、クエリのコスト上限もしています。他にも気をつけることがあるので、以下にまとめてみました。

・BigQueryを使用するにあたって注意点

  • use Legacy SQLのチェックをはずす(新UIだとデフォルトかも?)
    ・BigQueryは LegacySQL と StandardSQLの2つのモードがある
    ・StanddardSQL が今後標準となるのでStandardを利用する
    ・クエリ作成時デフォルトで LegacySQL が選択されているので ShowOption の項目から use Legacy SQL のチェックを解除する必要がある
  • 日付がUTCで保存されている
    ・BigQueryでは、全世界から利用されることが想定されているためUTC(日本時間と9時間ずれている)で保存されている
    ・下記のようにcastしてJSTに変換しましょう
SELECT cast(FORMAT_TIMESTAMP("%Y-%m-%d %H:%M:%S",p.created,'Asia/Tokyo') as datetime)
  • Redashからのスケジューリング
    ・BigQueryなどをRedashから定期実行する場合は、Queryを投げる度にコストがかかるため、過度な自動更新は辞めましょう

・RDSからBigQueryに同期の際気をつけていること

例えばこのテーブルをBigQueryに投入お願いします!と依頼が来た場合、毎回各テーブルのレコード数を確認しています。

mysql> select count(*) from hogehoge;
+-----------+
| count(*)|
+-----------+
|1500000|
+------------+
1 row in set (0.00 sec)

上記だと150万レコードをBigQueryに同期する分にはembulkのデータ転送に時間はそこまでかかりません。なので1000万レコード以上の場合は以下のように別テーブルで保存し、差分のみ取るようにして、それ以下は上書き(replace)するようにしています。

・hoge.yml.liquid

in:
type: mysql
{% if env.EMBULK_ENV == 'prod' %}
{% include 'db/prod_DB' %}
{% else %}
{% include 'db/pre_DB' %}
{% endif %}
query: |
SELECT
xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx
FROM
results
WHERE
modified > DATE_SUB(CURDATE(), INTERVAL 1 DAY)

・hoge.dig

_error:
  sh>: export $(cat config/env | xargs) && /redash/digdag/post_slack.sh "[${session_time}][${session_id}] DigDag Fail xxxxxx"

+payments:
  sh>: export $(cat config/env | xargs) && /usr/local/bin/embulk run -b $EMBULK_BUNDLE_PATH embulk/hoge.yml.liquid

+transform: 
  bq>: queries/hoge.sql
  destination_table: hogehoge
  write_disposition: WRITE_TRUNCATE

続いては分析基盤を応用したランサーズの新機能である「ユーザレポートのアナリティクス」の実装したお話をご紹介します。

ランサーズ/ユーザレポート/アナリティクス

・構成図

・BigQuery/profile_views

プロフィール数とプロフィールを見たクライアントの可視化はPHPで今年新卒の森泉くん(@IZUMIRU0313)に実装してもらいました。流れは深夜にアプリケーションログをviewに作成し、続いてviewテーブルからRDSへ同期しています。(embulk-input-bigqueryを使用しています)つまり、BigQueryのviewテーブルからRDSへ同期といういつもの逆を実装しています。その方法については私の個人ブログに詳しく書いているのでぜひ参考にしてみてください。
https://blog.adachin.me/archives/8492

まとめ

この分析基盤は他社でも同じよう運用しているとのことで、初め共有されたときは理解するのに時間がかかりました。。。もちろんcapybaraは大事に大事に育てていきます!明日は同じSREチームのyuu26さんです。

ランサーズで脆弱性スキャナVulsを導入しました!!

adachin|2018年06月26日
SRE

5月にランサーズのSREチームに入社しました@adachin0817(あだちん)と申します。

さてさて皆さん以下のブログをお読みになられましたか?
https://engineer.blog.lancers.jp/2018/06/5267/
SREチームの発足

普段はインフラ改善、開発環境、新規インフラ構築、コードレビュー、分析基盤の運用などを行っています。そこで、今回SREチームが4人になったことで、セキュリティ強化のため、Linuxの脆弱性対応は活動していこうと決めました。

皆さま日々Linuxの脆弱性対応をしていますでしょうか?..

・脆弱性を追いたいけどNVDやJVNを追うのは…(ツライ)
・Twitterやメールなどでアナウンスされてバタバタしちゃう…(脂汗)
・そういえば管理しているサーバの脆弱性ってどのくらいあるんだろう…(白目)

・そもそも脆弱性アップデートとかしていない…(ギグっ)
・とりあえず置いとこう…(諦め)

なんて経験ある方は多いと思います。SREは日本語で「サイト信頼性エンジニア」と言われますが、もちろんセキュリティの担保も該当します。そこでVulsは脆弱性の検知や管理の手段として、今熱いOSSとなっています。

今回はランサーズでのVuls運用と今後の展望についてブログします!

脆弱性スキャナVulsとは/インストール方法

簡単にまとめますと、

・Linuxサーバに存在する脆弱性をスキャン
Ubuntu, Debian, CentOS, Amazon Linux, RHELに対応、dockerも

・OSパッケージ管理対象外のミドルウェアをスキャン
プログラミング言語のライブラリやフレームワーク、ミドルウェアの脆弱性スキャン
CPEに登録されているソフトウェアが対象

・エージェントレスアーキテクチャ
スキャン対象サーバにSSH接続可能なマシン1台にセットアップするだけで動作

・設定ファイルのテンプレート自動生成
CIDRを指定してサーバを自動検出、設定ファイルのテンプレートを生成

・EmailやSlackなど通知可能(日本語でのレポートも可能)

・付属するTerminal-Based User Interfaceビューアでは、Vim風キーバインドでスキャン結果を参照可能

・開発者はフューチャーアーキテクトの神戸氏

VulsはGolangでできています。基本Linuxの脆弱性をスキャンしますのでアプリケーションレベルでの脆弱性スキャンはできません。スキャン方法はSSHで接続するのでPull型となります。つまり、vulsユーザを作りansibleで公開鍵を配布するのがベストかと思います。

https://blog.adachin.me/archives/5540
【脆弱性スキャナ】Vulsをインストールしてみた!

インストール方法は非常に簡単でございます。
上記の私のブログを参考にしてもらえば幸いでございます!!

Lancers x Vuls

■環境

・Amazon Linux
・vuls v0.4.2 92f36ca

・vulsrepo
・go1.10.2 linux/amd64

本番環境と検証環境はAWSアカウントが別なので、各踏み台サーバにインストールして管理することにしました。

スキャン対象ホストですがホストもLB配下に置いてないからスキャンしないではなく、可動しているサーバ全てにスキャンするようにして、いつでも最新のKernelなどバージョンに保つようにしています。なぜ全て?と思われますが、実際弊社でどのくらいのサーバが運用されているのか、こんなサーバあったっけ?何動いてるっけ?などがないように、サーバ自体の管理も行えるからです。

また、コミュニケーションツールとしてChatWorkが主流となっています。
実は私が入社前に開発して下記のようにいい感じに通知しています。(脆弱性がない場合は再起動必要か,ホスト名,OS名と表示しています)もちろんSlackにも通知させていますが、今後Slackに完全移行することになりました!!(トホホ..)

Vuls 定期実行

$ sudo crontab -l
#run vuls-auto.sh
00 09 * * 3 sudo -u vuls bash -l /home/vuls/vuls/vuls-auto.sh /tmp/vuls.log 2&>1

毎週水曜日の午前9時にvuls-auto.shというシェルスクリプトを叩いています。
毎日スキャンしてもいいのですが、1週間に1回ということで、日々アップデートされるKernelなどは量がかなり多いため、1ヶ月に1回というペースでサーバ再起動をしています。

今までscan,reportをわざわざcrontabに直接書いていましたが、管理し難いことがあったので、
スクリプトにすることで「nvd,jvn,ovalらがupdate、scan、report」らが一つになりました。
下記のgistで管理しているのでぜひ使ってみてください!

・vuls-auto.sh

https://gist.github.com/RVIRUS0817/5228ead105329438f8f643d6b1849bd0

・vuls reportでオプションはどんな感じ?

$ vuls report -format-short-text -format-json -to-slack -to-s3 -to-chatwork -cvss-over=7 -lang=ja -ignore-unfixed

・-to-s3
resultsの結果をS3に同期させるようにしています。
・ -cvss-over

CVSSスコアが7以上で通知させるようにしています。(鬼のようにくるので汗)
・ -ignore-unfixed
弊社は主にAmazon Linuxを使っていますが、一部Ubuntuもあります。Amazon Linuxは主に該当しませんが、下記のようにまだ脆弱性未対応なものは-ignore-unfixedを付け足すことで通知させないようにしています。

VulsRepo

VulsRepoというVulsでスキャンしたデータを可視化するOSSがあるのですが、もちろん弊社でも利用して、社内のみにアクセスできるようにしています。
実際に脆弱性のレベルやJVNなどのリンクに飛べたりなど詳細が細かく可視化されます。これにより、開発者やSREチームでも「この脆弱性は対応したほうがイイね!」など議論ができるので、今後の未知なる脆弱性にも対応しやすくなると思います。

今後Vuls運用でやっていきたいこと/まとめ

resultsで出力されるJSONファイルをBigQueryに同期して、Redashで今月どのくらいこのホストには脆弱性が出てるなど、簡単に可視化されたらSREチームでも共有できますし、さらに脆弱性対応も捗りそうです!

まだ運用して1ヶ月ですが、チーム内でアップデートすることでサービス影響ないのか!?などと議論していますが、ランサーズでも脆弱性対応をし続けることで、サービスの安全性を高められることは間違いないと思います。ユーザ様も安心/安全にサービスを使ってほしいのが我々弊社エンジニアの願いです。

Vulsは早いスピードで新機能がリリースされていっています。私も今後OSS活動として企業さんが導入されるよう広報していきますので、まだ導入していない方はぜひともおすすめします!!
今年のVuls祭りでは私もお手伝いなどやらせて頂くことになりましたので、その時はぜひお話しましょう!!

お昼はボードゲームを主にやっているので、
オフィス近い方はぜひ!!!

具体例で見るユーザーファーストなプロダクト改善プロセス

adachin|2017年11月30日
DevOps

こんにちは。「ランサーズ」というサービスのプロダクトマネージャーをしております、新卒2年目の齋藤です。
独学でUIデザインを学んでおり、部署は違いますが、このユーザーファーストデザイン室にもこっそり参加している人間です。

今日はデザインの話から少し遠くなりますが、「ユーザーファースト」なプロダクト改善について思っていることをまとめてみます。

何も具体例がないまま書いてもなかなか想像しにくいかと思いますので、今回は数週間前にリリースしました「あしあと機能」を例に挙げてお話しします。

あしあと機能とは

読者の方の中にはランサーズを使ったことがない方もいらっしゃるかと思いますので、あしあと機能について軽くご説明します。

ランサーズには「ランサー(受注側)」「クライアント(発注側)」の二方向のユーザーがいます。
あしあと機能とは、ランサーのプロフィールを閲覧したクライアントの履歴を、ランサーに対して表示する機能です。
あしあと機能と聞くと、某SNSを連想される方も多いのではないでしょうか。

ユーザーへの価値提供を最速にする

とにかくユーザーへの価値提供が最優先です。
僕も細かいインタラクションなどこだわりたい派ですが、ぐっとこらえて、まずは出すことを最優先に考えています。

このあしあと機能の開発でも、最速で価値提供するために「データベースに新規テーブルを作らず、既に取得しているアクセスログデータを応用する」「本当は全履歴一覧ページをつくるといいかもしれないが、まずは直近5件のみ表示する」etc…といったことをしました。

データの持ち方をリリース後のKPIモニタリングに少し時間がかかるなどトレードオフな側面も多分にありますが、出さずに価値提供していない状態より1728612987倍良いです。

ただし、最速で出す上で
1)ユーザーに提供する価値の最低ラインを満たしていない(課題を解決していない)
2)仮説の検証ができない(サンプル数が不足するような表示ロジックなど)
といったケースについては注意が必要です。

仮説を明確にする

当たり前ですが、日々並行して様々な施策を打っていると意外と曖昧になりがちなところではないでしょうか。
上記でも述べましたが、最速で出しても学びがなければ意味がありません。

このあしあと機能も、社内で話を出したときには「サイト上に活発感が出るからいいね!」「SNS感出ていいよね!」といった声をもらうことが多々でした。
まだリリースもしていないのに社内での評判がうなぎ登りになっていくあしあと機能…

しかし、この機能の仮説はより実際のKPIに結びつくところにありました。
これまでランサー(受注側)は仕事検索ページから能動的に仕事起点で仕事をさがすというルートしかありませんでした。
そこで、ランサーが「人起点」で仕事をさがす世界があっても良いのではないか?そのルートのほうがマッチング率が高いのではないか?という上段の仮説の下、様々な詳細仮説を立て、そのうちの一つとしてこの機能をリリースしました。
なので、仮説に基づき、ステークホルダーからの声があっても逆方向のあしあとはあえて表示しない仕様にしています。
また、上記の仮説の下準備として、クライアント(発注側)のプロフィールに募集中の仕事一覧を表示させるという施策でフィジビリティも取り、仮説の確度を上げた上で検証しました。

重要なのは、ユーザーやステークホルダーから色々な期待・要望が寄せられても仮説・課題の定義をブレさせないことだと考えています。

ユーザーの声を拾いにいく

ユーザーへのそれぞれの価値提供の前後どちらでも、能動的に声を拾いにいくことは非常に大切です。僕は一度、ユーザーさんと飲みに行き、そのまま仲良くなってお宅に泊まらせていただいたことがあります。笑
このようなシチュエーションはあまりないことなので再現性は低いかもしれないですが、実際にユーザーがプロダクトを使用している場を目の前で見ることには多くの学びがあり、おすすめです。
実際、あしあと機能とその後の構想も、その時に課題と仮説が明確化しリリースに至ったという側面もありました。

また、施策リリース後もデータだけでなくTwitterや各種ユーザーミートアップイベントで定性的な声を聞きに行っています。ただし、ユーザーの声をそのまま反映することが「ユーザーファースト」ではありません。そこから課題を抽出し次の仮説に結びつけていくという意識が重要です。ユーザーの声を「聞きにいく」のではなく「拾いにいく」感覚が近いかもしれません。

まとめ

いかがでしたでしょうか。
「ユーザーファースト」というと人によって定義がブレてしまうかと思います。チームで上記のように定義をすり合わせておくと向かう先、そこへの向かい方が明確になるかもしれません。
今回生まれて初めてブログというものを書いたので拙かったかもしれませんが、これを機に引き続き「ユーザーファーストなプロダクト作り」についてアウトプットしていきたいと思います。

UI/UX Designer’s Meetup 〜ユーザーファーストなサービスの作り方とは?〜登壇させていただきました。

adachin|2017年11月13日
DevOps

初めまして。ユーザーファーストデザイン室の上野です。

9月28日にUI/UX Designer’s Meetupに「ゼロイチにおいて、デザイナーがやるべき取り組み」と題しまして登壇させていただきました。

発表した内容についての概要をここで話できればと思います。

0→1のフェーズで熱狂的なファンを作るために必要だと思っていて、そのための大きなやるべき取り組みは下記2つだと考えています。

プロトタイプを最速で作ってメンバーと認識合わせをして進めること
コアバリューを定めて、やる・やらの判断を明確にすること

1つ目ですが、ある施策をやろうとした時に要件をプロダクトマネージャー(もしくはデザイナー)が決めた後に最速でプロトタイプを作って、メンバーに共有することです。

これは施策のイメージをビジュアルに落とし込み共有することにより、各役割視点でのFBを早い段階で反映することができ、開発着手後の手戻りをする事がなくなります。

2つ目は、そのサービスのコアバリューを定めて各施策がちゃんと、則っているかどうかを判断することです。まずチームメンバー全員がコンセプトの作り方を読み、全員で議論をして、明文化していきました。

この結果、各施策に対してコアバリューベースでやる・やらの議論をすることができ、各メンバーがちゃんと腹落ちをちゃんとした状態で業務をすることができます。

上記2つの取組みは、デザイナー以外の役割でも比較的できることだと思いますし、これから新しい事業をやられる方の参考になればと思います。

詳しい資料は下記スライドがありますので、興味のあるかたはご覧ください。

その他発表者のプレゼンも非常に楽しかったので見てみてください◎

以上、現場からでした。

~ユーザーファーストなサービスの作り方とは?~

BASE株式会社 早川 宗亮

株式会社みんなのウェディング 齊藤 有香

ランサーズ株式会社 上野 翔平

株式会社トクバイ 吉井 裕貴

発表者登壇資料