Nuxt道場 弐面を開催しました🎉

f:id:kubotak:20210910162946p:plain

こんにちは久保田(@kubotak_public)です

2021/09/08 19:30よりNuxt道場 弐面を開催いたしました。
弐面は第二回という意味です。

記念すべき第一回の様子は以下です。

tech.macloud.jp

今回は弊社の津崎が登壇しました。
弊社のエンジニアはもともとフロントエンドを書いて来たエンジニアではなく、どちらかというとインフラやバックエンドがキャリアとしては多いです。
そんな我々も今ではNuxt.jsをTypeScriptを用いて開発しています。
今ではゴリゴリにTypeScriptを書いている津崎の発表を是非御覧ください。

以下イベント配信のアーカイブ動画です。 youtu.be

Nuxt.js x Composition API x TypeScript - Speaker Deck

また、弐面ではベースフード株式会社よりVPoE 煙草森直也さんが師範として登壇いただきました。
Shopifyとの連携した決済システムなど、なかなか聞くことのできない貴重な発表でした。
現在エンジニア募集中とのことです。気になる方はぜひチェックください)

その他、弊社プラットフォームM&Aクラウドを利用して資金調達をされた株式会社Re:Build 代表 鈴木孝之さんのMiddrewareの権限周りの大変だった話や、イベント初の道場破りtyamahoriさんのDocker Desktop on MacによるNuxtの開発Tipsの話など盛り上がりました。
配信は全てアーカイブとして残っていますので今からでも閲覧できます。ぜひご視聴ください。

Nuxt.jsのmiddlewareを使って権限チェックしたらスパゲティになってしまった話 - Speaker Deck

qiita.com

謝辞

配信をご覧くださった視聴者の皆様、また登壇をしていただいた皆様には感謝いたします。
今回の配信では私の配信環境によるトラブルで二度ほど配信が途切れることがあり大変申し訳ありませんでした。
(リモートワークのため自宅から配信してますが機材の見直しなど必要かもしれません・・・)

最後に

二度あることは三度あるということで、登壇したいという方がいらっしゃいましたらぜひ久保田までお声がけください。

M&AクラウドのPHP Conference 2021登壇速報!

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

先日、PHP Conference Japan 2021 のプロポーザル当落が発表されましたね! 今回、弊社はゴールドスポンサーもしております。

スポンサーでもトークでも盛り上げていくぞ!

全員インフルエンサー

弊社のエンジニアチームでは「全員インフルエンサー」という言葉があり、今回も全メンバーがプロポーザルを出しました。 全員インフルエンサーについては以下の記事を是非御覧ください。

tech.macloud.jp

当落発表の日はこのように各メンバー一喜一憂しておりました。

f:id:kazuhei0108:20210826235446p:plain
一喜一憂する人たち

運営さんありがとうございます!

登壇内容

それでは早速ですが、登壇内容を紹介していきます!

[ Sponsored LT ] LaravelとAWSで漸進的なプロダクト開発

fortee.jp

M&AクラウドではPHP、LaravelとAWSを使ってM&Aのマッチングプラットフォーム「M&Aクラウド」を開発しています。サービスリリースから徐々にアプリケーションとして成長していく過程でどの様な技術を組み合わせて課題を解決してきたかを、短い時間ですがご紹介させていただきます。

[ Regular Session (25 mins) ] LaravelとTailwindCSSで始めるコンポーネント指向UI

fortee.jp

Laravel7系から導入されたBlade Componentsと近年注目されているUtility FirstをコンセプトとしたTailwindCSSを利用して再利用性の高いコンポーネントの作り方を紹介します。 Blade ComponentsはVue.jsのSFC(Single File Component)のような使い方をBladeで実装できる機能です。 対象者はこれからLaravelを触る方やまだLaravel7系以前の@extend,@yield,@sectionを利用してレイアウトを作ってる方となります。

[ Regular Session (25 mins) ] 【IMO】コードレビューって難しいよね

fortee.jp

みなさんのチームでは日頃からコードレビューはされてますか? 弊社でもリリースするコードに対して2人以上のコードレビューを必須にしたりと活発に取り組んでいます。

コードレビューには以下のような効果が期待できます 「ソフトウェア品質の向上とアーキテクチャの統一」、「スキルの向上とナレッジの共有」 いかに効果的にコードレビューを実施するかによって、チームの成熟度やプロダクトの品質に影響すると言っても過言では無いかもしれませんね。

しかし、正直なところ自分はコードレビューに苦手意識がありました。 一度のレビューに時間がかかったり、他のメンバーと比較してコードの改善提案をする回数が少ないのです。。。 そんな私が苦手意識のあるコードレビューをどの様に克服していくのか、体験談を踏まえてお話しできればと思います!

[ Regular Session (25 mins) ] Repositoryパターンを維持しながらN+1問題を起こさないようにする方法論について

fortee.jp

速度は求めたい。ユーザのためである。 設計方針は崩したくない。開発者のためである。 「速度も求めつつ、既存の設計方針を守り、ユーザに価値を届ける。そんな方法が欲しい。」

こちらはそんな思いから生まれたテクニックを紹介するセッションです。

[ Lightning talk (4 mins) ] 【超特急】「SQLアンチパターン」 総おさらいLT 【4分で25個】

fortee.jp

PHPといえば、Web開発。 Web開発と切っては切り離せないのが「データベース」と「SQL」です。

このトークは、オライリー・ジャパン出版の名著「SQLアンチパターン」で紹介されている25のアンチパターンを「超特急」で学ぶものです。 わずか4分のLTで、25個のアンチパターンをおさらいします。 東京2020オリンピックのピクトグラムパフォーマンスのようなスピード感のある超特急LTをお楽しみください。

大事なところだけをギュッとして、明日からすぐ使える知識としてお届けできたら幸いです。

まとめ

いかがでしたでしょうか?どれか一つでも聞いてみたいトークはありましたでしょうか? 2021/10/02 - 10/03はぜひPHP Conference Japan 2021でM&Aクラウドのメンバーとお会いしましょう! カンファレンス当日はスポンサーツアーも行われるということで、弊社について直接質問などありましたら、ぜひお気軽にしていただければと思います!

また、弊社ではエンジニアの採用を行なっています。 ベンチャー企業でのWeb開発に興味のある方は、ぜひカジュアルにご応募ください🤝

www.wantedly.com

www.wantedly.com

それではみなさん、カンファレンスまでもう1ヶ月です!頑張って発表資料作りましょう!

Vue.js で入力フォームに Google reCAPTCHA v2 を埋め込む

f:id:hamakou108:20210802213420j:plain

Vue Composition API-0.3 Nuxt-2.1 TypeScript-3.7

こんにちは。エンジニアの濱田( @hamakou108 )です。

今回は Vue.js で作成した入力フォームに Google reCAPTCHA v2 を埋め込むコードを書く機会があったので、その実装例を紹介します。 またその際に利用した vue-recaptcha というライブラリについても軽く紹介します。

はじめに

  • 本記事執筆時点では vue-recaptcha は v2 のみ対応しています。
  • reCAPTCHA へのサイトの登録、サーバーサイドでのトークンの検証に関しては本題から逸れるため割愛します。

背景

M&Aクラウドの幾つかの入力フォームでは、スパムなどの不審なリクエストへの対策として Google reCAPTCHA を導入しています。 一方、以前からフロントエンドの Nuxt.js 移行を進めており、これらのフォームについても移行を行いました。

tech.macloud.jp

旧ページで reCAPTCHA を埋め込んでいた箇所では HTML のフォームによる POST を行っていました。 この場合はドキュメントにある通り、フォーム要素内に g-recaptcha タグを埋め込むだけで事足ります。

一方、 Nuxt.js の新ページでは API による POST を使用しています。 旧ページと同じ手法は使えないため、実装方法を再検討する必要がありました。

reCAPTCHA 埋め込みの実装

vue-recaptcha の利用

先人の知恵がないかググってみたところ、 vue-recaptcha というドンピシャなライブラリがありました。

github.com

vue-recaptcha は reCAPTCHA を埋め込みたいページにコンポーネントを埋め込むだけで利用できます。 また reCAPTCHA のオプションについては v-bind で設定でき、検証の成功やエラーのイベントも v-on でハンドリングできるので便利です。

vue-recaptcha は reCAPTCHA v2 にのみ対応していますが、弊社で利用しているものも v2 のみだったため、特に問題なく採用することができました。 またフロント移行が進むにつれて reCAPTCHA を使用するフォームが増えることが予想されたため、最低限の知識で reCAPTCHA を埋め込めるようなコンポーネントを vue-recaptcha をラップして実装しました。

実装したコンポーネント

以下のようなコンポーネントを実装しました 1

<template>
  <vue-recaptcha
    ref="recaptcha"
    :sitekey="sitekey"
    size="invisible"
    :load-recaptcha-script="true"
    class="recaptcha"
    @verify="onVerify"
  ></vue-recaptcha>
</template>

<script lang="ts">
import VueRecaptcha from 'vue-recaptcha'
import { defineComponent, ref, SetupContext, toRefs, watch } from '@vue/composition-api'

export default defineComponent({
  components: {
    VueRecaptcha
  },
  props: {
    submit: {
      type: Boolean,
      default: false
    }
  },
  setup(props, { emit }: SetupContext) {
    const { submit } = toRefs(props)
    const recaptcha = ref<InstanceType<typeof VueRecaptcha> | null>(null)
    const sitekey = // サイトキーを設定
    const onSubmit = (): void => {
      if (submit.value) {
        return recaptcha.value?.execute()
      }
    }
    const onVerify = (response: any): void => {
      emit('verify', String(response))
    }
    watch(submit, onSubmit)

    return {
      recaptcha,
      sitekey,
      onVerify
    }
  }
})
</script>

<style src="./recaptcha.scss" lang="scss" scoped></style>

以下、要点を説明します。

reCAPTHCA の実行

vue-recaptcha を使って reCAPTCHA の認証を実行する際は VueRecaptcha コンポーネントexecute メソッドを呼び出します。 呼び出しタイミングをロジック側で制御したいため、 template refs を使ってコンポーネントインスタンスrecaptcha という定数に格納し、 recaptcha.value?.execute() のような形で呼び出せるようにしています。

props の submit は親コンポーネントが reCAPTCHA を呼び出したいタイミングで true に変更されることを期待しています。 submitwatch で監視しているため、 true に更新された際に onSubmit メソッドが呼び出され、 reCAPTCHA の認証が実行されます。

reCAPTCHA の認証トークンの受け取り

reCAPTCHA の認証が成功すると VueRecaptcha コンポーネントから verify イベントが emit されます。 reCAPTCHA のレスポンスも一緒に渡されるので、それを文字列に型変換して親コンポーネントに emit します。 親コンポーネントではこのレスポンスを POST API のパラメータに含めることができます。

reCAPTCHA 実行用スクリプトの埋め込み

本来は reCAPTCHA の共通的な導入手順として実行用の JavaScript<script> タグで埋め込む必要があります。 しかし vue-recaptcha には<script>タグの inject 機能があり、 props に :load-recaptcha-script="true" を渡すことで必要なタグを自動的に <head> 内に追加してくれます。

まとめ

vue-recaptcha を利用して

  1. reCAPTCHA の起動が必要なタイミングで submit props の値を true にする
  2. verify イベントで reCAPTCHA のレスポンスを受け取る

の2つの手順のみで reCAPTCHA を埋め込むことができるコンポーネントを実装しました。 Vue.js で作成した web ページに reCAPTCHA を埋め込みたい方の参考になれば幸いです。

おわりに

M&Aクラウドではデザイナーやエンジニアを募集しています! 是非お気軽にご連絡ください!

www.wantedly.com

www.wantedly.com

www.wantedly.com


  1. Vue.js の Composition API 0.3 による実装のため、バージョン 1.0 以降の記法と異なる場合があります。

開発大臣制度とMACテック勉強会、あるいはフルスタックVSスペシャリスト

f:id:zacky2:20210718234003p:plain

どうもこんにちは、エンジニアの津崎です。

梅雨が明けて、モワっと蒸し暑くて気が狂いそうですね。

夏といえば、海。 海といえば「開発大臣制度」と、MACテック勉強会」でございます。(?)

そんなわけで今回は、今年から実験的に開始された「開発大臣制度」と、MACテック勉強会」についてご紹介したいと思います。

テクノロジーの力でM&A流通革命

f:id:zacky2:20210719002754p:plain

弊社のエンジニアチームでは、全ての作業を全員ができるように専門分野というものをあえて作らずにタスクを分配しています。 今までのフェーズでは「他のWebサービスにあるような便利な機能」をいち早く作ることが求められていました。 そのため、特別何かに詳しい必要はなく、エンジニア全員が「Webサービス開発」に詳しければ問題はありませんでした。

テクノロジーの力でM&A流通革命

この言葉は、弊社のミッションです。

Webサービス開発」に詳しいだけで、ミッションを実現できるのか?

私たちは、「革新的なサービスを作るには、新しい技術や深い専門知識をベースとした機能提案が必要である」と考えました。 その考えに基づき、新しい技術や専門知識をキャッチアップするために生まれたのが「開発大臣制度」です。

開発大臣制度

開発大臣制度とは、弊社のM&Aプラットフォームに関連するテクノロジーについて、各エンジニアが担当(=大臣)となり、そのテクノロジーについて独自に調査を行うというものです。 (チーム内で担当のことを大臣と呼ぶのが流行っています) それぞれが自由にいろんなことを調べるより、分野を区切り、分野ごとの担当を決めることで、効率良く知識レベルが上がることを期待しています。

弊社のM&Aプラットフォームに関連する技術は、CTOの荒井が以下のように分類しました。

  • ログ集計と分析
  • 検索
  • レコメンド
  • queue、メッセージ、非同期処理
  • セキュリティ
  • 外部API連携・スクレイピング

MACテック勉強会

大臣がそれぞれの担当技術について、社内のエンジニア(およびPdM、デザイナー)に知見共有する場が「MACテック勉強会※」です。 (※MACM&Aクラウドの略称)

週に一度、1時間の枠で行っています。各技術について3回行う想定で実施しており、これまで3回実施しました。

「レコメンド」

「レコメンド」の分野はCTOの荒井が担当しました。第一回は「レコメンドシステムとはなにか?」という話から、具体的なレコメンドアルゴリズムの解説について学ぶ内容となっておりました。

聞きかじったことのあるワードはありましたが、体型的に学んだことはなかったので勉強になりました。

f:id:zacky2:20210719110505p:plain
スライドタイトル
f:id:zacky2:20210719110500p:plain
目次
f:id:zacky2:20210719110731p:plain
強調フィルタリングの図解
f:id:zacky2:20210719111130p:plain
数式が載っていてかっこいいページ

「ログ集計と分析」

「ログ集計と分析」の分野は私が担当しました。第一回はデータ分析やビッグデータ分析基盤についての概要や他社事例について発表しました。 データレイク、データウェアハウス、データマートなどの分析基盤の構成要素についてや、実際の製品などについて紹介しました。

次回は、実際にRedShiftやAthenaなどの製品を使った具体的な紹介ができたらと思っております。

f:id:zacky2:20210719005043p:plain
スライドタイトル

f:id:zacky2:20210719103746p:plain
分散処理の図

f:id:zacky2:20210719103742p:plain
分析システムの全体像
(画像はデータ収集の基本と「JapanTaxi」アプリにおける実践例 こちらから引用)

f:id:zacky2:20210719103755p:plain

f:id:zacky2:20210719103751p:plain
データ分析のフロー

フルスタックVSスペシャリスト

私たちのチームでは、基本的には、全ての仕事を皆ができるようにフルスタックなスキルを求めています。 しかしながら、Web開発の技術だけではテクノロジーの力でサービスの爆発的なグロースを起こすことはできません。 一方で、私たちのような小さなチームでは、完全に分業スタイルではスムーズな開発ができません。 そこで、「開発大臣制度」というフルスタックにスペシャリストをちょい足しするという手法をとりました。

キャッチーなタイトルにするために「フルスタックVSスペシャリスト」をつけたことをここでお詫びします。すみませんでした。

おわりに

今回は、今年から実験的に開始された「開発大臣制度」と、「MACテック勉強会」についてご紹介しました。 「テクノロジーの力でM&A流通革命を」というミッションに従い、関連技術についてエンジニアそれぞれが担当をもち専門性を深める施策「開発大臣制度」。 そして、身につけた専門性をチームに共有する「MACテック勉強会」。 この施策がうまく機能するかまだ不明ですが、色々なことを試しながら、M&A×テクノロジーで最先端をいくエンジニアチームになれるよう努力していきます。

おっと、もしかして僕たちに興味がありますか?

なんということでしょう! M&Aクラウドでは共に働く仲間を募集しているようですよ!

www.wantedly.com

www.wantedly.com

M&Aクラウドで実践している不具合対応フローをご紹介します

f:id:tsukahara1991:20210709173755j:plain
不具合対応中

こんにちは、塚原(@AkitoTsukahara)です。

サービス開発を続けていると対策していても大なり小なり不具合が発生してしまいます。そのため、早期に不具合を発見して、少ない被害に抑えることが大切になります。(もちろん、不具合が発生しないことが一番!)

弊社では不具合を早期発見できるように2つの仕組みを用意しています。
1つは以前もご紹介したRollbarを利用したアラート検知する仕組みです。
Rollbarについて詳しく知りたい方は、こちらの記事をご覧ください。 tech.macloud.jp

もう1つは、非エンジニアでも不具合をSlackから報告できる仕組みです。今回はこちらの仕組みについて、ご紹介します。
弊社では非エンジニアでも不具合を報告できる「バグかもしれない報告」というSlackチャンネルを用意しています。ここでエンジニアは報告を受け取り、不具合を解消していきます。

不具合と言っても、サービスが停止してしまうような大規模障害もあれば、一部のユーザにのみ影響する不具合もあります。 緊急度に応じて対応方針が変わってくるのですが、その都度チーム間で対応方針を相談することでコミュニケーションコストが高くなり、障害対応の初動が遅れてしまう問題がありました。

そのため弊社では、不具合発生時の対応フローをまとめ、スムーズな対応ができるようにしています。

対応フロー

下の図は実際に弊社で共有されている対応フローになります。

f:id:tsukahara1991:20210712004022p:plain
不具合フロー

ポイントになるステップを補足させていただきます🙋‍♂️

「バグかもしれない報告」をSlackで受け取る

Slackのワークフロー機能を活用し、一定のフォーマットに沿って報告をしています。

f:id:tsukahara1991:20210711233414p:plain
バグかもしれない

ユーザ影響の調査を行う

不具合の影響度によって、早急に対応が必要なものかどうかをエンジニアが判断します。 影響度のポイントは「後戻りのできないユーザ影響なのかどうか?」
もう少し具体例を加えて説明させていただくと、

  1. サイト外に影響して取り返しのつかないもの
    ・ユーザへ重要な通知が届かない
    ・データベースに登録されるデータが欠損する etc

  2. ユーザ行動に影響する
    ・入力フォームの不具合で申し込みが進まない
    ・ログインできない etc

上記の2つが主な指標になります。 この判断が難しい場合は、他のエンジニアに相談するようにしています。

ユーザ影響高の場合

この場合は即日対応を行います。通常差し込みタスクが発生した場合はPMに対応すべきか確認するルールになっていますが、ユーザ影響高の場合は、エンジニア判断で不具合修正を進めて良いことになっています。エンジニア側で影響度を見極めて対応できることで、不具合発生時の初動を早めることが可能になっています。

まずはフローに沿って、早急にPMに不具合に関する情報共有を行い、報告を行ったエンジニアは取り掛かり中のタスクを一旦そのままにして不具合の対応に入ります。

ユーザ影響高ではない場合

この場合は対応タイミングをPMと確認することが必要になります。 弊社は2週間を1スプリントとして、毎週火曜と木曜をリリースタイミングにしています。 報告された不具合の程度によって、次のリリースまでに行うのか?現在のスプリント中に行うのか判断していきます。 ユーザ影響あるものは「2nd Priority」の方針に従って極力早いタイミングでの対応が奨励されています。

2nd Priorityについてはこちら。 tech.macloud.jp

報告者への対応完了報告

不具合が解消されたことを報告します。 同じ障害が起きない安心感を与えたり、似たような不具合が再発した時に再度報告してもらうことができます。

このような形で弊社では不具合の共有を行い、対応フローを整備しておくことで初動までのコミュニケーションコストを抑えて、スムーズな対応を可能にしています。このフローではコミュニケーションを減らすのではなく、不具合対応までの初動を早めることを目的としています。不具合発生時は常に報告・共有が重要なので単にコミュニケーションを減らせば良い訳でないので注意したいですね。

弊社では、一緒にサービス開発をしてくれる仲間を募集しています。 興味のある方はぜひご応募ください。

www.wantedly.com

M&Aクラウド初主催のエンジニア向け勉強会を開催しました

f:id:kubotak:20210630143334p:plain

こんにちは久保田(@kubotak_public)です

先日の2021/06/23にNuxt道場というオンライン勉強会を開催しました。

macloud.connpass.com

この勉強会は弊社でも扱っているフロントエンドのフレームワークであるNuxt.jsをテーマとした勉強会で、 株式会社Hajimariの三宅様、株式会社レアジョブの田原様を師範(登壇者)としてお迎えいたしました。

Nuxt道場はYoutubeLiveで配信したため、アーカイブとして現在でも視聴することができます。 Nuxt道場って何?という方はぜひご視聴ください。

www.youtube.com

今回の勉強会はM&Aクラウドでは初となる弊社主催によるエンジニア向け勉強会でした。 弊社主催で勉強会をすることによって次の効果を期待しています。

弊社を知ってもらう・興味を持ってもらう

弊社のようなベンチャー企業知名度が低く、エンジニア採用も難しいです。 そのため、一人でも多くのエンジニアに弊社を知ってもらうための広報活動の一環でもあります。

社外へ発信する・社内だけでは得られない知見を外から得る

広報活動だけでなく、社内のレベルを底上げするためにも自分たちが発信すること、また他社の事例や知らなかったことを知る機会を作ることが大事です。 弊社のエンジニアには「全員インフルエンサー」というバリューがあるのでこれを体現するためにも発表できる場を自分たちで作っていくことも大切です。

tech.macloud.jp

最後に

一回で終わらず、シリーズとして続けていければと思いますので登壇したいという方がいらっしゃいましたらぜひ久保田までお声がけください。 また、Nuxt道場に限らず弊社で扱っている技術であるLaravel道場やAWS道場などを開催しても良いかもしれません。

見えないエラーを見れるようにする & 効率化のため Rollbar を導入した話

こんにちは。エンジニアの鈴木(yamotuki)です。 今回は本番や開発環境でエラーが起こったときに、効率よく対応ができるように Rollbar というツールを導入した話です。

Rollbar とは

公式はこちら

JavaScriptPHPで発生したエラー詳細をSlack通知してくれます。
通知や画面詳細ページは後述してあります。

導入目的

導入目的としては、フロントエンドのエラー検知とバックエンドサーバのエラー対応の簡素化の二つがあります。

1. フロントエンドのエラー検知

Universalモード(SSRCSRでシームレスに動作する仕組み)で動いているNuxt.jsによるアプリケーションのエラー検知の仕組みが欲しい、というのが一番最初の導入のきっかけでした。 SSRで動いている部分については、なんとかしてログ出力をしてエラーを検知することをできるかもしれません。しかし、それぞれのクライアントで動いているJavaScriptについてはコンソールログにだけ出ている状態で、エラーが起こっていることを知ることができない、というのが一般的なお困りごとかと思います。
Rollbarを使用すれば、エラー発生時のSSR/CSRを問わない統一的な仕組みとしてエラー通知を行うことができます。

2. バックエンドサーバのエラー対応の簡素化

弊社では AWS CloudWatch によりCloudFrontやEC2で発生した5xx系のアラートを検知してSlack通知していますが、以下のように情報量が少ないのが悩みの種でした。問題調査をするためにAWSコンソールを開いて、該当のアクセスログや、対応するエラーログを確認する必要があり、ちょっとしたエラー確認でも手間がかかっていました。

f:id:yamotuki:20210615170011p:plain
調査に時間がかかるアクセスログの5xx検知

導入結果

フロントエンドのエラーを検知して対処できた

振り返って見てみると、この記事にかけるような面白いエラーはログ保存期間の間には起こっていませんでした。 導入当初には広範囲のユーザ影響が出てしまう致命的なエラーが何度か起こっていましたが、逐次対応してきた結果、最近ではエラー頻度はぐっと減っているようです。

バックエンドサーバのエラー対応が効率化された

Rollbar を使うと以下のように何が起こったのか詳細がSlack通知され、さらに詳細を見たければリンクをクリックするだけでいいので劇的に調査が楽になります。

f:id:yamotuki:20210615165935p:plain
RollbarからSlack通知

詳細画面に行くと以下のような情報を見ることができます

  • 何回、いつ、影響したユーザ(IP)数
    • 障害対応においては、どれくらい深刻な障害なのか?というのは重要な情報なので、これがログをいちいち漁って見なくてもまとまっているのが良い
  • スタックトレースを引数つきで見れる
    • 「最終的にエラーが起こっている場所は分かったけど、途中でなんでこうなった?」みたいなケースも簡単に追跡することができます

f:id:yamotuki:20210617190317p:plain
詳細ビュー

導入でハマった点&工夫した点

Nuxt.js

nuxt-rollbar-module を用いています。細かい導入方法についてはドキュメントを参照してください。
導入に際して工夫した点だけ共有します。

  • 問題点
    • local で rollbar 通知をすると回数制限を無駄にしてしまう。TOKENを入れないとrollbar通知するためのコードが無視されるので、localでうまく動いているか判断できない。
  • 解決策
    • plugins に dummy-rollbar.ts を作成し、rollbar を呼んでいるところは local では console.log にマッピングするようにしました。
import { Context } from '@nuxt/types'

export default (ctx: Context, inject: (key: string, value: any) => void) => {
  const rollbar = ctx.$rollbar ?? {
    debug: (...e: any) => console.log(...e),
    info: (...e: any) => console.log(...e),
    warn: (...e: any) => console.log(...e),
    warning: (...e: any) => console.log(...e),
    error: (...e: any) => console.error(...e),
    critical: (...e: any) => console.error(...e)
  }
  // ref: https://github.com/gaelreyrol/nuxt-rollbar-module/blob/develop/lib/templates/rollbar-client.js#L46-L47
  ctx.$rollbar = rollbar
  inject('rollbar', rollbar)
}

plugins の差し込みについては公式ドキュメントを参考にしてください。

Laravel

基本はドキュメントを読んで導入かと思いますが、ハマったところだけ共有しておきます。

config/logging.php で以下のような設定を入れて、error log と rollbar の両方に通知するようにしてあります。

<?php

    'channels' => [
        'errorlog_and_rollbar' => [
            'driver' => 'stack',
            'channels' => ['errorlog', 'rollbar'],
            'ignore_exceptions' => true,
        ],
        'errorlog' => [
            'driver' => 'errorlog',
            'level' => 'debug',
        ],
        'rollbar' => [
            'driver' => 'monolog',
            'handler' => \App\Providers\Rollbar\MonologHandler::class,
            'access_token' => env('ROLLBAR_TOKEN'),
            'level' => 'error',
            // rollbarでマスクしたいパラメータを指定
            'scrubFields' => [
                // user
                'password',
            // 以下略

rollbar の handler として指定している MonologHandler クラスの雛形はこちらです。

雛形の namespace が間違っている問題

こちらのライブラリへのPRが出されているように、namespaceが間違っていていました。

ignore_exceptions の問題

雛形のコードを少し書き換えて使っていたのですが、とある変数の初期化がされておらず無言エラーになり、本番通知がうまくされていませんでした。”無言”である理由はignore_exceptionsがtrueになっているからでした。この設定の意図としては、片方の channel でエラーが起こっても、握りつぶしてもう片方の channel には通知が行って欲しいという意図かと思われます。localで一時的に試しにfalseにしたところ、すぐにどこでExceptionを吐いているか特定し、修正できました。

開発環境にも入れておく

上記の通り、本番環境で迅速にエラー対応するために効果的なのですが、開発環境にも入れておくことで、エラーをユーザに見せる前に修正できることがあります。
開発環境に入れるときに通知先Slackチャンネルの分離に一工夫があったので共有します。

  • 問題点
    • Project ごとで通知先が一箇所しか選べない。Projectはトップレベルの階層で、その下にEnvironmentがあります。Projectの中の Rollbar の Items(エラーの一つ一つ)には Environment が紐づいているので、それによって通知先を分離したいと思っていましたが、できませんでした
  • 解決策
    • Project を開発環境、本番環境で分離しました。Environment が情報として冗長になってしまいますが、Slack通知先を分離することができました。

終わりに

www.wantedly.com

フロントエンドのエンジニアに届かないエラーを可視化することで大きな問題でもすぐに対応できるようになりました。エラー対応を効率化すると、神経をすり減らす障害対応を少し楽にすることができました。

弊社では生産性向上をして、ユーザにより多くの価値を一緒に届ける気持ちを持ったエンジニアを募集しています。

AWS LambdaからECS Fargateへの移行

こんにちは、久保田(@kubotak_public)です

今回は弊社で運用しているサービスであるM&Aクラウドのフロントエンドの実行環境をAWS LambdaからECS Fargateへ移行した話です。 まずは弊社のサービスが動いている環境は次のようになっていました。

f:id:kubotak:20210609141326p:plain

フロントエンドにNuxt.js(JavaScript)、バックエンドにLaravel(PHP)を利用しています。 LaravelはAWS ElasticBeanstalkで作成されたEC2インスタンス上で動作しています。

そしてフロントエンドのNuxt.jsはAWS Lambda上で動作し、API Gatewayを利用してHTTPによりアクセスできるようになっていました。 もともとはLaravelの環境だけでしたが、Nuxt.jsでフロントエンドをリプレースしたページが混在しているのが現状です。 これらはCloudFrontによって各環境にリクエストがルーティングされています。

Nuxt.jsへの移行に関しては別途シリーズでお届けしていますのでよろしければご参照ください。

tech.macloud.jp

なぜ移行するのか

このNuxt.jsの実行環境であるAWS Lambdaでは次のようなメリットがありました。

  • 運用が楽
  • 費用が安い

弊社の運用においてはLambdaのコールドスタートに関しても特に問題ではありませんでした。 一年程はLambdaによる運用にも特に問題にはなっていませんでした。

しかし、Nuxt.jsのアプリの肥大化により状況が変わってしまいました。 AWS Lambdaではデプロイできるサイズがzipの状態で50MB、展開した状態で250MBの制限があり、Nuxt.jsとTypeScriptのバージョンアップを行った際にこの制限に引っかかる様になってしまいました。

そこで、容量の制限に余裕がある環境への移行が求められ、Amazon ECSのFargateが候補にあがりました。

Amazon ECSとは

Amazon Elastic Container Service(Amazon ECS)は完全マネージド型コンテナオーケストレーションサービスであり、コンテナ化されたアプリケーションを簡単にデプロイ、管理、スケールするのに役立ちます。

AWS Fargateとは

FargateはECSやEKS上で動作するコンテナ向けサーバーレスコンピューティングエンジンです。 Amazon EC2 インスタンスでサーバーまたはクラスターを管理する必要なくコンテナを実行することができます。

サーバー管理にコストを掛けずに運用したいという考えからAWS Lambdaを利用していましたので、同じようにサーバー管理をマネージドしてくれるECS Fargateを採用しました。

AWS LambdaへのデプロイからAWS Fargateへのデプロイに切り替え

まずはFargateで動作させるためにDockerコンテナ化と、そのコンテナをホスティングする必要があります。 Dockerfileは非常にシンプルです。

FROM node:12.14.0-alpine

RUN mkdir -p /var/www/workspace
WORKDIR /var/www/workspace
COPY ./.nuxt /var/www/workspace/.nuxt
COPY ./dist /var/www/workspace/dist
COPY ./node_modules /var/www/workspace/node_modules
COPY ./.env /var/www/workspace/.env

EXPOSE 80

ENTRYPOINT ["node", "dist/server/server.js"]

※一部改変しています。

ベースとなるnode.jsのDockerイメージを利用してビルドしたアプリケーションがコンテナ内に配置されるだけです。

Dockerイメージのpush

DockerイメージはAmazon Elastic Container Registry(Amazon ECR)にホスティングします。 弊社ではアプリケーションのデプロイのCI/CDとしてCircleCIを利用しています。 CircleCIでECRへpush(Dockerイメージをホスティング)するには次のプラグインを利用しています。

version: 2.1
orbs:
  aws-ecr: circleci/aws-ecr@7.0.0

定義は次のようになります。

- aws-ecr/build-and-push-image:
          account-url: AWS_ECR_ACCOUNT_URL
          aws-access-key-id: AWS_ACCESS_KEY_ID
          aws-secret-access-key: AWS_SECRET_ACCESS_KEY
          create-repo: true
          region: AWS_REGION
          repo: repository-name
          skip-when-tags-exist: true
          tag: "${CIRCLE_SHA1}"

これでDockerfileを利用してDockerイメージの作成とECRへのpushをCI上で行ってくれます。

Fargateへのデプロイ

AWS LambdaへのデプロイはServerless Frameworkを利用していたので、同じ仕組みでFargeteへのデプロイを行いました。

Serverless Pluginを追加してFargateへのデプロイを追加します。 検索すると次のプラグインが上位に出ます。

GitHub - honerlaw/serverless-fargate-plugin: Serverless plugin to deploy fargate tasks to an ECS cluster.

しかし、こちらのプラグインは保守がされてなく、弊社の環境ではデプロイも失敗しました。 そこでこのプラグインをForkしているものを使っています。

github.com

※一部subnetに関する拡張を行いたかったのでコントリビュートしました
※このプラグインの作者が別途新規でプラグインを作成中ですのでそちらもチェックされると良いかもしれません。

デプロイして新環境で動いていることが確認できたらAWS Lambdaで動いている環境から切り替えます。 この切り替えは前段であるCloudFrontからの向き先を変更するだけです。

f:id:kubotak:20210609141837p:plain

移行してみて

AWS Lambdaと異なり、Fargateでは稼働している台数のハンドリングや利用しているCPUやメモリのリソースの把握が重要になってくるかと思います。 しかし、Fargateのオートスケールの設定などはわかりやすく、スケーリング自体もスムーズな印象です。 API Gatewayが不要になり、代わりにロードバランサーが追加された点などもあり、アーキテクチャとしては複雑になったという印象があります。 デプロイ時間に関してはECRへのイメージpushやECSがローリングデプロイをする関係上遅くはなってしまいましたが、現時点では運用して間もないので過不足は特に感じていません。 引き続き監視を行い、アプリケーションの成長に合わせてインフラもスケールするように改善していきたいと思います。

最後に

弊社のフロントエンドエンジニアは今回のようにAWS環境を利用した改善・保守も行います。
アプリケーションコードにとどまらず、インフラ環境も扱いたいフロントエンドエンジニアの方は一緒にアプリケーションを成長させていきましょう。

www.wantedly.com

MeCabを使ってテキストクレンジングをする

f:id:kazuhei0108:20210607110723j:plain

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

弊社のサービス「M&Aクラウド」では、ビジネスキーワードと呼ばれるキーワードを使って買収・出資企業様と売却・資金調達企業様のマッチングを行っております。

f:id:kazuhei0108:20210607112917p:plain
ビジネスキーワードを入力している様子

このビジネスキーワードというものは、ユーザー様が自由に入れられるものなのですが、その分表記ブレが発生したり、キーワードとして使えない文章だったりといった事が起きていました。

今回は簡易的に、キーワードではないものを判別して除外する、という条件で進めることにしましたので、MeCabを使って品詞からキーワードではないものを判別し除外していくことにします。

MeCabとは

MeCabオープンソース形態素解析エンジンです。形態素解析とは、自然言語で書かれた文を言語上で意味を持つ最小単位(=形態素)に分け、それぞれの品詞や変化などを判別することです。文章を名詞、動詞、助詞、助動詞などの品詞に分解し、種類を判別します。Mecabは日本語の形態素解析エンジンとしてはかなりメジャーなものだと思います。

mecabのインストール

弊社ではWEBサーバーにAWS Elastic Beanstalkを利用しているため、その設定ファイルを書いていきます。ebextensions/*以下に配置しました。 実際のコードは以下を御覧ください。

qiita.com

MeCab自体のインストールと、MeCabから使う辞書データのインストールという2つをインストールします。

実際に使ってみる

MeCabをコマンドとして実行します。

f:id:kazuhei0108:20210607111017p:plain

このように、テキストを品詞分解した上でそれぞれが何の品詞かを判別してくれます。上記のように文章をMeCabに渡すと助詞や助動詞が判別されます。これらがある場合、そのテキストはキーワードではなく文章だと判別できます。 MeCab: 品詞 ID にありますが、MeCabの品詞分類の結果はかなり細かいです。実際ここまで細かく品詞を分類して使うことってあんまりないんじゃないでしょうか?

今回は助詞、助動詞、記号を含む場合、文章であると判定し除外するという処理にしました。

はまりどころ

こちらの記事に紹介されているのですが、記号がなぜかサ変接続の名詞として判定されてしまうという問題がありました。

qiita.com

サ変接続の名詞というのは「該当」のような後ろにするをつけると「該当する」となり動詞になることができる名詞なのですが、これだけだと名詞ではあるので、除外したくはありません。一方、「#」のような明らかに記号のものがなぜかサ変接続の名詞というふうに誤判定されてしまいます。

今回は色々試したところ、半角の記号は全角に変換してからMeCabにわたすと記号として認識される事がわかりましたので、これで対応することができました。

まとめ

普段WEBアプリケーションを書いていると、こういったPHPからコマンドを実行するというような処理はあまりやらないので面白かったです。あと、WEBサーバーにMeCabが入ったことによって、今回のキーワードのクレンジングだけでなく、ユーザーの入力値のバリデーションなど様々なことに応用できそうだと考えています。

最後に

M&Aクラウドではデザイナーやエンジニアを募集しています! 是非お気軽にご連絡ください!

www.wantedly.com

www.wantedly.com

www.wantedly.com

Feature toggles を複数の環境へ即時反映する仕組みを開発しました

f:id:hamakou108:20210528145639p:plain

こんにちは。エンジニアの濱田( @hamakou108 )です。

数ヶ月前にM&Aクラウドの feature toggles の仕組みを刷新したので、今回はその内容について紹介したいと思います。

Feature toggles とは?

Feature toggles はアプリケーションのビルド時または実行中に機能の切り替えを行う仕組みです。 Feature toggles はいわゆる feature branches の戦略とは対照的に、メインのブランチに頻繁にコードを統合します。 こうすることで CI/CD による早期のフィードバックと開発中の個別機能へのアクセスを両立します。

詳細については以下のページが参考になるかと思います。

刷新前の feature toggles の運用方法と問題点

M&Aクラウドフレームワークとして Laravel と Nuxt.js を利用しており、それぞれが別の環境で稼働しています。 各環境用の環境変数はファイルで管理しており、そこに feature toggles の値を追加するような形で運用を行っていました。

しかしこの運用方法には幾つか問題がありました。

環境変数の更新からリリースまでのタイムラグ

各環境に環境変数を反映するために、わざわざファイルを更新して CircleCI のワークフローを実行する必要がありました。 この一連の作業に30分から1時間程度の時間が掛かり、リリースのタイミングのコントロールが難しい状況になっていました。 バグが混入していた場合の切り戻しでも同様の作業を行う必要があるため、 MTTR の悪化の要因の一つにもなっていました。

各環境の切り替えタイミングの差異

Laravel と Nuxt.js の動作環境が異なることから、デプロイフローもそれぞれ分かれています。 このためフロントエンドとバックエンドで feature toggle の切り替えタイミングに差異が生じてしまい、それに起因してエラーが発生することが何度かありました。

Feature toggles の機能の刷新

上述した問題点を解消するべく、以下の課題を克服する新たな feature toggles 機能を開発するミニプロジェクトが立ち上がりました。

  1. Feature toggles の切り替えタイミングをコントロール可能であること
  2. フロントエンドとバックエンドで同じタイミングで feature toggle を切り替えられること

ここからは設計上のポイントについて3つ紹介します。

コード中にマスタを定義し、 RDB で on/off を管理

環境変数による feature toggles の管理は廃止し、次のような設計を行いました。

まず RDB に feature toggles 用のテーブルを作成し、 toggle の on/off をレコードとして管理できるようにします。 レコードを追加・更新すれば toggle の on/off が即時に切り替わるようにする算段です。

もう一つの工夫として FeatureToggleName という Enum 型のクラスを用意し、プロパティとして各 toggle の名前を持たせています。

<?php

class FeatureToggleName extends BaseEnum
{
    // 新規作成する際に定数を追加
    const FOO = '2021_05_27_foo';
    const BAR = '2021_05_28_bar';
    const BAZ = '2021_05_29_baz';

    public function __construct($value)
    {
        parent::__construct($value);
        if (!$this->isValidValue()) {
            throw new InvalidArgumentException('引数の形式は YYYY_MM_DD_name でなければなりません');
        }
    }

    private function isValidValue(): bool
    {
        return (bool) preg_match('/\d{4}_\d{2}_\d{2}_.+$/', $this->rawValue());
    }
}

アプリケーション内では FeatureToggleName のプロパティを feature toggles のマスタとし、ここに定義されていない toggle は存在しないものとして扱うように設計しています。 こうすることで不要になったレコードがテーブル内に残存していても、プロパティを削除しておけば UI から不要な toggle を排除できます。

また新たに追加する toggle の名前が過去に使っていたフラグの名前とたまたま重複していた場合、残存していた過去のレコードによって意図せずにフラグが on になってしまう危険があります。 これを避けるため、(現実的には)重複しないようなフラグ名を設定することをコンストラクタで強制しています。

管理画面から GUI でフラグ切り替え

M&Aクラウド社内のメンバーがアクセスできる管理画面に feature toggles 管理用のページを追加し、フラグの一覧表示および更新ができるようにしました 1

管理画面のフラグ管理ページの UI
コード中で定義されている feature toggles と ON/OFF の状態が表示され、個別に編集できる

即時に反映されるのは勿論のこと、アプリケーション経由で更新することで監査ログも残るようになり、ガバナンスの面でも強固な仕組みとなりました。 監査ログの機能に関しては別の記事としてまとめられていますので、興味のある方はこちらもご覧ください。

tech.macloud.jp

フロントエンド向け API

フロントエンド向けの feature toggles 取得 API を作成しました。 Nuxt.js の Router の middleware として設定することで各ページを開いた際に API が呼び出され、 Vuex 経由で feature toggles が取得できるようになりました。

const nuxtConfig: Configuration = {
  // ...

  router: {
    middleware: 'fetch-feature-toggle'
  },

  // ...
}

Feature toggles の刷新後

上述した課題を克服し、先日リリースした「かんたんM&A診断」では新しい feature toggles の仕組みを使って即時リリースすることができました!

macloud.jp

その後、開発時に想定していませんでしたが、この仕組みにはデータとロジックを同時に移行する際にメリットが得られることに気づきました。 Feature toggles も RDB で管理されているため、同一トランザクション内で移行したいデータと feature toggles のレコードを更新することで、データ移行の間にユーザーの操作が発生してデータに不整合が発生するといったケースを防止できます 2

一方で新たな課題も浮かび上がってきました。 機能のリリース後に不要なコードを削除する際、 FeatureToggleName のプロパティを先に消してしまうとそのフラグが off として扱われるようになるため、リリースした機能が巻き戻ってしまいます。 そのため削除の際は

  1. フラグを使って条件分岐を行うコードを削除する
  2. FeatureToggleName のプロパティを削除する

という手順を踏まなくてはなりません。 この順序を気にしなくても良いように改善することが今後の課題です。

最後に

M&Aクラウドではデザイナーやエンジニアを募集しています! 是非お気軽にご連絡ください!

www.wantedly.com

www.wantedly.com

www.wantedly.com


  1. 開発チーム内では feature toggles のことを feature flags や機能フラグのように呼んでいます。

  2. トランザクション数や移行するデータの量が多い場合はロックの影響を無視できなくなるため、この仕組みが万能というわけではありません。