ラベル Programming の投稿を表示しています。 すべての投稿を表示
ラベル Programming の投稿を表示しています。 すべての投稿を表示

2012年10月21日日曜日

プログラミングのタネ

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
椅子から立ち上がっただけで、激しいぎっくり腰に見舞われた、たなけんです。
本エントリでは、私なりのプログラミングのネタの探し方について記載します。

どう書く?org

はじめに頭に浮かんだのはどう書く?orgです。(久しぶりにのぞいてみるとサーバエラーになっていましたが)
問題の範囲が小さく、様々な言語で解答されているので、とっかかりやすく、他言語の特徴なども知ることができ、新しく覚えた言語を手に馴染ませる際に良く利用していました。

プログラミング本の写経

プログラミングの本、例えばPaul Grahamのon Lispであれば、Common Lispでどう書くか、ということが示されています。僕の場合は、Common LispではなくClojureでon Lispの写経を行いました。(SICPも早く完了したいのですが。。。)
その言語についての知識が全くない状態であれば、ただ写経するだけでも、習慣的な記法が身に付いて良いかと思いますが、私は少し退屈だと感じたのと、Clojureが好きであるという点から、少し言語を変えて写経を行いました。
Ruby on Railsを初めて学んだ際には”RailsによるアジャイルWebアプリケーション開発”という本を黙々と写経(というかコマンドとかもそのまま打ってました)しました。そのころは、Javaで書かれた自社製の独自フレームワークを使って開発することしかしておらず、Railsでは本当に少しのコードで、こんなことができるんだと衝撃を受けました。
写経をしながらだと、開発環境が整えられているためか、フレームワークのソースなどもその場で気になった瞬間に読むことができ、そういった点からも、手を動かさずに読むよりも理解が深まる気がします。
そういった訳で、プログラミング本はプログラミングのネタ供給元としてなかなか優れていると思います。

競技プログラミング

プログラミングコンテストチャレンジブックなど競技プログラミングのお題が紹介されている本やWebサイトも良質なネタの供給元だと考えられます。
しかし、僕自身がそれ程高度なアルゴリズムや実行時のパフォーマンスに関心がないため、競技プログラミングのお題でプログラムを書くことはあまりありません。(Excelの自動操作なんとかして的な、泥臭いけど知識が無いとてこずる系が興味の中心です)

ランサーズ

ランサーズというフリーランスへ仕事を依頼することができるサイトがあるのですが、ここでシステム開発系の依頼もいくつかあるようです。
内容としては、Webサイト構築、データの変換やデータベース構築などです。
その中で下記の2つの依頼が僕の目を引きつけました。

  • Webから商品情報をスクレイピングしてデータベースに登録する
  • 独自性ルールの麻雀ゲームを実装する

これを見た時、『これは職業プログラマ向け、どう書く?orgだ』と感じました。
それほど難しくなく、かつ現実的なスキルセットが必要なプログラムのネタが、ランサーズには転がっています。さらにそのプログラムの市場価値(依頼金額)も見られるので、『自分だったらx時間でできそう』とか、『この分野の依頼が多いから、やったことないけど手を出してみるか』といった自分のスキルの需要と供給についても考えられるので、『プログラム書きたいけど手頃なネタがないなぁ』という方には、ランサーズに出されているお題に取り組んでみることを、是非おすすめします。(個人的には、こういったスキルマッチングの市場がより一般的になるのかどうかなど、プログラムのネタ探し以外の点でもランサーズおよび類似サービスに注目しています)

必要に迫られ系

最後になりますが、やはり最も楽しいのは、自分のプログラムで現実の問題を解決することでしょう。ざっと思い出しただけで、今年は下記のプログラムを留学生活の合間に書いていました。

  • 計算問題自動生成(姪っ子向け、問題数、難易度を選んで計算問題生成)
  • 数独を途中までソルバ(単純に数を当てはめるだけの部分はプログラムに解かせ、推理が必要な部分は自分が楽しみながら解くためのツール)
  • 超簡易ERP(発注、在庫、営業、受注、販売、顧客、採用、給与、財務を管理するRailsアプリ、友人が文房具販売のスモールビジネスを始めるため、夏休み中に作成)
  • レポーティング (ビジネスゲームで得られる膨大なデータをDBに落とし込み、グラフを作成、マーケットシェアなど加工が必要な情報の計算)
  • ビジネスゲームロジック類推(蓄積したデータを変数に、統計モデルを検証し、どのパラメータが何に、どれくらい影響を与えるかを類推。)
  • 簡易OCR(画像データを変換、分割し、必要な箇所の文字を読みDBへ補完)
  • 英単語検索、記録(はじめは自分向けのコンソールツール、同じ単語を何回調べるかとか、類義語が簡単に取得出来るようにするなどをWordNetを使って実装。その後Webアプリとしてリニューアル)
  • オークションの売買履歴自動記録(アマゾンマーケットプレイスの上位1200冊の出品情報を継続的に取得(スクレイピング)記録し、売れるまでの期間、価格とランキングの変遷、売れる本のジャンルなどを求める)
  • 2chまとめの自動取得(スクレイピング)
  • Wordpress.comのブログに自動投稿(Seleniumでブラウザを自動操作)
  • POIを使ってExcelファイル作成(アドホックに良くある)


必要に迫られ系の変種としては、ライブラリの検証が挙げられます。このブログで紹介したDatomicQuartziteWeb-driverなど、新しいライブラリを使う際には、いきなり既存のプロジェクトに組み込むのではなく、検証用プロジェクトを作成し、機能を一通り試しています。厳密には『何を書くか?』というプログラムのネタを供給してはいませんが、『何か書く、できることの幅を広げる』という観点からは、ライブラリの検証もひとつのプログラムのネタと言っても良いかと思います。
ローカルに保存されているプロジェクトの残骸を数えてみると、上記プログラム以外にも30ほどプロジェクトがあり、2週間に1つ以上のベースでは新規ライブラリを試していた様です。(ふと思い出しましたが、今年の頭はcoffeescriptやクライアントサイドMVCにこってりはまっており、spine.jsなどソースをガリガリ読んでいました。こちらも機会を見つけて紹介したいと思います)

まとめ

今年書いたプログラムの総括のようになってしまいましたが、プログラムを書きたいけど何を書けば良いか分からない、という方のヒントになればと思い、本記事をしたためました。
ランサーズを見て、どう書く?orgを思い出したのが事の発端ですが、ブログを書いているうちに、必要に迫られて書いたプログラムの思い出が頭に浮かび、長くなってしまいました。
Clojureを使い続けて3年目です。はじめはファイルの入出力でさえもわざわざ調べて書いていたのですが、今ではDBやWebのプログラミングも手短にできるなど、手に馴染んできました。現実的な問題を解き続ける事で、できることの幅が広がり、達成するまでの労力と時間が短縮されました。
この冬に、学生からソフトウェアエンジニアへと職業が戻りますが、業務内/外にこだわらず、Clojureを使って問題を解決していきたいと思います。
また、ゲームを使った学習についても関心があるので、Javascriptのゲームライブラリであるenchant.jsもClojurescriptのラッパを書くなどして使ってみたいと思っています。

今日の作業は以上、最後までお読み頂き、ありがとうございました。
たなけん(作業時間30分)

2012年10月13日土曜日

Clojureアプリのデプロイ: Heroku

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
オーストラリアでの留学生活も終わりが見えて来た、たなけんです。
本エントリではClojureアプリケーションのHerokuへのデプロイについて記載します。

Webアプリケーションの作成

これまでいくつかClojureのWebアプリケーションを作成してきたのですが、Herokuで運用するために何か特別なライブラリが必要なのか等、不明な点が多かったので、Leiningenのプラグインであるheroku/lein-templateのテンプレート機能を利用して、Webアプリケーションの雛形を作成しました。
プラグインは~/.lein/profiles.cljに[heroku/lein-template "0.2.0"]と追記するだけで、インストールが完了します。(次回leinコマンド実行時に、必要なjarなどが自動的にダウンロードされます)
下記コマンドを実行し、Heroku上で動作するWebアプリケーションを生成します。
lein new heroku プロジェクト名

Webアプリケーションの構成

上記コマンドにより、下記の8ファイルが生成されます。

  • .gitignore
  • Procfile
  • README.md
  • web.clj
  • 500.html
  • 404.html
  • web_test.clj
  • project.clj

project.clj

ソースはlein-heroku/lein-templateで公開されているので、要約のみを記載します。
Webのライブラリとしてはオーソドックスにcompojureとringを利用しています。
しかしenvironとdrawbridgeという見慣れないライブラリも利用されていました。
そこで少し調べた所、environは設定情報を管理するライブラリでした(Javaでいう所のpropertyのような物でしょうか)。また、drawbridgeはリモートデバッグのためのライブラリでした。

web.clj

こちらもソースはGit上で公開されていますので、直接の引用は控えたいと思います。
environはHeroku上で設定された環境変数を読み込む為に使われているようです。
(REPLを使う際のユーザ認証。確かに、悪意あるユーザからプロセスを守らないといけないですね)その他、起動ポートや、セッションキーなどHerokuから割り当てられる変数を取得している様です。

Herokuアカウントの取得

さて、デプロイするアプリケーションを用意したところで、次はアカウントを取得します。
アカウントを取得する為には、Herokuのサイトからユーザ登録を選択肢、メールアドレスを入力するだけです。メールアドレスの入力後、確認のメールが送られてくるので、そのメール内のリンクから確認画面へ移動し、パスワードを設定します。
以上で、アカウントを取得する事ができます。

開発ツールのダウンロード、ログイン、アプリケーションの登録

Heroku ToolbeltというHerokuのCLIクライアントをダウンロードし、インストールします。インストール後、heroku loginでHerokuにログインし、アプリケーションルートに移動後、Heroku createでアプリケーションをHerokuに登録します。
あとはGitコマンドをパチパチ打ってソースをコミットし、コミットしたソースをheroku側と同期します。(コンソールでの操作は下記を参考下さい。)


Heroku Toolbeltの操作

プロセスの起動と終了

heroku psコマンドでプロセスの状態を確認する事ができます。
プロセスを起動する際は、下記のようにプロセス名とスケール数を指定します。
heroku ps:scale web=1
また、プロセスを終了する場合は、プロセス名.プロセス番号で終了するプロセスを指定します。
heroku ps:stop web.1

ログの確認

heroku logsコマンドでログを見る事ができます。初回起動時にLeiningenが依存関係の解消の為に必要なライブラリを取得しようとした形跡が見られます。(一度あるリポジトリへアクセスしたものの、そのリポジトリからは目的のライブラリを取得出来なかった際に出されるメッセージがログに残されていました。)
ログレベルの変更や、アプリケーションからのログ出力などは、アプリケーションの運用に必須な項目なので、変更方法等は知っておきたいところです。(調べてブログに書きます。。。)

環境変数の設定

heroku configコマンドで環境変数を設定します。ここで設定した環境変数のキーで、アプリケーション内から環境変数の値にアクセスする事が出来ます。

以上簡単に、Heroku Toolbeltを使ってみました。コマンド体系が直感的で理解しやすいといった感想を持ちました。作成した英単語学習アプリを公開したり、日々PCから実行しているルーチンのタスクをHeroku上のアプリからやらせるなど、いろいろとクラウド上でやってみたいことがあります。
HerokuはClojureを稼働させるのが簡単そうだったので、まず試してみましたが。今後データ量が大きくなりそうなアプリなどもありますので、他のホスティングサービスも試しつつ、ローカルのPCで走らせている日々のルーチンプログラムをクラウド上に移していこうと思います。

今回の作業は以上。最後までお読み頂き、ありがとうございました。
たなけん(作業時間1時間)



2012年10月10日水曜日

マーケットモニタリングアプリの開発(5): スクレイピングTips

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
可能な限り「どのような操作をするか」ではなく「(操作に依存せず)どんな結果を得たいか」をプログラミングしていたい、宣言型プログラミング大好き、たなけんです。
本エントリでは、スクレイピング(Webリソース(e.g. htmlページ)から必要な情報を抽出すること)のTipsを記載します。

FireBug

プログラマであれば、真っ先に思い浮かべるのはFirebugだと思います。御多分に漏れず、私もまずはFirebugでhtmlの構造を(タグを掘り下げながら)解析して行きます。
Firebugの便利な点としては、htmlエディタ(画面下部)上にマウスカーソルを移動させると、対応するhtmlイメージ(画面上部)がハイライトされる点が挙げられます。
スクレイピングしたい部分を画面上部に表示しておき、該当するタグを探って行くことでおおよそ必要な要素を特定することができます。

YQL Console

私がスクレイピングする際に重宝しているもうひとつのツールがYQL Consoleです。
YQLとはYahoo!が開発した『Webリソースに適用出来るSQL』のようなものです。
Firebugで取得したい要素を特定し、enliveのselectorを記述したものの、意図していない結果が返される事が多々あります。なぜならenliveのselectorは該当する要素を全て含んだ結果を返しますが、私が欲しいのはその中の一部だからです。
このような場合、selectorで返される要素を俯瞰し、必要な要素と必要でない要素の違いを見分けるために、私はYQL Consoleを利用します。
具体的には結果をtreeで表示し、必要な要素と必要でない要素を比較します。
理論的にはEmacs上でも結果の比較は可能なのですが、YQL Consoleは階層を可視化して
くれるので、直感的に要素の違いを見分けることができます。

今回の作業は以上。最後までお読み頂き、ありがとうございました。
たなけん(作業時間15分)


マーケットモニタリングアプリの開発(4): ランキングの更新

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
バイト先のレストランからビールを一箱もらってご機嫌の、たなけんです。
本エントリでは、モニタリング対象のランキングの更新について記載します。

ランキング更新の必要性と処理の流れ

取引が成立した理由を探る為には、出品時のランキングだけではなく、実際に売買が成立した時点のランキングも必要だと考えています。(出品後に人気が出て売れたのかどうかを検証するため)
そこで、モニタリング対象の本については、たとえそれが1200位(一括で取得できる上限)以下であっても、日々のランキングを取得する必要があります。
そこで、下記の流れで、ランキング情報を管理します。

  1. 本日のランキング上位1200を取得
  2. 前日までの累積されたISBN(ISBNマスタに登録済み)と比較
  3. 本日のランキング上位1200とISBNマスタとの差分を取得
  4. ISBNマスタに存在せず、本日のランキング上位1200に入ったものは、ISBNマスタに追加
  5. 本日のランキング上位1200に存在しないが、ISBNマスタに存在するものは、個別にランクを取得する


ソースコードと解説

ソースコードは下記の通りです。

ランキングは商品詳細ページに含まれるため、まずは商品詳細ページにアクセスします。(詳細ページのurlはhttp://www.amazon.co.jp/dp/商品コード(ISBN))順位を含むタグから値を取得、また順位が含まれない場合はnilを設定します。ただし、18禁のコンテンツは直接商品詳細ページにアクセス出来ないため、仮置として-1を設定しています。
技術的には特に新規要素は無く、ただenliveを用いて必要な情報を取得しているだけです。
取得した情報はRDBMSのランキングテーブルに追加されます。

今日の作業は以上。最後までお読み頂き、ありがとうございました。
たなけん(作業時間1時間)

マーケットモニタリングアプリの開発(3): 取引情報取得

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
日本に帰国したら、携帯キャリアは何にしようか決めかねている、たなけんです。
本エントリでは、アマゾンマーケットプレイスの出品情報の取得について記載します。

ブラウザからアクセス

アマゾンの商品詳細ページから、中古の出品リンクをクリックすると、出品情報の一覧が表示されます。その時のurlは下記のようなものでした。
http://www.amazon.co.jp/gp/offer-listing/4121020618/ref=dp_olp_used?ie=UTF8&condition=used
このurlからhttp://www.amazon.co.jp/gp/offer-listing/にISBNを付けると、取引情報の先頭ページにアクセスできることが予想されます。
実際に別のISBNで試した所、予想通り取引情報の先頭ページにアクセスすることができました。
また、先頭ページのhtmlを解析したところ、次ページへのリンクはa要素のidがolp_page_nextであるタグのhrefの値であることが分かりました。

プログラムからスクレイピング

上記の観察に基づき、ISBNから出品情報を取得するため、下記の様な関数を作成しました。


  • condマクロ: JavaなどのCase文のようなもの
  • その他工夫した点: Lispらしく、再帰を利用。次ページがあれば、結果をリストに追加して、再帰。次ペーがなければ結果を返す。

その他は、前回と同様enliveを用いて、販売者ID、販売価格、商品状態を抜き出しています。
抜き出した値は、RDBMSの取引情報テーブルに日付とともに収納しています。

今回の作業は以上。最後までお読み頂き、ありがとうございました。
たなけん(作業時間1時間)

マーケットモニタリングアプリの開発(2): 中古ランキング取得

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
最近少しずつ体重が減少してきた、たなけんです。
本エントリでは、アマゾンマーケットプレイスに出品されている本の、ランキングの取得について記載します。

ブラウザからアスセス

プログラムからアクセスする前に、まずはブラウザからアクセスしてurlを見てみました。
アマゾンのトップ画面から”カテゴリー > 本”を選択し、メニューの詳細をクリック後、条件を入れずに検索すると、左下に状態を選択するリンクが出るので、それをクリックします。さらに右上の並べ替えで『人気度』を選択すると、アマゾンマーケットプレイスに出品されている本のランキングが取得出来ます。さらに下部のリンクから次のページへと移動すると、urlは以下のようなものでした。
http://www.amazon.co.jp/s/ref=sr_pg_2?rh=n%3A465392%2Cp_47%3A2020%2Cp_45%3A0%2Cp_46%3Abefore%2Cp_n_condition-type%3A680579011&page=2&bbn=465392&sort=salesrank&unfiltered=1&ie=UTF8&qid=1349846898
このurlをデコードすると、下記のようになります。
http://www.amazon.co.jp/s/ref=sr_pg_2?rh=n:465392,p_47:2020,p_45:0,p_46:before,p_n_condition-type:680579011&page=2&bbn=465392&sort=salesrank&unfiltered=1&ie=UTF8&qid=1349846898
このurlからrh=以降のパラメータは検索条件、pageはページ番号、sortは並べ替え順であることが推測できます。
pageパラメータの値を3にしたところ、推測通り3ページ目を読み込むことができました。

プログラムからスクレイピング

上記urlのページを変えてアクセスすることで、1ページから100ページまでプログラムからアクセスすることができることが分かりました。各ページ12冊の本が表示されるため、最大で1200位までの本の取引をモニタすることになります。
それでは、ランキングのページからISBNを抽出してみましょう。
ランキングのページのhtmlの構造を解析したところ、div要素の、id=順位 - 1のタグに含まれる事が分かりました。
そこで、スクリプト用ライブラリのenliveを用いて、各ページから順位とISBNを取得する関数を下記のように定義しました。


  • net.cgrand.enlive-html/html-resource関数: 引数のurlをhtmlとして読み込む
  • clj-http.client/get関数: 引数のurlを読み込む。オプション引数は文字コード
  • clj-time.coerce/to-sql-date関数: java.sql.Date型に変換
  • clj-time.core/now関数: 現在時刻を取得
  • net.cgrand.enlive-html/select関数: 指定したタグの値を取得

上記関数で取得したISBNをRDBMSのUSED_RANKテーブル(日付、ISBN、ランキング)に保存し、まずはモニタリング対象となる本を登録することができました。

今回の作業は以上。最後までお読み頂き、ありがとうございました。
たなけん(作業時間1時間)

マーケットモニタリングアプリの開発(1): 概要

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
しばらくマーケットモニタリングアプリの開発に没頭していました、たなけんです。
本エントリでは、マーケットモニタリングアプリの概要について記載します。

事の発端

クラスメイトとの雑談で、古本の流通について話題となりました。そこで私は、日本では個人がアマゾンに本を出品できることを紹介しました。すると友人は、『どんな本が、どれくらいの値段で売れるのか、自動的にデータを取れないかな? データが取れるとどんな本をいくらで出品するのが良いか分かるね。』とアイデアを提案してくれました。
そこで、Clojureでプログラムを作成し、アマゾンマーケットプレイスでどのような本が売れているのかのデータを取る事にしました。

処理の流れ

売れ筋の本の方が、中古本であっても回転が早いだろうと仮定し、まずはベストセラーランキングから本のISBNを取得し、その後、そのISBNをキーに取引情報(sellerIdとisbnで一意に識別)を取得します。
取引情報を継続して取得し、公開されている取引情報が消えた時点で、その取引が成立したと見なし、成立取引一覧に取引情報を移します。
成立取引一覧のISBNから本の属性(ジャンル、出版日)や値引率などを分析し、どんな本がどれくらい売れるのかを求めます。

今回の作業は以上。最後までお読み頂き、ありがとうございました。
たなけん(作業時間15分)

2012年9月13日木曜日

第3イテレーションの振り返り

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
肩甲骨のストレッチの効果か、姿勢が良くなったと最近言われた、たなけんです。
本エントリでは、第3イテレーションを振り返ります。

Datomicおよび各種ライブラリを利用した所感

長所

Clojureで書かれている製品である為、クエリにそのままClojureの式(自作の関数も含む)を使う事が出来る

Clojureで書かれている製品である為、Clojureのデータをそのまま収納する事が出来る

原理的にはスケールアウトが可能
クエリおよびデータの追加、変更がほぼClojureのS式である(Clojureネイティブである)点が唯一にして最大の長所だと思います。RDBMSを利用していると、例えばSELECT文ではSQLの書式に従い、SQLの関数を利用して結果を得て、そこからClojureのデータに束縛し直す必要があります。しかし、Datomicではfindの条件にそのままClojureの関数が使えるため、SQLとClojureのデータを行き来するような処理は必要なく、手早く開発することができました。

短所


  • 無料版ではfreeおよびmemプロトコルのみであるため、スケールアウト性能を検証することができない
  • BIツールのように複数のテーブルを結合するなど、様々な角度からデータを解析する方法が確立されていない
  • 集約系の関数など、自力で実装しなくてはならない

RDBMSであればスタースキーマなど、分析対象のデータを多次元的に扱う手法が確立されています。Datomicの柔軟なクエリ構築力を考慮すると、恐らく良い実装方法があるのだろうと、ぼんやりとそのポテンシャルは感じたのですが、今の時点では具体的な方法までは見えていません。

短所としてBIツールの様な多次元表の利用を挙げましたが、「プログラマブルなクエリが書ける、マクロも書ける」というDatomicの潜在能力を引き出せば、SQLを使うよりもスマートにこれらのソフトウェアを実装することができると(根拠は薄弱ですが)直観しています。

Webアプリケーションを一通り書いてみて気付いたこと(およびClojure愛)

これまで、主なClojureの使い道はツール作成でした。しかし、今回はプレゼンテーション層からパーシステント層までClojureを用いて、小さいながらもWebアプリケーションを完成させることができました。そこで気付いたことを振り返りたいと思います。

自転車あるいは糊

Clojureは私にとって最も手に馴染んだプログラミング言語です。そのしっくり来る感じを例えると「自転車」です。気軽に、どこへでも、最短距離で移動できる乗り物です。
他のプログラミング言語を同様に例えるとすれば、Cは飛行機、Javaは鉄道、Pythonはバスでしょうか。それぞれに利点はありますが、家の裏の公園に行く為に、飛行場を作ったり、線路を引くのは、得たい結果に対して労力が釣り合わない気がします。その点Clojureは行きたい場所へ、そこが車さえも入り込めない路地であっても、最短経路でたどり着くことができます。
また、目的地が遠ければ、鉄道や飛行機を乗り継いで行けばいいのです。駅と飛行場の間は自転車で移動し、最後のバス停から終着地点までの間だけ自転車に乗る事もできます。これは必要に応じてCやJavaで書かれたアプリケーションやライブラリをClojureから使って、目的の機能を実現している時の、僕の頭の中にあるイメージです。
実際、ブログでも紹介したTesseractやImagemagickをClojureから操作し、H2 Database Engineへデータを格納後、帳票を出力するツールの実装は、この乗り継ぎの比喩の良い実例と言えるでしょう。そしてWebアプリケーションに関しても、一から書いたコードは少なく、殆どはライブラリが提供する機能をつなぎ合わせたものでした。
多くの人はこう言うでしょう。「それは自転車ではなくて糊だよ」と

マクロ

自転車の例えはまだ続きます。車のエンジンをバラしてまた組み挙げられる人はどれくらい居るでしょうか、またそれに掛かる時間は?工具は?
バラして組み直す事、これはすなわち言語そのもののハックのしやすさの比喩といえます。
Clojureはシンプルです。特殊形式とマクロと関数しかルールが無いと言っても良いでしょう。構造が簡潔であり、なおかつユーザが手を加える余地を十分に残しています。マクロは、簡単に言えば言語の構文を規定し直す機能です。私は多用はしませんが、「いざとなればマクロでなんとでもできる」という信頼感があります。メカニズムを把握していて、そこに手を入れることができる感覚、それは自転車いじりに似ています。自動車のエンジンや、電車のモーターは、固そうですし、私には複雑過ぎます。
マクロの存在がClojureをシンプルかつ柔軟にしており、マクロがあるため僕はClojureを信頼して使い込む事ができています。この感覚が、やはり私にとって自転車なのです。

万人の自転車へ

Clojureが私にとって自転車である事、それは多くの人にとってどうでも良い話だと思います。しかし、Clojureは他の人にとっても自転車となり得る言語だとしたら?
私はJavaのアプリケーションやライブラリを鉄道に例えました。同様にClojureのライブラリは地下鉄や高速道路網と例えても良いかもしれません。多くの人が利用する点から点への移動には、より効率よく移動するための道が敷かれるからです。そして、それら全ての乗り物に、だれでも自転車を携えて乗ることができます。
このブログを読まれた方が、「Clojure使ってみようかな」と思ってもらえるように、これからもClojureの魅力を伝えていきたいと思います。

私に足りないもの

自転車は簡単に乗れますが、奥が深い乗り物です。フォームの善し悪しで、疲労度が大きく変わります。
私はこれまで、全くの我流でコードを書散らしてきました。自転車で言えばがむしゃらに漕いでいる状態です。
Webアプリを設計、開発する中で何度も「どう書くのが関数型言語の特性を活かしているのか?」と自問しつつも、まず動く物を優先して、ここまで漕ぎ進めて来ました。
当初の目標であったプレゼンテーション層からパーシステント層まで実装を終えた今、次に何をすべきかと考えました、私には何が足りないのだろうか?と。
そこで考え至った結論が、フォームの改善です。プログラミングの基礎です。

年内の目標

コンピュータ書の古典"SICP(計算機プログラムの構造と解釈)"の原著が本家サイトから無料で読む事ができます。関数型プログラミングのエッセンスを掴むべく、このSICPの原著を年末までに読み切りたいと考えています。
学習記録をブログに綴る事で、読者の皆様にも関数型言語でのプログラミングの公理のようなものをお伝えできればと考えています。

運用フェーズに向けて

Webアプリの開発フェーズはほぼ終了しましたが、まだこのプロジェクトは終わっていません。そうです、Herokuにデプロイしてサービスを公開、運用ノウハウを蓄積するというタスクが残っています。また、運用しながらメンテナンス性を高める為にリファクタリングしたり、ログ解析ツールそして機能追加など、改修のアイデアはまだまだあります。
SICPリーディングと平行して、Webアプリプロジェクトも継続していきます。

今回の作業は以上。最後までお読み頂き、ありがとうございました。
たなけん(作業時間1時間)


2012年8月19日日曜日

Webクライアントのテスト

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
先日、魔女の宅急便を見ました。映画の最後で語られる「おちこんだりもしたけれど、私はげんきです」のメッセージに、とても励まされた、たなけんです。(ダイエットに挫折しそうになっていたため。。。)
本エントリでは、Webクライアントのテストについて記載します。

Webクライアントのテストの位置づけ

Webクライアントのテストの為に、今回テスト手法やテスト用ライブラリなどを調査しました。その結果、いくつかの興味深いフレームワークやライブラリ、ツールを見つけることができました。
しかし、今回のWebクライアントは

  • ソースコードが実質20行程度と非常に短い
  • 条件分岐がなく一本道のロジックである

ことから、それらのライブラリを利用してテストする程ではないと考えました。
本来であれば、クライアントのメソッド単位で、まずは単体テストを実施し、その後ユーザの操作フローに基づいた結合テストを実施します。また、正常系だけではなく、異常系も漏らす事無くテストするのが本来のテストの姿であると考えています。
しかしながら今回は、Webクライアントの機能が十分すぎる程シンプルであるため、テストの目的を、デグレーションの検出に限定して考えたいと思います。

テストプログラム実装方針

正常系の動作を自動実行し、以上が発生しない事を確認する。
ライブラリとしてSeleniumをラップしたclj-webdriverを利用する。

依存ライブラリのダウンロードの問題

project.cljにclj-webdriverを利用するよう記載し、lein depsを実行したところ、bcprov-jdk15on-147.jarおよびbcpkix-jdk15on-147.jarのダウンロード時に、チェックサム例外が発生し、Leiningen経由では上記2ライブラリがインストールできませんでした。
そこで新規Mavenプロジェクトを作成し、Seleniumの依存ライブラリをインストールしたところ、問題なく上記2ライブラリをインストールすることができました。
私の環境ではLeiningenとMavenでライブラリを共有しているため、この方法で解決をすることができました。
また、Maven利用の前にlein-localrepoによるfloating jarのローカルインストール(Mavenの3rd party jarのインストールのようなもの)を試してみましたが、こちらは上手くいきませんでした。

テストコード



  • doマクロ: 手続き型のプログラミング言語のように、以下のS式を順に処理する
  • clj-webdriver.taxi/set-driver!関数: ブラウザを起動し、引数のurlを開く
  • clj-webdriver.taxi/implicit-wait関数: 指定ミリ秒処理を停止する
  • clj-webdriver.taxi/input-text関数: テキストボックスに引数の文字列を入力する
  • clj-webdriver.taxi/click関数: 引数の要素をクリックする
  • clj-webdriver.taxi/find-element関数: 引数で指定された要素を取得する。要素はxpathなどで指定が可能


clj-webdriverの感想

依存ライブラリのダウンロードで問題が発生するなど、アルファバージョンにつきものの不安定さはありました。
その反面、一度インストールしてしまえば、非常に短いコードでSeleniumを用いたテストを記述することができました。
業務ソフトウェアをClojureで書くよう周囲を説得するのは難しいと思います。しかし、clj-webdriverのように、テストツールとしてClojureを導入するのは、非常に現実的な選択肢ではないかと、clj-webdriverを使ってみて強く感じました。
(通常の単体テストも、JUnitの代わりにテストだけClojureで書くことも出来そうですね)

今後利用してみたい、Javascriptテストの技術要素

今回のテスト(そもそもロジックがない)で利用するにはオーバースペックでしたが、Clojurescript (Javascript)のテストに関連する様々なフレームワークやライブラリ、ツールについても多少調査したため、この場を借りて紹介します。

Jasmine

Javascriptテスティングフレームワークの大本命。
Google Closure Library (Closurescriptを影で支えているJavascriptライブラリ)はJsUnitを公式テストフレームワークとして採用しています。しかし今やJsUnitはメンテナンスされておらず、JsUnitのサイトでもJasmineへの以降を推薦していました。
Clojurescriptをテストする方法が、Odyssomayさんのブログに分かりやすく解説されています。(なぜClojurescriptをビルドするためのスクリプトがPythonで書かれているかは追求しません。。。)

Sinon.js

Javascriptの柔軟性を存分に活かした黒魔術のようなライブラリ。単体テストの際、関連オブジェクトを差し替えてテストしたいといった要望は多々あるかと思います。(テストするクラス以外は、単純にある値を返して欲しいなど)
Sinon.jsはオブジェクトのスタブ化、モック化またフェイクサーバやフェイクタイムなどを提供し、オブジェクトを差し替えたいといった要望に応えてくれます。
モックあるいはスタブ化関数で処理することで、テスト対象以外のオブジェクトは、メソッドインタフェースは普遍のまま、振る舞いをテストに都合の良いように変えることができます。
同じ様なコンセプトのライブラリ、是非ともClojureにも欲しいなあと感じました。(JavaでSpring frameworkなど使えば、同様の機能は実現可能ですが、Clojureの持つ柔軟な言語特性を活かしたライブラリがあればもっと手軽に実現できそうなので)

PhantomJS

Javascriptのテストライブラリはブラウザから実行することが多いのですが、ブラウザの起動や動作までサポートするライブラリはあまりありません。
PhantomJSはコマンドラインから起動でき、読み込んだJavascriptを実行することができるブラウザです。(内部で、WebKitエンジンを利用しています)
PhantomJSを利用することで、コマンドラインからJavascriptをテストすることができ、単体テストの自動実行が容易になるかと感じました。

今回の作業は以上。最後までお読み頂き、ありがとうございました。
たなけん(作業時間30分)

2012年8月18日土曜日

画面デザインの改善

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
ダイエットを続けて半年、やっと2キロの減量に成功したものの、気がつけば1キロリバウンドしてしまい、意気消沈のたなけんです。
本エントリではTwitter Bootstrapを利用した、Webページのデザイン改善について記載します。

Twitter Bootstrapとは

Twitter社が提供しているCSSフレームワークです。
デザインが苦手なプログラマでも、見栄えの良いWebサイトが作れるとの評判なので、今回作成中のWebアプリケーションに組み込んでみました。

ナビゲーションの追加

今回の要件では、画面そのものがシンプル極まりないため、デザインを取り入れる要素があまりありません。そこで、機能毎に画面遷移するためのナビゲーションを追加することにしました。
実装方法として、ナビゲーションとiframeからなるindex.htmlを作成し、ナビゲーションのクリックイベントをにより、iframe内のベージがそれぞれの機能のページ(例dictionary.html、spelling.html)に切り替わるようにしました。

実装結果


未だ地味な感じは否めませんが、無味乾燥だった画面が、少しまとまった気がします。

ソースコード



  • 6行目: ダウンロードしたBootstrapのCSSを利用
  • 9-10行目: ナビゲーションへのクリックイベントに対応した動作(jQuery使用)
  • 14-30行目: ナビゲーションの描画
  • 32行目: iframeに各機能のページを割り当て(初期値はdictionary.html)


今回の作業は以上。最後までお読み頂き、ありがとうございました。
たなけん(作業時間45分)

2012年8月12日日曜日

Clojureで帳票処理(csv読み書き、RDBMS利用、グラフ描画、PDF出力)

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
授業が始まってからグログ更新が滞っていた、たなけんです。
本エントリでは、Clojureを利用した帳票処理について記載します。

事の発端

現在、大学院で会計を専攻しているのですが、任意科目でいくつかのMBA専攻のクラスを受けています。(前期までに、ほぼ会計は履修したため、今期は75%がMBAのクラス)
その履修しているMBAクラスのひとつに、企業戦略を立案するクラスを履修しています。
面白いことに、このクラスの成績は、シュミレーションゲーム上のスコアにより決定されます。(クラスのメンバーを8チームに分け、チーム間で競争することとなります。)
決定すべき項目として、製品開発(高機能戦略や低価格戦略)、マーケティング(世界を4地域に分け競合の出方を伺いながらどのエリアを攻めるか)、生産(工場の人員配置や設備投資など)、財務(株式発行、社債発行など)などがあり、毎週50項目ほどのパラメータを検討して、事業戦略を実装し、他チームと結果を競い合っています。
各チームが決定する50項目のうち、27項目は年度末(実際は毎週日曜日)に結果とともに全チームに公開され、翌年のパラメータ検討の際の参考資料とすることができます。
他チームが見る事のできるパラメータは27項目なのですが、それがチーム毎(8)、地区毎(4)、四半期毎(4)で公開されるため、結果として毎年3,456(=27*8*4*4)項目に目を通すこととなります。また、年間の比較を考えると、1年(1週間)毎にデータが3,456項目ずつ増えることになりますので、数値だけを見て比較するのは困難であると考えられました。
そこで、数値の変化を、各社、各地域で比較出来るようグラフを作成することとなりました。

仕様

入力: 会社、地域ごとに1csvファイル。行は項目、列は四半期ごとの数値が記載されている。
出力:1項目1ページ、1ページに各地域のグラフを縦に配置、1グラフに8社と平均値を表示、横軸は時間、縦軸は値。

出力例
製品販売価格



数値をグラフにすることにより、各チームの意思決定が比較しやすくなっているのが分かると思います。例えば、EA市場ではほとんどのチームが価格を他の地域より高めに設定していること、また、year7に突然ピンクチームがAP、LA、NA市場で価格を高く設定したことなどがこのグラフから読み取れます。

実装

全ソースはtana-kenのGithubにて公開しています。
興味を持たれた方は是非ご覧になって下さい。
以下、ポイントを絞って、実装内容を紹介します。

nsマクロ

https://gist.github.com/3331553
ライブラリとしてclojure.java.io、clojure.data.csv、clojure.java.jdbc、incanter.core、incanter.chartsを利用します。

csvファイル読み書き


ファイルサイズが十分に小さいため、遅延シーケンスとして処理をせず、doallにより全データをメモリ上に読み込んでいます。

行列入れ替え


元ファイルは、列方向にデータが追加される仕様であったため、行方向にデータが追加されるよう、行と列を入れ替える処理を実装しました。

RDBMS利用


組み込みRDBMSとしてH2 Database Engineを採用しました。
csvファイル読み込み同様、想定される取得データが十分小さいため、doallにより全データをメモリ上に読み込んでいます。
また、今回はテーブルを結合する必要がないため、H2 Database Engineのcsvファイル読み込み機能を利用しました。(csvファイル読み込み -> 整形 -> 1ファイルに結合 -> H2 Database Engineにてテーブルとして利用)

グラフ描画


incanterを通じてjfreechartオブジェクトを作成しています。
RDBMSからグラフ描画に必要なデータセットを取り出し、グラフを描画します。

nsマクロ


incanterで利用しているjarと依存関係で不整合があったため、プロジェクトを分けました。ライブラリにはclj-pdfを利用しています。

内容作成


タグ付けされたベクタにて要素を構成しています。
sort-by関数により、ページを制御しています。

PDF描画


pdfマクロにて、与えられた内容をpdfファイルとして出力します。

今回の作業は以上、最後までお読み頂きありがとうございました。
たなけん(作業時間4時間)

2012年7月29日日曜日

Webクライアントの実装(3)

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
鳥のさえずりで、毎日優雅に目覚めている、たなけんです。(私の住んでいるキャンベラは人よりも大型の鳥の方が数が多いようで、叫び声に似た鳴き声で毎日起こされています。)
本エントリでは、Clojurescript(というかClosure Library)でのログ出力の方法および、これまで作成したWebクライアントの、ロジックの分離について記載します。

ログ出力の設定

Closure Libraryではログ出力の為のクラスを提供しており、それをインスタンス化するだけでログを出力することができます。
また、ログの出力先をコンソールにするなど、コンソール環境を整えるクラスのスタティックメソッドを用いて、ログ出力環境を設定することができます。
コードは、本エントリ末尾に掲載します。

ロジックの分離

ロジック分離前のソースコードでは、サーバから渡されたデータをさらにgoogle visualization apiのDataTableクラス用に加工していました。このデータ変換は、クライアント側で行う必要性が薄いため、サーバ側でクライアントが必要するデータの形式に変換するようにしました。
また、clj->js関数については非常に汎用性が高い関数(標準ライブラリに入っていても良さそう)であるため、名前空間my-dictionary-client.utilに移動しました。

ロジック分離後のソースコード(クライアント)


ログの出力設定後、google visualization apiを読み込み、読み込み後にinit関数を呼び出します。init関数でdictionary-button要素のonClickイベントとdictionary-request関数を結びつけ、ボタン押下時にサーバと通信し、結果を表示します。
ロジックを可能な限りサーバ側へ寄せたことで、クライアント側での処理をライブラリの利用準備とユーザの操作への応答のみに限定することができました。
サーバおよびクライアントの全ソースコードは、githubにて公開していますので、関心のある方は是非ご覧になって下さい。

今回の作業は以上。最後までお読みいただきありがとうございました。
たなけん(作業時間30分)

Clojurescriptでrepl

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
Clojurescriptの深みに日々はまっている、たなけんです。
本エントリでは、Clojurescriptでのrepl使用方法を記載します。

Clojurescriptのreplの種類

Clojurescriptでは、以下の2種類のreplを利用することができます。

  • Rihno環境
  • Webブラウザ環境

今回は、ブラウザ上でのClojurescriptの挙動を確認するため、後者のWebブラウザ環境でのreplの使用方法について記載します。
Webブラウザ環境のreplでは、cljsbuildプロセスが入出力を処理し、Webブラウザプロセスが入力されたS式を評価します。

cljsbuildによるrepl利用の準備

cljsbuildはコンパイルだけではなく、replの起動、テストの実行といった機能も兼ね備えています。しかし、Webブラウザ環境でreplを起動するには、接続用のhtmlを読み込むClojurescriptおよび接続用のClojurescriptが必要となります。今回はClojurescriptのwikiを例として取り上げますが、実際に開発しているアプリケーションに、数行付け加えるだけでも、Webブラウザ環境のreplを使用することができます。
下記で示される、コードはClojurescriptのrepl利用の手引きからの引用となります。


htmlファイル


何の変哲も無い、ただ接続用のClojurescriptを読み込むだけのhtmlです。
しかし、1点だけ注意事項があります。それは、必ずボディ部でscript要素を宣言しなくてはいけないということです。
私は当初ヘッド部でJavascriptライブラリの読み込みを宣言しており"Type error: parentElm is null"というエラーに悩まされてしまいました。

接続用のClojurescript


clojure.browser.replを利用し、cljsbuildで起動したポートへ接続します。
clojure.browser.repl/connect関数: 引数のurlへ接続し、replへの入力を受け付ける

起動から接続まで

以下の手順によりreplを起動し、入出力プロセスと評価プロセスを接続します。

  1. コンソールを起動、cljsbuildを利用しているプロジェクトのルートへ移動
  2. コンソールから、lein trampoline cljsbuild repl-listenと入力し、replを起動
  3. Webブラウザを起動し、接続用htmlを読み込む
  4. 同じWebブラウザからurl(デフォルトlocalhost:9000)へアクセスし、cljsbuildのreplと、Webブラウザの接続を確立(接続用のhtmlファイル名がindex.htmlではない場合(例. not-index.html)、urlはhttp://localhost:9000/not-index.htmlのようになる)

replの利用

接続が確立された後は、コンソールから評価したい式を入力することで、ブラウザのdom要素等を操作することができます。
また、load-namespace関数を使うことで、クラスパス内の任意のClojurescriptファイルを読み込むことができます。

今回の作業は以上。最後までお読み頂きありがとうございました。
たなけん(作業時間45分)

2012年7月27日金曜日

Webクライアントの実装(2)

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
新学期が始まり、そろそろ会計とマネジメントの授業に集中せねばとプレッシャーを感じている、たなけんです。
本エントリでは、Google visualization APIを利用したUIの実装について記載します。

Webクライアントの実装(2)

Closure Libraryでは多彩なUIコンポーネントが用意されています。しかし、Closure LibraryのUIコンポーネントはややオーバースペックであるため、Google visualization APIを利用し、表形式で結果を表示したいと思います。

htmlへの追記


Google jsapiを利用するため、下記の内容をindex.htmlのヘッダ部に追記しました。

データの変換


JSONをClojureオブジェクトへ変換する関数です。
semperosnのgistで公開されていた関数をコピーさせて頂きました。

google visualization API読み込み


ライブラリを読み込み、読み込み後にinit関数を実行するよう設定します。

  • google/loadメソッド: ライブラリを読み込む
  • google/setOnLoadCallbackメソッド: ライブラリ読み込み後に実装する関数を指定


表データの作成


サーバから返された値から、google.visualization.Tableクラスのコンストラクタが要求する形式のデータを作成します。

表の描画


div要素resultに表を描画します。
  • js/クラス名 特殊形式: 指定されたクラスをJavaScriptのオブジェクトとして利用する
  • google.visualization.Tableクラス: テーブルを描画するクラス。引数に、描画する位置となる要素を指定する
  • google.visualization.DataTableクラス: データを司るクラス。引数にデータとなるJSONを指定する

今回の作業は以上。最後までお読み頂きありがとうございました。
たなけん(作業時間45分)

2012年7月25日水曜日

クライアント/サーバ間通信でのトラブル

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
最近になってビリーズブートキャンプに入隊した、たなけんです。
本エントリでは、クライアント/サーバ間通信でのトラブルとその解決方法について記載します。

現象の整理

Webクライアントからサーバにアクセスした際、あるブラウザ(Safari)では期待通りの結果が表示されるが、他のブラウザ(Chrome、Firefox)では期待通りの結果が表示されませんでした。
表示されない原因として、サーバから返されるhttpレスポンスのボディ部に、ブラウザ毎で下記の違いがありました。

  • Safari: httpレスポンスのボディ部にサーバから返されたデータが設定されている
  • Chrome & Firefox: httpレスポンスのボディ部に何も設定されていない


クライアントを疑う

ClojurescriptでのWebクライアントの実装は初めてだったため、もしかしたら何かバグを踏んでいるのではないかと思い、極力シンプルな2つのテストを実施しました。

  • ブラウザから直接アクセス: すべてのブラウザで期待した結果が得られた(リクエストのボディ部に設定したJSON文字列が表示された)
  • jQueryを用いたAjaxクライアントの利用: Clojurescriptと同様、Safariと他のブラウザで異なる結果となった

クライアントコード

これらの結果から、問題はクライアントの実装ではないと判断しました。

サーバ側を変更してみる

Compojureとブラウザ側のXmlHttpRequestとの相性問題などの可能性を考え、2つの異なるhttpサーバを用いたコードを作成し、各Webブラウザより先述したクライアント(jQuery版)からアクセスしたところ、下記の様な結果となりました。

  • Bishop (clojure/ringベースの別のwebサーバ(Web Machineクローンで、Webサービス提供用に機能を特化している)): Clojurescriptと同様、Safariと他のブラウザで異なる結果となった
  • restify (node.js上で動作するWebサーバ用ライブラリ): すべてのブラウザで期待した結果が得られた

Compojure同様clojure/ringベースの別のwebサーバであるBishopを用いても問題は解決せず、node.jsベースのrestifyでは問題なく動作することが分かりました。

トラブルの原因と解決方法

ブラウザからローカルのファイルにアクセスする場合には、ブラウザの起動オプション等を変更する必要があるという様な話は以前より知っていましたが、今回の現象はローカルのWebサーバへのアクセスなので、ブラウザの起動オプションを変更しても問題は解決されませんでした。
通常の開発と今回のとの相違として、httpサーバにアクセスしてindex.htmlを取得し、それをブラウザから操作するのではなく、ローカルで作成したindex.htmlをブラウザから直接開いて操作しているという点に思い至りました。つまり、サーバとしては自分がホストしているドメインとは異なるドメインからアクセスを受けたと認識している訳です。
そこで、外部ドメインからのアクセスを許可するようサーバ側のコードを変更しました。具体的にはhttpヘッダに"Access-Control-Allow-Origin" "*"を追加するよう改修しました。
改修の結果ChromeおよびFirefoxでも期待通りの結果を得ることができました。
今後クライアントサイドMVCフレームワークの流行等で、サーバとクライアントを切り離して開発することも増えるかと思います。その際、同様の問題が発生した場合には、サーバ側でAccess-Control-Allow-Originが適切に設定されているかどうかを確認すると良いという貴重な教訓を得ることができました。


今回の作業は以上。最後までお読み頂きありがとうございました。
たなけん(作業時間120分(トラブルシュート含む))

Webクライアントの実装(1)

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
昨日美味しい生牡蠣を腹一杯食しご機嫌の、たなけんです。
本エントリでは、Clojurescriptを利用したWebクライアント開発について記載します。

Clojurescriptとは

Clojurescriptとは、ClojureでJavaScriptアプリケーションを開発するためのライブラリ群です。CoffeeScriptやJSX同様、書かれたプログラムをJavaScriptにコンパイルすることによって、アプリケーションをJavaScriptが動作する環境(webブラウザやnode.jsなどのサーバ上)で動作させることができます。

なぜClojurescriptなのか

JavaScriptの言語仕様(変数スコープ、プロトタイプ方式オブジェクト指向など)に馴染めないこと、Clojureスタイルでのプログラミングが私にとって最も効率が良いということからClojurescriptを利用することにしました。
また、ClojurescriptはGoogle Closure Toolsを利用しているため、Closureが提供するクラス方式のオブジェクトシステムや、多彩なUIコンポーネントが利用できる点も魅力でした。

Clojurescriptの導入

ひなたねこさんの記事を参考にlein-cljsbuildを導入しました。lein cljsbuild auto としておけば、core.cljsを更新したタイミングでJavaScriptにコンパイルされます。(他のツールは必要なく、lein-cljsbuildだけで完結している点が素晴らしいです)
また、emacsのClojurescript-modeはELPA経由でインストールしました。
Clojurescript用のreplもemacsから利用可能な様でしたが、今回は出力されたJavaScriptを見てデバッグを行いました。(時間を見つけて、Clojurescriptのreplも試そうと思います)

Webクライアントの実装(1)

プロジェクトファイル


プラグイン部でlein-cljsbuildの利用を宣言します。また、closure compilerで用いるコンパイルオプションをcljsbuild部で指定します。今回は生成されるJavascriptの可読性を重視したため、最適化はしない方針としました。

index.html


ヘッダ部でJavaScriptファイルを指定し、ボディ部の最後でmain関数を呼び出しています。また検索語を入力するフォーム、確定ボタン、結果表示用のdiv要素を宣言しました。

nsマクロ


通常のClojureとの違いとして、ClojureからJavaのクラスを利用する場合は:requireではなく:importを使用するのですが、ClojurescriptからClosure Libraryのクラスを利用する場合もClojureのライブラリ同様:requireで良いという点があります。
nsマクロでは、以下のライブラリの利用を宣言しました。
  • clojure.browser.event: ブラウザのイベントを操作するClosure Libraryのクラス群の薄いラップしたライブラリ
  • clojure.browser.dom: ブラウザのDOMを操作するClosure Libraryのクラス群の薄いラップしたライブラリ
  • goog.net.XhrIo: Closure Libraryが提供するJacascriptのhttpXmlRequestオブジェクトを操作するクラス


main関数


確定ボタンのクリックイベントをトリガーにdictionary-request関数を呼びます。

  • clojure.browser.event/listen関数: 引数に指定された要素、イベントによって第3引数で指定された関数が呼び出されるよう設定
  • clojure.browser.dom/get-element関数: 引数に指定されたシンボルのidに合致する要素を取得

生成されたJavaScript


dictionary-request関数


httpのGETメソッドによるリクエストを送信し、結果を引数にコールバック関数を呼び出します。
  • goog.net.XhrIo/sendメソッド: 引数のurlにhttpのGETメソッドによるリクエストを送信
  • clojure.browser.dom/get-value関数: 引数に指定された要素の値(今回の場合、フォームquery-wordに入力された文字列)を取得
生成されたJavaScript


dictionary-callback関数


httpレスポンスからJSONオブジェクトを取得し、create-list関数を用いて結果を変換し、変換された結果をdiv要素の子要素として追加します。
  • .-プロパティ名 特殊形式: JavaScriptオブジェクトのプロパティにアクセス(今回の場合entriesプロパティ)
  • goog.net.XhrIo/getResponseJsonメソッド: 取得されたレスポンス内のデータをJSONオブジェクトとして取得
  • clojure.browser.dom/append関数: 第1引数に指定された要素に、第2引数に指定された要素を子要素として追加
生成されたJavaScript

create-list関数


JSONオブジェクトを引数に取り、textプロパティから値を取得し、<ul><li>textプロパティの値</li> ... </ul>形式のdom要素を作成します。

  • clojure.browser.dom/html->dom関数: html形式の文字列からDOMツリーを生成


生成されたJavaScript

意外な落とし穴

実装を終えて早速クライアントからサーバへの疎通を確認しようと、ブラウザからアクセスしたところ、Safariでは問題なくレスポンスが処理されるが、Firefoxではレスポンスのボディ部が0バイト(サーバ側で設定したはずの値が、ボディ部に含まれていない)様な挙動を見せ、想定した通りの処理をすることができませんでした。
ブラウザ毎に異なる挙動はClosureライブラリで吸収されているはず、と思いながらも、ここから問題解決まで思ったよりも時間が掛かってしまいました。。。(次回に続く)


今回の作業は以上。最後までお読み頂きありがとうございました。
たなけん (作業時間90分)

2012年7月23日月曜日

第2イテレーションの計画

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。
『今やる、すぐやる、出来るまでやる』がモットーの、たなけんです。
本エントリでは、第2イテレーションの計画として、仕様および実装方針を記載します。


第2イテレーション(プレゼンテーション層/Webクライアント)の仕様

第2イテレーションで実装する機能の仕様は以下の通り。
  • 定義を取得したい単語をhttpリクエストを送信する
  • 外部APIからの抽出結果をhttpレスポンスとして受信する
  • 受信したデータを整形して

実装方針

  • クライアントはWebブラウザとし、Ajax通信によりサーバへ問い合わせる
  • クライアントプログラムの実装には、Clojurescript / Google Closure Libraryを用いる
  • CSSの作成にSCSS(Sass)を用いる

テスト方針

  • JsUnitを用いて単体テストを実施する
  • PhantomJSを用いて単体テストを自動化する
  • Seleniumにより結合テストを実施する


今回の作業は以上。最後までお読み頂きありがとうございました。
たなけん (作業時間10分)

2012年7月15日日曜日

第1イテレーションの振り返り

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。、たなけんです。本エントリでは、第1イテレーションを振り返ります。


第1イテレーションの振り返り

普段はツール開発にClojureを利用していましたが。今回のアプリケーション開発では、堅牢なアプリケーション開発のために以下の点を意識しました。

  • ライブラリの利用
  • ツールの利用
  • 実装


ライブラリの利用

多数のライブラリを利用しましたが、その中でも下記のライブラリについて利用した感想を簡単に紹介したいと思います。

  • clojure.tools.logging: ログ出力。副作用のある処理なのでdoと合わせて使うと便利
  • clj-xpath: xpath問い合わせ。完結かつ柔軟にxmlノードを抽出できて便利
  • clojure.test: テストコード定義。Leiningenからもテストが実行可能で便利


ツールの利用

実際にツールを利用した感想を以下に記します。

  • IDE: emacs。起動、終了が高速かつ、replを利用しながらテスト可能でありEclipceよりも使い勝手が良い印象
  • バージョン管理: git。特別な利用をしていないためSubversionなどと同様な印象
  • 継続的インテグレーション: Jenkins。まだ運用方法が未確立



実装

実装時に様々なClojureの機能や関数を利用しましたが、その中でも便利だったものを以下に紹介します。


  • 例外処理: gen-classを使用。Exceptionを継承することでアプリケーション例外を定義
  • 関数の公開範囲: 他の名前空間から呼ばれない関数はdefn-で定義
  • reduce関数: ネストされたハッシュから値を抽出する際に利用




今回の作業は以上。最後までお読み頂きありがとうございました。
たなけん (作業時間30分)

アプリケーションのテスト(3)

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。夜6時以降は炭水化物を摂取しない、たなけんです。本エントリでは、アプリケーションのテスト(3)について記載します。

アプリケーションのテスト(3)

関数の機能を変更したため、テストコードも変更しました。
テスト事項は以下となります。
  • interface-for-clientのテスト
  • call-apiのテスト
  • 抽出関数のテスト
また、以下のテストデータを追加しました。
  • test/data/test-dictionary.xml
  • test/data/test-thesaurus.xml
  • test/data/test-slang.xml
  • test/data/test-etymology.xml
  • test/data/test-example.xml
  • test/data/test-questionanswer.xml
  • test/data/test-synonym.xml
  • test/data/test-random-dictionary.xml
  • test/data/test-random-thesaurus.xml
  • test/data/test-spelling.xml
  • test/data/test-wotd.xml

interface-for-clientのテスト


httpのGETリクエストからcall-apiを呼び出し、正常に処理されることを確認します。

call-apiのテスト


url、パラメータ及び抽出関数を引数に、call-apiが期待する動作をするかどうかを確認します。

抽出関数のテスト


与えられたxmlから、期待される値が抽出されることを確認します。
また期待される値を定数として定義します。

テストデータの登録


Dictionary.comの各APIにアクセスした際に取得されるxmlを定義します。

今回の作業は以上。最後までお読み頂きありがとうございました。
たなけん (作業時間30分)

2012年7月14日土曜日

クライアント向けインターフェースの実装(2)

はじめに

おはようございます。当ブログにアクセス頂き、ありがとうございます。好きな言語は?と聞かれたら、Clojureと即答する、たなけんです。本エントリでは、プレゼンテーション層とアプリケーション層とをつなぐ、クライアント向けインターフェースの実装について記載します。

クライアント向けインターフェースの実装(2)

前回リストアップした以下の項目に従い、各関数を修正します。
  • interface-for-clientへのリクエストの処理を追加
  • 関数を引数に取り、抽出結果のJSON文字列を生成する関数の追加
  • 利用APIに対応した抽出関数の追加

interface-for-clientへのリクエストの処理


urlリソースと関数を関連付けます。例えば、http://localhost/dictionary/testへアクセスすると、引数のwordに"test"が拘束された状態で、call-apiが呼び出されます。

  • compojure.core/defroutesマクロ: urlリソースを定義
  • compojure.core/GETマクロ: http GETメソッドによりアクセスされる節を構成
  • call-api関数: url、パラメータリストおよび抽出関数を引数に取り、JSON文字列を生成


抽出結果のJSON文字列を生成する関数


抽出関数を引数に取り、Dictionary.comから取得したxmlから必要な情報を抽出した結果のJSON文字列を生成します。

  • ->マクロ: 左の関数を評価した結果を右の関数の引数とし、順次関数を実行
  • build-url-with-prms関数: urlパラメータのリストからurl文字列を生成
  • get-body関数: 引数のurlへhttpリクエストを送信し、そのhttpレスポンスのbody要素を取得
  • extract-function(引数): 関数呼び出し時に指定される抽出関数
  • clj-json.core/generate-string関数: clojureオブジェクトをJSON文字列に変換

抽出関数


xpathによりxmlからノードを取得し、さらにそこから指定した要素を抽出します。

  • safety-xpath-call関数: xpathによりxmlからノードを取得する。指定したxpathが取得出来なかった場合、handle-exception関数を呼び出す
  • get-result関数: safety-xpath-call関数により取得したxmlノード(ネストした状態のハッシュ
  • )から、順にキーを指定して、求める値を取得する
  • get-query-word関数: xml内に含まれる、問い合わせ単語を取得する。具体的にはxpathが(/*)[1]のノードから、キー:attrs :queryの値を取得する。
  • extract-dictionary関数: 英英辞書APIから取得したxmlから、問い合わせ単語と定義を抽出する。
  • extract-example関数: 例文辞書APIから取得したxmlから、問い合わせ単語と例文を抽出する。
  • extract-random関数: ランダムAPIから取得したxmlから、単語を抽出する。
  • extract-spelling関数: 綴り時APIから取得したxmlから、問い合わせ単語と綴り字の候補を抽出する。





今回の作業は以上。最後までお読み頂きありがとうございました。
たなけん (作業時間120分)