The Core Principle: Separation of Concerns
One Job, Done Well
In the last chapter, we made the case for a well-designed monolithic application. The single most important principle that elevates a simple monolith into a professional, maintainable system is Separation of Concerns (SoC).
At its heart, SoC is a simple idea. Every part of the application should have one clearly defined responsibility and should not know about the inner workings of other parts. Code that displays a button on a web page should not be responsible for calculating the data that the button shows. Code that fetches data from the database should not be responsible for the final HTML layout. Each component does one job, and does it well.
This chapter is the philosophical core of our book. We will explore how this one principle is the driving force behind every major architectural decision in our unified application, from the server configuration down to the database security model.
Think of a professional restaurant kitchen. The head chef's responsibility is to create the dishes. The waiter's responsibility is to take the customer's order and deliver the food. The chef doesn't go to the table, and the waiter doesn't cook the steak. Each role is separate, specialised, and communicates with the others through a well-defined interface—the order ticket. This separation allows each component to be an expert at its job and enables the entire system to function efficiently. An Example of What to Avoid: You will see this type of coding in many books. A common way developers learn is by writing single-file scripts to accomplish a task. While this works for simple exercises, it quickly becomes unmanageable. The following example, which connects to a database, fetches user data, and displays it, is a classic illustration of what happens when there is no Separation of Concerns.
<?php
// single_page_user_list.php
// 1. Configuration and Connection Logic
$dbHost = 'localhost';
$dbName = 'some_database';
$dbUser = 'root';
$dbPass = 'password';
try {
$pdo = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUser, $dbPass);
} catch (PDOException $e) {
die("Could not connect to the database: " . $e->getMessage());
}
// 2. Business Logic (Data Fetching)
$sql = "SELECT username, email, dateCreated FROM users WHERE isActive = 1 ORDER BY dateCreated DESC";
$statement = $pdo->query($sql);
$users = $statement->fetchAll(PDO::FETCH_ASSOC);
// 3. Presentation Logic (HTML Rendering)
<!DOCTYPE html>
<html lang="en">
<head>
<title>User List</title>
<style>
body { font-family: sans-serif; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>Our Users</h1>
<table>
<thead>
<tr>
<th>Username</th>
<th>Email</th>
<th>Date Joined</th>
</tr>
</thead>
<tbody>
<?php foreach ($users as $user): ?>
<tr>
<td><?php echo htmlspecialchars($user['username']); ?></td>
<td><?php echo htmlspecialchars($user['email']); ?></td>
<td><?php echo htmlspecialchars($user['dateCreated']); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</body>
</html>
In this single file, we have database credentials (Configuration) and the SQL query (Business Logic). The *HTML (Presentation) has PHP code all tangled together. A change to any one part of this code requires editing the entire script, making it brittle, insecure, and difficult to maintain. This is a perfect example of the "Ball of Mud" that our architecture is designed to prevent.
SoC in Our Architecture, A High-Level Tour
This principle of Separation of Concerns is not just a theory; it is embedded at every level of our unified application. This section will provide a high-level tour of the system, showing how SoC is applied in practice and providing a roadmap for the more detailed chapters that follow.
We enforce separation in four key areas:
Server vs. Application (Chapter 3): The first separation happens before PHP is even involved.
The Apache web server is responsible for routing domain requests and injecting the environment configuration. The PHP application is only responsible for handling the request once it has been delivered.
Model, View, and Controller (Chapters 5, 6, & 7)
We adhere to a classic MVC pattern. The Controller orchestrates the request, the Model handles all business logic and data access, and the View (our Smarty templates) is only responsible for the HTML presentation.
Business Logic vs. Data Access (Chapters 4 & 5)
We take SoC a step further within our Model layer. Business logic (in a Model file) is kept separate from the data access (in a Stored Procedure). The Model knows what it wants, and the database knows how to get it.
Application vs. Database Security (Chapter 4)
Our most critical separation is for security. The PHP application is treated as an untrusted client. It is denied all direct table access and is only granted EXECUTE permission on a curated list of stored procedures.
Conclusion: From Monolith to Modular Monolith
We began this book by making the case for a monolithic architecture. Throughout this chapter, we have detailed the single guiding principle that makes this approach successful: Separation of Concerns.
By applying this principle at every level, from the server to the application, from the controller to the database, we transform our unified application. It is no longer just a "monolith" in the traditional, chaotic sense. It becomes a "modular monolith."
Although all the code resides in a single codebase, it is organised into distinct, independent, and well-defined modules. This gives us the primary benefit of a microservice architecture (modularity) without the significant overhead of a distributed system. It is this disciplined, structured approach that is the key to the platform's success.
In the following chapters, we will begin to explore this structure in practice, starting with Chapter 3—the foundation of our entire multi-site platform: the web server configuration.