忍者ブログ
雇われるだけの人生から目指せ独立、社会人2年目なゲーム脳SEのブログ。更新頻度=週2~3回。
[1]  [2]  [3]  [4
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

まだ私は社会人2年目の若造プログラマなのですが、もろもろの事情により今年入社の08新卒の方々のメンターとして指導する側に回ることになりました。
せっかく教える側に回るのですから、教えられる方々には是非イケてる人になってもらいたいです。
というわけで、新卒の皆様の参考になればと、以前にも書いたようなネタですけど、改めてイケてるプログラマのソースとイケてないプログラマのソースを見比べて、何がその差なのかを調べてみました。

まずは例をいくつか挙げてみます。


○イケてない英語、フランス語
たとえば今の現場ではこんな感じの例があります。

gross
(総計、総合金額)
gloss
(光沢、つや、うわべの飾り)
enquete(アンケート、フランス語) enquate
(何語?)

ほかにも沢山沢山ありますが、省略。

○イケてないコードスタイル
たとえば、インデントがタブとスペース混合。行末に意味のないタブやスペース。
タブを^、スペースを_で表現すると、
^^^^____^^^^____hoge.fugafuga();^^^^^^^^
________________foo.bar(hoge);^^^^
平気でこんなソースが。そこらじゅうに。

○イケてないSQL
0以上5以下の小数(小数点以下2桁まで)の、小数部を取り出すためのロジックが、
TO_NUMBER(SUBSTR(LTRIM(TO_CHAR(var_num, '0.09')), 3, 2)) 
これです。・・・うーん、書いてる本人は必死に作ったものなんでしょうけれども、
これはイケてないですね。


こういうことを書くと、
  • 変数名ぐらいで何ムキになってんの?
  • 動けばいいんじゃね?modとか知らないし意味わかんないし!
という反論が、たいてい、飛んできます。

常々私は周りの人に
「変数名は自分の子供の名前だと思ってつけるものだ!!」
とエラソーに語っています。
自分の息子に太郎やら花子やら、「騎士と書いてナイトちゃん」と読ませるようなセンスのない名前をつける親になりたいですか?なりたくないですよね。
自分の息子に「大輔」と言う名前をつけようとして、手が滑って「犬補」と出生届に書いてしまったら、出生届ごと破り捨てて書き直しますよね?まさか、「アハハハ!いぬほだってよ!これでいくか!!」なんてバカなこと言いませんよね?
なぜなら子供に一度つけた名前は一生消えないからです。一生名づけの親はその名前を見て笑われることになるからです。

変数やクラス名、ロジックだって同じです。

自分が一度書いたソースは(特に大きなプロジェクトでは)5年10年の間、平気で残ります。
「後から誰かが直してくれる」なんてことは、Googleのような一部大例外を除いて、絶対にありません。これは保障します。
5年後に保守に入った人に「何このセンスのないソース・・・読みづらいし意味わかんないし、こんなの保守したくないなぁ・・・」と思われることこそ、プログラマにとって何物にも変えがたい屈辱であります。

にもかかわらずその5年後のことを考えない輩が異常なほど多い。

grossとかenqueteとか、わからないならGoogle先生に聞くなり辞書サイトで調べればいいのに、その手間すら怠っているのです。もしくは、調べたけど何か結果が出てきたから、中身を吟味すらせずに妄信したのかもしれません。
商品の金額に関係するクラスなのに、どうしてgloss(光沢、つや)なんて意味をつけているのか、と疑問に思うことが出来れば、発音は同じグロスでもglossではなくて別のつづりの単語ではないかと思い直すことが出来たに違いありません。

0以上5以下の小数(小数点以下2桁まで)の、小数部を取り出すためのロジック、
これだって、一度書いてみて明らかに変だと思ったなら、

Googleに"Oracle 関数"と検索クエリを投げて(30秒)、

http://www.shift-the-oracle.com/sql/functions/function-base-reference-1.html
このページを見つけ出し(1分)、

関数の内容を吟味して使えそうなものを割り出し(5分)、
http://www.shift-the-oracle.com/sql/functions/mod-remainder.html

手元のSQL実行環境でテストすれば(2分)、
SELECT mod(2.03, 1)*100 FROM DUAL
たったの8分かそこらで、よりよい解決策が見つかるのです。
ページを探すのに時間がかかっても、10分もあれば解決できるのに、
「まぁ、動くからいっか!次次!」
なんて思考停止して次に行くから、こうして数年後に私のような若輩者にコケにされるようなソースになってしまうのです。


と言うわけで結論。
イケてるプログラマと、イケてないプログラマの差は、
  • イケてないコードに気づくことが出来るか
  • イケてないコードを無視しない勇気があるか
  • イケてないコードを修正するために10分考える習慣があるか
この3点ではないかと思います。ではどうすればこの差を埋められるのか?
  • イケてないコードに気づくためには、イケてないコードだと認識できるだけの知識が必要!→勉強するぞ!
  • イケてないコードを無視しないためには、自分の首をかけて「これは間違っている!」と言うだけの熱意と説得力が必要!
  • イケてないコードを見つけたら、どうすれば修正できるのか頭の中だけではなくて実際に調べ検索し試し動かして検証する!
こんな感じで、少しでもイケてるプログラマに近づければ幸いです。
PR
紹介記事をいくつか流し読みしてみた感じでは・・・

やっぱりjQueryでしょうか!

理由は記法がシンプルだからです。
$だの$$だの$Aだの$Hだのprototype.js拡張クラスだのなんだの・・・これじゃあまるで別の言語じゃないですか。それよりも覚えることが少なそうなjQueryを選んでみることにします。
物足りなければもちろんまた考えます!

だいぶ間が開きましたが前回の続きです。
Djangoのテンプレートの継承機能を用いて、ソースを書き直します。

template_inheritance.jpg

イメージを書いてみました。何がなにやらわかりませんが、そこはお手数ですが個々人でイマジネーションを働かせてください

あとは、Baseとなるテンプレートを拡張した各画面のテンプレートを作成して、
それを読み込んでrenderするだけですね。

TO000049.JPG

うまくいきました!

さて、テンプレートの継承機能を用いるところまでは、Djangoのリファレンスサイトを見ればあっさり終わったのですが、新たな問題が出現してきました。
現在開発にはPleiades Eclipse 3.3のPython開発用セットを用いています。この開発セットにはWTPが含まれていて、HTMLやCSSなどを編集する際にはWTPのHTMLエディタを使用することになっています。ここまではOK。
問題はこのHTMLエディタ、フォーマット機能があまりにもひどいのです。
まともにインデントを考慮してくれず、非常に汚いフォーマットにされてしまいます。

TO000050.JPG

いったいどうしてこんなフォーマットになってしまうのかを探るため、Google先生にいろいろとお尋ねしてみたのですが、満足な結果が得られず・・・
ここで腹をくくって、Eclipse WTPのサイトからWTPプラグインのソースコードを実際にダウンロードして調査してみることにしました。
Eclipse Web Tools Platform (WTP) Downloads 

さて、ソースコードをダウンロードしてきたのはよいのですが、いったいどこを見ればHTMLファイルをフォーマットしているソースを見ることが出来るのかさっぱりわかりません。
悩んでいても仕方がないので、ダウンロードしてきたソースコードフォルダ全体のsrc.zipファイルに対して、"format"という文字列が含まれていないか、サクラエディタでgrepをかけてみることにしました。

TO000048.JPG

ビンゴ!
160件もヒットしました。zipファイルといえどもファイル名だけは普通にテキストエディタで見えるんですね。
いかにもそれっぽいあたりを解凍してソースを読んでみました。
すると・・・

/**
 */
protected void formatNode(IDOMNode node,
        HTMLFormatContraints contraints) {
if (node == null)
    return;

if (node.hasChildNodes()) { // container
    formatChildNodes(node, contraints);
}
else { // leaf
    IStructuredDocumentRegion flatNode 
        = node.getStartStructuredDocumentRegion();
    if (flatNode != null) {
        String source = flatNode.getText();
        if (source != null && source.length() > 0) {
            setWidth(contraints, source);
        }
    }
}
}

・・・え?コレダケ?
ぱっと見た感じ「setWidth()」しかしていません。
要するに・・・文章の横幅の設定に合わせてテキスト全体の折り返しをしているだけ!?インデントの調整とか一切なし!?

なるほど、WTPのHTMLエディタ付属のフォーマット機能は使えねえということだけがはっきりとわかりました。

仕方がないので外部のフォーマッターを使いましょう。
問題はDjango独自のタグ・・・{{}}ですとか{##}ですとか{%%}ですとか・・・が入るので、普通のhtmlフォーマッターは使えないということです。
「django template 整形」とかで検索をかけてみましたが、やはりDjango専用のものは存在しないようです。また困りました。
どうしましょう、自作するしかないのか・・・と考えていた矢先。

急にひらめきが。

「HTMLにHTMLタグ以外のタグを埋め込む=PHP=そうだPHPのフォーマッターを使い回せるんじゃないか!」
php 整形 - Google 検索 
PHPスクリプトの基本構造/PHP入門 

さすがは歴史のあるPHP、たくさんフォーマッターが見つかりました。
あとはこの中から改造が容易そうな奴を選んで、PHPタグを判定しているところをDjangoテンプレートのタグに変更してやればよいのです。楽勝楽勝。

とりあえず本日はここまで。
集中力が続かないなぁ・・・寺に行って座禅して修行かなぁ・・・

 

現在仕事で扱っているシステムは、外部のシステムとXMLで連携したりします。
そのXML電文にバグがあるんじゃないかということで、調査依頼が飛んできました。

昔の自分なら、帰ってきたXML電文を自分の目で比較したりdiffエディタに突っ込んで比較したりしていたことでしょう。しかし、目での比較は文章化しづらく説得力に欠ける(せいぜいスクリーンショットを取って並べる程度の資料しか作れない)ところがありますし、何より面倒です。
しかも今の私にはPythonと言う強い味方がいるのですから、PythonにXMLの解析をやらせましょう。
コマンドラインからファイル名を受け取って、DOMで解析し、特定の名前の要素の値だけを抜き出して列挙するプログラムをささっと書いてみます。

参考にしたページ一覧:
13.6 xml.dom -- 文書オブジェクトモデル (DOM) API
Python でUTF-8, shift_jis, euc_jpなど日本語を使う方法
xml.dom.minidom を用いた XML の取り扱い
Python備忘録 - mynote

ソースコードは↓こちら。
import sys
import codecs
from xml.dom.minidom import parse


def main():
#    for args in sys.argv:
#        print args
#
#    print 'asobiha kokomadeda! xml parse suruze!!'
#    xmlfile = codecs.open(sys.argv[1], 'r', 'shift_jis')
#    dom = parse(xmlfile)
    dom = parse(sys.argv[1])
    nodes_rcode = dom.getElementsByTagName('FareItemNo')
    for node in nodes_rcode:
        print node.firstChild.nodeValue
    
    dom.unlink()


if __name__ == "__main__":
    main()

たったの20行(本質的に意味があるのは4行!)で出来ました!
ファイルからの読み込み&パースもわずか1行です。
(Javaでつくるとこの部分だけで10行超えてしまいそうです)
Javascriptみたいに、getElementsByTagNameが使えるのが非常にうれしいですね。

注意するべき点は、xml.dom.minidom.parse()が、なぜかencoding="Shift_JIS"のXMLを読み込んでくれないことです。IANAにも登録されている由緒正しい?エンコードなのですが、うまくいかないものは仕方が無いので、XMLの文字エンコードをUTF-8に変換してencoding="UTF-8"を指定すればうまくいきました。

あとは、コマンドラインから起動して、結果をテキストファイルに>リダイレクトしてやればOK!
python abesi.py hogehoge.xml > hogehoge.txt
いやー、スクリプト言語はストレス無く使えていいですね。
今回の作業で一番ストレスを感じたのがDOS窓のあまりのシェルの弱さ(TABキーによる入力補完がLinuxのbashに比べると天地の差)だったぐらいですから。

こういうちょっとしたスクリプトをささっと書けると、なんだかプログラマレベルが上がった気になれて自己満足度アップです。
↑こんな質問されたら、
私はもちろん、こういってやるつもりです。

「クラスパスだ、このド畜生が!」

と。
それぐらい私はこのクラスパスと言うやつが嫌いです。むしろクラスパスが好きと言う人がいるのでしょうか。
Java classpath 嫌いの検索結果:1420件
Java クラスパス 嫌いの検索結果:1210件
原因不明な環境系のバグをさらに原因不明にし、結果おまじない的な対応を強いられることになるのも、すべてこのクラスパスと、不可解なJavaのクラスローダの動きが原因に違いありません。

どうして今更こんなことを言うか、ですって?
もちろん、たった今、現在進行形で、このクラスパス関係のおまじないに苦しめられているからです。
たとえばこんな感じです:
  • 現在の職場ではStruts1.2.4とTomcat5.0.30を使用しているが、/WEB-INF/lib以下にjasper-compiler.jarとjasper-runtime.jarを「プロジェクトのクラスパスに追加しないようにして」配置しないと、実行時にJSPが動作しない。クラスパスに追加する・外部クラスパスに追加する・ライブラリを移動するなどの処置を取ると直ちに動かなくなる。当然Tomcat側の/common/lib/以下にも同様のjasperライブラリ2種類が配置されているにもかかわらず動かない。完全に原因不明。
  • 最初からStruts付属のcommons-validatorライブラリがついてくるにもかかわらず、プロジェクトのライブラリにcommons-validator-1.1.3を追加しないとTomcatがコンテキストの立ち上げに失敗する。完全に原因不明。
もはやこうなると何が原因なのかを切り分けするのも不可能(自分のソースが悪いのかTomcatが悪いのかStrutsが悪いのかJavaのインストールディレクトリがおかしいのか環境変数の設定がおかしいのかetc...)になってしまいます。
その他、ライブラリのアップデートをしようにもなぜかバージョンを挙げたら動かなくなるのが怖いからずっと昔のバージョンを使わざるを得ない、その結果セキュリティホールが残りっぱなしとか・・・

RubyのGemが心底うらやましいです。
Linuxのパッケージ管理(apt-getとかrpmとか)にまったくなじみが無かったころはGemのパッケージ管理の意味がまったく理解できず、「Gem?誰だよこんな意味不明な仕様考えた奴」とか狂ったことを平気で口走っていましたが、本当に申し訳ございません。私が本物の⑨でした。今更言わなくても重々承知ですけど。

Java7でjamなどという機能が増えるらしいですが、遅きに失した感があります。今更出てこられても、「jam導入しましょうよ!パッケージ管理が楽になりますよ!」なんて私が言っても上司が首を縦に振ってくれないんですって。
前回の記事でようやく画面イメージが多少なれどもできあがってきたところがお伝えできたと思いますが、一目見てわかるほど画面イメージが貧弱です。あまり華美なのは好きではありませんが、それでも少しぐらいはリッチなインターフェースを持たせたいものです。
たとえば、RTM(Remember the Milk)にならいまして、日付は「today」とか「4th sunday」とかで指定したいところですし。

そういったリッチなUI機能を実装するために、javascriptのライブラリについて調査してみました。
すでにいくつものサイトでjavascriptライブラリの比較記事が上がっています。
まずはメジャーどころから、@ITの記事。
Webアプリに使えるAjaxライブラリ8選! - @IT

続きまして個人ブログでの比較記事が二つ。
blog.shimazu.org : JavaScript ライブラリ比較
GANCHIKU.com » Javascriptライブラリ比較
こちらは海外の記事。
The JavaScript Library World Cup [JavaScript & AJAX Tutorials]

最後に、非常にたくさんのライブラリが一覧としてあげられているページ。
あるSEのつぶやき: Ajaxライブラリまとめ 

聞いたことがあるprototype.jsやdojo、jQueryをはじめ、Yahoo UI Library、Mochikit、Google Web Toolkit、script.aculo.us、Ricoなどなどなどなど・・・これではきりがありません。
こんなにたくさんあるのではどこから手をつければよいのかすらさっぱりです。

おそらく、具体的にライブラリを使ってどのような機能を実装したいのか、イメージがまだできあがってないから適切なライブラリが選択出来ない状態に陥っているのかなぁと思います。
まずはjavascriptなしで立派に動作する画面を作って、それからですね。

一応、使うときはRuby on Railsでも使用されておりメジャーどころであるprototype.jsか、または最近よく名前を聞くjQueryを使ってみようと考えております。dojoは超高機能ですが重いらしいですし私には使いこなせそうもありません。

2週間ぐらい前から、Google App Engineで動かすためのアプリケーションを作成しています。
進捗状況はといえば、要件定義がだいたい終わって、ようやくそれらしい画面のレイアウトを作るのに成功したという程度で、あまり芳しくありません。
HTMLやCSSに詳しくなかったり、DjangoどころかPython自体初心者なので調べ物をしながら進めているのが主な遅延原因でしょうか・・・

ともかく!Djangoのテンプレートエンジンを使用して出来た画面がこちらです。

TO000042.JPG

この程度の画面を作るのに休みを丸一日つぶしてしまったなんて・・・
やはり実際に手を動かして作ってみると、自分のスキルのなさが如実にわかっていいですね。もっと勉強してやろうという気になります。

閑話休題。画面の説明をします。
いわゆるよくあるヘッダ+右サイドバー付きのコンテンツ+フッタで構成される画面ですが、個人的にテーブルでレイアウトを作るのが大嫌いなので、なんとしてでもCSSだけで綺麗にレイアウトを作ってやろうと考えました。
しかしCSSでどうやって2段構成を作っているのかなんてまるでわかりません。
Google先生に聞いてみたところ、一番良い解答を返してくださったのがこちら。

Learn CSS Positioning in Ten Steps: position static relative absolute float 

実際に10ステップのチュートリアルを踏まえて、CSSをどのように設定すればどのようなレイアウトが作れるのかが説明されています。ひとまずはここのやり方をパク・・・拝借しました。

↓こちらが先ほどの画面のテンプレート用のソース。

TO000043.JPG

↓そしてこちらがCSSのソース。
TO000045.JPG

↓最後に、pythonスクリプト(リクエストハンドラ)のソース。

TO000044.JPG

見ての通り、リクエストハンドラの中で複数のテンプレートを読み込んで、
それをテンプレートパラメータとしてメインのテンプレートに埋め込むという手法をとってます。

この方法で問題ないのかと思っていたのですが、
実はDjangoにはテンプレートの継承という機能があることがわかりました。
テンプレートの継承とプロトタイプ | スパムとか 
Django | The Django template language: For template authors | Django Documentation 

1:すべての親になるテンプレートを作成し、{% block %}タグを埋め込む。
2:{% extends %}タグを利用して、親テンプレートのblockタグを実装した子テンプレートを作る
3:子テンプレートをrenderする
この手順を踏むことで、今回のようにわざわざ5種類ものテンプレートをインクルードしたりしなくてもすむみたいです!明日、早速試してみます。


Google App Engineでアプリケーションを作ろうと考える以上、表示言語はもちろん英語を使わなければなりません。なんてったって全世界の人がアクセスできるわけですからね。

しかーし。我々日本人にはアレルギーとでも言わんばかりの英語嫌いがありまして、日本語のインターフェースにしない限り、どんなによいアプリでも誰も使ってくれません。それはさておいても、これからの国際社会を生き残るためには、「国際化対応?英語でアプリケーションを作ってハイおしまい!」でよいわけが無く、簡単にローカライズが出来るような仕組みを理解した上でアプリケーションを作ったほうがいいと思うわけです。

御託はこれぐらいにしまして。
というわけで、Python標準機能のローカライズモジュール"gettextを使用しまして、アプリケーションのローカライズにチャレンジしてみました。
参考にしたサイトはこちら。
2006-01-18 - himainuの日記
21.1 gettext -- Multilingual internationalization services(Python2.5.2公式ドキュメント)
6.27 gettext -- 多言語対応に関する国際化サービス(Python2.3日本語化ドキュメント)

公式のドキュメントを見ると意味不明な関数の羅列が並んでいて、コレでいったいどうすればいいんだと途方にくれてしまいます。
こんなときは、実装されたソースを読めばいいんです。なんといったってCやJavaと違いソース=モジュールですから、いちいちソースをダウンロードしてくる手間すらありません。インタプリタ言語って素敵。
gettext.pyをエディタで開いて格闘すること1時間、おおよその動きはつかめました。図にまとめるとこんな感じです。

WS000131.JPG

なんだか射的の的みたいなステートチャートになってしまいましたが、要するに先ほど紹介しました参考サイトの中で指摘されているように、「gettext.install()」を呼び出して「_('MESSAGE')」みたいにアンダースコア関数を使えばいいだけです。たったの2ステップ。滅茶苦茶楽勝です。

さっそくやってみました。
まずは翻訳元になるソースを書いて、pythonインストールフォルダにあるTools/i18n/pygettext.pyスクリプトを呼び出します。
python pygettext.py test.py
みたいに。

WS000128.JPG

うまくいきました。途中%の使い方を間違えて散々苦労している姿が見受けられますが気にしないでください。
pygettext.pyスクリプトを呼び出すとpo形式のファイルが出力されますので、コレをエディタで開いて思う存分に翻訳します。以下、翻訳内容です。手を加えたところは強調表示しています。

# TESTTEST.
# Copyright (C) 2008 akisute
# FIRST AUTHOR <abesix@bakasu.com>, 2008.
#
msgid ""
msgstr ""
"Project-Id-Version: 0.1\n"
"POT-Creation-Date: 2008-05-08 10:44+JST\n"
"PO-Revision-Date: 2008-05-08 00:00+JST\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: japanese\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=Shift_JIS\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"


#: test.py:13
msgid "Q.E.D \"Ripples of %s Years\""
msgstr "Q.E.D \"%s年の波紋\""


最も重要なのは一番下のmsgstrと、ヘッダ中のContent-Typeです。特にContent-Typeのcharsetは極めて重要で、poファイルの文字エンコードとあわせないとうまくいきません。

編集したら次はTools/i18n/msgfmt.pyスクリプトを呼び出して、poファイルをmoファイルにします。
python msgfmt.py poファイルのファイル名(拡張子は不要)
私はpoファイルのファイル名をja.poにしていたので、python msgfmt.py jaと入れたらうまくいきました。

で、生成したファイルを以下のように配置してみました。
C:\Python25\workspace>tree /f
フォルダ パスの一覧
ボリューム シリアル番号は 0000EE57 1C83:607F です
C:.
│ ja.po
│ test.py
│ utf8ja.po

└─locale
└─ja
└─LC_MESSAGES
ja.mo

ポイントは、install関数の引数localdirの指定と、LC_MESSAGESと言うフォルダを間に挟むことと、moファイル名を引数domainで指定することでしょうか。localdirとLC_MESSAGESの間にlanguagesフォルダがあって、これはなにやら環境変数から取得するだの何だのと言う話があったのですが、さっぱりわからないのでディレクトリ名をjaとしてみました。

moファイルも生成したし、早速試してみましょう。
・・・やっぱりだめでした。明らかにmoファイルを読み込んでくれていません。99%がlanguageフォルダの指定がうまくいっていないせいだと思われます。
だってWindowsの環境変数にLANGUAGEもLANGもLC_ALLも無いですし。だからといっていちいち環境変数を設定しなければ動かないシステムなんて欠陥です。第一環境変数に左右されるシステムなんてちょいと問題があります。
ですが、gettext.install()はそのままではlanguageを引数に取れません。仕方が無いのでgettext.translation()を使うことにします。再度試してみました!

WS000129.JPG

ばっちりですね!
いやースクリプト言語はデバッグが難しい!ここまで来るのにだいぶ苦しみました。完成したときには正直軽く小躍りしてしまいましたよ。

・・・が。ダメです。まだ完成ではありません。
poファイルの文字エンコードが「Shift_JIS」じゃないと動作してくれないのです。UTF-8に変えて再度moファイルを生成し、試すと文字化けします。
別にShift_JISでいいじゃん?確かにその通りなのですが、Googleの発表によるとすでにWeb上のリソースの半数はASCIIではなくUnicodeになっているそうなので、ここでその流れに反するようなまねをするわけにはいきません。なんとしてもUnicodeで動作させたい。
Content-Typeの指定ミスかと何回も見直しましたがそうではない様子。困りました。

ここでNullTranslation.install()メソッドのソースを見直してみると・・・第2引数にunicode=Falseというものが指定されています。どうもこれが怪しい。さっそくt.install()としているところをt.install(unicode=True)にして再実行してみました。

WS000130.JPG

ブラボー!やはりこいつでした。この引数の値に応じて_にバインドする関数をgettextとugettextで変化させているのが原因だったようです。

さて、次はこの成果をGoogle App Engine上で利用できるかどうかを試さなくてはいけませんね。
アクセスしてくるURLに応じて適切に言語体系を振り分ける必要がありそうです。どうしようかな・・・
前回より大変長らくお待たせしましたが、諸事情・・・おもに作者のやる気不足とかSwingの面倒さについていけなくなった等の理由で・・・ついに終わってしまいました!

まずは完成品をご覧ください。

TO000038.JPG

ださっ!!!
GridLayoutというレイアウトを使ってみてボタンとリストを並べてみたのですが、これはひどいです。仕方がないのでGridBagLayoutというよくわからないレイアウトを使ってみます。

TO000039.JPG

おお、だいぶスマートになりましたね。
もっともこれを実現するためだけに1時間以上APIリファレンスと格闘するはめになりました。どうしてこう、SwingのAPIは複雑怪奇なんでしょう・・・いやWin32APIに比べれば確かにマシだとは思いますけど。

TO000040.JPG

こちらがAdd new Notebookボタンを押したときに動くアクションリスナーです。匿名の内部クラスとして実装するのがSwing(といいますかVisual Editor)のしきたりみたいなのですが、このアクションリスナーを作っている最中にまた相当イライラさせられました。
  • パネルやウィンドウ自身を指し示めそうと思ってthisと使うとアクションリスナークラスの内部なのでアクションリスナー自身が返ってくる
  • アクションリスナーの外部の変数をアクションリスナー内部で使うためには外でfinal宣言した変数を作らなければならない
  • getTopLevelAncestor()メソッドを使えば自分の親(すなわちOreNotebook本体)のオブジェクトにアクセスできるのですが、そもそもコンポーネントのGetterメソッドがすべてprivateになる(Visual Editorのしきたりみたいです)ので、親にアクセスできたところで何も出来ない。ひょっとしたら無理矢理publicに書き換えるのが正解なのかもしれませんけど。
とまぁ、書いていてとにかくイライラ。なんでこんな美しくないソースになるんだろうと・・・
アクションリスナーの中身は1行、コントローラクラスを呼び出すだけにしたかったのですが・・・そうすれば同じ操作を画面の別の場所で行うとしても、1行書くだけですみます。アクションリスナーの中身で操作を行ってしまうと、別の場所に移植する際にすべてコピペすることになってしまい後から困ります。

愚痴はさておきまして。
コントローラやエンティティの実装も行いまして、実際に動作させてみました。

TO000041.JPG

Add new Notebookボタンを押すと新しい"abesi"という名前のノートブックがノートブックリストに追加されます!やった!
と、ここで私の忍耐力が限界を迎えてしまいました。もうこれ以上こんな設計思想もインターフェースもわからないAPIを使って綿密に設計するなんてできません。綺麗に設計するためには、本を買ってきてSwingを勉強し直す必要があるみたいです。

一応、ここまでの完成品をまとめたものをアップしておきます。
・Eclipse Workspace&Source
OreNotebook.zip
・UML
OreNotebook.jude

今回の企画の反省点。
  • UMLを作ることを重視しすぎた。設計だけなんてやっぱり楽しくないし、全くゼロの状態で設計だけを延々と進めると、実際に実装したときとUML図の乖離が大きくなり、結局UMLを修正しなくてはならなくなる、実装あってUMLありき。少し書いたらすぐ作る、すぐ作ったらまた設計。
  • Swingなどというよくわからないものを使おうとしてしまった。もっと熟知してから進めるべきだった・・・
  • 途中でGoogle App Engineという別の楽しそうなおもちゃを見つけてしまった。
次回に生かしたいと思います!
前々回の最後に描いたいけてないシーケンス図・・・
↓こちらです

bc0cbbbf.jpeg

これをばっちり描き直しました。これで最終版です。ご覧ください!

ad08b8fa.jpeg

どうでしょう。会心のできです。
それでは個々のクラスについて説明いたします。

○CreateNotebookAction
コントロールクラスです。コントロールクラスは一つのシナリオに1個つくります。
こうしておくと、現在は画面上のボタンを押したときだけ実行されるノートブック作成動作を拡張して、メニューからノートブック作成ができるようにしたいときでも、このコントローラを呼ぶだけですむという便利なシステムになります。まぁ、Strutsの構造をパクっただけとも言うんですが。

○NotebookDao
ノートブックを作成するDAO(Data Access Object)です。ノートブックに対して、永続記憶装置へのCRUD機能を提供します。ものっすごくかみ砕いてわかりやすくすると、ノートブックをファイルに書き出して保存したり、ファイルから読み込んだりするクラスです。
ファイルではなくてデータベースに書き込みたい場合や、ファイル保存にしてもテキストベースからYAMLやXMLで保存するようにしたいなんて時は、このクラスだけをいじれば解決します。

異常系の処理についてですが、CreateNotebookActionクラスの中で例外をキャッチして処理を行います。本当はこのActionクラスを呼び出すローダークラス(ファサードクラスっていうんだっけ)を用意して、そこで例外処理をするようにすれば例外処理を個々のActionの中に書き込まなくてすむため非常に楽なのですが、そのファサードを作るのが非常に面倒なため今回はパスします。ヘタレでごめんなさい。



次回の内容ですが、一つシナリオも出来たことですし、そろそろ実装してみましょうかと考えています。本当ならステートチャート図やアクティビティ図みたいな重要な図があるのでそちらもやりたいところなんですが、こんな小さいシステムでは使いどころが少なすぎるというのと、単純に飽きてきたからそろそろ実装したいという私の自分勝手すぎる事情があります。ほんとすみません。

それではまた!
カレンダー
09 2017/10 11
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
ブログ内検索
最新コメント
[11/13 DSLR-A850]
[08/29 逆援助交際]
[08/23 クンニ]
[08/22 熟女]
[08/19 痴漢]
はてなブックマーク
プロフィール
HN:
akisute
性別:
男性
職業:
システムエンジニア
趣味:
ゲーム・東方・ニコ動。あと散歩。
バーコード
推奨環境

横幅900px以上、Firefox 3, Safari 3, Opera 9.5, Chrome 0.2以上。IE7ギリギリ対応。IE6未対応。

忍者ブログ [PR]