09

YAPC::Asia Tokyo 2014 行って来た

初めてYAPCに参加した。盆休みとか取っても無駄に時間を潰すだけだしなーとか思ってたところで、rebuild.fm で紹介(宣伝)されていたのとか、複数のperlユーザがここのところjavaを書いていていろいろ面白いことを言っているのを見かけたので、ちょっと perl コミュニティに興味が出て、参加してみた。perlは学生の頃に挫折して以来書いた事無いんだけど。

day0

18:40 - 18:50 - @papix / GeekDojo

GeekDojoを作る過程の話・・・だったのかな。

あまり高スキルでもないチームでサービス開発どうするか見たいな流れから「最初からテスト書いててよかった」みたいな話が出たと思ったのだけど、なんだか腑に落ちなかった感。しかしそのための仕組みをちゃんと作りあげてるのはえらいというかすごい。その仕組みのあたりで先達のブログ記事がすごく役に立ったと話していたけど、正直それを役立てられるのがうらやましい。

スキルの問題なのかなんなのか、個人的にブログなどの記事を参考にすると「これをこうするとこうなる」と書かれていると、そもそも「これ」自体が見つからないという事態に陥るのがしょっちゅうで、特に ops 周辺のプロダクトは仕事の合間に仕事環境に導入しようとしてだいたいがこのパターンで頓挫する。つらい。

18:50 - 19:00 - @hondallica / hrhm.info

http://www.slideshare.net/hondallica/yapcasia-2014

ハードロック・ヘヴィメタルの情報をとにかく集めたい話。

個人的にはday0一連のトークの中では一番いままで知らなかった世界をかいま見た感があった。MusicBrainzとか初めて知った。VM配ってるとかいうのも面白すぎる。

「情報をとにかく集める」といってとにかくいろんなサイトから集めているような話をしていたけど、どのくらいの時間費やしてコードを書いているのか聞けば良かったな。たくさんクローラー書いているんだろうか。

スライドの最後の一枚、よく言われていることなんだけど、なんだか妙に腑に落ちた。

19:00 - 19:10 - @ppworks / pplog

http://www.slideshare.net/naotokoshikawa/yapcasia2014pplog

READMEの横にPOEMを書いておいているらしい。ポエムがあるべきというのは rebuild.fm なんかでも言ってたかな。後から書けなくなるので、最初に必要だとか言ってた気がする。 サービスの声を聞くという表現が印象的だった。

フィーチャーテストを書いておくと、後から人がjoinしやすいみたいな事を言ってた気がするんだけど、スライドには無いな。勘違いだったかな。

19:10 - 19:20 - @syachi / ゴミ収集カレンダー

http://www.slideshare.net/syachi/yapcasia-2014-38474000

これうちの自治体向けにも作りたいと思った事がある。結構需要あるはずな割にあまりセマンティックなデータにならないイメージがある。

PDFをそのままなんとか解析するのではなくて、読み上げ用のテキストデータに着目したというのが最初のポイント。後の解析の話は、笑えたんだけど、以前の同僚が irc bot で似たようなこと(チャンネルの発言に対してマッチさせる正規表現を新しいケースが出る毎にメンテする)をやっていたのを見た事があるので、やっぱりそうなるか、という印象だった。9月に更新できているかどうか楽しみ。

ちなみに、札幌市のゴミ収集日カレンダー。PDFと読み上げ用データがそれぞれ公開されている。 http://www.city.sapporo.jp/seiso/KAISYU/index.html

我らが富山市は読み上げ用データなんて出してないなどうも。OCRと画像解析組み合わせてなんとかするしかないのか?

19:20 - 19:30 - @masuidrive / wri.pe

wri.pe 公開時のお話。

作りたいものリストを作っておいて、時間ができたときにそこから選んで作る、ということをしているとか。それでサービス公開までこぎ着けてしまう所を含め凄いなあと思った。

そういえば、個人的に少し前から作りたいものリストをつくっているのだった。が、振り返ってみるとどうも仕事関係のものばっかり。仕事のし過ぎなのか。

19:30 - 19:40 - @hika69 / プライベートで3年間チーム開発した話

http://www.storyboards.jp/viewer/u1g2d7

前半淡々と作ったサービスの紹介をしていたのだけど、作り続けている事がまずすごい。しかしチームでやる気のある人がやる気のあるときにやる、というスタイルらしい。「やる気がある状態はどっちかというとおかしい状態」という解釈からそうしていると言っていたけど、それにしてもここまでやれるのは仲間に恵まれている印象もちょっと受けた。

「スタジオを予約するのがリーダーの仕事」の下りはとてもぐっときた。

19:40 - 19:50 - @sugyan / ttyrecからGIFアニメを作る話

http://www.slideshare.net/sugyan/ttyrec

ttyrecの話は割愛。

seq2gifはCで書かれていて、ttyrec2gifはgo、で最終的にjavascriptでも実装してみている、という話。

結局プラットフォームはなんでもありだな、なのか、もうjavascript一本で全部いいんじゃないかな、なのか。言語の適材適所はもちろんあるんだけど、最近javascriptのカバーする範囲がすごく広くなってきていて、個人的に設計の際なんかに判断を迷ったりすることがあるんだけど、その印象がまた強くなった感じ。

19:50 - 20:00 - @razokulover / GIFMAGAZINEの話

https://speakerdeck.com/razokulover/gifmagazinefalsehua

普通ここはこうするよねというところでも、誰のためにつくるのかを掘り下げて、あえて逆の戦略を(ユーザーのために)取るべきという話だったと思っている。

何事もトレードオフという物があって、こちらを立てればあちらが立たないというのが世の中ではあるものの、そのバランスの支点自体を押し上げるのが技術の価値(のうちの一つ)だ。今の時代、コンテンツを作る人(実は別に人でなくても良いのだが)の原動力こそ価値になりつつある。生み出す側にフォーカスする事はすごく重要な事だと思う。

20:00 - 20:10 - @yositosi / togetter

togetterの話。経緯がおもしろかった。

でも@masason砲とか個人的にはちょっと遠い話かなあ?

リリース後初期に4000件とかまとめ作ってくれたヘビーユーザがいたらしい。でもこれも個人的にはあまり当てはまりそうにないレアケースかな・・・

20:10 - 20:20 - @debility / クイズを支える技術

一番笑えた。笑えたけど、サービス開発云々とはちょっとちがうような・・?

「暇なんですかっていわれる」って言ってたけどそりゃ言われるだろというか、デモ見ててなんでここまで作り込んでるんだ?って疑問が自然と出るくらいのクオリティだった。

day1

・・・このペースで書いていくと書ききる前に気力がつきてしまうので、申し訳ないけど後の事はざっくりと。 以下のトークを聞いた

  • Releasing perl ( Abigail )
  • 完成されたシステムなどない。完成された人間もいない。あるのは成長し続ける未完成なシステムと、それを支える未完成な人間だけだ (Kenji Naito)
  • 最近のウェブサービスの検索機能やその先の話 (Yusuke Yanbe)
  • Git を使ったツール開発(motemen)
  • コマンドラインツールについて語るときに僕の語ること(Taichi Nakashima)
  • いろんな言語を適材適所で使おう (Kentaro Kuribayashi)
  • WHERE狙いのキー、ORDER BY狙いのキー (yoku0825)
  • ウェッブエンジニアのローレベルプログラミング (cho45)
  • Java For Perl Mongers (Kazuhiro Osawa )
  • Lightning Talks

全体的にプラクティカルというか実装よりの話が多く聞いたので、かえったら俺も作ってみよう!と思わせる内容が多かった。以下特に書いておかなければならない事があるセッションがあるとすれば

Releasing perl ( Abigail )

リスニングするぜと思ってなるべくがんばって聞いていたのだけど結局ほとんど分からなかった。一応訳は聞いていたけど。

しかし同時通訳とはいえ、ちょっと難しそうだったのかな。このセッションの間にSawyer X がこの雰囲気ちょっと難しいな、見たいなツイートをしてたとおもうんだけど、それが印象に残っている。Sawyerのトークは途中というか、ほとんど最後の方しか聞いていないので、どうだったんだかわからないけれど。(でもDancer2のLTではがっちり掴んでたね)

あとやはり同時通訳のレシーバ1台最後まで回収できてなかったと思うし、いろいろ難しいんだなーという印象を持った。BTLEみたいなのを駆使して持ち出し管理できるといいのかな。まあ、取り組める問題はいっぱいありそう、な感じ。

完成されたシステムなどない。完成された人間もいない。あるのは成長し続ける未完成なシステムと、それを支える未完成な人間だけだ (Kenji Naito)

トーク自体は徹頭徹尾スピリチュアルな展開で壁紙が宇宙だったりアブストラクトなCGだったりしてどこに連れて行かれるのか分からない微妙な不安に会場が包まれていた。と思う。しかも予定時間の半分で終わってしまうという自由度。

トークの概要ではもうちょっと現場からの知見の話のような雰囲気だったので、完全に肩すかしだったんだけど、最初からこういう形を狙っていればまた別な結果になったのかもなあという気はした。

コマンドラインツールについて語るときに僕の語ること(Taichi Nakashima)

ベストスピーカー第3位おめでとうございます。

発表のスライドとか説明の順序とか、内容に沿って非常に整理された構成で、トークの内容云々よりまずそこにちょっと驚いた。それなりに数をこなしてきているからなのか、楽天の文化的なものだったりするのか、と氏のバックグランドがちょっと気になったりした。

内容も普段コマンドラインツールなんて作らない自分にはいざ作ろうと思ったときにとっかかりになりそうな実践的なところと設計に対するガイドラインを合わせてもらったような感じで有り難かった。

そう、なんかスライドがそのまま教科書として使えるんじゃ無いかとおもったんだった。

Java For Perl Mongers (Kazuhiro Osawa)

Java屋なのでJavaの話を聞きにきたぜ!とTweetした瞬間に「あまり習得の進捗がよろしくないので・・」みたいな事を言われてまた肩すかしかよという感じになってたんだけど、結局はJavaの話してたと思う。

Javaおかしいと思うかもしれないけどPerlも大概じゃん、みたいなノリで全体としてPerlから見たらそんなにJava変じゃないですよ見たいな話を終始してたと思うのだけど、なんでそんなJava dissに対する弁解みたいなことをわざわざ話してたんだろう、とこれを書いてる今になって思った。

day 2

以下のトークを聞いた

  • Plack for Fun and Profit (But Mostly Profit) (Sawyer X):終盤すこしだけ
  • Perl For (Non?) Perl Mongers (songmu)
  • Perl5 meta programming (karupanerura)
  • Mobile Application Development for Perl Mongers [ninjinkun x gfx]
  • そんなにビッグでもないデータ処理手法の話 (tagomoris)
  • Lightning Talks
  • Keynote (typestar)

実践的というよりは、ざっくりとした話が多かったかな。

Perl For (Non?) Perl Mongers (songmu)

プログラマ向けのPerlの紹介みたいな感じだった。結局のところプログラミング言語なんて適材適所ではありつつも、アプリケーション領域では明確に「これは駄目、あれがいけてる」みたいなのがなくなってきていてだいたいが枝葉末節の部分であーだこーだいってる、見たいな話で、まあPerlもいろいろ言われてはいるけど、結局住めば都なんだろうという気はする。逆に言えば、今住んでいる都からわざわざ引っ越すのがめんどいみたいな感じになってしまう。これは @yappo さんの発表で言っていたことなんだけど、このブログでも前に同様なことを書いてて、なまじ「同じようなもの」だとわざわざ覚える気がしなくなってしまう。

そういう意味では、おっさんになるともうその辺の言語に移行するほどの魅力を感じなくなってしまうのかな。

Mobile Application Development for Perl Mongers [ninjinkun x gfx]

普通のトークを二人分やって、残りがフリートークという構成。

二人分のトークをくっつけたせいか終始早口でフリートークも早口だったんだけど、なんだか最終的に「まあそこは課題ですね・・・」になってしまうあたりまで何となく読めてしまうあの不思議なノリは何だったんだろう。なんだかあんまりアドリブ感がなかったというかなんと言うか。rebuild.fmでなんとなく聞いたような話だったから?

けどあのフリートークまた違うネタで聞いてみたい。

そんなにビッグでもないデータ処理手法の話 (tagomoris)

こちらはベストスピーカー第二位。おめでとうございます。

内容としては実践的な細かい話ではなく、ここのところはやってきている大量のデータ処理(多分ビッグデータといわれるところとは若干趣向が違う)に関して、どのような事をするためにどんなプラットフォームがあるか、どう選ぶのかというようなお話。

この辺の話はわりと最近のWeb系の人たちは普段やってるような話なのかなと思っていたけど、人気が集まったところを見ると、そうでもなかったのかな。個人的には正直ギガバイトオーダーのデータ処理すらあまりする事が無いので、この辺全く知らないのだけど、最近よく流れてくるキーワードについて何となく大まかな地図が頭の中にできた気がする。

あと、このセッションもスピーカーの限界に挑戦するかのような早口で、一瞬エクストリームスポーツという言葉が脳裏をよぎった。

Keynote (typester)

@typesterさんの「壮大な自己紹介」。

30代でどうなってるか、20代で何をするかがとても大切みたいな話があって、はい分かってたよ、あー俺は、もう駄目だ。駄目だ。という感じになった。

まあそれはいいのだけど、結局何かしら専門的な能力が必要なのかねーというあたりが、ちょっと痛みを感じる。結局、今の自分には何かしら尖った知識ってのは無いからだ。

んで

懇親会は申し込み忘れたし、別な所へ飲みにいったりしててあまりPerlな人たちとコミュニケーションは取らなかったのだけど、総じて楽しかった。し、何か作らなくてはという気にさせてくれた。

いろいろ楽しい仕掛けもあって、運営さんはほんとに大変だったんだろうなあ。想像もつかない。ご苦労様でした。

次回もできれば参加したいけど、門外漢が人気のイベントの一席を占めてしまうというのも若干気が引ける所ではあるな。

intra-mart Accel Collaboration のスケジュール権限周辺を調べて見た

intra-mart Accel Platform (iAP) の権限周りに関しては、 ワタシハ認可(im-Authz)チョットデキル んだけど、intra-mart Accel Collaboration (iAC)の権限管理については疎かったので、マニュアルとAPIドキュメントベースだけどちょっと調べた。

version 7.x 以前のグループウェアとして提供されていたintranet Start Pack(iSP)と比べると、だいぶ違っててちょっと驚いた。

まず機能的な面でいうと、

  1. iSPでは管理者が設定する権限とは別に個人設定として、自分のスケジュールを誰に見せるとか見せないとか設定できたのだけど、それがなくなっている
  2. iSPでは更新可能/参照可能 見たいな権限レベルの並びに秘書権というレベルがあったのをiACでは代理という機能で補っている

が、肝心の権限設定においても概念的に以下のように異なっている。っぽい。

  • iSP:AがBのスケジュールを変更・参照する権限を付与(一方向)
  • iAC : AとBがスケジュールを共有する(双方向)

基本的にスケジュールの権限というのは共有グループというのを作って行う事になっていて、そのグループ内でデータは共有される(データ個別で非公開や登録者以外変更不可などの設定はあるものの、基本誰が触っても良い)という考え方。っぽい。見る限り。 この辺はIMBoxやワークスペースにその思想が色濃く出ているけれど、Accel Platform世代のアプリケーションの設計がトップダウンで一方通行なコントロールよりボトムアップで双方向なコラボレーションを意識して設計されているからなんだろう、と勝手に思っている。

しかしこういった違いがあるので、iSPでは設定できたけどiAPでは設定できないという領域は思ったより大きくなるかもしれない。とはいえ実用上問題になるかは別な話なんで、それが悪いかは分からない。 顕著に問題になるのはおそらく、 iSPの権限設定をなんとかしてiACに移行しようとすると、単純にはできないというところ。まあ、その需要は現時点では割と高いんだろうけど。

ClojureでHello World

前口上

基本的にJava屋で、たまにpythonを使っている。.NET は C#よりVB.NETの方が面白いと感じている。なぜかといえば、 なんとなく文法が似ていてJava -> C#という流れに魅力を感じない。 同じ理由でScalaも辛い。界隈の人が声高にコンパイル遅いと叫んでいる事に、まだ手を出すべき時期じゃないかなあ感を抱いているというのもあるけど。

VisualBasicは.NETの機能を手に入れているというのに熟練者にはあまり好かれない空気があって残念だな。可能性を突き詰めれば今と違う世界か見えそうな気がするんだけど。まああのへんの好きなひとはF#にいってるのかねえ。

というわけで、 Clojureをやってみようと言う気になった。 教科書はコレだ

プログラミングClojure 第2版

プログラミングClojure 第2版

今回のテーマは Hello World

なぜ Hello World か

ハマったからである

今回の環境
  • Mac OS X Mavericks.
  • JDK 1.8.0
Closure のインストール

LeiningenというMaven的なことをやってくれるツールが、Clojureのインストールもしてくれるらしい。

https://github.com/technomancy/leiningen

レイニンゲン?人の名前かな。元ネタはこちらのようだ http://en.wikipedia.org/wiki/Leiningen_Versus_the_Ants

REPL の起動(できない)

REPLがあるらしい。Leiningenを使って起動するようだ。

$ lein repl

でREPLが起動してClojureの勉強を開始できる・・・らしいが、以下の例外が出て起動できない。

Exception in thread "Thread-3" java.net.ConnectException: Connection refused
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:345)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    ...

REPLがいきなり例外はいて死ぬってちょっとハードル高いな。

ググってみるとGithubのIssueが立っている https://github.com/technomancy/leiningen/issues/1321

どうも内部的にはクライアントサーバ型になっていて、サーバだけ起動するとか、サーバを指定してクライアントを指定するとか色々できるようだ。普通に起動すればサーバとクライアントを起動してプロンプトを出すのだろう。 しかしそこで接続に問題が発生している。理由としてはどうもlocalhostが何に解決されるかで違うんじゃないかとかWifi切れば起動できるとかJava8だと発生するけどJava7なら大丈夫とか、色々あるみたい。自分の場合、ホスト名を設定してやる事でクリアできたようだ。

$ sudo scutil --set HostName kitchen-mac.local

しかし今度は違う例外が発生する

$ lein repl
nREPL server started on port 56857 on host 127.0.0.1 - nrepl://127.0.0.1:56857
REPL-y 0.3.2, nREPL 0.2.0-beta5NoSuchMethodError clojure.tools.nrepl.StdOutBuffer.length()I  clojure.tools.nrepl.middleware.session/session-out/fn--7630 (session.clj:43)NoSuchMethodError clojure.tools.nrepl.StdOutBuffer.length()I  clojure.tools.nrepl.middleware.session/session-out/fn--7630 (session.clj:43)Exception in thread "nREPL-worker-0" java.lang.NoSuchMethodError: clojure.tools.nrepl.StdOutBuffer.length()I

REPLでNoSuchMethodってどんだけハードル高いんだよなどと思いつつ再びGoogle先生に聞くとコレもやっぱりIssuesが立っている

https://github.com/technomancy/leiningen/issues/1625

in non-project REPL とあったので、教科書のサンプルコードのプロジェクトをダウンロードしてみた。 そこで実行する分には問題ないようだ。

$ lein repl
nREPL server started on port 56906 on host 127.0.0.1 - nrepl://127.0.0.1:56906
REPL-y 0.3.2, nREPL 0.2.3
Clojure 1.3.0
Java HotSpot(TM) 64-Bit Server VM 1.8.0-b132
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=> (println "Hello World")
Hello World
nil

SQL Server Express 2012+ JDBC

SQL Server Express に JDBC でつなごうとしてなぜかつながらずかなり悩んだのでメモ。 SQL Server Express は インストール時にTCP/IPソケットが有効になっていない。なのでこれを有効にしてやる必要がある。この設定はSQLServer の構成マネージャの「SQL Server ネットワークの構成>SQLEXPRESSのプロトコル」を選択するとTCP/IPの項目があるのでプロパティを開き、有効にする。IPアドレスのタブで個別のアドレスに対してポートを割り振る事ができるが、このタブの設定は少々注意して行った方が良いようだ。TCP動的ポートが0になっているとなんらかのポートを自動的に振ろうとして面倒なことになるので、これはとにかく空欄にするのが良いようだ。あとVM等が入っているとやたらネットワークインタフェースが増えるので、どれに設定が必要なのか注意してみていく必要がある。また、一番最後にAllなる項目があり、これを設定すれば全体的に効果を発揮するのかもしれないが、複合的にどういう挙動を示すのか確認できていない。なので今回とにかく固定になるように動的ポートは0を削除して空欄に設定した。

で、ちゃんとポートが開いているかの確認の仕方。 まず構成マネージャで「SQL Serverのサービス」の項目でSQL Server(SQLEXPRESS)のプロセスIDを確認する。これはタスクマネージャでも確認できるのでそっちでも良い。 で、コマンドプロンプトで netstat -ano を実行する。右側にプロセスIDが出てくるので、この中から上記で確認したプロセスIDを探す。左列にローカルアドレスが出ているので、ここで指定したポートになっているかを確認できる。これでポートが開いていて、それでも接続できないならファイアウォールの設定を疑えばいいかな。

当初まさかTCP/IPが無効になっているなどと思わず、なんだかんだで3、4時間浪費してしまった。

どこまで薄くできるのか

前回サーバサイドが大分薄いシステムを作っている話を書いたのだけれども、こんなに薄くて大丈夫なのかなとぼんやり考えていた。

考えてみると、今実装している機能はドメインロジックらしきものがとても薄い。ドメインロジックが複雑な場所ではこんな実装にすることは難しいのかもしれない。大概のシステムではドメインモデルをきちんとレイヤ分割やクラスシステムによって保護できるように設計しつつ、WEBシステムとしての構造に組み込んでいくだろう。ドメインロジックが複雑であればあるほどそのロジックを持つクラス周辺が大きな構造になるが、自分が今実装している機能は他の業務に影響したり影響されたりする要素が少なく、ぶっちゃけて言えば業務フローにおいてはスキップしても構わない機能だ。おもに後続業務の効率化のために存在していて、いわゆるクリティカルパスではない。

要するに、業務の関係でよそに配慮したり逆にガードしなければならない部分があまり多くない。

業務システムといっても利用する組織規模によって必要な事項は大分違っていて、大規模になればなるほど業務ドメインごとのデータの完全性が重要になりそうだが、小規模の場合はむしろ人による制御の可能性の方が重要視される場合が多いように思っている。一般的に人によるデータに対する制御可能性を高めようとするとある程度データの完全性は妥協しなくてはならない。順序付けて並べられた業務プロセスを順番に完了させていくのではなく、業務の個別のステップは状態が確定せず同時進行的に進むというようなことを業務フローとして許容できるシステムを要求されることがままある。大規模な組織的利用をするシステムなどでこういった設計を適用してしまうと、適切に情報共有されない部署間の問題などで全体として一貫した対応が取れず、コントロールを失ってしまう可能性がありそうだが、中小規模ならば逆にこのような形態の方が都合がいいという場合もある。

まあ、今回のはそんなに規模が大きくない前提というわけだね。

実装の方に話を戻すけれど、そもそもクライアントサイドでデータ構造を作ってJSON/Ajaxで飛ばすことも割と普通になってきている昨今、クライアントから受け取ったデータを静的型のモデルにマッピングする処理は最低限でいい(フレームワークによるサポートも充実している点も理由としてある)し、今作っているシステムにおいてはデータベースから取り出した結果をサーバサイドで処理する要件もあまりない。データベースから取り出した結果から複雑な処理を行いたい場合、型システムのある世界では型をもった値に変換したくなるのが普通ではあるけれど、そうでもなければSQLの結果を逐一モデル型をつくってそれに変換するというのはオーバーヘッドになるだけで意味があまりない。現状として必要になっているのは、クライアントサイドで利用しやすいように若干の整形処理を行うことくらい。

たとえば、HTTPを型付のシリアライズデータ(OData?)などで転送して、クライアント側ではTypeScriptみたいな言語(TypeScriptが値にたいして型を持てる言語かどうか知らないが)が型付で受け取れるとか、つまりサーバサイドの型をクライアントサイドの型に簡単にマッピングでき、かつその利点を生かせるのならばサーバサイドでも厳密に肩を扱うことに意味が出てくるだろう。

しかし現状それはないので、まあ特別型を使うことにこだわる必要がない。

あとまあ、個人的な経験を振り返って、あるデータ型のオブジェクトから、別の似たような(しかし明確に異なる)型のオブジェクトへひたすら値の転記をやるというコードを過去に何度も書いていて、いい加減(コード上だけでなく実処理として)価値がないよなという認識になっていて、そういった処理を極力排除してみたいという欲求があるというのも、こんな実装にしている理由としてはある。

ただまあ、若干テストについては悩んでいる。

既に述べているとおり、HTTPの入り口からデータベースまでのレイヤがとても薄いシステムになっている。データベースを使用したロジックのテストにおいては、データベース側を抽象化しておいて、モックに差し替えるなんてことをやるのが常套なんだろうけども、サーバサイド側の実装がとても薄いと、あまりそういうものを差し込む場所がない。テスタビリティが低いというのかもしれないが、そのために "SQLを発行して連想配列の配列を吐き出す実装" をモック化したとして意味があるようにも思えない。結局SQLが正しく構成されて発行されるかが重要になっているので、そういう意味では、DBに接続してエンドツーエンドで実行するテストを網羅的に用意した方が、テストとして効果が高い気がする。結局DB依存のクエリなどもあるし、今回の案件は既存システムに対する改修なのでALTERTABLEみたいなデータベース変更もあるため、その辺含めてDBMS様的にも問題ないかチェックしてもらえた方がいい。 つまり、モックを使用したテストにあまり時間をかける価値を感じていない。

自動テストでデータベースに接続してスキーマ作ってなんてやっているととても重いテストになってしまうんだけど、最終的に大掛かりなCIなんかを目指すと結局そこはやりたいし、今回の構成でもっとも効果が高いのはそういうテストだと思っている。 ただまあ、環境が.NETということで全く勝手がわからないのだけど。少し時間が出来たら調べてみようと思う。うまく回りそうならまだブログに挙げることにしよう。

ASP.NET の 永続化層で悩む

現在作成しているシステムは諸事情あってクライアントサイドがAngularJSでサーバサイドがASP.NET(VB) / WebAPI2 になっている。なるべく早く顧客に動きを見せるためにおおざっぱに全体を実装する感じでやっている。クライアントサイドはまあAngularJSで適当にやっているけど、サーバサイドはいわゆるREST API的に実装しているのだけど、ロジックのほとんどがSQLだ。

  1. HTTPリクエスト受付
  2. ⇒SQL生成
  3. ⇒実行
  4. ⇒結果取得
  5. ⇒そのまま1レコードを連想配列とするようなオブジェクトの配列としてJSON変換
  6. ⇒HTTPレスポンス

みたいな流れがほとんど。

今のところまだバリデーションやらセキュリティやらは考慮していないので今後その辺増えていく可能性はあるけれど、サーバサイドがほとんどSQLで済むのならば、サーバサイドレイヤーはほんとに薄くなりそう。

本当はORマッピングレイヤーを何かしら入れるつもりでいたのだけど、いろいろいじってみているうちにどれも.NET初心者(自分)にとって学習コスト含め重すぎるという結論になってやめた。

EntityFramework6

方式がモデルファーストとコードファーストとDBファーストの3種類ある。らしい。モデルファーストは専用のモデルエディタを使ってエンティティの定義を作ってやるとデータベースのスクリプトとそれにマッピングされるモデルクラスを自動生成してくれるようだ。はじめこれを使ってやっていたのだけど、いろいろがちゃがちゃとやっているうちにモデルエディタがうんともすんとも言わなくなってしまって全く原因もわからないのでパスした。他の方法はあまり試してないのだけど、このあたりでEntityFrameworkの評判を聞いてみたところあまりよい反応はなさそうだったので、別な方法を探した方がよさそうな空気になった。

Linq to SQL

EntityFrameworkを使いたかった理由の一つがLinq to Entitiesを使えるからということで調べていたのだけど、それ以外の方法としてLinqをSQLにマッピングするLink to SQLとやらがあるらしいのでそちらの使用方法も調べてみた。しかしどうもこれDeprecated扱いにしたい雰囲気を感じるのと、こちらでも妙なGUIを使ったモデルエディタの力が必要になるっぽいのでパス。

Dapper

SQLはSQLとして発行してその結果をクラスにマッピングしてくれるだけの薄いDBアクセスフレームワークらしい。いいんだけど、正直結果の数だけクラス作るのかなあと思うと、どうせ結果はそのまま画面に出すだけなんだから結果セットをそのままJSONに変換するくらいの勢いでいいんじゃないだろうか、と思い当った。

といった経緯で、SQLの実行結果はそのままクライアントに転送してもいいのではないかと思い始め、単純にSQL編集の補助をしてくれて結果をJson関数に渡せる形で返すというだけのラッパーを書いてみた。現状サーバサイドロジックは大体こんなような書き方になっている。

Using db as new DB()

    dim sql as new SQLBuilder
    sql.Add("select * from hoge_table ")
    sql.Add("where foo=@bar", barValue)

    return Json(db.Q(sql))

End Using

今のところは(プロトタイプであることもあってか)特に問題とはなっていないけれども、エンティティの整合性を保つためにHTTPのインプット側に関してはサーバサイドでも強固なチェックの必要性はありそうかな。 詳細画面なんかだと、情報の構成がいわゆるヘッダー - 明細構成になっているものがあったりして、その場合はSQLの実行結果から、クライアントサイドで使いやすそうなオブジェクトの形へ整形処理を行ったりしている部分も若干ある。

この辺うまくというか、宣言的な方法でわかりやすい記述でやれるといいんだけどなあ。まあその辺はこれから。

あ、あとエラーハンドリングに関してもまだ方針を決めていない。 個人的にはエラーと正常のフラグを持つオブジェクトを一つ作って、その中に適当に結果を入れて返すのがいいかなあと漠然と考えていたのだけど、どうせならHTTPヘッダにそれらしい情報を埋めてしまうのがいいのかもしれない。

YappoLogs: 2014年に向けた JSON API の実装の方向性と X-JSON-Status 改め X-API-Status header のご提案

Python で Aipo にログインして掲示板に何かしらポストする

概要: requests 便利

というわけでとあるグループウェアの掲示板に定期的にポストするというのを自動化したかったので、やり方を調べてみると、requests というパッケージを使うと良いらしい。

http://docs.python-requests.org/en/latest/

今回のグループウェアは Aipo という製品のオープンソース版です。 http://www.aipo.com/

このグループウェアはApache Turbine というフレームワークをベースとしたポータルフレームワークである Jetspeed をベースに日本語化したプロダクトをベースにしたプロダクトで、オープンソースで提供されている。 由来が古いのでいろいろと古い部分もあり、いわゆるRESTful URLのような設計でも無いように見える。なので継続するリクエストパラメータやセッション情報の取り回しなどが重要。自前でHTTP リクエストを飛ばしたりして作るとその辺面倒だったりしますね。しかし今回requests のおかげで大分楽に実装できた感じ。

今回勘違いしてテストサーバにAipo Version 4をインストールしてしまって、それを対象にスクリプトを書いてしまったのだけれども、まあ最新のバージョンでも多分大筋変わらないんじゃないでしょうかね(という希望的観測)。

掲示板投稿するには

Aipoで普通に掲示板に投稿しようと思ったら以下のような手順を踏むことになる。

  1. Aipoにログイン
  2. 掲示板のフォーム(Ajax)を開く
  3. 内容を記入し、投稿

前提としてログインしたアカウントが掲示板に投稿する権限を持っている必要があるけど、それ以外にこの流れでプログラムが気にする必要があるのは以下。

  • ログインし、ログイン状態を保持しなければ投稿できない
  • CSRF対策等でフォームにワンタイムトークンが発行されている可能性

ログイン状態の保持というのは要するにセッション情報という奴だけど、これについてはCookieの取り回しができれば(だいたいの場合は)良いはず。 ワンタイムトークンは一度フォームにアクセスしてみないと分からないので、上記の手順を忠実に守った上で、取得したフォームの情報からトークンを抽出して記事投稿時に一緒に投げるようにしないといけない。

requests ってみる

さて、いきなりセッションのハンドリング。

    s = requests.Session()

これで s に HTTP GETやHTTP POSTのためのメソッドがついてくる。 つまりあとは手順に従って s.get() とか s.post() とか呼べば良いだけ。分かりやすい!

ログインするために以下のようなコードを書いた。

    # Login to Aipo
    login_data = {'action': 'ALJLoginUser',
                  'username': AIPO_USER,
                  'password': AIPO_PASSWD}
    s.post('%s://%s/aipo/portal' % (AIPO_SCHEMA, AIPO_HOST), login_data)

パラメータ名などはそのまんまですね。actionが何なのかよくわからないけど、Jetspeed か Turbine のお作法で操作をこんな形で指定するのだった気がする。 とりあえずこれでログインはOK。次はトークンを取得するために掲示板の投稿フォームをリクエストする。

    # Open posting form
    form_data = {
        'template': 'MsgboardTopicFormScreen',
        'entityid': 'new'
    }
    js_peid = 'P-14398eea627-1000b'
    form_response = \
        s.post('%s://%s/aipo/portal/media-type/html/user/pass/page/default.psml/js_peid/%s?'
               % (AIPO_SCHEMA, AIPO_HOST, js_peid),
               form_data)

Chromeでネットワークのキャプチャを見ながらパラメータを調べたんだけど、templatenew というパラメータで開くフォームを決定しているっぽい。 js_peid は jetspeed由来のパラメータかな。何度かログイン・ログアウトしてみても特にセッションによって変化する値のようでも無かったので、とりあえず固定値で持つ事に。若干ググってみたところ、おそらく、ポートレット固有のIDだと思われるのだけど、確定情報には至らず。

さて、上記で掲示板の投稿フォームが取得できるので、そのレスポンスからトークンらしき物を探してみたところ、secid なるパラメータを見つけた。

正規表現を使ってこれを取り出す。

    # Extract secid(security id?) from response text
    secid = re.search('name="secid" value="([^"]+)"', form_response.text).group(1)

どうせならタグからマッチさせた方が良い。もっと言うならDOMに変換すべきか・・・まあ、今回は置いておきましょう。 あとはこれを使って投稿するだけ。

    # Post main subject
    entry_data = {
        '_name': 'msgboardForm',
        'secid': secid,
        'is_new_category': 'false',
        'mode': 'insert',
        'category_name': '',
        'topic_name': 'こんにちわこんにちわ',
        'folderName': '',
        'eventSubmit_doMsgboard_insert': '追加する',
        'category_id': '2',
        'note': """
        てすててす
        """ ,
        'template': 'MsgboardTopicFormJSONScreen'}
    s.post('http://%s/aipo/portal/media-type/html/user/pass/page/default.psml/js_peid/%s' % (AIPO_SCHEMA, AIPO_HOST, js_peid),
           entry_data)

この辺のパラメータも全部Chromeのネットワークのキャプチャから引っ張ってきただけなんだけど。secidを設定し、topic_name と note に投稿したい内容を設定して s.post() すれば今回の目的は達成と。

まとめ:requests 便利

HTTPのキャプチャは最近ではブラウザ付属のデバッガなどで簡単に取れるようになってきているので、今回使ったrequestsのようなライブラリがあれば手で操作しているような操作を簡単にシミュレートできますね。こんなに簡単ならHTTPベースのソフトウェアテストなんかをそのまま書いてもそんなに面倒じゃないかも。