About me

GitHub Twitter Presentations Qiita

Recent Posts

    Heartless code review

    Sat, Aug 15, 2015
    I talked about code review at potatotips #20. Sometimes I think that code review is not only for code but also for human. If bots can review code completely, reviewing code by human has value. My FindBugs’ setting is below. // FindBugs - Gradle DSL Version 2.5 https://docs.gradle.org/current/dsl/org.gradle.api.plugins.quality.FindBugs.html apply plugin: 'findbugs' task findbugs(type: FindBugs, dependsOn: assembleDebug) { description 'Run findbugs' group 'verification' classes = fileTree(dir: rootProject.projectDir, includes: ['*/build/intermediates/classes/**/*.class'], exclude: '**/*test*/**')

    イタリアに行ってきた

    Thu, Apr 30, 2015
    1週間ほどイタリアに行ってきた記録です。 ミラノ ミラノは北イタリアの首都呼ばれる二番目に大きな都市らしい。 とにかく観光客が多く、アジア人もたくさんいたため外国感があまりなかった。 後日、友人に写真を見せたらディズニーランドみたいと言われた。たしかに。 僕は人が少ないところの方が好きなので、ミラノ滞在中は食事以外はホテルでコードを書いていたので、街の印象があまり心に残っていない。 食事は高かったが美味しかった。 トリノ 今回の出張の目的であるカンファレンスのためにトリノに移動した。 移動中窓からアルプス山脈が見えるのが良かった。 トリノは観光客もそんなに多くなく、のどかで良い街だった。 至る所にジャラート屋があったので、街をふらふら歩きながらジェラートを食べていた。 イベントだとヨーロッパ各地から人が集まってくるから当然イベントは英語で行われて、学部卒業程度の教育を受けていれば英語が話せて当然という感じだった。 観光地だとホテルでもレストランでも英語が通じて困らなかった。 でも現地の言葉を覚えると馴染んでる感が出て良い、店員さんも心なしかちょっと優しく接してくれるようになる。 あと、スペイン語とイタリア語は似ていて便利っぽいということが分かった。 スペイン語勉強してポルトガル語やイタリア語話者ともコミュニケーション取れるようになると便利だと思う。

    インドネシアに行ってきた

    Wed, Apr 29, 2015
    1ヶ月ほどインドネシアに行ってきた記録です。 街 スカルノハッタ国際空港からジャカルタの中心地までは遠く、また電車は中心地の短い区間に一本走っているだけなので、タクシーで移動した。 青いタクシー以外は乗らない方が言われていたので、滞在中は青いタクシーだけを使っていた。青いタクシー以外に乗るとどうなるのかは分からない。 街の雰囲気は、今まで行ったことのない雰囲気で新鮮だった。 道端では数十円、数百円の服や食べ物を売っているかと思えば、富裕層向けのデパートでは数万円の服が売っていたりレストランがあって、生活水準のギャップが大きかった。 また、あちこちで工事していて街全体が今まさに成長しているという印象を受けた。 気温は年間を通して28度くらいで、1月だったが海に行ったら普通に泳いでいた。 11月から3月は雨季で、そのため滞在日数の半分くらいは雨が降っていて、道路が氾濫して出社できなくなってホテルで仕事をすることも結構あった。 そんなとき子供たちはジャバジャバ外で楽しそうに泳いでいた。 滞在中2回お腹を壊し38度の熱が出て病院でぐったりしていた。現地の食事に慣れていない + 雨季でリスクが高かったとのことだけど、詳しいことは分からなかった。 医療費は10万円くらいかかったと思うのだけど、保険に入っていたので無料だった。 食 17000の島々からなり、330以上の民族がいるらしい。 そのため食文化も多様で、たとえばJava島の食事は甘く、Lombok島の食事は辛いなどの違いがあった。 生きている魚を手づかみでレジに持っていくレストランは勢いがあった。 ジャカルタには日系企業が多くあるので日本の某カレー屋、某うどん屋、某ラーメン屋などがあり、そこまで日本の食事が恋しくなったりはあまりしなかった。 あとヨーロッパにはコンビニはないけど、日本の影響かインドネシアにはコンビニがたくさんあって、実際便利だった。 私が病院に運ばれたのは屋台の水が原因だったらしいが、屋台は安くて美味しかった。 その他 たぶん8、9割の人がAndroidを使っていた。 日本には売っていないようなローエンドの端末と、厳しい通信環境が相まってどのサービスを使うにしろ厳しいという感じだった。 伝聞ではなく実際に体験すると感じるところがある。

    スペインに行ってきた

    Wed, Dec 24, 2014
    1ヶ月ほどスペインに行ってきた記録です。 街 スペインの中でもリゾート地っぽいところだったのでビーチ、港、カジノ、城という感じだった。 また、近くにヌーディストビーチがあったのだけど、あいにく冬は日本と同じくらい寒いので、誰も泳いでいなかった。夏にまたおいでと言われた。 その代わりクリスマスシーズンだったので、スペインのクリスマスを見ることができた。 まあ、街がイルミネーションで飾られたり、クリスマスソングが流れてたりと、あまり日本と変わらないと思ったのだけど、スペインでは法律か何かで日曜に働くことが禁止されているので、休日に店が空いてるというのが特別なことらしい。 食 精肉店や市場やスーパーに通って人々の生活を見つつ、その土地の食材を使って料理をした。 食べ物が口に合わないということはなかった。ビールは水より安かった。 滞在していたアリカンテはビーチ、遺跡、カジノがあるリゾート地でありながら、そこまで人も多くなくのんびり過ごすにはとても良い街だと思った。

    嵐山とか見た

    Sun, Aug 24, 2014
    京都の嵐山に行ってきた。 雨が降っていたが、寺とか庭とかは雨が降ってると趣が増すので良い。 言の葉の庭の影響かもしれない。 駅周辺は人がたくさんいたけど、ちょっと奥まった寺とかに行くと人が少なくて良かった。 京都Android勉強会というはてな主催の勉強会に参加するという目的があって京都に行ったのだけど、そのことはまた別の形で書きたい。 そういうことで3日京都に滞在して、うち2日ははてな社の人と飲んでいた。 はてなの人のはてなっぽさはどこから来ているのだろうかと前々から気になっていたので色々話を聞いていたけど、結局よく分からなかった。 でもその中で @cockscomb さんが「技術力がないのに奇行に走ってはいけない」と言ってたのが印象に残った。 途中から酔っ払ったひとでくんさんがやってきて、cockscombさんの足をホールドして動かなくなったりしてて、端から見ると30近いおっさんが30近いおっさんの足に掴まってて最悪な感じがするけど、ひとでくんさんは技術力があるし、はてなの取り組みは僕もよく参考にさせてもらっている。 狂気と情熱は似ていて、それが開発の原動力だったりするのだろうと思う。 しかし、端から見ると狂気だけが目立つので、おかしなことをしてれば最高みたいな雰囲気が若者に広がっていくのはよろしくないし、やはり技術力は大切だということを再認識した。

    サンフランシスコの写真 + 知見

    Sun, Jun 29, 2014
    先週の月曜から日曜までGoogle I/Oでサンフランシスコに行ってました。 発表の所感 Googleのプラットフォームをあらゆるところに浸透させる (Android of Things) のに力を入れている印象を受けた そのためのMaterial Design そのためのパフォーマンス改善 そのためのジャバ (write once run なんとか) 数年前にGoogle App Engineを触って以来でクラウドはあまりウォッチしてなかったけど良さそうだったので使ってみたい Netflixも使ってた: Netflix Lipstick on Google Compute Engine — Google Cloud Platform Google Cloud PlatformはIDEに統合されていくだろうし、強いインフラの上にプラットフォームを持ってる強みがあるから一気に普及ワンチャンあるかも {% oembed https://twitter.com/rejasupotaro/status/482398332170424320 %} 各発表内容の詳細は別のところで書くか、報告会をやるかもしれません。 滞在の知見 はじめてのGoogle I/Oだったので学びが多かった。次回に活かしたい。 宿 Moscone Centerから徒歩5分のホテル予約できたけど、近いと忘れ物を取りに帰れたりなにかと便利だった 当選が決まったらすぐ宿を探した方がいい、Expediaが一番安くてアプリと連携できるので便利だった 部屋ごとのチャージなのでツインルームにエクストラベッド置かせてもらって複数人で泊まると安い 持ち物 服を一週間分持っていったけど、イベントでもらったりしてどんどん増えて荷物が入らなくなって他の人に入れてもらったりしたので、服はなかったら現地で買うので良かった クレジットカードなくすの怖かったので持っていかなかったら、まさかのGoogle Glassが現地で売られてたのだけどお金足りなくて悔しかった。次回はクレカ持っていきたい ノートPCは盗まれると困るので常に持ち歩いてたけど重いし、ネット環境もあまり良くなくてたいした作業もできなかったので次回は持っていかない インターネット 現地でプリペイドSIMを買うのは契約内容を読んだり説明したりするのハードル高い思ってたけど、一言二言で買えて簡単だった。空港到着後即インターネット吸えて良かった 会場のwifiは混み合っててビルドに40分かかって辛かった。場所によっては激速だったりしたので、SDKはそういう場所で落とすのがいい 英語 中学レベルの英語でOKみたいな記事読んで安心してたけど、それでは不十分だった 行って帰るだけなら中学レベルで問題ないけど、現地のエンジニアや参加者と情報交換したり、議論をしたりするには中学レベルじゃ足りない スケジュール セッションでびっしり予定を埋めてたけど、どうしても見たいもの以外は空けてた方がいい セッションを見るのは日本でもできるし、日本の方がネット環境良くて調べもの捗る 現地に行くならコードラボに行ったり、UXレビュー受けたり、世界中のエンジニアが集まってるんだから情報交換した方がいい Google I/O前後のイベントをチェックしておくといい 事前登録がないと入れないイベントもある Intelのイベントに行ったら8インチのハイスペックタブレットがもらえて最高だった Keynoteを見るなら朝7時にから並んだ方がいい アーリーチェックインもした方がいいので数日前にサンフランシスコに到着していたい (当日の朝にチェックインするとかなり後ろの方に並ぶことになってKeynoteの序盤は聴けない) 移動 空港は2時間前に着くように予定を組むとちょうど良くなる

    関数型言語を学ぶことは実務でどう役に立ったか

    Sun, May 11, 2014
    関数型LT大会で「実社会の問題を解決する関数型言語」というタイトルで発表しました。 というのも、会社で「すごいHaskellたのしく学ぼう!」の輪読会をしていて、最初こそ10人以上の人が参加していたのだけど、章が進むごとにどんどん人が離脱していって、主催者としてはなんとか完走したいという思いがあったので、調べたのですが、 ヒアリングから、この二つの線がクロスしたときに、人は離脱するという知見が得られました。 ということで、Haskellに対して実用性を見出したいと思いながら半年を過ごしたのですが、実用的 = 仕事で使うということであれば、今の現場でHaskellに移行するのは現実的ではありません。 でも、Haskellには関数型言語のエッセンスが詰まっていて学びが多かったと思っていて、直接的には使っていないけど、概念として役立つことがあると思ったので、それを伝えるために今回文章に起こしました。 実用性と言ったけど、何が実用的かは立場によって異なっていて、ここでの実用性とは一般的なWeb企業の話です。 NetflixのAPIの最適化 NetflixのAPIの最適化についての記事(Optimizing the Netflix API)がまさにそれで、多くのWeb企業でREST APIのクライアントから見たときの効率の悪さには頭を悩ましていると思うのだけど、それをいかにして最適化したのかと、後日その記事のフォローで、具体的なサーバの実装について解説した記事(Functional Reactive in the Netflix API with RxJava)がまさに好例だなと思って、この話をしました。 APIの最適化のために、スレッドセーフにしつつ時には同期させたりしながら並列でリクエストを送る低レベルなスレッド操作を、シンプルに表現できるようにする必要があって、そこでNetflixではFRP(Functional Reactive Programming)のアプローチを取っていました。 FRPとは Behaviorの例 マウスの座標 日照によって変化するボンネットの温度 振り子運動をしているブランコの速度 刻々と変化する株価 Eventの例(時間と値が組になったストリーム) キーを押した時刻tと、どのキーかを表すcを組にした(t, c) マウスをクリックするごとに発生するEvent ボンネットの温度が5度上がる毎に発生するEvent ブランコの速度が0になるたびに発生するEvent 株式市場で取引の開始・終了を知らせるEvent 応用先 イベントドリブンなコードで処理がぶつ切りになったりコールバック地獄になるのを避ける アニメーションやコンピュータミュージックのシグナル処理を自然に書けるようにする LINQ Excel Haskell界では10年以上前からFRPに関する研究が続けられているようです。 実装ではMicrosoftがOSSで開発しているRx(Reactive Extensions)が有名で、そのNetflixがそのJava版であるRxJavaを開発しています。 複雑なGUIの世界を完結に表現したい 今度はサーバ側ではなく、クライアントでの具体的な実装例を紹介します。 下の画像はシンプルなメッセージングアプリのスクリーンショットです。 仕様を書き出すと、次のようになります。 一見シンプルに見えるアプリですが、以外と複雑ですね。 画面内の見えている要素はどこかの要素の状態に依存していて、しかもアプリやシステムが非同期で各要素の状態を更新する、ということはアプリではよくあります。 そのため、画面のある一部を変更したいだけなのに依存性を検証してあちこちのイベントを貼り直したりして、そして保守しにくいコードへ…という問題が起こります。 FRPのライブラリの多くは、MicrosoftのReactive Extensionsから派生していますが、RxではBehaiviorはObservableというクラスで表現されています。 Instead of blocking APIs ... class VideoService { def VideoList getPersonalizedListOfMovies(userId); def VideoBookmark getBookmark(userId, videoId); def VideoRating getRating(userId, videoId); def VideoMetadata getMetadata(videoId); } ...

    Android StudioでのLombokの導入手順と対応状況

    Wed, Apr 30, 2014
    Lombokとは Very spicy additions to the Java programming language. ★ ビルド時にAST変換をしてメソッドを生やしたり後処理を追加したり、便利なコードを自動生成する(ソースコードを書き出すのではなく生成されるバイナリを書き換える)ライブラリです。 導入手順 1. build.gradleのdependenciesに追加します provided 'org.projectlombok:lombok:1.12.2' 2. Preferences > Plugins > Browse Repositories > Lombok Plugin をインストールします プラグインがなくてもビルドはできますが、入れないと警告が出たり定義にジャンプしたりできないので入れます。 Androidアプリ開発で使えそうなもの(行数は目安です) @Data Getter、Setter、ConstructorおよびtoString、equals、hashCodeの自動生成を行う ビルド前(5行) @Data public class DataExample { private final String name; @Setter(AccessLevel.PACKAGE) private int age; } ビルド後(45行) public class DataExample { private final String name; private int age; public DataExample(String name) { this.name = name; } public String getName() { return this.name; } void setAge(int age) { this.age = age; } public int getAge() { return this.age; } @Override public String toString() { return "DataExample(" + this.getName() + ", " + this.getAge() + ")"; } @Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof DataExample)) return false; DataExample other = (DataExample) o; if (!other.canEqual((Object)this)) return false; if (this.getName() == null ?

    AndroidのCIに纏わる諸々の問題

    Sat, Dec 14, 2013
    この投稿はAndroid Advent Calendar 2013の14日目の記事です。 昨日、Android Test Casual Talks #1というイベントがありました。 僕もテストについて何か話す予定だったのですが、残念ながら体調不良のため行けませんでした。 それで、ハッシュタグを追って見ていたのですが、現場に入ったときにAndroidにテストを書く文化がなくて驚いたという話がありましたが、今やその状況もだいぶ変わってきていて、会場にいた人の80%の人がJenkinsを導入しているというのはちょっとすごいなと思いました。 さて、そんなJenkinsですが、弊社では運用についていくつかの悩みを抱えています。 その悩みと考えている解決策を公開することによって、意見交換したり、何かの参考になればいいなと思います。 Jenkins、ビルドの設定 弊社のAndroidのJenkinsはawsでここの1スレーブとして動いています。 ビルドにはgradleを使っていて、以下の設定で種類ごとにbuildを行なっています。 buildTypes { debug { debuggable true runProguard false ... } beta { debuggable true runProguard true ... } release { debuggable false runProguard true ... } } productFlavors { staging {} product {} } また、gradleはdaemon起動しています。 ライブラリはs3に認証付きでホストしています。署名の情報もそうですが、キーとシークレットはリポジトリに含められないので、Google Driveに置いて開発者に権限を付与してスクリプトで取得するようにしています。 repositories { mavenCentral() maven { url "https://${project.s3Bucket}.s3.amazonaws.com/release" credentials { username project.s3Key password project.s3Secret } } } 実際のジョブの内容は StagingBetaをassembleする StagingBetaをconnectedInstrumentTestする Lintを走らせる ProductBetaをassembleする DeployGateでProductBetaを配信する HipChatにビルド結果を通知する というようになっています。 悩み1.

    ActiveAndroidの初期化時間を4分の1にする

    Thu, Dec 5, 2013
    ActiveAndroidとは ActiveAndroidとは、アクティブレコードパターンのAndroidのORMです。 こういうクエリーがあったら INSERT INTO Items(id, name) VALUES(NULL, 'My Item'); こう書けます。 Item item = new Item(); item.name = "My Item"; item.save(); セレクトするときにこうしていたのは、 SELECT * FROM Items; このようになります。 new Select().from(Item.class).execute(); ※公式ドキュメントより DBの接続もテーブルの作成もマイグレーションも、なんでもActiveAndroidが面倒を見てくれます! ん?今なんでもっていったよね? 初期化と破棄 public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); ActiveAndroid.initialize(this); // ここでなんでもします! } @Override public void onTerminate() { super.onTerminate(); ActiveAndroid.dispose(); } } ※公式ドキュメントより ボトルネックを探す Traceviewで表示してみる。 Invocation Countが1でInclusive Timeの80.1%を持っていっている ModelInfo#scanForModel が重いのでソースを見る。 private void scanForModel(Context context) throws IOException { String packageName = context.getPackageName(); String sourcePath = context.getApplicationInfo().sourceDir; List<String> paths = new ArrayList<String>(); if (sourcePath != null && !(new File(sourcePath).isDirectory())) { DexFile dexfile = new DexFile(sourcePath); Enumeration<String> entries = dexfile.entries(); while (entries.hasMoreElements()) { paths.add(entries.nextElement()); } } // Robolectric fallback else { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Enumeration<URL> resources = classLoader.getResources(""); while (resources.hasMoreElements()) { String path = resources.nextElement().getFile(); if (path.contains("bin") || path.contains("classes")) { paths.add(path); } } } for (String path : paths) { File file = new File(path); scanForModelClasses(file, packageName, context.getClassLoader()); } } private void scanForModelClasses(File path, String packageName, ClassLoader classLoader) { if (path.isDirectory()) { for (File file : path.listFiles()) { scanForModelClasses(file, packageName, classLoader); } } else { String className = path.getName(); // Robolectric fallback if (!path.getPath().equals(className)) { className = path.getPath(); if (className.endsWith(".class")) { className = className.substring(0, className.length() - 6); } else { return; } className = className.replace("/", "."); int packageNameIndex = className.lastIndexOf(packageName); if (packageNameIndex < 0) { return; } className = className.substring(packageNameIndex); } try { Class<?> discoveredClass = Class.forName(className, false, classLoader); if (ReflectionUtils.isModel(discoveredClass)) { @SuppressWarnings("unchecked") Class<?