きょこみのーと

技術に関係ないほうのブログ

脱ソシャゲして、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書いてたり。

iOSAndroidPythonとGoとRuby書いたりインフラやったりする人がいたり(マジすげぇ。。。)

上記のようなメンバーと一緒に仕事できるのと、業務でGo書いているとこんなGoのツールあるといいなーとかライブラリあるといいなーという閃きをそのまま形にできる環境ということもあって、すごく充実してます。

以下、仕事中に閃いてつくってるやつ。

ここまでガッツリ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

スクリーンショット 2015-02-01 15.54.26.png

なんかチャットっぽいやつのようだ。

色々触って動きを追って見る

サーバーのログを見るとわかるけど、2秒毎にGET:/comments.jsonが呼ばれている。

スクリーンショット 2015-02-01 15.57.02.png

それっぽいコードがある。

// 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の良さがわかってきた気がする。

英語が苦手な方は、こちらを読むといいと思います!!!とてもわかりやすいです!

一人React.js Advent Calendar 2014 - Qiita

GoogleComputeEngineのVMインスタンスにerrbitを構築

はじめに

errbitを業務で使っているので、自分用のSandboxがほしくて作ろうかなと思ってやってみたら、 思った以上に苦戦したので備忘録がてら残します。

※herokuでの導入例はよくあるのですが、ローカルとかAWSとかでの記事があまり見当たらず...

苦戦したのは、たぶん自分がRails初心者なのが理由かと思いますが一応

環境について

  • GoogleComputeEngineのVMインスタンスn1-highcpu-2(vCPU 2 個、メモリ 1.8 GB)
  • OSはubuntu 14.04

※ちなみに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でエラー投げまくってる。

f:id:kyokomi:20150128222115p:plain

参考

Goのテンプレート言語egoを使ってみた

golangtext/template最近ようやく慣れてきたけど、 やっぱり{{}}が増えてくると辛いので、他のパッケージに手をだしてみました。

egoが触った中で一番しっくりきたのと、一通り色々なことができそうな気配を感じたので気に入りました。

benbjohnson/ego · GitHub

インストール

go getだけでOKです。

$ go get github.com/benbjohnson/ego

egoを呼び出すソースコード

ディレクトリ構成

├── main.go
└── templates
    └── sample.ego

templates/sample.egoは、ego用のtemplateファイル。拡張子.egoじゃないとダメです。

golang ego sample

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の使い方とかは以下などを参考にしていただければと。

アセット的なアレを実行バイナリ内に入れる話。 — さにあらず

jteeuwen/go-bindata · GitHub

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)を作った

docomoAPIを利用する目的で作ったGo製のライブラリです。 各API叩いてるだけなので、特別なにかやってるとかはないです。

kyokomi/go-docomo · GitHub

今のところ以下のAPIに対応しています。

  • 雑談対話
  • 知識Q&A
  • トレンド記事抽出

ライブラリの構成とかはgo-githubを参考に作りました。

docomo API

docomoAPIを利用するには、以下でDeveloper登録が必要です。 Google+とかFacebookとかのSNSアカウントでログイン対応してるので、すぐAPIを触れます。

docomo Developer support | NTTドコモ

docomoAPI

f:id:kyokomi:20150114142403p:plain

※詳しくは公式APIドキュメントを見ていただければと

利用例

大体こんな感じに使われてます。

以下の記事を見て自分もGoでやってみたいなーと思いました。

DocomoruでBOTと雑に会話する - Qiita

go-docomoでつくったGo製のSlackbot

雑談APIと知識Q&AのAPIを使ってます。

f:id:kyokomi:20150114142934p:plain

いーすんさん可愛い!!!

雑なソースコードはこちら ↓

kyokomi/nepu-bot · GitHub

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を使う機会がなかったので、よくわかってなくてハマりました。

(単に使い方わかってなくて使い所がわかってなかっただけかもしれませんが・・・)

触りながら自己理解したので、もし認識違い等ありましたら指摘いただけると助かります。