宮水の日記

宮水の日記

主に書評や資格取得について記事を書いています。

「プロダクトマネジメントのすべて」を読みました

プロダクトマネジメントのすべて」を読みました。

なぜ読んだのか

  • プロダクトマネージャー(以下PM)さんが何をしているのかちゃんと理解したいから。
  • 個人開発でどんな機能を追加した方がいいのか考えるきっかけにしたいから。

対象読者

  • PMを目指す人
  • 新米PM
  • PMとして働いている人
  • プロダクトマネジメントに関わるエンジニア、デザイナー、マーケター、事業推進者

この本で学べること

本の概要

Chapter1 プロダクトの成功とは
  • プロダクトの成功を定義するのは、ビジョン、ユーザー価値、事業収益の3つ。
  • PMFとは、強力な価値仮説を見つけること。価値仮説とは、なぜユーザーや顧客があなたのプロダクトを使うのか説明しうる重要な仮説のこと。
Chapter2 プロダクトマネージャーの役割
  • プロダクトを育てること、ステークホルダーをまとめプロダクトチームを率いることの2種類の役割がある。
  • PMはプロダクトを成功させることに責任を持つ。プロダクトに関係する意思決定を実施し、プロダクトチームを率いる。(よく対比されるプロジェクトマネージャーはプロジェクトの品質、費用、納期に責任を持つ。そもそも概念が違うので、比較するものではない。)
Chapter3 プロダクトマネージャーの仕事とスキルの全体像
  • Core, Why, What, Howの4階層から、プロダクト全体に一気通貫した強い軸をつくる。
  • PMに必要なスキルは、発想力、計画力、実行力、仮説検証力、リスク管理力、チーム構築力の6つ。
Chapter4 プロダクトの4階層
  • プロダクトのCore: ミッションとビジョン、事業戦略
  • プロダクトのWhy: 「誰」を「どんな状態にしたいか」、なぜ自社がするのか
  • プロダクトのWhat: ユーザー体験、ビジネスモデル、ロードマップ
  • プロダクトのHow: ユーザーインターフェース、設計と実装、Go to Merketなど
  • プロダクトの方針のフレームワークには、「リーンキャンバス」スケジュールとゴールを作成する「マイルストーン」がある。
  • プロダクトをつくるには、仮説検証が重要。実用最小限の単位でプロダクトを作り価値検証を促したり、チームでアイデアを出し合ったりするのが良い。
Chapter5 プロダクトのCore
  • プロダクトの世界観(ミッション、ビジョン)と企業への貢献(事業戦略)の2つのことを考える。
  • プロダクトの世界観とは、「プロダクトを提供することでどのような未来を作りたいのか」
  • 事業戦略は、「プロダクトが戦うドメインとそのドメインでの勝ち筋を描くこと」
Chapter6 プロダクトのWhy
  • 「誰」を「どんな状態にしたいか」と「なぜ自社がするのか」を考える。
  • 以下のようなフレームワークを使う。

- バリュー・プロポジションキャンバス ... プロダクトとサービスを説明する「バリューマップ」とユーザーについて説明する「カスタマープロフィール」を書く
- PEST分析 ... 「Plotics: 政治」「Economy: 経済」「Society: 社会」「Technology: 技術」の4つの視点で外部環境を分析するフレームワーク
- SWOT分析 ... 自社の強みと弱みを可視化するためのフレームワーク
- STP分析 ... 自社のポジショニングを確立し、ターゲットを絞り込みたいときに使う。
- ユーザーインタビュー

Chapter7 プロダクトのWhat
  • 何をつくり、どのような優先度で取り組むのかを検討する。
  • ユーザー体験 ... UIに当たるのは、カップやBGMなどのユーザーが触れるもの。ユーザー体験(UX)とは、「土曜日の午後におしゃれなカフェで素敵な音楽を聴きながらゆっくりカフェラテを飲む体験」のこと。ユーザーを理解するために、ペルソナやメンタルモデルダイアグラムを作る。
  • ビジネスモデル ... プロダクトがビジネスとして成立するかどうかは、ビジネスモデルキャンバスを用いて考える。また、ユーザーインタビューも有効である。
  • ロードマップ ... プロダクトを開始してから向かうべき経過地点をあらかじめいくつか設定しておき、明確なゴールの場所が定まらなくても着実にゴールに近づいていくための行程表。KPIなどの指標を定め、達成できているか定期的に確認する。
  • Whatが定まったら、一つ上の階層であるWhyの部分とずれていないか確認する。プロダクトのWhat検討後に気をつけるべきポイントも考慮する。
Chapter8 プロダクトのHow
  • プロダクトのCoreからWhatで見てきた内容について「どのように実現するのか」を検討する。
  • プロダクトバックログ(プロダクトに求められている機能や仕組みのリスト)を作る
  • 利用規約や適切な価格を設定する
  • 障害に備える
  • リリースが終わったら、振り返りをする
Chapter9 プロダクトマネージャーを取り巻くチーム
  • PMは一般的に、プロダクトチームと機能型組織(プロダクトマネジメント部)の2つのチームに所属する。
  • PMの仕事で重要なのは、ステークホルダーとの関係性
  • RACI ... チームメンバーの責任分担を明確にする手法
Chapter 10 チームとステークホルダーを率いる
  • コミュニケーションを深める方法について。

- プロダクトの全体像 / スケジュール / 優先度 / 進捗を可視化する
- 心理的安全性大事
- インセプションデッキを使用する
- ふりかえり大事

Chapter 11 チームでプロダクトを作るためのテクニック
  • チームでプロダクトをつくる際に有効な5つのテクニック

- ドキュメンテーション
- 共有や公開、レビューがしやすい適切なツールを選定する。
- コーチン
- チームメンバーの目標到達のための支援をすること
- ファシリテーション
- 集団活動の進行。参加者の役割を決めたり、事前準備、議論の活発化などを促す。
- プレゼンテーション
- 情報量は必要最小限に、伝えたいことが伝えられるように訓練する。
- ネゴシエーション
- 多様なステークホルダーをマネジメントするために必要になるのが交渉力。交渉相手の関係性の度合いと継続性を加味して交渉する。

Chapter 12 プロダクトステージによるふるまい方の違い

プロダクトの置かれた状況別にPMgaどのように振る舞うのかについて

  • プロダクトライフサイクルについて
  • カスタマーアダプションについて
  • 0→1、1→10、10→100のライフサイクルについて
  • プロダクトに見切りをつけたときに気をつけること
Chapter 13 ビジネス形態によるふるまい方の違い
  • BtoCのPMに求められるのは、「機敏さ」。ユーザーの反応を素早く集め、ユーザーのプロダクト体験を常にアップデートし、いかにして継続して使ってもらうかが勝負。
  • BtoBのPMに求められるのは、業界特有の商習慣に対する深い関心、ユーザーとユーザーを取り巻くステークホルダーに対する想像力、優先度のつけ方のバランス。
Chapter14 未知のビジネスドメインに挑む
  • ビジネスドメイン知識を学ぶ。ドメイン知識を獲得するために現場に入り込む必要がある。
  • 未知のビジネスドメインを学ぶには、「プロダクトランドスケープ」「モチベーション分析」「対立スコープ」「トレードオフの発見」などがある。ビジネスドメインを学んだら、その知識をプロダクトチームで理解すると良い。
Chapter15 技術要素の違いによるふるまい方の違い
  • ハードウェア、AI、ソフトウェアなどの技術要素の違いによって、PMが求められるふるまい方が異なる。
Chapter 16 プロダクトマネージャーと組織の成長
  • プロダクトマネジメントが根付いていない組織に所属する場合、まずは共通の課題認識を持つところから始める。
  • ジョブディスクリプションを作成し、各従業員の責務を明確にする。
Chapter 17 プロダクトマネージャーのスキルの伸ばし方
  • PMになるために、ビジネス、UX、テクノロジーのどれかについて自分が自信がもてる領域を作る。
  • W型モデルで自分のスキルをマッピングし、自分の持ち合わせていないスキルや十分に足りていないスキルを可視化して、今後どのように成長していくか検討する。
Chapter 18 プロダクトマネージャーのキャリア
  • PMは担当範囲や担当プロダクトの重要性や複雑さによって高いスキルが要求される。
  • PMを務めた後も、キャリアに色々な選択肢がある。
Chapter 19 ビジネスの基礎知識
  • 様々な収益モデルについて
  • パートナーシップについて
  • 知的財産の扱いについて
Chapter 20 UXの基礎知識
  • デザインを学ぶためのマインドセットや、デザイン6原則について。
  • デザイナーに意図を的確に伝えるために、ペルソナの設定をしっかり揃えたり、ワイヤーフレームや画面遷移を表現すると良い。
  • プライバシーポリシーと利用規約について。
Chapter 21 テクノロジーの基礎知識
  • プロダクトの品質を保つ上で、QAの知識、狩野モデルの利用、ソフトウェアテストなどの知識を持っておくと良い。
  • 開発手法の基礎知識としては、DevOps、ウォーターフォール開発とアジャイル開発などの知識を持っておくと良い。
  • ソフトウェアの基礎知識としては、ソフトウェアがプログラミング言語で動いていること、アーキテクチャ、ネットワークの仕組み、データベースの基本、セキュリティなどの知識を持っておくと良い。

感想

とても読み応えのある本でした。私の中でプロダクトマネージャーとプロジェクトマネージャーがごっちゃになっていることがわかりました。
プロダクトマネージャーさんが、どういった役割を持っているのか、普段どういったことを勉強されているのか知ることができてよかったです。
また、本書の知識は個人開発のプロダクトにも色々と応用できそうでした。こうやって別の職種の方の本を読むのもいいですね!

ここまでお読みいただきありがとうございました!

「WEB+DB PRESS Vol. 122『特集3 作って学ぶ RDBMS のしくみ』」を読みました。

WEB +DB PRESS 〜作って学ぶRDBMSのしくみ〜を読みました。

なぜ読んだのか

  • SQLRDBMSの本を読んでいたら、内部の構造が知りたくなったから。

この本で学べること

  • ミニRDBMSを実際に作りながらその内部を知り、RDBMSをもっと活用できるようになる。

本の概要

第1章 RDBMSを作ろう

RDBMSは以下の層で構成されている。本書では、ディスクマネージャー〜クエリプランナまでを作成する。
- 構文解析器 ... クエリの構文解析
- クエリプランナ ... 実行計画の最適化・決定
- クエリエクスキュータ ... 実行計画どおりにアクセスメソッドを呼び出す
- アクセスメソッド ... ディスク上のデータ構造をたどる
- バッファプールマネージャ ... データの塊をメモリにキャッシュする
- ディスクマネージャ ... データの塊をディスクに書く・読む

本書で作るDBは、テーブル作成、行の挿入、行のクエリ、セカンダリインデックスなどの機能を持つ。トランザクションや複数のテーブル、JOINなどは対応しない。

第2章 ディスクマネージャの実装
  • ディスクマネージャは、ファイルの読み書きを担っているコンポーネント
  • Rustでヒープファイルを新しく作ったり、ページを書き込んだり読みだしたりする機能を実装する。
第3章 バッファプールマネージャの実装
  • バッファプールマネージャは、ページの内容をメモリ上にキャッシュすることでディスクの遅さを隠蔽する役割がある。一度読んだページをメモリに保持しておく。
  • どのバッファを捨てるか決めるClock-sweepアルゴリズムは、PostgreSQLでも採用されている。
  • バッファがない場合、バッファがいっぱいになった場合、ページの貸し出しといった処理を実装する。
第4章 B+Treeの観察
  • B+Treeをアクセスメソッドのデータ構造とアルゴリズムとして利用する。
  • B+Treeは挿入、検索、削除などの計算量がいずれもO(log n)でありバランスがよく、範囲検索・列挙が得意。
第5章 テーブルの実装
  • B+Treeにテーブルを格納する
第6章 セカンダリインデックスの実装
  • セカンダリインデックスとは、検索しやすい形に変形されたデータ構造のこと。

感想

ちゃんと実装したわけじゃないのですが、RDBMSが何で構成されているのか、B+Treeのアルゴリズムについて雰囲気だけわかったので面白かったです。

ここまでお読みいただきありがとうございました!

「達人に学ぶDB設計徹底指南書」を読みました

「達人に学ぶDB設計徹底指南書」を読みました。

なぜ読んだのか

基本情報を取ったときに読んだ本で、初心に返りたかった。

対象読者

  • DBエンジニア
  • DB設計を初級者で終わりたくない人

この本で学べること

  • リレーショナルデータベースの論理設計と物理設計について

本の概要

第1章 データベースを制する者は、システムを制す
  • 「データベース」と「DBMS」は異なる。「データベース」はデータの集合を指す論理的概念であるのに対し、「データベース」を管理するためのシステムを「DBMS」という。
第2章 論理設計と物理設計
  • 概念スキーマを定義する設計を論理設計と呼ぶ。論理とは、「物理層の制約にとらわれない」という意味。ER図などを書いて設計する。
  • 物理設計は、論理設計の結果を受けてデータを格納する頼め物理的な領域や格納方法を決める工程。容量、冗長構成、ファイルの物理配置(データベースのファイルをどのディスクに保存するか)などを検討する。
  • バックアップ設計とリストア設計についても触れていた。
第3章 論理設計と正規化 〜なぜテーブルは分割する必要があるのか?〜
  • テーブルとは、共通点を持ったレコードの集合である。
  • 正規化は、データの更新の不都合/不整合を排除するために行う。
  • 第一正規形は「一つのセルの中には一つの値しか含まない」
  • 第二正規形は「部分関数従属を解消する」ことで得られる。

- 部分関数従属とは、主キーの一部の列に対して従属する関係のこと。
- 結合すると、第一正規形のテーブルに戻すことができる。

  • 第三正規形は「推移的関数従属を解消する」ことで得られる。

-推移的関数従属とは、 {社員ID}→{部署コード}→{部署名}のように、テーブル内部に存在する段階的な従属関係のこと。

  • テーブルの正規化は簡単だが、「なぜ正規化しなければならないのか」「正規化のメリット」を説明できる人は少ない。
第4章 ER図 〜複数のテーブルの関係を表現する〜
  • ER図の書き方について
第5章 論理設計とパフォーマンス 〜正規化の欠点と非正規化
  • 正規化とSQLのパフォーマンスはトレードオフの関係にある。
  • 正規化すると、データを集計するときに結合が必要になり、パフォーマンスが落ちる。対処法として、テーブルを非正規形の形に戻したり、冗長なカラム(商品数やいいねの数など)を作る方法がある。
  • どちらも正解はない。ケースバイケースで実装する。
第6章 データベースとパフォーマンス
  • DBMSSQLを受け取ったあとたくさんの経路の中から最短経路を選択し、SQL手続きに変換する。経路はDBMSがお任せで決めてくれる。
  • B-treeインデックスはバランスの良いインデックス。計算量はO(log n)となり、データが増えても検索や更新にかかる時間はほとんど増えない。
第7章 論理設計のバッドノウハウ
  • 配列型は利用しない。あとから結合されたものを分割するのは難しい。
  • テーブルにポリモルフィズムはいらない。
  • レコード単位で分割する「水平分割」をするとどんどんテーブルが増えてしまうので×
  • 列単位でテーブルを分割する「垂直分割」は、定期的にデータの同期が必要になるデメリットがある。
第8章 論理設計のグレーノウハウ
  • 主キーがないテーブルに主キーを作る方法
  • 行持ち、列持ちテーブル
  • データクレンジングについて
第9章 一歩進んだ論理設計 〜SQL木構造を扱う〜
  • SQL木構造を扱うのが苦手。方法としては以下のようなモデルがある。

- 隣接リストモデル
- 入れ子集合モデル
- 入れ子区間モデル
- 経路列挙モデル

感想

今までもDB設計は業務でやったことがあり、本書を読んでいて、「普通に」考えたらそうなるでしょ、「普通に」考えたらそんな設計にはならないのでは?と思う箇所がたくさんありました。しかしながら、この「普通」について、なぜ必要なのか、なぜいけないのかちゃんと考えたことはありませんでした。DB設計の基本を丁寧に説明されている本だと思いました!
三年くらい前に一度目を通した本でしたが、あたらめて読んでみると新しい発見がありました。読んで良かったです。

ここまでお読みいただきありがとうございました!

「達人に学ぶSQL徹底指南書」 を読みました

達人に学ぶSQL徹底指南書 を読みました。

対象読者

  • 実務でのSQLプログラミングの経験が半年から1年くらいある方
  • レベルによらず、「SQLとは何なのか」知りたいと思っている方々

この本で学べること

  • CASE式、ウィンドウ関数、外部結合、相関サブクエリ、HAVING句、EXISTS述語などのSQLの道具を取り上げて、それらの便利な使い方をサンプルケースを通じて学んでいく。
  • SQLの原理となっている仕組みや、この言語を作った人々が何を考えて現在の形にしたのかというバックグラウンドを学ぶ。

本の概要

1. CASE式のススメ
  • CASE式を使えば、異なる条件の集計を1つのSQLで行える。例えば、県名と人口のテーブルを、「四国」「九州」などで括って集計できる。条件の異なるUPDATEを一度にかけられる。CASE式の中で集約関数(SUM、MAX、COUNTなど)を使うことができ、複数のSQL文を一つにまとめられ、可読性もパフォーマンスも向上する。
  • CASE"文"ではなく、CASE"式"であるがゆえに、実行時には評価されて一つの値に定まる。「1+1」や「a + b」などと一緒。式だから、SELECT句にもGROUP BY句にもWHERE句にもORDER BY句にも書くことができる。(※ 式と文の違いを調べてみたら、例えば「a = 1 + 2」が文で、「1+2」が式っぽいです。)
2. 必ずわかるウィンドウ関数
  • ウィンドウとは「範囲」という意味。ざっくりいうとウィンドウ関数は手続き型でいうfor文やwhile文に似ている。

1. PARTITION BY句によって、レコードの集合のカット(カットとは、母集合のレコードから操作したいレコードを集めて部分集合を作ること)
2. ORDER BY句でレコードを順序付け
3. フレーム句で、カレントレコードを中心に処理を行っていく
f:id:kattyan53:20211010224226p:plain

3. 自己結合の使い方

自己結合を使うと、

  • 重複順列・順列・組み合わせ
  • 重複行の削除
  • 部分的に不一致なキーの検索(同じ家族レコードだけど、住所が違う)

などをしたいときに応用が効く。

4. 3値論理とNULL
  • NULLには「未知」と「適用不能」の2種類がある。NULLは値でも変数でもない。
5. EXISTS述語の使い方
  • SQLに置ける述語とは、戻り値が真理値(true, false, SQLの世界ではunknownも)になる関数のこと。
  • EXISTS / NOT EXISTSを応用すれば、テーブルに存在しないデータを検索できる。
6. HAVING句の力
  • HAVING句はCASE式や自己結合といった他の武器と組み合わせると真価を発揮する
  • 探したいデータがあるときは、線と資格ではなく円(ベン図)を書く
  • 歯抜けのデータを探せる
  • 最頻値を探せる
  • NULLを含まないデータを抽出できる
7. ウィンドウ関数で行間比較を行う
  • 行間の比較は、昔は相関サブクエリを使っていたが、今はパフォーマンスや可読性の観点からウィンドウ関数が使われている。
  • 以下のようなテーブルで、前年より売上が上がったのか、下がったのか、変わらなかったのかみたいなデータを抽出できる。

f:id:kattyan53:20211011223912p:plain

8. 外部結合の使い方
  • 本来、SQLは検索のためのクエリであって、表の再形成には向いてない。
  • この章では、外部結合やCASE式を駆使していろんなテーブルの整形を行う。
9. SQLで集合演算
  • 和(UNION), 交差(INTERSECT), 差(EXCEPT)は最近標準に入った。
  • 除算(DIVIDE BY)はまだ実装されていないので、自前で作る必要がある。
  • 和(UNION)を応用して、2つのテーブルが等しいか否か調べたりできる。
10. SQLで数列を扱う
  • SQLで数列や順序集合を扱う方法について
11. SQLを速くするぞ

SQLを早くするテクニックについて学びます。

  • 暗黙裡にソートが使われる関数を使わないようにする
  • GROUPBY句とORDERBY句でインデックスを使う
  • 中間テーブルをなくし、HAVING句を活用する
  • 早い段階でレコード数が絞れるなら絞る
12. SQLプログラミング作法

全ての言語に共通するような話

  • わかりやすいカラム名をつける、インデント、スペース、大文字と小文字、カンマの位置

SQL独特の作法

  • SQLの世界はコメント推奨
  • PostgreSQLOracleMySQLなど方言が強いので、いつか移行するかもしれないことを視野に入れて標準語で書くようにする。
13. RDB 近現代史
  • RDBは従来の階層型DBを置き換えた破壊的イノベーション。エンジニアが扱うものとされていたデータベースをエンドユーザーが扱えるものにしようとした。
  • RDBは、非循環グラフ(例えば、組織図)やネットワーク構造(例えば、SNS)を表すのが苦手。
  • 近年NoSQLの製品群が登場しているが、RDBの補完的関係として共存する可能性が高い。
14. なぜ"関係"モデルという名前なのか?(なぜ表モデルではないのか)

簡単にいうと、関係モデルは数学の集合論を基礎に作られたので、使われる用語も集合論の用語を流用している。関係と表は、以下のような違いがある。

  • 関係には重複する組みは存在してはならないが、表には存在しても良い。
  • 関係の組は上から下へ順序付けられていないが、表の行は上から下へ順序付けられている。
  • 関係の属性は左から右へ順序付けられていないが、表の列は左から右へ順序付けられている。
  • 関係のすべての属性値は分割不可能だが、表の列の値は分割可能である。
15. 関係に始まり関係に終わる
  • SQLが持っている面白い性質の一つ、「閉包性」について。
  • 演算時の入力と出力が共に関係になる、関係の世界が閉じていることを保証する性質のこと。
  • 関係が閉包性を満たすおかげで、これらの演算の出力を、別の演算の入力にすることが可能になる。
16. アドレス、この巨大な怪物
  • SQLでは、ポインタが隠蔽されている。そうすることで、人間が認識しやすい有意味な世界を作り上げようとした。
17. 順序をめぐる冒険
  • ウィンドウ関数の登場は、なぜこんなに遅かったのか。
  • SQLには、「行は順序を持つべきではない」という思想があったから。
18. GROUP BY とPARTITION BY
  • どちらもほぼ似たような動きをする
  • PARTITION BYは数学でいう「類」の概念に由来して付けられた
  • GROUP BYは個々の要素を集合に振り分ける機能を持つ
19. 手続き型から宣言型・集合指向へ頭を切り替える7箇条

① if文やcase文はcase式で置き換える。
② ループはGROUP BY 句とウィンドウ関数で置き換える
③ テーブルの行に順序はない
④ テーブルを集合とみなそう
⑤ EXISTS述語と「量化」の概念を理解しよう
⑥ HAVING句の真価を学ぶ
⑦ 四角では無く、円を描く

20. 神のいない論理
  • 3値論理の歴史について
21. SQL再帰集合
  • 集合の中に集合を含むような入れ子の集合を再帰集合という。
  • よくわからなかった。
22. NULL撲滅委員会
  • NULLでは無く、コードを割り当てる(0:未知, 9:適応不能など)
  • 数値の場合は0で代替する
  • 日付の場合、最大値・最小値で代替する
23. SQLにおける存在の階層
  • SQLでは、集約すると元のテーブルの列名をそのまま参照できなくなる。
  • 例えばage列はメンバー一人一人の年齢の情報を保持しているが、年齢というのが一個人にまつわる属性であって、チーム全体の属性ではないから。1人の人間について「年齢は?」とたずねることはできても、複数の人間の集まった集団に対して「年齢は?」とたずねることはできない。

感想

率直にいうと、DBエンジニア向けの本だったので結構難しかったです。説明はありますが、たくさん数学用語が出てきたり、ソフトウェアエンジニアがあまり使わないようなデータの取得のケースを取り扱っていたからです。難しい箇所に関しては、「こういうSQLを使ったら、こういうテーブルからこんなデータを抽出できたり、こんなテーブルの再成形ができるんだな」くらいの感想で読んじゃいました。

しかしながら、今まで抱いていたSQLへのイメージがかなり変わりました。特に「テーブルには順序がない」「ループがない」「ポインタが隠蔽されている」など、言われてみないと気づかないような、今まで意識したことがない事柄を学ぶことができました。

また、SQLの歴史も初めて知りました。データの持ち方にもいろんな種類があって、それぞれに利点や欠点があるので、RDBMSだけでなくそのサービスにあったものを検討してみるのもいいと思いました。

一見簡単な構文しか持っていないように見えて、実は奥が深いですね!

ここまでお読みいただきありがとうございました!

「SQL実践入門」を読みました

今月はSQL強化月間ということにして、「SQL実践入門」を読みました。

なぜ読んだのか

  • 普段Active Recordばかり使っていて、SQLに向き合ったことがなかったから。
  • 文法だけじゃなくてSQLの仕組みについてちょっと知りたいと思ったから。

この本で学べること

  • パフォーマンスの良いSQLの書き方、特に大量データを処理するSQLの性能向上の方法
  • データベース内部のアーキテクチャやストレージのようなハードウェアの特性まで含めた総合的な知識

本の概要

第1章:DBMSアーキテクチャ──この世にただ飯はあるか

第1章では、RDBの内部的な動作に関するモデルを理解し、SQLのパフォーマンスに関係する「バッファ」「オプティマイザ」などの概念を理解します。データベースは、その仕組みから「容量・永続性・データの整合性」と「速度」がトレードオフの関係になっていたり、SQLを実行可能な手続きに変換するために実行計画を作っていることがわかりました。

1章で出てきた単語

クエリ評価エンジンユーザーから受け取ったSQLを解釈し、どのような手順で記憶装置のデータへアクセスに行くか決定する。

バッファマネージャメモリ領域の使い方を管理する。ユーザとストレージとの間に割って入り、SQL文のディスクアクセスを減らす役割がある。

ディスク容量マネージャどこにどのようなデータを保存するかを管理し、それに対する読み出し/書き込みを制御する。

トランザクションマネージャとロックマネージャトランザクション同士をうまくデータの整合性を保ちながら実行させたり、データにロックをかけて待機する。

リカバリマネージャ定期的にバックアップを取得し、いざという時にデータを復旧する。

キャッシュユーザーとストレージの中間に位置することでデータの転送遅延を緩和するための機構

オプティマイザインデックスの有無、データの分散や偏りの度合い、DBMSの内部パラメータなどの条件を考慮して、選択可能な多くの実行計画を作成し、それらのコストを計算して、最も低コストな1つに絞り込みます。

LRU(LeastRecentlyUsed) 「参照される頻度が最も少ないものをキャッシュから追い出す」というアルゴリズム。逆に頻繁に参照されるデータが長くキャッシュに留められるため、全体としてのキャッシュヒット率が上昇する。

第2章:SQLの基礎──母国語を話すがごとく

この章では、SQLの基本構文を理解します。

基本の構文については、

  • SELECT句
  • WHERE句 / 複数のOR条件をまとめて書けるINを使った記述
  • GROUP BY句
  • 集計用の関数(COUNT、SUM、AVG、MAX、MIN)
  • HAVING句
  • ORDER BY句

そして、SELECT文をデータベースに保存できるビューという機能や、サブクエリについて解説されていました。

応用として、

  • CASE式
  • UNION(和集合)
  • INTERSECT(積集合)
  • EXCEPT(差集合)
  • ウィンドウ関数

について。

そして最後に INSERT、DELETE、UPDATE構文について解説されていました。意外とSQLの構文って少ないのですね。

第3章:SQLにおける条件分岐──文から式へ

この章では、CASE式がパフォーマンス改善で重要であることを学びます。CASE式で条件分岐を表現できればテーブルへのスキャンを大幅に減らすことができるケース、UNIONで愚直に書いた方がパフォーマンスがいいケースなど、実行計画を読み解くことで明らかにしていきます。

"文"ではなく"式ベース"でクエリを考える大切さを学びました✨

第4章:集約とカット──集合の世界

SQLの特徴的な考え方に、集合指向といって、行の「集合」単位でひとまとめにして記述するというものがあります。集約関数には、COUNT, SUM, AVG, MAX, MINなどがあります。これらは複数行を1行に集約する機能を持っている関数です。カットとは、母集合である元のテーブルを小さな部分集合に切り分けることを言います。この章では、集約関数とカットの効果的な使い方について学びます。手続き型言語だとループや分岐を使って記述しないといけない複雑な処理を、SQLの集約関数を使えばスッキリ簡単に書けるケースがあることがわかりました。

第5章:ループ──手続き型の呪縛

SQLの世界には、ループがありません。SQLの世界に手続き型言語のようにループを持ち込んで処理を書くとパフォーマンスが悪くなってしまうケースがあります。
SQLの世界でループを使うことのデメリットや、その代替となる手段を学びます。

第6章:結合──結合を制する者はSQLを制す

結合のアルゴリズムは大きく分けてNested Loops, Hash, Sort Mergeの3つがあります。この章では、この3つの結合アルゴリズムの実行計画を読み解き、RDBがどのように結合を最適化しているか学びます。ちなみに、この章を読んで初めてなぜ内部結合と外部結合が、なぜ「内部」と「外部」と呼ばれるのかわかりました。

第7章:サブクエリ──困難は分割するべきか

サブクエリとは、SQLの中で生成される一時的なテーブルです。サブクエリとテーブルは機能的観点から見ると違いはありませんが、パフォーマンスの観点から見ると大きな違いが存在します。

サブクエリの問題点は以下です。

  • 実体的なデータを保持していないので、アクセスするたびにデータを作る必要があり、実行コストがかかる。
  • 計算結果を保持するためにI/Oコストがかかる
  • 制約やインデックスのようなメタ情報が存在しないため、最適化を受けられない。

この章では、サブクエリの問題点を解決する方法とサブクエリを使ったほうがパフォーマンスがいいケースを見ていきます。

第8章:SQLにおける順序──甦る手続き型

SQLは昔、順序を持った数を扱うための機能を持っていませんでした。ところが、実務においては適当な集合に対して連番を求められるケースが多くあります。そうした実務的な要望に応えるために、SQLにも順序と連番を扱うための機能が追加されました。

この章では、ウィンドウ関数や相関サブクエリを利用して行に対して連番を振る方法や、それを応用して中央値を求めたりします。

第9章:更新とデータモデル──盲目のスーパーソルジャー

SQL文を変えることよりも、データモデルを変更したほうがパフォーマンスがよくなるケースをみていきます。

第10章:インデックスを使いこなす──秀才の弱点

インデックスの利用方法について学びます。インデックスのアルゴリズムを知り、それを有効活用する方法、どのような条件下で性能向上が難しいかなどを取り上げています。

感想

当たり前ですが、SQLに関してかなり踏み入った話もあったので、難易度は高めの本でした。
それでも今までなんとなく文法だけ覚えて使っていたSQLでしたが、この本を読んで、データベース内部のアーキテクチャや、集合指向の概念、SQLで使われているアルゴリズムなどを知ることができました。SQLの中身を知ることで、アプリケーション側でもデータをどのように扱うのか意識できるので、より良い設計を勉強できるきっかけになったと思います。読んで良かったです。次はデータモデル設計の本を読んでみようと思います。

ここまでお読みいただきありがとうございました!

「nginx実践入門」を読みました

今回は、nginx実践入門を読みました。

なぜ読んだのか

仕事でSLO(※1)を設定した際に、nginxについて触れる機会があり、SREさんに色々教えていただきました。雰囲気でその場で理解して終わってしまったので、こちらの本を読むことにしました。

※1 SLO: サービスレベル目標のこと
cloud.google.com

対象読者

  • これからnginxを使ってみたい人
  • すでにnginxを使っているけどもっと使いこなしたい人

この本で学べること

  • nginxとは何か
  • 静的なサイトの構築
  • nginxとセキュリティ
  • Webアプリケーションサーバの構築
  • 大規模なコンテンツを配信する際の設定
  • nginxのメトリクスについて
  • Luaについて
  • OpenRestyについて

本の概要

第1章 nginxの概要とアーキテクチャ

nginxは、オープンソースのHTTPサーバです。

「HTTPサーバってなに?」って聞かれるとはっきり答えられなかったのでこちらを読みました。MicrosoftIIS(Internet Information Service)や オープンソースソフトウェアのApacheApache HTTP Server)などもHTTPサーバだそうです。

nginxは、他のHTTPサーバ同様、テキストや画像といった静的なコンテンツの配信、もしくはアプリケーションサーバへのリバースプロキシとして動作しますが、イベント駆動、I/O Multiplexing、ノンブロッキングI/O、非同期I/Oなどのテクニックを組み合わせることで、非常に少ないリソースで大量の接続を同時に処理できるのが強みです。

第2章 インストールと起動

nginxのインストール方法、起動方法、オプションなどの解説がありました。

第3章 基本設定

Webサーバの設定は、nginx.confに書きます。この章では、HTTPサーバに関する基本的な設定の書き方、nginx本体の動作に関する基本的な設定について説明があります。また、ディレクティブとコンテキストの概念を理解することで、設定のスコープの範囲を操ることができ、より複雑な設定ができることがわかりました。

第4章 静的なWebサイトの構築

4章では、本番環境に特化した設定を行います。locationディレクティブを使用して異なるURLごとに配信するファイルの指定をしたり、IPアドレスBasic認証によるアクセス制限、returnディレクティブを使って特定のステータスコードでエラーページを表示したりします。

第5章 安全かつ高速なHTTPSサーバの構築

5章では、nginxでHTTPSを利用するための設定方法や、Mozillaの運用セキュリティチームが公開している資料を元に、安全かつ高速なHTTPSを実現するためのポイントについて解説されています。

HTTPS通信にするメリットを本書から引用します。

HTTPSを利用することで、通信内容を暗号化し、盗聴、改ざんを防止するだけでなく正しいサーバかどうか認証することでなりすましを防ぐことができます。

Railsを使用する際に、gemのインストールでOpenSSLのバージョンでハマったことがあったんですが、これはTLSを実現するためのライブラリだったのですね)

第6章 Webアプリケーションサーバの構築

Webアプリケーションにおけるnginxの主な役割はリバースプロキシです。
※リバースプロキシとは、ユーザのリクエストを受け取りそれを上位サーバ(アップストリームサーバ)に転送する機能

この章では、Ruby on Railsを用いたアプリケーションサーバの構築も行なっています。
アプリケーションサーバにnginxを組み合わせると、重要な基本機能をアプリケーションからnginxに委譲することができ、静的ファイルを代わりに処理してくれたり、リクエストを効率よく捌いてくれることがわかりました。

第7章 大規模コンテンツ配信サーバの構築

大量の画像ファイルを配信するケースを想定し、多数のリクエストを処理するうえで注目すること、nginxの機能の解説がありました。負荷のボトルネックには、ファイルの読み込み/書き込み、ネットワークの帯域幅、ネットワークの物理的距離や品質などが挙げられます。これらのボトルネックには、キャッシュやロードバランサなどで対応していきます。nginxにも、キャッシュやロードバランサを設定する機能があるので、その解説がされていました。

第8章 Webサーバの運用とメトリクスモニタリング

ログファイルの取り扱い、メトリクスモニタリングについて解説されていました。

Fluentdによるログ収集基盤を構築すれば、Norikraのようなストリームプロセッシング以外に、TreasureData、GoogleBigQuery、AmazonRedshiftといった外部サービスによるデータ解析や、ElasticsearchとKibanaによるログの可視化も行えるそうです。

また、nginxのバイナリアップグレードにも触れられていました。こまめにアップグレードすることで、動作速度の改善やセキュリティの面の修正を得ることができます。

第9章 Luaによるnginxの拡張 ーEmbed Lua into nginx

nginxのサードパーティモジュールであるngx_luaについての章です。

ngx_luaについては、本書の以下の文を引用します。

ngx_luaはnginxをLuaで拡張するためのサードパーティモジュールです。nginxの主要なAPILuaから利用できるようになっているほか、Luaのコルーチンやnginxのノンブロッキングソケットとイベント駆動アーキテクチャを組み合わせることで、サブリクエストの実行や外部サーバプログラムとの通信処理をノンブロッキングで行うことが可能になっています。

第10章 OpenResty ーnginxベースのWebアプリケーションフレームワーク

最後は、OpenRestyについてです。

OpenRestyについては、本書の以下の文を引用します。

OpenRestyは、nginxに大量のサードパーティモジュール一式をバンドルしたWebアプリケーションフレームワークです。

nginxとngx_luaを基本ベースにmemcached、Redis、MySQLといった各種サーバソフトウェアと通信するためのドライバやJSONエンコード/デコードのためのモジュールなど、Webアプリケーション開発で必要となるモジュールを多数バンドルして簡単に利用できるようになっています。

感想

この本を読んで、nignxは大量の接続を同時に処理するのが得意なHTTPサーバであるということがわかりました。本書は、「実践入門」と書いてある通り、nginx.confに実際に設定を書きながら機能について学べる本でした👍 nginx.confに各種設定が書いてあることがわかったので、nginx documentationでディレクティブを検索すれば少しはファイルが読めるようになりそうです。反省点として、私の場合 nginxに入門する前に、HTTPサーバに入門しないといけませんでした。そのことがわかったのも収穫になりました。

以上です。ここまでお読みいただきありがとうございました!

NextAuthのsessionに任意のプロパティを追加する

簡単な個人開発のログインで、NextAuthを使用しました。

やりたいこと

sessionオブジェクトが用意されているのですが、デフォルトだと以下の値が参照できるようになっています。

session.user.name
session.user.email
session.user.image
session.expires

私のプロダクトでは、user.idを参照できるようにしたいです。

session.user.id

sessionオブジェクトにuser.idを追加する

[...nextauth].ts ファイルのoptions: callbacksに以下のように書き、要素を追加します。

// [...nextauth].ts

import NextAuth from 'next-auth'
  - 中略 - 

const options = {
  - 中略 - 
  callbacks: {
    async session(session, user) {
      session.user.id = user.sub
      return Promise.resolve(session)
    },
  }
}

型をつける

今のままだと参照した際に型エラーになってしまうので、型をつけます。
f:id:kattyan53:20210807183656p:plain

types/next-auth.d.ts を作成し、以下のように書きます。

declare module "next-auth" {
  interface Session {
    user: {
      id: string | null
    }
  }
}

エラーがなくなりました。
f:id:kattyan53:20210807184047p:plain

何をしたのか

ライブラリの中身を見てみると、デフォルトだとDefaultSession型が参照されます。

export interface DefaultSession extends Record<string, unknown> {
  user?: {
    name?: string | null
    email?: string | null
    image?: string | null
  }
  expires?: string
}

export interface Session extends Record<string, unknown>, DefaultSession {}

今回は、独自に定義したSession型を参照するようにしました。

declare module "next-auth" {
  interface Session {
    user: {
      id: string | null
    }
  }
}

ハマったこと

デフォルトでは、Session型はDefaultSessionをextendsしています。

f:id:kattyan53:20210808040126p:plain


てっきり↓こんな感じで拡張されていると思っていたのですが、上記の型定義だとuser.idしか参照できません。

  export interface DefaultSession {
    user?: {
      name?: string | null
      email?: string | null
      image?: string | null
    }
    expires?: string
  }
  
  interface Session {
    user?: {
      id?: string | null
    }
  } 
   
  interface NewSession extends DefaultSession, Session {}
   
  const session: NewSession = {
    user: {
      name: 'a',
      email: 'b',
      id: 'a'
    }
  }
  
  // 参照できると思っていたけど、  session.user.idだけうまく参照できない。
  session.user.id
  session.user.name
  session.user.email
  session.user.image
  session.expires

NewSessionには以下のようなエラーが出ていました。

Interface 'NewSession' cannot simultaneously extend types 'DefaultSession' and 'Session'. Named property 'user' of types 'DefaultSession' and 'Session' are not identical.

ref: github.com

同じ名前のプロパティは継承できないんですね。変な勘違いをしていました。

以上です!