コーディングアンチパターン

# まえがき

どうやったら品質の高い開発をチーム全体で行えるか考えていた時に、ベストプラクティスを広めるよりも、やってはいけないことを広めた方が効果が高いのではないかと思いました。

よくよく考えれば、ベストプラクティスなんかはよく調べているのに、やってはいけないことについてはちゃんと勉強したことがありません。

良い機会なので、そういったやってはいけないこととして広く認知されていることを調べて、他の人にも知ってもらえるように記事にしようと考えました。

<br>

この記事ではアンチパターンについてまとめています。

新人エンジニアの方は今後の業務に生かすために、経験者の方は共感を持って楽しんでいただければ幸いです。

# アンチパターンとは何か

アンチパターンという用語は『オブジェクト指向における再利用のためのデザインパターン』という、開発におけるベストプラクティスをまとめた本をもじったものです。

「デザインパターンの反対の（anti）パターン」がアンチパターンです。

ただただ悪例の総称がアンチパターンと呼ばれたりしますが、実はちゃんとした定義があります。

> - 動作やプロセス、構造についての繰り返されるパターンで、最初は有益だと思えるが、最終的に悪い結果をもたらすもので、
> - リファクタリングするための方法が存在し、文書化され、実例で証明されており、再現可能であること

*https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%B3%E3%83%81%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3*


最初から悪いと思われているものがアンチパターンであるわけではないのですね。

言うなれば、知らなければ自ら進んでいってしまう**落とし穴**のようなものがアンチパターンであり、存在や対処法を知っていればそれほど怖くないということです。


# 良いコードとは何か

実際のアンチパターンの紹介に進む前に、良いコーディングとはなんなのか、ここで確認しておきます。

良いコードとはつまり、**保守性の高いコード**です。


## 保守について

まだ現場に入ったことがない新人の方向けに保守について説明しておきます。

システムは開発して納品したら終わりではありません。

たまに成果物を他社さんに渡して、あとは向こうに任せるということもありますが、基本的にその後のメンテナンスは自分たち、あるいは保守チームの人が行います。

保守では「障害対応」「機能拡張」「セキュリティパッチの適用」「OSのアップデート対応」など、様々な対応をします。


## 「保守性が高い」とは

保守性の高いコードとはつまり、開発後のさまざまな対応において、開発にかかわらなかった人でも**理解しやすく**、追加機能などの**拡張が容易**であるということです。

もしもあなたがあるシステムの追加機能開発を頼まれた時、改修するコードが1千行近くある上に夥しい数のif文が何層にもネストしていたらどうでしょうか。

改修すべき箇所を特定するのにも時間がかかりますし、テストするためにどんな条件で行えばいいか理解するのにも追加の時間がかかります。

アンチパターンはその様な保守性の低いコードを意図せず生み出してしまうパターンのことです。


# 有名なアンチパターン紹介

アンチパターンとはなんなのかをみてきたところで、ここからは一般に知られているアンチパターンを見ていきましょう。

実際に自分や周りがやってしまっていないか考えてみてください。


## スパゲッティーコード（Spaghetti Code）

アンチパターンという文脈以外でも耳にすることが多いかと思います。

理解しにくいコード全般を指す場合にも使われますが、意味的には**処理やモジュール間の関係が複雑に絡み合っており、実行順序が把握しにくい**コードのことを指します。

例を挙げると：

- グローバル変数があちこちで読み書きされている
- モジュール同士が連鎖的に互いを呼び出し合っている
- クラスで過度な継承を行なっている
- 整理されていない並列処理

などがあります。

中でも最も多いのはグローバル変数の多用と脈絡のないモジュール間の呼び出しです。

プログラミングを始めたての初学者がやりがちなパターンですので、初学者の方は自分のコードが分かりにくいものになっていないか、常に意識するようにしましょう。

:::note

### 考えられる対策

- グローバル変数で状態を保持するのではなく、状態を表すオブジェクトを処理間で受け渡しする
- モジュールの用途を適切に狭める
- 継承よりはインターフェースを使って振る舞いを統一する
- 定期的にリファクタリングを行う

:::

## 打ち出の小槌（Golden Hammer）

別名**銀の弾丸**です。

**ある場面でうまくいった方法が、別の場面でもうまくいくと信じ込む**ことを指します。

**デザインパターン**を学び始めた頃、自分もこれに陥っていました。

オブジェクト生成が必要になるたびに**Factoryパターン**を使ったり、開発の初期段階から**Adapterパターン**を取り入れたりしていました。

解決方法は本来、問題が起こった環境や状況に結びついているものです。

それがわからずに、自分が学んだばかりの方法をまるで**銀の弾丸**であるかのように扱ってしまうと、無駄な処理が増えたり、できたはずの最適化ができなくなったりしてしまいます。

何かのツールやプラクティスについて学ぶときは、それが**なんのためのものなのか**、**どういう場合で効果的なのか**考えつつ学びましょう。

:::note

### 考えられる対策

- トレードオフについて把握する
- パターンやプラクティスよりも、理解のしやすさを優先する

:::

## ボートの碇（Boat Anchor）

**役に立たないものを「いつか使えるかもしれないから」とそのままにしておく**ことです。

ホルダー気質のプログラマーバージョンといったところでしょうか。

そういう処理は大概、後になっても使いません。

システムは時間によって変化していき、求められるものも変わっていきます。

つまり、時間が経つほどにその**いつか使う処理**を実装した時から状況が変わってしまいます。

どうしても残しておきたいなら、自分のPCのフォルダの中にひっそりとしまっておきましょう。

:::note

### 考えられる対策

- 機能は必要になった時にその都度実装する
- 実装する前に改めて要件を確認する

:::

<details>
<summary>死んだコード</summary>

ちなみに、似た様なアンチパターンに **死んだコード（Dead Code）** というものがありますが、そちらは「使わないとわかっているのに残されているコード」のことです。

経緯を残すために残されていることが多いのですが、そんなものはドキュメントに残すべきです。

今現在のシステムと関係のない処理はいたずらに混乱を招くだけでメリットはありません。

使わないとわかったらその場で消す様にしましょう。

</details>

## 神クラス（God Object）

**処理を詰め込みすぎていて、責任範囲が過剰に広くなってしまっているクラス（オブジェクト）** のことです。

「こいつさえ呼び出せば大丈夫」と同僚が実装したクラスを鼻高々に勧めてきたらその鼻を即座にへし折りましょう。（本当に実行しないように）

処理が一極集中していれば理解も容易いと考えるかもしれませんが、異なるビジネスロジックが混在しているクラスは変更が容易ではなくなります。

あと単純に1クラスに数千行も詰め込まれたコードはめちゃくちゃ読みにくい...。

ひとつのクラスはひとつのことに専念させる様にすべきです。

:::note

### 考えられる対策

- [**SOLID**](https://ja.wikipedia.org/wiki/SOLID)に則ったクラス設計を行う
- クラスの処理がそのクラス名から推測できるものになっているか考える

:::


## マジックナンバー（Magic Number）

**それがなんなのかの説明もなしに使われている数値**のことを**マジックナンバー**と呼びます。

円周率（`3.14`）などのよく知られている定数ならともかく、なんの脈絡もなしに現れた数値はコードを読む人にとっては謎の数字です。

いじってもいい数値なのか、もしいじったらどんな影響が出るのか、何も伝えて来ず、把握するために前後の処理を読み解く必要が出てきます。

決まった数値を使う際は必ず変数か定数に持つ様にしましょう。

円周率やデータ型の最大値などの数値はどの言語でも定数として用意されている場合が多いので、積極的にそれらの定数を活用しましょう。

:::note

### 考えられる対策

- 意図が伝わりやすい変数名をつけてそこに格納する
- 言語が用意している定数を利用する
- 適宜コメントをつける

:::


## カーゴ・カルト・プログラミング（Cargo Cult Programming）

これは**コーディングスタイルやパターンを、その背景や目的を理解しないまま実装する**ことを指します。

ドメイン駆動設計やクリーンアーキテクチャなどの設計パターンを学んだばかりの技術者が、よく理解もせず、ただ**有用だと言われているから**という理由で実装に使っている場合はこれに当てはまります。

どんな設計パターンやデザインパターンにも、それが考案された背景があり、利用する理由があります。

それを理解せずに場違いな場面で実践してしまえば、意図がよく理解できないコードやモジュールが出来上がってしまいます。

コーディングする際は、成果物についてちゃんとその様に実装した理由を説明できるかどうか、適宜振り返ることを心がけましょう。

:::message

### 考えられる対策

- 他の人に自分の実装についてちゃんと説明ができるかどうかを考える
- 実装パターンについて学ぶときは、その背景も一緒に学ぶ

:::

<details>
<summary>コピーアンドペースト</summary>

全ての**コピペ**が悪いとは思いませんが、その内実を理解しないまま実装に組み込む場合はカーゴ・カルト・プログラミングとなります。

</details>

# あとがき

今回はアンチパターンについて紹介しました。

「やってはいけないよ」ということを、連想しやすい名前と共にまとめてくれているのはありがたいですね。

改めて調べてみると、今回紹介したもの以外にも知らなかったアンチパターンを知ることができてとても有意義でした。

ぜひ皆さんもご自分で調べてみて、今後のプログラマーライフの糧にしてください。

---

#### 参考文献

- [アンチパターン](https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%B3%E3%83%81%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)
- [新人プログラマ アンチパターン：原理原則多すぎて脳みそOOMエラー](https://qiita.com/_mi/items/d008267d2e181bc7ba25)
- [6 Types of Anti Patterns to Avoid in Software Development](https://www.geeksforgeeks.org/6-types-of-anti-patterns-to-avoid-in-software-development/)
- [良いコードとは何か - エンジニア新卒研修 スライド公開](https://note.com/cyberz_cto/n/n26f535d6c575)
- [スパゲッティプログラム](https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%91%E3%82%B2%E3%83%86%E3%82%A3%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0)
- [カーゴ・カルト・プログラミング](https://ja.wikipedia.org/wiki/%E3%82%AB%E3%83%BC%E3%82%B4%E3%83%BB%E3%82%AB%E3%83%AB%E3%83%88%E3%83%BB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)
- [What Is a God Class and Why Should We Avoid It?](https://linearb.io/blog/what-is-a-god-class)