Здравствуйте, Sharov, Вы писали:
S>Ну тогда save ломает srp -- и создание и обновление объектов, все на нем.
Ну почему же. Зависит от того, что называть responsibility в данном случае. Если "создавать объект в базе" и "обновлять существующий", то да, ломает. А если иметь в виду "сохранить в базу", то там уже фиолетово, произошёл INSERT или UPDATE на уровне SQL. Главная responsibility — данный объект сохранён в базу — выполнена.
Здравствуйте, scf, Вы писали: scf>Вы за какой вариант и почему?
Я за DDD. У каждого варианта своя семантика, которая может быть предпочтительна для разных предметных областей и сценариев.
Здравствуйте, scf, Вы писали:
scf>Вы за какой вариант и почему?
Если смотреть на реальные бизнес сценарии, то могу припомнить только 2:
— работает сервсис которому падать нельзя. Ему нужно перезаписать объект и его не волнует что было до этого. Если АПИ предлагает только стандартные CRUD методы, то выходит такое:
var newObj = new {};
try{
var obj = api.Read();
api.Update(newObj);
}
catch(NotFoundException)
{
api.Create(newObj);
}
— есть ГУИ и пользователь хочет создать/поменять объект. Но если кто-то еще уже сделал изменения когда он несколько минут вводил свои изменения и нажал потом "Сейв" — то показать алерт и спросить — перезаписать или отклонить свои изменения.
Для того чтобы удовлетворить все потребности мы у себя исполуем такое:
class API
{
//Create or update
ObjectVersion Save(object obj);
//when expectedVersion = 0 - Create if and only if obj is not exist
//when expectedVersion > 0 - Update with concurrency check
ObjectVersion Save(object obj, int expectedVersion);
}
Здравствуйте, scf, Вы писали:
scf>Как известно, есть два способа сформировать интерфейс изменения объекта в DAO: scf>a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый. scf>b) save, который умеет и создавать, и обновлять объекты scf>Вы за какой вариант и почему?
Во втором случае проблемы с идемпотентностью, поэтому в лес.
Как известно, есть два способа сформировать интерфейс изменения объекта в DAO:
a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый.
b) save, который умеет и создавать, и обновлять объекты
Здравствуйте, scf, Вы писали:
scf>Как известно, есть два способа сформировать интерфейс изменения объекта в DAO: scf>a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый. scf>b) save, который умеет и создавать, и обновлять объекты
Здравствуйте, Sharov, Вы писали:
S>Здравствуйте, scf, Вы писали:
scf>>Как известно, есть два способа сформировать интерфейс изменения объекта в DAO: scf>>a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый. scf>>b) save, который умеет и создавать, и обновлять объекты
S>За а). На REST хорошо отображается.
А если Save > PUT (но тут смотря как соответствие определяется)
Здравствуйте, Doc, Вы писали:
Doc>Здравствуйте, Sharov, Вы писали:
S>>Как понять Save > PUT? Типа Save больше (может выполнить) чем Put? Doc>Save отобразить на Put
Ну тогда save ломает srp -- и создание и обновление объектов, все на нем.
Здравствуйте, scf, Вы писали:
scf>Как известно, есть два способа сформировать интерфейс изменения объекта в DAO: scf>a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый. scf>b) save, который умеет и создавать, и обновлять объекты
scf>Вы за какой вариант и почему?
за а). обычно известно что делается в коде — добавляеш или обновляеш объект.
и если вдруг какая ошибка и пытаешся обновить объект, а его нет (нетот идентифкатор получен, или уже удалён)
то получиш вменяемую ошибку (объект не существует), в случае б) проблема вылезет сильно позже с большим кол-вом времени
потраченным на поиск и возможно и ещё рядом неприятных побочных проявлений.
Здравствуйте, scf, Вы писали:
scf>Как известно, есть два способа сформировать интерфейс изменения объекта в DAO: scf>a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый. scf>b) save, который умеет и создавать, и обновлять объекты
scf>Вы за какой вариант и почему?
Вариант а), если используется паттерн типа ActiveRecord. Вариант b) — если UnitOfWork.
Если по задаче будет нужно, то в варианте а) так же появится метод save, только где-то в другом месте или просто рядом с create/update, не вижу смысла им ограничивать интерфейс DAO.
Здравствуйте, scf, Вы писали:
scf>Как известно, есть два способа сформировать интерфейс изменения объекта в DAO: scf>a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый. scf>b) save, который умеет и создавать, и обновлять объекты
scf>Вы за какой вариант и почему?
Я за тот вариант, с которым будет легче писать клиентский код.
В rest будет одна операция put, которая create и update в одном. Поэтому в rest удобнее save.
В типовом UI-сценарии на уровне вызывающего кода известно создается объект или нет (create или update). Если клиентский код будет выглядеть как create(obj) и update(obj) без дополнительных условий, то можно заменить на save(obj)
Поэтому в целом save универсальнее, но могут быть исключения и вообще говоря зависит от того, что внутри save.
Здравствуйте, scf, Вы писали:
scf>Как известно, есть два способа сформировать интерфейс изменения объекта в DAO: scf>a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый. scf>b) save, который умеет и создавать, и обновлять объекты
scf>Вы за какой вариант и почему?
За оба. В большинстве случаев приложение прекрасно знает, сохраняет оно новый объект или обновляет существующий. Никакого смысла использовать универсальный метод нет. Кроме того это может помочь отловить баг. При всём этом в базе данных сохранение и обновление отличаются, поэтому это должны быть две разные операции. Но могут быть случаи, когда полезен третий вариант и он тоже должен быть.
scf,
не ответ "за какой вариант", но мысли на тему:
если речь о БД, в которых традиционно записи имеют ключевое поле (ID) —
играет роль момент и место генерации этого ID для новых записей.
в варианте (а) скорее всего метод "create" будет присваивать объекту сгенеренный на стороне сервера ID
и не должен срабатывать вообще, если ID объекту уже присвоен,
а метод "update", наоборот, не должен срабатывать при ID==null.
в варианте (b) метод "save" должен либо требовать ID!=null,
(т.е. интерфейсу нужен дополнительный метод "get_new_id" и одним "save" не обойтись),
либо он 1) будет не идемпотентным, при этом еще 2) генерация ID без участия сервера чревата проблемой неуникальных ID.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Во втором случае проблемы с идемпотентностью, поэтому в лес.
А где там проблемы с идемпотентностью?
Таки save() как раз можно вызывать столько раз, сколько хочется. А create() выдаст эксепшн при повторном вызове.
Здравствуйте, Artem Korneev, Вы писали:
AK>А где там проблемы с идемпотентностью? AK>Таки save() как раз можно вызывать столько раз, сколько хочется.
Почти всегда создание объектов не идемпотентно, а обновление — да. Если намешать в кучу — придется и обновление делать неидемпотентным.
AK> А create() выдаст эксепшн при повторном вызове.
Эксепшен при повторном вызове не означает отсутствия идемпотентности, так как не меняет состояние сервера.