TECH PLAY

ニフティ株式会社

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

500

はじめに こんにちは。宮永です。 最近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で ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 25日目の記事です。 概要・はじめに 開場! 共通セッション ニフティの過去・現在・未来 KDDI共同講演:@￰niftyメール基盤移行プロジェクト 生成AIが切り拓く未来〜AWSにおける機械学習と自然言語処理〜 職種と企業を飛び越えたNTT Comとの新規ビジネス共創 Expert Tech Talk!〜ニフティスペシャリスト対談〜 2レーン開催セッション ポイントサービス設計の異常な挑戦 または我々は如何にして心配するのを止めてドメイン駆動設計を愛するようになったか ニフティ社内ISUCON開催への道のり ニフティLT大会大公開スペシャル クロージング セッション終了後 抽選会 懇親会 まとめ 概要・はじめに こんにちは。NIFTY Tech Day 2023 実行委員の西根です! 11/18(土)に初のハイブリッド開催でテックカンファレンス「NIFTY Tech Day 2023」を開催しました! ご参加いただきありがとうございました。 今年は会場とオンラインのハイブリッドで開催し、配信も一部2レーンで行うという初めての試みでしたが、無事大きな問題もなく終了することができました! NIFTY Tech Day 2023 では、ニフティのいまと未来をお伝えするセッションを15個ご用意いたしました! この記事では実施されたセッションの様子や裏話をお届けします アーカイブ動画の再生リストは こちら 発表資料は こちら 開場! 9:30から受付を開始しました! 続々と参加者の方も来てくださり、運営的にはホッと一安心でした(笑) 受付の様子です!ノベルティや名札をお渡ししました! 受付では、オリジナルのトートバッグに来場特典のノベルティを入れてお渡ししました! 今回のノベルティ内容は、NIFTY Tech Book #1・クリアファイル・パンフレット・ステッカー・ニフティラベルのお水と豪華内容!!! NIFTY Tech Book #1 は オンラインでも配布 されていますので、ご興味のある方はぜひご一読を! ノベルティが入っているトートバッグ。 こうして揃えると、イベントやってるんだなという気持ちになりました…! 可愛い女性のイラストが描かれた NIFTY Tech Book #1 です NIFTY Tech Book #1 の執筆の経緯などは こちら から確認いただけます! 今年は会場参加の方もいらっしゃるということで、前日までにconnpassにて参加登録をしてくださった来場者の方には、connpassの名前とアイコンを記載したオリジナルの名札をお渡ししました。 実はこの名札は前日に印刷所へ駆け込んで作成しました 共通セッション ニフティの過去・現在・未来 開場して最初のセッションは弊社代表取締役社長の前島による「ニフティの過去・現在・未来」です! 社員にも大人気の社史講話を拡張し、ニフティの創業期から現在、これからの展望を社長直々にお話しました。 現在計画中のプロジェクト の初公開の場でもありました! パネルでイベントらしい雰囲気に 朝一番のセッションですが、会場には参加者がたくさん!新プロジェクトのお話には驚きと喜びの声がXでも上がっていました! KDDI共同講演:@￰niftyメール基盤移行プロジェクト 続いて、KDDI株式会社 プラットフォームエンジニアリング部 足立様と弊社メール基盤移行チームマネージャーによる「KDDI共同講演:@￰niftyメール基盤移行プロジェクト」です! ニフティは今年@￰niftyメールの基盤移行を行いました。 その背景や、それぞれのメールシステムについての発表と、裏話や苦労について対談形式で語られています 大規模な基盤移行を終えたお二方は、まさに苦楽を共にした戦友のようでした! 登壇者は黒いTシャツでした! 生成AIが切り拓く未来〜AWSにおける機械学習と自然言語処理〜 午前中ラストのセッションは、アマゾンウェブサービスジャパン合同会社 ソリューションアーキテクト 馬様、シニアソリューションアーキテクト 石見様の2名と弊社 N1! Machine Learning Product Engineerの3名によるディスカッション「生成AIが切り拓く未来〜AWSにおける機械学習と自然言語処理〜」です! 前半はニフティニュースの記事要約について2022年までと2023年の比較を行い、AWS様からはAWSの生成系AIの開発・運用支援ができるサービスなどについてお話がありました 後半は3人のディスカッションパートでした! ニフティでも様々なサービスでAWSを利用しています! 職種と企業を飛び越えたNTT Comとの新規ビジネス共創 午後イチのセッションは、NTTコミュニケーションズ株式会社 ビジネスソリューション本部 浅川様と山下様、ニフティ N1! スクラムエバンジェリストと基幹システム バックエンドエンジニアの4名による、共創をテーマにした「職種と企業を飛び越えたNTT Comとの新規ビジネス共創」です! 昨年から新たに取り組んでいる共創プロジェクトの取り組みや、エンジニアとビジネス視点についてのLTを行いました! ベンダーとしてではなく、1つのチームとしてプロジェクトに取り組む4名が振り返りや苦労話を特別に公開しました。こちらのセッションはエンジニアだけでなく、ビジネスサイドの方でもわかりやすいと思われる内容でした 登壇中も楽しそうな雰囲気でした! Expert Tech Talk!〜ニフティスペシャリスト対談〜 ニフティには N1!というスペシャリスト制度 があります。 データサイエンス、スクラム、オートメーション、ID基盤のスペシャリストが一堂に会して、どんな制度なのか?どんな活動をしているのか?といった、普段あまり社外に出ない内容についてお届けしました! 今後のビジョンについては私も聞いていてワクワクする内容でした! 司会もN1!という豪華セッションでした! 皆さん良い笑顔ですね 2レーン開催セッション ここからは会場を2つに分けての開催になります。 開催されたセッションの中からアンケートで人気だった3セッションをご紹介します ポイントサービス設計の異常な挑戦 または我々は如何にして心配するのを止めてドメイン駆動設計を愛するようになったか ドメイン駆動設計 x 実際の事例 といった、実用性がある内容のセッションでした! 理想と現実のお話など、ドメイン駆動設計に挑戦したことがある方ならつい共感してしまうような内容がたくさんありました ニフティポイントクラブの開発・運用を担当しているエンジニアによる裏話です ニフティ社内ISUCON開催への道のり 2023年8月に社内で行われた ニフティ社内ISUCON の運営メンバーによる、200台もの大量のEC2インスタンスを立ち上げるために工夫したこと、悩んだことと、その解決策についての発表を行いました! ※「ISUCON」は、LINEヤフー株式会社の商標または登録商標です。 https://isucon.net 社内ブカツであるニフティISUCON部にも所属しているエンジニアが登壇しました ニフティLT大会大公開スペシャル まず始めは「 VRの世界でLTしていく 」です。 社内のLT大会でもVRで登壇していましたが、ついに目の前でVRゴーグル姿を見ることができました VRゴーグルがあると人の視線が気にならなくて気が楽だったそうです!配信で見ていた方は素顔が気になっていたかもしれませんね 2番手はニフティライフスタイル株式会社のバックエンドエンジニアによる「 コードを読みやすくしよう!〜秒で身に付くよい命名〜 」です! こちらはすぐに実用できそうな良い命名を身に着ける方法がぎゅっと詰まったLTでした コードを書く時間より、読んでいる時間の方が遥かに多い、沁みる言葉です… お次は新入社員による「 朝起こしてくれるメイドさんがほしい 」です! 朝起こしてくれるメイドさん、皆さんも欲しいですよね?欲しいなら作ればよいのです… メイドさんへのこだわりを話しているみたいですね さらに「 ニフティ開発インターンで使うAWS環境をできるだけ楽に構築した話 」です! こちらは開発インターンでのAWS環境の構築についてです!手作業でやりたくない様々な面倒なことを解決したお話でした 7分で資料を作成してしまった…と冒頭でお話ししていましたが、1つのセッションとして成立しそうなほどモリモリな内容でした LT大会のトリを飾るのはニフティライフスタイル株式会社のモバイルアプリエンジニア!タイトルは「 文系出身・開発未経験エンジニアが入社から5年間で実践した学習法〜エンジニアの世界で圧倒的に成長するために〜 」です! 開発経験がほぼない文系学生からエンジニアとして自信を持てるようになるまでにやったことが語られており、新人エンジニア必見の内容でした 輝けるもの、見つけていきたいですね クロージング 全てのセッションが終わり、システム統括部 統括部長である最上によるクロージング映像でNIFTY Tech Day 2023 は幕を閉じました! かなりの長丁場でしたが、朝からずっといてくださった来場者の方もいらっしゃいました…!本当にありがとうございました セッション終了後 抽選会 セッションの会場は懇親会会場を兼ねていたので、一度受付へ移動していただき、抽選会を行いました! 当社社員おすすめの技術書が当たるということで、以下の5冊をプレゼントしました! 良いコード/悪いコードで学ぶ設計入門 ―保守しやすい 成長し続けるコードの書き方 プリンシプル オブ プログラミング3年目までに身につけたい一生役立つ101の原理原則 プロダクトマネージャーのしごと ―1日目から使える実践ガイド プログラマー脳 ~優れたプログラマーになるための認知科学に基づくアプローチ ノンデザイナーズ・デザインブック 抽選会にもたくさんの人が参加してくださいました!この間、運営は懇親会の準備に勤しんでいました 懇親会 お寿司やケータリング、お酒もあり、活気のある懇親会となりました スタッフもおいしいご飯ににこにこです まとめ ニフティとしては初めてのハイブリッド開催でのイベントで、対面形式のイベントを開催すること自体が久しぶりでしたが、無事終えることができました! 個人的な意見ですが、来年はもっとパワーアップさせて開催できたらいいな~と思っています また、今後も日頃の業務や取り組みについて発信していきますので、ぜひNIFTY Tech Talkなどにもご参加いただけると幸いです! ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 25日目の記事です。 メリークリスマス!!! こんにちは!メリークリスマス! ニフティグループアドベントカレンダー2023 も無事完走いたしました!! 読んでくださった皆様、書いてくださったニフティ社員の皆様のおかげです。 今年は去年よりも多くの記事を書いてもらいました! 良かったこと 記事公開通知や週次ブログランキングをSlackにポスト 記事を公開するだけでなく、それをSlackにポストすることで社員同士の交流が一層深まりました。 リアクションやコメントを通じて直接のフィードバックを得られ、記事に対する興味や感想が分かち合えたことは大きな収穫でした。 社内LT大会に登壇 アドベントカレンダー開始前に社内LT大会に登壇することで、参加の促進に繋げることができました。 LT大会に積極的に参加している社員はアウトプットすることにとても積極的だと思うので、 参加してくれたと思っています! ↓LT大会で使用した資料の一部 分報チャンネルで投稿したことを共有している人がいた ニフティでは、分報文化があります。個人の分報チャンネルにブログ書いた〜と共有している社員が割と多くいました! 社内で盛り上がってる感が出てていいなぁと思いました! 大変だったこと カレンダーに埋めてもらうこと カレンダーを社員の方々に埋めてもらうことが予想以上に大変でした。 作ってそのまま放置しても自然に埋まっていくわけではありませんでした。 枠自体は少しずつ埋まってきたのですが、少し足りないなぁと思っていました。 そこで、上長経由でこの記事を書いてほしいと依頼したり、先述のLT大会に登壇(これが意外と反響をもらえた)しアドベントカレンダーへの参加を促したりしました。 記事を書くこと 無事に開催されたアドベントカレンダーですが、 ブログ運用チームが積極的に書かないと、社員の皆さんは書いてくれないと考えていました。 なので、ブログ運用チームは積極的にアドベントカレンダーへ参加していました。 私自身も3つ登録していたのでなかなか大変でした。。。 根気でブログを3本とも書き切って、なんとか締め切りまで間に合わせることができました。 また、社員からも「そろそろ書かないと…」と悲痛の声がありました。。。 ですが、ブログ運用チームから、カレンダー当日には遅れても良いことを事前に知らせていました。 なので自分のペースで書いていただけたのではないかなと思います! おわりに 今年のアドベントカレンダーも盛り上がっててよかったと思います! ブログ運用チームではこれからもアドベントカレンダーのようなイベントを開催し、NIFTY engineeringを盛り上げていけたらと思います! ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 24日目の記事です。 はじめに こんにちは。会員システムグループの上原です。 みなさん、コーディングは好きでしょうか?私は業務ではGo, Python, TypeScript, プライベートでゴリゴリRustを書いていて毎日楽しいです。 さて、業務でコーディングしていると付きまとうのがコードレビューです。コードのどこを変えたのかGitHubが頑張って出してくれますが、見た目であったり動作はどう変わったのか?は頑張って自分で追ってやる必要があります。 テストコードを見れば仕様の変化はわかるようになっているのでは?というのはあるんですが、やっぱり自分で試しにAPIを叩いたりブラウザを動かしてみないと安心できません。 ただ、手動で動かして確かに意図した通りに動作が変わっているのか?を追いかけるのは面倒です。特にAPIが返すjsonを比較するのは大変です。 例としてSpotifyのアルバム情報を取得するAPIのレスポンス例と、その例を一部改変したレスポンスを載せています。ぱっと見何が変わったかわかりますか?一瞬でわかったあなたはすごいです。 {"album_type":"compilation","total_tracks":9,"available_markets":["CA","BR","IT"],"external_urls":{"spotify":"string"},"href":"string","id":"2up3OPMp9Tb4dAKM2erWXQ","images":[{"url":"https://i.scdn.co/image/ab67616d00001e02ff9ca10b55ce82ae553c8228","height":300,"width":300}],"name":"string","release_date":"1981-12","release_date_precision":"year","restrictions":{"reason":"market"},"type":"album","uri":"spotify:album:2up3OPMp9Tb4dAKM2erWXQ","artists":[{"external_urls":{"spotify":"string"},"href":"string","id":"string","name":"string","type":"artist","uri":"string"}],"tracks":{"href":"https://api.spotify.com/v1/me/shows?offset=0&limit=20","limit":20,"next":"https://api.spotify.com/v1/me/shows?offset=1&limit=1","offset":0,"previous":"https://api.spotify.com/v1/me/shows?offset=1&limit=1","total":4,"items":[{"artists":[{"external_urls":{"spotify":"string"},"href":"string","id":"string","name":"string","type":"artist","uri":"string"}],"available_markets":["string"],"disc_number":0,"duration_ms":0,"explicit":false,"external_urls":{"spotify":"string"},"href":"string","id":"string","is_playable":false,"linked_from":{"external_urls":{"spotify":"string"},"href":"string","id":"string","type":"string","uri":"string"},"restrictions":{"reason":"string"},"name":"string","preview_url":"string","track_number":0,"type":"string","uri":"string","is_local":false}]},"copyrights":[{"text":"string","type":"string"}],"external_ids":{"isrc":"string","ean":"string","upc":"string"},"genres":["Egg punk","Noise rock"],"label":"string","popularity":0} {"name":"string","popularity":0,"release_date":"1981-12","images":[{"url":"https://i.scdn.co/image/ab67616d00001e02ff9ca10b55ce82ae553c8228","width":300,"height":300}],"tracks":{"items":[{"is_playable":false,"duration_ms":0,"explicit":false,"is_local":false,"id":"string","external_urls":{"spotify":"string"},"track_number":0,"disc_number":0,"available_markets":["string"],"artists":[{"uri":"string","name":"string","href":"string","type":"artist","id":"string","external_urls":{"spotify":"string"}}],"preview_url":"string","restrictions":{"reason":"string"},"href":"string","linked_from":{"uri":"string","type":"string","id":"string","href":"string","external_urls":{"spotify":"string"}},"type":"string","name":"string","uri":"string"}],"limit":20,"next":"https://api.spotify.com/v1/me/shows?offset=1&limit=1","offset":0,"href":"https://api.spotify.com/v1/me/shows?offset=0&limit=20","previous":"https://api.spotify.com/v1/me/shows?offset=1&limit=1","total":4},"type":"album","uri":"spotify:album:2up3OPMp9Tb4dAKM2erWXQ","restrictions":{"reason":"market"},"id":"2up3OPMp9Tb4dAKM2erWXQ","album_type":"compilation","artists":[{"uri":"string","external_urls":{"spotify":"string"},"id":"string","href":"string","name":"string","type":"artist"}],"genres":["Egg punk","Noise rock","House Music"],"release_date_precision":"year","total_tracks":9,"label":"string","available_markets":["CA","BR","IT"],"external_ids":{"upc":"string","ean":"string","isrc":"string"},"copyrights":[{"type":"string","text":"string"}],"external_urls":{"spotify":"string"},"href":"string"} どうでしょうか?自分もいきなり出されたら自信がありません。 すぐにはわからない方が自分を含め大半だと思いますが、この記事を読むとすぐに違いがわかるようになります。 手始めにファイルを比べてみよう 今回はシェルを用いて違いを見つけてみます。 diffコマンドを用いて、まずはファイルの差分を見てみましょう。 AというファイルとBというファイルを比較するには以下のようにコマンドを実行すれば良いです。uオプションをつけておくとGitの差分ぽく表示されるのでさらにわかりやすくなります。 diff -u A B 実行してみると以下のように2ファイルの差分がわかりやすく表示されます。 diff -u a.txt b.txt --- a.txt 2023-12-22 10:43:55 +++ b.txt 2023-12-22 10:44:01 @@ -1 +1 @@ -hello world +hello rust コマンドの実行結果を比べてみる 今度はファイルではなくコマンドの実行結果を比較する場合を考えてみましょう。 実行結果をファイルに書き出す機能であるリダイレクトをご存知であれば、以下のようなコマンドを実行すれば良いかなという想像がつくと思います。 コマンド1 > result_a.txt コマンド2 > result_b.txt diff -u result_a.txt result_b.txt まずはリダイレクトでファイルに実行結果を書き出してやり、生成したファイルをdiffコマンドで比較するという感じです。試しに使うとこんな感じです。 $ date > a.txt $ date > b.txt $ ls a.txt b.txt $ diff -u a.txt b.txt --- a.txt 2023-12-22 10:49:34 +++ b.txt 2023-12-22 10:49:39 @@ -1 +1 @@ -金 12 22 10:49:34 JST 2023 +金 12 22 10:49:39 JST 2023 はい。無事日時の差分が出てきました。dateは現在日時を出力するだけのコマンドです。 とまぁやってみましたが、コマンドの実行結果を比較するためにわざわざファイルに書き出すのは面倒ですし、なにしろ謎のファイルが増えていきますよね。 ここで使えるのがプロセス置換という方法です。 プロセス置換は、bashでコマンドの出力を一時ファイルとして扱うための機能です。これにより、複数のコマンドの結果を比較したり、変数に代入したりすることが容易になります。 プロセス置換を使用すると上のコマンドが以下のようにワンライナーに書き直せます。 diff -u <(date) <(date) では実行してみましょう。 $ diff -u <(date) <(date) (何も表示されない) あれ?何も表示されないですね。あ、dateは現在日時を出すので、同時に実行すると差分が何も出なくなってしまうのでした。わざと1秒ずらして実行タイミングをずらしてみましょうか。 diff -u <(date) <(sleep 1 && date) --- /dev/fd/11 2023-12-22 10:58:05 +++ /dev/fd/13 2023-12-22 10:58:06 @@ -1 +1 @@ -金 12 22 10:58:05 JST 2023 +金 12 22 10:58:06 JST 2023 デモンストレーションのためsleepコマンドを挟む必要がありましたが、無事1回で実行結果の差分を表示させることができました。 このように本来は引数としてファイル名しか受け付けないコマンドであってもプロセス置換を用いることで、コマンドの実行結果を引数として渡すことが可能になります。 diff以外でもプロセス置換は使えるのですが、コマンドの実行結果を比較したい場合は以下のようなコマンドをイディオムとして覚えておきましょう。 diff -u <(コマンド1) <(コマンド2) <と(の間にスペースを入れると動かなくなるので注意です。 レビューでの使用例 APIのレスポンスがどう変わったかわかりやすくする 記事冒頭で話したAPIのjsonの比較方法について考えてみます。 まずはAPIを叩くにはcurlコマンドを使用すれば良いです。 curl example.com そのままだと進捗状況が画面に出てくるので-Sを入れて表示されないようにします。 curl -S example.com APIからはjsonが一行にまとめられて返却されることが多いため、jqコマンドに通して整形しましょう。ついでにSオプションでオブジェクトのキーでソートしておくと、捗ります。 curl -S example.com | jq -S "." 仕様変更によってリリースしたいAPI(ここでは仮にステージング環境としておく)のレスポンスをとるコマンドも作っておきましょう。 curl -S staging.example.com | jq -S "." さて、この二つのAPIを比較したい場合は、diffとプロセス置換を組み合わせると簡単に差分を取れます。 diff <(curl -S example.com | jq -S ".") <(curl -S staging.example.com | jq -S ".") 引数の順番はどちらでも良いのですが、1番目に変更前、2番目に変更後の内容を入れるようにすると差分がわかりやすくなります。 先ほど出てきたjsonが返ってくるサーバーを立てて、curlしてみると以下のような結果になります。 diff -u <(curl -S example.com | jq -S ".") <(curl -S staging.example.com | jq -S ".") --- /dev/fd/11 2023-12-22 13:33:26 +++ /dev/fd/13 2023-12-22 13:33:26 @@ -33,7 +33,8 @@ }, "genres": [ "Egg punk", - "Noise rock" + "Noise rock", + "House Music" ], "href": "string", "id": "2up3OPMp9Tb4dAKM2erWXQ", 誰が見てもHouse Musicがgenresの中に追加されているとわかるので、いい感じですね! ついでにこのコマンドをPRやissueのコメントに貼っておくと、レビュアーも自分も幸せになれると思います。 Amazon RDSのインスタンスの設定を比較する インスタンスを複製する際にちゃんと同じ設定になっているかなど気になったことはないでしょうか?そんな時は、インスタンス同士の設定を比較して、想定した通りの設定になっているか確認してみましょう。 AWSのコンソールを横に並べて、左右見て設定が同じかどうか確認すれば良さそうですが、項目数が多く確認漏れがありそうです。 そこで今回もdiffコマンド使って比較してみます。インスタンスの設定は以下のようにAWS CLIを使えば取得することができます。 aws rds describe-db-instances --db-instance-identifier database-1 --query 'DBInstances[0]' --output json --region ap-northeast-1 db-instance-identifierオプションにインスタンスの識別子を指定します。outputオプションにjsonを指定するとjsonで結果が返却されます。 返ってきたjsonを比較しやすくなるように、jqコマンドで整形してやります。jqでjsonのキーをソートしないと順番がバラバラで見にくくなるので気をつけてください。以下のような感じです。 aws rds describe-db-instances --db-instance-identifier database-1 --query 'DBInstances[0]' --output json --region ap-northeast-1 | jq -S "." データベースの情報をとるコマンドは組み立てられたので、あとはいつも通りdiffコマンドとプロセス置換に突っ込んでやりましょう。 diff -u <(aws rds describe-db-instances --db-instance-identifier database-1 --query 'DBInstances[0]' --output json --region ap-northeast-1 | jq -S '.') <(aws rds describe-db-instances --db-instance-identifier database-2 --query 'DBInstances[0]' --output json --region ap-northeast-1 | jq -S '.') 実行してみると以下のようになります。 --- /dev/fd/63 2023-12-22 04:20:42.250700418 +0000 +++ /dev/fd/62 2023-12-22 04:20:42.250700418 +0000 @@ -4,7 +4,7 @@ "AssociatedRoles": [], "AutoMinorVersionUpgrade": true, "AvailabilityZone": "ap-northeast-1d", - "BackupRetentionPeriod": 7, + "BackupRetentionPeriod": 1, "BackupTarget": "region", "CACertificateIdentifier": "***********", "CertificateDetails": { @@ -13,9 +13,9 @@ }, "CopyTagsToSnapshot": true, "CustomerOwnedIpEnabled": false, - "DBInstanceArn": "arn:aws:rds:ap-northeast-1:************:db:database-1", + "DBInstanceArn": "arn:aws:rds:ap-northeast-1:************:db:database-2", "DBInstanceClass": "db.t3.micro", - "DBInstanceIdentifier": "database-1", + "DBInstanceIdentifier": "database-2", "DBInstanceStatus": "available", "DBParameterGroups": [ { @@ -57,28 +57,26 @@ "VpcId": "vpc-*****************" }, "DbInstancePort": 0, - "DbiResourceId": "db-**************************", + "DbiResourceId": "db-**************************", "DedicatedLogVolume": false, "DeletionProtection": false, "DomainMemberships": [], "Endpoint": { - "Address": "database-1.************.ap-northeast-1.rds.amazonaws.com", + "Address": "database-2.************.ap-northeast-1.rds.amazonaws.com", "HostedZoneId": "Z24O6O9L7SGTNB", "Port": 5432 }, "Engine": "postgres", "EngineVersion": "15.4", - "EnhancedMonitoringResourceArn": "arn:aws:logs:ap-northeast-1:************:log-group:RDSOSMetrics:log-stream:*****************************", "IAMDatabaseAuthenticationEnabled": false, - "InstanceCreateTime": "2023-12-22T02:57:01.355000+00:00", - "Iops": 3000, + "InstanceCreateTime": "2023-12-22T02:59:15.979000+00:00", "IsStorageConfigUpgradeAvailable": false, "KmsKeyId": "arn:aws:kms:ap-northeast-1:************:key/************************************", - "LatestRestorableTime": "2023-12-22T04:14:32+00:00", + "LatestRestorableTime": "2023-12-22T04:14:34+00:00", "LicenseModel": "postgresql-license", "MasterUsername": "postgres", - "MonitoringInterval": 60, - "MonitoringRoleArn": "arn:aws:iam::************:role/rds-monitoring-role", + "MaxAllocatedStorage": 1000, + "MonitoringInterval": 0, "MultiAZ": false, "NetworkType": "IPV4", "OptionGroupMemberships": [ @@ -88,14 +86,16 @@ } ], "PendingModifiedValues": {}, - "PerformanceInsightsEnabled": false, - "PreferredBackupWindow": "18:51-19:21", - "PreferredMaintenanceWindow": "thu:14:38-thu:15:08", + "PerformanceInsightsEnabled": true, + "PerformanceInsightsKMSKeyId": "arn:aws:kms:ap-northeast-1:************:key/************************************", + "PerformanceInsightsRetentionPeriod": 7, + "PreferredBackupWindow": "18:47-19:17", + "PreferredMaintenanceWindow": "sat:15:00-sat:15:30", "PubliclyAccessible": false, "ReadReplicaDBInstanceIdentifiers": [], "StorageEncrypted": true, - "StorageThroughput": 125, - "StorageType": "gp3", + "StorageThroughput": 0, + "StorageType": "gp2", "TagList": [], "VpcSecurityGroups": [ { コンソールを頑張って確認しなくてもコマンドの実行結果を見て差分を見ることができるようになりました! ついでにこのコマンドをPRやissueのコメントに貼っておくと、レビュアーも自分も幸せになれると思います。(2回目) まとめ レビュー時、想定通りの動作になっているか細かい部分を血眼になって確認するのは大変です。 目で見て一つ一つ比較するしかないこともあるかもしれませんが、エンジニアなので可能な限り楽をできないか考えてみるのも時には大事です。 自分のためにも、またレビュアーのためにも短い時間で正しいことが確認できるような動作確認方法が何かを考えていきましょう。その際にこの記事が参考になれば幸いです。 明日は、@ike-chanさんの「AdventCalendarお疲れ様でした!ブログ」です。 お楽しみに! ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 23日目の記事です。 はじめに こんにちは。新卒1年目の終わりが近づいてきていることに怯えている西根です。 ニフティでは複数のチームでスクラム開発を採用しています! ジョブローテーションで配属されていたチームでもスクラム開発(厳密にいうとなんちゃってスクラム開発)を採用していました! 今回は、あるスプリントのレトロスペクティブでTRYとして挙がったデイリースクラムの改善に取り組んだ方法について紹介します。 この記事の対象読者 スクラムイベントの改善方法がわからない人 デイリースクラムを改善したい人 チケットの管理が難しいと感じている人 背景 チーム編成とプロダクト 私が所属していたチームは5人の先輩と、私を含めて2人のジョブローテーションの新人という編成でした。 そのチームが抱えているプロダクトは4つあり、そのうち1つのメインプロダクトについてスクラムで開発を行っているという状況でした。 メインプロダクトのみをスクラムで行っているとはいえ開発メンバーは同じなので、すべてのプロダクトをプランニング時に考慮し、デイリーでの進捗確認も行っていました。 当時のデイリースクラム TRYに改善が挙がった当時は9:45-10:00の15分間で以下の流れでデイリースクラムを行っていました。 チームメンバーがそれぞれ以下を報告する。その間画面共有をしてるファシリの人が、なんとなくGitHubのProjects(開発側のチケット)やNotionのチケット(事業側のチケット)を確認する。 前営業日に行ったタスク、参加したミーティング その日行うタスク、参加するミーティング ファシリがNotionチケット(事業側のチケット)の更新内容を確認する。 今日のアラート確認、運用作業の担当者を確認する。 共有事項や困っていることの相談を行う。 ですが、 個人の作業報告で時間を取られてしまい、肝心の相談や共有にあまり時間を割けていません でした。 また、15分を超えてしまうこともあり、デイリーの直後のミーティングに十分な時間が割けなくなってしまうこともありました。 課題 私は時間がかかりすぎてしまうのは以下が原因だと考えました。 誰が担当のタスクかを把握できていないのでファシリは誰に話を振れば良いかわからない(特にスプリントの前半) Projectsの今スプリントの中に半期継続の作業(改善タスクやモブプログラミング)や進展がなくなったタスクも含まれており、今スプリントのPBIがわかりづらい また、開発の進捗に影響がある課題だと感じていた以下についてもデイリーで解決できないかと考えていました。 slackで行っているレビュー依頼が流れてしまい、2日以上放置になってしまっていることがある 具体的な改善に向けて TRYに挙がったレトロスペクティブでは、 今スプリントの対応内容のストーリーごとに作業を報告する それ以外の作業があれば別途共有する ということになりましたが、実際にやってみると思うように進めることができませんでした。 slackの自分のtime(分報)チャンネルで悩んでいると、別のチームの先輩から見学しにくる?とお声がけをいただきました!(timeはこれがあるから最高ですよね) 改善までの道のり 自分が実際にデイリースクラムの改善までに踏んだ手順は以下の通りです。 見学先のチームへのアポ & 自分のチームへの説明 実際に見学 そもそもデイリースクラムとは何かを勉強 チームへの共有資料作成 チームへ共有し、実際にどう改善するか相談 1つ1つ細かく取り上げていきたいと思います。 1. 見学先のチームへのアポ & 自分のチームへの説明 timeでお声がけしていただいた先輩に行きたい旨を伝えたら、見学先のチームへの共有までしてくださっていました(本当にありがとうございます) 自分のチームとデイリーの時間帯がかぶっていたので、自分のチームには事前にデイリーで「他のチームの見学に行くのでデイリー欠席します」と伝えておきました! 2. 実際に見学 宣言通り見学に行きます。 最初に挨拶をした以外は基本的にそのチームのデイリーを見てメモして…という形で見学していました。 わからないことが出てきたらslackで聞く形を取らせていただきました!手厚いサポートがありがたいですね。 3. そもそもデイリースクラムとは何かを勉強 改善を行うにあたり、まずはデイリースクラムってそもそも何なの?という部分をスクラムガイドと、社内で行われていたスクラムガイド輪読会の資料から考えていきます。(関係ないですが、輪読会や勉強会の資料が自由に見れるとこういうときに助かったりしますよね) デイリースクラムの⽬的は、計画された今後の作業を調整しながら、スプリントゴールに対する進捗を検査し、必要に応じてスプリントバックログを適応させることである。 スクラムガイド 2020年11月 進捗共有の意味合いはありそうな気がしますね。 開発者は、デイリースクラムがスプリントゴールの進捗に焦点をあて、これからの1⽇の作業の実⾏可能な計画を作成する限り、必要な構造とやり⽅を選択できる。これは集中を⽣み出し、⾃⼰管理を促進する。 スクラムガイド 2020年11月 「実行可能な計画を作成する」ということは、どこまでやる!と決めるということですが、このチームではステークホルダーが多く、割り込み作業が少なくなかったため、ここを完璧に実行する必要はないと判断しました。 (開発者という集団として)「自己管理を促進する」ということは、極論開発者たちが自走していけるならば、デイリーのやり方自体に正解はないということだと解釈しました。 そうなってくると、自分のチームに合ったやり方を模索する必要が出てくることがよくわかりますね! 4. チームへの共有資料作成 見学時のメモは自分の思ったことと事実がごちゃごちゃになってしまっていたので、後から共有用にまとめなおしました。 共有用資料は以下のような構成にしました。 デイリースクラムが目指すべき姿について これは先ほど学んだ内容をそのまま共有しました。 デイリーがどういう役割でどうあるべきなのか、という部分について考えながら改善アクションを決定したいと考え、共有資料に含めました。 他のチームとの比較(違う / 同じ) 今回見学にいったチームは、扱うプロダクトが自分のチームと近いチームだったので、似ている部分もありました。 反対に全く違う部分もあったため、比較して共有しました。 自分が良いなと思った点 自分のチームで実現できるかや、課題を解決できるかに関わらず純粋に良いと感じたものを以下のようにまとめました! GitHub Projectsが整備されていて使いやすそう reviewやwaitingステータスがあるため、状況がわかりやすい Assigneesが登録されていることで担当者が一目でわかる 協力会社のタスクについても状況確認を行っている 私のチームでも協力会社にお願いしているタスクが存在するプロダクトがあり、そのプロダクトが属人化しがちで不透明であるということが数スプリント前にProblemとして挙がっていた スプリントのゴールがデイリーの進め方をまとめているslackチャンネルのcanvasに書かれている あまり今まで意識していなかったが、デイリーはスプリントゴールに対する進捗の確認なので、確認しやすいことは大切 レビュー依頼はslackのワークフローで行い、終わるまではチャンネルにピン止めしている デイリーですぐ確認できるのでレビュー依頼が流れてしまうことがない マネできそうな部分 良いと思った点から実行できそうなものと具体的なアクションを以下のようにまとめました。 全プロダクトがまとまったProjectsを作成する 既に上期計画の時に上がっていたが断念していた 今スプリント全体で一気に見れた方が時短&わかりやすい issueの管理方法 Assigneesを必ず登録する reviewやwaitingステータスを作成する PBIステータスを作成し、そのステータスにはPBIのissueのみ設定する レビュー依頼の管理方法 PRで管理するのが理想だが、GitHub移行できているのは一部のプロダクトのみなので、暫定対応でピン止めで対応する すでにピン止めが使われているし微妙かもしれない… 5.チームへ共有し、実際にどう改善するか相談 4でまとめた資料をチーム全員に共有しました。 その中でデイリーの進め方を決めたり、Projectsの運用を改めたりなどのアクションまで行いました。 共有したときに取り組んだこと まずはGitHub Projects自体の改善から行いました。 デイリーの時間でこれを見れば進め方が自ずとわかるものを目指し、以下の4点を変更しました。 Reviewステータスを追加 不要なビューの削除 今のスプリントの開発対象のissueが一目でわかるボードビューの作成 ワークフローを設定 プロダクトのリポジトリにissueがopenされたらProjectにissueを追加する issueがProjectに追加されたらstatusをTodoにする issueが再度openされたらstatusをIn Progressにする issueがcloseされたらstatusをDoneにする また、このProjectが活用できるように運用ルールを2つ新たに定めました。 スプリントプランニングで担当者が決まったらissueにAssigneesを登録する Assigneesが自分でステータスを動かす こうすることで、Projectを見るだけで進捗を確認し、各々が最大限スプリントゴールに向かって自律的に行動することができるようになりました。 デイリーの進め方 各プロダクトのProjectsを見ながらファシリが担当者に確認 想定より進んでいる、オンスケ、遅れているなどの進捗 必要なフォローなどがあれば調整 今日何をやるかもその時に共有する Reviewステータスのものについて漏れがないか確認する Notionチケットの確認 アラート確認、運用作業の担当者確認 共有事項、確認事項 まとめ 実際に他のチームのデイリーに参加するのはとっても勉強になりました! GitHubのProjectsはどんどん使いやすくなっている最中なので、リリースをチェックして便利に使っていきたいです。 ワークフローが非常に便利で複製することもできるので、複数Projectを1つのProjectにまとめることも簡単にできそうです! 今回は近しいチームのデイリーでしたが、全然違うプロダクトを扱っているチームのデイリーと比較しても面白い収穫がありそうだな~と思いました。 実際にデイリーもやりやすくなった(と思う)ので、見学に行って良かったです! timeでいろいろ言ってるとこういうチャンスをつかめるのでとても良いですね…すべての作業や疑問をtimeに吐き出していくことを推奨しています。 明日は、上原さんです。クリスマスイブの記事もお楽しみに ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 22日目の記事です。 はじめに こんにちは。最近はGitHub Copilot無しでコーディングしたくない ShibataRyusei です。 業務ではiOS/Androidアプリ「マイ ニフティ」の開発を行っており、iOS, Android, バックエンドなどほとんどの開発に携わっています。 (ちなみに弊チームではエンジニアを 募集中 です!) 個人では日々Flutterを使った開発を楽しんでいます。 かなり昔の話ですが今年の2月ごろにFlutterにコントリビュートしたのでメモとして残します。 今年のことは今年のうちにアウトプット… コントリビュートとは? 「コントリビュート」とは、日本語で「貢献する」という意味で、OSSに貢献することを指します。 コントリビュートするメリットとして、下の記事では「コントリビュートすることはやりがいがあり、…学習し、教え、経験を積むことができます」と述べています。 https://opensource.guide/ja/how-to-contribute/ コントリビュートというと、コードを書いてPull requestを出すイメージがありますが、コードの作成だけでなく、ドキュメントの作成やイシューの整理、カンファレンスの企画なども含まれるようです。 Flutterとは? 今回コントリビュートするFlutterを簡単に紹介します。 FlutterはGoogleが中心に開発しているOSSです。 Dartという言語のフレームワークであり、Dartのコード1つでマルチプラットフォーム(iOS, Android, Web, Windows, macOS, Linux)のネイティブアプリケーションを作ることができます。 実はFlutterはコントリビューターの多いOSSランキングでnext.jsを抑えて3位に入るような活発なOSSです。 https://octoverse.github.com/2022/state-of-open-source Flutterへのコントリビュートのしかた 今回はコードを書いてPull Request(PR)を出す方法をまとめます。 1. Flutterのルールを学ぶ まずはFlutterのコントリビュートに関するルールを学びます。 ここら辺は見ておくと良いと思います。 CONTRIBUTING.md CODE_OF_CONDUCT.md FlutterのWiki コントリビュート関連のページ(values, Issue-hygieneなど) 2. 環境構築をする ドキュメントに従って、Flutterのengineとframeworkの開発環境を構築します。 frameworkであればこれです。 https://github.com/flutter/flutter/wiki/Setting-up-the-Framework-development-environment 3. Issueを探す コントリビュートするためのIssueを見つけましょう。 Flutterには多くのIssueがあるため、自力で探すのは大変です。そのためラベルから絞り込んで探すのがおすすめです。 おすすめのIssueラベルは”good first issue”、”a:first hour”です。 昔は”easy fix”もあったけどいつの間にかなくなってる… 4. 実装をする Issueを決めたらコードを実装します。 GitHubにあるFlutterのレポジトリからforkして自分のレポジトリで作業をします。 5. Pull Requestを出す forkしたレポジトリからFlutterのレポジトリに対してPull Requestを出します。 Pull Requestを出す際、PRテンプレートのチェックボックスを確認しましょう。 6. Mergeされたら完了! Pull Requestがマージされたら、コントリビュートは完了です! 実際にやってみた まず、Issueを選択します。今回は、”a:first hour”のラベルがついている(2月には”easy fix”も付いてた)このIssueに取り組みました。 https://github.com/flutter/flutter/issues/115357 このIssueは、flutter createで使用するテンプレートのLintテストを追加する内容です。 実装を完了し、Pull Requestを提出しました。 https://github.com/flutter/flutter/pull/120526 FlutterではCIが整備されており、約30分間テストなどが実行されていました。 数日後レビューがきて何回か修正したらLGTMをもらいマージされました。 3.10.0のリリースノートにも載りました! Add lints test for all templates by @ShibataRyusei in 120526 @ShibataRyusei made their first contribution in 120526 https://docs.flutter.dev/release/release-notes/release-notes-3.10.0 終わりに コントリビュートは難しいイメージがありましたが、全然自分でもできるものが結構ありました。 そして実際にコントリビュートすることでFlutterコミュニティの活発さを感じました。Pull Requestのレビューも早いですし、放置されているIssueもあまりなかったです。 Issueを探しているとFlutter EngineのIssueはまだまだ難しいと感じます。既存コードのコードリーディングがまだまだ足りなかったり、C++, Skia, Metalなどの深い知識が必要だと感じました。 皆さんもぜひOSSに貢献していきましょう!! 明日の ニフティグループ Advent Calendar 2023 は@nishine829です。お楽しみに!! Flutter and the related logo are trademarks of Google LLC. We are not endorsed by or affiliated with Google LLC. ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 4日目の記事です。 ニフティ株式会社の仲上です。 私は以前Notionの作図機能についてまとめたことがあります。 私的Notion作図ベストプラクティス【2023年5月版】 – Qiita こちらの記事はあくまで個人利用を前提として書かれているため、会社で利用している状況とは若干異なります。また、時間が立ってNotion側の機能にもいくつか更新が入ったので、2023年12月版【会社利用編】ということでNotionの作図機能について紹介しようと思います。 5月からの変化 最初に2023年5月から現在(2023年12月)までの変更点についてまとめていきます。 Notionの更新内容は こちらのリリースノート にまとめられています。 この中で、作図機能に関係しそうなものをいくつかピックアップして紹介します。 コードブロックにコード整形機能が追加 September 22, 2023 – Notion 2.33: Automate workflows コードの整形をNotionの標準機能で行えるようになった mermaidのコードを整形できる figmaのデータをNotionDBに追加できるようになった Link previews & synced databases – Notion Help Center Figmaはブラウザベースで動くインターフェースデザインツール NotionDBに直接リンクできるようになったので、「画面のデザインを考える」といったチケットを作ったときの管理がしやすくなった インテグレーションギャラリーの追加 August 8, 2023 – Notion 2.32: new features for project management, AI, and more インテグレーションとは、Notionに他のサービスのアカウントを連携し、データの編集や作成などをシームレスに行える機能のこと miroやCanvas、Adobe XDなどのインテグレーションが追加さた miroについては、前回の記事で紹介 ( 私的Notion作図ベストプラクティス【2023年5月版】 – Qiita ) このページの最後で少しだけ紹介 Notion Q&A(ベータ)の追加 November 14, 2023 – Notion 2.35: Introducing Q&A by Notion AI (now in beta) 現状作図機能とはあまり関係ありませんが、Notion Q&A(ベータ)が追加されました。 生成系AIを応用して作らたツール チャット形式で情報を検索できる ワークスペースの情報を学習して解答を生成してくれること が最大の特徴 ベストプラクティス(会社版) ベストプラクティス 用途 ツール シーケンス図、ER図、フローチャート https://qiita.com/nahiro_tus/items/131514c49187c3eb08cd#mermaid グラフ https://www.google.com/intl/ja_jp/sheets/about/ その他の図 https://app.diagrams.net/ 前提条件 GWSを契約している 当社のルールで、データは原則Google Driveやローカル環境、準備されたサーバー以外にはアップロードしない メリットとデメリット メリット 追加料金が発生しない GWSのサービスをフルに活用できる データのグラフ化はGoogle Sheets 作図データの保存先はGoogle Drive デメリット 作図機能に不足を感じる時がある 各ツールの使い方 mermaid 前回の記事 参照 Google Sheets グラフの描画にはGoogle Sheetsを利用しています。 NotioinにはGoogle Sheetsにデータを同期する機能はないので、Google Apps Scriptを使って自前で実装しています。定期的にNotion APIを叩いて、データを取り出しています。 コードはGitHubに公開しています。 https://github.com/Nalagami/synch-notiondb-to-spreadsheet Diagram.net(旧 draw.io) 無料で使えるブラウザベースの作図ツールです。保存場所をクラウドストレージ(Google DriveやOneDrive、Dropboxなど)にすることで、複数人で編集できるようになります。 Notionへの連携方法は、主に以下の2つがあります。 Google Chromeの拡張機能を使う 以前はこれが最も手軽にNotionに図を埋め込める方法でした。 ただ、最近はDiagram.netで図を作成してから次の方法をでリンクを発行することが多いです。 埋め込みリンクを作成する方法 Diagram.netでNotion用の埋め込みリンクを作成し、それをNotionに埋め込む方法です。 編集するときオリジナルのデータを操作するか、編集者が作成した複製を編集するか選ぶことができます。オリジナルのデータを操作する場合は、編集者にNotionのアクセス権限とは別に保存先へのアクセス権限を付与してあげる必要があります。そのため、「Notionのアクセス権限はあるけど、Diagram.netのデータ保存先(Google Driveなど)にはアクセスできない」場合は編集も表示もできなくなります。(「複製を編集」を選んだ場合は閲覧も編集もできる) まとめ 自分が仕事で使っているNotionの作図機能についてまとめてみました。今回はあくまで当社のセキュリティルールに則った場合のベストプラクティスなので、会社のセキュリティ要件によっては若干変わってくることをご了承ください。 ぜひセキュリティ担当と相談して、理想のNotion環境を構築していってください。 (番外編)miroインテグレーションの使い心地 前回の記事で紹介したので、少し使ってみました。軽く触った感じだとあまり変わった感じはしなかったです。ただ、公式でmiroの埋め込みがサポートされるようになったのは大きいですね。 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 21日目の記事です。 この記事を読んで分かること ニフティの情シス(コーポレートエンジニア)の概況 スクラムとは何か(ざっくりと) 情シスでスクラムをやるにあたってどんな工夫をしているか  ニフティで情シス、スクラムマスターをやっている小浦です。人生で初めてクリスマスケーキを予約したので、今年はクリスマスがとっても楽しみです。豪快に1/4に切って大きいフォークでワシワシと食べる予定です。  さてさて、今日はスクラムの話をします。スクラムといっても開発チームではなく、運用メインの情シスでスクラムをどう工夫してやっているかについて話したいと思います。 ニフティの情シスとは?  名前に情シスの冠を持った組織はありますが、ニフティはエンジニア集団なので情シス的役割を果たしている人がその組織外にもいたりします。  私のチームはその冠をもった組織の中にあり、GWSやSlackなどのSaaSやオンプレのアプリケーションetcの管理運用を行っています。この記事では各SaaS、アプリを「プロダクト」と呼ぶとして、プロダクトを数えてみると24個ありました。 私のチームは情シスですが、スクラム体制を採用しています  情シスでスクラムを採用しているところはあまりないと思いますが、私のチームは約3年前からスクラム体制で活動しています。  スクラムとはチームが一丸となってプロダクトを迅速に良くしていくためのフレームワークです。スクラムでは、チームメンバーが スクラムマスター (スクラムチームをうまく機能させる人)、 プロダクトオーナー (プロダクトの未来を決め、願いを表現する人)、 開発メンバー (プロダクトオーナーの願いを実現する人)に分かれ、 スプリント と呼ばれる短い期間の中で決められたイベントを通してコミュニケーションをとりながら、そのスプリントにやるべきことだけに集中して開発とリリースを行い、それを繰り返していきます。  情シス的には次のようなメリットがあります。 目的意識を強く持ち続けることができる 突然の変更、変化に適応できる 業務共有が進み、属人化、スキルの偏りが解消される コミュニケーションの機会があらかじめ設定されているので、シャイな人が集まりやすい情シスチームでも交流が持てる などなど  複数のプロダクトを抱えていて、運用が多く、ウォーターフォール式でプロジェクトが進みがちな情シスにはあまり用いられていませんが、上記のようなメリットを享受するべく日々工夫してスクラムしています。  情シスでスクラムやっているよ、の触りについては以前のLT(下記)や、技術書典で頒布した「 ニフティのスクラム 」で紹介しているのでよろしければご覧ください。 ※当時プロダクトは14個でしたが、2023年の4月に別の情シスチームを吸収したことにより24個に増えました。開発メンバーも3名→9名に増え、スクラムチームとしてはかなり賑やかな体制になりました。 【本題】情シスでスクラムをやるにあたってどんな工夫をしているか  以前のLTや本記事の冒頭でも「情シスはスクラムに向いていない」と散々書いてきましたが、工夫したポイントについてすべて書きます。 プロダクト横断的に優先順位がわかるようにした 24個のプロダクトを1つの大きなプロダクトと見なし、スプリント内のタスク(※スクラムでは スプリントバックログアイテム といいます)を一元管理することでチーム全体で優先すべきタスクが分かるようになりました。 <そうした理由> スクラム前はプロダクトごとにタスクを管理しており、さらにプロダクトと人が属人的に結びついていたので「いまチームで最も重要なこと、急ぎで対応すべきことが何か分からない」「隣の人が忙しそうだけど手が出せない」状態で非効率的だったからです。 <実際にやったこと> すべてのタスクを スプリントバックログ と呼ばれる「このスプリントにやることリスト」に集め、重要なこと/急ぎで対応することに重みづけを行い、スプリントバックログアイテムを並べ替えて確認できるようにしました。 ▼スプリントバックログのイメージです。プロダクト関係なく、 Must (対応必須)、 Should (対応すべき)、 Could (できれば対応)で並んでいます。列は状態です。 プロダクト全体に通じるチームのビジョンを作成し、全員で同じ方向へ向かえるようにした チームビルディングを兼ねてビジョンを作成し、全員のありたい姿が一致するようにしました。 <そうした理由> 私のチームは出来た当初はいわば寄せ集めで、それぞれが目指す方向や考えていることがばらばらの状態でした。その状態を続ければ考えの違いでいつかは衝突するし、推進力も生まれないと思ったからです。 <実際にやったこと> 一つの方向に向かって進めるように、全員でありたい姿を持ち寄って言葉にまとめたチームビジョンを作成しました。 ▼ビジョンのブレストの様子 スクラムのルールで決められたイベント+αを通してコミュニケーションの機会を増やした コミュニケーションをとることによりお互いを知り、悩みやタスクをシェアできるようになりました。 <そうした理由> チーム発足時、ちょうどコロナ禍が始まったところでニフティもフルリモートワークになりました。フルリモートワークで属人的に仕事をしていると、チームの誰とも会話せず一日を終える…なんてこともありました。これでは属人化の解消もできず、チームで動いている意義もありません。 <実際にやったこと> スクラムには デイリースクラム (朝会)、 プランニング 、 レビュー 、 レトロスペクティブ といったコミュニケーションをとる機会を設けるルールがあります。これらの他に、雑談タイムや作業配信(運用などをおもむろに社内向けにライブする)なども行い会話できる機会を作っています。 特に属人化しているプロダクトについて共有会を行い、他の人でもタスクがこなせるようにした <そうした理由> 属・人・化…情シスあるあるだと思います。その人がいなくなると誰も分からない、そんな状況を打破したかったからです。 <実際にやったこと> 特に属人化が激しいプロダクトについて週次で共有会を開催し、業務共有を行ったうえでそのプロダクトの細分化されたタスク(スクラムでは スプリントバックログアイテム と言います)に対し「✕✕さん以外でもできる」というタグ付けを行いました。そのタグがついたスプリントバックログアイテムを✕✕さん以外がどれだけ消化したかについてスプリントの終わりに振り返りを行いました。 3年間情シスでスクラムをやって見えてきたこと  ここまで読んだ情シスの方は、きっと「大変そう」と思われたことでしょう。そう、スクラムはコストがかかる取り組みなのです。しかし3年間継続してみた結果、投資対効果でいうと効果の方が大きく上回ったと断言できます。もし、3年前にスクラムを始めていなかったらずっと寄せ集めチームのままで活動していたことでしょう。特に情シスは長く続いている組織が多く、ヒトも固定されていて新しい取り組みがしづらいケースが多いのではないかと思います。その現状を打破したい時に、スクラムのような型にはめるようなやり方は案外気楽ではないかと私は考えます。もちろんすべてを完璧にしてから始める必要はありません。まずは「スクラムっていう良さげなやり方があるんだって…」と、デイリースクラムから始めてみるのがおススメです。 まとめ+宣伝  今回はニフティの情シスと、私のチームで取り組んでいるスクラムについて工夫点に焦点を当ててご紹介しました。  体制が変わる前の文章になりますが、当時の開発メンバーがスクラムについてどう思っているかなどのコメントが載った本がありますのでぜひご覧ください。ニフティのスクラムマスターが寄稿しあって作った本なので、スクラムそのものに関心がある方もぜひダウンロードを!(無料です) ▼クリックするとダウンロード画面に飛びます  また、ニフティの情シスメンバーも大募集中ですのでご興味がありましたら 採用サイト をご覧ください。 明日の記事は…  明日の記事を書いてくれるShibataRyuseiさんは、実は1年目のエンジニアが全員体験するジョブローテーションという制度で3カ月間情シスにきてくれました。その後マイニフティチームに配属となり、すっかりチームの顔になったShibataさんの記事が楽しみです!
この記事は、 ニフティグループ Advent Calendar 2023  20日目の記事です。 はじめに こんにちは、IWSです。 Yotutubeで配信している NIFTY Tech Talk では運営の方からYoutubeの枠を作成してほしいという依頼を受けるときにNotionのデータベースを活用し、こういったタイトル、概要欄にしてほしいというのを書いてもらっています。その際、Zapierを使って作成依頼が来たことが分かるようにSlackに通知をしています。 今回はこの通知をどうやって作っているかを書いていこうかなと思います。 Zapierとは Notionのプロパティを読み取ってSlackに通知を行うのにZapierを使っています。 Zapier  は複数のサービスやアプリと連携するワークフローをノーコードで作成できるサービスです。今回扱うNotionやSlack以外にもGoogle Workspaceや、Githubなど様々なサービスとの連携が行なえます。 今回はZapierで簡単な以下の処理を作りたいと思います。 Notionのプロパティで「新規」が付いたら実行 タイトルとURLを取得してSlackのチャンネルにメッセージで送信 Zapier まずは、あらかじめNotionにデータベースを作っておきます。 今回はプロパティのステータスが「新規」になったときにSlack通知をしてもらうので、そのプロパティを作成しておきます。 では早速Zapierを触っていきましょう! Zapierのダッシュボードを開いて Create Zap を押すとZap(ワークフロー)の作成画面が開きます。 最初はTriggerとActionの2つが配置されていると思います。 まずはTriggerから「プロパティのステータスが【新規】になったとき」のトリガーを作っていきましょう。 Triggerを選択するとどのサービスをトリガーとして使用するかが選べるので中からNotionを選択します。そうするとNotionのどのイベントをトリガーに使うか選べるので「Update Database Item」を選択。 Account, Triggerの項目ではNotionのどのアカウント、ページをZapで使用するか選んでいきます。 Notionの自分のアカウントとの紐づけ画面に移動するので Choose → Connect a new account で画面に従っていきましょう。Zapierで使いたいページにチェックするのを忘れずに、うまく行っていればTriggerの項目で使いたいDBの名前が表示されていると思います。 ここまでできたら最後に Test から使いたいDBのアイテムが取れているかを確認しましょう。 ステータス:新規 に設定した オンライン勉強会#4 がばっちりとれていますね! ここで忘れずにZapier のトリガーに使いたい条件のアイテムを選択しておきましょう(今回はステータスが新規になっているもの)、後ほどテスト実行の際に使用します。もし作っていなければ右下のペンマークからテスト用のデータを作ることもできます。 Continue with selected record を押すと Change Action のメニューが表示され、次になにを行うかを選ぶことができます。今回はFilterを選びましょう。 Filterではどの条件のときにZapを実行するかを設定できます。 今回はステータスに「新規」が付いたら実行してほしいので以下のように設定しました。 AndやOrでより複雑な条件を指定することもできます。 設定ができたらContinueからフィルターのテストをしましょう!先程選んだテストデータを使いフィルターのテストを行うことができます。 テストデータにフィルターがマッチしたらOKです! フィルターが完成したらいよいよSlackへ通知を送信する部分を作成しましょう!Continueを押すとまたChange Actionが出るので一覧からSlackを選んで追加します。 どういうEventを発生させるかを聞かれるので今回はメッセージの送信ができる Send Channel Message を選びます。 AccountタブではNotionのときと同じ用に Connect a new account からリクエストを許可します。 Actionタブでは送信先のチャンネル、送信メッセージの内容などを設定できます。 メッセージにはNotionのURLやタイトルなども含めることができるので色々試してみてください。 使用できるフォーマットはこちらのページにまとめられています。 https://help.zapier.com/hc/en-us/articles/8496025607181 というわけでシンプルに自分へのメンションとページのタイトル、URLで作ってみました 今回は使用しませんが、他にもスレッドへの投稿、画像の添付、スケジュール投稿など細かい設定ができるので触ってみてください。 最後にきちんとSlackに届くかテストをしてみましょう どうですか?Slackにメッセージが届いたでしょうか? まとめ 今回はZapierでSlack、Notionの簡単なZapを作ってみました。Zapierは思いつき次第でもっと便利なものを作ることもできます。ぜひ一度Zapierを触ってみてください!この記事を読んでZapierに興味を持ってもらえればとてもうれしいです。 また、NIFTY engineering には他にも Zapierについての記事 が投稿されています。Zapierについてもっと知りたくなった方はぜひそちらもご覧ください! 明日の ニフティグループ Advent Calendar 2023 は @yCola さんです。お楽しみに! ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
インフラチームに所属しております松本と申します。 当社のお客様サポートセンター内の業務作業環境は、 情報漏洩やセキュリティ強化を考慮し、約15年前から タイトルにある環境を採用しております。 接続元機材は環境初期より、下記4点の特徴【コンセプト】 がある端末(筐体)を用いております。 1.記憶装置を搭載せず 2.単体で起動するOSでは業務遂行ができない 3.【画像転送型】シンクライアント方式に特化 4.端末ごとのキッティング作業が不要 また上記機材から接続する先は、時代とともに オンプレミス環境のBladePCから仮想デスクトップ、 そして現在はDaaSへと変化しております。 接続元機材や接続先環境自体は、H/WやHyperVisorの EOLもしくはEOSLごとにリプレースや見直しを行い、 事業継続を最優先に計画されますが、デスクトップOSの 寿命もこのリプレース計画に影響を与えます。 直近の当社は、これから約一年程度で以下対応を 順次進めるリプレース期間に突入します。 ※以下の丸数字と色は、イメージ図に対応しています。 ① 接続元機材更新(約7年ぶり要因はEOL)   ※【コンセプト】に変更なし ② 接続先環境更新(約5年ぶり要因は利用中DaaS提供終了)   ※約8年ぶりにオンプレミス+設計~構築も内製化   ※自社資産化による柔軟なスケール変更への対応   ※完全内製化による技術力の向上から、日々の安定した    運用・保守だけではなく、迅速な障害対処を目指す    ③ デスクトップOS更新(Windows10のEOLまでに)   ※無償期限:2025年10月14日   ※有償期限(ESU):2028年10月(無償期限から最長+3年間)   ※ESUとは「拡張セキュリティ更新プログラム」のことです ご興味がある方、一緒にリプレースしましょう。 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 18日目の記事です。 風邪を引いてアドベントカレンダー遅刻しました はじめに ニフティ株式会社新卒入社一年目の中井です。今日は皆さんに会社でも回せるガチャを実装する方法、もとい、SlackワークフローからGoogle Apps Scriptを実行する簡単な方法についてご紹介します! 早速ですが、皆さんは普段、Slackを使われていますか? ニフティでは、社員なら使わない日はないんじゃないかというほどSlackが利用されています。やっぱり単なるチャットツールとして以上に、Slackから様々なアクションを起こすことができる点が強いんですよね。そんな部分の一つの例として、今回は簡単に実行できるガチャを作ってみましょう。 ちなみにガチャというのは別に私がガチャを引きたかったわけではなくて、私自身は全然ソシャゲとか知らないので、単にガチャは楽しいよねという周囲の要望に応えただけであって、あくまでも技術的な探求のためにですね、はい。 なお、今回利用するSlackのワークフロー機能(を作成するワークフロービルダー)は有料プランでないと利用できないので、個人で試される場合はそこにご注意ください。とはいえ個人だと有料プラン高いですよねえ……。 SlackワークフローとGoogle Apps Scriptについてかんたんに Slackワークフロー とは、ざっくり言えばSlackの中のリンクなどから開始できる一連のアクションのことです。最近大きめのアップデートがあって、できることがかなり増えました。アクションには例えばメッセージを送信したり、チャンネルに招待したり、そしてGoogleスプレッドシートに書き込んだりということができます。 Google Apps Script とは、かんたんに言えばGoogleの基盤上で簡単なJavaScriptのスクリプトを動かすことができるというサービスです。このサービス、何がとんでもないかというと、まず1つは無料なこと、そしてもう1つは実行タイミングの設定が豊富なことです。例えばGoogleスプレッドシートに変更があった時に実行、のようなことができてしまうんですよね。 さて、なんとなくおわかりでしょうか? そう、Slackからガチャを回すとはこういうことです。 まずSlackワークフローからGoogleスプレッドシートに書き込む 書き込みに対する変更通知でGoogle Apps Scriptを発火する Google Apps Scriptさえ発火してしまえばこちらのもの。JavaScriptでなんでもできるので、ランダムに文字列を抽選して、結果をSlackのIncoming Webhook機能を通してチャンネルへ投稿するということが可能なわけですね。便利! スプレッドシートを作成する ところで、実はGoogle Apps Scriptにはざっくり2種類があります。 スクリプト単独で存在するもの スプレッドシートに結びついて存在するもの 今回は「スプレッドシートが変更されたときに発火されてほしい」ので、スプレッドシートに結びついて存在するスクリプトのほうが簡単です。すなわち我々のガチャづくりはスプレッドシートを作成するところから始まります。 おもむろに次のURLをタイプしましょう。 https://spreadsheets.new すると新規にスプレッドシートが作成され、白紙のスプレッドシートが立ち上がります。わからなくなる前に、左上のタイトル欄に適当に「ガチャ」とでも入れておきましょう。このスプレッドシートはあなたのGoogleドライブに自動保存されています。 さて、後々設定するSlackワークフローでは、スプレッドシートのシート全体を表と見立て、そこに行を追加するという形でスプレッドシートを編集することができます。そのために最低限、表として認識されるようにシートを修正します。 シート名をわかりやすく「実行履歴」に変更する。 シートの一番左上のセルに「実行者」と入力(最初の行は表のヘッダー行として扱われます)する。 これで1列の表ができました。実行されるたびに「実行者」の下にどんどんと行が増えていくイメージですね。もちろん、実行した時刻や内容など、列をもっと増やすこともできます。 さて、ここからGoogle Apps Scriptでガチャを作っていきます。 「拡張機能」→「Apps Script」を開いて、ガチャを引くコードを書いていきましょう。 一つの例ですが、ここでは次のようなコードを使ってみました。これは、いわゆるカタカナから3文字を抽出して単純に連結するというものです。もちろん他にも、もしかしたら0〜9の数字などにしてスロットっぽくするなどの応用もあるかもしれませんね。夢も膨らみます。 function gacha() { const KATAKANA = "アイウエオカキクケコサシスセソタチツテトナニヌネノ" + "ハヒフヘホマミムメモヤユヨラリルレロワン" + "ガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポァィゥェォッャュョヴー"; const pick = () => { return KATAKANA[Math.floor(Math.random() * KATAKANA.length)]; }; const word = pick() + pick() + pick(); console.log(word); } そしてプロジェクトを保存した上で実行ボタンを押すと… この通り、下部の「実行ログ」の部分に、カタカナ3文字が適当に表示されたのがわかると思います。コードは上手く動いていそうですね。 次は、これをSlackのIncoming Webhookを使ってSlackに投稿する部分を作っていきます。 SlackのIncoming Webhookをつくる Slackの Incoming Webhook とは、外から特定のURLにアクセスすることにより、予め指定したチャンネルにメッセージを送信することができる魔法です。このURLを用意するためには、まず「アプリ」を作成して、そのアプリでIncoming Webhookの機能を有効化するというステップが必要です。しかし、これをGUIでやるとなかなか大変になります。主に説明が。 そこで、その辺を簡単に作れちゃうURLを生成しておきましたので、ぜひ使ってください。 https://api.slack.com/apps?new_app=1&manifest_json=… ちなみにこのURLにアクセスすると、次のようなApp Manifestを持ったアプリを一つ新規に作成することになります。ざっくりと説明すると、Incoming Webhookを一つ、そしてそれを利用するために必要なBot情報を一つ追加しています。 { "display_information": { "name": "gacha" }, "features": { "bot_user": { "display_name": "gacha", "always_online": false } }, "oauth_config": { "scopes": { "bot": [ "incoming-webhook" ] } }, "settings": { "org_deploy_enabled": false, "socket_mode_enabled": false, "token_rotation_enabled": false } } 何はともあれ、とりあえず先のURLをクリックすればいいんです。画面の指示に従ってどんどん進めちゃってください! アプリをインストールするワークスペースを指定する。 色々進んだ後、吹き出しなどで誘導してくれるボタンに従って、アプリのインストール先のワークスペースを指定する(上と同じでOK)。 ここまで終わると、もうすでにIncoming Webhookの作成は完了しています。URLを確認しにいきましょう。 画面左側から「Basic Information」へ進む。 「Add features and functionality」をクリックして開く。 中に並んでいるボタンたちのうち「Incoming Webhooks」を選ぶ。 ページの下方にURLが表示されている。 URLの横に「Copy」ボタンがあると思いますので、URLをコピーしておいてください。 Incoming WebhookのURLをGoogle Apps Scriptのプロパティに設定する 先のURLをGoogle Apps Scriptの スクリプトプロパティ という機能に登録していきます。 一応、理屈としてはとにかくURLが叩ければよいわけですから、別に直接文字列としてソースコードに貼り付けても問題はないです。ただ、なにかできちゃう秘密の文字列を直接コードに貼るのはうっかりGitHubで流出みたいなことになりかねないのでやめておいたほうがいいな、と個人的には思います。 まず、Slackの設定からGoogle Apps Scriptの画面に戻りましょう。そして左側のバーから「プロジェクトの設定」を開き、スクリプトプロパティを追加します。INCOMING_WEBHOOK_URLという名前のプロパティで、値には先程コピーしたURLを入れ、「スクリプトプロパティを保存」を選択してください。 これで、Google Apps Scriptのコード側からはINCOMING_WEBHOOK_URLという名前のプロパティを問い合わせるだけでURLを取得することができるようになりました! 先程のコードをもう少し書き換えて、Slackに送るコードを追記します。 function gacha() { const KATAKANA = "アイウエオカキクケコサシスセソタチツテトナニヌネノ" + "ハヒフヘホマミムメモヤユヨラリルレロワン" + "ガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポァィゥェォッャュョヴー"; const pick = () => { return KATAKANA[Math.floor(Math.random() * KATAKANA.length)]; }; const word = pick() + pick() + pick(); console.log(word); const incoming_webhook_url = PropertiesService .getScriptProperties() .getProperty("INCOMING_WEBHOOK_URL"); UrlFetchApp.fetch(incoming_webhook_url, { "method": "post", "contentType": "application/json", "payload": JSON.stringify({"text": word}), }); } このコードを初めて実行すると、アクセス権限を要求されるかもしれません。これはUrlFetchAppという外部APIを叩くライブラリを利用するためです。 きちんと承認すれば、Incoming Webhookを設定したチャンネルにメッセージが届くはずです。 コード部分はこれで完成。残りはこれをSlackワークフローから呼び出せるようにするだけですね! スプレッドシート変更時に実行する Slackワークフローとの連携はスプレッドシートの変更イベントで行いますので、Google Apps Scriptにそのトリガーを設定します。左のメニューから「トリガー」を選択し、次のような設定でトリガーを追加してください。 注意点は、イベントの種類で「変更時」を選ぶことです 。ややこしいことに「イベントの種類を選択」の部分には「編集時」と「変更時」の二つがありますが、「編集時」はどうも人間が編集した場合のトリガーで、今回のようにSlackワークフローから自動で連携されるケースではトリガーされないようでした。 保存するとまた承認ダイアログが現れます。スプレッドシートを起点にしたことでスプレッドシートへのアクセスが要求されていますので、ここは承認して次へ進みましょう。 設定できたらスプレッドシートへ戻り、何でも良いので適当な変更を加えてみてください。A2セルに適当な文字を打ってみるとか。しばらく待って、Slackへガチャ結果が通知されたら問題なく動作しています! Slackワークフローからスプレッドシートへ書き込む いよいよ最後のステップです。SlackのWFを作りましょう。 左上のワークスペース名をクリックし、「ツールと設定」→「ワークフロービルダー」を選択します。この選択肢は、有料プランに入っていないと現れないかもしれません。 開いた画面の右上の「ワークフローを作成する」を押し、ついで「Slack内のリンクから」として進んでいきます。右側のステップ欄でsheetsなどと検索して、「スプレッドシートに追加する」を選んでください。 現れたフォームで、先程までに準備したシートを指定します。これで保存です。 最後にWFの公開を行います。これは別に全世界に大公開ということではなく、WFの編集が終わったからワークスペースで使用可能な状態にするよ、くらいの意味です。 公開ボタンから画面の指示に従って適当な説明を付ける。 必要ならコラボレーターを追加して「公開」にすすむ。 最後のフォームでリンクをコピーする。 最後にコピーしたリンクはもう準備万端で、踏めばガチャが引けるようになっています!次に進みましょう。 Slackで実行してみる チャンネルに貼ってみると、こんな感じの枠がでます。そして枠をクリックすると… いい感じですね!! このリンクはどこにあっても良いので、チャンネルにピン止めするでも、ブックマークバー的なところに登録するでも、お好きなところにどうぞ。 まとめ 今回はSlackワークフローからスプレッドシートの変更通知を通してGoogle Apps Scriptを実行する例を実装してみました。今回はガチャのために使いましたが、このスプレッドシートの変更通知を利用するという方針は、Zapierなど他のスプレッドシートと連携するツールへもすぐに応用できます。また、今回はSlackが外部API呼び出しに対応していないために回りくどい手法を取りましたが、元々Google Apps ScriptにはGETリクエストでスクリプトを実行するなどの、さらに便利な機能もあります。これからも色々できることを探求していきたいです。…ガチャの探求ではないですよ? ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 18日目の記事です。 こんにちは。会員システムグループでエンジニアをしている山田です。 前回 はDocker Composeを利用し、コンテナ上でアプリケーションを実行する環境を整えました。今回はコーディングまでを含めた開発環境を整えていきます。 コンテナ環境の課題 コンテナという独立した環境を用意したので、コーディング作業もコンテナ内で行いたいところです。LinterやFormatterなどのツールもコンテナ内で完結させることにより、統一された開発環境をチームメンバー全員に提供できます。 一方でコンテナ環境は基本的にCUI環境です。GUIアプリケーションを利用する方法がなくはないですが、ローカルPC側・コンテナ側とも設定が煩雑になるため、基本的にCUIアプリケーションを利用することになります。こうなるとVSCodeなどのリッチなIDEを利用できません。 Dev Containers 前述の問題を解決するのがDev Containersです。 これは元々「VSCode Remote – Container」と呼ばれるVSCode拡張機能だったもので、現在ではコア部分がVSCodeとは独立した OSS になっています。最近ではIntelliJなどでも 使えるようになっている ようです。 仕組みとしては以下のようになっています。前回のモノレポ構成にDev Containersを追加した図です。 コンテナ作成時にVSCodeを追加インストールし、 VSCodeごとコンテナ内で動かします 。ローカルPC側のVSCodeはコンテナ内のVSCodeと通信し、画面描画のみを担当することになります。エディタ自体がサーバ・クライアント構成をとることで、コンテナ内で開発環境を完結させつつ、リッチなエディタを利用することができます。 設定方法 今回はVSCodeでの設定方法を紹介します。設定方法はDockerfileを利用する方法と、Docker Composeを利用する方法の2種類がありますが、後者の方が柔軟なのでこちらで解説を行います。 VSCode拡張機能のインストール VSCodeをインストールし、 Dev Containers拡張機能 をインストールしておきます。 Docker Composeの用意 前回用意したようなDocker Composeの定義ファイルを用意しておきます。単一のcompose.ymlでも、統合機能を利用したcompose.yml + compose-dev.ymlのような複数ファイル構成でも、どちらでも可能です。 設定ファイルの用意 設定ファイルは . devcontainer / ディレクトリに配置するので、このディレクトリを作ります。これはコンテナごとに用意することになります。 ポリレポであれば repository/ - .devcontainer/ - compose-devcontainer.yml - devcontainer.json - src/ - compose.yml のような構成になりますが、モノレポであれば repository/ - frontend/ - .devcontainer/ - compose-devcontainer.yml - devcontainer.json - src/ - backend/ - .devcontainer/ - compose-devcontainer.yml - devcontainer.json - src/ - compose.yml のように、各サブプロジェクトごとに用意することになります。 設定ファイルとしては以下の2つが必要です。 compose-devcontainer.yml 名前は何でも良いのですが、動作上書き用のDocker Compose定義ファイルを用意します。 # compose-devcontainer.yml services: <開発対象コンテナのservice名>: command: /bin/sh -c "while sleep 1000; do :; done" あらかじめ用意したcompose.ymlではアプリケーションが全て起動してしまうため、コーディング後の反映にコンテナ再起動が必要になってしまいます。これは面倒なので、commandの書き換えによって「ただ動き続けるだけ」のコンテナにしてしまい、アプリケーション実行は自力でコマンドを叩くようにします。 devcontainer.json Dev Containers特有の設定ファイルです。最低限必要なのは以下の設定になります。 { "name": "frontend", "dockerComposeFile": [ "../../compose.yml", "compose-devcontainer.yml" ], "service": "frontend", "workspaceFolder": "/usr/src/app", } name エディタ上での表示名 dockerComposeFile Docker Composeの定義ファイル . devcontainer ディレクトリからの相対パスで記述する 複数指定することで - f オプションと同じ動きになるので、最後に前述のcommand上書き用のファイルを指定する service 開発対象となるコンテナの、Docker Compose上でのservice名 workSpaceFolder コンテナ内で、VSCodeが開くディレクトリのパス compose.ymlでソースコードをマウントした先のパスになるはず 起動方法 VSCodeで 開発対象コンテナの プロジェクトルートディレクトリを開きます。 . devcontainer を置いたのと同階層です。 モノレポの場合は開くディレクトリを間違えやすいので注意してください。 repository/ <- ココじゃなくて - frontend/ <- ココ!!! - .devcontainer/ - backend/ - .devcontainer/ - compose.yml 開いたら、「Cmd+Shift+P (WindowsはCtrl+Shift+P)」でコマンドパレットを開き、「Reopen with Container」を実行します。 またはプロジェクトを開いた時点でダイアログが出るはずなので、こちらからでも同じ操作が可能です。 初回起動時はコンテナ起動に加えてVSCodeのインストールなどが走るので時間がかかります。無事起動すると左下が「Dev Container」または「開発コンテナー」になります。 アプリケーション実行 commandの書き換えによりアプリケーションの実行を止めているため、自力でアプリケーションの実行が必要になります。 VSCode内蔵のターミナルはコンテナ内に接続されているため、ここからアプリケーション起動コマンドを実行しましょう。 # Node.jsアプリケーションの場合 pnpm install pnpm dev コンテナの終了 VSCodeを閉じた時点でコンテナも同時に終了されます。 ただし閉じた後すぐに開きなおすと前のコンテナの終了が完了しておらず、ポート干渉などでコンテナ起動に失敗することがあります。慌てずにリトライしましょう。 コンテナ定義を変えた場合 Dev Containersは一度起動・停止した後は前回起動したコンテナを再利用しようとします。compose.ymlやDockerfile、devcontainer.jsonなどを書き換えた場合はコンテナ定義の再読み込みが必要です。 すでにDev Containersを開いた状態の場合、再読み込みはコマンドパレット(Cmd+Shift+P)から「Rebuild Container」を実行します。 開く前の場合はコマンドが「Rebuild and Reopen in Container」に変わります。 追加設定 VSCode拡張機能 Dev Containersで利用されるVSCodeはコンテナに新規インストールしたものなので、ローカルPC側のVSCodeでインストール済みの拡張機能は引き継がれません。 devcontainer . json にはエディタごとのカスタマイズ設定があり、ここに拡張機能を記載することでインストールすることが可能です。 { ... "customizations": { "vscode": { "extensions": [ "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "stylelint.vscode-stylelint" ] } } } ユーザ拡張機能設定 Vimキーバインドを使いたい、Copilotを使いたいなど、プロジェクトごとではなくユーザごとにインストールする拡張機能を変えたい場合があります。この場合は、VSCodeのユーザ設定に記述を加えます。ユーザ設定はmacであれば $ HOME / Library / Application Support / Code / User / settings . json にあるはずです。 { ... "dev.containers.defaultExtensions": [ "github.copilot" ] } defaultExtensionsに設定した拡張機能は、そのユーザが起動するDev Containers全てに追加されるようになります。上記例ではGithub Copilot拡張機能が追加されることになります。 VSCodeの設定 VSCodeのユーザ設定は引き継がれますが、チーム内で統一する設定はリポジトリ内で管理すると良いでしょう。これは通常のVSCodeと同じく、 . vscode / settings . json に記載します。 { "editor.formatOnSave": true, ... } なお拡張機能と同じくdevcontainer.jsonに書くことも可能ですが、設定の反映に「Rebuild Container」の実行が必要になってしまうため、あまりお勧めしません。 注意点 暗黙的なファイルコピー Dev Containersは起動時にコンテナ定義を書き換えてVSCodeをインストールするほか、以下のファイルをローカルPCからコピーします。 ~/.gitconfig ~/.ssh/* これはコンテナ内でもGit操作を行えるようにするための措置ですが、プロキシの設定やローカルPC上にしかないツールの指定を行っている場合、コンテナ内でのGit操作に失敗する場合があります。 このような場合、 devcontainer . json でコンテナ起動後のコマンドを指定できるので、該当箇所を消す処理を入れるようにしましょう。 { ... // postAttachCommandで、コンテナが起動してVSCodeにアタッチされた時の処理を指定できる // プロキシやテンプレートの削除、エディタ指定の上書きを実施 "postAttachCommand": "(git config --global --unset http.proxy || exit $(($? == 5 ? 0 : $?))) && (git config --global --unset commit.template || exit $(($? == 5 ? 0 : $?))) && git config --global core.editor vim" } モノレポ時のコンテナ切り替え モノレポ環境では以下の点に注意が必要です。 同時に複数のコンテナでDev Containersを起動することは不可能 Dev Containersの対象コンテナを切り替える場合、「Rebuild Container」の実行が必要 Dev ContainersはDocker Composeで起動したコンテナのうち、開発対象コンテナ1つだけにVSCodeをインストールします。複数同時にインストールするように作られてはいないので、複数コンテナ同時に開発を進めることはできません。必ず切り替えて使う必要があります。 またコンテナを切り替えた場合には既存コンテナをリセットし、VSCodeをインストールするコンテナを変える必要があります。このため、切り替え時に毎回「Rebuild Container」を実行する必要があります。忘れがちなので注意が必要です。 実際に使ってみて 最後に1年以上Docker ComposeとDev Containersによる開発を行ってみたメリット・デメリットをまとめてみます。 メリット 環境によって起こるエラーに悩まされなくなった メンバージョイン時の負担が少ない PC交換時にもすぐ開発を始められる DB接続状態での自動テストを考慮に入れられるようになった やはり環境の可搬性・再現性という面が大きいです。git cloneしてVSCodeを開くだけで環境が出来上がるので、細かくメンテしていた構築手順書が不要になりましたし、新メンバーが来ても「とりあえず動かしてみて!」ができるようになりました。CI上でもDocker Compose一発なのは変わらないので、テストの幅も広がっています。 デメリット Dockerを動かす分のオーバーヘッドがある Windowsだとファイル更新検知ができない 一方で性能面での問題はどうしてもあり、MacbookだとM1 mac以降は問題ないのですが、Intel macだと正直厳しいと感じる時が多かったです。Docker for mac特有のI/O性能問題で遅いと感じることもあります。 またDocker for Windows特有の問題として、ファイル更新(inotify)がWindows – コンテナ間で共有されないという問題があります。ホットリロードが効かなくなるなどの弊害があるため、Windowsユーザが多い環境では注意が必要です。 まとめ 以上2回にわたってコンテナによるローカル開発環境を作る話でした。 デメリットも挙げましたが、環境構築に迷わなくなる利点は大きく、周りのプロジェクトでもコンテナベースの開発環境が浸透していっています。私個人としてもHomebrewやasdfの使い方を忘れるくらいに利用しています。 本番でコンテナを使っていなくとも、ローカル開発環境だけでも十分にメリットはあるので、皆さんも導入してみてはいかがでしょうか。 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 17日目の記事です。 こんにちは。会員システムグループでエンジニアをしている山田です。 私が担当するシステムでは、コンテナベースでの開発環境を整えて開発を行っています。その内容を社内レポートにまとめたりしていたりもするのですが、プライベートでも確認したいという声が社内から挙がったので、出せる範囲で公開しようと思います。 内容が長いので2回に分けての記事となります。 コンテナで開発するモチベーション システム開発を行う際、ローカルPC上でコーディングを行い、それをなんらかの方法で本番環境にデプロイする、というのがよくあるフローかと思います。デプロイがCI/CDで自動化されているかいないか、などの違いはあれど、大きな流れとしては同じでしょう。 この際、ローカルPC上に直接開発環境をセットアップする場合には色々な問題がありました。 構築・起動が面倒 複数のツールのインストールが必要 アプリ本体の他に、別途DBの起動や初期化などを要する 人による環境差分 人による手順違い、導入時期などによる差異 PC上にインストールしている他の物の影響 CI環境とローカル環境の環境差分 複数プロジェクト兼任時の干渉 同一ミドルウェアのバージョン・パッケージ違いの併存 同一DBへのデータ同居 干渉については、 anyenv ・ asdf などのランタイム管理ツールや、言語ごとの環境分離機構(Pythonのvenvなど)で軽減することが可能です。しかし経験上、これらツールの操作手順は継続的にメンテされないことが多く、数年後に新メンバーがジョインした時などに問題を起こしがちです。 これらを解決するには、 一発で起動でき ・ 差分なく再現可能で ・ プロジェクトごとに独立した 開発環境が必要になります。これをコンテナ(Docker Compose)によって実現しようという話になります。 事前の注意 環境を作る前に、いくつか注意ポイントがあります。 本番環境とのコンテナイメージ統一を目指さない コンテナの利点の1つとしてどんな環境でも同じコンテナイメージが動く、というものがありますが、開発環境においてはこれを意識しない方が良いと思っています。 本番用イメージと開発用イメージでは、以下のように求めるものが全く異なります。 本番用イメージ 極力イメージサイズを抑え、最小限のものしか入れない、なんならログインシェルすら不要 実行ファイルはイメージ内に内蔵する 開発用イメージ Git、各種ターミナルコマンド、デバッグツールなど多種のツールが入っていて欲しい 実行ファイルはイメージ内に不要、ソースコードをディレクトリごとマウントする 強引にイメージを統一しようとすると開発が辛くなるので、独立したイメージとして管理した方が現実的です。 # 本番用 FROM node:18.19-alpine ENV NODE_ENV=production ENV NEXT_TELEMETRY_DISABLED=1 WORKDIR /app COPY package.json yarn.lock ./ RUN yarn install --frozen-lockfile COPY . . RUN yarn build CMD yarn start # 開発用 FROM node:18.19-bookworm RUN apt-get install -y git vim Apple Sillicon搭載macの場合 Apple M1などのCPUはarm64アーキテクチャを採用しています。最近のイメージはarm64対応していることが多いですが、使用している言語バージョンが古いなどの場合、x86_64イメージしかない場合があります。この場合でもRosettaによるエミュレーションで動かせることも多いですが、動作しないこともあるのでご注意ください。 Docker Composeの構成 実際に環境を作っていくにあたり、ソースコードリポジトリをモノレポとするか、ポリレポとするかで方針が異なってきます。どちらを選ぶかは運用体制やシステム規模によりますが、いずれにしても docker compose up docker compose down のみで開発環境を起動・停止し、デバッグできるようにします。 モノレポの場合 あるシステムを構成する 全てのサブシステムをローカルで起動しちゃおうぜ! という方式です。Docker Compose一発でシステムの全てを再現することを目指します。 この場合、リポジトリは1つになり、サブディレクトリにサブシステムが並ぶモノレポ構成になります。 repository/ - frontend/ - Dockerfile - src/ - test/ - backend/ - Dockerfile - src/ - test/ - mock-ext-api/ - Dockerfile - src/ - test/ - compose.yml compose.ymlは全てのアプリケーションやDB、モックなどを起動するように設定します。 version: '3' services: frontend: build: context: frontend volumes: - ./frontend:/usr/src/app ports: - 3000:3000 backend: build: context: backend volumes: - ./backend:/usr/src/app ports: - 3080:3000 mock-ext-api: build: context: mock-ext-api volumes: - ./mock-ext-api:/usr/src/app database: image: mysql volumes: - database-volume:/var/lib/mysql volumes: database-volume: 動作イメージは以下のようになります。 モノレポ構成 Docker Compose上でサブシステムが全て起動している状態で、各コンテナに対してディレクトリをマウントすることによりソースコードを同期します。 開発に必要な言語ランタイム、ツールなどは全てDockerfileで定義しておき、ローカル環境には依存しないようにします。 コンテナ間での通信はコンテナ間通信で行い、基本的にlocalhostを経由しません。各コンテナのホスト名はDocker Composeに定義したserviceの名前(上記ではfrontend, backend, …etc)で解決されるので、これらを指定するようにします。ローカルPC側から確認したいポートのみローカルPC側に公開します。 メリット 複数サブシステム間の結合動作が容易に確認できる CI上での実行も容易 Docker Compose内でほぼ全ての処理が完結するため、再現性が高い 同一DBを複数サブシステムで共用するような環境にも対応できる デメリット システム規模が大きい場合、マシンスペックを大きく消費するため現実的でない 外部システムへの依存度が高い場合、メリットが薄くなる モックなどを使ってローカル完結させることもできるが、動作の信頼性は下がる リポジトリをモノレポ構成にできない場合がある サブシステムごとに担当者が異なる場合 CI/CDツールの発火条件をディレクトリ単位で制限できない場合 同一チームで複数サブシステムを複数運用していて、サブシステム間の結合処理が重要な場合に有効な構成です。 ポリレポの場合 開発したいシステムだけ起動しようぜ! という方式です。この場合は1リポジトリ1サブシステムのポリレポ構成となります。 repository/ - src/ - test/ - Dockerfile - compose.yml compose.ymlにはアプリコンテナは開発対象の1つのみとなり、その他は直接使用するDBなどのみが記載されることになります。 version: '3' services: backend: build: context: backend volumes: - ./backend:/usr/src/app ports: - 3080:3000 database: image: mysql volumes: - database-volume:/var/lib/mysql volumes: database-volume: 動作イメージは以下のようになります。 ポリレポ構成 アプリコンテナと必須のDBコンテナなど最低限のコンテナのみが起動した状態になります。別のサブシステムはDocker Composeの外にあるため、結合動作の確認は諦めるか、複数のDocker Composeの起動で対応します(後述)。 メリット 最低限のコンテナ起動で済むので、マシンスペックの消費が少ない リポジトリ管理上の制約が少ない デメリット サブシステム間の結合動作の確認が難しい 特にCI上で確認しようとすると、手順が複雑になりがち システムが大規模で全サブシステムの起動が困難であったり、担当者が分かれているような場合はこちらを採用することになります。 応用設定 以上で基本的なDocker Composeの環境は用意できましたが、実際に使っていくには追加の修正が必要です。 書き込みの多いディレクトリをVolumeにする Dockerはイメージとして保存することを前提としたファイルシステムを採用しています。このため、コンテナ内への書き込みは著しく遅くなります。 書き込みが多いと思われる 言語ごとのパッケージディレクトリ node_modulesなど ビルド結果の出力先ディレクトリ キャッシュディレクトリ DBコンテナのデータディレクトリ などはDocker Volumeとして切り出しましょう。コンテナを再作成したとしてもデータが消えなくなるという利点もあります。 version: '3' services: frontend: volumes: ... - node_modules:/usr/src/app/node_modules ... volumes: node_modules: (macOS限定) cached/delegatedオプションの活用 macOSではホストディレクトリをマウントした場合、I/O性能が著しく落ちるという問題が知られています。最近では virtiofsの採用 などで高速化を図っているとはいえ、依然として遅い状態は変わっていません。 マウント時のオプションを指定することで、ホスト-コンテナ間の整合性の担保を一部省略し、多少高速化するので設定しておきましょう。オプションは2つあり、 cached: ホストを信頼し、コンテナ側への反映が遅延することを許容 delegated: コンテナ側を信頼し、ホスト側への反映が遅延することを許容 の違いがあります。ホスト側でコーディングするならcachedを、コンテナ側でコーディングするならdelegatedを設定するようにしましょう。 services: backend: volumes: - ./backend:/usr/src/app:delegated // コンテナに入ってコーディングする場合 ... またそもそも、ホスト-コンテナ間で同期の必要がないディレクトリはDocker Volumeによるマウントにしましょう。DBのデータディレクトリまでホストディレクトリのマウントで行っているような例をたまに見かけますが、I/O性能が大きく悪化するので避けるべきです。 本番・開発間での設定共有 本番用と開発用でDockerイメージを分けるという話をしましたが、「それでも本番用イメージをビルドして動作確認をしたい」という要望はあります。このような場合はDocker Composeの統合機能を利用します。 docker composeコマンドは docker compose -f a.yml -f b.yml のように、fオプションで複数のファイルを指定できます。これは後続のファイルが前のファイルを上書きしていく、という挙動をします。 これを利用し、本番相当のcompose.ymlを用意しておいて # compose.yml services: frontend: build: context: frontend ports: - 3000:3000 開発用に上書きしたい部分だけ別ファイルを作ります。 # compose-dev.yml services: frontend: build: dockerfile: Dockerfile.dev volumes: - ./frontend:/usr/src/app この2ファイルを先の上書き挙動によってマージすると、以下のような結果が得られるはずです。 services: frontend: build: context: frontend dockerfile: Dockerfile.dev ports: - 3000:3000 volumes: - ./frontend:/usr/src/app こうすることで、 docker compose up とだけ指定した場合には本番用イメージで起動し、開発時には docker compose -f compose.yml -f compose-dev.yml up として上書きすることで、開発用Dockerfileやホストディレクトリのマウントを使う設定にできます。 ポリレポでの結合動作 ポリレポでは結合動作の確認が難しいという話をしましたが、一工夫することで結合動作の確認が可能です。 docker composeは何も設定しない場合、compose.ymlごとに別々のDockerネットワークを作成して環境を分離します。一方、ネットワークを明示的に指定することも可能です。 services: frontend: networks: - <ネットワーク名> networks: <ネットワーク名>: external: true として外部ネットワークを指定します。「<ネットワーク名>」の部分はネットワークを共用したいサブシステム全てで共通の名前を使用してください。こうしておいて docker network create <network> (サブシステムAで)docker compose up (サブシステムBで)docker compose up ... として順次コンテナを起動していくことで、compose.ymlが分かれていても同一ネットワーク内で起動し、コンテナ間通信ができるようになります。 この場合の注意点です。 最初に一度必ず docker network create < ネットワーク名 > を実行する必要がある 全てのコンテナにnetworksの指定を行う必要がある 複数コンテナから同一DBにアクセスするなど、共通リソースがある場合の再現は難しい 単独動作か結合動作、どちらかの確認を諦めなければならない まとめ 以上、Docker Composeによるローカル開発環境の構築でした。リポジトリ構成をどうするかという決めの問題がありますが、これ以外はDocker Composeの基本に則った内容かと思います。 これでコンテナ実行環境は整ったのですが、コーディングを行う上ではまだまだ課題があります。 次の記事 ではDev Containersを利用したコーディング環境の構築についてご紹介します。 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 9日目の記事です。 こんにちは。会員システムグループの三浦です。とあるプロダクトの開発チームリーダーを担当しています。 今回は、チームで行ったふりかえりで特にやって良かったと感じた、フォースフィールドアナリシスについて紹介します。 チーム背景の詳細についてもある程度書いています。ぜひあなたのチームが同じ状況に陥っていないか、その時どうすればいいのか、参考にしていただければと思います。 ふりかえりをする前のチームの現状 私たちのチームは、開発メンバーが自分を含め4人。当時、新規プロダクトのWEBシステム開発にアサインしていました。 元々の見積もりでは開発開始から約1ヶ月程度経ったタイミングで「そろそろWEB、API、データベースの最低限の機能は構築して、開発用のインフラも作ってみて、申込は試せるかな?」くらいのペースだったのですが・・・。 実際にはようやく1つ目のAPIがローカルで動くかという頃で、インフラ構築も、WEB画面も用意できませんでした。 この進捗遅れについてはバーンダウンチャートを作っていたおかげで気づくことができました。 青色の線が順調に作業ポイントを消化できていた場合の線、赤色が自分たちの消化した作業ポイントの線です どうみても青色の線と赤色の線が乖離しています。消化予定のポイントとはかなりの乖離がありました。明確に見積もりから進捗が遅れている状況です。 ふりかえりの場を作る さて、バーンダウンチャートによってチーム内で「これは遅れているという状況なんじゃないか?」という認識ができたところで、チームのふりかえりの時間になりました。 メンバーは皆なんとかして遅れを取り戻さなければ!と思っていましたが、こういった悪い状況を改善するアクティビティをやる前には、チーム全員でとある認識が必要です。 ふりかえりでは課題に対しての改善を探しますが、その時に「もっとこうしていれば」という発想がどうしても生まれます。 この発想のよくないところは、他人に対しても自分に対しても、過去の原因に目を向けさせてしまうところです。私たちは今開発の遅れを取り戻したいと考えており、それは未来の話なのです。 まず最初に読み上げたのは、森 一樹氏が作成・公開された「 ふりかえりカタログ 」の1番目の項目にもある「Norm Kerthの最優先指令」です。 どんな道をたどったにせよ、 当時の知識・技術・能力・利用可能な リソース・状況の中で、みんなができる 限り最高の仕事をしたはずです。 それを心から信じます。 その後、「非難をしないこと」というルールに賛同できるかを全員に問いました。 儀式的なものに感じられるかもしれないですが、この確認を行うことで、課題に対する原因探しから未来を改善させることに意識を集中できるようになります。 フォースフィールドアナリシスの実施 振り返りをやる場を設定したら、次にメインのフォースフィールドアナリシスを行います。 フォースフィールドアナリシスは、チームが置かれている現状、課題に対して何が改善の要因となるのか、何が抑制の要因となるのかを列挙して分析する手法です。 列挙した要因は矢印の太さによってその要因の強さを相対的に表現し、どうすればより改善の要因を強め、どうすればより抑制の要因を弱めることができるのかを考えます。 実践した手順は以下の通りです。かける時間についても設定していますが、多少のブレはあります。全体の時間は40~50分程度ですが、余裕を持って1時間確保してもよいでしょう。 テーマ(現状)を決定(3min) この場で分析したい現状を決める。 改善を促進する要因を書き出す(8min) この現状を改善したい、となったときに、現状を変えるようなきっかけ、要因、行動、理由を書き出す。 書き出した要因の重みづけ(4min) 書き出した要因に対して、どれがより効果が高いかを上から順に並べてみる。 改善を抑制してしまう要因を書き出す(3min) この現状を改善したい、となったときに、現状を維持、悪化させてしまう要因、行動、理由を書き出す 書き出した要因の重みづけ(4min) 書き出した要因に対して、どれがより影響が大きいかを並べてみる。 最も促進する要因・抑制してしまう要因を改善するアクションのアイデアだし(13min) 改善を促す要因については、それをどうすれば引き起こすことができるか 改善を抑制する要因については、それをどうすれば止めることができるか アクションの決定(5min) 出てきたアクションに対してドット投票を行い、次のアクションを決める 私たちのチームが書き上げたフォースフィールドアナリシスは以下の通りです。ツールはGoogle Jamboardを使用しました。 全体の進捗が遅れていることを改善すべき現状と置き、まずはそれに対しての改善要因と抑制要因をカードで列挙します。その後、緑やオレンジのカードで出てきた要因をさらっと確認しました。 太さの違う矢印を引いていくことでどの要因が強いのか、どの要因が弱いのかを可視化するのが本来の手順なのですが、カードで列挙したため、カードを上から影響度が強い順で並べてみました。 すると複数のカードが同じ「知らないこと・不確定なこと」に関する要因になっていることがわかってきます。 今回では、開発が始まってから分かる不確定な要素が多く、それを出てくるたびに再検討し直してチームで合意を取る、というのを繰り返していて、それによって開発の進捗が遅れていた・・・ということがアクティビティで浮かび上がりました。 そのため、不確定要素の多さを強い要因としてグルーピングし、それに対する改善行動をピンクのカードで深掘りしていくようにします。 ふりかえりでは実現確率を高めるためになるべく具体的な行動を1つ決めることを目指します。 今回は、私たちが忙しさを理由に出来ていなかったリファインメント(プロダクトバックログアイテムに対する見直し)を実施し、タスクのゴールや詳細を詰めることを決めました。 時間についても2時間を制限とし、次のプランニングから早速組み込みました。 ふりかえりの効果 リファインメントを実施することにより、開発チーム内にあった知識の偏りがある程度解消され、メンバーそれぞれが主体的に実装方法やテストを検討することができるようになりました。またプロダクトバックログアイテムに詳細な情報が集約されるようになり、作業量の見積もり制度も向上しました。 結果的に、元々見積もっていた作業量からはタスクの詳細化によってさらに作業量が増加しましたが、その詳細をチームメンバーが把握できていることによる案件全体のポイント消化効率が上がったことにより、チームの生産性は確実に上がりました。 青色の計画を示す線の角度がなだらかになっているのは作業量が増加している兆候ですが、赤色の実作業の線がその作業量を超える角度で緩やかになっているため、良い兆候が見えるようになりました。 ただこれだけで全てが良くなるというものでもなく、実際にはこの後にもステークホルダーとのコミュニケーション不足による手戻りや突発的な他案件との調整など、さまざまな課題に立ち向かうことになるのですがそれはまた今度の話とします。 さいごに チーム開発はうまくいかない場面も多々ありますが、それを乗り越えるのもまたチームです。課題のないチームなどないですが、少しずつ行動を変えていくことでチームは成長していける、それを改めて感じられる出来事でした。ブログを読んでいる皆様のチームも多かれ少なかれ課題があると思いますが、こうした解決事例を参考にして、よりよいチーム開発を作っていただければと思います。 ニフティではスクラム開発が主な開発手法として浸透しています。こうしたチーム活動などに興味のある方に対して技法を教え合うような場も設定されていますし、手助けができる環境です。こうした事例に興味を持った方がいらっしゃいましたら、ぜひ以下のリンクからお気軽にご連絡ください。 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 16日目の記事です。 InnerSource Commons #11 にて、ニフティでのインナーソースを導入期の事例紹介し、ディスカッションパートでは、全社展開に向けての悩んでいることについて話しました。 12/11 InnerSource Commons #11にて当社エンジニアが登壇いたします 本記事の内容 InnerSource Commons Japanのイベント ニフティの事例紹介 事例紹介の内容で参加者の方と話したこと 社内展開に向けて悩んでいることの共有 他の会社はどのように進めたのか? 成熟度モデルは誰がどの単位で自己評価していくか? メインストリームの開発業務とのバランスをどう考えるか? 感想 こんにちは!会員・認証基盤システムの開発・運用をしている基幹システムグループの小松です。 InnerSource Commons #11 の発表したことやディスカッションした内容を一部紹介します。 ディスカッションパートではとても勉強になる情報を教えていただきました! InnerSource Commons Japanのイベント connpassにてInnerSource Commons Japanのイベント が開かれています。 まだ日本の事例は少ないので、有識者の方と直接お話ができる有意義なイベントとなっています。 アーカイブも YouTube にて公開されています。 2024年度からは、コミュニティ内の繋がりを活発にするためオフラインの開催も増えるらしいです。 ニフティの事例紹介 InnerSource Commons #11 ではまずニフティから、インナーソース導入に向け今までやったことの概要、インナーソース実験プロジェクトの結果と全エンジニアに向けたアンケートの結果を紹介しました。 ブログ記事( インナーソースを導入してみた その① お試し導入編 )にアンケート結果など書かれているので気になる方はご覧ください。 登壇時に発表した資料は以下です。 発表パートはアーカイブに残っています。 事例紹介の内容で参加者の方と話したこと ブログの内容も含め取り組みに感動したと言うフィードバックをいただけて嬉しかったです。 日本ではまだ事例が少ないので、ニフティとしても取り組み内容など情報発信をしていきたいと思います。 「インナーソースを始めたモチベーションは、やはりインナーソースのような開発の必要性を感じているのが大きいか?」という質問が来ました。 ニフティとしては必要性を感じています。 私と芦川が所属している基幹システムグループでは、共通基盤となるシステムが多くあるため、今後の開発業務で、共通基盤で必要となる修正がボトルネックになることを避けるためにもインナーソースは必要だと思っています。 「実験プロジェクトに参加した人数に比べて、アンケートの内容はポジティブな人が多かった。実際の社内の雰囲気はどうだったのか?」という質問が来ました。 2ヶ月の実験プロジェクト(社内ツール1リポジトリをインナーソース化)で約150人エンジニアがいるなかIssueをアサインした人が7名でした。 しかしアンケートは43名が回答してくれ、全社展開に賛成が76.7%、中立が23.3%、反対は0%でした。 メリットについても多くの方が記入してくれました。 実際、実験プロジェクトを始めますとエンジニア全体会で発表したときも、「〇〇リポジトリをインナーソース化したい!」といったフィードバックが何件か来ていたので、メリットは伝わっていてインナーソースに対してポジティブな人が多いと感じていました。 良い取り組みにポジティブな反応をしてくれるニフティのエンジニアの雰囲気もあると思います。 実験プロジェクトの参加者が少なかったのは、メインストリームの開発業務とのバランスがネックになっていたと思います。 これについては後述する悩みにも入っています。 社内展開に向けて悩んでいることの共有 現在インナーソースガイドラインやインナーソースポータルを公開し、いくつかインナーソースリポジトリが徐々に増えてきている段階です。 全社展開に向けての悩んでいることを共有し、ディスカッションさせていただきました。 他の会社はどのように進めたのか? 悩みの背景 ニフティの規模に近いサンプルがあるのか 組織の人数感、文化、B2B orB2C、など 浸透速度なども知りたい 社内に普及するためのコツはありますか? ニフティではトップダウンでなくボトムアップで進めている 導入にはポジティブな雰囲気だが、スピード感が早いとは言えない状況 ディスカッションした内容 まずニフティの規模(エンジニア約150名)に近いサンプルは日本にはない。 ヨーロッパの方には近しいものがあるが、日本ではまだ知られない会社が多い。ソフトウェアベンダーの会社が多い。 社内に進めるスピード感について。 ここまでの流れは世界的にみても平均よりは早い方。 ただし更に社内展開していくところから色々な課題がでてくるので、ここからの方が重要でスピード感が求められる。 もともとインナーソースに近い活動をすでにしていた組織ではインナーソース普及が早いとのことでした。 ニフティはチームを超えて協力しあう雰囲気はすでにあったので、ここまでは順調に来れたのではないかと思います。 全社展開のコツ。 やはり人が多くなると時間もかかり、1年かかるところもあれば2,3年くらいかかるところもある。 社内で引っ張っていく人を1、2人を決めるのがよい。 元々OSSコントリビュートをやっていた人がなるケースがある。 成熟度モデル は誰がどの単位で自己評価していくか? 悩みの背景 例えば、透明性(プランや開発プロセス、ツール、意志決定など)は各プロダクト単位で自己評価していくとよさそうだが、ガバナンス(リワード、カルチャーなど)は全社的にインナーソースオフィスが評価すべきか? ディスカッションした内容 あくまでベンチマークなので、組織的な課題と突合させて判断する。 成熟度モデルに関しては、誰のためのアセスメントなのかが重要。 単純に数値を上げることに注力しては意味がない。 自分たちの課題を見つけてレベルアップするために使うもの。 第三者含め、背景なども踏まえ議論しながら使うのがよい。 最初から全ての項目を測る必要はない。 事例として全てをチェックしたらどの項目も最低値になり、結局どこから手を付けるのかがわからなることがあった。 まず導入期は細かいプロダクト単位で測っていくのがよい。 徐々に案件や組織ベースで測っていくのがよいとのこと。 アンケートなどで課題や目指す姿を聞いてみるの効果的。 メインストリームの開発業務とのバランスをどう考えるか? 悩みの背景 そもそもインナーソースは余力時間にやるものなのか 例えば、スクラムで開発をしている場合で、期待する成果物をより早くデプロイできる場合、プロダクトバックログアイテムに他リポジトリへのコントリビュートをすることも視野にいれていくのか スクラムをやっているチームはどのようにインナーソースを取り入れているか ディスカッションした内容 まずボトムアップで組織にインストールする場合、良いカルチャーがあるとこの活動いいね、やりたいまではすぐ行くが、実際の業務で効率が上がったと認識するまでにはハードルが高い。 メインストリームの開発とのバランスを考えるよりもインナーソースを使って生産性を上げるという考え方への変換が必要になりそう。 余力時間を会社が認めて上げることも必要。 コントリビュートなどを試してみる時間の確保(Googleの20%ルールなど)や評価制度などのサポートがあるとよい。 実際のコントリビュートは余力時間以上のコストがかかるのでサポートが必要。 評価システムによって導入が難航している事例が多い。 とある事例では、コントリビューターを引き付けるようなものがあるとサイクルが回ったとのこと。 コントビュートされる側が一緒にやりましょうと呼びかけ、コントビュートする側もコントビュートされる側もプロダクトが良くなって、より多くの人が使われるようになり評価もされるとのこと。 スクラムとの兼ね合いについて。 スクラムはスプリントで期限が決まっているので、インナーソースと同期できないので単一のスクラムチームでは厳しい。 Large-Scale Scrum (LeSS) とインナーソースの相性はいいかもしれない。 スプリントゴールを達成するために、他チームのリポジトリに手を入れる必要がある場合が発生するため。 感想 まだニフティは導入始めたばかりでインナーソース文化の定着まではできていませんが、InnerSource Commons で事例紹介をさせていただく機会をいただけて嬉しかったです。 とても有意義なイベントでした。 まだ日本での事例が少ないので、情報発信をしつつ社内の普及活動を続けていきたいです。 悩みの部分に関してもいい情報をもらえたので良かったです。 成熟度モデルの評価はまずはできるところから検討してやっていこうと思います。 今回の話を聞かなかったら、とりあえず全部計測してみるというアンチパターンをやってしまいそうでした。 コントリビュートをサポートの仕組みなども検討していきます。 ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
こんにちは。ニフティの浅見( @rubihiko )です。 ニフティでは毎年エンジニアの新人研修を先輩エンジニアが 内製 で行う文化があります(通称、 エンジニア定例 と呼ばれています)。 今年から、資料を一般公開いたします(一部公開出来ない資料もございます)。 公開時期が遅くなってしまったことについて補足しますと、公開する取り組みが今年度が初めてで、資料を公開用に手直しなど諸々作業が発生したためです。 来年度以降はスムーズに公開できるよう調整していきたいと思います。 特徴 基礎学習とチーム開発を経験しながら研修は進んでいきます。 新人は来年は講師として教える側になるという特徴があります。 また、毎年内製研修の内容を改善していて、新しいテーマが研修内容に加わるのも特徴です。 2023年度はプロダクティビティが加わりました。 研修では以下の点を重視しています。 ニフティの開発基礎を学ぶ チーム開発を経験する サービス運用を意識・経験する 来年は教える立場だと意識する 生徒→講師による継続的な新人研修の運用 目標 基本的なWebサービスの開発・運用に関する知識とチーム開発を身につけます。 期間は、4月後半〜6月中旬にかけて行います。 ニフティでは、6月末頃からOJTが始まります。それまでにニフティにおける開発運用(+α)の基本を身につけることが目標です。 他の研修もあるので、新人はインプットが多くなり大変な時期です。 今年のテーマは以下 開発の基礎 フロントエンド バックエンド データベース Webフレームワーク セキュリティ コンテナ Git AWS オブジェクト指向 機械学習 スクラム SRE スマートフォンアプリ開発 バックボーンネットワーク [NEW] プロダクティビティ 研修資料一覧 講義の内容は、座学パートと演習パートに分かれており、基本からしっかり学べます。 演習パートは個人作業だったりグループ作業だったり講義によって特徴がでます。 開発の基礎 Webフレームワーク フロントエンド(Speaker Deck) バックエンド(Speaker Deck) データベース データベース基礎(Speaker Deck) セキュリティ セキュリティ入門(Speaker Deck) コンテナ コンテナの基礎(Notion) Git 初めてのバージョン管理(Speaker Deck) AWS AWS基礎(Speaker Deck) オブジェクト指向 機械学習 機械学習の基礎(Notion) スクラム SRE SRE実践(Notion) スマートフォンアプリ開発 Androidアプリ開発(Notion) バックボーンネットワーク バックボーンネットワーク(Notion) プロダクティビティ プロダクティビティ(Notion) 最後に ニフティの内製研修の歴史は長く、資料アップデートや新規講義の追加、今年の新人は来年の講師、といったことが継続的に行われてきました。新人だけでなく、2年目以降のメンバーの成長にもつながるよい文化ができていると思います。 教育面で力をいれており、毎年充実したカリキュラムを考えています。今後も新人研修の様子や資料を公開していこうと思いますので、ブログを確認市ていただければ幸いです。 We are hiring! ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 15日目の記事です。 はじめに こんにちは SREチームの @rubihiko です。 CodeWhispererですが、最近コマンドラインツールにも対応したので試してみたいと思います。 CodeWhispererは2つのTierで提供されており、今回は個人利用の方法について試します。 詳しい料金体系はこちらを確認してください。 https://aws.amazon.com/jp/codewhisperer/pricing/ Amazon CodeWhispererについて https://aws.amazon.com/jp/codewhisperer/ IDE とコマンドラインのための AI 搭載生産性向上ツール Amazon CodeWhisperer は、コメントと既存のコードに基づいて、スニペットから完全な関数まで、さまざまなコードの提案を IDE 上でリアルタイムで生成します。また、コマンドラインでの CLI 補完や自然言語から bash への翻訳もサポートしています。 CLIのセットアップ https://docs.aws.amazon.com/codewhisperer/latest/userguide/command-line.html インストール こちらからダウンロードしてインストールします https://docs.aws.amazon.com/codewhisperer/latest/userguide/command-line-getting-started-installing.html 認証情報の設定 個人で利用する場合は、Builder IDで認証を行います ※Builder IDの取得はこちらから https://docs.aws.amazon.com/signin/latest/userguide/sign-in-aws_builder_id.html あとは指示にした以外インストールを完了させます。 以下の項目を有効にしてください。 shell integrations Enable accessibility サポートされているコマンドライン環境 現時点では以下が対応しています Operating systems: macOS Shells: bash, zsh, fish Terminal emulators: iTerm2, macOS terminal, Hyper, Alacritty, Kitty, wezTerm IDEs: VS Code terminal, Jetbrains terminals (except Fleet) CLIs: 500+ of the most popular CLIs such as git, aws, docker, npm, yarn 補完機能 AWS CLIはもちろんですが、gitやdockerなどのコマンドにも対応しています 自然言語からコマンドを生成 以下のコマンドで自然言語からコマンドを生成することができます cw ai cw ai prompt # promt # で呼び出さないよう無効にすることもできます ファイルをs3にコピーする aws s3 cp $FILENAME s3://$BUCKET_NAME/$FILENAME 起動中のEC2インスタンスの一覧を取得する aws ec2 describe-instances --query 'Reservations[*].Instances[*].{InstanceId:InstanceId,State:State.Name,PublicIP:PublicIpAddress,PrivateIP:PrivateIpAddress}' --output table 問題なければそのまま実行できますし、修正も可能です。 危険なコマンドの場合は警告が出ます 感想 いかがでしょうか。 今回はCLIにフォーカスして試してみましたが、自然言語からコマンドを生成できるのはかなり便利に感じます。 よく使うものであれば、そのまま alias に登録してしまうのも良いかもしれません。 また、個人で利用する分には無料なもの嬉しいポイントです。 参考 CodeWhisperer for command line Introducing Amazon CodeWhisperer for command line AWS re:Invent 2023 – Best practices for Amazon CodeWhisperer (DOP201) ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する
この記事は、 ニフティグループ Advent Calendar 2023 15日目の記事です。 はじめに ニフティ株式会社の島田です。 以前ご紹介したAWS Chatbotの送信内容をカスタムする方法がCustom notificationsとして正式に提供されたため、使ってみました。 EventBridge+ChatbotでECSタスクの状態をslackに通知してみた ついでにAmazon CloudWatch Logsから特定のワード発生を検知し、slackに通知する仕組みをAWS Lambdaを使わずに実現したので紹介します。 一般的なログ検知 一般的なログ検知、通知の手法として、以下のような構成があると思います。 登場するリソースは以下です。 Amazon EC2 (以降EC2) / Amazon ECS (以降ECS) これらはアプリケーションが起動しているコンピューティングを表しています Amazon CloudWatch (以降CloudWatch) / Amazon CloudWatch Logs (以降CloudWatch Logs) AWS Lambda (以降Lambda) コンピューティング環境から収集したログをCloudWatch Logsに連携し、サブスクリプションフィルターで検知したログをLambdaに連携、イベントをパースしてslackに連携します。 ノーコードの構成 今回は以下の構成でノーコードを実現しました。 新たに登場するリソースは以下です。 Amazon Kinesis Data Firehose (以降Kinesis Firehose) Amazon S3 (以降S3) Amazon EventBridge (以降EventBridge) Amazon SNS (以降SNS) AWS Chatbot (以降Chatbot) リソースは増えますが、Lambdaを使わずにslack通知を実現しています。 ちょっとしたハマりポイントもあるので順を追って説明します。 CloudWatch → Kinesis Firehose → S3 まず、対象ログを配置するS3を作成します。 次に、S3をターゲットにしたストリームを作成します。このとき、S3にアクセス可能な権限を付与する必要があります。 最後にCloudWatch Logsの対象のロググループにサブスクリプションフィルターを設定します。 送信先としてKinesis Firehoseを選択し、Kinesis Firehoseへのアクセスを許可します。 これらをTerraform化したサンプルです。 # S3 resource "aws_s3_bucket" "main" { bucket = "logs" } # Firehose resource "aws_kinesis_firehose_delivery_stream" "firehose" { name = "subscriptionfilter-stream" destination = "extended_s3" extended_s3_configuration { role_arn = aws_iam_role.firehose.arn bucket_arn = aws_s3_bucket.main.arn prefix = "subscriptionfilter/" error_output_prefix = "subscriptionfilter/error/" buffering_interval = 60 compression_format = "GZIP" } } resource "aws_iam_role" "firehose" { name = "FirehoseRole" assume_role_policy = jsonencode({ "Version" : "2008-10-17", "Statement" : { "Effect" : "Allow", "Principal" : { "Service" : "firehose.amazonaws.com" }, "Action" : "sts:AssumeRole" } }) } resource "aws_iam_policy" "firehose" { name = "FirehosePolicy" policy = jsonencode({ "Version" : "2012-10-17", "Statement" : [ { "Effect" : "Allow", "Action" : [ "s3:AbortMultipartUpload", "s3:GetBucketLocation", "s3:GetObject", "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:PutObject" ], "Resource" : [ "${aws_s3_bucket.main.arn}", "${aws_s3_bucket.main.arn}/*" ] } ] }) } resource "aws_iam_role_policy_attachment" "firehose" { role = aws_iam_role.firehose.name policy_arn = aws_iam_policy.firehose.arn } # CloudWatch Logs resource "aws_cloudwatch_log_subscription_filter" "filter" { name = "filter" role_arn = aws_iam_role.filter.arn log_group_name = ${var.log_group_name} filter_pattern = "?ERROR ?Error" destination_arn = aws_kinesis_firehose_delivery_stream.firehose.arn distribution = "Random" } resource "aws_iam_role" "filter" { name = "LogFilterRole" assume_role_policy = jsonencode({ "Version" : "2008-10-17", "Statement" : { "Effect" : "Allow", "Principal" : { "Service" : "logs.ap-northeast-1.amazonaws.com" }, "Action" : "sts:AssumeRole", "Condition" : { "StringLike" : { "aws:SourceArn" : "arn:aws:logs:ap-northeast-1:${var.account_id}:*" } } } }) } resource "aws_iam_policy" "filter" { name = "LogFilterPolicy" policy = jsonencode({ "Version" : "2012-10-17", "Statement" : [ { "Effect" : "Allow", "Action" : ["firehose:PutRecord"], "Resource" : ["${aws_kinesis_firehose_delivery_stream.firehose.arn}"] } ] }) } resource "aws_iam_role_policy_attachment" "filter" { role = aws_iam_role.filter.name policy_arn = aws_iam_policy.filter.arn } これでサブスクリプションフィルターの対象のログをS3に保存することができるようになりました。 S3 → EventBridge 作成したS3のイベントをEventBridgeから取得できるようにします。 これをTerraform化したサンプルです。 # S3 resource "aws_s3_bucket_notification" "main" { bucket = aws_s3_bucket.main.id eventbridge = true } # EventBridge resource "aws_cloudwatch_event_rule" "event" { name = "event" description = "object created event" is_enabled = true event_pattern = jsonencode({ "source" : ["aws.s3"] "detail-type" : [{ "prefix" : "Object Created" }], "detail" : { "bucket" : { "name" : ["${aws_s3_bucket.main.bucket}"] } } }) } S3のオプションでcreateイベントを送信することもできるのですが、この後Chatbotにわたす際にイベントを編集したいのでこの方法を使っています。 また、Object Createdイベントは完全一致でなくprefixとして指定する必要があります。 EventBridge → SNS イベント送信先のSNSトピックを作成します。このとき、SNSのリソースベースポリシーとしてEventBridgeを許可する必要があります。 また、EventBridgeで入力を変換し、ChatbotのCustom notificationsの構造を作って送信します。 これらをTerraform化したサンプルです。 # EventBridge resource "aws_cloudwatch_event_target" "event" { rule = aws_cloudwatch_event_rule.event.name arn = aws_sns_topic.sns.arn input_transformer { input_paths = { source = "$.source", id = "$.id", bucket = "$.detail.bucket.name", key = "$.detail.object.key" } input_template = <<EOF { "version": "1.0", "source": "custom", "id": <id>, "content": { "title": "log detected", "description": "S3 object created event\n - source: `<source>`\n - bucket: `<bucket>`\n - key: `<key>`" } } EOF } } # SNS resource "aws_sns_topic" "sns" { name = "SNS" } resource "aws_sns_topic_policy" "sns" { arn = aws_sns_topic.alert.arn policy = jsonencode({ "Version" : "2008-10-17", "Id" : "__default_policy_ID", "Statement" : [ { "Sid" : "__default_statement_ID", "Effect" : "Allow", "Principal" : { "AWS" : "*" }, "Action" : [ "SNS:GetTopicAttributes", "SNS:SetTopicAttributes", "SNS:AddPermission", "SNS:RemovePermission", "SNS:DeleteTopic", "SNS:Subscribe", "SNS:ListSubscriptionsByTopic", "SNS:Publish" ], "Resource" : "${aws_sns_topic.sns.arn}", "Condition" : { "StringEquals" : { "AWS:SourceOwner" : "${var.account_id}" } } }, { "Sid" : "SNS topic policy from EventBridge", "Effect" : "Allow", "Principal" : { "Service" : "events.amazonaws.com" }, "Action" : [ "SNS:Publish" ], "Resource" : "${aws_sns_topic.sns.arn}", "Condition" : { "StringEquals" : { "aws:SourceAccount" : "${var.account_id}" } } } ] }) } リソースベースポリシーはマネジメントコンソールから作成した場合のデフォルトのポリシーを含めています。 SNS → Chatbot Chatbotが利用するロールを先に作成しておきます。 現時点ではTerraformでChatbotを作成できないため、Chatbot自体はマネジメントコンソールから作成します。 これらをTerraform化したサンプルです。 # Chatbot resource "aws_iam_policy" "chatbot" { name = "ChatbotPolicy" description = "AWS Chatbot policy" policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = [ "cloudwatch:GetMetricData", "cloudwatch:ListMetrics", "cloudwatch:ListDashboards" ] Effect = "Allow" Resource = "*" }, ] }) } resource "aws_iam_role" "chatbot" { name = "ChatbotRole" assume_role_policy = jsonencode({ "Version" : "2008-10-17", "Statement" : [ { "Sid" : "", "Effect" : "Allow", "Principal" : { "Service" : "chatbot.amazonaws.com" }, "Action" : "sts:AssumeRole" } ] }) } resource "aws_iam_role_policy_attachment" "chatbot" { role = aws_iam_role.chatbot.name policy_arn = aws_iam_policy.chatbot.arn } 結果 こんな感じで通知が可能になりました。 まとめ Custom notificationsのおかげで、色々なslack通知がChatbotに任せられるようになりました。 今回の構成はLambdaを使った場合と比べて以下のようなメリット/デメリットが考えられます。 メリット コード、Lambdaの管理をしなくて良い ログがS3に保存される デメリット 通知が来るまで若干時間がかかる ログの内容は出力できない 特に今回作った通知ではログの内容を知ることはできないため、広くフィルタを適用する場合などは不向きと考えられます。 それが許容できる場合はLambdaの管理を手放す事ができ、コードを書くことなく実現可能ですので用途に合わせて参考にして頂ければと思います。 明日は、 @sonoha さんの記事です。 お楽しみに! 参考記事 https://aws.amazon.com/jp/about-aws/whats-new/2023/09/custom-notifications-aws-chatbot/ https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/ev-mapping-troubleshooting.html https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/confused-deputy.html https://docs.aws.amazon.com/ja_jp/chatbot/latest/adminguide/custom-notifs.html https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/ev-events.html ニフティでは、 さまざまなプロダクトへ挑戦する エンジニアを絶賛募集中です! ご興味のある方は以下の採用サイトより お気軽にご連絡ください! ニフティ株式会社採用情報 Tech TalkやMeetUpも開催しております! こちらもお気軽にご応募ください! Event – NIFTY engineering connpassでニフティグループに 参加いただくと イベントの お知らせが届きます! connpassで ニフティグループに参加する