09

Javaエンジニア養成読本よんだ

けど、その内容については書かない。

Javaエンジニア養成読本 [現場で役立つ最新知識、満載!] (Software Design plus)

Javaエンジニア養成読本 [現場で役立つ最新知識、満載!] (Software Design plus)

Javaエンジニア養成読本という本があって、その頭できしだ(@kis)さんという人が今までのJavaについてまとめてられていた。自分としてはいろいろ脇道にそれつつも10年程度Javaでやってきているので、懐かしい話を読みながら自分でもいろいろ考えたことを思い出したので書いてみた。

まぁあんまりまとまらなかったんだけど、出さないといつまでも下書きに保管されたままになるので出してしまう。

中途半端に神が登場する

オブジェクト指向という思想は既に世界が組み上がってしまっている前提で語るには美しい論理なのだけれど、その世界をくみ上げる作業についてはあまり現実的には考えられていないと思う。

車オブジェクトは車体オブジェクトとタイヤオブジェクト×4の組み合わせでできていて、accelerate() をコールすれば車輪は回り前へ進む。だけれども、そのまえに車自体を組み立てる必要がある。そのためには Engineer とかいうクラスを用意して、constructCar() とかなんとかいうメソッドを用意して、そこに組み立て方を記述してやると良い。 Engineer がいることによって車オブジェクトをまともに使えるようになるがしかし、これがまた新たな問題を生む。Engineer インスタンスを果たして誰が生み出すのか。 それは当然 Enginner に父と母がいてという事なんだが、こんな事を延々繰り返していくうちにアダムとイブまで記述しなければ成らなくなるので、もういいよというわけで神様が Engineer インスタンスを作り出す(あるいはEngineerは自然発生する)事にする。

どこから神様が介入していいのかは議論があるだろうが、まあそんな事はどうでも良い。要するに、オブジェクト指向の基本コンセプトはその世界を構築する段階ではちょっと忘れた方がいいってことで、この辺まだ進化の余地がある気がしている。

リテラルは悪っぽい

割と2000年代から、リテラルは悪という感じの空気がある気がしている。Javaコードに成っているものには一切のデータを含んではならない、というような。

基本リテラルとして扱えるものは何らか別ファイルにされる事に成っている。これはJavaがコンパイル言語であることに起因しているような気はする。つまり、コード中に書かれてしまうと変更の度にコンパイルし直さなければならないしアーカイブし直さなければならない。

慣習的にリテラルはすべて外部化されるべきみたいな空気が出来上がってる気がする。

その影響を受けてなのかなんなのか、Javaはリテラルがとても貧弱だと思う。リテラルが使いにくいということはテストに悪影響を与えているような気がしないでもない。 神様の話とも関連するが、テストはとにかくテストの前提状態をくみ上げるブートストラップが簡単に書けないといろいろつらい(はず)。設定とか外部ファイルでできるから良いじゃんということかもしれないが、個人的にはその程度の分離でも面倒だ。コードの世界でブートストラップを分かりやすく簡潔にまとめる為にはやはりオブジェクトリテラルが、当然、簡潔な形で存在したほうがいい(のではないか)。

最終的に別の言語が誕生する

さて2000年代後半になるとリテラルに留まらずコンポーネント同士の接合も外部化するのが良いという空気になってきた。いわゆるDIによって。発想の起源としてはEJBのようなローカル・リモートでオブジェクトを分散するといった話だったのかもしれない。 コンポーネント同士の接合面はInterfaceとして設計され、その実態は設定や特定の規約によって構成される。

これがさらに進み、コンポーネントは細分化し設定の記述量は増え、気がつくと設定ファイルでプログラムを組むような事さえできるようになっていて、それってもはや設定じゃなくてスクリプト言語じゃないの、といった域に達すると末期である。

共通化というか規格化できたらドメインを記述する為の新しい言語に成りうるのかもしれないんだけど、そこまで突き抜けた人は未だ見た事は無い。BPMの分野がこの辺掘り下げていってそうな気がするけどどうなんだろ。個人的にはBPMは最終的にビジネスの人がコード書くのと変わらない状態にたどり着くと思っているのであまり真剣に見ていないのだけれど。

コードの文脈感と型

rebuild.fm#59 (http://rebuild.fm/59/) にて、まつもとゆきひろさん (@yukihiro_matz)が、こんなような事を言っていた。

  • 手続きが書いてあることで何となくそのオブジェクトに要求しているものが記述されている。それが型のようなものを表しているはず。
  • そこにさらに型を書くのは冗長。

長くJavaを書いてきた者の感覚としては型は単に情報の型ではなく役割としての意味合いも期待しているところがある。手続き的に処理を書いていく事でボトムアップ的にそのロジックやオブジェクトの役割が決まっていくのと平行に、トップダウン的にクラスとして役割を明示することで自分の思い描いているロジックやクラスの構成に誤りというか違和感が無い事を検証したいという欲求がある。 しかし考えてみれば、現状これはコードの見た目上違和感がなくなるということで自分の中で確認しているだけの事であって、コンパイラによってロジックと役割の矛盾が指摘されるという訳ではないから別に静的型付けの優位性ではないのかもしれない。

いやいや。ずらっと手続きから書いていった感覚と、クラスの定義を中心に見た時の感覚と、コンパイラのチェックの3本の柱で設計の違和感を抽出していっているのだ。そのはず。そんな気がする。多分。

EmacsでJava楽しめるわけない(と思っている)

上記のような感覚でプログラムを書く事に慣れていくと、プログラムができていくに従って増えてくる概念を分離したりメソッドの構成を全体的に見直したりと言った事が発生しやすいのかもしれない。これはあくまで設計ベースで行われるので、その処理に流れるデータがいかに効率的に処理されるかは若干蚊帳の外に成る。 現在のJavaであれば、メソッドやクラスの再編成や分離・統合はIDEがかなりの部分でカバーしてくれている。これが静的な型無しで実現できるものなのか、がJava使いからLLを眺めたときに不安になる。

この辺、Java(というか私の感覚)ではリファクタリングの範疇なんだけど、「そもそも機能が変更されるならリファクタリングといわないだろ」というツッコミを見たことがあるので、人によってはリファクタリングじゃないのかもしれないが、個人的にはこのレベルの変更は安全にできないと快適にプログラミングできない。

そもそも、LLに慣れた人がLLを書く感覚と、Javaを書く人がJavaを書く感覚はメンタルモデルからしてに大きく異なっているだろうなあとは感じている。あくまでJava屋の私の感覚で言うならば、LL系のプログラムを書く際には、関心の中心となるデータに対して、積極的に処理によって関与していくようにコードを書く印象を持っている。Javaでコードを書く場合には、まず存在するデータや概念をクラスやアーキテクチャによって表現することから始まる。データの実態に関与するのは、抽象化できなくなった所でようやくと言った印象がある。 LLで書く場合はいきなり本題である問題を解くコードを記述し始める(ような気がする)といえばいいのか。それに対して、Javaで書く場合はまず問題を解くための世界をどう構築するかから入ってるような気がする。感覚としては、本題である問題を解くコードをうまく記述するために、中間レイヤーをもう一つ設計しているような感覚がある。

まあこれは単に経験の違いというだけのことかもしれない。(つまり、私はLLでちゃんとしたシステムを作った経験が乏しいので、いままでJavaでしてきたような経験を得ていない、というような。まああるいは逆に、Javaでも最近はそんなやり方ができるように変化してきているところもある)

setter getter

getter/setterでなんやかんや公開したくない処理を書いても最終的に取り除いてる場合が多い気がする。結局外部からコントロールできない部分があるコンポーネントというのは後々の保守なり拡張でネックになりがちな印象がある。 個人的にはgetter/setterはIDEで生成してしまう派なので、getterとかsetterの中に処理書くなと思っている。Beanにバグになりうるようなコード入れて欲しくない、というのもある。つまり、publicフィールド使えばいいような気がしている・・・が、publicフィールドだとそれはそれで問題だと思った経験がある気がするのだけど、具体的に思い出せない。逆にprivateは極力使わないほうがいいと言えばいいのか。(多分フレームワーク屋さんはもうちょっと違った見解があるだろう)

プロパティはまああってもいいけどC#みたいなんだったら今更入れてもらってもという感じはある。Lombokは使ったことがないけど、わりと好評のようなのでそれでいいのかもしれない。

別に率直に書いても良い筈

Javaを敬遠する向きに多いのは、文法が冗長というものだが、文法として冗長というよりも文化的に回りくどい事をしたがると受け止められているのではないかという気がする。もちろんLLに比べれば冗長にならざるを得ないのはそうなのだけれども、Javaの常識を無視して今までとは違った姿を目指してみるのもいいのかもしれない。

Java EE

いまやWeb開発をするには必須ではないにしろ押さえておくべきポイントになったと言っていいとは思う。先進的なフレームワークがいろいろある中で着実な手法を選んで進歩することで人類の英知を蓄積して行っている。・・・とまでは言わないんだけど、そんな感じなので先進性はない気がする。かといって10年大丈夫かというと、なんだかんだコンポーネント毎に勃興ある感じなので必ずしもこれ使っとけば10年安心というわけでもなさそう。まあ、大丈夫だったとしても今から10年前のJavaのコードなんて見たくないというのが本音であるので、正直なんでもいい気はする。

JSFとJPAが2大悩みの種という感じがする。みんな関心があって人気のある部分なのだけど、なかなかカッコよく問題が解決されない。

JSFは使ったこともないんだけどここのところフロントはクライアントサイドで生成するのも普通になってきているし、個人的には現状のJSFは解決する問題に対してレイヤが厚すぎるという印象があってHTTPとの親和性も薄い気がしている。最終的にはデザイン(見た目)がネックになってあまりオープンに流行ることはないと思っているけど、どうなんでしょ。

JPAもこれ以前の永続化レイヤーと比べればマシなんだろうけど別に使わなくていいじゃんという空気がある気がする。個人的には永続化レイヤーはメモリに置いてあるものとストレージに置いてあるものをシームレスに扱えるようにすることが命題だと思っているので、今の仕様では物足りない。ストレージから必要なオジェクトグラフを柔軟に切り出したり書き戻したりできなければならないが、それができる仕様ではない。少なくとも今のスペックリードはその辺意識しているような記事をどこかで読んだので、5年とか10年くらいしたらそれなりになるのかもしれないけど、そんなに待ってたらメモリかストレージが進化してJPAの解こうとしている問題自体を消し去ってしまう可能性がある。