ぱと隊長日誌

ブログ運用もエンジニアとしての生き方も模索中

JSTQB 第10回 AL テストマネージャ 勉強記録振り返り(2020年8月)

始めに

JSTQB認定テスト技術者資格 第10回 Advanced Level <テストマネージャ>試験は2020年8月の試験が中止となりました。理由は新型コロナウィルス (COVID-19) の国内状況を考慮したとのことです。

f:id:pato_taityo:20200607140848p:plain
当時、JSTQBのサイトに掲載されたお知らせ

私にとって今回の試験は再挑戦(前回の受験記録:JSTQB AL テストマネージャ 受験記録 (2019/8/24) - ぱと隊長日誌)であり、COVID-19 によって再び邪魔された試験でもあります(データベーススペシャリスト試験(令和2年度春期)勉強記録 - ぱと隊長日誌)。

大変残念ではありますが、再挑戦までの準備期間が増えたと前向きにとらえることにしました。そこで、次回の受験機会に向けて今回どのような準備を行ったのか、まとめておくことにします。

なお、前回の受験記録と重複する内容は省いたものもあります。よろしければ前回の記事もご参照ください。
JSTQB AL テストマネージャ 受験記録 (2019/8/24) - ぱと隊長日誌

教材と利用方法

シラバス

Foundation Level シラバス 日本語版 (2018年度版)

JSTQB認定テスト技術者資格-シラバス(学習事項)・用語集-

略記:FLシラバス

最新(2018年度版)のFLシラバスを読みました。ただ、今回は1周することもできませんでした。

次回への反省点として以下を挙げます。

  • FLシラバス⇒TMシラバスの順に読む。
  • FLシラバスは「2011年度版」と「2018年度版」のいずれがTM試験に適用されるかを事前に運営側へ確認する。
Advanced Level シラバス 日本語版 テストマネージャ

JSTQB認定テスト技術者資格-シラバス(学習事項)・用語集-

略記:TMシラバス

今回の勉強期間ではサラッと1周しました。当初の計画では問題集などに取り組んだ後、読み直すつもりでいました。

単に読み通すのはしんどいので、自分なりにまとめを作るなどの工夫をした方が良いかもしれないと考えています。しーちきさんがまとめ方の一例をわかりやすく解説しています。
モチベーションが上がらない夜のJSTQB ALTMシラバス読みこみ - 私は迷いの中にいる

【問題集】

JSTQB による Advanced Level 過去出題問題の解説セミナー資料

JSTQB認定テスト技術者資格-イベント-

略記:AL過去問セミナー

シラバスからどのように出題されるかを理解するために読みました。
昨年の受験経験からすると、実際にはより難易度の高い問題が出ていました。

Advanced Level サンプル問題 日本語版 テストマネージャ

JSTQB認定テスト技術者資格-シラバス(学習事項)・用語集-

略記:TMサンプル問題

日本語版公式のサンプル問題。問題数が少ないのでサクッと。

スクエアリング・サービス テスティング基礎コース

スクエアリングサービス

略記:スクエアFL問題集

FL試験向けの模擬試験サービスです。

まずはFLの復習からということで取り組みました。一通り解き切る前に試験中止となりました。

スクエアリング・サービス テスティング中級コース(マネージャ編)

スクエアリングサービス

略記:スクエアTM問題集

テストマネージャ試験向けの日本語版の模擬試験サービスです。

今回は取り組む前に試験中止が決まってしまいました。

JSTQB Advanced Level テストマネージャ問題集

【PDF】JSTQB Advanced Level テストマネージャ問題集 - JSTQB Advanced Level - BOOTH

略記:非認定TM問題集

JSTQB Advanced Level 試験対策勉強会」が発行する【非認定】の問題集です。

問題集は以下の流れで取り組みました。

  1. 出題内容の目標を読む。
  2. 問題を解く。
  3. 解答で答え合わせをし、解説を読む。
  4. 間違えた問題はシラバスの該当部分を読み直す。
  5. なぜ間違えたのかを分析し、教訓として書き残す。
  6. 流れの先頭に戻り、次の問題に取り組む。

勉強期間内に解けた問題は少なかったですが、出題形式は実際の試験に近いと感じました。

【参考文献】

ソフトウェアテスト教科書 JSTQB Foundation

略記:FL教科書

今回は使いませんでしたが、時間に余裕があれば取り組みたかった。

AL過去問セミナー推薦図書

AL過去問セミナーでお勧めされていた3冊の本です。

体系的ソフトウェアテスト入門

体系的ソフトウェアテスト入門

残念ながらいずれも絶版となっており、古本で入手するのが現実的です。

私はいずれもAmazonで古本として購入しました。Amazonで購入した理由はコンディションとその基準が明確で、トラブルがあったときも解決しやすいためです。コンディションが「非常に良い」であれば多少の日焼けやカバーの端がわずかに切れているぐらいでした。その分プレミア価格になっていますが、入手困難なことを考えるとやむを得ないと納得することにしました。

いずれの本も分厚く、読み通すだけでも大変です。また、教科書ではないため試験に直結しているわけではありません。試験を合格するためではなく、テストマネージャとしての基礎力を身に着けるために学ぶというモチベーションで臨む必要があります。

3冊とも異なる目的をもって書かれ、カバーする範囲もそれぞれです。どれかだけを読めばよい、というものではありません。それでも1冊を選ぶのであれば、Rex Black の助言が参考になります。

「テストに関する本を1冊しか読む時間がない場合、これらのどれか1冊を選ぶようお勧めします」という注釈を付けた推薦書の短いリストに、『体系的ソフトウェアテスト入門』を含めるつもりです。
体系的ソフトウェアテスト入門 Rex Black による推薦の言葉より

「基本から学ぶテストプロセス管理」はハードウェア・ソフトウェアテストの両方を扱っています。ただ、ハードウェアテストは私の現在の業務とは乖離しており実感がわきにくいこと、時間が限られていることから、一部を読み飛ばしました。

ソフトウェアテスト12の必勝プロセス」は架空のプロジェクトのテストマネージャによるストーリーが描かれており、テストマネージャが具体的にどういうことを求められているかがイメージしやすかったです。

「体系的ソフトウェアテスト入門」はこの3冊の中では最も読みやすかったです。ページ数が少ないこともありますし(それでも397ページありますが)、小話の説明も丁寧でした(他2冊の Rex Black の本は本筋と関係のない小話の説明が割愛されがちでした)。

勉強時間と進め方

勉強時間の測定にはStudyplusのスマホアプリを利用しました。
学習総合サイト Studyplus(スタディプラス)

2020/03 2020/04 2020/05 小計
TMシラバス 2.5h 2.0h 4.5h
基本から学ぶテストプロセス管理 12.5h 12.5h
AL過去問セミナー 0.5h 0.5h
非認定TM問題集 2.5h 2.5h
FLシラバス 2.0h 2.0h
スクエアFL問題集 3.5h 4.0h 7.5h
体系的ソフトウェアテスト入門 5.5h 2.5h 8.0h
ソフトウェアテスト12の必勝プロセス 8.0h 8.0h
小計 2.5h 28.5h 14.5h 45.5h

※TMサンプル問題に取り組んだ時間は短かったので、割愛しています。

時間を効率的に使うため、場所に応じて取り組む内容を決めました。

通勤中は本を持ち歩いたりノートを広げたりするのが難しいです。そこで、通勤中の電車ではiPadシラバスを読みこむ、もしくはスマホでスクエアの問題集に取り組みました。

会社の始業前・終業後はまとまった時間を最も確保しやすいタイミングでした。そこで、会社のロッカーに問題集とノートを置いておき、リフレッシュルームで集中して取り組むことにしました。

家は家事・育児で時間が細切れになりやすいです。持ち歩くには重く、呼ばれたらすぐに手を止めやすいということから、「AL過去問セミナー推薦図書」の3冊を読み込むことにしました。

ただ、想定外だったのは COVID-19 による自宅待機でした。これにより、通勤と会社の始業前・終業後の時間が使えなくなり、家では一日中育児に明け暮れることとなりました。
これに加えて試験開催が危ぶまれたこともあり、試験勉強というよりは「AL過去問セミナー推薦図書」の3冊を読み込むことに気持ちを切り替え、取り組みました。

教訓

問題集を解いていて私が得た教訓をまとめます。個人差があると思いますので、ここは参考程度になさってください。

スケジュール問題は全体を見る。タスクの実施期間を重ねることができるかもしれない。余裕があればWBSを引いてみる。

選択肢の「~とはいえない」という表現が必ずしも根拠を伴う否定ではないことに留意する。問題文内では根拠が無いから「~とはいえない」としていることがある。
例えば、要件に対するリスク評価やカバレッジの測定を行っていないから、「要件ベースのテストのカバレッジを満たしているとはいえない」となったりする。

私はテストマネージャの役割とテスト担当者の役割を混同していることがある。問題文に「テストマネージャの行動として」のように明記されているときはより注意する。

シラバスで箇条書きになっているところは組み合わせの問題として出題されやすいかも。例えば、テストステークホルダーの各役割を問われるなど。
⇒試験範囲の箇条書きを抜き出すと覚えやすくなるか?

最後に

今回は開催されるのか否かが中々決まらず(運営側の方も大変悩まれたのだと推察します)、モヤモヤした気持ちの中で勉強に取り組んできました。そんな状況の中だったので、ALTM試験に特化しない「AL過去問セミナー推薦図書」の3冊と向き合えたことは今後の礎を築くうえでも、精神的にも良かったです。

今回のボリュームを私のペースで取り組もうと思えば、半年はかかるでしょう。次回に向けて計画的に進めていきます。

PostgreSQL が空テーブルの統計情報を更新しないことによる実行計画への影響

概要

PostgreSQL の ANALYZE コマンドの説明に以下の記載があります。

解析しようとするテーブルが完全に空である場合、ANALYZEはそのテーブルに対する新しい解析情報を記録しません。 これまでの統計情報はすべて保持されます。

ANALYZE

「これまでの統計情報はすべて保持されます」というのがポイントで、以前の統計情報を基に実行計画を立案してしまうことがあります。このケースについて、検証と考察を行います。

検証方法

PostgreSQL 12.1 で検証を行いました。

統計情報の更新タイミングを制御するため、autovacuum = off に設定しています。

(key, value) 列で構成されたテーブルを作成します。
key 列にはインデックスを作成します。

初期データとして (1...10000, 'aaaaa') を投入します。

key value
1 aaaaa
2 aaaaa
(中略) (中略)
10000 aaaaa

VACUUM ANALYZE コマンドを実行します。

ここで key = 1 を条件に SELECT を実行すれば、key 列はインデックスがありユニークという統計情報があるため、実行計画で Index Scan を選ぶであろうことが推測できます。

TRUNCATE コマンドを実行し、続けて VACUUM ANALYZE コマンドを実行します。
テーブルは完全に空ですが、ANALYZE コマンドは統計情報を更新しません。

新たなデータとして (1, 'aaaaa')×10000行を投入します。
初期データと異なり、key 列はユニークではありません。

key value
1 aaaaa
1 aaaaa
(中略) (中略)
1 aaaaa

ここで key = 1 を条件に SELECT を実行します。key 列はユニークでありませんが、「key 列はユニークである」という統計情報を参照し、実行計画で Index Scan が選ばれるはずです。

VACUUM ANALYZE コマンドを実行します。

再度 key = 1 を条件に SELECT を実行します。今度は key 列の値が "1" しかないという統計情報を参照し、実行計画で Index Scan 以外が選ばれるはずです。

統計情報で key 列がユニークか否かどちらに判定したかは pg_stats.n_distinct を参照します。PostgreSQL のドキュメントより n_distinct の説明を引用します。

ゼロより大きい値は列内の個別値の推定数です。 ゼロより小さければ行数で個別値を割算した数字の負数です。 (テーブルが肥大するにつれ個別値の増大があり得るとANALYZEが判断した場合に負変換形式が使われます。 正変換形式は列の取り得る値が固定数を持つと思われる場合に使用されます)。 例えば-1は個別値の数が行数と等しいような、一意な列を表します。

51.88. pg_stats

n_distinct の値が "1" なら列内の個別値が1個、つまり列はユニークでないといえます。また、n_distinct の値が "-1" なら、列はユニークといえます。

検証結果

=# CREATE TABLE tab1(key INTEGER, value CHAR(5));

=# CREATE INDEX ON tab1 (key);

=# INSERT INTO tab1 SELECT generate_series(1, 10000), 'aaaaa';

=# VACUUM ANALYZE tab1;

=# SELECT tablename, attname, n_distinct FROM pg_stats WHERE tablename = 'tab1' AND attname = 'key';
 tablename | attname | n_distinct
-----------+---------+------------
 tab1      | key     |         -1
(1 row)

=# EXPLAIN SELECT * FROM tab1 WHERE key = 1;
                                QUERY PLAN
--------------------------------------------------------------------------
 Index Scan using tab1_key_idx on tab1  (cost=0.29..8.30 rows=1 width=10)
   Index Cond: (key = 1)
(2 rows)

=# TRUNCATE tab1;

=# VACUUM ANALYZE tab1;

=# SELECT tablename, attname, n_distinct FROM pg_stats WHERE tablename = 'tab1' AND attname = 'key';
 tablename | attname | n_distinct
-----------+---------+------------
 tab1      | key     |         -1
(1 row)

=# INSERT INTO tab1 SELECT 1, 'aaaaa' FROM generate_series(1, 10000);

=# EXPLAIN SELECT * FROM tab1 WHERE key = 1;
                                QUERY PLAN
--------------------------------------------------------------------------
 Index Scan using tab1_key_idx on tab1  (cost=0.29..8.30 rows=1 width=10)
   Index Cond: (key = 1)
(2 rows)

=# VACUUM ANALYZE tab1;

=# SELECT tablename, attname, n_distinct FROM pg_stats WHERE tablename = 'tab1' AND attname = 'key';
 tablename | attname | n_distinct
-----------+---------+------------
 tab1      | key     |          1
(1 row)

=# EXPLAIN SELECT * FROM tab1 WHERE key = 1;
                        QUERY PLAN
-----------------------------------------------------------
 Seq Scan on tab1  (cost=0.00..180.00 rows=10000 width=10)
   Filter: (key = 1)
(2 rows)

まとめ

検証方法で事前に予測した通りの結果が得られました。

空テーブルの統計情報は ANALYZE コマンドを実行してもクリアされないということを理解し、データ投入後の ANALYZE コマンドを忘れず実行しましょう。

PostgreSQL の ANALYZE コマンドをトランザクション内で実行した際の挙動

概要

PostgreSQL の ANALYZE コマンドはトランザクション内でも実行できます。また、トランザクション内でのそれまでの更新結果が統計情報に反映されます。

ANALYZE コマンドをトランザクション内で実行した際の挙動について、検証と考察を行いました。

検証

PostgreSQL 12.1 で検証を行いました。

基本的にトランザクション TX1, TX2, TX3 の順で実行します。コメントに記載した実行タイミングを満たさない、もしくは応答待ちになったときは次のトランザクションに実行順序を移します。

TX1 はトランザクション内で更新処理の後に ANALYZE コマンドを実行することで、それまでの更新結果も統計情報に反映されることを確認します。

TX1 が先行した状態で TX2 を実行し、TX1 が進行中もしくは COMMIT 後に TX2 からは統計情報がどのように見えるかを確認します。

TX1, TX2 は PostgreSQL のデフォルト分離レベルである READ COMMITTED でしたが、TX3 は REPEATABLE READ とし、トランザクション分離レベルが統計情報の見え方にどのような影響を与えるかを確認します。

-- TX1

=# CREATE TABLE tab1(c1 INTEGER);

=# INSERT INTO tab1 SELECT generate_series(1, 10);

=# VACUUM ANALYZE tab1;

=# SELECT tablename, attname, n_distinct, most_common_vals, most_common_freqs, histogram_bounds FROM pg_stats WHERE tablename = 'tab1';
 tablename | attname | n_distinct | most_common_vals | most_common_freqs |    histogram_bounds
-----------+---------+------------+------------------+-------------------+------------------------
 tab1      | c1      |         -1 |                  |                   | {1,2,3,4,5,6,7,8,9,10}
(1 row)

=# BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;

=# UPDATE tab1 SET c1 = '1';

=# ANALYZE tab1;

=# SELECT tablename, attname, n_distinct, most_common_vals, most_common_freqs, histogram_bounds FROM pg_stats WHERE tablename = 'tab1';
 tablename | attname | n_distinct | most_common_vals | most_common_freqs | histogram_bounds
-----------+---------+------------+------------------+-------------------+------------------
 tab1      | c1      |          1 | {1}              | {1}               |
(1 row)

-- TX3 の ANALYZE コマンドを実行後に TX1 の COMMIT を実行した。
=# COMMIT;
-- TX2

=# BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;

=# SELECT tablename, attname, n_distinct, most_common_vals, most_common_freqs, histogram_bounds FROM pg_stats WHERE tablename = 'tab1';
 tablename | attname | n_distinct | most_common_vals | most_common_freqs |    histogram_bounds
-----------+---------+------------+------------------+-------------------+------------------------
 tab1      | c1      |         -1 |                  |                   | {1,2,3,4,5,6,7,8,9,10}
(1 row)

=# ANALYZE tab1;
-- TX1 が COMMIT するまで待機状態となる。

=# SELECT tablename, attname, n_distinct, most_common_vals, most_common_freqs, histogram_bounds FROM pg_stats WHERE tablename = 'tab1';
 tablename | attname | n_distinct | most_common_vals | most_common_freqs | histogram_bounds
-----------+---------+------------+------------------+-------------------+------------------
 tab1      | c1      |          1 | {1}              | {1}               |
(1 row)

=# COMMIT;
-- TX3

=# BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;

=# SELECT tablename, attname, n_distinct, most_common_vals, most_common_freqs, histogram_bounds FROM pg_stats WHERE tablename = 'tab1';
 tablename | attname | n_distinct | most_common_vals | most_common_freqs |    histogram_bounds
-----------+---------+------------+------------------+-------------------+------------------------
 tab1      | c1      |         -1 |                  |                   | {1,2,3,4,5,6,7,8,9,10}
(1 row)

=# ANALYZE tab1;
-- TX1, TX2 が COMMIT するまで待機状態となる。

=# SELECT tablename, attname, n_distinct, most_common_vals, most_common_freqs, histogram_bounds FROM pg_stats WHERE tablename = 'tab1';
 tablename | attname | n_distinct | most_common_vals | most_common_freqs |    histogram_bounds
-----------+---------+------------+------------------+-------------------+------------------------
 tab1      | c1      |         -1 |                  |                   | {1,2,3,4,5,6,7,8,9,10}
(1 row)

=# COMMIT;

=# SELECT tablename, attname, n_distinct, most_common_vals, most_common_freqs, histogram_bounds FROM pg_stats WHERE tablename = 'tab1';
 tablename | attname | n_distinct | most_common_vals | most_common_freqs | histogram_bounds
-----------+---------+------------+------------------+-------------------+------------------
 tab1      | c1      |          1 | {1}              | {1}               |
(1 row)

考察

TX1 の実行結果より、トランザクション内で更新処理の後に ANALYZE コマンドを実行すると、それまでの更新結果も統計情報に反映されたことが分かります。トランザクション内で大量の更新を行った後、ANALYZE コマンドを実行することで、後続のクエリで効率の良い実行計画を得られることが期待できます。

TX2 の ANALYZE コマンドの実行が先行する TX1 の終了を待ちました。これは ANALYZE コマンドが SHARE UPDATE EXCLUSIVE ロックを取得するためです。

SHARE UPDATE EXCLUSIVE


SHARE UPDATE EXCLUSIVE、SHARE、SHARE ROW EXCLUSIVE、EXCLUSIVE、およびACCESS EXCLUSIVEロックモードと競合します。 このモードにより、同時実行されるスキーマの変更およびVACUUMコマンドの実行から、テーブルを保護します。


(FULLなしの)VACUUM、ANALYZE、CREATE INDEX CONCURRENTLY、REINDEX CONCURRENTLY、CREATE STATISTICS、ALTER TABLE VALIDATE、および、ALTER INDEXやALTER TABLEの特定の亜種(詳細はALTER INDEXやALTER TABLEを参照してください)によって獲得されます。

13.3. 明示的ロック

TX2, TX3 はトランザクション分離レベルが異なります。TX1 を COMMIT した後、TX2 は TX1 を反映した統計情報が見えていますが (READ COMMITTED)、TX3 はトランザクションを終了するまで以前の統計情報が見えています (REPEATABLE READ)。TX2, TX3 の ANALYZE コマンド実行が結果に影響を与えた可能性を考慮し、ANALYZE コマンドを実行せずに単に待機した場合でも同様の結果が得られました。このことから、統計情報の可視性もトランザクション分離レベルに従うと推測されます。スナップショットと統計情報の状態に整合性があることは正しい実行計画を得るためにも重要といえます。