何でも屋エンジニアのブログ

ソフトウェア関連技術、コミュニティ、日々の雑貨

2023年1月の振り返り

仕事の話

直接の上長にあたる人が退職し、実質的に事業部の技術組織のトップの人間となった(別に昇格したわけではない)。選択肢として今まで通りの感覚・業務内容を継続するか、視座を上げアクセルを踏むかの二択があるが、せっかくの機会なのでアクセルを踏む方を選んだ。事業を推進する上でもその方が良いことが多いだろうし、個人的にもそのポジション(に立ったつもり)で仕事ができるチャンスは滅多にないだろうから、流れに乗ってみようと思った。 キャリアを時間・空間軸で考える / Thinking about your career from both time and space viewpoints - Speaker Deck で触れられているが、見晴らしの良い場所に立ったことで色々なことが鮮明に見えてくる。

見晴らしの良い場所に立つ、山の中腹だと全体が見えないという比喩のイラスト。

見えてくる課題の数・サイズも変わり、今までとは違ったアプローチや解決方法が必要になった。今までは(ギリギリ)直接的に情報を取得し判断することができる範囲でのマネジメントをしていたが、今後はそうはいかない。各チームに責任者を置き、かつ、そのメンバーたち適切に委譲しマネジメントを行う必要が出てきた。その場合、その責任者たちとは何を軸にしてコミュニケーションを取れば良いのかつまりミッションは何なのかという部分を明確に打ち出す必要がある。さらに、事業目標を達成するためにどういう組織を編成し何人必要なのか、どういう技術選択をすべきなのかも考えていく必要があり、去年の末から事業部のビジネスとエンジニアリングを紐づけていくという試みを行って来た。その際に Shin Takeuchi さんの記事や yasaichi さんの以下の記事・Podcast がとても参考になった。

CTOの頭の中:技術を財務で表現する|Shin Takeuchi|note

CTOの頭の中:組織と言葉とアーキテクト|Shin Takeuchi|note

CTOの頭の中:技術と組織と牽制関係|Shin Takeuchi|note

経営とソフトウェアエンジニアリングの接続 - WEB SALAD

6. 1on1 in Public by texta.fm

このような観点を組み込み、年初ということで今期の方針を作成した。

子供の話

一歳半を過ぎてからというのも、成長がさらに早くなった気がする。身体能力もメキメキ向上し、うつ伏せになって顔を上げてお絵描きをしているのを見たときには「すごい...人間じゃん...」となりとても驚き嬉しくなった。

一方でいやいや期が本格化し結構大変なことが増えた。しかし「意志がめばえてきたんだなぁ」と捉えると頼もしくもある。昔なら何かやろうとして「危ないから」と止めるときも新たに何か気をひくものを渡せば平気だったのだが、今はそうはいかない。きちんと「やりたいことが邪魔されている」という現実を認識できるようになった証拠だと思う。放っておくと自分で気持ちを落ち着かせて泣くのをやめるということが少しずつできるようになってきた。めちゃくちゃ大変だけど。こだわりという点では、最近傘がお気に入りで、天気関係なく傘を引きずって歩き回っている。

精神的な成長について他にも目に見える変化があった。保育園で自分より月齢の低い子の面倒を見たがるなど、先生からも「入園した頃はこんなにお姉さん気質があるとは思わなかった」と言われるほどの成長を見せている。言われてみると僕に飲み物をコップを持って飲ませてくれたり、頭をなでてくれたり、お姉さんのような振る舞いがあるなぁと思った。

自分のこと

筋トレしたい。重たいもの持ちたい。なんか始めよ。

ActiveJob のリトライの挙動

job の内部でネットワークエラーを拾うケースでは、定間隔より exponential backoff でリトライしたいなぁと考え調べた。

ActiveJob::Exceptions#retry_on で定義されている。

    def retry_on(*exceptions, wait: 3.seconds, attempts: 5, queue: nil, priority: nil, jitter: JITTER_DEFAULT)
        rescue_from(*exceptions) do |error|
          executions = executions_for(exceptions)
          if attempts == :unlimited || executions < attempts
            retry_job wait: determine_delay(seconds_or_duration_or_algorithm: wait, executions: executions, jitter: jitter), queue: queue, priority: priority, error: error
          else
            if block_given?
              instrument :retry_stopped, error: error do
                yield self, error
              end
            else
              instrument :retry_stopped, error: error
              raise error
            end
          end
        end
      end

rails/exceptions.rb at v7.0.4 · rails/rails · GitHub

間隔の決定は同クラスの #determine_delay 内で行っている。

  def determine_delay(seconds_or_duration_or_algorithm:, executions:, jitter: JITTER_DEFAULT)
        jitter = jitter == JITTER_DEFAULT ? self.class.retry_jitter : (jitter || 0.0)

        case seconds_or_duration_or_algorithm
        when :exponentially_longer
          delay = executions**4
          delay_jitter = determine_jitter_for_delay(delay, jitter)
          delay + delay_jitter + 2
        when ActiveSupport::Duration, Integer
          delay = seconds_or_duration_or_algorithm.to_i
          delay_jitter = determine_jitter_for_delay(delay, jitter)
          delay + delay_jitter
        when Proc
          algorithm = seconds_or_duration_or_algorithm
          algorithm.call(executions)
        else
          raise "Couldn't determine a delay based on #{seconds_or_duration_or_algorithm.inspect}"
        end
      end

rails/exceptions.rb at v7.0.4 · rails/rails · GitHub

ということで waitActiveSupport::Duration1.second など)を渡すと jitter はあるものの定間隔でリトライする。 wait:exponentially_longer を渡せば exponential backoff となる。

育児休業と仕事復帰後の振り返り

この記事は 🎄GMOペパボエンジニア Advent Calendar 2022 - Adventar 14日目の記事です。

私は2021年8月1日から2022年3月末まで育児休業を取得しました。育児休業中の子育てや過ごし方、復帰後の仕事の振り返りを書いていこうと思います。

産まれてから育休開始まで

会社からは休むことを勧められたが、仕事の区切りが悪く中途半端な状態で休みに入りたくなかったので、最初の一ヶ月は仕事をしながら育児をした。

産後ということもあり妻を夜寝かせてあげる必要があり、当面の間夜のお世話はメインで担当することにしていた。自分自身の寝つきが悪く、何度も起こされるのがつらいため、ずっと起きているという選択をした。特に産まれてから3 ~ 4ヶ月くらいは、ミルクを飲んで寝る → 数時間後に起きるというわけではなく、起きたら割とグズグズで起きているタイプだったので、この選択は正解だったのだと思う。

というわけで明け方まで起きていて昼まで寝てそのまま仕事をする、という一ヶ月になった(フレックスタイムとリモートワークのおかげで本当に助かった)。

最終日には会社の方々から出産祝いを頂いた。

取得後

このような生活をしていたので、育児休業開始当初に生活がとても楽になった。明け方に寝ることは変わらないけど、起きる時間の制約がないのはとても気楽だった。

8月

相変わらず夜のぐずりに苦しんでいる様子。

調子良いときもあるけど、逆にリズムが取れずそれはそれで難しいんだよなぁ。懐かしい。

夜の時間にコーディングをする習慣をつけた。8月頃は Gem を書いていた。

この頃の動きはまだもにょもにょする感じがありとても可愛かったよなぁ。産まれて数ヶ月だけの貴重な思い出。

9月

生後 3 ヶ月を迎え、徐々に意志を感じる行動をするようになった。

少しずつ遠めのお出かけを増やして、楽しんでいた。

書いていた Gem をリリースした。

blog.ebihara99999.com

10月

まだまだ悩んでいる。夜しっかり寝られるようになるのはだいぶ先だもんな。

お食い初めの袴を minne で購入した。妻が色々準備を進めてくれて本当にありがたかった。

minne.com

11月

平日の空いているときに行けて便利なので、コストコの会員になったのだった。継続しなかったけど、ミルクやおむつなどいろいろお世話になった。

頑張ってる様子と娘に翻弄されている様子。

12月

「絶対無理だよね」と夫婦で話しながら試してみたベビーフォト、予想通り見事撃沈していた。 撮影中スタッフの方が気を使って元気にあやそうとしてくれていたのだけど、この頃は特に大きな声や音が苦手だったのでスタッフの方が頑張れば頑張るほど泣いてしまい面白かった(面白くはない...)。

ハーフバースデー用に minne で購入したもの。着心地が良かったのか、娘も上機嫌でニコニコして着てくれていた。

minne.com

年賀状や新年の挨拶に使う写真のための帽子も minne で購入した。どちらもモフモフでとても似合っていてすごく良かった。

minne.com

minne.com

1月

勇気を出して初めての1泊旅行にチャレンジした。広い部屋で楽しんでハイハイして娘もとても楽しんでくれた様子でよかった。スケジュール管理に課題を見つけたので次の TRY とした。

2月

娘といると自分がトイレに行くのが億劫になるので水分補給を控え、かつ少ない水分補給をほぼすべてコーヒーですませた結果がこれ。マジで痛くて「このまま死ぬのかな...」と思ったので絶対ちゃんと水分取ると誓った。

ハイハイができるようになり、大喜びしている様子。

この頃には割と日常のイベントはこなせるようになっていたんだったなぁ。

3月

平日に旅行行けるのは最後になり、仕事始まったら当分行けないだろうなぁと思い1泊旅行に。前回の TRY もあったおかげかこなれた感じで楽しめた。4月から復帰のためドキドキしている。

4月

4月1日より復帰した。

取得してどうだったか

育児休業を取得して本当に良かったと感じている。

一番大きい理由は0歳から1歳までの思い出がとても多くできたことだ。今は懐かしむ余裕がそんなにないが、娘がライフイベントを迎えるたびにこの日々のことを懐かしむと思う。ふとしたときに回想できる思い出が多いというのはとても大きな財産になるのだろう。たくさんの写真とともに「あの頃はこんな様子だったなぁ」と実体験の記憶を遡れるのは本当に素敵なことだ。

ただ単純に楽しかったのかというとそうではなく、育児をメインに据えた生活は自分にとって大変だった。仕事から離れ社会との関係が希薄になっていき、新型コロナウィルスがそれに拍車をかけた。家庭の外と接点を持つのが難しく、精神的に辛いと感じることは多かった。

しかし、この大変さを考慮しても、育児休業を取得して本当によかったと感じている。

復帰後について

長期間離脱したことによる仕事への影響を書いておく。

復帰前は「ちゃんと仕事できるのだろうか...」と心配していたのだが、驚くことに以前より良い形で仕事ができている。

復帰当初はとても緊張していた。ある意味新入社員のときよりも緊張していたかもしれない。ブランクや生活の変化がある中で以前のように働けるのか、成果が出せるのかという心配が大きかった。しかし上司のサポートのおかげもあり徐々に「こんなに長く休んでいたのだからできないことがあって当たり前だし、子供がいることでプライベートの研鑽の時間はおろか仕事自体もお休みすることが増える。そんな中で全部完璧にやるなんて無理。」という事実を素直に認められるようになった。その結果

  • 周りに頼ることに躊躇しなくなった
  • 「自分にできないことがある」という事実にフラットに向き合えるようになった
  • 委譲ができるようになった
  • より大事なことに集中しようという意識を以前に増して持てるようになった

という変化が起こり以前より良い仕事ができている。

ところで、休日には子供の世話があるので、本当の意味での休みは少ない。育児が休める時間は保育園のある平日、すなわち仕事の時間なので、仕事がご褒美みたいな感覚になり「休日も平日も違う意味で休みなんでボーナスタイムじゃん」ってなっているのが面白い。仕事の間育児のことを気にせず仕事を楽しめるのは妻がそういう環境を作ってくれているおかげなので本当に感謝している。

ジュニアエンジニアに意識してほしいこと

あまり大きな成果が出せずに思い悩んでいるジュニアエンジニアの方に意識して欲しいことがある。ジュニアエンジニアとは、一人前の手前のエンジニアのことである。実績を残すこと以上に、成長するためのアクションを取れているかが求められている。成長途中なので、バーンとした実績を残すことは現実的に難しいかもしれない。だがそこでめげず成長のための種をまき続けて欲しい。

 

ミーティング中に分からないことがあれば躊躇せず聞く。もし都合が悪ければ「後でフォローするから後で話しましょう!」となるだけで誰も損しない。その都度質問することが当人に有益なのはもちろんだが、他の人が質問しやすい雰囲気を醸成することに繋がる。なんなら先輩もその環境に助けられるかもしれない。チームの良い文化を作ることに貢献するというのは誰にでもできることではない。

PRを作る時、分からないから既存の処理をコピペするという経験は誰にでもあると思う。それをしれっと出し、突っ込まれずマージしたとする。それでホッとしてしまうとそれに関する知識がつかないどころか、分からないことをやり過ごす悪習を身につけてしまうことにもなる。弊害として、意図ないコードをあげる人は信頼を得づらくもなる。誰にでも分からないことはあるので、「よく分かっていないです」と一言添えておけば誰かからのFBを得られる。自分がその知識について学べるし、チームメンバーも同じ内容を見聞きすることで学びが深まるかもしれない。

  • 分からないこと・できないことを表明する技術
  • 現状や気持ちを適切な形で表現し吐き出す技術
  • 自分が得するだけでなく他人にも影響を広げる技術

技術の前にソフトスキルとして僕はジュニアエンジニアにこれらを身につけていくことを求めている(もちろん一部であるが)。

既に書いたように、ジュニアエンジニアの成果はバーンとした実績を出すこと(だけ)ではないので、周りの職位が上のエンジニアが実績を残す中でもやもやしてしまうことがあったら、「職位が上のメンバーのようになるためにできることを今やれているか」と自問自答して欲しい。できていたら誇って良いし、できてなかったら明日からやっていけば良い。周りと比べて凹む必要は全くない。

成長スピードは人それぞれなので、色々な気持ちに折り合いをつけ成長するためのアクションをやめないことが大事なのである。

CodeKeeper v0.5.1をリリースした

v0.5.0をリリースした翌朝、ふとClass Lengthのメトリクス結果にNamespaceを付与してなかったことに気づいた。これではUserクラスもAdmin::Userクラスも同じUserになってしまうのでマズい。ということで以下のPRで直した。もし困っていた方いたらアプデしてもらえるとありがたいです。

github.com

いざとりかかってみると、ネームスペースを取得していないだけでなく、

class Root
  class A
    # このコメントのカウントが間違っていた
  end
end

のようなinner classがありそこにコメントがある場合、Rootクラスのコメントとして計上してしまうバグや、以下のように3つ以上ネストした場合

class Root
  class B
    class C
    end
  end
end

Rootクラスの行数を誤ってしまうバグなどを発見したので併せて修正した。

大変だったのは、コメントや空行の数を数える際、Inner nodeと親nodeで二重計上しないようにすることだった。例えばコメントの場合、Rubocop::AST::ProcessedSource#commentsでソース内のコメントの行数を把握し、node.first_line..node.last_lineのRangeに入るものであればあるnodeのコメントであると判断しても良いように思えていたが、そのクラス内にネストされたクラスを持ちコメントがある場合、当然二重計上となってしまうのであった。

この辺の煩わしさを避けるため、空行とコメントを数える際はInner nodeの行数を配列に持ち、あるnodeの本体が何行目にあるのかを正確に取得するようにした(余談だがRangeとArrayの変換や演算がとても便利だった)。

Namespaceに関して、上述したclass A;endのような記述には対応したが、Class#newやStructを利用した記述については、別実装となるため対応しなかった。なので

Class Root
  SubClass = Class.new
end

SubClass = Class.new

も両方SubClassと表示される。とはいえ、メトリクスを取りたいクラスでこのような記述、特にStructを使った記述はしないだろうと予想しているので、大きく困ることはないのではないかと思う。

コードの品質に関するメトリクスを取得するGemをリリースした

CodeKeeperというGemをリリースした。循環的複雑度、ABCソフトウェアメトリクス、クラスの行数という品質面にまつわるメトリクスを取得するGemで、Rubyファイルを対象にしている。

github.com

動機

主に以下の3つである。

  • Four keysのような生産性を測る指標とは別に、内部的な品質に関する指標を取りたかった
    • 継続的な改善を続けた結果としての変化を見たかった
  • コードを解析するコードを書いてみたかった
    • Saasなどもあるが自分で書いてみたかった
  • Gemを1から書いて公開したことがなかったのでやりたかった

使い方

メトリクス・出力形式

対応しているメトリクスは

  • 循環的複雑度(ファイル)
  • ABCソフトウェアメトリクス(ファイル)
  • クラスの行数

である。

前者2つは、実装の簡便さを鑑みファイル単位とした。また、出力について、取得したメトリクスをBigQueryなどに取り込めるように、csvもしくはjsonにて標準出力に吐き出す形とした。

設定

以下のような設定で、

  • 取得するメトリクス
  • 実行スレッド数
  • 出力フォーマット

を選択できる。

CodeKeeper.configure do |config|
  # If you choose metrics, specify as follows:
  config.metrics = %i(cyclomatic_complexity abc_metric class_length)
  # The number of threads. The default is 2. Executed sequentially if you set 1.
  config.number_of_threads = 4
  # The default is json
  config.format = :csv
end

以下は例としてGitlabの適当なファイルに実行した結果である。

$ bundle exec code_keeper app/models/user.rb app/models/ability.rb > metrics.csv 
$ cat metrics.csv                
metric,file,score
cyclomatic_complexity,app/models/ability.rb,9
cyclomatic_complexity,app/models/user.rb,24
class_length,Ability,86
class_length,User,1494
abc_metric,app/models/ability.rb,76.909
abc_metric,app/models/user.rb,1549.264
$

調べたこと

CodeKeeperを作るにあたり、以下をキャッチアップした。 コード解析やASTについてはRubocopのソースやRubocopAstのドキュメントを読み、実際に手を動かし挙動を確認した。その際pockeさんの記事にはとても助けられました。ありがとうございます。 qiita.com

pocke.hatenablog.com

Class length metricを作るときに参考にした rubocop/class_length.rb at master · rubocop/rubocop · GitHub 周りのコードが特に勉強になった。一行一行動かしながら意味を理解するのも楽しかった。return unless block_node.respond_to?(:class_definition?) && block_node.class_definition? の意味がわからなかったが以下のissueを見てなるほどーとなった。 github.com

実装の多くはRubocopを参考にしており、本当に感謝しかない。

メトリクスについて、株式会社Sider様のブログがとても参考になった(ありがとうございます)。基本的にはその記事のリンクを辿ったり、GMetricsの対応しているメトリックを調べたりして勉強した。

siderlabs.com siderlabs.com

dx42.github.io

作ってみて

Rubocopに依存しすぎている(private apiも使っている)のではがして実装しようと思っていたが、Rubocopがとてもよくできているし、中身読んで理解するだけで勉強になるしこれで良いかなという気持ちや、細かいところしっかり考えるのかなり大変そうという理由もあり、現在はRubocopに依存しているMetricsが多い。とはいえ、Rubocopでは内部的にMetricを計算した後違反の有無に応じて結果を保存しているため、結果(スコア)を取得することができずカスタマイズする必要はあったが。

また、アプデに追従するの大変かもしれないとも考えたが、依存先がそこまで多くないし問題にはならないだろう。そして作って感じたことだが、Rubyの表現力が高くバグにつながるパターンは(自分のRuby力では)ある程度ユーザーに見つけてもらう必要があり、そう考えると既に利用者が多くFBに対しきちんと対応しているRubocopに依存するのも悪くない選択肢だろうと考えた。

その他

Rubyでどう書くか、そしてそれがどう構文解析されるかに関する理解が深まるので、静的解析に関して遊ぶのは結構有益だなと感じた。

余談だが、README.mdにも書いた通りメトリクスを取得することはコードをきれいにすることに繋がるのでCodeKeeperという名前をつけたが、キレイにするのは人なので単純にRMetricsとかにすれば良かったかなと思っている。

育児休業を取得している

8月から半年予定で育児休業を取得しているので、現時点の雑感を残しておこうと思う。

育児休業かなり多くのメリットを感じているし、子供と過ごす時間がとても貴重なので本当に取得して良かったと感じている。

生後一ヶ月頃から私は育休を開始した。育児休業に入る前から積極的に育児に参加していたため、家の中で行う分には特に困ることはなかったものの、何事も二人でやったほうが楽なので、担当が二人いるというのはかなりメリットだった。「家の中で行う分には」と書いたことからも分かるように、慣れない場所でのお世話の難易度は家で行うときよりもはるかに高かった。育児休業開始時点で子の外出許可が出たので、育児休業開始と外出し始めが同時期だったが、育休のタイミングでたくさん外出し経験値を上げられたのはとても良かった。持ち物や必ず近隣の授乳室を探しておくなどの知見もたまり、今ではかなりスムーズに外出を楽しめるようになった(持ち物に関しては妻が対応してくれているのでとても助かる)。

また、娘は比較的敏感な子なので子育てに関する負荷は高めで、特に夜はまぁまぁキツイ。今は交代で見ているが、どちらかが働いていて一人で全部見る状態になると考えると、かなり厳しかっただろうなと思う。

実務的なメリットを上げてきたが、感じるメリットは他にもある。

一般的かどうかは分からないが、赤ちゃんは非線形な成長をするように見える。例えば、ある日を境に

  • 表情が豊かになる
  • 声を出すようになる
  • なにかに興味を持つようになる

など、突然急に何かが変わるのである。

継続して寝ることをあまりしない娘がミルク飲む以外ほぼ一日寝てる日があったのだが、その日を境に色々できるようになることが増え、顔つきも変わったということがあった。

非線形な成長と言ったもののそれらは本当に些細な変化であり、毎日一日中面倒を見ているからこそこの変化に気付けるのだろう。このような日々の変化を妻から聞くのではなく、自分で気づきリアルタイムで感動できるのは間違いなく育児休業のおかげである。このような体験が子育てで最も嬉しい瞬間の一つであり、まさに貴重な体験だと思う。

この記事、「さすがに育児休業取って3ヶ月くらい経つしさすがに書かないと...」と思って書いてるあたり、どれだけ密度の濃い時間を過ごせているかが分かる(まだ一ヶ月しか経過してなかった…)。

ところで、デメリットについて、心配なのは金銭面と仕事復帰への不安だが、まだ一ヶ月なので大きな問題だとは感じていない。また何かあれば書こうと思う。