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

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

2024年の振り返り

今年は自分の中で色々あった年だったなぁ。

まず念願の家を購入した。マンションの人みんな感じが良く必ず挨拶してくれるし、子どもにもとても優しく接してくれる点がとても気に入っている。引っ越して一ヶ月くらいで壁にクレヨンで落書きされたが、ピリピリしないで済むしなんなら良い思い出としてもう少し大きくなったときに話すことを楽しみにしている。

 

今年一番の変化は会社をやめて独立したことだろう。辞めて言うのも変だが全然辞めるつもりなんかなく、やりたいこともたくさんあったので勤め続け10年の永年勤続の賞をもらうのだろうと考えていた。とてもチャレンジングな環境で過ごさせて頂いたことを今でもとても感謝している。

しかしタイミングというのは恐ろしいもので、色々なタイミングが重なり独立してしまった。独立についてはずっと夢だったこともあり、やるならもう今しかないだろうと思い切ってみた。今のところ楽しくやれているので決断してよかったと思っている。迷ったときに安牌を選ばないのが自分の性格で今回もそのような判断をしたのだけど、今のところ楽しくやれているのでとても良い判断だったと思う。

独立してから家族との時間をより取れるようになった。それについて家族みんなとても嬉しそうにしていて、特に子どもとの距離がとても縮まった。子どもの成長を目に焼き付けながら、毎日を過ごせることがすごく幸せに感じている。いちプログラマに戻ったこともあり、技術力の向上にもプライベートの時間が割けているし、良いバランスで進められているように感じる。

 

独立して初めての現場では、久しぶりの IC プラス業務委託という立場もありどう振る舞うのが良いのか迷いつつ参画したが、結局普段通りに振る舞うことにした。年末の挨拶をした際、海老原さんがいなかったらプロジェクトがもっと大変だったはずととても嬉しい言葉をかけて頂けたので、心配だったがお役に立てたんだなとほっとした。チーム内外みなさんとても良い人で、個人的にわいわいやりたいタイプなのでこの辺もとても助かっている。出社してランチするのが楽しみという生活ができているのでとてもありがたい。

 

ところで、今年の夏から秋にかけては個人的に色々あったけど、家族と友人たちが気にかけてくれたおかげで、なんとかやってこられた。特に気にかけてくれた友人は今でも高頻度でやり取りして悩みを相談したり何でもない話をさせてくれるのでとても助かっている。世話になったお礼を先日の長電話のときに言えたのでよかった。今年はお互い色々あったけど、来年の戦略も見えてきたことだしお互いぼちぼちやっていきましょ。

 

ウェイト始めたいの夢は、前職の同僚が会社にあるジムに同行し色々レクチャーしてくれたのをきっかけに始めることができた。今は IT 健保の割引を使ってジムに通っている。キックボクシングも走るのもウェイトの効果が出ているし、体調も良いのでもっと早く始めればよかったなと思っている。

 

来年はまた色々忙しくなりそうなことが分かっているので、日々を楽しみつつやっていくつもりだ。

Ruby コードの内部品質に関するメトリクスを取得する

はじめに

この記事は Ruby Advent Calender 2024 の25日目の記事です。

qiita.com

内部品質に関するメトリクスとは

ソフトウェアの内部品質に関するメトリクスとは、大まかに言うと読みやすさに関するメトリクスのことを指します。プログラムの長さ、呼び出しの回数、条件分岐の多さ・深さ、代入の回数等を計測し、これらが悪化すると読みづらいプログラムになってくる、というものです。

メトリクスを用いたソフトウェア品質定量評価・改善 (GQM, Metrics, ET2013) ではプロダクトの分野として6つのメトリクスが定義されています。

ソフトウェアメトリクスのうち主なメトリクスに関する表

Ruby を書く方であれば Rubocop の MetricsCop に指摘をもらったことのある方もいらっしゃるのではないでしょうか。まさに当該 Cop の内容が内部品質に関するメトリクスで、2024年12月22日現在10個の内部品質に関するメトリクスの Cop が定義されています。 詳しく知りたい方は以下の公式ドキュメントをお読みください。

docs.rubocop.org

CodeKeeper について

上述のように、Rubocop では内部品質に関するメトリクスについて違反を指摘してくれます。しかし必ずしも推奨の閾値を守れるとは限らず、閾値を緩めるもしくは指摘を無視するという対応をしてしまう現場もあるのでないでしょうか。一方で、改善活動の結果、コードの品質が向上するケースも存在します。このような日々のアクションの結果を継続的に取得し、観察できるようにしておくことは意義があると考え、CodeKeeper という Gem を開発しました。

github.com

使い方

メトリクス・出力形式

対応している内部品質に関するメトリクスは

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

です。

前者2つは、実装の簡便さを鑑みファイル単位とし、出力については取得したメトリクスを S3 や 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.json
$  cat metrics.json                                                                                             
{"cyclomatic_complexity":{"app/models/ability.rb":10,"app/models/user.rb":28},"class_length":{"Ability":100,"User":2033},"abc_metric":{"app/models/ability.rb":95.5092,"app/models/user.rb":2047.3842}}

用途

どのケースも S3 や BigQuery などのデータストアに内部品質に関するメトリクスの数値を貯め、活用することを想定しています。

  • リファクタリング・技術負債の返済・カイゼン活動の結果として眺める

    現状を改善していく何らかの活動の結果としての指標の一つとして、活用します。

  • Four Keys などの生産性指標と同時に観察する

    現在開発生産性の指標の一つとして Four Keys があります。

    • デプロイの頻度 - 組織による正常な本番環境へのリリースの頻度
    • 変更のリードタイム - commit から本番環境稼働までの所要時間
    • 変更障害率 - デプロイが原因で本番環境で障害が発生する割合(%)
    • サービス復元時間 - 組織が本番環境での障害から回復するのにかかる時間

    引用: エリート DevOps チームであることを Four Keys プロジェクトで確認する | Google Cloud 公式ブログ という4つの指標を測り、チームの開発のパフォーマンスを測定するというものです。 (詳しく知りたい方や興味のある方は「LeanとDevOpsの科学」や「State of DevOps Report」などをお読みください。) cloud.google.com book.impress.co.jp

    Four Keys と内部品質に関するメトリクスを観察することにより、生産性と内部品質に相関がある場合に改善活動を始めるという手段が取れます。

  • 閾値を定めアラートをあげる( Slack などに通知する)

    上述の通り Rubocop の指摘を必ずしも守り続けられるとは限りません。その場合、徐々に当該メトリクスの品質が悪化し続けることが想定できるので、暫定で新たな閾値を設け Slack にアラートを通知する等の手法をとり、Rubocop の指摘以外の強制力を働かせます。

今後について

まず、メトリクスについて増やしていきたいと考えています。Groovy でメトリクスを取得するライブラリの GMetrics を目指していきたいです。

dx42.github.io

Ruby の表現力を網羅できるよう仕上げるのは利用者の FB がないとかなり難しいので、Rubocop の private API を積極的に利用するのはありな気がしています。自身で実装するのは楽しいので、とても迷うのですが...。

また、上記の用途で上げたように基本データストアに保存したいはずなので、S3 などにアップロードする機能は早めにサポートしたいなとおもっています。

これは Gem でサポートする話ではないですが、解析してグラフを表示するような Web サービスを作りたい気持ちでいます。

最後に

CodeKeeper は、自身が携わっていたプロダクトでのソフトウェアマネジメントに活用しようと思い作ったものです。しかしより優先順位の高い事項が多く活用ができないまま、私自身が独立しフリーランスになってしまいました。趣味プロジェクト等で使おうとは思っていますが、より本格的に活用した事例など聞けるととても嬉しいです。荒削りですが、FB や要望等お待ちしています。

Ruby のコード品質のメトリクスを取得する Gem の CodeKeeper v0.6.1 をリリースした

CodeKeper とはRuby のコード品質のメトリクスを取得する Gem のことである。

blog.ebihara99999.com

ある程度形にしてからずっと触れていなかったのだが、以下の PR を頂いたので確認してマージした。

github.com

その際 EOL の Ruby の CI を回していることに気づきサポートを切った。

github.com

ダウンロード数はある程度あるんだけど使っているみたいな話を聞くことはなかったので、今回 PR を頂けて非常にうれしかった。 余談で僕は必ず issue や PR 投げるときには「 Thank you for the great gem. 」 と書くようにしている(使っているので実際すごく感謝している)が、今回頂いた PR に類似のお礼が書いてあって「こんなにうれしいんだ」と感動したので、続けていこうと思った。

この Gem を作ったときは自分が見ていたサービスのコードを使い品質のマネジメントに使おうと思っていたのだが、とある経緯で CTO を目指すことになり、あまりそちらに時間を割けなくなってしまい使えずじまいだった。(このような試みは大事だが、 CTO は一経営者なのでまずは経営陣に認めてもらう実績やふるまいをする必要があり優先度がさがってしまったのであった。)

今はフリーランスとして活動しているが、コードの品質という部分に自分はとても興味があるんだと改めて感じていて、何か OSS のメトリクスをとったりこの Gem に機能を追加しつつ育てたり活用していきたいな、と思った矢先に PR を頂けたのですごくタイミングが良かった。次は S3 に json あげて解析できるようにしたいのでやっていく。

ActiveModel::AttributeMutationTracker を読んだ

今日は朝刊(yyagi さんの「なるようになるブログ」)で取り上げられてた PR から ActiveModel::AttributeMutationTracker を読んだ。

y-yagi.hatenablog.com

属性変更をトラッキングするクラス。ActiveModel::Dirty とかで使われていそうで馴染みがあったのでシュッと読めたが、ForcedMutationTracker クラスが何のためのクラスかわからなかった。

コミットログから高速化の目的で切り出されているのが分かった。 force_change を track するために切り出したクラスなんだけど、ivar backed のものと attributes backed のものを一緒に動かすとすごく遅かったので切り出したとのこと。ソースとにらめっこしたりオブジェクトの中身見たりしたけど、いまいちなぜこれでここまで高速化されるかが分からない...ぐぬぬ。それにしてもすごい成果だ。

PR

github.com

「良いテストコード」の議論から気づいた価値観の違いの由来について

良いテストコード、と言われて思い浮かぶ要素はいくつかあるだろう。

  • 過度に DRY になっていない
  • 上から下に読み下せる
  • 仕様を網羅している
  • テストデータが過不足なく当該セクションで作られている

など。

たまたま良いテストコードについて議論する機会があったのだが、DRY 具合について話していたとき

過度なDRYを行わず、APIドキュメントだと思って書く 脳内メモリを消費させない“リーダブルなテストコード”の書き方 | ログミーBusiness

のようなリンクを見せ説明したが僕のいわんとすることがあまり伝わらなかった。そして相手が重要視していることも正直なところあまり理解できなかった。 価値観が違うのだろうということは話していて感じていたが、どうしてこういう違いが生まれるのだろうということを疑問に思った。「育ってきた環境が違うから」とは思うものの、より本質的に理解するにはもう少し何かが必要だなと感じ考えていた。

僕はテストを(特にユニットテストを)きれいな設計・実装を助ける道具だと捉えていて、そういう世界を実現するために使っている。依存関係を正常に切り出し、インターフェースを整え、ケースを整理しデバッグするための手段の一つだと捉えている。一方、おそらく議論した方はあまりテストを書くのが得意でないか、もしくは実装は開発環境で確認しすべて実装が終わったあとに品質のためある種の義務として書くものというように捉えているように見えた。

これでは良いテストについての価値観が違うのは当然で、どっちが良いというわけでなく使う道具の目的が違うんだからそれに求めるものや理想が異なるのは当然のことだろうと腹落ちした。(もちろんテストを使いこなすメリットは大きいとは思うが、色々な開発方法がありバリューを出しやすい方法を採用すれば良いと思うのでその是非はここでは問題にしていない。)

僕が PC に求めるものと営業の方が PC に求めるものは違うだろうし、趣味ランナーの僕がランニングシューズに求めるものとプロランナーがシューズに求めるものは違うだろう。

どっちが良いとか悪いではなく、そういうことなのである。

ActiveRecord::Reflection を読んだ

空いた時間に Rails コードリーディング。今日は ActiveRecord::Reflection をザーッと読んだ。

ActiveRecord::Reflection は model の関連付けに関するデータを保持するクラスという感じだった。例えば、belongs_to の実装では

def belongs_to(name, scope = nil, **options)
  reflection = Builder::BelongsTo.build(self, name, scope, options)
  Reflection.add_reflection self, name, reflection
end

のように add_reflection を呼んでいる。

細かいオブジェクトのふるまいを見たかったのだが、binding.irb を使うと

SyntaxError: /home/vscode/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/irb-1.13.0/lib/irb.rb:1600: syntax error, unexpected `end'

というエラーが出てしまうの、IRB の不具合だったりするのだろうか。全然ちゃんと調べてないけど地味に困っている。

ActiveModel::Access について調べたメモ

Rails のコードリーディング、久しぶりにしてみようと思いどこから読もうか眺めていたらたまたま見たことないモジュールが見つかったので読んだ。

ActiveRecord::Base#sliceActiveRecord::Base#values_at を ActiveModel に移植したもの。non-Active Record なモデルで利用したかったからという理由。

github.com

テストを回して挙動を確認した

irb(#<AccessTest:0x00007f095f9d5bb0>):008> @point
=> #<AccessTest::Point:0x00007f095f504398 @vector=[123, 456, 789]>
irb(#<AccessTest:0x00007f095f9d5bb0>):009> @point.x
=> 123
irb(#<AccessTest:0x00007f095f9d5bb0>):010> @point.y
=> 456
irb(#<AccessTest:0x00007f095f9d5bb0>):011> @point.z
=> 789
irb(#<AccessTest:0x00007f095f9d5bb0>):012> @point.slice(:x, :y, :z)
=> {"x"=>123, "y"=>456, "z"=>789}
irb(#<AccessTest:0x00007f095f9d5bb0>):013>