Authyがとても良い

みなさん二段階認証ってちゃんと設定してますか?

俺はずっとGoogleAuthenticatorを使って二段階認証してました.

Gmailくらいならまぁ……という気がしてますが,AWSのアカウントはさすがに怖いしね!

二段階認証のバックアップがほしい

二段階認証,大変良いのですが,認証設定をしたiPhoneなりAndroidなりがかなり大切になってきます.

まだ,他にログインできる人がいる,例えば会社で使ってるAWSアカウントなら,たとえ端末を紛失しても復旧はできるし,IAMアカウントを停止させることもできます.

ただ,個人で使ってるAWSだったり,Githubだったりって,端末を紛失したら復旧手段がないじゃないですか. もうサポート問い合わせしかない.

そうでなくとも,例えば端末を新しくした時に,二段階認証の設定をちゃんとやりなおしていないと,新しい端末ではログインできなくなったりします.

こういうのが最近怖くて…….

続きを読む

RxSwiftとAPIKitの組み合わせに対する違和感

みなさんさようなら.

最近ようやくRxSwiftを触り始めています.

RxSwiftでAPI通信を含むような動作をさせたいとき,何を使おうかと迷ったので,その話をします.

swiftで書けるってことは,別に NSURLSession をそのまま使って rx_response を呼んでもいいわけです. ただ,そうはいっても世の中にはいくつかAPI呼び出し用のライブラリがあります.

Alamofireあたりはかなり有名ですよね. 前にアプリを作った時は,まだAlamofireが出てきていなくて,AFNetworkingを使っていました.

で,最近ではAPIKitというのがちょいちょい名前聞きますね. 名前聞くっていうか,高専時代の友人が作ってるんで,最初から知ってるんですけど,そういうつながりなしにも名前を聞くようになってきました.

続きを読む

最近思うgolangのerror

golangが結構好きになりつつある. そんな中でも延々と悩まされ,設計を考え続けているのが,error型だ.

もしかしたら,あまりgolangmysqlのような,がっつりSQLでできているRDBを使う人は少ないのかもしれない.

だけど,自分が作っているものが,がっつりWebサービスで,どうしてもRDBに近いところで動かさなきゃいけないので,こういうことで悩む.

panic時にはtransactionのrollbackを

func hoge(tx *sql.Tx) (e error) {
    defer func() {
        if err := recover(); err != nil {
            tx.Rollback()
            e = errors.New("unexpected error")
        }
    }()
    tx.Exec(...)
}

どうしてもtransactionを使うとこういう処理を書かざるをえない. もちろん, sql.Txerror型を返すのだが,それ以外のところで,例えば nil 参照等が起こらない保証がない. どうしても,そういうリスクは消し去ることが出来ない以上,どこかでrollbackを仕掛けておくべきだろう.

というわけで,しばらくこの方式で,transaction周りではrecoverで防いでいたのだが,いざ本当にrecoverしなきゃいけないようなエラーが起こった時に,困ったことに気付いた.

unexpectedって何が起こったかわからない

当然だった. 自分で握りつぶしてunexpectedにしているんだから,何が起こったのか全然わからなかった.

ただ,recoverした段階ではerror 自体は取得できているはずだ.

というわけで,苦戦してみた.

func hoge(tx *sql.Tx) (e error) {
    defer func() {
        if err := recover(); err != nil {
            transaction.Rollback()
            switch ty := err.(type) {
            case runtime.Error:
                e = ty
            case string:
                e = errors.New(err.(string))
            default:
                e = errors.New("unexpected error")
            }
        }
    }()
}

なるほど,こうすれば,何が起こったのかをerrorとして渡すことができる.

まぁ本当はすべてのエラーを渡したいところではあるが,recoverした段階では err はただの interface{} になってしまっているので,実際どんな型にキャストできるかはわからない. なので仕方なく, runtime.Error と,任意の errors から出てくるエラーだけ拾っている. まぁ,大抵のものは拾えたりする.

どこでエラーになったのか?

これは今でも悩みどころだ.

error としてメソッドの戻り値にしてしまうのはとてもよかった. ただ,メソッド呼び出しが何階層も深いところで起こっていて,最終的に呼び出し元のメソッドerror 型が渡ってきた時,はたしてそのエラーが,どのメソッドで発生したものかを特定することができるだろうか?

これはなかなか難しい問題だ. もちろんすべてのエラーについて,たとえばメソッド名を頭につけるような変更をしておけばいい.

ただ,これはこれで書く人間にやたら負担を強いるし,必ずしもstringにキャストできるerrorばかりではないので,あまり現実的とは言い難い.

エラーの通知

また,エラーを通知することを考えると,いったいどの階層でエラーをハンドリングして通知すればいいのだろうか?

自作のメソッド,A, B, Cがあったとする.

A -> B -> C という階層順でメソッド呼び出しを行い,Cのどこかでエラーが発生したとしよう. error型の戻り値は,C -> B -> Aと伝搬する.

さぁ,果たしてエラーの通知はどこで行うべきだろうか?

Aでエラーの通知を行うと,Aから見た場合,「Bを呼び出したらエラーになった」という情報しか得られない. しかし,実際にエラーになったのはメソッドCの中である.

では,Bでエラー通知を行うとしよう.

そうすると,Bから見た場合「Cの呼び出しでエラーになった」という情報しか得られず,結局Cの中のどこがダメだったのかわからない.

最下層のメソッドだけでエラー通知をする

やはりここはCでエラー通知を行おう. 戻り値を返す手前でエラー通知してしまえばいいのだ.

たしかに一見正しい情報を伝えることができる.

しかしその後のことを考えよう. Cでエラー通知をしたから,AもBもエラー通知をしなくても良いのか?

こうしてしまうと,Cについては良くても,たとえば,A -> Dのようなメソッド呼び出しがあった場合,Aは常にDがメソッド内でエラー通知しているかを確認しなければならない. メソッドの呼び出しが単純ならばそれほど困らないが,いろんな場所で使いまわされるメソッドであったり,逆にいろんなメソッドを呼び出すようなメソッドを作る場合,信じられないくらいの負担になってくる.

また,自身が呼び出し順序的に最下層のメソッドになっているという判定はどうしたらできるだろうか? これは非常に難しい問題になってきてしまうので,結局最終的には「全部のメソッドでエラー通知するしかない」となってきてしまう.

すべてのメソッドでエラー通知

これはこれで合理的ではある. こうしておけば,エラーがどんな順序で起こったかがすべてわかるからだ.

まぁ行数が増えるのでまったくうれしくないのだが…….

しかし問題もある. goはgorutineを使ったスレッド実行がお得意だ. スレッド実行になった場合,スレッド1でCがエラーになって通知されたとしよう.同時にBもAもエラー通知をしてくる. ひとつのエラー発生で3回通知されてしまう.

さらにややこしいことに,スレッド2ではBでエラーが発生したとしよう.同時にAもエラー通知をしてくる.

ふたつのエラーで合計5回のエラー通知がされる.

これは非常にわかりにくい. その上,どのメソッドがどのコンテキスト(今回はどっちのスレッドで実行されていたのか)でエラーになったのかがわかりにくくなる.

これでは通知が来た時,いったいいくつの処理,いくつのスレッドでエラーが発生して,リカバリには何をしたらいいのかがわからなくなってしまう.

複数回通知しても,それらが同じ原因であるなら,同じコンテキストで発生したエラーであることを明示しておかないと,エラー通知の意味がなくなってしまう.

そうなると,じゃぁエラー通知の瞬間にgorutineの情報を得ようと考えるだろう.

しかしそれはできない.

moznion.hatenadiary.com

qiita.com

groups.google.com

できないんだ.

どうにもできない

結局今のところ「エラー通知をうまいことする」というのは非常に難しい問題になっている.

やはり最上位階層で,「これがエラーだったら,別の処理にしよう」という段階で通知を仕込むのが最も適切だろう.

あと,最近思うことなのだが,panic自体はそんなに悪い手法ではないのではないだろうか?

例えばWebサーバを考えた時,panicしなければサーバの処理は継続される. もちろん,そういうレベルのtry-catcheであれば,error型の得意とするところなので,エラー処理を書けばいいだろう.

だが,goを元にした大抵のWebサーバフレームワーク(gojiやmartini)は,panicが起きても,スタックトレースを出して500を返して,次のリクエストを受けられるようになる. つまりサーバのプロセス自体は殺されない.

ということは,むしろエラー通知をしたいレベルのものであれば,error型で拾って,コントローラ層等で通知を考えたり,その後の処理を考えるよりは,panicしてしまって,panicの通知を考えたほうがいいのではないだろうか. スタックトレースが出るのであれば,どこでpanicされたのかは一目瞭然だし,任意のerrorを送ることもできる.

むしろこっちのほうが,通知やリカバリということを考えたら,使い勝手がいい方法なのではないだろうか.

俺のためのタスク管理サービスを作った

みなさんさようなら,またひとつサービス作ったよ.

俺のためのタスク管理サービス.

Fascia

めずらしく痛くないというのが一番の特徴じゃないですかね.

動機

ToDoリストをどこかで管理したい

これに尽きる.

だいたい普段生活していると,メモできなかったり,PCが近くにない状況に限って「あ,あれやらなきゃじゃん」というのを思い出したり,思いついたりする. これをいかにして管理していこうかと悩んで,いろいろ使ってはみたものの,どれも定着しなかった.

iPhoneにアプリを入れて,出先でも登録できるようにしても,なぜか定着してない.

なんで定着しないんだろう?

github管理下のToDoとそれ以外のものが並列に出てくるから

俺の脳内では,「あ,Whalebirdにあの機能積んでおこう」という思いつきも,「あ,仕事であれやっといたほうがいい」という思いつきも,「キッチンペーパー買ってこないと」という思いつきも,すべてが並列に出てくる. とくに何かについて考えていない時に,こういうものが順不同に適当に出てくる.

これらのToDoリストを,例えばtrelloで管理するとどうなるか.

  • Whalebirdのタスク

    trelloにメモ -> githubにissue立てる -> PRが出てくる -> PRとissueがcloseされる -> trelloのタスクを自分でdoneにする

  • 仕事のタスク

    trelloにメモ -> redmineにissue立てる -> PRが出てくる -> PRとissueがcloseされる -> trelloのタスクを自分でdoneにする

  • キッチンペーパー

    trelloにメモ -> 買い物に行く -> trelloのタスクを自分でdoneにする

フロー違いすぎ,手順多すぎ,めんどくさすぎ,無理.

一度,全部github管理にしようかとも思ったんですよ. でもキッチンペーパーの買い物とかが入る,家用のリポジトリ作るの?

コード0行だよ?

というわけで自作することにした.

使い方

いや,特に説明するようなことはないです.

githubログインにしておくと,project作るときに,githubリポジトリ関連にするかどうかの選択ができるんですが,そのくらいじゃないですかね.

あとはtrelloと同じ感じで使えます.

リポジトリ関連にしておくと,ちょっと複雑なことができます.

  • github側に勝手に同期される
  • webhookが設定されるので,github側の変更も同期される

コンセプト

俺のためにって書いたとおり,自分で使いたいものを作ったので,俺が便利だと思うように動くようにしてあります.

そして,個人のToDoを管理したかったので,チームで使うような用途は想定していません. なので,プロジェクトを他人と共有したり,チームを作成したり,何かをパブリックにしたりする機能はないです.

そのため,githubのissue管理として運営される類似のサービス(waffle.ioやzenhub)のように,チーム開発やスクラム向けの機能は提供しません.

ただ,githubのissue管理機能については,もっと便利にしていきたいので,

  • issueやPull Requestのコメント関連機能

あたりは近いうちに実装するかもしれません.

開発

リポジトリはこちら.

github.com

サーバサイド

サーバは全部goで書きました. あまり機能的には多くないアプリですが,それなりに行数増えてしまった.

golangを書いていると,設計をいろいろ悩んだりするので,とてもよかった. 特にpackageという分離は,classみたいに手軽に使えないよねっていうのが,今の感想.

それと,エラーハンドリングについてはかなり悩まされました. できれば,本当に不要なパターンを除いて,ほとんどのメソッドerror 型の戻り値をつけておいた方が良い.

フロントエンド

ほとんどReact Reduxです. ログインとか,そのへんだけはjs使わなかったので,サーバサイドでhtmlレンダリングしている.

SPAと決めて,覚悟しちゃうとこれはかなり使いやすいなー. Reactのサンプルでは,よくToDoリストのサンプルが載せられていて,「これ簡単にいけるかなー」って思ったけど,全然その後が大変だった. サンプルはみんな載せてくれるけど,本当に大変なのはあの先である.

あと,こういう形でjsレンダリングしたかったのは,のちのちアプリを作ることを考えて,サーバを全部APIにしておきたかったというのもある.

俺のために

あとはiOSアプリにすれば,俺の欲望は満たされることになる. しかし先は長そうだなこれ…….

Shoryuken,それと例外検知gemを作った話

みなさんさようなら. Railsの非同期処理って何使ってますか?

Sidekiq?Resque?,え?DelayedJob?

個人的にはSidekiqが結構好きで,よく使っていたのですが,最近Redisのメモリが足らなくなってきて…… たまにエンキューに失敗します.

もちろんインスタンスタイプを上げればいいんですが,それなりの値段するじゃないですか.

Shoryukenを使ってみる

Shoryukenというのがあってですね,だいたいSidekiqと同じ要領で使える非同期処理用のgemなんですが,バックエンドがAWS SQSなんですよ. だから,これRedisの運用とか真面目に考えなくてもいけるんじゃね?とりあえず全部メッセージに突っ込んでも,重くならないし!

そんなこんなでShoryukenを使ってみました. というか,既に運用しているasumibotに入れて,運用してます.

github.com

Shoryukenの細かい動作についてはこのへんにまとめました.

qiita.com

使用感:

  • SQSを使うのでメモリのことを気にしなくても良く,エンキュー数が増えてきても安心
  • 料金的に$0.5/1M という非常に安い価格設定なので,Redisを増設するより安い
  • (そもそもキューってRedisに入れるほどの情報でもないし……
  • マルチスレッドで,だいたいSidekiqと同じ要領で使える
  • ローカルでのSQS再現にはFakeSQSを使えばいいので,開発環境でのAWSSQS課金についての心配は不要
  • 今のところ例外が起こってもどこにも通知されない
  • リトライの機構についてはSQSを頼ることになるので,若干不便
  • 速度的には,SQSのポーリグ間隔(によってSQSの料金が変わる)に依存するので,Sidekiqほど即時に処理してくれるわけではない

例外が通知されないのは困る

上記の中でも特に例外のところが困っていて,RailsのアプリだとExceptionNotification等で例外を検知していると思うのですが,そこで検知してくれない.

Sidekiqなんかだと,ExceptionNotification側に既に用意されていて,割と簡単に用意できたりします.

github.com

これがないのが困っていて,みんなどうしているのかなー?

ExceptionNotification::Shoryuken

と思っていても始まらないので,gemを作りました.

github.com

だいたい,ExceptionNotificationのSidekiqをパクった感じです.

普通にインストールしたら,config/initializers/exception_notification.rb あたりに,

require 'exception_notification/shoryuken'

ExceptionNotification.configure do |config|
  # setup some notification
end

とか書いておけば,勝手に検知して,その他の例外と同じように設定してある通知先(メールとかSlackとか)に通知してくれます.

Shoryukenってまだ直しどころがある

実はShoryuken本体の方にもPullRequestを投げたりしているのですが,Shoryukenってまだ未熟な感じがします. 使ってると足らないところを結構発見するので,直し甲斐があるというか,PullRequestが積まれるというか.

ソース的にはSidekiqを参考にしている色が強く出ていて,PullRequestやIssueの議論でもSidekiqの話がたまに例に出されます.

そういう話をして,Sidekiqのソースを見に行くと「完成度たけーなおい」と思うしかない.

Shoryukenはそれに比べると,機能的にも少ないし,完成度もまだまだな感じがします. それは盛り上がり方とか,作者のやる気にも寄るんでしょうけど…….

使う人が増えてくれれば嬉しいんですが,みんな本当に非同期処理って何使ってるんだろう?

SQSの機能が,Sidekiq+Redisほどブラックボックスとして扱えないので,SQSの知識が必要になってしまうという障壁はあるんですが. それでも,それなりの大きさのRedis運用をまともに考えるよりは,かなり手抜きができて使いやすいと思うんですけどね.