LINUX.ORG.RU

Архитектура веб-приложения


0

1

Добрый вечер, люди.

Хотел спросить у вас как бы вы спроектировали модели (бд), если бы у вас были следующие сущности:

  • Клиент
  • Агент
  • Курьер
  • Перевозчик
  • Оператор
  • Получатель

У них у всех общее:

  • Авторизация

Т.е. они все в каком-то смысле пользователи системы. Но у каждой из этой сущности свои свойства и методы. Плюс ко всему агент, например, принадлежит другой сущности - агенству.

Хотел бы услышать, как бы вы спроектировали это?

★★★

* Пользователь
* Клиент (Пользователь)
* Агент (Пользователь)

...

trashymichael ★★★ ()

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

drakmail ★★★★ ()
Ответ на: комментарий от drakmail

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

Я точно так же думал. Но symfony 2 не позволяет построить простейшую фабрику в сущностях (entity). И все комментарии по этому вопросу следующие: «Может тебе стоит пересмотреть архитектуру?».

VirRaa ★★★ ()
Ответ на: комментарий от trashymichael

зачем фабрика?

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

VirRaa ★★★ ()
Ответ на: комментарий от trashymichael

это неправильно, пусть лучше другие сущности ее агрегируют

Во второй симфони SecuredBundle (пакет который работает с авторизацией и разграничением прав) не может работать с несколькими сущностями.

VirRaa ★★★ ()
Ответ на: комментарий от VirRaa

должно работать, не знаю как там в симфониях, но тебе нужна просто связь в моделях

class User:

def some_cool_stuff

...

class Agent(User):

...

agent.user.some_cool_stuff

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

trashymichael ★★★ ()
Ответ на: комментарий от VirRaa

Я точно так же думал. Но symfony 2 не позволяет построить простейшую фабрику в сущностях (entity). И все комментарии по этому вопросу следующие: «Может тебе стоит пересмотреть архитектуру?».

Может стоит использовать SQL, а не какие-то костыли?

xpahos ★★★★★ ()

сущность «Роль», по ролям права доступа. каждому из них какую то роль назначать. потому что еще будет админ, гости и проч.

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

VladimirMalyk ★★★★★ ()
Ответ на: комментарий от VladimirMalyk

Это не совсем роли, это разные сущности. Например из всех сущностей только одна может иметь свойство «Имя + Фамилия», другим это не надо. И т.п.

VirRaa ★★★ ()
Ответ на: комментарий от VirRaa

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

VladimirMalyk ★★★★★ ()
Ответ на: комментарий от GateKeeper

я не знаю есть ли для php поделок дебагер для просмотра SQL запросов сделанных ORM, но если такой есть, то посмотри что твоя ORM делатет.

xpahos ★★★★★ ()
Ответ на: комментарий от xpahos

Генерит SQL. Я тебе это гарантирую. Даже в дебаггер не полезу. Одно но:

$user = ORM::factory('user', 5);
if ( ! $user->loaded()) die('No this sh!t in DB found. Now piss off');
$user->password = 'DerParol';
$user->save();
vs.
/*
предварительно куча шлака по установке соединения, проверке на установку соединения, установке параметров соединения (кодировки, прочий мусор), етц. Его много, просто лень писать
*/

$query = "SELECT id from users where id = ?";
$st = $conn->prepare($query);
if ( ! $st ) die ($conn->lastError());
$st->bindParam(0, 5);
$st->exec();
if (/* блиааа, еще иф, уже не смешно.. проверяем выполнился ли запрос */) {}
// далее проверяем, сколько вернулось строк (больше 0 - ок, нет - вываливаемся, как в примере выше
// сбрасываем $st, освобождаем буферы сервера и локальные, чо тут... ах да
$query = "UPDATE users set password = ?";
$st = $conn->prepare($query);
// опять проверяем, мало ли, накосячили с запросом
$st->bindParam(0, megaPasswordHashingFunction_anotherImplementation_wtf_zomg_nomnomnon('derParol'));
// и по идее вообще-то каждый bindParam надо тоже проверить, а то false вернет и пушнойзверь
$st->exec();
//и опять тыща проверок и прочего....

Какой вариант ты выбрал для работы с моделями объектов? При этом, заметь, с ORM у меня в базу пошел уже хеш, а не то, что пользователь ввел. Это пример на пыхе. Почти аналогично было бы для любого ЯП в вараинтах с и без ORM. Для конкретной поделки на пыхне есть косяк: в Kohana не осилили prepare statement, поэтому до сих пор тр***тся с quote(), но это мелочи. На взгляд пробить с наскоку по теме injection не удалось, а т.к. проект чисто внутренний, остальное уже не так важно. Тем более, что будет переписываться на жабке.

И еще одно: конфиг доступа к базе намеренно пропустил, т.к. будет одинаков для обоих подходов.

GateKeeper ★★ ()
Ответ на: комментарий от GateKeeper

Какой вариант ты выбрал для работы с моделями объектов?

Я не использую модели.

При этом, заметь, с ORM у меня в базу пошел уже хеш, а не то, что пользователь ввел.

ну может в php все так плохо с экранированием.

Давай лучше другой пример.

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

Что-то вроде: Trips id - int title - char 255 ....

Text id - int title - char 255 trip - foreign key trip.id stat - foreign key stats.id ....

Stats id - int week_views - int last_access - date ....

Нужно выбрать все отчеты из поездки с id = 5, при этом нужно выбрать все, которые были просмотрены за сегоднешний день и отсортировать по количеству просмотров за неделю.

Сделаешь с помощью ORM?

xpahos ★★★★★ ()
Ответ на: комментарий от xpahos

Опять же, пока только на примере Kohana ORM (аналогичное есть и в алхимии и, верю, в Hibernate - его только начинаю ковырять):

$trip = ORM::factory('trip', 5); //можно не делать, а просто этот кусок зацепить паровозом перед следующим, сама поездка (Trips) при этом у тебя потеряется, ну ты понял...
$reports = $trip->texts->with('stats')->where('stats:last_access', '>=', $today)->order_by('stats:week_views')->find_all();
// $reports теперь содержит iterable, годный для foreach
// В алхимии подобный подход, только не надо делать .all() в конце, но тоже получим iterable

GateKeeper ★★ ()
Ответ на: комментарий от GateKeeper

А теперь давай посмотрим сколько было запросов к БД ? :)

Я это все могу написать на PL/SQL и дальше без изненения кода менять структуру БД, без всяких моделей итд.

xpahos ★★★★★ ()
Ответ на: комментарий от xpahos

Я это все могу написать на PL/SQL и дальше без изненения кода менять структуру БД, без всяких моделей итд.

Да Вам, батенька, нужно книжки умные почитать, про проектирование, про ООП и паттерны.

VirRaa ★★★ ()
Ответ на: комментарий от VirRaa

Да Вам, батенька, нужно книжки умные почитать, про проектирование, про ООП и паттерны.

И что мне даст перечитывание книжек по ООП? Ну вот читал я в свое время, делал тесты, вроде как все круто, и модели и контроллеры и вьювы, все отдельно. А на практике оказалось, что ORM не правильно делает запросы, индексов вообще нет, да и не совсем логично ORM делает Foreign Key. Еще куча мусора осталась от всяких content_type. Где там магическая книжка, которую все читают и вдруг понимают, что ООП их спасет?

xpahos ★★★★★ ()
Ответ на: комментарий от xpahos

У меня - 2, если тебе не нужен сам $trip - один (немножко поменять строку). А у тебя сколько получилось запросов?

GateKeeper ★★ ()
Ответ на: комментарий от xpahos

И это, я и без PL/SQL могу просто вьюху создать, объявить ее моделью в ORM и дергать вот так:

$reports = ORM::factory('todaysortedreports')->where('id', '=', 5)->find_all();
И тоже один запрос. Что сказать-то хотел?

GateKeeper ★★ ()
Ответ на: комментарий от GateKeeper

И это, я и без PL/SQL могу просто вьюху создать, объявить ее моделью в ORM и дергать вот так:

view объединить с моделью? :) Ну ладно, говнокод опустим. Отвязаться от структуры БД ты можешь?

xpahos ★★★★★ ()
Ответ на: комментарий от xpahos

Что значит, «отвязаться от структуры БД»? У меня в ORM вообще не объявляются поля таблицы, это делают потроха ORM 1 раз для каждой модели при попытке создать объект этой модели (factory как раз дергает соответствующий SELECT по системным таблицам, дергает оттуда поля и типы, кэширует и затем я могу хоть тыщу раз эту модель дернуть). Естественно, если я скажу $trip->ids (и такой колонки в базе не окажется), меня лютым эксепшном пошлет в... далеко.

А что плохого в том, чтобы вьюху объявить моделью? Ну, если мне, например, только на «посмотреть», это очень плохо? Подводные камни? Неизбежная кара? Вечность в аду?

GateKeeper ★★ ()
Ответ на: комментарий от xpahos

Можно и в 1 уложиться, с выборкой из всех таблиц, и тоже совсем-совсем немного переделать ту длинную строку (а ту, что с $trip = ... выкинуть совсем). И?

Только заметь, у меня chained object proxy, а тебе каждый раз руки об SQL ломать. Особенно, когда запрос дико параметризован в духе «если из приложения пришел такой параметр - добавить его условием к запросу, если такой - добавить как group by, а если такой - использовать как колонку в сортировке результатов выборки». Я даже не парюсь особо, что на том конце - sqlite, мускль, постгрес, окакел, дб2, список можно продолжать... Всеми этими проволочками занимается драйвер БД лежащий под ORM. Он пишется 1 раз на века.

Ты не на те вещи наезжаешь, главная проблема ORM: производительность. Hardcoded queries производительней, конечно же, но вот по понятности кода и скорости разработки эти hardcoded queries пристраиваются сначала в дупу к ORM, а потом и вовсе теряются в пыли.

А вот ты с окакела на ДБ2 переедешь (ну, внезапно, вдруг!), будешь половину своего приложения переписывать, или как нормальные пацаны 1 строчку в конфиге подправишь?

GateKeeper ★★ ()
Ответ на: комментарий от GateKeeper

А вот ты с окакела на ДБ2 переедешь (ну, внезапно, вдруг!), будешь половину своего приложения переписывать, или как нормальные пацаны 1 строчку в конфиге подправишь?

Буду все переписывать. Но мне переезжать не нужно, уже все спланировано. Я тем же PL/SQL могу сделать шардинг и у меня не будет проблем с ростом. У меня нет лишних прослоек, они избыточны.

Только заметь, у меня chained object proxy, а тебе каждый раз руки об SQL ломать. Особенно, когда запрос дико параметризован в духе «если из приложения пришел такой параметр - добавить его условием к запросу, если такой - добавить как group by, а если такой - использовать как колонку в сортировке результатов выборки». Я даже не парюсь особо, что на том конце - sqlite, мускль, постгрес, окакел, дб2, список можно продолжать... Всеми этими проволочками занимается драйвер БД лежащий под ORM. Он пишется 1 раз на века.

Я только передаю функции параметр выбрать это и вон то, а функция уже внутри БД все это делает. Это пишется один раз и на века :)

А что плохого в том, чтобы вьюху объявить моделью? Ну, если мне, например, только на «посмотреть», это очень плохо? Подводные камни? Неизбежная кара? Вечность в аду?

Выше же товарищ вот посылает учить ООП и паттерны! Вот скажешь ему, а он тебя отправить читать про паттерны.

Суть в том, что где нет всяких ORM у нас, количество запросов очень высоко. Это не 50 тыщ пользователей, которые тыщ 200 обновят в день странички. Там ты взял сервер помощнее, нанял пхп программистов за еду - они тебе сваяли очередной выкидышь из монструозных ООП конструкций. При большой нагрузке в некоторых местах вообще используется свой бинарный способ хранения данных. Это не РСУБД, но довольно близко.

xpahos ★★★★★ ()
Ответ на: комментарий от xpahos

Я только передаю функции параметр выбрать это и вон то, а функция уже внутри БД все это делает. Это пишется один раз и на века :)

И чуть только смена структуры базы - переписывать овер9к процедур, триггеров, вьюх... Т.е. ты от структуры БД не можешь отвязаться, совсем никак.

А последний абзац вообще не распарсил.

GateKeeper ★★ ()
Ответ на: комментарий от GateKeeper

И чуть только смена структуры базы - переписывать овер9к процедур, триггеров, вьюх... Т.е. ты от структуры БД не можешь отвязаться, совсем никак.

В чем привязанность моего кода на том же Python к БД?

xpahos ★★★★★ ()
Ответ на: комментарий от GateKeeper

Внутри хранимок (но ты же говорил PL/SQL, причем тут Python?).

ты предлагаешь на PL/SQL писать полностью FCGI приложения?

xpahos ★★★★★ ()
Ответ на: комментарий от xpahos

Т.е. от портянки (нижней), что я приводил, тебе так или иначе не избавиться? В итоге костылишь с библиотеками с процедурами вида def insert_data(conn, identifier, **kwargs) которыми оборачиваешь тыщи if result.rows / if result / if etc..., либо без них? Тебе же один хрен из рутнопа надо дергать query(), проверять его выполнение, ловить исключения, не забыть при этом еще в самом начале установить соединение, выставить его параметры, а при каждом query проверять состояние соединения (ну, мало ли, вдруг сбросилось, а мы же не быдлокод пишем). Ты просто вынес логику в СУБД, ничем вообще не облегчив себе работу по управлению состоянием подключения, запроса и результатов этого запроса. Открой уже для себя алхимию, те десятые доли процента нагрузки, которые генерирует ORM, в общем потоке нагрузки от логики работы с данными (у тебя же окакел, ты его шардишь, нагрузки непосильные, да?) ты просто не заметишь. Зато рапид во всех полях.

И да, тебя я уже даже не пытаюсь убедить, это послужит уроком «наследникам»

GateKeeper ★★ ()
Ответ на: комментарий от GateKeeper

Т.е. от портянки (нижней), что я приводил, тебе так или иначе не избавиться? В итоге костылишь с библиотеками с процедурами вида def insert_data(conn, identifier, **kwargs) которыми оборачиваешь тыщи if result.rows / if result / if etc..., либо без них? Тебе же один хрен из рутнопа надо дергать query(), проверять его выполнение, ловить исключения, не забыть при этом еще в самом начале установить соединение, выставить его параметры, а при каждом query проверять состояние соединения (ну, мало ли, вдруг сбросилось, а мы же не быдлокод пишем).

есть класс, который передает параметры и возвращает JSON

Ты просто вынес логику в СУБД, ничем вообще не облегчив себе работу по управлению состоянием подключения, запроса и результатов этого запроса. Открой уже для себя алхимию, те десятые доли процента нагрузки, которые генерирует ORM, в общем потоке нагрузки от логики работы с данными (у тебя же окакел, ты его шардишь, нагрузки непосильные, да?) ты просто не заметишь. Зато рапид во всех полях.

как мне алчеми хотя бы шардить поможет?

xpahos ★★★★★ ()
Ответ на: комментарий от xpahos

как мне алчеми хотя бы шардить поможет?

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

GateKeeper ★★ ()
Ответ на: комментарий от GateKeeper

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

я то гуглил, но это опять же на уровне кода, а не на уровне БД.

xpahos ★★★★★ ()
Ответ на: комментарий от xpahos

Так, еще раз: ты спрашиваешь «как ${someLanguage} может помочь шардить БД не на уровне своего кода, а на уровне самой БД?», правильно я понимаю?

GateKeeper ★★ ()
Ответ на: комментарий от GateKeeper

Так, еще раз: ты спрашиваешь «как ${someLanguage} может помочь шардить БД не на уровне своего кода, а на уровне самой БД?», правильно я понимаю?

я спрашиваю как шардить без изменения кода приложения.

xpahos ★★★★★ ()
Ответ на: комментарий от xpahos

я спрашиваю как шардить без изменения кода приложения.

Ты так говоришь, будто код на PL/SQL не является кодом приложения.

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

Ты так говоришь, будто код на PL/SQL не является кодом приложения.

мухи отдельно, котлеты отдельно :)

xpahos ★★★★★ ()
Ответ на: комментарий от xpahos

Ок. Show me your code, т.е. показывай куски своего FCGI, которые у тебя отвечают за шардинг. Можешь анонимизировать некоторые несущественные вещи.

GateKeeper ★★ ()
Ответ на: комментарий от GateKeeper

Ок. Show me your code, т.е. показывай куски своего FCGI, которые у тебя отвечают за шардинг. Можешь анонимизировать некоторые несущественные вещи.

ты глюпый? Тебе же выше написал, что сам код на Python не имеет ни единой строчки, отвечающей за шардинг. Посмотри как у Skype это сделано, в принципе все тоже самое.

xpahos ★★★★★ ()
Ответ на: комментарий от xpahos

Ты предъявляешь к ORM (т.е. тому самому рутнопу, который у тебя FCGI делает) требования по шардингу, при этом обзываешь глюпыми тех, кто просит тебя показать, как ты делаешь это без ORM в своем FCGI сейчас?

GateKeeper ★★ ()
Ответ на: комментарий от xpahos

Архитектура веб-приложения (комментарий)

Я слишком культурен, чтобы гуглить шардинг в алхимии за тебя. Ты просил шардинг в алхимии, я сказал тебе, что есть. Ты опять уперся, что это же не на уровне БД. Тебе вообще здесь кто-нибудь говорил про Pl/python + алхимия? Тебе говорили про алхимию и прочие ORM в контексте твоего приложения, а не базы.

Ну, а, «отвечая на твой ответ», ты не шардишь. Твоя FCGI не шардит совсем. Не помогает ни одной строчкой кода шардить. Совсем. Никак. Не шардит. FCGI. Приложение. Не делает, совсем.

Так понятнее?

GateKeeper ★★ ()
Ответ на: комментарий от GateKeeper

Ну, а, «отвечая на твой ответ», ты не шардишь. Твоя FCGI не шардит совсем. Не помогает ни одной строчкой кода шардить. Совсем. Никак. Не шардит. FCGI. Приложение. Не делает, совсем.

Так понятнее?

неа

xpahos ★★★★★ ()
Ответ на: комментарий от GateKeeper

Тогда гугли()

от гугли слышу. Я уже не понимаю при чем тут PL/Python и SQLAlchemy :)

xpahos ★★★★★ ()
Ответ на: комментарий от xpahos

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

GateKeeper ★★ ()
Ответ на: комментарий от GateKeeper

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

Так при чем тут PL/Python и SQLAlchemy и вообще PL/* и шардинг? О мой юный друк - тролль.

xpahos ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.