廃墟

本ブログは更新を終了しました。 技術的な記事のみ、有用性を鑑みて残しておきます。

cocos2d-x メモ 2016/06/02

ほぼ個人的なcocos2d-xのお勉強メモだけど、誰かの役にも立ちそうなのでブログに載せとく。

BlendFunc

BlendFuncというのを使うと、Photoshopとかにある乗算レイヤとか加算レイヤとかスクリーンレイヤとかと似たような事が出来るらしい。 そもそもがOpenGL ESのAlphaBlending機能なので、それに関する情報を漁れば色々出て来る。

# 加算
BlendFunc blend;
blend.src = GL_SRC_ALPHA;
blend.dst = GL_ONE;

# 乗算
BlendFunc blend;
blend.src = GL_DST_COLOR;
blend.dst = GL_ZERO;

# 乗算別バージョン (結果は一緒になる)
BlendFunc blend;
blend.src = GL_ZERO;
blend.dst = GL_SRC_COLOR;

ようは、srcが対象のNodeで、dstが親(+兄ノード? 事前にレンダリングされてるものだと思うんだよな)のことで、 blendfuncでの指定をそれぞれの色に乗じて和を取るってことみたい。

疑似的にはたぶん、こういうこと。

render.pixel = child.pixel * blend.src + parent.pixel * blend.dst;

RenderTexture

あらゆるNodeをスクリーンショット的に一度レンダリングして使い回せるようにするやつ。 メソッド一覧を見てたらどうやらファイルへの書き出しも出来るっぽいので、スクリーンショットSNSに投稿する機能とかにも使われてるやつだと思う。

RenderTexture *texture = RenderTexture::create(visibleSize.width, visibleSize.height);
texture1->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2));
texture->beginWithClear(0, 0, 0, 1);
sprite->visit();
texture->end();

visitが重要。 これでspriteのレンダリングを実行してくれる。 beginWithClearはvisit直前のキャンバスクリアみたいなやつだろう。

このtextureを使ってSpriteを作る事も出来る。

Sprite *sprite2 = Sprite::createWithTexture(texture->getSprite()->getTexture());
sprite2->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2));
sprite2->setFlippedY(true);

※ 手元のコード見たら setFlippedY つけてたけど、必要なのかはよく分かってないです。。

特にDrawNodeとかはそのままだと扱いにくいことがある(どうもBlendFuncと相性が悪い)ので、一度RenderTextureにしちゃってからBlendすると結構期待通りに動く。 恐らくGPUだけで完結するはずのものが一回CPUに回ってくる処理になっちゃうので、updateの中でぐりぐり動くようなのを作りたい場合はパフォーマンスに気をつけないとFPSが保てないと思う。 initの中で最初だけ作ってあとは使い回すとかなら問題少なそうだし積極的に使って行きたいな。

GLSLとsetGLProgram

まだ詳細が分かってないんだけど、C言語を拡張したようなGLSLっていう言語でシェーダプログラミングが出来るらしい。 これはWebGLを含むかなり色々な環境で動く言語のようで、汎用性が高い技術みたい。 アニメーションもヌルヌルかけるので、cocos2d-xのレイヤで書くべき部分とシェーダで書くべき部分の目利きが出来るとよさそう。ある程度は推測がつくけど、やっぱ詳細が分からないので意外な盲点がありそうな感じがする。

Xcode6.3とXcode6.2を併用してる環境でApp StoreへのSubmitが途中で止まる問題の解決策

元ネタはこちら。

stackoverflow.com

普通にXcodeからアプリをSubmitするときって、OrganizerのSubmitボタンからやると思うんですが、別な方法を使うことでこのバグ?らしき挙動をバイパスできるってことみたいです。たぶん。

  • OrganizerでExportを押下
  • "Save for iOS AppStore" からRipaファイルを生成、適当なとこに保存
  • ドックのXcodeを右クリック → Developer toolsApplication Loader
  • このApplication Loaderを使ってsubmitすると問題ない

誰かの参考になれば幸い。

Application Loaderってなんだろ。

herokuにRails4.2.0 with mongoid & angularjsなプロジェクトをデプロイ

地雷だらけで死にそうだったのでメモ

config/production.rb のjs_compressor書き換え

Angular.jsが動かなくなるのを防ぐためにmangleをfalseにしたUglifierを使う

config.assets.js_compressor = Uglifier.new(:mangle => false)

mongoid.yml の設定

以下のようにする

production:
  sessions:
    default:
      uri: <%= ENV['MONGOLAB_URI'] %>

MongoHQを使ってる場合は環境変数名が違うだけ。 production直下にuriを書けるって情報があるけど、古いようで今のバージョンでは動かない。

雑感

そこそこ使われてそうな組み合わせの割に情報あんまりないし、最近ネット上に技術メモ流す人減ってないか?Twitterに書いて満足するのやめてこの程度にはまとめて書こうな!?

参考: バージョン情報

ruby 2.1.3

Gemfile.lock

GEM
  remote: https://rubygems.org/
  specs:
    actionmailer (4.2.0)
      actionpack (= 4.2.0)
      actionview (= 4.2.0)
      activejob (= 4.2.0)
      mail (~> 2.5, >= 2.5.4)
      rails-dom-testing (~> 1.0, >= 1.0.5)
    actionpack (4.2.0)
      actionview (= 4.2.0)
      activesupport (= 4.2.0)
      rack (~> 1.6.0)
      rack-test (~> 0.6.2)
      rails-dom-testing (~> 1.0, >= 1.0.5)
      rails-html-sanitizer (~> 1.0, >= 1.0.1)
    actionview (4.2.0)
      activesupport (= 4.2.0)
      builder (~> 3.1)
      erubis (~> 2.7.0)
      rails-dom-testing (~> 1.0, >= 1.0.5)
      rails-html-sanitizer (~> 1.0, >= 1.0.1)
    activejob (4.2.0)
      activesupport (= 4.2.0)
      globalid (>= 0.3.0)
    activemodel (4.2.0)
      activesupport (= 4.2.0)
      builder (~> 3.1)
    activerecord (4.2.0)
      activemodel (= 4.2.0)
      activesupport (= 4.2.0)
      arel (~> 6.0)
    activesupport (4.2.0)
      i18n (~> 0.7)
      json (~> 1.7, >= 1.7.7)
      minitest (~> 5.1)
      thread_safe (~> 0.3, >= 0.3.4)
      tzinfo (~> 1.1)
    angularjs-rails (1.3.10)
    arel (6.0.0)
    autoprefixer-rails (5.1.7)
      execjs
      json
    binding_of_caller (0.7.2)
      debug_inspector (>= 0.0.1)
    bootstrap-sass (3.3.3)
      autoprefixer-rails (>= 5.0.0.1)
      sass (>= 3.2.19)
    bson (2.3.0)
    builder (3.2.2)
    byebug (3.5.1)
      columnize (~> 0.8)
      debugger-linecache (~> 1.2)
      slop (~> 3.6)
    coffee-rails (4.1.0)
      coffee-script (>= 2.2.0)
      railties (>= 4.0.0, < 5.0)
    coffee-script (2.3.0)
      coffee-script-source
      execjs
    coffee-script-source (1.9.1)
    columnize (0.9.0)
    connection_pool (2.1.1)
    debug_inspector (0.0.2)
    debugger-linecache (1.2.0)
    erubis (2.7.0)
    execjs (2.3.0)
    globalid (0.3.3)
      activesupport (>= 4.1.0)
    hike (1.2.3)
    i18n (0.7.0)
    jbuilder (2.2.8)
      activesupport (>= 3.0.0, < 5)
      multi_json (~> 1.2)
    jquery-rails (4.0.3)
      rails-dom-testing (~> 1.0)
      railties (>= 4.2.0)
      thor (>= 0.14, < 2.0)
    json (1.8.2)
    loofah (2.0.1)
      nokogiri (>= 1.5.9)
    mail (2.6.3)
      mime-types (>= 1.16, < 3)
    mime-types (2.4.3)
    mini_portile (0.6.2)
    minitest (5.5.1)
    mongoid (4.0.2)
      activemodel (~> 4.0)
      moped (~> 2.0.0)
      origin (~> 2.1)
      tzinfo (>= 0.3.37)
    moped (2.0.4)
      bson (~> 2.2)
      connection_pool (~> 2.0)
      optionable (~> 0.2.0)
    multi_json (1.10.1)
    nokogiri (1.6.6.2)
      mini_portile (~> 0.6.0)
    optionable (0.2.0)
    origin (2.1.1)
    puma (2.11.1)
      rack (>= 1.1, < 2.0)
    rack (1.6.0)
    rack-test (0.6.3)
      rack (>= 1.0)
    rails (4.2.0)
      actionmailer (= 4.2.0)
      actionpack (= 4.2.0)
      actionview (= 4.2.0)
      activejob (= 4.2.0)
      activemodel (= 4.2.0)
      activerecord (= 4.2.0)
      activesupport (= 4.2.0)
      bundler (>= 1.3.0, < 2.0)
      railties (= 4.2.0)
      sprockets-rails
    rails-deprecated_sanitizer (1.0.3)
      activesupport (>= 4.2.0.alpha)
    rails-dom-testing (1.0.5)
      activesupport (>= 4.2.0.beta, < 5.0)
      nokogiri (~> 1.6.0)
      rails-deprecated_sanitizer (>= 1.0.1)
    rails-html-sanitizer (1.0.1)
      loofah (~> 2.0)
    railties (4.2.0)
      actionpack (= 4.2.0)
      activesupport (= 4.2.0)
      rake (>= 0.8.7)
      thor (>= 0.18.1, < 2.0)
    rake (10.4.2)
    rdoc (4.2.0)
      json (~> 1.4)
    sass (3.4.12)
    sass-rails (5.0.1)
      railties (>= 4.0.0, < 5.0)
      sass (~> 3.1)
      sprockets (>= 2.8, < 4.0)
      sprockets-rails (>= 2.0, < 4.0)
      tilt (~> 1.1)
    sdoc (0.4.1)
      json (~> 1.7, >= 1.7.7)
      rdoc (~> 4.0)
    slim (3.0.2)
      temple (~> 0.7.3)
      tilt (>= 1.3.3, < 2.1)
    slim-rails (3.0.1)
      actionmailer (>= 3.1, < 5.0)
      actionpack (>= 3.1, < 5.0)
      activesupport (>= 3.1, < 5.0)
      railties (>= 3.1, < 5.0)
      slim (~> 3.0)
    slop (3.6.0)
    spring (1.3.2)
    sprockets (2.12.3)
      hike (~> 1.2)
      multi_json (~> 1.0)
      rack (~> 1.0)
      tilt (~> 1.1, != 1.3.0)
    sprockets-rails (2.2.4)
      actionpack (>= 3.0)
      activesupport (>= 3.0)
      sprockets (>= 2.8, < 4.0)
    temple (0.7.5)
    thor (0.19.1)
    thread_safe (0.3.4)
    tilt (1.4.1)
    tzinfo (1.2.2)
      thread_safe (~> 0.1)
    uglifier (2.7.0)
      execjs (>= 0.3.0)
      json (>= 1.8.0)
    web-console (2.0.0)
      activemodel (~> 4.0)
      binding_of_caller (>= 0.7.2)
      railties (~> 4.0)
      sprockets-rails (>= 2.0, < 4.0)

PLATFORMS
  ruby

DEPENDENCIES
  angularjs-rails
  bootstrap-sass
  byebug
  coffee-rails (~> 4.1.0)
  jbuilder (~> 2.0)
  jquery-rails
  mongoid
  puma
  rails (= 4.2.0)
  sass-rails (~> 5.0)
  sdoc (~> 0.4.0)
  slim-rails
  spring
  uglifier (>= 1.3.0)
  web-console (~> 2.0)

Angularが悪いんじゃなくて使い方が間違ってるんだという話

最近いろんな案件や記事でAngular.jsを耳にしますが、結構「あれ使いにくいよね」などという話もちらほら。 実際ぼくが使っていてもなんだか使いにくく感じることがままあります。

多少触ってみたり考えてみたりして、僕なりの結論めいたものが見えてきたので記事にしてみようとおもいます。

サーバーサイドレンダリングとクライアントサイドレンダリング

perl, PHP全盛期

古来(?)、perlPHPの時代、多くのWebページは手打ちのHTMLで出来ていました。 この中で、フォームなどの機能をちょっとだけ追加したい、などの要請から、HTMLに直接ちょっとだけコードを埋め込めるPHPが一斉を風靡しました。

Rails全盛期

PHPによるWebアプリケーションが盛んになってくると、そのプログラムに重複する部分が多いことや、設計・実装をパターン化することで効率化が図れることがわかってきて、Ruby on RailsなどをはじめとするMVCフレームワークが登場しました。

大事なのは、ここまでずっと「サーバー側でHTMLを生成して、動的な要素はその中に埋め込まれていた」ということです。

Twitterの公開APIスマートフォン向けアプリの拡大、プラットフォームの多様化

TwitterAPIを公開し、サードパーティが自由に対応アプリを開発できることが、多様なアプリケーションを生むようになりました。 これとほぼ同時期にスマートフォンが普及し、そういった複数プラットフォームへの対応が要請されるようになりました。

その中では、すべてのWebでやろうという流れも強く、未だにその流れもありますが、レスポンスの悪さなどから好かれない傾向にあるようです。

補足

  • そもそもゲームとかだとRPCが当たり前のようにやられてたので、そこから輸入した考えではある
  • スマホの台頭以前からデスクトップアプリでは必要なことでしたが、やはりスマホ以後で大きくこの状況が動いたというのはあると思います。

SPAという提案 (Single Page Application)

スマートフォンアプリが発達してきたことで、Webサービスというものの捉え方は変わり、(大抵はJSON+HTTPの)APIこそがWebサービスである、という考え方が出てきました。 また、Webページより先にアプリ側を作ることも増えてきたので、じゃあどうせなら、アプリ側でシッカリ作ったAPIをWebでも使えたら、セキュリティの問題もHTMLよりは考えやすくなるし、良いことづくめじゃないか。 じゃあ、もうページの遷移すらやめてしまって、全ページをJSでレンダリングするという考え方で作ってもいいんじゃないか。 HTML/CSS/JSはクライアントサイドのもので、サーバーとはAPIで通信する。HTML/CSS/JSは静的なサーバーから配信すれば十分高速だろうし、API通信で重い部分はきちんとUIで解消していけばいいじゃん、行ける行ける!

…と、SPAが生まれるまでは、こんな流れなんじゃないでしょうか。

結論「AngularのSPA的アプローチと静的HTML生成アプローチの混在が混乱を招く」

さて、そういわけで結論にすっとばします。

Angularなどを使ったSPA的なアプローチは、バックエンドが全てJSONAPIで構成されていることを前提にしている。 だから、APIベースで考えずにviewレイヤでHTMLをレンダリングする過去のアプローチと混ぜてはいけない。 SPAで重要なのは、API側とビュー(クライアント)側が疎結合になり、それぞれ独立して開発を進められるようにすること。

わかってる人には当たり前のことなんだと思うんですけど、今のところの自分の解釈をざっと書いてみました。 この辺り、まだまだ流動性の高い部分なのでこれからも変わっていくと思います。コメントもお待ちしておりますので、いろいろ考えを深められたら、と思います。

RailsやMiddleman で自動的に目次を作るにはどうすればいいのか

せっかくなのでブログでも共有しておく。

お世話になってる先輩が泣いているのは忍びなかったので適当にサンプルコードをつくった。

考え

リポジトリにも書いたんだけど、以下の様な感じで考えて作った。何かの参考になるかもしれないので公開しておく。

目次の責任範囲はどこにある?

  • テンプレートエンジン、ジェネレータ
    • そういう考え方もある
  • h2の代わりになるタグをヘルパで定義して使う
    • Dirty! Dirty! Dirty!
    • 再利用性低すぎ!
  • レイアウトファイル
    • あ、行けそう

ということでレイアウトファイルが目次を作るのはそれなりにアリだと思います。

拡張の仕方

  • レイアウトファイルの中の処理をゴリゴリ書く
  • レイアウトファイルの中の処理をHelperに切り出す

例:ヘッダへのリンクが貼りたい

  • ヘッダにname要素やid要素をつける (どうせセマンティック的には自分でつけるべき)
  • パースした方でゴリ押し

ISUCON4 予選に出てきた

去年に引き続いて今年もISUCON4の予選に出ました。

去年は学生だったので @cnosuke , @rkmathi と一緒に出てたのですが、 今年は学生じゃないので @syu_cream , @suma90h と一緒に出ました。チーム名は「SSS」 (僕の本名、彼らのアカウント、の頭文字がすべてSなので。) 僕がタイミング悪く沖縄に出張していて、合流出来ずリモート参戦でご迷惑おかけしちゃいました。

前回はプログラムの方にいろいろとバグがあったのですが、今回はコード自体は普通に動くようにできていたという印象です。 寧ろ、改変したSQLにバグがあったりして3時間ぐらいドブに捨ててしまったのが痛かったです。 8時間って短いですねぇ、やっぱり。

mysqlのCPU負荷が異常に高かったのでインデックスを貼ってみた所で劇的に解決しました。 コードの改変より先にそっちをやれば良かったですね。

16:50時点でのスコアが4426しかなくて、こりゃあお通夜だなーと思っていたら、後半いろいろ頑張ったら結果としては25348ぐらいまで向上しました。 それほどインフラ特化じゃないプログラマーのチームとしては、悪くないんじゃないでしょうか。

主にやったこと

  • nginx チューニング
    • syu_cream がやってくれた
    • 静的ファイルはnginxで返す
    • worker_processは1で同時接続数は1024ぐらいにしてた
    • gz圧縮の話もあったけど、ベンチマークがローカルで動いていることから逆効果かなと思って止めた
  • mysql のパラメータチューニング
  • mysql へのインデックス追加
    • わりと順当に login_log の ip と user_id それぞれにインデックスを追加しただけ
  • unicorn のプロセス数と mysql の max_connections のチューニング
  • puma への変更
    • 最終的にスレッド5つ、プロセス4つに落ち着いた
  • TCP(OS)のパラメータチューニング
    • "dial tcp 127.0.0.1:80: cannot assign requested address" エラーへの対処
    • sysctl -w net.ipv4.tcp_tw_recycle=1
    • (syu_cream/suma90hがやってくれたから良く分からないけどエラーが止まった)

やってみたかったけどできなかったこと

  • MySQLのvarchar(255)になっているカラムの長さを調節
    • login_log の login とか、 (24) にすれば良かった気がする
    • booleanで良い部分が tinyint(4) になっていた所も似たような話
  • ベンチマーク直前のウォームアップ時
    • MySQLのキャッシュを暖める
    • MySQLのコネクションをあらかじめ貼っておく
  • きちんとボトルネック解析
    • 結局、せいぜいtopを見る程度で、細かくボトルネックを解析できなくて、場当たり的でした

感想

去年も言ったけど、こういうパフォーマンスチューニングも面白いですねぇ。 勉強になるので、来年も参加したいなーと思っています。

一緒に参加してくれた @syu_cream さん、 @suma90h さん、ありがとうございました!

DTI@VPS 上のRailsからSendGridを使うとタイムアウトする問題の解決策

Railsからのメール送信にSendGridを使う様に変更してたら起きた問題。誰かの役に立つかもしれないので、メモ。

遭遇した現象とか雑多気味なメモ

SendGridの通例通りsmtpの設定をしてみた、けれどうまく送信されないという現象に遭遇。 同じコードをローカルで立ち上げるとちゃんとメールが送られる。なんじゃこりゃ。と。

動作を見る限りでは、タイムアウトの気配なので、おもむろに以下の様に確認した。

$ telnet smtp.gmail.com 465

まずビンゴで、telnetが通っていない事が判明。

試しにufw disable すると、上記のtelnetが通った。 → 原因がファイヤーウォールに搾られた

次に iptables -L してやると、ESTABLISHED,RELATEDが読まれていない事が確認できる。何か変だぞ、と。 他の似たような設定を為ている環境でiptables -Lした結果と全然ちがう。 ここで、試しに以下の様にしてみる。

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

すると、きちんと繋がる。

(しかしここではufw経由で設定出来ないと困るなーと思っていたら、うっかりiptables -FしちゃってサーバーからSSHがBANされたので、一回VPSの管理コンソールから再起動。)

その他の途中で見てた不穏なエラーメッセージ

検索でだれかが行き着くように、遭遇した不穏なエラーメッセージを書いておく。

problem running ufw-init
# とか…
iptables: Bad rule (does a matching rule exist in that chain?).
# とか…

結論

どうやら OpenVZ環境でufw を使っていると起きるらしい。 (DTIはOpenVZ、らしい)

そういうわけで、以下のサイトの内容の通りにしたら上手く動作してくれました。