読書メモ:SCRUM BOOT CAMP THE BOOK

下記の本を読んだので備忘を記録する。

https://www.amazon.co.jp/SCRUM-BOOT-CAMP-BOOK%E3%80%90%E5%A2%97%E8%A3%9C%E6%94%B9%E8%A8%82%E7%89%88%E3%80%91-%E3%82%B9%E3%82%AF%E3%83%A9%E3%83%A0%E3%83%81%E3%83%BC%E3%83%A0%E3%81%A7%E3%81%AF%E3%81%98%E3%82%81%E3%82%8B%E3%82%A2%E3%82%B8%E3%83%A3%E3%82%A4%E3%83%AB%E9%96%8B%E7%99%BA/dp/4798163686

所感

  • インセプションデッキは、システム要件(開発の概要)をまとめたスライドで外注するとしたらベンダーに最初に提案依頼の説明をするときの資料に近いように感じた
  • プロダクトバックログは、機能要件をテキストで記載した機能一覧のようなものと思った
  • ウォーターフォールでは全てのプロダクトバックログ項目をまとめて進めていくのに対して、アジャイル(スクラム)では機能別に毎回のスプリントで最後の受け入れテスト(スクラムの言葉で言えばデモ手順)まで進めていくのが違いかと思った。進め方だけが異なり、リリースまでに必要なことはどちらでも行う認識。
  • この本は漫画&スクラム入門書と思われるため、実際の現場の泥臭い部分やうまくいかない部分で省略されている箇所もあるんだろうと思った。例えば下記の描写は実際にはスムーズにいかないところもあるのでは?と思った(引っかかった箇所を矢印で記載)
    • ゴールに間に合いそうにないとき、スクラムチームでスコープ調整がすんなりできて部長(orステークホルダー)もすんなり従うところ ← 部長や発言力のあるステークホルダーはすんなり納得するのか?
    • 開発チームが自己組織化していて、得意な人が自ら手を差し伸べて協力して開発するところ ← 経験上優秀な開発者ほど謙虚だが、周りに対してそんなに自信がありますと手を差し伸べてくれるのか?そうでない場合はどのロールの人がどのように働きかけるべきなのか?

以下備忘

--------------

基礎編

  • アジャイル開発とは何か単一の開発手法を指すものではなく似たような開発手法に共通した価値観と行動原則に名前がついたものであり体現する手法は複数ある
  • スクラムの定義
    • スクラムは5つのイベント(会議など)、3つのロール(人の役割)、3つの作成物など最低限のルールのセットで構成される
  • スクラムの具体的な特徴
    • 【成果物1】スクラムでは、機能や要求、要望、修正などプロダクトに必要なものを抽出し、順番に並べ替えたプロダクトバックログと呼ばれるリストを作成する(バックログはプロダクトに1つ)

      • 順番は、その項目が実現されたときに得られる価値やリスク、必要性などによって決定する(優先度ではない?)
    • 【成果物2】スプリントプランニングで決めることの2つ目として(1つ目はプロダクトバックログ項目の選択)、選択したプロダクトバックログ項目と作業の一覧を合わせて、スプリントバックログと呼ぶ。スプリントバックログは開発チームの作業計画であり、スプリント期間中も自由に作業を追加したり削除したりすることができる。また、個々の作業は1日以内で終わるように分割するのが一般的。

    • 【成果物3】インクリメントとは、過去のスプリントでの成果と今回のスプリントで完成したプロダクトバックログ項目を合わせたもの。多くの場合、動作しているソフトウェアとして提供され、スプリント終了時点で完成していて正常に動作する必要がある。

    • 【ロール1】プロダクトバックログの管理の責任者をプロダクトオーナー(PO)と呼ぶ。POはプロダクトのWhatを担当する。

    • 【ロール2】開発チームはプロダクトのHowを担当する

    • 【ロール3】スクラムマスターは、スクラムのルール、作成物、進め方をPOと開発チームに教育すると同時に妨害や割り込みから守るのが役割

    • 【イベント1】スクラムでは最長1か月までの固定の期間に区切って、繰り返し開発を行うがこの固定の期間のことをスプリントと呼ぶ。

      各期間の長さは変えてはならない。最終日に作業が残っても期間の延長はしない。

    • 【イベント2】スプリントプランニングでは、各スプリントのWhatとHowを決定する

    • 【イベント3】デイリースクラムは、開発チームのための会議。スプリントバックログの残作業を確認し、このまま進めてスプリントゴールが達成できるのかどうかを、毎日15分のタイムボックスで検査する

      ※ デイリースクラムは、問題解決の場ではないことに注意(問題があれば別途タイムボックスを設ける)

    • 【イベント4】スプリントの最後では、プロダクトオーナー主催でスプリントの成果をレビューするイベントを開催する(スプリントレビュー)。スプリントレビューはステークホルダーからプロダクトに対するフィードバックを得るのが目的。

    • 【イベント5】スプリントレトロスペクティブは振り返りのことでスプリントレビューのあとにスプリント内の最後のイベントとして行う

実践編

Scene No.01 ロールを現場にあてはめる

  • ロールの兼務はOKだが、POとスクラムマスターの兼務はNG(役割が相反しており利害関係の衝突が起きるため)

Scene No.02 どこを目指すのか理解する

  • インセプションデッキという下記を含む10の質問で開発を始める前に明らかにしておくべきことを知ることができる

    • どういうことを実現するのか(ゴール)→エレベーターピッチ
    • 絶対に達成したいことは何か(ミッション)→我々はなぜここにいるのか
  • インセプションデッキを作るには、下記テンプレートをもとに叩き台を作り、疑問点や気になる点がないかをスクラムチームで話し合い、相談しながら具体的にしていく

    テンプレート:

    https://github.com/agile-samurai-ja/support/blob/master/blank-inception-deck/blank-inception-deck1-ja.ppt

  • ちゃんとスライドを作っても開発チームに一方的に説明するだけではNGで不安を持たなくなるくらい自分たちが向かう先を理解するのが重要(なのでみんなで集まって話し合う)

Scene No.03 プロダクトバックログをつくる

  • 最初のプロダクトバックログの作り方は、インセプションデッキや既存のシステム機能一覧を持ち寄り、含めた方が良い項目を付箋などに書き出していき、4段階くらい(超重要〜あれば嬉しい)に分類していく
  • プロダクトバックログの並び順は、自分たちが大丈夫そうと思えるようなものにするために自分たち(スクラムチーム)で決める
  • プロダクトバックログの項目は、目玉となる機能以外でも、目立たないが必要不可欠な機能、アーキテクチャの妥当性を検証できる機能やまだ不安のある技術要素を試すことができる機能といった、開発をする上で優先したい機能という分類を設けるのも重要

Scene No.04 見積りをしていく

  • 各プロダクトバックログ項目を見積もれば最初のリリース時期や予算が分かるが、そのために相対見積もりという方法がよく使われる
  • 相対見積もりは見積もり対象が不確実であるという前提があり、1,2,3,5,8,13,…とフィボナッチ数列を割り振っていくことが多い
    • まず各項目を簡単に終わりそう、少し大変そう、結構大変そうの3分類に分け、少し大変そうに分類した項目を全て並べ、その真ん中あたりから具体的に作業がイメージできる項目を選び3として基準とする。その他項目はフィボナッチ数列から割り振っていく。
  • 相対見積りでは素早く見積もるのが重要(素早く見積もることで先の見通しを確実にするための時間にあてられるため)
  • 見積もりポーカーをやる目的は、作業を行う自分たち(開発チーム)で見積もりについて対話することで認識のズレを初期段階で明らかにしながら、素早くある程度の抜け漏れを防ぐため

Scene No.06 いつ何が手に入るのか?

  • スプリントごとに終わらせられるポイント数を、ベロシティと呼ぶ。スクラムチームのスピードのこと。
    • 絶対に必要な項目の見積りの合計 / ベロシティ = 必要なスプリント数(期間)
    • ベロシティ × 期間内に実施できるスプリント数 = 実現できるポイント(どこまで実現できそうか)
  • ベロシティは決めるものではなく測るもの。スプリントを1つやってみて、実現できたプロダクトバックログの項目の見積りの数字を合計する。
  • リリースに伴う作業は、品証の部署との調整やパフォーマンス・セキュリティに関するテストといった通常時の作業とは異なることも多いため、自分たちの実力に応じて、プロダクトバックログの項目としてリリースの作業を扱うか、リリーススプリントを用意するか対応しておく

Scene No.07 ちゃんと計画できたかな?

  • スプリントプランニングでは2つのことを行う
    • そのスプリントで完成させる項目を選定し(POが開発チームに提示し実現可否を判断)、各項目の完成状態をPOと開発チームで合意する。完成状態は具体的に、このボタンを押下するとこの画面に遷移して〇〇が確認できるといった粒度のもの(デモ手順とも呼べる)
    • 開発チームはタスク(XX画面を実装するなど)を洗い出し、詳細な見積もりを行い、その期間で本当に終えられるか見極めを行う。タスクと見積もりはバックログと呼び開発チームの成果物となる。

Scene No.08 スプリントは順調かな

  • デイリースクラムは、スプリントゴールを達成できるかを検査するイベントであって、問題を見つけること(問題がないか検査すること)が目的であり、誰かへの進捗報告会ではないことに注意

Scene No.09 これって間に合うのかな?

  • タスクボードは、あるスプリントのプロダクトバックログの項目とそのためのタスクを全て、未着手(ToDo)、着手(Doing)、完了(Done)に分けて貼り出すというもの
  • スプリントバーンダウトチャートは、各スプリントの営業日に対する残タスクの見積もり時間合計の実績をプロットしたもの

Scene No.10 だいたい終わってまーす

  • スプリントは、スプリントレビューとスプリントレトロスペクティブ(振り返り)で完了する
  • スプリントレビューでは、率直な意見やフィードバックをもらうためにデモがとても重要なので万全の状態で臨む(動かないものにはフィードバックできないため)。画面キャプチャの切り張りではNG。
  • 完成の定義は開発チームのチェックリストのようなもので、一例として下記のようなもの。スプリント開始前にスクラムチーム全体で合意しておく。
    • デモ手順の通りに動作する
    • publicメソッドのテストコードが存在する
    • 最新の仕様がwikiにまとめてある
  • 完成の定義は、リリース時で求められる品質基準とは一致していなくてもよいが(例:セキュリティ、パフォーマンス、ドキュメント検証等)、後回しにしておくと痛い目に合う。

Scene No.11 あともう1日あれば…

  • タイムボックス(例:スプリントの期間)は変えないのが重要(最終的に実現したいプロダクトバックログの項目が完成するタイミングを予測するためにスプリントのポイントを使って計算するため、延長してしまうと他のスプリントと比較できないため)

Scene No.12 少し早く終わったぞ!

  • プロダクトバックログは、工数に余裕があり少しだけ(例:2ポイント)追加したいといった状況があるが、その場合はバックログの項目を分割するようにする。そのときに分割しやすさだけを考慮し画面だけ作成するといった項目を追加するのはNG(スプリントレビューで動くものを見せてフィードバックをもらうため)。
    • 例えばノートPCとスマホの両方で見れるようにしてほしいという要求があった場合、ノートPCで見る機能とスマホで見る機能に分割するのが分割(エンドユーザーから見た時の価値が提供できる必要がある?)

Scene No.16 うまく伝わっているのかな?

  • 開発チームに実現したいことの意図を共有するのが重要(開発の中で細かな実現手段を自分たちで判断しやすくなるため)
  • プロダクトバックログにデモ手順の隣に「ストーリー」として下記を記載する
    • 〈どういったユーザーや顧客〉として 〈どんな機能や性能〉がほしい それは〈どんなことが達成したい〉ためだ

Scene No.19 今後のことが分からない?

  • プロダクトバックログは誰でも記入可能であるため、順序の見直しや見積もりの最新化といった手入れ(リファインメント)を行うのが重要。スプリント期間中に少なくとも1回(スプリント半分経過後あたり)は実施するようにするのが良い(順序の見直しはPO主導で、見積りは開発チーム主導で)。

Scene No.21 あれ?間に合わない…

  • スクラムがこのままではゴールに届かなさそうなとき開発を進める上で調整可能なものを調整する
    • 品質 ← 一定レベルにする必要がある
    • 予算 ← 即効性がない(部内の承認がある、人員追加でも立ち上げ期間を要する等)
    • 期間 ← 少しなら調整可能なことはある
    • スコープ ← 最も調整が現実的。スコープの順番の変更、項目削減、項目順序は変えずに実現手段のみ変更といった形で調整する。

Scene No.22 この作業は苦手です…

  • スクラムでは、開発チームは自己組織化していて、機能横断的であることが求められている
    • 自己組織化:自分たちで状況に応じて役割を決めていくこと
      • 開発を進めていると、様々な状況があるため(例:POと議論、設計の方向性決め、技術選定、議事録やマニュアルの作成)、それぞれで得意な人がリーダーシップを発揮し困っている人を助けるのが重要
    • 機能横断的:開発チームだけでスプリントを円滑に進めていけるようになっていること
      • スプリントを進める上で必要なことを一人ひとりではなく開発チーム全員でうまく協力できていれば十分だが、開発チーム全体が持つスキルや経験で期待されるゴールが達成できそうかを話し合い、スキル不足の場合やメンバーのスキルに偏りがある場合はスクラムチーム外の関係者と相談する
    • スクラムでは分担とスウォーミング(swarming、1つのバックログ項目に複数メンバーで協力して取り組むこと)を使い分けるのが重要
      • スウォーミングは完了までのリードタイムの短縮、手戻りを減らす、知識移転が進むといった利点がある
      • スウォーミングの方法として最近はモブプログラミングが人気

読書メモ:オブジェクト指向でなぜつくるのか

 

下記の本を読んだのでメモしておく。(読んだのは数年前であり既に2021年に第3版が出版されている)

www.amazon.co.jp

所感

  • ソフトウェア開発の歴史、特に、オブジェクト指向プログラミング(Object Oriented Programming)に焦点を当て解説してあり、3章~4章で、既存の高級言語の課題を明示した後になぜOOPが必要なのかという部分がしっかり言及されていたので説得力があった。
  • 5章でOOP の特徴の1つにはメモリの使い方にあることが分かった。歴史的にヒープメモリが既存の言語では利用されていなかったがOOPでは有効活用することが分かったので、普段のプログラミングでは静的領域、ヒープ領域、スタックメモリそれぞれを必要に応じて意識して使い分けを試みたい。
  • クラスライブラリ、フレームワークコンポーネントといった紛らわしい言葉は共通点や特徴、違いをそれぞれ述べてあり初心者にも分かりやすかった。
  • 関数型言語への時代の流れや用語が分かった。関数型言語OOPとは立場や考え方が異なるものとして記載されているが、実際異なる部分は大いにあるだろうが、考え方自体はメジャーなプログラミング言語にも取り入れられてきているような気がする。
  • 近年(2020~)の開発でもOOPのメリットがどれくらい享受されておりどのような技術が用いられているか気になった(例えばクラスはメジャーな言語は大体備えているイメージだが継承はあまり使うべきでないといった話も聞くため)。

以下、読書メモ


※ 1,2,7章は導入の章であり特にメモしていない&その他の章も適宜取捨選択

3章 OOPを理解する近道はプログラミング言語の歴史にあり

  • 分かりやすさを重視する構造化プログラミング
    • FortranCOBOL 等の高級言語の登場後、1960 年代後半には「20 世紀末にはソフトウェアの需要にプログラマの人口、通常の意味での人口ですら追いつかない」というソフトウェア危機が宣言

      → 様々なアイデアや新たなプログラミング言語が考案された

    • オランダ人学者ダイクストラが提唱した**構造化プログラミング(GOTO レスプログラミング)**はその 1 つであり、「正しく動作するプログラム作成のためのキーは分かりやすい構造のプログラムを作成することであり、それは例えばプログラムのロジックを順次進行、条件分岐、繰り返しの3つの構造(基本3構造)だけで表現することで実現される」というもの

  • サブルーチンの独立性を高めて保守に強くする
    • この当時、プログラムの保守性を高めるために工夫されたのが、サブルーチンの独立性を高めること。そのために、グローバル変数(複数のサブルーチンが共有する、メインルーチンとサブルーチンで共有する情報を格納した変数のこと) の使用を減らすことが考えられた。

      • その理由は、グローバル変数デバッグするとき、変更するときにはプログラム全てのロジックを確認する必要が生じるため。

        例えばあるサブルーチンが別のサブルーチンを呼び出しており、それぞれの間では情報をグローバル変数でやり取りしていたとすると、どのサブルーチンがグローバル変数をいつ変更/参照しているのかわかりづらくなってしまう

      → そこで 2 つの仕組みが考案された:

      • ローカル変数(サブルーチンの中だけで使われる変数であり、サブルーチンに入ったときに作られ、抜けるときに消える性質を持つ)
      • 引数の値渡し(call by value, サブルーチンに引数として情報を渡す際に、呼び出し側が参照している変数を直接使わずに、値をコピーして渡す仕組みであり、これに より、呼び出されたサブルーチン側で受け取った引数の値を変更しても、呼び出す側が参照している変数に影響を与えることがなくなるのが嬉しい)
  • GOTOレスプログラミングを実現する構造化言語
    • 構造化プログラミング理論の浸透に合わせて、Pascal, C言語などの構造化言語が登場したがC言語には2つの特徴がある:
      1. ポインタなど細かな機能を携えていることから、UNIX OS の記述言語に使われるなど、アプリケーション開発からシステムプログラミングまで幅広く使われた
      2. 必要な機能のすべてを言語仕様で提供せず関数ライブラリでくみ上げるようにした(言語コンパイラを改良せずとも言語仕様レベルの機能追加ができるようになった)
  • 残された課題はグローバル変数問題と貧弱な再利用
    • 構造化プログラミングでも、2つの問題が残った:
      • グローバル変数問題(何らかの事情でグローバル変数を変更する際には、影響範囲を確かめるためにロジックをすべて調べる必要が生じてしまう問題)
      • 貧弱な再利用問題(大規模化するアプリケーションに対し、再利用/共通部品として使えるものがサブルーチンだけだったという問題)

4章 OOPは無駄を省いて整理整頓するプログラミング技術

  • OOP が持つ構造化言語には無い 3 つの仕組み
    • OOP の 3 つの仕組みは構造化言語では解決できない2つの課題を解決するためのものであり、それを一言で述べると、「重複した無駄なロジックを排除し必要な機能を整理整頓する仕組み」と言える。
      • クラスは関連性の強いサブルーチン(関数)とグローバル変数を 1 つにまとめて粒度の大きいソフトウェア部品を作る仕組みである。この仕組みを使うことで、従来はバラバラに存在していたサブルーチンと変数をまとめて整理整頓できる。
      • ポリモーフィズム継承は、共通サブルーチンではうまく対処できない重複したコードを一本化する仕組みであり、これにより、ソースコードの無駄を徹底的に省くことができるようになる。
  • インスタンス変数は「仲間内だけのグローバル変数
    • クラスの仕組みにより、従来はグローバル変数として定義していたものをクラス内部のインスタンス変数として隠せるようになった
    • インスタンス変数の性質は 2 つある:
      1. 別のクラスのメソッドからアクセスできないよう隠すことができる
      2. 一度インスタンスが作られた後は、必要なくなるまでメモリ上に残される
    • インスタンス変数は、影響範囲を局所化できるローカル変数の嬉しさと、存在期間が⻑いグローバル変数の嬉しさを良いとこどりした仕組みであり、「⻑持ちするローカル変数」または「仲間内だけのグローバル変数」である

5章 メモリの仕組みの理解はプログラマのたしなみ

  • プログラムが動く上での概念 1:実行方式について

    • プログラムの実行方式には、基本的には下記の種類がある。コンパイラ方式は実行効率が良く、インタプリタ方式では同じプログラムを異なる環境で動かすことができる。

    • Javaマイクロソフト社の.NETは中間コード方式と呼ばれる実行方式と対応する。

      CPU がプログラムを実行するためにはプログラムを最終的に機械語に翻訳する必要があるが、中間コードの命令は特定の動作環境に依存しない形式になっているため、そのステップを仮想マシンが担っている。例えば JVM はプラットフォームごとに提供されており、実行時に Java の中間コードであるバイトコードを読み込んで、そのプラットフォーム用の機械語に変換してプログラムを実行する。

  • プログラムが動く上での概念 2:スレッド、プロセス、ジョブ、タスク

    • プロセス(メインフレームではジョブと呼ぶのが一般的である)はメーラーや Web ブラウザ、表計算ソフトとといったパソコン上で独立して動く各アプリケーションプログラムとよばれる単位
    • スレッドはプロセスよりも小さいプログラムの実行単位のこと(スレッドはメインフレーム全盛時代にはタスクと呼ばれていた)。
    • スレッドはあるプロセスの中に複数存在することが可能で、実際に多くのアプリケーションが複数スレッドから構成されている(例:Web ブラウザのリクエスト処理や「中止」ボタン)。
  • プログラムが動く上でのメモリ領域

    • プログラムのメモリ領域は基本的に「静的領域」「ヒープ領域」「スタック領域」の 3 つに分けて管理される。
      • 静的領域は、プログラムの開始時に確保されプログラムが終了するまで配置が固定される領域であり、ここにはグローバル変数とプログラムの命令を実行可能な形式に変換したコード情報が格納される。各アプリケーションごとに 1 つずつ確保される。
      • ヒープ領域はプログラムの実行時に動的に確保するためのメモリ領域のことである。空き領域をなるべく効率的に活用する必要があることや、複数スレッドから同時に割り当て要求が来た時に整合性を保つ必要があることから OS や仮想マシンが管理しており、プログラム実行中にアプリケーションから必要なサイズを要求することで割り当てを行ったり、不要になれば元に戻したりする。各システムまたはアプリケーションごとに 1 つ確保される。
      • スタック領域はスレッドの制御のために使うメモリ領域のことであり、ヒープ領域が複数スレッドから共用されるのに対し、スタック領域は各スレッドに 1 つずつ用意される。各スレッドはサブルーチン(OOP ではメソッド)呼び出しの繰り返しで動作するため、スタック領域はサブルーチン呼び出しの制御のために使われることになり、サブルーチンの引数やローカル変数、戻り先などの情報が格納される。スタック領域は LIFO(Last In First Out)という方式で使われることで、メモリ領域を効率的に使用できる。
  • メモリ領域の使い方からの OOP の特徴付け

    • クラス情報は各クラスごとに 1 つだけロードされる

      クラス情報(個々のインスタンスに依存しないクラス固有の情報)は、内容としては主にメソッドに書かれたコード情報になるが、これはインスタンスに依存しないため、各クラスごと 1つずつロードされる。その方式(タイミング)は大きく分けて2つ存在する

      • 事前に全てのクラス情報をロードする方式(例:C++)
      • 必要な時点でメモリに逐次ロードする方式(例:Java)
      • これらの方式の間には実行性能とメモリ使用量のトレードオフがある。クラス情報のロードで 2 つの方式に共通しているのはロード先であり、静的領域(Java ではメソッドエリアとよばれる)にロードされる。
    • インスタンス生成のたびにヒープ領域が使われる

      • インスタンスを作る命令(Java では「new」)が実行されるとき、そのクラスのインスタンス変数を格納するのに必要な大きさのメモリがヒープ領域に割り当てられる。このとき同時に、インスタンスを指定してメソッドを呼び出す仕組みを実現するために、インスタンスからメソッドエリアにあるクラス情報への対応付けも行う。各インスタンスはクラス情報を共用する。
      • OOP におけるメモリの使い方の最大の特徴はこのインスタンスの生成法にあり、従来のプログラミング言語で書いたプログラムはコードとグローバル変数を静的領域に配置し、サブルーチンの呼び出しの情報はスタック領域を使って受け渡すことでほとんどの処理を実現していた(つまり、ヒープ領域は積極的に使われていなかった)のに対し、OOP では作成したインスタンスはすべてヒープ領域に配置される。
    • 変数にはインスタンスの「ポインタ」が格納される

    • ポリモーフィズムは異なるクラスが同じ顔を見せる

      • ポリモーフィズムの仕掛けは、メモリにおいては、対象となるクラス間でメソッドテーブル(各クラスで定義された各メソッドのポインタを順番に格納したもの)の形式を統一することのみである。
      • 実際にメソッドを呼び出すときには、このメソッドテーブルを経由して目的のメソッドを特定して実行する。こうすることでクラスによってメソッドに書かれたコードが異なっていても、呼び出し方法を統一することができる。
    • 継承される情報の種類(メソッドかインスタンス変数か)によってメモリ配置は異なる

    • 独立したインスタンスはガベージコレクタが処分する

      • ガベージコレクションはガベージコレクタと呼ばれる専用のプログラムが行う。このプログラムはプログラミング言語の実行環境(Java の場合は JavaVM)が提供するもので、独立したスレッドとして動作する。
      • このプログラムは適切なタイミングでヒープ領域の状態を調べ、空きメモリ領域が少なくなったことを検知すると実際のガベージコレクション処理を起動する。そのタイミングとは、「孤立したインスタンスを見つけた」タイミングである。
      • OOP の場合は引数やローカル変数にインスタンスを指定することが可能であり、その場合スタックにはヒープ領域に存在するインスタンスのポインタを格納することに注意されたい。また、メソッドエリアからもヒープ領域のインスタンスを参照できる。
      • プログラムがメモリ不足で異常終了した時に、アプリケーションを見直すポイントとして覚えておくべきことは、不要になったインスタンスをスタックやメソッドエリアから参照し続けていないようにすることである

6章 OOPがもたらしたソフトウエアとアイデアの再利用

  • フレームワークにはさまざまな意味がある
    • フレームワーク(framework)はソフトウェア開発の分野に絞っても定義が曖昧であり、「包括的なアプリケーション基盤」といった比較的漠然とした意味で使う場合と、「特定の目的のために書かれた再利用部品群」を指す場合の大きく 2 つに分けることができる。
    • 後者の定義を前提にすると、フレームワークとクラスライブラリは、いずれも再利用可能なソフトウエア部品群を指すが、目的や使い方で両者を使い分けるのが一般的。
      • クラスライブラリと呼ぶ場合、OOP の仕組みを利用して作った再利用部品を指すだけで、目的や使い方までは限定しない。
      • フレームワークと呼ぶ場合、単に OOP を利用して作ったライブラリというだけでなく、特定の目的を果たすためのアプリケーションの半完成品を指す。加えて、アプリケーションからの使い方としては、従来の関数ライブラリのように単に呼び出すのではなく、その反対にフレームワークからアプリケーションを呼び出すように使うものを指す。つまり、基本的な制御の流れをフレームワーク側であらかじめ提供しておき、アプリケーションで個別の処理を組み込む仕組みである。
    • フレームワークの選定が適切な場合、複雑なアプリケーションを簡単に作ることができる。基本的な利用方法としては、フレームワークが用意するデフォルトのクラスを継承しいくつかのメソッドを記述するだけである。Java の Applet(アプレット)などはその典型であり、Applet クラスを継承し、init、start などのいくつかのメソッドを記述するだけで、動的な Web ページを手軽に作ることができる。こうした芸当はポリモーフィズムや継承の仕組みを備えた OOPだからこそできることである。
  • 独立性の高い部品を意味するコンポーネント
  • デザインパターンは優れた設計のアイデア

8章 UMLは形のないソフトウエアを見る道具

  • シーケンス図とコミュニケーション図で動きを表現
    • クラス図はソースコード情報を表現するのに対し、シーケンス図とコミュニケーション図はプログラムの実行時の動きを表現する。従来のプログラミング言語(構造化言語)ではプログラムが動くこのような図の必要性はさほど高くなかった
      • その理由は、構造化言語では、サブルーチンの単位でプログラムを記述しその単位で動くことから、構造化チャートやフローチャートで静的な情報と動的な情報をほぼ表現できたため
  • ユースケース図でコンピュータに任せる仕事を表現
    • ユースケース図は、コンピュータの仕事の範囲を明確に表現するために使われる。具体的には対象とするシステムと外部(利用者や他のシステム)との境界を定め、コンピュータにまかせる仕事の内容を簡潔に表現する。
    • ユースケースの中心となるユースケース(Use Case)とは、「実際に使う例」といった意味で、コンピュータが利用者に提供する機能を指す
  • 仕事の流れをアクティビティ図で表現

13章 関数型言語でなぜつくるのか

  • 特徴 1:関数でプログラムを組み上げる
    • 従来のプログラミング言語において、「関数」という用語は一般的に「ひとまとまりの手続き」の意味で使われてきた。プログラミング言語によっては、戻り値を持つ手続きを「関数」、戻り値を持たない手続きを「プロシージャ」のように用語を使い分けるものもある。
    • 関数型言語の「関数」は数学の関数とほぼ同じ仕組みを表す。関数型言語における関数は、引数と戻り値を必ず持つ。
  • 特徴 2:全ての式が値を返す
    • 従来のプログラミング言語関数型言語では、プログラムの基本的な構成要素についても呼び方の違いがある。前者が**命令文(statement)と呼ぶのに対し、後者は式(expression)**と呼ぶ。

      • 命令型言語は、命令文(例:変数のメモリ領域への確保、計算結果のメモリ領域への格納、手続きの呼び出し)から成るプログラミング言語のこと

        命令型言語の例:アセンブリ言語高級言語、構造化言語、オブジェクト指向言語

      • 関数型言語ではプログラムの構成要素を式と呼ぶ。式は必ず値を返すものであり、式は「(命令を)実行する(execute)」ではなく「(式を)評価する(evaluate)」と表現する。

        関数型言語は「式」から成り立ち、関数もデータも値を返す「式」とみなされる。

    • 命令型言語は手続き的であり、関数型言語は宣言的であると表現されることがある。

  • 特徴 3:関数を値として扱える
    • 関数そのものを変数に格納したり、別の関数の引数や戻り値に指定することも可能であるようなプログラミング言語の性質、関数そのものを**第一級関数(first-class function)**と呼ぶ。
    • 関数型言語では関数が第一級オブジェクトであるため、関数を引数として渡すことができ、それはポリモーフィズムと同様の仕組みを導入したいときシンプルな仕組みをもたらしてくれる。
    • OOP では「クラス」があり、1 つのメソッドだけを入れ替えたい場合でもサブクラスとスーパークラスを定義し継承する必要があるが、関数型言語では単に関数を引数として渡すのみである。さらに、関数型言語では、関数を戻り値として返すこともでき、これは部分適用や関数の合成(後述)を可能にする。このように、関数を引数として受け取ったり、関数を戻り値として返したりする関数を**高階関数(higher order function)**とよぶ。
  • 特徴 4:関数と引数を柔軟に組み合わせることができる
    • **部分適用(partial application)**は、2 つ以上の引数を持つ関数に対し一部の引数だけを適用させ別の関数を作る仕組みである。
    • 部分適用を施すこと、つまり、2 つ以上の引数を持つ関数に一部の引数のみを適用させた結果の、残りの引数としての関数として表現することをカリー化と呼ぶ。
  • 特徴 5:副作用を起こさない
    • 関数型言語副作用というと、「引数から戻り値を求めること以外の仕事」を指す。
      • 「副作用を起こさないプログラム」とは、変数を更新せず、画面やネットワーク、データベースやファイルなどの外部入出力も一切行わないプログラムという意味になる。
    • 副作用が無い場合、引数が同じならば何回評価しても関数の戻り値は必ず同じになるが、このような性質を**参照透過性(referential transparency)**と呼ぶ。
    • **遅延評価(lazy evaluation)**はプログラムの実行時の仕組みであり、式を上から順に評価するのではなく、実際に必要になった時点で個々の式を評価する仕組みである。

読書メモ:楽々ERDレッスン

下記の本を読んだため備忘として投稿する。

ER図の練習問題が複数ついていて良かったが、テーブルの切り出し方、多重度等の設定の仕方、実際にヒアリングしながら設計する経験(本書ではレシートや請求書のみから設計するため)が必要と感じた。

www.amazon.co.jp

--------

第1部DB設計総論

2章 データベース設計の基礎知識

  • p37, 商品コードや顧客区分コードなど、〇〇コードの類(コード体系)は、主キーにすることでコードの洗い替え(コードおよびそれを参照している側も全て変更する。商品コードだとスペックチェンジでA→Bに一新する)が必要になる場合がある。

    コードの洗い替えに備えてそれぞれ専用のテーブルを作成する(元のコードとは別でIDを振って、参照元からはIDを外部キー参照するようにする)と安定する。

  • p54, 正規化ではよく導出項目は排除すると言われるが、排除しても良いのは可逆性を有する導出項目(例:単価×数量=金額の際の金額)のみであることに注意する。例えば上記では値引きがある場合は金額と単価が分かっても数量が出せないため不可逆になる。

    可逆性の導出項目はビューを使う。複雑な場合はストアドファンクションを使うこともあるがそのときもファンクションを呼び出すビューをテーブルを補完する仮想表として用意する。

  • p58, DB設計は手順としては下記のように進めていく

    1. 大まかにブロック分けを行う(業務単位か部門単位)
    2. それぞれのブロックごとにイベント系を洗い出す(この時点では正規化を意識しない)
    3. イベント系に対する正規化を行って、リソース系を洗い出す
    4. リソース系に対する分類の洗い出しを行なって、リソース系の正規化を行う
    5. ブロック間でリソース系の統合を行い、さらに正規化を行う
    6. 導出系の整理をして、最終的な正規化を行う

第3部楽々ERDレッスン

第1回:お持ち帰りご注文用紙

  • 注文-商品の関係はN:Nになるかと思ったがN:1とされている理由がよく分からない
  • 商品カテゴリはマスタにする

第2回:図書館の予約申込書

  • 図2-10(詳細なバージョン)を設計するのはハードルが高そうに見えるため、簡略化したデータベース設計の一例(図2-11)と比較する
    • 貸出券番号は、予約ごとに変わらないため予約テーブルではなく予約者テーブルに持たせるようにする

    • 連絡先(番号)は、予約のたびに変わる(予約のたびに入力してもらう)のであれば予約の附帯情報になるが、毎回同じで良いのであれば予約者の付帯情報になる。番号は本来予約者にぶら下がるものだが、予約に持たせるのもあり(図2-11だと予約に持たせている)

      → 項目は何に依存して変わるかでどのテーブルに持たせるかを判断する

    • 「受け取り希望館又はみどりステーション」は受取図書館のことだが、予約の一環にはなるがフリーテキストではなくマスタから選択することになるため図書館テーブルを追加してそれを予約から参照するようにする

      → マスタから選択するものは別テーブルにする

    • 書籍と予約の間の関連は、N:Nではなく1:Nとなっている理由はよく分からない気もする(本来1つの予約で複数の書籍を借りられるため書籍側もNではないのか?)。ある書籍は一年間で複数の人に借りられる(予約される)と考えると予約側に黒丸があるのは分かる。

    • 予約テーブルから連絡方法テーブルを外部キー参照していない理由は、連絡不要の場合があるから?それとも誤記?

    • 「この本を何で知りましたか」は「知った」というイベント系テーブルとして予約者、書籍と関連させるか、(誰が知ったという情報を記録しない前提で)書籍の付帯情報として書籍とのみ関連させることもできる。

第3回:ハンバーガーショップのレシート

  • まとめとしての部分と個別の内訳を表現する部分とに分けることができる場合、見出し明細形式(ヘッダディテール形式)やマスタディテール形式と呼ぶ。典型的には注文-注文明細などが該当する。注文:注文明細が1:Nで明細テーブルが親テーブルを外部キー参照する。
  • セット商品-単品商品は、一見ヘッダディテール形式に見えるが、セット商品はあくまでも単品の組み合わせでありその組み合わせに単品としての名前を付与していることになるため、内訳がまとめと同じレベルに存在するという特殊構造になる。このときはテーブル1つだけで表現する方法(自身の主キーを外部キー参照する自己参照)と2つテーブルを使う方法:商品-セット構成(セット構成IDの他セット商品ID、構成商品IDをFK参照)がある。
  • 商品は注文明細テーブルに含めずテーブルとして分ける
  • 預かり金額とおつりは注文テーブルに含めず別テーブルとする

第4回:病院の受付伝票

  • 受診番号、受診内容、医師はリソース系として別テーブルに切り出す
  • 受付は受付明細とヘッダディテール形式にする
  • 患者と受診は直接関連づける必要はなく受付を介すことになる

第5回:病院の領収書

  • 保険区分と保険負担は患者テーブルに持たせる
  • 請求明細は医師の商品明細テーブルのようなものと考えて請求テーブルとヘッダディテール形式にする

第8回:プロジェクトマネジメントプロセスの説明図

  • ツリー図になっているが、テキスト項目のみをもつテーブル同士としてシンプルなER図にできる
  • PMPポイントテーブルとPMP可能になることテーブルはN:Nなので間で関連テーブルを持たせるようにする

読書メモ: Railsの教科書

下記の本を読んだため備忘を投稿する。

tatsu-zine.com

----------

第2章 一番小さな Rails アプリづくり

  • rails s コマンドは web サーバを起動するコマンドで、s は server の略

  • Routes はリクエストの URL と HTTP メソッドから Controller のアクションを決定するため、リクエストとControllerのアクションの対応表と言える

  • Routesは画面から確認可能だが、Controller#Actionに"hello#index" と書かれている場合、#の左側がコントローラ名、右側がアクション名です。この場合は、「HelloController の index アクション」を示している

  • ビューやコントローラで使い回す変数はローカル変数ではなくインスタンス変数を使う

  • ビューのファイルである index.html.erb はHTMLの元になるファイルだが、普通の HTML との違いとして、Ruby のコードを実行した結果を埋め込むことも可能。このようなファイルをテンプレー トと呼ぶ。ここでは erb という種類のテンプレートが使われている。

  • 環境構築時Railsのインストールで詰まったが下記で解決した

    https://k-koh.hatenablog.com/entry/2020/01/21/120142

第3章 CRUD の基礎と index アクション

rails g scaffold コマンドは新規作成、表示、更新、削除、各機能を一度に作る機能です。つまり、scaffold を使うとCRUD 機能を持ったページを作成することができます。

rails g scaffold book title:string memo:text

コントローラのアクションでの処理が終わると、次はビューで処理が移ります。特に指定がないときは、app/views/コントローラ名/アクション名の view ファイルへ処理が移ります。例えばコントローラがbooks#indexの場合は app/views/books/index.html.erb です。

<%= %>で囲まれた部分は、Ruby コードの実行結果が HTML として埋め込まれま す。類似の部品<% %>では、囲まれた Ruby コードは実行されますが結果を埋め込みません。今回は@books.each の繰り返しの指示で <% %> が使われています。

第4章 new, create アクション

  • Railsでは次の順に処理が進んでいく

    リクエスト(URL, HTTPメソッド)

    Rails App(Routes→Controller→View)

    →レスポンス(HTML)

  • ビューのコード views/books/new.html.erbでは下記の書式になっている

    <%= render 埋め込むパーシャルビューファイル名, パーシャル内で使う変数名: 渡すオブジェクト %>
    

    パーシャルであるビューファイルの名前は先頭に_を付けるルールがあるので、パーシャルは render で書いた「埋め込みたいパーシャルビューファイル名」文字列の先頭に_を付けたファイル 名にします。つまり、<%= render "form", book: @book %>で埋め込まれるファイルは _form.html.erb になります。

  • Chromeデベロッパーツールでリクエストヘッダとパラメータを観察することができる。リクエストを送信するタイミングで、Networkタブの当該リソース(例えばbooks)のHeadersにURLとメソッドが記載されている。Payloadにパラメータ(画面での入力内容)が記載されている。

  • Strong Parametersというセキュリティの仕組みがあり、パラメータの内容を制限することができる。

    def book_params
          params.require(:book).permit(:title, :memo)
    end
    

    params 以降の require, permit メソッドは、パラメータの内容を制限します。意図していない データが入ってくるのを防ぐための仕組みです。ここでは、book の title, memo だけを受け取るようにしています。require には対象となるモデル名(モデルについては次章で説明します)を、 permit には更新を許可するカラム名を指定します。

第5章 モデル

  • 作成されたモデル(app/models/book.rb)ではコードがほとんど記載されていないにも関わらずsaveやallといったメソッドが使える理由は、ApplicationRecordクラス(およびさらに親のクラス)を継承しているから。 ApplicationRecordクラスがtitleやmemoといった要素(カラム)があることはDBを通じて知っている

  • Railsでのインスタンス変数の寿命は次のように考えればよい

    Rails の場合、@book のようなコントローラのアクションで代入したインスタンス変数は、1 つのリクエスト内が有効範囲だと考えることができます。おおまかには、あるページをブ ラウザで表示することが 1 回のリクエストだと考えて差し支えありません。別のページを表示したり、リロードを行ったりすると、新しい別のリクエストになります。コントローラのアクションで インスタンス変数に代入すると、コントローラからビューまで使うことができますが、その後なくなります。

モデルの作り方

  • scaffold は DB 設計書(migration)を作るコマンド。

    rails g scaffold book title:string memo: text

    生成されるファイル:

    app/models/book.rb (モデルファイル)

    db/migrate/日付_create_books.rb (migrationファイル)

  • DB設計書(migrationファイル)からDBのテーブルをつくるのがrails db:migrate コマンド。

    このコマンドを実行すると/db/migrate フォルダにあるマイグレーションファイルを 実行して DB テーブルを作る。

モデルの使い方

book = Book.new(title: "RubyとRailsの学習ガイド",
memo: "Rails関連技術地図とそれらの学習資料の紹介")

Book.new で Book モデルオブジェクトを作ります。モデル名は大文字はじまりで、単数形にするルールがあります。引数で title、memo といった各カラムのデータを渡せます。

book.save

save メソッドを呼ぶと保存できます。成功すると true を、失敗すると false を返します。

books = Book.all.to_a

Book.all で DB に保存されている Book Model の全データを取得できます。Book.all.to_a を実行すると、Array に Book オブジェクトが詰まって返ってきます。

book = Book.where(title: "RubyとRailsの学習ガイド").first
book.title #=> "RubyとRailsの学習ガイド"
book.memo #=> "Rails関連技術地図とそれらの学習資料の紹介"

where メソッドを使うと検索ができます。タイトルが"RubyRails の学習ガイド"である Book オブジェクトを取得します。取得した Book オブジェクトは、title メソッドでタイトルを、memo メソッドでメモを返します。

  • 既存のDB テーブルにカラムを増やすには、下記コマンドで追加可能(その後rails db:migrate コマンドで DB へ内容を反映する必要有り)

    rails g migration Addカラム名Toテーブル名 カラム名:型名

rails g コマンドまとめ

  • rails g migration: migration

    rails g migration AddAuthorToBooks author:string

  • rails g model: model + migration

    rails g model book title:string memo:text

  • rails g controller: routes + controller + view

    rails g controller books index

  • rails g scaffold: model + migration + routes + controller + view

    rails g scaffold book title:string memo:text

既存のテーブルにカラムを追加して画面から入力できるように変更する

  • 追加のmigrationの作成、migrationからDBの作成に加えて、下記を修正する必要がある
    • フォームパーシャルビューファイルを修正app/views/books/_form.html.erb にフォームラベルとテキストフィールドを追加する

    • 詳細表示画面のビューファイルを修正

      app/views/books/_book.html.erb に追加したフィールドを表示するよう要素を追加する

    • controller を修正

      app/controllers/books_controller.rb のStrongParametersに追加したフィールドを追加する

第6章 Gem ライブラリ

  • Bundler では Gemfile という名前のファイルに使用する Gem を書く
  • Gemfile を作成し bundle installコマンドを実行すると、Gem 群がインストールされる
  • bundle install コマンドを実行すると Gemfile をもとに Gemfile.lockファイルが生成されるので、両方をソース管理対象にする
  • Gemfile は発注書、Gemfile.lock は納品書に相当する

第7章 画像アップロード機能の追加

  • carrierwave gem を使うと画像アップロード機能を追加できる
  • Gemfile に新しい gem を追加した後、bundle install コマンドでインストールする

読書メモ:統計的機械学習

数年前になるが下記の本を読んだので備忘として記録する。

www.amazon.co.jp

------------------

所感

  • 全体的に最尤推定法やベイズ推定法(ベイズ予測分布を考える手法)を含む統計的推測の考え方がまとまっていて大変わかりやすかった。特にベイズ推定法の話は、MAP推定法とベイズ予測分布の導入から、事前分布、事後分布それぞれを求める方法(事前分布:周辺尤度最大化、事後分布:モンテカルロ積分、共役事前分布)が導入され、周辺尤度最大化(経験ベイズ法)はさらに計算手法として、MCMC法、ラプラス近似、変分近似法が紹介されていて、全体をストーリーとして捉えられるようになった気がする。

3章

  • 識別関数の良さを測る規準として最大事後確率則(maximum a posteriori probability rule)(=:MAP則)、最小誤識別率則(minimum misclassification rate rule)、ベイズ決定則(Bayes decision rule)の3つが挙げられていたが、それぞれの特徴が少しわかりスッキリした。本書ではMAP則を採用するとのこと。 
    • MAP則はある入力パターンが属する可能性が最も高いカテゴリを選ぶ考え方という点で自然であり、損失(loss)を考えるという点に特徴があるベイズ決定則も日常の人間の思考に近いという意味で自然であるようだが、損失の定量化が難しかったり計算が複雑になるといった理由からMAP則が用いられることが多く、本書でもこれを採用する(p48)。

5章

  •  MLE(最尤推定量)の理論的性質が主に述べられたが、MLEの性質について再認識できた。
    • そもそもMLEの良さ(期待二乗誤差の小ささ、p73)が保証されるのはサンプルサイズが大きいときであり、さらに、サンプルサイズが大きいときも、漸近不偏性、漸近有効性はあるものの不偏とは限らない推定量のクラスも考えるとバイアス+バリアンスの意味でより良い推定量が存在しうる(p81)。現実には有限標本であり、ゆえに一般に不偏性も持たない(ゆえに有効性も持たない)MLEではあるが(p76)、サンプルサイズが十分大きければ、漸近正規性とクラーメル・ラオの不等式の下限を達成することから導かれる(p76, 81)漸近有効性がその良さの根幹となっているのだと、バイアス・バリアンス分解(p73)からの一連の導出の流れを俯瞰することで実感できた。

7章

  • 7章ではまずガウスモデルについての説明がなされたが、一口にガウスモデルといっても様々な種類があり、3種類のガウスモデル(A)共分散行列が任意の正定値対称行列である場合 (B)共分散行列が対角行列かつ対角成分が異なる場合(C)共分散行列が対角行列かつ対角成分が等しい場合が紹介され、同じ確率分布であっても同じモデルであるとは限らない例を再認識できた。
  • 次に、モデル選択の一般論が述べられたが、その手法として、情報量規準(information criterion)と尤度交差確認法(likelihood cross validation)が紹介された(実務上はCVがメインと思われる)。これらは使用場面としてパラメトリックモデルに限られていた無意識の前提があったが、12章ではカーネル密度推定法(kernel density estimation)におけるバンド幅(band width)の選択に用いられており、その認識を改めることができたのでよかった。
  • 尤度原理(入れ子構造を持つモデル集合において、平均対数尤度を最小にするモデルを選択することにすれば(すなわち、KL情報量で第一項目を平均対数尤度で近似しそれを最小にするモデルを選ぶことにすれば)常に最も複雑なモデルを選んでしまう)についての説明のあと、情報量規準TICが導入され、負の期待対数尤度の推定量としては負の平均対数尤度と比較して誤差項のオーダーが次数1/nの項を含まないという意味でより優れていることがわかった。

8章

  • 勾配法は知っていたがその他関連手法がまとまっていて勉強になった。
    • 勾配法(gradient method)は最大化したい目的関数(objective function)の勾配を上っていくことにより、パラメータを最適化する汎用的な手法。このアルゴリズムは、解の初期値を適当に定めて、(1)現在のパラメータでの目的関数(の対数をとったもの)の勾配を計算→(2)パラメータにステップ幅×(1)の値を加えて更新→...を繰り返していくもの。このアルゴリズムは実装が非常に簡単で局所的最適解に収束することが保証される汎用的な手法だが、ステップ幅の決め方が難しい(具体的には、ステップ幅を大きくするほど大きく更新されるが大きくしすぎると局所解を通り過ぎてしまう)という問題がある。
    • この問題に対処するため、最初は大きめのステップ幅から始めその後徐々に小さくしていく焼きなまし(annealing)と呼ばれる手法が有効である。しかし、その実装は容易でない(なぜなら最初のステップ幅をどのくらいの大きさに設定すればよいか、どのくらいの早さでステップ幅を小さくしていけばよいかは目的関数に強く依存するため)。また、勾配法は局所最適解しか求めることができないという問題点もある。実際的には、異なる初期値から何度か勾配法を実行し、目的関数を最も大きくしたものを選ぶ多点探索(multipoint search)がよく用いられる。

9章

  • ベイズ推定法と関連手法の考え方が分かった。MAP推定は最尤推定ベイズ推定の中間的手法(橋渡し?)とみなせることも分かった。
    • 統計的機械学習におけるベイズ的立場、つまり、(ハイパーパラメータを除く)パラメータが確率分布に従うという立場ではベイズ予測分布を考える。ベイズ予測分布は事後分布に関しての積分計算を含むため、その近似手法という位置づけのものとして、MAP(maximum a posteriori probability estimation)推定法がある。これは事前分布の項を罰則項として見た罰則付き最尤推定法ともみなせる。ベイズ予測分布を考えるに際し、2つの主要な問題点--(1)事後分布の計算方法(2)事前分布を決める方法--がある。
      •  (1)のためには、例えば共役事前分布を使って閉形式で求める、あるいはモンテカルロ積分を基礎とする各種ランダムサンプリングの手法(例:重点サンプリング、逆関数法、棄却法、MCMC)で数値的に求める、などが考えられる。
      • (2)事前分布を決める方法には、BICを使うことが考えられるが、BICはもはや事前分布に依存しないため、事前分布のハイパーパラメータの設定のためのモデル選択には使えない。そこで、最尤推定法と同様、ハイパーパラメータも、手元の学習データが生成される確率が最も高くなるように設定するのは自然な考え方だといえる。周辺尤度を最大化するハイパーパラメータを用いて事前確率を設定しようとするこの考え方を、経験ベイズ法とよぶ。
        • 周辺尤度の計算はパラメータに関する積分を含む。MCMC法を用いることで数値的に計算することができだろうが、計算効率の観点からはラプラス近似の方が良く、これを用いることも考えられる。ラプラス近似は周辺尤度をガウス関数で近似する手法であるため、周辺尤度がガウス関数に近くないとき精度が良くない。そこで、あらかじめ用意しておいた関数族から最も良い近似を求める手法として、変分近似法(variational approximation)がある。

 

読書メモ:Linuxで動かしながら学ぶ TCP/IP ネットワーク入門

数年前になるが下記の本を読んだので備忘としてメモを書く。

www.amazon.co.jp

------------

Linuxで動かしながら学ぶ TCP/IP ネットワーク入門

環境構築

TCP/IPとは

  • pingTCP/IPで疎通確認に使われる。例えば、2つのNetwork Namespaceをルータで繋ぎ、一方のNetwork Namespaceからもう一方にパケットを送信できるかを確認できる。

  • tcpdump は通信(例:ping)を覗き見する(=パケットキャプチャ) プログラムである。各パケットの送信元/送信先IPアドレスなどを参照できる

  • traceroute はある通信での経路(Route, 通過した各RouterのIPアドレス) を確認するときに使う

  • ip address showコンピュータのIPアドレスをネットワークインターフェース(NIC無線LANアダプタ) ごとに表示できる。inet という表示の後ろに表示される。

  • ip route show でルーティングテーブル(経路表) を表示できる。**ルーティングテーブルはインターネットに繋がる全てのノード(ホスト含む) がそれぞれ持つ。**先頭列に宛先IPアドレスが表示される。

    インターネットを構成するルータはルーティング(ルーティングテーブルからネクストホップを調べるまでの作業) とフォワーディング(Forwarding, ネクストホップにパケットを渡す作業) を実施している

    ルータはネットワーク層でパケットを転送する機器のこと。

Network Namespace

  • ip nets add ns1 で新たにns1というNetwork Namaspaceを作成することができる。Network Namespaceはネットワーク的にシステムから独立した領域でありルーティングテーブルも独立して持つ。

  • ip link add veth1 type veth peer name veth2 でNetwork Namespace同士をveth(Virtual Ethernet Device, 仮想的なネットワークインターフェース)を使って繋ぐことができる。veth1veth2 は作成するネットワークインターフェースの名前。

    作成したvethはシステムの領域に所属しているためNetwork Namespaceで利用するためにはそこに所属させる必要があり、次を実行する必要がある。

    ip link set veth1 netns ns1

  • IPを使って通信するにはネットワークインターフェース(veth)にIPアドレスを付与する必要がある(ip address add)。

    また、ネットワークインターフェースは初期は無効な状態になっているため有効にする必要がある(ip link set veth1 up)。

  • IPで構築されるネットワークでは異なるセグメント(ネットワークやサブネットワークともいう) 同士で通信したい場合にルータが必要となる。セグメントはIPアドレスのネットワーク部で識別される(同一ネットワークアドレスのIPアドレスは同一セグメントに属する)。

    ルータのネットワークインターフェースに付与するIPアドレスのホストアドレスは自由に設定できるが、一般的にセグメントの先頭または末尾のIPアドレスを使うことが多い。また、下記のアドレスは設定できない。

    • ホスト部のビットが全て1のアドレスはブロードキャストアドレスといいそのセグメントに所属しているノード全てに通信したい場合の宛先に用いる
    • ホスト部のビットが全て0のアドレスはネットワークアドレスとなるためホストアドレスには使えない
  • Network Namespaceにはネットワークインターフェースを複数所属させることができる。例えばルータは1つのNetwork Namespaceとして設定でき、異なるセグメントの橋渡しをするため、各セグメントに所属するネットワークインターフェース (IPアドレス) をそれぞれルータに所属させることになる。

    • Network Namespaceはどの情報で識別可能?ルータのような複数のIPアドレスを保持するものがあるためIPアドレスでも識別不可と思われる。
  • Network Namespace同士で特定のルータを介した通信では、送信元のNetwork Namespaceのルーティングテーブルに、宛先がデフォルトルートのルーティングエントリ(宛先とネクストホップの組) を追加すると良い (ip route add サブコマンド)。

    デフォルトルートはルーティングテーブルの他のどのルーティングエントリの宛先にも該当しない場合の宛先のこと。デフォルトルートを使わずに特定のIPアドレスを宛先としたルーティングエントリを追加しても良いが、この方法だと通信したい相手が増えるたびにルーティングエントリを追加する必要があるため、デフォルトルートで特定のルータを介すようにする。

    送信先のNetwork Namespaceのルーティングテーブルも同様に設定する必要がある(相手からの通信時に必要であるため)。

  • 2つのNetwork Namespace間の通信で、それぞれが異なるセグメントに所属しており、セグメントの間にさらに別のセグメントを介す場合には、間のセグメントとそれぞれのセグメントを橋渡しするルータがそれぞれ必要となる。このような場合は、各ルータは通信したい相手のセグメントとは直接つながっていないため、各Network Namespaceにデフォルトルートとして対応するルータのIPアドレスを追加するのみでは通信できず、各ルータにもルーティングエントリ(宛先は宛先のセグメント、ネクストホップは相手側のルータの自分側のネットワークインターフェースのIPアドレス) を追加する必要がある。つまり、ルータは自身が直接繋がっているセグメント内のIPアドレスであれば自身のルーティングテーブルのネクストホップに設定できる。

  • 上記2つのケースのような人間が人手でルーティングエントリを追加する方式をスタティックルーティングといい、ブロードバンドルータではこちらが使われていることが多いが、ブロードバンドルータでは自動でGUIで設定されるように作られている。

    インターネットはダイナミックルーティング(ルータ同士が自律的に自身の知っているルーティング情報を教え合う方式) で制御されており、BGPという特定のプロトコルが使われている。(特定のネットワークに変更があったからといって全世界のルータを手動で変更するわけにはいかないため)。

イーサネット

  • イーサネット (Ethernet)OSI参照モデルではデータリンク層物理層に対応するプロトコルを含んだ規格のことでありIPを含む上位層のプロトコルのデータを運ぶ。IPのパケットがルータまで辿り着く際にも使われている。

  • IPのヘッダはイーサネットのヘッダの直後に連結され、各ヘッダはIPのパケットとイーサネットのフレーム(Frame, イーサネットでデータを送る単位) を表すため、フレームはIPのパケットという荷物を運ぶトラックと言える。Network Namespace間で通信する際(例:pingを打つ場合) tcpdump コマンドで-e オプションをつけることでイーサネットのヘッダ情報を表示することができる。

  • IPアドレスが分かっている相手と通信するためには、相手のMACアドレス(Media Access Control address, イーサネットのフレームを送受信するネットワーク機器ごとに付与される)を知る必要があるが、MACアドレスは、IPv4ではARP(Address Resolution Protocol)IPアドレスから解決する (IPv6ではICMPv6)。通信した際にARPで既知のIPアドレスを持ったMACアドレスを教えてくれるよう要求をMACアドレスブロードキャストアドレス (特殊なMACアドレス) に投げ、そのIPアドレスを持っている機器が自分のMACアドレスを返答してくれる。

    送信先がブロードキャストアドレスのフレームはフレームが届く範囲の (ブロードキャストドメインという) 全ての機器に対するリクエストとなり、このようなフレームをブロードキャストフレームという。MACアドレスのブロードキャストドメインの範囲はネットワークのセグメントと一般的に同じになる。

    MACアドレスは(ARPで使う際に)ブロードキャストドメインで一意であれば問題にならない。MACアドレスは機器のベンダーごとに割り振られる上位24ビットと、ベンダーが製造する際に割り当てる下位24ビットで構成される。

  • イーサネットを利用した通信でフレームが複数登場する通信は、例えば2つのネットワークセグメント (それぞれの中でNetwork Namespaceを設定) 間でルータを介した通信がある。送信元のNetwork Namespaceからもう一方のNetwork Namespaceに通信を試みたとき、宛先IPアドレスのセグメントが異なっているためルーティングテーブルのデフォルトルートに従いルータのIPアドレスネクストホップとなる。そこでARPを使いデフォルトルートのネクストホップのMACアドレスを解決することになる。

    送信先のセグメントのインターフェースからtcpdumpでその続きを観察することができる。パケットを受け取ったルータは、送信先IPアドレスをルーティングテーブルから調べ、送信先IPアドレスがこのインターフェースのブロードキャストドメインに存在することが分かり、ARPを使って (=ブロードキャストフレームで) 宛先IPアドレスMACアドレスを解決する。

    なお、相手先からの返答時には、必要なIPアドレスMACアドレスの対応関係はARPリクエストを通して知ることができ、その結果はキャッシュされているため、ARPを使う必要はない。

  • 家庭やオフィスでよくあるのがルータに接続するネットワーク機器が複数存在する場合であり、このときブリッジ(データリンク層でフレームを転送する機器、スイッチングハブをより一般化した概念)を使う。ブリッジはMACアドレステーブルで自身のポート (トランスポート層のポートではない) と接続する機器のMACアドレスの対応関係を管理する。

    Linuxのネットワークブリッジという機能を使うことで、3つ以上のNetwork Namespaceを同一のセグメントに接続することが可能になる。ネットワークブリッジのMACアドレステーブルはbridge fdb show サブコマンドなどで確認可能。

トランスポート層プロトコル

  • IPの通信で問題となるのが下記の2点であるが、これを解決するのがトランスポート層TCP(Transmission Control protocol)UDP(User Datagram Protocol)である

    • IPヘッダの情報のみではコンピュータが扱う様々なアプリケーションの通信を識別できない
    • IPパケットは経路上で破棄される恐れがある
  • UDPではポート番号を使ってアプリケーションを識別する。集合住宅をコンピュータのOSとすると、その住所はIPアドレス、各部屋番号がポート番号、各住人がTCP/IPで通信するアプリケーションに相当する。

    なお、他のアプリケーションが使っているポートは別のアプリケーションから利用することは基本的に不可。

    ポート番号は次のように決定される:

    • アプリケーションが通信を待ち受ける立場の場合(例:サーバ・クライアント方式のサーバ)、ポート番号はUDPを使う上位層のプロトコルで決定される (例:DNSならば53番)
    • アプリケーションが通信を自分から始める立場の場合(例:サーバ・クライアント方式のクライアント)、特にアプリ側から指定しない限りOSが自動的にポート番号を選んで割り当てる(Ephemeral Portという)。
  • UDPの通信の様子はncコマンド (正式にはNetcatというプログラム) でサーバ・クライアント方式の通信を確認できる。なお、トランスポート層プロトコルはシステムのループバックアドレスさえあれば観察可能のため、Network Namespaceは必要ない。ダイナミックポート(ポート番号のうち組織が管理していない範囲) を使いサーバ、クライアントを用意しそのポート番号をtcpdumpで観察すると、文字列を送信した際に運ばれる様子が確認できる。

  • UDPコネクションレス型のプロトコルであり、経路上でパケットが破棄されても関与しないが、TCPはコネクション型のプロトコルでありパケットが破棄された場合には再送制御が行われる。また、パケットが送られた順番と到着した順番が変わることがあるが(アウトオブオーダーという)、これが生じた場合にもデータの順序を正しく認識できる。TCPはWebブラウジングで使うHTTPやメールを転送するSMTPで下位層のプロトコルとして使われる。

  • TCPでは通信を始める際にスリーウェイハンドシェイクという方法で通信する。スリーウェイハンドシェイクの中では、コントロールビット (TCPヘッダに含まれるフィールドで6ビット分のフラグから構成される) の中でSYN(Syncronize sequence numbers)とACK(Acknowledgement field significant) というフラグの立ったパケットを送り合う。

    SYNはシーケンス番号を同期し、セグメントが到着する順序やどこまでデータが送信できているか等、データの順番を管理することができる

    ACKはTCPのセグメントを受信した側が立てるフラグでそのセグメントをきちんと受信したことを示す。送信側は、これが返ってこない場合同じセグメントを送信し直す(再送制御)。

アプリケーション層のプロトコル

  • アプリケーション層のプロトコルは無数にあるが、重要なものは3つ:

    HTTP

    • HTTPはサーバ・クライアント方式のプロトコルであり、トランスポート層TCPを用いるテキストベースの (=文字列として解釈できるビット列をやり取りする) プロトコルTCPの80番ポートを使う。
    • HTTPクライアントとしてncコマンドを使い、メソッドと文字列をループバックアドレスに送るとサーバ側でも文字列を確認できる。curlというHTTPクライアントを実装したコマンドでも同様のことができ、URLはncコマンドを使った操作を文字列として表現したものであることが分かる。

    DNS

    DHCP

    • DHCP(Dynamic Host Configuration Protocol) はUDPの67番ポートを使うバイナリベースのプロトコルTCP/IPのネットワークを使う際に必要となる下記のような設定作業を自動で実施する:
      • ネットワークインターフェースにIPアドレスを付与する
      • デフォルトルートのルーティングエントリをルーティングテーブルに追加する
      • 名前解決に利用するネームサーバを指定する
    • 家庭やオフィスのネットワークでは、デフォルトルートとなるサーバがDHCPサーバを兼任することが多く、配布するIPアドレスの範囲やデフォルトルートの情報をDHCPサーバに対し指定しておき、DHCPクライアントはその情報をDHCPサーバから受け取ってネットワークに関する設定作業を実施する。
    • DHCPサーバにはdnsmasq というプログラムの機能を用いる。

NAT

  • NAPT(Network Address Port Translation) (Source NAT, IPマスカレード) を使うと少数のグローバルアドレスを多数のプライベートアドレスで共有でき、IPv4のグローバルアドレスを節約できる。

  • プライベートアドレスは家庭やオフィスといった組織内のネットワークで自由に使えるよう予約されている下記のIPアドレスであり、LANは次からサブネットを切り出して使う:

    • 10.0.0.0/8
    • 172.16.0.0/12
    • 192.168.0.0/16
  • Source NATは一般的にNATやNAPTと呼ばれる場合に指されるもの。IPv4の節約になるのはNAPTの方であり、ルータが送信先がグローバルアドレスで送信元がプライベートアドレスになっているパケットのヘッダで、送信元のプライベートアドレス (厳密にはIPアドレスとポート番号両方) を自身のインターフェースに付与されているグローバルアドレスに書き換えることで、インターネットのホストの台数分だけグローバルアドレスを節約することができる。

    「戻り」の通信の際には、変換を元に戻す反対の処理、つまり、宛先のグローバルアドレス (書き換え後の送信元のグローバルアドレス) をプライベートアドレスに書き換える必要がある。書き換え前後の対応関係をNAPTではセッションと呼んで管理(記憶) しておくことで、インターネットからパケットが戻ってきたときにどのノードにパケットを転送すればよいか判断できる。

  • Destination NATでは「ポートを空ける」、つまり送信先のポートが特定の値になっているTCPUDPのパケットだけを選択的に書き換えてLANに転送することで、つまり特定のポートに関してだけは通信を許可することでインターネットからのパケットをLANに繋がっているノードに転送することができる。インターネットではプライベートIPアドレスを宛先にしたパケットをルーティングできないためである。これによりSourceNATを使う環境でもインターネットを起点とした通信が可能となる。

ソケットプログラミング

  • ソケットはUnix系OSデファクトスタンダードとなっているAPIであり、ネットワークを抽象化したインターフェースである。ホスト間通信やホスト内のIPC(Inter Process Communication) に用いられる。

読書メモ:ゼロからわかるRuby超入門

下記の本を読んだので備忘としてメモを書いた(個人的に印象に残った部分のみ)。

ゼロからわかる Ruby 超入門 (かんたんIT基礎講座) | 五十嵐 邦明, 松岡 浩平 |本 | 通販 | Amazon

--------

2章:かんたんなプログラムをかく

  • irb(Rubyの対話型インターフェース)は.rbファイルの中でbinding.irbを記載することでプログラムを一時停止できる(変数を参照したりするときに使う)
  • pメソッドとputsメソッドは似ている(おそらく標準出力に出力する)が、pメソッドはデバッグの道具として使う。プログラムの機能として意図して表示するときには puts を使う。

3章:処理の流れを変える

  • caseには2つ書き方がある
    • caseの後に変数を書きwhenで変数の値を記載する
    • caseの後に変数を書かず、when のあとに条件式を記載する
  • x回の繰り返しは下記のように書く
    • x.times do 処理 end
    • x.times { 処理 }

4章:まとめて扱う - 配列

  • 特になし

5章:便利な道具を使う

  • プログラミング言語 Ruby リファレンスマニュアル」というWebページがあり、組み込みライブラリで組み込みのメソッドが確認可能(例:配列のuniq)

    https://docs.ruby-lang.org/ja/

  • 末尾に ! が付くメソッド(例:uniq!)は、オブジェクトを破壊的に変更するものが多い

  • Rubyには「ブロックを渡せるメソッド」が存在する

    #例(メソッドの後ろにブロックを記載する)
    p [1, 3, 2, "2", "3"].uniq { |n| n.to_s } # => [1, 3, 2]
  • mapメソッドは配列の各要素を変換した配列を作るメソッドだが、map含むいくつかのメソッド(呼び出すだけのもの)のブロックには短い書き方がある。次は全て同じ処理を実行する。

    # 配列の変換処理
    result = ["abc", "123"].map do |text| 
    	text.reverse
    end
    # ブロックを使った書き方
    result = ["abc", "123"].map{|text| text.reverse}
    # シンボル(:)を使った書き方
    result = ["abc", "123"].map(&:reverse)
    
  • classメソッドとクラスメソッドがややこしかったが後者は一般的なクラスメソッド(8章に記載)で前者はレシーバのクラスを返すメソッドのこと(英語圏ではどう使い分けされている?)。

6章:組で扱う - ハッシュ

  • p145, ハッシュをpメソッ ドに渡すときには括弧を省略できない(シンボルはコロン記号(:)から始める):

    p( {:coffee => 300, :caffe_latte => 400} )
    
  • p146, ハッシュのキーにシンボルを指定したときのみ使える書き方がある

    # ハッシュのキーにシンボルを指定した場合のみ使える
    {coffee: 300, caffe_latte:400}
    # ハッシュのキーに文字列などシンボル以外のオブジェクトを使うとき
    {"コーヒー" => 300, "カフェラテ" => 400}
    

7章:小さく分割する - メソッド

  • 特になし

8章:部品をつくる - クラス

→ p204, レシーバはメソッド呼び出す際の呼び出し元のオブジェクトのことで、インスタンスまたはクラスのいずれかになる。レシーバがインスタンスのメソッドがインスタンスメソッドであり、レシーバがクラスのメソッドがクラスメソッドになる。

クラスメソッドはdef self.メソッド名で定義する

  • p192, クラスの中で(=インスタンスメソッド/クラスメソッドの定義内で)メソッドを呼び出すときはレシーバとドット(.)を省略してメソッド名だけで呼び出せる

  • p195, メソッド定義の中でインスタンス変数とローカル変数の使い分けはどのようにすればいいか?インスタンス変数は便利に見えるが、その分メモリを消費するはずなので(実装を左右するレベルかは不明だが)、基本はローカル変数にしておいて、他のメソッドも使う可能性がありそうならばインスタンス変数にしておくのが良いのではないかと思った

    インスタンス変数はその名の通り、 インスタンス(オブジェクト)が持つ変数です。ローカル変数と違って、同じオブジェクトであ れば、複数のメソッドをまたいで使うことができます。寿命もオブジェクトと同じになり、オブ ジェクトが存在する間ずっとインスタンス変数を使うことができます。

  • p214, レシーバを書かないでメソッドを呼び出す方法は、そのクラス定義内のインスタンスメソッドの中で定義すること

    →クラスメソッド内でレシーバを記載せずにメソッドを呼び出すことはできない(検証済み)

  • private なメソッドを定義するとレシーバを省略できるところだけで呼び出せるので、結果的に、メソッドを呼び出すことができる場所をクラス定義の中だけに限定できる(レシーバから直接呼び出さずに他のメソッド経由でしか呼び出せないようにできる)

9章:部品を共同利用する - モジュール

  • p224, モジュールの優れたところは、複数のクラスで使えるところ

  • p227, あるモジュールのメソッドをあるクラスのクラスメソッドとして呼び出したい場合、extendを使うが元のモジュールではインスタンスメソッドとして定義しておく必要があることに注意する

  • p228, モジュールはクラスと違いインスタンスを作ることができないが、クラスメソッドや定数をまとめるときには、使い方に迷わないため便利

  • p233, includeとrequire_relativeの違い:

    includeはモジュール名を渡して、そのモジュールに書かれたメソッドをクラスから利用できるようにするメソッドです。require_relativeは、ファイル名を渡してそのファイルに定義されたクラスやモジュールを使えるようにするメソッドです。セットで使うことも多いこの 2 つですが、それぞれ機能が違います。

10章:Webアプリをつくる

  • debugについて

    標準添付ライブラリ debug は、irb のように 1 行ずつプログラムを実行できる機能に加えて、 デバッグに便利な機能を持っています。debugには2つの使い方があります。1つ目はrubyコマンドのように、コマンドプロンプトからrdbgファイル名 で実行する方法。2 つ目はプログ ラム中でrequire "debug"とbinding.breakの2行を書いて、そこで一時停止して、入力し たプログラムを実行する方法です。一時停止中に n コマンドを打つとプログラムを 1 行ずつ実行し、 c コマンドで実行を再開します。P.61 〜 63 の irb についての説明を参考に使ってみてください。

11章:使いこなす

    • p267, 本文中で見落としているのかもしれないが、クラスの中で下記のようなメソッド定義をよく見かけるがどのような文法なのか?(単なるSetterとは思われる)

      def name=(text)
      	@name = text 
      end
      

      → 読み返すとp198に下記の記載有り

      インスタンス変数へ代入するメソッドは、慣習的に「インスタンス変数名から @ を取り、末尾 に = を加えたもの」にすることが多いです。

    • p267, コロンの右のインスタンス変数へのgetter, setterは下記のように記載する(まとめてattr_accessorでもよい)

      class Drink
      	attr_reader :name 
      	attr_writer :name
      end
      
    • p270, インスタンス変数の持ち主は self が指すオブ ジェクトなのでクラスメソッドとインスタンスメソッドでのインスタンス変数は同名であっても別物

    • p276, ブロックを渡すことができるメソッドの例としてdice の例が記載されているがブロックを渡すこと(yield)の使いどころがよくわからない。

      yield を使うと、メソッドの中で実行する処理を、メソッド呼び出し元にブロックで書くことができます

      とのことだが、本来メソッドに条件分岐を使って記載できるロジックを、メソッド呼び出し元にブロックで記載できることの何が嬉しいのかよく分からなかった(本ではそこまではあえて説明していないのだと思われるが)。

    • p277, ブロックをProcオブジェクトとして変数に格納しメソッドの引数に渡し(&ブロック変数名で渡す)、その定義の中で&ブロック変数名.call でブロックの処理を呼び出すことができるとのことだが、この例もメソッド内の処理を外出しにしただけに見え、どういう使い所があるのか分からなかった。