Apache + Perl の WebDAV 実装を Go に刷新した話 — 実装より難しかった「移行設計」

目次

長く運用されてきたシステムには、その期間を経て積み重ねられた価値があります。一方で、当時は合理的だった設計や実装が、時間の経過とともに新しい改善の足かせになることもあります。

私たちのプロダクトでも、ファイル機能を支える WebDAV サーバーがまさにそうした存在でした。既存の構成は Apache をベースに Perl モジュールで拡張したもので、長年運用されてきた実績があります。しかし、今後のストレージ構成の見直しや継続的な改善を考えると、変更や保守のしやすさの面で課題が見え始めていました。

そこで今回、WebDAV の実装を Go ベースへ刷新する取り組みを進めました。

このプロジェクトで目指したのは、単に使う言語を Perl から Go に置き換えることではありません。ファイルの読み書きという WebDAV のコア部分を自分たちで制御しやすい形へ寄せ、今後の改善を進めるための土台を整えることが目的でした。ただ、実装そのものより難しかったのは、無理なく安全に、そして関係者と認識を揃えながらどう進めるかを設計することでした。

今回は、その過程で直面した課題と判断を整理します。

背景:既存実装が抱えていた課題

変更前の WebDAV サーバーは、Apache と Perl を組み合わせた構成でした。これは長い運用の中で積み上がってきた構成で、当時としては合理的な選択でした。ただ、実際に新しい要件や将来の改善を見据えて触ろうとすると、いくつかの難しさがありました。

特に課題だったのは、保守性と変更容易性です。長年運用されてきたコードは、ひとつの機能だけを説明するサンプルコードのように単純ではありません。現実のプロダクトコードとして必要な事情を抱え込みながら少しずつ責務が重なり、見通しが悪くなっていきます。

既存実装でも、WebDAV としての振る舞い、アプリケーション固有のドメインロジック、ストレージ操作、トランザクション境界などが密に結びついている部分がありました。たとえば、ファイルを読み書きする処理ひとつを見ても、単にストレージへアクセスするだけではなく、権限確認、メタデータの扱い、既存クライアントとの互換性、エラー時の振る舞いなど、複数の関心事が絡み合います。

既存実装で絡み合っていた関心事

既存実装で絡み合っていた関心事

こうした保守性の課題に加え、この取り組みは単なる内部整理ではなく、今後のストレージコスト最適化につながる土台づくりという意味も持っていました。既存の Apache + Perl 構成のままでは、ストレージ層の変更や実装の拡張を進めるたびに、長年積み重なった構造と向き合う必要があります。だからこそ、「今動けばよい」ではなく、「次に改善しやすい形になっているか」を重視する必要がありました。

単純移植にしない:互換性と構造整理の線引き

実装面で特に意識したのは、既存コードをそのまま移し替えないことでした。

背景で触れたような状態のまま単純移植をしてしまうと、表面的には Go に書き換わっても、実質的には現在の複雑さをそのまま新しい実装に移すだけになります。だからこそ今回の移植では、「何を互換性として守るべきか」と「何を構造として整理し直すべきか」を分けて考える必要がありました。

WebDAV サーバーでは、読み取り系と更新系で求められる性質が異なります。読み取り系であれば性能や既存クライアントとの互換性、更新系であればデータの整合性や失敗時の扱いが重要です。そうした違いを意識せず一枚岩のまま移植すると、テストも変更もしづらくなります。

そこで、密結合になっていた部分を少しずつ分離し、責務の境界を整理しながら移植しました。ドメインロジックを固有のパッケージとして切り出し、トランザクション境界やストレージ操作もアプリケーションの意図が読み取りやすくなるように整理しました。

ただし、理想的な再設計を目指しすぎるとスコープが広がり、プロジェクトが前に進みません。「どこまでなら今やるべきか」、「どこから先は今後の改善として残すべきか」を見極めながら、現実的な落としどころを探りました。このあたりの事情は「Perlコードベースの再設計:Go言語によるモダン化へのアプローチ」に記録として残しています。

リリース方式と判断基準の事前設計

今回のプロジェクトでは、リリース方式や判断基準をどう設計するかが、実装と同じくらい重要なテーマでした。

大きな変更ほど、完成した実装を最後にまとめてリリースする、というやり方は取りづらくなります。本番環境への反映が近づくほど重要になるのは、リリース前後に何を確認し、どの条件で継続や停止を判断し、異常があればどう検知するかを先に設計しておくことです。コードそのものの品質はもちろん重要ですが、それだけで安全性は担保されません。切り替えの順序、観測のしやすさ、手順の再現性、関係者の認識合わせといった、周辺の設計も同じくらい重要です。

移行の時系列

移行の時系列

今回の移行では、リクエストの性質に応じて切り替え方を分ける方針を取りました。読み取り系の処理は段階的に切り替えて挙動や性能を確認しやすくし、更新系の処理は整合性を重視して慎重に切り替えるようにしました。すべてを同じ方法で移行するのではなく、それぞれの処理が持つリスクに合わせてリリース方式を変えたことがポイントです。

この判断は、実装だけを見ていても出てきません。WebDAV のメソッドごとの性質、既存クライアントへの影響、問題が起きたときの切り分けやすさ、リリース時に関係者が判断しやすいかどうかを合わせて考える必要がありました。ここで必要だったのは、技術的に可能かどうかだけでなく、運用として成立するかどうかを見ることでした。

こうしたリリース方式と判断基準の設計は地味ですが、本番作業時の判断コストとリスクを下げます。準備が不十分なまま本番に変更を適用することは、技術的な自信があっても避けるべきです。

手順をレビュー可能なものにする

もうひとつ重要だったのが、作業手順の整備です。

ここで重視したのは、判断そのものよりも、同じ品質で作業を進められる状態を作ることです。つまり、実行の再現性の確保です。

大きな変更ほど、「詳しい人がその場で判断しながら進める」やり方には限界があります。その場では成立しても、再現性が低く、レビューもしづらくなります。特に、環境ごとの差分やリリース順序を含む作業では、手順の抜け漏れがそのままリスクになります。

今回のプロジェクトではリリース手順をできるだけ標準化し、ソースコードと同様に Git でレビューできる形に整えました。手順を文書として書くだけでなく、環境ごとの差分を機械的に反映できるようにし、人が毎回手で書き換える範囲を減らしました。結果として、再現性・レビュー可能性・手順の信頼性をあわせて高めやすくなりました。

リリース手順の標準化

リリース手順の標準化

手順書は、単に作業者のためのメモではありません。リリースの進め方を関係者に共有し、問題が起きたときに同じ前提で判断するための道具でもあります。どの順番で進めるのか、どこで確認するのか、どこまで進んだら次に進めるのかが文書化されていると、作業そのものが透明になります。

この透明性は、新構成へのリプレイス作業では特に重要です。システムの歴史が長いほど、暗黙知も増えます。暗黙知が多い状態で大きな変更を進めると、特定の人に判断が集中しやすくなります。手順をレビュー可能な形にすることは、特定の人への依存を減らす取り組みでもあります。

ADR で判断の前提を揃える

手順書が実行の再現性を支えるとすれば、判断の再現性を支えるのが ADR(Architecture Decision Record)です。何をしたかだけでなく、「なぜその方針にしたのか」を共有できる状態にする必要がありました。

新しい Go ベースの WebDAV サーバーを既存基盤の上でどう動かすか。どのようなリリース方式にするか。どのリスクを許容し、どのリスクを避けるか。こうした判断は、実装担当者だけで完結するものではありません。ソフトウェアエンジニア、SRE、エンジニアリングマネージャー(EM)、プロダクトマネージャー(PdM)、サポートチームなど、それぞれ異なる観点を持つ関係者と認識を合わせる必要があります。

そこで、重要な技術判断については ADR の形で明文化しました。なぜその方針を取るのか、検討した選択肢は何か、採用しなかった案にはどんな懸念があったのか、最終的に何を優先したのか。これらを書き出すことで、議論の土台を作りました。

判断の前提を ADR に集約する

判断の前提を ADR に集約する

ADR の利点は、結論だけでなく、判断の文脈を残せることです。時間が経つと、なぜその構成にしたのか、なぜ別案を採らなかったのかは忘れられがちです。後続の改善で同じ論点に出会ったとき、過去の判断が文書として残っていれば、そこから議論を再開できます。

また、文書があることで、議論は個人の感覚論から離れやすくなります。「なんとなく不安」、「たぶん大丈夫」ではなく、何が不確実なのか、何を根拠に進めるのかを言葉にできます。これは、関係者と認識を揃えながら進めるうえで非常に重要でした。

開発・運用・リリースを分断しない

今回のプロジェクトでは、アプリケーションの実装だけでなく、デプロイ先を含むインフラの構築、リリース方式の設計、関係者との調整も重要でした。これらが別々に進むと、どこかで前提のずれが起きやすくなります。

たとえば、アプリケーションの事情だけを見て設計したことが、運用の観点では扱いづらいことがあります。反対に、運用上は単純に見える方式でも、アプリケーションの振る舞いを考えるとリスクが高いこともあります。WebDAV のようにファイル操作を扱う機能では、そうしたずれがサービス影響につながりやすくなります。

そのため今回は、実装、インフラ、監視、手順、リリース判断をできるだけ分断せずに考えました。Go のコードを書くときにも、リリース時に何を確認すれば次へ進めるかを意識し、自動計装や継続的プロファイリングも取り入れながら、切り替え後の挙動や性能劣化、ボトルネックを追いやすい状態を整えました。インフラ構成を考えるときにも、アプリケーションの振る舞いや移行手順との整合を意識しました。

実装からリリース判断までを分断しない

実装からリリース判断までを分断しない

たとえば、段階的に切り替える処理では、実装側でリクエストの種類や処理結果を追えること、運用側で確認すべきログやメトリクスが決まっていること、手順側で次へ進む条件が明文化されていることが必要になります。どれかひとつだけ整っていても、リリース判断としては不十分です。

リリース直前の不具合と、構造的なリカバリ

このプロジェクトは特定のタイミングでのリリースを目標に進めており、チーム全体がそのスケジュールを意識しながら開発を進めていました。

しかし、リリース直前の段階で、複数のクリティカルな不具合が顕在化しました。Apache と Go の振る舞いの差異や、周辺システムとの結合部分における問題など、単体では見えていなかった課題でした。

代表的だったのは、既存実装ではユーザーから見えない前提だった内部管理用の領域が、新実装では通常のリソースとして扱われ、クライアントから参照できる状態になっていたことです。これは、WebDAV のメソッド単体の実装が正しいかどうかだけでは見つけにくい問題でした。既存実装の中には、アプリケーションコードとして明示されている処理だけでなく、暗黙的に守られていた振る舞いがありました。新実装へ移す際には、その暗黙の前提も含めて再現する必要がありました。

見えていなかった暗黙の仕組み

見えていなかった暗黙の仕組み

この問題をきっかけに、内部管理用の領域がユーザー操作の対象にならないことを、検証の観点として明示的に追加しました。互換性確認とは「同じ操作が同じ結果になること」だけではなく、「既存実装では見えなかったものが、新実装でも見えないこと」まで含めて確認する必要があると分かりました。

こうした問題の背景のひとつとして、結合テストのプロセスがリリース直前まで後ろ倒しになっていたことがありました。移植作業を進めていた段階では統合された開発環境がまだ整っておらず、検証の多くをローカル環境で行っていました。既存サービスとの境界面での振る舞いは、実際に結合してみるまで見えにくい部分が多く、問題の発見が遅れた一因になりました。開発環境を早期に整備し、小さい単位で段階的に結合・検証できていれば、問題をもっと早い段階で発見できた可能性はあります。修正・検証・未完了タスクが重なり、スケジュールは急速に逼迫しました。

リカバリにあたっては、関係者と協議のうえ、週単位でフェーズを区切り、各フェーズで完了させるべき内容を明確にしました。そしてリリースの Go/No-Go 判定基準として「過去1週間以内に開発環境でクリティカルな不具合が見つかっていないこと」という具体的な条件を定めました。この基準があることで、「次の週に進む判断」も「もう一週スライドする判断」も、共通の事実に基づいて行えるようになりました。

Go/No-Go 判定のチェックリスト

Go/No-Go 判定のチェックリスト

振り返ると、今回の遅延の根本には、統合された開発環境の整備や段階的な結合検証の仕組みづくりが、小規模なチームでの開発の進行に対して間に合っていなかったという構造的な課題もありました。延期にあたっては、EM や PdM がリスクと事業影響を評価したうえでステークホルダーとの合意形成を主導し、プロジェクト全体として品質を優先する判断を下しました。次に同様の移行を進める際には、もっと早い段階で環境と結合検証の仕組みを整えることが必要です。

横断的な視点が、移行の安全性を支えた

新しい構成を既存基盤の上でどう成立させるかを考えるには、インフラや運用に詳しい人たちの知見が不可欠です。また、リリース判断やステークホルダーとの合意形成を進めるうえでは、EM や PdM を含む関係者の視点も欠かせません。実装として「作れる」ことと、プロジェクトとして「進められる」ことの間には、思っている以上に距離があります。

手順書や運用上の観測ポイントを整える過程でも、異なる立場からの視点が精度を上げる場面が繰り返しありました。たとえば、自分たちでは十分だと思っていた確認項目でも、運用する人の視点では切り分けに使いづらいことがあります。また、ステークホルダーとの合意形成を意識することで、リリース時に誰へ何を共有すべきかが明確になります。

この取り組みは「チームが頑張って移植した話」というより、技術的な課題を分解し、文書化し、複数の専門領域の知見を組み合わせながら前に進めた話でした。それぞれの役割から持ち寄られた視点が重なることで、はじめて安全な移行が成立します。

おわりに

長く使われた構成を置き換える場面では、技術的な正しさだけでは足りません。それをどう運用に乗せ、どう安全に切り替え、どう関係者と共有するかまで含めて設計する必要があります。今回の WebDAV 刷新を通じて、そのことを改めて整理できました。

このプロジェクトでチームが価値を出した部分は、個々の実装だけではなく、複雑な制約を整理して実行可能な移行方針に落とし込んだことです。曖昧な論点を分解し、判断できる形にし、手順や文書として残しながら前に進める。そこに今回のプロジェクトが技術的な難しさと向き合えた理由があります。

既存構成を刷新する価値は、過去の仕組みを新しいものへ置き換えることだけではありません。継続的に改善しやすい構造を整え、その進め方を組織の知見として残していくことにもあります。こうした取り組みは、今後の改善を進めるための基盤として位置づけられます。

「エンジニアリング」の関連記事

ブログ一覧へ