2011年12月29日木曜日

Go言語のErrorオブジェクトの変更


$ 8l -V
8l version weekly.2011-12-22 11086

12/22時点のGolang本体の変更点(気がついた分)のメモです。

「Go言語プログラミング入門 on Google App Engine」では、エラーオブジェクトの内容を出力する時に、
err.String()を利用していました。現在のGo言語本体の安定版リリースだと、
Stringメソッドは無くなっていて、代わりに、err.Error()のように、
Errorメソッドを呼び出さないとコンパイルエラーになってしまいます。

現時点のGAE/G SDKでは、書籍のまま、Stringメソッドを呼び出せば良いですが、
そのうち、本体の変更に合わせることになるかもしれません。

書くのを忘れていたので追記(18:00)
httpパッケージがnetパッケージの下に移動していました。
書籍ではimport "http"ですが、Go言語本体で利用するためには"net/http"と宣言する必要があります。


2011年12月28日水曜日

Go言語のtemplate.Setを使う

書籍「Go言語プログラミング入門 on Google App Engine」でも記述していない事なので
Blogに残しておこうと思います。

Google App EngineのアプリケーションはWebアプリケーションなので、HTMLを
出力する事が多いと思います。(WebAPIを作成する場合はテキストベースかもしれませんが)
HTMLのタグで面倒なヘッダ部分、フッタ部分など共通化したい所があったりすると
思います。
書籍では、Templateパッケージを利用して、HTMLファイルに変換タグを追加し、プログラムで変換タグを置き換えるというアプローチでHTMLを出力させています。しかも、Templateが一つの例が載っていますが、複数ページを作成するという事がなかったので
登場することがありませんでした。

前置きはこの辺にして、複数のページを作成する場合、ヘッダとフッタに関しては共通化される事が多いかと思います。Go言語でもその機能は提供されていますので、サンプルを書き残しておきたいと思います。

まず、HTMLの部分です。

ヘッダ
  
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>Set Sample</title>
</head>
<body>

フッタ
<hr>
Footer
</body>
</html>

ボディ(全体)
{{define "body"}}{{template "header"}}
<h1>Set Sample</h1>
{{template "footer"}}{{end}}

ソースコード
package setsample

import (
 "http"
 "template"
)

func init() {
 http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
 header := template.Must(template.New("header").ParseFile("header.html"))
 footer := template.Must(template.New("footer").ParseFile("footer.html"))
 body := template.SetMust(template.ParseSetFiles("body.html"))

 body = body.Add(header, footer)

 if err := body.Execute(w, "body", "no data needed"); err != nil {
  http.Error(w, err.String(), http.StatusInternalServerError)
 }
}

ポイントは、headerとfooterはtemplateとして読み込み、bodyをSetとして読み込む所です。
Setにはtemplateを追加する事ができるので、bodyにheaderとfooterのtemplateのタグを追加しておき、プログラムでAddします。

最後、Setに関しては名前を指定しないと出力(Execute)できないようなので、defineタグをbodyに追加しています。

これにより、HTML出力の処理が1回で済むようになります。

2011年12月27日火曜日

Slim3 Source Code Reading #2

今日は、Slim3 Source Code Reading #2を開催してきました。
今回はModel関連でDatastore#putを読み進めました。

読み進めたソースコードは以下のファイルです。

  • Datastore.java
  • DatastoreDelegate.java
  • FutureUtil.java
  • AsyncDatastoreService.java
  • DatastoreUtil.java


以下、その時のメモです。
DatastoreUtil.java 952行目
modelmeta.assignKeyToModelRefIfNecessary(ds, model);

エンティティ間の紐付けを行うための処理を個別に実装する。
(自動生成された時点では、中身は空)
※現時点では紐付けたサンプルコードがないので確認できず。。

ModelMeta.java 518行目
prePut()

データストアに格納する前に何か処理をしたい場合は、個別に実装する。
(自動生成された時点では、中身は空)
多分、postGet()とペアで見せる時とデータの中身が変換されないと
いけないケースが記述する?

DatastoreUtil.java 532行目
assignKeyIfNecessary()
エンティティにキーがなければキーを生成している。
ここで、親エンティティが存在している場合は、親のキーを設定して
紐付けしたキーを生成する。
Idは自動生成。

Datastore.put()で例外が発生した場合、(データストアのPutで例外が発生した時)
どうするの?(例えば、データストアの書き込みタイムアウトなど)

Slim3本のP.212中段にデータストアのリトライをSlim3が行うとなっているが?

DatastoreTimeoutException.javaはSDKに存在しているが、
RuntimeExceptionの扱いになっているのでドキュメントにthrowsの記述がない。

Slim3 1.0.6の時点ではリトライ処理(最大10回)が存在したようだが、
今日のソースコードを読んだ範囲では見つけられなかった。
(どこにもcatchがない?)

------

解散後の話題として@sinmetalさんが、Slim3のリポジトリから過去のソースコードを
取得して確認してくれたのですが、メモにある記事のように10回のリトライの処理は
確かに存在していました。しかし、現時点ではその処理は存在していません。
恐らく、AsyncDatastoreServiceの中(よりネイティブに近い所)でリトライ処理と
等しい事が行われていると予想されます。
(そうでなければ、処理を削除する理由がない)

次回#3は1/10(火)19:00〜の予定で、トランザクションに行く前に、Getを読みすすめます。

2011年12月26日月曜日

2011年を振り返る

だんだんと、今年(2011年)を振り返るというBlog記事が増えてきました。

という事で、私も同じように2011年を振り返ってみたいと思います。

参考までに、2010年の振り返りと目標の記事へのリンクを張っておきたいと思います。

2010年を振り返る
http://hobby.txt-nifty.com/t1000/2010/12/post-fe5a.html
今年の抱負?
http://hobby.txt-nifty.com/t1000/2011/01/post-4404.html

まず、2010年を振り返る記事に対して。

よく考えるとオープンセミナー@岡山の実行委員長をしていたのは昨年の事だったんですね。オープンセミナー@岡山は開催が5月頃なので半年ぐらいカレンダーとずれる感じなのですが、ずっと前のような感覚でした。
今年のオープンセミナー@岡山も130人ぐらいの参加があり、大変盛り上がりました。
来年はまた実行委員長が交代しますので、今年とは違ったものになりそうです。

また、来年はいい意味で「しがらみ」がなくなったので、勉強会も
「行きたい」と思う勉強会に参加しようと思います。
これに関しては、ある程度、達成できたのかな?と思っていますが、今年は行きたい勉強会に都合が合わずに行けなかったような気がします。それは金銭面が主な理由だったように思います。仕方がないと言えばそうなのですが、もう少し金銭面での余裕がでるようにしたいところです。
Google技術を勉強すると言って始まった2010年でAndroidばかりになって
しまったというのは良くないなと思いました。
来年はGoogle App EngineやHTML5なんかに力を入れていきたいです。
Go言語も途中で止まってしまったので、もう少し力を入れたいと思っています。
この点は、書籍「Go言語プログラミング入門 on Google App Engine」を書かせていただきましたし、中国GTUGの活動でも幅広いテーマで発表をしました。この目標は達成できたと捉えていいと思います。
来年もこの調子で幅広く押さえていきたいと思いますが、HTML5の勉強が足りなかった気がするので多少HTML5+CSS3+JavaScriptに力をかけていきたいと思っています。

次に、仕事に関して。
今年は以下の仕事をしました。

  • 専門学校の非常勤講師(週4日)
  • Androidの講師(センサー、OS)
  • 職業訓練校の立会い
  • 派遣会社の単発案件(PCの導入作業)
  • 執筆

専門学校の非常勤講師として週4回も授業をさせていただいたので、開発の案件に手を出すことができませんでしたが、来年は専門学校の授業が減ると言われているので、また新しい仕事を探さないといけなくなりそうです。今の生活は好きだったのですが、どうやら、1年限定だったようです。もう少し教育分野で活動してみたい気もするので、手を広げる方法を見つけないといけないなと思っています。

職業訓練校の立会では、学校やコミュニティとは違った感じの雰囲気を感じました。
私が立ち会ったのは半分の3ヶ月間だけでしたが、アプリケーションを作成する力を
どんどん身につけて行って、作品が完成していきました。アイデアも私の周りで
思いつくようなものではなかったのも、生活スタイルや文化の違いがあるのかもしれないと思いました。
ただ、彼らが無事将来を切り開いたのかどうか気になります。

そして、派遣会社の単発案件もさせていただきました。これも新しい経験でしたが、当時は「GTUGのマネージャを派遣できる会社なんてないだろ。貴重だぞ」なんて思っていましたが、本当にただの派遣社員として扱われました。派遣会社の社員で通さないといけないので、自営業と兼務するのは向かないかもしれません。名刺交換もできないし、営業活動的な事はできないので。これも本当に金に困った時にやることにしようと思います。

最後に執筆ですね。3月に「Google Android WebAPIプログラミング入門」、12月に「Go言語プログラミング入門 on Google App Engine」を書きました。年に2冊も
出版できるとは思っていませんでしたが、1冊目はそれなりに、2冊目はまだ結果が出ていないようですが、注目して、購入もしていただいているようなので安心しています。
3冊目に関してもまた書きたいとは思っているのですが、2冊目の時にボツになったネタなので書けなさそうだと思っています。GoやGoogle App Engineが盛り上がってきて、2冊目の内容から1歩進んだり、Go言語自体に注目した内容の本が書けたりすると良いなと思っていたりします。GoもしばらくするとVersion 1がリリースされて互換性の保証もされるようになるようですし。

最後に中国GTUGの活動に関して。
今年はハッカソンを増やすと言って、結局新年と盆の2回の開催をしました。
ポイントとして、中国地方だと2週連続で場所を確保するということが難しく、アイデアソン、チーム決めとハッカソンを分割する事ができませんでした。新年のハッカソンは2日確保して、前日にアイデアソンを、2日目にハッカソンを行いました。
8月は1日しか確保できなかったので、チーム決めも適当にせざるを得ず、「難しい」と
いう意見を頂きました。
個人的には満足していますが、課題をクリアできればと思っています。

新しい講師の発掘もしたいという事で、これまでの経緯を振り返ってみると、全体的に発表回数が少ない方に登壇をしていただけたのではないかと思っています。次の2月の勉強会も初めての発表の方にお願いしてありますし、岡山では選択の幅が広がってきたかなと思っています。広島でも開催の要望があるので、来年は広島での開催も実現したいです。
(広島のスタッフにお願いして場所を確保するしかないわけですが)

年末から、新しい試みとして、東京や大阪ではすでに行われているようですが、ソースコードリーディングを行うことにしました。きっかけは岡山Javaユーザ会で、@sinmetalさんと会話をしていた時に”そういえばSlim3のソースコードを読んでみたいよね”という話題になって、早速開催してみました。初回は5名の募集に6人の応募があるなど(そのうち2人は私と@sinmetalさん)注目度は高かったようで、楽しく(?)Controllerの辺りを読みました。

と、色々振り返ってみると、活動としては充実してたのかなと思っています。
これも中国GTUGのメンバー、地元の技術者の積極的な参加が非常に大きいと思います。
来年もどこかでハッカソン、発表挑戦者の発掘。ハンズオン、ソースコードリーディングなど、色々挑戦していきたいと思います。

が、やっぱりまず仕事の確保だな!

2011年12月25日日曜日

Slim3ソースコード読み会(2)の前に。

次回のSlim3 Source Code Reading #2が12/27(火)に開催されるのですが、
次回はmodel周りを読んでいく予定になっています。

ただ、model周りはデータストアへの読み込み、書き込みがあるため、
奥が深いので、事前に少し読んでおこうと思って読んでみました。

ひとまずメモを残しておきます。

  • Slim3はAsyncDatastoreServiceを使ってデータストアに書き込みを行っている。
非同期での書き込みなので、何もしなければ更新がすぐに反映されない(表示されない)時がある。

  • ModelクラスからModelMetaクラスを生成してデータストアに書き込みを行う。
    • ModelMetaクラスはVersionを持っている(データストアに書き込まれる)
      • Versionはputのたびにカウントアップされる。これはなぜ?
    • 同じく、SchemaVersionも持っている(データストアに書き込まれる)
      • 生成された直後は固定で"1"を書きこむ
      • SchemaVersionはプログラムの更新により、エンティティの内容が混在する時に新旧のバージョンのエンティティを判定するのに使う?
      • Modelのプロパティが追加される時にSchemaVersionも変更すべき?
  • Model→Modelの生成手順
例:slim3.model.Tweet
1. クラス名(フルパス)から".model."を探す。
2. 見つかった場合(lastIndexOf()の戻り値が0以上)
".model."より前、(今回の場合、"slim3") + ".meta." + "Tweet" + "Meta"にする
3. 見つからない場合は、そのまま+"Meta"にする
4. 2、3で生成したクラス名でインスタンスを生成する。
5. 1度生成されたMetaクラスは変換前のクラス名をキーにしてConcurrentHashMapに保存される。(2度目以降はHashMapにあるインスタンスを読みだして再利用する)


2011年12月21日水曜日

Slim3ソースコード読み会(1)

今日は中国GTUGのSlim3ソースコード読み会(1)を開催しました。

今日は最初だったので、様子を見ながらFrontControllerから読み進める事にしました。

今日読んだファイルは

  • FrontController.java
  • Controller.java
  • ControllerConstants.java
を主に読みました。

自分で実装したコントローラが呼び出されるまでの大まかな流れが知りたかったので
以下のソースコードは、呼び出しがあるのですが、読みませんでした。

  • RouterFactory.java
  • ApplicationMessage.java
  • CipherFactory.java
  • RequestUtil.java
  • RouterImpl.java
でも、帰ってからじっくり読んでみると、FrontController.javaの231行目の静的ファイルの判定の部分のためにはRequestUtil.javaとRouterImpl.javaは読んだ方が良かったのかもしれません。(という事で、再度読んでいます)

FrontController.javaの235行目のdoForward()が呼び出される条件がよくわからない等、
今回は不明な点を残しつつ進めて行きました。
(なんとなく、235行目は自分でRouterを実装した場合に変化がありそう)

FrontController.javaの261行目のdoFilter()では、リクエストとレスポンスを退避して、元に戻している処理がありますが、これの意味も今日の段階ではよくわからないポイントだったと思います。

分かった点は、

  • slim3-blankのweb.xmlにある、context-paramで、slim3.rootPackageは省略できない。
  • 同じく、javax.servlet.jsp.…localizationContextは設定が無くても"application"となる。(デフォルトが"application")
  • 同じく、javax.servlet.jsp.…request.charsetも設定がなくても"UTF-8"となる(デフォルトが"UTF-8"。ただし、リクエスト時にcharset指定がある場合はリクエストが優先される)
  • IndexController(というか、Controllerを継承したコントローラ)はsetUp()、run()、tearDown()の順番で呼び出される。それぞれ、事前処理、主処理、後処理となる。tearDown()で例外が発生すると、WARNレベルのログが出力される。

今日、一番の議論は、リクエストURLからコントローラのクラス名(フルパス)に変換するルールでした。

例えば、
http://localhost:8888/sample/
だと、
slim3.controller.sample.IndexControllerというパスに変換されて呼び出されます。

変換ルールは、
rootPackage + "." + コントローラパッケージ名 + "/"を"."に変えたgetServletPath() + "Controller"となります。

これにより、例えば、
http://localhost:8888/sample/hoge
であれば、
slim3.controller.sample.HogeControllerが呼び出されるようになります。

しかし、
http://localhost:8888/sample
だと、
slim3.controller.sampleControllerというパスに変換されるはずですが、
URLがhttp://localhost:8888/sample/に書き換わって実行されていました。
(想定と違った動き)

単純なURL書き換えが発生しているのか、Framework側で書き換えているのかは
よくわかりませんでした。

といった所で、本日はタイムアップしました。

次週は12/27(火)の19:00〜21:00の予定で、
Modelのあたりを読む予定です。

2011年12月20日火曜日

Slim3ソースコード読書会の前に

12/21(水)にSlim3ソースコード読書会(1)を開催する予定なのですが、
思ったより参加者が多いので、それなりに前提知識を整理したいと思います。

第1回はFrontControllerから各Controllerへの処理の振り分け部分について
読んでいく予定ですが、まずjavax.servlet.Filterインターフェイスの認識がないと
だめだと思ったのでその辺りの挙動をまとめておきます。

まず、Slim3でも(Blankプロジェクトのweb.xmlに定義)3つのFilterが定義されています。

    <filter-mapping>
        <filter-name>HotReloadingFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>  
    <filter-mapping>
        <filter-name>DatastoreFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
    <filter-mapping>
        <filter-name>FrontController</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>ERROR</dispatcher>
    </filter-mapping>
第1回は名前の通りのFrontControllerから読み進めてどのようにControllerの振り分けを
行っているかを確認していこうと考えています。
処理の順番としては、<filter-mapping>タグが付いている順番にFilterインターフェイスが呼び出されます。今回のケースだと、
  1. HotReloadingFilter
  2. DatastoreFilter
  3. FrontController
が呼び出し順になります。したがって、<filter-mapping>の順番を入れ替えると呼び出し順も逆転します。

その挙動を確認するプログラムは、どこかにおく…必要もないと思うので、抜粋します。
3つぐらいFilterを作って設定すれば動作可能だと思います。

public class FirstFilter implements Filter {

 @Override
 public void destroy() {
  // TODO Auto-generated method stub

 }

 @Override
 public void doFilter(ServletRequest req, ServletResponse res,
   FilterChain chain) throws IOException, ServletException {
  System.out.println("FirstFilter#doFilter");
  chain.doFilter(req, res);
 }

 @Override
 public void init(FilterConfig arg0) throws ServletException {
  // TODO Auto-generated method stub

 }

}

Filterインターフェイスは3つのメソッドを実装し、以下のタイミングで呼び出されます。
  • init():フィルタの初期化時(1度だけ呼び出される)
  • doFilter():web.xmlの<filter-mapping>タグで設定したリクエスト時
  • destroy():コンテナが破棄される時などフィルタが破棄されるタイミング
Slim3では、doFilter()を駆使してコントローラの振り分けを行っているようです。

また、doFilterの引数であるFilterChain#doFilter(req, res)を呼び出さないと、
以降のFilterが実行されなくなるので、サーブレット/JSPを実行する場合も
注意が必要です。(動作を確認する場合は、chain.doFilter()をコメントアウトして下さい。)

以下、参考にしたサイト

Javaの道(Servlet-10.フィルタ)
http://www.javaroad.jp/servletjsp/sj_servlet10.htm

tomcatのドキュメント(Filterインターフェイス)
http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/Filter.html

Tomcatでフィルタを使う
http://www.nina.jp/server/slackware/webapp/tomcat_filter.html

new関数とmake関数について


私が書いたGo言語プログラミング入門 on Google App Engineにある記述で間違いがあったのですが、正誤表に書くには長いので、この記事に残しておこうと思います。

P.125のnew関数とmake関数の使い分けの所で、
次のように間違った例を掲載しています。

intArray := new([]int)
fmt.Fprintf(w, "%d¥n", intArray[0])

これは、そもそも書き方が間違っているという指摘を受けまして、
確認をしてみました。結論は間違ってます。

new([]int)が返す型は「*[]int」型です。int型配列に対するポインタが返されます。
しかも、配列の長さを指定していませんので、配列の長さが0です。
中身がありません。

したがって、intArray[0]と書くのは間違いで、(*intArray)[0]と書くのが
正しい表記となりますが、配列の中身がないので、実行時にエラーになります。

しかし、次のように、配列の長さを指定した形で使えば実行時エラーにはならなくなります。

intArray := new([5]int)
fmt.Fprintf(w, "%d¥n", (*intArray)[0])
検証したプログラムも掲載しておきます。
検証したバージョンはVer.1.6.1ですが、未検証ですが1.5.5でも問題ないと思います。

package newsample

import (
 "fmt"
 "http"
)

func init() {
 http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
// 書籍の例は間違い!
// intArray := new([]int)
//
// fmt.Fprintf(w, "%d\n", intArray[0])

 intArray := new([5]int)

 fmt.Fprintf(w, "%d\n", (*intArray)[0])

 intArray2 := make([]int, 5)

 fmt.Fprintf(w, "%d\n", intArray2[0]) 
}


new関数の使い方について認識不足でした。
今回も柴田芳樹さんにご指摘いただきました。本当にありがとうございました。

GoのTypeAssertion(型変換?)


私が書いたGo言語プログラミング入門 on Google App Engineにある記述で間違いがあったのですが、正誤表に書くには長いので、この記事に残しておこうと思います。

P.108で「インターフェイスの型の変数に値を代入した後、本来の型に戻す事はできません。」と記述しているのですが、実際は、戻すことが可能です。
具体的な方法は、"変数名.(型)"と記述することで復元します。
Go言語の言語仕様にも、Primary expressionsに記載がありました。

実際の検証用のソースコードです。
動作確認はSDK1.6.1で行いましたので、書籍のベースバージョン1.5.5では未検証ですが、
古いバージョンのSDKで開発される事は減るかと思いますので、検証していません。

以下のソースコードが検証用です。(ほぼツッコミ時に紹介されたソースのままですが…)

package interfacesample3

import (
 "fmt"
 "http"
)

type Introduction interface {
 intro(w http.ResponseWriter)
}

type Coffee struct {
 Sugar bool
}

func (coffee Coffee) intro(w http.ResponseWriter) {
 if coffee.Sugar {
  fmt.Fprintf(w, "This is a coffee with sugar\n")
 } else {
  fmt.Fprintf(w, "This is a black coffee\n")
 }
}

func init() {
 http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
        // Introduction型の配列を作成し、Coffee型のインスタンスを代入する。
 array := make([]Introduction, 1)
 array[0] = new(Coffee)
 array[0].intro(w)

        // そもそもnew関数で返される型はCoffeeではなく、*Coffee!
 var coffee *Coffee
 coffee = array[0].(*Coffee)
 coffee.Sugar = true
 coffee.intro(w)
}

出力結果は
This is a black coffee
This is a coffee with sugar

となり、復元できている事がわかります。

書籍の型の復元については、完全に不勉強でした。
今回は柴田芳樹さんにご指摘いただきました。本当にありがとうございました。

2011年12月18日日曜日

Goでの日付変換

私が書いたGo言語プログラミング入門 on Google App Engineにも記述していないので、ここに載せておきたいと思います。

書籍内だとデータストアに日付を登録する時に、以下のような記述をしています。

datastore.SecondsToTime(time.Seconds())

これは、現在日時が取得されて日付がdatastore.Time型(中身は整数)に変換されます。
確かに現在日時であれば、これで良いのですが、指定した日時を格納したい場合に
この方法では日時のデータに変換することができません。
したがって、他の言語と同様に、文字列から日時データに変換します。
以下のような記述にします。

strdate := "2011-12-18 23:00:00"
inputtime := time.Parse("2006-01-02 15:04:05", startdatestr)
datastore.SecondsToTime(inputtime.Seconds())

これは、年:4桁、月:2桁、日:2桁、24時間表記の時間、2桁の分、2桁の秒となります。

time.Parse関数の第1引数がフォーマットを指定するのですが、標準で用意されている
フォーマットもあります。以下、timeパッケージのformat.goからの抜粋です。

const (
ANSIC    = "Mon Jan _2 15:04:05 2006"
  UnixDate = "Mon Jan _2 15:04:05 MST 2006"
RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
RFC822   = "02 Jan 06 1504 MST"
// RFC822 with Zulu time.
RFC822Z = "02 Jan 06 1504 -0700"
RFC850  = "Monday, 02-Jan-06 15:04:05 MST"
RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
RFC3339 = "2006-01-02T15:04:05Z07:00"
Kitchen = "3:04PM"
// Handy time stamps.
Stamp      = "Jan _2 15:04:05"
StampMilli = "Jan _2 15:04:05.000"
StampMicro = "Jan _2 15:04:05.000000"
StampNano  = "Jan _2 15:04:05.000000000"
)

RFC準拠のフォーマットであれば、"RFC3339"などと指定することで書式に合わせて文字列を解析し、変換してくれます。

JavaやC#などと違って"yyyy/MM/dd HH:mm:ss"というフォーマットが指定できないのが大変ですが、慣れると意外と良いかもしれません。

2011年12月16日金曜日

Go言語プログラミング入門(正誤表)

そろそろ(12/16時点)私の2冊目の書籍、「Go言語プログラミング入門 on Google App Engine」が発売されて、手元に届いた頃だと思うので、読者の方からの指摘、自分自身で発見した誤りをメモしておきたいと思います。
正式な発表は出版社のサイトを御覧ください。
※2011/12/20追記:秀和システムさんにも連絡して公式の正誤表となりました。

  • P.43 中段3行目:「メソッドf()」→「メソッドf」
余計な()が含まれていました。()は不要です。
柴田芳樹さんありがとうございました。

  • P.69 8行目:「2バイトずつ読み取っている」→「3バイトずつ読み取っている」
これに関しては、内部の文字コードがUTF-8なので、全角文字は基本的に3バイトとなります。JIS X0213のBMPセットからはみ出す文字は4バイトとなります。
私の文字コードの知識不足でした。
@titoi2さんありがとうございました。
  • P.108 4行目:「インターフェイスの型の変数に値を代入した後、本来の型に戻すことはできません。」→「できます」
詳細は、別の記事に残しましたのでご確認下さい。
柴田芳樹さんありがとうございました。

  • P.125 new関数の間違った使い方の例が間違っている。
詳細は、別の記事に残しましたのでご確認下さい。
柴田芳樹さんありがとうございました。

  • P.216 「今回のプログラムは、ローカルサーバで実行しようとしても、図4-19のようにエラーになってしまうので」→「図4-26」
指定している図の番号が間違っていました。正しくは図4-26です。
また、ローカルサーバでもCross Group Transactionの実行は可能です。
ただし、ローカルサーバの起動オプションの--high_replicationを指定する必要があります。
現時点では、--high_replicationはデフォルトfalseなので、Master-Slave型で動作します。

  • P.228 ユーザ認証のポイント2点目「OpenIDについては現時点ではAPIのみ提供していて動作しない」→「OpenIDはクラウド環境でFederated Loginの設定にすれば、動作する」
これは、直前で設定の手順だけ記述しましたが、(今、思えば、キャプチャ画像ぐらいは貼れば良かった)本番環境にデプロイして実行すれば動作します。
結果は、デプロイして出力結果を確認してみてください。
  • P.271 ソースコード1行目「var body = make([]byte, res.ContentLength)」→「var body make([]byte, 0, res.ContentLength)」
SDK 1.5.5ではこのままでも大丈夫だと思うのですが、1.6.1で利用する場合は先頭に余計なデータが詰まってしまうので長さ0の容量がデータ長のバッファを確保する必要があります。
別の記事にもまとめてあるのでご確認下さい。
http://takashi-yokoyama.blogspot.com/2012/01/bytesnewbuffer.html
  • P.349 「必ずデータを登録した状態で実行してください」
  • P.352 「また、最初に注意しましたが…プログラムが応答を返さなくなってしまう」→「Load()でdatastore.LoadStruct()、Save()でdatastore.SaveStruct()を呼び出すか、close(c)を呼び出してChannelをクローズしないとプログラムが応答を返さなくなってしまう」
文章自体は正しいのですが、PropertyLoadSaverのSaveメソッド(P.350(4))で、SaveStruct()かclose(c)を実行しないと登録処理を行うときにロック(応答を返さなくなる)してしまいます。
逆にP.350のLoad()メソッド(2)内でLoadStructを呼び出すかclose(c)を呼び出さないと読み出し時もロックします。
  • P.359 2段目、3行目最後「本書の内容も動作するような」→「本書の内容が動作しなくなるような」
正反対の記述になっていました。バージョンが上がると、書籍のソースコードがコンパイルエラーになってしまう可能性があります。



2011年12月8日木曜日

Googleの周辺技術(メモ)

shin1ogawaさんが発表された時の資料で、中国GTUGでの発表のネタになるかと
思ったので、ブックマークしようかと思ったのですが、
ブログに残しておこうかなと思います。

ひと通りのGoogleのAPIやサービスを知るには良い資料だと思いました。

2011年12月7日水曜日

第1回岡山PHP勉強会に参加しました。

第1回岡山PHP勉強会に参加してきたので、そのメモを残しておきます。

システム構築事例の話(…?)

  • 突発的なアクセスの増加
  • Yahooアタック
    • Yahooのトピックスにリンクが付くと…
    • 動画への直接リンクはやばい
  • PHPを選んだ理由
    • 簡単
    • みんな使っている
    • 自由度が高い
    • サーバ設定が簡単
    • 速い(?)
  • しかし
    • コードの統一性がない
    • セキュリティが最悪
  • フレームワークを活用することにした。
    • 開発時間の大幅短縮
    • ルールに従うと、コードが統一
    • DBとの連携が簡単
    • 表示が速い(ページキャッシュ機能)
  • PHP勉強法
    • 参考までに。
      • 目標を作る(アプリを1週間で作る。必ず日程を決めておく事。)
      • 入門書とリファレンスブックを購入
        • 作りたいものに近いサンプルがある本が良い
      • 説明を見ながらとにかく作る
      • リファレンスブックを見ながらソースコードを読む
      • 自作アプリケーションを作成する。
    • オープンソースを解読(バグ情報は便利)
    • 参加する
    • オープンソースを作る
    • 勉強会に参加する
  • TIPS
    • コードのガイドラインを決める
    • コードの最適化
    • セキュリティに気を使え!
      • サニタイズ処理だらけの関数等を通して無効化する。
    • 英語ができたほうが良い
    • 最新情報を得る(セキュリティ等)
    • 初級者こそフレームワークを使うべき
  • 3カ月以前の自分のソースコードを恥ずかしく思える様になること。
    • 常に精進しつづけましょう!
  • アイデアをお待ちしております!
  • 苦労した点
    • ロードバランサ
PHPフレームワーク入門
  • 無害化する方法(フレームワークを使わない場合)
    • htmlspecialchars()
    • mysql_real_escape_string()
  • いつも同じようなコードを書いている?
  • 以下のようなコードは…
    • ロジックとデザインがごちゃまぜになったコード
    • ルールが統一されていない
  • サーバを移したら動かなくなった。(PHPの場合)
    • バージョンの違い
    • 設定値の違い
    • ライブラリの不足
  • セキュリティが不安
    • いろいろな攻撃

  • フレームワーク(Framework)
    • 骨組み
    • 土台となるもの
    • 主な役割
      • 標準的な機能の提供
        • ライブラリ
        • ヘルパー関数
          • CakePHPのpr()
            • print_r()の結果を<pre></pre>で囲って出力する
      • MVCモデルの実現
        • Model
        • View
        • Controller
      • MVCモデルのメリット
        • 独立性の確保
          • 機能毎の役割が明確になる
        • 依存性の抑制
        • 保守性の向上
      • ORマッピング
      • ルールの制定
        • 命名規則
          • 変数名、テーブル名
          • ディレクトリ構成
          • コーディングスタイル
    • フレームワークのデメリット
      • 学習コスト
      • どれが良いかわからない
        • 色々なフレームワーク
          • 場合に応じて使い分ける
        • 選定基準
          • 実用性
            • 安定性
            • 機能、対応バージョン
          • 開発の継続性
          • ライセンス
          • 情報の入手しやすさ
    • CodeIgniter
      • 高速
      • 軽量
        • ソースの容量は(展開後で)1.2M
      • 低い学習コスト
      • 日本語のユーザガイドが完備
    • CodeIgniterのURL
      • index.phpがフロントコントローラ
        • URLは、index.php/fuga/piyo/paramなど。
          • class fuga extends CI_Controller {
            • function piyo($param) 
    • 便利な機能
      • active_record
      • form_validation
    • View
      • 共通部分はinclude

セキュリティについて考えてみよう
  • バグ、脆弱性
    • バグとは何か?
      • なるべきものが、そうならない。
    • 脆弱性とは何か?
      • バグと言えばバグ。
      • そのうち、セキュリティに関係するもの
        • 例)脆弱なOSで動作しているサーバがあっても、ファイアウォールで完全に隔離されていれば問題はない。
          • 外部から接続できないので。
      • セキュリティホール、脆弱性はバグの一部。
    • アプリケーションが正常に動作するように作ること。
      • 「一定の定義」に従って正常に動作するのであれば問題ない。
    • リスクを知り、対応する
      • 以下のような問題に対して
        • SQL Injectionでデータを取られた
        • SQL Injectionでページを書き換えられた
      • Webアプリケーションは「最もリスクがあるもの」
        • 全世界に向けて公開する前提だと。
        • 自分のサーバは人気がないから問題ないだろう。
          • クラックする人は、踏み台にするためにサイトの大小に関わらず攻撃してくる!
          • 従って、これは間違い。
    • リスクとは何か?
      • CVEというデータベースがある。
    • 入力、処理、出力
      • エコーバック問題?
      • 9割方、入力と出力の部分で対処がない。
      • 基本的に自分のアプリ以外は全て信用できない前提で考える。
        • 信頼境界線
      • 入力は「全てバリデーション」
        • 「サニタイズ」とは違う
          • ブラックリスト的考え方。(悪いものを弾く)
          • validationはホワイトリスト的考え方。(良いもののみを受け入れる)
      • 処理は「ベストプラクティスに従う」
        • 話をすると長くなるので省略
        • めんどくさい
      • 出力
        • エスケープを理解し、エスケープする
        • ヘルパーを理解し、ヘルパーを使う
          • 属性名をエスケープしないヘルパーがあるので、下手すると、そこがXSSの原因になる可能性も。
        • エスケープもヘルパーも使えないものはバリデーション
        • どうしようもないもの、絶対に安全だとわかっているもの
          • そのまま出力
    • アプリケーションが正しく動作することを担保する
      • 特にセキュリティに特化する場合
        • CIAを保証する
          • Confidential(機密性)
          • Integrity(統合性)
          • Availability(可用性)
      • セキュリティ対策に役立たないセキュリティ対策はない
    • セキュリティ対策とはリスクマネジメント
      • リスクを許容できれば、どんな対策でも構わない。
        • リスクを理解した上で、どこまでリスクを許容できるのか。
        • ただし、他人に迷惑はかけない
      • 例えば、文字エンコーディングのバリデーション
        • 入力時に文字エンコーディングをバリデーションする。
      • 適切な設計も必要
      • どれが優れたセキュリティ対策か?よりも、必要なセキュリティ対策か?が重要



2011年12月3日土曜日

第11回中国GTUG勉強会

第11回勉強会を開催しました。内容のメモを残しておきます。

DevQuizへの参加

  • Googleの開発者向けイベント
    • できるだけ能力の高い人に参加してもらうため
    • より多くの開発者に参加してもらう
    • 公平な選抜方式
    • イベントの前に開発者に楽しんでもらう
  • ウォームアップ問題
    • Google技術のトリビア
  • 分野別問題
    • Web Game
      • JavaScriptを使った神経衰弱
    • Go
      • PNG画像を与えられて、何色の画像があるかを調べる
    • Android
      • AIDLを使ってデータを抜き出す。
    • Google Apps Script
    • 一人ゲーム
  • スライドパズル

  • 参加者:3000人
  • 通過者:1000人
  • ボーダー:100.56点/150点
  • スライドパズルは、結果を探索するコードをバグ無くかければ。。
  • スコア分布
    • 100〜110点のところに大半の方が分布
  • 問題作成チームのコメント
    • みんな頑張りすぎ。
    • 30人も満点を取るとは思っていなかった。

  • スライドパズル
    • 解決するための定石
    • 幅優先探索
      • 1手後、2手後の状態を保持して、ゴールの状態になるかを調べる
    • 双方向探索
      • スタートとゴールから幅優先探索
    • でも、最短経路を見つけるのは無理!という結論
      • 20Byteぐらい保持して、2億通りなので、4GBぐらいになる。PCではこれが限界。
      • ゴールに近づいたかどうかを評価する関数を準備。
        • 当然、壁の有無も考慮しなければならない。
        • この時点で844問/5000問
    • 評価関数に一工夫をする。
      • 先に盤面の真ん中を揃えると、左上を揃えに行く時に乱される。
        • 無駄が多くなる。
      • 人間だと左上から揃えるようにする。
        • 人間が解決する方法を考えると解決策が思いつく場合がある。
    • メモリの省力化
      • 経路を1byte保持→2bit保持へ。
      • intをint8_tへ。
      • 4000問ぐらいまでは結構行ける。
    • 難しいケースの対策
      • 通路のようになっているケース
      • 4966問/5000問
    • もっと難しいケース
      • 結局、手動で解いた。
      • 5000問/5000問
    • 手数は12426手余った。
    • 最長手数は303手
    • 思考・コーディングは40時間
    • 計算時間は40時間
    • 最後の手動の問題を解くのに10時間位
  • 言語はC++で。
    • 処理速度が重要
    • 寝るときに計算し始めて…
      • 起きた時に終わる or 丸一日
    • C++11は便利
      • 拡張for
      • 型推論のauto
      • ラムダ式
      • サイズを指定できる整数型
    • 実装上のほそぼそとしたこと。
      • 盤面サイズをテンプレートパラメータ化
        • 1.5倍ぐらいの速度向上
        • ただし、コンパイル時間は16倍…
  • Samurai Coding
  • TopCoder
  • Code VS
  • AI Challenge Ants(スポンサーがGoogle)

  • 近似解を求めるプログラムの重要性
    • 「アルゴリズムイントロダクション」の練習問題より。

  • NASA TopCoder Challenge
    • NASAがスポンサー
  • 身につく能力
    • ボトルネック以外を最適化する無意味さ
      • 面白いぐらい無意味なんだそうです。手を付けやすい所からやってしまうという人間の性も。
    • 実装の難しさと効果を天秤に掛ける感覚
    • コードを綺麗に保つことの大事さ
      • 後で改造が難しくなる
    • 作業管理
      • バージョン管理は大事!

  • EXP-Hackathon
    • WebIntents、GITKitを使って簡易画像ピッカー
    • 自動飲み会幹事システム
    • Hangoutsを自分のガジェットに埋め込む
    • etc

Google Code Jam Japanに参加した
  • TopCoderは言語の縛りがあるが、Google Code Jamについては、縛りはない。
    • TopCoderはAppletか何かで動作しなければNGとなるかも?
  • Google Code Jam Japan
    • 問題は3〜6問
      • SmallとLarge
        • Smallは制限時間4分(再挑戦可能、即答される)
        • Largeは制限時間8分(時間内に限り、再挑戦可能)
    • テストケースの入ったファイルをダウンロードし、実行結果をソースコードと一緒に提出
    • 各問題の得点と回答した時間で順位が付く
  • 競技の流れ
    • 参加登録(2月中旬登録開始)予選終了前なら登録可能
    • 練習問題
    • 予選(10/1 13:00〜19:00)
      • 6時間で3問の問題
        • 予選で1問以上の問題でSmall、Largeの両方を解いた人のみ
        • 600人程度
    • 決勝(10/8 13:00〜16:00)
      • 3時間で5問の問題
  • 戦略
    • 言語:Java(Eclipse)
    • 予めプロジェクトを作成しておく
      • ファイルを読み込み、出力するというテンプレート的なコード等
    • 先に問題を全部読んで、解けそうなものから解く
    • サンプルの入力・結果で確認
      • 問題にサンプルの入力、結果がある。
  • 予選
    • B問題はコーヒーの幸福度、賞味期限を扱う
    • C問題はビット数を数える
  • 決勝
    • 手も足も出ず
    • 長さを持つアンテナのエレメントを並べて、感度が良くなるパターンを算出。みたいな問題など
Google Developer Day 2011のフィードバック
  • 技術的な情報を紹介するイベント
  • OAuth1.0→OAuth2.0へ!
  • OAuth2.0とOpenID Connectによる認証
    • Google Identity Toolkit
    • Account Chooser
  • Google APIs Consoleで登録
  • OAuth2.0のaccess_tokenを取得
    • Scope https://www.googleapis.com/auth/userinfo.mailなどを指定。
  • Account Chooser
    • https://account-chooser.appspot.com
    • 認証で使うウィジェット
  • 認証はGoogleなどのクラウド側に任せてしまって、アプリケーションの開発に力を注いだほうがいいのでは?
  • Chromeのデベロッパーツールについて
    • HTML/CSSの編集・更新、差分履歴、バージョン管理
    • スタイルシートの変更をリアルタイムに反映
    • 定義を追加も可能
    • 補完機能
    • 差分履歴、バージョン管理
      • 変更履歴が残る
      • 指定するバージョンに戻すことも可能
    • Firebug CommandLine APIとの互換もある。
    • リモートデバッグ

  • HTML5のオフライン機能
    • バイナリデータの保存
      • File System API
と、言う感じで、タイムアップ
資料は、公開されたら中国GTUGのサイトで公開します。