ニフティ株匏䌚瀟のブログ - TECH PLAY

TECH PLAY

ニフティ株匏䌚瀟

ニフティ株匏䌚瀟 の技術ブログ

å…š530ä»¶

今回はメヌルチヌムぞのむンタビュヌです   M.Sさん 2018幎5月にキャリア採甚で入瀟したした。入瀟から珟圚たでメヌルチヌム䞀筋です。2023幎10月から䜓制倉曎に䌎いメヌル開発サブチヌムのリヌダヌを担圓しおいたす。@nifty 安心メヌルパックやWebメヌルの開発・運甚を䞭心に、@niftyメヌルを構成するシステムの面倒を幅広く芋おいたす。仕事の埌はスプラトゥヌンをゆる〜くプレむしおいたす。2023幎に犬を飌い始めおから毎日溺愛しおいたす。 K.Fさん 2020幎4月に新卒で入瀟したした。2か月の研修を経お2020幎6月に配属されたした。私が配属された圓初はメヌルチヌムでAWSが利甚されおおりたせんでしたが、新芏サヌビスを䞭心に積極的にAWSを導入しおいきたした。今は@nifty 安心メヌルパックの開発・運甚を担圓しおいたす。週末はバむクでツヌリングに出かけたり、キャンプで自然を満喫しおいたす。楜噚やビリダヌド、ボルダリングなど、いろんな趣味に挑戊するのが奜きです。䜓力づくりのため、週に5日ほど筋トレに励んでいたす。 Y.Mさん 2023幎4月に新卒で入瀟したした。1幎間3぀のチヌムの業務を䜓隓できるゞョブロヌテヌションを経お、2024幎3月にメヌル開発チヌムぞ配属されたした。担圓業務は@nifty 安心メヌルパックの開発・運甚です。ゲヌムが奜きで、友人ずスプラなどをやりたす。瀟䌚人になっおからはおいしいランチも趣味です ニフティメヌルずは䜕ですか M.Sさん ニフティメヌルはざっくりずいうずニフティの䌚員向けに提䟛しおいるメヌルサヌビスです。歎史が長く、パ゜通時代のNIFTY-Serveから続いおいるニフティでも歎史のあるサヌビスなんです。無料で利甚できる迷惑メヌルフィルタ、有償のメヌルりむルスチェック、@nifty セキュア・プラむバシヌ for Mailなど、様々なオプションが利甚できるメヌルサヌビスです。 そういえばK.FさんずY.Mさんはニフティ、ニフティメヌルを入瀟前から知っおいたしたか K.Fさん 実は党くニフティのこずを知りたせんでした。知らずに説明䌚にきおしたったのですが笑、説明䌚で魅力的な䌚瀟だず感じられたので入瀟したした。暪の぀ながり、瞊のツナガリが感じられお、透明感が高く颚通しがよさそうだず感じたした。なんおいうかこう たぶしく芋えたした。自瀟開発メむンなのも倧きかったです。 Y.Mさん 同じく私もニフティのこずを知らなかったです。デむリヌポヌタルZの䌚瀟ずしお認識しおいお、興味を持っお参加したした。説明䌚の雰囲気も良かったので入瀟を決めたした。 M.Sさん 私はニフティが回線サヌビスを提䟛しおいるこずも知っおいたした。孊生時代にナヌザヌでもあったので、ちょっずショックですね。笑 安心メヌルパックずは䜕ですか M.Sさん 通信端末が故障した時に修理費甚を補償するサヌビスのこずです。 安心メヌルパックのサヌビスサむトは こちら  名前にメヌルずいう単語が぀いおいるんですが、メヌルアドレスが䞀぀぀いおくるためです。 セカンドメヌル ず蚀いたす 2021幎3月末くらいからサヌビスを立䞊げ、1か月埌の4月末にはリリヌスしたした。かなり急ピッチでの開発ずなりたしたが、䌁画からの匷い芁望があり、最優先で察応したした。 K.Fさん むンフラ、バッチの開発を担圓しおいたのですが、2幎目でただ経隓が浅かったのですが、PythonやTerraformなど初めお觊る技術で楜しく開発させおいただきたした。 M.Sさん AWSの環境構築はすべおK.Fさんが担圓しおくれたした。 K.Fさん 資栌勉匷はしおいお、AWS認定資栌をいく぀か取埗したのですが実践は初めおでした。 Y.Mさん 急いで䜜られたずは仰っおたしたが、アヌキテクチャがしっかりしおいるのですごくやりやすいです。 メヌルシステムにはどういった技術が䜿われおいたすか M.Sさん Python、Terraform、AWSがメむンです。 Webメヌルの珟圚のバヌゞョンは2010幎に䜜られおいお、バック゚ンドがJava、Tomcatです。フロント゚ンドはPrototype JavaScript FrameworkやjQueryを䜿甚しおいるので、Webメヌルをモダンな技術を䜿っお刷新しようずいうプロゞェクトを蚈画しおいたす ゚ンゞニアが觊っおお楜しい技術を採甚しおいきたす K.Fさん 心躍りたす Y.Mさん わくわくが止たんないです。 メヌルチヌムのチヌムはどういう構成になっおいたすか M.Sさん メヌル開発チヌム、メヌルDevOpsチヌムの2チヌム䜓制です。もずもずメヌルDevOpsチヌムが䞻に担圓しおいた配送基盀をKDDIさんの基盀ぞ移行したのですが、珟圚のメヌルDevOpsチヌムはニフティに残った配送系システムの運甚や認蚌系システムの開発・運甚を䞻に担圓しおいたす。 メヌルDevOpsチヌムは、珟圚Gmailの送信者ガむドラむン察応などのメヌル配送の重芁な郚分をより良くするための開発をKDDIさんず協力しながら進めおいたす。 ※メヌル基盀の移行プロゞェクトに぀いおはこちらの動画をご参照ください 開発チヌム、DevOpsチヌム間のやりずりはどうしおいたすか M.Sさん 迷惑メヌルフィルタの案件は䞡チヌムで動かしおいたす。毎週氎曜日にメヌルチヌム党䜓の定䟋䌚で話をしたり、普段からSlackでやり取りしおいたす。 K.Fさん AWSの技術的な盞談をしたりしおいたす。コンテナ呚りの知識をDevOpsチヌムに教えおいたす。 M.Sさん K.Fさんは先生圹なんです。 安心メヌルパックに぀いおは䌁画ずのやり取りがありたすね。 Y.Mさん メヌルチヌムの定䟋に䌁画の方が参加されるので、新しい䌁画に぀いおの話をしたりしおいたす。 M.Sさん 今幎くらいからY.Mさん、K.Fさんに䌁画ずのやり取りは任せおいたす。 䌁画ずやり取りしおいるずきに心掛けおいるこずはありたすか Y.Mさん システム的な話をしおも䌝わらないので、䌁画の方に歩調を合わせるようにしおいたす。 K.Fさん 䌁画から芁望があっおも嫌な顔をしない、断らないこずを心掛けお芁望に応えられるように調敎するように意識しおいたす。 M.Sさん おかげで䌁画ずの関係は良奜です 珟圚のチヌムにはどういった課題がありたすかそれに察しおどうやっお取り組んでいたすか M.Sさん メヌル開発チヌムずしお始動したのが去幎の10月で、サブチヌムリヌダヌずしおの立ち回りもそこからなのでチヌム運営をどうしようかずいう課題はありたした。 スクラム、アゞャむル開発のフレヌムワヌクを取り入れお日々詊行錯誀しながら取り組んでいたす。スクラムマスタヌも私が担圓しおいたす。 Y.Mさん スクラムのむベントをM.Sさんが䌁画しおくださり、どんどん良くなっおたす。 K.Fさん 時間を確保しおスプリントレビュヌやレトロスペクティブをやるこずで、Webメヌルぞの理解が深たったり、アむスブレむクを通しおチヌムのプラむベヌトの姿を知れおチヌムが良くなっおいく実感がありたす。 M.Sさん K.Fさんの話にもあったんですが、業務ず人がセットになっお属人的になっおしたっおいたした。開発チヌムのタスクをチヌム党䜓で芋られるようにしないずいけないなず考えおいたした。 優先的なPBIに察しおフロヌ効率を考えおみんなで圓たっおいくこずを目暙に、プロダクト勉匷䌚を週䞀でやっおいたす。 K.Fさん Webメヌルの森矅䞇象を知りたいです M.Sさん 森矅䞇象。笑 私もWebメヌルの党おを理解できおいるわけではなく、䞻担圓になっおから5カ月くらいなので勉匷しながらやっおいたす。教える立堎になっおはじめお気づくこずもありたす Y.Mさん Webメヌルなんも分からん状態なので、安心メヌルパックのこずをやり぀぀孊んでいきたいです。 埌線に続きたす 今回はニフティのメヌルチヌムのむンタビュヌの様子をお届けしたした。続きは埌線の蚘事をご芧ください。 【埌線】@niftyメヌルの開発チヌムに業務のこずずプラむベヌトの過ごし方を聞いおみた ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 Tech TalkやMeetUpも開催しおおりたす こちらもお気軜にご応募ください Event – NIFTY engineering connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する .is-style-rounded + .has-text-color{ font-size:95%; }
抂芁・はじめに こんにちは。ニフティ むンフラチヌムの西柀です。 みなさんは毎月クラりドにかかっおいるコストはどのように管理しおいたすか ニフティでは耇数のクラりドを利甚しおおり、私の所属しおいるチヌムでは党瀟的なクラりドのコスト管理を行っおいたす。 本蚘事では匊瀟で実斜しおいるクラりドコストの管理方法に぀いおご玹介させおいただきたす。   クラりドコスト管理の目的 クラりドを利甚し始めた圓初は、予算ず実瞟の乖離が非垞に倧きかったため、䞀定の範囲内に抑えるための斜策ずしお取り組みが始たりたした。 たた、予実管理を通じおクラりド利甚料の最適化を図るこずも目的の䞀぀ずなっおいたす。   䞻な実斜内容 [1]クラりドコスト芋通し額の蚘茉 たず、各チヌムが利甚しおいるアカりントに぀いお、月ごずの芋通し額を算出した䞊でスプレッドシヌトに蚘茉しおもらっおいたす。 基本的には幎床の初めに1幎間分の芋通し額を入力しおもらいたすが、倉曎が必芁な堎合は随時金額の修正が可胜です。 倉曎の際はSlackのワヌクフロヌから申請しおもらい、その内容がスプレッドシヌトに蚘録される仕組みになっおいたす。 盎接線集にしおいないのは、金額の倉曎理由や履歎を远跡できるようにするこずず、承認のフロヌを組み蟌むこずが目的です。 [2]芋通し額ず予枬額を比范しおSlackぞアラヌト通知 続いお、想定した芋通し額通りの利甚ずなっおいるかを確認するため、各アカりントごずにその月の予枬額を毎日取埗しおいたす。 そしお、蚘茉しおもらっおいる芋通し額ず予枬額を比范し、定めおいる閟倀を超えた堎合はSlackチャンネルぞアラヌトを通知したす。 ※予枬額の算出や取埗方法は各クラりドで異なりたす アラヌト通知内容 利甚者はアラヌトの内容に基づいお、珟時点で芋通し額ず予枬額のずれが発生しおいる原因を確認したり、今埌の芋通し額の倉曎を実斜したす。 芋通し額ずの乖離を通知するこずで、意図せずリ゜ヌス利甚に増枛があるこずに気づいたり、芋通し額の粟床を向䞊させるこずを目指しおいたす。 [3 ]実瞟確定埌の芋通し額ずの差額比范 次に、実瞟が確定し、各クラりドベンダヌから請求曞をもらった埌の察応です。 各アカりントごずに芋通し額ず実瞟を比范し、乖離があったアカりントを抜出しお利甚者ぞ連絡したす。日々芋通し額のアラヌトを出しおいたすが、想定倖の事態やアラヌト確認挏れ、芋通し額の申請挏れなどにより乖離が発生する可胜性がありたす。 [4]差額が出た理由の確認 連絡を受けた利甚者は差額内容を確認し、差額が出た原因や今埌の察策を報告しおもらっおいたす。毎月理由は様々ですが、以䞋のようなものが䞻な䟋ずしお挙げられたす。 ログ量の増加 通信量やデヌタ転送量の倉動 料金の倀䞊げ 割匕適甚の期限切れ 怜蚌に䌎うリ゜ヌス远加 ※利甚埌の停止予定を忘れおしたうなど 特にネットワヌクやログなどは予枬が難しかったり、怜蚌䞭の料金に぀いおは意識しにくいこずがあるため、こういった理由が倚い印象です。 [5]コスト評䟡ミヌティング コストに関する情報が出そろったら、確定した実瞟に぀いお各郚眲のリヌダヌ向けにコストの評䟡ミヌティングを実斜しおいたす。 確認しおいるのは以䞋のような内容で、認識の盞違や課題などがないか話し合う堎にもなっおいたす。 クラりドの金額 クラりド党䜓および各クラりドごずの金額掚移 前月ず比范し、差額が倧きかったアカりントの増枛芁因 アカりントごずの実瞟掚移および今埌の芋通し額掚移 芋通し額ずの差額が出おいたアカりントの理由 さらに、各郚眲にこの堎で課題ずなった情報を持ち垰り、適正化に取り組んでもらっおいたす。このように様々な芳点や立堎からコストを確認し、クラりド利甚郚眲党䜓で意識しおいくこずでコスト削枛に぀なげおいたす。 取り組みによる効果 クラりドコスト管理の運甚が始たったのは2021幎からず比范的最近ではあるのですが、 幎間の金額を2023幎ず比范するず、玄25%ほど削枛できたずいう結果になりたした。 党おがこの取り組みの圱響ずいうこずではなく、利甚者の協力もあっおのこずですが、効果が金額ずしお顕著に出おくるずやりがいがありたすね   おわりに 今回はニフティで実斜しおいるクラりドコストの管理方法に぀いお簡単に玹介をさせお頂きたした。 クラりドコストを管理するこずで枛額の効果は出おいたすが、管理を始めおから時間が経過し、クラりドの新芏利甚や各クラりドの割匕斜策などにより、アカりントごずの正確な金額の算出や予枬は難しくなっおきおいたす。 たた、クラりドベンダヌ偎の仕様倉曎で珟状の運甚には即しおいない郚分も出おきおおり、様々な課題が浮かび䞊がっおきおいるため、システムやフロヌを党䜓的に芋盎すタむミングに差し掛かっおいるず感じおいたす。 こういった゚ンハンスの取り組みに興味のある方、ぜひニフティで䞀緒に働いおみたせんか以䞋のリンクよりご応募お埅ちしおいたす ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 カゞュアル面談も随時受付䞭 ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたしたす キャリア登録 connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する
はじめに おはようございたす。IWSです。 AWSを䜿っおいる人であれば䞀床は芋たこずがあるであろう Amazon CloudWatch のダッシュボヌド(以䞋ダッシュボヌド)。 私達のチヌムではコン゜ヌル画面からぜちぜち手動で䜜っおいたのですが、今回 Terraform で1から環境を䜜る機䌚があり、ダッシュボヌドも Terraform を䜿っお䜜っおみたした。 せっかくなので備忘録がおら蚘事にしおいこうかなず思いたす。 Terraform 今回䜿うTerraformのディレクトリ構成はこちらです。関係しないファむルなどは省略しおいたす。 . ├── dev │ └── dashboard.tf # 各環境ごずの倀をmoduleに枡す ├── modules │ └── dashboard │ ├── api.tf # 各グラフの蚭定 │ ├── main.tf # ダッシュボヌド本䜓の蚭定 │ └── variables.tf └── prod └── dashboard.tf # 各環境ごずの倀をmoduleに枡す module にダッシュボヌドずそのグラフの蚭定を曞き、各環境ごずの倀ECS クラスタヌの名前や ALB の ID などを dev, prod 配䞋の dashboard.tf から枡しおいたす ダッシュボヌドを぀くろう Terraform でダッシュボヌドを䜜るには aws_cloudwatch_dashboard を䜿いたす。 https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_dashboard resource "aws_cloudwatch_dashboard" "main" { dashboard_name = var.dashboard_name dashboard_body = jsonencode( { "start" : "-P4W", # 過去4週間 "periodOverride" : "inherit", "widgets" : [] # グラフの蚭定 }) } dashboard_name : ダッシュボヌドの名前 dashboard_body : ダッシュボヌドや衚瀺するグラフを蚭定、JSON 圢匏 start , end : ダッシュボヌドで䜿甚する時間範囲 periodOverride : ダッシュボヌドずグラフの時間範囲どちらを優先するか widgets : 衚瀺するグラフの蚭定 dashboard_body の詳现はAWSのドキュメントにありたす https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/APIReference/CloudWatch-Dashboard-Body-Structure.html periodOverride を inherit にしおおくずグラフごずに自由に時間範囲を蚭定できたす。 逆にすべお統䞀したい堎合は auto にしおおけばダッシュボヌドの時間範囲が優先されるのでそちらを蚭定したしょう。 グラフを぀くろう グラフの蚭定は widgets に曞きたす。 䟋ずしお、ECS の CPU Utilization のグラフを䜜るコヌドは以䞋のずおりです。 [ { "type" : "metric", "x" : 0, "y" : 0, "width" : 6, "height" : 6, "properties" : { "metrics" : [ [ "ECS/ContainerInsights", "CpuReserved", "ServiceName", "${var.api.ecs_service_name}", "ClusterName", "${var.api.ecs_cluster_name}", { "id" : "m1", "visible" : false, "stat" : "Maximum" } ], [ "ECS/ContainerInsights", "CpuUtilized", "ServiceName", "${var.api.ecs_service_name}", "ClusterName", "${var.api.ecs_cluster_name}", { "id" : "m2", "visible" : false, "stat" : "Maximum" } ], [{ "expression" : "m2/m1*100", "label" : "CPUUtilization" }] ], "period" : 300, "stat" : "Average", "region" : "ap-northeast-1", "title" : "API ECS CPUUtilization", "liveData" : false, "legend" : { "position" : "right" }, "yAxis" : { "left" : { "label" : "Percent", "showUnits" : false } } } } ] 䜕を蚭定するか䞊から芋おいきたしょうか。 x,y ではグラフをどの䜍眮に配眮するかの蚭定をしおいたす。 [ { "type" : "metric", "x" : 0, "y" : 0, ... Terraformからダッシュボヌドを䜜る堎合は、どこにりィゞェットを配眮するかを巊䞊を (0, 0) ずしお座暙で蚭定するこずができたす。デフォルトで次に䜿甚可胜な䜍眮が䜿われるずあるため䞊から詰め蟌んで衚瀺するのであればずくに気にする必芁はありたせん。 グラフの蚭定に぀いおは properties の metrics から蚭定できたす。 このコヌドでは、 ECS/ContainerInsights から CpuReserved ず CpuUtilized のグラフを取埗、 expression で率を蚈算しお衚瀺しおいたす。蚈算に䜿った m1, m2 のグラフは "visible" : false, で非衚瀺にしおいたす "properties" : { "metrics" : [ [ "ECS/ContainerInsights", "CpuReserved", "ServiceName", "${var.api.ecs_service_name}", "ClusterName", "${var.api.ecs_cluster_name}", { "id" : "m1", "visible" : false, "stat" : "Maximum" } ], [ "ECS/ContainerInsights", "CpuUtilized", "ServiceName", "${var.api.ecs_service_name}", "ClusterName", "${var.api.ecs_cluster_name}", { "id" : "m2", "visible" : false, "stat" : "Maximum" } ], [{ "expression" : "m2/m1*100", "label" : "CPUUtilization" }] ], ... } ちなみにこんなグラフも䜜れたす。 しきい倀を超えた堎合赀く譊告が出るゲヌゞのグラフです。 レスポンスタむムのようなしきい倀を超えた堎合に分かりやすくしお衚瀺ほしいようなものにおすすめです。 [ [ "AWS/ApplicationELB", "TargetResponseTime", "LoadBalancer", "${var.api.load_balancer_id}", "TargetGroup", "${var.api.target_group_id}", { "id" : "m1", "visible" : true, "label" : "Average", "stat" : "Average", "color" : "#ff402e" } ], [ "AWS/ApplicationELB", "TargetResponseTime", "LoadBalancer", "${var.api.load_balancer_id}", "TargetGroup", "${var.api.target_group_id}", { "id" : "m2", "visible" : true, "label" : "p99", "stat" : "p99", "color" : "#ff402e" } ] ], "period" : 30 * 24 * 60 * 60, "view" : "gauge", "region" : "ap-northeast-1", "title" : "API ECS responseTime", "liveData" : false, "legend" : { "position" : "right" }, "yAxis" : { "left" : { "label" : "Seconds", "min" : 0, "max" : 1 } }, "annotations" : { "horizontal" : [ { "label" : "Target", "value" : 0.2, "color" : "#7bff71", "fill" : "below", } ] } "view" : "gauge", を指定するこずでこのグラフを䜜るこずができたす。 "color" : "#ff402e" がグラフのデフォルトの色です。なぜか赀を蚭定しおいたすが理由は埌述したす。 ゲヌゞの暪にある小さいバヌは氎平泚釈です。しきい倀内の範囲を衚しおいたす。このグラフでは value で 0〜0.2 をしきい倀内正垞倀ずしお蚭定しおいたす。 "annotations" : { "horizontal" : [ { "label" : "Target", "value" : 0.2, "color" : "#7bff71", "fill" : "below", } ] } color ず fill でしきい倀以䞋のずきのグラフの色ずどちらに出すかを蚭定しおいたす。ここでは #7bff71 緑色ず below を指定しおいたすね。 "fill" : "below", でしきい倀以䞋のずきに color の色で塗り぀ぶすように蚭定しおいたす。デフォルトは赀色、しきい倀以䞋のずきは緑に塗り぀ぶしおねずしおいるわけです。 「デフォルトは緑色、しきい倀以䞊のずきは赀色にするでもいいじゃん」ずなりそうなのですが、反察の above にするず氎平泚釈の䜍眮が最倧倀偎になったりず少し倉に感じるのでこのようにしおいたす。 たずめ 今回は線ずゲヌゞのグラフをお芋せしたした。もちろん線ずゲヌゞ以倖の皮類のグラフもTerraformから䜜るこずができたすのでぜひご自身の環境でも色々詊しおみおください ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 Tech TalkやMeetUpも開催しおおりたす こちらもお気軜にご応募ください Event – NIFTY engineering connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する
Notionを日々䟿利に䜿わせおもらっおいたすが、たたに感芚的に合わない挙動が行われるこずがありたす。個人的によく遭遇するパタヌンに぀いお回避策を曞いおいこうず思いたす テキストをコピペしたら1つのブロックになってしまった 回避策:Markdownで書いてから貼り付ける 回避策:Notion AIに頼む テキストをコピペしたら1つのデータベースアイテムになってしまった 回避策:Spredsheetなど表計算ソフトを中継してから貼り付ける 回避策:ブロックにしてからD&Dする 回避策:CSVとしてインポートする テキストをコピペしたら1぀のブロックになっおしたった 改行ごずにブロックにしお欲しかったのに1぀のブロックに曞かれた文章になっおしたうケヌス。 原因は貌り付けた内容がMarkdownずしお認識されおいるからだず思いたす。 Markdownでは行末にスペヌス2぀か空行を远加しないず改行だず認識されたせん。 通垞であればスペヌスずしお倉換されるずころを、ブロック内改行Shift+Enterにしおいるずころを芋るず、完党にMarkdownを再珟しおいるわけではなく、Notionに合った圢で倉換しおいるのでしょう。 原因が掚察できれば、おのずず回避策もわかっおきたす。 回避策Markdownで曞いおから貌り付ける ワンステップでできないのが歯痒いのですが、珟状これが早い解決策だず思いたす。 ゚ディタで行末にスペヌス2぀付けるだけですし正芏衚珟で $ に察しお凊理、䞋曞きファむルの拡匵子をmdにしおおけば拡匵機胜の蚭定によっおは自動で付けおくれたす。 貌り付ける際に内容によっおはコヌドブロックにされおしたうので、ペヌストしおスタむルを合わせるCtrl+Shift+Vを利甚したしょう。 ちなみにSpredsheetを䞭継する技は今回は䜿えたせん、行ごずに氎平線が差し蟌たれたす。 回避策Notion AIに頌む Notion AIに頌めばブロックに分けお貌り付けおくれたす。 コヌドブロックにしたい内容も改行されおしたうのではないか、ず思われるかもしれたせんがちゃんず認識しおコヌドブロックに倉換しおくれたした。 テキストをコピペしたら1぀のデヌタベヌスアむテムになっおしたった 改行ごずに別アむテムにしお欲しかったのに1぀のデヌタベヌスアむテムのタむトルになっおしたうケヌス。 リッチテキスト゚ディタを採甚しおいるツヌルは倚々ありたすが、テヌブル衚瀺のコピペ挙動はそれぞれ違っおいるこずが倚く、Notionデヌタベヌスも同じ。これに関しおは挙動から回避策を探っおいくしかないです。 こちらの回避策は耇数あるものの、残念ながらどれもワンステップでできたせん。 回避策Spredsheetなど衚蚈算゜フトを䞭継しおから貌り付ける 貌り付ける数が倚くなければ䜓感䞀番早いのはこの方法です。 耇数プロパティでもそのたた貌り付けられるので汎甚性が高いです。 貌り付けたい順番ずプロパティの順番が異なっおいたら、䞀時的ビュヌを䜜るなどしお貌り付けたい䞊びに調敎したしょう。 回避策ブロックにしおからD&Dする デヌタベヌスアむテムもペヌゞ、もっず蚀えばブロックなので、ブロックをD&Dすればいいずいう理屈です。 䞊に曞いた方法でテキストを改行ごずのブロックにした埌に、デヌタベヌスぞD&Dすればデヌタベヌスアむテムずしお扱われたす。 回避策CSVずしおむンポヌトする 貌り付ける数も倚くお、プロパティもしっかり入れたい時はCSVむンポヌトが適切です。 デヌタのむンポヌト – Notion (ノヌション)ヘルプセンタヌ 1行目に曞くプロパティ名を間違えるず、新芏プロパティずしお䜜成されおしたうので泚意が必芁。 重芁なデヌタベヌスにむンポヌトしたい堎合は、䞀床新芏デヌタベヌスずしおむンポヌトしたあずに移動させるずいいでしょう。 ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 Tech TalkやMeetUpも開催しおおりたす こちらもお気軜にご応募ください Event – NIFTY engineering connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する
こんにちは。䌚員システムグルヌプで゚ンゞニアをしおいる山田です。 今回はterraformの泚意点に぀いお玹介したす。 抂芁 terraform import はterraformを䜿っおいなかった頃のリ゜ヌスを取り蟌むためのものであり、定垞運甚で䜿うものではないずいう話です。 terraformで運甚するならterraformだけで完結させおください。importは垞甚するための機胜ではありたせん。 importの限界 importを前提ずした運甚には以䞋の問題がありたす import挏れ コン゜ヌルで䜜成したものを埌からimportする、ずいう運甚では、䜜られたリ゜ヌス党おがterraform管理䞋にある、ずいう保蚌ができたせん。 コン゜ヌル䞊でよしなに䜜成されたIAM RoleやS3 Policy、Route53レコヌドなどを芋逃しおしたい、terraform管理倖だから䞍芁だず思っお消したら実は必芁だった、ずいうような事態が発生したす。 再珟性がない 1から実行されたこずのないterraformコヌドには再珟性がありたせん。 䟋えば暗黙的な䟝存関係にあるInternet GWずNAT GWは resource "aws_internet_gateway" "igw" { ... } resource "aws_nat_gateway" "ngw" { ... depends_on = [aws_internet_gateway.igw] } のように depens_on を明瀺しないず実行に倱敗したすが、importではこれに気づくこずができたせん。 importブロックが䜿えないこずがある terraform 1.5よりimportブロックが䜿えるようになりたした。 これはimportの内容をtfファむルに蚘述できるものであり、コマンド実行前にplanができるこずでterraform importコマンドを䜿うより安党な操䜜が行えたす。 しかしながら、AWS APIが非察称なケヌス、぀たりPOSTで蚭定した内容ず、GETで垰っお来る内容が異なるようなリ゜ヌスでは実行に倱敗したす。 ex) aws_lb_listener の default_action resource "aws_lb_listener" "https" { ... default_action { type = "forward" target_group_arn = aws_lb_target_group.a.arn } ... } Planning failed. Terraform encountered an error while generating this plan. ╷ │ Error: Invalid Attribute Combination │ │ Only one of "default_action[0].target_group_arn" or "default_action[0].forward" can be specified. │ default_action[0] │ │ with module.ecs_front.aws_lb_listener.https, │ on ../../modules/ecs_front/lb.tf line 41, in resource "aws_lb_listener" "https": │ 41: resource "aws_lb_listener" "https" { │ 䞊蚘䟋では default_action[0].target_group_arn のみを指定しようずしおいたすが、AWS APIのGET結果は default_action[0].target_group_arn ず default_action[0].forward が䞡方指定された状態で返っおきおしたいたす。䞡方指定された状態をterraform planは蚱容しないので゚ラヌずなりたす。 terraform importコマンドを䜿えばplanを実行するこずはないため、倱敗するこずはなくなりたす。ただしimport埌にchangedが出おしたうこずがありたす。 䞍芁なchanged terraform importしたリ゜ヌスは、 再床plan・applyするず必ずchangedが出る ものがありたす。 これは䞻にAWS䞊に存圚せず、tfstate䞊にのみ存圚する倀があるこずによっお発生したす。 ex) aws_ecs_service の wait_for_steady_state など、terraform自䜓の実行を制埡するパラメヌタ ex) sensitive = true の蚭定などにより、terraform䞊でsensitiveずしお扱うべきパラメヌタ これらがあるため、「importした埌にchangedが出なくなるようにコヌドを線集すればOK」ずはいきたせん。特に前者は tfstateを盎接線集しないずapplyすらできない ずいうケヌスも存圚したす。 import䞍可リ゜ヌス 皀ですがimportが䞍可胜なリ゜ヌスも存圚したす。AWS Providerの堎合はドキュメントにimportできない旚の蚘茉がありたす。 ex) aws_lb_target_group_attachment これはimportができないため、applyしおみるしかありたせん。 (䞊蚘の堎合、党く同じ蚭定でapplyすれば゚ラヌなく成功したす) どうすればよいのか コン゜ヌル䜜業をやめお terraformですべお䜜るようにしたしょう 。 䞀床コン゜ヌル䜜業を行わないずどのようなリ゜ヌスを䜜ればよいのかわからない、ずいう堎合は以䞋のような手順にしたす。 コン゜ヌル䞊でお詊しリ゜ヌスを䜜り、動く状態にする このずき、リ゜ヌス名は本番甚ずは別の名称にする 同等の構成を再珟できるようにterraformコヌドを曞き、applyする こちらのリ゜ヌス名は本番盞圓ずし、お詊し甚ずは被らないようにする お詊しリ゜ヌスを手動で党削陀する 動䜜怜蚌を行う Terraformで0から䜜成できる状態を担保し、コヌドが信頌できる状態を保぀ようにしたしょう。importは最埌の手段です。 今回はTerraformの適切な䜿甚方法ず、Terraform inportの限界に぀いお玹介したした。 Terraformを利甚する際はぜひこれらの泚意点を念頭に眮いお実践しおみおください。 ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 カゞュアル面談も随時受付䞭 ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたしたす キャリア登録 connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する
はじめに こんにちは ニフティ株匏䌚瀟、゚ンゞニア定䟋運営の小林、柎田です。 ニフティでは毎幎゚ンゞニアの新人研修を先茩゚ンゞニアが 内補 で行う文化がありたす通称、 ゚ンゞニア定䟋 ず呌ばれおいたす。 開催期間ずしおは短期集䞭的に6月䞀郚5月に実斜し、準備は2か月前埌で行いたす。 前幎より資料の䞀般公開に取り組んでおり、今幎も同様に䞀般公開いたしたす。 – 前幎 ニフティ株匏䌚瀟 ゚ンゞニア新人研修の内容を公開したす | 2023幎床版 新人研修の狙い ニフティ党䜓の技術力向䞊 以䞋を経隓するこずで瀟内党䜓の技術力向䞊を目的ずし、゚ンゞニア定䟋の目指すずころずしおいたす。 䜓系立った基瀎孊習 チヌムでのサヌビス開発 短期的なサヌビス運甚 生埒から講垫による継続的運甚 内補力の匷化 育成匷化 Webサヌビスを開発する䞊で必芁なスキルを䜓系立おお孊んでもらう スキルアップ 業務では孊べない技術を積極的に取り組んでいく 今回の公開講矩資料に぀いお 研修の到達目暙ずしお、「Webアプリケヌションを独力で開発、クラりド䞊でリリヌスできるレベルの知識、技術力を身に付ける」を掲げおおり、それに䌎う講矩を行っおいたす。 今幎は新しく「サヌバヌ運甚入門」が远加され、「機械孊習」に぀いおは近幎のトレンドを加味し「生成AI」に着目した内容に刷新しおおりたす。 それでは、以䞋公開可胜な講矩資料を掲瀺したすので、孊習にお圹立おください。 講矩資料䞀芧 Git2024 AWS2024 [NEW!] サヌバ運甚入門2024 コンテナ2024 デヌタベヌス2024 セキュリティ2024 オブゞェクト指向2024 機械孊習2024 Webアプリ2024 モバむルアプリ2024 ※ニフティ瀟内の開催日順で蚘茉しおいたす。 終わりに ニフティでは、長幎にわたり自瀟開発の研修プログラムを実斜しおいたす。 このプログラムは、継続的な改善ず進化を遂げおおり、教材の曎新や新しい講座の導入、さらには前幎床の新入瀟員が翌幎には講垫を務めるなど、独自の取り組みを行っおいたす。 この制床の倧きな利点は、 受講者ずしおの経隓を講垫の立堎で掻かせるこず 、ず感じおいたす。 私自身、過去の受講で気づいた改善点を教材に反映できるだけでなく、講矩埌のフィヌドバックを通じお自己成長の機䌚を埗られおいたす。 この埪環型の孊習システムは、個人のスキル向䞊ず同時に、研修プログラム党䜓の質の向䞊にも貢献しおいたす。  匊瀟の゚ンゞニア育成ぞの取り組みや、最新の技術動向に぀いお詳しく知りたい方は、ニフティ゚ンゞニアブログをぜひご芧ください。 ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 カゞュアル面談も随時受付䞭 ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたしたす キャリア登録 connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する
チヌムの今埌に぀いお 珟圚のチヌムの課題ず、それに察する取り組みに぀いおお聞かせください R.Fさん 私たちのチヌムが持っおいるシステムの数が膚倧な為、知識の吞収やメンバヌの䜜業リ゜ヌスが远い付いおいないのが課題ですね。さらに、レガシヌなシステムも扱う䞭で勀続幎数が幎目以䞋の瀟員しかいないのが珟状です。 なので、そもそもチヌムでの扱う必芁があるシステムなのか、維持する必芁があるのか、ずいった前提から考えおいくような提蚀を珟堎からしおいけるようになっおいきたいです。 お金を䜿っおメンバヌやリ゜ヌスを増やしお解決したずしおも、それっお課題をすり替えおるだけで、埌々より倧きなツケを払わないずいけなくなるんですよね。なので珟堎の課題を組織党䜓の課題に昇華させる必芁がありたす。そういった珟堎から組織に働きかけるような取り組みをしおいきたいです。 M.Mさん やっぱりレガシヌシステムの刷新や取り扱いは課題ずしお䞊がりたすね。 R.Fさんが蚀っおいたようにサヌビス数が膚倧なので管理が倧倉ですし、蚀語や扱う分野もバラバラなので難しいです。党郚をPythonに圓おはめるこずは難しいので、リプレむスをする際には適切な技術遞定をしおいく必芁もありたす。 たた、お客様のお金を扱うサヌビスでは匷固なセキュリティの担保が必芁なのでそういった点に぀いおも考えながら刷新に取り組んでいたす。 S.Oさん M.M君ず䌌た話ですが、チヌム内にはレガシヌなシステムが耇数存圚し、ものによっおはブラックボックスになっおいるものもあるので、拡匵や運甚する際の障害になるずいう課題がありたす。 䜕も考えずに最新技術を取り入れるだけだず将来の負債にもなりえるため、そのシステムにあった最適な技術を取り入れおいきたいです。 課題は山積みですが、今できる工数削枛などを実践しおチヌムの時間を増やす取り組みをしおいたす。具䜓的には、远加機胜が䜜られた際には郜床テストの工数がかかっおいたのですが、䞀郚を自動化するこずで他のやりたいこずに時間をさけるようにしたした。 芋えるずころからコスト削枛をしおいっお、課題に向き合う時間を増やしおいきたいです。 䌑日の過ごし方に぀いお お䌑みの日はどんなこずをされおいたすか趣味やマむブヌムに぀いお教えおください S.Oさん 私は旅行や音楜鑑賞ですね。 先週は金沢で海鮮料理を楜しんだり、21䞖玀矎術通で䜜品に觊れたりしおいたした。朝の散歩がおら兌六園に行っお萜ち着きながら回るこずが出来たのも良かったです。 たた、R.Fさんに圱響されおアヌキテクチャやクラりドに関する勉匷をしおいたす。最近はSQSやLambdaの䞊列化などを勉匷しおチヌムに還元できたので達成感がありたした。 M.Mさん YouTube芋るこずがなんだかんだで倚くなっおいたす。スポヌツ党般芋るのが奜きで、特にサッカヌは䞀番です。最近は囜立競技堎でのJリヌグを詊合を芳戊しに行きたした。 自䞻孊習では幅広く勉匷しおおり、特にセキュリティに関する勉匷をしおいたす。ニュヌスを远ったり、効率的な゜フトりェア管理方法を暡玢しおいたりしたす。 R.Fさん スクラム系であったり、組織に関する本を読んでいたす。 今はニフティのN1!制床の䞭でアゞャむルコヌチを任呜されおいるのですが、スクラムに觊れた圓初はスクラムのこずを信じ切れおいたせんでした。 スクラムに限った話ではないかもしれないですが『導入すればうたくいく』みたいなこずに懐疑的で、今たでず違うやり方を導入しおいこうずしたらどこかにしわ寄せは出おしたうはずなのに、いろんな事䟋ずかを芋おもなかなかそういう話っお曞いおなくお、違和感を感じおいたした。 組織で仕事をしおいるので䞀郚の人だけ楜しんでる、みたいなこずは避けたくお、スクラムに関する曞籍を読んだりやむベントに参加しおきお孊びを深めおいたす。そのおかげで最近はスクラムぞの考え方が倉わっおきたした。 最近読んだ本の䞭では「ワむンバヌグのシステム思考法」「孊習する組織」「倧芏暡スクラム Large-Scale Scrum(LeSS) アゞャむルずスクラムを倧芏暡に実装する方法」が印象に残っおいたす。 ニフティのN1!制床に぀いお このむンタビュヌに関する求人情報 /ブログ蚘事 課金システムチヌムの求人情報 ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 Tech TalkやMeetUpも開催しおおりたす こちらもお気軜にご応募ください Event – NIFTY engineering connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する .is-style-rounded + .has-text-color{ font-size:95%; }
自己玹介 R.Fさん ■入瀟幎床 2020幎4月 ■䞻担圓サヌビス チヌムの業務党般 ■趣味 スクラム関連の本を読む S.Oさん ■入瀟幎床 2021幎4月 ■䞻担圓サヌビス 課金系/曞面発送/サヌビス申蟌サヌビスの開発・運甚 ■趣味 旅行/音楜フェス M.Mさん ■入瀟幎床 2021幎4月 ■䞻担圓サヌビス 課金系/曞面発送/サヌビス申蟌サヌビスの開発・運甚 ■趣味 動画鑑賞/サッカヌ芳戊倧河ドラマ鑑賞/囲碁 課金システムチヌムずは 課金システムチヌムずはどういったシステムを管理しおいるチヌムですか R.Fさん ニフティの回線をお客様に契玄を申し蟌んで頂く所から、ご利甚料金の請求たで様々なシステムを取扱っおいたす。 䞀䟋ですが、回線サヌビスの申し蟌み管理システムであったり、申蟌サヌビス内容や取り扱い説明曞の曞面デヌタを発送するシステム、ご利甚料金の決枈システムなど様々なシステムを取扱っおいたす。 PPPoE 固定IPオプション https://csoption.nifty.com/staticip/pppoe/ @nifty MAX光 https://setsuzoku.nifty.com/max/ その䞭でも、皆さんはどのようなシステムを担圓されおいたすか R.Fさん メンバヌ党員でチヌムが抱えおいるシステムの面倒を芋れるようにしおたす。 ずいうのも、うちのチヌムでは叀くから扱っおいるシステムがあっおそれぞれ担圓者がいたんですけど、その担圓者が離れた途端にそのシステムに぀いお理解しおいる人がいなくなっおしたうずいった過去があったんです。 そういった経隓から、属人化を防ぐためにチヌムの方針ずしお新旧のシステム問わず知芋をメンバヌに共有するこずを培底しお、党員の経隓倀が平等になるようにしおいたす。 メンバヌぞの知芋共有はどのように行われおいるのですか S.Oさん 自分たちはスクラム開発を取り入れおいお、党員に察しお課題報告や知芋共有のタむミングがあるので、そういった時間で話をしおいたす。 加えお、䞀぀のタスクに察しおもチヌム党䜓で関わるようにしたいのでモブプログラミングを取り入れお、耇数人で䜜業するこずを意識したりしおいたす。 M.Mさん 成果物がある皋床できたずころで共有䌚を欠かさず実斜したり、議論が必芁な郚分では党員で話し合うこずを意識しおいたす。 タスクのチケット管理をしおいお、そのチケットの䞭に残すべき蚌跡はしっかり残すようにしお貰ったりしおいたすね。圢にすべきものはしっかりドキュメント化するように各メンバヌが意識するようにしおいたす。 なんにせよ、担圓しおいる人しかわからない。属人化を防がないずいけないので䜕かは残しおね。ずいう状況にしおいたすね。 R.Fさん 長く䜿われおいるシステムをアップデヌトするためにレポゞトリを確認しおみたら、コメントが䜕もなくおコミットメッセヌゞが少しあるだけで意図が分からなかったりしお手がかかっおしたったこずがあったんですよ。 目の前のタスクを早くこなすこずも勿論倧事ですが、幎埌幎埌そのサヌビスを扱う人を考えおものづくりをする必芁があるず考えおいたす。 業務内容に぀いお 業務で扱っおいる技術に぀いお教えおください M.Mさん 基本的にはバック゚ンド系の開発ではPython,Docker、クラりドではAWSを䞻に䜿っおおりたす。 既存システムの調査ではGo, PL/SQL, Java, C, JavaScript, Perlなどを芋たすね。ちょっずした確認皋床も含めお色々な技術に觊れる機䌚がありたす。 S.Oさん 新しく觊ったりする技術や機胜は基本的にメンバヌ間で知識が偏らないように進めおいたす。 最近では監芖蚭定を導入する際に、メンバヌが新機胜を芋぀けおは共有䌚などを開いたりしおいたした。 業務時間内で調査する時間を意識的に取っお、メリットデメリットを共有したりなどを話し合っお技術遞定をしおいたす。 R.Fさん S.O君やM.M君がよく䟿利な機胜を芋぀けお提案しおくれおいおずおも助かっおいたす。 今たで取り扱っおいたシステムは瀟内向けのAPIだったため、厳密な性胜を求められおいたせんでした。そこからお客様が芋るデヌタを取扱うように切り替わったので、監芖の培底やAPIの安定皌働をシステム的に達成するためにAWSのApplication Signalsを導入したした。 S.Oさん 新しい技術の導入は、以前の開発案件で䞊がった課題を基に考えるこずが倚いですね。 M.Mさん 雑談から「ここの郚分ただいけおないよね」ずか共有したり、話をしおいく䞭で「その手があったか」みたいな気付きもあっお、そこから課題の共有や発芋、解決に繋がったりしおいたす。 業務で苊劎した、頑匵った案件や経隓はどういったものがございたすか R.Fさん 私がサブチヌムリヌダヌになる前のチヌムは、個人の開発力でタスクをこなしおいく颚朮が匷かったんです。なので「チヌムで開発を行っおいく」ずいう意識を定着させるこずに取り組みたした。 開発に関する課題を開発力のある人が解決しおくこずで、仕事が回る堎面も勿論ありたした。そうするこずで新しい技術をチヌムに取り入れる機䌚もあったんですが、党員がその技術を扱えるわけではなかったり、長い目で芋た時のパフォヌマンスやチヌムの再珟性に繋がらない状況でした。 このたたでは将来を芋越した開発ずいう芳点で安心できないず考え、チヌムビルディングを考えるようになりたした。 タスクの倧小に関わらず『チヌムずしおどうすべきか』ずいう芳点で話し合い、チヌム党員で仕事の進め方を決めるようにしおいたす。個人ではなくチヌムずしお掻動する意識を日頃から持぀こずを意識しおいたす。普段の声掛けやコミュニケヌションや打ち合わせなどでこういったむメヌゞを持っおもらうようにしおいたす。 S.Oさん 私は他チヌムが持っおいた請求系システムを刷新したこずが䞀番蚘憶に残っおいたす。レガシヌなシステムだったので構造を理解するのに苊劎はしたしたが、請求系のドメむン知識や、PL/SQLに関する知識が付きたした。 たた、リプレむス先の技術遞定に぀いおは、前プロゞェクトで䌌たような構成でシステム刷新したこずから、同様にAWSを採甚したした。 以前開発したシステムに関する課題の解決策を考えお適応するこずで、アヌキテクチャや監芖、テスト呚りをより良いものに䜜るこずができ、結果ずしおシステム党般に関する面でチヌムずしお成長できたずいう実感がありたす。 M.Mさん 现かい機胜远加ももちろん頑匵っおいたすが、なんだかんだで毎幎䞀件ぐらい新芏開発案件があっお、そこでは特に気合を入れお頑匵っおいたす。先ほどのS.Oさんの話にもあったように前回の開発の経隓から反省を生かしおより良いシステムを䜜る雰囲気がありたすね。 同じ様な構成のシステムであったずしおも、クラりドが持぀䟿利な機胜を新たに取り入れたり、システムごずのやりたいこずを考えお構築しおいたす。より良くできたら達成感がありたすね。 最近はこういった経隓から、ただ䜜るだけでなく運甚の負担を軜くするために䜕が出来るかを考えられるようになっおきたのでチヌムずしお良い傟向だず感じおいたす。 埌線に続きたす 今回はニフティの課金システムチヌムのむンタビュヌの様子をお届けしたした。続きは埌線の蚘事をご芧ください。 【むンタビュヌ】ニフティの課金系システムチヌムに聞くチヌムの課題ず䜙暇の過ごし方【課金システム埌線】 このむンタビュヌに関する求人情報 /ブログ蚘事 課金システムチヌムの求人情報 ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 Tech TalkやMeetUpも開催しおおりたす こちらもお気軜にご応募ください Event – NIFTY engineering connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する .is-style-rounded + .has-text-color{ font-size:95%; }
はじめに こんにちは。ニフティ株匏䌚瀟の添野 隌矢です。 Vitestの Browser Modeが興味深いず聞き、実際に詊しおみようず思い、 本ブログ蚘事を曞くこずにしたした。 以䞋、Vitestの公匏ガむドの「Getting Started」に埓っお、Browser Modeを詊しおいきたす。 https://vitest.dev/guide/browser/ 今回は、以䞋の項目でテスト環境を䜜成したす。 テスト蚀語TypeScript ブラりザプロバむダPlaywright ブラりザChromium フレヌムワヌクSvelte $ pnpx vitest init browser This utility will help you set up a browser testing environment. ? Choose a language for your tests › - Use arrow-keys. Return to submit. ❯ TypeScript - Use TypeScript. JavaScript Choose a language for your tests › TypeScript ? Choose a browser provider. Vitest will use its API to control the testing environment › - Use arrow-keys. Return to submit. ❯ playwright - Playwright relies on Chrome DevTools protocol. Read more: https://playwright.dev webdriverio preview Choose a browser › chromium Choose your framework › svelte Install Playwright browsers (can be done manually via 'pnpm exec playwright install')? 
 yes Installing packages... @vitest/browser, @testing-library/svelte, playwright, @sveltejs/vite-plugin-svelte Packages: +111 -3 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- Progress: resolved 208, reused 164, downloaded 7, added 111, done node_modules/.pnpm/msw@2.4.1/node_modules/msw: Running postinstall script, done in 1.5s devDependencies: + @sveltejs/vite-plugin-svelte 3.1.2 + @testing-library/svelte 5.2.1 + @vitest/browser 2.0.5 + playwright 1.46.1 Done in 5s Created a config file for browser tests vitest.config.ts Added "test:browser" script to your package.json. Installing Playwright dependencies with `pnpx playwright install --with-deps`... Packages: +3 +++ Progress: resolved 3, reused 3, downloaded 0, added 3, done Downloading Chromium 128.0.6613.18 (playwright build v1129) from https://playwright.azureedge.net/builds/chromium/1129/chromium-mac-arm64.zip 138.1 MiB [====================] 100% 0.0s Chromium 128.0.6613.18 (playwright build v1129) downloaded to /Users/Library/Caches/ms-playwright/chromium-1129 Downloading FFMPEG playwright build v1009 from https://playwright.azureedge.net/builds/ffmpeg/1009/ffmpeg-mac-arm64.zip 1 MiB [====================] 100% 0.0s FFMPEG playwright build v1009 downloaded to /Users/Library/Caches/ms-playwright/ffmpeg-1009 Downloading Firefox 128.0 (playwright build v1458) from https://playwright.azureedge.net/builds/firefox/1458/firefox-mac-arm64.zip 79.6 MiB [====================] 100% 0.0s Firefox 128.0 (playwright build v1458) downloaded to /Users/Library/Caches/ms-playwright/firefox-1458 Downloading Webkit 18.0 (playwright build v2051) from https://playwright.azureedge.net/builds/webkit/2051/webkit-mac-13-arm64.zip 68.3 MiB [====================] 100% 0.0s Webkit 18.0 (playwright build v2051) downloaded to /Users/Library/Caches/ms-playwright/webkit-2051 Add "@vitest/browser/providers/playwright" to your tsconfig.json "compilerOptions.types" field to have better intellisense support. Created example test file in vitest-example/HelloWorld.test.ts You can safely delete this file once you have written your own tests. All done! Run your tests with pnpm test:browser pnpm run test:browser を実行するず、 @sveltejs/vite-plugin-svelte パッケヌゞがES module (ESM)であるのに察し、 CommonJSのコンテキストでむンポヌトしようずしおいるず゚ラヌが出たす。 そのため、package.jsonに以䞋を远加したす。 "type": "module" package.jsonの修正埌、再床実行するず新たな゚ラヌが発生したす。 衚瀺された゚ラヌは、Svelteコンポヌネント内でTypeScriptを䜿甚しおいるにも関わらず、 TypeScriptのプリプロセッサが蚭定されおいないずいうものになりたす。 そのため、以䞋の内容のsvelte.config.jsを远加したす。 import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; const config = { preprocess: vitePreprocess(), }; export default config; svelte.config.jsを远加埌、再床 pnpm run test:browser を実行したずころ、新たな゚ラヌが発生したした。 衚瀺された゚ラヌは、プロゞェクトにSvelteパッケヌゞが導入されおいないこずを瀺しおいたす。 そのため、Svelteを远加したす。 $ pnpm add svelte 再床実行するず、ブラりザが正垞に立ち䞊がり、テストが正垞に実行されおいるこずを確認できたした。 $ pnpm run test:browser RERUN x1 ✓ vitest-example/HelloWorld.test.ts (1) ✓ renders name Test Files 1 passed (1) Tests 1 passed (1) Start at 17:20:25 Duration 13ms PASS Waiting for file changes... press h to show help, press q to quit 次に、Vitestの動䜜をより深く理解するために、initで自動生成されたコヌドを以䞋のように修正しおみたす。 最初は䜕も衚瀺されおいない画面を衚瀺し、1秒埌に “Hello Vitest!” ずいうテキストが衚瀺されるような凊理に倉曎 HelloWorld.svelte <script lang="ts"> export let name: string </script> <h1>Hello {name}!</h1> HelloWorld.test.ts import { expect, test } from 'vitest' import { render } from '@testing-library/svelte' import HelloWorld from './HelloWorld.svelte' test('renders name', () => { const { getByText } = render(HelloWorld, { props: { name: 'Vitest' }, }) const element = getByText('Hello Vitest!') expect(element).toBeInTheDocument() }) 修正埌のコヌド HelloWorld.svelte <script lang="ts"> import { fade } from 'svelte/transition'; export let name: string; let visible = false; setTimeout(() => { visible = true; }, 1000); </script> {#if visible} <h1 transition:fade>Hello {name}!</h1> {/if} HelloWorld.test.ts import { expect, test } from 'vitest' import { render } from '@testing-library/svelte' import HelloWorld from './HelloWorld.svelte' test('shows greeting after delay', async () => { const { getByText } = render(HelloWorld, { props: { name: 'Vitest' } }) // 最初はHello Vitest!が衚瀺されおいないこずを確認 expect(() => getByText('Hello Vitest!')).toThrow() // 遅延埌にHello Vitest!が衚瀺されるこずを確認 await new Promise(resolve => setTimeout(resolve, 1100)) expect(getByText('Hello Vitest!')).toBeVisible() }) テストを実行した結果、以䞋の動䜜が確認できたした。 1. テスト開始盎埌画面䞊に䜕も衚瀺されない。 2. 1秒経過埌画面に “Hello Vitest!” ずいうテキストが衚瀺される。 䞊蚘より、以䞋の点が確認できたした。 1. Vitestが1秒の遅延を正確に凊理し、その埌の状態倉化を適切にテストできおいるこず。 2. 実際のブラりザに近い環境でコンポヌネントが正しくレンダリングされ、DOMの曎新が適切に行われおいるこず。 3. 意図した動䜜最初は䜕も衚瀺せず、1秒埌に特定のテキストを衚瀺するが正確にテストされ、期埅通りの結果が埗られるこず。 この結果から、Vitestの Browser Modeが非同期凊理を含むUIコンポヌネントのテストに効果的であるこずが分かりたした。 特に、時間に䟝存する動䜜や状態倉化を䌎うコンポヌネントのテストにおいお、Vitestが優れた胜力を発揮するこずが確認できたした。 VitestのBrowser Modeの機胜を詊しおいく過皋で、Playwrightでよく䜿甚しおいたスクリヌンショット機胜を詊しおみたした。 await page.screenshot({ path: 'screenshot.png' }) しかし、䞊蚘をテストコヌドに远加しお実行したずころ、 page オブゞェクトで゚ラヌが発生したした。 䞊蚘の゚ラヌより、Vitestの環境ではPlaywrightの page オブゞェクトが盎接利甚可胜ではないこずが分かりたした。 たずめ VitestのBrowser Modeは、公匏には執筆時点ではExperimentalの機胜になりたす。 䞊蚘のスクリヌンショットの件などもあり、Playwrightの盎接的な代わりにはならなさそうですが、単玔なコンポヌネントテストであれば、Browser Modeも考慮にいれおよいかもしれたせん。 ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 Tech TalkやMeetUpも開催しおおりたす こちらもお気軜にご応募ください Event – NIFTY engineering connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する
はじめに N1! 制床 でスクラム゚バンゞェリストを担圓しおいる西野です。 8月にCTIでCo-Avtiveコヌチングの研修をうけおきたのですが、スクラムマスタヌにかなりフィットするスキルだなず思ったのでレポヌトしおみたいずおもいたす。 コヌチングに興味を持ったきっかけ 数幎前、スクラムマスタヌに぀いおより深く孊ぶ「アドバンスドスクラムマスタヌ」の研修を受けた際、コヌチングをやっおみるワヌクがありたした。 スクラムチヌムの成長を助ける方法ずしお良さそうだず思ったので、その研修以来1on1の堎を通じおメンバヌにコヌチングをやっおいたす。 スクラムチヌムに察しコヌチングを始めたころは手応えを感じおいたのですが、時間が経぀に぀れお 「恣意的に䌚話誘導しおいるかも 」 「アドバむスをしおしたっおいないか」 「1on1を終えたメンバヌに掻力を䞎えられおいるのだろうか」 ずいった自身のスキルの限界を感じるシヌンが増えおきお、䞀床きちんず孊びたいずいう気持ちが膚らんできたした。 その時ふず、「コヌチング研修を受けお良かった」ず蚀っおいた人がいたこずを思い出し、コヌチング研修に興味を持぀ようになりたした。 なお、ニフティのN1! ではこういった研修などに䜿える掻動予算が幎間100䞇円もあるので、その予算を䜿わせおもらっおいたす。 スクラムマスタヌはコヌチング研修をうけるべき これはかなり食い気味に「YES」です。 スクラムガむドにも ⟃⌰管理型で機胜暪断型のチヌムメンバヌをコヌチする。 組織ぞのスクラムの導⌊を指導・トレヌニング・コヌチする。 https://scrumguides.org/docs/scrumguide/v2020/2020-Scrum-Guide-Japanese.pdf ずコヌチングぞの蚀及がありたす。 ティヌチング教えるこずは孊校や䌚瀟で経隓しおいたすが、自分の堎合きちんずしたコヌチングを受けた経隓はありたせんでした。 スクラムマスタヌに必芁なスキルである「コヌチング」を、頭ではなく䜓で芚える経隓は、なかなか他の手段で代替が効かないものだず思いたす。 そもそもコヌチングっおなに 䞀般的にコヌチずいうず、スポヌツのコヌチずいうむメヌゞが匷いず思いたす。 自分の堎合コヌチングに぀いお孊び始める前は、コヌチは「プレむダヌになにかアドバむスをする人」たたは「緎習をさせる指導者」ずいうむメヌゞを持っおいたした。 スクラムガむドにある「コヌチ」や、ここでいう「コヌチング」は䞊蚘ずは異なりたす。 「アドバむスをする」「緎習などの行動を指瀺する」のはコヌチングではなくティヌチングず呌ばれるスキルです。 コヌチングは「気持ちを䞊向かせる」「盞手の成長をサポヌトする」、芁は「他者の圚り方を支揎」をするこずに特化したスキルだず今は思っおいたす。 念の為、近幎のスポヌツのコヌチは、いわゆる自己成長を促すコヌチング芁玠が倚くなっおいるず聞いたこずを付け加えおおきたす コヌチング研修を受けおみおどう倉わったか 研修の詳现を曞くこずはできないのですが、もし曞けたずしおも「䜓隓しないず䌝わらないな」ずいう内容が倚かったので、研修を受けお気付いたこずを䞭心にたずめたす。 話題にフォヌカスしお人を芋おいなかったず気づけた 研修をうけお䞀番衝撃が倧きかったこずは、これたでやっおた぀もりの「傟聎」が党然できおいなかったこずでした。 傟聎の぀もりで自分がやっおいたのは、「盞手の話の内容をちゃんず理解しお、次に䜕の質問をしようか䞀生懞呜考えおいる」ずいう状態でした。 盞手の䌚話にどう切り蟌もうか考え蟌んでいるうちに、盞手が䜕の話をしおいるかわからなくなっおしたうこずは普段の経隓でもあるのではないでしょうか。 話の内容を深く理解するこずず、盞手を知るこずは必ずしもむコヌルではありたせん。 ほかに、メモをずりながら1on1をしおいたこずも、話の内容ばかりに目を向けおしたっお盞手を芋ないこずに繋がっおしたっおいたかもず思うようになりたした。 盞手の衚情や声のトヌン、䜓の動きをよく芳察するこずも含めお傟聎です。 今たでの1on1の堎で、盞手に意識がむいおいない瞬間がどれほど倚かったか気付かされたした。 コヌチングは異空間 「傟聎」をはじめずしお、普段の䌚話ずコヌチングの察話には倧きな差がありたす。日垞䌚話ではたずしないな、ず思うような質問をあえおするこずが盞手の新たな気づきに繋がりたす。 コヌチングを日垞の䌚話ず同じ流れでやっおしたうず、盞談䌚や愚痎の発散で終わっおしたいがちです。 「ここはコヌチングの堎だ」ずいう違いを、コヌチだけでなくコヌチをうける偎クラむアントにも匷く意識しおもらう必芁がありたす。 実際、研修の理解を深めるためにコヌチングをやっおみたずきに、コヌチングの堎であるこずをクラむアントが意識できず倱敗しおしたったこずがありたす。 緎習ずしお家族にコヌチングをしおみたのですが、「コヌチングの緎習をしたい」ずしか䌝えおおらず、コヌチングずは䜕か、この堎をどうしおいきたいかずいう前提の䌚話をしなかったために「䜕回も同じような質問をされお嫌な気持ちになった」ずいうフィヌドバックをもらっおしたいたした。 家族間なので正盎にフィヌドバックがもらえおただよかったのですが、今たでチヌムメンバヌに察しおこういうコヌチングをしおいたのかもしれないず思うず怖くなりたす。 効果的にコヌチングを行うための聞き方や質問の仕方は日垞䌚話ずはかなりかけ離れおいたす。研修䞭、飛躍した提案や、考えたこずもないようなこずを聞かれおクラむアントずしおドキッずするシヌンもありたした。 研修を受けおみるず、その「ドキッずする」気持ちは自分が思い悩むだけでは出ない答えに繋がるこずが䜓隓できたす。 䞀人で考えおいるず、どうしおも思考の範囲が狭くなっおしたいたす。䞀芋突拍子もなく感じる質問が、それを打砎するきっかけになるのです。 このように「盞手をドキッずさせるかもしれない」ような質問をする堎でもあるので、受ける偎ずどんな堎を぀くっおいくのかを擊り合わせないず、堎が成立しないばかりか、ストレスを感じる方向に働いおしたう可胜性があるこずにも気づけたした。 スクラムマスタヌずしおどうコヌチングを行うか 最埌に、コヌチングの研修をうけおみお自分がスクラムマスタヌずしおチヌムに接する䞊で倉えようず思ったこずを挙げおいきたす。 自埋には「自分の䟡倀芳」が必芁 スクラムマスタヌ同士で集たるず「どうやったらチヌムの自埋を促せるのか」ずいう話題があがるこずが過去䜕回かありたした。 自埋を逊うためには「自分で決定、行動するこず」を繰り返す必芁があるず思っおいたすが、そもそも決定するこずが苊手ずいう人もいるでしょう。 決定は埗意ずいう人でも、決めたこずを必ずやり切れる人は滅倚にいたせん。 人が意志決定する重芁なファクタヌずしお、自分の「䟡倀芳」がありたす。 どれだけ䞖の䞭的に良いずされおいおも、自分にずっお䟡倀があるず思えないこずを無理に決定しおしたうず、モチベヌション持おずにやりきるこずができたせん。 仕事における「自分の䟡倀芳」が芋぀かるようチヌムをサポヌトする 仕事のフレヌムワヌクはさたざたにありたすが、スクラムは「䟡倀芳」に蚀及しおいるこずが特城的だず思いたす。 スクラムがうたく機胜しおいないずきは、スクラムにおける䟡倀基準ず、その人の仕事の䟡倀芳を照らし合わせるこずをしおいないのではないか、ず気づきたした。 しかし、働くうえで䜕を倧事にしおいるかをぱっず答えられる人はそれほど倚くはないでしょう。自分も改めお考えるず蚀語化が難しいです。 スクラムの䟡倀基準は「確玄」「集䞭」「公開」「尊敬」「勇気」ですが、その䟡倀はわかり぀぀も、チヌムメンバヌの䟡倀芳がスクラムの䟡倀基準ずどの皋床マッチしおいるのか、あたり向き合っおこなかったず思いたす。 スクラムマスタヌずしお、たずチヌムメンバヌそれぞれが「自分の䟡倀芳」が芋぀けられるようサポヌトする必芁があるのではないかず思い至りたした。その手段ずしおコヌチングがありたす。 「自分自身」に向き合うこずは、倚くの人が無意識に避けおいる郚分です。 コヌチングの時間を持぀こずで、意図的に「自分」や「自分の䟡倀芳」に向き合っおもらうこずができたす。 スクラムマスタヌは、そのずきコヌチずしお「自分」に向き合うこずの抵抗感をやわらげ、自分自身ず向き合うこずから逃げないように導くこずで、指瀺以倖の方法でその人の行動を倉容させるこずができるのではないかず思えるようになりたした。 過去ではなく未来に目を向けさせる 研修前にコヌチングを意識しお指瀺ではなく質問をするよう心がけおいた時期もありたすが、「なんでこのアクションになったの」「なんでこの決定になったの」ずいう「WHY」の問いかけをしおしたうこずがありたした。 これは質問される方はもちろん、質問をする偎も息苊しく、これを繰り返しおも安心できるチヌムになりそうなむメヌゞがわきたせんでした。 今なら、この問いが効果的でない理由がわかりたす。未来に焊点を圓おた問いかけではないからです。 もし同じこずを問うなら「このアクションをするこずで、䜕を埗たい」「この決定をするこずはこの先どんな圱響がある」ずいうような質問に倉えるず思いたす。 スクラムマスタヌずしお、倉えられない過去に焊点を向けるより、倉えられる未来の行動に焊点をあわせおもらうほうが、よりスクラムチヌムの成長をサポヌトしやすいからです。 自分に向き合い、倉化し、成長するために 私はコヌチングの研修をうけおみお「スクラムチヌムが無意識のうちに逃げおいるこずに察面させ、行動の倉容を促し、成長を導く」ずいうこずにもっずチャレンゞしたいず思うようになりたした。 コヌチングを通じおチヌムメンバヌが自身の䟡倀芳を芋぀け、自埋的に行動できるようサポヌトするこずは、スクラムチヌム党䜓の成長に繋がりたす。 もうひず぀重芁な気づきがありたす。スクラムマスタヌ自身が肉䜓的・粟神的に元気で前を向ける状態にないずコヌチは難しいずいうこずです。 自分のこずでいっぱいいっぱいのずきは、他人に目を向けられたせん。他人をみれないずきは、スクラムマスタヌずしお十党には振る舞えたせん。 チヌムメンバヌが䟡倀芳に向き合うよう促すず同時に、スクラムマスタヌである自分自身の䟡倀芳にも向き合っおいく必芁性を感じおいたす。 この自分自身ず向き合う手段ずしお、倖郚のコヌチを぀けおみるずいう遞択肢があるこずを知れたのもよかったです。 さいごに コヌチングの基瀎研修を受けた埌のアクションずしお、コヌチングの孊習・実践をより深めおいく方向もあったのですが、今はたず自分の䟡倀芳を知る方向でアプロヌチしおいこうず考えおいたす。 誰の人生においおも、自分ずどう向き合っお生きおいくかは倧きな課題ずしお立ち塞がりたす。 スクラムマスタヌは、スクラムチヌムや組織など倖偎に目を向けおいる時間が長いです。そんな䞭で、スクラムチヌムや組織の䞭に自分がいるこずを忘れおいた気がしたす。 コヌチングの孊習を通じお、他者の成長を促すだけでなく、スクラムマスタヌである自分自身ず正しく向き合おうずいう芖点が持おたこずは倧きな倉化でした。 蚘事の最初に「スクラムマスタヌはコヌチングの研修を受けるべき」ず曞きたしたが、これはチヌムのためだけでなく、スクラムマスタヌの自己管理のためでもありたす。 スクラムマスタヌが成長する䞀぀の手段ずしお、コヌチングの研修を受けおみるのはかなり効果的だず思いたした。 今は、瀟内にコヌチ制床を導入するために、コヌチングに興味がある人を集めおコヌチングの䟡倀を広められるよう頑匵っおいたす。なにか実を結んだら、この取り組みも蚘事にしたいず思いたす。お楜しみに ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 Tech TalkやMeetUpも開催しおおりたす こちらもお気軜にご応募ください Event – NIFTY engineering connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する
むベント抂芁 NIFTY Tech Talkは、ニフティ株匏䌚瀟の瀟員が䞻催するトヌクむベントです。 本むベントでは、ニフティグルヌプの瀟員が業務を通じお孊んだこずを発信しおいたす テヌマ 倩気予報があなたの手元に届けられるたで   〜今日傘を持っお出掛けるこずができるための仕組みの裏偎〜 2008幎に開始した@nifty倩気予報が぀いにリニュヌアル。その開発のりラ偎をお話ししおいきたす。 たた、今回はコラボ䌁画ずなっおおり、りェザヌニュヌズ様ずコラボしたす リニュヌアルで䜿甚したNext.js、Go、GraphQLでどのように開発しおいったのか、気象デヌタを提䟛する偎の仕組みなどをりェザヌニュヌズずニフティの技術者が玹介しおいきたすので、是非ご参加ください。 今回はハむブリッド開催ずなっおおりたす。 お時間やご興味のある方は是非新宿たで足をお運びください 開催抂芁 日皋10月2日氎19:00〜20:30 ハむブリッド開催 珟地参加: ニフティ 新宿本瀟 来堎予定で19:30以降に来られる方は「 @NIFTYDevelopers 」からご連絡お願いしたす オンラむン参加: YouTube Live 登録はこちらから https://nifty.connpass.com/event/328943/ こんな方におすすめ 以䞋に぀いお興味があるかたにおすすめです Next.js、Go、GraphQLに぀いお興味がある方 サヌビスリニュヌアル時の技術遞定に興味がある方 他瀟ずのデヌタ連携を行うシステムに興味のある方 デザむンシステムを甚いたフロント゚ンド開発に興味がある方 タむムテヌブル 時間 コンテンツ 19:00 – 19:10 オヌプニング 19:10 – 19:25 倩気予報があなたの手元に届けられるたで仮 19:25 – 19:40 @nifty倩気予報フルリニュヌアルぞの挑戊 19:55 – 20:10 @nifty倩気予報のフロント゚ンドを実装するたで 20:10 – 20:25 AWS AppSyncを甚いたGraphQL APIの開発に぀いお 20:25 – 20:30 クロヌゞング 登壇者プロフィヌル 登壇者未定りェザヌニュヌズ りェザヌニュヌズ様からの登壇ずなりたす。 登壇者決たりたしたら反映いたしたす 枡邊 倧介ニフティ 自瀟WEBサヌビスの開発・運甚担圓をしおいたす。 @nifty倩気予報ではPLをしおいたす。 䜐々朚 優ニフティ @nifty倩気予報で開発を担圓しおいたす。 フロント゚ンドの他、最近はAWSのやサヌビスのむンフラコストを削枛できないかなどを勉匷䞭です。 川端 航平ニフティ SREずしお瀟内暪断でプロゞェクトサポヌトをしおいたす。 @nifty倩気予報のフルリニュヌアルプロゞェクトにもサポヌトずしお参加。 ニフティグルヌプでは䞀緒に働く仲間を募集䞭です 新卒採甚、キャリア採甚を実斜しおいたす。ぜひ リクルヌトサむト をご芧ください。 ニフティ゚ンゞニアが業務で孊んだこずやむベント情報を ゚ンゞニアブログ にお発信しおいたす ニフティ゚ンゞニアのX(旧Twitter)アカりント NIFTY Tech Talkのこずや、ニフティの゚ンゞニアの掻動を発信しおいきたす。 @NIFTYDevelopers アンチハラスメントポリシヌ 私たちは䞋蚘のような事柄に関わらずすべおの参加者にずっお安党で歓迎されるような堎を䜜るこずに努めたす。 瀟䌚的あるいは法的な性、性自認、性衚珟倖芋の性、性指向 幎霢、障がい、容姿、䜓栌 人皮、民族、宗教無宗教を含む 技術の遞択 そしお䞋蚘のようなハラスメント行為をいかなる圢であっおも決しお蚱容したせん。 䞍適切な画像、動画、録音の再生性的な画像など 発衚や他のむベントに察する劚害行為 これらに限らない性的嫌がらせ 登壇者、䞻催スタッフもこのポリシヌの察象ずなりたす。 ハラスメント行為をやめるように指瀺された堎合、盎ちに埓うこずが求められたす。ルヌルを守らない参加者は、䞻催者の刀断により、退堎凊分や今埌のむベントに聎講者、登壇者、スタッフずしお関わるこずを犁止したす。 もしハラスメントを受けおいるず感じたり、他の誰かがハラスメントされおいるこずに気が぀いた堎合、たたは他に䜕かお困りのこずがあれば、すぐにご連絡ください。 ※本文章はKotlinFest Code of Conductずしお公開された文章( https://github.com/KotlinFest/KotlinFest2018/blob/master/CODE-OF-CONDUCT.md )を元に掟生しおいたす。 ※本文章はCreative Commons Zero ラむセンス( https://creativecommons.org/publicdomain/zero/1.0/ ) で公開されおいたす。
はじめに みなさん、こんにちは「爆速でシリヌズ」っお聞いたこずありたすよねでも、そのたた真䌌しおみおも、環境の違いやバヌゞョンアップのせいで動かないこずっおありたすよね。でも倧䞈倫今回は、そんな壁に負けずに挑戊しおみたしょう お題抂芁 今回のミッションは、S3のバケットを確認しお、ファむルのダりンロヌドずアップロヌドができるようにするこずです。わくわくしたすね お題詳现 ある日、䌁画郚門から「システムで生成されるCSVデヌタを確認したい」ずいう䟝頌が飛び蟌んできたした。時間がない䞭で、どうしようどうしようず悩んでいたら、「S3を閲芧するツヌルを䜜っおみおは」ずいうアむデアが浮かびたした。他にも方法はあるかもしれたせんが、今はこのアむデアで突き進むしかありたせん そこで、SvelteKitを䜿っおS3バケットの䞀芧参照、ダりンロヌド、アップロヌドができるツヌルを䜜るこずにしたした。さあ、䞀緒に挑戊しおみたしょう 䜜業抂芁 ここからが本番です以䞋の順番で䜜業を進めおいきたす SvelteKitの初期蚭定 .envファむルの䜜成 ディレクトリ、ファむルを䜜る 远加でいろいろむンストヌルする ダりンロヌド機胜を実装する アップロヌド機胜を実装する 䞀芧衚瀺機胜を䜜成する 衚瀺甚ペヌゞを䜜る 起動する 動かしおみた 準備はいいですかそれでは、䞀぀ず぀芋おいきたしょう 1. SvelteKitの初期蚭定 たずは、SvelteKitのプロゞェクトを立ち䞊げたす。今回は、Node.jsのコンテナ内で䜜業しおいたすが、コンテナの蚭定は省略させおいただきたす。ごめんなさいね 公匏ペヌゞ を参考に、以䞋のコマンドを実行したした $ npm create svelte@latest ./ > npx > create-svelte ./ create-svelte version 6.3.10 ┌ Welcome to SvelteKit! │ ◇ Which Svelte app template? │ SvelteKit demo app │ ◇ Add type checking with TypeScript? │ Yes, using TypeScript syntax │ ◇ Select additional options (use arrow keys/space bar) │ Add ESLint for code linting, Add Prettier for code formatting, Add Playwright for browser testing, Add Vitest for unit testing │ └ Your project is ready! Install more integrations with: npx svelte-add Next steps: 1: npm install 2: git init && git add -A && git commit -m "Initial commit" (optional) 3: npm run dev -- --open To close the dev server, hit Ctrl-C Stuck? Visit us at https://svelte.dev/chat 遞択肢はこんな感じで進めたした SvelteKit demo appを遞択 TypeScriptを䜿甚 ESLint、Prettier、Playwright、Vitestを遞択 最埌に、npm installを実行しお準備完了です npm install 2. .envファむルの䜜成 S3にアクセスするための倧切な情報を.envファむルに保存したす。セキュリティ面で気になる方もいるかもしれたせんが、今回は爆速重芖で進めちゃいたす touch .env .envファむルの䞭身はこんな感じです # 機密 AWS_ACCESS_KEY_ID= # IAMで発行したキヌを入れおください AWS_SECRET_ACCESS_KEY= # IAMで発行したシヌクレットキヌを入れおください AWS_REGION=ap-northeast-1 # 䜿甚するリヌゞョンを指定しおください AWS_ENDPOINT_URL=https://s3.amazonaws.com # 必芁に応じお倉曎しおください S3_BUCKET_NAME= # 䜿甚するバケット名を入れおください ゚ンドポむントは、業務甚に別のものを䜿う可胜性もあるので、倉曎できるようにしおいたす。臚機応倉に察応できるっお玠晎らしいですよね 3. ディレクトリ、ファむルを䜜る さお、ここからが本栌的な䜜業の始たりです各機胜のコヌドを眮くためのディレクトリずファむルを䜜成したしょう。 mkdir ./src/routes/api mkdir ./src/routes/api/download mkdir ./src/routes/api/upload mkdir ./src/routes/api/list-files touch ./src/routes/api/download/+server.ts touch ./src/routes/api/upload/+server.ts touch ./src/routes/api/list-files/+server.ts 正盎に蚀うず、私もSvelteKitをただ完党には理解しおいたせん。でも倧䞈倫 瀟内でよくSvelteKitの話を耳にする 最新技術に乗り遅れたくない GPTがあるから䜕ずかなる ずいう3぀の理由でSvelteKitを遞びたした。ファむル構成が正攻法かどうかはわかりたせんが、ずにかくチャレンゞです 4. 远加でいろいろむンストヌルする S3の操䜜には@aws-sdk/client-s3を䜿いたす。これはGPTさんが教えおくれたした。ありがずう、GPTさん さらに、@types/nodeもむンストヌルしおおくず良さそうです。準備䞇端ですね npm install @aws-sdk/client-s3 npm install --save-dev @types/node 5. ダりンロヌド機胜を実装する GPTさんに「S3のバケットのダりンロヌド機胜をSvelteKitで䜜成したい」ずお願いしお、こんなコヌドができたした src/routes/api/download/+server.ts import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3"; import type { RequestHandler } from '@sveltejs/kit'; import { error } from '@sveltejs/kit'; import { env } from '$env/dynamic/private'; const s3Client = new S3Client({ region: env.AWS_REGION, credentials: { accessKeyId: env.AWS_ACCESS_KEY_ID, secretAccessKey: env.AWS_SECRET_ACCESS_KEY }, endpoint: env.AWS_ENDPOINT_URL, }); export const GET: RequestHandler = async ({ url }) => { const fileName = url.searchParams.get('file'); if (!fileName) { throw error(400, 'File name is required'); } const bucketName = env.S3_BUCKET_NAME; const s3Key = fileName; try { const command = new GetObjectCommand({ Bucket: bucketName, Key: s3Key, }); const response = await s3Client.send(command); if (!response.Body) { throw error(404, 'File not found'); } // ストリヌムをArrayBufferに倉換 const chunks: Uint8Array[] = []; for await (const chunk of response.Body as AsyncIterable<Uint8Array>) { chunks.push(chunk); } const fileBuffer = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0)); let offset = 0; for (const chunk of chunks) { fileBuffer.set(chunk, offset); offset += chunk.length; } return new Response(fileBuffer, { headers: { 'Content-Type': response.ContentType || 'application/octet-stream', 'Content-Disposition': `attachment; filename="${fileName}"`, }, }); } catch (err) { console.error("Error", err); throw error(500, 'Failed to download file from S3'); } }; 詳现は省きたすが、なんずなくバむナリデヌタをレスポンスに入れおいる感じがわかりたすね。面癜いです 6. アップロヌド機胜を実装する アップロヌド機胜もGPTさんにお願いしたした。結果はこちら src/routes/api/upload/+server.ts import { error, json } from '@sveltejs/kit'; import type { RequestHandler } from '@sveltejs/kit'; import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3"; import { env } from '$env/dynamic/private'; const s3Client = new S3Client({ region: env.AWS_REGION, credentials: { accessKeyId: env.AWS_ACCESS_KEY_ID, secretAccessKey: env.AWS_SECRET_ACCESS_KEY }, endpoint: env.AWS_ENDPOINT_URL, }); export const POST: RequestHandler = async ({ request }: { request: Request }) => { try { const formData = await request.formData(); const file = formData.get('file') as File; if (!file) { throw error(400, 'No file uploaded'); } const bucketName = env.S3_BUCKET_NAME; const key = `in/${Date.now()}-${file.name}`; const fileBuffer = await file.arrayBuffer(); const putObjectParams = { Bucket: bucketName, Key: key, Body: Buffer.from(fileBuffer), ContentType: file.type, }; const command = new PutObjectCommand(putObjectParams); await s3Client.send(command); return json({ message: 'File uploaded successfully', key }); } catch (err) { console.error('Error uploading file:', err); throw error(500, 'Internal server error'); } }; const key = の郚分に「in/」があるのは、今回はアップロヌド先を固定しおみたかったからです。必芁なければ削陀しおOKです盎に曞くのはよくないですね 7. 䞀芧衚瀺機胜を䜜成する 䞀芧衚瀺機胜も、もちろんGPTさんにお願いしたした import { S3Client, ListObjectsV2Command } from "@aws-sdk/client-s3"; import type { RequestHandler } from '@sveltejs/kit'; import { json, error } from '@sveltejs/kit'; import { env } from '$env/dynamic/private'; const s3Client = new S3Client({ region: env.AWS_REGION, credentials: { accessKeyId: env.AWS_ACCESS_KEY_ID, secretAccessKey: env.AWS_SECRET_ACCESS_KEY }, endpoint: env.AWS_ENDPOINT_URL, }); export const GET: RequestHandler = async () => { const bucketName = env.S3_BUCKET_NAME; try { const command = new ListObjectsV2Command({ Bucket: bucketName, Delimiter: '/' }); const response = await s3Client.send(command); const allFiles = []; if (response.Contents) { const files = response.Contents .filter(item => item.Size !== 0) // サむズが0のファむルを陀倖 .map(item => ({ key: item.Key, size: item.Size, lastModified: item.LastModified })); allFiles.push(...files); } // バケット盎䞋のディレクトリの凊理 if (response.CommonPrefixes) { const dirs = response.CommonPrefixes.map(prefix => ({ key: prefix.Prefix, isDirectory: true })); allFiles.push(...dirs); } return json({ files: allFiles }); } catch (err) { console.error("Error listing files:", err); throw error(500, 'Failed to list files from S3'); } }; ListObjectsV2Commandで取埗したファむル情報をallFilesに詰め蟌んでいるんですね。わかりやすい 8. 衚瀺甚ペヌゞを䜜る 最埌に衚瀺甚ペヌゞを䜜りたす。既存のファむルを䞊曞きしちゃいたしょう src/routes/+page.svelte <script lang="ts"> class HttpError extends Error { constructor(public status: number, message?: string) { super(message || `HTTP error! status: ${status}`); this.name = 'HttpError'; } } import { onMount } from 'svelte'; interface S3File { key: string; size: number; lastModified: string; } let files: S3File[] = []; let loading = true; let error = ''; let fileInput: HTMLInputElement; onMount(async () => { await fetchFiles(); }); async function fetchFiles() { try { loading = true; const response = await fetch('/api/list-files'); if (!response.ok) { throw new HttpError(response.status); } const data = await response.json(); files = data.files; } catch (e) { if (e instanceof HttpError) { error = `Failed to fetch files: ${e.message}`; } else { error = 'An unexpected error occurred while fetching files'; } console.error(e); } finally { loading = false; } } function formatBytes(bytes: number, decimals = 2) { if (bytes === 0) return '0 Bytes'; const k = 1024; const dm = decimals < 0 ? 0 : decimals; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; } async function downloadFile(fileName: string) { try { const response = await fetch(`/api/download?file=${encodeURIComponent(fileName)}`); if (!response.ok) throw new Error('Download failed'); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = fileName; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); } catch (error) { console.error('Error downloading file:', error); alert('Failed to download file'); } } async function uploadFile() { if (!fileInput.files || fileInput.files.length === 0) { alert('Please select a file to upload'); return; } const file = fileInput.files[0]; const formData = new FormData(); formData.append('file', file); try { const response = await fetch('/api/upload', { method: 'POST', body: formData }); if (!response.ok) { throw new HttpError(response.status, 'Upload failed'); } alert('File uploaded successfully'); await fetchFiles(); // Refresh the file list } catch (error) { if (error instanceof HttpError) { console.error('Error uploading file:', error.message); alert(`Failed to upload file: ${error.message}`); } else { console.error('Unexpected error during upload:', error); alert('An unexpected error occurred during upload'); } } } </script> <h1>S3 Bucket Files</h1> <div class="upload-container"> <input type="file" bind:this={fileInput}> <button on:click={uploadFile}>Upload File</button> </div> {#if loading} <p>Loading...</p> {:else if error} <p class="error">{error}</p> {:else if files.length === 0} <p>No files found in the bucket.</p> {:else} <table> <thead> <tr> <th>File Name</th> <th>Size</th> <th>Last Modified</th> </tr> </thead> <tbody> {#each files as file} <tr> <td> <button on:click={() => downloadFile(file.key)} class="download-link"> {file.key} </button> </td> <td>{formatBytes(file.size)}</td> <td>{new Date(file.lastModified).toLocaleString()}</td> </tr> {/each} </tbody> </table> {/if} <style> .upload-container { margin-bottom: 20px; } table { width: 100%; border-collapse: collapse; } th, td { border: 1px solid #ddd; padding: 8px; text-align: left; } th { background-color: #f2f2f2; } .error { color: red; } button { margin-left: 10px; padding: 5px 10px; background-color: #007bff; color: white; border: none; cursor: pointer; } button:hover { background-color: #0056b3; } .download-link { background: none; border: none; color: #007bff; text-decoration: none; cursor: pointer; padding: 0; font: inherit; } .download-link:hover { text-decoration: underline; } </style> styleもそれっぜく䜜っおくれおいたすねtableタグしか䜿えない私には倢のようです 9. 起動する いよいよ起動です以䞋のコマンドで立ち䞊げたしょう npm run dev -- --host 0.0.0.0 毎回、「 — –host 0.0.0.0 」を入力するのが面倒な方は、vite.config.tsをこんな感じに倉曎しおおくず䟿利ですよ import { sveltekit } from '@sveltejs/kit/vite'; import { defineConfig } from 'vite'; export default defineConfig({ plugins: [sveltekit()], server: { host: '0.0.0.0' } }); これで npm run dev だけで起動できたす。簡単ですね 10.動かしおみた 単に開いおみた アップロヌドしおみた OK抌しおみた あれ inずoutのSizeずLast Modifiedの衚瀺、なんだか䞍思議ですねたるで宝探しゲヌムみたい。これは次のアップデヌトで解明する楜しい謎になりそうです おっず、「ファむルを遞択」ボタンの暪のファむル名がクリアされおいないみたい。でも倧䞈倫これはナヌザヌに「あなたが最埌に遞んだファむルだよ〜」っお芪切に教えおくれおいるんですね。ちょっずしたサプラむズ機胜かも笑 終わりに埌日談ずいうか今回のオチ なんず驚くこずに、私たちが苊劎しお䜜ったものず䌌たようなものを公匏が䜜っおいたんです https://github.com/aws-amplify/amplify-ui/issues/5731 「時代が私に远い぀いた」なんお蚀えたら栌奜いいんですけどね笑。でも、これっお逆に考えるず、私たちが本圓に必芁ずされおいるものを䜜っおいたっおこずですよね。すごくない この経隓を通しお、私はずおも倧切なこずを孊びたした。それは、「SvelteKitがよくわからなくおも、GPTの力を借りればここたでできる」ずいうこずです。正盎、最初は䞍安でしたが、やっおみたらどんどん圢になっおいっお、すごくワクワクしたした みなさんも、「やったこずないからわからない」っお思っおも、たずは䞀歩螏み出しおみおください。きっず新しい発芋があるはずです。倱敗を恐れずに、どんどんチャレンゞしおいきたしょう そうそう、最埌にちょっずした宣䌝です。ニフティでは、このような面癜い挑戊を垞に募集しおいたす。䞀緒に新しいこずにチャレンゞしおみたせんかきっず楜しい経隓になりたすよ さあ、次はどんな冒険が埅っおいるでしょうか。楜しみですねそれでは、たた次回の「爆速シリヌズ」でお䌚いしたしょう。バむバヌむ  終わりの終わりに いかがでしたでしょうか。䜕ずも蚀えないテンションだったかず思いたす。今回はある皋床、原皿を曞いた状態で、「明るい口調で曞き盎しお」ずGPTさんにお願いしおみたずころこのような文章になりたした。䞭の人はこんなキャラではありたせん。お蚱しください。ただ、最埌の「時代が私に远い぀いた」の郚分に぀いおは、「本圓に必芁ずされおいるものを䜜っおいた」なんおポゞティブな考えはたったく思っおいたせんでした。こういうものの考え方もあるのだなあず感心したした。コヌド生成だけではなく考え方の参考にもなるず気づかされたしお今埌、掻甚しおいきたいず思いたす。 ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 Tech TalkやMeetUpも開催しおおりたす こちらもお気軜にご応募ください Event – NIFTY engineering connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する
こんにちは。ニフティ株匏䌚瀟のyamanakaです。 所属しおいるチヌムでPlaywrightのフィクスチャを導入したため、備忘録も兌ねお調べた内容やフィクスチャ抂芁から実際の䜿甚䟋 @nifty玹介特兞 から玹介コヌド払い出しずずもに玹介したす。 はじめに りェブアプリケヌションの自動テストは、品質保蚌プロセスにおいお䞍可欠な芁玠ずなっおいたす。その䞭で、Microsoftが開発したPlaywrightは、匷力で䜿いやすいクロスブラりザテスト自動化ツヌルずしお泚目を集めおいたす。 Playwrightは、ChromiumChrome、Edge、Firefox、WebKitベヌスのブラりザに察応し、JavaScriptやTypeScriptを䜿甚しお盎感的なAPIを提䟛したす。これにより、高速で信頌性の高いE2Eテストを簡単に䜜成できたす。 しかし、効率的なテスト環境を構築するには、単にテストケヌスを曞くだけでは䞍十分です。ここで重芁な圹割を果たすのが「フィクスチャ」です。 フィクスチャずは フィクスチャずは、テストの実行に必芁な前提条件や環境を蚭定するためのコヌドのこずです。Playwrightにおいお、フィクスチャは以䞋のような圹割を果たしたす。 1. テスト環境の䞀貫性を保蚌 2. コヌドの重耇を削枛 3. テストの可読性ず保守性を向䞊 4. テスト実行の効率化 䟋えば、ブラりザの起動、ペヌゞの読み蟌み、ナヌザヌログむンなど、倚くのテストケヌスで共通しお必芁な操䜜をフィクスチャずしお定矩するこずで、テストコヌドをクリヌンに保ち、効率的に管理できたす。 フィクスチャの定矩 Playwrightでは、 test.beforeEach() や test.beforeAll() などのフックを䜿甚しおフィクスチャを定矩したす。䞀般的な圢匏は以䞋のずおりです。 javascript import { test as base } from '@playwright/test'; export const test = base.extend({ myFixture: async ({ }, use) => { // フィクスチャのセットアップ const value = 'フィクスチャの倀'; // フィクスチャの䜿甚 await use(value); }, }); 別ファむルでブラりザ、コンテキスト、ペヌゞフィクスチャをそれぞれ䜜成したす、そしおこのフィクスチャを䜿甚するテストファむルでは、以䞋のようにむンポヌトしお䜿甚したす。 javascript // myFixtures.js import { test as base, chromium } from '@playwright/test'; export const test = base.extend({ page: async ({ }, use) => { const browser = await chromium.launch(); const context = await browser.newContext(); const page = await context.newPage(); await use(page); await context.close(); await browser.close(); }, }); javascript // myTest.spec.js import { test } from './myFixtures'; test('フィクスチャを䜿甚するテスト', async ({ page }) => { await page.goto('https://example.com'); // テストロゞック }); 䞊蚘により、基本的なブラりザ、コンテキスト、ペヌゞフィクスチャを䜿いこなすこずで、テストの基盀を匷固にできたす。 カスタムフィクスチャの䜜成 基本的なフィクスチャに加えお、プロゞェクト固有のニヌズに合わせおカスタムフィクスチャを䜜成するこずができたす。 これにより、テストコヌドの再利甚性ず管理性をさらに向䞊させるこずができたす。 ナヌザヌ認蚌ずAPIレスポンスのモック化を䟋にあげたす。 javascript import { test as base } from '@playwright/test'; export const test = base.extend({ loggedInPage: async ({ page }, use) => { // ログむン凊理 await page.goto('https://example.com/login'); await page.fill('#username', 'testuser'); await page.fill('#password', 'testpass'); await page.click('#login-button'); await use(page); }, // APIモックを蚭定するフィクスチャ mockApi: async ({ page }, use) => { // APIリク゚ストのモックを蚭定 await page.route('**/api/dashboard', route => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ username: 'testuser', lastLogin: '2023-04-01' }) }); }); // モック蚭定枈みのペヌゞをテストに提䟛 await use(page); }, // ログむン枈みか぀APIモック適甚枈みの環境を提䟛するフィクスチャ preparedTestEnvironment: async ({ loginPage, mockApi }, use) => { // loginPage に mockApi の蚭定を適甚 await mockApi(loginPage); // 準備完了した環境をテストに提䟛 await use(loginPage); }, }); この組み合わせたフィクスチャを䜿甚するテストは以䞋のようになりたす。 javascript import { test } from './myFixtures'; // テスト test('ダッシュボヌドテスト', async ({ preparedTestEnvironment }) => { // 実際のダッシュボヌドペヌゞに遷移 await preparedTestEnvironment.goto('https://example.com/dashboard'); // ここで 'https://example.com/api/dashboard' にリク゚ストを送る // テストアサヌションなど }); 遷移する凊理ずAPIリク゚ストのモックを別々の抂念ずしお考えながら組み合わせおナニットテストを構築するず良いのかなず蚘事にしながら思いたした。 フィクスチャのスコヌプ Playwrightでは、フィクスチャのスコヌプを適切に蚭定するこずで、テストの効率ず信頌性を向䞊させるこずができたす。 テストファむルスコヌプ テストファむル内でのみ䜿甚するフィクスチャは、そのファむル内で定矩したす。 javascript import { test as base } from '@playwright/test'; const test = base.extend({ localFixture: async ({}, use) => { // このファむル内のテストでのみ䜿甚可胜なフィクスチャ await use('local value'); }, }); test('ロヌカルフィクスチャを䜿甚', async ({ localFixture }) => { console.log(localFixture); // 'local value' }); グロヌバルスコヌプ プロゞェクト党䜓で䜿甚するフィクスチャは、専甚のファむル䟋 fixtures.ts で定矩し、むンポヌトしお䜿甚したす。 javascript // fixtures.ts import { test as base } from '@playwright/test'; export const test = base.extend({ globalFixture: async ({}, use) => { await use('global value'); }, }); // test.spec.ts import { test } from './fixtures'; test('グロヌバルフィクスチャを䜿甚', async ({ globalFixture }) => { console.log(globalFixture); // 'global value' }); 非同期フィクスチャの扱い方 Playwrightのフィクスチャは非同期操䜜を効果的にサポヌトしおおり、async/awaitを䜿甚しお簡単に非同期凊理を組み蟌むこずができたす。 基本的な非同期フィクスチャ javascript import { test as base } from '@playwright/test'; export const test = base.extend({ asyncData: async ({}, use) => { const data = await fetchDataFromApi(); await use(data); }, }); test('非同期デヌタを䜿甚', async ({ asyncData }) => { console.log(asyncData); // テストロゞック }); ゚ラヌハンドリング ゚ラヌが発生した堎合のハンドリング凊理も忘れず䜜成したしょう。 javascript import { test as base } from '@playwright/test'; export const test = base.extend({ errorProneFixture: async ({}, use) => { try { const result = await fetchDataFromApi(); await use(result); } catch (error) { console.error('フィクスチャの初期化䞭に゚ラヌが発生したした:', error); throw error; // テストを倱敗させる } }, }); フィクスチャの䟝存関係 フィクスチャは他のフィクスチャに䟝存するこずができ、これによっお耇雑なテスト環境を構築できたす。 javascript import { test as base } from '@playwright/test'; export const test = base.extend({ config: async ({}, use) => { // 蚭定をロヌド const config = await loadConfig(); await use(config); }, apiClient: async ({ config }, use) => { // configフィクスチャを䜿甚しおAPIクラむアントを初期化 const client = new ApiClient(config.apiUrl); await use(client); }, loggedInUser: async ({ page, apiClient }, use) => { // apiClientフィクスチャを䜿甚しおナヌザヌを䜜成 const user = await apiClient.createUser(); // ペヌゞにログむン await page.goto(config.loginUrl); await page.fill('#username', user.username); await page.fill('#password', user.password); await page.click('#login-button'); await use(user); }, userWithData: async ({ loggedInUser, apiClient }, use) => { // ログむン枈みナヌザヌにデヌタを远加 const userData = await apiClient.addUserData(loggedInUser.id, { posts: ['Test Post'] }); await use({ ...loggedInUser, ...userData }); }, }); test('ナヌザヌデヌタのテスト', async ({ userWithData, page }) => { await page.goto('https://example.com/profile'); const postTitle = await page.textContent('.post-title'); // 怜蚌 expect(postTitle).toBe('Test Post'); expect(userWithData.posts).toContain('Test Post'); }); この䟋では、耇数のフィクスチャが互いに䟝存関係を持っおいたす。 1.  apiClient  ã¯  config  ã«äŸå­˜ 2.  loggedInUser  ã¯  page  ãš  apiClient  ã«äŸå­˜ 3.  userWithData  ã¯  loggedInUser  ãš  apiClient  ã«äŸå­˜ 実践的な䟋払い出したURLに遷移するテスト ニフティでは光回線サヌビスをお友達に玹介するず、玹介した方玹介された方それぞれにニフティポむントをプレれントするサヌビスがありたす。 @nifty玹介特兞  今回は䞊蚘サヌビスから玹介コヌドを払い出し、玹介ペヌゞから申蟌画面に遷移する内容を䟋にあげたす。 import { test as base } from '@playwright/test'; import { expect } from "@playwright/test"; export const test = base.extend({ mainPage: async ({ page }, use) => { await page.goto('https://setsuzoku.nifty.com/syokai/index.htm'); await use(page); }, searchUrl: async ({ mainPage }, use) => { await mainPage.getByRole('link', { name: '玹介する' }).click(); // ペヌゞにログむン await mainPage.fill('#id_user_id', 'xxxxxxxx'); await mainPage.click('#next'); await mainPage.fill('#id_pw', 'xxxxxxxx'); await mainPage.click('#login'); const url = await mainPage.evaluate(() => { const element = document.querySelector('.shokaiCode_signUp a'); return element ? element.href : null; }); await mainPage.goto(url); // url を返すように倉曎 await use({ page: mainPage, url: url }); }, }); test('払い出されたURLに遷移', async ({ mainPage, searchUrl }) => { const { url } = searchUrl; // URLを確認する await expect(mainPage).toHaveURL(url); }); おわりに Playwrightのフィクスチャを導入するこずで、コヌドの再利甚や共通化するこずができるためチヌムずしおも䞀貫したテストを採甚しやすくなりたす。 APIレスポンスのモック化に぀いお調べながらコヌドを曞きたしたが、ナニットテストに察しお柔軟で安定したテスト環境が構築できるず思いたした。 ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 カゞュアル面談も随時受付䞭 ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたしたす キャリア登録 connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する
この蚘事は、リレヌブログ䌁画「24卒リレヌブログ」の蚘事です。 はじめに 初めたしお、新卒1幎目の緑川です。 珟圚、OJTゞョブロヌテの1期目ずしお、 䌚員システムグルヌプの第二開発チヌム に所属しおいたす。䞻な業務はオプションサヌビスの開発ず運甚であり、フロント゚ンド・バック゚ンド問わず様々な技術を日々孊んでいたす。 開発にあたっお Svelte ずいうフレヌムワヌクを䜿甚する堎面があり、そのために Svelteチュヌトリアル をやっおみたので、この蚘事ではそこで重芁だず思った点や難しかった点、知らなかった甚語などを自分なりの理解でたずめおいきたいず思いたす。あくたでチュヌトリアルの説明の補足のようなものなので、そちらを読んでいる前提で執筆したす。たた、各項目の解説の密床は、自分の理解床に䟝拠しおいるために偏りがあり、䞀郚の項は䞀纏めにしおいたす。 なお、チュヌトリアルはSvelteずSvelteKit(Svelteの拡匵版のようなもの。今回は割愛)それぞれの基本ず応甚ずで4぀のPartに分かれおいたすが、今回は Part1:Basic Svelte をやりたした。 Svelteずは たずSvelteに぀いお説明したす。Svelteずは、前述のチュヌトリアルによれば、 web アプリケヌションを構築するためのツヌルです。他のナヌザヌむンタヌフェヌスフレヌムワヌクず同様、マヌクアップ(markup)、スタむル(styles)、振る舞い(behaviours) を組み合わせたコンポヌネントでアプリを  宣蚀的(declaratively)  ã«æ§‹ç¯‰ã™ã‚‹ã“ずができたす。 Svelte を理解するには、HTML、CSS、JavaScript の基本的な知識が必芁です。 https://learn.svelte.jp/tutorial/welcome-to-svelte だそうです。少し䜿っおみた感じではHTMLずJS(JavaScript)をシヌムレスに融合させ、その䞊簡単に曞けるようにしたものずいった印象を受けたした。自分はJSに぀いおも詳しくはないので、本蚘事で解説する単語の䞭にはJSのものも含たれおいたす。 Introduction Svelteにようこそ ここから解説に入っおいきたす。 Svelteチュヌトリアルは以䞋のような画面で進行したす。 巊䞊がファむル構造を衚しおいたす。右䞊がファむルの䞭身で、ここを倉曎するずリアルタむムで䞋の衚瀺に反映されたす。 フットプリント プログラムが動䜜する際のメモリ䜿甚量の倚さ コンポヌネント 次項で解説される オヌバヌヘッド プログラムが行う䜜業のために間接的に生じる䜙蚈な負荷 Your first component, Dynamic attributes ここでは、倉数やコヌドを䞭括匧で埋め蟌むずいうSvelteの基本的な動䜜が解説されおいたす。倉数の䞭身にはテキストだけでなく画像も䜿甚するこずができたす。 Styling これは芁するにCSSです。 Nested components この項目はSvelteを孊ぶにあたっお重芁です。この埌もほが党おの項でコンポヌネントのむンポヌトが行われたす。 HTML tags @html によっおHTMLタグを䜿うこずができたす。これは埌述の BindingsTextarea inputs でも出おきたす。 DOM
Document Object Modelの略。Webペヌゞの芁玠やコンテンツなどをツリヌ構造で衚珟したもの brob
Binary Large Objectの略。単にバむナリデヌタの塊を衚珟したもの サニタむズ 脆匱性を突こうずする入力を別の衚蚘に眮き換え無害化するこずを指す。 英語では「消毒する」などの意味がある Reactivity Assignments カりントを増やす関数ず、カりントを衚瀺するテキストを䜜り、「クリックした時にこの関数を実行する」ずボタンに蚭定するこずでそれらを結び぀けおいたす。 Declarations, Statements, Updating arrays and objects 他の倉数に䟝存する倉数は、 $: を぀ければ自動的に連動蚈算しおくれたす。たた、 $: は倉数だけでなく文やブロックなどにも付䞎できたす。ただし、連動蚈算は代入によっお起こるものであり、リストに远加する堎合はもう䞀工倫必芁だそうです。 このリアクティブ宣蚀ずいう抂念は開発でよく䜿う印象がありたす。 statements プログラミングにおける文のこず Props Declaring props, Default values, Spread props IntroductionStyling の項などでコンポヌネント同士の独立性に぀いおの話がありたしたが、もちろんデヌタの受け枡しも可胜です。受け枡しにあたっおは import ず export をセットで䜿甚したす。これも開発には欠かせないものです。 プロパティはデフォルト倀も蚭定するこずができ、しない堎合はundefinedになりたす。たた、枡す倉数が耇数あり、か぀その数ず名前が䞀臎しおいれば、䞀気に代入できたす。 Logic If blocks, Else blocks, Else-if blocks 他のあらゆる蚀語、フレヌムワヌクず同様、if、else、else-ifも実装されおいたす。これらのブロックは # にはじたり / に終わりたす。elseのような間に挟むものには : が぀きたす。 HTMLでこのような凊理を実装しようずするずJSを組み蟌む必芁がありたすが、Svelteであれば地続きの感芚で蚘述できたす。 Each blocks # にはじたり / に終わるのはifず同じです。配列やそれに類するものをあらかじめ宣蚀しおおけば、eachブロックを利甚しお䞀気に代入できたす。 Keyed each blocks ここは少し理解に時間がかかった郚分です。 たず初期化時に、 Thing コンポヌネントに things の䞭身が枡され、 emoji は things の name に察応したものがセットされたす。 things が決めおいるのは name ずコンポヌネントの数なので、 things = things.slice(1); によっお配列の先頭を消すず、コンポヌネントは banana 〜 egg の぀になりたす。しかし、 emoji を決めおいるのは Thing であり初期化時点から動かないこず、そしおコンポヌネントは末尟から消える法則があるこずから、ズレが生じるようです。 // Thing.svelte <script> const emojis = { apple: ' ', banana: ' ', carrot: ' ', doughnut: ' ', egg: ' ' }; export let name; const emoji = emojis[name]; </script> // App.svelte <script> import Thing from './Thing.svelte'; let things = [ { id: 1, name: 'apple' }, { id: 2, name: 'banana' }, { id: 3, name: 'carrot' }, { id: 4, name: 'doughnut' }, { id: 5, name: 'egg' } ]; function handleClick() { things = things.slice(1); } </script> <button on:click={handleClick}> Remove first thing </button> {#each things as thing (thing.id)} <Thing name={thing.name} /> {/each} shift メ゜ッドを䜿わず slice メ゜ッドを甚いおいるのは、 shiftがsliceず違っお配列を盎接倉曎するもの だからです。 ReactivityUpdating arrays and objects で述べられたように、リアクティビティは代入によっおトリガヌされるため、 shift メ゜ッドを䜿う堎合は以䞋のように蚘述する必芁があり、冗長になりたす。 things.shift(); things = things; Await blocks utils.jsの getRandomNumber() は、たず /random-number  ãšã„うAPI゚ンドポむントにリク゚ストを送信しお結果が垰るたで埅ち、レスポンスが成功した堎合レスポンスの本文をテキストずしお取埗するのを埅ち、それをApp.svelteに枡したす。 res.ok は通垞、 HTTPステヌタスコヌドが200-299の範囲内にある堎合にtrue だそうです。たた、waitingメッセヌゞを衚瀺するため、APIにはあえお遅延が組み蟌たれおいるようです。゚ンドポむントの実装はサヌバサむド(バック゚ンド)で行われおおり、ここからは芋えたせん。 // utils.js export async function getRandomNumber() { const res = await fetch('/random-number'); if (res.ok) { return await res.text(); } else { throw new Error('Request failed'); } } App.svelteは let promise = getRandomNumber(); ず #await promise で、䞀連の凊理が終わるのを埅ちたす。 {number} があるのに let number などがないのは䞍思議に思えたすが、 {:then number} が getRandomNumber() の返した倀を number ずしお割り振っおいるのだず思われたす。 // App.svelte <script> import { getRandomNumber } from './utils.js'; let promise = getRandomNumber(); function handleClick() { promise = getRandomNumber(); } </script> {#await promise} <p>...waiting</p> {:then number} <p>The number is {number}</p> {:catch error} <p style="color: red">{error.message}</p> {/await} Events DOM events, Inline handlers, Event modifiers ReactivityAssignments では button にむベントハンドラを付䞎しおいたしたが、 div に付䞎するこずもできるそうです。むンラむンで宣蚀するこずも、修食子を぀けるこずで条件・属性を远加するこずもできたす。 Component events Inner.svelteの1行目に import { createEventDispatcher } from 'svelte'; ずありたすが、これは今たでのように他のファむルからではなく svelteパッケヌゞから関数をむンストヌル しおいるずいうこずです。 ここでは、ボタンを抌すず sayHello 関数が発火し(実行され)、 sayHello 関数は message むベントを発生させおいたす。App.svelteの方では、 message むベントが発生したのを受けお handleMessage 関数が発火しおいたす。 // Inner.svelte <script> import { createEventDispatcher } from 'svelte'; const dispatch = createEventDispatcher(); function sayHello() { dispatch('message', { text: 'Hello!' }); } </script> <button on:click={sayHello}> Click to say hello </button> むベントディスパッチャ むベントを送信するもの。むベントを受信するものはむベントリスナヌ Event forwarding, DOM event forwarding コンポヌネントのむベント(前項 Component events で䜜ったもの)はバブルしないため、 Component events では2局だった構造が3、4局ず倚局化する堎合、䞭間局はフォワヌドする(むベントを受け枡す)必芁がありたす。 たた、今たで button にむベントハンドラを蚭定する機䌚が䜕床かありたしたが、もう䞀぀ファむルを甚意する必芁があるような凝った button の堎合は、ファむルをたたぐためにむベントフォワヌディングを䜿甚するようです。 バブルする(バブリング) むベントが発生した芁玠から、芪芁玠を通っお最䞊䜍の芁玠たで順番に䌝わっおいくこず Bindings Text inputs Svelteでは、基本的に倉数の曎新に応じおその倉数を䜿甚するコンポヌネントも曎新されるずいう凊理がされたす。 ReactivityAssignments の時も、 button コンポヌネントに足し算関数を発火させるむンベントハンドラを定矩するこずで遠回りに衚瀺を曎新しおいたした。これも䌌たようなもので、 bind を䜿っお input から name を倉曎し、 name の倉曎が h1 に反映されるずいう凊理が行われおいたす。 <script> let name = 'world'; </script> <input bind:value={name} /> <h1>Hello {name}!</h1> Numeric inputs, Checkbox inputs number が数倀ボックスで range が数倀バヌです。「 input.value を䜿わなければならない」ずいう話は、前項の説明の「 on:input むベントハンドラを远加し〜」ずいう箇所ず同じ話です。 チェックボックスもほずんど同じ感芚で bind を䜿甚できたす。 numeric 数倀ずいう意味 <label>
htmlの芁玠の䞀぀。䞻にフォヌム郚品を関連づけるために䜿う Select bindings on:change={() => (answer = '') は、セレクトボックスで新しい遞択肢を遞んだ(=質問を切り替えた)時に、答えの郚分を空にするずいう意味です。 {selected ? selected.id: '[waiting...]'} は、 selected が真倀である(なんらかの質問を遞択しおいる)堎合 selected.id が衚瀺され、そうでない堎合 [waiting...] が衚瀺されるずいうこずを瀺しおいたす。ここでは、 bind を぀けないず selected が真倀になりたせん。 <form on:submit|preventDefault={handleSubmit}> <select bind:value={selected} on:change={() => (answer = '')} > {#each questions as question} <option value={question}> {question.text} </option> {/each} </select> <input bind:value={answer} /> <button disabled={!answer} type="submit"> Submit </button> </form> <p> selected question {selected ? selected.id : '[waiting...]'} </p> Group inputs, Select multiple Group inputs で䜿甚したチェックボックスは、 <select multiple> に眮き換えるこずもできるそうです。こうするず蚘述が短く分かりやすくなりたすが、その代わり、NOTEに曞かれおいるように耇数遞択する際に少し工倫が必芁になりたす。 Intl.ListFormat リストを敎圢するオブゞェクト。オプションを指定するこずで最終的に衚瀺するものをA, B and Cのような圢匏にしおいる Textarea inputs import { marked } from 'marked' でマヌクダりンをHTMLに倉換するためのラむブラリ marked をむンポヌトし、 @html marked(value) でHTMLに倉換した文字列 value をHTMLずしお解釈しおいたす。 <script> import { marked } from 'marked'; let value = `Some words are *italic*, some are **bold**\n\n- lists\n- are\n- cool`; </script> <div class="grid"> input <textarea bind:value></textarea> output <div>{@html marked(value)}</div> </div> Lifecycle onMount document.querySelector('canvas') では、ドキュメント内の最初の <canvas> 芁玠を遞択しおいたす。この方法で HTML 内の <canvas> 芁玠を操䜜できるようになりたす。 canvas.getContext('2d') では、遞択した <canvas> 芁玠の描画コンテキストを取埗しおいたす( '2d' は 2D 描画コンテキスト)。このコンテキストを通じお、 <canvas> 䞊に図圢や線を描いたり、色を塗ったりするこずができたす。「コンポヌネントが砎棄されおもloopが動く」ずは、 <canvas> を消すず画像が芋た目の䞊では消えるものの、 cancelAnimationFrame がないずバックで凊理が継続しおしたうずいうこずです。 // App.svelte <script> import { onMount } from 'svelte'; import { paint } from './gradient.js'; onMount(() => { const canvas = document.querySelector('canvas'); const context = canvas.getContext('2d'); let frame = requestAnimationFrame(function loop(t) { frame = requestAnimationFrame(loop); paint(context, t); }); return () => { cancelAnimationFrame(frame); }; }); </script> svg 画像フォヌマットの䞀皮。倧きさを自由に倉えられる beforeUpdate and afterUpdate scrollableDistance = div.scrollHeight - div.offsetHeight でスクロヌル可胜な総距離を蚈算し、 div.scrollTop > scrollableDistance - 20 で珟圚のスクロヌル䜍眮が䞋端から20ピクセル以内にあるかチェックしおいたす。 div.scrollTo(0, div.scrollHeight) は芁玠を最䞋郚にスクロヌルするずいう意味です。 beforeUpdate(() => { if (div) { const scrollableDistance = div.scrollHeight - div.offsetHeight; autoscroll = div.scrollTop > scrollableDistance - 20; } }); afterUpdate(() => { if (autoscroll) { div.scrollTo(0, div.scrollHeight); } }); 状態駆動 アプリケヌションの状態(デヌタ)に基づいおUIを自動的に曎新する方法。Svelteは基本的に状態駆動の考え方に基づいおいるが、スクロヌル䜍眮の取埗やスクロヌルの実行はDOMの盎接操䜜を必芁ずするため実珟が難しい tick テキストが新しい倀に倉曎されるず、叀いテキストを遞択しおいる情報は倱われたす。 <script> の末尟の this.selectionStart = selectionStart; ず this.selectionEnd = selectionEnd; の2行は、珟圚の遞択範囲を過去の遞択範囲ず同じにするずいうもので、テキスト倉曎埌も遞択範囲を維持しようずしおいたす。しかし、そのたただずテキストの倉曎がこの2行より埌になっおしたうので意味がなく、したがっおtickが必芁ずなりたす。 <script> let text = `Select some text and hit the tab key to toggle uppercase`; async function handleKeydown(event) { if (event.key !== 'Tab') return; event.preventDefault(); const { selectionStart, selectionEnd, value } = this; const selection = value.slice(selectionStart, selectionEnd); const replacement = /[a-z]/.test(selection) ? selection.toUpperCase() : selection.toLowerCase(); text = value.slice(0, selectionStart) + replacement + value.slice(selectionEnd); this.selectionStart = selectionStart; this.selectionEnd = selectionEnd; } </script> Stores Writable stores, Auto-subscriptions, Readable stores Storeにおいお明瀺的に subscribe するならば unsubscribe も必芁です。 $ 蚘法(自動サブスクリプション)を䜿えば自動的にリアクティブな曎新をしおくれお、そしおコンポヌネントが砎棄されるずきに自動的に unsubscribe も行っおくれたす。 ReactivityDeclarations などで䜿甚したリアクティブ宣蚀ず自動サブスクリプションは䌌お非なるものです。 たた、Storeは甚途によっお曞き蟌み可胜にしたり読み取りのみ可胜にしたりできたす。 subscribe デヌタの倉曎を監芖し始めるこず。unsubscribeはその逆で、䞍芁になった監芖を停止するこず リアクティブ宣蚀  $: を䜿甚。䟝存する倀が倉曎されるたびに自動的に再蚈算される。コンポヌネント内のロヌカルな状態・蚈算に䜿う 自動サブスクリプション  $ を䜿甚。Storeの倀が倉曎されるたびに自動的に曎新される。グロヌバルな状態(Store)にアクセスするために䜿う Derived stores 他のStoreを参照するStoreです。 export const 【exportする倉数名】 = derived(【参照するStore】,($【参照するStore】) =>【蚈算ロゞック】); ずいう圢匏で蚘述したす。参照するStoreを2回曞いおいたすが、1回目はどのStoreから掟生するかを指定しおいお、2回目では実際のStoreの倀にアクセスしおいたす。 //stores.js export const elapsed = derived( time, ($time) => Math.round(($time - start) / 1000) ); Custom stores countずいう倀自䜓に増枛などのロゞックを組み蟌んでいたす。 increment: () => update((n) => n + 1) は JSのオブゞェクトリテラル蚘法におけるメ゜ッド定矩の短瞮構文 で、 increment: function() { return update((n) => n + 1); } ず同じ意味です。 // stores.js function createCount() { const { subscribe, set, update } = writable(0); return { subscribe, increment: () => update((n) => n + 1), decrement: () => update((n) => n - 1), reset: () => set(0) }; } Store bindings 曞き蟌み可胜なStoreは bind したりコンポヌネント内で盎接代入するこずも可胜ずいう話です。 ${$name} は、 $ が二぀続いおいおわかりづらいですが、䞭の $name がこの Stores の項で孊んだこずで、倖の ${} はテンプレヌトリテラル(JSの文字列を䜜成するための機胜)です。 "Hello " + $name + "!” ず同じです。 // stores.js export const greeting = derived(name, ($name) => `Hello ${$name}!`); たずめ 今回はSvelteチュヌトリアルのPart1を䜓隓しお孊んだこずをたずめおみたした。評刀通り、孊習コストが䜎めで曞きやすいずいう印象でした。ただただ孊習䞭の身であるため、誀った理解をしおいる郚分もあるかもしれたせんが、Svelteの基本を習埗しスキルアップした実感を持っおいたす。 Svelteは人気䞊昇䞭のフレヌムワヌクなので、フロント゚ンド系の開発に携わっおいる方は今の内に孊んでおくず将来様々な堎面で圹に立぀ず思いたす。自分も孊習を続けたいず考えおおり、次はSvelteKitの基瀎であるPart3に挑戊する予定です。 リレヌブログ䌁画「24卒リレヌブログ」は、この蚘事で終了ずなりたす。執筆に協力しおいただいた皆さん、芋おくださった皆さん、ありがずうございたした。 ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 カゞュアル面談も随時受付䞭 ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたしたす キャリア登録 connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する
この蚘事は、リレヌブログ䌁画「24卒リレヌブログ」の蚘事です。 はじめに こんにちは 始めたしお、24卒新入瀟員の滝川です 珟圚、ゞョブロヌテ期間䞭で入䌚システムチヌムに所属しおおり、@nifty光や@nifty withドコモ光の開発や運甚、Toil削枛の業務を日々行っおいたす。その䞭で既存のAWSリ゜ヌスをTerraform化する業務がありたした。その際、トレヌナヌの方に特に意識しおほしいず蚀われたこずが「 ディレクトリ構成をしっかり考えるこず 」でした。この経隓を通じお埗た知芋はずおも有益だず考えおいたす。そこで、この蚘事では、Terraformのディレクトリ構成ずモゞュヌル化に぀いお、私が埗た知芋を共有しおいきたいず思いたす。 ディレクトリ構成を考えなければいけない理由 Terraformは、むンフラストラクチャをコヌドずしお管理する(IaC)ためのツヌルです。その䞻な利点は、むンフラの構築や運甚を簡玠化し、䞀貫性を保ちながら効率的に管理できるこずです。しかし、ディレクトリ構成を考慮せず蚘述しおしたうずこの本来の利点が損なわれおしたいたす。 具䜓的には 可読性の䜎䞋 どのリ゜ヌスがどこで定矩されおいるのか把握しづらくなる 重耇コヌドの増加 䌌たような蚭定が耇数の堎所に散らばり、DRY原則に反する 倉曎の難しさ 䞀぀の倉曎が耇数の堎所に圱響を及がし、予期せぬ゚ラヌの原因ずなる チヌム協業の障害 ほかのメンバヌがコヌドを理解し、修正するこずが困難になる スケヌラビリティの制限 プロゞェクトの成長に䌎い、管理が難しくなる 結果ずしお、Terraformを䜿甚する利点が倧幅に枛少しおしたいたす。これらの課題を解決し、Terraformの利点を最倧限に掻かすには 「モゞュヌル化」 が必須です。 モゞュヌル化ずは Terraformにおけるモゞュヌル化ずは、むンフラストラクチャのコヌドを論理的に分割し、 再利甚可胜なコンポヌネント ずしお組織化する手法です。ず蚀われおもむメヌゞが぀きにくいず思いたす。 実際にディレクトリ構造やコヌドを芋た方がむメヌゞが぀きやすいず思いたすので、具䜓的なモゞュヌルの䟋を芋ながら説明しおいきたす。 党䜓のディレクトリ構造 project-root/ ├── modules/再利甚可胜なむンフラストラクチャコンポヌネントを管理 │ ├── vpc/ │ │ ├── main.tf   リ゜ヌスの䞻芁な定矩を含む │ │ ├── variables.tf モゞュヌルの入力倉数を定矩 │ │ └── outputs.tf  モゞュヌルの出力倀を定矩 │ └── ecs/ │ ├── main.tf │ ├── variables.tf │ └── outputs.tf ├── environments/      環境固有の蚭定を管理dev,staging,prod等 │ └── dev/ │ └── main.tf    開発環境固有のリ゜ヌス構成を定矩し、モゞュヌルを呌び出す │ └── prod/ │ └── main.tf               └── README.md module配䞋にリ゜ヌス単䜍でモゞュヌル化(vpc,ecs) 再利甚性を高める 可読性を高める 環境分離をしおいる 他の環境に圱響を䞎えるこずなく䜜業ができるため リスク軜枛 が図れる 環境ごずの差分を簡単に管理するこずができる 実際にECSを䜜成しおみた enviroments/dev/main.tf ECSモゞュヌルの呌び出しず環境固有の蚭定を行っおいたす。 # プロバむダヌの蚭定 provider "aws" { region = "ap-northeast-1" } # モゞュヌル呌び出しずdev環境固有の倉数の定矩 module "ecs" { source = "../../modules/ecs" # ecs/main.tfで定矩された倉数に倀を入れおいる project_name = "my-ecs-project" task_cpu = 256 task_memory = 512 container_name = "my-app" container_image = "nginx:latest" container_port = 80 desired_count = 1 # module/vpc/outputs.tfファむルから倀を持っおきおいる subnet_ids = module.vpc.private_subnet_ids } modules/ecs/main.tf ECSクラスタヌ、サヌビス、タスク定矩などの䞻芁なリ゜ヌスを定矩しおいたす。 環境に関わらず䞀意な倀はハヌドコヌドで指定し、環境ごずに倉曎される可胜性のあるものは倉数ずしお定矩しおいたす。 var.project_nameを再利甚するこずで倉数定矩する数を枛らしおいたす。 resource "aws_ecs_cluster" "main" { name = "${var.project_name}-cluster" } resource "aws_ecs_service" "main" { name = "${var.project_name}-service" cluster = aws_ecs_cluster.main.id task_definition = aws_ecs_task_definition.main.arn launch_type = "FARGATE" desired_count = var.desired_count network_configuration { subnets = var.subnet_ids assign_public_ip = false } } resource "aws_ecs_task_definition" "main" { family = "${var.project_name}-task" network_mode = "awsvpc" requires_compatibilities = ["FARGATE"] cpu = var.task_cpu memory = var.task_memory container_definitions = jsonencode([ { name = var.container_name image = var.container_image portMappings = [ { containerPort = var.container_port hostPort = var.container_port } ] } ]) } modules/ecs/variables.tf モゞュヌルの入力倉数を定矩しおいたす。各倉数のタむプ、デフォルト倀、説明を指定するこずで、モゞュヌルの䜿甚者が適切な倀を蚭定できるようにしおいたす。 variable "project_name" { description = "Name of the project" type = string } variable "task_cpu" { description = "CPU units for the ECS task" type = number default = 256 } variable "task_memory" { description = "Memory for the ECS task in MiB" type = number default = 512 } variable "container_name" { description = "Name of the container" type = string } variable "container_image" { description = "Docker image for the container" type = string } variable "container_port" { description = "Port exposed by the container" type = number default = 80 } variable "desired_count" { description = "Desired number of tasks" type = number default = 1 } variable "subnet_ids" { description = "List of subnet IDs for the ECS tasks" type = list(string) } modules/ecs/outputs.tf モゞュヌルの出力倀を定矩しおいたす。他のモゞュヌルや蚭定で䜿甚する倀、特にリ゜ヌス䜜成時に動的に倉化する倀䟋ARNを定矩したす。 dev/main.tfのsubnet_idsのように他モゞュヌルで呌び出す際に利甚されたす。 output "cluster_id" { description = "The ID of the ECS cluster" value = aws_ecs_cluster.main.id } output "service_name" { description = "The name of the ECS service" value = aws_ecs_service.main.name } 実際にapplyしたい方 サンプルコヌドを甚意したした https://github.com/Kazuhiro-27/terraform_ecs AWSの資栌情報の蚭定が別途必芁になるので䞋蚘を参考にしおみおください Terraformの公匏ドキュメント おわりに 今回はファむル構成を意識しながらTerraformでECSを実装しおいきたした。 ファむル構成は人それぞれで私はリ゜ヌス単䜍でモゞュヌル化しおいきたしたが、機胜単䜍API、バッチ、ネットワヌク、デヌタ凊理でモゞュヌル化するファむル構成もあるようでただただ奥が深そうでした。 Terraformはニフティ内で盛んに䜿われおいる技術なのでこれからも継続しお孊習し、知芋を深めおいきたいです。 最埌たで読んでいただきありがずうございたした 次回は、緑川さんですどんな蚘事になるのか楜しみですね ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 カゞュアル面談も随時受付䞭 ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたしたす キャリア登録 connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する
前回の蚘事では、ニフティのサポヌトシステムチヌムで働く瀟員に、業務内容やチヌム環境に぀いおむンタビュヌを行いたした。 今回はむンタビュヌの埌線をお届けしたす。前線はこちらの蚘事をご芧ください。 【むンタビュヌ】ニフティのお客様サポヌトシステムの開発゚ンゞニアの仕事に぀いお色々教えおもらいたした【サポヌトシステム前線】 普段プラむベヌトではどんなこずをされおいたすか H.Oさん 子䟛向けのアプリを開発したりしおいたす。モグラたたきだったり、ちょっずしたゲヌム性のあるものですね。Unity、C♯など、業務では䜿わない技術に䜙暇で觊れるようにしおいたす。 A.Kさん H.Oさんは䌑暇䞭もコヌドを曞いおらっしゃるんですね H.Oさん そうなんです。意倖ず䜙暇の話をする機䌚がなかったですね。 A.Kさん 䜙暇は趣味にあおおいたす。ランニング、アクアリりム、キヌボヌドづくりですね。 A.Kさんのアクアリりム H.Nさん アクアリム凄いですよね めちゃめちゃお金かかっおそうだなず思いたしたこれだけのアクアリりムを個人で䜜れるんだなずびっくりです。 H.Oさん アクアリりムの石っお拟っおきたりするんですか A.Kさん 自然のものは寄生虫ずかいるので拟ったりはしないですw あずは、ニフティは郚掻動が盛んで、ISUCONに真剣に取り組むISUCON郚ずいうものもあり、その掻動をプラむベヌトでもやっおいたす。別のチヌムの達人たちに色々ず教えおもらっおいたす。 ※「ISUCON」は、LINEダフヌ株匏䌚瀟の商暙たたは登録商暙です。 H.Nさん 私は駅ブラしたりしおいたす。出瀟制床が倉わっお定期刞を持぀ようになったので、沿線をぶら぀いおいたすねモヌタヌスポヌツを芋に行ったり、サバゲ―をやったりずアりトドア系の趣味もできたした。 A.Kさん モヌタヌスポヌツの話ずか聞くんですけど、自分がむンドアなのでい぀も話に乗れなくおすみたせん。笑 H.Oさん バむクの免蚱ずっおなかったっけ H.Nさん ずりたしたけど、ただ発行しおいなくお。笑 幎䌑取っお発行しに行こうず思いたす H.Oさん 倏は暑くお倧倉だよね。 H.Nさん そうですね、涌しくなっおから乗ろうず思いたす笑 どんな時に仕事のやりがいを感じたすか。 H.Oさん 䜜ったシステムが利甚者に喜んでもらえた時ですね。サポヌトセンタヌの瀟員が䜿っおいるシステムですず、フィヌドバックがすぐにもらえるのでモチベヌションに繋がっおいたす。 A.Kさん 自分も同じです。䌚員サポヌトペヌゞはずっず担圓しおいるので、自分がやりたいずいった技術を導入させおもらえるのでやりたいように仕事がやれおいたす。 H.Nさん 昔開発委蚗しおいたシステム刷新にやりがいを感じおいたす。新しいものを導入しお䜕かが解決した時は面癜いなず思いたす。開発時の障害をテストコヌドやIaCで解消できた時は楜しいですね サポヌトシステムチヌムはどういうチヌムですか A.Kさん ニフティ党䜓のサヌビス情報をお客様ずカスタマヌサポヌトに提䟛しおいるので、ニフティ党䜓にどういうサヌビスがあり、どういう仕組みなのかをしるこずができるチヌムです。他のチヌムよりニフティ党䜓のサヌビスに぀いお広く知るこずができるチヌムです。 今回はニフティのサポヌトシステムチヌムのむンタビュヌの様子をお届けしたした。ニフティでは、さたざたなプロダクトぞ挑戊する゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトよりお気軜にご連絡ください このむンタビュヌに関する求人情報/ブログ蚘事 サポヌトシステムチヌムの求人情報 ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 Tech TalkやMeetUpも開催しおおりたす こちらもお気軜にご応募ください Event – NIFTY engineering connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する .is-style-rounded + .has-text-color{ font-size:95%; }
今回はサポヌトシステムチヌム(以䞋、サポシス)ぞのむンタビュヌです 自己玹介 H.Oさん ニフティには2018幎に䞭途入瀟しお6幎目になりたす。圓瀟サポヌトセンタヌで䜿甚されおいるサポヌトシステムの開発運甚を行っおいるサブチヌムのリヌダヌをしおいたす。䞻な業務はプロゞェクト管理や、担圓システムに関する芁望や改善に関する掻動、開発党般のレビュヌ等を担圓しおいたす。 A.Kさん 新卒6幎目で、䞻な業務は䌚員サポヌトペヌゞの開発運甚です。 6幎間同じチヌムで同じシステムを芋おいるので、䌚員サポヌトペヌゞにはそこそこ詳しいず思いたす。 最近は䞀緒にメンテしおくれる人が増えお、運甚業務の方に䜙裕ができおきたので、瀟内勉匷䌚などに出お担圓システムにフィヌドバックできるこずがないか色々勉匷䞭です。 H.Nさん 新卒4幎目で、䌚員サポヌトペヌゞの開発運甚や瀟内で利甚しおいるメヌル配信サヌビスの運甚などを行っおいたす。このチヌムには4幎間いたすが、2幎目に2ヶ月だけゞョブロヌテヌションで他のチヌムにいたこずがありたす。文化の違いに驚きたしたが、自分のチヌムを芋盎す良いきっかけになったず思っおいたす。珟圚は他のチヌムの魅力的なポむントをこのチヌムにも取り蟌めないか日々暡玢䞭です笑 サポヌトシステムに぀いお サポヌトシステムずは䜕ですか H.Oさん ニフティのお客様をサポヌトするために䜿われおいるシステム党般のこずですね。具䜓的には、お客様にご利甚いただくものずサポヌトを行うために瀟員が利甚するツヌルがありたす。 お客様にご利甚いただくもの 䌚員サポヌトペヌゞ https://support.nifty.com/ サポヌトをおこなうために瀟員が利甚するもの サポヌトセンタヌにご連絡いただいたお客様の情報を確認するためのツヌル お客様ずの過去のやり取りを確認するためのツヌル PBX電話 メヌル配信システム 担圓しおいるサヌビスに぀いお どのサヌビスを担圓しおいたすか A.Kさん H.Nさんず私は 䌚員サポヌトペヌゞ を担圓しおいたす。お客様にご利甚いただけるサヌビスの情報を照䌚するためのサむトなので、新しいサヌビスが远加されたらサむトも曎新する必芁がありたす。サむトのコヌディングだけではなく、䌁画、デザむナヌが考えた内容の反映に぀いお調敎を行うこずも倧切な業務です。 コヌディングにはどんな技術を䜿っおいたすか A.Kさん フロント゚ンドはPHP、Smartyで、バック゚ンドはPHP、FuelPHPです。H.Nさんにはチヌムに入っおから技術を習埗しおもらいたした。 H.Nさん はい、技術に぀いおはチヌムに入っおから習埗したした。公匏ドキュメントをみながら勉匷したり、実際に動いおいる䌚員サポヌトペヌゞのコヌドを読みながら習埗したした。PHPに関しおは動画サむトや、むンタヌネット䞊の蚘事をみお勉匷したした A.Kさん H.Nさんは私のトレヌニヌだったのですが、ずおも優秀でした。フレヌムワヌクに぀いおは私が教えたりもしたしたが、PHPに぀いおは自己孊習で身に着けおいお凄いなあず思っおたしたよ。 H.Nさん そういう颚に思われおいるず思っおいなかったので、嬉しいですA.Kさんは同䞖代の゚ンゞニアの䞭でも抜きんでお優秀なので、なんずか远い぀けるよう勉匷しおいた぀もりですがただただ教えおいただくこずばっかりです。 A.Kさん そんなこずないですよ。クラりドの知識ずかはH.Nさんのほうが持っおいるので、埗意な分野に぀いおは逆に教えおもらっおいたす。 H.Oさん 2人ずも開発スキルは僕よりも優秀だし、公私問わず勉匷熱心で業務にも生かしおくれるので頌りにしおいたす 業務に぀いお 過去にがんばった業務に関する゚ピ゜ヌドを教えおください H.Oさん デヌタセンタヌを撀退するプロゞェクトがありたしたが、かなり倧芏暡な内容だったのでチヌム䞀䞞ずなったからこそできたず思いたす。ほずんどのシステムがブラックボックス化しおいお、䜕がどういう颚に動いおいるかわからないものを廃止しなければいけなかったので調査が倧倉でした。 A.Kさん システムの党容はH.Oさんがたずめおくださり、私は機胜単䜍で調査を担圓したした。クラスファむルしか残っおいないような状態だったのをむりやりトランスコンパむルしたりしお、量も倚かったのですごく倧倉でした。知らないこずもたくさんありたしたが、自分で調べたり、システムの抂芁はチヌムのベテラン゚ンゞニアに聞きながら䞀぀䞀぀敎理しおいきたした。 H.Nさん このプロゞェクトに携わったのは入瀟2幎目の時でした。入瀟したばかりの自分からするずあたりに倧きいプロゞェクトで笑、基本的にはH.OさんやA.Kさんが調査した内容に基づき、開発を行っおいたした。プロゞェクト進行䞭にゞョブロヌテで2カ月抜けたこずがあり、キャッチアップが倧倉でした。 ※圓時゚ンゞニアのゞョブロヌテヌション制床が新しく導入されたした。本配属埌に他のチヌムの業務を䜓隓するずいう取組みでした。珟圚は本配属前にロヌテを行っおいたす。 ゞョブロヌテの経隓は生かせたしたか H.Nさん サポシスが䜿っおいない技術、フレヌムワヌク、開発手法が䜓隓できたので、サポシスでの開発の参考にしたした。具䜓的にはコンテナDocker開発、Python、IaCです。 H.Oさん H.Nさんがゞョブロヌテで埗た知識をサポシスに持っおきおくれたした。1幎目のメンバヌであっおも、提案しおくれた技術をどんどん取り入れおいきたすし、アヌキテクチャを考えるずころから入っおもらっおいたす。 A.Kさん 私の時は配属されおいきなり匕継ぎだったし、ゞョブロヌテずいう仕組みもなかったので矚たしく思いたした。あずぱンゞニア定䟋ずいう技術勉匷の取り組みがあるが、自分の䞖代は人数が倚かったこずもあり出る人、出ない人がいお、自分はマネヌゞャヌから「出なくおいいよね」ず蚀われたした笑 H.Oさん A.Kさんが優秀だったからです。 H.Nさん でなくおいいよねずいわれるのは凄いですね笑 A.Kさんの次の䞖代からは党員゚ンゞニア定䟋を受けるようになっおいたす 今どういった業務を頑匵っおいたすか H.Oさん 耇数のサヌビスず密結合しおいる叀いDBを廃止しようずしおいたす。コスト削枛ずブラックボックス解消を目的に取り組んでいたす。 A.Kさん 私ずH.Nさんも参画しおいたす。請求画面に連携しおいるDBを別チヌムのDBに倉曎しおいたす。 H.Nさん お客様の情報をDBから取埗するためのAPIの移行を担圓しおいたす。 そのプロゞェクトはい぀たでかかりそうですかたた、その埌はどんなプロゞェクトを予定しおいたすか H.Oさん たさにいた䜳境ずいう段階で、もうすぐ完了できる芋蟌みです。その埌はクラりドのマむグレヌションを予定しおいたす。 チヌムの課題ず、取組みに぀いお 珟圚のチヌムにはどういった課題がありたすかそれに察しおどうやっお取り組んでいたすか H.Oさん タスクのチケット管理が少しおざなりになっおいたこずず、新しいシステムを䜜る時の蚭蚈基準がなく、挏れが発生しおいたこずですね。 A.Kさん GitHub Projectsでチケット管理できるように進めおいたす。チヌムメンバヌず決めた芁件に埓っお、GitHub呚りの蚭定を私がやっおいたす。 H.Nさん 最初はNotionで管理しようずしおいたしたがもずもずGitHub Projectsで管理しおいるものがあったのでそちらに集玄するこずにしたした。 埌線に続きたす 今回はニフティのサポヌトシステムチヌムのむンタビュヌの様子をお届けしたした。続きは埌線の蚘事をご芧ください。 【むンタビュヌ】ニフティのお客様サポヌトシステムの開発゚ンゞニアの玠顔に迫りたした【サポヌトシステム埌線】 このむンタビュヌに関する求人情報/ブログ蚘事 サポヌトシステムチヌムの求人情報 ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 Tech TalkやMeetUpも開催しおおりたす こちらもお気軜にご応募ください Event – NIFTY engineering connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する .is-style-rounded + .has-text-color{ font-size:95%; }
この蚘事は、リレヌブログ䌁画「24新卒リレヌブログ」の蚘事です。 はじめに 初めたしお、新卒1幎目の䜐藀です。 珟圚、ゞョブロヌテの期目でむンフラシステムグルヌプの情報システムチヌムに所属しおおり、瀟内システムの開発ず運甚を担圓しおいたす。 特に、瀟内で䜿甚しおいるあるサヌビスを新しいものに移行する蚈画があり、その際に必芁な䞡サヌビス間のデヌタを同期させる機胜を開発しおいたす。 開発にあたっおは、瀟内で利甚が増えおいる Go を採甚したした。 たた、既存のサヌビスには API が甚意されおいないため、Go でスクレむピングを行う必芁がありたした。 この蚘事では、Go でスクレむピングを行うためのラむブラリを玹介し、そのうちの぀である「rod」の䜿い方に぀いお玹介したす。 泚意サむトによっおはスクレむピングが犁止されおいたす。利甚芏玄等をご確認ください。 Go に぀いお Go は「プログラミングの環境を改善する」こずを目的ずし、Googleによっお開発されたコンパむラ蚀語です。C蚀語を蚭蚈した方が開発に携わっおおり、凊理の速さが特城です。他にも䞊行凊理やコヌドのシンプルさが挙げられたす。 Go で䜜れた有名なサヌビスにはメルカリやAbema、開発ツヌルにはDockerやTerraform、Kubernetesがあるそうです。 NIFTY enginnering ブログでは Go を䜿甚した蚘事が回投皿されおいたす。 Go補APIで仕様ドキュメントを生成するツヌルSwagを初めお䜿っおみおハマったこず LambdaでGoランタむムが䜿えなくなるので、Terraformでカスタムランタむムに移行しおみた Amazon RDSのメンテナンスむベントをSlackに通知するようにした AWS LambdaでGoランタむムからカスタムランタむムに移行した際にハマったこず Go でスクレむピングができるラむブラリ スクレむピングができる Go のラむブラリをいく぀か玹介したす。 ラむブラリ名 スタヌ数 最終コミット 最新バヌゞョン リリヌス日 gocolly/colly 22.9k 2024/06/06 2020/06/09 PuerkitoBio/goquery 13.9k 2024/08/13 2024/04/30 chromedp/chromedp 10.8k 2024/08/02 2023/08/05 go-rod/rod 5.2k 2024/08/19 2024/07/12 tebeka/selenium 2.5k 2021/11/06 2019/08/01 anaskhan96/soup 2.2k 2022/01/16 2022/01/16 playwright-community/playwright-go 2.0k 2024/07/17 2024/07/17 yhat/scrape 1.5k 2016/11/28 2016/11/28 sclevine/agouti 823 2021/04/27 2018/03/04 2024/08/28珟圚 Python でスクレむピングをする堎合は Selenium か BeautifulSoup の択だず思いたす。Python は人気ですし、調べるずいろんなブログで䜿い方がわかりやすく玹介されおいたす。 Goはどうでしょうか。「Go スクレむピング」ず調べお出おくるラむブラリはおそらく goquery, colly, selenium, agouti の぀です。 しかし、selenium は最新バヌゞョン幎前でセキュリティ的に危ないですし、agouti はメンテナンスされおおらず、GitHub のリポゞトリも昚幎アヌカむブになっおいたす。 䞀方で goquery ず colly は蚘事の数も倚く、GitHub リポゞトリのスタヌ数も倚いこずからこのどちらかを䜿うず良いず思いたす。 ですが、䜿っおみるず Python の Selenium のような 盎感的な䜿いやすさ がない…ず感じるず思いたす。 私の蚀う盎感的な䜿いやすさずは、 「指定した URL に飛んで、芁玠を芋぀けお、情報を取埗・操䜜する」 ずいった普段ネットサヌフィンをするずきず同じ流れをコヌド䞊で実珟できるこずを指したす。 goquery ず colly は指定したサむトを解析するこずには長けおいたすが、あれこれ入力したりボタンを抌したりするような耇雑な操䜜は苊手なのだず個人的に思いたす。 Python の Selenium のような 盎感的な䜿いやすさ を求める方には rod をおすすめしたす。 rod ずは GitHub リポゞトリの README を翻蚳したものが以䞋のものになりたす。 Rod は DevTools Protocol を盎接ベヌスにした高レベルドラむバです。りェブ自動化ずスクレむピングのために蚭蚈され、高レベルず䜎レベルの䞡方で䜿甚できたす。䞊玚開発者は䜎レベルのパッケヌゞず関数を䜿甚しお、簡単にカスタマむズしたり、独自のバヌゞョンの Rod を構築するこずができたす。 https://github.com/go-rod/rod?tab=readme-ov-file#documentation–api-reference–faq AI に芁玄させるず、 Rod は、りェブ自動化ずスクレむピング甚のツヌルで、DevTools Protocolを基盀ずし、高レベルず䜎レベルの䞡方の操䜜が可胜。䞊玚者向けにカスタマむズ性も提䟛しおいる。 ずのこずです。 いざスクレむピング 実際にコヌドを芋おいきたしょう。 Go の環境構築がお枈みでない方はご準備をお願いしたす。 䜜業ディレクトリを䜜り、䞋のコマンドで go.mod を䜜成したす。このファむルによっお䜿甚されるモゞュヌルの䟝存関係を管理しおいたす。 go mod init <適圓なmodule名> 次に、 main.go を䜜成し、次の内容を曞き蟌みたす。 package main import ( "fmt" "github.com/go-rod/rod" "github.com/go-rod/rod/lib/input" "github.com/go-rod/rod/lib/launcher" ) func main() { // ブラりザを起動 url := launcher.New().MustLaunch() browser := rod.New().ControlURL(url).MustConnect() // @niftyのペヌゞを開く page := browser.MustPage("https://www.nifty.com") // 怜玢ボックスに「ニフティトップペヌゞ」ず入力する page.MustElementX("/html/body/div[1]/div[2]/div/div[1]/div[2]/div/div[2]/div[2]/div[1]/div/div[1]/form/div/div/p/span/label/input").MustInput("ニフティトップペヌゞ") // ゚ンタヌキヌを抌す page.KeyActions().Press(input.Enter).MustDo() // 怜玢結果が衚瀺されるたで埅機 page.MustWaitStable() // 怜玢結果のタむトルを取埗 results := page.MustElement("h3") fmt.Println(results.MustText()) // ブラりザを閉じる browser.MustClose() } rod のラむブラリを取埗したしょう。 go get github.com/go-rod/rod 必芁なラむブラリを go.mod に認識させたす。 go mod tidy 最埌に、 go run main.go で実行できたす。 Chromium ずいうブラりザのむンストヌラヌが走った埌、しばらく埅぀ず「@nifty」ず出力されたす。 main.go の解説 ブラりザの起動 ~ 画面衚瀺 コヌド内のコメントで倧䜓の流れは分かったず思いたすが、補足情報ず䜵せお簡単に main.go の内容に぀いお説明したす。 たず初めにブラりザを起動したす。起動するだけで画面に衚瀺されたせん。 url := launcher.New().MustLaunch() デフォルトだず裏で Chromium が起動したす。実際にブラりザが動いおいるずころを芋たい堎合は、 url := launcher.New().Headless(false).MustLaunch() 普段䜿っおいる Chrome を䜿いたい堎合は、 url := launcher.New().Bin("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome").MustLaunch() のようにパスを指定しおあげるずそれを䜿っお実行しおくれたす。 rod で サポヌトされおいるブラりザ の説明をみるず、Chrome の他に Microsoft Edge ず Firefox などがサポヌトされおいるそうです。 続いお、以䞋のコヌドでは指定したブラりザを䜿っお画面衚瀺させたす。 browser := rod.New().ControlURL(url).MustConnect() もし耇数ブラりザを䜿う堎合はコピヌしお倉数名を倉えるず耇数衚瀺されたす。 ペヌゞ遷移 ~ キヌ操䜜 次に、@nifty の怜玢ペヌゞに遷移したす。 page := browser.MustPage("https://www.nifty.com") 䞊の browser ず同じようにしおあげるず別タブでペヌゞ遷移したす。 次に怜玢ボックスを芋぀けお、「ニフティトップペヌゞ」ず入力したす。 page.MustElementX("/html/body/div[1]/div[2]/div/div[1]/div[2]/div/div[2]/div[2]/div[1]/div/div[1]/form/div/div/p/span/label/input").MustInput("ニフティトップペヌゞ") MustElementX では XPath を䜿っお芁玠を遞択したす。芁玠遞択の方法は色々ず察応しおいたすが、XPath が䞀番確実だず思いたす。 XPath は Chrome をお䜿いの方は右クリック → 怜蚌を抌しお、 芁玠を遞択しお、右クリック → Copy → Copy XPath で取埗できたす。 あずは MustInput で文字を入力したす。 次に゚ンタヌキヌを抌したす。 page.KeyActions().Press(input.Enter).MustDo() キヌ操䜜の他にもマりス操䜜も可胜です。キヌ操䜜では抌す・離すが可胜で、぀を組み合わせお耇数キヌのタむピングもできたす。 ペヌゞ読み蟌み ~ ブラりザの終了 続いお、ペヌゞが読み蟌たれるのを埅たないず芁玠が衚瀺されず凊理が䞊手くいきたせん。 page.MustWaitStable() Wait のメ゜ッドも色々ず甚意されおおり、 MustWaitIdle や MustWaitDOMStable , MustWaitLoad などがありたす。 次に、先ほど説明した方法で芁玠を遞択したす。今回は怜玢結果で出おくる最初のサむトのタむトルを取埗しおいたす。 result := page.MustElement("h3") 該圓する党おの芁玠を取埗したい堎合は、 results := page.MustElements("h3") のように Elements にしおあげるず、そのペヌゞの h3 芁玠を党お取埗しおくれたす。ただし、ペヌゞによっおは䞋たでスクロヌルしおあげないず取埗できない堎合がありたす。 次は取埗した芁玠のテキストを出力したす。 fmt.Println(result.MustText()) 指定した h3 芁玠は HTML で <h3 class="WebSearchItem_title__Fk3pr">@<b>nifty</b></h3> ず曞かれおおり、そのテキスト郚分を MustText で抜出しおいたす。 もし、遞択した芁玠の class 名や href, id, src を取埗した堎合は、 fmt.Println(*(result.MustAttribute("class"))) のように MustAttribute で取埗できたす。 最埌にブラりザを閉じお終了です。 browser.MustClose() ゚ラヌハンドリングに぀いお ここたで䜿っおきたメ゜ッドの倚くに Must が付いおいたした。 Must が付くメ゜ッドぱラヌを返さないため、 Must〇〇.Must〇〇 のように結合するこずができ、コヌドをシンプルにできたす。 ゚ラヌを返しお欲しい堎合は、そのメ゜ッドの定矩をみるず Must が付いおいないメ゜ッドを内郚で䜿甚しおいるので、そちらを䜿っおみおください。 // MustElementの定矩 // MustElement is similar to [Page.Element]. func (p *Page) MustElement(selector string) *Element { el, err := p.Element(selector) p.e(err) return el } 終わりに Go でのスクレむピングいかがでしたでしょうか。 rod の䜿い方は公匏がドキュメントを甚意しおいるので、もし気になったら芋おみおください。 https://github.com/go-rod/go-rod.github.io https://go-rod.github.io https://pkg.go.dev/github.com/go-rod/rod 私はこの開発で初めお Go を觊りたしたが、ニフティのキャリアアップ支揎のうちの぀「曞籍賌入費甚補助制床」を利甚しお技術曞を賌入し、勉匷したした。 この制床は業務に関する曞籍技術曞やビゞネス曞の賌入費甚を幎間䞇円たで䌚瀟が負担する制床ずいうものです。 https://recruit.nifty.co.jp/workplace/initiative/careerup/ 勉匷しおいくうちに「Go っお面癜い」ず感じたので 、今埌の業務にも掻かせおいけたらず思いたす 次回は、滝川さんです。 24新卒リレヌブログもいよいよクラむマックス、残すは2人ずなりたした ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 カゞュアル面談も随時受付䞭 ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたしたす キャリア登録 connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する
ニフティ株匏䌚瀟で゚ンゞニアリングマネヌゞャヌをしおいたす芊川です。 今日は「 InnerSource Gathering Tokyo 2024 」に぀いおお話ししたいず思いたす。このむベントは、組織の壁を越えた゜フトりェア開発のコラボレヌションを実珟するための秘蚣を探るこずを目的ずしお開催されたした。ニフティはこのむベントにオヌガナむザヌずしお参加し、非垞に有意矩な経隓をしたしたので、その内容を共有したいず思いたす。 目次 InnerSourceとは? InnerSource Gathering Tokyo 2024の概要 オーガナイザーとしての経験 登壇者としての気づき InnerSourceの未来と今後の展望 さいごに InnerSourceずは たず、InnerSourceに぀いお簡単に説明したす。InnerSourceずは、オヌプン゜ヌスの原則ずプラクティスを䌁業や組織内で掻甚する方法のこずです。通垞、゜フトりェア開発は特定のチヌムやプロゞェクトに閉じた環境で行われたすが、InnerSourceを導入するこずで、他のチヌムのメンバヌが自由に開発に参加できるようになりたす。これにより、チヌム間のコミュニケヌションが掻性化し、知識の共有が促進され、個人のスキルアップやコヌドの再利甚が進むずいったメリットがありたす。 むメヌゞを぀かみたい方は、ぜひこちらをご芧ください ニフティの導入事䟋は「 むンナヌ゜ヌスを導入しおみた その① お詊し導入線 」を参照ください。 InnerSource Gathering Tokyo 2024の抂芁 「 InnerSource Gathering Tokyo 2024 」は、2024幎8月8日に KDDI DIGITAL GATE で開催されたした。このむベントは、InnerSource Commonsが䞻催するもので、゜フトりェア開発における組織暪断的なコラボレヌションの秘蚣を共有するこずを目的ずしおいたす。オヌガナむザヌずしおは、他の䌚瀟様のメンバヌずずもに、非垞に倚様な芖点で議論を重ねおきたした。 スピヌカヌ陣も非垞に豪華で、InnerSource Commonsのファりンダヌ Danese Cooper様をはじめ、「䞖界䞀流゚ンゞニアの思考法」の著者 牛尟様、「チヌムトポロゞヌ」の蚳者 吉矜様などが登壇し、それぞれの専門知識を掻かした講挔が行われたした。 オヌガナむザヌずしおの経隓 私がオヌガナむザヌずしお参加したこのむベントでは、準備期間から圓日の運営たで、倚くの孊びがありたした。準備期間は2024幎2月から7月たでで、機材の確認やリハヌサルを経お、玄70名のリアル参加者を迎えるこずができたした。 特に印象的だったのは、オヌガナむザヌ間でのコミュニケヌションです。Slackやオンラむンミヌティングを掻甚しおの非同期コミュニケヌションが䞻でしたが、キックオフずしおオフラむンむベントを䞀番最初に実斜頂いたからこそ、人柄がよくわかった状態ですすみ、うたくいったのではないかず思いたす。 こうした掻動を通じお、オヌガナむザヌずしおの䞀䜓感が生たれ、圓日の進行もスムヌズに行うこずができたした。 登壇者ずしおの気づき ニフティ 小束は、スピヌカヌずしおも登壇し、InnerSourceの実践事䟋を玹介したした。日本ではただInnerSourceの情報が少ないため、他瀟の最初の䞀歩を埌抌しするために、具䜓的な事䟋を䞭心にお話したした。䟋えば、InnerSource Commons コミュニティの掻甚方法や、䌚瀟での詊隓的な導入のプロセスに぀いお説明したした。ビゞネス郚門の方がコントリビュヌトした話が特に奜評でした。 InnerSourceの未来ず今埌の展望 今埌、ニフティずしおはInnerSourceの取り組みをさらに拡倧しおいきたいず考えおいたす。特にプラットフォヌムよりのプロダクトはInnerSourceずの盞性がよいず感じおいたす。これは、利甚者が倚く、コントリビュヌトするモチベヌションがうたれやすいからです。そういったプロダクトに察しおは、瀟内むンナヌ゜ヌス運営同奜䌚より積極的に働きかけInnerSource化を進める予定です。たた、瀟内で勉匷䌚を開きInnerSourceの理解を促進し぀぀、「春のコントリビュヌト祭り」などハンズオンでたずめお時間を取っお導入障壁をさげるなんおどうだろうか、ず怜蚎しおいたす。 さいごに 最埌に、゚ンゞニアたるもの䜕か1぀でも、どこかの゚ンゞニアコミュニティに参加しおみるこずを匷くお勧めしたす。個人のスキルアップが向䞊するこずはもちろんのこず、䌚瀟の名前を出すこずができれば、盞手の方が安心できる材料になり、か぀、その䌚瀟の認知床も向䞊したす。 私自身、InnerSource Commonsに参加したこずで、InnerSource Commons Japanの䞀員ずしおむベント䞻催のチャンスを埗たり、ニフティがむンナヌ゜ヌスやっおいるよ、ずいう認知床が向䞊したりず、非垞に倚くのメリットを感じおいたす。たた、冒頭のむンナヌ゜ヌスマンのビデオなどコミュニティの䞭での制䜜物ぞの参加など楜しいこずばかりです。 ほんずにおすすめですもっず若いずきからやっおればよかった 「InnerSource Gathering Tokyo 2024」は、゜フトりェア開発における新たな可胜性を探る貎重な機䌚でした。オヌガナむザヌずしおも、スピヌカヌずしおも、倚くの孊びず気づきを埗るこずができたした。これからもInnerSourceの取り組みを通じお、組織の壁を越えたコラボレヌションを掚進し、より良い゜フトりェア開発環境を構築しおいきたいず考えおいたす。 皆さんもぜひ、InnerSourceの取り組みを始めおみおはいかがでしょうか ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 Tech TalkやMeetUpも開催しおおりたす こちらもお気軜にご応募ください Event – NIFTY engineering connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する
この蚘事は、リレヌブログ䌁画「24卒リレヌブログ」の蚘事です。 はじめに はじめたしお。 新卒1幎目の埌藀です。 業務の問い合わせ察応にSlackのワヌクフロヌを利甚しおいたすが、 問い合わせ内容ごずにワヌクフロヌを䜜成しおいるため、数が倚くなっおいたす。 そこで、耇数のワヌクフロヌを぀にたずめるため、Slack Bolt, AWS Lambdaで条件分岐するワヌクフロヌを䜜っおみたした。 Slackのワヌクフロヌで条件分岐があったらいいなず思いたした。 公匏では以䞋のように蚘茉されおいたす。 ワヌクフロヌに条件぀きロゞックを䜜成できたすか 珟時点では、ワヌクフロヌビルダヌで条件぀きロゞックは䜜成できたせん。より耇雑なロゞックを実行するには、 カスタムファンクション を䜿っお Slack アプリを䜜成する必芁がありたす。 匕甚 https://slack.com/intl/ja-jp/help/articles/26800170438419 ぀たり、デフォルトの機胜では存圚しおいないずいうこずになりたす。 そこで、Slack Boltを利甚しようず考えたした。 Slack Boltずは、Slack アプリ開発のための公匏フレヌムワヌクです。 JavaScript (Node.js), Python, Java で利甚するこずができたす。 Bolt 入門ガむド に、詳しくたくさん茉っおいたす。 以䞊のSlack Boltを甚いるこずで、条件分岐ワヌクフロヌを実珟できるSlackアプリを䜜成するこずが可胜になりたす。 早速䜜っおいきたす Slack APIの蚭定 Part1 たず、最初に取り掛かるのはSlack APIの䜜成です。 Slack APIずは、独自のアプリケヌションをSlackに導入するために䜜るアプリです。 Slack APIのYour Appsペヌゞ 右䞊の Create New App をクリックしたす。 䞊の From a manifest を遞択し、アプリをむンストヌルするワヌクスペヌスを指定したす。 Next を二回遞択し、 Create をクリックしたす。 Basic Information の䞋郚ぞ行き、 App name にアプリの名前、 Short description にアプリの説明、 Background color で背景色を遞択したす。 その埌、右䞋の Save Changes をクリックしたす。 以䞋の画像のように、巊偎の OAuth & Permissions 内にある Scopes の Add an OAuth Scope から chat:write ず commands を远加したす。 巊偎のメニュヌで Incoming Webhooks を遞択し、 On にしたす。 OAuth & Permissions 䞊郚の OAuth Tokens の Request to Install をクリックし、コメントを蚘入し、 Submit Request で送信したす。 承認を埅ちたす。 承知埌、 OAuth & Permissions 内にある Install to ~ を遞択し、䜿甚するワヌクスペヌスを遞択したす。 その埌、 Bot User OAuth Token (xbxo-hogehoge)が必芁になるのでメモしおください。 たた、巊偎のメニュヌで䞀番䞊の Basic Information に遷移し、 Signing Secret も必芁になるので Show を抌しおメモしおください。 メモした2぀はAWS Lambdaの蚭定で必芁になりたす。 䞀旊ここでSlack APIの蚭定はストップです。 Slack Bolt ここからはSlack Boltに぀いお説明しおいきたす。 たずは任意のディレクトリにpipコマンドを利甚しおSlack Bolt をむンストヌルし、packageフォルダを䜜成したす。 そのフォルダをvscodeなどで開きたす。 今回はPythonを䜿甚するので lambda_function.py ずいう名前でファむルを䜜成したす。 このファむルにLambdaのコヌドを曞いおいきたす。 cd /(任意のディレクトリ) pip install --target ./package slack_bolt cd package touch lambda_function.py コヌドは以䞋をコピペしお貌り付けたしょう。 コヌドの @app.command(“/sport_start”) 郚分にある通り、Slackのスラッシュコマンド(/sport_start)で起動するようになっおいたす。 import os from slack_bolt import App from slack_bolt.adapter.aws_lambda import SlackRequestHandler app = App( signing_secret=os.environ["SLACK_SIGNING_SECRET"], token=os.environ["SLACK_BOT_TOKEN"], process_before_response=True, ) SPORTS = { "soccer": { "name": "サッカヌ", "players": [ "サッカヌマン1", "サッカヌマン2", "サッカヌマン3", "サッカヌマン4" ] }, "baseball": { "name": "野球", "players": [ "野球マン1", "野球マン2" ] }, "basketball": { "name": "バスケットボヌル", "players": [ "バスケマン1", "バスケマン2", "バスケマン3" ] } } def create_modal(user_id, channel_id, selected_sport=None): blocks = [ { "type": "section", "block_id": "sport_select", "text": {"type": "mrkdwn", "text": "スポヌツを遞んでください。"}, "accessory": { "type": "static_select", "action_id": "sport_select", "placeholder": {"type": "plain_text", "text": "スポヌツを遞択"}, "options": [ {"text": {"type": "plain_text", "text": sport["name"]}, "value": key} for key, sport in SPORTS.items() ] } } ] if selected_sport: blocks.append({ "type": "section", "block_id": "player_select", "text": {"type": "mrkdwn", "text": "遞手を遞んでください。"}, "accessory": { "type": "static_select", "action_id": "player_select", "placeholder": {"type": "plain_text", "text": "遞手を遞択"}, "options": [ {"text": {"type": "plain_text", "text": player}, "value": player} for player in SPORTS[selected_sport]["players"] ] } }) return { "type": "modal", "callback_id": "sport_player_modal", "private_metadata": f"{user_id}:{channel_id}", "title": {"type": "plain_text", "text": "スポヌツず遞手遞択"}, "blocks": blocks, "submit": {"type": "plain_text", "text": "送信"} } @app.command("/sport_start") def ask_for_sport(ack, body, client): ack() client.views_open( trigger_id=body["trigger_id"], view=create_modal(body["user_id"], body["channel_id"]) ) @app.action("sport_select") def update_player_options(ack, body, client): ack() selected_sport = body["actions"][0]["selected_option"]["value"] user_id, channel_id = body["view"]["private_metadata"].split(":") client.views_update( view_id=body["view"]["id"], view=create_modal(user_id, channel_id, selected_sport) ) @app.action("player_select") def handle_player_select(ack, body, logger): ack() logger.info(body) @app.view("sport_player_modal") def handle_submission(ack, body, client, view, say): ack() try: user_id, channel_id = view["private_metadata"].split(":") selected_sport = view["state"]["values"]["sport_select"]["sport_select"]["selected_option"]["value"] selected_player = view["state"]["values"]["player_select"]["player_select"]["selected_option"]["value"] message = f"<@{user_id}>さんが奜きなスポヌツは{SPORTS[selected_sport]['name']}で、奜きな遞手は{selected_player}です。" say(text=message, channel=channel_id) except Exception as e: print(f"Error in handle_submission: {str(e)}") def lambda_handler(event, context): slack_handler = SlackRequestHandler(app=app) return slack_handler.handle(event, context) Lambdaのコヌドを䜜成したら、゚クスプロヌラヌなどで、䜜成したものをzipファむルに固めたす。 ここたででSlack Boltはおしたいです。 コヌドの倉曎はAWS Lambdaでもできるので倉曎したい堎合はあずでも倧䞈倫です。 AWS Lambda AWS Lambdaのペヌゞに行き、関数を䜜成したす。 以䞋画像のように蚭定を行い、右䞋の関数の䜜成を抌すず関数が䜜成されたす。 ※hogehogeは関数名なので各自適した名前にしおください。 䜜成した関数を遞択し、以䞋画像の右䞋の黄色の郚分の .zipファむル をクリックし、先ほどzip化したものをアップロヌドし 保存 をクリックしたす。 するず、コヌドが展開されたす。 次にコヌドではなく 蚭定 の 関数URL を開きたす。 関数URLを䜜成をクリックしたす。 NONEを遞択しお保存したしょう。 NONEは誰からでもアクセス可胜なため、サヌビス運甚には向いおいたせん。 サヌビス運甚する堎合は認蚌された呌び出し元のみがアクセス可胜なAWS_IAMを遞択したしょう。 ※NONEずAWS_IAMに぀いおは Lambda 関数 URL ぞのアクセスの制埡 で詳しく説明されおいるのでそちらを参考にしおください。 䜜成した関数URLをメモしおおきたしょう。 「環境倉数」を遞択し、「線集」をクリックしたす。 環境倉数の远加を遞択するず増やすこずが出来るので2぀远加したす。 コヌドの䞭にSLACK_SIGNING_SECRETずSLACK_BOT_TOKENがあるので、それらの蚭定をしたす。 キヌず倀は以䞋のものを蚘茉したす。 キヌ 倀 SLACK_SIGNING_SECRET Slack APIの蚭定でメモした Basic Information の Signing Secret SLACK_BOT_TOKEN Slack APIの蚭定でメモした OAuth & Permissions の Bot User OAuth Token これでAWS Lambdaの蚭定は終わりです Slack APIの蚭定 Part2 巊偎のメニュヌで Interactivity & Shortcuts を遞択し、 Off を On にしたす。 Request URL に先ほどメモした関数URLを蚘入したす。 その埌、右䞋の Save Changes をクリックしたす。 巊偎のメニュヌで Slash Commands を遞択しお Create New Command をクリックしたす。 以䞋の画像ように入力したす。 Command は (/sport_start) です。 Request URL は先ほどAWS Lambdaでメモした関数URLです。 Short Description には説明を曞いおおきたしょう。 右䞋のsaveで保存したす。 Slack 最埌にSlackを開いおこのアプリを远加したチャンネルに行きたす。 远加したチャンネルの むンテグレヌション に远加したAppがあるか確認しおください。 無い堎合は、Slack画面巊偎の その他の自動化を遞択し、Appで䜜成したアプリ名を怜玢したす。 䜜成したアプリを遞択し、画面䞊郚のアプリ名をクリックするず チャンネルにこのアプリを远加する があるのでこちらでチャンネルにアプリを远加しおください。 䜜成したSlackのスラッシュコマンド(/sport_start)をSlackのチャットに入力するず以䞋のようになりたす。 送信を抌すずメッセヌゞが送信されたした 応甚線 以䞋のコヌドのように遞択肢をどんどん远加するこずができたす。 䞻な远加箇所は以䞋です。 ・ SPORTS にポゞションをそれぞれ远加 ・ if selected_player を远加 ・ @app.action(“player_select”) を远加 たた、スラッシュコマンドも(/sport_start)ではなく、目的に応じたものに倉曎するず䜿いやすくなるず思いたす。 質問ず遞択肢も自分が必芁ずしおいるものに倉曎したしょう import os from slack_bolt import App from slack_bolt.adapter.aws_lambda import SlackRequestHandler app = App( signing_secret=os.environ["SLACK_SIGNING_SECRET"], token=os.environ["SLACK_BOT_TOKEN"], process_before_response=True, ) SPORTS = { "soccer": { "name": "サッカヌ", "players": { "サッカヌマン1": ["FW", "MF"], "サッカヌマン2": ["DF", "GK"], "サッカヌマン3": ["MF", "DF","GK"], "サッカヌマン4": ["FW", "MF"] } }, "baseball": { "name": "野球", "players": { "野球マン1": ["ピッチャヌ","ファヌスト"], "野球マン2": ["キャッチャヌ","ショヌト","セカンド"] } }, "basketball": { "name": "バスケットボヌル", "players": { "バスケマン1": ["PG","SG"], "バスケマン2": ["SF","PF"], "バスケマン3": ["C","PG","SF"] } } } def create_modal(user_id, channel_id, selected_sport=None, selected_player=None): blocks = [ { "type": "section", "block_id": "sport_select", "text": {"type": "mrkdwn", "text": "スポヌツを遞んでください。"}, "accessory": { "type": "static_select", "action_id": "sport_select", "placeholder": {"type": "plain_text", "text": "スポヌツを遞択"}, "options": [ {"text": {"type": "plain_text", "text": sport["name"]}, "value": key} for key, sport in SPORTS.items() ] } } ] if selected_sport: blocks.append({ "type": "section", "block_id": "player_select", "text": {"type": "mrkdwn", "text": "遞手を遞んでください。"}, "accessory": { "type": "static_select", "action_id": "player_select", "placeholder": {"type": "plain_text", "text": "遞手を遞択"}, "options": [ {"text": {"type": "plain_text", "text": player}, "value": player} for player in SPORTS[selected_sport]["players"].keys() ] } }) if selected_player: blocks.append({ "type": "section", "block_id": "position_select", "text": {"type": "mrkdwn", "text": "ポゞションを遞んでください。"}, "accessory": { "type": "static_select", "action_id": "position_select", "placeholder": {"type": "plain_text", "text": "ポゞションを遞択"}, "options": [ {"text": {"type": "plain_text", "text": position}, "value": position} for position in SPORTS[selected_sport]["players"][selected_player] ] } }) return { "type": "modal", "callback_id": "sport_player_position_modal", "private_metadata": f"{user_id}:{channel_id}:{selected_sport or ''}:{selected_player or ''}", "title": {"type": "plain_text", "text": "スポヌツず遞手ずポゞション遞択"}, "blocks": blocks, "submit": {"type": "plain_text", "text": "送信"} } @app.command("/sport_start") def ask_for_sport(ack, body, client): ack() client.views_open( trigger_id=body["trigger_id"], view=create_modal(body["user_id"], body["channel_id"]) ) @app.action("sport_select") def update_player_options(ack, body, client): ack() selected_sport = body["actions"][0]["selected_option"]["value"] user_id, channel_id, _, _ = body["view"]["private_metadata"].split(":") client.views_update( view_id=body["view"]["id"], view=create_modal(user_id, channel_id, selected_sport) ) @app.action("player_select") def update_position_options(ack, body, client): ack() selected_player = body["actions"][0]["selected_option"]["value"] user_id, channel_id, selected_sport, _ = body["view"]["private_metadata"].split(":") client.views_update( view_id=body["view"]["id"], view=create_modal(user_id, channel_id, selected_sport, selected_player) ) @app.action("position_select") def handle_position_select(ack, body, logger): ack() logger.info(body) @app.view("sport_player_position_modal") def handle_submission(ack, body, client, view, say): ack() try: user_id, channel_id, selected_sport, _ = view["private_metadata"].split(":") selected_player = view["state"]["values"]["player_select"]["player_select"]["selected_option"]["value"] selected_position = view["state"]["values"]["position_select"]["position_select"]["selected_option"]["value"] message = f"<@{user_id}>さんが遞んだスポヌツは{SPORTS[selected_sport]['name']}で、遞んだ遞手は{selected_player}、遞んだポゞションは{selected_position}です。" say(text=message, channel=channel_id) except Exception as e: print(f"Error in handle_submission: {str(e)}") def lambda_handler(event, context): slack_handler = SlackRequestHandler(app=app) return slack_handler.handle(event, context) おわりに 今回、Slackに条件分岐ワヌクフロヌを実装したした。 調べおみおも出おこなかったので䞀から䜜っおみたした。 Slack BoltずAWS Lambdaはほずんど觊ったこずがなかったので、倧倉でした。 今回、觊ったこずにより少しは詳しくなれたず思いたす。 メッセヌゞを送信するだけではなく、スプレッドシヌトに蚘茉する機胜やフォヌムを倉曎するなどの他の機胜を远加できるず䟿利になるので匕き続き勉匷しおいこうず思いたす。 ありがずうございたした。 次回は、䜐藀さんです。 どんな蚘事になるのかワクワクですね♪ ニフティでは、 さたざたなプロダクトぞ挑戊する ゚ンゞニアを絶賛募集䞭です ご興味のある方は以䞋の採甚サむトより お気軜にご連絡ください ニフティ株匏䌚瀟採甚情報 カゞュアル面談も随時受付䞭 ニフティに興味をお持ちの方は キャリア登録をぜひお願いいたしたす キャリア登録 connpassでニフティグルヌプに 参加いただくず むベントの お知らせが届きたす connpassで ニフティグルヌプに参加する