shibuya.apk主催のGoogleI/O 2018報告会にいってきた

まぁなんとかやってます


久々にブログ書きます。
というか、勉強会も行ってきたの久しぶりかもしれない。。。
という訳なので、勉強会で取ったメモメモ (資料はどこかに上がってる)

Slices氏


資料

  • (端末の検索)検索結果の中に自分のアプリのアクションを出せる
  • push通知とかホームスクリーンで出せるようになる

  • 確認用のアプリがあるので、エミュレータで専用のアプリを必要

  • 4.4以上

  • SliceManager #<= 作れるけどあんまりないと思う

  • SliceProvider #<= 実装は大体こっち

  • manifestにproviderタグ

  • contentproviderを継承したもの
  • builderpatternで色々設定
  • sliceaction(実際はpendingintentみたいなもの)
  • sliceviewで画面

  • adb shellで動作検証する

  • 初回だけパーミッション確認ある

  • manifestに書くのはcontentprovider

  • authoritiesは後々に重要になる

  • contentprovider(sliceprovider)

  • onBindingSliceが重要
  • 中で実装したパスによって動きが変わる
  • authoritiesはここで使う
  • builderはここで実装
  • slice-content:///<provider定義のpath>でadb起動
  • sliceactionで起動したいintentとか

  • 動的に更新もできる

  • contentresolver.notifyChangeにsliceのuriを設定すればOK

Android Test は “Write once, run everywhere.” の夢を見るか


資料

  • robolectricとinstrumentedテストのAPIが似てたので統一された
  • instrumentedテストのAPIがローカルで動く(robolectricが必要)
  • テストの実行方法も統一したい = nitrogen pj
  • flavorとかリセットとかその他辛いので、実行環境を抽象化とかしたもの
  • googleのサポートの信頼性は高い(リリースはまだされてない)

Android App Bundle


  • 5.0以上でsplit apk
  • base apk, configuration apk, dynamic featureapk
  • base apkは基本機能でユーザーが最初にインストールするもの
  • configuration apkは特定の画面サイズとか言語のネイティブコードとか
  • gradleでbundleセクションでlanguageとかdensityとか設定する
  • dynamic feature apkは初回に必要にないものすべて
  • manifestでmodukeを設定
  • 4.4以下では、dist:fusing=true
  • dependencyにbaseを設定する
  • base側はdynamicを読む設定を入れる
  • base側にはmoduleをインストールする実装が必要><
  • 端末に合わせたアプリにできるようになる
  • 最適化されてるので小型のアプリにできる
  • 後から追加してもいいものが対象
  • cliではbase:bundleみたいなのを打つといい
  • play consoleのアップロードはちょっと面倒
  • 100MBとかbata program登録
  • play側の署名できるようにしておく
  • bundleツールでローカルテスト
  • bundletoolsでインストールとか端末設定抽出とかして自動で個別設定いれる
  • 端末設定を変更すると追加の設定がインストールされる
  • playが古いと4.4以前と変わらない動きになることに注意
  • dynamic feature modukeは大規模でないと実装コスパが悪そうだけどモジュール化は重要かも

Material Components


  • materail theme editor = skitch plugin
  • material components = 新しいsupport design library
  • designライブラリにあったものは全部同梱されている(名前が変わったものがあるCardとか)
  • chips = gmailとか送信とかにでてくる小さいタグっぽいview
  • textfieldもアウトラインとか縁が簡単に囲まれたものができる

RuubyKaigi2017に参加してきた

はじめに


Rubykaigi2017に参加してきましたので、メモを共有しておきます

Keynote


Nobuさんの発表

  • ゆるふわRuby生活
    • デバッグ
    • 新機能
    • バグ作成
  • リポジトリ
    • Rubyのgithubはミラーなのであんまり見ない
    • 移行コスト(svn to git)
    • hashが明確でない(リビジョン番号と比較して)
    • gitがwindows非サポート
  • issue
    • redmine
    • mailinglist
  • meeting
    • (物理で会う場合)バグチケットの棚卸し
  • build
    • out-of-place-build
      • configureのオプション
    • baseruby
      • ソース生成したりなど
    • miniruby
      • ビルド時の中間生成物
      • 拡張ライブラリ
      • 共有ライブラリの非サポート
        • 単独で動かせる
        • エンコードが固定
        • 共有ライブラリの機能が無理
    • extconfのビルドが遅い
      • 別プロセスでビルドするようにした(2.5以降)
        • 依存関係がなければ
    • ヘッダーや共有ライブラリの位置
    • trace_var
      • ビルド時に変数の代わり内容をhookする
  • bug?
1
2
p = 2
p (-1.3).abs #=> 1.3
  • カッコの前にspaceを置く
  • キーワード引数の名前を内部的にはラベルと呼称
  • parse_ident()
    • 小文字で始まってるか識別する
  • lavr_ident
    • 既に定義済みかチェック
  • lvar_definedを外せば多分意図通りになって直るけど・・・
  • string.intern(symbol作成)の再定義するとsymbolにならない
    • :”#{aaa}”みたいな書き方で、refineでstring.internを上書きしたのだとsymbolにならない
  • 2.5にnew featureはないのか?
    • rescure inside do-end
    • hash,transform_keys
  • 議論中
    • メソッドオブジェクトを作るためのメソッドみたいなのは議論中
    • 右代入(rightward assignment)

Fiber in the 10th year


ko1さんの発表

  • suspend/continueはprocはできないけどfiberならできる
  • Fiberの応用
    • 使うところ
      • ブロックの仲で繰り返す
      • ブロックの外で制御
    • ゲームのキャラクタごとにパラメータ制御
    • IOscheduler(none-blockingio)
      • timerがない
      • ioblockingでも切り替え無し
      • 共有データの同期処理を書く必要がおそらく無い
  • 当初、Fiberは任意のFiberに処理を渡すpassというAPIだけを持っていた(coroutineだった)。
  • coroutineは強すぎて管理が難しい。
  • contextの切替
    • thread state
    • vm stack
    • machine stack
  • 昔はコピー
    • コードを参考にできた
    • 殆どの環境で使える
    • スタックが深いと領域が必要で時間かかる
  • その次
    • nativeのスタック領域を使うように
    • ポインター切替で実行
      • 5%早くなった
      • 30%メモリ消費減った(但し、局所的)
  • autofiber
    • 既存コード変更不要
    • blockimgioを勝手に切り替える(ioblockのみ)
    • fiberの指定不要
    • 同期処理を書く必要が出て来る

How Close is Ruby 3x3 For Production Web Apps?


Noah Gibbsさんの発表

  • Real Web Appsはproductionで人々に使われていることで、fasterはベンチマークテスト結果を改善
  • くりかえしすることを実行
  • 通常アクションを記録
  • optcarrotでwarmup
  • discurseで採取(https://github.com/discourse/discourse)
  • Ruby2.0.0からRuby2.4.1で速度はどうなったか。途中でDiscourse自体がv1.5からv1.8に変わってしまったが、同バージョンの中ではRuby Versionが上がるにつれて着実に改善
  • DiscourseでのベンチマークではRuby2.0.0 -> Ruby 2.4.1にかけて150%ほど速くなっている
  • ウォームアップについて。MRIでもwarmupについれてスループットが改善する。どのRubyバージョンでも同程度。5000
  • warmup iterationで5-7%程度の改善。
  • firstrequestは2.0.0に比較して30%確実に早くなている
  • https://github.com/noahgibbs/rails_ruby_bench
  • https://docs.google.com/presentation/d/1tUQpblTufP0IWiZSfnky56y9WvYeqMQF9ve45yIcpYY/edit

Gemification for Ruby 2.5/3.0


hsbtさんの発表

  • 現状と展望について
    • raa
    • rubyforge
    • gems.github.com
    • gemcutter.org
    • rubygems.org
    • bundler <= イマココ
  • 標準添付ライブラリ
    • requireしなくても使えるもの
    • standard libraries
      • svnと一致しているもの
    • default gems
      • rubyと一致orメンテナがリリース
    • bundled gems
      • メンテナがリリース
  • default gems
    • openssl
      • githubで開発
      • あるタイミングでsvn側に取り込み
      • rubyのバージョン違っていても、使える
    • psych
      • jruby/crubyの互換性確保
    • rdoc
  • bundledgems
    • testunit/minitest
    • ビルド時にinstallするもの
    • rake
      • 標準添付する必要があんまりないので
    • デメリット
      • 開発中のrubyでbundledgemsが動くかも保証もできない
  • gemfication
    • standaradのもをgemで配布していく
    • 標準添付ライブラリをgemとして切り出していく
    • 2.5,2.6で追加したものを2.4でも使える可能性ある
  • 問題
    • 標準添付ライブラリ間の依存関係
    • バックポートによるメンテナの負担がヤバイ
    • メンテナが古いのでも使えうように頑張る必要でてくる
      • 1.8.7のサポート対応
  • rubygems/rubygems.org
    • サイト
  • rubygems/rubygems
    • ライブラリ周り(bundlerチーム)
  • rubyfication
    • rubygems上に名前空間周りでバッティングして調整して上書き
  • 3.0へ向けて
    • bundlerはデフォルトgemになる
    • 標準添付は全てgemにしておきたい
    • 標準ライブラリのバージョン周りでもしかしたらバージョンの不具合起きるかも
    • Bundler がないと RubyGems 2.7 の動きが怪しい

Development of Data Science Ecosystem for Ruby


mrknさんの発表

  • 現在
    • Rubyだけで頑張る方法
      • データ処理部分
    • 併用する方法
      • メイン処理に関わる箇所でmデータの受け渡し処理
      • 2重変更が必要(データ処理とメイン処理)
      • pythonやrを呼び出すとデータ交換コストが高く、データ形式の変更時などは両方に変更が必要
    • rubyからpythonを呼び出す方法
    • rails上でpandasで表示
      • パフォーマンスに問題ありそうだけど、pandas呼べてる
    • rubyからpythonを呼び出すことに不自然ではない
      • 先入観では?
      • RPy2みたいなものも存在している
        • 大体のことがPythonでできるから、Pythonになっている
    • issue登録が欲しい
  • 将来への展望
    • 未来を見据えてPycallでないようにしたい
    • 一つの言語では完結しない
      • pysparとはいえ、spark自信はscala,java
    • apache arrowを例にとっても、bindingを作っておけば将来apache arrowが流行れば使われるようになる
    • red data toolsに参加してもらいたい
    • pycallにissue/prが欲しい

Ruby Committers vs the World


  • 型注釈、結局コミッターはどう思ってるのか?
    • 全体的に「別にあってもいいんじゃないの」って空気感
  • 右代入?
    • matz右代入ありなんだけど、いい記号がない。。。

keynote


Matzによるkeynote

  • 言語愛が最大の要因
  • プログラミング言語面白い
  • 例外なくプログラミング言語が好き
  • 他の言語を貶めることは無い
  • simula(一番最初と言われるオブジェクト指向言語)
    • inheritance
    • 差分プログラミング
  • simulaからではなくlisp, smalltalkから影響を受けているのでsimulaから直接ではない
  • super classは2つでは?
  • roleは複数持ってるのでは?
  • 単一継承ではなく多重継承
    • Lisp(flavors)の世界から
    • 自然な拡張だが、複雑化しやすい
      • daiamond継承など
      • c3 linialization algorizm(線形化アルゴリズムで、継承順序を決定する)
  • mix-in
    • lisp内ではflavorsと呼ばれる
      • バニラアイスに、チョコチップやミントの味を追加するみたいな意味
        • アイスクリームはインスタンスにできるが、チョコチップはできない
        • 混ぜた味(ミントアイスクリーム)はインスタンスにできる
    • モジュールはmixinの単位
    • Rubyではグループ分けの単位として使われてる
      • Net::HTTPのNetなど
    • singletonとしても使われている
      • FileUtilsなど
    • メソッドや機能の集まりとして使われている
      • Mathモジュールなど
        • includeすると直接使えるようになる(モジュールファンクション)
        • メソッドをコピーしてオブジェクトに注入
    • メソッド結合としての単位
      • alias method chain
        • メソッドの別名をつけて、置き換えることができる
      • module prepend
        • dynamicに変更することができなくなる
      • 最初は入れる気がなかったが考える事で入れるようになった
        • lispのメソッドコンビネーション
        • classにおけるaround hook
        • aspect思考からも影響
    • refinement
      • open classの機能はあった
        • monkey patching機能(昔はgerilla -> gorilla -> monky)
        • ActiveSupport
      • グローバルに影響与える
        • selector namaspaceも候補にあった
        • usingを都度書く必要があるので、イマイチ使われていない?
      • スコープを区切ったmonkey patch
      • レキシカル
      • 使い方
        • C#のエクステンション
        • 既存のメソッドを置き換える
          • ローカル里バインディングがない
          • 想定外に置き換わることもない
    • structural signature
      • type check
        • Javaのインターフェースでは?
      • まだ導入されていない
  • performanace
    • Benchmark suite
    • MJIT
    • Rubex
  • concurrency
    • fiber
    • autofiber
    • guild
  • static analytics

An introduction and future of Ruby coverage library


mameさんの発表

  • 型システムだけではなくカバレッジ方面でも活躍していく
  • カバレッジ
    • コード
    • 未テストのコード検出
    • テストスイートの良さ体語
    • function coverage
      • 簡単可視化しやすい
      • 関数の中はみないので指標として弱い
    • line coverage <= Rubyはこちらのみサポート
      • 簡単可視化しやすい
      • 関数の中はみないので指標として弱い
      • 後置ifなど見落としやすい
    • branch coverage
      • 網羅的に検証できている
      • 可視化が難しい(多くのツールでサポートできてない)
      • 更に細かいcondition coverageがある
    • C0/C1/C2の指す内容については人によって異なる可能性あるので注意
  • 理解してつかっていくには
    • よいテストスイートは?
      • 仕様を満たしているかは取れない
        • 設計に対する網羅性はない
      • 間違えてたしてもテストコードがありカバレッジがあるとないとでは大違い
        • カバレッジは指標なので、100%を目指してもダメ
    • 未テストを理解
    • テストデザインを考える
      • 特に観点が重要
    • どれくらい網羅性があれば?
      • 重要なものに関しては100%を目指す(ぐらいの温度感)
      • 費用対効果も考慮に入れて考える
        • ioとかテストしにくいものは、割に合うか考えてやる
  • ライブラリの現状と展望
    • simplecov
      • coverage.soのラッパー
      • htmlで結果出力
      • テストの一番最初に呼ばないと、それ以前に呼ばれたものは測定対象にならないことに注意
      • 関数定義も実行対象になってしまうので、意味が無いことに注意(メソッドが呼ばれてない場合)
    • concov
      • 時系列カバレッジ
      • 追加されたコードに対してテストがされているかのチェック
    • other lang
      • C/c++
        • gcov/lcov
      • java
        • covertura emma, clover, jacoco
  • 今後の計画と展望
    • function / branch coveargeの測定追加
      • issueにコメント欲しい
      • 互換性を持って作っている
    • 100%既存に互換性
    • 他のcoverageツールも参考
      • lcovなど
    • overhead
      • 現状ruby本体だと5倍弱時間がかかる
      • railsだと2倍くらい?の見込み

workshop


前日のmrknさんが発表されていたPycallについてのworkshop
リポジトリはこちら
docker runをすることで、workshopの内容が出てきます

Ruby Language Server


mtsmfmさんの発表

  • lanugageserver
    • エディタの補完
    • メソッド定義
    • ビルド
    • languageserverプロトコル
    • ドキュメントの整形
  • 今までのものはエディタ向けのもの
    • viならvi, emacsならemacs
  • msが仕様を公開している
    • でもvsコードの拡張プラグイン向け
  • Languageserverprotocol
    • 汎用と専用がある
  • rubyで書くには?
    • 基本はnode
    • JSON-RPCでアクセスができればOK
      • 但し、クライアントがうまくサーバと通信できるようにする必要がある
    • gemでlanguage_server-protocolとして公開している
  • 内容
    • rocodetoolsで補完
      • 動的解析に利用、副作用とか到達不能な場合は無力
      • インスタンスレベルの補完はできてない(静的解析)
    • エラーメッセージは実行して(wcオプション)、正規表現で結果取得
  • 将来
    • 静的解析の改良
    • ドキュメント
    • rubocop
    • syntax highlight

Compacting GC in MRI


Aaronさんの発表

  • copy on write最適化
    • 性質や定義に注意
    • コピーしたものは、複製元のメモリ上の場所だけを持ってる
      • 配列も同じだが、hashはできない
      • コピー元に変更があったら、コピー先に掛かれる
      • プロセスforkだとコピーしない
      • Copy on Writeは何かの変更が起きない限り、コピーを作る必要はなく、必要になったときにはじめてコピーを作る
      • unicornは親プロセスをforkしている
        • unicornはforkして子プロスを立てるので、Railsが子プロセスで別々に読み込まれてつらい
        • 子プロセスは親プロセスのメモリを指してるのでメモリ使用量を減少させることができる
          • 子で書き込むとコピーされる
    • pagefault(共有メモリの変更が原因 => GC)
      • GCのobject allocationでpage faultが起きる。ruby objectのサイズはOSのpageよりも小さいので、object割り当てをするとページまるごとコピーされるし、無駄に使用量がどんどん増える
      • オブジェクトのサイズはページサイズより小さいので1オブジェクトの変更でも1ページ分のメモリコピーが行われて非効率
    • heap compaction
      • two finger compaction(単純なクイックソートアルゴリズム)
        • 欠点 ランダムに移動するので遅い
        • 利点 他のアルゴリズムよりに簡単に実装できる(下記の2つしかない)
          • オブジェクトの移動
          • 更新
  • gc
    • ヘルパー関数を用意した
    • 移動できないビットテーブル
    • rb_gc_mark
      • lowlevelでC拡張
    • GC.compaction
      • rb_gc_mark以外が対象
    • 難しいもの
      • hash key
      • 2重参照
      • global変数
      • rb_class_define
        • gcはglobal変数を変更することはできない
      • string literalの移動するとbytecode更新が続いているので対応が難しい
      • 結局、何も動かせていないような・・・
        • とはいえRailsでも46%程度削減できている
  • inspect memory
    • object_space.dump_all
      • rubyのメモリ
      • address: 位置
      • reference: 参照先メモリ
      • size: メモリサイズ
    • グラフを作成して変化を追ってみるといいかも tendorlover/heap-utils
    • spaps
    • pss
  • conclusion
    • プロダクションでテスト中
    • 小さいものでは全然効かない

Ruby for Distributed Storage System


tagomorisさんの発表

  • disk & networkioがボトルネックではなくなってきてる
    • storageは最近早いのでネックではない
    • networkはクラウド事業者のものが早い
  • disk/networkioには、serialization/deseriazationが走る
  • 分散ストレージの場合はさらにレプリケーションが発生する
    • 検証やネットワークioの非同期化
    • これらをこなすためのさらなるThreadなど
  • quoram
    • 最低2つのレプリカをできればよいというもの
      • 短いレイテンシ
        • 最後のレスポンスは無視する
      • 非同期処理のコストを下げる
  • bigdam(TD)
    • データ入力系(pipeline)の見直しのPJ名
      • 小さいデータから大きいものまで
    • 世界中に配備する
    • bigdam-pool
      • 分散key-value storage
      • buffer pool
        • S3は使わなくてもよいように
      • MB単位くらいをそうてい
      • 追記も可能にする
      • 同一データを書き込みできないようにしている
      • replicationもする
        • 無くなったデータの補充みたいなのは内
      • edge locationで一度受けて、center locationに置くうような仕組みを取ってる
  • design bigdom
    • mockから先につくたり、IFを全部先に用意
    • ここをRubyで実装
      • 柔軟なので、作って足りない場合に修正したりしてた
      • 手早く
    • integration /interface test
      • hashっぽいものを書くにはjavaは辛い
      • さっさとシリアライズ、デシリアライズでサクッと使えて嬉しい
      • Rubyだと型がないのでシリアライズ、デシリアライズが書きやすく、Mockやテストが書きやすかった。
  • bigdum-pool-ruby
    • java版と同じものを用意している
  • 非同期networkio
    • eventmachine
    • cool.io
    • celluloid::id
  • thread/timer
    • javaのほうが若干便利かも
    • executerservie(Java)
  • monitormixin
    • mutexと似ているもの
  • resourcecontrol
    • try-with-resourceがrubyにはない
    • begin_with_rescueが2.5から追加される
    • 型を混ぜてしまうこと(ArrayにIntegerやStringを混ぜるなど)
      • 多言語に対応させるときには・・・・
  • アプリケーションサーバ
    • Rubyだと基本webサーバしか・・・
    • ストレージで動かせるとか汎用があると嬉しい

Bundler 2


0xColbyさんの発表

  • bundle addコマンド経由でできるようになる
  • plugin機構を取り入れて、事前処理や後処理も追加できる
  • エラーメッセージの改良
  • 1.16が1.x系最終
  • Bundler2は2.3以上
  • sourceの名前付けをショートカットさせる(:githubみたいな指定)
    • gem ‘rack’ github: ‘user/repo’
    • ブロック指定もできる
  • bundle infoやbundle gemの情報が出て来る
  • bundle packageがbundle cacheに変更
  • bundler 1.xとの後方互換製ない
  • bundlerは今後1年ごとにメジャーリリース(メジャーバージョンアップという意味ではなく)
    • ruby2.5ではruby側に同梱
  • bundler2でGemfile.lockが解釈できるが逆はできない(だったかな)

Memory Fragmentation and Bloat in Ruby


nateberkopecさんの発表

  • 512MBのDYNOでRails動かしてる場合は50%くらい(?)はMemory-constrained
  • Rubyでのメモリ確保の挙動はレイヤーが深くて難しい、みたいな話をしてる。Ruby Code自体/Ruby Runtime/Allocator/MMU/実メモリ配置
  • Rubyコード自体からランタイム、アロケーター、MMU、RAM構造まで考えること沢山
  • freeは本当にfreeするわけではない。OSに領域を返すわけではない.初期化コストかかるのでガバッと拾ってしまってる
  • web request allocation pattern
  • http requestが終われば関連するメモリ全部捨てられる
  • 確保したメモリを更に小分けにして、リクエストごとに割り当ててレスポンスが終わったらまとめてfreeして再利用
  • 全てのオブジェクトには40ByteのRVALUEが与えられている。また、実際にmallocされて割り当てられた実際のオブジェクトデータへのポインタを持つ
  • 文字列も短いとRVALUEに入り大きければmallocで確保された場所へのポインタ
  • GC.statの:heap_live_slotsでスロット数が、:heap_eden_pagesでページ数が取れる。GC::INTERNAL_CONSTANTS[:HEAP_PAGE_OBJ_LIMIT]でページごとの上限が取れる
  • eden_pages * slots_per_pageで確保できるオブジェクトの上限が取れる。live_slotsをこれで割れば使用率が出せる
  • PUMAはUnicornより多くのメモリを使ったり、Sidekiqがリークしたりする。スレッドごとのメモリ領域がメインスレッドのメモリ領域に還元
  • スレッドごとにメモリ領域を確保した後、スレッドが終了しても開放されずにメインスレッドのメモリに統合される
  • MALLOC_ALENA_MAXを指定すると確保するメモリ領域の上限を制限できるけど、速度とトレードオフになる

Writing Lint for Ruby


p_ck_さんの発表

  • ripper
  • Rubyのparserはほかにもある。標準のRipper。パースのRubyと実行するRubyが同じバージョンになってしまう問題
  • ASTのトラバースでも無視するnilの可能性
  • Traverserパターンで解析をする。nodeとvisitorを受け取り再帰的に呼び出していますね。
  • node.source で括弧の有無など AST で欠損するソースそのものの情報を入手することができる
  • lintの限界
    • ローカル変数の中身はparserは知らない
      • 要はエラーがあったものを代入して回避なおd
    • method呼び出しで定義がわからない
      • 静的解析とRubyの相性がイマイチよくない
    • monkypatch / params(rails) / evalだとLintではできない
      • 実行できないという制約
  • 構造が理解ができる
    • 全てのケースに対して警告出せる
  • 解析時間が短い
    • 実行したりしないので
  • rubocopは汎用ルールなので、こっち使ったほうが楽
  • Rubocop(Lintのルール)の作り方。rakeタスクがある。lintの実装とテストのテンプレートを作ってくれる
    • rubocop-plugin(特化したもの)
  • Lintはバグ検出に使えるもの
  • 解析は、ASTトラバースして見つける
  • 静的解析にはいくつか方法はある

終わりに


スピーカー、スタッフの皆様ありがとうございました

久しぶりな方々ともお会いできて、新たな刺激がありました 印象深いのが型、parser周りの話が多かった印象です
来年は仙台なので、広島よりは都内から近いですね

認証系のgemをちょっと見てみた

はじめに


だいたいのwebサービスにはユーザー登録をしてはじめて使用することが多いと思います

ご多分にもれずに、これから実装しようとしたものでメンバースキルを鑑みるとRailsという形ですすむことになりました。

では、Railsでアプリを書くときに認証系のgemって、今は何が使えるものだろうかということを軽く見てみました。

# ちょっと実装してよと軽く言われるものの困ったものですorz

RubyToolboxを眺める


自分の個人内の観測範囲でよく聞くもの

  • warden
  • devise
  • Authlogic
  • Sorcery
  • doorkeeper
  • OmniAuth

# provider提供も関係無く書いてますが、話と毛色が違う感あるのでこの後は出てきません

メンテ厳しいらしいもの


この2つの模様

  • Authlogic
  • Sorcery(Currently Sorcery project is not actively maintained.という文章がREADMEにあった)

PR眺める限り、Authlogicは対応させようと頑張っている模様 Sorceryは、ちょっと厳しそうかな(とはいえ、一応動く&issueとPRをあげたら対応自体はしてくれる模様)

devise&warden


changelog見ると、
4.0.0rc1からRails5に対応していました
流石ですね。

# が、多機能で便利でいいのですが癖が強いのとdeviseのレールから外れた瞬間悲惨な目に遭うので避けたいところ

他に無いか?


個人的に良さそうかなと思ったのは、monbanですかね。
(ちょっとgithubのスター数が少ないのは気になりますが・・・)

Rails使ってるなぁと思ってみたら、殆どconcern(helper)と初期ロード&設定(railtie&configure)だけだった模様
案外Railsのアップデート影響も少なそうな印象でした。

実装や設定内容を読む限り、拡張の幅も広いので好印象でした
実際、Rails5でカスタム実装してみましたが問題なく認証させることができました

肌感&経験上ですが、認証機能自身はサービスによって独自の仕様、または既存機能との併用となることが多いので
拡張しやすいgemの方が対応のさせやすさ、メンテナンスさせやすいほうがやりやすいかなと思ってます

そういう意味では、(余計な機能が無いという意味で)軽量かつ、拡張可能、機能の置き換え可能なmonbanはいいなと思いました

# ぶっちゃけ、monbanカワイイよってことだけが言いたかったw

Gitのブランチ系コマンドでよく使うもの

はじめに


たまになんだっけ?ってなるものがあるのでメモしておく
基本的に削除系

ブランチ作成


普通に作る

1
$ git branch hoge

別のやり方

1
$ git checkout -b hoge

ローカルブランチの削除


マージ済みのものを削除

1
$ git branch -d hoge

マージされていないものを強制削除

1
$ git checkout -D hoge

リモートブランチの削除


pushの逆をするだけ

1
$ git push origin :hoge

マージ済みブランチの探索


こんな感じで難しくない

1
$ git branch -r --list --merged

オプションを変更するだけで、未マージも見つかる

1
$ git branch -r --list --no-merged

リモートブランチとの同期


誰かがリモートブランチが削除したとしても、その前にfetchしていたら自分のローカルブランチには残っているので同期をする
これは、放置しておくとよく忘れるやつ

1
$ git remote prune origin

# ぶっちゃけ、よく忘れる一番最後のだけ書きたかった

Kotlin 1.0リリース記念勉強会 in 京都に行ってきた

はじめに


界隈の情報を収集しておきたかったので行ってきました

結論的なところを言ってしまうと、
もうプロダクトに放り込んでも良さそうという印象でした
(kobaltやKotolin for JSのようなエコシステムはまだまだですが・・・)

とはいえ、多少は混ぜるな危険(nullとか)もあるようなので
ビジネスロジックデータクラス(所謂JavaBeanとか)からやり進めたほうがいいかなという感覚です
(swiftでobj-C混ぜて大変なことになったのは、大体一年前の話w)

AndroidだとActivityとかコアなところをやるのではなくロジック周りからかな
# 新規に作る場合、その限りではない

JetBrainsさん、ロードマップ出すぐらいに本気!!
(大したことでは無いが唯一の懸念としてあるとすれば、Androidに限ればGoogle本家のサポートでは無いというところぐらいかな)

SIerアーキテクト視点でみたKotlinの紹介


期待

  • 新しく覚えることを少なくできる
  • 一番期待しているのは後方互換性(コンパイラは古いバイナリを使える)

機能

  • NullSafe(no-null type / nullable type)
    • 言語レベルでnull safeサポート
    • Java8のOptionalは使い勝手がよくなかった(バッドコードが生まれやすかった)
  • Dataクラス
    • valueオブジェクトとして使ったほうがよい
  • smartcast
    • ソースの文脈で、判断してくれる
    • 型分岐で処理するのがやりやすい(instanceof & キャストしなくていい)
  • extension
    • 既存クラスを拡張することが可能
      • swiftとだいたい同じ
  • delegation
    • インターフェースだけ可能
    • 移譲プロパティ
      • 遅延評価とか可能
  • 演算子のオーバーロード
    • BigDecimapを演算子で計算可能

まとめ

  • 実用的で使いやすい
  • 後方互換性がある(サポートすることを名言している)
  • webで勉強できる

kotilinはじめました


  • scalaとかswiftやってれば似ているのでやりやすい
  • scalaのoptionalとkotolinのnull safeは似ているようで微妙に違う
  • scalaからbetter javaを抜き出してシュリンクした感じ
  • 言語仕様が少ないので覚えやすい
  • scalaの入り口にはなりやすい(基本構文が似ていることがいい)
  • swiftっぽい感(構文似ているけど、違うことはそれなりにある)
  • ?:はエルビス演算子(scalaのgetOrElse)って言うんだよ!

kotlinとjavaee


  • インジェクションがちょっと面倒そう(明示的に)
  • none null型にはcdiで注入するのが面倒
    • コンストラクタで初期化するとか
    • lateinit修飾子をつけるとか工夫が必要
  • JAX-RSはjavaのコードをそのままで
    • 継承するためにopenアノテーション必要
  • JPA
    • static fieldはcompanionオブジェクトにする(static backing field)
  • 混ぜるな危険はあんまり無さそう
    • どう書くかというのは悩むことは非常に多いかも
  • 少しずつkotolinに置換は現実的かも
  • 古いドキュメントが多いので注意

springboot + kotlin


  • springbootでkotlinが使えるようになった模様
  • DIはlateinit使え!
  • JRebel(ホットスポットVMかな)
    • 問題無く動く
  • Spring AOP
    • finalになっているのでopenにすることが必要
    • @Beanはfunc hoge() = “hoge”でかけるとおもいきやopen
  • getter/setter書かなくてよいのですっきり
  • none null対策にはいい
    • @NonNullアノテーションは書かないやつでてくるので、none nullを強制できる

kotlinとモダンライブラリを使ってアプリを作る


  • dagger2と相性良さそう
    • そこそこ記述量が減ってる
    • 登壇者もActivity書いたりやcontextの引き回しは気になる模様
  • databinding
    • プロパティクラス使えばいい
    • java同様に普通に使える
    • lazyやnone null、delegateでデータ作らないと表示されないかも
  • property observer
    • 変更監視可能なプロパティ
    • ListViewとかで有効
      • データが更新される
  • binding adapter
    • JvmStaticアノテーションでstaicなメソッドになる
  • value converter
    • kotolinでは使えなかった模様
    • javaで書くしかない
  • JetBrainのankoというライブラリが素敵
    • context, serviceとかに便利拡張がある
    • dslはデータバインディングと組み合わせは辛い(相性があまり良くない模様)
  • ハマりどころあるものの大体使える
    • Javaのライブラリもそのまま使える模様

Kotlinこんなん出ましたけど


  • kotlin as JS
    • JVM側はメジャーリリースで仕様が大体固まった
    • JSはもうちょい変更入る
  • kobalt
    • gradleライク
    • kobaltプロジェクトを参考するといい模様
    • ドキュメント生成可能だけど、フォーマット
  • エコシステムも作ろうとしている模様
    • Androidだけに注力している訳ではない

Dataクラスから始めるKotlin / JetBrains行ってきたよ!


  • groovy柔軟性を引き換えにパフォーマンスと型安全が犠牲
  • scalaは別の世界
  • kotolinはスムーズ
  • lombokプラグインは時々壊れる
  • データクラスからの以降がよい
  • ロジックに集中して、細かいところを以降していくといい
  • java to kotlinはたまに失敗することがある
    • コンバート後のコンパイルに失敗
    • 修正過程で勉強になるとポジティブに捉えるといいかも
  • Jankinsでビルドががが
    • サブモジュールの.ktが見つからない
  • 突然のillegalstateexception
    • javaの世界からnullが渡されると起きる
    • javaからも使うフィールドはnone nullにするか慎重になる必要
  • おしいところ
    • shift + commnad + enterが効かない
  • ゆるやかに以降できる
  • データオブジェクトとかビジネスロジックから手をつけて以降するのがオススメ

攻めるラムダ式禁止おじさん


  • 関数参照を使えば、ラムダ式を消せる
  • 引数を取らないものもできる
  • 引数を2つとるものは、かりー化
  • メソッド参照
  • java的なメソッド参照は使えないけど、かりー化使えば対応可能
  • ラムダ式をきちんと使う方向で・・・

Railsのリクエストヘッダーを調べる

はじめに


リクエストヘッダーの中身を見ようとしたときの備忘録
ヘッダーを利用してゴニョゴニョしてた時とかに使ってましたw

Railsのリクエストで一覧を取得


requestで来たhederの一覧を調べる場合、以下のコードをbefore_actionに仕込んでおく

1
request.headers.sort.map { |k, v| logger.info "#{k}:#{v}" }

特定のヘッダーの内容確認


HTTP_ACCEPTを見たい場合は、以下のコードをbefore_actionに仕込んでおく
(多分このコードはよく使うかも)

1
accept = request.headers['HTTP_ACCEPT']

利用可能なMIME Typeの確認

Railsで定義されているMIME Typeを観る場合は以下のコードを利用する
以下はjsonに対応したMIME Typeを確認するコード

1
2
Mime::EXTENSION_LOOKUP.each { |m| puts m}
Mime::Type.lookup_by_extension(:json)

sshでX11 Forwardingをsudoコマンド時に実施する方法

あったこと


表題のようにsshでX11 Forwardingでコマンドを実行したところ
下記のようなエラーになった

1
2
3
4
5
6
7
$ ssh -XY -l hoge xxx.xxx.xxx.xxx
$ sudo virt-manager
** (virt-manager:3166): WARNING **: Could not open X display
X11 connection rejected because of wrong authentication.
X11 connection rejected because of wrong authentication.
(virt-manager:3166): Gtk-CRITICAL **: gtk_settings_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed
(virt-manager:3166): Gtk-CRITICAL **: _gtk_settings_get_style_cascade: assertion 'GTK_IS_SETTINGS (settings)' failed

どうやら認可が正しくできていない模様
(GTKのSCREEN系のエラーっぽく見えるところが、ややこしさに拍車かけてると思う・・・)

解決案


sudoコマンドを実行する際、Xauthorityを読み込むようにして実行する
(下記では、念の為xauthをインストールしている)

1
2
3
$ ssh -XY -l hoge xxx.xxx.xxx.xxx
$ sudo yum install xorg-x11-xauth
$ sudo  XAUTHORITY=~/.Xauthority virt-manager

強引に認可させているので、セキュリティ的に果たしてこれでいいのかという疑問は残りますね
何れにせよ、ローカルネットワーク内で実行するだけなのでこれでいいかなと。

GroovyでWALKMAN用のプレイリストコンバーターを作成した

はじめに


自分の楽曲管理なのですが、以下で行っていました

  • Macを使っている&元iPhoneユーザーのためiTunes
  • 現状はAndroidユーザーでXperiaZ3Compactを活用
  • iTunesとの連携にはiSyncrアプリでAndroidアプリを連携

ここ最近、残念なことにXperiaZ3Compactのイヤホンジャックが故障してしまいました
海外版SIMFree版のため、国内で修理することもできません。

部品を調達してきて、別途修理するか悩みましたがリスクが高い
(ネットで調べる限りだいたい、何かしらミスしたという話が多かったです)

仕方ないのでWALKMANを調達するとして、以下の条件で機種が無いかをしらべました

  • WALKMANであること
  • iSyncrアプリの恩恵を預かれること
  • microSDは活用してもいい
  • ある程度の運用は許容するので、何かしらのコンバーター(アプリorスクリプト)は実装してもよい

条件に合致するものであれば・・・

  • 高額機種のWALKMAN
  • Android WALKMAN(3~4年前)で売り出していたFシリーズ
  • microSDが使用しているNW-A20シリーズ

というわけで、機能面でも最新であることたお値段も含めて一番条件に合致するWALKMAN(NW-A25)を新たに新調することとしました
(Fシリーズは別途問題があったようなので却下にしました)

何故コンバーターが必要になったか


iSyncrで作成したプレイリストは、Android向けに最適化されたもののようなので、そのままではNW-A25では活用することができませんでした
(店頭に通って挙動を確認しました)

症状としては以下のような形です

  • プレイリストは認識するが曲が存在しない扱いとなる
  • プレイリストを通さない、ミュージック一覧では楽曲の認識と再生可能

何故こういう状態が起こるかというと、WALKMANはOSがAndroidではない為、ファイルパスの扱いが異なるようです
なので、改善として以下のようにしてあげれば、プレイリストから楽曲再生ができるようになりました
(こちらも店頭で確認)

変更前

1
2
3
#EXTM3U
/hoge/fuga.mp3
/hoge/fugafuga.mp3

変更後

1
2
3
#EXTM3U
hoge/fuga.mp3
hoge/fugafuga.mp3

つまり、うまく認識させるためには相互変換できるようなものがあればよいということになります

何故Groovy?


以下の打算があったので、Groovyでやってみました

  • iSyncrはAndroidアプリなので、コンバーターもAndroidアプリでやれば運用が楽になるのではないか
  • AndroidはJavaで動作し、JVM言語であるGroovyが動作することも確認取れている
  • GroovyはJavaよりもライトに(Clojureを活用してですが)ファイル変更処理を実装することができる
  • ライトにできるので実装モック作成も割りと早めにできるのではないか

が、結局Android上での外部ストレージ周りのファイル操作の挙動が変わってる(DocumentFileを通したファイル作成、変更がスクリプトと相性悪い為)ので
後述のスクリプト処理が活用しづらいのでアプリ内での変換処理は諦めました

なのでコマンドラインツールとして実装&運用する方向としました
(運用できなくなるのが困るので、多少の労力(SDの抜き差し回数が増える)ぐらいなら労力を割いてもいい方向にしました)

iSyncr向けのプレイリストからWALKMAN向けのプレイリストに変換


少し手間ですが、以下のような形をとりました

  1. WALKMAN向けのプレイリストファイルを作成する(この時点では一時ファイルとして)
  2. iSyncr向けのプレイリストファイルを開く
  3. iSyncr向けのプレイリストファイルの内容をWALKMAN向けのプレイリストファイルに書き込む
  4. このとき行の先頭文字が/で始まっている場合、空文字に置換
  5. ファイル名を正しいもの変更する
  6. iSyncr向けプレイリストは、識別可能なファイル名に変更
  7. 一時ファイルのWALKMAN向けのプレイリストファイルは、正しいプレイリストファイル名になるよう変更

これらを実装したものが以下になります

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def isyncrToWalkman() {
  def sdCardDirPath = "/Volumes/WALKMAN/syncr"
  def files = new File(sdCardDirPath).listFiles()

  playList = files.findAll { it.getName() =~ /.*\.m3u$/ }
  if (playList.empty) {
    println "PlayList not found!"
    return
  }

  playList.each { file ->
    def playListName = file.canonicalPath

    def newPlayListName = "${file.canonicalPath}.new"
    def newPlayListFile = new File(newPlayListName)

    newPlayListFile.withWriter('UTF-8') { writer ->
      file.newReader().transformLine(writer) { line ->
        if (line.startsWith("/")){
          line.replaceFirst(/\//,"")
        } else {
          line
        }
      }
    }

    file.renameTo("${file.canonicalPath}.isyncr")
    newPlayListFile.renameTo("${playListName}")
  }
  println "Convert iSyncr To WALKMAN Complete!!"
}

WALKMAN向けのプレイリストからiSyncr向けのプレイリストに変換


こちらは以下を実装するだけでよいので簡単です

  1. WALKMAN向けのプレイリストを削除
  2. iSyncr用のプレイリストの名前を変更

上記を実装したものが以下になります

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def walkmanToIsyncr() {
  def sdCardDirPath = "/Volumes/WALKMAN/syncr"
  def files = new File(sdCardDirPath).listFiles()

  def isyncrPlayList = files.findAll { it.getName() =~ /.*\.m3u.isyncr$/ }
  if (isyncrPlayList.empty) {
    println "PlayList not found!"
    return
  }

  def walkmanPlayList = files.findAll { it.getName() =~ /.*\.m3u$/ }
  walkmanPlayList.each { file -> file.delete() }

  isyncrPlayList.each { file ->
    def name = file.canonicalPath.replaceFirst(/\.isyncr$/, "")
    file.renameTo(name)
  }
  println "Convert WALKMAN TO iSyncr Complete!!"
}

コマンドライン部分


こちらはGroovyのBuilderを実装しているCliBuilderを活用しました これは、コマンドラインから実行する際、どちらの変換を実行するかを選択させるようにしたかった為です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def cli = new CliBuilder(usage:"PlayList Converter")
cli.w("Playlist : iSyncr TO WALKMAN")
cli.i("Playlist : WALKMAN TO iSyncr")


def opt = cli.parse(args)
if (opt.w) {
  isyncrToWalkman()
  return
}

if (opt.i) {
  walkmanToIsyncr()
  return
}
cli.usage()

コードみれば非常に簡単なのですが・・・

オプションにwを付けて実行すると、前述のiSyncrのプレイリストからWALKMAN向けのプレイリストに変換する処理を実施
オプションにiを付けて実行すると、前述のWALKMAN向けのプレイリストからiSyncrのプレイリストに変換する処理を実施
何もつけなければ、実行方法を表示するようになっています

運用


前提

  1. PCが認識するSDカードのパスが/Volume/WALKMANになるように設定
  2. 前述のコードをまとめたGroovyファイルをplaylist_converter.groovyとする
  3. sdkmanを使って、Groovyをインストール

運用手順

  1. iSyncrでAndroid上のSDカードとプレイリストを同期
  2. 同期完了後、AndroidのSDカードを取外しPCにSDを接続
  3. WALKMAN向けプレイリストになるように以下のコマンドで変換
  4. $ groovy playlist_converter.groovy -w
  5. WALKMANにSDカードをさして、ミュージックを楽しむ
  6. WALKMANからSDを取り外し、PCにSDを接続
  7. WALKMAN向けプレイリストになるように以下のコマンドで変換
  8. $ groovy playlist_converter.groovy -i
  9. AndroidにSDをさして、更にプレイリストの同期を実施

少し煩雑な感じもしますが、手作業でプレイリストを修正するよりも多少マシかなぁと思ってます
(実際に自分は運用できてます)

AndroidでGroovyを使ってみる

はじめに


現在常用のスマホとしてAndroid端末を使っています。
(つい半年前まではiPhoneを使っていました)

端末機としては海外版、XperiaZ3 Compactです。
(昨今の大型化している流れの中軽量かつ音楽プレイヤーとしても優れている機種として選定しました。)

元々iPhoneユーザーかつ環境が全てApple製品で統一されているので、音楽管理もiTunesで行っています。

そういう状況下であったので、iSyncrというアプリでiTunesのプレイリストと端末を同期させて利用していました

どうもXperiaZ3 Compact側のイヤホンジャック(ヘッドホンジャック)が壊れたようで、
音楽プレイヤーとしてはまともには利用できなくなりました

とはいえ、Youtubeを見て修理するのはリスクが高いのと、パーツが個人輸入になるので調達までのハードルが高いので修理方向は諦めました

が、どうも最近のwalkmanでは、microSDを使えプレイリストを少し調整すれば認識できるようなことを聞きつけました
(店頭モックでも、プレイリストを認識し再生可能であることを確認しました)
なので、microSDとの同期はiSyncrに任せ、同期したプレイリストの変更を独自のアプリでやればいいのではないかと思い今回やってみました

やりたいこと


まずはiSyncrで作ったプレイリストがウォークマンから認識できるかどうかを確認しました。
結論的に言うとそのままでは不可能で、一旦編集が必要のようです。

どうやらiSyncrを使ってiTunesの曲を転送したときは、iSyncrの作ったm3uプレイリストを正しく認識出来ないようです
これは、ウォークマン側のプレイリスト内のパスの解釈の問題のようです。
対処方法としては、パスの先頭の「/」を削除することで認識させることできます
(ウォークマン内部では、パスが補完されているのかもしれませんがその辺りは不明です)

こんな感じになるようにします

1
2
/hoge/fuga.mp3     -> hoge/fuga.mp3
/hoge/fugafuga.mp3 -> hoge/fugafuga.mp3

ということで実装としてやりたいことは至ってシンプルです

  • 編集後のプレイリストファイルを作成する
  • iSyncrで作成したプレイリストの内容を、ほぼそのまま編集後のプレイリストに書き込む
  • この時、行の最初の文字が「/」の場合、上記のように先頭の「/」を空文字に置換する

何故Groovy


Javaで書くと、以下の内容が面倒だったりするわけなのです

  • StreamだとかWriterやらReaderやらでコード自体が肥大化、冗長化すること
  • ファイルの中身の操作や置換とか結構大変で面倒

なので、今回その辺もサクッと実装できるGroovyで書いてみました

他にあるとすれば・・・

  • GroovyがAndroidでも動くということ
  • 置換検証用のコードをサクッと移植したかったこと
  • 個人的にGroovyでコード書くというリハビリ(書かなくなって久しいので)

当該Groovyコード


やりたいことを実施するファイルの置換用コードは以下のようになります

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def files = new File('Your Path').listFiles()
playList = files.findAll { it.getName() =~ /.*\.m3u$/ }

playList.each { file ->
  def playListName = file.canonicalPath

  // 変更版プレイリスト
  def newPlayListName = "${file.canonicalPath}.new"
  def newPlayListFile = new File(newPlayListName)

  // 変更版プレイリストに現行プレイリストの修正内容を出力
  newPlayListFile.withWriter('UTF-8') { writer ->
    file.newReader().transformLine(writer) { line ->
      if (line.startsWith("/")){
        // 行の最初の文字の場合、「/」を置換する
        line.replaceFirst(/\//,"")
      } else {
        // それ以外の場合はそのまま出力
        line
      }
    }
  }

  // ファイル名を変更する
  file.renameTo("${file.canonicalPath}.old")
  newPlayListFile.renameTo("${playListName}")
}

本当であれば上書き保存という形にしたいところですが、
元のファイルが無くなってしまうと今度は同期が取れなくなる可能性があるので別ファイルとしました

GroovyをAndroidに導入


まずはGroovyのインストールをします。
以下のような形でsdkmanを使いましょう

1
2
3
4
$ curl -s http://get.sdkman.io | bash
$ sdk ls groovy
$ sdk install groovy 2.4.5
$ sdk use groovy 2.4.5

次にAndroidStudioでAndoridプロジェクトを用意します
Androidプロジェクトに対して、groovy-android-gradle-pluginを導入します

プロジェクトROOTにあるbuild.gradleを以下のようにします
(プラグインを導入するのみです)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.3.0'
        classpath 'org.codehaus.groovy:gradle-groovy-android-plugin:0.3.6'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

次にアプリ側のbuild.gradleを変更します
(プラグインの適用と、コンパイルライブラリの追加、プラグインの設定追加)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apply plugin: 'com.android.application'
apply plugin: 'groovyx.grooid.groovy-android'

android {
    中略
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:design:23.1.1'
    compile 'org.codehaus.groovy:groovy:2.4.3:grooid'
}

project.androidGroovy {
    options {
        configure(groovyOptions) {
            encoding = 'UTF-8'
            forkOptions.jvmArgs = ['-noverify'] // maybe necessary if you use Google Play Services
        }
        sourceCompatibility = '1.7'
        targetCompatibility = '1.7'
    }
}

ソースの配置を「src/main/java/MainActivity.java」から「src/main/groovy/MainActivity.groovy」変更します

最後にソースを以下のようにしてGroovyライクに実装します

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

@CompileStatic
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        def hello = { lang ->
            def toast = Toast.makeText(this, "Hello ${lang}!", Toast.LENGTH_LONG)
            toast.setGravity(Gravity.CENTER, 0, 0)
            toast.show()
        }
        hello("Hello Groovy on Android!")
    }
}

一応いっておきますが、@CompileStaticアノテーションで静的コンパイルしなくても動作はします
が、動的コードはパフォーマンス的にきびしいので@CompileStatic推奨されているようです

ビルド時の注意点


Android Studioでビルドを実行したとき、エラーがあった場合以下のような形でEventLogに出力されてビルドが停止します。
メッセージを見ても、何が悪いか分かりません。正直、自分は困惑しました

1
2
3
4
5
6
7
0:52:06 Platform and Plugin Updates: The following components are ready to update: Google Play services, Google Repository, Android SDK Platform-tools
1:14:33 Gradle sync started
1:14:57 Gradle sync completed
1:14:57 Executing tasks: [:app:generateDebugSources, :app:generateDebugAndroidTestSources]
1:15:01 Gradle build finished in 4s 168ms
1:15:41 Executing tasks: [:app:generateDebugSources, :app:generateDebugAndroidTestSources, :app:compileDebugSources, :app:compileDebugAndroidTestSources]
1:15:47 ExternalSystemException: String index out of range: -105

そのときはGradle Consoleを確認しましょう
以下のような形でエラーメッセージが表示されています
(この場合、Syntaxエラーですね)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
:app:compileDebugJavaWithJavac UP-TO-DATE
:app:compileDebugGroovyWithGroovyc
startup failed:
MainActivity.groovy: 53: expecting ')', found '}' @ line 53, column 13.
               }
               ^

1 error


 FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:compileDebugGroovyWithGroovyc'.
> Compilation failed; see the compiler error output for details.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 5.687 secs

因みに上記のような形になった場合、何故かそのままではビルドの再開が出来ませんでした。
対応としては一度「Clean Project」を実行する必要があります

結果的に・・・


ここまで読めば、分かる方はわかりますが実現はサクッとは出来ませんでした。

何故かと言うとAndroid4.4あたりから導入されたStorage Access Frameworkのことをスッカリ忘れていたのでやりたいことは出来ませんでしたorz

当初の運用自体は、iSyncrの同期先をSDカードにしてSDカードに対して同期
その後同期されたSDカードをPC側にマウントして、上記コードを通してやればよいので無理にAndroid経由させなくていいかなぁと思った次第です

とはいえGroovyでAndroidアプリを書いてみることはまぁできたのでよしとします。
GroovyでGroovy GDKの便利なAPIやクロージャの恩恵を最大限に受けてて、簡潔に書くことが出来て素晴らしいなと思いました

RubyKaigi3日目に行ってきた

The OMR GC Talk


OMRというランタイム

  • 多くの言語に対応している
  • (plugin機構で実現?)

調査はこれを使っていた模様 https://www.ibm.com/developerworks/jp/java/library/j-ibmtools5/

allocationを早くした

  • スレッドローカルヒープ
  • ロック無しでallocate

可変長のバッファを作る OMRのランタイム上で動作するGCがMRIに比べてよかった

GCのmark速度は早い(MRI)

OMR GCを確認するのはこれ https://github.com/rubyomr-preview/rubyomr-preview

Refinements - the Worst Feature You Ever Loved


method aliasとかモンキーパッチだと元の動きの振る舞いが全体に影響するからよくない

assertとかの振る舞いもかわってしまう

refinementsなら影響範囲を制御できる

スコープは働くので継承とかcalss_evalでも有効

文字列で与えたもので使えるeval ‘using SomeClass; hoge.fuga’みたいな感じなの

Discussion on Thread between version 1.8.6 and 2.2.3


Thread#status スレッドの状態が取れないような状況が起きた →mission crtalなシステムでも使えるThreadの使い方

  • 子スレッドでforを同期的に上がった場合
  • 同期的にraiseが上がった場合

Ruby2.2.3でも早くなったけど、CPU負荷も上がった 実行回数は変わらなかった

raiseのインスタンスは重い メモリ消費は少ない selectで対応することができる

早くなったけど、リソース消費も多いのでスレッドとかはメモリ消費量を意識したほうがよい

Plugin-based software design with Ruby and RubyGems


  • 多くの機能
  • コアコードがシンプル
  • testが簡単
  • developerコミュニティが活発

デザインパターン

  1. ホストアプリを拡張する(拡張ポイントを用意している、コールバックで実行)
  2. DIでプラグインを追加(I/Fとか決めてDIコンテナを置き換え、ホストからアプリを実行)
  3. 動的にプラグインをロードする方法
  4. 1と2を組み合わせる方法

プラグインのバージョンコントロール(依存ライブラリのコンフリクト解消)

fluentdは動的にpluguin emblukは組み合わせ

Actor, Thread and me


アクター

  • メッセージを適当なタイミングで送る
  • レシーブ
  • 仕事をする

破綻の予兆

  • 複数のイベントを待つ
  • DBへの問い合わせとか
  • 資源の協調