はじめまして。初投稿になります。
GxPの@tesaito-gxpです。
この記事はグロースエクスパートナーズ Advent Calendar 2020の18日目の記事となります。
アドベントカレンダーのテーマが今年の学びを振り返る
とのことでしたが、配属されてからの3年間でようやく他人にお伝えできる位にはApache Wicket
について身についたのかなと思い書き綴っていこうかなと思います。
ここ最近はあまり触れてなかったですが、上半期ではバリバリに使っていたので、それについて書いていこうかと思います。
Apache Wicketについて
Apache Wicket(以下、Wicket)はJavaWebアプリケーションフレームワーク、その中でもユーザインターフェイスに特化したフレームワークになります。基本的にフレームワークというのは、「如何にしてソースコードを書かずに実現するか」を考えられて作られていると思いますが、Wicketの思想というのは全くの逆で「すべてをJavaで実現したい」というフレームワークになります。
もちろん多少の設定ファイル(web.xml)はありますが、Wicketで記載するのはページのテンプレートとしてのHTMLとJavaのソースコードだけになります。
webアプリケーションを作る際は、xmlファイルを書いて、JSPを作成し、サーブレットを用意、フレームワーク用の設定ファイル、プロパティファイルを作って・・・と、開発作業は様々な工程を踏む必要があります。
しかし、Wicketでの開発ではHTMLを用意したら後はひたすらJavaを書くだけになります。GETだのPOSTだのに応じて呼ばれるメソッドではなく、ただクラス定義として記述することができます。
もちろん、一長一短ですが。
Wicketの大きな特徴は以下の通り。
- Javaらしいコードを書ける 先ほども触れたとおり、WicketではJavaを用いてWebアプリケーションを作ることができます。「Javaらしい」となればオブジェクト指向を活用し、継承やカプセル化による部品化が挙げられます。 Wicketではこれらをうまく活用し、継承による画面レイアウトの共通化や、共通部品のクラス化を可能としています。
- Ajaxが統合されている WicketにはAjaxが内包されているので、応答性の良いアプリケーションを容易に作ることができます。
- バックエンドとフロントエンドのデータの結合を実現するModelの提供 WicketではModelという概念を用い、画面とバックエンド側のデータのやりとりを容易に行うことができます。
アトミックデザインについて
アトミックデザインについてはアドベントカレンダー11日目で奥山さんが書いてくださっています。アトミックデザインはUIは小さな構成要素の入れ子の組み合わせという考えを元に、化学のメタファーを用いて階層と粒度を定義した設計手法
- 原子(Atom): 最も小さい粒度の要素
- 分子(molecule): 2つ以上の原子を組み合わせたシンプルなUI要素
- 有機体(organism): 切り離して単体でも機能する分子の集まり
- テンプレート(Templates): いくつかの有機体・分子・原子から成り立っている骨組み
- ページ(Pages): テンプレートに実際のコンテンツを適用したもの
このアトミックデザインというものを知ってから今までやってたことが間違ってたんだなぁ。。。と思い知らされました。
Wicketの話に戻します。
サンプルコード
Wicketで画面をデザインする際に、どうやって実現するのか極々簡単なパターンを2つ書いてみようかと思います。 今回実装するのはブラウザ上に「WicketでLabelを置いたよ」とただ一文表示するという簡素なものを書きます。パターン1:クラスを継承させる
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" xml:lang="ja" lang="ja" dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<!--ここから下は継承したクラスで書くよ-->
<wicket:extend />
</body>
</html>
import org.apache.wicket.markup.html.WebPage;
public abstract class SamplePage1 extends WebPage {
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" xml:lang="ja" lang="ja" dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<wicket:child>
<div wicket:id="sampleLabel" />
</wicket:child>
</body>
</html>
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.model.Model;
public class SamplePage1Impl extends SamplePage1 {
public java:SamplePage1Impl() {
super();
Label sampleLabel = new Label("sampleLabel", Model.of("WicketでLabelを置いたよ"));
this.add(sampleLabel);
}
}
このような感じで、ヘッダー(bodyに書いていますが)などのどのページでも変わらない要素を親クラスで持ちつつ、継承した子クラスで必要な要素を追加することによって機能を実装していきます。
子クラスで様々な機能を追加で実装していくためポリモフィズムを意識して実装を行うことができます。
パターン2:Panelを使用する
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" xml:lang="ja" lang="ja" dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<div>↓ここから下はPanelクラスで書くよ↓</div>
<wicket:panel wicket:id="samplePanel" />
</body>
</html>
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.panel.Panel;
public class SamplePage2 extends WebPage {
public SamplePage2() {
super();
Panel samplePanel = new SamplePanel("samplePanel");
this.add(samplePanel);
}
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" xml:lang="ja" lang="ja" dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<div>
<span wicket:id="sampleLabel" />
</div>
</body>
</html>
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;
public class SamplePanel extends Panel {
public SamplePanel(String componentId) {
super(componentId);
Label sampleLabel = new Label("sampleLabel", Model.of("WicketでLabelを置いたよSample2"));
this.add(sampleLabel);
}
}
こちらの書き方は、アトミックデザインに近いものになります。
新たにPanelというクラスを実装しましたが、アトミックデザインでいうところのテンプレートに該当します。
Panelに様々な要素を置くことで再利用可能なプログラミングを行なうことができます。
(今回はLabelを1つしか置いていませんので分子や有機体という過程を飛ばしてます。)
両パターン簡単に表すとこんな感じになります。
どちらの実装が良いかというのはプロジェクトの指針などがあるので一概には言えませんが、頭の中ではパターン2で考えていたのに・・・完成形はパターン1だったなんてこともありました。
この辺りの考え方を自分の中ではうまくまとめられたのかなと思います。
猛省
私がアトミックデザインというものを知ったのはおそらく1年ちょっと前かと思いますが、これまでもWicketをガンガンに使って画面を作成していました。 もともと既存システムの保守ということもあり過去の書き方を参考に・・・ということもあったんですが、上記の2パターンを混合して使っておりました。 「パターン1でもパターン2でも再利用できるもの書けるじゃん!どっちでもいいじゃん!!」そんな風に思っていたわけです。その結果、どうなった・・・というのは有りませんが、今となってみればあまり考えずにプログラミングをしていたと猛省するばかりです。アトミックデザインを知ってからはパターン2で書くことが多くなり、そのおかげで例えばコードレビューの際も自分の中で指針が持ちやすかったり、追加で変更がある場合でも書き方に迷わなくなりました。
プロジェクトや個人レベルで方針が決まってるとやりやすい部分できたのかなぁと思います。
あぁ過去の自分をぶん殴りたい。