まっしろけっけ

めもてきなやーつ

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 頭目飼うならシルケン・ウインドハウンド飼いたいけど広さが足りない...

最近喋ったことを書く

はじめに

最近(7月)社内で色々喋っていたのでそれについてざっくりまとめておこうという気持ちです。

1. プロダクトおはなし会

minne 事業部の PO,デザイナー,エンジニア(アプリ,web,インフラ) の代表が 3Q はこんなことやりますよって話す会

web チームとして話した内容は 1Q, 2Q 終えての課題だと思った。

障害時の対応
タスクを最後までやりきる

この 2 点をもう少し頑張ろうっていう話。

障害時の対応

これに関しては、障害の大きさ(事業への影響)を即座に判断し障害の根本原因解決
もしくは最低限ユーザに影響がない状態へ持っていく際の判断を出来るだけ間違わずに出来るようになろうという話。

例えば iOS のアプリをリリースしたんだけどバグがあり API のレスポンスを受け取ると高確率でクラッシュするという問題が発生した際

根本原因を解決するという部分を最優先にしてしまうと、
根本原因が解決するまでユーザはアプリを使うことが出来なくなるという問題が発生してしまい事業への影響は大きくなってしまう。

そうならないように原因を特定したら API のレスポンスを調整することでアプリで一部表示されないエリアが発生するが
アプリを使うことは可能という状態に持って行った方が影響は少なくて済む。

web チームの面々は根本原因を解決するという部分に目が行きがちな時が多々あったので
このような判断を即座に出来るようになり事業への影響が出来るだけ少なくなるようにしようというのが 1 点

もう 1 点が障害解決の為にもっと技術力つけていこうぜっていう話(障害解決の為にと書いているが結果的に障害解決以外の部分にも大いに役立つと思っている)

障害の原因を特定するにも技術力が必要だし、原因を解決するにも技術力が必要という話をした。

例えば障害の原因がインフラ関連のものだった場合にインフラだから解決できないというのは技術力がない(自分の専門とする技術以外の技術力がない)から解決できないと同義なんで技術力をつけよう。技術力というのは知識を持ち経験をすることで飛躍的に向上すると僕は思っているので、自分のサービスで使われている技術やインフラ環境の知識を得て、調査をすることで技術力をつけていこうっていう感じ。

なぜこんな話をしたかというと僕はチーフテクニカルリードという立場で確かに技術方針を決めたりするのでチームで一番技術力がないといけないと思っているけれど、それがチームとしての SPOF になってしまうのは出来るだけ避けたいという考えがあったからです。

僕がいつ死ぬかもわからん(この記事を公開した数秒後に死ぬことだってあり得る)ので、僕が死んでもチームのメンバーで変わりないクオリティでサービスを運用できれば最高だなと考えている為です。

タスクを最後までやりきる

これに関しては、 2Q にチームに特に期限も決めずに 1 つ仕事を投げて見たのだけれどこれの進捗があまり良くなかった。
というのと各スプリントでもスプリントで完了しなかったもしくは時間ができたらやります的なタスク。

原因は色々あると思うのだけれど、これに関しては特にこうやって解決していこうという案は出さずに
みんなで意見を出して解決して見てよって感じにした。

なぜか?
今のチームは 2 週間ごとのスプリントだと振り返りで KPT を出してしっかりと P に対して T を出し取り組めていて
セルフマネジメントがある程度できているチームだと思っているので
更に最高のチームを目指す為に 2 週間という枠ではなくもう少し大きな期間でのチームの課題も自分たちで気づき解決をして行って欲しいと思った。

今のチームであればそれは出来るであろうと僕は思っているので後はきっかけを与えるだけなのかな?と思ったので僕からは解決案を出さずに(悪く言えば)丸投げという形をとって見た。
これに関してはどうなるかは 3Q 終わってみてという感じかな

2. 新卒向けの minne の web チーム紹介

minne のマーケと CS に配属された新卒向けになんか喋って〜と言われたので web チームのことは僕がアプリチームのことは@hisaichi5518 が喋った。

これは非エンジニア向けだったのでそもそも web チームの人たちが何を開発しているのか?という点と普段 web チームが大事にしていることについて。
普段 web チームの人たちが大事にしていることは「アタリマエをアタリマに」 + 「アタリマエじゃないこともアタリマエに」なんだけれど、
サービスが成長するに当たってその時々で必要とされるアタリマエも変わってくるのでサービスが成長するのに合わせてチームも成長していこうっていうのを大事に web チームは開発をしているよっていう感じの紹介。

3. bigfoot 勉強会

最近勢いがある PO に勉強会やってもらえないっすか?と言われ、おっ!いいじゃんと思ったのでやりましょう!って話したのがきっかけ。
みんながどんな内容のことを知りたいのかわからなかったので、とりあえず知りたいことなんですか?という感じでいくつかの選択肢を用意してアンケートをとってみた。でその結果を元に喋った。

1. bigfoot とはどういうものか?
2. bigfoot でどんなことが出来るのか?
3. bigfoot のクエリの書き方(基本編)

という 3 点を喋った。
エンジニア相手なら三宅さんのこの資料見てで終わるのですが、非エンジニアに対してなのでもう少しわかりやすく。

どういう流れでログが TD に投げられるかや TD の PlazmaDB や datatank の違いに関して等を話した後に、実際にどんなログを送っていてその結果としてどういうことが集計できるのかという話をした。
で、最後に簡単なクエリの書き方を説明して終わり。

この話をした 1 週間後くらいに福岡の財津君が来たタイミングで、希望者を集めて今知りたいと思っている数値を実際にクエリ書いてとってみましょうという会を開いていたので参加した人にはわかりやすかったのではなかろうか?という気持ち。

参加した人たちも前より積極的にクエリを書いてくれている気配があるので一定の成果はあったのでは

4. ECTechMTG

下記の内容。主に bigfoot の宣伝をした。

shiro-16.hatenablog.com

最後に

最初の3つが一週間に詰まっていて発表練習は全くできてなかったので(という言い訳)、なんか話まとまってんのかよくわからん...個人的にはイマイチだなぁという感じになってしまったのはすまん...という気持ちです。

EC 事業部の TechMTG でなんか喋った

経緯

tech.pepabo.com


上記の第 2 回が終了した直後に けんちゃんくんさん (@kenchan) | Twitter に第 3 回のゲストトークどうですか?ってお願いされたのでじゃなんか喋りますって感じで喋ることになった。当日はスペシャルゲストという紹介のされ方だったのでマジか!という気持ちだった。

発表内容

資料は下記

www.slideshare.net


内容としてはペパボのログ解析基盤である bigfoot を活用したサービス改善事例の紹介(という名の bigfoot の宣伝)。
EC 事業部は PHP のサービスもあり bigfoot 周りの便利ツールは gem として提供しているものがほとんどなので、即導入とかはちょっとつらめかなと思いつつ...


ペパボのログ解析基盤と言いつつ minne 以外で有効に活用できているサービスは少ないという状況なのでこういうことできますよ〜っていうのの一部を紹介した。公開している資料は当日使ったものの中で、まだリリースしていない機能だったり具体的な数字を削除していたりするのでもう少し多めに事例を喋りました。


社内用の発表だったので煽りを入れつつ多少面白く話せたのでは?という気持ち

最後に

EC 事業部に(2 ヶ月だけ)いたので帰って来た感があった(嘘です)

発表直後から EC の人々が続々アカウント作ってくださいという issue が作られた( issue ベースでアカウント申請をしている )ので
話してよかったなという気持ちです。

Treasure Data の job の状態を監視する mackerel plugin 作った

経緯

ペパボのデータアナリストの @zaimy何らかの原因で job が詰まって割当リソースを使い果たすと、該当のクエリ以外の job も巻き込まれて error になることがあり困った と言っていて
mackerel とかで見れると嬉しいなと言ってたのでじゃなんかやっておきますねって感じが経緯です。

mackerel plugin を選んだ理由

mackerel 使う以外にも色々方法はあると思うのですが、mackerel 使ってるし mackerel plugin 作ったことないから面白そうだし作ってみるかなで決めました。

TD API 調査

TD の API のリファレンスはこちらこれで job の一覧が取得できる。
がしかし 20 件しか取得できないっぽい。ということがわかった。

また、パラメータとして ?status=running とか渡すとその status で絞り込めるっぽいというのを発見したけど
リファレンスに載ってないので使わんでおこうかなと思った。
TD の client は td-client-go 使った。
この client でも上記の API にパラメータ渡せない仕様だったので素直に使うことにした。

20 件しか取得できないっぽいということなのでその 20 件の job の status しか見れないが、20 件の各 job の status を分類できるだけでも困っていることは解決できそうだったのでそれで良いかなということにした。

plugin 作成

plugin の作成はここら辺の公式のヘルプをみたり、大量にある plugin のコード読めばわかったのでそこまで問題はなかった。

一点だけハマったのが結果を出力するときに出力する値の型が制限されているのに気づかずに int で値を渡していて結果が出力されない...なぜだ...となりハマった。さっさとコードを読めば解決する案件だった

できたもの

github.com

できたものがこちら。
下記みたいになる。0 件の場合も出力しておいた方がグラフ途切れたりしないので良いなって思ったので追々やる予定

$ mackerel-plugin-treasure-data-job-count -treasure-data-api-key="your API KEY"
treasure-data-job-count.error	1	1493270870
treasure-data-job-count.success	19	1493270870


あとは monitoring を行う server に plugin の設定入れて mackerel 側で監視の設定入れておしまい。

最後に

面白かったので満足

Rubyエンジニアが語る、2016年の振り返りとこれからに登壇して来たよ

株式会社 Speee さんと自分が勤めるペパボが共同で開催した下記のイベントに登壇して来ました。

speee.connpass.com

経緯

経緯としては、CTL になったし喋らない?って声をかけられたからなのですが、
個人的に昨年のアウトプットが圧倒的に少ないこと、
その反面インプットは大量にあり話せることはいっぱいあるぜ!って感じだった即答で喋りますって言った記憶がある。

発表内容

当日の資料は下記
最初作って練習してみたら 30 分超えの大作になってしまったのでだいぶ削った。

www.slideshare.net

内容としては 2016 年に行った minne の API の改善の一部を紹介
問題だと思ったことを 1 つずつ改善しましたって話なのですが、
この問題に対して技術的負債と言う人もいると思いますが、
自分は特に負債とは思っていなくて minne の急成長には必要なものだったと思っていて、
管理のしやすさとかよりも、急成長する為にスピードを優先した結果なので必要なものだったと捉えています。
成長の機会を逃し、サービスが終了しては本末転倒なので...

また、ペパボでは今後を見据えてこういうことの改善をしたいですと言えば、
非エンジニアの人も納得してくれる環境があるのでいいバランスが出来ているのではないかと思っています。

発表後の質問や懇親会でも質問を幾つか頂いたのでそれなりにみんな興味のある内容だったのかなという感じでよかった。

イベント全体

Speee さんのオシャレなオフィスのカフェで開催され、
PHP から Ruby への移行の話を聞きながら 3 年くらい前に自分もやったな...って思ったり、
縦に長すぎるコントローラやばいな...と言う話、独自言語辛いという話など面白い内容が多かったのではという感じ。

懇親会でも質問を幾つか頂いたり Speee さんの若者に色々お話を伺ったり楽しかった。

最後に

最初の方に CTL になったとさらっと書いたのですが、それについては別で記事を書く予定です。

昨年のアウトプットが圧倒的に少なかったので今年は 2 ヶ月に 1 回くらいのペースでなんか喋りたいなという気持ちでいます。
昨年は API 改善,検索改善,開発基盤改善とかやりつつ普通の機能追加などの開発やってたりしたのでそこら辺の話とか
昨年から今年 1 月に Rails 5 対応してるのでそこら辺とかネタはあるのでまぁ大丈夫だろうという気持ち。

2016 年振り返り

はじめに

約 4 ヶ月ぶりのブログ...
今回は 2016 年の振り返りをしてみようと思います。

お仕事

シニアエンジニアになったり、テクニカルリードになったりした。
ペパボに入社した時から 1 年以内にシニアになると決めてたのでなれてよかったね。

技術的な話だと前半は Elasticsearch 使って検索周りで色々やってた。
後半は API のテクニカルリードとして検索や他になんかやってたら Apple Pay の対応やることになったのでそればっかりやってた。
Apple Pay は色々な意味で辛かったりしたけど、Apple公式サイトに minne が載ったり新 MBP の CM に使って貰ったりしたので報われたなという感じ。
Apple Pay 終わった後は Rails 5 の対応とかやってる(現在進行形)

2017 年から僕自身の minne 内で求められる役割が変わるという話を 11 月頭に聞いて、
人生で初めて 11 月から次の年のことを真剣に考えてた。

API のテクニカルリードとしてもっと API 関連のあれこれやれればよかったというのが心残り

アウトプット

OSS

何個か gem 作ったり、バグ見つけて PR 出したりとかしてた。
ここら辺は別で記事を書きたい気持ち。

ブログ

...あまり書けてない...ただのメモのつもりで書いているブログなのでもっとメモを残していこうというお気持ち。

執筆

WEB+DB PRESS Vol.92 の Web 開発新人研修の web アプリケーションのパートを担当した。
今読み返すとまだまだな部分が多いなと感じるが本当に良い経験になった。

発表

社外で何か発表したということはなかった気がする。
社内では幾つか発表してた。

今年は社内、社外含めて幾つか声を掛けて貰ったりしてるので頑張っていく気持ち。

その他

お見合い

面白年賀状をもらった


読書

技術書 20 冊
ビジネス書(?) 5 冊
数学関連 2 冊

記憶にあるのだけでこんなもん。
本は実物を持っていたい + 実物をさらっと眺めて買いたいという謎のこだわりがあるので
Amazon とかに購入履歴があまり残ってないので把握できないのが辛いところ

あと、本読む速度が遅いので速読スキルが欲しい...

旅行

30 手前で初の一人旅をした。
行き先は京都だったのだが同僚が京都の便利情報を次々教えてくれて便利だった。
歩き疲れたけどめっちゃ楽しかったので、また旅したい。

ちなみにこの旅の為にカメラ買った。

運動

ほぼ毎週スポーツをしているし、ジムにも週 2,3 行っているが今年は週 2, 3 いけない週が結構あったなぁという記憶
忙しかろうが強い意志で週 2 は行きたい。

健康

5 月頭、8 月中旬、 11 月末と 3 ヶ月 + 1 週間くらいの周期で急性腸炎になってて辛い感じ...
真剣に健康について考えていこうという気持ちになった。