TECH PLAY

ニフティ株式会社

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

517

はじめに こんにちは!新卒3年目の加藤です。普段は社内システムの運用・開発を担当しています。 一番好きな社内ツールはSlackです。 Slackには単純にメッセージを投稿するだけではなく、APIを利用してアプリを作ることが可能です。 その中でも、何かのトリガーを元に処理を行う Slack Events API というものがあります。 今回は試しに、そのSlack Events APIを利用し、「Timesチャンネルが開設されたときに通知をしてくれるアプリ」の作り方をご紹介します。 SlackのTimesチャンネルとは?? いわゆる「分報」と呼ばれるものです。 (別名「社内Twitter」とも) 今何をしているか、何に困っているかといった業務のことから、ちょっとした雑談など、個人個人が開設し、自由に利用することができるチャンネルです。 他の人のTimesチャンネルに参加しておけば、業務の合間の雑談やその人が何の業務をしているのかがわかるので、コミュニケーションの活性化に繋がります。 ニフティでもこのTimesチャンネルが活発に活用されていて、自身も、開発で詰まってしまった部分を呟いた際に、部署の垣根を超えて他のエンジニアの方が教えてくれた経験もよくあります。 また、配属1年目の新人の方には先輩のトレーナーがついてOJTを行いますが、リモートワーク全盛の昨今、常に隣に座って相談に乗るということが出来ません。 また新人の方も先輩の顔が見えないなか遠慮してしまい、積極的に先輩社員に質問するというのも難しかったりします。 そこで、Slackを使って今の自分自身の進捗や困ったことをどんどん自身のTimesに載せて、トレーナーがアドバイスをしてくれるような新しい働き方など、様々な使われ方がされています。 (中には、トレーナーを呼び出すボタンをTimesチャンネルに設置している新人もいるとか…?) 今回は、このTimesチャンネルを誰かが開設した際に、いち早く参加するために、その開設のお知らせをチャンネルにするアプリを作ってみます。 事前に準備するもの 次のものは事前に準備されていることを想定しています。 Python(手元ではver 3.8で実行) Node.js(手元ではver 16で実行) AWSアカウント AWS CLIのインストールとプロファイルの設定 なお、手元ではMacを利用しています。 サービスの構成 今回はSlack APIから来たデータをAmazon API Gatewayを介してAWS Lambdaで処理するという、とてもシンプルな構成で作りたいと思います。 なお、AWSのサービスをGUIで設定するのは大変なので、今回は Serverless Framework を用いてInfrastructure as Code(IaC)も組んでみたいと思います。 手順 では早速アプリを作っていきましょう! 作業はすべて適当なディレクトリにて行います。 最終的には、次のようなファイル・ディレクトリ構成になります。 . ├── .serverless ← 自動生成 ├── Pipfile ← 自動生成 ├── Pipfile.lock ← 自動生成 ├── lambda_function.py ← 手順4内にて作成 ├── node_modules ← 自動生成 ├── package-lock.json ← 自動生成 ├── package.json ← 自動生成 └── serverless.yml ← 手順3内にて作成 1. Slackアプリの設定 まずはSlack APIを利用するためにSlackアプリの設定をします。 https://api.slack.com/ の「Create an app」からSlack アプリを作成しましょう。 その際、以下のような画面が出ると思います。 これは、Slackアプリをどうやって設定するか選択する画面です。 From scratch で画面からポチポチ設定していってもいいですが、少し大変なので、今回は manifest を使ってみましょう。 ワークスペースを選んで、YAMLには下記をコピペします。 display_information: # アプリの設定 name: NofityNewTimes description: Notify new times channels features: app_home: home_tab_enabled: true messages_tab_enabled: false messages_tab_read_only_enabled: true bot_user: # Botの設定 display_name: Notify New Times always_online: true oauth_config: # 許可するscopeの設定 scopes: bot: - channels:read # channel_createdのイベントを受け取るのに必要 - chat:write # Slackにメッセージを投稿するのに必要 - chat:write.public # チャンネルにアプリを追加しなくても投稿できるようにする settings: event_subscriptions: # イベントを受信する設定 request_url: https://example.com # イベント送信先。後で変えるので一旦適当 bot_events: # 受信するイベント。今回はチャンネルが作られたら発火します。 - channel_created org_deploy_enabled: false socket_mode_enabled: false token_rotation_enabled: false これで「Create」をし、アプリができたら「Install to Workspace」をクリックしてワークスペースにインストールしておきましょう。 2. 環境構築系 実際のアプリを作っていく前にアプリを構築するための環境を整備しましょう。 まずは、デプロイに利用するServerless Frameworkと、デプロイパッケージにPythonの依存パッケージを自動で含めてくれる便利なプラグインをインストールします。 % npm init (npm initの設定はすべて何も入力せずEnterでOK) % npm i -g serverless # Serverless Frameworkインストール % npm i --save serverless-python-requirements # デプロイパッケージに自動でPythonパッケージを含めてくれるプラグイン 次にPython関連の準備です。 今回は、仮想環境として pipenv を使うので、そのインストールと仮想環境の作成をします。 % pip install pipenv==2022.8.5 # pipenvインストール % pipenv --python=3.8 # pipenv仮想環境作成 最後に、作成した仮想環境に対して、今回の開発に必要なPythonパッケージをインストールしましょう。 % pipenv install slack-bolt # Slack Boltインストール 3. Serverless Frameworkの整備 AWSのリソースを自動で作成してくれるServerless Frameworkの設定ファイルを作ります。 serverless.yml service: notify-new-times frameworkVersion: '3' custom: pythonRequirements: # Pythonの依存パッケージを自動でデプロイに含めてくれるプラグインの設定 usePipenv: true # pipenvを使うためtrue provider: name: aws # AWSにデプロイ runtime: python3.8 # LambdaのランタイムにPython3.8を利用する region: ap-northeast-1 # デフォルトのAWSリージョン(東京) iam: # デプロイするLambda関数に与えるロールの設定 role: statements: - Effect: "Allow" Action: # Slack Boltでは下記が必要 - "lambda:InvokeFunction" - "lambda:GetFunction" Resource: "*" environment: # Lambda関数に設定する環境変数 SLACK_BOT_TOKEN: ${env:SLACK_BOT_TOKEN} # SlackアプリのAPIトークン SLACK_SIGNING_SECRET: ${env:SLACK_SIGNING_SECRET} # Slackアプリのシークレット(リクエストが正当なものか検証するのに必要) CHANNEL_ID: ${env:CHANNEL_ID} # 通知をするSlackチャンネルのチャンネルID package: # デプロイパッケージに含めるファイル patterns: # lambda_function.pyのみ必要なので、全部を除いたあとにlambda_function.pyのみ追加 - '!**' - 'lambda_function.py' functions: # Lambda関数の設定 notify-new-times: handler: lambda_function.lambda_handler # 最初に実行されるファイルと関数名 timeout: 10 # Lambda関数のタイムアウト(10秒) events: # Lambda関数のトリガー - httpApi: # API Gateway(自動でデプロイ時にAPI Gatewayも作成してくれる) method: POST path: /notify-new-times plugins: # 利用するプラグイン - serverless-python-requirements 4. Lambda関数の準備 では、実際にLambdaで動かすスクリプトを作ります。 lambda_function.py from slack_bolt import App from slack_bolt.adapter.aws_lambda import SlackRequestHandler import os # Slack Boltのappの初期化 app = App(token=os.environ.get("SLACK_BOT_TOKEN"), signing_secret=os.environ.get("SLACK_SIGNING_SECRET"), process_before_response=True) # LambdaのようなFaaSでSlack Boltを利用するときはTrue # Slack APIにackを返す関数 def respond_ack(ack): ack() # 指定されたチャンネルにTimesチャンネルの開設者とそのリンクを送信する関数 def notify_created_times(body, client): channel_info = body["event"]["channel"] if channel_info["name"].startswith('time'): # チャンネル名が「time」で始まっていれば notify_text = f'<@{channel_info["creator"]}>さんが<#{channel_info["id"]}>を開設しました:partying_face:' client.chat_postMessage(channel=os.environ.get( 'CHANNEL_ID'), text=notify_text) # channel_createdのイベントが来た時に実行される関数 # Ref:https://api.slack.com/events/channel_created app.event('channel_created')( ack=respond_ack, # Slack APIに3秒以内にackを返さないといけないので、それを行う関数 lazy=[notify_created_times] # 時間がかかりそうな関数はすべてこっちに載せる ) # 最初に実行される関数 def lambda_handler(event, context): slack_handler = SlackRequestHandler(app=app) return slack_handler.handle(event, context) 5. 環境変数の設定 デプロイに必要な環境変数を設定します。 APIトークンは「OAuth & Permissions」に、Signing Secretは「Basic Information」にそれぞれ書かれています。 % export SLACK_BOT_TOKEN=xoxb-xxxxxxxxx # SlackアプリのAPIトークン % export SLACK_SIGNING_SECRET=xxxxxxxxxxxx # SlackアプリのSigning Secret % export CHANNEL_ID=xxxxxxx # 通知先のSlackチャンネルID 6. デプロイ ではデプロイしましょう! % sls deploy --aws-profile プロファイル名 # Serverless Frameworkでデプロイする 7. イベント通知先のURLを設定する デプロイに成功すると、ターミナルの最後の方にendpoint URLが記載されているはずです。 これが、今回のデプロイで作成されたAPI GatewayのURLになるので、これをSlack APIに設定しましょう。 これで、チャンネルが作成された場合に、Lambdaが起動するようになります。 動作確認 Timesチャンネルを作成してみると… 無事に通知されました! 最後に ニフティではTimesチャンネルを多く活用しており、コミュニケーションの活性化に繋げています。 近年ではリモートワークによりコミュニケーションが希薄になりがちですが、そんな中でもSlackを通じてコミュニケーションを維持し、困ったことや雑談に対して誰かがすぐに反応をくれる文化は、ニフティの良い文化かなと個人的に思っています。 今回は、そんなTimesチャンネルのメリットを最大限に活かすために、Slack Events APIを用いて、Timesチャンネルの開設を通知してくれるアプリを作ってみました。 もし、Slackを活用していらっしゃれば、ぜひ参考にしてみてください。 また、今回はAPIのイベントトリガーとして「チャンネルが作られたら」というトリガーのみ利用しましたが、それ以外にもたくさんのトリガーで処理をさせることができるので、ぜひ試してみてください! We are hiring! ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering
はじめに はじめまして。 中廣と申します。 ニフティ株式会社に中途入社して4年目になります。 私が所属しているチームでは、日々の運用作業をこなしつつ、並行して開発作業も行っていますが、開発作業に時間を取りたいので、運用作業はなるべく自動化若しくは簡易化を進めています。今回は、AWS Chatbot + AWS Lambda + Slackを利用して運用作業を簡易化した話を書きたいと思います。 とある運用作業の手順(簡易化前) これまで手運用で実施していた運用作業の手順を以下に記します。 ※ 実際の手順より簡略化しています。また、テーブル名・項目名は適当な値にしています。 依頼元より作業依頼を受ける 他部署より作業依頼をメールで受けます。 依頼内容と、対象データのキー(受付番号:HOGE_NO)が連携されます。 SQLを順番に実行する 作業用サーバからSQL実行環境へログインし、以下SQLを実行します。 -- テーブルAのデータを依頼元から連携された受付番号で検索し、 -- 現在登録されているデータを確認する&後続処理に必要な値を取得する SELECT HOGE_ID, HOGE_A, HOGE_B, HOGE_C, LAST_UPDATE FROM TABLE_A WHERE HOGE_NO = &HOGE_NO; -- テーブルAの値を更新する -- HOGE_A,HOGE_B の設定値は HOGE_C の値によって決まるため、手作業で設定する UPDATE TABLE_A SET HOGE_A = &VAL1, HOGE_B = &VAL1, LAST_UPDATE = SYSDATE WHERE HOGE_NO = &HOGE_NO; -- 更新後の値を確認するため、再度SELECT文を実行し、目視で確認する SELECT HOGE_ID, HOGE_A, HOGE_B, HOGE_C, LAST_UPDATE FROM TABLE_A WHERE HOGE_NO = &HOGE_NO; -- テーブルBのデータを受付番号で検索し、データがないことを確認する SELECT HOGE_NO,FUGA_A,FUGA_B,LAST_UPDATE FROM TABLE_B WHERE HOGE_NO = &HOGE_NO; -- テーブルBへデータを投入する -- FUGA_A, FUGA_B の値は HOGE_C の値によって決まるため、手作業で設定する INSERT INTO TABLE_B (HOGE_NO ,FUGA_A,FUGA_B,LAST_UPDATE) VALUES (&HOGE_NO, &VAL_3, &VAL_4, SYSDATE); -- テーブルBのデータを受付番号で再検索し、データが投入されていることを確認する SELECT HOGE_NO,FUGA_A,FUGA_B,LAST_UPDATE FROM TABLE_B WHERE HOGE_NO= &HOGE_NO; -- 問題なければコミットする COMMIT; APIを実行し、外部システムへ連携する SQL更新後、APIを実行して外部システムへの連携を行います。 # HOGE_IDはテーブルA.HOGE_IDの値を設定する # VAL1, VAL2, VAL3 の値はテーブルA.HOGE_Cの値によって決まる curl "http://hogehoge/renkei?HOGE_ID=XXXXX&VAL1=XXX&VAL2=YYY&VAL3=ZZZ" …いかがでしょうか。 手順が決まっているとはいえ、なかなか面倒です。 また、すべて手作業なので作業漏れ・ミスにもつながります。 運用作業手順をもっと簡単にする 上記の手順を見ると、以下のことが分かります。 受付番号があればテーブルAのデータを特定できる 更新時に設定する値は、テーブルAを見ればわかる API連携する値はテーブルAを見ればわかる …ということは、受付番号さえわかれば自動化できちゃいそうですね。 ① 一連の作業を Lambda関数化する ということで、上記の作業手順をLambda関数(hogehoge_operation)にまとめました。 (以下はサンプルなのでデータチェック・エラーハンドリングなどは一切考慮していません!!) from lib.settings import session from lib.models import TableA,TableB import requests def lambda_handler(event, context): """ ほげほげ運用作業用Lambda関数(サンプル) """ # 受付番号を取得 hoge_no = event.get("hoge_no", "") # テーブルAのデータを取得 data = session.query(TableA).filter(TableA.hoge_no == hoge_no ).one_or_none() id = data.id hoge_c = data.hoge_c # テーブルAのデータを更新しつつ、テーブルBへ追加する値・API連携値を設定する if hoge_c == '1': data.hoge_a = 'hoge_a_1' data.hoge_b = 'hoge_b_1' fuga_a = 'fuga_a_1' fuga_b = 'fuga_b_1' val1 = 'val_1_1' val2 = 'val_2_1' val3 = 'val_3_1' else: data.hoge_a = 'hoge_a_0' data.hoge_b = 'hoge_b_0' fuga_a = 'fuga_a_0' fuga_b = 'fuga_b_0' val1 = 'val_1_0' val2 = 'val_2_0' val3 = 'val_3_0' data.last_update = dt.now() session.add(data) # テーブルBにデータ挿入 data2 = TableB( hoge_no= data.hoge_no, fuga_a = fuga_a, fuga_b = fuga_b, last_update = dt.now() ) session.add(data2) # コミット session.commit() # APIを叩いて外部連携する requests.get("http://hogehoge/renkei", params={"ID" : id, "VAL1" : val1, "VAL2" : val2, "VAL3" : val3,}) # 結果を返す return {"result" : "0"} この関数に引数 hoge_no を設定し実行することで、上述の運用作業を自動でやってくれるようになりました。これだけでだいぶ楽になりましたね。早速実行してみます。 PS C:hogehoge> aws lambda invoke --function-name hogehoge_operation --payload '{ "hoge_no": "xxxxxx" }' --cli-binary-format raw-in-base64-out response.json --profile profile_name { "StatusCode": 200, "ExecutedVersion": "$LATEST" } PS C:hogehoge> cat response.json {"result": 0 } 応答結果がresponse.json に出力されています。問題なさそうですね。 …ただし、aws-cliがインストールされていない環境では実行できません。 さらに手軽に実行できるように、Lambda関数をSlack経由で呼び出せるようにしたいと思います。 ② AWS Chatbot を利用してLambda関数をSlack経由で呼び出す WebコンソールからAWS Chatbotを開き、Slack ワークスペースを追加します チャットクライアントで「Slack」を選択し、「クライアントを設定」を押下すると、 認証画面へ遷移しますので、そのまま進めてください。 Slackワークスペースが作成されますので、「新しいチャネルを設定」ボタンを押下します。 設定画面から各種設定を行います。 チャネルID には、利用するSlackチャンネルのIDを入力します。 SlackのリンクURLを入力すると、チャネルID部分だけ切り取ってくれます。(便利) アクセス許可には、適切なロールを設定しましょう。 チャネルロールは「テンプレートを使用してIAMロールを作成する」を選択し、 ポリシーテンプレートは「通常のアクセス許可」「Lambda呼び出しコマンドのアクセス許可」を選択します。 ここまで設定したら、利用するSlackチャンネルで以下を入力します。 /invite @aws 入力後、以下が表示されればOKです! 続けて、以下のコマンドを入力します。 @aws lambda invoke –payload {“hoge_no” : “xxxxx”} –function-name hogehoge_operation –region ap-northeast-1 実行確認のメッセージが通知されますので、「[Run] command」 を押下します。 押下すると、コマンドを実行した旨の通知と実行結果が返ってきました! aws-cli を使わずに、SlackからLambda関数を呼び出すことができるようになりました!! …が、毎回コマンドを入力するのも正直面倒ですよね。 更に運用を楽にするため、Slackワークフローを利用してみましょう! ③ Slackワークフローを利用してコマンドを実行する Slackワークフロービルダーにて、以下のようなフローを作成します。 チャンネルのショートカットから起動する フォームを作成し、受付番号(hoge_no)を入力できるようにする チャンネルにコマンドを送信する hoge_no は引数に指定する 送信するメッセージはこんな感じです。ほぼ入力していたコマンドそのままですが、 hoge_no は「変数を挿入する」からフォームの入力値を設定します。 公開をしたら早速ワークフローを実行してみます。 チャンネルから「てすと」ショートカットを選択します。 フォームが表示されますので、受付番号を入力し、「Submit」ボタンを押下します。 ワークフローからコマンドが送信され、引数付きでLambdaを実行することができました! とある運用作業の手順(簡易化後) 上記①~③の対応を行ったことで、運用作業手順は以下になりました。 依頼元から作業依頼を受ける Slackのショートカットからワークフローを起動し、受付番号を入力して送信 結果を確認して終わり 簡易化前・後を比較するとだいぶやることが減りましたね♪ おわりに いかがでしたか? 面倒な運用作業もAWS・Slackを利用することによって簡易化することができました。 是非参考になればと思います。 We are hiring! ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering
こんにちは。最近PCを買い替えましたたけろいどです。 Nuxt3にStorybookとTailWindCSSを入れるまで はじめに Nuxt3、RC1おめでとうございます。 本リリースまでが待ち遠しいです。 ちょうど社内用ツールの開発があったのでNuxt3を導入しStoryBookなどのエコシステムを入れてみました。 Nuxt2であればモジュールが存在しますので簡単にセットアップできますがNuxt3はまだその辺りが充実していません。そのため手動でセットアップしていくこととなります。 その備忘録を残しておきます。だれかの参考になれば幸いです。 Nuxt3のインストール まずはNuxt3をインストールしましょう sample-project部分はご自身のプロジェクトに合わせましょう npx nuxi init sample-project Storybook パッケージインストール 必要なパッケージをインストールします。 yarn add -D @storybook/vue3 @storybook/addon-essentials storybook-builder-vite .storybookディレクトリ作成 storybookの設定を行うディレクトリを作成します mkdir .storybook touch .storybook/main.js touch .storybook/preview.js main.jsとpreview.jsも書いておきます。 // main.js module.exports = { stories: [ "../components/stories/**/*.stories.mdx", "../components/stories/**/*.stories.@(js|jsx|ts|tsx)", ], addons: ["@storybook/addon-essentials"], framework: "@storybook/vue3", core: { builder: "storybook-builder-vite", } }; // preview.js export const parameters = { } 次はpackage.jsonにstorybookを立ち上げるコマンドを書きましょう "storybook": "storybook-start -p 6006" その後実際に yarn storybook などでstorybookを立ち上げてみましょう 以下のような画面が表示されます。 まだstoriesがないのでその旨のエラーが吐かれていることがわかります。 storiesの作成 storiesを作成していきます。 まずは必要なディレクトリを切っていきましょう。 mkdir components touch components/Button.vue mkdir components/stories touch components/stories/Button.stories.ts 今回は以下のようなButton.vueを作成しました。 <script setup lang="ts"> interface PropType { type?: "button" | "submit" | "reset"; } withDefaults(defineProps<PropType>(), { type: "button", }); </script> <template> <button :type="type"> <slot></slot> </button> </template> <style scoped> button { font-size: 24pt; } </style> storiesも一緒に作成しましょう。 import Button from "../Button.vue"; export default { title: "Button", component: Button, }; const Template = (args: any) => ({ components: { Button }, setup() { return { args, }; }, template: ` <Button v-bind="args">Button</Button> `, }); export const Primary: any = Template.bind({}); Primary.args = { type: "button", }; 再度 yarn storybook などでstorybookを立ち上げてみます 無事Buttonが表示されています。 Storybookの導入ができました。 一方でTailWindCSSをStorybook上で使うことはまだできません。 次の章でTailWindCSSを導入していきます。 TailWindCSS パッケージインストール StorybookにTailWindCSSを動かす前にまずはNuxt3上で動作するようにしていきましょう。 必要なパッケージをインストールします。 yarn add -D @nuxtjs/tailwindcss 初期化処理 Tailwindが入ったら初期化します。 tailwind.config.jsが作られていることを確認してください npx tailwindcss init これでTailwindCSSがVueファイル内で使えようになりました。 class=”p_10” などを指定して確かめてみましょう。 StorybookとTailwindCSSをつなぐ 以上の設定によりStorybook起動とNuxt3上でのTailwindCSSの適応は確認できました。 一方でStorybook上でTailwindCSSが反映されておらずレビュー時に混乱を招く可能性があります。 このセクションではこれを解決していきます。 assetsの作成 tailwindCSSのbaseなどを読み込むためにassetsを作成します mkdir assets mkdir assets/css touch assets/css/tailwind.css tailwind.cssは以下のようにします @tailwind base; @tailwind components; @tailwind utilities; tailwind.config.jsの修正 tailwind.config.jsのcontentに設定を追加します。 /** @type {import('tailwindcss').Config} */ module.exports = { content: [ "./app.{vue,js,ts,jsx,tsx}", "./components/**/*.{vue,js,ts,jsx,tsx}", "./layouts/**/*.{vue,js,ts,jsx,tsx}", "./pages/**/*.{vue,js,ts,jsx,tsx}", "./plugins/**/*.{js,ts}", ], theme: { extend: {}, }, plugins: [], } StorybookにpostCSSの設定を追加 まずはpostCSSをStorybookに設定していきましょう。 そのためにアドオンをinstallしましょう。 npm install -D @storybook/addon-postcss まずはStorybookのmain.jsを変更していきます。 addonsにpostCSSを追加します module.exports = { stories: [ "../components/stories/**/*.stories.mdx", "../components/stories/**/*.stories.@(js|jsx|ts|tsx)", ], addons: [ "@storybook/addon-essentials", { name: "@storybook/addon-postcss", options: { cssLoaderOptions: { importLoaders: 1, }, postcssLoaderOptions: { implementation: require("postcss"), }, }, }, ], framework: "@storybook/vue3", core: { builder: "storybook-builder-vite", }, }; 次はpreview.jsを修正していきます。 修正内容は簡単でtailwind.cssをimportするだけです。 import '../assets/css/tailwind.css' export const parameters = { } 以上のことをやったのち npm run storybook とすることでtailwindCSSがStorybookに適応されていることが確認できました。 終わりに 今回はNuxt3でStorybookとtailwindCSSを導入してみました。 Nuxt3はTSがしっかりとサポートされており、触っていてとても楽しかったです。 useFetchやserverディレクトリなどの新機能も非常に使い勝手がよく、これからの開発もワクワクしてくるよいフレームワークです。 ぜひみなさんもお試しください 参考 https://github.com/nuxt-community/storybook/issues/330 We are hiring! ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering
はじめに ニフティでエンジニアをしている添野 翔太です。 ここ最近、 @niftyトップページ システム基盤の刷新を進めていく中で、ニフティの様々なサービスのデータを取得するために、APIをGoで作成していました。 そして、API仕様ドキュメントの管理をどうするか悩む中で、 こちらの記事 (@pei0804さんに感謝)を見つけ、Swagというツールに着目しました。 本稿ではAPI仕様ドキュメントを生成するSwagを導入した際にハマったことを紹介します。 Swagとは API仕様定義に基づくツールセット Swagger に関連するツールであり、Go向けのものとなります。 SwaggerにはYAML形式やJSON形式で記述したAPI仕様定義に基づいてHTMLドキュメントを生成する機能があります。Swagを使うと、コードコメントからYAML形式とJSON形式で記述したAPI仕様定義を生成できます。 コード内に記述するため、ドキュメントの更新漏れリスクを低減させることが可能となります。なお、詳しい記述ルールは Swag公式リポジトリにあるREADME を参照してください。 実際にSwagを使ってみる 実際にコードコメントからYAML形式とJSON形式のAPI仕様定義を生成してみます。 そのために適当なユーザーの一覧を返却するサンプルAPIを用意しました。 以下は、抽出したいユーザーが所属するサービスの識別子をもとに、ユーザー一覧を返却するAPIのコードです。import文の下とhandler関数の下に、Swagで使用されるコードコメントを記載しています。 package main import ( "bytes" "encoding/json" "fmt" "log" "net/http" "time" ) // @title ブログ記事用サンプルAPI // @version 1.0 // @description ブログ記事用サンプルAPI // @host localhost:8081 type User struct { ID json.Number `json:"id"` Name string `json:"name"` LastUpdateDate time.Time `json:"last_update_date"` } type Error struct { ID string `json:"id"` Message string `json:"message"` } var users = []User{{ ID: "1", Name: "太郎", LastUpdateDate: time.Now(), }, { ID: "2", Name: "花子", LastUpdateDate: time.Now(), }, { ID: "3", Name: "次郎", LastUpdateDate: time.Now(), }} var error_400 = Error{ ID: "ERROR-001", Message: "リクエストパラメータが不足しています", } // handler godoc // @Summary users // @Description get the users list // @Accept json // @Produce json // @Param service query string true "Service you want to get the users list" // @Success 200 {object} main.User // @Failure 400 {object} main.Error // @Router /users [get] func handler(w http.ResponseWriter, r *http.Request) { var buf bytes.Buffer enc := json.NewEncoder(&buf) service := r.URL.Query().Get("service") fmt.Println("service =>", service) if service == "" { if err := enc.Encode(&error_400); err != nil { log.Fatal(err) } fmt.Println(buf.String()) http.Error(w, buf.String(), 400) return } if err := enc.Encode(&users); err != nil { log.Fatal(err) } fmt.Println(buf.String()) _, err := fmt.Fprint(w, buf.String()) if err != nil { return } } func main() { // GET /users http.HandleFunc("/users", handler) log.Fatal(http.ListenAndServe(":8081", nil)) } さて、API仕様ドキュメントを生成するための準備が揃いましたので生成します。 APIのコード(main.go)が存在するディレクトリで以下のコマンドを入力すると、 $ go install github.com/swaggo/swag/cmd/swag@latest $ swag init 構文解析エラーが表示されました。これが本稿の題名にあるハマりポイントでした。 Generate swagger docs.... Generate general API Info, search dir:./ Generating main.User ParseComment error in file ./main.go :cannot find type definition: json.Number ここでエラーメッセージをもとに調べると、 こちらのissue や こちらのissue がヒットし、モジュール依存を解決するためのオプションが必要だと判明しました。 そこで、 $ swag init --parseDependency --parseInternal --parseDepth 1 を実行してみると、今度は上手く行ったようです。 Generate swagger docs.... Generate general API Info, search dir:./ Generating main.User Generating main.Error create docs.go at docs/docs.go create swagger.json at docs/swagger.json create swagger.yaml at docs/swagger.yaml 生成されたYAMLファイルを https://editor.swagger.io/ で確認してみると、API仕様ドキュメントを閲覧できました。 おわりに 本稿では、Swagとそれを初めて使ったときにハマったことを紹介しました。 Swagの記述ルール は個人的には分かりやすいと感じていて、導入してみてAPI仕様ドキュメントをすぐに生成できることに感動しました。 皆さんもぜひSwagを使うことを検討してみましょう。 We are hiring! ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering
はじめに こんにちは!新卒入社4年目の小松です。主にお客様が初めて@niftyをご利用になる際の無料ID会員登録システム、いろいろなサービスをご利用になる際のログインシステムの開発・運用を担当しています。 先日「マルチクラウド管理ノウハウ公開(AWS、ニフクラ)」に登壇しましたので、その様子を紹介していきます! イベント概要 NIFTY Tech Talk は、ニフティ株式会社の社員が主催するトークイベントです。 本イベントではニフティ社員が業務を通じて学んだことを発信しています。 第三回目となる今回は、「クラウドコスト」に関するテーマで開催しました。 ニフティでは、主にAWSとニフクラ、少しGCPを利用したマルチクラウドを管理しています。 テーマ1:「コストダウンの取り組み」 テーマ2:「コスト可視化の取り組み」 テーマ3:「コスト管理の取り組み」 イベントの詳細については こちら の記事でも紹介しておりますので、ぜひご覧ください。 また、今回の Tech Talk のアーカイブを YouTube にアップロードしております。 こちらもご覧いただけますと幸いです。 内容レポート 各テーマから一部抜粋して、どのような内容だったかご紹介したいと思います。 オープニング 今回はTech Talk初のYouTube Liveで開催しました。 はじめにニフティの会社紹介、登壇者の自己紹介から始まりました。 今回は最後にニフティポイントのプレゼントもありました! 今回の登壇者 小松 勇貴:会員システムグループ グループ長 福田 紫穂:インフラシステムグループ マネージャー 河野 曜平:インフラシステムグループ インフラチーム 小松 初:基幹システムグループ サービスインフラチーム 深田 健太:会員システムグループ メールチーム ニフティでのクラウド利用状況 ニフティでは現在、AWS・ニフクラ・GCPを利用しています。アカウント数は、AWS約240、ニフクラ約150、GCPが少数あり、これを社員のエンジニア150人で管理しています。 過去3年分のクラウドコストを見てみると増加傾向にあるのと、クラウドの予算と実績の乖離も増加傾向であったため、全社的にクラウドコストダウンとコスト管理強化に取り組みました。 テーマ1:「コストダウンの取り組み」 まず1つ目のテーマは、「コストダウンの取り組み」です。 実際に社内で取り組んだAWS、ニフクラのクラウドコストダウン方法を一部紹介しました。 初歩的なものから紹介しているので、何か参考になるものがあれば幸いです。 紹介した取り組み一覧です。 不要サーバ停止 スペック見直し(サーバ、ディスク) 料金プランの変更 利用時間外のリソース停止 Fargate Spotの利用 AWSによる推奨事項の活用 AWS RI/SPの適用 Amazon CloudFront Security Savings Bundleの適用 AWSの通信量の節減 CloudWatchログの保持期間設定 例えば、全クラウド共通でコストダウン効果が大きいものとしては、利用時間外のリソース停止があります。ここではAWS Lambdaとニフクラ、AWSのそれぞれのSDKを用いて、スケジューリングを行う方法を紹介しました。なおニフクラの場合は月額課金ではなく、従量課金にしておく必要があります。 工夫した点 工夫したことの一部にはチーム全員でクラウドコストダウンを取り組む方法として、スクラム開発で行った話を紹介しました。 ニフティでは、スクラム開発を導入するチームも増えてきています。 テーマ2:「コスト可視化の取り組み」 2つ目のテーマでは、「コスト可視化の取り組み」です。 継続的にクラウドコストダウンをするために、マルチクラウドのコスト可視化に取り組んだ話を紹介しました。 各ベンダーから提供されている生データをそのまま分析するのは手間なので、AWSとニフクラの請求情報をRedashでグラフ表示させた話をしました。 AWS、ニフクラ、それぞれの請求データ収集方法も話していますので、気になる方はアーカイブの方をご覧いただけますと幸いです。 さらに、フィルターを充実させることにより、期間ごと、プロダクトごと、部署ごとにフィルターをかけることができて、分析しやすくなりました。 今後は機械学習など用いて、予測額の精度を上げていく取り組みを行っていきます。 またGCPなどにも対応予定になっています。 工夫した点 AWS為替レートの取得で工夫した点を紹介しました。 フォーマット変更に弱い、AWSのPDFベースの請求書からデータ取得をやめ、AWS CURからデータを取得するようにしました。 このためにAWS Lambdaを実行する必要がありますが、さらにSlackワークフローを用いるように工夫したことにより、アカウントにログインせずとも、誰でも請求データを作成できるようになりました。 テーマ3:「コスト管理の取り組み」 最後のテーマは「コスト管理の取り組み」です。 適正なコストを維持するための、コスト管理の仕組みを紹介しました。 各アカウント単位で月次のクラウドコスト見通し額を立て、月末実績と一定以上の乖離があれば、差額と理由を報告する仕組みを導入した話をしました。 アカウントごとに見通しと実績に一定以上の乖離があれば、アラートが飛ぶ仕組みもあり、コスト見直しのきっかけになっています。 見通し額などの修正をする場合は現在Slackワークフローで申請するようになっていますが、もっと申請の手間をなくすためのプラットフォームを開発しています。 利用者側からの感想 アラートによって実際に誤請求に気づけた AWS、ニフクラの全アカウントにアラート設定をしてくれているので、手間がかからず助かっている アラートが来た場合は原因調査もするためクラウドコスト意識は上がった などの感想があり、実際にクラウドコスト意識向上に役立っています。 大変だった点 経理が円で管理しているのに合わせて、AWSも円で管理していたが、円安影響を受けアラートが大量に出てしまった話をしました。 これにより、「円安影響のため」といった無意味な見通し額修正の申請が大量にされてしまい、AWSはドルで受け付けるようにシステムの改修をしました。 まとめ 今回の Tech Talk では、ニフティでのマルチクラウドコスト管理方法、クラウドコストダウン方法を紹介しました。 1 時間という短い枠だったので、今回話しきれなかったものもありますが、参考にできるものがあれば幸いです。 初のYouTube Liveで開催でしたが、コメントくださった方もいました。ありがとうございました。 今後も NIFTY Tech Talk は継続して実施していきますので、ぜひご参加ください。 We are hiring! ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering
はじめに はじめまして。会員システムグループでメールシステムの担当をしている鹿野です。 みなさまは、担当されているシステムの監視アラート対応はどうされていますか? 弊社のメールシステムはメールサービスを提供しているというその特性もあり、緊急度の高いアラートは電話で担当者に通知を行う構成を採用しています。 今回はそのアラート発生から担当者に電話で通知するまでのフローを Alertmanager と Amazon Connect を使って構成したお話です。 この記事で使用している構成コードのサンプルは こちら システム構成 構成はとてもシンプルです。 アラートが発生するとAlertmanagerがSNSトピックにメッセージを発行し、メッセージを受けたSNSトピックはサブスクライブしているLambda関数を呼び出します。 呼び出されたLambda関数がAmazon ConnectのStartOutboundVoiceContact APIをコールします。 Amazon Connectが電話で通知を行います。 Lambda関数のコードサンプルを以下に抜粋しておきます。 import os import boto3 DEST_PHONE_NUMBER = "+81xxxxxxxxxx" connect = boto3.client("connect") def lambda_handler(event, context) -> None: contact = connect.start_outbound_voice_contact( DestinationPhoneNumber=DEST_PHONE_NUMBER, ContactFlowId=os.getenv('CONNECT_CONTACT_FLOW_ID'), InstanceId=os.getenv('CONNECT_INSTANCE_ID'), SourcePhoneNumber=os.getenv('SOURCE_PHONE_NUMBER'), Attributes={"message": "This is alert notification system."}, ) 今回使用するサンプルでは発信先電話番号を定数(DEST_PHONE_NUMBER)として定義していますが、環境変数で渡してあげたり、またはDBで管理するなどお好みで拡張ができます。 また、着信時に流れる機会音声の内容についてはAttributesパラメータに渡すmessage属性の内容がそのまま適用されるようになっています。 構成してみる 以下のステップで構成していきます。 通知システムの構成 Alertmanagerのアラート通知設定 通知システムの構成 ここでの通知システムとは、構成図のAWSリソース群のことを指します。 構成するには、以下の要素が満たされていることが前提です。 Terraformクライアントがインストール済み AWS IAM認証情報が設定済み 実行計画を確認して、 terraform plan 構成を反映します。 terraform apply outputsに出力された以下項目はAlertmanagerのアラート通知設定で使用するので、値を控えておきます。 iam_assumable_role_arn sns_topic_arn terraform outputs また、SNSトピックへメッセージを発行するIAMユーザーのアクセスキーが必要です。 コンソールまたはCLI等から取得しておきましょう。 Alertmanagerのアラート通知設定 Alertmanagerのバージョンは 0.23.0 以降が必須です。 Prometheus及びAlertmanager自体の構成は済んでいるものとし、Alertmanagerのバージョンは 0.23.0 を使用しています。 以下のステップで構成していきます。 IAM認証プロファイルの作成 Alertmanager設定ファイルにAWS SNSレシーバーを追加 IAM認証プロファイルの作成 Alertmangerのホスト上にIAM認証プロファイルを作成しておきます。 このサンプルでは、プロファイル名を共に alertmanger  とします。 Alertmanager設定ファイルにAWS SNSレシーバーを追加 Alertmanager設定ファイルにAWS SNSレシーバーを追加します。 route: receiver: 'snsreceiver' receivers: - name: 'snsreceiver' sns_configs: - api_url: 'https://sns.ap-northeast-1.amazonaws.com' topic_arn: '<sns_topic_arn>' subject: 'optional string' sigv4: region: 'ap-northeast-1' profile: 'alertmanager' role_arn: '<iam_assumable_role_arn>' topic_arn に前の項目で控えておいた sns_topic_arn の値を入力します。 sigv4.role_arn に iam_assumable_role_arn の値を入力します。 設定ファイルを保存後、Alertmanager を再起動、または設定を再読み込みさせれば Alertmanager の通知設定は完了です。 構成後の注意点 AWSリソースを構成して、Alertmanagerにも通知設定を反映したからはい終わり! となればいいのですが、電話でアラート通知を受けるにはあともう2ステップ必要です。 発信元電話番号の取得とコンタクトフローへの紐づけ 発信先電話番号の制限解除 発信元電話番号の取得とコンタクトフローへの紐づけ この記事を執筆した時点では、発信元電話番号の取得や、取得した電話番号をコンタクトフローへ紐づけするリソースが、TerraformのAWSプロバイダーに存在していなかったため構成内に組み込むことができませんでした。 本サンプルではコンソール上から紐づけ作業を行いますが、CLIでも同様のこと(claim-phone-number, associate-phone-number-contact-flow)ができるので構成フローに組み込もうと思えばできると思います。 発信元電話番号の取得とコンタクトフローへの紐づけは、Amazon Connectインスタンスの管理画面から行います。 取得と紐づけができたら、terraform.tfvarsファイルを作成して、 connect_source_phone_number に取得した発信元電話番号(E.164)を設定します。 connect_source_phone_number = "+1xxxxxxxxxx" 構成を更新します。 terraform apply 発信先電話番号の制限解除 地味なハマりポイントです。 これで発信できるようになったと思いきや、試しにアラート通知テストをしてみると以下のエラーに遭遇します。 [ERROR] DestinationNotAllowedException: An error occurred (DestinationNotAllowedException) when calling the StartOutboundVoiceContact operation: None エラー文だけだとさっぱり分かりません。 原因は、日本の携帯電話番号が デフォルトでは許可されていないプレフィックス として、サービス側で制限されていたからでした。 リストに載っているプレフィックスから始まる電話番号に発信したい場合は、AWSサポートからサービスクォータ引き上げ申請を行います。 内容に問題がなければ、数日程度で受理されます。 ここまでやることで、アラート通知を電話に発信できるようになります。 カスタマイズするとしたら 大きく二分すると、カスタマイズ先は以下の2つが挙げられます。 Lambda関数 コンタクトフロー 「発信先電話番号の指定」は前者でしかできませんが、それ以外のことはどちらでも可能です。 しかし、StartOutboundVoiceContact をコールしてから電話が切断されるまでのフローはコンタクトフローで制御されているため、フローの制御はできることならコンタクトフローに任せてしまったほうが楽かと思います。 例えばですが、「電話を受信して対応を開始したか?」に基づいてSlackに通知したければ、以下のようなフローを組み込めば実現できるかもしれません。 「顧客の入力を取得する」+「顧客の入力を保存する」 or 「コンタクト属性の設定」 -> 「コンタクト属性を確認する」 -> 「Slack通知するLambda関数を呼び出す」 まとめ Amazon Connect を使って電話アラート通知の仕組みを構成できる 発信先電話番号に制限がある点には注意が必要 以上がAlertmanagerとAmazon Connectで構成する電話アラート通知についてのお話でした。 Terraformのアップデートで、将来的にはTerraformだけで構成作業が完結できるようになることを期待しています。 We are hiring! ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering
イベント概要 NIFTY Tech Talkは、ニフティ株式会社の社員が主催するトークイベントです。 本イベントではニフティ社員が業務を通じて学んだことを発信しています! 第4回目のテーマは「レガシーシステムからの脱却」。現在、ニフティではさまざまなシステムの刷新やリプレースなどを行っています。今までのレガシーなシステムからモダンなシステムにどんどん切り替えていこうという流れが全社的に強くなっています。 今回は、レガシーシステムから脱却したプロダクトに携わっている現場のエンジニアを中心に、パネルディスカッション形式でリアルな現場の声をお伝えします。 概要 日程:8月23日(火)19:00〜20:00 配信方法:YouTube Live 視聴環境:インターネット接続が可能なPC/スマートフォン 参加方法 YouTube Live connpass にて参加登録をお願いします! こんな方におすすめ レガシーシステムからの脱却を検討している方 モダンな技術を現場で導入したいと考えている方 ニフティの現場でどのような技術が使われているか興味のある方 タイムテーブル 時間 コンテンツ 19:00-19:05 オープニング+会社紹介 19:05-19:15 登壇者紹介 19:15-19:20 固定IP受付システム刷新 19:20-19:25 老舗ポータルサイトの新たなシステムへの挑戦 〜@niftyトップページ〜 19:25-19:30 ニフティニュースの夜明け 〜32万超のページをレガシーシステムから救出!〜 19:30-19:35 レガシーなシングルサインオンシステムを 完全内製で作り直した話 19:35-19:55 ディスカッション & 質疑応答 19:55-20:00 クロージング テーマ 各プロダクトに携わっている方々に登壇していただき、それぞれLT形式で発表していただきます。 その後、発表していただいた内容についてディスカッションしていただきます。 固定IP受付システム刷新 ニフティ接続サービスで利用できるIPv4固定IPサービスの刷新について話していただきます。中でKubernetesが使われており、モダンな作りになっています! 老舗ポータルサイトの新たなシステムへの挑戦 〜@niftyトップページ〜 @niftyトップページの刷新について話していただきます。外注で作られた複雑なシステムをNext.jsとAWSを使って刷新しました! ニフティニュースの夜明け〜32万超のページをレガシーシステムから救出!〜 月間1億PV、32万記事超の規模であるニフティニュースを、レガシーシステムから段階的に移行しています。大規模システムの移行中で得られた知見や学びに関して紹介します! レガシーなシングルサインオンシステムを完全内製で作り直した話 各サービスで使われているSSOシステムの刷新について話していただきます。より安全に、互換性を持って前のバージョンから移行し、完全内製で刷新しました! 登壇者プロフィール 島田 大徳 (登壇者 & ファシリテータ) ニフティ株式会社 基幹システムグループ 課金システムチーム 新卒4年目。資料発送システムを中心に課金系、入会系システムを扱っています。好きなものはコンテナ技術。 添野 翔太(登壇者) ニフティ株式会社 会員システムグループ 第1開発チーム 新卒入社6年目。@niftyトップページの開発・運用を担当。AWS認定資格9冠達成、電気通信主任技術者資格を所持し、電気通信主任技術者に選任。 村松 啓寛(登壇者) ニフティ株式会社 会員システムグループ 第2開発チーム 新卒入社4年目。ニフティニュースの開発・運用を担当し、最近はモダンなフロントエンド開発を学びながら、実践中。 清水 利音(登壇者) ニフティ株式会社 基幹システムグループ サービスインフラチーム 新卒入社6年目。シングルサインオンシステムのスクラムマスターとして刷新・開発・運用などの活動をしています。 一緒に働く仲間を募集中です 新卒採用、キャリア採用を実施しています。ぜひ リクルートサイト をご覧ください。 ニフティエンジニアが業務で学んだことやイベント情報を エンジニアブログ にて発信しています! ニフティエンジニアのTwitterアカウントを作りました NIFTY Tech Talkのことや、ニフティのエンジニアの活動を発信していきます。 https://twitter.com/NIFTYDevelopers
初めに こんにちは!ニフティ新卒1年目の柴田です。研修が終わり、会員システムグループに配属されました。 配属先では、US配列のMacを使用しています。US配列を使用すると、JIS配列に慣れているため、英数/かなの切り替えが不便に感じます。そこで、US配列でもJIS配列のように英数/かなを切り替えられるよう設定しました。この記事ではその方法をまとめます。 不便な点 JIS配列のMacはスペースキーの左右に英数/かなを切り替えるキーがあり、左側のキーを押すと「英数」、右側のキーを押すと「かな」に切り替えることができます。 これがとても便利です。(Windowsを使用していた時も変換キー、無変換キーを英数/かなに割り当てて使用していました。) しかし、US配列のMacには英数/かなキーがありません。そのため、US配列のMacでは「Control + Space」での切り替えになってしまい、とても不便に感じます。 そこで、スペースキーの左右にある⌘COMMANDキーをそれぞれ英数/かな切り替えに割り当ててJIS配列のようにします。 設定方法 karabiner-elementsをインストール 画面に出てくる指示に従いインストールを完了させます karabiner-elements.pqrs.org karabiner-elementsでキーを割り当てる 今回はスペースキーの左右にある⌘COMMANDキーをそれぞれ英数/かな切り替えに割り当てます。 v14.5.0以降は  Swift UIに移行して UIが大幅に変わっているので過去の情報に注意してください https://karabiner-elements.pqrs.org/docs/releasenotes/#karabiner-elements-1450 Karabiner-Elementsを開く (Karabiner-EventViewerではない) サイドバーにある「Complex Modifications」をクリック 「Add rule」をクリック 「コマンドキーを単体で押したときに、英数・かなキーを送信する。(左コマンドキーは英数、右コマンドキーはかな) (rev 3)」の Enableをクリック 完了! これで左側の⌘COMMANDキーを押すと「英数」、右側の⌘COMMANDキーを押すと「かな」に切り替えることができます。 終わりに 今回は、US配列のMacをJIS配列のように英数/かなを切り替えらるように設定しました。 生まれて初めてUS配列を使用していますが、英数/かなの切り替え以外にはUS配列に不便を感じず、むしろcontrol, option, commandが並んでいるのがJIS配列に比べて使いやすく感じています。今後JIS配列とUS配列を選べる場合はUS配列にしようと思うくらい気に入っています! We are hiring! ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering
はじめに こんにちは。ニフティ株式会社に入社して新卒四年目の佐々木です。 今回は、業務で触れる機会のあった「NextAuth.js」について紹介したいと思います。 この記事の内容 NextAuth.jsの特徴 NextAuth.jsの実装方法 NextAuth.jsとは NextAuth.js とは、Next.jsで認証機能を実装するためのライブラリです。 特徴 NextAuth.jsの 特徴 としては以下になります。 セッションデータの保存をデータベースなしでも使用できる サーバーレス環境向けに設計されている(それ以外の環境でも利用はできる) デフォルトの設定でセキュアになるように設計されている ログインのセッションについては、データベースを使用せずにJWTで管理することができます。 例えばユーザー情報をアプリケーション側に保持しなくても良い場合は、「ログイン機能のためにデータベースを用意する」といった手間も省くことが可能です。 認証を行うコンポーネントを自前で実装する方法もありますが、NextAuth.jsといったライブラリを利用した方が、自前で実装したときと比較してアプリケーション以外にかけるコスト(運用やセキュリティ面のリスク)を下げることができると思います。 実装してみる 次に、NextAuth.jsを利用した際の実装例について紹介したいと思います。 NextAuth.jsでの認証の実装で作成するファイルは以下になります。 pages/api/auth/[…nextauth].js:認証プロバイダーやセッション保存方法を指定するために必要 pages/_app.js:Sessionオブジェクトを取得できるようにするために必要 pages/index.js: ログイン処理の実装を埋め込むために必要 next.config.js: 本番環境で外部の環境変数を参照するために必要 前提条件 技術:NextAuth.js(v4) + Next.js + React セッション格納方法:JWT Next.jsのアプリケーションは作成済み (NextAuth.jsはv3系からv4系へのアップデートで大きな変更が入ったため、今回は最新版である v4系 での紹介となります。詳細は こちら をご参照ください。) インストール まずは必要なパッケージのインストールを行います。 yarn add next-auth pages/api/auth/[…nextauth].js NextAuth.jsを組み込むには、pages/api/auth配下に[…nextauth].jsというファイルを用意する必要があります。 認証プロバイダー 認証プロバイダーを指定するため、providerオプションを追加します。認証プロバイダーに関しては、clientId、clientSecretなどの指定を行います。 認証プロバイダーには 組み込みのプロバイダー も用意されており、Google、Twitter、Githubといった有名なプロバイダーであればこちらから利用が可能です。 例として、Googleをプロバイダーとして指定する場合は以下のようになります。 import NextAuth from "next-auth" import GoogleProvider from 'next-auth/providers/google'; export default NextAuth({ providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, }), ], }) ちなみに、指定するプロバイダーについては、自前で用意した任意のカスタムプロバイダーを指定することもできます。詳細は NextAuth.jsの公式ドキュメント をご参照ください。 セッション 次に、セッションの保存方法を指定するため、sessionオプションを追加します。 NextAuth.jsは、デフォルトでDBを使用せずJWTのみでセッション管理とユーザ情報の管理を行います。しかし、公式のFAQ(  https://next-auth.js.org/faq#databases  )の例にあるようなDBへのユーザ情報の保存が必要なケースでは、strategyをdatabaseに指定しDBに接続するためのadapterを別途用意します。 今回はJWTでセッション管理を行うため、strategyをjwtに指定します。 providers: { ... }, session: { strategy: "jwt", maxAge: 30 * 24 * 60 * 60, }, pages/_app.js SessionProviderの設定 後ほど設定するuseUsession()でSessionオブジェクトを取得できるようにするために、<SessionProvider>を設定する必要があります。取得したセッションは同じアプリケーションが動くすべてのブラウザタブ/ウインドウで同期されるようになります。 pages/_app.jsに以下を追加します。 import { SessionProvider } from "next-auth/react" export default function App({ Component, pageProps: { session, ...pageProps }, }) { return ( <SessionProvider session={session}> <Component {...pageProps} /> </SessionProvider> ) } pages/index.js NextAuth.jsには Client API といったものが用意されており、これらのフック関数を使用することでログイン処理や、セッション情報の判定といった操作を簡単に行うことができます。 ログイン・ログアウト pages/index.js内でログインボタンを設置し、クリックした際に サインイン処理 が実行されるようにします。 signiIn()関数を使用すると、NextAuth.jsのサインインの中間ページにリダイレクトされます。 import { signIn } from "next-auth/react" export default () => <button onClick={() => signIn()}>Sign in</button> signIn()関数の第1引数にGoogleなどのプロバイダー名を指定することで、NextAuth.jsの中間ページをスキップして直接ログインさせることもできます。 また、第2引数にcallbackUrlを指定すると、ユーザーがサインイン後にリダイレクトで戻ってくるページを任意のURLに変更もできます。ログイン後に別ページにリダイレクトさせたい場合には使えそうですね。 import { signIn } from "next-auth/react" export default () => <button onClick={() => signIn('google', { callbackUrl: 'http://localhost:3000/bar' })}>Sign in</button> ログアウトさせたい場合は signout()関数を使用します。 import { signOut } from "next-auth/react" export default () => <button onClick={() => signOut()}>Sign out</button> セッション情報の利用 NextAuth.jsでログインすると、sessionにユーザー情報が格納されます。 それらを利用して、ログイン後に別のコンポーネントを表示させたり、ユーザーごとにクライアント側の処理を変更させる、というように簡単にクライアント側のみで動作のカスタマイズが可能です。 クライアント側からsession情報にアクセスするにはuseSession()を利用します。useSession()はクライアントアプリケーションのどの階層からでも呼び出すことができます。 以下がその利用例です。 import { useSession, signIn, signOut } from "next-auth/react" export default function Component() { const { data: session } = useSession() if (session) { return ( <> Signed in as {session.user.email} <br /> <button onClick={() => signOut()}>Sign out</button> </> ) } return ( <> Not signed in <br /> <button onClick={() => signIn()}>Sign in</button> </> ) } 環境変数の設定 ローカル環境で試す場合 先程[…nextauth].jsに記述した、clientId や callbackUrl などの値を env.local に環境変数として設定します。 GOOGLE_CLIENT_ID=xxx GOOGLE_CLIENT_SECRET=xxx 本番環境にデプロイする場合 本番環境にデプロイする場合は、ローカル環境で設定した値に加えて以下の環境変数を追加します。 NEXTAUTH_URL NEXTAUTH_SECRET NEXTAUTH_URL NEXTAUTH_URL にはサイトの正規URLを指定します。 NEXTAUTH_SECRET NEXTAUTH_SECRET にはデフォルトのシークレットの値を指定します。この値はJWTを暗号化しトークンをハッシュするために使用します。 (本番環境ではNEXTAUTH_SECRETの値が定義されていないと エラー が発生するため) また、シークレットにはopensslコマンドでランダムな文字列を生成すると便利です。 openssl rand -base64 32 環境変数の追加方法 本番環境などにデプロイする際には env.local だと環境変数として利用できないので、外部から値を参照できるようにする必要があります。 next.config.js というファイルを作成し、外部の環境変数を参照できるようにします。 require("dotenv").config(); module.exports = { env: { GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET, NEXTAUTH_URL: process.env.NEXTAUTH_URL, NEXTAUTH_SECRET: process.env.NEXTAUTH_NEXTAUTH_SECRET, }, }; さいごに 導入としては簡単になりますが、今回はNextAuth.jsのライブラリについて紹介しました。 NextAuth.jsには他にもオプションや機能などが充実しているので、もし興味があるという方は使ってみてください! 参考記事 https://next-auth.js.org/ https://nextjs.org/ We are hiring! ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering
この記事は、ニフティのエンジニア組織を知っていただくための一環としての、チーム紹介記事です。 はじめに はじめまして、三国と申します。 私はニフティに入社して二十数年、様々なシステム部門を巡り巡ってきましたが、今回は、現在マネージャーとして担当している会員システムグループの第三開発チームを紹介します。 まず、当チームは以下2つのサブチームから構成されています。 メールチーム データ基盤チーム 「第三開発」だけでは何を担当しているチームか全く分からなかったと思いますが、これで多少のイメージはつきましたでしょうか。以下、順にご紹介します。 メールチームの紹介 メールチームでは@niftyのメールサービスを支えるシステムの運用・開発を行っています。 @niftyのメールサービスは歴史が長く、始まりを辿るとパソコン通信NIFTY-Serveの誕生までさかのぼることになってしまいますが、ここを割愛したとしても、インターネットの電子メールサービスを二十数年に渡って提供し続けています。 お客さまと共にサービス35周年 | @nifty この記事を読まれているみなさんも、友人・知人とメールをやり取りする際、「〇〇〇@nifty.com」というアドレスを一度は見た事がありますよね?(無かったらすみません)これのことです! @niftyメール このようなサービスですので、システムの規模、利用されているお客様の規模、いずれもニフティ内で随一です。そのためメールチームだけで全てを賄っている訳ではなく、システム監視の部門やお客様サポートの部門などと協力して、日々、サービスの維持に努めています。 直近のメールチームのお仕事は@niftyメールのリニューアルです。 @niftyメール リニューアルのお知らせ 長年積み重なった複雑な仕組みや仕様を解きほぐしながら、新たなシステムを構築するのは骨の折れる作業ですが、やりがいはあります。(チームメンバーもそう感じてくれているはず。。) 現在は登山で言うとまだ五~六合目と先はまだ長いですが、様々な課題をチーム一丸で解決しながら進めています。 最後に、メールチームのメンバーに仕事のやりがいを聞いてみましたので、いくつか紹介します。 メールシステムのベテラン Aさん 「非常に大規模なシステムの開発&運用を経験できる。コンシューマ向けのサービスであり、リアルな利用者の声を聞ける。関わることができる範囲が広く、システム担当でも機能提案が可能。このような点にやりがいを感じています。」 中途入社〇年目 Bさん 「システム構成が一般的なWeb系のサービスとは異なっており、知識・経験の幅を広げるという意味合いでも価値があると思います。」 入社〇年目の若手エンジニア Cさん 「〇〇万人ものユーザーがいるシステムを支えているため、責任感とやりがいがあります!」 データ基盤チームの紹介 上記ご紹介した通り、メールチームではお客様が直接ご利用されるサービスを提供していましたが、データ基盤チームではニフティ社内向けに「データ基盤」を提供しています。 みなさま「データ基盤」とは何なのかご存じでしょうか。 ニフティではお客様に、光ファイバー回線やモバイル回線などのネットワークサービスを始めとして、メールやセキュリティなどのオプションサービス、ニュースやポイントサイトなどのWEBサービスを提供しています。 事業紹介 | ニフティ株式会社 これら様々なサービスの情報を一元的に集約し、社内に共有しているのが「データ基盤」です。これにより社員であれば誰でも、事業の状況をすぐに参照したり、サービス横断的なデータ分析をすることができるようになります。ニフティの縁の下を支えているシステムなのです! ニフティには、特定の分野で突出した知識とスキルを持って活躍している社員を「N1!(nifty No.1)」として任命する制度があり、この第一期メンバーに名を連ねるデータアーキテクトが在席しています。データ基盤に興味を持たれた方はこちらもご覧ください。 N1! 制度 | ニフティ株式会社 データ基盤チームのメンバーにも仕事のやりがいを聞いてみていますので、いくつか紹介します。 N1!データアーキテクト Dさん 「様々な理由で分断されていたデータを集めて触れられ、利活用がバッチリハマったときは特に面白い。日々進歩している業界の知識を得られる点も楽しいです。」 入社〇年目の若手エンジニア Eさん 「社内のデータを集約しているので、様々なシステムについての知見を深められる!」 以上、簡単でしたが第三開発チームの紹介でした。 We are hiring! ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering
はじめに こんにちは!新卒入社3年目の塩田です。社内システムの開発・運用を担当しています。 先日「 NIFTY Tech Talk #2 SRE【ポストモーテム・品質向上】 」に登壇しましたので、 その様子を紹介していきます! イベント概要 NIFTY Tech Talk は、ニフティ株式会社の社員が主催するトークイベントです。 本イベントではニフティ社員が業務を通じて学んだことを発信しています。 第二回目となる今回は、「SRE」というテーマに沿って座談会を開催しました。 テーマ1:「チームでポストモーテムをどのようにしているか!?」 テーマ2:「ポストモーテム導入後の効果は?」 テーマ3:「障害の備えとしてロールプレイングした話、どのように周囲を巻き込んでいったか」 テーマ4:「品質への取り組み、自動化や耐障害性について」 イベントの詳細については こちら の記事でも紹介しておりますので、ぜひご覧ください。 また、今回の Tech Talk の録画を YouTube にアップロードしております。 こちらもご覧いただけますと幸いです。 SRE とは? SRE とは、Google が提唱したエンジニアのシステム運用論です。 詳しい内容については Google のページ をご参照ください。 内容レポート オープニング + 会社紹介 はじめに会員システムグループグループ長 小松より、ニフティの会社紹介、ニフティでの SRE に対する取り組みなどを紹介しました。 ニフティでの SRE 活動は、各チーム内で SRE 担当を決め、SRE 推進チームが全体のサポートを実施しています。 SRE 推進チームが行っているのは「Embedded SRE」で、各チームで担当者が実施しているのは「The Google Model」というものになります。ニフティではこの組み合わせで浸透を進めています。 テーマ1:「チームでポストモーテムをどのようにしているか!?」 早速本題に入ります。 まず一つ目のテーマ「ポストモーテムの運用形態」についてディスカッションしました。 そもそもポストモーテムとは、障害報告書とは違い、読み手として現場のエンジニアを対象としている障害振り返りドキュメントのことを指します。 ディスカッション内では、ポストモーテムを導入した目的や、ポストモーテム共有会の実施方法、実施時の工夫点などが会話されました。 障害対応を実施した方には大きな負担がかかるため、精神的な支援も含めた体制づくりを心掛けているチームもあり、とても参考になりました。 ディスカッション内で話された、導入、運用状況を一部抜粋して紹介します。 <舟久保> 根本原因の検討、ドキュメント化を主な目的として導入しました。スクラム開発手法を導入していますが、障害が発生した際はスクラムイベントとは別で組み込んでいます。 <浅見> ポストモーテムにはインパクトや根本原因などを調べてドキュメント化する必要がありますね。 <舟久保> 私のチームでは、根本原因や対応の項目はチームで話し合って書くようにしています。 … <浅見> 定期的なポストモーテム共有会を開くのも重要です。隣のチームに対して、自分の担当サービスではこんな障害が発生していてこんな対応をしていますという共有ができると、勉強にもなっていいと思います。 また、障害対応を頑張った人を MVP として表彰し、ピアボーナスを贈るといったこともしています。 <舟久保> ドキュメント化する際は、タイムラインを作成する必要があるなど負担がかかりますね。 <浅見> SRE 本(https://sre.google/books/)にも障害対応をした人にご褒美をあげるべき!と強く書かれていたので、導入しました。 共有会で MVP 表彰を取り入れ、ピアボーナスを贈る文化を形成しているチームもあり、とても興味深いですね。 テーマ2:「ポストモーテム導入後の効果は?」 2つ目のテーマ「実際にポストモーテムを導入して感じた効果」について紹介します。 ポストモーテムを導入することによってノウハウが見やすい形で多くの人に共有され、後の振り返りがしやすいという意見が挙げられました。 現在ニフティではチーム単位でのポストモーテム共有会にとどまっていますが、ドキュメントとしては全社員が見られる環境が整ってきています。今後はより大きい範囲で共有会を実施できる体制を整えていきたいですね。 <舟久保> 障害対応時に獲得できる重要な知見が集まるのがメリットかと思います。タイムラインを見れば全体の流れがつかめるので、当事者ではなくても重要な場所が分かります。共有会を実施することで、システムだけではなく運用面やチーム体制などの改善点が見えてきます。 <川上> 無意識に手を入れるのを避けてしまっている部分はあるので、ポストモーテムを見返すことで改めて見つめなおすきっかけになりますね。 … <塩田> ノウハウが蓄積されるのが大きなメリットに感じています。エンジニア歴が短い社員にとってはノウハウが蓄積されている場がまとまっていると、見返すことで自分自身の成長につなげていけると思います。 <浅見> ポストモーテム共有会を実施していく中でも、共有会で得られたノウハウを各チームで実践した結果障害を防ぐことができているという効果が少し感じられる気がします。 テーマ3:「障害の備えとしてロールプレイングした話、どのように周囲を巻き込んでいったか」 3つ目のテーマは「障害ロールプレイング」についてです。 障害が発生した際の対応マニュアルを作成するのは一般的ですが、いざ障害が発生してみると予測できていなかった事態が発生するのは珍しいことではありません。 事前にロールプレイングをしておくことで、不測の事態を防ぐことができます。 実際にロールプレイングを実施した際のコミュニケーションの様子をご紹介します。 事象発覚から関係者連絡、担当アサイン、その後の対応とスムーズに進んでいる様子が分かります。 ファシリテーター 浅見が SRE NEXT 2022 に登壇した際に上記の内容を発表しておりますので、 こちら もぜひご覧ください。 ディスカッション内でもいくつかロールプレイングを実施した体験談が話されましたが、事前に準備していたマニュアルでは対応しきれない部分がいくつか発生し、見直しにつながったとの意見が多数上げられました。 また、障害ロールプレイングは実施するのにコストがかかるという相談もありましたが、過去に発生した障害をトレースすることから始めるのがいいといった声もあり、参考になりました。 以下、ディスカッションの内容も抜粋してご紹介します。 <塩田> 社内勉強会がきっかけとなり「Slack で障害が発生した際のロールプレイング」を実施しているチームがあります。実際に障害が発生した際にパニックになることを防ぐこと、事前に設定していたフローに考慮漏れがないかをチェックすることを目的として実施しています。実施した結果、代替ツールの仕様が変更されていることにより若干の混乱が発生し、フローを一部見直すきっかけになったとのことです。 <浅見> ロールプレイングで気づきが得られたとのことですが、私のチームで実施した際も「これを見ておかなければいけなかった」といった気づきがありましたね。 <舟久保> 実施してみたい気持ちはありますが、実施するまでのハードルが少し高い気がします。 <浅見> 最初は過去に起きた障害をトレースする形で実施し始め、慣れてきた段階でこれから起こるであろう障害を再現する方式を取りました。過去に起きた障害を振り返るだけでもいいと思います。 テーマ4:「品質への取り組み、自動化や耐障害性について」 4つ目のテーマは「品質への取り組み」についてです。 各メンバーの所属チームにて、どんな取り組みを実施しているのかをディスカッションしました。 SLI / SLO を設定し、ダッシュボード上で管理できるように設定しているチームも複数ありました。 SLI / SLO の設定やダッシュボードの作成ににおいて、アーキテクチャやノウハウなどの詳しい部分についても今後ディスカッションしたいですね。 <川上> 月一でパフォーマンス会を実施しています。システムに SLI / SLO を設定していて、ダッシュボード上でこれらの値をチェックしたり、リソースの遷移グラフを確認しています。また、即時対応が必要な問題なのか、潜在的な問題がないかなどを議論しています。 <浅見> SLO を見ながら定期的に問題を確認する場ができているということですね。異常があった際にすぐ気づける状態になっていて、とてもいいですね。 <塩田> 私の担当システムでは、Toil の洗い出し・優先度付けを行い、撲滅活動を実施しています。Toil を自動化し撲滅することで、オペミスのリスクが減り品質向上につながっています。 まとめ 今回の Tech Talk では、ニフティで SRE がどのように展開されているのか、また各チームでどんな工夫を凝らして運用しているかをディスカッションしました。 1 時間という短い枠でしたが、他チームで運用している内容やノウハウが次々と出てきたので、大変貴重な時間となりました。 今後も NIFTY Tech Talk は継続して実施していきますので、ぜひご参加ください。 We are hiring! ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering
はじめまして、種田 大地(たねだ だいち)と申します。 ニフティに入社して10年以上エンジニアをしておりますが、 これまでに複数のシステムを新しく作ったり、廃止したりしました。 システムを新しく作ったことがある方は多くいらっしゃると思いますが、 廃止に携わった・実際に廃止作業をした方というのはあまりいらっしゃらないかもしれないと考えて、この記事を書きました。 システム廃止作業に取りかかる前に システム廃止を行う場合は、大きく2つに分かれると思います。 利用がなくなったため廃止する 利用はあるが、価値が低下しているので廃止する(別の方法に変更する) 後者の場合は、実際の利用がどの程度あるのか、それがどういった価値をもたらしているのか、代替手段で同様の価値を生み出せるのかといった点も考慮する必要が出てくるため、廃止を行うにあたっての事前調査がなかなか難しいです。 そのため今回は前者の「利用がなくなったため廃止する」場合を想定して書いていきます。 廃止想定システム AWS環境で構築された、以下構成のシステムを廃止する想定で記事を書いていきます。 赤枠で囲ってあるのが廃止対象システム、黒枠は廃止しないシステムです。 システム構成図 廃止の段取り 事前作業 記録の準備 はじめに、廃止作業を記録する準備をします。 皆さん普段から作業を行う際はチケットなどにどのような作業を行ったか、作業のログなどを残していると思います。 システム廃止作業でもそれは同じです。 後述する事前調査時には対応不要だと考えていた部分などが、記録を取るうちに対応が必要な部分であると気づいたり、万が一復旧作業を行う際には、作業記録を頼りに復旧計画を練ったりします。 システム構成の調査 システム構成をできるだけ正確に把握しましょう。 これにより副次的な障害発生を防ぐことができますし、廃止する担当者の心理的不安を軽減できます。 また、廃止による定量的な効果測定を行うためにも必要な段取りです。 今回は想定として具体例がありますが、通常であれば以下のような観点が必要になると思います。 サーバにディスクやNFSがマウントされているか LBを利用しているか 他システムとの連携はないか また、システム構成を調査をより簡単・確実にする方法のひとつとして、以下が考えられます。 インフラのコード管理(IaC化) 新規構築時のドキュメントは更新漏れがあったりしますが、IaC化されていればそれがそのままシステム構成を示すことになります。 廃棄予定になってからのIaC化はなかなか大変ですが、初期構築時からIaC化されていれば、 システム構成を調査するにあたって役立つと思います。 今回の例では、廃止対象システムで利用しているEFSが、廃止しないシステムからも 利用されていることがわかりますので、廃止しないシステムに移管します。 以下が廃止作業後のイメージとなります。 ※✕印が廃止対象 システム廃止後のイメージ また、システムの監視を行っている際は、監視の内容も確認しましょう。 監視ありの状態のままシステム廃止を進めてしまうと、急に「システム落ちてます」といった連絡が来てしまうことになります。 アクセス状況調査 利用がなくなった前提ではありますが、廃止前にはアクセス確認を行いましょう。 廃止の中心となるアプリケーションのログを確認するのはもちろん、アプリケーションの前段にあるApache, nginxといったWEBサーバのログ、LBのログなども必要に応じて確認します。 これによって、現状アクセスがあるか・ないか、アクセスがある場合は利用の頻度がどの程度かと言った点を確認します。 認証などが必要ないアプリケーションのログを確認する場合、自身がアクセスしたログを「どこからかまだアクセスがある」と誤認することがありますので注意が必要です。 ここまではログからアクセス状況を調査する方法に触れましたが、もしアクセス状況がCloudWatchのダッシュボードなどにわかりやすくまとめられていると、ログ調査を行うよりは楽にアクセス状況を確認することができます。 廃止するシステムが復旧可能か検討 システムの利用がないという前提ですが、復旧が可能かどうかの検討も行います。 例えば、以下のようなポイントを廃止前に検討する必要があります。 システムのソースコードが手元に存在するか OSSで提供されているツールなどは、同じバージョンのソースが手に入らない場合もあります システムのリリースを行うことができるか リリース手順などが残っているか 手順などがない場合、自身やチームのスキルで復旧が可能か DBは復旧可能か DBデータのバックアップがあるか ドメインの所有権は持ち続けているか ドメインが変更になるとリンク切れや、SEOへの影響が考えられます 他にも検討する事項はあると思いますが、上記の例にとどめておきます。 システムを廃止する 各種バックアップの取得 システムの復旧ができるように、各種バックアップを取得していきます。 バックアップを取得する対象の例を以下にあげます。 アプリケーションの設定ファイル DBの設定ファイル、データバックアップ cronなどのスケジュール また、システムによっては、OSレベルで個別の設定を入れている場合もあると思います。 そのような場合はOSレベルの設定ファイルをバックアップしておくと、より安心です。 システムの一時停止 システムの全リソース(サーバなど)を廃止する前に、一度システムの稼働を停止します。 アプリケーションの稼働に利用しているコンテナやプロセス、サービスを停止状態にします。 これは、システムを停止したことにより、問題が発生しないということを確認するためです。 停止する期間は過去に利用されていた頻度を参考にするのがよいと思います。 例えば、毎日利用されていたシステムであれば数日~1週間程度の停止でいいでしょうし、 月に1度利用されるようなシステムですと、ひと月~ふた月程度の期間停止していれば利用者が困ることはないと考えられるでしょう。 システム稼働に必要な周辺リソースの切り離し システム本体を廃止する前に、前述の システム構成の調査 で記載した様々な関連リソースの切り離しを行います。 これにより、今回の構成例では ELB経由で停止したアプリケーション以外へのアクセスができなくなる ようになります。 これにより、今回の想定からは外れるのですが 実はELB経由で利用されている別のアプリケーションが廃止対象のEC2に相乗りしている といった場合に、利用者からの申告や周辺システムからのアラートによって、廃止してはいけないリソースであるということがわかりますので、より安全に廃止を進めることができます。 以下の接続を切り離していくイメージです。 ※DynamoDBおよびS3との接続は、前述のシステムの一時停止を行った際に切り離されている想定です 切り離しのイメージ システムが稼働しているサーバなどの停止 各種リソースを切り離した後は、システムが稼働しているサーバなどを停止していきます。 今回のシステム構成例ですと、EC2を停止するイメージです。 なぜこのような段階を踏むかというと、別システムが廃棄対象システムへアクセスしに来る、かつアクセス頻度が低い場合などは、事前調査における影響確認が難しいためです。 例えば、ひと月に一度別のシステムからファイルの取得が行われていた場合、ログイン・ログアウトのログをしっかりと確認すれば問題を防ぐことはできますが、なかなか発見が難しい場合もあります。 このような漏れがあった場合、システム廃止済みだと復旧不可能になる場合があります。 その回避のために一旦サーバなどを停止するような段階を踏みます。 より慎重を期すのであれば、この際に切り離した各種リソースへのアクセス状況を再度確認します。 こちらは、別システムからのアクセスが本当にないかを特定するために役立ちます。 システムの廃止 多くの方はクラウドサービスでシステムを運用されているかと思います。 そういった場合はAPIやCLI、もしくはWEB画面でシステム稼働していたリソースを削除しましょう。 はじめてリソースを削除する際は緊張するかもしれませんが、ここまでの段取りを取っていれば、復旧する準備も十分にできているはずです。 安心してリソースを削除しましょう。 今回のシステム構成例で廃止を行った場合は、以下の状態になります。 システム廃止後のイメージ 廃止後の作業 効果測定 せっかくシステムを廃止したのですから、効果を測定して自分やチームの成果にしましょう。 今回廃止したシステム例は、利用者がいない前提のシステムでしたので、どれだけコスト削減に寄与したのかを測定するのがいいと思います。 もし、利用者がいるシステムの場合は、コスト削減効果に加えて、利用者からの問い合わせやクレームがどの程度あったか・どのような内容だったかも測定するといいかもしれません。 最後に いかがだったでしょうか? 様々な事情はありますが、システムの廃止というのはいつか訪れると思います。 そんなときにこの記事が少しでも役に立つと嬉しいです。 ちなみに、本記事を書いている間も小規模な社内向けシステムの廃止作業中です。 現在は 「システムが稼働しているサーバなどの停止」 段階まで進んでいます。 We are hiring! ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering
初めに 新人研修の一環としてニフティ2022年度新卒入社の3名が、AWS JumpStart for NewGrads 2022(オンライン開催)に参加しました。 ニフティ2022年度新卒入社3名は、それぞれ別のチームで成果物を作成しました! このワークショップ3日間で行った内容と成果物を紹介します! 参加者 ニフティ2022年度新卒入社の小林、西牧、柴田の3名が参加しました! AWS JumpStart for NewGradsとは? 新卒1年目 のエンジニアの方々を対象とした、3日間の実践的な研修プログラム。 将来的にAWS活用をリードする人材になるための第一歩をスムーズに踏み出せるようなコンテンツをというコンセプトで企画されているため、単なるAWSサービスの学習だけでなく、チームに分かれて要件に合った適切なアーキテクチャを検討・設計する経験を積む部分にフォーカスした内容。 約250 名以上のエンジニアが参加 情報処理サービス(SI)、Web、ゲームなど様々な業種からの参加 業種混同で64チームに分かれる 1チーム 3~5人 少人数のチームでアーキテクチャを作成 全てオンラインで実施 主に使用するツールについて Slack: 各種アナウンス、チーム毎のチャットルームとして使用 Zoom: 本イベント会期中、様々な目的でWeb 会議ツールとして使用 Bluescape: アーキテクチャ検討時のホワイトボードツール ハンズオン用AWS アカウント: ハンズオンの際にチーム毎にお渡し 参加するまでやること AWS JumpStart 事前学習コンテンツ(必須) はじめてのアーキテクティング(60分) AWS入門(180分) ちなみに、ニフティの22新卒の研修では 事前学習コンテンツとは別に 下の内容を行いました!(一部抜粋) AWS基礎 ハンズオン – WEB3層アプリケーション – サーバレスなチャットアプリ チーム開発演習 – アプリの企画・開発 – AWSリソースの構築 内容 アーキテクチャ検討(メインイベント) 4人前後のチームに分かれ、お題に沿ったWebサービスのアーキテクチャを検討 最終日は工夫した点も含めてチームごとに発表 ハンズオン 実際にAWSのサービスを使ってみることで、実際の使い勝手や機能の詳細を学ぶ 実施期間 6/1(水) ~ 6/3(金)の3日間 スケジュール ※ お菓子・飲み物など持ち込み自由! 目標/課題 など 大規模チャットサービスを作る 成果 小林チームの成果 小林チームでは、3日間を通して作り上げたAWSのアーキテクチャ構成図は下図のようになりました。作り上げていく3日間の軌跡を紹介します。 完成されたアーキテクチャ構成図 1日目 同じチームの皆様もAWSに関しては事前学習で培った知識が大半を占めて、お互いに探り探り調べながら行っていました。 初めてで何も分からなかったので、まずは最小構成でEC2のみを作成し、そこから要件に合わせてリソースを追加していく流れで行いました。 その上で、 スケーラビリティ どの箇所がボトルネックになるのか RDSとDynamoDBの違い など、調べながらアーキテクチャを作り上げていきました。 2日目 1日目の調査のおかげで、アーキテクチャがだんだん構成されていきました。 構成していく上で、実装におけるコスト管理やRDSの詳細について考えました。 RDSに関しては、リードではなくライトの部分に関して考える必要があり、以下のことを知りました。 シャーディング Auroraの場合にユーザIDの剰余などでどの部分のDBに入るのかを決定させることが可能 また、DynamoDBに関して、以下のメリットがあることを知りました。 1 秒あたり数十万のトランザクションへの即時スケーリング 3日目 最終日は大体の構成が決定しており、続いてセキュリティ面に関する調べものを行いました。 また、DNSウェブサービスに加え大量のトラフィックを吸収・障害を分離するサービスのRoute53を導入した際、信頼性確保のため当サービスに対するセキュリティに着目しました。調べたところ以下の2種類が存在し、より強力なAdvancedに注目しました。 AWS Shield Standard すべてのリソースで自動的に利用可能 一般的なDDoS攻撃から防御してくれる AWS Shield Advanced Route53などの特定のリソースのみに適用可能 より大規模なDDoS攻撃から防御してくれる これに加え、以下の2つを導入しました。 AWS WAF(Web Application Firewall) CloudFrontにWebアプリケーションに特化したファイアウォールの機能を追加できる ACM(AWS Certificate Manager) SSL/TLS用の証明書を管理してくれる また、小林チームではアーキテクチャ構成図以外に、AWS Well-Architected Framework という、アーキテクチャがクラウドのベストプラクティスにどの程度準拠できているかを把握できるドキュメントを用いて、信頼性やコスト、運用の効率化の各観点においてどのような利点があるかを記述しました。 AWS Well-Architected Frameworkに基づいて作成された当アーキテクチャの特徴 西牧チームの成果 私のチームは全員が研修でAWSを触ったことあるよ!の初心者チームでした。 1日目 まずは自己紹介の時間。想像以上に多種多様な企業の方々が参加されていることと研修で少しAWSを触っただけであることがわかりました。 メンバーのAWS知識が少しわかったところで、次にたくさんあるサービスを知るために各自で調べて付箋で貼りました。 (初日に調べたおかげで全員の理解度の向上や話し合いの円滑化につながり大正解でした!) サービスしらべの風景 調べたサービスをどうつなげるかを手探りで考えながら、1日目は終了しました。 2日目 サービスについての理解ができてきた中、構成図のむずかしさに直面しました。そこでAWS公式のページなどを見て構成図の作り方を勉強しながら必要なサービスを絞っていきました。 ここで初日にメンバー全員で書いたサービス調べが役立ちました! 後半はAWS運営の方に質問しながらコスト管理について考え、サービスの内容だけでなくコストについての調査も行いました。 3日目 ここからはより実例のことを考えていきました。 大規模チャットサービスでありうることといえば? 話し合いの中で出たものは「あけおめ」や特定の映画などのセリフの投稿でした。 そこで、それらが予測される日や時期(年末や映画の地上波公開など)には自動的にスケーリングするようにlambdaを使いました。 西牧チームの成果がこちらです。 柴田チームの成果 私のチームでは、1つの要素ずつ検討し、アーキテクチャ構成を徐々に変更を加えながら作成していきました。 1日目 初めに、簡単に自己紹介をしました。メンバーのAWSの経験は、ほぼ使ったことないからちょっと使ったことあるくらいでした。 次に、お題のサービスを実現するのに必要な機能を検討しました。また、それらの機能を実装するのに使いそうなAWSのサービスのピックアップを行い下の図のようにまとめました。「Webサイトの配信には、S3とCloudFrontは使いそうだよね〜」って感じです。 2日目 まずは、1日目にピックアップしたAWSのサービスを用いて必要な機能を実現する最小限の構成を構成図を作りました。 そして、作成した構成図を信頼性、スケーラビリティを意識してアップデートしました。 2日目の成果が下の図になります。信頼性を意識し、RDSを複数のAZに設置しました。また、スケーラビリティを意識し、ECSを使用しました。 3日目 3日目は、2日目までの構成からパフォーマンス、コスト、セキュリティを意識して変更を加えました。 チャットは低レイテンシを求められるため、マルチリージョンにすることを検討しました。しかし、全ての機能をマルチリージョンにするとコストが高くなるため、低レイテンシが求められる機能のみをマルチリージョンに配置することでコストを抑えました。 さらに、セキュリティ強化のため、AWS WAFを設置しました。 感想・学び 当社でも技術研修としてAWSの基礎について学びつつ、ハンズオンにおいてアーキテクチャ構成図を見ながらリソースの構築と削除を行う機会がありました。その時点ではAWSの概念と使用用途のみを学ぶことが出来ました。その上で当研修を行った後同じハンズオンを行いましたが、「なぜこのリソースを用いるのか」「リソースの影響範囲はどこまでか」をしっかり把握した上で完了できたので、AWSに対する理解度がより深まり、実際の業務でも生かせています。(小林) 3日間のワークに参加して、AWSサービス同士の効率の良いつなげかたを考えながらアーキテクチャ構成図の書き方や、それぞれのサービスの特色や使いどころを学ぶことができました。またワーク内ではコスト面やパフォーマンス面についても考えることができ、実際に運用する側の視点を身に着けました。これにより実際の業務の中で社内システムの構造への理解度の向上を実感しています。(西牧) 同じ機能を実装するのでも複数のやり方があり、実装方法によりコストが変わってくるため、最適なアーキテクチャ構成を作成するのが難しかったです。アーキテクチャ構成を検討する中で、様々なサービスを比較しながら調査することで、それぞれのサービスの特徴を学ぶことができました。また、ハンズオンを行うことでサービスへの理解度がより向上したと感じています。(柴田) We are hiring! ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering
初めに 最近全てのシステムは人間というシステムの運用開発であるという考えを持ち始めた, 会員システムグループの2年目社員の関です. システムにおいて最も重要なことは人間がいかに使いやすいかである と考えてアクセシビリティに興味関心を持ち, 社内に広げたいと考えています. TechDayという社内イベントのLTでアクセシビリティに関して話したりもしました. 今回は社内で開いたオーサリングプラクティス輪読会という勉強会の中での課題の話をしたいと思います. オーサリングプラクティス輪読会とは オーサリングプラクティス輪読会はオーサリングプラクティスを輪読する会です. オーサリングプラクティスって? 一言で言うと HTML/CSS/JavaScript/WAI-ARIA* を使用してどのようにアクセシブルなWebシステムの機能を作成するかについて実践的な記述方法が学べるWeb上のコンテンツです. *WAI-ARIAとは : HTMLだけでは表すことのできない構造や状態を表現するための仕様のことです. 以下のページで読むことができます. ARIA Authoring Practices Guide-patterns . 輪読会では上記のPatterns一つ一つを読んで, どのようにHTML/CSS/JavaScript/WAI-ARIAを使って機能を作成すれば良いのかということを学んでいます. オーサリングプラクティス輪読会で出した課題 オーサリングプラクティス輪読会では7回目までの理解度を測るための中間課題を出しました. 課題 ダイアログ要素を使用したTODOリストをアクセシブルに作成する 要件 React, Vue, Svelte, Solid.jsなどのライブラリは使っても良いが, React-modalなどのライブラリは使わずに自分で実装を行う 作ってほしいシステムのイメージ(以下のイメージを元にシステム作成を行なってもらいました) TODOリストメイン画面 TODOの追加画面.ダイアログとして作成する TODO編集画面.ダイアログとして作成する TODO削除画面.ダイアログとして作成する. 以上です. 課題としてはモーダル要素部分以外は正直大したことはないように思えますが, 実は考慮することは結構あります. 課題の答え 課題の答えも自分で考えて作成しました(ゆえに不足している点がある気がします). 答えにおいて肝になる点を何点か以下で紹介します. モーダルウィンドウを表示しているときのキーボードフォーカスについて これがモーダルを自分で実装する際の最も難関な部分だと思います. アクセシブルなモーダルを1から作るとなると以下の部分を考えなければなりません. フォーカスの移動 モーダルを開いている間はフォーカスをモーダル上に留めなければならない モーダルだということを 支援技術* に伝える( *支援技術 : スクリーンリーダーなどの障がい者等が使用する装置, ソフトウェアの総称です.) role=modalなどを使用して支援技術*にモーダル要素であることを伝える必要があります モーダルのデザイン 視覚的にモーダルだとわかるように, モーダルが表示されているときは元のページは灰色などでマスキングすることが理想です これを一から作るとなると大変です. 現状のHTMLにはdialogという要素が存在しており, これを使うことで簡単に上の要件を満たしたモーダルを作成することが可能です. <dialog>: The Dialog element . dialog要素は2022のInteropにて2022年以内に現在の主要ブラウザの全てで対応するようにすり合わせを行なっています.そのため, 2022年7月現在すでに主要なブラウザは対応している状態です. Interop 2022: browsers working together to improve the web for developers . そのため, 今回のシステムではHTMLのdialog要素を使用してモーダルウィンドウを作成しました. <dialog></dialog> dialog要素を使うことで非常に簡単にモーダルが作成できるため, 非常に便利だと感じました. 音声でそれぞれの操作が認知できるか チェックボックスをチェックしたかどうか?は目が見えないなど視覚にハンデを持っている人にとっては認識できないかもしれません. その場合には, そのような操作は逐次音声として伝える必要があります. どのように実装したか 今回はこれを解決するために以下のように画面には表示されないが, 支援技術には認識されるHTML要素を作成しています. <div className={styles.visuallyHidden} id='notes_save_status' role='alert' > {alertText} </div> 要素には role='alert' を設定して中身に変更があった場合は支援技術が検知するようにしています. React側のコードは以下のようになっています. setAlertText(`${title}のTODOを完了しました`); 上記は完了の例ですが, setStateでalertTextを切り替えることでTODOリストへの追加, 編集, 削除, 完了, 未完了などが支援技術を通してユーザに伝わるようにしています. WAI-ARIAを適切に設定しているか 今回のモーダル要素は複数存在するため, どのモーダルが表示されたのかをWAI-ARIAを使って支援技術に伝える必要があります.そのため, 今回は以下の二つのWAI-ARIAを設定しなければなりません. ariaの名前 説明 aria-describedby Dialog要素の中にタイトル以外にダイアログを説明する要素がある場合にそのIDを指定する aria-labelledby Dialog要素内のタイトル要素のIDを指定する HTML内に記述するaria要素とその説明 実際に設定すると以下のようなHTMLになります.(実装ではDialogコンポーネントを作っていたので微妙に違います). <dialog aria-describedby='deleteDialogDesc' aria-labelledby='deleteDialogLabel' .../> <h2 id="deleteDialogLabel">{title}</h2>   <div aria-describedby='deleteDialogDesc' > {`${todoVal[parseInt(selectTodoId)]?.title}`}のTODOを削除しますか? </div> </dialog> 上記は削除要素の例ですが, タイトルであるh2を aria-labelledby , 削除の文章に aria-describedby を指定しています(削除の確認の文章は説明ではないので設定する必要はなかったかもしれません). 削除以外の要素はフォーム以外に説明する要素はないのでaria-describedbyは設定していません. まとめ 今回の勉強会で課題の作成と答えの作成をしてみて, 現在のモダンフレームワークでどのようにアクセシブルなシステムを作成するのか, どのように要件を考えていくのかなどがなんとなくわかってよかったと思います. 将来的にこの経験を業務にも活かして, 全ての人間が使いやすいシステムの構築を目指していきたいと思います. We are hiring! ニフティでは, さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering
ニフティ株式会社でマネージャーをしている北浦です。 今回は私がマネジメントしている基幹システムグループ 課金システムチームのマネジメントについて紹介します。とはいえ自身のマネジメント歴が浅い(2022年4月〜)ので、今回は僕たちのチームがどのようにスクラムを導入していったのかを書いてみたいと思います。 (0) スクラム導入前 2017年まで課金システムチームの前身のチームではウォータフォール開発を採用し、ほぼ全ての開発業務を外注していました。社員の業務は要件整理や社内外調整、プロジェクトマネジメントなどがメインであり、自ら開発を行うシーンはとても少なかったと思います。社内向けツールや運用作業の自動化などで開発を行うメンバーもいましたが、コードを一切書かないメンバーもいました。 また、属人化もかなり進行しておりシステムごとに人(社員&協力会社メンバー)が張り付いており、同じチーム内でも隣のシステムについては全く分からず手が出せない状況でした。 このような環境の中でチームメンバーが大きく変わっていきましたが、いざシステムを引き継いでみると多くの問題が発生しました。”ドキュメント化されていない業務仕様”、”ドキュメントがなくリポジトリ管理されていない謎のプログラムがプロダクション環境で動いている”、”ビジネス部門の担当者が不在”、”社員が仕様を把握しておらず協力会社メンバーしかわからない(そのメンバーは既にプロジェクトから離れている)”など、とても苦労しました。 このままではまずいということで、主に属人化の解消とエンジニアの技術力向上を目指しスクラムを導入することにしました。 (1) 1チームスクラム: 1プロダクトを開発 2018年からスクラムを導入しました。既存プロダクトの全面刷新をスクラムで完全内製開発しました。ポイントは以下です。 スクラムマスター研修に参加してスクラム開発を学ぶことで導入時のハードルを下げた 比較的規模の小さい既存プロダクトを対象として全面刷新する方針とした ビジネス部門に相談してPO(プロダクトオーナー)を立ててもらった 職制上のチームを跨いでスクラムチームを構成、若手メンバーに多く参加してもらった ウォータフォール開発に慣れていたメンバーにとって、最初はスクラムガイドや書籍で勉強してもなかなかスクラム開発のイメージを掴むのは難しいので、一部メンバーがスクラムマスター研修に参加して学んできたことはスクラム導入がスムーズに進められた要因の一つだと感じています。 以降、各フェーズごとにKPT法でふりかえってみたいと思います。 良かったこと ビジネス部門とシステム部門が協力して”プロダクトを育てる”という意識が芽生えはじめた 小さく始めることで無理なく少しずつスクラムに慣れていくことができた 完全内製によるチーム開発の土台づくりができた 開発スキルを向上できた 改善したいこと 暫定で組んだスクラムチームだったので”チームの成長”をメンバーが意識しづらかった スクラムチームメンバーは職制上チームのタスクも継続して担当していたため、スクラムに注力できないメンバーが発生してしまった 初期リリース実施前に職制上チームのタスクが忙しいメンバーはスクラムチームから外れることになってしまった メンバーが職制上チームを跨ぐのでマネジメントが難しい トライ(実験) チームを跨ぐ状況を改善して職制上チームとスクラムチームを一致させる (2) 1チームスクラム: 複数スクラムを同時に実施 2019年からは職制上チームとスクラムチームのメンバーが一致するようチームを再編しました。また、別プロダクトでもスクラム開発したいものがでてきたので、新規にスクラムを立ち上げて複数のスクラムを同時に実施してみました。以下がそのふりかえりです。 良かったこと 新規にスクラムを開始したプロダクトはプロトタイプを小さくリリースしてPOから早期にフィードバックをもらうことで必要な機能を素早く提供できた 改善したいこと 同時期に複数のスクラムを1チームで実施することによるオーバーヘッドが想像以上に大きく、開発時間の確保が難しかった(スイッチングコスト、各種スクラムイベントなど) スクラム対象プロダクト以外にもチームが担当しているプロダクトがあるが、それに割り当てる時間がなくなってしまった トライ(実験) 全てのプロダクトを1つのスクラムで管理してみる (3) 1チームスクラム: 複数プロダクトを対象とした1つのスクラムを実施 1つのスクラムチームが複数のスクラムを同時に実施するのはかなり厳しいことがわかりましたので、2020年からは1つの職制上チームが担当する全てのシステム・サービス・プロダクトを1つのスクラムで管理してみることにしました。ただし、全ての関係者のスケジュールをあわせることが難しかったため、各プロダクトのPOと簡易スクラムイベントを個別設定することで対処しました。以下がそのふりかえりです。 良かったこと スクラムイベントのオーバーヘッドが削減できた 職制上チームが担当する全てのプロダクトに関するタスクが可視化され属人化解消に役立った 簡易スクラムイベントの導入によって各種イベント実施が効率化できた 改善したいこと プロダクトを跨ぐ優先順位付けが困難 社内システムへの要望やシステムリプレース対応のような技術的負債の改善につながる活動は、相対的に優先順位が常に低くなってしまう レガシーシステムに関するプロダクトバックログアイテムは認知負荷が高く多くのドメイン知識が必要となるため共有が進まない トライ(実験) チームが担当するプロダクトのPOを集めて、各プロダクトのスケジュール共有会を定期的に実施してみる (4) サブチーム同士が協力してスクラムを実施(検討中) 各プロダクトのPOを集めて実施するスケジュール共有会の実施により、事前にスケジュールのバッティングが確認できるようになり、早い段階で関係者と調整するなど対策が立てられるようになりました。 また、2021年には大規模スクラム(LeSS:Large-Scale Scrum)を採用し新規接続サービスの内製開発も行いました(こちらは別途ブログ化される予定です)。 2022年現在では、”複数プロダクトを扱う1チームスクラム”と”LeSS”の2つのスクラムを同時に実施しています。一般的にスクラムは”1つのチームは1つのスクラムに専念する”という大原則があるのですが、現実はなかなか難しい状況ですので現在の形となりました。2つのスクラムで可能であればスクラムイベントを共通化するなど、できる限り複数スクラムを実施することによるオーバーヘッドの最小化を目指しています。 現在は途中でもう1つサブチームが合流して2つのサブチームで課金システムチームとなったのですが、サブチーム間の協力がまだまだ弱いのでより良いチーム体制を模索しています。 チームにどのようにスクラムを導入していったのかを紹介させていただきました。”スクラムは理解するのは簡単だけど実践するのは難しい”と言われています。上記の内容がどこかのチームの参考になれば幸いです。 We are hiring! ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering
NIFTY Tech Talkは、ニフティ株式会社の社員が主催するトークイベントです。 本イベントではニフティ社員が業務を通じて学んだことを発信しています! 第三回目のテーマは「AWSコストダウン」。ニフティでは各チームコストとパフォーマンスの最適化を行っています。 ニフティが取り組んでいる「AWSコストダウン」について、現場のエンジニアを中心にパネルディスカッション形式でリアルな現場の声をお伝えします。 概要 日程:7月26日(火)19:00〜20:00 配信方法:YouTube Live 視聴環境:インターネット接続が可能なPC/スマートフォン 参加方法 Connpassイベントページ より参加申し込みください! こんな方におすすめ AWSのコストを下げたい方 コスト削減のベストプラクティスを知りたい方 組織でのコスト削減の取り組みに興味ある方 タイムテーブル 時間 コンテンツ 19:00-19:05 オープニング+会社紹介 19:05-19:15 登壇者紹介 19:15-19:55 メインディスカッション 19:55-20:00 クロージング ディスカッション テーマ 「AWSコストダウン」をメインテーマとして以下のような話題についてディスカッションします。 コストダウンの取り組みについて コスト意識醸成のための行ったこと 登壇者プロフィール 福田 紫穂(ファシリテータ) ニフティ株式会社 インフラシステムグループ クラウド・仮想化環境・ネットワークなどインフラ全般を担当。現在はハイブリッドクラウドのあるべき姿を検討中。 小松 初(登壇者) ニフティ株式会社 基幹システムグループ 新卒入社4年目。チーム内のクラウドコスト削減担当の一人として活動中。 河野 曜平(登壇者) ニフティ株式会社 インフラシステムグループ 新卒入社4年目。クラウドインフラ周りの整備をしています。最近はISUCONに夢中です。 深田 健太 (登壇者) ニフティ株式会社 会員システムグループ 新卒入社3年目。@nifty安心メールパックの開発・運用を担当しています。SAP勉強中。 ニフティでは一緒に働く仲間を募集中 ! 新卒採用、キャリア採用を実施しています。 ぜひ リクルートサイト をご覧ください。 ニフティエンジニアのTwitterアカウントを作りました NIFTY Tech Talkのことや、ニフティのエンジニアの活動を発信していきます。 https://twitter.com/NIFTYDevelopers
はじめに インフラシステムグループの河野です。 最近集計・分析系のクエリを書く機会が多くなっています。 その中でGROUPING SETSに出会って感動したのでこの気持を分かち合いたいと思います。 記事中ではクエリエンジンとしてpresto 0.217を使用しています。 GROUPING SETSとは GROUPING SETSはGROUP BY句に付与する構文で、複雑なGROUP BYを実現するときに使用できます。 具体例を見ていきましょう。例えば、以下のようなstockテーブルを考えます。店舗ごとにフルーツの在庫がいくつあるか、値段はいくらなのかをまとめたテーブルです。 SELECT * FROM ( VALUES ('orange', 1, 100, 51), ('lemon', 2, 50, 102), ('melon', 3, 1025, 23), ('banana', 1, 25, 154), ('orange', 2, 104, 105), ('lemon', 3, 55, 55) ) AS t (name, shop_id, price, qty) 商品ごとの合計を出しつつ、全体の合計も出したいときが来たとします。この場合GROUPING SETSを使わないとすると以下のようなクエリで実現できます。 SELECT name, SUM(price) AS total_price FROM stock GROUP BY name UNION ALL SELECT NULL, SUM(price) AS total_price FROM stock # 実行結果 name total_price 1359 banana 25 orange 204 melon 1025 lemon 105 これをGROUPING SETSで書き換えると以下のようになります。 SELECT name, SUM(price) AS total_price FROM stock GROUP BY GROUPING SETS((), name) # 実行結果 name total_price 1359 lemon 105 melon 1025 orange 204 banana 25 このように複数の基準でGROUP BYしなければならないものを、GROUPING SETSで一つにまとめることができます。 実務ではクラウドコストを集計してグラフ表示するときに非常に役に立ちました。クラウドベンダごとに別のグラフを描く。合計値も同時に描画したい。といった要件が出てきて、はじめは愚直にUNIONしていて、30行程度のクエリになっていました。その後prestoのリファレンスを見ていたらGROUPING SETSを見つけたので試しに書き換えてみたら、15行ほどにすっきりとクエリを書き替えることができました。 ROLLUP、CUBEとの関係性 GROUPING SETSと似た構文にROLLUPとCUBEがあります。ROLLUPでは小計、総計をまとめて取得することができます。CUBEではすべての組み合わせに対して総計を取得することができます。 それぞれ先程のstockテーブルに対して適用した結果を見てみましょう。 ROLLUP: SELECT name, shop_id, SUM(price) AS price, SUM(qty) AS qty FROM stock GROUP BY ROLLUP(name, shop_id) # 実行結果 name shop_id price qty 1359 490 banana 25 154 orange 204 156 orange 1 100 51 lemon 3 55 55 melon 1025 23 lemon 2 50 102 melon 3 1025 23 lemon 105 157 banana 1 25 154 orange 2 104 105 CUBE: SELECT name, shop_id, SUM(price) AS price, SUM(qty) AS qty FROM stock GROUP BY CUBE(name, shop_id) # 実行結果 name shop_id price qty 1359 490 banana 25 154 2 154 207 orange 1 100 51 melon 3 1025 23 lemon 3 55 55 melon 1025 23 1 125 205 orange 2 104 105 orange 204 156 lemon 2 50 102 banana 1 25 154 lemon 105 157 3 1080 78 これらをGROUPING SETSで書き換えると以下のようになります。 ROLLUP → GROUPING SETS: SELECT name, shop_id, SUM(price) AS price, SUM(qty) AS qty FROM stock GROUP BY GROUPING SETS((), name, (name, shop_id)) # 実行結果 name shop_id price qty 1359 490 banana 25 154 melon 1025 23 lemon 2 50 102 melon 3 1025 23 lemon 105 157 banana 1 25 154 orange 2 104 105 orange 204 156 orange 1 100 51 lemon 3 55 55 CUBE → GROUPING SETS: SELECT name, shop_id, SUM(price) AS price, SUM(qty) AS qty FROM stock GROUP BY GROUPING SETS((), name, shop_id, (name, shop_id)) # 実行結果 name shop_id price qty 1359 490 banana 25 154 2 154 207 orange 1 100 51 melon 3 1025 23 lemon 3 55 55 lemon 105 157 3 1080 78 orange 204 156 lemon 2 50 102 banana 1 25 154 melon 1025 23 1 125 205 orange 2 104 105 それぞれの差分だけ見るとどういう動きをしているかわかりやすいと思います。 ROLLUP(name, shop_id) → GROUPING SETS((), name, (name, shop_id)) CUBE(name, shop_id) → GROUPING SETS((), name, shop_id, (name, shop_id)) 例えば、組み合わせが一個増えたときの対応はこうなります。ROLLUPでは一番左のカラムを基準としたときの組み合わせ、CUBEではすべての組み合わせをそれぞれグルーピングしています。 ROLLUP(name, shop_id, qty) → GROUPING SETS((), name, (name, shop_id), (name, shop_id, qty)) CUBE(name, shop_id, qty) → GROUPING SETS((), name, shop_id, qty, (name, shop_id), (name, qty), (shop_id, qty), (name, shop_id, qty)) GROUPING SETSで書くことで、どの組み合わせで集計しているのかがわかりやすくなるため、個人的にこの書き方が好みです。 終わりに 今回はGROUPING SETSについて使い方と、他の類似構文との関連性をまとめました。有効に使えるとクエリをすっきりとさせられるので機会があれば使ってみてください。 参考記事 https://prestodb.io/docs/0.217/sql/select.html We are hiring! ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering