Я хотел бы затронуть тему правильной архитектуры приложений на PHP. Статья будет посвящена паттерну проектирования MVC. Написать про MVC меня сподвиг именно тот факт, что понимание этого паттерна является ключевым в становлении программиста. Так что если вы новичок и хотите начать писать программы правильно, читайте дальше.

Теория


Если коротко, то MVC (model view controller) это такой способ написания программы, когда код отвечающий за вывод данных, пишется в одном месте, а код который эти данные формирует, пишется в другом месте. В итоге получается так, что если вам надо подправить вывод вы сразу знаете в каком месте искать. Сейчас все популярные фреймворки используют такую архитектуру.

Также стоит упомянуть тот факт, что существует два лагеря: один пишет логику в контроллерах, второй в моделях. В тех фреймворках, которые знаю я (yii, laravel) логику пишут в контроллерах, а модели являются просто экземплярами ORM (почитайте про паттерн Active Record). У yii кстати в мануале написано, что писать логику надо в моделях, а потом они сами в примерах пишут её в контроллерах, довольно забавно.

С бизнес-логикой определились, пишем в контроллерах. Также в методах контроллера происходит вызов моделей, которые у нас по сути экземпляры ORM, чтобы с их помощью получить данные из базы над которыми будут производить изменения. Конечный результат отправляется в виды. Виды cодержат HTML-разметку и небольшие вставки PHP-кода для обхода, форматирования и отображения данных.

Ещё можно упомянуть, что есть два вида MVC Page Controller и Front Controller. Page Controller'ом пользуются редко, его подход заключается в использовании нескольких точек входа (запросы к сайту осуществляются к нескольким файлам), и внутри каждой точки входа свой код отображения. Мы будем писать Front Controller с одной точкой входа.

Практика


Начать надо с настройки сервера для переадресации на нашу единую точку входа. Если у нас apache, то в файле .htaccess пишем следующее

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [L]

Дальше в папке нашего проекта создаём папку, которую можно назвать App например. В ней будет следующее содержимое.

Наш Service Locator. Файл App.php


<?php

class App

{
        
    public static $router;
    
    public static $db;
    
    public static $kernel;
    
    public static function init()
    {
        spl_autoload_register(['static','loadClass']);
        static::bootstrap();
        set_exception_handler(['App','handleException']);
        
    }
    
    public static function bootstrap()
    {
        static::$router = new App\Router();
        static::$kernel = new App\Kernel();
        static::$db = new App\Db();
       
    }
    
    public static function loadClass ($className)
    {
        
        $className = str_replace('\\', DIRECTORY_SEPARATOR, $className);
        require_once ROOTPATH.DIRECTORY_SEPARATOR.$className.'.php';
        
    }
    
    public function handleException (Throwable $e)
    {
        
        if($e instanceof \App\Exceptions\InvalidRouteException) {
            echo static::$kernel->launchAction('Error', 'error404', [$e]);
        }else{
            echo static::$kernel->launchAction('Error', 'error500', [$e]);  
        }
        
    }
    
}

Сервис локатор нужен чтобы хранить в нём компоненты нашего приложения. Поскольку у нас простое mvc приложение, то мы не используем паттерн registry (как например в yii сделано). А просто сохраняем компоненты приложения в статические свойства, чтобы обращаться к ним было проще. Ещё App регистрирует автозагрузчик классов и обработчик исключений.

Роутер. Файл Router.php


<?php
namespace App;

class Router

{
    
    public function resolve ()
    {
        
        if(($pos = strpos($_SERVER['REQUEST_URI'], '?')) !== false){
        $route = substr($_SERVER['REQUEST_URI'], 0, $pos);
        }
        $route = is_null($route) ? $_SERVER['REQUEST_URI'] : $route;
        $route = explode('/', $route);
        array_shift($route);
        $result[0] = array_shift($route);
        $result[1] = array_shift($route);
        $result[2] = $route;
        return $result;
        
    }
    
}

В простом mvc приложении роутер содержит всего один метод. Он парсит адрес из $_SERVER['REQUEST_URI']. Я ещё не сказал, что все наши ссылки на страницы сайта должны быть вида www.ourwebsite.com/%controller%/%action%, где %controller% — имя файла контроллера, а %action% — имя метода контроллера, который будет вызван.

Файл Db.php


<?php

namespace App;

use App;

class Db 
{

    public $pdo;
    
    public function __construct()
    {
       
        $settings = $this->getPDOSettings();
        $this->pdo = new \PDO($settings['dsn'], $settings['user'], $settings['pass'], null);
        
    }
    
    protected function getPDOSettings()
    {
        
        $config = include ROOTPATH.DIRECTORY_SEPARATOR.'Config'.DIRECTORY_SEPARATOR.'Db.php';
        $result['dsn'] = "{$config['type']}:host={$config['host']};dbname={$config['dbname']};charset={$config['charset']}";
        $result['user'] = $config['user'];
        $result['pass'] = $config['pass'];
        return $result;       
    }
    
    public function execute($query, array $params=null)
    {
        
        if(is_null($params)){
            $stmt = $this->pdo->query($query);
            return $stmt->fetchAll();
        }
        $stmt = $this->pdo->prepare($query);
        $stmt->execute($params);
        return $stmt->fetchAll();
        
    }    
}

Этот класс юзает файл конфига, который возврашает массив при подключении

Файл Config/Db.php


<?php

return [
'type' => 'mysql',
'host' => 'localhost',
'dbname' => 'gotlib',
'charset' => 'utf8',
'user' => 'root',
'pass' => ''
];

Наше ядро. Файл Kernel.php


<?php

namespace App;

use App;

class Kernel 
{
    
    public $defaultControllerName = 'Home';
    
    public $defaultActionName = "index";
    
    public function launch()
    {
        
        list($controllerName, $actionName, $params) = App::$router->resolve();
        echo $this->launchAction($controllerName, $actionName, $params);
            
    }
    

    public function launchAction($controllerName, $actionName, $params)
    {
        
        $controllerName = empty($controllerName) ? $this->defaultControllerName : ucfirst($controllerName);
        if(!file_exists(ROOTPATH.DIRECTORY_SEPARATOR.'Controllers'.DIRECTORY_SEPARATOR.$controllerName.'.php')){
            throw new \App\Exceptions\InvalidRouteException();
        }
        require_once ROOTPATH.DIRECTORY_SEPARATOR.'Controllers'.DIRECTORY_SEPARATOR.$controllerName.'.php';
        if(!class_exists("\\Controllers\\".ucfirst($controllerName))){
            throw new \App\Exceptions\InvalidRouteException();
        }
        $controllerName = "\\Controllers\\".ucfirst($controllerName);
        $controller = new $controllerName;
        $actionName = empty($actionName) ? $this->defaultActionName : $actionName;
        if (!method_exists($controller, $actionName)){
            throw new \App\Exceptions\InvalidRouteException();
        }
        return $controller->$actionName($params);
        
    }

}

Ядро обращается к роутеру, а потом запускает действия контроллера. Ещё ядро может кинуть исключение, если нет нужного контроллера или метода.

Файл Controller.php


Ещё нам нужно создать базовый класс для наших контроллеров, чтобы потом наследоваться от него. Наследовать методы нужно для того, чтобы вы могли рендерить (сформировать вывод) виды. Методы рендеринга поддерживают использование лэйаутов — шаблонов, которые содержат общие для всех видов компоненты, например футер и хэдер.

<?php

namespace App;

use App;

class Controller 
{
    
    public $layoutFile = 'Views/Layout.php';
    
    public function renderLayout ($body) 
    {
        
        ob_start();
        require ROOTPATH.DIRECTORY_SEPARATOR.'Views'.DIRECTORY_SEPARATOR.'Layout'.DIRECTORY_SEPARATOR."Layout.php";
        return ob_get_clean();
                
    }
    
    public function render ($viewName, array $params = [])
    {
        
        $viewFile = ROOTPATH.DIRECTORY_SEPARATOR.'Views'.DIRECTORY_SEPARATOR.$viewName.'.php';
        extract($params);
        ob_start();
        require $viewFile;
        $body = ob_get_clean();
        ob_end_clean();
        if (defined(NO_LAYOUT)){
            return $body;
        }
        return $this->renderLayout($body);
        
    }
    
}

Файл index.php


Не забываем создать индексный файл в корне:

<?php

define('ROOTPATH', __DIR__);

require __DIR__.'/App/App.php';

App::init();
App::$kernel->launch();

Создаём контроллеры и виды


Работа с нашим приложением (можно даже сказать минифреймворком) теперь сводится к созданию видов и контроллеров. Пример контроллера следующий (в папке Controllers):

<?php

namespace Controllers;

class Home extends \App\Controller
{
    
    public function index ()
    {
        
        return $this->render('Home');
        
    }
    
}

Пример вида(в папке Views):

<img src="Img/my_photo.jpeg" alt="my_photo" id="my_photo">
<h1>Привет</h1>
<p>Меня зовут Глеб и я - веб-разработчик.</p>
Мои контакты:<br>
8-912-641-3462<br>
goootlib@gmail.com

В папке Views/Layout создаём Layout.php:

<!DOCTYPE html>
<html lang="ru">
    <head>
        <meta charset="utf-8">
        <title>Обо мне</title>
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <link href="/Css/style_layout.css" rel="stylesheet" type="text/css">
        <link href="https://fonts.googleapis.com/css?family=Roboto+Condensed" rel="stylesheet">
    </head>
    <body>
        <header>
            <nav>
                <a id="about_button" href="/home">Обо мне</a>
                <a id="portfolio_button" href="/portfolio">Портфолио</a>
                <a id="blog_button" href="/blog">Блог</a>
            </nav>
        </header>
        <div class="main">
                <?= $body ?>
        </div>
        <footer>
            <div class="copyrights">
            2017 Жуков Глеб(gotlib)<br>
            При копировании материалов на сторонние ресурсы, ссылка на http://www.gotlib.info обязательна!
            
            </div>
            <div class="contacts">
                8-912-641-3462<br>
                goootlib@gmail.com
            </div>
        </footer>
    </body>
</html>

Заключение


Если решите пользоваться кодом приложения, которое описал я, не забудьте создать контроллер Error с методами error404 и error500. Класс для работы с бд, описанный мной, подходит для написания запросов руками, вместо него можно подключить ORM и вас будут настоящие модели.
Поделиться с друзьями
-->

Комментарии (61)


  1. lair
    26.01.2017 11:37
    +11

    Написать про MVC меня сподвиг именно тот факт, что понимание этого паттерна является ключевым в становлении программиста.

    Э, серьезно? А аргументировать?


    Если коротко, то MVC (model view controller) это такой способ написания программы, когда код отвечающий за вывод данных, пишется в одном месте, а код который эти данные формирует, пишется в другом месте.

    Это, на минуточку, называется Separated Presentation, и MVC — только один частный случай.


    (и я даже не буду вдаваться в нюансы того, какие именно MVC бывают)


    С бизнес-логикой определились, пишем в контроллерах.

    Смешно вы определились, да. А на основании чего? А то, что бывает доменная модель и доменные сервисы, вы не слышали?


    Конечный результат отправляется в виды. Виды cодержат HTML-разметку и небольшие вставки PHP-кода для обхода, форматирования и отображения данных.

    Вообще, это называется "представление".


    Ещё можно упомянуть, что есть два вида MVC Page Controller и Front Controller.

    Откуда, стесняюсь спросить, вы взяли эту классификацию?


    Ну и да, где полное описание паттерна-то? Что с чем взаимодействует, зачем, и все вот это вот?


    Нее, понимания после вашего поста не будет, будет только еще одно "я тут написал что-то под названием MVC".


    1. Old_Chroft
      26.01.2017 13:02
      +1

      Написать про MVC меня сподвиг именно тот факт, что понимание этого паттерна является ключевым в становлении программиста.
      Э, серьезно? А аргументировать?
      Ну не слышал человек ни разу ни про драйвера, ни про системные сервисы, где View не может быть в принципе (ибо _не_нужно_). Ну бывает, чо уж.
      А касаемо самой статьи — объяснения по сути никакого, код на первый взгляд неплохой, за исключением парочки сомнительных мест:
      index.php
      define('ROOTPATH', __DIR__);
      require __DIR__.'/App/App.php';
      
      Какая такая причина пихать исходники в доступную из WWW директорию?
      В папке Views/Layout создаём Layout.php:
      ...
      <div class="copyrights">
      2017 Жуков Глеб(gotlib)<br>
          При копировании материалов на сторонние ресурсы, ссылка на http://www.gotlib.info обязательна!
      </div>
      ...
      Ах, ну да, ну да.


      1. Old_Chroft
        26.01.2017 15:58

        Какая такая причина пихать исходники в доступную из WWW директорию?
        Отвечу сам себе: «чтобы любопытные смогли пошариться в структуре вашего сайта»:

        • http://www.gotlib.info/App/
        • http://www.gotlib.info/App/Exceptions/
        • http://www.gotlib.info/App/Recaptcha/
        • http://www.gotlib.info/App/Kernel.php
        • ...

        Фу так делать.


  1. SamDark
    26.01.2017 13:13

    В тех фреймворках, которые знаю я (yii, laravel) логику пишут в контроллерах, а модели являются просто экземплярами ORM (почитайте про паттерн Active Record). У yii кстати в мануале написано, что писать логику надо в моделях, а потом они сами в примерах пишут её в контроллерах, довольно забавно.

    Очень был бы благодарен за указания на конкретные места в гайде Yii, которые:


    • Рекомендуют писать логику в контроллерах.
    • Показывают логику в контроллерах (скорее всего ради упрощения сделано).
    • Рекомендуют писать логику в Active Record или намекают на это.
    • Говорят, что AR === модель.

    У меня, как автора довольно значительной части этих текстов, развилась слепота на ошибки :(


    А вообще вот что я об этом думаю: https://github.com/samdark/yii2-cookbook/blob/master/book/mvc.md


    1. Zazza
      26.01.2017 15:20

      Есть такая тема про толстые контроллеры/модели и этому в значительной части подвержен именно yii. Но в этом виновата не документация, а огромное число проектов с такими подходами. Я даже видео по фреймворку видел, где делают именно так: логику пишут в контроллере, а модели максимально загружают различными вызовами. Еще и минус php как шаблонизатора (1-й yii), вставить виджет на страницу, а перед ним код прямо в шаблоне.
      Раз у вас есть опыт написания статей, м.б. написать статью с примерами хороших подходов: соблюдение PSR-ов, создание либ для помещения логики, и если рассматривать yii можно запихнуть, как хорошо организовывать конфиги и структуру папок проекта и т.д.?


      1. SamDark
        26.01.2017 18:59

        Я это делаю время от времени. Недавно рассказывал в Иванове про это. Ссылки и видео тут: http://slides.rmcreative.ru/


        Статьи тоже пишу, выше ссылка как раз.


        1. VolCh
          26.01.2017 22:01

          М — это прежде всего классы и функции, содержащие бизнес-данные в рантайме и реализующие бизнес-логику. Как данные туда попадают, куда деваются и откуда запускаются функции и методы классов к М особого отношения не имеет, даже если классы основных сущностей наследуют какой-нибудь АктивРекорд.


          1. Zazza
            26.01.2017 22:58
            +1

            что во всех подобных разговорах мне не нравится, код в первую очередь должен быть понятен. Не важно M это или нет, проблема толстых контроллеров и моделей именно в в уложении восприятия, а уж где и как, что будет располагаться это вообще мало важно, я могу в контроллере использовать приватные функции, лишь бы это было логично и понятно. А то устроили какую-то религию из этого ))


            1. oxidmod
              26.01.2017 23:05

              Это не религия, это просто следующий шаг после отделения логики от представления. Слоеная архитектура, как её называют. бизнес-логика должна быть в бизнес слое, чтобы не зависеть от контролера, бд, фреймворка.


              1. Zazza
                26.01.2017 23:22
                +1

                Я же не говорил писать в представлкнии. Я сказал, что код должен быть понятным. Все зависит от ситуации. Вы говорите теорию.


            1. SamDark
              26.01.2017 23:30
              +1

              Да, всё так. К сожалению, код становится непонятным сразу по двум причинам:


              1. Когда его слишком много и он делает всё и сразу.
              2. Когда абстракции слишком много, каждая отдельная часть кода слишком проста, а взаимодействие частей слишком сложно.


              1. VolCh
                27.01.2017 00:00
                +1

                Это мобильное приложение куда попало комменты распихивает :(


              1. http3
                27.01.2017 10:44

                Пункт 2 очень точно подмечен. :)


                1. oxidmod
                  27.01.2017 10:55

                  Такое бывает когда используют паттерны ради паттернов.


                  1. SamDark
                    27.01.2017 11:54

                    Когда ради дела используют тоже бывает и довольно часто.


                    1. oxidmod
                      27.01.2017 12:16

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


            1. VolCh
              27.01.2017 00:04
              +1

              Один из факторов понятности — контекст, в том числе именование, в том числе место расположения в проекте. Один кусок кода будет понятнее в папочке/классе Controller, а другой в Model.


          1. SamDark
            26.01.2017 23:27

            Так и есть. Я где-то этому противоречил?


    1. http3
      26.01.2017 15:59

      Большинство фреймворщиков (писунов в интернетах) именно так неправильно и понимают M.
      Типо, M — это наследник базового класса по работе с базой и этот M расширяют всяким мусором. :)

      А что плохого, если простая логика будет в контроллере?
      Если M ограничится ORM? :)


      1. lair
        26.01.2017 16:20

        А что плохого, если простая логика будет в контроллере?

        … а где будет сложная?


        1. http3
          26.01.2017 16:50
          +1

          А сложной не будет вообще…


          1. lair
            26.01.2017 16:54

            Если вы можете сказать, что в вашем приложении никогда не будет сложной бизнес-логики — да пишите тогда простую где хотите, конечно.


    1. Temirkhan
      26.01.2017 18:28

      Все-таки, когда я только начинал, мне тоже везде попадались примеры с толстымиконтроллерами.

      Но с другой стороны, если почитать в самому низу
      документации(параграф BestPracice), правда на Вашей стороне…

      К тому же, в доках и демках практически все известные мне фреймворки грешат этим. Тот же laravel, тот же symfony. Полагаю, это связано с привлечением внимания большей части аудитории.(порог вхождения, все дела)


      1. SamDark
        26.01.2017 19:01

        Не, это просто несколько разгружает доку. Если каждый раз заворачивать всё в нормальный бизнес-слой, дока будет про него, а не про то, что сказать хотели.


  1. CnapoB
    26.01.2017 13:33
    +1

    Слишком часто последнее время попадается подобный код, который они гордо называют MVC, в качестве портфолио от соискателей.

    Так что если вы новичок и хотите начать писать программы правильно, читайте дальше.

    — array_shift слишком затратная функция (извлечь + сдвинуть все элементы с числовыми индексами), вместо нее лучше обращаться напрямую через [], либо, если так уж хочется удалять элементы из массива, то array_reverse + array_pop, а конкретно в вашем примере $result=explode('/',$route,3);
    — Судя по тому, как добавляются файлы через require, документация к нему прочитана не была.
    — Функция launchAction накладывает ограничения на названия файлов и классов.
    — Об использовании двойных кавычек вообще молчу.

    ИМХО: И представленный код не для новичков с его namespace и классами. Если вы действительно хотели написать гайд, начали бы с процедурного стиля.


  1. AlexLeonov
    26.01.2017 13:49
    +1

    class Controller 
    {
        
        public $layoutFile = 'Views/Layout.php';
    


    Кол вам за тему «MVC», приходите пересдавать.


  1. MadridianFox
    26.01.2017 14:39
    +2

    Так что если вы новичок и хотите начать писать программы правильно, читайте дальше.

    С бизнес-логикой определились, пишем в контроллерах.

    Одного только этого достаточно, чтобы сказать, что польза от данного текста скорее отрицательна.


  1. SerafimArts
    26.01.2017 16:45

    Судя по коду у вас получился MVP, но без моделей.


  1. akubintsev
    26.01.2017 18:30

    Только мне одному кажется сегодня чем-то диким заморачиваться на тему MVC и какой архитектуре/паттерну соответствует код?

    Может люди живут в идеальном мире с только новыми и хорошо написанными проектами? Или где-то водятся в большом количестве компании, щедро бюджетирующие непродуктовые задачи типа рефакторинга?

    Расслабьтесь и получайте удовольствие: в реальном мире нереальное количество говнокода. Процедурного из эпохи 5.2 и псевдо-ООП из 5.3. Чему и нужно учиться, так это как выживать среди всего этого бедлама, сводя к минимуму факапы и намазывая поверх код с новыми бизнес-фичами.


    1. SerafimArts
      26.01.2017 18:35
      +1

      Это ваше личное мнение. Лично я уже лет 5 подобного не видел. На проде нынче только php 7+, максимум php 5.6. Совет — меняйте работу.


      1. akubintsev
        26.01.2017 19:04

        Я за свои 7 лет в вебе как раз встречал больше плохого, чем хорошего. И это логично, поскольку многие проекты писались в старую эпоху и разработчиками, которые не рвались переучиваться на новый лад.
        А что вы скажете, если разработчик придёт работать в компанию, где портал крутится на wordpress? Там и по сей день новый версии не блещут красивым кодом даже на фоне joomla.

        Работу менять только из-за плохого кода считаю эскапизмом. Есть множество и других определяющих факторов.


        1. SerafimArts
          27.01.2017 00:44

          А что вы скажете, если разработчик придёт работать в компанию, где портал крутится на wordpress? Там и по сей день новый версии не блещут красивым кодом даже на фоне joomla.

          Это опять же конкретно ваши неудача, что попадались такие проекты и переходили на такие работы. За более чем 5 лет работы (может меньше, может больше, начинал во времена php 5.2) мне ни разу не встретилась та, где использовались бы какие-нибудь CMS или просто код в стиле php 4.


          Да, может я излишне цинично рассматриваю этот вопрос, не учитывая каких-то факторов, но вы сами определяете где и кем будете работать. Если вам нравится работать с битриксоподобными продуктами — это ваше личное предпочтение.


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


          Ещё раз прошу прощения за цинизм. Но стоит развиваться, чтобы вас оценивали как специалиста, а не бежать в первое попавшееся место.


          1. http3
            27.01.2017 10:51

            Если вам нравится работать с битриксоподобными продуктами

            Хм, но какая разница, что внутри CMS или фреймворка? :)

            С этим кодом разработчику работать не приходится.

            А вот на якобы нормальных CMS или фреймворках программисты создают свой говнокод, с которым приходится работать другим. :)


            1. michael_vostrikov
              27.01.2017 11:24

              Разница в том, как использовать то, что внутри. Насколько это удобно и понятно. И какие дает возможности.


              1. http3
                27.01.2017 11:35

                Внутри черный ящик с публичным API.
                API битрикса — более менее норм. А также его плюс в том, что оно обратно совместимо.

                А вот когда куча говнокода на якобы нормальном фреймворке — вот это печально.
                Методы CMS или фреймворка не так и часто нужно использовать.


          1. akubintsev
            27.01.2017 11:45

            Да всё нормально, я понимаю вашу позицию. У меня был опыт в «долгом» стартапе и это было прекрасное время, когда всё писалось красиво с нуля на самых передовых технологиях. Но стартап умер, как это часто и бывает.

            С каждым годом ситуация с проектами становится лучше, но про вордпресс я не зря упомянул, поскольку это одна из самых популярных CMS в мире PHP на сегодня, а значит и шансы встретиться с ней велики.
            На это конечно можно возразить, что подобные CMS используют только в маленьких компаниях. Ок, давайте тогда рассмотрим большие компании. В больших компаниях большие и долгоживущие проекты. Я трижды попадал в такие и во всех случаях был самописный велосипед. В одном вообще хаос и анархия, оттуда быстро убежал (2012 год). В другом (2015) вроде получше были ситуация, стали потихоньку переписывать с процедур на псевдоООП. И наконец в последней компании процедурный стиль, но хотя бы с каким-то намеком на архитектуру, но конечно же без единого теста.

            Я соглашусь с тем, что на определенных этапах развития, особенно раннем, лучше сменить работу. Но когда уже есть опыт разработки и выработано чувство прекрасного, а всё остальное в работе, кроме кода, устраивает, в том числе и карьерная перспектива, то есть резон продолжать трудиться на этом месте. Впрочем это вопрос личных целей.


            1. SerafimArts
              27.01.2017 13:30

              Начиная с года 2012го, когда я вернулся из фронт-энда обратно на бекенд — мне попадались проекты в которых не то что процедурного стиля, даже нарушений PSR не было. Покрытие тестами, согласен, все этим грешат, зачастую просто лень, работа сделана, всё работает, а дальше новые задачи. На последнем же месте работы коверейдж примерно 90%+, правда тесты функциональные, т.к. они более профитны для рефакторинга.


              В любом случае наличие или отсутсвие тестов я могу принять, но подобную кодовую базу — нет, кажется что это какая-то фантастика из параллельных вселенных. Даже когда куда-то переходил и просто рассматривал какое-то место работы — всегда, если давали примеры кода, тем более примеры из реальных проектов — они были вполне вменяемыми и современными.


              Единственное место на моей памяти, которое не соответсвовало этому критерию — это Кинопоиск. У них там древний php 5.3 и судя по вопросам на собеседовании — они мало стремятся это дело поправить, скорее искали разработчиков на поддержку. Так что рассматриваю это скорее как исключение, связанное с обширной неподдерживаемой кодовой базой.


            1. http3
              27.01.2017 15:14

              В больших компаниях большие и долгоживущие проекты. Я трижды попадал в такие и во всех случаях был самописный велосипед.

              Хм, я постоянно говорю, что большие компании используют самопись, а не фреймворки.
              Но получаю минусов. :)

              Только некоторые уже сейчас пытаются следовать моде, создавая новые проекты.


    1. lair
      26.01.2017 18:54
      -1

      Только мне одному кажется сегодня чем-то диким заморачиваться на тему MVC и какой архитектуре/паттерну соответствует код?

      Нет, не вам одному. Но людей, которым хорошая архитектура нужна, все еще достаточно.


      1. akubintsev
        26.01.2017 19:11
        +3

        Нужна — да. Но не стоит забывать, что все паттерны носят рекомендательный характер, а не обязательный, когда шаг влево/вправо — расстрел. Впрочем, на каком-то этапе может надо и построже, но я больше верю в целительную силу код ревью, поскольку второй задачей кода после выполнения им поставленной задачи является ясность для другого разработчика. А паттерны — один удобных из способов.
        Удачность же архитектуры определяется способностью предвидеть изменения в проекте.


        1. lair
          26.01.2017 19:13
          -1

          Вот чтобы у код-ревью была целительная сила, рано или поздно придется заморочитсья вопросом "какому паттерну соответствует этот код".


        1. VolCh
          28.01.2017 08:04

          Паттерны — это не более, чем общеупотребительные имена проверенных решений общих задач. Это даже не рекомендация решать эти задачи таким образом, это просто соглашение: такое-то решение такой-то задачи называется так-то. Именно для понятности другим разработчиком. Всё.


    1. http3
      27.01.2017 15:19

      Только мне одному кажется сегодня чем-то диким заморачиваться на тему MVC и какой архитектуре/паттерну соответствует код?

      +1
      Да и в повседневной разработке не нужно заново создавать MVC-каркас или использовать паттерны.
      Пользуемся готовым функционалом, меняем в случае необходимости. Но не ради моды или галочки.


    1. Fesor
      28.01.2017 22:00
      +2

      Расслабьтесь и получайте удовольствие: в реальном мире нереальное количество говнокода.

      Да, в этом и проблема. Его слишком много. У Роберта Мартина есть неплохая теория на этот счет. Количество разработчиков каждый 5 лет удваивается. Это значит что сегодня, завтра и через год в мире половина всех разработчиков будет иметь менее 5-ти лет опыта. Что это значит? Это значит что процент людей которые понимают что откуда и куда постоянно уменьшается.


      Вместо того чтобы "учить людей MVC" попути спутав все понятия в одну кучу и забыв зачем вообще все это придумывалось (а ведь придумали MVC ажно 38 лет назад) следует больше внимания уделять таким вещам как декомпозиция, функциональная абстракция, принципы проектирования и т.д. Учить писать тесты (заметьте, не TDD а хотя бы тесты).


      Чему и нужно учиться, так это как выживать среди всего этого бедлама, сводя к минимуму факапы и намазывая поверх код с новыми бизнес-фичами.

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


      • посадили на пару недель QA/разработчиков написать e2e тесты на основной функционал ну и попутно разобраться как все работает
      • составили приоритизацию новых фич
      • делаем дела постепенно переписывая функционал

      И прикол тут в том что чтобы не погрузиться еще больше в ведерко с гуано нужно хорошо знать как делать правильно. Работа с легаси это посложнее чем работа с чистого листа (свой код не так пахнет как чужой).


      1. akubintsev
        30.01.2017 15:59

        Полностью согласен с тем, чему реально надо учить.
        А вот достать дополнительно QA и тем более разработчиков — это далеко не всегда возможно. Ресурсов никто не даст просто так на рефакторинг, даже если обосновать математически выгоду в перспективе. В далекую перспективу неохотно верят, особенно в последние годы, нужны пруфы. Потратили столько денег — заработали на x% больше через год например.


        1. Fesor
          30.01.2017 17:04

          А вот достать дополнительно QA и тем более разработчиков — это далеко не всегда возможно.

          ну так это ж челендж для разработчика. Как с минимальными усилиями достич максимальной изоляции разработки и автоматизировать рутину на которую тратится время. Я не говорю о том что надо месяц или более чето там пилить, недельку достаточно для старта. Хотя конечно все сильно зависит от проекта, скоупа работ и команды.


          Потратили столько денег — заработали на x% больше через год например.

          тут тоже такой момент. Если ваш рефакторинг проекта окупится только через год — возможно вы взяли кусок непомерный. Возможно можно подумать еще, пойти на компромисы и почисть только ту часть кода которая принесет профит уже в течении месяца.


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


        1. Temirkhan
          31.01.2017 17:22

          Стоимость разработки всегда растет. А наличие техдолга ускоряет ее рост. Вы не можете донести до бизнеса, что рефакторинг поможет заработать больше. Только то, что это снизит затраты и стоимость разработки.


          1. VolCh
            01.02.2017 06:41

            Если разрабатываемые фичи приносят деньги (а иначе зачем их разрабатывать? :) ), а рефакторинг ускоряет последующую разработку (тут сложнее, он может не ускорять, а, например, требовать для поддержки/развития специалистов меньшей квалификации), то рефакторинг приносит деньги напрямую. Грубо, есть пул задач на год вперёд с текущим графиком по фиче в месяц, каждая приносит по миллиону в месяц, а рефакторинг, на который требуется два месяца, сократит срок разработки каждой до трех недель. Без рефакторинга за год получим 66 миллионов, с рефакторингом задержим первое поступление на 2 месяца, через полгода догоним график по общей сумме дохода, а весь план выполним за 10 месяцев, заработав за год 68 миллионов, при условии что последних два месяца фич, приносящих деньги, делать не будем.


            1. Temirkhan
              01.02.2017 14:32

              Мы сделаем эту фичу за 4 недели, а следующая будет стоить уже 1 месяц. И так по нарастающей, если не займемся разрешением техдолга и тем самым не снизим дальнейшие расходы компании.


              Мы сделаем рефакторинг за 2 месяца, а потом все фичи будут стоить 3 недели. Таким образом мы увеличим дальнейшие доходы компании.


              На втором подносе присутствует ложь и она сыграет во вред тем, кто ведет разработку.


            1. Fesor
              01.02.2017 23:33

              то рефакторинг приносит деньги напрямую.

              Есть нюанс. Для этого разработчик должен четко представлять в чем проблема и как ее исправить. Многие разработчики же просто хотят убрать то что им не нравится, и часто бывает так что с точки зрения бизнеса профита в этом нет.


              В целом выделать время на рефакторинг так себе идея, а вот закладывать устранение тех долга в процесс разработки (скажем 20%) вполне себе норм.


              1. VolCh
                03.02.2017 06:35

                Часто бизнес настаивает на скорейшем запуске фич, типа оно уже работает — запускайте.


                1. Fesor
                  03.02.2017 14:21

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


                  Разработчики любят рефакторить и улучшать свой код. Точно так же как оунеры любят генерить фичи которые не нужны. Ну то есть проблема одна и та же, плохая приоритизация, нет целей, нет таргет группы (или пула задач на ближайшее время или статистики по регрессиям чтобы оценить импакт технического долга в случае разработчиков)… Словом можно тратить намного меньше времени. Да, код не будет идеальным (как будто бы это возможно) но если поддерживать должный уровень изоляции то все будет относительно неплохо и дешево.


  1. EmotionTigran
    29.01.2017 11:45

    Сама по себе статья довольно слабая. Очень очень много информации не раскрывается. В любом случае, писать MVC самописку в 2017 году уже нету смысла. Если вас не устраивают full-stack большие фреймворки типа Symfony, Laravel, то скорее всего вам подойдут их микрофреймворки типа Silex


    1. Fesor
      29.01.2017 15:35
      +1

      Интересный факт, фреймворки вроде Symfony или Silex не являются MVC фреймворками (по сути сам термин MVC фреймворк это маркетинговый булшит который начался в 2004-ом году с появлением всяких RoR).


    1. MetaDone
      29.01.2017 17:46

      еще можно использовать тот же Symfony как микрофреймворк, или использовать Phalcon Micro Applications, или же собрать свое из компонентов


  1. SmiteVils
    29.01.2017 19:12
    -1

    А мне понравилась. Не знаю как уж с тех. сороны, но на пальцах хорошо обьяснил что такое MVC, я как новичек кажется понял. А если вы такие знающие, напишите пожалуйста статью для новичков, только правильную, и что бы понятно был, а то статей миллион и нихрена не понятно.


    1. Fesor
      29.01.2017 20:46
      +2

      Так и что такое модель? И что вы будете делать если у вас одна и так же логика будет требоваться в 2-х контроллерах?


    1. EmotionTigran
      30.01.2017 13:35

      Самое главное, что надо понять новичку — не надо писать свой MVC фреймворк. Над готовыми инструментами работает целая команда разработчиков и они скорее всего более опытные чем Вы.


      1. oxidmod
        30.01.2017 14:49

        не писал свой MVC-фреймворк — не пацан))


        1. Fesor
          30.01.2017 17:04

          зато мужик.


  1. VolCh
    29.01.2017 20:50
    +1

    Также стоит упомянуть тот факт, что существует два лагеря: один пишет логику в контроллерах, второй в моделях.

    А я как всегда ни рыба, ни мяса… Бизнес-логику пишу в модели (сущности, объекты-значения и сервисы в основном), логику приложения в контроллерах и инфраструктурных сервисах, а логику представления вообще в шаблонах.