2014年03月21日

ラムダ禁止じゃなくてラムダ促進を目指してStream APIを考える

今日のJJUGイベントで、Stream APIについて、
@cero_tさんから『ラムダ禁止』でぐぐってみてという話があったのでぐぐった。

ラムダ禁止について本気出して考えてみた - 9つのパターンで見るStream API
これだよね。

Twitterだと書き切れなさそうなので、ブログで書くよ。
あんまり推敲してないから読みにくかったり、おかしい事書いてたら、
生暖かく見守るか、優しく指摘してね。

まず、記事を、1分くらい上から下まで眺めてみたよ。
たぶん、どんどん最新コードを書いていく人にとっては良い記事なんだと思う。

でも、なんて言うか、それ、書く側からの視点に集中しすぎてるんじゃない?と思った。
いやいや、それ以前に、ここに書かれているのって何の例なんだろう。
まぁ、ほとんど読んでいないんだけど(マテ

基本的に、Stream APIは必要があって出来たと思っているんだよね。
だから、Stream APIの使い方が悪くてバグるんだったら、禁止で良いと思う。

もちろん、わたしも禁止なんかしない方が良いと思っているよ。

ただ、記事の下の方に書いてある一覧もラムダ禁止の一種な気がしたりしなかったり。
これだと、使いはじめにくいんじゃないかなぁ。
書いちゃダメというか、書き方はそうじゃない。ってことだと思うの。

理想を言うなら、
  1. どういう理由でStream APIが出来たのか。
  2. なにを実現するためにStream APIが出来たのか。
  3. どういう風にStream APIを適用していくべきなのか。

これを整理しておくことが、利用の促進につなって、ラムダ禁止の抑止になると思う。
整理をしないで、変な書き方スルならその現場はラムダ禁止で良いよ。

たとえば、『Stream API使うとforよりも短いコード行でかけるんだよ!だから使うべきだ!』とか、
『for文は全部Stream APIで置き換えるべきだ!』って言う人はラムダ禁止で良いんじゃないかな!
……そう言うためのAPIじゃない、よ……ね……?( ̄▽ ̄;)

そして、アプリケーションを書くときには、技術要素だけじゃなくて、業務要素を気にしないといけないはず。
業務要素をすっ飛ばして、技術要素に凝った書き方をすると、ラムダ禁止への近道になると思う。

だから、
  1. 技術要素の存在意義を考える。
  2. 業務要素との親和性を考える。
この二つを大事にして、Stream APIとλ式の利用を守っていきたいな。

最終的に、最初にあげた記事みたいにパターンとアンチパターンで埋め尽くされるとしても、
それを掲げるには、もうちょっといろいろ調べていきたいかな。

あ、書き忘れてたけど、
促進をしない現場はいつか禁止になるんじゃないかな。
別に全員が促進する必要は無いと思うけどね。

わたしの現場はわたしが促進するよ。
みんなもガンバレ。

posted by そら at 21:13| Comment(0) | TrackBack(0) | 日記

2011年08月01日

TDD Boot Camp 東京 1.6 に参加してきたよ


詳細は、Togetterとかあるから、見ればいいと思うので、

ここでは、わたしなりの感想というか、意見というか、考え方というか、そういうものを書いておきたい。

読みにくいのはいつものことなので気にしない方向で。



前書き



わたしは、正直、プログラムは素人、っていうか全然コードを評価してもらったことがないレベル。

でも、書きたいものはだいたいすらすら書ける。

書いてる間に、動かさなくても、ある程度のバグは、「あっ」と気づくこともできる。



そうすると、「テストコードなんて必要ないんじゃないの」って思うんだよね。

でも、必要だと言うことがわかってる自分もいるの。

リリース後の変更とかの『命綱』っていわれている部分がそれ。

そんな、必要そうな、必要なさそうな、不安定な気持ちをどうにかしたくて参加したってわけ。




んで、いくつかの観点というか、ごーるに向けてまとめていきたいんだけど、

用語とかはわたしが勝手に頭の中で想像した内容を指しているので、

意味わからなかったらスルーするのが良いと思うよ。




下に書いた順番で進めていくよ。

見てわかるとおり、この記事の目的は、

TDDの本質を知り、広める方法を考えるってことだよ。

と、偉そうに書いてみる。




・TDDでのテストコードは誰のためのもの?

・TDDでのテストコードは何のためのもの?

・テストコードはどの程度書けばいいのか

・テストコードは最初に書かなければならないのか

・TDDと品質保証の関係

・TDDを広めるために



TDDでのテストコードは誰のためのもの?



さぁ、さくさくいこう。長くなっちゃうからね。

Togetterを見ていると出てくるけど、

正統派TDDと検証指向TDDって言うのがあるみたい。

この記事でTDDっていったら正統派TDDの方ってことで。

それは、つまり、テストコードはプロダクトコードを書いている人(開発者)のためのものってこと。



TDDでのテストコードは何のためのもの?



テストコードは開発者が「不安」な部分を書いていくの。

これによって、『安心なコード』の『作成を促進する』ってこと。



ここで注意したいのは、『品質が保証される訳ではない』と言うこと。

でも、『保証はされないけどバグは減る(品質は上がる)』んだよね。

そりゃ、開発者が不安に思うところを検証するんだから当然の結果だよね。



テストコードはどの程度書けばいいのか



TDDでは、不安をテストコードにしようって言ってたよ。

ここでも注意、書き始めるとよくやっちゃうのが『仕様をテストコードにする』こと。

これは、違う。もちろん、やっちゃダメという訳じゃないよ。

ただ、その仕様はほんとに不安に思ってるの?っていうこと。

不安に思っていないなら、ただ、メンテナンスが必要なコードを増やしているだけだからね。

あ、そうそう。不安に思ってないからって、
テストコード書かないでいて、あとで不具合いっぱい出たら、

きっと、自意識過剰ってことだよ(笑)



TDDと品質保証の関係



前にも書いているけど、TDDは品質を保証するものではないんだよね。

「じゃぁ、やらなくても良いの?」という質問には、わたしなら「Yes」と答える。

「やった方が良いの?」という質問には、わたしなら「わからない」と答える。


書くかどうかは、その人のスキルとプロダクトによると思うな。

「簡単」、「難しい」、「作ったら放置」、「作っても長くメンテナンスを続けてバージョンアップする」……。

そんな状況によると思うの。


何度でも書くけど、TDDは品質を保証するものではないの。

品質を保証するのは、別の段階(フェーズ?)でやっているでしょ。

やっていないという場合は、「別に今までもやってないんでしょ」ってことで。


あくまでも、TDDは開発の促進のためにあって、

その結果、変更時にチェック機能を果たす『命綱』が『副産物』として誕生してくるに過ぎない。

その『命綱』も、当然、品質は保証しない。決して、保証しない。無駄ではないけど保証しない。

なので、『TDDのこころ』に、『テストが命綱』って言うのがあったと思ったけど、

わたしは、これは、『TDDのこころ』ではないと思う。


この命綱は、当然、開発者によって太さ(量)とか強度(質)が変わってくる。

決して、万能のツールじゃない。でも、安心はくれるし、助かる確率も高くなる。



TDDを広めるために



2011/07/31のTDDBCでは、Togetterにも書いたけど、

結局、『周囲(主に上)に広めて通す方法まではわからなかった』。

だけど、その後、いろいろ考えてたら、なんか自分は勘違いしているのではないかと思ってきたの。



「偉い人がテストに期待するは、品質の保証である。」

……この通りだったら、TDDの導入は無理に見えるんだよね。

だって、TDDは、品質を保証するものではないから。

バグの数が減る?そうそれは、確かに数値は出ている。

でも、それって保証された数値でも何でもないしね。



そこでもう一歩立ち戻ってみるよ。

TDDは誰が何のためにやるのか。

『開発者』が『安心なコード』の『作成を促進する』ため。

『命綱』は『副産物』。



つまり、「できたテストコード自体が重要だと思うこと」

「テストコードがプロダクトだと思っていること」が間違いじゃないのかと思うの。

もちろん、そうなるかもしれない。でも、そうである必然性はないんじゃないのかな、TDDには。



そう、「テストコードは破棄したって良いと思う」んだ。

言ってれば、ちょっと、紙にメモしたようなものだと思うの。

メモした内容を、電子媒体にして資料として保管するか、ゴミ箱にポイするかは自由でしょ。

メモを禁止されていない限り、TDDもまた禁止されていない。

上に許可なんて求める必要はないんじゃないかな。



あとは、周りに広めるだけ。それこそ『メモしなよ。』と同じ要領だと思うの。

なんか実はすごく簡単じゃない?



重要なことは、TDDは必須ではなく品質を保証しないと言うこと。

そして、それはとても自由だと言うこと。



長くなったけど、何かの気づきになると良いな。

最後まで読んでくれてありがとね。

タグ:TDD
posted by そら at 22:12| Comment(9) | TrackBack(0) | 日記

2010年02月13日

CDIのBeanManagerを使ったBean取得と手動Inject

Weldかどうかに限らず動くはず〜。
基本的なBeanの取得(例外処理は省略)は、
BeanManager bm = InitialContext.doLookup("java:comp/BeanManager");

Bean<?> bean = bm.resolve(bm.getBeans(ClassA.class));
CreationalContext<?> cc = bm.createCreationalContext(bean);
ClassA result = (ClassA)bm.getReference(bean, ClassA.class, cc);

って感じかな〜。
この場合は最後にキャストね。

んで、インスタンスのフィールドのInjectとかを手動でしたいなら、
BeanManager bm = InitialContext.doLookup("java:comp/BeanManager");

@SuppressWarnings("unchecked")
Bean<ClassA> bean = (Bean<ClassA>)bm.resolve(bm.getBeans(ClassA.class));
CreationalContext<ClassA> cc = bm.createCreationalContext(bean);
AnnotatedType<ClassA> at = bm.createAnnotatedType(ClassA.class);
InjectionTarget<ClassA> it = bm.createInjectionTarget(at);
it.inject(targetOject, cc);

って感じかな〜。
この場合は、最初にキャストかな〜。

ClassAとか継承してるとresolveで一意にならないので気をつけないとね。
posted by そら at 12:41 | TrackBack(0) | 日記

Weld(CDI)のInjectの使い方、それは魔法

Weld(CDI)管理下にあれば、例えばフィールドに、
  @Inject
private ClassA hoge;
なんて書くだけでClassAが入る。

でも「ClassAの初期化に特別なことをしたい!」
ってこと、あるよね!え?ない?
……あることにしよう(強引)。
そんなときは、こんなのを用意してみる。

@Qualifier
@Retention(RUNTIME)
@Target({METHOD, PARAMETER, FIELD})
public @interface Marker {
}
で、これを使って、
@Produces @Marker
public ClassA generateClassA() {
    // return ClassA Object;
    return new ClassA();
}
こんな風にすれば、@Marker(ClassA)の生成方法が指定できる。
対応したInject側は、こんな風に。
@Inject @Marker
private ClassA hoge;

つまり、好きなマーカー作って、それのProducesとInjectを作れば、
対応したマーカー間でInjectを自在にコントロールできるのだ!
……言い過ぎかな?(笑)

でもこれで、Userクラスをログインしたやつってことで@LoggedInとか
他にも@UserDatabaseとかが公式のサンプルにあるんだよね。
普通にInject出来ないやつとか、継承関係とかもこれでいけるかな?
他にも方法あるかもだけど。

乱用は良くないけど、適切に使えば可読性向上とか、依存関係の切り離しとか上手く調整できそうね〜。
posted by そら at 00:30 | TrackBack(0) | 日記

2009年12月27日

Weldのセッション復帰時に警告

なんかWeldで警告でるなぁ。

どうやら、セッション復帰時で起きてるみたいだけど……。
詳細調べても、解消は出来なかったのだ。

ServletConversationManager(AbstractConversationManagerのcurrentConversationフィールドに、
ConversationImplを放り込もうとしてるみたいね……。
WeldClassImplのdeclaredFieldsByNameフィールドに対象の値が含まれていないのか……。

う〜ん。いいのかな。とりあえず、最初のページだけ出して再デプロイとかすると出てくる……。
まぁ、確かに対話(Conversation)は開始してなかったし、警告レベルだし、問題はないのかな?
でも、スタックトレースも表示されているし……う〜んう〜ん……。
一応、スタックトレースを張っておいてみる!

2009/12/29追記:スタックトレースの表示行がずれてるモジュール使ってたので修正しました。
続きを読む(StackTrace)
posted by そら at 22:30| Comment(0) | TrackBack(0) | 日記

2009年12月23日

Weldの力

JSFとEJBの管理対象

JSF2.0では、クラスに@javax.faces.bean.ManagedBeanと書くと、そのクラスはJSFさんの管理対象になる。
EJB3.1では、クラスに@Statefulとか@Statelessと書くと、そのクラスはEJBさんの管理対象になる。
って話だったんだけど、Weldさんは、クラスに@Namedって書く。

Weldの特徴

Weldは何をするノカって言うと、基本的に大量のアノテーションの提供とそのProcessorをを提供してるのかな。
それによって、JSF2.0とかEJBをまとめて扱えるのだ。おぉ、なんか便利?
たとえば……、 とにかく、@Namedつけておけば、EL式でも参照できる!
なんかこれだけで、@ManagedBeanの役割が無くなった気がする。
さらに、@Namedついたクラスのフィールドとかに@Injectって書くと、
他のManagedBean、Named、Stateful、Statelessつけたやつを適当に入れてくれる!
むー、@EJBも@ManagedPropertyも要らない予感!

結局Weldって?

たった二つのアノテーションでこの威力。
まだまだいっぱいあるけど、正直使いこなせない気がするわ。
トランザクションとかも、Weld使うと、JTA要らずになりそう。
うーむ、本格的にEJB要らない予感が!!!
まぁ、実際には、JSF2.0とかEJBをさらにまとめて管理してる感じなのかな。
まだEJBにしかない機能もあるみたいだし、JSFのフェーズ概念が無くなる訳じゃないけど
Inject周りは、Weldが便利っぽいね。

Weldの使い方

一応、beans.xmlっていうのをWEB-INFの直下に入れないと有効にならないので注意です。
JavaSE環境でも使えるらしいけどよく知らない。
beans.xmlの中身はこんなかんじ。

<?xml version="1.0" encoding="UTF-8"?>
<beans></beans>
うーむ、簡単だけど、有効にするために大分悩んだ(笑)

まとめ

JavaEE6になって、強力で便利な機能がすごく増えてる。Weldに限らず、JSF2.0とかもね。
正直どれだけ使いこなせるか不安になっちゃう……。
OSGiとかも組み込まれて、GlassFishがAP鯖の標準でそこから他のAP鯖がカスタマイズされて提供されるとか言うウワサもあるけど、
JavaEE6がいろんな組織に承認された以上、基本はマスターしておかないとね!

posted by そら at 12:24| Comment(0) | TrackBack(0) | 日記

EJB3.1の簡単なまとめ

定義

EJB3.1では、クラスに@Statefulとか@Statelessと書くと、そのクラスはEJBさんの管理対象になる。
管理されてるオブジェクトは、管理コンテキスト(管理領域)に置かれる。
JSF2.0とかと同じ感じ。
JSF2.0でやるなら、@Statelessじゃなくて、@Statefulもばんばん使っていきたい。

EJBの良いところ

EJBの良いところは、トランザクション管理が出来るところ!JTAってやつね。
これを有効にするには、鯖の対応と、persistence.xmlでJTA使うってやらないとダメなんだよね。
で、もう一つ!
このStatefulとかのを呼び出す(生成する)のに、呼び出し側のクラス(フィールドとか)で@EJBって指定してあげないといけないんだ。
そうしないと、トランザクション管理が有効にならないのだ。
他の方法で呼び出すとトランザクションが開始されてないって怒られたりするので注意。

……なんか色々制約多いなぁ。
結論:EJBは使いにくい(マテ

posted by そら at 12:01| Comment(1) | TrackBack(0) | 日記

JSF2.0の簡単なまとめ

対象定義

JSF2.0では、クラスに@javax.faces.bean.ManagedBeanと書くと、そのクラスはJSFさんの管理対象になる。
管理されてるオブジェクトは、管理コンテキスト(管理領域)に置かれる。

スコープ定義

ついでに、@ViewScopedとかつけると、それの生存期間が設定できる。
ViewScopedは、同じ画面を見てる間有効ってことね。
画面をリフレッシュする系ではプロパティとかが消えずに残るって感じ。

初期処理定義

@PostConstructをメソッドにつけると、初期処理が設定できるのだ。
画面のプルダウンの選択肢を作ったりとか、ここでやると良いのかな。
ちなみに、@PreDestroyで終了処理ね。一応。

利用

@ManagedBeanがついてると、何がうれしいって、EL式で呼び出せるってところ
#{beanName.propertyName}とか#{beanName.methodName(param)}って感じね。
最初に呼ばれた時点でコンストラクタと@PostConstructが順番に呼ばれるのだ。
ボタンとかの実行時に、値もセットしてくれるし、便利便利。

フェーズ

実際、使ってると、スコープってドコまで有効なの?って思って実際に調べてみた。
JSFはなんかライフサイクルって、リクエストごとに一定のフェーズを自動でまわしてくれる。

1RESTORE_VIEW元画面の復元
2APPLY_REQUEST_VALUES元画面にリクエスト内容を適用(この時点では文字列とかのイメージ)
3PROCESS_VALIDATIONS適用した内容の検証
4UPDATE_MODEL_VALUESモデル更新(ここで文字列とかを変換してObjectにして値が更新されるイメージ)
5INVOKE_APPLICATIONここで処理実行
6RENDER_RESPONSE新しい画面描画
基本的には、5に対応するactionListenerのEL式で呼ばれるメソッドと、6のxhtmlを作れば良いってことね。
で、どうやら、ViewScopedだと、次の画面に行くときのRenderResponseフェーズの直前で、消えるみたい。
当然な気もするけど、なんか最初悩んじゃった。

posted by そら at 11:48| Comment(0) | TrackBack(0) | 日記

2009年10月31日

ManagedPropertyアノテーションでの不具合?

う〜ん。フィールド名の先頭を大文字にすると@ManagedPropertyが動かない……。
EL式とかは大丈夫なんだけどな、先頭小文字だと正常だから、バグかな。

警告: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception
com.sun.faces.mgbean.ManagedBeanCreationException: 管理対象 Bean hoge を作成できません。次の問題が見つかりました:
- 管理対象 Bean hoge にプロパティー Piyo が存在しません。
at com.sun.faces.mgbean.BeanManager.create(BeanManager.java:263)
posted by そら at 19:56| Comment(0) | TrackBack(0) | 日記

2009年10月25日

JSF2.0とJPA2.0の設定

JSF 2.0の設定をしてみる。

基本は、web.xmlにかくだけみたい。WEB-INFの下のやつね。
	<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
url-patternは、faces/*とか*.xhtmlとかかなぁ。 これで、アクセスしたときに、JSF 2.0のライフサイクルに載るようになるんだね。

JPA 2.0の設定をしてみる。

persistence.xmlを書く。web.xmlでの参照設定は何も要らないみたいだよ。
まだネット上には、2.0用のXMLスキーマないみたいだから1.0ので書く。
JTA使うだろうから、以下のような感じ。

	<persistence-unit name="SoraPersistenceUnit" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>SoraDataSource</jta-data-source>
<properties>
<property name="eclipselink.ddl-generation" value="create-tables"/>
<property name="eclipselink.logging.level" value="INFO"/>
</properties>
</persistence-unit>
non-jtaの場合も同じ感じ。
RESOURCE_LOCALの場合の設定URLとかは汎用的にかけるようになってるみたい。
	<persistence-unit name="SoraPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:db2:SORA"/>
<!--
<property name="javax.persistence.jdbc.url" value="jdbc:db2://localhost:50000/SORA"/>
-->
<property name="javax.persistence.jdbc.password" value="Sora's Password"/>
<property name="javax.persistence.jdbc.driver" value="com.ibm.db2.jcc.DB2Driver"/>
<property name="javax.persistence.jdbc.user" value="Sora"/>
</properties>
</persistence-unit>
JavaSEの場合はJTAないからこれ使うようになるんだね。
posted by そら at 12:55| Comment(0) | TrackBack(0) | 日記