ググってもMavenの方法しか出てこないのでメモ。
start.spring.io で作ったbuild.gradleに次を追加するだけ。
ext['thymeleaf.version'] = '3.0.0.RELEASE' ext['thymeleaf-layout-dialect.version'] = '2.0.0'
元ネタはこちらのステファン・ニコルさんのコメント
ググってもMavenの方法しか出てこないのでメモ。
start.spring.io で作ったbuild.gradleに次を追加するだけ。
ext['thymeleaf.version'] = '3.0.0.RELEASE' ext['thymeleaf-layout-dialect.version'] = '2.0.0'
元ネタはこちらのステファン・ニコルさんのコメント
JSUGの勉強会に参加したので、そのメモ。
資料は公開されるだろうから、ここでしか聞けないことを中心にメモ(ツイート)したつもりだが、資料に盛り込まれている可能性は十分にある。なお、資料は以下の通り。
www.slideshare.net
ソフトウェア開発においては契約、法令、明文化されてない商習慣などが分析対象
— ちょもち@Neo4jさわってる (@mike_neck) 2017年3月28日
ビジネスルールをプログラミングで表現したのがドメインロジック
いわゆるウォーターフォール(個人の所感を含む)
ソフトウェアの構成
トランザクションスクリプト = ドメインモデルを構築しない手続きだけを書いたソフトウェア
トランザクションスクリプト型のSpringアプリケーションの構成
ドメイン駆動設計によるSpringアプリケーションの構成
ドメイン駆動でアプリケーションを作ると、各層とは別にドメインモデルの層を用意して、ここをインクリメンタルに成長させていく
enum
)List
や Set
をラップしたオブジェクト(List
や Set
には直接触れさせないで、必要な操作だけを提供する))ソースコードの文書化
具体的なドメインモデルによるSpringアプリケーションの構成
後半のトークセッション
ウォーターフォールでDDDは可能か?
— ちょもち@Neo4jさわってる (@mike_neck) 2017年3月28日
増田さん「ウォーターフォールでもいけるのではないかと思ってる。ただし、伝言ゲームでなくて、お客さんにインタビューして、設計して、実装するのが同じ人であること」
ドメインモデルの用語はどこから取り入れているのかという質問に対して
お客さんのドキュメントからドメインモデルの参考にする
— ちょもち@Neo4jさわってる (@mike_neck) 2017年3月28日
同じく名前についてわたびきさんのエピソード
「クラス名が80文字になるんだがどうすればいいか?」とエリック・エバンスに質問したら「お前、なんで日本語でクラスを作らないんだ」と返された
— ちょもち@Neo4jさわってる (@mike_neck) 2017年3月28日
ロジックの順序について
ドメインモデルには順序依存性がないように作る。順序依存性が必要なものはアプリケーション層(サービス)に書く
— ちょもち@Neo4jさわってる (@mike_neck) 2017年3月28日
既存コードが有る状態でのドメイン駆動の取り込み方 : 少しずつ入れていく
Date and Time APIでの和暦の扱いをちゃんと調べていなかったので、調べた。
なお、以下で用いるコードにおいては次のフォーマッタおよび、タイムゾーンを使った。
final ZoneId tokyo = ZoneId.of("Asia/Tokyo"); final DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendText(ChronoField.ERA) .appendText(ChronoField.YEAR_OF_ERA) .appendLiteral("年") .appendText(ChronoField.MONTH_OF_YEAR) .appendText(ChronoField.DAY_OF_MONTH) .appendLiteral("日") .toFormatter(Locale.JAPAN); final DateTimeFormatter iso = DateTimeFormatter.ISO_DATE;
1.和暦を扱う場合は以下のクラスを使う。
java.time.chrono.JapaneseDate
java.time.chrono.JapaneseEra
2.日付インスタンスの作り方
JapaneseDate#of(JapaneseEra, int, int, int)
あるいは JapaneseDate#of(int, int, int)
を使う。JapaneseDate#now
または JapaneseDate#now(ZoneId)
または JapaneseDate#now(Clock)
を使う。JapaneseDate#from(TemporalAccessor)
を使う。というわけで、試してみましょう。まず、東京の今の日付が欲しい場合は次のようになります。
final JapaneseDate now = JapaneseDate.now(tokyo);
System.out.println(now.format(formatter));
結果
平成29年3月23日
昭和最後の日付近辺
final JapaneseDate showa = JapaneseDate.of(1989, 1, 7); System.out.println(showa.format(formatter)); final JapaneseDate heisei = JapaneseDate.of(1989, 1, 8); System.out.println(heisei.format(formatter));
結果
昭和64年1月7日 平成1年1月8日
明治は6年以前というのがないそうです
try { final JapaneseDate meiji = JapaneseDate.of(1872, 12, 31); System.out.println(meiji.format(formatter)); } catch (Exception e) { System.out.println(e.getClass().getCanonicalName()); System.out.println(e.getMessage()); System.out.println("1872/12/31"); }
結果
java.time.DateTimeException JapaneseDate before Meiji 6 is not supported 1872/12/31
というわけで、明治6年以前は出力されないので、 厳密 にJIS X 0301に対応している模様です。
同様に和暦を変換していきます。
final JapaneseDate h = JapaneseDate.of(平成, 29, 1, 1); System.out.println(h.format(iso)); final JapaneseDate m = JapaneseDate.of(明治, 6, 1, 1); System.out.println(m.format(iso)); try { JapaneseDate.of(明治, 5, 12, 31); } catch (Exception e) { System.out.println(e.getClass().getCanonicalName()); System.out.println(e.getMessage()); System.out.println("明治5年12月31日"); }
結果
2017-01-01 1873-01-01 java.time.DateTimeException JapaneseDate before Meiji 6 is not supported 明治5年12月31日
こちらも難しいことは特に必要なさそうです。
最後に別の型からの変換
final LocalDate ldm = LocalDate.of(1873, 1, 1); System.out.println(JapaneseDate.from(ldm).format(formatter)); try { final LocalDate ldk = LocalDate.of(1872, 12, 31); System.out.println(JapaneseDate.from(ldk).format(formatter)); } catch (Exception e) { System.out.println(e.getClass().getCanonicalName()); System.out.println(e.getMessage()); System.out.println("明治5年12月31日"); }
結果
明治6年1月1日 java.time.DateTimeException JapaneseDate before Meiji 6 is not supported 明治5年12月31日
最後に古の java.util.Date
からの変換ですが、かなり面倒です。もう java.util.Date
使うなと言いたくなるくらいです。
final Date date = new Date(); final Instant instant = date.toInstant(); final ZonedDateTime zonedDateTime = instant.atZone(tokyo); final JapaneseDate japaneseDate = JapaneseDate.from(zonedDateTime); System.out.println(japaneseDate.format(formatter));
結果
平成29年3月23日
API的には JapaneseDate.from(instant)
とやりたくなりますが、ゾーン情報を持たない Instant
は変換できません(。逆もまた然り)。まあ、日付の計算も面倒ですし、 java.util.Date
使うのやめましょう。
「java.util.Date
使うのやめましょう」と書くと、「これだからJava8の使えるサーバーの人間は…」と言われるので、紹介しておくと、これと同じAPIがAndroidでも使えます。threetenbpというプロジェクトがあって、そちらがターゲットバージョン1.6で同じAPI(パッケージは異なる)のものを提供しています。したがってJava8が使えない環境の方はそちらを使うとよいです。
また、ThreeTenABP(Three Ten Android Back Port)というプロジェクトもあるようですが、ソースを見たところクラスの数が異様に少ないので同じAPIが使えるかどうかわかりません。どうやらメモリおよび速さの関係からバイナリファイルの中にゾーンの情報をすべて入れているようなのですが、JapaneseEraとかどうやってるんだろうという印象を持ったりします。
(追記:2017/03/24 1:03)教えてもらいました。ThreeTenABPはThreeTenに依存しているので同じAPIを使えるようです。
おわり
JetBrainsユーザーグループにて「IntelliJとYouTrack」というタイトルにて発表してきましたが、グダグダな発表をしたのでちゃんとまとめた記事を書きます。
JetBrains系IDEでは、標準に付属しているツールを用いることで、スマートに作業ができます。(なお、一部のIDEについてはリポジトリーからインストールしないといけなさそうです(GoglandにはTaskManagementプラグインが付属していないようだった))
Task
を開くTask
に関係のない変更(ちょっと気になった部分のリファクタリングなど)を行った場合は別の Changelist で管理するTask
に取り掛かる場合には開いているファイルなどの情報(Context
)が自動で切り替わるTask
終了と同時にイシュー管理システムのステータスを更新するITS(イシュー管理システム)とIDEを連携させてTask
と Context
を管理できるプラグインです。Task
はイシュー管理システムのチケットに該当する、作業の単位をあらわします。Context
は開いているファイルのカーソルの位置や、プロジェクトツリーの開いているディレクトリー、ツールウィンドウの状態などIDEの状態をあらわします。IDEにておこなう作業(Task
)はITSのチケットに基づいておこなわれ、作業している状態(Context
)が作業に関連づいているような感じです。
特に何も操作をしていなければ、IDE上では Default Task
が選択されており、その Context
は Default Task
に紐付いたコンテクストになっています。
上の画像は Default Task
にて作業をおこなった後の状態です。画像右上のあたりにあるプルダウンが Default Task
となっているのがわかるかと思います。
まず、ITSに登録されているチケットと連動させます。
Tools
> Task & Contexts
> Configure Servers...
からITSのサーバー設定を行います。
リストの左下にある +
ボタンから連携するサーバーの種類を選びます。JIRA/YouTrack/Redmine/Trackなど主要なITSはカバーしています(Backlogはありませんが…)。
サーバーを選択した後、ITSのURL、ログイン用ユーザー名、パスワード、チケット検索用のクエリを入力してサーバーの設定は完了です。
このプラグインの具体的な使い方は後述します。
IDEとVCSを連携させる機能もあります。以下はGitベースでの解説ですが、他のVCSでも同様のことができ(ると思い)ます。
add
は自動的に行われます。IDE内でおこなった変更はすべて add
された状態になります(正確には add
されていないけど、IDEにて add
相当の状態として管理されている)。
commit
は ⌘
+ K
からおこないます。コミットの前にコードインスペクションやリフォーマット、importのオプティマイズなどをおこなえます。push
は ⌘
+ ⇧
+ K
です。fetch
は VCS
> Fetch
、 merge
は右下のブランチからマージするブランチを選んでから Merge
を選びます
上の画像は現在のブランチから新しいブランチを作成する場合
上の画像は origin/master
ブランチを現在のブランチにマージする場合
IDEのVCS連携は普通すぎるのですが、changelistはかなり強力な機能です。この機能によりコミットをより綺麗なものにできます。changelistは変更されたファイルを意味のある単位にまとめた集まりのことです。IDEのコミットはこのchangelist単位で行われます。よく言われる git add .
をしないでファイルを指定して git add
していると思いますが、changelist機能はIDEでその慣例をサポートするための機能です。先程IDE上で行われた変更は add
された状態になると記述しましたが、正確にはchangelistで管理された状態になります。そしてコミットの際にchangelistにあるファイルが add
されてコミットされます。
changelistを使っていくと、よくある関係ない変更がコミットに紛れ込んでしまうようなケースでも、簡単にコミットを綺麗に保つことができます。例えば、現在のチケットとは関係のない部分のちょっとしたリファクタリングをおこなったとしても、その変更を別のchangelistに入れておくことでコミットの中に関係のない変更が紛れ込むのを抑制したりできます。
changelistは左下の方にあるVersion Controlツールのchangelistタブで見ることができます。
changelistにはアクティブなchangelistとアクティブでないchangelistの二つがあります。エディタスペースなどでおこなった変更はすべてアクティブchangelistに加わります。そしてコミットする場合もアクティブchangelistに入っているファイルがコミット対象になります。
現在行っている作業と関係のない変更はすべてアクティブでないchangelistに加えるとよいでしょう。changelist間のファイルはドラッグ&ドロップで移動できます。
アクティブchangelistの切り替えは、changelistを選んでから左のチェックボックスのようなボタンを押すことで切り替えられます。
左にある +
ボタンから新しいchangelistを作ることができます。
ダイアログにはchangelistの名前を入力します。なお、コミットコメントを先に書いておきたい場合は、コメント欄に書いておくこともできます。
以下、JetBrains系IDE(ここではIntelliJ IDEA)とITS(ここではYouTrack)とGit(およびGitHub)を用いたワークフローのサンプルケースを記述します。
Task
を開く現在、次のような未解決のチケットが自分に割り当てられているとします。
Default Task
のコンテクストで Tools
> Task & Contexts
> Open Task
(または ⌥
+ ⇧
+ N
)から上記チケットの中から一つ選びます。
Open Task ダイアログにて次のように設定して、 Task
を開きます。
Context
をクリアする(別の Context
を作ると同意)
Task
を開いた後のIDEの状態。 Context
をクリアすると、今まで開いていたファイルなどがすべて閉じられた状態になります。
もちろん、ITSではチケットの状態が更新されています。
コードを書きます。おこなった変更はすべて先程作成したchangelistに入ります。
ここで Task
と関係のない変更を行います。
この変更は同じコミットに加えたくないので、新しいchangelistを作成して、そちらに移します。
⌘
+ K
からコミットします。
Task
を開く作業の途中ですが、別の変更もしてしまったため、その変更に該当するチケットから Task
を開きます。この際、ブランチ作成元のブランチは現在のブランチでなくmasterを指定しておきます。
新しい Task
に切り替える際に、アクティブchangelistの中身が空の場合はchangelistを削除するか聞かれます。削除してしまってかまわない場合は「Remove」を、削除しない場合は「Cancel」を選びます。
先程、一時的にchangelistに加えておいた変更をドラッグ&ドロップで新しいchangelistに移動させます。
この後にコミットをしておきます。
そして Tools
> Task & Contexts
> Switch Task
(⌥
+ ⇧
+ T
)から最初に作った Task
に切り替えます。
Task
を終了するTools
> Task & Contexts
> Close Active Task
(⌥
+ ⇧
+ W
)から Task
を終了します。
Task
を終了する際にできることは次のことです。
プルリクエストからマージしたいので、ここではITSのステータスを「Waiting Review」に更新するだけにとどめます。
なお、 Task
を終了しても、IDE上では特に変化があるわけではありません。というのも、レビューによってこの後に同じ Context
にて作業をする可能性があるかもしれないからです(と理由を言い切ることもできない…)。
プルリクエストを作っていないので、IDEから作ります。特にキーマップを割り当てていないかぎりプルリクエストの作成はキーマップからはできないので、 ⌘
+ ⇧
+ A
からコマンドを探してプルリクエストを選びます。
titleとdescriptionを入力して「OK」を押してプルリクエストを作成します。
これでプルリクエストが作成されます。
このような形で、JetBrains系のIDEとITSを連携させるとかなりスマートに作業ができます。
おわり