2014年8月30日土曜日

Golang Cafe #44を開催しました。

Golang Cafe #44を開催しました。

今回は東京で行われたGolang勉強会の資料のうち、 +Takuya Uedaさんの「インターフェイスの実装パターン」を読み進めました。

主な内容としては

  1. 独自の型定義(typeキーワードの使い方)
  2. インターフェイス型変数への代入とキャストの方法
  3. Goのインターフェイスはメソッドが全て実装されていれば、インターフェイスとして認識される。
  4. 関数型を定義してメソッドを実装すると、関数にインターフェイスを実装することができる。
  5. 構造体に別の型の埋め込みについて
  6. 埋め込みによるインターフェイスの実装
ポイントとして、私も以前から思っていたことなのですが、
何でもstructで実装するのはGo言語っぽくない。
ということで、typeとメソッドの理解をしっかりしましょうということでした。他にも埋め込みのところで、同じメソッド名でも埋め込むと型名を省略する事ができるなど(参考:http://play.golang.org/p/XRFBWEtqpu)Goの仕様を確認しました。

現時点の個人的なプロジェクトのみで話をすると、埋め込みやインターフェイスを活用するケースはほとんどないのですが、技術は知っておいていいと思うのですが、できるかぎり「仕様をシンプルに」できるようにするのがいいんだろうなー。と思っています。(それができれば苦労はしないのでしょうが…。)

埋め込みも便利ですが、DBに格納するとか、jsonに変換する時に複雑にな(≒ハマ)りがちな気がするので埋め込みもほどほどに…(?)


2014年8月23日土曜日

Golang Cafe #43を開催しました。

Golang Cafe #43を開催しました。

今回は久しぶりに、+Takanobu Haginoさんと+Ryuji Iwataさんと私の3人だったので、
今後のGolang Cafeで扱ってみる内容を話してみました。さすがに43回もみっちりやってくると、昔のことは忘れてくるとはいえ、経験値が上がってきて新しい発見も少なくなってきます。

Golang Cafe #24とか、Golang Cafe #25のblogあたりで触れた「熟練度による需要の差」も気になっているままではありますが、だんだんとやることがなくなってきました。(という気がする。が、無いわけではない。)

次回は資料を読むことにしていますから、その次ぐらいから「実際に作る」ことをメインの活動にしようと思います。都度、何か資料が出てきたらそれを読む回にしようかなと。
(もとからそのつもりでやって来たので、43回の遅れがあっただけということで。)

その作るという作業の中で、個人的に作りたいツールとか、APIを実行したりということがあるので、Goで(主にGAE/Goで)やってみたいと思ってます。

Managed VMsのPreviewにも申し込んだし、基本的にはGoというよりは、GCP関連の作業がしたいだけなんですが、言語はGoでやってきたので、それを実践するという感じで。

Goに関するアピールとしては、40回以上やってきたので、だいぶ知れ渡ったかな?と思っていますが、どうなんでしょうね。

それから、新たな人が参加する事が増えてきて、人数も気にしないといけないと考えたりしましたが、そんなに満員御礼が長続きすることもなく、規模は大きくするつもりがないので、もしも満員になったら補欠で登録しておいてください。

あまりまとまっていませんが、計画もまとまっていないのでこんな感じで。

2014年8月9日土曜日

Golang Cafe #41を開催しました。

Golang Cafe #41を開催しました。今回は、Goで作られたORマッパーのgorpを触ってみました。
今回の内容を進めるにあたっては、@mattn_jpさんのblogを参考にしました。
blogの記事自体は古めのものですが、最新バージョンでも安心して利用できますので、
読み進めて見てください。
ただし、blog記事では、SQLiteを使ったサンプルになっているため、PostgreSQLで使うためには、

gorp.SQLiteDialectをgorp.PostgresDialectに読み替えて進める必要があります。
読み替えるだけで、プログラムの動作の結果は変わりませんので、インストールしてあるデータベースを利用して使えばいいでしょう。
ただし、利用するデータベースとDialectが一致しないと全く動作しませんのでご注意下さい。

サンプルコードはgithubにpushしてありますのでそちらをごらんください。

個人的な感想としては、Golang Cafe #4の時に標準ライブラリでデータベースを利用する時に比べると段違いに便利になります。(ORマッパーを普段から使っていらっしゃる方の場合は、大体分かっていると思いますが)
私は、ORマッパーを使ってみたのはほぼ初めてに近かったので、非常に感動しました。

ちなみに、機能としては、テーブルの作成、検索/更新は動作確認をしました。本家のサンプルを見る限りだとテーブルの削除もできるようですし、構造体のフィールドタグも利用できるようになっています。(`db:"project_id`など)

今回は、初めての参加者がいらっしゃったのですが、今回も+Ryuji Iwataさんにお願いして最初のセットアップのお世話をしていただきました。ありがとうございました。
また、Windowsユーザだったので、+Takanobu Haginoさんのノウハウを参考に進めたのですが、最初のセットアップのノウハウを本家サイトに載せておいた方がいいんじゃないの?という話題がでてきました。これまでは、Golangのセットアップ自体は適当に参加者がやってくるというスタイルだったので適当だったのですが、前回は初心者の方を置き去りにする形になってしまったので、ちょっと考えないといけないと思った瞬間でした。
(ちなみに、座席の関係で+Ryuji Iwataさんにお願いしましたが、私の隣だったら私が対応するつもりだったという前提でお願いします。)

次回はこれまで読んでいなかったEffective Goを読み進める予定です。

が、台風が近づいていてかなり危ないと予想されるので初めての中止となるかも…?

2014年8月2日土曜日

Golang Cafe #40を開催しました。

Golang Cafe #40を開催しました。

今回は、Gorilla Toolkitの残りの4つ(reverse、rpc、schema、securecookie)を使う回でしたが、schemaとsecurecookieはドキュメントを読むだけで終わっています。

reverseですが、元になるURLの文字列をコンパイルしておいて、部分文字列を指定するとURLの文字列が生成されるというパッケージです。用途として、URLの一部の文字列を渡して復元してリクエストを送信するというケースで使えそう(クライアント側の処理を作る時など)ですが、いまいちそこまでの需要があるのかどうかは疑問が残る結果となりました。

package main

import (
 "log"
 "net/url"

 "github.com/gorilla/reverse"
)

func main() {
 var err error

 regexp, err := reverse.CompileRegexp(`/foo/1(\d+)3`)
 if err != nil {
  log.Fatalln(err)
 }

 // url.Valuesの値からURLを生成。
 url, err := regexp.Revert(url.Values{"":{"45678"}})
 if err != nil {
  log.Fatalln(err)
 }

 log.Println(url)
}

reverse.CompileRegexp()で正規表現を含むURL文字列のひな形を作成して、
reverse.Revert()で復元した文字列を返しています。最初は他のパッケージで使っているものなのかと思いましたが、どうやら使われている様子はなさそうです。

次に、rpcパッケージですが、これは、rpcサーバを作る時に利用します。
サーバ側の実装はそこまで難しくなく、Codecの登録と、RPCのリクエストに対して呼び出されるServiceのTypeのインスタンスを登録しておくだけです。

package main

import (
 "net/http"

 "github.com/gorilla/rpc"
 "github.com/gorilla/rpc/json"
)

func main() {
 s := rpc.NewServer()
    s.RegisterCodec(json.NewCodec(), "application/json")
    s.RegisterService(new(HelloService), "")
    http.Handle("/rpc", s)

 http.ListenAndServe(":8080", nil)
}

type HelloArgs struct {
    Who string
}

type HelloReply struct {
    Message string
}

type HelloService struct {}

func (h *HelloService) Say(r *http.Request, args *HelloArgs, reply *HelloReply) error {
    reply.Message = "Hello, " + args.Who + "!"
    return nil
}

サーバ側はそんなに難しくないのですが、動作を確認するためにクライアントを作成して通信させる所でハマりました。

Goにも標準のnet/rpcパッケージが存在するのでそれを利用するのが便利だと思うのですが、標準のパッケージだとgorilla/rpcと通信することはできません。
理由は、gorilla/rpcでの待受はPOSTのリクエストを待っているようなのですが、
標準のnet/rpcパッケージはどうやらGETのリクエストを送っているらしく、レスポンスが400とか、415が戻されてしまいます。したがって、自分でリクエストの処理を実装してやらないといけません。

package main

import (
 "io"
 "log"
 "net/http"
 "os"
 // "net/rpc"
 "strings"
)

type HelloArgs struct {
 Who string
}
func main() {
 // HTTP ClientによるRPC呼び出し。
 // jsonのパラメータを自分で作って上げる必要がある。
 client := http.Client{}
 res, err := client.Post("http://localhost:8080/rpc", "application/json", strings.NewReader(`{"method":"HelloService.Say","params":[{"Who":"Test"}], "id":"1"}`))
 if err != nil {
  log.Fatalln(err)
 }

 // 標準のDialHTTPPathはGETのリクエストが投げられるらしい。
 // したがって、標準のrpcパッケージは使えない(?)
 // client, err := rpc.DialHTTPPath("tcp", "localhost:8080", "/rpc")
 // if err != nil {
 //  log.Println("DialHTTP")
 //  log.Fatalln(err)
 // }

 // defer client.Close()

 // var reply int

 // args := HelloArgs{Who: "hoge"}
 // err = client.Call("HelloService.Say", args, &reply)
 // if err != nil {
 //  log.Println("Call")
 //  log.Fatalln(err)
 // }

 // log.Println(reply)
 io.Copy(os.Stdout, res.Body)
}

RPCのリクエストを送ったことがなかったので、どうすればいいのかわかりませんでしたが、curlの例が検索にヒットしたのでパラメータを設定して送り、無事レスポンスが得られました。でも、これはめんどくさい!
設定があるのか、コードが悪いのかは調べきる事はできなかったので、また今後調べていこうと思います。ただ、RPCサーバを実装する事があるかどうかはわかりません。

次回は、GoのO/Rマッパーであるgorpを使ってみる会になります。