
Sergey
23.07.2017
11:19:49
вот для такого приложения предложи вариант "потери консистентности"
кроме багов в твоем коде

Dmitry
23.07.2017
11:20:01
еще раз, у васи нужно отнять 5, у пети прибавить 5

Sergey
23.07.2017
11:20:14
$transactions->add()

Google

Sergey
23.07.2017
11:20:37
а потом по доменным ивентам строим балансы васи и пети
изи бризи
или даже веселее

Dmitry
23.07.2017
11:21:53
в inmemory есть транзакции?

Sergey
23.07.2017
11:22:02
там не нужны транзакции
у тебя однопоточное приложение, гонок быть не может, все строго последовательно
все операции со стэйтом атомарны
сча погодь
пример нарисую

Dmitry
23.07.2017
11:23:25
я тебя понял
я не понял почему ты частный случай стораджа, который в общем и не сторадж вовсе, выставляешь эталоном, тогда как все внешние стораджи оказываются исключениями с костылями вида flush :)

Sergey
23.07.2017
11:25:17
class Account
{
public function deposit(int $amount, Account $sender)
{
$sender->decreseAmount($amount);
$this->increaseAmount($amount);
$this->transactions->add(new Transaction($sender, $this, $amount));
}
private function decreseAmount(int $amount)
{
if ($this->balance < $amount) {
throw new UnsuficientBalance($this->id, $this->balance, $amount);
}
$this->balance -= $amount;
}
}

Google

Dmitry
23.07.2017
11:26:02
почему реляционные? любые

Sergey
23.07.2017
11:26:04
ты можешь взят документноориентированную базу и хранить каждый агргегат сущностей как JSON
поскольку ты каждый раз трогаешь только один агрегат - операция по итогу атомарна
но flush надо будет всеравно дернуть что бы затригерить синхронизацию
либо вешать проксю на корень агрегата которая будет сама решать что ты уже вызвал метод сущности и можно сохранять
но последнее ооочен сложно и слишком волшебно
бизнес транзакция != транзакция в базе
короч да, flush нужен для любой модели хранения где нужна синхронизация

Dmitry
23.07.2017
11:28:49
ага, но как правило очень близко

Sergey
23.07.2017
11:29:12

Dmitry
23.07.2017
11:29:16
синхронизация нужна всегда

Ivan
23.07.2017
11:29:16

Sergey
23.07.2017
11:29:33

Dmitry
23.07.2017
11:29:53
просто в случае inmemory синхронизация настолько копеечная, что не выделена отдельно
и add может работать не над сущностью, а над набором правил, ничего не мешает

Sergey
23.07.2017
11:30:17

Dmitry
23.07.2017
11:30:44

Sergey
23.07.2017
11:30:44
просто представь себе что репозиторий для любого стораджа это immemory + sync
соответсвенно для inmemory репозитория sync не нужен

Dmitry
23.07.2017
11:31:20
inmemory все же не uow?

Google

Sergey
23.07.2017
11:31:42
sync это тот самый кастыль который позволяет тебе работать с хралилищем как с inmemory репозиторием.
uow - это как раз таки sync в случае с доктринами и прочими
а inmemory репозиторий - это просто хранить ссылку на объект
считай identity map
да, вот identity map это вполне себе часть inmemory repository так как нам нельзя допустить "клонов" сущностей

Ivan
23.07.2017
11:33:16

Sergey
23.07.2017
11:33:30
хотя.... я чет не могу придумать как там могут быть клоны... так что хз
> группа логически объединённых последовательных операций по работе с данными, обрабатываемая или отменяемая целиком.

Dmitry
23.07.2017
11:34:34
тут нужно тебе определиться, или inmemory - это не сторадж, тогда сравнивать со стораджем и говорить - а тут flush костыль - не верно. Или inmemory считаем стораджем, но тогда имеем скрытый flush - т.е. то, что по ->add ну нас сразу объект попадет в inmemory сторадж - и есть flush

Sergey
23.07.2017
11:34:36
если ты добавишь слово "бизнес" - это это группа бизнес операций например)

Ivan
23.07.2017
11:34:44
ну регистрация пользователя - бизнес транзакция, и users->add() является её концом?

Ivan
23.07.2017
11:35:07
или прочие вещи, которые должны происходить при регистрации - тоже часть бизнес транзакции?

Sergey
23.07.2017
11:35:10
это идеализированная модель

Dmitry
23.07.2017
11:35:33
ага, и еще у тебя только один поток

Sergey
23.07.2017
11:35:54
ну один поток это потому что я не знаю умеешь ли ты в lock-free структуры, семафоры и прочее

Dmitry
23.07.2017
11:35:54
это не модель, это, извини, крайний случай

Sergey
23.07.2017
11:36:06

Dmitry
23.07.2017
11:36:32
нет, потому что если у тебя два потока - тебе нужны транзакции, пусть путем блокировок, но flush - нужен

Google

Sergey
23.07.2017
11:36:46
у тебя в памяти лежит объект, и ты просто доступ к стэйту закрываешь семафорами и юзаешь lock-free коллекции к примеру
ты можешь это "транзакциями" называть если хочешь конечно, но это не те самые транзакции

Dmitry
23.07.2017
11:37:45
два объекта

Sergey
23.07.2017
11:38:09
два объекта - нет необходимости в рарзграничении
один объект - две операции паралельные - тут надо семафоры или чего-нибудь такое

Dmitry
23.07.2017
11:39:05
не, смотри, ты изменил первый объект, но ты не можешь с него снять блокировку

Sergey
23.07.2017
11:39:09
именно по этой причине я говорю о однопоточном приложении работающем синхронно. Эта модель позволяет выкинуть все ненужное и показать основную идею
ты работал с локами вообще?

Admin
ERROR: S client not available

Sergey
23.07.2017
11:40:28
ну мол у тебя есть сущность, у нее есть стэйт, ты напрямую стэйт менять не можешь - только просишь сущность стэйт поменять, внутри можно просто сначала захватить доступ к стэйту и потом уже менять.
если кто-то уже получил доступ к стэйту - метод будет ждать пока освободится занятый стэйт
короч, в любом случае это все не важно

Dmitry
23.07.2017
11:41:14
проблема в том, что отпустить стейт сущности ты можешь только после того, как изменишь стейт другой сущности
+5 -5

Sergey
23.07.2017
11:41:46
я тебе выше пример скинул как это происходит
+ обычно все же такие вещи делаются по другому - сначала транзакция и по ней пересчитывают баланс
как раз таки что бы небыло необходимости заморачиваться
короч, модель идеальной системы хранения которая описывает идею persistance ignorance - однопоточное приложение без необходимости локов (что бы не усложять реализацию), которая хранит весь стэйт в памяти и никогда не падает.

Google

Sergey
23.07.2017
11:43:08
если ты можешь себе представить такую реализацию (не заморачиваясь о ее не применимости в реальном мире) - то ты можешь себе предтавить основную идею за unif of work и т.д

Dmitry
23.07.2017
11:43:19
ага, выбросили из машины колеса, двигатель и руль и рассказываем на этом примере о идельном странспорте ;)

Sergey
23.07.2017
11:43:29
вот тебе в школе говорили модель вычислений включающую "на ноль делить нельзя"
что бы не тратить время на объяснение концептов которые тебе на данном этапе не нужны
точно так же - если я хочу объяснить тебе идею persistance ignorance - самый простой вариант это однопоточное приложение выполняющая все операции последовательно и хранящая весь свой стэйт в памяти процесса.

Dmitry
23.07.2017
11:44:57
почитай определение "адекватность модели" ;)

Sergey
23.07.2017
11:46:01
понимая эту реализацию ты можешь попробовать ее воплотить с другими праметрами - многопоточность - добавляем локи на стэйте. Что бы не делать этого - берем какой-нибудь готовый сторадж который все это и сам захэндлит и реализуем UoW
идея в том что бы бизнес логика и бизнес операции были максимально изолированы от инфраструктуры и максимально близко соответствовали идее "думай что стэйт у тебя просто лежит в памяти"
и тогда эту бизнес логику можно будет "читать" бизнесу

Dmitry
23.07.2017
11:46:56
а реализация uow - она storage-specific?

Sergey
23.07.2017
11:46:57
вслух
у тебя был стэйт, у тебя есть стэйт, diff -> генерим запросы
ну то есть как "универсальная" - для одног осимейства хранилищ
скажем для тех же коменентноориентированных своя реализация UoW
хоть и очень похожая
документноориентированных*

Dmitry
23.07.2017
11:49:09
отлично, т.е. получаем один интерфейс uow для всех, разные реализации, одна из которых вполне может содержать flush

Sergey
23.07.2017
11:49:18
можно писать на каждый агрегат сущностей по своему UoW заточенному под сторадж - это нудно и скучно но зато будет работать оооочень быстро и можно пользоваться всеми преимуществами хранилища
flush/sync/syncronize

Dmitry
23.07.2017
11:50:04
ну все, пофиг, ты вспомни о чем речь с самого начала шла