Web系に転職してからの9年を草と一緒に振り返ってみた

この記事は ファインディ株式会社 Advent Calendar 2024 - Adventar の11日目の記事です。

500000000兆年ぶりの投稿ですが、今回は新卒組み込みSEからWebエンジニアにキャリアチェンジしてからの9年を、GitHubの草とその傾向を一緒に振り返ってみようと思います。
大前提、あまり手が速く動くタイプではないので、草少なくないすか?w ちゃんと働いているんすか?w と感じるかもしれませんがご承知置きください。

1社目:2015年10月〜2017年5月

1社目は主にRuby on Railsを用いて、画像素材を取り扱うマーケットプレイスを運営開発している会社に在籍していました。
市場的な枠に当てはめて話すとジュニアエンジニアといえる時代かと思います。
また、グラフにこそ現れませんが、優秀な同僚と上司に恵まれ、設計/テストに対する考え方や実装の基礎力はこの頃特に鍛えられました。

2015 2016 2017
19 contributions 562contributions 831 contributions

草に目を移します。
初めて草がついたのが、入社日と同じ10/1・・・・!エモいものがありますね。
やっぱり駆け出しの頃は草が薄いなーという印象です。
ただ、極端に草が薄いので、もしかしたら入社当初にコミットしていたリポジトリは既に削除されているのかもしれないです。
(異動した記憶のある2016年10月あたりからまともな草の量なので)

後はここ数年と傾向が違って面白いのは、Pull requestsに対してCode reviewの比率が低いことですね。
やはりジュニアだとそんなにコードレビューする側に回らないのが読み解けます。
CommitsとIssueの比率は粒度次第なのであまりアテにならなそう。

また、この頃は当時の師匠(と勝手に慕っています)に触発されて自分でgemを作っていた時代でもあります。
muramurasan.hatenablog.jp 2017年4月前後に草がないのは、プライベートで色々あって体調崩した時期ですね。
今となっては懐かしいですが、こうした人生の波もグラフに現れるのは面白いです。

2社目:2017年6月〜2019年6月

2社目は同じくRuby on Railsを用いての運送系マッチングサービスを運営開発している会社です。
ただただRailsでMVC作っているだけではなく、外部APIやサービスとの繋ぎ込み、課金周辺部分の改修など、難度の高いところも挑戦させてもらえました。
また、AWSの各種サービスを組み合わせたサーバーレスアーキテクチャにも挑戦させてもらえて、この時はエンジニアとしての適応能力的なものを鍛えられた気がします。

2017 2018 2019
831 contributions 544 contributions 1,003 contributions

時期によって波がありますが、草がパラパラと薄めに生えていますね。直近と比べるとまだまだ全然少ない印象です。
Pull requestsに対してのCode review比率については、少しずつレビュー比率が増えてきた感じです。
この頃は最初の数ヶ月こそ圧倒的なテックリードに師事しての開発だったんですが、途中から同僚と横並びで開発する感じにシフトしていったのでそれがあると思います。
世間的にはジュニア卒業してミドルに足突っ込んだぐらいの時期かなと思います。

自作gemの保守はしなくなりましたね、、、散々各所で宣伝してたのにごめんなさい。
1社目と違って、プロダクションに自作gemが入っていなかったので、メンテナンスに対するモチベーションが下がっていたのは正直あると思います。

2018年9月前後で草が薄いのは、またプライベートで色々あって体調崩した時期ですね。
この頃は特に同僚・上司に迷惑をかけてしまいましたが、暖かく復帰迎え入れてもらえたことをよく覚えています。

3社目:2019年7月〜2022年7月

3社目は旅行のサブスクリションサービスを運営開発している会社です。
ローンチ後数ヶ月のタイミング、3人目のエンジニアとしてジョインしていて、準創業期メンバーみたいな位置づけです。
相変わらず主戦場はRuby on Railsなんですが、途中、LaravelからRailsに全面リプレイスしつつDBリアーキテクチャもするというプロジェクトを経験させてもらっています。
自分より経験豊富なメンバーと二人三脚的に進めていったのですが、このリプレイスプロジェクトはエンジニアとしての地力を更に引き上げてもらえました。

後は主にgemですが、ライブラリの技術選定を自分でするようになりました。
市場的にはミドルぐらいなレベル感だと思うんですが、立場上シニア....という状況になっていたと思います。
これは創業期そこそこでリソースも潤沢ではなかったので、メンター的なことや技術的な意思決定の機会が増えてきたという事情もあったと思います。

後、めちゃくちゃ特徴的なのが、コロナ前からフルリモートだったのに加え、最終的にエンジニアの半数近くが日本人ではなくなっていたので、Slack、PRやりとり、ZOOM.... 全部英語が前提だったことです。
英語全然できないけど、書く/話すしないと何も進まない。よく仕事していたフィリピン人がめちゃめちゃ良い人で、彼は何故か自分の英語汲み取れるみたいなことも。(日本人ですら自分の英語はワカランってなってたのに)
ともかく、できていないけど開き直るみたいなメンタルセットはここで鍛えられた気がします。

2019 2020 2021 2022
1,003 contributions 4,106 contributions 4,433 contributions 2,170 contributions

草に目を移すと、最前線で手を動かしていた2020年、2021年がコミット数4000超えしていて、2019年までと比べると界王拳使ったみたいな数字になっています。
自覚している実力に対してめちゃめちゃキツかった記憶あるんですが、やっぱキツかったんですね、そりゃそうか。
この辺りからPull requestsよりもCode review の方が多くなってきてますね。

後、特徴的なのはPR作成比率が極端に少ないことですね。
これはリプレイスプロジェクトでPRが大きくなりがちだったこと、リソース的に小粒度でのレビューがなかなか追いつかず、一つ一つが大きめのPRとならざるを得なかったのがあると思います。
私が辞める頃にはFeatureブランチ切ってそこに小まめに入れていく運用にシフトしていっていたので、今はこういう傾向にはなっていないと思います。

2022年になって草が薄いのは、前年末に第一子を授かって育休を取らせてもらっていたこと、復帰後は機能開発バリバリというより外部連携サービス部分の保守や引き継ぎ、レビュー主体にシフトしていったのがあると思います。
ただ、改めて眺めているとやっぱり最後はモチベーション的なものもあるのかも..... 同僚もEMもいい人ばかりだったので、こう振り返ると申し訳ない。。。

4社目:2022年8月〜 現職

4社目現職は、ハイスキルなエンジニア向けに企業をマッチングする転職サービス Findy*1の開発に携わっています。

findy-code.io

自分が入った時にはコードベースもかなりきれいで、テストも十分に書かれていたため、キャッチアップに全然時間がかからなかった記憶があります。
また、後述するPR粒度を小さく保つ文化のおかげで、オンボーディング終わったあたりからレビューも普通に任されていたと思います。
本体サービス以外の周辺は程よくマイクロサービス化されて適切な技術選定がされていたので、経験のない言語も半強制的にさわることができたみたいなのもありました。

前職もここはしっかりしていましたが、各ライブラリのバージョンは最新を保っているので、変更把握のためにライブラリのコード読む機会も定期的に持つことができています。
自然と最新バージョンの問題を踏むことがあるので、必要ならばOSSのIssueにも報告や提案を上げにいきます。
以下例として、ActiveAdminのメジャーバージョン上げる際 activeadmin_addons というgemで引き当てた問題に対してコメントしています。
(本当は修正PR作るところまでのムーブができるようになりたい....)

github.com

また、専属のデータ基盤/分析/機械学習チームとも協業する機会にも恵まれ、刺激ある環境で仕事ができています。

今現在、恐らく市場的にはシニアレベルにやっと足突っ込めたね、って感じかと思います。
今の開発組織にはシニアレベルのエンジニアがごろごろいるので、彼らと横並びで開発できている状況はとても自信につながっています。

2022 2023 2024
2,170 contributions 4,452 contributions 3,317 contributions

草に目を移します。
特徴的なのは、Commitsに対してPull requestsやCode Reviewの割合が今までより多くなっています。
これは、なるべくPR作成粒度を小さくすることを心がけているためです。
開発着手前にタスクリストを洗い出して、事前にどんな単位でPRを作っていくか狙い定めてから開発していく動きが染み付いています。

Pull requestsに対してCode Reviewの割合が前職までと比較して増えているのは、自身と比較して周囲のエンジニアが優秀すぎて、圧倒的な量のレビュー依頼が来るからですね.... 後はPRの内容によっては複数人アサインする文化も影響していると思います。
そんな鬼のようなレビュー量(月間平均200PR、多い月で350PRとか)の中でもコミット量自体は前職より増えているのは、前述のPR粒度の話や、テストコードがしっかり書けている安心感から、1個1個のPRのレビュー負荷が小さいことが上げられると思います。後はCI待ち時間なんかも効いているかも。
この辺りPR粒度の話は以下の記事がわかりやすいので興味のある方は参照ください。

tech.findy.co.jp

また、2024年は1ヶ月強の育休を挟みつつ、エンジニアリングマネージャー見習いのようなことも始めてプレイングの割合自体は減っている状況なのですが、それでもコミット数3500ぐらいで着地できそうなのかと感心しています。(これはファインディEM陣の中ではかなり低い方)

まとめ

いかがでしたでしょうか?
草の量がすべてではありませんが、長い期間で並べてみると、少なくとも自分の中での相対的な成長の振り返りはしやすかったなと感じています。
また、その会社ごとの状況・文化・自身のロール、ライフイベントにも草の傾向は表れやすく、中長期的なキャリアの棚卸にも使えるんじゃないかなあと思いました。

みなさんも年末年始で良い機会なので、自身のキャリアや活動を振り返ってみてはいかがでしょうか?

それでは良い師走を!

おまけ

恥ずかしくて布団被ってジタバタしたくなりますが、Webエンジニアに転職する前後あたりの記事は以下残っていたので貼っておきます。
(9年前当時の話なので、紹介しているサービス自体既になかったり、何でこんなことしてたんだろうーみたいな話もあります)

muramurasan.hatenablog.jp

muramurasan.hatenablog.jp

*1:「挑戦するエンジニアのプラットフォームをつくる。」のビジョンの通り、それ以外にもエンジニア組織支援SaaS Findy Team+など、様々なサービスを展開しています。

Rubyで写経:テスト駆動開発 第5章「原則をあえて破るとき」

テスト駆動開発という本を題材に、dodosoft のメンバーでもくもく写経会をやっています。
各々が違う言語で取り組んでいるので、言語ならではの悩み、言語共通のコンテキストを共有できて、なかなか学びがあります。

会場は ラクスル株式会社 の会議室です。いつも弊社ありがとうございます!


第5章 原則をあえて破るとき

TODOリスト

  • $5 + CHF = $10
  • $5 * 2 = $10
  • amount ã‚’ privateにする
  • Dollarの副作用どうする?
  • Moneyの丸め処理どうする?
  • equals()
  • hashCode()
  • null との等値性比較
  • 他のオブジェクトとの等価性比較
  • 5 CHF * 2 = 10 CHF
  • Dollar と Franc の重複
  • equals の一般化
  • times の一般化

自分の気付き・感想

  • コピペのメンタルコスト

みんなで話した気付き・感想

  • 「Kent Beck が設計なんてどうでもいいって書いてたよ」
  • コードの重複排除は3つ目が出てきた時かなー
  • 今回のケースは、実際の実装を考えると、コピペじゃなくて、いきなり共通化しちゃう気がする
  • 実際のプロダクトコードを考えると、こんなクソコミット残したくないかも。。。
    • チームの理解が大切?
    • 恥ずかしさを捨てる?
    • squash marging を使えば、恥ずかしいのはコミットコメントだけになるので便利
      • ブランチの切り方統一すれば、featureごとにコミットがまとまるので、いいぞ!
  • t_wada さんの「クソコード」についての和訳バリエーションがすごい

実装面でのひっかかり

  • なし

以上です!
この章については何も言うことないですね。。。とりあえずコピペしたので、ここから重複を排除しつつテストも書いていくという話になるかと。
このクソコードがどう洗練されていくのか楽しみです!

次回は第6章です。

Rubyで写経:テスト駆動開発 第4章「意図を語るテスト」

テスト駆動開発という本を題材に、dodosoft のメンバーでもくもく写経会をやっています。
各々が違う言語で取り組んでいるので、言語ならではの悩み、言語共通のコンテキストを共有できて、なかなか学びがあります。

テスト駆動開発

テスト駆動開発

会場は ラクスル株式会社 の会議室です。いつも弊社ありがとうございます!


第4章 意図を語るテスト

TODOリスト

  • $5 + CHF = $10
  • $5 * 2 = $10
  • amount ã‚’ privateにする
  • Dollarの副作用どうする?
  • Moneyの丸め処理どうする?
  • equals()
  • hashCode()
  • null との等値性比較
  • 他のオブジェクトとの等価性比較

自分の気付き・感想

  • 粗く実装してから結合度を下げていくのはなるほどな! と思った
    • 最初から細かく可視性まで考慮してしまい、結果的に手が遅くなることがよくあったなと思った
    • そんなぐずぐず悩んでいる暇があるのなら、テストを先に書いてしまって(インタフェースを先に決定づける)後からリファクタリングすればいいと思った
  • カプセル化はMUSTなのか、WANTなのか?

みんなで話した気付き・感想

  • TDD的には、いきなり完璧なコードを目指すのではなく、要求を実現するための最小限のコードを少しずつ書く。小さなステップを踏んでいくのだ!
    • 普段は最初からカプセル化を意識してコードを書いていくので、アプローチが逆方向だなと新鮮だった
  • 3章までにテストをしっかり書いていないと(テストが正しいこと)、この章で大胆には変更できなかった

実装面でのひっかかり

  • Rubyのインスタンス変数のカプセル化。。。
  • eq だと同値性ではなく、同一性(object_idレベルで)を比較してしまうので、 == を使わなければならなかった

以上です!
はじめにインタフェースを設計できている必要があるので、テスト駆動開発ってスキルが必要だなー(今の自分には力不足。。。)と思いました。
ガチャガチャ実装しているうちに、インタフェース結構変えちゃうんですよね、自分の場合。がんばらねば。。。

次回は第5章です。

Rubyで写経:テスト駆動開発 第3章「三角測量」

テスト駆動開発という本を題材に、dodosoft のメンバーでもくもく写経会をやっています。
各々が違う言語で取り組んでいるので、言語ならではの悩み、言語共通のコンテキストを共有できて、なかなか学びがあります。

テスト駆動開発

テスト駆動開発

会場は ラクスル株式会社 の会議室です。いつも弊社ありがとうございます!


第3章 三角測量

第3章では、 equals という型と値が一致しているか確認するメソッドの実装をします。
Rubyは基本ダックタイピングなので、型を意識する機会がありませんが、
本章では返り値が Dollar 型であることを強く意識しています。
そのため、本書の意図にならって、Rubyでも型を意識したテストを書いています。

github.com

TODOリスト

  • $5 + CHF = $10
  • $5 * 2 = $10
  • amount ã‚’ privateにする
  • Dollarの副作用どうする?
  • Moneyの丸め処理どうする?
  • equals()
  • hashCode()
  • null との等値性比較
  • 他のオブジェクトとの等価性比較

自分の気付き・感想

  • Rubyだと意識していないけれど、静的型付けの言語でテストを書く場合、型気にしないといけないんだね。。。
  • 他のメンバーは静的型付けで写経しているので、気にするポイントが違って面白い

他のメンバーの気付き・感想

  • 途中参加のメンバーは、参加の前に最低でもテスト回せてコンパイルができるプロジェクトを作っておいた方がいい
  • テストケースの書き方で、そのメソッドで意図していることを表現できるんですね。どんな条件でテストを書いているかで、その意図が見えてくる
  • テストするためのお膳立て(必要なオブジェクトの事前生成)は実際にはあるから、こんなに単純にはテスト書けないだろう(実際はクソ長くなる)

実装面でのひっかかり

  • it にラベルをつける時とつけない時の判断が自分の中でつかない....まあ、期待値を明示的にラベルしたい時は書いて置いた方がいいのかな?
    • たぶん、入力条件は context のラベルに書くべき

以上です!
型一致の評価を == としましたが、これ大丈夫なんですかね?(少なくとも eq はobject_idレベルで同一性比較をするので使えない)

次回は第4章です。サクサク進んで気持ち良いですね!

Rubyの Set / Array それぞれの検索速度を比較してみた

RubyではArrayよりSetの方が高速に検索(include?)できるとのことですが、実際どのぐらいの差があるか調べてみました。

実行環境

以下の通りです。

$ ruby -v          
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]

計測に使うコード

require './process_measure.rb'
require 'set'

array = Array.new
set = Set.new
10001.times { |i| array.push("#{i}") }
10001.times { |i| set.add("#{i}") }

6.times do |i|
  str = "#{i * 2000}"
  puts "-------------------- #{str} --------------------"
  measure_do { array.include?(str) }
  measure_do { set.include?(str) }
end

※ process_measure.rbについては、以下の記事をご参照ください。

muramurasan.hatenablog.jp

計測結果

$ ruby set_array.rb
-------------------- 0 --------------------
      user     system      total        real
  0.000000   0.000000   0.000000 (  0.000007)
      user     system      total        real
  0.000000   0.000000   0.000000 (  0.000005)
-------------------- 2000 --------------------
      user     system      total        real
  0.000000   0.000000   0.000000 (  0.000071)
      user     system      total        real
  0.000000   0.000000   0.000000 (  0.000004)
-------------------- 4000 --------------------
      user     system      total        real
  0.000000   0.000000   0.000000 (  0.000115)
      user     system      total        real
  0.000000   0.000000   0.000000 (  0.000004)
-------------------- 6000 --------------------
      user     system      total        real
  0.000000   0.000000   0.000000 (  0.000170)
      user     system      total        real
  0.000000   0.000000   0.000000 (  0.000004)
-------------------- 8000 --------------------
      user     system      total        real
  0.000000   0.000000   0.000000 (  0.000395)
      user     system      total        real
  0.000000   0.000000   0.000000 (  0.000008)
-------------------- 10000 --------------------
      user     system      total        real
  0.000000   0.000000   0.000000 (  0.000576)
      user     system      total        real
  0.000000   0.000000   0.000000 (  0.000008)

考察

Setの方が明らかに高速ですね。 Arrayは先頭から順番に検索するんでしょうか? 検索対象が後ろになればなるほど遅くなる傾向にあります。

Arrayは便利なメソッドがたくさんありますが、追加/削除/検索しかせず、値が重複しないならばSetを使う方が良いですね。