1 of 44

ソフトウェアエンジニアリングサバイバルガイド:

廃墟を直す、廃墟を出る、廃墟を壊す

あるいは

廃墟に暮らす、廃墟に死す

�YAPC::Kyoto 2023

Mar 19, 2023

@moznion

2 of 44

@moznion

ソフトウェアエンジニア

From Seattle, WA

好きなPerlの�組み込み関数:

do, kill, die

3 of 44

免責

本トークの内容は実在する企業・組織とは関係ありません。

4 of 44

本トークにおける「廃墟」とは何か

  • 前提: ソフトウェアエンジニアリングの文脈
  • 廃墟とは: 動いているけれどメンテできない・されていない、�あるいはなぜ動いているかわからないもの
  • これはソフトウェアの「実装」に限定されない
    • API
    • 設計思想・アーキテクチャ
    • などなど、システムのすべてに存在しうる

5 of 44

本トークにおける「廃墟」とは何か

  • 「ソフトウェアは壊れない」という神話に対する反駁
    • 「ソフトウェアは現実世界の製品と違って自然劣化しない」ということに拠る
    • しかしソフトウェアは壊れる / ソフトウェアは壊れている
    • ソフトウェアに対する改善・拡張の要求は継続する
      • この要求に応えられなくなった時からソフトウェアの破損・劣化は進む
      • => 廃墟

6 of 44

「技術的負債」の誤用・誤謬

7 of 44

廃墟の何が問題か

  • 誰もメンテできない
    • 突然止まったらどうする?
    • 奇跡的にリカバリできたとして次に発生したら?
    • 運用でカバー™?�
  • 新機能を安全に入れられない
    • 仕方がなくアドホックに変更が入れられる
      • いびつな違法建築に
      • 一般的に破損チャンスが増える�
  • 廃墟は伝搬する

8 of 44

「枯れ」と「廃墟」は違う

  • 枯れているコンポーネントはメンテナンスはされている
    • 依存ライブラリが継続的に整備されているとか
    • 機能追加や不具合修正が安全とか
    • デプロイが自動化されているとか
    • => 単に新規の機能追加の要望が無いだけ、と見做せる�
  • 廃墟はメンテナンスされていない
    • すべてが危険である
      • 新機能追加
      • 不具合修正
      • デプロイ
      • 構成変更
    • 何が起こるかわからない!

9 of 44

「枯れ」と「廃墟」は違う

  • どちらも長期間「安定走行」しているように見える場合もある
    • 大爆発するまでわからない、というケース
      • 大体障害発生時に明らかになるというのは皮肉な話
    • このへん、平常時にどう見極めるか
      • 定期的な棚卸?
      • 判断を自動化できないかどうか
        • Last Commited Dateとかだけだと判断しにくい

10 of 44

廃墟を直す

11 of 44

廃墟を直す

  • おそらく一番理想的である
    • 一方、状況によっては最適であるとは限らない
      • コストとのトレードオフ
  • しかしおそらく一番難しい
    • 廃墟になっている時点で詳しい人がいなくなっている�
  • どうするか
    • 歯を食いしばってやるしかない

12 of 44

廃墟をどう直すか

  • 人を当てる
    • 本質的にこれが最も重要
      • 当然、人がいなければ何もできない
    • 最低でも1人、できれば複数人
    • チームでやらないとまた廃墟に逆戻りする可能性が高まる
      • 個人技の限界
      • ⇔ 個人技による圧倒

13 of 44

廃墟をどう直すか

  • CIとデリバリパイプラインの整備
    • CIが無いと変更による破損を検出できない
      • 誰もテストを書かなくなる
    • いつでも誰でもデプロイできる仕組みを整えるのが先決
      • これが鈍重だったり、手オペに依存していると誰もデプロイしなくなる
    • このへんが整うとおぼろげでも廃墟の間取りがわかってくるはず�
  • 開発環境の整備
    • 廃墟ではこのへんが口伝になっていることが多く、誰も手を付けたがらない
    • CI/デリバリパイプラインの整備によってこのへんも同時に整うことが多い
    • 今だと一式コンテナに押し込むとかが良い?
      • 誰でも参加できるようになる
      • ローカルでもクラウドでも開発できるようにできる

14 of 44

廃墟をどう直すか

  • テストで固める
    • 廃墟であってもユニットテストくらいはあってほしい、あってくれ
      • しかし現実は非情である
      • そもそも「テスト」という概念が無いことすらある
    • すべてのレイヤーで網羅的なテストが存在しているのが理想だが......
      • 無理であればシナリオ・ユースケースをベースとしたE2Eテストを�網羅的に書くことでガッチリと固めていくのがリーズナブル�
  • ステージング環境を作る
    • 廃墟を直す過程では不確定要素が多い
    • 本番と構成を同じくするステージング上でend-to-endテストを流す、�人力を介したQAプロセスを回す、といった営みは不可欠
    • これが無いと、本番環境に強く念じながらデプロイすることになる
      • 「壊れないでくれ、頼むッ......!!」

15 of 44

廃墟をどう直すか

  • 各種バージョンを上げていく
    • ランタイム・ライブラリ
    • このへんが古いままだと廃墟のまま
      • 脆弱性たっぷり
      • そもそも古いものを使い続けるのは今後の改善の足枷になる
        • rel: 木こりのジレンマ
    • 地道に上げていく
      • バージョンあげる、テスト流す、ステージングで様子見る、デプロイする
      • ^ というサイクルを回して上げまくっていく
      • 1度のサイクルで欲張ると失敗することが多いのでちまちまやると良い
        • 「このサイクルではJDKのバージョンと、Spring Bootのバージョンと、Elasticsearchクライアントのバージョンを上げています!!!!」
        • こわすぎる

16 of 44

廃墟をどう直すか

  • と、足回りを固めると普通のプロジェクトと同様のサイクルを回せる
    • もっとテストで固めた上でリファクタリングするとか
    • 新機能を足すとか
    • アプローチをがっつり変更するとか
      • ランタイムやライブラリのバージョンを上げることによって新機能がもたらされる
      • それによって不要なコードやポリフィルを除外できる

        • こういうのをなんとかできるようになる
      • 当時は存在しなかったテクノロジーを導入していくこともできる
        • JSプロジェクトにTSを部分的/全面的に入れていくとか
  • めでたし、めでたし

17 of 44

廃墟を出る

18 of 44

廃墟を出る

  • 作りなおす、あるいは別のコンポーネントに機能を移譲する�
  • これを選ぶべき場合もある
    • 再設計、という観点ではこれがリーズナブルであることが多い
    • リクルーティングの目的もある
      • 古い (あるいは不人気) 技術スタックのままだと人が来ず終わっていく

19 of 44

廃墟を出る

  • 事前条件: セカンドシステム症候群ではないかという疑いを持つ
  • セカンドシステム?
    • =>「畜生! 作りなおしじゃい!!!」
    • ref: 人月の神話 - 第5巻 セカンドシステム症候群
    • ご存知! だいたい失敗します!!
      • あんま欲を出さないのが肝要
      • あくまで「同じ機能」を有したものを「今後にわたって拡張可能」な形で作る
        • (それが難しいっつってんだろ)
    • 個人的にv2.0が成功する背景には「圧倒的な個人の技量」が存在すると思っている
      • その個人技に依存したv2.0もやがて廃墟になっていくことがままある......
        • 廃墟から引っ越した先がまた廃墟になってしまっては元の黙阿弥
        • (とはいえ廃墟をそのまま放置するくらいなら、次に期待してしまうのが人情�というもの!)

20 of 44

全部作り直すという時

  • 「外部からの入力に対する出力」を満たす形で作るべき
    • 古い実装をそのままなぞってコピっても意味が無い (ことが多い)
      • 言語・フレームワークを変更するとかだったら意味があるかも
    • 「インターフェース」と「実装」の関係性を拡大して考える
      • インターフェース: 外部に対する入出力
      • 実装: 実装
        • 裏側に存在するこの「実装」はどうなっていても良い
      • これらを満たすようにする
        • もちろんここを保証するテストが無いままやるのは単なる破壊活動である
    • 再設計して、理想的な実装にすげ変えてゆく良い機会

21 of 44

全部作り直すという時

  • チャレンジのチャンス
    • だが欲を出しすぎると......
      • たとえば突飛な...
        • 言語
        • フレームワーク
        • アーキテクチャ
    • 誰もメンテできなくなってまたしても廃墟に�
  • 本当に作り直すべきかどうかは熟考する必要がある
    • 失敗した時には思い出以外何も残らない
    • 他にやりかたはないのか?
    • 歯を食いしばって既存のシステムを直すべきではないのか?

22 of 44

別のコンポーネントに機能を移譲する

  • 廃墟は伝搬する
    • 侵食する廃墟
      • 「メンテされていなかった機能」を他のコンポーネントに持っていくことで、�そのコンポーネントにも廃墟が広がる可能性がある
    • 廃墟の移設・移築は逆効果である

23 of 44

別のコンポーネントに機能を移譲する

  • 何はなくともまず機能の境界を見極める
    • 不適切な機能を他のコンポーネントに丸投げしても廃墟が広がるだけ
    • 機能の適切な粒度、責務を負うべき適切なコンポーネントを適切に判断する
    • あるいは逆に機能を集約するというのもあり
      • 廃墟おまとめセット
        • そしてまとめた廃墟をまるっと直す、あるいは消滅させるとか...�
  • そして分割した機能を他のコンポーネントに移譲する
    • 既存コンポーネントに移植する、あるいは新規コンポーネントに切り出す
    • ここでごっそり直す、テストは必要�
  • 責務レベルで切り出していくと、その部分部分で見られる人が�増えて良くなる傾向にある
    • 故障点が増えるかも、という観点はある

24 of 44

廃墟を壊す

25 of 44

廃墟を壊す

  • 商売が許すのであればいっそシステムを消し飛ばすのも手
    • 例: メンテコストが利益を明確に上回っている�
  • 「やめましょう」
    • 一言欲しい、その勇気
    • 一方で感情でのみ判断してはいけない
    • 実績に基きましょう
      • 売上、顧客影響、などなど
        • お客様に影響を出すのは基本的に「ダサい」

26 of 44

廃墟を壊す

  • 再掲: 廃墟による汚染は伝搬する
    • 汚染の例
      • おかしなインターフェイス
        • 狂ったインターフェイスを提供している場合、そのクライアントもおかしくなる
        • クライアント側に理性が無いとその「おかしさ」はクライアントの内部の�ロジックにも入り込んでくる
      • 劣悪なパフォーマンス
        • 利用する側のパフォーマンスも当然ここに引きずられていく
      • ヤル気
        • だせえコンポーネントの面倒は見たくねえ!!!
        • ということでその周辺からどんどん面倒が見られなくなっていく
      • 過度な妥協 (「割れ窓」に近い) の連鎖�
  • なので叩き壊してなかったことにする、という選択

27 of 44

廃墟を壊す

  • 「別のコンポーネントに一部機能を移譲する」というのとの組合せで�実現することも多い
    • システムに必要不可欠な機能だけ別に移譲して、残りは壊す、とか
    • 逆に廃墟を集約して消し飛ばすとか�
  • サービスを畳むのもテクニックのうち
    • 影響度を測る
    • ちゃんと告知する
    • 例: Blackout testによる影響の周知と計測
    • そしてクローズ、その後のガレキの片付け
      • これを怠るとせっかくサービスを畳んだ意味が無い

28 of 44

廃墟に住む

29 of 44

廃墟に住む

  • 一番やってはいけない
  • 一方でやむをえず採用されがち
    • 事情はわかる
      • 人はいない
      • 金はない
      • しかしやることはある......
    • 近視眼的に見るとこれが一番安い
      • 後でそのツケがすごいことになる場合がある
  • そもそも「現状維持」なので特に何も考えてないとこうなる

30 of 44

廃墟住みノウハウ

  • 不愉快
    • 動かなくなるまで動かし続ける
      • 脆弱性ノーガード
      • とりあえず再起動
      • 運用でカバー™�
    • 違法増改築
      • アドホックに機能を足していく
      • テストが無ければ壊れていない戦法

31 of 44

廃墟住みノウハウ

  • 悪くない?
    • 合法増改築
      • 既存コードとは違う新しいコンセプトの世界をプロジェクト内に作る
        • 緩衝するレイヤを介して元々あるコードとコミュニケーションする
      • ここまでやっていると、実は廃墟を直すことができるかもしれない
        • 崩壊する速度が勝つか、直す速度が勝つかの勝負
      • とはいえ廃墟に建て増している状況には変わりはない
        • 耐えられるか? その重さに�
    • ライブラリだけは頑張って上げていく
      • 大本でメンテされていないライブラリには独自パッチを当てたり...
      • まあここまで成されているのであれば廃墟ではないという説

32 of 44

しかし廃墟は廃墟

  • 徐々に綻びは出てくる
  • そして周囲を蝕む (前述)
  • 時間が経過すればするほど直せるチャンスは狭まっていく
    • 違法改築されると複雑度が増し、変更の影響が読めなくなっていく
    • コンポーネントを見れる人は減っていく
      • 時代遅れのものを見られる人は減る一方。新しい人は来ない。
        • 古いものにちゃんと詳しい人はレア
      • キャリアパス
        • 10年前にはトレンドだったが、今まったく主流でない技術をやって未来があるか
          • あるかもしれない
          • でも普通はない
            • だから普通の人はやらない
            • おわりだ......

33 of 44

しかし廃墟は廃墟

  • しかしいずれどうにかする必要がある
    • 直す? 壊す?
      • いずれにせよコストがかかります�
  • あるいは: 「廃墟に死す」
    • つまり諦める、ずっと廃墟に住み続けるぞ、行けるところまで行くぞ!!!!!
      • サービスとのチキンレース
        • システムが倒壊するのが先か、サービスが終わるのが先か
        • ただ、普通はシステムが倒壊する前提でサービスを提供していることは無い
          • エンジニア以外には理解できないと思う
      • いずれにせよ廃墟に蟄居、その生涯を廃墟で終える
    • ただサービスをやっているということは、その対価をエンドユーザーから得ている、�ということを忘れてはならない
    • エンジニアリングの観点では承服できない状況だとは思う

34 of 44

廃墟を作らない

35 of 44

そもそもなぜ廃墟が発生するのか

  • 人がいない
    • なぜ
      • カネがない
        • 人を呼べない
          • 単価
          • head count
        • 基本的に、すべてはこれに集約される
        • 嗚呼、無限にカネさえあれば......
      • 技術がオールドスクールすぎてダサい
        • 古い技術スタックではやはり人を呼びにくい
          • ⇔ 新しいものが必ずしも良い、というわけではない
        • 今後のキャリアに響く
      • 本質的に複雑なものを見たくない

36 of 44

廃墟の対応にはコストがかかる

  • 「貧乏、腹立つ、廃墟に住む!」
    • はい
    • ただ問題が起きてにっちもさっちも行かなくなった時にツケを払う必要が出てくる
      • ここが見えないコストになっていませんか?
    • 「嗚呼、最初からちゃんとしておくんだったよ〜、とほほ......」

37 of 44

廃墟を作らないために

  • 「廃墟」ではなく「枯れ」を目指す
    • 運用の自動化
      • 誰でもアーティファクトを作れて、デプロイできる仕組み
      • RenoveteやDependabot等による依存の自動更新
        • セキュリティパッチの適用
      • 自律的に状態が復元する、というような弾性のあるシステム
    • ドキュメント
      • コードがドキュメント、というクオリティを目指すべきではあるが
        • コードがドキュメント、はドキュメントが書かれない時の言い訳である�場合が多い
      • 複雑な仕組みを紐解く時、やはり自然言語で書かれた説明があり、その前提を�知っている状態でコードなりなんなりを読むというのが楽
        • 例: ドキュメントが無いオープンソースプロジェクトで成功しているものは稀
      • あとはなんかマズいことが起きた時のためのrunbookなどがあると良い

38 of 44

廃墟を作らないために

  • チームでやる
    • 個人技には限界がある
      • 個人が去ってもサービスは続く
    • ひとりだとモチベーションの維持が難しい
      • それだけを専業でずっと見続ける、とかであればマシかもしれない
      • が、兼業で別のサービスも見ている、というような状況だと優先度付けが�難しくなり、時間が経つにつれ放置されていく傾向にある
    • ひとりだと油断・悪い妥協が生じる
      • 「まあ `main` に直pushしても良いか......」
      • 「まあテスト無いけど動くから良いか......」
    • これらをカバーするためにチームでやるというのは必要
  • + やるという気持ち
    • 結局はこれ

39 of 44

廃墟に対するリスペクト

  • 利益を生んでいる・生んでいたというのは事実
  • そのサービスを蔑ろにしてはならない
    • 蔑ろにすると廃墟を無視しはじめる
    • 無視された廃墟は朽ちるのみ

40 of 44

廃墟に困ったら: 考古学

  • 技術
    • その時期の技術トレンドから掘っていく
    • コードを読みまくる
    • Wikiを読みまくる
    • チャットを検索しまくる
    • とにかく訊く
      • 組織内にわかる人がいるとラッキー
        • (いないから廃墟になっているのでは......?)
      • 組織内に知ってる人がだれもいなければ一般化して詳しい人に訊くしかない
        • とはいえそれが脆弱性に繋る内容だったりするとアレだし難しいですね

41 of 44

廃墟に困ったら: 考古学

  • ビジネスロジック
    • とにかくユースケースから掘りまくる
      • なにがどう作用して機能を実現しているかを1つ1つ理解していく
    • コードを読みまくる
    • Wikiを読みまくる
    • チャットを検索しまくる
  • 結局自律的に調べていかなければ解決しない

42 of 44

廃墟に困ったら

  • 現代の技術によってアーマーされているというハッピー
    • 今の技術のほうが昔の技術より優れているはずである (そうであってくれ)
    • その優れた技術で武装して古い技術に立ち向かっていく
      • 完全な置き換えを狙うのではなく、融和させるというのは1つの手
        • 型が無いところにpluggableな型によるサポートを入れていくとか。

43 of 44

頑張って廃墟と向き合っていきましょう

  • そして人類は「廃墟」を超える存在である「遺跡」に出会うのであるが......
    • これはまた別のお話

44 of 44

Q?