ninjinkun's diary

ninjinkunの日記です

2012-03-26

iOS組み込みのキャッシュモジュールNSCacheについて発表しました

NSCacheというキャッシュモジュールについて第43回Cocoa関西で発表してきました。

NSCacheの特徴

  • スレッドセーフ
    • NSDictionaryのように手動でロックする必要がない
  • 格納オブジェクトの上限を決められる
    • 溢れたら自動破棄
    • iOSのようなメモリ制約の厳しい環境に最適
  • NSDictionaryに似たインターフェイス
  • Mac OS 10.6 / iOS 4.0以上で使える

具体例としては、ダウンロードした画像をオンメモリにキャッシュする際等にとても有用だと思います。同じような機能を提供してくれるOSSのモジュールは見たことがあるのですが(例えばnimbusに含まれているNIMemoryCache)こちらはOS組み込みなので手軽に使えます。

発表資料

サンプルコード

Twitter及びInstagramの画像をロードしてデモするサンプルコードは以下です。それぞれの機能を動かすには、組み込みTwitterの連携設定とInstagramのアプリケーションキーが必要になります。
http://github.com/ninjinkun/NSCacheTest

おまけ

発表後の質疑応答で、キャッシュの破棄は基本的にLRUで行われていそうだという部分に、コストを入れた場合は別のアルゴリズムで破棄が行われるのではないかという意見が出ました。一応追試をしてみましたが、コストを入れた場合でもLRUのようでした。追試のコードは以下の通りです。

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        NSInteger size = 1024;
        NSCache *cache = [[NSCache alloc] init];        
        
        for (int i = 0; i < 100; i++) {
            NSData *data = [NSData dataWithBytes:malloc(size) length:size];
            cache.totalCostLimit = 1000;
            [cache objectForKey:[NSNumber numberWithInt:10]]; // 途中で10にアクセスしてみる
            [cache setObject:data forKey:[NSNumber numberWithInt:i] cost:i];                        
        }
        
        for (int i = 0; i < 100; i++) {
            NSData *data = [cache objectForKey:[NSNumber numberWithInt:i]];            
            if (data) {
                NSLog(@"has data #%d", i);
            }
        }
    }
    return 0;
}

has data #10
has data #90
has data #91
has data #92
has data #93
has data #94
has data #95
has data #96
has data #97
has data #98
has data #99

3/26 16:50追記

id:KishikawaKatsumi さんが参考になる感じの使い方をつぶやかれていたので、以下に引用します。転載許可ありがとうございます! > id:KishikawaKatsumiさん



3/30 12:10追記

3/27にid:KishikawaKatsumiさんの画像キャッシュとダウンローダーについての記事が公開されていました。反応遅れてすみません…。だいぶ参考になる内容です。
ダウンロードした画像をキャッシュするクラスの設計と実装について - 24/7 twenty-four seven

2012-02-19

プロiOS開発者への入り口 - iOSプログラミング第2版

iOSプログラミング 第2版

昨年末に出たiOSプログラミング第2版が結構良いと思っているので紹介します。全体的にプロのiOS開発者を養成するための教科書として作られた感じがある良書です。
以前はオライリーから出ている本が良いと思っていたのですが、iOS 3ベースで書かれているのでだいぶ古くなってしまっていました。この本は最新のiOS 5…ではなくてiOS 4.3ベースですが、きちんと内容としては現在でも通用するものになっていると思います。以下、良いと思うところを書き出してみます。

  • まずアプリを作ってみて、それを解説するスタイルになっている
  • 網羅的、UIKitでできることはほとんど書いてある
    • きちんとUIView, CALayer, CoreData等がカバーされている
  • 設計方針についてもきちんと書かれている
    • Cocoa的な設計、コーディングスタイルが解説されている
    • Delegate, Target Action, Blocks, など多彩なコールバック手法について用途とベストプラクティスきちんと解説されている
  • 開発ツールにも触れられている
    • Xcode、ドキュメントの引き方、Instrumentsについてもきちんと解説されている

原書は2011年7月に発売されたようなので、iOS 5のARCやStoryBoardについては解説されていないのが残念ですが、タイミングを考えると仕方ないでしょう。4月には原書版が3rd Editionになるようなので、恐らくその辺りの内容が盛り込まれるものと思います。(どうせ6月のWWDCでまたいろいろ変わるので、3rd Editionを待ってもそんなに良いことはなさそう)

自分が知っている中では現時点で一番良い入門書だと思います。はてなでは先月からこの本を使ってアプリ開発未経験者向けの勉強会を始めました。なかなか濃い内容なので大変ですが、きちんと読んでコードを書いていけば大抵のアプリは作れるようになると思うので、がんばって完走したいところです。

というわけで、多少ハードコアでもきちんと解説されている方が好きな方にオススメです。

2012-02-09

ゼルダの伝説 風のタクトをクリアしました

ゼルダの伝説 風のタクト

Wiiを手に入れたので、ずっとやりたかったゲームキューブソフト『ゼルダの伝説 風のタクト」をプレイした。2002年の作品で、当時受験生だったので買えなくて、ほぼ日に上がる攻略日記をひたすら追いかけていた。

実際プレイしてみると恐ろしく作り込まれていて、キャラの動作が何パターンあるのか把握しきれないくらい動くし、ダンジョンも毎回3つくらい発見があるくらいアイデア満載で、いちいち唸りながらプレイしていた。こんな壮大なものを監修して世に出すのは、どういう体制なんだろうというのがひたすら気になった。音楽もとても良いですね。

最後の最後で作業ゲーになってしまうのが非常に残念で、それさえなければ気持ちよく終われたのに惜しい感じだった。*1

余談だけど、「ゼルダの伝説」のゼルダはスコット・フィッツジェラルドの奥さんの名前から取られていると知ってちょっとびっくりした。

次はトワイライトプリンセスにチャレンジです。(コントローラーが無線になって嬉しい)

2012-01-26

iPhoneアプリの通信エラー処理についてCocoa勉強会関西で発表しました

第42回Cocoa勉強会関西でiPhoneアプリの通信エラー処理について発表してきました。内容としては先日書いたブログエントリの焼き直し + ケーススタディのデモ + サンプルコードの実装という感じです。「やっぱりちゃんとやらなくちゃね…」などの感想が漏れる等、開発者にとっては耳が痛い内容になっております(僕も辛い)。

スライドは以下です。

サンプルコードは以下にあります。
https://github.com/ninjinkun/AlertResume

2011-12-24

はてなTGIFの歴史 - Hatena Staff Advent Calendar 2011

こんにちは、はてなアプリケーションエンジニア兼TGIF幹事のid:ninjinkunです。このエントリはHatena Staff Advent Calendar 2011の24日目の記事です。TGIFとはThanks God It's Fridayの略で*1金曜の夜に一週間の仕事を労って飲み会をやるというものです。元々はGoogleシリコンバレーの企業がやっていたものを取り入れたと聞いています。
はてなのTGIFは一応オフィシャルな会社行事です。なのでご飯、お酒は会社から提供されます。オフィスランチを作ってくださっているさっこさんの手による軽食が提供され、ビールやチューハイなどが並びます。東京オフィスと京都オフィスをポリコムで繋ぎ、同時に開催しています。
会社で飲み会?しかもタダ?いいじゃない、いいでしょう。しかしこのTGIFというイベント、実はこの数年でその形態をじわじわと変えてきました。今日はその変遷と幹事の苦労について語ろうと思います。

過去のTGIF

TGIFは僕の入社よりさらにその前、はてなの開発部が東京にあった時代から開催されていました。記録を漁ってみたところ、2007年3月9日が第一回目であったようです。その当時のことはあまり詳しく知らないのですが、各チームが振り返りをやったり、役員やサービスの責任者が発表をするなど、会社の情報共有の側面が強かったようです。

2008年

僕が始めてはてなのTGIFを体験したのは、2008年のはてなインターンでした。あまりネット企業のカルチャーを知らない学生だった自分は、そもそもまず会社でお酒を飲んでいるということに驚きました。そしてTGIFが会社の情報がオープンに入って来る場として機能していることも印象に残りました。全員参加自由の雰囲気だったので、インターンが社員の方々と交流するのにも丁度よい場でした。
当時は新ほたてシステムが稼働し始めたところで、毎回ほたて賞の投票と発表が行われていました。

f:id:ninjinkun:20080822191147j:plain

ほたて賞について

ほたて賞、Hotな Taskを Tataeる賞の略と言われていますが、詳細は定かではありません。スタッフのタスクを称えるための仕組みです。毎週のタスクをシステムに入力し、投票で1位〜3位を決定します。入賞者にはAmazonギフト券が贈られます。

ここに各々の細かいタスクを集めることで、個々人やチームの細かい仕事も全社で共有することができます。現在のシステムはid:suzakのアルバイト研修の課題として作られたのですが、非常にコードが綺麗に書かれていて見通しも良いので、新人やインターンに見本プロジェクトとして紹介しています。このシステムは開発合宿の成果発表会での投票にも使われています。

2009年

僕が入社した2009年春は丁度リーマン・ショック後で、セコイア・キャピタルの「サバイバルに努めろ」が発せられた後でした。
入社してみるとビールは発泡酒に変わり、ほたて賞のAmazonギフト券は廃止されていましたが、TGIF自体は継続されていました。
しかしここで号令がかかります。「TGIFを改革せよ」ずっと継続してきたTGIFですが、もっと良いものにできないかという話でした。毎回の司会のid:nagayamaさんの負担も相当なものだったようで、そろそろ運営の中核を変えても良いのではないかという話もありました。

TGIF幹事

そこで6月にTGIF幹事という役職が開始されます。id:nagayamaさんは名誉幹事長という職に退き、3人の幹事が任期付でTGIFを運営するというものです。入社してまだ特に何も成果もなく(というかひどいミスを繰り返していた)、しかし意識の高かった自分は、とりあえずみんなに名前を覚えてもらえるチャンスかもしれないと打算的に考え、立候補しました。こうして第一期TGIF幹事団が結成されました。
時々お昼休みにid:jkondoさんも交えてミーティングをし、IRCの#tgifチャンネルで細かい話をしながら*2、色々詰めていった覚えがあります。だいたい以下のことが決まりました。

  • TGIFを隔週にする
    • 幹事と参加者の負担軽減、予算の削減
    • ほたて賞Amazonギフト券の復活
  • 毎回なにか発表を入れる
    • 技術的なことや成果等
  • ほたてには達成率や目標を書く

発表者を集めるのも結構苦労していた記憶があります。新入社員が自分たちのやっていることを紹介する時間にしたこともありました。
外回りや用事などでTGIFに参加できなかった人のためにTGIFの空気を伝える、『TGIF通信』も開始されました(現在はお休み中)
また、今は恒例行事になっているはてなハロウィンもこの年から開始しました。年末には一年分のタスクをもう一度称える忘年ほたて賞も行われました。
f:id:ninjinkun:20100326193514j:plain

司会

肝心の司会は、自分がアドリブでしゃべるのが苦手だったため、毎回id:chris4403さんにお願いしていました。しかしどこかのタイミングで自分が司会をする羽目になったことがあり、とりあえず本をAmazonで買って読みました。


すぐに役立つ司会の進め方と実例

挨拶の順番やお店とのやりとりなどが中心で、自分の用途にはあまり役にたたなかったので、先日処分しました。

2010年

幹事は3ヶ月ごとに交代するのですが、自分は確か3期務めたのでこの年の初めまで幹事だったと記憶しています。多少変更も行いました。

  • 発表は毎回の確保が難しいのと時間が長引くので廃止
  • 会場が会議室に変更に

また、一部社員しかほたて賞の投票をする人がいないなどの話もあり、1~3位を予想して、予想が的中すると商品がもらえるような制度もできました。このあたりを実現するためにほたて賞システムに多少手を入れて行きました。こうしたシステム改修がたまにあるため、TGIF幹事にはエンジニアが最低一人は要ることが望ましいですね。
id:kyabanaさんの運営があまりにも安定していたため、その後長期にわたりid:kyabanaさん主導・司会によるTGIF運営が継続されることになります。
この時期にほたて賞の社員投票によるAmazonギフト券分配がなくなり、役員による賞の決定が行われるようになりました。

f:id:ninjinkun:20090918194927j:plain

2011年

id:kyabanaさんによる安定したTGIF運営が継続していました。しかしあまりにも長い間、2年近く幹事をされてきたid:kyabanaさんの負担も相当なものであったと思います。TGIF幹事が再び交代する時期が来ました。
そしてこの秋、id:chiros4403幹事長の元、僕も幹事として復帰することになりました。
新しいTGIFも隔週で行われているのですが、

  • 1週はサービス開発各チーム責任者による発表とディスカッション
    • 仕事の一分として夕方から定時内に行う
  • もう1週は今まで通りほたて賞
    • ほたて賞はスタッフによる投票制に戻す

という内容になり、フォーマルな要素と慰労の要素が混じった形になりました。

まとめ

こうして振り返ってみると、なんで飲み会のことにこんなに時間を費やしているんだろうという気分になってきます。しかし、全社の一体感を保つという意味で、はてなのカルチャーの中でもTGIFはかなり重要であると思っています。
現在のTGIFの意義は以下の2つだと考えています。

  • 全社の方針を共有し、それに対してコミットする
  • 社員同士がボトムアップにお互いの仕事を知って評価する

制度を作ったり変えたりするのは大変ですが、TGIFは社員がボトムアップにつくりあげていくところに意味があるのではないかと思っています。これから先社員がもっと増えると今の形態も変わって行くのでしょうが、できるだけみんなの納得行く形で残していきたいですね。来年も楽しく金曜日を迎えましょう!

明日の大トリは僕の上司でもあるid:nmyさんです。

2011-12-23

iPhoneアプリの通信エラー処理を考える - iOS Advent Calendar 2011

こんにちは。お仕事でiPhoneアプリを開発しているid:ninjinkunです。このエントリはiOS Advent Calendar 2011 23日目の記事です。今回はあまり注目されることがなさそうなiPhoneアプリのエラー処理を取り上げてみようと思います。

エラー処理と言うとプログラマが粛々とやるものというイメージで、主に内部のエラーハンドリングのことが中心になりがちです。しかしエラー処理はそれをユーザーに通知するところまで考えて初めて完結します。この記事ではユーザー体験の面と内部処理と両方に言及してみようと思います。自分の今までのアプリでもあまり実践できていなかったので、自戒の念も込めて…。

エラーは様々な状況で発生しますが、ここでは主にHTTP通信のエラーを想定します。HTTP通信はiPhoneのようなモバイル端末では高い確率で失敗します。移動中、地下鉄、山の中の中など通信が不安定なヘビーな環境で使われることが想定される為です。また、サーバー側が何らかの障害で応答できない場合もあります。このため、通信のエラーは必ず起こるという前提での設計が必要になります。

さて、理想的なエラー処理のユーザー体験とはどのようなものでしょう。書籍About Face 3のエラーの項目では以下のようなことが言われています。

エラーメッセージボックスは、プログラムがバカなので処理を停止するといっているようなものであり、避けなければならない
エラーメッセージには、究極のアイロニーがある。ユーザーがエラーを犯すのを防いではくれないのだ。

エラーメッセージが散々に言われていますね。確かに正しいのですが、瞬時にリカバリがしにくいHTTP通信ではどうしてもエラーをフィードバックする必要がある場合があります。書籍中ではエラーメッセージは最後の手段として取り上げられていますが、

エラーダイアログは、必ず礼儀正しく、わかりやすく問題点を示し、役に立つものでなければならない。

という注文がついています。そしてその中で、ユーザーに必要な情報を提供した上で、必ず一つは解決策を提示せよ(キリッと言っています。かっこいいですね。痺れますね…。

 

エラー処理プラン

これを元にして私が考えたエラー時の処理プランは以下の3つです。

  • ユーザーの操作をインタラプトせずにレジュームする
  • ユーザーの操作をインタラプトしてレジュームする
  • エラーメッセージを表示するだけ

エラーに気づかせずに粛々と進めるのが最善ですが、それができなければきちんと知らせるという感じです。しかしここでHTTP通信のことを考えると、松プランの実践は結構困難になります。HTTP通信が途切れる場合、しばらく(もしくは長時間)通信が復活しない可能性が考えられます。

また、iPhoneアプリの制約もあります。一度バックグラウンドに入ったアプリのタスクは特殊なものを除いて10分しか存続できないのです(Task Completion機能)。つまり通信を監視してレジュームしようにも、すでにアプリがバックグラウンドに入っていて処理が継続できない場合があるわけです。このような状況から、おそらく現実的な選択肢は竹プランになると思います。 

ここまでの考察を踏まえた上で、ケーススタディに入ってみようと思います。HTTPを使い、何かをPOSTするアプリケーションの中から、よくできていると評価の高いアプリを選んでみました。エラーは通信を遮断された状態を想定しています。機内モードで通信を切った場合と、通信がタイムアウトする場合と両方の環境を試しましたが、たいていのアプリでエラー処理は同じでした。*2以下の例でも両方の環境が混在しています。

Mail

メール送信が失敗すると、一旦送信ボックスに入ります。送信の失敗ダイアログなどは表示されませんが、送信ボックスのカウントが増えるので、まだ未送信のメールがあることは確認できます。このアプリはバックグラウンドにいても、通信が再開してしばらくすると再送信を試みます。純正アプリだからできる挙動ですが、松プランが的確に実装されている例と言えるでしょう。

f:id:ninjinkun:20111223102625j:plainf:id:ninjinkun:20111223102647j:plain

 Twitter

投稿に失敗すると下書きボックスに入ります。そしてアラートが出ます。下書き機能が付いているアプリは下書きをエラー時のキューとして使えるのが良いですね。投稿は特に自動で再送されたりはせず、ユーザーの操作でリカバリする必要があるので、竹プランの実装例になります。

f:id:ninjinkun:20111223094338j:plainf:id:ninjinkun:20111223094315j:plain

余談ですが、最近エラーをLocalNotificationで通知する例が増えてきました。バックグラウンドでアップロードしていても前面に通知が出せる上に、iOS5からの通知センターのお陰でそれほど邪魔ではなくなったからでしょうか。

f:id:ninjinkun:20111223095549j:plain

Facebook

POSTが失敗しても何も出ません。エラーが握りつぶされました。何のフィードバックも無くデータも消えたので、梅プランよりひどいケースであると言えそうです。タイムラインの表示が失敗した場合にリロードボタンが出るのは非常に良いと思えるだけに残念です。

f:id:ninjinkun:20111223101334j:plainf:id:ninjinkun:20111223101348j:plain

一方、Facebookメッセージアプリの方はきちんとエラー処理を実装しています。Belugaの買収が効いているのでしょうか。こちらはSMSアプリなどと同じような感じですね。ユーザーがエラーを意識してリカバリするので竹プランです。

f:id:ninjinkun:20111223100350j:plain

Instagram

アップロードキューがあり、失敗するとそこに失敗が表示されます。リカバリボタンで再投稿、諦めて削除が選べます。竹プランです。複数の写真が失敗しても、個別にリカバリできるのがポイント高いです。リッチですね。

f:id:ninjinkun:20111223104704j:plainf:id:ninjinkun:20111223105549j:plain

Path

驚きです。Pathはネットワークがない状態でも、通常と同じようにPOSTに成功したように見えます。写真はタイムラインに表示され、問題なく処理が継続されます。注意深く見ていましたが、アプリがアクティブな状態でネットワーク接続が回復すると、投稿が自動的に行われます。複数枚の写真を投稿しても問題ないです。POSTというよりはタイムラインの双方向同期のような動き方をします。つまりPathの世界では通信が不可能な状態はエラーではないと言えます。これを実装するのはアプリの内部モデルとサーバーのデータを同期する必要があって相当面倒なはず。天晴と言うしか無いですね。文句なしの松プランです。

f:id:ninjinkun:20111223095534j:plainf:id:ninjinkun:20111223095613j:plain

ネイバーフォトアルバム

国産アプリの例です。アップロードキューが実装されており、複数枚写真のアップロードに失敗しても、個別にリカバリをすることができます。竹プランですね。リッチな作りです。

f:id:ninjinkun:20111223113745j:plainf:id:ninjinkun:20111223114014j:plain

f:id:ninjinkun:20111223113749j:plain

エラー処理の実装

さて、次はこれらの処理を実装する場合を考えてみたいと思います。松プラン難しそうなので、竹プランで考えてみましょう。

iPhoneのエラー処理に使われるオブジェクトにNSExeptionとNSErrorがあります。NSExeptionは例外を通知する際に使われるオブジェクトです。try{}catch(NSExeption *e){}の文脈で使われます。NSExeptionはコード内部での例外を通知するのに使われるので、ユーザー体験に影響を及ぼすところで使うことは想定されていません。また、iOSの例外処理はJavaなどとは違い頻繁にExeptionを投げるような設計にはなっていません。

例外が発生するのはライブラリが想定外の使い方をされている、使い方が間違っている場合がほとんどです。まずはコードを修正して、発生しないようにできないかを検討してみましょう。通信エラーのエラー処理ではNSExeptionに出会うことはほとんどありません。もし例外の発生をリカバリできないようであれば、次のNSErrorに繋げるコードを書くことになります。

ユーザーにエラーを通知する場合はNSEerrorを使います。NSErrorはNSAlertViewというMacOSXでのエラーダイアログにそのまま使える構造になっています。iOSのUIAlertViewはNSErrorを直接渡すようなことはできませんが、似たようなノリで使うことができます。NSErrorのプロパティを覗いてみましょう。

  • -(NSSttring *)domain
    • エラードメインを定義します
    • システムで用意されたドメインの他にユーザー定義のドメインを使うことも出来ます
  • -(int)code
    • エラーの種類を表すコードです
    • ユーザー定義ドメインの場合はまた独自に定義します 
  • -(NSSttring *)description
    • エラーの概要を説明する文章を入れます
  • -(NSSttring *)reason
    • エラーの原因を説明する文章を入れます
  • -(NSDictionary *)userInfo
    • エラーの付随情報を格納するNSDictionaryです
    • ユーザーにエラーを表示する際にはこの中の値が重要になります
  • -(NSSttring *)localizedDescription
    • 翻訳されたエラーの概要です
    • userInfoに格納されたNSLocalizedDescriptionKeyの値へのショートカットになります
  • -(NSSttring *)localizedFailureReason
    • 翻訳されたエラーの理由です
    • userInfoに格納されたNSLocalizedFailureReasonErrorKeyの値へのショートカットになります
  • -(NSSttring *)localizedRecoverySuggestion
    • 翻訳されたエラーを回復する手段の説明です
    • userInfoに格納されたNSLocalizedRecoverySuggestionErrorKeyの値へのショートカットになります
  • -(NSSttring *)localizedRecoveryOptions
    • 翻訳されたエラーを回復するための選択肢です
    • ボタンのタイトルに使われることを想定しています
    • ボタンのタイトルをNSArrayに格納します
    • userInfoに格納されたNSLocalizedRecoveryOptionsErrorKeyの値へのショートカットになります
  • -(id)recoveryAttempter 
    • エラーを回復するために使うオブジェクトです。
    • 上のRecoveryOptionsでリカバリを選択した場合はこのオブジェクトに何かを通知するような設計にするのかな(よくわからない)
  • -(NSString *)helpAnchor;
    • ヘルプへの導線です(これもよくわからない)

 エラー通知に使える値がいろいろと格納されていることがわかります。この値を使ってUIAlertViewを作ってみると、以下のようになります。

f:id:ninjinkun:20111223223523p:plain

このアラートを生成するためにUIAlertViewを少し拡張します。

@implementation UIAlertView (NSError)
-(id)initWithError:(NSError *)error {
    self = [super init];
    if (self) {
        self.title = [error localizedDescription];
        self.message = [[NSArray arrayWithObjects:[error localizedFailureReason], [error localizedRecoverySuggestion], nil] componentsJoinedByString:@"\n"];
        NSArray* optionTitles = [error localizedRecoveryOptions];
        for (NSString *title in optionTitles) {
            [self addButtonWithTitle:title];
        }
    }
    return self;
}
@end

そしてもちろん、このアラートからもう一度再投稿処理を行うために、POST時にリクエストを保存しておく仕組みも必要になります。そのあたりはだいぶ複雑なコードになりますし、実装ごとにだいぶ変わって来ると思うので(タイムリミットも迫ってきたので)しりすぼみな感じですが割愛します。

おわりに

エラー処理とそのフィードバック、そしてリカバリはユーザー体験に大きな影響を与えます。良くできているアプリは細部に凝っているものです。最後の完成度を上げるために、がんばってリッチなエラー処理にトライしてみましょう!

2011-11-19

iOSとAutomatic Reference Countingについて発表しました

第41回Cocoa関西でAutomatic Reference Countingについて発表しました。資料は以下です。発表時はBlocksの仕様の理解などで怪しい部分があって申し訳なかったです。一応この資料は大丈夫だと思います。
 
会場で聞いた範囲では、ARCをプロダクションで採用している方はまだいない感じでした。