Category Archives: Mayaa

プログラマーとデザイナーの境界が縮まってきた気がする

今日のひがさんのエントリを読んで、appengineとは全然関係ないけど思ったことを書きます。
http://d.hatena.ne.jp/higayasuo/20101109/1289290143

ひがさんのエントリでは、appengine/Javaのスピンアップ問題を解決するために、静的HTMLをレスポンスして、JavaScriptで後から動的なデータを取得するパターンが提案されています。

別にこれ、appengineに限らず最近僕の近辺ではトレンドだなと思っていました。
SEOがあるので、サーバーサイドテンプレートもまだ必要だとは思いますが。

それで、思ったのがプログラマーの仕事についてです。僕が見てきたことを書きます。

むかしはJSPを書くだけのプログラマーがいました。

むかしむかし、ウェブシステムの画面はJSPという難解な呪文を駆使しなければ書けない、とても高級なものでした。
しかし、世の中には、「JSPが書ける」プログラマーが沢山いました。少しコツを教えればすぐにやり方を覚えてくれるので、派遣さんや学生のアルバイトが多く担当しました。

彼らは、デザイナーさんが書いたHTMLを「HTMLきもーい」とか言いながら、一生懸命コピペしていました。

この仕事は誰でもできる反面、誰がやっても同じくらいのコストがかかる仕事でした。優秀なプログラマーなら、普通のプログラマーの20倍は生産するのが普通な現場ですが、みんな一律に同じ程度の時間がかかるのです。それに、デザインを組み込むために何週間もかかるため、お客様にもご迷惑がかかりました。

それを解決したのが、(弊社の場合は)Mayaaでした。最初の導入は大変でしたが、導入後は、デザイナーの人が一人でサイト全体のデザインをしてくれるようになりました。もう、JSPを書けるだけのプログラマーは必要なくなり、プログラマーはJavaに専念し、デザイナーはHTMLに専念することができるようになりました。時々、中間言語のmayaaファイル(XML)を書かなければいけないのですが、こういう時、プログラマーは腕の見せ所でカッコ良く対応してあげるとデザイナーさんからの株が上がります。大いにがんばりましょう。

ところが、これを導入してたった半年で時代は変わりました。

みんな、JavaScriptでなんとかしたくなっていたのです。
MayaaはJavaScriptの変数を置換することはできません。強引にやることもできますが、やるべきではありません。セキュリティー的に。
それではどうするのかというと、一旦mayaaでspanタグにデータを落として、スタイルシートで非表示にし、JavaScriptから、getElementByIdしてinnerHTMLなどで値を取得するという方法が良さそうです。

これくらいのことなら、デザイナーさんにレクチャーすればやってもらえるのですが、

デザイナーといえど、JavaScriptを知らなければやっていられない時代なんだなと思います。

このことにとどまらず、今、毎日のように、デザイナーさんがいろんなJavaScriptをWEBから見つけては、「動かない」と悩んで僕に質問をします。その都度、「これはjQueryのバージョンが合わない」とか「このJavaScriptわかってない人が書いてるから使わない方が良い」とか答えるのですが、時には「わかった。僕がやっとくよ」ということもあります。

今までは、
Java, JSP, HTML(CSS)
と、それぞれの言語で話していたことが、今は
HTML/JavaScript
という共通の言語でプログラマーとデザイナーが会話をしているのです。

本当はUIプログラマーという職種が、橋渡しを担当するのでしょうか?でも、なんだかむしろ、今時のWebはUIを取ってしまったらあとは何も残らないくらいUIに依存しているので、UIプログラミングのできないプログラマーも、JavaScriptの書けないデザイナーもあんまり活躍できないのではないかと思います。

その後の追記

ついに、デザイナーさんから、「私ができそうなところは私がmayaa書いていいですか?」と言われました。もはや最強!

プログラマーに取ってmayaaファイルを書く事はXMLプログラミングですので、割と苦痛なのですが、デザイナーさんにとっては、JavaScriptよりもフレンドリーのようです。

この記事は以前多くのブックマーク・コメントを頂きました。

これからブックマークされる方はこちら↓

Mayaa ファイルの共通化

 同じ機能のテンプレートが複数セット存在する場合を考えます。例えば、/1/A.htmlと、/2/A.htmlは、デザインが違いますが、全く同じ機能だとします。このとき、/1/A.mayaa を /2/A.mayaa に複製するのが基本です。しかし、それだと、/1/A.mayaaを修正したときは、同時に/2/A.mayaaも修正しなくてはなりません。/3/A.mayaa、/4/A.mayaaのように、さらに複製されていた場合はなおさら厄介です。
 
 複数のテンプレートが共通のMayaaファイル(Specファイル?)を参照する場合、手っ取り早い方法としては、templateSuffixを使う方法があります。
http://mayaa.seasar.org/documentation/template_suffix.html
 しかし、上記のようにフォルダでテンプレートをグループ分けしたい場合は、suffixは使いにくいです。

 シンボリックリンクによる方法も簡単です。これなら、Mayaaのカスタマイズなしに、すぐに使えます。しかし、Windows上でテストできない点が私はネックだと思いました。Javaシステムなので、OSやサーバに依存しないで解決したいです。

 この度、Mayaa ユーザメーリングリストにて、次のように質問させていただきました。
 http://ml.seasar.org/archives/mayaa-user/2009-December/000868.html
 suga様の回答(ありがとうございます。)を参考に、SourceDescriptorのカスタマイズによって解決しました。以下ソースを貼っておきます。

package mypackage;
import java.io.InputStream;
import java.util.Date;
import org.seasar.mayaa.impl.source.PageSourceDescriptor;
import org.seasar.mayaa.source.SourceDescriptor;
public class MyPageSourceDescriptor extends PageSourceDescriptor {
// ルートのmayaaファイルを探しに行くディスクリプタ
private SourceDescriptor rootDescriptor = new PageSourceDescriptor();
// 注意:SystemIDはmayaaファイルの絶対パス
/**
    * ソースSystemIDを設定する。
    * 
    * @param systemID
    */
@Override
public void setSystemID(String systemID) {
super.setSystemID(systemID);
// ルートのパス取得。
String rootId = getRootId(systemID);
if (rootId != null) {
rootDescriptor.setSystemID(rootId);
} else {
rootDescriptor.setSystemID(systemID);
}
}
// 要求パスからルートのパスを解決する。
private String getRootId(String systemId) {
if (systemId.startsWith("/client_info/")) {
int pt = systemId.indexOf("/", "/client_info/".length());
if (pt != -1) {
return systemId.substring(pt);
}
}
return null;
}
/**
    * ソースが存在するかどうかを取得する。
    * 
    * @return ファイルが存在すればtrue。無ければfalse。
    */
@Override
public boolean exists() {
// ルートの方が見つかりやすいから、処理高速化のためルート優先
return rootDescriptor.exists() || super.exists();
}
/**
    * ファイルのインプットストリームを取得する。
    * 
    * @return ストリーム。もしファイルが無い場合は、null。
    */
@Override
public InputStream getInputStream() {
InputStream result = super.getInputStream();
if (result == null) {
result = rootDescriptor.getInputStream();
}
return result;
}
private static final Date nullDate = new Date(0);
/**
    * ファイルの日付を取得する。
    * 
    * @return ファイルの最終更新日付。ファイルが無い場合は「new Date(0)」を返す。
    */
@Override
public Date getTimestamp() {
Date result = super.getTimestamp();
if (result.equals(nullDate)) {
result = rootDescriptor.getTimestamp();
}
return result;
}
}

 このようにラッパーにすることで、外側からは完全に隠蔽しつつ、内部で代替ロジックを動かすことができます。教科書的に言えばMyPageSourceDescriptor はSourceDescriptorをimplementsして、PaseSourceDescriptorをもう一つフィールドとして持ち、メソッドをそちらに移譲するようにした方が、構造がわかりやすいでしょう。しかし、それだとコード量が増えてしまうので、わかった上で継承で代用することはありだと思ってます。

 これを動かしたところ、うまくユーザごとのMayaaファイルが存在するときはそちらを、存在しない時は、ルートのMayaaファイルを処理するようになりました。

 また、この修正の副作用として、ユーザのテンプレートが存在しない場合に、ルートのテンプレートを探すようになりました。内部的にinsertしている場合も、うまいこと処理してくれるので、Mayaa内部で賢いことをしてくれているのだと思います。
 勘違いしてました。SourceDescrptorは、mayaaファイルだけでなく、htmlテンプレートも探しに行くようです。私としては大変都合が良いことでしたが、勘違いしないように気を付けた方が良さそうですね。

MayaaでGuice2.0 AOPを使うとうまく動かない件〜解決編

http://d.hatena.ne.jp/s-ishigami/20090906/1252210901 の続きです。
MLにてsugaさんに回答いただき、無事解決することができました。感謝です。

解決方法

Mayaa Blank Warにバンドルされているrhino-1.7r.jarを使用せず、下記URLよりRhino最新版を入手して、その中のjs.jarを使用する。
http://www.mozilla-japan.org/rhino/download.html

解説

Rhinoには、js.jarとjs-14.jarの2種類のjarファイルが存在し、前者はJava5以上、後者はJava1.4でも動くとのことです。

Guiceを使っているならJava5なので、Guice+Mayaaの組み合わせはこれで問題なさそうです。