Введение
По ходу эксплуатации различных современных фреймворков я понял, что недостаточно понимаю, как все устроено внутри; не осознаю, почему разработчики выбрали то или иное решение; обращаю внимание только на текущую задачу и не смотрю «выше, глубже и дальше». И, как вариант для профессионального роста, я выбрал создание собственного проекта.
Как показала дальше практика: читать, знать, слышать о чем-либо, и уметь самому это реализовать — совершенно разные вещи. Теоретизировать можно бесконечно, но только настоящее практическое задание позволяет понять, на каком уровне ты находишься. Всвязи с этим и было начато «написание собственного велосипеда». Каким он получился — судить вам.
Процесс разработки
Разработка фреймворка велась следующим образом: изначально было некое простейшее веб-приложение, которое дорабатывалось, переписывалось, меняло структуру, обрастало новыми классами и компонентами и т. д. Несколько месяцев назад у меня появилось свободное время, много энтузиазма и решительности таки доделать фреймворк «по-серьезному». На написание данной версии я потратил в совокупности 3-4 недели (работая в среднем 1-3 часа в день, 3-4 дня в неделю).
По мере разработки стандарты и требования я сознательно завышал для себя, искал оптимальные решения много раз переписывал код. Так, например, работу с конфигурацией я переделывал раз 5-6 (причем несколько раз кардинально), роутинг — 3-4 раза. В качестве примеров я брал код из статей, публикаций, руководств, фреймворков (Yii2, CodeIgniter, Zend, Phalcon, Bun) и т. п.
Анализ требований
Все начинается с анализа требований и пожеланий к итоговой системе.
Фреймворк должен:
- позволять быстро создать сайт «с нуля»
- иметь в себе ряд уже реализованных базовых технических решений и инструментов
- содержать разделенный frontend и backend
- отвечать современным требования по коду, технологиям, применяемым техническим решениям и т.п.
- содержать уже в базовой комплектации демо-приложение, на основе которого можно вести свою разработку
- быть модульным и расширяемым
- иметь понятную документацию, техподдержку (в идеале — сообщество)
Применяемые технологии
Список таких решений напрямую зависит от того, о чём знаете и что применяете в своей реальной практике. Т.е. подходим к необходимости постоянного мониторинга новинок и изменений в сфере ИТ.
Практики и технологии:
- Язык программирования: PHP >= 5.5.* или PHP >= 7.*
- База данных: MySql >=5.4.*
- Менеджер пакетов: Composer
- Автозагрузка: PSR-4, кодирование: PSR-2, логирование: PSR-3
- Используем функционал языка: неймспейсы, трейты, магические функции и т.п.
- Применяем паттерны при построении структуры классов, реализации задач
- Верстаем html-код с использованием Twitter Bootstrap
- Пользуемся лучшими подходами в программировании: SOLID, DRY, KISS, YAGNI
- Покрываем код PhpUnit-тестами (тестирование работы базовых классов приложения)
- покрываем функционал Codeception-тестами (приемочное тестирование)
Структура папок
Приведу структуру файлов и папок в фреймворке (также можно посмотреть код на GitHub):
Код
В приложении есть одна единственная точка входа. Привожу код файла index.php из корневой публичной папки веб-сервера.
session_start();
$loader = require(__DIR__ . '/../../vendor/autoload.php');
$loader->addPsr4('framework\\', __DIR__ . '/../../system/');
$loader->addPsr4('frontend\\', __DIR__ . '/../');
$loader->addPsr4('common\\', __DIR__ . '/../../common/');
$config = array_merge(
require(__DIR__ . '/../config/main.php'),
require(__DIR__ . '/../../common/config/main.php')
);
$appication = new \framework\core\Application();
$appication->run($config);
Код метода run($config) из класса \framework\core\Application(). Производится загрузка необходимых классов приложения и производится вызов соответствующего контроллера (в методе execute()).
/**
*
* @param array $config
*/
public function run($config = [])
{
$this->benchmark = new Benchmark();
$this->environment = Environment::get();
$this->config = new Registry($config);
$this->response = new Response();
$this->request = Request::getInstance();
$this->assets = new Asset($this->config->assets);
$this->setParams();
$this->router = new Router($this->config->routes);
$this->execute();
}
Код метода execute() из класса \framework\core\Application(). Нужный контроллер на данном этапе уже выбран, производим инициализацию этого контроллера, обработку хеадеров, вывод контента. В случае ошибки — бросаем 404 Not Found.
public function execute()
{
$controllerName = $this->router->getControllerName();
try {
$controllerClass = '\\' . $this->config->name . '\controllers\\' . $controllerName . 'Controller';
if (class_exists($controllerClass)) {
$controller = new $controllerClass;
if ($controller instanceof Controller) {
$controller->setApplication($this)->run();
}
} else {
throw new CoreException('Controller "' . $controllerName . '" not exists: ' . Request::getInstance()->server["REQUEST_URI"]);
}
} catch (CoreException $e) {
$e->logError();
$this->response->setHeader("HTTP/1.1 404 Not Found");
$this->router->error404();
$this->execute();
exit();
}
foreach ($this->response->getHeaders() as $header) {
header($header);
}
echo $this->response->getContent();
}
Улучшения и планы на будущее
В качестве адаптера для коннекта к БД я использовал PDO. В ходе работы PDO мне не очень понравился — сложно отлаживать запросы, хочется комфорта использования ORM. Можно установить Eloquent ORM — это современное и готовое решение (применяется в фреймворке Laravel), да и к тому же оно хорошо документировано и может быть установлено из composer за несколько минут.
Так же думал о расширении базового функционала фреймворка: хотел добавить поддержку модулей. Т.е. чтобы можно было написать например, блог как отдельный модуль (со своими контроллерами, вьюверами, моделями и т.п.). И потом подключать этот модуль в любом месте приложения.
Можно расширять и базовый «джентельменский» набор классов в ядре, усложнять систему логирования, обработки ошибок, конфигурирования, писать полноценный демо-сайт со всем функционалом и т.д.
Заключение
Буду рад услышать критику кода, архитектуры, изначальных требований и прочего. Комментарии буду активно читать, постараюсь ответить на вопросы.
Так же хотелось бы реализовать какой-либо проект на базе данного фреймворка. Так сказать опробовать инструмент в работе. Понятно, что поиск заказчиков — это совсем не к данному разделу, но хотел бы услышать, можно ли на данном решении стартовать реальный проект? Популярные фреймворки «из коробки» дают функционал в 50-100 раз качественнее и масштабнее, конкурировать с ними сложно.
> Код на GitHub
Комментарии (71)
impwx
28.02.2017 13:58+2По ходу эксплуатации различных современных фреймворков я понял, что недостаточно понимаю, как все устроено внутри, ..., я выбрал создание собственного проекта.
Чукча не читатель, чукча писатель!
Презентацию очередного фреймворка лучше всего со сравнения с существующими. Так читатель может понять, на какую нишу этот фреймворк претендует. Для этого нужно хорошо разбираться в существующих решениях. Если же вы начали писать свой ради того, чтобы не изучать чужое, вас ждет сизифов путь.
oxidmod
28.02.2017 14:00$loader->addPsr4('framework\\', __DIR__. '/../../system/');
$loader->addPsr4('frontend\\', __DIR__. '/../');
$loader->addPsr4('common\\', __DIR__. '/../../common/');
это же можно вынести прямо в composer.jsonvolmir
28.02.2017 18:03А как?
Я пробовал отключать этот код — но тогда ничего не работает.
Добавлял такие конструкции:
"psr-4": {
"Frm\\": "/system/",
"App\\": "/application/"
}
Но не дошел до работающей конструкции.
:(
GeMir
28.02.2017 14:13+2«Хотел бы услышать, можно ли на данном решении стартовать реальный проект?» — я правильно понимаю, что вы что-то создали, но не понимая насколько оно жизнеспособно просите оценить со стороны?
volmir
28.02.2017 18:30-2После какого-то этапа разработки фреймворка его можно применять «в жизни», на реальных проектах.
Мне кажется, что для текущей конструкции этот этап уже наступил — т.е. фукнциоанл перевалил за какую-то граничную точку, когда это уже не учебный проект, а нечто самостоятельное и жизнеспособное.
Если поэксплуатировать этот фреймворк на продакшне в течении 6-9 месяцев (с постоянной доработкой и сопровождением реального проекта) — то после этого срока можно будет сделать програмный редизайн и рефакторинг кода ядра и всего приложения в целом.
Может получиться следующий релиз, качественно отличающийся в лучшую сторону от предыдущего, с более богатым функционалом, протестированный и т.п.
Вот для этого и пишу о поиске реальных проектов.Fesor
01.03.2017 09:11-1Нет, не надо применять это "на реальных проектах", пожалуйста. Миру уже хватает проектов на no-name фреймворках которые нереально суппортить.
Суть использования "чужих решений" раскрывается в том, что если у решения есть комьюнити то стоимость поддержки этого решения распределяется по всему комьюнити. А когда это самое комьюнити состоит из одного человека — дешевле будет взять готовые компоненты и склепать свой клей вокруг.
volmir
01.03.2017 11:36+1Я вот тоже к тому же прихожу: ОРМ хочется взять стороннюю, а так же и шаблонизатор, мейлер…
vlreshet
28.02.2017 14:38Можно немножко критики?
— почему неймспейсы начинаются с маленьких букв?
— вашей целью было использовать всю мощь языка — а везде конкатенации вместо двойных кавычек
— что за прикол с двумя конфигами которым нужно ещё и array_merge делать? как минимум странно
— что за прикол с путями в стиле "/../../system/"? почему нет константы корневого пути проекта вместо этого?
— зачем у вас есть свой класс исключений типа CoreException, если вы строите строку-сообщение вручную, вместо передачи грубо говоря реквеста и всё? зачем новый класс если он судя по всему ничего не делает?
— Не вопрос а просто критика — местами есть очень сомнительный код, типа вот такого:
foreach ($this->response->getHeaders() as $header) { header($header); }
P.S. Всё выше — чисто моё ИМХО, на истину в последней инстанции не претендуюgoodnickoff
28.02.2017 18:48Полагаю, что пространства имен с маленькой буквы навеяны Yii2. Не вижу ничего плохого в этом. Стандарт PSR-4 об этом умалчивает, поэтому это дело вкуса как их обзывать.
То что касается
CoreException
вовсе странная претензия. По вашему расширять класс исключений нужно только для того чтобы добавить новый функционал или переопределить конструктор?ellrion
28.02.2017 18:59в yii то понятно это так сложилось, это их стиль и всё такое, но все пакеты нынче используют UpperCamelCase. Так зачем следовать за таким редким стандартом. Да и смотрится потом при использовании сторонних пакетов это стремно.
vlreshet
28.02.2017 21:25Да, я считаю что нет смысла расширять класс исключений только ради нового названия класса. Зачем плодить новую сущность которая отличается от встроенной в язык только названием?
BoShurik
28.02.2017 21:50Скажите это PSR
https://github.com/php-fig/log/blob/master/Psr/Log/InvalidArgumentException.php
Очень удобно ловить исключения, относящиеся к конкретному модулю/библиотеке/etc, а не все подряд
volmir
01.03.2017 11:29Присоединяюсь, к пред. высказыванию.
Как на мой взгляд, расширяя базовый класс исключений, удобно писать сои обработчики на исключения и строить сою логику действий в этом случае.
goodnickoff
28.02.2017 22:08Этим вы подтвердили мои догадки о том, что понятия не имеете как работать с исключениями.
volmir
01.03.2017 12:06что за прикол с двумя конфигами которым нужно ещё и array_merge делать?
Это сделано для того, чтобы указывать уникальные настройки (например коннект к БД) только в одном месте, а потом — объединять настройки из разных файлов для запуска текущей конфигурации приложения.
Например: у нас есть фронтэнд, бекэнд и консоль. Коннект к БД хранится в одном файле.
В каждом приложении мы подключаем конфиг самого приложения и конфиг с настройками коннекта к БД.
Получается просто и универсально (ка на мой взгляд).oxidmod
01.03.2017 12:13а если я с cli хочу конектится к другой базе?
volmir
01.03.2017 12:53Если требуется из CLI коннектиться к другой базе — то в конфиге CLI прописывается эта база.
В общем конфиге коннекта к этой базе нет, конфиги разделены.
Есть очень много способов решить указанную задачу. Я привел лишь один из них.oxidmod
01.03.2017 13:04ну у меня в основном конфиге конект к основной базе, а в кли к другой. мы смержили конфиги и куда я приконекчусь?
volmir
01.03.2017 13:10Чтобы разрешить такие коллизии нужно:
1) Иметь в фреймвопке возможность задавать неогр. количество конфигов к БД.
2) Иметь возможность передавать в скрипт коннекта к БД один из выбранных конфигов.
Тогда будет универсальность и многовариантность применения.oxidmod
01.03.2017 13:17Ну тоесть вы понимаете, что такой бездумный мердж может вызывать неочевидные проблемы
ellrion
28.02.2017 15:31+4Не хочется хейтить или негатив лить. Но простите, я не очень понимаю зачем вы это выложили. Нет оно конечно даже боли ваш код не вызвал. Для себя в академических целях, прекрасное занятие.
Дам пару советов что стоило бы поменять: про неймспейсы вам уже сказали, ту да же и автолоад.
Еще очень просится разделить код самого ядра с его тестами и непосредственно приложения на его основе. Вынесите его в отдельный пакет.
Управление ассетами в контролере и конфигах бекенда как то неуклюже, не их это дело.
Php как шаблонизатор если используете то имхо лучше использовать
<?= ... ?>
вместо<?php echo ...; ?>
и для управляющих конструкций вариант синтаксиса с:
. Т. е.
<?php foreach(): ?> ... <?php endforeach ?>
vlreshet
28.02.2017 16:39-1Я не автор, но с вами немножко поспорю :) Шорт-теги (<?=) — зло, и использовать их нежелательно. А учитывая то что надо бы экранировать вывод в шаблонах (во избежание XSS) — так лучше ещё и нагородить свою функцию вместо echo). А синтаксис с : — оно то вроде как для вёрстки и задумано, но есть большой минус — редакторы кода не находят такие логические блоки, в отличие от блоков с классическими фигурными скобками.
Delphinum
28.02.2017 16:45Шорт-теги (<?=) — зло, и использовать их нежелательно
Потому что потому?
так лучше ещё и нагородить свою функцию вместо echo
<?= escape($data) ?>
Не вариант?
ellrion
28.02.2017 17:03+1Функцию экранирования это само собой. Т. е. в идеале нужен нормальный шаблонизатор. Но если мы используем просто php шаблон то делаем функцию
/** * @param mixed $value * @return string */ function e($value) { return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8', false); }
и используем её:
<?= e($some) ?>
Шорт-теги (<?=) — зло
У вас устаревшая информация. Во первых шорттеги считались злом потому что могут быть не включены. Но с PHP 5.4.0 именно
<?=
не считается шорттегом и директива конфигурации на него не влияет.
редакторы кода не находят такие логические блоки
Я не знаю чем вы пользуетесь. Мой шторм справляется. Но смысл что эти теги делают более читаемым код и без сворачивания
vlreshet
28.02.2017 17:39Хмм. По поводу шорт-тегов — признаю, как-то пропустил этот момент когда они перестали быть злом (хотя уже давно на PHP7 мигрировал).
А вот по поводу шторма — только что пробовал, и мой шторм не воспринимает endif и endforeach как логические блоки, и следовательно не работают хоткеи перехода к логической скобке. Мы у себя на проекте пробовали использовать : синтаксис — но в итоге вернулись на классику, не понравилось. Но тут уже вкусовщина, спорить не буду.Xu4
28.02.2017 17:56По поводу шорт-тегов — признаю, как-то пропустил этот момент когда они перестали быть злом
Мне кажется вы не до конца правильно понимаете ситуацию. Шорт-теги остались злом. Но конкретно тег<?=
к этому злу не имеет отношения, так как конфигурационная опция, связанная с шорт-тегами, на его работоспособность не влияет после версии 5.4.
volmir
28.02.2017 23:45Еще очень просится разделить код самого ядра с его тестами и непосредственно приложения на его основе. Вынесите его в отдельный пакет.
Ага, пришел так же к этому (вообще узнал о такой возможности недавно).
лучше использовать <?=… ?> вместо <?php echo ...; ?>
Да, буду переучиваться себя на такой стиль.
Одно время были споры по поводу коротких тегов.
Рад что сообщество вернулось к <?=… ?>
Alex_T666
28.02.2017 17:49А сессию вы используете всегда при любом запросе?
volmir
28.02.2017 18:16Получается, что всегда.
«Узких» мест много.
На своем опыте я понял, что чем больше пишешь — тем больше разрастается код, тем больше надо думать об архитектуре и общей схеме вызова компонентов.
Список «К исправлению» увеличивается и увеличивается, а для каждого исправления — надо много читать и думать об оптимальных решениях.
И тесты писать и прогонять их после каждого изменения в ядре.
Положительным моментом всей этой затеи является то, что квалификация и опыт программирования растет так же с исправлением каждой ошибки. Но цена этого опыта — перебор горы пустой породы в поисках того алмаза.
Хотя другого пути нет, никто за человека это не сделает, кроме него самого.
bioroot
28.02.2017 19:11Говорил Чехов нехорошее, про людей, которые не умеют скрывать свои плохие повести… Велосипедить всегда хорошо, но для себя.
По коду. А что будет, если нам подсунули не инстанс контроллера?
if ($controller instanceof Controller) { $controller->setApplication($this)->run(); }
Молча проглотим? Хотя если класс не существует, то кидаем исключение. Не аккуратненько…
volmir
01.03.2017 13:15Спасибо всем за критику, замечания и предложения.
Со «своей колокольни» не все видно (или видно недалеко), а так все накидали комментариев по чуть-чуть — понятно что с этим всем делать и что есть в сухом остатке на данный момент.
sspat
01.03.2017 13:33Похвально желание учиться, поэтому вместо критики лучше добавлю свои пару копеек к процессу обучения.
— Хранить пароли в md5 не стоит.
http://php.net/manual/ru/function.password-hash.php
https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet
— Модели уж совсем примитивные, нужно как минимум абстрагироваться от работы с PDO напрямую. Вообще я бы не рекомендовал учиться на примере Active Record, ничему хорошему не научит. Лучше возьмите готовый слой абстракции построения запросов, например Doctrine DBAL (там особо нечему учиться, но много рутины) и стройте поверх него свою ORM.
— Сила фреймворков в расширяемости и модульности, у вас же все компоненты очень тесно связаны, компонент авторизации например может работать только с вашей моделью User. На весь фреймворк у вас один интерфейс.
— Как дальнейшее направление для обучения — написать свой DI контейнер и диспетчер событий.
Skull
01.03.2017 23:21База данных: MySql >=5.4.*
Это что за зверь такой? После версии 5.1 сразу же идет 5.5
nepster-web
06.03.2017 15:10Почему почти все пытаются влепить AR в свой велосипед?
Fesor
06.03.2017 18:39потому что это самый простой способ сделать взаимодействие с БД. Даже DAO сложнее потому что думать больше надо. А тут — есть табличка в базе и она 1:1 мэпится на объектик. Ну и еще — многие кроме AR ничего и не юзали.
nepster-web
06.03.2017 18:43Я тоже практически ничего не использовал кроме AR, но он практически всегда приносит жесткий дискомфорт, как только приложения выходит за рамки блога или сайта визитки.
Плюс у AR есть приличное кол-во недостатков, которые уже в моем случае превосходят его преимущества. Поэтому нужно как-то людей толкать в сторону сущностей, репозиториев и дата-маперов.ellrion
06.03.2017 18:52Т. е. вы "практически ничего не использовал кроме AR" и при этом уверены что где то там солнце ярче?
nepster-web
06.03.2017 19:02Ключевое слово практически. Мое объяснение будет заключатся скорее всего в минусах AR связанных с магией и большой связанность. По мимо этого AR внес весьма солидную путаницу в разработку, а именно теперь большинство разработчиков, а в частности это новички, понимают примерно так:
модель == один класс == active record (я тоже так думал еще 2 года назад).
На примере Eloquent ORM: так есть такие понятия как аксессоры, мутаторы, скопы и тп. Работая со всеми этими терминами в контексте одного класса «модель» становится не много неповоротливой. Дальше более продвинутые новички, которые почитали про «MVC», и узнали примерно такую цитату "… Контроллеры должны быть тонкими, а логика должна быть в модели...", придерживаясь вышеупомянутого сравнения начинают логику писать в моделях (а в 99% это 1 класс).
В результате появляется весьма не очень хорошая практика и очень много не очень хороший статей и видео по теме.
Что касается меня, я не использовал скажем доктрину вне учебных целей, поэтому не могу топнуть ногой и сказать, что я все попробовал на достаточно уровне. Однако сейчас я пишу модульную архитектуру где все-же есть AR, однако он фигурирует только в реализации репозиториев, при этом, что очень важно, из репозиториев возвращаются сущности.
А так все получилось, потому, что очень сложно объяснить новичку, который 10 лет пишет на AR, почему нужно создать еще 5 классов, а не один AR.
Fesor
06.03.2017 18:56но он практически всегда приносит жесткий дискомфорт
Ну можете перейти на уровень выше — row data gateway. Это когда у вас над каждой "моделькой" или графом "моделек" представляющих именно модель данных, есть объекта модель которая представляет корень агрегата например.
Можно по разному готовить работу с базой данных. И вы редко ограничены каким-то одним подходом. Причем даже в одном проекте могут быть ситуации при которых надо комбинировать подходы.
Fesor
06.03.2017 18:58-1Поэтому нужно как-то людей толкать в сторону сущностей, репозиториев и дата-маперов.
или DAO.
nepster-web
06.03.2017 19:08я сейчас сделал не много по другому.
— сущность
— репозиторий
— для некоторых вещей View Model
А вот реализация уже использует AR. И то очень аккуратно, так как строить запросы в нем очень легко. А с помощью View Model иногда можно возвращать кастомные штуки, чтобы не плодить частичные объекты (http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/partial-objects.html).
В теории я тестировал, реализацию можно подменить без проблем, так как на выходе единый формат сущности или view modelFesor
06.03.2017 20:02Кто у вас отвечает за сохранение сущности (кто дергает save)? Как разруливаете связи? Что у вас является сущностью? Выделяете ли корень агрегата сущностей?
чтобы не плодить частичные объекты
partial objects из доктрины слегка бесполезная штука. Мне больше импонируют выборки с
select new SomeDTO(u.id, u.name)...
;
Тут проблема в другом. Вам действительно все это надо? Особенно например репозитории (я так понимаю что у вас нет UoW). Ну и в целом посмотрите в сторону row data gateway, я подозреваю что вы что-то подобное и сделали только сложнее.
nepster-web
07.03.2017 12:02Кто у вас отвечает за сохранение сущности (кто дергает save)?
За сохранение отвечает тот-же репозитроий. Хоть и во круг этого ходят холивары, однако репозиторий это абстракция над хранилищем, поэтому думаю, что методу «сохранить в хранилище» место в репозитории, ну и пока на практике не узнал обратного.
Как разруливаете связи?
AR. Тоесть репозитории и сущности это такая себе абстракция над AR в моем случае.
Что у вас является сущностью?
Взял идею из Symfony. Тоесть у меня есть несколько понятий DTO — класс только с геттерами, который я гоняю между модулями и Сущности, которые в основном находятся в главном модуле Application, и являются практически идентичными как в Symfony.
«я так понимаю что у вас нет UoW»
Да, UoW пока нет, мы только начали пилить проект и подобные штуки я взял на себя смелость внести на этап оптимизации.
Тут проблема в другом. Вам действительно все это надо?
Как показывает практика, если Вы за рамками «бложика» или «сайта-визитки» и требуется постоянно допиливать и обновлять функционал, то подобные вещи весьма кстати.Fesor
07.03.2017 12:16Хоть и во круг этого ходят холивары
да на самом деле холивары высосаны из пальца. Если у вас есть штука у которой есть метод
save
и вы используете его как для добавления новой сущности так и для сохранения изменений в уже имеющейся — у вас не очень то и репозиторий, больше походит на table gateway.
Взял идею из Symfony.
являются практически идентичными как в Symfony.Тут подробнее. У вас там геттеры/сеттеры или полноценная объектая модель, с логикой в сущностях и тд.
Просто ребята из команды доктрины грустят когда их ORM юзают так как показано в документации симфони. Слишком сложная штука для того чтобы использовать тупо как DTO между приложением и базой. Ну и доктрина не является частью симфони.
смелость внести на этап оптимизации.
UoW нужен не для оптимизации, а для того что бы обозначить границу бизнес транзакции и избавиться от необходимости вручную отслеживать изменения всего графа сущностей составляющего агрегат.
Если вы это уже разруливаете руками, я не вижу смысла уже делать UoW. Но тогда мне было бы интересно узнать как вы это разруливаете.
то подобные вещи весьма кстати.
Ну для того что бы объективно оценить надо все же видеть код, просто как по мне у вас слишком уж резкий переход от простого active record к DDD-ной структуре. Да и AR не мешает делать DDD, просто будет больше похоже на row data gateway нежели обычный ar.
nepster-web
07.03.2017 12:36у вас не очень то и репозиторий, больше походит на table gateway.
Ну тут спорный вопрос, так как данные одной сущности могут быть раскинуты на несколько таблиц. К примеру есть сущность Product, у него есть поля name, description и тп. и данные этих полей могут быть в таблице скажем product_translations (да я пока не решился отойти от этого подхода в пользу json).
Тут подробнее. У вас там геттеры/сеттеры или полноценная объектая модель, с логикой в сущностях и тд.
Видимо не натыкался я на примеры с логикой, но в моем понятии сущность — это класс с геттерами и сеттерами, который ничего не делает, кроме как позволяет предоставить контейнер для данных сущности. Как-то я уже натыкался на весьма серьезную проблему (https://habrahabr.ru/post/316836/) и сущности рассматриваю как обертку над данными и единый формат, который можно гонять по проекту, ну скажем если подменить хранилище, то оперируя сущностями приложение не должно заменить, что что-то пошло там поменялось.
Вообще логика — это понятие скольское, так как сегодня это одно, завтра это другое, в том плане, что у меня были частые ситуации, когда нужно было быстро что-то менять. Например попробовали 1 схему, «не зашла», пробуем другую схему (имеется ввиду работа приложения под бизнес). Поэтому теперь я стараюсь очень аккуратно прятать все за интерфейсами, как можно больше разделать и как можно меньше связывать.
UoW нужен не для оптимизации
Походу его основная задача, это (с) "… Реализация паттерна Unit of Work следит за всеми действиями приложения, которые могут изменить БД в рамках одного бизнес-действия. Когда бизнес-действие завершается, Unit of Work выявляет все изменения и вносит их в БД. ..."
у вас слишком уж резкий переход от простого active record к DDD-ной структуре
Много обжигался. Однако не совсем DDD у меня, скорее просто модульная архитектура и стараюсь следовать SOLID. Сейчас мы пилим API, и возможно версия 2 будет разбита на микросервисы и некоторые даже начнут жить по DDD. Однако сейчас просто нет финансовой возможности позволить «жирных» специалистов. Клиент скорее наймет 5 человек за $5000, чем одного. Поэтому как минимум я весь опыт черпаю из неудачных решений проходя через собственные ошибки.
Fesor
07.03.2017 14:10-1Ну тут спорный вопрос, так как данные одной сущности могут быть раскинуты на несколько таблиц.
А это уже спрятано за уровень абстракции, так что не столь важно.
но в моем понятии сущность — это класс с геттерами и сеттерами
Рекомендую почитать про такой термин как "анемичная модель". Если коротко — это такая модель которая налагает ту же сложность что и обычная, но не приносит профита поскольку ничего не делает.
А с примерами туго, согласен.
просто модульная архитектура и стараюсь следовать SOLID
Если с тестами и именно юнит тестами, тогда все хорошо)
nepster-web
06.03.2017 19:10Что касается темы, то мне точно не хватает статей на PHP про:
— DDD
— Entity / VO / DTO
— Repository
и тп.
Ну и Вы про всякие гексагональные архитектуры весьма редко пишите.Fesor
06.03.2017 19:59-1точно не хватает статей на PHP про:
Начните с синей книги Эрика Эванса. Там это все тесть. И вы забыли про агрегаты сущностей, bounded context и т.д.
Ну и Вы про всякие гексагональные архитектуры весьма редко пишите.
Я вообще редко пишу… Да и гексагональная архитектура — это один из вариантов построения приложений. Нужно понимать какие характеристики дает та или иная архитектура и думать надо ли вам это или нет.
eshimischi
Вы изобрели лекарство от рака или сделали мир лучше благодаря своей «разработке»? Не поймите неправильно, мы все любим изобретать новые и новые инструменты, чтобы делать одни и те же простые вещи, вопрос для кого-чего? Если вы используете свой проект для личных разработок, то тем самым решаете поставленные перед собой задачи, конкурировать с другими не нужно, нужно использовать то что есть.
FedyaShlyapkin
ну от чего же. начинающим будет интересно. PHP не по фреймворкам изучают.
lair
И это написано в защиту статьи "простой современный MVC-фреймворк"?
FedyaShlyapkin
да. и в чем тут проблема? Неплохо понимать как писать фреймворк на PHP, а не как я крут зная фреймворк но не зная как все устроено.
lair
Зачем? Есть, знаете ли, маленькая разница между "я понимаю, как устроено" и "я знаю, как написать".
volmir
Я писал весь код исключительно для повышения своей квалификации как программиста.
Так как просто читать «о программировании» — это не то.
Надо ручками, ручками — кодить, думать, анализировать.
Fesor
фреймворки — это не то на чем поднимается скил.
Приведу пример:
А вот если бы вместо этого вы бы просто на PHP написали логику какую сложную, поработали со структурами данных, написали бы e-commerce решение (только логика, ни баз данных ни прочего) с какими-нибудь сложными скидками и купонами, вот там есть где покачать скил. Особенно если при "качании скила" наложить кучу ограничений на свой код (аля никаких геттеров, ну или взять просто "объектную гимнастику"). Вот эти ограничения вас думать заставят. Ну или попробовали бы по TDD работать (phpspec желательно, ну или хотя бы phpunit, а не codeception который позволяет тестить любой код) отбросив все свои старые привычки. Это тоже будет "чем-то новым" для вас.
А так… просто еще один фреймворк который не должен увидеть продакшена.
volmir
Спасибо за идеи куда «расти», как специалист. Я тоже подумывал о чем-то подобном.
Хочется интегрировать программную составляющую (что писать: структуры, сложная логика, объекты и т.п.) и общественно-полезную составляющую (для кого для чего писать, суть самой разработки, её полезность для людей).
Fesor
С этим сложно, это надо думать и смотреть чего не хватает комьюнити. Было бы круто иметь такой вот список "хотелок" с возможностью пообсуждать имплементацию.
Посмотрите чего не хватает инфраструктуре PHP. Я бы например предложил бы вам сделать солюшен вроде attache, и даже звездочку бы поставил.
Еще как вариант — leaderboard для PHP, потом возможность истории впилить.
Еще — можно попробовать попилить фичи для популярных библиотек/фреймворков.