かとじゅんの技術日誌

技術の話をするところ

WEB+DB PRESSでJavaの連載を担当することになりました

6/24発売 の WEB+DB PRESS vol63 より Javaの連載を担当することになりました。

WEB+DB PRESS Vol.63

WEB+DB PRESS Vol.63

  • 作者: 竹迫良範,和田卓人,じゅんいち☆かとう,太田昌吾,小野修司,ミック,嶋田裕二,個々一番,みやけん,清水亮,おにたま,中島聡,角田直行,はまちや2,上谷隆宏,青木俊介,大塚知洋,生尾剛士,大和田純,WEB+DB PRESS編集部
  • 出版社/メーカー: 技術評論社
  • 発売日: 2011/06/24
  • メディア: 大型本
  • 購入: 19人 クリック: 428回
  • この商品を含むブログ (22件) を見る

「え、ScalaじゃなくJavaなの?」と思う方もいると思いますが、Javaもしっかり勉強しておきましょうね、ということで*1。まぁ、Javaは目新しい話題が少ないという説もありますが、なるべく現場の目線で面白いネタを提供できたらと思っています。どうぞよろしくお願いします。
今回のテーマは「コレクションライブラリの再考」です。身構えずに読める記事なっているので、書店で見かけたら手にとってみていただければ幸いです。

*1:どっかでScalaのネタをねじ込むかもしれませんが、、、

日経ソフトウエア 2011年6月号でScalaの特集記事を書きました

こんばんわ。
ブログの記事が滞っているときは執筆中だったりするわけですが、今回はScalaの記事を書きました。

日経ソフトウエア 2011年 06月号 [雑誌]

日経ソフトウエア 2011年 06月号 [雑誌]


私がScalaを始めたのは2010年10月ごろですが、それ以来取り憑かれたようにScalaをやっています。関連の書籍も買い込んで自炊してiPadで読み歩いています。また、近々、Scalaで実装したライブラリを公開する予定です。何事ごとも挑戦ですね。
Scalaの特徴はオブジェクト指向言語関数型言語のハイブリッド言語というのはよく知られていますが、記述性が極めて高いというところが気に入ってます。簡潔で明瞭にコードの意図を伝えるプログラミングできるというのは本当にすごいことだと思います。
今回の特集は、Javaプログラマを対象にして、Scalaを始めるきっかけの特集記事になっています。また、簡単ですが、IntelliJ IDEAの構築方法にも触れています。レビューをしてくれた、id:yuroyoroid:xuwei ありがとう!
書店で見かけたら、手に取ってみていただければ嬉しいです。

ちなみに、入門記事でページ数が限られているのでプログラムの書き方は説明していますが、言語としてなぜそのようになるかの深い原理をあまり説明していません。そのあたりを詳しく知りたい方は以下の書籍がお勧めです。順不同です。

オブジェクト指向プログラマが次に読む本 ?Scalaで学ぶ関数脳入門

オブジェクト指向プログラマが次に読む本 ?Scalaで学ぶ関数脳入門


ボクらのScala ~ 次世代Java徹底入門

ボクらのScala ~ 次世代Java徹底入門


Scalaプログラミング入門

Scalaプログラミング入門


Scalaスケーラブルプログラミング[コンセプト&コーディング] (Programming in Scala)

Scalaスケーラブルプログラミング[コンセプト&コーディング] (Programming in Scala)


プログラミングScala

プログラミングScala

「エリック・エヴァンスのドメイン駆動設計」 を献本していただきました

嬉しいことに「エリック・エヴァンスのドメイン駆動設計」 を献本していただきました!
訳者の和智さん、関係者の方々、翔泳社さん ありがとうございます。おめでとうございます!Tシャツまでもらった!!

実は、私とid:daisuke-mは、この翻訳版の実装編のレビューに参加させていただきました。
昨年、DevLOVEのイベント「Beautiful Develpment」でDDDの話を聞いた後に、翻訳版が発売される噂を聞きつけ、和田さん(id:t-wada)に「レビューに参加したい!」と無理を言って、訳者の一人である和智さん(id:digitalsoul)を紹介してもらいました。
和智さんは快く対応くれて、レビューさせてもらうことになりました。ありがとうございました。

ドメイン駆動設計との出会いは、id:daisuke-mに勧められたのがきっかけです。洋書だし、分厚くて枕になりそうだし、英語も文体が固く、エンティティの章を読むと裁判がどうのって、読むのはハードルが高かった。。

しばらく読み進めて、id:ashigeru の思惑通りDDDが気に入った俺は、今度は上司 id:j5ik2o にこの本を買って読ませる、という暴挙に出る。この本の内容を理解して、俺と共感してくれる変態はこの人しかいないだろう、と。まぁ、思惑通り上司はこの本に魅了され、翻訳レビュー謝辞にまで名を連ねるに至った。

でも、この本の中には設計と実装の面で深い示唆を与えてくれるという。「う〜ん、う〜ん」と言いながら英語を訳しながら読みました。簡単にいうと現実世界の問題をオブジェクト指向を使って設計・実装するにはどうしたらよいか、そういう示唆を与えてくれる本です。ドメインと聞くと業務系のノウハウかと勘違いしそうですが、オブジェクト指向設計やプログラミングに関する濃い話題の本だと思ってもらえばよいかと思います。
オブジェクト指向懐疑論を唱える人もいるくらい、オブジェクト指向は、本当の意味で理解が難しいし、それをシステム化する業務の対象で扱う場合は、どのように現実世界と抽象的なオブジェクトを関連付けるべきか、特に難しいです。それらに立ち向かうために、世の中には様々な設計手法が存在しますが、DDDはそれらの設計手法を踏まえた上で、ドメインをオブジェクト指向で解決するための新しい道しるべを示してくれると思っています。難しいからって諦めていては良いものは作れませんから、こういう本を読むわけです。まぁ、今年一番のお勧めの書籍であることは言うまでもありません。

近々に、以下のイベントも控えていて、今年は日本のDDDの夜明けを見ることになりそうです。
4月9日 Beautiful Development ソフトウェアの核心にある複雑さに立ち向かう(東京都)
セッション スピーカー : Eric Evans|QCon Tokyo 2011 Conference|QCon 東京 2011 カンファレンス

ということで、オブジェクト指向に慣れてきて、これからどういう設計や実装がよいか、暗中模索している悩めるプログラマにはぜひ読んでもらいたい一冊です。

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

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

日経ソフトウエアの特集がムックになりました

まず、
3月11日の「東北地方太平洋沖地震」で、被害にあわれた皆様に心よりお見舞い申し上げるとともに、犠牲になられた方々とご遺族の皆様に対し、心よりお悔やみを申し上げます。
私も関西出身で阪神大震災の酷さを体験している人間でもありますし、気を負わずに自分なりにできることはやっていきたいと思います。ということで、通常通り ブログの方は継続します。



お知らせです。これまでに日経ソフトウエアで執筆した特集がムックになりました。
Javaツール完全理解 (日経BPパソコンベストムック)

Javaツール完全理解 (日経BPパソコンベストムック)


タイトルはJavaツール完全理解ということで、前半はJavaの開発環境やビルドツールなどの開発に必要なツールの解説があり、後半は私の記事を含めて実装編の記事が満載です!!

私が担当したのは以下です。
【第2部】 最新Eclipseで良いJavaプログラムを書こう
【第4部】 現場で通用するソフトウエア設計を学ぼう

読みどころ

読みどころとしては以下です。
【第2部】については、Javaで良いプログラムを目指すにはどういう視点を持つべきかというテーマで、Eclipseの基本から入ってオブジェクト指向ポリモーフィズムをおさらいしながら、後半ではドメイン駆動設計(DDD)に基づいてRDBMSスキーマを作成するツールの開発を実践的を紹介しています。
この当時はまだDDDの翻訳本が出ておらず、本誌初登場でどのように解説すべきか、日経BPさんとも悩みながら書いた記事でした。そして、いよいよ4月にDDDの翻訳本が出ます。DDDは簡単にいうとオブジェクト指向を生かしたアプリケーション開発をしようという哲学です。オブジェクト指向は面倒だから使えない、で思考停止するのではなく、自分たちが実際に使ってみて評価して改善を加えていくべきだと思います。その意味では第一歩としてDDDを学ぶことは間違いではないと思います。
情報源としては、まず翻訳本です。これは間違いありません。それ以外に日本語の情報源はまだ少ないので、今回のムックは一つの情報源として活用していただければ幸いです。

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

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

そして、【第4部】については、【第2部】とは違ってDDDは全面に出ていません。もしかしたら、こちらの方がみなさんが日常で書いているコードに近いかもしれません。ここでのテーマは現場で通用する設計とは何か。まさに幅広いテーマですが、一例として設定ファイルに基づいてJavaBeansを生成するコードジェネレータを設計/実装する特集になっています。
その中で様々なノウハウを紹介していますが、中でも「不変性」についてページを割いて説明しています。
若干、話しが逸れますが、18ヶ月でCPUのチップ性能が倍になるというムーアの法則があります。それを維持するためにマルチコア化に流れています。今や18ヶ月でCPUのコア数が2倍になる法則になっていくだろうとも言われています。この変化によって、これまで以上に並行プログラミングに気を配らなければならなくなるでしょう。このストーリについては「Java: The Good Parts」の並行処理にもっと分かりやすく書かれているのでぜひ読んでみてください。

Java: The Good Parts

Java: The Good Parts

この並行処理の課題に対応するには、「不変性」について理解しなければなりません*1。「不変性」は、並行処理以外にも、理解しやすい、テストしやすいプログラムを作る上でも効果があると言われています。この「不変性」の考え方は、最近話題の関数型言語設計思想の根底にもあります。「不変性」を今のうちに学んでおくと、関数型言語の学習がしやすくなるかもしれません。

*1:不変というのはどのような操作を行っても状態を変更することができないオブジェクトを作るための考え方です

ScalaでBrainf*ckインタープリタを実装してみた

ScalaでBrainf*ckのインタプリタを書いてみたよ - 都元ダイスケ IT-PRESS
Scalaを頑張っておるようなので、私もBrainf*ckのインタープリタをなんとなく実装してみた。

BrainfuckRuntimeと、Expression系のクラスが関数型らしくないのでなんとかしたいな...。
ソースはgithubにあげてます。ツッコミ or フォーク歓迎 https://github.com/j5ik2o/brainfuck-scala
とりあえず、nullチェックとか、例外処理は適当です。

package com.github.j5ik2o.brainfuck

object BrainfuckApplication {

  def main(args: Array[String]) =
    try {
      new BrainfuckRuntime(new BrainfuckParser).execute(args(0))
    } catch {
      case BrainfuckException(msg) => println(msg)
    }

}

以下のように実行するとHello World!が表示されるはず。

$ scala com.github.j5ik2o.brainfuck.BrainfuckApplication "++++++++++[>++++++++++<-]>++++.+++++++.--------.--."

以下、パーサーとランタイムのソース。

package com.github.j5ik2o.brainfuck

case class BrainfuckException(msg:String) extends RuntimeException

class BrainfuckRuntime(parser: BrainfuckParser, size: Int) {
  require(size > 0)

  val memory = Array.fill(size)(0)

  var pointer = 0

  var counter = 0

  val evaluator = new Evaluator()

  def this(parser: BrainfuckParser) = this (parser, 3000)

  // Brainfuckのスクリプトを実行する
  def execute(script: String) {
    val parseResult = parser.parse(script)
    if (parseResult.successful) {
      evaluateExpressions(parseResult.get)
      println
    } else {
      throw new BrainfuckException("parse error")
    }
  }

  // ASTを評価するビジター
  class Evaluator extends ExpressionVisitor {

    override def visit(expression: Expression): Unit = expression match {
      case IncrementPointerExpression() => incrementPointer
      case DecrementPointerExpression() => decrementPointer
      case IncrementMemoryAtPointerExpression() => incrementMemoryAtPointer
      case DecrementMemoryAtPointerExpression() => decrementMemoryAtPointer
      case OutputMemoryAtPointerExpression() => outputMemoryAtPointer
      case LoopExpression(expressions: List[Expression]) => loop(expressions)
    }

  }

  // 以下、ランタイムが持つAPI

  private def validateRange =
    if (counter > size) throw new BrainfuckException("limit over")

  private def readMemory = {
    validateRange
    memory(pointer)
  }

  private def writeMemory(b: Int) = {
    validateRange
    memory(pointer) = b
  }


  private def incrementPointer {
    validateRange
    pointer += 1
    counter += 1
  }

  private def decrementPointer {
    validateRange
    pointer -= 1
    counter += 1
  }

  private def incrementMemoryAtPointer {
    writeMemory(readMemory + 1)
  }

  private def decrementMemoryAtPointer {
    writeMemory(readMemory - 1)
  }

  private def outputMemoryAtPointer {
    print(readMemory.toChar)
  }

  private def loop(expressions: List[Expression]) {
    while (readMemory != 0) {
      evaluateExpressions(expressions)
    }
  }

  private def evaluateExpressions(expressions: List[Expression]) {
    expressions.foreach(_.accept(evaluator))
  }


}

Scalaのパーサコンビネータを使って実装しているので、以下のURLを読むとコードを理解しやすいと思います。
http://www.coins.tsukuba.ac.jp/~i021216/Scala-parser-combinator.pdf

package com.github.j5ik2o.brainfuck

import util.parsing.combinator._

// 式を訪問するビジター
trait ExpressionVisitor {
  def visit(e: Expression): Unit
}

// 式を表すトレイト
trait Expression {
  def accept(visitor: ExpressionVisitor): Unit = {
    visitor.visit(this)
  }
}

// 式の実装 これを使ってASTを構築する
case class IncrementPointerExpression extends Expression
case class DecrementPointerExpression extends Expression
case class IncrementMemoryAtPointerExpression extends Expression
case class DecrementMemoryAtPointerExpression extends Expression
case class OutputMemoryAtPointerExpression extends Expression
case class LoopExpression(expressions:List[Expression]) extends Expression

// Brainfuckパーサ
class BrainfuckParser extends JavaTokenParsers {

  def parse(source:String) = parseAll(brainfuck, source)

  def brainfuck: Parser[List[Expression]] = rep(instruction)

  def instruction: Parser[Expression] = loop | token

  def token: Parser[Expression] = incrementPointer ||| decrementPointer |||
    incrementMemoryAtPointer ||| decrementMemoryAtPointer ||| outputMemoryAtPointer

  def incrementPointer: Parser[Expression] = ">" ^^ {
    case ops => IncrementPointerExpression()
  }

  def decrementPointer: Parser[Expression] = "<" ^^ {
    case ops => DecrementPointerExpression()
  }

  def incrementMemoryAtPointer: Parser[Expression] = "+" ^^ {
    case ops => IncrementMemoryAtPointerExpression()
  }

  def decrementMemoryAtPointer: Parser[Expression] = "-" ^^ {
    case ops => DecrementMemoryAtPointerExpression()
  }

  def outputMemoryAtPointer: Parser[Expression] = "." ^^ {
    case ops => OutputMemoryAtPointerExpression()
  }

  def loop: Parser[Expression] = "["~>brainfuck<~"]" ^^ {
    case exprs => LoopExpression(exprs)
  }

}

Scalaの統一アクセス(プロパティ構文)がなかなかイカしてる件

今回は統一アクセス(プロパティ構文)がなかなかイカしてる件について。C#とかRuby,Pythonやってる人からすると何を今頃という感じなのですが。

Scalaで統一アクセス(プロパティ構文)を使う

Scalaでフィールドを宣言する場合は以下のような書き方になります。

class Employee(name_ : String) {
  var name = name_
}

クライアント側のコードは以下。

val e = new Employee("Kato")
e.name = "Kato"
println(e.name) // Kato

追記:
上記のようなコードは以下と同じ意味なので、こちらのほうが短くてわかりやすいので適切。

class Employee(var name : String)

Employeeのnameはpublicなフィールドですね。*1

nameフィールドには大文字の文字列のみを格納したいという制約を付ける場合は、このままではダメです。setterを追加する必要があります。JavaだとsetNameやgetNameを追加することになるので、クライアント側は変更の影響をもろに受けてしまいます。
しかし、Scalaの統一アクセスはそんなことはありません。

class Employee {
  private val re = """([A-Z]+)""".r // 正規表現
  private var name_ :String = _ // _はその型に応じたデフォルト値

  def name = name_
  def name_= (value:String) {
    name_ = value match {
      case re(v) => v // 正規表現でパターンマッチし、該当した値を取得しmatch式の戻り値として返す。
      case _ => throw new IllegalArgumentException
    } // match式の戻り値をname_ に代入
  }
}

このようにすると、以下の代入は事前条件を違反するので例外がスローされます。

val e = new Employee
e.name = "Kato" // IllegalArgumentExceptionがすっ飛びます!
println(e.name) // Kato

setterだけではなくgetterでもフィールドとしては保持していないけど、getterが呼ばれた場合に値を計算する(導出という)場合も同じ要領でgetterを定義できる。

class Employee {
  def name = {
    // ロジックでnameを導出する
  }
}

統一アクセス(プロパティ構文)は何も目新しい機能ではない

古くはEiffel - Wikipediaという言語が発祥だそうです。EiffelWorld Column by Dr. Bertrand Meyerの、ページの上の方に書いてある通りですが、気がつけば多くの近代的な言語でサポートされています。
スクリプト言語では、RubyPython
Ruby

class Employee
  def name
     @name
  end 
  def name=(n) 
     @name = n
  end
end
e = Employee.new
e.name = "Kato"

Python

class Employee:
    def setName(self, name):
      self.__name = name
 
    def getName(self):
      return self.__name

    name = property(getName, setName, doc="name")
e = Employee()
e.name = "Kato"

コンパイラ言語では、Delphi言語(旧ObjectPascal)はこんな感じ。私はDelphi1.0でプロパティ構文を初めて書きました。

type
  TEmployee  = class(TObject)
  private
    FName: string;
    function GetName: string;
    procedure SetName(const Value: string);
  public
    //Nameプロパティ
    property  Name : string      read GetName write SetName;
  end;

implementation

{ TEmployee }

//Nameプロパティ (GET)
function TTestClass.GetName: string;
begin
  Result  :=  FName;
end;

//Keywordプロパティ (SET)
procedure TEmployee.SetName(const Value: string);
begin
  FName  :=  Value;
end;
var
  Employee : TEmployee
begin
  Employee = TEmployee.Create;
  Employee.Name = "Kato";
end;

C#も初期からプロパティ構文をサポートされていました。C#Delphiの生みの親は、アンダース・ヘルスバーグですから、当然と言えば当然。

class Employee {
  private String name;
  public String Name {
    set{ this.name = value; } // setter
    get{ return this.name; } // getter
  }
}
Employee e = new Employee();
e.Name = "Kato";

統一アクセスは、いくつかの言語で普及し現在のバージョンでも利用できるということは、ある程度成功したといえると思います。Scalaの統一アクセス機能もこれらとほぼ同等の機能なので間違いないと思います。setter/getterの手間を最小化できるので便利だと思います。

まとめ

ちょっとしたことだけど、日常的に使うだけにこの機能は欲しい。Javaではいつごろ採用されるのかな。JavaBeansとの整合性とか考えると現実的ではないような気もしますが。Java8でも登場しない感じすかね?よく知らない。。
ともあれ、Scalaなら今すぐ書けますね。クライアント側のコードを変更しなくてもよいから、YAGNI原則に従って、必要になった時点でアクセッサを作ればよいということですね。

補足:
id:ryoasaiさん の質問を受けて、参考までにScalaのフィールド宣言がJavaのコードでどういう表現になるか調査してみました。

class Employee{
  var name:String = _
}

だと、以下で、

public class Employee
    implements ScalaObject {

    public String name() {
        return name;
    }

    public void name_$eq(String s) {
        name = s;
    }

    public Employee() {
    }

    private String name;
}

そして

class Employee{
  private var name:String = _
}

だと、こうなる。

public class Employee
    implements ScalaObject {

    private String name() {
        return name;
    }

    private void name_$eq(String s) {
        name = s;
    }

    public Employee() {
    }

    private String name;
}

んで、今度はこれ。

class Employee{
  private[this] var name:String = _
}

では、このようになりました。id:kxbmapさんのご指摘のとおり、本物のフィールドですね。

public class Employee
    implements ScalaObject {

    public Employee() {
    }

    private String name;
}

オーバーライドする場合は、抽象フィールドの時だけだと思います。こういう場合

trait Employee{
  val name:String
}
class SubEmployee extends Employee {
  override val name:String = "aaa"
}
public interface Employee {

    public abstract String name();
}
public class SubEmployee
    implements Employee, ScalaObject {

    public String name() {
        return name;
    }

    public SubEmployee() {
    }

    private final String name = "aaa";
}

追記:
@ さんより、正規表現の間違いの件 指摘もらいました。修正しました。ありがとうございます。

*1:実際のバイトコードレベルではnameフィールドとname()というgetterが出来ているのですが、それは一旦忘れます。