UX / UI のデザインに強いWebシステムの開発と、BtoB Webマーケを支援するWeb制作を提供するN’s Creates (エヌズクリエイツ) 株式会社の西山です。
ソフトウェア工学の世界には、「大きな泥団子 (Big Ball of Mud)」と呼ばれる有名なアンチパターン(悪しき設計)が存在します。
これは、明確なアーキテクチャや規律を持たず、場当たり的な修正と機能追加を繰り返した結果、内部構造が崩壊してしまったシステムを指す言葉です。残念ながら、これは机上の空論ではなく、多くの現実のプロジェクトが直面している問題でもあります。
この記事では、なぜこの「泥団子」が生まれてしまうのか、そしてPHPのコード例を元に、この状態を回避するための具体的な設計原則を紹介します。
「大きな泥団子」とは何か?
「大きな泥団子」とは、アーキテクチャ(設計構造)が崩壊し、無秩序で複雑怪奇になってしまったシステムを指します。
名前の通り、泥の塊(かたまり)のどこを掴んでも全体が崩れてくるように、コンポーネント間の境界が曖昧で、すべてが密結合している状態です。変更が非常に困難で、バグの温床となります。
なぜ「泥団子」は生まれるのか?
最初から泥団子を作ろうとするエンジニアはいません。多くは、日々の開発の中で徐々に形成されていきます。
- 納期の圧力: 「設計は後回し!とにかく動けばいい」という判断の積み重ね。
- 「一時的な」修正: 本来の設計を無視した「とりあえず」の修正が、いつしか恒久的なコードになる。
- 継ぎ足し開発: リファクタリング(整理)を行わず、既存のコードに新しい機能をコピペして継ぎ足していく。
- 経験不足: 開発者がSOLID原則や設計パターンを知らず、最も簡単な方法(一つのファイルに全部書くなど)で実装してしまう。
PHPコードで見る「泥団子」の兆候
あなたのプロジェクトに、こんなコードはありませんか?
兆候1:神クラス (God Class)
一つのクラスが何でもやりすぎる状態です。「単一責任の原則」に真っ向から違反しています。
悪い例 (God Class)
UserController が、ユーザー登録、プロフィール更新、なぜか決済処理まで担当しています。
class UserController {
public function register($email, $password) {
// ユーザー登録処理…
}public function updateProfile($userId, $data) {
// プロフィール更新処理…
}// なぜここに決済処理が?
public function chargeCreditCard($userId, $amount) {
// Stripe APIを叩く処理…
// 領収書PDFを生成する処理…
// 決済完了メールを送る処理…
}
}
改善例 (関心の分離)
決済処理を BillingService という別のクラスに切り出し、UserController はそれを呼び出すだけにします。
class UserController {
// 依存性の注入(DI)
public function __construct(private BillingService $billing) {}public function updateProfile($userId, $data) {
// プロフィール更新処理…
}// 決済はBillingServiceに任せる
public function charge($userId, $amount) {
$this->billing->charge($userId, $amount);
}
}class BillingService {
public function charge($userId, $amount) {
// Stripe APIを叩く処理…
// 領収書PDFを生成する処理…
// 決済完了メールを送る処理…
}
}
兆候2:スパゲッティコード (Spaghetti Code)
処理があちこちに飛び、ロジックが追いづらい状態です。LaravelやSymfony登場前の古いPHPによく見られました。
悪い例 (1ファイルに全てを記述)
index.php が、ルーティング、DB接続、ビジネスロジック、HTML描画の全てを担当しています。
// index.php
session_start();
$db = mysqli_connect(“localhost”, “user”, “pass”, “db”);if (isset($_GET[‘action’]) && $_GET[‘action’] == ‘save_post’) {
// データ保存処理
$title = $_POST[‘title’];
mysqli_query($db, “INSERT INTO posts (title) VALUES (‘$title’)”);
header(“Location: index.php”);
exit;
}// データ表示処理
$result = mysqli_query($db, “SELECT * FROM posts”);// — HTML —
<html>
<body>
<h1>ブログ記事</h1>
<form action=”index.php?action=save_post” method=”POST”>
<input type=”text” name=”title”>
<button type=”submit”>保存</button>
</form>
<ul>
( … ここでPHPのwhileループが始まる … )
</ul>
</body>
</html>
→ これを修正しようとすると、MVCフレームワーク(Laravelなど)を導入する話になり、それは「リファクタリング」ではなく「リライト(再構築)」に近くなります。
兆候3:グローバル変数の汚染
どこからでもアクセスできるグローバル変数や $_SESSION に何でも詰め込み、処理の流れを不透明にします。
悪い例 (グローバル変数への依存)
関数 calculate_total は、引数で値を受け取らず、外側にある $user_cart を直接参照しています。これではテスト(ユニットテスト)が非常に困難です。
global $user_cart;
$user_cart = [100, 50, 200];function calculate_total() {
global $user_cart; // 悪魔の呪文
$total = 0;
foreach ($user_cart as $price) {
$total += $price;
}
return $total;
}echo calculate_total(); // 350
改善例 (純粋な関数)
関数は「引数」としてデータを受け取り、「戻り値」として結果を返すだけにします(純粋な関数)。
$user_cart = [100, 50, 200];
// 引数で $cart を受け取る
function calculate_total(array $cart) {
$total = 0;
foreach ($cart as $price) {
$total += $price;
}
return $total;
}echo calculate_total($user_cart); // 350
どうすれば「泥団子」を避けられるか?
- フレームワークに従う: LaravelやSymfonyのようなフレームワークは、「泥団子」化を防ぐための設計(MVC、DIコンテナなど)を最初から提供しています。レールに乗ることが最善の策です。
- SOLID原則を意識する: 特に「S: 単一責任の原則(クラスの役割は一つだけ)」を強く意識するだけで、神クラスの発生を防げます。
- リファクタリングを恐れない: 「動いているコードに触るな」は間違いです。「ボーイスカウト・ルール(来た時よりも美しく)」を心がけ、機能追加のついでに少しずつコードを綺麗にしましょう。
まとめ
「大きな泥団子」は、ある日突然生まれるのではなく、日々の小さな妥協と怠慢によってゆっくりと育っていきます。
コードが複雑になってきたと感じたら、それは「泥団子」のサインかもしれません。手遅れになる前に、こまめなリファクタリングを習慣づけましょう。
UX / UI のデザインに強いWebシステムの開発と、BtoB Webマーケを支援するWeb制作を提供する
N's Creates 株式会社は、神戸三宮オフィスまで週1出社(それ以外はリモートワーク)できる「デザイナー」「エンジニア」を募集しています。
興味のある方は、カジュアル面談しますので気軽にお問い合わせください!









