2019年の開発チームの振り返り

こんにちは、M&Aクラウドの荒井です。 2019年も終わりということで、今年の振り返り的な記事を書こうと思います。

1年間で変わったこと

  • サービスが立ち上げ期を終えた
  • メンバーが増えた
  • よりチーム全体でのアウトプットを意識するようになった

サービスが立ち上げ期を終えた

M&Aクラウドは2018年4月にリリースした、M&Aのマッチングプラットフォームサービスですが、ユーザー様同士の口コミや営業チームのおかげもあり、日々買い手企業様が増え続ける状態となっています。売り手企業様も同様です。毎日買い手企業様と売り手企業様が、Web上でマッチングし、会社売却の相談をされていてこれは本当にすごいことだと思います。サービスの核となる部分は今年一年でだいぶ形になったのではないかと思います。

メンバーが増えた

今年は5月に @ytzk_、6月に @arue_tomo 、11月に @kubotak_public が入ってくれました。

メンバーが増えるとできることが本当に広がります。それはただ単にやろうとしていたことがより消化されるというだけじゃなくて、今までできなかったこと、気が回らなかったこともどんどんメンバーが考えて勝手に進めてくれています。

今年だけで以下のような開発側面での改善が進みました。

  • QuickSightでデータ可視化
  • 踏み台サーバーでDBアクセスを簡単にセキュアに
  • ログインセッションとDBキャッシュサーバーの分離
  • CloudSearch → ElasticSearch
  • GithubFlow → GitFlow
  • PHPStormからのPHPUnit実行
  • Laravel Mix → Webpack
  • CircleCIからテスト、リリースを完全自動化
  • ElasticSearch&Kibanaでアクセスログ、検索ログ解析基盤構築
  • Elasticbeanstalk Worker
  • Laradock → Docker

また、チーム全体で採用にコミットすることができました。 週次でwantedlyから候補者を手分けしてリストアップし、スカウトを行い、採用という結果につなげることができました。チームメンバーみんなで候補者の方と話して、納得した方と一緒に働く、という体制をこれからも続けられたらと思います。

チームでのアウトプットをより意識するようになった

去年まではエンジニアは2名だったので阿吽の呼吸という感じでしたが、さらに2名増えるとそうは行かなくなってきます。 都度探したり、都度考えたりしないように、情報共有やルーチン化が必要です。

今年だけでもチームメンバーの提案で以下の様なことが導入されました。

  • カンバンの導入
  • LGTM
  • 2週間ごとのスプリント、開発計画、振り返り(KPT)
  • 日例
  • サービス改善提案の受付
  • ユーザーヒアリングの実施、ペルソナ作成
  • リリース前確認回
  • 障害対応反省会
  • Slackチャンネル活用 #product、#maybe_bug、#お困りごと相談

来年もどんどんやることが変わっていくと思いますが、それに合わせて新しい仕組みを導入し、より良い組織を常に目指していきたいです。

今年一年お疲れさまでした

今年一年お疲れさまでした!来年は2月から新メンバーが入りますし、Laravel JP Conference 2020にも協賛させていただいたりなどイベントがたくさんあって楽しみです。良いお年を。

【Laravel】AWS Elastic Beanstalkのワーカー環境を使ってバックグラウンド処理用のサーバを構築しました

Qiita Laravel #2 Advent Calendar 2019 17日目の記事です。

こんにちは、M&Aクラウドの津崎です。

今日は、AWS Elastic Beanstalk Worker環境でLaravelを動かして、キュー処理、定期実行処理の専用環境を構築した話をします。

最初はQiitaに投稿する予定で記事を書いていたんですが、自社の環境に限った話が多かったので、自社ブログで公開しました。

記事の最後には、本番環境でやらかしちゃった話もありますので、Laravel でワーカー環境の構築を検討されている方はチェックしていただけたらと思います。

弊社が運用しているM&Aクラウドというウェブアプリケーションは、AWS Elastic Beanstalkのウェブサーバー環境で構成されています。

macloud.jp

AWS Elastic Beanstalkは、お手軽にWebアプリケーション構築できる、インフラに手が回らないスタートアップ企業にはとてもありがたいAWSのサービスです。 冗長化、オートスケーリングをAWSのWebコンソール上から簡単に構築・設定することができます。 (弊社のインフラを最強にしてみたいエンジニアの方、お待ちしてます🙇‍♂️)

サーバ構成

導入前の構成

f:id:zacky2:20191216211131p:plain

導入後の構成

f:id:zacky2:20191216211100p:plain

ワーカー環境を導入する以前は、キュー処理や定期実行のタスクなどのバックグラウンド処理もウェブサーバ環境で実行していました。

バックグラウンド処理のトリガーは、CloudWatch Eventsを使っています。 CloudWatch EventsからLambdaを実行し、HTTPによってLaravel製のウェブアプリケーションの特定URLにアクセスしています。

ウェブアプリケーションは、特定URLにアクセスされた時にバックグラウンド処理を開始します。 図では、バックグラウンド処理の代表的な例として、Amazon SQSからキューを受け取って処理を行い、Amazon SNSを呼び出してユーザにメールを送信するケースを表しています。

構成上の問題

ウェブサーバ環境でバックグラウンド処理する構成にはいくつかの問題がありました。

  • セキュリティについて
    • タスク実行のためのURLが外部に露出しており、URLが流出しアクセスされると不正に処理が実行されてしまうリスクがある
  • 性能ついて
    • キュー処理は1分に一回、100個のキューを取得して処理するように実装しているため、キューを数百個積まれると処理が詰まってしまう
      • 例えば、2000通送る場合、メール送信に20分かかってしまい、その間他のメールが送られないなど
      • ※これは実装上の問題なので上手く作ればもっと効率的になるがキチンと実装しようとするとチョットムズカシイ
  • 負荷について
    • 将来的に利用者が増えていくと、ウェブサーバにおけるバックグラウンド処理による負荷を無視できなくなる

これらの問題はワーカー環境を使わなくても様々な工夫で改善できますが、 ワーカー環境にはこれらの問題を一度に解決できるというメリットがあったので採用しました。

AWS Elastic Beanstalk ワーカー環境とは

Beanstalkには、2つの環境枠があります。 1つは、通常のウェブサーバに用いられるウェブサーバー環境です。

もう1つが、ワーカー環境です。 ワーカー環境は、ウェブサーバ環境と違い、SQSデーモン😈という、Amazon SQSからキューを読み取り、ローカルのポート80にHTTP POSTリクエストを送ってくれるデーモンプロセスが各インスタンス内に常駐しています。 自前のアプリケーションでSQSデーモンからPOSTされたデータを処理するように実装すれば、バックグラウンド処理用のサーバの完成になります。

f:id:zacky2:20191216211118p:plain (https://docs.aws.amazon.comから引用)

https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/using-features-managing-env-tiers.html

ワーカー環境の導入

ワーカー環境の導入には、SQSのキューを受け取るエンドポイントを作る必要があります。 このエンドポイントの作成には、dusterio/laravel-aws-workerというパッケージを利用しました。 インストールするだけで/worker/queueというエンドポイントが作成されます。 めちゃくちゃ便利です。

https://github.com/dusterio/laravel-aws-worker

あとは、ワーカー環境を作って各種設定をすればOK!

導入結果

f:id:zacky2:20191216211100p:plain

ワーカー環境の導入によって、当初抱えていた問題は解決されました。

  • セキュリティについて
    • ワーカー環境はデフォルトでインターネットからアクセスできない
  • 性能について
    • キューを並列に最大100個処理できるので、リソースの利用効率がよくなり処理が早くなった
    • 並列数を高めてもSNSで詰まってしまうので、徐々に並列数を増やしている
    • 今の所4並列で運用しており、ワーカー環境導入前よりメールの一括送信が4.8倍が早くなった
  • 負荷について

本番環境でやらかしちゃいました

ワーカー環境導入にあたって、本番環境でユーザーに迷惑をかけてしまうような不具合が発生してしまいました。 Laravelでワーカー環境を導入する方は、同じ過ちを犯さないように十分注意して欲しいです😢

発生した現象

ワーカー環境から送信されたメールにおいて、メール内のボタン動作しないとユーザから連絡がありました。

なんと、メールに表示されたボタンのリンク先がhttp://localhost/から始まるURLになってしまっていたのです。

原因

Laravelのデフォルトの設定では、自サイトのURL生成の時に、リクエスト時のドメイン名を利用するようになっています。 ウェブサーバ環境では、ユーザからmacloud.jpというドメインでアクセスされるので、自サイトのURLを生成するとmacloud.jpというドメインのURLが生成されます。 一方、ワーカー環境では、SQSデーモンがLaravelに対してlocalhostでアクセスを行います。 そのため、Laravelは自サイトのURLをhttp://localhost~として生成してしまったのです。

対策

app/Providers/AppServiceProvider.phpboot()メソッドに、 環境変数で指定したルートURLを使用するように追記しました。

    public function boot()
    {       {
        if (env('REGISTER_WORKER_ROUTES', true)) {
            URL::forceRootUrl(config('app.url'));
        }

   // 略

反省

大きな機能の開発の時には、エンジニアとプロダクトマネージャーが集まって、機能やデグレードの確認会を必ず行うようにしています。 しかし、今回のインフラの変更は、コードの変更が少なく、メールが送られれば大丈夫だろうとチーム全員が思っていたため、担当者レベルでの確認に留まっていました。

ベースURLが異なるという不具合は、事前にその可能性に気づくのが難しく、テストコードを書いておくことは困難ですので、どうしても人間の手によるチェックが必要になります。

今後は、インフラの変更においても確認会を実施し、周辺の機能も含めての確認を徹底していきます!

まとめ

  • ワーカー環境は、キュー処理、定期実行などのバックグラウンド処理を行わせるのに便利
  • dusterio/laravel-aws-workerで簡単に導入できる
  • ベースURLに気をつけて

最後に

我々は、一緒にインフラを改善をしてくれるエンジニアを随時募集中です。 www.wantedly.com

www.wantedly.com

Laradockを卒業しました

こんにちは、kubotakです。 アドベントカレンダーシーズンですが敢えて会社のブログを書こうと思います。

弊社では開発環境としてDockerを利用しています。 Dockerの管理はLaradockというOSSを利用していましたが、最近自前のdocker-composeに移行したという話をしたいと思います。

Laradockとは

laradock.io

もともとはPHPフレームワークLaravelをDockerでローカル開発しやすいようにしたパッケージでしたが今ではPHP開発全般で利用できるように汎用的にあらゆるミドルウェアなどが追加されているOSSです。 弊社では開発当初からLaradockを利用してローカル開発を行っていました。 とても便利なツールで助かっていたものの以下の点で困っていました。

導入手順が複雑

導入するためにアプリケーションのREADMEに多く手順を残す必要がありました。 また、Elasticsearchなど使うミドルウェアも増えてきていて、docker-compose up -d {container}に追加するものが増えていきました。

イメージが重い

できるだけ初回起動を早めるためにイメージは最小限で良いと思いますのでLaradockではオーバーな気がしていました。 また、自分たちでDockerfileを書かないとイメージにどんなライブラリを入れているのかなどの見通しが悪く、とりあえず動くからOKみたいになりがちで良くないなと思っていました。

自前でDockerfile,docker-compose.ymlを作る

Makefileで管理する

まず導入手順を簡略化するためにMakefileによる管理を行いました。 導入手順をそのままMakefileで実行できるようにmake initというコマンドで作り初回起動の一連の手順を自動化させました。 また、よく使うdocker-compose updown,execなどはそれぞれmake up, make down, make sshなど簡易的なコマンドに変更。 make helpで利用可能なコマンド一覧を出力させるなどの工夫も取り入れました。

composer_install               アプリケーションに依存するPHPライブラリをインストールする
down                           開発環境を落とす
import_es                      Elasticserachにデータを格納する
init                           初回実行用
migrate                        DBマイグレーションを実行する
migrate_seed                   DBマイグレーション(fresh)とシードを実行する
php_unit                       PHPユニットを実行する
ssh                            開発環境内にsshで入る
up                             開発環境の立ち上げ

ミドルウェアなどはalpineイメージ

Alpine Linuxは軽量なLinuxのイメージです。 ミドルウェアなどは直接コンテナに入ってコマンドを実行するなどがないのでalpineイメージで構成しました。

移行後

現在ではメンバー全員がLaradockから移行しましたが特に問題なく開発を続けられているようです。 当初はLaradockに比べてアクセスが遅い、重たいなどとのレビューがありましたが、Laradock側の実装を参考にopcacheの設定やNginxのconfigのチューニングなどを行い同等レベルまでパフォーマンスを出せるようになりました。 また、メンバーでPHPUnitの実行時間に差が大きい事象がありましたがDockerに割り当てるメモリが8GB未満だと顕著に遅くなっていたことがわかりました。 おそらくElasticsearchのコンテナがメモリを多く消費してそうな気がしてますが、メモリの割当によって改善されたのでそのまま運用しています。

余談ですが、移行後に弊社鈴木がLaradockへのOSSコミットなどを果たすなどもありました。

PHP開発環境のOSS(Laradock)に初めてのプルリクを出してマージされた話 - Qiita

最後に

一緒にDeveloper Experience(開発体験)を向上させてくれる仲間も随時募集中です。 www.wantedly.com

www.wantedly.com

弊社デザイナーの仕事とこれから。

f:id:mac-tech:20191204183906j:plain

初めまして

Webデザイナーの長竹です。 今年6月にジョイン、はや半年経ちました。 それなりに慣れてきてやれること / 課題がたくさん出てきました。

この記事では、Webデザイナーとしてこの半年間どのように過ごしてきたか、この先どういう感じになるのか(なりたいのか)をまとめて行こうと思います

自己紹介

イケたいWebデザイナー長竹です。専門卒業後、自社開発系の会社に就職。 その後フリーランスで活動していたところ株式会社M&Aクラウドにたどり着きました。 twitter.com note.com

なにをやってるの?

  • 社内印刷物の作成
  • SNS広告クリエイティブ作成
  • イベント用グッズ制作
  • 新規機能のデザイン・実装(HTML/CSS)
  • 既存機能(ページ)の改善
  • 動画制作(デモ・広告用) などなど…

現在は唯一のデザイナーなので、デザインが絡むものは大方やらせてもらっています メインではM&Aクラウドのプロダクトチームで開発に関するデザイン(UI/UX)、HTML/CSSマークアップなどをしています。

何を使って作業しているの?

Githubを使ってエンジニアと連携し実装を行います。 基本ツールに縛りはなく、自由に選択しています(Sourcetreeは自分だけ) モックアップツールはXDがメインです。

スプリントのワークフロー

f:id:mac-tech:20191202183542j:plain
弊社プロダクトチームは2週間のスプリントでプロジェクトを進行しています。 ざっくりですがこんな感じで、デザイン(仕様)作成中にバックエンドが動き出し、デザイン完成後にフロントエンドの実装に入ります。

エンジニア作業が重い場合は自分でHTML/CSSマークアップをして、デザイン作業が重い場合はエンジニアにお願いする。といったバランスです。

プロジェクトオーナーとのワークフロー

すでにある程度の仕様が固まっているものに関しては 仕様を元にデザイン作成 → オーナー確認 → 修正 → 最終チェック → 完成 といった流れがベースです。 このフローの中で意識してることが3つあります。

  1. まずは仕様通りに作る

  2. リデザインする(考えられるパターンを作る)

  3. 比較しながら提案する(自分の答えは決めておく)

一度形にしてみて、その上でもっと良いUI・UXがあると思ったらそれも形にしています。 これにより「実際に作ってみたが、このような問題点があった。その解決方法を考えてみました」というやりとりが可能になります。 仕様の段階で細部まで考えることも重要ですが、UIを実際に作って全体像を見て初めて気づくことが多く存在します。 何よりデザイナーの頭の中身を一番伝えることができるのは、ビジュアルそのものだと思っています。

f:id:mac-tech:20191206090040p:plain
ざっくりこんな感じでXDでパターンを確認出来るようにしています

失敗と学び

この半年間のプロジェクトでは、既存サイトへの追加機能や機能改善がメインでした。 その中でいくつか失敗がありました。

既存UIとのズレ

新規機能で絞り込みなどをデザインする際に、他のページの絞り込みやチェックボックスのUIがどうなっているかなどを考えずに1つの箇所にこだわってしまいました。 ユーザーが同じような機能を使う際に、それぞれでUIやインタラクションが異なれば困惑します。今後はStorybookやXDのコンポーネント機能などを用いてUIを一元化し管理出来るようにしていきます。

仕様が曖昧

把握しきれていない仕様が存在し、デザインに落とし込めていなかった。なんてことがありました。 これはプロジェクトに関わる時間が増えることで減りましたが、ここが不足していると混乱してしまうのでエンジニアに想定漏れがないかを聞いたりなどして 設計漏れを減らしています。

上流工程に関わる

やはり最初に仕様が固まってしまうと、そもそものUX変更などが難しくなります。 弊社は柔軟なのでそこまで問題はありませんが、仕様策定の段階でデザイナーが加わればUI・UXの方向性をその時点でブラッシュアップすることができます。 そのためには人に伝わるデザインロジックやビジュアルの用意が必要になります。

インプット

  • UX MILK Fest 2019
  • Web担当者Forum
  • Adobe MAX
  • その他細かいミートアップイベントなど

インプットのためのイベント参加は推奨されていて、たくさん行かせてもらっています。 他には海外のサイトや本、SNSなどから常に最新の情報が取れるようにしています。 (Slackのフィードを利用したり、デザインの第一人者をフォローしたり)。

f:id:mac-tech:20191204170749j:plain Adobe MAX Japan 2019

アウトプットを増やして名を上げよ

デザイナーという存在はプロダクトを生かすも殺すも自由自在、超重要なポジションです。 技術だけでなく、プロジェクトを成功に導くためのロジックや思考が必要になります。 このあたりはアウトプットを増やして少しずつ身になってくるものなので、積極的に活動したいと考えています。

おわりに

今回は自己紹介も合わせて半年間でやったことなどを簡単にご紹介しました。 今後は技術的な内容などを発信できればと思います!

Adobe MAXのイベントレポートをnoteにまとめました note.com

LaravelMixから卒業しました

こんにちは、M&Aクラウドの荒井です。M&Aクラウドサービスもリリースされてから1年半が立ち、開発メンバーも増えてきたので、フロントエンドのビルド周りをテコ入れしました。

フロントエンドのビルド周りの課題

M&Aクラウドの開発環境はLaravelに同梱されているLaravel Mixというライブラリーを使って整備されていました。 Laravel Mixは以下のようにほんの数行の設定を書くだけでwebpack経由でscssやJavaScriptのビルドをやってくれるので、とても便利です。

mix.sass('resources/sass/app.scss', 'public/css');

Laravel Mixは本当に便利なのですが、公式サイトに「An elegant wrapper around Webpack for the 80% use case.」と書いてあるとおり80%くらいの用途しか満たしてくれないので、なかなかかゆいところに手が届かないライブラリでも有りました。

laravel-mix.com

具体的な課題としては

  • 複数のアセットを別々にビルドできない。
  • 複雑なプラグイン(DllPlugin等)などを入れることができない
  • LaravelMixの依存しているwebpackやその他のライブラリのバージョンに合わせて設定を書かないといけない。

などです。特に、複数のアセットを別々にビルドできない点が問題でした。弊社のサービスはユーザー側画面(service)、ビジネス側画面(business)、管理者側(admin)と複数のレイアウトが存在していましたが、それを下図のように一括でビルドしている状態でした。

f:id:kazuhei0108:20191202123214p:plain

全然関係ない画面をいじっていても毎回全体のscssとjsのビルドが走るため時間の無駄になっていました。

Laravel MixからWebpackへの移行

これらの課題を解決するためにLaravel Mixをやめ、Webpackの設定を自前で書くことにしました。

下記のような工程で作業していき、なんとか移行を終えることができました。

  • Webpackの構造を理解する
  • (当時)Laravel Mixの内包するWebpackが3系だったが、移行先が4系だったので設定を4系で書き換え
  • Laravelのグローバルのmix関数に当たる関数の自作

ビルドを分けるためにwebpack.jsを複数作つ構成にしました。 また、ビルド高速化のためにDllPluginという仕組みも導入しました。これによりビルドは以下の様に、

  1. ライブラリーを中心としたvendor.jsをビルド、
  2. vendor.js以外をビルド

という2つの工程に別れました。

f:id:kazuhei0108:20191202124906p:plain

普段は2のみをやり、ライブラリー等を追加したタイミングで1をやることにより、ビルドする範囲を更に小さくすることができます。

DllPluginの導入はぜひ以下をごらんください。

qiita.com

Webpack移行の恩恵

Webpackを直接設定できるようになったことによって、課題は解決され以下のような状態になりました。

  • 複数のアセットを選択してビルドできる
  • Webpackを最新の4系に
  • アセットのビルド時間が短く

特にビルドの時間についてはアセットを選択してビルドする、DllPluginの導入、HappyPackの導入などを経て約1/3ほどに短縮されました。

Laravel5.8から6.4にバージョンアップしました

f:id:kubotak:20191114171317j:plain

こんにちはkubotakです。 弊社プロダクトはPHPフレームワークであるLaravelを採用しています。 私が入社した時点(2019/11)は利用しているバージョンがLaravel5.8でした。 現在ではLaravelのバージョンは6を迎え、長期サポートの対象となっています。

LaravelはOSSオープンソースソフトウェア)であり、有志によりサポートされています。 メンテナンスやセキュリティのサポートなどは各バージョンで特定の期間で実施されていて次のようなスコープになっています。

Version Release Bug Fixes Until Security Fixes Until
5.5 (LTS) August 30th, 2017 August 30th, 2019 August 30th, 2020
5.6 February 7th, 2018 August 7th, 2018 February 7th, 2019
5.7 September 4th, 2018 March 4th, 2019 September 4th, 2019
5.8 February 26th, 2019 August 26th, 2019 February 26th, 2020
6 (LTS) September 3rd, 2019 September 3rd, 2021 September 3rd, 2022

5.8はすでにバグフィックスサポートの期限を迎え、セキュリティサポートも来年の2020/02/26に期限を迎えます。 そこで、弊社では6系へのバージョンアップを実施しました。

ちなみにLaravel5系では5.xというバージョンがメジャーバージョンでしたが6系からセマンティックバージョニングになり、{メジャー}.{マイナー}.{パッチ}という形で管理されています。 現時点(2019/11)では6.4が最新バージョンとなります。

5.8から6.xへのバージョンアップは公式でアップグレードガイドが出ているのでそれを参考にすることができます。

Upgrade Guide - Laravel - The PHP Framework For Web Artisans

弊社で引っかかった項目は以下でした。

URLの生成に関しての変更

URLの生成が以下のように変更されていました。

Route::get('/profile/{location}', function ($location = null) {
    //
})->name('profile');

// Laravel 5.8: http://example.com/profile/active
echo route('profile', ['status' => 'active']);

// Laravel 6.0: http://example.com/profile?status=active
echo route('profile', ['status' => 'active']);

第2引数に渡す配列で、ルーターで指定した名前と一致しない場合はクエリパラメータとして扱うという変更です。 むしろ今まで名前が一致していないのにパスパラメータに変更していたのが驚きですね。 弊社ではこのパラメータが、例えばルーターuserIdとしているのにURL生成時の引数では['id' => xx]のように扱っていて想定していたURLと違うURLを生成していました。

JobWorkerのインスタンス引数が変更されていた

これはアップグレードガイドに載っていないものですが、Laravel Jobを実行する際のWorkerのインスタンス引数が変わっていたのでエラーになりました。 変更はこちら

github.com

ドキュメント通りにLaravelを使っている際はおそらく心配ないかと思いますが、弊社ではこのWorkerの生成を独自に行なっている処理がありました。 引数が一つ増えていたので見事に死・・・静的解析が求められますね・・・

さいごに

無事、Laravel6系に追従できました。

最後に宣伝です。 弊社では来年の2020年3月21日(土)に開催されるLaravel JP Conference 2020にゴールドスポンサーとして協賛しています。

conference2020.laravel.jp

私もコアスタッフとして参加しているのでLaravelを使っている、興味があるという方はぜひご参加ください。

弊社久保田がShizuoka.js#4で発表しました

2019/11/16(土) エニシア静岡マルイ店で開催されたShizuoka.js#4で弊社久保田が「Vue.jsの状態管理」というタイトルで発表しました。

connpass.com

発表資料はこちら speakerdeck.com

前職に在籍していたときに参加・発表させていただいたShizuoka.php#1の際にお誘いいただき、Shizuoka.jsでも発表の機会をいただきました。 Shizuoka.jsは発表内容のレベルが高く、静岡のJavaScriptの勢いを感じました。

弊社ではフロントエンドの開発に力を入れていくためにフロントエンドエンジニアを募集しています。 静岡の勢いに負けないように頑張りたいと思います!

www.wantedly.com

Amazon CloudSearchからElasticsearchへ移行した話(会社のフェーズと技術選定)

f:id:yamotuki:20191114142408p:plain

こんにちは。M&Aクラウドのエンジニアの鈴木智也です。 「自分たちのプロダクトが市場にまだ受け入れられておらず、開発チームが小さく、さらに作ろうとする機能が実際に使われるか分からない。」
そういう時にどういう技術選定をしてきたか、というM&Aクラウドの開発チームの歴史についての話です。

概要

ざっくりいうと

  • サイト立ち上げから4ヶ月目の2018年8月。サイト内検索を作るのに Amazon CloudSearch というAWSにロックされた導入が楽チンなソリューションを選択してしばらく運用していた
  • それから1年弱たった2019年7月。諸々の問題が発生した。全環境で可能な限りインフラ構成を合わせようと Elasticsearch を使うように変更する

当時のイメージ図でいうと以下のパーツだけです。

f:id:yamotuki:20191113140858j:plain
サイト内の買い手企業が検索できるようにする機能

現在の検索は以下のような形で高機能になってきました

f:id:yamotuki:20191113141752p:plain
2019年10月時点での買い手検索

最初にAmazon CloudSearchを導入した。その時何を考えていたか?

Amazon CloudSearch (以下CloudSearch)は超ざっくりいうと「全文検索エンジンを細かい設定とか気にせずすぐに使えるAWSフルマネージドのサービス」です。 CloudSearchの裏では OSS の Elasticsearch が動いているらしく、だいたい同じことができますが、CloudSearchの方は細かいこと気にしなくていいです。自分で ElasticSearch 立ち上げてクラスタ設定して、細かい日本語形態素解析設定とか、そういうことを気にしなくていいのは良いです。

CloudSearch導入時に考えていたこととやったこと

当時の状況

  • 開発チームはエンジニアが2人だけ
  • プロダクトはローンチしたばかり
  • そもそもプロダクトに何が求められているか手探り状態。検索ワードを取得すればニーズを探ることができるのでは???
  • 買い手検索機能が求められているかどうかも分からない。精度は低くてOK

技術調査

当時の状況に合わせて最適な解を探しました。

  • そもそもサイト内検索であればGoogleサイト内検索を組み込めばいいのでは?
    • => 必ず広告が表示されることが判明。苦労して集めた顧客に対して競合の広告が出るのは望ましくないのでNG。広告なし有料プランは直前まで提供されていたようだが廃止されていた。
  • Yahooのサイト内検索(カスタムサーチ)は?
    • => 「閲覧などを制限したり、パスワードを要求するサイト」は使用NG。M&Aクラウドは会員登録が必要なサービスなのでNG
  • 専用のソリューション
    • => いい感じのがありそうでしたが、初期導入費用に数十万、月額で数万かかるものだったのでNG。ベンチャーはお金ないのだ。
  • Elasticsearch は頑張れが導入できるけど、使われるか分からない機能のためにインフラ設定を初期投資としてがんばるの??
    • => 今はやめておこう。NG
  • AWS に Elasticsearch っぽいいい感じに使えるのがあるっぽいぞ?
    • => これが CloudSearch でした。1インスタンス4000円安い!(上記の専用ソリューションに比べたらだけど)

構成を考える

  • 本番環境と開発環境の2つのCloudSearchインスタンスを作る
  • 開発者が当時2人だけ。だからLocalで開発するときも開発環境のCloudSearchインスタンスに繋げれば OK。Localの環境整えるのも手間だしね
  • Localと開発のデータ差異もプロジェクトが始まって間もなく、そんなにないのでDBの内容と CloudSearch の Index が多少食い違ってもOK
  • サイト内検索の精度は、最初はその機能がどう使われるかの検証するレベルなのでそんなに高くなくて良いし、導入コストをたくさん払いたくない

会社が大きくなってくると最適解も変わる

より高機能な検索が必要だ

2019年も半ばになって、プラットフォームの売り上げも上がってきて、買い手も増えた。どういう機能が顧客に求められているかも徐々にはっきりしてきた。 例えば、買い手が100件超えそう。売り手は全ての買い手の記事に目を通すのができなくなってきた。絞り込みをする必要がある。買い手検索を高機能にしよう。 というわけで雑に作ってあまり使われていなかった買い手検索に光が当たることになりました。

起こるトラブル

高機能な買い手検索の開発にあたりいくつかトラブルが起こりました。

  • LocalからCloudSearch繋げないと検索周りの確認ができないが、env設定変更が面倒
  • 面倒がゆえに、開発中に一時的にCloudSearchに繋げないでメソッド内部で固定値を返すように無理やり変更。これがうっかりプルリクエストに入ってマージされて本番でも固定値しか返らないようになるトラブル
  • 無理やり固定値を返さなくても良いようにLocalではDBから検索するように分岐をするようにした(LaravelのServiceProviderでの分岐)。本格的なサイト内検索を作ろうとすると、CloudSearch叩く方とDBから検索する方と両方の開発を同時に進めなくてはならず、コストが膨らんでいった
  • ちゃんと検索機能を開発しようとするとDBとの整合性も大事なので、手元で書いて開発環境にデプロイして確認、また書いてを繰り返すのがコスト

インフラアーキテクチャがいけてないからトラブルが起こるんだ・・・!

根本対応をしたい。環境差異を無くそう。 エンジニアも3人になった(注: 2019年11月時点ではエンジニア4人デザイナ1人)。Localと開発環境のDBデータの差異も大きくなってきた。もう環境差異があってはやっていけない! ということでこの二つの環境を合わせることに。

環境を合わせる選択肢は以下のものが現れました

  • CloudSearch を各開発者向けに1台ずつ立ち上げる
    • 10人いたら10台*4000円? 無駄じゃね
  • 裏で ElasticSearch 動いているんだから ElasticSearch 動かせばよくない?
  • EC2 に ElasticSearch 立てて自分たちでマネージしていくの? きつくない?

こんな話があり、しかしちょっと調べてみると ElasticSearch は思ったよりも簡単に導入できそうだということがわかりました。

  • Localに関しては、Laradock で docker-compose up するときに elasticsearch を追加したらすぐに立ち上がることがわかりました。しかもkibanaも同様に簡単につけられる
  • 開発/本番環境に関しても、フルマネージドのAWS Elasticsearch Serviceがある

というわけで、Elasticsearchが導入されました

そこらへんの技術記事は以下のような形で qiita に断片的にまとまっているので参照してください

終わりに

問題が起こった時に気合いで解決せず、あるべき形の判断材料を並べてチームで判断できたのはよかったと思います。 みんなでスクラム組んで、より生産性を高い状態にしようということを努力しているチームです。

そういうわけで、私たちと一緒に四苦八苦しながら最高のプロダクトを作ってくれる仲間を募集しています。

www.wantedly.com

www.wantedly.com

Qiita記事を書くための取り組みについて

f:id:zacky2:20191111181015j:plain Webエンジニアの津崎です。

弊社のプロダクトチームでは、 社内での知見共有と、知見の正確性を担保するためにQiitaへの記事投稿を積極的に行なっています。

今回は、Qiitaの記事を定期的に書けるようにする、記事を書きたくなるようなTipsを紹介します。

運用の成果について

本取り組みは、記事数を増やすことが目的ではないため、投稿数などの定量的な目標は設定していませんが、取り組みを始めることで以下のような効果がありました。

記事がバズってランキング上位に掲載

ある記事がバズり、デイリーランキング1位、900いいね & 30,000viewまで伸びました🏅

qiita.com

Organizationランキング(週間)上位に載る

Qiitaトップページに表示されるOrganizationランキング(週間)上位10件に何度か掲載されました🎉

週6ポストほどでトップページに会社名が載るので、チームでのモチベーションに繋がりました。

f:id:zacky2:20191107181716p:plain

チームでの記事投稿頻度が増えた

過去1ヶ月の実績では、1人あたり3記事/1ヶ月。

だいたい週に1回弱くらい記事を投稿できています🤔

Qiita記事を書くための取り組み

取り組みの内容について紹介します。

毎週リマインダーを設定する

Qiita記事をたくさん書こうと思っても、日々の業務を行なっていく中ですっかり忘れさられてしまうことがあります。

Slackには簡単にリマインダーを設定する機能があるので、それでQiita記事を書くようにリマインド設定しました。

@channelでチャンネルメンバーみんなに見せればプレッシャーが上がります😈

スクリーンショット 2019-08-30 14.52.18.png

以下の文字列をSlackのチャット欄に貼り付けるとリマインダーが設定できます

/remind @channel 今週Qiitaの記事書いた? at 14:00 every Friday

Qiitaスタンプを導入する

いざ記事を書こうと思っても、ネタが思いつかないなことや、書こうと思っていたネタがあったのに失念してしまうことは往々にしてあります。

そんな問題を解決する方法として便利なのが、Slackのカスタム絵文字機能です。

カスタム絵文字機能を使ってQiitaアイコンの絵文字を作ります。

Qiitaのネタになりそうなチャット内容があったら、Qiitaスタンプを押しておきます。 他人のチャットにも、ガンガンQiitaスタンプをつけて、Qiita記事をかく圧力をかけましょう😈

こんな感じでスタンプします。

f:id:zacky2:20191108143033p:plain

QiitaスタンプをつけたSlackの投稿を検索する

has::qiita: というキーワードで検索するとqiitaスタンプついたチャットを検索できます。 記事を書くときは、ここからネタを振り返ると便利です。

f:id:zacky2:20191108140547p:plain

おわりに

Qiita記事を書くために行なっているTipsを紹介しました。

これからもチームのアウトプットを多くするために工夫をしていきたいと思います。

【kubotak】中途入社しました。

こんにちは、こんばんは、おはようございます。

今月からM&Aクラウドにジョインしましたkubotakこと久保田です。

ツイッターはこちらです。宜しくおねがいします。

kubotak (@kubotak_public) | Twitter

 

前職では国内最大級のコスメのクチコミサイトを運営する会社でよくわからないエンジニアをやってました。

ときにはPHPでWebアプリケーションを作り、GolangでコンソールアプリケーションやREST APIアプリケーションを作ったり、ScalaRDBMSからHDFSに挿入するスクリプトをSparkを利用して作ったり、JavaScriptで社内イベントで遊ぶゲームアプリ作ったり、HHVM/Hackも書いたりしました。

知ってますか?Hackいいですよ(今はやってないですが)

 

今回M&AクラウドのCTOである荒井さんにお誘いいただいてジョインする運びとなりました。どういったところに惹かれたのかと言うと・・・

 

まだまだ実装したい機能がいっぱいある

この辺は人手不足と、成長の幅を感じました。

やりがいがありそう!

 

フロントエンド力を高めていきたい

フロントエンドを手探りで学びながらやっているみたいです。

私もフロントエンドエンジニアではないし、前職でもあまりやってないんですが趣味でJavaScript(Vue/Nuxt,Svelte)などを書いていたりフロントエンドへのモチベーションは高いので頑張ってやっていきたいと思います。

 

設計をちゃんと考えていきたい

設計やアーキテクチャなんかは僕も大好物です。みんなで学んで考えて最適解を見出してより変化の強いコードをかければいいなと思ってます。

 

他の社員もスキルアップのモチベーションが高い

毎週UIや設計、フロントエンドのトレンドなどを追って勉強会をしています。

とても向上心のあるメンバーだなぁと感心しています。

 

採用も強化していきたい

作りたいものは多いんですがそれを作るメンバーが足りていません。

絶賛募集中です。 

PHP系の勉強会ではちょくちょく参加させてもらっているんですが、外部の勉強会を通してこの会社をアピールしていけたらいいなと思っています。露骨な宣伝はしませんが、自分が所属していることで認知されていくと嬉しいなと思います。

 

入社後

この会社の事業ドメインを理解するのは大変だと思います。M&Aなので専門用語が多い!それは日々覚えていくよう頑張っています。

で、いきなりドメイン知識の必要な実装はできないので整備されてないものをちょっとずつやるようなタスクを消費してます。

今まではデプロイを各作業者の端末からAWSのebコマンドでElasticBeanstalkを利用したデプロイを採用していましたが、CircleCIによるCI/CDができるように変更したり、途中で放置されていたプルリクエストのLaravel mixをやめて自前のWebpackタスクでJavaScript/CSSのビルドをできるようにする・・・などなどやっております。(この辺は別記事で詳しく紹介できればと思います)

 

イマドキな開発ができる環境を作りつつ、事業ドメインをキャッチアップしていい感じに実装できるマンになりたいと思います。

 

最後に

現在、M&Aクラウドではエンジニアの募集をしております。興味のある方は、是非下記からご応募お願い致します!


https://www.wantedly.com/projects/159995

https://www.wantedly.com/projects/275331