脱ソシャゲして、Gunosyに転職しました
某ソシャゲ会社を退職して、2015年1月中旬にGunosyに転職しました。
といっても、もう約2ヶ月くらい経過していますね。(今更感ある)
Gunosyに入ったキッカケでもある、Gunosy.go#11を先日開催して一段落ついたのでご報告?も兼ねてブログに書くことにしました。
前職
2年半くらいスマートフォン向けのソーシャルゲームの開発してました。ちゃんとしたエンジニアが一杯いる中で、日々成長してこれたのは前職のおかげだと思ってます。
最初のPJがiOS向けのWebViewのゲームだったので、JavaでサーバーサイドとBackbone.jsとかのフロントエンドをやりました。 1年くらい運用して、Android向けも出すことになって、サーバーサイドまたやるのも味気ないので、Android側やらせてもらって、ついでにCocos2d-xでクロスプラットフォーム対応していったりなど色々自由にやらせてもらいました。
Cocos2d-xは、個人開発でも色々やってこのブログもなんかCocos2d-xブログっぽくなりました。
良かった点は、色々とあって中々辞め時が難しかったです。
- Qiita:Teamがかなり活発になってて、エンジニアの雰囲気がよくなってた
- 設計書と呼べるものはないが、ER図は必ず正とする文化ができていた
- 裁量労働制、福利厚生など充実してた( ^ω^)
退職した細かい理由は色々あったけど重要な点を以下に抜粋。
- 数年先を考えた時、このままゲーム開発技術を伸ばしていくことへの疑問
- 今は技術力よりプロジェクトを回す能力を高めるべきでは?思ってしまうような状況(マネージャ不足)
- 一緒に研鑽したり、尊敬できるようなエンジニアが周りにいなくなった
- Go書きたい
タイミングとか色々ちょうどいい感じだったのもあったのですが、社内政治的な話になりそうなので黙っておきます。
Gunosyを選んだ理由
- 冒頭にも書きましたが、Gunosy.goに参加して興味を持った
- Goをプロダクトで採用していて、今後もGoにする勢いの強さを感じた
- 技術的なチャレンジを推奨する文化(仮に爆死したとしても)
Gunosy入って感じたこと
とにかく開発者各個人のスキルレベルが高いです。デザイナもiOS書いたり、React.Js書いてたり。 Android開発担当がGoでAPI書いてたり。
iOSとAndroidとPythonとGoとRuby書いたりインフラやったりする人がいたり(マジすげぇ。。。)
上記のようなメンバーと一緒に仕事できるのと、業務でGo書いているとこんなGoのツールあるといいなーとかライブラリあるといいなーという閃きをそのまま形にできる環境ということもあって、すごく充実してます。
以下、仕事中に閃いてつくってるやつ。
- github/kyokomi/goma: domaぽいDatabaseアクセスフレームワーク
- 生クエリとORMの中間がほしい...的な
- github/kyokomi/renkin: GoDocベースのAPIドキュメント生成ツール
ここまでガッツリGoをプロダクトで採用している会社は、国内では今のところGunosyだけなのかな?と思います。
800万DL!Gunosyと共に成長したいGoエンジニア募集! by Gunosy Wantedly
あと、今後もGunosy.goの運用やらせてもらうことになったので、Goの布教活動とGoの実例収集を行っていければと思いますので宜しくお願いします。
個人活動
Goのライブラリ開発とかはもちろんやっていきますが、 ゲーム開発は引き続き作っていきたいと思いますので、Cocos2d-xのバックエンドにGoで書いてほしいとか、デザインとグラフィックやるからCocos2d-xやってくれとかあればお気軽にお声がけしていただければと!!!
とりあえず、年内に前作ってたローグライクゲームのライト版を作って出したい・・・(今度こそGWに)
一緒に企画からやる人募集中。。。
React.jsのチュートリアルをGoで動かしてみた
React.js入門しました。とりあえず動かしてみたレベル。
(とりあえず触る&ソース読んでよくわからない点とかメモってから、概要とか読む派なので。。。)
チュートリアルのexampleで用意されている言語はRuby, Node.js, Pythonしかありませんが、あえてGoでやります。
Goで起動する
チュートリアルのソースコードをgit clone
で取得します。
$ git clone https://github.com/reactjs/react-tutorial
プロジェクト直下にmain.goを作成します。(goji使ってます)
$ go get github.com/zenazn/goji
React.jsのチュートリアルをGoで書いてみたhttps://github.com/reac ...
あとは起動するだけ。
$ go run main.go
なんかチャットっぽいやつのようだ。
色々触って動きを追って見る
サーバーのログを見るとわかるけど、2秒毎にGET:/comments.json
が呼ばれている。
それっぽいコードがある。
// public/scripts/example.js(126行目) <CommentBox url="comments.json" pollInterval={2000} />,
このCommentBoxのComponentの実装は以下のようにajaxでGETしてsetState
でCommentBoxのrenderを行っている。
// public/scripts/example.js(29行目) var CommentBox = React.createClass({ // 2秒毎に呼ばれるやつ loadCommentsFromServer: function() { $.ajax({ url: this.props.url, dataType: 'json', success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, // CommentBox子要素のCommentFormのPostボタンを押した時に呼ばれる handleCommentSubmit: function(comment) { var comments = this.state.data; comments.push(comment); this.setState({data: comments}, function() { // `setState` accepts a callback. To avoid (improbable) race condition, // `we'll send the ajax request right after we optimistically set the new // `state. $.ajax({ url: this.props.url, dataType: 'json', type: 'POST', data: comment, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }); }, // 初期呼び出し getInitialState: function() { return {data: []}; }, // TODO: これが2秒毎にajax呼ぶやつのトリガーっぽい? componentDidMount: function() { this.loadCommentsFromServer(); setInterval(this.loadCommentsFromServer, this.props.pollInterval); }, // 表示更新(setStateで呼ばれる) render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm onCommentSubmit={this.handleCommentSubmit} /> </div> ); } });
CommentBoxは子要素にCommentListとCommentFormを持っていて、setStatusで渡されたdataでrenderを呼び出している。
また、CommentFormのPostボタンを押したは、親要素からpropsでもらったonCoomentSubmitのfunctionを呼び出して、ajaxでPOST:/comments.json
を呼び出している。
呼び出し後のrenderの流れは2秒毎に呼んでいる方と同じ。
おわり
とりあえず動かしてみて、その後に概要を読んでReact.jsの良さがわかってきた気がする。
英語が苦手な方は、こちらを読むといいと思います!!!とてもわかりやすいです!
GoogleComputeEngineのVMインスタンスにerrbitを構築
はじめに
errbitを業務で使っているので、自分用のSandboxがほしくて作ろうかなと思ってやってみたら、 思った以上に苦戦したので備忘録がてら残します。
※herokuでの導入例はよくあるのですが、ローカルとかAWSとかでの記事があまり見当たらず...
苦戦したのは、たぶん自分がRails初心者なのが理由かと思いますが一応
環境について
※ちなみにf1-micro(vCPU 1 個、メモリ 0.6 GB)はメモリ不足でbundle install
でコケますのでご注意ください。
rubyとかその他必要な物をinstall
色々更新とinstall
$ sudo apt-get update $ sudo apt-get install -y mongodb $ sudo apt-get install -y libxml2 libxml2-dev libxslt-dev libcurl4-openssl-dev libzip-dev libssl-dev $ sudo apt-get install -y libreadline6 libreadline6-dev $ sudo apt-get install -y g++ $ sudo apt-get install -y make $ sudo apt-get install -y git
rubyのバージョン管理はrbenvにした。
$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile $ source .bash_profile
2.1.0だとlibreadlineのバージョンが上がって型の定義が変更な不具合で詰んだので、2.1.2にしました。
$ rbenv install -v 2.1.2
install ながい。。。
$ rbenv rehash $ rbenv global 2.1.2
bundlerとかinstall
$ gem install bundler $ gem install therubyracer
errbit起動
ちなみにinstallしたerrbitのリビジョンはこちら 。更新が活発なのでご注意ください↓
errbit/errbit at d3d7ad54f7b136a804d5cb7c9a118ae35b7e5c7a · GitHub
errbitをgit cloneして手順通り起動。
$ git clone https://github.com/errbit/errbit $ cd errbit $ bundle install $ rake errbit:bootstrap $ sudo script/rails server -p 80
supervisorで常駐させる
無事起動したけど、常駐してほしいので、雑にsupervisorを導入。
$ sudo apt-get install supervisor $ sudo vim /etc/supervisor/conf.d/supervisord.conf
supervisord.conf
[program:errbit] command=sudo /home/kyokomi/.rbenv/shims/ruby /home/kyokomi/errbit/script/rails server -p 80 user=kyokomi autorestart=true stdout_logfile=/var/log/supervisor/jobs/errbit.log stdout_logfile_maxbytes=1MB stdout_logfile_backups=5 stdout_capture_maxbytes=1MB redirect_stderr=true
supervisor起動
sudo service supervisor start
おわり
Goでエラー投げまくってる。
参考
Goのテンプレート言語egoを使ってみた
golangのtext/template最近ようやく慣れてきたけど、
やっぱり{{}}
が増えてくると辛いので、他のパッケージに手をだしてみました。
egoが触った中で一番しっくりきたのと、一通り色々なことができそうな気配を感じたので気に入りました。
インストール
go get
だけでOKです。
$ go get github.com/benbjohnson/ego
egoを呼び出すソースコード
ディレクトリ構成
├── main.go └── templates └── sample.ego
templates/sample.ego
は、ego用のtemplateファイル。拡張子.ego
じゃないとダメです。
egoを実行する
$ ego -package main templates
実行するとego.go
が作成される。*1
├── ego.go ├── main.go └── templates └── sample.ego
go runで実行する
$ go run main.go ego.go ## Titleを表示 test ## Titleをローカル変数titleに代入して表示 title = test ## FooListをfor文で回して表示 abc ローカル変数のスコープ = test def ローカル変数のスコープ = test ghi ローカル変数のスコープ = test foo ローカル変数のスコープ = test ## FooMapをfor文で回してkeyとvalueを表示 キー: a 値: 111 ローカル変数のスコープ = test キー: b 値: 222 ローカル変数のスコープ = test キー: c 値: 333 ローカル変数のスコープ = test
*1: go:generateでも実行できます。参考
go-bindataをgo:generateで実行する
この手の生成ツールはgo:generateで、まとめて実行するようにすればMakefileとか書かなくていいので幸せになれそうです。
go-bindataの使い方とかは以下などを参考にしていただければと。
アセット的なアレを実行バイナリ内に入れる話。 — さにあらず
go-bindataしたファイルを参照したいmainのソースコード
ディレクトリ構造はこんな感じです。
├── data │ └── emoji.json └── main.go
//go:generate go-bindata data/
のコメントを入れる。
go-bindataをgo:generateで実行するhttp://kyokomi.hatena ...
go generateを実行する
bindata.goが生成されました。
$ go generate $ ll total 144 0 drwxr-xr-x 5 kyokomi staff 170 1 17 21:01 . 0 drwxr-xr-x 16 kyokomi staff 544 1 17 20:51 .. 136 -rw-r--r-- 1 kyokomi staff 69509 1 17 21:00 bindata.go 0 drwxr-xr-x 3 kyokomi staff 102 1 17 20:54 data 8 -rw-r--r-- 1 kyokomi staff 222 1 17 21:01 main.go
おわり
もっと色々とgo:generateで便利なやつないかな。
docomo APIのGoライブラリ(go-docomo)を作った
docomoのAPIを利用する目的で作ったGo製のライブラリです。 各API叩いてるだけなので、特別なにかやってるとかはないです。
今のところ以下のAPIに対応しています。
- 雑談対話
- 知識Q&A
- トレンド記事抽出
ライブラリの構成とかはgo-githubを参考に作りました。
docomo API
docomoAPIを利用するには、以下でDeveloper登録が必要です。 Google+とかFacebookとかのSNSアカウントでログイン対応してるので、すぐAPIを触れます。
docomo Developer support | NTTドコモ
docomoAPI
※詳しくは公式APIドキュメントを見ていただければと
利用例
大体こんな感じに使われてます。
以下の記事を見て自分もGoでやってみたいなーと思いました。
go-docomoでつくったGo製のSlackbot
いーすんさん可愛い!!!
雑なソースコードはこちら ↓
go-docomoの使い方
普通にgo get
します。
go get github.com/kyokomi/go-docomo/docomo
docomoで登録したAPIはNewClientの引数で渡すようにしているので、 環境変数なり起動引数なりで読み込んでセットしてください。
package main import ( "log" "os" "github.com/kyokomi/go-docomo/docomo" ) func main() { apiKey := os.Getenv("DOCOMO_APIKEY") c := docomo.NewClient(apiKey) message := "こんにちわ" req := docomo.DialogueRequest{ Utt: &message, } res, err := c.Dialogue.Get(req, true) if err != nil { log.Fatalln(err) } log.Printf("%+v", res) }
実行結果
2015/01/14 14:52:02 &{Context:kqRd3UD-30ov__ecH7exLA Da:0 Mode:dialog Utt:こんにちわー Yomi:こんにちわー RequestError:{PolicyException:{MessageID: Text:}}}
Memo: トレンド記事取得の関連記事取得が中々ヒットしない仕様?みたいで「ぐぬぬ」ってなりますのでご注意ください
おわり
気軽にPR等投げていただければと思います。
ただ、英語全然ダメなので、こっそりTwitterとかで日本語で話しかけていただけると助かります・・・
Go言語でのInterfaceの可視性について
ちょっとハマったのでメモがてらまとめました。
Interfaceも通常のstruct等と同じく先頭が小文字で始まる場合に別パッケージで参照できないという点についてです。
ディレクトリ構成
example ├── factory1 │ └── factory.go ├── factory2 │ └── factory.go ├── main1.go └── main2.go
外部でinterface実装可能
Factory
インターフェースのCreate()
,Register()
ともに先頭が大文字でパッケージ外から参照可能なので、別のパッケージでインターフェースを実装することが出来ます。
// example/factory1/factory.go package factory1 type Factory interface { Create() Register() }
// example/main1.go package main import "./factory1" type BarFactory struct { } func (h BarFactory) Create() { } func (h BarFactory) Register() { } var _ factory1.Factory = (*BarFactory)(nil) func main() { f1 := BarFactory{} f1.Create() f1.Register() }
外部でinterface実装不可能
Factory
インターフェースと同じパッケージ内で実装したものなら、
外部パッケージから利用可能です。
ポイント
register()
は先頭小文字で不可視になっているため、外部パッケージからはCreate()
しか呼べないregister()
は先頭小文字で不可視になっているため、外部パッケージではインターフェースの実装ができない
//example/factory2/factory.go package factory2 type Factory interface { Create() register() // 別packageから参照不可能 } type FooFactory struct { } func (h FooFactory) Create() { h.register() } func (h FooFactory) register() { } var _ Factory = (*FooFactory)(nil)
// example/main2.go package main import "./factory2" func main() { f2 := factory2.FooFactory{} f2.Create() // ERROR: 不可視なので呼び出せない // f2.register() } type BazFactory struct { } func (b BazFactory) Create() { } func (b BazFactory) register() { } // ERROR: Factory.register()が不可視なのでinterface実装できない //var _ factory2.Factory = (*BazFactory)(nil)
おわり
あまりinterfaceを使う機会がなかったので、よくわかってなくてハマりました。
(単に使い方わかってなくて使い所がわかってなかっただけかもしれませんが・・・)
触りながら自己理解したので、もし認識違い等ありましたら指摘いただけると助かります。