tRPC と GraphQL 徹底比較:設計自由度・型安全・オーバーフェッチの実態
API 設計を検討する際、tRPC と GraphQL のどちらを選ぶべきか迷われる方は多いでしょう。特に「設計の自由度」「型安全性の実現方法」「オーバーフェッチ問題への対応」という 3 つの観点は、開発体験やアプリケーションのパフォーマンスに直結します。
本記事では、実際のコードや設計例を用いて tRPC と GraphQL を多角的に比較し、それぞれの強みと弱みを明らかにしていきます。また、どのような場面でどちらを選ぶべきかの判断基準もお伝えしますので、プロジェクトの技術選定にお役立てください。
背景
API 設計における共通の課題
現代の Web アプリケーション開発では、フロントエンドとバックエンドを明確に分離し、API を通じて連携させるアーキテクチャが主流です。しかし、従来の REST API には以下のような課題がありました。
REST API の 3 つの制約
| # | 課題 | 具体例 |
|---|---|---|
| 1 | エンドポイント管理の複雑化 | リソースごとに個別のエンドポイントが必要(/users、/posts、/comments など) |
| 2 | 型安全性の欠如 | フロントエンドとバックエンドで型定義が分離し、実行時エラーが発生しやすい |
| 3 | オーバーフェッチ・アンダーフェッチ | 必要以上のデータを取得したり、複数のリクエストが必要になったりする |
これらの課題を解決するために、GraphQL と tRPC という 2 つのアプローチが登場しました。
GraphQL の登場と特徴
GraphQL は Facebook(現 Meta)が 2015 年に公開したクエリ言語兼ランタイムです。単一のエンドポイントでクライアントが必要なデータを宣言的に取得できる点が最大の特徴といえるでしょう。
typescript// GraphQL クエリの例
// クライアント側で必要なフィールドを明示的に指定
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
posts {
title
createdAt
}
}
}
`;
このクエリ構文により、クライアントは必要なデータだけを要求できます。
tRPC の登場と特徴
一方、tRPC は TypeScript エコシステムに特化した RPC(Remote Procedure Call)フレームワークとして 2020 年に登場しました。TypeScript の型システムをそのまま活用し、コード生成なしで完全な型安全性を実現する点が特徴です。
typescript// tRPC プロシージャの例
// TypeScript の型がそのままクライアントに伝播する
const userRouter = router({
getById: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ input }) => {
return await db.user.findUnique({
where: { id: input.id },
});
}),
});
以下の図は、REST API、GraphQL、tRPC のアーキテクチャの違いを示しています。
mermaidflowchart TB
subgraph REST["REST API"]
rest_client["クライアント"] -->|"GET /users/:id"| rest_api["API"]
rest_client -->|"GET /posts?userId=:id"| rest_api
rest_api -->|"レスポンス1"| rest_client
rest_api -->|"レスポンス2"| rest_client
end
subgraph GraphQL["GraphQL"]
gql_client["クライアント"] -->|"単一クエリで<br/>必要データを指定"| gql_api["API(単一エンドポイント)"]
gql_api -->|"リクエスト通りの<br/>データのみ"| gql_client
end
subgraph tRPC["tRPC"]
trpc_client["クライアント<br/>(型情報あり)"] -->|"型安全なプロシージャ<br/>呼び出し"| trpc_api["API<br/>(型情報共有)"]
trpc_api -->|"型付きレスポンス"| trpc_client
end
図で理解できる要点:
- REST は複数エンドポイントで複数リクエストが必要
- GraphQL は単一エンドポイントで必要なデータを宣言的に取得
- tRPC は TypeScript の型システムで完全な型安全性を実現
課題
開発者が直面する 3 つの選択基準
tRPC と GraphQL のどちらを選ぶべきか判断する際、開発者は以下の 3 つの観点で悩むことが多いでしょう。
1. 設計自由度の違い
GraphQL はスキーマファーストの設計思想を持ち、独自の SDL(Schema Definition Language)でデータ構造を定義します。これにより柔軟なクエリが可能になる一方、学習コストや設計コストが高くなります。
一方、tRPC は TypeScript の既存の型システムをそのまま活用するため、追加の学習は最小限です。ただし、TypeScript プロジェクトに限定されるという制約があります。
2. 型安全性の実現方法
GraphQL の型安全性は、スキーマから TypeScript の型定義を生成するコード生成ツール(GraphQL Code Generator など)に依存します。このプロセスは自動化できますが、ビルドステップが増え、生成された型とスキーマの同期を保つ必要があります。
tRPC は TypeScript のコンパイラがそのまま型チェックを行うため、コード生成が不要です。サーバー側の型定義が自動的にクライアント側に伝播し、完全な End-to-End の型安全性が実現されます。
3. オーバーフェッチ問題への対応
オーバーフェッチとは、必要以上のデータを取得してしまう問題です。REST API では頻繁に発生しますが、GraphQL と tRPC ではどのように対処されているのでしょうか。
以下の図は、それぞれのアプローチにおけるデータ取得の流れを示しています。
mermaidsequenceDiagram
participant Client as クライアント
participant API as API
participant DB as データベース
Note over Client,DB: GraphQL のケース
Client->>API: クエリで必要フィールド指定<br/>{user{id,name}}
API->>DB: クエリに応じて<br/>必要データのみ取得
DB-->>API: id, name のみ
API-->>Client: 指定されたデータのみ
Note over Client,DB: tRPC のケース
Client->>API: プロシージャ呼び出し<br/>getUser({id})
API->>DB: プロシージャ実装に応じて<br/>データ取得
DB-->>API: 実装次第で全データor部分データ
API-->>Client: プロシージャの戻り値
図で理解できる要点:
- GraphQL はクライアントがクエリで必要なフィールドを指定できる
- tRPC はプロシージャの実装次第でオーバーフェッチが発生する可能性がある
比較検証の必要性
これらの観点を理論だけでなく、実際のコード例を用いて検証することで、それぞれの技術の適用場面を明確にできます。次のセクションでは、各観点における具体的な解決策を見ていきましょう。
解決策
1. 設計自由度の比較
GraphQL の設計アプローチ
GraphQL ではスキーマファーストの設計が基本となります。まず SDL でスキーマを定義し、それに基づいてリゾルバーを実装する流れです。
スキーマ定義(SDL)
graphql# GraphQL スキーマの定義
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
createdAt: DateTime!
}
この定義により、クライアントは柔軟にクエリを構築できます。
リゾルバーの実装
typescript// GraphQL リゾルバーの実装
const resolvers = {
Query: {
user: async (_parent, { id }, context) => {
return await context.db.user.findUnique({
where: { id },
});
},
},
User: {
// フィールドリゾルバー:必要に応じて posts を取得
posts: async (parent, _args, context) => {
return await context.db.post.findMany({
where: { authorId: parent.id },
});
},
},
};
GraphQL では、各フィールドに対してリゾルバーを定義できるため、データの取得ロジックを柔軟に制御できます。
tRPC の設計アプローチ
tRPC では TypeScript の型定義をそのまま活用し、プロシージャとして API を定義します。
プロシージャ定義
typescript// tRPC ルーターの定義
import { z } from 'zod';
import { router, publicProcedure } from './trpc';
export const userRouter = router({
// ユーザー取得プロシージャ
getById: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ input, ctx }) => {
const user = await ctx.db.user.findUnique({
where: { id: input.id },
});
return user;
}),
});
型の自動推論
typescript// クライアント側の型は自動的に推論される
// コード生成は不要
import { trpc } from './trpc-client';
const user = await trpc.user.getById.query({ id: '123' });
// user の型は自動的に推論される
// TypeScript の補完も完全に機能する
console.log(user.name); // 型安全
設計自由度の比較表
| 観点 | GraphQL | tRPC |
|---|---|---|
| スキーマ定義 | SDL(独自言語) | TypeScript |
| 学習コスト | 高い(SDL、リゾルバー、クエリ言語) | 低い(TypeScript の知識のみ) |
| クライアントの柔軟性 | 非常に高い(任意のフィールド選択) | 中程度(プロシージャの戻り値に依存) |
| エコシステム | 多様(Apollo、Relay、Urql など) | 限定的(TypeScript 専用) |
| 適用範囲 | 言語非依存 | TypeScript プロジェクトのみ |
結論: GraphQL は言語やクライアントを問わない柔軟性が魅力ですが、学習コストが高めです。tRPC は TypeScript に特化することで、シンプルさと開発効率を重視しています。
2. 型安全性の実現方法
GraphQL の型安全性
GraphQL で型安全性を実現するには、スキーマから TypeScript の型を生成するツールが必要です。
GraphQL Code Generator の設定
yaml# codegen.yml
# GraphQL スキーマから TypeScript 型を自動生成
schema: './src/schema.graphql'
generates:
./src/generated/graphql.ts:
plugins:
- typescript
- typescript-operations
- typescript-react-apollo
生成された型の利用
typescript// 生成された型をインポート
import {
GetUserQuery,
GetUserQueryVariables,
} from './generated/graphql';
// 型安全なクエリの実行
const { data } = await client.query<
GetUserQuery,
GetUserQueryVariables
>({
query: GET_USER,
variables: { id: '123' },
});
// data.user は型付けされている
console.log(data.user.name);
GraphQL では、スキーマ変更時に型を再生成する必要があるため、ビルドプロセスにステップが追加されます。
tRPC の型安全性
tRPC では TypeScript の型推論を直接活用するため、コード生成は不要です。
サーバー側の型定義
typescript// サーバー側でプロシージャを定義
export const appRouter = router({
user: userRouter,
post: postRouter,
});
// AppRouter 型をエクスポート
export type AppRouter = typeof appRouter;
クライアント側での型利用
typescript// クライアント側で AppRouter 型をインポート
import type { AppRouter } from './server/routers/_app';
import {
createTRPCProxyClient,
httpBatchLink,
} from '@trpc/client';
// 型安全なクライアントを作成
const client = createTRPCProxyClient<AppRouter>({
links: [
httpBatchLink({
url: 'http://localhost:3000/api/trpc',
}),
],
});
// 完全な型安全性と補完
const user = await client.user.getById.query({ id: '123' });
console.log(user.name); // 型エラーが即座に検出される
型安全性の比較表
| 観点 | GraphQL | tRPC |
|---|---|---|
| 型の生成 | 必要(Code Generator) | 不要(型推論) |
| ビルドステップ | 増加する | 変化なし |
| 型の同期 | スキーマと型の同期が必要 | 自動的に同期される |
| リアルタイム型チェック | 生成後のみ | 常時(TypeScript コンパイラ) |
| 型の精度 | 高い | 非常に高い(End-to-End) |
結論: GraphQL は型生成プロセスが必要ですが、tRPC は TypeScript の型システムをそのまま活用するため、追加のビルドステップなしで完全な型安全性が実現されます。
3. オーバーフェッチ問題への対応
GraphQL のアプローチ
GraphQL の最大の強みは、クライアントが必要なフィールドのみを指定できる点です。
必要なデータのみを取得
typescript// 名前とメールアドレスのみを取得するクエリ
const GET_USER_BASIC = gql`
query GetUserBasic($id: ID!) {
user(id: $id) {
name
email
}
}
`;
typescript// ユーザー情報と投稿一覧を同時に取得するクエリ
const GET_USER_WITH_POSTS = gql`
query GetUserWithPosts($id: ID!) {
user(id: $id) {
name
email
posts {
title
createdAt
}
}
}
`;
クライアントの要求に応じて、API は必要なデータのみを返します。
tRPC のアプローチ
tRPC では、プロシージャの実装次第でオーバーフェッチが発生する可能性があります。これを防ぐには、複数のプロシージャを用意するか、入力パラメータでオプションを制御します。
複数プロシージャで対応
typescript// 基本情報のみを取得するプロシージャ
export const userRouter = router({
getBasic: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ input, ctx }) => {
return await ctx.db.user.findUnique({
where: { id: input.id },
select: { id: true, name: true, email: true },
});
}),
});
typescript// 投稿も含めて取得するプロシージャ
export const userRouter = router({
getWithPosts: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ input, ctx }) => {
return await ctx.db.user.findUnique({
where: { id: input.id },
include: { posts: true },
});
}),
});
オプションパラメータで制御
typescript// オプションで取得データを制御するプロシージャ
export const userRouter = router({
getById: publicProcedure
.input(
z.object({
id: z.string(),
includePosts: z.boolean().optional(),
})
)
.query(async ({ input, ctx }) => {
return await ctx.db.user.findUnique({
where: { id: input.id },
include: {
posts: input.includePosts ?? false,
},
});
}),
});
オーバーフェッチ対策の比較表
| 観点 | GraphQL | tRPC |
|---|---|---|
| 柔軟性 | 非常に高い(任意のフィールド選択) | 中程度(プロシージャ設計次第) |
| 実装コスト | 低い(クエリのみで制御) | 中程度(複数プロシージャまたはオプション) |
| パフォーマンス最適化 | 容易(N+1 問題に注意) | プロシージャ設計次第 |
| 学習コスト | クエリ言語の学習が必要 | TypeScript の知識で対応可能 |
結論: GraphQL はクライアント側で柔軟にデータ取得を制御できるため、オーバーフェッチ問題への対応が容易です。tRPC では、プロシージャの設計やオプションパラメータで対応する必要があります。
具体例
実践シナリオ:ブログアプリケーションの API 設計
ユーザー情報と投稿記事を管理するブログアプリケーションを想定し、GraphQL と tRPC の実装例を比較してみましょう。
要件定義
以下の機能を実装します:
- ユーザー情報の取得(基本情報のみ)
- ユーザー情報と投稿一覧の取得
- 投稿記事の作成
- 投稿記事の一覧取得(ページネーション付き)
以下の図は、両者のデータフロー比較を示しています。
mermaidflowchart LR
subgraph GraphQL_Flow["GraphQL のデータフロー"]
gql_client["クライアント"]
gql_query["クエリ構築"]
gql_api["GraphQL API"]
gql_resolver["リゾルバー"]
gql_db[("データベース")]
gql_client -->|"1. クエリ定義"| gql_query
gql_query -->|"2. 送信"| gql_api
gql_api -->|"3. 解析"| gql_resolver
gql_resolver -->|"4. データ取得"| gql_db
gql_db -->|"5. 必要データのみ"| gql_resolver
gql_resolver -->|"6. レスポンス"| gql_client
end
subgraph tRPC_Flow["tRPC のデータフロー"]
trpc_client["クライアント<br/>(型付き)"]
trpc_proc["プロシージャ呼び出し"]
trpc_api["tRPC API"]
trpc_handler["ハンドラー実装"]
trpc_db[("データベース")]
trpc_client -->|"1. プロシージャ指定"| trpc_proc
trpc_proc -->|"2. 送信(型安全)"| trpc_api
trpc_api -->|"3. 実行"| trpc_handler
trpc_handler -->|"4. データ取得"| trpc_db
trpc_db -->|"5. 実装次第のデータ"| trpc_handler
trpc_handler -->|"6. 型付きレスポンス"| trpc_client
end
図で理解できる要点:
- GraphQL はクエリの解析とリゾルバーによる柔軟なデータ取得
- tRPC は型安全なプロシージャ呼び出しとハンドラー実装による処理
GraphQL の実装例
スキーマ定義
graphql# GraphQL スキーマ
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
createdAt: DateTime!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
createdAt: DateTime!
}
graphql# クエリとミューテーションの定義
type Query {
user(id: ID!): User
posts(limit: Int!, offset: Int!): PostConnection!
}
type Mutation {
createPost(input: CreatePostInput!): Post!
}
input CreatePostInput {
title: String!
content: String!
authorId: ID!
}
リゾルバー実装
typescript// ユーザー取得リゾルバー
const resolvers = {
Query: {
user: async (_parent, { id }, { db }) => {
return await db.user.findUnique({
where: { id },
});
},
},
};
typescript// フィールドリゾルバー(投稿一覧)
const resolvers = {
User: {
posts: async (parent, _args, { db }) => {
return await db.post.findMany({
where: { authorId: parent.id },
});
},
},
};
typescript// 投稿作成ミューテーション
const resolvers = {
Mutation: {
createPost: async (_parent, { input }, { db }) => {
return await db.post.create({
data: {
title: input.title,
content: input.content,
authorId: input.authorId,
},
});
},
},
};
クライアント側の実装
typescript// ユーザー情報のみを取得
const { data } = await client.query({
query: gql`
query GetUser($id: ID!) {
user(id: $id) {
name
email
}
}
`,
variables: { id: '123' },
});
console.log(data.user.name);
typescript// ユーザー情報と投稿一覧を同時に取得
const { data } = await client.query({
query: gql`
query GetUserWithPosts($id: ID!) {
user(id: $id) {
name
email
posts {
title
createdAt
}
}
}
`,
variables: { id: '123' },
});
tRPC の実装例
ルーター定義
typescript// ユーザールーター
import { z } from 'zod';
import { router, publicProcedure } from './trpc';
export const userRouter = router({
// 基本情報のみ取得
getBasic: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ input, ctx }) => {
return await ctx.db.user.findUnique({
where: { id: input.id },
select: { id: true, name: true, email: true },
});
}),
});
typescript// 投稿も含めて取得
export const userRouter = router({
getWithPosts: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ input, ctx }) => {
return await ctx.db.user.findUnique({
where: { id: input.id },
include: { posts: true },
});
}),
});
typescript// 投稿ルーター
export const postRouter = router({
// 投稿一覧取得(ページネーション)
list: publicProcedure
.input(
z.object({
limit: z.number().min(1).max(100),
offset: z.number().min(0),
})
)
.query(async ({ input, ctx }) => {
const posts = await ctx.db.post.findMany({
take: input.limit,
skip: input.offset,
});
return posts;
}),
});
typescript// 投稿作成
export const postRouter = router({
create: publicProcedure
.input(
z.object({
title: z.string().min(1),
content: z.string(),
authorId: z.string(),
})
)
.mutation(async ({ input, ctx }) => {
return await ctx.db.post.create({
data: input,
});
}),
});
クライアント側の実装
typescript// tRPC クライアントの設定
import type { AppRouter } from './server/routers/_app';
import {
createTRPCProxyClient,
httpBatchLink,
} from '@trpc/client';
const trpc = createTRPCProxyClient<AppRouter>({
links: [
httpBatchLink({
url: 'http://localhost:3000/api/trpc',
}),
],
});
typescript// ユーザー基本情報の取得(型安全)
const user = await trpc.user.getBasic.query({ id: '123' });
console.log(user.name); // 型推論が効く
typescript// ユーザー情報と投稿一覧の取得
const userWithPosts = await trpc.user.getWithPosts.query({
id: '123',
});
console.log(userWithPosts.posts[0].title); // 完全な型安全性
typescript// 投稿の作成
const newPost = await trpc.post.create.mutate({
title: 'tRPC 入門',
content: 'tRPC の基本的な使い方を解説します',
authorId: '123',
});
// newPost の型も自動的に推論される
実装比較のまとめ表
| 観点 | GraphQL | tRPC |
|---|---|---|
| コード量 | 多い(スキーマ + リゾルバー) | 少ない(プロシージャのみ) |
| 型生成 | 必要(codegen) | 不要(型推論) |
| データ取得の柔軟性 | 高い(クエリで制御) | 中程度(プロシージャ設計次第) |
| 学習コスト | 高い(SDL、クエリ言語) | 低い(TypeScript のみ) |
| 開発効率 | 中程度 | 高い(型推論の恩恵) |
| パフォーマンス | 最適化が容易 | プロシージャ実装次第 |
まとめ
tRPC と GraphQL の選択基準
本記事では、tRPC と GraphQL を「設計自由度」「型安全性」「オーバーフェッチ対策」の 3 つの観点から徹底的に比較してまいりました。それぞれの技術には明確な強みと弱みがあり、プロジェクトの要件に応じて適切に選択することが重要です。
GraphQL を選ぶべき場面
以下の条件に当てはまる場合は GraphQL が適しています:
| # | 条件 | 理由 |
|---|---|---|
| 1 | 複数のクライアント(Web、モバイルアプリ、サードパーティ)がある | 言語非依存で柔軟なクエリが可能 |
| 2 | クライアントごとに必要なデータが大きく異なる | 各クライアントが必要なフィールドのみを取得できる |
| 3 | パブリック API を提供する予定がある | スキーマベースで API 仕様が明確 |
| 4 | 複雑なデータ関係を扱う | リレーションシップの表現が得意 |
| 5 | エコシステムの豊富さを重視する | Apollo、Relay などの成熟したツールが利用可能 |
tRPC を選ぶべき場面
以下の条件に当てはまる場合は tRPC が適しています:
| # | 条件 | 理由 |
|---|---|---|
| 1 | フロントエンドとバックエンドが同一リポジトリにある | 型の共有が容易 |
| 2 | TypeScript プロジェクトである | 型推論の恩恵を最大限に受けられる |
| 3 | 開発スピードを最重視する | 学習コストが低く、コード生成不要 |
| 4 | チーム規模が小〜中規模である | シンプルな設計で保守しやすい |
| 5 | 社内向け API である | 柔軟性よりも型安全性と開発効率を優先できる |
最終的な判断ポイント
両技術の選択は、以下の 3 つの質問で判断できるでしょう:
質問 1:クライアントの多様性
複数の異なるクライアント(Web、iOS、Android、サードパーティ)が存在する、または将来的に増える可能性がある場合は GraphQL が有利です。単一または少数のクライアントであれば tRPC で十分でしょう。
質問 2:型安全性へのこだわり
End-to-End の完全な型安全性をコード生成なしで実現したい場合は tRPC が最適です。型生成プロセスを許容できるなら GraphQL でも問題ありません。
質問 3:学習コストと開発効率
チームが TypeScript に精通しており、すぐに開発を始めたい場合は tRPC が適しています。一方、長期的な柔軟性や拡張性を重視し、学習コストを投資と考えられるなら GraphQL が向いています。
これからの展望
GraphQL は既に成熟した技術として広く採用されており、エコシステムも充実しています。一方、tRPC は比較的新しい技術ですが、TypeScript エコシステム内での採用が急速に進んでいます。
どちらの技術も REST API の課題を解決するための強力なツールです。プロジェクトの特性、チームのスキルセット、将来の拡張性を総合的に考慮し、最適な選択を行ってください。
関連リンク
tRPC 公式ドキュメント
GraphQL 公式ドキュメント
TypeScript リソース
比較記事・参考資料
articletRPC と GraphQL 徹底比較:設計自由度・型安全・オーバーフェッチの実態
articletRPC 使い方入門:Todo API を 50 行で作るフルスタック体験
articletRPC アーキテクチャ設計:BFF とドメイン分割で肥大化を防ぐルータ戦略
articletRPC チートシート:Router/Procedure/ctx/useQuery/useMutation 早見表
articletRPC の始め方:Next.js App Router と Zod を使った最小構成テンプレート
articletRPC とは?型安全なフルスタック通信を実現する仕組みとメリット【2025 年版】
articleSolidJS コンポーネント間通信チート:Context・イベント・store の選択早見
articleWebLLM 中心のクライアントサイド RAG 設計:IndexedDB とベクトル検索の組み立て
articleShell Script の set -e が招く事故を回避:pipefail・サブシェル・条件分岐の落とし穴
articleRuby の本番運用ガイド:ログ設計・メトリクス・トレースのベストプラクティス
articleVitest テストデータ設計技術:Factory / Builder / Fixture の責務分離と再利用
articleRedis キーネーミング規約チートシート:階層・区切り・TTL ルール
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 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来