まっしろけっけ

めもてきなやーつ

Rails Developers Meetup 2018: Day 2 で minne での CM 対応でのハイブリッドクラウド運用という話をした。 #railsdm

はじめに

Rails Developers Meetup 2018 こちらのイベントの登壇のお誘いが @kenchan があり話すということが決まったのが昨年の末とかだった記憶

話す内容を考えていたのだけれど、Elasticsearch 周りの話とかオンラインで全テーブルの DB の文字コードを変えた話とかその他色々考えたんだけど、被りそうなのと 30 分枠だと長すぎるか〜という感じだったのであまり聞いたことがなくちょうど年末くらいにやっていたハイブリッドクラウドを絡めた CM 対応の話をするか〜となった。

資料はこちら

speakerdeck.com

Rails のコード 3 行しかないので Rails Developers Meetup #とは となるような内容で、自分が主に担当した部分を多めに事例を紹介しました。
もう少し流れがスムーズになるように資料作れればよかったな〜というのと途中にちょっとしたトラブルがありアレだったという反省

AWS + Nyah 環境というのは社内でも珍しい構成でツラみとかもあるので気になる人はなんか聞いてください。

最後に

次喋る機会があるならちゃんと Rails の話をしたいね!

資料には含めなかったアレです。
pepabo.com

GraphQL の spec に関してアレコレ考えている

はじめに

最近 GraphQL を本格的に使い始めるぞいとなってんですよ。
経緯は下記参照

それでいくつか filed とか定義してデータ取れるようにしつつ rspec で test 書いててう〜むとなったので自分の考えをまとめて世の知見を知りたいとなったという経緯

前提

環境はこんな感じ

  • Rails なアプリケーション
  • graphql-ruby
  • graphql-batch
  • graphql-guard

その1 request spec は書く必要ないのでは?

実際に呼ばれるのは HogeSchema.execute なので request spec では GraphQL API に対して execute に渡される引数周りのチェックをすれば良いと考えた。
expect(HogeSchema).to receive(:execute).with(hoge, hoge, hoge) くらいを引数のパターン分あると良さそう。

何故ならば実際のクエリ書いてテストしていくとネストの深い巨大なクエリが出来上がって、
そのクエリの検証も辛いしレスポンスの json の検証もネストが深くなり辛いということになると考えたから。

実際に 4 種類ほどのデータ取れるようにしただけで辛いなって気持ちになったのでこの考えに至った。
ではどういうことをテストすれば安心を得られるだろうか?と考えた結果がその 2,3 になる

その2 GraphQL::ObjectType 毎に spec を書いていく

GraphQL で大事なのはそれぞれの GraphQL::ObjectType で定義された各スキーマ要素をチェックしていくと良さそう

どんな field が定義されているか?をチェックする。
PostType = GraphQL::ObjectType.define do
  name "Post"
  description "A blog post"
  field :id, !types.ID
  field :title, !types.String
  field :body, !types.String do
    guard ->(obj, args, ctx) { ... }
    resolve ->(obj, args, ctx) { ... }
  end
end

上記のような PostType があった場合は下記のようにチェックする。

describe PostType do
  subject { described_class.fields.keys }
  it { is_expected.to eq(["id", "title", "body"])
end

この他にも field 毎の型定義も想定した通りになっているかチェックしておきたい。
Ruby とかやってると型とかそんなに気にしないかもしれないけれど静的型付け言語がこの API を使うとなった場合はいい加減な型定義は出来ないのでちゃんとしておきたいという気持ち。

しかし一個一個書いていくのもダルいなと感じ他ので db のカラムのデータ型がそのまま field になっている場合が多いと考えるとある程度自動でチェックする仕組みは用意できそうなのでは?と考えたのでちょっとゴニョゴニョしようかなと考えている
db 以外の field はちゃんと個別チェックする。

graphql-guard の設定が正しいかをチェックする

これは README に書いてあるのだけれど下記のように呼び出せるので返り値を適切にチェックすると良さそう。

describe PostType do
  it do
    body = PostType.field_with_guard('body')
    expect(body.guard(obj, args, ctx)).to be_truthy
  end
resolve もチェックする

これも上記と同じようにチェックできる

describe PostType do
  it do
    expect(PostType.fields["body_url"].resolve(obj, args, ctx)).to eq("...")
  end

しかしこの方法だと resolve 内で graphql-batch の loader を使ってる場合にエラーが出るんでどうしたら...というのが悩み

その3 実際のクエリ書いてチェックする必要ってある?

その1 とも被る内容なのですが、その2 の spec をしっかり書いていれば schema の定義はしっかりと出来ているわけでその状態でデータ上手く取れない〜となった場合はクエリが悪いのだろうということになると考えられるからです。

それでも心配なら全スキーマを取ってくるクエリ書いてエラーでないねっていう程度はいいかもしれん(けど、factory bot でデータを用意するのすらだるい)

でも個別(field 毎)のエラーのチェックはクエリ投げないとダメなんかな〜という感じだが現状エラーが出るようなパターンを書いてないのでなんとも言えない

最後に

まだ本格的に使い始めて3,4日程度なのと通常の query のみで mutation に関しては全くという感じなので上に書いた考えは変わってくるかもしれない。

ペパボ社内で他に GraphQL を使っているサービスがあったので、どういう方針なんって聞きにいくついでに今の考えまとめようと思って雑に gist 書き出したらこういう考えに至った。
でそれを共有したらこんなこと考えてたんですよ〜とやまちゃんがナイスなブログを書いてくれて優秀な若者便利!!1となった

blog.kymmt.com

続:社内のテックミーティングでマイクロサービスの基本的なことについて喋った

はじめに

下記の記事で基本的なことを非エンジニアにもわかりやすく喋った。
で、次は下記の資料の課題をどうやって技術的に解決していくの?という部分を説明しなければいけなかったのでサラッと資料で説明したという経緯

shiro-16.hatenablog.com
× モノシリック
◯ モノリシック

資料

speakerdeck.com

具体的にこれ使うというのは記述してるけどその説明は口頭で説明したり、参考のページを紹介したりなどした。
あとは実際に導入するときに pull request にアレコレ書くのでそんな感じにした。

最後に

喋ったのは一週間くらい前なのだけれど slideshare に uploade できないマンと化してしまって...となっていたのでアップが遅れた。
もう speakerdeck にしよと思い立ったのでピッとアップしたという感じ

社内のテックミーティングでマイクロサービスの基本的なことについて喋った

はじめに

定期的に(?)開催されている minne のテックミーティングでマイクロサービ化を進める上で基本的なことをエンジニア以外の人にも知っておいて欲しかったので喋った。

資料

www.slideshare.net


基本的なことをエンジニア以外の人にも知っておいて欲しかったという前提があるので技術的に具体的にこういう風に〜というのは話さず概要をわかりやすく説明したつもり。

最後に

LT 5 分!という感じだったけど絶対終わらないんでという前置きをして 15 分喋った。
今回喋った内容はマイクロサービスアーキテクチャに載っている内容がほとんどです。

rspec-mail_matcher という gem を作った

経緯

仕事で開発している minne というサービスの Rails の version を 5.1.3 から 5.1.4 にあげようと雑に bundle update rails して見たら CI が通らんぞってなっていろいろ調べて行った結果。

CI が通らなくなった箇所

mailer の spec が落ちるようになっていた。具体的な内容はこんな感じ

it '本文に url が含まれること' do
  url = %r{http://example.com/?test1=1\&test2=2}
  expect(mail).to have_body_text(/#{url}/)
end

CI の結果を見ると本文に含まれる URL が http://example.com/test1=1test2=2 と & が消えた状態になってしまっていた(& が消えてることに気づかずにあってるやん!なんで!と二時間ほどハマったのは内緒)

原因の調査その 1

have_body_text という matcher は email-spec という gem で実装されている。

で email-spec を読むと #default_part_body という method から取得した文字列をメールの本文として扱っているので #default_part_body の結果が期待するものかとりあえず調べる。

it '本文に url が含まれること' do
  url = %r{http://example.com/?test1=1\&test2=2}
  binding.pry
  expect(mail).to have_body_text(/#{url}/)
end

spec を実行して止まったところで mail.default_part_body とやると確かに & が消えた状態になっている。


なるほどでは mail.html_part.body では?ということで実行して見ると & は & となっていて消えてはいない。なるほど〜 ここ の HTMLEntities の処理がおかしいっぽいぞというのがわかった

原因の調査その 2

その 1 で htmlentities がアレっぽいというのがわかったので処理を追っていくと ここ の処理で HTML 関連の文字列置き換えをしているぞというのがわかる。

prepare(source).gsub(@entity_regexp){
  binding.pry
  if $1 && codepoint = @map[$1]
    codepoint.chr(Encoding::UTF_8)
  elsif $2
    $2.to_i(10).chr(Encoding::UTF_8)
  elsif $3
    $3.to_i(16).chr(Encoding::UTF_8)
  else
    $&
  end
}

上記のように pry を追記して spec を実行して止まったところでそれぞれの違いを見て見た。

# 5.1.3
pry> prepare(source)
=> "......"
# 5.1.4
pry> prepare(source)
=> "......"

prepare(source) は差分なし

# 5.1.3
pry> $1
=> "amp"
#5.1.4
pry> $1
=> nil

なるほど〜、ということは String#gsub が ActiveSupport あたりで override されてるのか?という考えにたどり着く。
上記の pry 時に caller を実行すると activesupport/lib/active_support/core_ext/string/output_safety.rb が 5.1.4 だと追加されていることがわかる。
確証を得たいので下記で確認。

# 5.1.3
pry> prepare(source).class
=> String
pry> prepare(source).class.ancestors
=> [ActiveSupport::ToJsonWithActiveSupportEncoder,
 String,


#5.1.4
pry> prepare(source).class
=> String
pry> prepare(source).class.ancestors
=> [ActiveSupport::SafeBuffer,
 ActiveSupport::ToJsonWithActiveSupportEncoder,
 String,.....

なるほどね。ということで ActiveSupport::SafeBuffe が追加されたことで htmlentities の処理がうまく動かなくなってしまったことが原因だということが判明。

解決方法を考える

email-spec or htmlentities に PR 投げるか〜というのを最初考えてリポジトリ見たら 3 years ago とかの文字が並んでてなるほど...という感じになった。
それなら自分で作るか〜という気持ちになって今回作ったのでした。

email-spec との差

minne の spec を書き換えるのはダルいと思ったので基本的に matcher の method 名は email-spec に合わせる方向で設計したのだけれど、email-spec の default_part_body に関しては納得いかなくて html_part, text_part の順で取得されるのでこの仕様を知らないと have_body_text で text mail の本文をチェックしているはずなのに html mail の本文チェックしてて同じ記述があるから CI 通った(逆も然り)ということが起きそうなのがダメっぽいな〜という感じになった。

そこで have_body_text で text mail の body を have_body_html で html mail の body をチェックする matcher を定義して実装した。
しかし、現状の v0.1.2 だと 3,4 時間で雑に作ったので multipart? が false の際は雑に #body を使ってしまっているので次の version ではそこら辺の metcher を用意するか have_body_ でそれぞれチェックするかの処理を実装する予定

github.com

最後に

5.1.3 と 5.1.4 のソースの差分 ActiveSupport っぽいなというのはわかっていたけれど、どこがどう問題になっているのか調べて見るか〜と言った感じ。
だらだらと調査内容から書いたのはこのブログを PR に貼り付けて説明いらずにするためです。

Rails + GraphQL で REST じゃない API を作る

はじめに

ここに書いている内容は僕が仕事で開発を行なっている minneAPI に GraphQL を導入するにあたり
gist に雑にまとめてメンバーに共有した内容で公開できない部分をアレしたやつです。
(minne の API は現状オープンなものではないです。

GraphQL #とは

メリット

  • クライアントが必要とするデータを 1 回のリクエストで取得できるようになる
    • REST に近い API だとモバイルアプリで 1 画面を表示するために複数回のリクエストを投げる必要がある
  • どのデータが必要なのかは投げられたクエリから判断するので無駄なデータを返す必要がなくなる
    • 古い version で使っているので消せない json の key どうする?とか悩まなくていい
    • 無駄なデータを返す必要がないのでほんの少しだけ通信コストを抑えられる(高速化)
    • 無駄な JSON を parse する必要がなくなる(高速化)
  • どのデータが必要なのかは投げられたクエリから判断するので大きなロジックの変化がない場合は server 側の実装が不要
    • 投げたクエリによって返すデータが変わるだけなので、デザインの変更でこのテーブルのこのカラムの情報が必要ってなった場合もアプリ側でクエリを修正するだけ
  • クエリには型が存在する
    • ruby では厳密に型を気にすることはない
    • しかしアプリで使用している言語は静的型付けである為、型は重要
  • graphql-ruby ではカーソル形式のページネーションをデフォで提供してくれている

デメリット

  • server 側の実装はそれなりに大変
    • クエリを覚えたり、 N+1 対応したり
      • 補助するための GraphiQL が優秀なのである程度はツールに頼れる
      • N+1 に関しては graphql-batch gem を使うとスマートに解決できそう
  • クライアント側で、何のデータが必要なのかを「すべて」明示する必要がある
    • コードを書く量が増える
    • クエリを覚えなければならない
      • どのデータを使用しているか明示されるため、後で見た時にわかりやすいかもしれない

実際に使ってみた

使う model は下記 (実際は login_id, password とかもあるけど割愛

今回は users#show products#index 相当の処理を実装する

$ rails g model User name:string
$ rails g model Product user_id:integer  name:string 
$ rails g model Love user_id:integer  product_id:integer 

model 周りの実装も割愛

初期設定

# Gemfile
+gem 'graphql'
+gem 'graphql-batch'

Gemfile に常軌を追加して bundle install する
その後諸々の初期ファイルを作ってくれる下記を実行

$ bundle exec rails generate graphql:install
Running via Spring preloader in process 58662
      create  app/graphql/types
      create  app/graphql/types/.keep
      create  app/graphql/ponica_schema.rb
      create  app/graphql/types/query_type.rb
add_root_type  query
      create  app/graphql/mutations
      create  app/graphql/mutations/.keep
      create  app/graphql/types/mutation_type.rb
add_root_type  mutation
      create  app/controllers/graphql_controller.rb
       route  post "/graphql", to: "graphql#execute"
     gemfile  graphiql-rails
       route  graphiql-rails

Gemfile に graphiql-rails が追加されたり routes.rb に graphql の endpoint や graphiql-rails の mount が追加されたりしている。

graphiql-rails の認証周りの設定

graphiql-rails から graphql の API を呼ぶ際にヘッダーにデフォで○○設定したい〜とかいう場合は下記のように initializer で設定する

# config/initializers/graphiql.rb
GraphiQL::Rails.config.headers["X-Hoge"] = -> (context) { "Hoge" }

Github みたいに v4 にしてみる

まずは routes.rb 編集

# routes.rb
  scope 'v4', module: 'v4' do
    post "/graphql", to: "graphql#execute"
  end

controller を移動
mv app/controllers/graphql_controller.rb app/controllers/v4/

# app/controllers/v4/graphql_controller.rb
- class GraphqlController < ApplicationController
+ class V4::GraphqlController < ApplicationController
...

graphiql で使う path も変更

-    mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
+    mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/v4/graphql"

この状態で rails s で server を立ち上げる。

http://localhost:3000/graphiql にアクセスすると GraphiQL の画面が表示される

# request
query {
  testField
}

# response
{
  "data": {
    "testField": "Hello World!"
  }
}

みんな大好き Hello World が出来た

認証周り

ログイン認証とかは今あるものをそのまま使えば ok で GraphQL の処理の中で current_user を使えるように context に格納しておく

# app/controllers/v4/graphql_controller.rb
     context = {
-      # Query context goes here, for example:
-      # current_user: current_user,
+      current_user: current_user
     }

schema 設定

初期設定 の時に app/graphql 以下に諸々のファイルが生成されるのでそこら辺をいじる

app/graphql/ponica_schema.rb というのができているので ponica 部分をいい感じの名前に変える
mv app/graphql/ponica_schema.rb app/graphql/minne_schema.rb とか、で下記のように編集する

# app/graphql/minne_schema.rb
-PonicaSchema = GraphQL::Schema.define do
+ MinneSchema = GraphQL::Schema.define do

# app/controllers/v4/graphql_controller.rb
-    result = PonicaSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
+    result = MinneSchema.execute(query, variables: variables, context: context, operation_name: operation_name)

type を定義していく

順番的には type を定義した後に graphql-batch の処理を実装した方がわかりやすいと思いますが長くなるのでまとめてます。

# app/graphql/minne_schema.rb
MinneSchema = GraphQL::Schema.define do
+ use GraphQL::Batch
# app/graphql/types/user_type.rb
Types::UserType = GraphQL::ObjectType.define do
  name "User"
  global_id_field :id

  field :id, !types.ID
  field :name, !types.String
  connection :products, Types::ProductType.connection_type # 先で述べたページネーションを実装してくれる
end

# app/graphql/types/product_type.rb
Types::ProductType = GraphQL::ObjectType.define do
  name "Product"
  global_id_field :id

  field :id, !types.ID
  field :name, !types.String

  field :user, !Types::UserType do
    resolve -> (obj, args, context) { RecordLoader.for(User).load(obj.user_id) } # N+1 解消用の処理
  end

  field :loved, !types.Boolean do
    resolve ->(obj, args, ctx) {
      LovedLoader.for(ctx[:current_user]).load(obj.id) # いいねしたかどうかをまとめて判定
    }
  end
end

# app/graphql/record_loader.rb
class RecordLoader < GraphQL::Batch::Loader
  def initialize(model)
    @model = model
  end

  def perform(ids)
    @model.where(id: ids).each { |record| fulfill(record.id, record) }
    ids.each { |id| fulfill(id, nil) unless fulfilled?(id) }
  end
end

# app/graphql/loved_loader.rb
class LovedLoader < GraphQL::Batch::Loader
  def initialize(user)
    @user = user
  end

  def perform(ids)
    love_product_ids = @user.loves.where(product_id: ids).pluck(:product_id)
    ids.each { |id| fulfill(id, love_product_ids.include?(id)) }
  end
end

コメントで書いた通り graphql-ruby はページネーション用の処理も簡単に実装してくれる。

また graphql-batch を使えば N+1 の問題も解消可能

loved に関しても 1 レコード毎いいねをしたかを判定するのではなくまとめて判定している

query を定義する

 Types::QueryType = GraphQL::ObjectType.define do
   name "Query"
-  # Add root-level fields here.
-  # They will be entry points for queries on your schema.

-  # TODO: remove me
-  field :testField, types.String do
-    description "An example field added by the generator"
+  field :user do
+    type Types::UserType
+
+    argument :id, !types.String
+
+    description "Find a User By account"
+    resolve ->(obj, args, ctx) {
+      User.find(args[:id])
+    }
+  end
+
+  connection :products, Types::ProductType.connection_type do
+    description "all Product"
     resolve ->(obj, args, ctx) {
-      "Hello World!"
+      Product.all  # 雑に all とかしてるので実際はごにょごにょする必要があります
     }
   end
 end

実際に使ってみる

直接 id を指定してもいいが variables を使うこともできる

__typename とかで type を見たり__hogeで色々見れる

# users#show っぽいやつ
# request
query GetUser($id: String!) { 
  user(id: $id) { 
    __typename
    name
    products(first: 2, after: "Mg==") { # first が件数 after がカーソル
      edges {
      	node {
          id
          name
        }
      }
      pageInfo {
        startCursor
        endCursor
      }
    }
  }
}

# variables
{
  "id": "2"
}

# response
{
  "data": {
    "user": {
      "__typename": "User",
      "name": "test user",
      "products": {
        "edges": [
          {
            "node": {
              "id": "25",
              "name": "hoge"
            }
          },
          {
            "node": {
              "id": "24",
              "name": "fuga"
            }
          }
        ],
        "pageInfo": {
          "startCursor": "MQ==",
          "endCursor": "Mg=="
        }
      }
    }
  }
}
# products#index っぽいやつ
# request
query {
  products(first: 2) { 
    edges {
    	node {
        id
        name
        loved
        user {
          name
        }
      }
    }
    pageInfo {
      startCursor
      endCursor
    }
  }
}

# response
{
  "data": {
    "products": {
      "edges": [
        {
          "node": {
            "id": "1",
            "name": "hoge",
            "loved": true,
            "user": {
              "name": "hoge user"
            }
          }
        },
        {
          "node": {
            "id": "2",
            "name": "fuga",
            "loved": false,
            "user": {
              "name": "fuga user"
            }
          }
        }
      ],
      "pageInfo": {
        "startCursor": "MQ==",
        "endCursor": "Mg=="
      }
    }
  }
}

わかりやすいようにバラバラで呼んでますがクエリを変更すれば上記の 2 つを一回のリクエストで取得することが可能です。
Rails のログを見ればわかりますが N+1 も発生していません。

mutation に関して

mutation に関しては REST から移行するメリットが見出せていないという感じが今のステータスです。
なので処理を記述するのは割愛(あとで別記事として書くかも

エラーハンドリング周り等は下記あたりが参考になりました。
GraphQL -Mutation Query Implementation - Ruby on Rails - Rails Kitchen
GraphQL Ruby Error Handling - Rails Kitchen

最後に

まだ query をどう定義するのがベストなのか? + cache 周りの検証が出来ていないのでその辺り頑張る + mutation メリットが見出せてないのでそこら辺知見がある人と話してみたい。 REST に引っ張られがちになるので考え方を変えるのが大変だったりする。

個人的には GraphQL すごくいいなと感じていて、graphql-ruby, graphql-batch, graphiql-rails もすごく良く出来ているという感想なんで導入進めるぞという気持ち

下記のページを参考にしました。(英語のページを見ながら実装したんでなんか間違ってたら指摘を〜

GraphQL | A query language for your API
GraphQL - Welcome

書いてて疲れたんで最後雑になっちゃったな

犬を飼って 4 ヶ月たったので(主にお金周りの)知見をメモする

はじめに

5 月 14 日から一人暮らしの僕が犬を飼い始めたので、飼いたいと思っている人用にお金のこととかその他諸々まとめておこうと思う。
あくまで小型犬を飼った際の知見です。

先に言っておくのは「可愛いから」という軽い理由だけでペットを飼うのはダメだよってこと。
1 つの命であり飽きたから捨てるとか、思ってたんとちゃうから捨てるとか言う奴はとりあえず◯んだ方がいいよ。
自分の生活リズムも変わるしそういう諸々の覚悟を持って飼いましょう。(僕は諸々覚悟の上で買いました)

なぜ犬を選んだか?

これよく聞かれるんですが、犬 or 猫がよく選択肢として上がると思います。
僕はどっちも好きでもふもふしているのが特に好きなので猫を飼うなら白いノルウェージャンフォレストキャット一択だということも考えてたりする。

しかし、犬を選んだ理由は特にないんだけど猫より好きだからかな。
物心ついた時から(僕が生まれた時からかもしれない)実家には犬がいたし、記憶にあるだけでも 5 頭飼っていた。(同時に 3 頭飼っていた時期もある)

実家で過ごした 18 年間で犬がいなかった時期はおそらく 3 年くらいなので、犬がいるのがアタリマエになっていた。
その中でも twitter やブログのプロフ画像に使っている犬は 3 年前に 15 歳(?)で死んでしまったけれど、それでもアイコンを変えたくないほどに僕にとっては本当に特別な犬だった。それもあって犬を飼いたいって思っていた気がする。

けれど、僕自身が飼いたいって言って飼った犬は 1 頭もいない。姉が飼いたいって言って飼って世話をしないということが n 回ありその犬の世話をするというのはあったので、それが反面教師となりペットを飼う場合は覚悟が必要だという考えが自然と身についたのはよかったなと思っている。

事前準備

犬を飼う際は事前に準備しないといけないものがあるんでここではそれらを記述する。
事前というのは犬を家に迎える前までという話。(ペット可物件がどうのこうのとかは説明しない)


犬を購入する費用

犬をお迎えする方法は色々あるので一概に購入というわけではないと思うけど、僕はブリーダーから購入したのでそれについて話す。
購入したい犬種、犬種によっても毛色や性別によって値段はまちまちなので事前に調べてどの程度が相場なのか?を理解しておく必要がある。

ちなみに僕が購入したのはカニンヘン・ダックスフンドのメスで毛色はシルバーダップルで 15 ~ 20 万という感じ。
シルバーダップルについて遺伝性の病気の発症率が高いというのも調べた上で購入しています。(今の所元気すぎて困るくらい元気)

犬の生活環境整備費

僕が購入したブリーダーさんは犬を送ってくれる際にそれまで使っていたドッグフード 4 kg + トイレ + トイレシート40 枚 + ご飯、お水入れ用食器を一緒に送ってくれました。なのでこれらをそのまま使えば費用はかからなかったのですが、トイレと食器に関しては利便性が良いものを購入しました。

そのほかに必要なものとしては、ペットの行動を制限するためのサークル、ペット用のベッド(タオルとかでもいいかもしれない)、またこれは飼ってから汚れとかを防止したくて導入したのですが床にマットのようなものを敷いた方が良さそうだと思ったのでジョイントマットを購入しました。

ドッグフード 4 kg 4000円(種類によって値段はピンキリ)
トイレ 2500円
トイレシート 700円
ご飯、お水入れ用食器 1600円
サークル 5000円
ベッド 1700円
ジョイントマット 600円 * 3

家や設置するサークルの広さによっても変わると思いますが、うちはこんな感じ。
アタリマエですがドッグフード、トイレシートは消耗品なのでなくなりそうになったら買い足す必要があります。
お迎えして気づいたのですがトイレシートは本当にすぐになくなるので大量に購入した方がいいということ、僕は上記のものを飼った後日 amazon のセールで 400 枚入りが 4500 円で売っていたのをポチったのですがこれはマジでいい買い物だったと思っています。
あと、ベッドを買ったはいいのですが子犬は遊ぶのが大好きなのですぐにボロボロにされてしまいました...躾にもよるかもしれませんが...その為最初はタオルでもよかったかもという考えになりました。

お迎え後

お迎え後の費用その 1

お迎え後も色々とお金がかかります。
まずは犬の登録です。これは自分は犬を飼ってますよという登録を役所にする必要があり費用は 3000 円です。(住んでる地域によって費用は違うかも)
また、混合ワクチンの摂取もした方が良いでしょう。
ペットショップやブリーダーから子犬を飼った場合基本的には 1 回目の混合ワクチンは済んでいると思われますが、
子犬の場合は混合ワクチンの種類によって後 1 ~ 2 回受ける必要があります。 診察も含めると 15000 円ほどかかった記憶です。
その他に狂犬病のワクチンを受けなければならずこれが 3000 円ほど。(狂犬病ワクチンは義務、他のワクチンは任意)

登録費 3000円
混合ワクチン 15000円 * 2
狂犬病ワクチン 3000円
フィラリアの薬(3ヶ月) 3000円
ダニ・ノミ薬(3ヶ月) 3000円

ちなみに登録は 1 回ですが、混合ワクチンと狂犬病ワクチンは年 1 回それぞれ摂取した方が良いよう(狂犬病ワクチンは義務)ですので
その費用が毎年かかるようです。フィラリアに関しては蚊を媒介にして感染するので蚊が発生する期間(約半年)、ダニ・ノミは通年(?)で費用がかかります

お迎え後の費用その 2

その 2 に関しては必要になった時期に買い揃えればいいよねっていう費用になります。
爪切りや耳掃除用の薬、家でシャンプーをする場合はシャンプー剤、散歩時の首輪とリード
その他にはおもちゃ

爪切り 1800円
耳掃除用の薬 1700円
シャンプー 1000円
首輪 500円
リード 1400円

シャンプーに関してはお店でやってもらうっていうなら不要ですし、散歩行かなくても家で十分だという場合は首輪やリードは不要かと思われます。

お迎え後の費用その 3

その 3 に関してはこれから掛かるのがわかっている費用です。
不妊手術に関してはメリット、デメリットあるので個々の判断かと思います。
費用に関しても性別によって変わるようです。

何かしらの病気や体調が悪くなり医療費が発生する場合があると思うのでペット保険に入っておくという選択肢もあります。

最後に

という感じでペットを買うには覚悟も必要ですし、お金もかかります。
ですが、僕は 4 ヶ月で大変だと思ったことは一度もないですし毎日かわいいなと思いながら犬と戯れています。
飲み会とかも結構普通に行ってますが、二次会を断る明確な理由が出来たのも結構便利だったりする。(もともと二次会にそんなに行かない人なので
ペットを飼ったからといってあまり無理せず自分の生活リズムといい感じに折り合いをつけていければうまくいくような気がしている。

みんなも親バカになればいいと思うよ!
f:id:shiro-16:20170716161049j:plain

2 頭目飼うならシルケン・ウインドハウンド飼いたいけど広さが足りない...