サンプルアプリ
勢いと思いつきで作り、今もまた濃いMLが飛び交うGoogleGroup[buri-ja](http://groups.google.co.jp/group/buri-ja?hl=ja)で、Buriを使った開発と従来通りの開発(便宜上、こう表現しています)を比べてみる為のサンプルアプリを作ろうなんて事になりまして、現在GoogleCode(http://code.google.com/p/buri-ja/)にて作っております。
僕個人がイマイチGoogleCodeの使い方に慣れていない事もありまして、日々「え!?jarとかxlsとかコミットできねーの??」みたいな若干ネガティブな驚きの連続なのと、主に睡眠時間を削って開発していくしかないので、速度はそんなに早くないのが非常に申し訳ない感じです><
加えて、プレゼンテーションにMayaa+Cubbyをチョイスしました。実は今までこの2つのプロダクトとは、主開発者とお話をさせて頂いた事がある事とリファレンスをざっと読んだ事があるくらいしか接点がなかったので、これまたお勉強しながらという感じになってしまってます><
(Mayaa+Cubbyの組み合わせは素敵、という噂を聞いて何となく決定しましたが、これは本当になかなか素敵なプロダクトさんです)
でも、これで作ったアプリケーションは、Morph(http://panel.mor.ph/)というWarをデプロイできるフリースペースで使える状態で公開できそうなので、ちょっと頑張りたいと思ってます。
さらには、サンプルとしてのデータ収集用に、Buriを使わないものとBuriを使うものと同じ仕様でそれぞれ作ってみようかな、とも思ってます。
ちなみに、前回のエントリの反省を活かして、今回はBuri版を最後まで作りません!(先にBuri版に手を出すと前回同様めんどくさくってやってらんなくなっちゃう気がしてならないのでw
そして、それぞれの成果をburi-jaのMLでご提案のありましたクラス数やエンティティ数、ステップ数、メソッド数なんかで数字として比較できたら、Buriというものを知る上での重要な情報が生み出せるんじゃないかなとwktkしてます。
レガシーについて
Buriを勉強してまして、その中で「Buriは基本的にレガシーを相手にしてないよ」なんて話を聞いたりしまして、さてレガシーをどうするのが良いんだろう?等と考えておりました。
まだ全然まとまっていないので、メモ。
まず、レガシーとは何かと言うと「古い仕組み」というのが適切かな、と。
「古い」=「悪い」ではないのですが、これは対象をきちんと見極めてからでないと良し悪しは判断できない筈なのですが、一部には「古い」=「悪い」=「これがレガシー」という表現をされていたりして違和感を感じます。
古い仕組みが良いか悪いかを見極めるには、その古い仕組みの「使われ方」を見る事が必須となる筈です。
ここから、業務システムに特化した話になるのですが、「古い」仕組みが「悪い」仕組みになるには「現在の業務と乖離していないか」という点がまず何よりも重要。次いで、「現在の業務との乖離を埋める為のコストが大きい」となるかな、と。
この「現在の業務」が、そもそもずっと同じである保障もないし、その必要性もない訳です。業務を遂行している人がやり易いように、または業務を遂行する環境に適応していく為に、変わっていくものです。
なので、第一の「現在の業務と乖離していないか」という点は、事前に予測できるもの、予測できないものも含めて、必ず発生するものだと考えた方が自然です。仮に、将来の変化を見込んで業務のシステム化に取り組んだ場合でも、「現在の業務」との乖離は避けられませんし。
続いて「現在の業務との乖離を埋める為のコストが大きい」という点ですが、これは率直に言って「作りなおす」とした場合に「今あるものを直す」より安上がりに済めば、無理して今あるものを直す必要性はなくなります。
最も典型的なのが、過去の業務で存在していた「hoge区分」とか「foo分類」「barフラグ」を現在はもう使っていないというのに、ERの再設計をしないのでずっと今も残っているというケースかな、と思います。当時はnullを許容していなかったので、今も使われていないのにnullではない何かをセットしている。何かセットする上で業務的に意義のある値を割り当てられないので(だってnullの代わりですからね)、「99999」なんてコードを割り当てていたりする、とかですね。
このデータがお客様のビジネス上価値ある資源かと考えると、システムが表向きは問題なく動くようにする為の仕様調整の産物であって、業務遂行上の価値はほとんどないんじゃないかな、等と思えてくる訳です。これを後生大事に残していく意味って本当にあるの?とか。
ついでに言うと、こういう「仕様の為の仕様」みたいなものでも立派に仕様なので、使われない無意味なコードを割り当てていたとしても、テストの対象にはしっかり乗せないとダメですよね。で、そういったコストは人月商売をやっていると「オイシイ」と思うのかも知れないのですが、そこでまたバグが出る可能性が増えてしかもデバッグして他の箇所に影響を与えない可能性も考慮して、などリスクを意識すると恐ろしく非効率、非合理的ではないかいな、と。
等と考えて、「既存のものを直すより、作りなおした方が早い」なんて仕組みを考えないといけないんだなぁ、とぼんやりと思っております。
楽にしたいですねぇ。
何を、というと「開発」という仕事をです。
楽、というと語弊があって、正確には「瞬殺」できるようにしたいです。
ギョイゾー!の話で「すっげぇぇぇぇ」と騒いだり、最近Buriにばっちり心奪われてしまったのも、cfneoを開発しているのも(最近煮詰まって止めてしまっていますが><)、要するにこの「楽にしたい」という個人的な願望から、です。
業務システムのコストのほとんどは、テストが楽になればずいぶん減るんじゃないか、と思っていました。実証するにはまだ至っていませんが、手戻りとかデバッグ、仕様の再検討なんかを「防ぐ」のではなく「瞬殺」。この仕組みが出来れば、要件定義や設計で使える時間が増えるだろう、というのがcfneoの最初のステップでした。まぁ、どこから見てもAgileのUnitTestとJUnitです、という感じなのですがw
続いてBuriでは品質面で非常に気になるポイントがありまして、フローという形で実装を行うという点が1つ、そのフローがそのまま動くという点が1つ、そのフローのお蔭で退屈で複雑で辛い業務ロジックが相当楽になるっぽいという点が1つ。これらで業務ロジックの実装もテストも楽にすれば、より一層要件定義、設計とUIの実装に手間と時間を割けるだろうなぁ、と。
少なくとも、現場によってド鬼門になるERD設計が凄く楽になるっぽい、というのはその後の設計、実装、デバッグのコストとリスクを見る上で、スバラシイ効果が得られるのはどうやら間違いないようです。
と、全部を一気にというのはやはり無理で、少しずつ成果をきちんと出して積み重ねていくしかない訳ですが、そこで得られるであろう余力を今まで不十分だった所に向けるか、更なる成果を生み出す方に向けるかはともかく、まずは発展する為の余力・ゆとりを手にする為にもっともっと頑張らないとなー、と。
という訳で、出来たら年内にBlogに移行するよう地味にあれこれやってます。
いい加減マトモなIDで頑張ります><
でも、あれが引き継げない、これが引き継げない、とか何だか色々あるので並行運用も良いかもな、とか。
それも含めて頑張ります><
入門記12:Buriを使う為に必要なマインド(version 0.1.1)。
いきなりですが、「Buriは敷居が高い理由はすぐそこにある」でFAですよね?
今回は、ぶり祭りで羽生さんがおっしゃられていた「状態という観点による正規化」についてです。
Buriは業務システムをターゲットにしたライブラリです。
そして、業務システムの業務とは、お客様であるユーザの日々の仕事です。
日々の仕事は、そのほとんどが小さな目的・目標の連鎖と言えます。僕らの仕事で言えば、プログラムを書くのはテストをする為、テストをするのはテスト済のプログラムをシステムに組み込むため、テスト済のプログラムをシステムに組み込むのはシステムに新しい機能を加える為、等というように、小さな目的が積み重なって最終的に「お客様であるユーザの日々の仕事のお役に立つシステムを完成させる」というゴールを目指します。
この小さな目的を達成する事を、ここでは仮に「ミッション」と表現します。
このミッションの連続によってさらに大きなミッションを達成しようとするのが、たいていの仕事の根本です。「プログラム1つ作るだけ、されどそのプログラムがなければシステムは完成しない」という事ですね。
ここで、業務システムを見てみると、このミッションの達成はシステムによって完全に自動化したりする訳ですが、それだけではないミッションもあります。「判断する」といったもので、これは仕事と人間の接点です。この接点ではシステムで勝手にアレコレしてはダメで、人間(多くの場合、僕らのお客様)の意思を入れていただいて、その次のミッションに進むかどうかを決めていただかなくてなりません。
非常に分かり易い例で言えば、会社に交通費を請求する際に請求書を書きますが、これを完全に自動化してしまうと請求額にあり得ない金額を入れてもそのまま支払手続きをしてしまいます。しかし、心無い人間もたまにはいるので、その請求額が妥当かどうかきちんと見て判断しないとならない、というルールができます。そしてそのルールに則って、請求書は受領されるのか、差し戻されるのかが決まります。
この一連の流れには、「請求書を書く」、「請求書を受け付ける」、「請求書を受領する」、「請求書を突き返す」、「受領した請求書の支払をする」というミッションがあります。
ここで僕は、Buriが相手にしようとしている「状態」とはつまりここで書いたミッションではないか、と。
上記のミッションをアクティビティに、流れをトランジションに置き換えるとまるまるBuriで使うフローの下地になると思います。
こんな感じに。
(差し戻しの後は・・・どうなるんでしょうね。JPEdだとトランジションの繋ぎ方がなんかアレらしい。。。
そして、冒頭に出た「正規化」という点です。
正規化=NormalizationでNormal=正しいと訳されるところを、その著書で「普通にするって訳せば良いじゃん」とおっしゃられる羽生さんが、言う「状態という観点による正規化」です。では、「普通にする」ってどんなこと?となる訳ですが、これが非常に難しい。「普通って何?」は過去数世紀に渡って中二病を発症した若者が分かってくれない大人に反発しながら苦悶してきたにも関わらず解明されていないものです。
なのでもう少し軽く考えると、「普通にする」というのは「当たり前にすること」であり、前述の例で言えば「請求書を書く」ことと「請求書を受け付ける」ことはイコールではありません、という事です。イコールではないので、2つのアクティビティとして表現されます。同様に、「請求書を受領する」と「請求書を突き返す」もイコールではありませんので2つのアクティビティです。しかし、この一連の流れの中でさらに細かく分割できるものはないので、5つのアクティビティより増やす事もありません。(もちろん、ミッションが増えれば当然増えますが)
例にしてしまえば「当たり前のことだよなぁ」という感じのことですよね。
ハイ!「当たり前」になりました、やりましたね!
前回の「入門記8:Buriを使う為に必要なマインド(version 0.1.0)」に付け加える形で、以上のイメージがあるとまたぐっとBuriに近づけるのではないかと思っています。(突っ込みがなければ><
入門記11:動かしてみ・・・ようと思ったけど挫折。
今回は凄く長いです。
なぜならコードがいっぱいなので。
And-Split、And-Joinを使ってみましたが、これを既存の手法で実装するとどうなるか?にトライしてみます。(ぶり脳に侵される前にこういう事をしておかないと、ぶり脳になってしまった後でこういうコードを書こうとするとジンマシンが出る身体になるとかならないとか)
仕様を整理すると・・・
- 文書を登録できる
- 登録された文書は公開される
- 公開中の文書が公開を終える際、印刷指示を受けてから公開を終了する
- 印刷指示をされた文書は、印刷をされて、かつそれが確認されたら公開終了
ありそうでなさそうな感じですね。
これを「Buri使用禁止」というルールで同じようにしようとすると。。。
まずDto。
@Bean(table="OldDocument") public class OldDocumentDto { /** * S2DaoのIDアノテーション。 */ public static final String id_ID = "sequence, sequenceName=documentID"; private long id; private String title; private String content; private int docStatus; private int printStatus; private int deleteFlag; private Date createDate; private String createUser; private Date updateDate; private String updateUser; /** * コンストラクタ。 */ public OldDocumentDto() { ; } /** * コンストラクタ。 * <p> * doStatusとprintStatusはそれぞれ初期値で生成される。 * </p> * @param title * @param content */ public OldDocumentDto(String title, String content) { this.title = title; this.content = content; this.docStatus = 0; this.printStatus = 0; } // toString()メソッド割愛 // setter/getter割愛 }
以前使っていたサンプルと異なり、いくつかプロパティを増やしています。
文書のステータス、印刷のステータス、削除フラグ、レコードの登録日と登録ユーザ、更新日と更新ユーザ。業務システム開発の現場で見られるテッパンな構成なのではないか、と思います。
続いてDao。
@S2Dao(bean=OldDocumentDto.class) public interface OldDocumentDao { @Query(value = "id=?") OldDocumentDto selectById(long id); List<OldDocumentDto> selectAll(); List<OldDocumentDto> selectByDocStatus(int docStatus); List<OldDocumentDto> selectByPrintStatus(int printStatus); long selectAllCount(); void insert(OldDocumentDto oldDocument); void update(OldDocumentDto oldDocument); @Query(value = "id=?") void deleteById(long id); }
検索系のメソッドが多くなりました。
そして、Service(Seasar2 Containerの使用を前提としてインターフェイスだけ。。。)
public interface OldDocManageService { public void regist(String title, String content); public void releaseDocument(OldDocumentDto doc); public void closeDocument(OldDocumentDto doc); public void printDocument(long id); public void printExecute(long id); }
そして最後にServiceの実装。
public class OldDocManageServiceImpl implements OldDocManageService { private OldDocumentDao dao; public OldDocManageServiceImpl() { } @Override public void closeDocument(OldDocumentDto doc) { // TODO Auto-generated method stub } @Override public void printDocument(long id) { // TODO Auto-generated method stub // ここまで書いてクラスを消すw
激しくめんどい><