Playwright 並列実行設計:shard/grep/fixtures で高速化するテストスイート設計術
E2E テストの実行時間が 30 分を超え、CI/CD パイプラインのボトルネックになっている。そんな状況に直面したことはないでしょうか。本記事では、実際に 500 件以上のテストケースを持つプロジェクトで、実行時間を 35 分から 8 分に短縮した設計手法を解説します。
Playwright の shard による分散実行、grep によるテスト絞り込み、fixtures による効率的なセットアップを組み合わせた並列実行設計について、採用した理由・採用しなかった選択肢・運用で発生した問題と回避策を含めてお伝えします。
並列実行設計の要点
| # | 項目 | 概要 | 主な用途 |
|---|---|---|---|
| 1 | shard | テストを複数の CI ジョブに分割して並列実行 | CI/CD での分散実行、大規模テストスイートの高速化 |
| 2 | grep | タグやパターンでテストをフィルタリング | 機能別・優先度別のテスト実行、デバッグ時の絞り込み |
| 3 | fixtures | テスト間で共有するセットアップを効率化 | 認証状態の再利用、データベース接続の共有 |
| 4 | workers | 同一マシン内での並列ワーカー数を制御 | CPU コア数に応じた最適化、リソース競合の回避 |
| 5 | fullyParallel | ファイル内のテストも並列実行する設定 | テスト間に依存がない場合の最大並列化 |
| 6 | retries | 失敗したテストの自動リトライ | flaky テストの安定化、CI の成功率向上 |
| 7 | timeout | テスト・アクション単位のタイムアウト設定 | 無限待機の防止、CI リソースの保護 |
| 8 | reporter | テスト結果の出力形式を制御 | CI 連携、デバッグ情報の可視化 |
検証環境
本記事では、以下の環境で動作確認を行っています。
- OS: macOS Sequoia 15.2 / Ubuntu 24.04 LTS(CI 環境)
- Node.js: 22.13.0
- 主要パッケージ:
- Playwright: 1.50.1
- @playwright/test: 1.50.1
- TypeScript: 5.7.3
- CI 環境: GitHub Actions
- 検証日: 2026年1月24日
✓ 動作確認済み(Node.js 22.x / Playwright 1.50.x)
背景:E2E テスト実行時間の肥大化とビジネスへの影響
プロジェクト規模の拡大がもたらす課題
E2E テストは UI の品質を担保する重要な手段ですが、プロジェクトの成長とともにテストケースは増加し続けます。私が担当したプロジェクトでは、2 年間でテストケースが 50 件から 500 件以上に増加しました。
当初は 5 分程度で完了していたテストスイートが、35 分を超えるようになっていたのです。
以下の図は、テスト実行時間が開発フローに与える影響を示しています。
mermaidflowchart TD
subgraph before["改善前の開発フロー"]
pr1["PR 作成"] --> ci1["CI 実行開始"]
ci1 --> wait1["35分待機"]
wait1 --> result1["結果確認"]
result1 --> fix1["修正が必要"]
fix1 --> ci1
end
subgraph after["改善後の開発フロー"]
pr2["PR 作成"] --> ci2["CI 実行開始"]
ci2 --> wait2["8分待機"]
wait2 --> result2["結果確認"]
result2 --> merge["マージ可能"]
end
図の要点:
- 改善前は 1 回の CI 実行に 35 分かかり、修正が必要な場合はさらに待機時間が発生
- 改善後は 8 分で結果が確認でき、開発者のコンテキストスイッチが減少
- 1 日に 10 回の CI 実行がある場合、270 分の時間短縮効果
なぜ単純な workers 数の増加では解決できないのか
Playwright はデフォルトで並列実行をサポートしています。workers オプションで並列数を増やせば高速化できると考えるかもしれませんが、実際にはいくつかの壁にぶつかります。
1 つ目は リソース競合 です。同一マシン内で多くのブラウザインスタンスを起動すると、メモリ不足やCPU 競合が発生し、かえってテストが不安定になりました。
2 つ目は テスト間の依存関係 です。認証状態やデータベースの状態を共有するテストがあり、並列実行すると予期せぬ失敗が発生するケースがありました。
3 つ目は CI 環境の制約 です。GitHub Actions の標準ランナーは 2 コアであり、単一ジョブでの並列化には限界があったのです。
課題:並列実行設計で直面した 3 つの問題
テスト分割の粒度とバランス
shard を使ってテストを分割する際、どの粒度で分割するかが重要になります。当初は単純にファイル数で均等分割していましたが、テストファイルごとの実行時間にばらつきがあり、一部のジョブだけが長時間実行される状況が発生しました。
認証状態の効率的な共有
E2E テストでは、ほとんどのテストがログイン後の画面を対象とします。各テストで毎回ログイン処理を実行すると、500 件のテストで 500 回のログイン処理が走ることになり、これだけで数十分の時間を消費していました。
flaky テストの増加
並列実行を導入すると、タイミングに依存した flaky テストが顕在化しました。シーケンシャル実行では問題なく通っていたテストが、並列実行では失敗するケースが増えたのです。
解決策:shard・grep・fixtures を組み合わせた設計
shard による CI ジョブ分散
shard は Playwright の組み込み機能で、テストスイート全体を指定した数に分割し、それぞれを別々の CI ジョブで実行できます。
typescript// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
// テストディレクトリの指定
testDir: './tests',
// 各ワーカーでの並列実行数
workers: process.env.CI ? 2 : undefined,
// shard は CLI から指定するため、config では設定しない
});
shard の実行は CLI から行います。
bash# 4 分割の 1 番目を実行
npx playwright test --shard=1/4
# 4 分割の 2 番目を実行
npx playwright test --shard=2/4
GitHub Actions での設定例を示します。
yaml# .github/workflows/e2e.yml
name: E2E Tests
on:
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
続いて、各ジョブのステップを定義します。
yamlsteps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'yarn'
- name: Install dependencies
run: yarn install --frozen-lockfile
Playwright のインストールとテスト実行を行います。
yaml- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
- name: Run tests
run: npx playwright test --shard=${{ matrix.shard }}/4
- name: Upload test results
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.shard }}
path: test-results/
✓ 動作確認済み(GitHub Actions / Ubuntu 24.04)
shard 分割数の決定基準
shard の分割数は、以下の観点から決定しました。
| # | 分割数 | メリット | デメリット |
|---|---|---|---|
| 1 | 2 分割 | CI コスト低、設定シンプル | 高速化効果が限定的 |
| 2 | 4 分割 | バランスが良い | テスト数が少ないと非効率 |
| 3 | 8 分割 | 大規模プロジェクト向け | CI コスト増、ジョブ起動オーバーヘッド |
| 4 | 動的分割 | テスト数に応じて最適化 | 設定が複雑になる |
私たちのプロジェクトでは、500 件のテストに対して 4 分割を採用しました。8 分割も検討しましたが、ジョブの起動オーバーヘッド(約 1 分)を考慮すると、4 分割が最も効率的でした。
grep によるテストのタグ付けとフィルタリング
すべてのテストを毎回実行する必要はありません。開発中は関連するテストだけを実行し、CI では優先度に応じて実行するテストを制御したいケースがあります。
Playwright の grep オプションを使うと、テストのタイトルやタグでフィルタリングできます。
typescript// tests/auth/login.spec.ts
import { test, expect } from '@playwright/test';
// タグを使ったテストの分類
test('ログインフォームが表示される @smoke @auth', async ({
page,
}) => {
await page.goto('/login');
await expect(
page.getByRole('heading', { name: 'ログイン' })
).toBeVisible();
});
優先度が高いテストには @critical タグを付与します。
typescripttest('正しい認証情報でログインできる @critical @auth', async ({
page,
}) => {
await page.goto('/login');
await page
.getByLabel('メールアドレス')
.fill('test@example.com');
await page.getByLabel('パスワード').fill('password123');
await page
.getByRole('button', { name: 'ログイン' })
.click();
await expect(page).toHaveURL('/dashboard');
});
エッジケースのテストには @edge タグを付与します。
typescripttest('無効なメールアドレスでエラーが表示される @edge @auth', async ({
page,
}) => {
await page.goto('/login');
await page
.getByLabel('メールアドレス')
.fill('invalid-email');
await page
.getByRole('button', { name: 'ログイン' })
.click();
await expect(
page.getByText('有効なメールアドレスを入力してください')
).toBeVisible();
});
CLI からタグを指定して実行します。
bash# smoke テストのみ実行(PR 時の簡易チェック)
npx playwright test --grep @smoke
# critical テストのみ実行(デプロイ前の重要チェック)
npx playwright test --grep @critical
# auth タグを除外して実行
npx playwright test --grep-invert @auth
タグ設計のベストプラクティス
実運用で効果的だったタグ設計を紹介します。
mermaidflowchart LR
subgraph priority["優先度タグ"]
critical["@critical<br/>必須機能"]
smoke["@smoke<br/>基本動作"]
edge["@edge<br/>エッジケース"]
end
subgraph feature["機能タグ"]
auth["@auth<br/>認証"]
payment["@payment<br/>決済"]
user["@user<br/>ユーザー管理"]
end
subgraph timing["実行タイミングタグ"]
pr["@pr<br/>PR 時に実行"]
nightly["@nightly<br/>夜間バッチ"]
manual["@manual<br/>手動実行のみ"]
end
図の要点:
- 優先度・機能・実行タイミングの 3 軸でタグを設計
- 1 つのテストに複数のタグを付与可能
- CI ワークフローごとに異なるタグの組み合わせで実行
fixtures による認証状態の効率的な共有
fixtures は Playwright の強力な機能で、テスト間で共有するセットアップを効率化できます。特に認証状態の共有は、テスト実行時間の短縮に大きく貢献しました。
まず、認証状態を保存するセットアップスクリプトを作成します。
typescript// tests/auth.setup.ts
import { test as setup, expect } from '@playwright/test';
const authFile = 'playwright/.auth/user.json';
setup('authenticate', async ({ page }) => {
// ログインページにアクセス
await page.goto('/login');
// 認証情報を入力
await page
.getByLabel('メールアドレス')
.fill(process.env.TEST_USER_EMAIL!);
await page
.getByLabel('パスワード')
.fill(process.env.TEST_USER_PASSWORD!);
await page
.getByRole('button', { name: 'ログイン' })
.click();
// ダッシュボードへの遷移を確認
await expect(page).toHaveURL('/dashboard');
// 認証状態を保存
await page.context().storageState({ path: authFile });
});
次に、設定ファイルでセットアップとテストの依存関係を定義します。
typescript// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
projects: [
// セットアップ用プロジェクト
{
name: 'setup',
testMatch: /.*\.setup\.ts/,
},
認証済み状態を使用するテストプロジェクトを定義します。
typescript // 認証済み状態でテストを実行
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
storageState: 'playwright/.auth/user.json',
},
dependencies: ['setup'],
},
認証不要なテスト用のプロジェクトも用意します。
typescript // 認証不要なテスト用
{
name: 'logged-out',
use: {
...devices['Desktop Chrome'],
},
testMatch: /.*\.logged-out\.spec\.ts/,
},
],
});
✓ 動作確認済み(Playwright 1.50.x)
カスタム fixtures の作成
認証だけでなく、テストで頻繁に使用するセットアップをカスタム fixtures として定義できます。
typescript// tests/fixtures.ts
import { test as base, expect } from '@playwright/test';
// カスタム fixtures の型定義
type CustomFixtures = {
authenticatedPage: import('@playwright/test').Page;
testUser: { email: string; name: string };
};
fixtures の実装を定義します。
typescriptexport const test = base.extend<CustomFixtures>({
// 認証済みページを提供
authenticatedPage: async ({ page }, use) => {
await page.goto('/dashboard');
await expect(page.getByTestId('user-menu')).toBeVisible();
await use(page);
},
テストユーザー情報を提供する fixtures を定義します。
typescript // テストユーザー情報を提供
testUser: async ({}, use) => {
const user = {
email: 'test@example.com',
name: 'テストユーザー',
};
await use(user);
},
});
export { expect } from '@playwright/test';
カスタム fixtures を使ったテストの例です。
typescript// tests/dashboard.spec.ts
import { test, expect } from './fixtures';
test('ダッシュボードにユーザー名が表示される', async ({
authenticatedPage,
testUser,
}) => {
// authenticatedPage は既にログイン済み
await expect(
authenticatedPage.getByText(testUser.name)
).toBeVisible();
});
workers と fullyParallel の最適化
同一マシン内での並列実行を最適化するには、workers と fullyParallel の設定が重要です。
typescript// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
// ファイル内のテストも並列実行
fullyParallel: true,
// CI 環境では 2 ワーカー、ローカルでは CPU コア数の 50%
workers: process.env.CI ? 2 : '50%',
// flaky テスト対策として CI でのみリトライ
retries: process.env.CI ? 2 : 0,
タイムアウト設定を追加します。
typescript // テスト全体のタイムアウト
timeout: 30000,
// expect のタイムアウト
expect: {
timeout: 5000,
},
// アクションのタイムアウト
use: {
actionTimeout: 10000,
navigationTimeout: 15000,
},
});
fullyParallel を使う際の注意点
fullyParallel: true を設定すると、同一ファイル内のテストも並列実行されます。これにより高速化が期待できますが、テスト間で状態を共有している場合は問題が発生します。
私たちのプロジェクトでは、以下のケースで flaky テストが発生しました。
typescript// 問題のあるテスト例
test.describe('ユーザー設定', () => {
test('プロフィールを更新できる', async ({ page }) => {
await page.goto('/settings/profile');
await page.getByLabel('表示名').fill('新しい名前');
await page
.getByRole('button', { name: '保存' })
.click();
});
// 上のテストと並列実行されると失敗する可能性
test('更新後の名前が表示される', async ({ page }) => {
await page.goto('/settings/profile');
await expect(page.getByLabel('表示名')).toHaveValue(
'新しい名前'
);
});
});
解決策として、依存関係のあるテストは test.describe.serial を使用します。
typescript// 修正後:シリアル実行を明示
test.describe.serial('ユーザー設定の更新フロー', () => {
test('プロフィールを更新できる', async ({ page }) => {
await page.goto('/settings/profile');
await page.getByLabel('表示名').fill('新しい名前');
await page
.getByRole('button', { name: '保存' })
.click();
await expect(
page.getByText('保存しました')
).toBeVisible();
});
test('更新後の名前が表示される', async ({ page }) => {
await page.goto('/settings/profile');
await expect(page.getByLabel('表示名')).toHaveValue(
'新しい名前'
);
});
});
具体例:500 件のテストを 8 分で実行する構成
全体アーキテクチャ
以下の図は、私たちが採用した並列実行アーキテクチャの全体像です。
mermaidflowchart TB
subgraph trigger["トリガー"]
pr["PR 作成/更新"]
end
subgraph setup["セットアップフェーズ"]
auth["認証状態を生成<br/>auth.setup.ts"]
end
subgraph parallel["並列実行フェーズ"]
shard1["Shard 1/4<br/>~125 テスト"]
shard2["Shard 2/4<br/>~125 テスト"]
shard3["Shard 3/4<br/>~125 テスト"]
shard4["Shard 4/4<br/>~125 テスト"]
end
subgraph report["レポート集約"]
merge["結果をマージ"]
notify["Slack 通知"]
end
trigger --> setup
setup --> parallel
shard1 --> merge
shard2 --> merge
shard3 --> merge
shard4 --> merge
merge --> notify
図の要点:
- セットアップフェーズで認証状態を 1 回だけ生成
- 4 つの shard で並列実行(各 shard は 2 workers で実行)
- 合計 8 並列でテストを実行
完全な playwright.config.ts
実際に使用している設定ファイルの全体像を示します。
typescript// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
import path from 'path';
// 認証状態の保存先
const STORAGE_STATE = path.join(
__dirname,
'playwright/.auth/user.json'
);
基本設定を定義します。
typescriptexport default defineConfig({
testDir: './tests',
// 並列実行の設定
fullyParallel: true,
workers: process.env.CI ? 2 : '50%',
// リトライ設定
retries: process.env.CI ? 2 : 0,
// タイムアウト設定
timeout: 30000,
expect: { timeout: 5000 },
レポーター設定を追加します。
typescript // レポーター設定
reporter: process.env.CI
? [
['github'],
['html', { outputFolder: 'playwright-report' }],
['json', { outputFile: 'test-results.json' }],
]
: [['html', { open: 'on-failure' }]],
共通の use 設定を定義します。
typescript use: {
baseURL: process.env.BASE_URL || 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'on-first-retry',
actionTimeout: 10000,
navigationTimeout: 15000,
},
プロジェクト設定を定義します。
typescript projects: [
// 認証セットアップ
{
name: 'setup',
testMatch: /.*\.setup\.ts/,
use: { ...devices['Desktop Chrome'] },
},
// メインテスト(認証済み)
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
storageState: STORAGE_STATE,
},
dependencies: ['setup'],
},
認証不要テスト用のプロジェクトを追加します。
typescript // 認証不要テスト
{
name: 'logged-out',
use: { ...devices['Desktop Chrome'] },
testMatch: /.*\.logged-out\.spec\.ts/,
},
],
// ローカル開発サーバーの起動
webServer: {
command: 'yarn dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
timeout: 120000,
},
});
GitHub Actions ワークフローの完全版
yaml# .github/workflows/e2e.yml
name: E2E Tests
on:
pull_request:
branches: [main, develop]
push:
branches: [main]
env:
BASE_URL: http://localhost:3000
ジョブの定義を行います。
yamljobs:
e2e-tests:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'yarn'
依存関係のインストールとキャッシュを設定します。
yaml- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
テスト実行と結果のアップロードを行います。
yaml- name: Run E2E tests
run: npx playwright test --shard=${{ matrix.shard }}/4
env:
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.shard }}
path: playwright-report/
retention-days: 7
よくあるエラーと対処法
エラー 1: browserContext.storageState: Target page, context or browser has been closed
shard 実行時に認証状態の保存が失敗するケースで発生しました。
bashError: browserContext.storageState: Target page, context or browser has been closed
発生条件
- セットアップスクリプトでページを閉じた後に
storageState()を呼び出した場合 - タイムアウトによりブラウザが自動終了した場合
解決方法
typescript// 修正前(エラーが発生)
setup('authenticate', async ({ page }) => {
await page.goto('/login');
// ... ログイン処理
await page.close(); // NG: 閉じた後に storageState できない
await page.context().storageState({ path: authFile });
});
ページを閉じる前に状態を保存するように修正します。
typescript// 修正後(正常動作)
setup('authenticate', async ({ page }) => {
await page.goto('/login');
// ... ログイン処理
await page.context().storageState({ path: authFile }); // OK: 先に保存
// page.close() は不要(Playwright が自動で処理)
});
エラー 2: Timeout 30000ms exceeded
並列実行時にタイムアウトが頻発するケースです。
bashError: Timeout 30000ms exceeded.
waiting for locator('button:has-text("保存")')
原因
並列実行により、サーバーへのリクエストが集中し、レスポンスが遅延したためです。
解決方法
タイムアウトを適切に設定し、リトライを追加しました。
typescript// playwright.config.ts
export default defineConfig({
timeout: 60000, // テスト全体を 60 秒に延長
expect: { timeout: 10000 }, // expect を 10 秒に延長
use: {
actionTimeout: 15000,
navigationTimeout: 30000,
},
retries: process.env.CI ? 2 : 0,
});
まとめ
採用した設計と効果
Playwright の shard、grep、fixtures を組み合わせた並列実行設計により、500 件のテストスイートの実行時間を 35 分から 8 分に短縮できました。
| # | 施策 | 効果 | 導入コスト |
|---|---|---|---|
| 1 | shard 4 分割 | 実行時間 75% 削減 | 低(CI 設定の変更のみ) |
| 2 | fixtures による認証共有 | ログイン処理 99% 削減 | 中(セットアップスクリプト作成) |
| 3 | grep によるタグ分類 | 開発時の待機時間削減 | 低(テストタイトルの修正のみ) |
| 4 | fullyParallel + serial | 最大並列化と安定性の両立 | 中(テスト設計の見直し) |
向いているケース
- テストケースが 100 件以上ある大規模プロジェクト
- CI/CD の実行時間がボトルネックになっている
- テスト間の依存関係を適切に管理できるチーム
向かないケース
- テストケースが 50 件未満の小規模プロジェクト(shard のオーバーヘッドが大きい)
- CI の並列ジョブ数に制限がある環境
- テスト間で共有状態が多く、分離が難しいレガシーコード
採用しなかった選択肢
当初は Cypress Cloud や BrowserStack の並列実行サービスも検討しましたが、以下の理由で採用しませんでした。
- コスト: 月額費用が発生し、テスト数の増加に応じて費用も増加
- 依存性: 外部サービスへの依存が増え、障害時に CI が停止するリスク
- カスタマイズ性: 自社の要件に合わせた細かい調整が難しい
Playwright の組み込み機能で十分な高速化が実現でき、追加コストなしで運用できています。
関連リンク
著書
articlePlaywright 並列実行設計:shard/grep/fixtures で高速化するテストスイート設計術
article2026年1月13日PlaywrightとTypeScriptでテスト自動化を運用する 型安全な設計と保守の要点
article2025年12月25日PlaywrightとTypeScriptで型安全なE2Eを最短でセットアップする手順
articlePlaywright スクリーンショット/動画取得のベストプラクティス集【設定例付き】
articlePlaywright × GitHub Actions 導入ガイド:キャッシュ最適化と並列戦略まで一気通貫
articlePlaywright と Selenium の違いを実測で検証:乗り換え判断チェックリスト付き
articleNotebookLM に PDF/Google ドキュメント/URL を取り込む手順と最適化
articlePlaywright 並列実行設計:shard/grep/fixtures で高速化するテストスイート設計術
article2026年1月23日TypeScriptのtypeとinterfaceを比較・検証する 違いと使い分けの判断基準を整理
article2026年1月23日TypeScript 5.8の型推論を比較・検証する 強化点と落とし穴の回避策
article2026年1月23日TypeScript Genericsの使用例を早見表でまとめる 記法と頻出パターンを整理
article2026年1月22日TypeScriptの型システムを概要で理解する 基礎から全体像まで完全解説
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来
