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

みなさん、こんにちは!

先月からM&Aクラウドにジョインしました濱田です。 ネット上では hamakou108 という id で存在してます。

今回は自分が入社するまでの経緯と、実際に入社して分かったM&Aクラウドの良さについて紹介したいと思います。

入社まで

前職ではインターネット回線接続サービスを提供する会社で WEB エンジニアをしていました。

ユーザーの生活インフラに関わることもあり、堅牢なシステムを開発・運用する上で必要な技術が身につく環境でした。 一方で基準を満たしたドキュメントやエビデンスの作成など開発プロセス上の制約も多く、モダンさやアジリティを追求することは難しい環境でした。

そろそろ後者のスキルを伸ばしていきたいと考えていたとき、 Wantedly 経由で CTO の荒井さんからお誘いいただき入社する運びとなりました。

入社してみて

技術やプロセス、コミュニケーションの取り方まで様々な点で変化がありました。 自分にとって特に印象的だった点を3つ挙げてみます。

リリースサイクルの速さ

M&Aクラウドでは週に2、3度のペースでリリースを行っています。 不具合や仕様漏れが入り込まないように、自動テストやレビューは勿論、大きな機能追加の際にはチーム全員で確認会を行っています。

前職では数週間〜数ヶ月に1度のリリースが普通だったので、刺激的でしたね!

アーキテクチャに対するこだわり

速いサイクルで継続的に開発を行うためには、変更に強く、理解しやすいアーキテクチャが必要不可欠です。 M&Aクラウドは DDD や CQRS などの考え方をシステムに取り入れており、レイヤーごとの責務や依存関係に注意を払いながら開発を進めています。

また定期的に勉強会を行い、何か取り入れられそうなプラクティスはないか日々探求しています。

UX について全員で考える

M&Aクラウドの開発チームでは週に一度 UX 会議というものを開いており、世の中の色々な UX を取り上げてサービスに活かせる要素がないか議論しています。 また機能追加にあたってユーザーインタビューを行うなど、プロダクトアウトを避けるための取り組みも行っています。

会社としても『全員UX』というバリューを掲げており、開発チームの外からも積極的にサービス改善提案を受け付け、一丸となって UX の向上に努めています。

今後は

技術的なスキルに限らず、ドメイン知識も膨大な事業領域であるため学ぶことは尽きません。 これから次第に事業の規模も大きくなっていくと思うので、必要な情報を効率良くキャッチアップして事業の成長を支えられるように頑張りたいと思います!

弊社津崎・久保田がYoutube配信のオンライン勉強会で登壇しました。

新型コロナウイルス感染症(COVID-19)による影響で勉強会が自粛されるなか、Youtubeによるオンライン配信を行うケースがあります。 今回は弊社の津崎が2/27 スタートアップ×AWS オンラインLT大会 Coral Developers Night、久保田が2/25 Roppongi.vue #5Youtubeライブ配信でLT枠登壇をしました。

M&Aクラウドにおける
AWS ElasticBeanstalkの活用


津崎からは、弊社のサービス開始時から利用しているAWSのElasticBeanstalkを採用した事例の紹介です。 現在ではElasticBeanstalk以外にもLambdaとAPI Gatewayを利用したページへの移行なども進めています。

Nuxt.jsでCompositionAPIを使う

久保田からは、先述したLambdaとAPI Gatewayへの置き換えを実施しているアプリケーションであるNuxt.jsで、Vue.js version3から導入されるComposition APIを利用して開発をする話です。 現在はトップページをこのNuxt.jsにリプレースしていて、今後も順次Nuxt.jsによるページを増やしていく予定です。

最後に

AWSによるインフラやNuxt.jsによる開発に興味のある方はぜひご連絡ください!

www.wantedly.com

www.wantedly.com

社内勉強会で「現場で役立つシステム設計の原則」を読了しました。

こんにちは、M&Aクラウドのかずへいです。今日は弊社の勉強会の取り組みについて紹介ます。

勉強会について

M&Aクラウドでは、現在週に2度勉強会が行われています。水曜日にはフロントエンド勉強会と題して、主にTypeScriptやNuxt.js周りについて勉強していて、金曜日にはアプリケーション設計勉強会と題して、「現場で役立つシステム設計の原則」の輪読を行っていました。

弊社の提供するM&Aマッチングプラットフォーム「M&Aクラウド」はこの本に一部影響を受けて設計されている箇所があるので、メンバー全員に読んでもらっています。

一人で読むだけではなく、開発チームみんなで輪読することによって、「うちのコードのこの部分ってこの考え方で設計されているよね」「いまはこの設計になっているけど、こうしておけばもっと良かったかもしれないね」といった話しで盛り上がり、実際にその場でプログラムを一緒に読んだり書き換えたりということが起きるのでなかなかに有意義です。

本の内容の実践

実際にM&Aクラウドでは以下を実践しています。

  • ファーストクラスコレクション
  • 画面とオブジェクトの設計を連動させる
  • サービスクラスを分ける

ファーストクラスコレクション

ファーストコレクションクラスは配列などのコレクションを独自のクラスとして定義する考え方です。配列をそのまま使ってしまうと、その配列に大してロジックを書くことが出来ません。

同じ配列でもListとListで持つべきロジックは当然違うはずですよね。それをHumanList、ItemListとしてそれぞれクラスを作り、そこにロジックを書いていくという方法です。

qiita.com

このサンプルコードでは\IteratorAggregate, \ArrayAccess, \Countableを実装してクラスが配列として振る舞えるように実装しています。isEmpty()のような関数は配列にはありませんがファーストクラスコレクションにすると自分で足すことが出来ます。

M&AクラウドPHPで書かれていて、PHPにはGenericsが無いのでこういうコードを書くとロジックが重複しやすいという問題もありますが、そこは継承やtraitでうまく避けています。

画面とオブジェクトの設計を連動させる

どこまでがオブジェクトの知識でどこからが画面の知識なのかというのは、設計でよく議論になることかとは思います。M&Aクラウドでは、部分的にはありますが、この資料のような方法でオブジェクトの値を利用して画面が切り替わるように設計しています。

speakerdeck.com

サービスクラスを分ける

M&AクラウドではApplication層に

  • QueryService
  • CommandService
  • ScenarioService

という3つのサービスを作っています。ScenarioServiceクラスは買い手、売り手といったユーザー属性ごとに作られていて、ScenarioServiceがControllerに対してAPIを提供しているような形になっています。ControllerはScenarioServiceしか呼びません。

ユーザー属性ごとにScenarioServiceを作ることにより、Controllerは呼ぶべきScenarioServiceが決まっているので、本来そのユーザーが呼べない関数を呼ぶというようなことが無いのが良い点だと思っています。

まとめ

設計についての本をチーム全員で読むことにより、共通の認識が生まれます。 今の設計も人が考えたものも誰かが考えたものであって、より良い設計があればそれに変えていけるというふうにメンバー各人が理解して、今の設計を神格化しないというのが重要だし、そのためにも共通の認識づくりは大事ですね。 輪読するとたくさんのアイディアが出て良いです。

次の題材

次回からはこちらの本を読み進めていこうと思います。

imgixの活用

こんにちは、M&Aクラウドのかずへいです。

M&Aクラウドではimgixという画像配信のSaaSを活用しています。サービス開始当初から導入していますが、端的に言って神サービスなので紹介できたらと思います。

imgixとは

imgixは画像配信のSaaSで、画像をリアルタイムに変換する機能とその結果をCDNに保存し配信してくれる機能を持っています。画像にアクセスする際、クエリパラメーターに画像の変換用のパラメーターを渡すと、その通りに画像を変換してCDNにキャッシュしてくれます。どんな感じで画像が変換されるかはここで簡単に試すことができます。最近だと国内ではさくらインターネットとPixivが出しているImageFluxが、ほぼ同様のことが出来るのでは無いかと思いますので、こちらでも良いかもしれません。

imgixを導入しているサービスには、Qiitaや日経電子版等があります。

利用料金は配信量と、サムネイルのマスターサイズの種類の数による従量課金です。

画像配信のよくある課題

弊社のM&Aクラウドはマッチングプラットフォームですが、買い手企業様を掲載するという点ではメディアサービスとも言えます。実際に企業様に取材させていただいて、プロのカメラマンが撮った写真を掲載させていただいてます。

画像の配信では、

  • 画像のサイズやフォーマット等はクライアントやデザインによって適切なものが変わるので事前に固定したくない
  • 画像を速く返すためにCDN使いたい

といった課題があると思いますがimgixではちょっとした設定だけでこれらを解決することができます。

imgixの導入

弊社ではAWSのS3を元画像の置き場として設定しています。

f:id:kazuhei0108:20200209232853p:plain

imgixはS3から取ってきた画像をリアルタイムに変換しクライアントに返します。一度変換された画像はCDNに保存され、以降、全く同じ画像がリクエストされた場合にはCDNから画像を返却します。imgixが必要に応じて画像を変換してくれるので、S3には変換元の画像を1つだけ用意しておけば、リサイズしたり、クロップしたりして様々なバリエーションのサムネイルを生成することができます。

また、formatを指定することで、スマホにはWebPで変換したり、dpiを指定したりといったこともできます。

M&Aクラウドではサービス開始時からimgixを利用していますが、導入以降全く設定を変更せずに運用し続けていまして、しかも障害なども起きたこともありません。利用料もとても安く抑えられており、とても助かっています。

まとめ

imgixは画像変換機能とCDN機能がついたSaaSでとても便利で、手軽な設定ですぐ使えます。おすすめですのでぜひ試してみてはいかがでしょうか?

PHPerkaigiイベントレポート(LTで登壇もしました)

こんにちは。エンジニアの@yamotukiこと鈴木です。 昨日、PHPerのためのカンファレンス PHPerKaigi2020 に参加してきました。

phperkaigi.jp

私もLTのスピーカーとして登壇させていただきました。

他の日は残念ながら都合がつかず、最終日のday 2 昼頃から参加させていただきました。

聞いたセッションについて

全部ちゃんと感想書くと長くなってしまうので、特に印象に残った内容だけ書いておきます。

クリーンな実装を目指して by Hamee株式会社

ランチ提供のHamee株式会社さんによるランチセッションでした。

印象に残っている話(うろ覚えのやつ) => 色々なシチュエーションで出てくる商品の画像更新処理について。同じような情報を触るのに、更新の入り口が複数あって保守が大変なことになっていた。それを「画像差し替え」集約ルートを導入することにより整理。
まず関連する処理についてドメイン的な文脈で集めてきて、流れを整えてレガシー改善していくとっかかりにしているのだなと受け取りました。

懇親会で登壇者のお二人とお話しさせていただいて印象に残っていること => 「ランチセッションだからみんなもぐもぐしててそんな聞いてないから気軽に発表して、と20分枠だったが、みんな食べ終わってガチで聞いてた。大変だった。」
新卒2年目のお二人にとっては大変だったと思いますが、お疲れ様でした。

ぼっちからはじめるレガシーカルチャー改善ガイド 〜はじめの一歩編〜 by blue_goheimochi

レガシー文化の中にあるレガシーコード。まず仲間を集めて文化から変えていこうというセッション。
青ごへいもちさんが根気よく周りを巻き込んでいたのがよくわかりました。めっちゃ人格者。

一方で、Q&Aで出た"どうしても変わらない人相手にどうしたらいいですか?"みたいな話の流れで「そいつはドアではない。壁だ。」との発言で爆笑を誘っていたのが印象的でした。 ほとんどの人はドアなので根気よく長い時間をかけて当たっていくのも良いものなのだなあと思わせてくれる話でした。

PHP未経験者を育てる独自フレームワークの作り方 by kanbo0605

新人研修の一環として、フルスタックフレームワークを使わずに、自分で素のPHPを使ってフレームワークを書いてみることによりレベルアップさせられるよ、というお話。

多少誇張だとは思いますが 新人「CSRSトークンとかいうのでエラーになっていたので消しておきました!」 とか極端な話で笑いをとっていたのが、真似をしてみたいと思うセッションでした。

オレオレフレームワークを作ると成長できるという話は他でもちらほら聞くので、私もいつかやってみたい。

RFCの歩き方 by YKanoh65

RFCはとっつきにくいけど、構成さえわかってしまえば案外読めるのだよ、というお話。

特にRFCの概要部分は、それを書く人向け資料に "ここはよく読まれるところだから気合いを入れて書くように" と書かれているらしい。私も気合いを入れて読もうと思いました。
あとは status の部分が大事だというところで、"status: implemented" だったら次のバージョンで確実に入るものだから特に自分に関連があるとか、新しい視点をもらいました。

発表の残り時間を逆手に取った笑いを取る手法は必見です。

発表した内容について

発表の様子

資料 speakerdeck.com

LeetCodeという世界の企業のコーディング面接の過去問をWeb上で解けるサイトがあります。 このサイトで100問題解いてみたよ、という内容になります。 多くの問題をPHPで解いて言語実装や速度改善の方法を学んでいるので、PHPerKaigiで話すにはぴったりかなと思って応募しました。

社会人になって初めての会社外での登壇でしたが、申し込みをした時に想定していた10倍くらい聞いてくださる人がいて、大変緊張しました。(LTなので小さい会場かな?とかなんとなく思っていました)

発表の前のラウンドテーブルでたまたま ytake さんと初めましての挨拶をさせていただく機会がありました。 その時に”発表の秘訣を教えてください”と質問したところ「発表で3回笑いが取れたら成功だと思うよ」と言っていたのが印象に残っています。 残念ながら1.5笑いくらいしか取れなかったので、次回はもっとみんなが聴きたくなるような発表を心がけたいと思います。

謝辞

良いコミュニケーションと気づきの場を与えてくれたPHPerKaigiのスタッフのみなさま、ありがとうございました! また、会場で話しかけた時にオープンマインドで受け入れてくれた参加者のみなさま、ありがとうございました。今後もPHP関連カンファレンスで会うことも多いかと思いますが、その時はよろしくお願いします。

DX向上のためにPull Pandaを導入しました

f:id:zacky2:20200128190429p:plain

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

今回は、Pull Pandaというツールを導入して2ヶ月ほど経過して、DX向上を感じられたので便利な点を紹介したいと思います。

Pull Pandaとは

Pull PandaはGitHubを使っているチームのためのツールです。 2019年6月にGitHubに買収され、誰でも無料で利用できるようになりました。

pullpanda.com

Pull Pandaは、3つの機能があります。

Pull Reminder

Pull Reminderは、GitHubのpull requestのレビューとマージについてSlackでリマインドと通知をしてくれる機能です。

Pull Analytics

Pull Analyticsは、レビューにかかった時間や、オープンしているPR数の遷移などを分析、視覚化してくれる機能です。

f:id:zacky2:20200128164325p:plain f:id:zacky2:20200128164014p:plain

Pull Assigner

Pull Assignerは、PRのレビュワーを自動でアサインしてくれる機能です。

Pull Pandaの活用

我々のチームでは、Pull Pandaの3つの機能のうち、Pull Reminderを活用しています。

Pull Analyticsは、組織の運営状況の把握や改善に役立つデータが閲覧できるため、活用していきたい機能ではありますが、 まだチームが小さく、データ集計の期間も短いため、活用には至っていません。

Pull Assignerは、円滑なPRレビュー体制を構築できるため注目している機能ではありますが、 現在の我々のチームは、小さなチームに分かれて相互レビューする体制で進めている関係でまだ活用には至ってません。

Pull Reminderは、小さなチームでもすぐに導入できて、すぐに価値が発揮される機能であるため導入しました。

Pull Reminderの活用

Pull Reminderのメリット

  • 今までは口頭でレビューを依頼したりリマインドしたりしていたが、自動でできるようになってレビュー漏れがなくなった
  • レビューのマージ速度が上がった(体感)

チームへの通知設定

Pull Pandaでは、開発者をチームという単位にグルーピングすることができます。 Pull Reminderの設定もチーム単位で行うことができます。

チームへの通知では、指定した曜日の指定した時間に、レビューリクエストされてるPRをリマインドしてくれます。 f:id:zacky2:20200128164402p:plain

我々のチームでは#developersチャンネルに平日の10時と16時にリマインドが送信されるように設定しています。

個人設定

個人に送るSlack通知・リマインドについて設定できます。

  • あなたがレビューにアサインされた時
  • あなたのチームがレビューにアサインされた時
  • あなたのPRが承認されたか変更をリクエストされたとき
  • あなたがAssigneeになったとき
  • あなたのPRがマージされた時
  • あなたのPRにコメントされた時
  • あなたがコメントでメンションされた時
  • あなたが参加してるスレッドにコメントされた時
  • あなたのPRにマージ競合があるとき
  • あなたのPRのCIチェックが失敗した時

個人へのリマインドも、曜日と時間を設定することができます。

まとめ

Pull PandaのPull Reminderを導入することで、以下のようなメリットがありました。

  • レビュー依頼のコミニュニケーションコストの低減
  • コミニュニケーションロスの低減
  • PRのマージ速度の向上

まだ活用していないPull Assigner, Pull Analyticsについても、チームが拡大した時に効力を発揮しそうだと期待しています。

最後に

M&Aクラウドでは、日々よりよい開発体制を築きながら、プロダクト開発を行っています。 一緒にプロダクトを成長させてくれるあなたの応募を待っています!

www.wantedly.com

www.wantedly.com

企業一覧ページのレスポンスを速くする取り組み

f:id:kubotak:20200117095822j:plain

こんにちはkubotakです。

今回は弊社で運用・開発しているサービス「M&Aクラウド」の積極買収企業一覧ページの速度改善の話をしたいと思います。 前職でも速度改善プロジェクトをやってましたが、昨今のWebサービスが抱える大きい課題ですね。

まずは今までのアーキテクチャから説明します。

今までのアーキテクチャ

f:id:kubotak:20200116110759p:plain
今までのアーキテクチャ

企業一覧ページは検索機能も持っています。 初期表示の全件表示と検索による絞り込み表示が行なえます。

検索するために全文検索エンジン・データベースであるElasticsearch(以下ES)を利用しています。 定期実行バッチによって検索に必要なデータを同期しています。

そして、検索された際にはヒットしたIDの一覧を取得し、そのIDをもとにRDBMSからデータをIN句を利用して取得して表示しています。 つまり、検索用とデータ用は分離しているように見えて、データ取得時には依存関係にあり、分離できていない状態といえます。

また、データの取得処理での速度犠牲として弊社が採用しているLaravelのORMであるEloquentが大きく関わってきます。

f:id:kubotak:20200116103403p:plain

Eloquentでは別のテーブルにあるデータをJOINする際に、実際にはSQLでのJOIN句ではなく、データを取得する際に依存しているテーブルにIN句を利用して取得したデータをマッピングします。 先程のESとRDBMSの関係と似てますね。

データが多ければ多いほど取得処理がより遅くなるという仕組みです。

変更したアーキテクチャ

f:id:kubotak:20200116103440p:plain
変更したアーキテクチャ

要するにRDMBSのデータを参照せずに、ESから取得したデータだけで画面を生成することができればロスを減らせるというわけですね。 これはCQRSの考え方によるもので、入力するデータと取得するデータのデータベースを分離している状態です。

これを実現するためにはESに画面表示に必要なデータも格納しておく必要があるので、定期実行されるデータ移行バッチを修正して対応しています。 弊社ではある一定の間隔でこのバッチを実行しているのですが、もしリアルタイム性が必要であれば何らかのメッセージングシステムを利用することで実現できると思います。

そして、ESから取得したデータは今まで利用していたドメインロジックを経由することなく、クエリ専用のDTOマッピングさせて画面で利用しています。

改善後

f:id:kubotak:20200116104619p:plain
改善前

f:id:kubotak:20200116104640p:plain
改善後

TTFB(Time to first byte)までの時間が3.32secから679msに改善されました。 現在ページネーションなどを導入せず、すべての要素を表示しているのでまだまだ速度改善としてやれることはありますが、バックエンドの改善だけでも十分な速度改善となりました。

最後に

速度改善だけでなく、一緒にプロダクトを成長させてくれるメンバーを募集しています。

www.wantedly.com

www.wantedly.com

デプロイの半自動化をして楽で安全にリリースできるようにした話

f:id:yamotuki:20200108120317j:plain

こんにちは。エンジニアの鈴木智也です。 今回はデプロイの効率化を通してDX: Developer Experience (開発体験)を向上させ、デプロイの安全性を高めた話です。

ボタン一つで開発環境へデプロイ、さらにボタン一つで本番環境へデプロイできるようになりました。 背景と技術概要について記述します。

背景

弊社ではWebサーバとしてAWS ElasticBeanstalk(以下EBと呼びます)を採用しています。 EBにおいては、eb deployコマンドやAWS Console のGUIから簡単にコードをデプロイすることができます。 弊社では以下のステップでデプロイを行なっていました

  1. eb deploy <EB開発環境名> で開発環境にデプロイ
  2. 開発環境サーバにSSHログインして手動で migration とキャッシュクリア
  3. 機能が正しく動いていることを確認
  4. AWS Console から本番環境にデプロイ
  5. 本番環境サーバにSSHログインして同様のコマンド

問題点として以下のものがありました

  • 手元から eb deploy コマンドを打つときに環境名を指定しなければいけないが、誤って本番環境を指定しまって意図しない本番デプロイが発生する可能性があり得る。危険!
  • 開発・本番ともにSSHログインしてmigrate, cache clearコマンド打つのがめんどくさい
  • 本番デプロイにおいては特にコードが入った時点でタイミングを見計らって migrationとcache clearを行わなければいけない。
    • DBのレコードからLaravel Eloquent経由でドメインオブジェクトにマッピングを行なっている
    • そのためドメインオブジェクトを作るコードを変更した場合には、コードがサーバに入った時点でレコードも追従している必要がある
    • しかし migration ファイルはコードとともにサーバに配置されるので、migration ファイルが置かれた = コードが入ったタイミング を見計らって migrate しなければいけない
    • これが遅れるとmigrateを実行するまでの間サーバエラーになる

これらの問題があったことにより、デプロイは心理的負荷の高い作業になってしまっていました。

改善方法

EBのCLIコマンドとCircleCI Workflow を組み合わせることで、自動テストからの流れでボタンクリックだけでデプロイをできるようにしました。 これにより環境の取り違えは起こり得ないようになりました。もう安全!

具体的には以下のようなCircleCIの画面で待ちになっている状態のところをクリックすれば次のステップに進むようになります。

f:id:yamotuki:20200108105645p:plain
デプロイフローの図

本番デプロイができる条件は、2020-10-01 などの形式のリリースタグに対応するCircleCI Workflow でなければいけないように制限をしました。具体的なCircleCIの設定ファイルの書き方については以下の記事を参照してください。 qiita.com

migration の問題についても改善しました。 ebextensions で設定することにより、EBデプロイのソースコードが抽出されたタイミングで自動実行されるようになりました。これでもうリリースにつきっきりでタイミングを計るだけの開発者はいなくなりました。具体的な ebextension の設定ファイルの書き方については以下の記事を参考にしてください。

qiita.com

改善した結果

これでもう環境の取り違えも、コマンドの打ち忘れも起こりません。 心理的負荷も下がったので、リリースやると疲れて他のことをやる気力が失われる、という状況もかなり緩和されました。

DX上がった!

最後に

我々は、一緒にDX向上してくれるエンジニアを随時募集中です。 www.wantedly.com

www.wantedly.com

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