時計を壊せ

駆け出してからそこそこ経ったWebプログラマーの雑記

#yapcasia 2013 で 「ぼくがかんがえたさいきょうのMVC」について話してきました

昨日の13:40から多目的教室3で「ぼくがかんがえたさいきょうのMVC」という題でトークをさせて頂きました。


http://yapcasia.org/2013/talk/show/f60b8522-d43e-11e2-ac80-4cc16aeab6a4

内容について

大それたタイトルですが、MVC disというかんじではなく、上手くMVCを使うためにそれぞれのアプリケーションの要件に最適化した「ぼくがかんがえたさいきょうのMVC」をつくり、そこに対して規約を作り運用していくとだいぶ良い感じですよという感じの話で話をさせて頂きました。
20分は思いの外短いなということで、トピックスに対する答えはだいたい詰め込んだつもりですが、
時間の都合上一部削ったものもあります。すみません。


前半でMVCを何故カスタマイズするべきかについて触れ、後半でMVCをカスタマイズする例*1とそれを守るためにチーム内規約を作って運用するのオススメですという感じの事を話しました。
MVCは抽象的、って表現はいま思えば適当ではなかったです。「MVCは必ずしもあなたの書こうとしているアプリケーションの構成要素に対して具体的な紐付けが確定されているものではない」って表現のがたぶん僕の言いたい事に近いです。
なので具体的な構成要素との紐付けは自分で考えなければいけないけど、チーム内で解釈にブレが出るとカオスになるし、ちょっとイレギュラーな事をやってるとどこに紐付ければ良いか分からなくなるので、具体的に目的のアプリケーションのどの部分とMVCそれぞれが紐づくのか具体化しましょうということが伝えたかったです。


今回、MVC自体がビギナー向けの話題ではないかもしれないと思い、レギュラー向けで応募させて頂きましたが、ビギナーの方にも分かりやすい内容にまとめられたかなと思います。スライドはぜひご覧ください。内容についておかしいと思う点、不明な点があれば、Twitterのメンションやコメント欄などでぜひ気軽に質問/反論してください。



という問題があったみたいで、Sub Room3で id:yappo さんのトークを聴いていたのですが、Sub Room2での発表だと思ってちょっと前に抜けてSub Room2に行ったら違かったので慌ててSub Room3に戻ってだいぶ緊張した状態でトークを始める感じになるというハプニングもありました。
※これは僕が事前にちゃんとトークの前後関係や部屋を把握していれば防げた問題で、僕の責任です。アプリ自体は非常に便利に利用させて頂きました。作者の方、本当にありがとうございます。

*1:実例をもとに簡略化しました

JavaでDH鍵交換を実装する

やんごとなき事情でJavaでDH鍵交換を実装しなければならなくなったので実装してみました。
クラス/メソッドの説明と型しか書かれていないJavaのドキュメントをdisりつつ、いろいろ試行錯誤してみたらできた。
ググっても無駄に長くてめんどくさくて実用性に欠ける実装ばかり出てきたりして辛い思いをしたので公開してみます。
javaは最近はじめて書いたのでよくわかんないんだけど、Exceptionのcatchは公開用に適当にe.printStackTrace()してお茶を濁しております。こういうのどうするのがいいんすかね。
念のため書いておくと、DH鍵交換は単体だと中間者攻撃に対して脆弱なので、素直にSSLなどを使うのがおすすめでございます。

YAPC::Asia 2013 で ぼくがかんがえたさいきょうのMVC についてはなします #yapcasia

YAPC::Asiaとは

日本で最大級の規模のPerlのカンファレンスです。Perlのカンファレンスですが運用、プロトコル、テスト等開発に関わる様々なトークがあり、和気あいあいとした雰囲気でときには意識高い話もしつつ、ゆるふわにPerlとその周辺技術等への学びや発見を得る事が出来ます。詳しくは http://yapcasia.org/2013/ をどうぞ。

今回、ありがたい事に僕が応募していたトークを採択して頂きました。

ぼくがかんがえたさいきょうのMVCとは

下のリンク先をご覧下さい。

http://yapcasia.org/talk/show/f60b8522-d43e-11e2-ac80-4cc16aeab6a4

ではちょっとさみしいのでこのトークを応募した経緯を書いてみます。


僕は仕事でソーシャルげーむを作っています。ソーシャルゲームは若干特殊な部分はありますが基本的には普通のWebアプリです。(最近はクライアントをAndroid/iOS向けに提供しているものも多いですがそれも多くの場合はバックエンドはWebAPIを提供するWebアプリです)
ソーシャルゲームは場合によってはかなりの種類の機能を提供する場合があり、対応デバイスもAndroid4系/Android2系、iOS/FeaturePhone(所謂ガラケー)などに対応させ、更に複数のソーシャルプラットフォームで動作させる場合もあり、プラットフォームによってOpenSocialの同じAPIでも微妙に仕様が違う場合があったり、同じ目的のAPIをそれぞれ独自の仕様で持っている場合があり、またゲーム自体のロジックが複雑な場合もあり、規模が大きくなる傾向があります。
ある程度の規模まではぶっちゃけ設計が適当でもなんとかなります。意味のわからないコードもひたすら追えばなんとかならなくもないでしょう。最悪全部書き直す事が現実的なコストでできる場合もあります。場合によってはschemaだけ真面目に設計してコードはゴリっと愚直に書いたほうが運用を含めた総合的なコストを低くする事もできる場合も多いと思っています。
しかし、ある程度以上になってくると、適当な設計のアプリケーションでは全てのコードを把握する難易度はかなり上がります。特にRPG系と呼ばれるジャンルのソーシャルアプリは確実に困る規模だと思います。
規模が大きいとどうしても複数人で同時に開発を進める事になります。規模が大きい割に設計が適当だと、同じ役割のコードが様々な場所に書かれたり、様々な機能が沢山搭載されている「ぼくがかんがえたさいきょうのClass!!!」「ぼくがかんがえたさいきょうのmethod!!!」みたいなやつが出来たり、非常にカオスなコードが出来上がります。処理の共通化も困難になり、そのようなコードベース上で無理に行われた共通化は諸悪の根源になりがちです。プロダクションコードでこのようなコードが出来上がると非常に悲しいことになります。テストが書かれていればかなりマシですが、それでもそもそもの設計がぐちゃぐちゃだとリファクタリングにかなり苦労する印象が強いです。コードレビューも苦労します。

これを解決するための考え方の1つが僕はソフトウェアアーキテクチャだと考えています。MVCはそのうちの1つですが、これも必ずしもそのままWebアプリケーションに当てはめられる訳ではなく、特にRDBMSとの関わり方やコンテンツキャッシュとの関わり方について悩んだり、ロジックが変に分散してしまったり、逆に殆どのロジックが詰め込まれる「ぼくがかんがえたさいきょうのClass」みたいな奴が出来て苦労する場合が多いと思います。その為、MVCの考え方を拡張して、目的のアプリケーションに合わせて整理して設計する事が必要になります。
そこに関してある程度考えがまとまったので、今回この話をする事にしました。
ただ、ぼくの考えも非の打ち所の無い完璧なものであるとは思っておらず、より良い感がえ方がきっとあると思うので、この話をきっかけにみんなそれぞれの「ぼくがかんがえたさいきょうのMVC」について話し合うきっかけにでもなれば、ベースの設計の重要性について考える機会が出来たらいいな風な感じです。
id:TAKESAKO さんの「SPDY、HTTP/2.0の使い方」とかid:xtetsujiさんの「mod_perlの展望とApacheの超絶技巧」とかid:akiymさんの「Herokuで学ぶ、初めてのPerl」とか裏番組みんな面白そうなので僕も聴きに行きたいくらいですが、もし興味があれば聴きに来て頂けると喜びます!

YAPC::Asiaに参加するには

チケットの購入が必要です。2日通し券で5000円、1日券で4000円です。なお、学生は無料です。(!!)
チケットの購入はこちらからどうぞ! http://yapcasia.org/2013/tickets/
明日、8/11までなのでまだ購入していない方はお早めに!

Yomiuri構想

まだ構想段階だけどこれだいぶイケてね?って思ったので勢いで書いてみる。

Yomiuriとは

手軽に拡張出来るJekyllインスパイア系ブログフレームワーク/オーサリングツール

特徴

CLIで記事が書ける

vimemacsなどお好みのエディタでどうぞ。

Github Flavord Markdownで記事が書ける

エンジニア的にアツい。

レイアウトの自由度

Kolon(Text::Xslate)の継承テンプレートで良い感じに拡張出来ます。
また、良い感じのメソッドを提供しているので
まるまるテンプレートを置き換える事もできます。
JS/CSSも自由に書けます。

機能拡張の自由度

JavaScriptとWebAPIを使って機能拡張を行う事をYomiuriはサポートします。
用意されたhook pointにJavaScriptAPIクライアント処理を埋め込むと良い感じにWebAPIを叩いてunderscore.jsで書いたtemplateをレンダリングするイメージです。
仕様として決まるのはWebAPIのCSRF対策*1JavaScriptのhook pointだけです。*2
この仕様を満たす事が出来ればWebAPIは自由な言語で実装する事が出来ます。
また、APIを楽に実装するための標準API仕様とサーバーサイド(Perl)/クライアントサイド(JavaScript)フレームワークも別途用意します。
大概はこれをつかうと楽にそこそこ便利なAPIをおてがるに開発出来る様になる予定です。

シンプルな動作

Jekillと同様に記事ファイル(Markdown)とテンプレートから静的なHTMLを生成するだけです。
gitで管理しやすいと思います。
静的ファイルサーバーがあれば公開可能なのでやろうと思えばGithub Pagesとかでも公開出来ます。*3

使い方イメージ

インストール

$ cpanm App::Yomiuri

新しいブログを作成

対話式で良い感じに設定作ってくれる。

$ yomiuri create MyBlog
title: My Blog of darkness
description: publishing my darkness
creating yomiuri.toml ... OK
creating MyBlog ... OK
$ cd MyBlog
$ git init
$ git add .
$ git commit -m 'initialize commit'

暗黒面を綴るブログが出来ました。

カテゴリの追加

カテゴリははてブと同様にタグっぽいやつ。

$ yomiuri category add darkness
$ yomiuri category add emacs

darknessとemacsという2つのカテゴリが出来ました。

記事の作成/編集

insert or update的な感じで処理してくれるのでファイル食わせるだけです。
h1(レベル1の見出し)の前に[]でカテゴリを囲んで書くとそのカテゴリの一覧に追加してくれます。

$ cat > entry/hoge.md
[darkness][emacs]My first entry.
===============

Hi.

I write a blog post for the first time. 
My hobby is to messing about with emacs.
^D
$ yomiuri entry entry/hoge.md

HTMLなどの生成

コマンド一発でお手軽生成

$ yomiuri publish
creating htdocs/index.html ... OK
creating htdocs/entry/hoge.html ... OK
creating htdocs/archive/1.html ... OK
creating htdocs/config.json ... OK
creating htdocs/meta.json ... OK
生っぽい感じで拡張
$ cat > htdocs/js/darkness.js
(function () {
  var Comment = {
    model: null,
    view:  null
  };

  Comment.Model = Backbone.Model.extend({
    apiUrl: "http://api.yomiuri.yourhost.com/comment/",
    list  : function () { return this.get("list"); }
  });
  Comment.View = Backbone.View.extend({
    el     : "#yomiuri-comment",
    model  : new Comment.Model(),
    events : {
      "click .button.add":    "openAddEditModal",
      "click .button.res":    "openAddEditModalWithRes",
      "click .button.submit": "submit"
    },
    initialize: function() {
      Comment.model.get(this.$el.attr)
      this.template      = _.template($("script#yomiuri-comment-template").text());
      this.modalTemplate = _.template($("script#yomiuri-comment-modal-template").text());
      this.render();
    },
    openAddEditModal: function (e) {
      $("#yomiuri-comment-modal").html(this.modalTemplate());
      $("#yomiuri-comment-modal").modal("show");
    },
    openAddEditModalWithRes: function (e) {
      var targetCommentId = e.target.getAttribute("data-comment-id");
      $("#yomiuri-comment-modal").html(this.modalTemplate({ targetCommentId: targetCommentId }));
      $("#yomiuri-comment-modal").modal("show");
    },
    submit: function() { throw "飽きた"; },
    render: function() {
      this.$el.html(this.template({ list: this.model.list }));
    }
  });

  Yomiuri.router.on("entry/:name", function () {
    new Comment.View();
  });
});

})();
^D

本日の一言

Jekillでよくね!!!!!!という気持ちは凄く分かります。
ぶっちゃけ最初はPerlでJekill的な奴自作してみよっかなー的なところから始まって、
JS自由に書いて機能拡張する事考えたらある程度フレームワークあると楽だよねってなって、
ああいう感じの静的HTML吐く系のブログエンジンを利用者が独自拡張するためのアプローチとして、
こういう感じの事が『手軽に』出来たら楽しいんじゃないかなと思っている。
そのためには仕様と実装をサポートするライブラリの整備が不可欠なので、
また、その肝心の部分はまだまじめに作り始めてないので実装が進んだらまた記事書きます。
まとまんねーーーーーーーーーーーーーー

本日のこだわりぽいんと

宗教間戦争が起きないようにcatで書きました

*1:http://d.hatena.ne.jp/hasegawayosuke/20130302/p1

*2:なんか足りない気もしつつ実装段階でまた考え直す

*3:Github Pagesに公開するのはgitのrootがそのままページのrootになるという仕様上ちょっと面倒なのでなんか上手い手段を考え中…

plenv.el 0.31 released!!

plenv.elのメジャーバージョンアップが行われました。


今回のバージョンアップでは--asオプションを利用してperlをインストールしたケースでうまくperlのパスを取得出来なかった問題が修正され、README.mkdnのサンプルコードにおけるflymakeと連携する部分のコードが間違っていたものが修正されました。*1

また、plenv 1.9からrbenv basedなコードになった事により、
一部のインターフェースで互換性が無くなってしまった為、既存のコードではplenv-globalなどのバージョンの補完が効かなくなっていたりplenv-listが動かなくなってしまいましたが、
このバージョンからplenv 1.9以降もサポートするようになりました。
一応まだplenv 1.6未満もサポートしていますが、これは将来的にはサポートされなくなる可能性がありますので1.9以上へのバージョンアップをオススメします。


また、ちょっと前にMELPAに登録した為、
package.elからインストールする事が可能になっています。
これを機会にplenvとemacsを使っている方はぜひお使い下さい。


余談: YAPC::Asia 2013のトークに応募しています。よかったら。 http://yapcasia.org/2013/talk/show/f60b8522-d43e-11e2-ac80-4cc16aeab6a4

*1:id:sun-basix++

コンテキストとハッシュの怪

怖い話

割とハマりがちなので。
たとえば、以下のようなコードがあったとします。

use strict;
use warnings;
use utf8;

use Data::Dumper;

sub yyy {
    my $key = shift;
    return unless $key;

    return "yyy_$key";
}

my $hashref = {
    xxx => yyy(),
    aaa => 'bbb',
    ccc => 'ddd',
};

print Dumper $hashref;

上のサンプルコードの出力は以下のようになります。

$VAR1 = {
'bbb' => 'ccc',
'xxx' => 'aaa',
'ddd' => undef
};

マテマテマテマテって思うかもしれませんが、perlのバグなどではなく正常な挙動です。

コンテキスト

Perlにはコンテキストと呼ばれる概念があります。
これは、値の解釈によって処理を変えるための概念です。
詳しい説明は初めてのPerl*1を読むか、こことかこことかを読むと良いかもしれません。

Perlは値をスカラーコンテキストで評価する場合とリストコンテキストで評価する場合があり、それぞれで処理内容が変わる場合があります。
例えば変数への代入の場合はスカラー型の変数への代入の場合は値をスカラーコンテキストで評価します。

例1:

use strict;
use warnings;
use utf8;

my $calar1 = 'aaa';                 ## スカラーをスカラーコンテキストで評価
my $calar2 = ('xxx', 'yyy', 'zzz'); ## リストをスカラーコンテキストで評価(リストの最後の値が得られる)

print $calar1, "\n"; # 'aaa'
print $calar2, "\n"; # 'zzz'

アレイ型/ハッシュ型変数への代入の場合は値をリストコンテキストで評価します。
例2:

use strict;
use warnings;
use utf8;

use Data::Dumper;

# ARRAY
my @rray1 = 'aaa';                 ## スカラーをリストコンテキストで評価(与えたスカラー値が1つだけ入ったリストが得られる)
my @rray2 = ('xxx', 'yyy', 'zzz'); ## リストをリストコンテキストで評価

# HASH
my %ash1  = 'aaa';                 ## スカラーをリストコンテキストで評価(与えたスカラー値がkeyとなりvalueがundefなハッシュが得られる)
my %ash2  = ('xxx', 'yyy', 'zzz'); ## リストをリストコンテキストで評価

print Dumper \@rray1; # ['aaa']
print Dumper \@rray2; # ['xxx', 'yyy', 'zzz']

print Dumper \%ash1; # { 'aaa' => undef }
print Dumper \%ash2; # { 'xxx' => 'yyy', 'zzz' => undef }

また、更に変な書き方として、リストの中にリストを含む事も出来ます。
これは結合され1つのリストとして解釈されます。

('xxx', 'yyy', ('aaa', 'bbb')); # => ('xxx', 'yyy', 'aaa', 'bbb')

ハッシュ内では値はリストコンテキストで評価します。
なので、一番上の何も返さない関数の場合、空のリストとして解釈されてキーがズレてしまうのです。

{
    xxx => (),
    aaa => 'bbb',
    ccc => 'ddd',
}; ## { xxx => 'aaa', bbb => 'ccc', ddd => undef }

この場合、ほぼプログラマの思い通りの挙動にはならないでしょう。怖いですね。

こわいのこわいのとんでけー

上のコード類を実行してみた人は以下のような警告が出るのに気づいたかもしれません。

Odd number of elements in hash assignment

これはハッシュとして与えたリストが奇数だった場合に警告してくれています。
上のような間違ったコードを書いてしまっている場合がある事を危惧して(かどうかは知りませんが)教えてくれているのです。
なので警告は/dev/nullには決して捨てたりせずに*2、不可解な挙動が起こった場合は警告も含め怪しいメッセージが出ていないか確認するとよいでしょう。

*1:最近第6版が発売されたようですね

*2:捨てると椅子が飛んできます