kasei_sanのブログ

かせいさんのIT系のおぼえがきです。胡乱の方はnoteとtwitterへ

自分の考えるリファクタリング指針

なにこれ?

文書化して明確にしてみよう

目次

  1. 何故リファクタリングをするか?
  2. リファクタリングの優先順位
  3. 性能改善との兼ね合い
  4. どこまでリファクタリングすべきか?

1. 何故リファクタリングをするか?

  • 可読性を上げるため
    • 何故可読性を上げるか?
      • 品質を上げるため
      • 開発速度を上げるため
  • 可読性の高いコードの利点
    • バグを発見しやすい(品質up)
    • 不具合発覚時に修正がし易い(品質up)
    • 機能の追加がしやすい(開発速度up)
    • 再利用しやすい(開発速度up)

ぶっちゃけもう二度と機能追加/修正をしないコードはリファクタリングする必要はない

  • でもなんだかんだ手を入れる事になるんだよね...

2. リファクタリングの優先順位

テスト -> リファクタリング -> 機能追加

3. 性能改善との兼ね合い

  • 可読性を上げたために速度が遅くなった! なんてことはあんまりないので、そこまで気にしなくて良いと思う
    • 理想をいえばCIに性能計測を仕込んで、リファクタリング前後で計測できると良いのだけど...
  • リファクタリングと性能改善は別の作業なので、同時に行わない

4. どこまでリファクタリングすべきか?

個人的な指針なので異論はあると思う

自己満足のリファクタリングはしない

必要に応じたリファクタリングをすべき

リファクタリング前に問うこと

リファクタリングをすべきとき

  • 機能追加の前
    • 積極的にすべき
    • コードを理解するために
    • 追加すべきコードの量を減らすために(品質/生産性up)
  • 機能追加の後
    • コードレビュー時など
    • リファクタリングが行われる最後のチャンスと思っても良いかもしれない
  • 汚いコードを見つけた時
    • ただし、他の作業との優先度は兼ね合うべき
  • 性急な機能追加が一区切りついた時
    • 一区切りつく前に、生産性や品質について課題が発生している場合は絶対にやるべき
    • プロダクトオーナーに了承を取って、一定の期間をリファクタリングに費やす
      • これ以降の生産性や品質が上がります! という形で説得する
      • 課題感を共有できていれば説得できるはず

Serverspec本どくしょかんそうぶん

Serverspec

Serverspec

読書メモ

かんそう

  • set_property, property 大事
  • set で使える設定の一覧って、公式ドキュメントのどこにあるの?

作者のスタンス

  • テストを実行することに注力していて、どのサーバに行うとか、サーバ毎の違いを吸収するとかは自分でなんとかしてね!
    • その「自分でなんとかしてね」を実現するライブラリっていろいろありそうだけどどうなのだろう
  • 構成管理ツールとの連携はしない
    • サーバの構成のテストはするけど、構成管理ツールが正しく動作しているかは知らない
    • 構成管理ツールの設定をする人が間違えていないか? 意図しない変更を発生させていないか? を保証する

課題

  • linux系で理解が足りていないことが多い
  • Infratasrer, test kitchen 気になる
  • consul 理解が足りていない
  • Dockerも手を付けたい

【持ってきてよかったもの】4泊6日のオーストラリア旅行に行って【持っていった方がよかったもの】

家庭の用事で4泊6日のオーストラリア旅行に行ってきました

次回の備忘のために、持ってきてよかったものと、持って行ったほうが良かったものを記します

良かったもの

ファーストクラスラウンジのチケット

  • ヤフオクで1枚3500円程度で購入
  • ラウンジ以外に、ちょっとしたレストランでディナーが食べれる
  • 親同伴だったので、ちょっとした親孝行風ができて良かったw
  • ラウンジチケットを見せる前に、エコノミーの航空券を提出したら「お前のラウンジはここじゃねえよ」と遠回しに言われて悲しかった...

SIMフリーのモバイルルータ

  • 海外で気兼ねなくネットができるのはすごく良い!
  • GL04Pジモティーにて5000円弱で購入
  • SIMはOptusを使用。設定方法はSIMが梱包されている紙に書いてある
  • 1日2$で500MBまでのプランがあると、いくつかのblogにあったが、見つけられず(&尋ねても不明だった)
  • 仕方なく1G/10$のプランを選ぶが、何かしらのソフトウェアアップデートが起動し、600M近くを浪費...
  • その後、追加で3G(30$)を購入
  • SMSを使った残額確認や、持ち歩く機器が1個減るので、可能ならSIMフリーのスマートフォンの方が便利

モバイルバッテリー

  • モバイルルータと、iPhoneが1日出歩いてると持たないので必須
  • 多少重くても大容量であればあるだけ良いと思っている
  • 自分は、Anker Astro M3 13000mAhを使用中

iPhone (google Maps!)

  • バス乗車時、目的地と現在地が一発で判断できるのは精神にとても良い
  • 公共交通機関が発達している街の場合、ルート検索がとても便利!
  • ホテルまで迷わず到着
  • あと、現在地の近くの観光地やレストランを一覧表示してくれる機能を初めて知った...

ゴミ袋

  • 100円ショップの20枚位入っているものを1袋
  • 何かと使いみちが
  • 飛行機内等でゴミ袋に
  • 着終わった服入れに
  • おみやげ入れに
  • まるめて割れ物のガードに

歯ブラシ

  • 飛行機に持ち込んで寝る前に使用
  • 後海外のホテルでは大抵歯ブラシが無いので注意!

100円ショップの物干し

  • 靴下や下着は最低限持って行って、洗面台で洗濯して干した
  • あと寝る前にジーンズを干しておくと、後日履くときに少しさっぱり

(シドニー限定)Operlカード

  • suica的なプリペイドSIM
  • 電車、バス、路面電車、フェリーがこれ1枚
  • 駅近くのお店でタダで貰えて、その場でデポジット可能(最低10$
  • 料金キャップ制なのでお得
    • 平日15$、休日2.5$!
    • 空港に電車で行くときは、空港税が別料金
  • 時間によってはバスはOperlカード限定らしい

持ってくれば良かったと思ったもの

スリッパ

  • 機内、ホテル(備え付けが無かった!) であると便利
  • シャワーの後も履くので、サンダル的なものの方がよいかも

給電可能なusbハブ

  • 変換プラグ2個では足りず
  • モバイルルータとモバイルバッテリーと、iPhoneをまとめて充電したかった

長めのUSBケーブル

  • 飛行機の充電ポートが大体変な位置にあるので長いほうが便利

英語力(だいじ

そんな感じでした

【1日1gem】 rspec3 でも its が使いたい! rspec/rspec-its

1日1gemとは

最近好きなgemってありますか? という質問に自分が答えられるように始めたgemを紹介する記事

rspec/rspec-its

https://github.com/rspec/rspec-its

何をするの?

rspec3 で core から無くなった、 its を復活させる gem

  • 正確には、 its が別gemに分離した

サンプル

require_relative '../lib/hoge'

RSpec.describe Hoge do
  let(:message){ 'hello' }
  subject { Hoge.new(message) }

  # こんな風に書き換えられる
  #it { expect(subject.message).to eq(message) }
  its(:message) { is_expected.to eq(message) }

  # ネストできる
  its('say.hello') { is_expected.to eq('hello') }

  describe '#saids' do
    before do
      @hoge = Hoge.new(message)
      @hoge.say.hello
      @hoge.say.hoo
    end
    subject { @hoge }
    # 複数型なら `are_expected`
    its('saids') { are_expected.to eq(%w[hello hoo]) }

    describe 'array' do
      subject { @hoge.saids }
      # 配列の要素指定
      its([1]) { is_expected.to eq('hoo') }
    end
  end
end

そもそもなんで its が core から無くなったの?

ここに、rspec の中の人のコメントがある

Explanation for why `its` will be removed from rspec-3 · GitHub

要約すると、 its を使った場合に、rspecの出力結果が直感的でなくなって、デバッグに支障がでると思うので辞めたとのこと ただ、個人的にはあんまり納得いってない

  • コメントにある it { expect(subject.name).to eq "Bob" } みたいに書いた場合、 its と変わんないのに、ただコードが長くなるだけでないの? という疑問への回答が無い
  • 悪い例が書かれているけど、良い例が無いので、「じゃあどうするのが理想なの?」への回答が無い
  • そもそも、rspec って、テストコードを英文と一致させることを諦めてなかったっけ?

ActiveRecordeの関連付けで、class名と異なる関連名を使いたい場合、 class_name オプションを使う

こんな場合

class Item < ActiveRecord::Base
  has_one :item_detail, dependent: :destroy
end
class ItemDetail < ActiveRecord::Base
  belongs_to :item
end

ItemDetail を参照するとき、記述が冗長になってしまう

# item って単語が重複するのがキモい
item.item_detail.description

こういう時には、class_name オプション

class Item < ActiveRecord::Base
  has_one :detail, dependent: :destroy, class_name: ItemDetail
end

こうすることで、関連名は、 detail。 実際に使用する model は、 ItemDetail になる

item.detail.description

便利!

paperclip の写真の格納先をS3に変更する

やりたいこと

paperclip の写真の格納先をS3にしたい

方法

Paperclip に S3 用のオプションがあるので、それを使う

aws-sdk のインストール

Gemfile

gem 'aws-sdk'

paperclip のデフォルトの設定を追加

config/application.rb

  class Application < Rails::Application
    config.active_record.raise_in_transactional_callbacks = true

    config.paperclip_defaults = {
      storage:        :s3,
      bucket:         ENV['S3_BUCKET'],
      s3_region:      ENV['AWS_REGION'],
      s3_credentials: {
        access_key_id:     ENV['AWS_ACCESS_KEY'],
        secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
      },
      hash_secret:    'uO4l0IJA5hWKPo3kDgXj/Oo9H1KvDt912jDkzOIpP2ecaBMQgejN0MtVdkCee0FMOooNAnqIyMzIbb9BINVMbVza8Xbu8LT7Ee1vu538JzRtUKpLlB6hOezs/FzCBSmmmch4pDUemROm7iS8O8GAKs9jNkLUJydbqXHBvWX2qJM',
      path:           ':attachment/:style/:hash.:extension',
    }
  end
end
  • storage: S3を使いたい場合は :s3
  • bucket: 格納先のbucket名
  • s3_credentials: S3の認証情報
    • access_key_id と、secret_access_key が必要
  • s3_region: S3のリージョン
    • S3の管理画面にアクセスした時に home?region=us-east-1 みたいに URLに表示されるやつを指定すればよい...はず...
  • s3_host_name: S3のホスト名
    • S3の管理画面の適当なオブジェクトのプロパティを開いて「リンク」を見れば分かる
  • hash_secret: ファイル名にhash(後述)を使いたい場合のhashのキー
    • secret とあるけど、まぁ別にhash名から元のファイル名を復元されても困らないので直書き
  • path: S3のup先のpath
    • attachment: has_attached_file で指定した attachment_name
    • style: has_attached_file で指定した style
      • medium とか thumb とか。後オリジナル画像は、original
    • hash: ファイル名をhashにしたもの
      • ファイル名が2バイト文字とかの時に困らないように
    • extension: ファイルの拡張子

参考 : https://github.com/thoughtbot/paperclip#defaults

トラブルシューティング

endpoint を指定しろ的なエラーが出る

The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint
  • s3_host_name の設定漏れ

環境変数 AWS_REGION を設定しろ的なエラーが出て、設定してもおんなじエラーが出る

Aws::Errors::MissingRegionError (missing region; use :region option or export region name to ENV['AWS_REGION']):
  • s3_region を設定する
  • 環境変数を設定しても paperclip の s3_region を優先するらしく、反映されない

Paperclip を使って Rails アプリに画像アップロード機能を追加する

やりたいこと

Rails アプリに画像アップロード機能を追加したい

方法

thoughtbot/paperclip を使う

paperclip のインストール

Gemfile

# 次のイテレーションで aws-sdk を使うが、その時に ver2 を使いたいので、Paperclipを最新のものにした
gem 'paperclip', git: 'https://github.com/thoughtbot/paperclip', tag: 'v5.0.0.beta1'

Photo model に、paperclip の設定を追加

app/models/photo.rb

class Photo < ActiveRecord::Base
  belongs_to :item
  has_attached_file :image, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/no_image.png"
  validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
end

Paperclip::ClassMethods#has_attached_file

has_attached_file( attachment_name, options={} )
  • attachment_name : 添付ファイルを参照する時に使用する名前。
    • 今回ならば、 photo.image_file_name のように、 attachment_name に紐付いた属性が追加される
  • options :
    • styles : オリジナルと別に、#{name}: #{size} で指定したサイズの画像を生成する
    • default_url : 画像がない場合に表示する画像のPATH

参考 : https://github.com/thoughtbot/paperclip#usage

migrate で、Photo に paperclip 用のカラムを追加

rails g migration AddImageColumnsToPhotos
class AddImageColumnsToPhotos < ActiveRecord::Migration
  def up
    add_attachment :photos, :image
  end

  def down
    remove_attachment :photos, :image
  end
end

View

app/views/items/show.html.haml

%ul
  - @item.photos.each do |photo|
    %li
      = photo.title
    %li
      = image_tag photo.image.url(:thumb)

Form

params[:photo] を許可

app/controllers/items_controller.rb

    def item_params
      params.require(:item).permit(:name, :price, photos_attributes: %i[id title image _destroy])
    end

form に file_field を追加

app/views/items/_photo_fields.haml

.nested-fields
  .field
    = f.label :title
    %br
    = f.text_field :title
    = f.file_field :image
  = link_to_remove_association 'remove', f

これで、public/system に写真がupされるようになる

.
└── photos
    └── images
        └── 000
            └── 000
                └── 001
                    ├── medium
                    │   └── IMG_8990.JPG
                    ├── original
                    │   └── IMG_8990.JPG
                    └── thumb
                        └── IMG_8990.JPG