blog.waterlow.work

Ruby, Rails, js, etc...

【読書ノート】SOFT SKILLS ソフトウェア開発者の人生マニュアル(学び方を学ぼう、前半)

目的

soft skilsに載っている独学の方法をまとめる。(前半)

soft skilsという本がちょっと前に話題になっていたのですが、その中に「学び方を学ぼう」という章があります。

SOFT SKILLS ソフトウェア開発者の人生マニュアル

SOFT SKILLS ソフトウェア開発者の人生マニュアル

勉強本はちょこちょこ読んではいたのですが、ここまで技術的な勉強に最適化された内容には出会ったことがなく、参考にしたいと思いました。
今回は本の内容をまとめて、今後適宜見返して自分の勉強に役立てたいと思います。 10個のステップが登場するのですが、今回は1〜6まで記載しています。

学ぶことを学ぼう

技術を身につけるために知るべき3つのこと

  1. どうすれば始められるか(最低限の基礎知識)
  2. テーマの幅(規模、何ができるか)
  3. 基礎(基本的なユースケース、コアの20%はどこか)

10ステップシステム

上記の3つ(特に2,3)を知るのは簡単ではないので以下の10ステップを用意してアプローチする。

  1. 全体像をつかむ
  2. スコープを決める
  3. 成功の基準を決める
  4. 参考資料を見つける
  5. 学習プランを作る
  6. リソースをフィルターにかける
  7. 使い始められるようにする方法を学ぶ
  8. 遊び回る
  9. 役に立つことができるところまで学ぶ
  10. 教える

1. 全体像をつかむ

ブログポストや記事を読み漁る。持っている本のイントロダクションを読む。
数時間が目安。

2.スコープを決める

今回の勉強で何をどこまでやるのかを考える。時間も考慮する。本に載っていた例は以下。

元のテーマ 適切なスコープ
C#を学ぶ 簡単なコンソールアプリケーションを作るために必要なC#言語の基礎を学ぶ
写真を学ぶ ポートレート写真を撮影するためのデジタル写真術を学ぶ
Linuxを学ぶ Ubuntu Linuxをセットアップ、インストールする方法と基本機能の使い方を学ぶ

3.成功の基準を決める

成功を定義する明確で簡潔な文をつくる、これも書籍の例を参考に

悪い成功基準 いい成功基準
デジタルカメラでいい写真が撮れるようになる デジタルカメラの全てを使うことができ、それがどういうものかを説明でき、いつ、どのような理由でそれぞれの機能を使うべきかも言えるようになる
C#の基礎が身についている C#で主要な言語機能をすべて利用している小さなアプリケーションをかけるようになる
HTMLを使ってウェブページを構築する方法を知っている HTML5を使って、インターネット上に自分の履歴書と仕事の例を表示するホームページを作れるようになる

4.参考資料を見つける

ぐぐって本やコンテンツなど勉強の際に参考になりそうなものを探す。 soft skilsに載っていた参考資料のリソースの例は以下

  • ブログポスト
  • オンラインビデオ
  • 学ぼうとしているテーマについての知識を既に持っている専門家など
  • ポッドキャスト
  • ソースコード
  • サンプルプロジェクト
  • オンラインドキュメント

5.学習プランを作る

参考資料を流し読みして、どういう順序で勉強していくかを決める
他人がどう教えているのかも参考に

6.リソースにフィルタをかける

どの参考資料を使うか決める。本であれば、レビューを見て1,2冊に絞る。

まとめ

前半は以上です。 個々の内容で真新しい物はなさそうですが、ここまでしっかりガイドライン的に書いてあるので非常に有効かなと思いました。

また、1〜6ステップを見ると、計画の時点で非常にしっかりしていることが読み取れます。
計画の重要性という点で、かなり前のものですが以下の記事を思い出しました。

teruyastar.hatenablog.com

続きは後日。

【備忘録】Atomの今後使っていきたいキーバインディング

目的

勉強の復習と自分用チートシート目的。 最近Atom実践入門という本を読んで、まだまだAtomには知らない機能がたくさんあることを改めて感じました。

Atom実践入門──進化し続けるハッカブルなエディタ (WEB+DB PRESS plus)

Atom実践入門──進化し続けるハッカブルなエディタ (WEB+DB PRESS plus)

特にキーバインドに関しては、マウスカーソルでやるものをキーボードで完結させることができるためいろいろなことを効率化できる可能性があるのですが、いかんせん覚えづらいです。
そこで今回は、復習と自分用チートシート目的で、使えそうなキーバインドをまとめてみることにしました。

キーバインドまとめ

カーソル移動系

alt-shift-v:ページ最上部(カスタマイズ
alt-v :1ページ上(カスタマイズ
alt-shift-v:1行上
ctrl-b:1つ左
alt-b:1単語左
ctrl-a:行頭
ctrl-f:1つ右
alt-f:1単語右
ctrl-e:行末
ctrl-n:1行下
ctlr-v :1ページ下(カスタマイズ
ctrl-shift-v:ページ最下部(カスタマイズ

文字列操作系

ctrl-h:1文字削除(backspace)
ctrl-d:1文字削除(delete)
alt-h:1単語削除(backspace)
alt-d:1単語削除(delete)

検索系(cmd-fかcmd-shift-Fで検索窓を開いてから)

shift, shift-tab:テキストフィールドを行ったり来たり
alt-cmd-/正規表現使う/使わない([.*]みたいなボタン)
alt-cmd-c:大小文字区別しない/する([Aa]みたいなボタン)

その他

cmd-r:関数定義(symbols view)

Git Plus系

要インストール
shift-cmd-a a:add all & commit
shift-cmd-h:Git Plusの操作一覧(コマンドパレット風fizzy finder)

※以下キーバインドではないですが、よく使いそうなので
操作一覧でplを入力してenter:git pull
操作一覧でnb〃:git checkout -b
操作一覧でda〃:git diff

term3系

要インストール
cmd-k t t:ターミナルオープン

まとめ

ひとまず、今後使っていこうというキーバインドのみまとめてみました。自分用備忘録なので、今後もちょいちょいちょい追加していこうと思います。
いろんな人のキーバインドやおすすめパッケージ等知りたいな-と思いました。
あと、基本的に「エンター以外はホームポジションから動かないようにする」がモチベーションだったのですが、ちょいちょいカスタマイズしているうちに、emacsvimキーバインドそのまま使ったほうがいいかなという気がしてきました^^;

やること

この記事のアップデート
暇な時にキーバインドやパッケージを調べる

参考

blog.jnito.com

【Rails】DatabaseCleaner導入でテストが遅くなった話

現在仕事のrailsプロジェクトで、feature specの導入のところでdatabase_cleanerの設定でいろいろ時間を費やしたため、時間を費やした箇所についてまとめておこうと思います。 その時のRailsバージョン/Rubyバージョン:3.2.11/1.9.3。古い!

DatabaseCleanerとは

github.com databaseのお掃除をしてくれるgem。主にrspecやminitestの際に、「テストが終わったらテストデータを全部消したい」みたいなモチベーションで使われる。

使い方

簡潔にまとまっている記事がたくさんあるので省略します。

【Ruby on Rails】Database Cleanerによるテストデータの消去 | Developers.IO
RSpec + database_cleaner で永続的なマスターデータを扱う - 彼女からは、おいちゃんと呼ばれています

困ったところ(今回のメイン)

DatabaseCleanerを使いはじめると、急にテストが遅くなる

rspecである程度テストが書いてあるプロジェクトにDatabaseCleanerを入れてみたのですがテストが急に遅くなりました。 今回実施した導入方法は以下になります。
* Gemfile

gem 'database_cleaner'
  • spec/spec_helper.rb
RSpec.configure do |config|

  # これより前の設定は省略...
 
  # config.use_transactional_fixturesはコメントアウト
  # config.use_transactional_fixtures = true
  
  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

log/test.logをみていると、同じクエリログが何回も出ていました。よくよく調べてみるとspec/fixturesディレクトリで定義しているfixtureをテストのたびにDBにinsertしてtruncateしているようでした。DatabaseCleanerを入れるまでは以下の設定が入っていたのでfixtureは一番最初にinsertして、テスト毎に入れたり消したりされることはありません。DBのクリーンはrspecに入っている機能で行う模様です。

config.use_transactional_fixtures = true
config.global_fixtures = :all

解決方法

spec/spec_helper.rbのDatabaseCleanerのstrategyをtransactionにしました。

  # これより前の設定は省略

  # config.use_transactional_fixtures = true
  # config.global_fixtures = :all
  
  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
    dir = "#{Rails.root}/spec/fixtures"
    Dir["#{dir}/*.yml"].map { |f| f[(dir.size + 1)..-5] }.each do |fixture_file|
      ActiveRecord::Fixtures.create_fixtures(dir, fixture_file)
    end
  end

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

要約すると、①fixtureは自力で入れる。②DatabaseCleanerのstrategyをtransactionにする。
です。rspecのtransactionを使うとfeature specは上手く動かない場合があるのですが、DatabaseCleanerの場合はひとまず大丈夫そうでした。
テストの速度も以前通りになりました。

その他

他のプロジェクト(Rails4系)でtruncate→transactionの設定を試したところ、残念ながらテストは早くならず逆に遅くなってしまいました。
テーブル数、データ量等の違いによって結果が異なりそうなので、ベストな設定はこれ!というものはなさそう。実は、パーフェクトRuby on Railsにはfeature spec用の設定としてはまた若干違った設定が書かれています。
他にもいろいろ設定があるようで、DatabaseCleaner.strategy = :truncation:exceptというオプションを与えてtruncateするテーブルを制限する方法もあるようです。

悩んでるポイントはみんな同じ!?「Rubyistのためのテストコード相談会」の質疑応答まとめ - give IT a try

database_cleaner transactionの設定 - Qiita

まとめ

rspecやDatabaseCleanerの設定にはいろいろあるので、テストの量やDBの状態に応じてベストな設定を模索していきましょう。
もっと良い設定があればぜひ教えてほしいです!

【Ruby】配列の&と|の機能について

特殊なルールで配列を並び直す。たとえば
['いち', 'に', '', 'よん', 'なな', 'ご']
から
['に', 'よん','いち', 'ご', 'なな']
を作りたい(奇数が優先、2で割る等の数値演算はできない)ときはどうするか。
①まず以下のようにやることを思いついた。

['いち', '', '', 'よん', 'なな', '']
  .reject { |v| v.nil? || v == '' }
  .sort_by { |v| %w(に よん ろく はち いち さん ご なな).index(v) }

②ドキュメントを読んでいた時にArray#|のところで「preserving the order from the original array」という記述があり
 Array#&もやっぱりそうだった

%w(に よん ろく はち いち さん ご なな) &
['いち', '', '', 'よん', 'なな', '']

めでたしめでたし。これを期に、必要に迫られる前にドキュメントを読んでおくくせを付けておこうと思います! もっと良い方法がありましたらぜひ。

【ActiveRecord】exists?の引数にwhereクエリの内容を書いてみたらうまくいかない。

Person.exists?(1) # => true
# SELECT  1 AS one FROM `job_offers`  WHERE `job_offers`.`id` = 1 LIMIT 1
Person.exists?('id = 1') #=> false
# SELECT  1 AS one FROM `job_offers`  WHERE `job_offers`.`id` = 0 LIMIT 1

なぜか?
exists?にArrayもしくはHashを引数で渡すと、where(condition).limit(1)とほぼ同じ挙動をする。
それ以外の引数を渡すと主キーでの検索を行おうとする。
ただし、findではなくPerson.where(id: 'id = 1')が呼ばれ、(この後はソースを読み切れていないが)エラーにならずWHERE job_offers.id = 0なんてクエリが発行されてしまうらしい。

解決策
whereと同じような挙動を期待する場合はArrayもしくはHashを与えれば良い。 したがって今回の場合であれば

Person.exists?(['id = 1']) #=> true
# SELECT  1 AS one FROM `job_offers`  WHERE (id = 1) LIMIT 1

となる。(カッコが付いてしまうのは仕方なさそう。) ActiveRecord:: FinderMethods#exists?

railsエンジニアの勉強法(読む本とか)まとめ

初心者レベルを脱却するための記事とか読む本とか、いろいろと溜まってきたのでまとめておこうと思います。
勉強するのは常に一人なので、歩みは非常に鈍いのですが…

Rails で "とりあえず動くコード" を書けるようになった人が次に遭遇する問題とそれを解決してくれる本まとめ - 彼女からは、おいちゃんと呼ばれています

Rails Tutorial以前 - Web系エンジニア入門レベルを達成するには - - 国境の南

新卒ソフトウェアエンジニアのための技術書100冊 - クックパッド開発者ブログ


やること多々ですね!!
デザインパターンとかオブジェクト指向をちゃんと勉強したければJavaはある程度読めたほうが良さそう。「オブジェクト指向のこころ」という本を読んでいて思いました。

[追記 6/19]
Railsアプリケーション構築ガイド — Railsアプリケーション構築ガイド
Ruby on Rails チュートリアル:実例を使って Rails を学ぼう
Rails Girls - Japanese

【ruby】モジュールをextendした時の動き

タイトルそのまんまです。 疑問だったのでいろいろ調べてみたのですが、メタプログラミングRubyの特異クラスのところを読んでいたらわかりました。 オブジェクトからモジュールをextendすると、そのメソッドはオブジェクトのクラスではなく特異クラスに入る。

class Object
  def eigenclass
    class << self; self; end
  end
end

class C; end

module M
  def my_singleton_method
    'obj#my_singleton_method()'
  end
end

obj = C.new
obj.extend M

obj.eigenclass.instance_methods.grep(/my_/) #=>[:my_singleton_method]
obj.class.instance_methods.grep(/my_/) #=>[]

だから、もしオブジェクトに対してextendする予定のモジュールに定数とか名前空間を更に定義している場合、外からは非常にアクセスしづらい。

class C
  C_VAL = :c
end

module M
  M_VAL = :m
end

obj = C.new
obj.extend M
obj.class::C_VAL #=> :c
obj.singleton_class::M_VAL #=> :m
obj.class::M_VAL #=> uninitialized constant C::M_VAL

もし2つモジュールをインクルードするとどうなるかというと…

class C; end
module M; end
module N; end

obj = C.new
obj.extend M
obj.extend N
obj.singleton_class.ancestors
# => [M, C, Object, Kernel, BasicObject]

特異クラスで継承が行われる。