リファクタリングのハードル、自分で上げすぎてない？

# はじめに

年次関係なく誰でもできる小さな品質改善活動の話をします。

私事ですが、今年の1月に同じ部署内のCI/CD Grp.に異動しました。 CI/CD Grp. という名前ではありますが、組織でやっていきたいのは [Developer Productivity Engineering](https://zenn.dev/hiro_torii/scraps/89b8b1bd04eced) で、CI/CD関連の業務以外にもいろいろと自由にやらせてもらえてます。

『いいコードを学んだけど、最近コード書けてないや』と、ふと思ったのでせっかく書くなら品質上げるコミットをdevelopブランチにマージするナニカをしようと思ったのが本記事の背景です。

# 仕様化テストとリファクタするぞ！と意気込んでました

今まで一生懸命がんばってきた甲斐があって、保守しやすいコードを書く大切さを理解し、意図をもってコーディングできる自信がついてきました。（成長したね...）

『CI/CD Grpメンバーとして、他グループの開発メンバーが楽しく開発できるように既存のコードをよりよくしたいなぁ』ということで、自分が観測できる範囲でプロダクトコードに手を加えようと考えました。

コードの品質が劇的に向上するなんてことはほぼないはずなので、小さな積み重ねがとっても大事ですよね。で、自分にもできる小さな改善活動はないかと考えた結果、ぱっと思いついたのは、クラスやメソッドに仕様化テストをかぶせて、リファクタしていくこと。

異動する前のグループでは『いつかこのクラス（or メソッド）をリファクタする』という動機で切られたまましばらく着手されていないチケットがいくつかあったので、それらを対象にやっていくか、と。

# それ本当に効果あるんかな？

てなわけで、開発者たちが「手を付けたいけど手が届かない（優先順位が１番にならない）」ところにアプローチしていけば、製品品質は上がるしほかの開発者もハッピーだし優しい世界だなと意気込んでいたわけです。

なので、師匠のところに『こういうことやろうと思うけどどうです？』と1on1で企画しに行ったのですが..................。

『 **すごく良い行動だと思う。でも、もっとコスパのいいリファクタリングがあるんじゃない？思い描いている「リファクタリング」って、遠すぎない？なんか...頑張りすぎてない？** 』

『 **──────ッッッ！？！？！？！？！？！？！？！？！？** 』

ここで言っているコスパがいいというのは「**テスト不要だけど効果が見込める**」というものです。

例えば、

- 変数名がわかりにくい -> 分かりやすく命名しなおす（機械的リファクタ）
- 長いメソッド -> 適切な単位に切る（機械的リファクタ）
- 深いネスト -> 浅くする（早期リターンなど）

たしかに、これらはテストを書かずに理解容易性上がる、そして誰でも簡単にできるじゃん。

一方で、自分がやろうと思っていたリファクタリングはというと、さすがに着手されてこなかっただけあって重たいものが多め。シンプルに難易度が高そう（神クラス・１メソッド数百行とか）、加えて効果があるかは不明...。

# 理解容易性を上げるためのtipsを思い出す

以前私は、「保守しやすいコードは「変更容易性」「理解容易性」「テスト容易性」が満たされている」という記事を書きました。[^以前書いた記事] 

変更容易性・テスト容易性を上げるリファクタよりも、理解容易性を上げる方がよりハードルが低い（見た目を整えるイメージでできるものもあるし）気がしています。

> 理解が容易である = 該当の処理がすぐ特定できる かつ 誰が見ても同じ解釈になる かつ 解釈に至るまでのスピードが速い

で、特に機械的なリファクタリングや、内部実装をいじらなくてもできそうなのは以下を目標に改善していけそうです。

> - 誰が見ても同じ解釈になる
>   - 明確な命名規則
>   - 適切なコメントアウトやドキュメンテーション
> - 解釈に至るまでのスピードが速い
>   - シンプルで直感的なロジック
>   - 役割ごとに適切に分割されたクラスやメソッド

こういう変更、バカにできません。余計な脳内メモリもっていかれますからね。

[^以前書いた記事]: 自分で言うのもなんですが、コーディングうまくいかないと思っている方にすごくおすすめな記事です。 [新人プログラマ アンチパターン：原理原則多すぎて脳みそOOMエラー](https://qiita.com/_mi/items/d008267d2e181bc7ba25)

# 勝手に自分でハードルを上げていた

『[テストがないコードはレガシーコードだ！](https://www.amazon.co.jp/%E3%83%AC%E3%82%AC%E3%82%B7%E3%83%BC%E3%82%B3%E3%83%BC%E3%83%89%E6%94%B9%E5%96%84%E3%82%AC%E3%82%A4%E3%83%89-Object-Oriented-SELECTION-%E3%83%9E%E3%82%A4%E3%82%B1%E3%83%AB%E3%83%BBC%E3%83%BB%E3%83%95%E3%82%A7%E3%82%B6%E3%83%BC%E3%82%BA/dp/4798116831)』とか『[テスト駆動開発だ！](https://www.amazon.co.jp/%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA-Kent-Beck/dp/4274217884)』とか、生まれて間もないころから耳にしてきたので、勝手に「品質改善 = そういうことをしないといけない！」とばっかり考えていました（しないといけないんですけどね）

リファタリングは「プログラムの入出力（インプット/アウトプット）を変えずに内部設計を改善（可読性や保守性の向上）すること」ですが、目指しているのは結局ソフトウェアの振る舞いや機能を変更せずに、**ソフトウェアの内部品質を向上させること**ですよね。

ここで目指している内部品質ってのは「保守しやすいコード」で、つまり変更に強くて理解しやすいコードの認識です。

今まで無意識に変更容易性の向上を考えていたけど、理解容易性の向上だって立派な品質改善の取り組みだよね、と気が付くことができました。

※ リファクタリングは「振る舞いを変えずに内部実装を改善すること」だから名前の変更はちょっとズレてるくね？というツッコミはNG


# 今日からすぐできそうなこと

てなわけで、せっかくなので誰でも明日からすぐにできそうなコードの品質改善案を共有します。（なかにはテストかぶせたほうがいいものも含まれるかもしれません）

### 変数らへん

| すぐできること | たとえば |
| :--:  | :-- |
| 変数名 | 的確な命名・長い変数名を短くする、など |
| マジックナンバー | 定数化する・enum化する |
| 無駄な宣言 | そもそも宣言する必要がないとか、ほぼ使われてないとか |

### メソッドらへん

| すぐできること | たとえば |
| :--:  | :-- |
| メソッド名 | 的確な命名・長い場合はメソッドを切ること考える |
| メソッド分割 | 責務ごとにを分割する |
| パラメータ | Valueオブジェクトなどにして引数を減らす |
| 共通化 | 再利用可能なコードをメソッド抽出（共通化の罠に注意） |
| ネスト浅くする | メソッド切るとか、早期リターンとか |
| メソッドの移動 | デメテルの法則を遵守して高凝集化[^デメテルの法則] |
| コマンド・クエリの分離 | 主作用と副作用が１メソッドに同居しないようにする |

### ドキュメンテーションらへん

| すぐできること | たとえば |
| :--:  | :-- |
| コメント追加 | JavaDocなどの追加でコードの意図を明確にする |
| コメント削除 | メソッド見たらわかるコメント消すとか |
| 空白行追加・削除 | 可読性を考えていい感じにする |


ほかにもいろいろできることはあるかと思うので、

- １週間ごとにテーマを区切ってやる
- みんなを巻き込んでキャンペーンする

みたいな感じで楽しく継続的にやっていければベストですね！

[^デメテルの法則]: 尋ねるな、命じよ。の原則（Tell, Don't Ask.）も似たようなことを言ってますが、「インスタンスを使った必要な処理は、インスタンスを持っているオブジェクト（クラス内）で処理させましょう」てことです。

# さて、どこからやっていこう？

コスパを考えたら「多くの人が読むコードから」やっていければベストですが、計測が難しいです。
なので、「**より多く変更が加えられているクラスから**」、がいいのではないでしょうか。

その中でもさらに優先順位をつけるとするなら、

- 自分が過去に修正を加えたコードとその周辺から
- 静的解析の結果で判明したCodeSmellがある箇所から
- 今やっている機能強化・不具合修正しているところから
- テストカバレッジが低い箇所から

などでしょうか。
ここはメンバーや組織の方針などを考慮して決められたらいいと思います。

**▼ 参考 ▼**

「特定ディレクトリ以下の変更回数の取得」に関しては以下のGitコマンドでテキストファイルに出力できました（適宜いい感じに改造してください）

```bash
$ git log --name-only --oneline --diff-filter=M --since='5 years ago' -- <ディレクトリのパス> | sort | uniq -c | sort -nr | awk '{print $1 " " $2}' > diff_with_counts.txt
```

# 機械的リファクタでこういうのもあるよ

https://docs.openrewrite.org/

使うレシピによっては一瞬でこうなる（GitLabのMR画面）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3388832/d82e535f-90b0-94d2-b84d-f20d333d4483.png)


参考記事：

- [【初見者向け】Javaのリファクタリングツール OpenRewriteを少し検証](https://qiita.com/kyappamu/items/78227dfb17916f4ec326)
- [大規模なコード書き換えツール OpenRewrite の使い方](https://blog1.mammb.com/entry/2023/12/09/090000)



# おわりに

結局、こういう改善活動が評価される組織文化が一番大事だと思います。（みんな忙しいからね...）

小さなことからコツコツとやっていきましょう。誰を巻き込んで一緒にやると楽しいよ。