魑魅魍魎クソコード中級編

# このコード書いたの誰だy…一週間前の私じゃねぇか
今までに自らつくりだしてしまった異類異形、種種雑多のクソコードたちです。
// [初級編はこちら](https://qiita.com/matty_alh/items/6d25f4e013796f6310ca)
いろいろとあってこうするしかなかったんだ……というオトナの事情と無知ゆえにやらかした過去が入り混じった。ちょっぴりしょっぱい思い出味。
今回はShellScriptとJavaで3本立てです。
クソコードで胸やけしても大丈夫な準備ができたぜ！という方だけどうぞ！
（今回も全部本当にあったシリーズです）

# クソコードをクソコードで打ち消さざる得なかった話
## ことの発端
ShellScriptで実行する初期コマンドの実行確認についてのやりとりがきっかけでした。

ちょこっとえらいひと
「うっかり間違えてコマンド実行しちゃわないようにy/nの入力チェック2回いれてほしいんですよね」

わたし
「ちょっとうざいタイプの退会させてくれない会員サイトかな？（わかりました！）」

## 言いたいことしかねぇ！！！
セーブデータの削除の時に何回も確認してくる[星の●ービィ](https://dic.pixiv.net/a/%E5%BE%8C%E6%82%94%E3%81%97%E3%81%BE%E3%81%9B%E3%82%93%E3%81%AD%3F)じゃねぇんだぞ。
実行するとき手順書に沿って2名体制とかで実行確認するのにミスるのは悪意だろもはや！！とキャンキャン喚いたのですが、抗議はむなしく2回実行確認を実装することになりました。
偉い人にはわからんのですよ。

## 実装
コード自体は非常に簡単で、y/nの入力確認のスクリプトを**愚直に2回書きました**。
function化するのも馬鹿馬鹿しくなってしまって、いつか消すのであれば愚直に2回書いてしまったほうがいいだろう。の判断です。

```bash:うろ覚えの再現
#!/bin/bash
#前略
while true; do
    echo -n "$* [Y/n]: "
    read ANS
    case $ANS in
      [Y]*)
        ;;  
      [Nn]*)
        return 1
        ;;
      *)
        echo "実行しますか？"
        echo "Yまたはnを入力してください"
        ;;
    esac
  done

while true; do
    echo -n "$* [Y/n]: "
    read ANS
    case $ANS in
      [Y]*)
        ;;  
      [Nn]*)
        return 1
        ;;
      *)
        echo "本当に実行しますか？"
        echo "Yまたはnを入力してください"
        ;;
    esac
  done
# 後略
```

## だから本当にそれ要りますか？って私聞きましたよね…！？
コマンドを作成してしばらくすると、各種初期スクリプトをまとめて呼び出しできるような親バッチみたいなのが欲しいね、という話になりました。
子となるスクリプトは自動実行ができるようにしたいということで、オプション付けて入力処理を消すのはどうだろう？という案も出たのですが、**これ以上コードをクソにしてたまるか**と思ったので、改修はせず、回避策としてyesコマンドを用いて無理やり全部Yって打ったってことにしようという方針に……

```bash:更なるクソコード爆誕の瞬間である
yes Y | init_hoge.sh
```

何が悲しくて、自分で作ったクソコードを更なるクソコードで打ち消す羽目になってしまったのか。
yesコマンドってサーバに負荷を与える以外の利用方法もあるんだ…と初めて知ったエンジニア2年目の出来事でした（時期はもう覚えてない）

# 何もわからずにグローバル化してスレッドセーフをぶっ壊した話
これはもう無知な私の完全なるやらかしです。
Javaではローカル変数のみがスレッドセーフとなります。スレッドセーフとは、ざっくり言えば同一のコードを複数同時並行的に実行しても問題が発生しないような作りのことを指します。
逆にグローバル変数というのは、プログラムのどこからでも参照できる変数のことです。

## いたずらにグローバル化してしまうと何が起こるのか……
オブジェクト指向型プログラミングの概念がまだ全く理解できておらず雰囲気でJavaを書いていた駆け出しエンジニアの私は、「あれ？この処理スコープ外やから呼び出せへんやん。この処理、ほかからも参照できたほうが便利やし、staticにしたろ」と気軽な思いでコードをpublicでstaticなものに書き換えてしまいます。

```java:全然覚えてないけど間違いなく私がやったことだけ覚えてる
// 変数じゃなくてメソッドかなんかだった気がするけど間違ってるかもしれん
public static void getHogeList() {
  /**
   * 表示用に店舗ごとのデータをDBから取得して処理する
   * というような内容だったと思うんだけど…
   * もう戻り値も引数も覚えとらん
   **/
}
```

## そしてデータは上書きされる
テスト工程も結構終盤に差し掛かっており、性能面でコード修正していた際にやらかした出来事だったのですが、当時のPLの方がまじで一生尊敬するレベルで天才的な方だったので「同時実行テストもやろうね」ということで、隣の人と「せーの」でデータの検索→表示処理を実行しました。

すると
「Aさんが001店舗で検索したデータが、Bさんの検索した002店舗のデータに上書きされている」
ということが発生します。

**これがスレッドセーフぶっ壊れコードです。**

幸いなことにSVNで管理していたコード履歴から原因はすぐさま明らかになりました。
特に怒られることはなかったのですが、「もしかしたら他にもスレッドセーフではないコードがあるかも」という仮説のもと、すべてのグローバル変数を調査するという羽目に。

## 基礎って本当に大事なんだな、と改めて初心者が身を持って冷や汗かいて経験するのも大事なんだよなぁ…
Javaに限らずグローバル変数の多様はだめだよ、という記事は世の中に大量にあるかと思いますので、本記事では取り上げません。
結果のみ見ただけでもいかに愚かなコードだったかはなんとなく伝わるかと思います。

Java初学者のみんなは、publicとかstaticとかを「おまじない」だと思っていたらいつか痛い目に遭うかもしれないぞ！ということだけ学び活かしてください……

# ギリギリ全開限界状態で書いたTODOなんて誰が直すんだよ…という悲しい話
大量の改修に新規コントローラークラスの山、定められた期限は刻一刻と迫り、ほとんど毎日を終電ギリギリくらいで帰宅しながらコードを書く……という時代を私も一度経験したことがあります。// 二度とやりたくないｗ
各人員で手分けしても終わらないコーディング、ただでさえ複雑な画面遷移と大量の入力フォーム、独自バリデーション、一癖も二癖もあるWebテンプレートエンジン。いつまで経っても仮置きのまま組み込まれた新元号…（まさに時代の節目の時期でした）

## 炎上は人とコードを狂わせる
大量のコントローラークラスをさばく中、本来ならば共通化してサービスで処理するべきコードを、作ったそばからテストしなければならない状況化で「いったん」「後できっと直すから」という想いを`TODO: いつか共通化する`というコメントに残し、ひたすら終わりだけを目指してコーディングとテストを分担し、疲労で脳は回らず、コピペでコードを量産するという無策に走る羽目になりました。

冷静に考えてみれば、前工程からすでに遅延が発生している中で、事前にやるべき仕様が決まっていたならば共通化処理を最優先で作成する、ということも可能だったはずなのに、どうしてそんなことになったのか、今となっては「炎上は人とコードを狂わせる」としか言えないです。

## 共通化しなかった処理は、個別にテストせざるを得ない
ひとつ前に記載したグローバル化とはある意味で対極にあるような話です。
各コントローラークラスに同じ処理をバラバラに記載しているのですから、そのコントローラーが表示する画面ごとにテストを行う必要が発生します。
共通処理であったのであれば修正しても１つ確かめれば済んだところを、１つ修正が発生したらすべてのコントローラークラスを修正し、すべての修正対象画面を再テストしなくてはなりません。

ただでさえ遅延している中で、致命的でした。かといって余裕のない中で今更共通化をしたところで間に合わないし、他のテストの打鍵にも影響してしまう…

## 「いつか直す」の「いつか」はとうとう訪れなかった
かくして、総合テストのフェーズまで修正と打鍵を繰り返し、コードは凍結されました。
私が残した`TODO: いつか共通化する`は次年度までそのまま残される羽目になり、私はそのプロジェクトを去ることになります。
いつか直そう、と思っていた機会は二度と来ることはなく、「あの時、TODOメッセージを遺言のように書き残してしまったな……」という切ない思いだけが私の記憶の中に残っています。
その後、処理が共通化されたのかどうか、私には知るすべもありませんでした。

それ以来、誰が書いたかわからない`FIXME`というコメントや`TODO`コメントをみかけると、誰かの遺言なのだろうな…と思うようになりました。そしてそのコードは大抵の場合、そのままにされることを私はよく知っています…

# クソコードを嘲笑う時、コードもまたこちらを嘲笑っているのだ…
クソハイテンションなコード話で書き始めたのになんかしんみりしてしまいました。ほとんどコードの話じゃなくてお前の思い出話じゃねぇか、と自分で反省しています。
おかしいな、こんなはずでは……？

とはいえ、長年溜め込んでいたネタと残念なコードの話を供養できてなんだかスッキリしました。

いろいろな失敗ばかりしてきましたが、幸いだったのはこれらのコードはクソコードながらもリリースを迎えたり、リリースを迎える前に然るべき対応で駆除されつつ、大きな事件、事故などには発展しなかったということです。
苦い思い出は教訓となって、次なる世代に「こういうのは気をつけようね…」と語れるネタになります。

# 君　も　ク　ソ　コ　ー　ド　を　お　焚　き　上　げ　し　な　い　か！？
[クソコードお焚き上げの会 Advent Calendar 2024](https://qiita.com/advent-calendar/2024/anti-code-fire)では自分がやってしまった。もしくは見かけてしまったクソコードのお焚き上げをひっそりと「その他」カテゴリの中でお待ちしています。

最後に敬愛するビタワン先生のこんなコマで締めくくりといたしましょう。


https://x.com/vitaone_/status/1780855456401105174?s=46&t=BSI_DL-At2XP98ByNvAqSvw

「プログラムは思ったとおりには動かない　書いたとおりに動くのだ」

上級編は出せる気がしませんが、また供養したいコードがでてきてしまったら記事にしたいと思います。
それでは！2日目以降の皆様の記事も楽しみに見ていただければと思います。