TPOP principle 3.64 UNIX哲学9 - フィルタ化
第3章
principle 3.64 UNIX哲学9 - フィルタ化
ソフトウェアはフィルタである
- データを生成するのは人間
- データにフィルタをかけて別の出力を表示するのがコンピュータ
- 故に、まず入力ストリームと出力ストリームに着目し、そのフィルタリングとして設計を考えればよい
- UNIXではstdin, stdout, stderrをインターフェースとしてソフトウェア同士をコネクタブルにしている
UNIX哲学・小定理
環境カスタマイズ
- 最初の学習コストが高くても、ある程度学べばユーザがチューニングできるようになる方が長く使われるソフトウェアになる
-
- カーネルにアプリケーションを組み込んだら、そのアプリケーションを保守する人がいなくなる
小文字使用
- 小文字で短く、目に優しくする
- ソート時に大文字が目立つ
森林保護
- ドキュメントは電子化されていなければフィルタリング出来ない
沈黙は金
- 必要な情報が無駄な情報に埋もれてはならない
- エラーなどには基本的に沈黙し、成功したときだけ有益な出力を返す
並列思考
- 部品コラボレーション
90パーセント解
- 90パーセントを効率的に処理することを保証し、10パーセントはユーザに任せる
- 10パーセントの、時間のかかる処理や、プログラミングしにくい処理を故意に無視する
劣るが勝る
- 単一の巨大なソフトウェアよりも、小さい劣ったソフトウェアの最大公約数で勝負する
階層指向
- 階層構造アーキテクチャ
- 各々の階層構造で成功実績を収める
- プロセスツリー
- Xウィンドウシステム
- ネットワークサービス
TPOP principle 4.5 コードの臭い
第4章 視点
principle 4.5 コードの臭い Bad smell in code.
言葉の復習
- 設計とは何か。
- principle 1.2 コードは設計書
- 「基本設計」「詳細設計」「プログラミング」「テスト」「デバッグ」全てを「設計」と呼び、「コード」は設計書、「リリースビルド」が製造である。
臭いの傾向
よく見る
- 状態
- そっくりのコードがあちこちに存在する
- 改善策
- 重複したコードを一つにまとめる
長過ぎる
- 状態
- 「この関数でやっていることはAである」と一言で言えない
- 改善策
- 関数を分割して、関数の責務を一言で表現できるようにする
大きすぎる
- 状態
- モジュールの責務が大きい
- モジュールの修正の機会が多い
- 時間経過に連れ、モジュールの規模が増加し続ける
- 改善策
- 分割して、モジュールの責務を一言で表現できるようにする
多すぎる
- 状態
- モジュールの数が多すぎて、依存関係、処理の流れを追うことが出来ない
- 改善策
- 仲介役の削除、統廃合によりモジュールの数を減らす
名前が合わない
- 状態
- 名前と実際のコードの内容が合わない
- 改善策
- 表現したい概念と合っていなければ、直ちに適切な名前に修正する
- 以前正しかった名前でも、改修によって正しくなくなることがあるので、その時点で名前も修正する
リファクタリング 第1章
問題
- 構造的に機能を付け加えにくいプログラムに新規機能を追加しなければならない場合、どうすればよいか。
- リファクタリングをする時に、最初にすることは何か。
- メソッドを抽出した際に、抽出したコードの責務が元のクラスにないことがわかった。メソッドの移動をさせたいが、はじめに抽出したメソッドを消す前に、どのような過程を挟むのが安全か。
- メソッドの中だけで有効なローカル変数、一時変数は少ない方が良い。それはなぜか。
- 4の解決策は何か。
- リファクタリングによってメソッドの持つ責務を別々のメソッドに切り分けたことで、外部にどのような利点が生じうるか。
- 他のオブジェクトの属性を調べるswitchやif文を書くことは常に間違いであるが、それはなぜか。
- switch, ifによるオブジェクトの属性の分類は、同じ質問に対してオブジェクトが異なる処理をすることである。これはサブクラスの処理と考えられ、継承が利用可能である。しかし、オブジェクトの属性が度々変わる場合、それに合わせて派生先のサブクラスを変更することは出来ない。どうすればよいか。
LYH 9.1 ファイルとストリーム
問題
(1) foreverについて、型シグネチャと用途、importすべきものを言え。
(2) toUpperについて、importすべきものを言え。
(3) capslocker.hsを実装せよ。
(4) getContentsは遅延I/Oであり、入力が大きい場合は( )消費量の面で有利である。
(5) contents <- getContents
によって、contentsにgetContentsの結果が束縛されるとき、最終的に文字列として評価される( )としてメモリ上に置かれる。
(6) 10文字より短い行だけ出力するプログラムを作れ。
(7) interactとはどのような関数か。
(8) inretactを用いて、入力した文字列の回文判定をせよ。
続きを読む入門ソーシャルデータ 1.1, 1.2
※本記事では、書籍を読んだときの自己解釈によるまとめや感想を記述しています。実際の内容とは異なりますのでご注意下さい。
1.1 概要
TwitterのAPIを概観し、頻度分析を使ってツイートから何らかの分析結果を導き出し、データマイニングの基礎を学ぶ。
学ぶこと
- TwitterのデベロッパプラットフォームとAPIリクエストの発行方法。
- ツイートに関するメタデータとその使い方。
- ツイートからユーザのコメント、ハッシュタグ、URLなどの抽出。
- Pythonを使った頻度分析のテクニック。
- IPython Notebook を使った Twitter データのヒストグラムの作成。
1.2 Twitterはなぜ人気があるのか
Twitterは相互フォローが前提ではなく、一方的なフォローモデルで構築されている。一方的なフォローは、好奇心・関心の矢印に言い換えられる。
インタレストグラフ(関心の結びつき)としてTwitterを考える。このとき各ノードが本物の人間でなくてもよい。このグラフによって関心を持つ人の集合を特定できる。どのようなコミュニティが存在しうるかも分かる。
Twitterは、規則として組織化を強制しようとしない。特定できる人物であったり、特定の団体に所属していたりする必要がない。代わりに、少しのツールによって、ツイートの自己組織化を支援する仕組みが備わっている。
例えばハッシュタグというツールが存在する。このタグで検索をかければ、数多のツイートからタグが付随するツイートのみを抽出することが出来る。この機能は、ユーザにとってすぐに理解でき、ユーザに様々な利用方法の想像を掻き立たせ、ユーザがすぐに使うことが出来るものである。ハッシュタグに具体的な利用方法の制限が付随して、正しくツイートを組織化する方法をユーザに強制することはない。ユーザ間や利用するコミュニティによって、組織化の方法が自ずと定まってくるシステムになっている。個々の要素を分類学的な方法(タクソノミー)で区別するのではなく、個々人の勝手なラベル付の判断によって区別されていく方法(フォークソノミー)が用いられている。
LYH 8.3 I/O アクションどうしをまとめる
8.3 I/O アクションどうしをまとめる
main = do putStrLn "Hello, what's your name?" name <- getLine putStrLn $ "Zis is your future: " ++ tellFortune name
8.1と説明が重複するところがあるが、もう一度書く。
上のコードでは、getLineが副作用を扱っているものの、Stringを束縛したnameが関わるいかなる関数においてもI/Oについての情報を知る必要はない。上のtellFortuneという関数はString -> String
という型シグネチャを持っているものとする。確かにI/Oの影響が及ぶ箇所はない。副作用が発生する部分は、getLine
の中だけに留まっている。このIOアクションによって生成された結果が<-
によって取り出されてname
に束縛されてからは、副作用のない世界でname
が処理されるようになる。
IOアクションは、実行されるまで不活性なままである。Haskellではmainという、ただ一つのIOアクションが実行される。mainが1つのIOアクションのみで定義されるなら、
main = some IO action
となるし、doブロックでまとめれば
main = do (IO action 1) (IO action 2) ... do (IO action x) (IO action y) ...
と記述することも出来る。
また、main以外でも、I/Oアクションが実行される場合がある。GHCiにI/Oアクションを入力してENTERキーを押した時である。
ghci> putStrLn "HEEY" HEEY
以下のようなコードは書けるだろうか。
nameTag = "Hello, my name is " ++ getLine
型を考えてみよう。"Hello, my name is "の型は、String
すなわち [Char]
であるが、getLine
の型はIO String
である。
Char
のリストとIO String
とでは型が違うので、当然、リストの連結を行うことは出来ない。よって、このコードは間違いである。
I/Oアクションはどれも結果を生成する。
main = do foo <- putStrLn "Hello" name <- getLine putStrLn ("Hey " ++ name ++ "!")
上のコードは間違いではないが、putStrLn "Hello"
の型はIO ()
であるため、fooに束縛した値は()
であり、意味がない。
また、doブロックの最後の行は束縛を書くことは出来ない。この理由は「13章モナドがいっぱい」で分かるらしい。
以下の文は、getLineをmyGetLineに変えただけで、決してgetLineからStringを取り出してmyGetLineに束縛したものではない。
let myGetLine = getLine
無意味なコードだが、上の文を書いたあとには以下のような記述が可能となる。
name <- myGetLine
8.3 確認問題
- 複数のI/Oアクションを糊付けして1つにするには何を用いればよいか。
- "Hello, what's your name?"と一行に出力し、続いて文字列として名前を読み取らせ、最後に、"Hey (名前), you rock!"と一行に出力せよ。
- 2においてdo構文でまとめられたI/Oアクションの型は何か。
- 3の型になる理由を答えよ。
- mainの型シグネチャはどんな形をしているか答えよ。
- getLineの型を答えよ。
- putStrLnの型を答えよ。
- doブロック内で、getLineをmyGetLineという名前で使えるようにするにはどうすればよいか。