システム開発で思うところ

Javaで主にシステム開発をしながら思うところをツラツラを綴る。主に自分向けのメモ。EE関連の情報が少なく自分自身がそういう情報があったら良いなぁということで他の人の参考になれば幸い

JSF(ManagedBean)

作成単位

コンポーネント単位(呼出元となるxhtml単位)。
またはユースケース単位(呼出元となるxhtmlが複数にまたがるケース)

個人的なこだわり

少し調べて見ると「ManagedBeanは画面単位で作成します」という表現を見かけることがある。
多くの場合、画面におけるメインコンテンツが1つ(1面?)となる場合はコンポーネント=画面になるので画面単位という整理で基本的に問題ないとは思っているが、その整理だとテンプレートやコンポーネントを組み合わせて構築するJSFコンポーネント指向という仕組みとピタッと一致した感じが無いように思う。

ユースケース単位というのは「一画面で実現出来うるオペレーションだけれども、ユーザビリティを考えると複数画面に分割した方が良いケース」を意図している。 ウィザード操作のように一連の操作が単純で会話型で進められるようなものは、xhtml単位でManagedBeanを作成すると資産が増えすぎてしまう。増える事自体が悪いというつもりはないけれど操作の順序性など必要以上に発散させるのも良くないと考える。この場合は「一連の操作」の目的単位でManagedBeanを作成することで操作の見通しが良くなると考える。


遷移時の情報共有は@ConversationScoped

画面遷移時の情報共有というか受け渡しにはFlash*1という仕組みもあるけれど、それは使わない。

個人的なこだわり

同一フロー(もしくは会話)内の情報の生存期間を管理する仕組みを統一しておきたい。ちょっとした受け渡しだからFlashで、といった場合の「ちょっとした」が、本当に「ちょっとした」で終わる保証がどこにも無いから。改修があった場合、多くのケースでは既存の仕組みを残して対応をしたくなる。例えば、始めは画面1から画面2への単純な遷移、かもしれないけれど、もし画面2から画面1に戻ったり(加えて画面2の状態を画面1に反映させたり)という要件が発生した場合、結構しんどくなることが想定される。いやいや、そんな、、と思うところはあるけれどSIerの現場だと聖域を犯すべからずという感じで起こりやすい。ちゃんと仕組みも含めて会話が出来ることを永劫に保証できるというのであれば問題ないと思う。
複数画面を跨る情報は会話スコープのBeanに格納して読み出すという整理であれば、上述のケースが発生しても問題なく対応できる。

なおFlashはダメという話ではない。基底となるFWは極力「何でも出来る」が望ましいと思っている。その上で利用局面を考えて、それぞれの利用者として制約を設けて品質を担保するのが良いという話。


リンク

JSFにおけるPostback、そしてライフサイクル - 理系学生日記

会話スコープとAjax - じゃばらの手記

*1: FacesContext.getCurrentInstance().getExternalContext().getFlash()

JSF(Form)

アイディアメモ(随時更新)

ViewForm

@Label

  • 独自のアノテーション@Labelはメッセージ出力時の対象項目名として使用する
  • 表示名は表示にのみ使用するものでありドメインでは無いと考えた
  • 表示名はResourceで管理する
  • クラスパスと同じフォルダ構成でファイルを作成する
  • ファイル名はクラス名と同じにする
  • aptコンパイル時にResourceが存在しない場合は警告を標準出力する(エラーにはしない)
  • Resourceが存在しない場合は表示ラベルとしては、フィールド名をそのまま出力する
  • デフォルトは同構造のパスに格納したものを使用するが、任意の文字列の指定も可能とする*2
    任意の指定をしている場合はResourceを使用しないので警告出力はしない。

画面表示アイテム

  • 固定文字はResourceで管理する。
  • Resourceコンポーネント単位で作成するか、Resourceのキーに画面名を付与してシステムで1つにする。JSFの仕組みで入力補完対象になることを考えたら1つにする方が良い。*3

*1:JavaScriptHTML5でプリミティブ型について、ある程度対応が出来ることは分かっているが、どこで正しくデータを保証するのか?というのを考えた結論として、クライアント(ブラウザ)ではなく、あくまでサーバーサイドで きちんと保証するのが正しいと考えた

*2:Resourceの恩恵は受けられないが、使い捨てシステムの場合には この仕組みを設けておくことで開発が楽にできる。

*3:悩みどころ。移植性を考えたらコンポーネント単位で作成になるけど、細かい資産が増えすぎることと、Resourceが多い事を嫌がる人がそこそこいるような気がする

CDIのメモ

全般

JavaEE7をはじめよう(13) - インジェクション候補が複数ある場合の対処方法 - エンタープライズギークス (Enterprise Geeks)

CDI(Contexts and Dependency Injection)まとめ - A Memorandum

なるほど!ザ・Weld | Exploring CDI extensions

@n_agetsu

パーフェクトJavaEECDIパートの著者でもあります。実際に何度か勉強会で話は聞かせていただいたこともあります。とにかく分かりやすいし聞きやすいです。

www.slideshare.net

www.slideshare.net

n-agetsuma.hatenablog.com

Java EE環境におけるCDIのデフォルト化 - 見習いプログラミング日記

CDIとiBATIS2.3を組み合わせる - 見習いプログラミング日記

CDIでアプリケーション設定をインジェクション - 見習いプログラミング日記

インジェクト

コンストラクタインジェクトをつかう

DIコンテナのインジェクション方法の使い分けについて - 日々常々

パーフェクトJavaEE:P47

@xxScopedには@Typedを忘れずに

パーフェクトJavaEE:P49

依存の注入ポイントとなる型(Interface)を明言した方が良さそう。Interfaceと実装が1対1であれば必ず限定できるけど、それだと何のためにDI使っているのか、という話になってしまう。また同じく複数の型(Interfaceや抽象クラス)から具象化されるクラスが意図せず1つという状態になるのも良くない。少なくともScopeを限定している具象クラスにおいては論理的に1対1しておいた方が良い。

なおテストを考えても@Typedを使った方が良い。

CDIでコンストラクタインジェクションしたい - CLOVER🍀

もう少し詳細な情報や使い方

Java EE 7 CDIを使う際の注意点──『Java EE 7徹底入門』番外編 第2回 - page2 - builder by ZDNet Japan

CDIビーンを動的に取得する - ksino's diary

CDIビーンを動的に取得するコードの単体テスト - ksino's diary

BeanManagerでCDIコンテナにアクセスする | なるほど!ザ・Weld

Java Examples for javax.enterprise.inject.spi.CDI

Java EEのCDIで定義しておくと便利なプロデューサーとインターセプタ - きしだのはてな

Java EEアプリケーションで起動時になにかしらの処理をする方法 — 裏紙

JavaSE環境

依存ライブラリが極力少ない方が良いと思うけど、CDIは使った方が良いと思う。JavaEEだけじゃなくてJavaSEでも。

JavaSE 環境でCDI(Weld)を使う - Qiita

JPAのメモ

全般

Java EE 8がそろそろ固まってきたのでJPA 2.2のJavaDocを日本語に翻訳し始めた(2/3完了) - 水まんじゅう2

JavaEE使い方メモ(JPA その1 - 基本) - Qiita

Red Hat JBoss Web Server 1.0 Hibernate Entity Manager リファレンスガイド - Red Hat Customer Portal *1

JavaEE Code探索 その3 〜 トランザクション属性 〜 - A Memorandum

JPA2.1でエンティティからインデックスを自動生成する - 水まんじゅう2

spring-data-jpa アンチパターン - Qiita

はじめてのJPAでちょっと怖い勘違い - ビールとプリンとプログラミング。

JavaEE7をはじめよう(9) - JPA TIPS - エンタープライズギークス (Enterprise Geeks)

EntityManager

JavaEE7をはじめよう(14) - Producerの効果的な利用方法 - エンタープライズギークス (Enterprise Geeks)

複数のEntityManagerを切り替える(on CDI) - edgegram

JAX-RS(Jersey)とJPAのサンプルにCDIを使ってTomcatで動かす - Qiita

JPAとJTAをJavaSE環境で使えるようにする: すふぃあの記憶

@RequestScopedにする。

トランザクション

JavaEE使い方メモ(JTA) - Qiita

Jerseyでリソースメソッドをトランザクション境界にする — 裏紙

大量処理

JPAで少しずつデータを処理する方法を考える - 見習いプログラミング日記

メモリを逼迫させずにJPAで大量データを取得する方法 - エンタープライズギークス (Enterprise Geeks)

Native Query

JavaEE7をはじめよう(5) - JPAクエリ(その2) Native Query - エンタープライズギークス (Enterprise Geeks)

SQL文を外部ファイルに | 老いぼれSEの艱難辛苦

Builderパターン

JPA Builder パターン

トランザクション

[Spring] 宣言的トランザクションがネストした時はどうする!? REQUIRES_NEWを使ってみた | DevelopersIO

わかりやすい JPA(12)楽観的ロックと悲観的ロック

作りたい共通部品

  • Listインターフェースを良い感じにパラメータとして設定できるようにする
    (とりあえず、数値と文字列だけ)
  • Listが空の場合はnullin()にならないようにする)*2
  • SQLの参照はパッケージをフォルダにする*3
  • JPABuilderをEntityの情報からAnnotationProcessorで自動生成
  • JPAの型情報からフィールド毎のBeanValidationをAnnotationProcessorで自動生成
    全体でフィールド名が重複している場合はエンティティ名を接頭文字につける。
    同じドメインにしたい場合は、アノテーションドメイン名を指定。重複している場合は「マージ」
    必須(NotNull)は対象外(集約であるEntityにとって必須という扱いと考えるから)
  • Eneityクラスからテーブル定義的(とりあえずhtml)なものをAnnotiontionProcessorで自動生成。
    (重複しているドメインがある場合、備考にその旨を追記すると後々ありがたい機能になる気がする。)

note

  • SQLファイル読み込みの仕組みはorm.xmlがあるけど使わない(リンクはメモ)。

その他

Spring Data JDBC Preview - Qiita

*1:仕様に目を通すのは大事

*2:Domaの2waySQLを参考

*3:Doma方式を参考

Presentationのスコープについて

Presentation層におけるスコープについて

@ConversationScoped

画面操作に関するスコープとして、また その考察

実装イメージ

  • 開始ポイントを必ずindex.xhtmlにする。
  • ファイル名を除くフォルダパスが変更されるタイミングを@ConversationScopedの開始・終了の境界にする。
  • フォルダ名を宛先(index.xhtmlは省略可能。SAStruts風?)
  • 同一会話内の画面遷移はxhtml名だけで遷移する。.xhtmlの省略不可。
  • 会話開始前にindex.xhtml以外のパスにアクセスをしようとしたら、同一フォルダのindex.xhtmlフォワードする。
  • 画面遷移はリダイレクトするようにInterseptor?faces-redirect=true";を付与する。同一画面遷移(return null)の場合は、自画面パスを取得して対応する
  • サブフォルダも親フォルダの会話範囲にする*1

考察

@ViewScopedJSF依存)は使わない

  • フォルダパスが変わらない=同一画面ということになるので、会話の開始・終了のタイミングは問題なさそう。
  • クライアントに情報を持たないので通信量が少なくて良さそう。

@FlowScopedJSF依存)は使わない

  • 同一会話を同一フォルダまたは子フォルダで表現すれば求めている要件は満たしている。
  • @FlowScopedと違って遷移フローのためのクラスとかXMLを作成しなくていいので分かりやすくなりそう。
  • jarにして部品化することは出来なくなる可能性大?。部品化する場合、仕組みを含めて全て取り込まないといけないことになるのでサイズが大きくなってしまう?。

会話の開始は どうやって?

タイミング

画面初期表示

なぜ

遷移の終了フェーズで開始をしないと、前回の会話をそのまま引き継いでしまう。

Interseptorで実現しようとしたけれど、終了から開始までにフェーズが変わっていないため、前回の会話スコープIDを そのまま引き継いでしまって想定していた挙動が実現できなかった。

どうやって

viewActionで実装。
共通的に扱えるようにするためにテンプレートを使用すればボイラーな実装はしなくてよくなる。

JSF 2.2ではf:eventのpreRenderViewではなくf:viewActionを使う? - DENの思うこと

会話の終了は どうやって?

タイミング

Interseptor

なぜ

処理前後のURLで終了判定をしたいため、処理前後のURLを把握できる場所がInterseptorだから。

また、終了時点で、次の画面に遷移する前に確実に終了させておきたい。

どうやって

処理前の画面URLと処理後のURLのフォルダが異なる場合は会話を終了させる。

画面遷移のルール

遷移というか、パス指定のルールはSAStrutsを参考にしようかと思っています。

随分、昔の話にはなりますが、SAStrutsをやって、EEを見たときに「ほとんど同じじゃない?」と思ったということもあって、親和性がある気がしている。

全く同じにする、というつもりはないけれど、基本的な考え方については色々と参考にしようかな。

Super Agile Struts - Tutorial

フォルダで会話スコープの実装例

2018/5/3 追記
イメージしていることの お試し実装をしてみました。

vermeer.hatenablog.jp

@RequestScoped

単純な参照のみの画面の事を考えて@RequestScopedは残す。

実装イメージ(悩み中)

StatelessViewの強制

Stateless Viewの制御を@RequestScopedを使用した場合に強制的に行うようにInterseptorで対応。

閲覧のみのコントローラーですよ、ということが分かるようにする工夫が必要かな。

@ApplicationScoped

ユーティリティクラス(悩み中)

ユーティリティクラスをInject対象にする状態が、すでに良くない気がしている。でもテスト容易性のためにstaticクラスにしないで、ということはあるかもしれないので、一応想定はしておく。

@SessionScoped

ユーザー情報

  • ログイン以降のユーザーの状態。
  • 認証・認可

ゲストユーザー情報

  • ログインする前の状態保持。ショッピングカート的な仕組みだと必要かも。

*1:2017/8/6 追記:スコープが広すぎるので対象外にするべき?

JJUG ナイトセミナー 「Java O/Rマッパー特集」に参加してきました #jjug

まとめ

【東京】JJUG ナイトセミナー 「Java O/Rマッパー特集」 7/26(水)開催 #jjug - Togetterまとめ

スライド

speakerdeck.com

Doma

www.slideshare.net

www.slideshare.net

スライド(関連)

speakerdeck.com

www.slideshare.net

感想

私が使用しているのはJPAで、話を聞いたうえでJPAで良いかな、と思った。

理由

JPQLとかORMらしさに拘っていない

基底となる技術要素がRDBである以上、実行SQLから目を背けることは出来ないということから、私は割と気軽にNativeQueryを使っている。標準SQLに限ればDB製品依存も言うほど気にしなくて良いと思っている*1
ただコード内で直接文字列操作をするのは好きではないというのと、SQLの確認のやり易さということでSQLファイルを読み込む共通部品は作った。今は、フラットに格納しているけれどDomaのようにパッケージに準じたフォルダで格納するというのは良さそうだから、今後、改修しよう。

テーブルにEntityクラスが1対1にも拘らない

@ReadOnlyをつけたEntityDTOとして参照のためだけに作ってDomaみたいにフラットな結果を後からゴニョゴニョしている。

キャッシュをあてにしない

キャッシュというかEntityManagerが原因で困ることが割とあるので、あてにしない仕組みにしておいた方が無難と思う。例えばflushはちゃんとコールするとか、selectはDBから最新のものを取ってくるようにするとか、そういうこと。

標準だから

JavaEE標準の看板は選定理由として大きい。思考停止していると言われたら その通りだと思う。ORMに対してトランザクションとクラスマッピングの基本的な仕組みしか求めていない私には何かしらルールと実装があれば良いので「標準」は訴求力になる。

あえて「好み」をいうと…

S2JDBCは良かった。2 way SQLが便利だった印象があるので。なので 今回、話を聞いてDomaが良さそうと思った*2
ただJPAを止めてまで、aptベースの仕組みを導入するか?というと難しいかなぁ。apt自体は理解をすると決して尻込みをするような技術ではないし、実際に動くコードが見られるので むしろ安心感すらあるんだけれど、分かってもらうためのハードルが高いかも。apt自体がもっと使いやすくなれば良いんですけどね。
ということもあって、今のところDomaを使うよりもJPAを便利に使えるための仕組みの精錬を優先しようかと思った結果『JPAで良いかな』という結論に至った次第。

*1:実際に移植しているわけではないので困った経験はないけれど

*2:以前、aptの教材・参考としてDomaのコードをみたけれど、ORMとしては既にJPAを使っていた&一通り仕組み作りまでしてしまっていたのでスルーしていたので、今回、話を聞けて良かった。

PaaS

PaaSに関するブックマークとメモ

外部サービスなどを考えるのであれば、PaaSが良いと思う。理由は運用コスト。ローカル環境や社内環境だと自分でカスタマイズできる自由度に惹かれるけれど、時間は有限なので何かしらのトレードオフは必要。ということで、外部・内部に関係なく、サービスを検討する場合には、まず「これはPaaS上でも動くものなのかな?」というところをスタート地点にするのが良いと考えた。 *1

なんて言っているが実際には全く手を付けていない。。情報収集をしては、その情報がどこかにいったりして毎回調べ直し。 ということで、無くさない場所に必要になりそうな情報のメモを残す。

コミュニティ

https://paas.connpass.com

スライド

www.slideshare.net

Cloud Foundry

PaaSをローカル環境で試せる。ただ、私の環境では貧弱すぎる可能性大。

自宅 Cloud Foundry環境を構築する : まだプログラマーですが何か?

GitHub - Pivotal-Japan/cf-workshop: Cloud Foundry Workshop

Bulemix

Bluemixが良いと思うところは、ベースがCloudFoundryだということ。移植性が高そう。また、小さい規模であれば、ずっと無料枠が使えるみたいなところ。

使い方

IBM Bluemix DevOps Services 概要

IBM developerWorks 日本語版 : Cloud computing : Learn

www.slideshare.net

www.slideshare.net

BluemixでJava 8を使う(on Liberty Runtime & DevOps Service)

Java EE

IBM Cloud ライト・アカウント&Java EEアプリのデプロイ #IBMCloud #jjug_ccc - Challenge Java EE !

無料枠

クラウドサービスIBM Bluemixを無料で使うノウハウまとめ

Google Apps Engine

PaaS当初の感動とは別に、癖が強そうということなどもあり、今のところ選定対象から外すことにした。

その他

今のところ、無料枠がネックになって選定外。

*1:GAEが世に出た時には感動に近いものがあったなぁ。