blog.katsuma.tv

TokyuRuby会議07でitunes-clientの発表をしてきました

  • 2014年3月29日 15:17

TokyuRubyKaigi07itunes-clientの発表をしました。 Rubyを使わずにiTunesを操作していいのは小学生までですよね!!1

あと、スライドの中でいろいろ動画をいれていたのですが、それもあわせて公開しておきます。

Itunes::Track.find_by

Itunes::Track#play/pause/stop

Itunes::Player.add / Itunes::Track#update

Middleman + SinatraでALOHA FISHMANSのサイトをリニューアルしました

  • 2014年3月 9日 03:31
  • ruby

去年の秋頃、友人経由で、Fishmansファンのためのイベント「お彼岸ナイト」を開催しているALOHA FISHMANSの人たちを紹介してもらったのですが、何か僕で手伝えることがあれば、、というわけでサイトのフルリニューアルを手伝わせていただきました。

今回利用した技術としては

フロントエンド

バックエンド

インフラ

コード管理

  • github(のプライベートレポジトリ)

な、感じ。

今回、このリニューアルでいろいろハマったところや工夫できたことがあったので、もろもろまとめたいと思います。

CSSフレームワーク

以前のサイトは、PCでの閲覧のみ意識していたような作りになっていたので、スマホ(というかタッチデバイス)への対応が一番の要件でした。

さて、じゃぁレスポンシブ対応のCSSフレームワークを選ぶか、、と思って選定に入りました。検討したのはこんな感じ。

CSSフレームワークは似たものが乱立していてさてどうするか。。と思ったのですが、こんな基準で選びました。

  1. サイズが小さい
  2. スマートフォンに最適化されたUIが標準で用意
  3. フレームワークに依存したマークアップを強要されない

Bootstrapは1.が引っかかってやめました。あと、デフォルトの見た目が「いかにも」な感じになるのでもうちょっとシンプルで単純なスタイルが欲しかったこともあって利用はヤメ。

Foundationは全体的にバランスがいいのですが、メニューまわりのマークアップがちょっと複雑なので保留に。最終的には利用することにしたのですが、正直いまだにメニューまわりにクセがある印象なので、そんなに強くオススメできません。。

Skeltonはシンプルでいいんだけども2の観点で見ると、自分でスタイルいじるのは最低限に抑えたかったので、全然スマホサイトっぽい感じがしなかったのでヤメ。

HTML KickStartはすごく単純なマークアップで一番最初は利用していたのですが、メニューまわりのデフォルトの見た目がまったくスマホサイトっぽくない感じだったので途中でヤメました。

Pureはフォント周りのスタイルは一番好きなのですが、マークアップにpure-*とフレームワーク依存のclassやdata属性を強要されるのがどうにもシックリこなかったのでヤメ。

ベストなものは無い

これだけ乱立してるCSSフレームワークだから、さすがにグッとくるものがあるだろう。。と思い込んでたのですが、正直いまだにグッとくるものは見つかってません。。 Foundationを消去法的に利用しましたが、デフォルトのリストUIの見た目はあまりグっとこなかったので、結局いろいろベースとなるスタイルは自分で用意しました。

たとえばクックパッドで利用しているSaraフレームワークは、このへん見た目的にもマークアップ的にも、相当使いやすくなっていると実感できたので、SaraがOSSで公開されてれば。。(チラッチラッ)と何度も思った次第です。

そう考えると、これだけCSSフレームワークが乱立するのもやはり一周回って理解できるわけで、みんな痒いところに手を届かせるために「俺の考えた最強CSSフレームワーク」を作ろうとするんでしょうね。。

middleman

フロントエンドの基盤はmiddlemanにするのは最初から決めていました。

オリジナルのサイトはベースはPHPで実装されていて、チケット管理ページなど動的ページが一部あるものの、ユーザに見える部分はほぼ全てのページが静的な情報なため、PHPのメリットはレイアウトをDRYに書ける、というところに留まっていそうでした。

middlemanは最終的に静的なページを出力しつつ、

  • haml/slimなどのテンプレート言語
  • assetパイプライン
  • LiveReload

などのツールがすぐ使えるので、最近のRailsで開発するような感覚で開発を進めることができるのが大きなメリットです。

実際今回触った感想としてmiddlemanは大正解でした。今後も数ページだけのサイトだったらmiddlemanを利用しない理由は無いんじゃないかな、と言えそうです。1点を除いては。。

Sinatra

1点を除いては、と言ったのは動的なページが出てきたときの対応です。

middlemanはそもそも静的サイトジェネレータなので、動的なページなんて入れようとするほうが悪いのですが、いかんせん必要なものは必要です。今回もイベントのチケット予約に1ページだけ必要でした。

ロジックはシンプルなのでSinatraで完結できれば。。と安易に思っていたのですが、いかんせん事例がほとんどありません。milddeman公式サイトにももちろん載っていません。

で、おそらく唯一であろうヒントはmiddleman作者のThomasさんのコードの断片。要するにconfig.rbに特定のパスだけSinatra::Baseにリクエストを処理させる方法です。

「開発時はいいけどリリース時はproduction環境にどうやって載せるんや。。。」と悩んでたのですがnginxで特定のパスへのリクエストだけUnicorn(で動かしたSinatra)へリクエストを流すようにすればなんとかなりそうかも?と思ってトライ。このへんのインフラ全然触ったことなかったのでハマりましたが、なんとかかんとかできました。

ディレクトリ構造

開発時はこんな感じにしてます。

  • build (ビルドしてできる静的HTMLファイル)
  • app (Sinatraなんかの動的な処理をまとめ)
    • config.ru (production用、開発時は使わない)
  • source (静的ページの開発)
  • config.rb (Sinatraの設定)

middleman buildするとminifyやgzip化されたHTMLファイルがbuildディレクトリにできるので、リリース時はこの中身をまるっとrsync。nginxも基本このファイルを直接返します。

appはSinatraの実態。たとえばこんなかんじ。

app/ticket_reservation.rb

require 'sinatra'
require 'active_record'
require 'mysql2'
require_relative 'models/ticket'

config = YAML.load_file('./database.yml')
ActiveRecord::Base.establish_connection(config["db"]["development"])

class TicketReservation < Sinatra::Base
  post '/reserve' do
    ...
    redirect '/events/reserved'
  end
end

こいつをconfig.rbから呼び出しておく。

config.rb

require_relative 'app/ticket_reservation'

...

map '/tickets' do
  run TicketReservation
end

これで、middleman serverで手元でサーバを起動すると/ticketsのリクエストだけSinatraでハンドリングすることができます。

app/config.ru

開発時は利用しないのですが、productionではUnicornで利用するために必要です。プロセスの再起動はいい感じのタイミングにお願いしたいので、unicorn-worker-killerに任せてます。(設定はデフォルトのまま...)

require_relative 'ticket_reservation'

# Unicorn self-process killer
require 'unicorn/worker_killer'

# Max requests per worker
use Unicorn::WorkerKiller::MaxRequests, 3072, 4096

# Max memory size (RSS) per worker
use Unicorn::WorkerKiller::Oom, (192*(1024**2)), (256*(1024**2))

# Run main app
run TicketReservation

production環境

こんなかんじのディレクトリツリーにしてます。

  • alohafishmans.com
    • app
    • public

リリース時は

  • build ⇛ public
  • app ⇛ app

へrsyncして、appのコードを変更したときのみUnicornを再起動させています。

nginx

config.rbでの設定と同じような感じで設定します。/ticketsへのリクエストだけをUnicornを利用するようにします。こんなかんじ。

alohafishmans.com.conf

upstream unicorn_alohafishmans {
  server unix:/path/to/alohafishmans.com/app/tmp/sockets/unicorn.sock
  fail_timeout=0;
}

server {
  server_name alohafishmans.com;

  location ^~ /tickets/ {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://unicorn_alohafishmans/;
  }

  location / {
    root /path/to/alohafishmans.com/public;
  }
}

その他の問題

基本的な構成は以上なのですが、その他にも細かいとこにもいろいろハマりました。。一応メモがてら残しておきます。

濁点問題

今回ブログのコンテンツのURLを、SEOを意識してタイトルをパス名に入れたURLにしました。例えばこんな感じ。

これも実際は「3/22「お彼岸ナイトvol.8 2014春」まであと1ヶ月!!」ディレクトリと、その直下にindex.htmlを作っているだけですが、buildしてrsyncするとアクセスできず404が。 どうもディレクトリ名がバグっておかしなものになっている模様。。

日本語が悪い??と思いきや、アクセスできるページもある。1文字づつ削って、問題の切り分けをするとどうやら「まであと1ヶ月」の「で」が悪い模様(!)

なんだこりゃ。。。。と思いきやUTF8-Macのエンコーディングに起因する話な模様。解決策としてはrsyncを3系にバージョンアップして(brew install rsyncでOK)iconvオプションをつければ良い。

rsync --iconv=UTF-8-MAC,UTF-8 -avz build/ foo@bar:/path/to/alohafishmans.com/public

FacebookのLikeをすると「You like 404 Not Found」問題

Likeボタンはそれなりに何度も設置しているつもりなのですが、今回はogpの設定をして、DeveloperページのDebuggerで見て情報が正確に設定されているにもかかわらず。Likeするとダイアログに「You like 404 Not Found」が出る、という謎現象に悩まされました。

類似の話としてSEM pdxの記事で全く同じものがあったのですが、向こうでは「IPv6を無効にしたらどうにかなったよ」と言ってる一方、僕の方では無効にしても全く変化なし。

で、やっとこさ気づいたのですが元々のボタンを

.fb-like{ data: { layout: 'button_count', width: '130', href: CGI.escape(page_url) }}

にしていたのですがdata-hrefの指定がどうも間違っていいた模様。正解は

.fb-like{ data: { layout: 'button_count', width: '130', href: page_url }}

コレ。

日本語がパスに含まれてるのを気にしてURLエンコードしていたのですが、まさかそれが足を引っ張っていたとは。。。 (ドキュメント見てもURLエンコードについて特に何も書いて無さそうなのですが。。)

まとめ

久々にゼロの状態からインフラ、DB、アプリケーションの実装まで全部実装したのですが、いい勉強になりました。特にインフラ面は現職ではセットアップ周りを自分ですることはここ数年ほとんどなかったので、仕組みを理解するいい機会になったと実感しています。

また、middlemanは相当使いやすく便利な一方、少しでも凝ったことをしようとするとハマるポイントも割りとあるので、改めて別途エントリをまとめるなり、プラグイン系へ修正PR投げるなりして貢献したいと思います。

最後に、Fishmans好きな人はお彼岸ナイトもぜひぜひ遊びにきてください :)

JISAの要求工学技術部会でクックパッドのものづくりについて発表をしてきました

  • 2013年12月19日 22:45

JISA(情報サービス産業協会)の要求工学技術部会で、クックパッドのものづくりについて発表をしてきました。 内容としては、ここ1年ほどのサービス開発のフローをざっとまとめたものになっています。

ひょんなこと(WEB+DB PRESSの記事をご覧になられていた模様)から南山大学の青山先生にお声がけいただいて参加することになりましたが、普段は触れることがない世界に入ることができてとても新鮮でした。

「要求工学」という存在もまったく知らなかった初心者がその筋のトップの方々の前に現れてWebサービスについてしゃべる、、、という割と無茶な感じではあったのですが、質疑応答でも鋭いコメントをもいただきつつ、ディスカッションもできて、有意義な時間を過ごさせていただきました。こういう場があると、自分たちの考え方を振り返るいい機会になりますね。

RubyMotion2.11がリリースされてspecの中でcontextが利用できるようになりました

  • 2013年10月16日 22:24
  • ruby

相変わらずの週末RubyMotion野郎な日々です。

前回の記事の中でMacBaconにPull Request送った話を書きましたが、本家のRubyMotion自体とは実装が分かれていることに気づいたので、改めてPull Requstを送ることにしました。(実質同じ内容)

実はこのPRなかなかマージされるどころか一切反応がないまま数週間放置されていました。つついていいのかどうなのか温度感もわからないままムーと唸っていたのですが、なんとなく唐突にtwitter経由で確認してもらうようにお願いしてみました。突然のPR確認依頼。

さて、どうなるかな、、と思ってたら3分後mentionが。 まじでー!ってくらい速攻でマージされました。驚愕。。 RubyMotionのメンテナにCocoaPodsメンテナのAlloyさんがJoinしてくれて(前回のMacBaconのPRを見ていただけていた)理解が早かったのかな、、と思いつつ、なかなか動きがないPRは個別でtwitterなり何なりでつついてみるのはアリなようですね。うーむ。

2.11リリース

そうこうしていたら、RubyMotionの2.11が昨日リリースされました。リリースノート見ていたら、確かに僕のPRも入っていましたね!これでSpecの中でcontext使い放題です!!
= RubyMotion 2.11 =

  * Added the `rake clean:all' task which deletes all build object files
    (ex. those in ~/Library/RubyMotion/build). We recommend using that task
    before building an App Store submission.
  * Added support for Xcode asset catalogs. This can be used to manage all your
    image assets in a visual way, including your application's icons. You can
    create and edit a new catalog like so:
    $ mkdir resources/Images.xcassets && open -a Xcode resources/Image.xcassets
  * Fixed a long standing limitation in the compiler where overriding in Ruby
    an Objective-C method that accepts a C-level block was not possible.
  * Fixed a regression where `return' from a block would terminate the app.
  * Improve the build system to always copy embedded.mobileprovision. Thanks to
    Jan Brauer for the patch (pull request #121).
  * Fixed a bug where a boxed struct would incorrectly be interpreted as a
    object type, leading to the dispatcher not recognizing a signature.
  * Fixed a bug where compiled object files of a vendored project were not
    actually being cleaned when running `rake clean`.
  * Fixed a bug where defining a singleton method on an object inside a method
    with named parameters (Objective-C-style selector) would result in that
    method being defined in the runtime with a wrong selector.
  * Fixed a bug where Range objects created with non-literal begin/end points
    would never be released, and therefore leaking memory.
  * Added `context` method as `describe` alias in spec.  Thanks to Ryo Katsuma
    for the patch (pull request #134).
  * Fixed a small internal memory leak in the dispatcher when sending the
    #method_missing message.
  * Fixed a bug in the compiler where providing nil as the value of a C-level
    block argument would not actually pass NULL but an empty Block structure
    instead. Thanks to Ruben Fonseca for the detective work.
  * [iOS] Fixed a bug where device log is wrong filtered with `rake device' 
    when performed day is 1-9.
  * [iOS] Added support to launch the app as 64-bit in simulator.
  * [iOS] Fixed where non-retina iPad simulator does not launch as default.
    Thanks to Fabio Kuhn for the patch (pull request #133).
  * [iOS] Fixed a regression where certain GameKit class properties could not
    be used (ex. GKMatchRequest#minPlayers).
  * [iOS] Fixed a link error where "ld: framework not found IOKit" is caused
    with iOS 7 SDK when it will run `rake device'.
  * [OSX] Fixed the wrong default settings of short cut key in menu. Thanks to
    Kazuhiro NISHIYAMA for the detective work.

変更はほんの数行だけど、自分のちょこっとした貢献で世の中のソフトウェアがちょこっと良くなるのは嬉しいですね。

RubyMotionはじめました

  • 2013年9月19日 01:06
  • ruby

身の回りのiTunes関連で書きたいコードはtaifu, musical, itunes-clientあたりが落ち着いて一段落しました。 そろそろここらでiOSアプリを書けるようになりたいなぁ、でもObjective-Cをゼロから学ぶのもなかなか時間かかりそうだなぁ、、ともやもやしていたところ巷で噂のRubyMotionの存在を思い出したので、週末軽く手を出してみました。

RubyMotionについて細かな説明は省きますが、要するにRubyでネイティブのiOSアプリを作れるコンパイラ、テストスイートなどのツール群です。 Xcodeを(インストールはされていないとダメですが)起動しなくても、ターミナル+好きなエディタでサクサクとTDDでiOSアプリを書けるのが非常に良さそうです。ひとまずこの記事がいい感じにまとまってて良さそうです。

最初の一歩

ひとまず僕はこんな環境で始めてみました。

motion-modeはさくっとDash連携ができて、「このAPIどういう意味なんだ。。」とか疑問に思ってもすぐ調べられるのがとてもいいですね。補完は「ものすごく賢い!」とまでは正直思わなかったのですが、まぁまぁいいかな、な感じ。ここはさすがにXcodeの方が賢そうではあります。

チュートリアル

一番驚いたのは日本語情報が結構多いこと。 とくにRubyMotion.jpは、とんでもないほどの量の翻訳ドキュメントが揃っています。チュートリアルも文句ないレベルで翻訳されているので、ひとまずこれをなぞれば良さそう。僕もUITabBarController付けただけのありがちなサンプルアプリを作ってムフムフしていました。XcodeのDeveloperPreview版を利用したら、ちゃんとiOS7用でビルドできましたよ。

テスト

RubyMotionに興味をもったきっかけの1つがRSpecぽい形でテストが書けること。マジで??と最初はびっくりしたけど、確かにこんな感じで書けた。 これは、タップして状態が変わってるかどうかのテスト。

describe "button controller" do
  tests ButtonController

  it "changes instance variable when button is tapped" do
    tap 'Test me!'
    controller.instance_variable_get("@was_tapped").should == true
  end
end

よく見たらRSpecぽいけど、実はちょっと違う。

というのも中身はBaconというミニマムRSpecクローンをforkしてObjective-C用に拡張してできたMacBaconというものが利用されています。 ミニマムなクローンなので、当然のごとく本家RSpecには無いものも多くあって、subjectもletもcontextすら無い、、とRSpecに普段慣れている人にとってはむずむずしそうな内容。まぁテストをRubyで書けるだけでもかなりいいのですが。

ひとまずcontextはdescribeにalias張るだけで簡単にできるので、MacBaconにcontextを利用できるようにするPull Requestを送ってみたところ、早速取り込んでもらえました。

ただ、この変更がRubyMotion本家にどうやって反映されるのかは正直よくわかっていないので、もうちょっと掘りたいところ。MacBaconはまだまだ手が出せそうな雰囲気があるので、ここはいろいろ貢献していきたいと思っています。

まとめ

ひとまず身近な開発環境でiOSアプリを作ることができるようになりました。

iOSのAPIは正直まだまだ全く理解できていないので、作りたいものを作れるレベルには全く達していないのですが、少しづつ手を動かして学びながら怪しいアプリを作っていこうと思います。

Index of all entries

Home

Search
Feeds

Return to page top