TECH PLAY

ニフティ株式会社

ニフティ株式会社 の技術ブログ

517

はじめに 初めまして!新卒一年目のpopopopman、稲継、statiolakeです。 弊社では新人の育成のため、毎年エンジニア定例という勉強会が行われています。先日、その集大成として3日間にわたる開発合宿、通称「エンジニア定例合宿」に参加してきました。 詳細につきましては こちら をご覧ください。 本記事では私達チーム†skyscraper†の作ったスポーツイベントでビンゴを行うサービスについて紹介していきます。 メンバー紹介 popopopman 担当 :フロントエンド 普段の業務 :インフラ管理とセキュリティの運用 一言 :いい仕事は、いい遊びからよ。 稲継 担当 :フロントエンド 普段の業務 :バックボーンネットワーク運用 一言 :がんばるます statiolake 担当 :バックエンド、DB設計、インフラ 普段の業務 :Webサービス開発 一言 :NeovimでRustを書く、これが最強。 プロダクト紹介 概要 今年は第39回夏季オリンピック競技大会、パリ2024が開催されます。この楽しいイベントをさらに盛り上げるべく。オリンピックのメダル獲得をした国と競技に応じてビンゴを行うサービスを作成しました。機能を紹介していきます。 遊び方 今年開催されるパリオリンピックの試合結果を元にビンゴゲームを行います。 はじめに、トップページで”名前”と”秘密の言葉”を入力し、ビンゴカードに移動ボタンを押します。 すると、入力された”名前”と”秘密の言葉”を元にビンゴカードが生成されます。 このビンゴカードの1マス1マスには、競技と国がセットになって描かれています。オリンピック期間中、ある競技である国がメダルを獲得した場合、そのマスを開けることができます。普通のビンゴカードだと数字が書かれていて、呼ばれた番号のマスを開くことができますよね。このビンゴでは、例えば、仮に100m走で日本がメダルを獲得したときに、そのマスを開けることができるという寸法です。 ビンゴ画面(初期状態) 大会はまだ始まっていないため、今回は結果を仮で設定しました。すると、以下のように表示が変わります。青がビンゴで黄色がリーチ、灰色がどちらでもない開いているマス、黄色い線で囲まれているマスが、そのマスが空くとビンゴになるマスです。 ビンゴ画面(ゲームが進行した状態) また、マスをクリックすると画面右側に競技名、種目名、チーム名、パネルが開くことで得られる点数が表示されます。 ビンゴ画面(マスの情報を表示) システム構成図 システム構成図 フロントエンドはSvelteというJavaScriptフレームワークとTailwind CSSというCSSフレームワークを使用しました。これにより、少ないコードで高いユーザーエクスペリエンスを実現しました。また、バックエンドにはRustとそのWebアプリケーションフレームワークであるaxumを、データベースとしてPostgreSQLを使用しました。これにより、バックエンドの高速な処理を実現しています。 これらをコンテナ化してEC2上で動作させることでユーザーがこのサービスにアクセスできるようにしました。(実際にリリースはされていません。) 開発で工夫したところ 開発期間が短いながら、なるべく完成度の高いものを作り上げるため、様々な工夫をしました。ここでは、そのうちのいくつかをご紹介します。 フロントエンドとバックエンドを効率よく完全に分業する 開発期間の短縮と作業効率の向上を実現するために、バックエンドとフロントエンド間のデータ通信をAPIを介して行うことにより、開発を完全に分業しました。これにより、各自の担当範囲に集中することができ、プロジェクト全体の進行速度と生産性が向上しました。 フロントエンド側のUXにかなりの比重を置き、粗の少ないユーザー体験を作る フロントエンドの開発では、ユーザー体験(UX)に特に重点を置きました。アニメーションや直感的でシンプルなインターフェースの設計、ローディング時間の短縮、など、ユーザーがストレスなく、そして楽しく操作できるような環境を作り上げることに注力することで、長時間使用したくなるようなサービスを目指しました。 ビンゴ画面の動作 「最低限の機能」を十分小さく定義し、動作する状態をキープしながら拡張を続ける 開発の初期に「最低限の機能」を定義し、まずはその範囲内で動作するシステムを作りました。これ対し段階的に機能を追加していくことで、短い開発期間で間に合わないという不安のない状態を保ちつつ完成度を高めていく作業に注力することができました。 合宿を通じた学び 短期間でのチーム開発 今回の合宿では、各自が持つ技術や知識をチームの中でどう活かせるかについて深く考える機会を得ることができました。それぞれの強みを生かし、役割を効果的に分担することで、プロジェクトの進行が大きくスムーズになったのを感じることができました。また、短期間ならではの迅速な意思決定と効率的なタスク管理の技術を磨くことができ、自分の最高速の開発スピードを知ることが出来たので貴重な経験になったと思います。 新しい技術に触れる 私たちのチームの裏のテーマとして「触れたことのない新しい技術に触れる」というものがありました。誰も触れたことのないフレームワークだったり、言語を積極的に用いたことでチームメンバーとの相談や議論が盛り上がったと思います。ただ技術を学ぶだけでなく、新しい技術に触れることの面白さや、そしてそれをチームで共有する楽しさを経験することができました。 終わりに 合宿を通して、私達は限られたリソース、期間と持ちうる技術の中で最大限の成果を出すための戦略を体験しました。チームで協力し、強みに応じた役割の分担や「最小限の機能」からの機能の拡張といった工夫によってより良い成果物を生み出すことができたと思います。一つのシステムをゼロから作り上げ、かつ効率や完成度を求め達成するという貴重な経験ができました。 しかし、今回の成果物に完全に満足しているわけではなく、終わってから振り返ると、改善の余地や技術力の不足を感じています。 この経験を個人での学習やより大規模な業務でのチーム開発に活かしていきたいです。 引用 本記事に掲載されているシステムで使用されているピクトグラムは、Wikimedia Commonsによってパブリックドメインとして提供されたものです。 https://commons.wikimedia.org/wiki/User:Parutakupiu#Summer_sports ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 カジュアル面談も随時受付中! ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたします! キャリア登録 connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
はじめに こんにちは。新卒1年目の宮永です。もうすぐ新卒バリアが使えなくなるので怯えています。 先日、1年目・2年目を対象としたハッカソン合宿に参加しました(合宿概要は こちら )。 テーマがいくつかあり、今回私たちは「健康を増進するサービス」として飲酒量管理のwebアプリを作ったので紹介します。 メンバー 江口 普段の業務:社内システムの開発・運用 今回はDBやflaskなどのバックエンドを主に担当 三度の飯よりDBが好き。初日は不安でご飯の味がしなかった。 西根 普段の業務:ニフティポイントクラブの開発 今回はflaskとフロントエンドを主に担当 CSSを完全に理解している。得意なことは賑やかしです!!!!! 宮永 普段の業務:SREを社内に広める活動 今回はコンテナ周りやDB等のバックエンドを主に担当 パケットの話で盛り上がりたいタイプ。最近はダイヤルアップにはまっている。 成果物 今回は飲酒量管理のwebアプリを作成しました。 概要 飲酒量を入力して、純アルコール量と血中アルコール濃度、分解に必要な時間を表示 酔い度により肝臓の色が変化し、視覚的にどれくらい肝臓に負担がかかっているかを表示 ログイン機能と履歴機能を付け、飲酒習慣を可視化 デモ ページにアクセスすると最初にログイン画面に遷移します。 ログインすると、今までに登録した飲酒の履歴一覧が見れます。 飲酒量登録画面では、飲んだお酒の量と体重を入力します。 入力すると、アルコールが抜けるのに必要な時間や酔い度などが表示されます。酔い度によって肝臓が黒くなっていくのがポイントです。 ネタ枠で、好きな割合でハイボールを作るページも作りました。 TailwindCSSを使ったおかげもあり、短時間でいい感じの見た目にできたのではないかと思います。 システム構成 今回はDocker Composeを用いたコンテナで構成しました。メンバーの使用PCにWindowsとMacの両方があり、開発時に環境差分で苦しみたくなかったからです。 また、時間があればAWSデプロイしたかったのですが、その際もデプロイしやすいだろうという判断でコンテナ構成にしました。(結局デプロイまでは間に合いませんでした…) バックエンドはFlask、DBはMySQLを使用しました。入社時の技術研修で使っており、ネット上にも情報が多かったので採用しました。 フロントエンドにはTailwindCSSを使用しました。メンバー全員触ったことのない技術でしたが、面白そうなので思い切って採用しました。興味だけでシステム構成を決められるのは合宿の良い所ですね。 工夫した点 開発期間が短い制約がある中でも、工夫して上手にできた点がありました。 作業の優先順位をすばやく決める事ができた やりたい事、やらないといけない事が沢山ある中、手を動かす前に話し合って優先順位を上手に決めることができました。ある程度進んでいく中でも、無理そうであれば早めにあきらめる事もできました。 開発初期で環境を上手に作ることができた 最低限作らないといけない部分の優先度を上げたため、開発期間前半でバックエンド構成やDB初期データ自動投入の仕組みを完成させることができました。開発後半は「とりあえずシステムが動いている」という安心感を持った状態でアプリケーションの機能開発に集中して取り組むことができました。 CSSフレームワーク使って短時間でいい感じにできた 最初からCSSフレームワークを使ったため、「この画面と同じような感じで!」というざっくり指定でも別のメンバーに作業を引き継ぎやすかったです。導入は多少大変でも、トータルでかかる時間を短縮することができました。 作業が軌道に乗ってからは2時間毎に進捗確認→新規タスクの洗い出しと優先度決め→タスク割り振りをしたので作業を進めやすかった 後から思えば、スプリントがとても短いスクラムのように回すことができました。ハッカソンではハプニングがつきものですが、その中でも変化に強い動き方ができたのではないかと思います。 またコミュニケーションがとれていたため、メンバーの忙しさやスキル面をお互いに理解しやすく、結果として作業割り振りが上手にできました。重複が無いようなタスクの分割ができるようにも注意できたため、「マージしたら壊れて動かなくなった!」という事故が起こらなかったです。 苦労した点 もちろん苦労した部分も多かったです。 DB周り DB設計を23時に行ったため、頭が働いておらず不完全なものになっていました。翌日に結局DB構成を変えることになり、DBが関わる実装部分をすべて修正することになってしまいました。(江口君本当にごめんなさい…) コンテナNW周り Docker ComposeでアプリケーションコンテナとDBコンテナの2つを作る際にbridgeネットワークの設定を忘れており、ホスト側からは接続できるのにコンテナ同士は接続できない状態にしてしまいました。ホストから見るlocalhostとコンテナから見るlocalhostが違うことを理解するまでにかなり時間を費やしてしまいました。 flaskの導入が大変 メンバー全員が研修以来使っておらず、覚えていなさすぎて最初これ動くものできる?大丈夫?という気持ちになりました。普段の業務ではフレームワークの導入を触ることは無いため導入部分が一番大変であることを痛感しました。 フロント周り フロントを主に担当した西根さんはCSSに慣れており、はじめはCSSを想像してTailwindのクラス名調べて…という謎作業をしていました。フレームワークは慣れるまでも大変でした。 また、svg画像の扱いが不慣れで、画像にグラデーションを付ける作業(肝臓の色を悪くする部分)に苦労しました。 学んだこと 設計をちゃんとすることは大事 DBのカラムを別テーブルに移動させなければいけなくなったり、新規アカウント登録機能がないことに2日目の途中で気づいたりなど、本来序盤でビシッと決めておくべき部分が決まり切っていないせいで後半苦労した面が多かったです。とりあえずコードが書きたくなっても、決めるべきことはしっかり決めないと自分が痛い目に遭うという事を痛感しました。 コンテナ周りの知識 今回は一番最初に「全部コンテナで構成するぞ!」と決めましたが、メンバー全員Docker Composeでの構成経験はありませんでした。苦しみながらもコンテナやコンテナを接続するネットワーク回りの知識が付いたかなと思います。 エンハンスと新しく作ることで要求されるレベルの違い 普段の業務はどうしてもエンハンスが多くなりがちですが、新しく何かを作るとなると設計を考える力やチームビルディングの力など、様々な力が要求されることが実体験として理解できました。 大変な一方で、全体が理解できていることの安心感や、自分たちで作り上げた達成感も体感することができました。 まとめ 今回の合宿ではメンバーそれぞれ得意な部分を主に担当しつつ、普段触らない技術についても助け合いながら担当し、短い期間で成果物を作り上げることに成功しました。技術面はもちろん、なんとかすることができたという自信を得る事ができました。 制約がある中でなんとかすることができた経験を自信につなげ、これからの業務に生かしたいです。 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 カジュアル面談も随時受付中! ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたします! キャリア登録 connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
前回の記事では、ニフティのISPオペレーションチームで働く社員に、業務内容やチーム環境についてインタビューを行いました。 今回はインタビューの後編をお届けします。前編はこちらの記事をご覧ください。 【インタビュー】ニフティのISPオペレーションチームチームの過去から未来について【ISP前編】 過去行った業務内容について H.Fさん、K.Hさんはニフティに長く勤めていますが、過去にはどういった業務を行ってきましたか K.Hさん 勤続年数が30年を超えたので、様々なことを経験しました。 入社当初はパソコン通信アプリの開発をしていました。お客さんの回線からきた通信に応答を返すプログラムを作っていました。当時はコンピュータを何十台も繋いで通信するような例が無い中でそれを実現するネットワークベースの通信ソフトの開発・運用をやっていましたね。 その後もNIFTY Managerという新規ソフトの立ち上げにも携わりました。いままでは1つのファイルしかリアルタイム通信できませんでしたが、バックグラウンドで複数のファイル送受信を可能にしたりなど、やりがいのあるものでした。他にも、当時の弊社のサービスはリアルタイムのチャット機能がなかったので、Javaアプレットを用いてチャットを行うようなツールを作ったりもしました。 技術の黎明に携わらせてもらうことが多かったように思います。誰もやったことがないことをスケジュール管理しながら取り組んだ経験が今の業務にも生かせているなと感じていますね。 H.Fさん 私が一番印象に残っているのは社内インターネットのデータセンターの立ち上げですね。 社内から外部インターネットの接続方法の検証なども行っていましたが、仮想化基盤の作成が一番大きい仕事でした。一つのマシン上に複数のサーバーを立てられるように、ローカル仮想マシンソフトウェアをデータセンターのマシンに導入しました。どうすれば動くかといった技術的課題について、当時のネットワークチームとも協力して解決に導きました。 一方で苦労した点としては、社内で動いていた沢山のサーバーを全てデータセンターに移行させるので、考慮すべきことや調整すべきことが複数あったことです。 社内の多種多様なマシンを移行するので、適切なスペックを計算したり、コストの見積もりをしたり、ネットワークの回線速度やキャパシティの観点を把握するのが大変でした。加えて、サーバーは複数部署で使われていたので、移行にあたり各所での調整が必要だったりスケジュールの調整などで頭を悩ませました。 これらを乗り越えて培った技術のお陰で、いまの回線状況の把握やスピードテストといった業務に繋がっています。 ニフティの「ISPオペレーションチーム」ができるまで ISPチームはどのような経緯で出来上がったのでしょうか? H.Fさん 実は、自分やK.Hさんの入社当初のニフティにはまだ「ISPのチーム」といったものはありませんでした。 M.Kさん そうだったんですか。 H.Fさん 以前のネットワーク運用はグループ会社が担当していたので、今とは異なる状況でしたね。ニフティの会社構造が変わるにつれてISPオペレーションチームが出来上がりました。そのため、社内にノウハウがない中で何をすればいいのか、お客様に快適に使用していただくためにはどうしたらよいのだろうかを日々考えながら一歩一歩手探りで進めてきて今のチームがあります。 K.Hさん ニフティが今のニフティであるのは、いままでサービスが続けられているのは、サービスの利用者は勿論、社員達が培っていた技術や経験のお陰と思っております。 現在のチームの課題とは 現在のチームの課題はどういったものがありますか、それに対してどうやって取り組んでいますか M.Kさん 先ほどのお話にもありましたが、ISPチームではDNSサーバーと認証サーバーの管理を行っています。しかし、アーキテクチャや設計思想が昔から引き継がれてきた状態のままになっております。 そのため、運用コストや利用料などの多くの面で最適化の余地が見られており、より柔軟で効率的な運用を目指すためにクラウド基盤への移行を検討しています。 具体的な移行計画を立てるために、現在は既存サーバーの詳細な仕様調査を進めています。 今後の展望 今後の展望を聞かせてください。 K.Hさん お客様サービスの品質を最重要視しつつ、新たに出てくる技術を用いてお客様に魅力あるISPサービスを引き続き提供していきたいと考えています。 M.Kさん ログの取得作業や分析データの前処理の自動化といった効率化を進めていますが、まだまだ手作業だったりモダンな技術に載せ替えられていない部分があります。その他データ処理の自動化だけでなく、運用をより手軽にしていくために、サーバー上で行っているバッチの実行を順次サーバーレスにしていくなど、引き続き改善を行っていきたいです。 H.Fさん チームとして成果を出すためには、皆が成長することが必須です。ISPチームはそのような土壌を作ってきましたので、皆で考え、あるべき姿を描き、それに向けて一丸となってチャレンジしていきたいと考えています。 今回はニフティのISPオペレーションチームのインタビューの様子をお届けしました。ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! このインタビューに関する求人情報/ブログ記事 ISPオペレーションチームの求人情報 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する .is-style-rounded + .has-text-color{ font-size:95%; }
自己紹介 K.Hさん ■入社年度・社歴 1992年入社 ■担当サービス   ・PPPoE用(@nifty光、NifMo)  接続認証サービス ・NTT系バックボーン運用 ・ダイヤルアップ運用 ■趣味やマイブーム、特技など ・自宅サーバ構築 ・飛行機や人などの写真撮影 ・北極ラーメン H.Fさん ■入社年度・社歴 1995年入社 ■担当サービス ・サービス用DNS ・NTT系バックボーン運用 ■趣味やマイブーム、特技など ・自宅サーバ構築 ・3Dプリンター工作 M.Kさん ■入社年度・社歴 2021年入社 ■担当サービス ・サービス用DNS ・NTT系バックボーン運用 ■趣味やマイブーム、特技など ・映画鑑賞・ゲーム ・SFやアクションなどを見る 最近見た映画は「キングスマン」 ISPとは? ニフティは「ISP(インターネットサービスプロバイダー)の老舗」と呼んでいただくことがあります。聞き馴染みの無い方に向けてISPとはどういったものなのか聞かせてください。 H.Fさん ISPはInternet Service Providerの略称で、インターネット接続サービスを提供する事業者のことをいいます。平たく言えば、プロバイダと契約したお客様がインターネットを使えるようにする役割を担っている人達ですね。 今やガス水道などのライフラインと同じように、無いと困るインフラの一つになってきています。 ISPに関する業務としては、一般的にはどういったものがありますか。 H.Fさん 業務は多岐にわたりますが、まずは、お客様が使用しているインターネットのネットワーク管理があげられます。また、お客様がきちんとサービスを利用できているか確認するために、インターネットの速度をモニタリングしたり、お客様の会員情報を管理することなどがあります。 これらを実現するために様々なサーバーを利用しますので、サーバーの運用や構築なども必要になります。 業務内容や取り組みについて 現在みなさんはどういったサービス、分野を扱っていますか。 H.Fさん お客様に提供しているインターネットのネットワーク管理分野に携わっております。インターネット利用者は年々増加し、それに伴うデータ量も増えてきています。かつてはテキスト中心だったインターネットが、今では動画やゲームなどのデータ容量の大きいものに変わってきました。そういったネットワークの使用量を観測し、将来のトラフィックを予測することで通信品質を確保しています。 お客様に提供しているインターネットの回線状況を確認するために、社内にお客様と同様の回線を複数用意して、回線スピードのチェックを定期的に行います。また、PC上で仮想マシンを構築し、複数の回線を適宜切り替えて利用できるようなシステムを整えています。これらにより、サービス品質を継続的に保証し、お客様により良いインターネット体験を提供する取り組みをしています。 これらの業務に加えて、DNSサーバの管理運用なども行っています。 K.Hさん 私はお客様がユーザー名とパスワードを入力することでインターネット接続を可能にするPPPoE認証の管理を中心に行っております。認証を行うだけでなく、インターネット接続サービスの使用開始及び終了についても管理しています。 対象は全てのお客様であり、PPPoE認証のリクエスト数が極めて多いです。大規模なデータを効率的かつ高速に処理することが求められています。そのため、処理にはC言語を用いています。ライブラリを使わず、システムコールをそのまま呼び出してオーバーヘッドを無くすことで、高速に動作させるようにしています。 M.Kさん 私もH.Fさんと同じく、DNSサーバーの管理を行っています。 具体的には、ドメイン名とIPアドレスの対応情報を管理するレコード情報の登録と変更作業を行っています。レコードは数万行に渡って存在するので、ニフティのISPとしての歴史の積み重ねを感じます。 また、バックボーンネットワークの管理に関しては、トラフィック需要を予測して対策を立てるプロセスの自動化に注力しています。現在はトラフィックログデータの取得や、分析の前処理などを自動化して効率化を図っています。 働き方やチーム環境について ISPオペレーションチームは様々な年齢層の方がご活躍している印象なのですが、チーム間のコミュニケーションはどのように取っていますか。また、どんなことを心がけていますか。 K.Hさん うちのチームはたまたま知見があったメンバーが集まり、そのあとに入社してくれた新人が加わった状態なので年齢層が高くなっていますね。 M.Kさん ベテランの先輩社員たちが多くの知見を持っていて、相談してもすぐに適格なアドバイスが返ってくるので、チャレンジしやすい環境だと思います。 H.Fさん M.Kさんは色々な物事に積極的に取り組んでくれていますね。仕事を進める上で気にかけないといけない部分や、大切な部分を理解しながら着手してくれていて助かっております。 M.Kさん ありがとうございます。 まだまだ覚えることがあるので引き続き頑張っていきます。 K.Hさん 毎朝、皆で議論する場をもっています。加えて、Slackを活用して悩んでいることや新しいアイデアを常に意見交換しています。メンバー皆が気軽に発言できる雰囲気づくりを心掛けています。 また、精神的に孤立しないよう、オープンチャンネル、DMを活用して交流を絶やさないようにしていますね。 後編に続きます! 今回はニフティのISPチームのインタビューの様子をお届けしました。続きは後編の記事をご覧ください。 【インタビュー】ニフティのISPオペレーションチームチームの過去から未来について【ISP後編】 このインタビューに関する求人情報 /ブログ記事 ISPオペレーションチームの求人情報 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する .is-style-rounded + .has-text-color{ font-size:95%; }
エンジニア定例 運営の南川です。 ニフティでは毎年、エンジニア定例という新卒1年目エンジニア向けの開発研修を行っています。 今年度の講義資料の一部を公開しているので、研修内容について気になる方は以下の記事をご確認ください。 ニフティ株式会社 エンジニア新人研修の内容を公開します | 2023年度版 – NIFTY engineering その研修の一環でハッカソン合宿を行っており、今回は4年ぶりのリアルでの合宿となっています! ちなみに私の代はリモートでの開催でした。その時の様子は以下の記事をご確認ください。 リモートでのハッカソン合宿を行いました! – NIFTY engineering ハッカソン合宿概要 目的 座学で学んだ技術を 実践 することで知識を定着させる。 2泊3日というまとまった時間で 集中したアウトプット を出す経験をする。 既存システムのエンハンスではなく、 0からシステムを作る力 を身につける。 個人開発と チーム開発 の違いを学ぶ。 スケジュール 1日目 2/5(月) 12:30 集合・チェックイン 13:00-18:00 開発 (14:00-14:30 オンライン配信) 18:00-19:00 夕食 19:00- 自由 (開発・入浴など) 2日目 2/6(火) 07:00-08:00 朝食 08:00-09:00 自由 (開発・散歩など) 09:00-12:00 開発 12:00-13:00 昼食 13:00-18:00 開発 (14:00-14:30 オンライン配信) 18:00-19:00 夕食 19:00- 自由 (開発・入浴など) 3日目 2/7(水) 07:00-08:00 朝食 08:00-09:00 自由 (開発・散歩など) 09:00-12:00 開発 12:00-13:00 昼食 13:00-14:00 成果報告会 14:00-15:00 終了連絡・撤収作業 15:00 解散 参加者 受講者 新卒1年目エンジニア 10名 3人チーム2組, 4人チーム1組 新卒2年目エンジニア 2名 2人チーム1組 新卒2年目エンジニアが少なく昨年度はハッカソン合宿ができなかったため、今回は1, 2年目合同で実施しています。 運営・開発サポート エンジニア6名 監督 シニアエンジニア1名 場所 ノジマ大磯スクウェア 〒255-0003 神奈川県中郡大磯町大磯1010 https://maps.app.goo.gl/qDRevCT8tqmRSnE88 JR東海道線 大磯駅から徒歩2,3分 レポート 1日目 2024/2/5(月) 今回の研修施設であるノジマ大磯スクウェアに現地集合しました。 集合時点で雪が降っていましたが、まだ交通網に影響が出る前で、誰も遅刻せずに来れました。 研修室にはWi-Fiやディスプレイ、ホワイトボード、延長コードなどが用意されており、開発する環境が整っています。 チームごとに分かれて、事前に行ったアイデアソンで考えてきたアイデアをもとに開発していきます! ドラッグストアやコンビニが近くにあるおかげで、2Lペットボトルやエナジードリンクなどの買い出しも気軽にでき、立地が良い感じです。(雪が降ってたのでしんどかったですが…) 14時からは社内向けのオンライン配信を行い、合宿や施設について、チームと作るものを紹介しました。 1日目の夕食ですが、配食の業者さんが雪の影響による交通渋滞に巻き込まれ遅れていたので、先に入浴を済ませ、20:30に待ちに待った夕食が来ました! こんな雪の中でも食事を作っていただき、ありがとうございました。 夕食を食べ終わった後も研修室に戻り開発です。 2日目に余力を残すため、22時上がりの参加者もチラホラ… ちなみに、宿泊室は個室でシングルベッド、机と椅子、洗面台、クローゼットがありました。 2日目 2024/2/6(火) 2日目は朝から丸一日の開発です! 朝食から1時間程度自由時間があり、海岸へ散歩しに行く方もいました。 昨日に引き続き、14:00から配信を行い、各チームの進捗報告を行いました。 段々と形になってきていますね。 開発も終盤戦ということもあり、この日は全員24時近くまで作業していました。 3日目 2024/2/7(水) 3日目は午前中が作業時間で午後は成果報告会になっており、発表準備やデザインなどの微調整がメインです。 成果報告会では作ったサービスとデモ、工夫点、開発での良かった点と悪かった点、成長したことや学んだことを発表します。 持ち運び式のプロジェクターとスクリーンが用意されており、スライドを投影しながらでの発表となります。 まずは、チーム「チームD」の飲酒量を管理するサービスです。 次は、チーム「欲望の沼」のスポーツの勝敗を賭けるサービスです。 そして、チーム「†Skyscraper†」のオリンピックビンゴです。 最後は、チーム「とり」の社内ブカツのまとめサイトです。 トリだけに最後です。 成果報告会も社内配信を行い、たくさんの方に見ていただきました。 おわりに 今年は4年ぶりのリアルでのハッカソン合宿となり、合宿史上初の試みとなるオンライン配信も実施しました。 触ったことがない技術を導入してみたり、 社内の ChatGPT の Slack BOT や GitHub Copilot などの AI を活用したり、AWS環境にデプロイして実際に触れるようにしたり、皆さんチャレンジや工夫をされていました。 最後に、開発環境を提供してくださったノジマ大磯スクウェアさん、ありがとうございました! 後ほど、各チームの記事を公開していきますので、お楽しみに! ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 カジュアル面談も随時受付中! ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたします! キャリア登録 connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
はじめに こんにちは、最近はCDKを触る機会がやや多く、Terraformとどっちを使うのが良いのかやや悩み気味な宮本です。 今回の記事はAWS Amplifyのビルド通知についてです。 Amplifyのビルド通知 ※以下の内容は全て2024/02/26現在の情報を元にしています 簡単にサイトを立ち上げることのできる Amplify ですが、ビルドする際の通知が貧弱という問題があります。 デフォルトで用意されているのは Eメールによる通知 のみ Eメールで送ることのできる通知内容が物足りない Eメール通知もCDKやTerraformのようなIaCで管理する方法が公式で説明されていない 通知内容が物足りないという点ですが、実際に送られてくるのは以下のようなメールです。 Build notification from the AWS Amplify Console for app: https://<ブランチ名>.<app id>.amplifyapp.com/. Your build status is <ビルドステータス>. Go to https://console.aws.amazon.com/amplify/home?region=<リージョン>#<app id>/<ブランチ名>/<ビルド番号> to view details on your build. Amplifyのビルド結果メール通知の例 メールに含まれている内容はapp idとブランチのみで、ぱっと見でどの環境かまではわかりません。複数のAmplifyによるアプリケーションを管理している場合は、もはや何がなんだかわかりません。URLがついているのでアクセスすればわかりますが、同じアプリの別ブランチの差であれば瞬時に見抜くのは難しいです。他にも、ビルドに失敗した場合であればコンソールのエラー内容も欲しいかもしれません。 Amplifyのビルド通知をSlackに送る ※重ねて注意。以下の内容は公式ドキュメントになく、仕様が変更される可能性は十分にあるのでご注意ください。 先に結論 Amplifyのコンソールから設定できるEメールによるビルド通知はEventBridge+SNSで実装されている コンソールで通知を作成した場合は必要なリソースが自動で作成される EventBridgeを用意すれば、そのまま直でLambda経由でSlackに通知することができる IaCで通知リソースを管理することもできる アプリ名などAmplifyの作成するイベントに含まれないデータは、Lambda内で別途データを取得する必要がある Amplifyのビルド通知 デフォルトだとAmplifyのビルド通知はコンソールからのみ作成できます。その際にAmplify自体に通知機能があるわけではなく、別のAWSサービスを利用してビルド通知を実現しているようです。なので、Amplify自体のTerraformやCDKに通知周りの設定がないんですね。 ビルド通知を設定した際に自動で作成されるリソースは次のようなものです。 Amazon EventBridge ルール: amplify-<app_id>-<branch名>-branch-notification ブランチ指定しない場合: amplify-<app_id>-AMPLIBRANCHSENTINEL-branch-notification Amazon SNS トピック: amplify-<app_id>_<branch名> ブランチ指定しない場合: amplify-<app_id>_AMPLIBRANCHSENTINEL EventBridgeの ドキュメント にも記載はないのですが、どうもAmplifyのビルド時にEventBridgeで引っ掛けることのできるイベントが配信されているようです。作成されるEventBridgeのルールを見ると、以下のようなイベントパターンを指定しています。ブランチを指定しない場合は、detailのbranchNameの項目自体がありません。 { "detail": { "appId": ["<app_id>"], "branchName": ["<ブランチ名>"], "jobStatus": ["SUCCEED", "FAILED", "STARTED"] }, "detail-type": ["Amplify Deployment Status Change"], "source": ["aws.amplify"] } この条件で引っ掛けたイベントを元に入力トランスフォーマーを使ってメール文面を作成し、SNS経由で送っています。 なお、引っ掛けているイベントの全体像は以下のようになっています。残念ながら、Amplifyのアプリ名までは入っていません。そのため、アプリ名を入れたい場合はLambdaを挟んでそこで別途データを取得する必要があります。 { "version": "0", "id": "<イベントid>", "detail-type": "Amplify Deployment Status Change", "source": "aws.amplify", "account": "<AWSアカウントid>", "time": "2024-01-01T00:00:00Z", "region": "ap-northeast-1", "resources": [ "<Amplifyのarn>" ], "detail": { "appId": "<app id>", "branchName": "<ブランチ名>", "jobId": "<ビルド id>", "jobStatus": "<ステータス>" } } Amplifyのビルド通知をSlackに送るために必要なリソースのCDK さて、Amplifyのビルド通知の仕組みがEventBridgeが元になっていると分かればこっちのものです。以下はCDKの場合ですが、このようなEventBridgeのリソースを作成することでイベントをLambdaに送ることができます。ビルド開始時の通知が不要な場合はパスパターンから STARTED を省くなど、工夫のしがいがあります。(なおlambdaのコード周り含めたリソース定義をここで書くと長くなるので省略します。) from aws_cdk import ( aws_iam as iam, aws_lambda as _lambda, aws_events as events, aws_events_targets as targets, Stack, ) from constructs import Construct class BuildNotificationStack(Stack): """指定したLambdaにAmplifyのビルド通知を送るEventBridge""" def __init__(self, scope: Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) app_id_list = ["hogehoge"] # 通知したいAmplifyのidリスト notification_brunch_list = ["master"] # ビルド通知したいブランチのリスト function = _lambda.Function(self, "NotificationLambda", ...) # 通知用のLambdaを作成(細かいコードは省略) # 以下の権限はLambdaから追加でAmplifyのデータを取得する場合に必要 function.add_to_role_policy( iam.PolicyStatement( actions=[ "amplify:GetApp", ], resources=["*"], ) ) # EventBridgeからLambdaを起動するために必要な権限 function.add_permission( "Eventbridge", principal=iam.ServicePrincipal("events.amazonaws.com") ) # appIdに複数のidを指定することで、一つのEventBridgeで複数のAmplifyのビルド通知を受け取ることも可能 notification_rule = events.Rule( self, "NotificationEventRule", event_pattern={ "detail": { "appId": app_id_list, "branchName": notification_brunch_list, "jobStatus": ["SUCCEED", "FAILED", "STARTED"] }, "detail_type": ["Amplify Deployment Status Change"], "source": ["aws.amplify"] }, ) build_notification_target = targets.LambdaFunction(function) notification_rule.add_target(build_notification_target) Slackに通知を送るLambda EventBridgeから叩かれた際、Lambdaはハンドラーの第一引数に入るeventとしてAmplifyから発行されたイベントがそのまま辞書形式で入ってきます。前述の通りAmplifyのアプリ名まではイベントに入っていないため、必要な場合はLambdaでアプリの情報を取得しなければいけません。 以下は、SlackのWebhook経由でビルド通知を送るLambdaの一例です。この例のメッセージ周りはだいぶ簡素なので、ビルドステータスによって必要な情報を増やしたり(e.g. 失敗した時のみコンソールへのURLを追加する)、通知文自体も見やすいようにカスタマイズしていくとわかりやすくなると思います。 import os import json import boto3 import requests from aws_lambda_powertools import Logger logger = Logger() # Lambdaの環境変数SLACK_WEBHOOK_URLにあらかじめSlackのWebhookを登録しておく SLACK_WEBHOOK = os.environ["SLACK_WEBHOOK_URL"] status_message = { "STARTED": "ビルドを開始します", "SUCCEED": "ビルドに成功しました", "FAILED": "ビルドに失敗しました", } @logger.inject_lambda_context def lambda_handler(event, context): try: logger.info("AmplifyのApp名取得") amplify_client = boto3.client("amplify", region_name="ap-northeast-1") # eventに入っていないAmplifyのアプリ名をboto3を使って取得する # lambdaのroleに「amplify:GetApp」の権限が必要 response = amplify_client.get_app(appId=event["detail"]["appId"]) app_name = response["app"]["name"] logger.info("Slack通知") data = json.dumps({"text": f"{app_name}の{event['detail']['branchName']}の{status_message[event['detail']['jobStatus']]}"}) response = requests.post( SLACK_WEBHOOK, data, headers={"Content-Type": "application/json"}, timeout=3 ) return None except Exception as e: logger.exception(e) return None 通知のサンプル おわりに 今回はAmplifyのビルド通知をSlackに流す方法について紹介しました。いくつか似たような方法を紹介していた記事はあったのですが、基本的にAWSのリソースは全てIaC管理しておきたい病にかかっているので、CDKで管理できるようにしました。リソース的にはEventBridgeとLambdaおよびそれに必要なIAM Roleを用意しているだけなので、Terraformでも問題ありません。 また、今回はLambdaを使いましたが、もともと出力されるイベントに含まれる内容自体で十分であれば、 EventBridgeから直にchatbotに送る こともできるようです。Lambdaを挟むとどうしてもランタイムのEOLによる継続的なメンテが必要になったりするので、不要であれば省きたいです。しかし、利用できるデータがどうしても限られてしまう点は現時点では解消できないため、細かくカスタマイズするのであればLambdaはまだ必要そうです。 他にも失敗したい場合はエラーログなども出せるとありがたいのですが、そもそもAmplifyのビルド時のログはCloudWatchにすら吐き出されないため現状打つ手が無さそうです。 参考 AWS Amplify(アプリケーションの構築とデプロイ)| AWS AWS Amplifyホスティングへようこそ – AWS Amplify ホスティング Amazon EventBridge とは – Amazon EventBridge Amplify Hostingのビルド結果をAWS ChatbotでSlackに通知 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 カジュアル面談も随時受付中! ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたします! キャリア登録 connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
はじめに こんにちは。宮永です。 半年ほど前に電気通信主任技術者を取得した のですが、これを持っていると工事担任者の受験で科目免除が使えます。特に使う予定はないのですが覚える知識が似ているので、勢いで取得してみました。今回はその体験談です。 工事担任者とは アナログ伝送路設備又はデジタル伝送路設備に端末設備等を接続するための工事や監督に必要な免許です。平たく言えば、 電話線や光ファイバー周りの工事をするのに必要な免許 です。 第一級・第二級アナログ通信、第一級・第二級デジタル通信、総合通信の5つに免許が分かれており、総合通信はすべての範囲の工事が可能です。今回は総合通信を取得しました。 試験科目と免除科目 試験科目は 電気通信技術の基礎(基礎) 端末設備の接続のための技術及び理論(技術) 端末設備の接続に関する法規(法規) の3科目です。各科目60点以上で合格です。 電気通信主任技術者を持っていると3科目のうち基礎と法規が免除になります 勉強方法 基本的には過去問周回です。試験では過去問と同じor非常に似た問題が多く出題されるので、「見たことがある問題を可能な限り多く作り、絶対に落とさない」という戦法で挑みました。6割合格なので、数問出る初見問題は落としても合格できます。 電気通信主任技術者試験と出題方法がほぼ同じ(同じ団体が試験を主催)なので、電気通信主任技術者を持っている人であれば勉強法で苦戦することは無いかなと思います。 また、技術の試験範囲は電気通信主任技術者の出題範囲と一部被っているため、すべてを1から学習する必要が無いです。 総勉強時間は約14時間でした。土日+αの勉強時間で挑みました。 試験 試験申し込みの段階で科目免除の申請をする際は、申し込み時に手元に電気通信主任技術者証を用意する必要があります。 電気通信主任技術者試験に合格して最初の工事担任者試験に申し込もうとすると、申請にかかる時間と試験日程の関係上、 手元に電気通信主任技術者証がまだ届きません 。本来であれば資格者証が届くのを待ってから申請するべきなのでしょうが、記憶がフレッシュなうちに受験したかったので、今回は 免除申請を出さずに工事担任者試験を受験する(3科目受験) 技術のみ合格する(基礎と法規はノー勉なので不合格) 技術の科目合格と電気通信主任技術者の科目免除を併用して 全科目免除申請 をする 全科目免除申請はほぼ確定で合格するので、晴れて資格者証を手に入れる という手順で資格者証を手に入れました。全科目免除申請を追加でする分お金は余分にかかりますが、スピード重視です。 試験申し込み まずは免除申請を出さずに普通に工事担任者試験を申し込みます。主催団体が同じなので、工事担任者試験の申し込みも電気通信主任技術者試験とほぼ同じです。 試験料は科目免除・全科目受験問わず8700円です。 受験 日曜日の朝に頑張って起きます。年に2回しかない試験なので、寝坊すると次のチャンスは半年後になってしまいます。 試験会場では試験種別ごとに建物が分かれており、総合通信の受験者は150人ほどだったと思います。ほとんどが40~50代の男性に見えました。おそらく自分が会場内で一番若かったです。試験会場の雰囲気、試験の進み方は電気通信主任技術者試験とほぼ同じでした。 11月の寒い雨の日に試験でしたが、会場は暖房ガンガンでものすごく暑かったです。隣の人は半袖Tシャツになってました。調整しやすい服装で行くべきだったと後悔しています。 試験時間は3科目分で160分ですが、私は1科目だけ合格すればよかったので時間はものすごく余りました。指示に従って途中退出可能です。 合否発表(1回目) 試験からしばらくたつとwebで結果を見る事ができます。 結果は技術のみ合格で基礎・法規は不合格、つまり試験は不合格です。が、私の目的は技術科目の合格が欲しかったので実質合格です。不合格通知ですが喜びます。 全科目免除申請 技術科目の合格と電気通信主任技術者の科目免除を組み合わせて、全科目免除申請を行います。全科目免除申請は通常の試験とは異なり、通年で受け付けています。申請方法は通常の工事担任者試験や電気通信主任技術者とほぼ同じですので、困るところはありません。 申請手数料は5600円です。 合否発表(2回目) 全科目免除申請も一応試験という扱いのようで、1か月ほどで合否通知が届きます。虚偽申告をしなければ合格になるはずです。 これでついに工事担任者試験に合格したことになります! 資格者証申請 まだ安心できません。試験に合格した人は申請して「工事担任者資格者証」の交付を受けなければいけません。管轄の総合通信局へ申請書を提出します。 顔写真、収入印紙などを用意します。この資格者証は、電気通信主任技術者資格者証と同様に 有効期限がない ので、残念な写真は使わない方が良いです。一生残念な写真の資格者証と共に過ごすことになります。 申請から約1か月で資格者証が届きました。これで堂々と有資格者と名乗ることができます。 まとめ 工事担任者の試験内容は電気通信主任技術者試験と被っている部分が多いので、記憶が残っているうちに取得して正解でした。同じような方法で取得する方はかなり少数派だと思いますが、参考になれば幸いです。 リンク 電気通信国家試験センターHP  https://www.dekyo.or.jp/shiken/charge/ ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 カジュアル面談も随時受付中! ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたします! キャリア登録 connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
皆さん、お疲れ様です。ニフティ基幹システムグループの山田(山田一族)です。 突然ですが、皆さんも昔は英語を話せるようになりたいと思っていませんでしたか?私も昔はそう思っていた時期がありました。 英語を話せるようになりたいと思って、かれこれ8年ぐらいは通勤時の電車内で BBC放送 のpodcastを聞いています。ですが一向に英語を話せるようにはなりません。やはり聞くだけではだめで、能動的に英語フレーズを作り出す「会話」という動作をしていかないとダメなのでしょう。 では、その会話をしたいのですが、典型的な日本人ですから英語を話すのが恥ずかしいです。英会話スクールは費用も掛かるし、相手に何を思われてるか分かったものではありません(被害妄想)。そういえば最近AIの英会話アプリがあったような・・・でも音声を録音されてたらどうしよう(完全な被害妄想) じゃあ自分で作ればいいじゃないか!技術力もアップするし一石二鳥だ! この辺りの複雑な事情を踏まえて今回は、gradioとLLMを用いて英会話のアプリを作ってみたいともいます。結論から言うと。。。まだカイゼンの余地ありです。でもそこはニフティの素晴らしい社員の皆さんの協力しあう力でカイゼンしていきたいとおもいます。 今回使う機能などは以下の通りです。 Google Colaboratory (誰が実行しても同じになるよう環境を共通化します) gradio (数行のコードできれいなUIを作成してくれます) TinyLlama (今回の私の話相手です。Metaの Llama2 の小規模言語モデルといったところでしょうか。GPUメモリがかつかつなのでこちらを使います。) whisper (音声からテキストに起こしてくれます。安心と信頼の?openai製です) Google Coraboratoryの使い方についてちょっと勉強が必要ですが、エンジニアの方も、エンジニアでない方も実践できるようにしたつもりです。是非皆さんチャレンジしてみてください。では早速実装していきましょう! 1.まずは必要なパッケージを入れていきます。 !pip install -qqq accelerate gradio import gradio as gr import numpy as np ※記事作成時点ではlidaやllmx関連のエラーが表示されますが使えますので構わず進んでください 2.次に話相手をしてくれるTinyLlamaと、文字を起こしてくれるwhisperをインストールします。 GoogleCoraboratoryのフォームを使いmodelを選択できるようにするとオシャレですが今回はスキップします。 import torch from transformers import pipeline pipe = pipeline( "text-generation", model="TinyLlama/TinyLlama-1.1B-Chat-v0.6", torch_dtype=torch.bfloat16, device_map="auto", ) transcriber = pipeline( "automatic-speech-recognition", model="openai/whisper-base.en", device_map="auto" ) 3.ここで、AIさんの返信だけを抜き出すfunctionを用意します。 ROLE_SYSTEM = "<|system|>" # 今回は使わない ROLE_USER = "<|user|>" # 今回は使わない ROLE_ASSISTANT = "<|assistant|>" def extract_role_phrase(text): text_array = text.split("\n") start = 0 for i, x in enumerate(reversed(text_array)): if ROLE_ASSISTANT in x: start = i break return "\n".join(text_array[-1 * start :]) このAIとチャットすると以下のようなテキストを返してきます。このテキストから最後の<|assistant|>以降を抜き出したいだけです。もっといいやり方があるのかもしれませんがあきらめました(考えるのをやめた)。誰か教えてください! <|system|> You are a friendly chatbot who always responds in the style of a pirate <|user|> How many helicopters can a human eat in one sitting? <|assistant|> I am not capable of human interaction or information. However, based on the passage, it is stated that humans can eat up to 1,000 helicopters in one sitting. 4.AIの役割を決めましょう。私は英語の練習をしてみたかったので以下のように設定しました。contentのところをそれぞれ変更してみてください。 messages = [{"role": "system", "content": "you are my english teacher in japan"}] 5.最後に、おしゃれなUIを設定していきましょう。ここが今回のメインのコードになります。 このコードだけできれいなUIが表示されてくれますので、時代は変わったなあと・・・ with gr.Blocks() as demo: def transcribe(audio, chat_history): sr, y = audio y = y.astype(np.float32) y /= np.max(np.abs(y)) text = transcriber({"sampling_rate": sr, "raw": y})["text"] messages.append({"role": "user", "content": text}) chat_history.append([text, None]) return chat_history def generate(): prompt = pipe.tokenizer.apply_chat_template( messages, tokenize=False, add_generation_prompt=True ) outputs = pipe( prompt, max_new_tokens=256, do_sample=True, temperature=0.7, top_k=50, top_p=0.95, )[0]["generated_text"] result = extract_role_phrase(outputs) return result def post(chat_history): text = generate() messages.append({"role": "assistant", "content": text}) chat_history.append([None, text]) return None, chat_history chatbot = gr.Chatbot() audio = gr.Audio(sources=["microphone"]) audio.stop_recording(transcribe, [audio, chatbot], [chatbot]).then( post, [chatbot], [audio, chatbot] ) demo.launch(height=800) 使い方を軽く説明をすると、stopボタン(あとで出てきます)を押すと、transcribeファンクションにて、音声から文字を起こしてchatのボードに文字をセットします。その後(まさにthen)、postファンクションにて、AIさんにその言葉を投げかけて回答を再びchatのボードにセットさせます。 このコードを張り付けて実行することで、以下のような画像が表示されます。 ブラウザの設定によってはこの時、マイクの使用の許可を求めてきます。必要に応じて許可するようお願いします。 マイクの許可をしましたら、左下にあるRecordボタンを押してみてください。いきなり録音が始まります。(ボタンが以下のようにRecordからStopに変わります。) 何か一言しゃべってStopボタンを押してみてください。自動的に音声のテキスト化とAIとの会話が始まります。 では試していきましょう ランタイムのタイプをGPUにしたうえで、「すべてのセルを実行」を実施してください。 まっさらなchatbotのボードとrecordボタンが表示されますので、recordボタンを押して、お話を始めてください。終わったらstopボタンを押し、文字が起こされて、相手から返事が来たらまたrecordボタンを押して会話する。これの繰り返しになります。 今回は以下のように会話をしました。 「私はタローです。何か英語の質問をください」(本名はタローではありませんよ) 「日本の7月は何度なの?」 「70℃ぐらいかな、これって暑い?」(本当は17℃といったのですが・・・でも摂氏じゃなく華氏になった。日本の7月は17℃じゃない) 「うん。暑いね」 「Dooda japa」(日本は好きですか?って言ったつもりです。何話せばいいのかわからなり・・・) 「はい、そうです。 7 月の日本は高温多湿で知られ、気温は華氏 80 度、湿度は 100% に達します。」 最後は会話が崩壊してしまいましたが、慣れれば何とかなるのではないかという希望を持ちました。 最後に いかがでしょうか。 私の発音も含めてまだまだ完全体ではありませんが、これで相手を気にせずに英会話の練習ができます! うすうす感づいているかと思いますが、英会話に限定する必要はありません。messages 部分を書き換えることによっていろいろな応用を効かせることができます(本当に効いてたのか不安はありますが)。みなさんもぜひお試しください! 今回のコードでは、 stopボタンを押さないと会話ができない→無音が一定時間続いたら自動的に会話できるようにしたい chatの回答が文字のまま→しゃべらせたい などなどカイゼンの余地が多くあります。 そのあたりは次回以降やっていきたいと思います。 それでは皆さん、英語を話せるように頑張りましょう。自動翻訳機で済む時代が来るのかな? ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 カジュアル面談も随時受付中! ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたします! キャリア登録 connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
はじめましてニフティ株式会社インフラシステムグループインフラチームの松居と申します。以前、 福田から紹介をしていたインフラチーム 内でご紹介していた ②ネットワークを担当するチーム について今回はご紹介させていただきます。 私はニフティには中途で入社し、それ以来ネットワーク一筋、16年ほど携わっております。ネットワークと一口に言うとかなり広い範囲となりますが、私たちが担当している範囲はお客様向けではなく、下記のような主に社員やシステム間での通信を行う箇所となります。 担当範囲 ①拠点間 事務所(新宿本社) データセンタ クラウドへのプライベート接続 ②拠点内 いわゆるLANと呼ばれる範囲となり、主に社員が日常的に業務で利用する無線LAN等が対象となります。 ③データセンタ内 クラウドとの接続やオンプレミス環境の基盤となるネットワークを対象にしております。 業務内容 上記担当範囲においてメンバー全員で下記の業務を執り行っております。 新規案件や機器寿命による入替に伴う設計・構築 運用・保守 セキュリティのため通信制御している箇所のフィルタ開放 VPNにまつわる設定  機器故障等による障害対応、等々 日々の運用を効率化するための自動化 その他、ネットワークが関係しそうなトラブルや相談受付 業務で扱う機器やツール ネットワーク機器 Cisco Juniper BIG-IP FortiGate ツール(SaaS含む) NetBox(機器やIPアドレス等の論理情報も合わせて管理) Ansible Zabbix Grafana GitHub Slackワークフロー AWS Lambda 上記のように列挙いたしましたが、ネットワークに関わる範囲はなんでも担当するというチームになっております。スキル蓄積のため内製で対応を行うことを基本としております。運用・保守においては依頼件数が多く繰り返し発生する業務についてはAnsible等を利用して積極的に自動化による効率化を図っております。 現在は物理機器に頼る部分も多くなっておりますが、今後の事を見据えてコンポーネント単位での仮想化の導入や機器のクラウド管理を目指しております。   ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 カジュアル面談も随時受付中! ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたします! キャリア登録 connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
SREチームの島です。最近Terraformを書いてるのですがまだまだ理解不足なところもあり日々試行錯誤しています。 今日は開発環境をTerraformで作成した話をします。 背景 複数人でGCP上で動くアプリを開発したい 各自がローカルで変更したソースを動作確認できる環境を作りたい やりたいこと 各自がローカルで変更したソースを動かせる環境をGCP上に作りたい 全部ローカルに作れたら良かったが作るのが大変なので手っ取り早く動く環境を作りたかった 各自が自由に自分用の環境を作成、削除できるようにしたい。また環境の作成、削除をしても他の環境には影響を与えないようにしたい。 前提 ブランチ戦略 developブランチを親ブランチとしてそこから派生して子ブランチ(feature/X)を作成し、featureブランチで個人開発するようなイメージです。 以下、developブランチが動く環境をdevelop環境、featureブランチが動く環境をfeature環境、まとめて開発環境と呼びます。 クラウド構成概略 niftyというGCPプロジェクトの中にdevelop環境とfeature環境(N個)を作ります。feature環境は自由に作成、削除することを想定していますので数は増減します。 詳細は省きますがPub/SubでBigQueryに溜め込んだデータをCloudRunでグラフ化するようなアプリ「serviceA(仮名)」を想定しています。 各環境用のリソースの他に全環境共用のワークロードID、develop環境用、feature環境用のサービスアカウントの作成が必要です。これらは環境ごとに増減するものではないので一度作成すればいいものになります。 ポイント 「環境ごとに作るもの」はリソース名被りがないように作る必要がある 「共通設定」はTerraformでどのように定義すればいいのか 作ったもの Terraformのディレクトリ構造は以下のようにしました。 . ├── serviceA │ ├── envs │ │ ├── develop │   │ │ ├── main.tf │   │ │ └── variables.tf │ │ └── feature │   │ ├── main.tf │   │ └── variables.tf │      └── modules                // 環境ごとに作るリソース │      ├── bigquery.tf │      ├── dashboard.tf │   ├── iam.tf │      ├── locals.tf │      ├── outputs.tf │      ├── parsers.tf │      ├── provider.tf │      ├── services.tf │      └── variables.tf └── project-common // 共通設定 ├── projects/nifty │ ├── main.tf │ ├── output.tf │ └── variables.tf └── modules     ├── oidc-github-pool-provider // ワークロードID     │   ├── main.tf     │   ├── output.tf     │   ├── provider.tf     │   └── variables.tf     └── oidc-github-sa  // develop、feature環境のサービスアカウント    ├── main.tf    ├── output.tf    ├── provider.tf    └── variables.tf 解説 環境ごとに作るリソースの定義 develop環境はserviceA/envs/develop、feature環境はserviceA/envs/feature配下でterraform applyすると、serviceA/modulesで定義した「環境ごとに作るリソース」を作成します。 このとき、変数でブランチ名をモジュールに渡して、各リソース名にブランチ名を付けることでリソース名が被らないようにしました。 serviceA/envs/feature/main.tf module "serviceA" { source = "../../modules/serviceA" project_id = var.project_id (中略) branch_name = var.branch_name // ブランチ名を変数で渡す } serviceA/modules/dashboard.tf resource "google_cloud_run_service" "dashboard" { name = "dashboard-${var.branch_name}" // リソース名にブランチ名をつける location = var.region project = var.project_id (略) ステートファイルの管理 ステートファイルの管理についてはGCSで管理する設定にしました。 develop環境のステートファイルは下記のようにprefixを固定で設定しました。 serviceA/envs/develop/main.tf terraform { backend "gcs" { bucket = "tf-state-project-nifty" prefix = "service-a-develop" // prefixを固定で設定 } } feature環境については環境ごとにステート管理する必要があるので、固定で設定せずterraform initをする際に terraform init - backend - config = "prefix=service-a-${TF_VAR_branch_name}" といった感じでブランチ名を付けた値をprefixに設定するようにしました。 serviceA/envs/feature/main.tf terraform { backend "gcs" { bucket = "tf-state-project-nifty" // prefixはここには設定しない } } これで環境ごとにステートファイル管理ができます。 共通設定の定義 次に、共通設定は/project-common配下に定義しました。 project-common/projects/nifty/main.tf // develop環境用のサービスアカウント module "oidc-sa-develop" { source = "../../modules/oidc-github-sa" project_id = var.project_id env_name = "develop" } // feature環境用のサービスアカウント module "oidc-sa-feature" { source = "../../modules/oidc-github-sa" project_id = var.project_id env_name = "feature" } // ワークロードID module "oidc-github-pool-provider" { source = "../../modules/oidc-github-pool-provider" project_id = var.project_id } /modules/oidc-github-saをenv_nameの値を変えて2回実行しています。ここで「develop環境用のサービスアカウント」と「feature環境用のサービスアカウント」が作られます。 /modules/oidc-github-pool-providerは「ワークロードID」を定義しています。 さきほどの図に当てはめると以下のようなイメージです。 まとめると develop環境構築時(一度だけ実行):「serviceA/envs/develop」、「/project-common/projects/nifty」配下でterraform applyしてdevelop環境と共通設定を作成 feature環境構築時(環境数分実行):「serviceA/envs/feature」配下でterraform applyしてfeature環境を作る。共通設定は上記で作成済みなのでfeature環境を増やそうが消そうが影響を受けない といった状態を作ることができました。 これがベストな状態かは定かではないですが、ひとまず開発環境の動作確認ができる状態を作ることができました。 共通設定と環境ごとのモジュールの定義の分け方など実際に実装してみて良い学びになりました。 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 カジュアル面談も随時受付中! ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたします! キャリア登録 connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
挨拶 はじめまして、新卒3年目サービスインフラチームのムサシです。 ツールのアクセス成功率を可視化したいなあ 先日私のチームでは、とあるツールのアクセス成功率をCloudWatchのダッシュボードに可視化しました。やったことは以下になります。 ① CloudWatchに流れているログを利用してメトリクスフィルターを作成する ② メトリクスを利用して、ログの発生回数から成功率のグラフを作成する ③ 一定の値を下回った場合にアラートを設定し、Slackに通知 ④ ダッシュボードに成功率のグラフとアラートの状態を表示する すべて説明すると長くなってしまうので、今回は①、②について手順、詰まったことなどを備忘録的に書いていこうと思います。これを書いているのは2024年1月末の情報なので画像・内容が古いこともありますがご了承ください。 ①CloudWatchに流れているログを利用してメトリクスフィルターを作成する フィルターパターンを作ろう まずはログをカウントするためにメトリクスを作ります。CloudWatchからロググループを選択しメトリクスフィルター内の「メトリクスフィルターを作成」から作ることができます。 パターンを定義という画面が出てくるので、抽出したいログに含まれる文字列をフィルターパターンに設定します。フィルターパターンは若干癖があるのですが、 一部の正規表現が使える ので複数のアラートをまとめて抽出したい場合に便利です。 ただし正規表現を利用したメトリクスは1つのロググループにつき5個までの制限があるので注意。 ## こんなエラーが出てつまづいた メトリクスフィルター「ほげほげ」を作成できませんでした。 Resource limit exceeded. 注記 クォータ メトリックスフィルターまたはサブスクリプションフィルターを作成するとき、ロググループごとに regex を含むフィルターパターンが最大 5 つあります。 メトリックスフィルターとサブスクリプションフィルターの区切りまたは JSON フィルターパターンを作成するとき、またはログイベントまたはライブテールをフィルタリングするとき、フィルターパターンごとに 2 つの regex の制限があります。 https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html もしログを新しく出す場合は以下の記事のように抽出しやすい形で出すと正規表現の枠を使い切らずに済みそうです。 Amazon CloudWatch Logs に出力するログは JSON 形式だと分析が楽になるかもしれない話 パターンをテストでは、どのログが引っかかるかを確認することができます。直近のログがテストデータの候補として表示されますが、「カスタムログデータ」を選択することでテストデータを自由に変える事ができます。あまり発生しないログ(処理に失敗したときのログなど)の場合はこちらを利用してフィルターパターンが正しいか確認できて便利です。 良い感じのフィルターパターンができたら次へ 次はメトリクスの設定を行います。オプションと書かれているデフォルト値とUnit以外が必須項目となります。埋めていきましょう。 まずは名前を入力します。フィルター名は後から変えられないので気をつけましょう。いくつか作ることを見越して命名ルールを決めておいた方が良いです。(1敗) メトリクス名前空間はフォルダみたいな感じでしょうか。既にメトリクス名前空間を作っている場合は、新規作成をオフにすると既存のメトリクス名前空間から選ぶ事ができます。今回はメトリクス名前空間を新規作成し、そこに作ったメトリクスを入れていきました。 メトリクスを参照するときには、このとき作ったカスタム名前空間の中に入ることになるので、その辺りも考えつつ名前を付けましょう。画像はメトリクス名前空間の意味がよくわからずに名付けしてしまった名前空間です。わかりやすい名前を付けましょう。 メトリクス名にもわかりやすい名前を付けてあげましょう。こちらはフィルター名と違い後から変更できそうでした。 メトリクス値には1を、デフォルト値には0を設定します。こうすることで、ログをカウントすることができます。 全て埋められたら次へ。確認画面に進むので、問題なければメトリクスフィルターを作成ボタンで作成完了です。 作成したフィルターはロググループの「メトリクスフィルター」で、ロググループごとに見る事ができます。後から編集したい場合もここからできます。 ②メトリクスを利用して、ログの発生回数から成功率のグラフを作成する 成功率を計算するための準備 成功率を出したい時、 ( ( 全体数 - 失敗数 ) / 全体数 ) * 100 で計算できます。初めは成功パターンをカウントしようとしていたのですが、成功とするログのパターンが多かったため、数が少なく絞り込みやすい失敗パターンをカウントする方向で進めていくことにしました。全体数をカウントするメトリクスと失敗パターンをカウントするメトリクスの2つが必要なので、これらを①で説明した手順で作成していきます。 ステータスコードやURLをフィルターパターンとして設定し、「アクセス失敗ログをカウントするメトリクス( m2 とする)」「ツールのアクセス全体のログをカウントするメトリクス( m1 とする)」を作成しました。 グラフを作ろう メトリクスができたら、グラフを作っていきましょう。CloudWatchのすべてのメトリクスを選択し、参照タブで先ほど作ったm2とm1を探してチェックを入れます。すると上にグラフとして表示させることができます。表示した各グラフはグラフ化したメトリクスタブで設定が変更でき、統計を「合計」にすることでログの発生回数をカウントすることができます。 全体数(m1)、失敗数(m2)が揃ったので、あとはこれを用いて計算したものをグラフとして出せばOKです。成功率を出すための式を作るため「数式を追加」ボタンを押します。関数などいろいろ選べますが、今回はシンプルな四則演算を設定したいため「空の式で始まる」を選択することにします。 グラフ化したメトリクスの欄に式 e1 が作成されました。 詳細の欄には数式が設定できます。この数式には既に参照したメトリクスを設定可能です。成功率の数式にメトリクスm2、m1を当てはめると、 ( ( 全体数 - 失敗数 ) / 全体数 ) * 100 = ( ( m1 - m2 ) / m1 ) * 100 となります。e1に ( ( m1 - m2 ) / m1 ) * 100 を数式として設定しましょう。成功率がグラフとして表示されれば完成です。 もし全くアクセスがない場合は 全体数が0になることで上手く計算されず、グラフが表示されないかもしれません。そのときはIF式を使うことで計算エラーを回避できます。IF式は IF ( n , n ≠ 0 のときの値 , n = 0 のときの値 ) のように使えるみたいです。今回は、アクセスが無い場合は問題なしとして成功率100%になって欲しいので IF ( m1 , e1 , 100 ) という式 e2 を新たに追加しました。e1のチェックを外して非表示にし、e2のみをグラフとして表示することで欲しいグラフを見ることができました。 終わりに 説明は割愛しましたが、この後アラート設定やダッシュボード作成をすることで、監視の手間や問題の把握までの時間を小さくする事ができます。アラートはSlackへ飛ばしているのですが、この後どうするかの相談や、なぜアラートが上がったのかというような情報共有もそのままSlack上で行えるため非常に便利です。 ぜひ試してみてください。 ~special thanks~ 手間取ってたらチームのタスクとしてやってくれたチームメンバーに感謝 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 カジュアル面談も随時受付中! ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたします! キャリア登録 connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
こんにちは、IaCお姉さんです。 CloudFormationにIaC ジェネレーターという新しい機能が出たので使っていきます。 IaC ジェネレーターについては、以下の公式ページをご覧ください。 https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/generate-IaC-write-only-properties.html 今回はLmabda関数をIaC化します。 コンソールからLambda関数を作成 言語はPythonを選んで、デフォルトのソースコードのまま作成しました。 CloudFormation IaCジェネレーターでテンプレートを作成 コンソールのIaCジェネレーターから「テンプレート作成」をクリックし、今回作ったLambda関数を選択し、テンプレートを作成します。 できたテンプレートがこちらです。 --- Metadata: TemplateId: "arn:aws:cloudformation:ap-northeast-1:999999999999:generatedTemplate/hoge" Parameters: LambdaFunction00iacgentest00hDmeyCodeS3BucketOneOftEfZZ: NoEcho: "true" Type: "String" Description: "An Amazon S3 bucket in the same AWS Region as your function. The\ \ bucket can be in a different AWS account.\nThis property can be replaced with\ \ other exclusive properties" LambdaFunction00iacgentest00hDmeyCodeS3KeyOneOfI1FJJ: NoEcho: "true" Type: "String" Description: "The Amazon S3 key of the deployment package.\nThis property can\ \ be replaced with other exclusive properties" Resources: LambdaFunction00iacgentest00hDmey: UpdateReplacePolicy: "Retain" Type: "AWS::Lambda::Function" DeletionPolicy: "Retain" Properties: MemorySize: 128 Description: "" TracingConfig: Mode: "PassThrough" Timeout: 3 RuntimeManagementConfig: UpdateRuntimeOn: "Auto" Handler: "lambda_function.lambda_handler" Code: S3Bucket: Ref: "LambdaFunction00iacgentest00hDmeyCodeS3BucketOneOftEfZZ" S3Key: Ref: "LambdaFunction00iacgentest00hDmeyCodeS3KeyOneOfI1FJJ" Role: "arn:aws:iam::999999999999:role/service-role/iac-gen-test-role-tzzzpewe" FileSystemConfigs: [] FunctionName: "iac-gen-test" Runtime: "python3.12" PackageType: "Zip" LoggingConfig: LogFormat: "Text" LogGroup: "/aws/lambda/iac-gen-test" EphemeralStorage: Size: 512 Architectures: - "x86_64" テンプレートを手直しする テンプレートを作成するとこのような画面になります。 黄色い枠の中にwarningが出ています。 The template contains properties that can be replaced with other mutually exclusive properties. Additionally, some optional properties were not included. You can download the template and edit it to modify the properties to suit your needs. 「このテンプレートはまだ未完成だから自分でなんとかしてね」と言っています。 「View warning details」をクリックしてみると、どうやら「Code/S3Bucket」と「Code/S3Key」は自分で値を用意しないといけないようです。 CloudFormationでLambda関数を作成する際、コードのアップロード方法として、以下の3種類があります。 S3からアップロード ECRのイメージとしてアップロード zipファイルをアップロード ですが、IaCジェネレーターから既存のLambda関数のテンプレートを作成する時に、コードがどうやってアップロードされたかは検知できず、「Code」部分にはS3からアップロードした場合のソースが作成されるようです。 (ECRイメージの関数もテンプレート化してみましたが、同様に「Code/S3Bucket」と「Code/S3Key」のパラメータでテンプレートが生成されました。) テンプレートを実際に使う時は、適宜アップロード方法を書き換えないといけません。 詳細はこちらのドキュメントを参照 https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/generate-IaC-write-only-properties.html 今回は、凝ったことはせずzipファイルでアップロードするようにテンプレートを書き換えます。 Lambda関数の画面からコードをコピーして、テンプレートの「Code」部分に貼り付けます。 Code: ZipFile: | import json def lambda_handler(event, context): # TODO implement return { 'statusCode': 200, 'body': json.dumps('Hello from Lambda!') } インポートする テンプレートが完成したら、インポートして、リソースをCloudFormationの管理下に置きます。 画面の「Import edited template」から、先ほど「Code」部分を編集したファイルをアップロードしてインポート完了です。 まとめ IaCジェネレーター、とっても便利なので皆さんも使ってみましょう^ヮ^ ただし、一部のリソースではテンプレート作成後に人力で修正を加えないといけないようです。 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 カジュアル面談も随時受付中! ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたします! キャリア登録 connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
Notionの管理者をしている石川です。 先日行われたNotion Japan チャンピオンズコミュニティアワード2023で「Notion導入推進賞」をいただきました! Notionチャンピオンズコミュニティとは Notionチャンピオンズコミュニティは、Enterprise利用している(なにかしらの有償プランに入っている)企業のチャンピオンが集まる公式コミュニティです。アンバサダーとは別のコミュニティとなってます。 参考: Notionチャンピオンズコミュニティ Notionアンバサダー Notion導入推進賞 トロフィーとお土産 受賞記念にいただいたクリスタルトロフィーは重量感あってとても綺麗 具体的な評価ポイントは教えてもらってないですが、モデルケースとなりやすい移行や導入時のノウハウを発信していったところが評価されたのかなと思ってます。 今後もこれに驕らず実運用の中でよいノウハウが出てきたらアウトプットしていきます! 参考リンク いままでNotion関係でアウトプットしたブログやスライドを以下にまとめました。 Notionのアップデートはとても多く一部古い情報になっている部分はありますが、導入や推進などのアクションは大きく変わるものでもないので、まだまだ参考になるかと思います。 2022-12-25 Notionで社内情報をスムーズに検索!移行前の大掃除と再配置で効率アップ – NIFTY engineering 2023-03-14 Notion全社導入に伴う移行とデータ整理のノウハウ | ドクセル 2023-04-27 NotionのWiki機能を使ったページ管理を考えてみる – NIFTY Tech Talk #10 – Speaker Deck 2023-11-08 Notionへのデータ移行体験談とTIPS | ドクセル 2023-11-18 Notionへのデータ移行を成功させる5つのポイント – NIFTY Tech Day 2023 – Speaker Deck ちなみに昨年アップデートがあったもの一覧は以下のURLから確認ができます。 アップデートがあるごとに、ちょくちょくフィードバック送っていたんですが、要望として挙げていたものが実現されると嬉しいですよね。昨年出た中だとユニークIDプロパティが一番嬉しかったです。 参考: 2023年 – Notionアップデート総まとめ90 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
NIFTY Tech Talkは、ニフティ株式会社の社員が主催するトークイベントです。 本イベントではニフティグループの社員が業務を通じて学んだことを発信しています! 概要 日程:01/30 (火曜日) 12:00~13:00 配信方法:YouTube Live 視聴環境:インターネット接続が可能なPC/スマートフォン 参加方法 connpass にて登録をお願いいたします。 ※YouTube Liveにて配信いたします。 ※YouTube LiveのURLは決定後、参加者への情報欄に記載いたします。 こんな方におすすめ スクラムマスターの経験がある方 1on1に興味がある方 タイムテーブル コンテンツ 12:00 – 12:10 オープニング+会社紹介 12:10 – 12:25 LT: スクラムマスターの自律について 12:25 – 12:40 LT: 社内で行なっている1on1トレーニングについて 12:40 – 12:55 QAなど 12:55 – 13:00 まとめ+クロージング テーマ スクラムマスターとしての学習や研鑽活動について 登壇者プロフィール 西野 香織(登壇者) ニフティ株式会社 会員システムグループ 第2開発チーム ニフティのスペシャリストを任命するN1!制度にて、スクラムエヴァンジェリストを担当しています。 2019年スクラムマスターとして、ニフティへのスクラム導入を開始。 8チーム、エンジニア約30名以上に対しスクラム導入を支援しています。 アドバンスド認定スクラムマスター(A-CSM)資格所持。 三浦 拓実(登壇者) ニフティ株式会社 会員システムグループ 第2開発チーム お客様向けセキュリティサービスのシステム開発担当で、2023年3月に認定スクラムマスターを取得しました。 ニフティグループでは一緒に働く仲間を募集中です 新卒採用、キャリア採用を実施しています。ぜひ リクルートサイト をご覧ください。 ニフティエンジニアが業務で学んだことやイベント情報を エンジニアブログ にて発信しています! ニフティエンジニアのTwitterアカウントを作りました NIFTY Tech Talkのことや、ニフティのエンジニアの活動を発信していきます。 Tweets by NIFTYDevelopers アンチハラスメントポリシー 私たちは下記のような事柄に関わらずすべての参加者にとって安全で歓迎されるような場を作ることに努めます。 社会的あるいは法的な性、性自認、性表現(外見の性)、性指向 年齢、障がい、容姿、体格 人種、民族、宗教(無宗教を含む) 技術の選択 そして下記のようなハラスメント行為をいかなる形であっても決して許容しません。 不適切な画像、動画、録音の再生(性的な画像など) 発表や他のイベントに対する妨害行為 これらに限らない性的嫌がらせ 登壇者、主催スタッフもこのポリシーの対象となります。 ハラスメント行為をやめるように指示された場合、直ちに従うことが求められます。ルールを守らない参加者は、主催者の判断により、退場処分や今後のイベントに聴講者、登壇者、スタッフとして関わることを禁止します。 もしハラスメントを受けていると感じたり、他の誰かがハラスメントされていることに気がついた場合、または他に何かお困りのことがあれば、すぐにご連絡ください。 ※本文章はKotlinFest Code of Conductとして公開された文章( https://github.com/KotlinFest/KotlinFest2018/blob/master/CODE-OF-CONDUCT.md )を元に派生しています。 ※本文章はCreative Commons Zero ライセンス( https://creativecommons.org/publicdomain/zero/1.0/ ) で公開されています。
AWSコスト削減が巷で話題になってますね。 こんにちは、ニフティのAWS組織管理をしている石川です。 とんでもない削減額を叩き出したわけではないですが、長年やりたかったSPs(Savings Plans)とRI(Reserved Instance)の一括購入を行いましたので、そのときに得たノウハウを共有していこうと思います。 .article__content ul > li > ul > li { list-style: circle; } .article__content ul > li > ul > li > ul > li { list-style: square; } .article__content ul > li > ul > li > ul > li > ul > li { list-style: disc; } .article__content table thead th:first-child { background: #005AD7; } Before/After Before After 購入したもの SPsカバレッジ 21% 95〜99% Compute Savings Plans 3年 前払いなし RI(RDS)カバレッジ 15% 83% RDS Reserved Instance 1年 前払いなし 表1: SPs/RIのカバレッジ ※表の値は購入直後のもので現在はリソースが増えてカバレッジはちょっと下がっています ※RIをRDSのみにしているのは他のRIは利用アカウント数が少数でしたので一括購入していません 管理アカウントで一括購入することの是非 個々のAWSアカウントで買うか、管理アカウントで一括で買って共有したほうがいいのか問題。 各プロダクトチームが個々のAWSアカウントで買う場合、リソースの調整がしやすいためリソースごとに最適なプランで購入することができ割引効率がよくなります。一方、AWSアカウント×リソース×購入タイミングごとに購入タスクが発生するため、買い忘れが発生したり、少額だから買わないという状況が起きたりします。 組織管理者が管理アカウントから一括で買う場合、共有前提なので常時起動分はカバーできるように買うことができます。一方、再利用性を考慮して買うため柔軟なプランを選ぶことになり割引率が下がります。また会計上、共有して利用したAWSアカウントの費用として計算する必要があり、一手間増えます。 それぞれメリット・デメリットがあります。AWSアカウントやリソースを統制管理しているのか各チームで管理しているのか、現状適切に購入できているのかを見て、自身の組織に合う方を選ぶと良いでしょう。 ニフティの場合、各プロダクトチームごとに管理していましたが、AWSアカウントも多いためかカバレッジも低く、適切に購入できている状態とも言えなかったため今回一括購入を採用しました。 SPs/RIの仕様確認 高額な買い物となるため、AWSのSPs/RIの共有や利用のされ方をちゃんと理解しておかないといけません。個人的にここはしっかり把握しておきたかったという点をいくつか紹介します。 ※2023年11月時点で公式ドキュメントやサポートに確認した内容となります 共有されたSPs/RIが使われる順番 ざっくりいうと SPsよりRIが先に使われ、適用範囲が狭い順 に使われていきます。 割引共有がない状態での適用順番 Own: Reserved Instances Own: Savings Plans (EC2 Instance) Own: Savings Plans (Compute) 割引共有がある状態での適用順番 Own: Reserved Instances Share: Reserved Instances Own: Savings Plans (EC2 Instance) Share: Savings Plans (EC2 Instance) Own: Savings Plans (Compute) Share: Savings Plans (Compute) SPs/RIが適用される単位 1時間単位に割引効率が一番いいリソースから順 に割り当てられていきます。 消費した順に適用されるわけではないです。 即時割引額が反映されるわけではなく請求レポート上への反映は翌日以降。 正規化係数の仕様 購入期間だけ異なる同じプランのRIを買い増ししたときに合算されて適用されるかどうか。 購入期間が異なっていてもRIは正規化係数で合算されて適用される。 購入期間が異なっていて問題になるのは、RIの変更時に結合できない点。 例: 購入したRI 2023-09-01: t2.medium 1つ購入 2023-09-08: t2.medium 1つ購入(期間以外は上記と同じ設定) 稼働中のインスタンス t2.large 適用状況 2023/09/01-2023/09/08: t2.largeにt2.mediumのRI1つ分の割引が適用 2023/09/08以降: 先に購入されたRIが失効するまで: t2.largeにt2.mediumのRI2つ分の割引が適用 先に購入されたRIが失効した以降: t2.largeにt2.mediumのRI1つ分の割引が適用 参考: リザーブドインスタンス がどのように適用されるか – Amazon Elastic Compute Cloud リザーブドインスタンス の変更 – Amazon Elastic Compute Cloud 購入額の見積もり 基本的に管理アカウントで確認できる推奨値を買えば問題ないです。 推奨値と同じ値をコストエクスプローラーで出せないか試してみたところ、期間内の最小か平均で推奨値を出してくれているように見えました。スパイクは無視してくれるし、一時的に立ち上がっているものも無視してくれています。 そのため直近での変化がないかだけ購入前に確認するだけでよいです。ただ古いインスタンスは購入推奨に含まれない場合があるので、古すぎるものがないかはチェックして可能なら最新のインスタンスタイプに上げておきましょう。 今回は推奨値から以下のものを抜き足しした額を購入しました。 除外 直近でSPs/RIを購入していたもの 近いうちにリソースを削除する予定のもの ライセンスありのリソース 個別購入して管理したいAWSアカウント or リソース 追加 近いうちに個別で購入していたSPs/RIが切れるもの 直近で立ち上げられた永続利用するリソース 購入作業 買うだけではあるんですが、何度も確認や再計算して購入したのですごく疲れる作業でした。 SPsの購入は、見積もり額通りに時間あたりの費用を入力して買うだけなので比較的楽です。 ただ 額が大きくて購入ボタンを押すのがすごく怖かったです。。 ここの心理的負荷を下げるなにかが欲しい。 購入した翌日の昼過ぎくらいにコストエクスプローラーへ反映されていました。CURにも反映されていました。 購入した翌日に確認したコストエクスプローラー(時間単位) RDSのRIの購入は、推奨値のままだと購入台数多くて上限に引っかかりそうなので、合計正規化係数の変わらないインスタンスタイプと台数に変更後それぞれ購入するのですが、インスタンスファミリーやらエンジンやら組み合わせ数が多くてオペミスがすごく怖かったです。。 CLI で予約購入を入れて、画面で確認して問題なかったらそのまま購入、問題があったらキャンセルというフローにしたかったのですが、RDSのRIは予約購入機能なかった(EC2にはある)ため実現できず。予約購入というかRDSのSPsが欲しい。 想像より調整・確認工数や精神的疲労が大きかったので、買い足しは半年に1回の運用にするつもりです。 効果確認 コストエクスプローラーでは購入したSPs/RI単位の効果を調べにくいので、AthenaからCURにクエリーを投げて調べます。 購入したSPsごとにarnが振られるので、それを使ってSPsが適用されたリソースのオンデマンド価格(pricing_public_on_demand_cost)からSPsが適用された価格(savings_plan_savings_plan_effective_cost)と未使用分(savings_plan_total_commitment_to_date – savings_plan_used_commitment)を引いてコスト削減額を出せます。 SELECT savings_plan_savings_plan_a_r_n, sum(pricing_public_on_demand_cost) as pricing_public_on_demand_cost, sum(savings_plan_savings_plan_effective_cost) as savings_plan_savings_plan_effective_cost, sum( savings_plan_total_commitment_to_date - savings_plan_used_commitment ) as savings_plan_unused_cost, sum( pricing_public_on_demand_cost - savings_plan_savings_plan_effective_cost ) as savings_plan_reduction_cost FROM "aws_billing"."aws_billing_cur_month_parquet" WHERE year = '2023' and month = '11' and line_item_line_item_type != 'Tax' and savings_plan_savings_plan_a_r_n like 'arn:aws:savingsplans::{AWSAccountID}%' group by savings_plan_savings_plan_a_r_n RIも同じように管理アカウントのRDSのarnを使って、RIが適用されたリソースのオンデマンド価格(pricing_public_on_demand_cost) からRIが適用された価格(reservation_effective_cost)と未使用分(line_item_unblended_cost – reservation_effective_cost)を引いてコスト削減額を出せます。 SELECT reservation_reservation_a_r_n, sum(pricing_public_on_demand_cost) as pricing_public_on_demand_cost, sum(reservation_effective_cost) as reservation_effective_cost, sum( line_item_unblended_cost - reservation_effective_cost ) as reserved_unserd_cost, sum( pricing_public_on_demand_cost - reservation_effective_cost - ( line_item_unblended_cost - reservation_effective_cost ) ) as reserved_reduction_cost FROM "aws_billing"."aws_billing_cur_month_parquet" WHERE year = '2023' and month = '11' and line_item_line_item_type in ('RIFee', 'DiscountedUsage') and reservation_reservation_a_r_n like 'arn:aws:rds:ap-northeast-1:{AWSAccountId}%' group by reservation_reservation_a_r_n 費用の付け直し 管理アカウントでSPs/RI一括購入すると、unblended cost(非ブレンドコスト) では管理アカウントの費用として請求されます。組織内のAWSアカウントに共有されて使われた分は、それぞれのAWSアカウントの費用として計算したいので、内部的に請求費用の再計算を必要があります。 サクッと出すには amortized cost(償却コスト) を使うのが良いです。前払いでも月ごとに期間按分してくれます。amortized cost は便利な項目ではあるものの、なぜかCURには amortized cost という列がありません。なにか調査したいときにCURで同じような値(完全に同じ値は出せなかった)を出すには、そこそこ複雑なSQL書く必要があります。 最終的にどの数字を元に費用の付け直しをするかは社内で相談して決めましょう。 -- 擬似amortized cost算出、前払いには未対応 WITH b AS ( SELECT year, month, bill_invoice_id, line_item_usage_account_id, line_item_line_item_type, line_item_unblended_cost, CASE WHEN line_item_line_item_type = 'SavingsPlanCoveredUsage' THEN savings_plan_savings_plan_effective_cost WHEN line_item_line_item_type = 'SavingsPlanNegation' THEN 0 WHEN line_item_line_item_type = 'SavingsPlanRecurringFee' THEN ( savings_plan_total_commitment_to_date - savings_plan_used_commitment ) WHEN line_item_line_item_type = 'DiscountedUsage' THEN reservation_effective_cost WHEN line_item_line_item_type = 'RIFee' THEN reservation_unused_recurring_fee ELSE line_item_unblended_cost END AS line_item_unblended_cost_haihu FROM "aws_billing"."aws_billing_cur_month_parquet" WHERE year = '2023' and month = '11' ) SELECT year, month, bill_invoice_id, line_item_usage_account_id, SUM(line_item_unblended_cost) AS line_item_unblended_cost, SUM(line_item_unblended_cost_haihu) AS line_item_unblended_cost_haihu FROM b WHERE b.line_item_line_item_type != 'Tax' GROUP BY year, month, bill_invoice_id, line_item_usage_account_id ORDER BY bill_invoice_id, line_item_usage_account_id; line_item_line_item_type item type説明 差し替えて使っている値 SavingsPlanCoveredUsage SPsが適用された分のオンデマンド費用 (集計用ではなくデータとして残すために出力されていると思われる) savings_plan_savings_plan_effective_cost (SPsが適用された費用、要は使った分) SavingsPlanNegation SavingsPlanCoveredUsageを相殺する行 (集計用ではないので相殺しているのだと思われる) 0 SavingsPlanRecurringFee 前払いなしまたは一部前払い時に対応する定期的な時間単位の料金 SPsを購入したアカウントに表示される savings_plan_total_commitment_to_date – savings_plan_used_commitment (定期的な時間単位の料金から使った分を引いたもの、要は余った分) DiscountedUsage RI適用後の費用 reservation_effective_cost (RIを使った分) RIFee RI前払いなしか一部前払いで買った場合、時間単位の料金 reservation_unused_recurring_fee (RIが余った分) 表2: SQL内に使われているCURスキーマの説明 参考: 予約の明細項目を理解する – AWS コストと使用状況レポート 予約の詳細 – AWS コストと使用状況レポート Savings Plans について – AWS コストと使用状況レポート 見落としていた点 唯一見落としていたのがサポート費用の増大。 SPs/RIを一括購入した管理アカウントには請求書上ではかなりの額が乗るので、それに合わせてサポート費用も増大します。 仕方ないこととはいえ、どうにかならんかという気持ちではあります。最安を目指すなら専用のAWSアカウントを新設してサポートプランをベーシックのまま、そのアカウントで一括購入するのがよいかと思います。 最後に 今回ドキュメントからは判別つかない点も多く、AWSサポートにだいぶ助けられました、本当にありがとうございました。実際に購入してみないとわからない点や、CURの複雑な点はどうしても自力でどうにかするのは難しいですね。 おかげさまで見積もり通りミスなくSPs/RIが購入できて、カバレッジも高められ、それなりの額のAWSコスト削減ができました。 ただ定期的に買い足しや買い直しをしなければならない運用はありますし、精神的負荷も変わらずあります。ここは定型化やチェックフローを自動化できるところはして負荷を下げていきたいと思います。 最後にこれからSPs/RIを買おうとしている方達へアドバイス。 事業が成長し続ける限り、買った方が得なので買うなら早く買おう 割引額が少し低くても柔軟性があるほうが事前調整が楽 Compute SPsが再利用されないことはほぼないので許可が取りやすい 不要インスタンスは削除、稼働インスタンスも最適化してから買いましょう 参考: 適切なサイズ設定に関する推奨事項によるコストの最適化 – AWS コスト管理 SPs/RIの仕様をしっかり理解しておこう 大きい買い物になるのでちゃんと説明できるようになっておく必要がある 購入時の恐怖がちょっと和らぎます CURと戯れておこう コストエクスプローラーだけでは出せない数字もあるので、欲しい数字がありそうな列を思いつけるくらいになっておくとなにかと便利です 参考: AWS CUR Query Library :: AWS Well-Architected Labs 初めて買うなら少額買って適用具合や費用の付き方を調べよう 買ってからじゃないと体験できないことも多いので、買って学ぶほうが早い ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
はじめに こんにちは。ニフティに新卒で入社して5年目の佐々木です。今回はAWSのサービスの一つである CloudWatch についてコスト削減を行う方法を紹介します。 以前ご紹介したコスト削減手法ついては、以下のブログ記事をご参考ください。 S3編 CloudFront編 背景 ニフティではサービス基盤にAWSを活用しており、コスト削減のためにサービスのインフラ効率を追求する取り組みや、有志で取り組んでいる社内でのコスト削減勉強会なども実施しています。 CloudWatchのコスト削減においてのポイントや注意点について簡単にご紹介したいと思います。 この記事の内容 触れること CloudWatchのコスト削減方法 CloudWatchのコストを削減する上での注意点 実際に試した社内でのコスト削減事例とTips 触れないこと CloudWatch自体の詳細の説明 自社での詳しいインフラ構成(コスト削減が目的のため、今回は一般的なインフラ構成のご紹介に限らせていただきます) CloudWatchの基本 CloudWatchとは、AWS上で展開されるサービスを監視するサービスです。 CloudWatchのコスト削減 課金形態 サービスの運用にかかるコストを正確に把握するため、いつもの如くAWSの公式をチェックしましょう。 2024年1月現在では主に以下のようになっています。(ap-northeast-1の場合で無料利用枠は除きます) ログの収集(データ取り込み)に対する課金 例えば「 収集 (データインジェスト )」の場合はスタンダードへの配信で0.76USD/GB課金される 取り込むログのデータサイズの取り込み量に依存される ログのデータの保存に対する課金 取り込むログ量だけでなく、ログデータの保存期間や保存先によっても追加で課金対象となる 例えば、CloudWatchの「 保存(アーカイブ) 」の場合は0.033USD/GB課金される メトリクスに対する課金 最初の 10,000 メトリクスの場合0.30USD課金される アラームに対する課金 アラームが発生した最初の時間からが課金対象 例えば「 標準解像度メトリクスアラーム 」の場合はアラームメトリクスあたり 0.10USD課金される その他にも課金要素はありますが、主に重要なのはこの3つだと思います。 詳細はこちらの AWS公式の資料 をご参考ください。 コスト削減方法 次に、CloudWatchに対する一般的なコスト削減方法をご紹介します。 ログのサイズの削減 CloudWatch Logs は基本的には安価でかつ活用場面も多いかと思いますが、ログ量が多くなると保存に対する課金も無視できなくなってきます。 そのため、まずは大元のログの量そのものを減らす方向で検討すると良いかと思います。 ログのデータ保存方法の最適化 前述した通り、CloudWatchの「 収集 (データインジェスト )」の場合は0.033USD/GBですが、S3の「 S3標準 」の場合は0.023USD/GBなので、データ保存先としてはS3の方がコストメリットが大きいです。 監視方法や保存期間などによりますが、リアルタイムでの監視が必要がないデータはS3へ移行し、CloudWatch Logs に保存する期間をその分短く設定するなどの最適化を行うことで、コスト削減の効果が狙えます。 実際に削減する際には、ログ保存期間の社内ルールなどと照らし合わせつつ最適な保存方法を検討すると良いかと思います。 使われていないメトリクス・アラームの見直し こちらも一つあたりの単価は安いので積極的に使いたいところですが、量が多いとそこそこの料金がかかります。 もし環境ごとや機能ごとなどに個別にアラームやメトリクスなどを定義していた場合は、開発環境で明らかに必要のないアラートを既に使われなくなったメトリクスなどを見直してみても良いかもしれません。 実際に社内で試したこと ログサイズの削減 担当したサービスでは、バックエンドで定義したAPIのデータ取得のタイミングで、特定のINFOログを生成していました。該当のログでは、接続先のURLやユーザーIDなどのメタ情報を出力しています。 これは、障害等が発生した場合などに、該当のAPIが問題なく動作していることを確認するために必要で、CloudWatch Logs への出力によりログの解析ができるようになっています。 CloudWatchに出力することを想定したINFOログが冗長なものになっていたので、ログ出力時の文言などを調整することでサイズを最適化しました。 また、今回のコスト削減の方針としては、「開発者として必要な情報量は減らさずにコストのみを削減する」といったことを目的としています。 出し分ける必要のないログは1つのログに集約する 削減自体の内容としては非常に簡単に行えました。 一部のログで、単一のリクエストを送るタイミングで複数のINFOログを送信する仕様になっていたため、コスト削減のためこちらを単一のログに集約してみます。 出力する文言としては、分かりやすさを重視するために以下のような形でした。(以下の例では、Goのロギングライブラリである Zap を使用しています) logger.Info("msg", zap.String("id", "XXX-001"), zap.String("body", "接続先URL: "+url), ) logger.Info("msg", zap.String("id", "XXX-002"), zap.String("body", "生成パス: "+filePath), ) 上記の形だと、個別のログそれぞれに対してタイムスタンプ等の情報が付与されてしまうので、余分にログのサイズに計上されてしまう恐れがありました。 そのため、以下のように1つのログに集約することで、全体のログサイズを削減しました。 logger.Info("msg", zap.String("id", "XXX-001"), zap.String("body", "接続先URL: "+url + " 生成パス: "+filePath), ) このような形で、チームメンバーと都度相談しながら出力されるログを必要なものだけに整理することで、結果的にCloudWatch全体の約5%のコスト削減を達成することができました! 学んだ教訓とTips 全体を通しての感想ですが、CloudWatchは気軽に利用できる反面、コストについて考える機会はあまりなかったと感じました。ただ、課金内容を詳しく調べてみると「意外とここで指定したログがかなり料金を食ってるなー」みたいな箇所が割とすぐに分かったので、対処自体はしやすいですし取り組むモチベーションにもつながるのかなと個人的には感じました。 まとめ 今回はCloudWatchのコスト削減方法についてご紹介しました。 重ねてになりますが、現状のコストを分析することで不要なリクエストや課金形態の発見に繋がることがあるので、普段使用しているサービスをCostExplorerなどで確認することが大事だなと思います。 CloudWatchについては、やや課金形態が細かく様々な要因で課金発生することも多いので、サービスの要件とも照らし合わせて要不要を分析しながら改善していけると良いのかなと思います! 他のAWSサービスでもコスト削減事例が思いついたら別のブログ記事にする予定なので、また機会があれば紹介したいと思います! We are hiring! ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 カジュアル面談も受け付けています! カジュアル面談 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering ニフティ株式会社 – connpass
こんにちは!ニフティ基幹システムグループの佐藤です。 業務では、主にまかせて365, Wi-Fiルーターレンタルの開発・運用を担当しています。 最近、Zapierを使ってコードを書かずにSlackワークフローを投稿すると自動でNotionDBにアイテムが追加されるようにしてみたのでお話したいと思います。 背景 私の所属チームでは複数のサービスのシステムの開発・運用を担当しています。そのため問い合わせを各方面からいただくのですが、問い合わせ用のSlackチャンネルでそれらのやり取りをしていました。その度に管理用に使用しているNotionDBに問い合わせのアイテムを手動で作成していて、それが本当に大変でした・・・(手間がかかる・・・) 登場人物 Slackワークフロー Zapier スプレッドシート NotionDB この4つが登場します。 全体構成 以下のような構成になります。 手順 1. Slackワークフローを準備する Slackワークフロービルダーから、Slackワークフローを作成します。 全体のイメージとしてはこんな感じです。 フォームの内容にはサービスが複数あるので、ワークフローにサービス名のドロップダウンを仕込みました。(後で使います)あとは、タイトルと質問内容を記入欄として用意しました。 次に、「スプレッドシートに追加する」を選択します。 スプレッドシートは「フォームからスプレッドシートを選択する」にすると勝手に作られます。これを選択するとシートも勝手に作って指定してくれます。特定のスプレッドシートを選択したい場合は「自分のスプレッドシート」から選択すればできそうです。 列はフォームに入力した内容を「変数を挿入する」から選択してください。 こうすることで、フォームに入力された内容がスプレッドシートに投入されるようになります。 最後に、フォームを投稿したらチャンネルに投稿した内容が通知がされるようにします。 (全体イメージを参考にしてみてください) 2. Zapierを準備する 全体構成 トリガーにスプレッドシートを設定する Eventには「 New Spreadsheet Row 」を選択します。ワークフローで書き込まれるスプレッドシートとシートをここで指定します。そうすることでワークフローで行が追加されたらZapierが発火するようにできます。 問い合わせワークフローのSlackリンクを取得する NotionDBのアイテムから問い合わせスレッドを追いたかったのでこの処理を入れています。必要なければカットでもOK 結構無理矢理ですが、「 Find Message in Slack 」で検索をして問い合わせワークフローのスレッドを引っ張ってきています。タイトルが全く同じものでなければ複数取れないし、取れちゃっても一番最新のものが取れるようにしてるので大丈夫・・・! NotionDBにアイテムを作成する Eventには「 Create Database Item 」を設定します。 追加したいNotionDBを選択し、プロパティ・本文に追加する内容を設定します。 Nameはアイテムのタイトルに当たるものなので、スプレッドシートのタイトルを指定しました。 チームで使用している問い合わせ用のNotionDBには、プロパティに「サービス名」という欄を設けているので、そこにはスプレッドシートのサービス名を指定しました。 本文はContentから指定できるので、ここにはスプレッドシートの質問内容と手順2で取得したSlack問い合わせのURLが入るように設定しました。 アイテムが作成されたらSlackに通知されるようにする Eventには「 Send Channel Message in Slack 」を設定します。 Channelに手順2で取得した ChannelId を指定します。MessageTextには好きな文言を入れてください。アイテムのタイトルやNotionURLなどを文面に含めるとSlackからNotionに飛べるので便利で良さそうですね。 問い合わせフォームを通知したスレッドに通知する場合は、Threadに手順2で取得した Ts を指定すれば良いです。 感想 問い合わせがそこそこあるので、その度にアイテムを作成するのが大変だったので、自動化できてよかったです。githubとの連携もできるので、それについても今後ブログにできたらと思います。 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
はじめに こんにちは。宮永です。 最近X(Twitter)やYouTubeで「公衆電話でダイヤルアップしてみた」のような投稿をよく見かけます。令和の時代になぜかブームが来ているようです。そこでダイヤルアップ接続ブーム(?)に乗って、「PPPサーバを立てて公衆電話から自宅にダイヤルアップ接続してみた」ブログを投稿します。 今回はUbuntuサーバと入手が容易なアナログモデムを用いてダイヤルアップサーバを構築し、実際に公衆電話から接続してみるところまでやります。 ちなみに、本来ダイヤルアップの接続先は契約したISPです。ニフティは2024年1月現在も ダイヤルアップ接続サービス を提供しているため、多くの「ダイヤルアップ接続してみた」投稿では接続先として使われていることが多いようです。 開発環境 作業は以下の環境で行いました。汎用的な作業しか行っていないので、異なっていても問題ないことが多いと思います。 ひかり電話 HGW PR-400MI Ubuntu 22.04.3 LTS アナログモデム ×2(サーバ用と公衆電話で接続する用) アナログモデムはブログの性質上特定の製品をおすすめできませんが、USB接続でドライバインストール不要の物を選んでください。Amazonで探すと選択肢はあまりないはずです。 方針 今回は、以下の流れで動くものを作成していきます。 mgettyがアナログモデムを接続したデバイスを常時監視し、着信があった際にpppdを起動する。 接続要求を受けたpppdはログイン可否をサーバ機に登録されているユーザか否かで判定し、パスワード認証する。 ログインできるユーザであれば設定したIPアドレスをクライアントに割り振り、内部ネットワークに加える。 開発 さっそく作業内容に入ります。 サーバ機のUbuntuは基本的な設定を完了し、root以外のユーザが登録してあるものとします。 アナログモデムをサーバ機に接続し、アナログモデムとHGWの「電話機2」接続口をモジュラーケーブルで接続します。接続口にある数字が内線番号になるため、今回接続したアナログモデムは内線番号2番になります。 HGWの設定 192.168.1.1 にブラウザでHGWの管理画面へアクセスし、ログインします。 電話設定→内線設定に移り、内線番号2の編集ボタンを押します。下の表にある自宅の電話番号の「着信音選択」が「IR」であることを確認します。 なお、HGWの管理画面へのアクセス方法やログインパスワードは環境により異なります。デフォルトの着信音はIRなので、もし管理画面にアクセスできない場合はそのまま次の作業に進んでしまっても問題ないケースが多いと思います。 パッケージインストール ここから先の作業はすべてrootで行います。 Ubuntuなのでapt-getでインストールします。mgettyはシリアルポートを監視するデーモンで、pppdは名前の通りPPPを扱うデーモンです。 # apt-get update # apt-get upgrade # apt-get install mgetty # apt-get instal ppp mgettyの設定 シリアルポートの確認 アナログモデムがどのシリアルポートに接続されているかを確認します。 # ls -lrt /dev/serial/by-id/ total 0 lrwxrwxrwx 1 root root 13 Dec 30 13:42 usb-Conexant_USB_Modem_24680246-if00 -> ../../ttyACM0 この例だとttyACM0になります。後で使うのでメモしておきます。 mgettyの起動設定 /etc/systemd/system/mgetty.service を以下のように編集します。 [Unit] Description=mgetty modem getty After=network.target [Service] ExecStart=/usr/sbin/mgetty -D ttyACM0 33600 Restart=always RestartSec=3 Type=simple [Install] WantedBy=default.target ExecStartの行にあるttyACM0の場所は、先ほど調べたシリアルポートの名前にします。 設定ファイルの編集 /etc/mgetty/mgetty.login に /AutoPPP/ から始まる行がコメントアウトされているので、そこを以下のように編集します。 /AutoPPP/ - a_ppp /usr/sbin/pppd auth -chap +pap login debug mgetty.configの設定 /etc/mgetty/mgetty.config に一番下に以下2行を追加します。 port /dev/ttyACM0 init-chat "" ATH OK ATS0=0Q0M0&D3&C1&M5&S1 OK ttyACM0の場所は、先ほど調べたシリアルポートの名前にします。 起動設定 systemd に新しいサービスを認識させ、有効にし、サービスを起動します。 # systemctl daemon-reload # systemctl enable mgetty.service # systemctl start mgetty.service pppdの設定 /etc/ppp/options に以下の設定を加えます。一部コメントアウトですでに書かれているものもあります。 ms-dns 8.8.8.8 proxyarp defaultroute usepeerdns pppdの認証設定 /etc/ppp/pap-secrets に以下の設定を加えます。似たような形でコメントアウトされているところがあるので、コメントアウトを外して編集します。 * server02 "" 192.168.100.200 この行は、<client_name> <server_name> <password> <IP_address>の順に記載します。 今回はPAMを使って認証するので、誰からでも受け付ける(ただし認証が通るかは別の話)ようにするために、<client_name>を*にします。同様の理由で<password>は””にします。 <server_name>にはサーバ名を記入します。この例だとserver02です。 <IP_address>はppp接続するクライアントに割り振りたいipアドレスを記述します。この例だと192.168.100.200です。サーバ機と同じサブネットに入るように、かつ重複がないようにします。 IPパケットの転送設定 以下の1行を実行します。 # echo 1 > /proc/sys/net/ipv4/ip_forward PAM(認証システム)の設定 nano /etc/pam.d/ppp に以下を追記します。 auth required pam_unix.so account required pam_unix.so session required pam_unix.so 動作確認 完成したので、あとは動作確認をするのみです。実は家の内線でも検証できるのですが、せっかくなので流行りに乗って公衆電話から接続します。 公衆電話はよくある緑色のものとグレーのものがあります(厳密にはピンク等もありますが省略)。今回は受話器を使うのではなくモジュラーケーブルを差し込む必要があるため、グレーの公衆電話を利用します。 しかしこれが全然見つかりません。 公衆電話の設置場所一覧ページ はNTT東日本が提供しているのですが、公衆電話のタイプまでは記載がありません。自宅の近くはすべて緑色でした。 調べてみると、都庁・ディズニーランド(本当に?)・品川駅にあるという噂を得たので、パソコンとアナログモデムと大量の小銭を持って品川駅に行きました。 あれだけ探していたグレーの公衆電話が3つもありました。パソコンを取り出し作業します。周りからの目がかなり痛いですが、気にしてはいけません。 公衆電話の端末接続口にある「アナログ」の方とアナログモデムをモジュラーケーブルで接続します。液晶に表示されている「データ通信」のボタンを押し、お金を入れます。 PC側も設定します。Windowsであれば、設定→ネットワークとインターネット→ダイヤルアップ→新しい接続を設定する→インターネットに接続します→ダイヤルアップ から簡単に設定できます。「ダイヤルアップの電話番号」に自宅の電話番号を入力します。ユーザ名とパスワードはサーバ機(Ubuntu)に登録されているユーザのものを入力します。 接続をクリックしてしばらく待つと接続が完了します。ここからは電話代がかかるのでサクサク作業していきます。といってもダイヤルアップ接続なので通信速度は遅く、今どきのデラックスなwebページは開けません。今回は検証のために軽量なサイトを見ることにします。 google検索は重くて使えないので、ブラウザにURLを直書きし、サイトが読み込まれるのをしばらく待ちます。(この時間が一番周りからの目が痛いです) じっと待っているとじわじわサイトが表示されます。これで検証完了です!恥ずかしいので急いで撤収します。 まとめ 完成しましたが、実は課題がいくつか残っています。何回か接続しないとうまくゲートウェイの情報が割り振られない時がある、ユーザを増やしたいときに逐次サーバ機のユーザを追加しないといけない等々、完ぺきではありません。設定をもっと見直す、radius認証に対応するといった作業が残っていますが、とりあえず完成ということにします。 PPPサーバに関する情報は古いものが多く調べても情報が出てこない場面が多かったので、ブログを書くことができてよかったです。(googleで「PPPサーバ」と調べても、PPPoEに関する情報ばかり出てきます……) デーモンの起動方法がinit.dからsystemdに代わっている、PAMではpam_pwdb.soではなくpam_unix.soを使うなど、現代のOSに合わせた設定を見つける作業にも時間を取られてしまいましたが、そういった知識を身に着けるきっかけにもなり楽しかったです。 みなさんもPPPサーバを立てて、令和に起きているダイヤルアップ接続ブームに乗りましょう! 参考文献 高原 利之, ひとりで作れる Linuxインターネットサーバー入門, ソシム, 2000年 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 19日目の記事です。 はじめに こんにちは。会員システムグループの川上です。普段はiOS/Androidアプリ「マイ ニフティ」の開発をしています。(弊チームではエンジニアを 募集中 です!) 今回は、ISUCONという競技イベントにニフティ社員でチームを組んで参戦するにあたって実施した準備について紹介します。 イベント当日のレポートについては下記の記事をご覧ください。 ISUCON13にニフティ社員で参戦してみた ISUCONとは? ISUCONは制限時間8時間でWEBアプリケーションを高速化してスコア化された性能を競い合うコンテストです。今年は11月25日に ISUCON13 が開催されました。 ※ 「ISUCON」は、LINEヤフー株式会社の商標または登録商標です。 メンバー集め 私は去年の ISUCON12 が初参戦で、今年も出ようかな〜とゆるく考えていました。 そんなとき、ニフティの部活制度でISUCON部を作らないかという話が出て、その流れで部員の中から自分を含め3名の出場メンバーを集めることができました。 ちなみにニフティの部活には、フットサル部やe-sports部など幅広いジャンルがあります。 参戦するまでにやったこと 1. 初心者向けの問題を解いてみる 基礎的なノウハウから学ぶため、ISUCON本と呼ばれる下記の書籍を各メンバーが購入しました。 達人が教えるWebパフォーマンスチューニング 〜ISUCONから学ぶ高速化の実践 ザックリと全体を読んだ後、まずはシンプルな問題でISUCONの典型的な流れを体験することにしました。そのため、ISUCON本にも登場するpixiv株式会社の社内ISUCON「private-isu」を解くことから始めました。 https://github.com/catatsuy/private-isu 進め方は初出場のメンバーがドライバー、それ以外のメンバーがナビゲーターをして、実際のISUCONの流れに沿う形で学習しました。 例えば、下記のような内容です。 マニュアル確認 systemctl・journalctlをはじめとした基本的なコマンド alp・pt-query-digest等の計測ツールの使い方 mysqlやnginxの設定 インデックス追加、N+1の解消 また、理解をアウトプットする場として、社内でハンズオンを開催しました。そのときの様子はぜひ下記の記事をご覧ください。 ニフティ株式会社 社内ISUCONを実施しました! 2. 過去問を解いてみる ISUCONにおいて最も効果のある練習法は過去問を利用した素振りだと思います。 私のチームでも、もちろん素振りをしました。今回は技術的に新しいコンテストの方がマッチしているため、ISUCON 11予選と12予選を実施しました。 https://github.com/isucon/isucon11-qualify https://github.com/isucon/isucon12-qualify 環境の構築はAWS上に行い、下記のリポジトリのAMIを利用させていただきました。 https://github.com/matsuu/aws-isucon/tree/main この時点では、時間制限を設けることがなく、気が済むまで思いついた改善を試していきました。練習した項目は主に次の項目です。 nginxによる静的画像の配信(認証なし/あり) キャッシュ戦略(Redisなど) 外部コマンド呼び出し解消 インデックス追加、N+1の解消、テーブルの変更 解いた後は公式の解説を読み、実施できていなかった改善を挑戦しました。 本当はその後、本戦の問題や8時間制限での素振りをした方が良かったのですが、時間の都合により叶わずでした。 3. 本番の直前準備 本番1週間前には下記のようなことを改めて振り返りました。 デプロイ等のスクリプト準備 初動の役割分担 再起動試験のタイミング デプロイ等のスクリプト準備 本番中は「ベンチ → 計測 → 修正 → デプロイ」のサイクルを大量に回すため、それぞれを実行する時間を短縮することは重要です。対象のサーバーは複数台あるので、手動で行うより一括で実行できる方法を準備しておく必要があります。 今回は実行内容を4つに分割して用意しました。(ベンチはISUCON公式コンソールから実行されます) プロビジョニング デプロイ(ファイル同期とサービスのrestart) ログのtruncate 計測(alpやpt-query-digest等の実施) 私のチームではAnsibleの知識が疎かったため利用せず、練習段階ではGithub Actionsで実行していました。しかし、Actionsは立ち上がるまでの時間が長く、待ち時間が非効率に感じたため、シェルスクリプトに落ち着きました。計測だけはそのままGithub Actionsで行い、自動でIssueに結果を作成するようにしました。 また、シェルスクリプトを含めたリポジトリはテンプレートリポジトリとして、簡単に複製できるようにしておきました。 初動の役割分担 初期段階では未知のアプリケーションがサーバーに動作している状態から始まるため、可能な限り早く必要な情報を取得して、改善に入れるように役割分担が必要です。 私のチームでは次の3つで役割を分担して、やることをNotionのチェックボックスで管理するように認識を事前に合わせておきました。 サーバーから必要なファイルの取り込み・デプロイスクリプトの整備 ソースコード解読、SQLの抽出 当日マニュアル読み、アプリを触ってみる 完了時間の目標も定めて、1時間以内にデプロイスクリプトが動作し、並行してアプリの気になる点やマニュアルの概要をNotionに抽出することにしていました。(実際にはメンバーが最速で終わらせてくれて、10分ほどでデプロイできるようになりました) 再起動試験のタイミング ISUCONには競技終了後にいくつか追試項目が存在します。そのなかに主催者が全サーバーの再起動後にベンチマークを実施して、再現スコアが最終スコアの75%以下の場合は失格になるという内容があります。 全チームに対して行う追試項目 再起動後の負荷走行でfailした場合 再現スコアが最終スコアの75%以下の場合 envcheckを利用したサーバ環境の確認 最終スコアで上位のチームに対して行う追試項目 負荷走行実行時にアプリケーションに書き込まれたデータが、サーバー再起動後に取得できない場合 https://github.com/isucon/isucon13/blob/main/docs/cautionary_note.md#追試 実は私が去年参加したチームではこの再起動試験でfailになってしまい、ランキング外になってしまったという経験があったので、今回は17:00には一度再起動を試すように決めました。本番当日は焦りもあるので、忘れないように連絡に利用していたDiscordにもリマインダーを仕込みました。 おかげで、当日はリマインダーが来た時刻に再起動試験を行い、無事failになることなく追試OKでした。 おわりに この記事では、私のチームがISUCON13本番までに実施した内容を振り返りました。事前の準備を固めておくことで、去年参加した際より、本番でスムーズに改善に取り組むことができ、見落としも少なくすることができました。 ちなみに当日の結果は661チーム中81位でした。 25,674  nisucon-bu ISUCON13 受賞チームおよび全チームスコア ISUCONは参加するたびWEBアプリケーション開発に足りないスキルを知ることができる貴重な機会だと思っています。最近は過去問も実施しやすい環境が整っているため、ぜひ未経験の方も体験してみてください! ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 22日目の記事です。 こんにちは。ニフティ会員システムグループの増井です。 みなさん業務や趣味でPythonを使っていますか。 高い汎用性とシンプルな文法で知られるPythonは、データ分析や機械学習のプロジェクトから、Web開発、さらには日々の作業を自動化するスクリプトまで、幅広い分野で活躍しています。 私の所属するニフティ契約者向けオプションサービスを開発するチームではサーバーサイドロジックを記述する言語としてPythonを採用しています。 今回のブログはそんなPythonの超基礎的な話です。 動機 先日、他の人が書いたPythonのテストコードを書いていてこんなことがありました。 with self.assertLogs(logger, level='WARNING') as log: response = obj.request(HogeHogeClass(param=some_value)) # responseの確認 self.assertIsInstance(response, HogeHogeResponse) self.assertEqual(response.fugafuga, 0) 自分「なんでresponseがwithブロックの外で参照できてるの?」 これ、ちゃんとPythonの仕様を理解している人からしたら至極当たり前のことかもしれないのですが、withブロックの中で定義した変数はwithブロックを抜けたあとも参照できます。 しかし自分はwithのコードブロックはスコープを形成するものだと思い込んでいたので、このコードを読んで非常に違和感を感じたのです。 また、ifやfor, while, tryブロックについても自分の直感に反してスコープを形成しないということに気づきました。 そこで自分への戒めを込めてPythonのスコープについてという初歩的な記事を書こうと思ったのでした。よく理解している人は笑いながらお読みください。 主な対象者 初学者 他の言語を書ける状態からPythonを速習で学んだのでちゃんと仕様を理解できている自信がない人 Pythonを書いているが他の言語も並行して書いているのでよく言語間の仕様がごっちゃになる人 スコープとは 基礎的な話なのでまず変数のスコープについての説明も書いておきます。 スコープとはその変数が参照可能な範囲のことです。 アセンブリのような低レイヤーな言語を除いて大半の高級言語に変数スコープはあると思います。 例えばJavaだとif文などで {} で囲われた中で宣言された変数は {} 内のみで有効で、{} を脱出すると寿命が尽きてその変数は参照できなくなります。 なぜ今まで気づかなかったか 自分が冒頭で書いたようなPythonの仕様に今まで気づかなかった大きな理由は、 これまではコードを1人で書くことが多かった 自分は数ヶ月前に中途で入社した者で、前職では社内に手を動かしてコードを書ける人があまりいなかったため自分一人でコーディングすることが多かったです。 先ほどのようなコードを一人で記述するならいつもこう書いていました。 response = None with self.assertLogs(logger, level='WARNING') as log: response = obj.request(HogeHogeClass(param=some_value)) # responseの確認 self.assertIsInstance(response, HogeHogeResponse) self.assertEqual(response.fugafuga, 0) with句の中で値を入れる変数をwithの外で予め宣言しておき、ブロックスコープ(と思い込んでいる)の外でも確実に参照できるようにします。 実際にこれでも問題なく動くのでずっと気づくことができなかったのです。 また、最初に学習したときにwithを抜けた後にwithの中の変数を参照しているようなサンプルコードを見たことはあるが使われている変数はwithの前のどこかで宣言されているもの、と暗黙的な前提を置いてコードを読んでいた可能性もあるでしょう。 Pythonのスコープ まず改めてPythonについて調べていて個人的に少し衝撃的だったのは Pythonにブロックスコープは存在しない ということです。ブロックスコープとは変数が定義されたブロックの中でのみアクセス可能で、外側からアクセスできない範囲のことを指します。 ブロックとはPythonではインデントされたコードの塊、Python以外の多くの言語の場合はコードのまとまりを中括弧 {} で表すものが多いと思いますがその場合は {} で囲まれた部分の塊です。 Pythonにあるスコープは以下の4種類です。 ローカルスコープ 関数内で定義された変数。関数が呼ばれると新しいスコープが作成され、関数が終了するとそのスコープも終了する。 def function() -> None: a = "nifty" function() print(a) # エラー エンクロージングスコープ ネストされた関数(内部関数)の外側にある関数内でスコープが作成される。内部関数が外側の関数の変数を参照できるが、内部関数からは外側の関数のローカル変数を変更することはできない。 def outer_func() -> None a = "nifty" def inner_func_read() -> None print(a) # nifty def inner_func_write() -> None a = "another_isp" # エラーにはならないがaはouter_func()直下のaとは別物として扱われる print(a) # another_isp inner_func_read() inner_func_write() 通常は関数をこのようにネストして書くことは少なく、主にlambda式を記述するときに意識する。 グローバルスコープ モジュールレベルで定義された変数。プログラム全体からアクセス可能。 a = "nifty" # グローバル変数 def hoge() -> None: print(a) # nifty ←グローバルに宣言された変数を参照できる a = "another_isp" # 同名の変数が初期化されるとhoge()内のローカル変数扱いとなりグローバルなaとは別物になる hoge() print(a) # nifty def fuga() -> None: global a # global文でグローバルに宣言されたaを使うことを明示する a = "another_isp" # グローバル変数aの値が変わる fuga() print(a) # another_isp ビルトインスコープ Pythonの組み込み関数や属性にアクセスするスコープ。 グローバルスコープよりもさらに広い。 以下のコードではmain.pyでhogeモジュールをインポートしてグローバル変数を参照しています。 hoge.py a = "nifty" #グローバル変数 main.py import hoge print(hoge.a) # nifty しかし、モジュール名を指定しないと参照できません。 main.py import hoge print(a) # モジュールを指定しないとエラー そこでhoge.pyでbuiltinsをimportしてビルトインスコープに加えるとimportさえしていればモジュール名を指定しなくても参照できるようになります。 hoge.py import builtins builtins.a = "nifty" main.py import hoge print(a) # nifty クラスとカプセル化について もう一つ、スコープに絡めてクラスを作る上で陥りがちな罠を紹介しておきます。 主に他の言語でオブジェクト指向のものを書いたことがある人向けの内容になります。 Pythonでclass直下に宣言されている変数はクラス変数 これはオブジェクト指向言語をメインで書いている人が陥りがちな罠だと思いますが、まず以下のコードを見てください。 class TestClass: _a = "nifty" def set_a(self, value: str) -> None: self._a = value def get_a(self) -> str: return self._a instance = TestClass() instance.set_a("another_isp") print(instance.get_a()) print(instance._a) print(TestClass._a) 出力はどうなると思いますか。 まず print ( instance . get_a ( ) ) の部分は another_isp が出力されることが分かると思います。 では print ( instance . _a ) の部分はどうなるでしょうか? Pythonではクラス内でプライベートな使い方を意図した変数には「_」を付ける慣習があるのでそれを考慮するとエラーが出力されそうですが実は 「_」を付けるのはあくまで慣習に過ぎず、言語の機能的に変数をプライベート(参照可能範囲をクラス内に限定)にすることはできない のです。 よってエラーにはならずちゃんと文字列が出力されます。 another_isp print ( TestClass . _a ) はどうでしょうか。 _a はインスタンスに属する変数なのでエラーでしょうか。 これもちゃんと出力されます。 nifty 「あれ、_ a は”another_isp”で上書きしたはずでは…」とも思うかもしれません(数週間前の自分なら思っていました) Pythonではクラス直下のフィールドに定義した変数はクラス変数 Javaのようなメジャーなオブジェクト指向言語では static キーワードなどを付けることによって初めてクラス変数になりますが、Pythonでは変数に対して明示的に static を付けることがありません(メソッドに対しては @ staticmethod がありますが)。 そういった事実を知らずにオブジェクト指向脳で上記のコードを読むと TestClass のインスタンス変数 _a に set_a ( ) で値をセットしているように見えますが クラス変数 _a (”nifty”で初期化されている) インスタンス変数 _a ( set_a ( ) をした時点で初めてインスタンスに変数が追加されている) の2つの変数が別々に存在している状態になっています。 ネームマングリング クラスを定義してオブジェクト指向的な書き方をしているのに変数をプライベートに出来ないのは不便です。そこでPythonではネームマングリングと言って変数の名前を自動で書き換えることで参照しづらくする(しかし厳密にプライベートにはできない)機構が備わっています。 class TestClass: __a = "nifty" def set_a(self, value: str) -> None: self.__a = value def get_a(self) -> str: return self.__a instance = TestClass() instance.set_a("another_isp") print(instance.get_a()) # another_isp print(instance.__a) # エラー print(TestClass.__a) # エラー print(instance._TestClass__a) # another_isp print(TestClass._TestClass__a) # nifty 変数名の先頭に「__(アンダースコア2つ)」を付けて「__name」などとすることで「_(クラス名)__name」という変数に内部的に置き換えることができます。 普段からプライベート変数を定義するとき当たり前にこうしている人にとっては「未だにアンダースコア1つでプライベートの意味を持たせてたの!」と思われてしまいそうですが。 ちなみに上記のコードでクラス変数とインスタンス変数がそれぞれ別個に作られるのは先ほどと同様です。 まとめ 以上、Pythonのスコープやクラス変数で陥りがちな罠についてでした。 冒頭で述べたようにちゃんと理解している人にとっては笑ってしまうような内容だったかもしれませんが、言語の仕様は今一度しっかりと確認してから使いたいですね。 今後新しい言語を学習するときも既存の言語の仕様から思い込みで判断していないか気をつけながら学んで行きたいところです。 ニフティでは私のチーム以外にもPythonを使った開発をしているチームが数多くあります。Pythonを使ったWebサービスの開発などに興味がある方はぜひ下のリンクからお気軽にご連絡ください! ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する