TECH PLAY

AGEST

AGEST の技術ブログ

479

初めまして。金丸です。 この度、私が参加していたSQiP研究会の研究成果として執筆した論文「繰り返しのテストを要する生成AIテストの効率化 – 類似度算出と同義文判定による検証コスト削減の検討 -」が、幸運にも最優秀賞をいただくことができました。本日は、この研究にどのように取り組み、SQiP研究会でどのような経験を得られたのか、私の視点からお話ししたいと思います。 ※SQIP研究会とは? ソフトウェア品質向上と開発プロセス改善をテーマに、日科技連が主催する実践的な学びの場です。参加者は事例共有や討議を通じて、現場で役立つ知識やノウハウを深め、具体的な課題解決を目指します。 なぜSQiP研究会に参加したのか? 私がSQiP研究会に参加した一番の動機は、日々進化する「AI」に関する最新の動向や技術に対する強い渇望感でした。特に、私たちの主要な事業領域である「ソフトウェアテスト」において、AI、とりわけ生成AIの存在感は無視できないものになってきています。しかし、そのテスト手法についてはまだまだ確立されていない部分が多く、体系的で詳細かつ具体的な知識を身につけたいと考えていました。SQiP研究会であれば、様々なバックグラウンドを持つ専門家の方々と集中的に議論できる機会があると考え、参加を決めました。 試行錯誤から生まれた研究テーマ SQiP研究会は、月1回の定例会を中心に活動が進みます。午前中は特別講義として、ソフトウェア品質に関する第一線で活躍されている講師の方々から、大変示唆に富むお話を伺うことができます。午後は分科会に分かれ、それぞれのテーマに沿った知識共有や活発なディスカッションが行われます。 私たちの分科会には、私と同じようにAI、特に生成AIのテストや品質評価に課題意識を持つメンバーが集まりました。最初は漠然とした問題意識の共有から始まりますが、議論を重ねるうちに、それぞれが抱える具体的な課題の共通点が見えてきます。そこで、似通った課題を持つメンバーでチームを組み、検討するテーマを絞り込んでいきました。 私たちのチームが着目したのは、生成AIの「回答の多様性」がテストの大きな負担になっている、という点でした。同じ問い合わせをしても、AIの回答の表現は毎回異なります。もちろん、その意味内容が同じであれば問題ないのですが、テスト担当者はその都度、回答を読んで内容が正しいかを確認する必要があり、これが繰り返しのテストにおいて膨大な工数を生み出していたのです。 研究の核心:類似度評価はテストを効率化できるか? この課題を解決できないか、という問題意識から生まれたのが、本研究テーマである「類似度算出と同義文判定による検証コスト削減」の検討です。つまり、生成AIが生成した文章の意味的な類似度を機械的に評価し、「これは以前に確認済みの回答と同じ意味内容だ」と判定できれば、人間の確認作業を大幅に削減できるのではないか、と考えたのです。 研究では、この「類似度の数値化」の手法として、文章をベクトル化して類似度を測る「埋め込み表現のコサイン類似度」と、生成AI自身に類似度を評価させるという、ある種ユニークな「生成AIによる類似度評価」の2つのアプローチを取り上げ、どちらがより人間の感覚に近い判定ができるかを比較検証しました。 夏には泊まり込みの合宿を行い、長時間にわたり集中的に議論を深めました。この合宿で、研究の方向性が固まり、その後の実験計画が具体的に定まりました。合宿後は、メンバー間で役割分担を行い、手分けして実験データの準備、実験の実行、そして結果の分析を進めました。 実験の結果、特に生成AIを用いた類似度評価が、人間の感覚により近い評価傾向を示すことが明らかになりました。AUC(曲線下面積)という評価指標で比較しても、生成AIによる評価の方が高い値を示し、テスト効率化の手段として一定の有効性があることが示唆されました 。一方で、文章が長くなると類似度が高く判定されやすくなるなど、課題もいくつか見つかりました 。これらの実験結果に基づき、メンバー3名で分析を行い、追加で検討すべき観点なども取捨選択しながら、研究の論旨をまとめていきました。   論文執筆、そして成果報告会へ 12月頃からは、研究成果を論文としてまとめる作業と並行して、成果報告会での発表資料作成を進めました。論文執筆は初めての経験でしたが、メンバーと協力し、お互いのドラフトをレビューしながら推敲を重ねました。 そして迎えた3月の成果報告会。緊張感のある空気の中、研究成果を発表しました。発表会後に「最優秀賞」という素晴らしい評価をいただき、チームメンバーと共に喜びを分かち合いました。 SQiP研究会に参加して得られたもの、そしてそのメリット・デメリット SQiP研究会に参加して得られたものは非常に大きかったです。まず、最新のAI品質評価に関する国内外の知見や、RAG、Ragas、MCPといった関連技術の情報をキャッチアップできたことは、日々の業務にも直結する大きなメリットでした。また、特別講義や分科会での議論を通して、講師陣や他の参加メンバーからいただいた本質的で的確なレビューやフィードバックは、研究の質を高める上で不可欠でした。 SQiP研究会の大きなメリットとして挙げられるのは、「締め切り駆動で研究を進めることができる」点だと感じています。本業がある中で研究活動の時間を確保するのは容易ではありませんが、定例会や論文提出、発表会といった明確なマイルストーンがあることで、モチベーションを維持し、計画的に研究を進めることができました。そして何より、普段の業務では関わることが難しい、社外の様々なバックグラウンドを持つ方々と深く議論できたことは、自身の視野を広げ、新たな視点や着想を得る上でかけがえのない財産となりました。 おわりに 私の所属している会社ではSQiPでの活動も業務の一環として認められており、この論文以外にも、非常に多くの知識を得ることができました。 今後、それらを社内のAIテストのワーキンググループなどにフィードバックし、よりよいAIテスト手法の構築を目指して行きたいと考えております。 参考文献 繰り返しのテストを要する生成AIテストの効率化 – 類似度算出と同義文判定による検証コスト削減の検討 – (本研究論文)(PDF) AIプロダクト品質保証コンソーシアム ガイドライン 謝辞 最後に、本研究を共に推進し、貴重なご意見とご協力を賜りました共同研究者の皆様に心より感謝申し上げます。 リーダーとして本研究を牽引してくださった 中川 桂 様(東京海上日動システムズ株式会社)、共に研究員として議論を重ねた 多田 麻沙子 様(TIS株式会社) には大変お世話になりました。 主査として的確なご指導を賜りました 石川 冬樹 様(国立情報学研究所)、副主査として本研究をサポートしてくださった 徳本 晋 様(富士通株式会社)、アドバイザーの 栗田 太郎 様(ソニー株式会社) に深く感謝申し上げます。 皆様のご協力なくして、本研究の成果は得られませんでした。この場をお借りして、改めて御礼申し上げます。 The post SQiP研究会で生成AIテストの最前線に挑む:不確実性による評価の壁をどう乗り越えるか? first appeared on Sqripts .
はじめまして。クオリティコンサルタントの つとう工房 です。 ソフトウェア開発における「品質」とは、いったい何を意味するのでしょうか。 PMBOKやISO等の国際的な標準に準拠し、チェックリストを整備し、ルール通りにレビューを行う。確かに、それは品質保証にとって欠かせない取り組みの一つです。しかし、「品質」の問題に関して、私が、現場で常に感じているのは、その取り組みだけでは不十分だということです。 真に求められるのは、現場の実態を理解し、プロジェクトごとの特性を見抜き、表層的な課題の奥に潜む本質を見極める力。言い換えるならば、“イメージ力”と呼ばれるものの重要さです。本稿では、気軽な読み物の体裁を保ちながら、私が、直近対応した大規模プロジェクトの事例をもとに、“イメージ力”がなぜ品質向上に不可欠なのかを掘り下げてみたいと思います。 1. 品質の確保を阻んでいたのは開発に向き合う“体質”だった 現在、私が支援中の案件は、3年にわたる大規模システム開発プロジェクトです。私が参画したタイミングでは、開始からすでに2年以上が経過していましたが、進捗管理も、プロダクトの品質管理もまったく機能していない状態でした。 ヒアリングを開始した当初、関係者からは「うまくいっていないのは外部要因のせい」「人手不足がすべての原因だ」といった声がまことしやかに囁かれていました。 しかし、私は、その言葉を鵜呑みにせず、現場で交わされる会話、提出された資料、ミーティングでの空気感から醸し出される、いわゆる“ノイズ”に注目しました。そうして、時間をかけて丁寧に観察していくうちに、次第にプロジェクトの根本的な問題が浮かび上がってきたのです。 問題の本質は、管理スキルの不足にはなく、開発部門に根付いた“組織体質”にありました。 たとえば、明らかに遅延しているのに「全体的には順調です」と報告されるケースが散見されたり、進捗会議では数値を用いた報告がほとんどなく、問題を報告する文化自体が欠如していたり、さらには、開発メンバーの多くが「自分のタスクだけやっていればよい」という姿勢で、チームとしての一体感が感じられない雰囲気が蔓延していました。 エンドユーザーからは、「遅延の原因を具体的に示してほしい」「今後の改善策を提案してほしい」といった要求が繰り返し出されていましたが、開発側からは具体的な説明もなければ、対策の提示もありませんでした。結果として、ユーザーとの信頼関係は大きく損なわれ、プロジェクトの空気は次第に重苦しくなっていくのが、傍からも感じ取れました。 PMBOK、ISO/IEC25010およびISO/IEC9126に基づく改善提案 私は、品質コンサルタントとして、本プロジェクトの中盤からこの案件に参画させていただき、PMBOK、ISO/IEC25010およびISO/IEC9126などに基づく、A4用紙100枚程度の体系的な改善提案書を作成しました。 そして、その提案書の中で、 進捗管理の可視化 リスク管理の仕組みの提案 レビュー手順の見直し などの提案を展開しました。 しかし、その一方で、その作業を進めながら、この提案だけでは足りないと強く感じながら執筆を進めてもいました。 なぜなら、この現場の品質の根本的な問題は、プロジェクトマネージメントのテクニカルな手法不足に起因しているというよりも、「事実を正しく受け止めようとしない・伝えようとしない」という姿勢の欠如、つまり“ ファクト=事実 ”に寄り添うというごくごく常識的で基礎的な姿勢の欠如にあると痛感していたからです。 レトロスペクティブ文書にまとめる これを受け、私は、テクニカルな提案書とはまた別に、振り返り文書として「レトロスペクティブ文書」をまとめることにしました。 「レトロスペクティブ文書」では、まず、この数年にわたってエンドユーザーが声を上げても、不毛地帯に向かって叫んでいるように実行に結びつかなかった、あたかも“暖簾に腕押し”のように繰り返されてきた虚しいやりとりを、ひとつひとつ議事録から拾い上げ、その実態を示しました。そして、問題の根本原因は、開発担当部門の組織体質に関わる問題であり、プロジェクトの状況をありのままに報告し、解決に向けて真摯に取り組む姿勢がなかったことに起因すると結論付けました。 そして、さらにそれを受け、「進捗を正直に報告する」「問題を隠さずに共有する」「曖昧な表現を避ける」といった、組織として根付かせるべき“行動様式”を示し、「良い報告ではなく、正しい報告が信頼を生む」「実態を変えずに見せかけだけ整えても意味がない」といった箴言も書き添えることにしました。これらの提言は、テクニカルな手法以上に、文化的な改革の重要性を訴えるものでした。 2. 「イメージ力」が導く実践的な品質支援 品質エンジニアが、品質改善を検討する上で最も重視しなければいけないのは、プロジェクトに対して杓子定規に「標準規格を適用する」という点にはありません。もちろん、標準に従うことは大変重要ですが、それ以上に必要なのは、「 現場の実態を正しくイメージし、適切な手を打つこと 」です。それを、私は、“イメージ力”と呼びたいです。 “イメージ力”とは、形式に表れない情報を読み取る力です。たとえば、ある週の進捗会議で「ほぼ予定通りです」と報告されたとします。その言葉の裏に、何があるか。関係者の表情や声のトーン、前週の報告との矛盾、未提出の成果物の存在、些細な変化に注意を向けることで、プロジェクト実態の息遣いを汲み取ることができます。 また、開発メンバーとの雑談の中からも、重要なヒントを得ることがあります。あるメンバーが「最近は、毎晩遅くまで残業していて…」と漏らした一言から、タスクの見積もりに無理があることを察知し、工数再計算の提案をしたこともありました。これは、数値データだけでは決して見えてこない問題です。 また、ドキュメントレビューでも、単に「記載ミスがないか」をチェックするだけではなく、「このドキュメントで次工程の作業者が正しく動けるか」という視点を持ちます。文書が整っていても、読み手の視点を想像しなければ、品質は担保できません。実際、過去にレビューで「問題なし」とされた仕様書が、実装段階で多数の不整合を生んだケースもありました。 こうした経験から、私は、「品質とは、書かれていないものを想像する力」によって左右されるものと考えます。品質エンジニアにとっての武器は、標準規格の知識だけではなく、現場と対話し、空気を読み、背景を推察する“イメージ力”なのです。 以下、ここまで詳述してきた“イメージ力”について、簡潔に要約してみます。 現場とつながり、密に対話する姿勢を持つことの必要性 直接、現場に足を運ぶ、ないし定期的な対話やオンラインでのやり取りを通じて、現場の声や温度感をつかむことの重要性。情報の行間や空気を捉えるには、「話す量」と「聴く姿勢」が何より大切であるということ。 些細な変化や違和感を見逃さない観察眼を持つことの必要性 進捗報告やレビュー内容、メンバーの一言一言の裏にある「兆し」に気づくためには、日頃から注意深く観察し、「あれ?」と感じる感度を磨いておく必要があるということ。 ドキュメントや発言の“先”を読み、次工程や他者の立場を想像することの必要性 成果物は、次工程の作業者にどう伝わるか? 実際に手を動かす人の視点を想像することで、形式だけではない「本当に使える品質」を見極めることが可能になるということ。 標準の適用に捕らわれ過ぎず、柔軟に現場に合わせた対応を心掛けることの必要性 いうまでもなく標準は重要ですが、それをどう現場に馴染ませるかが、品質エンジニアの腕の見せ所。常に、現場の実態を起点に考える姿勢が、品質改善の鍵になるということ。 私が、本稿でお伝えしたい“イメージ力”は、上記のような形に要約できるかと思います。 3. 前職のQA統括部門に抱いた違和感 私の前職では「QA統括部」という部門があり、全社の品質保証活動を担っていました。部門としての体制は整っており、各プロジェクトに対して一律の品質ガイドラインを適用するスタイルでした。 しかし、私は、その部門の品質に対するアプローチに対して、長年、強い違和感を抱いていました。なぜなら、その施策の多くが“目的化”しており、本来支援すべき現場の実態と乖離していたからです。 たとえば、ある小規模な改善プロジェクトでは、ステークホルダーが限られており、関係性も非常に安定していたにもかかわらず、「PMBOKに記載されているから」という理由だけで、「ステークホルダー・エンゲージメント・アセスメント・マトリックス」の提出が求められたことがありました。担当PMは、「この作業、誰のためにやるんでしょうか…」とこぼしていたものです。(デヴィッド・グレーバー博士の“ブルシットジョブ —— クソどうでもいい仕事”が産み落とされた瞬間!) また、プロジェクトに重大な品質リスクが発生した際にも、「定期レビューに合格しているから問題はない」と判断され、現場の悲鳴は聞き流されたこともありました。形式的なレビュー手続きが、実態を覆い隠す盾となっていたのです。 私は、QA部門こそが、最も柔軟であるべきだと考えています。プロジェクトごとに状況を見極め、何が本当に必要なのかを見出す。それは、画一的な知識ではなく、経験と洞察と対話から生まれる対応力です。つまり、ここでも“イメージ力”が問われているのです。 QA部門が、ただ規格を押し付ける存在ではなく、「現場のパートナー」として機能するようになれば、品質文化は劇的に変わるはずです。そのためには、制度やチェックリストよりも、現場に寄り添う姿勢が求められます。 まとめ 言うまでもなく、われわれは、品質エンジニアのプロとして、お客様や、そこらのソフトウェア開発ベンダーが足元にも及ばないくらい、ソフトウェア品質に関しての専門的な知見を保有していなくてはいけません。しかし、品質とは、標準規格による単なる文書管理やレビュー手続きの整備ではありません。それに加え、現場に入り込み、プロジェクトの実像を“イメージ”し、必要な対応を的確に提案できることを併せ持つことが不可欠なのです。 品質を支えるのは、標準規格ではなく“人”です。だからこそ、QAエンジニアには、机上の知識だけでなく、現場を観察し、対話し、本質を見抜く力が求められます。私は、これからも“イメージ力”を更なる武器に、プロジェクトの実態に即した品質支援を続けていきたいと思います。 そしていつか、形式に縛られず、現場の声を真に受け止められるQA部門が、業界全体に広がっていくことを願っています。品質の本質は、形式ではなく、“想像と行動”の中にあると考えるからです。 ——しかし、いったんそんな風に結論付けてはみたものの、その理想郷を目指そうとする姿勢自体が、かつて紀元前の昔、世界最高の知性が独り言ちた、 “The more perfect a thing is, the harder it is to acquire.”(物事が完全であればあるほど、それを手に入れるのは困難である。)—— アリストテレス という、現代に至るまで、人間が性懲りもなく繰り返してきた“退屈な”取り組みそのものを、また繰り返し反芻してしまっていることにハタと思い至り、その結論の凡庸さに、我ながらいささかのうんざり感を覚えつつ、この場はいったん以上で筆を擱きたいと思います。 The post 品質はイメージ力で決まる —現場に寄り添うQAエンジニアの視点 first appeared on Sqripts .
こんにちは、セキュリティエンジニアの河村です。 今回はオライリー出版による「ポートスキャナ 自作ではじめるペネトレーションテスト」の書評をお届けします。本書はペネトレーションテストを初めとするセキュリティ業務では必須なツールと言えるポートスキャナについて、基本的な原理から説明してくれる内容です。 ■ ポートスキャナ自作ではじめるペネトレーションテスト―Linux環境で学ぶ攻撃者の思考 (株式会社ステラセキュリティ 小竹 泰一 著/O’REILLY JAPAN) ポートスキャナ自作ではじめるペネトレーションテスト 本書は、ポートスキャンを用いて攻撃者がネットワークを経由してどのように攻撃してくるのかを具体的な手法を交えて学び、攻撃手法を知ることでセキュリティレベルの向上を目指す書籍です。Scapyを用いてポートスキャナを自作し、ポートスキャンの仕組みや動作原理を...  詳細はこちら  www.oreilly.co.jp 本の概要 セキュリティエンジニアが通常、業務でツールを用いるときはsocketモジュールやnmapなどの高度なツールを用います。しかしながら、それらのツールは、多くの人にとって高度に自動化されてるが故に中身がブラックボックスな部分があります。また、特殊なパケットの再現を行いたい場合などでは再現が難しいことがあります。 本書ではサイバー攻撃が具体的に行われるプロセスを表したフレームワーク、Unified Kill Chainの解説から始まり、ScapyというPythonライブラリを通してパケットレベルでSynスキャンなどを体験できるプラットフォームを用意してくれています。第三章以降ではNmap、Nessus、Metasploitとペンテスターにとって基本となるツールの用い方を通して、ペンテスターにとって必要不可欠な攻撃の手順を体系的に学べます。 章ごとの概要 以下に、本書の各章で特に注目したい内容をピックアップしてご紹介します。 第一章 攻撃者はいかにしてシステムを攻撃するのか この章では攻撃者がシステムを侵害していく過程を具体的に学ぶことで、各種セキュリティ対策をより効率的に実施する方法を学びます。 攻撃者がシステムを侵害していく過程を学ぶことは、管理しているシステムの弱点を把握し、セキュリティ対策を効果的に実施する上で重要です。 本章では具体的な事例として2019年の7payが不正利用によりサービス停止となった事件 ※1 、2021年、徳島県の病院で発生したランサムウェアによる電子カルテが閲覧不能になった事件 ※2 、2009年から2010年の間にイランの核燃料施設を攻撃したStuxnet ※3 などが紹介されています。この中でもStuxnetの攻撃は特定の組織を狙って周到に準備した上で実行され、標的型攻撃と呼ばれます。 ※1 「7pay」決済サービス、開始早々の大量不正アクセス,5500万円の被害 ※2 徳島・鳴門の病院にサイバー攻撃 電子カルテにアクセスできず ※3 国家間サイバー戦争の幕開け イラン核施設を攻撃したマルウェア「Stuxnet」(2009~10年) 標的型攻撃の中でも特に高度で持続的に行われるものはAPT(Advanced Persistent Threat)攻撃と呼ばれたりもします。 現在進行形で行われているウクライナでの戦争では現実世界の軍事行動と一体化したハイブリッド攻撃が行われています。このことからわかるように、サイバー攻撃を制す者が現実の戦いをも制す時代になっています。 サイバー攻撃の進行をスケーリングした指標として有名なものがMITRE ATT&CK ※4 やUnified Kill Chain ※5 です。本書ではUnified Kill Chainを用いて説明します。このフレームワークを学ぶことでサイバー攻撃の過程をより分析して捉えることが可能になります。 ※4  https://attack.mitre.org/ ※5  https://www.unifiedkillchain.com/ サイバー攻撃における最初の段階である「初期の足場の確保」から解説します。 初期の足場の確保(Initial Foothold) 流れ:偵察⇒武器化⇒配送⇒ソーシャルエンジニアリング⇒攻撃⇒永続化⇒防衛回避⇒コマンド&コントロール 偵察 Reconnaissance 攻撃者は標的組織の情報を収集し、攻撃に活用出来る情報がないか調査します。この活動で用いる手法はOSINT(Open Source INTeligence)と呼ばれます。 この偵察フェーズは受動的偵察と能動的偵察の2種類に分類出来ます。受動的偵察は標的組織の組織にアクセスしないので、検知されるリスクが低いです。対して、DNS問い合わせ、Nmapなどのポートスキャン行為を行う能動的偵察は直接標的組織にアクセスするため、検知リスクがあります。Subdomain Takeover ※6 などの攻撃の実行可能性はこの段階でわかったりします。 ※6 Subdomain Takeoverについて   武器化 Weaponization 偵察によって得た情報をもとに攻撃に必要な環境を準備するフェーズです。標的組織の環境に合わせてマルウェアを作ることもこのフェーズに含まれます。対象組織がセキュリティ対策を適切に行ってる場合、攻撃に工夫が必要となります。 このような際に必要である検知回避技術にはLOTL攻撃(Living Off The Land攻撃)があります。標的の端末にすでにインストールされているソフトウェアを活用して攻撃を行うことで、検知を回避する手法です。GTFOBins ※7 などにはこのような攻撃を行うのに有用なコマンドが記載されています。 ※7 GTFOBins   配送 Delivery 武器化フェーズで作成したマルウェアを標的組織へ届けるフェーズです。攻撃者この手段として、メールやSNS、USBメモリなど様々な手段を用います。特に特徴的な手法として、 水飲み場型攻撃 サプライチェーン攻撃 があげられます。 ソーシャルエンジニアリング Social Engineering 配送したマルウェアを、メールやSNS等での人を通した会話によって、能動的に起動する手法をソーシャルエンジニアリングと呼びます。ときにはマルウェアの起動をスキップして、直接クレデンシャルを狙う場合もあります。「スミッシング」、「スピアフィッシング」などもソーシャルエンジニアリングにあたります。 攻撃 Exploitation 標的組織にマルウェアを能動的に実行させる方法は前述のソーシャルエンジニアリングの他に「攻撃」があります。例えば、標的にRCE(Remote Code Execution)の脆弱性があれば、それを用いてシステム内でマルウェアを実行させられます。 攻撃フェーズ以前からIPアドレスを偽造したり、SOCKS5プロキシ、Torネットワーク、VPNなどを用いて送信元を偽るケースも多いです。 永続化 Persistence 攻撃者は、システムへの持続的なアクセスの獲得を目的としている場合があり、この場合永続化フェーズが必要になります。永続化の手法として代表的なものに以下の三つがあげられます。 アカウントの操作⇒サーバへの公開鍵の追加など ブートまたはログオンの自動開始実行⇒Linuxでのrcコマンド、Windowsでのスタートアップなど スケジュールされたタスク/ジョブ⇒cronなど 防衛回避 Defense Evasion 攻撃者がセキュリティ製品に検知されないようにとる対策のことです。様々な手法がありますが、本書では5章でMetasploitを用いた防衛回避方法を解説します。 コマンド&コントロール Command and Control 「初期の足場の確保」の最後のフェーズとして、マルウェアは攻撃者の用意したC2サーバ ※8 との通信を確立します。 これらのプロセスではドメインフロンティングやDNSトンネリングなどの隠蔽技術が用いられることがあります。 ※8 C2サーバとは   標的ネットワーク内での被害拡大 標的となるネットワークにアクセスした後、目的の資産を獲得する際の活動をUnified Kill Chainでは「ネットワークを介した拡大」(Network Propagation)と名付けています。 ネットワークを介した拡大フェーズは以下のようなプロセスで構成されています。 流れ:ピボッティング⇒探索⇒権限昇格⇒実行⇒クレデンシャルアクセス⇒横展開 ピボッティング Pivoting 攻撃者は必要に応じて侵害した端末を通じて、直接アクセス出来なかった他のネットワークへ通信をトンネリングし、これをピボッティングといいます。横展開と異なり端末間の移動のみをUnified Kill Chainではピボッティングとしてます。 探索 Discovery 攻撃者が現在ログインしているシステムとそのシステムが接続している内部ネットワークに関する情報を得るために行う活動を探索と言います。検知されないようにPowerShell等、OSにデフォルトで備わってるツールが多用されます。 権限昇格 Privilege Escalation 取得出来た権限が制限されたものだった場合、脆弱性を利用してより高いレベルの権限への昇格を試みます。この活動を権限昇格と呼びます。 実行 Execution コードを実行するのに必要な権限を得た攻撃者は攻撃を実行します。 クレデンシャルアクセス 攻撃者は目的に応じて、クレデンシャルを盗み出そうとします。この活動をクレデンシャルアクセスと呼びます。 ⇒ わざわざ侵入行為を働かなくても、GitHubなどで公開されてるリポジトリから機微な情報を取得出来る場合もあります。 横展開 Lateral Movement 侵入した端末から、同一ネットワーク内の他の端末の権限の取得を試みます。 目的の実行 (Action on Objectives) ここまでのプロセスで攻撃者は標的のネットワークへの足場を広げ、多大な被害を拡大できました。このあと、入手できたデータを収集し、持ち出していきます。 流れ:収穫⇒持ち出し⇒影響⇒目的 収穫 Collection 攻撃者は目的に応じて標的からデータを収集します。システム内のデータ以外にSamba、クラウドストレージから収集したり、キーロガー、Webカメラなどを用いる場合もあります。 持ち出し Exfiltration 目的達成のために収集されたデータを持ち出します。検知回避のためにデータを圧縮・暗号化することも多いです。IDS・IPS回避のための工夫も行われます。この際以下の技術が用いられます。 Smash&Grab Low&Slow 影響 Impact 攻撃者が標的のビジネスプロセスや運用プロセスを操作することで、その可用性や完全性を損なわせる活動です。 目的 Objectives 攻撃者の社会的・技術的な最終目標のことです。以下に例をあげます。 知的財産(ソースコードなど)の奪取 奪取したアカウントの販売 ランサムウェアによる身代金の獲得 第二章 Scapyでポートスキャナを自作して動作原理を知ろう ポートスキャナは前章のUnified Kill Chainの中では「初期の足場の確保」の「偵察」にあたる行為です。この章ではポートスキャナを「Scapy ※9 」というライブラリを用いて自作することを通して、パケットの操作方法を学んでいき、実在する脆弱性に対する攻撃も体験します。 ※9 https://scapy.net/ 実際の業務では基本的にポートスキャナはNmapで十分なのですが、ポートスキャナの仕組みを理解するには自作することは非常に有用です。このようなことを学ぶとセキュリティエンジニアにとって必要なPoCのコードの実装を素早くできたりします。 環境構築の細かいことについては本書を読んで欲しいです。また、ここに掲載してるソースコードは本文が冗長にならないよう概要のみなので、そのままでは動作しないものがあることはご了承ください。更に、外部に対してこれらのコードを実行することは法に抵触する可能性があるため、必ず自分の管理下のネットワークで試してください。 ここでは大まかな流れと概要を伝えます。本書の実習環境は、Docker ※10 を用いており、Scapyが使えるコンテナと各種脆弱性を持ってるコンテナが用意されております。 ※10 コンテナの基本   本書はDockerの知識がない方でも環境を十分に扱えるよう基本レベルからDockerの解説が載っているので安心です。また、Dockerの性質上、Windows、Mac、Linuxのどれでも検証環境は動作します。 Scapyに入門する Scapy は、Pythonでネットワークパケットを操作するための強力なライブラリです。パケットの生成、送信、解析、操作などを簡単に実現でき、ネットワークテストやセキュリティ分析に広く利用されています。使用仕方として、Pythonから呼び出す方法と、インタプリタから使用する方法があります。 Pythonコードから使用する方法 from scapy.all import srl, IP, ICMP のような形で必要な関数、クラスをインポートしてします。 インタプリタから使用する方法 scapyを使用できる環境のコマンドラインから以下のコマンドを押下します(Linux、Macの場合)。 $ sudo scapy インタプリタを終了する場合、exitと入力します。 パケットの送受信 ICMPを題材としたパケットの送受信が紹介されています。インタプリタ版の場合、以下のようにしてICMPパケットを作成します。 >>> req = IP(dst="10.8.9.3")/ICMP() >>> req.show() scapyの基本的な使い方は本書を実際に読むか、もしくは下記などを参考にしてください。 ※11 Scapy入門  https://qiita.com/Howtoplay/items/4080752d0d8c7a9ef2aa パケットキャプチャを行う Scapyのsniff関数を用いるとパケットキャプチャが容易に実装できます。以下のようなコードを用います(詳細は本書P.50)。 from scapy.all import sniff def print_packet(packet):   packet.show() sniff(filter='icmp', prn=print_packet, count=5) このPythonスクリプトを実行するとICMPパケットを待ち受けます。 TCP SYNスキャンをScapyで行う SYNスキャンは、TCP 3ウェイハンドシェイクの特性を利用します。以下はその流れです。 3ウェイハンドシェイクの流れ SYNパケット送信 スキャナーがターゲットにTCP SYNパケットを送信します。 応答の受信 SYN/ACK : ポートが「オープン」の場合。 RST : ポートが「クローズ」の場合。 応答なし: ポートが「フィルタリング」(ファイアウォールでブロック)されている場合。 接続の中断 スキャナーは応答を受け取ると、接続を完了せずにRSTパケットを送信して接続を終了します。 SYNスキャンは接続を完全に確立しないため、高速で実行でき、ログに残りにくく比較的検出されづらいことが特徴です。 Scapyにおいては syn_packet = IP(dst=dst_p)/TCP(dport=target_port, flags='S') # SYNパケットの作成 response_packet = srl(syn_packet) # パケットを送信する のように記述することで、SYNパケットオブジェクトを作成出来ます。 これでSYNパケットを送信した後にSYN/ACKパケットが返ってくるかを判別するコードを追加すると、ポートが開いてるか判断出来ます。 if(response_packet.haslayer(TCP) and   response_packet[TCP].flags == "SA"):   print(f"TCP port {target_port} is open") else:   print(f"TCP port {target_port} is closed") TCP ConnectスキャンをScapyで行う TCP Connectスキャンでは3ウェイハンドシェイクを最後まで行うので、SYNスキャンのときのコードにTCPの接続を正常に終了するためのFINパケットの送受信のコードも書き加えます。 3ウェイハンドシェイクを完了するにはシーケンス番号や確認応答番号の設定が必要です。Pythonを用いたら容易に実装できます。 パケットの確認 tcpdumpを使います。 $ sudo tcpdump port <port> and host <ip> socketモジュールを使って実装する より高性能なsocketモジュールならばTCP Connectスキャンの3ウェイハンドシェイクをより簡単に実装できます。 s = socket.socket() errno = s.connect_ex((target_ip, target_port)) # これでTCP Connectを試みます s.close() 特殊なパケットやパケット単位の実装はScapyが便利ですが、それ以外の場合はsocketモジュールが便利だったります。 パケットを工作しないと攻撃出来ない脆弱性 以下の脆弱性の学習にはパケット単位でカスタマイズ可能なsocketモジュールのカスタマイズ性の高さがいきてきます。 ARPスプーフィング ARPスプーフィング(ARP Spoofing)は、コンピュータネットワークにおける攻撃手法の一つで、偽のARP(Address Resolution Protocol)メッセージを送信して、通信を傍受したり改ざんしたりする攻撃です。 この攻撃を行う上で、ARP要求を送信し、偽のARP応答を送りつけてキャッシュを改ざんします。偽のARPパケットはScapyでは以下のようにして送信できます。 arp_response = ARP(pdst=target_ip, hwdst=target_mac, psrc=dest_ip, op='is-at') send(arp_response) scapyモジュールのARPクラスでは以上のように、容易に改ざんされたARPパケットを作れます。 DoSを引き起こすCVE-2020-8617 CVE-2020-8617 は、BIND(Berkeley Internet Name Domain)に関連する重大な脆弱性です。BINDは最も広く使用されているDNSサーバーソフトウェアの一つで、この脆弱性を悪用されると、リモートの攻撃者がサービス拒否(DoS)攻撃を引き起こす可能性があります。 この脆弱性では細工されたTSIGリソースレコードを含むリクエストを用います。発見者はPython上でバイト列を組み立て、Socketモジュールで送信していますが、Scapyを用いるともっとシンプルに記述出来ます。 DNSRRTSIG(rrname="local-ddns", algo_name="hmac-sha256", rclass=255, mac_len=0, ac_data="", time_signed=0, fudge=300, error=16) 以上のコードの断片がペイロードの一部です。 第三章 デファクトスタンダードのポートスキャナNmap Nmap ※11 の基本的な使い方は以下のような様々なソースで確認出来るので省略します。 ※11  https://qiita.com/kenryo/items/1b49bddce44e9412638f Nmapの機能を拡張するNSE NmapにはスクリプトエンジンであるNSE(Nmap Scriting Engine) ※12 上で動くLua製スクリプトが付属してます。これらを使うことで、コマンド一つでブルートフォース攻撃などを行えます。 ※12 NSEの使い方の参考   NSEの使用例:ミドルウェアへのログイン試行を行うスクリプト $ nmap -p 22 --script ssh-brute 127.0.0.1 有名な脆弱性であるHeartbleedやPOODLE、EternalBlueなどをNSEで調査することも出来ます。 $ nmap -p 443 --script ssl-heartbleed example.com 第四章 既知脆弱性を発見できるネットワークスキャナ Nessus Nessus ※13 の基本的な使い方は以下のような様々なソースから確認出来るので省略します。 ※13  https://qiita.com/mefuku/items/d22a2747bcdb6ff19d75 ネットワークスキャナには他のものもたくさんあります。例として、CloudflareによるFlan Scan、GoogleによるTsunamiなどがあります。 Nmapとの使い分け NessusのBasic Network ScanやAdvanced Scanでは脆弱性をスキャンする前段階でポートスキャンを行います。ただし、出力結果がNmapとは異なったていたりするので、使い分けとして、網羅性を重視するセキュリティベンダの場合、NessusとNmapを併用して両方の差分を確認する場合したりします。 第五章 攻撃コードを簡単に生成できるMetasploit Framework MetasploitはRapid7社が開発してるペネトレーションテストツールです。無料版はCUIでしか基本的に使えませんが、有料版のMetasploit ProはGUIで操作できます。 Metasploitの基本的な使い方は以下のような様々なソースから確認出来るので省略します。 ※14  https://zenn.dev/sanflat/articles/6c9b007c787035 第六章 攻撃者はどのように被害を拡大するか Unified Kill ChainにおけるPost-Exploitationで行う行動をここでは解説しています。 ファイル読み込みを成功させたあと 標的端末のファイル読み込みが出来ただけでは、RCEが出来た場合と比べて出来ることが限られています。そこでまず、端末内の多数の重要なファイルを「収集」します。「収集」ファイルを元に、次のステップであるファイル書き込みに向けての権限昇格を目指します。 ファイル書き込みを成功させたあと RCEへの発展や、マルウェアの書き込みを目指します。Unified Kill Chainでは「初期の足場の確保」の「永続化」にあたります。 以下が具体的に行うことの例です: ・Webシェルの配置 ・SSH公開鍵の配置 ・cronを用いた永続化と権限昇格 RCEを成功させたあと RCEを成功させたということは、任意のコマンドが実行可能です。このフェーズで行いたいことを列挙します。 コンテナエスケープ ⇒既知脆弱性の利用、Dockerソケットがマウントされてる場合、特権コンテナ マルウェアの実行 ⇒Vimプラグインによるキーロガー ⇒LD_PRELOADによる関数フック C2フレームワークによる侵害した端末の管理 C2フレームワークは侵害した端末を遠隔操作するためのツールです。目的達成には侵略した端末をまとめて操ることが必要だったりするので、攻撃において有用な場合が多いです。 OSSのC2フレームワーク:  ⇒Covenant、C3、Empire、PoshC2、Sliverなど 商用のC2フレームワーク:  ⇒Brute Ratel C4、Cobalt Strikeなど DBにアクセス出来たら DBには重要な情報が格納されてることが多いため、DBにアクセスできる事は目的達成において重要です。 DB内の情報の閲覧 ファイル読み込み ファイル書き込み RCEを行う ⇒ PostgreSQLのCOPYコマンドなど どのようにして他の端末へ被害を拡大させるか ここまでのフェーズで目的を達成できなかった場合、組織が管理しているネットワーク上の他の端末への攻撃を試みます。その方法の例をあげます。 メモリからのクレデンシャルの抽出 既存のセッションの活用 ⇒ ControlMasterによって既存のSSH接続を活用するなど ⇒ 二回目以降のSSH接続ではPWの入力が不要な場合がある 認証情報が弱いサーバや既知脆弱性が存在する端末への攻撃 ⇒後者はスキャナで発見できることがある 本書を読んで 第一章で学ぶUnified Kill Chainはペネトレーションテストのフレームワークとしてはかなり詳細な部類です。これの各フェーズを日本語で丁寧に解説してる文書はインターネット上には少なく、なので本書の解説は貴重で有用だと思いました。ペンテスター向けのフレームワークですが、セキュリティエンジニアは皆サイバー攻撃と何らかの形で関わり、このフレームワークを知ることでサイバー攻撃についての理解が非常に深まると思います。 第二章でのScapyを用いた自作のポートスキャナの章は本書の目玉といえると思います。本書を読む人で3ウェイハンドシェイクを知らないって方はあまりいないと思いますが、実際にパケット単位で操作できる実行環境を作った人は少ないと思います。Socketモジュール等の一般的なモジュールでは、Synスキャンのような基本的なハッキング技術でさえ再現が意外とめんどくさく、比較的低レイヤーの操作が可能なツールScapyの有用性を感じました。私自身も今後より高度なレベルのScapyの使用法を学び、仕事でのPoC作りなどに活かしたいと思いました。 第三章から第五章の内容は非常にメジャーなツールの入門的な使い方なので今回はほとんど省略しましたが、ペンテスト系の学習をしたことがないセキュリティエンジニアにとっては網羅的に学ぶ上でいい教材だと思いました。これらを学習すればハッキングの登竜門であるHack The Boxなどにも挑みやすくなると思います。 第六章は、第二章から第五章までのツールを用いて標的端末へアクセス出来たあとの手順が第一章に登場したUnified Kill Chainフレームワークに基づいて記載されており、非常にためになります。Hack The Box等では端末のルートを取れたら終わりだったりしますが、現実のハッキングでは違います。機密情報の取得だったり、DoSの達成と言った目標達成にはルートの取得後の端末間の垂直・平行移動や情報収集が必要だったりします。 本書は取り扱ってる内容はペンテスト全域に渡っており、ボリュームはかなりありますが、要求レベル的にはLinux(できればPythonも)の基本がわかってれば十分に読める内容だとも思いました。ポートスキャナの原理に限らず、ペンテスターが用いるツールについて学びたい人は是非一読をお勧めいたします。 The post 『ポートスキャナ自作ではじめるペネトレーションテスト』書評 first appeared on Sqripts .
帰納的な推論 と 発見的な推論(アブダクション) は、 私たちがソフトウェア開発の現場/実務で(知らず知らずにでも)駆使している思考の形です(それどころか日々の暮らしでも使っています)。 それほど“自然な”思考の形ですが、どんな考え方で、どんなところに注意すると質の高い思考ができるのか、基本知識を押さえておくと実務のレベルアップにつながります。 <実務三年目からの発見力と仮説力 記事一覧> ※クリックで開きます 【第1回】見つけるための論理【連載初回、全文公開中】 【第2回】 “共通項”を見つけ出す 【第3回】発見はよい観察とよい方法から 【第4回】帰納の仲間と落とし穴 -前編- 【第5回】帰納の仲間と落とし穴 -後編- 【第6回】 なぜ・どのようにを説明したい 【第7回】 仮説の糸を手繰り寄せる 今回は仮説を考える時の進め方の解説です。 仮説は拙速を貴ぶ――とは限らない コニャンくんがソフトウェアXで起こる故障F( 第3回 など参照)の原因について考えを巡らせています(図7-1)。 図7-1 よい仮説を求めて アブダクションは杖ひと振りでよい仮説を手にする魔法ではありませんし、そもそもよい仮説がすぐに見つかることは稀です。 アブダクションの進め方・パースの「ふたつの段階」 ホップ、ステップ、よい仮説 パース( 第6回参照 )は、仮説はふたつの段階を経て形成されるとしています。 (参考: 『アブダクション 仮説と発見の論理』 。以降『アブダクション』) 第1段階:心に思い浮かぶ仮説を列挙する 第2段階:最も正しいと思われる仮説を選ぶ 図7-2 アブダクションのふたつの段階 第1段階 では、対象について考えを巡らせ、判っていることや調べたことをもとに、説明仮説を考えていきます。 この段階で素晴らしい仮説を思いつくかも知れません。 しかしそこで決めてしまうのでなく、事象を説明できる仮説は他にも考えられないか、検討します。 (思いつきがイマイチならなおさらです) 時にはいわゆる閃きや天啓といったものの助けもありますが、それが降りてくるよう、対象を詳しく調べたり理解を深めたりしながら考えることが大切です。 『アブダクション』では 洞察的な段階 とも言っています。 第2段階 では、第1段階で挙がった仮説を、後述の4つの基準で総合的に評価し、最も理にかなっていると思われるものを選定します。 『アブダクション』では 熟考的な段階 とも言っています。 「最も正しいと思われる仮説」の選定基準/条件 「最も正しいと思われる仮説」の選定の基準ないし条件として、パースは次の4つを挙げています。 (参考: 『アブダクション』 ) (1) もっともらしさ(plausibility) 問題となっている事象や因果関係について、理にかなった説明を与えるものであること。 (2) 検証可能性(verifiability) 仮説は事実に照らして検証可能(真偽を判断できる)であること。 反証可能であること(偽であると判定できること)も含みます。 (3) 単純性(simplicity) (1), (2)が同程度の仮説が複数ある場合は、より単純な仮説であること。 (4) 経済性(economy) 仮説の検証にかかる思考の努力や、時間やコストが少なくて済むこと。 総合的に見て「最も理にかなっている」と思えるものを選定します。 これらの基準は、第6回で挙げた 「よい仮説」が持つ性質 に対応します。 (「検証」の意味も第6回に準じます) 図7-3 「よい仮説」の判定基準と、「よい仮説」が持つべき性質 なお、パースのいう 単純性 は、論理的な単純さ(原因から結果まで一本道/短い、過程が入り組んでいない、etc.)よりは「説明が自然で考えやすい」「受け容れやすい」といった“自然さ”を意味しています。 また、 経済性 は第6回で挙げた仮説の性質の4番目とは若干異なりますが、「少数の仮定から整合的に説明できる」ならパースのいう経済性の条件にかなうと言えるでしょう。 念のため 「最も理にかなった仮説」が選ばれたとしても、 それはまだ仮説 です。 仮説が事実に対して正しい(不整合がなく、過程や結果をよく説明している)かどうかは、その後の検証(ソフトウェアの場合、最終的には動的テストなど)に委ねられます。 「ふたつの段階」の取り組み方 二重ループでイテレーティブに 筆者の経験を交えると、次のように考えると取組みやすいでしょう。 第1段階で「仮説を列挙する」際には: 考えやすいところから手をつける。 「説明仮説にはならない」ものを早めに排除して考える範囲を絞るのも大事。 思いついた段階でざっと検証してみる。 現象や結果を説明できるか、ざっと確かめる( 粗い検証 )。 よさそうなら残す。 そうでなければ脇に置いておく。 (忘れ去る必要はなくて、後で修正を施されて“敗者復活”してもよい) これを繰り返す(いわば「 内側のループ 、 小ループ 」)。 最初の仮説で終わらず、「粗い検証」で得たフィードバックも加味して次の仮説を考える。 ある程度考えられた(もう思いつかない)と判断できたら終了する。 第2段階で「最も正しいと思われる仮説を選ぶ」際には: 「1回目の第2段階」で「最も正しいと思われる仮説」が決まらなくてもよい。 (詳しく考えてみると、細部に説明できないことがある場合や、必ずそうなるとは言えない場合もある) そういう場合はもう一度「第1段階」からやる(いわば「 外側のループ 、 大ループ 」)。 図7-4 アブダクションのふたつの段階・変形版 第1段階で心がけたいこと ①原因候補と説明仮説をさまざまな視点・見方から考えてみる。 原因候補が結果(故障や不具合)を引き起こす筋道を、多角的に考えましょう。 図7-1のように、途中で道が塞がっていても、別の道が見つかるかも知れません。 人的要因やプロセス要因の可能性を含めて考えるのがよい場合もあります(作業や確認の漏れ、単純ミス、勘違い、etc.)。 原因候補から結果までの筋道(可能性としての)が一本か、複数あり得るか考えられると、仮説の確からしさを強化できるでしょう。 原因候補を絞り込みたい場合には、差異法や剰余法の考え方が参考になります( 第3回参照 )。 ②大きな“瑕”がある仮説は躊躇なくいったん脇によけておく。 魅力ある原因候補でも、結果に至る筋道を説明しきれない、仮説の通りにならない場合がある、 といった目につく“瑕”があるなら、いったん脇に追いやって別の仮説を考えてみるのがよいです。 いわば「幅優先の探索」です。 原因の候補がいくつも考えられる状況なら、候補から外してよいものと、残しておくものを仕分けるためにも「幅優先」で考えた方がよいでしょう。 幅優先に対して「深さ優先の探索」をしたくなる場合もあります。 “瑕”がなければ最有力になるような原因候補なら、“瑕”をなくせないか時間をかけて考えてみるのもありでしょう。 「粗い検証」 は、①②を柔軟に行なうことを促します。 第1段階の「粗い検証」 机上(ひとり脳内ウォークスルーで可)でよいので、「仮説Hが正しいならば、Cという結果になる」かどうか、先の4つの選定基準/条件をざっと評価します。 大雑把なウォークスルーでも もっともらしさ や 検証可能性 を損ねるような大きな“瑕”が見つかるなら、綿密に検証してみるまでもありません。 また、第1段階で仮説による説明の 単純さ 、 判りやすさ がある程度把握できていれば、第2段階が捗ります。 アイデアを見失わないように ただでさえアイデアは思いついたそばから消えていってしまうものですから、「原因から結果に至る見えない道筋を、結果から遡って考える」作業を頭の中だけで完結させるのは困難です。 思い浮かんだ考えや仮説案は忘れずに書き留めましょう。 考える過程を書き留めること自体が重要ですし、形に表すことで考えがはっきりすることもあります。 (“見込みあり”と光明が差すこともあれば、足りていないところ・弱いところが判明することも) ということで、次回は「アブダクションを支援するのに使える“ツール”」をいくつか紹介する予定です(特定のプロダクトではありません)。 参考文献 米盛裕二 『アブダクション 仮説と発見の論理』 勁草書房 2007 パース(著), 伊藤邦武(訳) 『連続性の哲学』 岩波書店 2001 近藤洋逸, 好並英司 『論理学入門』 岩波書店 1979 図版に使用した画像の出典 Loose Drawing 人物画、電球の絵をお借りしています。 品質探偵コニャン:Produced by Sqripts . No Unauthorized Reproduction. 【連載】ソフトウェアエンジニアのための論理スキル[実務三年目からの発見力と仮説力] 記事一覧 【第1回】見つけるための論理 【連載初回、全文公開中】 【第2回】 “共通項”を見つけ出す 【第3回】発見はよい観察とよい方法から 【第4回】帰納の仲間と落とし穴 -前編- 【第5回】帰納の仲間と落とし穴 -後編- 【第6回】 なぜ・どのようにを説明したい 【第7回】 仮説の糸を手繰り寄せる The post 【第7回】 仮説の糸を手繰り寄せる|実務三年目からの発見力と仮説力 first appeared on Sqripts .
こんにちは!フロントエンドエンジニアのつかじです。 皆さんは日々の開発の中でテスト自動化に取り組んでいますか?手動での繰り返しテストは時間がかかり、ヒューマンエラーも発生しがちです。そこで今回は、JavaScriptベースのE2Eテストフレームワーク「CodeceptJS」をご紹介します。シンプルな記述でありながら、強力な自動テストを実現できるツールです。 CodeceptJSとは? CodeceptJS は、エンドツーエンド(E2E)テストをシンプルに記述できるテストフレームワークです。 主な特徴は以下の通りです。 直感的なDSL記述 自然言語に近いDSL(ドメイン固有言語)を採用しており、テストコードが読みやすく、出力結果も直感的に理解しやすいです このシンプルな記述方法は、BDD(振る舞い駆動開発)の文脈で、テストの意図を明確に伝え、保守性の向上にも寄与します 複数のヘルパーへの対応 Puppeteer、Playwright、WebDriver、TestCafe など、さまざまなブラウザ操作ライブラリをヘルパーとしてサポート ヘルパーを切り替えるだけで、同一のテストコードを異なるバックエンドで実行可能なため、プロジェクトの要件に合わせた柔軟な運用が実現できます 複数ブラウザでのテスト実行 Chromium、Firefox、WebKit など、複数のブラウザ上でテストを実行でき、クロスブラウザテストが容易に行えます エコシステムの充実 豊富なプラグイン群(スクリーンショット自動取得、レポート生成、リトライ機能、データ駆動テストなど)により、様々なニーズに対応可能 カスタムヘルパーやプラグインを自作することも容易で、コミュニティによるサポートも充実しています APIテストへの対応 HTTPリクエストの送信やレスポンスの検証を行うためのAPIヘルパーが用意されており、Webアプリケーションだけでなく、APIテストもシンプルに記述できます モバイルテスト(Appium利用)への対応 Appiumを利用することで、CodeceptJSからモバイルアプリケーションのテストも可能です 同一のDSLで、WebだけでなくモバイルのUIテストも統一的に記述できるため、テスト環境の統合が容易です 他ツールとの比較 Cypress 高速で自動ウェイト機能が強力ですが、対応ブラウザが限定的です。一方、CodeceptJSは複数のドライバーに対応しており、柔軟なテスト環境を提供します。 Selenium ほぼ全てのブラウザに対応する実績がありますが、APIが冗長でテストコードが複雑になりがちです。CodeceptJSは抽象化レイヤーを提供することで、シンプルな記述を可能にします。 Robot Framework 非エンジニアでも扱いやすいキーワード駆動型ですが、JavaScript環境との統合が難しいという点があります。 Playwright/Puppeteer 低レベルのAPIで柔軟な自動化が可能ですが、テスト全体を構築する際に記述量が増えがちです。CodeceptJSはこれらをヘルパーとして統合し、BDDスタイルの簡潔な記述を実現します。 WebdriverIO 柔軟性が高く、多くのプラグインや拡張機能が利用可能ですが、設定が複雑になりがちです。また、BDDスタイルの記述を行うには追加のプラグイン導入が必要な場合があります。 TestCafe インストールや設定が非常にシンプルで、Seleniumを必要としません。自動待機機能が組み込まれており、非同期処理が扱いやすいですが、細かいカスタマイズや多様なブラウザサポートには制限がある場合があります。 Gauge + Taiko Gaugeはシナリオ記述に重点を置いたフレームワークで、Taikoはシンプルな構文でブラウザ操作を実現します。非常にシンプルな記述が可能ですが、CodeceptJSのような豊富なプラグインや柔軟なヘルパーの選択肢は少ないです。 Nightwatch.js Selenium/WebDriverを利用した標準的なE2Eテストフレームワークとして実績がありますが、設定が煩雑になりがちで、BDDスタイルの記述を実現するには追加の工夫が必要です。一方、CodeceptJSは複数のヘルパーをサポートし、シンプルなAPIで記述できる点で差別化できます。 各ツールともに独自の強みがあるが、CodeceptJSはDSLの記述のシンプルさ、多様なヘルパー対応、豊富なプラグインエコシステム、さらにはAPIテストやモバイルテストまでカバーできる点で、非常にバランスの取れたテスト自動化フレームワークと言えます。 CodeceptJSのインストールとセットアップ 必要な環境 Node.js(バージョン12以上) ※ 執筆時(2025/04/03)時点での CodeceptJS 最新バージョン:3.7.3 インストール CodeceptJSは、インストーラーを使用する方法が最も簡単で推奨されています。以下の手順で簡単にセットアップできます: # 新しいディレクトリを作成してインストール mkdir codeceptjs-demo cd codeceptjs-demo npx create-codeceptjs . 特定のディレクトリにインストールする場合は、以下のようにディレクトリ名を指定できます: npx create-codeceptjs e2e-tests デフォルトではPlaywrightがインストールされますが、他のテストエンジンを使用したい場合は、以下のようにオプションを指定できます: # Puppeteerを使用する場合 npx create-codeceptjs . --puppeteer # WebDriverIOを使用する場合 npx create-codeceptjs . --webdriverio その他のインストール方法や詳細な設定については、 公式マニュアル をご参照ください。 セットアップ インストール完了後、以下のコマンドでCodeceptJSのセットアップを行います: npx codeceptjs init 対話形式で以下の設定を行います(本記事のセットアップ内容。テスト対象の機能名以外はデフォルト値です。): # TypeScriptを使用するか? ? Do you plan to write tests in TypeScript? -> No # テストファイルの配置場所 ? Where are your tests located? -> ./*_test.js # 使用するヘルパー(テストエンジン)の選択 ? What helpers do you want to use? -> Playwright # テスト実行時の出力ディレクトリ(スクリーンショットやレポートの保存先) ? Where should logs, screenshots, and reports to be stored? -> ./output # テストの言語設定 ? Do you want to enable localization for tests? <http://bit.ly/3GNUBbh> -> English (no localization) # Playwrightの設定:使用するブラウザの選択 ? [Playwright] Browser in which testing will be performed. Possible options: chromium, firefox, webkit or electron -> chromium # テスト対象のベースURL ? [Playwright] Base url of site to be tested -> <http://localhost> # ブラウザウィンドウを表示するかどうか ? [Playwright] Show browser window -> Yes # テスト対象の機能名(今回は予約機能をテスト) ? Feature which is being tested (ex: account, login, etc) -> reservation # 作成するテストファイルの名前 ? Filename of a test -> reservation_test.js 基本的なテストの作成|CodeceptJS ここでは、日本Seleniumユーザーコミュニティが提供しているデモサイト「予約情報入力」にアクセスして簡単な操作をテストします。 今回は以下のケースを記述します。 トップページを開く 入力フォームに日付、宿泊人数、名前などを入力 「利用規約に同意して次へ」をクリック後、予約内容を確認 「確定」をクリック後、予約完了を確認 ※ デモサイトは現時点で利用可能ですが、将来的にURLが変更される可能性があります。 テストファイル作成 reservation_test.js へ以下のようなテストコードを作成します。 Feature('reservation'); Scenario('宿泊予約ができることを確認する', ({ I }) => { // 1. トップページへ遷移 I.amOnPage('<http://example.selenium.jp/reserveApp_Renewal/>'); // 2. 入力フォームに日付, 宿泊人数, 名前などを入力 // 日付を選択(例: 2025/05/01) ※ 翌日以降3ヶ月以内の日付を指定 I.fillField('#datePick', '2025/05/01'); // 宿泊日を入力(例: 3日) I.selectOption('#reserve_term', '3'); // 人数を入力(例: 2人) I.selectOption('#headcount', '2'); // 名前を入力(例: 山田太郎) I.fillField('#guestname', '山田太郎'); // 3. 「利用規約に同意して次へ」をクリック I.click('利用規約に同意して次へ'); I.see('予約内容'); I.see('2025年5月1日'); I.see('3泊'); I.see('2名'); I.see('山田太郎'); // 4. 「確定」をクリック I.click('確定'); I.see('予約を完了しました'); I.see('ご来館、心よりお待ちしております。'); }); ポイント: CodeceptJSでは、Scenarioの第2引数に{ I }を受け取ることでブラウザ操作APIを利用できます .amOnPage() でページを開き、.fillField() や .checkOption() などでフォーム操作を行います I.see() によってページ上に特定の文字列が存在するかをテストできます I.see() のシンプルな記述方法は、ユーザー視点でページに表示されるテキストの存在をシンプルに確認できるため、テストコードの保守性と可読性を向上させ、BDDの振る舞い記述と非常に相性が良いです。テストの目的に応じて、単にテキストの存在を確認するだけの場合は I.see() を使用し、特定のエリアや要素内でのテキストの存在確認など、より厳密な検証が必要な場合にはセレクタなどを追加するのが望ましいです。 例: // ページ上のどこかに「ログイン成功」が存在すればOK I.see('ログイン成功'); // ヘッダー部分に「ログイン成功」が表示されているかを検証する場合 I.see('ログイン成功', '.header'); テストの実行|CodeceptJS ターミナル上で次のコマンドを実行します。 npx codeceptjs run --steps -stepsオプション: テストの各ステップ(I.fillFieldなど)をコンソールに詳細表示します。 実行結果: CodeceptJS v3.7.3 #StandWithUkraine Using test root "path-to-your-project" reservation -- 宿泊予約ができることを確認する Scenario() I am on page "<http://example.selenium.jp/reserveApp_Renewal/>" I fill field "#datePick", "2025/05/01" I select option "#reserve_term", "3" I select option "#headcount", "2" I fill field "#guestname", "山田太郎" I click "利用規約に同意して次へ" I see "予約内容" I see "2025年5月1日" I see "3泊" I see "2名" I see "山田太郎" I click "確定" I see "予約を完了しました" I see "ご来館、心よりお待ちしております。" ✔ OK in 2197ms OK | 1 passed // 3s 上記のように「OK」と表示されればテスト成功です。もし失敗すると、該当ステップでエラーが表示され、スクリーンショットも自動保存されます(デフォルトでoutputフォルダ内)。 また、言語設定で日本語に設定している場合は、下記のような実行結果になります。(日本語でのテスト記述も可能) CodeceptJS v3.7.3 #StandWithUkraine Using test root "path-to-your-project" reservation -- 宿泊予約ができることを確認する Scenario() 私は ページを移動する "<http://example.selenium.jp/reserveApp_Renewal/>" 私は フィールドに入力する "#datePick", "2025/05/01" 私は オプションを選ぶ "#reserve_term", "3" 私は オプションを選ぶ "#headcount", "2" 私は フィールドに入力する "#guestname", "山田太郎" 私は クリックする "利用規約に同意して次へ" 私は テキストがあることを確認する "予約内容" 私は テキストがあることを確認する "2025年5月1日" 私は テキストがあることを確認する "3泊" 私は テキストがあることを確認する "2名" 私は テキストがあることを確認する "山田太郎" 私は クリックする "確定" 私は テキストがあることを確認する "予約を完了しました" 私は テキストがあることを確認する "ご来館、心よりお待ちしております。" ✔ OK in 1444ms CodeceptJSと他のツールとの連携について CodeceptJSは複数のブラウザ制御エンジン(ヘルパー)に対応しており、以下のように設定を変更するだけでテストが動作します。 Playwright(今回使用) Puppeteer WebDriver TestCafe codecept.conf.jsファイルの中でヘルパーを指定する部分があります。たとえばPlaywrightの場合は以下のようになります。 helpers: { Playwright: { url: '<http://example.selenium.jp/reserveApp_Renewal/>', show: true, browser: 'chromium' } } browserを切り替えるとFirefoxやSafari相当でもテスト可能です。 また、他のプロダクトと連携したい場合(Allureレポート、BDDツールなど)のプラグインも充実しています。 おわりに デモサイトを使った簡単なテストを書くことで、CodeceptJSの導入からE2Eテストの実行までの流れを理解していただけたかと思います。シンプルな記述で強力なE2Eテストが実現できるCodeceptJSは、テスト自動化の強い味方となるでしょう。ぜひ本記事を参考に、あなたのプロジェクトでもCodeceptJSを導入・活用してみてください。 また、今後はAIを活用したテストコードについても解説したいと考えています。CodeceptJSは公式にAI連携機能を提供しており、ChatGPTなどの生成AIを活用したテストコードの自動生成や、自然言語での指示によるテスト作成が可能です。さらに、テスト失敗時の原因分析やテストケースの提案など、AIの力でテスト自動化をさらに効率化できます。CodeceptJSのAI機能を活用すれば、テストコードの品質向上と開発時間の短縮を同時に実現できるでしょう。 The post テスト自動化の決定版!CodeceptJSで実現するメンテナブルなE2Eテスト first appeared on Sqripts .
こんにちわ。 GSです。 今回はGoogle CloudでOpen WebUIを構築する方法を解説します。 本記事では、一つひとつのgcloudコマンドを実行しながらGoogle Cloud上にプライベートなAIチャット環境「Open WebUI」を構築していきます。Terraformのような一括デプロイではなく、各ステップを順に進めることで、Cloud Run、Cloud Storage、Cloud SQLなどのサービスがどのように連携するのかを体系的に理解できます。コマンドを実行し、結果を確認する過程を通じて、Google Cloudの基本から応用まで自然と身につき、最終的にはセキュアで拡張性のあるAI環境を自分の手で構築できる実力が養われます。初心者から中級者まで、実際に手を動かしながらクラウド技術を習得したいエンジニアにぴったりの実践ガイドです。 先に結論 この記事でわかること、得られること。 Open WebUI Open WebUIが使えるようになる Open WebUIのデプロイ設定方法が分かる Google Cloud Google Cloudをgcloudで操作することができる Cloud Runが何となく分かる サイドカーコンテナが何となく分かる 独自ドメインで運用できるようになる Cloud Storageが何となく分かる Cloud Runにマウントして使えることが分かる gsutilでファイルをアップロードできることが分かる Cloud SQLが何となく分かる Cloud Secret Managerが何となく分かる Cloud Runのスケール対応が何となく分かる Google Cloudにおけるプロダクトへのアクセス制限方法について何となく分かる Cloud Armorが何となく分かる Identity-Aware Proxy(IAP)が何となく分かる OAuthやOIDCの設定が何となく分かる VPCが何となく分かる Cloud Load Balancingが何となく分かる 前提条件 以下の必須条件および状況に応じてオプション条件を満たしていることを前提とします。 必須 この記事を作業する人に対して OPENAIのAPIキーがあること Google Cloudのプロジェクトを作成していること Google Cloudリソースを操作できる権限があること オプション この記事では段階的に環境を構築していきます。 Cloud DNSが操作できる権限があること または 扱いたい独自ドメインを管理しているサービスにアクセスできること Open WebUIとは? Open WebUIは、オープンソースのチャットインターフェースで、様々な大規模言語モデル(LLM)と対話するためのウェブベースのユーザーインターフェースです。元々はOllamaのフロントエンドとして開発されましたが、現在ではOpenAIをはじめ、追加の設定を行うことでAnthropic、Google、Mistral AIなど、多くのAIプロバイダーのモデルをサポートしています。 主な特徴 多様なモデルサポート : OpenAI GPT-4/3.5、Anthropic Claude、Google Gemini、Mistral AI、Ollama、その他のローカルモデルなど、様々なAIモデルと接続できます。 RAG(検索拡張生成)機能 : ウェブ検索、PDFアップロード、画像分析などを通じて、AIの回答を外部情報で強化できます。 チャット履歴管理 : 会話履歴を保存し、後で参照したり続きから対話したりできます。 カスタマイズ可能 : テーマ設定、プロンプトテンプレート、システムプロンプトなど、ユーザー体験をカスタマイズできる機能が豊富です。 マルチユーザー対応 : 複数のユーザーアカウントをサポートし、チームでの利用が可能です。 セルフホスティング : 自分のサーバーやクラウド環境にデプロイして、データの管理を自分で行えます。 利用シナリオ Open WebUIは以下のような用途で活用できます: 個人やチームでのAIアシスタントとして 社内向けのプライベートなAIチャットボットとして 複数のAIモデルを一つのインターフェースから利用したい場合 データプライバシーを重視する環境でのAI活用 この記事では、Google Cloud上にOpen WebUIをデプロイする方法を解説します。これにより、セキュアで拡張性の高いAIチャットインターフェースを構築することができます。 SearXNGとは? SearXNGは、プライバシーを重視したオープンソースのメタ検索エンジンです。複数の検索エンジン(Google、Bing、DuckDuckGoなど)から結果を収集し、それらを統合して提供します。Open WebUIには検索機能が統合されていないため、SearXNGを使用して最新のデータを取り込みます。o1のような検索機能がないモデルを利用しつつ、ネット上を検索させ結果を取り込みたいという場合、必須のサービスです。 しかしながら、 GPT-4o searchモデルなどの検索機能があるモデルを利用している場合は、SearXNGを使用する必要はありません。 以下にSearXNGの主な特徴を紹介します: 主な特徴 プライバシー保護 : ユーザーの検索クエリを匿名化し、検索エンジンに対して中継役として機能することで、ユーザーのプライバシーを保護します。 多様な検索ソース : 一般的なウェブ検索だけでなく、画像、動画、ニュース、地図など、様々なカテゴリの検索結果を提供します。 カスタマイズ可能 : 使用する検索エンジンの選択、結果の表示方法、インターフェースのテーマなど、多くの設定をカスタマイズできます。 トラッキングなし : ユーザーの行動を追跡せず、広告も表示しません。 セルフホスティング : 自分のサーバーにインストールして運用できるため、完全に制御可能です。 APIサポート : プログラムから検索結果にアクセスするためのAPIを提供しています。 Open WebUIとの連携 この記事では、Open WebUIとSearXNGをサイドカーコンテナとして配置し連携させて使用します。この組み合わせにより、以下のようなメリットがあります: AIチャットボットが最新の情報にアクセスできるようになります(RAG機能) ウェブ検索結果をプライバシーを保護しながら取得できます 外部依存を減らし、より自律的なAIアシスタント環境を構築できます SearXNGはOpen WebUIのRAG(検索拡張生成)機能のバックエンドとして機能し、AIの回答生成に役立つ最新の情報をウェブから取得します。 サイドカーコンテナとは? サイドカーコンテナは、メインのアプリケーションコンテナと同じPod内で実行される補助的なコンテナです。Kubernetes環境やCloud Runなどのコンテナオーケストレーションプラットフォームで利用される設計パターンの一つです。 サイドカーコンテナの主な特徴と利点は以下の通りです: 共有リソース : メインコンテナとネットワーク名前空間やボリュームを共有できるため、localhost経由で通信が可能です 分離された責務 : 機能ごとに別々のコンテナに分けることで、各コンテナの責務を明確にし、メンテナンス性を向上させます 独立したライフサイクル : メインアプリケーションに影響を与えずに、サイドカーコンテナを更新・再起動できます 専門化されたサービス : ログ収集、モニタリング、プロキシなど特定の機能に特化したコンテナを追加できます 今回のケースでは、Open WebUIがメインコンテナとなり、SearXNGがサイドカーコンテナとして動作します。これにより、Open WebUIはlocalhostを通じてSearXNGの検索機能にアクセスでき、両者が密接に連携しながらも、それぞれのコンテナが独自の責務を持つ構成が実現できます。 この構成により、Open WebUIの更新とSearXNGの更新を独立して行うことができ、また各コンテナが専門の機能に集中することでシステム全体の保守性が向上します。 操作環境 今回は環境の差異をできるだけなくすため、Google Cloud Shellを使用します。 Google Cloudの画面右上にある「Cloud Shellをアクティブにする」ボタンをクリックしてください。 「Cloud Shell の承認」ダイアログが表示されるので、「承認」をクリックしてください。 ブラウザ上で、gcloudやある程度のLinuxコマンドが使えるターミナル環境がブラウザに表示されます。 以降、この記事に書いてあるコマンドは、このターミナル上でコマンドを打っていきます。 gcloudのための環境変数 この記事では多くのコマンドを打っていきますが、そのコマンドを汎用的なコマンドにするために環境変数を使用しています。 以下の環境変数を設定してください。 今回はデプロイ先リージョンをus-central1にしています。 ご利用予定の環境に合わせて変更してください。 export PROJECT_NUMBER=$(gcloud projects describe $(gcloud config get-value project) --format="value(projectNumber)") export PROJECT_ID=$(gcloud config get-value project) export REGION=us-central1 export LOCATION=us-central1 export OPEN_WEBUI_DOMAIN=open-webui-${PROJECT_NUMBER}.${REGION}.run.app export OPENWEBUI_BUCKET_NAME=${PROJECT_ID}-open-webui export SEARXNG_BUCKET_NAME=${PROJECT_ID}-open-webui-searxng-config-bucket 適切に設定できているかを確認してみましょう。 echo PROJECT_NUMBER: $PROJECT_NUMBER \ PROJECT_ID: $PROJECT_ID \ REGION: $REGION \ LOCATION: $LOCATION \ OPEN_WEBUI_DOMAIN: $OPEN_WEBUI_DOMAIN \ OPENWEBUI_BUCKET_NAME: $OPENWEBUI_BUCKET_NAME \ SEARXNG_BUCKET_NAME: $SEARXNG_BUCKET_NAME それぞれの値が表示されれば、環境変数の設定は完了です。 Google Cloud API Google Cloud で必要な API を事前に有効化するための gcloud services enable コマンドがあります。 このコマンドを使用することで、インタラクティブなプロンプトなしに必要な API を事前に有効化できます。 gcloud services enable secretmanager.googleapis.com この記事全体で使う可能性のあるAPIを一括で有効化します。 gcloud services enable \ artifactregistry.googleapis.com \ secretmanager.googleapis.com \ run.googleapis.com \ sqladmin.googleapis.com \ admin.googleapis.com \ iap.googleapis.com \ certificatemanager.googleapis.com \ cloudresourcemanager.googleapis.com \ redis.googleapis.com Artifact Registry Open WebUIは、GitHub Container Registryにイメージが登録されています。 Google Cloudからは、GitHub Container Registryにアクセスできないため、そのミラーをArtifact Registryに作成して使用します。 Artifact Registryリポジトリの作成 リポジトリを作成します。 gcloud artifacts repositories create ghcr \ --repository-format=docker \ --location=${LOCATION} \ --description="Remote repository for GitHub Container Registry" \ --mode=remote-repository \ --remote-docker-repo=https://ghcr.io \ --remote-repo-config-desc="GitHub Container Registry" ### リポジトリの削除 リポジトリを削除したい場合は、以下のコマンドを実行します。 ```bash gcloud artifacts repositories delete ghcr --location=${LOCATION} Artifact Registryリポジトリ一覧の確認 リポジトリ一覧を確認します。 gcloud artifacts repositories list Artifact Registryリポジトリにキャッシュされているイメージ一覧の確認 リポジトリにキャッシュされているイメージ一覧を確認します。 gcloud artifacts docker images list ${REGION}-docker.pkg.dev/${PROJECT_ID}/ghcr サービスアカウント 今回はCloud Runにサービスをデプロイしていきます。そのCloud Runのためのサービスアカウントを作成します。 サービスアカウントとは サービスアカウントは、Google Cloud上でアプリケーションやワークロードが使用する特別な種類のアカウントです。人間のユーザーではなく、サービスやアプリケーションがGoogle Cloudリソースにアクセスするために使用されます。 サービスアカウントの主な特徴 アイデンティティとアクセス管理 Google Cloudリソースへのアクセスを制御するためのIAM(Identity and Access Management)と統合されています 必要最小限の権限を付与する「最小権限の原則」に基づいて設定できます 特定のサービスやリソースに対してのみ権限を付与することが可能です セキュリティ APIキーやパスワードではなく、より安全な認証メカニズムを提供します 自動的にローテーションされる短期の認証情報を使用できます 監査ログによりアクセスの追跡が可能です 柔軟性 複数のサービスアカウントを作成して、異なる役割や責任を分離できます 環境(開発、テスト、本番)ごとに異なるサービスアカウントを使用できます Compute Engine、Cloud Run、Cloud Functionsなど様々なサービスで利用可能です サービスアカウントの使用シナリオ Cloud Runアプリケーションが他のGoogle Cloudサービス(Cloud Storage、Cloud SQL、Secret Managerなど)にアクセスする場合 バッチジョブやスケジュールされたタスクがAPIを呼び出す場合 マイクロサービスアーキテクチャにおける、サービス間の認証 CI/CDパイプラインがリソースをデプロイする場合 サービスアカウントを適切に設定することで、アプリケーションに必要な権限のみを付与し、セキュリティリスクを最小限に抑えながらGoogle Cloudリソースへのアクセスを管理することができます。 サービスアカウントの作成 サービスアカウントを作成します。 gcloud iam service-accounts create open-webui \ --display-name="Open WebUI Service Account" サービスアカウントの削除 サービスアカウントを削除したい場合は、以下のコマンドを実行します。 gcloud iam service-accounts delete open-webui@${PROJECT_ID}.iam.gserviceaccount.com サービスアカウントにIAMポリシーのバインド Cloud RunからGoogle Cloudのサービスにアクセスするためには、サービスアカウントにIAMポリシーをバインドする必要があります。 シークレットマネージャーにアクセスするためのIAMポリシーをバインドします。 gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="serviceAccount:open-webui@${PROJECT_ID}.iam.gserviceaccount.com" \ --role="roles/secretmanager.secretAccessor" ストレージにアクセスし、ファイル作成編集するためのIAMポリシーをバインドします。 gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="serviceAccount:open-webui@${PROJECT_ID}.iam.gserviceaccount.com" \ --role="roles/storage.objectAdmin" Cloud SQLにアクセスするためのIAMポリシーをバインドします。 gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="serviceAccount:open-webui@${PROJECT_ID}.iam.gserviceaccount.com" \ --role="roles/cloudsql.client" RedisにアクセスするためのIAMポリシーをバインドします。 gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="serviceAccount:open-webui@${PROJECT_ID}.iam.gserviceaccount.com" \ --role="roles/redis.editor" IAMポリシーの削除 IAMポリシーを削除したい場合は、以下のコマンドを実行します。 –roleに削除したいロールを指定します。 以下の例では「secretmanager.secretAccessor」ロールを削除しています。 gcloud projects remove-iam-policy-binding ${PROJECT_ID} \ --member="serviceAccount:open-webui@${PROJECT_ID}.iam.gserviceaccount.com" \ --role="roles/secretmanager.secretAccessor" Google Cloud Storage gcsにはいくつかの設定やファイルを保存します。今回は ユーザーのアップロードファイル SearXNGの設定ファイル のためのバケットを作成します。 SearXNGのバケットはCloud Run内のコンテナへマウントされて使用されます。コンテナからは通常のファイルやディレクトリとしてアクセスできます。 Google Cloud Storage(GCS)とは? Google Cloud Storage(GCS)は、Googleが提供するオブジェクトストレージサービスです。ファイルをオブジェクトとして保存し、世界中のどこからでもアクセスできるようにします。 Google Cloud Storageの主な特徴 高い耐久性と可用性 データは複数の場所に冗長的に保存され、99.999999999%(11個の9)の耐久性を実現 標準ストレージクラスでは99.99%の可用性を提供 地理的に分散したロケーションにデータを保存することも可能 柔軟なストレージクラス 標準ストレージ : 頻繁にアクセスされるデータ向け Nearline Storage : 月に1回程度アクセスされるデータ向け Coldline Storage : 四半期に1回程度アクセスされるデータ向け Archive Storage : 年に1回未満のアクセスで、長期保存が必要なデータ向け 強力なセキュリティ IAMによる詳細なアクセス制御 データの暗号化(保存時および転送時) VPCサービスコントロールによる境界保護 統合性 他のGoogleサービス(BigQuery、Cloud Run、Compute Engineなど)と簡単に連携 RESTful APIを通じて様々なアプリケーションから利用可能 Google Cloud Storageの利用シナリオ ウェブサイトのコンテンツ配信 データバックアップとアーカイブ ビッグデータ分析のためのデータレイク アプリケーションのユーザーアップロードファイルの保存 機械学習モデルの保存と配布 Cloud RunとGCSの連携 Cloud RunからGCSを利用する方法は主に2つあります: APIを通じたアクセス : Cloud Runのアプリケーションから、GCSのクライアントライブラリやRESTful APIを使用してバケット内のオブジェクトにアクセス マウント : Cloud Storage FUSEを使用して、GCSバケットをファイルシステムとしてマウント この記事では、Open WebUIのユーザーアップロードファイルの保存先としてGCSを利用し、SearXNGの設定ファイルをGCSに保存してCloud Runコンテナにマウントする方法を解説します。 Open WebUIに対するユーザーのアップロードファイル保存バケットの作成 ユーザーのアップロードファイル保存バケットを作成します。 gcloud storage buckets create gs://${OPENWEBUI_BUCKET_NAME} --location=${LOCATION} ユーザーのアップロードファイル保存バケットの削除 上記で作成したバケットを削除したい場合は、以下のコマンドを実行します。 gcloud storage buckets delete gs://${OPENWEBUI_BUCKET_NAME} SearXNGの設定ファイル保存バケットの作成 SearXNGの設定ファイルを保存するバケットを作成します。 gcloud storage buckets create gs://${SEARXNG_BUCKET_NAME} --location=${LOCATION} SearXNGファイル保存バケットの削除 上記で作成したバケットを削除したい場合は、以下のコマンドを実行します。 gcloud storage buckets delete gs://${SEARXNG_BUCKET_NAME} OPENAI Open WebUIでは、OPENAIのAPIを使用して、チャットや画像生成、音声生成などの機能を利用できます。 ここではOpen WebUIで、OPENAIに関する機能を使うための設定を行っていきます。 事前にOPENAIより APIキーを取得 してください。 OPENAI APIキーのシークレットの作成 シークレットを作成します。 YOUR_OPEN_WEBUI_OPENAI_API_KEY部分を実際に利用するキーに書き換えます。  別のキーに更新したい場合も、同じコマンドで更新できます。 ここで作成されたシークレットの値がOpen WebUIのCloud Runの環境変数に設定されます。 echo -n "YOUR_OPEN_WEBUI_OPENAI_API_KEY" | gcloud secrets create open_webui_openai_api_key \ --replication-policy="automatic" \ --data-file=- シークレットの削除 シークレットを削除したい場合は、以下のコマンドを実行します。 gcloud secrets delete open_webui_openai_api_key OAuth OAuthに関する設定をおこないます。 この設定を行うことで、Open WebUIにGoogle Workspaceのユーザーがログインできるようになります。 gcloudである程度の設定を行えますが、機能的に厳しいため、ブラウザでGoogle Cloud Consoleを開いて操作します。 OAuthとは OAuth(Open Authorization)は、ユーザーが自分のアカウント情報を第三者のアプリケーションに直接提供することなく、安全に認証・認可を行うための標準プロトコルです。 OAuth 2.0の主な特徴 安全な認証委任 ユーザーはパスワードを第三者アプリケーションに直接提供する必要がありません 代わりに、信頼できる認証プロバイダー(GoogleやFacebookなど)を通じて認証します アプリケーションはユーザーの同意を得た特定の権限(スコープ)のみを取得できます 柔軟なアクセス制御 アクセストークンを使用して、リソースへのアクセスを制御します トークンには有効期限があり、セキュリティリスクを軽減します 必要に応じてトークンを無効化することも可能です 様々な認証フロー 認可コードフロー:Webアプリケーション向け インプリシットフロー:ブラウザベースのアプリケーション向け クライアントクレデンシャルフロー:サーバー間通信向け リソースオーナーパスワードクレデンシャルフロー:高度な信頼関係がある場合向け OpenID Connectとは OpenID Connect(OIDC)は、OAuth 2.0プロトコルの上に構築された認証レイヤーです。OAuth 2.0が「認可」(何ができるか)に焦点を当てているのに対し、OpenID Connectは「認証」(誰であるか)に焦点を当てています。 OpenID Connectの主な特徴 ID Token : JWT(JSON Web Token)形式で、ユーザーの身元情報を含みます UserInfo Endpoint : ユーザーに関する追加情報を取得するためのエンドポイント 標準化されたクレーム : email、name、pictureなど、ユーザー情報の標準フィールド ディスカバリー : 認証サーバーの設定を自動的に発見する機能 OpenID Connectの利点 シングルサインオン(SSO)の実現が容易になります 標準化されたプロトコルにより、異なるプラットフォーム間での相互運用性が向上します セキュリティが強化され、フィッシング攻撃などのリスクが軽減されます Open WebUIでは、このOAuth 2.0とOpenID Connectを利用して、Googleアカウントでの安全なログインを実現しています。ユーザーはGoogleの認証システムを通じて認証され、Open WebUIはユーザーの基本情報のみを受け取り、パスワードなどの機密情報は一切取得しません。 OAuthブランドの作成 Google Cloud ConsoleでOAuthブランドを作成します。 ブランディングより「開始」ボタンを押します。 アプリ情報と連絡先メールアドレスを入力します。 対象を「内部」に設定します。 連絡先にメールアドレスを設定します。 同意を選択し「作成」ボタンを押しましょう。 以上でブランディングの作成は完了です。 OAuthブランド一覧の確認 作成したOAuthブランドはGoogle Cloud Consoleで確認できますが、以下のコマンドでも確認できます。 gcloud iap oauth-brands list OAuthクライアントの作成 OAuthクライアントはgcloudでも作成できますが、機能的にはGoogle Cloud Consoleで作成した方が良いです。 クライアントメニューより「+ CREATE CLIENT」を選択します。 アプリケーションの種類を「Webアプリケーション」。名前は適切なものを設定してください。 最後に作成ボタンを押します。 OAuth Client IDをシークレットマネージャーへ登録 OAuth Client画面から、Client IDとClient Secretを取得し、その値でシークレットを作成します。YOUR_OPEN_WEBUI_OAUTH_CLIENT_ID部分を実際に利用するキーに書き換えます。 echo -n "YOUR_OPEN_WEBUI_OAUTH_CLIENT_ID" | gcloud secrets create open_webui_oauth_client_id \ --replication-policy="automatic" \ --data-file=- OAuth Client IDシークレットの削除 上記で作成したシークレットを削除したい場合は、以下のコマンドを実行します。 gcloud secrets delete open_webui_oauth_client_id OAuth Client Secretをシークレットマネージャーへ登録 シークレットを作成します。YOUR_OPEN_WEBUI_OAUTH_CLIENT_SECRET部分を実際に利用するキーに書き換えます。 echo -n "YOUR_OPEN_WEBUI_OAUTH_CLIENT_SECRET" | gcloud secrets create open_webui_oauth_client_secret \ --replication-policy="automatic" \ --data-file=- OAuth Client Secretシークレットの削除 上記で作成したシークレットを削除したい場合は、以下のコマンドを実行します。 gcloud secrets delete open_webui_oauth_client_secret Cloud SQL Cloud SQLでPostgreSQLを作成して使用します。 Cloud SQLはOpen WebUIの設定やチャットのデータ管理に使用されます。 Cloud SQLとは Cloud SQLは、Google Cloudが提供するフルマネージドのリレーショナルデータベースサービスです。MySQL、PostgreSQL、SQL Serverなどの主要なデータベースエンジンをサポートしており、インフラストラクチャの管理やメンテナンスの負担を軽減しながら、高可用性と耐久性のあるデータベース環境を提供します。 Cloud SQLの主な特徴 マネージドサービス バックアップ、パッチ適用、レプリケーション、容量管理などの運用タスクを自動化 データベースエンジンのアップデートを自動的に管理 監視とアラートの機能が組み込まれている セキュリティ データの保存時と転送時の暗号化 ネットワークファイアウォールによるアクセス制御 IAMとの統合による認証と認可 Virtual Private Cloud (VPC) 内でのプライベート接続 高可用性と耐久性 リージョン内での高可用性構成(99.95%のSLA) 自動フェイルオーバー機能 定期的な自動バックアップとポイントインタイムリカバリ クロスリージョンレプリケーション(災害復旧用) スケーラビリティ 垂直スケーリング(マシンタイプのアップグレード) 読み取りレプリカによる水平スケーリング ストレージの自動拡張 統合性 Google Cloud内の他のサービス(Cloud Run、Compute Engine、BigQueryなど)との簡単な連携 Cloud SQLプロキシを使用した安全な接続 データベース移行サービス(DMS)によるデータ移行のサポート Cloud SQLの利用シナリオ Webアプリケーションやモバイルアプリのバックエンドデータベース ビジネスアプリケーション(CRM、ERP、eコマースなど)のデータストア データ分析や報告のためのデータウェアハウス マイクロサービスアーキテクチャにおけるサービス固有のデータベース レガシーデータベースのクラウド移行先 Cloud SQLを使用することで、データベース管理の複雑さを軽減しながら、スケーラブルで信頼性の高いデータベース環境を構築することができます。 インスタンスの作成 今回は単純な構成でPostgreSQL 17のインスタンスを作成します。 利用の環境に合わせて、各パラメーターを調整したり、バックアップの設定やリードレプリカの作成などを行ってください。 また、コマンドにある「YOUR_SECURE_PASSWORD」部分を実際に利用するパスワードに書き換えます。 gcloud sql instances create open-webui \ --database-version=POSTGRES_17 \ --tier=db-custom-1-3840 \ --region=${REGION} \ --edition=ENTERPRISE \ --root-password="YOUR_SECURE_PASSWORD" インスタンスの削除 インスタンスを削除したい場合は、以下のコマンドを実行します。 gcloud sql instances delete open-webui データベースの作成 Open WebUIのデータベースを作成します。 gcloud sql databases create open-webui \ --instance=open-webui データベースの削除 データベースを削除したい場合は、以下のコマンドを実行します。 gcloud sql databases delete open-webui \ --instance=open-webui ユーザーの作成 Open WebUIのユーザーを作成します。 また、コマンドにある「YOUR_USER_PASSWORD」部分を実際に利用するパスワードに書き換えます。 gcloud sql users create open-webui \ --instance=open-webui \ --password="YOUR_USER_PASSWORD" ユーザーの削除 ユーザーを削除したい場合は、以下のコマンドを実行します。 gcloud sql users delete open-webui \ --instance=open-webui データベースrootパスワードをシークレットマネージャーに作成 シークレットを作成します。YOUR_SECURE_PASSWORD部分をデータベースrootパスワードに書き換えます。 このシークレットは今回の作業では使うことはありません。 設定したパスワードを記録しておくためだけに作成しています。 ですのでこの工程は省略可能です。 echo -n "YOUR_SECURE_PASSWORD" | gcloud secrets create open_webui_database_root_password \ --replication-policy="automatic" \ --data-file=- データベース接続URLをシークレットマネージャーに作成 シークレットを作成します。YOUR_USER_PASSWORD部分をデータベースアカウント作成時に指定したパスワードに書き換えます。 echo -n "postgresql://open-webui:YOUR_USER_PASSWORD@/open-webui?host=/cloudsql/${PROJECT_ID}:${REGION}:open-webui" | gcloud secrets create open_webui_database_url \ --replication-policy="automatic" \ --data-file=- データベース接続URLシークレットの削除 上記で作成したシークレットを削除したい場合は、以下のコマンドを実行します。 gcloud secrets delete open_webui_database_url SearXNG設定 SearXNGの設定ファイルを保存するバケットを作成します。 以下は一般的な設定です。 細かい制御を行いたい場合は、 SearXNGの公式ドキュメント を参照してください。 limiter.tomlを作成 limiter.tomlを作成します。 cat << 'EOF' >| limiter.toml # This configuration file updates the default configuration file # See https://github.com/searxng/searxng/blob/master/searx/botdetection/limiter.toml [botdetection.ip_limit] # activate link_token method in the ip_limit method link_token = false [botdetection.ip_lists] block_ip = [] pass_ip = [] EOF settings.yamlを作成 settings.yamlを作成します。 cat << 'EOF' >| settings.template.yml use_default_settings: true server: secret_key: "$(openssl rand -hex 32)" search: formats: - html - json safe_search: 0 outgoing: request_timeout: 6.0 max_request_timeout: 15.0 retries: 3 EOF 一部シェルコマンドが含まれているため、以下のコマンドでシェルコマンドを展開します。 envsubst < settings.template.yml >| settings.yml バケットに設定ファイルをアップロード 作成した設定ファイルをバケットにアップロードします。 gsutil cp limiter.toml settings.yml gs://${SEARXNG_BUCKET_NAME}/ 作成したファイルがアップロードされているか確認してみましょう。 gsutil ls gs://${SEARXNG_BUCKET_NAME}/ ファイルが見えれば成功です。 SearXNGの設定ファイルを削除 作成した設定ファイルを削除したい場合は、以下のコマンドを実行します。 gsutil rm "gs://${SEARXNG_BUCKET_NAME}/*" Cloud Run アプリケーションの実態であるコンテナをCloud Runへデプロイします。 Cloud Runとは Cloud Runは、コンテナ化されたアプリケーションをサーバーレスで実行できるマネージドコンピューティングプラットフォームです。 主な特徴 サーバーレス インフラストラクチャの管理が不要 使用した分だけ課金される従量課金制 自動でスケーリング コンテナベース DockerコンテナをそのままデプロイできるためCI/CDとの親和性が高い 言語やフレームワークを問わずアプリケーションを実行可能 コンテナイメージの管理が容易 セキュリティ HTTPSエンドポイントを自動で提供 IAMによる認証・認可の制御 VPCとの接続も可能 運用性 リビジョン管理によるロールバックが容易 ヘルスチェックによる自動復旧 ログやメトリクスの可視化 Cloud Runを使用することで、インフラストラクチャの管理から解放され、アプリケーションの開発に集中することができます。 Cloud Run構成定義yamlファイルの作成 今回はyamlファイルを用いてCloud Runサービスを作成します。 以下のコマンドで、Open WebUIの環境を作成するためのテンプレートファイルを作成します。 cat << 'EOF' >| open-webui.template.yaml apiVersion: serving.knative.dev/v1 kind: Service metadata: name: open-webui annotations: run.googleapis.com/ingress: all run.googleapis.com/ingress-status: all spec: template: metadata: annotations: autoscaling.knative.dev/minScale: '0' autoscaling.knative.dev/maxScale: '1' run.googleapis.com/cloudsql-instances: ${PROJECT_ID}:${LOCATION}:open-webui spec: containerConcurrency: 40 timeoutSeconds: 600 serviceAccountName: open-webui@${PROJECT_ID}.iam.gserviceaccount.com containers: - name: open-webui image: ${REGION}-docker.pkg.dev/${PROJECT_ID}/ghcr/open-webui/open-webui@sha256:9b7fb388f0828b597e67c263667214c93592cbc5cac3047be89f5e92bc1085ba ports: - name: http1 containerPort: 8081 env: - name: DEFAULT_USER_ROLE value: user - name: ENABLE_LOGIN_FORM value: 'True' - name: STORAGE_PROVIDER value: gcs - name: GCS_BUCKET_NAME value: ${OPENWEBUI_BUCKET_NAME} - name: ENABLE_OAUTH_SIGNUP value: 'True' - name: OPENID_PROVIDER_URL value: https://accounts.google.com/.well-known/openid-configuration - name: ENABLE_OAUTH_GOOGLE value: 'True' - name: GOOGLE_REDIRECT_URI value: https://${OPEN_WEBUI_DOMAIN}/oauth/google/callback - name: WEBUI_URL value: https://${OPEN_WEBUI_DOMAIN} - name: ENABLE_OLLAMA_API value: 'False' - name: ENABLE_EVALUATION_ARENA_MODELS value: 'False' - name: ENABLE_RAG_WEB_SEARCH value: 'True' - name: RAG_WEB_SEARCH_ENGINE value: "searxng" - name: RAG_WEB_SEARCH_RESULT_COUNT value: '3' - name: RAG_WEB_SEARCH_CONCURRENT_REQUESTS value: '10' - name: SEARXNG_QUERY_URL value: "http://localhost:8080/search?q=<query>" - name: DATABASE_URL valueFrom: secretKeyRef: key: latest name: open_webui_database_url - name: OPENAI_API_KEY valueFrom: secretKeyRef: key: latest name: open_webui_openai_api_key - name: GOOGLE_CLIENT_ID valueFrom: secretKeyRef: key: latest name: open_webui_oauth_client_id - name: GOOGLE_CLIENT_SECRET valueFrom: secretKeyRef: key: latest name: open_webui_oauth_client_secret resources: limits: cpu: 2000m memory: 2.0Gi startupProbe: httpGet: path: / port: 8081 initialDelaySeconds: 10 periodSeconds: 3 failureThreshold: 30 - name: searxng image: searxng/searxng:latest env: - name: SEARXNG_HOSTNAME value: 'localhost:8080' - name: SEARXNG_PORT value: '8080' - name: SEARXNG_BIND_ADDRESS value: '0.0.0.0' - name: SEARXNG_STATIC_USE_HASH value: 'true' - name: SEARXNG_LIMITER value: 'false' - name: SEARXNG_IMAGE_PROXY value: 'true' resources: limits: cpu: 1000m memory: 1Gi volumeMounts: - name: searxng-config mountPath: /etc/searxng volumes: - name: searxng-config csi: driver: gcsfuse.run.googleapis.com readOnly: false volumeAttributes: bucketName: ${SEARXNG_BUCKET_NAME} EOF 続けて以下のコマンドを実行し、yamlファイルを作成します。 envsubst < open-webui.template.yaml > open-webui.yaml Cloud Runサービスの作成 作成したyamlファイルを用いてCloud Runサービスを作成します。 gcloud run services replace open-webui.yaml --project=${PROJECT_ID} --region=${REGION} --platform=managed Cloud Runサービスの削除 上記で作成したサービスを削除したい場合は、以下のコマンドを実行します。 gcloud run services delete open-webui --project=${PROJECT_ID} --region=${REGION} Cloud RunサービスのIAMポリシーの設定 Cloud RunサービスのIAMポリシーを設定します。 この設定は非常に重要で、たとえばOpen WebUIのCloud Runを削除して作り直した場合などには常に再実行する必要があります。 今回はこの設定で、誰でもアクセスできるようにしています。逆を言えば、この設定を行わないと、誰もアクセスできないようになります。 gcloud run services add-iam-policy-binding open-webui --member="allUsers" --role="roles/run.invoker" --region=${REGION} OAuth認証設定 OAuthを使うための設定を行っていきます。 この設定の中で、Open ID Connectを使うための設定も間接的に行っています。 ブランディング Google Cloud Console → APIとサービス → OAuth 同意画面 → ブランディング の認証済みドメインへ echo ${OPEN_WEBUI_DOMAIN} で表示されるドメイン名を追加します。 OAuth2.0クライアント Google Cloud Console → APIとサービス → OAuth同意画面 → クライアント → 前工程で作成したOAuth2.0クライアントを選択 承認済みの JavaScript 生成元を追加 Cloud Run作成時に表示されたURLまたは gcloud run services describe open-webui --region=${REGION} --format="value(status.url)" で表示されるURLを「承認済みの JavaScript 生成元」に追加します。 「+URIを追加」をクリックして、URLを追加します。 承認済みのリダイレクトURIを追加 「承認済みのリダイレクト URI」には、Cloud Run作成時に表示されたURLまたはbash gcloud run services describe open-webui --region=${REGION} --format="value(status.url)" で表示されるURLに、 /oauth/google/callback を追加した値を追加します。 「+URIを追加」をクリックして、URLを追加します。 追加するURLは、 https://${デプロイ後に表示されるURL}/oauth/google/callback のようになるはずです。 データアクセス Google Cloud Console → APIとサービス → OAuth同意画面 → データアクセス ここからScopeの設定を行います。 「スコープを追加または削除」を押して、上から3つを選択します。 …/auth/userinfo.email Google アカウントのメインのメールアドレスの参照 …/auth/userinfo.profile ユーザーの個人情報の表示(ユーザーが一般公開しているすべての個人情報を含む) openid Google で公開されているお客様の個人情報とお客様を関連付ける これらを選択した後、「更新」を押します。 Open WebUIを利用してみる 以上で、Cloud Runサービスの作成は完了です。 Cloud Run作成完了後に表示されるURLへアクセスしてみましょう。 Open WebUIのログイン画面が表示されます。 URLがわからないという場合、以下のコマンドでURLを確認できます。 gcloud run services describe open-webui --region=${REGION} --format="value(status.url)" アクセスした際に Error: Forbidden Your client does not have permission to get URL / from this server. というエラーが表示される場合は、Cloud RunサービスのIAMポリシーを適用していない可能性が高いです。またIAMポリシー適用には時間がかかるため、動かないからと言ってすぐに設定を変えてみたりせず、しばらく待ってから再度確認してください。 今回のセットアップではGoogle Workspaceユーザーを使用したOAuthによるログインを有効にしているので、トップ画面より「Continue with Google」ボタンでログインし、そのまま使用することが可能です。 独自ドメインでの運用 ここまでの設定でもOpen WebUIを使うことは可能です。 ただ実際に使っていくとなると、独自ドメインを使用したくなると思います。 今回はGoogle Cloudで独自ドメインのゾーンを作成し、そのゾーンに独自ドメインをマッピングして運用してみます。 そのため、その使用予定の独自ドメインを管理することができるだけの状況下にあることを前提とします。 独自ドメインを使うための前準備 まずは独自ドメインとDNSのゾーン名称を環境変数に設定します。 YOUR_OPEN_WEBUI_DOMAIN / YOUR_ZONE_NAMEには、使用予定の独自ドメインとDNSのゾーン名称を設定します。 export OPEN_WEBUI_DOMAIN=YOUR_OPEN_WEBUI_DOMAIN export ZONE_NAME=YOUR_ZONE_NAME open-webui.example.comなら、 export OPEN_WEBUI_DOMAIN=open-webui.example.com とします。 example.comなら、 export ZONE_NAME=example-com とします。 指定した独自ドメインを使用して再度yamlファイルを生成します。 envsubst < open-webui.template.yaml >| open-webui.yaml 作成したyamlファイルを用いてCloud Runサービスを作成します。 gcloud run services replace open-webui.yaml --project=${PROJECT_ID} --region=${REGION} --platform=managed 独自ドメインのマッピング ドメインマッピングを作成します。 gcloud beta run domain-mappings create --service open-webui --domain ${OPEN_WEBUI_DOMAIN} --region ${REGION} (Cloud DNSでゾーン管理している人向け)独自ドメインのDNSレコードの作成 独自ドメインのDNSレコードを作成します。 レコードを追加するゾーンについては、すでに作成済みであり、ゾーンの所有確認が完了しているとします。 gcloud dns record-sets create ${OPEN_WEBUI_DOMAIN} \ --rrdatas="ghs.googlehosted.com." \ --ttl=300 \ --type=CNAME \ --zone=${ZONE_NAME} DNSレコードが正しく設定されたかを確認するには以下のコマンドを実行し、CNAMEレコードが存在することを確認します。 gcloud dns record-sets list --zone=${ZONE_NAME} または、nslookupやdigコマンドを使用して確認することもできます。 nslookup ${OPEN_WEBUI_DOMAIN} (Cloud DNSでゾーン管理していない人向け)独自ドメインのDNSレコードの作成 ご自身が利用されているDNSサービスで、CNAMEレコードを作成してください。 証明書のプロビジョニング DNSレコードが正しく設定されると、Google Cloudは自動的にSSL証明書のプロビジョニングを開始します。証明書のステータスは以下のコマンドで確認できます。 gcloud beta run domain-mappings describe --domain ${OPEN_WEBUI_DOMAIN} --region ${REGION} 証明書のプロビジョニングには時間がかかる場合があります。 いくつかのステータスがtrueになれば証明書のプロビジョニングが完了しています。 完了できていることが確認できたら、今回設定した独自ドメインへブラウザでアクセスしてみましょう。 画面が表示されれば設定は完了です。 ロードバランサー下での運用 より一層細かい制御を行いたいという場合、ロードバランサー下での運用を行うことも可能です。 ロードバランサー下での運用の前準備 前工程での独自ドメイン運用設定を行っている場合、まずはその設定を削除します。 ドメインマッピングの削除 ドメインマッピングを削除します。 gcloud beta run domain-mappings delete --domain ${OPEN_WEBUI_DOMAIN} --region ${REGION} ドメイン名のDNSレコードの削除 CNAMEレコードを削除します。 ゾーン名称は適切な値に変更してください。 gcloud dns record-sets delete ${OPEN_WEBUI_DOMAIN} --type=CNAME --zone=${ZONE_NAME} グローバルIPアドレスの予約 ロードバランサー下での運用にはグローバルIPアドレスが必要です。 前もってグローバルIPアドレスを予約しておきます。 gcloud compute addresses create open-webui-ip \ --global 予約したIPアドレスの確認 gcloud compute addresses describe open-webui-ip --global --format="get(address)" Cloud Run NEGの作成 gcloud compute network-endpoint-groups create open-webui-neg \ --region=${REGION} \ --network-endpoint-type=SERVERLESS \ --cloud-run-service=open-webui バックエンドサービスの作成 gcloud compute backend-services create open-webui-backend \ --global \ --load-balancing-scheme=EXTERNAL_MANAGED NEGをバックエンドサービスに追加 gcloud compute backend-services add-backend open-webui-backend \ --global \ --network-endpoint-group=open-webui-neg \ --network-endpoint-group-region=${REGION} URLマップの作成 gcloud compute url-maps create open-webui-url-map \ --default-service=open-webui-backend Cloud DNSへAレコードの作成 グローバルIPアドレスの予約時に取得したIPアドレスを使用します。 ゾーンは適切な値に変更してください。 gcloud dns record-sets create ${OPEN_WEBUI_DOMAIN} \ --type=A \ --ttl=300 \ --rrdatas=$(gcloud compute addresses describe open-webui-ip --global --format="get(address)") \ --zone=${ZONE_NAME} マネージドSSL証明書の作成 gcloud compute ssl-certificates create open-webui-cert \ --domains=${OPEN_WEBUI_DOMAIN} \ --global HTTPSプロキシの作成 gcloud compute target-https-proxies create open-webui-https-proxy \ --ssl-certificates=open-webui-cert \ --url-map=open-webui-url-map 転送ルールの作成 gcloud compute forwarding-rules create open-webui-https-rule \ --load-balancing-scheme=EXTERNAL_MANAGED \ --network-tier=PREMIUM \ --address=open-webui-ip \ --target-https-proxy=open-webui-https-proxy \ --global \ --ports=443 Cloud Runに対する外部からの直接アクセスを遮断 まず最新の情報でopen-webui.yamlファイルを更新します。 envsubst < open-webui.template.yaml >| open-webui.yaml open-webui.yamlファイルの以下の部分を変更します。 この設定の変更を行いデプロイすることで、Cloud Runに対する外部からの直接アクセスを遮断できます。 sed -i 's/run.googleapis.com\/ingress: all/run.googleapis.com\/ingress: internal-and-cloud-load-balancing/g' open-webui.yaml sed -i 's/run.googleapis.com\/ingress-status: all/run.googleapis.com\/ingress-status: internal-and-cloud-load-balancing/g' open-webui.yaml その後、デプロイします。 gcloud run services replace open-webui.yaml --project=${PROJECT_ID} --region=${REGION} --platform=managed この時点で、Cloud Runデプロイ後に表示されるURLや、 gcloud run services describe open-webui --region=${REGION} --format="value(status.url)" で表示されるURLにアクセスしても、Cloud Runに対する外部からの直接アクセスを遮断されているため、アクセスできなくなっているはずです。 代わりに設定した独自ドメインにアクセスすると、Open WebUIの画面が表示されるはずです。 今回の行程においては証明書のプロビジョニングを行っています。この処理は通常20分ほどかかるため、証明書のプロビジョニングが完了するまでは、設定した独自ドメインにアクセスしてもアクセスできない可能性が高いです。 証明書のプロビジョニングが完了しているかを確認したい場合は、以下のコマンドを実行してください。 gcloud compute ssl-certificates describe open-webui-cert --global status: PROVISIONING の場合は、証明書のプロビジョニングが完了するまで待ってください。  status: ACTIVE の場合は、証明書のプロビジョニングが完了しています。 Open WebUIに対するアクセス制御 ロードバランサー配下においたことにより、ロードバランサーの背後にあるCloud Runサービスに対するアクセス制御を行うことができます。 今回はセキュリティポリシーの適用による日本からのアクセスに限定する方法と、Identity-Aware ProxyによるGoogle Workspaceユーザーのみがアクセスできるようになる方法を紹介します。 なお この2つの方法は同時に適用することはできません。 Identity-Aware Proxyによるアクセス制御の一部が日本以外からのアクセスとなり、セキュリティポリシーの適用による日本からのアクセスに限定する方法とは矛盾するからです。 セキュリティポリシー(Cloud Armor)で制御したい場合 日本からのアクセスのみ許可するように設定してみます。 セキュリティポリシーの作成 まずはポリシーを作成します。 gcloud compute security-policies create open-webui-security-policy \ --description "open-webuiに対するセキュリティポリシー" 作成したポリシーに対して、日本からのアクセスを許可するルールを作成します。 gcloud compute security-policies rules create 1000 \ --security-policy open-webui-security-policy \ --description "日本からのアクセスを許可" \ --expression "origin.region_code == 'JP'" \ --action "allow" 作成したポリシーにおけるデフォルトルール(明示したルールにマッチしない場合のルール)を拒否に設定します。 2147483647はデフォルトルールのIDです。 gcloud compute security-policies rules update 2147483647 \ --security-policy open-webui-security-policy \ --description "デフォルトでアクセスを拒否" \ --action "deny-403" セキュリティポリシーをバックエンドサービスに適用 gcloud compute backend-services update open-webui-backend \ --security-policy=open-webui-security-policy \ --global 以上の設定で、日本からのアクセスのみ許可するようになります。 海外のProxyなどを利用して、アクセスできなくなっていることを確認してみてください。 セキュリティポリシーの適用を解除したい場合、 gcloud compute backend-services update open-webui-backend \ --security-policy= \ --global で、セキュリティポリシーの適用を解除できます。 Identity-Aware Proxy(IAP)で制御したい場合 Identity-Aware Proxyで、Google Workspaceユーザーのみがアクセスできるようにしてみます。 Identity-Aware Proxy(IAP)とは Identity-Aware Proxy(IAP)は、Google Cloudが提供するセキュリティサービスで、アプリケーションやリソースへのアクセスを細かく制御することができます。従来のVPNやファイアウォールとは異なり、ユーザーの身元(アイデンティティ)に基づいてアクセス制御を行います。 IAPの主な特徴 ユーザーベースのアクセス制御 Google WorkspaceやCloud Identityのユーザーアカウントを使用して認証を行います 特定のユーザー、グループ、ドメイン単位でアクセス権を付与できます IPアドレスではなく「誰であるか」に基づいてアクセスを制御します セキュリティの向上 VPNを使わずともセキュアなアクセスが可能になります 多要素認証(MFA)と組み合わせることで、さらにセキュリティを強化できます すべてのアクセスはログに記録され、監査が可能です 簡単な導入 アプリケーションコードの変更なしに導入できます Google Cloud Consoleから簡単に設定可能です 既存のCloud RunやApp Engineなどのサービスにシームレスに統合できます Identity-Aware Proxy(IAP)の仕組み Identity-Aware Proxy(IAP)は、ユーザーがアプリケーションにアクセスする際に「門番」のような役割を果たします: ユーザーがアプリケーションのURLにアクセスします Identity-Aware Proxy(IAP)がリクエストを受け取り、ユーザーに認証を要求します ユーザーがGoogle認証情報でログインします Identity-Aware Proxy(IAP)はユーザーの身元を確認し、アクセス権があるか確認します アクセス権がある場合のみ、リクエストをアプリケーションに転送します これにより、認証されていないユーザーはアプリケーションにアクセスできなくなり、セキュリティが大幅に向上します。 Identity-Aware Proxy(IAP)の利用シナリオ 社内ツールへのアクセスを特定の従業員のみに制限したい場合 顧客向けアプリケーションを特定の顧客のみに公開したい場合 開発環境や管理コンソールへのアクセスを開発者のみに制限したい場合 VPNを使わずに社内リソースへのセキュアなアクセスを提供したい場合 Identity-Aware Proxy(IAP)を使用することで、「誰が」「どのリソースに」アクセスできるかを細かく制御でき、セキュリティを強化しながらも利便性を損なわないアクセス管理が可能になります。 backend-servicesにIAPを有効化 先ほど作成したbackend-servicesに対し、Identity-Aware Proxy(IAP)を有効化します。 Google Cloud ConsoleのIdentity-Aware Proxy(IAP)のページで、確認できるようになります。 gcloud compute backend-services update open-webui-backend \ --global \ --iap backend-servicesのIAPを削除 backend-servicesを削除する場合は、以下のコマンドを実行します。 ただこのコマンド単体では削除に失敗する可能性が高いです。 gcloud compute backend-services delete open-webui-backend --global 実際削除しようと思うと、関係するリソースを先に削除する必要があります。 # 1. 転送ルールの削除 gcloud compute forwarding-rules delete open-webui-https-rule --global # 2. HTTPS プロキシの削除 gcloud compute target-https-proxies delete open-webui-https-proxy # 3. URL マップの削除 gcloud compute url-maps delete open-webui-url-map # 4. バックエンドサービスの削除(これで成功するはず) gcloud compute backend-services delete open-webui-backend --global 指定したドメインのみ許可 指定したドメインのみ許可する場合は、以下のコマンドを実行します。 たとえば、example.comのメールアドレスのみを許可する場合は、以下のコマンドを実行します。 gcloud iap web add-iam-policy-binding \ --member=domain:example.com \ --role=roles/iap.httpsResourceAccessor \ --resource-type=backend-services \ --service=open-webui-backend 指定したドメインの削除 指定したドメインを削除する場合は、以下のコマンドを実行します。 以下の例は、example.comを削除したい場合のコマンドです。 gcloud iap web remove-iam-policy-binding \ --member=domain:example.com \ --role=roles/iap.httpsResourceAccessor \ --resource-type=backend-services \ --service=open-webui-backend 独自ドメインをOAuth設定に追加 OAuth認証設定 と同じ手順で、独自ドメインをOAuth設定に追加します。 Identity-Aware Proxy(IAP)越しにアクセス 以上で、Identity-Aware Proxy(IAP)の設定は完了です。 トップページのアドレスにアクセスすると、「Googleでログイン」画面が表示されます。 ここでGoogle Workspaceのユーザーでログインすると、Open WebUIにアクセスできるようになります。 ここまでの内容で、ロードバランサー下での運用は完了です。 スケール対応 現在のopen-webui.yamlの設定では、1つのインスタンスしか起動しないようになっています。 これは、現在の設定のままだと、セッション情報の保存場所がローカル(インスタンス内)になっていて、インスタンスを複数起動しても、インスタンス間セッション情報が共有されず、正しいセッション管理ができないためです。 想定している同時アクセス数がそれほど多くない場合は1インスタンスで運用しても問題ないでしょう。 しかし、同時アクセス数が多い場合は、インスタンスを複数起動して水平スケールを行う必要があります。 VPC セッション情報の共有ためにRedisを使います。その際、Cloud RunからRedisにアクセスするためには、VPCを使う必要があります。 VPCとは? VPC(Virtual Private Cloud)は、Google Cloud Platform上に作成できる仮想ネットワークです。VPCを使用することで、クラウド内のリソース間で安全に通信できる独立したネットワーク環境を構築できます。 VPCの主な特徴と利点は以下の通りです: 分離されたネットワーク環境 : 他のプロジェクトやユーザーのリソースから論理的に分離された環境を提供します。 カスタムIPアドレス範囲 : 自分で定義したIPアドレス範囲を使用できます。 ファイアウォールルール : ネットワークトラフィックを制御するためのルールを設定できます。 プライベート接続 : インターネットを経由せずにGoogleのサービスに接続できます。 VPNやCloud Interconnectとの連携 : オンプレミス環境との安全な接続が可能です。 今回のケースでは、Cloud RunからRedisへの接続をインターネットを経由せずに安全に行うためにVPCを使用します。これにより、セッション情報を複数のCloud Runインスタンス間で共有し、水平スケーリングを実現します。 VPCの作成 今回はVPCをカスタムモードで作成します。 作成されるVPC名は、PROJECT_IDと同じになります。 gcloud compute networks create ${PROJECT_ID} \ --subnet-mode=custom VPCの削除 サブネットが作成されているとエラーになります。 gcloud compute networks delete ${PROJECT_ID} サブネットの作成 VPCにサブネットを作成します。 Cloud RunとVPCの間をDirect VPC Egressで接続するため、少し広め(24ではなく16)のサブネットを作成します。 gcloud compute networks subnets create ${PROJECT_ID}-open-webui \ --network=${PROJECT_ID} \ --region=${REGION} \ --range=10.0.0.0/16 \ --enable-private-ip-google-access サブネットの削除 gcloud compute networks subnets delete ${PROJECT_ID}-open-webui \ --region=${REGION} Redis Redisとは? Redisは、高性能なインメモリデータストア・キャッシュシステムです。主な特徴と利点は以下の通りです。 高速なパフォーマンス : データをメモリ上に保持するため、非常に高速なレスポンスが可能です。 多様なデータ構造 : 文字列、ハッシュ、リスト、セット、ソート済みセットなど、様々なデータ構造をサポートしています。 永続化機能 : データをディスクに保存することで、再起動時にもデータを復元できます。 パブリッシュ/サブスクライブ : メッセージングシステムとしても利用可能です。 分散システムのサポート : 複数のインスタンスでデータを共有できます。 今回のOpen WebUI環境では、Redisを以下の目的で使用します。 セッション管理 : ユーザーセッション情報を保存し、複数のCloud Runインスタンス間で共有します。 WebSocketサポート : リアルタイム通信のためのWebSocket接続を管理します。 SearXNG検索エンジン : 検索結果のキャッシュやレート制限の管理に使用します。 これにより、Open WebUIを水平スケーリング可能な構成で運用することができます。 Redisインスタンスの作成 Redisインスタンスを作成します。 その際、Redisと先ほど作成したVPCを接続します。 Redisのスペックは利用環境に合わせて適宜変更してください。 Redisの作成は他のリソース作成より時間がかかります。 gcloud redis instances create open-webui \ --region=${REGION} \ --tier=basic \ --size=1 \ --redis-version=redis_7_0 \ --connect-mode=DIRECT_PEERING \ --network=${PROJECT_ID} Redisインスタンスの削除 gcloud redis instances delete open-webui \ --region=${REGION} Redisの接続先設定確認 Redisの接続先設定を確認します。 gcloud redis instances describe open-webui \ --region=${REGION} \ --format="value(host)" firwall Cloud RunからMemorystore for RedisにアクセスするためのFirewallルールを作成します。Open WebUIのサービスにはredisというタグがついているため、このタグを使ってFirewallルールを作成します。 gcloud compute firewall-rules create allow-redis-traffic \ --direction=INGRESS \ --priority=1000 \ --network=${PROJECT_ID} \ --action=ALLOW \ --rules=tcp:6379 \ --source-tags=redis 作成したFirewallルールの確認 gcloud compute firewall-rules list --filter="network=${PROJECT_ID}" スケール用open-webui.template.yamlの作成 以下のコマンドで、open-webui-redis.template.yamlを作成します。 cat << 'EOF' >| open-webui-redis.template.yaml apiVersion: serving.knative.dev/v1 kind: Service metadata: name: open-webui annotations: run.googleapis.com/ingress: internal-and-cloud-load-balancing run.googleapis.com/ingress-status: internal-and-cloud-load-balancing spec: template: metadata: annotations: autoscaling.knative.dev/minScale: '0' autoscaling.knative.dev/maxScale: '2' run.googleapis.com/vpc-access-egress: private-ranges-only run.googleapis.com/network-interfaces: '[{"network":"${PROJECT_ID}","subnetwork":"${PROJECT_ID}-open-webui","tags":["redis"]}]' run.googleapis.com/cloudsql-instances: ${PROJECT_ID}:${LOCATION}:open-webui spec: containerConcurrency: 40 timeoutSeconds: 600 serviceAccountName: open-webui@${PROJECT_ID}.iam.gserviceaccount.com containers: - name: open-webui image: ${REGION}-docker.pkg.dev/${PROJECT_ID}/ghcr/open-webui/open-webui@sha256:9b7fb388f0828b597e67c263667214c93592cbc5cac3047be89f5e92bc1085ba ports: - name: http1 containerPort: 8081 env: - name: DEFAULT_USER_ROLE value: user - name: ENABLE_LOGIN_FORM value: 'True' - name: STORAGE_PROVIDER value: gcs - name: GCS_BUCKET_NAME value: ${OPENWEBUI_BUCKET_NAME} - name: ENABLE_OAUTH_SIGNUP value: 'True' - name: OPENID_PROVIDER_URL value: https://accounts.google.com/.well-known/openid-configuration - name: ENABLE_OAUTH_GOOGLE value: 'True' - name: GOOGLE_REDIRECT_URI value: https://${OPEN_WEBUI_DOMAIN}/oauth/google/callback - name: WEBUI_URL value: https://${OPEN_WEBUI_DOMAIN} - name: ENABLE_OLLAMA_API value: 'False' - name: ENABLE_EVALUATION_ARENA_MODELS value: 'False' - name: ENABLE_RAG_WEB_SEARCH value: 'True' - name: RAG_WEB_SEARCH_ENGINE value: "searxng" - name: RAG_WEB_SEARCH_RESULT_COUNT value: '3' - name: RAG_WEB_SEARCH_CONCURRENT_REQUESTS value: '10' - name: SEARXNG_QUERY_URL value: "http://localhost:8080/search?q=<query>" - name: ENABLE_WEBSOCKET_SUPPORT value: 'True' - name: WEBSOCKET_MANAGER value: redis - name: WEBSOCKET_REDIS_URL value: redis://${REDIS_HOST}:6379/0 - name: REDIS_URL value: redis://${REDIS_HOST}:6379/0 # - name: ENABLE_GOOGLE_DRIVE_INTEGRATION # value: 'True' - name: DATABASE_URL valueFrom: secretKeyRef: key: latest name: open_webui_database_url - name: OPENAI_API_KEY valueFrom: secretKeyRef: key: latest name: open_webui_openai_api_key - name: GOOGLE_CLIENT_ID valueFrom: secretKeyRef: key: latest name: open_webui_oauth_client_id - name: GOOGLE_CLIENT_SECRET valueFrom: secretKeyRef: key: latest name: open_webui_oauth_client_secret # - name: GOOGLE_DRIVE_CLIENT_ID # valueFrom: # secretKeyRef: # key: latest # name: open_webui_google_drive_client_id # - name: GOOGLE_DRIVE_API_KEY # valueFrom: # secretKeyRef: # key: latest # name: open_webui_google_drive_api_key # - name: ANTHROPIC_API_KEY # valueFrom: # secretKeyRef: # key: latest # name: open_webui_anthropic_api_key resources: limits: cpu: 2000m memory: 2.0Gi startupProbe: httpGet: path: / port: 8081 initialDelaySeconds: 10 periodSeconds: 3 failureThreshold: 30 - name: searxng image: searxng/searxng@sha256:662971a55feacea2eacd2a8a2f51b3e26b56a73080dd131d079d15d7b991faed env: - name: SEARXNG_HOSTNAME value: 'localhost:8080' - name: SEARXNG_PORT value: '8080' - name: SEARXNG_BIND_ADDRESS value: '0.0.0.0' - name: SEARXNG_STATIC_USE_HASH value: 'true' - name: SEARXNG_LIMITER value: 'false' - name: SEARXNG_IMAGE_PROXY value: 'true' - name: SEARXNG_REDIS_URL value: redis://${REDIS_HOST}:6379/0 resources: limits: cpu: 1000m memory: 1Gi volumeMounts: - name: searxng-config mountPath: /etc/searxng volumes: - name: searxng-config csi: driver: gcsfuse.run.googleapis.com readOnly: false volumeAttributes: bucketName: ${SEARXNG_BUCKET_NAME} EOF スケール用open-webui.yamlの作成 テンプレートファイルから新しいopen-webui.yamlを作成します。 新しいテンプレートファイルではRedisに関する情報が必要なため、環境変数にセットします。 export REDIS_HOST=$(gcloud redis instances describe open-webui --region=${REGION} --format="value(host)") 続けて新しいopen-webui.yamlを作成します。 envsubst < open-webui-redis.template.yaml >| open-webui.yaml スケール対応版Open WebUIのデプロイ 作成したopen-webui.yamlを使用してデプロイします。 gcloud run services replace open-webui.yaml --project=${PROJECT_ID} --region=${REGION} --platform=managed 以上で、スケール対応版Open WebUIのデプロイが完了です。 今回の設定では最大2インスタンスで運用するようになっています。 Open WebUIの設定 ここでは、Open WebUIの設定のうち、比較的複雑な設定を必要とする項目についてその設定方法を詳しく説明します。 Google Driveの設定 Open WebUIにはGoogle Driveからファイルをアップロードする機能があります。 APIを有効化 Google Drive APIとGoogle Picker APIを有効化します。 gcloud services enable \ drive.googleapis.com \ picker.googleapis.com Google Drive用OAuthクライアントの作成 Google Cloud ConsoleでOAuthクライアントを作成します。 基本的な手順は以前説明した OAuthクライアントの作成」 と同様です。 Google Drive用OAuth Client IDをシークレットマネージャーへ登録 OAuth Client画面から、Client IDとClient Secretを取得し、その値でシークレットを作成します。YOUR_OPEN_WEBUI_GOOGLE_DRIVE_CLIENT_ID部分を実際に利用するキーに書き換えます。 echo -n "YOUR_OPEN_WEBUI_GOOGLE_DRIVE_CLIENT_ID" | gcloud secrets create open_webui_google_drive_client_id \ --replication-policy="automatic" \ --data-file=- Google Drive用APIキーを作成 「+認証情報を作成」をクリックしてキーを作成します。 APIの制限で、「Google Picker API」と「Google Drive API」を選択しましょう。 「鍵を表示します」をクリックすることで、Google Drive用APIキーを取得できます。 Google Drive用APIキーをシークレットマネージャーへ登録 取得したAPIキーをシークレットマネージャーへ登録します。 YOUR_OPEN_WEBUI_GOOGLE_DRIVE_API_KEY部分を実際に利用するキーに書き換えます。 echo -n "YOUR_OPEN_WEBUI_GOOGLE_DRIVE_API_KEY" | gcloud secrets create open_webui_google_drive_api_key \ --replication-policy="automatic" \ --data-file=- Google Drive用データアクセス Google Drive用データアクセスを設定します。  データアクセス を参照して設定してください。 今回追加するのは drive.file drive.readonly の2つです。 open-webui.yamlの設定 open-webui.yamlの設定を変更します。 open-webui.yamlにはGoogle Driveに関する設定がコメントアウトされた状態で含まれています。コメントアウトを解除して設定します。 以下の部分のコメントを解除してください。 (略) # - name: ENABLE_GOOGLE_DRIVE_INTEGRATION # value: 'True' (略) # - name: GOOGLE_DRIVE_CLIENT_ID # valueFrom: # secretKeyRef: # key: latest # name: open_webui_google_drive_client_id # - name: GOOGLE_DRIVE_API_KEY # valueFrom: # secretKeyRef: # key: latest # name: open_webui_google_drive_api_key (略) Google Drive対応版Open WebUIのデプロイ 作成したopen-webui.yamlを使用してデプロイします。 gcloud run services replace open-webui.yaml --project=${PROJECT_ID} --region=${REGION} --platform=managed アップロード機能を使ってみる チャット入力欄の「+」からGoogle Driveを選択すると、OAuthの認可画面が表示されます。 許可を認めることで、Google Driveのファイルをアップロードすることができます。 まとめ 長文になりましたが、Open WebUIの実装について様々なパターンを紹介できたのではないでしょうか。 Cloud ArmorやIdentity-Aware Proxy(IAP)によるセキュリティ設定、VPCを活用したスケーリング対応など、Google Cloudの機能を活用することで、Open WebUIをより安全かつ安定的に運用できます。 本記事で解説したCloud ArmorやIdentity-Aware Proxy(IAP)は導入が比較的容易で、高い効果を発揮します。これらの知識は他のシステムにも応用可能です。 また、今回は詳しく触れませんでしたが、Cloud RunにはGPUコンテナオプション(一部リージョンのみのベータ機能)があります。このGPUを活用することで、ollamaをCloud Run内で実行し、Open WebUI上でセキュアなLLM実行環境を構築することも可能です。 Cloud Runは様々なアプリケーションの実行基盤として活用できます。ぜひ本記事を参考に、独自のユースケースでも試してみてください。 The post 【完全ガイド】Google CloudでプライベートなChatGPT「Open WebUI」をセキュアに構築する first appeared on Sqripts .
この連載では、ソフトウェア開発のQAエンジニアとして働き始めた皆様に向けて、私の実体験をもとに「こんなことを知っておけばよかった」という、ちょっとした気づきを共有します。 一緒にソフトウェア開発のQAエンジニアとしての充実したエンジニアライフを築くためのヒントを探っていきましょう。 <QAエンジニアのスタートガイド 記事一覧> ※クリックで開きます 【第1回】充実したQAエンジニアとしてスタートするためのガイドライン 【第2回】「誰のためか」を意識しよう 【第3回】QAエンジニアの第一歩、「ソフトウェアテスト」を知ろう -前編- 【第4回】QAエンジニアの第一歩、「ソフトウェアテスト」を知ろう -後編- 【第5回】コミュニケーションが鍵を握る 【第6回】学ぶ姿勢を持ち続けよう 【第7回】良い働き方を継続するためのマインドセット ソフトウェアテストを背景としたQAエンジニアはその専門性として、批判的思考を持っています。 これらのスキルがテストにおいて重要であることはいうまでもありません。 一方で、アジャイル開発の現場をはじめとするソフトウェア開発の現場では、チームワークが不可欠です。 そういった状況の中で、批判的思考の一辺倒ではうまくいかなくなることがあります。 また、テストを担うQAエンジニアは、納期や品質に対するプレッシャーから、様々な精神的な問題に直面してしまうことがあります。 これらの課題を乗り越えるには「マインドセット」が重要です。 本稿では、こういった状況を乗り越えるために、私が大切にしている「マインドセット」について解説いたします。 他者ではなく、自分を変えるという気持ち 誰かを変えたいという欲求にかられるQA QAエンジニアは品質保証のために欠陥や改善点を見つけることが求められる職種であり、常に批判的思考・視点を持つことが重要です。 こういった批判的な思考を続けるうちに、QAエンジニアは「周りの人を変えたい」「チームを変えたい」という考えにいたることがあります。 しかし、これらの欲求はほとんどの場合満たされません。 なぜなら、他者を変えるということは自分自身ではコントロールできないからです。 その結果、様々なフラストレーションを抱えてしまったり、時には対立を生む可能性があります。 こうした「誰かを変えたいという」考え方を持って苦しんでいるQAエンジニアによく出会いますし、私自身もその苦しみに悩まされることがあります。 自分ごとで捉える そこで考えていただきたいのは「自分が変わる」あるいは「自分ごとで捉える」ということです。 仮に「相手の問題がある」と思ってしまっても、一度自分自身の考え方・捉え方・思い込みによって「問題」だと捉えていないかを自問自答してみることをおすすめします。 悪感情を抱くことは、もしかしたら自分の捉え方やバイアスが原因かもしれません。 重要なことは、「自分がコントロールできる問題に変換する」ということです。 相手がどのような人であろうが、どのような行動であろうが、他者を変えることよりも自分が変わることの方がはるかに簡単なのです。 チームやプロジェクト全体の課題を考える際にも、「誰かのせいでこうなった」と捉えるのもおすすめしません。 むしろ自分自身の責任として捉えて、自分のコントロールできる範囲で、小さく対処していくことも必要になります。 こういった視点で行動することが、問題解決と自己成長につながると考えています。 これらのマインドセットのあり方について「自分の小さな「箱」から脱出する方法」という書籍が参考になります。 この本では、他者を変えようとするのではなく、自分自身の考え方や行動を変えることで、より良い人間関係を築く方法が解説されています。 自分の小さな「箱」から脱出する方法 (アービンジャー・インスティチュート 著/金森 重樹 監/冨永 星 訳/大和書房)  また、NLPという考え方も自分のマインドセットを適切に保つことに役に立ちます。 NLPは独特の単語が出てきて難しい部分がありますので、「マンガでやさしくわかるNLP」といった初学者向けの書籍から入ることをおすすめします。 マンガでやさしくわかるNLP (山崎 啓支 著/サノ マリナ 作画/JMAM) チームに合わせて仕事をする 個人の仕事を充実させる 社会人、あるいはQAエンジニアとして働くなかで、効率的な働き方や個人のスキルを高めることはとても重要です。 そんな中で、例えば効率的なスケジュールの組み方を実践したくなることもあると思います。 「朝には重要な仕事をする」などです。 こういった形で自分の仕事術や仕事のやり方を確立することは生産性の向上や自己肯定感の向上に繋がります。 チームの仕事を優先する しかし、ソフトウェア開発はチームで行うということを忘れてはいけません。チームのミーティングが入ったり、作業が入ったり、様々な事情で自分の仕事術が妨げられてしまうこともあると思います。 ここで重要なのは、自分の生産性や自分のやり方だけにこだわるのでなく、チーム全体のことやチームのやり方を尊重するということです。 私自身、自分のやり方やタイムスケジュールにこだわって仕事をしていた時期もありました。 しかしながら、周りの意見に耳を傾け、建設的な議論を行い、合意形成を図ることは自分のタスクをこなすことよりもチームの利益につながることに気がつきました。 時には自分の意見ではなく チーム全体の利益を優先したり、自分の都合を変えて全体のイベントを優先することが必要です。 自分の仕事へのこだわりから脱してチームの利益のことを考えて仕事をすることは、自分自身の達成感に繋がったり、チームでしか解決できないような難しい課題を解決することができるのではないかと考えています。 尊敬と感謝を能動的に持つ 尊敬の気持ちを持つ QAエンジニアとして、様々な人と関わるのではないかと思います。 職場の同僚・上司・部下・顧客・様々なステークホルダーです。 そして、その関係するすべての人に対して、尊敬の念を持つということはとてもいいことです。 「自分はこんなに尊敬している人たちと働いてるんだ」と思いながら働くことは精神衛生上もいい効果があると実感しています。 周囲の人たちのいいところをできるだけたくさん感じ・探して・言語化し、それに対して尊敬してください。これは、エンジニアのマインドにいい影響を及ぼすと考えています。 能動的に感謝する 周りに感謝の気持ちを持つことは、自分自身のマインドにいい影響を与えると考えています。 感謝して、それを伝えることにデメリットは何もありません。 私がおすすめするプラクティスは、感謝にかかわる日記やメモを毎日書くということです。 自分が受動的に感じた「ありがとう」の気持ちを書くのもいいですが、むしろ能動的に感謝の気持ちや「ありがとう」と思った気持ちを探すということが大切です。 そしてそれを書き起こすことも重要です。 これらのプラクティスによって、毎日接する人への気持ちや心持ちが好転し、よりよいマインドセットで働けると考えています。 さいごに この記事では、QAエンジニアが直面する課題を乗り越えるためのマインドセットについて解説しました。他者を変えようとするのではなく、自分自身の考え方や行動を変えること、チーム全体の利益を優先すること、そして周囲への尊敬と感謝の気持ちを持つことが重要です。 これらのマインドセットを実践することで、QAエンジニアはより良い人間関係を築き、チームでの協働を円滑に進め、難しい課題を克服し、自己成長を達成できるでしょう。 皆様が、この記事で紹介したマインドセットを日々の業務に活かし、より充実したキャリアを築かれることを願っています。 【連載】QAエンジニアのスタートガイド 記事一覧 【第1回】充実したQAエンジニアとしてスタートするためのガイドライン 【第2回】「誰のためか」を意識しよう 【第3回】QAエンジニアの第一歩、「ソフトウェアテスト」を知ろう -前編- 【第4回】QAエンジニアの第一歩、「ソフトウェアテスト」を知ろう -後編- 【第5回】コミュニケーションが鍵を握る 【第6回】学ぶ姿勢を持ち続けよう 【第7回】良い働き方を継続するためのマインドセット The post 【第7回】良い働き方を継続するためのマインドセット|QAエンジニアのスタートガイド first appeared on Sqripts .
こんにちは。まーくー&くまねこです。 ゆるっとシリーズ第8話です。 前回 から引き続き、まーくーの学び直し回です! 書籍「基本から学ぶソフトウェアテスト」 を読んで、現在でも活かせる内容があるのか?、まーくー&くまねこの会話形式でお話させていただきます。 最後まで楽しんで読んでいただければ幸いです! ゆるっと♪Blogシリーズの記事一覧はこちら(クリックで開きます) 第1話 ゆるっと♪ファームウェアテストよもやま話 第2話 ゆるっと♪学び直し!アジャイルソフトウェア開発技術者検定試験 第3話 ゆるっと♪どうやってる?探索的テストの世界! 第4話 ゆるっと♪学び直し![書籍]基本から学ぶソフトウェアテスト! 第5話 ゆるっと♪学び直し![書籍] 基本から学ぶソフトウェアテスト!②     ~あきらめてしまわないでね 難しさ感じても~ 第6話 ゆるっと♪学び直し![書籍] 基本から学ぶソフトウェアテスト!➂     ~きっとそこに信じていた、バグ管理の姿があるはずさ♪~ 第7話 ゆるっと♪学び直し![書籍] 基本から学ぶソフトウェアテスト!④     ~君がおしえてくれたテストの名前は~ 第8話 ゆるっと♪学び直し![書籍] 基本から学ぶソフトウェアテスト!⑤     ~つかまえて デバイスたちの歌を~ 自己紹介 まーくー QA業界経験2x年のエンジニア。 年齢からくる(?)気力、体力の衰え、体重の増加を感じつつ、お気に入りアーティストのMCを完コピすることで奮い立たせる今日この頃。自宅から徒歩3分のところにあるチョ○○ップ入会すら躊躇ってしまう、一歩踏み出せない自分がいます・・・ くまねこ QA業界経験1x年のエンジニア。 最近のマイブームはペットボトルをどこまで縦にまっすぐ立てて飲めるかトライすること。 ノドに勢いよく流れ込む液体に身を任せ、テストの日々を泳いでいます。 イラストby くまねこ 今日も二人のやりとりをお楽しみください! 2025年も!学び直しの旅は続く… (ズッタンズズタン♪ズズタタズッタン♪)Wow! (あっ、まーくーさんだ。何やらリズムに乗ってゴキゲンだ…! どうしよう。話しかけてみようかな…) まーくーさん! おつねこです~! おつねこ! 私は最近こんな風に思っている。 ダイエットっていうのは数字にしばっ、しばられないことなんだ。そして、自分に与えられた全ての食物の中で、一体何が食べたくて、何が食べたくないのか、見分ける力を持つことが大事なんだって。 Oh…とにかく好きなものを食べようってことですか! どんな体重でもそれがベスト! 今がベスト! (まーくーさん、ちょっと嚙んでたけど…かっこいい! しびれるぅ~!) そう! ベストが毎日続けばいつでもベスト! Yeah~! \ / オゥーライ! では、今日も学びなおしていこうかぁ~ ? Yeah~! \ /(今日は書籍に関する前振りなしでいきなり始まった~!) 第8章 プリンタ(およびその他デバイス)のテスト を読んで① 前回 は7章まで進み、今回は8章ですね…。「プリンタ(およびその他デバイス)のテスト」ですって。プリンタって聞くとまーくーさんと同じ現場だった時のことを思い出します。 あっのっころっは~♪ Wow!…で、どんなことが書いてあるんだい? (今日はテンション高い&展開が早い~!)そうですね…ふむふむふむふむ。 大きく分類すると以下のような記載になっていますね。  ・デバイス構成テスト  ・プリンタのテスト  ・プリンタの内部処理  ・プリンタのテスト戦略  ・プリンタのテスト項目  ・テスト自動化のヒント なので、この中からプリンタにしばっ、しばられない項目から汎用的に学べそうな部分をピックアップしていくと良いと思います。(意図的に噛んでみたけど…気づくかなぁ?) そうだね。構成テストというくくりで言えば、私たちも行っている他端末検証とかにも応用できる知見が得られそうだね。「プリンタの内部処理」は分野が限定されすぎるから、今回は無しにしても良いかもね。ひとまず前半の2つをピックアップしてみよう。 「デバイス構成テスト」 と 「プリンタのテスト」 についてですね。Yeah~ッサー! \ /(気づかなかった~!) まずは「デバイス構成テスト」について。 ここではテスト対象を動作させる環境面のことが書かれています。テスト対象と互換性のあるプリンタの用意をするかどうか、PCのハードウェアやOSのバージョンなども記載がありますね。 なるほど。テストの大前提ではあるけど、テストを行うための環境の洗い出しやバージョン情報などは最初にしっかりと確認し、ステークホルダーと合意して進めていけるようにしたいね。 本文にもあるけど構成の組み合わせは「ブラックホール」のように多様なデバイスを飲み込んでしまって複雑になりすぎたり、せっかくテストが順調に進んでいたのに、実はテスト対象プログラムのバージョンが違ってました…とかだと目も当てられないしね。 ですよね…そこまで大きなロスをしたことはないですが、プロジェクト終盤で判明してしまった時のことを考えるといろいろな意味で背筋が凍りますね。((( ))) 続きまして、「プリンタのテスト」について。本書発行当時はプリンタは1000種類以上あり、その中からプリンタと連携するPC(OS)のシェア、プリンタのシェアなどを考慮して動作保証範囲を検討する必要がある旨が書かれています。 当時はそれぐらいの種類だったんだね。現在はプリンタの種類もそうだけど機能も高度化しているから、その辺も考慮に入れてデバイス構成を検討すると良いと思う。もっとも当時よりデバイス間の互換性が保たれていることも多いだろうから、思ったよりうまく整理できるかもしれないね。 第8章 プリンタ(およびその他デバイス)のテスト を読んで② では8章の後半も進めていこう。「プリンタのテスト戦略」について。ここは私が… 「テスト戦略」として大切なことは一般的なところから特殊なところへ進めていく、というところが参考になると思う。色々な種類のプリンタがある中で、ひとつ目の機種ではプリンタに依存しない不具合を見つけ、次のプリンタではプリンタとして共通の不具合を見つけていく…というところ。これを行うことで同じテストをプリンタ種類毎に全て実施しなくても良くなるから良いよね。 そうですね。この考え方はプリンタやデバイスのテストだけでなく、アプリのテストでも活用できそうです。まーくーさんはテストを進めていく上でのアイデアって他にどのようなものがあると思いますか? 戦略と言うほど大がかりなことではないけど…(目を細めながら遠くを見つめる)、 派生開発とかならテスト実行の順番を考えるとき、過去の傾向から不具合が多かった機能や、プログラムの修正に時間がかかった不具合を検出した機能から先にテストを進められるようにスケジュールするかな。そうすれば不具合が発生しても早めに対処することが可能となって、終盤に重大不具合が発生してアップアップするなんて事態を回避できるよね。 なるほど。テストチームだけでなく、開発チームの作業負荷も考慮して進めることができれば、より効率よく安心してプロジェクト終了へ進めていくことができますね! 次は「テスト項目」についてだけど…現在では一般的になっている内容かと思うので今回は割愛させてもらおうかな。 了解しました ゞそしたら最後は「テスト自動化のヒント」ですね。自動化っていうと今でもテーマとしては重要かと思います。ふむふむふむふむ。やはり当時から以下のようなポイントで語られていますね。 (プリンタテストの自動化に関する四つのリスク※要約)  ・すべてを自動化しようとしないこと  ・合否判定が正しくできない項目は実施しないこと  ・印刷に関連するバグを見逃さないように注意すること  ・同じ自動テストだけを実施し続けないこと なるほど。ここでも自動化する前にどういった範囲を自動化していくのか、ツールの特性でできること/できないことも調査しながら適切に自動化ができるようにしていきたいところだよね。 はい。合否判定のところも、もし実際の印刷まで自動化するのであれば出力された紙の目視確認も必要になると思います。その際、どの自動化テストケースで印刷したのかわかるようなデータ作成をする必要もありますね。他にも紙出力ではなくファイル出力したデータと期待値ファイルと比較して合否判定するっていうのも良いですよね! うん。あと4つ目の同じ自動テストを続けないこと、のところはまさに殺虫剤のパラドックスと同じだね。既存の動作に問題ないことを確認するのは良いけれど、テスト対象の成熟度に応じて自動テストの量や内容も臨機応変に対応していかないといけないよね。 変化を恐れず常に前を向いて前進する、まーくーさんのようにですね! 最初はトライ&エラーの時間が少なからず発生すると思うけど、「テスト自動化のヒント」で学べることを活かせば自動化の成功率向上と安定した運用ができそうだね。 トライ! トライ! トライ! Yeah~! We can do it! \ / まとめ 第8章はこれぐらいかな。 次回のまーくー&くまねこは、 まーくー: JSTQB ALTM試験、うっかり受かっちった! 次はTA? (仮) くまねこ: JSTQB ALTM試験、ではないものを受け、あと1問で x  2 (苦) の2本でーす! 最後まで読んで頂き、ありがとうございました! よろしければ、過去のゆるっと♪シリーズもお楽しみください! 次回もまた見てねー ノシ 三 ノシ 三 ゆるっと♪シリーズ 第1話 ゆるっと♪ファームウェアテストよもやま話 第2話 ゆるっと♪学び直し!アジャイルソフトウェア開発技術者検定試験 第3話 ゆるっと♪どうやってる?探索的テストの世界! 第4話 ゆるっと♪学び直し! [書籍]基本から学ぶソフトウェアテスト! 第5話 ゆるっと♪学び直し![書籍] 基本から学ぶソフトウェアテスト!②     ~あきらめてしまわないでね 難しさ感じても~ 第6話 ゆるっと♪学び直し![書籍] 基本から学ぶソフトウェアテスト!➂     ~きっとそこに信じていた、バグ管理の姿があるはずさ♪~ 第7話 ゆるっと♪学び直し![書籍] 基本から学ぶソフトウェアテスト!④     ~君がおしえてくれたテストの名前は~ 第8話 ゆるっと♪学び直し![書籍] 基本から学ぶソフトウェアテスト!⑤     ~つかまえて デバイスたちの歌を~ The post ゆるっと♪学び直し![書籍] 基本から学ぶソフトウェアテスト!⑤~つかまえて デバイスたちの歌を~ first appeared on Sqripts .
みなさんこんにちは。 「ソフトウェアレビューをエンジニアリングっぽく捉える会」の”きたのしろくま”です。 前回 に引き続き、「#5レビューの終わり方~レビュー評価・ふりかえり(2/2)」をお伝えします。 【第3回】[#5]レビューの終わり方~レビュー評価・ふりかえり(1/2)|ソフトウェアレビューをエンジ... みなさんこんにちは。「ソフトウェアレビューをエンジニアリングっぽく捉える会」の”きたのしろくま”です。次の話題は「#5レビューの終わり方~レビュー評価・ふりかえり」です。前回うれっしーさんが書いてくれた「#1レビューとは?」の次に#5・・・かなり飛んだテ...  続きを読む  Sqripts <ソフトウェアレビューをエンジニアリングっぽく語ってみる 記事一覧> ※クリックで開きます 【第1回】[#0]イントロダクション 【第2回】[#1]レビューとは? 【第3回】[#5]レビューの終わり方~レビュー評価・ふりかえり(1/2) 打開策2:レビュー指摘事項の分類/評価の実施 打開策1と同様、レビュー終了直後に、レビューにより検出された指摘事項をいくつかの視点で分類し、評価します。 分類/評価の方法にはいろいろありますが、ここでは2つの事例(視点)を紹介します。 1つ目の視点は、このフェーズで作り込まれた欠陥・不備なのか、他のフェーズで作り込まれたものなのかの分類です。理想的なのは、このフェーズで作り込まれた欠陥・不備を同じフェーズのレビューで見つけ出すことです。(図2の上)これが実現できなければ、プロジェクトが混乱する原因となってしまいます。(図2の下) よって、他のフェーズで作り込まれた欠陥・不備があれば、作り込まれたフェーズのレビューを見直す必要があることに気づきます。 図2:フェーズで作りこんだ欠陥・不備をどこで見つけるか? 2つ目の視点は、レビュー目的の達成度と指摘事項の効果です。 レビューの“効果”を何で示すのかについてもいろいろ考えられますが、今回はその一例として「仮に今回のレビューでこの欠陥・不備を見逃した場合、あとでどの程度悪い影響が出るものかの度合い」をご紹介します。 あとになって発生する悪い影響を正確に把握することはできない場合も多いので、下記のように進めます。 少なくとも自分たちの開発の進め方から想定すると、この欠陥・不備はこの先どのフェーズで見つかる可能性が高いか、見つかった時の対処にどのくらい期間、工数を費やして対処することになるのかを(ザックリでもOK)見積もります。その際にプランニングポーカーを使うなどの工夫が可能です。 見積結果を活用して3つの枠:効果大、効果中、効果小に割り振ってマッピングします。 さらに、それぞれの指摘事項がどのような観点にあたるのか?を明らかにして、効果大中小の観点分布を把握します。(以上、図3) 図3:レビュー指摘事項の分類/評価の流れ(例) 以上の結果を見ながら、どの観点の指摘事項がどの程度見つかったのか?や、効果大・中・小の指摘数、観点の偏りはないか?、今回のレビュー目的は達成できたといえるのか?、レビューにおける費用対効果はいかほどか?、等を分析、評価します。(図4) 図4:レビュー指摘事項評価の観点例 最初は効果大、中、小をどのように分けたらよいのか、それぞれの指摘事項がどのような観点(意味がある)と言えるのか、などメンバーの認識が合わずに難航するかもしれませんが、議論を重ねて一度出来上がるとそれを再利用しながら短い時間で分類/評価を進められるようになります。 完成したレビュー指摘の効果分類図に表現された内容が、対象となるソフトウェアの品質に対するチームの価値観を表すことになります。これがマネジメント、開発メンバー、QAメンバーの共通の価値観になり、あらゆるタスクを進める上で注視して開発を進められるようになっていきます。それがさまざまな役割のメンバーが相互に協力して同じ目的達成を目指すうえで協調関係を築く土台になります。 ここで間違ってほしくないのは、完成した図が大事なだけではなく、それを創りあげる過程=チームメンバーによる対話や議論がなにより重要である点です。そして、一度完成したら終わりではなく、さまざまなレビューやテストの結果を同様に分類/評価しながら何度も見直し、更新していくことが本質である点です。 なお、この打開策2は 打開策1:「レビューふりかえり」 の前に実施し、その結果を踏まえてふりかえることをおススメします。 この組合せにすることで、レビューの実施過程+実施結果の両面を解像度高くふりかえることが可能になるため効果的です。 おわりに ~忙しくてそんなことしている時間はないよ、と言っていた当時の私に 以上の提案をすると「レビュー終了直後に指摘事項を分類/評価したり、ふりかえりを実施するなんて、、、忙しいからそんな時間はないよ。」という声をよく聞きます。 私も当時はそう思っていた一人なので、この先は当時の私に伝える/問いかける内容です。 当時のしろくまさんへ どうしてそんなに毎日忙しいのか、現状で自分が何にどのくらい時間を割かれているのかちゃんと把握しているかな?例えば、計画された作業を実施したものの、あとで仕損じていたことがわかり、作業をやり直したり、成果物を手直ししたりする工数って作業全体の中にどのくらいあるんだろう? それを把握することも大事なふりかえりの一種なんだけど、それも忙しいからできないって言うかもしれないね。 自分(たち)の作業や成果物をふりかえって、仕事の仕方をもっとより良く変えない、良くないところを直さないから、いつまで経っても仕損じて手戻り(再作業や非効率状態)が減らず、その結果忙しさが解消されない、さらに忙しいのを言い訳に本当に必要な作業を端折ったりしてまた手戻りを増やしている、なんてことはないかな? 実は、忙しいからふりかえりなんてできない、のではなく、ふりかえらないから忙しくなってしまう、ということなんじゃないのかな? 「忙しい」が結局は現状維持・現状肯定のための言い訳にならないように、そして意図せず自らの成長を阻害することにならないように、しろくまさんの今後の健闘を祈ります。疑問点などあれば遠慮なく教えてね。他者のせいにしていても解決しないからさ。一緒によりよい世界を自ら創り上げていこう! この記事を担当したメンバー きたのしろくま(安達 賢二/ @kitanosirokuma ) 自律・自己組織化を促進する価値共創プログラムSaPIDをベースに三方よしとなる新しい価値を一緒に考えて創る「共創ファシリテーター」として活動中。 https://www.softwarequasol.com/ 【連載】ソフトウェアレビューをエンジニアリングっぽく語ってみる|記事一覧 【第1回】[#0]イントロダクション 【第2回】[#1]レビューとは? 【第3回】[#5]レビューの終わり方~レビュー評価・ふりかえり(1/2) The post 【第4回】[#5]レビューの終わり方~レビュー評価・ふりかえり(2/2)|ソフトウェアレビューをエンジニアリングっぽく語ってみる first appeared on Sqripts .
こんにちは。執筆者のおすしです。 ChatGPTが世にリリースされてから、私には続けてきた趣味があります。 変わった料理のレシピをAIに提案してもらい、作って食べてみること です。 数あるおかしなレシピの中からおいしかった3つを紹介します。 ルール 次のような単語を入れてAIにレシピ作成を依頼する。 「奇抜な」「前衛的な」「いまだかつてない」「狂った」 無難なレシピを提案してきたら、「より奇抜なものをお願いします」のように指示してやり直してもらう。 提案したレシピ名や材料の組み合わせを検索して、同じレシピがヒットしなかったらOK。ヒットしたら手順2を繰り返す。 食べても安全かチェックしてから作成に入る。 AIは食品以外を材料にしたり、危険な食べ方を提案してしまうことがあります。必ず安全を確かめてください。 残さず食べる。 レシピ①「かんぴょうと餃子のカルパッチョ」 AIとのやり取り まずは普通に依頼した場合の結果です。しけてきたかんぴょうの残りを使い切りたかったので、必ず使ってほしいと依頼します。 無難なレシピを提案されました。「前衛的な」を指示に入れてみます。 「かんぴょう 餃子 カルパッチョ」で検索しましたが、似たような料理はヒットしませんでした。 ※2025年現在は「餃子のカルパッチョ」というレシピがヒットします。 レシピ 【かんぴょうと餃子のカルパッチョ】 【材料】 餃子 6個 白菜 4枚 かんぴょう 20g ベーコン 2枚 スプラウト 適量 レモン 1/2個 オリーブオイル 大さじ2 塩、胡椒 適量 【作り方】 餃子を沸騰した湯で1分程茹でます。 冷水で餃子を冷やし、食べやすい大きさに切ります。 白菜を塩茹でし、水に取っておきます。 かんぴょうを水で戻して、茹でます。 ベーコンをフライパンでカリカリに焼きます。 レモンの汁、オリーブオイル、塩、胡椒を混ぜ合わせ、ドレッシングを作ります。 盛り付け皿に3と2を乗せ、5と4を添えます。 ドレッシングをかけ、スプラウトを散らして完成です。 和のかんぴょうと洋のカルパッチョが融合した、前衛的な一品となります。おしゃれなパーティーやディナーにもぴったりです。 作成 ゆでた餃子を冷水で冷やすのか…と驚きながら調理しました。 餃子は切らない方が見栄えが良いので作り方の手順2の後半は無視します。「おしゃれなパーティーやディナーにもぴったりです」とあるのでおしゃれに盛りつけます。しかし、白菜を下に敷くと餃子が転がって盛り付けが難しい。白菜はお浸しとして食べてしまいました。時にはレシピを無視するのも楽しく続けるコツです。 実食 とてもおしゃれな見た目です。確かにパーティにぴったりかもしれません。 おいしくいただきました。 冷やした餃子の皮のもちもち感、添えたかんぴょうの歯ごたえ、上に載ったベーコンのカリカリ感。面白い食感でした。上に散らかしたスプラウト(カイワレ大根)の辛味がアクセントになって、食べ続けても飽きません。レモンのおかげで後味もさわやかでした。お酒のつまみにぴったりだと思いました。 この料理がおいしかったとAIに伝えました。かんぴょうが好きだとインプットされたらしく、しばらく提案するレシピにかんぴょうが入るようになりました。 レシピ②「うどんティラミス」 AIとのやり取り 「うどん ティラミス」で検索するとうどんのティラミス風がヒットしました。しかしながら、作り方や材料を比較すると全く違う料理のようです。やや驚きに欠ける気もしますが、同じものはないのでOKとします。 レシピ 「うどんティラミス」 うどんをデザートに大胆にアレンジし、ティラミス風に仕上げた一品です。もちもちのうどんが、意外とマスカルポーネとコーヒー風味に合います! 【材料】 うどん(冷凍うどんを推奨):1玉 マスカルポーネチーズ:100g 生クリーム:100ml 砂糖:大さじ2 インスタントコーヒー:小さじ1(湯大さじ2で溶かして冷ましておく) ココアパウダー:適量 【作り方】 冷凍うどんを茹でて冷水でしっかり締め、水気を切ります。1~2cmほどの長さに切り、ティラミスのスポンジ部分の代わりにします。 ボウルにマスカルポーネチーズと砂糖を入れて混ぜ、生クリームを加え、ふわっとするまで泡立ててクリームを作ります。 切ったうどんをコーヒー液にさっとくぐらせ、グラスや容器に敷き詰めます。 3の上にマスカルポーネクリームを重ね、再度コーヒーにくぐらせたうどんを敷き詰めて、もう一層クリームをのせます。 最後にココアパウダーをふりかけ、冷蔵庫で1時間ほど冷やして完成です。 うどんのもちもち食感がティラミスのクリーミーさと相まって、新しいスイーツの食感と風味が楽しめます。まさかうどんがデザートになるとは思わない驚きの一品です。ぜひ話のネタに試してみてください! 作成 うどんという中身の詰まったものをスポンジ部分の代わりにするのですね。「ティラミスのクリーミーさ」とあるけどスポンジ部分も含めてティラミスなのでは?ティラミスってどういう意味なんでしょう。ちょうど開いていたGoogleのAI(Gemini)に聞いてみます。 【語源】Tira(引っ張る、mi(私、 su(上に。 「私を上に引っ張り上げて」が転じて「私を元気づけて」という意味になりました。 また、「私を天国に連れて行って」という意味もあります。 強烈な味で天に召されるのかもしれない。材料からそこまでおかしな味にならないとは思いますが…。 実食 上から見ると完全にティラミスです。 横から見るとうどんが…。クリームにうどん。複雑な気持ちになりますが、目を閉じて食べてみます。 意外にもおいしくいただきました。 うどんの弾力が大福などのモチ系のお菓子と似ています。食べ始めはうどんが甘いことに違和感がありましたが、慣れたらおいしく感じます。うどんって甘い味も合うんですね。 レシピ③「鹿胸肉のカーボン化ロースト ブラックダイヤモンド仕立て」 AIとのやり取り 鹿肉の塊が手に入りました。私の大好きな食材です。早速レシピを提案してもらいます。 鹿肉とチョコレート、ベリーソースを使ったものはすでにある料理でした。私も食べたことがあります。奇抜さが足りないのでやり直してもらいます。 いまだかつてなく危険なにおいのする料理名とサブタイトルです。念のため「鹿肉 ロースト 炭」「鹿肉 カーボン」「鹿肉 ブラックダイヤモンド」で検索しましたが同じ料理はヒットしませんでした。 プロンプトは胸肉と書いてしまいましたが、手元にあるのは鹿の肩肉でした。気にせず調理に入ります。 レシピ 「鹿胸肉のカーボン化ロースト 〜ブラックダイヤモンド仕立て〜」 (見た目は真っ黒、食べるとジューシー!炭と科学を駆使した革新的な一皿) コンセプト 鹿肉を「完全に黒焦げ」に見せつつ、中は驚くほどジューシーで旨味たっぷり。 活性炭や黒ニンニクを使い、炭化したような見た目ながら、旨味を凝縮させる新感覚の料理。 【材料】 (2人分) 鹿胸肉(ブロック):300g 食用活性炭パウダー:大さじ1(※食品用を使用) 黒ニンニク(ペースト状にする):3片 バルサミコ酢:大さじ2 黒蜜:大さじ1 カカオパウダー(無糖):小さじ1 オリーブオイル:大さじ1 塩・黒胡椒:適量 【作り方】 漬け込み(ブラックマリネード) 黒ニンニク、バルサミコ酢、黒蜜、カカオパウダーを混ぜてペーストを作る。 鹿胸肉に塩・黒胡椒をふり、ペーストをたっぷり塗り込む。 1時間以上漬け込み、冷蔵庫で休ませる。 カーボンコーティング(完全黒化) 活性炭パウダーをふるい、マリネした鹿肉全体をまぶす。(しっかり真っ黒に!) 表面が乾燥しすぎないよう、オリーブオイルを軽く塗る。 低温調理(ジューシーに仕上げる) 120℃のオーブンでじっくり40分焼く。(中はピンクをキープ) 焼き上がったらホイルに包み、10分ほど休ませる。 仕上げ(カーボンローストの完成) 表面が完全に黒くなっているはず!だが、中はレアでジューシー。 薄くスライスし、岩塩を添えて提供。 驚きのポイント 見た目は「真っ黒の炭」、でも食べると柔らかくて旨い! 活性炭の効果で胃腸に優しく、デトックス効果もあるヘルシー料理! 黒ニンニク&バルサミコの甘酸っぱさが鹿肉の旨味を爆発させる! 作成 AIのモデルが変わったのでしょうか。以前よりも絵文字と「!」が多く「驚きのポイント」も炎で挟むというハイテンションぶりです。やや不安になりましたが、「食用活性炭パウダー:大さじ1(※食品用を使用)」と注意書きがあります。安全性を考える冷静さは残っているようです。 鹿肉の生食は危険な場合があります。温度計で中心温度を確認してしっかり低温調理をします。味はともかく、安全性には必ず配慮しましょう。危険なものは残さず食べることができません。 食べ物と思えない黒い塊ができました。期待と不安で胸が高鳴ります。 実食 切ってみました。程よく火が通った美しいお肉が見えます。 とてもおいしくいただきました。 しっとり柔らかいお肉に、黒ニンニクとバルサミコ酢の風味がしっかり染み込んでいます。赤ワインに合いそうな味です。 炭の味がするのかな、と心配でしたが外側の炭は特に味がしません。切る前の見た目と味のギャップがおもしろい料理でした。 まとめ 今まで複数のレシピを提案してもらいましたが、プロンプトに入れる形容詞や副詞によって傾向があるようです。 「驚くような」「奇抜な」:既存のレシピで、ちょっと変わっているなと感じるものが多いです。(例:お肉にチョコレートソースなど) 「前衛的な」:既存のレシピを食材の変更でアレンジする傾向があります。また、比較的おしゃれなレシピが多いです。 「いまだかつてない」:調理法から変わったものが多いです。 「激しい」「狂った」:調理法は普通ですが、量、色、味で狂気を表現するものが多いです。(例:大量の食材を積み上げる、真っ赤にする、大量の唐辛子で激辛にするなど。)また、レシピの説明で中二病のような表現を使うようになります。 毎日の献立に悩んだり、同じご飯が続いて飽きることがあると思います。上記のような言葉を入れて、ちょっと変わったレシピをAIに提案してもらうのはいかがでしょうか。 作成の際はレシピの安全確認を忘れないように気を付けてください! The post AIに前衛的な料理のレシピを提案してもらった(写真と実食あり!) first appeared on Sqripts .
みなさんこんにちは。 「ソフトウェアレビューをエンジニアリングっぽく捉える会」 の”きたのしろくま”です。 次の話題は「#5レビューの終わり方~レビュー評価・ふりかえり」です。 前回うれっしーさんが書いてくれた「 #1レビューとは? 」の次に#5・・・かなり飛んだテーマではありますが、 準備できた順に投稿していくと宣言 して始めた連載ですのでご容赦ください。 (すべてのテーマ投稿が出揃った際にこの連載の価値がわかるはず・・・です) 今回のテーマは少し長くなりますので2回に分けてお伝えします。 今回は「#5レビューの終わり方~レビュー評価・ふりかえり(1/2)」です。 レビューのよりよい終わり方を一緒に考える機会になるとうれしいです。ではスタートです! <ソフトウェアレビューをエンジニアリングっぽく語ってみる 記事一覧> ※クリックで開きます 【第1回】[#0]イントロダクション 【第2回】[#1]レビューとは? レビューってどうしたら終わる? みなさんのレビューはどうなれば終了しますか? 例えば、 ・予定していた時間が来たら終了~まだ途中だけど、残りの内容でこれまでの指摘と同様の箇所があれば同じように直しておいてね(ハート) ・レビューアから指摘事項が出揃ったら/それを作成者に伝えたら終了 ・声の大きな人が「終わり」と言ったら終了 ・正式なレビュー記録が承認されたら終了(QMS的) など、いろいろありそうです。 これは「レビューの終了基準」の話題ですが、(「開始基準」と同様)特に決まりがないまま、いや「慣習になっている暗黙のやり方」に従って運営している、という状態が意外と多い気がしています。 ”やりっぱなしレビュー”の影響 先ほど示した4例ですが、どれをとっても「レビュー計画」や「レビューの実施方法」「レビュー結果」の良し悪しをふりかえらず、集まった人たちでレビュー指摘さえ出せば、あるいはそれを申し渡したら終わり、という状態になっている可能性があります。 この状態を「やりっぱなしレビュー」と呼ぶことにします。 やりっぱなしレビューがもたらす主な影響は以下の通りです。 ・レビューに費やす工数や時間が最小限で済むので、実務に早めに戻ることができる。(これは良い影響) ・レビューで新たな経験や気づきを獲得した特定の個人にのみ、その分の学習効果が得られる。  しかし、あくまでも個人の話であり、かつレビュー能力の向上は非常に小さく、組織としてのレビュー能力向上には長い年月が必要になる。 ※有識者がいないとレビュー結果が伴わない状態はこのように作られる ・(一度のレビューで各自が獲得するノウハウはそう多くはないため)次回以降のレビューでも同じような結果になることを繰り返す可能性が高い。 例1:検出すべき欠陥や不備を見逃しがちなレビューになっているチームは、以降も同様に見逃す結果になりやすい。 例2:集合レビュー時に話題が横道に逸れてもそのまま放置される(ムダな時間、工数が多くなる)運営になっているチームは、以降も同じ状態になりやすい。 以上のように、メリットよりもデメリットが目立つのが実態だと思います。 さらに、業務やプロジェクトのメンバーは、自分が割り当てられているタスクを遅延なく進めることでさえも簡単ではなく、多忙な中で依頼されたレビューを何とかして行っている場合も多いと推察します。 多忙な中、何とかやりくりしてレビューを実施しているのに、その効果が実感できないと、レビューに対するモチベーションが低下し、前向きにレビューが実施できなくなってしまいます。 このような「やりっぱなしレビューの悪影響や負の連鎖」はどのように打開すればよいでしょうか? 打開策1:レビュー実施直後のふりかえり実践 レビューを実施した直後に今回のレビュー全般をふりかえり、次(今後)のレビューでどのように進めるとより良い結果が出せるのかを明確にするのが打開策の一つ目です。 ふりかえりを実施するときの大事なポイントの一つは「ふりかえりの対象活動を小さくする」そして「終了直後に実施する」ことです。 小さい活動の終了直後にふりかえりを実施することで、対象活動(今回はレビュー)で発生した「継続すべきよい事項」や「見直すべき事項」が記憶のかなたに消えてしまうリスクを軽減し、何が起きたのか、その結果どうなったのかを思い出すための余計な時間を最小化します。(図1-【B】) よく、プロジェクト終了後にプロジェクトふりかえりを実施しているケースを目にしますが、数か月~数年の期間で運営してきた内容を一度に一気に思い出すことを暗に求めることになります。1日経過すると7割程度の記憶がなくなる、数日前の食事の内容ですら思い出すのに苦労するのが人間ですから、数か月前、半年前の記憶はほんのささやかな断片でしかありません。必要なことをしっかり思い出して共有するには余計な時間と手間をかける必要がありますが、それでも実際には思い出せずに終わることのほうが多くなります。 この方法だと、時間も工数も大きくなる割に効果的な結果が得られる可能性はとても低くなってしまいます。(図1-【A】) レビュー実施直後にふりかえりを行うことで、短い時間と工数で次(以降)のレビューで実践すべき事項を確実に導出することができるわけです。 さらに慣れてくると、ふりかえり時に各自がふりかえって結果を書き出す(そのために時間をかける)のではなく、レビュー計画立案や準備、各自のレビュー実施、集合レビュー時などの各段階で気づいたことや見直すべき事項(ふりかえり結果)を共有場所に書きだしながら進めることができるようになります。その結果、ふりかえり時にはすでに書き出された各自の結果を確認・共有するところからスタートするため、ふりかえりにかかる時間・工数が小さくできます。これを、リアルタイムふりかえり、と呼んでいます。(図1-【C】) 図1:ふりかえり実施形態と費用対効果 個人的な経験則ですが、この形式で運営できるようになると、ふりかえりにかかる時間は最短で5分程度、長くても15分程度で済み、次のレビューで実践する具体的な内容を確定することができます。 ふりかえりを実施するときのもう一つの大事なポイントは「関係者で観点を共有して実施する」ことです。 ソフトウェアレビューは一般的に“成果物”に対するレビューですが、ふりかえりは“活動”を対象としたレビューです。 突然「何かあれば指摘してください」と言われると、何となくぼんやり実施することになり、必要な結果が得られる可能性が低くなってしまいます。 関係者が今回のレビュー計画~終了までに体験したことの中には、磨けば光る財宝級の情報が含まれていることがあります。それをしっかり抽出・言語化するために「観点」を活用します。 下記はレビューふりかえりの観点例です。 [全体共通] ナイスプレー(自薦他薦問わず)、個人的に獲得した気づき、あとから準備不足や仕損じが判明したこと、など [レビュープランと準備] レビュー目的、確認すべき観点は適切であったか レビュー目的、観点等に必要なレビューアを割り当てていたか レビュー対象成果物の難易度や重要性・規模、作業者のスキル等からふさわしいレビュータイプを選択できたか ・レビュー実施に必要なインフラ(各種様式、結果格納場所の確保と周知、集合レビュー時の会議室やオンライン会議の準備など)は遅滞なく準備できていたか [集合レビュー] 集中して建設的に議論し結論が導けたか 全員参画できたか/全員から発言・意見・コメントが提示されたか 司会のファシリテーションは適切であったか [レビュー結果] 特定の観点による確認の欠落、不足が危惧されることはないか 指摘件数や指摘内容から想定されるリスクや問題点はないか ふりかえり時に各自が観点に沿ってふりかえり結果を1件1葉で書きだし、全員で共有してまとめていきます。とある一人の気づきや考えを関係者の気づきや考えに変えられる、共有されるのがふりかえりの大事な期待効果です。ふりかえりを通じて次のレビュー時にチームとして継続して実践すること、見直して実践方法を変えることを具体化します。 なお、ふりかえり観点は固定化するモノではありません。 個別のレビューの目的やチームや関係者の習熟度、実践レベル等に応じて内容を見直す必要があります。 このように「やりっぱなしレビュー」によるいつも同じような結果しか得られない状態から、レビューを実施するたびに個々人の体験やノウハウをチームのノウハウに変えてレビューのパフォーマンスを段階的に変えていく基盤にすることができます。 ・・・ちょっと長くなりました。 まだ途中ではありますが以上で「#5レビューの終わり方~レビュー評価・ふりかえり(1/2)」は終了です。 この続きは次回「#5レビューの終わり方~レビュー評価・ふりかえり(2/2)」でお伝えします。 お楽しみに。 この記事を担当したメンバー きたのしろくま(安達 賢二/ @kitanosirokuma ) 自律・自己組織化を促進する価値共創プログラムSaPIDをベースに三方よしとなる新しい価値を一緒に考えて創る「共創ファシリテーター」として活動中。 https://www.softwarequasol.com/ 【連載】ソフトウェアレビューをエンジニアリングっぽく語ってみる|記事一覧 【第1回】[#0]イントロダクション 【第2回】[#1]レビューとは? The post 【第3回】[#5]レビューの終わり方~レビュー評価・ふりかえり(1/2)|ソフトウェアレビューをエンジニアリングっぽく語ってみる first appeared on Sqripts .
はじめまして!クオリティマネージャーの”黒山羊さん”です。 どのような業種においても、複数のチームで仕事を進めることは常に発生します。 複数人で仕事を進めるにあたり、打ち合わせやミーティングを開催して認識合わせから始まり、情報の共有、方針・内容の決定、合意に至っているのではないでしょうか。 会議の参加者はお客様、他社様、上役、チームメンバーとそれぞれ異なりますが、いずれの場合でもどのようなことを決定したかを残すために議事録を作成します。 それとは別に、議事メモというものもあります。 社内の小さな会議体の時に議事録代わりに作るというところもあると思いますが、私は議事録とは別に、会議の振り返りに役立てるため、議事メモを作成しています。 今回は、議事メモ作成のポイントを共有させてください。 議事録と議事メモの違い 議事録は会議全体の概要や決定事項等を記録するものです。 議事メモは議論の内容や議題の要点が記載され、決定事項に行き着く流れがわかるものです。 チームメンバーとの会議であれば、会議中に議事メモを表示させ、加筆修正しながら議論を進めるといった使い方もします。 議事録の内容 概要 会議の議題や論点、アジェンダを記す 決定事項 議題に対して決定したことを記す 未決事項 議題に対して決まらなかったこと、次回持ち越したことを記す 確認事項・宿題事項 次回までにやるべきことTODOとして記す この時、対応する担当と期限も記載しておく 議事メモの内容 議事メモは定められたものではなく、それぞれの組織にあわせて記載すればよいと思います。 ただ、議事録と突き合わせて会議の振り返りに使用する場合、アジェンダ毎にどのような意見や議論、質疑応答があったかを記載し、どのタイミングで決定事項と確認事項・宿題事項が出たかわかるようにすると使用しやすいです。 今の議事録事情 昨今のテレワークの普及により、オンライン会議が増えました。 オンライン会議をする際に録画をしておくことで、その録画データをもとに、生成AIが議事録を作成してくれる世の中です。 音声から文字起こしを行い、それを要約することで完成するのですが出来上がったものは要点や決定事項がしっかりまとめられており、少し手直しして議事録のフォーマットに落とし込めばそのまま使えるものになります。 生成AIで作成しなくても、録画が残っていれば後から見直して議事録と突き合わせることもできます。 議事メモ作成のポイント 議事メモは自分やチーム内で会議を振り返ったり、議事録の内容を深堀りするために使います。 個人的に議事メモに残しているポイントを連携します。 確認事項、宿題事項の記録について 確認事項や宿題事項も話の流れで誰がやいつまでにが抜けることがあります。アクションが着実に進むよう、5W1Hがわかるように心掛けるとTODOが明確になります。 確認事項、宿題事項にマークを付けておく 議事録にもTODOとして記載される事項ではありますが、議事メモであれば前後の流れも含めて確認できるので、やることのズレを少なくすることが出来ます。 マークをつけておくことで、後でメモを確認する際に見つけやすくなります。 誰の発言か書いておく 質問やその回答、依頼事項や意見などが出た場合は誰の発言かわかるようにしておきましょう。それによって、発言の意図を確認することに役立ちます。 資料のページ数を書いておく 資料の説明中に質問が出た場合、ページ数も添えておきます。 振り返りの際、資料を突き合わせやすくするため、役立ちます。 時間をメモる これは録画データを確認するときに重宝します。基本議事メモは時系列に記載しているので、前から順に追っていけば該当箇所にたどり着けますが、意見が出たタイミングの時間を書いてあれば、直接アクセスすることが出来ます。 資料とは違う意見は残しておく 資料が間違っていて訂正しているのであれば、後で修正した資料を連携してもらえばいいのですが、報告最中に補足説明や懸念事項が挟まれた場合は残すようにしています。 やっかいなのが、例えば技術者から報告の最中に出てきた懸念事項。ちょっと気になっている・引っかかっている箇所がある。課題にはしたくないけど報告はしておきたい。そういった理由で会議の中の報告の最中に混ぜてくることはあります。(私自身も技術者だった頃、チーム内ミーティングでやりました) そういったものが会議でスルーされると議事録から外れてしまうこともあるので、議事メモには残しておきましょう。 おわりに テレワークや生成AIと我々を取り巻く環境は日々変化していっていますが、人と人が協力して仕事を進めることに変わりはありません。 お互いの意思疎通ができ、認識齟齬が発生しないよう、よりよい会議を開催し、スムーズな決定事項が出来るような資料作成を念頭に置いて頂ければと思います。 参考書籍 コンサル一年目が学ぶこと (大石哲之 著/Dicover) こちらの記事もおすすめです QAコンサルタントの私が、文章を書く時に気を付けている事(5W1H) こんにちは、そして初めまして、QAコンサルタントのsakkyです。  私達は日々、短いものから長いものまで、色々な文章を書いていますが、文章を書くのを苦手に感じたり、なんだかイマイチしゃっきりしないと感じたり、記載の過不足があるのではないかと思ったりする事...  続きを読む  Sqripts 段取り八分/仕事二分のマネジメント こんにちは。クオリティマネージャーのおすぎです。「段取り八分、仕事二分」という言葉があります。仕事の事前準備の大切さを表すもので、仕事に取り掛かる前にきちんと段取りを済ましておくことで仕事の8割は完了している、という格言です。段取りはプロジェクトマ...  続きを読む  Sqripts 環境構築ミスやヒューマンエラーをなくすためのノウハウ こんにちは、テスシです。私はソフトウェア開発で、システムテストに携わっています。この工程では、これまでに開発したプログラムを一つにまとめて、想定通りのものができているかどうかや本番環境でちゃんと動作するかどうかを確認しています。はじめに今回のお話...  続きを読む  Sqripts The post 議事メモのすすめ first appeared on Sqripts .
帰納的な推論 と 発見的な推論(アブダクション) は、 私たちがソフトウェア開発の現場/実務で(知らず知らずにでも)駆使している思考の形です(それどころか日々の暮らしでも使っています)。 それほど“自然な”思考の形ですが、どんな考え方で、どんなところに注意すると質の高い思考ができるのか、基本知識を押さえておくと実務のレベルアップにつながります。 <実務三年目からの発見力と仮説力 記事一覧> ※クリックで開きます 【第1回】見つけるための論理【連載初回、全文公開中】 【第2回】 “共通項”を見つけ出す 【第3回】発見はよい観察とよい方法から 【第4回】帰納の仲間と落とし穴 -前編- 【第5回】帰納の仲間と落とし穴 -後編- 【第6回】 なぜ・どのようにを説明したい 今回からは、“非演繹的”なもうひとつの推論、 アブダクション の考え方を見ていきます。 今回は「仮説(説明仮説)って何?」「アブダクションって何!?」という話です。 ところで仮説って何だろう? “なぜ” “どのように”を解き明かしたい、説明したい・して欲しい 帰納的推論で一般的な傾向を見つけたり、原因と結果の関係を見つけるのに加えて、 「その条件(原因)から なぜ この事象が起こるか」「原因から結果まで、 どのようにして (どのような過程・機序で)起こるか」の説明ができれば、 推測の説得力は相当高まるでしょう。 アブダクションが考える仮説は、 このような「事象の原因を見つけたり、原因から結果に至る過程などを説明する」仮説( 説明仮説 )です。 よい仮説の性質 はじめに、当てずっぽうや思いつきの推測と一線を画す「よい仮説」が具えているべき性質を確認しておきましょう。 (参考:『論理学入門』) いくつか考えられますが、外せないのは次の4点です。 問題となっている事象や因果関係を説明できる。 直接的/間接的に 真偽を検証可能 (verifiable)である。 仮説自体でなくとも仮説がもたらす帰結などの真偽を、事実に照らして判断できる。 ( 反証可能性(偽であると検証できる) は、 誤った仮説を除外できるために重要な性質) 説明能力が同じなら、 より単純な仮説 が望ましい。 複数の仮説が考えられて、同じように不整合や破綻がなく、同じように説明できるなら、単純な仮説を採るのがよい。 少数の仮定から、整合的に説明できる仮説 が望ましい。 既に確立された知識・理解に基づいて、多くの仮定を足すことなく、系統的・体系的に説明できるのが理想的。 アブダクションとは 仮説を考える推論とその形式 19世紀から20世紀アメリカの哲学者・論理学者パースは、説明仮説の重要性と、よい仮説を考える推論( アブダクション )はどのようなものか(どうあるべきか)を研究しました。 パースによれば、アブダクションの典型的な形は次のように示されます。 (出典:『アブダクション 仮説と発見の論理』。太字は引用者による) ①驚くべき事実Cが観察される。 ②しかし もしHが真であれば、Cは当然の事柄 であろう。 ③よって、Hが真であると考えるべき理由がある。 「驚くべき事実C」とは、理由や原因を探りたくなるようなものごとや、解明が必要なものごとです。 (推理小説や推理ドラマの「不可解な事件」や、日常で「これは何だろう?」と不思議に思う出来事もそうです) このCに対して 「こう考えれば C は説明できる」と、“謎”の解消を図る のが仮説Hです(図6-1)。 図6-1 アブダクションの典型的な形・例 アブダクションの形式面での特徴 図6-1の推論の形を図式化すると図6-2のようになります。 図6-2 アブダクションの論理 図6-2の前提1と前提2の順序を入れ替えると、混合仮言三段論法の形をしています(図6-3)。 つまり、アブダクションによる推論は、見かけ上演繹的な推論っぽい形をまとっています。 図6-3 アブダクションの論理・変形 ただし、それは 後件肯定 という、演繹的な推論では誤りになる形です(図6-4。実践編「 “ならば”を使って推論する 」参照)。 図6-4 混合仮言三段論法・後件肯定の誤謬 このように、 (後件肯定という 演繹的には誤った形ではあるが )後件(事実や結果)から、その後件を導く前件(前提や原因など)を“逆向きに”考え、 「 そう考えるのが理にかなっている、もっともらしい 」という説明仮説を発案する のが、アブダクションという推論形式の特徴です。 図6-5 アブダクションの論理の特徴 ポリアの「発見的三段論法」 仮説を考える推論の、もうひとつの見方 パースとは別に、20世紀アメリカの数学者ポリアが「発見的推論」というテーマの論考を著しました。 「発見的推論」とは「帰納や類推(類比的推論)から新たな知見を引き出す推論」に与えた名称で、 パースのアブダクションに言及したものではありませんが、内容はアブダクションに通じるものがあると思われるので、 アブダクションを“側面支援”するひとつの考えとしてその一部を紹介します。 発見的三段論法 ポリアはこの種類の推論の形と意味を考察し、 演繹的な三段論法に対応づけて「発見的三段論法」と呼びました。 発見的三段論法の典型は次の例で示されます。 (参考:『いかにして問題をとくか』、『数学における発見はいかになされるか』) ①Pが正しいならば、Qも正しい。 (例:外洋の航海から陸に近づくと鳥を見かける) ②Qが正しいことが判った。 (例:今、鳥の姿が見えた) ③Pが正しいということは確からしい。 (例:多分陸が近いだろう) 「①PならばQ。②Q。③従って、Pであろう」 という形で、Pがアブダクションでいう仮説Hに相当すると見ることができます。 やはり後件肯定の形(図6-4)ですが、発見的三段論法でもこれを誤りとせず、次のように考えます。 前提Pを裏づける帰結Qが正しい事例が増えると、Pに対する信頼が増す(図6-6 上)。 (「陸が近づくと鳥を見た」事例が増えれば、「鳥が見えた」から「陸が近い」確からしさは増す) 前提Pが正しくない事例が増えると、帰結Qに対する信頼は減る(図6-6 下)。 (「陸は近くないのに鳥を見かけた」“反例”が増えれば、この推測は怪しくなる) 図6-6 発見的な推論の形と意味 なお、この「信頼が増す/減る」は、PとQとの関係性の強弱に応じて“グラデーション”(度合の違い)があります。 PでないのにQである可能性が低い場合は、Qが真の時、Pの信頼はかなり増しますが、 PでなくてもQである可能性が高い場合は、Qが真の時、Pの信頼はわずかに増すにとどまります(図6-7)。 図6-7 発見的な推論の形と意味・グラデーション版 “犯人でないのに手の込んだトリックを仕組むだろうか?” 図6-1上の「V氏殺人事件」で具体化してみましょう(図6-8)。 (なお、図6-1から捜査が進んで、②で「V氏が犯行時刻に間に合うように戻ってきたことが判明している」時点であるとします) 図6-8 発見的な推論・例 レッツアブダクション アブダクションとは、形式や意味の面から見ると、どのようなものなのか? 今回はその概要を見ました。 アブダクションもまた蓋然的な推論であり、“間違い”の可能性をはらみますが、“間違えるリスク”以上の価値をもたらし得る推論です。 説明仮説の質を高めて、原因究明の効果と効率を高めましょう。 次回は、「仮説を考える」にはどう取り組むとよいのか、どんな進め方があるかを見ていきたいと思います。 参考文献 近藤洋逸, 好並英司 『論理学入門』 岩波書店 1979 米盛裕二 『アブダクション 仮説と発見の論理』 勁草書房 2007 パース(著), 伊藤邦武(訳) 『連続性の哲学』 岩波書店 2001 ポリア(著), 柿内賢信(訳) 『いかにして問題をとくか』 丸善 1954 (1997(日本語第11版30刷)) ポリア(著), 柴垣和三雄(訳) 『数学における発見はいかになされるか 2 (発見的推論 そのパターン)』 丸善 1959 図版に使用した画像の出典 Loose Drawing 人物画をお借りしています。 品質探偵コニャン:Produced by Sqripts . No Unauthorized Reproduction. 【連載】ソフトウェアエンジニアのための論理スキル[実務三年目からの発見力と仮説力] 記事一覧 【第1回】見つけるための論理 【連載初回、全文公開中】 【第2回】 “共通項”を見つけ出す 【第3回】発見はよい観察とよい方法から 【第4回】帰納の仲間と落とし穴 -前編- 【第5回】帰納の仲間と落とし穴 -後編- 【第6回】 なぜ・どのようにを説明したい The post 【第6回】 なぜ・どのようにを説明したい|実務三年目からの発見力と仮説力 first appeared on Sqripts .
こんにちは、テストエンジニアの ナカノ です。私は以前、とあるプロジェクトで「お金に関するシステム」に関するテスト設計・実施を行う機会がありました。 「課金 = お金」 というわたしたちの日常生活に密接に関わるモノのシステムにおいて不具合が発生してしまった場合、ユーザーに対する損失は多大なる影響を与えることになります。そのため、一般的なシステムに加えて様々な状況やリスク等を考慮しながらテスト設計を行う必要があると感じました。そういった経験を基に、今回は「お金に関するシステム」においてテストで使用できるような観点を考えてみました。 ※今回ご紹介するケースはあくまで1つの事例・観点であり、全てのカバレッジを網羅するわけではありませんが、少しでも参考にしていただけたらと思います。 お金に関するシステムとは? はじめに、今回のメインテーマである 「お金に関するシステム」 についてどのようなものがあるか、一例をご紹介したいと思います。 オンライン決済システム:Eコマースや店舗での支払い等、Webシステムやアプリで決済を行うシステム 金融機関システム   :金融機関(銀行・証券・保険)が利用する業務システム 資産運用システム   :AI等を利用して資産運用を取り扱うシステム 仮想通貨取引システム :金融機関を介さずに仮想通貨の取引を行うためのシステム 上記で挙げたものの中では特に「オンライン決済システム」がもっとも身近に感じられるシステムなのではないでしょうか。最近はお店でのタッチ決済やネットショッピングなど、モノやサービスの購入をオンライン上で済ませることが当たり前の時代となり、またシステムの需要も増えてきました。本記事では、そういったオンライン決済システムの中でも「課金システム」や「決済」についてピックアップして、テストの観点をご紹介していきたいと思います。 汎用的なテスト観点について まずはじめに大前提として、他のシステムテストなどでも共通と言える汎用的なテスト観点を挙げてみます。 汎用的なテスト観点例) 表示    :仕様通りの文言やアイテム等が適切に表示されているかを確認する レイアウト :レイアウト崩れ等が発生せず適切に描画されているかを確認する 入力    :テキストボックスやテキストエリア等に文字列が入力できることを確認する 画面遷移  :仕様通りに各ページ等に画面遷移できるかを確認する 挙げればキリがないので他は割愛しますが、このような汎用的なテスト観点はどのようなシステムにおいても重要な確認項目となります。 数値のバリデーション観点について 次に数値のバリデーションについてご紹介します。課金システムや決済システムでは、「お金=数値」を入出力する機能が想定されるため、「バリデーション(入力値が正しい形式や範囲に合致しているか)」もとても重要な観点となります。 「数字」に関するバリデーション観点例) 小数点あり :100.1、0.1234 など 記号あり  :+100、-1234 など 指数表記  :1e2 (=100)、1e12 (=1,000,000,000,000) など また、半角数字以外を入力したときの挙動を確認する観点も考慮する必要があります。 「文字」に関するバリデーション観点例) 全角数値     :12345 など 数値以外の文字種 :ひらがな・カタカナ・漢字・アルファベット・記号 など 数値の入力が可能なシステムの場合、「境界値」に不具合が潜んでいる可能性が高いため、値の有効・無効の範囲を確かめる観点も重要なポイントとなります。 「境界値」に関するバリデーション観点例) 最小値の境界値  :最小有効値の境界値、最小無効値の境界値 など 最大値の境界値  :最大有効値の境界値、最大無効値の境界値 など 境界値分析については、こちらの『 「境界値分析」をテスト設計に取り入れる 』でも紹介しているので、ご興味がある方は是非読んでみてください! 「境界値分析」をテスト設計に取り入れる こんにちは、はまたくです。前回の「同値分割法」を使ってみたに続いて、今回は「境界値分析」についてのお話をします。JSTQB FLを勉強したけど実際にテスト技法を使用したことが無い方や、現在JSTQBの勉強を進めている方々の参考になれば幸いです。境界値分析の定義...  続きを読む  Sqripts 以上が数値に関する観点の一例のご紹介となります。他にもシステムの仕様や条件によって様々な要素や観点の考慮が必要なため、実際の作業では仕様やテスト条件を見逃さないように、十分注意してテスト設計を行う必要があります。 課金システム特有のテスト観点について 続いて、「課金システム」特有のテスト観点について考えてみます。課金システムでは、テスト対象となるシステムの仕様によって課金に関する各機能の実装が異なるため、本記事ではいくつかの代表的な機能をピックアップしてテスト観点をご紹介します。 クレジットカード決済 Eコマースサイト等の課金システムの場合、ほとんどの機能仕様としてクレジットカード払い、コンビニ払い、口座振替といった「決済方法」が選択できるようになっているかと思います。本記事ではその中でも決済代行システムを利用した 「クレジットカード」 について、観点を検討してみました。 対象の課金システムが決済代行システム(ECサイト等の運営と決済機関との間で第三者が決済を仲介するシステム)を利用している場合、「テスト専用のカード」を使用して架空のデータで決済処理を行ってテストすることができる場合があります(実際に決済は行われません)。通常、テスト専用のカードのデータとしては、 ①正常に決済できるカード と ②決済処理を作為的に失敗させるカード の2種類あります。さらに、①正常に決済できるカードには、「カードブランド」の種別(基本的には国際的な5ブランドなど)や「カード属性」として「デビッドカード」や「プリペイドカード」などの種類があります。一方、②決済処理を作為的に失敗させるカードには、エラーの種別として「残高不足」や「限度額オーバー」といったデータが用意されていることがあります。 クレジットカードの因子例) 決済に成功するケース : カード種別     :国際的な5ブランド、デビットカード、プリペイドカード、海外発行カード など セキュリティコード :4桁、3桁 名前の文字列長   :有効桁数最小、有効桁数中間、有効桁数最大 など 有効期限      :最短期限、中間期限、最長期限 など 決済に失敗するケース : エラー種別     :残高不足、限度額オーバー、取扱不可 など クレジットカードの条件の注記 例えば、上記記載の「決済に成功するケース」のようなパターンについては、システムの特徴やテストの規模感等を考慮したうえで、「全網羅」とするのか「水準網羅」とするのかといった、どのような条件でテストを行うのかをテスト設計段階でステークホルダーや開発側と協議して合意を形成したうえで決定する必要があります。 クレジットカードの因子例を基にした因子・水準リスト 因子・水準リストを基にした全網羅のパターン例 すべてのパターンをテストケース化する「全網羅」でテストしようとした場合、8 × 2 × 3 × 3 = 144パターンとなるため、テストケース数は大きく増加します。全パターンの組み合わせで確認できるため、ケースの抜け漏れなどは防ぐことができますが、その分テストに必要な工数が膨らむ傾向があります。 因子と水準を基にした水準網羅のパターン例 1つの水準に対して最低限1回は確認を行う「水準網羅」の場合は、「全網羅」ほどの複雑な組み合わせは確認できませんが、例えばシステムの特性として任意の組み合わせで確認できればよいといった条件の粒度感が提示されているのであれば、比較的有効となる確認方法となります。 課金方法種別と残高 課金方法種別について 課金システムにおける課金方法では、主に 「都度課金」 と 「継続課金」 が挙げられます。「都度課金」では商品やサービスの決済ごとにその都度課金する方法に対して、「継続課金」ではサブスクリプションシステムの月額使用料などに代表される設定された金額が毎月決められた日に課金される課金方法となります。各課金方法に関するテストについては、対象システムの仕様に即した各機能が動作するか(都度課金であれば決済時に毎回課金する方式となっているか、継続課金では決済時は課金せず決済日に引き落とされるか など)といった単体的な機能の確認に関するテストが有効となるでしょう。 残高について 課金システムでは、事前にチャージされているお金やポイントを 「残高」 として取り扱い、そこから決済を行う機能仕様が備わっている場合があります。残高は決済前後の状態が重要なポイントとなるため、以下のような観点を抽出すると有効な確認となるでしょう。 都度課金時の決済金額と残高の関係に着目したバリデーション例) 決済金額 < 残高(決済できるか/決済後の残高情報が適切か) 決済金額 = 残高(決済できるか/決済後の残高情報が適切か) 決済金額 > 残高 決済可能な額を追加で課金(決済できないか/決済後の残高情報が適切か) 決済のキャンセル(決済できるか/決済後の残高情報が適切か) 継続課金であっても同様に、設定された決済日に対して自動で課金額が引き落とされるシステムとなるため、決済日当日に上記観点を応用することができます。 年齢による課金額制限 システムによっては、使用するアカウントの年齢に対して課金できる金額の上限が定められている場合があるため、年齢や金額の境界値等の仕様を十分に確認し、テスト設計を行う必要があります。仕様を整理するためには、以下のようなデシジョンテーブルが有効となるでしょう。 課金額制限の仕様例) 15歳までは月額で課金できる上限金額を 5,000円 までとする 16歳から19歳までは月額で課金できる上限金額を 20,000円 までとする 20歳以上は上限金額なし とする 上記仕様を基にしたデシジョンテーブル例 デシジョンテーブルについては、『 いまさらデシジョンテーブルというものを考えてみた 』でも解説されています。こちらもご興味がある方は是非読んでいただければと思います! いまさらデシジョンテーブルというものを考えてみた こんにちは、ゆーすけです。 「V&V」「シフトレフト」に続く、いまさらシリーズの第3回です。今回は、ブラックボックステスト技法の一つである「デシジョンテーブルテスト」について考えてみたいと思います。デシジョンテーブルとは一旦、JSTQB FLシラバスでどの...  続きを読む  Sqripts 決済タイミングとステータス 近年、市場はクレジットカードやスマホから決済を利用するようなシステムにおいて、 二重決済 (システム上の欠陥等により同じ金額が2回決済されてしまう現象)などのトラブルが発生する事例が増えてきました。原因としては、システム側で請求したはずの履歴がないために再請求が行われるケース(システム間の連携不備)や、注文時と商品発送時などで送信されるデータがそれぞれ2回分決済されてしまうといったケースがあるようです。そのため、課金システムにおいても決済を行うときのタイミングやそのときの各ステータスの変化に着目するような観点は重要なポイントとなります。例えば、決済時のアイテムやコンポーネント間での確認であれば「機能テスト」が、決済処理とそのステータスといった各処理の連携に関する確認であれば「状態遷移テスト(または画面遷移表や状態遷移図を用いたテスト設計)」がそれぞれ有効なテストとなるでしょう。 機能テストの観点例) 正常系: 決済処理を行ったとき、関連するステータスが適切に変化するか 決済処理を行ったとき、関連する履歴が適切に反映されるか フロントシステムから決済処理を行ったとき、バックエンドシステムや基幹システムなどに決済した情報が適切に受け渡されるか 異常・特殊操作系: 同時処理(複数ブラウザ等から同タイミングで決済したとき二重決済されないか) 割込処理(決済処理中などで別の決済情報が割り込みしたとき各決済が適切に処理されるか) 連続操作(決済を確定するボタンを連打したとき二重決済されないか) ※上記で記載している当該処理・操作時の期待結果はあくまで想定で記載しているため、実際のテスト設計時は対象システムの仕様を考慮する必要があります。 状態遷移テスト例) 決済に関する各ステータスの仕様例 仮売上: 決済が完了して注文が入った状態 処理中: 売上処理・キャンセル処理を行っている状態 決済完了: 実売上処理が正常に完了した状態 決済失敗: エラーが発生して決済処理が失敗した状態 キャンセル: ユーザーが注文のキャンセルを行った状態 上記仕様を基にした状態遷移図例 状態遷移図については、『 幅広いソフトウェアとテストレベルで適用可能な状態遷移テスト 』にて解説されているため、詳しい内容はこちらでご確認いただけます! 幅広いソフトウェアとテストレベルで適用可能な状態遷移テスト 初めまして。テストエンジニアリング部のこまです。今回はテスト技法の1つ、「状態遷移」についてのお話です。実際の業務でお世話になることも多い技法であることに加えて、JSTQBの学習を進めている方で苦手意識がある方もいらっしゃるかと思い(私がそうでした)、...  続きを読む  Sqripts その他の機能 その他に、例えば 「ポイント」 を付与・利用できるような機能や、 「クーポン」 に対応しているような機能があれば、課金額への影響に関するテスト観点や今回ご紹介した「残高について」周りのテスト観点をかけ合わせてテスト設計を行うと有効となる場合があります。その他にもテスト対象となる課金システムによって様々な機能やサービスがあるため、各機能仕様やテスト条件、テスト環境やテストの規模感などに応じて、適切なテスト設計を行う必要があることを忘れてはいけません。 おわりに 冒頭の「お金に関するシステムとは?」でも述べた通り、近年ではオンライン決済等、お金を扱うシステムが増えてきました。一方で、そのようなお金に関するソフトウェアが正しく動作しないと、経済的な損失、時間の浪費、信用の失墜など企業やユーザーにとって生活レベルで重篤な問題が発生する可能性があります。そのため、テスト設計者は仕様通りに動作することはもちろんのこと、仕様通りの動きが妥当か、ユーザーの様々な利用シーンを考慮できているかなど、開発視点とユーザー視点の両方からテストを考えることが品質保証にとって重要なポイントとなります。仕様やリスクを深く理解し、様々な状況を想定してテストを設計していきたいと改めて感じました。今回の記事が少しでも参考になれば幸いです。 The post 課金システムのテスト設計に必要な観点を考えてみた first appeared on Sqripts .
この連載では、ソフトウェア開発のQAエンジニアとして働き始めた皆様に向けて、私の実体験をもとに「こんなことを知っておけばよかった」という、ちょっとした気づきを共有します。 一緒にソフトウェア開発のQAエンジニアとしての充実したエンジニアライフを築くためのヒントを探っていきましょう。 <QAエンジニアのスタートガイド 記事一覧> ※クリックで開きます 【第1回】充実したQAエンジニアとしてスタートするためのガイドライン 【第2回】「誰のためか」を意識しよう 【第3回】QAエンジニアの第一歩、「ソフトウェアテスト」を知ろう -前編- 【第4回】QAエンジニアの第一歩、「ソフトウェアテスト」を知ろう -後編- 【第5回】コミュニケーションが鍵を握る 【第6回】学ぶ姿勢を持ち続けよう 本記事ではエンジニアとして重要な課題である「学ぶこと」について解説します。 学ぶことは大切です。ITという分野は技術やトレンドの移り変わりが激しく、常に最新の知識をアップデートしていく姿勢が求められます。 また、ITエンジニアは、学ぶことでさらにキャリアを飛躍できる可能性が高いです。 私が過去に経験していた営業職では、「勉強してもなかなか結果につながらない」ということがありました。もしかしたら他の職種でも同じような状況があるかもしれません。 一方で、ITエンジニアは学んだ知識をすぐに試せる特徴があると実感しています。また、世の中で広く知られている知識の多くは、現実のプロダクト開発の貢献につながるような、実践的なものがたくさんあるとも思います。 なので、前向きに学び、それを普段の業務で実践することは充実したエンジニアライフに繋がると考えています。 学び方は、学校教育や受験勉強など、これまでの人生でたくさん経験してきたのではないでしょうか。 しかし、実際に働いていく中では、学生時代と同じように学べないことがあると思います。 本記事では、社会人として、学びを継続することの考え方やコツを伝えていきます。 さまざまな方法で学習する 学習の仕方を学ぶ 社会人になると、1日のほとんどを学びに使っていた学生時代と状況が異なります。 もしかしたら、仕事や家庭の事情で、以前と同じようには学習できないかもしれません。 これらは時間的な要因だけでなく、脳の成長や、経済的な環境の変化にも影響を受けているのだと考えています。 そのため、社会人、そしてエンジニアとしての学び方を身につける必要があります。 具体的な学習の方法は、様々な書籍で言及されていますので、ここでは個別の学習方法について言及しないでおきます。 学習の仕方を学ぶには、以下の本をおすすめします。 エンジニアの知的生産術 (西尾泰和 著/技術評論社) 一生頭がよくなり続ける すごい脳の使い方 (加藤俊徳 著/サンマーク出版) 独学大全 (読書猿 著/ダイヤモンド社) 学習方法には様々なものがあり、具体的にどうやって学ぶかは、自身で考える必要があります。 重要なのは、一人一人に合った学習方法があり、「これが最高」というベストプラクティスは存在しないということです。 アウトプットを通じて学ぶ 個人的にいい学習方法だと思っているのは、アウトプットを通して学ぶことです。 ご自身が使用するナレッジマネジメントツールへの記録、SNSやブログへの発信、イベントへの登壇、普段の仕事での実践などです。 しかし、SNSやブログを通してパブリックな場にアウトプットすると、批判を受けてしまう可能性もあります。外部に向けてのアウトプットはいい面もあれば悪い面もあります。 それでもアウトプットをおすすめする理由は、自分の記憶に頼らなくても、ネット上から自分で検索して思い出すことができるというメリットがあることです。 アウトプットを通じて、自分の力を自分の外に蓄えておくことが可能になるのです。 「テスト」を通じて学ぶ QAエンジニアとして、様々なソフトウェア開発の言語やフレームワークを学ぶことがあると思います。 そういった場合に私は「どうやったらテストできるかを考える」ことを通して学んでいます。 テストとは試験ではなく、ソフトウェアテストです。 ソフトウェアテストは、そのプログラムの呼び出し、処理、アウトプットなど、ソフトウェアの概観を理解するのに重要な要素が詰まっています。 プログラミングを苦手だと感じているQAエンジニアは少なくありません。 そんな人は一度、「この言語やフレームワークはどのようにすればテストできるのだろうか」から考えてみることをおすすめします。 習慣を味方につける 社会人になると、様々な年齢や経験を持った人と比較されます。 そのため、学生時代のような、「同じ世代が同じスタートを切って比べる」ような経験からマインドをチェンジする必要があります。 早く到達することより、むしろ長い時間をかけてでも高い能力に到達することで、メリットを享受できることを理解することです。 だからこそ、長期的な視点で学習に取り組むことは大切だと思います。 「習慣にできるかどうかはその人の性格による」と考えている人もいるかもしれません。実際に私もそう考えていました。 しかしながら、習慣化にもまた技術があり、習熟することが可能なのです。 小さな習慣から始める 私のおすすめは、小さな習慣を作ることです。 学習の具体的な習慣だと、「1行だけ本を読む」や「1問だけ解いてみる」といったことです。 こういった小さな習慣は、数秒から数分程度で実行できるので、習慣化しやすいです。 これらの習慣をアプリやカレンダーなどで簡単に記録します。 小さな習慣の実行と記録を一定期間、例えば1ヶ月続けたとき、これは成功体験となり、次の習慣化のモチベーションに繋げることができるのです。 小さな習慣は育つ 小さな習慣は小さな歩みですが、時間を味方につけることで、長期的には大きな飛躍につながります。 そして、ここで強調したいことは、「小さな習慣は進化する」ということです。 例えば、1日1行の読書を続けているうちに、「1行から1ページにしよう」といった、小さな習慣が大きな習慣に育っていくことがあります。 私のおすすめはこういった前向きなモチベーションには正直に従い、大きな習慣にしてしまうことです。 続けるのが難しくなればまた小さな習慣に戻せばいいのです。 習慣化に失敗しても、習慣化をする技術は失敗を通じて向上させることができると考えます。 習慣化の技術については以下の本が参考になります。 200万人の「挫折」と「成功」のデータからわかった 継続する技術 (戸田大介 著/ディスカバー) 仕事から学ぶ エンジニアとして、様々な学び方があります。 机に向かって勉強するだけでなく、普段の仕事から学ぶことも大切です。 ふりかえりから学ぶ 普段の仕事をしていて、学習よりもむしろ、業務に追われてしまうことは少なくないと思います。 そういった中で、「ふりかえり」や「内省」を通じて学ぶことも有効です。 失敗を繰り返さないことも大切ですが、「よかったことを習慣化する」という点でも、自分の普段の業務をふりかえり、自分自身の学びに繋げることができます。 たとえばKPTというフレームワークがあります。 これは自分が行ったことや感じたことなどを、 Keep/Problem/Try という3つの視点で分類して、次のアクションを考えるという手法です。 KPTの中ではProblemに気を取られる人は少なくないですが、むしろ私はKeepを習慣化することが大切だと考えています。 ふりかえりについては下記の書籍をおすすめします。 アジャイルなチームをつくる ふりかえりガイドブック 始め方・ふりかえりの型・手法・マインドセット (森 一樹 著/翔泳社) 失敗から学ぶ 失敗から学ぶことも大切です。 失敗には学びにつながる「良い失敗」と学びに繋がらない「悪い失敗」があります。 たとえば「失敗学」という分野では失敗の原因を分析し、レベルの低い判断ミスを防止しつつ、高度な判断ミスを形式知にして改善していくという考え方があります。 失敗学のすすめ (畑村洋太郎 著/講談社) 最後に 最後に、1つだけアドバイスしたいことがあります。 「さあ学んでみよう」と学んでみても、うまく記憶が定着しなかったり、アウトプットに繋がらないことがあります。 それによって「また、これを学ばなければいけない」とか「また、こんなこと忘れていて恥ずかしい」と思うことがあると思います。 私はよくあります。 そういった時に私が自分に言い聞かせていることがあります。 「繰り返しの中から、また学べばいい」と考えることです。 何かを学び、忘れてしまって、同じことを学んでしまうこともあります。 しかし、それを悔やむ必要はありません。 そうして悔やむのではなく、「また学ぶことができる」「同じことでも学べばいい」と前向きに考えて、好奇心を持ち続けることが大切だと考えています。 「どれだけ学べたか」は他者から見れば、大事かもしれません。 一方で、「学ぶ姿勢を持ち続けよう」は、自分自身が充実したエンジニアであると感じて過ごすために、重要だと思っています。 【連載】QAエンジニアのスタートガイド 記事一覧 【第1回】充実したQAエンジニアとしてスタートするためのガイドライン 【第2回】「誰のためか」を意識しよう 【第3回】QAエンジニアの第一歩、「ソフトウェアテスト」を知ろう -前編- 【第4回】QAエンジニアの第一歩、「ソフトウェアテスト」を知ろう -後編- 【第5回】コミュニケーションが鍵を握る 【第6回】学ぶ姿勢を持ち続けよう The post 【第6回】学ぶ姿勢を持ち続けよう|QAエンジニアのスタートガイド first appeared on Sqripts .
こんにちは、K.Oです。 現代のソフトウェア開発では、新しい技術やプロセスの導入機会が増えています。特に、スピードと柔軟性が求められるスタートアップのアジャイル開発では、技術導入による生産性向上が大きな魅力です。しかし、現場の抵抗感やスキルギャップにより、導入が思うように進まないことも少なくありません。 そこで鍵となるのがチェンジマネジメントです。これを活用することで、組織や個人が変革に柔軟に適応し、スムーズに定着させるためのプロセスを可視化・管理できます。 本記事では、まずチェンジマネジメントの全体像を押さえ、以下の2つの事例をもとに、ADKARとKotterの2つのモデルを用いてチェンジマネジメントの実践方法を解説します。 スタートアップのアジャイル環境に品質管理の仕組みを導入 第三者検証企業のテスト工程にAIベースのテスト支援を導入 チェンジマネジメント とは?変革を定着させる基本原則 チェンジマネジメントとは、新しい技術やプロセスをスムーズに導入し、定着させるための手法です。単にツールを導入するだけでなく、組織や個人の行動変化を支援し、変革を持続させることが目的となります。 代表的なフレームワークとして、以下の2つがよく知られています。 ADKARモデル ジェフ・ハイアット(Jeff Hiatt)が提唱した、個人に焦点を当てた変革モデルです。 変革を受け入れる個人の心理プロセスを次の5つの要素で定義しています。 Awareness(認識) – 変革の必要性を理解していること Desire(欲求) – 変革に参加し支えたいという意欲があること Knowledge(知識) – 変革の方法に関する知識を持っていること Ability(能力) – 新しいやり方を実行するスキルが備わっていること Reinforcement(強化) – 定着させ変化を持続するための強化策があること ADKARモデルでは、個々人が「なぜ変わる必要があるのか」「変化が自分にどう影響するのか」を明確に理解し、自発的に変化を受け入れる状態を作ることを重視します。 個人レベルでこの5要素を順に満たす支援を行うことで、組織全体の変革成功率を高めることができます。 Kotterの8段階プロセス ジョン・コッター(John Kotter)が、多くの企業の変革事例を分析してまとめたフレームワークです。変革を成功させるために踏むべき8つのステップを提示しており、特に大規模な組織変革における人の動きに焦点を当てています。 8段階の概要は次の通りです。 危機意識を高める – 変革の必要性を周知し、現状のままでは問題であるという認識を共有する 強力な連帯を築く – 変革推進チームを結成し、信頼できるメンバーで連帯して取り組む 戦略的ビジョンを策定する – 目指す方向性(ビジョン)と実現する戦略を示す 全員の支持を得る – ビジョンを社内に浸透させ、できるだけ多くの支持と参画を得る 障壁を取り除いて行動を可能にする – 新しい取り組みを妨げる抵抗や障害を排除し、現場が行動しやすい環境を作る 短期的な成功を生み出す – 早い段階で小さな成功事例を作り出し、成果を実感させる 加速を持続する – 得られた成果を踏み台にさらなる変革を進め、勢いを維持する 変化を定着させる – 変革で導入した施策を組織文化や日常業務に組み込み、元の状態に戻らないよう定着させる このモデルのポイントは、抵抗感のある人々も巻き込みながら信頼関係と透明性を持って進めることで、受動的で抵抗感のある人を主体的な変革の担い手へと変えていく点です。 コッターのモデルはトップダウン視点の色合いが強いため、ADKARモデルで個人の理解と納得を促しつつ、コッターのステップで組織の環境を整えるという使い分けが効果的です。 以降の事例では、ADKARモデルとコッターの8段階プロセスを効果的に組み合わせながら、品質管理の導入やAIベースのテスト支援の導入を例に成功させるポイントを解説していきます。 ケース1:スタートアップのアジャイル環境に品質管理を導入 スタートアップのアジャイル開発に起こりがちな品質管理の課題 アジャイル開発を採用するスタートアップでは、以下のような課題が起こりやすい傾向があります。 スピード重視文化の弊害 「動くものを早く届ける」を優先し、テストや品質基準を軽視しやすい 属人的な判断・経験頼み KPIや品質基準がなければ、リリース前のチェックも各エンジニアの裁量に依存 リリース後のバグ増大と修正コストの上昇 初期不良が重なり、結果的に作業負荷や開発スピードが落ちる アジャイル開発はスピードと柔軟性が強みですが、品質面が甘いと長期的な成長を妨げる可能性があります。こうした状況を改善するためには、品質管理の仕組みを「無理なく」アジャイル開発に取り込むアプローチが効果的です。 ADKARモデルを活用した導入ステップの一例 A(Awareness) :認識 まずは、品質管理の重要性を全員に認識してもらうことが出発点です。 過去の不具合件数や修正コストを可視化。チームが「長期的な開発速度低下」を実感するようなデータを共有 D(Desire) :欲求 次に、品質管理導入がチームのメリットにつながることを共有します。 バグ修正頻度が下がれば、エンジニアはより新機能開発に専念できる 品質管理の導入は、開発者のストレス削減につながることを強調 K(Knowledge) :知識 品質基準やKPI測定の方法など、具体的な知識を浸透させます。 軽量な品質基準の策定し、テストカバレッジ、コードレビュー実施率など、導入ハードルの低い指標からスタート プロジェクト管理ツールに「バグ起票ルール」や「優先度付け方法」をまとめ、誰でも確認できる状態を整える A(Ability) :能力 実際の開発現場で運用できるよう、チームに必要な技術を身につけてもらいます。 デプロイ時に自動テストが実行されるようにするなど、開発フローを大幅に変えずに品質管理を自然に取り込める仕組みを整える コードレビューの基準化を進め、チェックリスト形式で「レビューすべきポイント」を定義するなど、担当者の迷いを軽減、レビュー工数が増えすぎるリスクを抑える R(Reinforcement) :定着 最後に、成果を振り返り、チーム文化として定着させます。 バグ発生率の変化やテストカバレッジの推移を週次やスプリント末に確認し、チームで議論 良い変化があれば称賛し、継続的な振り返りと改善を重ねて開発文化として定着させる 成功のポイント 大きな変革は小さく始める いきなり品質基準を厳しくするのではなく、テストカバレッジやコードレビューの導入など、小さいステップから取り入れる 品質管理の形骸化を防ぐ 「テストカバレッジ100%」を目指すことが目的ではなく、「実際の品質向上」を重視するという意識づけを行う 成功事例をチーム全体で共有 不具合の減少や長期的な工数削減のデータを共有し、品質管理のメリットを実感してもらう ケース2:第三者検証のテスト工程にAIベースのテスト支援を導入 第三者検証へのAI導入も考えてみます。 AI導入時の典型的な課題 第三者検証企業におけるテスト工程にAIベースのテスト支援を導入する際は、技術的ハードルに加えて、顧客や現場の理解を得る必要があります。具体的には、以下のような点が課題となりがちです。 AIによるテストケース生成の妥当性 顧客が「本当に十分な品質が担保できるのか?」と懐疑的 不具合起票の一貫性 AIが自動で発見した不具合と、テストエンジニアが手動で発見した不具合の整合性をどう確保するか 現場エンジニアの抵抗感 「AIに仕事を奪われるのでは?」という誤解や、新ツール学習への負荷 ADKAR+ Kotter で見る導入プロセスの一例 AI導入時は、個人の変革を促すADKARモデルに加え、組織全体の変革を推進するコッターの視点が役立ちます。 危機感を高める :Kotter Stage 1 人手不足や工期短縮要請など、従来のやり方では対応が難しい現状を明示 Awareness(認識) :ADKAR AI導入の必要性をデータで裏付ける(例えば、テストケース自動生成やテストの自動実行で〇%の工数削減見込み) 強力な連帯を築く :Kotter Stage 2 開発チームに加え、営業やカスタマーサポートも含めた横断的なチームを編成し、導入をリードする Desire(欲求) :ADKAR 「AIがルーティン作業を担うことで、テストエンジニアはより高度なテスト設計に集中できる」というメリットを明確に示す Knowledge(知識) :ADKAR AIによるテストケース生成の仕組みや、誤評価・評価漏れリスクの対処方法を従来のテストと比較し、社内勉強会で共有 短期的な成功を生み出す :Kotter Stage 6 一部プロジェクトでPoC(概念実証)を実施し、バグ検知率の向上や工数削減といった成功データを取得する Ability(能力) :ADKAR PoCで得たノウハウを手順化し、マニュアルや動画チュートリアルを整備 Reinforcement(定着) :ADKAR 成果を関係者全体で評価し、顧客への提案資料に活用する 組織全体でAIベースのテスト支援に対する理解を深め、現場での定着を図る 変化を定着させる :Kotter Stage 8 組織として「AI活用」を当たり前の体制にし、人事評価やプロジェクト計画書にAI活用を織り込む リスク管理と成功のポイント 顧客とのコミュニケーションを強化 AIがどの範囲まで自動化し、どこから人が判断するのかを、契約時やテスト計画の段階で明確にし、関係者間で合意形成しておく PoC→段階的導入→水平展開 まずは限定的なプロジェクトで導入し、成功を確認。その後、他のプロジェクトへ段階的に展開する 透明性と説明責任 AIが生成したテストケースや不具合起票の根拠を説明できる仕組みがあると、顧客が安心しやすい まとめ 変革=ツール導入だけではない 技術導入の成否は「ツールそのものの優秀さ」だけでなく、人や組織がどう変わるかにかかっている 小さな成功体験の積み重ねがカギ まずは限定的な範囲で導入し、成功体験を積み上げることで、チーム全体のモチベーションを高めながら定着を促す “なぜ今この変革が必要なのか”を共有する 関係者全員が納得できる理由を明確にし、データや事例を活用して効果を示すことで、チェンジマネジメントをスムーズに進められる チェンジマネジメントの本質は、「人の意識と行動をいかに変えるか」にあります。スタートアップの品質管理導入からAIベースのテスト支援の活用まで、ADKARモデルやKotterの8段階プロセスといった理論を適切に応用することで、変革の成功率を大きく高めることができます。 本記事が、チェンジマネジメントを進める際のヒントとなり、少しでもお役に立てれば幸いです。 #チェンジマネジメント #ADKAR #Kotter #アジャイル #品質管理 #AIテスト The post チェンジマネジメントで変革を加速!ADKAR×Kotterで実現するアジャイル品質管理とAIテスト導入 first appeared on Sqripts .
こんにちわ。GS です。 今回は、playwright-mcp を駆使して、AI を活用したソフトウェアテストの設計から実行、結果の出力に至るまでの様々な工程の自動化を試みていきます。 キーとなる技術は、 MCP Playwright Aria snapshots LLM の3つです。 前知識 まずは今回使用する技術や概念について説明します。 MCP(model context protocol)とは MCP は「Model Context Protocol」の略で、AI モデル(LLM)が外部のデータソースやツールと通信するための標準化されたプロトコルです。 MCP をわかりやすく説明すると MCP は、「AI のための USB-C」のようなものと考えてください。 例えば、あなたが持っている様々な家電(テレビ、スピーカー、照明、コーヒーマシンなど)を 1 つのリモコンで操作できるユニバーサルリモコンをイメージしてください。MCP は AI アシスタントにとってのそのユニバーサルリモコンです。 従来、AI モデル(ChatGPT、Claude、LLaMA など)が外部のシステム(データベース、API、社内文書など)と連携するには、それぞれのシステムごとに専用の接続方法を開発する必要がありました。これは、テレビ、エアコン、照明器具などにそれぞれ別のリモコンが必要なようなものです。 MCP はこの問題を解決し、AI モデルと外部ツールの間の「共通言語」を提供します。これにより: 開発者は各 AI モデルと外部ツールの組み合わせごとに独自の連携方法を作る必要がなくなります ユーザーは AI アシスタントに「今日のサンフランシスコの天気は?」と聞くだけで、AI が適切な外部ツールを使って最新情報を取得できます 新しいツールやデータソースを簡単に AI システムに追加できるようになります 2024 年末に Anthropic によって公開された MCP は、オープンスタンダードとして急速に普及し、多くの開発者がさまざまなツールやサービスと AI を連携させるためのサーバーを開発しています。 Playwright とは Playwright は、Microsoft が開発したブラウザ自動化ツールです。 簡単に言うと、人間がブラウザで行う操作(ウェブサイトを開く、ボタンをクリックする、テキストを入力するなど)をコンピュータが自動的に行えるようにするソフトウェアです。 例えば、オンラインショッピングサイトで商品を検索したり、フォームに情報を入力したり、ログインしたりといった作業を、人間が手動でやる代わりに自動的に実行できます。 これは特にウェブサイトのテストや、繰り返し行う作業の自動化に役立ちます。 playwright-mcp とは playwright-mcp は、Microsoft の Playwright チームが開発した MCP(Model Context Protocol)サーバーで、AI アシスタントがウェブブラウザを操作できるようにするツールです。このサーバーは、構造化されたアクセシビリティスナップショットを通じてウェブページとの対話を可能にし、スクリーンショットや視覚ベースのモデルを必要としない特徴があります。 playwright-mcp の主な機能 playwright-mcp の主な特徴は以下の通りです: 高速で軽量 :Playwright のアクセシビリティツリーを使用し、ピクセルベースの入力に依存しません LLM フレンドリー :視覚モデルを必要とせず、純粋に構造化データで動作します 決定論的なツール適用 :スクリーンショットベースのアプローチでよくある曖昧さを回避します playwright-mcp を使用すると、AI アシスタント(Claude や GPT-4 など)は以下のようなウェブブラウザの操作を行うことができます: ウェブページの閲覧・ナビゲーション テキスト入力やボタンのクリック ページ内の要素の検索と情報取得 フォームの入力と送信 構造化されたコンテンツからのデータ抽出 Aria Snapshot とは Aria Snapshot は、Playwright が提供するウェブページのアクセシビリティ構造をテストするための機能です。この機能は、HTML の構造をアクセシビリティツリーの YAML 表現として提供し、ページの状態を検証するために使用されます。 特徴 アクセシビリティツリーの表現 : Aria Snapshot は、DOM の構造ではなく、アクセシビリティツリーを基にしています。これには要素の役割、名前、状態などの情報が含まれます。 YAML 形式 : スナップショットは YAML 形式で表現され、人間にも読みやすい形式で保存されます。 柔軟な比較 : 部分的なマッチングや正規表現を使用した比較が可能で、動的なコンテンツにも対応できます。 強み リファクタリング耐性 : DOM の内部構造が変更されても、アクセシビリティツリーは変わりにくいため、リファクタリングに強いテストが可能です。 アクセシビリティの検証 : アクセシビリティの観点からページ構造を検証できるため、支援技術との互換性を確保しやすくなります。 視覚に依存しないテスト : 見た目ではなく、構造的な変更を検出できるため、CSS の変更などに影響されにくいテストが可能です[1]。 弱み 詳細な視覚的テストには不向き : レイアウトや色などの視覚的な要素のテストには適していません。 学習コスト : アクセシビリティツリーの概念を理解する必要があり、初心者には難しい場合があります。 他の技術との違い 従来の DOM スナップショットとの違い : DOM の構造ではなく、アクセシビリティツリーを比較するため、内部実装の変更に強いテストが可能です。 ビジュアルリグレッションテストとの違い : 視覚的な差異ではなく、構造的な差異を検出するため、異なる目的で使用されます。 YAML 表現の例 以下は、シンプルな HTML とそれに対応する Aria Snapshot(YAML 表現)の例です: HTML: <nav> <ul> <li><a href="/">ホーム</a></li> <li><a href="/about">概要</a></li> <li><a href="/contact">お問い合わせ</a></li> </ul> </nav> Aria Snapshot(YAML 表現): - navigation: - list: - listitem: - link "ホーム" - listitem: - link "概要" - listitem: - link "お問い合わせ" この例では、ナビゲーション構造がアクセシビリティツリーとして表現されており、各要素の役割と名前が明確に示されています。 playwright-mcp での活用 playwright-mcp では、この Aria snapshots を活用することで、AI アシスタントがウェブページの構造を理解し、適切な操作を行うことができます。視覚的な情報に依存せず、構造化されたデータのみを使用するため、軽量かつ高速な処理が可能になり、テキストベースの LLM でも効果的にウェブブラウザを操作できるという大きな利点があります。 使用例 playwright-mcp の典型的な使用例には以下のようなものがあります: ウェブナビゲーションとフォーム入力 構造化されたコンテンツからのデータ抽出 LLM による自動テスト エージェントのための汎用ブラウザ操作 バックグラウンドまたはバッチ操作(ヘッドレスモード) 導入方法 playwright-mcp は、npm 経由で簡単に導入できます。以下は基本的な設定例です: { "mcpServers": { "playwright": { "command": "npx", "args": ["@playwright/mcp@latest"] } } } ヘッドレスモード(GUI なしのブラウザ)で実行する場合は以下のように設定します: { "mcpServers": { "playwright": { "command": "npx", "args": ["@playwright/mcp@latest", "--headless"] } } } 実行前準備 MCP サーバーを起動する方法は色々ありますが、今回使用する playwright-mcp サーバーをローカルの Node.js を使用して起動してみます。 Node.js そのもののインストール方法についての詳しい説明は割愛します。ちなみに筆者は Windows も Mac も mise を使ってインストールしています。 mise use -g node@lts npx コマンドの確認 Node.js がインストールされていれば、以下のコマンドで npx コマンドが使用できるはずです。 npx --version npx コマンドのパス確認 npx コマンドのパスを確認します。 Mac の場合 which npx Windows の場合 where npx 操作ツール MCP サーバーを呼び出せるツールなら何でもいいのですが、今回は  Claude のデスクトップアプリ  を使ってみます。 Claude Desktop の設定画面より、構成を編集を押します。 claude_desktop_config.json をお好きなエディタで開きましょう。 開いたファイルに以下の内容を追記します。今回設定する MCP サーバーは、アクセシビリティスナップショットを用いて操作をおこなう MCP サーバーです。 { "mcpServers": { "playwright": { "command": "npx", "args": ["@playwright/mcp@latest"] } } } 設定が完了したら、Claude Desktop を再起動します。 正しく設定されていると、以下のように MCP サーバーが追加されているのが確認できるはずです。 設定がうまくいかない場合、command の部分をフルパスにすることで解消する可能性があります。 たとえば mise を使ってインストールした Node.js に付随する npx コマンドのパスは Mac の場合 "command": "/Users/{ユーザー名}/.local/share/mise/installs/node/22.14.0/bin/npx" Windows の場合 "command": "C:\Users\{ユーザー名}\scoop\apps\mise\current\mise\installs\node\22.14.0\npx.cmd" のようなパスになります。  ●ヒント MCP を使える MCP クライアントにはどんなものがある? ・ Visual Studio Code ・ Cursor ・ Visual Studio Code や Cursor で使える拡張機能の一つである Cline ・ 自作した MCP クライアント など様々な選択肢があります。 playwright-mcp の実行 実際に実行して、様々な動作を確認しながら、テストに活用できる具体例を紹介します。 MCP サーバーに実行してほしい操作を伝えると、指示通りに実行されます。 実行時には、「この操作を本当に実行してもよいですか?」といった確認メッセージが表示されることがあります。 「このチャットで許可」を選択すると、同じ種類の操作については以降確認なしで自動的に実行されるようになります。 ウェブサイトの構造を確認してみよう まずは MCP サーバーにウェブサイトの構造を確認してもらい、正しく動作していることを確認してみましょう。 以降 Web サイトに対する操作は、弊社サイト「 Sqripts 」を対象とします。 以下の命令を与えると、サイトの構造を tree コマンド形式で出力してくれます。 https://sqripts.com このサイトの構造をtreeコマンド形式で出力してください。 このように、サイトの構造を tree コマンド形式で出力してくれます。 テストケースを生成してみよう サイトの構造を確認したところで、テストケースを生成してみましょう。 今回はトップページ だけ のテストケースを生成してみます。 https://sqripts.com このページの内容から、このページのためのテストケースを生成してください。 以下が実際に生成されたテストケースのマークダウンです。 # Sqripts.com のテストケース ## 1. ナビゲーションとリンクテスト |ID|テスト項目|前提条件|テスト手順|期待結果| |---|---|---|---|---| |1.1|ヘッダーナビゲーションリンクの動作確認|Sqripts.comのトップページにアクセスする|1. 各ナビゲーションリンク(テクノロジー、品質、エンジニアリング、スクリプター、特集、ニュース、資料ダウンロード、Sqriptsについて)をクリックする|各リンクをクリックすると対応するページに正しく遷移する| |1.2|「新規登録・ログイン」リンクの動作確認|Sqripts.comのトップページにアクセスする|1. 「新規登録・ログイン」リンクをクリックする|ログインページに正しく遷移する| |1.3|フッターリンクの動作確認|Sqripts.comのトップページにアクセスする|1. フッター内の全てのリンクを一つずつクリックする|各リンクが正しく対応するページに遷移する| |1.4|記事カテゴリタグリンクの動作確認|任意の記事ページを開く|1. 記事に付与されているカテゴリタグ(品質、エンジニアリング、ソフトウェアテストなど)をクリックする|対応するカテゴリページに正しく遷移する| ## 2. コンテンツ表示テスト |ID|テスト項目|前提条件|テスト手順|期待結果| |---|---|---|---|---| |2.1|おすすめ記事セクションの表示確認|Sqripts.comのトップページにアクセスする|1. 「RECOMMEND おすすめ記事」セクションを確認する|おすすめ記事が正しく表示され、タイトル、日付、カテゴリ、著者情報が表示されている| |2.2|最新記事セクションの表示確認|Sqripts.comのトップページにアクセスする|1. 「LATEST 最新記事」セクションを確認する<br>2. 複数の記事が表示されていることを確認する|複数の最新記事がサムネイル画像、タイトル、日付、カテゴリ、著者情報と共に表示されている| |2.3|ランキングセクションの表示確認|Sqripts.comのトップページにアクセスする|1. 「RANKING アクセスランキング」セクションを確認する|人気記事が順位付けされて表示されている| |2.4|著者情報の表示確認|任意の記事ページを開く|1. 記事内の著者情報(名前、画像)を確認する|著者の名前と画像が正しく表示されている| |2.5|記事本文の表示確認|任意の記事ページを開く|1. 記事のタイトル、日付、カテゴリ、本文を確認する|記事の全コンテンツが正しく表示されている| ## 3. 機能テスト |ID|テスト項目|前提条件|テスト手順|期待結果| |---|---|---|---|---| |3.1|「もっと見る」ボタンの動作確認|Sqripts.comのトップページにアクセスする|1. 最新記事セクション下部の「もっと見る」リンクをクリックする|記事一覧ページに正しく遷移し、より多くの記事が表示される| |3.2|タグによる記事絞り込み機能確認|Sqripts.comのトップページにアクセスする|1. 「#TAGS 人気のタグ」セクションから任意のタグ(例:「AI」「ソフトウェアテスト」)をクリックする|選択したタグに関連する記事のみが表示されるページに遷移する| |3.3|イベント・ニュースバナーの確認|Sqripts.comのトップページにアクセスする|1. 「EVENT・NEWS」セクションのバナーをクリックする|バナーに対応するイベントページやニュースページに正しく遷移する| ## 4. レスポンシブデザインテスト |ID|テスト項目|前提条件|テスト手順|期待結果| |---|---|---|---|---| |4.1|モバイル表示確認|モバイルデバイスまたはブラウザの開発者ツールでモバイル表示を有効にする|1. Sqripts.comのトップページを表示する<br>2. 画面をスクロールし、各セクションの表示を確認する|全てのコンテンツがモバイル画面に適切に表示され、レイアウトが崩れない| |4.2|タブレット表示確認|タブレットデバイスまたはブラウザの開発者ツールでタブレット表示を有効にする|1. Sqripts.comのトップページを表示する<br>2. 画面をスクロールし、各セクションの表示を確認する|全てのコンテンツがタブレット画面に適切に表示され、レイアウトが崩れない| |4.3|画面回転時の表示確認|モバイルデバイスまたはブラウザの開発者ツールでモバイル表示を有効にする|1. Sqripts.comのトップページを表示する<br>2. 画面を横向きに回転させる|横向き表示でもコンテンツが適切に表示される| ## 5. パフォーマンステスト |ID|テスト項目|前提条件|テスト手順|期待結果| |---|---|---|---|---| |5.1|トップページの読み込み速度確認|ブラウザの開発者ツールを開く|1. 開発者ツールのNetworkタブを有効にする<br>2. Sqripts.comのトップページをリロードする<br>3. 読み込み完了時間を確認する|ページの読み込み時間が3秒以内である| |5.2|画像の最適化確認|ブラウザの開発者ツールを開く|1. 開発者ツールのNetworkタブを有効にする<br>2. Sqripts.comのトップページをリロードする<br>3. 画像ファイルのサイズを確認する|画像が適切に最適化されており、大きなファイルサイズの画像がない| |5.3|記事ページの読み込み速度確認|ブラウザの開発者ツールを開く|1. 開発者ツールのNetworkタブを有効にする<br>2. 任意の記事ページを開く<br>3. 読み込み完了時間を確認する|記事ページの読み込み時間が3秒以内である| ## 6. 機能性テスト |ID|テスト項目|前提条件|テスト手順|期待結果| |---|---|---|---|---| |6.1|検索機能の動作確認|Sqripts.comのトップページにアクセスする|1. 検索ボックスにキーワード(例:「テスト自動化」)を入力する<br>2. 検索を実行する|入力したキーワードに関連する記事が検索結果に表示される| |6.2|新規登録機能の確認|「新規登録・ログイン」ページにアクセスする|1. 新規登録に必要な情報を入力する<br>2. 登録ボタンをクリックする|アカウントが正常に作成され、ログイン状態となる| |6.3|ログイン機能の確認|「新規登録・ログイン」ページにアクセスする|1. 既存アカウントの情報を入力する<br>2. ログインボタンをクリックする|正常にログインでき、ログイン状態となる| ## 7. アクセシビリティテスト |ID|テスト項目|前提条件|テスト手順|期待結果| |---|---|---|---|---| |7.1|画像の代替テキスト確認|ブラウザの開発者ツールを開く|1. トップページの画像要素を検査する<br>2. alt属性の値を確認する|全ての重要な画像に適切な代替テキストが設定されている| |7.2|キーボードナビゲーション確認|Sqripts.comのトップページにアクセスする|1. マウスを使用せず、Tabキーのみでページ内を移動する<br>2. Enterキーでリンクを開く|キーボードのみでページのすべての機能にアクセスできる| |7.3|フォントサイズの変更確認|Sqripts.comのトップページにアクセスする|1. ブラウザの設定でフォントサイズを大きくする(Ctrl + または Cmd +)|コンテンツが読みやすく表示され、レイアウトが崩れない| ## 8. セキュリティテスト |ID|テスト項目|前提条件|テスト手順|期待結果| |---|---|---|---|---| |8.1|HTTPSプロトコルの確認|ブラウザでSqripts.comにアクセスする|1. URLバーの鍵アイコンを確認する|サイトがHTTPSで保護されている| |8.2|パスワード強度の確認|「新規登録・ログイン」ページにアクセスする|1. 新規登録フォームで弱いパスワードを入力する|強度が不足しているパスワードを拒否または警告が表示される| ## 9. クロスブラウザテスト | ID | テスト項目 | 前提条件 | テスト手順 | 期待結果 | | --- | ------------ | ---------------------- | ------------------------------------------------------------------------- | ---------------------- | | 9.1 | Chrome互換性確認 | Google Chromeブラウザを起動する | 1. Sqripts.comのトップページにアクセスする<br>2. 各セクションの表示を確認する<br>3. リンクをクリックして動作を確認する | すべての機能とデザインが正常に表示・動作する | | 9.2 | Firefox互換性確認 | Firefoxブラウザを起動する | 1. Sqripts.comのトップページにアクセスする<br>2. 各セクションの表示を確認する<br>3. リンクをクリックして動作を確認する | すべての機能とデザインが正常に表示・動作する | | 9.3 | Safari互換性確認 | Safariブラウザを起動する | 1. Sqripts.comのトップページにアクセスする<br>2. 各セクションの表示を確認する<br>3. リンクをクリックして動作を確認する | すべての機能とデザインが正常に表示・動作する | このように、AI がテストケースを自動生成してくれました。 今回はあえて簡潔な指示だけで生成してみましたが、より具体的なテストケースが必要な場合は、テスト観点や重要なポイントを詳細に入力することで、それらの指示に沿ったテストケースを生成できます。 要件定義書や基本設計書、詳細設計書などを入力し、適切なプロンプトを与えれば、対象画面と設計書の仕様を照合したテストケースを生成することも可能です。 生成されたテストケースに修正や追加が必要な場合は、具体的な指示を入力するだけで、AI が修正や加筆を行ってくれます。 テストケースを実行してみよう 生成されたテストケースを元に、テストを実行していきます。しかし単純に実行するだけでは、テストの再利用性が確保できません。 そこで、テストを実行しながら、同時にそのテストを再利用可能な形式でアウトプットする方法を検討しました。 今回は、playwright-mcp で実施されているテストを、TypeScript + Playwright コードとして出力することにします。 以下は使用したプロンプトです。 「1.1ヘッダーナビゲーションリンクの動作確認」のテストをplaywrightで操作して実行し、その実行した手順をtypescript + playwrightコードとしてまとめ、最終レポートにテスト結果と、そのテストを再現できるまとめたコードをレポートとして出力してください。 今回の例では、元となるテストケースの抽象度が高く、そのままではテスト実行が困難でしたが、 実行過程でより具体的なテストケースが自動生成 され、同時にテスト実行も完了してレポートが作成されました。 この結果から、「テストケースを抽象から具象(ステップ)へと変換する」能力が明確に見て取れ、さらに実際の実行までを一貫して行える点が、このテストケース生成システムの大きな強みだと言えます。 もちろん、すべての状況でこれが最適解というわけではなく、ケースによっては適していない場合もあるでしょう。 しかし、このようなテストケース生成システムは、効率的かつ効果的なテスト設計において非常に価値のある強力なツールであることは間違いありません。 作成されたテストコードを実行してみよう 以下が作成されたテストコードです。 このテストコードでは、スクリーンショットを取得していますが、スクリーンショット名にユニーク性がないため、複数のブラウザで実行した場合、後から実行したブラウザのスクリーンショットで上書きされてしまう問題があります。 この問題を解決するため、スクリーンショット名にユニークな値を含めるように修正しました。 また、ファイル名がテストファイルの命名規則に沿っていなかったため、適切な名称に変更しました。 // navigation.spec.ts - Sqripts.comヘッダーナビゲーションリンクのテスト import { test, expect } from "@playwright/test"; test("1.1 ヘッダーナビゲーションリンクの動作確認", async ({ page }) => { // ナビゲーションリンクとその期待されるURLを定義 const navLinks = [ { name: "テクノロジー", url: "https://sqripts.com/category/technology/" }, { name: "品質", url: "https://sqripts.com/category/quality/" }, { name: "エンジニアリング", url: "https://sqripts.com/category/engineering/", }, { name: "スクリプター", url: "https://sqripts.com/writer/" }, { name: "特集", url: "https://sqripts.com/feature/" }, { name: "ニュース", url: "https://sqripts.com/news/" }, { name: "資料ダウンロード", url: "/document/" }, { name: "Sqriptsについて", url: "https://sqripts.com/about/" }, ]; // テスト結果を保存する配列 const results = []; // テスト開始時刻を記録 const startTime = new Date(); console.log(`テスト開始: ${startTime.toLocaleString()}`); try { // ホームページに移動 console.log("Sqripts.comに移動中..."); await page.goto("https://sqripts.com/"); await page.waitForLoadState("domcontentloaded"); console.log("ホームページのスクリーンショットを取得"); await page.screenshot({ path: "./screenshots/homepage.png" }); // 各ナビゲーションリンクをテスト for (const link of navLinks) { try { console.log(`ナビゲーションリンクをテスト中: ${link.name}`); // ナビゲーションリンクを見つけてクリック // ナビゲーションは通常、HTMLではnavタグに含まれているため、このセレクタを使用 const linkElement = await page .locator(`nav >> text="${link.name}"`) .first(); // クリック前にスクロールして要素を表示 await linkElement.scrollIntoViewIfNeeded(); // リンク要素がクリック可能かどうかを確認 await expect(linkElement).toBeVisible(); await expect(linkElement).toBeEnabled(); // リンク要素をクリック await linkElement.click(); // ページ遷移の完了を待機 await page.waitForLoadState("networkidle"); // 現在のURLを取得 const currentUrl = page.url(); // 遷移先ページのスクリーンショットを保存 await page.screenshot({ path: `./screenshots/${link.name}-page.png` }); // 期待されるURLに遷移したかどうかを確認 // 相対URLの場合はベースURLを考慮する const expectedUrl = link.url.startsWith("http") ? link.url : `https://sqripts.com${link.url}`; const passed = currentUrl === expectedUrl || currentUrl.includes(link.url); // テスト結果を保存 results.push({ link: link.name, expectedUrl: expectedUrl, actualUrl: currentUrl, passed, }); // コンソールにテスト結果を出力 if (passed) { console.log(`✅ ${currentUrl} に正常に遷移しました`); } else { console.log( `❌ 遷移に失敗しました。期待値: ${expectedUrl}, 実際: ${currentUrl}` ); } // 次のテストのためにホームページに戻る await page.goto("https://sqripts.com/"); await page.waitForLoadState("domcontentloaded"); } catch (error) { console.error(`エラー発生 ${link.name}のテスト中: ${error}`); results.push({ link: link.name, expectedUrl: link.url, actualUrl: "Error", passed: false, error: error.toString(), }); } } } catch (error) { console.error(`ホームページへの移動に失敗: ${error}`); } // テスト終了時刻を記録 const endTime = new Date(); const testDuration = (endTime.getTime() - startTime.getTime()) / 1000; console.log(`テスト終了: ${endTime.toLocaleString()}`); console.log(`テスト所要時間: ${testDuration}秒`); // テスト結果レポートを生成 let passCount = 0; let failCount = 0; console.log("\n========== テスト結果レポート =========="); console.log("ヘッダーナビゲーションリンクテスト結果:"); console.log("==================================="); for (const result of results) { if (result.passed) { passCount++; console.log(`✅ ${result.link}: 成功`); console.log(` 期待値: ${result.expectedUrl}`); console.log(` 実際: ${result.actualUrl}`); } else { failCount++; console.log(`❌ ${result.link}: 失敗`); console.log(` 期待値: ${result.expectedUrl}`); console.log(` 実際: ${result.actualUrl}`); if (result.error) { console.log(` エラー: ${result.error}`); } } console.log("-----------------------------------"); } console.log(`\n概要: ${passCount}成功, ${failCount}失敗`); console.log("==================================="); // すべてのナビゲーションリンクが正常に動作したことを検証 expect(failCount).toBe(0); }); テストコードを動かすための設定ファイルです。 こちらは自動出力されたものをそのまま使用しています。 この設定は Chromium、Firefox、Webkit の 3 つのブラウザ(エンジン)で実行するように最初から設定されていました。 // playwright.config.ts - Playwrightの設定ファイル import { PlaywrightTestConfig } from "@playwright/test"; const config: PlaywrightTestConfig = { testDir: "./tests", timeout: 60000, // タイムアウトを60秒に設定 reporter: [ ["html"], // HTMLレポートを生成 ["list"], // コンソールに結果リストを表示 ["json", { outputFile: "test-results.json" }], // JSON形式のレポートも生成 ], use: { // ブラウザの設定 headless: false, // テスト実行時にブラウザを表示(視覚的に確認するため) viewport: { width: 1280, height: 720 }, // ブラウザのビューポートサイズ ignoreHTTPSErrors: true, // HTTPS証明書エラーを無視 screenshot: "only-on-failure", // 失敗時のみスクリーンショットを撮影 video: "on-first-retry", // 最初の再試行時にビデオを記録 trace: "on-first-retry", // 最初の再試行時にトレースを記録 // アクションのタイムアウト設定 actionTimeout: 10000, // アクション(クリックなど)のタイムアウトを10秒に設定 navigationTimeout: 15000, // ナビゲーション(ページ遷移)のタイムアウトを15秒に設定 }, // 並列実行の設定 workers: 1, // シーケンシャルにテストを実行(ナビゲーションテストの場合は順序が重要) // プロジェクト固有の設定 projects: [ { name: "chromium", use: { browserName: "chromium" }, }, { name: "firefox", use: { browserName: "firefox" }, }, { name: "webkit", use: { browserName: "webkit" }, }, ], // フォルダ構造の設定 outputDir: "test-results/", // テスト結果の出力ディレクトリ }; export default config; 以下のコマンドを実行してテスト環境を構築しましょう。 macOS の場合 # 新しいディレクトリを作成 mkdir sqripts-test cd sqripts-test # npm プロジェクトを初期化 npm init -y # Playwright をインストール npm install -D @playwright/test # Playwright ブラウザをインストール npx playwright install # スクリーンショットを保存するディレクトリを作成 mkdir screenshots mkdir tests touch tests/navigation.spec.ts touch playwright.config.ts Windows の場合 # 新しいディレクトリを作成 mkdir sqripts-test cd sqripts-test # npm プロジェクトを初期化 npm init -y # Playwright をインストール npm install -D @playwright/test # Playwright ブラウザをインストール npx playwright install # スクリーンショットを保存するディレクトリを作成 mkdir screenshots # テストディレクトリとファイルを作成 mkdir tests New-Item -Path tests/navigation.spec.ts -ItemType File New-Item -Path playwright.config.ts -ItemType File tests/navigation.spec.ts と playwright.config.ts ファイルに、それぞれ上記のコードを記載しました。 最後にテストを実行してみます。 npx playwright test ブラウザごとにテストが正常に実行されていることが確認できます。 WebKit はヘッドレスモードで動作しているようです(他のウィンドウの背後に隠れている可能性もあります)が、その他のブラウザは問題なく動作しています。 すべてのブラウザのスクリーンショットは screenshots フォルダに正しく保存されています。 ちなみに今回のテスト動画をよく見ると、Firefox では途中からレイアウトが崩れている箇所があります。 今回のテストケースにはレイアウトのテストが含まれていないため問題なく成功していますが、レイアウトに関するテストケースを作成する場合は、視覚的な検証を行うことでこのような問題を検出できるでしょう。 視覚的な検証を行うには、単純に考えると playwright-mcp サーバーを ビジョンモード で動作させる必要があるでしょう。 ただし、今回のテストのように途中でスクリーンショットを撮影している場合は、これらのスクリーンショットを LLM に渡すことでもレイアウトの検証が可能かもしれません。 まとめ playwright-mcp を使って テストケースを生成 テストケースの具象化(ステップ化) テストケースを実行 テストケースを再利用可能な形式で出力 テストの再実行 結果レポートの生成 これらの機能を活用し、AI を用いたソフトウェアテストを実施しました。 さらに別の技術やMCP、ソフトウェアに関するドキュメントと組み合わせれば テスト結果から仕様書の記載漏れを検出 テスト結果と仕様書を突き合わせて想定外の仕様を検出 NGテストとGithub MCPを組み合わせて不具合箇所を特定 テスト結果に基づく改善点をGithub MCPと連携してリファクタリングを実施 などの様々な活用方法が考えられます。 実際、これらの機能を提供しているプロダクトやサービスはすでに登場しています。 人の手で行わなければならない作業は確実に減少しています。今回紹介した例は単体タスクの依頼であり、自律的なエージェントはまだ登場していません。 しかし、十分な精度を持つ自律型エージェントが登場すれば、人間が行うべき作業は限りなく0に近づいていくでしょう。 1年後にはどのようなソフトウェアテストが可能になっているでしょうか。 1年と言わずとも、わずか1〜2ヶ月で技術が劇的に進化する可能性もあります。 そのような変化が起きた際には、また新たな記事でご紹介したいと思います。  The post 【自動化】playwright-mcpを駆使し、ソフトウェアテストの設計から実行、テスト結果の出力までの自動化を試みる first appeared on Sqripts .
帰納的な推論 と 発見的な推論(アブダクション) は、 私たちがソフトウェア開発の現場/実務で(知らず知らずにでも)駆使している思考の形です(それどころか日々の暮らしでも使っています)。 それほど“自然な”思考の形ですが、どんな考え方で、どんなところに注意すると質の高い思考ができるのか、基本知識を押さえておくと実務のレベルアップにつながります。 <実務三年目からの発見力と仮説力 記事一覧> ※クリックで開きます 【第1回】見つけるための論理【連載初回、全文公開中】 【第2回】 “共通項”を見つけ出す 【第3回】発見はよい観察とよい方法から 【第4回】帰納の仲間と落とし穴 -前編- 前編では「帰納的推論で気をつけたい落とし穴」についてお伝えしました。 後編となる今回は「帰納的推論の仲間」( 第2回 の続き)です。 帰納の仲間たち 帰納的な推論には 第2回 で紹介したものの他にも仲間がいます。 ここではふたつ、 類推(類比的推論) と 既知の因果関係を用いた推論 を紹介します。 (実は、どちらもこれまでの記事の中でさりげなく活躍しています……) 類推(類比的推論) 「あるものごとを他のものごとになぞらえて、共通項を見出す」「あるものごとと他のものごととの類似点を見つけ、一般化する」 といった思考の形は 類推 、 類比的推論 と呼ばれます。 有限の事例の列挙から共通項を見出し、対象全体に一般化する点で、これも帰納的な推論の仲間と言えます。 類推の形には2種類あります。 事例群αに見出された共通点を、別の事例群βの中に見出す(推論する)形 (本記事内独自の呼称として、“タイプA”と呼びます) 事例群αとβとの類似性を基に、新たな共通点を見出す(推論する)形 (本記事内独自の呼称として、“タイプB”と呼びます) 図4-4 類比的推論のふたつの形 “タイプA”では、 ①ある事例群αにおける共通項(属性/特徴/etc.)から、 ②同じ共通項を持つ別の事例群βでも同じことが言えるだろう、 と推論しています。 この形はこれまでも本連載の中でひそかに出てきています。 「ソフトウェアZがプリインストールされているスマートフォンで故障Fが起こる」では、「故障Fが起こるスマートフォンの特徴」「起こらないスマートフォンの特徴」を仕分ける際に、「同じ特徴を持っているなら、同じ故障が起こるのでは」という見方をしています。 “タイプB”はちょっと込み入っていますが、 ①ふたつの事例群α, βに共通項を見出し、 ②事例群αに新たに発見された属性/特徴に対して、 ③ 似ている 事例群βにも 同じ属性/特徴 が見られるだろう(共通項が増えるだろう)、 と推論しています。 図4-5 “タイプB”の推論の構造 類推をする上での 注意点 は、 ふたつの事例群間の共通項が多いほど、推論の蓋然性は高くなります。 既知の共通項と、新たに加わる共通項との関連が密接であるほど、蓋然性は高くなります。 図4-4の“タイプA”の例で、ソフトウェアYとZの共通項は、単に「同じようなサービスを提供する」だけよりは、「使用するリソース、必要とする権限設定、制御構造など」の類似点が多い方が、「ソフトウェアYでも同じ故障Fが起こる」見込みが高いでしょう。 (といっても、「同じようなサービスを提供する」のような目につく点に着目するのは悪手、ということではありません。調査初期の、手がかりが何もないような状況では、見えやすい類似点から手をつけることはよくあります) “タイプB”の例では、ソフトウェアZとYの共通項と故障Fとの関連が強そうで、故障Gもそれら共通項との関連が強そうなら、「Yでも故障Gが起こる」見込みは高いでしょう。 逆に故障GがZに固有の故障でありそうなら(Z独自の処理や、Zに特有のデータに関わる、etc.)、その見込みは低くなるでしょう。 なお、今回紹介した「帰納的推論の性質に関わる落とし穴」はそのまま類推でも気をつける必要があります。 既知の因果関係を用いた推論 既知の因果関係の知識を手がかりに、起こった事象から原因を(または、先行事象から起こり得る結果を)推論する、というのも一種の類推と言えるでしょう。 (たとえば、電子レンジの原理を知っていれば、実際にレンジ内で“爆発”が起こった時に何が原因か推測が働きやすいでしょうし、ある種の食品を電子レンジで温める際に注意深くなるでしょう) 図4-6 既知の因果関係を使って推論する 「ハードウェアやソフトウェアで起こりがちなトラブルの原因と事象の知識」は、問題発生時の原因の切り分けにも通じますし、エラー推測といったテスト技法とも関わります。仕入れておくに越したことはありません。 ネットワーク機器などのハードウェアで起こるトラブルと、ソフトウェアの実行に及ぼす影響 使用しているOS, ミドルウェア, サーバー等の典型的なトラブルと、それが引き起こす事象 プログラミング言語や処理系に関する知識 etc. なお、既知の因果関係の知識は推論を支えてくれはしますが、状況証拠からの推測である点、やはり蓋然的な推論になります。 事象の原因を説明する仮説 「因果関係の推定に関わる落とし穴」の「早急な特定は禁物」で触れているように、因果関係の推定は簡単にいかない場合も多々あります。 原因らしきものを挙げるにとどまらず、「それが原因だとして、どんな過程でこの結果に至ったのか」を説明する仮説( 説明仮説 )が考えられるとなおよいです。 (類推(類比推論)や既知の因果関係を用いた推論は仮説を考える助けになります) 原因から結果までの過程に矛盾がない、他の事象との整合もとれているような“よい” 説明仮説 は、原因の推定に対する確信を与えてくれますし、原因の特定作業も助けてくれます。 そこで、次回からはよい仮説を考えるためのもうひとつの推論の形である アブダクション を紹介していきます。 参考文献 近藤洋逸, 好並英司 『論理学入門』 岩波書店 1979 鈴木美佐子 『論理的思考の技法Ⅱ』 法学書院 2008 藤野登 『論理学 伝統的形式論理学』 内田老鶴圃 1968 J.S.ミル(著), 大関将一(訳) 『論理学体系 : 論証と帰納 5』 春秋社 1959 T・エドワード・デイマー(著), 小西卓三(監訳), 今村真由子(訳) 『誤謬論入門 優れた議論の実践ガイド』 九夏社 2023 図版に使用した画像の出典 Loose Drawing 人物画をお借りしています。 品質探偵コニャン:Produced by Sqripts . No Unauthorized Reproduction. The post 【第5回】帰納の仲間と落とし穴 -後編-|実務三年目からの発見力と仮説力 first appeared on Sqripts .
帰納的な推論 と 発見的な推論(アブダクション) は、 私たちがソフトウェア開発の現場/実務で(知らず知らずにでも)駆使している思考の形です(それどころか日々の暮らしでも使っています)。 それほど“自然な”思考の形ですが、どんな考え方で、どんなところに注意すると質の高い思考ができるのか、基本知識を押さえておくと実務のレベルアップにつながります。 <実務三年目からの発見力と仮説力 記事一覧> ※クリックで開きます 【第1回】見つけるための論理【連載初回、全文公開中】 【第2回】 “共通項”を見つけ出す 【第3回】発見はよい観察とよい方法から 【第4回】帰納の仲間と落とし穴 -前編- 今回のトピックは2つ、前編では「帰納的推論で気をつけたい落とし穴」、そして後編では「帰納的推論の仲間」( 第2回 の続き)です。 帰納的推論で気をつけたい落とし穴 帰納的な推論にも落とし穴(誤謬)はあります。 見つける共通項が因果関係である場合には、因果関係の推定に関わる落とし穴もあります。 第2回 , 第3回 で説明したことも併せ、改めて今回見ていきましょう。 なお、[ 実践編 ]と同様、以下の点に注意してください。 本記事で紹介しているものがすべてではありません 。 これらの分類は排他的なものではありません。複数の分類に該当する誤りもあります(視点によって分類が変わる)。 複数の誤謬が重複したり関連したりして間違った推論を形づくることもあります。 誤謬の名称は、人により文献によって名称が異なることもあります。 帰納的推論の性質に関わる落とし穴 一般化:標本(サンプル)にまつわる落とし穴 軽率な一般化 、または 不十分な標本 の誤謬。 母集団の規模に対して少な過ぎる事例を基に一般化をしてしまう誤りです。 偏った標本 の誤謬。 数は問題ないとしても、母集団の傾向(属性/特徴の在りよう)を適切に反映できていない事例を基に一般化をしてしまう誤りです。 事例の数が少ない場合は 軽率な一般化 だけでなく 偏った標本 になっていないか気をつける必要があります。 こうしたことは、統計的な推論でなく枚挙的な帰納をする場合でも気をつけたい事柄と言えます。 (参考: 第2回 の図2-1(B)) 図2-1 帰納的な推論(再掲) 帰納的な推論ができそうな場合は、まず、 「事例の数と傾向を把握した上で推測を立てる」ことを意識して、これらの点を確かめましょう。 事例の数は、一般化するには十分そうか? (推測に合致しそうな事例だけ無意識に集めているということはないか) (数が少ない場合、推論の蓋然性が低い可能性を意識できているか) 事例は偏っていないか? (推測に合致しそうな事例だけ無意識に注目しているということはないか) (偏りがありそうなら、事例を増やして多様性を増すことはできないか) なお、「事例の数が少ないならば、帰納的推論の蓋然性は低い」、というわけではありません。 母集団の均質性、類似性が高いなら(どれも同じ属性を持っている、どれもみな似通っている、etc.)、事例の数が少なくても結論の蓋然性は見込める場合があります。 一般化:結論の導き方にまつわる落とし穴 事例の数や偏りの点で問題がなくても、共通項から結論を引き出す際の考え方や態度にも落とし穴はあります。 いずれも、共通点/類似点に対して相違点への注目が相対的に弱まってしまうところからはまる落とし穴と言えます。 キャリアX社のAndroidスマートフォンA, B, C, D, Eがあるとして、 (1)共通点や類似点にばかり注意が向いて、 相違点を見落とす 。 「A, B, C, D, EはAndroidスマートフォンだから同じだ」と考える類です。 (ハードウェアスペックもUI回りも違っている、etc.) (2)共通点や類似点と結論する性質との 関連が薄い 。 A, B, C, Dで同じ故障が起こっていることから「Eでも同じ故障が起こるだろう」と考える類です。 (見かけの共通点/類似点に引っ張られて結論に飛びついてしまう、etc.) (3)結論の 蓋然性を過度に見積もる 。 A, B, C, D, Eすべてで試したことから「この故障はすべてのAndroidスマートフォンで起こる」と考える類です。 (事例の多さや傾向の偏りのなさなどから、結論が必ず正しいと考える、etc.) (実は権限設定に問題があり、使用したスマホで同じ権限設定のミスをしていたためだった……などの可能性もあります) 図4-1 枚挙的帰納の落とし穴 統計的帰納で気をつけたいこととしては、 的外れな一般化 といったものがあります。 よく起こりがちなものは、事例の数を割合と同一視してしまう(または置き換えてしまう)、というものです。 第2回 の「A子さんの学校でのいちごフォンユーザーの割合」でいうと、 いちごフォンユーザーの数が多いならば、いちごフォンのハードウェア故障の 件数 も多いのは自然でしょう。 対して、その他のスマートフォンユーザーのハードウェア故障件数は相対的に少ないでしょう。 ここで「いちごフォンはハードウェア故障が多い」と考えるのは、ユーザー数の規模の違いを見ずに、ハードウェア故障の件数を故障を起こす割合と同一視、ないし置き換えて考えてしまっています(「故障件数が多い=故障の割合が高い」)。 より適切には、いちごフォンとその他のスマートフォンそれぞれのハードウェア故障の割合を比較するべきです。 図4-2 統計的帰納の落とし穴:的外れな一般化 因果関係の推定に関わる落とし穴 因果関係の取り違え 前後即因果 の誤謬。 時系列の前後関係を因果関係と思う 誤りです。 結果画面の表示が崩れた直後にフリーズしたことから、「表示の崩れがフリーズの原因」と考える類です。 この誤りは古くは「『この後に,だからこの故に (post hoc, ergo propter hoc)』の誤謬」と呼ばれていたそうで、昔からありがちな誤りだったのでしょうね。 原因と結果の混同 。 サブシステムAの処理の重さがサブシステムBのデータ転送遅延を引き起こしているのを、「Bの遅延がAの処理の重さの原因」と考える類です。 間違った原因探し   たまたま共存しているだけ の複数の事象の間に因果関係があると考える誤り。 サブシステムAの応答速度の低下とサブシステムBの転送遅延はたまたま同時に起こっていたただけ(互いに何の干渉もしていない)、といった類です。 相互作用の一面だけ見て 因果関係を考えてしまう誤り。 サブシステムAの応答速度の低下がサブシステムBのデータ転送遅延の原因と思ったが、それぞれの故障が互いに影響を与えていた、といった類です。 原因の見逃し 関連する原因の無視/見落とし 。 複数の原因が関連し合って生じている事象に対し(原因の多数性)、 ひとつの原因を特定するに留まり、他の原因を無視/見落としてしまう 誤りです。 取得するデータの間違えと、計算ロジックの誤りと、画面表示の処理の誤りが合併した故障を、計算ロジックの誤りにだけ注目して他を見落としてしまう類です。 共通する原因の無視/見落とし 。 複数の事象や状態が、共通する原因の結果として起こっている可能性を見落とす(そして、それら事象の間に因果関係を求めてしまう)誤りです。 モジュールAでのデータ加工の故障と、モジュールBでのデータ転送の故障は、実は中間ファイルのデータの破損が引き起こしているのに、個別の事象と判断する(場合によっては「Aの故障がBの故障を引き起こした」などと考える)類です。 早急な特定は禁物 ここまで挙げた誤りにもつながり得る落とし穴が、 因果関係の過剰な単純化 です。 「目につく」「最初に気づいた」「判りやすい」「いかにもそれらしい」といった理由から、見つかった“原因っぽいものごと”に飛びついてしまう(そこで因果関係の推定を止めてしまう)誤りです。 図4-3 因果関係推定の落とし穴 一般に、ある事象が起こった際、その要因と考えられる事柄や先行する事象は数多くあります。 複数の要因が(複雑に)関連してひとつの事象を起こすことも珍しくありません。 それらの中から原因を見つけるのは、時間や手間がかかるものです。 特に、ソフトウェアの故障や不具合発生時のような、起こった事象から遡って原因を考える場合、「事象を確認した段階で、原因の候補を洗い出して、原因らしきことを推定する」のは簡単なことではありません。 (同じようなことが、プロセス改善時の原因分析でも言えます) 因果関係を見つけようとする時には、まずこのことに気をつけましょう。 ( 第3回で紹介した「ミルの帰納法」 も参考になります) 事象や発生状況の詳細を十分調べたか? 原因の候補(先行する事象や、故障の要因になり得る事項)を十分考えて挙げたか? 見つけた(と思う)原因は、観察結果に即しているか? 原因から結果に至る道筋を単純に考えていないか? この章に挙がっている 因果関係の推定に関わる落とし穴 に落ちていないか? 別の落とし穴にはまらないように 観察結果をまとめて共通項を見つけたり、因果関係を特定しようとする際には、演繹的な論理のスキルも働きます。 演繹的推論の落とし穴( 形式面(前編) 、 非形式面(後編) )にも併せて気をつけましょう。 ★ 長くなってしまいましたので、今回はここまで。帰納の仲間については後編でお伝えします。 参考文献 近藤洋逸, 好並英司 『論理学入門』 岩波書店 1979 鈴木美佐子 『論理的思考の技法Ⅱ』 法学書院 2008 藤野登 『論理学 伝統的形式論理学』 内田老鶴圃 1968 J.S.ミル(著), 大関将一(訳) 『論理学体系 : 論証と帰納 5』 春秋社 1959 T・エドワード・デイマー(著), 小西卓三(監訳), 今村真由子(訳) 『誤謬論入門 優れた議論の実践ガイド』 九夏社 2023 図版に使用した画像の出典 Loose Drawing 人物画をお借りしています。 品質探偵コニャン:Produced by Sqripts . No Unauthorized Reproduction. 【連載】ソフトウェアエンジニアのための論理スキル[実務三年目からの発見力と仮説力] 記事一覧 【第1回】見つけるための論理 【連載初回、全文公開中】 【第2回】 “共通項”を見つけ出す 【第3回】発見はよい観察とよい方法から 【第4回】帰納の仲間と落とし穴 -前編- The post 【第4回】帰納の仲間と落とし穴 -前編-|実務三年目からの発見力と仮説力 first appeared on Sqripts .
みなさん、こんにちは。 「ソフトウェアレビューをエンジニアリングっぽく捉える会」 の”うれっしー(うれしのあや)”です。 今回は「レビューとは?」がテーマです。 「〇〇レビューと名前がついていなくても、それはレビュー!って捉えて活動していきましょう」 と言いたい、少し視野を広めていただきたい記事になります。 ▼前回の記事はこちら [#0]イントロダクション |ソフトウェアレビューをエンジニアリングっぽく語ってみる レビューとは何か? さてさて、レビューとはいったい何でしょうか? まずは気楽に、字面(じづら)として意味をとらえてみましょう。 「レビュー(Review)」は、「 re (再び)」+「 view (見る)」が合成した形になっています。 このままの意味「再び見る」のであれば、日常生活がレビューだらけです。 朝出かける時の「携帯持った、財布持った、鍵持った!」も、もう十分レビューなわけです。 次に言葉として、辞書的な意味合いを見ていきましょう。 Googleさんに聞いてみると、「Review(レビュー)には、「批評する」「復習する」「再考する」などの意味があります。 」と教えてくれました。 例えば今回のような記事を読んでいると この記事のここはいいけど、あの部分はもう少しよく書けたはず あのポイントは覚えておきたいから、もう一度チェックしておこう ちょっと引っかかった言葉があるので、別の記事も調べてみよう なんてことがあるでしょう。 たしかに、一目見ただけではなく、今一度記事を見たり頭の中で思い起こしたりして、批評も復習も再考もしています。 というわけで、これらが「レビュー」なわけです。 それは辞書ひっくり返しただけじゃないか、エンジニアリングではなく日常の話だよね、開発で役立つことが知りたいんだよ!というあなた、ここから開発っぽくなりますのでご安心ください。 開発現場における「狭義のレビュー」と「広義のレビュー」 多くの開発現場では、コードレビューや工程移行判定のレビュー、出荷判定のレビューなど、エンジニアリングとして開発プロセスの中で形が定義されていると思います。 指摘事項について合意ができるまでさらに議論したり、疑問については関係者に説明ができるような回答を用意したり、To-doリストを残して管理したりもしているでしょう。 つまり多くの方は「レビュー」と言えば、このような公式に規定されているレビューを思い浮かべるのではないでしょうか。 これらを我々は「狭義のレビュー」と捉えています。 一方、規定されているレビュー以外で、設計書やコードを読んだり、プロセスを策定したり改善したりする際も、気になったことを同じチームのエンジニアに相談に乗ってもらったり、上司に聞いてコメントをもらったりすることが多いと思います。 我々はこれらを「広義のレビュー」として捉えています。 つまり、開発やテスト、プロセスにまつわる相談も「レビュー」に入れているわけです。 「広義のレビュー」として捉えた方が、規定のレビューだけではカバーできない、今まで見えてなかったものが見えてくると思っているからです。 コードや設計書などの成果物を理解するために、 わからないことを聞いて、わかるようになる この部分は、そもそもどうなっていたのか?と確認する もっとこうした方が分かりやすいのではないか?と改善案を考える 公式レビューの準備のために、事前に合意をとっておく、有識者だけで仮の結論を出しておく このような行為を複数人で実施しているのであれば、ピアレビューと言えるのではないかと考えているわけです。 他にも、 エンジニアの頭の中にあるけど、うまく成果物に表現できていないことを引き出す 規定されたレビューの範囲内で多くの項目があり、網羅しているつもりだが、リリース後に問題が起こったので、確認項目を見直してみる 有識者が直接関係しない部分にも参加が必要になっていて時間がもったいないため、レビュー自体の手順やプロセスを効率化する これらもエンジニアリング行為であり、テクニックと同等のものを行使する必要がありますので、「レビュー」と捉えています。 にしさんがよく言っていた「テクい」話の方で、「会議術」(一般的な会議を回す技術)ではない方です。 レビューはテストとは違って動かないもの・ことも対象に入ってきますので、テストとは異なる技術が必要になることは明確でしょう。 必要な技術の中身については今後の連載の中に出てきますので、お楽しみに。 「広義のレビュー」の効果 「狭義のレビュー」の重要性は書くまでもありませんが、でき上がった後の成果物に頼ると現場の負担が大きくなりがちです。 特にレビューでお悩みの方は、公式レビューよりも前の気軽な相談や確認会を増やす=レビューをシフトレフトすると、コストをあまりかけずに製品やサービスを一歩でも改善できると思います。 加えて、レビューの役割分担も普段とは少しずらしたり別の視点にしてみたりすると、みんなの知恵や日常とは異なる良いところも見えてきそうです。 いろんな人の知恵を集めてちゃんと使えるようになると、さらに進化した、強い組織になっていくことにも繋がるはずです。 まとめ 「〇〇レビューと名前がついていなくても、それはレビュー!って捉えて活動していきましょう」 レビューを「狭義のレビュー」で捉えるよりも、「広義のレビュー」として考えてみた方が、手戻りが少なくちょっと気楽になる未来が見えてくるのではと思います。 この連載で書くのはあくまで例にはなりますが、それぞれの現場でどのようにあてはめてみると良いかを、まずはゆる目に検討されてみてください。 「広義のレビュー」の検討が、少しでも皆さまの良い製品・サービスにつながることを願っております。 この記事を担当したメンバー うれっしー (うれしのあや/ @ureshino66 ) 大規模ソフトウェアの品質管理を22年ほど経て、最近の活動は、 ASTER のバグシェルジュとSReEE(スリー)「ソフトウェアレビューをエンジニアリングっぽく捉える会:Software Review Engineering Explorers」。 https://www.softwarequasol.com/ 【連載】ソフトウェアレビューをエンジニアリングっぽく語ってみる 記事一覧 [#0]イントロダクション [#1]レビューとは? The post [#1]レビューとは?|ソフトウェアレビューをエンジニアリングっぽく語ってみる first appeared on Sqripts .