🌟

モノリシックなシステムの保守開発のツラミと面白さ

2024/12/10に公開

この記事は「レバテック開発部 Advent Calendar 2024」の 10 日目の記事です!
昨日は タカハシ さんが担当していました!

こんにちは。レバテック開発部のきょうかです。
レバテックの社内業務用システムの保守開発を担当しています。
本記事では、これまでの保守開発の中で遭遇したツラミ(課題)とツラミ解消の取り組み、ツラミから感じた 面白さについて書いていきます。

どんなシステム?

私が担当しているシステムは、営業、マーケティング、管理、経理など、さまざまな部署が使用する社内向けの業務システムです。
レバテックでは複数の事業を展開していますが、それらで使用するデータを一元管理している重要なシステムでもあります。

このシステムは社外には公開されませんが、レバテックの業務を支える要となる存在です!

どんなツラミがあった?

これまでの開発で特に印象的だったツラミをご紹介します。

小さな修正が意図しない影響を引き起こす

「契約詳細ページ」に表示する項目をひとつ増やしてほしいという要望がありました。
画面に項目追加するだけの簡単なお仕事です( ◠‿◠ )
ただその対応をした直後に、「契約一覧ページ」の表示ができなくなるという事象が起きてしまいました😢

原因は、「契約詳細ページ」と「契約一覧ページ」で共通して使用されていたクラスに修正を加えたためでした。
以下のコードで修正箇所を説明します。

class HogeContractDomain extends BaseContractDomain
{
    protected $model; // これは元々あったプロパティ
    protected $id;
    protected $hogehoge_number;
    // 以降その他プロパティ

    public function __construct(array $attributes = [])
    {
        parent::__construct($attributes);
        // ↓今回追記箇所 $modelプロパティを使用している
        $this->hogehoge_number = $this->model->getHogehogeNumber();
    }
}

以下はHogeContractDomainのインタンス生成している箇所のみ抜粋したものです。

// 契約詳細ページ用のインスタンス生成時
new HogeContractDomain(array_merge(
    $hoge_contract->toArray(),
    ['model' => $hoge_contract]
));

// 契約一覧ページ用のインスタンス生成時
new HogeContractDomain($hoge_contract->toArray());

「契約詳細ページ」では$modelを渡してインスタンスを生成していますが、「契約一覧ページ」では渡していません。
そのため、$modelを使用する処理を追加した結果、「契約一覧ページ」でエラーが発生しました。

契約詳細ページと契約一覧ページでは表示している項目が違うので、本来は共通のクラスを使用する必要はありません。
異なる用途のページのコードを共通化していることで、意図しない箇所にも影響を出してしまいました😞

上記はほんの一例です。上記に限らず、ちょっとした修正が修正したいところとは関係ないところにまで影響してしまう、ということが多々ありました。

※コードは説明のために簡潔に表現しています。
※そもそものコードにツッコミどころ満載ですが、論点がズレるので今は触れません。

何をするにも形態判定メソッドを挟まないといけない

現状のレバテックのシステムでは、事業によって複数の形態が存在する「人材情報」を共通のデータとして管理しています。
そのため追加仕様を特定の形態にのみ適用したい場合は、都度「A形態の人材か?」「B形態の人材か?」の判定処理をはさむ必要があります。

例として「人材情報が編集可能かどうか」を判定するメソッドを見てみましょう。

public function isEditable(): bool
{
    // A形態の人材の場合
    if ($this->engineer_type->isA()) {
        return $this->isEnabled();
    } else {
    // B形態の人材の場合、複数の判定ロジックがある
        return ($this->isEnabled() && $engineer_type->type_b_property !== null);
    }
}

このようなif文が頻出し、コードが煩雑化しています。
また、判定処理を忘れると「A形態の人材はtype_b_propertyというデータは持っていないよ🥺」といったようなエラーになってしまいます。

ちょっと項目追加しようにも、テーブルが巨大すぎて手出しできない

当システムにはさまざまなテーブルに紐づく「活動」というテーブルがあります。
テーブル名の抽象度の高さで察するかもしれませんが、さまざまな用途で使用されているテーブルです。
その登録画面からみてもわかるようにフリーテキスト項目が多いため、いわゆる「なんでも登録できちゃう便利テーブル」です😇

気づけば当システムで最も多いレコード数を誇るテーブルになっていました。
重要なデータも含むものもあればメモ程度の内容のものもあり、適切な状態に改修しようにもなかなか手出しができない状態でした。

そんな「活動」に対して、「活動編集ページに項目をひとつ追加してほしい」という改修依頼がきました。
ユーザー視点で見るととても簡単な依頼だったのですが、該当テーブルを直接変更するわけにはいかないのでテーブルの正規化から始めることに。
結果、1週間もあれば完了するであろうタスクに1ヶ月ほどかかりました。。。

その他

他にも以下のようなツラミもありますがあげ出したらキリがないので今回は割愛します。

  • クエリが重すぎてページが開かない
  • 連携システムが多すぎるため問題が起きるとさまざまなシステムを巻き込んでしまう
  • 他リソースからデータ更新されるトリガーが多い
  • ネストが深すぎて処理が追えない

ツラミ解消に向けた取り組み

関心の分離を意識したコード

「人材情報」をA形態、B形態どちらでも同じものとして扱ったり、異なる画面の表示に同じクラスを使ったりと、関心を分離できていないコードが散見されます。
異なる関心ごとが共通化されたコードに修正が入った場合は、別物として切り離して実装するようにしています。

下記記事に詳細が記載あります🙆‍♀️
https://zenn.dev/kkyoka/articles/02d96c9723a527

領域ごとのユニット化

元々当システムは1つのチームで運用していたのですが、今は4つのユニットに分かれて運用しています。
それぞれが担当する領域を狭めることで、その領域のドメイン知識が蓄積され開発スピードが速くなります。
それだけでなく、より関心の分離が意識しやすくなります。(各領域の改修は各領域に閉じるように改修するようになる)

下記資料にグループリーダーが領域ごとにユニットを分けたときの話があります🙆‍♀️
https://speakerdeck.com/leveragestech/mou-du-shi-ye-wozhi-erusisutemuni

モデリングの強化

当システムには、必要になった項目をひとつのテーブルにどんどん追加していった結果超巨大化したテーブル(カラム数200越え)や、さまざまなテーブルとの関連を持つ汎用すぎるテーブル(関連テーブル数6つ)など、困ったテーブルたちがたくさんあります。

それらを一度に綺麗にすることは難しいですが、改修があった場合は都度データモデリングをすることが増えてきています。
ひとつのカラム追加をすれば簡単に終わる改修でも、モデリングのフェーズを挟んで適切なテーブル状態に正規化しています。
改修に時間はかかりますが、長い目で見ると工数削減につながっているはずです...!

下記記事に詳細が記載あります🙆‍♀️
https://zenn.dev/levtech/articles/dcba1d7b68ebdb
https://zenn.dev/kkyoka/articles/8b9657b27c8005

面白さとは?

私は今のチームに参画する前は、「既存システムの保守開発って面白いの〜?(´・ω・`)」と思っていました。(当時周りにいた方が「保守開発はつまらんよ😅」派の人だったからそれに影響されてた)
また上記を読むと「なんか辛そうだな」と思うかもしれません。

ただ実際やってみて、
「システムの保守開発、意外と面白いっっ」
となりました。

ツラミを経験するたびに「どうすればこのツラミを回避できるのか🤔?」「どうすれば今後起きないようにできるのか🤔?」を考える必要があります。
課題を解決しながらシステムを改善していく過程には、新規開発とは違う面白さがあります。
改善策を考えること自体が刺激的であり、成長のきっかけとなっています。

ツラミの経験の何が良い?

あるべき姿を考える上でいろんな書籍や記事を読むわけですが、ツラミを実際に経験していると共感できることが多いので内容がスッと入ってきやすいと感じています。
経験がないまま知識を入れるだけだと、なんか理解した気になっているだけで2割くらいしか頭に入っていないのでは?と思います。(経験主義)

また「もう同じツラミを経験をしたくない」という気持ちが、より良い改善案を考えるモチベーションにつながっています。

ツラミを乗り越えるには何が必要?

  1. 既存の実装を悪く言わない
    ツラミに遭遇にした時に「既存のコードが悪いから...😩実装したの誰?😩」と言うのはやめましょう(気持ちは分かる)
    開発当初の実装が最適な状態でないと感じるのは、当初とシステムのあるべき姿が変化しているからとも言えます。
    事業成長や業界の変容などで、システムに求められるものや開発にさけるリソース状態が変わっていきます。
    既存のものを悪く言うのではなくて、今の状態に合った適切な改修に集中できると良いなと思います🧑‍💻

  2. 改善していく文化の醸成
    改善していく文化があるかどうかも大切です。
    私のチームは以下が揃っているので良い文化が浸透してきているのではないかと思います。

    • テックリードの方がどんどん改善に向けて動いてくれている
      • 既存の状態を理解した上で改善に向けて動いてくれる&サポートしてくれる
    • 業務委託のつよつよエンジニアの方がガンガン提案してくれている
    • チーム内メンバーの柔軟性が高い(ここ大事!)

最後に

ここまで読んでいただきありがとうございます。
本記事でモノリシックなシステムの保守開発の面白さが伝われば幸いです!
面白さは人それぞれなので異論は認めます。

明日は azm さんが投稿します~
レバテック開発部 Advent Calendar 2024」をぜひご購読ください!

参考

レバテック開発部

Discussion