雑草SEの備忘録

東大を卒業し、SEとして働くことになった。備忘録的に作業を綴る。

unless A && Bを使っても読める場合

以前

unless A && B

は辞めたいという記事を書きました。
normalse.hatenablog.jp
しかし、その後、場合によっては使用しても良いという意見になりましたので、追記します。
「場合」というのは、guard節を使うとき。

def hoge
  return unless A && B
  something_hoge
end

のような場合です。このようなソースコードの読み方は、A && Bのときのみsomething_hogeを実行すると呼びます。すなわち、

def hoge
  if A && B
    something_hoge
  end
end

と同じということですね。この二つは等価で、十分に読めるので、guard節でunlessを使う場合は、unless A && Bも許容できるのではないかと思いました。

git submoduleのちょっとしたこと

git submoduleでsubmoduleが更新されたから自分のブランチでも反映させたいという場合、

git submodule foreach git pull origin master

こう叩くと、すべてのsubmoduleが最新化されます。 あとは普通にcommitすればOKです。

自分で更新する場合はいいのですが、git submoduleを使っていると、誰かがsubmoduleを更新してcommitしたあと差分が見えてしまうことがあります。具体的には次の画像のような感じです。git stはgit statusのエイリアスです。
f:id:smartenergy:20170102135240p:plain:w360
これ、気持ち悪いですよね。submoduleの方は触ってないから差分を解消したい!そういうときには

git submodule update

をします。
f:id:smartenergy:20170102135644p:plain
すると、差分は解消されます。
f:id:smartenergy:20170102135716p:plain:w300
デザイナーさんとかで特にsubmoduleを触らないけど、メインのリポジトリは触って困るという場合の備忘録でした。

RailsリポジトリをTravisCI, CodeCov, CodeClimateと連携

Ruby on Railsエンジニア2年目で初めて本格的にRails newをして諸々の初期設定をしたので備忘録的に作業を綴ります。

CIツールはCircleCIなどいくつかありますが、今回はTravisCIを利用させていただきました。

TravisCIの設定

language: ruby

rvm:
 - 2.3.1
services:
 - postgresql
bundler_args: '--without development --deployment'
cache: bundler
before_script:
  - cp config/database.travis.yml config/database.yml
  - bundle exec rake db:create
  - bundle exec rake db:migrate
script:
  - bundle exec rspec spec
  • config/database.travis.ymlを追加します。↑のbefore_scriptのところでcpしているファイルですね。
test:
  adapter: postgresql
  database: travis_ci_test
  username: postgres
  • Travis CIのバッチをREADME.mdに追加したい場合は追加してください。
[![Build Status](https://travis-ci.org/[your_account]/[your_repository].svg?branch=master)](https://travis-ci.org/[your_account]/[your_repository])

CodeCovの設定

gem install travis

travisのgemをインストールします。Gemfileに書いてbundle管理下にしても良いかと思います。

group :development do
   gem 'travis'
end
  • spec/spec_helper.rbを修正。(rspecを使っている場合)
require 'simplecov'

SimpleCov.start 'rails'

if ENV['CODECOV_TOKEN']
  require 'codecov'
  SimpleCov.formatter =  SimpleCov::Formatter::Codecov
end

RSpec.configure do |config|
  (省略)
  • coverageディレクトリができるので、git管理から外しておくと良いでしょう。
/coverage
  • CodeCovに行ってGitHubでSignUpし、自分のリポジトリを追加します。
    • Repository Upload Tokenが出てくるのでコピーしておきます。
  • travisコマンドでCODECOV_TOKENを暗号化します。
    • Gemfileに追加した場合、bundle execが必要な場合あります。
travis encrypt CODECOV_TOKEN=[Repository Upload Token]
  • そうすると次のような意味不明な文字の羅列が出てくるのでそれをコピーし、
secure: "zaZ/DaFV・・・"
  • .travis.ymlに追加します。(本当はもっと長い。ターミナルの横幅にもよるが、100文字ぐらいで6行ほど)
env:
  global:
    - secure: "zaZ/DaFV・・・"
  • これでGitHubにpushしてテストが終わると自動的にCodeCovに情報が通知され、カバレッジが見れるようになります。
  • バッジをREADEME.mdにつけたい方は、以下のようなコードを埋め込んでください。CodeCovの画面上からも取得できます。
[![codecov.io](https://codecov.io/github/[your_account]/[your_repository]/coverage.svg?branch=master)](https://codecov.io/github/[your_account]/[your_repository]?branch=master)

CodeClimateとの連携

  • カバレッジの取得だけでよければCodeCovでいいかと思います。逆に、カバレッジ以外のメトリクスも欲しければCodeClimateを利用して、CodeCovは必要ないでしょう。今回は欲張り的に2つ入れてみたいと思います。
  • カバレッジを取得しないのであれば、CodeClimateのサイトに行きGitHubでSignUpし、自分のリポジトリを追加すれば良いです。
  • バッチをREADME.mdに追加したい場合は、以下のような感じで。
[![Code Climate](https://codeclimate.com/github/[your_account]/[your_repository]/badges/gpa.svg)](https://codeclimate.com/github/[your_account]/[your_repository])
  • カバレッジを取得したい場合は、CodeClimateの右下にあるTest Coverageのところからトークンを取得し、CodeCovと同じように暗号化します。
travis encrypt CODECLIMATE_REPO_TOKEN=[token]
  • .travis.ymlに追加する。
env:
  global:
    - secure: '・・・' # CodeCov用
    - secure: '・・・' # CodeClimate用
  • .travis.ymlにCodeClimateに送信するコマンドを追加します。
after_success:
  - bundle exec codeclimate-test-reporter

以上、一通り作業を終えてから振り返り的にメモをしているので抜け漏れがあるかもしれませんがその際はご指摘お願いします。

rubyで再帰

先日、関数型の初心者の勉強会に参加してきました。
私は、もともと情報系の学科を卒業したわけではないので、アルゴリズムや関数型の考え方は全くの初心者です。

なので、再帰の考え方に慣れるのにとても大変でした。まだ慣れているとは言えないレベルですが。。
備忘録もかねて、rubyで実装してみたいと思います。

今回はmapを実装してみたいと思います。rubyのmap関数はよく使うと思いますが、
配列の各要素に対してある処理を施し同じく配列を返す関数です。

こんな感じですね。

["1", "2", "3"].map { |num| num.to_i }
["1", "2", "3"].map(&:to_i)

各要素をFixnum型にしています。

今回のmapは引数は二つ。
一つ目は処理の対象となる配列。二つ目は処理を施したい関数です。
rubyの場合、関数をオブジェクトにするのはprocとかlambdaですので、これを利用します。

※proc、lambdaについてはこのあたりの記事がわかりやすいです。
http://qiita.com/kidach1/items/15cfee9ec66804c3afd2
Rubyの ブロック、Proc.new、lambdaの違い - Qiita

ではさっそく、こんな感じで実装してみました。

def map(array, f)
  return [] if array.empty?
  [f.call(array[0])] + map(array[1..-1], f) 
end
# もちろんarray.firstやarray.drop(0)を利用してもOK。

1個目の要素に処理をして残りの配列をもう一度自分自身に引き渡す。
実際に手で処理を追っていくと理解が深まりそうです。
だんだんやっていくと空配列になるので、そのときは処理は終わるようにしています。

実際に使ってみた例はこんな感じです。

[1] pry(main)> def map(array, f)
[1] pry(main)*   return [] if array.empty?
[1] pry(main)*   [f.call(array[0])] + map(array[1..-1], f)
[1] pry(main)* end
=> :map
[2] pry(main)> twice = ->(x) { x * 2 }
=> #<Proc:0x007fc3c2c82700@(pry):5 (lambda)>
[3] pry(main)> map([1,2,3,4,5], twice)
=> [2, 4, 6, 8, 10]

ただし、このような再帰関数でうと、関数呼び出しの階数が深くなるとスタックオーバーフローが発生してしまいます。
そこで使うのが末尾再帰というものだそうです。

実装してみた結果がこんな感じです。

def map(array, f, result = [])
  return result if array.empty?
  map(array[1..-1], f, result + [f.call(array[0])])
end

今度はどんどんresultに新しい配列が入っていくので空配列になったときはresultを返すようにします。

配列の掛け算や足し算をする処理なんかも再帰を使って書くとすっきりします。

def sum(array)
  return 0 if array.empty?
  array[0] + sum(array[1..-1])
end

def product(array)
  return 1 if array.empty?
  array[0] * product(array[1..-1])
end

左畳み込みと右畳み込みがあり、今回は、配列の左側から処理をしていっているので、左畳み込みで処理をしてみました。

「オブジェクト指向設計実践ガイド」を読んだ感想

9月2日に発売になったSandi Metz著の「Practical Object-Oriented Design in Ruby: An Agile Primer (Addison-Wesley Professional Ruby) 」の邦訳版です。

私はプログラムの世界には新卒で入社したSIerからJavaから学んだので、新卒の研修ではオブジェクト指向については基本から学びましたが、実戦経験ではRubyがほとんどです。

ただ、これまでプログラムを書いてきてもオブジェクト指向についてなんとなくこんなもんかなーと思いながら先輩エンジニア方のアドバイスもいただきながら書いてきました。

ここらで今一度整理してオブジェクト指向で実装するにはどうしたら良いかを学んでみたいと思い、本書を購入しました。(正確には会社で買ってもらったので、読み終わったら会社の本棚に行きます)

 

この本の英語版自体は、ドイツ人が持っていたので、ちらっと読んだことがあります。それは以前の記事でも少し紹介しました。本書を読む目的としてはドイツ人とのコミュニケーションを円滑に進めるためというのも大きいです。

この本の感想としては発売前に書いてくれている方がいたので、概ね同意します。

d.hatena.ne.jp

とくに注意書きの*3については、私も以前の記事で書いた通り違和感を覚えており、このブログの方に共感をいたしました。

 

さて、私独自の感想については以下のような感じです。

よかった点
  • ダッグタイピングや継承のまわりは勉強になりました。特に継承する際、initializeをオーバーライドしてsuperを使ったりせずにpost_initializeメソッドなどを作ってそれをオーバーライドするというのは考えたことのなかった発想でした。
  • コンポジションのところでOpenStruct使えば良いんじゃない?と思って読み進めたらイメージ通りに実装していて、自分の考え方はあながち間違っていなかったと自信が少しつきました。
悪かった点
  • 邦訳が悪いのか、それともそもそもの英語が悪いのかわからないのですが、文章が少し冗長に感じました。コードで説明してくれているので、勘の良い人はコードのbefore、afterを見るだけで理解出来ると思います。
  • リファクタリング:Rubyエディション を読んだときは心揺さぶられたのですが、そこまでのものではありませんでした。一般的なオブジェクト志向の知識を持っていて、Effective Rubyリファクタリング:Rubyエディション を読んだことのある人はさらっと読む程度で良いのではないかと思います。

全体的にはAmazon的レビューで星3つ ぐらいでしょうか。

楽々ERDレッスン

前々回の記事で、リレーショナルデータベースに関する良書として、こちらの本の紹介をしました。

今回は、前々回も紹介した、楽々ERDレッスンも読み終わったので紹介したいと思います。

この本は大きく3つの部に分かれています。第1部のDB設計総論、第2部のRDBMS総論、第3部の楽々ERDレッスンです。

 

第1部のDB設計総論では、データベース設計の手順について書かれているのですが、その中で口を酸っぱくして書かれているのは、アイデンティファイアをつけるべきだということです。ここでいうアイデンティファイアとは、いわゆるid。Railsを触ったことのある方なら、テーブルをつけると問答無用で各タプルにidが付与されます。これがこの本でいうアイデンティファイアであると言えます。

純粋なテーブル設計をしていた人がRailsを触ると、何勝手にid振ってくれてんねん!と思う人もいると思います。かくいう私がそうでした。私はRailsをやるまえにデータベーススペシャリストの資格を取得していたので、複合キーなども駆使して他テーブルと連関づけるというのを普通に(社会人2年目の4月に資格をとったので、実務上の経験ではなく、試験の問題上でですが)やっていました。そういう人から見ると全てのデータにidを付与するというのは奇妙に感じます。しかし、楽々ERDレッスンでは、idを付与することがいかに有用かが書かれています。詳細は本を読んでいただくとして(きちんと説明しきる自信もない)、実はこれは私もRailsを始めて1年近く経ちましたが、実感として感じていることです。idの付与があることで他テーブルとの関連づけが非常に楽になりました。

 

第2部は経営資産としてのRDBMSの重要性について書かれています。データはもはや経営にとって欠かせないものになっています。これをいかに管理し、いかに活用するかが競争力のある会社になるかどうかの肝となってくるのは言うまでもありません。経営資産であるデータをうまく管理すること、そのためには、ERDを作ってデータを正規化(筆者は数学的正規化と業務的正規化の両方を考える必要があると言っています)する必要があり、その過程で既存の業務の見直しもできることになります。

確かに、RDBMSにデータを落とし込めるということは、既存の業務を正しく理解していないといけません。ERDを書いてデータを管理するということは、業務理解が大前提です。これは現実の世界と向き合うということなので、ただ機械と向き合えば良いプログラミングの世界とは違ったスキルが求められます。個人的には、ソフトウェアエンジニアとしてこの部分こそが一番面白みのあるところなのではないかと思っています。

 

第3部はいよいよ楽々ERDレッスン。ここでは、実際の例を元にERDを作成する過程を説明しています。ファストフード店でのレシートや病院の明細書兼領収書等をもとに説明されています。具体例があるので、まずは自分でERDをつくってみて、本書と照らし合わせてみるといった実践的な使い方もできます。

 

この本を読んでよかったことは、Railsが強制する各データにidを付与するということの重要性です。Railsを1年やってみて、その有用性を感じながらも経験者に裏付けされた理由は非常に納得感のあるものです。

また、単に教科書的なリレーショナルデータベースの知識ではなく、経営とも密接に結びついたデータベースを、ともするときれいな実装や理想ばかりにとらわれがちなエンジニアに、それをやる本来の目的を思い出してくれてくれます。

また、この本は初版が2006年ですが、10年をたった今でも色褪せないリレーショナルデータベースの技術であることを確信させてくれます。また、データベースの正規化をすると性能が悪くなるからあえて正規化しないという意見を持つ人もいますが、こういう立場に対して、

今のCPUのスペックは一体どれほどのものかということです。あるいはメモリです。RAMの容量がもう平気で1Gを超えられるようになっている状態で、ましてOSが64ビットに突入している状況において、20年ほど前のハードスペックを前提にした方法論をいまだに引きずっているというのは、ナンセンスではないのかということです。

(羽生章洋「楽々ERDレッスン」p 99)

 

と丁寧な口調でこき下ろしています。

10年前の書籍においてもこのように言われているのですから、まして2016年の今となっては、ということです。

 

最後に、前々回の記事でも書きましたが、@t_wadaさんに勧められたデータベース関連の書籍を改めて載せてこの記事を締めくくりたいと思います。

Rails 5でdraperを使う(2016年8月27日現在)

Rail 5でdraper(ActiveRecordをdecorateしてくれるgem)を使おうと思ったら、少しつっかかったのでメモ。
普通に、draperと書くと、

  gem 'draper'

2.1.0がinstallされてしまう。
そうすると、rails consoleとかしたときに、

/Users/user_name/.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/draper-2.1.0/lib/draper.rb:5:in `require': cannot load such file -- active_model/serializers/xml (LoadError)

のエラーが出る。
これは、 active_model/serializers/xmlがgem化されて、デフォルトではインストールされなくなったからである。

参考:
Remove XML Serialization from core by zzak · Pull Request #21161 · rails/rails · GitHub
Rails5 に Draper 導入した際にエラーが出た - Yamakichi’s blog

それで、

  gem 'activemodel-serializers-xml', git: 'https://github.com/rails/activemodel-serializers-xml'

とすると、ここの部分は抜ける。
しかし、次にこのエラーが出る。

/Users/user_name/.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/actionpack-5.0.0/lib/action_controller/test_case.rb:49:in `initialize': wrong number of arguments (0 for 2) (ArgumentError)

記事によっては、これは、rails5のブランチから持ってこれば良いという記事もあり、これでも動く。

gem 'draper', github: 'audionerd/draper', branch: 'rails5'

あるいは、3.0.0.pre1が公開されているので、それを使えば良いだろう。

gem 'draper', '>= 3.0.0.pre1'

これでbundle installをすると、

Installing activemodel-serializers-xml 1.0.1
Installing draper 3.0.0.pre1 (was 2.1.0)

と、activemodel-serializers-xmlも入れてくれる。もうすぐrails5対応のdraperが出るであろうからこの記事の賞味期限も短いだろうけれども。。

(2016/08/28 追記)
Rails 5でDraperを使ったら、ControllerからXxxxxDecoratorが呼べなかったorz...