Между получением запроса пользователя и передачей ему ответа, системе необходимо обработать этот запрос согласно ее бизнес-логике, которая, в свою очередь, реализуется в рамках выбранной архитектуры. Но что такое “Программная архитектура”? Давайте попробуем ответить на этот вопрос.

В хорошей программе действия пользователя должны обрабатываться согласно выбранной модели взаимодействий. Рассмотрим пример сценария, обрабатывающего запрос стоимости билета в кино:

<?php
// Функция возвращает стоимость билета в кино на данное время

function getCinemaPrice($time){
  ...
}

// Получение данных от пользователя

$targetTime = $_GET['target_time'];

// Бизнес-логика

$price = getCinemaPrice($targetTime);

// Возврат ответа пользователю

echo json_encode([
  'price' => $price
]);

В данном скрипте прослеживается архитектура системы, которая на первый взгляд имеет следующий вид:

Архитектура системы получения стоимости билета в кино

Но давайте рассмотрим ее подробнее:

  1. Компонент User data getter (запрос к массиву $_GET) принимает данные от пользователя
  2. Он передает их к Business logic, которая в процессе взаимодействия с Library (вызов функции getCinemaPrice) получает полезные для пользователя данные
  3. Полученные данные передаются Response generator, который форматирует (в виде JSON) их и передает пользователю

Возможно вы уже заметили, что User data getter не передает данные в Business logic непосредственно, как и последняя не передает их в Response generator. Делается это “автоматически”, путем использования общедоступных (для всех слоев системы) переменных, таких как $targetTime и $price. Правила взаимодействия компонентов и называются архитектурой системы, а вовсе не их порядок следования или состав.

Чтобы было с чем сравнивать, давайте рассмотрим еще один пример программной архитектуры:

<?php
class Application{
  public static function run(){
    // Получение данных от клиента

    $request = new GetCinemaPriceRequest;
    // Формирование ответа

    $response = $request->prepare();
    // Передача ответа клиенту

    $response->send();
  }
}

class GetCinemaPriceRequest{
  private $targetTime;

  public function __construct(){
    $this->targetTime = $_GET['target_time'];
  }

  public function prepare(){
    $cinema = new Cinema;
    $price = $cinema->getPrice($this->targetTime);
    $response = new CinemaPriceResponse($price);

    return $response;
  }
}

class Cinema{
  public function getPrice($time){
    $db = new DataBase;
    $price = $db->getCinemaPrice($time);

    return $price;
  }
}

class CinemaPriceResponse{
  private $price;

  public function __construct($price){
    $this->price = $price;
  }

  public function send(){
    echo json_encode([
      'price' => $this->price
    ]);
  }
}

// Обработка запроса

Application::run();

В этом примере компоненты взаимодействуют не через общедоступные переменные, а с помощью прямых вызовов (или сообщений, как они называются в ООП). Так, приложение инициирует обработка запроса создавая экземпляр класса GetCinemaPriceRequest, который, в свою очередь взаимодействует с классом Cinema, представляющим бизнес-логику системы для получения от него стоимости билета в кино на запрошенное время. После этого, объект GetCinemaPriceRequest создает объект CinemaPriceResponse и возвращает его приложению, а метод send этого объекта передает данные пользователю.

Архитектура заметно изменилась, и дело здесь не в использовании объектной-ориентации, аналогичную архитектуру можно реализовать и с использованием одних только процедур, различия в правилах взаимодействия компонентов.

Зачем она нужна?

Программная архитектура формирует единый стандарт взаимодействия компонентов системы, что упрощает разработку и сопровождение. Это достигается благодаря тому, что исходный код системы с удачно подобранной архитектурой проще читать, связи компонентов в ней более логичны и всегда есть место для новой функциональности.

Чтобы было ясно, рассмотрим простой пример системы без ясно прослеживаемой архитектуры:

<?php
if(isset($_GET['action'])){
  if($_GET['action'] == 'get_cinema_price'){
    if(isset($_GET['target_time'])){
      $targetTime = $_GET['target_time'];
      if(!empty($targetTime)){
        $db = mysqli_connect(...);
        $stmt = mysqli_prepare($db, 'SELECT price FROM cinema WHERE time = ?');
        ...
      }
      else{
        exit;
      }
    }
    else{
      exit;
    }
  }
}
else{
  header('Location: http://my_site.ru/', true, 301);
}

if(isset($price)){
  echo json_encode([
    'price' => $price;
  ]);
}

Возможно это вполне рабочая система, которая исправно выполняет свои функции, но из за множества вложенных конструкций ветвления нам тяжело понять ее архитектуру. Не очевидно, как именно скрипт получает полезные пользователю данные (цену билета в кино $price) и какие проблемы могут возникнуть в процессе этого.

Выбор архитектуры

В примерах архитектур, которые были рассмотрены нами в начале статьи, мы познакомились с двумя различными вариантами взаимодействия компонентов:

  1. Через общие переменные
  2. Через объектные сообщения

Какую из них выбрать в качестве наиболее удачной?

Задача

В первую очередь все зависит от целей системы. Если система только предоставляет стоимость билетов в кино, то архитектура, использующая общие переменные, выглядит более привлекательной, ведь она гораздо проще в реализации. С другой стороны система, обслуживающая весь кинотеатр и всевозможные запросы пользователей к нему, лучше реализуется с использованием объектных сообщений. Другими словами чем проще система, тем проще должна быть ее архитектура и наоборот.

Вариации

После оценки задач системы, необходимо выбрать одну из возможных архитектур, но сколько их? Много. Программная архитектура это не дискретная сущность, она больше похожа на непрерывный градиент, сильно зависящий от деталей.

Архитектура на основе общих переменных может рассматриваться как более процедурное решение, использующее глобальное пространство имен без вспомогательных компонентов. С другой стороны архитектура на основе объектных сообщений использует объектную-ориентацию, сообщения и инкапсуляцию. Перенесите, к примеру, инкапсуляцию в первую группу, и вот уже новая архитектура.

В будущих статьях мы обязательно рассмотрим некоторые, из наиболее популярных программных архитектур в Web, а если вам не терпится ознакомиться с ними уже сейчас, обязательно прочитайте: “Архитектура корпоративных программных приложений” Мартина Фаулера.