この記事はBASE Advent Calendar 2020の10日目の記事です。 devblog.thebase.in はじめに こんにちは、BASE株式会社 ServiceDevセクション マネージャーの菊地です! サービスの急成長に伴って組織の拡大が急務であり、最近は採用活動に専らコミットメントしています。BASEに興味ある方はお気軽に 私まで ご連絡ください! さて、BASEでは120万を超えるショップオーナー様と多くのユーザー様にご利用いただいており、日々多くのお問い合わせを頂いております。基本的には弊社カスタマーサポートチーム(以下CSチーム)が一次受けして回答しているのですが、CSチーム内で回答できないものについては開発チームに依頼がきて調査/対応しています。 採用活動を行う中で他社のエンジニアと話す機会が多くあるのですが、「CS対応の運用がうまくいかない。一部のメンバーに負担が集中してしまう」といった悩みを持っている会社さんがとても多いようです。一方「BASEではCS対応を当番制にしたらうまく運用できています」とお話しすると興味を持って頂けることが多くあり、弊社のCS対応に関する知見を共有することは一定の需要があるのかなと思い、アドベントカレンダーのネタとして採用しました。 CS当番制導入以前の対応について 開発チームへのお問い合わせ対応依頼は1日あたり10数件程あります(11月23日~12月4日のデータを集計)。すぐに回答できるものもあれば、不具合が発覚し不具合修正に1日かかってしまうケースも少なくありません。 当番制導入以前はSlackにある #CSお問い合わせ対応チャンネル (弊社の全エンジニア約60名がジョインしています)において @here で全エンジニアに対応が呼び掛けられていました。 しかしどのエンジニアもメインのPJの機能開発で忙しいため、こういった日々の突発的なお問い合わせの対応を行うことは各々の主体性に期待しているだけではなかなかうまくいきませんでした。 @here のメンションが飛んできても誰も反応しないということが多々あり、結果的に人一倍当事者意識の強いCTOやテックリードに対応の負担が集中してしまうという状況が起きていました。CTOやテックリードには彼らにしか解決できない難しい課題に取り組んで欲しいので、毎日数時間をCS対応に費やす状況は好ましい状況ではありませんでした。 そこで課題を解決するべく、今年の4月頃から全開発組織を巻き込んでCS当番制を導入してみようということになりました。 CS当番制の仕組みについて 「CS当番に期待されていること」、「お問い合わせの対応フロー」等は社内のドキュメントに明文化してあり、CS当番が選出されるたびにメンバーを集めて読み合わせを行い認識のすり合わせを行っています。 仕組みの大枠の部分はエンジニアリングマネージャ(以下EM)とテックリード(以下TL)陣で議論して決めましたが、運用が始まってからはメンバーからの改善案も多く取り入れています。取り入れた案についての具体的な事例は後ほど紹介します。 下記にドキュメントから一部抜粋して弊社のCS当番制の仕組みについて紹介します。 CS当番のメンバー CS対応に責任を持つメンバーを毎週全開発チーム(バックエンド, フロントエンド, SRE, DS, etc)から1人以上選出して @CS当番 というグループを作成します 当番の人数は大体10人弱くらいになります 担当期間は1週間です 開発チームは各チーム6人程度なので大体1.5ヶ月に1回当番が回ってくるペースになります 全体の指揮(決起会、振り返り会の開催、改善案の採用など)はEMが行います CS当番に期待されていること 当番の週はCS対応を優先に行うこと。本来の業務に専念したい場合等は上長に相談して当番の週を変更してもらいましょう ボールを持った人が必ずしも調査/対応を行う必要はありません。難しかったり、忙しかったりした場合は他のメンバーや上長にヘルプを求めましょう 一部の人に負荷が集中しないように、みんなで協力して対応しましょう お問い合わせ対応を通してBASEのサービス&システムの理解を深めていきましょう 月曜日に決起会、金曜日に振り返り会を行い改善していきましょう お問い合わせの対応フロー @CS当番 のメンションがきたら対応をお願いします。 メンションがきたら5分以内の反応を心がけましょう。 絵文字で反応だと調査に取り掛かっているのか分からないので「確認します」のように一言書いてボールを持っている人が誰だかはっきりと分かるようにしましょう。 1問い合わせにつき1スレッドでやりとりを行いましょう。 問い合わせの回答が得られたら 済 の絵文字をCSメンバーに入れてもらいましょう。 調査/対応したことはドキュメントにまとめて知見を貯めていきましょう。 運用していく中で改善したこと 当番制を導入後、メンバーから上がってきた多くの改善案を取り入れてきました。上記の対応フローの中にもメンバーから上がってきた案が多く含まれています。ここでは案を取り入れるに至った背景なども含めていくつか紹介させていただきます。 決起会・振り返り会を行うことでチームの結束力を高める CSお問い合わせは自分が詳しくない領域のものも多くあるので、自分以外の当番のメンバーが「どういった領域が得意な人たちなのか」を把握していることはコミュニケーションをとって円滑にお問い合わせ対応を行う上でとても重要です。 一方で最近ではフルリモート下で入社してきたメンバーも多く、彼らにとってはもはや「話したこともないし、見たこともない」メンバーとの連携が求められることになります。さすがにこれを新入社員のコミュニケーション能力でカバーしてもらうことを期待するのは酷なのではないかという課題感がありました。 そういった課題感を感じていたときにメンバーから、「当番がスタートする月曜日に決起会を行い、そこで自己紹介や得意な領域等に関する共有を行うようにし、金曜日には振り返り会としてCS対応を行ってみて感じたことや改善案などを話し合う場を設けるようにしたらメンバー間でコミュニケーションが取りやすくなるのではないか」という提案があり、取り入れてみることにしました。 決起会・振り返り会を行うようになってからは新入社員に限らず、古くから在籍しているメンバーからも「コミュニケーションが取りやすくなり、お問い合わせ対応を協力して行いやすくなった」という声があがっています。 決起会の様子です。本記事を書くにあたって久しぶりに参加したら好きな動物について紹介し合っていました。この画像の中だけでもフルリモート下で入社してきたメンバーが5人もいます。 「誰がボールを持っているか」を明確にする CS対応は1つの「コト」に対して多くの「ヒト」で向き合っているので、「誰が何をするのか/しているのか」が明確になっていると、状況の進行に対して安心感を付与させられると思います。1番不安なのは「ボールが宙に浮いて誰も手を付けていない」という状況です。その他にも、「全く同じことを調べていた」「複数人で別個に調査資料をまとめていた」というのも勿体ないです。 そういった課題感を感じていたメンバーから、「調査に取り掛かる際は「確認します!」のようにはっきりと宣言して、ボールを持っている人が誰だか分かるようにしよう」という提案があり、対応フローの一つとしてルール化しました。 ルール化して以降は 「誰がボールを持っているか」が把握しやすくなったため、「あの人がボールを持ってくれてるから自分は他の問い合わせの調査をしよう」「ボールを持っている人のフォローとして私に何か出来ることはあるか」などそれぞれのメンバーが自分が今何をすべきかを理解し、チームとして効率的に動けるようになったと感じています。 1問合せにつき1スレッドで対応する BASEではスレッドの運用について明確にルールはなく、CS対応についても人によってチャンネルとスレッドでやりとりが混在していました。それによって次のような課題がありました。 複数の問い合わせのやりとりが、 #CSお問い合わせ対応チャンネル 上に混在しているのでやりとりを追いづらい 各お問い合わせの対応ステータス(解決済みなのかどうかなど)が追いづらい そういった課題感を感じていたメンバーから、「スレッドでやりとりするようにルール化すれば、問い合わせ元のメッセージに対して「 済 」などと絵文字を入れておくだけで、状況の把握が容易になるし、「どの問題が発生中・進行中なのか」について、チャンネルを開くだけで判然とするようになるのでは」という提案があり、対応フローの一つとしてルール化しました。 ルール化して以降は下の画像のようにお問い合わせが解決したかどうか、一目で把握できるようになり非常に見通しが良くなりました。 過去の類似のお問い合わせや関連する社内ドキュメントを自動的に取得する 過去の類似のお問い合わせや関連する社内ドキュメントを見つけることができれば容易に解決できるパターンがそれなりに多かったため、DS(機械学習)チームのメンバーがそれらを複数件自動取得してくるシステムを自発的に作ってくれました。これにより調査がしやすくなりました。こちらについては明日のアドベントカレンダーで詳しく紹介させていただきます。 その他 その他にも「調査/対応した際はドキュメントを書くこと」をルール化したり、「誰に相談したら分からないときに相談できるチャンネルを作成」したりなどメンバーからの改善案を多く取り入れてきました。今後もさらに改善を積み重ね、より良い運用を行っていきたいです。 CS当番制を導入して良かったこと CS対応を当番制とすることで責任の所在や期待されていることが明確になり、BASEの全エンジニアがお問い合わせ対応に取り組むようになりました。 導入前、一番課題に感じていた一部のメンバーへ負荷が集中するという問題が大きく軽減されました。 コミュニケーションが不足しがちになる昨今のフルリモート環境下において、決起会や振り返り会を行うなどチームを超えて協力し合うことでコミュニケーションの活性化に役立っています。 お問い合わせ対応を通して普段馴染みのない領域の調査を行うことでBASEの幅広いサービス理解・システム理解に役立っています。 新入社員がBASEに馴染むためのオンボーディングとしても役立っています。 まとめ 以上、CS対応を当番制にしたらうまく運用できていますという紹介でした。少しでも参考になれば幸いです。 今後も改善を積み重ね、より早くお問い合わせの返信ができるように体制を整えていきたいと思います。 明日は、DSチームの粟村さんです!お楽しみに!ばーい! ※ 文中で用いている #CSお問い合わせ対応チャンネル や @CS当番 という名前は事実とは異なります 改めて、仲間大募集中です! Webアプリケーションエンジニア open.talentio.com Webアプリケーションエンジニアは主体技術はバックエンド実装ですが、サービスを作る時にフロントエンドも書いています。 フロントエンドエンジニア open.talentio.com 開発プロジェクトにおけるフロントエンド実装と、BASEのフロントエンド実装におけるライブラリや実装技術の守り神を担います。
はじめに この記事はBASE Advent Calendar 2020 9日目の記事です。 初めまして、BASE株式会社 CSEチームに所属している秋谷です。CSEについては下記の記事に詳しく書かれていますので詳細は省きますが、一言で言うと社内の業務効率良くして働きやすくして行こう!をミッションに、社内業務改善と内部統制の二つの軸で業務を遂行しています。 devblog.thebase.in 私は今年の3月に入社しましたが、その頃には既にコロナが流行し始めており、特にBASEはWork From Home (以下WFH)をいち早く実践していたため、出社した回数はトータルで1ヶ月もありません。 そんな私がこの10ヶ月を振り返り、WFH下でのCSEとしての業務の振り返りをしていきたいと思います。 社内業務改善 社内業務改善では、私は主に経理業務の業務改善に携わっています。「業務改善」とは現存のプロセス全体を最適化することを目的としており、ごくごく一部だけ自動化するプログラムを書いて終わりではありません。関係する各所へのヒアリングや業務全体に関わるフローの確認、不要なプロセスの削減・代替方法の検討など様々あります。 このWFH下では既存の業務の多くを見直し、フローをより良く改善する良い機会になったのではないかと個人的には感じています。 実際に入社後すぐに経理業務の一部を改善する機会をいただいたのですが、その際に既存業務のフローを洗い出し、出社が必要な部分のフローが本当に必要なのかをヒアリングし、その業務に関わる全てのフローを出社無しで従来の半分以下の時間で実施出来るようになりました。 元々業務を経理からCSEに移管する話は出ていましたが、更に業務に関わるフローを短縮できたのはWFHのおかげではないかと感じています。 余談ですが、この時の業務は後に取得できる情報を大幅にアップデートし、売上データダウンロードAppとしてリリースされています。ぜひご活用ください。 apps.thebase.in 内部統制整備 こちらの記事 にもあるように、BASEでは上場企業が守らないといけないJ-SOX法に対して、2021年度末までに未整備な項目の是正・必要書類の作成などが必要になります。一社員として決められた項目に沿って証跡を取得するのではなく、整備していく立場になるのは殆どのメンバーが初めての経験だったため、まずはCSEチーム内での内部統制本の輪読会を実施し、内部統制への理解を深めてから担当にわかれ、それぞれが業務を遂行していきました。 輪読した本はこちら www.amazon.co.jp 私はIT業務処理統制の担当になったのですが、IT業務処理統制ってなんぞ??なところからスタートしています。そのため、最初に社内で対象になりそうな項目を洗い出していただき、その担当者に対してヒアリングを実施していきました。余談ですが、このヒアリングが社内業務の理解にも繋がり、内部統制とは直接は関係ないところでも大いに役立っています。ヒアリングした内容はPlantUMLを用いてワークフロー図に起こし、社員全員が見られるところに公開しました。これにより、新しい取り組みを開始する前に既存のワークフローの確認やいろんな場面で共有し易くなり、フロー図の修正も容易になりました。 また、内部統制上必要なテーブルに対して変更が実施された場合、この変更を内部統制のレポートを作成するシステムに反映する必要がありますが、このWHF化ではこの情報をキャッチするのがなかなか大変でした。 これを解決するために、BASEでは期の初めにその期で実施するプロジェクトの概要をスプレッドシートにまとめて全社員に共有するという取り組みがあるのですが、そのプロジェクト一覧に内部統制上必要なテーブルに対して影響があるかどうかを記載するようにしてもらい、影響がありそうであれば担当者に話を聞きにいくということを実施するようになりました。このシートにはいつ頃リリース予定かが記載されているため、リリース前の少なくとも1ヶ月前には必要な項目を確認していくことができるようになったのでやりやすくなったかなと思います。 終わりに 多くの企業が在宅に踏み切る中、いきなり在宅になって戸惑った方も多くいらっしゃるかと思います。 ここで紹介した内容はちょっとした工夫程度のものですが、意外とそういったちょっとした工夫でフローは良くなっていくことが多々あります。この機会に、手元の業務のフローや伝達方法を見直してみてはいかがでしょうか。 明日はServiceDevセクションの菊地さんです!
はじめに この記事はBASE Advent Calendar 2020の8日目の記事です。 devblog.thebase.in BASE株式会社 ServiceDevのShopグループ所属、エンジニアの栗田です。 Shopグループではネットショップ作成サービス「BASE」及びショッピングアプリ「BASE」の機能をチームで協力しながら開発しております。 この記事では、私が属するShopグループで勉強会を続けて行くことができたよ。というお話と付随して様々なコミュニケーションのきっかけになったよ。というお話を紹介したいと思います。 チーム勉強会開始前 元々エンジニアを中心に社内で不定期に勉強会が開催されておりました。 具体的には下記のようなテーマ・形式の勉強会でした。 ここ1,2年の間に開催されていたテーマ BASEで使われている特定の技術の勉強会 エンジニア向けの決済勉強会 全従業員向けの BASE BANK勉強会 (※ BASE BANKは金融サービスを扱うグループ会社) デザイナー勉強会 その他多数 開催されていた形式 特定のメンバーで輪講形式 特定のメンバーで事前読み&感想共有形式 特定のチーム内での開催をする形式 個人で読書メモを残す形式 特定のメンバーで輪講形式で行われた「入門 監視」については、SREグループの富塚が書いた記事がありますので もしよければ、こちらも合わせてご覧いただければと思います。 devblog.thebase.in Shopグループでの勉強会 今までは例えば決済代行について突発的な勉強会の開催や、特定の問題について突発的にカジュアルに話す機会はありましたが、1つの本や話題についてチームで腰を据えて学ぶといった事はありませんでした。 個人個人で主に技術的にスキルアップしてその結果をプロダクトに還元できる流れを作っていこう!という事で開催していく事になりました。 題材は 1冊目にクリーンアーキテクチャ、2冊目にオブジェクト指向プログラミングの本を読みました。 1冊目の選定は結構勢いで決まり、2冊目の選定は社内のテックリードエンジニアとも話合って、BASEの環境で直に実践で使えそうで勉強会にオススメの本を何冊か紹介してもらいその中から選びました。 どんな形式で行ったか 自由参加で、各自が好きなタイミングで1週間に1章読んでドキュメントに感想をまとめる形式を取りました。 平日に読む事のできなかったメンバーは休日にもり返したりと各自好きなペースで進めていきました。感想がまとまった後は、ドキュメント上で会話したり 1時間ほど時間を取ってZoomでランチ勉強会したりしました。 ちょうど他のチームも以前読んでいた本なので、様々なメンバーの感想がドキュメント上で見れたり会話のキッカケになる事もあったのも良かったポイントでした。 またランチ勉強会に関しては、オンライン懇親会制度を活用して美味しいランチを食べながら進めるなどメリハリをつけて進めました。 basebook.binc.jp 良かったこと オンラインで集まる事が難しくなった中でのコミュニケーションのきっかけになった。 チームを超えて参加があった。システム基盤の開発を担うチームからの参加・サポートも得て知識を補完する事ができた。 普段の開発の内容に勉強会の内容を盛り込めるようになった。 次の勉強会は何にしようかという声が自然に上がるようになった。 テックリードエンジニアに教えてもらえるのは福利厚生! まとめ 皆様の会社ではどのような方法で勉強会をされていますか? またどのようにチームでの勉強会のコミュニケーションを取られていますか? BASEではShopグループ以外にも同じProductDevのPaymentグループや特定のプロジェクト内などでも勉強会が活発になり、より盛り上がりを見せています。 一緒にプロダクトを作っていく仲間と共に学べて、学びをプロダクトに還元できるサイクルが回っていくととても良いですね。 明日はCSEグループの秋谷さんです!
この記事はBASE Advent Calendar 2020の7日目の記事です。 devblog.thebase.in こんにちは、BASEのCorporate Engineering CSEグループの小林です。 昨年まではProduct DevのShopグループに所属し、Instagram販売 App、顧客管理 App、メールマガジン App、時にはAndroidアプリの開発まで、幅広く「BASE」の機能開発に携わっておりました。 今までの開発経験をもとに、新設されたグループに異動しましたので、どのようなグループなのかを紹介させていただきます。 CSEとは Corporate Solutions Engineering (略CSE) 「BASE」のショップ開設は120万店舗を突破し、登録される商品数、取引額が増える中、社内業務の効率化と財務の信頼性担保することを専門とするチームとして、1年ほど前にProduct DevのCorporate EngineeringにCSEグループが発足しました。 ミッション コーポレートエンジニアのミッションは、ショップオーナーに安心してサービスを使い続けていただくために、業務の有効性及び効率性・財務報告の信頼性・事業活動に関わる法令などの遵守並びに資産の保全といった内部統制の環境整備と、DX(Developer Experience:開発者体験)の両立を考え続け、改善し続けていくことです。 上記のミッションで、私が好きなのは 「 ショップオーナーに安心してサービスを使い続けていただくため 」ここを大事にしている事です。 社内ではすごくたくさんの業務が日々発生しています。その中には属人化している業務などを、適切に作業分担・自動化などできれば、素早い対応ができるようになり、結果的にショップオーナーのためになります。 ミッション達成のために、大きく2つの業務をする 社内業務改善 サービス成長に伴い、増え続ける社内業務を見直し、サービスを安定的に提供するための業務改善 社内で利用している管理画面の開発、銀行、外部の会計サービスとの連携し、作業の効率化 属人化していた作業を適切に分担できるように、システムの改善 内部統制の整備 ショップ、BASE、取引先企業、株主の資産を守るために、不正がおこらないよう仕組みを整備/ルールづくり 業務を適切な承認・適切な部門で業務が遂行されるよう、業務のプロセスを整理し体系化する 以下は誤った認識。CSEは、こういう目的のチームではない 新しくできたチームだったため社内でもCSEの意味が伝わらず、CSEは何をするチームなのか曖昧で、他のチームの人に正しく理解してもらえずにいました。目的とミッションを正しく知ってもらうために、間違った認識例もあえて定義もしました。以下の内容は、どれも深くCSEの業務に深く係る内容ですが、それが目的のチームではないという事です。 社内用の管理画面の開発をするチーム 業務改善で社内の管理画面の開発が起点となる事はあるが、開発担当ではありません。「BASE」に新しい機能がリリースされ、社内の管理画面にも開発が必要あれば、機能開発をしたプロジェクトメンバーで社内ツールも実装します。 IT全般統制に必要な開発をするチーム IT全般統制で整備が必要な項目は、内部統制に関わるメンバーで議論し、統制が必要になる項目は出していきます。しかし整備項目は開発だけでなく、ネットワーク、DBなど多岐にわたるため、必要な開発などは他のチームなどにお願いしています。もちろん、全く実装しない方針ではありません。 決済・売上に関する開発をするチーム CSEとして経理部門などと連携する事が多く、ショップの売上周りデータを常に意識しています。経理部門とのデータ連携や突き合わせ作業のため開発はしますが、決済周りの実装を担当する事はほぼありません。 内部統制の目的で、不正ができないような開発(整備)はするが、「BASE」の新規機能などの開発の設計などには関わる事は、ほぼありません。 「BASE」の機能開発を しない チーム 実はこれも違います。業務改善の一環で、「BASE」にちょっとした機能を追加すれば、解決する項目も多くあります。今年の11月には、メンバーの1人が売上データダウンロード Appという機能の開発に携わっていました。 開発設計・実装は別のチームにお願いする形となりましたが、売上についての知識やショップオーナーのニーズなどを深く理解できているからこそ、「BASE」の機能開発に関わっていく、良い例でした。 どのような業務をやっているか CSEは、実際にどのような業務を行なっているのか、もう少し詳しく説明したいと思います。 社内業務改善 社内で多くの作業が毎日発生していますが、課題感をもって詳しく見てみると、大体このパターンに分類できます。 作業の属人化で、スケールしてない業務 システム起因で、スケールしてない業務 対応できているが、自動化できる業務 承認プロセスなどで、作業効率が悪くなる業務 作業の属人化で、スケールしてない業務 1つの業務でも、複数のシステムで操作をする必要があるなり、条件によって操作が違うなど場合など、属人化していってしまいます。 また、1日で作業が完了しないタスクなども、どこまで作業したのかをエクセルで管理してしまうなど、よくあるかと思います。 解決方法としては、1つのタスクとして正しく定義をして、やらなくてはならない作業フローを構築していきます。ミスなく作業を完了できるよう、社内の管理画面または外部のシステムとの連携で、誰でも作業できるように設計・構築していきます。 システム起因で、スケールしてない業務 複数人での作業分担を考慮していない管理画面の要因で、分担できない業務などもあります。 管理画面に、タスク一覧などページもあるのですが、1人で作業していた場合は上から順に作業で問題なかったのですが、2人で作業分担にしようとすると難しくなっていきます。上から作業する人と下から作業する人に分かれて作業するなど工夫して運用していました。 同時に同じタスクをするなどの作業ミスが発生しやすいため、システム側で適切に作業を分けていく必要があります。 対応できているが、自動化できる業務 システムでの運用ができておらず、自動化ができてない業務。または、機械学習などを利用することで業務の負担を減らすこともできます。 社内の業務をヒヤリングしていくと自動化できておらず、手作業によって対応している内容が多くあることに気づきます。「BASE」の開発しているエンジニアは、「BASE」のシステムについてはとても詳しいのですが、社内で利用している業務ツール・外部システムの理解が浅いため、業務ツールの連携が弱く、結果的に手作業が発生しています。 毎日開設されるショップ、登録される商品、振り込み申請など多くの情報から、機械学習で自動化に貢献できる業務もあり、Data Strategyチームと協力し自動化をしていきます。 承認プロセスなどで、作業効率が悪くなる業務 一人で完結できない業務などは、他部署・上長へ作業を依頼、または稟議や上長の承認プロセスを得ないと実施できない業務など、人とのコミュニケーションが必要な業務です。下記の項目などが重要になってきます。 承認プロセスや作業依頼のため、ワークフローツールの導入 差し戻し原因となる入力不備おきないよう管理画面の改修 Slack通知などを利用して、コミュニケーションロスを減らす 内部統制の整備 BASE株式会社は、2019年10月25日に東証マザーズに上場しましたが、上場企業は、いわゆるJ-SOX法の遵守が求められます。そのため、2021年度末までにIT統制として不十分な項目の是正・必要書類の作成などが必要となってきます。 CSEメンバーには、IT統制や内部統制について深く理解しているメンバーがいなかったため、プロジェクトを開始する前にメンバー全員でIT統制についての読書会を実施しました。 Amazon: ITエンジニアのための内部統制対応マニュアル 週1回の読書会を通して、IT統制の要点や用語、書類などは理解する事ができるようになりました。しかし、IT統制について書かれている本の多くが、J-SOXが施行された2008年前後に出版された本が多いです。そのため、いわゆるWeb系の企業が想定されている本が少なく、ウォーターフォール開発やオンプレミスの運用の記載されている事が多く、BASEにはそのまま適用できません。 また、IT統制については各社によって事情が異なる事が多く、ネットにも有益な情報があまりありません。 BASEでは、GithubのPullRequestでの開発フロー(承認プロセス)、AWSを前提とした内容に読みかえながら、監査法人と議論を重ねています。 なお、昨年のAdvent CalendarでもGithubを活用した事例をあげています。 devblog.thebase.in IT全般統制 財務に関する不正が起きないように、社内のルールの策定・システムの改修 統制がとれた開発ができるように、システム要件の定義 IT全般統制で整備が必要な項目が出てくると、開発、ネットワーク、DBに関する変更なども発生します。全てをCSEメンバーでは対応できないため、要件をまとめ、各部署と整備を実施して行く事が肝心となってきます。 IT業務処理統制 財務に関わるシステム・業務手順、それにまつわるリスクの把握 新しいApp、新たな取り組みなど、システム・業務手順の整備 いわゆる3点セット(業務フロー図、業務記述書、リスク・コントロールマトリクス)の作成 メンバー全員がエンジニア出身な事もあり、業務フロー図と業務記述書については、PlantUMLを用いて記述しています。 エクセルで図を作成してしまうと、バージョン管理ができず修正が発生した際に、修正箇所の把握が難しくなります。PlantUMLを利用すればテキストで管理できるため、githubでバージョン管理し、PullRequestで変更箇所、承認なども把握しやすくなります。 個人情報の取り扱いの方針定義など J-SOXとは直接関係ありませんが、個人情報の取り扱い方針の定義などもしています。 ショップオーナーが安心してご利用いただくには、個人情報の取り扱いについても重要な要素となってくるため、指針などを策定し、適切に管理できるよう整備を行っていきます。 監査法人へ内部監査状況の報告 監査法人へ内部統制の状況を報告しています。 新しい機能など日々リリースされています。システムの変更内容、システムの構成、時にはテーブル構造を説明し、財務報告の内容やショップの売上が正しい事を確認し報告します。 まとめ BASEの成長を支えてきた行動指針のひとつに「Move Fast」があります。内部統制については、統制内容によっては開発スピードを落としてしまう要因になりかねません。全員が重要視している指針だからこそ、どういった統制内容ならBASEの文化に合い、なおかつ統制として信頼できるかが重要になります。メンバーで統制内容を決める際に、一番気をつけている内容です。 業務改善では、私自身もすべての業務を把握していないので、「一度は業務をやってみる」ことを心がけています。アカウント権限などでできない業務もありますが、それでも一度は一緒に画面を見ながら操作することで内容を把握しているようにしています。一番の理由は、担当者から業務を聞いただけでは業務全体が把握しづらく、業務改善も部分最適になってしまうと感じているからです。 CSEのチームメンバーが社内業務について深く知ることで、他の部署とのミーティングで「○○ような事できますか?」という質問がどんどん出てくるようになりました。小さな問題や改善要望なども気軽に相談してもらえる環境になってきていると感じます。 明日はShopグループの栗田さんです。 お楽しみに。
この記事はBASE Advent Calendar 2020の6日目の記事です。 devblog.thebase.in こんにちは。BASE BANK 株式会社 Dev Division所属、Software Developer の松雪( @applepine1125 )です。 現在、BASE BANK株式会社(以下BASE BANK)内で事業に対する認識を揃え効率良くプロダクト開発を行うために行っているドメインモデリングについてご紹介します。 BASE, BASE BANKのドメインとは BASE BANKでのドメインモデリングの話をする前に、まずはBASE株式会社(以下BASE)やBASE BANKの事業領域について少しお話しましょう。 BASEでは、誰でも簡単にネットショップを作成できるサービス「 BASE 」 を運営しており、ショップ画面のカスタマイズや商品の管理、決済、発送、売上管理など、オーナーズが「BASE」上でショップ運営を行うための様々な機能を提供しています。 BASE BANKでは、オーナーズのキャッシュフローを加速させるために、資金調達サービス YELL BANK や売上金を最短翌日に振り込むことができる お急ぎ振り込み機能 など、オーナーズがBASEで作成したショップを通して得た売上にまつわる様々なサービスや機能の開発、運用を行っています。 これらのことからわかるように、BASE BANKの事業はBASEから完全に独立しているわけではなく、むしろBASEと事業面でもシステム面でも密接に結びついています。 そのため、事業運営のためのドメイン知識も共通の概念が多く、サービスや機能の設計、開発ではBASE側のメンバーとコミュニケーションを取りながら進めることがほとんどです。 ドメインモデリングを始めるキッカケ BASE BANKが設立されてから最近までごく少数のメンバーで開発運用が行われてきたこともあり、事業やシステムに登場する概念とその関係が何らか目に見える形で継続して整理され続けるということはありませんでした。 しかしBASE BANKとしてショップの売上というかなり重要な領域に携わっているため、BASE BANKのメンバーはドメインに対する理解を常に深めていくべきであり、またチームに人が増えてきたタイミングなのでドメインモデリングを通してドメイン知識のインプットも行えると効率がよいのでは、という声があがりBASE BANKのメンバーでドメインモデリング会が開催されるようになりました。 自分が入社して日が浅い頃に出したPRの中で、そこそこな量の語彙やロジックの認識合わせが発生し、上記のようにドメインモデリングの機運が高まったのがキッカケでした。 そもそもドメインモデリングとは そもそもドメインモデリングとは一体何なのでしょうか、ここで一旦おさらいしておきましょう。 Domain Driven Designの著者であるEric Evansは、まずドメインモデルについて ドメインモデルとは特定の図ではなく、図が伝えようとしている考え方である。 これはドメインエキスパートの頭の中にある単なる知識ではなく、その知識が厳密に構成され、選び抜かれて抽象化されたものなのだ。 と述べています。 そしてドメインモデルの基本的用法、つまりシステムや事業に対しどのように作用するかとして、 1. モデルと設計の核心が相互に形成し合う 2. モデルは、チームメンバ全員が使用する言語の基盤である 3. モデルとは、蒸留された知識である の3つを挙げています。 モデルと設計の核心が相互に形成し合う とは、つまりモデルとそれに基づいた設計、実装が密接に結びつくことでモデルに価値が生まれ、ソフトウェアが正確であると言えることを示しています。 モデルは、チームメンバ全員が使用する言語の基盤である ことで、モデルをチーム内の共通言語とし、エンジニアのみならず同じチームであるデザイナーやビジネスのメンバーとも共通言語を用いてコミュニケーションを取ることで、コミュニケーションとソフトウェアの実装とを深く素早く結び付けられるようになります。 最後の モデルとは、蒸留された知識である が指し示しているのは、先に引用した 知識が厳密に構成され、選び抜かれて抽象化されたもの と同義と考えてよいでしょう。 モデルが "厳密に構成され、選び抜かれ" ていることで、無駄な語彙のブレや認識のズレの発生を抑えることができ、より効率的にメンバーが作業を行えるようになります。 そういったドメインモデルを形成する際、効率的なモデリングの要素として 1. モデルと実装を結びつける 2. モデルに基づいて言語を洗練させる 3. 知識豊富なモデルを開発する 4. モデルを蒸留する 5. ブレインストーミングと実験を行う の5つをEric Evansは自身の経験を基に導き出しています。 1,2,4はドメインモデルの基本的用法に結びつきそうなのですが、3と5はどういった意味なのでしょうか。 モデルの名前や関係だけでなく、その振る舞い、制約も含めてモデリングすることで、業務に必要な様々な知識をモデルを通して捉える事ができる。そういったことを 知識豊富なモデルを開発する と表現しています。 ブレインストーミングと実験を行う ことは、思考実験用に様々なモデルを登場させ、様々なユースケースに適用し使えるかどうかを机上で試すことで、表現や振る舞いが的確かどうかのフィードバックを素早く獲得できるということを指しています。 モデリングにおいていちばん重要なのは、以下の図のようにモデリングの成果物を設計や実装に落とし込んで運用してみて得た新たな知見をモデルに反映させる フィードバックループ(継続的な学習) を構築することです。 ドメインエキスパートも含め、事業やシステムについて始めから"完全に"理解していることは殆ど無いでしょう。事業を運営したりシステムを構築、運用していく上で様々な発見をするはずです。"わからないことがわかる(無知の知や不確実性に気づく。と言えるかもしれないですね)"ということもあるでしょう。 そういった発見を無碍に扱うのではなく、意識的にモデルに取り込み、育て、共有し、次の設計や開発に活かすことでドメインモデルの真価が発揮されます。 俺たちのドメイン”リ”モデリングとは ここまで前提となるBASE, BASE BANKのドメインについてや、ドメインモデリングの考え方について説明してきましたが、ようやくBASE BANKで行っているドメイン"リ"モデリングについてご説明します。 ちなみにタイトルやこの節の名前がドメインモデリングではなく ドメイン"リ"モデリング となっていることにお気づきでしょうか。 ドメインモデリングを始めるキッカケ の節で述べたように、これまで体系立てて継続的にドメインの整理を行ってこなかったので、メンバー各々の頭の中に存在するふわっとしたモデルを一度解体し、再構築する。という意味合いを込め ドメイン"リ"モデリング と呼びました。 具体的に、ドメイン"リ"モデリングでは、 - 現在運営、開発しているサービスの概念をホワイトボードツール miro を使ってまず羅列し、ドメインエキスパート(BASE BANK立ち上げ時から関わっているPMやエンジニアなど)に各概念や関係の説明をしてもらう - その中で他のメンバーも含め質問や議論をしながら、名前(クラス名含む)のブレを修正し、各概念の関係を再検討、再構築していく といったことをひたすら繰り返していきます。 例を挙げると、振込申請という機能についてドメインモデリングを行った際は以下のような成果物となりました。 モザイクだらけで申し訳ありません。概念が多数登場して色々な整理を行っていそうだな?というのが伝わればと・・・ ドメイン"リ"モデリングではモデルの脱構築を目的としているので、すでに構築されているシステムの実装(各モジュールやテーブル定義など)に引っ張られないことが重要です。チーム内の議論でも、油断すると現在のシステムではこうなっているから~という論じ方になってしまうため注意深く進めました。 より深くモデリングを行うのであれば、リレーションシップ駆動要件分析(RDRA)やICONIXなどの分析フレームワーク、プロセスを採用すべきかと思いますが、BASE BANKのドメインモデリングではRDRAで言うところの概念モデルのみを作成している段階です。 理由は、BASE BANKが複数サービス、機能を受け持っているため、まずはそれぞれの概念について広く整理することを目的としたからです。 しかしライトウェイトなドメインモデリングだけで終わらせる気はなく、運用していく上でさらにドメインに関する知見を得たり、フィードバックループのイテレーションをより素早く回せるようになったら、より深いモデリングを行っていくつもりです。 ドメイン"リ"モデリングのこれから そもそもドメインモデリングとは で述べたように、モデルは実装と結びついて価値が生まれます。しかし”リ”モデリングを始めてからまだ日も浅く、すでに構築されたシステムに対して"リ"モデリングしたモデルを適用しようとすると大きく変更が必要となる箇所がいくつかあるため、現状モデルと実装を密接に結びつけられているとは言い難い状況であるというのが課題としてあります。 しかしドメイン"リ"モデリングをきっかけに、追加機能の設計やそれに伴うリファクタリングにおいて、チーム内で作成したモデルを基に活発に議論が交わされたり、カジュアルにドメインモデリング会が開催され設計や実装が行われている様が見受けられます。 また現在新規開発しているサービスにおいても、概念やその関係の整理を丁寧に行いながら開発を進められているので、ドメイン"リ"モデリングはただのムーブメントに終わらずBASE BANKチームに定着していくだろうな、そうなるように今後も継続して既存の実装に対してもアプローチできるようにしていかなければと感じています。 もう一つの課題として、 BASE,BASE BANKのドメインとは の節で BASE側のメンバーとコミュニケーションを取りながら進めることがほとんど と述べましたが、BASE側のメンバーも含めてドメインモデリング会をやろうとすると大所帯になり機動力が落ちてしまうので、BASE BANKのメンバーのみでモデリングを行っているというのが現状です。 つまり業務上の関係者全員とはモデルを共有できていないということになるので、Eric Evansの言う "モデルは、チームメンバ全員が使用する言語の基盤である" というドメインモデルの基本用法と逸脱してしまっています。 これに関しては、今後業務内で関係者とコミュニケーションを取る際に少しづつ浸透させていったり、ドメインモデリングという活動自体を社内に広めていき、よりコミュニケーションを取りやすくできればなと思っています。 おわりに 以上、俺たちのドメイン"リ"モデリングの紹介でした。 余談ですが、ドメインモデリングを行う過程で各事業のドメインが整理されるだけでなく、BASEの中でのBASE BANKという会社の立ち位置がより明確になったのがとても印象的でした。 after baseとは、オーナーズがショップで売上を立ててから先のお金の流れとそれに関連する機能、サービス(YELL BANKやお急ぎ振込など)を指す社内用語です。 ドメイン"リ"モデリングを通じて、各事業への理解が深まるだけでなく、それらを運営していく会社そのもののスタンスも明らかになることは今回新たな発見でした。 明日は BASE 株式会社 CSEチームの小林さんです! ではまた。 参考文献 Eric Evans, エリック・エヴァンスのドメイン駆動設計( https://www.shoeisha.co.jp/book/detail/9784798126708 ) Vaughn Vernon, 実践ドメイン駆動設計( https://www.shoeisha.co.jp/book/detail/9784798131610 )
この記事はBASE Advent Calendar 2020の5日目の記事です。 SRE Groupのngswです。 Eコマースプラットフォーム「BASE」における障害発生時に、社内関係者に連絡網に基づいて電話発信するシステムを構築しました。 このエントリでは、その導入までの経緯と具体的な当該システムの説明をします。 TL;DR 「BASE」で問題が発生した際に意思決定者に電話発信する周知システムを構築した 「導入前に考えたこと」をまず主題として書いた 参考URL記事のまま手順であるが、それでも導入時に詰まった事柄など落ち穂拾い的に追記した 謝辞 Twilio FunctionsとStudioを使って連続架電を行う - Qiita 大変わかりやすい記事であり、ほぼすべてを参考にさせていただいた。このQiita記事がなければ短期間で実現することは不可能であったと考える 導入に至る経緯 07月某日 : サイト閲覧遅延障害が起きたことで「発生とあわせて社内関係者に機械的に一斉周知する方法が必要なのではないか」という議論があった 09月某日 : 07月と別起因ではあるが同様のサイト閲覧遅延が発生し、当時の議論が再度浮上した 個人的な感想 : 二度議論されたことは対応する価値があるのではないか。少なくとも検証する価値はあるのではないかと考えた 導入前に考えたこと まずはじめに「解決すべき課題がなにか」を考えなくてはならない。 「あわせて社内関係者に機械的に一斉周知する方法が必要なのではないか」という議論から考えられるのは、議論発案側の役割(とそこに課せられた責務)が関係してくる。プロダクトが正常動作していないことを利用者であるショップオーナー様に通知する責任があり、またはその状況を認識して次なる意思決定に備える必要があるという、それぞれの立場からくる「わたしに然るべき通知をできるだけ早くください」という表明にほかならない。 その一方でこれらがなぜ求められる状態になったのか。これは「システム障害対応時に対応エンジニアが周知する時間をうまく取れない場合がある」ということの証左でもある。システムに対する止血対応と、プロダクトに対するインパクト度合いを含めた状況説明。これがアラートに機敏に反応できた対応エンジニアに一手にかかってきてしまっていて、結局その対応エンジニアが障害対応全般を含めたボトルネックになっているということでもある。この点を機械的にスムーズに解決する方法が求められているのだろう。 なるほど、裏を返せばWebエンジニアは意思決定者を含めた社内関係者に、関係者はユーザであるショップオーナー様に対して「説明責任がある」ということである。今思えば仕事というもののほとんどはこの「説明責任を果たすことに終始するのではないか」とまで考えるようになった。 であればこれは単なる障害通知システムの補助機能ではない。わたしは大義を手に入れた。それでははじめよう。 仕様 BASEショップページの応答速度低下の検知は、既存のmackerel監視設定を利用する 発報はmackerel にて Twilio架電通知 を利用すればよさそうである ただし上記機能だけでは架電先が1つの番号に限られてしまうという制約がある そのためmackerel上の設定では dummy call とする(この成否はどうでもよいので ngsw の番号を設定した) mackerelは上記処理の成否をStatus Callback URL(Twilio) にリクエストする 上記のリクエストを契機に後述する Twilio Functions に設定したjsが電話番号のDictを持つのでfor文で一人ずつ電話発信 音声「対応可能なら1、無理なら0」に対して、キー1押下ならそこでループ終了、キー0なら次の人(無視、通話中、即切りも同じ) 配列最後までいったら指定最大回数までループする 構成要素 / 登場人物 全体 Name Role Memo 「BASE」 監視対象 主に閲覧に関する応答速度に注目 Mackerel 監視システム 「BASE」システムを監視してTwilioに通知 Twilio 電話発信システムとして利用 Twilio内の細分化 Name Role Memo Twilio Functions Flowを呼び出すためのスクリプト URLをもつ Twilio Studio Flowを定義する 音声認識やプッシュ番号認識ができ、条件分岐ができる 購入番号 発信番号 購入しないと発信行為に制約がある 参考URL Twilio FunctionsとStudioを使って連続架電を行う - Qiita を参考にした 大事なことなので何度でも Twilio Functions Functionsのコードは一度デプロイして画面を閉じた場合、改めてFunctions画面からスクリプト内容を再取得しようとすると失敗が繰り返され編集できない事象を確認している(運良く取れるときがある / Rate Limit ?) 以下でURLが確定する https://${DOMAIN}/$(パス名) Functions作成時に Environments DOMAIN が払い出される パス名を自分で決める Functions /function-name Assets (無視) Settings - Environment Variables - FLOW_SID https://jp.twilio.com/console/studio/dashboard で閲覧可能な FW から始まるSIDのこと FROM_NUMBER +{購入番号} // https://qiita.com/mobilebiz/items/8757eec854f37ce0cb2d /** * Studioを連携させた連続架電 - serialCallStudio * * @param idx リストインデックス * @param loop ループ回数 */ // 架電先リスト(発信したい電話番号のリストをE.164形式で記述します) const callList = { "携帯1": "+8150yyyyyyy0", "携帯2": "+8180yyyyyyy1", }; // ループ回数(1以上の整数、1ならループしない) const maxLoop = 2; exports.handler = function(context, event, callback) { // カウンター関連 let idx = event.idx || 0; // インデックスパラメータを取得 let loop = event.loop || 1; // ループパラメータを取得 if (idx >= Object.keys(callList).length) { // リストの最後まで到達 idx = 0; // インデックスは0に戻す if (loop >= maxLoop) { // ループ回数が最大値を超えたので終了 callback(null, "Call count was expired."); } else { loop++; // ループ回数をインクリメント } } // 架電先電話番号 let number = callList[Object.keys(callList)[idx]]; idx++; // インデックスをインクリメント // 架電するStudioフローを呼び出す const client = context.getTwilioClient(); client.studio.v1.flows(context.FLOW_SID).executions.create({ to: number, from: context.FROM_NUMBER, parameters: JSON.stringify({ idx: idx, loop: loop, }) }) .then((call) => { callback(null, "OK"); }) .catch((error) => { callback(error); }); }; Twilio Studio 手順的なデッドロック Functions が先にできないと Twilio Studio で Flow が完成しない しかしFunctions完成には FLOW_SID が必要 解決策は以下の手順の中で Run Function だけをとりあえず置いといてPublishなりして Flow SID を確定しておくこと FLOW CONFIGURATION Flow 実行のトリガー Config FLOW NAME SerialCallStudio REST API URL https://studio.twilio.com/v1/Flows/FWxxxxxxxxxxxxxxxxxxx/Executions WEBHOOK URL https://webhooks.twilio.com/v1/Accounts/ACxxxxxxxxxxxxxxxx/Flows/FWxxxxxxxxxxxxxxxxxxx TEST USERS (空) Transitions IF INCOMING MESSAGE (空) IF INCOMING CALL (空) IF REST API call MAKE OUTGOING CALL V2 架電時に受電側のステータスで分岐 Config WIDGET NAME call NUMBER TO CALL {{contact.channel.address}} RECORD CALL OFF DETECT ANSWERING MACHINE OFF SEND DIGITS (空) TIMEOUT 60 SECONDS SIP USER NAME (空) SIP PASSWORD (空) Transitions IF ANSWERD Gather IF BUSY LoopFunction IF NO ANSWER LoopFunction IF CALL FAILED LoopFunction GATHER INPUT ON CALL 通話中のメッセージと、そのメッセージに対する回答の保持 メッセージはテキストだけでなく設定次第で音声ファイルでも可能 受電者の以下のアクションを理解できる どのプッシュボタンを押下したか 音声認識による回答内容(はい or いいえみたいなもの) これはうまく動かなかった Config WIDGET NAME Gather SAY OR PLAY MESSAGE TEXT TO SAY {ここに発音させたい1 or 0で分岐するようなテキスト文を書く} LANGUAGE Japanese MESSAGE VOICE Alice NUMBER OF LOOPS 1 STOP GATHERING AFTER 5 SECONDS STOP GTHERING ON KEY PRESS? YES / # STOP GATHERING AFTER (空)DIGITS SPEECH RECOGNITION LANGUAGE Default SPEECH RECOGNITION HINTS (空) PROFANITY FILTER True ADVANCED SPEECH SETTINGS - SPEECH TIMEOUT (IN SECONDS) auto SPEECH MODEL Numbers & Commands Transitions IF USER PRESSED KEYS YesOrNo IF USER SAID SOMETHING (空) IF NO INPUT LoopFunction Split Based On… 条件分岐とその判定 Config WIDGET NAME YesOrNo VARIABLE TO TEST widgests.Gather.Digits Transitions COMPARING WITH {{Gather.Digits}} IF NO CONDITION MATCHES LoopFunction YES == 1 Equal To / 1 / SayYes NO == 0 Equal To / 0 / LoopFunction Say/Play Push 1 だった際の後処理 Config WIDGET NAME SayYes SAY OR PLAY MESSAGE OR DIGITS Say a Message TEXT TO SAY {ここに発音させたいテキスト文を書く} LANGUAGE Japanese MESSAGE VOICE Alice NUMBER OF LOOPS 1 Transitions IF AUDIO COMPLETE (空) Run Function Push 0 ないしは 1 以外だった際の再実行 または通話中やなんらかの理由で通話不可だった場合 Config WIDGET NAME LoopFunction SERVICE SerialCallStudio ENVIRONMENT ui FUNCTION /function-name 1 FUNCTION URL (自動付与) Function Parameters これらはjs内で引き回して利用される idx {{flow.data.idx}} loop {{flow.data.loop}} Transitions IF SUCCESS (空) IF FAIL (空) 結び 前半では導入の経緯を、後半ではシステムの詳細を書いた。繰り返しになるが概ねの主題は前半部である。そこが語りたいことのすべてであった。後半部の成果物解説はその残滓でしかないが、それでも同様に導入を考えた方がいた場合に、何かしらの参考になればと大元のQiita記事をさらに補完できるような記述を心がけた。 導入後はすこぶる順調で特にクレームもなく、期待通りの稼働をしており役割は果たせたと考えている。このようなシステムやツールを用いて説明責任を果たしていくのがSRE(だけでなくエンジニア)なのだと感じたという点を強く強調し、結びとしたい。 明日は BASE BANK 株式会社の松雪さん (@applepine1125) の記事です。 引き続きよろしくお願いいたします。
この記事はBASE Advent Calendar 2020の4日目の記事です。 devblog.thebase.in こんにちは、BASEのデータストラテジーチームを担当している鈴木( id:rmarl )です。 普段は、機械学習エンジニアやデータエンジニアメンバーと一緒にデータ活用の推進を行っております。 昨年のアドベントカレンダー でもDSチームの取り組みについて書かせていただきましたが、今年はより開発対象を拡大し、以下のような領域について開発を進めております。 ネットショップ作成サービス「BASE」をご利用のショップオーナー様への自動アドバイス、ショッピングアプリ「BASE」のユーザーへおすすめ商品のレコメンド 時系列分析やそれを活用したモデルの構築(BASE BANK) 異常検知 検索エンジンの精度向上 データ基盤の構築とBIツールの利用促進 このように開発領域が広がっていくにつれて、集中して技術習得する時間がないという課題が見えてくるようになりました。 それに対して年初からHackWeekを導入し実際に目に見える効果も出てきたので、ここで共有したいと思います。 HackWeekとは? 一定期間業務を離れて、一つの研究テーマに集中する時間を設ける事です。 それにより、チーム全体の開発力の底上げを期待しています。 元々は2017年にデータサイエンティスト向けの教育プランの論文として発表された物がベースになっております。 arxiv.org ここにもあるように、HackWeekは集中する事によってもたらす以下の効果を期待しています。 最先端の方法論の習得 ピアラーニング 実務との融合(論文にあるコラボレーションもその一つ) 上記に加え、Google社の20%ルールのような「内製化による技術革新のブースト」、ハッカソンのような「短期間における発想力の強化」も期待できます。 BASEでの活用方法 そもそもがチーム全体の開発力の底上げを期待しているため、実業務を優先しつつ無理のない範囲で、メンバー主体でHackWeekに立候補して頂いています。 個々のメンバーの希望を元に、以下のような条件で定めています: 対象テーマ 先述の開発領域において、将来的に活用しそうな学習モデルの検証 最新の論文内容を実データで検証 過去の開発時に、後で検討するとしたテーマの検証 日程について 期間は原則1週間 期間終了後、速やかに報告会を行う リリース前・繁忙期を避ける サポート問い合わせ対応期間は避ける 環境の準備 検証のためだけの有料サービス利用も可 sandboxとして、ML専用サーバーに空きがあれば占有も可 また、HackWeekに入る事を宣言したメンバーに対しては、その期間の間、以下のような勤務体系としています。 弊社では特に導入で問題はなかったのですが、この辺りの調整を要するケースもあるかと思います。 HackWeekに専念するため、出社は任意 現在はWork From Home実施のため、基本はリモート勤務となっております そのメンバーが担当していた通常業務は、出来る限り他のメンバーが協力して代行する それでも緊急対応が入ったら、その対応の日数分、報告会を延期する どのような内容を実施したか進捗ログをまとめておき、報告会で共有する。 報告会 HackWeek終了後、報告会は以下の要領で実施します。 検証完了・中途問わず、発表する 報告20~30分、質疑応答20~30分と1時間で開催 可能であれば、デモ環境も用意する 報告用文書は必須とする どういったテーマが選ばれるか? 今年に入ってから20件近く報告会が開催されましたが、一部を抜粋すると以下のようなテーマがありました。 ナレッジ収集のためのグラフDB活用法 商材動画における物体検知 学習にobjectの位置情報を利用しないobject detection Grad-CAM カテゴリー・属性抽出の手法 音声フレームワークの検証 どのような成果が出てきているか? 一番の成果としてはピアラーニングの効果が大きく、メンバーの気付きが開発中案件に応用される例も出てきています。 また、メンバーは任意のテーマを選ぶことが出来るようにしてあるのですが、実務と結びついたテーマも多かったです。メンバー曰く「実務中に試してみたかったけど時間や採算性の問題で保留にした課題をこの期間で検証したい」との事で、こちらもHackWeekの成果の方が効果があるという事で実務に組み込まれた例もあります。 まとめ HackWeek実践のメリットを取り上げてきましたが、BASEにおいてはデータ活用を非常に重要視した取り組みをおこなっており、その実現に対して柔軟な体制をしいております。 今後とも、データ活用を通じて皆様の利便性に貢献していければと思います。 明日は、SREチームの長澤さん( id:ngsw )です!お楽しみに!
この記事はBASE Advent Calendar 2020の3日目の記事です。 devblog.thebase.in BASE株式会社 SRE Groupの相原です。 BASEのインフラはAWS上に構築しておりいくつかのツールを使って構成管理していますが、主にEC2のサーバ設定ツールとして利用しているのが現状で、構成管理できていないAWSリソースもちらほらあります。 そこでまずはSRE Groupで使っている社内ツールや、直接サービス影響のないものを Terraform で構成管理をしてみて、ある程度運用が固まってきたら主サービスの管理もそちらに寄せていこうという方向で進んでいます。 Terraform導入にあたり最も悩んだのがtfstateの分け方とディレクトリ構成だったので、そこをメインに紹介できればと思います。 謝辞 以下の書籍と記事を非常に参考にさせていただきました。ありがとうございます。 野村友規 (2019) 『実践Terraform AWSにおけるシステム設計とベストプラクティス』インプレスR&D Terraformのディレクトリ構成の模索 | ADWAYS ENGINEERS BLOG Terraformなにもわからないけどディレクトリ構成の実例を晒して人類に貢献したい | M3 Tech Blog Sansan Labs 開発での Terraform ディレクトリ構成 | Sansan Builders Blog 前提として 最初から全てのAWSリソースをTerraformで構成管理することは諦める AWS上ではTerraform以外ですでに構成管理されているリソースや、そもそも管理されていないものも存在しています。それらを一挙にまとめてTerraformへ移行するのは難しいと感じたので まずは社内ツールなどサービスに直接影響のないものから小さくはじめる 運用の形が定まってきたら徐々にTerraformへ移行していく という前提で進めています。 tfstateの分け方とディレクトリ構成 ディレクトリ構成は以下となります。 . ├── prd │ ├── projectA │ │ ├── terraform.tf │ │ ├── main.tf │ │ └── variables.tf │ └── projectB │ ├── terraform.tf │ ├── main.tf │ └── variables.tf ├── stg │ ├── projectA │ │ ├── terraform.tf │ │ ├── main.tf │ │ └── variables.tf │ └── projectB │ ├── terraform.tf │ ├── main.tf │ └── variables.tf ├── dev ... └── modules ├── moduleA │ ├── README.md │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── moduleB │ ├── README.md │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ... 方針としては以下になります。 1. 環境ごとにディレクトリを分ける BASEでは多少なりとも環境間での差分があります。workspaceの利用も検討しましたが、その場合差分を吸収するためのロジックを書く必要があり、かえって分かりにくくなりそうでした。そのためディレクトリで環境を分けるようにしました。 2. tfstateは環境ごとではなくprojectごとにもつ projectという単位は「なんらかの意味を持ったリソース群」といった意味合いで便宜上使っています。 前提として社内ツールなどサービス影響の少ないものから小さく始めていきたいというのがあります。環境単位でtfstateを持ってしまうと、影響範囲が大きくなることもありこの前提から外れてしまいます。そのためtfstateはprojectごとに持つようにしました。 3. moduleを利用する resource はmoduleに書いて、projectのtfファイルから呼び出す形をとっています。これにより環境の複製はmoduleに渡す変数の値を変更するだけで良くなります。 ただこの場合、どこまでmoduleに汎用性を持たせるか難しいところではあります。また複数のprojectから同一moduleを呼び出している場合、module変更による影響範囲が大きくなってしまいます。この辺りは特に運用しながら改善していくポイントかなと考えています。 その他取り入れたこと 1. Terragruntの導入 Terragrunt というTerraformのラッパーツールを導入しました。これはbackend定義周りのコードをDRYに保つためです。 というのもtfstateを環境単位ではなくproject単位で持たせるので、backendの定義もproject単位で書く必要があります。その場合にproject毎でそれらを書くのが面倒なのと、設定ミスが起きることを懸念したためです。 Terragruntの導入にあたっては、以下記事を大変参考にさせていただきました。 TerragruntでTerraformのbackend周りのコードをDRYにする | Developers.IO 以下は、ほぼ記事の内容通りに実践したものになりますが、具体的なディレクトリ構成とファイルの内容です。 . ├── prd │ ├── projectA │ │ ├── terragrunt.hcl │ │ ├── terraform.tf │ │ ├── main.tf │ │ └── variables.tf │ ├── projectB │ │ ├── terragrunt.hcl │ │ ├── terraform.tf │ │ ├── main.tf │ │ └── variables.tf │ └── terragrunt.hcl ├── stg │ ├── projectA │ │ ├── terragrunt.hcl │ │ ├── terraform.tf │ │ ├── main.tf │ │ └── variables.tf │ ├── projectB │ │ ├── terragrunt.hcl │ │ ├── terraform.tf │ │ ├── main.tf │ │ └── variables.tf │ └── terragrunt.hcl ├── dev ... 各環境、projectごとにterragrunt.hclが追加されています。 このファイルにTerragruntの設定を書いていきます。 環境ごとのterragrunt.hcl {env}/terragrunt.hcl remote_state { backend = "s3" config = { bucket = "test-aihara-terraform-tfstate" key = "${path_relative_to_include()}.tfstate" region = "ap-northeast-1" dynamodb_table = "test-aihara-terraform-tfstate-lock" } } path_relative_to_include()は親ディレクトリから子ディレクトリへの相対パスを返します。 https://terragrunt.gruntwork.io/docs/reference/built-in-functions/#path_relative_to_include projectごとのterragrunt.hcl {env}/{project}/terragrunt.hcl include { path = find_in_parent_folders() } find_in_parent_folders()は親ディレクトリからterragrunt.hclを探してきて読み込んでくれます。 https://terragrunt.gruntwork.io/docs/reference/built-in-functions/#find_in_parent_folders 例えばこの場合だと{env}ディレクトリにあるterragrunt.hclを読み込むことになります。こうすることでprojectごとにおけるbackendの定義は、同じ内容のterragrunt.hclを用意するだけで済みます。 2. terraformで作られたことがわかるようにtagをつける AWS上ではTerraformで構成管理されたもの/そうでないものが混在していくことになります。その時、どれがTerraformで作られたのかわかるように特定のtagをつけるようにしています。 例えば以下のように terraform: true のtagをつけるようにするなどしています。 resource "aws_security_group" "security_group" { name = var.name description = var.description vpc_id = var.vpc_id tags = { "terraform" = "true" } } おわりに 前述したとおりTerraformの導入はまだ社内ツールやサービス影響のないものに留まっております。 一旦方針決めはしたものの、tfstateの分け方やディレクトリ構成に関してまだ試行錯誤しているというのが現状です。ここに関して決まった正解はないと思いますが、運用を続けていく中で継続的に改善しより組織やサービスにフィットするようにしていければと思います。 明日はProduct Dev DS Groupの鈴木(@rmarl)さんです!お楽しみに〜
この記事はBASE Advent Calendar 2020の2日目の記事です。 devblog.thebase.in こんにちは、BASEのフロントエンドチーム エンジニアの加藤です。 先日、弊社松原の こちらのブログ にて、「既存のVue.jsによる資産は積極的にメンテナンスしつつ、その時その時で総合的に判断して最適な技術を選定する」スタンスで我々は考えているということをお話しました。直後に Vue.js 3.0の正式リリース があり、アップデートに関して実際に取り組みを始めています。 現在イメージしている流れ 現在、BASEのサービスで使われているバージョンは2.6系で、そこからのアップデートということになります。 現在利用しているVue.jsに依存したUIライブラリやバリデーションライブラリも3系対応で大きくAPIが変わることが予想され、一気に全ての使用箇所でバージョンをアップデートすることは困難だと感じています。 そこで、次のような流れで進めていくことを現在計画しています。 Deprecatedな機能の置き換え作業 社内UIライブラリのVue.js3系対応版の開発 monorepo化とそれに際する依存関係の再整理 packageごとにバージョンを使い分け、徐々に移行 Vue.jsを使用しているBASEのショップ向け管理画面では、 こちらのブログ にあるように、機能単位でエントリポイントが存在するMPAであるという前提があります。この単位でpackageを分割し、それぞれでVue.jsのバージョンを使い分けることで段階的なアップデートの実現を考えています。 今回は、現在進行中の「Deprecatedな機能の置き換え作業」についてお話します。 対象範囲 Vue.js 3のマイグレーションに関するドキュメント から参照します。 前述の通りpackageごとにアップデートするという予定ですが、事前に対応できるものがあればやっておきたいところです。今回対応するものは、この中で「置き換える機能がすでに2.6系に存在しているか、3にアップデートせずとも別の修正方針が存在する」もののみをターゲットにしました。 filterの廃止 Functional Componentの廃止 slot属性,slot-scope属性の廃止 (2.6にてDeprecatedとなっていますが3で正式に廃止されます) EventEmitter系のAPI($on, $off, $once)の廃止に伴う対応 以上が一旦対応すべきものとして洗い出されました。 事前準備 弊社右京の こちらのブログ で設定してもらったように、ESLintのeslint-plugin-vueプラグインで非推奨の機能を機械的に判定します。また、fixオプションで修正できるものは修正してしまい、それ以外の以下は手動で修正して回ります。 実際の修正 filterの廃止 どのように修正するか メソッドに置き換える 対応するeslint-plugin-vueのルール vue/no-deprecated-filter 注意点 ここでは単なるメソッドに置き換えます。場合によっては、算出プロパティでその処理を記述しておくほうが良さそうな実装も見かけましたが、対応を統一したいため一旦方針として今回はメソッドで実装しています。 金額表示を変換するfilterがよく使われていましたが、これらはMixin経由でVueのprototypeメソッドとしても登録されているのでそちらに置き換えました。 Functional Componentの廃止 どのように修正するか 通常のコンポーネントに書き換える 対応するeslint-plugin-vueのルール vue/no-deprecated-functional-template 注意点 関数型コンポーネントはインスタンスを持たない(thisのコンテキストが無い) ため、render関数内にcontextというオブジェクトが渡され、そこからpropsなどを参照するといったコードになっています。注意しながらこれらを普通のSFCに書き換えました。 実はこの対応で1つバグを出してしまったので、詳しくお話します。 我々はVeeVelidateというバリデーションライブラリをサービス全体で利用しています。このライブラリでは各コンポーネントに独自のバリデータスコープがあり、親子コンポーネントでのバリデーション結果を共有するために、$validatorという変数を親からinjectオプションを利用して注入することでバリデーションスコープを共有する、ということをおこなっています。 たとえばこういったparentコンポーネントがあった場合、 <template> <child> <grandchild /> <grandchild /> <grandchild /> </child> </template> childコンポーネント内でinjectオプションを利用することで、grandchildコンポーネントにて$validatorを参照することが出来るようになり、親から子のバリデーションを実行することもできるようになります。 今回のバグはこういったケースでFunctionalコンポーネントかそうでないかで挙動が変わってしまった、というものです。 たとえば、上記のgrandchildコンポーネントがFunctionalコンポーネントであった場合を考えてみます。Functionalコンポーネントにはインスタンスがないため、親のスコープですぐに評価されます。このときの親のスコープというのが、ややこしいのですが childではなくparentコンポーネントになります 。生成されたvnodeがスロットコンテンツとしてparentに渡されるわけです。 これは、childがレンダリングされる前に、grandchildコンポーネントがすでに実行されている、ということです。ですから、childコンポーネントでinjectしようにもできない、ということが発生します。 ということで、grandchildがFunctionalコンポーネントだった当時は実装者がparentコンポーネントで$validatorをinjectして事なきを得ました。 これを知らずにそのままFunctionalコンポーネントをそのまま通常のコンポーネントに直してしまうと、当然意図しない動作になります。通常のコンポーネントは、親コンテキストですぐにはレンダリングされず、childのレンダリングサイクル中にレンダリングされます。つまりchildコンポーネントに必要なものをinjectする必要があるということです。 こちらのissueコメント がこの現象を詳しく説明しています。 slot属性,slot-scope属性の廃止 どのように修正するか それぞれ、slot属性ではなくv-slotディレクティブに、slot-scope属性ではなくプロパティを受け取るv-slotディレクティブに書き換える 対応するeslint-plugin-vueのルール vue/no-deprecated-slot-attribute vue/no-deprecated-slot-scope-attribute 注意点 eslint --fix にて一部自動で修正できますが、v-slotディレクティブはtemplateタグにしか利用できないので、templateタグ以外にslot属性が使われているものは自動修正できません。これが修正としては一番数が多く面倒でした。 1つハマったポイントなのですが、slot属性で渡す要素内でthisを参照したときに、slot属性であれば動くものが、v-slotディレクティブでは動かない、という事象がありました。事前にこれらをすべて修正してからslot属性を修正する必要があります。こちらは vue/this-in-template のルールにてチェックできますので慌てて追加しました。元々thisの使用は禁止されていたはずなので、いい機会でした。 まとめ Deprecatedな機能の置き換えに関しては、以下を残り対応する予定です。 Event Emitter系のAPI($on, $off, $once)の廃止に伴う対応 実は今回お話したものもまだすべては直しきれていないので、引き続き対応を続けていきます。 この作業が終了次第、前述の流れに沿って移行していく予定です。 また、2021 1Qに作業される予定の2.7は、3系移行のための支援となる機能が追加されることが予定されています。まず2.7に移行することでよりソフトランディングなアップデートになるのではないでしょうか。タイミングによっては既存の2.6系を2.7にアップデートしてから3系に進めることも考えてもよいと思っています。 明日はProduct Dev SREチームの相原さんです。お楽しみに〜
この記事は2020年 BASEグループのアドベントカレンダー1日目になります。 devblog.thebase.in BASE株式会社取締役EVP of Developmentの藤川です。同じく子会社であるPAY株式会社の取締役、BASE BANK株式会社にも関わっており、グループ横断でスムーズな組織運営とサービス開発を実現し、グループシナジーを通じたバリューアップを意識して仕事をしています。 まだ12月の頭で少し早いタイミングではありますが、2020年を振り返っていきたいと思います。 2020年ってどんな年だった これはずばり我々の価値の出し方の潮目が変わったタイミングだと考えています。グループの真ん中にあるBASEというサービスは、サービスを作ってから今年の頭まで、誤解を恐れずに言えば、代表の鶴岡が作ったサービスコンセプト、そしてそれを体現するユーザ体験、平たく言えばデザイン性に支えられてきたサービスだったように今を考えると思えます。今どきで言うBizDevとサービスデザインが優れていたと表現するとわかりやすいでしょうか。 これまでのエンジニア陣の仕事は、あえて大げさな表現をすると、その環境を維持運営し、ビジネスの自然成長を支えたことで会社が上場するところまで来た、そんな印象すら思うこともあります。 ところがコロナ禍において増えゆくトラフィックを支えていくシーンを目の当たりにし、このままだとこの先の5倍10倍それ以上の成長において壁が出てきそうだと考えたのが2020年に起きたことでした。 その辺を技術的な言葉で冷静に書いたのがCTO川口の記事ではあります。 devblog.thebase.in この経験を通じて、考え方が変わったは大げさまでも、これまで徐々に自分たちが作ってきた採用基準や既存メンバーの成長について、再度言語化することになり、CTOが責任を担うサービス技術と、マネージャメンバーが責任を担うチームマネジメントを一体化して取り組むことを始めたのが2020年の最大の変化だったと思います。 それまでは、どこかサービスを作るという取り組みと、技術を良くしていくという取り組みを、それぞれが得意な人が分業してやればできるんじゃないか?と考えていたところがありましたが、それでは成長していくサービスを支えきれない。このサービスに携わるメンバー全員が、しっかり技術のことを意識し、優れた技術力を礎に良いサービスを作っていくという形にしないといけないということを強く認識させられることになりました。 新型コロナによる社会情勢の変化はとても望ましいものではありませんが、コロナ禍において発生した急速な社会のデジタルシフトの波の中で、我々にとっての甘えが許されなくなったタイミングだとも言えます。 devblog.thebase.in エンジニアリング力の底上げについては、技術投資として仕込んでいるものもあり、引き続きCTOの川口がリードする形でマネージャ陣やチームメンバーと連携しながら進めていくことになります。この成果についてはまた来年の技術ブログで継続的にご報告して参ります。 basebook.binc.jp 2021年はどうなる 開発チームにおいては、非連続的な成長を求められる1年になるかもしれません。 それは今後起こりうる組織の成長や人の増加によって、起こりうるであろう軋轢をどうやってマネジメントしていくか?という視点であったり、人が増えることで責任が明確化されていくであろうCTOを始めとする技術責任者級の人たちの行動、技術、人間における成長を求めていくことになる気がしています。 2020年までの僕自身は、あえて自負をさせていただくと、さまざまな問題について、どうにかうまく立ち回って解決するという行動をしてきたように思えます。新しい問題解決のために体制を作ると言った、インキュベーションのプロセスにおいては、ひとまず自分で手を動かしてプロトタイプを作って知見をまとめてからプロジェクトや組織として人に移譲することもあるし、または、いろんな人達に仕事を任せ動いてもらうことで、成果を出せた人もいれば、そうでない人もいて不確実なイシューを解決することに対するチャレンジをしてきました。 チャレンジそのものは引き続き続いていきますが、そういう混沌の中で成長してきてくれた人に、明確な責任を渡して、責任者としてチームとしてまとめていくことを求めていく年になりそうです。 僕自身は、その中で起きるさまざまなことに目を向けて、開発メンバー全員がBe Hopefulに働き続け、かつSpeal Openlyに自由に発言でき、開発者界隈で叫ばれる心理的安全性的なるものを維持しながら、メンバーの成長を実現し、結果としてサービス開発を成功に導くというのが仕事になるだろうなと思っています。 それにより新たに課題を増やし、共有し、それを解決するために新たに人を迎えてチームが大きくなっていくイテレーションを描いていくというのが、組織の正常進化と思っていますので、このことを躓かないようにしっかりやっていくというのが、引き続きの課題になります。 devblog.thebase.in PAYとBASE BANKについて 技術ドリブンでサービス開発者向けの決済APIを提供するPAYチームは、引き続き少数精鋭の技術者を中心にサービス提供を続けていくことになります。2020年のコロナ禍においては、BASEの決済安定性のためにPAYのメンバーにも多々ご尽力いただきました。BASEというサービスが想定以上に成長することで、PAY.JPサービスにおけるBASEの関与度が大きくなりすぎてしまい、メンバーに対して大きな負担をかけてしまったというのが一つあります。しかし、この経験を礎にPAY.JPのより一層の安定運用に寄与するべく、SREの採用なども進めています。 BASE BANKは2020年で仲間が順調に増えてきたのがなによりもの特徴です。BANKチームは、プロダクトマネージャの柳川と、テックリードの東口が元々BASE開発チームのコアメンバーだったことから、BASEと強く連携するサービスを作ることに慣れていますが、後から入ってきたメンバーもGo言語というキーワードでの入社が無視できなかったにも関わらず、PHPで書かれたBASE側のサービスにもがっつり携わってもらうなど、意識の高い技術者集団として活躍してもらっています。BANK自体のビジネスの促進もさることながら、BASEサービスのショップで売上が発生した後の取り回しについて、しっかりソリューションを強化していき、ショップの成長を支えていくという今後の活躍が楽しみですし、しっかりバリューを実現していきたいと思っています。 僕自身はどうなるんだろう笑 自分が2021にどうなるとかどうしたいとかはあんまりよくわからないですね 笑 実現すべき計画そのものはしっかり存在していますから、それをしっかり実現していくのは当たり前ですが、それ以外に起きうるいろんなことをしっかり問題解決していける余力を持ちながら、日常を生きていく、そんなイメージを持っています。PMIでひーひー言ってるような近しい未来もまたあるのではないでしょうか?ぐらいは覚悟しています。その際には業界での経験者(大体CTO/VPoE経験者かな)には採用オファー、業務委託等々でご相談することもあると思いますので、その際にはよろしくお願いいたします。 2020年もまさかこんなことになるなんて思ってもみませんでしたが、来年もまた自分たちの成長を促される難しい問題が出てきて、それをしっかり解いていける機会があったら、それはそれで楽しいんじゃないかと思っています。我々はまだまだスタートアップであり、上場もゴールではなくサービスの社会的信用を得るためのプロセスでしかないと思います。ショップオーナーさんはもちろんのこと社会からの期待にしっかり応えていく開発組織を作っていくことが責務だと思っていますので、まぁいろいろ起こることが楽しいなと。 何も起きないのが一番退屈でモチベーションが下がる混沌loverなタイプなのですが、変化によってメンバーが躓いたりするのは見たくないですし、慎重かつ大胆にしっかり状況をモニタリングしていきながら、何か問題が起きても小さなうちに発見し、解決していくイテレーションを回すというのは変わらないと思っています。
こんにちは。BASE BANK 株式会社 Dev Division にて、 Software Developer をしている東口( @hgsgtk )です。 TL;DR AWS のマネージド脅威検出サービスである Amazon GuardDuty を有効化する場合、全リージョンに対して設定することが推奨される Amazon GuardDuty を全リージョンで有効化し、検出した内容を Slack に通知するまでの構成を説明・それを実現する具体的な Terraform コードを解説する 記事公開時点で terraform-provider-aws が AWS Chatbot に対応していないため、一部 Console 画面で作成する 当記事のサンプルコードは こちら にて公開している Amazon GuardDuty / AWS Chatbotとは Amazon GuardDuty(略:GuardDuty)は悪意のある操作・不正動作をモニタリングするツールです。AWS 環境を実運用する場合、セキュリティ上の脅威が含まれていないか継続して確認する事が重要でしょう。GuardDuty はセキュリティベストプラクティスとして導入できる 1 つのサービスです。 aws.amazon.com Amazon GuardDuty は、AWS のアカウント、ワークロード、および Amazon S3 に保存されたデータを保護するために、悪意のあるアクティビティや不正な動作を継続的にモニタリングする脅威検出サービスです。 GuardDuty は発見的統制のサービスとなります。発見的統制とは望ましくない事象が発生したことを発見するIT統制活動の一種です。セキュリティ保護に関して GuardDuty がどのような役割を担うかについては次の YouTube 動画にて詳しく説明されています。 www.youtube.com そして、AWS Chatbot を用いると Slack チャンネルへの通知を手間少なくかんたんに実現できます。 aws.amazon.com AWS Chatbot は、Slack チャンネルや Amazon Chime チャットルームで AWS のリソースを簡単にモニタリングおよび操作できるようにしてくれるインタラクティブエージェントです。 今回は、この2つのサービスを組み合わせて検出された脅威を Slack に通知するワークフローを紹介します。CloudFormation での構築例はいくつかあったのですが、Terraform で構築する例について解説している内容がインターネット上に少なかったので、Terraform で運用している開発現場の方にとって参考になる手順となれば幸いです。 当記事で出来ることと構成図 当記事では、GuardDuty からの検出結果を AWS Chatbot を用いて Slack 通知する構成を紹介しています。そのため、当記事の内容・サンプルコードを用いることで次のような通知を Slack で受けることが出来るようになります。 Slack通知のイメージ なお、画像内にある検出内容は GuardDuty の機能の 1 つである「Generate sample findings(結果のサンプルの生成)」によって生成したサンプル内容です。 そして、これを実現するための構成図が以下です。 本記事で実現する構成図 各リージョンごとに必要なリソースと、AWS Chatbot や IAM Role といった Global なものが存在します。 また、執筆当時 AWS Chatbot は terraform-provider-aws が対応していないため直接 Terraform 管理にすることはできません。 github.com そのため、当記事ではこの構成の作成のため次の手順を踏みます。 Terraform で全リージョン分の GuardDuty の有効化・通知ワークフローを構築する AWS Console 画面から AWS Chatbot を設定する なお、 @gainings さんにご教示いただきましたが、CloudFormation を Terraform 管理することで間接的に AWS Chatbot を Terraform 管理下に置くという方法があるそうです。Booth で販売されている『 クラウド破産を回避するAWS実践ガイド 』という書籍にその方法について詳しく説明があります。どのような方針でコード化していくかによりますが、AWS Chatbot を構築するひとつの選択肢になりますね。 Terraformで構築する 今回のサンプルコードは次のリポジトリに公開しています。 github.com 当リポジトリの構成は以下です。 . ├── hgsgtk-dev <- 構築する環境、moduleを利用して全リージョン分設定する └── modules ├── chatbot <- AWS Chatbot module └── guardduty <- GuardDuty module guardduty module GuardDuty とその通知ワークフローのための構成要素は以下です。 GuardDuty の有効化 EventBridge(CloudWatch Event)の設定 SNS Topic の暗号化 SNS Topic の作成 GuardDutyの有効化 GuardDuty の有効化は次の記述のみで完了です。 resource " aws_guardduty_detector " " guardduty " { enable = true } その他、S3 へのエクスポートなど様々な設定が可能です。当記事では通知ワークフローの紹介が趣旨なので詳しく紹介しませんが、気になる方は AWSの開発ガイド や Terraformのドキュメント を確認してください。 EventBridge(CloudWatch Event)の設定 EventBridge では GuardDuty からの検出をイベントとして受け取って後続の SNS Topic をターゲットにハンドリングします。 まず Event Rule を作成します。 resource " aws_cloudwatch_event_rule " " guardduty " { name = " capture-guardduty " description = " Capture Guard Duty finding events " event_pattern = << EOF { " source " : [ " aws.guardduty " ] , " detail-type " : [ " GuardDuty Finding " ] } EOF } event_pattern で設定した内容は、「イベントを検出した」ことを条件にしています。これらの設定以外にも検出内容の severity(緊急度)を条件に追加できます。 docs.aws.amazon.com { " source ": [ " aws.guardduty " ] , " detail-type ": [ " GuardDuty Finding " ] , " detail ": { " severity ": [ 4 , 4.0 , 4.1 , 4.2 , (省略) ] } } 筆者の現場では最小限の設定で始めて必要に応じて通知対象の severity(緊急度)を調整する方針としました。 次に、作成したルールで受け取ったイベントの送信ターゲットに次に作成する SNS Topic を設定します。 resource " aws_cloudwatch_event_target " " guardduty-sns " { rule = aws_cloudwatch_event_rule.guardduty.id target_id = " guardduty-sns " arn = aws_sns_topic.event_bridge_to_chatbot.arn } SNS Topicの暗号化 以前、当開発ブログで Terraform のセキュリティ静的解析 tfsec を紹介しました。 devblog.thebase.in tfsec の指摘項目には SNS Topic の暗号化 が含まれています。セキュリティ上のベタープラクティスのひとつとして SNS Topic は Amazon KMS(Key Management Store)によって暗号化します。 resource " aws_kms_key " " for_encrypt_sns_topic " { description = " guarddutyからのeventを受けるsns topic暗号化用 " enable_key_rotation = true policy = data.aws_iam_policy_document.policy_for_encrypt_sns_topic.json } resource " aws_kms_alias " " for_encrypt_sns_topic_alias " { name = " alias/guardduty/for_encrypt_sns_topic " target_key_id = aws_kms_key.for_encrypt_sns_topic.key_id } data " aws_iam_policy_document " " policy_for_encrypt_sns_topic " { version = " 2012-10-17 " # defaultでついてくるルートアカウントに対する権限設定 statement { sid = " Enable Root User Permissions " effect = " Allow " principals { type = " AWS " identifiers = [ " arn:aws:iam::${var.aws_account_id}:root " ] } actions = [ " kms:* " ] resources = [ " * ", ] } # events.amazonaws.com に対する権限が暗号化対象のサービス操作に必要 statement { sid = " AWSEvents " effect = " Allow " principals { type = " Service " identifiers = [ " events.amazonaws.com " ] } actions = [ " kms:GenerateDataKey ", " kms:Decrypt " ] resources = [ " * ", ] } } 注意点として、今回の構成で CloudWatch Event Rule のターゲットとして設定する場合、 events.amazonaws.com に対して復号化( Decrypt )・データキーの生成( GenerateDataKey )のアクションを許可する必要があります。 aws.amazon.com SNS Topicの作成 SNS Topic 暗号化用の KMS Key が作成できたので SNS Topic を作成します。作成した Key は aws_sns_topic.kms_master_key_id で設定します。 resource " aws_sns_topic " " event_bridge_to_chatbot " { name = " event-bridge-to-chatbot " kms_master_key_id = aws_kms_key.for_encrypt_sns_topic.key_id } resource " aws_sns_topic_policy " " event_bridge_to_chatbot_policy " { arn = aws_sns_topic.event_bridge_to_chatbot.arn policy = data.aws_iam_policy_document.sns_topic_policy.json } data " aws_iam_policy_document " " sns_topic_policy " { version = " 2012-10-17 " # defaultでついてくるルートアカウントに対する権限設定 statement { sid = " __default_statement_ID " effect = " Allow " principals { type = " AWS " identifiers = [ " * " ] } actions = [ " SNS:GetTopicAttributes ", " SNS:SetTopicAttributes ", " SNS:AddPermission ", " SNS:RemovePermission ", " SNS:DeleteTopic ", " SNS:Subscribe ", " SNS:ListSubscriptionsByTopic ", " SNS:Publish ", " SNS:Receive " ] resources = [ aws_sns_topic.event_bridge_to_chatbot.arn, ] condition { test = " StringEquals " variable = " AWS:SourceOwner " values = [ var.aws_account_id ] } } # events.amazonaws.com がイベント発行するために必要 statement { sid = " allow_AWSEvents_publish " effect = " Allow " principals { type = " Service " identifiers = [ " events.amazonaws.com " ] } actions = [ " sns:Publish ", ] resources = [ aws_sns_topic.event_bridge_to_chatbot.arn, ] } } ここでは、 events.amazonaws.com に対して sns:Publish アクションを許可する必要があります。 chatbot module AWS Chatbot 用の module を用意します。 AWS Chatbot 自体は前述したとおり Terraform でのコード管理対象外になりますが、AWS Chatbot が利用する IAM Role は既存の IAM を利用できるので Console で作成する前に Terraform で作成します。 AWS Chatbot では 4 パターンの許可設定がテンプレートで用意されています。 通知のアクセス許可 読み取り専用コマンドのアクセス許可 Lambda 呼び出しコマンドのアクセス許可 AWS サポートコマンドのアクセス許可 今回のユースケースでは、「通知のアクセス許可」を権限としてもつ IAM Role を作成することになります。 resource " aws_iam_role " " chatbot-notification-only " { name = " chatbot-notification-only " assume_role_policy = jsonencode ( { Version : " 2012-10-17 ", Statement : [ { Sid : "", Effect : " Allow ", Principal : { Service : " chatbot.amazonaws.com " } , Action : " sts:AssumeRole " } ] } ) description = " AWS Chatbot Execution Role for Only Notification " } resource " aws_iam_role_policy_attachment " " chatbot-notification-only-attach " { policy_arn = aws_iam_policy.chatbot - notification - only.arn role = aws_iam_role.chatbot - notification - only.name } resource " aws_iam_policy " " chatbot-notification-only " { name = " chatbot-notification-only " policy = jsonencode ( { Version = " 2012-10-17 " Statement : [ { Sid : "", Effect : " Allow ", Action : [ " cloudwatch:Describe* ", " cloudwatch:Get* ", " cloudwatch:List* " ] , Resource : " * " } ] } ) } 作成した IAM Role に紐づく IAM Policy は AWS 公式ドキュメント内の解説や実際に Console 上で試しに作成したものを参考にしています。 docs.aws.amazon.com moduleを利用して全リージョン分作成する module の用意が終わったので全リージョン作成していきます。 全リージョン作成するために、今回の作成方法では複数の Provider を用意する方針とします。Terraform では module を利用する際、明示的に Provider を渡せます。 www.terraform.io その仕様を用いてリージョンごとに module を用意します。 全リージョン分のProviderを作成 guardduty moduleを利用し、GuardDutyと通知ワークフローを作成 chatbot moduleを利用し、AWS Chatbot用のIAMロールを作成 全リージョン分のProviderを作成 全リージョン分のProviderを作成します。 # デフォルトのProvider provider " aws " { version = " ~> 3.18.0 " region = var.region } provider " aws " { region = " us-east-1 " alias = " us-east-1 " } provider " aws " { region = " us-east-2 " alias = " us-east-2 " } # (省略) 注意点としては、有効化していないリージョンがある場合は全リージョン設定する必要がない点です。以下のリージョンは有効化しない限り管理対象にする必要はない可能性があります。 af-south-1 アフリカ (ケープタウン) ap-east-1 アジアパシフィック (香港) eu-south-1 欧州 (ミラノ) me-south-1 中東 (バーレーン) docs.aws.amazon.com guardduty moduleを利用し、GuardDutyと通知ワークフローを作成 作成した Provider を利用して全リージョン分の module 利用コードを用意します。 module " guardduty-us-east-1 " { source = " ../modules/guardduty " aws_account_id = var.aws_account_id providers = { aws = aws.us - east - 1 } } module " guardduty-us-east-2 " { source = " ../modules/guardduty " aws_account_id = var.aws_account_id providers = { aws = aws.us - east - 2 } } # (省略) chatbot moduleを利用し、AWS Chatbot用のIAMロールを作成 AWS Chatbot はリージョン設定がない global なサービスなため 1 つだけ作成します。 module " chatbot " { source = " ../modules/chatbot " } Console 画面で残りの AWS Chatbotを作成する 最後 AWS Chatbot を Console 画面から作成していきます。 AWS Chatbot は当記事の公開時点では Amazon Chime と Slack の2つのクライアントをサポートしています。今回は Slack 通知が要件なので Slack を選択します。 Configure client を選択し Slack の Authorization を完了すると、対象の workspace が作成されます。 実際に通知するチャネルを当該画面の Configure Slack channel から設定していきます。 Logging では「エラーのみ」か「全てのイベント」が選択できますが、このロギング先の CloudWatch Logs は US East (N. Virginia) となります。その理由は、 公式ドキュメント にて次のように説明されているとおりです。 You can view your logs in the Amazon CloudWatch console. Note that you must specify US East (N. Virginia) for the Region. docs.aws.amazon.com AWS Chatbot 用に必要な IAM Role は事前に作成したものを利用できるため、Terraform で作成した IAM Role を指定します。 最後に AWS Chatbot で通知する SNS Topic を指定します。ここでは、Terraform で事前に全リージョン分作成した SNS Topic を設定してきます。 この設定をすると内部的には AWS Chatbot からの protocol: HTTPS の SNS Subscription を作成されます。 AWS Chatbotの通知設定をすることで作成されるSNS Subscription なお、筆者は Terraform で SNS Subscription を作成すること検証しましたが不可でした。理由は、terraform上の記法である sns_topic_subscriptionのprotocol の仕様です。 https -- delivery of JSON-encoded messages via HTTPS. Supported only for the end points that auto confirms the subscription . そして、AWS Chatbot の通知設定から SNS Topic を指定するフローでなければ「確認済み」にならないようです。そのため、SNS Topic に対する Subscription も Console 画面から作成する必要があります。Terraform コードで管理する場合は、 terraform-provider-aws の AWS Chatbot のサポート を待つ必要があります。 以上で設定は完了です。 ここまでやると冒頭で紹介したとおり当該 Slack チャンネルに通知が来るようになります。 動作確認方法 GuardDuty では「Generate sample findings(結果のサンプルの生成)」という機能があります。 この機能ではサンプルの検出結果を生成してくれます。この機能で生成された結果は CloudWatch Event にも発行されるため、本記事で紹介しているような通知ワークフローを組む際のデバックに有用です。 おわりに GuardDuty を有効化し Slack 通知を行なう構成を Terraform で作成する事例について情報が少なかったので紹介させていただきました。実際に作成する際に参考になれば幸いです。
こんにちは、BASE BANK 株式会社 Dev Division でエンジニアとしてインターンをしている前川です。 今回、Amazon Elasticsearch Service(以下、Amazon ES)による、ECS/Fargate で稼働するアプリケーションのログデータの解析基盤を新規で構築することになったので、構築するにあたって調査した内容や関連する内容、実際におこなった構築方法についていくつか紹介します。 今回の構築の簡単な全体構成図は次のようになります。 今回は、 ECS/Fargate のログを S3 にルーティングする Amazon ES にログをルーティングする VPC アクセスの Amazon ES を構築し、Kibana を外部からアクセスできるようにする の3つの手順にわけて、構築方法や関連する内容について紹介していきたいと思います。 なお、この記事で取り扱っている各ツール・サービスのバージョンは次のとおりです。 Terraform: v0.12.5 Terraform provider.aws v3.6.0 SAM CLI: version 1.7.0 AWS CLI: aws-cli/2.0.61 Python/3.9.0 Darwin/19.3.0 source/x86_64 Fargate platform version: 1.4.0 FireLens で ECS/Fargate のログを S3 にルーティングする FireLens について Kinesis Data Firehose を用いて ECS/Fargate のログを S3 へのルーティングする ECS/Fargate のログを S3 に直接ルーティングする方法について Amazon Elasticsearch Service にログをルーティングする Amazon Elasticsearch Service の構築 Amazon Elasticsearch Service の Terraform による構築 ECS のリバースプロキシサーバーを使用した Kibana によるデータ解析環境構築 ECS デプロイツールについて おわりに FireLens で ECS/Fargate のログを S3 にルーティングする FireLens について ECS のコンテナの標準出力/標準エラー出力に出力されたログを S3 にルーティングするために、FireLens をログドライバーとして使用しました。 FireLens を使用することで、ECS で出力されたログを、サイドカーとして実行された Fluentd や Fluent Bit のログルーターコンテナにルーティングすることができます。 別のアプリケーションでは、S3 へのログのルーティングは、CloudWatch Logs 経由で行っていましたが、FilreLens を用いた方法によって、CloudWatch Logs のコストを抑えることや、カスタム設定を用いた柔軟なログの取り扱いができるようになりました。 Kinesis Data Firehose を用いて ECS/Fargate のログを S3 へのルーティングする 今回の構築では Kinesis Data Firehose 経由で S3 にログをルーティングしました。 まずはじめに、Kinesis Data Firehose と S3 の構築をします。 Terraform での定義例は次のようになります。 resource "aws_kinesis_firehose_delivery_stream" "sample" { destination = "s3" name = "sample" s3_configuration { bucket_arn = aws_s3_bucket.sample.arn role_arn = aws_iam_role.sample-kinesis-firehose-iam-role.arn prefix = "sample/" } } resource "aws_iam_role" "sample-kinesis-firehose-iam-role" { name = "sample-kinesis-firehose" assume_role_policy = jsonencode( { Version = "2012-10-17", Statement = [ { Sid = "", Effect = "Allow", Principal = { Service = "firehose.amazonaws.com" }, Action = "sts:AssumeRole" } ] } ) } resource "aws_iam_policy" "sample-kinesis-firehose-iam-policy" { name = "sample-kinesis-firehose-iam-policy" policy = jsonencode( { Version = "2012-10-17" Statement = [ { Sid = "" Effect = "Allow" Action = [ "s3:AbortMultipartUpload", "s3:GetBucketLocation", "s3:GetObject", "s3:ListBucket", "s3:ListBucketMultiPartUploads", "s3:PutObject", ] Resource = [ aws_s3_bucket.sample.arn, "${aws_s3_bucket.sample.arn}/*", ] } ] } ) } resource "aws_iam_role_policy_attachment" "sample-kinesis-firehose-iam-role-attach" { role = aws_iam_role.sample-kinesis-firehose-iam-role.name policy_arn = aws_iam_policy.sample-kinesis-firehose-iam-policy.arn } resource "aws_s3_bucket" "sample" { bucket = "sample" acl = "private" } Kinesis Data Firehose に対しては、データを送信する S3 の設定と、その S3 を操作するために割り当てる IAM ロールを作成しています。 次に、ECS のタスク内へ FireLens コンテナを追加し、サイドカー構成とするために、ECS のタスク定義を修正する必要があります。 ログを出力するアプリケーションコンテナにログドライバーを次のように設定します。 "logConfiguration": { "logDriver": "awsfirelens", "options": { "Name": "firehose", "region": "ap-northeast-1", "delivery_stream": aws_kinesis_firehose_delivery_stream.sample.name } } delivery_stream のところには、先程構築した Kinesis Data Firehose の name で設定したものを使用します。 次に FireLens 設定を含むログルーターコンテナを追加します。 定義例は次のようになります。 { "name": "log-router", "image": "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:latest", "essential": true, "firelensConfiguration": { "type": "fluentbit" } } 最後に、タスクロールを修正し、FireLens コンテナが Kinesis Data Firehose へとストリームを送信できるようにします。 ポリシーの定義例は次の通りです。 { " Version ": " 2012-10-17 ", " Statement ": [ { " Effect ": " Allow ", " Action ": " firehose:PutRecordBatch ", " Resource ": " * " } ] } 以上の設定で、ECS のログを S3 に出力することができます。 ECS/Fargate のログを S3 に直接ルーティングする方法について また今回の構築では、S3 へのログの転送に Kinesis Data Firehose を使用しましたが、Fluent Bit が v1.6 より、コンテナログをルーティングする送信先として S3 をサポートし、Kinesis Data Firehose を経由せずに直接 S3 にログを転送することができるようになったようです。 aws.amazon.com ただし、デフォルトの設定である S3 のマルチパートアップロード API を使用し、この方法を使う場合は、Fluent Bit のインスタンスが、データのバッファリングのために永続的なディスクを必要とするので注意が必要です。 このディスクは、マルチパートアップロード API で送信するデータのチャンクをバッファリングするために使用され、もし Fluent Bit が不意に停止した場合に、同じディスクで再起動し、未完了のアップロード処理を完了するために必要だということです。 今回のような ECS/Fargate の環境で使用する場合は、Amazon EFS ファイルシステムを ECS タスクで使用することが推奨されているようでした。 また、永続的なディスクを使用しない場合に、S3 の PutObject API を使用し、データをバッファリングせずに頻繁に送信する方法によって、データの損失を抑える設定もあるようでした。 信頼性を重視する場合には、Kinesis Data Firehose を Fluent Bit と S3 間のバッファとして使用する方法が推奨されているようでしたので、S3 にログを転送する場合には、特別な理由がない限り Kinesis Data Firehose を経由する方法でおこなうのが良いのかなと思いました。 github.com Amazon Elasticsearch Service にログをルーティングする Kibana を用いたログの調査環境を構築するために、S3 にルーティングされたログを Amazon ES に転送する Lambda を作成しました。 Lambda は S3 の PUT をトリガーにして起動し、受け取った event の情報を用いて取得した S3 からの対象のログデータを加工し、Amazon ES に転送します。 BASE BANK チームでは、AWS SAM CLI を使用した Lambda の運用をおこなっており、今回の Lambda の環境構築にあたっても AWS SAM CLI を使用しました。 AWS SAM CLI を用いた Lambda の環境構築方法に関しては、同僚の永野が書いた下記エントリをご参照ください。 devblog.thebase.in AWS SAM CLI で Lambda を管理する場合は、AWS SAM のテンプレートファイルでトリガーとなるイベントの設定やロール、環境変数、VPC 周りの設定をおこないます。 BASE BANK チームでは、AWS リソースの管理を Terraform で行っているので、Lambda リソースの管理のみを SAM を用いて Cloud Formation でおこない、arn などを通してトリガーの対象となるリソースを参照し、テンプレートファイルを記述していました。 今回 Lambda のトリガーの対象となる ECS からのログが保存されている S3 についても、当初は Terraform で管理していたのですが、AWS SAM CLI で Lambda を構築し、トリガーの対象を S3 とする場合は、S3 を Lambda と同じテンプレートファイルで定義しなければならないという制約がありました。 github.com よって、Terraform で管理されていた S3 を、AWS SAM のテンプレートファイルで定義することで CloudFormation で管理するようにし、Terraform 側では、Data Resource として S3 を参照するように修正しました。 SAM テンプレートファイルのリソースセクションの作成例は次のようになります。 Resources : LogToEsFunction : Type : AWS::Serverless::Function Properties : CodeUri : log_to_es/ Handler : app.lambda_handler Runtime : python3.8 Events : BucketEvent : Type : S3 Properties : Bucket : !Ref LogBucket Events : s3:ObjectCreated:Put Filter : S3Key : Rules : - Name : prefix Value : log_prefix/ Role : !Ref ExecutionRole Environment : Variables : ES_DOMAIN_URL : !Ref EsDomainUrl VpcConfig : SecurityGroupIds : !Ref SecurityGroupIds SubnetIds : !Ref SubnetIds LogBucket : Type : AWS::S3::Bucket Properties : BucketName : !Ref S3Bucket S3 に保存された ECS のログを、Lambda を使用して Amazon ES に転送する方法を今回は使いましたが、ECS のログを Amazon ES にルーティングする方法として、FireLens を使用することで Fluent Bit が直接ログデータを Amazon ES にルーティングすることもできるようになったようです。 aws.amazon.com こちらの方法を使う場合は、Amazon ES へ送信するデータの加工についてや、ログデータが欠損した場合の考慮などを考える必要がありそうでしたが、手軽に Amazon ES にログデータをルーティングできるのは良さそうだと思いました。 Amazon Elasticsearch Service の構築 Amazon ES の VPC アクセスでの構築と、外部から Kibana にアクセスするための環境構築をおこないました。 Amazon ES の使い分けとして、 Lambda による、Elasticsearch API を用いたログデータの投入 Kibana によるログデータの解析のためのアクセス があります。 今回は、VPC アクセスによる構築により、Amazon ES に対するセキュリティの強化、Amazon ES と Lambda 間の安全な通信を実現することができましたが、一方で、Kibana に対しては適切なアクセス制限をした上で、データ解析のための外部からのアクセスをする必要があったので、ALB と ECS のリバースプロキシサーバーを使用した環境構築をおこないました。 Amazon Elasticsearch Service の Terraform による構築 今回 Amazon ES は、Terraform で構築しました。 Amazon ES を Terraform で構築する場合の、基本的な設定をした定義例は次のようになります。 resource "aws_elasticsearch_domain" "es" { domain_name = "sample" elasticsearch_version = "6.3" cluster_config { instance_type = "t2.small.elasticsearch" instance_count = 1 } vpc_options { subnet_ids = var.es_subnet_ids security_group_ids = var.es_security_group_ids } ebs_options { ebs_enabled = true volume_size = 10 } } この例では、Elastic Search の version や、インスタンスタイプの設定、サブネットやセキュリティグループの VPC 周りの設定をしています。 Amazon ES のセキュリティに関しては、 VPC アクセス設定によるネットワークに関するセキュリティレイヤー ドメインアクセスポリシーによる、リソースベースのセキュリティレイヤー Fine Grained Access Control による、ロールベースの細かいアクセスコントロールによるセキュリティレイヤー の 3 つの主要なセキュリティレイヤーがあり、このうち Terraform によるドメインアクセスポリシーの定義例は次のようになります。 resource "aws_elasticsearch_domain_policy" "es" { domain_name = aws_elasticsearch_domain.es.domain_name access_policies = jsonencode( { Version : "2012-10-17", Statement : [ { Effect : "Allow", Principal : { AWS : "*" }, Action : "es:*", Resource : "${aws_elasticsearch_domain.es.arn}/*" } ] } ) } ドメインアクセスポリシーの設定については、aws_elasticsearch_domain 内の access_policies でも設定することができますが、Terraform では、リソースの定義内で自らを参照することができないので、今回の場合は上記のように別リソースで定義しました。 BASE BANK チームでは、Terraform のセキュリティ静的解析ツールである tfsec を導入していて、今回の構築にあたって、tfsec の指摘により設定の検討をした項目がいくつかありました。 tfsec についてや、検討した項目に関しては、同僚の東口が書いた下記エントリをご参照ください。 devblog.thebase.in Amazon ES の構築にあたって注意すべき点として、既存のドメインには設定できず、新規で構築する際にしか設定できない項目や、インスタンスタイプや Elasticsearch のバージョンによっては設定できない項目が存在するというのがありました。 例えば、Audit Logs の有効化があります。 Amazon ES では、Audit Logs を使用することで、Elasticsearch へのすべてのリクエストのロギング、インデックスの変更、受信検索クエリの記録などのあらゆるユーザーアクティビティのログが記録できるようになりました。 aws.amazon.com しかし、この項目を設定するには、既存、または新規の Amazon ES で、Elasticsearch のバージョンが 6.7 以降であり、Fine Grained Access Control が有効になっている必要があります。 Fine Grained Access Control とは、ロールベースのアクセスコントロールによる、クラスターレベル、インデックスレベル、ドキュメントレベル、フィールドレベルの細かいアクセス許可や、Kibana マルチテナンシーの使用などができるようになるものです。 この設定を有効化するには、 保管時のデータの暗号化 と ノード間の暗号化 が有効になっており、ドメインへのすべてのトラフィックに HTTPS を要求する設定が有効になっていなければなりません。 このうち、保管時のデータの暗号化と、ノード間の暗号化、Elasticsearch のバージョンに関しては、既存のドメインに対して変更することができないので、変更したい場合はドメインを新規に作成する必要があります。 また、保管時のデータの暗号化に関しては、インスタンスタイプによっては設定できないので注意が必要です。 docs.aws.amazon.com ECS のリバースプロキシサーバーを使用した Kibana によるデータ解析環境構築 VPC アクセスによって構築された Amazon ES において、Kibana への外部からのアクセスをする方法はいくつかありますが、今回は ALB と ECS のリバースプロキシサーバーを使用した方法により環境構築しました。 ECS のリバースプロキシサーバーを経由せずに、ALB から直接アクセスすることもできますが、Amazon ES の Private IP の変更を定期的にメンテナンスする必要があり不便です。 ECS のリバースプロキシサーバーを経由することで、Amazon ES のホスト名を使って設定ができるので、定期的なメンテナンスが不要になり、より柔軟な設定をすることもできるかと思います。 今回の構築では、ECS のリバースプロキシサーバーは、nginx のイメージを使用し、設定ファイルを置き換えるだけの簡素な方法でおこないました。 ECS デプロイツールについて ECS のデプロイ方法についてはいくつか検討した上で、ECS CLI によるデプロイ環境を構築しました。 docs.aws.amazon.com ECS CLI は、ECS クラスターおよびタスクの作成、更新を、Docker Compose ファイルを利用しておこなえるツールです。 ECS CLI では、ALB やセキュリティグループなどのリソースの作成、管理ができませんが、今回は Terraform で ECS サービス、タスク以外の必要な AWS リソースが管理されていたので容易に導入することができました。 また、Docker Compose と Amazon ECS の統合により、Docker コマンドラインを使用し ECS へのアプリケーションのデプロイ ができるようになりました。 aws.amazon.com Docker Compose で構築された既存のアプリケーションの拡張や、Docker Compose を利用する ECS 開発者の開発体験の向上が図れるようになるようなので、機会があれば ECS CLI との違いについても含めて調査してみたいと思いました。 デプロイ方法を検討する中で、AWS Copilot CLI についても調査しました。 aws.github.io AWS Copilot CLI は、最低限 Dockerfile さえあれば、ECS クラスターやサービス、タスクに加えて、VPC やサブネット、ALB などのその他必要な AWS リソースを作成と、複数の AWS アカウントや複数の環境に対するデプロイのサポートまでおこなってくれる、かなり抽象度の高いツールです。 一方で、v0.3 から既存の VPC やサブネットの設定ができるようになりましたが、細かい設定についてはまだまだできない状況です。 aws.amazon.com 既存の ALB を設定するなど、その他の細かい設定ができない状況から今回は導入を見送りましたが、ECS でプロトタイプを動かしたり、技術検証をしたりすることが簡単にできる強力なツールだと思いますので、今後の進化に期待しつつ、使っていきたいと思いました。 おわりに Amazon ES を用いた、ECS/Fargate アプリケーションのログ解析基盤の構築例と、それに関連する内容について紹介させていただきました。 これから ECS/Fargate アプリケーションのログ解析基盤の環境構築をされる方々の助けになれば幸いです。 また今回の構築にあたっては、AWS のアップデートのサイクルの早さをとても感じました。 次々と新しい機能がリリースされるので、定期的にキャッチアップしたり、環境構築するたびに新しい技術の検証をしていかないとなと思いました。
BASE BANK 株式会社 Dev Division でSoftware Developer をしている清水( @budougumi0617 )です。 みなさんの開発現場でも社内ライブラリ・モジュールとして開発しているコード・GitHubリポジトリがあると思います。 そのようなリポジトリはパッケージ管理システムを経由して利用することがほとんどですが、そのためにはリリース作業を行う必要があるかと思います。 私のチームでは先日GitHubリポジトリのリリース作業をGitHub Actionsで自動化したので、本記事ではその内容を共有したいと思います。 TL;DR 今回はGitHub Actionsとrelease-it npmを使っています。 github.com www.npmjs.com 上記の技術を組み合わせることで次のような自動リリースのワークフローを構築しました。 (Pull Requestがマージされるなどで)mainブランチにコミットがプッシュされたらタグを打ち、GitHubリリースを作成する。 前回リリースとの差分で コミットメッセージのリリースノートを作成する 特定のファイルまたはディレクトリが更新されていたときだけ リリースする コミットメッセージに応じてセマンティックバージョンのパッチ/マイナー/メジャーアップデートを切り替える Actions上でしか使わないnpmパッケージなので、 リポジトリにpackage.jsonを置かない GitHub Actionsを使って自動化を行なうと、 コミット内容に応じた操作が簡単に実現 できます。 ただし、次の制約もありました。 プロテクトブランチを利用している場合はGitHub Actions上からコミットをプッシュすることはできない リリース用のPRをつくるといった迂回策が必要 そのため、今回の自動リリースでは「リポジトリ内の version 変数の値を更新してコミットしておく」のような操作は含んでいません。 なお、今すぐ試してみたい方は以下の2つのファイルを用意するだけで実現できます。 .release-it.json .github/workflows/release.yml .release-it.json の内容は次のとおりです。GitHubリポジトリのルートディレクトリに配置します。 https://github.com/budougumi0617/autorelease-by-release-it-on-actions/blob/main/.release-it.json { " requireUpstream ": false , " requireCleanWorkingDir ": false , " github ": { " release ": true } , " git ": { " commit ": false , " push ": false , " requireUpstream ": false , " requireCleanWorkingDir ": false } , " npm ": { " publish ": false , " ignoreVersion ": true } } .github/workflows/release.yml の内容は次のとおりです。 https://github.com/budougumi0617/autorelease-by-release-it-on-actions/blob/main/.github/workflows/release.yml name : auto release demo on : push : # mainブランチにコミットがpushされたときに限定 branches : - main # 上記条件に加えてgenディレクトリ配下が変更されたときのみという条件を追加 paths : - gen/** jobs : auto-release : runs-on : ubuntu-latest env : GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} RELEASE_IT_VERSION : 14.2.1 steps : - name : Check out codes uses : actions/checkout@v2 with : fetch-depth : 0 - name : Setup Node uses : actions/setup-node@v1 with : node-version : '12' - name : Set releaser settings run : | git config --global user.name release-machine git config --global user.email email@example.com - name : Major release id : major if : contains(toJSON(github.event.commits.*.message), 'bump up version major' ) run : npx release-it@${RELEASE_IT_VERSION} -- major --ci - name : Minor release id : minor # メジャーバージョンアップをしていないときマイナーバージョンアップを行なうか if : steps.major.conclusion == 'skipped' && contains(toJSON(github.event.commits.*.message), 'bump up version minor' ) run : npx release-it@${RELEASE_IT_VERSION} -- minor --ci - name : Patch release # コミットメッセージに特に指定がない場合はマイナーバージョンを更新する if : "!(steps.major.conclusion == 'success' || steps.minor.conclusion == 'success')" run : npx release-it@${RELEASE_IT_VERSION} -- patch --ci 今回のサンプルYAMLの場合はmain ブランチに gen ディレクトリ内への変更を含んだPRをマージすると自動でリリースが行なわれます。 また、 bump up version major といったメッセージが含まれていた場合はメジャーバージョンアップが行なわれます。 https://github.com/budougumi0617/autorelease-by-release-it-on-actions/releases サンプルリリースページ なお、本記事で利用している各ツールのバージョンは以下のとおりです。 ツール名 バージョン GitHub Actions v2 release-it npm 14.2.1 Node.js 12.X系 以下のURLは実際にGitHub Actionsで何回か自動リリースをしてみたサンプルリポジトリです。 https://github.com/budougumi0617/autorelease-by-release-it-on-actions リリース作業を自動化したい どんな言語を使っていても、業務で開発を行なっていると社内ライブラリを作成することがあると思います。 作成したライブラリはnpmやComposer、Go Modulesなどのパッケージ管理システムを経由して使うことになるのが大半だと思います。 そうなると一定の更新ごとにタグを設定し、バージョン管理する必要が出てきます。 とはいえ 「PRをマージしたら git tag コマンドを打って…」と各開発者が行なうのは億劫 です。 そのため、 mainブランチにPRがマージされたら(コミットがプッシュされたら)自動でタグ打ち、リリースする という自動化を試みました。 もちろんタグはリリースのたびにセマンティックバージョンがインクリメントされるようにします。 GitHub Actions上でrelease-it npmを実行してリリースをする https://www.npmjs.com/package/release-it release-it npmはよしなにセマンティックバージョンをインクリメントしながらリリースノートも作ってGitHubリリースを作成してくれるコマンドです。 たとえば、現時点のバージョンが 0.1.2 だったとき、次のように実行するとマイナーバージョンをインクリメントした 0.2.0 バージョンのリリースを作成してくれます。 $ npm run release -- minor --ci 次のリンクはrelease-it npmで作成されたリリースノートです。 https://github.com/budougumi0617/autorelease-by-release-it-on-actions/releases/tag/0.0.1 リリースノートのサンプル GitHub Actions上でNode.js環境を用意して実行するだけで終わりかと思いきや、いろいろ設定する必要があったので、ポイントを解説していきます。 GitHub Actions実行時にタグも取得しておく https://github.com/actions/checkout#checkout-v2 Set fetch-depth: 0 to fetch all history for all branches and tags. 今回構築する自動リリースのワークフローでは既存のタグからリリースするセマンティックバージョンを決定します。 そのため、GitHub Actions実行時に タグも一緒にチェックアウトしておく必要があります 。タグはGitHub Actionsを利用時にほぼ100% use されているであろう actions/checkout に対して fetch-depth: 0 オプションを渡すだけで取得可能です。 - name : Checkout codes uses : actions/checkout@v2 with : fetch-depth : 0 特定のパス配下が更新されたときのみリリースする 今回自動リリースしたいリポジトリはコードの自動生成を行なっていました。そのため、次のような事情がありました。 PRがマージされるたびのリリースは (どんどんバージョンが上がってしまうので)してほしくない 自動生成したコードが配置されている gen/ ディレクトリの内容が変更されたときだけ リリースしたい OpenAPIやgRPCなどを利用して同リポジトリ内でクライアントコードを自動生成したりしていると、同様のニーズが生まれると思います。 最初はCircleCIを利用して自動リリースを実現しようと思ったのですが、 パスを使ってCIを制御するのはGitHub Actionsのほうが簡単だったので 、GitHub Actionsで自動リリース作業を行なうことにしました。 GitHub Actionsのワークフローでは次のような制御をすることができます。 コミット内容を確認して特定ディレクトリに更新があったか確認する https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#onpushpull_requestpaths GitHub Actionsでは、 on.<push|pull_request>.paths を使うことで、特定ディレクトリに更新があったときだけにジョブの実行を制限できます 1 。 次のサンプルコードは以下の2つの条件を満たしたときのみ実行される設定です。 mainブランチにコミットがプッシュされた プッシュされたコミットの中に gen/ ディレクトリ内の更新が含まれていた on : push : branches : - main paths : - gen/** ワークフローの制御にコミットメッセージを利用する https://docs.github.com/en/free-pro-team@latest/actions/reference/context-and-expression-syntax-for-github-actions このデータ構造は おそらく公式ドキュメントに明示的に載っていない のですが、GitHub Actionsでブランチにpushされた 一連のコミットの情報をジョブ実行中に利用可能 です。 ワークフロー実行時の情報は github context として参照できるのですが、この中の github.event でpushされたコミットの情報を持っています 2 。 この情報をパースするとコミットの内容をワークフロー中に使うことができます。 次のコードは「コミットのメッセージに 'bump up version major' があったら true になる」式です。 contains(toJSON(github.event.commits.*.message), 'bump up version major' ) https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsif これと、 jobs.<job_id>.steps.if 、を使うことで、「コミットメッセージによって実行されるstep」をワークフローに用意することができます。 jobs : sample : runs-on : ubuntu-latest steps : - name : teststep if : contains(toJSON(github.event.commits.*.message), 'コミットメッセージを確認' ) run : echo 'executed!!' https://docs.github.com/en/free-pro-team@latest/actions/reference/context-and-expression-syntax-for-github-actions#steps-context また、contextの steps.<step id>.conclusion を用いることで前ステップの実行結果を利用して else if のような制御を行なうことも可能です。 jobs : ifelse-pattern : steps : - name : foo id : foo if : contains(toJSON(github.event.commits.*.message), 'foo' ) run : echo 'if step!' - name : bar id : bar # fooステップがスキップされた && コミットメッセージにbarを含む場合に実行する if : steps.foo.conclusion == 'skipped' && contains(toJSON(github.event.commits.*.message), 'bar' ) run : echo 'elseif step!' 次のリンクは実際にステップをいくつかスキップしているActionsの実行結果です。 https://github.com/budougumi0617/autorelease-by-release-it-on-actions/runs/1454817991 Actions実行画面 ここまではGitHub Actionsの設定方法でしたが、次はrelease-it npmをGitHub Actions上で使うコツです。 タグの設定とリリースはするが、コミットはしない release-it npmはGitHub Actions上で npx コマンドで実行しているので package.json は不要です。 が、release-it npm用の設定を用意する必要があります。 今回利用している設定は次のとおりです。 { " requireUpstream ": false , " requireCleanWorkingDir ": false , " github ": { " release ": true } , " git ": { " commit ": false , " push ": false , " requireUpstream ": false , " requireCleanWorkingDir ": false } , " npm ": { " publish ": false , " ignoreVersion ": true } } ざっくり説明すると、次のような設定です。 GitHubリリースを作成する gitのコミットは作成しない gitのpushはしない npmの公開はしない バージョンを決定するために package.json 内のバージョンを参照しない 鋭い方は「”pushしない”ってことはタグも公開されないんじゃないの?」と思うかもしれませんが、いいのか悪いのか、リリースを行なうときにタグはプッシュされるようです。 Actionsからプロテクトブランチにはコミットをpushできない https://github.community/t/how-to-push-to-protected-branches-in-a-github-action/16101/5 ここまで便利なGitHub Actionsでしたが、ひとつ制約があります。それは プロテクトブランチにコミットをプッシュすることができない 点です。抜け道がないか探していたのですがなさそうなので諦めました。 なので、先ほどのrelease-it npm用の設定ファイルは「タグの設定とリリースはするけどコミットはプッシュしない」という内容になります。 「自動リリースするときは package.json の中にある version も更新したい(コミットプッシュしたい)んだけど!」というようなニーズももちろんあると思います。 しかし、今回のユースケースではリリースタグでバージョンが管理されていればファイルとしてバージョンが参照できる必要はなかったので、こちらも妥協しました。 あとは開発するだけ! 以上の設定を行うと、特定条件のコミットを作るだけで自動でリリースされるようになります。 それぞれの設定は独立しているので、お好みでカスタマイズしていただけばと思います。 特定のディレクトリに限定する必要はないので on.<push|pull_request>.paths の設定は削除する マッチするコミットメッセージを変更する etc... name : auto release demo on : push : # mainブランチにコミットがpushされたときに限定 branches : - main # 上記条件に加えてgenディレクトリ配下が変更されたときのみという条件を追加 paths : - gen/** jobs : auto-release : runs-on : ubuntu-latest env : GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} RELEASE_IT_VERSION : 14.2.1 steps : - name : Check out codes uses : actions/checkout@v2 with : fetch-depth : 0 - name : Setup Node uses : actions/setup-node@v1 with : node-version : '12' - name : Set releaser settings run : | git config --global user.name release-machine git config --global user.email email@example.com - name : Major release id : major if : contains(toJSON(github.event.commits.*.message), 'bump up version major' ) run : npx release-it@${RELEASE_IT_VERSION} -- major --ci - name : Minor release id : minor # メジャーバージョンアップをしていないときマイナーバージョンアップを行なうか if : steps.major.conclusion == 'skipped' && contains(toJSON(github.event.commits.*.message), 'bump up version minor' ) run : npx release-it@${RELEASE_IT_VERSION} -- minor --ci - name : Patch release # コミットメッセージに特に指定がない場合はマイナーバージョンを更新する if : "!(steps.major.conclusion == 'success' || steps.minor.conclusion == 'success')" run : npx release-it@${RELEASE_IT_VERSION} -- patch --ci 終わりに 「PRマージしたぞー!」と思っても、そのあとにポチポチリリース作業をするのは億劫でした。 これで少しでも生産性があがるといいなと思っています。 なお、GitHub Actionsからプロテクトブランチへの直接コミットプッシュはできないのですが、renovateはPRを作成、Appで自動承認、自動マージという迂回をしてプロテクトブランチへのプッシュを実現しているようです。 GitHub Apps - renovate-approve · GitHub もっと突き詰めたくなったら同様の操作を実装してファイル更新も含めた自動リリースを実現したいなと思います。 最後に、BASE BANKでは新しくデザイナーとカスタマーサクセスの募集を開始したので、ぜひご応募お待ちしています。 www.wantedly.com www.wantedly.com 参考リンク https://github.com/budougumi0617/autorelease-by-release-it-on-actions https://www.npmjs.com/package/release-it https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions https://docs.github.com/en/free-pro-team@latest/actions/reference/context-and-expression-syntax-for-github-actions https://github.community/t/how-to-push-to-protected-branches-in-a-github-action/16101/5 「特定のディレクトリに更新があったときは無視する」という逆制御もできます。 ↩ contextをechoして無理やり確認しました。 ↩
BASE株式会社取締役 EVP of Developmentの藤川です。 世界中が新型コロナの影響で雇用の先行きが不透明な中、当社は引き続き成長を模索している状況で、マネージャ陣を中心に採用活動にも注力する毎日を送っています。 当社は正社員採用はもちろんのことですが、業務委託契約の方々にもお手伝いいただいておりますが、今回は業務委託契約にフォーカスした記事を書いてみたいと思います。 内製にこだわるチームを維持するための採用活動 私達はサービスを維持、成長させるために毎日ソースコードのメンテナンスをしています。我々はAWSやGCPなどのクラウドの環境とオープンソースのソフトウエアに恩恵を受けながら、独自のロジックは内製で開発しています。 他社の開発体制の事例として、スタートアップとして最初は内製で立ち上げたとしても、組織が大きくなりビジネスの成長が問われる中で、SIerさんに社内にがっつり入り込んでもらってSES契約などで開発力を補填したり、オフショアで海外に開発をお願いする事例をよく聞きます。 我々は創業以来、内製でソースコードを書いてきたチームですので、やはり内製での開発にはこだわりがあります。内製の重要性は、正社員がソースコードを書くか否かということではなく、ソースコードを書く行為とサービス運用が密接に結びついており、デプロイ後に何かあったら、ソースコードを書いた当人に即座にフィードバックして改善を求められる体制が維持されていることを示します。 これによりWebサービスを作る楽しさと技術者としての成長をリアルタイムに実現し、プロダクトクオリティに結びつけるということを大切にしています。スピーディな開発と改善を実現することが、持続的に成長するWebサービスの改善サイクルを支えています。開発メンバーにおいても、この開発サイクルを回し続けることが、複利的にエンジニアとしてのスキルを向上することに繋がります。 言い方を変えると「プロダクトを成長させることを前提とし、内製による開発体制を維持し続ける」ということもあります。プロダクトを連続的に成長させないのであれば、内製の開発体制にこだわる必要はなく、開発をアウトソースしフェーズごとに、僕らの預かり知らないソースコードを積み上げていって機能を付け足していくという選択もまたあるのでしょう。積極的にオフショアなどをやられている会社さんからすると、これはチームの覚悟の話と思われるのかもしれません。 現時点で思うこととして、もし受託契約やオフショアで開発し、納品されたソースコードによって深夜に不具合やパフォーマンス問題等が起きれば、いの一番に対応するのはSREチームやCTOである可能性が高く、誰が書いたのかの顔が見えないソースコードで不具合に対応し続けるのは酷な話だと僕は考えています。 サービスを運営し続けるのであれば、言い方は変ですが、不具合を出した仲間の顔が思い浮かぶ形、すなわち、自分たちチームの責任として納得行く形で不具合対応をしたりソースコードの改善をしていくことは仕事に対するモチベーション維持としても重要視しています。Webサービスにおいて人が携わる時間は、サーバを維持をするだけの活動ではなく、ショップオーナーさんの流通総額の実現を支え、サービスの改善のヒントを得る大切な活動なので、無駄な時間には使いたくないです。 つまり、内製組織を維持するための人件費や採用費に投資することは、それに携わる人の成長とプロダクトの成長を実現するためであり、結果として企業のポテンシャルを蓄積的に向上させていく手段ということになります。 ただし、これも成長圧力に対して、ちゃんと開発が追いついていればの話。内製にこだわり続けて、採用が滞ってしまって想定する成長を実現できなかったとしたら、もしかしたら内製にこだわる僕が経営責任を取る形で会社の様相が変わってしまったら、こういうこだわりを続けることはできなくなってしまうかもしれません。 そうならないためにもしっかり仲間を増やしていくことは開発チーム全員で携わっていく重要な仕事であると考えています。 内製にこだわるチームを維持するための業務委託 内製チームを実現するために雇用形態や国籍はこだわりません。同じチームで動いて改善サイクルを回せる状態を維持できていれば良いのだと思います。そのため携わるメンバーの契約形態は、現状は正社員としてジョインいただくか、業務委託契約でお願いしている状況です。 これまでBASEやPAYの開発においては、比較的少人数ではあるものの業務委託契約の方にもご活躍いただいてきました。我々が業務委託契約でお願いする方は「社員として登用できないハイスキルな方」と定義してきました。 つまり既に独立してフリーランスや自分の会社を持っていて独立心が高かったり、所属している会社の愛着があるからこそ、社員として来ていただくことが難しい方との契約形態として活用しています。 その代表例として、沖中さんのインタビューを動画で収録しました。もう2年半、BASEをお手伝いいただいていて、BASEの発展には欠かせない仲間です。 業務委託契約の方と社員とは多少の役割の差はあれど、労働環境や開発に必要な情報も含め、できる限り分け隔てなく、社員と同じように活躍を期待しています。技術ブログの執筆も普通にお願いしていたり社内勉強会で活躍いただくなど、情報のインもアウトも特に分け隔てなく業務としてこなしていただいております。 2021開発計画をお手伝いいただく業務委託契約の方を募集します! 現在、2021年の開発計画を整えていますが、とてもとても人が足りません。BASEというサービスをもっとよくして、ショップオーナーさんの成長を支えるための開発を一緒にやっていただける業務委託の人を増やしたいと思っています。もちろん、社員登用も積極的に行っております。 なおエンジニア採用向けの会社紹介資料を作ったので、よろしかったら是非見てみてください。 speakerdeck.com 役割別の募集要項はこちら! あらゆる役割で人材募集中! フロントエンドエンジニア open.talentio.com 開発プロジェクトにおけるフロントエンド実装と、BASEのフロントエンド実装におけるライブラリや実装技術の守り神を担います。 Webアプリケーションエンジニア open.talentio.com Webアプリケーションエンジニアは主体技術はバックエンド実装ですが、サービスを作る時にフロントエンドも書いています。 バックエンドエンジニア(アプリAPI開発) open.talentio.com BASEアプリのAPIの部分を開発するエンジニアになります。
フロントエンドチームの右京です。サービスの利用者向けには BASE U にて告知いたしましたが、2020 年 11 月 15 日をもって BASE は Internet Explorer 11 (以下 IE11) のサポートを終了しました。サポート終了と聞くと基本的にはネガティブな印象になりがちですが、ここでは主に開発者に向けて、サポートを終了することによって広がる新しい未来の話をしたいと思います。 ショップのデザインを進化させるであろう 2 つの技術 IE11 サポート終了後に新たに利用できる技術の中で、特に注目しているのは「Web Components」と「CSS カスタムプロパティ」です。 developer.mozilla.org developer.mozilla.org どちらも名前を聞くことが増えてきていて、すでにご存知の方も多いと思います。簡単に言えば前者は独自のタグを作って提供できる機能、後者は CSS で使える変数だと思ってもらえるとイメージしやすいのではないでしょうか。 HTML 編集とショップデザイン これらを活用できる背景には BASE が提供している「HTML編集」という App の存在があります。この機能はショップのデザインをかなり自由に編集できる機能で、 デザインマーケット のベースとなるものともなっており BASE の発展とは切っても切れない関係です。その自由度の高さから多くのオーナーズに利用していただいているのですが、一方で機能の動作保証や技術的サポートが難しいという問題がありました。 機能を提供し、保護するための Web Components HTML 編集が提供している、BASE のショップを構築するための条件や変数を BASE Template と呼びます。これについて詳しく知りたい場合は、以下のドキュメントを参照してください。 はじめに · Developers この中でも「商品の名前」を取得するための {ItemTitle} のようなタグで問題が起こることはほとんどありません。しかし例えば {AppsReviewTag} は、そのタグをレビュー機能を実現するための比較的大きめの HTML と JavaScript に置き換えて動作するタグとなっています。このタグはいわゆるコンポーネントのような扱いとなるのですが、これは現状多くのブラウザで動作をさせるため、必要な HTML、JavaScript、CSS に置き換えるような素朴な実装となっています。(例のコードはわかりやすくしたもので、実際に配信されるものではありません。) // HTML 編集で記述されたコード < div class = "review" > {AppsReviewTag} </ div > // 実際にショップとして配信されるコード < div class = "review" > < div class = "base-review-container" > < div ...> .... </ div > </ div > < script > .... </ script > </ div > これによって特に多く起こる問題が「意図しない破壊」です。スコープの存在しないものに BASE が開発したものを後付けするような形になるため、コードに予期せぬコンフリクトが発生するケースがあります。例えば、 BASE 側の改修によって HTML 編集で作成されたショップのデザインと CSS がコンフリクトしデザインが崩れてしまったり、他の箇所の JavaScript の実行エラーによって一部の機能が停止してしまったことがありました。結果としてオーナーズ、BASE 共に問い合わせやクレームに繋がってしまいます。 // 意図せず class が衝突してしまった! < div class = "review" > < style > .review { padding : 40px ; /* 二重に padding が適用されてしまい、デザイン崩れの原因に */ } </ style > < div class = "review" > < div ...> .... </ div > </ div > < script > document . querySelectorAll ( '.review' ) . ... // 本来想定していない要素も対象に </ script > </ div > これらの問題を解決する方法として Web Components、 特に Shadow DOM への期待が大きくなっています。Shadow DOM はカプセル化された DOM ツリーやスタイルを使用できるため、HTML 編集が書かれたコードと BASE が提供しているコードがお互いに干渉しづらくなります。これを利用することで、提供側利用側に関わらず安定した機能の開発、追加が実現できるようにしていきたいと思っています。 また、BASE のショップ以外への BASE の機能の追加のようなことも考えられます。将来的に以下のようなコードを埋め込むことで、どこからでも BASE の商品を購入できる機能が提供されるかもしれません。 < base -order itemId= "1234567890" ></ base -order > CSS カスタムプロパティによるデザインの変更 CSS カスタムプロパティについては 2 通りの活用方法を考えています。 1 つは先ほど紹介した Web Components での機能提供のデザイン面を補助するような形での利用です。Web Components に機能を隠蔽していくと安全性が高まる一方で、これまで比較的容易に行えていたスタイルの上書きによるデザイン調整が行いづらくなってしまいます。機能の安定性ももちろんですがショップやテーマにあったデザインを提供できる必要もあるため、この隙間を埋めるための方法として CSS カスタムプロパティ経由で多くのスタイルを変更可能にできないかと考えています。 2 つ目は実際に BASE のショップ運用している方でないと分かりづらいかもしれません。 デザインマーケット で販売されている多くの素敵なテーマは、さらに細部をカスタムできる「デザインオプション」を提供しています。 デザインオプション · Developers このデザインオプションを本当に細かく用意してくださるテーマデザイナー様も多く BASE としても非常に嬉しいのですが、どうしてもその数に圧倒されてしまうようなケースも存在します。そこで、こだわり度にあわせて段階的な設定を CSS カスタムプロパティをベースに導入できないかと考えています。例えばですが「デザインオプション」で設定できるものは大まかなカラーのみに絞り、細かなカラー調整については個々に CSS カスタムプロパティを設定できるような機能です。 他にもカラーセットのような機能も考えられます。現行のものでも一部のカラーについてはテーマ間で設定を引き継げるようになっているのですが、これをより汎用的な仕組みとすることでテイストを維持したまま様々なテーマを試せるなど。これらはもちろん BASE だけで実装できるものではなく、テーマデザイナーの協力も必須なものです。 まだまだできることはたくさん 今回は特に HTML 編集やショップデザインに大きく関わるものについて言及しましたが、もちろん他にも BASE がもっと使いやすくなるような改善も実施されていきます。 IE11 のために妥協していたユーザーインターフェイスの調整 管理画面のパフォーマンスの向上 そして、開発のスピードアップ IE11 のサポートを終了し、開発にブーストのかかった BASE の今後にご期待ください。そしてそんな開発を一緒にやってみたいメンバーも常に募集しております。 open.talentio.com
自己紹介 こんにちは。BASE株式会社のフロントエンドチームの谷口です。 本日は、BASEのフロントエンドで使用している日付ライブラリについてお話しします。 BASEの日付ライブラリについて BASEでは、frontendという領域が出来始めた当初、最もメジャーな日付ライブラリである moment.js を使用していました。 その後、 デザインコンポーネントの開発 など、frontend領域が成長していく中で より使い勝手の良い別の日付ライブラリが検討され、 date-fns が採用されました。 現時点で、ほぼ全てのコードがdate-fnsに移行済みです。 date-fnsについて date-fnsについて少し説明すると、公式にもありますが下記のような特徴が上げられます。 moment.jsや day.js がDateオブジェクトをラップして扱うのに対し、純粋な関数を必要な分だけ読み込んで使用することが出来ます。 こちらの ディレクトリ を見ると、180以上の機能が用意されており、全て関数をexportしている事がわかります。 date-fnsは値を不変に保つことが可能です。 これはmoment.jsと比較すると下記のような違いが見られます。 //moment.jsの場合、addを呼び出す度に元の値が変更され、同じ結果が得られません。 //コンソールに警告こそ表示されますが、この動作が予期せぬバグを生み出す可能性があります。 const today = new Date (); const momentToday = moment(today); momentToday.add( "day" , 3); console.log(momentToday.toDate()); // Sat Nov 07 2020 11:17:47 GMT+0900 (日本標準時) momentToday.add( "day" , 3); console.log(momentToday.toDate()); // Tue Nov 10 2020 11:17:47 GMT+0900 (日本標準時) //date-fnsの場合、元の値を変更することはありません。 const threeDaysTime = addDays(today, 3); console.log(threeDaysTime); // Sat Nov 07 2020 11:17:47 GMT+0900 (日本標準時) const sixDaysTime = addDays(threeDaysTime, 3); console.log(sixDaysTime); // Tue Nov 10 2020 11:17:47 GMT+0900 (日本標準時) また他のライブラリと依存しておらず、関数を呼び出す度に新しいDateオブジェクトが返ります。 関数自体にも副作用が無いため、テストツールや他のライブラリに組み込むことも容易です。 bundleサイズも使用する言語やwebpackの設定により異なりますが、比較的軽量です。 出典: https://bundlephobia.com/ TreeShakingをサポートしています。 TypeScriptとFlowどちらにも対応しています。 ドキュメント も充実しており、サンプルコードも豊富なので、使い方に困るということも少ないでしょう。 また近頃、moment.jsがメンテナンスモードになるという主旨の 記事 が公開されました。 その移行先候補の1つとしてdate-fnsも記載されており知名度も高いライブラリです。 出典: https://www.npmtrends.com/ date-fnsのバージョンアップ 上記の経緯で採用されたdate-fnsですが、BASEでは、実装当初のv1.30.1 からアップデートされていなかったため、今年の3月にv2.0.0にメジャーアップデートしました。 v2.0.0の開発にはおよそ 2年の歳月 がかけられており、 中には 破壊的変更 も含まれていたため、いくつか修正する必要がありました。 v1.30.1 -> v2.0.0の主な破壊的変更点 下記が関数名の変更などを除いた主な変更箇所です。 (サンプルコードは公式より抜粋しています) 主要な関数は文字列を許可していたが、日付のみ指定になった。 文字列を使用したい場合はparseISOで変換して使用する必要があります。 // Before v2.0.0 addDays( '2016-01-01' , 1) // v2.0.0 onward addDays(parseISO( '2016-01-01' ), 1) Unicodeのフォーマットが変わりました。 以前まではmoment.jsの仕様を模倣していた 経緯 がありましたが、その他の多くの言語に習って、より普遍的な物に変更されました。 後方互換用のオプションが用意されていますが、今後このオプションが削除される可能性も高いので、可能な限り変更した方が良いでしょう。 // Before v2.0.0 format( new Date (), 'YYYY-MM-DD' ) //=> 2018-10-283 // v2.0.0 onward format( new Date (), 'yyyy-MM-dd' ) //=> 2018-10-10 format( Date .now(), 'YY-MM-dd' , { awareOfUnicodeTokens: true } ) //=> '86-04-04' format関数は明示的にフォーマット形式を指定する必要があります。 // Before v2.0.0 format( new Date (2016, 0, 1)) // v2.0.0 onward format( new Date (2016, 0, 1), "yyyy-MM-dd'T'HH:mm:ss.SSSxxx" ) 日数の変換はparse関数に全て委任していましたが、parseは引数を必須とし、それぞれの用途に合わせた関数が用意されました。 // Before v2.0.0 parse( '2016-01-01' ) parse(1547005581366) parse( new Date ()) // Clone the date // v2.0.0 onward parse( '2016-01-01' , 'yyyy-MM-dd' , new Date ()) parseISO( '2016-01-01' ) toDate(1547005581366) toDate( new Date ()) // Clone the date 最後に 日付という性質上、変更箇所は多岐に渡りましたが、破壊的変更があったにも関わらず アップデートの難度はそこまで難しいものではありませんでした。 これは、date-fnsがDateを引数として渡すだけ、というシンプルな使い方であるため、修正すべきコードも比較的読みやすかったおかげだと感じています。 moment.jsがメンテナンスモードになる中、移行候補の1つとしてdate-fnsを検討してみていかがでしょうか。
こんにちは。BASE BANK 株式会社 Dev Division にて、 Software Developer をしている東口( @hgsgtk )です。 BASE BANK Dev での開発では、クラウドインフラの構成管理に、 Terraform を利用しています。 世の情報をたくさんキュレーションしている CTO の @dmnlk さんに、手軽に CI に組み込めそうなセキュリティチェックツールがあることを教えてもらったので、導入してみました。 CTO氏のキュレーションメディアで紹介された tfsec を早速試して良さそうだった https://t.co/bl67dlW2Ub https://t.co/vAkTOVagec — Kazuki Higashiguchi (@hgsgtk) August 21, 2020 このブログの公開日は 2020/10/30 ですので、導入してから約 2 ヶ月強経ちました。導入・運用をつづけた経験から、いろいろ tfsec 自体の変化や、運用したことで学べた AWS セキュリティプラクティスをご紹介します。 目次 目次 TL;DR tfsec とは 始め方 クラウドの認証キー・権限付与が必要ないため導入しやすい GitHub Actions で始める 既存の指摘は tfsec:ignore でいったん Fixme issue にする tfsec の指摘から AWS におけるセキュリティプラクティスを学ぶ Amazon CloudFront の推奨 SSL/TLS Policy Amazon ECR のイメージスキャン機能の有効化 Amazon S3 のバケットロギング AWS Key Management Service のキーローテーションの有効化 Amazon Elasticsearch Service のデータ保護 ノード間通信の暗号化 保管時の暗号化 Redis 用 Amazon ElastiCache のデータ保護 In-Transit Encryption (TLS) At-Rest Encryption その他 aws_security_group_rule' should include a description for auditing purposes aws_cloudfront_distribution' does not have a WAF in front of it おわりに TL;DR Terraform のセキュリティ静的解析 tfsec はクラウドの認証キー・権限付与が必要ないためすぐに試すことが出来る tfsec 自体の開発も頻繁にコミットされており日々進化を遂げている tfsec を使い続けることで学んだ AWS セキュリティプラクティスをいくつか紹介する tfsec とは tfsec は、Terraform ファイルを静的解析しセキュリティイシューとなるような点を指摘してくれるツールです。 A static analysis security scanner for your Terraform code. Discover problems with your infrastructure before hackers do. www.tfsec.dev AWS・Azure・GCP といったクラウドベンダーをサポートしています。また、秘匿情報の混入がないかといった特定ベンダーに関わらない一般的なセキュリティチェック事項も備えています。 開発はメンテナー・コアコミッターの方々によって頻繁に行われています。チェック項目の新規追加はもちろんのこと、先ほど紹介した https://www.tfsec.dev というウェブサイトを公開したり、tfsec 自体のパフォーマンスチューニングや カスタムチェック 作成のサポートなど、日々新機能が追加されています。また、筆者自身いくつか PR を提出していますがそれに対してもすぐに反応いただきメンテナー・コアコミッターの熱量の高さを感じます。 始め方 クラウドの認証キー・権限付与が必要ないため導入しやすい tfsec が始めやすい特徴として、当該クラウドの認証キー・権限などが不要な点です。たとえば、 terraform plan をするようなツールだと、AWS の場合 IAM を発行する必要があります。しかし、本ツールは *.tf ファイルの内容の静的解析を行うだけなので、これらがいりません。 AWS でのインフラ構成管理を Terraform でやる場合、 Terraform に対してそれなりに強い権限を付与するため、その権限管理をどこでやるかは論点になりがちです。それを考えなくていいのは、とても始めやすい利点だなと感じます。 GitHub Actions で始める 私の所属するチームでは、 GitHub Actions で導入をはじめました。 公式の GitHub では、 triat/terraform-security-scan が紹介されています。しかし今回は、GitHub の Pull request(PR) へのコメントがすぐに実現できる点で、 reviewdog が公開している reviewdog/action-tfsec を使用しました。 github.com 本アクションを使った設定方法は例えば次のような yml ファイルです。 name : tfsec on : [ pull_request ] jobs : tfsec : name : tfsec runs - on : ubuntu - latest steps : - name : Checkout uses : actions /checkout @v2 - name : Terraform security scan uses : reviewdog /action - tfsec@master with : github_token : $ {{ secrets.github_token }} reporter : github - pr - review # Change reporter fail_on_error : " true " # Fail action if errors are found filter_mode : " nofilter " # Check all files, not just the diff flags : "" # Optional これにより、次のように指摘内容が GitHub の PR のコメントで見れるようになります。 ReviewDogによるPRへのコメント ちなみに、最近 GitHub に Unchanged files with check annotations という Beta 版の機能がついて、PR での変更差分外のファイルに対するコメントも反映されるようになりました。 "Unchanged files with check annotations" によるPR差分外のコメント tfsec は、Release によって新たなチェック項目が増えたりします。チェック項目が増えた際に、それに引っかかる内容が Terraform の記述に含まれていないかを継続的にチェックするにあたって、便利な機能だなと個人的に感じています。 github.com 既存の指摘は tfsec:ignore でいったん Fixme issue にする GitHub Actions に入れると、多かれ少なかれ、 Error / Warning レベルの内容が指摘されるかもしれません。導入にあたりすべてを直してからというのも新規に生まれるセキュリティの穴を塞げなくてもったいないので、弊社の例では、最初に tfsec:ignore というマーキングで既存の指摘を無視する設定をしていきました。 resource " aws_ecr_repository " " hoge " { # tfsec : ignore : AWS023 # Fixme above it Fixme で残しつつ、随時解消していく方法をとっていきました。 tfsec の指摘から AWS におけるセキュリティプラクティスを学ぶ 実際に tfsec を使い続けてさまざまな指摘によって、 AWS におけるセキュリティプラクティスを学びました。それらの学びをおすそ分けします。具体的には次の内容を紹介します。 Amazon CloudFront の推奨 SSL/TLS Policy Amazon ECR のイメージスキャン機能の有効化 Amazon S3 のロギングバケット AWS Key Management Service のキーローテーションの有効化 Amazon Elasticsearch Service のデータ保護 Redis 用 Amazon ElastiCache のデータ保護 その他 ひとつひとつ見てみましょう。 Amazon CloudFront の推奨 SSL/TLS Policy tfsec では aws_cloudfront_distribution' defines outdated SSL/TLS policies (not using TLSv1.2_2018) という指摘項目があります。これは、以下の issue で追加された CloudFront のチェック観点です。 github.com この issue 当時のベストプラクティスでは、 TLSv1.2_2018 が推奨されておりました。しかし現在は、 AWS Console に表示されていますが、 TLSv1.2_2019 が推奨されるセキュリティポリシーとなっています。 「そもそも TLSv1.2_2019 はどう違うの」という疑問を持たれた方(かつての自分ですね)は、クラスメソッドさんの次のブログの解説がとてもわかりやすいのでおすすめです。 dev.classmethod.jp resource " aws_cloudfront_distribution " " example.com " { # (省略) viewer_certificate { acm_certificate_arn = " certificateのarn " cloudfront_default_certificate = false minimum_protocol_version = " TLSv1.2_2019 " ssl_support_method = " sni-only " } ) もともと、 TLSv1.2_2018 ではない場合 Error と指摘されていましたが、PR を提出しリリースいただきました。もし TLSv1.2_2019 にあげても Error になる場合は、tfsec のバージョンを 0.27.0 >= に上げてみてください。 github.com Amazon ECR のイメージスキャン機能の有効化 こちらは、同僚の前川さんに対応いただきました。 aws_ecr_repository' defines a disabled ECR image scan という指摘を受け対応したものです。ECR image scan は、2019 年 10 月 28 日に公開された ECR image に対するイメージスキャンの機能です。 aws.amazon.com 他のツールでは、 trivy や dockle などがあげられます。 ECR Image scan を有効にするには、 aws_ecr_repository.image_scanning_configuration を設定します。 image_scanning_configuration は、Terraform 2 系の場合は 2.34 から、 3 系の場合は 3.10 から使用可能です。 resource " aws_ecr_repository " " hoge " { # (省略) image_scanning_configuration { scan_on_push = true } } Amazon S3 のバケットロギング aws_s3_bucket does not have logging enabled と指摘された場合、S3 のバケットロギングの検討が必要です。 S3 では AWS開発者ガイド:Amazon S3 サーバーアクセスのログ記録 で解説がある通り、サーバーアクセスに対するログ記録機能が提供されています。このロギングを有効にしておくとセキュリティやアクセス監査の観点で役に立ちそうです。 resource "aws_s3_bucket" "public-usecase-bucket" { # (省略) logging { target_bucket = aws_s3_bucket.access-logs.id # logging bucketを指定 target_prefix = "logs/" } } resource "aws_s3_bucket" "access-logs" { # (省略) acl = "log-delivery-write" } S3 のアクセスログバケットを作成する際には、acl を log-delivery-write にします。 discuss.hashicorp.com log-delivery-write は、AWS があらかじめ定義した既定 ACL と呼ばれるものの 1 つです(既定 ACL については、 AWS開発者ガイド:アクセスコントロールリスト (ACL) の概要 をご参照ください)。 LogDelivery グループはバケットに対する WRITE および READ_ACP アクセス許可を取得します。 ロギングバケット自体の ACL を考える際にはこの既定 ACL を使用するのが便利です。 以前は、ロギングバケット自体にも aws_s3_bucket does not have logging enabled という指摘が入り tfsec:ignore マーキングで回避する必要がありました。しかし、tfsec に対して PR を提出し解消いたしました。S3 バケットのロギングバケットの場合、当該指摘をしないように修正されています。 github.com AWS Key Management Service のキーローテーションの有効化 これは、同僚の @budougumi0617 さんが新規 KMS Key を構築時に指摘され、対応いただいたものです。AWS Key Management Service(以降、AWS KMS と略します)には、 カスタマーマスターキー ローテーション という機能があります。 AWS KMS は自動的に有効にした日から CMK(Customer Master Key) を 365 日後にローテーションし、その後は 365 日ごとに実行します。 docs.aws.amazon.com resource "aws_kms_key" "sample_key" { description = "機密情報の暗号化に利用" enable_key_rotation = true # 自動キーローテーションを有効にする } 作業としては、 enable_key_rotation = true の設定だけです。その設定をしてから 365 日後に自動でローテーションされます。 Amazon Elasticsearch Service のデータ保護 こちらは、同僚の前川さんが新規 Amazon Elasticsearch Service (以降、Amazon ES と略します)構築時に指摘され対応いただいたものです。Amazon ES は、データ保護におけるセキュリティ上の機能として「ノード間通信の暗号化」・「保管時の暗号化」という2つのオプションを備えています。 ノード間通信の暗号化 Amazon ES のドメインは、デフォルトでは VPC 内のノード間トラフィックは暗号化されませんが、ノード間通信の暗号化を有効にすることで VPC 内のすべての通信で TLS 1.2 暗号化が有効になります。 docs.aws.amazon.com この設定をしていないと、 Resource 'aws_elasticsearch_domain.es' defines an Elasticsearch domain with plaintext traffic (missing node_to_node_encryption block). という指摘を受けます。 具体的には次のようなコードによってノード間通信の暗号化の設定が可能です。 resource "aws_elasticsearch_domain" "es" { elasticsearch_version = "6.3" # (省略) node_to_node_encryption { enabled = true # true にすることで有効化する } } しかし、 AWS開発者ガイド: Amazon Elasticsearch Service のノード間の暗号化 にある通り、これは既存ドメインに対しての設定のつけ外しはできないため、既存の Amazon ES ドメインに対しては別のドメインを作成する必要があります。 また、elasticsearch_version も 6.0 以降が求められます。既存リソースに対して作り直しのコストを書けるのはしんどいという判断したら、tfsec:ignore マーキングするとよいでしょう。 保管時の暗号化 Amazon ES ドメインでは、AWS KMS を使用してインデックスやログ・アプリケーションディレクトリのデータなどを保管時に暗号化する機能が提供されています。 docs.aws.amazon.com Terraform では encrypt_at_rest という記述で指定します。 resource "aws_elasticsearch_domain" "my_elasticsearch_domain" { domain_name = "domain-foo" encrypt_at_rest { enabled = true # 保管時のデータ暗号化を有効化 } } しかし、こちらも既存ドメインでは有効にできません。また、特定インスタンスタイプの場合はサポートしていないこともあります。 docs.aws.amazon.com R3 インスタンスタイプは、保管時のデータの暗号化またはきめ細かなアクセスコントロールをサポートしていません。 サポート対象外の場合 tfsec:ignore マーキングすることになりますが、このような暗号化の検討を指摘によって考えられるのは tfsec の良い点ですね。 Redis 用 Amazon ElastiCache のデータ保護 こちらも Amazon ES における「ノード間通信の暗号化」・「保管時の暗号化」と類似したセキュリティプラクティスが存在します。前者を「In-Transit Encryption (TLS)」、後者を「At-Rest Encryption」にて設定します。 In-Transit Encryption (TLS) tfsec からは Resource 'aws_elasticache_replication_group' defines an unencrypted Elasticache Replication Group (missing transit_encryption_enabled attribute というメッセージで指摘されます。 Amazon ElastiCache には、ネットワーク転送時の暗号化オプションが用意されています。 docs.aws.amazon.com 具体的には、 transit_encryption_enabled というオプションを true にしておくことで設定可能です。 resource "aws_elasticache_replication_group" "my-resource" { # (省略) transit_encryption_enabled = true } こちらの設定は、Redis の対応バージョン(3.2.6, 4.0.10 or later)や対応可能なノードタイプが限られるといった 制約条件 を事前に確認する必要があります。 また、暗号化の実装によるバックアップオペレーション・ノード同期オペレーションの実行パフォーマンスが低下する場合があることを 開発者ガイド にて示しています。 なお、既存のレプリケーショングループの場合は新しいレプリケーショングループを作成する必要があります。こちらの方法についても、 開発者ガイド にて具体的な手順が説明されています。実際に読者の中で気がついて検討をしたい方がいらっしゃれば、是非ご覧になってください。 At-Rest Encryption tfsec からは Resource 'aws_elasticache_replication_group.bb-prd-auth' defines an unencrypted Elasticache Replication Group (missing at_rest_encryption_enabled attribute) というメッセージで指摘されます。 Amazon ElastiCache には、データの暗号化オプションが用意されています。 docs.aws.amazon.com 具体的には、 at_rest_encryption_enabled というオプションを true にしておくことで設定可能です。 resource "aws_elasticache_replication_group" "my-resource" { # (省略) at_rest_encryption_enabled = true } こちらも、「In-Transit Encryption (TLS)」と同様の制約事項・考慮事項があります。 セキュリティ観点とパフォーマンス観点のバランシングは自身のアプリケーション要件に沿って検討が必要ですが、tfsec によってセキュリティ観点での指摘を純粋に受けられるのは設計上の利点でしょう。 その他 その他、少し細かいですが管理上大事な内容を紹介します。 aws_security_group_rule' should include a description for auditing purposes Security group の INBOUND / OUTBOUND ルールには、説明(description)を設定できますが、監査上は設定することが推奨されます。 resource "aws_security_group_rule" "huga" { # (省略) description = "BASE Office" } aws_cloudfront_distribution' does not have a WAF in front of it tfsec の v0.30.0 にて追加されたチェック項目です。 docs.aws.amazon.com WARNING レベルの指摘なので、要件上神経質になる必要がないユースケースでの CloudFront の利用であれば tfsec:ignore マーキングで対応可能です。 おわりに tfsec の導入と、その指摘項目から AWS のセキュリティプラクティスを紹介しました。 今回は紙面の都合上紹介しておりませんが、ちょうど 2020 年 10 月に一気に開発が進んでいるのが カスタムチェック です。JSON 形式でルールを指定することで自分たちにとってのルールを tfsec のチェック内に導入できます。こちらもまた別の機会に紹介いたします。 かんたんに使用開始できるので、ちょっとセキュリティに関心・不安があるけど何も出来ていないという方がいらっしゃれば、試してみてはいかがでしょうか。
BASE の Service Dev にて主に決済周りのバックエンド開発をしている翠川( @midori44 )です。 昨年は PayPal決済の導入 のプロジェクトでメインエンジニアとして携わらせていただきました。 今回は決済周りの開発をしていく中で、社内の開発環境を整えた話をします。 ローカル開発環境での課題 BASEでは現在、 BASEかんたん決済 として6つの決済方法を提供しています。 日々の機能開発をしていく中で、すべての決済方法において各機能が正しく動作するかを確認するために、ステージング環境や社内検証用のQA環境だけでなく開発者のローカル環境でも決済をテストできるようになっています。 新機能のリリース時にはもちろん本番環境で実際の決済を通して動作確認するわけですが、開発中のテストの度に本番相当の決済をするわけにはいかないので、各決済代行会社様のほうで用意していただいている検証用サーバーやsandbox環境に接続してテストすることになります。 基本的にはそれで問題ないのですが、キャリア決済に関してだけはちょっと他の決済とはフローが異なることから、ローカルでのテスト決済ができない状態になっていました。 キャリア決済のフロー キャリア決済では、購入者は一度カートを離れて決済代行サービスのほうで購入手続きを完了します。そのため、決済が確定したかどうかはwebhookで受け取る必要があるのですが、外部にある決済代行サービスは開発者のローカル環境にあるwebhookサーバーへアクセスできません。 もちろん、外部アクセスできるhttpサーバーを立ててリモートフォワードなどをすれば可能ですが、開発用の個人マシンでそこまでするのはリスクが高く現実的ではありません。 ということで、キャリア決済の動作確認をしたいときは共用の検証環境で確認するという方法で長らく運用されていましたが、やはり不便に感じる声が多かったのでDocker上で動く決済代行サービスのモックサーバーを作って解決しました。 外部サービスのモック化 弊社のローカル開発環境はDockerで構築されています。Docker Composeの設定ファイルはGitHubで管理しており、カートが動いているwebサーバー、ショッピングアプリ用のAPIサーバー、データベース用のDBサーバー……等々、各種サーバーをコマンド1つで立ち上げることができます。 今回は、その中の1つのコンテナとしてキャリア決済用のモックサーバーを立ち上げられるように準備します。 適当なwebサーバーを用意して、実際の決済代行サービスと同じレスポンスを返すモックサーバーを作ります。今回は購入中のリダイレクト先としてブラウザからアクセスするため、正常系だけでなく異常系もテストできるように、画面上の操作によって意図的にエラーを起こせるようにしておきました。 モックサーバーのサンプル画面 純粋なAPIサーバーの場合は、異常系のテストをしたいときは『特定のリクエストを渡された場合にはエラーを返す』という実装が一般的かと思います。 たとえば PayPal のsandbox環境では、リクエストヘッダーに PayPal-Mock-Response を渡すことで任意のエラーを受け取ることができるようになっています。 https://developer.paypal.com/docs/api-basics/sandbox/request-headers/ Docker Composeに定義を追加して、用意したモックサーバーをコンテナとして立ち上げられるようにします。今回のモックサーバー構築で注意したいのは、購入者に確認画面を表示させるためのブラウザ経由でアクセスと、裏でwebhookサーバーへ通知を飛ばすためのコンテナ間通信の2つの通信が発生することです。 弊社のDocker環境では本番と同じように任意のホスト名かつSSLでアクセスできるようDNSやリバースプロキシを通しているため、 docker-compose.yml で extra_hosts を設定してモックサーバーからwebhookサーバーへのコンテナ間通信のときにもリバースプロキシを通すようにする必要がありました。 最後に 外部サービスのサーバーを丸ごとモック化することで、一通りの動作確認をDockerネットワーク内で完結させることができました。 今回はローカルでの動作確認が最後までできないことからのモック化でしたが、外部サービスに対する動作確認(こちらからのリクエストに対して想定したレスポンスが返るかどうか)と、自サービス内の動作確認(正常レスポンスもしくはエラーを受け取ったとき正しく処理されるか)を分けて考えるためにも、適切なモック化は役に立つかと思います。 BASEでは開発環境の整備や中長期的な技術基盤の改善を担っていくエンジニア、および120万ショップの決済を支えていくエンジニアを募集しています。 binc.jp
この記事について コロナウイルスによる社会不安の影響でこの半年でリモートワークの機運が特に都心部を中心に大きく高まってきました。 つい先日ヤフー株式会社が全社テレワークへの移行を正式発表したことは記憶に新しいです。 BASEでもコロナウイルスの感染拡大に伴っていち早くリモートワークの制度を構築し(2020年2月には全社的にリモートワークを開始)、 その制度は現在でもまだ運用されています。 また、世の中の動向やニーズの高まりもあり、リモートワークへの関心の高まりは採用の場面でも感じられるようになってきています。 我々も各種求職者の紹介サービスを利用していますが、そういったサービスではリモートワーク可・不可という選択肢しか選べない場合が多く、 結局面接に来ていただいた方に、BASEでどのようなリモートワーク制度が取られているか、今後どうなっていく予定か、 そういった内容を毎回口頭でお伝えする形になっています。 そこで、毎回のように質問を受けるのであればいっそ記事にして公開し、 現場からみたBASEのリモートワークをお伝えしたい、というのがこの記事の趣旨になります。 あなたは誰 私はBASEのフロントエンドチームでエンジニアリングマネージャーをやっている松原( @simezi9 )です。 マネージャーになったのは2020年7月からです。それまではエンジニアとして働いていました。 なので、BASEがリモートワークを導入する上でどういう議論が行われていたかを直接耳にしたわけではありませんし、 当初は1メンバーとして会社の決定に従って行動する立場でもありました。 そして今ではその制度を運用する立場となってこの記事を書いています。 BASEでのリモートワークの位置付け まず最初にBASEのリモートワークに対して結論だけを述べると、 「BASEではリモートワーク(以下、WFH = Working From Home)は現状可能ですが、フルリモートで働きつづけていく可能性を積極的に模索することは現時点では想定していない。リモートとオフラインのバランスを探りつつ、サービス運営に最も最適な形を模索していく」 ということです。 これについては月並な表現かもしれませんが、対面でもしくは物理的に一緒に働くことで生まれる連帯感やコミュニケーション、文化といったものをBASEでは大事にしたいという思いがあるためです。 大前提としてBASEではよいプロダクトを送り出し、ユーザーの皆様をサポートするという点を第一に考えています。 そしてよりよいプロダクトを作る、品質を高めるという点において、中で働く人間の深いコミュニケーションや文化の醸成といったものが必要不可欠であると考えています。 そしてそういった関係を構築することは、WFHだけでは現時点では難しそうだという判断をしているためです。 コロナ禍におけるBASEの流れ 具体的にBASEにおいて、WFHがどのように運用されてきたか、またその中で自分が具体的にどのように振る舞ってきたかを紹介します。 WFH移行初期(2〜5月ころ) 全社的な動き BASEではコロナウイルスの感染拡大に伴い比較的早い段階でWFH制度が整備され、2月中旬〜下旬にはほぼ全社のメンバーがWFHを開始しました。 いままでは基本的にWFHのための制度はなく出社が前提であったBASEでこれだけ早期に移行できたのは情シスのメンバーの努力の賜物でした。 それらの仕組みの整備が進められていくとともに、社内的にコロナウイルスと働き方のあり方をどのように定義するのかという内部資料が用意され、 都の発表する警戒レベルなどと照らし合わせながら定期的に運用がアップデートされています。 社内で運用されているガイドライン 自分の動き この時期は自分はまだただのエンジニア職であったので基本的に家で作業をしていました。 3月頭と4月頭にチームに新メンバーが入社してきてくれたので、その顔合わせのために最初だけ2〜3日会社に行った以外は出社はありませんでした。 もともと家の作業環境を無意味に整えるのが大好きな性分だったので、WFH開始時には会社の情報共有ツールに謎のエントリを投下してはしゃいだりしていましたし 作業的には特に大きな問題はなく移行できたと思っています。 当時のハイテンションで書いた謎のエントリ群 ただ、フロントエンドエンジニアという仕事柄、作ったものを定期的にデザイナーやディレクターに直接見せて相談しつつ微調整をする、 といったことのコミュニケーションコストが高くなってしまったため仕事の効率という意味ではなんとも言えない部分があったことは否定できません。 WFH移行中期(6~8月頃) 全社的な動き 世の中的には少しずつ以前のような活動を取り戻す取り組みを始めた企業もあらわれはじめた時期だと思いますが、 BASEではWFHで一切出社しないメンバーが大半でした。 一部の、オフィスでないと仕事が難しいメンバーだけは出社していましたが、エンジニアは数名の方を除いて家で仕事をしていました。 オフィスの利用自体を禁止しているわけではなく、「オフィスを使うほうが都合が良ければ使って良い」というような柔軟な運用であったため、 育児などの家庭の都合で家だと作業が難しいようなエンジニアが出社をしていました。 業務都合で出社を要請されたエンジニアは基本的にはいなかった記憶があります。 自分の動き 私自身にも8月に自分が携わった比較的大きい機能のリリースがあったり、 7月にエンジニアからエンジニアリングマネージャーへの配置換えなどのイベントがありましたが、 リリースもマネージャー研修もzoomを利用してリモートで行われたため特に出社することはありませんでした。 現在(2020年9月〜10月) 全社的な動き 都の警戒レベルも少し下がってきたために、オフィスを深いコミュニケーションのできる場所・会社の文化を生む土壌として捉え、 適切なタイミングで活用していこうという機運が高まっています。 例として、一部のチームでは高度な業務知識が必要な場面でドメインモデリングのために週に一度出社して仕様を煮詰めていたり、 マネージャー陣が今後の作業のアサインや組織の構成を考えるために毎週出社してミーティングをする、といった具合です。 個人の事情は考慮されていますので、どうしても出社できないという方に強制したりはしていませんし、全社的に出社日があったりもしません。 ただチーム単位で出社日を決めるといった試みが見られるようになってきました。 また業務外のところでも、最近では新メンバーの歓迎会なども行われていました。 (BASEでは広いフリースペースがあり、そこに感染対策の衝立などが用意してあるためそれを使ってパーソナルスペースを確保した上で開催しています) 歓迎会の様子 家ではなんだか仕事がはかどらないというメンバーの自発的な出社も少しづつ増えてきています。 現在BASEでは社員が約140名ほど在籍していますが、20名前後がオフィスに出社しているようです。 自分の動き 私もマネージャー会議のために毎週金曜日は出社しています。 また、現在メンバーとの1on1を毎週30分行っていますが、BASEでは3ヶ月に一回OKRで個人の目標設定をする機会があるので、そのタイミングでの1on1ではメンバーに出社してもらって対面でちゃんと話すということを行いました。 リモートで満足なコミュニケーションを取り切れていなかったという批判はあるかとは思いますが、自分が実際にオフィスであって会話することによって得られる情報量や充実感というのは、オンラインミーティングだけでは補いきれないものであるなと感じました。 折角金曜に出社するのであればということでMtgなどの用事をなるべく金曜日に固めたりするなどの工夫をしています。 突発的な雑談の時間なども多くとっており、金曜は定常業務よりもコミュニケーションを優先する日、と自分の中ではちょっとした割り切りをしていたりします。 これから コロナウイルスの感染拡大は着地点が見えず、冬が近づきまた感染拡大が発生するのではないかという想定もあります。 そんな中でwithコロナという言葉が表しているように、リスクとメリットの落とし所を探る動きが続いていくものと思われます。 WFHへの考え方もそのうちの1つであると思います。 あくまで現時点での予測ですが、BASEでは急に「来月から全員出社必須」というようなことにはならなさそうではあります。 ただし流れとしては なるべく出社の機会を大切にしていく 、という路線であることだけはまず確実です。 出社することによる不便を極力なくすための整備も進められています。 例えばリモートでのミーティングが増えたことで会議室が枯渇気味になってしまい、急に出社するメンバーが増えると耐えられなくなってしまいそうなので zoomでの会議をするための個室スペースの導入が検討されていたりします。 最後に 長くなりましたが、コロナウイルスの流行は社会構造を良くも悪くも大きく変化させました。 また世の中の働き方の在り方も大きく再考されるきっかけにもなりました。 会社がオフィスを捨てフルリモートに移行する話や、個人的に東京を離れ近郊に移り住みリモートワークをするといったような話も珍しくはなくなってきました。 ワークライフバランスという意味では、自分自身の生活もリモートによってよくなった点がいくつもあります(通勤がなくなった時間で自炊を始めたり、ジムに行ってみたりと精神的な余裕が増えた) そうはいいながらも、BASEでの働き方は社会情勢を見極めつつ柔軟に運用されていくことが当面続きそうになっています。 それはオフィスを完全に離れるということはせず、同じ空間で働くことの価値を大切にしながらリスクとのバランスをとることで実現されていく、ということです ある意味でリモートでのコミュニケーションだけで充分だという人にはBASEという会社は合わないかもしれませんし、 リモート疲れしてきてそろそろ出社してちゃんとコミュニケーションとりながら仕事をしたいという方には合っているかもしれません。 もしBASEでのそんな働き方に興味がありましたらカジュアル面談という形で社内のお話をさせていただく機会を用意しているので、ぜひ応募いただければと思います。 採用情報 | BASE, Inc. 採用情報-フロントエンドエンジニア 採用情報-Webアプリケーションエンジニア
こんにちはBASE株式会社取締役EVP of Developmentのえふしん( @fshin2000 )です。 今回は、年末の給与改定から運用を開始する評価グレード制導入のお話を書いてみたいと思います。 これまで人材採用時の給与決定や社員の評価時には、マネージャ間で相談し役員承認の上で給与を決めていましたが、その基準や空気感は詳しく社内のメンバーに共有できていませんでした。理由として、中途主体の採用だとどうしても前職給与に影響され、人によって給与にばらつきがでてしまうため、体系だった形に整える機会がなかったのですが、今度、社内に評価グレード制というものを導入することになり、各給与レンジの方に求めるスキルや意識についてまとめたのでこちらで公開いたします。 評価グレード制というのは、一般的に等級と呼ばれるもので、一定サイズ以上の会社のご経験がある方なら、類する制度はどこでもあると思いますので詳細説明は割愛いたします。 (採用面接等で詳しくご説明差し上げられれば幸いです ^^ ) 以前からある当社の報酬体系で特徴的なのは、年収7〜800万円以上とそれ以下で給与の上がり方が変わるということが挙げられます。社員の評価は半期毎に行っているのですが、700万円以下の給与の人はスキル向上がそのまま役割向上につながるレンジと捉えていて、仕事を頑張る努力が昇給に反映されやすいのに対して、700万円以上の人はそのような概念をなくして、その代わり、 役割や期待値の変更 に対して大幅な給与アップを目指す。エンジニアリングマネージャもそれを前提として期待を設定していくという考え方があります。 700万円以上の人は、国内の転職市場においても経験豊富なハイスキル層とみなされると思います。マネジメント側の責務として、評価面談やOKRの設定を通じて、大きな期待をかけ、大きな成果をあげてもらい、大きな昇給を実現することが仕事です。エンジニアリングマネージャは、チームメンバーをプロデュースするという仕事の結果、自分自身の評価と昇給にもつながります。 この以前から取っていた給与の構造を踏襲し、グレードを定めました。これまでやっていた給与決定プロセスを言語化したというのが、作業にあたってやったことです。 評価グレード制に至るまでの過程 歴史ある大企業や老舗企業で働いている人たちは、等級制度、評価制度が当たり前に存在していると思いますので、あまり意識したことはないかもしれませんが、スタートアップ企業が評価グレード制を導入する動機には組織の拡大におけるマネージャへの権限移譲の文脈が存在します。 数年前まで昇給額を役員で決めてた。役員もマネージャから報告されるメンバーの活躍を感じられる組織サイズでもあったし、役員がマネージャも兼ねるケースが多かったので、一定の納得感は得られていたと思われる。 役割や期待に対する給与レンジや昇給額のような基準は、役員とマネージャ間には存在していて、採用活動や半年ごとに行われる評価会議を重ねるたびにブラッシュアップされていった 組織が大きくなりマネージャも増えるなか、その基準を言語化することで、どうしたら給与が上がるのかをフレームワーク化し、目標設定と評価をスケールするようにしたもの 一般にマネージャに給与の提案権限を移譲するにあたって、評価クオリティを維持し、評価への納得感と事業成長を実現するための取り組みとして導入されるものが評価制度や等級制度ということになります。 評価グレードの分類 評価グレードは、 A1・A2・Ex1・Ex2・Ex3・Ex4の6段階 に分類されます。 ※A(エー)=Associate、Ex(イーエックス)=Expert 新卒やキャリアが浅い方はA1から始まって、グレードが上がっていけば行くほど、サービスや会社に対する影響範囲は広く、未来を見据えた課題解決や課題設定力に対する期待が設定されます。 グレードに対しては報酬の下限額が設定されています。上記例に挙げた700万円のラインはEx2の下限値に設定されています。 また、皆さんに親しみやすい役割名としてはリード職がありますが、現在、当社ではテックリードと呼ばれる役割の人がいます。彼らはEx3の枠に該当します。当社ではさらにテックリード of テックリードとしてのプリンシパルテックリードが設定されており、それが最上位のEx4に位置づけられます。完全にBASEの未来を作る期待に対して設定した役割です。 各グレードに対する報酬の上限額は設定されていますが、グレードをまたいだ金額の被りは存在しています。 これは中途採用において、実績のある方はもちろん、期待値込みで若くても高い給与で採用することを想定し、入社後に当社のサービスの経験を積んでいただく中で、適切なグレードに合うようにマネジメントしていくための高速道路の合流車線的なバッファとして存在しています。この辺をあまり厳密にしすぎると採用活動に影響が出てしまうので柔軟性をもたせています。 といろいろ前置きを書きましたが、抽象的には以下のようにグレードに対する期待が設定されています。 A1 (新入社員や経験の浅い社員) 指示/指導を受けながら業務を遂行する 自らの業務領域について、業務改善や課題解決の提案をする A2 特定領域において自立した業務遂行をする 所属チームの業務について、業務改善や課題解決の提案および実行する Ex1 特定領域において、 所属チームをリード する水準の事業成果を生む Ex2 特定領域において、所属チームをリード する水準の事業成果を生む 所属Division全体の課題解決 に影響力を持つ 同職種における社内比較で 高い専門性や課題解決能力 を有する Ex3 (テックリードなどのリード職相当) 全社をリード する水準の事業成果を生む 全社の将来的な課題 を解決する事業成果を生む 同業種における 全社トップレベルの高い専門性や課題解決能力 を有する Ex4(プリンシパルテックリードなど) 全社をリードする水準の事業成果を生む 全社の将来的な課題を解決する事業成果を生む 全社の課題解決に影響力 を持つ 同業種における 業界トップレベルの高い専門性や課題解決能力 を有する Web系エンジニアの具体例 以下は、各グレードをWeb系エンジニアに比較的具体例として割り当てたものになります。すべてを満たさなくてはグレードが上がらないというわけではありません。その人の個性と期待する役割にあわせて評価しますが、グレードが上がれば上がるほど、 未来をつくることへのビジョン、プロダクトクオリティの実現、不確実性へのチャレンジを求める ことになるという部分は、共通して期待することになります。 A1 (新入社員や経験の浅い社員) 通常プロジェクトの開発メンバーとして参加し、開発、テストを任せることができる 比較的平易な難易度のお客様のお問い合わせや不具合対応の解決を任せることができる 周囲の助言を受けながら、所々の問題を解決できる A2 通常プロジェクトの開発者として参加し、一人でも開発、テスト、リリースを任せることができる お客様問い合わせや不具合について、解決を任せることができる 本番運用の安定性実現のための障害対応、高負荷対応のオペレーションに参加できる Ex1 通常プロジェクトの技術責任者としてメンバーをリードすることができる (技術責任者とは主にプロジェクトの設計レビューを主導する人) 当社にて求められているソースコード、プロダクト等の品質向上を自ら実現し、メンバーに広げることができる 本番運用の安定性実現のため、障害対応、高負荷問題等を率先して発見、対応し解決に導ける 経験の少ないメンバーに対する技術指導を日常的に任せられる Webサービスを運営するエンジニアとしてPJと日常的な改善を並行して行うために、適切な段取り、スピード、クオリティを実現できる Ex2 難易度の高い技術課題やプロジェクト(決済の追加や商品オプション機能、抽選販売など)の開発の設計、改善について、見積もり、スケジュール通りの実現を任せることができる 技術的負債の返済を自ら先導し、解決することができる 現状のソースコード、プロダクトについて、チームでの品質向上を率先してリードできる 常に稼働しているサービスに目を向けて、技術的な問題を解決し続ける 自動テストやデプロイ改善等を通じて、デプロイ後の問題発見や運用中のサービス改善をリードできる 一つの技術に依存せず、自分が関わる事業領域で求められる技術への適応力がある。開発言語、フロントエンドやサーバサイド、インフラなどの技術概念に囚われず、近接領域の技術を学び続けて問題解決に貢献できる システム改善が必要になる難易度の高い障害対応を率先してリードしクローズに導ける Ex3 (テックリードなどのリード職相当) 難易度の高いPJを実現するためにアーキテクチャ設計、作業段取り、見積もりを行い、メンバーを引っ張ることでスケジュールと品質を実現する 計画の有無に関わらず、短期的、中期的な事業成長を見据えながら、現状のサービス、技術の問題に目を向けて、改善提案および改善実施ができる 技術提案、サービスの問題提起、研究等を常に行っている 自分にとって未知の技術を現状にフィットするように取り入れ、サービスの成長を実現することができる 品質、機能、スケーラビリティ、セキュリティ等を改善する技術的課題を提起し、メンバーをアトラクトしながら改善をリードできる Ex4 (プリンシパルテックリードなど) 会社の中期目標を技術で実現するための技術方針や組織方針の立案および遂行ができる 開発組織に起きる問題点を発見し、技術力の底上げに対する抜本的な施策、生産性の改善を任せることができる セキュリティ、ビジネス、スケーラビリティ等のリスクに目を向け続け、改善提案を行い、組織計画、開発計画に結びつける 今後も役割に対する肩書や、金額構成、トップラインの給与の上限額などは変えていきたいと思っています。Webサービスを支えるエンジニアは一人一人の主体的な活躍がすべてです。非・労働集約的な役割の働き方に対する制度として、ここで決めた制度が今後も固定的であるわけではなく、流動的に見直していけるように業績を上げていきたいと思っています。 それこそEx3やEx4のグレードの人たちが活躍し、サービスクオリティ、業績への寄与を行い給与のトップラインを向上させることが、全エンジニアのスキル、社会的評価、給与水準の底上げにもつながると考えていますし、それがやりやすい組織構造を常に模索していきたいと思っています。 エンジニアリングマネージャのグレード設定について エンジニアリングマネージャにも評価グレードの基準が設定されていますが、こだわりポイントだけ抜粋しますと、以下の特徴があります。 ・採用候補者の適切な給与提案ができる ・新規ビジネス等の際に送り出せるマネージャ、リード候補の育成ができる ・ 組織拡大、分割を前提としたマネージャの育成ができる つまり、人を育てていき、新規事業や組織変更に伴って、一番できる部下を送り出すことを前提としたマネジメントをしてくださいということです。安定した自分の城を作るのではなく、常に不確実である前提で会社全体が成長するように採用とチームを作ることに専念してください。 マネージャは新たに人を採用し、成長をプロデュースして、新たに送り出すことでBASEというサービスのドメイン知識や哲学を兼ね備えた人材が、新規事業や新しい組織のマネージャとして新しい活躍をするというループを描いていきたいと思っています。特に新人マネージャは、既存メンバーのいい兄貴、チームリーダーとしては積み上げた経験が使えるのですが、採用となると経験のない新しい取り組みになるので、時間の使い方として主体的に動けるようになるには時間がかかります。採用に対して、自分事かつ主体的に動けるようになって初めてマネージャとして一人前とみなされます。それはまた全体視点で事業を捉えられるようになり、未来を見据えるようになったという意味でもあります。 そして、よく大企業の新規事業で言われることとして、エースは温存され、そうでない人材が新規事業にあてがわれるという話があります。これはこれで大企業において若手がチャンスを得るという構図になっていると思いますが、当社のように年功序列ではなく若手をガンガン重用していきたい組織においては、なんなら一番できる人が抜けてしまうことを前提としたマネジメントを求めています。 例えば子会社のBASE BANK社を支えるプロダクトマネージャとテックリードは、元々、BASEの決済チームのど真ん中を支えていた若手メンバーでした。新規事業に手を上げてくれて、彼らは今、BASE BANKチームでいきいきと仕事をしていますが、そこでのチャレンジをまたBASEのチームにフィードバックしてもらいたいと思っています。そういったことの再現を今後もやっていきたいと思っています。 現状のエンジニア組織の課題 現状、Web技術に関しては、CTOとプリンシパルテックリードの2トップがサービスの最先端の進化をリードしています。しかし、増えゆくGMVを支えながら、機能性向上、プロダクト品質の向上等を行っていくにはとてもとても手が足りません。 こちらの記事 にある通り、来年以降、CakePHP2.xをなくしていくことをサービスを維持、成長させながら行うという難しいプロジェクトにも挑みたいです。おそらくDDD等のノウハウを活用して再設計をすることになると思いますが、それらを支えていく各分野のエキスパートであるテックリード候補やハイスキルエンジニア層、組織の作り手であるエンジニアリングマネージャ候補を募集していくことになります。 上のグレード表現で言うと、エンジニア組織をリードできるEx2以上の人たちを増やしながら、若手の有望株であるEx1候補を採用して、組織としてスケールさせていきたいです。そのためにもありとあらゆる方策を取って、社内のエンジニアのスキル向上はもちろんのこと、採用を推進していきたいと考えています。 もし、BASEの未来を作ることに興味を持っていただける方がいらっしゃったら是非お話しましょう。エンジニアとしての成長をチャレンジできる環境を用意したいと思っていますし、人材投資をできる環境は整っていますので、一緒に仕事をしましょう! binc.jp