ペーペープログラマの日記

ぺーぺーなプログラマが思ったことを書く日記です。

カプセル化はどんなときも必要か

2005-07-11 23:34:29 | Weblog
44さんは、カプセル化に相当こだわっているようですが、果たして本当にどんなときでもカプセル化を行わなければならないんでしょうか?
カプセル化すべき情報とは他のクラスは知る必要のない情報です。
たとえば同じく44さんがあげていた
http://www.atmarkit.co.jp/fdotnet/bookpreview/codecomp2nd_06/codecomp2nd_06_01.html
のattributeなんかは確かに隠蔽すべき情報です。

しかし、同じく44さんが例として出した社員の給与計算を行うのに必要な情報ははたして隠蔽すべき情報でしょうか?
たとえば、役職とか基本給とか残業時間とかですが、これらは明らかに社員クラス内だけに閉じていればいい情報ではないです。
給与計算に必要な情報で社員だけが知ってる情報なんてあるでしょうか?(いや、ない)
したがってこの例ではカプセル化できないし、またする必要もありません。

なぜリッチなどメインモデルに憧れを持つようになるか

2005-07-11 23:14:56 | Weblog
 いや、自分も実を言うとなぜリッチなドメインモデルに憧れを持ってる方なんですが、
やっぱりね、GoF本とか読んでデザインパターンとかに目覚めちゃうと、
やっぱり、自分でも使いたくなるじゃないですか。
金槌を持つとすべてのものが釘に見えてくる状態というか。

 でも、業務アプリケーション作ってる限り、デザインパターンなんてほとんど出番ないんじゃないかな。
業務アプリケーションのフレームワーク作ってるんなら別なんでしょうけど。


「データと振る舞いを分離する手法」はトランザクションスクリプトか

2005-05-10 02:36:59 | Weblog
賢いデータは必要なのかのコメントから
yusukeさんのおっしゃるデータと振舞の分離は、マーチン・ファウラーの言うところの「Transaction Script」パターン

て書いてあるけど、ほんとうにそうなのかな。別にデータと振舞の分離したからって「Transaction Script」パターンになるって事はないと思うんだけど。
というか、「Transaction Script」パターンは
ドメインロジックとSQLを参考にして書いてるんだけど、ここの「Transaction Script」パターンはひどすぎる。
百害あって一理なしです。別にデータと振舞の分離したからってこんなひどいことにはならないよ。
SQL内にロジック(Logic in SQL)パターンを使う事だって出来るんだし。

しかし、じぶんの感覚からするとここの例でのドメインモデル(Domain Model)パターンはなんかやな感じがする。
だって割引の適用なんてホットスポット中のホットスポットですよ。それをCustomerクラスに埋め込むなんて信じられません。割引の種類なんてあとからあとから増えていくにきまってます。そのたびにCustomerクラスにメソッドを追加するのでしょうか、細かい変更(たとえばタリスカーを5000ドル以上から2500ドル以上に変更)なんてでしょっちゅうでしょうがそのたびにCustomerクラスに手を加えなきゃいけないんですか?

自分ならDiscountManagerとか作ってそっちに処理をまわしてしまうけどな。

賢いデータは必要なのか

2005-05-10 01:37:14 | Weblog
 そりゃ、「賢いデータは必要なのか」ってきかれたら必要と答えるしかないわけですが。
まあ早い話ケースバイケースとしか言いようがないわけで。
でも、今までの経験から行くと「データに振る舞いを持たせすぎ」て困ることは合っても「データと振る舞いを分離しすぎ」(いわゆるドメインモデル貧血症)で困ったことってあんまりないんですよね。

 たとえば、ひがさんの日記や2chで出てくる44氏の例は明らかに「データに振る舞いを持たせすぎ」だとおもう(もっというとクラスに役割持もたせすぎ)。これはべつにオブジェクト指向か手続き型かとかじゃなくてふつうにオブジェクト指向で設計してもこうはならないよね。

public class Employee {
  private PayCaluculator calculator;
  ...
  public BigDecimal caluculatePay() {
    return calculator.calculatePay(this);
  }
}

だって現実問題、社員は自分の給料計算しないし。
まあ理由はhttp://pc8.2ch.net/test/read.cgi/tech/1102862221/172に書いたとおりなんだけど。

1.社員の情報だけじゃ給与計算なんて出来ん
勤怠情報とか、税金とか、手当てとか、あと成果主義の会社だったら
会社の業績とかが給与計算に必要なわけで、calculatePayを社員にもたすと
社員とその他もろもろのあいだに依存関係が出来る。
2.calculatePayを社員にもたすと給与計算の変更があるたびに社員クラスを変更しなければならない
そのときに社員クラスにバグを作りこまないという保証がない。
3.calculatePayは月給を計算するんだとして、ボーナスはどうするのか、出張旅費清算はどうするのか?
社員クラスにcalculateボーナスメソッドを持たすとして、会社の制度が変更になってボーナスがなくなったらどうすんの?

そしたらYAGNIだっていわれちゃった。でもドメインモデルを使う利点って変更に強いことなんじゃないの?
給与計算なんて超ホットスポットなんだからもうちょっと変更に強く作ってないと困ります。
自分ならこうするかな。
public class Employee {
getterとかsetterとか
}
public interface PayCaluculator{
  public BigDecimal caluculatePay(Employee employee) {
}

でここでデータと振る舞いを分離してるけどこれでオブジェクト指向の利点が得られなくなったかというとそんなことはなくて、たとえば会社に従業員、契約社員、管理者がいてそれぞれ給与計算の方法が違うとしたら、
public class Employee {
getterとかsetterとか
 public EmployeeType getEmployeeType();
}
public interface PayCaluculator{
  public BigDecimal caluculatePay(Employee employee);
}
public class PayCaluculatorImpl implements PayCaluculator{
  private Map payCaluculators = new HashMap();
  public void addPayCaluculator(EmployeeType employeeType,PayCaluculator payCaluculator) {
     payCaluculators.put(employeeType,payCaluculator);
  }
  public BigDecimal caluculatePay(Employee employee){
    PayCaluculator payCaluculator = 
      (PayCaluculator) payCaluculators.get(employee.getEmployeeType());
    return payCaluculator.caluculatePay(employee);
  }
}
public class 従業員PayCaluculatorImpl implements PayCaluculator{
 .....
}

とかしてDIすればオブジェクト指向の利点を十分利用できるわけです。しかも、たとえば給与計算するのにたとえば部門の情報が必要になってもEmployeeには一切手を加える必要はないですし。ボーナスの計算でも新しいPayCaluculatorの実装をつくるだけです。

あと
http://www.atmarkit.co.jp/fdotnet/bookpreview/codecomp2nd_06/codecomp2nd_06_01.html
の例なんだけど、これって「データに振る舞いを持たせる」って言っていいのか?
ほとんどsetterとgetterのみのJavaBeansのように感じるんですが。

もちろん上で言ったことはケースバイケースなわけで、たとえば誕生日と現在の日時から現在の年齢を計算するgetAge()なんてメソッドはもちろんEmployeeに入れるべきでしょう。

まあ結局何が言いたいかというと「データと振る舞いを分離しすぎ」なことに注意するべきなのと同様に、「データに振る舞いを持たせすぎ」にも注意が必要って事で。だとすると「データに振る舞いを持たせすぎ」なことにドメインモデル貧血症というなまえがついているように「データに振る舞いを持たせすぎ」なことにも名前を付けるべきじゃないでしょうか。ドメインモデル白血病とかかな。ちょっと不謹慎な気がしますが。なんかいい名前ないですかね。

ええーと、一応自分の立場をはっきりしておきますと

2005-02-25 01:22:34 | Weblog
べつにDIまんせー、なんでもかんでもDIだっていうわけじゃないですよ。
というより、仕事でDI使っている身としてはこういう場合はDI使ったらまずいとか
DIはここがだめだっていう(DIを使ってみての)具体的な情報はのどからでが出るほどほしいところです。

でも、DIに対する批判をいくつか見てみたけど、そういう有益な情報はほとんどないんですよね。

あと一応仕事でも趣味でもRuby使ってます。

DIなんてフツーのJavaプログラマには理解できっこない?

2005-02-24 21:37:40 | Weblog
DIなんてフツーのJavaプログラマには理解できっこないをよんで
結局この人のいいたいことはなんなんだろう。

1.最近(という訳でもないが)色んなところでDIがもてはやされてるけど,世の中のプロのJavaプログラマの大半にはEJBはもちろんDIすら理解できない(だからDIなんてだめ)

 それを言うならオブジェクト指向自体理解している人はほどんどいない(なぜならDI⊂オブジェクト指向だから、DIすら理解できないならオブジェクト指向なんて理解してるわけがない)。
だからってオブジェクト指向がだめだというのはちょっと違うと思うんですけど。
ていうか、DIのありがたみってある程度大きなプログラムを自分で設計した人じゃないとわからないと思うので、自分で設計できるレベルに達していない人が理解できないのは当然じゃないんでしょうか。

2.分かってる人達が「これはいいね」「今度こそいいパラダイムだ」とか言って満足してるだけ.(そんなのただの自己満足だ。DIまんせーな人は現場がわかっていない)

 うーん。DIってそんなに難しい概念なんでしょうか?
自分が会社でDI紹介したときはすぐにその利点をわかってもらえたけどな。
最悪DIすらもわからないようなへぼプログラマがプロジェクトにいたとして設計する人がDIを理解していればすむことだと思うのですが?

3.世の中のプロのJavaプログラマの大半にはEJBはもちろんDIすら理解できない.体感的には理解できてる奴なんて10%もいない.(Javaプログラマなんて馬鹿ばっかりだ)

 うちのプロジェクトはそれなりに経験つんだ人が多いのでそんなことないけど、いろいろ話し聞くとそういう人も多いみたいですね。でもそれってDIと関係ないんじゃ?

4.っつーかEJBとかDIに限らずJavaにまつわる2,3,4文字略語系の技術は軒並みそうだ.きっとそうだ.あんなの趣味プログラマでもない限り理解できる訳がない.(Javaなんてうんこだ)

 まあJava関連の技術の中にはうんこみたいなものがおおいのは認めますけど。だからってDIがだめって決め付けるのはどうなんだろ。だいいちDIってJava特有の技術じゃないわけだし。
Ruby関係の人って他の言語の悪口よく言いますよね。そこがなんかはなについていやになるんですけど。あんまりそういうこといわないほうがRubyにとってもいいんじゃないかな?

 結局、DIがだめなのか、DIまんせーな人がだめなのか、Javaプログラマがだめなのか、Javaがだめなのかそれとも全部だめなのか良くわかりませんでした。

interfaceは本当に「仕様」と「実装」を分離してくれるのか?

2005-02-07 23:15:17 | Weblog
interfaceは本当に「仕様」と「実装」を分離してくれるのか?

rubyのMix-in確かに便利ですが、この例はどうなんだろ。
これじゃいけないのか?
public interface Template {
  public void setUp();
  public void doSomething();
  public void tearDown();
  public void execute();
}
abstract class AbstractTemplate {
  public void execute() {
    setUp();
    doSomething();
    tearDown();
  }
}
public class TemplateImpl extends AbstractTemplate {
  public void setUp() { ... }
  public void doSomething() { ... }
  public void tearDown() { ... }
  public static void main(String[] args) {
    Template t = new TemplateImpl();
    t.execute();  // setUp(), doSomething(), tearDown()が実行される
  }
}

「ほかのメソッドを順番に呼び出す」ということこそがメソッドexecute()の「仕様」でありとかかれていますが、「仕様」には、メソッドを呼び出す側が必要とする「仕様」と、メソッドを実装する側が必要とする「仕様」があって(外部設計と詳細設計みたいなもんでしょうか)、ここでいう「仕様」ってメソッドを実装する側が必要とする「仕様」ですよね。
interfaceはその名のとおり、メソッドを呼び出す側が必要とする「仕様」しか表せないと思いますが、それで十分な気がするのは俺だけでしょうか?

確かにこの例だとexecute()呼び出してもsetUp(), doSomething(), tearDown()が呼ばれないTemplateの実装が作れてしまうけど、それってそんなに困らないような気がするのは自分だけ?

まあここら辺になると個人の趣味の領域になってしまうのかな。