株式会社エニグモのブログ - TECH PLAY

TECH PLAY

株式会社エニグモ

株式会社エニグモ の技術ブログ

252

こんにちは、 エニグモ カスタマー マーケティング 事業本部で出品審査などを担当している杉山です。この記事は 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に協力していただいたメンバーにアンケート取る形にした。 まとめ(というか感想) まとめというか感想なのですが、社内の利用者・情シス・インフラ・再販事業者・製品ベンダーなど立場が変わると見え方も変わると思いますが、それぞれの立場でみんな幸せになる形で、構成を改善していけるといいなという気持ちです。
エンジニアの木村です。最近は負荷対策のための リファクタリング やリアーキテクティングのリードや、データ基盤・ML・検索基盤を担当するチームのマネージャーとしてデータ関連の案件に携わっております。 先週、webinar 形式で行われた Akamai TechWeek 2021 Japan にて、6/16 に「EdgeWorkersの導入について」というテーマで、昨年末にバイマに導入したEdgeWorkersという Akamai のサービスについて講演しました。本ブログでもその内容を共有したいと思います。 スライドはこちらになります。 EdgeWorkers の導入について - Akamai TechWeek 2021 Japan Customer Session エッジコンピューティング導入の背景 導入背景としては、アクセス集中下でもサービス自身の ドメイン を通じて自らユーザーを追跡し、ファーストパーティデータを収集する必要性という事業課題がありました。 アクセス集中を伴う マーケティング 施策への対応 事業課題の1つとして、モバイルへのプッシュ通知と、フラッシュセール施策という、いずれもアクセスの集中を引き起こす マーケティング 施策へサービスとして対応していく必要がありました。 まず、モバイルへのプッシュ通知が増加しているのですが、その背景には時代やサービスの成長フェーズの移り変わりがあります。マス マーケティング からOne to One マーケティング へと、我々の注力ポイントが変わってきているからです。実際、以前は認知を広げて新規顧客を獲得するためにTVCMによるマスキャンペーンを展開し、当時はアクセス集中といえばTVCMの放映起因がほとんどでした。最近は既存顧客一人一人に対してパーソナライズ した通知を送ってリテンションを図る施策が増えています。モバイルアプリをインストールしているユーザーやLINEのバイマ公式アカウントと連携しているユーザーはサービスへのロイヤリティが高く、通知の 開封 率も高いので特に一斉に送信するような通知ではTVCM放映以上のアクセス集中が生まれています。 フラッシュセールとは、 ブラックフライデー ・ サイバーマンデー などのセール施策のことです。期間や商品の在庫も限定した形で行われ、また先程のプッシュ通知により開始が通知されるのでアクセスの集中が発生します。毎年性能改善を重ねてはいたのですが、スケールが難しいオンプレのインフラを使っているサービスのところでは対策に限界があったのと、年々増加していくユーザー数に追いつかない状況で、毎年このセールの開始直後はサイトのパフォーマンスが不安定になっていました。 パーソナライズとプライバシー保護の両立 直面していた事業課題の2つ目は、プライバシー保護とパーソナライズの両立です。 パーソナライズ についてですが、最近はレコメンドなどに代表されるパーソナライズ されたUXへの期待が高まっています。北米やイギリスの消費者を対象にした2019年の調査 *1 では、63%の消費者がサービスの標準としてパーソナライズ を期待しているそうです。また、自分だけの特別なオファーが送られてきたり、サービスとの各接点で一人の同一の顧客として認識されることで一人の個人として扱われていると感じるそうです。したがって、サイトのUXだけでなく、 マーケティング 施策にもパーソナライズ が求められています。さらに、そういったUX改善や マーケティング 施策の効果測定でも、施策による単純なKPIの動きだけでなく、ユーザーを一人一人区別して分析し、どのような属性の顧客に効いているのかといった高い解像度での分析が求められています。 また、ユーザーはパーソナライズ を期待している一方で、プライバシーの保護についての意識も高まっていて、個人データの収集に関して透明性が求められています。それに答えるように、 Safari や Chrome といったメジャーなブラウザでブラウザフィンガープリントや サードパーティ クッキー、クライアントサイドクッキーは何らかの制限や規制、あるいは廃止される予定になっています。これにより、ユーザーを追跡する手段としては、サービス自身の ドメイン を使ってのファーストパーティクッキーだけが残され、そのクッキーを通じて収集されるファーストパーティデータの重要性が増してきています *2 。 エッジコンピューティングの導入理由 そういった背景から、なぜエッジコンピューティングの導入に至ったのかをお話しします。 CDN 導入のための必須要件 背景にあったアクセスの集中に対応するために、それまで画像・js・ css といった静的コンテンツのみで多なっていた CDN での配信を、Webアプリから返しているHTMLや API という動的コンテンツの配信にも導入することになりました。また、これも背景で説明したパーソナライズ やデータ収集の必要性から、 CDN を選定するにあたり以下の3つの必須要件を定めました。 レスポンスをパーソナライズ可能 エッジアクセスデータと自社DWHの連携が可能 ファーストパーティ Cookie 操作をエッジへ移行可能 1つ目はレスポンスをパーソナライズ可能性、つまりキャッシュするコンテンツをユーザーによって分けたりが可能かどうかです。2つ目はエッジアクセスデータと自社DWHの連携が可能かという点です。それまではオリジンのWebサーバーのログをDWHへ連携することでユーザーのサイト内の行動を分析していたのですが、キャッシュされるコンテンツに関してはオリジン側へログが残らなくなるため、分析のためにエッジのアクセスデータを自社DWHへ連携する必要があります。3つ目ですが、バイマでは未ログインでセッションを張っていないユーザーも追跡可能にするためにファーストパーティ cookie を利用していて、これによりUXのパーソナライズや マーケティング 施策の効果計測を実現しています。その Cookie の操作処理をエッジへ移行する必要がありました。 ITP2.1 への対応 Cookie 操作処理のエッジへ移行する必要性の経緯としては、ITP 2.1 への対応というのがあります。 Cookie の操作処理の変遷 バイマでは当初、その Cookie の操作を JavaScript の API であるDocument. cookie で行っていたのですが、2019年に Apple によってブラウザの Javascript で作成する Cookie の有効期限は最大7日に制限するというITP 2.1の Safari への導入 がアナウンスされました。バイマでは iOS の Safari のユーザーが大半を占めるので、我々はそれまでブラウザの Javascript で行っていた Cookie の操作をオリジンの アプリケーションサーバ ー側へ移行し、Set- Cookie ヘッダーにより cookie を操作するように修正を行いました。今回の CDN の導入の際は、キャッシュヒット時にもSet- Cookie ヘッダを返すことで Cookie を操作する必要性がでてきます。したがって、ファーストパーティ Cookie の操作処理をエッジサーバー側へ移行する必要性がありました。 Akamai EdgeWorkers を採用 いくつかの CDN サービスから Akamai を選んだ理由としては、上述の必須要件を満たしていたという点がありました。プロパティだけでもかなり柔軟なルール設定が可能で、それだけでもある程度パーソナライズは実現可能でした。また、DataStream 2 というサービスにいよりエッジのアクセスデータをリアルタイムに近い形で、 Google のBigQuery上で構築している自社のDWHへデータ連携が可能でした。さらに、EdgeWorkersにより Cookie 操作をエッジサーバー上への移行が可能という点で必須要件を全て満たすことができました。 また、すでにスタティックコンテンツの配信では既に導入実績があったという点も採用への後押しになりました。実は、この3つの必須要件のパーソナライズ、データ連携、エッジコンピューティングの機能については、他の競合 CDN サービスも提供されています。ただ我々としては利用に慣れていて信頼のある Akamai を使いたかったので、逆にこちらからエッジコンピューティングの機能について問い合わせたところ、EdgeWorkersを提案いただき採用に至りました。 EdgeWorkers の開発・運用 EdgeWorkersでどのように開発をすすめたのかや、実際の運用状況について紹介します。 利用開始は簡単 最初のEdgeWorkersへのとっかかりは簡単でした。すでに Akamai をお使いの方にはお馴染みのWebコンソール「Control Center」から利用可能です。実装も簡単で、開発者は イベントハンドラ のファンクションを実装するだけになります。今回クライアントへのレスポンスするタイミングで呼ばれる onClientResponse を実装しました。Web UI上でコーディング、アクティベートも可能だったので、 チュートリアル としての Hello World を動かすところまでは1日で到達できました。 ライブラリも利用可能 利用できるライブラリについてですが、 cookie 操作やURLのパースなどは標準で組み込まれいているモジュールで十分可能でした。また、rollup.jsという JavaScript のモジュールバンドラーにより標準組み込みでない、npm リポジトリ で公開されている サードパーティ 製モジュールもbundle可能でした。1点だけ注意というか、当然ではあるのですが、ブラウザ JavaScript のコードをそのまま移植しようとしても動かなかったです。元々はブラウザ JavaScript で Cookie を操作していたロジックはあったのですが、書き換える必要はありました。さらに細かいところで言うと、ブラウザだとwindowのオブジェクトにatobやbtoaという base64 エンコーディング ・デコーディングをしてくれるfunctionが付いてるんですが、それは使えず、代わりにrollup.jsで base64 エンコーディング を行う3rdパーティモジュールをbundleして呼び出して使っています。 開発時の デバッグ 方法 開発時の デバッグ 方法ですが、ログ出力をレスポンスヘッダに埋め込んで確認できるenhancend debug headerを利用し、ステージングへアップロード&アクティベートを繰り返しながらのプリント デバッグ で切り抜けました。本当は akamai の CLI でローカルにSandboxを構築して利用する方法もあるのですが、その構築が手順通りにやってもうまくいかず、 ブラックフライデー が差し迫っていたこともあり、問い合わせる余裕すらなかったので、実環境のステージングでの開発となりました。ただステージングへのアクティベートは毎回許容範囲内の時間で終わってくれるので、このやり方でも開発は可能でした。手順通りにやってうまくいかないという点なのですが、ある程度経験のあるメンバーが二人がトライして、二人ともSandbox構築にハマっていたので、ドキュメントに関しては何らかの改善の余地はありそうです。昨年末の話なので、既に改善されているかもしれないですが、期待とフィードバックの意味も込めて、ここで苦労したエピソードとして紹介させていただきます。 開発時の参考リソース 開発時に参考にしたリソースとしては、 ユーザーガイド もあるのですが、他にも GitHubのリポジトリ にexampleが公開されていて、先行事例があまりない段階での利用だったので、開発時にはそれが大変助かりました。 ブログ にも参考になりそうな記事があります。 ユースケース の紹介もありますし、 Github ActionsでCICDを実現するような事例も載っていて、 デベロッパ ーフレンドリーにできてるなと思いました。 本番運用してみて 実際に本番運用してみている状況についてですが、実行時間的なパフォーマンスは非常に良いです。エッジでなにか処理を行っていてもUX上はなにもレイテンシを感じないレベルを維持できています。 EdgeWorkersの実行時間の推移 ただし、本番環境での トラブルシューティング 時のログ調査に課題があるなと感じました。原因調査のため、ログ出力の解析をするためにログ取得をしようとすると、Log Delivery Serviceを使うのですが、実際に手元にログが届くのが次の日になるので、 トラブルシューティング のサイクルを回すのが非常に時間を要する状態でした。EdgeWorkersをFaaS (Function As A Service) として見たときに、競合としては AWS のLambdaや GCP のCloud Functionがそれに当たると思うのですが、これらの場合はリアルタイムに近い形でWebUI上で本番のログをtailしたり、検索、分析できたりします。当然 Akamai そういった機能はあるのだろうと、期待していたところもありましたが、そういた機能は未提供となっているところは残念なポイントでした。今後提供されることを期待したいと思います。 EdgeWorkersの今後の活用と期待 私たちのEdgeWorkersの今後の活用案や、EdgeWorkers自体に対してどのような進化を期待しているかというお話しをしたいと思います。 EdgeWorkersの今後の活用案 今後の活用案としては、これまではキャッシュすることでオリジン側の負荷をオフロードするだけでしたが、EdgeWorkersによりオリジンのロジック自体をエッジへ マイグレーション してよりアグレッシブなオフロードが可能となったと思うので、今回は Cookie 操作の処理だけでしたが、分散処理可能なものはEdgeWorkersへ移行してよりオリジン側の負荷を減らすことが考えられます。また、これまでオリジン側の負荷の制約で諦めていたサイトUXのパーソナライズ施策がたくさんあります。工夫次第ではEdgeWorkersを使うことで実現できそうなものもありそうです。 EdgeWorkersへの今後の期待 最後に、EdgeWorkersへの今後の期待としては、運用のところでも述べた競合並みの監視・ログ管理ツールの提供です。また、監視として使えるものとしてEdgeWorkers Report API が提供されていて、各種メトリクスを取得できるのですが、自社の監視ツールに手動で設定する必要があります。最近は我々も導入しているDataDogやNew Relicといった3rd パーティの監視 SaaS があるので、 SaaS 側にEdgeWorkersのインテグレーションを用意してもらって簡単にメトリクスやログを収集し、常時監視できたらありがたいと思いました。率直に言って、現状のレポーティングの機能だけですと、 Cookie の操作のようなライトな使い方が限界かなという印象です。これら監視・ログのサポートが揃えば、ある程度複雑な処理を書いても本番運用に耐えると思うので、今後の活用案のところで書いたような、マイクロサービス をエッジ上で構築するぐらいのヘビーな活用も目指せると思いました。 また、データ連携の強化も期待したいです。EdgeKVという、Key Value ストアとして使えるストレージの機能があるのですが、そこのデータがエッジ上にあるままでは活用は限定的なものになってしまうと思いました。そこのデータも自社のDWHなどに取り込み、他のデータと紐づけての活用が可能になれば理想的です。 まとめ 私たちは、アクセス集中による負荷の軽減・パーソナライズ・プライバシーの保護というお互いに トレードオフ の関係にある課題を解決する必要がありました。エッジコンピューティングの導入により、それらをどれも犠牲にすることなくクリアすることができました。EdgeWorkersには、ドキュメントの整備や運用面ではまだ課題はあるもの、それらが改善されれば開発者体験としてはさらに向上し、よりディープな活用へと踏み出すことができると期待しています。 最後に、私たちは今回紹介したようなUXの向上やプライバシー保護についての課題など、純粋にユーザー目線でサービスの課題解決に日々取り組んでおります。 CDN を始め クラウド サービスや、最新テク ノロ ジー を駆使して世界を変える流れを作るサービスを提供する仕事に興味のある方は、下のリンクからご応募お待ちしております。 株式会社 エニグモ 正社員の求人一覧 hrmos.co *1 : https://www.businesswire.com/news/home/20190327005062/en/RedPoint-Global-Harris-Poll-Survey-Exposes-Gap *2 : https://www.gartner.com/en/newsroom/press-releases/2020-10-19-gartner-identifies-four-personalization-tactics-to-he
こんにちは。デザイナーの別所です。 本日はenigmoデザイナーの、最近気になっているデザインに関するトピックをご紹介したいと思います。 今回のテーマは「アプリUI編」です! 心地よい使い勝手!映画レビューアプリ「Must」 「Must」は映画/TVファンのための SNS アプリです。 作品のレビューを投稿したり、見たい映画や番組をコレクションとして保存できたり、友達と繋がって他の人がコレクションしている作品を見たりすることができます。 おすすめ作品をデイリーでレコメンドしてもらえたりもします。 2016年にリリースされた アメリ カ生まれのアプリです。 引用: https://mustapp.com/ デザイナーのこだわりを感じるUI/UX Mustの一番の特徴は、画面の下半分の操作で完結するように設計されているUI/UXではないでしょうか。 レビューの入力や「観たい」「鑑賞済み」を選択するボタンなど、このアプリのメインアクションは全て画面の下部で操作できるため、「指が届かない」「両手に持ち替える」などのストレスがなくスムーズに操作できます。 昨今の スマホ の様々な端末サイズに左右されないような設計がされているんですね! ストアのレビューでも優れたUI/UXに対してのコメントが多く見られます。 (レビューでUIについて言及されるアプリって珍しい気がします!) 心地良いUIモーション Mustは見た目の美しさだけでなく、モーションにもこだわりを感じます。 作品のサムネイルをタップすると、本棚から選んで取り出すような雰囲気のモーションがついてます。タップした時にサムネが少し小さくなるところも、ユーザーが押したことを認知させる表現で、細かい技が効いてます。 作品情報のモーダルは作品サムネイルにかぶさる様に画面下から表示されレイヤー感があるので、作品サムネイルと作品情報との優先順位を感じさせる見た目になっています。 テキスト要素をギリギリまで排除したシンプルさ 引用: https://mustapp.com/ 海外アプリっぽいな〜と感じるのがテキスト要素の圧倒的少なさ。 基本的には作品名はテキストで表示させず作品画像のみとなっています。 このシンプルさが美しい作品画像をより際立たせてる気がします。 視認性担保のため小さい画像も無いところが、作品情報を認識しやすく操作しやすいです。 楽しい絵文字遣い 絵文字の使い方にシャレが効いていてオシャレです。 レビューを10段階で入力するときは、数字によって表情が変わります。 こういう小技で入力を楽しめる体験って良いですね。 海外のアプリなので日本語のレビューや、邦題作品はまだ少ないようです。 日本でももっと広まって欲しいです! 株式会社 エニグモ 正社員の求人一覧 hrmos.co
こんにちは、Corporate IT/Business ITを担当している足立 です。 この記事は Enigmo Advent Calendar 2020 の 24日目の記事です。 エニグモ では1人目のコーポレートIT担当として未着手な社内IT環境をコツコツ整備してます。 世間的には1人情シスと呼ばれるポジションです。 今回は2020年に取り組んだ事を書きたいと思います。 2020年は何と言ってもコロナウィルス 1月後半から徐々に猛威が迫ってきて弊社も2月17日に対応・方針についての MTG が予定されてました。 また、偶然にも同タイミングでSlackの全社チャンネルに 会社に対し何らかの方針、対応があるのかと言う内容の投稿がありました。 今思うと見えない恐怖・不安が爆発した日だと思います。 コロナウィルス 2月17日 緊急招集 MTG 2月17日 夕方 経営陣、 監査役 、部署長、情シスが招集されました。 そこで決まった方針は下記内容になります。 方針の大概要 ①「在宅勤務」の推奨 ②出社勤務の場合は「時差通勤」推奨と「社内感染防止ルール」の厳守 ③本方針は翌営業日からのスタート コロナウィルスの影響により、急遽全社的にリモートワークを一斉にスタートする事になりました。 情シスとしてのMISSIONは リモートワーク環境の構築 リモートワーク環境・・・ 実はリモートワークを本導入してませんでした。 当初の予定だとオフィスが元々国立競技場が近いと言うこともありオリンピックに向けて リモートワークを段階的に試験導入する予定でした。 また、コロナ禍前は情シスとしてリモートワーク開始について反対の立場をとっていました。 反対した理由 当時でもリモートワークで業務出来る環境でありましたが いくつか課題があり中々、賛成する事は出来ませんでした。 代表的な理由としては・・・ 運用、緊急時のフローが無い リモートワークの運用フロー・ルールが構築されていない 重大インシデント 発生した際の緊急連絡フローが確立出来てない ウィルス対策が脆弱 コンシュマー版のウィルス対策ソフトを利用してましたが、リモートワークを実施するには強化すべき部分でした。 やはり管理コンソールが無い為、管理者として各端末の状況が把握しにくい部分が課題でした。 MDM (Mobile Device Management)導入して無い ウィルス対策の話と同様に端末の状況を一括で集中管理出来るソリューションが未導入 運用・緊急時のフロー等は社内で方針を決めるだけなので、直ぐに対応が出来る内容ですが 正直、セキュリティ周りをもう少し強化な環境に整えてから実施したいと言う思いでした。 真っ先にやった事 デスクトップ パソコンのリプレイス 緊急事態に付き兎に角、業務が出来る環境にすべくデスクトップPCのリプレイスに着手しました。 当然、パソコン無ければ仕事が出来ません。 当時、アルバイト・ 派遣社員 が使用していた約20台程の Windows デスクトップPCが 稼働中な為、直ぐにメーカーに連絡し、12~13台ずつ購入し3~4週間程で入れ替え完了させました。 キッティングに関し初めはイメージを作成しクローニングで対応も考えたのですが 作成・検証する時間も無かったのと、 エニグモ では予めインストールするソフトも少ないので 人力による力技で対応しました。 2019年より少しずつノートPC化をしていたので、何とかなった感じです。 デスクトップPC リプレイス WEB会議・問い合わせ対応 Zoomを導入しました。 実は運良くコロナ禍前から導入に向けて動いていました。 導入した理由としては Google Workspace(旧称 G Suite)があるので Google Meet利用出来ましたが、やはり大人数でのWEB会議はZoomの方が安定していたからです。 特に エニグモ では4Mと呼ばれる全体集会が月1回あるので、そこは重視しました。 また、仮想背景機能もあるので従業員のプライバシー保護の観点や リモートコン トロール 機能もあるのが決定打でした。 Zoom導入前にトラブルサポート対応で解決までに3時間かかった事例があったので この機能にはだいぶ助けられました。 Zoom対応ハードウェア DTEN導入 元々社 長室・会議室にAppleTVが設置されておりプロジェクターを使用して 会議資料を投影してました。 Mac はAirPlayを使用して安定的に投影出来ますが、 Windows の場合はAirParrot3と言う シェアウェア を利用してましたが非常に動作が不安定と言う課題がありました。 プロジェクターを利用する際に部屋を暗くする不便さ、動作が不安定な課題を解決する為 Zoom対応ハードウェア DTENを1番大きい会議室と社長室に導入しました。 導入後は Windows でも安定した投影が可能になりZoomRoomsアカウントで 無償アカウントユーザーでも時間無制限でWEB会議を利用出来るようになりました。 デメリットな部分としてはお値段が高いところでしょうか 個人的には気に入っているハードです。 当初は全会議室に導入しようとしていたので2台で止めといて良かったです。 社長室と会議室 電話対応 fondesk モバイルチョイス050 導入 コロナ禍と言えども会社へ電話が鳴る日々でした。 その殆どは業務と関係の無い営業電話や人材紹介の電話で月間300件程着信があり 主にバックオフィス部門にて全ての電話を受電し業務負荷が増え 電話対応する度に集中力が途切れて業務がままならない状況でした。 また、お客様の問い合わせについても迅速に対応出来ない事例も発生し 折返し対応するにも会社支給の携帯電話が無いので個人の携帯電話を利用する人も居ました。 そこで電話受付代行サービス fondeskを導入 導入後は会社代表電話番号をfondeskの番号へ転送し 転送先のオペレーターの人が一時対応し全て折返し対応となります。 対応内容はSlackにて投稿されるので、総務が内容毎に関係部署や個人へ共有する運用になりました。 導入後はオフィスが非常に静かになり、こんなにも効果があるものかと感心しました。 また、個人の電話対応として 楽天 コミュニケーションズの モバイルチョイス050 を導入しました。 導入後は個人 スマホ に050番号を付与する事が出来るので、折返し対応時にプライベートの番号が伝わる事が無い様になりました。 メリットとしては簡単にBYODを導入出来る、データ通信ではなく音声回線を利用しているので音質が安定しているのが良い部分だと思います。 FAX対応 メール送信&Slack連携 電話の次に対応したのでFAXです。 レガシーなシステムと言えども銀行やカード会社のやり取りで使用する為、 何かしら対応が必要になりました。 弊社のFAXは 複合機 で送受信を行っているのですが 仕様を確認したところ受信したFAXをメール送信出来る機能があり直ぐに設定 メール送信されたものはzapierを経由し Google ドライブ(共有ドライブ)へ保存され受信した際にSlackへ通知されるようにしました。 ただ、この構成で欠点があります。 複合機 のFAXメール送信機能は用紙切れになるとメールが送信出来ない仕様でした。 ここは盲点でした。 FAXの構成 冒頭でも触れたウィルス対策 リモートワークを始めるにあたり絶対にウィルス対策(エンドポイントセキュリティ)の強化は最低限譲れないと思ってました。 そもそも Windows は Norton 、 Mac はESETとOS毎に違っている。 しかも、コンシュマー版を利用している状況 Excel でシリアル番号とインストール端末を管理すると言う運用 この状況を打破する為、CrowdStrikeを導入 念願の EDR を導入する事が出来ました。 展開が終わった時は達成感が凄かった・・・・ 何と言っても管理コンソールの存在に感動、アラートが飛んでくる頼もしさ、勝手にアンインストールされない安心感はプライスレス。 ちなみに導入直後に管理コンソールにログイン出来ない事象がありました。 原因は セカンダリ 環境にCrowdStrikeが構築されログインURLが通常と違っていたのが原因でした。 (後日談としてESETのアンインストールを社内にアナウンスしたら、みんな光の速さで削除してました・・・) まとめ 2021年へ その他にも実施した事もまだあるのですが、今回書くことが出来ないのでいつかタイミングあれば書いてみたいと思います。 情シス視点での福利厚生制度を作ったり社内イベントをやったりしました。 今後リモートワークを核としたワークスタイルへの移行にむけてオフィスをリニューアルする予定で、 そこに向けて色々と動いています サーバールーム移設対応 社内ネットワーク対応(有線・無線) 電話回線周り( 光収容 化・Dialpad導入) インターネットFAX導入 受付システム導入 入退出システム導入 座席予約システム導入 AV機器周り対応 また、4月にokta導入が決定しました! 出来たら来年こそは MDM を構築したいと思ってます。 では、以上になります。 ありがとうございました。 明日の記事の担当は 出品審査担当 の 杉山 さんです。お楽しみに。 株式会社 エニグモ 正社員の求人一覧 hrmos.co
こんにちは、インフラチームの 加藤 です。 この記事は Enigmo Advent Calendar 2020 の23日目の記事となります。 本記事では、リモートワーク環境のため、擬似 DNS を社内提供したお話をします。 エニグモ では、今年の2月頃から全社的にリモートワークを開始しました。 それに伴いインフラチームでは、リモートワークのネットワーク周りの対応を行いました。 エニグモ が運用しているサーバ群 エニグモ の運用するサーバは、データセンター内に構築したものと AWS のものがあります。 情シスの足立さん が、 SaaS 導入を進めて下さったためオフィス内にサーバはほぼありません。 サーバへの疎通経路 オフィス・リモート環境共に VPN 経由(+ ファイアウォール )で、サーバ群へアクセス可能です。 リモートワーク開始後のサーバアクセスの問題 リモートワーク開始直後から、ネットワーク設定に関するお問い合わせと、インフラチームの対応が発生しました。 VPN や Wifi の設定など、個々人のネットワーク設定の問題は、一度解決すれば再発することは滅多にありませんでしたが、 名前解決 は、何度もお問い合わせが頻発する厄介な課題でした。 なぜ、名前解決がリモートワークの課題だったのか コロナ禍以前 エニグモ では、オフィス環境からサーバへのアクセスを楽にするため、 ファイアウォール でオフィスの グローバルIP を許可し、非エンジニアスタッフの使用するサーバへはサーバの グローバルIP を指定してアクセス可能にしていました。 名前解決がリモートワークの課題となった原因 リモート環境からサーバへは、 VPN 経由でサーバのローカルIPを指定してアクセスする形でした。そのためオフィスとリモート環境では、サーバのアクセス情報が異なりました。 整理すると、以下の形になります。 職場 アクセス元のIP アクセス先のIP リモート環境 スタッフのお家 サーバのローカルIPを指定 オフィス オフィスのGIP サーバの グローバルIP を指定 リモートワーク開始直後は、採用や営業活動、検品作業のため出社が必要なスタッフも居て、シフトで出社日を回していました。出社したスタッフは、Hostsを社内用に修正せねばならず、名前解決関係のお問い合わせが継続していました。 DNS を導入すべきでしたが、 工数 がかかり難しいところでした。 名前解決の課題を解決 Hostsを一元管理できないかと思案していたところ、 SwitchHosts! を発見し利用することにしました。 SwitchHosts!とは Hostsファイルのサーバ管理が可能になる、端末のアプリです。 開発者は、サーバからHostsファイルをダウンロードして端末で使用する形となります。 SwitchHosts!のよかったところ 無料公開されているアプリケーションだったこと。 配布元にリモートサーバが使えて、Hostsファイルを集中管理できたこと。 Mac / Windows でも、同じUIで使えてサポートし易かったこと。 HostsのパーツごとのON/OFFができ、localでHostsを修正できて組み合わせられること。 端末のHostsのバックアップが取れること。 SwitchHosts!を使用した、擬似 DNS の運用 ユースケース に合わせたHostsファイルを作成し、データセンターにNginxコンテナを立てて配布できるようにしました。 これにより、オフィスでもリモート環境でも、簡単に DNS の機能を提供できるようになりました。 SwitchHosts!導入後の課題と解決方法 SwitchHosts!の導入後、名前解決が原因となる問題はさっぱりとなくなりました。 しかし「 AWS 環境における開発に伴い、Hostsの修正が都度必要になる」という課題が残りました。 原因は、以下2つでした。 スポット インスタンス のマシンが再作成された際、Hostsの修正が必要だった。 AWS 環境に、日々サーバが増設されるため、Hostsに追記が必要だった。 一時は、ダウンロード元のHostsファイルを手動で修正していましたが、 無駄 な作業でした。 そこで、Hosts情報の更新 スクリプト を作成し、Hostsファイルの自動更新を実現しました。 以下が、 スクリプト です。 #AWSのマシンには、${Prefix}タグと${Name}タグに、 #マシンのAZやサイト環境を命名規則として持たせています。 #!/usr/bin/env ruby require ' aws-sdk-ec2 ' ec2_client = Aws :: EC2 :: Client .new() #ARGVに、${Prefix}タグの値(マシンのAZやサイト環境を命名規則としたもの)を持たせています。 Prefix_list = ARGV f = { filters:[{ name : " tag:Prefix " , values : Prefix_list }]} reservations = ec2_client.describe_instances(f).inject([]) do | s , list | s += list.reservations end instances = reservations.each.inject([]) do | s , list | s += list.instances end instance_list = [] instances.each do | e | instance_list << { :instance_id => e.instance_id, :vpc_id => e.vpc_id, :public_ip => e.public_ip_address, :private_ip => e.private_ip_address, :name_tag => e.tags.find{| t | t.key == " Name " }.value, :prefix_tag => e.tags.find{| t | t.key == " Prefix " }.value.downcase, } end instance_list.each do | e | hostname = e[ :name_tag ].downcase #あとは、環境に合わせてよしなに加工してHostsファイルに出力します。 end まとめ DNS の機能を低コストで提供できてよかったです❗️ VPN への依存度も減らしたいので、 Google IAPを検証中です。 同じインフラチームの先輩社員 山口さんが、記事にされていました。 old schoolerなネットワークエンジニアがIAP Connectorを試してみた - エニグモ開発者ブログ 最後に 明日の記事の担当は、 情シスの足立さん です。お楽しみに。 株式会社 エニグモ 正社員の求人一覧 hrmos.co
今年組織作りに貢献するためにやったこと こんにちは。アプリケーション開発グループの穴澤です。 この記事は Enigmo Advent Calendar 2020 の 22 日目の記事です。 今年の振り返りとともに主に自分が去年から今年にかけて中途で入社した方にやってきたことを書いておきます。 これからチームに新しい人を迎える人や、 中途採用 入社する方、チームの組織づくりに興味がある方に読んでいただければとおもいます。 実際に取り組んだこと オンボーディング資料 開発手法、フロー・チェックリストの読み合わせ 1on1 1.オンボーディング資料 エニグモ では部署問わず、今年から中途で入社した社員向けのzoomでのオンボーディングが開始されました。 簡単にいうと、「各事業部が具体的になにをやっているか」「どんな取り組みをしているか」を中途入社した方に説明します。 入社された人は部署ごとに数回に分けて参加しています。 思えば今年の早い段階からリモートワークが推奨された状況で、中途入社問わず、自分の所属する部署以外の方と顔を見合わせて話をする機会というのが極端に減りました。例えば「先月入社した方ですね、XX部署のXXです!」といったようなコミュニケーションも、廊下やエレベータで顔をあわせたり、ミーティングの終わりですれ違う、お手洗いで顔を合わせるなどのタイミングで行われてきました。それぞれを取るととても些細なことですが、これらを積み重ねた何かが会社の社風や文化を 醸造 する一部になっていたんだなと感じます。 社風や文化をオンラインでも実現するために、このオンボーディング時に自分が紹介する担当として実践していることは以下の点です。細かい箇所は割愛しますが、リモートワークならでは、でしょうか。 説明資料に自部署の社員の氏名とSlack名の紐付け(顔とアイコンと名前とSlack名が一致しない問題) アプリ、インフラ、データ基盤、それぞれについての相談相手としてまずは覚えておいてほしい人をエピソードを添えて紹介(そんなに色々紹介されても覚えられない問題) BUYMA の仕組みで聞きたいこと、相談したいことがあったら、ここで相談してね、のチャットの紹介(何かを相談したくなってもどこだかわからない問題) 参加してくれた方とサービスエンジニアリング本部との具体的な関わり(紹介してもらったけど具体的にどういう関わりがあるんだろう問題) 2.開発手法、フロー・チェックリストの読み合わせ BUYMA というサービスが産声を上げて10年以上たちます。尖った技術を使っているところもあれば枯れているところ、 やや温かみのある仕組みのところもあり、中途で入社するエンジニアの方が躓くところもあるため、主に若手の方対象に週1回程度開発やリリースの際に 気をつけてほしい点を esa にまとめたフロー・チェックリストの読み合わせを行いました。 基本的に開発に関わる問題点は、所属しているチームのリーダーやメンターが答えてくれますが、 彼らに一点集中よりも、誰にきいても答えてもらえる、誰にきいても大丈夫、という雰囲気作りに自分も貢献したかったから です。ましてや、自分の所属するチーム以外のエンジニアと、躓きや悩みを共有する場所はいくつあってもいいと考えています。 時には 検索エンジン チームのエンジニアをゲストに迎えて検索周りの説明をしてもらったり、 チェックリストについては実際トラブルに遭遇したエンジニア に「なぜこのチェック項目があるのか」というのを語ってもらいました。 3.1on1 1on1は前職でも取り組んできたことですが、今年特に自分が取り組んできたことをあげます。 アジェンダ を用意する 序盤はなかなか用意できませんでしたが、後半は実施の1,2日前にいくつか アジェンダ を用意するようにしました。 4,5つ用意してその中のトピックで話が広がれば盛り上がり、割愛してできるだけ 「話が盛り上がる」「相手の指向性、興味関心がわかりそう」 な所を意識してすすめていきました。 1on1は「・・・最近どうですか」というやり方もありますが、1on1を実施するメンバーの身になって考えてみると 「なにを話せばいいんだ」「なにを言われるのか」と身構えられてしまうこともあります。明日はこういう事を話そう。を用意する方が 時間も有意義ですし、もしネガティブな話をされるということが事前にわかっていれば、自分が言いたいことも事前に用意するなど、お互いに準備ができ、結果的に少しの準備で得られる物が大きいと感じました。 会社全体の動きがわかるトピックを アジェンダ に混ぜて話す メンバーの仕事や取り組みと直接関係のない、会社の動きや施策。最近の売上。他部署に入社した人のこんなところが凄いなど。 会社の中での私達の部署の動き、施策以外の取り組みや課題など、自分と会社をつないでいる環境にどんなものがあり、どんな動きをしているか。中途入社の序盤だと、見えにくい組織の動きを定期的に アジェンダ に混ぜて話をするようにしています。   まとめ 今年は、いつもやっていること+αの「工夫する」注力をしました。特に、コロナ禍のリモートワークで感じやすい「孤独感」を和らげるための「皆さんは一人ではないですよ」ということを伝えるために、様々なできることを模索した年だった様に思います。取り組みの結果を 定量 的にはかることはできないので難しいですが、フィードバックを受けながら、来年も少しずつ改善していきたいと思います。 よいお年を。 明日の記事の担当は インフラグループ の 加藤 さんです。お楽しみに。 株式会社 エニグモ 正社員の求人一覧 hrmos.co
こんにちは、データアナリストの田中里澄です。 エニグモ ではデータ活用推進室という部署に所属しており、主に他部署が行った施策の効果検証を担当しています。 私は2020年11月に エニグモ に入社したので、今回はその転職活動の中でどうして今の職を選んだのか、また入社後どのような仕事をしているのかを紹介できればと思います。 前職は ライブ配信 サービスを運営している会社で、同じくデータアナリストとして働いていました。 転職理由について前職に対してネガティブなことは一切なく(むしろ今も大好きな会社です)、今の自分は別の会社で経験を積んだ方がいいと判断したためです。 なぜこの内容を書くのか? 理由は社外の方向けと社内の方向けでそれぞれあります。 社外の方にはデータアナリストの転職活動の参考にしてもらいたいため 社内の方にはまだ入社して日が浅い私の自己紹介になるためです。転職活動だけでなく、自分がどんな仕事をできるか/したいかについても書いています。 そもそもデータアナリストとは? ここであくまで自分の考えにはなりますが、データアナリストとはどんな仕事をするのか?を説明します。 読んでくださっている方に知っていただきたいですし、私が転職活動をしたときにも実際に自分の中で整理しました。 その整理のおかげで、無数にある求人(特にデータ〇〇という職種は最近多い)の中でピックアップする際や、面接時に自分がしたいことを説明する際に役立ちました。 データアナリストがどんな仕事をするのかを一言で表すと、「意思決定に必要な情報/ インサイト を提供する仕事」だと思っています。 データを分析する仕事じゃないの?という意見もあるかもしれませんが、分析はあくまで手段であり意思決定をすることが目的だと考えているのでこのような書き方をしました。 もしかするとコンサルという職種でイメージされる仕事に近いかもしれません。(余談ですが、思考法を勉強するためにコンサル向けの本を読むこともあります) 逆にいうと、こういった仕事をする人のことを「データアナリスト」と定義している会社が多いとも言えます。(本質的にはこちらが正しいかもしれません) どんな会社を求めていたのか? 上記で書いたデータアナリストとしての仕事ができることはもちろんですが、さらにそれを具体化した自分のしたい仕事について2点、またそれに関連した仕事の環境について2点合わせて4点求めていることがありました。 どんな意思決定に携わりたいのか 意思決定にも長期的な経営に関するものや日々のオペレーションに関するものなど色々な種類があります。 その中でも私はプロダクトの改善に関する意思決定に携わりたいと考えていました。 なぜならユーザーに喜んでもらえることに直結して実感しやすく、また分析するなかで人がどんな考えで行動するのかを垣間見ることができるためです。 どんなデータを分析するのか データは大きく分けると 定量 と定性の2種類に分けることができますが私はその両方を用いて分析したいと考えていました。 特に 定量 的なデータだけを扱うことが求められる場合もありますが、ユーザーの行動理由を知るためにはそれだけでは分からないことがたくさんあるためです。 他の職種(特に意思決定者)との連携が取りやすい 上の方で書いていたデータアナリストの仕事内容を遂行するためには他の職種の方との連携が大切です。 その中でも特に最終的に意思決定をする方との連携がとても大事だと考えていました。 分析をする前にはどんなことが分かれば意思決定ができるかを摺り合わせ、分析後にはそこで分かったことを共有し議論することで意思決定に付き添うためです。 分析をするためのデータ基盤が整っているか 整っているという言葉が曖昧ですが、例外はあれど日々の分析をする際の前処理やデータの準備に自分の持っているスキル以上のことを求められないことが基準でした。 もちろん後々はデータ基盤の構築などのスキルも伸ばしていきたいのですが、それをすぐに求められて本当にやりたいことに時間が使えないのはしんどいので求める要件に入っていました。 実際に入社してみて感じたこと 最終的に エニグモ 社に決めた理由としては、上記の求めていることを全て満たせていると選考中や内定をいただいた後の面談で感じたからです。 ここでは入ってみて実際に感じたことを紹介します。 分析結果を共有する際に、集計結果だけでなく考察や ネクス トアクションも求められまた歓迎されていい。 求めていた意思決定者との連携について、非常に取りやすいので分析の方針を立てやすい。 データ分析基盤について、基本的に必要なデータがBQにあって扱いやすい。ただし、それぞれのテーブルの定義などがわからないところやGAのデータについての扱い方を調べる必要があったりと、データはあるが扱い方は聞いたり調べたりが必要なので、今後入ってくる方のためにまだまだ整える余地がある。 入ってからどんな仕事をしているか 主に2種類の施策の振り返りとアプリの分析方針を立てる仕事をしています。 施策についてはどちらも私が入社する少し前から始めていたもので、毎月改善を加えてやっていこうという前提のものでした。 なので振り返りでどんな数字を見るのか?というところから任せてもらい、翌月の改善点の提案を出すところまで行っています。 アプリの分析方針については、私が入社するまでは売上というKGIを追いつつ、KPIとして何を追うべきかについて試行錯誤をしていたという状況です。 そこで今後追うべきKPIについて決める仕事を担っており、今は私の提案を元に議論しています。 総じていうと、現在自分のしたいと思っていた仕事ができており今後もまだまだやりたいことが溢れています。 コロナ禍で入社後のコミュニケーションは以前と比較すると難しいなとは感じておりますが、より一層迅速で納得感のある意思決定に貢献できるように日々の業務に努めていければと思っています。 株式会社 エニグモ 正社員の求人一覧 hrmos.co
こんにちは。 今年4月に エニグモ に入社したデータエンジニアの谷元です。 この記事は Enigmo Advent Calendar 2020 の 20日 目の記事です。 目次 はじめに そもそも同期処理とは? Airflowによる同期処理 検証時のコード サンプルをAirflow画面で見ると? 同期遅延なし時のAirflowログ 同期遅延あり時のAirflowログ 同期タイムアウト時のAirflowログ 所感 最後に はじめに コロナ禍の中、皆さんどのようにお過ごしでしょうか。 私はリモートワークを続けてますが、自宅のリモートデスクワーク環境をすぐに整えなかったため、薄いクッションで座りながらローテーブルで3ヶ月経過した頃に身体の節々で悲鳴をあげました。猫背も加速... さて、 エニグモ での仕事も半年以上経過し、データ分析基盤の開発運用保守やBI上でのデータ整備などを対応をさせていただいてますが、今回は社内で利用されているAirflowの 同期処理 の話をしたいと思います。 尚、こちらの記事を書くにあたり、同環境の過去記事 Enigmo Advent Calendar 2018 がありますので、良ければそちらもご覧ください。 そもそも同期処理とは? 例えば、以下のようなデータ分析基盤上でのETL処理があったとします。 処理1. 連携元DBのあるテーブルをDataLake(GCS)へファイルとして格納後、DWH(BigQuery)へロードする 処理2. DWH上のデータを加工後、外部へCSV連携する 上記の処理は順番に実行されないと必要なデータを含めた抽出ができなくなってしまい、外部へデータ連携できなくなります。そのためには処理1の正常終了確認後に処理2を実施するという、同期処理を意識した実装をする必要があります。 例だとシンプルですが、業務上では徐々にETL処理も増えていき、複雑化していきます。 こうした同期処理は、初めはなくても問題にならないことが多いのですが、徐々に処理遅延が発生してタイミングが合わなくなったり、予期せぬ一部の処理エラーが原因で関連する後続処理が全て意図せぬ状態で動き出してしまったりします。そうならないためにも、設計時点で同期について意識することが大事だと思います。 Airflowによる同期処理 Airflowでは ExternalTaskSensor を使用することで実装可能となります。 Airflowのソース上ではdependという用語が使われているので、Airflowの世界では「同期」ではなく、「依存」と呼んだ方が良いのかもしれません。適弁読み替えていただければ... では、Airflowでの同期検証用サンプルコードを作成してみましたので、実際に動かしながら検証したいと思います。尚、Airflowバージョンは1.10.10となります。 先ほどのETL処理を例にして、下記の内容で検証してみます。 実際のファイル出力やDBへのロード処理などはここでは割愛して、 DummyOperator に置き換えてます。 処理1. 連携元DBのあるテーブルをDataLake(GCS)へファイルとして格納後、DWH(BigQuery)へロードする dag_id: sample_db_to_dwh_daily schedule: 日次16:00 tables: TABLE_DAILY_1, TABLE_DAILY_2, TABLE_DAILY_3 処理2. DWH上のテーブルを用いてデータ加工後、外部ツールへCSV連携する dag_id: sample_dwh_to_file_daily_for_sync_daily_16 schedule: 日次17:00 tables: TABLE_DAILY_1, TABLE_DAILY_2, TABLE_DAILY_3 検証時のコード まずは処理1のサンプルコードになります。 from airflow.models import DAG from datetime import datetime from airflow.operators.dummy_operator import DummyOperator dag = DAG( dag_id='sample_db_to_dwh_daily', start_date=datetime(2020, 12, 1), schedule_interval='0 16 * * *' ) tables = ['TABLE_DAILY_1', 'TABLE_DAILY_2', 'TABLE_DAILY_3' ] for table_name in tables: db_to_dwh_operator = DummyOperator( task_id='db_to_dwh_operator_%s' % table_name, dag=dag ) terminal_operator = DummyOperator( task_id='terminal_operator_%s' % table_name, dag=dag, trigger_rule='none_failed' ) db_to_dwh_operator >> terminal_operator 次に処理2のサンプルコードです。 from airflow.models import DAG from airflow.operators.dummy_operator import DummyOperator from airflow.sensors.external_task_sensor import ExternalTaskSensor from airflow.utils.state import State from datetime import datetime, timedelta tables = ['TABLE_DAILY_1', 'TABLE_DAILY_2', 'TABLE_DAILY_3' ] def _dwh_to_file_operator(dag, table_name, depend_external_dag_id, depend_external_dag_execution_delta): dwh_to_file_operator = DummyOperator( task_id='dwh_to_file_operator_%s' % table_name, dag=dag ) sensors = [] sensors.append(ExternalTaskSensor( task_id='wait_for_sync_db_to_dwh_%s' % table_name, external_dag_id=depend_external_dag_id, external_task_id='terminal_operator_%s' % table_name, execution_delta=depend_external_dag_execution_delta, allowed_states=[State.SUCCESS, State.SKIPPED], dag=dag)) for sensor in sensors: sensor >> dwh_to_file_operator terminal_operator = DummyOperator( task_id='terminal_operator_%s' % table_name, dag=dag, trigger_rule='none_failed') dwh_to_file_operator >> terminal_operator args = { 'start_date': datetime(2020, 12, 3) } dag = DAG( dag_id='sample_dwh_to_file_daily_for_sync_daily', default_args=args, schedule_interval='0 17 * * *' ) for table_name in tables: _dwh_to_file_operator( dag=dag, table_name=table_name, depend_external_dag_id='sample_db_to_dwh_daily', depend_external_dag_execution_delta=timedelta(hours=1) ) サンプルをAirflow画面で見ると? 上記2つのDAGをAirflowのWebUIで見ると以下のようになります。 同期処理をするoperatorは「wait_for_sync_db_to_dwh 」です。図でも ExternalTaskSensor のアイコンになってますね。 今回は3テーブルあり、それぞれ並列処理を想定しているため、3つあります。 そして、それぞれ、該当するテーブルのterminal_operator処理完了を確認後、後続処理が実行されます。 では上記の同期処理がAirflowのログでどのように表示されるか見ていきたいと思います。 同期遅延なし時のAirflowログ まずは、既に sample_db_to_dwh_daily が完了していた場合です。 3テーブル毎のログを載せておきます。 TABLE_DAILY_1 ~~ DAG: sample_dwh_to_file_daily_for_sync_daily Task Instance: wait_for_sync_db_to_dwh_TABLE_DAILY_1 2020-12-07 17:00:00 ~~ [2020-12-09 02:00:09,833] {taskinstance.py:669} INFO - Dependencies all met for <TaskInstance: sample_dwh_to_file_daily_for_sync_daily.wait_for_sync_db_to_dwh_TABLE_DAILY_1 2020-12-07T17:00:00+00:00 [queued]> [2020-12-09 02:00:09,840] {taskinstance.py:669} INFO - Dependencies all met for <TaskInstance: sample_dwh_to_file_daily_for_sync_daily.wait_for_sync_db_to_dwh_TABLE_DAILY_1 2020-12-07T17:00:00+00:00 [queued]> [2020-12-09 02:00:09,841] {taskinstance.py:879} INFO - -------------------------------------------------------------------------------- [2020-12-09 02:00:09,841] {taskinstance.py:880} INFO - Starting attempt 1 of 1 [2020-12-09 02:00:09,841] {taskinstance.py:881} INFO - -------------------------------------------------------------------------------- [2020-12-09 02:00:09,848] {taskinstance.py:900} INFO - Executing <Task(ExternalTaskSensor): wait_for_sync_db_to_dwh_TABLE_DAILY_1> on 2020-12-07T17:00:00+00:00 [2020-12-09 02:00:09,851] {standard_task_runner.py:53} INFO - Started process 48063 to run task [2020-12-09 02:00:09,905] {logging_mixin.py:112} INFO - Running %s on host %s <TaskInstance: sample_dwh_to_file_daily_for_sync_daily.wait_for_sync_db_to_dwh_TABLE_DAILY_1 2020-12-07T17:00:00+00:00 [running]> ip-123-456-78-910.dokoka_toku.compute.internal [2020-12-09 02:00:09,919] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_daily.terminal_operator_TABLE_DAILY_1 on 2020-12-07T16:00:00+00:00 ... [2020-12-09 02:00:09,921] {base_sensor_operator.py:123} INFO - Success criteria met. Exiting. [2020-12-09 02:00:09,924] {taskinstance.py:1065} INFO - Marking task as SUCCESS.dag_id=sample_dwh_to_file_daily_for_sync_daily, task_id=wait_for_sync_db_to_dwh_TABLE_DAILY_1, execution_date=20201207T170000, start_date=20201208T170009, end_date=20201208T170009 [2020-12-09 02:00:19,834] {logging_mixin.py:112} INFO - [2020-12-09 02:00:19,834] {local_task_job.py:103} INFO - Task exited with return code 0 TABLE_DAILY_2 ~~ DAG: sample_dwh_to_file_daily_for_sync_daily Task Instance: wait_for_sync_db_to_dwh_TABLE_DAILY_2 2020-12-07 17:00:00 ~~ [2020-12-09 02:00:09,831] {taskinstance.py:669} INFO - Dependencies all met for <TaskInstance: sample_dwh_to_file_daily_for_sync_daily.wait_for_sync_db_to_dwh_TABLE_DAILY_2 2020-12-07T17:00:00+00:00 [queued]> [2020-12-09 02:00:09,839] {taskinstance.py:669} INFO - Dependencies all met for <TaskInstance: sample_dwh_to_file_daily_for_sync_daily.wait_for_sync_db_to_dwh_TABLE_DAILY_2 2020-12-07T17:00:00+00:00 [queued]> [2020-12-09 02:00:09,839] {taskinstance.py:879} INFO - -------------------------------------------------------------------------------- [2020-12-09 02:00:09,840] {taskinstance.py:880} INFO - Starting attempt 1 of 1 [2020-12-09 02:00:09,840] {taskinstance.py:881} INFO - -------------------------------------------------------------------------------- [2020-12-09 02:00:09,846] {taskinstance.py:900} INFO - Executing <Task(ExternalTaskSensor): wait_for_sync_db_to_dwh_TABLE_DAILY_2> on 2020-12-07T17:00:00+00:00 [2020-12-09 02:00:09,848] {standard_task_runner.py:53} INFO - Started process 48062 to run task [2020-12-09 02:00:09,902] {logging_mixin.py:112} INFO - Running %s on host %s <TaskInstance: sample_dwh_to_file_daily_for_sync_daily.wait_for_sync_db_to_dwh_TABLE_DAILY_2 2020-12-07T17:00:00+00:00 [running]> ip-123-456-78-910.dokoka_toku.compute.internal [2020-12-09 02:00:09,916] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_daily.terminal_operator_TABLE_DAILY_2 on 2020-12-07T16:00:00+00:00 ... [2020-12-09 02:00:09,918] {base_sensor_operator.py:123} INFO - Success criteria met. Exiting. [2020-12-09 02:00:09,921] {taskinstance.py:1065} INFO - Marking task as SUCCESS.dag_id=sample_dwh_to_file_daily_for_sync_daily, task_id=wait_for_sync_db_to_dwh_TABLE_DAILY_2, execution_date=20201207T170000, start_date=20201208T170009, end_date=20201208T170009 [2020-12-09 02:00:19,832] {logging_mixin.py:112} INFO - [2020-12-09 02:00:19,832] {local_task_job.py:103} INFO - Task exited with return code 0 TABLE_DAILY_3 ~~ DAG: sample_dwh_to_file_daily_for_sync_daily Task Instance: wait_for_sync_db_to_dwh_TABLE_DAILY_3 2020-12-07 17:00:00 ~~ [2020-12-09 02:00:09,829] {taskinstance.py:669} INFO - Dependencies all met for <TaskInstance: sample_dwh_to_file_daily_for_sync_daily.wait_for_sync_db_to_dwh_TABLE_DAILY_3 2020-12-07T17:00:00+00:00 [queued]> [2020-12-09 02:00:09,837] {taskinstance.py:669} INFO - Dependencies all met for <TaskInstance: sample_dwh_to_file_daily_for_sync_daily.wait_for_sync_db_to_dwh_TABLE_DAILY_3 2020-12-07T17:00:00+00:00 [queued]> [2020-12-09 02:00:09,837] {taskinstance.py:879} INFO - -------------------------------------------------------------------------------- [2020-12-09 02:00:09,837] {taskinstance.py:880} INFO - Starting attempt 1 of 1 [2020-12-09 02:00:09,837] {taskinstance.py:881} INFO - -------------------------------------------------------------------------------- [2020-12-09 02:00:09,844] {taskinstance.py:900} INFO - Executing <Task(ExternalTaskSensor): wait_for_sync_db_to_dwh_TABLE_DAILY_3> on 2020-12-07T17:00:00+00:00 [2020-12-09 02:00:09,847] {standard_task_runner.py:53} INFO - Started process 48061 to run task [2020-12-09 02:00:09,901] {logging_mixin.py:112} INFO - Running %s on host %s <TaskInstance: sample_dwh_to_file_daily_for_sync_daily.wait_for_sync_db_to_dwh_TABLE_DAILY_3 2020-12-07T17:00:00+00:00 [running]> ip-123-456-78-910.dokoka_toku.compute.internal [2020-12-09 02:00:09,915] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_daily.terminal_operator_TABLE_DAILY_3 on 2020-12-07T16:00:00+00:00 ... [2020-12-09 02:00:09,917] {base_sensor_operator.py:123} INFO - Success criteria met. Exiting. [2020-12-09 02:00:09,920] {taskinstance.py:1065} INFO - Marking task as SUCCESS.dag_id=sample_dwh_to_file_daily_for_sync_daily, task_id=wait_for_sync_db_to_dwh_TABLE_DAILY_3, execution_date=20201207T170000, start_date=20201208T170009, end_date=20201208T170009 [2020-12-09 02:00:19,831] {logging_mixin.py:112} INFO - [2020-12-09 02:00:19,831] {local_task_job.py:103} INFO - Task exited with return code 0 注目して欲しい行は下記となります。 ※ 他テーブルのログも同じですので、ここから先は記載を割愛します [2020-12-09 02:00:09,919] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_daily.terminal_operator_TABLE_DAILY_1 on 2020-12-07T16:00:00+00:00 ... これが同期処理のログになります。 今回は既に正常終了していたため、1回の確認しか行われておらず、その後、後続処理も含めて正常終了してることが分かります。 同期遅延あり時のAirflowログ 次に前提のタスクが遅延して正常終了した場合のAirflowログもみていきたいと思います。 ~~~ DAG: sample_dwh_to_file_daily_for_sync_daily Task Instance: wait_for_sync_db_to_dwh_TABLE_DAILY_1 2020-12-08 17:00:00 ~~~ [2020-12-10 02:00:04,174] {taskinstance.py:669} INFO - Dependencies all met for <TaskInstance: sample_dwh_to_file_daily_for_sync_daily.wait_for_sync_db_to_dwh_TABLE_DAILY_1 2020-12-08T17:00:00+00:00 [queued]> [2020-12-10 02:00:04,182] {taskinstance.py:669} INFO - Dependencies all met for <TaskInstance: sample_dwh_to_file_daily_for_sync_daily.wait_for_sync_db_to_dwh_TABLE_DAILY_1 2020-12-08T17:00:00+00:00 [queued]> [2020-12-10 02:00:04,182] {taskinstance.py:879} INFO - -------------------------------------------------------------------------------- [2020-12-10 02:00:04,182] {taskinstance.py:880} INFO - Starting attempt 1 of 1 [2020-12-10 02:00:04,182] {taskinstance.py:881} INFO - -------------------------------------------------------------------------------- [2020-12-10 02:00:04,189] {taskinstance.py:900} INFO - Executing <Task(ExternalTaskSensor): wait_for_sync_db_to_dwh_TABLE_DAILY_1> on 2020-12-08T17:00:00+00:00 [2020-12-10 02:00:04,192] {standard_task_runner.py:53} INFO - Started process 21683 to run task [2020-12-10 02:00:04,245] {logging_mixin.py:112} INFO - Running %s on host %s <TaskInstance: sample_dwh_to_file_daily_for_sync_daily.wait_for_sync_db_to_dwh_TABLE_DAILY_1 2020-12-08T17:00:00+00:00 [running]> ip-123-456-78-910.dokoka_toku.compute.internal [2020-12-10 02:00:04,259] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_daily.terminal_operator_TABLE_DAILY_1 on 2020-12-08T16:00:00+00:00 ... [2020-12-10 02:01:04,322] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_daily.terminal_operator_TABLE_DAILY_1 on 2020-12-08T16:00:00+00:00 ... [2020-12-10 02:02:04,385] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_daily.terminal_operator_TABLE_DAILY_1 on 2020-12-08T16:00:00+00:00 ... [2020-12-10 02:03:04,448] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_daily.terminal_operator_TABLE_DAILY_1 on 2020-12-08T16:00:00+00:00 ... [2020-12-10 02:04:04,511] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_daily.terminal_operator_TABLE_DAILY_1 on 2020-12-08T16:00:00+00:00 ... (省略) [2020-12-10 10:27:29,163] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_daily.terminal_operator_TABLE_DAILY_1 on 2020-12-08T16:00:00+00:00 ... [2020-12-10 10:28:29,226] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_daily.terminal_operator_TABLE_DAILY_1 on 2020-12-08T16:00:00+00:00 ... [2020-12-10 10:29:29,273] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_daily.terminal_operator_TABLE_DAILY_1 on 2020-12-08T16:00:00+00:00 ... [2020-12-10 10:30:29,298] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_daily.terminal_operator_TABLE_DAILY_1 on 2020-12-08T16:00:00+00:00 ... [2020-12-10 10:31:29,360] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_daily.terminal_operator_TABLE_DAILY_1 on 2020-12-08T16:00:00+00:00 ... [2020-12-10 10:31:29,363] {base_sensor_operator.py:123} INFO - Success criteria met. Exiting. [2020-12-10 10:31:29,366] {taskinstance.py:1065} INFO - Marking task as SUCCESS.dag_id=sample_dwh_to_file_daily_for_sync_daily, task_id=wait_for_sync_db_to_dwh_TABLE_DAILY_1, execution_date=20201208T170000, start_date=20201209T170004, end_date=20201210T013129 [2020-12-10 10:31:33,698] {logging_mixin.py:112} INFO - [2020-12-10 10:31:33,698] {local_task_job.py:103} INFO - Task exited with return code 0 先ほどのPoking行がログに表示され続けていることが分かります。今回は途中でタスクを手動で動かして正常終了させました。 尚、Pokingの間隔はExternalTaskSensorの引数で poke_interval を設定すると変更ができました。ソースを見るとデフォルトは60秒のようです。ログとも一致してますね。 同期 タイムアウト 時のAirflowログ 業務では非機能要件も大事だと思います。 Airlfowでは、ExternalTaskSensorの引数で timeout があるようです。 こちらで タイムアウト (default: 1週間ですかね、長っ)を適切に設定して、エラー検知をしてみたいと思います。 sample_dwh_to_file_daily_for_sync_hourly/wait_for_sync_db_to_dwh_TABLE_HOURLY_1/2020-12-09T17:00:00+00:00/4.log. [2020-12-11 18:21:14,539] {taskinstance.py:669} INFO - Dependencies all met for <TaskInstance: sample_dwh_to_file_daily_for_sync_hourly.wait_for_sync_db_to_dwh_TABLE_HOURLY_1 2020-12-09T17:00:00+00:00 [queued]> [2020-12-11 18:21:14,551] {taskinstance.py:669} INFO - Dependencies all met for <TaskInstance: sample_dwh_to_file_daily_for_sync_hourly.wait_for_sync_db_to_dwh_TABLE_HOURLY_1 2020-12-09T17:00:00+00:00 [queued]> [2020-12-11 18:21:14,551] {taskinstance.py:879} INFO - -------------------------------------------------------------------------------- [2020-12-11 18:21:14,551] {taskinstance.py:880} INFO - Starting attempt 4 of 9 [2020-12-11 18:21:14,552] {taskinstance.py:881} INFO - -------------------------------------------------------------------------------- [2020-12-11 18:21:14,563] {taskinstance.py:900} INFO - Executing <Task(ExternalTaskSensor): wait_for_sync_db_to_dwh_TABLE_HOURLY_1> on 2020-12-09T17:00:00+00:00 [2020-12-11 18:21:14,568] {standard_task_runner.py:53} INFO - Started process 84130 to run task [2020-12-11 18:21:14,625] {logging_mixin.py:112} INFO - Running %s on host %s <TaskInstance: sample_dwh_to_file_daily_for_sync_hourly.wait_for_sync_db_to_dwh_TABLE_HOURLY_1 2020-12-09T17:00:00+00:00 [running]> ip-123-456-78-910.dokoka_toku.compute.internal [2020-12-11 18:21:14,639] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_hourly.terminal_operator_TABLE_HOURLY_1 on 2020-12-10T16:00:00+00:00 ... [2020-12-11 18:22:14,701] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_hourly.terminal_operator_TABLE_HOURLY_1 on 2020-12-10T16:00:00+00:00 ... [2020-12-11 18:23:14,764] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_hourly.terminal_operator_TABLE_HOURLY_1 on 2020-12-10T16:00:00+00:00 ... [2020-12-11 18:24:14,828] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_hourly.terminal_operator_TABLE_HOURLY_1 on 2020-12-10T16:00:00+00:00 ... [2020-12-11 18:25:14,892] {external_task_sensor.py:117} INFO - Poking for sample_db_to_dwh_hourly.terminal_operator_TABLE_HOURLY_1 on 2020-12-10T16:00:00+00:00 ... [2020-12-11 18:25:14,898] {taskinstance.py:1145} ERROR - Snap. Time is OUT. Traceback (most recent call last): File "/opt/airflow/venv/lib/python2.7/site-packages/airflow/models/taskinstance.py", line 983, in _run_raw_task result = task_copy.execute(context=context) File "/opt/airflow/venv/lib/python2.7/site-packages/airflow/sensors/base_sensor_operator.py", line 116, in execute raise AirflowSensorTimeout('Snap. Time is OUT.') AirflowSensorTimeout: Snap. Time is OUT. [2020-12-11 18:25:14,899] {taskinstance.py:1202} INFO - Marking task as FAILED.dag_id=sample_dwh_to_file_daily_for_sync_hourly, task_id=wait_for_sync_db_to_dwh_TABLE_HOURLY_1, execution_date=20201209T170000, start_date=20201211T092114, end_date=20201211T092514 [2020-12-11 18:25:15,070] {logging_mixin.py:112} INFO - [2020-12-11 18:25:15,070] {local_task_job.py:103} INFO - Task exited with return code 1 hourlyに変更して実施したログですが、「Snap. Time is OUT.」と良い感じ(?)にエラーとなってくれました。 業務上では、お目にかかりたくないログ内容ですが... 他にも色々あるようですが、この辺りを抑えておけば基本的な使い方は抑えたことになるかと思います。 所感 実際にAirflow同期処理をやってみて思ったのですが、 同期を取る対象のoperatorをどれにするか 同期を取るoperatorの時刻差はどれだけあるか 非機能要件にあった タイムアウト 設定で適切にエラーで落とそう 複雑になるとDAG間の関係性がわかるグラフをWebUIでサクッとみたい が、気になりました。 「同期を取る対象のoperator」は「terminal_operator_<テーブル名>」としました。 ダミー処理なので冗長にはなってしまいますが、各並列処理毎に加えておいたほうがDAG修正時の同期影響を意識しなくて良くなるのかなと思ったためです。 また、DummyOperator利用時に 「trigger_rule='none_failed'」の引数を付け加えないと、先に実行されたケースもありましたので注意が必要そうです。 「同期を取るoperatorの時刻差」ですが、何度も繰り返してると混乱してしまう可能性もあるので、テストでも十分に気をつけて対応しないといけないですよ(to自分)。実際の業務でもtimedeltaで指定する時刻に誤りをテストで見落としてしまい、その結果、リリース後に同期処理が想定時間通りに終わらず遅延してしまい、外部連携のタイミングに間に合わなくなり問題になってしまいました...。 今回の検証例は、お互いdaily実行だったのですが、頻度が異なると慎重な対応が求められそうです。 ただ、この辺の制御はAirflowのコアな制御なので、今後、利用者が意識しないで済むようにdag_idとオプション引数で渡したら、同期を取ってくれるような機能があると良いなとも思いました。利用頻度が多くなると、そういった実装も検討しないといけないのかもしれません。 あとは、WebUI上にてDAGの関係性がグラフで見れると、意図したoperatorで同期が取れているかの確認がやりやすいと思いました。 見方が分からないだけなのか、未実装なのか把握できてないのですが、WebUIをみる限り今回のAirflowのバージョン1.10.10ではなさそうです。 最後に Airflowでの同期処理について少しでも伝わればと思い、このテーマで記事を書いてみました。 本記事を通して少しでもイメージを掴めて頂けますと幸いです。 他にも面白そうな機能はあると思いますので、また、機会があれば投稿したいと思います。 私からは以上となります。最後までお読み頂きありがとうございました。 明日の記事の担当はエンジニアの高山さんです。お楽しみに。 株式会社 エニグモ 正社員の求人一覧 hrmos.co
こんにちは。 BUYMA の検索やデータ基盤周りを担当している竹田です。 この記事は Enigmo Advent Calendar 2020 の19日目の記事です。 エニグモ に入社して GCP や AWS といった クラウド サービスを利用することが多くなり、日々刺激を受けながら業務に従事しております。 その中でも Kubernetes のようにシステムを「宣言的」に定義するモデルに技術進化の恩恵を感じており、自分の体験も踏まえて、 クラウド サービスで Kubernetes を一般利用するに至るまでどういう歴史的経緯があるのかを辿ってみたくなりました。 (実際 Kubernetes で編集するファイルも「 マニフェスト (≒宣言)ファイル」といいますね) なお、記事内容には主観を含む部分や、内容を簡素化するため端折っている部分もありますので、あらかじめご了承ください。 chroot まずは Kubernetes で管理されるコンテナの歴史を探ってみたいと思います。 コンテナ技術の前身は1979年に登場した chroot と言われています。 chroot で特定階層以下をroot ディレクト リとすることで、システムとの分離を実現することができます。 変更した ディレクト リ配下には動作中のOSと同じ ディレクト リ構造を実体として持つ必要があり、利用シーンとしては ssh ログインしたユーザに ディレクト リ移動の制限をかけるような場合でしょうか。個人としてはあまり使った記憶はありません。 少なくともリソースの制限を設けることや ディレクト リ階層をイメージのような形で持つことはできませんでした。 コンテナのベース技術 コンテナのベースとなる技術は2000年に FreeBSD から発表された FreeBSD jail という機構です。 カーネル に手を加えてOSレベルでの仮想化機構を実現しており、 ファイルシステム やネットワークなどの分離ができるようです。 この FreeBSD jailは知らなかったのですが、当時は業務で Solaris を利用しており、すでに2005〜2006年頃には Solaris コンテナという概念が出てきていたことを記憶しています。 また、この頃はまだあまり Linux は表舞台には出てきていませんでした。10数年前当時は商用製品であることが重視されていたと思います。 当時の Linux は Solaris などの 商用UNIX と比較すると OSとしての安定性が高くなかった OOM Killerに悩まされたこともしばしば 比較的 スループット が重視されていた とりあえずタスク間がフェアじゃなかった リソース管理や デバッグ 面が弱かった など こういった背景もあり、ミッションクリティカルなシステムでは 商用UNIX を選択するのが一般的でした。 ただ、2000年台初頭から、 OSS(Open Source Software) が台頭してきました。 開発者のニーズにマッチしていたことや、 Red Hat社 のようなビジネスモデルを確立できたことなどが、 OSS を後押しした背景にあると思います。 ちなみにコンテナが出てくるまでの仮想化技術の筆頭は VM(VirtualMachine) ですが、本記事では割愛します。 cgroups Linux におけるコンテナは cgroups が根幹となっています。 カーネル の機構によりプロセスをグループ単位にして、そのグループ内でリソース配分や制限を行う技術です。 少しだけcgroupsには関わっていたこともあり、 Linux が 商用UNIX に追いつきそうだなと感じていた頃でした(おそらく2008〜2009年頃)。 ただし、設定方法が特殊であり、一般利用するにはかなり難易度が高いものでした。 この後、cgroupsを管理できる LXC というソフトウェアが出ています。 ポータビリティ性が低かったのか、使い勝手が良くなかったのか、、なぜかあまり脚光は浴びていませんね。 Docker 言わずと知れたDocker社が開発したコンテナを管理するソフトウェアです。 自分の印象では利用者がcgroupsを意識することなく利用でき、それをコードベースで管理できる柔軟なラッパー、、という解釈です。 ざっくりと表現すると Linux では以下のイメージです。 近年のCPUパフォーマンスや SSD 等によるI/Oパフォーマンスの向上、かつ VM よりも遥かに軽量でポータビリティ性が高く、簡素に利用できるということもあり、主に開発者の間で一気に広まったように思います。 Kubernetes Google 社が2013年に発表した コンテナオーケストレーションツール です。 この当時すでに大量のシステムをコンテナ化していた事実に衝撃を受けたのを覚えています。 kubernetes は紆余曲折ありましたが、現在の標準になっているものと思います。 宣言的な記載により、ブルーグリーンデプロイメントやローリングアップデートが非常に簡素に実現できるようになりました。 宣言的 システムがどういう状態にあるべきかを記述する 問題があった場合もその状態になるよう再構成する 内部アプリの修正やバージョンアップは、修正適用済みコンテナに置き換える 解釈は難しいです。今こうある状態が大事、というニュアンスでしょうか。 対義語としては命令的、ということなので、こうしてああしたらその状態になる、というニュアンスですかね。 思えば、トラブル発生の際はシステムを修復・復旧させることが一般的でした。 ステートレスシステム(状態維持が不要なシステム)では、もはや宣言的アプローチが一般的になっていると思います。 コンテナ、および Kubernetes のサービス利用 コンテナ技術は開発者にとっては非常に都合の良いものでしたが、実サービスでの利用では、となると敷居が高かったように思います。 自分の当時の立場で記載すると、以下のような理由からでした。 枯れた技術ではない リソース分割は VM で十分満足できている Kubernetes をオンプレ環境で管理するのはハードルが高い 新技術を使いたいという理由では上長(ひいては経営層)を納得させられない クラウド サービスによるサポート 各 クラウド サービスでのサポート開始により、サービス利用の敷居が一気に下がったものと思います。 Google GKE、 Amazon EKS、 Microsoft AKS などが挙げられます。 コンテナ オーケストレーション では大量のシステムを管理・運用することに長けており、 クラウド サービスの柔軟性と非常に相性が良いと思います。 マネージドな Kubernetes により管理を簡素化できる サポートを受けられる コスト面も使った分だけ 。。となると使わない手はないだろうな、という印象です。 終わりに 実際にはもっと複雑な背景があるとは存じますが、概要としてはこのような流れかなと思います。 「宣言的」概念はシステムのあるべき形だと感じつつも、まだステートレスなシステムでのベストプ ラク ティスなのかなという感触です。 ステートフルシステム(状態維持が必要なシステム、例えばDBサーバなど)でも利用はできますが、まだちょっと厳しいので今後より良い概念・機能が出てくるのかな、という期待があります。 おじさんエンジニアとしては過去に思いを馳せつつも、これからも技術の ビッグウェーブ には乗っていきたいので日々勉強・キャッチアップが本当に大事ですね。 最後まで読んでいただきありがとうございました。 明日の記事担当はデータエンジニアの谷元さんです。よろしくお願いします! 株式会社 エニグモ 正社員の求人一覧 hrmos.co
お疲れ様です。インフラチームの山口です。 この記事は Enigmo Advent Calendar 2020 の18日目の記事となります。 2020年はコロナ禍でほぼ全社的にリモートワークになったこともあり、 前職のネットワークエンジニアだった頃のWANやビデオ会議の思い出を思い返す機会が多い一年でした。 強く思い出に残っているのは大概、障害と機器の不具合などのトラブル系しかなく、それだけでお腹いっぱいになる感じです。 話は変わりますが、 アドベントカレンダー は業務から少しずらした内容で書くポリシーなので、現行の業務とはあまり関係ない、リモートワークに伴ってよく起こりがちなネットワークのごまかしの話をします。 今年、私の業務何やってたかなというとEKSの運用サポートとオンプレの保守対応が多かったので、業務からずれた内容をエイヤで書き下します。 1.はじめに 本記事はオフィスおよびオンプレミスのDCのPublicIPのみを ホワイトリスト に登録したS3 バケット 上の画像を、リモートワーク下の各ご自宅から閲覧する方法を考えた際の検討事項を整理したものです。 IAP Connectorをタイトルに入れていますが、本記事内ではZero Trust的な機能は使用しません。 IAP ConnectorはGKEに簡単にデプロイできるNAT箱として使っています。 そのため、Beyond Corp Remote Access やCloud IAPについても本記事では特に触れません。 2.問題設定と前提条件 問題設定とその問題を解くにあたっての前提条件(おもに弊社の VPN 関連の構成など)を説明します。 まず、何をやりたいかの問題設定を概説し、その後に付随する前提条件を説明します。 2-1.問題設定 解きたい問題を以下に記載します。 オフィスとDCのPublicIPを ホワイトリスト に登録したS3 バケット 上の画像を、リモートワーク下の自宅から閲覧できるようにしたい エンジニア以外のメンバーも閲覧できるようにしたい 2-2. 前提条件 2-1で説明した問題設定に加えて方法検討の際の制約になりうるNW構成などを思いつく限りに記載します。以降の節でなんやかんや本節の理由を参照して、対応案を絞っていきます。 オンプレミスのDCにある VPN サーバで L2TP / IPSec を終端する VPN 接続後のクライアントPCの経路はスプリットトンネリング(トンネルインタフェースにはデフォルトルート向けてない) クライアントPCは、エンジニアは Mac だが非エンジニアは Windows VPN サーバからクライアントに経路をpushすることは可能 オンプレミス環境は パブリッククラウド に移行中のため余計なリソースを増やしたくない また、概要を簡単に記載した図を以下に示します。 図1 3.方法検討 検討した方法を以下表と図に記載します。 方法は3種類に大別されます。タイトルにIAP Connectorを試してみたと記載しているタイトルの通り最終的には、3bを選択することになるのは明白ですが、建前として各案のPros/Consを考えていきます。 案 小項目 方法 案1.愚直案 S3 バケット のIPアクセス制限に各自の自宅のPublicIPを登録する 案2.ルーティングでごまかし案 2a VPN サーバでS3向けの経路をPushしDC経由にする 2b sshuttleなどを使用しクライアント側でルーティングを調整する 案3.Proxy建てる案 3a DCにProxyを建てる 3b IAP ConnectorをProxyとして建てる&S3 バケット 側の ホワイトリスト に追加 図2 案1.愚直案 S3 バケット 側で愚直に各ご自宅のPublicIPを ホワイトリスト 登録すればいいだけというのは、そのとおりでそれで済むならこの記事をグダグダ書いてる意味ないじゃんという形になってしまうので、半ば無理矢理感はありますが一旦は却下します。 これは人によって意見分かれそうですが、プライベートで契約しているPublicIPの情報をCloudFormationのテンプレートなどに書いて、Gitの履歴に残したくなさがあるので個人的には微妙かなという印象が強いです。 pros 一番シンプル cons アクセスする社員の数増えたら運用手間かもしれない。 そもそも、ご自宅が固定IPとは限らないケースもある。 現状はCloudFormationでS3 バケット 管理しているが、個人の自宅のPublicIPをテンプレートに残してしまうのって良いのか? なんか嫌じゃない? 案2. ルーティングでごまかし案 ルーティングでごまかし案は2a、2bに分かれます。 2aと2bの違いはルーティングの調整を VPN サーバ側で行うか、クライアントのPC側で行うかの違いです。 案2での基本方針は以下からS3で使用されるPublicIPのレンジを確認してそのIPレンジ向けの通信をDC経由にします。 AWS IP address ranges 2a、2bのpros/consを記載します。 正直自分しか使わないのなら他の環境に影響少なくて手軽な2bでローカルのPCでルーティングいじってごまかすぞ、となるのですが、 今回の要件的には他メンバーにも展開する可能性があるので却下します。 記事まとめている途中で、わざわざS3のPublicIPのレンジ全部経路切らなくても DNS 引いた結果をhostsに追加&それ向けのホストルートをトンネルインタフェースに切れば良いんじゃないかと思いましたが他の人に展開するという観点ではやっぱり却下です。 2a: VPN サーバでS3向けの経路をPushしDC経由にする pros クライアントPC側の作業は楽 cons この要件のためだけに VPN サーバの経路調整したくない S3のPublicIPのレンジをすべてDC経由にした場合に意図しない影響って本当に出ないんだっけ? 2b: sshuttleなどを使用しクライアント側でルーティングを調整する pros VPN サーバ側の設定を変えなくて済む 当該S3 バケット を参照したい人だけDC経由になるので、2aより意図しない副作用は少なそう cons エンジニアならローカルで経路調整したりできそうだけど、非エンジニアの人には難しいかもしれない 案3. Proxy建てる案 Proxy建てる案はどこにProxyを建てるかどうかで3a、3bに分かれます。 3aはDCにProxyを建てる案です。DCにnginxのProxy建ててアクセスしている実績はあるのですが、オンプレのリソースは極力減らしていっている状況なので却下します。 3a: DCにProxyを建てる pros VPN のルーティングは調整しなくて済む 同様のProxyはDCにも何台かすでにある cons DCに余計なリソースが増える 運用手間 3b: IAP ConnectorをProxyとして建てる&S3 バケット 側の ホワイトリスト に追加 pros VPN のルーティングは調整しなくて済む Deployment Managerでデプロイは楽にできそう cons 動作確認は必要 GKEの クラスタ がデプロイされるのでコスト面は大丈夫? 方法決定 一旦案をまとめます。 5案だしましたが、以下の3案が確度高く現実的には行けそうな感じがします。 案1、案2bはこの検討時点では動作することが分かっていたので、案3bの構成の検討を次節で行います。 案3bの検討事項ではコスト面と動作確認がconsとして上がっていますが、本記事ではとりあえず動作確認だけを行います。 案1.愚直案 とりあえずはこれできるけど面白みはない 案2b: sshuttleなどを使用しクライアント側でルーティングを調整する エンジニアは拾えるかつ楽だけど非エンジニアは拾えない 案3b: IAP ConnectorをProxyとして建てる&S3 バケット 側の ホワイトリスト に追加 検証はした方が良いが意外と楽にできそう 4.リソース作成・動作確認 本節では 案3b: IAP ConnectorをProxyとして建てる&S3バケット側のホワイトリストに追加 の説明を簡潔に行います。 IAP Connectorのデプロイは基本的には以下公式の手順に従います。 オンプレミス アプリでの IAP の有効化 最終的な構成図を以下に示します。 構成上、Deployment Managerのテンプレートでは、IAP ConnectorのNAT後のPublicIPとGCLBに アサイ ンするPublicIPも同じテンプレートでデプロイされてしまうようですが、以下の理由から、PublicIPはコンソールでリソースを作成しそれをテンプレートから参照するように修正しました。また、とりあえずぱっとデプロイできて動きだけ確認できればいいので、Terraformで作成する選択肢は取らず、雑にDeployment Managerのテンプレート一枚で作成しました。 GKE クラスタ はなにか問題が出たら潰して再構築する程度の温度感の運用を想定 ambassadorのPodの問題判別や クラスタ 運用は極力しない手抜き前提 PublicIPはGKE クラスタ と合わせて潰れてしまうとS3 バケット の ホワイトリスト 設定や DNS 設定が手間 所謂ライフサイクル異なるリソースは別テンプレートにというやつ(今回PublicIPは CLI でリソース作ったけれど) 図3 5.まとめ 本記事では、IAP Connectorを容易にデプロイできるNAT箱として利用しました。 Cloud IAP側でZero Trust的な制御を入れたとしても、IAP ConnectorからS3 バケット のアクセス制御は昔ながらのIP制限方式になってしまっているなど、ツッコミどころや深堀りする余地はありますが、 S3 バケット の前段に設置する構成については、一応当初の目的通りの動作を確認できました。 また、この記事とは関係ない半ば余談の愚痴ですが、2020年の夏頃にIAP Connectorを検証したのですが、プロキシ先からのレスポンスの書き換えができなくて困って、IAP Connectorに対する熱が下がったという個人的な経緯もあり、 VPN もしくは既存のProxyの置き換え手段として手放しで愚直に推せる仕組みではないなというのが率直な印象でした。ただ、活用できる局面は多そうなので、引き続き継続的にキャッチアップしていきたいなと思います。 しかしながら、面倒でもGKEにnginxのProxyを建ててそれをCloud IAPで守った方がIAP Connectorより融通聞くのではという気持ちもあり、目的とそれにかける手間のバランスを見極めるのは難しいなと思いました。結論は毒にも薬にもならない感じなのですが終わります。 明日の記事の担当は、データテク ノロ ジー グループの竹田さんです。お楽しみに。 株式会社 エニグモ 正社員の求人一覧 hrmos.co