GraphQL-RubyのEnum classes are never instantiated and their methods are never called.とは何か

GraphQL-RubyのEnumを翻訳するにあたり、Enum classes are never instantiated and their methods are never called.に疑問を持ったのでソースコードを読むことにしました。

version

graphq-ruby: 1.9.5
ruby: 2.6.5

実装は、GraphQL::Schema::Enumにあります。GraphQL-Rubyは、既に巨大なOSSであるためテストから概要を確認しました。

enumという変数は、spec/supportに定義されておりGraphQL::Schema::Enumを継承しています。

テスト項目から、GraphQL::Schema::Enumを継承したクラス自体にdescriptionを定義できることやブロックでvalueを追加することがわかりました。

describe GraphQL::Schema::Enum do
  let(:enum) { Jazz::Family }

  ~~~~
  describe "type info" do
    it "tells about the definition" do
      assert_equal "Family", enum.graphql_name
      assert_equal 29, enum.description.length
      assert_equal 7, enum.values.size
    end

    it "inherits values and description" do
      new_enum = Class.new(enum) do
        value :Nonsense
        value :PERCUSSION, "new description"
      end

      # Description was inherited
      assert_equal 29, new_enum.description.length
      # values were inherited without modifying the parent
      assert_equal 7, enum.values.size
      assert_equal 8, new_enum.values.size
      perc_value = new_enum.values["PERCUSSION"]
      assert_equal "new description", perc_value.description
    end
    
    it "accepts a block" do
      assert_equal "Neither here nor there, really", enum.values["KEYS"].description
    end
    ~~~~
  end
  
  ~~~~
end

つまり、valueは以下のように複数の定義方法があるということです。

class Types::BaseEnum < GraphQL::Schema::Enum
end

class Types::MediaCategory < Types::BaseEnum
  description "Groups of media category"
  value "AUDIO", "An audio file, such as music or spoken word"
  value :TEXT, "Written words"
  value "IMAGE" do
    "A still image, such as a photo or graphic"
  end
  value "VIDEO", value: :video
end

利用方法がわかったので、実際のソースコードを追っていきます。

GraphQL::Schema::Enumには、クラスメソッドしか存在していません。

では、各valueの値はどこで定義されているのでしょうか?コードを見れば、明らかですがvalueメソッドが正解です。

def value(*args, **kwargs, &block)
  kwargs[:owner] = self
  value = enum_value_class.new(*args, **kwargs, &block)
  own_values[value.graphql_name] = value
  nil
end

このメソッドで重要な行は、value = enum_value_class.new(*args, **kwargs, &block)です。

enum_value_classは、superclass <= GraphQL::Schema::Enumがfalseになるまで再帰的に繰り返します。

ここで、GraphQL::Schema::Enumが定義された時にenum_value_class(GraphQL::Schema::EnumValue)を実行しているためGraphQL::Schema::Enumに対してenum_value_classを実行した結果はGraphQL::Schema::EnumValueです。

よって、value = enum_value_class.new(*args, **kwargs, &block)GraphQL::Schema::EnumValueのinitializeメソッドを呼び出します。

def enum_value_class(new_enum_value_class = nil)
  if new_enum_value_class
    @enum_value_class = new_enum_value_class
  end
  @enum_value_class || (superclass <= GraphQL::Schema::Enum ? superclass.enum_value_class : nil)
end

GraphQL::Schema::EnumValueは、とても単純でオブジェクトの初期値をセットするだけです。

to_graphqlメソッドは、クラスベース以前の.define-styleと互換性を保つために用意されているので気にする必要はありません。

def value(*args, **kwargs, &block)
  kwargs[:owner] = self
  value = enum_value_class.new(*args, **kwargs, &block)
  ## ここから
  own_values[value.graphql_name] = value
  nil
end

最後に、privateメソッドであるown_valuesを呼び出しGraphQL::Schema::EnumValueのオブジェクトを@own_valuesに代入します。

private

def own_values
  @own_values ||= {}
end

以上からvalueメソッドがGraphQL::Schema::EnumValueのオブジェクトを@own_valuesに代入していることがわかりました。

さて、テスト項目に振り返るとvaluesメソッドを呼び出していることがわかります。

it "tells about the definition" do
  assert_equal "Family", enum.graphql_name
  assert_equal 29, enum.description.length
  assert_equal 7, enum.values.size
end

valuesメソッドは、先ほど説明した@own_valuesを返しているだけということがわかります。

def values
  inherited_values = superclass <= GraphQL::Schema::Enum ? superclass.values : {}
  # Local values take precedence over inherited ones
  inherited_values.merge(own_values)
end

これで、以下のコードが内部で何をしているかわかりました。

class Types::BaseEnum < GraphQL::Schema::Enum
end

class Types::MediaCategory < Types::BaseEnum
  description "Groups of media category"
  value "AUDIO", "An audio file, such as music or spoken word"
  value :TEXT, "Written words"
  value "IMAGE" do
    "A still image, such as a photo or graphic"
  end
  value "VIDEO", value: :video
end

最後に

ソースコード読解を通して以下について大まかな把握ができたので、まとめます。

GraphQL-RubyのEnum classes are never instantiated and their methods are never called.とは何か

最初に説明した通り、GraphQL::Schema::Enumはインスタンスメソッドを持ちません。また、クラスを定義した時にenum_value_class(GraphQL::Schema::EnumValue)を呼び出すことでDSL風にEnumValueの設定できるようにしています。これらは、全てクラスメソッドで完結しているため仮にインスタンスメソッドを自前に実装したとしても呼び出されることがないことを示唆しています。

憶測ではありますが、Enumは他のオブジェクトから影響を受けるべきではありません。よって他のオブジェクトによって汚染されやすいインスタンスメソッドでは、クラスメソッドのみで完結するようにしているのではないかと思いました。

初めてのGraphQL ―Webサービスを作って学ぶ新世代API

初めてのGraphQL ―Webサービスを作って学ぶ新世代API

  • 作者:Eve Porcello,Alex Banks
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2019/11/13
  • メディア: 単行本(ソフトカバー)

メタプログラミングRuby 第2版

メタプログラミングRuby 第2版

  • 作者:Paolo Perrotta
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2015/10/10
  • メディア: 大型本

Rubyのmodule_functionは、引数なしで指定できる

Classにmoduleをmix-inしてもmoduleで定義したクラスメソッドを利用できない。

これを解決するために、以下ようにincludeされた時点でクラスに対してmoduleをextendする方法がある。

module M
  def self.included(klass)
    klass.extend ClassMethods
  end

  module ClassMethods
    def expand_class_method_to_included
      puts "expand_class_method_to_included"
    end
  end
end

class MyM
  include M
end

module_functionでも、問題を解決することができる。

Rubyドキュメントのコード例から、以下のようにmodule_function引数を都度指定する必要があると勘違いしていた。

module MyModule
  def hello
    'hello'
  end

  module_function :hello
end

module_functionの説明を詳しく確認すると、引数なしのときは今後このモジュール定義文内で新しく定義されるメソッドをすべてモジュール関数にします。の一文がある。

このことから、以下のようにmodule_functionを利用するとそれ以降のメソッドがモジュール関数になることがわかる。

module MyModule
  module_function
  def hello
    'hello'
  end

  def hi
    'hi'
  end
end

puts MyModule.hello
puts MyModule.hi

下記の場合、モジュール関数になるのはhiメソッドのみである。

module MyModule
  def hello
    'hello'
  end

  module_function

  def hi
    'hi'
  end
end

puts MyModule.hello
puts MyModule.hi

改訂2版 パーフェクトRuby

改訂2版 パーフェクトRuby

  • 作者:Rubyサポーターズ
  • 出版社/メーカー: 技術評論社
  • 発売日: 2017/05/17
  • メディア: 大型本

GraphQL-RubyのInstrumentationを翻訳して学んだこと

GraphQL-Rubyには、Queryの実行前後で処理を差し込むことが可能なInstrumentが実装されています。

この機能を利用するためには、必ず#before_query(query)#after_query(query)二つのメソッドを定義する必要があります。

以下のように自身のスキーマクラス内に追加します。

class MySchema < GraphQL::Schema
  instrument(:query, QueryTimerInstrumentation)
end

Railsアプリケーションの場合、ドキュメントに従うならばQueryTimerInstrumentationapp/graphql/query_timer_instrumentation.rbに定義するとよいでしょう。

module QueryTimerInstrumentation
  module_function

  # Log the time of the query
  def before_query(query)
    Rails.logger.info("Query begin: #{Time.now.to_i}")
  end

  def after_query(query)
    Rails.logger.info("Query end: #{Time.now.to_i}")
  end
end

各メソッドの引数である、queryはGraphQL::Queryクラスのインスタンスです。このことから上のログ機能を容易に拡張できます。

GraphQL::Queryは、lib/graphql/query.rbに定義されています。

利用できそうなメソッドとして、queryやmutation、subscriptionを判断できるquery?mutation?subscription?があります。

他にもprovided_variableoperation_namequery_stringメソッドなどを組み合わせることでGraphQL-RubyログGemなどが開発できそうです。

もう一点、補足しておくとquery、mutationともにGraphQL::Queryクラスであるためinstrument(:query, QueryTimerInstrumentation)を定義するだけでmutationに対してもhookされた状態となります。

気になる方は、query.class.ancestorsの実行結果がqueryとmutationで変化しないことを確かめてみるといいでしょう。

$ query.class.ancestors
=> [GraphQL::Query,
 GraphQL::Tracing::Traceable,
 ActiveSupport::ToJsonWithActiveSupportEncoder,
 Object,
 Tins::Full,
 FriendlyId::ObjectUtils,
 PP::ObjectMixin,
 JSON::Ext::Generator::GeneratorMethods::Object,
 ActiveSupport::Tryable,
 ActiveSupport::Dependencies::Loadable,
 Kernel,
 BasicObject]

初めてのGraphQL ―Webサービスを作って学ぶ新世代API

初めてのGraphQL ―Webサービスを作って学ぶ新世代API

  • 作者: Eve Porcello,Alex Banks,尾崎沙耶,あんどうやすし
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2019/11/13
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

High Performance Imagesの「Browser Image Loading」を読んだ

Browser Image Loadingを読みました。タイトルの通り、ブラウザで画像ロードをどのように行うかを知ることができます。

High Performance Images: Shrink, Load, and Deliver Images for Speed (English Edition)

High Performance Images: Shrink, Load, and Deliver Images for Speed (English Edition)

  • 作者: Colin Bendell,Tim Kadlec,Yoav Weiss,Guy Podjarny,Nick Doyle,Mike McCall
  • 出版社/メーカー: O'Reilly Media
  • 発売日: 2016/11/03
  • メディア: Kindle版
  • この商品を含むブログを見る

書籍について

  • Referencing Images

  • When Are Images Downloaded?

書籍は、上記二項目で構成されています。

Referencing Imagesは、ロード処理を説明するための基礎知識についてです。

ロード処理が行われるトリガーとしてよく知られているものにimgタグやCSSのbackground-imageがあります。その他にも、image-setプロパティやpictureタグ。JavaScriptだと、new Image()やHTMLImageElementなどが紹介されていました。

background-imageは、altをサポートしていないことからスクリーンリーダーが対応できません。これは、Userのアクセシビリティを下げるためオススメされていませんでした。

また、background-imageはコンテンツとソフトウェアを分離するというbest practiceから外れるため技術的に可能ならば他の方法を検討すべきだと学びました。

本書で、imgタグでheightとwidthを指定しないとリフローのコストが掛かってしまうことを知りました。

リフローについて調べる過程で、visibility: hiddendisplay: noneの違いは、後者はリフロー処理が走ってしまうことであることを学びました。両者に共通してる点は、リペイントを行うことです。

When Are Images Downloaded?は、具体的なロード処理についてです。

IE7以前は、Preloaderという機能が実装されていなかったため非効率なロードでしたがIE8以降はエッジケースを無視することで効率的な並列ロードでJSファイルをロードできるようになりました。

他にも、TCPの混線でパケットロスを防ぐためブラウザが同一ホストでの接続数を制限していることを知りました。これを解決するための手段として、複数のドメインから分けてリソースを取得するドメインシャーディングがあります。

まとめ

私がWebやブラウザという基礎知識がないこと、画像ロード処理は複雑ということがわかりました。

「Browser Image Loading」は、「High Performance Images」の一部なので全て読みたいです。

High Performance Images: Shrink, Load, and Deliver Images for Speed (English Edition)

High Performance Images: Shrink, Load, and Deliver Images for Speed (English Edition)

  • 作者: Colin Bendell,Tim Kadlec,Yoav Weiss,Guy Podjarny,Nick Doyle,Mike McCall
  • 出版社/メーカー: O'Reilly Media
  • 発売日: 2016/11/03
  • メディア: Kindle版
  • この商品を含むブログを見る

「初めてのGraphQL」の原書を読んだ

2018年に出版された「初めてのGraphQL」の原書である「Learning GraphQL」を読みました。

なぜ、読んだのか

新卒研修で一度読了したのですが、社内のエンジニアから日本語訳が出版される前に読書会を開かないかと誘われました。プロダクトコードで、もっとクライアントにわかりやすいSchemaに改善したい思い二つ返事で承諾しました。

実装した後で読む返すと思った以上に学ぶことが多く既にGraphQLを触っている人にもお勧めできる書籍です。

初めてのGraphQL ―Webサービスを作って学ぶ新世代API

初めてのGraphQL ―Webサービスを作って学ぶ新世代API

  • 作者: Eve Porcello,Alex Banks,尾崎沙耶,あんどうやすし
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2019/11/13
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

目次

  • 第1章 Welcome to GraphQL

  • 第2章 Graph Theory

  • 第3章 The GraphQL Query Language

  • 第4章 Designing a Schema

  • 第5章 Creating a GraphQL APIfield

  • 第6章 GraphQL Clients

  • 第7章 GraphQL in the Real World

各章で気になったことをメモとして残します。

Welcome to GraphQL

  • GraphQLは、HTTPに依存しない
  • クエリは、必要なデータのみを取得する
  • GraphQLは、クライアント視点で考えられ生まれた
  • GraphQLは単なる仕様である

1章では、GraphQLがどのような思想で生まれたかが語られています。また、RESTの比較があります。RESTは、GraphQLに変わるものと単純に考えてはいけません。GraphQLが不得意な部分はREST APIで補う必要があり、管理コストを最小限にしながら両方の恩恵を受ける構成を考える必要があると思いました。

Graph Theory

2章では、GraphQLの基礎となるグラフ理論について解説がありました。オイラーが、ケーニヒスベルクの橋をグラフ図にし問題を単純化しているのが天才なのだなと思いました。

GraphQLでは、複雑なクエリを単純化するようにスキーマを定義しなけれらばならないと述べられています。

The GraphQL Query Language

Fragmentsは、冗長なクエリをまとめるために利用できます。しかし、実際のプロダクトではフロントのコンポーネントによって取得したいデータが微妙に異なるため、上手くまとめることが難しいのではないかと思いました。意味のまとまりに対して命名を与えるためにFragmentsを利用すると便利ではないかという思っています。

Union型では、inline fragmentsを利用することでよりシンプルなクエリとなります。

クエリ変数の$など、GraphQL-SpecのPunctuatorsで規格化されている表現を抑えておく必要があると思いました。

Designing a Schema

  • 良いスキーマにするには、ドメイン知識を非エンジニアも含め共有しユビキタス言語を持つ必要がある
  • 1対多の関係は、ルートタイプにあることが多い
  • 可能な限り無向グラフにする(双方向の関係)
  • 多対多の関係は、through typeと呼ばれるスキーマをドメインに基づいて命名するとよい
  • interfaceは、共通するfieldを全て含めて定義する
  • fieldが大きく異なるならUnion、一つや二つならばinterfaceにする
  • mutationは動詞であるべきだ
  • 技術的に、queryとmutationは同義

4章は、GraphQLを利用したことがある人にとって最も学びの多い章だと思います。 この章を読むためだけでも購入する価値があります。

Creating a GraphQL API & GraphQL Clients

5と6章は、実務でGraphQLを利用しているため飛ばすことにしました。

コードはGitHubに公開されています。7章のコードをcloneするとApollo Engineを登録する必要があるため、chapter-06がよいでしょう。

GitHubから必要なフォルダーのみをcloneする手順は以下の通りです。

$ git init
$ git config core.sparsecheckout true
$ git remote add origin https://github.com/MoonHighway/learning-graphql.git
$ echo learning-graphql/chapter-06 > .git/info/sparse-checkout
$ git pull origin master

DB_HOSTを設定するためにMongoDBをMacにinstallします。

以下の手順でMongoDBのデータベースを作成し、.envDB_HOST=mongodb://localhost:27017/graphql-learning-photo-share-apiと設定します。

$ brew tap mongodb/brew
$ brew install mongodb/brew/mongodb-community@4.0

==> Installing mongodb-community@4.0 from mongodb/brew
~~~~
If you need to have mongodb-community@4.0 first in your PATH run:
  echo 'export PATH="/usr/local/opt/mongodb-community@4.0/bin:$PATH"' >> ~/.bash_profile
  ~~~
  brew services start mongodb/brew/mongodb-community@4.0
  ~~~
==> Summary
 /usr/local/Cellar/mongodb-community@4.0/4.0.13: 21 files, 221.8MB, built in 11 seconds

$ export PATH="$PATH:/usr/local/Cellar/mongodb-community@4.0/4.0.13/bin"
$ mongo
> use graphql-learning-photo-share-api

あとは、書籍の指示に従って以下を取得すると動かすことができます。

CLIENT_ID=<YOUR_GITHUB_CLIENT_ID>
CLIENT_SECRET=<YOUR_GITHUB_CLIENT_SECRET>

GraphQL in the Real World

7章では、ファイルのアップロードやSubscriptionsの実装を行います。実務では、まだ利用機会がないので必要に応じて読み返したい章でした。

RESTからGraphQLにどう切り替えていくのかという痒い所に手が届く解説が印象深かったです。

  • コンポーネント単位で徐々に
  • RESTのエンドポイントを新規開発しない
  • RESTをメンテナンスしない

などでした。スキーマを作り直したいので、同じような手法で不必要なfieldをdeprecatedにしてから徐々に移行していくのが良いのではないかと考えました。

まとめ

GraphQLを実装した人や、また単に気になる人にもオススメの書籍です。 日本語版では、GraphQLで有名な人が巻末付録を書いているようなのでチェックしたいです。

初めてのGraphQL ―Webサービスを作って学ぶ新世代API

初めてのGraphQL ―Webサービスを作って学ぶ新世代API

  • 作者: Eve Porcello,Alex Banks,尾崎沙耶,あんどうやすし
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2019/11/13
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

GemfileにRubyのVersionをベタ書きしない方法

GemfileにRubyのVersionをベタ書きしているプロジェクトがある。

rbenvでVersion管理を行っている場合、rbenv local 2.6.5と実行すると.ruby-versionというファイルが作られる。

$ cat .ruby-version 
2.6.5

そして、Gemfileで以下の記述するとGemfileにRubyのVersionをベタ書きしなくてよい。

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby RUBY_VERSION

MySQLで100年後の日時を設定する

RailsでActiveRecordを継承しているオブジェクトのデータ型カラムに対して100年後の日時を設定したい場合、Time.current.since(100.days)を利用することで実現できる。

しかし、Rubyを理解している人以外がデータを更新したい場合に上記は適切ではない。

SQLであれば共通言語になり得るため、プロダクトで利用しているMySQL5.6において実現する方法を調べた。

ドキュメントからADDDATE(date,INTERVAL expr unit)関数を利用すればいいことがわかった。

ADDDATE(NOW(), INTERVAL 100 YEAR)

NOW()は、現在の日付と時間を返す。unit値としては、YEARの他にHOUR、DAY、WEEK、MONTHがある。

参考文献

https://dev.mysql.com/doc/refman/5.6/ja/date-and-time-functions.html

スッキリわかるSQL入門 第2版 ドリル222問付き! (スッキリシリーズ)

スッキリわかるSQL入門 第2版 ドリル222問付き! (スッキリシリーズ)

  • 作者: 中山清喬,飯田理恵子,株式会社フレアリンク
  • 出版社/メーカー: インプレス
  • 発売日: 2018/11/30
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

株式会社グロービスに新卒入社して半年が経った

https://cdn-ak.f.st-hatena.com/images/fotolife/m/mktakuyax/20190629/20190629003726.png

TL;DR

株式会社グロービスに入社した。元気に生存中。押忍

はじめに

2019年4月1日から新卒エンジニアとして株式会社グロービスに入社しました。

普段は、グロービス学び放題というビジネスを動画で学べる学習サービスを開発しています。

hodai.globis.co.jp

RailsやGraphQLを書いていることが多いです。GraphQL-Rubyを最新に保ちつつ、アプリやフロントのエンジニアが楽しく開発できるスキーマについて考えています。

人生の転機に読み返して、価値があるように出来るだけ省略することなく書いているので長々しい文章となっています。まあ、読みたい人は読んでという感じです。

グロービスとは

学生は、知見録というメディア。社会人は、MBAを思い浮かべるのではないでしょうか?

globis.jp

mba.globis.ac.jp

他にも、ビジネス書籍の出版、ベンチャーキャピタル、バスケットチームである茨城ロボッツなどに力を入れています。

私が所属するGDP(グロービス・デジタル・プラットフォーム)は、EdTech分野の部門です。 ​

入社経緯

​ 私が高校生だった2012-2015は、CourseraedXといった無料で大学の授業を受講できるMOOCs(Massive Open Online Courses)が話題になっていました。

Courseで教育、Edxで哲学、MOOCsと異なりますが高校生にも優しいBig History Projectなどで受験勉強も無視して楽しんでいました。

市内に大学などなく良質な学習機会に恵まれることのなかった私にとって、世界の名だたる名門大学の講義を無料で受講できることに感動しました。この強烈な体験は、教師か動物を殺さない洗剤を開発する化学者になりたいという漠然な将来像をあっさりと破り捨てEdTech分野に進みたいと思うようになりました。

時は流れ、就職活動の時期。大学院に進もうと思っていたのですが、たまたま参加した逆求人で楽しそうに働いていた社会人に出会い就職することに決めました。

グロービスには、求人サイトで声をかけて頂きました。ちょうどその時期、東京に別の用事で来ていたので(本当の)カジュアル面談で組織体制やどのようなサービスを開発しているのかを隅々まで紹介してもらい面接を受けることにしました。

それ以降の面接は、主に教育について話していた記憶があります。当時は、小・中学生にScratchを教えていたこともあり教育と空間の関連性に興味があったので質問したりしました。その後、内定を頂くことができました。

ありがたいことに3社から内定をもらっていましたが、教育について一番考えながら仕事ができると思ったグロービスに入社することにしました。

就活で関わって頂いた全ての方に、ここで感謝したいと思います。ありがとうございました。

グロービスに入社してからの様子

入社してから半年の間で部門長に誕生日プレゼントをせがむ、押忍先輩からのマブダチ申請、ババロア戦争、うまい棒最強の味選手権、メンターの年に一度の必殺技「クワッド茶」などがありましたが、これでは社内の様子が伝わらないと思うので端折ります。 ​

研修期間

3ヶ月間新卒エンジニアは、業務時間の半分を研修に充てることができます。

また、研修期間はメンターが一人ついてくれます。私のメンターは、おっちょこちょいで忘れん坊さんだけど仕事のできる人でした。

これは、今までの教育や学びに関する自分なりの知見を生かす機会だったので楽しみながら研修を組むことができました。

私が組んだ研修は、費用が安価なことからも採用しやすいのではないかと思います。

研修の内容は、大学卒業から上京まで趣味にしていたテーマである「高等教育の大衆化は可能か」から派生して大学史に関する書籍を読み進めていたのですが、その過程でふっと考えた「ある学問は他の学問から多大な影響を受けていて知識は一方向から見ると複雑だが多角的に見ると実は単純になるのではないか」という仮説に基づいて作ることにしました。今まで会った優秀なエンジニアの多くが他分野の知識も貪欲に学んでいたので、目標にしていたということをありました。

しかし、専門的な知識を一気に吸収することのできる能力がないので、高校の資料集や信用している三省堂の図鑑シリーズを読むことにしました。覚えることより他分野の知識とどのようにリンクしているのかや全体的な流れを意識しました。教養は、速効性はないですが徐々に効果が現れるものだと思うので、継続的に学んでいこうと思っています。

次に、エンジニアリングの部分をどのように学んだかですが、その前に入社前のレベル感を紹介します。

  • 大学でコンピューターサイエンスの基礎を学んだ(OSとコンパイラと作ってない普通の学生)
  • Ruby Association Certified Ruby Programmer Silver version 2.1を取得
  • 趣味で開発してない
  • メタプログラミングわかってない
  • APIの実装したことない

という圧倒的力不足な新卒でした。同期や年齢の近いフリーランスの方々が優秀なので、尚更レベル違い感がある。

エンジニア研修では、入社二週間の業務をこなす中で上がってきた課題感を全て書き出した後に、どの技術を習得すれば効率的に生産性を上げることが可能かを考えました。チームメンバーが最高だったので、もっとチームが楽しく開発できる技術を学んでいこうと思いました。バックエンドエンジニアとしてキャリアなど諸々のことを考えた結果、RSpec、MySQL、Rails、GraphQLを重点的に学ぶことになりました。

良い教材が見つからなかったので、メンターに相談するとRefineryCMSやRedmineのソースコード読んだらいいのではないか?というアドバイスをもらいました。また、漢(オトコ)のコンピュータ道など有益なサイトも教えてもらうことができました。

学生時代にWordPressに触れたこともありRefineryCMSのソースコードを読むことにしました。社会人になって初めてOSSのソースコードを読んだのですが、何を学びたいか目的がはっきりしていると案外理解できることがわかりました。これ以降の研修期間中のタスクはできる限りソースコードまで見るように努めました。

書籍による学習も行いました。ACMの会員になると年間$99でO'Reillyをはじめとする数々の良書が読み放題になるO'Reilly Safariに登録しました。書籍はSafariで全て賄える上、金額も安いので登録しない手はありません。研修期間中には、11月に発売されるGraphQL本である「Learning GraphQL」やRSpecの関係者が執筆した「Effective Testing with RSpec 3」など沢山の書籍を読みました。

いい本が豊富なので、O'Reilly Safariにある書籍を読んでいけばいいと思います。一緒に読んでくれる人を探してるので、いれば連絡ください。エンジニア3年目突入するぐらいまでに以下を読みたいです。

Design Patterns in Ruby
Clean Architecture 
オブジェクト指向設計実践ガイド
エリック・エヴァンスのドメイン駆動設計
エンタープライズ Rails 
Clean Code
リファクタリング Ruby

実践的な訓練として、CircleCIのアップデート作業などを行いました。

www.imaharutech.work

アップデート作業は、プロダクトコードとドキュメントを読むことで力が付くので研修内容としてオススメです。

最近、Gemのアップデート方法を先輩に教えて頂きました。もっとアップデート作業を研修に取り込めばよかったと若干後悔しています。

www.imaharutech.work

まだまだ学生時代に出会った東京の学生エンジニアの平均と比べると心許ないですが、エンジニアとして業務を手探りながらをこなすことができるようになったので、いい研修だったのではないかと思います。

以上を簡単にまとめると私の研修内容は以下の通りです。

  • エンジニアリング以外の知識を学ぶ
  • タスク時に時間がかかってもいいので、ソースコードまで読んでみる
  • 書籍を読む
  • アップデート作業を行う

まだまだやったことだったり苦悩は多いのですが、長くなりそうなので需要があれば書こうと思います。将来的に最強の新卒研修を考えたい。

研修を組む際に使えそうなリンク集

  • 各情報系大学のシラバス

教育学の歴史

教育学の歴史

高等学校学習指導要領(平成30年告示)解説 総則編 ―平成30年7月 (高等学校学習指導要領解説)

高等学校学習指導要領(平成30年告示)解説 総則編 ―平成30年7月 (高等学校学習指導要領解説)

Learn Better――頭の使い方が変わり、学びが深まる6つのステップ

Learn Better――頭の使い方が変わり、学びが深まる6つのステップ

成人発達理論による能力の成長 ダイナミックスキル理論の実践的活用法

成人発達理論による能力の成長 ダイナミックスキル理論の実践的活用法

学んだこと

入社してから仕事を通して学んだことを紹介したいと思います。

レビューの仕方

ドメイン知識や技術を含めわからないことが多く、どのようにレビューをしていいのかすらわかりませんでした。まずは、PullRequest(以降、PR)を見てわからないことを全て質問するようにしました。また、学んだことや勉強になったと感じたコードには「勉強になりました」などとコメントをしました。

段々と慣れてくると、綺麗な書き方を提案できるようになります。ISUCONの解説記事のように技術的な提案ができるまでには、程遠いのでコツコツと実力をつけていきたいです。

優先順位の付け方

メンターから常日頃から、施策のインパクトを考えるように指導してもらってます。

言語化してからコードを書く

間違っている場合に、出戻りを少なくなるためIssueやPRにこれからやることや完了条件を書きチームメンバーとすり合わせる重要性を学びました。また、難しいと思ったストーリーに対しては、自分の方針とタスク分解を行なってチームで相談する工夫をしています。

捨てやすいコードを意識する

密結合なコードを作らないことを学びました。将来メンテをするのは、自分以外である可能性が高いということを意識することが重要です。

社内の雰囲気

GDPは主にslackでコミュニケーションをとっているのですが、個人のチャンネルとしてtimesがあります。

さながらruby-jpのように呟いたらどんどん知見をもらえようなチャンネルになっています。とてもありがたいことです。

エンジニア以外の方々もランチに行こ!と言ったらいいよ!という風になる環境です。私のような恥ずかしがり屋さんでも、ランチに困ることはありません。

また、多くの勉強会が昼休みや業務時間内に開催されています。

チームについて

この半年間、楽しく仕事ができたのは間違いなくチームメンバーのおかげです。

入社して初めて参加したスクラムイベントで、デザイナーがユーザーファーストで発言している様子に感動してデザインに興味を持ったり仕事の仕方や将来的に良いコードを書き方など、どれもチームメンバーから学びました。

今でも日々の業務で仕事が丁寧だったり、楽しく働いていたりと尊敬できるところがたくさん見つかる最高のチームです。チームのいいところを全て吸収しきれてない未熟者なので改善しないといけません。

しかし、新しいスクラムマスター就任やチームメンバーが若いこともあり、まだまだ成長の幅は無限大です。私がチームに出来ることは、まだまだ少ないですがバックエンドエンジニアとしてプロダクトをリードすることでスクラムマスターが速攻でマスターになれるようにサポートしていきたいです。

もっとユーザーの考えて、案をバンバン出して絞り価値を爆速で提供できるチームになれると思うのでやってくぞ!当面は、KPTの質を高める動きをしていきます!

社外活動

社外の人から学ぶことも多かったです。

  • 目黒バイナリ勉強会
  • ISUCONに参加した
  • OSSにコミットした
  • 外部発表をした
  • 日本酒会やってる
  • ブログメンタリングを卒業した

www.imaharutech.work

www.imaharutech.work

これからやりたいこと

  • 社内のスーパーエンジニアが集まるプロダクトのコードを1commitずつ追っていく活動をしているので区切りがいい所まで続ける
  • ビジネスの知識がないので、開発しているプロダクトであるグロービス学び放題で学んでいく。ドッグフーディングもできるので最高!
  • 設計に関する書籍を読む。業界の知識を学び、組織の目指すべき方向とあるべきアーキテクチャを考えられるエンジニアになる。
  • 銀座Railsで登壇したい。OSS Gateでメンターになって頂いた方からRails1.0のソースコードを読むといいと勧められてたのでやってみる。
  • 技術書典で書籍を出版する
  • GraphQL-Rubyの翻訳
  • 大学院で大学に関する研究をしたい
  • Scratchを小学生に教えたい
  • 学生時代にお世話になったコミュニティに知識やお金を還元していく
  • ISUCON勉強会を会社で開きたい

やりたいことをやったことにできるように少しずつレベルアップしていくぞ!

応援よろしくお願いします。(褒められて伸びるタイプ)

最後に

多種多様な人と出会い、もっと人として成長したいので声かけてくれると嬉しいです。

日本酒会やってるので、飲み明かしましょう。

Railsアプリケーション初期段階のGemfileに記載されているplatformsについて調べた

rails new .でRailsアプリケーションを作成すると、Gemfileが生成されます。

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.6.5'

gem 'rails', '~> 6.0.0'
  ~~~~~
gem 'bootsnap', '>= 1.4.2', require: false

group :development, :test do
  ~~~~~
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

  ~~~~~
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]には、オプションとしてplatformsが指定されています。

このオプションが何を表しているのか気になったので調べてみることにしました。

Gemfileとは

RubyのライブラリであるGemの依存関係を管理するためのツールにbundlerがあります。

Gemfileは、bundlerで管理するGemやその管理方法などを記載したファイルです。

公式のドキュメントには、以下のような記載があります。

A Gemfile describes the gem dependencies required to execute associated
Ruby code.

Platforms

platformsは、プラットフォームの種類によってinstallを行うかを指定できます。

bundle platformを実行することで現在のプラットフォームを知ることができます。

gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]のうちmingwx64_mingwはWindows環境のRubyです。mriはrubyの一部です。

ruby
C Ruby (MRI), Rubinius or TruffleRuby, but NOT Windows
mri
Same as ruby, but only C Ruby (MRI)

また、バージョンを指定することやグループ化することが可能です。

gem "ruby-debug", platforms: :mri_18

platforms :ruby do
  gem "ruby-debug"
  gem "sqlite3"
end

その他のオプション

source,git_source,requireについても調べてみました。

sourceは、Rubygemsのリンク先を指定します。

source 'https://rubygems.org'

git_sourceは、Rubygemsに登録されていないGemをinstallをしたいに利用します。ブランチ名も指定できます。 会社独自のGemを利用する際などに使えそうです。

git_source(:github) { |repo| "https://github.com/#{repo}.git" }
git "rails", :github => "rails"

git_source(:stash){ |repo_name| "https://stash.corp.acme.pl/#{repo_name}.git" }
gem "rails", :stash => "forks/rails", :branch => "branch_name"

requireをfalseにすることでRails起動時にautorequiredを行わないように設定できます。

gem 'bootsnap', '>= 1.4.2', require: false

@kakakakakkuさんのブログメンタリングで学んだこと

@kakakakakkuさんのブログメンタリングを卒業しました。

3ヶ月間があっという間に過ぎるぐらい濃い時間を過ごすことができました。

「最初は、誤字が多かったな〜」、「なんで@kakakakakkuさんはブログメンタリングをしてるんだろう?」、「もっと人生の先輩に多くのことを学べばよかった」などTwitterのDMと3ヶ月前のブログを見返すと、熱いものが込み上げてきます。

まだまだブログメンタリングは続くようなので、メンタリングを受けるか迷っている人が一歩踏み出せるように@kakakakakkuさんから学んだことを残したいと思います。

なぜ、応募しようと思ったのか

@kakakakakkuさんのブログメンティーへ応募したに詳細が書かれています。言語化することで知識を定着させるためのスキルや習慣をつけるためでした。

これは概ね達成できました。ブログを書く時に、なぜその方法で課題を解決できたまで深掘って調べることができたからだと思います。

メンタリング期間の様子

自分が設定した週目標にブログを投稿したら、DMで連絡しフィードバックを貰うことができます。

最初は、誤字に関する指摘をして頂くことが多かったのですが1ヶ月もブログを書いていると慣れてくるもので、アドバイスをしてもらえる箇所を変化してきました。

例えば

  • シンタックスハイライト
  • 検索流入を意識して、タイトルにこだわる
  • 今は、自分のためにブログを書くといい

などがあります。ブログメンタリングで一番の転機は、「です。ます。」調の方がしっくり書けるのではないかというアドバイスに従い、書いてみると文章スラスラ進むことがわかったことです。

エンジニアリングに関する記事は、「である」調でないと!いう固定概念があったため驚きの発見でした。

メンタリングは、最大で3ヶ月まで延ばすことができます。月末に卒業を希望するかを教えてほしいという旨のメッセージが届きます。結果的に、3ヶ月みっちり指導して頂いたのですが継続するかどうかを即座に決めず温泉に行ってなぜブログメンタリングを続けたいのか?何を学びたいのか?何を達成したいのか?など内省をした上で回答を送りました。

2ヶ月目の目標は、実戦投入力(@kakakakakkuさんからの受け売り)でした。内省して次に目指すべき方向性を報告していました。

ブログに対する取り組み方などを変えようと思っています。
具体的には、アウトプットの質に拘っていきたいです。

今までは、知りたいをベースでネタ出しをしてたので、自分の学びにはなるのですが、1から学ぶので知識レベルが浅いのと実務レベルの緊張から生じる課題感がないため記事の質が上がらないと考えました。

先日のCircleCI記事は、実務での課題を解決した内容だったため質の高い記事がかけたのではないかと思います。

よって、これからのブログの取り組み方として、日々の仕事で解決した課題を主な対象として記事を書きます!

2ヶ月目は8つの記事を書きました。週1投稿を目標にしていたので目標数の倍です。実戦で学んだことを深掘り記事が多く仕事で達成した解決方法を少し深掘りできました。小ネタの書き方に四苦八苦しましたが、最後の方はまとまりのある文章が書けるようになったと思います。

www.imaharutech.work

www.imaharutech.work

www.imaharutech.work

www.imaharutech.work

www.imaharutech.work

www.imaharutech.work

www.imaharutech.work

www.imaharutech.work

3ヶ月は、苦手なことに挑戦するという目標を立てました。具体的には、書評です。

技術書は新卒ということもあり月に4冊は読むようにしているのですが、なかなかアウトプットを出せずにいました。「完璧にやろうのではなく、終わらせることが大事」ということを教えてもらいました。

また、@kakakakakkuさんの書評を参考にするといいとのことなので、10記事ぐらい確認して方針を決めました。

OpenSSH実践入門の書評で苦手意識をなくすことができました。

www.imaharutech.work

他にも、疑問に思ったことやわからないことについて質問するなどしていました。

学んだこと

継続することが大事。これに尽きると思います。改善を意識しながら継続することでブログは、よくなっていきます。

何がなんでもやる。Podcastを聴いたとき時に感じたやりきり力みたいなものを感じながらメンタリング期間を過ごしました。 フィードバックが早く、いつ眠ってるんだろうというぐらいブログメンタリングへコミットしてる姿がかっこよかったです。全力でやることのかっこよさを学びました。

lean-agile.fm

最後に

卒業と当時に、メンタリング期間を通じてフィードバック頂けました。

私の長所は、「積極的に学べる姿勢」なようです。また、技術的な強みを見つけることを今後の課題にするといいとアドバイスをもらいました!これについては、GraphQLになるのではないかと思います。

人生の初のOSSコントリビュートをGraphQL-Rubyで達成し、思入れが強くなりプロダクトのgemを最新まで上げたりと知見も溜まっていきました。

www.imaharutech.work

卒業後、最初の投稿もGraphQL-Rubyです。

www.imaharutech.work

とは言ってもエンジニアとして働き始め1年も経っていないので、この1年はたくさんのことを学ぶことで何が得意か人生でどのような方向に進みたいのかをじっくり考えてから強みにしていく軸を探っていく期間にしたいと思います。

最高の3ヶ月でした。もらった優しさを還元できるような実力のある社会人となり、いつか後輩や下の世代に対して還元する機会を作りたいです。

ブログ書くぞ!