Javaプログラマになってしまった
小生、プログラムに使った最初の言語は、BASIC。そう、あの有名なBASIC。Visual Basicではない。Bill Gatesが、ハーバードの学生だったころ、Microsoftか、それともその前身の名前の会社だったのだか定かではないが、自分たちで作って、それをまんまと、当時の米国のホビーストのマシンだったAlltairに売り、さらにIBMにまで使わせることに成功した、あのinterpreter言語だ。
BASICを使って、私も、学生のころ、当時日本で売られていたSharpの『マイコン』で、色々とゲームを作った。ASICだと言ってもバカにしてはいけない、学生時代はゲームだったが、それなりに物理や数学を駆使したアプリだった。社会人になってからは、事務所で使っていたIBM PCに乗っていたBASICを駆使して、本業の合間に仕事で使うシステムを色々と、EUC(End User Computing)の一環で作った。
その後は、DBaseIIIなるものを使って、Relational Databaseの構造が必要な結構複雑なアプリを作ったり、性能を要求されアプリをCで作ったり。かなり大きなデスクトップのWindowsのアプリをC++で作ったりした。そこら辺りまでが、僕のアマチュアプログラマとしての実績だ。
私の定義でのプロのプログラマとは、しっかりと給料をもらえる仕事のなかでフルタイムでプログラムの作業をする人のことだ。プロになった直後、Javaを使った開発を約1年行うことになった。それは、デスクトップのアプリでSwingを使ったものだった。
約1年Javaを経験した後は、Microsoft陣営に入り、最初は、いわゆるclassic ASP。Microsoftが.NETをリリースした後は、.NET一本で約10年、ここまで来た。その間のプロのソフト開発の仕事で、Javaを使ったことは最初の1年を以外はない(*1)。ところが、今回Javaを使って開発することになり、今いろいろと勉強している。
ところで、私が『.NET』や『Java』とここで書くときは、言語のことを言っていない。そこら辺りは、.NETを、C#とかVB.NETとかいう言語で代表していないことからも、悟ってほしいが、両者を開発のプラットフォームなどを代表する単語として使っている。つまり、.NETと書けば、それがVisual Studioを使って開発し、VSSでソース管理する。
WebアプリはIISの上にASP.NETやASP.NET MVC。リッチなクライアントアプリはSilverlightやjQuery。デスクトップアプリはWPF。そして、エンタープライズアプリは、WCFやWFなど。ORMにはLINQ to SQLやNHibernate、そしてADO.NET entity framework。そして、非同期通信にはMSMQなど使う開発環境のことを指す。
Javaの陣営は、実はまだあまり把握していないが、開発環境はEclipseやNetBeans。ソース管理はSVN。そしてWeb アプリはApacheのTomcatの上にJSPやサーブレットそしてStruts, Java Server Faces。そしてエンタープライズアプリは、Java EE(旧J2EE)。最近は、このJava EEはPOJOの思想のものに置き換わっているらしく、今はSpringや、iBATIS、 そしてHibernateを使うらしい。
異論のある人も多いかもしれないが、現代のWebシステムの2大プラットフォームは、この.NETとJavaだと思う。他に、Ruby on RailsやPython、そしてPHPなどもあるが、言語の周りを囲むフレームワークの充実度を考えると、やはり.NETかJavaが2大プラットフォームだろう。そして、それは、技術を習得するためには充実したフレームワークの習得に時間がかかるということをも意味する。
誤解しないでもらいたいが、チームの中の1メンバーとしてソフト開発を行う場合、開発環境の違いなど、あまり大きな障壁ではなり、優秀なチームリーダーが、新しく入ったメンバーを多分1日で戦力にしてくれる。そして、それが出来ないチームリーダーはリーダー失格だ。
新しいプラットフォームに移行するときに苦労するのは、自分がチームリーダーのときだけだと思って良いと思う。そこら辺り、日本、そして世界の開発現場で開発者を選考するとき、どこまで理解しているのか、ちょっと疑問だったりする。面接で聞かれるのは、「Javaの経験は何年?」とか、どうでもいいことを聞かれることが多い。確かに一番聞きやすいことなので、面接で聞きたくなることは分かるが。
ここからは、.NETのプロの私が、今回Javaを再習得して、記憶が新しい間にJavaについて思ったことを少し書いてみる。書いてみて思ったが、書けることは、Javaに対する不平、不満でしかない。
- クラスのプロパティーのコードが、Javaでは長くなってしまう。例えば、C#では、
public int Count {get; set;}
と書けるところが、Javaでは、
private int _Count;
public setCount(int c)
{
_Count = c ;
}
public int getCount()
{
return _Count;
}
と、なってしまう。IDEが持つコード自動生成の機能を使うと、上記のJavaのコードなど、1発で書けるが、私はコード自体の長さを問題にしている。
2. Javaにはプリミティブ型を表すクラスが、プリミティブ型そのものと、そのプリミティブ型をラップするクラスの2種類あって、それを使い分けなくてはならない。
3. Javaにはchecked exceptionとunchecked exceptionの2種類のExceptionがあるが、checked exceptionを投げる可能性のあるメソッドを使う場合、そのExceptionをメソッドの定義の「throws」節で、宣言しなければならない。そして、throws節が宣言されているメソッドをコールする側が、かならずそのExceptionをcatchしなければならない。
.NETでは、Exceptionをcatchする場所は、それを投げたメソッドの外側のコールスタックでありさえすれば、どの層のコールスタックでもよい。例えばWebアプリ、ページの処理が1回1回、別のThreadで処理されるような単純出来るWebアプリでは、メソッド呼び出しスタックの1番外側で全てのExceptionをcatchするのが普通だ。ほとんどのケースでExceptionは、それを投げたメソッドを呼び出した直近で処理できることはないので、.NETのやり方が、もっとも理にかなっていると思う。
しかし、Javaではunchecked exceptionでしかその方法が使えない。 結果、前任者のコードを見ると、catch blockの中が空っぽになっている、つまり、エラーを無視する最悪のコードが散見される結果になっている。Javaを最初に作った人は、自分たちの生真面目さが、全世界のプログラマも同じく通用すると思っていたのだろう。開発言語は、生真面目でない開発者でもしっかりと、ちゃんとしたコードが書けるようなものでないと行けないと思う。
4. Javaには.NETのdelegateやラムダ式など、関数を変数として扱える仕組みがない。Javaのコードを見ていると、とにかくswitch文が多いような気がする。与えられた変数によって、行う処理を切り替えるような処理はswitch文で書くしかないためだ。
.NETではdelegate、そして、それをより簡易に書けるラムダ式などを使えるので、コードがよりすっきりしたものになる。delagateのもっとも強力な使い方は、関数そのものを、別の関数への引数として渡すというものだが、これは例えば、非同期の処理を扱うときなどのコードが、非常に簡単なものになる。Javaで同じことができない。
5. Javaに.NETのLINQに相当するものがない。これもJavaにないので、フラストレーションを溜める原因になる。例えば、C#でLINQを徹底的に使うと、例えばLoopを全くゼロにできるが、同じことをするコードをJavaで書くと、プログラムがLoopばかりになっていることになり、嘆くことが多い。
今のところ、僕にとって、Javaの悪い点しか気付かない。もしかしたら、そのうち良い点も見つけるのかもしれない。しかし、それを考えても、私は日本、そしてシンガポールのシステム開発の主流がいまだにJavaにある理由がよく分からない。.NETを使うと、はるかに楽にコードは書けると思う。
*1 : 実装担当としてJavaを使ったことがないという意味で、PMやビジネスアナリストとして参加したプロジェクトで使ったアプリがJavaだったことはある。
コメント
こう食い言うのを書くと、ぼろくそに書くやつが現れるとと予想していたが。出来れば、コメントに書きこんでほしい。色々な言語を経験している人は、前向きな発言が多いみたいだが、Java系列だけの人は、ぼろくそに書きたくなるのかもしれない。誰も、自分が慣れ親しんだ言語が一番と思うのは当然でしょう。そういう意味では、今回僕は、javaの悪口を書いているので、人のことは批判できない。しかし、Scallaと言うのがあるらしくて、それを使うと僕の悩みはほぼ解決するらしい。ちょっと調べて見ようと思う。教えてくれた人、ありがとうございます。
仲澤@失業者
じじいプログラマの仲澤です。
日ごろC++でやってる自分から見ると、.NETもJavaも夢の様に簡便な環境に思えます。
ですが、アプリケーションの多くの部分を覆うよな、ざっぱな例外の使い方には
やや疑問を持ちますね。つまり「落ちなきゃいいじゃん」的なコードに見えるわけです。
まぁ IF ERR GOTO 0(エラーなら最初に戻るの意) と大差無いように思えます。
もっとキメの細かい処理ができるのになぁと思うときもありますが、
大域での例外を使うと、そういう意識もなくなっちゃうのでしょうか、
そんなコードに出会うとやや残念です(vv;)。
Javaでswitchが多いのは自分も感じることがあるのですが、その多くは、クラス化するのが
面倒だったのだろうなぁというようなコードが多いようです。
この意味ではやや同情します(時間が無かったのでしょうかねぇ)。
さて、最近のM$さんの行動を見ていると、.NETで大きく独自化した方向が、
C++/CXで元のネイティブ+COMに戻りつつあるように見えます。
実際のところ主戦場がもはやPCではなくなったため、WindowsとPCに大きく依存する
.NETは、多様化する端末についてゆけないのかもしれません。
M$さんもそこんところは認識しているようで、多様な端末向けには、
皮を外した.NETライブラリを用意し、C++/CXでやってね的な雰囲気です。
web上での利用を除けば、.NETはある意味でみかぎられた可能性すらあります。
(ないとは思いますけど)
いずれにしても、C言語が本流になった頃のBASICプログラマと同じことにならないように気をつけたいもんです。
とおりすがり
Javaも最近はプロパティ普通に使えるはずですが・・・。それにLINQもサードパーティのライブラリありますし。
言語の特徴とプロジェクト固有の問題をゴッチャにしてませんか?
Javaでやたらに長いcase文書くような開発会社だと.NETやC++でも同じことしますよ。
(そういう会社でLINQ使うと「読めない」と一蹴されます^^;)
仲澤@失業者 さん
Exception処理をかなりコールスタックの高い位置で、行うと、たとえば少なくとも、コードは、処理を何も考えずに、並べていけばよくなり、開発生産性がよくなり、コードの見通しもよくなり、メンテナンス性も上がります。今までは、それが現代のプログラムだと思っていましたが、そうでもないのでしょうか?きめ細かくエラー処理を行うにも、たとえば、Exceptionのクラスを分けて、そのクラスごとに処理を切り分けるようなことをすれば、結構きめ細かく、処理を分けられます。switchが多いのは、今私が、見ているコードが単に悪いコードの例だからでしょう。しっかりと、ポリフォリズムを使えば、すっきりするのでしょうが、工数がかかります。delegateで、複数の関数をarrayに収めてというようなことをすれば、簡単にswitchがなくせます。
後、C++/CXなるものがあるのですね。今度勉強します。僕も、C++のATLでcomを昔作ったことがあります、たぶんそれを多少エンハンスしたものなのでしょうか?iPhoneアプリでしょうか?
なかじまゆうじ
Exceptionに関して、ちょっと。
自分も.NETからJavaに移ってきたときはchecked exceptionの意味が分からなかったのですが、友人に「.NETのExceptionは、Javaのunchecked exception。checked exceptionは、.NETでは例外として扱わないものを扱う」という話をされて、なんとなく理解しました。
例えば、検索メソッドを作った時、.NETでは「条件に合うものが見つかればそれを返し、見つからなければnullを返す」のように実装すると思いますが、Javaでは「条件に合うものが見つかった時だけ値を返す。見つからなければchecked exceptionをthrowする。」のように実装するようです。ですのでchecked exceptionは、通常、かなり「下のほう」でcatchすると。
(自分の解釈なので、正しいかどうかはわかりませんが。)
Rejaxon
Javaプログラマで.NETは友人に聞くレベルであまりしりません。
この記事読んで、.NETは優秀な開発者を育てやすい言語なのかなぁと感じました。
少し興味が湧きました。
Javaは入門はしやすいけど、中級者以上になるのが非常に難しい言語だと私は思ってます。
Java開発は様々なオープンソース、設計手法を用いてこそ、開発が楽な言語になっていきます。
getter/setterも@を変数に与えるだけで自動作成してくれるプラグインもあります。
プリミティブ型/クラス型に分かれている件も、
例えばAndroidアプリを作る場合、
インスタンスを増やしたくないのでプリミティブ型が
常備されているのはメモリ削減で嬉しい限りです。
また、クラス型は本当に値がない時は初期値のnullになるので様々な場面で分かりやすくなります。
Javaは様々な端末、プラットフォームで使われているので統一されていないことが一概に悪いと言えません。
Exceptioonのチェック例外については、私も解りづらいのに賛成します。
ただし、チェック例外のケースは原因が発生元で明らかなケースが多いです。
ParseExceptionだったりと・・・。
これはチェック例外発生するコードを書いた人はそれをすぐにcatchして
原因が分かりやすいのだから、情報を追記した形で
非チェック例外化して投げ直してよ!って事だと私は考えています。
だからthrowsを使っている時点で駄目コードだと感じます。
チェック例外が発生するソコでcathcし、
何故?発生したか解る情報を追記した形でWrapして非チェック例外してあげれば良いと思います。
ExceptionFactoryなどFrameworkを用意して、ログ出力や画面エラー出力も考慮した形で非チェック例外してあげるのが良いです。
4、5については私はよく知らないのですが、Javaにも専用プラグインがあるようですね。
クロージャーがあれば解決する問題なので、
callBackなど巧く利用してクロージャーっぽい汎用クラスをFrameworkとして作ってやれば良いだけだと思います。
Javaの場合、クロージャーっぽいだけで関数ではなくクラスになってしまいますが。
関数の方が処理が軽いので、スレッドがどんどん増えていく昨今の事情を考えて、
Javaにもクロージャーが追加されるらしいです。Java7では延期されちゃってまいました(涙)
後、Switchについては分岐が多く増加の可能性もあるなら、
デザインパターンのStateパターンを使えば良いと思います。
そういう訳で、Javaは入門簡単ですが
中級者以上になるには情報収集が欠かせず、確かに難しいと思います。
初心者向けに有識者がプロジェクトに合ったFrameworkを造り込み、
リファレンス実装を公開してあげるのが大切だと思います。
Javaの良いところは、英語とコードさえ読めれば世界中にツールと実装例が溢れている事です。
オープンソースも多いので、様々なFramewrokの実装方式をベースに作りなおすのもしやすいです。
開発しずらいと思えば、オープンソースをベースにシステムに合った自動コード生成を自分で作るのも面白いです。
是非、Javaに詳しくなって頂いて、.NETとJAVA両方の上級者の意見として
双方の良いところ、悪いところの記事をお待ちしています。
Rejaxon さま
あなたのようおな方が、今の私の現場に言えば、多分『ぶつぶつ』と、ぼやく僕に、色々とアドバイスしてくれるのだなと、思います。プリミティブ/クラス型の件。メリットがよくわかりました。C#では、プリミティブのタイプにnullを許可するため、nullbleなどというコンセプトがあるますが、javaではそんな、後ズけの機能は不要なんでしょう。チェック例外と非チェック例外の使い分けもよくわかりました。今後その、方針で使い分けて行こうと思います。
通りすがり
1. Lombok あるいはそのフォークである lombok-pg を使えば問題になりません。
これらの基盤になっている Annotation Processing Tool を使えば、理論上は Java からかなりの boilerplate をそぎ落とせます。
これに相当するものは .net には無いのでは。
2. Java5 以降は auto boxing してくれるので、苦痛がかなり減っています。
3. 現実的な話をすると、現代的な Java フレームワーク、ライブラリで checked exception を投げるのは少数派では。
JDK の API についての批判ならその通りです。
4, 5 Guava と lombok-pg を組み合わせると、少しは状況がマシになります。
ただ、他の方が指摘しているように Scala を使えば、これに限らずだいたいの問題はもっとエレガントに解決されます。
> delegateで、複数の関数をarrayに収めてというようなことをすれば、簡単にswitchがなくせます。
この解法が許される場面で、switch を無くそうとする動機はなんでしょうか。私には思いつきません。
これに関して、Java は enum の要素が「関数」を持てるという利点があります。これを使えば、
条件とそれに該当する場合の「関数」をセットで管理できるため、Typesafe enum パターンが .net よりも
直截に表現できます。おそらく、「delegateで、複数の関数をarrayに収めて」という方法よりもです。
通りすがりさま
どうもありがとうございます。 Lombokを教えていただきありがとうございます。これを使おうと思います。
enumに関数を持てる方法ですが、私のやりたいことには使えないようです。enumの関数は、基本の形はひとつで、その形のなかで使う変数をenumで定義されたvalueで切り替えるものみたいです。しかし、javaのenumは強力ですね。
scalaについては、このコラムへのレプライの方が紹介してくれたので、それをきっかけに知りましたので、本を購入しました。今、それを読んでいます。function指向や、closureなどの言葉が踊るようで、かなり強力みたいですね。static languageであることが良いです。僕は、dynamic languageと言うやつは嫌いです。ソフト開発はやはりstatic languageだと思います。もちろん、現場で使う言語、プラットフォームに合わせていくのが、プログラマの仕事ではありますが。