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

TECH PLAY

株式会社エニグモ

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

全255件

こんにちは、 エニグモ 嘉松です。 データ活用推進室という部署でデータ活用の推進や マーケティング ・オートメーションツール(MAツール)を活用した販促支援、 CRM などを担当しています。 この記事は エニグモ Advent Calendar 2024 の 25 日目の記事です。 はじめに この記事では、AppSheetを学び始めたばかりの私が実際に視聴して役立った YouTube 動画をご紹介します。 効率的に スキルアップ できるよう、おすすめの視聴順も一緒にご紹介します。 AppSheetとは AppSheetとは、プログラミングの知識がなくても簡単にアプリを作成できる Google 社が提供するノーコード開発プラットフォームです。 Google スプレッドシート などのデータと連携し、 GPS 機能やカメラ機能を活用したアプリも開発可能です。営業活動の効率化、在庫管理の最適化、顧客管理の強化など、様々な業務に活用することができ、業務効率化、コスト削減、意思決定のスピードアップを実現できます。現場の作業者など、IT知識がなくても アプリ開発 に挑戦したい方におすすめです。 おすすめ動画(再生リスト)2選 以下におすすめ動画の再生リストを2つ紹介します。 「AppSheetを作ろうの会」 「AppSheet入門シリーズ」 「AppSheetを作ろうの会」 チャンネル名 cooker8 by 明治クッカー https://www.youtube.com/@cooker8 再生リスト AppSheetを作ろうの会 https://youtube.com/playlist?list=PLI47ltjBt9zETX2YcHSGArWLe4UBKJazW&si=T8SOH8Xm_SjLkjJK 動画本数 22本(2024年12月時点) 内容 AppSheetの初心者向けに、アプリ作成の基本から応用までを解説しています。 各動画では、具体的なアプリの作成手順や機能の使い方が丁寧に説明されています。 メインで解説を担当する牛乳屋の社長と社員に加えて、 Google Cloud Japanの担当者も登場します。 動画の再生時間が30分を超えるものもあり、また動画本数も22本と多いです。 おすすめポイント AppSheet初心者の社長の視点で解説されているので、AppSheet初心者には同じ視点で動画を視聴することができます。 Google Cloud Japanの担当者の方も登場するので、AppSheetの中の人からの解説も聞ける点が他の動画と比較してユニークです。 現在も動画が追加されているので、定期的にウオッチしていくと最新の動向など把握できます。 AppSheet開発の考え方や作ったアプリをどのような業務に活かせるのか?といったAppSheetの開発の説明に留まらない重要な内容に触れているところに価値があると感じます。 おすすめ視聴方法 動画の本数も多く、30分を超えるような再生時間が長い動画もあるので、最初から一気に全て視聴するのはタイパという点でおすすめしません。 視聴者のこれまでの経験や担当する役割、確保できる時間との兼ね合いで、動画をピックアップして視聴するのがおすすめです。 視聴する優先度はこの後の「おすすめ視聴順」を参考にしてください。 「AppSheet入門シリーズ」 チャンネル名 AppSheetエンジニア岡田 https://www.youtube.com/@gasappsheet3423 再生リスト AppSheet入門シリーズ https://youtube.com/playlist?list=PLjtPSE_IHMnqyS35ChvLV_zGDcmXVRSA2&si=_fo_lXFwezpPj-PN 動画本数 10本(2024年12月時点) 内容 AppSheet専門 フリーランス エンジニアの方が解説している動画です。 初心者向けにプログラミングの知識がなくても理解しやすい構成になっています。 各動画がコンパクトにまとめられており、効率的に必要な知識を得ることができます。 おすすめポイント 開発の手順について実践的に解説されているので、いち早くAppSheetで アプリ開発 を進めるには最適な再生リストです。 実際の操作画面を見ながら学べるため、手順が分かりやすく、初心者でもスムーズに アプリ開発 に取り組めます。 動画のクオリ ティー も高いと感じました。 おすすめ視聴順 「おすすめ視聴順」の選定ポイント 最初はAppSheetの特性を理解できる動画をおすすめ! 具体的には、AppSheetでどのようなことができるのか、また、AppSheetがどのような場合に適していて、どのような場合に不向きなのかを理解できる動画を最初に視聴することをおすすめします。なぜなら、どのようなケースでAppSheetを使うべきか、逆にどのようなケースではAppSheetを使わない方が良いのかを判断できることは、その後の アプリ開発 において非常に重要だからです。AppSheetに向いていないことをAppSheetで行おうとすると、開発者もAppSheetも不幸になってしまうため、何事も適材適所が大切です。 次に実際に手を動かしながら開発手順、開発方法を学べる動画をおすすめ!! 次の段階としては、実際に動画を視聴しながら、開発を進めていく段階です。この段階では思ったとおりにいかないことも多々でてくると思います。なるべく迷わないように動画のクオリティが高く、丁寧に解説されている動画が良いと思いました。 AppSheetの開発の初期段階で知っておいたほうが良い小技的な知識も優先して視聴することをおすすめ!!! 開発が進んだ段階だと後戻り、作り直しになってしまうような知識(たいていは小技的なことが多い)は早めに見る価値は高いので、優先して視聴することをおすすめします。 おすすめ視聴順 視聴順 動画タイトル チャンネル名 視聴時間 1 【AppSheet新シリーズ】新企画始動!第一弾:AppSheetでめっちゃ便利なアプリを大公開! cooker8 by 明治クッカー 約33分 2 【AppSheet第三弾】5分で出退勤アプリをつくる。「ド素人」のにっしー社長の作成過程を全部見せます。 cooker8 by 明治クッカー 約26分 3 AppSheetの絶対ルールをまとめてみた。【AppSheet第5弾】 cooker8 by 明治クッカー 約21分 4 AppSheet入門シリーズ(Part1〜Part6) AppSheetエンジニア岡田 約60分 おすすめ視聴順の詳細 「AppSheetを作ろうの会」 【AppSheet新シリーズ】新企画始動!第一弾:AppSheetでめっちゃ便利なアプリを大公開!(視聴時間約33分) 33分と長いが、どんなアプリが作れるのか、アプリをどのように業務に活かせるのかをイメージできる。 アプリの作り方は説明していないが、どんなアプリを作れるか、どう業務に活かせるかをイメージできるのでオススメ。 個別のアプリの説明がやや長いので、その部分は飛ばして視聴してもオッケーです。 【AppSheet第三弾】5分で出退勤アプリをつくる。「ド素人」のにっしー社長の作成過程を全部見せます。(視聴時間約26分) アプリ開発 の初心者(未体験)の社長が、最初のアプリを作るまでを紹介している。 超シンプルなアプリの開発を通して、AppSheetの開発の流れを理解できる。 AppSheetの絶対ルールをまとめてみた。【AppSheet第5弾】(視聴時間約21分) スプレットシートからAppSheetを作成する前段階として押さえておいたほうが良いこと、特にAppSheeを作成した後だと容易に変更できないことなどがまとめられている。 AppSheetの開発の初期段階で知ってくと後戻りが少ないので、早めに見る価値は高い。 「AppSheet入門シリーズ」 「AppSheet入門シリーズ」のPart1からPart6まで通しで視聴する。(視聴時間約60分) 作りたいアプリによってはPart6の後にPart7とPart8を視聴する。(視聴時間約14分) 時間のある時にPart9、Part10を視聴する。(視聴時間約20分) おわりに この記事では、AppSheetの初学者の私が視聴してためになったYouTuebe動画をおすすめの視聴順と合わせて紹介させていただきました。 これからAppSheetを試してみたい、勉強したいという方の一助となれば幸いです。 他に参考になる動画があればコメントいただければ助かります。 本日の記事は以上になります。 なお エニグモ Advent Calendar 2024 もこの記事で最後になります。 最後までお読みいただきありがとうございました。 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは!Webアプリケーションエンジニアの 川本 です! この記事は Enigmo Advent Calendar 2024 の 23日目の記事です。 2024年12月18日に開催された Datadog Live Tokyo 2024 Reprise へ参加してきました。 www.datadoghq.com 10月に行われた Datadog Summit Tokyo 2024 にも参加したのですが、イベント内容の充実度とそこから得た学びが多かったことから今回のイベントにも参加を決めました。 Datadog Summit Tokyo 2024 へ参加した際のレポートを 2日目のAdventCalenderに投稿しているので、気になった方はこちらも合わせてご覧ください。 tech.enigmo.co.jp 印象に残ったトピック 今回のイベントを通して以下のトピックが印象に残りました。 ボトルネック 特定までの流れ サイバーエージェント 社の赤野さんの講演で紹介されていた、 API パフォーマンス改善を行なった際に APM Trace Queries を使って ボトルネック 特定の流れが非常に参考になりました。 APM Trace Queriesは Span の関係に基づいて Trace の検索、集計ができる機能です。 例えば ServiceA から直接呼び出されている ServiceB または ServiceC の Span を含むトレースを検索する場合、トレースクエリ 演算子 を用いて以下のように表現することができます。 ServiceA => ServiceB | ServiceC APM Trace Queries についての詳細 docs.datadoghq.com ボトルネック 特定までの流れは以下にように紹介されておりました。 APM Trace Queries を使って BFF のレイテンシに対して処理時間の割合が大きいマイクロサービス API を可視化 API ごとに APM Trace を確認して怪しい Span がないかを探す Continuous Profiler で ボトルネック になっている関数を特定 私もパフォーマンス改善の際に同じような手順で改善を試みたことがあるのですが、 APM Trace Queriesについてはここまで活用できていなあったので非常に参考になりました。 また Datadog を使った ボトルネック 特定の手順は属人化しないと思うので、手順としてチームに共有することもできるのでとてもいいなと思いました。 オブザーバビリティツールの統一 サービスによっては歴史的経緯やマイクロサービス化等によってオブザーバビリティツールが統一されていない状況があるかと思います。 しかし、このような状況ですとツールの管理者は事情を把握しているので 臨機応変 に使いわけられるかと思いますが、利用者は最初どれを使えばよいのか混乱を招く可能性があります。 他にも Wantedly 社の田中さんの講演ではツールを統一することには以下のようなメリットがあると紹介されており非常に参考になりました。 計装ライブラリへの依存が減りパフォーマンス向上 計装ライブラリ同士の競合による不具合の解消 サービス利用費用の圧縮 speakerdeck.com 弊社では Datadog が主に使われていますが、完全には統一されておらず他のツールと併用している状況です。私自身も入社当初どのツールを見れば良いのか迷って質問した経験があります。社内の誰でもオブザーバビリティを活用できるようにツールは統一していきたいです。 コスト管理 コスト管理に関する興味深い点として、オブザーバビリティツールが従量課金モデルかユーザー数課金モデルかで大きく違ってくるということです。 従量課金の場合はコスト管理は難しいが、 コストコ ン トロール はしやすい。 ユーザー数課金の場合はコスト管理はしやすいが、 コストコ ン トロール は難しい。 これらは組織によってツール選定の基準に大きく関わってきそうです。 従量課金のDatadog www.datadoghq.com ユーザー数課金のNew Relic newrelic.com エンドポイントごとの担当者(Owner)を可視化 大規模なモノリシックなサービスでエンドポイントが多数ある場合、どのエンドポイントが自分のチームが管理しているのものなのか把握するのが難しいことがあると思います。 リクルート 社の小檜山さんの講演で、エンドポイントのOwner一覧を ダッシュ ボードで見れるようにしたという事例が非常に参考になりました。 以下の資料で紹介されております↓ speakerdeck.com 弊社も大規模な Rails の モノリス が存在しており、お問い合わせ対応の際にすぐにエンドポイントのOwnerがどこかわからずに混乱するといったことがあります。この事例は弊社でも適用できそうだと感じました。 おわりに 様々な会社のオブザーバビリティ、Datadogの活用事例が聞けてとても勉強になりました。 また Datadog をエンジニア組織に普及することの難しさはどの会社でも語られていましたが、まずは興味を持ってもらう機会を作りだし、ちょっと便利だから使ってみようかなと思ってもらうことが大切なのかなと思いました。 イベント最後に、Datadogのキャップやステッカーをいただきました。 運営の皆様素晴らしいイベントをありがとうございました! 明日の記事の担当は SC本部 の 平澤さんです。お楽しみに。 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは、GASエンジニア の 佐伯 です。 この記事は Enigmo Advent Calendar 2024 の 21 日目の記事です。 この記事では Google 製の アプリ開発 ツールである、AppSheet について紹介します。 軽く自己紹介になりますが、普段はGAS( Google Apps Script)やBigQueryなどを用いて業務用ツールの開発を行っています。最近はGASとの親和性も高いAppSheetに挑戦しているので、その中で気づいたことをまとめます! 概要 AppSheetの利用を検討している方向けに、AppSheetの基本的な特徴やメリットをまとめる。また、より高度に使いこなしたい場合の拡張性や、筆者が感じる向いている用途、デメリット(弱点)、 Microsoft 製品との比較についても記載している。 特徴とメリット データに関する設定を重視した開発ツール 大前提とされるべきAppSheetの特徴として、データ重視の開発ツールである点がある。 これはどういう意味かというと、例えば、ある業務に関連した複数のリレーショナルなテーブルがあるとする。これらに対して、各テーブルの主キーやデータ型を定義し、またテーブル間の参照関係を設定すると、それらのテーブルの利用の仕方は、おおよそ決まってくる(予想がつく)。 「予想がつくなら、自動で作ればいいやん」というのが、 Google 社がAppSheetに込めた主要な思想かな、、と考えている。 それゆえ、それらのテーブルに対する CRUD ( = Create 生成、Read 読み取り、Update 更新、Delete 削除)操作を行うUIを、ほぼ自動で作成するのが AppSheetのメイン機能となっている。 それ以外にも多くの便利なサブ機能があるが、これらはメイン機能に付随し、補完する形で提供される。 UIの作成が非常に早い データソースの設定がなされた時点で、主要なUIは、ほぼ自動で作成される。 UIの表示形式も、テーブルやカード、タイル形式だけでなく、 ダッシュ ボード、カレンダー、マップ、フォームなどなど、ある程度のバリエーションが用意されている。 データ型に応じた入力補助のUIなども、自動で適用される。選択肢タイプであればドロップダウンが表示されるし、日付型であればカレンダーが表示される。当然、データ型に違反するような入力はできない。 あとは、表示順や、並び替えといった、実際に利用するユーザー目線での利便性を向上させれば完了である。 ここまで読んで、メイン機能それだけ?!と言われそうであるが、AppSheetを利用することで、UIとデータソースをほぼ完全に分離することができるため、これによるメリットはやはり大きい。 例えば、GASで スプレッドシート をベースにツールを組む場合、UI作成の手間を回避するために スプレッドシート をUIとして用いることが多いが、この場合、どうしてもユーザーがデータソースを直接編集する形になりがちであり、誤操作やツールの破壊が生じるリスクは大きい。 また、本来であれば正規化して複数のテーブルに分離されるべきデータ構造であっても、やはりユーザーの一覧性向上の観点から、一つのシートにまとめて表示させる場合も多く、冗長でもあるし、データの 保全 性という点でも、よろしくない。 AppSheetを利用することで、UIを独立させ、データソースを理想的なリレーショナルDBの構成で、堅牢に安全性高く維持することができる。しかもUIはほぼ自動でできるのだから、活用しない手はない。 ちなみに自動で作成されたUIを利用せずに、手動でイチから設定していくことも可能である。 データソースの選択肢が幅広い スプレッドシート をデータベースにするのが一番簡単な始め方だが、 AppSheetはそれ以外の方式にも幅広く対応している。 名称 説明 AppSheetデータベース 専用のリレーショナルデータベース。 Google フォーム Google フォーム入力値をテーブルに使える。 Google ドライブ フォルダーやファイルを指定し、そのコンテンツを解析して半自動でテーブルを作成する。 Microsoft OneDrive または SharePoint にあるエクセルを使える。 Airtable Cloud Database GCP , AWS ,Azureなど、 クラウド 上にあるデータベース。通常の SQL 形式はもちろん、BigQueryも含む。 On-premises Database オンプレデータベース。DreamFactory connection を使って接続する。 特に Google ドライブは、請求書などの書面からも自動的にデータを再現するとのことであり、使ったことはないが、おもしろそうである。 サブ機能によって処理内容の自由度を上げられる 基本的な CRUD 操作以上の処理フローを構築する手段として、AppSheetでは様々なサブ機能が提供されている。 サブ機能 内容 入出力補完 UI上でユーザーが様々な CRUD 操作を行う際に、いろいろなバリデーションや加工、警告といった機能を付与できる。 Action ユーザーが実際に CRUD 操作を行う際に、実行するであろう画面遷移や処理内容を、ボタン1クリックにまとめて、UI上に配置する機能である。 Automation テーブルに加えられた CRUD 操作や、スケジュール設定をトリガーにして、定められた処理を実行する機能である。処理内容の選択肢としては、大きく次の2種がある。 ①メール、通知、SMS、Chatなどの通知系 ②webhookやGASを実行する外部連携系 Chat app アプリと連動させて、 Google Chatにメッセージを送るような使い方ができる。普段から Google Chatを使っているならば、便利と思われる。 Action はアプリ内での画面遷移や、他のテーブルへ影響を伝播させるための機能で、処理内容は選択式となるため制約もあるが、比較的簡単な操作で処理フローを構築できる。 Automationは、ユーザー操作や時間タイマーをトリガーとする自動化処理を構築するための機能で、先ほどのActionによる内部的な処理はもちろん、web API などを通じた外部サービスとの連携や、GASとの連携を図ることができる。GASは GCP とも密接に連携可能であり、この点は、AppSheetの限界を大きく広げてくれる。 ただしweb API については、AppSheetから直接認証通過できるのは、 API キー方式などの単純なものに限られ、OAuth2といった主流の方式は(今のところ)直接接続はできない。ただしこの点も、GASに処理を任せてしまえば、そちらでOAuth2通過はできるので、あまり問題にはならない。 GASをどれだけ使いこなすかが、AppSheetの限界を決めそうであるが、GASとAppSheetを連携させる場合においても細かい注意点はあるので、こちらは別途まとめる予定。 SQL ライクの専用関数を利用して、複雑な処理フローも構築できる。 少し複雑な処理フローを構築する場合でも、 AppSheetには専用の関数が利用されており 、これらを用いることで、かなり複雑なデータ操作も作成できる。 これらの関数の使い心地としては、基本的には スプレッドシート 関数に似ていて、テー ブルデー タを操作する部分については SQL の記法も混じっている感覚となる。関数の数は少ないが、よく考えられており、組み合わせ次第で多彩な使い方が可能。 モバイルからの利用をメインで想定しているようだが、パソコンでも問題なく使えるし、便利。 AppSheetのエディター画面では、モバイル形式のプレビュー画面がデフォルトで表示されるが、パソコンのブラウザでのプレビューも表示できるし、実際、問題なく利用できる。 ただ、基本的にモバイルを想定しているため、パソコン(ブラウザ)で利用すると、画面がちょっとシンプルすぎる印象ではある。ただこの点も、デスクトップモードの改善が進んでおり、かなり利便性を向上させやすい状態になっている。 実質無料 驚くべきことに、無料の Gmail ユーザーであっても、AppSheetは利用できる。いくつか機能に制限があり、アプリを共有できるのも最大10名までではあるが、それで事足りる場合も多い。 ましてや workspaceを利用している組織であれば、使わない手はない。プラン関係なく、Business系プランには AppSheetの Coreプランが付属している。 AppSheet有料プランの料金体系は極めて複雑であり、合理的なのだろうとは思うが、ユーザーの理解を拒絶しているといっても差し支えないレベルである。 詳細を無視してざっくり言ってしまうと、「(有料レベルの機能を利用している、または10個以上の Google アカウントで利用しているアプリの場合、)そのユーザー数分の AppSheet有料プラン契約が必要」というイメージである。 workspaceを利用している組織であれば、そのユーザー数分の AppSheet有料プランは含まれているわけだから、例えば30人の組織であれば、あるアプリを最大30ユーザーで利用できる。しかも、これは組織内のアカウントに限られず、組織外の無料 Gmail ユーザーを含んでいてもよい。そのアプリの合計ユーザー数が30を超えなければよい、のである。 さらに無料、有料を問わずアプリ数の制限はなく、また全アプリの合計ユーザー数分の有料プランが必要なわけでもない。あくまで個々のアプリでユーザー数が判定されるのみで、先ほどの例で行くと、組織内でアプリA、アプリB、アプリC の 3つのアプリを運営しているとしても、それぞれのアプリで30ユーザーまで設定できる。 抜群の拡張性 ここまで AppSheetの主要な特徴に絞って記載してきたが、それ以外にも注目に値する特徴は多い。 バーコード、 QRコード の読み取りが可能 商品や資材といった物理的なアイテムを取り扱う業態の場合、これは非常に強力なメリットとなる。コードを読み取ってアプリに値を直接入力したり、コードを読み取ってそのアイテムに該当するデータを瞬時に検索したりすることができる。 データだけでなく、画像を始めとした各種ファイルの取り扱いが可能 画像やファイルを、データに紐付けて保管できる。アプリ内で端末からアップロードすると、 Google ドライブ内に作られた専用フォルダに自動で保管される。 CSV を介したデータ操作が可能 他ツールとの連携や一括更新の際に便利。現状のテーブルをそのまま CSV で出力し、修正の上で、アップロードして反映させることも可能 アプリごとに API を利用できる これもエンジニアにとっては嬉しいところ。他のシステムやツールから、 API を介して直接データ操作することができる。 GAS( GCP )連携 先にも述べた通りで、 スタンドアロン 型のGASと連携できる。GASは GCP や外部システムとの連携が可能であり、これはつまり、ほぼ何でもありであることを意味する。 デメリット AppSheetにはデメリット、または使いにくそうな面ももちろんある。以下は、これまでの使用経験の中で感じた主要なデメリットであり、今後の改善に期待している。 UI作成の自由度は低い。特に要素配置やメッセージ表示の観点で不自由を感じることが多い。 環境移行の手間が比較的多い。アプリAからBへ丸っと移行はできるが、その際にGitのような移行前後の差分確認ができない。来歴管理については、開発画面で編集保存するたびにバージョンが自動更新されるようになっており、過去のバージョンに ロールバック させる機能が備わっている。 スプレッドシート のように他ユーザーの利用状況を確認できない。 スプレッドシート のようにアプリ画面で関数や条件付き書式の設定ができない。(開発エディターからは可能) 他ユーザーによる操作の反映がリアルタイムに行われない場合がある。その際は画面再読み込みが必要。 向いている用途 SQL 形式のデータ構造に基づく、業務用アプリケーションの作成に向いている。 NoSQLや複雑なデータ構造が必要なアプリケーションや、顧客向けアプリのようなオシャレで複雑なUIデザインが必要な用途には、向いていない。 また業務アプリケーションであっても、複数人で同時にテーブルの同一行を編集するような用途では、衝突により更新が拒否される場面が多くなる可能性があり、工夫が必要である。 今後期待している点 一番は、UIの柔軟性の向上である。表示のデザインや操作性には特に文句はないのだが、項目やボタンの配置の自由度がもっと上がれば、非常に使いやすい画面になると思っている。 またユーザーからの指摘で「なるほど」と思ったのは、 スプレッドシート のように「誰がどこで作業しているかを表示してほしい」という意見であった。業務に関する操作を行うのが目的である以上、他メンバーの状況が一目瞭然にわかるということは、進捗の把握や連携の向上といった点で、得られるものは大きいと思う。 Microsoft 製サービスとの比較 仕事と言えばエクセル(?)、エクセルといえば Microsoft ということで、長く独壇場を維持していた Microsoft も負けてはいない。 グループウェア のビッグ2といえば、 Google Workspace と Microsoft 365 であり、 Microsoft 365 には AppSheet と類似する Power Apps が含まれている。 Power Apps もノーコード・ローコードツールであり、 SharePoint に作成したテーブルなどをベースに、 Poser Automate の処理フローと連携して作成する業務アプリケーション作成ツールである。 Google AppSheet と比較した際の一番の特徴は、UI制作の自由度の高さである。項目の配置はもちろん、その大きさや配置など、極めて柔軟であり、自由である。 VBA のユーザーフォーム(UI)作成の操作感とよく似ていると思う。 ただ自由度が高いということは、それだけ手間がかかるということであり、実際、同じような画面を作る 工数 は、AppSheet と比べると Power Apps のほうが大きくなると感じている。 Google AppSheetのようにスッパリ割り切るのがよいか、それとも、 Microsoft Power Appsで納得いくまでこだわれる方がよいか、、このあたりはまさに悩みどころかもしれない。 終わりに 近年のノーコード・ローコードツールの発達は目覚ましく、AppSheetがその代表例の一つであることは間違いない。いろいろとツールを調べたり使ってみたりする中で思うようになったのは「拡張性の高いノーコード・ローコードツールを、エンジニアが使うことが重要」という点だ。 プログラミングスキルに乏しい状態でノーコード・ローコードツールを使っても、さほど便利なアプリは作れない。あくまで標準的に準備されている環境の中だけで構築することになるからである。 しかし、エンジニアが拡張性に優れたノーコード・ローコードツールを使うことで、 (生産性の低くなりがちな)UIや簡単な処理フローの構築をツールに頼って高速化しつつ、 ツール内では対応しきれないような複雑な処理フローについては、連動可能なプログラミング環境内で実装することで、その業務特有の複雑なプロセスにも対応できる。 という、両者のいいとこどりが可能となる。 また、操作性がよいゆえに、ノーコード・ローコードツールの開発者は、かつての VBA のように今後ジリジリと増えていくと思われる。こういったツールでは開発手法がより規格化されやすいので、同じ機能を実装した場合の開発者による差も生じにくい。 それゆえ、できるだけこういったツールを用いることで、開発/保守業務の属人化を極小化し、ひいては業務の継続性・安定性を高めることになると考えている。 明日の記事の担当は RDチーム の 廣島 さんです。お楽しみに。 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは、データエンジニアの中村です。 新卒で入社してから、気づけば2年が経とうとしています。時間の流れは本当に早いものですね。 今回は、私がこれまで取り組んできたデータ基盤におけるアクセス制御に関する技術と取り組みについてお話ししようと思います。 昨日に引き続きデータ基盤関連の記事になりますが、ぜひ最後までご覧ください! この記事は Enigmo Advent Calendar 2024 の 20日 目の記事です。 目次 背景 ポリシータグとは ポリシータグの利用イメージ ポリシータグによるアクセス制御の仕組み 使ってみた感想 まとめ 最後に 背景 弊社のデータ基盤はBigQueryを利用しており、社内の個人ユーザーやサービスアカウント経由での各種サービスからアクセスがあります。 データの種類によってはユーザー・グループ毎にカラムレベルでアクセスを制御したいケースが発生することがありました。 以前は、通常のviewと特定のグループに見せたくないカラムをexceptしたviewの二つを作成し管理していました。 図1: アクセス制御方法(旧) シンプルな構成で直感的に理解しやすいのでこのままでも良さそうでしたが、特定のカラムが閲覧不可のグループから要望があるたびにViewを用意する必要があるので、要望が多いと対応が大変になってしまいます。 その課題を解決するために、BigQueryの ポリシータグ という機能を利用してアクセス制御を行おうと考えました。 ポリシータグとは ポリシータグは、BigQuery上のテーブルで、列レベルでのアクセス制御を可能にする タグ機能 のことです。 以下はBigQuery上で実際にポリシータグを設定した時の画像です。アクセス制御したいカラムに対して、作成したポリシータグを紐づけることでカラム単位でのアクセス制御が可能となります。 図2: ポリシータグ ポリシータグの利用イメージ イメージを以下に示しました。 図3: ポリシータグによるアクセス制御方法 ざっくり言うと ポリシータグを作成 → ポリシータグに対して権限周りの設定をゴニョゴニョ → アクセス制御したい列に対してポリシータグを設定 → アクセス制御したい列の見え方がユーザーによって変わる といった具合です。 ここで重要なのが、 「同じテーブルを見ているのにユーザーによって見え方が変わる」 ということです。 これまでは閲覧権限のないカラムをexceptしたviewを作って権限管理していましたが、ポリシータグによって1つのテーブルでそれぞれの閲覧権限に応じて閲覧可能なカラムのみ見せられるようになりました。 図4: アクセス制御方法(新) 現時点ではまだ移行途中ですが、最終的には図1から図4へ完全移行を考えております。 それでは、どのようにして見え方を変えているのかを説明していこうと思います。 ポリシータグによるアクセス制御の仕組み ポリシータグの挙動を理解する上で重要なのが以下のロールです。 1. roles/datacatalog.categoryFineGrainedReader (きめ細かい読み取り) 2. roles/bigquerydatapolicy.maskedReader (マスクされたデータの読み取り) 名前からある程度想像がつきますね。 1は 「ポリシータグが付与されていても、データをそのまま見れる」 ロールで、2は 「ポリシータグが付与されている場合、データをマスクされた状態で閲覧できる」 ロールです。 この二つのロールを利用してアクセス制御を行います。 ポリシータグを作成 図3① して、ポリシータグをテーブルへ設定 図3⑤ するだけだと、どちらのグループも権限エラーでクエリすらできません。 まずは閲覧可能グループの場合ですが、1のロールを付与したIAMポリシーをポリシータグへbinding 図3② します。そうすると、閲覧可能グループがクエリしてもポリシータグが付与されているカラムはそのままの状態で閲覧できる状態になります。 次に、閲覧不可グループの場合ですが、2のロールを付与したIAMポリシーをポリシータグへではなくデータポリシーにbinding 図3④ します。 データポリシーというのはポリシータグに紐づいているデータの マスキングルール を決定するリソースであり、それに対してポリシーbindingを行います。マスキングルールは複数あるので、ケースに応じて適切なルールを選ぶと良いでしょう。 ここまで行うと、閲覧不可グループがポリシータグを設定した列を含むクエリを実行した場合、ポリシータグを設定した列がマスキングルールに従った状態で返ってくる状態になります。 まとめると以下のような挙動になります。 図5: ポリシータグの挙動 ③の状態になってしまうと、そもそもクエリが実行できなくなってしまうので、そうならないように全てのグループ・ユーザーが①or②の状態になることが理想です。 使ってみた感想 約1年半利用しましたが、正直なところ当初の課題であった「特定のカラムが閲覧不可のグループから要望があるたびにViewを用意する必要がある」というケースがあまり発生しなくなったので、利用前後でそこまで恩恵を感じておりません。 ですが、アクセス制御方法を移行することによって将来的に以下のメリットがあると思いました。 組織が拡大してさらに細かいアクセス制御が必要になった場合、ポリシータグの方が対応が容易 セキュリティポリシー の一元管理が可能になり、管理コストが削減される デメリットももちろんあり、以下のような状況に陥りました。 テーブルへのポリシータグ付与をAirflowで行なっており、そこで利用している API が タイムアウト になり連携処理が失敗・遅延してしまい後続処理へ影響が出てしまった。 新規で作成したSAが図5③の状況になり、各所からこれまで以上に権限付与依頼が届くようになった。 API の タイムアウト の件は、暫定でリトライ回数を増やして対応しました。 権限付与依頼の増加は、デメリットというよりメリット寄りかもしれません。というのも新規ユーザーがデータ基盤にアクセスする場合はどのような権限を持つべきかを考えるべきだと考えているので、その状態が作れていることはプラスであると思います。 (あまりに多くなってきたらもっと良いやり方がないか考えます。。) まとめ 現段階では総じてポリシータグによるアクセス制御への移行は個人的に微差でプラス寄りな気がします。 最終的に移行してよかったと思えるように日々運用方法は改善していこうと思います。 最後に 最後までご覧いただきありがとうございました! 明日は佐伯さんよりAppSheetに関する記事をお届けします。お楽しみに! 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは、データエンジニアの中村です。 弊社ではBIツールとして Google Cloudから提供されている Looker を利用しています。 Lookerの利用者も徐々に増えており、日々データ活用が進んでいることは嬉しいですが、それと比例して気になるのは ダッシュ ボードの表示速度やクエリコスト等のパフォーマンスです。 最近 AggregateAwareness という機能を利用してパフォーマンスを改善することができたので、その機能を利用するに至った背景と、その改善効果を紹介したいと思います。 AggregateAwarenessの詳細な使い方は説明しないので、その点はご了承ください。 この記事は Enigmo Advent Calendar 2024 の19日目の記事です。 目次 背景 AggregateAwarenessとは 利用した結果 メリデメ まとめ 最後に 背景 弊社のデータ基盤はBigQueryを採用しており、LookerからBigQueryへのクエリでどのくらいのコストが発生しているかをモニタリングしています。 今年の8月ごろからクエリコストが増加していることが判明し、原因調査から始めました。 Lookerのコスト推移 原因はアクセス量の多い ダッシュ ボードにスキャン量の大きい Look を追加したことによるものでした。 対策としては、Lookに対応した軽量のデータマートを用意してあげることでコストを抑えるといった方法があると思いますが、パネル毎にデータマートを用意するのは大変ですし、メンテナンスコストも高くなります。 かといって、DWH層を一から整備していくのは時間がかかりそうです。 そこで、両者のメリットを兼ね備えた方法としてAggregateAwarenessという機能に辿り着きました。 AggregateAwarenessとは AggregateAwareness とは、 データマートに相当する、事前に集計されたテーブルを自動で作成し、クエリの際にそのテーブルを自動で認識してくれる機能 です。 ざっくりとした手順を以下に記載しますが、本題ではないので詳細は割愛します。利用方法はクラスメソッドさんの こちら の記事が参考になりました。 ①AggregateAwarenessを適用したいLookが参照しているExplore画面を表示 ↓ ②Explore画面より、AggregateAwareness用に自動生成されたLookMLをコピー ↓ ③コピーしたLookMLを、対象のexploreが定義されているmodelファイルのexploreブロックへコピペ ↓ ④Exploreからクエリを実行すると、BigQueryにLookMLで指定した条件で集計されたテーブルが作成される ↓ ⑤次回以降は④で作成された集計テーブルへクエリしに行ってくれるので、クエリパフォーマンスが向上する この方法だと、テーブルの作成をLooker側で行なってくれるので、 工数 をかけずにマートの作成が行えてよかったです。 また、パネルが不要になったら、コピペしたLookMLと自動で作成されたテーブルを削除すればクリーニングが済むので、後片付けが楽そうだと感じました。 紹介はここまでにして、AggregateAwarenessを利用した結果の方を説明していこうと思います。 利用した結果 AggregateAwareness適用後のコスト推移 グラフを見ると一目瞭然ですが、適用前後で大幅にコストを削減することができています。 修正した日付が11月14日なので、11/10の週から減少傾向になり、11/17の週から一気に削減効果が現れていますね。 クエリ一回あたりのコストも連動して減少しているので、クエリ回数が減ったことによる効果ではなさそうです。 コスト 期間① ※1 期間② ※2 減少率 クエリ全体のコスト(円) (省略) (省略) 71.8% クエリ1回あたりのコスト(円/クエリ) 13.75 3.53 74.3% ※1期間①: 10/14~11/13(修正日前日から直近1ヶ月) ※2期間②: 11/14~12/15(修正日当日から1ヶ月後まで) 具体的な数値だと、適用前後1ヶ月で全体のクエリコストを約71%、クエリ一回あたりのコストを約74%削減できました! また、今回の対応を行うきっかけとなったパネル以外にもAggregateAwarenessを適用したことで、コスト増加前の期間よりも改善されていました。 コスト 期間③ ※3 期間② ※2 減少率 クエリ全体のコスト(円) (省略) (省略) 34.0% クエリ1回あたりのコスト(円/クエリ) 7.17 3.53 50.8% ※3期間③: 7/1~7/31(コスト増加前) 平常時と比較しても約50%のコスト削減効果を得られたので、年間を通してかなり効きそうですね。 なお、クエリパフォーマンスも改善されており、平常時の平均実行時間はは4秒程度だったものが、適用後は3秒程度まで減少していました。 クエリの平均実行時間の推移 コスト削減と同時に ユーザビリティ を向上させることもできました! メリデメ AggregateAwarenessを使用してみて、以下のメリットがあると感じました。 メリット 簡単にデータマートを作成でき、削除する際もクリーニングが簡単 クエリのパフォーマンスが課題になっている場合、改善効果が大きい ただし、上記のメリットはあくまで短期的な視点で見た時のものであり、中・長期的な視点で考えると以下のようなデメリットもあると感じました。 デメリット パフォーマンスが低下するたびに対応が必要で、イタチごっごになってしまう。(スケーラビリティの低下) AggregateAwarenessの利用が膨大になると、メンテナンスコストが増加しそう。(このLookMLってどのLookに対応してるんだっけ?とかが起こる) これらのメリデメを加味してバランスよく利用していけばかなり有用な機能だと思いました。 メリットが大きすぎるので、個人的にはどんどん利用していきたいです。 まとめ AggregateAwareness を利用することで、Lookerのコストを約70%削減することができました。 平均クエリ実行時間も減少し、 ユーザビリティ の向上も同時に行えました。 「まだ利用していない&パフォーマンスを改善したい」場合は利用をお勧め! 最後に 最後までご覧いただきありがとうございました! 明日の記事の担当は、本日と同じくデータエンジニアの中村です。お楽しみに! 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは。エンジニアの竹田です。 BUYMA の検索システムやMLOps基盤の開発・運用を担当しております。 こちらは Enigmo Advent Calendar 2024 の18日目の記事です 🎄 はじめに 2024年もいよいよ年の瀬ですね!寒さが増すこの季節、みなさまいかがお過ごしでしょうか? 早速ですが本記事の主題のシステムリプレイスについてです。 ここ言うシステムリプレイスとは、老朽化したシステムの刷新、管理目的での移設など、既存システムがあり、それを何かしらの方法で置き換えることを指しています。 例えば、古くなったオンプレミス環境を クラウド に移行したり、データベースをより新しいものに入れ替えるといった作業も含まれます。 サーバサイドから下位のレイヤを担当している方々は、システムリプレイスを行う機会が割と多いのではないでしょうか。 実際に自分も エニグモ に入社してからもそうですが、それ以前からも新規システムを構築するよりはシステムリプレイスを行うことが多いと感じています。 今までの実績 各種検索システムのリプレイス MLOpsシステムのkubeflow pipelines→vertex ai pipelinesへのリプレイス アカウント検知システムのリプレイス どんなシステムでも老朽化が進むため、定期的なリプレイスが必要です。 気が付くとサポート期限間近であったりということは少なくないのではないでしょうか。 ただ、新しいもの作りという訳ではないので、なかなかモチベーションを上げ辛い作業ではないかなと思います。 また、旧システムとインプットやアウトプットは変えない、というのが命題となるので、結果比較に時間を要したりとナーバスになる作業も多いです。 そんな中でも、モチベーションを高く保つために自分が意識していることを紹介したいと思います。 システムリプレイスのモチベーションを高めるために 改善のチャンスと捉える:システムの価値を高める! 何か付加価値を提供できないかを考えます。 システムコストや学習コストの兼ね合いもありますが、思い切って足回りや ミドルウェア の置き換えなど検討しても良いと思います。 コスト削減 新たなマネージドサービスの利用 多めに見積もって構築されていたリソースの削ぎ落とし システム強化 少し気になっていたコードの修正 構成周りの定義での一工夫 マイクロサービス化 機能の一部を切り出して影響を局所化 監視強化 迅速な障害対応、柔軟な運用 学びのチャンスと捉える:自身のスキル底上げ! 少なくとも現状を一切変更しないリプレイスはあまり存在しないと思います。 例えば、旧システムのデータベースを調査中に、想定外のデータ構造や運用上の工夫を発見することもあります。それが新システム設計のヒントになることもしばしばです。 そう考えると、以下の点で新しく学びを得られる機会があります。 各種ライブラリのバージョン最新化 動作差異の確認、理解 あまり深く知らない言語の理解 どの言語でも固有の特徴がある 旧システムの構成や思想の理解 wiki 等が残っていれば確認、当時の思想が全く分からないこともある... とにかく旧システムを把握しないことには作業を進めづらい アウトプットのチャンスと捉える:学びを共有して価値を広げる! どういった方法でシステムを刷新したか、その意図など、技術ブログなどで外部発信する機会を得られます。 技術ブログの他にも、社内勉強会やカンファレンスでのLT(ライトニング トーク )なども該当するかと思います。 自分もこの点はあまり実践できていないので、自戒の意味も込めて記載しています。 自身の技術棚卸し こういった機会を作ることで、振り返りの機会を設ける 外部向け文章作成の機会 企業 ブランディング への貢献 より気持ちを高めるために 関わったことのなかった方と関わりを持てる可能性がある 過去担当していた方と関わりを持ち、人間関係を広げる機会になる可能性があります。 怯むことなく関わりを持てるようにしましょう。 今どきな言い方をしてみる slack等でやりとりする際、リプレイスではなく モダナイズ という言葉を使ってみたりしています。 ただし、 クラウド の新機能を利用したり、インフラやアプリの構成を大幅に見直すような場合でないと名前負けした感じになるので注意が必要です。 最後に 以上のようなことを意識して取り組んでいるため、比較的楽しくシステムリプレイスを行っていると思っています。 システム規模が大きくなればなるほどリプレイスは大変になるので、立ち止まって特定の機能を切り出せないかを考えたりするのも良いと思います。 みなさんもシステムリプレイスを楽しむ方法を見つけて、エンジニアとしての成長を一緒に楽しんでいきましょう! 明日の記事の担当は同グループの中村さんです。お楽しみに!! 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは! WEBアプリケーションエンジニア の小松です! この記事は[ Enigmo Advent Calendar 2024 ]の17日目の記事です。   Railsの場合: 自動的に日付オブジェクトとして認識 サンプルコード(Rails) Laravelの場合: 明示的な型変換が必要 サンプルコード(Laravel) RailsとLaravelの比較表 開発者の観点からの結論 Railsのメリット Laravelのメリット Rails の場合: 自動的に日付オブジェクトとして認識 Rails は ActiveRecord のORMを利用する場合だけでなく、 rawクエリを用いた場合でも date 型は Ruby の Date オブジェクトに変換されます 。そのため、日付フォーマットの変換を簡単に記述できます。 サンプルコード( Rails ) テーブル定義 # migration create_table :events do |t| t.date :event_date t.timestamps end rawクエリの利用 result = ActiveRecord::Base.connection.execute("SELECT event_date FROM events LIMIT 1") raw_date = result.first["event_date"] # => #<Date: 2023-12-13> puts raw_date.strftime('%Y%m%d') # => "20231213" ポイント event_date は Ruby の Date オブジェクトとして取得される。 .strftime メソッドを直接利用してフォーマットを変更可能。 Laravelの場合: 明示的な型変換が必要 Laravelでrawクエリを使用した場合、 デフォルトでは date 型は文字列として取得されます 。そのため、フォーマットを変更する際は、明示的に Carbon オブジェクトなどに変換する必要があります。 サンプルコード(Laravel) テーブル定義 // migration Schema::create('events', function (Blueprint $table) { $table->date('event_date'); $table->timestamps(); }); rawクエリの利用 use Illuminate\Support\Facades\DB; use Carbon\Carbon; $result = DB::select("SELECT event_date FROM events LIMIT 1"); $rawDate = $result[0]->event_date; // => "2023-12-13" (文字列) $carbonDate = Carbon::parse($rawDate); echo $carbonDate->format('Ymd'); // => "20231213" ポイント event_date は文字列として取得される。 PHP の Carbon ライブラリを利用して明示的に日付オブジェクトに変換する必要がある。 Rails とLaravelの比較表 特徴 Rails Laravel rawクエリでの date 型の扱い 自動的に Date オブジェクトとして認識される 文字列として取得される 日付フォーマットの変更 .strftime('%Y%m%d') が直接利用可能 Carbon::parse($date)->format('Ymd') が必要 追加の変換処理の必要性 不要 必要 デフォルトの開発者体験 日付操作が非常に簡潔で直感的 明示的な型変換が必要で、柔軟性が高い 適用範囲 ActiveRecord でもrawクエリでも同じ Eloquentとrawクエリで挙動が異なる 開発者の観点からの結論 Rails のメリット 開発効率が高い : 日付型は自動的に Date オブジェクトとして認識され、変換処理を意識する必要がありません。 統一性がある : ActiveRecord でもrawクエリでも同じように扱えます。 時間をかけてハマる前に、まず .to_sql でクエリを確認 する習慣をつけると、 デバッグ がスムーズになります! Laravelのメリット 柔軟性が高い : Carbon を使えば、細かい日付操作や タイムゾーン 操作が可能です。 設計の自由度 : 明示的な変換により、モデルや ユースケース に応じた日付処理を柔軟に適用できます。 Rails は「標準的な処理が簡潔」、Laravelは「柔軟性を重視」といった フレームワーク の哲学の違いが、日付型の扱い方にも表れています。どちらを選ぶかはプロジェクトの要件やチームの好みに依存しますが、簡潔さを求める場合は Rails が有利です。
こんにちは! WEBアプリケーションエンジニア の小松です! この記事は[ Enigmo Advent Calendar 2024 ]の16日目の記事です。     コンソールを使った デバッグ は開発において非常に重要です。 フレームワーク や言語ごとに特性が異なるため、それぞれの仕組みに慣れる必要があります。以下に PHP や Rails を例に、 デバッグ 手法や注意点を詳しく解説します。 1. PHPのデバッグ方法 2. Railsのコンソール機能 3. RSpecでのデバッグ 結論 1. PHP の デバッグ 方法 PHP には Ruby on Rails のような標準的なコンソール機能(例: rails console )が存在しません。そのため、 デバッグ の際には以下の手法を使うことが一般的です。 var_dump() の利用 PHP では主に var_dump() が使われます。これは CLI からの実行でも WEBブラウザ 経由のアクセスでも有効です。 例 : $data = ['name' => 'John', 'age' => 30]; var_dump($data); CLI での PHP スクリプト 実行 テスト スクリプト を作成して CLI から直接実行する方法もあります。これにより、サーバーを介さずに デバッグ が可能です。 2. Rails のコンソール機能 Rails には標準で rails console が用意されており、 デバッグ やテストに非常に便利です。ただし、注意すべき点もいくつかあります。 関数のテストが容易 Rails のコンソールでは、関数やクラスを直接呼び出してテストできます。 例 : def greet(name) "Hello, #{name}!" end puts greet("Alice") #=> Hello, Alice! デバッグ における注意点 Rails コンソールでの デバッグ には p を使用しますが、 PHP の var_dump() と異なるため、切り替えを忘れることがあります。 例 : data = { name: "John", age: 30 } p data #=> {:name=>"John", :age=>30} コード変更時の再起動 コードを変更した場合、 Rails コンソールに入り直す必要があります。これを忘れると、古いコードのまま デバッグ を続けることになり、時間を無駄にする原因になります。 3. RSpec での デバッグ RSpec の デバッグ でもコンソールと似ています。以下に注意点と手法を挙げます。 p を利用した デバッグ RSpec では、ログを確認するよりも p を使う方が効率的な場合があります。しかし、つい忘れてしまうことも多いです。 例 : it "tests addition" do result = 2 + 2 p result #=> 4 expect(result).to eq(4) end コード変更時の挙動 RSpec コードそのものを変更する場合、通常は何もせずにテストを実行できます。しかし、テスト対象のロジックを変更した場合、特定の環境では注意が必要です。 コード変更と反映 テスト用のコード変更は即時反映されますが、今の開発環境では実際のアプリケーションコードを変更した場合はDockerコンテナを再起動する必要がある場合があります。この手順を忘れると、古いコードで デバッグ を進めてしまう可能性があります。 手順 : コードを変更する。 以下のコマンドでコンテナを再起動する。 結論 PHP や Rails 、 RSpec 環境それぞれに特有の デバッグ 手法と注意点があります。特に Rails やDocker環境ではコード変更時の再起動を忘れがちになります。また、各環境での デバッグ 手法に慣れることで、無駄な時間を減らし、生産性を向上させることができます。
こんにちは! WEBアプリケーションエンジニア の小松です! この記事は[ Enigmo Advent Calendar 2024 ]の15日目の記事です。   PHPの場合 呼び方の具体例 文字列キーを使ったハッシュアクセス 文字列キーアクセスを使う場面 シンボルキーを使ったハッシュアクセス オブジェクト形式(OpenStruct)のアクセス 確認方法 クラス内のインスタンス変数の確認方法 シンボルはRubyのみ存在? PHP の場合 model['full_name'] こういう変数の持ち方を 連想配列 と呼んでいただけなので、シンボルキーという言葉と発想がなかったです。 呼び出し方でも model['full_name'], model[:full_name], model.full_name などがあり、 <%= debug model %> やログでオブジェクト全体の値が取れてもキーの持ち方が違って取得するのに時間がかかることがありました。 なので、呼び方の具体例や呼び出し方を記載しました。 model['full_name'] のような形式は、文字列キーを持つハッシュから値を取得する方法です。このような形式でのアクセスは、 Ruby の基本的なハッシュオブジェクトの操作です。 呼び方の具体例 文字列キーを使ったハッシュアクセス Ruby では、ハッシュのキーとして文字列(String)を使う場合に、この形式でアクセスします。 model = { 'full_name' => ' AIR JORDAN 13(エアジョーダン13)' } puts model['full_name']  # => " AIR JORDAN 13(エアジョーダン13)" 文字列キーアクセスを使う場面 JSON パーサーからのデータ: JSON を Ruby でパースした場合、デフォルトではハッシュのキーが文字列になります。 シンボルキーを使ったハッシュアクセス Ruby では、ハッシュのキーとしてシンボル(Symbol)を使うことも一般的です。この場合は、:full_name のようにしてアクセスします。 model = { full_name: ' AIR JORDAN 13(エアジョーダン13)' } puts model[:full_name]  # => " AIR JORDAN 13(エアジョーダン13)" オブジェクト形式(OpenStruct)のアクセス OpenStruct を使うと、ドット 演算子 (.)でプロパティにアクセスできます。 require 'ostruct' model = OpenStruct.new(full_name: ' AIR JORDAN 13(エアジョーダン13)') puts model.full_name  # => " AIR JORDAN 13(エアジョーダン13)"   確認方法 model.class を実行することで、オブジェクトがハッシュなのか、OpenStruct なのか、あるいは別の型なのかを確認できます。その型に応じたアクセス方法を選びましょう。   クラス内の インスタンス 変数の確認方法 インスタンス 変数の取得方法も初めは時間がかかりました。 docs.ruby-lang.org p obj.instance_variable_get(:@foo)  このように取得するみたいです。   シンボルは Ruby のみ存在? Python 、 PHP 、C、Go、 JAVA などには存在せず、 Javascript には存在するけど、挙動が少し違うようです。 qiita.com 慣れればメリットもあるとの事ですが、他の言語にない概念なので、 Ruby 使い始めは正直紛らわしかったです。  
こんにちは、インフラグループの片桐です。 この記事は Enigmo Advent Calendar 2024 の 14 日目の記事として、サーバ機器管理台帳を 表計算 ツールから OSS の「NetBox」に移行した取り組みについて紹介します。 はじめに サーバ機器やネットワーク機器、各機器に付随する IPアドレス の情報など、サーバ機器や関連情報をまとめる為に「機器管理台帳」は欠かせないものになっています。その中で、機器管理台帳は Excel や Google スプレッドシート 等の 表計算 ツールで管理されているケースもよく見られます。 表計算 ツールを台帳として機器管理している場合、台帳の規模が拡大するにつれて、管理すべき各種情報が複数のシートやファイルに分散しがちです。これにより管理コストが増大し、整合性の維持も難しくなります。こうした状況に心当たりのある方も多いのではないでしょうか。 弊部署も同様に、 表計算 ツールを用いた煩雑な機器管理に悩まされていました。そこで、データセンターのインフラ管理(DCIM)と IPアドレス 管理(IPAM)を兼ねるツールであるNetBoxを導入し、機器情報管理の一元化・整合性維持を試みました。本記事では、機器管理台帳の 表計算 ツール管理からNetBox移行について、取り組み内容、移行に際する知見等を紹介します。  用語の整理 DCIM DCIM(Data Center Infrastructure Management)は、データセンターに関連するサーバ機器やネットワーク機器、ラック、配電や配線、設備など、さまざまなリソースを管理・可視化するためのツールや手法のことです。DCIMおよびDCIMツールを導入することで、ハードウェア配置や容量、ネットワーク接続状況などを一元管理することが可能となります。 IPAM IPAM(IP Address Management)は、ネットワーク内で使用される IPアドレス を一元的に管理し、その割り当てや利用状況、変更履歴などを可視化・追跡するためのツールや手法のことです。IPAM及びIPAMツールを導入することで、利用可能な アドレス空間 のシステム的な管理と、管理に伴ったIP重複割り当ての予防等が可能となります。 NetBox NetBoxは、DCIMとIPAMの機能を併せ持つ OSS です。サーバ機器やラック構成、 IPアドレス 、ケーブル接続など、データセンターまわりの情報を一元的に、かつわかりやすく管理することに特化しています。 Webインターフェースや REST API を通して各機器やネットワーク関連のデータを登録・編集・参照できるため、機器情報の管理をするだけでなく、管理の簡略化・自動化も可能です。 お試しで触りたい方向けの公式デモ版サイトも公開されています。 github.com 移行の背景と課題 これまで、弊部署の機器管理台帳には複数ファイル/複数シートを跨ぐ Google スプレッドシート を使用しており、以下をはじめとする各種情報を管理していました。 ハードウェア関連:機材情報、シリアル番号、ラック配置、納品日/保守期限、各機材のLAN接続状況 ホスト関連:ホスト名、各 NIC ごとの IPアドレス 割り当て状況 etc... 台帳上の各機器について、あるシートではホスト名と IPアドレス の紐づけ、あるシートではホスト名とラック上の設置位置の紐づけ...等、1箇所のデータを更新した際に関連するデータを複数シート上で合わせて更新する運用でした。 一方、この管理方式には以下の様な課題もあります。 台帳更新の煩雑さ: 1つの機器について複数ファイル/複数シートを跨いで情報が登録されている場合。 シート上のある箇所を変更した際、別シートや別セルの依存箇所も特定して修正する必要がある。 依存箇所を漏れなく特定できる運用フローや仕組み構築が必要になる。 整合性管理の困難さ: 台帳更新の煩雑さ にも関連。 依存箇所の修正漏れが起きやすい状況下にて、依存データ間で整合性の取れていないデータが発生した場合に事実確認の手間が発生する。 外部連携の困難さ: 機器管理台帳に限らず、 表計算 ツールで作成された各種データファイルが完全な CSV 形式で構築されていない場合。 台帳上に存在する情報を読み込んで プログラマブル に利用したい場合や、外部のシステムにデータを取り込む際、各環境が扱える状態に一度変換する手間がある。 これらの課題に対してNetBoxを導入し、対応を試みました。 NetBoxのデプロイ NetBoxのデプロイ先として、社内向けツール用に構築しているEKS( Amazon Elastic Kubernetes Service) クラスタ 上に構築しました。 インストールには、Netbox Communityの GitHub 上で公開されている Helmチャート(netbox-chart) を使用しました。 github.com helmを利用する場合は 利用ガイド を読みながら、ご自分の環境に合わせて values.yaml の各値を変更してセットアップする流れとなります。 特に 管理者ユーザ周りの設定値 はログイン時に使用するため、ご利用の環境に合わせて事前設定することをおすすめします。 NetBoxへのデータ登録 NetBoxに登録できる項目について データの登録を始める前に、既存の機器管理台帳では何の情報を管理しているのか、NetBoxには何の情報を登録できるのかを一通り把握しておくことを推奨します。 ドキュメントをご参照いただくと分かる通り、NetBoxに登録できる項目は多岐にわたり、かつきめ細かい情報を登録であるため、最初から全ての情報を入れ込むことが難しい場合も想定されます。 (以下NetBox ドキュメントの models 配下の大項目、並びに大項目配下の詳細情報を各機器/各グループ毎に入力可能となっています。) github.com もしスモールスタートで「データセンタ内の機器情報、ラックへの機器マウント情報、各機器へのLAN配線、 VM ホストとゲスト VM の紐づけ、各 NIC への IPアドレス アサイ ン」程度で運用を開始したい場合は、以下図のmodel項目を参考に入力していくことで簡素版な環境を構築可能です。 データの登録 NetBoxの導入を検討した当初は スプレッドシート 上に散在していた情報を1件ずつ確認しながら手動で登録することも考えていましたが、登録すべき情報を整理していく中で、数百台以上の機器や IPアドレス 、接続情報等をすべて手動で移行するのはあまりにも現実的ではない事に気付きました。 一方、NetBoxには機器追加/変更/削除等のデータ操作を楽にする為の仕組みが複数整備されており、一括でのデータ操作が可能となっています。 CSV / YAML 形式での一括インポート: NetBoxのWEBインターフェースの機能として、 CSV / YAML 形式でのデータの一括インポートに対応しています。 登録するデータを各形式に整形して事前に整備出来ている場合、各model毎のWEB UI上から楽にデータをインポート可能です。 1行目に各modelに対応するヘッダを、2行目以降に登録するデータを入力する形で定義します。 CSV 形式インポートの入力例 REST API でのデータ操作: NetBoxに実装されている REST API を活用することで、各種データ操作を プログラマブル に行う事も可能です。 CSV でのインポートはデータの登録のみ可能ですが、 API を利用することで CRUD 各処理を複雑な条件式を絡めて実行することも可能となります。 Netbox API Document 上記2種類の一括操作方法を実施して、既存の機器管理台帳上のデータを移行していきました。 スプレッドシート から移行する際の知見 移行前の情報を整理した上で、完全に正規化された CSV を作成するべき 移行前の スプレッドシート には現状との乖離として、例えば以下の様な不整合が発生していました。 新しいホストに付け替えた IPアドレス が古い機器に付随されたままになっている。 ホスト名を変更したが、旧ホスト名のまま台帳に登録されている。 不整合を一つ一つ修正するのは非常に手間の掛かる作業となる上、独自管理の形式から完全な状態の CSV 形式に落とし込むことは、手間と時間の掛かる作業となります。 一方、NetBoxには強力な CSV インポート機能が備わっているため、一度完全な状態の CSV を作成してしまえば、NetBoxの運用は直ぐにでも開始可能です。 私は不整合の解消作業は実施したものの、完全な状態の CSV を作成する前に移行を始めてしまった為、変更が必要な所は REST API を使用して適宜修正する形での対応となりました。 再度移行作業を実施する機会のある際には、完全に正規化された CSV を作成してから実施すべきと実感しました。 NetBoxに登録する情報の精査と入力先カラムの確認 前述の完全に正規化された CSV を作成した後は、 CSV 上のカラムをNetBox上のどのモデルに入れるかを予め検討しておくべきでした。 ラックの情報は dcim > racks に、機器のモデル名やシリアルは dcim > devices に、IPは ipam > ip-addresses に登録出来る、あるいはこの項目について入力できそうな項目が存在しない、等を先行して把握しておくべきでした。 例えば、NetBoxには機器の納品日や保守期限といった項目を入力出来る箇所が標準項目としては存在しません。 そのため、機器情報の自由記述欄となる Comment カラムに入力するか、 カスタムフィールド を追加することで、標準機能外の情報管理もNetBox上で可能になります。 一括登録を実施する前に、整理された CSV の項目とNetBoxの入力項目を比較して、このデータは何処に入るのか?を明確にしておくとスムーズなデータの投入が可能でした。 カスタムフィールドで機材納品日の入力欄を追加する例 NetBox導入によって感じたメリット 情報の一元管理と可視化: NetBox移行後は IPアドレス 、機器モデル、シリアルナンバー、物理配置、接続関係など、あらゆる情報をNetBoxで一元的な管理が可能となりました。 スプレッドシート を利用していた頃は、ある箇所を修正した際依存する情報の修正を、複数シート/複数ファイルに跨って手動で行う必要がありました。 NetBox移行後には依存情報の修正も行われるため、整合性保持にも寄与します。 エクスポート/インポートの柔軟性: 前述の通り、NetBoxにデータを登録する際は CSV / YAML 形式でのインポートが可能です。 また、NetBoxに登録されている情報は、 CSV / YAML 形式でのエクスポートも可能であるため、将来的に別の管理基盤へ移行する際にもデータ移行が容易になることが見込まれます。 拡張性と自動化: NetBoxには REST API や各種WebHookが実装されています。 API による台帳上のデータの一括操作が可能になった他、WebHookによって台帳に新規機材が追加された際にSlackなどチャットツールに通知する等の対応が可能となりました。別途仕組み作りを実施することで柔軟な対応が可能となるため、今後の拡張性として期待が高まりました。 サー バラック の情報可視化例。ラックの色のついている部分には登録した機器が紐づいている まとめ スプレッドシート からNetBoxへと台帳管理を移行した結果、情報一元化や更新作業の効率化が期待できる基盤が整いました。初期構築やデータ整備に手間はかかりましたが、その分、長期的な整合性維持と運用自動化の可能性が大きく広がりました。 一方、現時点では、NetBoxの基本的な機能を用いて、ハードウェアと IPアドレス 、簡易な接続情報を一元管理する段階にとどまっています。今後は運用を通じて API やWebHookの活用や NetBoxのプラグイン導入 など、さらなる効率化と可視化を進めていきたいと考えています。 明日の記事の担当はWEBアプリケーションエンジニアの小松さんです。お楽しみに。 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは!インフラエンジニアの森田です! この記事は Enigmo Advent Calendar 2024 の12日目の記事です。 また、11日目の Googleスプレッドシート編 の続きであるため未読であればそちらからご一読いただければと思います。 前回の記事ではZapierで扱うデータのインプットとなる スプレッドシート の解説を行いましたので、今回は処理とアウトプットを行うZapの解説を行います。 現在以下のZapが稼働していますが、 毎月22日に翌月の発表者へまとめてリマインド 毎週月曜日に発表者へリマインドし、発表予定がなければ募集する 発表があれば開始のアナウンスをし、発表予定がなければスキップのアナウンスをする 今回は翌月の発表者へまとめてリマインドするZapの解説を行いたいと思います。 毎月22日に翌月の発表者へまとめてリマインド 1.毎月22日にトリガー まず、翌月頭の発表者の準備期間が取れるように毎月22日にトリガーするようにしています。 キャプチャと同じように設定すれば毎月のトリガーとなります。 2.翌月が何月か計算 次の工程で使用するために翌月が何月なのかを取得しています。 具体的には1のトリガーが次に動く日付(翌月の22日)から 正規表現 で何月かを抽出しています。 import re print (input_data[ 'next' ]) result = re.findall( r'-\d{2}-' , input_data[ 'next' ]) return { 'result' : result[ 0 ].replace( '-' , '' )} 3.翌月の行を取得 翌月発表の行をまとめて取得してきています。 具体的には「リマインド管理シート」に開催月という列があったと思いますが、開催月が2で取得したものと同値かつ開催フラグがTRUEの行を取得しています。 注意が必要なのがEventの設定で、「Lookup Spreadsheet Rows」と「Lookup Spreadsheet Rows (Advanced)」という似たイベントが存在しますが、「Lookup Spreadsheet Rows」では取得できる行が1行のため、翌月の発表全てというような複数行取得したい場合は「Lookup Spreadsheet Rows (Advanced)」を選択する必要があります。 4.Slack送信メッセージ作成 3で取得した要素をSlackのメッセージへ整形するため python で実装しています。 date_list=input_data[ 'date' ].split( ',' ) title_list=input_data[ 'title' ].split( ',' ) SlackID1_list=input_data[ 'SlackID1' ].split( ',' ) result = f ''' 【{input_data['month']}月 Hacker’s Delightスケジュールのお知らせ】 {input_data['month']}月のスケジュールの予定はこちらです。発表者の方は準備をよろしくお願いします。 何かあれば @devrel へご連絡ください ''' for i in range ( len (date_list)): string = f " \n {date_list[i]}:{title_list[i]} <@{SlackID1_list[i]}>" result = result + string print (result) return { 'result' : result} それぞれの発表の部分はリストの要素分ループで回して戻り値へ加算(追記)していく形になっています。 5.Slackへ送信 4で整形したメッセージ(戻り値)をシンプルにSlackのチャンネルに送信しています。 実際に以下のようなメッセージが送信されます。 Zapの解説は以上になります。 おわりに 今回は1つのZapを用いて解説を行いましたが、11日目の記事で解説したインプットがあれば 毎週月曜日に発表者へリマインドし、発表予定がなければ募集する 発表があれば開始のアナウンスをし、発表予定がなければスキップのアナウンスをする 上記のようなリマインドも実装することができます。 また、今回 エニグモ で行っている アドベントカレンダー のリマインドも同じ要領で自動化しています。 スケジュールを把握して色々なメンバーにリマインドをするというのは思いの外意識を割かれてしまうため、 Google スプレッドシート とZapierが利用できる環境にあれば是非自動化にチャレンジしていただければと思います。 2記事に分かれて長かったですが、お読みいただきありがとうございました。 明日の担当はRDチームの 廣島 さんです。お楽しみに。 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは!インフラエンジニアの森田です! この記事は Enigmo Advent Calendar 2024 の11日目の記事です。 私は社内の勉強会チーム(DeveloperRelationsチーム)としても活動しており、 人力で行なっていたリマインドをZapierで自動化したのでそのご紹介をしたいと思います。 今回は毎週金曜日に実施している軽い勉強会( Hacker'sDelight )のリマインドの自動化を例に記載します。 元々は以下のようなスケジュール管理シートがあり、こちらを人の目で見て翌月の発表者やその週の発表者にSlackでリマインドを送るという運用をしていました。 ただずっと人力でリマインドを送るというのはツラいため、社内で自動化ツールのZapierを契約しているため折角なら自動化してしまおうということで自動化に着手しました。 調べながらZapを作成する中で意外にZapierの日本語のドキュメントが少なかったため、この記事が備忘録かつ同じような自動化をやりたい方の参考になればと思います。 今回の自動化を構成しているのは大きく分けて以下の3要素になります。 スケジュール管理シート(パブリック) リマインド管理シート(クローズド) Zap 全ての要素の解説を1記事で行うと長くなってしまうため今回は「スケジュール管理シート」と「リマインド管理シート」の解説を行います。 Zapの解説は12日目の記事で解説したいと思います。 スケジュール管理シート(パブリック) 以下が「スケジュール管理シート」です。 基本的に上で貼ったスケジュール管理シートと同様ですが、「リマインド管理シート」でSlackIDをメールアドレスから自動検索するために列が追加されています。 こちらのシートは基本的にパブリックになっており、一般メンバーもHacker'sDelightのカレンダーとして見ることができます。 全て手動で管理しているので特に言及するところはありませんが、この後の解説で関連してくる列は以下となります。 内容 発表者1,2(敬称略) 発表者1,2メアド 日程 リマインド管理シート(クローズド) 「リマインド管理シート」は「Zapier通知用」と「Slackメンション用IDリスト」の2つのシートからなります。 Zapier通知用 このシートは「スケジュール管理シート」から参照した値から計算して自動的に埋められるため、手動での管理は不要になっています。 それぞれの列の解説をします。 日程 発表内容 発表者1,2 発表者1,2メアド これらの列は全て「スケジュール管理シート」からそのまま参照しています。 別の スプレッドシート から値を参照してくるには IMPORTRANGE関数 を使用します。 例) =IMPORTRANGE("https://docs.google.com/spreadsheets/d/xxxx","2025!G4") また、発表者の部分は敬称を スプレッドシート 側で入れておきたいので カスタム数値形式 で「@さん」と入れることで自動で敬称を付与するようになっています。 開催月 MONTH関数 を用いて何月に開催されるのかを抽出しています。 これは翌月の発表をまとめてリマインドするのに使用します。 例) =MONTH(A2) 当日までの日数 日程のセルから TODAY関数 で今日の日付をマイナスすることで発表当日まで何日なのかを算出することができます。 例) =A2-TODAY() メンション用ID VLOOKUP関数 で「Slackメンション用IDリスト」から発表者メアドに対応した IDを取得してきています。 元々人力でメンション用IDを探してコピペしていましたが辛すぎるうえミスが分かりずらいため、IDは自動で取得されるようにした方が良いと思います。 例) =VLOOKUP(F2,'Slackメンション用IDリスト'!$A$3:$B$1435,2,FALSE) 開催フラグ 発表があるのかないのかを判別するために ISBLANK関数 で発表内容のセルを空白判定しています。 また、そのままだと発表がある(セルが埋まっている)とFALSEと判定され違和感があるため、 NOT関数 で逆の論理値が返されるようにしています。 例) =NOT(ISBLANK(D2)) Slackメンション用IDリスト 以下のドキュメントを参考にメンバーリストを取得すると、ユーザーのメールアドレスとUserIDが記載された csv ファイルが取得できます。 ワークスペースのメンバーリストをダウンロードする こちらのシートは csv の内容をそのままコピペしたものです。 Zapierを使ってユーザーにメンションをする際にはこのUserIDが必要になります。 注意が必要なのはこのメンバーリストがSlackのオーナーまたは管理者権限を持っていないと取得できない点です。 不特定多数が見られる場所に書かれるのは好ましくないため、「リマインド管理シート」の参照権限はクローズドで必要のあるメンバーのみが見られるようにするべきです。 Zapierでリマインドを行うためのインプットとなる スプレッドシート の解説は以上となります。 明日の記事では実際にリマインドを行う部分であるZapの解説を行います。 株式会社 エニグモ すべての求人一覧 hrmos.co
この記事は 私は、株式会社 エニグモ でチームのマネージャをしている後藤です。 マネージャ業務の傍ら開発作業を行うこともあります。 この記事は Enigmo Advent Calendar 2024 の10日目の記事です。 この記事では多くの Ruby を使っている人が、使っているであろう ruby-lsp を少し便利にする ruby-lsp-addons について紹介しながら、 VSCode でどのように活用できるのかについて紹介したいと思います。 ruby -lspとは ruby-lsp とは、 Ruby 言語向けに Microsoft が定義している、 Language Server Protocol を実装したサーバになります。 Language Server Protocol (以下 LSP ) は、プログラム中に定義されたクラス名、関数名、変数名などを取得できる API とデータ型を定義したものになります。プログラム中のデータを取得する API を定義しておくことで、エディタから対象言語に対応した LSP サーバーを通して 関数定義情報を表示、関数/変数の定義箇所へのジャンプ、関数名/変数名を使った入力補間ができるようになります。 LSP の登場以前は universal-ctags + GNU Global などを用いて同様の機能を実現することが多かったように思いますが、 VSCode の登場と合わせて LSP の提案と普及が進みました。その結果、多くのエディタで LSP がサポートされるようになり、最近は補間や関数ジャンプのための機能が LSP に集約されつつあるように思います。 Visual Studio Code ( VSCode ) の場合は、 ruby-lsp プラグイン を VSCode に追加することで ruby ソース編集次に ruby -lsp を使った関数ジャンプや入力補間が使えるようになります。 ruby -lsp-addons ruby -lsp ですが、当然ながら ruby の文法しかサポートしていません。ただ、 Ruby on Rails の場合はモデルの has_many、blongs_to、validates などなど多数の DSL がありこれらもOUTLINEなどに表示して欲しいところですが、その機能を ruby -lsp に実装するのも違っている気がします。 そんな問題を解決しようとしているのが、 ruby-lsp-addons 機構になります。 公式のドキュメントは Add-ons | Ruby LSP にあります。ただ、公式ドキュメントにもあるように実験的な取り組みのようで、 ruby-lsp のメジャーバージョンが変わると、 インターフェイス が変わって addons が動かなくなることもありますし、将来a addons のサポートが終わってしまう可能性があることを心にとめて置いてください。 それでは、 ruby-lsp-rails ruby-lsp-rspec について紹介していきたいと思います。 ruby-lsp-rails こちらの add-on を使えるようにするには、 ruby-lsp-rails gem を追加します。 名前からわかる通り、 rails 固有の機能サポートを追加するadd-onになります。 今回は、 gitlabhq/gitlabhq のソースの一部を表示しながら、 公式ドキュメントからいくつかの機能を抜粋して紹介したいと思います。 modelの DSL サポート # frozen_string_literal: true module Achievements class Achievement < ApplicationRecord include Avatarable include StripAttribute belongs_to :namespace , inverse_of : :achievements , optional : false has_many :user_achievements , inverse_of : :achievement has_many :users , through : :user_achievements , inverse_of : :achievements strip_attributes! :name , :description validates :name , presence : true , length : { maximum : 255 }, uniqueness : { case_sensitive : false , scope : [ :namespace_id ] } validates :description , length : { maximum : 1024 } def uploads_sharding_key { namespace_id : namespace_id } end end end のようなコードがあると、 VSCode の OUTLINE には以下のように Rails 固有の DSL で定義された項目も表示されます。 コントローラーメソッドからviewへのジャンプ コントローラのメソッド画面にviewを開くリンクが追加されます。 上の絵の赤枠で囲ったリンクが表示されるようになります。 この、 Jump to view をクリックすることで view が表示されます。 地味に、便利です。 その他の機能 公式ドキュメントを読むと、モデルの belongs_to のアソシエーション先にジャンプできる機能、コントローラーのメソッド定義箇所から ルーター の定義にジャンプできる機能などがあることになっていますが、上手く機能していないようです。この辺は実験的な取り組みということを温かく見守ることしましょう。 ruby-lsp-rspec 次は、 ruby -lsp- rspec です。 こちらも add-on を使えるようにするには、 ruby-lsp-rspec gem を追加します。 こちらも名前から想像できる通り、 rspec 向けの機能拡張を行う add-on になります。 以下のような specファイルを開くと、 # frozen_string_literal: true require " spec_helper " RSpec .describe Diffs :: StatsComponent , type : :component do include RepoHelpers subject( :component ) do described_class.new( diff_files : diff_files) end let_it_be( :project ) { create( :project , :repository ) } let_it_be( :repository ) { project.repository } let_it_be( :commit ) { project.commit(sample_commit.id) } let_it_be( :diffs ) { commit.raw_diffs } let_it_be( :diff ) { diffs.first } let_it_be( :diff_refs ) { commit.diff_refs } let_it_be( :diff_file ) { Gitlab :: Diff :: File .new(diff, diff_refs : diff_refs, repository : repository) } let_it_be( :diff_files ) { [diff_file] } describe " rendered component " do subject { page } let( :element ) { page.find( " .js-diff-stats-dropdown " ) } before do render_inline component end ... VSCode の OUTLINE に以下のように、 examples のテキストが表示されるため、 spec ファイルの流れを追うのも、修正をするのも楽になります。 また、以下のようにspecファイル上に Run | Run In Terminal | Debug リンクが追加されます。 このRunなどをクリックすることで、 rspec のテストを実行できます。また、これらのテスト機構が、 VSCode の テスト機能に統合されているため、 以下のような VSCode 標準の、 Test: Run Test at Curosr などの機能が利用できるようになります。 また、テスト結果についても GUI で表示られるようになります。 テスト結果がエラーになっているのは、DBなどを構築せずテストだけ実行したためで、gitlab のバグではありません。 使いたいんだけど、プロジェクトの Gemfiles に組み込めないんだけど VSCode の ruby -lsp ですが、インストール時の設定では、プロジェクトに bundle install されているものを使う設定になっていると思います。そのため、プロジェクトの他のgemとの依存関係の問題で使いたくても最新の ruby-lsp が使えない、なんて問題に出会う事があると思います。 そのような場合は、 ruby-lsp などの ruby 開発サポート系ツールだけをインストールした リポジトリ を準備し、bundler でインストールした bin ディレクト リへ PATH を通しておいて、 VSCode 上の設定を変更することで、プロジェクトは独立した形で、 ruby-lsp を使うことができます。 手順は以下のようなGemfileを準備し # frozen_string_literal: true source ' http://rubygems.org ' gem ' ruby-lsp ' gem ' ruby-lsp-rails ' gem ' ruby-lsp-rspec ' 対象 ディレクト リで、 bundle config path vendor bundle install しておき、 VSCode の settings.json にいかの項目を追加します。 " rubyLsp.bundleGemfile ": "$ { インストールディレクトリ } / Gemfile " 私の場合は、 asdf を使って ruby をいれているのもあってrubocop、erblint などをひとまとめにしたチェック系ツールをまとめた リポジトリ を作り、homebrewと asdf 用の環境セットアップをするラッパー スクリプト を通して、bundle exec する シェルスクリプト から各種ツールを起動する リポジトリ を作って使っています。 また、PCが変わっても VSCode の設定が変わらないよう上記 リポジトリ を /opt/ruby_tool へcloneしています。 参考のために、 ruby_tool へのリンクも貼っておきます。頻繁にバージョンを上げたり、ツールを入れ替えたりしているので、ご利用される際は、forkしてお使いください。 最後に 最後までお読みくださりありがとうございました。 明日の記事の担当は 森田 さんです。お楽しみに。 また、株式会社 エニグモ では、ツールやエディタのカスタマイズを 愛する人 エンジニアもそうでないエンジニアも広く募集しております。興味のある方は、以下の求人一覧をご覧ください。 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは、データアナリストの井原です。 この記事は Enigmo Advent Calendar 2024 の9日目の記事です。 私は、普段データアナリストとして エニグモ で働いています。データからビジネスの意思決定を行うための示唆を出し、関係者に正しく伝えることが主要な業務です。 最近、チームの勉強会でも話題になったのですが、データアナリストは伝え方って大事だよねという話がありました。その場ではさらっと話が進んだのですが、確かに、データアナリストはいつもポジティブな結果ばかりを伝えるわけではありません。企画者が苦労をしてリリースにこぎつけた施策で、結果も期待されていてという状況で、数字がよくなかった、または、懸念点が上がってきたということも多いです。 この記事では個人のこれまでの経験を振り返って、ネガティブなことを伝えなければいけない時に、どのようなことに気をつけたらよいかを考えてみたいと思います。 この1年を振り返ってみても、結果を伝えにくいと思う案件はいくつかありました。「事前検証ではそれなりに効果が出そうであると(自分が)押した案件が、蓋を開けてみると効果はかなり微量だった。」「これまで重点的に企画が行われてきた施策について、利益性が低そうだと伝えなければいけなかった。」などなど。 そんな自分の経験を通して、どんなことに気を付けるとよさそうか、5つ洗い出してみました。挙げてみた要素はあくまでも個人の意見ではありますし、自分も常にうまくやれているわけではないのですが、自戒もこめて書いていきたいと思います。 1.言いやすい関係性を作っておく いきなり、そもそもといった内容にはなりますが、元々の関係性はかなり重要な要素だと思います。 これは、言う側だけでなく言われる側の身を想像しても、それまで関係性の薄い第 三者 から言われるよりは、自身の取り組みを知ってくれている人の方が受け入れやすくなると考えられます。 そのためには、可能な限り、企画の段階でデータアナリストも企画に入っていけるようにするとよいと思います。また、分析の時点から入らざるを得ないとしても、こまめに質問や進捗を伝えるなどして、コミュニケーションを増やしておくといざという時には伝えやすくなります。 巨大な組織だと難しいところもあるかもしれませんが、 エニグモ は比較的少人数の組織なので、その辺りはやりやすい気はしています。 2.言葉遣いに気を付ける 当たり前ではあるのですが、伝える時の言葉遣いは気を付ける必要があります。特に意識をしていないと、さらっと否定的な言葉が(そこまで否定的だと意識せず)つい出てしまう場合があります。 例えば、「意味がない」とか「ダメですね」のような全否定の言葉は使わないように自分は気をつけます。「この数字だとちょっと厳しいかもしれません」や「想定と違うかもしれませんが、どうですか?」のような、相手と会話していく姿勢を出すだけでも建設的に話せるのではないかと思います。 前項とは反対になりますが、言いやすい関係を作りすぎてしまうと、ぽろっと否定的な言葉も出やすくなってしまう(気軽に話せるので言葉を意識しなくなりやすい)側面もあるので、この辺りはバランスを考えてうまく調整出来るとよいのではないかと思います。 3.最初に「言いづらい結果なのですが」と言ってしまう これはテクニック的な話ではありますが、会議の最初に言ってしまうと、言う方も聞く方も受け入れる準備が出来るので楽になるのではないかと思います。あるいはタイミングがあれば、「今分析しているのですが、厳しい結果が出るかもしれません」と雑談的に話しておくのもよいでしょう。 根本的にはもう少し他の項目の方が大事ではないかとも思いますが、相手に結果を受け入れてもらうということも、アナリストの重要な仕事の一つです。こういった地味なテクニックを意識しておいて損はないと思います。 4.相手に労いと尊敬の気持ちを持つ 言葉遣いなどに繋がる話ですが、施策を進めているメンバーはその企画に対してかけた労力や思いがあります。その労力や思いに対しては、労いと尊敬の気持ちを持つことが大事です。 相手の企画に対しての思いを知る過程で関係性も作れると思いますし、言葉遣いも下手な言葉遣いはしにくくなると思います。例えば、相手が大切に思っていることに対して、「意味ないよ」などとは、ある程度の良識があれば言いにくいですよね。 5.それでも遠慮はしない、自分の分析結果には自信を持つ 相手を思いやることは大事だと思いますが、一方で、データアナリストとして伝えるべきことは伝えなければなりません。 そのため、最終的には自分の分析結果に対して自信を持つことも大事です。 伝えづらい分析結果が出てきた時、多くの分析者は分析内容を振り返ったり、よさそうな点を見つけようとデータをさらに詳細に区切って細かい分析を行ったりなど、よくあるのではないかなと思っています。しかし、持てる知識をフル活用して分析を行った結果なのであれば、下した結論がネガティブな内容であっても、それはしっかりと伝える必要があります。 伝え方自体は上で書いたように気を付ける必要がありますが、結論はしっかりと相手に伝わるように、準備できればよいと思っています。 おわりに 自分の一年間を振り返りつつ、ネガティブなことを伝えなければならない時に気を付けていること(きたこと)を洗い出してみました。 世の中には、データから新しい知見を発見して、それを活用して成功しました!というポジティブな話が多いと思いますが、現実のデータ分析では、新しい発見やポジティブな結果が確認できることばかりではありません。むしろ、特に目新しくない結果、ネガティブな結果が出てくる方が多いと思われます。 データアナリストという立ち位置は、時に第 三者 的な視点での意見が求められる職種ですので、データの解釈は冷静に客観的に行わなければなりません。しかし、それを伝えるところまで責任を持つという点では、合理性や客観性以外の人情的なコミュニケーションも必要になってくると思います。 少しでも、今回の話がデータを取り扱う方々の参考になったら幸いです。お読みいただきありがとうございました。 明日の記事の担当はエンジニアの後藤さんです。お楽しみに。 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは!Webアプリケーションエンジニアの レミー です! この記事は Enigmo Advent Calendar 2024 の 8日目の記事です。 Ruby on Rails 8が新しくリリースされ、Kamalという迅速かつ便利なデプロイツールが統合されました。私はこれまで Ruby on Rails アプリケーションのデプロイに Capistrano を使用していましたが、Kamalを試してみると、その便利さと簡単さに魅了されました。 この記事では、Kamalを使用して Ruby on Rails 8アプリケーションを AWS EC2サーバーにデプロイする手順を詳しく説明します。 Kamalとは? Kamalは 37Signals のチームによって開発された新しいデプロイメントツールです。このツールを使用すると、デプロイメントプロセスを1つのファイルで定義でき、複雑な手順を簡素化できます。ほとんどのアプリケーションで考慮する必要がない複雑な部分を省略することが可能です。Kamalは、DockerコンテナやTraefikなどのソフトウェアを組み合わせて動作します。セットアップ段階から包括的なソリューションを提供し、 Rails アプリケーションを最短時間で本番環境にリリースできます。 Kamalはどのように動作するのか? Kamalは、サーバー上でDockerコンテナ内にWebアプリケーションを実行し、Traefikを組み合わせてネットワーク トラフィック を処理します。新しいバージョンをデプロイする際、Kamalは以下の手順を実行します: 新しいDockerイメージをビルドする。 新しいイメージからコンテナを起動する。 新しいコンテナが正常に動作しているかを検証する。 Traefikを更新して、 トラフィック を新しいコンテナにルーティングする。 古いコンテナを停止する。 特に注目すべき点は、ダウンタイムなしのデプロイメントを実現し、blue/greenデプロイメントをサポートしていることです。 Ruby on Rails アプリケーションのサーバーの準備 ここでは、 AWS EC2でサーバーを準備します。 EC2 インスタンス の作成 Ubuntu Server 24.04 を選択します。 Keyペアは SSH とサーバーへのアクセスに使用します。 セキュリティグループでは、以下のポートを開放してください: 22 : SSH 用 80 : HTTP用 443 : HTTPS 用 SSH 権限の設定 まず、ローカルの公開鍵をコピーします。 cat ~/.ssh/id_rsa.pub インスタンス を起動したら、先ほど作成したKeyペアを使って、 ubuntu ユーザーでサーバーに SSH 接続します。 IPアドレス は新しく作成した インスタンス のものを使用します。 ssh ubuntu@ 18.182 . 197.19 -i /path/to/key.pem 次に、ローカルでコピーした公開鍵をサーバーの ~/. ssh /authorized_keys ファイルに貼り付けます。 ssh-rsa AAAABEAAAADAQABAAABgQ...AAAAB3Nzac2EAAAADAQABA Yuto MacBook Pro これでサーバーの準備は完了です。以降は以下のコマンドでサーバーに SSH 接続できます。 ssh ubuntu@ 18.182 . 197.19 Ruby on Rails 8アプリケーションの作成 まず、kamaltest という名前で Ruby on Rails 8アプリケーションを作成します。 rails new kamaltest プロジェクト ディレクト リに移動します。 cd kamaltest このアプリケーションは、タイトルと内容を持つ簡単なブログになります。そのため、scaffoldを使用して構築します。 rails g scaffold article title content:text データベースを作成します。 rake db:migrate routes.rb ファイルでホームページを設定します。 root "articles#index" アプリケーションを起動します。 bin/dev その後、 http://localhost:3000 にアクセスすると、アプリケーションが起動していることが確認できます。 deploy.ymlファイルでKamalを設定する Ruby on Rails 8ではKamalが既に統合されています。それ以前のプロジェクトにKamalを追加する場合は、Gemfileに kamal を追加し、以下のコマンドを実行します。 kamal init このコマンドを実行すると、Kamalがアプリケーションをデプロイするための設定を含む config/deploy.yml ファイルが生成されます。 Kamalの基本設定 デプロイのための設定は以下のようになります。 image: yutoyasunaga/kamaltest servers: web: - 18.182.197.19 # server IP proxy: ssl: true host: kamaltest.sampleapp.net registry: username: yutoyasunaga password: - KAMAL_REGISTRY_PASSWORD ssh: user: ubuntu image : Docker Hub上に保存されるDockerイメージの場所 servers web : サーバーの IPv4 アドレス proxy ssl : true に設定すると SSL が自動的に設定されます host : 使用する ドメイン registry username : Dockerアカウントのユーザー名 password : Dockerアカウントのログ インパス ワード。セキュリティのため、 KAMAL_REGISTRY_PASSWORD シークレットを通じて取得します。 ssh user : サーバーに SSH 接続する際のユーザー Kamalのシークレット 機密情報は .kamal/secrets ファイルに配置します。以下はその例です。 # 環境変数からレジストリパスワードを取得 KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD シークレットは 環境変数 から取得します。例えば、Dockerのパスワードが hogehoge の場合、以下のように設定します。 export KAMAL_REGISTRY_PASSWORD= 'hogehoge' 以下のコマンドで値を確認できます。 echo $KAMAL_REGISTRY_PASSWORD Kamalでデプロイを開始 config/deploy.yml の設定が完了したら、以下のコマンドを使用して初回のデプロイを開始します。 kamal setup このコマンドは以下の処理を行います: SSH キーを使ってサーバーに接続。 サーバーにDockerがインストールされていない場合は、get.docker.com を使ってDockerをインストール( SSH 経由でrootアクセスが必要)。 レジストリ にローカルおよびリモートでログイン。 アプリケーションのルートにある標準的なDockerfileを使用してDockerイメージをビルド。 イメージを レジストリ にプッシュ。 レジストリ からイメージをサーバーにプル。 kamal-proxy がポート80および443で トラフィック を受け入れることを確認。 現在のGitバージョンのハッシュに一致するアプリケーションバージョンで新しいコンテナを起動。 新しいコンテナが GET /up リク エス トに対して200 OKを返す場合、kamal-proxy に トラフィック を新しいコンテナにルーティングさせる。 前バージョンのアプリケーションを実行している古いコンテナを停止。 使用されていないイメージや停止したコンテナを削除して、サーバーの容量を確保。 デプロイが成功すると、次のような結果が表示されます。 Finished all in 70.0 seconds 初回のデプロイは kamal setup を使用しますが、2回目以降のデプロイでは kamal deploy のコマンドを使用します。 permission denied エラーの解決方法 初回のデプロイで以下のようなDockerに関連するエラーが発生した場合: Releasing the deploy lock... Finished all in 47.9 seconds ERROR (SSHKit::Command::Failed): Exception while executing on host 54.250 . 243.158 : docker exit status: 1 docker stdout: Nothing written docker stderr: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post "http://%2Fvar%2Frun%2Fdocker.sock/v1.47/images/create?fromImage=yutoyasunaga%2Fkamaltest&tag=4985d03bae739286203ce1185efdd4b2c71f90a9" : dial unix /var/run/docker.sock: connect: permission denied 次の手順で解決できます。 サーバーに SSH 接続します。 ssh ubuntu@ 18.182 . 197.19 以下のコマンドを実行して、現在のユーザーをDockerグループに追加します。 sudo usermod -aG docker $USER && newgrp docker Dockerが正常に動作するか確認します。 docker ps 以下のような出力が表示されれば成功です。 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES デプロイ後の結果を確認 まず、 https://hub.docker.com にアクセスして、イメージがプッシュされていることを確認します。 Route53を使用して ドメイン を管理している場合、以下のようにホストゾーン内でレコードを作成し、 ドメイン をサーバーのIPに向けます。 設定が正しい場合、 https://kamaltest.sampleapp.net にアクセスすると、アプリケーションの画面が表示されます。 このように、1分ほどで Ruby on Rails アプリケーションをサーバーにデプロイし、 ドメイン と SSL の設定まで完了しました。便利ですね! 🎉 よく使われるKamalコマンド aliases: console: app exec --interactive --reuse "bin/rails console" shell: app exec --interactive --reuse "bash" logs: app logs -f dbc: app exec --interactive --reuse "bin/rails dbconsole" デフォルトの deploy.yml ファイルでは、以下の4つの便利なコマンドが定義されています。 kamal console : Rails コンソールにアクセス kamal shell : サーバー上のコンテナにアクセス kamal logs : サーバーログを確認 kamal dbc : データベースコンソールにアクセス Kamalでのアセットのデプロイ RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile Dockerfile にはすでにアセットをプリ コンパイル するコマンドが定義されています。そのため、デプロイ時にアセットも自動的に処理されます。 Kamalでの 環境変数 (Environment Variable) 開発環境の 環境変数 の設定 開発環境では、 dotenv gem を使用します。 公式 リポジトリ : https://github.com/bkeepers/dotenv Gemfileに dotenv を追加 以下のコードを Gemfile に記載します。 group :development, :test do gem 'dotenv' end 環境変数 を管理する .env ファイルを作成し、例は以下のように記載します。 TEST_ENV_CLEAR=env_clear_local TEST_ENV_SECRET=env_secret_local 環境変数 が正しくロードされているかを Rails コンソールで確認します。 ENV .select { |key, _| key.start_with?( " TEST_ENV " ) } => { " TEST_ENV_CLEAR " => " env_clear_local " , " TEST_ENV_SECRET " => " env_secret_local " } 本番環境の 環境変数 の設定 現時点では以下の方法を使用していますが、より良い方法が見つかれば変更する予定です。 本番環境用の 環境変数 を管理する .env.production ファイルを作成します。 TEST_ENV_SECRET=env_secret_prod deploy.yml ファイルに 環境変数 を設定します。 env: secret: - TEST_ENV_SECRET clear: TEST_ENV_CLEAR: env_clear_prod clear : deploy.yml ファイルに直接記載される 環境変数 。 secret : 機密情報を含む 環境変数 で、 .kamal/secrets ファイルから読み込まれます。 .kamal/secrets ファイルで 環境変数 を以下のように設定します。 TEST_ENV_SECRET=$(cat .env.production | grep TEST_ENV_SECRET | cut -d '=' -f 2) 上記の設定は、 .env.production ファイルから情報を抽出します。 例えば、 .env.production に以下の行が含まれている場合: TEST_ENV_SECRET=env_secret_prod コマンド cut -d '=' -f 2 によって env_secret_prod が抽出されます。 デプロイ後、 Rails コンソールにアクセスして 環境変数 を確認できます。 kamal console ENV .select { |key, _| key.start_with?( " TEST_ENV " ) } => { " TEST_ENV_SECRET " => " env_secret_prod " , " TEST_ENV_CLEAR " => " env_clear_prod " } Kamalは、 Ruby on Rails アプリケーションのデプロイを大幅に簡素化し、効率化する強力なツールです。ぜひKamalを使ったデプロイに挑戦してみてください! 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは!UIUXデザイナーの和田です。 こちらは Enigmo Advent Calendar 2024 の7日目の記事です。 この記事では、定期的に実施している BUYMA のユーザーインタビューについてご紹介します。 また、ユーザーインタビューで得た気付きをもとに新設した【 まるわかりBUYMA公式スタートガイド 】についても後述します。 www.buyma.com 1. ユーザーの声を直に聞くメリット エニグモ では、社内のデータアナリストがBUMYAの利用データを分析して日々サービス改善に努めています。 定量 的な分析に加えて、的確なUX改善・向上を進めていくためには、ユーザーさまの声を直にお聞きして、なかなか数値からは解明できない 【ユーザーの行動の背景・ インサイト 】 をより深く理解することが重要だと考えています。 BUYMA では、ユーザーさまの声を直にお聞きするために、 定期的にオンライン形式(Zoom)のユーザーインタビューを実施しています。 社内のUIUXデザイナーとデータアナリストがインタビューアーをすることで、ユーザーさまからいただいたご意見やヒントをもとに「すぐに詳細な分析をおこない、施策化して改善を進められる」ようにしています。 2. BUYMA のユーザーインタビュー BUYMA では、ユーザーさまを対象に実施しているユーザーアンケートの中でインタビューにご協力いただける方を募っています。 毎回とても多くの方に、インタビューへのご協力に前向きな回答をいただいており、全国男女問わず幅広い年代の方にご参加いただいています! ユーザーインタビューの内容についてご紹介します。 🌟 2-1.ユーザーさまご自身について ユーザーさまご自身についてのお話を広くお聞きしています。 主に、『普段の生活スタイル』や『どのような「価値観・嗜好」をお持ちなのか』といった点や、 BUYMA との接点になりそうな「ファッション情報にふれる機会」「お買い物傾向」に関するお話などを伺っています。 🌟 2-2.サービス利用に関する ヒアリ ング ユーザーさまが普段 BUYMA を『どのように利用して』『どのように感じていらっしゃるか』、実際の利用エピソードをもとにプラスとマイナスの両側面から率直な話をお聞きできるようにしています。 ・ BUYMA の利用をはじめたきっかけ ・ BUYMA を使う理由( BUYMA の価値) ←→  BUYMA を使わなくなった理由(離脱理由) ・ BUYMA の気に入っているところ ←→ いまいちだと感じるところ、残念なところ ・ BUYMA を安心して利用できるポイント ←→  BUYMA に不安を感じるポイント ・ BUYMA でのよかった・満足できたエピソード ←→  BUYMA でのマイナスエピソード BUYMA において価値を感じていただいているポイント → より多くの方にその価値を広げていけるように BUYMA における課題・ペイン → 課題の背景を理解して適切な改善につなげていけるように 上記のように、プラス・マイナスそれぞれの気付きをもとに、UX改善・向上にむけた検討を進めています。 🌟 2-3.利用を見せていただく(行動観察) 実際にアプリやサイトを利用している様子を画面共有いただいて、どのように BUYMA をご利用いただいているか見せていただきつつ、お話を伺っています。 例えば、ユーザーさまの普段の利用(検索や商品閲覧・比較検討など)に即したシナリオをベースに、どのような操作をどのような手順でされているのか、利用の中の些細なつまずきやペインがどういったところにあるか、などを操作いただきながら ヒアリ ングを進めています。 🌟 2-4.サービスに関する認知・理解に関する ヒアリ ング BUYMA サービス・機能における「認知(知っていたか)」や「理解(理解できていたか)」についてもお聞きしています。 『どこで認知・理解したか』『どのように解釈していたか』なども率直にお聞きすることで、【対象サービス・機能の露出や導線が十分であるか】など、改善のヒントをいただけるようにしています。 🌟 2-5.検討中の施策に関するコンセプト ヒアリ ング 検討中の施策に関するプロトタイプをZoomミーティングの中で投影させていただきながら、率直な印象やご意見をお伺いしています。 施策を進める前に、初見の印象やニーズにマッチしているかなどを確認することができ、よりよいかたちに細かな調整をかけることができます。 BUYMA のUXリサーチについては、昨年の記事でもご紹介しておりますので、ぜひこちらもご覧ください。 tech.enigmo.co.jp 3. ユーザーの声から「気付くこと」「改めてわかること」がある ユーザーにとっての「ペイン・課題」「 BUYMA の価値」など、ユーザーの声から「気付くことができること」「改めてわかること・理解が深まること」がたくさんあります。 🌟ユーザーにとっての「ペイン・課題」に関する気付き BUYMA 利用におけるつまずきがどんなタイミングで起こっているのか、「 BUYMA 利用におけるペイン・課題」がどのくらいUXに影響を及ぼしているか、など、ユーザーインタビューを通じて具体的に理解を深めることができます。また、サービス提供側として想定していた捉え方と、ユーザーさまの捉え方が異なっていたり、思った以上に浸透していない情報についての気付きを得ることもあります。 🌟ユーザーにとっての「 BUYMA の価値」に関する気付き 一方で、ユーザーさまにとって「 BUYMA の価値」がどのように認識されていて、ユーザーさまのまわり(ご家族やご友人)に浸透しているか、などの気付きを得ることもできます。 以下では、ユーザーインタビューを通じて、改めて BUYMA の価値だと再認識することができた機能についてご紹介します。 世界中からさがす|リクエスト一覧 BUYMA には『リク エス ト』という機能があります。 世界中にいる BUYMA の出品者に、ほしい商品を探してもらうことができる機能ですが、 インタビューでは、この機能を利用して購入経験のある方は「リク エス ト機能の満足度がとても高い」ことがわかりました。 「どこを探しても見つからなかった国内完売商品がほしくて、 リク エス トを利用してみたら見つかって購入できて本当に嬉しかった!」 「ずっと探していたバッグがなかなか見つからず、中古は状態がいいものがなく諦めかけていたけれど、リク エス トを使って購入することができて非常に満足。」 また、インタビューの対象者の中でリク エス ト機能を使ったことがある方は、複数回リク エス トを利用しており、 「探したいと思うアイテムをリク エス トして世界中から探してもらう」体験を気に入ってくださっている傾向がありました。 今後は、「探したいアイテムがあるけれどリク エス ト機能を知らない・使ったことがない方」に、 このプラスの体験をより広げていけるように検討を進めていければと考えています。 4. ユーザーの声からまるわかり BUYMA 公式スタートガイドを作った話 ユーザーインタビューが終わったあとは、まとめ作業を行って主要な気付き( BUYMA の価値、ペイン・課題、仮説検証の結果など)を社内に共有しています。 そこから、UX改善・向上につなげる施策化をおこなっています。 今回は、ユーザーインタビューで得た気付きからコンテンツ作成を行った事例を紹介します。 まるわかりBUYMA公式スタートガイド 4-1.まるわかり BUYMA 公式スタートガイド新設の経緯 インタビューの中では、 BUYMA に関する分からないことや不安なことについてもお伺いしています。 その中で、以下のようなご質問・ご意見をいただくことがありました。 「 BUYMA の運営会社って日本企業なんですか?」 「 BUYMA の商品ってなんで安いんですか?」 「 BUYMA でほしい商品があるけれど購入して大丈夫なのか不安があります。」 このようなご質問・ご意見をいただいたことをきっかけに『 BUYMA を安心してご利用できると判断するための情報の重要性』について改めて認識することができました。 その後、社内で検討を進め「 BUYMA とはどういったサービスなのか」「安心して利用できるのか」などの疑問や不安を解消いただくために、【 まるわかりBUYMA公式スタートガイド 】というページを新設することになりました。ぜひこちらもご覧ください! www.buyma.com インタビューの中で BUYMA に関する分からなさや不安があるとお話されていたユーザーさまから、 いろいろと会話させていただいたインタビューの最後に 「思い切ってインタビューに参加してみてよかった。これまでより安心して買い物ができそう。」 とおっしゃっていただいたことがありました。 ユーザーインタビューを通して、ユーザーさま1人1人に向き合うことの大切さを実感するとともに、 UX改善・向上に向けて一歩ずつ前進するためのエネルギーをいただけていると感じています! 4-2. BUYMA ユーザーの声をよりたくさんの人に広げたい ユーザーインタビューの中で、積極的にご利用いただいているユーザーさまは、「まわりのご家族やご友人も BUYMA をご利用いただいている方が多い」という傾向が見えてきました。 一方で、 BUYMA でのお買い物を躊躇される理由として、「まわりに BUYMA を利用している人がいない」といった方が多くいらっしゃいました。 そこで、『どんな人が BUYMA を利用しているかイメージがつくことで親近感がわくようにするとよいのではないか』という仮説から、 BUYMA をご利用いただいているユーザーさまのお声を BUYMA のコンテンツとして掲載させていただくことにしました。 🌟 BUYMA ユーザーが感じる BUYMA のよさ BUYMA の利用者が「どんなところに BUYMA の魅力を感じてくださっているのか?」より多くの人に知っていただくために、 BUYMA を使う理由についてユーザーさまのご意見をピックアップしています。 BUYMAユーザーに聞く|なぜBUYMAを使ってるの? 🌟 BUYMA ユーザーが安心して利用できる理由 BUYMA を安心して利用してくださっている利用者が「どうして BUYMA を安心して利用できると判断してくださったのか?」より多くの人に知っていただくために、 BUYMA を安心についてお聞きした際のご回答をピックアップしています。 BUYMAユーザーに聞く|安心して利用できてる? www.buyma.com BUYMA についてより深く知っていただき、安心してご利用を続けていただけるように、今後も BUYMA のことをもっと深くわかりやすい情報を発信していければと考えています。 明日の記事の担当は・・・ 【 BUYMA サイトの開発と運用保守をされている レミー さん】です! お楽しみに! 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは、データサイエンティストの髙橋です。業務では企画/分析/ 機械学習 モデル作成/プロダクション向けの実装/効果検証を一貫して行っています。 この記事では類似画像検索システムの内製化にあたり、システム面での課題をどのように解決したかについて紹介します。内製化の背景や 機械学習 部分などについては 以前作成した記事 で説明しており、この記事はその続きとなります。 この記事は Enigmo Advent Calendar 2024 の 5 日目の記事です。 内製化の目的・事業インパクト 類似画像検索のシステム化における課題 システム化における各課題の解決策 「商品画像ダウンロード > セグメンテーション > Embedding 計算 > アップロード」の高速化 Embedding 同士の類似度計算処理の高速化 画像ハッシュ計算処理の高速化 複数 GCP サービスを連携させてスケジュール実行するアーキテクチャ作成 実装時の工夫 Cloud Composer からの GCP サービス呼び出し方法 Vertex AI Vector Search での類似度計算時にリトライ まとめ 追記:2025/01/21 第48回 MLOps 勉強会で登壇しました! 内製化の目的・事業 インパク ト 内製化の目的は、弊社が運営する CtoC EC サイト BUYMA において、商品 名寄せ で利用している他社製の類似画像検索システムの精度を保ちながらコストを削減することでした。既に内製化後のシステムに移行しており、同等の精度を維持しつつ年間数百万円規模(約8〜9割)のコスト削減を見込んでいます。 また、 名寄せ 以外にも類似画像検索システムを利用している施策があり、その移行も進めることでさらなるコスト削減の可能性があります。さらに、他社製の類似画像検索システムではコストが高く断念していた EC サイト上での画像起点のレコメンドや、画像による類似商品検索機能なども検討出来るようになりました。 より詳細な説明については 前編である機械学習編の記事 を参照ください。 類似画像検索のシステム化における課題 類似画像検索のシステム化における課題として、非常に大規模なデータを現実的な時間で処理する必要がありました。 機械学習編の記事に記載した類似画像検索の各ステップ に対して、毎月処理するデータ量は以下の通りでした。 ステップ 毎月処理するデータ量 商品画像をダウンロードし、物体存在箇所をセグメンテーションして切り抜き 約 200 万画像 切り抜いた画像の Embedding 計算 約 1000 ∼ 2000 万画像 切り抜いた画像・Embedding ファイルを GCS ( Google Cloud Storage) にアップロード 約 2000 ∼ 4000 万ファイル Embedding による画像同士の類似度計算 数十〜数千億の組合せ 画像ハッシュによる画像同士の類似度計算 数十万の組合せ 単純に単一のサーバー上で各ステップを実行する方法では、全体で1ヶ月以上かかる見込みであり、毎月定期的に処理を行うのは現実的ではありませんでした。 また、データ量以外の課題として、弊社では 機械学習 基盤として Vertex AI Pipelines を利用していましたが、今回のシステムはその基盤上に実装できない課題がありました。先述した規模のデータを処理するにはそれに特化した複数の GCP ( Google Cloud Platform) サービスを組み合わせる必要がある一方で、現行の基盤は VM インスタンス 上で Python コードを実行する用途を想定していたためです。そのため、複数の GCP サービスを連携して毎月スケジュール実行する アーキテクチャ を作る必要性がありました。 システム化における各課題の解決策 前述した課題をどのように解決したかを説明します。ただし、前提として類似画像検索の各ステップのうち、以下は1つのかたまりとして処理することにしました。 商品画像をダウンロードし、物体存在箇所をセグメンテーションして切り抜き 切り抜いた画像の Embedding 計算 切り抜いた画像・Embedding ファイルを GCS にアップロード 理由は、セグメンテーションおよび Embedding 計算の両方に GPU が必要であったため、また GCS とのデータのやり取りに時間がかかることから、「商品画像ダウンロード > セグメンテーション > Embedding 計算 > アップロード」の一連のステップを同一メモリ上で行いたかったためです。 「商品画像ダウンロード > セグメンテーション > Embedding 計算 > アップロード」の高速化 Dataflow  という並列分散処理が行える GCP サービスを利用することで高速化を実現しました。Dataflow とは、 GCP が提供するマネージドのバッチ・ストリーミングデータ処理サービスであり、並列分散処理により大量のデータを効率的に処理することが可能です。 今回 Dataflow を選択するにあたり、 Ray on Vertex AI も候補に上がりました。いずれも並列分散処理は実現できそうでした。Ray はその構文がネイティブの Python に近く、既存の Python コードに大きな変更を加える必要がなさそうだったため、実装コストが低そうに見えました。一方で、Dataflow は Apache Beam の構文を理解し覚える必要があり一定の学習コストが伴いそうでしが、社内で利用実績があり困ったときに既存の資産を参考に出来そうであったため Dataflow を選択しました。 実際に、 Dataflow の実装で困ったときに他プロジェクトでの ソースコード を参考にして解決することができ、この選択は正解であったと考えています。また、 Apache Beam の構文もそれほど複雑ではなく、初期の学習コストは多少ありましたが慣れれば実装に大きく手間取ることはなかったです。 約 200 万枚の画像に対して、並列分散処理無しでは約 30 日かかる見込みでしたが、Dataflow により約 56 時間に短縮することができました。 Dataflow の設定は ワーカーマシンタイプ: n1-highmem-4 (vCPU 4 、メモリ 26 GB) ワーカー数: 4 GPU :  nvidia -tesla-t4 としました。ハイメモリのマシンタイプを利用した理由は、メモリ枯渇でジョブが途中で停止してしまうことがあったためです。 Embedding 同士の類似度計算処理の高速化 Vertex AI Vector Search というサービスを利用しました。Vertex AI Vector Search とは、 GCP が提供するマネージドサービスで、膨大な数の Embedding 同士の類似度計算を高速に行うことができます。 Vertex AI Vector Search を利用することで約 1700億個の Embedding の組合せを約 8 時間で処理することができました。単一のサーバー上で処理した場合の処理時間は見積もっていませんが、おそらくこの規模のデータをこの速度で処理するシステムを作るにはそれなりの 工数 がかかったと思います。 Vertex AI Vector Search の設定としては、Algorithm type 、 Shard size はそれぞれデフォルト値である tree-AH 、 Medium で速度やコストに問題がなかったためそのままとしました。 Approximate neighbors count は値を変えて実験したところ検索速度に大きな違いが生じました。具体的には、 約 1 千万件の 768 次元のベクトルに対して類似度計算を 100 回行い、処理速度の統計量を算出したところ以下の通りでした。 num_neighbors mean (sec) std (sec) min (sec) max (sec) 10 0.031 0.013 0.021 0.076 100 0.189 0.034 0.146 0.266 1000 0. 218 0.034 0.17 0.297 10000 0.519 0.149 0.39 1.109 上記実験結果より可能な限り低い値にすることで処理時間が大きく短縮できそうでした。今回の用途では 1 画像に対して同一と検知される見込み画像数は数件程度であったため、それをカバーできる 10 としました。 画像ハッシュ計算処理の高速化 このステップでも Dataflow を利用しました。 約 27 万件の画像の組合せに対して、並列分散処理無しでは約 54 時間かかる見込みでしたが、Dataflow により約 45 分に短縮することができました。 Dataflow の設定は ワーカーマシンタイプ: n1-standard-1 (vCPU 1 、メモリ 3.75 GB) ワーカー数: 120 としました。Dataflow を採用したことで、ワーカー数を自由に変更することができ、120 ワーカーで並列分散処理を容易に実現できました。 複数 GCP サービスを連携させてスケジュール実行する アーキテクチャ 作成 Cloud Composer という Airflow のマネージドサービスを利用しました。Cloud Composer は、 GCP が提供するワークフロー オーケストレーション サービスで、複数の クラウド サービスを連携してスケジュール実行することができます。 今回 Cloud Composer を選択するにあたり Cloud Workflows も候補に上がりましたが、 Airflow の社内での利用実績が豊富であったため Cloud Composer を採用しました。こちらでも困ったときに他プロジェクトの既存の ソースコード が参考になる場面が多く、また移行前の類似画像検索システムの一部で Airflow を利用しており、既存システムの理解がスムーズに出来たメリットもありました。 以下のようなフローで Dataflow や Vertex AI Vector Search などを連携し、類似画像検索の各ステップを実行するシステムを Cloud Composer で実装しました。 開発生産性や保守性を向上させるために、 Dataflow では各ステップごとに Docker Image と Flex Template を、 Cloud Batch でも Docker Image を利用しました。これにより各ステップを独立に開発・テスト・デプロイ出来るようにしました。この部分の詳細については、別途機会があれば記事として執筆する予定です。 実装時の工夫 ここでは、システム実装時の工夫を2つ紹介します。同じようなシステム構成の実装をされる方の参考になれば幸いです。 Cloud Composer からの GCP サービス呼び出し方法 Cloud Composer から 各 GCP サービスを呼び出すに当たり、Dataflow には Airflow に専用のクラス が存在しましたが、 Vertex AI Vector Search には存在しませんでした。そこで、 GCP の REST API ( 例:インデックス作成 API )を呼び出すことでリソースの作成や作成状況のポーリングを行うクラスをカスタムで実装しました。具体的には Airflow の Sensor クラスを利用して以下のようなイメージで実装しました(あくまで ソースコード のイメージとして簡易化したものであり、実際のものとは異なります)。 from typing import Any, Dict from airflow import models from airflow.decorators import task from airflow.sensors.base import BaseSensorOperator @ task (task_id= "create_resource" ) def create_resource (args1: int , args2: str ): """GCP のリソースを作成する(Vertex AI Vector Search のインデックスなど)。 Args: args1 (int): 引数1。 args2 (str): 引数2。 """ # call_create_resource_api 関数は別途実装。内部で GCP の REST API を呼び出す。 response = call_create_resource_api(args1, args2) return response class ResourceSensor (BaseSensorOperator): """GCP のリソース操作の状況をポーリングする。 Attributes: poke_task_id (str): ポーリング対象のタスクID。 args1 (int): 引数1。 args2 (str): 引数2。 """ def __init__ (self, *, poke_task_id: str , args1: int , args2: str , **kwargs): """GCP のリソース操作の状況をポーリングするクラスを初期化。 Args: poke_task_id (str): ポーリング対象のタスクID。 args1 (int): 引数1。 args2 (str): 引数2。 """ super ().__init__(**kwargs) self.poke_task_id = poke_task_id self.args1 = args1 self.args2 = args2 def poke (self, context: Dict[ str , Any]) -> bool : """ リソース操作の状況をポーリングして、完了したかどうかチェックする。 Args: context (Dict[str, Any]): Airflow のコンテキスト。どのような値が格納されているかは以下参照。 https://airflow.apache.org/docs/apache-airflow/stable/templates-ref.html Returns: bool: リソース操作が完了したかどうか。 """ # 作成したリソース情報(IDなど)を取得。 response = context[ "ti" ].xcom_pull(task_ids=self.poke_task_id) # call_get_resource_status_api 関数は別途実装。内部で GCP の REST API を呼び出す。 status = call_get_resource_status_api(response, args1=self.args1, args2=self.args2) # status = {"done": True} のような値と仮定 return status[ "done" ] with models.DAG( "dag_name" , schedule_interval= "0 0 * * mon" , ) as dag: create_resource_task = create_resource(args1, args2) wait_create_resource_task = ResourceSensor( task_id= "wait_create_resource" , poke_interval= 60 * 10 , timeout= 3600 * 3 , poke_task_id= "create_resource" , args1=args1, args2=args2, ) create_resource_task >> wait_create_resource_task ここで、 Airflow のコンテキストを利用してポーリング時に必要なリソース情報(ID など)を Sensor クラスで取得するようにしました。 Vertex AI Vector Search での類似度計算時にリトライ Vertex AI Vector Search で類似度計算を行う際に、 Exponential backoff アルゴリズム によるリトライ処理を入れるようにしました。理由は、実際に運用していると Vertex AI Vector Search の呼び出し時に google.api_core.exceptions.InternalServerError: 500 Failed to call Service Control Check. や google.api_core.exceptions.Unknown: None Stream removed というエラーが稀に発生することがあったためです。Vertex AI Vector Search による類似度計算は1回の定期実行あたり約 8 時間かかるため、途中で停止するとリトライにかかる時間が大きいという問題がありました。 Exponential backoff アルゴリズム によるリトライは backoff ライブラリ を利用し、リトライ対象のエラーは google.api_core.exceptions.ServerError としました。 ソースコード を見ると今回発生した google.api_core.exceptions.InternalServerError や google.api_core.exceptions.Unknown がこのクラスの子クラスであり、他の子クラスも GCP 側のサーバーエラー起因のものであるためリトライする方が良いと判断したためです。 以下が実際の ソースコード のイメージです。(簡易化したものであり、実際のものとは異なります)。 from typing import List import backoff from google.api_core.exceptions import ServerError from google.cloud.aiplatform import MatchingEngineIndexEndpoint from google.cloud.aiplatform.matching_engine.matching_engine_index_endpoint import ( MatchNeighbor, ) # エラーが解消するまでの待ち時間が不明なため、リトライの最大時間は1時間半とした。 # 類似度計算は1回の定期実行あたり約 8 時間かかるため、1時間半の待ち時間は許容する。 @ backoff.on_exception (backoff.expo, ServerError, max_time= 5400 ) def find_neighbors ( index_endpoint: MatchingEngineIndexEndpoint, deployed_index_id: str , queries: List[List[ float ]], num_neighbors: int , ) -> List[List[MatchNeighbor]]: """デプロイされたインデックスで与えられた Embedding に対して近似最近傍探索を実行。 Args: index_endpoint (MatchingEngineIndexEndpoint): Vertex AI Vector Search のインデックスエンドポイントクラス。 deployed_index_id (str): インデックスのデプロイID。 queries: List[List[float]]: Embedding のリスト。 num_neighbors (int): 近似最近傍探索で取得する Embedding 数。 Returns: List[List[MatchNeighbor]]: 類似度トップ `num_neighbors` の id と類似度のリスト。 """ return index_endpoint.find_neighbors( deployed_index_id=deployed_index_id, queries=queries, num_neighbors=num_neighbors ) 実際にこのリトライ処理を入れたことで、その後の運用時に同じエラーが発生することがありましたが、無事にリトライされることで途中で停止せずに実行完了していました。 まとめ 本記事では、類似画像検索システムの内製化におけるシステム面での課題と、それをどのように解決したかについて説明しました。大規模なデータを毎月現実的な時間で処理しなければならない課題を、複数の GCP サービスを組み合わせて高速化することで解決しました。また、複数の GCP サービスを連携してスケジュール実行する必要がある課題を、 Cloud Composer を利用して実装することで解決しました。 今後は他の機能への応用を検討しています。本記事が類似のシステムを構築されている方々の参考になれば幸いです。 明日の記事の担当は UI/UXチーム の飯沼さんです。お楽しみに。 追記:2025/01/21 第48回 MLOps 勉強会で登壇しました! 第48回 MLOps 勉強会 にてこのブログの内容を発表いたしました。勉強会ページには配信 アーカイブ も掲載されておりますため、ご興味ある方はご覧いただけますと幸いです。 speakerdeck.com エニグモ では一緒にデータを利用したサービス価値向上を実現していただけるデータサイエンティストを募集中です!世界178ヶ国に1100万人超の会員を有し、出品数は630万品を超える BUYMA には膨大なデータが蓄積されており、データ活用の余地はまだまだあります。ご興味ある方はカジュアル面談からでもお話できますと幸いです。 他の職種も絶賛募集中です! 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは!フロントエンドエンジニアの張です! この記事はEnigmo Advent Calendar 2024の3日目の記事です。 エンジニアは日頃のタスクを対応するためにいろんなツール駆使していますが、絶対になくてはいけないツールと言いますと、やはり テキストエディタ ー一択だと、私は思っています。 その テキストエディタ ーですが、実は何種類もあって、側から見ると、どれも同じように見えるかもしれませんが、毎日何時間もそれで仕事をするエンジニアにとって、自分に合うエディターを選ぶことは実は仕事の効率とモチベーションに大いに関わっています。 本記事では、ここ約一年半、私が毎日使っている最強エディター Neovim について、ご紹介します。 Neovim とは もしかしたら Neovim を知らない方も多いかもしれませんが、それがエンジニアなら誰しも一回は使ったことがある、名高い Vim エディターをリファクターしたものです。 そのため、 Neovim は Vim の特性と独自の機能を備える、モダンな コマンドライン エディターになっています。 特性 Vim から受け継いだもの ベースが Vim になっている Vim を fork して開発したもの Vim motion Vim command 反応速度が早い ミニマル 独自の特性 Lua でコンフィグ可能 LSPのネイティブサポート 強み Neovim について簡単に説明しましたが、それは一体ほかの主流のエディターと比べて、何の強みがあるでしょう。 Vim Motion Vim Motionというのは Vim 、あるいは Neovim 上で使える、カーソルを移動させたり、テキストを編集したり、できるショットカットです。 Motionを使いこなせると、マウスなしでテキストを高速で編集、ナビゲートすることが可能になります。 それは日々大量なテキスト、あるいはコードを処理するエンジニアにとって、とても貴重なスキルです。 実例 個人的に最も使っている Normal Mode 下の基礎Motionが以下となります Motion 機能 [count] h カーソルを( count 行)左に移動させる [count] j カーソルを( count 行)下に移動させる [count] k カーソルを( count 行)上に移動させる [count] l カーソルを( count 行)右に移動させる [count] w カーソルを次/ count個後の単語に移動させる [count] b カーソルを前/ count個前の単語に移動させる i insert mode に移行して、カーソルを左に一行移動させる a insert mode に移行して、カーソルを右に一行移動させる d [motion] motionの終着点までの文字を削除する x カーソルの位置の文字を削除する y [motion] motionの終着点までの文字を複製する p yで複製した内容をペーストする Text object selection を利用したMotion Motion 機能 ciw カーソルが位置する単語を丸ごと削除して、insert modeに移行する diw カーソルが位置する単語を丸ごと削除する dap カーソルが位置する段落を削除する yap カーソルが位置する段落を複製する 使えるMotionは実際まだまだありますが、量が多いのもありますし、 公式ガイド を参考した方が的確なので、ここでは割愛させていただきます。 効率的で楽しい 以上の実例を見ると、 Vim / Neovim が高速なテキスト編集を実現できることがわかると思いますが、それは実は私にとって、一番大事なメリットではありません。 では、一番のメリットは何でしょうか! 楽しい! そう!楽しくテキストを編集できること自体が一番のメリットだと思います。 よく見ますと、 Vim Motionってゲームのコンボに見えないでしょうか? Vim / Neovim なら一日中コードを書いても退屈することはありません! それがエンジニアのモチベーションを引き上げて、効率を改善できることを私はこの一年半ですごく実感できました。 PDE(Personalized Development Environment) Neovim は一部のエンジニアから、 PDE 、つまり 個人的開発環境 とも呼ばれています。 それは Neovim のコンフィグ自由度がとても高くて、ユーザーがそれを思い通りに自分好みにできるからです。 具体的に言うと、UIの表示、文字を打つ時のエフェクト、ユーザー入力への反応など、その気になれば全部自分で実装できます。 結果として、ユーザーは自分のワークフローにピッタリな開発環境を構築できて、開発の効率を大幅に上げられます。 効率改善以外、PDEはユーザーのモチベーションの向上にもつながると思います。 なぜかと言うと、エンジニアが仕事のタスクをPDEで対応することで、自分が設計したツールをテストできるからです。 開発が好きなエンジニアなら、それだけで仕事へのモチベーションが大幅に上がるでしょう。 多彩な プラグイン 近年、開発を支援したり、ワークフローをスムーズにしたり、できる プラグイン がプログラミングエディターの必要不可欠な要素だと思われる傾向が強まりつつあります。 当然、 プログラマー のためのエディターである Neovim にも充実した プラグイン エコシステムがあります。 ここでは、重点的に、何個か人気な プラグイン についてご紹介します。 Telescope Telescopeは Neovim コアの機能を利用した、高性能な Lua 製 Fuzzy Finder です。 簡単に言うと、指定した範囲以内のコンテンツをキーワードで検索するツールです。 例えば、コードベース内のファイルを大まかな文字列で検索したり、特定な文字列がコードベースのどこに記載されているかを探したり、することが可能です。 それだけでも結構便利なツールなんですが、もっとすごいのはTelescopeの拡張性です。 Neovim と同様に、Telescopeは拡張性に重きを置いてデザインされました。 そのため、Telescopeの既存機能を利用して、新しい機能を作成することも比較的に簡単にできます。それに、純 Lua 製の プラグイン であるため、 Lua でカスタマイズするのもとても便利です。 もちろん、原作者と他のコミュニ ティー メンバーによって、もうすでにたくさんの 拡張機能 が作られたので、まだ自分で機能を作成したくないユーザーでも充実した既存機能を利用できます。 私がよく使っている機能をリストアップすると、以下となります。 builtin.buffer 開いたバッファの中からファイルを検索する builtin.find_files コースベース内のファイルを検索する builtin.live_grep コースベース内で特定の文字列やパターンを検索する 詳細に興味がある方はぜひ 公式GitHubページ をご覧ください! LSP(Language Server Protocol) 関連 プラグイン Neovim と Vim の違いの話になると、ビルトインのLSPサポートの有無が必ずといっていいほど話題に出されます。実際、LSPのサポートを目当てで Neovim に移行したユーザーも結構います。 では、LSPとは一体何なのでしょうか? 一言で言うと Microsoft 社が開発した、エディター/ IDE とLanguage Serverの間のコミュニケーションを可能にする プロトコル です。 Visual Studio Code などのエディターがコードのオートコンプリート、定義元への移動、コードの診断(Diagnostic) ができるのもLSPのおかげです。(LSPは元々 Visual Studio Code のために作られています) 詳細は こちらの公式サイト で閲覧できるので、興味がある方はぜひご確認ください。 前にも話した通り、 Neovim にもそのLSP機能を搭載されています。そして、それを中心に作られた プラグイン もたくさんあります。それらも利用すれば、簡単かつ自由度が高いLSP設定ができるため、 Neovim でのLSP体験はいろんなエディターの中でもトップクラスです。例えば、Language Serverから受信した情報に基づいて、画面上にコードに関する情報を表示するのも簡単にできます。 複雑だと思うかもしれませんが、以下のLSP プラグイン を利用すれば、大体のLSP設定ができます。 nvim-lspconfig いろんなLanguage Serverのデフォルトコンフィグを提供する mason.nvim Neovim 用のLanguage Serverパッケージマネージャー 簡単に主流のLanguage Serverをインストールできる mason-lspconfig nvim-lspconfig と mason を繋げるもの LSPを管理する mason. vim 今ではLSPを利用するエディターも結構増えましたが、設定の手軽さ、自由度、エコシステムの大きさのため、 Neovim を選択するユーザーもまだまだ増えています。 おわりに 以上が私が約一年半 Neovim を使って、未使用の方にも知ってほしい Neovim の見どころでした。 まだまだ説明しきれてないことが多いですが、 Neovim が素晴らしいプログラミングエディターであることが伝われたら嬉しいです! 文章を読むだけではピンと来ないかもしれないので、時間がある時、ぜひ、 Neovim を使ってみてください! 明日の記事の担当は 採用広報担当 の戸井さんです。お楽しみに。 おまけ 初心者が自分で0から Neovim を始めるのは結構ハードルが高いので、自分が最初に使ったリソースを幾つか共有したいと思います。 Neovim公式 kickstart.nvim Neovim のコア開発者の一人が開発した Neovim コンフィグ clone したらすぐ使える コードの説明がとても詳しくて、初心者に優しい vimtutor Vim Motionを勉強できる cli tool vim をインストールすれば、一緒にインストールされる Unix-like のシステムでは大体デフォルトでインストールされている
こんにちは!Webアプリケーションエンジニアの 川本 です! 最近は BUYMA の出品者向けのチームでパフォーマンス改善に取り組んでおります。 この記事は Enigmo Advent Calendar 2024 の 2日目の記事です。 少し日が経ってしまいましたが、2024年10月16に開催された「Datadog Summit Tokyo 2024」に参加してきました。 www.datadoghq.com 直近の業務でパフォーマンス改善に取り組む機会が多かったのですが、その際にオブザーバビリ ティー の向上を支えてくれる、Datadogに興味を持ちました。開発エンジニアにとってもこれらを活用できると視野が広がると感じ参加を決めました。 印象に残ったセッション Datadog ダッシュ ボードで 見える化 する、新たなビジネス価値創造のチャンス www.datadoghq.com このセッションでは、リリースした機能が意図通りに使われているかを分析し、期待されるスコアを可視化する ダッシュ ボードの活用例が紹介されました。 ダッシュ ボードから課題を発見し、改善につなげることでビジネス価値を創造していくという内容でした。 特に印象に残ったのは、エンジニアがビジネス観点を持つ重要性です。 ダッシュ ボードを作成するためには、案件の目的や必要なデータを理解する必要があり、それがビジネス観点を養うきっかけになると感じました。 弊社でも新機能をリリースする際に、エンジニアが ダッシュ ボードを準備し、ビジネス側と連携しながら価値創造に貢献していきたいです。 開発者の生産性向上 www.datadoghq.com このセッションでは、Datadogを活用した開発生産性向上に関するパネルディスカッションが行われました。 最も印象に残ったことは、 Wantedly 社の市古さんがおっしゃっていた「オブザーバビリティは開発を加速させる」という点です。 www.wantedly.com 大規模 リファクタリング やライブラリのバージョンアップ等を行った際の影響範囲はとても広いので、ステージング環境でなるべく確認しようとしても、全てを完璧に把握することは難しいことが多いかと思います。そのため、本番環境にリリースする際はどうしても慎重になりスピード感が損なわれてしまいます。 しかし、オブザーバビリティを向上させると、問題が発生しても素早く発見・対応できるという安心感が得られます。これにより、適切なリスクを取れるようになり、レビュー 工数 の削減や認知負荷の軽減につながるため、スピードと品質の両立が可能になるという内容はとても納得できました。 弊社で運営しているサービスの「 BUYMA 」も歴史の長いサービスで、これから大規模リプレイス、大規模 リファクタリング 、ライブラリの大幅なバージョンアップを控えております。その際に今回学んだことを活かして、オブザーバビリティを向上させながら開発生産性を維持しながら問題と向き合っていきたいです。 導入したいDatadogの機能 今回のサミットを通して様々なDatadogの機能について知ることができました。 その中でも自社で導入したいと考えている機能は Datadog Continuous Profiler です。 www.datadoghq.com Datadog Continuous Profilerとは? Datadogの公式ページでは以下のように紹介されております。 Datadog Continuous Profiler を使用すると、最小限のオーバーヘッドでスタック全体にわたって本番環境でのコードパフォーマンスを分析できます。コードプロファイリングを利用して、アプリケーションで最もリソースを消費するメソッドまたはクラスをすばやく検出および最適化できます。これにより、コードの効率が向上し、 クラウド プロバイダーのコストが削減されます メソッド単位でどれだけ時間がかかっているかや、CPU時間、メモリ使用量等のリソースの消費量が可視化されるので、パフォーマンスの ボトルネック を発見するのに最適です。 導入したい理由 この機能を導入したいと思ったのは、弊社で運用されはじめて長年経過した機能のパフォーマンス改善に取り組んだことがきっかけでした。 私は ボトルネック を見つけるのにまず該当するコード全体を読んでいたのですが、これは根拠のない推測をしているだけで効率が悪かったなと反省しております。 そういった際に Continuous Profiler で計測してコードレベルで可視化して ボトルネック になっている箇所を明確にし、修正の目処を立てるといったことができていればより効率的かつ効果的なアプローチがとれていたなと感じております。 おわりに 今回のイベントを通してDatadog、オブザーバビリティに関して新たな知見を得ることができたのと同時によりこの分野に興味を持つことができました。 今回ワークショップには参加できなかったので Datadog Learning Center で興味のある講座を受講して実際に手を動かしてDatadogに関する知見を深めていこうと思います。 最後に、帰り際にいただいたDatadogのかわいいグッズも大切に使わせていただきます! 運営の皆様、素晴らしいイベントをありがとうございました! 明日の記事の担当は フロントエンドエンジニア の張さんです。お楽しみに。 株式会社 エニグモ すべての求人一覧 hrmos.co
こんにちは!WEBアプリケーションエンジニアの 川本 です! この記事はEnigmo Advent Calendar 2024の1日目の記事です。 弊社の運営する BUYMA では、社内システムよりタイムセールを毎週 約100万商品 に設定しています。しかし従来のシステムでは、この処理に 約100時間 もかかっており、運用負荷が大きな課題となっていました。本記事では、パフォーマンス改善によって処理時間を 約5時間 に短縮し、運用効率を向上させた事例をご紹介します。 タイムセール設定機能について 処理フロー タイムセール設定機能はざっくり以下のような処理フローになっています。 CSV ファイルのアップロード タイムセール設定依頼情報を記載した CSV ファイルを S3 にアップロードします。 SQSへのエンキュー S3にファイルがアップロードされると、SQSにメッセージがエンキューされます。 Redisに保存 常駐しているデーモンがSQSキューをポーリングし、SQSから取得したメッセージをRedisに保存します。 Sidekiqジョブの実行 Redisに保存されたメッセージをSidekiqがデキューして、タイムセール設定の処理を実行します。 性能 タイムセール設定を行うSidekiqの性能は以下の通りです。 専用プロセスの使用 タイムセール設定ジョブは専用のSidekiqプロセスで実行。 並列処理数 1プロセスあたりの並列処理数は10。 冗長化 2台のサーバー構成で冗長性を確保。 設定例(sidekiq.yml) --- :labels : - default :concurrency : 2 :pidfile : tmp/pids/sidekiq.pid :logfile : ./log/sidekiq.log production : :concurrency : 10 :queues : - [ setting_timesale, 1 ] 課題の発見 従来の仕組みでは、タイムセール設定依頼の CSV ファイル1つを1スレッドで処理していました。これにより、以下のような問題が発生していました。 スレッド活用不足 Sidekiqはマルチスレッド対応で高い並列処理性能を持っていますが、1つのスレッドが1つの CSV を丸ごと処理していたため、マルチスレッドであること効果的に活用できていませんでした。 長時間実行による運用負荷 1つの CSV には約100万件の商品データが含まれており、これを1スレッドで処理することで、処理時間が長時間に及び、運用上現実的でない時間になっていました。 CSV 分割の運用負荷 スレッドを有効活用するには、 CSV をあらかじめスレッドの数だけ手動で分割する必要があり、これが運用上の手間となっていました。 改善アプローチ 上記の課題を解決するため、システム側で1つの CSV データをバッチ単位(100商品)で分割し、各バッチを複数スレッドで並列処理する方式に変更しました。これにより、処理の効率化と運用負荷軽減を同時に実現することが可能になりました。 改善後の処理の流れ 親ジョブ が CSV データをバッチ単位に分割し 子ジョブ を作成・エンキューする。 子ジョブ が実際のタイムセール設定処理を実行する。 監視ジョブ が 子ジョブ の進捗を追跡し、全て完了したら設定完了の処理を実行する。 登場してきたジョブについて↓ 親ジョブ CSV ファイルから取得したタイムセール設定依頼データをバッチ単位に分割。 各バッチについて 子ジョブ をエンキューし、ジョブIDを記録。 最後に 監視ジョブ をエンキューし、 子ジョブ の進捗を監視。 実装例↓ module SidekiqWorker # 親ジョブ class Parent include Sidekiq :: Worker sidekiq_options queue : :setting_timesale BATCH_SIZE = 100 def initialize (args) # 省略 end def perform child_job_ids = [] # バッチ単位でタイムセール依頼データを分割 timesale_request_data.each_slice( BATCH_SIZE ) do |batch| # バッチ単位でタイムセール設定を行う 子ジョブ をエンキュー child_job_ids << SidekiqWorker :: Child .perform_async(batch) end # 子ジョブの進捗状況を管理する 監視ジョブ をエンキュー SidekiqWorker :: Monitoring .perform_async(child_job_ids) end private # s3からタイムセール設定依頼データを取得 def timesale_request_data # 省略 end end end 子ジョブ バッチ単位(100件)の設定依頼に対してタイムセール設定の処理を実行。 ジョブの進捗状況をRedisに記録。 子ジョブの状態管理に sidekiq-status というgemを使用しました。 github.com sidekiq-status は、Sidekiqで実行中のジョブの状態を追跡するためのGemです。ジョブの状態(例: queued, working, completeなど)をRedisに保存し、進捗をリアルタイムで確認できるようになります。 module SidekiqWorker # 子ジョブ class Child include Sidekiq :: Worker include Sidekiq :: Status :: Worker sidekiq_options queue : :setting_timesale # 24時間ジョブの状態をRedisに保持する def expiration @expiration ||= 60 * 60 * 24 end def perform (timesale_request_data) SetTimeSaleService .new(timesale_request_data).call end end end 監視ジョブ 子ジョブの進捗を追跡し、全ての子ジョブが完了した場合に完了処理を実行 追跡できない子ジョブが存在した場合はアラートを飛ばす。 sidekiq-statusの API よって以下のように子ジョブの状態を確認することができます。 job_id = SidekiqWorker :: Child .perform_async # :queued, :working, :complete, :failed or :interrupted, nil after expiry status = Sidekiq :: Status ::status(job_id) # <- ジョブ状態を確認 Sidekiq :: Status ::queued? job_id # <- キューにあるか? Sidekiq :: Status ::working? job_id # <- 実行中か? Sidekiq :: Status ::retrying? job_id # <- リトライ中か? Sidekiq :: Status ::complete? job_id # <- 完了したか? Sidekiq :: Status ::failed? job_id # <- 失敗したか? Sidekiq :: Status ::interrupted? job_id # <- 中断されたか? 実装例↓ module SidekiqWorker # 監視ジョブ class Monitoring include Sidekiq :: Worker include Sidekiq :: Status :: Worker sidekiq_options queue : :setting_timesale SLEEP_TIME = 15 def perform (job_ids) @job_ids = job_ids loop do @job_ids .reject! do |job_id| job_complete?(job_id) end break if @job_ids .empty? sleep SLEEP_TIME end TimeSaleSettingCompletionService .new(args).call end private # ジョブが完了したか? def job_complete? (job_id) Sidekiq :: Status .complete?(job_id) end end end 学んだこと 性能要件の見直しの重要性 長年運用されているシステムは、リリース当時の性能要件がそのまま適用されていることが少なくありません。しかし、システムの利用状況や運用環境は時間の経過とともに変化します。今回の事例でも、リリース当初は妥当だった処理速度が、現在では運用負荷を引き起こす大きな要因になっていました。 そこで重要なのは、現状の運用方法をしっかりと把握し、必要に応じて性能要件を再定義することです。運用者に ヒアリ ングを行い、現在の問題点を明確にすることで、改善に向けた具体的な指針を得ることができます。 並列化によって増す複雑性 並列化はシステムの処理速度を大幅に向上させる一方で、複雑性を増す側面があります。一連の処理が複数のジョブに分散されるため、それぞれのジョブの状態を適切に管理する必要が生じます。今回の事例でも、Sidekiqを用いた並列化に伴い、以下のような課題が明らかになりました。 ジョブの状態管理コスト 並列化することで、ジョブの進捗や完了状態を追跡する仕組みが必要になります。このため、Redisを活用したジョブの状態管理が不可欠となりましたが、それには追加の開発コストと運用リスクが伴います。 ジョブの状態欠損のリスク 例えば、Redisに障害が発生した場合、一部のジョブの状態が欠損する可能性があります。このリスクを考慮し、ジョブの再実行や障害時の リカバリ ープロセスを検討する必要があります。 並列化の インパク トは大きいですが、システムの複雑性は増してしまいます。まずは 処理内容自体のパフォーマンス改善 に目を向けることが大切です。今回のプロジェクトでは、並列化に先立ち、子ジョブ内で実行されるタイムセール設定処理の最適化を行いました。 おわりに パフォーマンス改善は、単に処理を「速くする」ことが目的ではなく、システムの要件や複雑性を考慮し、最適なバランスを見つけることが重要だなと思いました。 今回学んだことを活かしてこれからもパフォーマンス改善に取り組んでいきたいです! 株式会社 エニグモ すべての求人一覧 hrmos.co