2018年以降の記事はGitHub Pagesに移行しました

PyConJP 2016 in TokyoでSphinxハンズオンのTAをしてきた #pyconjp

あらすじ

さる9/20のPyConJP 2016 Tutorial day(1日目)にて行われたSphinxハンズオンにTAとして参加しました。

振り返り

  • 参加者は6名
  • 参加動機など
    • 仕事でドキュメントが残ってない、まとめるにあたってツール選定していたらSphinxを知った
    • 重いWordファイルを操作するのが困難、別のフォーマットで簡単に扱いたい
    • Pythonでデータ解析をするにあたって使用しているツールのドキュメントがほぼSphinx製だったので、Sphinxとは何なのか知っておきたい

簡単にメモ。

Software Design 2016年11月号にSphinxの記事を執筆しました #sphinxjp

あらすじ

Software Designで連載している「Sphinxで始めるドキュメント作成術」の記事をかかせていただきました。

内容

Sphinxで文章を作成するにあたって知っておくと便利なツールなどの紹介をしています。

img

Androidのapkの総メソッド数を調べてMulti-dexを導入するか否かを判断する

あらすじ

  • Androidではapkのメソッド総数が65536を超える場合、ビルド/インストール時にエラーが発生する
    • Multi-dexを導入して対応しなければならないらしい
  • しかし、メソッド総数はどう判断すればよい?

参考

手順

  • dex-method-countsを使用する
git clone https://github.com/mihaip/dex-method-counts.git
cd dex-method-counts/
./gradlew assemble
./dex-method-counts hogehoge-debug.apk 
Processing hogehoge-debug.apk
Read in x method IDs.
Read in xxx method IDs.
<root>: xxx
    android: x
        app: x
        content: x
            res: x
        net: x
        os: x
        util: x
        widget: x
    com: x
        android: x
            tools: x
                fd: x
                    common: x
                    runtime: x
    dalvik: x
        system: x
    java: xxx
        io: x
        lang: x
            ref: x
            reflect: x
        math: x
        security: x
        util: x
            logging: x
            zip: x
Overall method count: xxx

Rubyの変数DATABASE_URLでハマった話

あらすじ

  • 一台のサーバーに複数のRailsアプリケーションがある
  • 新しく一つRailsアプリケーションを作成した
  • config/database.yml を見るとこんなコメントアウトがあった
# On Heroku and other platform providers, you may have a full connection URL
# available as an environment variable. For example:
#
#   DATABASE_URL="mysql2://myuser:mypass@localhost/somedatabase"
#
# You can use this database configuration with:
#
#   production:
#     url: <%= ENV['DATABASE_URL'] %>
#
  • こんな変数があるのね。 database.yml で使ってみた
production:
  url: <%= ENV['DATABASE_URL'] %>
  • 変数を .bash_profile あたりに定義
export DATABASE_URL="mysql2://myuser:mypass@localhost/somedatabase"
  • 結果、同じサーバーに存在している全部のRailsアプリケーションが上記の接続先を見に行った!

原因

コメントでも DATABASE_URL を使用してね、とあるが、環境変数ENV['DATABASE_URL'] が存在すると active_record/connection_handling.rbDATABASE_URL がマージされてしまう模様。

以下、引用。

config/database.ymlファイルと環境変数ENV[‘DATABASE_URL’]が両方存在する場合、両者の設定はマージして使用されます。以下のいくつかの例を参照して理解を深めてください。

提供された接続情報が重複している場合、環境変数が優先されます。

提供された複数の情報が重複しておらず、競合している場合も、常に環境変数の接続設定が優先されます。

poolはENV[‘DATABASE_URL’]で提供される情報に含まれていないので、マージされています。adapterは重複しているので、ENV[‘DATABASE_URL’]の接続情報が優先されています。

ENV[‘DATABASE_URL’]の情報よりもdatabase.ymlの情報を優先する唯一の方法は、database.ymlで”url”サブキーを使用して明示的にURL接続を指定することです。

マージしているのは、このあたりかな。 ./vendor/bundle/ruby/2.1.0/gems/activerecord-4.1.15/lib/active_record/connection_handling.rb

66       # Returns fully resolved connection hashes.
67       # Merges connection information from `ENV['DATABASE_URL']` if available.
68       def resolve
69         ConnectionAdapters::ConnectionSpecification::Resolver.new(config).resolve_all
70       end
71
72       private
73         def config
74           @raw_config.dup.tap do |cfg|
75             if url = ENV['DATABASE_URL']
76               cfg[@env] ||= {}
77               cfg[@env]["url"] ||= url
78             end
79           end
80         end

まあ影響範囲を考えて使いましょうという話。

Gatlingを使用してみた

あらすじ

サーバーにリクエストをいっぱい投げて負荷をかけたい。(いわゆる弾投げ)

Gatlingとは

  • 負荷テストツール
  • 2011年頃から作成
  • Scalaで実装されている
  • Scalaでテストケースを書く
  • ライバルはJMeter

実際に使う

からダウンロードできる。今回はzipでDLした。

  • DLしたzipファイルを解凍、ディレクトリに移動し、適当なテストケースを作成する
cd gatling-charts-highcharts-bundle-2.2.1
vi user-files/simulations/computerdatabase/advanced/Sample.scala
  • テストコードはサンプルを見ながら…scalaやったことないからちょっと難しい
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._
class Sample extends Simulation {
  // プロトコルの定義
  val httpConf = http
    .baseURL("http://localhost:8080")
  // シナリオの定義
  val scn = scenario("Sample")
    .exec(http("sample_request")
      .get("/"))
    .pause(100 milliseconds)
  // シナリオの構成
  setUp(scn.inject(rampUsers(10) over(5 seconds)) .protocols(httpConf))
}
  • bin/gatling.sh でテスト実行。他にもいくつかサンプルテストケースが列挙されるので、今回は自分で作った Sample [0] を選択
>|| $ sh bin/gatling.sh GATLING_HOME is set to /Users/kk_Ataka/Downloads/gatling-charts-highcharts-bundle-2.2.1 Choose a simulation number: [0] Sample (略) 0 Select simulation id (default is 'sample'). Accepted characters are a-z, A-Z, 0-9, - and _ Select run description (optional) Simulation Sample started... ================================================================================ 2016-07-30 14:05:54 5s elapsed ---- Sample -------------------------------------------------------------------- [###########################################################-------- ] 80% waiting: 1 / active: 1 / done:8 ---- Requests ------------------------------------------------------------------ > Global (OK=9 KO=0 ) > sample_request (OK=9 KO=0 ) ================================================================================ ================================================================================ 2016-07-30 14:05:55 5s elapsed ---- Sample -------------------------------------------------------------------- [##########################################################################]100% waiting: 0 / active: 0 / done:10 ---- Requests ------------------------------------------------------------------ > Global (OK=10 KO=0 ) > sample_request (OK=10 KO=0 ) ================================================================================ Simulation Sample completed in 4 seconds Parsing log file(s)... Parsing log file(s) done Generating reports... ================================================================================ ---- Global Information -------------------------------------------------------- > request count 10 (OK=10 KO=0 ) > min response time 5 (OK=5 KO=- ) > max response time 23 (OK=23 KO=- ) > mean response time 13 (OK=13 KO=- ) > std deviation 5 (OK=5 KO=- ) > response time 50th percentile 14 (OK=14 KO=- ) > response time 75th percentile 15 (OK=15 KO=- ) > response time 95th percentile 20 (OK=20 KO=- ) > response time 99th percentile 22 (OK=22 KO=- ) > mean requests/sec 2 (OK=2 KO=- ) ---- Response Time Distribution ------------------------------------------------ > t < 800 ms 10 (100%) > 800 ms < t < 1200 ms 0 ( 0%) > t > 1200 ms 0 ( 0%) > failed 0 ( 0%) ================================================================================ Reports generated in 0s. Please open the following file: /Users/kk_Ataka/Downloads/gatling-charts-highcharts-bundle-2.2.1/results/sample-xxxxxxxxxxx/index.html ||<
  • 実行が終わったら result 下にレポートが出力されている
open results/sample-xxxxxxxxxxx/index.html

リクエスト間隔や数を変更するなら「シナリオの構成」部分に手を加えたら良い。

というような感じで、今回は単純なリクエストを送信するだけに使ったが、もっと凝った事ができるので、詳細はWEB+DB-PRESS-Vol.83を読む。

Rubyで自然言語っぽくcrontab管理できるwheneverを使う

あらすじ

  • cronタスクを書きたいけど、そのままctontabを書きかえたりするのはめんどいし怖い( crontab -r とか)
  • Rubyでcrontab管理をできるライブラリwheneverを使う

javan/whenever: Cron jobs in Ruby

Whenever is a Ruby gem that provides a clear syntax for writing and deploying cron jobs.

参考

環境

手順

  • Gemfile に以下を追記し、 bundle install
gem 'whenever', require: false
  • bundle exec wheneverrize . でスケジュール記述するファイルを作成する
$ bundle exec wheneverize .
[add] writing `./config/schedule.rb'
[done] wheneverized!
  • config/schedule.rb の記述はこんな感じで記述できる
    • every n hour など自然言語っぽく書けてわかりやすい
# ログ出力先
set :output, "log/cron.log"
# productionの場合はproductionに
set :environment, "development"
# 3時間毎、他にも色々書き方ある(公式のREADME参照)
every 3.hours do
  # Rails内のメソッド実行するときはrunner
  runner "MyModel.some_process"
  # rakeタスクの場合はrake
  rake "my:rake:task"
  # コマンド自体も記述できる
  command "/usr/bin/my_great_command"
end
# いわゆるcronの書式でも書ける
every '0 0 27-31 * *' do
  command "echo 'hello'"
end
crontab更新と削除
$ bundle exec whenever --clear-crontab
[write] crontab file 
$ bundle exec whenever --update-crontab
[write] crontab file updated
スケジュール確認
  • bundle exec whenever で確認
$ bundle exec whenever
0 * * * * /bin/bash -l -c 'cd /Users/kk_Ataka/github/sample_whenever 実行するタスク'
## [message] Above is your schedule file converted to cron syntax; your crontab file was not updated.
## [message] Run `whenever --help' for more options.
  • crontab -l でも反映されている事確認できる
# Begin Whenever generated tasks for: /Users/kk_Ataka/github/sample_whenever/config/schedule.rb
0 * * * * config/schedule.rbに定義したcron
# End Whenever generated tasks for: /Users/kk_Ataka/github/sample_whenever/config/schedule.rb
  • 同じサーバー内の複数のプロジェクトで whenever --update-crontab , whenever --clear-crontab を実行しても、そのプロジェクトに紐づくcronのみ削除されるので安心

ProGuardでAndroidアプリを難読化していく手順(良い方法があったら知りたい)

あらすじ

  • Androidアプリの難読化作業を最後にまとめて実施しようとしたら思いがけずハマった
  • しかし「こうすれば全部OK」という定石はなく、ライブラリの情報を読み、実際にアプリを実行していくしか方法がなさそう?
  • ベストプラクティスなどあれば教えて下さい…

参考

手順

最後に一気にやろうとすると、とにかくまずビルドが通らない。

まっさらなプロジェクトを用意して一つずつライブラリを入れてくのが良さそう。

BUILD SUCCESSFULになるまで
  • まっさらなプロジェクト(以下、確認用プロジェクト)を作る
    • その状態でProGuardを適用するように設定変更する
    • リリースビルド( gradlew assembleRelease など)が成功する事を確認する
  • 本プロジェクトで使用しているライブラリ( build.gradle に定義されているものなど)を確認用プロジェクトに追加していく
    • 一つ追加してはビルドが失敗しない事を確認する
    • 失敗した場合はエラーメッセージを確認する
    • 恐らく追加したライブラリに関連するエラーが出ているはずなので、該当ライブラリREADME/GitHub IssueにProGuardに関する記載があるか確認する
    • 記載があった場合、ProGuard設定を追加し再度ビルドする
    • …以上の手順を全ライブラリに対して行う
  • 並行して、ビルド成功した場合は本プロジェクトにProGuard設定を転記していっても良いかも
BUILD SUCCESSFULになったあと

難読化の影響で 処理呼び出し時にコケる 、というパターンもある。これは実際にapkを叩いてみるまでわからない模様。

  • PCとAndroid端末をUSBで接続する
  • リリース用apkをインストールする( adb install など)
  • adb logcat でログを確認できるようにしておく
  • 実機でコケる操作を行う
  • logcatからエラーを確認する
    • コケているライブラリのREADME/GitHub IssueにProGuardに関する記載があるか確認する

…という感じの繰り返しで確認していく。

ライブラリ追加時

ライブラリを新たに追加する場合は毎回

  • BUILD FAILEDにならない事を確認する
  • 実機確認で追加ライブラリを使用している処理を実行する

しかない?