Twitterでお気に入りした画像をランダムで返すGAE/Goアプリをつくった
ランダムで返す部分が雑にキャッシュしてるのはご愛嬌・・・
https://koha-api.appspot.com/v1/api/image
画像はこちらを利用させていただきました。(経験値先生最高です!さっちん絵がほしかった・・・)
というわけでお蔵入りじゃから、ツイッター画像とかで使ってくれなのじゃ。あ、営利目的には使用禁止で頼むのじゃ。 pic.twitter.com/4QWYf45SuM
— 経験値@コハエースXP(9月頃発売) (@keikenti) 2015, 9月 30
注意!!!営利目的でのご利用はやめてくださいね!!!
お気に入りは適当にアカウント作って作りました。
GAE/Goの実装の方ですが、かなり雑ですが以下になります。
使い方はREADME.mdに書きましたが、 環境変数だけで一応どのアカウントにも対応できるようにしてます。
需要があれば、もうちょっとなんとかします!
主な使い方ですが、LGTMとかみたいな感じにAPIクライアント作ってしまえばいいかと思います。 自分はGo製のSlackbotでAPIクライアントを実装しました。
シルバーウィークにいよいよUnity入門した
はじめに
最近Goばかり書いてるのですが、今作ろうとしてるゲームをCocos2d-xで作るのは流石にもう辛いので、コレを期にUnity入門することにしました。
シルバーウィークの月〜水の3日間でサクッと1冊本読み切ってExampleを2,3個作るとこまでやりましたので、その所感とか。
準備したもの
Unity5 3D/2Dゲーム開発実践入門 作りながら覚えるスマートフォンゲーム開発
- 作者: 吉谷幹人
- 出版社/メーカー: ソシム
- 発売日: 2015/07/24
- メディア: 単行本
- この商品を含むブログ (2件) を見る
細かいミスだけど、正誤表あるので先に見ておくと良いです。 今の最新版のUnity5.2で挫折しないで最後までいけたので、すごいと思います。 自分みたいなガチ入門者向けかと。
正誤表はこちら => http://www.socym.co.jp/support/s-967#ttlWrong
- 出版社/メーカー: ロジクール
- 発売日: 2013/08/02
- メディア: Personal Computers
- この商品を含むブログ (24件) を見る
トラックパッド派なんだけど、流石に三次元の動きをトラックパッドで操作するの限界を感じて以前Unity挫折したので先に買っておいた。 買ってよかった・・・普通のマウスでも良かったかもしれないけどUnityで全然使えました。
環境
- Unityv5.2.0f3
はるか昔にUnity4になる前に触った頃に比べてサクサク動いてる気もするし、色々わかりやすくなった。 買った書籍がよかったのかもしれないけど、ストレスはほとんどなかった。
あと、マウス買ってよかった。以前にMacのタッチパッドでUnity操作しようとしたの無謀だった。 クリックしたまま引っ張るとか、回すとかかなりのテクニックがいるのでおとなしくマウスにしよう。
トラックボールだとマウス移動自体がないので場所も取らなくて楽だった。
Editorやばい
- Xamarin Studio: 日本語入力できるけど、日本語変換後の入力がスルーされることがあり結構ストレスだが、軽さや補完など平均点は維持してるのでコレに決めた
困ったこと
「変換が」を入力したつもりが「変換あ」になる
「変換」の時点でEnterをして確定してから「が」を入力すればいいのだが、「変換」の確定を「g」の入力でやる癖がもう抜けなくて辛い。(これ文章で説明してわかるのかな・・・)
他にも試したEditorたち
- MonoDevelop: まだ日本語入力できなくて消耗してるので没
- ReSharper: JetBrains製品好きとしては・・・と思ったがまさかのMac版なくて/(^o^)\
- VisualStudioCode: 一番ナウい感じなんだけど、Unity5.2での補完のきかせ方が分からず挫折
- 痛MonoDevelop: 惜しい所まできていたが、Unityちゃんの描画のためか重くなり没
色々教わったこと・学んだこと
- .gitignore設定しよう => ここにある
- 「Asset Serialization」を「Force Text」にする ※こちら参考にテラシュールブログ - Unity開発者が複数人で開発を進める上で覚えておくと幸せになる9つの事
- git initだけじゃなくてちゃんとこまめにCommitしよう(1回死んだ)
こんな感じでやってた
- まず章を1つざーっと目を通す
- 何作るかと何するかをざっくり把握してから、実際にExample作成の手を動かす
- とにかく作りきる
- 気が向いたら、ちょこっと改造する
こんな感じにキャラをUnityちゃんにしてみたり。
本読みながら、ポチポチ入力してくのもいいけど、結局図の方ばっかりみちゃって説明読み飛ばしちゃう気がする・・・(図だけで十分作れてしまうのもすごい)
なので、ざっと1回読んでから戻って作って行く感じでやっていくと、頭の中で整理もできて丁度良かったです。
C#なんとなく書ける
なんとなく書けるの良くない。もうちょいUnity自体の理解が深まったら、改めてC#も入門する。
(学生の時になんとなくC#書いてたから、軽く8年ぶりくらいか・・・)
所感
ようやくUnity入門してスタートに立てた感じ。Asset周りがなんか有料ばっかでゾッとしてるんだけど、まあ基本的な機能は揃ってるので、しばらくは手抜きしない方向でいこう・・・(素材周り以外は)
UnityちゃんかわいいよUnityちゃんかわいいよ
GitHubのREADME.mdに貼ったBadgeが更新されない時
なんかRefreshするタイミングとかミスすると更新されないときがあるので、手動でなんとかする方法。
こんなとき↓
↑のBadgeの画像URLをコピペして、こうする
$ curl -X PURGE https://camo.githubusercontent.com/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx {"status": "ok", "id": "xxx-xxxxxxxxxx-xx"}
そして、ブラウザを更新すると反映される。
参考
Aggressive image caching breaks image badges · Issue #224 · github/markup · GitHub
Goでlotteryという抽選ライブラリを作った
単なるmath/rand
のラッパーですが。
もしかしたら他にも似たようなやつあるかもしれませんが、見つからなかったので作りました。
指定した確率
20%の確率で〜みたいな処理をしたいときです。
lot := lottery.New(rand.New(rand.NewSource(time.Now().UnixNano()))) if lot.Lot(20) { // 20%の時の処理 }
抽選リストから1件抽選
以下のような複数の抽選対象から1件だけ抽選するときのinterfaceもあります。
- A: 10%
- B: 20%
- C: 30%
- D: 40%
Prob() int
というインターフェースを実装すればOKです。
type DropItem struct { ItemName string DropProb int } func (d DropItem) Prob() int { return d.DropProb } var _ lottery.Interface = (*DropItem)(nil)
抽選はこんな感じにやる。
lot := lottery.New(rand.New(rand.NewSource(time.Now().UnixNano()))) // 抽選対象リスト dropItems := []lottery.Interface{ DropItem{ItemName: "エリクサ", DropProb: 10}, // 10% DropItem{ItemName: "エーテル", DropProb: 20}, // 20% DropItem{ItemName: "ポーション", DropProb: 30}, // 30% DropItem{ItemName: "ハズレ", DropProb: 40}, // 40% } // 抽選 lotIdx := lot.Lots(dropItems...) if lotIdx == -1 { // errorです(抽選リストの指定ミスかと) } // 抽選結果のItem dropItem := dropItems[lotIdx].(DropItem)
以下のテストコードも参考にしていただければと。
lottery/lottery_test.go at 2c0264f14a47bf1be830ae12d2c84a90ce9f1ffa · kyokomi/lottery · GitHub
200万回実行した結果は以下になります。
2015/07/26 15:51 追記
@k_yokomi こんな感じにも使えていいですね!https://t.co/mlA7qfHv5z #golang
— taku ʕ ◔ϖ◔ʔ ==Go (@tenntenn) 2015, 7月 26
@tenntenn さんが「袋の中に球が3種類入っていてそれを順次取り出して行く」ような使い方を見つけてくれたので、紹介させていただきます。
ありがとうございます!
GoConでGoで作った拡張しやすいSlack botについてLTしてきた
拡張しやすいはず・・・
最初はkyokomi/gomaの話にしようかなと思ったけど、LT駆動開発キメたろうと思って、slack bot作ることにした。
LTであまり時間無く、ざくっと概要とデモ見せる感じで終わったので、exampleとか詳細を書こうと思います。
実際に実行するbotのサンプル
tokenの取得
slack botのtokenは以下で取得してください。
exampleを実行する
<token>
は、一つ前の節で取得したもの。環境変数SLACK_BOT_TOKEN
でも可。
$ go get github.com/kyokomi/slackbot $ cd $GOPATH/src/github.com/kyokomi/slackbot/example $ go run main.go -token <token>
これで実行終わり。起動時のログはこんな感じ。
Slackで発言してみる。(botが居る部屋で)
echoプラグインが動いていることがわかる。
pluginの仕組み
_ import
するだけでpluginを追加できているのは、この辺をみればわかる。
init()でplugins.AddPluginを読んでいる箇所
slackbot/echo.go at v1.1 · kyokomi/slackbot · GitHub
func init() { plugins.AddPlugin(pluginKey("naruhodoMessage"), NaruhodoMessage{}) }
SlackのMessage受信時に呼び出される処理している箇所
pluginsに突っ込まれたものを順番に呼び出している。
slackbot/plugin.go at v1.1 · kyokomi/slackbot · GitHub
func ExecPlugins(ctx context.Context, message string) { for _, p := range plugins { ok, m := p.CheckMessage(ctx, message) if !ok { continue } next := p.DoAction(ctx, m) if !next { break } } }
実は、とても原始的な実装。
割とウケた「なるほどですぞ」プラグインのソースは以下だけ。(ウケてよかった・・・)
package naruhodo import ( "math/rand" "strings" "time" "github.com/kyokomi/slackbot/plugins" "golang.org/x/net/context" ) type pluginKey string var naruhodoList = []string{ "なるほどなるほどですぞ!", "なるほど!", "なるほど?", "なーるほど!", "それはなるほどですね", "なるほど!!", "なるほど!!!", } var rd = rand.New(rand.NewSource(time.Now().UnixNano())) func init() { plugins.AddPlugin(pluginKey("naruhodoMessage"), NaruhodoMessage{}) } type NaruhodoMessage struct { } func (r NaruhodoMessage) CheckMessage(ctx context.Context, message string) (bool, string) { return strings.Index(message, "なるほど") != -1, message } func (r NaruhodoMessage) DoAction(ctx context.Context, message string) bool { idx := int(rd.Int() % len(naruhodoList)) plugins.SendMessage(ctx, naruhodoList[idx]) return false // next ng } var _ plugins.BotMessagePlugin = (*NaruhodoMessage)(nil)
ほとんどgenerateしたコードのまま。
CheckMessage
でなるほどという文字がmessageに含まれていたらtrue
を返すCheckMessage
でtrue
を返した時にDoAction
が実行されるDoAction
でcontext
に突っ込んでいたSendMessage
を使ったSlackへ返信する
たったこれだけ。簡単なのでぜひ使ってみてください! そしてプラグイン作ったら報告してくれると嬉しいです!! (特定の環境に依存してないプラグインじゃなければ、PullRequestでもOK)
GWにGo言語で作ったMeetAppというサービスの開発記録
GWに2〜3日くらい本気だして、MeetAppというサービスをリリースしました。
フロントエンド&企画をやっていただいた@tejitakさんのブログに大体の概要が書いてありますので、こちらを併せてご覧いただければと。
GWハッカソンでMeetAppという趣味アプリ開発者のためのサービス作りました - TEJI TECH BLOG
自分の方は、Goの構成や使っているライブラリや開発中のTipsなどをまとめようかと思います。
Goの構成
使ったライブラリ
- guregu/kami : Webフレームワーク(先輩)
- unrolled/render : jsonやhtmlのレンダリング
- kyokomi/goroku : 今回作った(heroku用)
- gotsunami/go-cloudinary : CloudinaryのAPI
- gopkg.in/airbrake/gobrake.v1 : airbrakeのAPI
- gopkg.in/mgo.v2 : mongoDB
- gopkg.in/redis.v2 : Redis
- boj/redistore : redisでsession管理
- huandu/facebook : facebookのGraph API
- ChimeraCoder/anaconda : TwitterのAPI
- microcosm-cc/bluemonday : Markdown変換1(1と2セットで使う)
- russross/blackfriday : Markdown変換2(1と2セットで使う)
今回の開発過程で作ったライブラリ
kyokomi/goroku
herokuの以下アドオンをx/net/contextベースで利用できるライブラリ
- mongolab : 永続データ
- Redis To Go : ログインセッションとか
- Cloudinary : 画像アップロードと画像のリサイズ
- airbrake : エラー通知
作ったといっても、他のライブラリをラップしてherokuの環境変数を使うようにしているだけですが。
開発時のTipsとか
心がけたこと
- 汎用性 vs 開発速度(2対8くらいの割合)
- 読みやすいコード vs 捨てやすい/改修しやすいコード(4対6くらいの割合)
- パフォーマンス考慮できるならやるけど、少しでも複雑になるなら
// TODO:
残してサクッとスルーする - おれおれフレームワークとか作らない
- テスト書いたほうが開発が早くなるor画面上で動作確認が難しいテストのみ書くようにした
良かった点
- mongolab便利だった(管理画面でデータいじったりするの楽)
- Cloudinary便利だった(画像リサイズとかURLベースでやってくれる)
- CircleCIで自動herokuデプロイを組んでから開発速度が加速した(最初からやってもよさそう)
- 開発後半で、リファクタしたりよく使うコードとかを別パッケージにしたりする余裕があった
- 開発はほぼ2人だったのでコミュニケーションロスもほとんど無く、スピード感良い感じでスムーズに開発できた
おわり
引き続き改善していくつもりですが、x/net/contextベースで開発したため結構使いまわせるようになっているので次はもっと早く開発できそうですので新しく別サービス作るのもアリかなと思ってます。
一緒に作るのも面白かったので、またやりたい。
CircleCI上でMySQLとPostgreSQLを扱ったtestを行う
先日Gunosy.go#12でLTしたkyokomi/gomaですが、 CircleCI上でDBを利用してgo generateとtestの実行を行っています。
たぶん公式ドキュメント見ればわかると思いますが、 サクッとやりたい人向けにCircleCI上でMySQLとPostgreSQLを利用する方法をご紹介しようかと思います。
CircleCIでCREATE DATABASE等のsqlを実行
この辺みたら大体わかると思いますが、普通にsqlファイルをmysqlとpsqlコマンドで実行してます。
https://github.com/kyokomi/goma/blob/master/circle.yml#L7
$HOME/$CIRCLE_PROJECT_REPONAME
は、CircleCIでgit checkoutされるリポジトリのPATH- 今回は例として、
sample_db
という名前のDatabaseを作成する data.sql
には、CREATE TABLE文やINSERT文が入っているイメージ
MySQL
/* ddl/mysql/setup.sql */ CREATE DATABASE sample_db;
circle.yaml
のdatabase:
に以下を追加します。
# circle.yaml database: post: - mysql -u root < $HOME/$CIRCLE_PROJECT_REPONAME/ddl/mysql/setup.sql - mysql sample_db -u root < $HOME/$CIRCLE_PROJECT_REPONAME/ddl/mysql/data.sql
PostgreSQL
念のためSUPERUSERとLOGINのROLEを設定してますが不要かもです。
/* ddl/postgres/setup.sql */ CREATE DATABASE sample_db; CREATE ROLE postgres SUPERUSER; ALTER ROLE postgres WITH LOGIN;
mysqlと書き方が違うので注意。
# circle.yaml database: post: - psql -U postgres -f $HOME/$CIRCLE_PROJECT_REPONAME/ddl/postgres/setup.sql - psql -d sample_db -U postgres -f $HOME/$CIRCLE_PROJECT_REPONAME/ddl/postgres/data.sql
CircleCI実行の順番
database
フェーズは、dependencies
フェーズの後になりますので、database
のpost
もしくは、test
フェーズでDBを使ったtest等を実行しましょう。
kyokomi/gomaの実行時のログですがこんな感じになります。
おわり
CircleCI困ったらsshして入れるので色々試せるのが便利ですね。(どっかでもいいましたが)
※go generateして生成したファイルもgo testしてるのがポイント。