真面目なブログはこっち 👉 blog.s64.jp

「マスタリングTCP/IP 入門編 第5版」の読書感想文

プログラミング学び直し活動の一環として、「マスタリングTCP/IP 入門編 第5版」を読みました。

マスタリングTCP/IP 入門編 第5版

マスタリングTCP/IP 入門編 第5版

以下は読書感想文です

読むとよさそうな人

  • アプリケーションばかりでOSやインフラ等の層へ関与しない人
  • 雰囲気でプログラミングをしている人
  • プログラミングに興味のある人、学生

向いてる用途

  • コンピュータとネットワークの歴史を知る
  • プログラミングの考え方を鍛える (OSI参照モデルなど)
  • 中学 〜 高校講師が生徒向けのテキストとして採用する
  • ネットワークについて雰囲気を知る
  • 現代のアプリケーションについて大雑把にイメージする

向いてない / できないこと

  • Internet Protocolを書けるようになる
  • TCP/IPより上の層でプロトコルを書く

感想

広く浅くネットワークやそれに付随する概念を学ぶことができた。

コンピュータの歴史上にネットワーク、特にインターネットが必要不可欠であることが理解できる解説から始まり、アプリケーションばかり開発している自分は関与し得ない歴史的背景を知ることができた。
他者からインターネットの仕組みについて訊ねられた際に返答する分には十分な知識を得ることができる。が、これを読むことで実際にIPやその上位層のプロトコルを書けるようにはならない。あくまで大まかな雰囲気を知る、まさに "入門" にふさわしい本であろう。

また、いわゆる "パソコンの授業" を担当している講師はこれを元にカリキュラムを作ることができると感じた。自分も実際に担当している授業で取り入れようと思う。
挿絵や例えも多く、前提知識が少なく平易な言葉で書かれているため、初学者への教え方に困った際にも参考になるだろう。

TCP/IP全体像として各層のプロトコルが複雑に絡み合っているため致し方ないことではあるが、各章の内容を順々に読むだけでは少々理解しづらく、2週するなどして前後の内容を把握した状態で読み直すとより理解が深められるのではと感じた。

f:id:S64:20180405224506j:plain

昭島市長である臼井 伸介さまより献本いただきました。ありがとうございます。

PLEXチューナ + Chinachu gamma + CentOS 7で録画サーバを作るAnsible Playbook

約3年ぶりに眠ってる録画サーバを復活させようとした時のメモ。
今回利用したのは、

  • x86_64系サーバ (ベアメタル前提)
  • PLEX社製USBデータ供給チューナ
  • ICカードリーダ
    • SCR3310-NTTComを使いましたが、SCR3310/v2.0でも平気かもしれません

など。
注意点として、今回 PX-W3PE, PX-Q3PE などの接尾辞が4でないチューナは扱えません。これはCentOS 6向けドライバしか提供されておらずCentOS 7で利用できないこと、またCentOS 6は既にDockerのサポートが切れておりdocker-composeなどの導入が困難なためです。

ちなみに、多分pt3とかでもいけます。

1. CentOS 7入れる

サーバなのでMinimalがよいです。以降はOS導入直後のクリーンな環境を前提に進めます。
そういったalternativeなメディアはこちらから取ってくるとよいと思います。
インストーラ時点でインターネットに接続しておくと、次の手順が楽です。

2. gitとansible入れる

OSを入れたら以下コマンドを実行すればインストールできると思います。インターネット接続済みであることが前提です。
gitは標準リポジトリから取得できますが、ansibleはepelからの取得になります。そのためepel-releaseを追加していることに注意してください。

yum update -y # 各種パッケージの更新
# ...
# Complete!
yum install -y git epel-release
# ...
# Complete!
yum install -y ansible
# ...
# Complete!

なお、ansibleは後述のplaybookを実行するため、gitはそのplaybookを取得するために使います。そのため録画サーバに直接関係はありません。
終わったらカーネルなども更新されてるかもしれないので、再起動しておきます。

3. 作っておいたPlaybookをcloneする

セットアップを全て自動化できるようにAnsibleのPlaybookにまとめておきました。サーバ構築の肝は全部勝手にやれると思います。

cd ~ # 念の為
git clone 'https://github.com/S64/ansible-chinachu-gamma-playbook.git'
cd ansible-chinachu-gamma-playbook # 入る

4. READMEやplaybookのソースをよく読む

S64/ansible-chinachu-gamma-playbookを読み、playbookを実行することで具体的に何が行われるのか確認しておいてください。少し変わったことをしています。例えば、Chinachu/docker-mirakurun-chinachuをベースにカスタマイズしている、PLEXチューナ向けrecpt1をrecpx4としてインストールしているなどです。

気に入ったらGitHub上でStarを付けてください。

Star

5. playbookを実行する

rootでやりました。記事執筆時点では冪等性を担保してないので注意してください。

ansible-playbook 10_setup.yml

ドライバインストールなどの様々な面倒がここで全て完了します。気に入ったらStarを付けてください。

6. チューナの設定ファイルを記述する

Mirakurunではtuners.ymlに設定を記述します。このplaybookを利用した場合、設定ファイルの位置は /opt/chinachu/docker-mirakurun-chinachu/mirakurun/conf/tuners.yml になります。

具体的な設定内容はこちらをそのまま利用しても問題ありません。

cd /opt/chinachu/docker-mirakurun-chinachu/mirakurun/conf
vi tuners.yml # `vi`が難しければ`nano`をインストールするとよいかも

7. 再起動して使い始める

再起動すると、自動的にChinachu / Mirakurunがビルドされ、起動します。
ビルドがそれなりに長いので、初回は起動に時間が掛かります。もし手元でビルドが成功することを確認しておきたい場合は、再起動する前に以下を実行するとよいです。

cd /opt/chinachu/docker-mirakurun-chinachu
docker-compose build

おしまい

もしわからないことがあったり、特に壊れている場合はGitHubのIssueまたはTwitterで教えてください。Playbook側管轄の内容なら対応したいです。

蟻本第2版34ページの問題をHaskellで書く

蟻本第2版23ページの問題 (POJ 1852) をHaskellで書く - 🍥shuma_yoshiokaに引き続き、プログラミング学び直し日記。「プログラミングコンテストチャレンジブック 第2版」の34ページより、「部分和問題」。類似問題はこちら。

プログラミングコンテストチャレンジブック [第2版] ?問題解決のアルゴリズム活用力とコーディングテクニックを鍛える?

プログラミングコンテストチャレンジブック [第2版] ?問題解決のアルゴリズム活用力とコーディングテクニックを鍛える?

f0 :: [Int] -> Int -> Bool
f0 (a:as) k = a == k || f0 as k || f1 a as k
f0 [] _ = False

f1 :: Int -> [Int] -> Int -> Bool
f1 x (y:ys) k = x + y == k || f1 (x+y) ys k
f1 _ [] _ = False

main :: IO ()
main = do
    _ <- readLn :: IO Int -- n
    as <- (map read . words) <$> getLine :: IO [Int]
    k <- readLn :: IO Int

    putStrLn $ if (f0 as k) then "Yes" else "No"

コレで合ってるか大変不安である。しかし参考ナシで例を一発正当できたので嬉しい。

蟻本第2版23ページの問題 (POJ 1852) をHaskellで書く

蟻本第2版21ページの問題をHaskellで書く - 🍥shuma_yoshiokaに引き続き、プログラミング学び直し日記。「プログラミングコンテストチャレンジブック 第2版」の23ページより、「Ants」の問題。類似問題はこちら。

プログラミングコンテストチャレンジブック [第2版] ?問題解決のアルゴリズム活用力とコーディングテクニックを鍛える?

プログラミングコンテストチャレンジブック [第2版] ?問題解決のアルゴリズム活用力とコーディングテクニックを鍛える?

fMin :: [Int] -> Int -> Int
fMin (x:xs) l = maximum [ minimum [x, l-x], (fMin xs l) ]
fMin [] _ = minBound

fMax :: [Int] -> Int -> Int
fMax (x:xs) l = maximum [(l-x), (fMax xs l)]
fMax [] _ = minBound

main :: IO ()
main = do
    l <- (readLn :: IO Int)
    _ <- (readLn :: IO Int) -- n
    xs <- (map read . words) <$> getLine :: IO [Int]

    let r = ( fMin xs l , fMax xs l )

    putStrLn $ "min = " ++ show (fst r) ++ "\nmax = " ++ show (snd r)

この回答自体はとてもアッサリで、問題文から導き出す過程が大変。解説文ナシで解く技量はまだ無い。

蟻本第2版21ページの問題をHaskellで書く

FPについて学び直しメモ - 🍥shuma_yoshiokaに引き続き、プログラミング学び直し日記。「蟻本」こと「プログラミングコンテストチャレンジブック 第2版」を読みながら、問題をHaskellで解いてゆく試み。

プログラミングコンテストチャレンジブック [第2版] ?問題解決のアルゴリズム活用力とコーディングテクニックを鍛える?

プログラミングコンテストチャレンジブック [第2版] ?問題解決のアルゴリズム活用力とコーディングテクニックを鍛える?

21ページより「三角形」の問題。類似問題はこちら。

f1 (x:xs) = maximum [(f2 x xs), (f1 xs)]
f1 [] = 0

f2 x (y:ys) = maximum [(f3 x y ys), (f2 x ys)]
f2 _ [] = 0

f3 x y (z:zs) = maximum [(f4 (maximum [x, y, z]) (x + y + z)), (f3 x y zs)]
f3 _ _ [] = 0

f4 max len = if (len - max) > max then len else 0

main :: IO ()
main = do
    _ <- (readLn :: IO Int) -- n
    as <- (map read . words) <$> getLine :: IO [Int]
    print $ f1 as

ほぼ初めてということもあり、ループを使わず再帰脳づくりするのにかなり時間掛かった

FPについて学び直しメモ

OOPについて学び直しメモ - 🍥shuma_yoshioka に引き続き、雰囲気でプログラミングしているのでFP (Functional Programming, 関数型プログラミング) について雑に学び直した。
学び直しとは言うけど、そもそも関数型プログラミングは勉強したことないし、もっと言うとちゃんとHaskell書いたのも初めてになる。

手続型言語と関数型言語の違い

明確な定義は無いらしいが、言語自体に 関数の再帰呼出しによるプログラムの数式化 を助ける機構があるか否か、がポイントとなるもよう。

Javaはオブジェクトを手続型のように扱えるのがコンセプトとなる言語なので、このような言語は オブジェクト指向型言語 などのように分類されやすい (手続き型言語として分類されにくい) 。よって、手続き型言語には例えば PHP, Python などが挙げられやすい。
対し関数型として挙げられやすい言語は、Lisp, Haskell, OCaml, Erlang, Scala など。(Scalaはハイブリッドと言われがちだが)

Javaが「全てがオブジェクトである」のと同じように、関数型言語は「全てが数式である」と言える。
オブジェクト指向言語は、たとえ同じメソッドであってもそのオブジェクトが持つ状態により暗黙的に値が変わる場合が多々ある。
あまり良い例とは言い難いが、パッと出せるとこで言うと例えば、

class MyCls {
  
  private final int state1;
  private final int state2;

  public MyCls(int state1, int state2) {
    this.state1 = state1;
    this.state2 = state2;
  }

  public int calcState(int x) {
    return x * (state1 + state2);
  }
}

// App.java
public class App {

  public static void main(String[] args) {
    MyCls obj = new MyCls(2, 3);
    System.out.println(obj.calcState(5)) // 上の行を知らないと、ここの式で何が出力されるかわからない
  }
}

というのが発生する。これは決して常に悪く作用するわけではないが、参照透過性が無いと言える。
参照透過性は、入力が同じなら同じ作用と同じ値を返す状態で成立する。つまり手計算した値を直接埋め込んでも大丈夫な状態でなければいけない。

対し関数型言語とし例えばHaskellの場合、以下のようにするだろう。

data MyState = MyState { state1 :: Int, state2 :: Int }

calcState x y = x * (state1 y + state2 y)

main = do
  let my = MyState { state1 = 2, state2 = 3 }
  print $ calcState 5 my

このような参照透過性を実現する強い制約が関数型言語をそれたらしめていると言える。
そしてこのような制約のおかげで、再帰呼出しによる数式化が助けられている。

fibSeq x y = [x] ++ fibSeq y (x + y)
-- または `fibSeq x y = x : fibSeq y (x + y)`

main = do
  print $ take 10 $ fibSeq 0 1

{-
  フィボナッチ数列を求める簡単な例。
  読み方:
    1. 第一引数のみを持った配列をつくる
    2. xとyを足し合わせたものを求める
    3. 再帰呼び出しで配列を取る。第一引数はy、第二引数はさきほど足し合わせたもの
    4. それらの配列を連結する。第一引数の次に第二引数という風に結合され、さらにそれを足し合わせたもの、という形に無限に求め続ける
    5. `take 10`を使い、先頭から10番目の要素までを取り出す (現れた時点で辞める)
    6. それを標準出力へ
-}

なおパターンマッチなども特徴的だが、これらはあくまでも言語機能、糖衣構文のようなものでしかないので深くは言及しない。

関数型言語のエッセンス

関数型言語の特徴として、前述のとおり数式化可能なこと、参照透明性が高いことが挙げられる。
そうした特徴は様々な非関数型言語へも取り入れられている。たとえば、JavaのStream, Reactive Extensionsなども関数型言語の影響を受けている。

関数を引数とした関数を高階関数 (ハイオーダー ファンクション) という。Reactive ExtensionsなどのRxと呼ばれるライブラリは、FRP (Functional Reactive Programming) を実現するもの。Reactive、Observableは非同期プログラミングにおける概念なので、ここでは深く言及しない。
またKotlinなどはCollectionsとして同様の高階関数を提供している。

おしまい

他にも触っておくべきことが多そうだが、恥ずかしながら関数型言語の利用経験が少ないためすぐに思いつかなかった。そのため一旦ここで区切ることにする。
参考にした記事は、

など。

OOPについて学び直しメモ

雰囲気でプログラミングをしているので、OOP (Object-Oriented-Programming, オブジェクト指向プログラミング) について雑に学び直した。

オブジェクトとは, OOPの基本

オブジェクトとはモノのこと。オブジェクト指向とは、モノを操作する (操作できるモノを作る) プログラミングの方向性のこと。

モノには様々あるが、例えばリモコンやゲームコントローラなどのアクションを起こせる物体を想像すると良い。
可能な操作が一覧されており、命令を行うと内部の仕組みを知らなくても (隠蔽されていても) 意図した動作になる。
そうした「リモコン」と「テレビ」、「ゲームコントローラ」と「ゲーム機」のようなモノとモノ同士、つまりオブジェクトの操作を組み合わせてプログラミングしていこうという、現実世界での任務遂行方法を模倣したプログラミング手法と言える。

カプセル化 (エンカプセレーション)

OOPにおける特徴的な概念として、カプセル化が挙げられる。
前述のとおり、リモコンやゲームコントローラの使い方は知っていても、その内部の仕組みは知らないし、知らなくても問題なく利用できる。
逆に直接基盤などへ触れられるようになっていると、意図されていない操作で破壊してしまう可能性がある。
そのような操作を防ぐため、利用者向けにはボタンで操作を、ランプで状態の確認をできるようにしている。

カプセル化とはつまり、オブジェクトの持つフィールドを直接操作する必要がないよう、メソッドで覆うことを指す。これにより、外側の操作を変えずとも、メソッドの実装で実際のフィールドに対する操作を安全に、あらゆる箇所で行える。

継承 (インヘリタンス)

継承関係とは、要はIs-a関係の話である。つまり、B extends Aの場合、BはAの一種 (亜種)であると判断し、Aとして扱うこともできることの話である。
具体例で言うと、Viewの一種としてButtonやProgressBarが存在し、これらには例えば共通の「描画位置情報を返しなさい」というメソッドがあるかもしれない。それらは恐らく各々の描画情報さえあればそれを元に計算が可能であり、別の実装を必要としない。そういった共通の処理を "継承" することを指す。

紛らわしいが、共通の "メソッド名" で各々の異なる実装を呼べることは多態性になるため継承ではない。継承で話しているのはinterfaceの話である。overrideではない。

もう少し現実寄りの例にする。例えば "果物" の種類として "リンゴ", "バナナ" があるとする。果物の定義に確固たるものは無いが、たとえば ”草木の実である" とする。
つまり裏を返せばリンゴとバナナには共通処理として「木から実る機能」が存在することになる。これを各果物ごとに実装すると、人的ミスにより定義が揺らぎかねない。もしかしたら間違えて土から生やしてしまうかもしれない。

なので基底となる「果物」自体に木から実る機能を実装してしまえば、手間も掛からずミスも防げる。

多態性 (ポリモーフィズム)

多くのリモコンやゲームコントローラは、たとえ機種が異なっても説明書を読まずに利用できる。その理由には、同様のラベル、同様の形状など、説明を不要とする工夫が挙げられる。そしてそのお蔭で、知らずとも期待した動作をする。
しかしながら実際には、ボタンを押す操作により送出される信号は機種により異なる。もちろん画面上の表示も異なるだろう。

このように具体的な中身の処理を知らずとも様々な処理が起こりうるのが多態性である。同様のラベルを持つものに意味付けをし、具体的な処理は実装に任せることができる。

カプセル化で気をつけること (ワイの経験則)

カプセル化すればなんでも隠蔽できると思っちゃダメ。あくまでも1つのオブジェクト (クラス) は1つの役割だけを持つようにする。例えば、データ構造を持つ、他のデータ構造にマッピングする、該当するデータ構造を複数の永続化機構のいずれかから取り出す、など。
リンゴは自身の特徴や状態だけを持つと期待されるため、もしキャッシュ機能が埋め込まれていれば誰も想像できず、実装者は意図しない挙動で混乱するだろう。

継承や多態性で気をつけること (ワイの経験則)

自分のサブクラスになり得るものにより処理を変えたりしちゃダメ。たとえば「果物」内で「もし自分がリンゴなら」「もし自分がバナナなら」という実装をしてはいけない。何故ならあくまでも「果物」の一種に「リンゴ」や「バナナ」があるのであって、「果物」自身は自分が何になり得るのかなど気にしちゃいないから。「自分は果物だ」としか知らないし、実際に「果物」として扱われる際にはそれにより挙動が変わってしまってはいけない。実装者はデバッグ時に意図しない挙動が発生し混乱するだろう。

OOPの良いところ

適切な名前付けで実装を担保するため、変化に強い。各オブジェクトが名付けされたとおりの小さな機能のみを持つため、その名前付けされた処理が正しく実装されている限りはオブジェクト間で正しく作用する。

OOPの残念なところ

理解するのがどうも難しいらしい。関わる開発者全員がOOPに精通していること、つまり適切な名前付けと責務分離が可能なことを前提としているため、誰か1人でも理解していない場合、暗黙の了解が壊れてしまう。何が起きるかというと、各 "気をつけること" で書いていることが発生し、バグの温床になる。

各オブジェクトがあって、それをどのように調理するか、という思考を全員が身に付けるまでは手続型言語の方が良いかもしれない。

おしまい

次は、FPについて学び直しメモ - 🍥shuma_yoshioka