Next.js + Material UI v5 でフロントエンドアプリケーションを作成する なぜこの記事を書いたのか こんにちは。 エニグモ でサーバサイドエンジニアをしております、寺田( @mterada1228 )です。 この記事は Enigmo Advent Calendar 2021 の 20 日目の記事です。 業務では主に Ruby on Rails を使っているのですが、最近新しいチャレンジとして、フロントエンドの勉強をしています。 そこで、Next.js + Material UI(以降 MUI)を使った Web アプリケーションの開発にチャレンジすることにしました。 ただ、この2つは全く異なる開発形態の フレームワーク ですので、一緒に使うためにはちょっとしたセットアップが必要になります。 参考にするため色々と検索してみましたが、なかなか求めている検索結果が得られなかったことと、なぜこのようなセットアップが必要になるかまで詳しくまとめられているものがなかったので、今回自分で調べて一つの記事を書いてみることにしました。 なお、本記事では Next.js で MUI を使うためのセットアップに焦点を絞っているので、Next.js のプロジェクトを立ち上げる部分は説明しません。 その部分を詳しく知りたい方は、 公式チュートリアル を参考にしてもらえると良いかと思います。 Material UI を使うために必要なパッケージをインストールする MUI v5 のパッケージをインストールしていきます。 ひとまず、コアな機能をインストールすれば十分かと思いますので、 @mui/material というパッケージをインストールしていきます。他のパッケージについては、必要に応じてインストールして下さい。 また、MUI ではスタイリングのために内部で CSS in JS のためのライブラリを使用しています。 こちらは、 emotion もしくは styled-component のいずれかを入れる必要があります。 emotion を使う場合 // with npm $ npm install @mui/material @emotion/react @emotion/styled // with yarn $ yarn add @mui/material @emotion/react @emotion/styled styled-component を使う場合 // with npm npm install @mui/material @mui/styled-engine-sc styled-components // with yarn yarn add @mui/material @mui/styled-engine-sc styled-components next/link, @mui/material/Link の統合 Next.js からは、 next/link 、MUI からは @mui/material/Link という コンポーネント が提供されており、名前からお察しの通りどちらもカスタマイズされたリンク(a タグ)を生成します。 この2つには競合する部分もありますが、ある場面では next/link を、また他の場面では @mui/material/Link を用いた方が便利というケースがあります。(どういった場面でどちらを使うべきか、という理由はサンプルコードの後で説明します。) なので、状況に応じてどちらかの コンポーネント を返してくれるように、独自の Link コンポーネント を作成します。 src/Link.js ここで重要になってくるのは65行目から86行目の部分で、href に設定された URL が、 internal か external のどちらであるかを判定して、 return する コンポーネント を分けている、ということです。 URL が internal な場合は、Next.js が提供する、 next/link を返します。 これは Link がアプリケーション内のページ遷移であるときは、以下のような、Next.js が提供する各種機能を使用することができるからです。 Client-Side Navigation Code Splitting and Prefetching これらの説明は本記事の趣旨から逸れますので省きますが、詳しくは こちら をみて頂くと理解することができると思います。 URL が external な場合は、 next/link である理由はあまりないので、豊富なスタイリング用の Props が使用できる @mui/material/Link を使うようにします。 実際にリンクを作成する時は、ここで作成した、 src/Link をインポートする形になります。 pages/Index.js 独自 Theme を作成する こちらは作成せずとも、MUI の default Theme を利用できますが、多くの場合アプリケーション独自の Theme を設定していくことになると思いますので、本記事でも取り上げていきたいと思います。 今回は src 配下に Theme ファイルを配置していきます。例は簡単のために、 Typography の font-size だけを設定したものになります。 src/Theme.js 独自で定義した Theme は、 ThemeProvider を使って、アプリケーションに適用させることが可能です。 具体的な実装方法としては、 _app.js にて、 Component より外側の コンポーネント に ThemeProvider を設定してあげれば OK です。 pages/_app.js app.js, document.js の修正 最後に、Next.js で MUI を使用するために、 _app.js と _document.js の設定方法についてお話ししていきます。 はじめに、これから行う設定が何のためのものかというのを説明します。 MUI は元々、サーバサイド レンダリング されるものという制約のもと開発されています。 なので Next.js をはじめとした、クライアントサイドで レンダリング する可能性がある フレームワーク を使用した場合に不具合が発生してしまいます。 具体的にどのようなことが起きるかというと、いわゆる FOUC( Flash Of Unstyled Content)というもので、画面上に CSS の当たっていないページが一瞬表示されてしまいます。 これはクライアントサイド レンダリング 時に、HTML だけ表示されて、後から CSS が注入されるような流れになるため発生します。 なので、大まかに以下のような手順を踏むことでこの問題を回避していきます。 サーバサイド レンダリング 時に一度、 コンポーネント ツリーの レンダリング を行う そこから CSS を抜き出す( <style> を抜き出す) 抜き出した CSS をクライアントに渡してあげる この手順では以下のパッケージが必要となりますので、事前にインストールしていきます。 // with npm $ npm install @emotion/server @emotion/cache // with yarn $ yarn add @emotion/server @emotion/cache まず、 _document.js から説明していきます。 _document.js は Next.js においてあらゆる コンポーネント の初期化時に実行される コンポーネント ですが、その特徴として、サーバサード レンダリング 時に、サーバサイドで実行されるという特徴があります。 要するに前述した、1, 2 の手順をここで実行していくわけです。 サンプルコードは以下になります。 pages/_document.js 30行目からの処理に注目していきます。 getInitalProps はサーバサイド レンダリング 時に、ページにあらかじめサーバから取得した情報を埋め混むことができるメソッドです。 getInitialProps 内の60行目から66行目までの部分で、一度ページ コンポーネント の レンダリング を行なっていきます(前述した 1. の手順に相当) 以降の処理で、 レンダリング された コンポーネント から CSS ( <style> )を抜き出し、 emotion/cache を使ってキャッシュに保存します。(前述した 2. の手順に相当) 次にクライアントサイドの処理について見ていきます。 _app.js は _document.js 同様に、あらゆる コンポーネント の初期化時に実行される コンポーネント ですが、クライアントサイド レンダリング 時には、 _document.js は実行されず、 _app.js しか実行されないという特徴があります。 ここでは、 _app.js でサーバサイド レンダリング 時にキャッシュに保存した CSS を受け取るといった方法で、クライアントサイド レンダリング 時に発生する FOUC を回避します。以下がサンプルコードです。 11行目でサーバサイド レンダリング 時に保存した CSS を取得します。 このキャッシュに保存された CSS は17行目のように、 <Component> コンポーネント の外側を <CacheProvider> で囲ってあげることで、各ページ コンポーネント に渡されます。 ここでお話しした内容は、 MUI の公式ドキュメント でも詳しく説明されていますので、お時間ある方は合わせて見て頂けると理解が深まるかと思います。 おわりに 今回紹介したサンプルコードですが、 https://github.com/mui-org/material-ui/tree/master/examples/nextjs で MUI が公式に提供しているものです。今後変更がある可能性もありますので、サクッとコピペして使いたい方は、紹介したリンクから取得いていただくのが確実と思います。 明日の記事の担当は データテク ノロ ジー グループの堀部さんです。お楽しみに。 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは。Corporate IT 所属の田中です。この記事は、 Enigmo Advent Calendar 2021 の19日目の記事です。本記事では、 Google Apps Script(以下、「GAS」といいます。)を使用して統合認証基盤サービスであるOktaの管理業務を効率化したことについて紹介したいと思います。 Oktaのグループにユーザーを追加する際、ユーザー数が多いと管理コンソール上で行うのに手間がかかり大変かと思います。 また、作業自体は簡単なものであるため業務アシスタントの方にお願いしたいと思いつつ、ロールの仕様上グループへのメンバー追加のみ権限を付与することも難しく、必要以上の権限付与を防ぐため結局自分で作業してしまうということもあるのではないでしょうか。 上記を改善するため、GASを用いて Google スプレッドシート 上で簡単にメンバーのグループ追加を行えるようにしました。 更に、DB化された スプレッドシート を利用して、Okta ユーザーのステータス情報を毎月コラボレーションツールのSlackに通知することで、月次のアカウント棚卸を効率化しました。 構成 仕組みはざっくり下図のとおりです。 *1 *2 ユーザー及びグループ一覧の取得 Oktaの API を使用してグループへユーザーを追加するためには、グループとユーザーそれぞれ一意に付与されているIDが必要です。 そのため、プロセスの前段としてGASでOkta API からユーザー情報一覧とグループ情報一覧を スプレッドシート に同期しています。同期は、GASのトリガーを定期的に実行することで実現しています。 下図が、 スプレッドシート へ反映されたユーザー一覧及びグループ一覧です。 「users-list」シートでは、ステータス、氏名、ローマ表記、email、ユーザーID、最後にログインした日時を取得しています。 また、group-listでは、グループ名、グループID、グループの説明を取得しています。 グループ追加 プロセスの後段として、上記取得した情報を基に、 スプレッドシート 上でOktaユーザーのグループ追加を行います。 下図左表「users-list」に追加する人の氏名を、右表「group-list」に追加先グループ名をそれぞれ入力すると、 スプレッドシート のvlookup関数を利用してid等が自動入力されますので、後は下図右側の画像をクリックすると、GASでOkta API を使用してグループへのユーザー追加プログラムが実行されます。 実行後、下図のように正常に追加されたことを確認しました。今後は、Slackの関連ページから本 スプレッドシート を開いて簡単にグループへ多数ユーザーの追加ができそうです。 Oktaユーザーのステータスを月次棚卸 Oktaユーザーに関するステータスやログイン状況を利用して、 スプレッドシート 上で集計し月末にSlackに通知することにより、棚卸作業がやりやすくなりました。 最後に いかがでしたでしょうか。私自身は非エンジニアで公開できる程綺麗なコードは書けませんためここでは非掲載とさせていただきますが、そんなレベルでも上記のような実装ができるぐらいGASは社内ITの連携に活用しやすく親和性のあるサービスかと思います。本記事の実装内容についてご興味ある方はご連絡くださいませ~。 また、enigmo Corporate ITでは各種 クラウド サービス間の連携・自動化を実装できるようなコーポレートエンジニア及び部門を横断的にセキュリティ整備を行うセキュリティエンジニアを募集しております!ご興味ある方は下記求人からご応募お待ちしております! 明日の記事の担当は、サービスエンジニアリング本部の寺田さんです。お楽しみに。 株式会社 エニグモ すべての求人一覧 hrmos.co *1 : Oktaのロゴは、次の 利用規約 に基づき使用しております。 https://www.okta.com/terms-of-use-for-okta-content/ *2 : Google 製品のロゴは、次の 利用規約 に基づき使用しております。 https://about.google/brand-resource-center/brand-elements/#product-icons
こんにちは、 BUYMA デザイナーの本田です。 BUYMA では今年の2月〜7月にかけてカートの大幅なリニューアルを行いました。 PHP から Rails への洗い替えや、パフォーマンスの改善がメインの施策だったのですが、UXの改善として、 上部に追従する購入ボタン や よくある質問エリア を新しく追加しています。 ユーザーからよくある実際に届いている声の中から、 購入ボタンが遠くて見づらい キャンセルや返品がわかりにくくて不安 配送が遅い エラーがわかりにくい 上記4つの課題を解決するために、どのような想いのもとでデザインに落とし込んだのかについて紹介します。 1. 購入ボタンが遠くて見づらい BUYMA はカート画面でユーザーに確認していただきたいことが多く、1商品あたりの高さができてしまい、購入ボタンまでスクロール回数が多いことが課題となっていました。 複数商品をカートに入れていても、購入ボタンを見失わないでもらうために 要素の見せ方整理をして、1商品あたりの高さを低くする 購入ボタンを上部へ固定し、スクロール時も追従するようにする の2つを行いました。 2. キャンセルや返品がわかりにくくて不安 海外で購入した商品を日本へ送るCtoCショッピングサイトという特性上、 偽物ブランドはないか 返品はできるか 送料や関税の負担はだれがするのか などの質問をユーザーからいただくことが多く、専用の説明LPや ガイドライン などで説明しているのですが、それでも購入前になかなか気づけない・ユーザーの不安を拭えないことが、課題となっていました。 解決策として、 LPへ遷移しなくてもカートページ内で補償サービスの内容を理解できるようにしたり 、 ユーザーからよくある質問エリアをまとめたエリア設置 しました。 3. 配送が遅い 海外配送となるため、送料の1番安いプランだと、繁忙シーズンには2週間以上かかってしまうこともあります。一方で、オプションメニューで、DHLやEMSなど海外の速達サービスを利用すると、+1,000円ほどで配送日数は大幅に短縮され、数日でお手元に届きます。 今までのUIですと、オプションメニューを選ぶことで、数日で到着することに気づかないまま、ご購入されるケースも多くありました。そのため、最短のプランがある時は、オプションメニューを選びやすくするUIパーツを追加しました。 4. エラーがわかりにくい 今回のプロジェクトを機に すべてのエラー文言を洗い出し 、どの状況下でエラーが発生してしまうのかを洗い出して整理し、提示するようにしました。 また、ユーザーは次に何をすればいいのか、 ネクス トアクションをきちんと提示することで、離脱率の低下を狙いました。 検証 1. 購入ボタン 購入ボタンのクリックの割合は 埋め込み:追従=8:2 くらいで予想以上に利用されていました。 以前に他のプロジェクトで、商品詳細ページでも追従ボタンを設置してABテストをしていたので、あまり期待はしていなかったのですが、購入をある程度決めているカート画面には適切だったということがわかりました。 2. キャンセルや返品についてわからなくて不安 よくある質問エリアのクリックが 全体の約2%で 、割合としてはそこまで高くないですが、あんしんしてお買い物をするための後押しに少しでも貢献できたと思うと、デザイナーとして手応えがあったなと思います。 3. 配送が遅い 「最短の配送方法あり」の ツールチップ が表示されているユーザーの中で、さらに配送選択をしたユーザーの 約45% が最短を選択していました。 サービスの特性などにもよるとは思いますが、追加料金を払っても早く商品が届いてほしいユーザーが多いことがわかりました。 まとめ 今回のカートリニューアルはユーザーの 今の課題を解決する に加えて、 あんしんして BUYMA でお買い物を楽しんでもらう というビジョンを持ってサービス開発ができたと思ってます。 プロトタイプを定例で関係者全員に見せてフィードバックをいただけたり、プロジェクトチームの方全員と一丸になれたのもいい思い出です。来年も今年学んだことをベースにさらにいろんなことに挑戦していきたいです。 最後まで読んでいただきありがとうございました。 明日の記事の担当は 情シス の 田中さんです。お楽しみに。 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは、 エニグモ 嘉松です。 この記事は Enigmo Advent Calendar 2021 の17日目の記事です。 はじめに 毎日毎日、それこそ仕事で使わない日は無いくらい、いつもお世話になっている 表計算 ソフト。 昔はみんな Excel を使っていましたが、最近は社内でも Google スプレッドシート を使うことが増えているように感じます。 (因みに私は Lotus 1-2-3 やNumbersは使ったこと無いです。) さて、皆さんいろいろな関数を駆使して作業を効率化していることかと思います。 代表的な関数をいくつか紹介すると、 SUM 表計算 ソフトの関数の代表格といえば何と言ってもSUMですかね。 指定した範囲の合計値を求めてくれます。 「=SUM(A1:A10)」といった形で、合計したいセルの範囲を指定してあげます。 COUNTIF 条件に一致するデータの個数を求めてくれます。 シンタックス は COUNTIF(範囲, 検索条件) です。 「=COUNTIF(A1:A10, "<100")」といった形で、検索の対象とする範囲と、検索する条件を指定します。 結果としては条件に合致したセルの数を返します。 実は私、ほとんど使ったことないですが、よく聞くので紹介しました。 VLOOKUP VLOOKUPを使えると 表計算 ソフトのスキルは中級くらいのレベルになりますかね。 この関数はホントに便利です。もはや無いと生きていけないレベル。 シンタックス は VLOOKUP(検索値, 範囲, 列番号, 検索方法) です。 範囲 で指定した先頭の列を上から順に検索して 検索値 に一致する値を探します。見つかったセルと同じ行の 列番号 にあるセルの値を結果として返します。 検索方法 は FALSE しか使ったことないです。 ちなみに、 Google スプレッドシート の関数の一覧はこちら。 Google スプレッドシートの関数リスト - ドキュメント エディタ ヘルプ 何十、何百の関数が用意されていて、使ったことも無い関数が殆どなのですが、自作のオリジナル関数を作ることも出来ます。 えっ、関数を自分で作る?そんな事できるの?と思われた方も多いかとも思いますが、私も最近知りました(笑) では、これからオリジナル関数を自作する方法を紹介します。 消費税を求めるオリジナル関数を作ってみる オリジナル関数、どう作るか? そのためには Google Apps Scriptで スクリプト を書く必要があります。 Google Apps Script(GAS)とは、 Google が開発・提供している プログラミング言語 です。 JavaScript をベースに開発されたそうです。 スクリプト エディタを起動する Google スプレッドシート を開いたら、タブから「 拡張機能 」>「Apps Script」を押下します。 スクリプト エディタを起動 新しいタブが追加されて、以下のような スクリプト エディタが起動されます。 スクリプト エディタが起動 スクリプト を書く スクリプト エディタが起動されたら、ここにオリジナル関数の スクリプト を書きます。 ここでは消費税を求める関数 myTAX 関数を作ってみます。 /* 消費税を返す関数myTAX */ function myTAX(price){ const taxRate = 0.1; //消費税率 return price * taxRate; } function のあとの myTAX は関数の名前です。 price は、関数の引数です。この関数の引数は1つなので、このように指定します。 const taxRate = 0.1; //消費税率 は taxRate という定数を作成して、税率の0.1(10%)を代入してあげます。 そして return price * taxRate; で引数で指定された price に消費税率 taxRate を掛けて、その結果を return で返してあげます。 スクリプト ができたら、 フロッピーディスク のアイコンをクリックして保存してあげます。 (いまの若い方は フロッピーディスク なんて知らないと思いますが、これでイメージ付くのかな?) オリジナル関数の使い方 では、作った関数を使ってみましょう。 使い方は簡単で、標準の関数と同様に = の後に関数の名前と引数を指定するだけです。 オリジナル関数の使い方 はい、このように消費税の金額が求められました。 オリジナル関数の結果 B2 のセルの右下の小さな四角を下に引っ張れば、 B2 のセルがコピーされて、下の行の消費税が算出されます。 関数のコピー 消費税の算出だけであれば、セルに直接 =A2 * 0.1 とすればできます。 ただ、オリジナル関数を作って消費税を算出するメリットは、消費税の税率が変わった時に スクリプト の消費税率を変えてあげるだけで、変更後の消費税が取得できます。 const taxRate = 0.12; //消費税率 こんな感じですね。 ABテストの信頼度を算出するオリジナル関数を作ってみた 実は、というか当然ですが私は消費税を算出するオリジナル関数を作りたかったわけではありません。 我々は日常的にABテストを実施しています。 例えばクーポンを配布した時に、配布したグループと配布しなかったグループで注文率に差があるが、どの程度差がでるか、クーポンを配布することで注文は増えるけど利益はどうなのか?といったようなことです。 この時、以下のような結果が出たとしましょう。 ABテストではクーポンの配布を実施したグループをトリートメントグループ、クーポンの効果を検証するために敢えてクーポンを配布しないグループをコン トロール グループと呼びます。 対象者 注文者 注文率 トリートメントグループ 179,120 1,677 0.94% コン トロール グループ 11,800 98 0.83% この結果からクーポンを配布したトリートメントグループの注文率が0.94%とコン トロール グループの0.83%を上回っているので「クーポンの効果があった」と判断したくなります。 ただ、世の中、誤差は付き物です。 サイコロを10回振った時に1が10回連続で出たとしても、必ずしもそのサイコロが イカ サマとは決めつけられません。偶然10回連続で1が出る確率は少なからずあります。 同様にクーポンのABテストでも偶然トリートメントグループの注文率が高かった、ということは無くはないです。 そんな事言ったらABテストを行う意味がないではないか、というとそうではありません。 今回の結果が偶然なのか、それとも偶然ではないのかを統計的な手法を使って判断することが可能です。 その方法を統計の用語で検定と呼びます。 検定の方法はいくつかあるのですが、今回は カイ二乗検定 という検定方法を使って検定を行います。 詳細は省略しますが カイ二乗検定 の方法は、以下の順序で行います。 ①実績値を集計 注文あり 注文なし 合計 トリートメントグループ 1,677 177,443 179,120 コン トロール グループ 98 11,702 11,800 合計 1,775 189,145 190,920 ②期待値を算出 注文あり 注文なし 合計 トリートメントグループ 1,665 177,455 179,120 コントールグループ 110 11,690 11,800 合計 1,775 189,145 190,920 ③実績値と期待度数の乖離値を求める ④乖離値を合算して カイ二乗 値を求める ⑤ カイ二乗 値からp値を求める ⑥p値から有意差を求める 一般的に有意差が95%を超えると有意な差がある、つまり偶然ではないと判断します。 このように有意差を求めるには多くの手順が必要となります。 そこでオリジナル関数の出番です。 今回は①〜④の カイ二乗 検値を求めるところまでをオリジナル関数で行い、⑤〜⑥は標準で用意されている関数を使いました。 function myGETCHISQ(a, b, c, d){ // 実績値 var o = [ a - b, b, c - d, d, ]; var s = o[0]+o[1]+o[2]+o[3]; // 期待値 var e = [ (o[0]+o[1]) * (o[0]+o[2]) / s, (o[0]+o[1]) * (o[1]+o[3]) / s, (o[2]+o[3]) * (o[0]+o[2]) / s, (o[2]+o[3]) * (o[1]+o[3]) / s, ]; // カイ二乗検値 var chisq = 0; for (i=0; i<=3; i++){ chisq += (o[i] - e[i]) * (o[i] - e[i]) / e[i]; } return chisq; } この関数の シンタックス は、以下のとおりです。 myGETCHISQ(試行回数A, 注文数A, 試行回数B, 注文数B) 上記の例だと、 =myGETCHISQ(179120, 1665, 11800, 98) となります。もちろん引数にはセルの値を参照させることもできますよ。 この関数で求められた カイ二乗 検値を標準で用意されている CHISQ.DIST.RT 関数に与えてあげることでp値が求められます。 CHISQ.DIST.RT( カイ二乗 値, 自由度) そして、1からp値を引いて100を掛けてあげれば有意差が求まります。 因みにこの例の有意差は75.36%で95%を下回っているので、有意な差が出ているとは言えない、となります。 最後に 今回は Google Apps Script(GAS)を使って Google スプレッドシート のオリジナル関数を作る方法を紹介しました。 また、より実践的な例としてABテストの信頼度を算出するオリジナル関数を作ってみました。 GASを使うと日頃の作業を上手に、そして簡単に効率化することが出来ます。 是非参考にしていただければと思います。 明日の記事の担当はデザイナーの本田さんです。お楽しみに。 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは、Webエンジニアの平井です。 この記事は Enigmo Advent Calendar 2021 の16日目の記事です。 現在、私は BUYMA のSellチームに所属していて出品者関連システムの実装を担当しています。 今季最も注力した受注リストページの Rails 化プロジェクトについて、プロジェクトの概要、プロジェクトを進める上で工夫した点、失敗した点について書きたいと思います。 Rails 化プロジェクトとは もともと BUYMA は PHP で実装されたシステムで、その実装を Ruby on Rails で書き換えるのを弊社では Rails 化と呼んでいます。 Rails 化する目的は以下になります。 PHP の古い フレームワーク で書かれた手続き的なコードを オブジェクト指向 なコードに書き換えて可読性、可用性を上げる。 不要な処理を無くし、レスポンスタイムをあげる。 受注リストページについて 受注リストページは BUYMA で発生した受注が一覧で表示されていて、出品者がその受注情報を確認したり、受注に対して発送通知などの アクションを実施するために用意されたページです。 出品者にとって利用頻度が高いページで、施策で修正する頻度が高いものの PHP の古い フレームワーク で実装されているため修正のコストがかかるのがネックでした。 また、絞り込み機能が乏しく、出品者が目的に沿った取引を絞り込めずに各アクションを実施するのが大変という企画サイドの要望も有りました。 ですので、今回は Rails 化に加えて、検索機能の充実化も開発スコープに含めてプロジェクトを進めました。 システム概要 クライアントサイド クライアントサイドは、実装スピードを上げるため大部分はerbで実装しました。ただ、検索フォームに関しては共通 コンポーネント を利用したかったため Reactを使いました。 サーバーサイド すべて Ruby on Rails です。また、 BUYMA では検索サーバーにSolrを利用していて、この受注リストでも例外なく 受注の検索はSolrを使っています。ただ、旧受注リストではSolrを直接利用していたためSolr特有のパラメーター生成処理など も実装されていました。そこで、検索エンジニアの方に API を開発してもらい新受注リストからはその API を利用して検索処理を実装しています。 API を利用したため、Solrの専門的な知識が不要でアプリケーション側の実装の負担がかなり減りました。 工夫した点 ドキュメントの作成 Rails 化プロジェクトの難しいところは、 PHP で書かれた ソースコード を読み正しく仕様を理解することです。 旧受注リストには、出品者が利用する様々な機能が実装されていますがまとまったドキュメントがなかったので ソースコード を 呼んで仕様を理解する必要があります。 ドキュメントがあれば非エンジニアとのコニュニケーションがスムーズに進むのでこのタイミングでドキュメントを作成しました。 また、実装とドキュメント作成を別々で行うとどうしてもドキュメント作成が後回しになってしまうため、実装しながらドキュメントも同時に作成するように 工夫しました。 ドキュメントを作成した事で、デザイナーやQA担当の方とのコニュニケーションがスムーズに進んだと思います。 フィーチャーフラグの利用 リリースの負担を減らすために、フィーチャーフラグを利用しました。 リリースブランチに受注リスト Rails 化に関わる修正をマージし、該当ブランチを毎週リリースすることで新受注リスト公開時のリリース負担を減らすことが出来ました。 追加機能の優先度付け リリーススケジュールに関しては、12月のセール時期より前に新受注リストをリリースしたいという企画側の要望が有りました。 そこで、企画サイドとコニュニケーションを取り追加機能の優先度を決めて、リリース目標日までに実装すべき機能とそうでない機能を切り分けました。 優先度を決めたのが功を奏し、目標としていたスケジュール日通りに基本的な機能をリリースすることが出来ました。 ユーザーインタビュー 企画的な内容になりますが、企画サイドの担当者の方が、新しく実装する機能やデザインについて多くの出品者に対してインタビューを実施してくれました。 リリース後に追加機能に関してネガティブな意見がほとんどなかったのもこのインタビューのおかげだと思います。 失敗した点 テスト環境でのパフォーマンス監視 そもそも Rails 化プロジェクトの目的としてレスポンスタイムの向上があるのですが、テスト環境でのパフォーマンス監視が不十分だっため 旧受注リストよりも、新受注リストのほうがレスポンスタイムが遅くなってしまいました。 原因としては, N+1とerb上でのrenderメソッドの多用です。 現在、絶賛修正中です。 最後に いかがでしたでしょうか。現在弊社で進められている Rails 化プロジェクトについて書かせて頂きました。 今回プロジェクトで学んだ点を活かし、今後も BUYMA の改善を進めていきたいと思います。 明日の記事の担当は。データ活用推進室の嘉松さんです。 株式会社 エニグモ すべての求人一覧 hrmos.co
この記事は Enigmo Advent Calendar 2021 の15日目の記事です。 はじめに 寒さが身にしみる今日この頃、みなさん如何お過ごしでしょうか。 最近、○○エンジニアという肩書きがよく分からなくなってきたエンジニアの伊藤です。 アドベントカレンダー の時期になると年末になったんだなという実感が湧きますね。 今回は今年一番注力してやってきたMLOpsについて書いていこうかと思います。 はじめに なぜMLOpsなのか? 全体的な流れ 調査 MLOpsの定義、目標の設定 エニグモにおけるMLOps 方針 小さく始めて、大きく育てる 同じ言葉で話せるようにする マネージドサービスの活用 目標 DSが開発しやすい環境作り 開発コスト削減 データの可視化と監視 変化に強い基盤構築 アーキテクチャの設計 ツール選定 アーキテクチャ ML基盤の構築 CI/CD/CTの検討、設計、実装 CI/CD CT おわりに MLOpsとは? については他にも色々と記事があると思うのでここでは触れずに、 導入に向けてどういった手順でどのような取り組みを行ってきたかを中心にご紹介できればと思います。 なぜMLOpsなのか? 弊社でも 機械学習 を活用したプロジェクトがここ最近増え始めています。 そういった中で課題も色々と見えてきました。 属人化 実装内容を把握しているのが個人に依存している レビューがされていない 使用されているバージョンやライブラリがプロジェクトによってバラバラ 開発効率の低下 同じような処理が色々なところにある テストコードがない 心温まる運用 モデルの作成、デプロイは手動 オブザーバビリティの欠如 こういった状況を踏まえつつ、 今後も増えてくるであろう 機械学習 プロジェクトを見据えて、MLOpsを導入することになりました。 全体的な流れ MLOps導入まではざっと下記のような流れで進めました。 調査 MLOpsの定義、方針/目標の設定 アーキテクチャ の設計 ML基盤の構築 開発体制やルール等の策定 実装 CI/CD/CTの検討、設計、実装 監視周りの検討、設定 4以降についてはきっちり分けて進めていた訳ではなく、走りながら(実装、構築しながら)並行で進めていくことが多かったです。 以降で各項目からいくつかピックアップして詳細については記載します。 調査 私自身、MLOpsについては何となく分かっていたつもりでしたが、先人たち(先行他社)の取り組みや関連資料を読み漁りました。 ここで特に気を付けていたのは下記の点です。 機械学習 プロジェクトにまつわる課題としてはどういったものがあるのか? 現時点で弊社としての課題感はないが、今後課題になりうるものがないか? 先人たちの取り組みを真似るのではなく参考にする 各課題に対してどういった考えで、どのようなアプローチをとっているのか 個人的な考えですが、組織の規模感や文化といったものが違うのに同じような取り組みをしても失敗すると思っています MLOpsの定義、目標の設定 MLOpsは バズワード だなんて意見もあります。 MLOpsという単語自体が一人歩きしている感もあるかなと思います。 なので一通り調査が終わったあとは弊社におけるMLOpsを定義することにしました。 今更ながら弊社のメンバー構成を紹介すると下記の通りで、スモールスタートにはちょうど良い人数かなという印象です。 データサイエンティスト(以降、DS) ✕ 2名 エンジニア(以降、 Ops ) ✕ 2名 エニグモ におけるMLOps 「DS(ML)とエンジニア( Ops )がお互いの役割を理解し、強調し合うことで、 機械学習 モデルの実装から運用までのライフサイクルを円滑に進めるための仕組みづくりやその考え方」 方針 続いて方針についてです。3つ挙げました。 小さく始めて、大きく育てる 同じ言葉で話せるようにする マネージドサービスの活用 小さく始めて、大きく育てる 最初からあれも、これもと色々なことを詰め込みすぎない いつまで立っても設計が固まらず、システムの構築や運用が始まらないというのは一番避けたい MLOpsを取り巻く環境はまだまだ成熟しておらず、ノウハウや技術も発展途上の段階 柔軟性が高くスケールする基盤であることを第一としてシステムを設計、構築する 同じ言葉で話せるようにする スキルセットやメンタルモデルが異なるメンバー同士で作業を進めていく上ではどうしてもコニュニケーションコストは高くなる エンジニア同士では 暗黙知 としているようなルールやお作法についてもきちんと明文化し、使用するツールや フレームワーク なども共 通化 ガチガチのルールで縛るのは好きではないので、バランスには注意 マネージドサービスの活用 限られた人的リソースの中で対応していくにはどうしても人が ボトルネック になりがち&人的コストはスケールさせるのが難しい お金で解決できるようなところは積極的に利用する 何でもかんでもマネージドという訳ではなくバランスが大事 コスト(人とお金) X システムとしての柔軟性は意識する 目標 最後に具体的に何をしていくか、どこを目指すかの目標についてです。 ひとまず今期(2021年)としては下記を目標として挙げました。 DSが開発しやすい環境作り UIベースでの実験管理 再現性の確保(今期はデータではなく環境面にフォーカス) パイプラインのバージョン管理、ライブラリ、 フレームワーク の統一 各種ルール化(明文化) コーディング規約、レビュー規則、ログ仕様、開発フロー 実験段階から本番環境へのデプロイがシームレスに可能 ドキュメントの充実化 開発コスト削減 共 通化 できるものは共 通化 し、再利用可能な仕組みづくり( 車輪の再発明 はしない) データの可視化と監視 モデルの性能指標など、可視化して確認したいデータが見たい時に見られる状態 過不足のない監視、アラート 変化に強い基盤構築 汎用性が高く、スケール可能な基盤であること チームとして1つの目標を目指す上で、言葉の定義や、目標の明文化というのはとても大事だと思っているので、 この辺については特に丁寧に行いました。 また目標としてやるべきことを明確化することと合わせて、やらないこともあえて決めておきました。 どうしても作業を進めていく中で「こんなこともできるとうれしいよね」みたいなことは出てきます。 方針にも挙げていますが、まずは小さく始めることを第一としていたので、こういった迷うケースでも チームとしてブレずに進めたのは良かったなと思います。 アーキテクチャ の設計 続いて アーキテクチャ の設計についてです。 ツール選定 アーキテクチャ を設計する上ではまずはMLワークフローの中心となるツール選定を行いました。 MLOpsを取り巻くツールは MLOps Toys に集約されるようにとても多岐に渡ります。 この1つ1つを調査、検証していてはとても時間がかかるのでツール選定については時間をかけずに、 下記の観点で一番相性の良さそうなKubeflowを選択しました。 利用事例が多い 開発が活発 柔軟性がある まずはPipelinesのみ導入し、その後必要に応じて他の コンポーネント 導入が可能 Kubernetes の構築、運用実績がある アーキテクチャ 分析等に扱うデータはBigQueryに集約している関係で、そのデータを扱うML系のプロジェクトも GCP 上で構築することが多いです。 そのため今回新たに構築するML基盤についても GCP 上で構築しています。 またKubeflow PipelinesについてはそのマネージドサービスであるAI Platform Pipelinesを利用することとしました。 ML基盤としてGKEを利用 3パターンのnodeプールを用意 KFP nodeプール Kubeflow Pipelinesが動作するための コンポーネント 群専用 ML nodeプール MLパイプラインでの処理を実行するpod用のnodeプール 0 to Nのノードスケール 使用するマシンタイプは短時間で高速で処理が完了するようにCPU,メモリともに潤沢なものを選択 API nodeプール 予測結果のサービング用 API 向け 1 to Nのノードスケール 使用するマシンタイプはCPUメインの比較的軽めのものを選択 GCP マネージドサービスとして下記を利用 AI Platform Pipelines BigQuery Cloud Storage Cloud Datastore Container Registry 各種メトリクスの可視化、監視にはDatadogを利用 ML基盤の構築 ML基盤としては上記の通り、GKEをインフラとしつつ、AI Platform Pipelinesを利用しています。 基本的には全てIaCとしてterraformで管理、運用していますが、AI Platform Pipelinesは未対応だったため対象外として扱っています。 また、システムに名前があった方が良いよねということで、 メンバーそれぞれで候補となる名前をいくつか挙げて、投票で一番多かった Capella という名前に決まりました。 CI/CD/CTの検討、設計、実装 CI、CD、CTともに全てGitlab CIを利用するようにしました。 Cloud Buildなども検討しましたが、Gitlab CIの方がより柔軟性が高かったのと、元々別のシステムでもGitlab CIを利用していたというのが理由です。 CI/CD テスト環境 本番環境 ポイント 各工程の細かい処理については置いておいて、ポイントについてここでは記載します。 成果物はテスト、本番環境で共通 Kubeflow Pipelinesにおける成果物してはパイプライン( コンパイル 済みファイル)とそこで実行される コンポーネント のコンテナイメージとなります。 本番環境ではテスト環境で作成された成果物を使用してパイプラインのデプロイを行います。 integrationテストとして実際にKubeflow Pipelines上で コンポーネント の動作検証を自動テスト 作業を進める中でコンテナイメージ単体としては問題なく動作するが、Kubeflow Pipeline上でパイプラインとして実行した際に問題となるケースがいくつかあったため組み込みました。 CT パイプラインの実行トリガーをどこに持たせるかは正直一番悩んだところです。 Kubeflow Pipelines側に標準実装されているスケジュール機能を利用するのが良いのかなとも思いましたが、下記の理由からGitlabパイプラインスケジュールを利用して定期実行するようにしています。 CI/CD用に作成したツールを使い回せる gitブランチと紐付けてスケジュール実行が可能 master → テスト環境 production → 本番環境 CI/CDジョブとシームレスに扱うことができる CI/CD/CTがすべてGitlabで管理されているという分かりやすさ Kubeflow Pipelines側のスケジュール機能で実行した場合に、MLパイプラインの実行ステータスの通知をどうするかの検討が別途必要だった Gitlab側であればパイプラインステータスを判断してSlack連携が可能なことは確認済みだった なお、下記がGitlabパイプラインスケジュールのUIになります。 内容としても直感的に分かりやすく、cronジョブベースでの定期実行と、設定した変数で処理が分岐できるようにしています。 おわりに ここまで調査/検討から始まり導入までについて、ざっとご紹介させていただきました。 書ききれていない内容もありますが、少しでもどういった取り組みをしているのかが伝われば幸いです。 また今回構築したシステムについてはまだまだ未熟で、これからどう成長させていくかが大事かなと思っております。 そんな訳で エニグモ ではMLプロジェクトを一緒に盛り上げていくメンバーについても募集中です! この記事を見て少しでも興味を持っていただけたら、まずは雑談からでもOKですので気軽にご相談ください。 明日の記事はエンジニアの平井くんです!きっとワクワクするような内容だと思うのでめちゃくちゃ楽しみですね!!! 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは。サーバーサイドエンジニアの伊藤です。 この記事は Enigmo Advent Calendar 2021 の 14 日目の記事です。 みなさんは シェルスクリプト を実装する機会はどのくらいの頻度でありますでしょうか? 私は社内ツールや個人で利用するちょっとしたツールを作成する際に、 シェルスクリプト を実装することがあります。 とはいえ、普段の業務では Ruby on Rails を用いて実装をすることが多いので、 シェルスクリプト を実装する機会自体はそれほど多いものではありません。 その為、 シェルスクリプト 実装時に割と基本的な罠に陥ってしまうことがありました。 そこでこの記事では シェルスクリプト の実装に潜む 4 つの罠を共有したいと思います。 1. shebang の記載漏れ 2. 適切な set options を指定しない -e (errexit) -u (nounset) 3. 1行で宣言と代入を行う 4. Double quotes で変数を囲わない shellcheck とは? 参考 1. shebang の記載漏れ # bad echo " FOO " # good #!/usr/bin/env bash echo " FOO " ファイルの 1 行目に shebang を記載することで、プログラムを実行するシェルを明示的に指定することが推奨されます。 というのも、シェルによってはサポートされている機能が異なることがあるため、 スクリプト を実行するシェルを明示的に指定することで意図しない挙動を避けることができます。 ここで 1 つの疑問が発生しました。 シェルスクリプト において shebang の記述は下記の通り複数ありますが、好ましい記述方はどれなのでしょうか? #!/bin/bash #!/usr/bin/env bash 一般的には #!/usr/bin/env bash の形式を利用することが推奨されるようです。 絶対パス 等で指定をした場合、実行環境によっては指定の場所に実行可能なコマンドが存在しない可能性が考えられます。 上記の方法で記載すると、 $PATH から実行可能なコマンド(この場合 bash )を捜査してくれるのでポータビリティという点でメリットがあります。 さて、少し話が逸れてしまったので 閑話休題 、 2 つ目の罠に話を移します。 2. 適切な set options を指定しない # bad #!/usr/bin/env bash echo " FOO " # good #!/usr/bin/env bash set -eu echo " FOO " -e (errexit) こちらのオプションを指定することで、 シェルスクリプト の途中でエラーが発生した場合その場で直ちに スクリプト を終了します。 大抵のケースではエラーが発生した場合、その場で スクリプト を終了したいことが多いと思いますので有効にしておくことが推奨されます。 ちなみに、エラーを許容したい場合には下記のように記述することで該当のコマンドのみエラーを許容することが可能です。 command1 || true echo " This line is executed anyway " -u (nounset) こちらは変数宣言に関するオプションです。 デフォルトでは宣言していない変数を利用した場合、空文字として扱われてしまいます。 その為、 typo 等で未宣言の変数を利用したとしても特にエラーにはならないので、意図しない挙動を招くことがあります。 そういったケースを避けるためこちらのオプションを有効にしておくことをお勧めします。 3. 1行で宣言と代入を行う # bad export BAR= " $( command2 ) " # good BAR = " $( command2 ) " export BAR 上記の スクリプト では command2 の結果が無視されてしまいます。 set -e を指定している場合、本来エラーが発生した箇所で スクリプト は終了します。 ただ、上記のケースでは command2 の結果に関わらず後続の処理が実行されてしまいます。 その為、代入と宣言の箇所を分けることが推奨されます。 4. Double quotes で変数を囲わない # bad file = " sample file.txt " ls $file DIR = " $( dirname $0) /.. " # good file = " sample file.txt " ls " $file " DIR = " $( dirname " $0 " ) /.. " double quotes を利用しないと該当の文字列中にスペースやタブ等を含むケースで、意図しない結果を招くことがあります。 例えば、上記のようにファイル名にスペースを含むケースだと、double quotes で該当の変数を囲わない場合スペースによって sample と file.txt という 2 つの単語に分割されてしまいます。 結果として、 sample file.txt というファイルではなく sample と file.txt を引数に ls コマンドが実行されてしまいます。 このような、意図しない挙動を避ける為、 シェルスクリプト では変数を double quotes で囲むことが推奨されます。 さて、ここまで シェルスクリプト の実装に潜む 4 つの罠について記載してきました。 シェルスクリプト を実装したことがある開発者にとっては、これらのどれもが一度は経験してきた問題なのではないでしょうか? これらの問題が一般的ではある一方で、全てをマニュアルで人間が気をつけることは難しく労力を要する作業かと思います。 ということで、 shellcheck というツールを利用することをお勧めします。 shellcheck とは? シェルスクリプト 用の静的 Lint ツールです。 こちらを利用することで、上記で説明してきたエラー(罠)を簡単に検知することが可能です。 コマンドを実行すると、下記の通り問題のある箇所を明瞭に指摘してくれます。 >>> shellcheck ./tmp.sh In ./tmp.sh line 1: set -eu ^-- SC2148 ( error ) : Tips depend on target shell and yours is unknown. Add a shebang or a ' shell ' directive. In ./tmp.sh line 5: echo ${baz} ^----^ SC2086 ( info ) : Double quote to prevent globbing and word splitting. Did you mean: echo " ${baz} " For more information: https://www.shellcheck.net/wiki/SC2148 -- Tips depend on target shell and y... https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ... さて、これだけでも記憶を頼りにマニュアルで全てを確認することに比べ、 簡便になったとは思います。 しかし、こちらのコマンドを修正の度に毎度手動実行することは非常に骨の折れる作業であり、非人間的です。 ということで、CI として設定して自動で実行しましょう。 今回はサンプルとして昨年の Advent Calendar 2020 の記事に記載した自作の OATHTOOL ラッパーコマンド に shellcheck を CI として追加してみます。 こちらのレポジトリは GitHub 上に存在するので、今回は GitHub Actions を用いて設定していきます。 設定ファイルは下記。 # .github/workflows/main.yml name : CI on : push : branches : [ main ] pull_request : branches : [ main ] jobs : shellcheck : name : Shellcheck runs-on : ubuntu-latest steps : - uses : actions/checkout@v2 - name : Run ShellCheck uses : ludeeus/action-shellcheck@master with : scandir : './bin' shellcheck は既に GitHub Action としてマーケットプレースに存在するので、設定自体は簡単です。 上記のように設定ファイルを 1 つ追加するだけで設定は完了です。 github.com 無事に CI として shellcheck が走るようになりました。 最後まで読んでいただきありがとうございました。 明日の記事の担当は検索エンジニアの伊藤 明大さんです。お楽しみに。 参考 What is the preferred Bash shebang? (最終アクセス: 2021/12/05) set man page (最終アクセス: 2021/12/05) koalaman/shellcheck (最終アクセス: 2021/12/05) 株式会社 エニグモ すべての求人一覧 hrmos.co
エンジニアの木村です。この記事は Enigmo Advent Calendar 2021 の 13日目の記事です。 いろいろやってますが、BUYチームという購入UXに関わる機能開発を担当するチームのマネージャーもやっています。11月末に行われる ブラックフライデー 、 サイバーマンデー といった大型キャンペーンに備えた開発もそのチームで担当したのですが、今日はそれに備えて行った負荷対策の1つの取り組みについてお話しします。 悔しい思いをした去年の ブラックフライデー 平素より BUYMA をご利用いただきまして、誠にありがとうございます。 本日0時頃より、サイトに繋がりづらい状況が続いており、現在復旧に向けて全力で対応を行っております。 ご不便をお掛けしてしまい大変申し訳ございませんが、何卒ご理解を賜りますようお願い申し上げます。 — BUYMA (バイマ)| 海外ファッション通販サイト (@ BUYMA ) November 26, 2020 これは昨年の ブラックフライデー 開始直後の BUYMA オフィシャルアカウントのツイートになります。。悲しいですね。下のリンクから当時の BUYMA の状況を表すタイムラインが見れますが、どういう状況だったか推察いただけると思います。 バイマ OR buyma until:2020-11-27_00:50:00_JST -filter:links -filter:replies - Twitter Search ユーザーのログイン状態管理が重い 原因の1つは、ユーザーのログイン状態の管理をサービスのメインDBで行っているところでした。スケールが難しい RDB です。最近はアクセス集中時にユーザーのログイン済み比率も増え、そのユーザーのアクセスでは毎リク エス トそのDBのテーブルへSELECTが走るのでメインDBが高負荷になり、メインDBなのであらゆる機能へ影響するためサイトとしては繋がりにくくなるという状況でした。もちろん、以前から問題視されていた仕組みではありましたが、ログイン状態の管理という重要な機能でもあり、原作者もおらず、別の仕組みへの移行の難易度が高くずっと放置してしまっていました。 したがって、DBのリソースをログイン管理のために温存する必要があるため、動的コンテンツ(HTMLや API )配信にも CDN を入れてキャッシュしたり、DB負荷が高い機能はアクセス集中が予測される時間帯には停止するようにスケジュールしたりなどいろんな手を尽くしていま。しかし、それでも ブラックフライデー だけは耐えることができませんでした。 セッションの保存を RDB からredisへ そこで、ログイン状態の保存先を RDB から、より読み取り レイテンシー が小さく、読み取りの集中にも耐久性のあるRedisへと移行するプロジェクトが始まりました。その移行の際に行った工夫が記事の本題となります。この工夫が、たまたま後日読んだこちらの本で紹介されている移行パターンそのものだったのでこちらの本の用語を使って説明していきます。 モノリスからマイクロサービスへ ―モノリスを進化させる実践移行ガイド 作者: Sam Newman オライリージャパン Amazon 利用パターン1:抽象化によるブランチ 現代のソフトウェア開発では1つのコードベースでブランチを切って複数人で並行して行うのは普通ですが、あまりブランチを切ってから長い時間が経つと差分が大きく、レビューやマージが大変になります。そこで、実装を改良しようとしている機能の抽象を作り、既存の実装と並行してその抽象の新しい実装を別に作り、さらにあとで切り替えるという方法が 抽象化によるブランチ と呼ばれる移行パターンです。大きな変更であっても、寿命の長いブランチを作らずに、他で並行して行われる開発と影響しにくいように開発が可能です。今回の事例で1ステップずつ手順を説明していきます。 今回は抽象というよりは ファサード となるクラスを前に立てて新実装へ切り替えているので、 モノリス 内での スト ラングラー パターン と言っても良いかもしれません。 ステップ0:変更前 変更前のアプリケーションはこのような構成でした。 ActiveRecord のモデルを介してDBのテーブルを呼び出すというオーソドックスな作りかと思います。 ステップ1: ファサード を作成し、既存のクライアントの向き先を変更 最初に行ったのは、実装の変更を呼び出し元へ影響するのを抑えるため、ログインステータスの操作を抽象化するために ファサード となるクラスを設けたことです。また、この ファサード を利用するように、順次呼び出し元の向け先もこの ファサード へ切り替えました。 ステップ2:並行して新しい実装を作成 従来の実装を稼働させつつ、新しい実装を横に作成します。実装のソースはデプロイされますが、この段階では事実上、従来の実装だけが動いたままです。 ステップ3: ファサード 内で新しい実装を使うように切り替え ファサード 内部を変更して、処理の流れを従来の実装から新しい実装へと切り替えます。この切り替えは後述する 同時実行パターン や カナリア リリース を使って段階的に行いました。 利用パターン2:同時実行 新旧の実装を切り替える時に、それぞれの実装で処理結果が変わらないことを担保する必要があるのですが、通常、デプロイ前にテストを頑張るという手段になると思います。ただ、テスト尽くしても本番環境で起こりうるシナリオは全て網羅することは困難です。特に、今回の変更はユーザーのログイン状態の管理になるので、不具合があると誤ってユーザーをログアウトさせてしまったり、あるいはBANしたユーザーを誤ってログインさせてしまったりなど重大な問題となってしまいます。 そこで、新実装を本番へ出してしまい、旧実装と同時に新実装も呼び出しつつ、旧実装の結果を呼び出し元へは返しておきながら、それぞれの実行結果を比較して新実装の結果が信頼できるか検証するという 同時実行 というパターンを利用しました。こちらの図のとおり、 ファサード 側でDB、Redisそれぞれの結果を処理が通るたびに比較検証し、差分があればログに出しておくようにしました。また、 ファサード の処理のタイミング以外でもバッチで定期的にそれぞれの内容をスキャンし、差分有無の検証も行いました。差分が出れば原因を調査し、原因を潰していくという作業を差分が出なくなるまで続けました。 カナリア リリースも利用 最初に同時実行モードに入る前に、気になったのはRedisの負荷でした。ほかの機能で導入実績はありましたし、負荷テストはしていたものの、やはり本番の トラフィック を一気に向けるのは勇気が要りました。そこで、徐々に10%ずつ新実装へ トラフィック を向けるように カナリア リリースを行いました。また、同時実行により十分に検証を行い、新しい実装へと切り替えるタイミングでも、予期しないユーザーへの影響の可能性を考え、そのタイミングでも10%ずつ新実装のみの結果を利用するようにしています。 カナリア リリースの仕組みは、 cookie ベースで トラフィック を振り分ける既存のABテストの仕組みを利用しています。 心穏やかに移行完了 以上の工夫によりあまりドキドキすることなく、心穏やかに移行を終えることができました。数ヶ月ほど時間はかかりましたが、抽象化ブランチの仕組みにより、切ってから長時間経った差分の大きいブランチをマージする必要も無かったですし、同時実行によりバグを十分出し切った上で、しかも カナリア リリースで少しずつリリースできたためです。時間がかかるというデメリットはあったものの、特に品質に気を遣う変更には有用かと思います。 負荷対策の効果 ついに迎えた ブラックフライデー 当日ですが、サイトのパフォーマンスを落とすことなく乗り切ることができました。こちらは、開始直後11/26の0時台の企画メンバーが集うslackのチャンネルの様子です。例年なら不安定になるはずのサイトがサクサク動いていて盛り上がっていました。 もちろん、今回紹介した移行以外にも負荷対策や様々なパフォーマンス改善策を重ねた結果なのですが、それらについてはまた別の機会に紹介しようと思います。
この記事は Enigmo Advent Calendar 2021 の12日目の記事です。 こんにちは。 BUYMA の検索やMLOps基盤周りを担当している竹田です。 この一年間はTerraformを業務で利用することが多かったため、普段気を付けていることなどを運用tipsとして紹介したいと思います。 Terraform Terraformは言わずと知れた Infrastructure as Code (IaC) を実現するためのツールです。 先日v1 🎉 になり、安定してきた印象があります。 Terraformに限った話ではありませんが、コード管理されている安心感は何ものにも変えがたいものがあります。 本記事はTerraform自体の説明は割愛し、ある程度利用したことのある方を対象としています。 個人の主観を多分に含んでいる、およびGoogleCloudに寄った内容のため他 クラウド ベンダーとは若干記述の毛色が違うといった可能性があります。あくまで参考程度としていただけると幸いです。 また、 terraform Advent Calender もあるようですので、より多くの情報を得たいという場合はそちらも参考にしていただくと良いかと思います。 定期的なバージョンアップ Terraformはv1化により安定してきたように思いますが、 クラウド ベンターのproviderは変化のサイクルが早く、新機能の追加やベータ版のGA化など定期的に追従した方が良いです。 気付かない内に有用な機能がリリースされており、無効の状態で運用を継続している可能性がある 新機能があった場合に気付きを得られる 項目の定義方法が変更になっている場合がある 設定理由を残す インフラ面のライフサイクルとして定義変更の頻度が少ないこともあり、いざ定義を変更しようとした際に設定理由を忘れていることが多々あります。 「この機能は何々の理由で有効・無効にした」といった内容を何かしら文章として残しておくことをお勧めします。 terraform apply の際にエラーとなってしまう場合がある 主に認証周りや、providerサイドで項目のvalidationがされていないものについて発生することがあります。 terraform plan した際には正常終了するものの、いざ terraform apply するとエラーになるというものです。 すでにコード管理上にcommitしていると二度手間になるため、開発環境やテスト可能な環境で terraform apply まで実施しておくことをお勧めします。 書き方のtips tfファイルの記法は若干クセがあるため、どの書き方が適切なのか、どう書くとやりたいことを実現できるのか分からない状況に遭遇することが稀にあります。 以下に一部例を挙げてみます。 変数参照 ハッシュ記述 value["preemptible"] なのかシンボル的記述 value.preemptible なのか迷います。大抵はどちらでも問題ありません。 ただし、混在すると見にくくなったり、記述箇所によっては意図があるように感じたりする場合があるため、統一感を持たせた方が良いように思います。 ↓こんな混在した書き方ができてしまう node_config { preemptible = each.value["preemptible"] machine_type = each.value.machine_type disk_type = each.value["disk_type"] oauth_scopes = each.value.oauth_scopes dynamicブロック 環境毎にリソース内の定義有無を設定できるため非常に便利なdynamicブロックですが、リソースによっては後で削除できないパターンが存在します。 例えば GoogleCloud のノードプールに設定可能なtaint定義などが該当します。taintの説明は こちら を参照ください。 なお、ここで例として挙げているtaintの変更は、変更の際にノードプール自体が作り直されてしまいますのでご注意ください。 taint定義を以下のようにdynamicブロック定義していたとします。 dynamic "taint" { for_each = contains(keys(local.gke_nodepools), "taints") ? local.gke_nodepools.taints : [] content { key = taint.value.key value = taint.value.value effect = taint.value.effect } } variables は以下のようになっており、 terraform apply により実環境にtaintが設定されていたとします。 locals { gke_nodepools = { taints = [ { key = "testkey" value = "testvalue" effect = "NO_SCHEDULE" } ] } あるタイミングでtaint定義が不要となり、削除したいと考えて variables の taints 項目自体を除去して terraform plan を実施します。すると No changes. Infrastructure is up-to-date. 削除差分が出ると思っていたのに差分が一切検出されませんでした 😢 これはdynamicブロック対象のオブジェクトを定義しない場合に、そもそも定義が存在しないものと解釈されて空の内容では更新してくれないためです。 こういった場合は、taint定義を以下のようにします。 taint = [ for item in local.gke_nodepools.taints : { key = item.key value = item.value effect = item.effect } ] 続いて、 variables を空に設定します。 locals { gke_nodepools = { taints = [] } このように定義することで、taint定義を空で更新することが可能となります。 以下は terraform plan 時の差分結果です。 ~ taint = [ # forces replacement - { - effect = "NO_SCHEDULE" - key = "testkey" - value = "testvalue" }, ] 最後に システム規模としては小〜中規模のため、規模面で困ったことは今のところありません。 大規模システムでは自動化などを考慮する必要がありそうなので、その辺りの悩みがない分は楽かもしれませんね。 今後はTerraform以外にもIaC関連のツールを利用するかもしれませんが、しっかり追従していきたいなと思います! 明日の記事担当はエンジニアマネージャーの木村さんです。お楽しみに! 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは、 エニグモ カスタマー マーケティング 事業本部で出品審査などを担当している杉山です。この記事は Enigmo Advent Calendar 2021 の10日目の記事です。 昨年の アドベントカレンダー では、 日頃の担当業務についてWantedlyで書きました が、今回は開発者ブログにお邪魔しました。 エンジニアではなくビジネスサイドの人間ですが、通常業務の傍らITツールを駆使して、ユーザー対応の現場の自動化や効率化などに取り組んでいます。 どうしても手元で作業が必要で、 エンジニアに開発してもらうほどではないんだけど、これが自動になったら楽なのに!とかもっと効率よく日々の業務をこなして価値の高い仕事に取り組みたいよー! と思う瞬間がありませんか?私はあります。もう毎日のようにあります。 もちろん大規模な運用改善やシステムの導入などはエンジニアと一緒に開発したほうが圧倒的にいいという案件も多々あるので見極めが必要ですが、ひとまず現場の人間が(ほぼ)ノーコードでいろいろできると、エンジニアのリソースが空くまでのその場を凌いだり、新しいことについて考えて取り組む余裕を作り出すことができます。今回はそんなお話の一つです。 餅は餅屋ですから専門家から見れば拙いやり方をしている面もあるかとは思いますが、そこは何卒多めに見ていただければ幸い。 NPSアンケートのチェック運用をツールの自動連携で効率化する 本日のテーマは、BigQueryのデータをデイリーでAirtableに自動連携して、 BUYMA のNPSアンケートチェック業務の効率化をした話を書きたいと思います。 NPS(ネットプロモータースコア) とは、EC事業者にとっては定番ですが、取引が完了したお客様に任意で答えていただいている、 BUYMA の顧客のロイヤリティを計測するためのアンケート調査です。 NPSの回答には、 BUYMA や出品者様のお取引についての貴重なご意見が詰まっています。 エニグモ ではNPS専用のプロジェクトチームを部門横断で結成し、回答を全てチェック、 アクティブサポート や今後の開発・施策の検討に活用させていただいています。 これまでのNPSチェック運用と課題 NPSプロジェクトでは、毎日いただく数百のアンケートすべてに目を通し、気になるものをピックアップして定期 MTG で今後の対応を議論しています。チェック作業は曜日ごとにプロジェクトメンバーで分担して行っているのですが、それがなかなか手間のかかる作業となっており、また、チェック対応結果の活用という点でも課題が多くありました。 いままでのやり方 Gmail にデイリーで送られる回答データを確認し、 Gmail 上に対応ログを残す Gmail で送られるNPSアンケートのサマリ例 課題 チェックに時間がかかりすぎる データに直接チェック結果を書き込むことができないので、気になったポイントなどをメモする場合 コピペしてドキュメントを整形する作業を毎回する必要 がある ピックアップの MTG で決まった対応について、 進捗管理 がしづらい 議論のログがメールにしかないため、 対応担当者が手元で別途タスクリストを作ったり情報をメモしておかないといけない アンケートに答えていただいた方へご連絡する際に、メールリストの作成をするだけで一苦労 手動で再度データを抽出し対応の一覧を Excel で作成、そこからメール送信対象者をチェックして SQL でメールアドレスリストを抽出……と 複雑な手順が必要 だった どのアンケートについてどういった議論が起こり、どんな対応を行ったのか、あとから振り返る手段が限られている Gmail の履歴から検索してひとつひとつ中身を見るしかないため、 一覧性が低い どんなご意見がどのくらいの件数来ているのかなどを 定量 的に把握することができない ……といった具合に、NPSアンケートを導入した初期から続く古の運用のため、やりづらいポイントが多数ある状態でした。 チェック運用のツールを Gmail →Airtableに移行し効率化 そこで、以下の2点について解決すべく、運用改善を行いました。 アンケートのチェック作業の手間を減らす 今後の対応のために過去のデータを参照しやすくする 購入者様がアンケートに回答→メンバーが内容チェック→対応内容を決定しタスクリストを作成→ 進捗管理 →回答者様へのご連絡→過去のピックアップ内容の振り返り 、という一連の業務の流れを整理し直して、最小限の手数で作業が完了できるようにします。そのために、チェック作業のツールを Gmail からデータベースサービスAirtableに移行することにしました。 Airtableは、一言で言うときれいで賢い スプレッドシート です。 表形式のデータを直感的に、かつ自由度高く扱うことができる ため、多数のデータをチェックして分類したり、追加の情報を手動でメモして管理したり、ということが Google Spreadsheet や Excel 以上に簡単に見栄え良くできます。 今回はBigQueryから抽出したNPSアンケートのデータを自動でAirtableに同期し、そこでピックアップ運用を全て完結させるようにしました。やることは単にデータの自動同期なのですが、使用ツールが変わるとチェック作業は劇的にやりやすくなります。 ※ 今回の記事ではAirtableの細かい使い方については割愛しますが、使いこなせれば本当に便利すぎるサービスなので、おすすめです! ▼参考記事 脱 Excel ・ スプレッドシート !WebプロジェクトのためのAirtable活用術 loftwork.com 使用ツールと自動化の流れ 今回の自動化の流れと使用したツールは以下になります。 Google BigQuery NPSアンケートの回答データが溜まっているDB Google App Script(GAS) BigQueryから毎日自動でデータ抽出し スプレッドシート に転記するプログラムを作成 Google Spreadsheet GASで抽出したデータを一時的に溜め、Zapierのトリガーにするために使用 Zapier 複数の Webサービス を組み合わせて独自の自動ワークフローを作成できるタスク自動化ツール。Spreadsheetに同期したデータをトリガーにして、Airtableに自動転記する設定を作成 zapier.com Aitable 自動同期したデータの目視チェック、対応ログの記録などを行う airtable.com GASでBigQueryからデータ抽出してシートに記入 GASを使ってBigQuery上で SQL を動かし、 スプレッドシート にデータを転記するまでのコードは以下のような感じです。これは社内の他のGASやググった内容を参考にあれやこれやしてなんとか作りました。GAS、もう数年間書いては忘れを繰り返しているのですが、今回の対応でやっと結構定着した気がします……。 GASは深夜の3時に毎日起動し前日分を取得するようトリガー設定をしています。 //BigQuery var projectNumber = 'データ抽出元の任意のプロジェクトNo' ; //スプレッドシート var ss = SpreadsheetApp.getActiveSpreadsheet(); //SQLの結果を出力するシート var sheetNPS = ss.getSheetByName( '任意のシート名' ); function check() { //処理開始メッセージ Browser.msgBox( "処理をしています。しばらくお待ちください。" ) //SQL結果書き出しシートのクリア sheetNPS.getRange(2, 1,sheetNPS.getLastRow(),sheetNPS.getLastColumn()).clearContent(); // SQLを生成 var sql = "任意のクエリ" ; Logger.log(sql); // SQLを実行する準備 var query_results; var resource = { query : sql, timeoutMs: 1000000, // Standard SQLを使用する場合はLegacySqlの使用をfalseにする useLegacySql: false } ; try { // SQLを実行 query_results = BigQuery.Jobs.query(resource,projectNumber); } // エラーが発生したらログ出力、メッセージ出力して終了 catch (err) { Logger.log(err); Browser.msgBox(err); return ; } while (query_results.getJobComplete() == false ) { try { query_results = BigQuery.Jobs.getQueryResults(projectNumber,query_Results.getJobReference().getJobId()); if (query_results.getJobComplete() == false ) { Utilities.sleep(3000); //以下の謎のエラーがでたら、この値を増やすか、timeoutMsの値を増やす。「ReferenceError: 「query_Results」が定義されていません。」 } } catch (err) { Logger.log(err); Browser.msgBox(err); return ; } } Logger.log(query_results); var resultCount = query_results.getTotalRows(); var resultValues = new Array (resultCount); var tableRows = query_results.getRows(); // 抽出結果を配列(resultValues)に格納 for ( var i = 0; i < tableRows.length; i++) { var cols = tableRows [ i ] .getF(); resultValues [ i ] = new Array (cols.length); for ( var j = 0; j < cols.length; j++) { resultValues [ i ][ j ] = cols [ j ] .getV(); } } // 配列(resultValues)の内容をシートに出力 sheetNPS.getRange(2,1,resultCount,tableRows [ 0 ] .getF().length).setValues(resultValues); Browser.msgBox( "完了したよ!" ) //完了メッセージ Zapierの設定 次に、 スプレッドシート のデータ更新をトリガとしてAirtableにデータを転記するZapierを設定します。 当初はGASでそのままAirtableに転記することを想定して作り始めたのですが、Airtableの API Documentをよくよく見ると、 一度に API で追加できるレコードは10まで、という制限 があり、数百行を一気に追加したかったため間にZapを挟むことにしました。 トリガに スプレッドシート のレコードの追加もしくはアップデートを指定 先ほど作ったGASのシートを指定 1行1トリガとして先ほど抽出したデータがテストに出てきます これでトリガー設定は完了です。 次に、Airtableに転記をするための設定をします。 APPにAirtableを選択しアカウントを連携 Create Recordを選択 あらかじめ作成したAirtable上のカラムと スプレッドシート のデータの対応を設定 テストで入力内容を確認し、問題がなければZapをONにする データを同期したAirtableシート これで、毎日前日分のデータをAirtableに自動同期することができます!! Zapierのトリガ数の上限を解除する と、うまくいったかと思いきや、運用開始してみたら問題が発生。 Zapierは動作したトリガ数に応じて課金されていく仕組みなので、 誤作動防止のために一度に動くトリガが100件を超えると自動でストップする仕様 になっていました。今回作ったZapは毎日数百件ある更新データをひとつひとつトリガとしてZapを動かす設定のため、動かすたびに毎回Zapが止まってしまいました。一時停止したZapはボタンひとつで再開作業をすれば問題なく動くのですが、毎朝対応が必要になるのでこれでは自動化の良さが半減してしまいます。 最初は解決方法がわからず、毎日再開をするひと手間をしばらく続けていたのですが、やっぱりめんどくさい!! Zapierに問い合わせてみると、トリガ上限を上げてもらえることが判明 。リミットを500に設定してもらい、無事に完全自動化することに成功しました。 よく調べると トラブルシューティング にも該当の内容がありました。サポートはすべて英語なので該当箇所を見つけるのも一苦労ですね……。 zapier.com 新・チェック運用 毎日のデータをAirtableに連携することで、フィルター機能で自由に表示を操作することができるようになったので、アンケートのチェック運用もAirtable上でスムーズに行えるようになりました。 まずは、曜日ごとに分担してチェックをしているため、回答を担当曜日ごとに表示できるようそれぞれのViewを作成。 曜日ごとの表示例 担当曜日の回答に目を通して 気になるものにはチェックマークをつけていき、コメント欄にメモを記入するだけでピックアップは終了 です。 MTG ではチェックがついたものについて確認して議論し、決まった対応内容を購入者様・出品者様それぞれの該当欄に記入して対応の進捗や担当者もここで管理します。 対応タスクの一覧View 更に、回答いただいたお客様へのご連絡のためのリストもAirtable上のViewで管理できるため、改めてデータ出しをする作業もなくなりました。 メール配信のためのリスト 運用変更の結果、実現したこと 今回のツールの変更と自動化で、課題だった以下の点について解決し、かなりの効率化を実現することができました。 MTG 前のピックアップのための所要時間が削減でき、 1日分のチェックに以前は1時間前後かかっていたものを30分程度でできるように なった MTG 中にチェックしたものがそのまま対応のタスクリストになるため、進捗が管理しやすくなり 対応時間の削減と対応漏れの防止 ができた 過去に出てきた類似案件の対応見直しや、特定の出品者様・購入者様に過去どういったご意見が多いかを MTG 中にさっと参照することができるようになったため、以前よりも 的確なフォローが可能に なった 回答者様への一斉連絡のためのメールリスト抽出が自動で完了できるようになり、 手動でリストを作成する手間がなくなった 今後の展望 今回の一番の目的だった業務の効率化は十分に達成することができた一方で、データ活用という観点ではまだまだやれることがあると考えています。 現在は個別のアンケートへの対応のみに活用されていますが、ピックアップしたデータを再度データベース内の他の情報と組み合わせてより高度な分析の材料としたり、特定の回答内容の方にのみMDツールと連携して自動でご案内をしたり、などデータが整ったことで活用の幅を広げることができるはず。貴重なお客様の声をサービス改善に繋げるべく、今後も試行錯誤を続けていきたいと思います。 明日の記事の担当は人事総務グループの右川さんです。お楽しみに! 株式会社 エニグモ すべての求人一覧 hrmos.co
はじめに こんにちは、インフラエンジニアの 高山 です。 この記事は Enigmo Advent Calendar 2021 の 9 日目の記事です。 現在、 BUYMA をオンプレから AWS へ移行するプロジェクトを進めています。 テスト環境の移行は完了し、本番環境の移行をしようというところです。 本番環境の移行をする前に 性能的に問題ないことを確認するため、本番環境と同程度のスペックで検証環境を構築し負荷テストを実施しました。 まだ終わっていませんが、今の時点で得た知見を記事にしようと思います。 負荷テストツール選定 詳細は割愛しますが、 以下のような要件から AWS の分散負荷テストのソリューション(正式名称は Distributed Load Testing on AWS 以下、 AWS 負荷テストソリューションと呼ぶ)を使うこととしました。 大規模な負荷テストができること 複雑なテストシナリオが作成できること 情報が多いこと 学習コストや構築運用コストが低いこと 費用が安価であること テストシナリオをコードで管理できること AWS 負荷テストソリューションは それ自体の情報は多くないものの JMeter の設定ファイルを読み込むことができるためテストシナリオ作成の情報は多く、 テストシナリオをコードで管理できること 以外は要件を満たしています。 ( ruby-jmeter を使えばコード管理できそうですが、手は出しませんでした。) AWS 負荷テストソリューションの概要 AWS 負荷テストソリューションは AWS のマネージドサービスを組み合わせた AWS のソリューションの1つで、 AWS が提供しているCloudFormationのテンプレートからスタックを作成すれば、簡単に作成することができます。 導入の説明などは割愛します。 以下を参考にしてください。 参考 AWS ソリューション AWS ソリューションのライブラリ AWS 分散負荷テスト ソリューション ここにCloudFormationのテンプレートが置いてあります 大規模な負荷テストを実行可能。「Distributed Load Testing on AWS」 を試してみる AWS 公式のやってみた記事 日本語のドキュメント 日本語のドキュメント 例によって、ちょっと古い 英語のドキュメント 英語のドキュメント こちらは最新 テストシナリオ作成 性能的に問題ないことを確認するためには 本番環境と同等の負荷をかける必要があります。 本番環境でのアクセスが多い機能と ログイン/未ログインの割合を調べ、それをテストシナリオにしました。 本番環境の確認 ログイン割合 未ログイン状態: 8 ログイン状態: 2 ログインページへのアクセスは300アクセスに1回程度 アクセスの多い機能の割合 Web検索: 70 Web商品詳細: 90 API 検索: 35 API 商品詳細: 35 作成したテストシナリオ 本番環境の確認結果より、1/5の確率でログインするようにしつつ アクセスが多い機能を任意の割合でアクセスするようなテストシナリオを作成しました。 作成したテストシナリオ JMeter の詳細な設定方法などは割愛しますが、ポイントは以下になります。 割合を近似してできるだけ小さい数にした インタリーブコントローラでログインの割合をコン トロール するようにした 会員IDリストの csv ファイルを用意してランダムにユーザを変えてログインするようにした (事前に同じパスワードでログインできるように仕込んでおきました) アクセスの割合で特に多い機能のHTTPリク エス ト サンプラー を割合の数だけ作成 さらにそれを5回ループし、ログインを300アクセスに1回程度になるようにした 同じ機能でも、HTTPリク エス ト サンプラー ごとに URLリストファイルを分割して別々の csv ファイルを参照するようにした (同じ csv ファイルを使うと、同一スレッドの同じ回で同じURLになってしまったため) AWS 負荷テストソリューションに JMeter の設定ファイルを読み込ませる ファイルアップロード 作成したテストシナリオで外部ファイル( csv ファイルや プラグイン ファイル)を読んでいる場合は、zipにまとめてからアップロードします。 ポイント 外部ファイルは 相対パス で指定すること テストシナリオの拡張子は jmx として、複数の jmx ファイルは含めないこと ファイルサイズ上限は50MB AWS 負荷テストソリューションのイメージと スクリプト 使用されているコンテナのイメージと実行される スクリプト を確認してみましょう。 Dockerfile を見ると、コンテナイメージはtaurusを元にしています。 ENTRYPOINTに指定されている スクリプト の中でアップロードしたファイルを読み込んでいる箇所を見てみます。 # download JMeter jmx file if [ "$TEST_TYPE" != "simple" ]; then # Copy *.jar to JMeter library path. See the Taurus JMeter path: https://gettaurus.org/docs/JMeter/ JMETER_LIB_PATH=`find ~/.bzt/jmeter-taurus -type d -name "lib"` echo "cp $PWD/*.jar $JMETER_LIB_PATH" cp $PWD/*.jar $JMETER_LIB_PATH if [ "$FILE_TYPE" != "zip" ]; then aws s3 cp s3://$S3_BUCKET/public/test-scenarios/$TEST_TYPE/$TEST_ID.jmx ./ else aws s3 cp s3://$S3_BUCKET/public/test-scenarios/$TEST_TYPE/$TEST_ID.zip ./ unzip $TEST_ID.zip # only looks for the first jmx file. JMETER_SCRIPT=`find . -name "*.jmx" | head -n 1` if [ -z "$JMETER_SCRIPT" ]; then echo "There is no JMeter script in the zip file." exit 1 fi sed -i -e "s|$TEST_ID.jmx|$JMETER_SCRIPT|g" test.json fi fi スクリプト から以下のことが わかりました。 jmx ファイルをfindで探しているようなので、zip内の jmx ファイルのパスは気にしなくても良さそうですが、含める jmx ファイルは1つだけにする必要がある プラグイン 用のjarファイルを JMETER _LIB_PATH配下へコピーしていますが、zipを解凍する前に コピーしているので プラグイン は追加できない模様 (今回のテストシナリオで使用した追加 プラグイン は Random CSV Data Set Config のみなのですが、zipに含めなくても使えました 謎です) $ docker run -it --rm --entrypoint "bash" public.ecr.aws/aws-solutions/distributed-load-testing-on-aws-load-tester:v2.0.0 root@1328dc7cdfdd:/bzt-configs# ls -l total 1296 -rwxr-xr-x 1 root root 1210 Sep 30 04:16 ecscontroller.py -rwxr-xr-x 1 root root 1360 Sep 30 04:16 ecslistener.py -rw-r--r-- 1 root root 16542 Sep 30 04:19 jetty-alpn-client-9.4.34.v20201102.jar -rw-r--r-- 1 root root 19600 Sep 30 04:19 jetty-alpn-openjdk8-client-9.4.34.v20201102.jar -rw-r--r-- 1 root root 320564 Sep 30 04:19 jetty-client-9.4.34.v20201102.jar -rw-r--r-- 1 root root 214251 Sep 30 04:19 jetty-http-9.4.34.v20201102.jar -rw-r--r-- 1 root root 164646 Sep 30 04:19 jetty-io-9.4.34.v20201102.jar -rw-r--r-- 1 root root 565135 Sep 30 04:19 jetty-util-9.4.34.v20201102.jar -rwxr-xr-x 1 root root 2998 Sep 30 04:16 load-test.sh root@1328dc7cdfdd:/bzt-configs# find ~/.bzt/jmeter-taurus -type d -name "lib" /root/.bzt/jmeter-taurus/5.2.1/lib root@1328dc7cdfdd:/bzt-configs# find /root/.bzt/jmeter-taurus/5.2.1/lib -type f -name "*jar" -ls | wc -l 109 root@1328dc7cdfdd:/bzt-configs# find /root/.bzt/jmeter-taurus/5.2.1/lib -type f -name "*jar" -ls | egrep -i "csv" root@1328dc7cdfdd:/bzt-configs# 参考 ECR Public Gallery - AWS Solutions/distributed-load-testing-on-aws-load-tester:v2.0.0 GitHub - aws-solutions/distributed-load-testing-on-aws 分析のための準備 Datadog ダッシュ ボード AWS 負荷テストソリューションのテスト結果レポートを見ても詳細な分析はできないので、詳細な分析をするためには監視ツールで必要なデータを取る必要があります。 今回はDatadogを使い、以下のようなデータを確認できるように ダッシュ ボードを作成しました。( APM も使っています) 各機能(DBやアプリサーバ、検索サーバ、キャッシュサーバ等)の負荷 アプリやLBのbusy/idle worker キャッシュサイズ、キャッシュヒット率、eviction etc 目標値 本番環境のある日の スループット /分 負荷テストした結果を分析できても、どの程度の値であればOKと判断できなければ意味がありません。 本番環境の スループット やページごとのレイテンシを調べておき、目標となる値を調査しました。 移行により性能を向上させるというよりは 現状より性能が低下せず移行できることを目標にしているため、 今回は現在の本番環境の スループット やページごとのレイテンシが そのまま目標値となります。 本番環境の全LBサーバのログを合計したところ、ピークタイムの スループット は5万アクセス程度/分でした。 ( CDN を利用しているので、オリジンのアクセスのみの計測値です) 負荷テストの流れ 以下のような流れを繰り返し、問題を解決しながら 負荷テストを進めていきました。 同時接続数を少ない数から始め、各サーバの負荷やbusy/idle worker数、 スループット を見ながら上げていく workerが枯渇する前に 各機能の負荷やレイテンシが上昇してしまう場合は、その原因を調査して解消 (設定のミスや構成的な問題、単純なスペック不足など 低レイヤーから高レイヤーまで様々な問題がでてきました) 問題が解消しworkerが枯渇した状態でも、目標となる スループット に達しない場合は アプリサーバの台数を増設 (アプリサーバの台数を増やすと、また別の場所が ボトルネック になる場合があるため、徐々に台数を増やします) 目標となる スループット に達しても、各機能の負荷やレイテンシが高くなっていなければOK AWS 負荷テストソリューションの設定値 設定項目 Concurrencyは どのように設定すれば良いのか? Task Count : <タスク数(コンテナ数)> Concurrency : <タスク毎の同時接続数(ユーザー数)> 合計の同時接続数(合計ユーザー数)は Task Count x Concurrency になります。 Task Count=1で Concurrency を増やせば安上がりなのですが、負荷をかける側にも負荷がかかるので そうはいきません。 Concurrency の推奨制限は200になっていますが、ECRの負荷を見ながら調節する必要があります。 これは ドキュメント の ユーザー数の決定 の項目が詳しかったので、ドキュメントを参照してください。 Ramp Upって必要? Ramp Up は負荷テスト開始時の暖気運転のためだと思っていて、ずっと0に設定して負荷テストしていたのですが 暖気運転以外でも Ramp Up を設定した方が良いケースに遭遇しました。 Ramp Upの設定で解消した定期的な負荷上昇 BUYMA では アプリケーションサーバ として PHP と Ruby on Rails を使用しています。 PHP で処理している機能は少ないのですが、ログイン処理は PHP を使用しています。 ログイン処理は300アクセスに1回程度ですが、 Ramp Up を設定しないと負荷テストのすべてのスレッドが同じタイミングでログイン処理をしようとするため、定期的に負荷が上がるような不可解なグラフになったと考えられます。 (時間経過とともにスレッドごとのタイミングがずれていくため、徐々に解消されていきます) Ramp Up を設定したところ、定期的な負荷上昇はなくなりました。 どれくらいの時間、負荷テストするべきか?(Hold for) 長時間負荷テスト あたりまえですが、テストをする環境や どんな負荷テストをしたいかにより、どれくらいの時間 負荷をかけるべきか変わってきます。 例えば 徐々にキャッシュがたまり、キャッシュヒット率が上がるにつれてDBへの問い合わせが減っていく様子を確認するため 長時間の負荷テストを実施しました(上記のグラフです)。 キャッシュされた状態でのテストをしたい場合はURLリストを少なくして負荷テストしました。 何をテストしたいかによって 設定を変更したり、負荷テストの時間を調節する必要があります。 AWS 負荷テストソリューションの問題 Failed to parse the results. Test Failed 長時間負荷テストを実施したり、何回もテストを作成すると AWS 負荷テストソリューションのテスト結果レポートが表示されず、 Failed to parse the results. になることがあります。 その場合は 負荷テストはできいて、レポート作成処理に失敗しているだけのようです。 ERROR finalResults function error ValidationException: Item size to update has exceeded the maximum allowed size CloudWatch Logsで確認したところ 原因はDynamoDBの制限超過エラーのようなのですが、サポートへ問い合わせたところ 仕様だそうです。 分析は主にDatadogを使用しているため、あまり支障はありませんでした。 ダッシュ ボードからテストシナリオが消えていく test-400,test-700,test-800が消えた ダッシュ ボード 何個もテストケースを作成して負荷テストしていくとなぜか、 ダッシュ ボードからテストシナリオが消えていくことがあります。 テストシナリオの数ではなく、テストの回数か何かに制限があるようです。 消えたテストシナリオでもタブが残っていれば/URLを覚えていれば、設定が残っていて、テスト実行も可能でした。 こちらはそんなに困らなかったので、サポートへ問い合わせはしていません。 サポートに項目がない サポート その1 サポート その2 明らかにDynamoDBの問題の場合はサポートに問い合わせできたのですが、 AWS 負荷テストソリューション自体の問題の場合は サポートのサービスに項目がありませんでした。 AWS 負荷テストソリューション自体の問題は SAの方に聞いてみましょう。 AWS 負荷テストソリューションの API 30分おきに Task Count を変更して負荷をかけていて API あったらいいなと思っていたのですが、 今回 ドキュメント を見返していたら、 API ありました。 見逃してました。 設定を変えてながら連続して負荷テストするような場合は API を使いましょう。 最後に 今回は大きなサービスの移行のための負荷テストで、テスト環境では発生しなかった問題が次々と発生するなど いろいろと大変でした。 負荷テストツールにはあまりコストをかけたくなかったので、 AWS 負荷テストソリューションを使うことで だいぶ ラク ができたと思います。 これから、バッチサーバなどが動いてDBに負荷をかけている状態でも 性能的に問題ないかなどを確認し、自信を持って本番環境の移行に臨めるようにしていこうと思っています。 明日の記事の担当は カスタマー マーケティング 事業本部の 杉山 さんです。お楽しみに。 株式会社 エニグモ 正社員の求人一覧 hrmos.co
はじめに こんにちは、サーバーサイドエンジニアの @hokita です。 この記事は Enigmo Advent Calendar 2021 の 8 日目の記事です。 今回はテッ クリード 兼 スクラム マスターとして約8ヶ月間プロジェクトを運用していく中で学んだことを8つ紹介したいと思います。 学び 1. ストーリーポイントと難易度 例えば2ポイントのストーリーがあり、経験の長いAさんは2日、初心者のBさんは4日かかるとします。では作業量が倍と見積もった4ポイントのストーリーはどうでしょうか。Aさんは倍の4日でできたのですが、Bさんは始めての作業だったので3倍の12日かかってしまいました。このようにスキルや難易度によってポイントと 工数 が単純な比例関係にならないことがよくあります。そのため、メンバーのスキルを認知しつつ、どのような策をとるべきか考える必要がありました。 納期が迫っているなら、Bさんが苦手なタスクをAさんにやってもらう スケジュールに余裕があるなら、Bさんに苦手なタスクをやってもらいながら スキルアップ を目指す Aさんに余力があるなら、Bさんを手伝ってもらう( ペアプロ を実施するなど) それぞれメリット・デメリットあるので、その時々で判断する必要があるかと思います。 2. フル稼働ではなく1名助人役になる プロジェクト開始時は私を含めた2名で開発していました。そのときのベロシティは約7ポイントで、途中で人員を増やし4名になってからは約14ポイント消化できるようになりました。人数が倍になったからベロシティも倍になったと思うかもしれませんが、そうではなく、私はあまり開発をせずに助人役に回っていました。実際には下記のようなことを行っていました。 進捗が著しいタスクを発見して対策を考える ストーリー着手前に一緒に設計を考える コードレビュー 手が空いたときには小さめのストーリーを消化 私が開発に集中することもあったのですが、進捗は逆に低下することが多かったです。開発中に発生する問題は思った以上に 工数 を膨らませます。それを解消する役がいることで安定した開発スピードを出すことができると気づきました。 3. レビューファースト スクラム 開発ではスプリント内で成果物を残し、 ステークホルダー へデモを見せフィードバックを貰うことが重要です。よくあったのが、一人で同時に複数ストーリーを進めて、結局どのストーリーもスプリント内に終わらせることができなかった、というものです。なぜそのようなことが発生するかというと、レビューを返すまでに時間がかかっていることが原因でした。レビュー依頼を出した開発者はレビューが返ってくるまでは他のストーリーに着手するかと思います。そうしているうちに複数ストーリーの マルチタスク となって、結局どのストーリーも消化できずじまいとなってしまいます。レビューはなるべく早く返して、1つのストーリーを確実に終わらせることが大事です。 4. ベロシティがプレッシャーに 良くなかったなと反省しているのですが、1on1の時に各開発メンバーに「次のスプリントでは○ポイントの消化を目指しましょう」とストーリーポイント基準で目標を設置していました。数値目標で管理しやすいと思っていたのですが結果どうなったかと言うと、コードの品質が下がり、時には仕様を満たないプルリクがくることもありました。個人のコーディングスピードはいきなり上がるものではないので、時間を省くとなれば デバッグ 時間となっていたのだと思います。それに気づいた後は、まずは安定したアウトプットができること、そして、ポイントはあくまで目安に過ぎないことを意識し、目標は消化ポイントとは別のものに変更しました。 5. レトロスペクティブが自己評価になりがち レトロスペクティブではメンバーそれぞれが KPT 法で書いていました。そこでよく上がってくるものは「〇〇の実装で時間がかかってしまった。なので、〇〇を勉強する」のような自己評価が多かったです。個人の能力を伸ばすことも重要ですが、どちらかというとチームとしてなにができるのかを議論することのほうが重要だと思っています。「〇〇で時間がかかった。」のは相談する機会がなかったのが原因なら「朝会で相談する(相談しやすくする)」やスキルが足りない場合は「詳しい人と ペアプロ の時間を設ける」というのが良い振り返りかと思います。これは開発している本人だと気づけないことが多いので、他の人が提案してあげることが望ましいです。 6. スプリント内で終わらないストーリーは放置しない 前述したとおりスプリント内で成果物を残すことは重要なことですが、どうしてもストーリーを消化できないことは多々発生します。ストーリーの粒度を小さくすることは心がけていたもののどうしてもそうはならないストーリーもありました。ほとんどの場合次の週にも継続して開発するのですが、なぜ終わらなかったのかを調査し対策することが大切です。例えば一人で行き詰まって終わらなかったのなら、次週は ペアプロ でそのタスクを最優先で終わらせる、もし思っていた以上に作ることがあった(例えばAという機能を追加するのに実はBという機能を作る必要があったなど)なら、まずストーリーを分解することはできないか、他のメンバーと役割分担はできないか、今のまま続けるとしたらどのくらいかかりそうか、など念入りに調査し対策を考えます。これを怠ると何スプリントにもまたがるストーリーになる可能性があり、開発者のメンタルを下げ、負のスパイラルに陥ることが多い印象です。 7. 早くリリースしたいなら機能を削る まず下記を スクラム チーム全員で認識を合わせる必要があるかと思います。 開発スピードが劇的に向上しないこと 最初に作成した仕様の大半は不要な機能であること それを前提に納期へ向けてできることといえば「機能を減らす」もしくは「納期を伸ばす」しか手段はないかと思います。今回のプロジェクトも バックログ を全て消化するにはベロシティなどの数値から計算して目標納期に間に合わせるのは「不可能」でした。やったことと言えば、優先度の低い機能をごっそりと削ることでした。リリース後にその削った機能を開発したかというとほとんどの機能は「不必要」でした。 8. 興味を引くスプリントレビューを 本プロジェクトはバックエンドのメンバーが多かったので、デザインは後回しにして簡素なページを作成していき、デモでは毎週動くものを提供していたのですが、 ステークホルダー からのフィードバックが薄いことに気付きました。その後デザインが当たった段階でやっといろいろな意見をいただけるようになりました。動けば良いというものではなく、もしデザインファーストなプロトタイプを作っていればもっと早い段階で多くのフィードバックを貰えたかと思われます。機能や ステークホルダー のよりけりだと思いますが、興味を引くようなプロトタイプを作ることも重要だと気づきました。 最後に いかがだったでしょうか。まだまだ未熟ですが、今回の学びを次回のプロジェクトへ生かしていこうと思います。 明日の記事の担当は インフラエンジニア の 高山 さんです。お楽しみに。 株式会社 エニグモ 正社員の求人一覧 hrmos.co
こんにちは、 エニグモ でデータアナリストをしている井原です。 この記事は Enigmo Advent Calendar 2021 の 7日目の記事です。 今日は、実際に業務で、データ分析をした内容を元に、データアナリストがどのような仕事をしているのかをお話したいと思います。 データアナリストの仕事 世の中では、データアナリストと言われる職種の仕事は多岐に渡ると思います。 データマイニング 、データ分析基盤の整備、ビジュアライゼーション、KPIの設計、 機械学習 モデルの構築、etc... エンジニアリングやサイエンスの領域と思われるところを担っているデータアナリストの方もいらっしゃるのではないかと思います。 エニグモ の場合、データサイエンティストやデータ基盤エンジニアといった、専門家が在籍しています。そのため、データアナリストは、施策の効果検証やサイト上の課題発見といった、ビジネス領域の課題に対して、データ分析で解を出す仕事にフォーカスすることが多いです。 また、 エニグモ は、データ分析の リテラシー が高く、データアナリストではないディレクターといった職種の人でも、 SQL を回して、データの抽出/分析を行うことが普通の文化になっています。 データアナリストとしては、データ分析の設計や手法を深く理解して、アウトプットを出していくことのやりがいを感じながら、仕事の出来る環境になっていると思います。 決定木による売れ筋商品の分析 ここからは、実際に分析した例を元にして、分析手法として使用した決定木分析について、お話したいと思います。 課題 エニグモ が運営している BUYMA では、CtoCの売買を仲介するプラットフォームビジネスを行っています。 そのため、 ECサイト として、購入者だけではなく、販売を行う出品者に対してのフォローも行うことが必要です。出品者の方に良質な商品を出品していただくことで、売り場としての魅力が向上し、購入者にとっても、良質なサイトになっていくと考えられます。 しかし、良質な商品とは何なのか?想像するものは、人それぞれで異なると思います。そこを、定性的な感覚だけでなく、 定量 的なデータ分析を行うことで、売り場にあるべき商品を定義し、出品者の方に出品促進を行っていきたい、というのが、今回の課題でした。 分析方法の選定 良質さを決める要素は数多くあると思いますが、今回はまず、基礎的な分析として、商品のブランド、カテゴリ、モデル名の中で、どのような商品が売れているのかを調査しました。また、売れている商品、の定義については、ビジネス側のメンバーと議論のうえ、CVR(出品された商品数のうち、販売された商品数の割合)としました。 早速、日別のデータを取得し、 BUYMA の中で主流となるジャケットカテゴリに絞ると、以下のようなデータが確認できます。 ※なお、記事内で取り扱っているデータについては、全て、ダミーデータとなります。 BUYMA で取り扱われているブランド、カテゴリ、モデル名は、数が多く、クロス集計などで解釈することは困難と思われます。 ブランド、カテゴリ、モデル名をそれぞれ単体で集計することも可能ですが、その場合、あるブランドのCVRが高いと、どのようなカテゴリ、モデルでも高いのか?といった解釈が難しくなります。 今回は、CVRに対して、ブランド、カテゴリ、モデル名といった特徴のうち、どの要素の影響が大きいのか?を分析したいですので、可視性が高く、解釈性のよい決定木分析を使って、分析してみることにしました。影響の大きさを見るには、重回帰分析といった手法もありますが、決定木分析であれば、要素の掛け算(このブランドのこのモデルのCVRが高い、といった見方)も確認できます。 ※厳密には、重回帰分析でも要素の掛け算を変数とすることで、出来ないことはありませんが。 実装 python を使って、実装していきます。 先ほど取得してきたデータのうち、ブランド、カテゴリ、モデル名、を説明変数とし、CVRを目的変数として予測する決定木モデルを作成します。 環境: Windows 10 Pro Python 3.9.9 1.ライブラリのimport 必要なライブラリをインポートします。 import pandas as pd import subprocess # 可視化を行うためのライブラリ import matplotlib.pyplot as plt # 回帰の決定木モデルを作成するためのライブラリ from sklearn.tree import DecisionTreeRegressor, export_graphviz from sklearn.model_selection import train_test_split from sklearn.metrics import r2_score from sklearn.metrics import mean_absolute_error 2.データの読み込み pandasでデータを読み込みます。 df = pd.read_excel( "cvr_data.xlsx" )[[ "date" , "brand" , "cate_name" , "model" , "listing_count" , "sell_count" ]] # 必要な列に絞る # データの確認 print (df.head()) print (df.columns) 3. 移動平均 に変換する ECデータの場合、平日より休日の方が多く売れる傾向がありますので、7日間 移動平均 に変換して、データを均します。 ローデータは、前の要素の9/30の次に次の要素の9/1が来てしまうため、9/7以降のデータに絞り込みます。 ※もっとよいやり方がありそうな気がしますが、自分の知識だとこうなりました。 df[ "listing_count" ] = df[ "listing_count" ].rolling( 7 ).mean() df[ "sell_count" ] = df[ "sell_count" ].rolling( 7 ).mean() df = df[df[ "date" ] >= "2021-09-07" ] # データの確認 print (df.head( 30 )) # CVRを計算して、カラムを追加 df[ "cvr" ] = df[ "sell_count" ]/df[ "listing_count" ] 4.変数をダミー変数に変換 今回、使用する予測変数は、全て質的データになるので、そのまま、決定木分析に使用することは、出来ません。 get_dummies関数を使って、ダミー変数に変換します。 df = pd.get_dummies(df, drop_first= True ) # 2の時点と異なることを確認 print (df.columns) 5.データの分割 予測変数と目的変数、学習用データとテスト用データに分割します。 今回は、モデルの精度を上げることは目的としていないため、テストデータは少なくして、ほとんどのデータを学習データにしました。 exclusion_list = [ "cvr" , "date" , "listing_count" , "sell_count" ] include_list = [column for column in df.columns if column not in exclusion_list] obj_df = df[ "cvr" ] exp_df = df[include_list] obj_array = obj_df.values exp_array = exp_df.values X_train, X_test, Y_train, Y_test = train_test_split(exp_array, obj_array, test_size= 0.01 , random_state= 222 ) 6. 決定木モデルの学習 作成したデータで、決定木モデルを学習させます。 # モデルのインスタンス生成 reg = DecisionTreeRegressor(max_leaf_nodes= 20 ) # 学習によりモデル生成 model = reg.fit(X_train, Y_train) print (model) # 評価 y_true = Y_test y_pred = model.predict(X_test) print (r2_score(y_true, y_pred)) print (mean_absolute_error(y_true, y_pred)) 7. 木構造 を画像に保存 モデルの 木構造 を解釈できるよう、画像に変換します。 dot_data = export_graphviz(model, out_file= "cvr_data.1.dot" , filled= True , rounded= True , feature_names=exp_df.columns ) subprocess.run( "dot -Kdot -Tjpg -Nfontname='MS Gothic' -Efontname='MS Gothic' -Gfontname='MS Gothic' cvr_data.1.dot -o cvr_data.jpg" .split()) # 日本語を含むと、文字化けするため、fontを指定 解釈 以上の ソースコード を実行すると、以下のような決定木のjpgファイルが出来上がります。 出来上がった決定木を見ながら、解釈をしていきます。 注意点として、決定木は、lossが少なくなるように分割していく アルゴリズム であるため、上位に出てくる変数が、必ずしも、CVRを高くする変数とは限りません。 value を確認しながら、どのような分割がなされているか、確認していきます。 まず、カテゴリ_jacketGが最初のノードで分割されるようになっています。 そして、右に分割されたノードの value は0.108と左の0.024のノードよりも高いため、カテゴリが、カテゴリ_jacketGの場合、CVRがかなり高くなると解釈できます。 では、カテゴリ_jacketGであれば、なんでもよいかというと、その次の分割を見てみると、ブランドがブランド_BNである場合、 value が0.142、そうでない場合は、0.006となっているため、カテゴリ_jacketGは、ブランド_BNが一強のカテゴリであることが分かります。さらにノードを下ると、ブランド_BNの中でもモデルによって、CVRは異なるようですが、全般的には、高いCVRを擁していることが見てとれます。 カテゴリ_jacketGではないノードを見ていくと、いくつかのブランド名でノードが枝分かれするようになっています。カテゴリ_jacketGでなければ、その次は、ブランドの選択が重要である、ということが見てとれます。実際には、企画担当者と会話をしながら、表示されているブランドをグルーピングなどして、整理しました。 さらに深く確認しようと思えば、ブランド_BFは、カテゴリによって差がある、カテゴリ_jacketBカテゴリかどうかで、ノードが分かれる、と状況に応じて、確認していくことも可能です。 決定木の場合、初めにも話した通り、視覚的に分析結果を表せるため、 ドメイン 知識が少なくても、結果の解釈が行いやすいことはメリットではないかと思います。また、企画担当者側も分析結果が分かりやすいので、スムーズに相談が行いやすくなると思います。 なお、解釈性が高い決定木分析ですが、注意点もあります。 まず、決定木分析は 機械学習 の アルゴリズム の中では、精度が高くなりにくい、と言われています。これは、モデルが学習データに 過学習 しやすく、汎用性が低くなってしまうためです(今回は、生データや、感覚値ともずれていないという判断をして、精度はあまり重視しませんでしたが。)。決定木に限りませんが、あくまでも学習データとして使用したものの説明にしかなっていませんので、将来的にも同じ傾向があるかどうかは、確実ではありません。特に、一時的に強い需要があったデータなどが含まれると、当然、そのデータの影響が強く出てしまうため、注意が必要です。 今後の展望 今回は、比較的、カジュアルな分析でしたので、そこまで、多くない変数で実施しました。感覚としては、企画担当者側も理解しやすかったのではないかと感じましたので、決定木を使ったデータ分析は有用であると考えています。 変数を増やしていくことで、目的とする変数に対して、どういった変数が影響を与えているのか、さらに詳細な分析を行うことも可能と考えられます。 また、決定木 アルゴリズム の発展形として、LightGBMやXGBoostなどの アルゴリズム が、データサイエンス分野では、スタンダードになっているようです。他にも、SHAPなど、今回、実施した内容以外で、 機械学習 モデルの可視化をする方法が研究されており、自分も現在、勉強中です。 最初にお伝えした通り、 エニグモ には、データアナリストとは別に、データサイエンティストの職種もあります。データサイエンスのプロフェッショナルがいて、通常のデータ分析を企画担当者の方も普通に行っている環境ですので、ビジュアライゼーションやモデルの説明性といった手法を使って、データとビジネスをうまくつなげていくのが、データアナリストの役割ではないかと考えています。 本日の記事は、以上です。読んでいただき、ありがとうございました。 明日の記事の担当はエンジニアの沖田さんです。お楽しみに。 株式会社 エニグモ 正社員の求人一覧 hrmos.co
この記事は Enigmo Advent Calendar 2021 の6日目の記事です。 こんにちは。 BUYMA でWebエンジニアをやっております、岡本です。 エニグモ に入ってから約1年が経過しました。 学生の時にプログラミングを始めてしばらくbashを使っていたのですが、イケイケの先輩に zsh を教えてもらい、 zsh の機能を拡張するための プラグイン マネージャーにはOhMyZshを勧められ、数年利用していました。この時期に使っていた macOS の標準シェルは bash で、 zsh はわざわざインストールするものでした。 1年前に エニグモ に入社した頃、支給されたMacBookProに搭載されている macOS の標準シェルは既に zsh になっていました。(標準シェルが zsh になったのは macOS 10.15 Catalina以降です) せっかくの機会なので気持ちを新たに プラグイン マネージャーも替えてみようと思い立ち、いくつか zsh の プラグイン マネージャーを調べたところZinitが良さそうに思えたので導入することにしました。今回は導入した感想を軽く綴ってみようと思います。 github.com (2021年12月6日閲覧、以下記載URLも同様) いいところ いくつか公式ドキュメントでもアピールされていますが、個人的に良いと思うところを挙げます。 zsh の起動が速くなる 公式ドキュメントで喧伝されているのが zsh の起動スピードについてです。早いことをアピールしています。 Zinit is currently the only plugin manager out there that provides Turbo mode which yields 50-80% faster Zsh startup 訳(Zinitは現在、ターボモードを提供する唯一の プラグイン マネージャーであり、 Zsh の起動が50〜80%速くなります。) cf. https://github.com/zdharma-continuum/zinit#zinit ここでターボモードとは何ぞやとなるのですが、 wait を使った遅延読み込みのことを指すようです。これについては後ほど紹介しますが、ターボモードを使わなくても従来の プラグイン マネージャーと比較すると zsh の読み込み速度は高速になっていると思います。 OhMyZshおよびPrezto プラグイン とライブラリの読み込みをサポートしている OhMyZshやPreztoなどを利用していた方もその資産を継承できます。なお私はOhMyZshの プラグイン は現在は読み込まずに使っています。気になる方は以下をご覧ください。 参考URL https://zdharma-continuum.github.io/zinit/wiki/INTRODUCTION/#oh_my_zsh_prezto 使ってみよう Zinitのインストール方法はこちらからご覧いただけます。 https://github.com/zdharma-continuum/zinit#automatic-installation-recommended sh -c " $( curl -fsSL https://git.io/zinit-install ) " source ~/.zshrc zinit self-update こちらを実行することで ~/.local/share/zinit/zinit.git にzinitがインストールされ、zshrcにzinitの設定が追加されます。 ここから自分好みにカスタマイズしていくわけですが、現時点の私のzshrcを見てみるとこんな感じになってました。1~7行目は romkatv/powerlevel10k を使うために設定しているものです。一言でいうとターミナルのUIをカラフルにしてくれるものです。 ペアプログラミング の機会があると「ターミナルのUIがカラフルですね」とよく言われます。 ディレクト リ名やブランチ名が見やすいのでOhMyZshを使っている時からずっと使っています。 1 # Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc. 2 # Initialization code that may require console input (password prompts, [y/n] 3 # confirmations, etc.) must go above this block; everything else may go below. 4 if [[ -r " ${XDG_CACHE_HOME:-$HOME/.cache} /p10k-instant-prompt- ${(%):-%n} .zsh" ]]; then 5 source " ${XDG_CACHE_HOME:-$HOME/.cache} /p10k-instant-prompt- ${(%):-%n} .zsh" 6 fi 7 8 ### Added by Zinit's installer 9 if [[ ! -f $HOME /.zinit/bin/zinit.zsh ]]; then 10 print -P "%F{33}▓▒░ %F{220}Installing %F{33}DHARMA%F{220} Initiative Plugin Manager (%F{33}zdharma/zinit%F{220})…%f" 11 command mkdir -p " $HOME /.zinit" && command chmod g-rwX " $HOME /.zinit" 12 command git clone https://github.com/zdharma/zinit " $HOME /.zinit/bin" && \ 13 print -P "%F{33}▓▒░ %F{34}Installation successful.%f%b" || \ 14 print -P "%F{160}▓▒░ The clone has failed.%f%b" 15 fi 16 17 source " $HOME /.zinit/bin/zinit.zsh" 18 autoload -Uz _zinit 19 (( ${+_comps} )) && _comps[zinit]=_zinit 20 21 # Load a few important annexes, without Turbo 22 # (this is currently required for annexes) 23 zinit light-mode for \ 24 zinit-zsh/z-a-rust \ 25 zinit-zsh/z-a-as-monitor \ 26 zinit-zsh/z-a-patch-dl \ 27 zinit-zsh/z-a-bin-gem-node 28 29 ### End of Zinit's installer chunk 30 以下略 さて、 プラグイン を設定してみます。 zsh を使う上で外せないのは補完と シンタックス ハイライトではないかと思います。 # 補完 zinit light zsh-users/zsh-autosuggestions # シンタックスハイライト zinit load zdharma/fast-syntax-highlighting ここで、 プラグイン の読み込み方法は load と light があります。 load を使うことで プラグイン のト ラッキング を可能にします。 zinit report {plugin-spec} で プラグイン の情報を出力し、 zinit unload {plugin-spec} で プラグイン を無効にします。 一方 light を使うと プラグイン のト ラッキング 機能が無効になり、loadに比べて読み込み速度が速くなるようです。 また snipet を使うと、URLを直接指定する形で プラグイン を読み込むことができます。 zinit snippet https://gist.githubusercontent.com/hightemp/ 5071909 /raw/ cf. https://zdharma-continuum.github.io/zinit/wiki/INTRODUCTION/#basic_plugin_loading このような感じでお好みの プラグイン を追加していきましょう。筆者のzshrcをみると zdharma/history-search-multi-word というコマンド履歴を検索する プラグイン が入っています。 zinit load zdharma/history-search-multi-word 設定例は zinitのドキュメントに記載されている ので私はこれを参考にして設定したのですが、ここで ice というものが出てきます。 zinit ice pick "async.zsh" src "pure.zsh" zinit light sindresorhus/pure zinit ice depth= 1 ; zinit light romkatv/powerlevel10k zinit ice は直後の行で実行される load や light の挙動を変更します。 ice の後の pick や src などはice-modifiersと呼ばれるもので、 iceという名前の由来は、氷は飲み物に入れて少し経つと溶けることから、変更が一時的なものであることを意味すると公式ドキュメントでは説明されています。ice-modifiersの後ろにクォーテーションやイコールで指定されているのは引数です。ice-modifiersが引数によってzinitの挙動を制御します。例えば上記の pick であれば、引数として与えられた"async. zsh "に実行権限を与えてPATHに追加するようにzinitに対して指示しています。 その他のice-modifiersの用法についてはこちらを参照してください。 https://github.com/zdharma-continuum/zinit#ice-modifiers おわりに 基本的な使い方はできていると思いますが、まだまだ知らないオプションが多いのでもっと使いこなせるように日々精進したいと思います。 次回の記事の担当はデータアナリストの井原さんです。お楽しみに!! 株式会社 エニグモ 正社員の求人一覧 hrmos.co
こんにちは、サーバーサイドエンジニアの竹本です。 この記事は Enigmo Advent Calendar 2021 の3日目の記事です。 みなさまは2021年どのように過ごされましたか、株式会社 エニグモ では昨年の 新型コロナウイルス の影響で2020年2月からリモートワークに以降したのですが、今年はなんとオフィスが半分になり全社的なリモート体制が整いました。(新オフィスの紹介記事 最高なオフィスにリニューアルしました!!BUYMA/株式会社エニグモ | 株式会社エニグモ ) コロナ禍抜けたら出勤再開しましょうなどの展開はなく、リモートに切り替える機動性の高い会社です🤗 採用情報は コチラ というわけで、1エンジニアの私もリモートワーク中心の生活が続いております。そういう状況の方は多いのではないでしょうか? ところで、お家での作業は捗っていますか!? あんまり集中できない日があったり、逆にいつの間にか窓の外が暗くなっていたりなど、色々あるのではないでしょうか?そこでおすすめしたいのが ポモドーロテクニック です。 ポモドーロとは ポモドーロテクニック といって25分作業して5分休憩することによって集中力を持続させることができる作業方法です。 私がポモドーロを始めてみようと思ったのは SOFT SKILLS ソフトウェア開発者の人生マニュアル を読んだことがきっかけでした。 ポモドーロテクニック 自体は知っていたのですが、作業中にタイマーがなるのが鬱陶しそうで敬遠していました。 しかし本書では ポモドーロテクニック は集中のためのツールというよりも、 ポモドーロ何セットかかるタスクなのかを見積もる (以下記事の中では ポモドーロ1セット=1ポモ と単位ポモで表記します) 実際何ポモかかったのかを計測する 以上を繰り返す これにより、タスク見積りの精度が向上していくメリットを中心に ポモドーロテクニック を紹介しています。 自分でタイマーをセットして見積りと計測をメモっていっても良いのですが、世にはいっぱいポモドーロアプリがあるので、便利に活用したい! というわけで自分の作業環境や、目的に合っていそうなアプリを探す旅に出ました。 以下の条件で選定しております。 無料で試せる mac で利用できる 作業ログを見ることができる そして条件に合った4つのアプリを実際に試したので紹介させていただきます。 Pomofocus Kanban Flow life line Be Focused Pomofocus https://pomofocus.io/ 「pomodoro timer」で ググる と一番上に出てくる シンプルなUI タスクにかかるポモドーロのセット数見積りを設定できる 中断できる ログが見れる Pomofocus画面 一番最初に試したのがこのアプリでした。本当にシンプルで簡単に利用することができ、私自身「ポモドーロ、試してみようかな…」という段階でこのアプリに出会うことができたところが今もポモドーロを継続できていることに繋がっていると思います。 またタスクの設定時に何ポモかかりそうか見積りを設定し、実際何ポモ経っているのかを計測できるので、当初の目標とマッチしています。以降紹介するアプリの中でも最も簡便に見積りの入力ができるので気に入っているポモドーロアプリです。 Kanban Flow https://kanbanflow.com/ カンバン的UI サブタスクも チェックボックス で管理できる タスクにかかる時間の見積りが設定できる ログがめっちゃ見やすい 中断しようとすると理由を聞かれる Kanban Flow画面 カンバンはユーザーを招待してチームで管理することもできる 名前の通りカンバンUIで全タスクを一望できるのが便利! 他のアプリは作業中のタスクだけ表示の場合も多いですが、こちらはTodo/DoToday/InProgress/Done全てのステータス(ステータスカラムは編集可能)のタスクが表示されており、またカンバンはプロジェクトごとに管理できるようになっています。 何よりSOFTSKILLS作者ジョンソンメズによって開発されているのもあり、こちらもタスク設定時にタスクにかかる時間の見積り設定が可能です。 しかし作業の中断に厳しい設計になっており、ちょっとトイレ行きたい時にも、タイマーを止めようとすると、ポモドーロを中断させられるし(また0からポモドーロを始める必要がある)急いでいるのに理由を聞かれたりして、まあいっかとタイマー回しながらトイレに行くことが多かったです。 ポモドーロ停止理由一覧 停止するときはこのくらいの覚悟を持てということなんですね oyatsuは自分で追加しました life line 画面上部のメニューバー下に作業時間が可視化される PCで作業しているとタイマーを自動で回してくれる 休憩時間は画面をグレーアウトしてくれる kanban flowを利用していたあたりに、「ブラウザでのタイマーはわざわざそのページを見に行かなきゃいけなくて面倒だな…」と思っていたところでこちらを試してみました。 mac 画面上部のメニューバー下に1日の作業している時間がグラフとして可視化されます。 また、ログを見ると、作業時間、休憩時間が日ごとに確認することができます。 life lineログ画面 お昼休みが黒かったり、 MTG 中は休憩していなかったりが一目瞭然 またlife lineの面白い機能として、一定時間以上PCで作業しているとタイマーが起動し、25分経過すると画面が ホワイトアウト して作業を止めることができるのでやや強制的に作業のリズムを作ることができます。 しかし、自動でタイマーが起動する性質上、個別のタスクに関する見積り、計測が難しいです。 ちょっとslack巡回しよ…って時もタイマーが動き出してしまい、「あー今はタスクやってたわけじゃないのにー!」となります。 Be Focused メニューバーで時間を確認できる タイマーのアラーム音をたくさんの中から選べて愉快 見積りも入力できる Be Focused画面 アップグレードしたら広告は消えるそうです やっぱりメニューバーで後何分か確認できるやつが欲しいな!そしてタスクごとにタイマーを手動で動かしたい!と思いこちらのアプリに出会いました。 タスクを追加して、タスク詳細画面から何ポモかかりそうか入力して、タイマーをスタートさせるというシンプルな流れ。 というわけで現在はBe Focusedに落ち着いています。 アプリはさまざまなものが出ているので、ポモドーロを導入する目的にあったアプリを見つけて、良いポモドーロライフをお送りください! 次回の記事の担当は サーバーサイドエンジニア の 岡本さんです。お楽しみに。 株式会社 エニグモ 正社員の求人一覧 hrmos.co
こんにちは、Corporate IT/Business ITを担当している足立 です。 この記事は Enigmo Advent Calendar 2021 の 2日目の記事です。 エニグモ では1人目のコーポレートIT担当として未着手な社内IT環境をコツコツ整備してます。 世間一般的には情報システム(情シス)と呼ばれるポジションです。 昨年はコロナ対応について書きましたが、もう早いものであれから1年が経過しました。 今年は コーポレートITの未来を考えた話 について書きたいと思います。 コーポレートITの未来って? 早い話、ロードマップ(中期計画)を考えた話になります。 今後、3年間で実施したいIT投資計画を策定し経営層に対し内容を共有しました。 では、何故中期計画を策定したのか? 私が エニグモ に来てから2年半以上の月日が経ち、入社直後のミッションとして下記内容がありました。 老朽化した 複合機 のリプレイス Google Workspaceのプラン変更 紙ベースの権限申請の電子化 それぞれについて書くと長くなるので割愛しますが、上記の目処が立った矢先にコロナ対応、オフィスリニューアルPJがあり 場当たり的な対応を続けて来ました。 とは言え外的要因が起因とした状況でしたが、 エニグモ の社内システムの環境は大幅に改善されたと思います。 入社直後の社内システムの一部 上記の図は私が入社直後の社内システムの一部になります。 管轄が違うシステムも含まれていますが、全社的に使用する物はコーポレートITが管轄しています。 現在の社内システム一部 現在はコロナ対応に伴うリモートワーク環境構築の為に導入した物やオフィス リニューアル時に導入したシステムを合わせると上記の図のようになりました。 環境が大きく変わりましたが思いとしては道半ば。 まだまだ、導入しなければならない物が沢山あると感じていますが、今後も場当たり的に導入するのではなく 中期的に必要性や導入計画も立て予算についても経営層と事前に共有する事が必要と思いました。 例えば導入したい物が高額な場合に経営層も直々にOKを出す事は難しいですし、 導入したいシステムが一部だけ承認が降りたとしても会社全体でのシステム構成にバラツキが出てしまうのも 余計な投資を実行してしまう要因にも成りかねません。 モダンなシステム構成の実現、無駄な投資を防ぐ為にも中期計画が必要でした。 中期計画 策定のパートナー 私自身の中に今後、導入したいシステム構成はボンヤリとありましたが、果たして本当にその構成で良いのか? エニグモ に取ってベストな構成なのか?と言う疑問がありました。 そこで中期計画を策定するにあたり外部の力を借りる事にしました。 クラウド ネイティブさん パートナーとして クラウド ネイティブさんのご協力をお願いしました。 お願いした理由としていくつかありますが、代表的な事としては下記の通りになります。 ベンダーフリー ベンダーに属されていないのでフラットな立場で様々なサービスを提案・導入が出来る ベンダーによっては導入提案出来る商材が決まっていたりする事があるのでフラットな立場で提案して頂ける部分に魅力を感じました。 自立を考えてくれる 支援をお願いすると基本、代行してやってくれるケースが多いですが基本、弊社にナレッジやノウハウを残して頂けるように支援してくれます。 また、問い合わせに関してはSlack出来る為、レスポンスが早くスピーディーに対応して頂けます。 強力なスタッフ 情シスSlack内やイベントでお見かけする強強な情シス経験者の方が参画しているので心強い。 尊敬する方もいらっしゃったので一度、お仕事をご一緒したい思いもありました。 元々、IdP導入は クラウド ネイティブさん経由で実施する予定でしたので、同時進行で進めていく事になりました。 やはり自分が考えている構成について壁打ち出来る相手が居ることは安心感に繋がりました。 コーポレートITのMVV 中期計画を策定にあたり、経営層との話し合いの場を設けて頂きました。 IT投資を実施する為に役員がコーポレートIT部門に対してどんな目的で、どのようなチームであって欲しいのか ヒアリ ングをさせて頂き その内容をベースにMVV(ミッション・ビジョン・バリュー)を策定し、その内容にあった計画を作る事にしました。 ヒアリ ング当日は役員に対してコーポレートITに対して思っている事、実現して欲しい事を兎に角、何でも良いので言って欲しいとお願いし 様々なワードが出てきました。 そのワードを元に作成したMVVが以下の通りになります。 ミッション(使命、目的) 全てのStakeholderをHappyに ビジョン(将来像) 社員と組織の Value 実現をITで支えるチーム バリュー(スタイル) 「 Location Free 」 「 Always update」 「 Balancing productivity and security」 MVV ミッションである「全てのStakeholderをHappyに」は代表である須田さんのお言葉でした。 ヒアリ ング当日はワードが出てこないのでは無いのかと懸念してましたが、予想とは裏腹に3人の役員が思いの丈をぶつけて頂きました。 中でも「従業員だけでなく、協力会社の方々、 BUYMA ユーザー、パーソナルショッパーなど エニグモ に関わる全てのStakeholderがHappyになる環境であって欲しい」とお話して頂いた時はミッションはコレしかないと感じました。 ミッション ビジョンである「社員と組織の Value 実現をITで支えるチーム」は エニグモ の企業理念にある3つの価値基準を大切する行動指針を後押し出来るチームである事を示しました。 セルフスターター 他人や環境に左右されず、自ら目標を見つけ引き金を引き、突き進める人 アウト パフォーマー 自分の強みを鍛え、常識、限界、期待値を超えていく人 チームビルダー ”日頃”のチーム作りと”実践時”のチームパフォーマンスに貢献できる人 ビジョン 最後にバリューについては3つの指針にしました。 Location Free コロナ禍後は会社を身軽にする事に注視し、物は持たずPC端末とインターネット回線があれば世界中どこでも業務が出来る環境の実現を目指す事にしました。 Always update 次から次へと新サービス、新しいシステムが出てきます。既存の環境に満足せずに常にアップデートし続ける事を目標としました。 Balancing productivity and security 管理出来ないツールやサービスが増えると、そこが セキュリティホール になる危険性がありますが、無闇矢鱈に規制すると生産性が低下します。 矛盾した話になりますが、「生産性と安全性」を両立した構成を目指す事にしました。 バリュー MVVについては無くても中期計画は策定出来ますが、私はあった方が良いと思っています。 経営層とコーポレートITの間でチームの方向性について同じマインドであった方がより良い組織になると感じるからです。 リスクと課題の洗い出し エニグモ にある想定されるリスクや課題の洗い出しに着手し懸念点については全てお話し必要な対応を可視化。 それに基づき必要なソリューションを マッピング していきました。 弊社のセキュリティに関わる部分になるので、詳細については書くことが出来ませんが、箇条書きでも良いので懸念点をメモしておく事をオススメします。 ソリューションの選定に基づきロードマップへ反映しました。 ロードマップ また、概算費用を算出する為、必要ライセンス数の洗い出し、定価ベースでの費用感を算出しました。 大凡の金額感だとしても、これだけの費用がかかるのかと思うと震えました。 未来へ 課題や懸念点、予算感を取りまとめてロードマップにし役員へ共有を行いました。 役員からは「概ね、agree」と言われて、同意して頂いたのでほっとしました。 今後についてはフェーズ毎に改めて詳細なシステム構成案、費用感、検証を実施し役員へ最終提案を行います。 より快適でセキュアな環境構築の為に日々、精進していきたいと思います。 明日の記事の担当は サーバーサイドエンジニアの竹本さんです。お楽しみに。 株式会社 エニグモ 正社員の求人一覧 hrmos.co
Advent Calendar 1日として初日を飾るのは、 エニグモ のエンジニアインタビュー第7回!今回はインフラチーム入社2年目の加藤さん( @kuromitsu_ka ) です。 趣味は自転車だそう。夕日すごい! 先日広島のうさぎ島に行ってきたそうです。もふもふしている。 インタビュアー 穴澤:2019年1月入社。エンジニアマネージャー。 穴澤: 加藤さんは エニグモ 入社丸2年ですね。 エニグモ はサービスエンジニアリング本部という部署の中でアプリケーション開発、 アプリ開発 、インフラなど複数のチームにわかれていますが、 加藤さんはインフラチームですね。前職もインフラをされていたんですか? 加藤: SESで、お客さん先に常駐するタイプのインフラエンジニアでした。 SIer に2年、サービス運営会社に1.5年お世話になりました。新卒で一番最初に常駐させていただいた SIer では、主に運用周りを担当していました。( Cacti の監視とかコードリリース、アラートが飛んでくると調査するなど) その後知人の繋がりでサービス運営会社にも常駐させていただきました。 ここはモダンな開発環境で、プロパー社員もいい人でIaCや クラウド サービスを使った新規構築、新規 OSS の検証、運用周りの自動化をさせていただきました。 こちらの現場の仕事を通して「自分もサービス開発に関わる仕事をしたいな」と思って転職することにしました。 エニグモ は一番早く連絡をくれていて、 BUYMA も知っていたので 記念受験 のつもりで受けたら受かりました。(初の転職面接でした。) 穴澤: 入社後、実際の実務をしながら独り立ち、という流れかと思いますが具体的にはどういうフォローだったりサポートをうけていたんでしょうか?入社後のギャップってありました? 加藤: 入社当初の試用期間、3ヶ月間は上司が日々何かと面倒を見てくれていました。ガイダンスもありましたが日ごとにわからないことはそこで解決していただいていました。その後別の先輩と aws のプロジェクトに参加しています。毎日 MTG しつつ作業の相談やわからないことはオンラインですすめていて、特に困ることはありませんでした。入社後のギャップとして良かったこととしては、 リア充 キラキラ系だと思っていて、自分にはちょっとしんどいかなと覚悟していたら、落ち着いた感じでした。自分が入社する当時は、「 やんちゃであれ 」が社訓だったので、もっとやんちゃにやってみたい/やんちゃな人に出てきて欲しいなとは日々思っています。 穴澤: みんなキラキラ系におびえて入社してきますね(笑)。 今の一日の流れと、実際一週間で実務作業がどのくらいなのかおしえてください。 加藤: 午前中は作業やMRレビューなどをやっています。ほぼ毎朝同じプロジェクト( AWS 化)の先輩と MTG しつつ作業です。ロールとしてはインフラ/SREですが ペアプロ 開発っぽい形で進められています。 午後は特定の曜日は MTG があったりしますが基本作業です。作業は17:00くらいまで。作業中の不明な点はチームのslackか定例で聞いています。作業時間は概ね7,8割だと思います。まとまった時間がとりやすくありがたいです。 以前、障害対応をしたことがあったんですが先輩とzoomで画面共有しながら一緒に作業した時先輩の操作を直接みれて勉強になるし質問もすぐできるし、すぐ教えてもらえるので普段の業務でも ペアプロ のように一緒に作業してもらえる時間をつくってもらえるようになりました。この進め方は今もとてもよかったと感じています。些細なことですが、チームでの仕事の進め方みたいなことも相談できるのでありがたいです。 直接会社とは関係ないかもしれませんが、リモートになったことで都内で飲んだり遊ぶことがなくなりました。その代わり、ジムや誘ってもらったバレーボールチームに参加したりと自分の時間を調整しながら仕事のバランスが取れてると感じます。 コロナ禍になってからキャンプも始めました。 先日は、友達と ゆるキャン△ 聖地巡礼 キャンプにいって、富士山の日の出を見てきました。 穴澤: おープライベート充実してますなあ。 インフラチームでも、 ペアプロ みたいな一緒に作業ができるのって安心感ありますね。 まとまった時間がとれるのもいいですね。コードを書く時もそうですが設定や実務やってると途中で遮られたり、ノッてる時に MTG になると辛いですもん。 今リモート勤務だと思いますが、加藤さんたまに出社してます? 加藤: 週1くらいの頻度で定期的に出社してて、リゾートエリア(休憩エリア)にいると自部署以外の人からちょっとしたお困りごとみたいな相談をうけることがあってそれが嬉しかったりもします。最近では ブックマークレット のjsの書き方を質問されて、答えるなどしました。ちょうど自分がNode.jsを勉強してたのもあって、自分の勉強にもなってよかったです。入社してすぐにリモートになったので、社内に知らない人が多いのが悩みでした。たまに出社していれば、社内の誰かが声をかけてくれるので、内心凄くありがたいです。 穴澤: あ〜そういう相談って結構リモートだと難しい、、DMみたいな深刻さもないし、かといって大勢のいるチャットできくようなだいそれた事でもないし・・すれ違ったときに「そういえばこれしってる?」みたいなノリがとてもいいですね。 エニグモ では、リモート後に入社した人むけにオンボーディングと称して各部署の方が定期的に部署の役割や他部署とのつながりを説明してくれるオンラインのイベント がありますが確かに別部署の方と接点というのは限定的になりがちですね。 さっき入社後のギャップみたいなお話をしましたが、入社後、仕事の仕方とかで大きく変わったことってあります? 加藤: 自分は、客先常駐の仕事から事業会社の社員に転職したのもありますが、仕事で何かトライする際のハードルが下がった気がします。プロジェクトを進めている時も、振られたタスクを進めるだけじゃなくて、提案や、課題発見→起案がし易いですね。些細な事の相談や、新しいサービスを導入するなどの相談と意思決定が早いので取り組みたいことや試してみたいことを予算やある程度の準備をしてお願いすれば大体「OK、やってみよう。」という流れになる。事業会社ならではだと思います。 穴澤: わたしもそういう文化を エニグモ に感じます。まず話をきいてくれる環境というか、耳を傾けてもらえるところがすごくいいなと。自分で考えてチャレンジしたり提案できるって環境や風土は大事にしていきたいですね。私も、組織づくりをがんばります。 開発環境周りでいつもサポートしてくれる加藤さん、これからも頼りにしています。また、入社3年目突入ということでますますの活躍、期待しています! 今日はインタビューありがとうございました。 明日の記事は人事総務グループの足立さんです!
エニグモ の若手社員インタビュー第一弾、平井さんです。入社3年目を迎えている平井さんに、現在の日々の仕事内容やリモートでの環境の変化などをざっくばらんに聞いてみました。 入社直後のインタビュー もどうぞ! 寝癖があったぽいですがご本人の許可を頂きました。:) ウェーイ感ある。 インタビュアー 穴澤:2019年1月入社。エンジニアマネージャー。 穴澤: 3年目ということで実務やチームの立ち回りも、ご自身のリズムみたいなものができてきてるかと思います。一日の流れを教えてもらえますか。 平井: 午前中は主に1日のタスク確認、そのまま所属する開発チームの朝会に出席します。基本的には実装メインなので、午後は実装していることが多いです。施策によってはミーティングが入ることもあります。 穴澤: 平井さんのスケジュール、毎日朝30分、プロジェクトの朝会がセットされていますね。ちなみに入社後、業務を行うまでどんな感じでフォローしてもらっていたんでしょうか? 平井: 1年目のときは毎週金曜日に同じチームの先輩エンジニアの方に参加頂き、週の振り返りをしていました。振り返りは事前に週で行った業務の中で改善したほうがいいことや来週やることを esa に書いて、その週で詰まった部分の原因や解決方法を相談させて頂いていました。あとは朝会でも不安点など相談していました。業務でわからないことは、基本的にslackのチャンネルで尋ねることが多いですが、文章で伝えづらいこととかは、朝会で聞いたりします。 当時の平井さんの振り返り 穴澤: 基本的には OJT ですね。その後入社した若手社員も週次で先輩と一緒に振り返りをやっていて、これはもう誰ともなく部内で引き継がれています。今は 今年入社の岡本さん の振り返りに先輩として参加してる感じですね。エンジニアとしての開発業務は8時間のうちどのくらいの割合ですか? 平井: 平均したら7, 8割くらいかなと思います。最近だと金曜日はミーティングが多めなのでそこまで開発できないですが、他の曜日はほぼ開発してる日もあります。 穴澤: (平井さんのスケジュールをみて)確かに金曜にまとまってミーティング入っていますね。結構こういうやり方してる人多いかも。 エニグモ のエンジニアはほぼみんなリモートですがお昼ってどうしてます? 平井: 常にコンビニに行って弁当買って食べています。運動はあまりしないので、意図的に歩く機会を作っています。リモート勤務になって、通勤が減って体動かす機会がなくなったことです。あとは、ずっと部屋にいるのでもう少し広い部屋に引っ越したいなと思い始めました。通勤する必要がなくなったのは、かなりストレスが減りました。逆に、仕事とプライベートの切り替えは難しいなと感じています。 写真いただきました。すっきり片付いている作業デスク 穴澤: 運動不足は重要な課題ですよね。わたしもミーティングはできるだけスタンディングデスク使っています。歩かないですよね・・。引っ越しいいですね! 仕事とプライベートの切り替えというお話がありましたが、業務の中で先輩、後輩との雑談とか業務外のちょっとした会話ってできてます? 平井: 雑談はチームの振り返りを行った後ちょっと雰囲気が砕けたタイミングで他愛のない話をすることもあります。 あとは最近後輩と時間がとれてないのでそこはフォローしたいと思ってるところです。 穴澤: 先輩っぽい!仕事の話に戻りますが、入社後、業務で一番達成感のあったものってなんですか? 平井: パーソナライズ特集ですね。先輩に教えてもらいながら環境も自分で構築して、独立した新機能を全部自分で作りきったところが達成感につながったと思います。今思えば設定ファイルでできてしまう部分が多く構築はそんなに大変ではなかったですが初めての事も多くローンチできた時は嬉しかったです。 *1 tech.enigmo.co.jp 穴澤: あー!これ私もアプリでレコメンド出てきたので覚えてます!記事が去年なので2年目の平井さんが作ったものですね。たしかに自分で全部作り切るってやりきった感ありそうです。 3年目、新しい社員も入ってきてフォローしたり指導したりということも増えてきてると思います。この後どういうエンジニアになっていきたいなという漠然としたものってありますか? 平井: 同僚(エンジニア、非エンジニア)が安心して一緒に仕事できる存在になりたいです。技術的にプロダクトの課題を解決できるようになりたいです。 穴澤: 平井さんが丁寧にレビューを返したり、岡本さんのtimes(slack上の自分チャンネル)にちょくちょく顔だしてサポートしているのをみかけて丁寧だなあ〜と言ってる諸先輩達も多いです。これからも一緒に頑張りましょう!ありがとうございました。 今年入社の岡本さんのtimesで召喚される平井さん(平井さん実はもっと岡本さんによばれたい) *1 : データテク ノロ ジー グループのレコメンドデータとアプリケーションをつなぎこみ、特定のユーザに適切なブランド・カテゴリを表示する機能。レコメンド取得 API は GCP 上に構成されている。
サービスエンジニアリング本部アプリケーション開発グループの岡本です。 私の前回の投稿 からおよそ1年が経ちました。 本記事では エニグモ 社内で行われている勉強会の中から、私も参加している通称「若手勉強会(Slackのチャンネル名は#junior_workshop)」の取り組みについてご紹介します。 勉強会の概要 こちらの勉強会は「Web開発における基礎知識を身に着ける」をテーマに掲げ、経験の浅いアプリケーションエンジニアの知識の底上げを目指して2020年の6月から開始しました。二週間に一回のペースで業務時間内にZoomや Google meetを繋いで実施します。 「若手勉強会」のREADME(一部) 主な参加者は BUYMA のWebアプリケーション開発を行っている入社数年以内のエンジニアです。 各回、1時間半程度を費やして技術書を輪読したり、普段利用している OSS の ソースコード リーディングを行っていました。 扱った題材 技術書 1 オブジェクト指向設計実践ガイド~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方(技術評論社) メタプログラミングRuby 第2版(オライリージャパン) 増補改訂版 Java言語で学ぶデザインパターン入門(SBクリエイティブ) 補足:2021年11月13日に Java言語で学ぶデザインパターン入門第3版 が出版されるそうです。 技術書を読む際は一週につき1章ずつ進めます。「 メタプログラミング Ruby 」を輪読した際は、各週で本の内容をまとめたドキュメントを作成する担当者を決め、わからなかった点・気づいた点を質疑応答の時間で話し合うという形式で進めていました。 「 Java 言語で学ぶ デザインパターン 入門」では章の初めに作りたいアプリケーションの要件が付されていることが多いので、その部分だけ読んで自分でクラス図を設計し、余裕があればコードを書き、全員集まってクラス図やコードを共有してレビューしながら本を読んで答え合わせをする、という形式をとっていました。 OSS pry/pry binding.pry でなぜ break できるのか コマンドがどのように処理を経ているか exit , !!! , step , next , continue , finish rails/rails ActiveRecord#save , ActiveRecord#save! Rails の初期化プロセス cf. https://guides.rubyonrails.org/initialization.html binarylogic/settingslogic drapergem/draper Draper::Decoratable モジュールが ActiveRecord::Base に include されるまで 業務では主に Ruby on Rails を使って開発をしているため、普段使っている Ruby のgemや Rails の機能を題材とすることが多いです。学んだことは若手勉強会用に作成したSlackの#junior_workshopチャンネルにメモしたり、 esa で記事を作成していました。 筆者が esa に記録していた回 Slackの#junior_workshopチャンネルで知見を共有している様子 1年のふりかえり 1年以上定期的に勉強会を行ってきたので、先日参加者全員でふりかえりを行いました。今回使ったふりかえり手法は「YWT(やったこと・わかったこと・つぎやること)」です。 Y(やったこと)は上記のため割愛しますが、WとTの中から参加者の皆さんの声を一部ご紹介します。 W 技術書、 OSS を読んでわかったこと デザインパターン を自発的に学習する機会がなかったが、いざ勉強して色んな ソースコード を読んでいると デザインパターン の文脈で扱われる用語が使われていることがあることに気づきコードの意図を理解しやすくなった ( デザインパターン の輪読会において)同じテーマで各自プログラムを作成し、その実装・設計に関して議論することで他の人の設計アイディアを知ることができ設計の幅が増えた。 Ruby で デザインパターン を学ぶことができ、 BUYMA の ソースコード を読むのに役立てることができた。 技術書の輪読に関しては、自分の理解が曖昧な箇所について質問したり、他の人の疑問に答えることで一人で読むよりも理解度が上がったのが良かった。 pryの ソースコード リーディングに関しては、自分の中で ブラックボックス 化していた内部処理を理解していく作業が単純に楽しかった。 OSS を読むことに抵抗が少なくなった デザインパターン を学んで新たな視点が芽生えたという意見が多かったです。普段使っている OSS 、一見難解に思えますがじっくりと時間をかけて内部構造を読み解いていく時間が私も楽しく感じました。 その他 輪読形式だったため発表することを意識し、一人で読書するときより知識が定着した。 他の人が利用しているエディターやその他のツールを知ることができた。 質問を受けることでなんとなくわかった気になっていた内容を復習し記憶として定着させることができた。 途中から業務が忙しいという理由で参加しなくなってしまった… 自学することに加えて他人に教えたり発表するなどして知見をアウトプットすることで理解が深まることを実感しました。 T OSS にコントリビュートしたい、今後も継続していきたい OSS の ソースコード リーディングで培った速読力?を普段の調査系のタスクで生かしていきたい。 なかなか OSS へのコントリビュートもできていないので積極的に OSS 活動にも参加していきたい。 実は既に Ruby / Rails に関する OSS に貢献している方もおられます。 tech.enigmo.co.jp おわりに 1年が経過し、参加者それぞれが重要なタスクを任されることが増え忙しくなってきたので、このタイミングで定期的な若手勉強会は一旦ストップすることにしました。今後は Ruby に限らず、勉強会でやりたい企画があれば随時開催しようということで合意しています。(今度はデザインとかフロントエンドの勉強会やりたいですね〜という話をしていました) エニグモ ではエンジニアを採用しています hrmos.co 技術書は会社の補助を利用して購入することができます。 ↩
お疲れさまです。インフラチームの山口です。 新型コロナウィルスの影響下でのリモートワークに伴い最近社内でいくつかの VPN アプライアンス のPoCを実施したのでその際に考えたことや振り返ってこうしておくべきだったという内容を戒めとして各フェーズに沿ってエッセイとして記載します。 なお、現在進行系で数種の製品のPoC中のため、「何か特定の製品を使ってうまくいった」や「弊社はこうしている」などの情報は何もない、私が感じた チラシの裏 的なレポートになります。 要は、技術的に新規性のあることはない内容ですが、同じような問題意識を持ってる人間に届けばいいなといった感じの文章になります(文章でもなんでも刺さる人にだけ刺さればいいというポリシーなので、そういった感じです)。 本稿の構成を以下に記載します。 まず、筆者の経歴および、前提条件を説明します。 次に、製品選定や実際のPoC準備から実施までに考えたことを記載します。 そして、最後に感想をまとめます。 筆者の経歴 前職は以下の感じの業務に従事しており、お客様のネットワーク構築やビデオ会議の導入などをしていました。 顧客のNW(主にWAN)構築・運用(所謂ネットワークエンジニア) ビデオ会議の端末やサーバの導入・運用など(これは何エンジニアなのか適切な表現は思いつかない) その後弊社に転職して今に至ります。 要は、法人のお客様にベンダーの アプライアンス 製品を導入したりする仕事をしている人の気持や挙動は薄々イメージつくといった感じになります。 前職では、企業の情シスの方が主に対面となる顧客の形でした。 が、今回のPoCでは、どちらかというと企業の情シスに近い動きをしており、立場変わると見え方変わるなというのを感じています。 その一方で、再販のベンダーさんが英語の資料ベースにパワーポイントなどでまとめられた日本語の手順書などいただくと、「こういう類作るの面倒だよね(困ったら英語の一次資料頑張って読むけど、利用者としては日本語でアウトラインまとめられているのはありがたい)」という気持ちもあったりして日々勉強させて頂いています。 前提条件 本稿全体の前提にかかる弊社の現状について開示可能な範囲で簡単に箇条書きで記載します。 今回のPoCについては基本的に情シスと協力して進めるという形を取っています。 社員数 150人強(業務委託の方なども含む) 人員の構成 情シス: 2名 社内NWや社内のPC/社内で利用する外部サービスの管理など インフラ: 7名 自社サービスのインフラ部分を担当 当初は情シスワークもインフラで実施していたが、専任の情シス担当者着任に伴い移管したという経緯がある 情シス・インフラは部署としては別ライン(会社でよくある構成だと思いますが、情シスは人事総務系の所属・インフラはエンジニア部門の所属) NW構成と運用 オンプレミスから AWS への移行中のためデータセンタ・ AWS 側それぞれへのIP到達性が必要 リモートアクセス VPN はルータではなく Linux サーバで終端(PC側は各OSに組み込みのクライアントを利用) VPN 関連はインフラの管轄(ただし、社員からの VPN 関連の問い合わせやサポートは情シスでも一部対応してい頂いているケースもある) 問題意識 リモートワークに伴い以下の 工数 が増えている点を改善したい VPN の初期設定時のサポート VPN がつながらないなどのサポート 製品の選定 製品の選定の際に考えたことを記載します。 まず、選択肢として、ベンダーの提供している製品を使うか、自分たちで OSS をベースに構築するかがあると思います。 弊社の状況としては、 OSS などを組み合わせて自分たちで独自に構築して運用する 工数 を取ることは避けたかったため、ベンダーの製品を選択する形を取りました。 また、ベンダーという単語は本稿では、サービスや製品を提供している企業と、その製品の代理店をなんとなく指す意味合いで使います。 OSS を組み合わせて構築する ベンダーの製品を使用する 次に、製品を選ぶ際に考えた点を以下に記載します。 以下に明示的に記載はしていませんが、コストも気にはします。 利用者の観点で設定が簡単か VPN の設定のサポートが辛いという問題を解消したいのでこれは重要。 端末の アップリンク でのポートの遮断などに対応可能か 要は、リモートワーク時のご自宅のNWなどでポートが遮断されている場合は TCP :443などにフォールバックしてつながってくれるような製品かどうか。 リモートワークの際に、社内のメンバーのご自宅のNW機器の設定起因と思われるトラブルに対して、会社としてどこまで手を出すかは悩ましいところなので極力robustに動いてくれる製品が良い。 前職なら「お客様責任のお客様機器」なので設定変更はご法度的な箇所を、製品の型番教えてもらいマニュアル読みつつ影響なく問題を回避する方法を調べ対応するのは面白くもあるが、しくじったときにお互いに辛い。 が、まあ最近の製品は、おおよそフォールバックして通信してくれるのでそこまで気にする必要は実際無い印象。 PoCや導入に際し既存への通信影響がなく、可能であればNW構成も変更せず利用可能なこと 要は、PoCや検証のために既存の通信経路などの変更はしたくない。 最近の流行りだと大概はデータセンタや VPC に配置する VPN サーバに相当する アプライアンス 側でも、アウトバウンドで クラウド 側と接続するデザインが大半の印象なのでこれもそこまで気にする必要はなかった。 また、オンプレミス側に配置する仮想 アプライアンス のためには、ESXiがあれば良い Dockerのイメージが提供されている製品もあるようであったが一部機能に制限などがあるため基本はESXiか Hyper-V に 仮想マシン をデプロイする。 余力があればEKSなりECSで動かしてみるかといった気持ちを当初抱いていたが実際はそんな余力はなかった。 サポート体制 英語での問い合わせでも良いですが、辛いので可能であれば日本語でサポートが受けられるのが望ましい。 息が長い製品であるかどうか 要は、ベンダー都合でEOS(End of Support もしくは End of Service)にすぐならなさそうか。 これは前職でベンダーの日本法人がなくなったり、EoSに伴う後継の製品への置き換えが辛かったりというケースがあったので少し気にしました。 が、根本的に利用者側としては回避する方法はないので頭に留めておく程度。 PoC準備 次に社内PoCの準備に際して考えたことを記載します。 事前に製品の検証をしておく 社内でPoCの依頼をする前に、事前に製品の挙動などの検証をしておきます。 社内のメンバーに使ってもらう状態になると気軽に設定変えて試験といった形が難しくなるため事前に気になる点は検証をしておくのが望ましい。 協力を依頼する部署に事前にお願いしておく 会社の規模にもよるとは思いますが、流石に昨日の今日で社内の各部署に「明日から社内PoCやるんで協力よろしく」は避けたいので、事前に協力を依頼したいメンバーをリストアップし、上長含めて事前にご協力のお願いを出すという形にしました。 各部門で数人ずつ協力していただき、概ね漏れがないような人選としました。 各種手順の準備 インストール/アンイストール/トラブルシュートの手順は事前に準備しておきます。 準備しておけばおくだけ、後が楽になるため注力しておいた方が良いと思いますが、後から漏れなどが出てくるので実際社内PoCの間にも追加で準備したりしていました。 ローカル開発環境でも影響が無いか PCから各リソースにIP到達性さえあればよしとしてしまっていて盲点的な箇所ではあったのですが、弊社サービスのローカル開発環境がリモートのDBなどと通信している箇所があり、PoCを行う製品でも既存の VPN と比較して、ローカル開発環境が極端に遅かったり不安定にならないかを確認します。 たまに遅いなどの問題をうまく検知するために、事前に 負荷試験 ツールの類でローカル開発環境に対して数時間試験をしてレスポンスタイムを記録し 定量 的に比較できるようにしておきます。 PoC実施&評価 PoC実施中から評価の際に考えた内容を列挙します。 実施する状態になったらやりきるしかなくて、どれだけ事前に準備して問題潰しておくかだなと言うのが正直な印象です。 PoC中はPoCに対する問い合わせ対応を最優先にする 社内PoC中はPoCに関連する問い合わせの対応を最優先にするよう事前に自分の持っているタスクの段取りなどを調整していました。 PoC実施中にうまくいかないケースがあったら問題判別を強行しない PoCしてもらっているメンバーからうまく動かないなどの問い合わせがあった場合、長時間に渡る可能性がある問題判別は極力避けるようにしました。 これは、社内PoCに協力いただいていること起因で、既存の業務に影響が出てしまうのは本意ではないため、うまくいかない点の解消がすぐできなそうなら、既存の VPN に切り戻して業務継続していただくような形です。 評価方法 複数製品を評価する場合何らかの形で数字に落として比較できると嬉しいので、PoCに協力していただいたメンバーにアンケート取る形にした。 まとめ(というか感想) まとめというか感想なのですが、社内の利用者・情シス・インフラ・再販事業者・製品ベンダーなど立場が変わると見え方も変わると思いますが、それぞれの立場でみんな幸せになる形で、構成を改善していけるといいなという気持ちです。