解くべき問題を探すには、優れた質問を探すのだ | アート・オブ・プロジェクトマネジメント

前章で、スケジュールについての理解は深まりました。 次はこのプロジェクトでどのような問題をどうやって解決するのか決めなければいけません。つまり計画フェーズです。本章では「計画」を、いわゆる要件定義と設計をセットにしたものとして扱っているようです。 どうやって計画を立てれば良いのでしょうか?

自分の受託開発での仕事の流れを思い返すと、作成する要求定義ドキュメントの定義について顧客との間で取り決めが交わされていました。でもあのドキュメントの定義ってどんな基準で作られたのでしょうか。雛形があるとしたらそれはどんなロジックで決められたものなのでしょうか。

ソフトウェア計画の因数分解

ソフトウェア計画は、大きく2つの項目にわけられる、と本著は言っています。それは、

  • 何を行う必要があるのか?(要求の洗い出し)
  • どうやってそれを行うのか?(設計)

の2つです。 そしてこれら2つの作業の内容は、組織のスタイルとプロジェクトの規模によって変化します。 組織のスタイルについては、要求事項・設計内容・技術的チャレンジ・予算への決定権の持ち主が誰かによって必要な作業内容や合意を取るべき人が変わることを言います。 また規模については、1人プロジェクトなら本当に大切なことだけをドキュメントにまとめておけば十分かもしれません。一方、『人月の神話』のブルックス先生が論じたような新しいPCの開発なら、すべてをドキュメント化するくらいの勢いでないと1人1人が何をすべきか全くわからなくなってしまいそうです。

上記のことを踏まえたうえで、本著では計画フェーズの成果物として以下のドキュメントを作成することを提供してくれています。勿論各プロジェクトによって変更すればいいのですが。

  • 市場要求ドキュメント
  • ビジョンのドキュメント
  • 仕様書
  • WBS

市場要求ドキュメントはビジネス機会についての文書、ビジョンはプロジェクトがなにを達成すべきなのかや大きなレベルでの要求などが定義された文書、仕様書はビジョンを実現するためにもう少し細かい部分について、各部分がなにを実現すべきなのか定義したドキュメント、そして最後にWBSは、仕様を満たすための作業の予定をチームメンバー全員が決められるようにするためのドキュメントです。

計画の3つの視点

上記でまとめたものには、ビジネスとしての観点とエンジニアリングとしての観点が両方入っています。本著はこれら2つの視点を、大抵のプロジェクトにおいて相反するものであると述べていますが、同時にこれらの視点が競合することは計画フェーズの失敗のもっとも基本的なシグナルであるとも述べています。計画フェーズでチームは、すべての視点に立つメンバーが貢献できるような計画を立てるべきなのです。

ではチームがどのような状態であれば、正しい計画を立てられているといえるのでしょうか? Scott氏は、それぞれの視点についてのある質問に答えられるかどうかを試金石とできると述べます。

ビジネス視点でみた計画

エンジニアから見て営業さんやビジネスサイドは、時たま特定の顧客の要望を丸投げする人に見えたりすることもあるかもしれません。しかしビジネスサイドの彼らが自分たちの組織の損益計算書を増益で終わらせる努力をしてくれるから、みんながお給料をもらえていることには、チーム全員が自覚的であるべきです。

チームがビジネス視点で計画を立てられているかを測るためには、以下のような質問が有効です(本の中にはもっとたくさんの質問が載っています)。

  • 顧客のニーズはなにか?
  • コストと、それに対して見込める利益はどれくらいか?
  • いかにして競合他社を出し抜くのか?

技術視点でみた計画

技術的に優れている結果顧客のニーズを満たす商品であれば最高ですが、単に技術的に優れただけの商品では売れません。エンジニアリングに携わるメンバーは、自分の仕事への審美眼を持つことは素敵なのですが、それだけに傾倒してはいけません。 顧客のニーズを満たすものを、最高の方法で実現するための計画になっているかは、以下のような質問で確かめられます。

  • このコンポーネントはどのようなインターフェースを持つのか?
  • このシステムはどれくらいのセキュリティレベル、可用性やパフォーマンスを担保するのか?
  • ある仕組みを実現するためには、どのような技術的な選択肢が考えられるのか?

顧客視点でみた計画

Scott氏は、この視点がソフトウェア計画で最も重要であり、最もないがしろにされがちであると言います。 プロジェクトマネージャは顧客視点での計画立案に長けたメンバーを採用し適切な権限を与えるべきです。彼らは以下のような質問に答えてくれるでしょう。

  • 実際のところ、我々の顧客はどのような作業を行っているのか?
  • どんな不満を感じているのか?
  • ユーザーになんと話せば、このプロジェクトの真価を分かってもらえるのか?

プロジェクトマネージャは3つの視点を操る者

プロジェクトマネージャは、ソフトウェア計画を構成する3つの視点を知ったうえで、それを適切にコントロールしなければいけません。 プロジェクトマネージャは、チームメンバーに各視点の共通点と相違点を理解してもらうことで、我々が時に「カネにならないが技術的に優れたアイデア」や「ビジネス的に最高だが技術的には実現不可能なアイデア」が出てき得るという事実を共有することができます。

また、3つの視点の政治的なパワーにも気を配る必要があります。 人数比は当然大切ですがそれだけではなく、各メンバーの声の大きさにも気を配り、 ある視点だけが強力になりすぎることを抑制しなければいけません。

優れた計画のためには、優れた疑問を探すこと

ソフトウェア計画の3つの視点についての話でもそうだったように、優れたプロジェクト計画には優れた質問が不可欠です。 計画を立てるときには、3つの視点からの質問を自分たちのプロジェクトに合わせてピックアップして回答していくとよいでしょう。しかし実際に疑問として使用するときにはもっと広い視点での疑問が必要です。 本著に書いてある疑問のごく一部を例として挙げておきます。

  • 議論の時に想定される顧客層は誰なのか?
  • 我々は解決したい問題に対して十分な技術力や知識を持っているのか?
  • 競合他社はこの問題に対して何を行っているのか?彼らの戦略はなにか?

勿論、良いソフトウェア計画手法があるならば、一方で悪い手法もあります。たとえば「このパージョンは前バージョンで省いた機能を入れるだけのものだ」など。 どんなに時間がなくてもこのようなパターンにハマってはいけません。

実際の計画の進め方

計画は少数のエキスパートで行うべきです。人数が増えるほど創造性と生産性が下がってしまいます。選出されなかったメンバーは自尊心が傷つくでしょうが、だからといって議論のメンバーを増やすよりは個別に彼らを癒やした方が良いです。

計画フェーズの成果物しての各種ドキュメントは、互いに相関しあいながらブラッシュアップされていきます。 しかし、抽象度に開きのある2つのドキュメントの修正はコストがかかるので、抽象度近いもの同士でフィードバックを行うべきです。

計画の手段として顧客調査を行う場合がありますが、様々な方法があるので適切なものを選択してください。

計画作業の成果として書き出される要求は、叙述的なシナリオになるはずです。ユースケース駆動開発に関する書籍がこのフェーズを助けてくれるでしょう。

スケジュールの役割 | アート・オブ・プロジェクトマネジメント

私たちは日々、スケジュールと共に生活しています。そして、頻繁に遅れます。 飲み会の開始時間、DVDの返却期限、クリスマスプレゼントの用意、そして仕事。 私などは自分が遅れることを知っていますし、遅れない計画の建て方もよくわからないので、ついスケジュールを立てることに消極的になってしまいます。

あの悩ましいスケジュールとは、一体なんなのでしょうか。また、どうやって立てればいいのでしょうか。

スケジュールの役目は、厳守されることだけではない

『アート・オブ・プロジェクトマネジメント』は、スケジュールの役割は3つあると言っています。

  • いつものごとが完了するのかを表す
  • チーム全体における個人の成果物の位置づけを理解させ、書くメンバーの協調を促進させる
  • 作業を管理可能な塊に分割するツールをチームに与える

です。 たしかに、状況が不確定すぎるからと仕事の完了期限を濁していて、チームメンバーに困った顔をされた経験があります。 状況が不確定でもいったん期限を切る、という行動の裏には、チームの協調を図るという目的もあったのです。 自信がないからといって叩き台にできるスケジュールも提供しないのでは、マネジメントもなにもできません。

じゃあどうやって、そのスケジュールを立てるのさ? 1/3の法則

といっても、守れもしない適当な期限でばかり合意したら、それこそアドレナリン・ジャンキーになってしまいます。現実的なスケジュールは、どうやったら立てられるんでしょうか。

本著はそこで「1/3の法則」を提唱しています。 1/3の法則とは、どんなスケジュールでもざっくり分ければ「計画 / 実行 / 検証」の3ステップに分けられるから、その3ステップのそれぞれにかかる時間をイメージしてみれば、そんなにズレのないスケジュールができるでしょ!という豪快な法則です。

この法則は、対象が自分1人でやる作業であったとしても、昔ながらのウォーターフォール型の開発モデルであったとしても、あるいはスクラム開発であったとしても、あてはめることができます。 自分1人の作業なら「何をするか、どうやってするか」を考え「実際に手を動かし」て「それが要件にあっていることを確認する」のが3つにわけられます。ウォーターフォールモデルでは対象が巨大になりますが同じです。そしてスクラム開発は、小さな1/3の法則の集合といえます。

そのスケジュールの正しさをどう担保しよう?

1/3の法則で作ったスケジュールは、どうして正しいといえるのでしょうか? 本著の著者、Scottさんは

初期計画時点でスケジュールを作成する場合、そのスケジュールに影響を与える、星の数ほどある意思決定は、まだ行われていないはずです。…(中略)… このため、でっち上げた数字と乱暴な予想で粗いスケジュールを作り上げ、それを角度の高いプロジェクト計画としてチームに引き渡すことになります。

と書いています。つまり、当たり前のことですが不確定な状況で正しいスケジュールは立てられないということです。 だから優れたスケジュールを立てるには、不確定な情報のない優れた設計が必要です。 優れたスケジュールは、見積もりを行うエンジニアが十分だと納得する程度に詳細な設計情報、エンジニアへの信頼、そしてなにより、チームメンバーが「スケジュールは確率と予想の掛け算であり、ブレ得るものだ」という前提に立っていることから生まれるのです。

本著に書いてあるけれど、本稿に書いていない具体的なこと

他にもこの章では、スケジュールを立てる時についつい見過ごしがちなチェックポイントのリストや(連休期間中の稼働時間は短めにしてあるか?)や、スケジュールを機能させるためにすべきことのリスト(リスクには先に対処する)が盛り込んであります。

http://amzn.asia/ieLFu8M

プロジェクトとは?マネジメントとは?そして、マネージャとは? | アート・オブ・プロジェクトマネジメント

  • 平易な言葉で書かれたマネジメント全体を説明する書籍

WillCan面談で決めた目標を達成するために、上司であるところの @kawasima さんからいただいた書籍のひとつ、アート・オブ・プロジェクトマネジメントを読み始めました。 本著は、体系立っている一方で難しい言葉を使わずに、プロジェクトマネジメント全体について説明した書籍です。目次だけ見ても、歴史にはじまりスケジュールの引き方、ビジョンについて、コミュニケーションの問題、プロジェクトの終わらせ方に社内政治など、様々なテーマが詰まっています。 その分厚みもあり、ページ数なんと400P超え!息切れしないように、1周目である今回は適度に飛ばしつつ全体像を把握していこうとおもいます。

そして今回は1章を読んだので、それについて書きます。

「プロジェクト」は古今東西にある、共通した骨組みを持つモノ

プロジェクトは古今東西に偏在してきた概念です。言われてみればそうですね。プロジェクトには目標があって、予算があって、納期があります。それは正倉院を作るのだって宇宙船を作るのだって映画を作るのだって、あるいはクレジットカードの決済基盤を作るのだって同じです。 そしてそれらは共通しているために、比較可能なはずです。ということは、今自分が進めているプロジェクトは、今まで行われてきたすべてのプロジェクトから何か学ぶことができるはずです。しかし現実はそうなっていません。

その要因のひとつは、見た目があまりに違うとそもそも「比較できる」と信じ難いことです。実際私も、ピラミッドの建造とWordpressサイト構築を比べて何か学べと言われても、想像もつかないです。 だから、現代の他の産業のプロジェクトマネジメント手法と、ソフトウェア開発を比較しましょう。私は学生時代、公文の先生のバイトをしていました。とても素敵な教室だったので、今はあの教室の空気を職場で再現するのが人生の目標です。あの教室と今の職場で、違うのはなんでしょう?そして同じものはなんでしょうか。

プロジェクトマネージャはプロジェクトを成功に導くリーダー

プロジェクトマネージャは、あるコードを美しく動かすことではなくプロジェクト全体の面倒を見ることで成功をもたらすリーダーです。 プロジェクトマネージャはある時は情熱家、ある時は現実主義者でなければありません。またある時は明確なドキュメントを求め、別の時は口頭での曖昧な説明を求める必要があるかもしれません。

しかしその職務内容は曖昧です。ただの観測者ではいけないし、管理したがりも邪魔なだけ。必要なのは、チームメンバーを助け、アツさを持って良いものを作り上げようとすることだけ。具体的には…なにをしたらいいんでしょうか?

それは今後の章のお楽しみ。

平易な言葉のシンプルさと難しさ

私は本著を読み始めたところなのですが、「平易な言葉での説明を貫く」という方法はとても好きです。私が書くもの、話すことにおいてもかくありたいです。ご覧の通り、まだまだなわけですが…。

本著の中でも述べられているのですが、シンプルな本質を見つけることで集中を高められる一方で、シンプルであることは簡単であることと直結しません。マラソンは「42.195km、一番早く走りきる」というシンプルなルールでできた競技ですが、決して簡単な競技ではありませんしね。 そう思うにつけ、「プロジェクト」などという巨大で難解なものをシンプルな言葉で語ろうという本著が気に入ります。 
http://amzn.asia/i2LR6mg

『アドレナリンジャンキー』を笑えなくなったらヤバい

『アドレナリンジャンキー』を読んだ。

『アドレナリンジャンキー』はソフトウェア開発あるあるネタ

『アドレナリンジャンキー』は、他にもユーモラスな本をいくつも書いているトム・デマルコ氏の著作です。本著は彼が仲間と一緒に、ソフトウェア開発現場での「あるあるネタ」をたくさん集めて本にしてやったぜ!という、あるあるネタ集です。 「あーこれ見たことあるわ」というのから、「言われてみればそうだけど、いつかこういう状況に鉢合わせることもあるんやろな…」というようなハッとさせられるようなものまで、様々なあるあるネタが満載です。

最近Twitterで時々流れてきていた「悪い情報は上司に登るほど美化される」みたいのも、2009年に刊行された本著にバッチリ収録されています。

輪読したら楽しそう

本著はどれも選りすぐりのあるあるネタなので、どのネタも心動かされること間違いなしです。だから「○○が一番おもしろかった」とは本著に関しては言えません…。 強いて言うなら、こんなに秀逸なあるあるネタがこんなに集まってること自体が最高の良い点です。

部内の先輩・後輩含めた幅広い年齢層で輪読、というかみんなでスライドに表示したKindleの画面を見ながら話すだけでも楽しそうだと思います。そしたら「反省会をしよう」と誰かが言った時、みんなで「あっ、これやり方に気をつけないとやばいやつ」と思えたりするんじゃないかなと思います。そういう共通の温度感を養う入り口に使ってみたいなと思いました。

ぜひ手にとってみてください

「テンプレートゾンビ」「魂の仲間」「隠れた美」「機能のスープ」…。どんな意味か想像がつきますか?きっと想像と、そんなに外れてはいないと思います。 シンプルでニヤッとできる寓話であるあるネタを楽しみたい人は、ぜひ手にとってみてください。きっと楽しめると思いますよ。

http://amzn.asia/dCDUGbD

『ハッカーと画家』から、富について学んだ

ハッカーと画家を読みました。

ハッカーと画家』はWebアプリの祖が書いたエッセイ

ポール・グレアム氏が、ソフトウェア開発やサービス開発、ベンチャー企業などについて綴ったエッセイ…なんでしょうか。

刊行されたのはずいぶん前で、しかしもうWebベースのアプリケーションが当たり前になった時代。それを最初に切り拓いたグレアム氏から見た、インターネットの過去・現在・未来を語ってくれます。

富は、それを生み出した人が手に入れる

この本には「いつか誰でもどこからでもインターネットに接続できるようになる。」「デバイスが小型化する」など、慧眼といえる未来予測も入っていて、それも面白いです。

しかし、僕が一番おもしろいと思ったのは、

「限られた人が大きな富を持つことは、『富は奪い合うのではなく、作り出すから手に入る』という前提が成り立つ社会では間違いではない」

という主張でした。

世の中では「人口の数%が世界の富の何%を独占している」というような主張が、とても悪いこととして喧伝されることがあります。僕も今まではなんとなくそれは良くないことのように思っていました。

ところがグレアム氏は、僕らがそう思うのは荘園制の時代の思い込みである、といいます。つまり、領主が無条件に農奴から富を奪い、農奴は富を奪われたから貧しいという状況なら、富の独占は悪いことと思われたはずだ、というのです。しかし現在はそうではない。MicrosoftやかつてのIBMがあんなに巨額の富を築いたのは、彼らが世の中にそれだけ大きな新しい富を作り出したからだ、というのです。

たしかに!と思いました。もしMicrosoftWindowsを作らなければ、僕らはいまだに紙に手書きでグラフを書いていたかもしれません。それなら、Microsoftが富むのは世界を良くした当然の報酬だと思いました。

ぜひ手に取ってください

ハッカーと画家』は、こんなワクワクし、ドキッとされられ、悩まされる話が詰まった本です。世界で初めてのWebアプリを作って公開し、Yahoo!に売却した彼が、どんな哲学を持ってそれを成し遂げたのか。

気になる方はぜひ手にとってみてください。きっと楽しめると思いますよ。

http://amzn.asia/6rxuQ17

SpringframeworkからはじめるSpringBoot Part.1 - 依存性注入

承前

SpringBootを触れるようになったけど仕組みが全然分からなくて応用できない!から、やっぱり内部が分からないとと思ってSpringframeworkから見直してみました。 誤った情報を広めたいわけではないのですが、それでも理解がおかしい部分はあるかもしれません。その時はコメントください。

この記事に書いてあること

  • springframeworkのDIとは?
  • xmlでDIを定義する
  • 実際に定義したDIが実行されていることを、サンプルコードで確認する

まずDI(依存性注入)

それでは、まずDIからはじめましょう。これがSpringframeworkの根っこです。

そもそもSpringframeworkにとってのDIって何?

DIというものについてのもっと良い情報は世の中に山ほど公開されています。しかしここでは改めて解説させてください。 ちなみに今調べたら他の資料としては猿でも分かる! Dependency Injection: 依存性の注入 - Qiitaなどが見つかりました。猿でも分かるそうなので人類ならばきっと理解できると思います。

Springframeworkの公式ドキュメントでDIについて言及している部分にはこう書いてあります。

IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies, that is, the other objects they work with, only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method.(引用元は公式ドキュメント)

(これは実はIoCについての記述なのですが)IoCは依存性注入(DI)という名前でも知られています。これはオブジェクトが自分の依存性(動作に必要な別のオブジェクト群)を、自分がインスタンス化されたりファクトリーメソッドから返却された後で、コンストラクタやファクトリーメソッドの引数、オブジェクトのインスタンスの変数のみによって定義する手段です。

つまりあるオブジェクトが使う別のオブジェクトを、なにかより柔軟な方法で定義できる、ということのようですね。

その後の方には、

  • 普通はBean(オブジェクト)自身が、自分が使うオブジェクトを規定するはずなのに、ここではDI ContainerがBeanを構築する時にそいつの使うオブジェクトを決める。これって逆転してるよね。だからIoC(Inversion of Control, 制御の逆転)っていうんだよ。
  • SpringframeworkではIoCを実現するためにorg.springframework.beansorg.springframework.contextってパッケージを使うよ。
  • BeanFactoryはオブジェクトの設定を行う基本的な機能を提供して、ApplicationContextでより実用的な機能を提供するよ。
  • ちなみにさらっと出てきてたけどBeanっていうのはIoCコンテナによってインスタンス化され管理されるオブジェクトのことだよ。

みたいなことが書いてあります。どれも目にしたことのある言葉ばかりですね。結構読みやすいのでぜひ一度目を透してみてください。今後ググった時にSpringの公式ドキュメントが出てきた時にビビらずに済むようになることでしょう。

さて、これでDIについてピンと来たでしょうか?私は当時全く何もピンと来ませんでした。 ですから、手を動かしてみましょう。

DIだけ試してみよう

ここで「ではSpringBootのプロジェクトを作ってAPIを作って…」みたいなことをやると、いろいろややこしいものが入りすぎて何がなんだかわからなくなるので、まずはDIだけを試してみましょう。

SpringframeworkでDIを試すには、 spring-context というライブラリを使います。 公式ドキュメントによればspring-contextは、

it is a means to access objects in a framework-style manner that is similar to a JNDI registry.(引用元はこちらの第2段落)

JNDIレジストリみたいなフレームワークのお作法に則ったやり方でオブジェクトにアクセスする手段です。 この「アクセスする手段」こそがDI(依存性注入)というわけですね。 spring-contextはその依存ライブラリに

  • spring-core
  • spring-bean

などを持っています。上で出てきたorg.springframework.beansパッケージが含まれていそうですね。

1.プロジェクトの準備

さて、では本当に手を動かしていきましょう。 まず元となるプロジェクトを作りましょう。

mvn archetype:generate

対話式でgroupIdなどを尋ねられるので好きなように設定してください。終わったらIntelliJなどのIDEに取り込みます。 古めのJUnitの依存が入ってますが使わないので消してあげましょう。

  <!-- pom.xml -->
  </properties>

  <dependencies>
-   <dependency>
-     <groupId>junit</groupId>
-     <artifactId>junit</artifactId>
-     <version>3.8.1</version>
-     <scope>test</scope>
-   </dependency>
  </dependencies>
</project>

src/test配下も使わないので削除しておいてください。

そしてspring-contextの依存を追加してあげましょう。

  <!-- pom.xml -->

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+   <spring.version>4.2.4.RELEASE</spring.version>
  </properties>

  <dependencies>
  </properties>

  <dependencies>
+   <dependency>
+     <groupId>org.springframework</groupId>
+     <artifactId>spring-context</artifactId>
+     <version>${spring.version}</version>
+   </dependency>
  </dependencies>
</project>

これでSpringframeworkのDIが使えるようになりました。

2.Beanオブジェクトの実装

今回は、文字列を標準出力するサービスクラスを用意して、それを呼び出してDIを体験してみましょう。

sayHelloメソッドを定義するHellointerfaceと、それを実装して文字列を標準出力するクラスを2つ、用意しましょう。

package jp.blackawa.examples;

/**
 * 文字列を標準出力するメソッドを定義するインターフェース.
 */
public interface Hello {
    void sayHello();
}
package jp.blackawa.examples;

public class HelloBoys implements Hello {
    public void sayHello() {
        System.out.println("Hello, Boys!");
    }
}
package jp.blackawa.examples;

public class HelloGirls implements Hello {
    public void sayHello() {
        System.out.println("Hello, Girls!");
    }
}

Helloを使用する( = Helloに依存する)サービスクラスも用意しておきましょう。SpringBootではビジネスロジックをよくサービスクラスに書きますよね。

package jp.blackawa.examples;

/**
 * 挨拶を出力するサービスクラス.
 */
public class HelloService {
    private Hello hello;

    // Getter, Setterを用意しておく.
    public void setHello(Hello hello) {
        this.hello = hello;
    }

    public Hello getHello() {
        return hello;
    }
}

Hellointerfaceの実装は2つ用意されています(HelloBoys, HelloGirls)が、ここまでではHelloServiceがどちらに依存するかは決まっていません。 なんだかDIっぽくなってきましたね。そんな感じがしませんか?

3.Bean定義の用意

では、このプロジェクトがどっちのHellointerfaceの実装を使うのか、決めてあげましょう。 それにはxmlファイルを使います。懐かしいですね。 xmlファイルによるBean定義は、SpringBootが採用しているアノテーションJavaベースの設定よりも冗長で記述量も多く、エラーにも気づきにくいです。しかしその分xml定義の方が何が起こっているか明確に分かるはずです。

src/main/resources配下にbeans.xmlという名前でxmlファイルを用意してください。

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

ここからが重要なので、段階的にいきましょう。上記の空ファイルができたら、次にBeanを登録しましょう。

Beanとはなんでしたっけ?SpringframeworkのDIコンテナで管理するオブジェクトでしたね。今回はHellointerfaceの2つの実装クラスをDIによって使い分けたいので、これらを登録すれば良さそうです。

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean id="helloBoys"
+          class="jp.blackawa.examples.HelloBoys"/>
+    <bean id="helloGirls"
+          class="jp.blackawa.examples.HelloGirls"/>
</beans>

2つのBeanにIDとそれに紐づくclassが定義されているのが一目瞭然ですね。DIっぽくなってきましたね。

そして最後に、HelloServiceクラスが使用(依存)するのがどちらのHellointerfaceの実装クラスなのかを定義してあげましょう。

    <bean id="helloGirls"
          class="jp.blackawa.examples.HelloGirls"/>

+    <bean id="helloService"
+          class="jp.blackawa.examples.HelloService">
+        <property name="hello" ref="helloBoys" />
+    </bean>
</beans>

HelloServiceクラスをBeanとして登録しました。 そしてHelloServiceクラスの変数(property)であるhelloの参照を、HelloBoysに定義します。 なんと、あるクラスの変数が保持するインスタンスをBean定義のxmlファイルから定義してしまっています!IoC、制御の逆転というのがなんとなく感じられますね!

4.HelloServiceを使ってみよう

では動かしてみましょう。SpringBootを通して、このようなBeanが思い通りのオブジェクトを使って動いてくれるのは知っていると思いますが、こういうのは実際に動かしてこそ面白いものです。

mainメソッドからHelloServiceを呼び出して、変数として保持しているHellointerfaceの実装を取得してみましょう。

package jp.blackawa.examples;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main( String[] args ) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        HelloService service = (HelloService) context.getBean("helloService");
        Hello hw = service.getHello();
        hw.sayHello();
    }
}

読んで字の如く、

  1. クラスパス上のxmlファイルからApplicationContextを取得する。(ApplicationContextってなんでしたっけ?)
  2. そのApplicationContextからhelloServiceを取得する。
  3. HelloServiceの中に入っているHellointerfaceの実装クラスを取得し、文字列を出力させる

をしているように見えますね。そして実際にそうしています。

では…お持ちのIDEでこのmainメソッドを実行してみてください! コンソールにHello, Boys!と出力されますね。

おめでとうございます。これがDIです。

beans.xmlの定義を変えてみましょう。

    <bean id="helloService"
          class="jp.blackawa.examples.HelloService">
-        <property name="hello" ref="helloBoys" />
+        <property name="hello" ref="helloGirls" />
    </bean>
</beans>

Javaソースコードを一切いじらないままに出力内容がHello, Girls!に変わりますね。

おめでとうございます。

ちなみに、mainメソッド内で直接HelloServiceを呼ぶことも可能ですが、そうするとBean登録されていないサービスクラスを使うことになるので、getHelloから何も取得できません。だってどこでもその変数の初期化をしていませんからね。 普通ならHelloServiceインスタンス化する時に引数としてHellointerfaceの実装クラスを渡すはずなのに、おかしいですね。制御、逆転していますね。

肌で感じられましたか?

さて、ここまででSpringframeworkのうちDIだけを試してきましたが、肌で感じられましたか? これでSpringBootのうち@Autowired@Component@Serviceなどは怖くなくなりましたね! アノテーションをつけると、今日書いたような設定がうまいことやってもらえてControllerクラスから好きなServiceクラスが使用できるんですね。

次回はただの文字列を出力するのではなく、Webアプリケーションを作ってみましょう。まだxmlでの設定はまだ続きますよ。 今回もそのおかげで仕組みがよく分かりましたしね。

参考資料

SpringFrameworkから始めるSpringBoot Part.0

SpringBootってよく分からない?

みなさん、SpringBoot、つかってますか?

使ったことがない方へ。 最低限Getting Started Guideをいくつかやったことがないと、この先は読み進めても面白くないです。今すぐコーヒーを淹れて、1時間ほどSpringの世界を楽しんできてください。それから次の行を読んでください。

SpringBootは簡単でシンプル?

さて、みなさんはSpringBootにどんなイメージをお持ちですか?私は仕事で使ってみるまで、 開発に必要な機能が全部揃ってて簡単に始められてシンプルでJava開発ではよく聞くWebフレームワークみたいなイメージでした。

@SpringBootApplication // こう書いとけばSpringBootだってことになる
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
@Controller // こう書いとけばリクエストを受け付けるクラスになる
public class UserController {
    @RequestMapping("/user/hoge") // こう書いとけばこのURLにリクエストが来た時このクラスが動く
    public String index() {
        return "user/index"; // こう書いとけばあるディレクトリのHTMLファイルが勝手に呼び出される
    }
}

「こう書いとけば○○」って便利ー!シンプルですごいなー!って私は思ってました。

でもこれが通用するのはチュートリアルをやっている間だけでした。

HTMLの置き場を変えなければいけなくなったらどうしたらいいの? DB接続の方法を変えなければいけなくなったらどうしたらいいの? UTF-8以外の文字コードが使いたい時どうしたらいいの? どこにも何も書いてないのに変な挙動をする... etc...

その他すべての、便利でシンプルな方法では解決できない問題を、私は解決できませんでした。

どうやらSpringBootは、少なくとも簡単ではないようです。

SpringBootは巨大なブラックボックス

たったひとつのアノテーションをつければ期待どおりに動くSpringBootが、なぜ少し道から外れたことをしようとすると途端に手も足も出ない複雑さで牙を向くのでしょうか。

答えは歴史が知っています。SpringBootはもともとWeb開発専用ではないライブラリをいくつもくっつけて、それらを隠して簡単に使えるようにした巨大なブラックボックスなのです。

DIライブラリから始まった

詳しくて正確な歴史はここでは必要ないのでより詳しい方にお任せしますが、SpringBootの元となっているのは、SpringFrameworkというDI用ライブラリです。

みなさん、SpringBootを使ってて@Autowiredとか@Serviceとか書いたことありませんか?あれがDIで、あれこそがそもそもSpringFrameworkが担っていたものです。

その後、そのDIライブラリを元にしてWebフレームワークやバッチフレームワーク、そして今やSNS連携やクラウド、マイクロサービスにも対応するようになった巨大なライブラリ群が、Springなのです。

そしてSpringBootはこれらのうち基礎的なWebアプリ開発用フレームワークを簡単に使えるようにしたツールです。その中にはもちろんDIが入っており、DB接続部品が入っており、Web開発用ライブラリも入っています。

こうしてみると、SpringBootが巨大なブラックボックスであることが少しずつ分かってきます。SpringBootは、もともとWeb開発専用に作られたわけではないツールをたくさん内包しているのです。

だから、少し違うことをしようとすると私たちはSpringFrameworkの中身と向き合うことになります。これが私が感じていた複雑さの原因でした。

避けてはもったいない!

さて、SpringBootはどうやら必ず簡単というわけではなさそうです。 でもこれはとてもワクワクすることだと思いませんか? SpringBootが隠してくれていた複雑さをそっと紐解いて眺めることができれば、きっともっとSpringBootと仲良くなれることでしょう。 HTMLテンプレートのディレクトリを自由に変える方法を知っていれば、胸を張ってコードを書いてよく眠れるかもしれません。

それに、これはJavaでのWeb開発やSpringFramworkが時代と一緒に試行錯誤してきた成果を少しだけ垣間見るチャンスにもなりそうです。

だから、「こう書いとけば○○する」の一歩先へ進んでみましょう。

というか進んできました

半年ほど、たまたま仕事でSpringBootを使う機会があって、SpringBootを構成するライブラリ群を少しずつ眺めてきました。 諸先輩方に比べればたいしたことのない道程ではありますが、それは楽しい時間だったので、少し時間は経っていますが改めて記事におこしてみようと思います。

次回は、SpringFrameworkからはじめましょう。