@prophp7

Страница 1136 из 1387
Artem
27.06.2018
15:44:34
Есть небольшой вопрос - стоит ли делать предсказания при проверке инвариантов? Например ящик с яблоками, у которого инвариант не больше 3х яблок. Делается проверка в методе добавления яблок, есть 2 варианта: 1. Сначала добавить яблоки в ящик (изменить состояние), потом посчитать количество яблок и проверить на соответствие инварианту. То есть тут получается инвариант нарушается на очень короткое время и это подозрительно, но мне кажется, что в этом ничего страшного нет, т.к. всё равно дальше выкинется эксепшен. public function addApple(Apple $apple) { $this->apples[] = $apple; if (count($this->apples) > 3) { throw new Exception(); } } 2. Посчитать количество уже имеющихся яблок, потом предсказать, что после добавления яблока их будет на 1 больше, проверить на соответствие инварианту и только потом изменить состояние. public function addApple(Apple $apple) { $applesCount = count($this->apples) + 1; if ($applesCount > 3) { throw new Exception(); } $this->apples[] = $apple; }

Tex
27.06.2018
15:49:48
Есть небольшой вопрос - стоит ли делать предсказания при проверке инвариантов? Например ящик с яблоками, у которого инвариант не больше 3х яблок. Делается проверка в методе добавления яблок, есть 2 варианта: 1. Сначала добавить яблоки в ящик (изменить состояние), потом посчитать количество яблок и проверить на соответствие инварианту. То есть тут получается инвариант нарушается на очень короткое время и это подозрительно, но мне кажется, что в этом ничего страшного нет, т.к. всё равно дальше выкинется эксепшен. public function addApple(Apple $apple) { $this->apples[] = $apple; if (count($this->apples) > 3) { throw new Exception(); } } 2. Посчитать количество уже имеющихся яблок, потом предсказать, что после добавления яблока их будет на 1 больше, проверить на соответствие инварианту и только потом изменить состояние. public function addApple(Apple $apple) { $applesCount = count($this->apples) + 1; if ($applesCount > 3) { throw new Exception(); } $this->apples[] = $apple; }
делать первой строкой if($this->apples === 3) { throw new LimitApplesException(); } не? если бы добавлялось "рандомное количество яблок", тогда да, нужен предварительный расчёт перед изменением стейта. пёс его знает что там с этим эксепшеном сделают, вдруг просто проигнорят и пойдут дальше, а стейт уже изменился.

Vitaly
27.06.2018
15:51:23
public function addApple(Apple $apple) { if (count($this->apples) >= self::APPLES_LIMIT - 1) { throw new Exception(); } $this->apples[] = $apple; }

Artem
27.06.2018
15:51:49
делать первой строкой if($this->apples === 3) { throw new LimitApplesException(); } не? если бы добавлялось "рандомное количество яблок", тогда да, нужен предварительный расчёт перед изменением стейта. пёс его знает что там с этим эксепшеном сделают, вдруг просто проигнорят и пойдут дальше, а стейт уже изменился.
это как раз вариант без предсказания, да. Просто меня смутило, что инвариант нарушается на короткое время в этом случае. В случае если количество яблок рандомное, надо првоерять на > 3, тогда никаких проблем не будет по идее

Google
Artem
27.06.2018
15:53:37
3 голоса за вариант 1 и ни одного против, спасибо =)

Tex
27.06.2018
15:54:04
public function addApple(Apple $apple) { if (count($this->apples) >= self::APPLES_LIMIT - 1) { throw new Exception(); } $this->apples[] = $apple; }
зачем >=? если при добавлении одного яблока стало именно больше, значит стейт был нарушен еще до этого и можно долго упарываться в рассуждения, должен ли этот метод здесь паниковать.

Vitaly
27.06.2018
15:54:16
Vitaly
27.06.2018
15:54:47
Tex
27.06.2018
15:54:55
и @jimke в общем-то о том же.

так что не, где ты здесь нашёл "3 голоса за вариант 1" это загадка )

Tex
27.06.2018
15:57:53
Artem давай по порядку. 1ый вариант плох, потому что ты получаешь невалидный стейт и не можешь быть уверен, что твой эксепшен не проигнорят. это не "на короткий срок", это в целом. если на вызывающей стороне будет catch (...) { // do nothing; } дальше объект будет невалидным. 2ой вариант хорош по идее, потому что решает проблему первого, но плох по реализации, зачем тебе что-то считать и складывать в отдельную переменную, если ты можешь просто чуть умнее проверить текущий стейт на возможность его изменить в нужную сторону. хочешь добавить? убедись что есть хотя бы одно свободное место (читай count($this->apples < 3)), хочешь убрать - убедись что они вообще есть.

Vitaly
27.06.2018
16:00:49
public function addApple(Apple $apple) { if (count($this->apples) >= self::APPLES_LIMIT - 1) { throw new Exception(); } $this->apples[] = $apple; }
Я тут тоже упоролся. Конечно нужно просто проверить достигнут ли лимит count($this->apples) === self::APPLES_LIMIT

Tex
27.06.2018
16:03:49
Я тут тоже упоролся. Конечно нужно просто проверить достигнут ли лимит count($this->apples) === self::APPLES_LIMIT
как говорил мой препод, код на листочке всегда работает. главное чтоб мысль демонстрировало.

Sergey
27.06.2018
16:05:46
Есть небольшой вопрос - стоит ли делать предсказания при проверке инвариантов? Например ящик с яблоками, у которого инвариант не больше 3х яблок. Делается проверка в методе добавления яблок, есть 2 варианта: 1. Сначала добавить яблоки в ящик (изменить состояние), потом посчитать количество яблок и проверить на соответствие инварианту. То есть тут получается инвариант нарушается на очень короткое время и это подозрительно, но мне кажется, что в этом ничего страшного нет, т.к. всё равно дальше выкинется эксепшен. public function addApple(Apple $apple) { $this->apples[] = $apple; if (count($this->apples) > 3) { throw new Exception(); } } 2. Посчитать количество уже имеющихся яблок, потом предсказать, что после добавления яблока их будет на 1 больше, проверить на соответствие инварианту и только потом изменить состояние. public function addApple(Apple $apple) { $applesCount = count($this->apples) + 1; if ($applesCount > 3) { throw new Exception(); } $this->apples[] = $apple; }
предсказания - хуйня

Google
Sergey
27.06.2018
16:06:16
а то что ты описал это не предсказание - это проверка предусловия и инварианта.

предсказание это когда ты не знаешь сколько яблок тебе подгонят

а если у тебя все есть и тебе буквально надо сложить 2 + 1 то это хороший вариант. И менять стэйт надо только и только тогда когда ты знаешь что все инварианты стэйта будут соблюдены

1Bot
27.06.2018
16:07:03
Пример производителей дисков увлек

Artem
27.06.2018
16:10:09
Artem давай по порядку. 1ый вариант плох, потому что ты получаешь невалидный стейт и не можешь быть уверен, что твой эксепшен не проигнорят. это не "на короткий срок", это в целом. если на вызывающей стороне будет catch (...) { // do nothing; } дальше объект будет невалидным. 2ой вариант хорош по идее, потому что решает проблему первого, но плох по реализации, зачем тебе что-то считать и складывать в отдельную переменную, если ты можешь просто чуть умнее проверить текущий стейт на возможность его изменить в нужную сторону. хочешь добавить? убедись что есть хотя бы одно свободное место (читай count($this->apples < 3)), хочешь убрать - убедись что они вообще есть.
действительно, может такое быть с вариантом 1, про то что можно так поступить с эксепшеном не подумал =\ В общем я вроде понял идею - проверять стейт на то, находится ли он уже в пограничном положении с точки зрения инварианта

да, любопытно, это же элементарная логика на самом деле, хех

Dmitry
27.06.2018
16:35:29
new ThreeAppleCollection($apple1, $apple2, $apple3) :)

Andrew
27.06.2018
16:59:46
https://github.com/WICG/webusb о, скоро флешки по интернету можно будет заражать прям из браузера

Борис
27.06.2018
17:02:18
Скоро OS будет просто прошивкой для браузера. А затем ее вообще выпилят, как рудимент. Будут висеть объявления на столбах" установим хром недорого"

Andrew
27.06.2018
17:04:15
капец, а как php тогда запускать? срочно нужно https://github.com/oraoto/pib осваивать

а то работы лишусь

Art
28.06.2018
14:00:01
что за дичь на хабре? Велосипеды, дережабли какие-то и прочая хрень

Art
28.06.2018
14:01:21
зачем? Нужно тонну новостей теперь скроллить

Sergey
28.06.2018
14:01:36
зачем? Нужно тонну новостей теперь скроллить
идешь в профиль и выкидываешь хабы которые тебе не интересны

Art
28.06.2018
14:03:07
Это в акк входить нужно. А так еще и в вк постят в ленте

F01134H
28.06.2018
14:09:01
почему в phpunit может не работать expectException? Делаю так: $this->expectException(ResponseValidationException::class); $strategy->createAddress(); по итогу все равно вываливается: App\Node\Exceptions\ResponseValidationException: error text...

Борис
28.06.2018
14:29:28
проверь неймспейсы

если не поможет - debug + "Step Into"

Maksim
28.06.2018
14:34:09
@expectedException \App\Node\Exceptions\ResponseValidationException а ещё так бы попробовать) стильно, модно, молодёжно)

Google
Patrik
28.06.2018
14:35:22
Нужна помощь зала, че-то я засомневался, что не полную ерунду тут сгородил) Было несколько таблиц в БД с данными 150 сущностей (нутриентов), данные там такие, что они не поменяются никогда, например названия, меры в которых они измеряются и т.д. Потом для каждого нутриента навалился вагон логики типа формул расчета, пришлось делать доменную модель на 150 классов описывающих особенности каждого, там же было в виде констант заведено все что было в БД (меры, названия и т.д.). Получились как бы энтити у которых и идентификаторы есть (не суррогатные), но они неизменяемые и целиком описаны в коде...при этом в БД есть другие сущности, которые ссылаются по этим идентификаторам на эти энтити, которых в БД нет.

Patrik
28.06.2018
14:46:11
Ну вот я и подошел к тому чтобы грохнуть все это в бд, т.к. дублируется там все безтолково и многим повадно забирать данные оттуда. Просто нет уверенности, что это правильный подход, получается как бы разные части агрегата персистятся кто в бд кто прямо в коде.

Roman
28.06.2018
15:07:06
Но в этом же вроде бы нет ничего плохого

Patrik
28.06.2018
16:33:03
они не персистятся, это просто куча VO
? спасибо, добавил уверенности

Artem
28.06.2018
17:06:58
Судя по LSP получается, что инварианты могут быть ослаблены в подклассах? Если где-то использовать A, а потом поменять на B, то тогда там где А не падало B тоже падать не будет. class A { protected $x; public function some() { if ($this->x > 0 && $this->x < 10) { throw new Exception('error'); } } } class B extends A { protected $x; public function some() { if ($this->x > 0 && $this->x < 15) { throw new Exception('error'); } } }

Evgeniy
28.06.2018
17:31:36
тут прям абзац есть

Саттер и Александреску в своём руководстве по использованию C++ для выражения этого принципа также используют фразу «подкласс не должен требовать от вызывающего кода больше, чем базовый класс, и не должен предоставлять вызывающему коду меньше, чем базовый класс». По мнению данных авторов, публичное наследование в C++ можно употреблять только тогда, когда оно удовлетворяет принципу Лисков. Приватное наследование, по их же мнению, дозволено использовать для доступа к protected части базы и перекрытия виртуальных методов. В любом же ином случае, то есть для всего лишь повторного использования кода из базы, наследование применять нельзя. Основания: использование публичного наследования для повторного использования кода приводит к тому, что внешний мир начинает считать класс Derived разновидностью класса Base, и возможно появление кода, явно использующего этот факт. Это сильно сужает простор для манёвра архитектора в дальнейшем поддержании и рефакторинге класса Derived.

ну и тут прям написано

Evgeniy
28.06.2018
17:32:16


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

даже в русской вики

https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF_%D0%BF%D0%BE%D0%B4%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B8_%D0%91%D0%B0%D1%80%D0%B1%D0%B0%D1%80%D1%8B_%D0%9B%D0%B8%D1%81%D0%BA%D0%BE%D0%B2

ну и слова сергея только наоборот тоже в вики про предусловия и постусловия

Artem
28.06.2018
17:45:15
как туда попал x?)
если через конструктор - тогда надо было бы проверять в конструкторе входящее значение и тогда это прекондишен и его можно ослабить =\

Sergey
28.06.2018
17:51:44
если через конструктор - тогда надо было бы проверять в конструкторе входящее значение и тогда это прекондишен и его можно ослабить =\
class Foo { private $x; // вот тут инвариант что x входит в множество [1, 10]; public function __construct(int $x) { assert(1 <= $x && $x <== 15); // а вот тут мы проверяем предусловие что x входит в [1, 15]; $this->x = $x; // а вот тут мы только что нарушили инвариант } } то есть мы просто имеем несогласованность условий для стэйта и для входящих параметров

Artem
28.06.2018
17:54:08
@KuvshinovEE «подкласс не должен требовать от вызывающего кода больше, чем базовый класс, и не должен предоставлять вызывающему коду меньше, чем базовый класс» Это же вроде только про пре/посткондишены?

Google
Evgeniy
28.06.2018
18:00:27
@KuvshinovEE «подкласс не должен требовать от вызывающего кода больше, чем базовый класс, и не должен предоставлять вызывающему коду меньше, чем базовый класс» Это же вроде только про пре/посткондишены?
тут еще есть определение Сформулировать его можно в виде простого правила: тип S будет подтипом Т тогда и только тогда, когда каждому объекту oS типа S соответствует некий объект oT типа T таким образом, что для всех программ P, реализованных в терминах T, поведение P не будет меняться, если oT заменить на oS.

у S -> Б, а T -> A в этом определение

у тебя поведение P поменяется, имхо

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

Admin
ERROR: S client not available

Artem
28.06.2018
18:06:11
у тебя поведение P поменяется, имхо
если считать, что там где A бы упало, B не упадёт изменением(что пожалуй таки изменение), то да

Evgeniy
28.06.2018
18:09:39
ну так не только в пхп объективности ради, но в пхп особо много говна

Artem
28.06.2018
18:09:51
значит везде :D

Sergey
28.06.2018
18:12:35
если считать, что там где A бы упало, B не упадёт изменением(что пожалуй таки изменение), то да
оно не просто должно "не упасть" - поведение не должно поменяться.

Sergey
28.06.2018
18:14:29
может быть это просто говорит о том, что всё печально с точки зрения архитектуры ПО в php =\
существует не так много языков, которые хоть как-то позволяют тебе типами задавать контракты. Есть DbC которое применимо и к php (с кастылями) но в целом это больше вопрос к тому как ты понимаешь слово "контракт" и как ты занимаешься верификацией

и да - старайся не юзать protected для стэйта. Вообще. Никогда не юзай. Просто потому что это самый простой способ нарушить LSP (а значит сломать код или начать везде расставлять instanceof)

и просто напомню - суть LSP в том что бы убедиться, что два типа могут (или не могут если принцип не соблюдается) входить в одну иерархию типов. Один контракт - могут быть объеденены абстракцией. Разные контракты - разные типы

дальше надо еще смотреть на interface segregation principle

Evgeniy
28.06.2018
18:16:46
протектед хорошо юзать в абстрактных классах, эти методы протектед абстрактными делать

но это довольно узкий пример использования)

Artem
28.06.2018
18:17:04
Да, вот соблюдать LSP тяжело и всякие условия с instanceof манят своей кажущейся простотой. Правда потом становится больно

Evgeniy
28.06.2018
18:17:15
методы, не стэйт.
ну да, свойство не сделать абстрактным

Google
Sergey
28.06.2018
18:17:43
ну да, свойство не сделать абстрактным
давно я уже абстрактных классов не делал...

Evgeniy
28.06.2018
18:17:48
я тоже ))

но это единственный пример который я могу придумать когда protected нужно

и без него только паблик делать

и это очень очень очень редкий кейс

Антон
28.06.2018
18:19:15
а есть статейка про то на что заменить абстрактные классы? вот не первый раз слышу, но никак не могу понять до конца альтернативу

Evgeniy
28.06.2018
18:19:40
интерфейсы и трейты в пыхе

но это имхо и холиварно

Антон
28.06.2018
18:20:07
типа композицию через трейты сделать?

Evgeniy
28.06.2018
18:20:12
но если кратко, все что делалось через наследование в пыхе может быть заменено трейтом

ну не совсем композиция

это имхо могу ошибаться

Антон
28.06.2018
18:20:59
вот увидеть бы 2 примера одного кода. Через Наследование и через композицию

Фесор, может следущий доклад на эту тему?

Страница 1136 из 1387