へぬもへメモ

https://twitter.com/henumohe

オブジェクト指向入門 第2版 原則・コンセプト

読書メモ。適宜更新。

1. ソフトウェアの品質

外的品質要因と内的品質要因の話。外的はユーザやクライアントに見えるもの、内的はそうでないもの。ここでは外的品質要因だけ紹介されている。正しく動くこと、拡張しやすいことなどのほか、UIの使いやすさや予算の話まで出てくるのが意外。

2. オブジェクト指向の基準

どういう機能があればオブジェクト指向と言えるのかという定義の話。クラス・カプセル化・例外処理・ジェネリクスポリモーフィズムGCなど色々。ビルドツールや依存関係管理、ライブラリまで話を広げている。環境まで揃って初めてオブジェクト志向が効果を発揮できるという話と認識した。

2.2.17 動的束縛

こういうやつ

List<String,String> list = new ArrayList<>();

たまに具象クラスだけが持つ便利関数使いたくて動的束縛やめるときあるけどいいのかな

3. モジュール性

外的品質要因である拡張性・再利用性を得るためのモジュール化の話。モジュール性があるということの定義から、それを満たすための原則(開放閉鎖原則・単一責任選択の原則など)について触れている。

3.2.1 直接的な写像

業務モデルとコードのモデルを合わせろっていう話?ドメインモデル作れということかな。

3.3.1 言語としてのモジュール単位

「モジュールは使用される言語(UMLなどの仕様言語含む)の構文単位に対応していなければならない。」とのこと。OOPに則った単位でモジュールを作成するよう設計しているのに、実装ではOOPをサポートしていないC言語を使おうとするような状況が例として書いてある。仕様定義〜実装まで、決めたモジュール単位をサポートしている道具を使いましょうという話か。

3.3.2 自己文書化の原則

ドキュメントとソースコードが独立して作られることを危惧している。かといってソースコードそのものはドキュメントとしては粒度が細かすぎるため、モジュールの中にソースコードとドキュメントが含まれているのが正しいとしている。詳しくは11.13.2章。

3.3.5 単一責任選択の原則

ifやcaseの変更・追加による修正点が複数箇所あってはいけない。ポリモーフィズムや動的束縛でどうにかする。

4. 再利用性へのアプローチ

OSS時代になって大きく変わった部分だと思うし、「たくさん再利用して、少しだけやり直す」というのができてるように思える。言語が変わると実装や人材が再利用できなくなるのは仕方ないのかな。PythonとCみたいな関係性がどのくらい便利なのか分かってないけど…

gitとgradleでeclipseのプロジェクト設定を管理する

警告やフォーマッター等のeclipse設定を、個々人の設定に依存しない形で管理できるようにしてみた。

方針

  • 基本的には、プロジェクト設定をgitに突っ込んでしまう
  • gradleが生成するファイルはgitに入れず、各々でgradle eclipseを叩いてもらう
    • classpathの設定値が環境ごとに異なる点への配慮
    • gradleでeclipse関連タスクを叩いた時の冪等性を保ちたい

以下、自分のGitHubより抜粋。

フォルダ構成

│  .checkstyle
│  .classpath
│  .fbprefs
│  .gitignore
│  .project
│  build.gradle
│  README.md
│
├─.settings
│      checkstyle.xml
│      findbugs.xml
│      org.eclipse.core.resources.prefs
│      org.eclipse.core.runtime.prefs
│      org.eclipse.jdt.launching.prefs
│      org.eclipse.jdt.ui.prefs
│      org.eclipse.ltk.core.refactoring.prefs
│      org.eclipse.pde.prefs
│      org.eclipse.wst.sse.core.prefs
│      org.eclipse.wst.validation.prefs
│
├─eclipse-settings-template
│      org.eclipse.jdt.core.prefs
│
└─src
    └─main
        └─java
            └─....

eclipseの設定は、@daisuke_m氏のMaven Archetypeの中にある設定を参考にしている。見つけたばかりなので細かい設定はまだ変えてないが、とりあえず以下の3点だけ変更した。

  • Javaのバージョンを1.6から1.8に変更(grepで4ヶ所ほど置換)
  • checkstyle.xmlから、5.6で廃止された設定を削除(<module name="DoubleCheckedLocking">)
  • maven関連の設定を削除( pom.xml, org.maven.ide.eclipse.prefs)

.gitignoreの内容は以下。githubjavaプロジェクト作った時のgitignoreに追記する形で作成。

*.class

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

#以下、追加内容

.gradle

# eclpse settings generated by `gradle eclipse`
.project
.classpath
.settings/org.eclipse.jdt.core.prefs

gradle eclipseを叩くと、サブタスクのeclipseClasspath, eclipseProject, eclipseJdtが実行され、上記.gitignore内の3ファイルが生成される。この3ファイルはcleanEclipseタスクによって、いとも簡単に初期化されてしまうので、gitで管理せず、gradleで生成するようにした。

/* ...省略... */
eclipse {
    classpath {
        downloadSources = true
        downloadJavadoc = true
        defaultOutputDir = file('build/classes')
    }
    jdt {
        file {
            def props = new Properties()
            props.load(new FileInputStream('eclipse-settings-template/org.eclipse.jdt.core.prefs'))
            withProperties { properties -> properties.putAll(props) }
        }
    }
    project {
        natures 'net.sf.eclipsecs.core.CheckstyleNature'
        buildCommand 'net.sf.eclipsecs.core.CheckstyleBuilder'
        //natures 'edu.umd.cs.findbugs.plugin.eclipse.findbugsNature'
        //buildCommand 'edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder'

        file.withXml {
            def node = it.asNode()

            def fr = node.get('filteredResources')
            if(fr) {
                node.remove(fr)
            }
            def fi, ma
            fi = node.appendNode('filteredResources').appendNode('filter')
            fi.appendNode('id', '1359048889071')
            fi.appendNode('name', '')
            fi.appendNode('type', '30')
            ma = fi.appendNode('matcher')
            ma.appendNode('id', 'org.eclipse.ui.ide.multiFilter')
            ma.appendNode('arguments', '1.0-projectRelativePath-matches-false-false-build')

            fi = node.appendNode('filteredResources').appendNode('filter')
            fi.appendNode('id', '1399217844078')
            fi.appendNode('name', '')
            fi.appendNode('type', '30')
            ma = fi.appendNode('matcher')
            ma.appendNode('id', 'org.eclipse.ui.ide.multiFilter')
            ma.appendNode('arguments', '1.0-name-matches-false-false-eclipse-settings-template')
        }
    }
}

org.eclipse.jdt.core.prefsは設定内容が多いので、eclipse-settings-template/org.eclipse.jdt.core.prefsをloadして、設定をマージしている。

findbugsはjava8未対応なので、一旦コメントアウトしている。最初はgradle.propertiesにjavaVersion明記してハンドリングしてたけど、もうjava7使うことないだろうからやめた。

.projectのfilteredResourcesを追加するAPIがgradleに用意されてないので、springのgradle設定を参考にして、直接Xmlに要素を追加している。正直この粒度でスクリプトを書くのは面倒なので、.projectや.classpathも、org.eclipse.jdt.core.prefsと同様にテンプレートをマージしたほうが楽そう。たぶんgroovy.util.XmlSlurperでやれる。

今後

ここまでやっておけば、git checkoutしてgradle eclipse叩いてeclipseからプロジェクトをimportして、どこでも同じeclipse設定を使うことができる。 残りの課題は以下。

  • IntelliJ IDEA環境との共存
    • eclipse, ideaそれぞれでテンプレートディレクトリを作って、タスク叩くと中のファイルがルートディレクトリにコピーされるようにすればいい?
    • ときたまIntelliJ使いたい欲が高まるので、その時に対処する
  • 勝手にeclipse設定変更してpushされるのを防ぐ方法
    • 何かのcommitに紛れて設定変更されるとつらい。↑の方法で解決できそうな気がする
    • テンプレートディレクトリ用意した上で、そこへのpush権限を絞れればよさげ。gitでできるだろうか?