TPOP principle 4.5 コードの臭い

第4章 視点

principle 4.5 コードの臭い Bad smell in code.

言葉の復習

  • 設計とは何か。
    • principle 1.2 コードは設計書
    • 「基本設計」「詳細設計」「プログラミング」「テスト」「デバッグ」全てを「設計」と呼び、「コード」は設計書、「リリースビルド」が製造である。

臭いの傾向

よく見る
  • 状態
    • そっくりのコードがあちこちに存在する
  • 改善策
    • 重複したコードを一つにまとめる
長過ぎる
  • 状態
    • 「この関数でやっていることはAである」と一言で言えない
  • 改善策
    • 関数を分割して、関数の責務を一言で表現できるようにする
大きすぎる
  • 状態
    • モジュールの責務が大きい
    • モジュールの修正の機会が多い
    • 時間経過に連れ、モジュールの規模が増加し続ける
  • 改善策
    • 分割して、モジュールの責務を一言で表現できるようにする
多すぎる
  • 状態
    • モジュールの数が多すぎて、依存関係、処理の流れを追うことが出来ない
  • 改善策
    • 仲介役の削除、統廃合によりモジュールの数を減らす
名前が合わない
  • 状態
    • 名前と実際のコードの内容が合わない
  • 改善策
    • 表現したい概念と合っていなければ、直ちに適切な名前に修正する
    • 以前正しかった名前でも、改修によって正しくなくなることがあるので、その時点で名前も修正する

リファクタリング 第1章

問題

  1. 構造的に機能を付け加えにくいプログラムに新規機能を追加しなければならない場合、どうすればよいか。
  2. リファクタリングをする時に、最初にすることは何か。
  3. メソッドを抽出した際に、抽出したコードの責務が元のクラスにないことがわかった。メソッドの移動をさせたいが、はじめに抽出したメソッドを消す前に、どのような過程を挟むのが安全か。
  4. メソッドの中だけで有効なローカル変数、一時変数は少ない方が良い。それはなぜか。
  5. 4の解決策は何か。
  6. リファクタリングによってメソッドの持つ責務を別々のメソッドに切り分けたことで、外部にどのような利点が生じうるか。
  7. 他のオブジェクトの属性を調べるswitchやif文を書くことは常に間違いであるが、それはなぜか。
  8. 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 概要

TwitterAPIを概観し、頻度分析を使ってツイートから何らかの分析結果を導き出し、データマイニングの基礎を学ぶ。

学ぶこと

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 確認問題

  1. 複数のI/Oアクションを糊付けして1つにするには何を用いればよいか。
  2. "Hello, what's your name?"と一行に出力し、続いて文字列として名前を読み取らせ、最後に、"Hey (名前), you rock!"と一行に出力せよ。
  3. 2においてdo構文でまとめられたI/Oアクションの型は何か。
  4. 3の型になる理由を答えよ。
  5. mainの型シグネチャはどんな形をしているか答えよ。
  6. getLineの型を答えよ。
  7. putStrLnの型を答えよ。
  8. doブロック内で、getLineをmyGetLineという名前で使えるようにするにはどうすればよいか。
続きを読む

LYH 8.2 Hello, World!

8.2 Hello, World!

main = putStrLn "hello, world"

これをhelloworld.hsとして保存し、

$ ghc --make helloworld

と入力する。コンパイルされて、helloworldという実行ファイルが作成される。

8.2 確認問題

  1. putStrLnの型を調べよ。(:t putStrLnの結果を示せ)
  2. putStrLn "hello, world"の型を示せ。
  3. putStrLnの型を言葉で説明せよ。
  4. helloworld.hsをコンパイルし、helloworldという実行ファイルを作成するコマンドを示せ。
  5. 実際にI/Oアクションが行われるのはいつか。
続きを読む