JJUG CCC 2013 Springへ参加まとめ

日本Javaユーザーグループ主催のクロスコミュニティカンファレンス 2013 Spring(通称:JJUG CCC 2013 Spring)へ参加してきました。 因みに、午後からのみの参加です。

日時: 2013年5月11日(土) 9:30-20:05(開場9:15)

場所: ベルサール西新宿(東京都新宿区西新宿4-15-3住友不動産西新宿ビル3号館)

Java EE 6 から Java EE 7 に向かって

Java エヴァンジェリスト、寺田さんの発表です。

  • JavaEEの歴史
  • JavaEE6
    • JavaEE6 のテーマ
      • 拡張性
        • 外部FWの設定が容易
          • web-fragment
      • プロファイル
        • JavaEEのサブセットを提供
        • Web開発するなら、WebProfileを利用すれば、必要なものだけロードしてくれる
      • Pruning:仕様の削減
    • EJBコンテナをJavaSEから呼び出し可能
      • 組み込みで動くのでテストが可能
    • 実行環境も軽量化 3 - 4秒で起動
  • JavaEE7
    • JavaEE7のテーマ
      • シンプル化
      • HTML5対応
    • 新機能
      • Concurrency
      • Batch
      • JavaAPI for JSON
        • Streaming API
          • Json内の個々の文字列ハンドリングが細かく指定可能
        • Object Model API
          • Builderを使って簡単にJSONを生成可能
      • WebSocket
    • アップデート
      • EL3.0
        • ラムダ式が実行可能
        • コレクションに対してLINQ式がかける
          • オブジェクトに対してのみのクエリ。DBには投げていない!
            • Viewでロジック書きすぎると可読性悪くなるので、使いどころあるのかな?微妙。
      • JMS 2.0

Java Small-Object Programming

Starrignt & Stormの長谷川 裕一さんによるDDD関連の話です。

1 S-OPとはなにか

  • 小さい部品でアプリケーションを作ろう
  • 背景
    • テストや変更の容易性、可読性の悪いアプリケーションの多さ
    • FWの定番化
    • DDDや9つのルール等の登場
  • S-OPの実現
    • オブジェクトを小さく作る
    • FWの有効活用

2 アプリケーションの現状

  • ビジネスロジックが理解しづらい
    • メソッドの行数が多い etc
  • ビジネスの変更がシステムに与える影響は、ビジネスロジックの変更である。
  • S-OPは何を解決するか
    • 上記の問題を解決するため、可読性が良く、変更容易性の高いシステムにする

3 Javaの抱える問題

  • JavaSmallTalkと比較して、純粋なオブジェクト指向ではない
  • 構文の冗長性
    • 例)Employeeクラス等、2つの属性を持つクラスで合っても複数のメソッドを記述しなければならない
  • Validation処理が複数のクラスに散らばってしまう

4 S-OPの実現

  • プリミティブ・文字列をラップしてクラスにする(フィールドクラス)

    • 例)Priceクラス
      • Priceに関するルールを知っている
    • 例) Codeクラス

      • Codeに関するルールを知っている
    • 先程のEmployeeクラスの場合も、nameとかcodeとかを一つのクラスにすることで処理を纏めることが可能。

      • Employeeクラスに対してValidationのアノテーションをつければ良い?
        • Controller等で、name, codeをEmployeeから離れて独自に扱う事があるからそれでは冗長になる。
    • フィールドクラスを利用するメリット

      • フィールド名が分散する事が無いので検索が便利
        • 例)商品コードがString shohinCode, String sc...
      • 修正は常に一箇所
    • フィールドクラスを利用するデメリット

      • ヒープを圧迫する
      • 多すぎると可読性が下がる
  • 不必要なSetter-Getterは記述しない

    • 本当に必要かを考える
    • 例) 倉庫の場合、set在庫はおかしいよね
      • 1から在庫をセットするのは文脈的におかしい。増やしたり減らしたりする方が文脈的には正しい。
  • フレームワークを利用する

    • Lombokで@Dataを利用すると、setter, getter, toString等を裏側で生成してくれるので、見た目がすっきりする
    • Springで例外、try-catch、loging等のコードを省略

5 9つのルール

  • 1つのメソッドにつきインデントは1段階までにすること
  • else句を使用しないこと
  • すべてのプリミティブ型と文字列型をラップすること
  • 1行につきドットは1つまでにすること
  • 名前を省略しないこと
  • すべてのエンティティを小さくすること
  • 1つのクラスにつきインスタンス変数は2つまでにすること
  • ファーストクラスコレクションを使用すること
  • Getter/Setter/プロパティを使用しないこと
  • S-OPにDDDのパターンを利用する
  • DDDを実施しないとS-OPにならない?
  • S-OPはトランザクションスクリプトに不向き?
    • ドメインロジックが余り無い場合にも、S-OPは使える
      • フィールドクラスでValidationをすると、使い回しが効く

6 DDDからDSLへ

  • 単純なプログラムであればDSLで自動生成で高速開発可能
    • プレゼンテーション
    • DBアクセス
  • 最低限必要なフィールドクラス等の基本的なコンポーネントはDSLで生成する
    • 開発者はこれをライブラリとして利用する。

JIRA開発の舞台裏 ~世界19,000社で使われる課題管理システムはどのように開発されているのか?

  • JIRAの解説
  • JIRAの開発

    • 年間3回のリリース
    • 開発メンバ
      • 74人
        • Devが8割
  • PM : Confluenceの利用によるストーリ管理

    • ペルソナ機能の利用
      • 利用者に関する情報を管理
        • 利用者がどの様な課題を持っているか?
        • 利用者はどの様なスキルセットを持っているか?
      • 個別の機能から始めるのではなく、ストーリを作る
        • JIRAの価値は何か?
          • ConfluenceはSNSプラットフォームなので、フィードバックが得られる
  • Design : Atlassian Design Guidelineの作成(共通のデザインコンポーネント

    • 開発者は見た目を気にしなくてもよくなった
    • Keynoteのテンプレートも作った
      • プレゼンなどでページのモックも作り易い
  • Dev : Gitへの移行(Stashというアトラシアンツールへの移行)

    • SVNのころはブランチ、マージへの恐怖心が有った
      • Gitでマージがし易くなった
        • rebaseがあるからってこと?
    • プルリクエスト
      • コードレビューの仕組みを活かす
    • トレーサビリティ
  • QA : Quality AssuranceからQuality Assistanceへ

    • テスティングノートの作成
      • テストの時に必要なガイドライン
      • ペアテスティング
        • Devと協力して品質を保証していく
    • 9ヶ月リリース -> 2週間へ短縮

失敗から学ぶAPI設計

  • いいライブラリとは

    • コストパフォーマンス高い
    • 機能が豊富
    • 品質高い
    • コミュニティが活発
    • 拡張しやすい
    • 使いやすい
  • Twitter4JのAPI

  • Twitter4Jの開発指針

    • シンプルにYAGNI
      • クラス数は極力少なく
      • インタフェースは使わない
        • インタフェースが分からない初心者にも優しく
      • 拡張ポイントはなるべく少なく
        • 柔軟さ < 使いやすさ の重視
      • なるべくImmutableに
      • クラス継承はさせない(final)
        • finalじゃないクラスはモッククラスとして使いたい場合のみ
      • strategyパターンはやらせない
        • 分かりづらいから
        • 認証の部分で使っているくらい?
    • Twitter4Jの拡張ポイント
      • 認証
      • ログ
      • httpクライアント
      • 非同期ディスパッチャ
    • デザインパターンを適用しない
    • IDEの補完を活かせるように
      • なるべく同一パッケージに
      • 一般的すぎるクラス名にしない
    • IDEの補完がいき過ぎないように
      • 使うべきでないクラス名を異様にする
        • z_T4JInternal***
          • zを付けてるのはIDEの補完で一番最後に来るようにしてる
    • 互換性維持の苦労
      • APIが増える
      • レスポンススキーマが変わる
      • 認証方式が変わる
      • 要素が増える
    • 互換性維持のために大事なこと
    • パッケージ訳の失敗

      • twitter4j.*
      • twitter4j.api.*
      • twitter4j.auth.* ...

      • パッケージ分けし過ぎると

        • クラスが見つけられない
        • blogのコード例をコピペしても動かない(import文が無いので)

        • 解決策

          • コードの見通しの問題であればパッケージ分けしない
          • ソースコードフォルダを移動する
    • API設計の失敗

      • new Twitter()
        • 使いやすいが、モッククラスを作れないからテストしづらい
      • インタフェース + ファクトリの導入
      • Sigletonを返すstaticメソッドを導入

        Twitter twitter = TwitterFactory.getInstance();

  • 参考図書

    • Effective Java
    • Practical API Design

参加してみて

始めてのJJUG CCCだけど、参加してよかった!しかし、セミナの醍醐味は懇親会にあるので、次回は是非参加せねば。

JavaとRubyの動的プロキシ

最近、Rubyを仕事で使いそうな気配があるため、メタプログラミングRubyを呼んでいる。

メタプログラミングRuby

メタプログラミングRuby

私は、Rubyを使うことの意義の一つとして、Javaと比較してメタプログラミングが簡易・柔軟に出来ること、又、それを活用したツール(RailsRSpec等)が充実していることだと思っている。

今回は、その中で動的プロキシを両言語で比較する。

動的プロキシとは

プロキシパターンとは、何らかのオブジェクトのインタフェースを実装したプロキシオブジェクトを利用し、そのプロキシから実際のオブジェクトのメソッドを呼び出すことで、メソッド実行の前後に処理を追加したりする物である。AOPが利用可能なフレームワーク等はこの機構を利用して機能を実現している。

動的プロキシとは、このプロキシオブジェクトを動的に生成する仕組みである。 ※ちなみにこれはJavaの話、Rubyではインタフェースを使用しないため、プロキシオブジェクトは使用しない。

動的プロキシで実現できること

動的プロキシでは以下の様な事が実現出来る

  • 既存のメソッドに対する処理の追加
  • 既存のオブジェクトに対するメソッド、プロパティの追加

両言語では、以下の様な対応となる

Java Ruby
処理の追加
メソッド、プロパティの追加

Javaでは、java.lang.reflect.Proxyクラス、cglib等のライブラリを利用して処理の追加は可能だが、メソッド、プロパティを追加することは出来ない。 しかし、Rubyでは後者が可能になっている。

Rubyにおける動的プロキシ

Rubyで、動的プロキシを実現する方法として、method_missingを利用する方法がある。

RubyJavaとは違い、実行時にメソッドを解決し、見つかったメソッドを呼び出す。対応するメソッドが存在しない場合には、BasicObject#method_missing(private)メソッドが呼び出される(Javaで言うところの,reflection使用時のNoSuchMethodException)。

全てのオブジェクトはBasicObjectを継承しているため、method_missingをオーバライドすることで、存在しないメソッドを呼び出すことが出来るわけである。

本では、FlickerのRubyライブラリの以下のコードを例にしている。

class Flickr
  def request(method, *params)
    #Flickrへのリクエスト処理
    #Flickrではリクエストパラメータのmethodで、処理を決定する。
    # 例)http://.../?method=flickr.people.findByUsername
    ...
  end 

  def method_missing(method_id, *params)
    #method_idはメソッドのシンボル、*paramsは配列引数.
    #flickr.people_findByUsername => flickr.perople.findByUsername へと変換される
    request(method_id.id2name.gsub(/_/, '.'), params[0])
  end
  
  ...

まとめ

Rubyのメタプログラミングはかなり協力でかなり使えるので、ガンガン使っていきたい! しかし、簡単に機能が拡張でき過ぎる麺もあるので、ある程度の規模の案件などで利用する場合は規約で縛ることがもちろん重要ですね。

Javaパッケージの分割、命名についてのまとめ。

Java: The Good Parts

Java: The Good Parts

JavaTheGoodPartsを読み終わったので、良いタイミングと思い、パッケージの分割、命名に付いてまとめてみました。

パッケージとは

Javaのパッケージとは、名前空間を作成するものである。 クラス名に一意な名前を指定する必要があるので、重ならないドメインを使用してパッケージ名を決定するのは基本だと思います。

パッケージ分割指針

レイヤでの分割

私は通常、Webアプリケーションを4層構造(view, controller, service, model)で作成し、クライアント側とサーバ側はJSONでやり取りすることが多いため、以下の様なパッケージ構成になります.私はある程度、大規模なシステムを作る場合が多いのでservice層を挟んでいますが、小規模な場合はserviceを省きます。

com.inoti.sample --- model
                  |
                  |- repository
                  |
                  |- service
                  |
                  |- contorller 
                  |
                  |- util

因みにこのService層の概念は、DDD(Domain-Driven Design)のものです。 詳しくは、以下の本を見ると良いです。

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

機能ごとに分けず、層で分けているのは、依存関係を一方向のみに集約させ易い(controller -> service -> model)からですね。非循環依存関係の原則って奴です。依存する対象が少ないパッケージはその分、システムの変更に強くなり、安定したパッケージとなります。 repositoryはデータストア部分を受け持つ部分です。aop等の共通処理がある場合は、aopパッケージを並列に追加します。

インタフェースと実装

インタフェースと実装のパッケージをどう分けるか、というのも悩みどころではないでしょうか。 私は基本、インタフェースをトップレベルパッケージに置き、そのサブパッケージに機能の分類として実装を置くようにしています。 この方が機能が分かれているので分かりやすく、Jarとして一部分の機能を切り出すときもやり易いと思います。 又、別の開発者が別の実装を作成する場合も、共通リソースを探しやすいのも利点です。

特に機能が分類される事が無く、デフォルトの実装のみ存在する場合は同一パッケージに置きます。 implパッケージはインタフェースが非常に多い場合に使用するくらい。

上記の例だとcontroller, service, modelなどはインタフェース、実装を同一パッケージに置き、repositoryでjdbcを使う場合、jpaを使う場合など、分けることが多いです。

com.inoti.sample --- model
                  |
                  |- repository 
                  |   |
                  |   |- jdbc
                  |   |
                  |   |- jpa
                  |
                  |- service
                  |
                  |- contorller 
                  |
                  |- util

例外

最後に、例外のパッケージです。 最近のWebアプリケーションではほとんどすべての場所でシステム用のRuntimeExceptinを使用し、Contorllerで全てキャッチするのをよく見かけます。 その場合、以下の様にexceptionパッケージが存在し、そこにシステム用のRuntimeExceptionが配置されていたりします。

com.inoti.sample --- model
                  |
                  |- repository 
                  |   |
                  |   |- jdbc
                  |   |
                  |   |- jpa
                  |
                  |- service
                  |
                  |- contorller 
                  |
                  |- util
                  |
                  |- exception

これはこれでシンプルで良いと思うのですが、例外に対するリカバリが行えないため、強いシステムにはなりません。 そこで検査例外を使うのですが、これもそのままexceptionに置いてあるアプリを良く見かけます。 これらの検査例外は大抵どこかのパッケージに依存しているので、そのパッケージ内に置くほうが良いと思います。

まとめ

パッケージ分割は、レイヤ分割、機能分割など、大まかな部分では共通すると思うのですが、細かな部分では個人の趣味が出るので指針をまとめてみました。

スタートアップ・マニュアルを企業内の新規事業開発へ応用する

スタートアップ・マニュアル ベンチャー創業から大企業の新事業立ち上げまで

スタートアップ・マニュアル ベンチャー創業から大企業の新事業立ち上げまで

業務上、研究や、新規事業について考えなければならない事がある。 これまで、幾つものアイデアを考え、プロトタイプソフトウェアを開発してきたのですが、それが事業に結びつくことは無かった。 これまでのプロセスには幾つもの間違いがあったのだと思う。

少しでもこのプロセスを改善するため、スタートアップマニュアルを読み、そのヒントを残そうと思う。

スタートアップマニュアルの一番の主張

オフィスを飛び出す

この本で、一番重要な点はこれ。本当にそのサービスや製品のニーズは有るのかを知ることである。例としてWebvanというサービスが載っているのだが、このサービスは必ず成功すると評判だったのにも関わらず、24ヶ月で倒産している。

これは、取締役や投資家の意見を聞き過ぎたために、実際にサービスを使用する顧客の潜在ニーズを無視した結果だといわれている。

実際、自分が担当した新規研究も顧客(この時は社内の事業部)のニーズに関しては実際に調査したわけでなく、単なる勝手な仮説を立てたのみ。その結果、リリースした時点でどこの部署にも受け入れられずお蔵入りとなるばかりだった。

社内研究開発部署は、よく現場社員から"お荷物"と揶揄されることが多い。その乖離を少しでも埋めるべく、新規研究のニーズを現場から調査し、そのフィードバックを受けるサイクルを素早く回す仕組みを作ることが必要である。

顧客開発モデル概要

スタートアップ・マニュアルでは、リーンスタートアップのプロセスを"顧客開発モデル"として、 4つのステップでまとめている。

  1. 顧客発見
  2. 顧客実証
  3. 顧客開拓
  4. 組織構築

顧客発見

ビジネスのビジョンをまとめ、実際に顧客との対話を繰り返しながら仮説/検証を繰り返す

このステップが自分には一番重要だった。これまではこの部分を我々のチームの思い込みで進めていた様に思う。ここで重要な事は以下の事。

  • 顧客は誰か
  • ターゲットとする顧客の課題は切実か。
  • 新製品・サービスを見せたときに、顧客は熱を上げるか。本当に課題を解決できるのか。

社内の研究開発では顧客は現場の開発部署、又はその顧客(ユーザ企業)である

課題の抽出

では、どの様に課題を抽出するか?その方法には以下のようなものがあるだろう。

  • 現場の課題抽出
    • 現場社員、幹部へのインタビュー
    • 課題管理ソフトウェアからの情報抽出
  • 社会の課題抽出
    • Webサイトからの情報抽出
    • ユーザ企業へのインタビュー
    • 情報交換会、社外勉強会での情報抽出

仮説と検証

ある程度の課題が設定できたら、その後はビジネスモデルの仮説を構築する。 この時に使えるのが、ビジネスモデルジェネレーションでも使用されるビジネスモデルキャンバス"である. これを使うことで抜け漏れがなくビジネスモデルを見直すことが可能である。

ビジネスモデルの仮説が検討出来たら、現場のステークホルダと連絡を取り、このモデルを評価してもらうことだ。もし全社に展開するようなソリューションを提供したい場合は、この時に顧客や市場を限定した話にしてはいけない。現在の技術動向、市場を跨いだ動向を話し、その中でこのソリューションはこういう価値をもたらすのだ、と話すようにする。現場の人間は現在の問題を解決することを主眼においている場合が多いので、有るべき姿を見せることも重要である。

次のステップについては又の機会で…

ビジネスモデル・ジェネレーション ビジネスモデル設計書

ビジネスモデル・ジェネレーション ビジネスモデル設計書

"SQLアンチパターン"を読み、MySQLにおけるNullの扱いについて再確認した。

SQLアンチパターン

SQLアンチパターン

DBMSを使う人なら誰もがハマるNullの取り扱いだが、結論から言うとDBMSのNullはよくあるプログラム言語のそれとは違うので、新しい物として正しく理解しようという事。Nullを怖がっては真っ当なデータ設計は出来ない。

DBMSにおけるNullとは

先に述べたように、DBMSのNullとアプリ側のNullは全くの別の物です。アプリ側のNullは値が存在しない事を示すのに対し、DBMSのNullは値が不定であることを示します。(3値論理と言われる概念が導入されています。)

そのため、以下のSQLMySQLで実行すると、Nullが結果として返ってくる。

> select Null + 1;
> Null

これは、Nullが不定を示す値であるため、何か分からない数に1を足しても何になるかわからないからである。

Javaだと?

そういう意味では、JavaのNaNと同様の物と考えると分かりやすいと思う。 (DBMSのNullは他の型に対しても同様の性質を示すことに注意)

public class NanTest{
  public static void main(String args){
    System.out.println(Double.NaN + 1);
  }
}
> NaN

上記のプログラムでも結果はNaNとなる。

Nullを用いた式評価

最もNullでハマる部分はここではないだろうか。 以下のSQLの挙動を不思議に思ったことは多くの開発者の記憶に有るはず…

> select Null = Null;
> Null

これも先の理由(Nullが不定であること)が分かるとなるほどと理解できる。 不定の値同士を比較しても結果が分からないのは当然である。

これを意図通りに記述する為には、以下の様に書く

> select Null is Null;
> 1

因みに、JavaでもNaN同士を比較してもtrueにはならない。

public class NanTest{
  public static void main(String args){
    System.out.println(Double.NaN == Double.NaN);
  }
}
> false

スカラー式でのNullの扱い

上記の様な動作をまとめた表が、SQLアンチパターンに有ったので一部引用させていただく

予想した結果 実際の結果
Null = 0 TRUE NULL
Null = 12345 FALSE NULL
NULL <> 12345 TRUE NULL

SQLアンチパターン 13.5.1 スカラー式でのNULL

論理式でのNull

論理式でのNULLの扱いも同様に、初めて見るときには"おっ?"と考えてしまうだろう。 これは以下の様になる。

予想した結果 実際の結果
Null AND TRUE FALSE NULL
Null AND FALSE FALSE FALSE
NULL OR FALSE FALSE NULL
NULL OR TRUE TRUE TRUE
NOT (NULL) TRUE NULL

SQLアンチパターン 13.5.2 論理式でのNULL

Nullは不要なのか?

この様な挙動を見ると、一部の開発者は拒否反応を起こし、Nullは使わないようにしよう!NOT NULL制約+デフォルト値や、使用されない値(0とか)で回避すること!と言い出す始末になる。これが恐怖のunknown現象である。

さらに、Nullを扱わないことの理由として、IS NULL 式にはインデックスが使用されないという理由もある。

MySQLではIS NULLでインデックスが使用される

他のDBMSは未調査だが、MySQLに関してはIS NULLでインデックスが使用されるので、これに関しては問題はない。

MySQL では、col_name = constant_value.の場合と同じ最適化を col_name IS NULLに対しても実行できます。 たとえば、MySQL では、インデックスと範囲を使用して、IS NULLで NULLを検索できます。

MySQL 5.1 リファレンスマニュアル 6.2.7. IS NULL最適化

Nullはデフォルト値や、使用されない値に置き換えられるのか?

これは状況により異なるため、完全に置き換えられるとは言えない。

例えば、ある商品に対するコメント(body)と評価(rate)を格納する以下のようなCommentテーブルが有るとする。 尚、評価を残さないテキストのみのコメントも可能であるとする。

create table Comment(
  comment_id varchar(100) NOT NULL;
  body text NOT NULL DEFALUT '';
  rate int DEFAUTL NULL;
  comment_by varchar(100) NOT NULL;
  );

この場合、NULLを避けるためにbodyをNOT NULLにし、デフォルト値を設定することは問題ないが、rateにはそれを適用するのは相応しいとは言えない。

何故なら、このCommentの仕様では評価を残さないコメントも存在するため、デフォルト値として数値を設定してしまうと後に評価の平均値等を計算させる際に評価を残さないコメントを除くことが困難になるからである。では、デフォルト値として絶対に使われない値(-9999等)を設定すると良いのではないか?と考えるが、その為にドキュメントを残す必要を考えると、それも上手くない。 このため、このような状況ではNullが妥当となるわけである。

まとめ

  • DBMSのNullはプログラム言語のNullとは違う
  • むしろNaNと似ている
  • Nullを全て排除しようとせず、適切に理解し、適切な場所で使うこと

今更ながら"Java Puzzlers"を読み始めた

Java™ Puzzlers: Traps, Pitfalls, and Corner Cases

Java™ Puzzlers: Traps, Pitfalls, and Corner Cases

以前から名著だと言われていた"Java Puzzlers"を読んでみたかったのだが、絶版になっていることを知り落胆。しかし、Kindle版が出ていることをJJUGで教えてもらったので嬉々として読み始めることにしました。(Kindle版なので英語ですが、iPhoneKindleアプリはその場で英単語を調べられるので通勤時間でサクサク読めます! )

内容はお遊びな感じだろうと思っていたが、j5ik2oさんも書いてるように"Effective Java"に書いてあるような内容に関する問題があったり、Javaの詳細な言語仕様を知れたりしてかなり面白い。

クリーンなコードに修正するための問題もあったりするので、Java中級者であれば一度読んでみることをお勧めします。

問題

さて、ここで"Java Puzzlers"から出題。 問題は"No.56 Big Problem"から。

以下のプログラムはなんと出力されるでしょうか?

public class BigProblem{
  public static void main(String[] args){
    BigInteger fiveThousand = new BigInteger("5000");
    BigInteger fiftyThousand = new BigInteger("50000");
    BigInteger total = BigInteger.ZERO;

    total.add(fiveThousand);
    total.add(fiftyThousand);
    System.out.println(total);
  }
}

正解は、"55000"... ではなく、"0"です。

なぜかというと、ご存じの方も多いかと思いますがBigIntegerはImmutableなクラスであり、BigInteger#addは返り値として加算結果を返すからです。 しかし、このメソッド名はCollectionパッケージのMutalbeなList#add等を連想させるため、良い名前とは言えません。 Java Puzzlersではこのメソッドに相応しい名前の候補として"plus"を挙げています。 こうすると、

total  = total.plus(fiveThousand);

となり、a = a + b のように英文的にも自然な文法として読めるため、綺麗なコードになると思います。

この辺りは流行りのリーダブルコートなどの"名前重要"でも言われている事ですが、Java APIでも意外と微妙なインタフェースのClassがあるものですね。

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

ubuntu serverでソフトウェアraid1の設定

ファイルサーバとして自宅のESXiサーバ上のVMにsoftware raid1を構成したので、そのメモ

環境

  • ESXi:ver 5.0
  • OS:ubuntu server 11.0

構成

  • 1.5TBx2のHDDをmdadmを使用してraid1
  • データディスクとして利用

レシピ

1.HDDの取り付け
先ずは、vSphere Clientから2つのHDDを接続。
この時、もちろんHDDは別のデータストアから生成すること。
(そうでなけりゃraid1の意味が無い)
2.HDDのパーティション作成

root@ubuntu-server:~# fdisk /dev/sdb
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0x754ddf48.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4, default 1): 1
First sector (2048-33554431, default 2048):
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-33554431, default 33554431):
Using default value 33554431

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
root@ubuntu-server:~#

3.ファイルシステムの作成
ext4に設定

root@ubuntu-server:~# mke2fs -t ext4 /dev/sdb1
mke2fs 1.41.14 (22-Dec-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
1048576 inodes, 4194048 blocks
209702 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=0
128 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000

Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 32 mounts or
180 days, whichever comes first. Use tune2fs -c or -i to override.
root@ubuntu-server:~#

4.ラベルの設定
特に必須ではないが、最近のLinuxではラベルでパーティションを管理するようだ。

root@ubuntu-server:~# e2label /dev/sdb1 /data

2,3,4を2つのHDDに対して行うこと。
5.RAIDデバイスの作成
RAIDデバイスとしてmd0をraid1で生成する。

root@ubuntu-server:~# mdadm --create --auto=yes /dev/md0 --level=1 --raid-devices=2 /dev/sdb1 /dev/sdc1
mdadm: /dev/sdb1 appears to contain an ext2fs file system
size=16776192K mtime=Thu Jan 1 09:00:00 1970
mdadm: Note: this array has metadata at the start and
may not be suitable as a boot device. If you plan to
store '/boot' on this device please ensure that
your boot-loader understands md/v1.x metadata, or use
--metadata=0.90
mdadm: /dev/sdc1 appears to contain an ext2fs file system
size=16776192K mtime=Thu Jan 1 09:00:00 1970
Continue creating array? (y/n) y
mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md0 started.

これでRAIDデバイスが生成されたので、この構成を保存する

# mdadm --examine --scan >> /etc/mdadm/mdadm.conf

6.RAIDデバイスの初期化(パーティションの生成+ファイルシステムの作成)

2,3,4と同様にしてファイルシステムを作成。ただし、fdオプションは設定しない。
7.RAIDデバイスのマウント設定

blkid /dev/md0p1

ここで表示されたUUIDを使用して, /etc/fstabを編集。

UUID=240170be-3115-xxxx-b943-0dc162f26cc1 /media/md0 ext4 defaults 0 0

fstabの設定を反映

# mount -a

マウントを確認する

# df