ためすう
Ruby で alias を使う
2019-06-17やったこと
Ruby で alias を使ってみます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
調査
app/controllers/tasks_controller.rb
class TasksController < ApplicationController
def new
logger.debug(__method__)
end
def new222
logger.debug(__method__)
end
alias :new :new222
end
ログの確認
Started GET "/tasks/new" for ::1 at 2019-06-15 18:18:07 +0900
(0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
↳ /Users/xxxx/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activerecord-5.2.3/lib/active_record/log_subscriber.rb:98
path is /tasks/new
Processing by TasksController#new as HTML
new222
Rendering tasks/new.html.erb within layouts/tasks
Rendered tasks/new.html.erb within layouts/tasks (264.0ms)
Completed 200 OK in 290ms (Views: 282.6ms | ActiveRecord: 0.0ms)
new222 が呼ばれます。
参考
アジャイルソフトウェア開発の奥義 第7章 リファクタリング
2019-06-16「アジャイルソフトウェア開発の奥義」の読書メモです。
時々、個人の見解入りです。
腐敗するソフトウェアの兆候
硬さ
変更しにくいシステム
たった1つの変更で、それと依存関係のあるモジュールを芋づる式に変更しなければならないような場合、設計が「硬い」という。
もろさ
「もろさ」とは、たった1つの変更によって他の多くの部分が壊れてしまうような傾向があるとうことだ。
移植性のなさ
再利用が困難
扱いにくさ
- ソフトウェアの扱いにくさ
- 開発環境の扱いにくさ
不必要な複雑さ
設計している時点で不必要な要素が含まれている設計である。
必要になったタイミングで、最小限の修正をする方が良いと思います。
不必要な繰り返し
同じような構造を繰り返し含み、抽象化してまとめられる部分がまとまっていないソフトウェア
個人的に抽象化してあるとは、ポリモーフィズムを使っていることなのかなと考えています。
不透明さ
読みにくく、わかりにくい。その意図がうまく伝わってこないソフトウェア
ソフトウェアのプロジェクトにおいて最も不確実なものは仕様要求であることを忘れてはならない。仕様要求は常に不安定な状態にある。
設計にパッチを当て新しい要求に対応するような一時しのぎをするのではなく、将来同じような変更があった場合に対応できるように設計を改善するチャンスだととらえる。
Metrics optimization
学習目標
- Describe the role of correct metric optimization method in a competition
- Analyze new metrics
- Create constant baselines
- Recall the most important classification and regression metrics
- Describe what libraries can be used to optimize a particular metric
Motivation
Metrics
- 提出物の評価で使われるもの
- コンペによって異なるのは、何に対して最適化するのかが決まっているからである
- バリデーションデータのメトリクスを改善しても、テストデータのメトリクスが改善しないことがある
Regression metrics review I
Regression
- MSE, RMSE, R-squared
- MAE
- ®MSPE, MAPE
- ®MSLE
平均二乗誤差: MSE (Mean Square Error)
$$ MSE = 1/N * \sum_{i=1}^N (y_i - \hat{y_i})^2 $$
$$ RMSE = \sqrt{MSE} $$
R-squared
$$ R^2 = 1 - \frac{MSE}{\frac{1}{N}\sum_{i=1}^N (y_i - \bar{y_i})^2} $$
MSEが0のとき、R-squared は1
MSEが定数と等しいとき、R-squared は0
MAE: Mean Absolute Error
$$ MAE = \frac{1}{N}\sum_{i=1}^N|y_i - \hat{y_i}| $$
- MSE ほどには外れ値にペナルティを与えない
- 最適な定数は中央値
MAE vs MSE
- 外れ値があるなら、MAE
- ただし、外れ値があるのが正常なら、MSE
- 異常値であるなら、MAE
参考
アジャイルソフトウェア開発の奥義 第5章 リファクタリング
2019-06-15「アジャイルソフトウェア開発の奥義」の読書メモです。
時々、個人の見解入りです。
書き上げるモジュールと保守するモジュールのすべてを必ずリファクタリングすることを強く勧める。リファクタリングに費やす時間は、それをしなかったことで自分自身を含む関係者が将来費やすことになる労力に比べれば微々たるものだからだ。
ソフトウェアモジュールの3つの機能
- 特定の処理を実行する機能
- 変化を許容する機能
- 読み手にそのモジュールの意図を伝える機能
この章で書かれていないが、リファクタリングをするには、自動テストが書かれている必要があると思います。
自動テストされていれば、自動テストが用意されている分については挙動が変わっていないと保証できます。
Rails5 で sidekiq を使う
2019-06-15やったこと
Rails5 で sidekiq を使います。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
調査
インストールからやっていきます。
redis のインストール
$ brew install redis
$ redis-server --version
Redis server v=5.0.5 sha=00000000:0 malloc=libc bits=64 build=272e5301ea2dcb73
redisサーバーを起動します
$ redis-server /usr/local/etc/redis.conF
sidekiq のインストール
Gemfile
gem 'sidekiq', '~> 5.2', '>= 5.2.7'
$ bundle install
もしかしたら、エラーが出るかもしれないのでこちら見てみてください
Rails5 で bundle install が失敗する件 – ためすう
sidekiq の設定
config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
config.redis = { url: 'redis://localhost:6379'}
end
config/sidekiq.yml
:pidfile: ./tmp/pids/sidekiq.pid
:logfile: ./log/sidekiq.log
:queues:
- task
$ bundle exec sidekiq -C config/sidekiq.yml
sidekiq の ワーカー作成
app/workers/task_worker.rb
class TaskWorker
include Sidekiq::Worker
sidekiq_options queue: :task
def perform(id)
logger.debug('id 出力')
logger.debug(id)
end
end
※ ログを出力するには、設定する必要があるのですが、また今度。
Queue を登録
app/controllers/tasks_controller.rb
class TasksController < ApplicationController
def new
TaskWorker.perform_async 333
end
end
参考
Rails5 で bundle install が失敗する件
2019-06-15やったこと
Rails5 で sidekiq をインストールしようとしたところ、bundle install が失敗してしまいました。
今回、そのエラーを解消したいと思います。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
調査
問題の再現
Gemfile
gem 'sidekiq', '~> 5.2', '>= 5.2.7'
bundle install で失敗します
$ bundle install
The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`.
Fetching source index from https://rubygems.org/
Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from https://rubygems.org/
Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from https://rubygems.org/
Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from https://rubygems.org/
Could not fetch specs from https://rubygems.org/
解決までの過程
bundle update してみます
$ gem update --system
ERROR: While executing gem ... (Gem::RemoteFetcher::UnknownHostError)
timed out (https://rubygems.org/specs.4.8.gz)
失敗したので、次は、wget できるかやってみます
$ wget https://api.rubygems.org/specs.4.8.gz
--2019-06-15 11:30:11-- https://api.rubygems.org/specs.4.8.gz
Resolving api.rubygems.org... 2a04:4e42::70, 151.101.0.70, 151.101.192.70, ...
Connecting to api.rubygems.org|2a04:4e42::70|:443... failed: Operation timed out.
Connecting to api.rubygems.org|151.101.0.70|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3886510 (3.7M) [application/octet-stream]
Saving to: 'specs.4.8.gz'
specs.4.8.gz 100%[=====================================================================>] 3.71M 1.91MB/s in 1.9s
2019-06-15 11:31:29 (1.91 MB/s) - 'specs.4.8.gz' saved [3886510/3886510]
wget は出来ました。IPv6 での通信に失敗しているようです。
IPv4 を使うようにします。
該当ドメインの IP アドレスを調べます。
$ host api.rubygems.org
api.rubygems.org is an alias for rubygems.org.
rubygems.org has address 151.101.128.70
rubygems.org has address 151.101.0.70
rubygems.org has address 151.101.64.70
rubygems.org has address 151.101.192.70
rubygems.org has IPv6 address 2a04:4e42::70
rubygems.org mail is handled by 10 mxa.mailgun.org.
rubygems.org mail is handled by 10 mxb.mailgun.org.
hosts を書き換えてみます。
$ sudo vim /etc/hosts
151.101.128.70 api.rubygems.org
151.101.0.70 api.rubygems.org
151.101.64.70 api.rubygems.org
151.101.192.70 api.rubygems.org
$ bundle install
sidekiq がインストールできました。
参考
Rails5 で validate の on オプションを使う
2019-06-13やったこと
Rails5 で validate の on オプションを使います。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
調査
app/models/task.rb
class Task < ApplicationRecord
validates :name , uniqueness: true, on: :task_setup
end
task.name に “name1” で1件登録します。
$ rails c
Running via Spring preloader in process 23605
Loading development environment (Rails 5.2.3)
irb(main):001:0> a1 = Task.new
=> #<Task id: nil, created_at: nil, updated_at: nil, name: nil>
irb(main):002:0> a1.name = "name1"
=> "name1"
irb(main):003:0> a1.save
(0.1ms) begin transaction
Task Create (0.5ms) INSERT INTO "tasks" ("created_at", "updated_at", "name") VALUES (?, ?, ?) [["created_at", "2019-06-12 12:50:53.647258"], ["updated_at", "2019-06-12 12:50:53.647258"], ["name", "name1"]]
(0.8ms) commit transaction
=> true
save メソッドに context で指定すると、保存に失敗します。
irb(main):005:0> a2 = Task.new
=> #<Task id: nil, created_at: nil, updated_at: nil, name: nil>
irb(main):006:0> a2.name = "name1"
irb(main):007:0> a2.save(context: :task_setup)
(0.1ms) begin transaction
Task Exists (0.2ms) SELECT 1 AS one FROM "tasks" WHERE "tasks"."name" = ? LIMIT ? [["name", "name1"], ["LIMIT", 1]]
(0.1ms) rollback transaction
=> false
context を指定せずに save すると、保存できました。
irb(main):008:0> a2.save()
(0.1ms) begin transaction
Task Create (0.4ms) INSERT INTO "tasks" ("created_at", "updated_at", "name") VALUES (?, ?, ?) [["created_at", "2019-06-12 12:52:31.539434"], ["updated_at", "2019-06-12 12:52:31.539434"], ["name", "name1"]]
(0.8ms) commit transaction
=> true
参考
rspec の let と let!
2019-06-13やったこと
rspec の let と let! の違いについて調べてみます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
$ gem list | grep rspec-rails
rspec-rails (3.8.2)
調査
- let は遅延評価
- let! はテスト前に実行される
let を使う
spec/models/task6_spec.rb
require 'rails_helper'
RSpec.describe Task, type: :model do
let(:user) { create(:user) }
let(:task) { create(:task) }
it 'test1' do
end
end
出力結果
$ rspec spec/models/task6_spec.rb
.
Finished in 0.01818 seconds (files took 1.66 seconds to load)
1 example, 0 failures
let! を使う
spec/models/task6_spec.rb
require 'rails_helper'
RSpec.describe Task, type: :model do
let!(:user) { create(:user) }
let!(:task) { create(:task) }
it 'test1' do
end
end
出力結果
$ rspec spec/models/task6_spec.rb
F
Failures:
1) Task test1
Failure/Error: let!(:user) { create(:user) }
KeyError:
Factory not registered: "user"
# ./spec/models/task6_spec.rb:7:in `block (2 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# KeyError:
# key not found: "user"
# ./spec/models/task6_spec.rb:7:in `block (2 levels) in <top (required)>'
Finished in 0.00288 seconds (files took 1.65 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/models/task6_spec.rb:10 # Task test1
参考
Ruby で each_with_object を使う
2019-06-12やったこと
Ruby で each_with_object を使ってみます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
調査
test.rb
scores = { 'Carol' => 90, 'Alice' => 50, 'David' => 40, 'Bob' => 60 }
names = scores.each_with_object([]) do |(key, val), arr|
arr << val * 2 if val >= 60
end
p names
arr に値を入れていくイメージです。
出力結果
$ ruby test.rb
[180, 120]
参考
Rails5 で escape_javascript を使う
2019-06-12やったこと
Rails5 で escape_javascript を使ってみます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.3
調査
例えば、下記の view ファイルに書いてみます。
app/views/tasks/new.html.erb
<span>
<%= escape_javascript("111
222") %>
</span>
<span>
<%= escape_javascript("<script>alert(1111);</script>") %>
</span>
<span>
<%= "333
222" %>
</span>
出力結果
<span>
111\n222
</span>
<span>
<script>alert(1111);<\/script>
</span>
<span>
333
222
</span>
改行もエスケープされてます。