Hatena::ブログ(Diary)

達人プログラマーを目指して このページをアンテナに追加 RSSフィード Twitter

2012-02-12

日本のユーザー企業は忍者のようなプログラマーをもっと登用して重用すべきでは

あの記事から一年、ひがやすを氏が以下のエントリーで、プログラマーとして、新しいサービスを作ることの難しさについて書かれています。

僕と君とSIerの生きる道 - ひがやすを blog

確かに私自身は、サービスを作る側に回った(まだISIDにいるけど、ベンチャーで働いているようなものです)のですが、身を持って面白いサービスを作る難しさも経験しました。

面白いサービスを作るのはほんとうに難しい。その後、マネタイズにも成功するのはさらに難しい。サービスを作る側に回って成功するのはほんの人握りの人なんです。

もともと一年前におっしゃっていたことは、SIerのビジネスに将来性はないから優秀なプログラマーは自分でサービスを作る側に回らなくてはならないし、単によいコードを作れるだけでなくて、自分からアイデアを考えられるようにならなくてはならないということだったかと思います。一年前この記事を読んだときは、私としてはかなり衝撃を受けました。一人前のプログラマーとして認められるには、もはや単にきれいなコードを書く技術やフレームワークやミドルの知識だけでは不十分なのであり、自分からビジネスを創り上げるアイデアがなくてはならず、単に勉強して技術力を磨くというだけでは不足であるということのように思われたからです。

どうしても、停滞気味なSI業界の中でエンジニアとして働いていると、ビル・ゲイツマーク・ザッカーバーグのように新しい時代を切り開いて成功者となったプログラマーにあこがれることは自然なことですし、プログラマーとして大きな目標を持って頑張るということは悪いことではありません。しかしながら、現実問題として、そういう成功者に誰もが簡単になれるわけではないですよね。

大きな目標を立てることは立派なことだけれども、これは、戦国時代に例えるならば、すべての武士に対して、信長秀吉を目指せといっているのと同じくらいに難しいことのように思われます。しかし、一方で、政治の表舞台には登場しなくても、裏方として活躍した軍師忍者として活躍したような人もたくさんいたと思われます。そういう忍者たちは、表向きの身分こそ低くても、自分の剣術や諜報スキルを磨くことで、大名に信頼されて、戦略上重要なプロジェクトを任されていたのではないでしょうか。

基本的に、信長の野望のようなシミュレーションゲームにおいては、大名のようなトップに立つ人はすべての能力において優秀でなくては務まらないと思いますが、忍者軍師のタイプは智謀や武力など一部の能力に特化したスペシャリストとして登場します。私としては、多くのプログラマーは大名タイプよりも、むしろこうした忍者タイプを目指した方がよいのではないかと思うのですよね。

忍者スペシャリストですが、大名のそばにいて、重要なプロジェクトを引き受けます。*1これは、現状のSI業界における開発が大部分百姓から臨時でかき集めたような傭兵による集団戦法に頼っているのとは対照的です。

Amazonではエンジニアのことを忍者と呼ぶことがありますが、単に外国人の興味を引くということだけでなく、この呼び方はエンジニアの職務を表現する上で非常にマッチしていると考えます。*2

取扱商品数の拡充等で成長を続けるオンラインストアだけでなく、最先端のクラウド技術を活かしたAmazon Web ServicesAWS)の展開と、さらなる挑戦を続けるAmazon。その影の存在でありながら凄いことをするという思いを込め、Amazonエンジニアは自分達を忍者Ninja)と呼びます。

Amazon エンジニア特別求人情報

army of traveling Code Ninjas

AWS、プライム、キンドル、モバイルなどそれぞれの戦略を担当するチームの中で、エンジニア忍者のように裏方として活躍しています。これらの忍者たちは、必ずしも有名人とか大金持ちというわけではないですが、スキルを活かして、ビジネスの戦略を遂行する上で重要な役割を担っています。

もともと、忍者というものを生み出した国でありながら、日本のSI業界においては忍者のようにプログラマーが重用されることが少ないのが不思議なくらいです。大量の傭兵軍団からなる集団戦法を使って数で勝負というだけではなく、少数精鋭のメンバーで戦略的に勝つというようなやり方が、日本のユーザー企業でももっとポピュラーになれば、日本でも上級プログラマーの活躍する場所がもっと増えるのではないかと思いますし、こうした忍者衆をそばに抱えておけば、ユーザー企業にとってもITを本当にビジネスで活用する上で有効なのではないかと思いますがいかがでしょうか。

*1:実際には当時の忍者には上忍とか下忍とかの身分があり、服部半蔵のような有名な忍者が自分から現場で活躍したかどうかは疑わしいそうですが。

*2PGというと伝統的にモノづくり職人、鉄砲鍛冶、刀鍛冶の職人のイメージがありますが、最近はITで得られた情報から素早く次の作戦を遂行するという役割があるので、忍者はイメージとして合っているのではと思いますね。つまり、作戦の考案から実行まで、上流から下流までプロジェクトを素早くタイムリーに遂行するということです。

2012-01-25

ソフトウェア技術者軽視のシステム開発を続けるのはもう限界かもしれない

つい先日、富士通がグループで抱える3万人ものSEを再教育して、職務転換を行う計画であるというニュースを知りました。

富士通の3万人SE職務転換大作戦は成功するのか? - GoTheDistance

一つのシステムを複数の企業などが利用するクラウドサービスがこのまま普及すれば、顧客の要望を聞いて個別システムを作り込むSEは仕事がなくなり、余剰人員問題が顕在化するからだ。

クラウドの普及により、オーダーメイドでシステムをゼロから構築する必要がなくなり、そもそも顧客からの要件をまとめてシステムを設計するSEの仕事が不要になったり、基盤を構築、運用するエンジニアが不要になるということは、最近になってよく言われることであり、特に新しいことではありません。もちろん、クラウドの普及によって、これらの伝統的なSEの仕事が少なくなり、人員が余るという議論は間違いではないと思います。

ただし、一方でより本質的に重要なことは、クラウドの普及により、要件の定義から実現、運用までの期間が大幅に短縮できるようになったり、基盤構築など多くの仕事が自動化されることで、上流から下流まですべてを担当できるような真のソフトウェア技術者の役割がシステム開発で重要になってきているというところにあると思います。したがって、上流担当のSEだからといってプログラミング言語や基盤技術のことをまったく知らないといったことが許されない時代になってきているということであり、アメリカ的な意味でのプログラマーディベロッパー)の仕事がもっと重要になってきているということを理解する必要があります。プログラマーというと、単に設計書に従ってコードを打ち込む単純作業をする人や、逆にすごく難しい計算式とアルゴリズムを使うような研究者など、まったく異なるいろいろな職業を思い浮かべる人がいますが、少なくともグルーバルな意味でのエンタープライズ開発のコンテキストにおけるプログラマーとは、顧客の要件を素早く実現する方法を提案して、そのまま構築し、場合によってはテスト自動化やデプロイメントまで担当する人のことを指します。そういう意味では当然上流も下流もありません。もちろん、経験やスキルによって下級プログラマーから最上級のプリンシパルプログラマーまで幅はありますが、上級職であっても、オブジェクト指向プログラミングができなくてよいということではなく、むしろお手本となるコードを書いたりコードレビューができることが求められます。

クラウド時代になったので、技術のわからない人でもシステムを構築できるということが時々聞かれます。もちろん、一部にはそのようなシステムもあるとはいえ、基幹業務やビジネスの中心にかかわるようなシステムであれば、クラウドを利用するとは言え、アイデアさえあればまったくの素人がシステムを構築できるとは考えるべきではないでしょう。この点については、ちょうど一年ほど前にも以下で議論しています。

日本のSI業界でこそ、専門の技術者の必要性がもっと見直されるべきではないのか? - 達人プログラマーを目指して

そういう意味において、ついに富士通のようなSIerも、今回の職務転換で今までのような上流偏重型の技術軽視の考え方を改め、

などの知識を持った専門家をついに育成することになるのかと期待したのですが、実情は大きく異なるようですね。

Weekly Memo:富士通が説くSIにおける人材革新のツボ - ITmedia エンタープライズ

 「これまでは、いわゆるモノづくりに焦点を当てた人材づくりを行ってきた。現在、SEが担っているスキルとしては、コンサルティングから入って、開発のためのプロジェクトマネジメント、業務アーキテクチャ、品質マネジメント、ITアーキテクチャ、プロダクトアーキテクチャ、そして運用・保守を行うサービスマネジメントがある。しかし、これからは顧客価値の実現に向けて顧客とともに考えていくという取り組みが一層求められるようになる」

 それが、図の上部に示されているところの「スキルからロールへのシフト」である。同社が新たな時代に向けて再定義したロール、すなわち「役割」に応じた職務は、「ビジネスプロデューサ」「フィールド・イノベータ」「コンサルタント」「サービスインテグレータ」の4つ。

もちろん、詳しい内容は分からないのですが、結局のところ、以前にもまして上流重視の方針のように思われます。*1残念ながら、富士通SEの職務転換先には、(アメリカ的な意味での)プログラマーもSDET*2クラウド基盤運用管理の専門家も含まれていないようです。

ところで、最近特許庁のシステム開発中断という以下のニュースも話題になっています。

朝日新聞デジタル:費やした55億円、水の泡に 特許庁がシステム開発中断 - ビジネス・経済

調査報告書 平成22年8月20日 特許庁情報システムに関する調査委員会

特許庁の情報システムについて - myatsumoto blog

5年も前からずっと設計を行って結局完成しなかったということですが、その間コア機能を含む一部のサブシステムですら構築することはできなかったのでしょうか?このように何年もかけて上流の設計を続けても、まともなシステムが一つも完成しないという話は特許庁に限ったことではなく、メガバンクの基幹システム構築などいたるところで耳にします。そもそも設計に5年もかけていては、技術の内容もビジネスの内容も大きく変化してしまうわけでウォーターフォール的に設計を固定できるわけがないですし、仮になんとか完成にこぎつけたとしても使い物にならないシステムができるだけだと思います。

プログラマーの自分の目から見て、いつも非常に不思議に思うのは、こういった問題が起こった場合、

  • 管理の方法が悪かった
  • 顧客との仕様の調整がうまくいかなかった
  • 上流の基本設計がうまくまとまらなかった

というような話は出てくるのですが、決してプログラムや基盤の設計が原因とされることがないということですね。実際にはこういった実装面の問題は全く無視できるはずはなく、コピーアンドペーストだらけで複雑になり、まったく手が付けられなくなったり、あまりにも性能が悪くて要件が満たせないというような問題はよほど簡単なシステムでもない限り大きな問題となるはずです。(プログラミングと設計は本来切り離せないものなのでは - 達人プログラマーを目指して

伝統的に、日本のSI業界ではその構造から実装、構築の作業を軽視する傾向があったわけですが、いい加減にこのような考え方でシステム開発を続けることは品質やコスト、スピードの面でもう限界に達していると考えられるのではないでしょうか。

富士通のようなSIerSEの職種転換を目指すのであれば、単に上流のコンサルタントだけでなく、上級の開発者の仕事をもっと重視すべきなのです。もちろん、そのためにはござ先輩も書いているようにSIerビジネスモデルの大変革が必要だと思いますが。あるいは、ユーザー企業がもっと率先して上級のプログラマーを雇ってより短期間で効率よくシステムを開発できるようになるべきかもしれません。その場合、SIerは文字通りシステム統合の手助けとか、開発基盤の提供など、ビジネスモデルなどではなく、より開発のインフラよりの部分を担当する役割を担うことになると思います。

*1:成果物がExcel方眼紙からパワーポイントになるという意味ではスキルの転換が必要かもしれませんが。

*2:Software Development Engineer in Test、テスト自動化などの専門家

2012-01-03

開発コストや技術リスクを考えない「上流設計」がシステムの複雑化と大規模な障害の原因となっているのでは?

皆さん、明けましておめでとうございます。昨年の後半は私自身SI業界からWeb業界へ転職したことなど仕事環境の変化があり、ブログの更新頻度も鈍りがちになってしまっていましたが、本年もどうぞよろしくお願いいたします。

さて、ちょうど、一年前のお正月にはグルーポンのおせち料理事件が話題になっていましたが、私はおせち料理の品質とIT業界における品質の問題を絡めて、以下の記事を書きました。

グルーポンのおせち事件を受けてSI業界が本当に教訓とすべきこと - 達人プログラマーを目指して

この記事では、一般にSIerによって開発される日本のシステムはあの事件のおせち料理のように、低い品質に甘んじているが、多くの場合、社内システムなどではそういった品質の問題が公に明らかにされることが少ないのではということを指摘しました。ただ、その時は私の希望も込めて

最近はOSSクラウドなどの影響で社内システムもどんどんネット上のオープンな世界から調達されるようになってきているわけですし、いい加減にこうした状態がこの先何年も続くことはないのではないかと思います。アリとキリギリスの話ではありませんが、来るべき冬の時代に備えて、本物の技術力(プログラミング力だけでなくて提案力などプロの技術者としての仕事力も含む)をつける勉強をしておくことは決して無駄な努力にならないと思います。自らが作り出して深く関わっているIT技術によって「真面目に勉強する人が損をする」「正直者が馬鹿を見る」業界の体質はそろそろ終わりにならざるを得ないのではないでしょうか?

のように結びました。残念ながら、その後1年間でシステム開発の方法が大きく進化し、品質の問題が劇的に改善されたという話はあまり聞きません。逆に、昨年3月の震災後にメガバンクが起こした大規模障害や最新スマートフォンの動作不具合など、多くのユーザーの生活や仕事に影響を与える大規模なシステム障害のニュースがたくさん耳に入ってきました。ますますB2Cのシステムが重要になってきているという一般的な傾向の中で、システムが直接消費者である顧客の目に触れる不具合が多くなってきたことで、いよいよごまかしが効かなくなってきているということは言えるかもしれません。もちろん、プログラムバグは付き物ですし、AppleGoogleなどのどんな優秀なプログラマーが作ったプログラムにも障害はたくさん含まれているわけですが、それにしても、日本製のシステムは最近多くの重大な障害を起こすように思われます。

さて、今年は早速ドコモspモードで全国的にメールが送信できなくなるという障害のニュースがありました。

通信障害のお知らせ : 全国でspモードメールがご利用しづらい状況について〜一部のお客様に影響した事象〜(2012年1月3日 16:00更新) | お知らせ | NTTドコモ

NHKオンライン

spモードは昨年末にも電子メールの送信先が入れ替わってしまうシャッフル問題など重大な障害があったばかりですし、これまでもあまりよい評判を聞かないようですね。今回の新たな障害の原因は

spモードサーバーの故障

と発表されていますが、やはり、これほどたびたび重大な障害を起こすということは、単に偶然ハードウェアが故障したという直接的な原因の前に、もっと根本的なシステムの設計や開発手法に問題があるのではないかとは誰もが想像するところです。spモードについては一部コンテンツプロバイダー(CP)向けの技術資料が以下で公開されているため、どのような開発が行われているのか、一部を伺い知ることができます。

サイト運営者様向け | docomo ログイン | NTTドコモ

上記のサイトから、docomo IDを用いたサイトの認証方式の仕様書ダウンロード可能です。

docomo ログイン I/F仕様書

これは、60ページほどのドキュメントで、シーケンス図など多くの図を用いて、spモードの「公式サイト」でdocomo IDを取得するためのインターフェースが説明されています。付録にはJavaPHPによるサンプルコードも書かれているので、CP側で実際にどんなプログラムを書く必要があるのかもわかります。

spモードドコモスマートフォンガラケーiモードのようなサービスが利用可能になるサービスなわけですが、マイメニュー登録など課金インフラを利用するためには、前提として携帯電話を使っているユーザーを特定するIDをCP側で取得する必要があります。従来のガラケーではGUIDと呼ばれるIDが端末と簡単に結びつけられたわけですが、当然スマートフォンの場合はサービスを利用する前に、認証によってユーザーを正しく特定することが前提となります。それで、この仕様書の要点としては、CPスマートフォンのユーザーを特定するSUIDを通知されるためにOpen IDプロトコルのRPを実装しなくてはならないということがわかります。

Open IDというのは認証IDを複数のサイトで共有する仕組みで、シングルサインオンメカニズムの一つとして利用されているオープンな仕様です。ユーザーから見ればいったんドコモのサイトでdocomo IDを使ってログインすれば、個々のサイトごとにログイン名やパスワードを個別に記憶する必要がないので便利です。オープンな標準仕様であり、さまざまな言語でアクセス利用可能なライブラリーも多数存在しています。

OpenID Wiki / Libraries

認証基盤もCPごとに作りこまなくてもドコモにおまかせすればよいので、サイトの開発コストを抑えることができるでしょう。このように考えると、この仕様は一見合理的によく考えられているように思われます。しかし、本当に最後までサイトを構築することを考えると

  • Open ID自体は複雑な仕様のため、プロトコルを全部自前で実装するのは非現実的だが、実際にどのライブラリーを利用すればよいのか。
  • spモードログイン仕様は、複数回のHTTPのやり取りが必要で、CPが何らかのサーバーサイドの状態を保持することを前提としたプロトコルとなっているように思われる。
  • 開発時にはどのような手順で接続し、試験すればよいのか
  • 既存のサイトでシングルサインオンの提供が難しい場合はどうすればよいか

などなど、実際に「下流の」開発者の立場で、細かいことを気にし出すと具体的には実際にどうやって作ったらよいのかということがまったく書かれていないことに気づかされます。多数の図を使って、一見非常にわかりやすく解説されてはいますが、実際の実装レベルを想定したアーキテクチャの詳細がほとんど書かれていませんし、技術リスクのようなことも十分に検討されているとは言い難いところがあります。

もちろん、自分はspモードシステム開発の当事者ではありませんし、直接的に開発にかかわったこともないので、もちろんこれは私の勝手な想像の域を出ないわけですが、結果として、開発側で細かいところは個別に何とか解決するしかなく、余程運に恵まれない限り、デスマといいますか、想像以上に開発リソースを必要とする非常に大変なプロジェクトになることが頭に浮かんできます。非公開の仕様にはもっと別の設計資料や開発SDKが存在する可能性もありますが、少なくとも公開されている仕様書を読む限り、これは、日本のIT業界には非常にありがちな上流の仕様書・設計書のように思われます。

GoogleTwitterなど外国のIT企業の場合、このような分厚い設計書を用意する以前に、システム連携のための便利なAPIを主要な言語でライブラリーとして実装し、試験用のSDKとともに開発側に提供するのが普通のように思われます。外国では設計に上流も下流もなく、きちんと動作する仕掛けができていて初めて設計が完了していると考えます。もし、ドコモがこのようなライブラリーやWebサービスインターフェースを実装して公開していれば、少なくとも各CP側の開発費用ははるかに抑えられたはずですし、プロジェクトが失敗する危険も小さくなるのではと思います。

もちろん、これは公開されている資料に基づいて想像されるspモードの設計の複雑性のほんの一部分の問題に過ぎず、今回の大規模障害との直接的なつながりはないと思いますが、他の部分でもこのように開発工程を上流、下流と分け、ウォーターフォール型で細かい技術リスクを下流の下請け業者に押し付けているのであれば問題ではないでしょうか。

やはり、私としては、日本のIT業界で伝統的に行われるウォーターフォール型の開発手法がシステムの複雑化と大規模な障害の原因となっているのではと考えてしまいますね。より、高度で複雑なシステムの開発を行うのであれば、下流工程を無視して「上流設計」を行うという考え方をいい加減に改めるべきではないかと思います。そして、キャリアーのようなインフラを担当する会社は、単に上流の設計書を仕様として作成するだけでなく、開発者が簡単に開発できるような開発環境やフレームワークを構築して提供するようにすべきではないでしょうか。少なくとも、簡単なサンプルだけではなく、参照実装としてのサンプルサイトのようなものをCP開発側に提供する必要があると思います。一方、プロトコルの詳細などは、RESTSOAPといった標準的な方法に従った上位のインターフェースを提供するライブラリーによってうまく隠ぺいするようにすればよく、各CPに対して大量の文書でプロトコルの詳細を説明することも重要ではないと考えます。(むしろ、APIのソースが提供された方がよい。)実際、このブログに張り付けてある広告などの多くのウィジェットは何も考えなくても多数のサービスを簡単に利用できています。

そのためにも、上流設計のSEコーディングPGといった役割を分けるといった考え方ではなく、上級のプログラマーが企画段階から設計にかかわることが大切だと思います。

(追記)

一般的にシステム障害の原因がウォーターフォール型の開発手法のみにあると考えるのは、もちろん適切ではないと思います。ただし、ここで取り上げたspモードのように、今までになかった新しい仕組みをウォーターフォール型で構築するのはいろいろと困難を伴うことが多いということは言えるのではないでしょうか。後から見つかった仕様上の欠陥を補うために、後からいろいろな回避策を考えるにしたがって、より複雑なシステムになってしまうということは実際によくあるのではと思います。すなわち、下流工程と呼ばれるプログラムの実装やシステム基盤の構築作業から得られた問題点の指摘やアイデアを仕様にフィードバックすることが難しくなってしまいます。*1

ここでspモードを取り上げたのはたまたまタイミングの問題で、もちろんドコモ一社のやり方を非難することがここでの目的ではありません。新しいサービスをタイムリーに提供する上で、従来のウォーターフォール的な考え方が大失敗の大きな要因の一つになっているのではないかということです。

*1Googleなどの場合はベータサービスという形で結構長い期間お試しのリリースが行われることが多いと思いますが、携帯電話のサービスの場合はそういう形は難しいのでしょうかね。

2011-12-17

Javaのクラスとオブジェクトについて再度解説を試みる

オブジェクト指向プログラミングの考え方については、今までこのブログでも何度か取り上げてきました。

[オブジェクト指向] - 達人プログラマーを目指して

オブジェクト指向プログラミングプログラミング技法のすべてではないとはいえ、Javaのようなオブジェクト指向言語で本格的なプログラムを作るには理解を避けて通ることができませんし、また、関数型言語など他のパラダイムの言語を利用するにしても、オブジェクト指向の考え方をまったく理解しないまま使いこなすということは困難でしょう。オブジェクト指向の考え方はデータ構造やアルゴリズムといったことと同様に、プロフェッショナルプログラマーが理解しておくべき基本的な素養といってもよいと思います。実際、海外では募集要項でオブジェクト指向の理解を前提とすると書かれていることが普通ですし、プログラマーの面接試験で、アルゴリズムと並んでオブジェクト指向プログラミングの基本についての正しい理解を問うケースが多いようです。

しかしながら、特殊なケースを除いて、我が国ではいまだになかなか普及していないようですね。数週間の新人研修やOJTのみで短期間に理解できるほど簡単ではないというのは事実かもしれません。それゆえ、SIの開発案件ではJavaVisualBasicといったオブジェクト指向言語を用いながらも、実際にはオブジェクト指向を利用しないで開発できるような規約を作るといったこともかなり一般的に行われているようです。

オブジェクト指向プログラミングの普及を妨げる原因の一つとして、わかりやすい入門向けの解説を作ることが難しく、また、実際にそのような解説が書かれている入門書も非常に少ないということがあると思います。実際に、Javaの入門書の場合、ずっとmainメソッドのみでifやforなどの構文を説明した後、いきなりVehicle(乗り物)クラスやCarクラスなどの説明に飛躍するといったケースも多く、初めてオブジェクト指向プログラミングを学ぶ人にとっては非常に理解しにくいところがあると思います。*1

さらに、一言でオブジェクト指向、(あるいはもっと範囲を狭めてオブジェクト指向プログラミング)と言っても、プログラミング言語によっていろいろな考え方やアプローチがあり、さまざまな人々がいろいろな解説を試みているので、学習する側の立場としてはどの考え方が正しいのか混乱に拍車がかかるというところがあるかもしれません。

私自身は「オブジェクト指向とはどう考えるべきか」という哲学的な研究をしているわけではなく、単に仕事をするうえで便利な考え方の枠組みの一つとして考えています。要するに、

  • 共通のロジックを流用しやすくする(再利用)
  • 大規模なプログラムを分割して扱い易くする(モジュール化)
  • 変化や拡張に強いプログラムにする(拡張性)
  • 設計のアイデアを共有する(パターン)
  • ビジネスルールをプログラムとしてわかりやすい形で表現する(モデル化)

といった目的を達成するための手段一つとして、欠かせないものとして考えています。

ここでは、Java言語のオブジェクト指向プログラミングの基礎となるクラスとオブジェクトについて、再度、自分なりの解説を試みてみることにしたいと思います。

staticおじさんの世界におけるクラスの役割

一昔前のJavaの解説では、「Javaは純粋なオブジェクト指向言語である」という説明のされ方をされることが多くありました。ご存じのように、Javaではどんなに簡単なプログラムでもクラスを作成することが必須です。実際、HelloWorldは以下のようにクラス内に定義する必要があります。

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

最初から、クラスというオブジェクト指向の概念を使う必要があるから、純粋なオブジェクト指向言語なのであるということです。これは、「純粋なオブジェクト指向」という言葉の定義にもよりますが、一般にはちょっと不適切で勘違いしやすい用法だと思います。確かに、このプログラムに登場する文字列配列オブジェクトですが、ユーザー定義のオブジェクトは利用していません。ただし、HelloWorldというユーザー定義のクラスは使っているので、クラス指向といった方がよいかもしれません。

さて、このHelloWorldプログラムと同様の形式を拡張して、すべてのクラスのメンバー(フィールド、メソッド)にstaticキーワードをつけることで、完全にstaticな世界で*2プログラムを作成することができます。staticフィールドやstaticメソッドは、Smalltalkなどの純粋なオブジェクト指向言語の用語をまねてクラス変数、クラスメソッドなどと呼ばれることもありますが、本来staticというのは静的、すなわち、動的(dynamic)と反対の意味を持つ用語です。Java言語において、staticキーワードの持つ意味はあまり理解されていないようですが、staticフィールドについては、一旦クラスローダーによってクラス定義がJVMに読み込まれたら、クラスごとに固定的に変数領域が割り当てられてずっと存在しているということを示しています。また、staticメソッドはそのようなフィールドを操作するためのメソッドとして、やはりクラスごとに定義が読み込まれます。*3

この点を理解するためには、以下のごく簡単な例を考えてみてください。

public class ClassA {
    public static int field;

    public static void method() {
        System.out.pirntln("ClassAのメソッド");
    };
}

public class ClassB {
    public static int field;

    public static void method() {
        System.out.pirntln("ClassBのメソッド");
    };
}

public void MainClass {
    public static void main(String[] args) {
        ClassA.field = 100;
        ClassB.field = 200;

        System.out.println(ClassA.field); // 100
        System.out.println(ClassB.field); // 200

        ClassA.method(); // ClassAのメソッド
        ClassB.method(); // ClassBのメソッド
    }
}

ClassA、ClassBのそれぞれに独立した変数の定義、メソッドの定義が存在し、クラスが読み込まれるとともに静的にメモリーに読み込まれます。このことは、フィールド名やメソッド名が以上の例のように同じであっても影響を受けません。特に、この例で、int型のstaticフィールドに対応するメモリー領域は、クラスがロードされると共にクラスごとに用意されることに注意してください。

このように、staticな世界におけるクラスの役割とは、単にたくさんあるフィールドやメソッドを種類ごとに分類して、適切な部品の単位に分割するというモジュール化の役割があるに過ぎません。つまり、クラスは単にstaticフィールドやstaticメソッドの入れ物として機能しています。また、Javaの場合、基本的には一つのクラスを一つのソースファイルに記述しますから、クラスというのは物理的なソースコードの分割単位としての役割もあります。英語のclassifyに分類分けするという意味があるように、クラスには分類されたものという意味もありますから、大規模なプログラムで必要な変数メソッドの定義を適切な単位に分割して扱うというのは、オブジェクト指向以前にクラスの持つ重要な役割であることがわかります。

抽象データ型の扱えることの便利さを理解することがstaticな世界を卒業する最初の一歩*4

このように、staticおじさんの世界でも適切にクラスを定義して、フィールドやメソッドをしかるべきクラスに定義することで、大規模なプログラムを適切な単位に分割して管理することができるようになります。しかしながら、この場合の問題は、プログラムが扱える変数パラメーターの型が基本型、文字列型、またその配列といった非常に限定された型しか扱えないということです。FORTRANCOBOLなどの昔の言語しかしらないstaticおじさん*5の問題点はプログラム言語が扱えるのはこのような限定された型のデータのみであると決めつけてしまっているところにあると思います。

ところが、実際の複雑なプログラムでは、

  • 注文をデータベースに登録する
  • 入力フォームを開く
  • カタログ一覧を検索する

といったように、プログラムで処理したい単位はintやfloatなどといった基本的な型のデータなのではなく、「注文」「入力フォーム」「カタログ項目」といった人間にとってもっと自然な単位でデータを扱いたいということがあります。JVMの仕組みを考えてみればわかるように、本当はコンピューターが扱いやすいデータというのは有限のビットの集まりとして表現できる数値や文字といったデータなのですが、そういう詳細のことは無視して、データをより抽象化して扱えるようになれば、プログラムを実際のユースケース(仕様)に近い形で記述でき、よりわかりやすく記述できるようになります。実際にJavaの場合は、intやfloatといった基本型の値だけでなく、文字列、日付、注文書といったさまざまなオブジェクトを利用することで目的に応じてあらゆるデータを変数から参照したり、メソッドパラメータ戻り値としてやり取りできるようになります。

もちろん、オブジェクトを真に使いこなせるようになるには、カプセル化ポリモーフィズムといったさまざまな事柄を理解する必要があるのですが、いきなりそのような概念を理解しようとせず、まずはこのようなさまざまなデータを扱えることの便利さを理解することが、staticな世界を卒業する最初の一歩として重要なのではないでしょうか。

一般のJavaオブジェクトを理解する前に、まず配列オブジェクトの性質を理解するとよい

ところで、一般のオブジェクトはクラスを使って自分で定義し、newを使ってメモリーに割り当てて使うわけですが、最初に勉強する際に、オブジェクトの性質と同時にクラスの定義方法を学習するのは、一気にいろいろな概念を覚えなくてはならずなかなか難しいかもしれません。そこでお勧めなのは、最初に配列の性質をきちんと理解するという学習手順です。配列はクラスで定義する必要がないため特殊ですが、Java配列

  • new演算子を使ってオブジェクトJVMのヒープと呼ばれるメモリー領域に動的に生成される。
  • 配列変数は参照型の変数である。
  • 多数の値をまとめて扱う抽象データ型の一種である。

という性質を考えると、一般のオブジェクトと共通の性質を備えていることがわかります。

一般的な入門書の説明では、配列は複数の値を読み書きする箱が並んだ絵が説明に使われることが多くあります。一個の変数が値を格納する箱なので、これが連続して横に並んだものが配列というわけです。これは、昔のBASICやC、COBOLなど多くの言語の配列の説明には最適ですし、この説明自身は間違っていないのですが、これだけではJava配列が持つ以上の重要な性質を見逃してしまうことになります。


int[] x = new int[3];
int[] y = x;

x[0] = 1;
x[1] = 2;
x[2] = 3;

System.out.println(y[0]); // 1
System.out.println(y[1]); // 2
System.out.println(y[2]); // 3

以上のコードは理解している人にとっては当然のことですが、配列オブジェクトは一個しか生成されておらず、xとyという二つの別々の変数によって同一オブジェクトが参照される状態となっているため、変数xの要素を変更すると、連動してyの参照する値も変わって見えるということです。これは、独立した値の箱として扱われる普通のint型変数の振る舞いと大きく違っています。


int x = 1;
int y = x;

x = 2;

System.out.println(y); // 1のまま

もちろん、参照型の変数オブジェクトを参照するためのものなので、nullという特別な値が代入されることで何もオブジェクトを指していない状態にもなれます。この状態の変数アクセスすると、有名なNullPointerExceptionが発生することになります。

なお、C言語そっくりにするため、Java配列を宣言する際には中括弧の初期化子を使って宣言することも可能です。

int[] x = {1, 2, 3};

あるいは、Javaでは推奨されませんが、以下のように書くこともできて、これだと本当にC言語のように見えます。

int x[] = {1, 2, 3};

ただし、似ているようにみえるのは見かけだけで、C言語配列とはメモリーの割り当て方が全く異なることに気を付けてください。このように、初期化子を使った場合でも、実際にはnewを使って動的に生成した場合と同様に配列オブジェクトは常に実行時に動的に生成されてメモリーに確保されます。*6

独自のメソッドを定義できないなど制約もありますが、配列は実際にオブジェクトの一種です。まずは、この配列の意味や配列変数の使い方に習熟することで、動的にオブジェクトを生成して使うというstaticでないプログラミングの世界への第一歩を踏み出すことができます。

ユーザー定義のオブジェクトを定義して生成する手段としてのクラス

以上で説明した、動的な配列オブジェクトの生成と配列変数によるオブジェクトの参照ということが理解できたら、一般のオブジェクトを理解することも難しくありません。配列との違いは、以下の点です。

配列の場合は、同一の型の値の集合しか表現できませんが、クラスを使えば、任意の値の組み合わせからなる構造のオブジェクトを生成できるようになります。

public class Person {
    public int age;
    public String name;
}

Person personX = new Person();
Person personY = personX; // 二つの変数が同じオブジェクトを参照するようになる

personX.age = 20;
personX.name = "test";

System.out.println(personY.age); // 20
System.out.println(personY.name); // test

フィールドを自由に定義できることと、要素にアクセスする際の演算子がピリオドである点を除けば、配列オブジェクトとまったく同様の性質を持っていることがわかります。要するに、Java言語においてオブジェクトとは、ヒープに割り当てられたメモリ領域で、オブジェクト生成元のクラスを型として持つ変数によって参照されるものということになります。まずは、データの塊がヒープに生成されて、変数を使ってそれを参照して使うということをイメージできるようになることが何よりも大切です。つまり、Javaオブジェクト指向プログラミングを理解する前提としては、

という性質をしっかりと理解することが重要だと思います。クラスがロードされたタイミングで最初から用意されるstaticなメモリ領域とは異なり、newされるたびに新しいオブジェクトが動的にヒープに割り当てられていきます。

ところで、どうしてJavaオブジェクトには、このような性質があるのでしょうか。これも、配列の性質を考えてみれば納得ができると思います。配列は一般にはたくさんの要素を含むので、あらかじめ静的に変数の領域を確保したり、メソッドが呼び出されるつどメモリーを毎回スタックに割り当てるのはあまり効率的とは言えません。実行時に必要なサイズで動的にメモリーを割り当てて、必要がなくなるまで(ガーベッジコレクションされる)ヒープに確保して使うというのは、一般的なプログラムでは効率的と考えられます。さらに、変数への代入時やパラメーターの受け渡し時にすべての値のコピーを行うよりも、単に既にメモリー上にあるオブジェクト変数が参照するようにした方が、プログラムの実行性能からも有利です。他の言語では、さまざまな方法でオブジェクトを割り当てることができるものがありますが、Javaの場合は常に動的にヒープに割り当てて、変数から参照するというという決まりになっています。常に、最適というわけではないかもしれませんが、JVMガーベッジコレクションの仕組みと合わせて、この割り切った仕様により、Javaでは効率的オブジェクトを扱えるようになっていると考えることができます。

オブジェクト指向プログラミングは、オブジェクトを定義するクラスとモジュールとしてのクラスを同一視することから始まる

前節で説明したクラスは、他の言語では構造体、レコード、あるいはユーザ定義型と呼ばれるものに過ぎず、複数の値から構成されるデータ構造を定義していました。

しかし、ここで本当に理解すべき重要なことは、Javaではオブジェクトの構造を定義して、そこから生成されたオブジェクトを参照する変数の型となるためのクラスと、「staticおじさんの世界におけるクラスの役割」の節で説明した、大きなプログラムを分割するモジュールとしての役割を持つクラスを同一視しているということにあります。

まず、Javaにおいて、この事実が当たり前と思えるようになれば、相当オブジェクト指向で考えられるようになっていると言えます。これは、Javaで適切な単位でクラスを設計し、オブジェクト指向プログラミングできるようになるための大前提であり、オブ脳の基本回路が脳に形成されたといっていいでしょう。

この同一視により、カプセル化という考え方も自然に理解できると思います。つまり、モジュールとして何を一緒に含めるのが自然であるかということを考えれば、オブジェクトに含まれるデータに関連する処理をメソッドとして一緒にクラスに定義し、フィールド自体はprivateにして外部から勝手に操作されないようにする考え方も納得がいくのではないでしょうか。String型のオブジェクトに含まれる文字列を加工するためのメソッドはStringクラスに定義されているので、文字列オブジェクトに対してそのまま呼び出すことができます。一般的にはこのように関連するデータと処理を同じクラス内に定義することが基本となります。

どうすれば、オブ脳が鍛えられるのでしょうか。こればかりは、JDKオープンソースのライブラリーをお手本として、また自分なりに似たような設計を試しながらプログラミングの経験を積むことに尽きると思います。

まとめ

ここでは、一般の入門書にあるような説明とは違ったアプローチで、Javaのクラスとオブジェクトについて理解するための説明を試みてみました。

実際には、最後の項目はかなり内容を端折っているので、クラスを有効なモジュールとして設計するためには、カプセル化の他に継承ポリモーフィズムなどさまざまなことを理解する必要があります。

いまさらですが、職業Javaプログラマーなら理解しておいてほしい「継承」の意味について - 達人プログラマーを目指して

さらに、実際の問題を上手に分割してクラスに割り当てるということができるためには、やはり、それなりの経験を積んで勘を養う必要があります。*7そして、クラスをオブジェクトと結びつけて自然な単位として扱うのがなぜよいのかといったことを納得するには時間がかかるでしょう。しかし、プログラミング言語としてのオブジェクトやクラスの意味や存在意義はここに書いたように非常に単純なものに過ぎないということもできます。

もちろん、オブジェクト指向プログラミング言語で実現する方法はさまざまですし、Rubyなど、より純粋な言語を使って学ぶべきであるという意見もあるかもしれません。しかし、大部分のJavaプログラマーにとっては、モジュール配列、構造体といった言語の仕組みの自然な拡張として、クラスやオブジェクトを理解するというパスがわかりやすいのではないかと思いますが、いかがでしょうか。乗り物や動物を使った説明や、逆に専門的すぎて難しい解説を読んでよく理解できなかったという人は、まずは、ここに書いたようにプログラミング上の当たり前の考え方との比較から徐々に理解するのがよいのではないかと思います。そして、この基本が理解できたら、お手本となるソースはいくらでも転がっているのですから、オブジェクト指向の良いクラスライブラリーを読んだり、拡張したりすることに是非挑戦してみてください。

*1:ただし、オブジェクト指向プログラミングを動物や乗り物で解説するのは和書だけでなく、世界的にも一般的な傾向のようです。

*2:ただし、厳密には文字列配列オブジェクトは除く

*3:勘違いしやすいところですが、メソッド定義はstaticでもそうでなくても静的にクラスごとに読み込まれます。ただし、staticでないメソッドは暗黙のthisオブジェクトを受け取ることで、動的なインスタンス変数アクセスできる点が違います。

*4:抽象データ型や参照はオブジェクト指向言語に限らず重要だと思います。スクリプト言語Perlでも、バージョン5から参照が使えるようになって随分と高度なプログラミングが可能になっていますし、このあたりは本格的なプログラミングには欠かせないツールなのだと思います。

*5:本家のstaticおじさんはC#VisualBasic使いなので、適切でなかったかもしれません。ここではオブジェクト嫌いなおじさんという意味の一般用語として使っています。

*6:重要な違いとして、C言語配列サイズはコンパイル時に決定されますが、Java配列は実行時に決められます。

*7:経験を補うものとして、デザインパターンなどがあるわけですが。

2011-12-05

ここぞというときの集中力Upのために、ヘッドフォンで音楽を聴きながらプログラミングしましょう

仕事や趣味でプログラミングしたり技術書を読みながら勉強したりする際には、言うまでもなく集中力を高めて維持することが大切ですね。職業プログラマーに必要な集中力ということには少なくとも二つの意味があるとは思いますが、

いずれにしても、自分の場合は寝不足だったり、周りの雑音で気が散ったりしてコンディションが悪い時にはあまり集中できずに、圧倒的に作業効率が下がってしまいます。逆に、調子よく集中できた時には時間がたつのも忘れて一気に仕事を片付けることができます。

もちろん、プログラミングで集中力を高めるためには、日頃から規則正しい睡眠や食事などが欠かせませんが、ここぞという時に一人で集中するにはヘッドフォンで音楽を聴くのが個人的には非常に効果的な手段だと思っています。

客先常駐の場合は、常駐先の会社の文化によってはヘッドフォンで音楽を聴きながら作業をすることを禁止しているところもあるかもしれませんが、幸運なことに自分のチームではOKなので、本当に一人で集中して考えたいときにはヘッドフォンを利用しています。もちろん、ヘッドフォンにはチーム間のコミュニケーションを阻害するという弊害もあって、周りの人に質問しづらくなってしまうという問題があるのですが、一日の作業のうちで集中する時間を区切って利用すればよいのではないでしょうか。

音楽を聴きながらプログラミングする際の問題は、どのような音楽が集中に適するかということですね。一般的には歌詞のない音楽でモーツァルトなどのクラシック音楽などがよいとよく言われますが、もちろん、これには好みによって個人差があると思いますし、人によってはクラシックはかえって心地よくて眠くなるという人もいるかもしれません。

私の場合はずいぶん以前からいわゆる「集中力Upのための音楽」というちょっと怪しげなジャンルの音楽に非常に興味があって、実際仕事や勉強でいろいろと活用しています。

Focus CD (フォーカス CD)

Focus CD (フォーカス CD)

たとえば、以上のCDは雨の音がひたすら聞こえるだけなのですが、左右の耳から周波数の異なる音を同時に聴くことでいわゆるバイノーラルビートと呼ばれる効果で脳の集中力が活性化するそうです。Amazonのレビューでも高評価なので試してみてはいかがでしょうか。このCDの製造元の説明は以下にあります。

Boost your concentration at the touch of a button

そのほか、同様のバイノーラルビートを活用した音楽でヘミシンクと呼ばれるシリーズのタイトルはいくつか利用していますが、個人的にはかなりおすすめです。(以下で部分的に視聴できます。)

D

D

インディゴ : Indigo for Quantum Focus [ヘミシンク]

インディゴ : Indigo for Quantum Focus [ヘミシンク]

コンセントレーション : Concentration [ヘミシンク]

コンセントレーション : Concentration [ヘミシンク]

Remembrance [ヘミシンク]

Remembrance [ヘミシンク]

ブレークスルー : Breakthrough [ヘミシンク]

ブレークスルー : Breakthrough [ヘミシンク]

以下は、ブレインシンクと呼ばれる別のシリーズで、ヘミシンクと同様に集中力や記憶の向上に役立つとされているタイトルがあります。

High Focus: Activate Lucid Thinking (Brain Sync audios)

High Focus: Activate Lucid Thinking (Brain Sync audios)

Brain Power

Brain Power

なお、これらの音楽は人によっては非常に深い集中状態をもたらすため、逆に外界に対する反応が鈍くなってしまうことがあり、自動車で運転中などには絶対に聴かないようにとの注意書きがあります。